@jackwener/opencli 1.7.5 → 1.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/README.zh-CN.md +5 -2
- package/cli-manifest.json +77 -1
- package/clis/bilibili/video.js +61 -0
- package/clis/bilibili/video.test.js +81 -0
- package/clis/deepseek/ask.js +21 -1
- package/clis/deepseek/ask.test.js +73 -0
- package/clis/deepseek/utils.js +84 -1
- package/clis/deepseek/utils.test.js +37 -0
- package/clis/jianyu/search.js +139 -3
- package/clis/jianyu/search.test.js +25 -0
- package/clis/jianyu/shared/procurement-detail.js +15 -0
- package/clis/jianyu/shared/procurement-detail.test.js +12 -0
- package/clis/twitter/shared.js +7 -2
- package/clis/twitter/tweets.js +218 -0
- package/clis/twitter/tweets.test.js +125 -0
- package/clis/youtube/channel.js +35 -0
- package/dist/src/browser/base-page.d.ts +13 -3
- package/dist/src/browser/base-page.js +35 -25
- package/dist/src/browser/cdp.d.ts +1 -0
- package/dist/src/browser/cdp.js +12 -3
- package/dist/src/browser/compound.d.ts +59 -0
- package/dist/src/browser/compound.js +112 -0
- package/dist/src/browser/compound.test.d.ts +1 -0
- package/dist/src/browser/compound.test.js +175 -0
- package/dist/src/browser/dom-snapshot.d.ts +7 -0
- package/dist/src/browser/dom-snapshot.js +76 -3
- package/dist/src/browser/dom-snapshot.test.js +65 -0
- package/dist/src/browser/extract.d.ts +69 -0
- package/dist/src/browser/extract.js +132 -0
- package/dist/src/browser/extract.test.d.ts +1 -0
- package/dist/src/browser/extract.test.js +129 -0
- package/dist/src/browser/find.d.ts +76 -0
- package/dist/src/browser/find.js +179 -0
- package/dist/src/browser/find.test.d.ts +1 -0
- package/dist/src/browser/find.test.js +120 -0
- package/dist/src/browser/html-tree.d.ts +75 -0
- package/dist/src/browser/html-tree.js +112 -0
- package/dist/src/browser/html-tree.test.d.ts +1 -0
- package/dist/src/browser/html-tree.test.js +181 -0
- package/dist/src/browser/network-cache.d.ts +48 -0
- package/dist/src/browser/network-cache.js +66 -0
- package/dist/src/browser/network-cache.test.d.ts +1 -0
- package/dist/src/browser/network-cache.test.js +58 -0
- package/dist/src/browser/network-key.d.ts +22 -0
- package/dist/src/browser/network-key.js +66 -0
- package/dist/src/browser/network-key.test.d.ts +1 -0
- package/dist/src/browser/network-key.test.js +49 -0
- package/dist/src/browser/shape-filter.d.ts +52 -0
- package/dist/src/browser/shape-filter.js +101 -0
- package/dist/src/browser/shape-filter.test.d.ts +1 -0
- package/dist/src/browser/shape-filter.test.js +101 -0
- package/dist/src/browser/shape.d.ts +23 -0
- package/dist/src/browser/shape.js +95 -0
- package/dist/src/browser/shape.test.d.ts +1 -0
- package/dist/src/browser/shape.test.js +82 -0
- package/dist/src/browser/target-errors.d.ts +14 -1
- package/dist/src/browser/target-errors.js +13 -0
- package/dist/src/browser/target-errors.test.js +39 -6
- package/dist/src/browser/target-resolver.d.ts +57 -10
- package/dist/src/browser/target-resolver.js +195 -75
- package/dist/src/browser/target-resolver.test.js +80 -5
- package/dist/src/cli.js +630 -125
- package/dist/src/cli.test.js +794 -0
- package/dist/src/execution.js +7 -2
- package/dist/src/execution.test.js +54 -0
- package/dist/src/main.js +16 -0
- package/dist/src/types.d.ts +18 -3
- package/package.json +1 -1
package/dist/src/execution.js
CHANGED
|
@@ -185,6 +185,9 @@ export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
|
185
185
|
throw new CommandExecutionError(`Pre-navigation to ${preNavUrl} failed: ${err instanceof Error ? err.message : err}`, 'Check that the site is reachable and the browser extension is running.');
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
+
// --live / OPENCLI_LIVE=1 keeps the automation window open after the
|
|
189
|
+
// command finishes, so agents (or humans) can inspect the page state.
|
|
190
|
+
const keepOpen = process.env.OPENCLI_LIVE === '1' || process.env.OPENCLI_LIVE === 'true';
|
|
188
191
|
try {
|
|
189
192
|
const result = await runWithTimeout(runCommand(cmd, page, kwargs, debug), {
|
|
190
193
|
timeout: cmd.timeoutSeconds ?? DEFAULT_BROWSER_COMMAND_TIMEOUT,
|
|
@@ -192,7 +195,8 @@ export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
|
192
195
|
});
|
|
193
196
|
// Adapter commands are one-shot — close the automation window immediately
|
|
194
197
|
// instead of waiting for the 30s idle timeout.
|
|
195
|
-
|
|
198
|
+
if (!keepOpen)
|
|
199
|
+
await page.closeWindow?.().catch(() => { });
|
|
196
200
|
return result;
|
|
197
201
|
}
|
|
198
202
|
catch (err) {
|
|
@@ -206,7 +210,8 @@ export async function executeCommand(cmd, rawKwargs, debug = false, opts = {}) {
|
|
|
206
210
|
// Close the automation window on failure too — without this, the window
|
|
207
211
|
// lingers until the extension's idle timer fires (unreliable on Windows
|
|
208
212
|
// where MV3 service workers may be suspended before setTimeout triggers).
|
|
209
|
-
|
|
213
|
+
if (!keepOpen)
|
|
214
|
+
await page.closeWindow?.().catch(() => { });
|
|
210
215
|
throw err;
|
|
211
216
|
}
|
|
212
217
|
}, { workspace: `site:${cmd.site}`, cdpEndpoint });
|
|
@@ -60,6 +60,60 @@ describe('executeCommand — non-browser timeout', () => {
|
|
|
60
60
|
expect(closeWindow).toHaveBeenCalledTimes(1);
|
|
61
61
|
vi.restoreAllMocks();
|
|
62
62
|
});
|
|
63
|
+
it('skips closeWindow when OPENCLI_LIVE=1 (success path)', async () => {
|
|
64
|
+
const closeWindow = vi.fn().mockResolvedValue(undefined);
|
|
65
|
+
const mockPage = { closeWindow };
|
|
66
|
+
vi.spyOn(capRouting, 'shouldUseBrowserSession').mockReturnValue(true);
|
|
67
|
+
vi.spyOn(runtime, 'browserSession').mockImplementation(async (_Factory, fn) => fn(mockPage));
|
|
68
|
+
const prev = process.env.OPENCLI_LIVE;
|
|
69
|
+
process.env.OPENCLI_LIVE = '1';
|
|
70
|
+
try {
|
|
71
|
+
const cmd = cli({
|
|
72
|
+
site: 'test-execution',
|
|
73
|
+
name: 'browser-live-success',
|
|
74
|
+
description: 'test closeWindow skipped with --live on success',
|
|
75
|
+
browser: true,
|
|
76
|
+
strategy: Strategy.PUBLIC,
|
|
77
|
+
func: async () => [{ ok: true }],
|
|
78
|
+
});
|
|
79
|
+
await executeCommand(cmd, {});
|
|
80
|
+
expect(closeWindow).not.toHaveBeenCalled();
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
if (prev === undefined)
|
|
84
|
+
delete process.env.OPENCLI_LIVE;
|
|
85
|
+
else
|
|
86
|
+
process.env.OPENCLI_LIVE = prev;
|
|
87
|
+
vi.restoreAllMocks();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
it('skips closeWindow when OPENCLI_LIVE=1 (failure path)', async () => {
|
|
91
|
+
const closeWindow = vi.fn().mockResolvedValue(undefined);
|
|
92
|
+
const mockPage = { closeWindow };
|
|
93
|
+
vi.spyOn(capRouting, 'shouldUseBrowserSession').mockReturnValue(true);
|
|
94
|
+
vi.spyOn(runtime, 'browserSession').mockImplementation(async (_Factory, fn) => fn(mockPage));
|
|
95
|
+
const prev = process.env.OPENCLI_LIVE;
|
|
96
|
+
process.env.OPENCLI_LIVE = '1';
|
|
97
|
+
try {
|
|
98
|
+
const cmd = cli({
|
|
99
|
+
site: 'test-execution',
|
|
100
|
+
name: 'browser-live-failure',
|
|
101
|
+
description: 'test closeWindow skipped with --live on failure',
|
|
102
|
+
browser: true,
|
|
103
|
+
strategy: Strategy.PUBLIC,
|
|
104
|
+
func: async () => { throw new Error('adapter failure'); },
|
|
105
|
+
});
|
|
106
|
+
await expect(executeCommand(cmd, {})).rejects.toThrow('adapter failure');
|
|
107
|
+
expect(closeWindow).not.toHaveBeenCalled();
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
if (prev === undefined)
|
|
111
|
+
delete process.env.OPENCLI_LIVE;
|
|
112
|
+
else
|
|
113
|
+
process.env.OPENCLI_LIVE = prev;
|
|
114
|
+
vi.restoreAllMocks();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
63
117
|
it('does not re-run custom validation when args are already prepared', async () => {
|
|
64
118
|
const validateArgs = vi.fn();
|
|
65
119
|
const cmd = {
|
package/dist/src/main.js
CHANGED
|
@@ -26,6 +26,22 @@ const __dirname = path.dirname(__filename);
|
|
|
26
26
|
// Use findPackageRoot so the path works both in dev (src/main.ts) and prod (dist/src/main.js).
|
|
27
27
|
const BUILTIN_CLIS = path.join(findPackageRoot(__filename), 'clis');
|
|
28
28
|
const USER_CLIS = path.join(os.homedir(), '.opencli', 'clis');
|
|
29
|
+
// ── Session lifecycle flags ──────────────────────────────────────────────
|
|
30
|
+
// `--live` / `--focus` are top-level-ish toggles that tweak the automation
|
|
31
|
+
// window's lifecycle. We strip them from argv before Commander runs so they
|
|
32
|
+
// can be placed anywhere and work on any subcommand (adapter or browser).
|
|
33
|
+
{
|
|
34
|
+
const liveIdx = process.argv.indexOf('--live');
|
|
35
|
+
if (liveIdx !== -1) {
|
|
36
|
+
process.env.OPENCLI_LIVE = '1';
|
|
37
|
+
process.argv.splice(liveIdx, 1);
|
|
38
|
+
}
|
|
39
|
+
const focusIdx = process.argv.indexOf('--focus');
|
|
40
|
+
if (focusIdx !== -1) {
|
|
41
|
+
process.env.OPENCLI_WINDOW_FOCUSED = '1';
|
|
42
|
+
process.argv.splice(focusIdx, 1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
29
45
|
// ── Ultra-fast path: lightweight commands bypass full discovery ──────────
|
|
30
46
|
// These are high-frequency or trivial paths that must not pay the startup tax.
|
|
31
47
|
const argv = process.argv.slice(2);
|
package/dist/src/types.d.ts
CHANGED
|
@@ -51,10 +51,25 @@ export interface IPage {
|
|
|
51
51
|
url?: string;
|
|
52
52
|
}): Promise<BrowserCookie[]>;
|
|
53
53
|
snapshot(opts?: SnapshotOptions): Promise<any>;
|
|
54
|
-
click(ref: string
|
|
55
|
-
|
|
54
|
+
click(ref: string, opts?: {
|
|
55
|
+
nth?: number;
|
|
56
|
+
firstOnMulti?: boolean;
|
|
57
|
+
}): Promise<{
|
|
58
|
+
matches_n: number;
|
|
59
|
+
match_level: 'exact' | 'stable' | 'reidentified';
|
|
60
|
+
}>;
|
|
61
|
+
typeText(ref: string, text: string, opts?: {
|
|
62
|
+
nth?: number;
|
|
63
|
+
firstOnMulti?: boolean;
|
|
64
|
+
}): Promise<{
|
|
65
|
+
matches_n: number;
|
|
66
|
+
match_level: 'exact' | 'stable' | 'reidentified';
|
|
67
|
+
}>;
|
|
56
68
|
pressKey(key: string): Promise<void>;
|
|
57
|
-
scrollTo(ref: string
|
|
69
|
+
scrollTo(ref: string, opts?: {
|
|
70
|
+
nth?: number;
|
|
71
|
+
firstOnMulti?: boolean;
|
|
72
|
+
}): Promise<any>;
|
|
58
73
|
getFormState(): Promise<any>;
|
|
59
74
|
wait(options: number | WaitOptions): Promise<void>;
|
|
60
75
|
tabs(): Promise<any>;
|