()
| 978 | |
| 979 | // ─── Main ────────────────────────────────────────────────────── |
| 980 | async function main() { |
| 981 | const rawArgs = process.argv.slice(2); |
| 982 | |
| 983 | // ─── Global flags (--proxy, --headed) ─────────────────────── |
| 984 | // Extract before command dispatch so they apply to any command. Throws |
| 985 | // ProxyConfigError on invalid URL or D9 cred-mixing violations. |
| 986 | let globalFlags: GlobalFlags; |
| 987 | try { |
| 988 | globalFlags = extractGlobalFlags(rawArgs, process.env); |
| 989 | } catch (err) { |
| 990 | if (err instanceof ProxyConfigError) { |
| 991 | console.error(`[browse] error: ${err.message}`); |
| 992 | console.error(`[browse] hint: ${err.hint}`); |
| 993 | process.exit(1); |
| 994 | } |
| 995 | throw err; |
| 996 | } |
| 997 | _globalFlags = globalFlags; |
| 998 | const args = globalFlags.args; |
| 999 | |
| 1000 | if (args.length === 0 || args[0] === '--help' || args[0] === '-h') { |
| 1001 | console.log(`gstack browse — Fast headless browser for AI coding agents |
| 1002 | |
| 1003 | Usage: browse <command> [args...] |
| 1004 | |
| 1005 | Navigation: goto <url> | back | forward | reload | url |
| 1006 | Content: text | html [sel] | links | forms | accessibility |
| 1007 | Interaction: click <sel> | fill <sel> <val> | select <sel> <val> |
| 1008 | hover <sel> | type <text> | press <key> |
| 1009 | scroll [sel] | wait <sel|--networkidle|--load> | viewport <WxH> |
| 1010 | upload <sel> <file1> [file2...] |
| 1011 | cookie-import <json-file> |
| 1012 | cookie-import-browser [browser] [--domain <d>] |
| 1013 | Inspection: js <expr> | eval <file> | css <sel> <prop> | attrs <sel> |
| 1014 | console [--clear|--errors] | network [--clear] | dialog [--clear] |
| 1015 | cookies | storage [set <k> <v>] | perf |
| 1016 | is <prop> <sel> (visible|hidden|enabled|disabled|checked|editable|focused) |
| 1017 | Visual: screenshot [--viewport] [--clip x,y,w,h] [@ref|sel] [path] |
| 1018 | pdf [path] | responsive [prefix] |
| 1019 | Snapshot: snapshot [-i] [-c] [-d N] [-s sel] [-D] [-a] [-o path] [-C] |
| 1020 | -D/--diff: diff against previous snapshot |
| 1021 | -a/--annotate: annotated screenshot with ref labels |
| 1022 | -C/--cursor-interactive: find non-ARIA clickable elements |
| 1023 | Compare: diff <url1> <url2> |
| 1024 | Multi-step: chain (reads JSON from stdin) |
| 1025 | Tabs: tabs | tab <id> | newtab [url] | closetab [id] |
| 1026 | Server: status | cookie <n>=<v> | header <n>:<v> |
| 1027 | useragent <str> | stop | restart |
| 1028 | Dialogs: dialog-accept [text] | dialog-dismiss |
| 1029 | |
| 1030 | Refs: After 'snapshot', use @e1, @e2... as selectors: |
| 1031 | click @e3 | fill @e4 "value" | hover @e1 |
| 1032 | @c refs from -C: click @c1`); |
| 1033 | process.exit(0); |
| 1034 | } |
| 1035 | |
| 1036 | // One-time cleanup of legacy /tmp state files |
| 1037 | cleanupLegacyState(); |
no test coverage detected