@jackwener/opencli 1.5.6 → 1.5.8
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 +34 -0
- package/README.md +4 -2
- package/README.zh-CN.md +4 -1
- package/SKILL.md +879 -0
- package/dist/browser/cdp.d.ts +1 -0
- package/dist/browser/cdp.js +30 -27
- package/dist/browser/daemon-client.d.ts +7 -1
- package/dist/browser/daemon-client.js +3 -0
- package/dist/browser/dom-helpers.js +1 -0
- package/dist/browser/dom-helpers.test.js +14 -1
- package/dist/browser/mcp.js +18 -13
- package/dist/browser/page.js +22 -2
- package/dist/browser/page.test.d.ts +1 -0
- package/dist/browser/page.test.js +44 -0
- package/dist/browser/stealth.js +198 -0
- package/dist/browser/stealth.test.d.ts +1 -0
- package/dist/browser/stealth.test.js +134 -0
- package/dist/browser.test.js +1 -1
- package/dist/build-manifest.d.ts +1 -0
- package/dist/build-manifest.js +5 -1
- package/dist/build-manifest.test.js +2 -0
- package/dist/cli-manifest.json +544 -137
- package/dist/cli.js +20 -3
- package/dist/clis/antigravity/serve.d.ts +1 -1
- package/dist/clis/antigravity/serve.js +5 -8
- package/dist/clis/bilibili/subtitle.js +4 -0
- package/dist/clis/bilibili/subtitle.test.d.ts +1 -0
- package/dist/clis/bilibili/subtitle.test.js +48 -0
- package/dist/clis/chatwise/ask.js +0 -2
- package/dist/clis/chatwise/export.js +0 -2
- package/dist/clis/chatwise/history.js +0 -2
- package/dist/clis/chatwise/model.js +0 -2
- package/dist/clis/chatwise/new.js +1 -2
- package/dist/clis/chatwise/read.js +0 -2
- package/dist/clis/chatwise/screenshot.js +1 -2
- package/dist/clis/chatwise/send.js +0 -2
- package/dist/clis/chatwise/status.js +1 -2
- package/dist/clis/ctrip/search.d.ts +13 -0
- package/dist/clis/ctrip/search.js +73 -48
- package/dist/clis/ctrip/search.test.d.ts +1 -0
- package/dist/clis/ctrip/search.test.js +64 -0
- package/dist/clis/douyin/_shared/sts2.js +8 -2
- package/dist/clis/douyin/_shared/sts2.test.d.ts +1 -0
- package/dist/clis/douyin/_shared/sts2.test.js +27 -0
- package/dist/clis/douyin/activities.js +4 -2
- package/dist/clis/douyin/activities.test.js +34 -1
- package/dist/clis/douyin/collections.js +1 -1
- package/dist/clis/douyin/collections.test.js +24 -2
- package/dist/clis/douyin/draft.d.ts +8 -11
- package/dist/clis/douyin/draft.js +302 -185
- package/dist/clis/douyin/draft.test.d.ts +1 -1
- package/dist/clis/douyin/draft.test.js +357 -2
- package/dist/clis/douyin/hashtag.js +9 -2
- package/dist/clis/douyin/hashtag.test.js +35 -2
- package/dist/clis/douyin/profile.js +1 -1
- package/dist/clis/douyin/profile.test.js +36 -1
- package/dist/clis/douyin/videos.js +22 -5
- package/dist/clis/douyin/videos.test.js +45 -2
- package/dist/clis/facebook/search.test.d.ts +5 -0
- package/dist/clis/facebook/search.test.js +60 -0
- package/dist/clis/facebook/search.yaml +4 -3
- package/dist/clis/instagram/download.d.ts +16 -0
- package/dist/clis/instagram/download.js +225 -0
- package/dist/clis/instagram/download.test.d.ts +1 -0
- package/dist/clis/instagram/download.test.js +118 -0
- package/dist/clis/notebooklm/bind-current.d.ts +1 -0
- package/dist/clis/notebooklm/bind-current.js +29 -0
- package/dist/clis/notebooklm/bind-current.test.d.ts +1 -0
- package/dist/clis/notebooklm/bind-current.test.js +35 -0
- package/dist/clis/notebooklm/binding.test.d.ts +1 -0
- package/dist/clis/notebooklm/binding.test.js +44 -0
- package/dist/clis/notebooklm/compat.test.d.ts +3 -0
- package/dist/clis/notebooklm/compat.test.js +16 -0
- package/dist/clis/notebooklm/current.d.ts +1 -0
- package/dist/clis/notebooklm/current.js +28 -0
- package/dist/clis/notebooklm/get.d.ts +1 -0
- package/dist/clis/notebooklm/get.js +37 -0
- package/dist/clis/notebooklm/history.d.ts +1 -0
- package/dist/clis/notebooklm/history.js +25 -0
- package/dist/clis/notebooklm/history.test.d.ts +1 -0
- package/dist/clis/notebooklm/history.test.js +58 -0
- package/dist/clis/notebooklm/list.d.ts +1 -0
- package/dist/clis/notebooklm/list.js +35 -0
- package/dist/clis/notebooklm/note-list.d.ts +1 -0
- package/dist/clis/notebooklm/note-list.js +28 -0
- package/dist/clis/notebooklm/note-list.test.d.ts +1 -0
- package/dist/clis/notebooklm/note-list.test.js +56 -0
- package/dist/clis/notebooklm/notes-get.d.ts +1 -0
- package/dist/clis/notebooklm/notes-get.js +47 -0
- package/dist/clis/notebooklm/notes-get.test.d.ts +1 -0
- package/dist/clis/notebooklm/notes-get.test.js +72 -0
- package/dist/clis/notebooklm/rpc.d.ts +36 -0
- package/dist/clis/notebooklm/rpc.js +189 -0
- package/dist/clis/notebooklm/rpc.test.d.ts +1 -0
- package/dist/clis/notebooklm/rpc.test.js +105 -0
- package/dist/clis/notebooklm/shared.d.ts +87 -0
- package/dist/clis/notebooklm/shared.js +3 -0
- package/dist/clis/notebooklm/source-fulltext.d.ts +1 -0
- package/dist/clis/notebooklm/source-fulltext.js +44 -0
- package/dist/clis/notebooklm/source-fulltext.test.d.ts +1 -0
- package/dist/clis/notebooklm/source-fulltext.test.js +106 -0
- package/dist/clis/notebooklm/source-get.d.ts +1 -0
- package/dist/clis/notebooklm/source-get.js +40 -0
- package/dist/clis/notebooklm/source-get.test.d.ts +1 -0
- package/dist/clis/notebooklm/source-get.test.js +84 -0
- package/dist/clis/notebooklm/source-guide.d.ts +1 -0
- package/dist/clis/notebooklm/source-guide.js +44 -0
- package/dist/clis/notebooklm/source-guide.test.d.ts +1 -0
- package/dist/clis/notebooklm/source-guide.test.js +104 -0
- package/dist/clis/notebooklm/source-list.d.ts +1 -0
- package/dist/clis/notebooklm/source-list.js +30 -0
- package/dist/clis/notebooklm/status.d.ts +1 -0
- package/dist/clis/notebooklm/status.js +31 -0
- package/dist/clis/notebooklm/summary.d.ts +1 -0
- package/dist/clis/notebooklm/summary.js +30 -0
- package/dist/clis/notebooklm/summary.test.d.ts +1 -0
- package/dist/clis/notebooklm/summary.test.js +78 -0
- package/dist/clis/notebooklm/utils.d.ts +37 -0
- package/dist/clis/notebooklm/utils.js +739 -0
- package/dist/clis/notebooklm/utils.test.d.ts +1 -0
- package/dist/clis/notebooklm/utils.test.js +390 -0
- package/dist/clis/substack/utils.d.ts +4 -0
- package/dist/clis/substack/utils.js +8 -2
- package/dist/clis/substack/utils.test.d.ts +1 -0
- package/dist/clis/substack/utils.test.js +46 -0
- package/dist/clis/v2ex/hot.yaml +4 -1
- package/dist/clis/v2ex/latest.yaml +4 -1
- package/dist/clis/v2ex/topic.yaml +6 -1
- package/dist/clis/weixin/download.d.ts +9 -0
- package/dist/clis/weixin/download.js +76 -6
- package/dist/clis/weread/book.js +108 -2
- package/dist/clis/weread/commands.test.js +262 -152
- package/dist/clis/weread/utils.d.ts +10 -0
- package/dist/clis/weread/utils.js +27 -7
- package/dist/clis/xiaohongshu/comments.d.ts +3 -0
- package/dist/clis/xiaohongshu/comments.js +76 -17
- package/dist/clis/xiaohongshu/comments.test.js +70 -9
- package/dist/clis/xiaohongshu/download.d.ts +4 -1
- package/dist/clis/xiaohongshu/download.js +83 -22
- package/dist/clis/xiaohongshu/download.test.d.ts +1 -0
- package/dist/clis/xiaohongshu/download.test.js +75 -0
- package/dist/clis/xiaohongshu/note-helpers.d.ts +12 -0
- package/dist/clis/xiaohongshu/note-helpers.js +23 -0
- package/dist/clis/xiaohongshu/note.d.ts +7 -0
- package/dist/clis/xiaohongshu/note.js +76 -0
- package/dist/clis/xiaohongshu/note.test.d.ts +1 -0
- package/dist/clis/xiaohongshu/note.test.js +136 -0
- package/dist/clis/xiaohongshu/search.js +9 -0
- package/dist/clis/xiaohongshu/search.test.js +10 -4
- package/dist/clis/youtube/search.js +57 -17
- package/dist/clis/zhihu/question.js +19 -17
- package/dist/clis/zhihu/question.test.d.ts +1 -0
- package/dist/clis/zhihu/question.test.js +54 -0
- package/dist/commanderAdapter.js +9 -0
- package/dist/commanderAdapter.test.js +25 -0
- package/dist/commands/daemon.d.ts +9 -0
- package/dist/commands/daemon.js +124 -0
- package/dist/commands/daemon.test.d.ts +1 -0
- package/dist/commands/daemon.test.js +185 -0
- package/dist/completion.js +3 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +2 -0
- package/dist/daemon.d.ts +1 -1
- package/dist/daemon.js +25 -14
- package/dist/daemon.test.d.ts +1 -0
- package/dist/daemon.test.js +65 -0
- package/dist/discovery.d.ts +9 -0
- package/dist/discovery.js +47 -2
- package/dist/electron-apps.d.ts +29 -0
- package/dist/electron-apps.js +65 -0
- package/dist/electron-apps.test.d.ts +1 -0
- package/dist/electron-apps.test.js +43 -0
- package/dist/engine.test.js +41 -9
- package/dist/execution.js +20 -16
- package/dist/extension-manifest-regression.test.js +1 -0
- package/dist/idle-manager.d.ts +19 -0
- package/dist/idle-manager.js +54 -0
- package/dist/launcher.d.ts +36 -0
- package/dist/launcher.js +152 -0
- package/dist/launcher.test.d.ts +1 -0
- package/dist/launcher.test.js +57 -0
- package/dist/main.js +3 -3
- package/dist/registry.d.ts +1 -0
- package/dist/registry.js +31 -3
- package/dist/registry.test.js +13 -0
- package/dist/runtime.d.ts +5 -3
- package/dist/runtime.js +12 -5
- package/dist/serialization.d.ts +1 -0
- package/dist/serialization.js +3 -0
- package/dist/serialization.test.js +17 -1
- package/dist/tui.d.ts +7 -0
- package/dist/tui.js +52 -0
- package/dist/tui.test.d.ts +1 -0
- package/dist/tui.test.js +19 -0
- package/dist/weixin-download.test.js +14 -0
- package/docs/.vitepress/config.mts +1 -0
- package/docs/adapters/browser/notebooklm.md +69 -0
- package/docs/adapters/browser/xiaohongshu.md +19 -10
- package/docs/adapters/index.md +67 -66
- package/docs/guide/browser-bridge.md +12 -0
- package/docs/guide/troubleshooting.md +9 -4
- package/docs/superpowers/plans/2026-03-31-daemon-lifecycle-redesign.md +857 -0
- package/docs/superpowers/specs/2026-03-31-daemon-lifecycle-redesign.md +208 -0
- package/docs/zh/guide/browser-bridge.md +12 -0
- package/extension/dist/background.js +250 -11
- package/extension/manifest.json +2 -1
- package/extension/src/background.test.ts +202 -2
- package/extension/src/background.ts +175 -10
- package/extension/src/cdp.test.ts +75 -0
- package/extension/src/cdp.ts +89 -3
- package/extension/src/protocol.ts +7 -5
- package/package.json +1 -1
- package/src/browser/cdp.ts +24 -17
- package/src/browser/daemon-client.ts +7 -1
- package/src/browser/dom-helpers.test.ts +15 -1
- package/src/browser/dom-helpers.ts +1 -0
- package/src/browser/mcp.ts +18 -13
- package/src/browser/page.test.ts +58 -0
- package/src/browser/page.ts +18 -2
- package/src/browser/stealth.test.ts +153 -0
- package/src/browser/stealth.ts +198 -0
- package/src/browser.test.ts +1 -1
- package/src/build-manifest.test.ts +2 -0
- package/src/build-manifest.ts +6 -1
- package/src/cli.ts +21 -3
- package/src/clis/antigravity/SKILL.md +3 -12
- package/src/clis/antigravity/serve.ts +5 -10
- package/src/clis/bilibili/subtitle.test.ts +60 -0
- package/src/clis/bilibili/subtitle.ts +4 -0
- package/src/clis/chatwise/ask.ts +0 -2
- package/src/clis/chatwise/export.ts +0 -2
- package/src/clis/chatwise/history.ts +0 -2
- package/src/clis/chatwise/model.ts +0 -2
- package/src/clis/chatwise/new.ts +1 -2
- package/src/clis/chatwise/read.ts +0 -2
- package/src/clis/chatwise/screenshot.ts +1 -2
- package/src/clis/chatwise/send.ts +0 -2
- package/src/clis/chatwise/status.ts +1 -2
- package/src/clis/ctrip/search.test.ts +73 -0
- package/src/clis/ctrip/search.ts +97 -47
- package/src/clis/douyin/_shared/sts2.test.ts +31 -0
- package/src/clis/douyin/_shared/sts2.ts +11 -3
- package/src/clis/douyin/activities.test.ts +41 -1
- package/src/clis/douyin/activities.ts +12 -3
- package/src/clis/douyin/collections.test.ts +35 -2
- package/src/clis/douyin/collections.ts +1 -1
- package/src/clis/douyin/draft.test.ts +444 -2
- package/src/clis/douyin/draft.ts +382 -218
- package/src/clis/douyin/hashtag.test.ts +42 -2
- package/src/clis/douyin/hashtag.ts +11 -3
- package/src/clis/douyin/profile.test.ts +43 -1
- package/src/clis/douyin/profile.ts +9 -2
- package/src/clis/douyin/videos.test.ts +52 -2
- package/src/clis/douyin/videos.ts +49 -15
- package/src/clis/facebook/search.test.ts +70 -0
- package/src/clis/facebook/search.yaml +4 -3
- package/src/clis/instagram/download.test.ts +159 -0
- package/src/clis/instagram/download.ts +286 -0
- package/src/clis/notebooklm/bind-current.test.ts +43 -0
- package/src/clis/notebooklm/bind-current.ts +36 -0
- package/src/clis/notebooklm/binding.test.ts +53 -0
- package/src/clis/notebooklm/compat.test.ts +19 -0
- package/src/clis/notebooklm/current.ts +38 -0
- package/src/clis/notebooklm/get.ts +53 -0
- package/src/clis/notebooklm/history.test.ts +70 -0
- package/src/clis/notebooklm/history.ts +36 -0
- package/src/clis/notebooklm/list.ts +40 -0
- package/src/clis/notebooklm/note-list.test.ts +64 -0
- package/src/clis/notebooklm/note-list.ts +42 -0
- package/src/clis/notebooklm/notes-get.test.ts +88 -0
- package/src/clis/notebooklm/notes-get.ts +67 -0
- package/src/clis/notebooklm/rpc.test.ts +126 -0
- package/src/clis/notebooklm/rpc.ts +286 -0
- package/src/clis/notebooklm/shared.ts +98 -0
- package/src/clis/notebooklm/source-fulltext.test.ts +123 -0
- package/src/clis/notebooklm/source-fulltext.ts +69 -0
- package/src/clis/notebooklm/source-get.test.ts +100 -0
- package/src/clis/notebooklm/source-get.ts +60 -0
- package/src/clis/notebooklm/source-guide.test.ts +121 -0
- package/src/clis/notebooklm/source-guide.ts +69 -0
- package/src/clis/notebooklm/source-list.ts +45 -0
- package/src/clis/notebooklm/status.ts +34 -0
- package/src/clis/notebooklm/summary.test.ts +94 -0
- package/src/clis/notebooklm/summary.ts +45 -0
- package/src/clis/notebooklm/utils.test.ts +446 -0
- package/src/clis/notebooklm/utils.ts +893 -0
- package/src/clis/substack/utils.test.ts +54 -0
- package/src/clis/substack/utils.ts +10 -2
- package/src/clis/v2ex/hot.yaml +4 -1
- package/src/clis/v2ex/latest.yaml +4 -1
- package/src/clis/v2ex/topic.yaml +6 -1
- package/src/clis/weixin/download.ts +95 -6
- package/src/clis/weread/book.ts +142 -2
- package/src/clis/weread/commands.test.ts +314 -154
- package/src/clis/weread/utils.ts +33 -4
- package/src/clis/xiaohongshu/comments.test.ts +85 -9
- package/src/clis/xiaohongshu/comments.ts +76 -17
- package/src/clis/xiaohongshu/download.test.ts +96 -0
- package/src/clis/xiaohongshu/download.ts +83 -22
- package/src/clis/xiaohongshu/note-helpers.ts +25 -0
- package/src/clis/xiaohongshu/note.test.ts +164 -0
- package/src/clis/xiaohongshu/note.ts +86 -0
- package/src/clis/xiaohongshu/search.test.ts +11 -4
- package/src/clis/xiaohongshu/search.ts +13 -0
- package/src/clis/youtube/search.ts +57 -17
- package/src/clis/zhihu/question.test.ts +71 -0
- package/src/clis/zhihu/question.ts +27 -15
- package/src/commanderAdapter.test.ts +30 -0
- package/src/commanderAdapter.ts +7 -0
- package/src/commands/daemon.test.ts +238 -0
- package/src/commands/daemon.ts +135 -0
- package/src/completion.ts +2 -1
- package/src/constants.ts +3 -0
- package/src/daemon.test.ts +88 -0
- package/src/daemon.ts +26 -14
- package/src/discovery.ts +52 -2
- package/src/electron-apps.test.ts +50 -0
- package/src/electron-apps.ts +89 -0
- package/src/engine.test.ts +45 -9
- package/src/execution.ts +24 -19
- package/src/extension-manifest-regression.test.ts +1 -0
- package/src/idle-manager.ts +60 -0
- package/src/launcher.test.ts +67 -0
- package/src/launcher.ts +185 -0
- package/src/main.ts +3 -2
- package/src/registry.test.ts +15 -0
- package/src/registry.ts +32 -3
- package/src/runtime.ts +13 -7
- package/src/serialization.test.ts +19 -1
- package/src/serialization.ts +2 -0
- package/src/tui.test.ts +23 -0
- package/src/tui.ts +65 -0
- package/src/weixin-download.test.ts +27 -0
- package/tests/e2e/browser-public-extended.test.ts +6 -2
- package/chatwise-opencli.ps1 +0 -82
- package/dist/clis/chatwise/shared.d.ts +0 -2
- package/dist/clis/chatwise/shared.js +0 -6
- package/src/clis/chatwise/shared.ts +0 -8
package/src/browser/stealth.ts
CHANGED
|
@@ -150,6 +150,204 @@ export function generateStealthJs(): string {
|
|
|
150
150
|
}
|
|
151
151
|
} catch {}
|
|
152
152
|
|
|
153
|
+
// ── Shared toString disguise infrastructure ──
|
|
154
|
+
// Save the pristine Function.prototype.toString BEFORE any patches,
|
|
155
|
+
// so all subsequent disguises use the real native reference.
|
|
156
|
+
// Anti-bot scripts detect per-instance toString overrides via:
|
|
157
|
+
// Function.hasOwnProperty('toString') → true if patched
|
|
158
|
+
// Function.prototype.toString.call(fn) !== fn.toString()
|
|
159
|
+
// Instead we patch Function.prototype.toString once with a WeakMap
|
|
160
|
+
// lookup, making disguised functions indistinguishable from native.
|
|
161
|
+
const _origToString = Function.prototype.toString;
|
|
162
|
+
const _disguised = new WeakMap();
|
|
163
|
+
try {
|
|
164
|
+
Object.defineProperty(Function.prototype, 'toString', {
|
|
165
|
+
value: function() {
|
|
166
|
+
const override = _disguised.get(this);
|
|
167
|
+
return override !== undefined ? override : _origToString.call(this);
|
|
168
|
+
},
|
|
169
|
+
writable: true, configurable: true,
|
|
170
|
+
});
|
|
171
|
+
} catch {}
|
|
172
|
+
const _disguise = (fn, name) => {
|
|
173
|
+
_disguised.set(fn, 'function ' + name + '() { [native code] }');
|
|
174
|
+
try { Object.defineProperty(fn, 'name', { value: name, configurable: true }); } catch {}
|
|
175
|
+
return fn;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// 8. Anti-debugger statement trap
|
|
179
|
+
// Sites inject debugger statements to detect DevTools/CDP.
|
|
180
|
+
// When a CDP debugger is attached, the statement pauses execution
|
|
181
|
+
// and the site measures the time gap to confirm automation.
|
|
182
|
+
// We neutralize this by overriding the Function constructor and
|
|
183
|
+
// eval to strip debugger statements from dynamically created code.
|
|
184
|
+
// Note: this does NOT affect static debugger statements in parsed
|
|
185
|
+
// scripts — those require CDP Debugger.setBreakpointsActive(false)
|
|
186
|
+
// which we handle at the extension level.
|
|
187
|
+
// Caveat: the regex targets standalone debugger statements (preceded
|
|
188
|
+
// by a statement boundary) to minimise false positives inside string
|
|
189
|
+
// literals, but cannot perfectly distinguish all cases without a
|
|
190
|
+
// full parser. This is an acceptable trade-off for stealth code.
|
|
191
|
+
try {
|
|
192
|
+
const _OrigFunction = Function;
|
|
193
|
+
// Match standalone debugger statements preceded by a statement
|
|
194
|
+
// boundary (start of string, semicolon, brace, or newline).
|
|
195
|
+
// This avoids most false positives inside string literals like
|
|
196
|
+
// "use debugger mode" while still catching the anti-bot patterns.
|
|
197
|
+
const _debuggerRe = /(?:^|(?<=[;{}\\n\\r]))\\s*debugger\\s*;?/g;
|
|
198
|
+
const _cleanDebugger = (src) => typeof src === 'string' ? src.replace(_debuggerRe, '') : src;
|
|
199
|
+
// Patch Function constructor to strip debugger from dynamic code.
|
|
200
|
+
// Support both Function('code') and new Function('code') via
|
|
201
|
+
// new.target / Reflect.construct.
|
|
202
|
+
const _PatchedFunction = function(...args) {
|
|
203
|
+
if (args.length > 0) {
|
|
204
|
+
args[args.length - 1] = _cleanDebugger(args[args.length - 1]);
|
|
205
|
+
}
|
|
206
|
+
if (new.target) {
|
|
207
|
+
return Reflect.construct(_OrigFunction, args, new.target);
|
|
208
|
+
}
|
|
209
|
+
return _OrigFunction.apply(this, args);
|
|
210
|
+
};
|
|
211
|
+
_PatchedFunction.prototype = _OrigFunction.prototype;
|
|
212
|
+
Object.setPrototypeOf(_PatchedFunction, _OrigFunction);
|
|
213
|
+
_disguise(_PatchedFunction, 'Function');
|
|
214
|
+
try { window.Function = _PatchedFunction; } catch {}
|
|
215
|
+
|
|
216
|
+
// Patch eval to strip debugger
|
|
217
|
+
const _origEval = window.eval;
|
|
218
|
+
const _patchedEval = function(code) {
|
|
219
|
+
return _origEval.call(this, _cleanDebugger(code));
|
|
220
|
+
};
|
|
221
|
+
_disguise(_patchedEval, 'eval');
|
|
222
|
+
try { window.eval = _patchedEval; } catch {}
|
|
223
|
+
} catch {}
|
|
224
|
+
|
|
225
|
+
// 9. Console method fingerprinting defense
|
|
226
|
+
// When CDP Runtime.enable is called, Chrome replaces console.log etc.
|
|
227
|
+
// with CDP-bound versions. These bound functions have a different
|
|
228
|
+
// toString() output: "function log() { [native code] }" becomes
|
|
229
|
+
// something like "function () { [native code] }" (no name) or the
|
|
230
|
+
// bound function signature leaks. Anti-bot scripts check:
|
|
231
|
+
// console.log.toString().includes('[native code]')
|
|
232
|
+
// console.log.name === 'log'
|
|
233
|
+
// We re-wrap console methods and register them via the shared
|
|
234
|
+
// _disguise infrastructure so Function.prototype.toString.call()
|
|
235
|
+
// also returns the correct native string.
|
|
236
|
+
try {
|
|
237
|
+
const _consoleMethods = ['log', 'warn', 'error', 'info', 'debug', 'table', 'trace', 'dir', 'group', 'groupEnd', 'groupCollapsed', 'clear', 'count', 'assert', 'profile', 'profileEnd', 'time', 'timeEnd', 'timeStamp'];
|
|
238
|
+
for (const _m of _consoleMethods) {
|
|
239
|
+
if (typeof console[_m] !== 'function') continue;
|
|
240
|
+
const _origMethod = console[_m];
|
|
241
|
+
const _nativeStr = 'function ' + _m + '() { [native code] }';
|
|
242
|
+
// Only patch if toString is wrong (i.e. CDP has replaced it)
|
|
243
|
+
try {
|
|
244
|
+
const _currentStr = _origToString.call(_origMethod);
|
|
245
|
+
if (_currentStr === _nativeStr) continue; // already looks native
|
|
246
|
+
} catch {}
|
|
247
|
+
const _wrapper = function() { return _origMethod.apply(console, arguments); };
|
|
248
|
+
Object.defineProperty(_wrapper, 'length', { value: _origMethod.length || 0, configurable: true });
|
|
249
|
+
_disguise(_wrapper, _m);
|
|
250
|
+
try { console[_m] = _wrapper; } catch {}
|
|
251
|
+
}
|
|
252
|
+
} catch {}
|
|
253
|
+
|
|
254
|
+
// 10. window.outerWidth/outerHeight defense
|
|
255
|
+
// When DevTools or CDP debugger is attached, Chrome may alter the
|
|
256
|
+
// window dimensions. Anti-bot scripts compare outerWidth/innerWidth
|
|
257
|
+
// and outerHeight/innerHeight — a significant difference indicates
|
|
258
|
+
// DevTools is open. We freeze the relationship so the delta stays
|
|
259
|
+
// consistent with a normal browser window.
|
|
260
|
+
// Thresholds: width delta > 100px or height delta > 200px indicates
|
|
261
|
+
// a docked DevTools panel. When triggered, we report outerWidth
|
|
262
|
+
// equal to innerWidth (normal for maximised windows) and
|
|
263
|
+
// outerHeight as innerHeight + the captured "normal" delta (capped
|
|
264
|
+
// to a reasonable range), so the result is plausible across OSes.
|
|
265
|
+
try {
|
|
266
|
+
const _normalWidthDelta = window.outerWidth - window.innerWidth;
|
|
267
|
+
const _normalHeightDelta = window.outerHeight - window.innerHeight;
|
|
268
|
+
// Only patch if the delta looks suspicious (e.g. DevTools docked)
|
|
269
|
+
if (_normalWidthDelta > 100 || _normalHeightDelta > 200) {
|
|
270
|
+
Object.defineProperty(window, 'outerWidth', {
|
|
271
|
+
get: () => window.innerWidth,
|
|
272
|
+
configurable: true,
|
|
273
|
+
});
|
|
274
|
+
// Use a clamped height offset (40-120px covers macOS ~78px,
|
|
275
|
+
// Windows ~40px, and Linux ~37-50px title bar heights).
|
|
276
|
+
const _heightOffset = Math.max(40, Math.min(120, _normalHeightDelta));
|
|
277
|
+
Object.defineProperty(window, 'outerHeight', {
|
|
278
|
+
get: () => window.innerHeight + _heightOffset,
|
|
279
|
+
configurable: true,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
} catch {}
|
|
283
|
+
|
|
284
|
+
// 11. Performance API cleanup
|
|
285
|
+
// CDP injects internal resources and timing entries that don't exist
|
|
286
|
+
// in normal browsing. Filter entries with debugger/devtools URLs.
|
|
287
|
+
try {
|
|
288
|
+
const _origGetEntries = Performance.prototype.getEntries;
|
|
289
|
+
const _origGetByType = Performance.prototype.getEntriesByType;
|
|
290
|
+
const _origGetByName = Performance.prototype.getEntriesByName;
|
|
291
|
+
const _suspiciousPatterns = ['debugger', 'devtools', '__puppeteer', '__playwright', 'pptr:'];
|
|
292
|
+
const _filterEntries = (entries) => {
|
|
293
|
+
if (!Array.isArray(entries)) return entries;
|
|
294
|
+
return entries.filter(e => {
|
|
295
|
+
const name = e.name || '';
|
|
296
|
+
return !_suspiciousPatterns.some(p => name.includes(p));
|
|
297
|
+
});
|
|
298
|
+
};
|
|
299
|
+
Performance.prototype.getEntries = function() {
|
|
300
|
+
return _filterEntries(_origGetEntries.call(this));
|
|
301
|
+
};
|
|
302
|
+
Performance.prototype.getEntriesByType = function(type) {
|
|
303
|
+
return _filterEntries(_origGetByType.call(this, type));
|
|
304
|
+
};
|
|
305
|
+
Performance.prototype.getEntriesByName = function(name, type) {
|
|
306
|
+
return _filterEntries(_origGetByName.call(this, name, type));
|
|
307
|
+
};
|
|
308
|
+
} catch {}
|
|
309
|
+
|
|
310
|
+
// 12. WebDriver-related property defense
|
|
311
|
+
// Some anti-bot systems check additional navigator properties
|
|
312
|
+
// and document properties that may indicate automation.
|
|
313
|
+
try {
|
|
314
|
+
// document.$cdc_ properties (ChromeDriver specific, backup for #6)
|
|
315
|
+
for (const _prop of Object.getOwnPropertyNames(document)) {
|
|
316
|
+
if (_prop.startsWith('$cdc_') || _prop.startsWith('$chrome_')) {
|
|
317
|
+
try { delete document[_prop]; } catch {}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
} catch {}
|
|
321
|
+
|
|
322
|
+
// 13. Iframe contentWindow.chrome consistency
|
|
323
|
+
// Anti-bot scripts create iframes and check if
|
|
324
|
+
// iframe.contentWindow.chrome exists and matches the parent.
|
|
325
|
+
// CDP-controlled pages may have inconsistent iframe contexts.
|
|
326
|
+
try {
|
|
327
|
+
const _origHTMLIFrame = HTMLIFrameElement.prototype;
|
|
328
|
+
const _origContentWindow = Object.getOwnPropertyDescriptor(_origHTMLIFrame, 'contentWindow');
|
|
329
|
+
if (_origContentWindow && _origContentWindow.get) {
|
|
330
|
+
Object.defineProperty(_origHTMLIFrame, 'contentWindow', {
|
|
331
|
+
get: function() {
|
|
332
|
+
const _w = _origContentWindow.get.call(this);
|
|
333
|
+
if (_w) {
|
|
334
|
+
try {
|
|
335
|
+
if (!_w.chrome) {
|
|
336
|
+
Object.defineProperty(_w, 'chrome', {
|
|
337
|
+
value: window.chrome,
|
|
338
|
+
writable: true,
|
|
339
|
+
configurable: true,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
} catch {}
|
|
343
|
+
}
|
|
344
|
+
return _w;
|
|
345
|
+
},
|
|
346
|
+
configurable: true,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
} catch {}
|
|
350
|
+
|
|
153
351
|
return 'applied';
|
|
154
352
|
})()
|
|
155
353
|
`;
|
package/src/browser.test.ts
CHANGED
|
@@ -140,7 +140,7 @@ describe('BrowserBridge state', () => {
|
|
|
140
140
|
|
|
141
141
|
const mcp = new BrowserBridge();
|
|
142
142
|
|
|
143
|
-
await expect(mcp.connect()).rejects.toThrow('Browser Extension is not connected');
|
|
143
|
+
await expect(mcp.connect({ timeout: 0.1 })).rejects.toThrow('Browser Extension is not connected');
|
|
144
144
|
});
|
|
145
145
|
});
|
|
146
146
|
|
|
@@ -84,6 +84,7 @@ describe('manifest helper rules', () => {
|
|
|
84
84
|
description: 'dynamic command',
|
|
85
85
|
strategy: Strategy.PUBLIC,
|
|
86
86
|
browser: false,
|
|
87
|
+
aliases: ['metadata'],
|
|
87
88
|
args: [
|
|
88
89
|
{
|
|
89
90
|
name: 'model',
|
|
@@ -109,6 +110,7 @@ describe('manifest helper rules', () => {
|
|
|
109
110
|
domain: 'localhost',
|
|
110
111
|
strategy: 'public',
|
|
111
112
|
browser: false,
|
|
113
|
+
aliases: ['metadata'],
|
|
112
114
|
args: [
|
|
113
115
|
{
|
|
114
116
|
name: 'model',
|
package/src/build-manifest.ts
CHANGED
|
@@ -23,6 +23,7 @@ const OUTPUT = path.resolve(__dirname, '..', 'dist', 'cli-manifest.json');
|
|
|
23
23
|
export interface ManifestEntry {
|
|
24
24
|
site: string;
|
|
25
25
|
name: string;
|
|
26
|
+
aliases?: string[];
|
|
26
27
|
description: string;
|
|
27
28
|
domain?: string;
|
|
28
29
|
strategy: string;
|
|
@@ -84,6 +85,7 @@ function toManifestEntry(cmd: CliCommand, modulePath: string): ManifestEntry {
|
|
|
84
85
|
return {
|
|
85
86
|
site: cmd.site,
|
|
86
87
|
name: cmd.name,
|
|
88
|
+
aliases: cmd.aliases,
|
|
87
89
|
description: cmd.description ?? '',
|
|
88
90
|
domain: cmd.domain,
|
|
89
91
|
strategy: (cmd.strategy ?? 'public').toString().toLowerCase(),
|
|
@@ -119,6 +121,9 @@ function scanYaml(filePath: string, site: string): ManifestEntry | null {
|
|
|
119
121
|
domain: cliDef.domain,
|
|
120
122
|
strategy: strategy.toLowerCase(),
|
|
121
123
|
browser,
|
|
124
|
+
aliases: isRecord(cliDef) && Array.isArray((cliDef as Record<string, unknown>).aliases)
|
|
125
|
+
? ((cliDef as Record<string, unknown>).aliases as unknown[]).filter((value): value is string => typeof value === 'string')
|
|
126
|
+
: undefined,
|
|
122
127
|
args,
|
|
123
128
|
columns: cliDef.columns,
|
|
124
129
|
pipeline: cliDef.pipeline,
|
|
@@ -230,7 +235,7 @@ export async function buildManifest(): Promise<ManifestEntry[]> {
|
|
|
230
235
|
}
|
|
231
236
|
}
|
|
232
237
|
|
|
233
|
-
return [...manifest.values()];
|
|
238
|
+
return [...manifest.values()].sort((a, b) => a.site.localeCompare(b.site) || a.name.localeCompare(b.name));
|
|
234
239
|
}
|
|
235
240
|
|
|
236
241
|
async function main(): Promise<void> {
|
package/src/cli.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { printCompletionScript } from './completion.js';
|
|
|
16
16
|
import { loadExternalClis, executeExternalCli, installExternalCli, registerExternalCli, isBinaryInstalled } from './external.js';
|
|
17
17
|
import { registerAllCommands } from './commanderAdapter.js';
|
|
18
18
|
import { EXIT_CODES, getErrorMessage } from './errors.js';
|
|
19
|
+
import { daemonStatus, daemonStop, daemonRestart } from './commands/daemon.js';
|
|
19
20
|
|
|
20
21
|
export function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void {
|
|
21
22
|
const program = new Command();
|
|
@@ -36,7 +37,7 @@ export function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void {
|
|
|
36
37
|
.option('--json', 'JSON output (deprecated)')
|
|
37
38
|
.action((opts) => {
|
|
38
39
|
const registry = getRegistry();
|
|
39
|
-
const commands = [...registry.values()].sort((a, b) => fullName(a).localeCompare(fullName(b)));
|
|
40
|
+
const commands = [...new Set(registry.values())].sort((a, b) => fullName(a).localeCompare(fullName(b)));
|
|
40
41
|
const fmt = opts.json && opts.format === 'table' ? 'json' : opts.format;
|
|
41
42
|
const isStructured = fmt === 'json' || fmt === 'yaml';
|
|
42
43
|
|
|
@@ -47,6 +48,7 @@ export function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void {
|
|
|
47
48
|
command: fullName(c),
|
|
48
49
|
site: c.site,
|
|
49
50
|
name: c.name,
|
|
51
|
+
aliases: c.aliases?.join(', ') ?? '',
|
|
50
52
|
description: c.description,
|
|
51
53
|
strategy: strategyLabel(c),
|
|
52
54
|
browser: !!c.browser,
|
|
@@ -54,7 +56,7 @@ export function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void {
|
|
|
54
56
|
}));
|
|
55
57
|
renderOutput(rows, {
|
|
56
58
|
fmt,
|
|
57
|
-
columns: ['command', 'site', 'name', 'description', 'strategy', 'browser', 'args',
|
|
59
|
+
columns: ['command', 'site', 'name', 'aliases', 'description', 'strategy', 'browser', 'args',
|
|
58
60
|
...(isStructured ? ['columns', 'domain'] : [])],
|
|
59
61
|
title: 'opencli/list',
|
|
60
62
|
source: 'opencli list',
|
|
@@ -80,7 +82,8 @@ export function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void {
|
|
|
80
82
|
const tag = label === 'public'
|
|
81
83
|
? chalk.green('[public]')
|
|
82
84
|
: chalk.yellow(`[${label}]`);
|
|
83
|
-
|
|
85
|
+
const aliases = cmd.aliases?.length ? chalk.dim(` (aliases: ${cmd.aliases.join(', ')})`) : '';
|
|
86
|
+
console.log(` ${cmd.name} ${tag}${aliases}${cmd.description ? chalk.dim(` — ${cmd.description}`) : ''}`);
|
|
84
87
|
}
|
|
85
88
|
console.log();
|
|
86
89
|
}
|
|
@@ -442,6 +445,21 @@ export function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void {
|
|
|
442
445
|
}
|
|
443
446
|
});
|
|
444
447
|
|
|
448
|
+
// ── Built-in: daemon ──────────────────────────────────────────────────────
|
|
449
|
+
const daemonCmd = program.command('daemon').description('Manage the opencli daemon');
|
|
450
|
+
daemonCmd
|
|
451
|
+
.command('status')
|
|
452
|
+
.description('Show daemon status')
|
|
453
|
+
.action(async () => { await daemonStatus(); });
|
|
454
|
+
daemonCmd
|
|
455
|
+
.command('stop')
|
|
456
|
+
.description('Stop the daemon')
|
|
457
|
+
.action(async () => { await daemonStop(); });
|
|
458
|
+
daemonCmd
|
|
459
|
+
.command('restart')
|
|
460
|
+
.description('Restart the daemon')
|
|
461
|
+
.action(async () => { await daemonRestart(); });
|
|
462
|
+
|
|
445
463
|
// ── External CLIs ─────────────────────────────────────────────────────────
|
|
446
464
|
|
|
447
465
|
const externalClis = loadExternalClis();
|
|
@@ -7,17 +7,10 @@ description: How to automate Antigravity using OpenCLI
|
|
|
7
7
|
This skill allows AI agents to control the [Antigravity](https://github.com/chengazhen/Antigravity) desktop app (and any Electron app with CDP enabled) programmatically via OpenCLI.
|
|
8
8
|
|
|
9
9
|
## Requirements
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/Applications/Antigravity.app/Contents/MacOS/Electron --remote-debugging-port=9224
|
|
13
|
-
\`\`\`
|
|
14
|
-
|
|
15
|
-
The agent must configure the endpoint environment variable locally before invoking standard commands:
|
|
16
|
-
\`\`\`bash
|
|
17
|
-
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9224"
|
|
18
|
-
\`\`\`
|
|
10
|
+
opencli automatically detects, launches (with `--remote-debugging-port=9234`), and connects to Antigravity.
|
|
11
|
+
If Antigravity is already running without CDP, opencli will prompt to restart it.
|
|
19
12
|
|
|
20
|
-
If the endpoint exposes multiple inspectable targets,
|
|
13
|
+
If the endpoint exposes multiple inspectable targets, set:
|
|
21
14
|
\`\`\`bash
|
|
22
15
|
export OPENCLI_CDP_TARGET="antigravity"
|
|
23
16
|
\`\`\`
|
|
@@ -33,7 +26,6 @@ export OPENCLI_CDP_TARGET="antigravity"
|
|
|
33
26
|
|
|
34
27
|
### Generating and Saving Code
|
|
35
28
|
\`\`\`bash
|
|
36
|
-
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9224"
|
|
37
29
|
opencli antigravity send "Write a python script to fetch HN top stories"
|
|
38
30
|
# wait ~10-15 seconds for output to render
|
|
39
31
|
opencli antigravity extract-code > hn_fetcher.py
|
|
@@ -42,6 +34,5 @@ opencli antigravity extract-code > hn_fetcher.py
|
|
|
42
34
|
### Reading Real-time Logs
|
|
43
35
|
Agents can run long-running streaming watch instances:
|
|
44
36
|
\`\`\`bash
|
|
45
|
-
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9224"
|
|
46
37
|
opencli antigravity watch
|
|
47
38
|
\`\`\`
|
|
@@ -6,13 +6,14 @@
|
|
|
6
6
|
* and returns it in Anthropic format.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
|
-
*
|
|
9
|
+
* opencli antigravity serve --port 8082
|
|
10
10
|
* ANTHROPIC_BASE_URL=http://localhost:8082 claude
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
|
|
14
14
|
import { CDPBridge } from '../../browser/cdp.js';
|
|
15
15
|
import type { IPage } from '../../types.js';
|
|
16
|
+
import { resolveElectronEndpoint } from '../../launcher.js';
|
|
16
17
|
import { EXIT_CODES, getErrorMessage } from '../../errors.js';
|
|
17
18
|
|
|
18
19
|
// ─── Types ───────────────────────────────────────────────────────────
|
|
@@ -436,13 +437,7 @@ export async function startServe(opts: { port?: number } = {}): Promise<void> {
|
|
|
436
437
|
}
|
|
437
438
|
}
|
|
438
439
|
|
|
439
|
-
const endpoint =
|
|
440
|
-
if (!endpoint) {
|
|
441
|
-
throw new Error(
|
|
442
|
-
'OPENCLI_CDP_ENDPOINT is not set.\n' +
|
|
443
|
-
'Usage: OPENCLI_CDP_ENDPOINT=http://127.0.0.1:9224 opencli antigravity serve'
|
|
444
|
-
);
|
|
445
|
-
}
|
|
440
|
+
const endpoint = await resolveElectronEndpoint('antigravity');
|
|
446
441
|
|
|
447
442
|
// Note: Antigravity chat panel lives inside editor windows, not in Launchpad.
|
|
448
443
|
// If multiple editor windows are open, set OPENCLI_CDP_TARGET to the window title.
|
|
@@ -461,7 +456,7 @@ export async function startServe(opts: { port?: number } = {}): Promise<void> {
|
|
|
461
456
|
console.error(`[serve] Connecting via CDP (target pattern: "${process.env.OPENCLI_CDP_TARGET}")...`);
|
|
462
457
|
cdp = new CDPBridge();
|
|
463
458
|
try {
|
|
464
|
-
page = await cdp.connect({ timeout: 15_000 });
|
|
459
|
+
page = await cdp.connect({ timeout: 15_000, cdpEndpoint: endpoint });
|
|
465
460
|
} catch (err: unknown) {
|
|
466
461
|
cdp = null;
|
|
467
462
|
const errMsg = getErrorMessage(err);
|
|
@@ -471,7 +466,7 @@ export async function startServe(opts: { port?: number } = {}): Promise<void> {
|
|
|
471
466
|
isRefused
|
|
472
467
|
? `Cannot connect to Antigravity at ${endpoint}.\n` +
|
|
473
468
|
' 1. Make sure Antigravity is running\n' +
|
|
474
|
-
' 2. Launch with: --remote-debugging-port=
|
|
469
|
+
' 2. Launch with: --remote-debugging-port=9234'
|
|
475
470
|
: `CDP connection failed: ${errMsg}`
|
|
476
471
|
);
|
|
477
472
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { AuthRequiredError, EmptyResultError } from '../../errors.js';
|
|
4
|
+
|
|
5
|
+
const { mockApiGet } = vi.hoisted(() => ({
|
|
6
|
+
mockApiGet: vi.fn(),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
vi.mock('./utils.js', () => ({
|
|
10
|
+
apiGet: mockApiGet,
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
import { getRegistry } from '../../registry.js';
|
|
14
|
+
import './subtitle.js';
|
|
15
|
+
|
|
16
|
+
describe('bilibili subtitle', () => {
|
|
17
|
+
const command = getRegistry().get('bilibili/subtitle');
|
|
18
|
+
const page = {
|
|
19
|
+
goto: vi.fn().mockResolvedValue(undefined),
|
|
20
|
+
evaluate: vi.fn(),
|
|
21
|
+
} as any;
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
mockApiGet.mockReset();
|
|
25
|
+
page.goto.mockClear();
|
|
26
|
+
page.evaluate.mockReset();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('throws AuthRequiredError when bilibili hides subtitles behind login', async () => {
|
|
30
|
+
page.evaluate.mockResolvedValueOnce(123456);
|
|
31
|
+
mockApiGet.mockResolvedValueOnce({
|
|
32
|
+
code: 0,
|
|
33
|
+
data: {
|
|
34
|
+
need_login_subtitle: true,
|
|
35
|
+
subtitle: {
|
|
36
|
+
subtitles: [],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
await expect(command!.func!(page, { bvid: 'BV1GbXPBeEZm' })).rejects.toSatisfy((err: Error) =>
|
|
42
|
+
err instanceof AuthRequiredError && /login|登录/i.test(err.message),
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('throws EmptyResultError when a video truly has no subtitles', async () => {
|
|
47
|
+
page.evaluate.mockResolvedValueOnce(123456);
|
|
48
|
+
mockApiGet.mockResolvedValueOnce({
|
|
49
|
+
code: 0,
|
|
50
|
+
data: {
|
|
51
|
+
need_login_subtitle: false,
|
|
52
|
+
subtitle: {
|
|
53
|
+
subtitles: [],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await expect(command!.func!(page, { bvid: 'BV1GbXPBeEZm' })).rejects.toThrow(EmptyResultError);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -39,8 +39,12 @@ cli({
|
|
|
39
39
|
throw new CommandExecutionError(`获取视频播放信息失败: ${payload.message} (${payload.code})`);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
const needLoginSubtitle = payload.data?.need_login_subtitle === true;
|
|
42
43
|
const subtitles = payload.data?.subtitle?.subtitles || [];
|
|
43
44
|
if (subtitles.length === 0) {
|
|
45
|
+
if (needLoginSubtitle) {
|
|
46
|
+
throw new AuthRequiredError('bilibili.com', 'Bilibili subtitles are hidden behind login for this video. Please log in to bilibili.com in Chrome and retry.');
|
|
47
|
+
}
|
|
44
48
|
throw new EmptyResultError('bilibili subtitle', '此视频没有发现外挂或智能字幕。');
|
|
45
49
|
}
|
|
46
50
|
|
package/src/clis/chatwise/ask.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { cli, Strategy } from '../../registry.js';
|
|
2
2
|
import { SelectorError } from '../../errors.js';
|
|
3
3
|
import type { IPage } from '../../types.js';
|
|
4
|
-
import { chatwiseRequiredEnv } from './shared.js';
|
|
5
4
|
|
|
6
5
|
export const askCommand = cli({
|
|
7
6
|
site: 'chatwise',
|
|
@@ -10,7 +9,6 @@ export const askCommand = cli({
|
|
|
10
9
|
domain: 'localhost',
|
|
11
10
|
strategy: Strategy.UI,
|
|
12
11
|
browser: true,
|
|
13
|
-
requiredEnv: chatwiseRequiredEnv,
|
|
14
12
|
args: [
|
|
15
13
|
{ name: 'text', required: true, positional: true, help: 'Prompt to send' },
|
|
16
14
|
{ name: 'timeout', required: false, help: 'Max seconds to wait (default: 30)', default: '30' },
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import { cli, Strategy } from '../../registry.js';
|
|
3
3
|
import type { IPage } from '../../types.js';
|
|
4
|
-
import { chatwiseRequiredEnv } from './shared.js';
|
|
5
4
|
|
|
6
5
|
export const exportCommand = cli({
|
|
7
6
|
site: 'chatwise',
|
|
@@ -10,7 +9,6 @@ export const exportCommand = cli({
|
|
|
10
9
|
domain: 'localhost',
|
|
11
10
|
strategy: Strategy.UI,
|
|
12
11
|
browser: true,
|
|
13
|
-
requiredEnv: chatwiseRequiredEnv,
|
|
14
12
|
args: [
|
|
15
13
|
{ name: 'output', required: false, help: 'Output file (default: /tmp/chatwise-export.md)' },
|
|
16
14
|
],
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { cli, Strategy } from '../../registry.js';
|
|
2
2
|
import type { IPage } from '../../types.js';
|
|
3
|
-
import { chatwiseRequiredEnv } from './shared.js';
|
|
4
3
|
|
|
5
4
|
export const historyCommand = cli({
|
|
6
5
|
site: 'chatwise',
|
|
@@ -9,7 +8,6 @@ export const historyCommand = cli({
|
|
|
9
8
|
domain: 'localhost',
|
|
10
9
|
strategy: Strategy.UI,
|
|
11
10
|
browser: true,
|
|
12
|
-
requiredEnv: chatwiseRequiredEnv,
|
|
13
11
|
args: [],
|
|
14
12
|
columns: ['Index', 'Title'],
|
|
15
13
|
func: async (page: IPage) => {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { cli, Strategy } from '../../registry.js';
|
|
2
2
|
import { SelectorError } from '../../errors.js';
|
|
3
3
|
import type { IPage } from '../../types.js';
|
|
4
|
-
import { chatwiseRequiredEnv } from './shared.js';
|
|
5
4
|
|
|
6
5
|
export const modelCommand = cli({
|
|
7
6
|
site: 'chatwise',
|
|
@@ -10,7 +9,6 @@ export const modelCommand = cli({
|
|
|
10
9
|
domain: 'localhost',
|
|
11
10
|
strategy: Strategy.UI,
|
|
12
11
|
browser: true,
|
|
13
|
-
requiredEnv: chatwiseRequiredEnv,
|
|
14
12
|
args: [
|
|
15
13
|
{ name: 'model-name', required: false, positional: true, help: 'Model to switch to (e.g. gpt-4, claude-3)' },
|
|
16
14
|
],
|
package/src/clis/chatwise/new.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { makeNewCommand } from '../_shared/desktop-commands.js';
|
|
2
|
-
import { chatwiseRequiredEnv } from './shared.js';
|
|
3
2
|
|
|
4
|
-
export const newCommand = makeNewCommand('chatwise', 'ChatWise conversation'
|
|
3
|
+
export const newCommand = makeNewCommand('chatwise', 'ChatWise conversation');
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { cli, Strategy } from '../../registry.js';
|
|
2
2
|
import type { IPage } from '../../types.js';
|
|
3
|
-
import { chatwiseRequiredEnv } from './shared.js';
|
|
4
3
|
|
|
5
4
|
export const readCommand = cli({
|
|
6
5
|
site: 'chatwise',
|
|
@@ -9,7 +8,6 @@ export const readCommand = cli({
|
|
|
9
8
|
domain: 'localhost',
|
|
10
9
|
strategy: Strategy.UI,
|
|
11
10
|
browser: true,
|
|
12
|
-
requiredEnv: chatwiseRequiredEnv,
|
|
13
11
|
args: [],
|
|
14
12
|
columns: ['Content'],
|
|
15
13
|
func: async (page: IPage) => {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { makeScreenshotCommand } from '../_shared/desktop-commands.js';
|
|
2
|
-
import { chatwiseRequiredEnv } from './shared.js';
|
|
3
2
|
|
|
4
|
-
export const screenshotCommand = makeScreenshotCommand('chatwise', 'ChatWise'
|
|
3
|
+
export const screenshotCommand = makeScreenshotCommand('chatwise', 'ChatWise');
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { cli, Strategy } from '../../registry.js';
|
|
2
2
|
import { SelectorError } from '../../errors.js';
|
|
3
3
|
import type { IPage } from '../../types.js';
|
|
4
|
-
import { chatwiseRequiredEnv } from './shared.js';
|
|
5
4
|
|
|
6
5
|
export const sendCommand = cli({
|
|
7
6
|
site: 'chatwise',
|
|
@@ -10,7 +9,6 @@ export const sendCommand = cli({
|
|
|
10
9
|
domain: 'localhost',
|
|
11
10
|
strategy: Strategy.UI,
|
|
12
11
|
browser: true,
|
|
13
|
-
requiredEnv: chatwiseRequiredEnv,
|
|
14
12
|
args: [{ name: 'text', required: true, positional: true, help: 'Message to send' }],
|
|
15
13
|
columns: ['Status', 'InjectedText'],
|
|
16
14
|
func: async (page: IPage, kwargs: any) => {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { makeStatusCommand } from '../_shared/desktop-commands.js';
|
|
2
|
-
import { chatwiseRequiredEnv } from './shared.js';
|
|
3
2
|
|
|
4
|
-
export const statusCommand = makeStatusCommand('chatwise', 'ChatWise Desktop'
|
|
3
|
+
export const statusCommand = makeStatusCommand('chatwise', 'ChatWise Desktop');
|