diff --git a/SKILL.md b/SKILL.md index 2f78a630..c79b710b 100644 --- a/SKILL.md +++ b/SKILL.md @@ -23,12 +23,9 @@ Auto-shuts down after 30 min idle. State persists between calls (cookies, tabs, ## SETUP (run this check BEFORE any browse command) ```bash -BROWSE_OUTPUT=$(browse/bin/find-browse 2>/dev/null || ~/.claude/skills/gstack/browse/bin/find-browse 2>/dev/null) -B=$(echo "$BROWSE_OUTPUT" | head -1) -META=$(echo "$BROWSE_OUTPUT" | grep "^META:" || true) +B=$(browse/bin/find-browse 2>/dev/null || ~/.claude/skills/gstack/browse/bin/find-browse 2>/dev/null) if [ -n "$B" ]; then echo "READY: $B" - [ -n "$META" ] && echo "$META" else echo "NEEDS_SETUP" fi @@ -39,13 +36,6 @@ If `NEEDS_SETUP`: 2. Run: `cd && ./setup` 3. If `bun` is not installed: `curl -fsSL https://bun.sh/install | bash` -If you see `META:UPDATE_AVAILABLE`: -1. Parse the JSON payload to get `current`, `latest`, and `command`. -2. Tell the user: "A gstack update is available (current: X, latest: Y). OK to update?" -3. **STOP and wait for approval.** -4. Run the command from the META payload. -5. Re-run the setup check above to get the updated binary path. - ## IMPORTANT - Use the compiled binary via Bash: `$B ` @@ -242,25 +232,36 @@ $B css ".button" "background-color" The snapshot is your primary tool for understanding and interacting with pages. ``` --i Interactive elements only (buttons, links, inputs) with @e refs --c Compact (no empty structural nodes) --d Limit depth --s Scope to CSS selector --D Diff against previous snapshot (what changed?) --a Annotated screenshot with ref labels --o Output path for screenshot --C Cursor-interactive elements (@c refs — divs with pointer, onclick) +-i --interactive Interactive elements only (buttons, links, inputs) with @e refs +-c --compact Compact (no empty structural nodes) +-d --depth Limit tree depth (0 = root only, default: unlimited) +-s --selector Scope to CSS selector +-D --diff Unified diff against previous snapshot (first call stores baseline) +-a --annotate Annotated screenshot with red overlay boxes and ref labels +-o --output Output path for annotated screenshot (default: /tmp/browse-annotated.png) +-C --cursor-interactive Cursor-interactive elements (@c refs — divs with pointer, onclick) ``` -Combine flags: `$B snapshot -i -a -C -o /tmp/annotated.png` +All flags can be combined freely. `-o` only applies when `-a` is also used. +Example: `$B snapshot -i -a -C -o /tmp/annotated.png` -After snapshot, use @refs everywhere: +**Ref numbering:** @e refs are assigned sequentially (@e1, @e2, ...) in tree order. +@c refs from `-C` are numbered separately (@c1, @c2, ...). + +After snapshot, use @refs as selectors in any command: ```bash $B click @e3 $B fill @e4 "value" $B hover @e1 $B html @e2 $B css @e5 "color" $B attrs @e6 $B click @c1 # cursor-interactive ref (from -C) ``` +**Output format:** indented accessibility tree with @ref IDs, one element per line. +``` + @e1 [heading] "Welcome" [level=1] + @e2 [textbox] "Email" + @e3 [button] "Submit" +``` + Refs are invalidated on navigation — run `snapshot` again after `goto`. ## Command Reference @@ -279,7 +280,7 @@ Refs are invalidated on navigation — run `snapshot` again after `goto`. |---------|-------------| | `accessibility` | Full ARIA tree | | `forms` | Form fields as JSON | -| `html [selector]` | innerHTML | +| `html [selector]` | innerHTML of selector (throws if not found), or full page HTML if no selector given | | `links` | All links as "text → href" | | `text` | Cleaned page text | @@ -287,22 +288,22 @@ Refs are invalidated on navigation — run `snapshot` again after `goto`. | Command | Description | |---------|-------------| | `click ` | Click element | -| `cookie` | Set cookie | +| `cookie =` | Set cookie on current page domain | | `cookie-import ` | Import cookies from JSON file | -| `cookie-import-browser [browser] [--domain d]` | Import cookies from real browser (opens picker UI, or direct with --domain) | -| `dialog-accept [text]` | Auto-accept next alert/confirm/prompt | +| `cookie-import-browser [browser] [--domain d]` | Import cookies from Comet, Chrome, Arc, Brave, or Edge (opens picker, or use --domain for direct import) | +| `dialog-accept [text]` | Auto-accept next alert/confirm/prompt. Optional text is sent as the prompt response | | `dialog-dismiss` | Auto-dismiss next dialog | | `fill ` | Fill input | -| `header ` | Set custom request header | +| `header :` | Set custom request header (colon-separated, sensitive values auto-redacted) | | `hover ` | Hover element | -| `press ` | Press key (Enter, Tab, Escape, etc.) | -| `scroll [sel]` | Scroll element into view | -| `select ` | Select dropdown option | +| `press ` | Press key — Enter, Tab, Escape, ArrowUp/Down/Left/Right, Backspace, Delete, Home, End, PageUp, PageDown, or modifiers like Shift+Enter | +| `scroll [sel]` | Scroll element into view, or scroll to page bottom if no selector | +| `select ` | Select dropdown option by value, label, or visible text | | `type ` | Type into focused element | -| `upload ` | Upload file(s) | +| `upload [file2...]` | Upload file(s) | | `useragent ` | Set user agent | | `viewport ` | Set viewport size | -| `wait ` | Wait for element/condition | +| `wait ` | Wait for element, network idle, or page load (timeout: 15s) | ### Inspection | Command | Description | @@ -312,30 +313,30 @@ Refs are invalidated on navigation — run `snapshot` again after `goto`. | `cookies` | All cookies as JSON | | `css ` | Computed CSS value | | `dialog [--clear]` | Dialog messages | -| `eval ` | Run JS file | +| `eval ` | Run JavaScript from file and return result as string (path must be under /tmp or cwd) | | `is ` | State check (visible/hidden/enabled/disabled/checked/editable/focused) | -| `js ` | Run JavaScript | +| `js ` | Run JavaScript expression and return result as string | | `network [--clear]` | Network requests | | `perf` | Page load timings | -| `storage [set k v]` | localStorage + sessionStorage | +| `storage [set k v]` | Read all localStorage + sessionStorage as JSON, or set to write localStorage | ### Visual | Command | Description | |---------|-------------| | `diff ` | Text diff between pages | | `pdf [path]` | Save as PDF | -| `responsive [prefix]` | Mobile/tablet/desktop screenshots | +| `responsive [prefix]` | Screenshots at mobile (375x812), tablet (768x1024), desktop (1280x720). Saves as {prefix}-mobile.png etc. | | `screenshot [path]` | Save screenshot | ### Snapshot | Command | Description | |---------|-------------| -| `snapshot [flags]` | Accessibility tree with @refs | +| `snapshot [flags]` | Accessibility tree with @e refs for element selection. Flags: -i interactive only, -c compact, -d N depth limit, -s sel scope, -D diff vs previous, -a annotated screenshot, -o path output, -C cursor-interactive @c refs | ### Meta | Command | Description | |---------|-------------| -| `chain` | Multi-command from JSON stdin | +| `chain` | Run commands from JSON stdin. Format: [["cmd","arg1",...],...] | ### Tabs | Command | Description | diff --git a/browse/SKILL.md b/browse/SKILL.md index 7b9a6cff..5e838649 100644 --- a/browse/SKILL.md +++ b/browse/SKILL.md @@ -104,25 +104,36 @@ $B diff https://staging.app.com https://prod.app.com The snapshot is your primary tool for understanding and interacting with pages. ``` --i Interactive elements only (buttons, links, inputs) with @e refs --c Compact (no empty structural nodes) --d Limit depth --s Scope to CSS selector --D Diff against previous snapshot (what changed?) --a Annotated screenshot with ref labels --o Output path for screenshot --C Cursor-interactive elements (@c refs — divs with pointer, onclick) +-i --interactive Interactive elements only (buttons, links, inputs) with @e refs +-c --compact Compact (no empty structural nodes) +-d --depth Limit tree depth (0 = root only, default: unlimited) +-s --selector Scope to CSS selector +-D --diff Unified diff against previous snapshot (first call stores baseline) +-a --annotate Annotated screenshot with red overlay boxes and ref labels +-o --output Output path for annotated screenshot (default: /tmp/browse-annotated.png) +-C --cursor-interactive Cursor-interactive elements (@c refs — divs with pointer, onclick) ``` -Combine flags: `$B snapshot -i -a -C -o /tmp/annotated.png` +All flags can be combined freely. `-o` only applies when `-a` is also used. +Example: `$B snapshot -i -a -C -o /tmp/annotated.png` -After snapshot, use @refs everywhere: +**Ref numbering:** @e refs are assigned sequentially (@e1, @e2, ...) in tree order. +@c refs from `-C` are numbered separately (@c1, @c2, ...). + +After snapshot, use @refs as selectors in any command: ```bash $B click @e3 $B fill @e4 "value" $B hover @e1 $B html @e2 $B css @e5 "color" $B attrs @e6 $B click @c1 # cursor-interactive ref (from -C) ``` +**Output format:** indented accessibility tree with @ref IDs, one element per line. +``` + @e1 [heading] "Welcome" [level=1] + @e2 [textbox] "Email" + @e3 [button] "Submit" +``` + Refs are invalidated on navigation — run `snapshot` again after `goto`. ## Full Command List @@ -141,7 +152,7 @@ Refs are invalidated on navigation — run `snapshot` again after `goto`. |---------|-------------| | `accessibility` | Full ARIA tree | | `forms` | Form fields as JSON | -| `html [selector]` | innerHTML | +| `html [selector]` | innerHTML of selector (throws if not found), or full page HTML if no selector given | | `links` | All links as "text → href" | | `text` | Cleaned page text | @@ -149,22 +160,22 @@ Refs are invalidated on navigation — run `snapshot` again after `goto`. | Command | Description | |---------|-------------| | `click ` | Click element | -| `cookie` | Set cookie | +| `cookie =` | Set cookie on current page domain | | `cookie-import ` | Import cookies from JSON file | -| `cookie-import-browser [browser] [--domain d]` | Import cookies from real browser (opens picker UI, or direct with --domain) | -| `dialog-accept [text]` | Auto-accept next alert/confirm/prompt | +| `cookie-import-browser [browser] [--domain d]` | Import cookies from Comet, Chrome, Arc, Brave, or Edge (opens picker, or use --domain for direct import) | +| `dialog-accept [text]` | Auto-accept next alert/confirm/prompt. Optional text is sent as the prompt response | | `dialog-dismiss` | Auto-dismiss next dialog | | `fill ` | Fill input | -| `header ` | Set custom request header | +| `header :` | Set custom request header (colon-separated, sensitive values auto-redacted) | | `hover ` | Hover element | -| `press ` | Press key (Enter, Tab, Escape, etc.) | -| `scroll [sel]` | Scroll element into view | -| `select ` | Select dropdown option | +| `press ` | Press key — Enter, Tab, Escape, ArrowUp/Down/Left/Right, Backspace, Delete, Home, End, PageUp, PageDown, or modifiers like Shift+Enter | +| `scroll [sel]` | Scroll element into view, or scroll to page bottom if no selector | +| `select ` | Select dropdown option by value, label, or visible text | | `type ` | Type into focused element | -| `upload ` | Upload file(s) | +| `upload [file2...]` | Upload file(s) | | `useragent ` | Set user agent | | `viewport ` | Set viewport size | -| `wait ` | Wait for element/condition | +| `wait ` | Wait for element, network idle, or page load (timeout: 15s) | ### Inspection | Command | Description | @@ -174,30 +185,30 @@ Refs are invalidated on navigation — run `snapshot` again after `goto`. | `cookies` | All cookies as JSON | | `css ` | Computed CSS value | | `dialog [--clear]` | Dialog messages | -| `eval ` | Run JS file | +| `eval ` | Run JavaScript from file and return result as string (path must be under /tmp or cwd) | | `is ` | State check (visible/hidden/enabled/disabled/checked/editable/focused) | -| `js ` | Run JavaScript | +| `js ` | Run JavaScript expression and return result as string | | `network [--clear]` | Network requests | | `perf` | Page load timings | -| `storage [set k v]` | localStorage + sessionStorage | +| `storage [set k v]` | Read all localStorage + sessionStorage as JSON, or set to write localStorage | ### Visual | Command | Description | |---------|-------------| | `diff ` | Text diff between pages | | `pdf [path]` | Save as PDF | -| `responsive [prefix]` | Mobile/tablet/desktop screenshots | +| `responsive [prefix]` | Screenshots at mobile (375x812), tablet (768x1024), desktop (1280x720). Saves as {prefix}-mobile.png etc. | | `screenshot [path]` | Save screenshot | ### Snapshot | Command | Description | |---------|-------------| -| `snapshot [flags]` | Accessibility tree with @refs | +| `snapshot [flags]` | Accessibility tree with @e refs for element selection. Flags: -i interactive only, -c compact, -d N depth limit, -s sel scope, -D diff vs previous, -a annotated screenshot, -o path output, -C cursor-interactive @c refs | ### Meta | Command | Description | |---------|-------------| -| `chain` | Multi-command from JSON stdin | +| `chain` | Run commands from JSON stdin. Format: [["cmd","arg1",...],...] | ### Tabs | Command | Description | diff --git a/browse/src/commands.ts b/browse/src/commands.ts index c3189ace..6024c4b6 100644 --- a/browse/src/commands.ts +++ b/browse/src/commands.ts @@ -43,13 +43,13 @@ export const COMMAND_DESCRIPTIONS: Record' }, - 'eval': { category: 'Inspection', description: 'Run JS file', usage: 'eval ' }, + 'js': { category: 'Inspection', description: 'Run JavaScript expression and return result as string', usage: 'js ' }, + 'eval': { category: 'Inspection', description: 'Run JavaScript from file and return result as string (path must be under /tmp or cwd)', usage: 'eval ' }, 'css': { category: 'Inspection', description: 'Computed CSS value', usage: 'css ' }, 'attrs': { category: 'Inspection', description: 'Element attributes as JSON', usage: 'attrs ' }, 'is': { category: 'Inspection', description: 'State check (visible/hidden/enabled/disabled/checked/editable/focused)', usage: 'is ' }, @@ -57,30 +57,30 @@ export const COMMAND_DESCRIPTIONS: Record to write localStorage', usage: 'storage [set k v]' }, 'perf': { category: 'Inspection', description: 'Page load timings' }, // Interaction 'click': { category: 'Interaction', description: 'Click element', usage: 'click ' }, 'fill': { category: 'Interaction', description: 'Fill input', usage: 'fill ' }, - 'select': { category: 'Interaction', description: 'Select dropdown option', usage: 'select ' }, + 'select': { category: 'Interaction', description: 'Select dropdown option by value, label, or visible text', usage: 'select ' }, 'hover': { category: 'Interaction', description: 'Hover element', usage: 'hover ' }, 'type': { category: 'Interaction', description: 'Type into focused element', usage: 'type ' }, - 'press': { category: 'Interaction', description: 'Press key (Enter, Tab, Escape, etc.)', usage: 'press ' }, - 'scroll': { category: 'Interaction', description: 'Scroll element into view', usage: 'scroll [sel]' }, - 'wait': { category: 'Interaction', description: 'Wait for element/condition', usage: 'wait ' }, - 'upload': { category: 'Interaction', description: 'Upload file(s)', usage: 'upload ' }, + 'press': { category: 'Interaction', description: 'Press key — Enter, Tab, Escape, ArrowUp/Down/Left/Right, Backspace, Delete, Home, End, PageUp, PageDown, or modifiers like Shift+Enter', usage: 'press ' }, + 'scroll': { category: 'Interaction', description: 'Scroll element into view, or scroll to page bottom if no selector', usage: 'scroll [sel]' }, + 'wait': { category: 'Interaction', description: 'Wait for element, network idle, or page load (timeout: 15s)', usage: 'wait ' }, + 'upload': { category: 'Interaction', description: 'Upload file(s)', usage: 'upload [file2...]' }, 'viewport':{ category: 'Interaction', description: 'Set viewport size', usage: 'viewport ' }, - 'cookie': { category: 'Interaction', description: 'Set cookie' }, + 'cookie': { category: 'Interaction', description: 'Set cookie on current page domain', usage: 'cookie =' }, 'cookie-import': { category: 'Interaction', description: 'Import cookies from JSON file', usage: 'cookie-import ' }, - 'cookie-import-browser': { category: 'Interaction', description: 'Import cookies from real browser (opens picker UI, or direct with --domain)', usage: 'cookie-import-browser [browser] [--domain d]' }, - 'header': { category: 'Interaction', description: 'Set custom request header', usage: 'header ' }, + 'cookie-import-browser': { category: 'Interaction', description: 'Import cookies from Comet, Chrome, Arc, Brave, or Edge (opens picker, or use --domain for direct import)', usage: 'cookie-import-browser [browser] [--domain d]' }, + 'header': { category: 'Interaction', description: 'Set custom request header (colon-separated, sensitive values auto-redacted)', usage: 'header :' }, 'useragent': { category: 'Interaction', description: 'Set user agent', usage: 'useragent ' }, - 'dialog-accept': { category: 'Interaction', description: 'Auto-accept next alert/confirm/prompt', usage: 'dialog-accept [text]' }, + 'dialog-accept': { category: 'Interaction', description: 'Auto-accept next alert/confirm/prompt. Optional text is sent as the prompt response', usage: 'dialog-accept [text]' }, 'dialog-dismiss': { category: 'Interaction', description: 'Auto-dismiss next dialog' }, // Visual 'screenshot': { category: 'Visual', description: 'Save screenshot', usage: 'screenshot [path]' }, 'pdf': { category: 'Visual', description: 'Save as PDF', usage: 'pdf [path]' }, - 'responsive': { category: 'Visual', description: 'Mobile/tablet/desktop screenshots', usage: 'responsive [prefix]' }, + 'responsive': { category: 'Visual', description: 'Screenshots at mobile (375x812), tablet (768x1024), desktop (1280x720). Saves as {prefix}-mobile.png etc.', usage: 'responsive [prefix]' }, 'diff': { category: 'Visual', description: 'Text diff between pages', usage: 'diff ' }, // Tabs 'tabs': { category: 'Tabs', description: 'List open tabs' }, @@ -92,8 +92,8 @@ export const COMMAND_DESCRIPTIONS: Record = [ { short: '-i', long: '--interactive', description: 'Interactive elements only (buttons, links, inputs) with @e refs', optionKey: 'interactive' }, { short: '-c', long: '--compact', description: 'Compact (no empty structural nodes)', optionKey: 'compact' }, - { short: '-d', long: '--depth', description: 'Limit depth', takesValue: true, valueHint: '', optionKey: 'depth' }, + { short: '-d', long: '--depth', description: 'Limit tree depth (0 = root only, default: unlimited)', takesValue: true, valueHint: '', optionKey: 'depth' }, { short: '-s', long: '--selector', description: 'Scope to CSS selector', takesValue: true, valueHint: '', optionKey: 'selector' }, - { short: '-D', long: '--diff', description: 'Diff against previous snapshot (what changed?)', optionKey: 'diff' }, - { short: '-a', long: '--annotate', description: 'Annotated screenshot with ref labels', optionKey: 'annotate' }, - { short: '-o', long: '--output', description: 'Output path for screenshot', takesValue: true, valueHint: '', optionKey: 'outputPath' }, + { short: '-D', long: '--diff', description: 'Unified diff against previous snapshot (first call stores baseline)', optionKey: 'diff' }, + { short: '-a', long: '--annotate', description: 'Annotated screenshot with red overlay boxes and ref labels', optionKey: 'annotate' }, + { short: '-o', long: '--output', description: 'Output path for annotated screenshot (default: /tmp/browse-annotated.png)', takesValue: true, valueHint: '', optionKey: 'outputPath' }, { short: '-C', long: '--cursor-interactive', description: 'Cursor-interactive elements (@c refs — divs with pointer, onclick)', optionKey: 'cursorInteractive' }, ]; diff --git a/scripts/gen-skill-docs.ts b/scripts/gen-skill-docs.ts index 19b68000..381278ca 100644 --- a/scripts/gen-skill-docs.ts +++ b/scripts/gen-skill-docs.ts @@ -64,20 +64,31 @@ function generateSnapshotFlags(): string { for (const flag of SNAPSHOT_FLAGS) { const label = flag.valueHint ? `${flag.short} ${flag.valueHint}` : flag.short; - lines.push(`${label.padEnd(10)}${flag.description}`); + lines.push(`${label.padEnd(10)}${flag.long.padEnd(24)}${flag.description}`); } lines.push('```'); lines.push(''); - lines.push('Combine flags: `$B snapshot -i -a -C -o /tmp/annotated.png`'); + lines.push('All flags can be combined freely. `-o` only applies when `-a` is also used.'); + lines.push('Example: `$B snapshot -i -a -C -o /tmp/annotated.png`'); lines.push(''); - lines.push('After snapshot, use @refs everywhere:'); + lines.push('**Ref numbering:** @e refs are assigned sequentially (@e1, @e2, ...) in tree order.'); + lines.push('@c refs from `-C` are numbered separately (@c1, @c2, ...).'); + lines.push(''); + lines.push('After snapshot, use @refs as selectors in any command:'); lines.push('```bash'); lines.push('$B click @e3 $B fill @e4 "value" $B hover @e1'); lines.push('$B html @e2 $B css @e5 "color" $B attrs @e6'); lines.push('$B click @c1 # cursor-interactive ref (from -C)'); lines.push('```'); lines.push(''); + lines.push('**Output format:** indented accessibility tree with @ref IDs, one element per line.'); + lines.push('```'); + lines.push(' @e1 [heading] "Welcome" [level=1]'); + lines.push(' @e2 [textbox] "Email"'); + lines.push(' @e3 [button] "Submit"'); + lines.push('```'); + lines.push(''); lines.push('Refs are invalidated on navigation — run `snapshot` again after `goto`.'); return lines.join('\n');