@jackwener/opencli 0.9.6 → 1.0.0
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/.github/ISSUE_TEMPLATE/bug_report.yml +83 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +42 -0
- package/.github/ISSUE_TEMPLATE/new_site_adapter.yml +57 -0
- package/.github/dependabot.yml +27 -0
- package/.github/pull_request_template.md +24 -0
- package/.github/workflows/ci.yml +14 -8
- package/.github/workflows/e2e-headed.yml +6 -2
- package/.github/workflows/pkg-pr-new.yml +2 -2
- package/.github/workflows/release-please.yml +25 -0
- package/.github/workflows/release.yml +2 -2
- package/.github/workflows/security.yml +36 -0
- package/CDP.md +1 -1
- package/CDP.zh-CN.md +1 -1
- package/CLI-ELECTRON.md +89 -36
- package/CLI-EXPLORER.md +4 -4
- package/CONTRIBUTING.md +167 -0
- package/README.md +113 -89
- package/README.zh-CN.md +114 -91
- package/SKILL.md +10 -8
- package/TESTING.md +7 -7
- package/dist/browser/daemon-client.d.ts +37 -0
- package/dist/browser/daemon-client.js +82 -0
- package/dist/browser/discover.d.ts +11 -34
- package/dist/browser/discover.js +15 -190
- package/dist/browser/errors.d.ts +6 -20
- package/dist/browser/errors.js +24 -63
- package/dist/browser/index.d.ts +2 -11
- package/dist/browser/index.js +5 -11
- package/dist/browser/mcp.d.ts +9 -18
- package/dist/browser/mcp.js +70 -284
- package/dist/browser/page.d.ts +28 -6
- package/dist/browser/page.js +210 -85
- package/dist/browser.test.js +4 -202
- package/dist/build-manifest.d.ts +26 -0
- package/dist/build-manifest.js +132 -60
- package/dist/build-manifest.test.d.ts +1 -0
- package/dist/build-manifest.test.js +26 -0
- package/dist/cli-manifest.json +1582 -29
- package/dist/clis/bilibili/download.d.ts +10 -0
- package/dist/clis/bilibili/download.js +135 -0
- package/dist/clis/chatwise/ask.d.ts +1 -0
- package/dist/clis/chatwise/ask.js +76 -0
- package/dist/clis/chatwise/export.d.ts +1 -0
- package/dist/clis/chatwise/export.js +46 -0
- package/dist/clis/chatwise/history.d.ts +1 -0
- package/dist/clis/chatwise/history.js +43 -0
- package/dist/clis/chatwise/model.d.ts +1 -0
- package/dist/clis/chatwise/model.js +81 -0
- package/dist/clis/chatwise/new.d.ts +1 -0
- package/dist/clis/chatwise/new.js +18 -0
- package/dist/clis/chatwise/read.d.ts +1 -0
- package/dist/clis/chatwise/read.js +39 -0
- package/dist/clis/chatwise/screenshot.d.ts +1 -0
- package/dist/clis/chatwise/screenshot.js +27 -0
- package/dist/clis/chatwise/send.d.ts +1 -0
- package/dist/clis/chatwise/send.js +45 -0
- package/dist/clis/chatwise/status.d.ts +1 -0
- package/dist/clis/chatwise/status.js +22 -0
- package/dist/clis/discord-app/channels.d.ts +1 -0
- package/dist/clis/discord-app/channels.js +45 -0
- package/dist/clis/discord-app/members.d.ts +1 -0
- package/dist/clis/discord-app/members.js +38 -0
- package/dist/clis/discord-app/read.d.ts +1 -0
- package/dist/clis/discord-app/read.js +45 -0
- package/dist/clis/discord-app/search.d.ts +1 -0
- package/dist/clis/discord-app/search.js +56 -0
- package/dist/clis/discord-app/send.d.ts +1 -0
- package/dist/clis/discord-app/send.js +27 -0
- package/dist/clis/discord-app/servers.d.ts +1 -0
- package/dist/clis/discord-app/servers.js +36 -0
- package/dist/clis/discord-app/status.d.ts +1 -0
- package/dist/clis/discord-app/status.js +16 -0
- package/dist/clis/feishu/new.d.ts +1 -0
- package/dist/clis/feishu/new.js +27 -0
- package/dist/clis/feishu/read.d.ts +1 -0
- package/dist/clis/feishu/read.js +40 -0
- package/dist/clis/feishu/search.d.ts +1 -0
- package/dist/clis/feishu/search.js +30 -0
- package/dist/clis/feishu/send.d.ts +1 -0
- package/dist/clis/feishu/send.js +39 -0
- package/dist/clis/feishu/status.d.ts +1 -0
- package/dist/clis/feishu/status.js +28 -0
- package/dist/clis/grok/ask.d.ts +1 -0
- package/dist/clis/grok/ask.js +82 -0
- package/dist/clis/grok/debug.d.ts +1 -0
- package/dist/clis/grok/debug.js +45 -0
- package/dist/clis/jimeng/generate.yaml +84 -0
- package/dist/clis/jimeng/history.yaml +47 -0
- package/dist/clis/linux-do/categories.yaml +41 -0
- package/dist/clis/linux-do/category.yaml +49 -0
- package/dist/clis/linux-do/hot.yaml +50 -0
- package/dist/clis/linux-do/latest.yaml +40 -0
- package/dist/clis/linux-do/search.yaml +45 -0
- package/dist/clis/linux-do/topic.yaml +38 -0
- package/dist/clis/neteasemusic/like.d.ts +1 -0
- package/dist/clis/neteasemusic/like.js +25 -0
- package/dist/clis/neteasemusic/lyrics.d.ts +1 -0
- package/dist/clis/neteasemusic/lyrics.js +47 -0
- package/dist/clis/neteasemusic/next.d.ts +1 -0
- package/dist/clis/neteasemusic/next.js +26 -0
- package/dist/clis/neteasemusic/play.d.ts +1 -0
- package/dist/clis/neteasemusic/play.js +26 -0
- package/dist/clis/neteasemusic/playing.d.ts +1 -0
- package/dist/clis/neteasemusic/playing.js +59 -0
- package/dist/clis/neteasemusic/playlist.d.ts +1 -0
- package/dist/clis/neteasemusic/playlist.js +46 -0
- package/dist/clis/neteasemusic/prev.d.ts +1 -0
- package/dist/clis/neteasemusic/prev.js +25 -0
- package/dist/clis/neteasemusic/search.d.ts +1 -0
- package/dist/clis/neteasemusic/search.js +52 -0
- package/dist/clis/neteasemusic/status.d.ts +1 -0
- package/dist/clis/neteasemusic/status.js +16 -0
- package/dist/clis/neteasemusic/volume.d.ts +1 -0
- package/dist/clis/neteasemusic/volume.js +54 -0
- package/dist/clis/notion/export.d.ts +1 -0
- package/dist/clis/notion/export.js +31 -0
- package/dist/clis/notion/favorites.d.ts +1 -0
- package/dist/clis/notion/favorites.js +84 -0
- package/dist/clis/notion/new.d.ts +1 -0
- package/dist/clis/notion/new.js +34 -0
- package/dist/clis/notion/read.d.ts +1 -0
- package/dist/clis/notion/read.js +30 -0
- package/dist/clis/notion/search.d.ts +1 -0
- package/dist/clis/notion/search.js +46 -0
- package/dist/clis/notion/sidebar.d.ts +1 -0
- package/dist/clis/notion/sidebar.js +41 -0
- package/dist/clis/notion/status.d.ts +1 -0
- package/dist/clis/notion/status.js +16 -0
- package/dist/clis/notion/write.d.ts +1 -0
- package/dist/clis/notion/write.js +40 -0
- package/dist/clis/twitter/download.d.ts +8 -0
- package/dist/clis/twitter/download.js +204 -0
- package/dist/clis/wechat/chats.d.ts +1 -0
- package/dist/clis/wechat/chats.js +28 -0
- package/dist/clis/wechat/contacts.d.ts +1 -0
- package/dist/clis/wechat/contacts.js +28 -0
- package/dist/clis/wechat/read.d.ts +1 -0
- package/dist/clis/wechat/read.js +58 -0
- package/dist/clis/wechat/search.d.ts +1 -0
- package/dist/clis/wechat/search.js +31 -0
- package/dist/clis/wechat/send.d.ts +1 -0
- package/dist/clis/wechat/send.js +42 -0
- package/dist/clis/wechat/status.d.ts +1 -0
- package/dist/clis/wechat/status.js +29 -0
- package/dist/clis/xiaohongshu/creator-note-detail.d.ts +10 -0
- package/dist/clis/xiaohongshu/creator-note-detail.js +88 -0
- package/dist/clis/xiaohongshu/creator-notes.d.ts +11 -0
- package/dist/clis/xiaohongshu/creator-notes.js +109 -0
- package/dist/clis/xiaohongshu/creator-profile.d.ts +10 -0
- package/dist/clis/xiaohongshu/creator-profile.js +54 -0
- package/dist/clis/xiaohongshu/creator-stats.d.ts +10 -0
- package/dist/clis/xiaohongshu/creator-stats.js +74 -0
- package/dist/clis/xiaohongshu/download.d.ts +7 -0
- package/dist/clis/xiaohongshu/download.js +155 -0
- package/dist/clis/xiaohongshu/search.js +1 -1
- package/dist/clis/xiaohongshu/user-helpers.d.ts +15 -0
- package/dist/clis/xiaohongshu/user-helpers.js +67 -0
- package/dist/clis/xiaohongshu/user-helpers.test.d.ts +1 -0
- package/dist/clis/xiaohongshu/user-helpers.test.js +81 -0
- package/dist/clis/xiaohongshu/user.js +46 -29
- package/dist/clis/zhihu/download.d.ts +11 -0
- package/dist/clis/zhihu/download.js +186 -0
- package/dist/clis/zhihu/download.test.d.ts +1 -0
- package/dist/clis/zhihu/download.test.js +10 -0
- package/dist/daemon.d.ts +13 -0
- package/dist/daemon.js +187 -0
- package/dist/doctor.d.ts +27 -61
- package/dist/doctor.js +70 -601
- package/dist/doctor.test.js +30 -170
- package/dist/download/index.d.ts +79 -0
- package/dist/download/index.js +325 -0
- package/dist/download/progress.d.ts +36 -0
- package/dist/download/progress.js +111 -0
- package/dist/engine.test.js +15 -0
- package/dist/main.js +22 -28
- package/dist/pipeline/executor.test.js +1 -0
- package/dist/pipeline/registry.js +2 -0
- package/dist/pipeline/steps/browser.js +2 -2
- package/dist/pipeline/steps/download.d.ts +34 -0
- package/dist/pipeline/steps/download.js +251 -0
- package/dist/pipeline/steps/intercept.js +1 -2
- package/dist/pipeline/template.js +28 -0
- package/dist/setup.d.ts +6 -0
- package/dist/setup.js +46 -160
- package/dist/types.d.ts +6 -0
- package/extension/icons/icon-128.png +0 -0
- package/extension/icons/icon-16.png +0 -0
- package/extension/icons/icon-32.png +0 -0
- package/extension/icons/icon-48.png +0 -0
- package/extension/manifest.json +31 -0
- package/extension/package.json +16 -0
- package/extension/src/background.ts +293 -0
- package/extension/src/cdp.ts +125 -0
- package/extension/src/protocol.ts +57 -0
- package/extension/store-assets/screenshot-1280x800.png +0 -0
- package/extension/tsconfig.json +15 -0
- package/extension/vite.config.ts +18 -0
- package/package.json +8 -7
- package/scripts/test-site.mjs +70 -0
- package/src/browser/daemon-client.ts +113 -0
- package/src/browser/discover.ts +18 -216
- package/src/browser/errors.ts +30 -100
- package/src/browser/index.ts +6 -12
- package/src/browser/mcp.ts +78 -278
- package/src/browser/page.ts +222 -88
- package/src/browser.test.ts +3 -210
- package/src/build-manifest.test.ts +28 -0
- package/src/build-manifest.ts +147 -57
- package/src/clis/bilibili/download.ts +161 -0
- package/src/clis/chatgpt/README.md +1 -1
- package/src/clis/chatgpt/README.zh-CN.md +1 -1
- package/src/clis/chatwise/README.md +38 -0
- package/src/clis/chatwise/README.zh-CN.md +38 -0
- package/src/clis/chatwise/ask.ts +87 -0
- package/src/clis/chatwise/export.ts +51 -0
- package/src/clis/chatwise/history.ts +47 -0
- package/src/clis/chatwise/model.ts +87 -0
- package/src/clis/chatwise/new.ts +21 -0
- package/src/clis/chatwise/read.ts +42 -0
- package/src/clis/chatwise/screenshot.ts +33 -0
- package/src/clis/chatwise/send.ts +50 -0
- package/src/clis/chatwise/status.ts +25 -0
- package/src/clis/discord-app/README.md +28 -0
- package/src/clis/discord-app/README.zh-CN.md +28 -0
- package/src/clis/discord-app/channels.ts +48 -0
- package/src/clis/discord-app/members.ts +41 -0
- package/src/clis/discord-app/read.ts +49 -0
- package/src/clis/discord-app/search.ts +64 -0
- package/src/clis/discord-app/send.ts +32 -0
- package/src/clis/discord-app/servers.ts +39 -0
- package/src/clis/discord-app/status.ts +18 -0
- package/src/clis/feishu/README.md +20 -0
- package/src/clis/feishu/README.zh-CN.md +20 -0
- package/src/clis/feishu/new.ts +32 -0
- package/src/clis/feishu/read.ts +48 -0
- package/src/clis/feishu/search.ts +35 -0
- package/src/clis/feishu/send.ts +46 -0
- package/src/clis/feishu/status.ts +34 -0
- package/src/clis/grok/ask.ts +90 -0
- package/src/clis/grok/debug.ts +49 -0
- package/src/clis/jimeng/generate.yaml +84 -0
- package/src/clis/jimeng/history.yaml +47 -0
- package/src/clis/linux-do/categories.yaml +41 -0
- package/src/clis/linux-do/category.yaml +49 -0
- package/src/clis/linux-do/hot.yaml +50 -0
- package/src/clis/linux-do/latest.yaml +40 -0
- package/src/clis/linux-do/search.yaml +45 -0
- package/src/clis/linux-do/topic.yaml +38 -0
- package/src/clis/neteasemusic/README.md +31 -0
- package/src/clis/neteasemusic/README.zh-CN.md +31 -0
- package/src/clis/neteasemusic/like.ts +28 -0
- package/src/clis/neteasemusic/lyrics.ts +53 -0
- package/src/clis/neteasemusic/next.ts +30 -0
- package/src/clis/neteasemusic/play.ts +30 -0
- package/src/clis/neteasemusic/playing.ts +62 -0
- package/src/clis/neteasemusic/playlist.ts +51 -0
- package/src/clis/neteasemusic/prev.ts +29 -0
- package/src/clis/neteasemusic/search.ts +58 -0
- package/src/clis/neteasemusic/status.ts +18 -0
- package/src/clis/neteasemusic/volume.ts +61 -0
- package/src/clis/notion/README.md +29 -0
- package/src/clis/notion/README.zh-CN.md +29 -0
- package/src/clis/notion/export.ts +36 -0
- package/src/clis/notion/favorites.ts +87 -0
- package/src/clis/notion/new.ts +39 -0
- package/src/clis/notion/read.ts +33 -0
- package/src/clis/notion/search.ts +54 -0
- package/src/clis/notion/sidebar.ts +44 -0
- package/src/clis/notion/status.ts +18 -0
- package/src/clis/notion/write.ts +45 -0
- package/src/clis/twitter/download.ts +227 -0
- package/src/clis/wechat/README.md +28 -0
- package/src/clis/wechat/README.zh-CN.md +28 -0
- package/src/clis/wechat/chats.ts +33 -0
- package/src/clis/wechat/contacts.ts +33 -0
- package/src/clis/wechat/read.ts +72 -0
- package/src/clis/wechat/search.ts +36 -0
- package/src/clis/wechat/send.ts +49 -0
- package/src/clis/wechat/status.ts +35 -0
- package/src/clis/xiaohongshu/creator-note-detail.ts +95 -0
- package/src/clis/xiaohongshu/creator-notes.ts +116 -0
- package/src/clis/xiaohongshu/creator-profile.ts +60 -0
- package/src/clis/xiaohongshu/creator-stats.ts +81 -0
- package/src/clis/xiaohongshu/download.ts +173 -0
- package/src/clis/xiaohongshu/search.ts +1 -1
- package/src/clis/xiaohongshu/user-helpers.test.ts +106 -0
- package/src/clis/xiaohongshu/user-helpers.ts +85 -0
- package/src/clis/xiaohongshu/user.ts +52 -32
- package/src/clis/zhihu/download.test.ts +12 -0
- package/src/clis/zhihu/download.ts +223 -0
- package/src/daemon.ts +217 -0
- package/src/doctor.test.ts +32 -193
- package/src/doctor.ts +74 -668
- package/src/download/index.ts +395 -0
- package/src/download/progress.ts +125 -0
- package/src/engine.test.ts +17 -0
- package/src/main.ts +18 -26
- package/src/pipeline/executor.test.ts +1 -0
- package/src/pipeline/registry.ts +2 -0
- package/src/pipeline/steps/browser.ts +2 -2
- package/src/pipeline/steps/download.ts +310 -0
- package/src/pipeline/steps/intercept.ts +1 -2
- package/src/pipeline/template.ts +26 -0
- package/src/setup.ts +47 -183
- package/src/types.ts +1 -0
- package/tests/e2e/browser-auth.test.ts +25 -0
package/dist/setup.js
CHANGED
|
@@ -1,180 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* setup.ts — Interactive
|
|
2
|
+
* setup.ts — Interactive browser setup for opencli
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Simplified for daemon-based architecture. No more token management.
|
|
5
|
+
* Just verifies daemon + extension connectivity.
|
|
6
6
|
*/
|
|
7
|
-
import * as fs from 'node:fs';
|
|
8
7
|
import chalk from 'chalk';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { getTokenFingerprint } from './browser/index.js';
|
|
13
|
-
import { checkboxPrompt } from './tui.js';
|
|
8
|
+
import { checkDaemonStatus } from './browser/discover.js';
|
|
9
|
+
import { checkConnectivity } from './doctor.js';
|
|
10
|
+
import { PlaywrightMCP } from './browser/index.js';
|
|
14
11
|
export async function runSetup(opts = {}) {
|
|
15
12
|
console.log();
|
|
16
|
-
console.log(chalk.bold(' opencli setup') + chalk.dim(' —
|
|
13
|
+
console.log(chalk.bold(' opencli setup') + chalk.dim(' — browser bridge configuration'));
|
|
17
14
|
console.log();
|
|
18
|
-
// Step 1:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (extensionToken && envToken && extensionToken === envToken) {
|
|
24
|
-
token = extensionToken;
|
|
25
|
-
console.log(` ${chalk.green('✓')} Token auto-discovered from Chrome extension`);
|
|
26
|
-
console.log(` Fingerprint: ${chalk.bold(getTokenFingerprint(token) ?? 'unknown')}`);
|
|
27
|
-
}
|
|
28
|
-
else if (extensionToken) {
|
|
29
|
-
token = extensionToken;
|
|
30
|
-
console.log(` ${chalk.green('✓')} Token discovered from Chrome extension ` +
|
|
31
|
-
chalk.dim(`(${getTokenFingerprint(token)})`));
|
|
32
|
-
if (envToken && envToken !== extensionToken) {
|
|
33
|
-
console.log(` ${chalk.yellow('!')} Environment has different token ` +
|
|
34
|
-
chalk.dim(`(${getTokenFingerprint(envToken)})`));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
else if (envToken) {
|
|
38
|
-
token = envToken;
|
|
39
|
-
console.log(` ${chalk.green('✓')} Token from environment variable ` +
|
|
40
|
-
chalk.dim(`(${getTokenFingerprint(token)})`));
|
|
41
|
-
}
|
|
15
|
+
// Step 1: Check daemon
|
|
16
|
+
console.log(chalk.dim(' Checking daemon status...'));
|
|
17
|
+
const status = await checkDaemonStatus();
|
|
18
|
+
if (status.running) {
|
|
19
|
+
console.log(` ${chalk.green('✓')} Daemon is running on port 19825`);
|
|
42
20
|
}
|
|
43
21
|
else {
|
|
44
|
-
console.log(` ${chalk.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
console.log(chalk.
|
|
53
|
-
console.log(chalk.dim(' Fix: Install from https://chromewebstore.google.com/detail/'));
|
|
54
|
-
console.log(chalk.dim(' playwright-mcp-bridge/mmlmfjhmonkocbjadbfplnigmagldckm'));
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
console.log(chalk.dim(` Cause: Extension is installed (${extInstall.browsers.join(', ')}) but token not found in LevelDB`));
|
|
58
|
-
console.log(chalk.dim(' Fix: 1) Open the extension popup and verify the token is generated'));
|
|
59
|
-
console.log(chalk.dim(' 2) Close Chrome completely, then re-run setup'));
|
|
60
|
-
}
|
|
61
|
-
console.log();
|
|
62
|
-
console.log(` You can enter the token manually, or fix the above and re-run ${chalk.bold('opencli setup')}.`);
|
|
63
|
-
console.log();
|
|
64
|
-
const rl = createInterface({ input, output });
|
|
65
|
-
const answer = await rl.question(' Token (press Enter to abort): ');
|
|
66
|
-
rl.close();
|
|
67
|
-
token = answer.trim();
|
|
68
|
-
if (!token) {
|
|
69
|
-
console.log(chalk.red('\n No token provided. Aborting.\n'));
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
const fingerprint = getTokenFingerprint(token) ?? 'unknown';
|
|
74
|
-
console.log();
|
|
75
|
-
// Step 2: Scan all config locations
|
|
76
|
-
const report = await runBrowserDoctor({ token, cliVersion: opts.cliVersion });
|
|
77
|
-
// Step 3: Build checkbox items
|
|
78
|
-
const items = [];
|
|
79
|
-
// Shell file
|
|
80
|
-
const shellPath = report.shellFiles[0]?.path ?? getDefaultShellRcPath();
|
|
81
|
-
const shellStatus = report.shellFiles[0];
|
|
82
|
-
const shellFp = shellStatus?.fingerprint;
|
|
83
|
-
const shellOk = shellFp === fingerprint;
|
|
84
|
-
const shellTool = toolName(shellPath) || 'Shell';
|
|
85
|
-
items.push({
|
|
86
|
-
label: padRight(shortenPath(shellPath), 50) + chalk.dim(` [${shellTool}]`),
|
|
87
|
-
value: `shell:${shellPath}`,
|
|
88
|
-
checked: !shellOk,
|
|
89
|
-
status: shellOk ? `configured (${shellFp})` : shellFp ? `mismatch (${shellFp})` : 'missing',
|
|
90
|
-
statusColor: shellOk ? 'green' : shellFp ? 'yellow' : 'red',
|
|
91
|
-
});
|
|
92
|
-
// Config files
|
|
93
|
-
for (const config of report.configs) {
|
|
94
|
-
const fp = config.fingerprint;
|
|
95
|
-
const ok = fp === fingerprint;
|
|
96
|
-
const tool = toolName(config.path);
|
|
97
|
-
items.push({
|
|
98
|
-
label: padRight(shortenPath(config.path), 50) + chalk.dim(tool ? ` [${tool}]` : ''),
|
|
99
|
-
value: `config:${config.path}`,
|
|
100
|
-
checked: false, // let user explicitly select which tools to configure
|
|
101
|
-
status: ok ? `configured (${fp})` : !config.exists ? 'will create' : fp ? `mismatch (${fp})` : 'missing',
|
|
102
|
-
statusColor: ok ? 'green' : 'yellow',
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
// Step 4: Show interactive checkbox
|
|
106
|
-
console.clear();
|
|
107
|
-
const selected = await checkboxPrompt(items, {
|
|
108
|
-
title: ` ${chalk.bold('opencli setup')} — token ${chalk.cyan(fingerprint)}`,
|
|
109
|
-
});
|
|
110
|
-
if (selected.length === 0) {
|
|
111
|
-
console.log(chalk.dim(' No changes made.\n'));
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
// Step 5: Apply changes
|
|
115
|
-
const written = [];
|
|
116
|
-
let wroteShell = false;
|
|
117
|
-
for (const sel of selected) {
|
|
118
|
-
if (sel.startsWith('shell:')) {
|
|
119
|
-
const p = sel.slice('shell:'.length);
|
|
120
|
-
const before = fileExists(p) ? fs.readFileSync(p, 'utf-8') : '';
|
|
121
|
-
writeFileWithMkdir(p, upsertShellToken(before, token, p));
|
|
122
|
-
written.push(p);
|
|
123
|
-
wroteShell = true;
|
|
22
|
+
console.log(` ${chalk.yellow('!')} Daemon is not running`);
|
|
23
|
+
console.log(chalk.dim(' The daemon starts automatically when you run a browser command.'));
|
|
24
|
+
console.log(chalk.dim(' Starting daemon now...'));
|
|
25
|
+
// Try to spawn daemon
|
|
26
|
+
const mcp = new PlaywrightMCP();
|
|
27
|
+
try {
|
|
28
|
+
await mcp.connect({ timeout: 5 });
|
|
29
|
+
await mcp.close();
|
|
30
|
+
console.log(` ${chalk.green('✓')} Daemon started successfully`);
|
|
124
31
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const config = report.configs.find(c => c.path === p);
|
|
128
|
-
if (config && config.parseError)
|
|
129
|
-
continue;
|
|
130
|
-
const before = fileExists(p) ? fs.readFileSync(p, 'utf-8') : '';
|
|
131
|
-
const format = config?.format ?? (p.endsWith('.toml') ? 'toml' : 'json');
|
|
132
|
-
const next = format === 'toml' ? upsertTomlConfigToken(before, token) : upsertJsonConfigToken(before, token, p);
|
|
133
|
-
writeFileWithMkdir(p, next);
|
|
134
|
-
written.push(p);
|
|
32
|
+
catch {
|
|
33
|
+
console.log(` ${chalk.yellow('!')} Could not start daemon automatically`);
|
|
135
34
|
}
|
|
136
35
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if (
|
|
140
|
-
console.log(chalk.green
|
|
141
|
-
for (const p of written) {
|
|
142
|
-
const tool = toolName(p);
|
|
143
|
-
console.log(` ${chalk.dim('•')} ${shortenPath(p)}${tool ? chalk.dim(` [${tool}]`) : ''}`);
|
|
144
|
-
}
|
|
145
|
-
if (wroteShell) {
|
|
146
|
-
console.log();
|
|
147
|
-
console.log(chalk.cyan(` 💡 Run ${chalk.bold(`source ${shortenPath(shellPath)}`)} to apply token to current shell.`));
|
|
148
|
-
}
|
|
36
|
+
// Step 2: Check extension
|
|
37
|
+
const statusAfter = await checkDaemonStatus();
|
|
38
|
+
if (statusAfter.extensionConnected) {
|
|
39
|
+
console.log(` ${chalk.green('✓')} Chrome extension connected`);
|
|
149
40
|
}
|
|
150
41
|
else {
|
|
151
|
-
console.log(chalk.
|
|
42
|
+
console.log(` ${chalk.red('✗')} Chrome extension not connected`);
|
|
43
|
+
console.log();
|
|
44
|
+
console.log(chalk.dim(' To install the opencli Browser Bridge extension:'));
|
|
45
|
+
console.log(chalk.dim(' 1. Download from GitHub Releases'));
|
|
46
|
+
console.log(chalk.dim(' 2. Open chrome://extensions/ → Enable Developer Mode'));
|
|
47
|
+
console.log(chalk.dim(' 3. Click "Load unpacked" → select the extension folder'));
|
|
48
|
+
console.log(chalk.dim(' 4. Make sure Chrome is running'));
|
|
49
|
+
console.log();
|
|
50
|
+
return;
|
|
152
51
|
}
|
|
52
|
+
// Step 3: Test connectivity
|
|
153
53
|
console.log();
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
console.log(` ${chalk.green('✓')} Token saved successfully.`);
|
|
163
|
-
console.log(` ${chalk.yellow('!')} Browser connectivity test failed: ${result.error ?? 'unknown'}`);
|
|
164
|
-
console.log(chalk.dim(' Token configuration is complete. To use opencli, make sure Chrome'));
|
|
165
|
-
console.log(chalk.dim(' is running with the Playwright MCP Bridge extension enabled.'));
|
|
166
|
-
console.log(chalk.dim(` Run ${chalk.bold('opencli doctor --live')} to re-test connectivity.`));
|
|
167
|
-
}
|
|
54
|
+
console.log(chalk.dim(' Testing browser connectivity...'));
|
|
55
|
+
const conn = await checkConnectivity({ timeout: 5 });
|
|
56
|
+
if (conn.ok) {
|
|
57
|
+
console.log(` ${chalk.green('✓')} Browser connected in ${(conn.durationMs / 1000).toFixed(1)}s`);
|
|
58
|
+
console.log();
|
|
59
|
+
console.log(chalk.green.bold(' ✓ Setup complete! You can now use opencli browser commands.'));
|
|
168
60
|
}
|
|
169
|
-
|
|
170
|
-
console.log(` ${chalk.
|
|
171
|
-
console.log(`
|
|
172
|
-
console.log(chalk.dim(' Token configuration is complete. Start Chrome to begin using opencli.'));
|
|
173
|
-
console.log(chalk.dim(` Run ${chalk.bold('opencli doctor --live')} to re-test connectivity.`));
|
|
61
|
+
else {
|
|
62
|
+
console.log(` ${chalk.yellow('!')} Connectivity test failed: ${conn.error ?? 'unknown'}`);
|
|
63
|
+
console.log(chalk.dim(` Run ${chalk.bold('opencli doctor --live')} to diagnose.`));
|
|
174
64
|
}
|
|
175
65
|
console.log();
|
|
176
66
|
}
|
|
177
|
-
function padRight(s, n) {
|
|
178
|
-
const visible = s.replace(/\x1b\[[0-9;]*m/g, '');
|
|
179
|
-
return visible.length >= n ? s : s + ' '.repeat(n - visible.length);
|
|
180
|
-
}
|
package/dist/types.d.ts
CHANGED
|
@@ -34,4 +34,10 @@ export interface IPage {
|
|
|
34
34
|
}): Promise<void>;
|
|
35
35
|
installInterceptor(pattern: string): Promise<void>;
|
|
36
36
|
getInterceptedRequests(): Promise<any[]>;
|
|
37
|
+
screenshot(options?: {
|
|
38
|
+
format?: 'png' | 'jpeg';
|
|
39
|
+
quality?: number;
|
|
40
|
+
fullPage?: boolean;
|
|
41
|
+
path?: string;
|
|
42
|
+
}): Promise<string>;
|
|
37
43
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"manifest_version": 3,
|
|
3
|
+
"name": "opencli Browser Bridge",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Bridge between opencli CLI and your browser — execute commands, read cookies, manage tabs.",
|
|
6
|
+
"permissions": [
|
|
7
|
+
"debugger",
|
|
8
|
+
"tabs",
|
|
9
|
+
"cookies",
|
|
10
|
+
"activeTab",
|
|
11
|
+
"alarms"
|
|
12
|
+
],
|
|
13
|
+
"background": {
|
|
14
|
+
"service_worker": "dist/background.js",
|
|
15
|
+
"type": "module"
|
|
16
|
+
},
|
|
17
|
+
"icons": {
|
|
18
|
+
"16": "icons/icon-16.png",
|
|
19
|
+
"32": "icons/icon-32.png",
|
|
20
|
+
"48": "icons/icon-48.png",
|
|
21
|
+
"128": "icons/icon-128.png"
|
|
22
|
+
},
|
|
23
|
+
"action": {
|
|
24
|
+
"default_title": "opencli Browser Bridge",
|
|
25
|
+
"default_icon": {
|
|
26
|
+
"16": "icons/icon-16.png",
|
|
27
|
+
"32": "icons/icon-32.png"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"homepage_url": "https://github.com/jackwener/opencli"
|
|
31
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencli-extension",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite build --watch",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"typecheck": "tsc --noEmit"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@types/chrome": "^0.0.287",
|
|
13
|
+
"typescript": "^5.7.0",
|
|
14
|
+
"vite": "^6.0.0"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* opencli Browser Bridge — Service Worker (background script).
|
|
3
|
+
*
|
|
4
|
+
* Connects to the opencli daemon via WebSocket, receives commands,
|
|
5
|
+
* dispatches them to Chrome APIs (debugger/tabs/cookies), returns results.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Command, Result } from './protocol';
|
|
9
|
+
import { DAEMON_WS_URL, WS_RECONNECT_BASE_DELAY, WS_RECONNECT_MAX_DELAY } from './protocol';
|
|
10
|
+
import * as cdp from './cdp';
|
|
11
|
+
|
|
12
|
+
let ws: WebSocket | null = null;
|
|
13
|
+
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
|
14
|
+
let reconnectAttempts = 0;
|
|
15
|
+
|
|
16
|
+
// ─── Console log forwarding ──────────────────────────────────────────
|
|
17
|
+
// Hook console.log/warn/error to forward logs to daemon via WebSocket.
|
|
18
|
+
|
|
19
|
+
const _origLog = console.log.bind(console);
|
|
20
|
+
const _origWarn = console.warn.bind(console);
|
|
21
|
+
const _origError = console.error.bind(console);
|
|
22
|
+
|
|
23
|
+
function forwardLog(level: 'info' | 'warn' | 'error', args: unknown[]): void {
|
|
24
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
25
|
+
try {
|
|
26
|
+
const msg = args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ');
|
|
27
|
+
ws.send(JSON.stringify({ type: 'log', level, msg, ts: Date.now() }));
|
|
28
|
+
} catch { /* don't recurse */ }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log = (...args: unknown[]) => { _origLog(...args); forwardLog('info', args); };
|
|
32
|
+
console.warn = (...args: unknown[]) => { _origWarn(...args); forwardLog('warn', args); };
|
|
33
|
+
console.error = (...args: unknown[]) => { _origError(...args); forwardLog('error', args); };
|
|
34
|
+
|
|
35
|
+
// ─── WebSocket connection ────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
function connect(): void {
|
|
38
|
+
if (ws?.readyState === WebSocket.OPEN || ws?.readyState === WebSocket.CONNECTING) return;
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
ws = new WebSocket(DAEMON_WS_URL);
|
|
42
|
+
} catch {
|
|
43
|
+
scheduleReconnect();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
ws.onopen = () => {
|
|
48
|
+
console.log('[opencli] Connected to daemon');
|
|
49
|
+
reconnectAttempts = 0; // Reset on successful connection
|
|
50
|
+
if (reconnectTimer) {
|
|
51
|
+
clearTimeout(reconnectTimer);
|
|
52
|
+
reconnectTimer = null;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
ws.onmessage = async (event) => {
|
|
57
|
+
try {
|
|
58
|
+
const command = JSON.parse(event.data as string) as Command;
|
|
59
|
+
const result = await handleCommand(command);
|
|
60
|
+
ws?.send(JSON.stringify(result));
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error('[opencli] Message handling error:', err);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
ws.onclose = () => {
|
|
67
|
+
console.log('[opencli] Disconnected from daemon');
|
|
68
|
+
ws = null;
|
|
69
|
+
scheduleReconnect();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
ws.onerror = () => {
|
|
73
|
+
ws?.close();
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function scheduleReconnect(): void {
|
|
78
|
+
if (reconnectTimer) return;
|
|
79
|
+
reconnectAttempts++;
|
|
80
|
+
// Exponential backoff: 2s, 4s, 8s, 16s, ..., capped at 60s
|
|
81
|
+
const delay = Math.min(WS_RECONNECT_BASE_DELAY * Math.pow(2, reconnectAttempts - 1), WS_RECONNECT_MAX_DELAY);
|
|
82
|
+
reconnectTimer = setTimeout(() => {
|
|
83
|
+
reconnectTimer = null;
|
|
84
|
+
connect();
|
|
85
|
+
}, delay);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ─── Lifecycle events ────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
let initialized = false;
|
|
91
|
+
|
|
92
|
+
function initialize(): void {
|
|
93
|
+
if (initialized) return;
|
|
94
|
+
initialized = true;
|
|
95
|
+
chrome.alarms.create('keepalive', { periodInMinutes: 0.4 }); // ~24 seconds
|
|
96
|
+
cdp.registerListeners();
|
|
97
|
+
connect();
|
|
98
|
+
console.log('[opencli] Browser Bridge extension initialized');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
chrome.runtime.onInstalled.addListener(() => {
|
|
102
|
+
initialize();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
chrome.runtime.onStartup.addListener(() => {
|
|
106
|
+
initialize();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
chrome.alarms.onAlarm.addListener((alarm) => {
|
|
110
|
+
if (alarm.name === 'keepalive') connect();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// ─── Command dispatcher ─────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
async function handleCommand(cmd: Command): Promise<Result> {
|
|
116
|
+
try {
|
|
117
|
+
switch (cmd.action) {
|
|
118
|
+
case 'exec':
|
|
119
|
+
return await handleExec(cmd);
|
|
120
|
+
case 'navigate':
|
|
121
|
+
return await handleNavigate(cmd);
|
|
122
|
+
case 'tabs':
|
|
123
|
+
return await handleTabs(cmd);
|
|
124
|
+
case 'cookies':
|
|
125
|
+
return await handleCookies(cmd);
|
|
126
|
+
case 'screenshot':
|
|
127
|
+
return await handleScreenshot(cmd);
|
|
128
|
+
default:
|
|
129
|
+
return { id: cmd.id, ok: false, error: `Unknown action: ${cmd.action}` };
|
|
130
|
+
}
|
|
131
|
+
} catch (err) {
|
|
132
|
+
return {
|
|
133
|
+
id: cmd.id,
|
|
134
|
+
ok: false,
|
|
135
|
+
error: err instanceof Error ? err.message : String(err),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ─── Action handlers ─────────────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
/** Check if a URL is a debuggable web page (not chrome:// or extension page) */
|
|
143
|
+
function isWebUrl(url?: string): boolean {
|
|
144
|
+
if (!url) return false;
|
|
145
|
+
return !url.startsWith('chrome://') && !url.startsWith('chrome-extension://');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Resolve target tab: use specified tabId or fall back to active web page tab */
|
|
149
|
+
async function resolveTabId(tabId?: number): Promise<number> {
|
|
150
|
+
if (tabId !== undefined) return tabId;
|
|
151
|
+
|
|
152
|
+
// Try the active tab first
|
|
153
|
+
const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
154
|
+
if (activeTab?.id && isWebUrl(activeTab.url)) {
|
|
155
|
+
return activeTab.id;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Active tab is not debuggable — try to find any open web page tab
|
|
159
|
+
const allTabs = await chrome.tabs.query({ currentWindow: true });
|
|
160
|
+
const webTab = allTabs.find(t => t.id && isWebUrl(t.url));
|
|
161
|
+
if (webTab?.id) {
|
|
162
|
+
await chrome.tabs.update(webTab.id, { active: true });
|
|
163
|
+
return webTab.id;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// No web tabs at all — create one
|
|
167
|
+
const newTab = await chrome.tabs.create({ url: 'about:blank', active: true });
|
|
168
|
+
if (!newTab.id) throw new Error('Failed to create new tab');
|
|
169
|
+
return newTab.id;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function handleExec(cmd: Command): Promise<Result> {
|
|
173
|
+
if (!cmd.code) return { id: cmd.id, ok: false, error: 'Missing code' };
|
|
174
|
+
const tabId = await resolveTabId(cmd.tabId);
|
|
175
|
+
try {
|
|
176
|
+
const data = await cdp.evaluateAsync(tabId, cmd.code);
|
|
177
|
+
return { id: cmd.id, ok: true, data };
|
|
178
|
+
} catch (err) {
|
|
179
|
+
return { id: cmd.id, ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function handleNavigate(cmd: Command): Promise<Result> {
|
|
184
|
+
if (!cmd.url) return { id: cmd.id, ok: false, error: 'Missing url' };
|
|
185
|
+
const tabId = await resolveTabId(cmd.tabId);
|
|
186
|
+
await chrome.tabs.update(tabId, { url: cmd.url });
|
|
187
|
+
|
|
188
|
+
// Wait for page to finish loading, checking current status first to avoid race
|
|
189
|
+
await new Promise<void>((resolve) => {
|
|
190
|
+
// Check if already complete (e.g. cached pages)
|
|
191
|
+
chrome.tabs.get(tabId).then(tab => {
|
|
192
|
+
if (tab.status === 'complete') { resolve(); return; }
|
|
193
|
+
|
|
194
|
+
const listener = (id: number, info: chrome.tabs.TabChangeInfo) => {
|
|
195
|
+
if (id === tabId && info.status === 'complete') {
|
|
196
|
+
chrome.tabs.onUpdated.removeListener(listener);
|
|
197
|
+
resolve();
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
chrome.tabs.onUpdated.addListener(listener);
|
|
201
|
+
// Timeout fallback
|
|
202
|
+
setTimeout(() => {
|
|
203
|
+
chrome.tabs.onUpdated.removeListener(listener);
|
|
204
|
+
resolve();
|
|
205
|
+
}, 15000);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const tab = await chrome.tabs.get(tabId);
|
|
210
|
+
return { id: cmd.id, ok: true, data: { title: tab.title, url: tab.url, tabId } };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function handleTabs(cmd: Command): Promise<Result> {
|
|
214
|
+
switch (cmd.op) {
|
|
215
|
+
case 'list': {
|
|
216
|
+
const tabs = await chrome.tabs.query({});
|
|
217
|
+
const data = tabs
|
|
218
|
+
.filter((t) => isWebUrl(t.url))
|
|
219
|
+
.map((t, i) => ({
|
|
220
|
+
index: i,
|
|
221
|
+
tabId: t.id,
|
|
222
|
+
url: t.url,
|
|
223
|
+
title: t.title,
|
|
224
|
+
active: t.active,
|
|
225
|
+
}));
|
|
226
|
+
return { id: cmd.id, ok: true, data };
|
|
227
|
+
}
|
|
228
|
+
case 'new': {
|
|
229
|
+
const tab = await chrome.tabs.create({ url: cmd.url, active: true });
|
|
230
|
+
return { id: cmd.id, ok: true, data: { tabId: tab.id, url: tab.url } };
|
|
231
|
+
}
|
|
232
|
+
case 'close': {
|
|
233
|
+
if (cmd.index !== undefined) {
|
|
234
|
+
const tabs = await chrome.tabs.query({});
|
|
235
|
+
const target = tabs[cmd.index];
|
|
236
|
+
if (!target?.id) return { id: cmd.id, ok: false, error: `Tab index ${cmd.index} not found` };
|
|
237
|
+
await chrome.tabs.remove(target.id);
|
|
238
|
+
cdp.detach(target.id);
|
|
239
|
+
return { id: cmd.id, ok: true, data: { closed: target.id } };
|
|
240
|
+
}
|
|
241
|
+
const tabId = await resolveTabId(cmd.tabId);
|
|
242
|
+
await chrome.tabs.remove(tabId);
|
|
243
|
+
cdp.detach(tabId);
|
|
244
|
+
return { id: cmd.id, ok: true, data: { closed: tabId } };
|
|
245
|
+
}
|
|
246
|
+
case 'select': {
|
|
247
|
+
if (cmd.index === undefined && cmd.tabId === undefined)
|
|
248
|
+
return { id: cmd.id, ok: false, error: 'Missing index or tabId' };
|
|
249
|
+
if (cmd.tabId !== undefined) {
|
|
250
|
+
await chrome.tabs.update(cmd.tabId, { active: true });
|
|
251
|
+
return { id: cmd.id, ok: true, data: { selected: cmd.tabId } };
|
|
252
|
+
}
|
|
253
|
+
const tabs = await chrome.tabs.query({});
|
|
254
|
+
const target = tabs[cmd.index!];
|
|
255
|
+
if (!target?.id) return { id: cmd.id, ok: false, error: `Tab index ${cmd.index} not found` };
|
|
256
|
+
await chrome.tabs.update(target.id, { active: true });
|
|
257
|
+
return { id: cmd.id, ok: true, data: { selected: target.id } };
|
|
258
|
+
}
|
|
259
|
+
default:
|
|
260
|
+
return { id: cmd.id, ok: false, error: `Unknown tabs op: ${cmd.op}` };
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function handleCookies(cmd: Command): Promise<Result> {
|
|
265
|
+
const details: chrome.cookies.GetAllDetails = {};
|
|
266
|
+
if (cmd.domain) details.domain = cmd.domain;
|
|
267
|
+
if (cmd.url) details.url = cmd.url;
|
|
268
|
+
const cookies = await chrome.cookies.getAll(details);
|
|
269
|
+
const data = cookies.map((c) => ({
|
|
270
|
+
name: c.name,
|
|
271
|
+
value: c.value,
|
|
272
|
+
domain: c.domain,
|
|
273
|
+
path: c.path,
|
|
274
|
+
secure: c.secure,
|
|
275
|
+
httpOnly: c.httpOnly,
|
|
276
|
+
expirationDate: c.expirationDate,
|
|
277
|
+
}));
|
|
278
|
+
return { id: cmd.id, ok: true, data };
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async function handleScreenshot(cmd: Command): Promise<Result> {
|
|
282
|
+
const tabId = await resolveTabId(cmd.tabId);
|
|
283
|
+
try {
|
|
284
|
+
const data = await cdp.screenshot(tabId, {
|
|
285
|
+
format: cmd.format,
|
|
286
|
+
quality: cmd.quality,
|
|
287
|
+
fullPage: cmd.fullPage,
|
|
288
|
+
});
|
|
289
|
+
return { id: cmd.id, ok: true, data };
|
|
290
|
+
} catch (err) {
|
|
291
|
+
return { id: cmd.id, ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
292
|
+
}
|
|
293
|
+
}
|