@jackwener/opencli 1.5.6 → 1.5.7
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 +26 -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/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 +794 -513
- package/extension/src/background.test.ts +202 -2
- package/extension/src/background.ts +174 -10
- package/extension/src/cdp.ts +12 -0
- 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/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
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export declare const NOTEBOOKLM_SITE = "notebooklm";
|
|
2
|
+
export declare const NOTEBOOKLM_DOMAIN = "notebooklm.google.com";
|
|
3
|
+
export declare const NOTEBOOKLM_HOME_URL = "https://notebooklm.google.com/";
|
|
4
|
+
export type NotebooklmPageKind = 'notebook' | 'home' | 'unknown';
|
|
5
|
+
export interface NotebooklmPageState {
|
|
6
|
+
url: string;
|
|
7
|
+
title: string;
|
|
8
|
+
hostname: string;
|
|
9
|
+
kind: NotebooklmPageKind;
|
|
10
|
+
notebookId: string;
|
|
11
|
+
loginRequired: boolean;
|
|
12
|
+
notebookCount: number;
|
|
13
|
+
}
|
|
14
|
+
export interface NotebooklmRow {
|
|
15
|
+
id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
url: string;
|
|
18
|
+
source: 'current-page' | 'home-links' | 'rpc';
|
|
19
|
+
is_owner?: boolean;
|
|
20
|
+
created_at?: string | null;
|
|
21
|
+
}
|
|
22
|
+
export interface NotebooklmSourceRow {
|
|
23
|
+
id: string;
|
|
24
|
+
notebook_id: string;
|
|
25
|
+
title: string;
|
|
26
|
+
url: string;
|
|
27
|
+
source: 'current-page' | 'rpc';
|
|
28
|
+
type?: string | null;
|
|
29
|
+
type_code?: number | null;
|
|
30
|
+
size?: number | null;
|
|
31
|
+
created_at?: string | null;
|
|
32
|
+
updated_at?: string | null;
|
|
33
|
+
}
|
|
34
|
+
export interface NotebooklmSourceFulltextRow {
|
|
35
|
+
source_id: string;
|
|
36
|
+
notebook_id: string;
|
|
37
|
+
title: string;
|
|
38
|
+
kind?: string | null;
|
|
39
|
+
content: string;
|
|
40
|
+
char_count: number;
|
|
41
|
+
url?: string | null;
|
|
42
|
+
source: 'rpc';
|
|
43
|
+
}
|
|
44
|
+
export interface NotebooklmSourceGuideRow {
|
|
45
|
+
source_id: string;
|
|
46
|
+
notebook_id: string;
|
|
47
|
+
title: string;
|
|
48
|
+
type?: string | null;
|
|
49
|
+
summary: string;
|
|
50
|
+
keywords: string[];
|
|
51
|
+
source: 'rpc';
|
|
52
|
+
}
|
|
53
|
+
export interface NotebooklmNotebookDetailRow extends NotebooklmRow {
|
|
54
|
+
emoji?: string | null;
|
|
55
|
+
source_count?: number | null;
|
|
56
|
+
updated_at?: string | null;
|
|
57
|
+
}
|
|
58
|
+
export interface NotebooklmHistoryRow {
|
|
59
|
+
thread_id: string;
|
|
60
|
+
notebook_id: string;
|
|
61
|
+
item_count: number;
|
|
62
|
+
preview?: string | null;
|
|
63
|
+
url: string;
|
|
64
|
+
source: 'rpc';
|
|
65
|
+
}
|
|
66
|
+
export interface NotebooklmNoteRow {
|
|
67
|
+
notebook_id: string;
|
|
68
|
+
title: string;
|
|
69
|
+
created_at?: string | null;
|
|
70
|
+
url: string;
|
|
71
|
+
source: 'studio-list';
|
|
72
|
+
}
|
|
73
|
+
export interface NotebooklmSummaryRow {
|
|
74
|
+
notebook_id: string;
|
|
75
|
+
title: string;
|
|
76
|
+
summary: string;
|
|
77
|
+
url: string;
|
|
78
|
+
source: 'summary-dom' | 'rpc';
|
|
79
|
+
}
|
|
80
|
+
export interface NotebooklmNoteDetailRow {
|
|
81
|
+
notebook_id: string;
|
|
82
|
+
id?: string | null;
|
|
83
|
+
title: string;
|
|
84
|
+
content: string;
|
|
85
|
+
url: string;
|
|
86
|
+
source: 'studio-editor';
|
|
87
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
import { EmptyResultError } from '../../errors.js';
|
|
3
|
+
import { NOTEBOOKLM_DOMAIN, NOTEBOOKLM_SITE } from './shared.js';
|
|
4
|
+
import { ensureNotebooklmNotebookBinding, findNotebooklmSourceRow, getNotebooklmPageState, getNotebooklmSourceFulltextViaRpc, listNotebooklmSourcesFromPage, listNotebooklmSourcesViaRpc, requireNotebooklmSession, } from './utils.js';
|
|
5
|
+
cli({
|
|
6
|
+
site: NOTEBOOKLM_SITE,
|
|
7
|
+
name: 'source-fulltext',
|
|
8
|
+
description: 'Get the extracted fulltext for one source in the currently opened NotebookLM notebook',
|
|
9
|
+
domain: NOTEBOOKLM_DOMAIN,
|
|
10
|
+
strategy: Strategy.COOKIE,
|
|
11
|
+
browser: true,
|
|
12
|
+
navigateBefore: false,
|
|
13
|
+
args: [
|
|
14
|
+
{
|
|
15
|
+
name: 'source',
|
|
16
|
+
positional: true,
|
|
17
|
+
required: true,
|
|
18
|
+
help: 'Source id or title from the current notebook',
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
columns: ['title', 'kind', 'char_count', 'url', 'source'],
|
|
22
|
+
func: async (page, kwargs) => {
|
|
23
|
+
await ensureNotebooklmNotebookBinding(page);
|
|
24
|
+
await requireNotebooklmSession(page);
|
|
25
|
+
const state = await getNotebooklmPageState(page);
|
|
26
|
+
if (state.kind !== 'notebook') {
|
|
27
|
+
throw new EmptyResultError('opencli notebooklm source-fulltext', 'Open a specific NotebookLM notebook tab first, then retry.');
|
|
28
|
+
}
|
|
29
|
+
const rpcRows = await listNotebooklmSourcesViaRpc(page).catch(() => []);
|
|
30
|
+
const rows = rpcRows.length > 0 ? rpcRows : await listNotebooklmSourcesFromPage(page);
|
|
31
|
+
if (rows.length === 0) {
|
|
32
|
+
throw new EmptyResultError('opencli notebooklm source-fulltext', 'No NotebookLM sources were found on the current page.');
|
|
33
|
+
}
|
|
34
|
+
const query = typeof kwargs.source === 'string' ? kwargs.source : String(kwargs.source ?? '');
|
|
35
|
+
const matched = findNotebooklmSourceRow(rows, query);
|
|
36
|
+
if (!matched) {
|
|
37
|
+
throw new EmptyResultError('opencli notebooklm source-fulltext', `Source "${query}" was not found in the current notebook.`);
|
|
38
|
+
}
|
|
39
|
+
const fulltext = await getNotebooklmSourceFulltextViaRpc(page, matched.id).catch(() => null);
|
|
40
|
+
if (fulltext)
|
|
41
|
+
return [fulltext];
|
|
42
|
+
throw new EmptyResultError('opencli notebooklm source-fulltext', `NotebookLM fulltext was not available for source "${matched.title}".`);
|
|
43
|
+
},
|
|
44
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './source-fulltext.js';
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
const { mockListNotebooklmSourcesViaRpc, mockListNotebooklmSourcesFromPage, mockGetNotebooklmSourceFulltextViaRpc, mockGetNotebooklmPageState, mockRequireNotebooklmSession, } = vi.hoisted(() => ({
|
|
3
|
+
mockListNotebooklmSourcesViaRpc: vi.fn(),
|
|
4
|
+
mockListNotebooklmSourcesFromPage: vi.fn(),
|
|
5
|
+
mockGetNotebooklmSourceFulltextViaRpc: vi.fn(),
|
|
6
|
+
mockGetNotebooklmPageState: vi.fn(),
|
|
7
|
+
mockRequireNotebooklmSession: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
vi.mock('./utils.js', async () => {
|
|
10
|
+
const actual = await vi.importActual('./utils.js');
|
|
11
|
+
return {
|
|
12
|
+
...actual,
|
|
13
|
+
listNotebooklmSourcesViaRpc: mockListNotebooklmSourcesViaRpc,
|
|
14
|
+
listNotebooklmSourcesFromPage: mockListNotebooklmSourcesFromPage,
|
|
15
|
+
getNotebooklmSourceFulltextViaRpc: mockGetNotebooklmSourceFulltextViaRpc,
|
|
16
|
+
getNotebooklmPageState: mockGetNotebooklmPageState,
|
|
17
|
+
requireNotebooklmSession: mockRequireNotebooklmSession,
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
import { getRegistry } from '../../registry.js';
|
|
21
|
+
import './source-fulltext.js';
|
|
22
|
+
describe('notebooklm source-fulltext', () => {
|
|
23
|
+
const command = getRegistry().get('notebooklm/source-fulltext');
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
mockListNotebooklmSourcesViaRpc.mockReset();
|
|
26
|
+
mockListNotebooklmSourcesFromPage.mockReset();
|
|
27
|
+
mockGetNotebooklmSourceFulltextViaRpc.mockReset();
|
|
28
|
+
mockGetNotebooklmPageState.mockReset();
|
|
29
|
+
mockRequireNotebooklmSession.mockReset();
|
|
30
|
+
mockRequireNotebooklmSession.mockResolvedValue(undefined);
|
|
31
|
+
mockGetNotebooklmPageState.mockResolvedValue({
|
|
32
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
33
|
+
title: 'Browser Automation',
|
|
34
|
+
hostname: 'notebooklm.google.com',
|
|
35
|
+
kind: 'notebook',
|
|
36
|
+
notebookId: 'nb-demo',
|
|
37
|
+
loginRequired: false,
|
|
38
|
+
notebookCount: 1,
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
it('returns fulltext for a source matched from rpc source rows', async () => {
|
|
42
|
+
mockListNotebooklmSourcesViaRpc.mockResolvedValue([
|
|
43
|
+
{
|
|
44
|
+
id: 'src-1',
|
|
45
|
+
notebook_id: 'nb-demo',
|
|
46
|
+
title: '粘贴的文字',
|
|
47
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
48
|
+
source: 'rpc',
|
|
49
|
+
type: 'pasted-text',
|
|
50
|
+
},
|
|
51
|
+
]);
|
|
52
|
+
mockGetNotebooklmSourceFulltextViaRpc.mockResolvedValue({
|
|
53
|
+
source_id: 'src-1',
|
|
54
|
+
notebook_id: 'nb-demo',
|
|
55
|
+
title: '粘贴的文字',
|
|
56
|
+
kind: 'generated-text',
|
|
57
|
+
content: '第一段\n第二段',
|
|
58
|
+
char_count: 7,
|
|
59
|
+
url: 'https://example.com/source',
|
|
60
|
+
source: 'rpc',
|
|
61
|
+
});
|
|
62
|
+
const result = await command.func({}, { source: 'src-1' });
|
|
63
|
+
expect(result).toEqual([
|
|
64
|
+
{
|
|
65
|
+
source_id: 'src-1',
|
|
66
|
+
notebook_id: 'nb-demo',
|
|
67
|
+
title: '粘贴的文字',
|
|
68
|
+
kind: 'generated-text',
|
|
69
|
+
content: '第一段\n第二段',
|
|
70
|
+
char_count: 7,
|
|
71
|
+
url: 'https://example.com/source',
|
|
72
|
+
source: 'rpc',
|
|
73
|
+
},
|
|
74
|
+
]);
|
|
75
|
+
});
|
|
76
|
+
it('matches by title from dom rows when rpc source list is unavailable', async () => {
|
|
77
|
+
mockListNotebooklmSourcesViaRpc.mockResolvedValue([]);
|
|
78
|
+
mockListNotebooklmSourcesFromPage.mockResolvedValue([
|
|
79
|
+
{
|
|
80
|
+
id: 'src-1',
|
|
81
|
+
notebook_id: 'nb-demo',
|
|
82
|
+
title: '粘贴的文字',
|
|
83
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
84
|
+
source: 'current-page',
|
|
85
|
+
},
|
|
86
|
+
]);
|
|
87
|
+
mockGetNotebooklmSourceFulltextViaRpc.mockResolvedValue({
|
|
88
|
+
source_id: 'src-1',
|
|
89
|
+
notebook_id: 'nb-demo',
|
|
90
|
+
title: '粘贴的文字',
|
|
91
|
+
kind: 'generated-text',
|
|
92
|
+
content: '第一段\n第二段',
|
|
93
|
+
char_count: 7,
|
|
94
|
+
url: 'https://example.com/source',
|
|
95
|
+
source: 'rpc',
|
|
96
|
+
});
|
|
97
|
+
const result = await command.func({}, { source: '粘贴的文字' });
|
|
98
|
+
expect(result).toEqual([
|
|
99
|
+
expect.objectContaining({
|
|
100
|
+
source_id: 'src-1',
|
|
101
|
+
title: '粘贴的文字',
|
|
102
|
+
content: '第一段\n第二段',
|
|
103
|
+
}),
|
|
104
|
+
]);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
import { EmptyResultError } from '../../errors.js';
|
|
3
|
+
import { NOTEBOOKLM_DOMAIN, NOTEBOOKLM_SITE } from './shared.js';
|
|
4
|
+
import { ensureNotebooklmNotebookBinding, findNotebooklmSourceRow, getNotebooklmPageState, listNotebooklmSourcesFromPage, listNotebooklmSourcesViaRpc, requireNotebooklmSession, } from './utils.js';
|
|
5
|
+
cli({
|
|
6
|
+
site: NOTEBOOKLM_SITE,
|
|
7
|
+
name: 'source-get',
|
|
8
|
+
description: 'Get one source from the currently opened NotebookLM notebook by id or title',
|
|
9
|
+
domain: NOTEBOOKLM_DOMAIN,
|
|
10
|
+
strategy: Strategy.COOKIE,
|
|
11
|
+
browser: true,
|
|
12
|
+
navigateBefore: false,
|
|
13
|
+
args: [
|
|
14
|
+
{
|
|
15
|
+
name: 'source',
|
|
16
|
+
positional: true,
|
|
17
|
+
required: true,
|
|
18
|
+
help: 'Source id or title from the current notebook',
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
columns: ['title', 'id', 'type', 'size', 'created_at', 'updated_at', 'url', 'source'],
|
|
22
|
+
func: async (page, kwargs) => {
|
|
23
|
+
await ensureNotebooklmNotebookBinding(page);
|
|
24
|
+
await requireNotebooklmSession(page);
|
|
25
|
+
const state = await getNotebooklmPageState(page);
|
|
26
|
+
if (state.kind !== 'notebook') {
|
|
27
|
+
throw new EmptyResultError('opencli notebooklm source-get', 'Open a specific NotebookLM notebook tab first, then retry.');
|
|
28
|
+
}
|
|
29
|
+
const rpcRows = await listNotebooklmSourcesViaRpc(page).catch(() => []);
|
|
30
|
+
const rows = rpcRows.length > 0 ? rpcRows : await listNotebooklmSourcesFromPage(page);
|
|
31
|
+
if (rows.length === 0) {
|
|
32
|
+
throw new EmptyResultError('opencli notebooklm source-get', 'No NotebookLM sources were found on the current page.');
|
|
33
|
+
}
|
|
34
|
+
const query = typeof kwargs.source === 'string' ? kwargs.source : String(kwargs.source ?? '');
|
|
35
|
+
const matched = findNotebooklmSourceRow(rows, query);
|
|
36
|
+
if (matched)
|
|
37
|
+
return [matched];
|
|
38
|
+
throw new EmptyResultError('opencli notebooklm source-get', `Source "${query}" was not found in the current notebook.`);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './source-get.js';
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
const { mockListNotebooklmSourcesViaRpc, mockListNotebooklmSourcesFromPage, mockGetNotebooklmPageState, mockRequireNotebooklmSession, } = vi.hoisted(() => ({
|
|
3
|
+
mockListNotebooklmSourcesViaRpc: vi.fn(),
|
|
4
|
+
mockListNotebooklmSourcesFromPage: vi.fn(),
|
|
5
|
+
mockGetNotebooklmPageState: vi.fn(),
|
|
6
|
+
mockRequireNotebooklmSession: vi.fn(),
|
|
7
|
+
}));
|
|
8
|
+
vi.mock('./utils.js', async () => {
|
|
9
|
+
const actual = await vi.importActual('./utils.js');
|
|
10
|
+
return {
|
|
11
|
+
...actual,
|
|
12
|
+
getNotebooklmPageState: mockGetNotebooklmPageState,
|
|
13
|
+
listNotebooklmSourcesViaRpc: mockListNotebooklmSourcesViaRpc,
|
|
14
|
+
listNotebooklmSourcesFromPage: mockListNotebooklmSourcesFromPage,
|
|
15
|
+
requireNotebooklmSession: mockRequireNotebooklmSession,
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
import { getRegistry } from '../../registry.js';
|
|
19
|
+
import './source-get.js';
|
|
20
|
+
describe('notebooklm source-get', () => {
|
|
21
|
+
const command = getRegistry().get('notebooklm/source-get');
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
mockListNotebooklmSourcesViaRpc.mockReset();
|
|
24
|
+
mockListNotebooklmSourcesFromPage.mockReset();
|
|
25
|
+
mockGetNotebooklmPageState.mockReset();
|
|
26
|
+
mockRequireNotebooklmSession.mockReset();
|
|
27
|
+
mockRequireNotebooklmSession.mockResolvedValue(undefined);
|
|
28
|
+
mockGetNotebooklmPageState.mockResolvedValue({
|
|
29
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
30
|
+
title: 'Browser Automation',
|
|
31
|
+
hostname: 'notebooklm.google.com',
|
|
32
|
+
kind: 'notebook',
|
|
33
|
+
notebookId: 'nb-demo',
|
|
34
|
+
loginRequired: false,
|
|
35
|
+
notebookCount: 1,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
it('returns a source by exact id from rpc results', async () => {
|
|
39
|
+
mockListNotebooklmSourcesViaRpc.mockResolvedValue([
|
|
40
|
+
{
|
|
41
|
+
id: 'src-1',
|
|
42
|
+
notebook_id: 'nb-demo',
|
|
43
|
+
title: 'Release Notes',
|
|
44
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
45
|
+
source: 'rpc',
|
|
46
|
+
type: 'web',
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
const result = await command.func({}, { source: 'src-1' });
|
|
50
|
+
expect(result).toEqual([
|
|
51
|
+
{
|
|
52
|
+
id: 'src-1',
|
|
53
|
+
notebook_id: 'nb-demo',
|
|
54
|
+
title: 'Release Notes',
|
|
55
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
56
|
+
source: 'rpc',
|
|
57
|
+
type: 'web',
|
|
58
|
+
},
|
|
59
|
+
]);
|
|
60
|
+
expect(mockListNotebooklmSourcesFromPage).not.toHaveBeenCalled();
|
|
61
|
+
});
|
|
62
|
+
it('falls back to page results and matches by title when rpc is empty', async () => {
|
|
63
|
+
mockListNotebooklmSourcesViaRpc.mockResolvedValue([]);
|
|
64
|
+
mockListNotebooklmSourcesFromPage.mockResolvedValue([
|
|
65
|
+
{
|
|
66
|
+
id: 'Meeting Notes',
|
|
67
|
+
notebook_id: 'nb-demo',
|
|
68
|
+
title: 'Meeting Notes',
|
|
69
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
70
|
+
source: 'current-page',
|
|
71
|
+
},
|
|
72
|
+
]);
|
|
73
|
+
const result = await command.func({}, { source: 'meeting notes' });
|
|
74
|
+
expect(result).toEqual([
|
|
75
|
+
{
|
|
76
|
+
id: 'Meeting Notes',
|
|
77
|
+
notebook_id: 'nb-demo',
|
|
78
|
+
title: 'Meeting Notes',
|
|
79
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
80
|
+
source: 'current-page',
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
import { EmptyResultError } from '../../errors.js';
|
|
3
|
+
import { NOTEBOOKLM_DOMAIN, NOTEBOOKLM_SITE } from './shared.js';
|
|
4
|
+
import { ensureNotebooklmNotebookBinding, findNotebooklmSourceRow, getNotebooklmPageState, getNotebooklmSourceGuideViaRpc, listNotebooklmSourcesFromPage, listNotebooklmSourcesViaRpc, requireNotebooklmSession, } from './utils.js';
|
|
5
|
+
cli({
|
|
6
|
+
site: NOTEBOOKLM_SITE,
|
|
7
|
+
name: 'source-guide',
|
|
8
|
+
description: 'Get the guide summary and keywords for one source in the currently opened NotebookLM notebook',
|
|
9
|
+
domain: NOTEBOOKLM_DOMAIN,
|
|
10
|
+
strategy: Strategy.COOKIE,
|
|
11
|
+
browser: true,
|
|
12
|
+
navigateBefore: false,
|
|
13
|
+
args: [
|
|
14
|
+
{
|
|
15
|
+
name: 'source',
|
|
16
|
+
positional: true,
|
|
17
|
+
required: true,
|
|
18
|
+
help: 'Source id or title from the current notebook',
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
columns: ['source_id', 'notebook_id', 'title', 'type', 'summary', 'keywords', 'source'],
|
|
22
|
+
func: async (page, kwargs) => {
|
|
23
|
+
await ensureNotebooklmNotebookBinding(page);
|
|
24
|
+
await requireNotebooklmSession(page);
|
|
25
|
+
const state = await getNotebooklmPageState(page);
|
|
26
|
+
if (state.kind !== 'notebook') {
|
|
27
|
+
throw new EmptyResultError('opencli notebooklm source-guide', 'Open a specific NotebookLM notebook tab first, then retry.');
|
|
28
|
+
}
|
|
29
|
+
const rpcRows = await listNotebooklmSourcesViaRpc(page).catch(() => []);
|
|
30
|
+
const rows = rpcRows.length > 0 ? rpcRows : await listNotebooklmSourcesFromPage(page);
|
|
31
|
+
if (rows.length === 0) {
|
|
32
|
+
throw new EmptyResultError('opencli notebooklm source-guide', 'No NotebookLM sources were found on the current page.');
|
|
33
|
+
}
|
|
34
|
+
const query = typeof kwargs.source === 'string' ? kwargs.source : String(kwargs.source ?? '');
|
|
35
|
+
const matched = findNotebooklmSourceRow(rows, query);
|
|
36
|
+
if (!matched) {
|
|
37
|
+
throw new EmptyResultError('opencli notebooklm source-guide', `Source "${query}" was not found in the current notebook.`);
|
|
38
|
+
}
|
|
39
|
+
const guide = await getNotebooklmSourceGuideViaRpc(page, matched).catch(() => null);
|
|
40
|
+
if (guide)
|
|
41
|
+
return [guide];
|
|
42
|
+
throw new EmptyResultError('opencli notebooklm source-guide', `NotebookLM guide was not available for source "${matched.title}".`);
|
|
43
|
+
},
|
|
44
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './source-guide.js';
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
const { mockListNotebooklmSourcesViaRpc, mockListNotebooklmSourcesFromPage, mockGetNotebooklmSourceGuideViaRpc, mockGetNotebooklmPageState, mockRequireNotebooklmSession, } = vi.hoisted(() => ({
|
|
3
|
+
mockListNotebooklmSourcesViaRpc: vi.fn(),
|
|
4
|
+
mockListNotebooklmSourcesFromPage: vi.fn(),
|
|
5
|
+
mockGetNotebooklmSourceGuideViaRpc: vi.fn(),
|
|
6
|
+
mockGetNotebooklmPageState: vi.fn(),
|
|
7
|
+
mockRequireNotebooklmSession: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
vi.mock('./utils.js', async () => {
|
|
10
|
+
const actual = await vi.importActual('./utils.js');
|
|
11
|
+
return {
|
|
12
|
+
...actual,
|
|
13
|
+
listNotebooklmSourcesViaRpc: mockListNotebooklmSourcesViaRpc,
|
|
14
|
+
listNotebooklmSourcesFromPage: mockListNotebooklmSourcesFromPage,
|
|
15
|
+
getNotebooklmSourceGuideViaRpc: mockGetNotebooklmSourceGuideViaRpc,
|
|
16
|
+
getNotebooklmPageState: mockGetNotebooklmPageState,
|
|
17
|
+
requireNotebooklmSession: mockRequireNotebooklmSession,
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
import { getRegistry } from '../../registry.js';
|
|
21
|
+
import './source-guide.js';
|
|
22
|
+
describe('notebooklm source-guide', () => {
|
|
23
|
+
const command = getRegistry().get('notebooklm/source-guide');
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
mockListNotebooklmSourcesViaRpc.mockReset();
|
|
26
|
+
mockListNotebooklmSourcesFromPage.mockReset();
|
|
27
|
+
mockGetNotebooklmSourceGuideViaRpc.mockReset();
|
|
28
|
+
mockGetNotebooklmPageState.mockReset();
|
|
29
|
+
mockRequireNotebooklmSession.mockReset();
|
|
30
|
+
mockRequireNotebooklmSession.mockResolvedValue(undefined);
|
|
31
|
+
mockGetNotebooklmPageState.mockResolvedValue({
|
|
32
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
33
|
+
title: 'Browser Automation',
|
|
34
|
+
hostname: 'notebooklm.google.com',
|
|
35
|
+
kind: 'notebook',
|
|
36
|
+
notebookId: 'nb-demo',
|
|
37
|
+
loginRequired: false,
|
|
38
|
+
notebookCount: 1,
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
it('returns source guide for a source matched from rpc source rows', async () => {
|
|
42
|
+
mockListNotebooklmSourcesViaRpc.mockResolvedValue([
|
|
43
|
+
{
|
|
44
|
+
id: 'src-yt',
|
|
45
|
+
notebook_id: 'nb-demo',
|
|
46
|
+
title: 'Video Source',
|
|
47
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
48
|
+
source: 'rpc',
|
|
49
|
+
type: 'youtube',
|
|
50
|
+
type_code: 9,
|
|
51
|
+
},
|
|
52
|
+
]);
|
|
53
|
+
mockGetNotebooklmSourceGuideViaRpc.mockResolvedValue({
|
|
54
|
+
source_id: 'src-yt',
|
|
55
|
+
notebook_id: 'nb-demo',
|
|
56
|
+
title: 'Video Source',
|
|
57
|
+
type: 'youtube',
|
|
58
|
+
summary: 'Guide summary.',
|
|
59
|
+
keywords: ['AI', 'agents'],
|
|
60
|
+
source: 'rpc',
|
|
61
|
+
});
|
|
62
|
+
const result = await command.func({}, { source: 'src-yt' });
|
|
63
|
+
expect(result).toEqual([
|
|
64
|
+
{
|
|
65
|
+
source_id: 'src-yt',
|
|
66
|
+
notebook_id: 'nb-demo',
|
|
67
|
+
title: 'Video Source',
|
|
68
|
+
type: 'youtube',
|
|
69
|
+
summary: 'Guide summary.',
|
|
70
|
+
keywords: ['AI', 'agents'],
|
|
71
|
+
source: 'rpc',
|
|
72
|
+
},
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
75
|
+
it('matches by title from dom rows when rpc source list is unavailable', async () => {
|
|
76
|
+
mockListNotebooklmSourcesViaRpc.mockResolvedValue([]);
|
|
77
|
+
mockListNotebooklmSourcesFromPage.mockResolvedValue([
|
|
78
|
+
{
|
|
79
|
+
id: 'src-1',
|
|
80
|
+
notebook_id: 'nb-demo',
|
|
81
|
+
title: 'Example Source',
|
|
82
|
+
url: 'https://notebooklm.google.com/notebook/nb-demo',
|
|
83
|
+
source: 'current-page',
|
|
84
|
+
},
|
|
85
|
+
]);
|
|
86
|
+
mockGetNotebooklmSourceGuideViaRpc.mockResolvedValue({
|
|
87
|
+
source_id: 'src-1',
|
|
88
|
+
notebook_id: 'nb-demo',
|
|
89
|
+
title: 'Example Source',
|
|
90
|
+
type: null,
|
|
91
|
+
summary: 'Guide summary.',
|
|
92
|
+
keywords: ['topic'],
|
|
93
|
+
source: 'rpc',
|
|
94
|
+
});
|
|
95
|
+
const result = await command.func({}, { source: 'example source' });
|
|
96
|
+
expect(result).toEqual([
|
|
97
|
+
expect.objectContaining({
|
|
98
|
+
source_id: 'src-1',
|
|
99
|
+
title: 'Example Source',
|
|
100
|
+
summary: 'Guide summary.',
|
|
101
|
+
}),
|
|
102
|
+
]);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
import { EmptyResultError } from '../../errors.js';
|
|
3
|
+
import { NOTEBOOKLM_DOMAIN, NOTEBOOKLM_SITE } from './shared.js';
|
|
4
|
+
import { ensureNotebooklmNotebookBinding, getNotebooklmPageState, listNotebooklmSourcesFromPage, listNotebooklmSourcesViaRpc, requireNotebooklmSession, } from './utils.js';
|
|
5
|
+
cli({
|
|
6
|
+
site: NOTEBOOKLM_SITE,
|
|
7
|
+
name: 'source-list',
|
|
8
|
+
description: 'List sources for the currently opened NotebookLM notebook',
|
|
9
|
+
domain: NOTEBOOKLM_DOMAIN,
|
|
10
|
+
strategy: Strategy.COOKIE,
|
|
11
|
+
browser: true,
|
|
12
|
+
navigateBefore: false,
|
|
13
|
+
args: [],
|
|
14
|
+
columns: ['title', 'id', 'type', 'size', 'created_at', 'updated_at', 'url', 'source'],
|
|
15
|
+
func: async (page) => {
|
|
16
|
+
await ensureNotebooklmNotebookBinding(page);
|
|
17
|
+
await requireNotebooklmSession(page);
|
|
18
|
+
const state = await getNotebooklmPageState(page);
|
|
19
|
+
if (state.kind !== 'notebook') {
|
|
20
|
+
throw new EmptyResultError('opencli notebooklm source-list', 'Open a specific NotebookLM notebook tab first, then retry.');
|
|
21
|
+
}
|
|
22
|
+
const rpcRows = await listNotebooklmSourcesViaRpc(page).catch(() => []);
|
|
23
|
+
if (rpcRows.length > 0)
|
|
24
|
+
return rpcRows;
|
|
25
|
+
const domRows = await listNotebooklmSourcesFromPage(page);
|
|
26
|
+
if (domRows.length > 0)
|
|
27
|
+
return domRows;
|
|
28
|
+
throw new EmptyResultError('opencli notebooklm source-list', 'No NotebookLM sources were found on the current page.');
|
|
29
|
+
},
|
|
30
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
import { NOTEBOOKLM_DOMAIN, NOTEBOOKLM_HOME_URL, NOTEBOOKLM_SITE } from './shared.js';
|
|
3
|
+
import { ensureNotebooklmNotebookBinding, getNotebooklmPageState } from './utils.js';
|
|
4
|
+
cli({
|
|
5
|
+
site: NOTEBOOKLM_SITE,
|
|
6
|
+
name: 'status',
|
|
7
|
+
description: 'Check NotebookLM page availability and login state in the current Chrome session',
|
|
8
|
+
domain: NOTEBOOKLM_DOMAIN,
|
|
9
|
+
strategy: Strategy.COOKIE,
|
|
10
|
+
browser: true,
|
|
11
|
+
navigateBefore: false,
|
|
12
|
+
args: [],
|
|
13
|
+
columns: ['status', 'login', 'page', 'url', 'title', 'notebooks'],
|
|
14
|
+
func: async (page) => {
|
|
15
|
+
await ensureNotebooklmNotebookBinding(page);
|
|
16
|
+
const currentUrl = await page.getCurrentUrl?.().catch(() => null);
|
|
17
|
+
if (!currentUrl || !currentUrl.includes(NOTEBOOKLM_DOMAIN)) {
|
|
18
|
+
await page.goto(NOTEBOOKLM_HOME_URL);
|
|
19
|
+
await page.wait(2);
|
|
20
|
+
}
|
|
21
|
+
const state = await getNotebooklmPageState(page);
|
|
22
|
+
return [{
|
|
23
|
+
status: state.hostname === NOTEBOOKLM_DOMAIN ? 'Connected' : 'Unavailable',
|
|
24
|
+
login: state.loginRequired ? 'Required' : 'OK',
|
|
25
|
+
page: state.kind,
|
|
26
|
+
url: state.url,
|
|
27
|
+
title: state.title,
|
|
28
|
+
notebooks: state.notebookCount,
|
|
29
|
+
}];
|
|
30
|
+
},
|
|
31
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { cli, Strategy } from '../../registry.js';
|
|
2
|
+
import { EmptyResultError } from '../../errors.js';
|
|
3
|
+
import { NOTEBOOKLM_DOMAIN, NOTEBOOKLM_SITE } from './shared.js';
|
|
4
|
+
import { ensureNotebooklmNotebookBinding, getNotebooklmPageState, getNotebooklmSummaryViaRpc, readNotebooklmSummaryFromPage, requireNotebooklmSession, } from './utils.js';
|
|
5
|
+
cli({
|
|
6
|
+
site: NOTEBOOKLM_SITE,
|
|
7
|
+
name: 'summary',
|
|
8
|
+
description: 'Get the summary block from the currently opened NotebookLM notebook',
|
|
9
|
+
domain: NOTEBOOKLM_DOMAIN,
|
|
10
|
+
strategy: Strategy.COOKIE,
|
|
11
|
+
browser: true,
|
|
12
|
+
navigateBefore: false,
|
|
13
|
+
args: [],
|
|
14
|
+
columns: ['title', 'summary', 'source', 'url'],
|
|
15
|
+
func: async (page) => {
|
|
16
|
+
await ensureNotebooklmNotebookBinding(page);
|
|
17
|
+
await requireNotebooklmSession(page);
|
|
18
|
+
const state = await getNotebooklmPageState(page);
|
|
19
|
+
if (state.kind !== 'notebook') {
|
|
20
|
+
throw new EmptyResultError('opencli notebooklm summary', 'Open a specific NotebookLM notebook tab first, then retry.');
|
|
21
|
+
}
|
|
22
|
+
const domSummary = await readNotebooklmSummaryFromPage(page);
|
|
23
|
+
if (domSummary)
|
|
24
|
+
return [domSummary];
|
|
25
|
+
const rpcSummary = await getNotebooklmSummaryViaRpc(page).catch(() => null);
|
|
26
|
+
if (rpcSummary)
|
|
27
|
+
return [rpcSummary];
|
|
28
|
+
throw new EmptyResultError('opencli notebooklm summary', 'NotebookLM summary was not found on the current page.');
|
|
29
|
+
},
|
|
30
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './summary.js';
|