* feat(exit-codes): add Unix-standard exit codes to all CliError types
Introduce EXIT_CODES constant table (sysexits.h conventions) and wire
exitCode into every CliError subclass so the process exit code reflects
the semantic type of failure:
0 success (default)
1 generic / unexpected error
2 argument / usage error (ArgumentError)
66 empty result / not found (EmptyResultError, SelectorError)
69 service unavailable (BrowserConnectError, AdapterLoadError)
77 permission / auth required (AuthRequiredError)
78 configuration error (ConfigError)
124 timeout (TimeoutError)
130 Ctrl-C / SIGINT (unchanged, tui.ts)
resolveExitCode() in commanderAdapter.ts reads err.exitCode for typed
CliErrors, and falls back to pattern-matching message text for untyped
adapter errors (auth pattern → 77, not-found pattern → 66, else → 1).
Shell scripts can now distinguish error categories:
opencli spotify status || echo "exit $?" # 69 if browser not running
opencli github issues --repo x 2>/dev/null; [ $? -eq 77 ] && opencli github auth
* fix(exit-codes): address review findings
- TIMEOUT: change from 124 → 75 (EX_TEMPFAIL); 124 is bash timeout(1)'s
own exit code, creating ambiguity when shell runs `timeout 30 opencli`
- SelectorError: change from EMPTY_RESULT(66) → GENERIC_ERROR(1); a
missing DOM selector is an adapter bug, not a user "no data" condition
- normalizeArgValue: throw ArgumentError instead of bare CliError so
invalid bool args correctly exit with USAGE_ERROR(2) not GENERIC_ERROR(1)
- resolveExitCode: explicitly map 'http' classification to GENERIC_ERROR
to keep exit-code path in sync with the render path
- tui.ts: replace hardcoded process.exit(130) with EXIT_CODES.INTERRUPTED
* feat(exit-codes): replace all hardcoded exit numbers with EXIT_CODES constants
Extend the exit code system to cover every process exit point in the codebase.
No magic numbers remain — all exit codes are now referenced by name.
Semantic upgrades beyond pure renaming:
- plugin update missing args → USAGE_ERROR (2) instead of 1
- plugin update conflicting → USAGE_ERROR (2) instead of 1
- opencli install <unknown> → USAGE_ERROR (2) instead of 1
- unknown command fallback → USAGE_ERROR (2) instead of 1
- record with no candidates → EMPTY_RESULT (66) instead of 1
- external CLI install fail → SERVICE_UNAVAIL (69) instead of 1
- daemon EADDRINUSE → SERVICE_UNAVAIL (69) instead of 1
Files touched: cli.ts, external.ts, daemon.ts, main.ts,
clis/antigravity/serve.ts
- Parallelize file scanning in discoverClisFromFs and discoverPluginDir
using Promise.all(files.map(async ...)) instead of serial for-of with
await, so isCliModule checks run concurrently
- Parallelize plugin directory scanning in discoverPlugins
- Cache loadExternalClis() result to avoid re-parsing YAML on every call
- Invalidate cache in registerExternalCli after writing to disk
- Cache strategyLabel() call in list command to avoid redundant computation
- Add comment explaining why discovery must remain sequential (plugin override semantics)
* fix: pre-release cleanup — bugs, version sync, and error handling
Bug fixes:
- Fix hasLimit using wrong Set (SEARCH_PARAMS → LIMIT_PARAMS) in
analysis.ts classifyQueryParams
- Remove phantom scroll step from BROWSER_STEPS and KNOWN_STEP_NAMES
(declared but never registered, causes runtime crash if used in YAML)
- Add missing download step to KNOWN_STEP_NAMES (was producing
false-positive validation warnings)
Docs:
- Sync version numbers: SKILL.md, extension/package.json,
extension/manifest.json → 1.3.3
- Add jd, web to README command tables (both EN and zh-CN)
- Update xueqiu commands with fund-holdings, fund-snapshot
Code quality:
- Replace all 22 catch (err: any) with typed error handling using
existing getErrorMessage() utility across 13 files
* fix: remove (err as any) casts in error handling
- antigravity/serve.ts: use typed Error.cause instead of (err as any).cause
- external.ts: move instanceof guard into shouldRetryWithCmdShim,
accept unknown instead of forcing NodeJS.ErrnoException cast at call site
* fix(security): harden against command injection and sandbox escape
1. cli.ts: Remove auto-discover of arbitrary system binaries via denylist.
Unknown commands now require explicit registration via `opencli register`.
The previous denylist approach was trivially bypassable (bash, curl, etc.).
2. template.ts: Protect evalJsExpr against prototype chain escape.
Block expressions containing constructor/prototype/__proto__/process/etc.
Deep-copy context objects to sever prototype chains before passing to
new Function().
3. external.ts: Expand shell operator detection in parseCommand to cover
$(), $, #, \n, \r — preventing command substitution and comment injection.
4. fetch.ts: Use JSON.stringify for HTTP method in browser evaluate() instead
of raw string interpolation, preventing JS injection via crafted method values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: harden security-sensitive execution paths
* chore: tighten template sandbox guard
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(external): replace execSync with execFileSync to prevent command injection
* fix(review): preserve Windows external installs and restore docs build
* fix(review): preserve Windows external installs after rebase
---------
Co-authored-by: jackwener <jakevingoo@gmail.com>