@jackwener/opencli 1.5.8 → 1.5.9
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/CHANGELOG.md +21 -0
- package/README.md +17 -1
- package/README.zh-CN.md +17 -1
- package/dist/browser/base-page.d.ts +48 -0
- package/dist/browser/base-page.js +160 -0
- package/dist/browser/cdp.js +4 -106
- package/dist/browser/daemon-client.d.ts +1 -7
- package/dist/browser/daemon-client.js +2 -9
- package/dist/browser/discover.d.ts +1 -4
- package/dist/browser/discover.js +1 -4
- package/dist/browser/errors.d.ts +4 -0
- package/dist/browser/errors.js +20 -0
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/page.d.ts +6 -35
- package/dist/browser/page.js +10 -189
- package/dist/browser/tabs.js +5 -5
- package/dist/browser.test.js +15 -15
- package/dist/cli-manifest.json +294 -22
- package/dist/clis/amazon/bestsellers.d.ts +21 -0
- package/dist/clis/amazon/bestsellers.js +130 -0
- package/dist/clis/amazon/bestsellers.test.js +20 -0
- package/dist/clis/amazon/discussion.d.ts +20 -0
- package/dist/clis/amazon/discussion.js +91 -0
- package/dist/clis/amazon/discussion.test.js +36 -0
- package/dist/clis/amazon/offer.d.ts +23 -0
- package/dist/clis/amazon/offer.js +140 -0
- package/dist/clis/amazon/offer.test.d.ts +1 -0
- package/dist/clis/amazon/offer.test.js +29 -0
- package/dist/clis/amazon/product.d.ts +18 -0
- package/dist/clis/amazon/product.js +92 -0
- package/dist/clis/amazon/product.test.d.ts +1 -0
- package/dist/clis/amazon/product.test.js +24 -0
- package/dist/clis/amazon/search.d.ts +18 -0
- package/dist/clis/amazon/search.js +87 -0
- package/dist/clis/amazon/search.test.d.ts +1 -0
- package/dist/clis/amazon/search.test.js +22 -0
- package/dist/clis/amazon/shared.d.ts +64 -0
- package/dist/clis/amazon/shared.js +255 -0
- package/dist/clis/amazon/shared.test.d.ts +1 -0
- package/dist/clis/amazon/shared.test.js +33 -0
- package/dist/clis/gemini/ask.d.ts +1 -0
- package/dist/clis/gemini/ask.js +40 -0
- package/dist/clis/gemini/image.d.ts +1 -0
- package/dist/clis/gemini/image.js +105 -0
- package/dist/clis/gemini/new.d.ts +1 -0
- package/dist/clis/gemini/new.js +20 -0
- package/dist/clis/gemini/utils.d.ts +34 -0
- package/dist/clis/gemini/utils.js +463 -0
- package/dist/clis/gemini/utils.test.d.ts +1 -0
- package/dist/clis/gemini/utils.test.js +31 -0
- package/dist/clis/notebooklm/compat.test.d.ts +1 -1
- package/dist/clis/notebooklm/compat.test.js +3 -3
- package/dist/clis/notebooklm/current.js +2 -3
- package/dist/clis/notebooklm/get.js +2 -3
- package/dist/clis/notebooklm/history.js +2 -3
- package/dist/clis/notebooklm/note-list.js +2 -3
- package/dist/clis/notebooklm/notes-get.js +2 -3
- package/dist/clis/notebooklm/open.d.ts +1 -0
- package/dist/clis/notebooklm/open.js +41 -0
- package/dist/clis/notebooklm/open.test.d.ts +1 -0
- package/dist/clis/notebooklm/open.test.js +63 -0
- package/dist/clis/notebooklm/source-fulltext.js +2 -3
- package/dist/clis/notebooklm/source-get.js +2 -3
- package/dist/clis/notebooklm/source-guide.js +2 -3
- package/dist/clis/notebooklm/source-list.js +2 -3
- package/dist/clis/notebooklm/status.js +1 -2
- package/dist/clis/notebooklm/summary.js +2 -3
- package/dist/clis/notebooklm/utils.d.ts +2 -1
- package/dist/clis/notebooklm/utils.js +20 -21
- package/dist/clis/xiaohongshu/creator-note-detail.test.js +11 -11
- package/dist/clis/xiaohongshu/creator-notes-summary.test.js +6 -6
- package/dist/clis/xiaohongshu/creator-notes.test.js +22 -22
- package/dist/commanderAdapter.js +6 -3
- package/dist/commanderAdapter.test.js +33 -0
- package/dist/commands/daemon.js +1 -1
- package/dist/commands/daemon.test.js +1 -1
- package/dist/doctor.d.ts +1 -2
- package/dist/doctor.js +7 -8
- package/dist/explore.js +1 -1
- package/dist/output.js +28 -0
- package/dist/output.test.js +15 -0
- package/dist/pipeline/executor.js +2 -7
- package/dist/pipeline/steps/browser.js +1 -1
- package/dist/pipeline/template.js +25 -3
- package/dist/record.d.ts +50 -0
- package/dist/record.js +298 -57
- package/dist/record.test.d.ts +1 -0
- package/dist/record.test.js +293 -0
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +1 -0
- package/dist/registry.test.js +10 -0
- package/dist/runtime.js +3 -3
- package/dist/snapshotFormatter.d.ts +1 -1
- package/dist/snapshotFormatter.js +4 -4
- package/dist/snapshotFormatter.test.d.ts +1 -1
- package/dist/snapshotFormatter.test.js +2 -2
- package/dist/types.d.ts +3 -1
- package/dist/types.js +1 -1
- package/docs/.vitepress/config.mts +2 -0
- package/docs/adapters/browser/amazon.md +53 -0
- package/docs/adapters/browser/gemini.md +72 -0
- package/docs/adapters/browser/notebooklm.md +5 -5
- package/docs/adapters/index.md +3 -1
- package/extension/dist/background.js +5 -143
- package/extension/src/background.test.ts +7 -163
- package/extension/src/background.ts +7 -157
- package/extension/src/protocol.ts +1 -5
- package/package.json +1 -1
- package/skills/opencli-explorer/SKILL.md +847 -0
- package/skills/opencli-oneshot/SKILL.md +216 -0
- package/skills/opencli-usage/SKILL.md +71 -0
- package/skills/opencli-usage/browser.md +429 -0
- package/skills/opencli-usage/desktop.md +118 -0
- package/skills/opencli-usage/plugins.md +82 -0
- package/skills/opencli-usage/public-api.md +149 -0
- package/src/browser/base-page.ts +197 -0
- package/src/browser/cdp.ts +7 -131
- package/src/browser/daemon-client.ts +3 -14
- package/src/browser/discover.ts +1 -4
- package/src/browser/errors.ts +22 -0
- package/src/browser/index.ts +1 -1
- package/src/browser/page.ts +13 -212
- package/src/browser/tabs.ts +5 -5
- package/src/browser.test.ts +15 -15
- package/src/clis/amazon/bestsellers.test.ts +22 -0
- package/src/clis/amazon/bestsellers.ts +180 -0
- package/src/clis/amazon/discussion.test.ts +38 -0
- package/src/clis/amazon/discussion.ts +131 -0
- package/src/clis/amazon/offer.test.ts +35 -0
- package/src/clis/amazon/offer.ts +185 -0
- package/src/clis/amazon/product.test.ts +26 -0
- package/src/clis/amazon/product.ts +131 -0
- package/src/clis/amazon/search.test.ts +24 -0
- package/src/clis/amazon/search.ts +128 -0
- package/src/clis/amazon/shared.test.ts +37 -0
- package/src/clis/amazon/shared.ts +316 -0
- package/src/clis/gemini/ask.ts +46 -0
- package/src/clis/gemini/image.ts +115 -0
- package/src/clis/gemini/new.ts +22 -0
- package/src/clis/gemini/utils.test.ts +36 -0
- package/src/clis/gemini/utils.ts +523 -0
- package/src/clis/notebooklm/compat.test.ts +3 -3
- package/src/clis/notebooklm/current.ts +2 -3
- package/src/clis/notebooklm/get.ts +1 -3
- package/src/clis/notebooklm/history.ts +1 -3
- package/src/clis/notebooklm/note-list.ts +1 -3
- package/src/clis/notebooklm/notes-get.ts +1 -3
- package/src/clis/notebooklm/open.test.ts +78 -0
- package/src/clis/notebooklm/open.ts +61 -0
- package/src/clis/notebooklm/source-fulltext.ts +1 -3
- package/src/clis/notebooklm/source-get.ts +1 -3
- package/src/clis/notebooklm/source-guide.ts +1 -3
- package/src/clis/notebooklm/source-list.ts +1 -3
- package/src/clis/notebooklm/status.ts +1 -2
- package/src/clis/notebooklm/summary.ts +1 -3
- package/src/clis/notebooklm/utils.ts +29 -20
- package/src/clis/xiaohongshu/creator-note-detail.test.ts +11 -11
- package/src/clis/xiaohongshu/creator-notes-summary.test.ts +6 -6
- package/src/clis/xiaohongshu/creator-notes.test.ts +22 -22
- package/src/commanderAdapter.test.ts +47 -0
- package/src/commanderAdapter.ts +7 -3
- package/src/commands/daemon.test.ts +1 -1
- package/src/commands/daemon.ts +1 -1
- package/src/doctor.ts +7 -8
- package/src/explore.ts +1 -1
- package/src/output.test.ts +17 -0
- package/src/output.ts +27 -0
- package/src/pipeline/executor.ts +2 -7
- package/src/pipeline/steps/browser.ts +1 -1
- package/src/pipeline/template.ts +27 -4
- package/src/record.test.ts +362 -0
- package/src/record.ts +341 -62
- package/src/registry.test.ts +12 -0
- package/src/registry.ts +3 -0
- package/src/runtime.ts +3 -3
- package/src/snapshotFormatter.test.ts +2 -2
- package/src/snapshotFormatter.ts +4 -4
- package/src/types.ts +3 -1
- package/.agents/skills/cross-project-adapter-migration/SKILL.md +0 -249
- package/.agents/workflows/cross-project-adapter-migration.md +0 -54
- package/SKILL.md +0 -879
- package/dist/clis/notebooklm/bind-current.js +0 -29
- package/dist/clis/notebooklm/bind-current.test.d.ts +0 -1
- package/dist/clis/notebooklm/bind-current.test.js +0 -35
- package/dist/clis/notebooklm/binding.test.js +0 -44
- package/src/clis/notebooklm/bind-current.test.ts +0 -43
- package/src/clis/notebooklm/bind-current.ts +0 -36
- package/src/clis/notebooklm/binding.test.ts +0 -53
- /package/dist/browser/{mcp.d.ts → bridge.d.ts} +0 -0
- /package/dist/browser/{mcp.js → bridge.js} +0 -0
- /package/dist/clis/{notebooklm/bind-current.d.ts → amazon/bestsellers.test.d.ts} +0 -0
- /package/dist/clis/{notebooklm/binding.test.d.ts → amazon/discussion.test.d.ts} +0 -0
- /package/src/browser/{mcp.ts → bridge.ts} +0 -0
package/dist/browser/page.js
CHANGED
|
@@ -9,13 +9,12 @@
|
|
|
9
9
|
* where resolveTabId() in the extension picks a chrome:// or
|
|
10
10
|
* chrome-extension:// tab that can't be debugged.
|
|
11
11
|
*/
|
|
12
|
-
import { formatSnapshot } from '../snapshotFormatter.js';
|
|
13
12
|
import { sendCommand } from './daemon-client.js';
|
|
14
13
|
import { wrapForEval } from './utils.js';
|
|
15
14
|
import { saveBase64ToFile } from '../utils.js';
|
|
16
|
-
import { generateSnapshotJs, scrollToRefJs, getFormStateJs } from './dom-snapshot.js';
|
|
17
15
|
import { generateStealthJs } from './stealth.js';
|
|
18
|
-
import {
|
|
16
|
+
import { waitForDomStableJs } from './dom-helpers.js';
|
|
17
|
+
import { BasePage } from './base-page.js';
|
|
19
18
|
export function isRetryableSettleError(err) {
|
|
20
19
|
const message = err instanceof Error ? err.message : String(err);
|
|
21
20
|
return message.includes('Inspected target navigated or closed')
|
|
@@ -24,15 +23,14 @@ export function isRetryableSettleError(err) {
|
|
|
24
23
|
/**
|
|
25
24
|
* Page — implements IPage by talking to the daemon via HTTP.
|
|
26
25
|
*/
|
|
27
|
-
export class Page {
|
|
26
|
+
export class Page extends BasePage {
|
|
28
27
|
workspace;
|
|
29
28
|
constructor(workspace = 'default') {
|
|
29
|
+
super();
|
|
30
30
|
this.workspace = workspace;
|
|
31
31
|
}
|
|
32
32
|
/** Active tab ID, set after navigate and used in all subsequent commands */
|
|
33
33
|
_tabId;
|
|
34
|
-
/** Last navigated URL, tracked in-memory to avoid extra round-trips */
|
|
35
|
-
_lastUrl = null;
|
|
36
34
|
/** Helper: spread workspace into command params */
|
|
37
35
|
_wsOpt() {
|
|
38
36
|
return { workspace: this.workspace };
|
|
@@ -95,29 +93,8 @@ export class Page {
|
|
|
95
93
|
}
|
|
96
94
|
}
|
|
97
95
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return this._lastUrl;
|
|
101
|
-
try {
|
|
102
|
-
const current = await this.evaluate('window.location.href');
|
|
103
|
-
if (typeof current === 'string' && current) {
|
|
104
|
-
this._lastUrl = current;
|
|
105
|
-
return current;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
// Best-effort: some commands may run before a debuggable tab is ready.
|
|
110
|
-
}
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
/** Close the automation window in the extension */
|
|
114
|
-
async closeWindow() {
|
|
115
|
-
try {
|
|
116
|
-
await sendCommand('close-window', { ...this._wsOpt() });
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
// Window may already be closed or daemon may be down
|
|
120
|
-
}
|
|
96
|
+
getActiveTabId() {
|
|
97
|
+
return this._tabId;
|
|
121
98
|
}
|
|
122
99
|
async evaluate(js) {
|
|
123
100
|
const code = wrapForEval(js);
|
|
@@ -135,120 +112,13 @@ export class Page {
|
|
|
135
112
|
const result = await sendCommand('cookies', { ...this._wsOpt(), ...opts });
|
|
136
113
|
return Array.isArray(result) ? result : [];
|
|
137
114
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const snapshotJs = generateSnapshotJs({
|
|
141
|
-
viewportExpand: opts.viewportExpand ?? 800,
|
|
142
|
-
maxDepth: Math.max(1, Math.min(Number(opts.maxDepth) || 50, 200)),
|
|
143
|
-
interactiveOnly: opts.interactive ?? false,
|
|
144
|
-
maxTextLength: opts.maxTextLength ?? 120,
|
|
145
|
-
includeScrollInfo: true,
|
|
146
|
-
bboxDedup: true,
|
|
147
|
-
});
|
|
115
|
+
/** Close the automation window in the extension */
|
|
116
|
+
async closeWindow() {
|
|
148
117
|
try {
|
|
149
|
-
|
|
150
|
-
// The advanced engine already produces a clean, pruned, LLM-friendly output.
|
|
151
|
-
// Do NOT pass through formatSnapshot — its format is incompatible.
|
|
152
|
-
return result;
|
|
118
|
+
await sendCommand('close-window', { ...this._wsOpt() });
|
|
153
119
|
}
|
|
154
120
|
catch {
|
|
155
|
-
//
|
|
156
|
-
return this._basicSnapshot(opts);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
/** Fallback basic snapshot — original buildTree approach */
|
|
160
|
-
async _basicSnapshot(opts = {}) {
|
|
161
|
-
const maxDepth = Math.max(1, Math.min(Number(opts.maxDepth) || 50, 200));
|
|
162
|
-
const code = `
|
|
163
|
-
(async () => {
|
|
164
|
-
function buildTree(node, depth) {
|
|
165
|
-
if (depth > ${maxDepth}) return '';
|
|
166
|
-
const role = node.getAttribute?.('role') || node.tagName?.toLowerCase() || 'generic';
|
|
167
|
-
const name = node.getAttribute?.('aria-label') || node.getAttribute?.('alt') || node.textContent?.trim().slice(0, 80) || '';
|
|
168
|
-
const isInteractive = ['a', 'button', 'input', 'select', 'textarea'].includes(node.tagName?.toLowerCase()) || node.getAttribute?.('tabindex') != null;
|
|
169
|
-
|
|
170
|
-
${opts.interactive ? 'if (!isInteractive && !node.children?.length) return "";' : ''}
|
|
171
|
-
|
|
172
|
-
let indent = ' '.repeat(depth);
|
|
173
|
-
let line = indent + role;
|
|
174
|
-
if (name) line += ' "' + name.replace(/"/g, '\\\\\\"') + '"';
|
|
175
|
-
if (node.tagName?.toLowerCase() === 'a' && node.href) line += ' [' + node.href + ']';
|
|
176
|
-
if (node.tagName?.toLowerCase() === 'input') line += ' [' + (node.type || 'text') + ']';
|
|
177
|
-
|
|
178
|
-
let result = line + '\\n';
|
|
179
|
-
if (node.children) {
|
|
180
|
-
for (const child of node.children) {
|
|
181
|
-
result += buildTree(child, depth + 1);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
return result;
|
|
185
|
-
}
|
|
186
|
-
return buildTree(document.body, 0);
|
|
187
|
-
})()
|
|
188
|
-
`;
|
|
189
|
-
const raw = await sendCommand('exec', { code, ...this._cmdOpts() });
|
|
190
|
-
if (opts.raw)
|
|
191
|
-
return raw;
|
|
192
|
-
if (typeof raw === 'string')
|
|
193
|
-
return formatSnapshot(raw, opts);
|
|
194
|
-
return raw;
|
|
195
|
-
}
|
|
196
|
-
async click(ref) {
|
|
197
|
-
const code = clickJs(ref);
|
|
198
|
-
await sendCommand('exec', { code, ...this._cmdOpts() });
|
|
199
|
-
}
|
|
200
|
-
async typeText(ref, text) {
|
|
201
|
-
const code = typeTextJs(ref, text);
|
|
202
|
-
await sendCommand('exec', { code, ...this._cmdOpts() });
|
|
203
|
-
}
|
|
204
|
-
async pressKey(key) {
|
|
205
|
-
const code = pressKeyJs(key);
|
|
206
|
-
await sendCommand('exec', { code, ...this._cmdOpts() });
|
|
207
|
-
}
|
|
208
|
-
async scrollTo(ref) {
|
|
209
|
-
const code = scrollToRefJs(ref);
|
|
210
|
-
return sendCommand('exec', { code, ...this._cmdOpts() });
|
|
211
|
-
}
|
|
212
|
-
async getFormState() {
|
|
213
|
-
const code = getFormStateJs();
|
|
214
|
-
return (await sendCommand('exec', { code, ...this._cmdOpts() }));
|
|
215
|
-
}
|
|
216
|
-
async wait(options) {
|
|
217
|
-
if (typeof options === 'number') {
|
|
218
|
-
if (options >= 1) {
|
|
219
|
-
// For waits >= 1s, use DOM-stable check: return early when the page
|
|
220
|
-
// stops mutating, with the original wait time as the hard cap.
|
|
221
|
-
// This turns e.g. `page.wait(5)` from a fixed 5s sleep into
|
|
222
|
-
// "wait until DOM is stable, max 5s" — often completing in <1s.
|
|
223
|
-
try {
|
|
224
|
-
const maxMs = options * 1000;
|
|
225
|
-
await sendCommand('exec', {
|
|
226
|
-
code: waitForDomStableJs(maxMs, Math.min(500, maxMs)),
|
|
227
|
-
...this._cmdOpts(),
|
|
228
|
-
});
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
catch {
|
|
232
|
-
// Fallback: fixed sleep (e.g. if page has no DOM yet)
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
await new Promise(resolve => setTimeout(resolve, options * 1000));
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
if (typeof options.time === 'number') {
|
|
239
|
-
await new Promise(resolve => setTimeout(resolve, options.time * 1000));
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
if (options.selector) {
|
|
243
|
-
const timeout = (options.timeout ?? 10) * 1000;
|
|
244
|
-
const code = waitForSelectorJs(options.selector, timeout);
|
|
245
|
-
await sendCommand('exec', { code, ...this._cmdOpts() });
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
if (options.text) {
|
|
249
|
-
const timeout = (options.timeout ?? 30) * 1000;
|
|
250
|
-
const code = waitForTextJs(options.text, timeout);
|
|
251
|
-
await sendCommand('exec', { code, ...this._cmdOpts() });
|
|
121
|
+
// Window may already be closed or daemon may be down
|
|
252
122
|
}
|
|
253
123
|
}
|
|
254
124
|
async tabs() {
|
|
@@ -271,25 +141,8 @@ export class Page {
|
|
|
271
141
|
if (result?.selected)
|
|
272
142
|
this._tabId = result.selected;
|
|
273
143
|
}
|
|
274
|
-
async networkRequests(includeStatic = false) {
|
|
275
|
-
const code = networkRequestsJs(includeStatic);
|
|
276
|
-
const result = await sendCommand('exec', { code, ...this._cmdOpts() });
|
|
277
|
-
return Array.isArray(result) ? result : [];
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Console messages are not available in lightweight daemon mode.
|
|
281
|
-
* Would require CDP Runtime.consoleAPICalled event listener.
|
|
282
|
-
* @returns Always returns empty array.
|
|
283
|
-
*/
|
|
284
|
-
async consoleMessages(_level = 'info') {
|
|
285
|
-
return [];
|
|
286
|
-
}
|
|
287
144
|
/**
|
|
288
145
|
* Capture a screenshot via CDP Page.captureScreenshot.
|
|
289
|
-
* @param options.format - 'png' (default) or 'jpeg'
|
|
290
|
-
* @param options.quality - JPEG quality 0-100
|
|
291
|
-
* @param options.fullPage - capture full scrollable page
|
|
292
|
-
* @param options.path - save to file path (returns base64 if omitted)
|
|
293
146
|
*/
|
|
294
147
|
async screenshot(options = {}) {
|
|
295
148
|
const base64 = await sendCommand('screenshot', {
|
|
@@ -303,31 +156,6 @@ export class Page {
|
|
|
303
156
|
}
|
|
304
157
|
return base64;
|
|
305
158
|
}
|
|
306
|
-
async scroll(direction = 'down', amount = 500) {
|
|
307
|
-
const code = scrollJs(direction, amount);
|
|
308
|
-
await sendCommand('exec', { code, ...this._cmdOpts() });
|
|
309
|
-
}
|
|
310
|
-
async autoScroll(options = {}) {
|
|
311
|
-
const times = options.times ?? 3;
|
|
312
|
-
const delayMs = options.delayMs ?? 2000;
|
|
313
|
-
const code = autoScrollJs(times, delayMs);
|
|
314
|
-
await sendCommand('exec', { code, ...this._cmdOpts() });
|
|
315
|
-
}
|
|
316
|
-
async installInterceptor(pattern) {
|
|
317
|
-
const { generateInterceptorJs } = await import('../interceptor.js');
|
|
318
|
-
// Must use evaluate() so wrapForEval() converts the arrow function into an IIFE;
|
|
319
|
-
// sendCommand('exec') sends the code as-is, and CDP never executes a bare arrow.
|
|
320
|
-
await this.evaluate(generateInterceptorJs(JSON.stringify(pattern), {
|
|
321
|
-
arrayName: '__opencli_xhr',
|
|
322
|
-
patchGuard: '__opencli_interceptor_patched',
|
|
323
|
-
}));
|
|
324
|
-
}
|
|
325
|
-
async getInterceptedRequests() {
|
|
326
|
-
const { generateReadInterceptedJs } = await import('../interceptor.js');
|
|
327
|
-
// Same as installInterceptor: must go through evaluate() for IIFE wrapping
|
|
328
|
-
const result = await this.evaluate(generateReadInterceptedJs('__opencli_xhr'));
|
|
329
|
-
return Array.isArray(result) ? result : [];
|
|
330
|
-
}
|
|
331
159
|
/**
|
|
332
160
|
* Set local file paths on a file input element via CDP DOM.setFileInputFiles.
|
|
333
161
|
* Chrome reads the files directly from the local filesystem, avoiding the
|
|
@@ -343,12 +171,5 @@ export class Page {
|
|
|
343
171
|
throw new Error('setFileInput returned no count — command may not be supported by the extension');
|
|
344
172
|
}
|
|
345
173
|
}
|
|
346
|
-
async waitForCapture(timeout = 10) {
|
|
347
|
-
const maxMs = timeout * 1000;
|
|
348
|
-
await sendCommand('exec', {
|
|
349
|
-
code: waitForCaptureJs(maxMs),
|
|
350
|
-
...this._cmdOpts(),
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
174
|
}
|
|
354
175
|
// (End of file)
|
package/dist/browser/tabs.js
CHANGED
|
@@ -19,12 +19,12 @@ export function extractTabEntries(raw) {
|
|
|
19
19
|
.map(line => line.trim())
|
|
20
20
|
.filter(Boolean)
|
|
21
21
|
.map(line => {
|
|
22
|
-
// Match
|
|
23
|
-
const
|
|
24
|
-
if (
|
|
22
|
+
// Match tab list format: "- 0: (current) [title](url)" or "- 1: [title](url)"
|
|
23
|
+
const tabMatch = line.match(/^-\s+(\d+):\s*(.*)$/);
|
|
24
|
+
if (tabMatch) {
|
|
25
25
|
return {
|
|
26
|
-
index: parseInt(
|
|
27
|
-
identity:
|
|
26
|
+
index: parseInt(tabMatch[1], 10),
|
|
27
|
+
identity: tabMatch[2].trim() || `tab-${tabMatch[1]}`,
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
// Legacy format: "Tab 0 ..."
|
package/dist/browser.test.js
CHANGED
|
@@ -84,31 +84,31 @@ describe('browser helpers', () => {
|
|
|
84
84
|
});
|
|
85
85
|
describe('BrowserBridge state', () => {
|
|
86
86
|
it('transitions to closed after close()', async () => {
|
|
87
|
-
const
|
|
88
|
-
expect(
|
|
89
|
-
await
|
|
90
|
-
expect(
|
|
87
|
+
const bridge = new BrowserBridge();
|
|
88
|
+
expect(bridge.state).toBe('idle');
|
|
89
|
+
await bridge.close();
|
|
90
|
+
expect(bridge.state).toBe('closed');
|
|
91
91
|
});
|
|
92
92
|
it('rejects connect() after the session has been closed', async () => {
|
|
93
|
-
const
|
|
94
|
-
await
|
|
95
|
-
await expect(
|
|
93
|
+
const bridge = new BrowserBridge();
|
|
94
|
+
await bridge.close();
|
|
95
|
+
await expect(bridge.connect()).rejects.toThrow('Session is closed');
|
|
96
96
|
});
|
|
97
97
|
it('rejects connect() while already connecting', async () => {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
await expect(
|
|
98
|
+
const bridge = new BrowserBridge();
|
|
99
|
+
bridge._state = 'connecting';
|
|
100
|
+
await expect(bridge.connect()).rejects.toThrow('Already connecting');
|
|
101
101
|
});
|
|
102
102
|
it('rejects connect() while closing', async () => {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
await expect(
|
|
103
|
+
const bridge = new BrowserBridge();
|
|
104
|
+
bridge._state = 'closing';
|
|
105
|
+
await expect(bridge.connect()).rejects.toThrow('Session is closing');
|
|
106
106
|
});
|
|
107
107
|
it('fails fast when daemon is running but extension is disconnected', async () => {
|
|
108
108
|
vi.spyOn(daemonClient, 'isExtensionConnected').mockResolvedValue(false);
|
|
109
109
|
vi.spyOn(daemonClient, 'isDaemonRunning').mockResolvedValue(true);
|
|
110
|
-
const
|
|
111
|
-
await expect(
|
|
110
|
+
const bridge = new BrowserBridge();
|
|
111
|
+
await expect(bridge.connect({ timeout: 0.1 })).rejects.toThrow('Browser Extension is not connected');
|
|
112
112
|
});
|
|
113
113
|
});
|
|
114
114
|
describe('stealth anti-detection', () => {
|
package/dist/cli-manifest.json
CHANGED
|
@@ -111,6 +111,163 @@
|
|
|
111
111
|
"type": "ts",
|
|
112
112
|
"modulePath": "36kr/search.js"
|
|
113
113
|
},
|
|
114
|
+
{
|
|
115
|
+
"site": "amazon",
|
|
116
|
+
"name": "bestsellers",
|
|
117
|
+
"description": "Amazon Best Sellers pages for category candidate discovery",
|
|
118
|
+
"domain": "amazon.com",
|
|
119
|
+
"strategy": "cookie",
|
|
120
|
+
"browser": true,
|
|
121
|
+
"args": [
|
|
122
|
+
{
|
|
123
|
+
"name": "input",
|
|
124
|
+
"type": "str",
|
|
125
|
+
"required": false,
|
|
126
|
+
"positional": true,
|
|
127
|
+
"help": "Best sellers URL or /zgbs path. Omit to use the root Best Sellers page."
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"name": "limit",
|
|
131
|
+
"type": "int",
|
|
132
|
+
"default": 100,
|
|
133
|
+
"required": false,
|
|
134
|
+
"help": "Maximum number of ranked items to return (default 100)"
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
"columns": [
|
|
138
|
+
"rank",
|
|
139
|
+
"asin",
|
|
140
|
+
"title",
|
|
141
|
+
"price_text",
|
|
142
|
+
"rating_value",
|
|
143
|
+
"review_count"
|
|
144
|
+
],
|
|
145
|
+
"type": "ts",
|
|
146
|
+
"modulePath": "amazon/bestsellers.js",
|
|
147
|
+
"navigateBefore": false
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"site": "amazon",
|
|
151
|
+
"name": "discussion",
|
|
152
|
+
"description": "Amazon review summary and sample customer discussion from product review pages",
|
|
153
|
+
"domain": "amazon.com",
|
|
154
|
+
"strategy": "cookie",
|
|
155
|
+
"browser": true,
|
|
156
|
+
"args": [
|
|
157
|
+
{
|
|
158
|
+
"name": "input",
|
|
159
|
+
"type": "str",
|
|
160
|
+
"required": true,
|
|
161
|
+
"positional": true,
|
|
162
|
+
"help": "ASIN or product URL, for example B0FJS72893"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"name": "limit",
|
|
166
|
+
"type": "int",
|
|
167
|
+
"default": 10,
|
|
168
|
+
"required": false,
|
|
169
|
+
"help": "Maximum number of review samples to return (default 10)"
|
|
170
|
+
}
|
|
171
|
+
],
|
|
172
|
+
"columns": [
|
|
173
|
+
"asin",
|
|
174
|
+
"average_rating_value",
|
|
175
|
+
"total_review_count"
|
|
176
|
+
],
|
|
177
|
+
"type": "ts",
|
|
178
|
+
"modulePath": "amazon/discussion.js",
|
|
179
|
+
"navigateBefore": false
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"site": "amazon",
|
|
183
|
+
"name": "offer",
|
|
184
|
+
"description": "Amazon seller, buy box, and fulfillment facts from the product page",
|
|
185
|
+
"domain": "amazon.com",
|
|
186
|
+
"strategy": "cookie",
|
|
187
|
+
"browser": true,
|
|
188
|
+
"args": [
|
|
189
|
+
{
|
|
190
|
+
"name": "input",
|
|
191
|
+
"type": "str",
|
|
192
|
+
"required": true,
|
|
193
|
+
"positional": true,
|
|
194
|
+
"help": "ASIN or product URL, for example B0FJS72893"
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
"columns": [
|
|
198
|
+
"asin",
|
|
199
|
+
"price_text",
|
|
200
|
+
"sold_by",
|
|
201
|
+
"ships_from",
|
|
202
|
+
"is_amazon_sold",
|
|
203
|
+
"is_amazon_fulfilled"
|
|
204
|
+
],
|
|
205
|
+
"type": "ts",
|
|
206
|
+
"modulePath": "amazon/offer.js",
|
|
207
|
+
"navigateBefore": false
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"site": "amazon",
|
|
211
|
+
"name": "product",
|
|
212
|
+
"description": "Amazon product page facts for candidate validation",
|
|
213
|
+
"domain": "amazon.com",
|
|
214
|
+
"strategy": "cookie",
|
|
215
|
+
"browser": true,
|
|
216
|
+
"args": [
|
|
217
|
+
{
|
|
218
|
+
"name": "input",
|
|
219
|
+
"type": "str",
|
|
220
|
+
"required": true,
|
|
221
|
+
"positional": true,
|
|
222
|
+
"help": "ASIN or product URL, for example B0FJS72893"
|
|
223
|
+
}
|
|
224
|
+
],
|
|
225
|
+
"columns": [
|
|
226
|
+
"asin",
|
|
227
|
+
"title",
|
|
228
|
+
"price_text",
|
|
229
|
+
"rating_value",
|
|
230
|
+
"review_count"
|
|
231
|
+
],
|
|
232
|
+
"type": "ts",
|
|
233
|
+
"modulePath": "amazon/product.js",
|
|
234
|
+
"navigateBefore": false
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"site": "amazon",
|
|
238
|
+
"name": "search",
|
|
239
|
+
"description": "Amazon search results for product discovery and coarse filtering",
|
|
240
|
+
"domain": "amazon.com",
|
|
241
|
+
"strategy": "cookie",
|
|
242
|
+
"browser": true,
|
|
243
|
+
"args": [
|
|
244
|
+
{
|
|
245
|
+
"name": "query",
|
|
246
|
+
"type": "str",
|
|
247
|
+
"required": true,
|
|
248
|
+
"positional": true,
|
|
249
|
+
"help": "Search query, for example \"desk shelf organizer\""
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"name": "limit",
|
|
253
|
+
"type": "int",
|
|
254
|
+
"default": 20,
|
|
255
|
+
"required": false,
|
|
256
|
+
"help": "Maximum number of results to return (default 20)"
|
|
257
|
+
}
|
|
258
|
+
],
|
|
259
|
+
"columns": [
|
|
260
|
+
"rank",
|
|
261
|
+
"asin",
|
|
262
|
+
"title",
|
|
263
|
+
"price_text",
|
|
264
|
+
"rating_value",
|
|
265
|
+
"review_count"
|
|
266
|
+
],
|
|
267
|
+
"type": "ts",
|
|
268
|
+
"modulePath": "amazon/search.js",
|
|
269
|
+
"navigateBefore": false
|
|
270
|
+
},
|
|
114
271
|
{
|
|
115
272
|
"site": "antigravity",
|
|
116
273
|
"name": "dump",
|
|
@@ -5218,6 +5375,114 @@
|
|
|
5218
5375
|
],
|
|
5219
5376
|
"type": "yaml"
|
|
5220
5377
|
},
|
|
5378
|
+
{
|
|
5379
|
+
"site": "gemini",
|
|
5380
|
+
"name": "ask",
|
|
5381
|
+
"description": "Send a prompt to Gemini and return only the assistant response",
|
|
5382
|
+
"domain": "gemini.google.com",
|
|
5383
|
+
"strategy": "cookie",
|
|
5384
|
+
"browser": true,
|
|
5385
|
+
"args": [
|
|
5386
|
+
{
|
|
5387
|
+
"name": "prompt",
|
|
5388
|
+
"type": "str",
|
|
5389
|
+
"required": true,
|
|
5390
|
+
"positional": true,
|
|
5391
|
+
"help": "Prompt to send"
|
|
5392
|
+
},
|
|
5393
|
+
{
|
|
5394
|
+
"name": "timeout",
|
|
5395
|
+
"type": "str",
|
|
5396
|
+
"default": "60",
|
|
5397
|
+
"required": false,
|
|
5398
|
+
"help": "Max seconds to wait (default: 60)"
|
|
5399
|
+
},
|
|
5400
|
+
{
|
|
5401
|
+
"name": "new",
|
|
5402
|
+
"type": "str",
|
|
5403
|
+
"default": "false",
|
|
5404
|
+
"required": false,
|
|
5405
|
+
"help": "Start a new chat first (true/false, default: false)"
|
|
5406
|
+
}
|
|
5407
|
+
],
|
|
5408
|
+
"columns": [
|
|
5409
|
+
"response"
|
|
5410
|
+
],
|
|
5411
|
+
"timeout": 180,
|
|
5412
|
+
"type": "ts",
|
|
5413
|
+
"modulePath": "gemini/ask.js",
|
|
5414
|
+
"navigateBefore": false
|
|
5415
|
+
},
|
|
5416
|
+
{
|
|
5417
|
+
"site": "gemini",
|
|
5418
|
+
"name": "image",
|
|
5419
|
+
"description": "Generate images with Gemini web and save them locally",
|
|
5420
|
+
"domain": "gemini.google.com",
|
|
5421
|
+
"strategy": "cookie",
|
|
5422
|
+
"browser": true,
|
|
5423
|
+
"args": [
|
|
5424
|
+
{
|
|
5425
|
+
"name": "prompt",
|
|
5426
|
+
"type": "str",
|
|
5427
|
+
"required": true,
|
|
5428
|
+
"positional": true,
|
|
5429
|
+
"help": "Image prompt to send to Gemini"
|
|
5430
|
+
},
|
|
5431
|
+
{
|
|
5432
|
+
"name": "rt",
|
|
5433
|
+
"type": "str",
|
|
5434
|
+
"default": "1:1",
|
|
5435
|
+
"required": false,
|
|
5436
|
+
"help": "Ratio shorthand for aspect ratio (1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3)"
|
|
5437
|
+
},
|
|
5438
|
+
{
|
|
5439
|
+
"name": "st",
|
|
5440
|
+
"type": "str",
|
|
5441
|
+
"default": "",
|
|
5442
|
+
"required": false,
|
|
5443
|
+
"help": "Style shorthand, e.g. anime, icon, watercolor"
|
|
5444
|
+
},
|
|
5445
|
+
{
|
|
5446
|
+
"name": "op",
|
|
5447
|
+
"type": "str",
|
|
5448
|
+
"default": "/home/runner/tmp/gemini-images",
|
|
5449
|
+
"required": false,
|
|
5450
|
+
"help": "Output directory shorthand"
|
|
5451
|
+
},
|
|
5452
|
+
{
|
|
5453
|
+
"name": "sd",
|
|
5454
|
+
"type": "boolean",
|
|
5455
|
+
"default": false,
|
|
5456
|
+
"required": false,
|
|
5457
|
+
"help": "Skip download shorthand; only show Gemini page link"
|
|
5458
|
+
}
|
|
5459
|
+
],
|
|
5460
|
+
"columns": [
|
|
5461
|
+
"status",
|
|
5462
|
+
"file",
|
|
5463
|
+
"link"
|
|
5464
|
+
],
|
|
5465
|
+
"timeout": 240,
|
|
5466
|
+
"type": "ts",
|
|
5467
|
+
"modulePath": "gemini/image.js",
|
|
5468
|
+
"navigateBefore": false
|
|
5469
|
+
},
|
|
5470
|
+
{
|
|
5471
|
+
"site": "gemini",
|
|
5472
|
+
"name": "new",
|
|
5473
|
+
"description": "Start a new conversation in Gemini web chat",
|
|
5474
|
+
"domain": "gemini.google.com",
|
|
5475
|
+
"strategy": "cookie",
|
|
5476
|
+
"browser": true,
|
|
5477
|
+
"args": [],
|
|
5478
|
+
"columns": [
|
|
5479
|
+
"Status",
|
|
5480
|
+
"Action"
|
|
5481
|
+
],
|
|
5482
|
+
"type": "ts",
|
|
5483
|
+
"modulePath": "gemini/new.js",
|
|
5484
|
+
"navigateBefore": false
|
|
5485
|
+
},
|
|
5221
5486
|
{
|
|
5222
5487
|
"site": "google",
|
|
5223
5488
|
"name": "news",
|
|
@@ -8079,28 +8344,6 @@
|
|
|
8079
8344
|
"type": "ts",
|
|
8080
8345
|
"modulePath": "medium/user.js"
|
|
8081
8346
|
},
|
|
8082
|
-
{
|
|
8083
|
-
"site": "notebooklm",
|
|
8084
|
-
"name": "bind-current",
|
|
8085
|
-
"aliases": [
|
|
8086
|
-
"use"
|
|
8087
|
-
],
|
|
8088
|
-
"description": "Bind the current active NotebookLM notebook tab into the site:notebooklm workspace",
|
|
8089
|
-
"domain": "notebooklm.google.com",
|
|
8090
|
-
"strategy": "cookie",
|
|
8091
|
-
"browser": true,
|
|
8092
|
-
"args": [],
|
|
8093
|
-
"columns": [
|
|
8094
|
-
"workspace",
|
|
8095
|
-
"tab_id",
|
|
8096
|
-
"notebook_id",
|
|
8097
|
-
"title",
|
|
8098
|
-
"url"
|
|
8099
|
-
],
|
|
8100
|
-
"type": "ts",
|
|
8101
|
-
"modulePath": "notebooklm/bind-current.js",
|
|
8102
|
-
"navigateBefore": false
|
|
8103
|
-
},
|
|
8104
8347
|
{
|
|
8105
8348
|
"site": "notebooklm",
|
|
8106
8349
|
"name": "current",
|
|
@@ -8231,6 +8474,35 @@
|
|
|
8231
8474
|
"modulePath": "notebooklm/notes-get.js",
|
|
8232
8475
|
"navigateBefore": false
|
|
8233
8476
|
},
|
|
8477
|
+
{
|
|
8478
|
+
"site": "notebooklm",
|
|
8479
|
+
"name": "open",
|
|
8480
|
+
"aliases": [
|
|
8481
|
+
"select"
|
|
8482
|
+
],
|
|
8483
|
+
"description": "Open one NotebookLM notebook in the automation workspace by id or URL",
|
|
8484
|
+
"domain": "notebooklm.google.com",
|
|
8485
|
+
"strategy": "cookie",
|
|
8486
|
+
"browser": true,
|
|
8487
|
+
"args": [
|
|
8488
|
+
{
|
|
8489
|
+
"name": "notebook",
|
|
8490
|
+
"type": "str",
|
|
8491
|
+
"required": true,
|
|
8492
|
+
"positional": true,
|
|
8493
|
+
"help": "Notebook id from list output, or a full NotebookLM notebook URL"
|
|
8494
|
+
}
|
|
8495
|
+
],
|
|
8496
|
+
"columns": [
|
|
8497
|
+
"id",
|
|
8498
|
+
"title",
|
|
8499
|
+
"url",
|
|
8500
|
+
"source"
|
|
8501
|
+
],
|
|
8502
|
+
"type": "ts",
|
|
8503
|
+
"modulePath": "notebooklm/open.js",
|
|
8504
|
+
"navigateBefore": false
|
|
8505
|
+
},
|
|
8234
8506
|
{
|
|
8235
8507
|
"site": "notebooklm",
|
|
8236
8508
|
"name": "source-fulltext",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface BestsellersPagePayload {
|
|
2
|
+
href?: string;
|
|
3
|
+
title?: string;
|
|
4
|
+
list_title?: string;
|
|
5
|
+
cards?: Array<{
|
|
6
|
+
rank_text?: string | null;
|
|
7
|
+
asin?: string | null;
|
|
8
|
+
title?: string | null;
|
|
9
|
+
href?: string | null;
|
|
10
|
+
price_text?: string | null;
|
|
11
|
+
rating_text?: string | null;
|
|
12
|
+
review_count_text?: string | null;
|
|
13
|
+
card_text?: string | null;
|
|
14
|
+
}>;
|
|
15
|
+
page_links?: string[];
|
|
16
|
+
}
|
|
17
|
+
declare function normalizeBestsellerCandidate(candidate: NonNullable<BestsellersPagePayload['cards']>[number], rank: number, listTitle: string | null, sourceUrl: string): Record<string, unknown>;
|
|
18
|
+
export declare const __test__: {
|
|
19
|
+
normalizeBestsellerCandidate: typeof normalizeBestsellerCandidate;
|
|
20
|
+
};
|
|
21
|
+
export {};
|