{"record":{"id":"5dcd69503f947311","repo":"garrytan/gstack","slug":"usage-state-save-load-name","errorCode":null,"errorMessage":"Usage: state save|load <name>","messagePattern":"Usage: state save\\|load <name>","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/meta-commands.ts","lineNumber":928,"sourceCode":"      }\n\n      lines.push('────────────────────────────────');\n\n      // Handle --clear flag\n      if (args.includes('--clear')) {\n        for (const file of files) {\n          try { fs.unlinkSync(path.join(inboxDir, file)); } catch (err: any) { if (err?.code !== 'ENOENT') throw err; }\n        }\n        lines.push(`Cleared ${files.length} message${files.length === 1 ? '' : 's'}.`);\n      }\n\n      return lines.join('\\n');\n    }\n\n    // ─── State ────────────────────────────────────────\n    case 'state': {\n      const [action, name] = args;\n      if (!action || !name) throw new Error('Usage: state save|load <name>');\n\n      // Sanitize name: alphanumeric + hyphens + underscores only\n      if (!/^[a-zA-Z0-9_-]+$/.test(name)) {\n        throw new Error('State name must be alphanumeric (a-z, 0-9, _, -)');\n      }\n\n      const config = resolveConfig();\n      const stateDir = path.join(config.stateDir, 'browse-states');\n      mkdirSecure(stateDir);\n      const statePath = path.join(stateDir, `${name}.json`);\n\n      if (action === 'save') {\n        const state = await bm.saveState();\n        // V1: cookies + URLs only (not localStorage — breaks on load-before-navigate)\n        const saveData = {\n          version: 1,\n          savedAt: new Date().toISOString(),\n          cookies: state.cookies,","sourceCodeStart":910,"sourceCodeEnd":946,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/meta-commands.ts#L910-L946","documentation":"The `state` meta-command requires both an `action` and a `name`: `state save <name>` or `state load <name>` (lines 925-928). Missing either one throws this usage error before any filesystem or browser-state operation.","triggerScenarios":"`browse state` alone, `browse state save` (no name), or `browse state mysession` (no action).","commonSituations":"Forgetting the action verb, or the name; an agent truncating the command; shell splitting that merged tokens.","solutions":["Use `browse state save <name>` to write cookies+pages to `<stateDir>/browse-states/<name>.json`.","Use `browse state load <name>` to restore them.","Pick a name matching `[a-zA-Z0-9_-]+` to also satisfy the regex guard (error 130)."],"exampleFix":"// before\nbrowse state save\n// after\nbrowse state save login-session","handlingStrategy":"validation","validationCode":"if (args.length < 2 || !args[0] || !args[1]) {\n  throw new Error('state requires an action (save|load) and a name');\n}\nif (!['save', 'load'].includes(args[0])) {\n  throw new Error(`Unsupported state action: ${args[0]}`);\n}","typeGuard":"const isStateAction = (s: string): s is 'save' | 'load' =>\n  s === 'save' || s === 'load';","tryCatchPattern":null,"preventionTips":["Model the state wrapper as `(action: 'save' | 'load', name: string)`.","Validate the name against `^[a-zA-Z0-9_-]+$` early."],"tags":["state","argument-parsing","usage"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}