{"record":{"id":"03cf526255055ac5","repo":"garrytan/gstack","slug":"usage-browse-style-sel-prop-value-style","errorCode":null,"errorMessage":"Usage: browse style <sel> <prop> <value> | style --undo [N]","messagePattern":"Usage: browse style <sel> <prop> <value> \\| style --undo \\[N\\]","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"browse/src/write-commands.ts","lineNumber":775,"sourceCode":"        if (err?.code !== 'ENOENT' && !err?.message?.includes('spawn')) throw err;\n      }\n\n      return `Cookie picker opened at http://127.0.0.1:${port}/cookie-picker\\nDetected browsers: ${browsers.map(b => b.name).join(', ')}\\nSelect domains to import, then close the picker when done.\\n\\nTip: For scripted imports, use --domain <domain> to scope cookies to a single domain.`;\n    }\n\n    case 'style': {\n      // style --undo [N] → revert modification\n      if (args[0] === '--undo') {\n        const idx = args[1] ? parseInt(args[1], 10) : undefined;\n        await undoModification(page, idx);\n        return idx !== undefined ? `Reverted modification #${idx}` : 'Reverted last modification';\n      }\n\n      // style <selector> <property> <value>\n      const [selector, property, ...valueParts] = args;\n      const value = valueParts.join(' ');\n      if (!selector || !property || !value) {\n        throw new Error('Usage: browse style <sel> <prop> <value> | style --undo [N]');\n      }\n\n      // Validate CSS property name\n      if (!/^[a-zA-Z-]+$/.test(property)) {\n        throw new Error(`Invalid CSS property name: ${property}. Only letters and hyphens allowed.`);\n      }\n\n      // Validate CSS value — block data exfiltration patterns\n      const DANGEROUS_CSS = /url\\s*\\(|expression\\s*\\(|@import|javascript:|data:/i;\n      if (DANGEROUS_CSS.test(value)) {\n        throw new Error('CSS value rejected: contains potentially dangerous pattern.');\n      }\n\n      const mod = await modifyStyle(page, selector, property, value);\n      return `Style modified: ${selector} { ${property}: ${mod.oldValue || '(none)'} → ${value} } (${mod.method})`;\n    }\n\n    case 'cleanup': {","sourceCodeStart":757,"sourceCodeEnd":793,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/write-commands.ts#L757-L793","documentation":"Thrown by `browse style` when the non-`--undo` form is invoked without all three required tokens: selector, property, and a non-empty value. The command destructures `[selector, property, ...valueParts]` and joins the remaining parts into `value`; if any of selector/property/value is missing/empty, it cannot form a valid CSS declaration and refuses to proceed.","triggerScenarios":"Calling `browse style` with no args; `browse style body` (property and value missing); `browse style body color` (value missing); `browse style body color ''` (value joins to empty string); a wrapper that split on whitespace and dropped a value containing only spaces.","commonSituations":"An agent emits a two-token style command assuming a default value; a user expects the command to toggle or read styles rather than set them; copy-paste lost the value when it was on a separate line; the value was a CSS variable like `var(--x)` but got URL-encoded or stripped.","solutions":["Provide all three tokens: `browse style body color red`.","For multi-word values, pass them as separate args — they are joined with spaces: `browse style body font-family Arial sans-serif`.","To revert a prior change, use `browse style --undo` or `browse style --undo <N>`.","Quote the value if your shell would otherwise split it incorrectly."],"exampleFix":"// before\nawait runBrowseCommand(['style', 'body', 'color']);\n\n// after\nawait runBrowseCommand(['style', 'body', 'color', 'red']);","handlingStrategy":"validation","validationCode":"function validateStyleArgs(args: string[]): { selector: string; property: string; value: string } {\n  const [selector, property, ...valueParts] = args;\n  const value = valueParts.join(' ').trim();\n  if (!selector || !property || !value) {\n    throw new Error('style requires <selector> <property> <value>');\n  }\n  return { selector, property, value };\n}","typeGuard":"function isStyleArgs(args: unknown): args is [string, string, string, ...string[]] {\n  return Array.isArray(args) && typeof args[0] === 'string' && typeof args[1] === 'string' && args.length >= 3 && args.slice(2).join('').length > 0;\n}","tryCatchPattern":null,"preventionTips":["Always pass selector, property, AND value.","Multi-word values can be passed as separate args (they are space-joined).","Use style --undo [N] to revert, not an empty value."],"tags":["cli-usage","style","css","argument-validation","browse-command"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}