Skip to content

Commit 0e168d5

Browse files
authored
refactor(browser): replace --session flag with <sessionname> positional (#1505)
* refactor(browser): replace --session flag with <sessionname> positional The `--session <name>` flag was semantically required but syntactically optional, which is an anti-pattern. Required + flag is a contradiction: flag form implies "optional", required is a runtime patch on top. Session is OpenCLI's "operation target" identifier — the natural form for that is a positional argument, like `docker exec <container> <cmd>` or `git checkout <branch>`. New surface: opencli browser <sessionname> open https://x.com opencli browser <sessionname> click 12 opencli browser <sessionname> bind opencli browser <sessionname> unbind Commander 14 cannot natively combine a parent positional with subcommand dispatch — the parent's positional is shadowed by subcommand matching. To bridge that, main.ts now pre-processes argv: when the token after `browser` is non-flag and not a known subcommand name, it is treated as the sessionname and rewritten to the internal `--session <name>` flag form before commander parses it. Help text on the `browser` command is overridden via `.usage('<sessionname> <command> [options]')` so users see the positional form. Reserved subcommand names (33) are listed in cli-argv-preprocess.ts and tested for parity with cli.ts subcommand registrations. If a future subcommand is added, the test fails loudly. Synced surfaces: - README.md / README.zh-CN.md — all examples - docs/guide/browser-bridge.md (+ zh) - skills/opencli-browser/SKILL.md (bind/unbind, examples, table) - skills/opencli-usage/SKILL.md - tests/e2e/browser-tabs.test.ts - CHANGELOG.md (Unreleased BREAKING) The internal `--session` flag and the unit tests calling `program.parseAsync(['...', 'browser', '--session', 'foo', ...])` are preserved as a stable internal API: tests bypass main.ts pre-processing and exercise commander directly. The pre-processor has its own targeted test file (cli-argv-preprocess.test.ts, 10 tests, all green). Verification: - npx tsc --noEmit — pass - npx vitest run --project unit — 1073/1074 pass (1 unrelated skip) - npx vitest run --project extension — 61/61 pass - npm run check:typed-error-lint — baseline 189 - npm run check:silent-column-drop — baseline 103 * fix(cli-argv): only rewrite when `browser` is the root command The preprocessor was looping through every argv slot and would mis-rewrite occurrences of the literal word `browser` deeper in argv (e.g. `opencli adapter init browser/x` or arg values containing `browser`). Now the preprocessor walks past leading root flags + their values to identify the root command token, and only acts when that token is `browser`. The full set of root value-consuming flags (`ROOT_VALUE_FLAGS`) is documented inline and kept in sync with the `program.option()` calls in cli.ts. Adds regression tests: - `opencli adapter init browser x` not rewritten - URL/path values containing `browser` not rewritten - `list browser state` (different root command) not rewritten - `--profile work browser foo state` correctly identifies `foo` as sessionname (not as --profile's value) - `--profile=work` long-form-with-equals consumes one slot only - boolean flags (`-v`) don't consume the next value 12/12 preprocessor tests pass. * fix(cli-argv): hide --session flag, fail-fast on retired form, rename to <session> Three blockers in #1505 review: 1. `--session` flag was still visible in `opencli browser --help` and could be used as a public entrance, contradicting "positional only" UX. Fix: switch from `.requiredOption()` to `.addOption(new Option(...).hideHelp())`. The flag is preserved as an internal API for the daemon protocol and direct `program.parseAsync` callers (tests), but is no longer documented or surfaced in structured help. 2. `opencli browser --session foo state` still succeeded. Now the argv preprocessor throws `BrowserSessionArgvError` when root `browser` is followed by `--session`, and main.ts catches it and exits with a user-facing usage error pointing to the positional form. 3. Missing-session error message exposed the internal flag: `required option '--session <name>' not specified`. Now `getBrowserSession()` in the action body throws `<session> is a required positional argument: opencli browser <session> <command>`, and commander no longer guards the hidden option. Also (per @WAWQAQ) rename placeholder `<sessionname>` -> `<session>` everywhere user-facing — shorter, matches CLI convention. The help text "<session> is a required positional: pass the name of the browser session..." carries the "name" semantics in description, not in the placeholder itself. Sync surfaces: - src/cli.ts — usage line, addOption with hideHelp, descriptions - src/cli-argv-preprocess.ts — throw on --session form - src/cli-argv-preprocess.test.ts — refusal test for old form - src/cli.test.ts — assertions updated for hidden option + new error path - src/help.ts — read `_usage` private field to respect `.usage()` override (commander's `.usage()` getter returns auto-generated form if not set, which would otherwise pollute every namespace's usage string) - src/main.ts — catch BrowserSessionArgvError, stderr + exit - README.md / README.zh-CN.md - docs/guide/browser-bridge.md / docs/zh/guide/browser-bridge.md - skills/opencli-browser/SKILL.md / skills/opencli-usage/SKILL.md - CHANGELOG.md Manual smoke tests (against built dist): - `opencli browser --help` shows `Usage: opencli browser <session> <command> [options]` - `opencli browser --help` Options block does NOT show `--session` - `opencli browser --session foo state` → friendly error, no commander stacktrace - `opencli browser state` → `<session> is a required positional argument: opencli browser <session> <command>` - `opencli browser foo state` → parses correctly * fix: inject <session> into subcommand help paths and drop stale sessions ref Two follow-up blockers from #1505 review: 1. Subcommand help and structured help still rendered the command path without the parent's positional. `opencli browser foo state --help` showed `Usage: opencli browser state [options]`, which would lead users (and agents reading structured help) to think `opencli browser state` was a valid invocation. Now: - `commanderPath()` injects an ancestor's leading-positional placeholder (extracted from its `.usage()` override) between the ancestor's name and the next path segment when building paths upward. - `commandPathFromRoot()` strips placeholder segments (e.g. `<session>`) from the relative `name` field so agents can still address subcommands by their leaf name; placeholders remain in the `command` / `usage` display paths. - `program.configureHelp({ commandUsage: ... })` is applied recursively to every descendant of `browser`, because commander does NOT inherit `configureHelp` into subcommands. Result: opencli browser <session> click --help -> Usage: opencli browser <session> click [target] [options] Daemon, plugin, adapter, profile namespaces (no `.usage()` override) are unaffected. 2. `skills/opencli-browser/SKILL.md` still referenced `opencli browser sessions`, which was removed in #1470. Replaced the sentence with the underlying invariant ("Bound sessions have no OpenCLI idle-close timer; the binding lasts until `unbind`, tab close, window close, or daemon restart") without mentioning the deleted command. Tests: - cli.test.ts: structured help expectations updated to include `<session>` in command/usage paths (3 tests) - cli-argv-preprocess.test.ts: 12 tests still green - 1136/1137 unit+extension green (1 unrelated skip) - typed-error-lint baseline 189 - silent-column-drop baseline 103
1 parent fa9b38c commit 0e168d5

14 files changed

Lines changed: 500 additions & 120 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### ⚠ BREAKING CHANGES
6+
7+
* **browser** — replace the `--session <name>` flag with a `<session>` positional argument that immediately follows `browser`. `opencli browser work click 12` instead of `opencli browser --session work click 12`; `opencli browser work bind` instead of `opencli browser bind --session work`. Required-flag semantics are now encoded structurally as a positional, matching the Docker/git convention for required operation-target identifiers. The internal `--session` flag is preserved for the daemon protocol and for direct `program.parseAsync` callers but is no longer part of the user-facing surface.
8+
39
## [1.7.18](https://github.com/jackwener/opencli/compare/v1.7.17...v1.7.18) (2026-05-12)
410

511
Hotfix release for the 1.7.17 doctor regression: `opencli doctor` failed connectivity probe with `Browser session is required` because the doctor probe didn't pass a session to the new strict-session browser bridge. Also adds new adapters and adapter fixes that were ready immediately after 1.7.17.

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,15 @@ The agent handles all the `opencli browser` commands internally — you just des
152152

153153
Available browser commands include `open`, `state`, `click`, `type`, `fill`, `select`, `keys`, `wait`, `get`, `find`, `extract`, `frames`, `screenshot`, `scroll`, `back`, `eval`, `network`, `tab list`, `tab new`, `tab select`, `tab close`, `init`, `verify`, and `close`.
154154

155-
`opencli browser` commands require `--session <name>`. `opencli browser --session work open <url>` and `opencli browser --session work tab new [url]` both return a target ID. Use `opencli browser --session work tab list` to inspect target IDs, then pass `--tab <targetId>` to route a command to a specific tab. `tab new` creates a new tab without changing the default browser target; only `tab select <targetId>` promotes that tab to the default target for later untargeted commands in the same session.
155+
`opencli browser` commands require a `<session>` positional immediately after `browser`. `opencli browser work open <url>` and `opencli browser work tab new [url]` both return a target ID. Use `opencli browser work tab list` to inspect target IDs, then pass `--tab <targetId>` to route a command to a specific tab. `tab new` creates a new tab without changing the default browser target; only `tab select <targetId>` promotes that tab to the default target for later untargeted commands in the same session.
156156

157157
## Core Concepts
158158

159159
### `browser`: AI Agent browser control
160160

161161
`opencli browser` commands are the low-level primitives that AI Agents use to operate websites. You don't run these manually — instead, install the `opencli-adapter-author` skill into your AI agent, describe what you want in natural language, and the agent handles the browser operations.
162162

163-
For example, tell your agent: *"Help me check my Xiaohongshu notifications"* — the agent will use `opencli browser --session <name> open`, `state`, `click`, etc. under the hood.
163+
For example, tell your agent: *"Help me check my Xiaohongshu notifications"* — the agent will use `opencli browser <session> open`, `state`, `click`, etc. under the hood.
164164

165165
### Built-in adapters: stable commands
166166

@@ -174,7 +174,7 @@ When the site you need is not yet covered, use the `opencli-adapter-author` skil
174174
2. Discover the right endpoint — network inspection, initial state, bundle search, token trace, or interceptor fallback.
175175
3. Decide the auth strategy — `PUBLIC` / `COOKIE` / `INTERCEPT` / `UI` / `LOCAL`.
176176
4. Decode response fields and design output columns.
177-
5. `opencli browser --session recon analyze <url>` for one-shot recon, then `opencli browser --session recon init <site>/<name>` → write adapter → `opencli browser --session recon verify <site>/<name>`.
177+
5. `opencli browser recon analyze <url>` for one-shot recon, then `opencli browser recon init <site>/<name>` → write adapter → `opencli browser recon verify <site>/<name>`.
178178
6. Persist site knowledge to `~/.opencli/sites/<site>/` so the next adapter for the same site is faster.
179179

180180
### CLI Hub and desktop adapters
@@ -207,7 +207,7 @@ OpenCLI is not only for websites. It can also:
207207
| `OPENCLI_VERBOSE` | `false` | Enable verbose logging (`-v` flag also works) |
208208
| `DEBUG_SNAPSHOT` || Set to `1` for DOM snapshot debug output |
209209

210-
`opencli browser *` requires an explicit `--session <name>`, uses a foreground browser window by default, and keeps that session's tab lease until `browser --session <name> close` or idle cleanup. Browser-backed adapters use a background adapter window and release one-shot tab leases by default. Interactive adapters can declare `siteSession: 'persistent'` to keep a stable site tab for continuity; pass `--site-session ephemeral` for a one-shot tab.
210+
`opencli browser *` requires an explicit `<session>` positional, uses a foreground browser window by default, and keeps that session's tab lease until `opencli browser <session> close` or idle cleanup. Browser-backed adapters use a background adapter window and release one-shot tab leases by default. Interactive adapters can declare `siteSession: 'persistent'` to keep a stable site tab for continuity; pass `--site-session ephemeral` for a one-shot tab.
211211

212212
## Update
213213

@@ -411,10 +411,10 @@ See [Plugins Guide](./docs/guide/plugins.md) for creating your own plugin.
411411
Before writing any adapter code, read the [`opencli-adapter-author` skill](./skills/opencli-adapter-author/SKILL.md). It takes you end-to-end:
412412

413413
- Recon the site and pick a pattern (SPA / SSR / JSONP / Token / Streaming).
414-
- Discover the right endpoint via `opencli browser --session <name> network`, `eval`, or the interceptor fallback.
414+
- Discover the right endpoint via `opencli browser <session> network`, `eval`, or the interceptor fallback.
415415
- Decide auth strategy (`PUBLIC` / `COOKIE` / `INTERCEPT` / `UI` / `LOCAL`).
416-
- Run `opencli browser --session recon analyze <url>` for one-shot recon, decode response fields, design columns, scaffold with `opencli browser --session recon init`.
417-
- Verify with `opencli browser --session recon verify <site>/<name>` before shipping.
416+
- Run `opencli browser recon analyze <url>` for one-shot recon, decode response fields, design columns, scaffold with `opencli browser recon init`.
417+
- Verify with `opencli browser recon verify <site>/<name>` before shipping.
418418

419419
For long-lived personal commands that should live in your own Git repo, use a local plugin instead; see [Extending OpenCLI](./docs/guide/extending-opencli.md). Quick private adapters can still live at `~/.opencli/clis/<site>/<name>.js`. Site knowledge (endpoints, field maps, fixtures) accumulates in `~/.opencli/sites/<site>/` so the next adapter for the same site starts from context instead of zero.
420420

README.zh-CN.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,15 @@ Agent 在内部自动处理所有 `opencli browser` 命令——你只需用自
136136

137137
`browser` 可用命令包括:`open``state``click``type``fill``select``keys``wait``get``find``extract``frames``screenshot``scroll``back``eval``network``tab list``tab new``tab select``tab close``init``verify``close`
138138

139-
`opencli browser` 命令必须显式传 `--session <name>``opencli browser --session work open <url>``opencli browser --session work tab new [url]` 都会返回 target ID。`opencli browser --session work tab list` 用来查看当前已存在 tab 的 target ID,再通过 `--tab <targetId>` 把命令明确路由到某个 tab。`tab new` 只会新建 tab,不会改变默认浏览器目标;只有显式执行 `tab select <targetId>`,才会把该 tab 设为同一 session 后续未指定 target 的默认目标。
139+
`opencli browser` 命令必须紧跟一个 `<session>` 位置参数`opencli browser work open <url>``opencli browser work tab new [url]` 都会返回 target ID。`opencli browser work tab list` 用来查看当前已存在 tab 的 target ID,再通过 `--tab <targetId>` 把命令明确路由到某个 tab。`tab new` 只会新建 tab,不会改变默认浏览器目标;只有显式执行 `tab select <targetId>`,才会把该 tab 设为同一 session 后续未指定 target 的默认目标。
140140

141141
## 核心概念
142142

143143
### `browser`:AI Agent 的浏览器控制层
144144

145145
`opencli browser` 命令是 AI Agent 操作网站的底层原语。你不需要手动运行这些命令——把 `opencli-adapter-author` skill 安装到你的 AI Agent 中,用自然语言描述你想做的事,Agent 会自动处理浏览器操作。
146146

147-
比如你告诉 Agent:*"帮我看看小红书的通知"*——Agent 会在底层调用 `opencli browser --session <name> open``state``click` 等命令。
147+
比如你告诉 Agent:*"帮我看看小红书的通知"*——Agent 会在底层调用 `opencli browser <session> open``state``click` 等命令。
148148

149149
### 内置适配器:稳定命令
150150

@@ -158,7 +158,7 @@ Agent 在内部自动处理所有 `opencli browser` 命令——你只需用自
158158
2. 发现目标 endpoint——network 精读、initial state、bundle 搜索、token 溯源,或 interceptor 兜底
159159
3. 定认证策略——`PUBLIC` / `COOKIE` / `INTERCEPT` / `UI` / `LOCAL`
160160
4. 字段解码 + 设计输出列
161-
5. `opencli browser --session recon analyze <url>` 一步侦察,再 `opencli browser --session recon init <site>/<name>` → 写适配器 → `opencli browser --session recon verify <site>/<name>`
161+
5. `opencli browser recon analyze <url>` 一步侦察,再 `opencli browser recon init <site>/<name>` → 写适配器 → `opencli browser recon verify <site>/<name>`
162162
6. 把站点知识沉到 `~/.opencli/sites/<site>/`,下次写同站点的其他命令直接吃缓存
163163

164164
### CLI 枢纽与桌面端适配器
@@ -190,7 +190,7 @@ OpenCLI 不只是网站 CLI,还可以:
190190
| `OPENCLI_VERBOSE` | `false` | 启用详细日志(`-v` 也可以) |
191191
| `DEBUG_SNAPSHOT` || 设为 `1` 输出 DOM 快照调试信息 |
192192

193-
`opencli browser *` 必须显式传 `--session <name>`,默认使用前台窗口,并保留该 session 的 tab lease,直到你手动执行 `opencli browser --session <name> close` 或等空闲超时。浏览器型 adapter 默认使用后台 adapter 窗口并在命令结束后释放一次性 tab lease;如果需要调试最终页面,可以传 `--window foreground --keep-tab true`
193+
`opencli browser *` 必须紧跟一个 `<session>` 位置参数,默认使用前台窗口,并保留该 session 的 tab lease,直到你手动执行 `opencli browser <session> close` 或等空闲超时。浏览器型 adapter 默认使用后台 adapter 窗口并在命令结束后释放一次性 tab lease;如果需要调试最终页面,可以传 `--window foreground --keep-tab true`
194194

195195
## 更新
196196

@@ -510,10 +510,10 @@ opencli plugin uninstall my-tool # 卸载
510510
在动代码前,先读 [`opencli-adapter-author` skill](./skills/opencli-adapter-author/SKILL.md)。它把整个流程串起来:
511511

512512
- 侦察站点,选定 pattern(SPA / SSR / JSONP / Token / Streaming)
513-
-`opencli browser --session <name> network``eval`、interceptor 等找到目标 endpoint
513+
-`opencli browser <name> network``eval`、interceptor 等找到目标 endpoint
514514
- 定认证策略(`PUBLIC` / `COOKIE` / `INTERCEPT` / `UI` / `LOCAL`
515-
- 先用 `opencli browser --session recon analyze <url>` 一步侦察,再字段解码、设计 columns、`opencli browser --session recon init` 生成骨架
516-
- 交付前用 `opencli browser --session recon verify <site>/<name>` 验证
515+
- 先用 `opencli browser recon analyze <url>` 一步侦察,再字段解码、设计 columns、`opencli browser recon init` 生成骨架
516+
- 交付前用 `opencli browser recon verify <site>/<name>` 验证
517517

518518
在仓库外写的私有适配器放到 `~/.opencli/clis/<site>/<name>.js`;每个站点的 endpoint、字段映射、抓包样本会累积在 `~/.opencli/sites/<site>/`,下次写同站点的其他命令可以直接复用。
519519

docs/guide/browser-bridge.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,22 @@ opencli doctor # Check extension + daemon connectivity
2727

2828
## Tab Targeting
2929

30-
Browser commands require an explicit `--session <name>`. Use the same session name for a multi-step flow, and use different names to isolate parallel work.
30+
Browser commands require an explicit `<session>` positional immediately after `browser`. Use the same session name for a multi-step flow, and use different names to isolate parallel work.
3131

3232
```bash
33-
opencli browser --session baidu open https://www.baidu.com/
34-
opencli browser --session baidu tab list
35-
opencli browser --session baidu tab new https://www.baidu.com/
36-
opencli browser --session baidu eval --tab <targetId> 'document.title'
37-
opencli browser --session baidu tab select <targetId>
38-
opencli browser --session baidu get title
39-
opencli browser --session baidu tab close <targetId>
33+
opencli browser baidu open https://www.baidu.com/
34+
opencli browser baidu tab list
35+
opencli browser baidu tab new https://www.baidu.com/
36+
opencli browser baidu eval --tab <targetId> 'document.title'
37+
opencli browser baidu tab select <targetId>
38+
opencli browser baidu get title
39+
opencli browser baidu tab close <targetId>
4040
```
4141
4242
Key rules:
4343
44-
- `opencli browser --session <name> open <url>` and `opencli browser --session <name> tab new [url]` return a `targetId`.
45-
- `opencli browser --session <name> tab list` prints the `targetId` values of tabs that already exist.
44+
- `opencli browser <session> open <url>` and `opencli browser <session> tab new [url]` return a `targetId`.
45+
- `opencli browser <session> tab list` prints the `targetId` values of tabs that already exist.
4646
- `--tab <targetId>` routes a single browser command to that specific tab.
4747
- `tab new` creates a new tab but does not change the default browser target.
4848
- `tab select <targetId>` makes that tab the default target for later untargeted `opencli browser ...` commands.

docs/zh/guide/browser-bridge.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,22 @@ opencli doctor # 检查扩展 + 守护进程连接
2525

2626
## 多 Tab 定位
2727

28-
浏览器命令必须显式传 `--session <name>`。同一个多步骤流程使用同一个 session;并行任务使用不同 session 隔离。
28+
浏览器命令必须紧跟一个 `<session>` 位置参数。同一个多步骤流程使用同一个 session;并行任务使用不同 session 隔离。
2929

3030
```bash
31-
opencli browser --session baidu open https://www.baidu.com/
32-
opencli browser --session baidu tab list
33-
opencli browser --session baidu tab new https://www.baidu.com/
34-
opencli browser --session baidu eval --tab <targetId> 'document.title'
35-
opencli browser --session baidu tab select <targetId>
36-
opencli browser --session baidu get title
37-
opencli browser --session baidu tab close <targetId>
31+
opencli browser baidu open https://www.baidu.com/
32+
opencli browser baidu tab list
33+
opencli browser baidu tab new https://www.baidu.com/
34+
opencli browser baidu eval --tab <targetId> 'document.title'
35+
opencli browser baidu tab select <targetId>
36+
opencli browser baidu get title
37+
opencli browser baidu tab close <targetId>
3838
```
3939
4040
规则如下:
4141
42-
- `opencli browser --session <name> open <url>``opencli browser --session <name> tab new [url]` 都会返回 `targetId`
43-
- `opencli browser --session <name> tab list` 会打印当前已存在 tab 的 `targetId`
42+
- `opencli browser <session> open <url>``opencli browser <session> tab new [url]` 都会返回 `targetId`
43+
- `opencli browser <session> tab list` 会打印当前已存在 tab 的 `targetId`
4444
- `--tab <targetId>` 会把单条 browser 命令路由到对应 tab。
4545
- `tab new` 只会新建 tab,不会改变默认浏览器目标。
4646
- `tab select <targetId>` 会把该 tab 设为后续未显式指定 target 的 `opencli browser ...` 命令默认目标。

0 commit comments

Comments
 (0)