{"record":{"id":"7686871f791de0c6","repo":"garrytan/gstack","slug":"usage-echo-goto-url-text-browse-c","errorCode":null,"errorMessage":"Usage: echo '[[\"goto\",\"url\"],[\"text\"]]' | browse chain\n   or: browse chain 'goto url | click @e5 | snapshot -ic'","messagePattern":"Usage: echo '\\[\\[\"goto\",\"url\"\\],\\[\"text\"\\]\\]' \\| browse chain\n   or: browse chain 'goto url \\| click @e5 \\| snapshot -ic'","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/meta-commands.ts","lineNumber":601,"sourceCode":"        validateOutputPath(screenshotPath);\n        await page.screenshot({ path: screenshotPath, fullPage: true });\n        await guardScreenshotPath(screenshotPath);\n        results.push(`${vp.name} (${vp.width}x${vp.height}): ${screenshotPath}`);\n      }\n\n      // Restore original viewport\n      if (originalViewport) {\n        await page.setViewportSize(originalViewport);\n      }\n\n      return results.join('\\n');\n    }\n\n    // ─── Chain ─────────────────────────────────────────\n    case 'chain': {\n      // Read JSON array from args[0] (if provided) or expect it was passed as body\n      const jsonStr = args[0];\n      if (!jsonStr) throw new Error(\n        'Usage: echo \\'[[\"goto\",\"url\"],[\"text\"]]\\' | browse chain\\n' +\n        '   or: browse chain \\'goto url | click @e5 | snapshot -ic\\''\n      );\n\n      let rawCommands: string[][];\n      try {\n        rawCommands = JSON.parse(jsonStr);\n        if (!Array.isArray(rawCommands)) throw new Error('not array');\n      } catch (err: any) {\n        // Fallback: pipe-delimited format \"goto url | click @e5 | snapshot -ic\"\n        if (!(err instanceof SyntaxError) && err?.message !== 'not array') throw err;\n        rawCommands = jsonStr.split(' | ')\n          .filter(seg => seg.trim().length > 0)\n          .map(seg => tokenizePipeSegment(seg.trim()));\n      }\n\n      // Canonicalize aliases across the whole chain. Pair canonical name with the raw\n      // input so result labels + error messages reflect what the user typed, but every","sourceCodeStart":583,"sourceCodeEnd":619,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/meta-commands.ts#L583-L619","documentation":"The `chain` meta-command expects a single argument that is either a JSON array of command arrays (`[[\"goto\",\"url\"],[\"text\"]]`) or a pipe-delimited script (`goto url | click @e5 | snapshot -ic`). When `args[0]` is empty/undefined the command cannot infer what to run, so it throws this usage message (lines 600-604).","triggerScenarios":"Calling `browse chain` with no arguments, piping nothing on stdin when the server expected `args[0]`, or passing an empty string.","commonSituations":"First-time users forgetting the JSON shape; shell quoting that swallowed the argument; an agent constructing the call without a payload.","solutions":["Pass a JSON array as the first arg: `browse chain '[[\"goto\",\"https://x\"],[\"text\"]]'`.","Or pass a pipe-delimited script: `browse chain 'goto https://x | text'`.","If piping via stdin, make sure the server/CLI forwards stdin into `args[0]` — otherwise inline the payload."],"exampleFix":"// before\nbrowse chain\n// after\nbrowse chain '[[\"goto\",\"https://example.com\"],[\"text\"]]'","handlingStrategy":"validation","validationCode":"if (!args[0] || typeof args[0] !== 'string') {\n  throw new Error('chain requires a JSON array or pipe-delimited script as args[0]');\n}","typeGuard":"const isChainPayload = (s: string): boolean => {\n  try { return Array.isArray(JSON.parse(s)); }\n  catch { return s.includes('|') || /\\s/.test(s); }\n};","tryCatchPattern":"try { await browse.chain(payload); }\ncatch (err) {\n  if (/Usage:/.test(err.message) && /chain/.test(err.message)) {\n    // rebuild payload as JSON array of [cmd, ...args]\n  }\n}","preventionTips":["Always construct chain payloads as `JSON.stringify([[cmd, ...args], ...])`.","Validate the payload is a non-empty string before dispatch.","Unit-test the JSON shape in your wrapper."],"tags":["chain","argument-parsing","cli","usage"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}