Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### ⚠ BREAKING CHANGES

* **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.
* **env** — remove `OPENCLI_KEEP_TAB`. The flag was a debugging shortcut, not a config dimension: `--keep-tab true|false` on the command line is the single source of truth, and adapter `siteSession: 'persistent'` already pins persistent site tabs as a hard constraint. Removing the env eliminates a globally-leaking process state that overrode every browser command in the shell.

## [1.7.18](https://github.com/jackwener/opencli/compare/v1.7.17...v1.7.18) (2026-05-12)

Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ OpenCLI is not only for websites. It can also:
| `OPENCLI_DAEMON_PORT` | `19825` | HTTP port for the daemon-extension bridge |
| `OPENCLI_PROFILE` | — | Browser Bridge profile alias/contextId to use when multiple Chrome profiles are connected |
| `OPENCLI_WINDOW` | command default | Set to `foreground` or `background` to override Browser Bridge window placement. Browser-backed commands also accept `--window <foreground\|background>`. |
| `OPENCLI_KEEP_TAB` | command default | Set to `true` or `false` to keep or release the browser tab lease after a browser-backed adapter command. Browser-backed adapter commands also accept `--keep-tab <true\|false>`. |
| `OPENCLI_BROWSER_CONNECT_TIMEOUT` | `30` | Seconds to wait for browser connection |
| `OPENCLI_BROWSER_COMMAND_TIMEOUT` | `60` | Seconds to wait for a single browser command |
| `OPENCLI_CDP_ENDPOINT` | — | Chrome DevTools Protocol endpoint for remote browser or Electron apps |
Expand Down
1 change: 0 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ OpenCLI 不只是网站 CLI,还可以:
|------|--------|------|
| `OPENCLI_DAEMON_PORT` | `19825` | daemon-extension 通信端口 |
| `OPENCLI_WINDOW` | 命令默认值 | 设为 `foreground` 或 `background` 来覆盖 Browser Bridge 窗口位置。浏览器型命令也支持 `--window <foreground\|background>` |
| `OPENCLI_KEEP_TAB` | 命令默认值 | 设为 `true` 或 `false` 来控制浏览器型 adapter 命令结束后是否保留 tab lease。浏览器型 adapter 命令也支持 `--keep-tab <true\|false>` |
| `OPENCLI_BROWSER_CONNECT_TIMEOUT` | `30` | 浏览器连接超时(秒) |
| `OPENCLI_BROWSER_COMMAND_TIMEOUT` | `60` | 单个浏览器命令超时(秒) |
| `OPENCLI_CDP_ENDPOINT` | — | Chrome DevTools Protocol 端点,用于远程浏览器或 Electron 应用 |
Expand Down
1 change: 0 additions & 1 deletion skills/opencli-usage/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ A few commands override the default via `cmd.defaultFormat` (e.g. chat commands
| `OPENCLI_CDP_ENDPOINT` | — | Manual CDP endpoint override (dev / remote Chrome / Electron). |
| `OPENCLI_CACHE_DIR` | `~/.opencli/cache` | Network capture + browser-state cache. |
| `OPENCLI_WINDOW` | command-specific | `foreground` or `background` browser window mode. |
| `OPENCLI_KEEP_TAB` | command-specific | `true` or `false`; controls whether browser tab leases are kept after a command. |
| `OPENCLI_VERBOSE` | `false` | Verbose logging (also triggered by `-v`). |

## Self-repair
Expand Down
16 changes: 4 additions & 12 deletions src/execution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,15 +440,13 @@ describe('executeCommand — non-browser timeout', () => {
vi.restoreAllMocks();
});

it('skips closeWindow when OPENCLI_KEEP_TAB=true (success path)', async () => {
it('skips closeWindow when --keep-tab=true (success path)', async () => {
const closeWindow = vi.fn().mockResolvedValue(undefined);
const mockPage = { closeWindow } as any;

vi.spyOn(capRouting, 'shouldUseBrowserSession').mockReturnValue(true);
vi.spyOn(runtime, 'browserSession').mockImplementation(async (_Factory, fn) => fn(mockPage));

const prev = process.env.OPENCLI_KEEP_TAB;
process.env.OPENCLI_KEEP_TAB = 'true';
try {
const cmd = cli({
site: 'test-execution',
Expand All @@ -459,24 +457,20 @@ describe('executeCommand — non-browser timeout', () => {
func: async () => [{ ok: true }],
});

await executeCommand(cmd, {});
await executeCommand(cmd, {}, false, { keepTab: 'true' });
expect(closeWindow).not.toHaveBeenCalled();
} finally {
if (prev === undefined) delete process.env.OPENCLI_KEEP_TAB;
else process.env.OPENCLI_KEEP_TAB = prev;
vi.restoreAllMocks();
}
});

it('skips closeWindow when OPENCLI_KEEP_TAB=true (failure path)', async () => {
it('skips closeWindow when --keep-tab=true (failure path)', async () => {
const closeWindow = vi.fn().mockResolvedValue(undefined);
const mockPage = { closeWindow } as any;

vi.spyOn(capRouting, 'shouldUseBrowserSession').mockReturnValue(true);
vi.spyOn(runtime, 'browserSession').mockImplementation(async (_Factory, fn) => fn(mockPage));

const prev = process.env.OPENCLI_KEEP_TAB;
process.env.OPENCLI_KEEP_TAB = 'true';
try {
const cmd = cli({
site: 'test-execution',
Expand All @@ -487,11 +481,9 @@ describe('executeCommand — non-browser timeout', () => {
func: async () => { throw new Error('adapter failure'); },
});

await expect(executeCommand(cmd, {})).rejects.toThrow('adapter failure');
await expect(executeCommand(cmd, {}, false, { keepTab: 'true' })).rejects.toThrow('adapter failure');
expect(closeWindow).not.toHaveBeenCalled();
} finally {
if (prev === undefined) delete process.env.OPENCLI_KEEP_TAB;
else process.env.OPENCLI_KEEP_TAB = prev;
vi.restoreAllMocks();
}
});
Expand Down
4 changes: 1 addition & 3 deletions src/execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,9 +511,7 @@ function normalizeBooleanOption(name: string, raw: unknown): boolean | null {

function resolveKeepTab(siteSession: SiteSessionMode, rawOption?: unknown): boolean {
if (siteSession === 'persistent') return true;
return normalizeBooleanOption('--keep-tab', rawOption)
?? normalizeBooleanOption('OPENCLI_KEEP_TAB', process.env.OPENCLI_KEEP_TAB)
?? false;
return normalizeBooleanOption('--keep-tab', rawOption) ?? false;
}

function normalizeWindowMode(name: string, raw: unknown): BrowserWindowMode | null {
Expand Down
Loading