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
102 changes: 102 additions & 0 deletions src/cli-argv-preprocess.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,108 @@ describe('rewriteBrowserArgv', () => {
]);
});

it('hoists a trailing browser --window option to the namespace slot', () => {
expect(rewriteBrowserArgv(['browser', 'work', 'open', 'https://x.com', '--window', 'background'])).toEqual([
'browser',
'--session',
'work',
'--window',
'background',
'open',
'https://x.com',
]);
expect(rewriteBrowserArgv(['browser', 'work', 'state', '--window', 'foreground'])).toEqual([
'browser',
'--session',
'work',
'--window',
'foreground',
'state',
]);
});

it('hoists trailing browser --window after leading root options', () => {
expect(rewriteBrowserArgv(['--profile', 'sandbox', 'browser', 'work', 'state', '--window', 'background'])).toEqual([
'--profile',
'sandbox',
'browser',
'--session',
'work',
'--window',
'background',
'state',
]);
});

it('hoists a trailing browser --window=<mode> option', () => {
expect(rewriteBrowserArgv(['browser', 'work', 'open', 'https://x.com', '--window=background'])).toEqual([
'browser',
'--session',
'work',
'--window=background',
'open',
'https://x.com',
]);
});

it('hoists browser --window after nested browser leaf commands', () => {
expect(rewriteBrowserArgv(['browser', 'work', 'get', 'url', '--window', 'background'])).toEqual([
'browser',
'--session',
'work',
'--window',
'background',
'get',
'url',
]);
expect(rewriteBrowserArgv(['browser', 'work', 'tab', 'close', 'abc123', '--window', 'background'])).toEqual([
'browser',
'--session',
'work',
'--window',
'background',
'tab',
'close',
'abc123',
]);
});

it('leaves an already parent-slot browser --window option untouched', () => {
expect(rewriteBrowserArgv(['browser', 'work', '--window', 'background', 'open', 'https://x.com'])).toEqual([
'browser',
'--session',
'work',
'--window',
'background',
'open',
'https://x.com',
]);
});

it('does not hoist browser --window after a literal -- separator', () => {
expect(rewriteBrowserArgv(['browser', 'work', 'eval', 'console.log(1)', '--', '--window', 'background'])).toEqual([
'browser',
'--session',
'work',
'eval',
'console.log(1)',
'--',
'--window',
'background',
]);
});

it('does not hoist a bare trailing browser --window without a value', () => {
expect(rewriteBrowserArgv(['browser', 'work', 'open', 'https://x.com', '--window'])).toEqual([
'browser',
'--session',
'work',
'open',
'https://x.com',
'--window',
]);
});

it('leaves argv alone when the root command is not `browser`, even if `browser` appears later', () => {
// The first browser keyword does NOT win — it must be at the root.
expect(rewriteBrowserArgv(['twitter', 'browser', 'work', 'state'])).toEqual([
Expand Down
33 changes: 33 additions & 0 deletions src/cli-argv-preprocess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,42 @@ export function rewriteBrowserArgv(argv: readonly string[]): string[] {
if (BROWSER_SUBCOMMAND_NAMES.has(next)) return result;
// Splice in --session <name> in place of the positional.
result.splice(sessionIdx, 1, '--session', next);
// `--window` is a browser namespace option, so commander accepts it before the
// leaf command. Users naturally put it at the end:
// `browser work open https://x.com --window background`. Hoist that public
// form into the namespace-option slot instead of mirroring the option onto
// every browser leaf command.
hoistBrowserWindowOption(result, sessionIdx + 2);
return result;
}

/**
* Move one trailing `--window <mode>` / `--window=<mode>` from after the browser
* subcommand to just before it. Stops at `--` so literal browser arguments are
* untouched. Mutates `argv` in place.
*/
function hoistBrowserWindowOption(argv: string[], fromIndex: number): void {
const subcommandIdx = argv.findIndex((tok, idx) => idx >= fromIndex && BROWSER_SUBCOMMAND_NAMES.has(tok));
if (subcommandIdx === -1) return;

for (let i = subcommandIdx + 1; i < argv.length; i += 1) {
const tok = argv[i];
if (tok === '--') return;
if (tok.startsWith('--window=')) {
const removed = argv.splice(i, 1);
argv.splice(subcommandIdx, 0, ...removed);
return;
}
if (tok === '--window') {
const value = argv[i + 1];
if (value === undefined || value === '--') return;
const removed = argv.splice(i, 2);
argv.splice(subcommandIdx, 0, ...removed);
return;
}
}
}

/**
* Thrown by the preprocessor when user argv uses a retired/old form that we
* intentionally refuse to accept. main.ts catches this and exits with a
Expand Down
1 change: 1 addition & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,7 @@ export function createProgram(BUILTIN_CLIS: string, USER_CLIS: string): Command

Examples:
$ opencli browser work open https://x.com
$ opencli browser work open https://x.com --window background
$ opencli browser work click 12
$ opencli browser work state
$ opencli browser work bind
Expand Down