@jackwener/opencli 1.7.16 → 1.7.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -9
- package/README.zh-CN.md +10 -8
- package/cli-manifest.json +377 -271
- package/clis/chatgpt/ask.js +1 -1
- package/clis/chatgpt/commands.test.js +2 -2
- package/clis/chatgpt/detail.js +1 -1
- package/clis/chatgpt/history.js +1 -1
- package/clis/chatgpt/image.js +38 -4
- package/clis/chatgpt/image.test.js +68 -1
- package/clis/chatgpt/new.js +1 -1
- package/clis/chatgpt/read.js +1 -1
- package/clis/chatgpt/send.js +1 -1
- package/clis/chatgpt/status.js +1 -1
- package/clis/chatgpt/utils.js +208 -16
- package/clis/chatgpt/utils.test.js +131 -2
- package/clis/claude/ask.js +1 -1
- package/clis/claude/detail.js +1 -1
- package/clis/claude/history.js +1 -1
- package/clis/claude/new.js +1 -1
- package/clis/claude/read.js +1 -1
- package/clis/claude/send.js +1 -1
- package/clis/claude/status.js +1 -1
- package/clis/deepseek/ask.js +1 -1
- package/clis/deepseek/detail.js +1 -1
- package/clis/deepseek/history.js +1 -1
- package/clis/deepseek/new.js +1 -1
- package/clis/deepseek/read.js +1 -1
- package/clis/deepseek/send.js +1 -1
- package/clis/deepseek/status.js +1 -1
- package/clis/doubao/ask.js +1 -1
- package/clis/doubao/detail.js +1 -1
- package/clis/doubao/history.js +1 -1
- package/clis/doubao/meeting-summary.js +1 -1
- package/clis/doubao/meeting-transcript.js +1 -1
- package/clis/doubao/new.js +1 -1
- package/clis/doubao/read.js +1 -1
- package/clis/doubao/send.js +1 -1
- package/clis/doubao/status.js +1 -1
- package/clis/doubao/utils.js +17 -0
- package/clis/doubao/utils.test.js +61 -0
- package/clis/gemini/ask.js +1 -1
- package/clis/gemini/deep-research-result.js +1 -1
- package/clis/gemini/deep-research.js +1 -1
- package/clis/gemini/image.js +1 -1
- package/clis/gemini/new.js +1 -1
- package/clis/grok/ask.js +1 -1
- package/clis/grok/detail.js +1 -1
- package/clis/grok/history.js +1 -1
- package/clis/grok/image.js +1 -1
- package/clis/grok/new.js +1 -1
- package/clis/grok/read.js +1 -1
- package/clis/grok/send.js +1 -1
- package/clis/grok/status.js +1 -1
- package/clis/notebooklm/current.js +1 -1
- package/clis/notebooklm/get.js +1 -1
- package/clis/notebooklm/history.js +1 -1
- package/clis/notebooklm/note-list.js +1 -1
- package/clis/notebooklm/notes-get.js +1 -1
- package/clis/notebooklm/open.js +2 -2
- package/clis/notebooklm/open.test.js +1 -1
- package/clis/notebooklm/source-fulltext.js +1 -1
- package/clis/notebooklm/source-get.js +1 -1
- package/clis/notebooklm/source-guide.js +1 -1
- package/clis/notebooklm/source-list.js +1 -1
- package/clis/notebooklm/summary.js +1 -1
- package/clis/qwen/ask.js +1 -1
- package/clis/qwen/detail.js +1 -1
- package/clis/qwen/history.js +1 -1
- package/clis/qwen/image.js +1 -1
- package/clis/qwen/new.js +1 -1
- package/clis/qwen/read.js +1 -1
- package/clis/qwen/send.js +1 -1
- package/clis/qwen/status.js +1 -1
- package/clis/reddit/comment.js +1 -1
- package/clis/reddit/frontpage.js +1 -1
- package/clis/reddit/popular.js +1 -1
- package/clis/reddit/read.js +1 -1
- package/clis/reddit/read.test.js +2 -2
- package/clis/reddit/reply.js +182 -0
- package/clis/reddit/reply.test.js +89 -0
- package/clis/reddit/save.js +1 -1
- package/clis/reddit/saved.js +1 -1
- package/clis/reddit/search.js +1 -1
- package/clis/reddit/subreddit.js +1 -1
- package/clis/reddit/subscribe.js +1 -1
- package/clis/reddit/upvote.js +1 -1
- package/clis/reddit/upvoted.js +1 -1
- package/clis/reddit/user-comments.js +1 -1
- package/clis/reddit/user-posts.js +1 -1
- package/clis/reddit/user.js +1 -1
- package/clis/rednote/comments.js +76 -0
- package/clis/rednote/download.js +59 -0
- package/clis/rednote/feed.js +95 -0
- package/clis/rednote/navigation.test.js +26 -0
- package/clis/rednote/note.js +68 -0
- package/clis/rednote/notifications.js +139 -0
- package/clis/rednote/rednote.test.js +157 -0
- package/clis/rednote/search.js +97 -0
- package/clis/rednote/user.js +55 -0
- package/clis/twitter/article.js +1 -1
- package/clis/twitter/bookmark-folder.js +1 -1
- package/clis/twitter/bookmark-folders.js +1 -1
- package/clis/twitter/bookmarks.js +1 -1
- package/clis/twitter/download.js +1 -1
- package/clis/twitter/followers.js +1 -1
- package/clis/twitter/following.js +1 -1
- package/clis/twitter/likes.js +1 -1
- package/clis/twitter/list-tweets.js +1 -1
- package/clis/twitter/lists.js +1 -1
- package/clis/twitter/notifications.js +1 -1
- package/clis/twitter/profile.js +1 -1
- package/clis/twitter/search.js +1 -1
- package/clis/twitter/thread.js +1 -1
- package/clis/twitter/timeline.js +1 -1
- package/clis/twitter/trending.js +1 -1
- package/clis/twitter/tweets.js +1 -1
- package/clis/xiaohongshu/comments.js +34 -24
- package/clis/xiaohongshu/download.js +32 -23
- package/clis/xiaohongshu/feed.js +23 -15
- package/clis/xiaohongshu/note-helpers.js +16 -6
- package/clis/xiaohongshu/note.js +26 -20
- package/clis/xiaohongshu/notifications.js +26 -19
- package/clis/xiaohongshu/search.js +37 -28
- package/clis/xiaohongshu/user-helpers.js +13 -4
- package/clis/xiaohongshu/user-helpers.test.js +20 -0
- package/clis/xiaohongshu/user.js +9 -4
- package/clis/youtube/transcript.js +28 -3
- package/clis/youtube/transcript.test.js +90 -1
- package/clis/yuanbao/ask.js +1 -1
- package/clis/yuanbao/detail.js +1 -1
- package/clis/yuanbao/history.js +1 -1
- package/clis/yuanbao/new.js +1 -1
- package/clis/yuanbao/read.js +1 -1
- package/clis/yuanbao/send.js +1 -1
- package/clis/yuanbao/status.js +1 -1
- package/dist/src/browser/bridge.d.ts +3 -1
- package/dist/src/browser/bridge.js +3 -1
- package/dist/src/browser/cdp.d.ts +3 -1
- package/dist/src/browser/daemon-client.d.ts +7 -14
- package/dist/src/browser/daemon-client.js +2 -6
- package/dist/src/browser/network-cache.d.ts +5 -5
- package/dist/src/browser/network-cache.js +8 -8
- package/dist/src/browser/network-cache.test.js +4 -4
- package/dist/src/browser/page.d.ts +8 -7
- package/dist/src/browser/page.js +23 -16
- package/dist/src/browser/page.test.js +60 -30
- package/dist/src/build-manifest.js +1 -1
- package/dist/src/cli.js +60 -162
- package/dist/src/cli.test.js +184 -198
- package/dist/src/commanderAdapter.js +2 -0
- package/dist/src/discovery.js +1 -1
- package/dist/src/doctor.d.ts +0 -4
- package/dist/src/doctor.js +14 -73
- package/dist/src/doctor.test.js +28 -97
- package/dist/src/execution.d.ts +1 -0
- package/dist/src/execution.js +20 -21
- package/dist/src/execution.test.js +27 -31
- package/dist/src/help.js +7 -1
- package/dist/src/main.js +0 -19
- package/dist/src/manifest-types.d.ts +2 -4
- package/dist/src/observation/artifact.js +1 -1
- package/dist/src/observation/artifact.test.js +3 -3
- package/dist/src/observation/events.d.ts +1 -1
- package/dist/src/observation/manager.js +1 -1
- package/dist/src/observation/manager.test.js +3 -3
- package/dist/src/registry-api.d.ts +1 -1
- package/dist/src/registry.d.ts +3 -12
- package/dist/src/registry.js +6 -10
- package/dist/src/runtime.d.ts +7 -2
- package/dist/src/runtime.js +3 -1
- package/dist/src/serialization.d.ts +1 -1
- package/dist/src/serialization.js +1 -1
- package/dist/src/types.d.ts +0 -15
- package/package.json +1 -1
|
@@ -14,9 +14,9 @@ describe('network-cache', () => {
|
|
|
14
14
|
afterEach(() => {
|
|
15
15
|
fs.rmSync(baseDir, { recursive: true, force: true });
|
|
16
16
|
});
|
|
17
|
-
it('sanitizes
|
|
18
|
-
const p = getCachePath('
|
|
19
|
-
expect(path.basename(p)).toBe('
|
|
17
|
+
it('sanitizes session names into safe filenames', () => {
|
|
18
|
+
const p = getCachePath('twitter/agent 1', baseDir);
|
|
19
|
+
expect(path.basename(p)).toBe('twitter_agent_1.json');
|
|
20
20
|
});
|
|
21
21
|
it('round-trips entries through save + load', () => {
|
|
22
22
|
saveNetworkCache('ws', [makeEntry('UserTweets'), makeEntry('UserByScreenName')], baseDir);
|
|
@@ -49,7 +49,7 @@ describe('network-cache', () => {
|
|
|
49
49
|
});
|
|
50
50
|
it('findEntry returns matching entry or null', () => {
|
|
51
51
|
const file = {
|
|
52
|
-
version: 1,
|
|
52
|
+
version: 1, session: 'ws', savedAt: new Date().toISOString(),
|
|
53
53
|
entries: [makeEntry('A'), makeEntry('B')],
|
|
54
54
|
};
|
|
55
55
|
expect(findEntry(file, 'B')?.key).toBe('B');
|
|
@@ -14,23 +14,24 @@ import { BasePage } from './base-page.js';
|
|
|
14
14
|
* Page — implements IPage by talking to the daemon via HTTP.
|
|
15
15
|
*/
|
|
16
16
|
export declare class Page extends BasePage {
|
|
17
|
-
private readonly
|
|
17
|
+
private readonly session;
|
|
18
18
|
readonly contextId?: string | undefined;
|
|
19
19
|
private readonly windowMode?;
|
|
20
|
+
private readonly surface;
|
|
21
|
+
private readonly siteSession?;
|
|
20
22
|
private readonly _idleTimeout;
|
|
21
|
-
constructor(
|
|
23
|
+
constructor(session: string, idleTimeout?: number, contextId?: string | undefined, windowMode?: "foreground" | "background" | undefined, surface?: 'browser' | 'adapter', siteSession?: "ephemeral" | "persistent" | undefined);
|
|
22
24
|
/** Active page identity (targetId), set after navigate and used in all subsequent commands */
|
|
23
25
|
private _page;
|
|
24
26
|
private _networkCaptureUnsupported;
|
|
25
27
|
private _networkCaptureWarned;
|
|
26
|
-
/** Helper: spread
|
|
27
|
-
private
|
|
28
|
-
/** Helper: spread
|
|
28
|
+
/** Helper: spread session into command params */
|
|
29
|
+
private _sessionOpts;
|
|
30
|
+
/** Helper: spread session + page identity into command params */
|
|
29
31
|
private _cmdOpts;
|
|
30
32
|
goto(url: string, options?: {
|
|
31
33
|
waitUntil?: 'load' | 'none';
|
|
32
34
|
settleMs?: number;
|
|
33
|
-
allowBoundNavigation?: boolean;
|
|
34
35
|
}): Promise<void>;
|
|
35
36
|
/** Get the active page identity (targetId) */
|
|
36
37
|
getActivePage(): string | undefined;
|
|
@@ -42,7 +43,7 @@ export declare class Page extends BasePage {
|
|
|
42
43
|
domain?: string;
|
|
43
44
|
url?: string;
|
|
44
45
|
}): Promise<BrowserCookie[]>;
|
|
45
|
-
/** Release the current
|
|
46
|
+
/** Release the current browser session lease in the extension */
|
|
46
47
|
closeWindow(): Promise<void>;
|
|
47
48
|
tabs(): Promise<unknown[]>;
|
|
48
49
|
newTab(url?: string): Promise<string | undefined>;
|
package/dist/src/browser/page.js
CHANGED
|
@@ -26,45 +26,52 @@ function isUnsupportedNetworkCaptureError(err) {
|
|
|
26
26
|
* Page — implements IPage by talking to the daemon via HTTP.
|
|
27
27
|
*/
|
|
28
28
|
export class Page extends BasePage {
|
|
29
|
-
|
|
29
|
+
session;
|
|
30
30
|
contextId;
|
|
31
31
|
windowMode;
|
|
32
|
+
surface;
|
|
33
|
+
siteSession;
|
|
32
34
|
_idleTimeout;
|
|
33
|
-
constructor(
|
|
35
|
+
constructor(session, idleTimeout, contextId, windowMode, surface = 'browser', siteSession) {
|
|
34
36
|
super();
|
|
35
|
-
this.
|
|
37
|
+
this.session = session;
|
|
36
38
|
this.contextId = contextId;
|
|
37
39
|
this.windowMode = windowMode;
|
|
40
|
+
this.surface = surface;
|
|
41
|
+
this.siteSession = siteSession;
|
|
38
42
|
this._idleTimeout = idleTimeout;
|
|
39
43
|
}
|
|
40
44
|
/** Active page identity (targetId), set after navigate and used in all subsequent commands */
|
|
41
45
|
_page;
|
|
42
46
|
_networkCaptureUnsupported = false;
|
|
43
47
|
_networkCaptureWarned = false;
|
|
44
|
-
/** Helper: spread
|
|
45
|
-
|
|
48
|
+
/** Helper: spread session into command params */
|
|
49
|
+
_sessionOpts() {
|
|
46
50
|
return {
|
|
47
|
-
|
|
51
|
+
session: this.session,
|
|
52
|
+
surface: this.surface,
|
|
48
53
|
...(this.contextId && { contextId: this.contextId }),
|
|
49
54
|
...(this._idleTimeout != null && { idleTimeout: this._idleTimeout }),
|
|
50
55
|
...(this.windowMode && { windowMode: this.windowMode }),
|
|
56
|
+
...(this.siteSession && { siteSession: this.siteSession }),
|
|
51
57
|
};
|
|
52
58
|
}
|
|
53
|
-
/** Helper: spread
|
|
59
|
+
/** Helper: spread session + page identity into command params */
|
|
54
60
|
_cmdOpts() {
|
|
55
61
|
return {
|
|
56
|
-
|
|
62
|
+
session: this.session,
|
|
63
|
+
surface: this.surface,
|
|
57
64
|
...(this.contextId && { contextId: this.contextId }),
|
|
58
65
|
...(this._page !== undefined && { page: this._page }),
|
|
59
66
|
...(this._idleTimeout != null && { idleTimeout: this._idleTimeout }),
|
|
60
67
|
...(this.windowMode && { windowMode: this.windowMode }),
|
|
68
|
+
...(this.siteSession && { siteSession: this.siteSession }),
|
|
61
69
|
};
|
|
62
70
|
}
|
|
63
71
|
async goto(url, options) {
|
|
64
72
|
const result = await sendCommandFull('navigate', {
|
|
65
73
|
url,
|
|
66
74
|
...this._cmdOpts(),
|
|
67
|
-
...(options?.allowBoundNavigation === true && { allowBoundNavigation: true }),
|
|
68
75
|
});
|
|
69
76
|
// Remember the page identity (targetId) for subsequent calls
|
|
70
77
|
if (result.page) {
|
|
@@ -144,13 +151,13 @@ export class Page extends BasePage {
|
|
|
144
151
|
}
|
|
145
152
|
}
|
|
146
153
|
async getCookies(opts = {}) {
|
|
147
|
-
const result = await sendCommand('cookies', { ...this.
|
|
154
|
+
const result = await sendCommand('cookies', { ...this._sessionOpts(), ...opts });
|
|
148
155
|
return Array.isArray(result) ? result : [];
|
|
149
156
|
}
|
|
150
|
-
/** Release the current
|
|
157
|
+
/** Release the current browser session lease in the extension */
|
|
151
158
|
async closeWindow() {
|
|
152
159
|
try {
|
|
153
|
-
await sendCommand('close-window', { ...this.
|
|
160
|
+
await sendCommand('close-window', { ...this._sessionOpts() });
|
|
154
161
|
}
|
|
155
162
|
catch {
|
|
156
163
|
// Window may already be closed or daemon may be down
|
|
@@ -163,20 +170,20 @@ export class Page extends BasePage {
|
|
|
163
170
|
}
|
|
164
171
|
}
|
|
165
172
|
async tabs() {
|
|
166
|
-
const result = await sendCommand('tabs', { op: 'list', ...this.
|
|
173
|
+
const result = await sendCommand('tabs', { op: 'list', ...this._sessionOpts() });
|
|
167
174
|
return Array.isArray(result) ? result : [];
|
|
168
175
|
}
|
|
169
176
|
async newTab(url) {
|
|
170
177
|
const result = await sendCommandFull('tabs', {
|
|
171
178
|
op: 'new',
|
|
172
179
|
...(url !== undefined && { url }),
|
|
173
|
-
...this.
|
|
180
|
+
...this._sessionOpts(),
|
|
174
181
|
});
|
|
175
182
|
this._lastUrl = null;
|
|
176
183
|
return result.page;
|
|
177
184
|
}
|
|
178
185
|
async closeTab(target) {
|
|
179
|
-
const params = { op: 'close', ...this.
|
|
186
|
+
const params = { op: 'close', ...this._sessionOpts() };
|
|
180
187
|
if (typeof target === 'number')
|
|
181
188
|
params.index = target;
|
|
182
189
|
else if (typeof target === 'string')
|
|
@@ -194,7 +201,7 @@ export class Page extends BasePage {
|
|
|
194
201
|
const result = await sendCommandFull('tabs', {
|
|
195
202
|
op: 'select',
|
|
196
203
|
...(typeof target === 'number' ? { index: target } : { page: target }),
|
|
197
|
-
...this.
|
|
204
|
+
...this._sessionOpts(),
|
|
198
205
|
});
|
|
199
206
|
if (result.page)
|
|
200
207
|
this._page = result.page;
|
|
@@ -24,21 +24,40 @@ describe('Page.getCurrentUrl', () => {
|
|
|
24
24
|
});
|
|
25
25
|
it('reads the real browser URL when no local navigation cache exists', async () => {
|
|
26
26
|
sendCommandMock.mockResolvedValueOnce('https://notebooklm.google.com/notebook/nb-live');
|
|
27
|
-
const page = new Page('
|
|
27
|
+
const page = new Page('notebooklm', undefined, undefined, undefined, 'adapter');
|
|
28
28
|
const url = await page.getCurrentUrl();
|
|
29
29
|
expect(url).toBe('https://notebooklm.google.com/notebook/nb-live');
|
|
30
30
|
expect(sendCommandMock).toHaveBeenCalledTimes(1);
|
|
31
31
|
expect(sendCommandMock).toHaveBeenCalledWith('exec', expect.objectContaining({
|
|
32
|
-
|
|
32
|
+
session: 'notebooklm',
|
|
33
|
+
surface: 'adapter',
|
|
33
34
|
}));
|
|
34
35
|
});
|
|
35
36
|
it('caches the discovered browser URL for later reads', async () => {
|
|
36
37
|
sendCommandMock.mockResolvedValueOnce('https://notebooklm.google.com/notebook/nb-live');
|
|
37
|
-
const page = new Page('
|
|
38
|
+
const page = new Page('notebooklm', undefined, undefined, undefined, 'adapter');
|
|
38
39
|
expect(await page.getCurrentUrl()).toBe('https://notebooklm.google.com/notebook/nb-live');
|
|
39
40
|
expect(await page.getCurrentUrl()).toBe('https://notebooklm.google.com/notebook/nb-live');
|
|
40
41
|
expect(sendCommandMock).toHaveBeenCalledTimes(1);
|
|
41
42
|
});
|
|
43
|
+
it('passes adapter site session lifecycle through daemon commands', async () => {
|
|
44
|
+
sendCommandFullMock.mockResolvedValueOnce({ page: 'page-1', data: { url: 'https://chatgpt.com/' } });
|
|
45
|
+
sendCommandMock.mockResolvedValueOnce(null);
|
|
46
|
+
const page = new Page('site:chatgpt', undefined, undefined, undefined, 'adapter', 'persistent');
|
|
47
|
+
await page.goto('https://chatgpt.com/', { waitUntil: 'none' });
|
|
48
|
+
await page.evaluate('document.title');
|
|
49
|
+
expect(sendCommandFullMock).toHaveBeenCalledWith('navigate', expect.objectContaining({
|
|
50
|
+
session: 'site:chatgpt',
|
|
51
|
+
surface: 'adapter',
|
|
52
|
+
siteSession: 'persistent',
|
|
53
|
+
}));
|
|
54
|
+
expect(sendCommandMock).toHaveBeenCalledWith('exec', expect.objectContaining({
|
|
55
|
+
session: 'site:chatgpt',
|
|
56
|
+
surface: 'adapter',
|
|
57
|
+
siteSession: 'persistent',
|
|
58
|
+
page: 'page-1',
|
|
59
|
+
}));
|
|
60
|
+
});
|
|
42
61
|
});
|
|
43
62
|
describe('Page.evaluate', () => {
|
|
44
63
|
beforeEach(() => {
|
|
@@ -50,7 +69,7 @@ describe('Page.evaluate', () => {
|
|
|
50
69
|
sendCommandMock
|
|
51
70
|
.mockRejectedValueOnce(new Error('{"code":-32000,"message":"Inspected target navigated or closed"}'))
|
|
52
71
|
.mockResolvedValueOnce(42);
|
|
53
|
-
const page = new Page('
|
|
72
|
+
const page = new Page('notebooklm', undefined, undefined, undefined, 'adapter');
|
|
54
73
|
const value = await page.evaluate('21 + 21');
|
|
55
74
|
expect(value).toBe(42);
|
|
56
75
|
expect(sendCommandMock).toHaveBeenCalledTimes(2);
|
|
@@ -64,30 +83,32 @@ describe('Page network capture compatibility', () => {
|
|
|
64
83
|
});
|
|
65
84
|
it('treats unknown network-capture-start as unsupported and memoizes it', async () => {
|
|
66
85
|
sendCommandMock.mockRejectedValueOnce(new Error('Unknown action: network-capture-start'));
|
|
67
|
-
const page = new Page('
|
|
86
|
+
const page = new Page('notebooklm', undefined, undefined, undefined, 'adapter');
|
|
68
87
|
await expect(page.startNetworkCapture()).resolves.toBe(false);
|
|
69
88
|
await expect(page.startNetworkCapture()).resolves.toBe(false);
|
|
70
89
|
expect(sendCommandMock).toHaveBeenCalledTimes(1);
|
|
71
90
|
expect(warnMock).toHaveBeenCalledTimes(1);
|
|
72
91
|
expect(warnMock).toHaveBeenCalledWith(expect.stringContaining('does not support network capture'));
|
|
73
92
|
expect(sendCommandMock).toHaveBeenCalledWith('network-capture-start', expect.objectContaining({
|
|
74
|
-
|
|
93
|
+
session: 'notebooklm',
|
|
94
|
+
surface: 'adapter',
|
|
75
95
|
}));
|
|
76
96
|
});
|
|
77
97
|
it('returns an empty capture when network-capture-read is unsupported', async () => {
|
|
78
98
|
sendCommandMock.mockRejectedValueOnce(new Error('Unknown action: network-capture-read'));
|
|
79
|
-
const page = new Page('
|
|
99
|
+
const page = new Page('notebooklm', undefined, undefined, undefined, 'adapter');
|
|
80
100
|
await expect(page.readNetworkCapture()).resolves.toEqual([]);
|
|
81
101
|
await expect(page.readNetworkCapture()).resolves.toEqual([]);
|
|
82
102
|
expect(sendCommandMock).toHaveBeenCalledTimes(1);
|
|
83
103
|
expect(warnMock).toHaveBeenCalledTimes(1);
|
|
84
104
|
expect(sendCommandMock).toHaveBeenCalledWith('network-capture-read', expect.objectContaining({
|
|
85
|
-
|
|
105
|
+
session: 'notebooklm',
|
|
106
|
+
surface: 'adapter',
|
|
86
107
|
}));
|
|
87
108
|
});
|
|
88
109
|
it('rethrows unrelated network capture failures', async () => {
|
|
89
110
|
sendCommandMock.mockRejectedValueOnce(new Error('Extension disconnected'));
|
|
90
|
-
const page = new Page('
|
|
111
|
+
const page = new Page('notebooklm', undefined, undefined, undefined, 'adapter');
|
|
91
112
|
await expect(page.startNetworkCapture()).rejects.toThrow('Extension disconnected');
|
|
92
113
|
expect(sendCommandMock).toHaveBeenCalledTimes(1);
|
|
93
114
|
expect(warnMock).not.toHaveBeenCalled();
|
|
@@ -96,7 +117,7 @@ describe('Page network capture compatibility', () => {
|
|
|
96
117
|
sendCommandMock
|
|
97
118
|
.mockRejectedValueOnce(new Error('Unknown action: network-capture-start'))
|
|
98
119
|
.mockRejectedValueOnce(new Error('Unknown action: network-capture-read'));
|
|
99
|
-
const page = new Page('
|
|
120
|
+
const page = new Page('notebooklm', undefined, undefined, undefined, 'adapter');
|
|
100
121
|
await expect(page.startNetworkCapture()).resolves.toBe(false);
|
|
101
122
|
await expect(page.readNetworkCapture()).resolves.toEqual([]);
|
|
102
123
|
expect(warnMock).toHaveBeenCalledTimes(1);
|
|
@@ -108,14 +129,14 @@ describe('Page download waits', () => {
|
|
|
108
129
|
sendCommandFullMock.mockReset();
|
|
109
130
|
warnMock.mockReset();
|
|
110
131
|
});
|
|
111
|
-
it('sends wait-download through the daemon with
|
|
132
|
+
it('sends wait-download through the daemon with session and timeout', async () => {
|
|
112
133
|
sendCommandMock.mockResolvedValueOnce({
|
|
113
134
|
downloaded: true,
|
|
114
135
|
filename: '/tmp/receipt.pdf',
|
|
115
136
|
state: 'complete',
|
|
116
137
|
elapsedMs: 5,
|
|
117
138
|
});
|
|
118
|
-
const page = new Page('
|
|
139
|
+
const page = new Page('mercury', undefined, undefined, undefined, 'adapter');
|
|
119
140
|
const result = await page.waitForDownload('receipt', 1234);
|
|
120
141
|
expect(result).toEqual({
|
|
121
142
|
downloaded: true,
|
|
@@ -124,7 +145,8 @@ describe('Page download waits', () => {
|
|
|
124
145
|
elapsedMs: 5,
|
|
125
146
|
});
|
|
126
147
|
expect(sendCommandMock).toHaveBeenCalledWith('wait-download', expect.objectContaining({
|
|
127
|
-
|
|
148
|
+
session: 'mercury',
|
|
149
|
+
surface: 'adapter',
|
|
128
150
|
pattern: 'receipt',
|
|
129
151
|
timeoutMs: 1234,
|
|
130
152
|
}));
|
|
@@ -138,10 +160,11 @@ describe('Page CDP helpers', () => {
|
|
|
138
160
|
});
|
|
139
161
|
it('handles JavaScript dialogs through the CDP passthrough', async () => {
|
|
140
162
|
sendCommandMock.mockResolvedValueOnce({});
|
|
141
|
-
const page = new Page('
|
|
163
|
+
const page = new Page('default');
|
|
142
164
|
await page.handleJavaScriptDialog(true, 'confirm');
|
|
143
165
|
expect(sendCommandMock).toHaveBeenCalledWith('cdp', expect.objectContaining({
|
|
144
|
-
|
|
166
|
+
session: 'default',
|
|
167
|
+
surface: 'browser',
|
|
145
168
|
cdpMethod: 'Page.handleJavaScriptDialog',
|
|
146
169
|
cdpParams: { accept: true, promptText: 'confirm' },
|
|
147
170
|
}));
|
|
@@ -158,24 +181,26 @@ describe('Page active target tracking', () => {
|
|
|
158
181
|
.mockResolvedValueOnce({ data: { url: 'https://first.example' }, page: 'page-1' })
|
|
159
182
|
.mockResolvedValueOnce({ data: { selected: true }, page: 'page-2' });
|
|
160
183
|
sendCommandMock.mockResolvedValue('ok');
|
|
161
|
-
const page = new Page('
|
|
184
|
+
const page = new Page('default');
|
|
162
185
|
await page.goto('https://first.example', { waitUntil: 'none' });
|
|
163
186
|
expect(page.getActivePage()).toBe('page-1');
|
|
164
187
|
await page.selectTab(1);
|
|
165
188
|
expect(page.getActivePage()).toBe('page-2');
|
|
166
189
|
await page.evaluate('1 + 1');
|
|
167
190
|
expect(sendCommandMock).toHaveBeenLastCalledWith('exec', expect.objectContaining({
|
|
168
|
-
|
|
191
|
+
session: 'default',
|
|
192
|
+
surface: 'browser',
|
|
169
193
|
page: 'page-2',
|
|
170
194
|
}));
|
|
171
195
|
});
|
|
172
196
|
it('allows the caller to bind a specific active page identity explicitly', async () => {
|
|
173
197
|
sendCommandMock.mockResolvedValue('bound');
|
|
174
|
-
const page = new Page('
|
|
198
|
+
const page = new Page('default');
|
|
175
199
|
page.setActivePage?.('page-explicit');
|
|
176
200
|
await page.evaluate('1 + 1');
|
|
177
201
|
expect(sendCommandMock).toHaveBeenCalledWith('exec', expect.objectContaining({
|
|
178
|
-
|
|
202
|
+
session: 'default',
|
|
203
|
+
surface: 'browser',
|
|
179
204
|
page: 'page-explicit',
|
|
180
205
|
}));
|
|
181
206
|
});
|
|
@@ -187,14 +212,15 @@ describe('Page active target tracking', () => {
|
|
|
187
212
|
page: 'page-2',
|
|
188
213
|
});
|
|
189
214
|
sendCommandMock.mockResolvedValue('ok');
|
|
190
|
-
const page = new Page('
|
|
215
|
+
const page = new Page('default');
|
|
191
216
|
await page.goto('https://first.example', { waitUntil: 'none' });
|
|
192
217
|
const created = await page.newTab?.('https://second.example');
|
|
193
218
|
expect(created).toBe('page-2');
|
|
194
219
|
expect(page.getActivePage()).toBe('page-1');
|
|
195
220
|
await page.evaluate('1 + 1');
|
|
196
221
|
expect(sendCommandMock).toHaveBeenLastCalledWith('exec', expect.objectContaining({
|
|
197
|
-
|
|
222
|
+
session: 'default',
|
|
223
|
+
surface: 'browser',
|
|
198
224
|
page: 'page-1',
|
|
199
225
|
}));
|
|
200
226
|
});
|
|
@@ -203,7 +229,7 @@ describe('Page active target tracking', () => {
|
|
|
203
229
|
data: { url: 'https://second.example' },
|
|
204
230
|
page: 'page-2',
|
|
205
231
|
});
|
|
206
|
-
const page = new Page('
|
|
232
|
+
const page = new Page('default');
|
|
207
233
|
const created = await page.newTab?.('https://second.example');
|
|
208
234
|
expect(created).toBe('page-2');
|
|
209
235
|
expect(page.getActivePage()).toBeUndefined();
|
|
@@ -212,16 +238,18 @@ describe('Page active target tracking', () => {
|
|
|
212
238
|
expect(sendCommandFullMock).toHaveBeenCalledWith('tabs', expect.objectContaining({
|
|
213
239
|
op: 'new',
|
|
214
240
|
url: 'https://second.example',
|
|
215
|
-
|
|
241
|
+
session: 'default',
|
|
242
|
+
surface: 'browser',
|
|
216
243
|
}));
|
|
217
244
|
});
|
|
218
245
|
it('closes a tab by explicit page identity', async () => {
|
|
219
246
|
sendCommandMock.mockResolvedValueOnce({ closed: 'page-2' });
|
|
220
|
-
const page = new Page('
|
|
247
|
+
const page = new Page('default');
|
|
221
248
|
await page.closeTab?.('page-2');
|
|
222
249
|
expect(sendCommandMock).toHaveBeenCalledWith('tabs', expect.objectContaining({
|
|
223
250
|
op: 'close',
|
|
224
|
-
|
|
251
|
+
session: 'default',
|
|
252
|
+
surface: 'browser',
|
|
225
253
|
page: 'page-2',
|
|
226
254
|
}));
|
|
227
255
|
});
|
|
@@ -230,7 +258,7 @@ describe('Page active target tracking', () => {
|
|
|
230
258
|
sendCommandMock
|
|
231
259
|
.mockResolvedValueOnce({ closed: 'page-2' })
|
|
232
260
|
.mockResolvedValueOnce('ok');
|
|
233
|
-
const page = new Page('
|
|
261
|
+
const page = new Page('default');
|
|
234
262
|
await page.selectTab(1);
|
|
235
263
|
expect(page.getActivePage()).toBe('page-2');
|
|
236
264
|
await page.closeTab?.(1);
|
|
@@ -239,7 +267,8 @@ describe('Page active target tracking', () => {
|
|
|
239
267
|
const evalCall = sendCommandMock.mock.calls.at(-1);
|
|
240
268
|
expect(evalCall?.[0]).toBe('exec');
|
|
241
269
|
expect(evalCall?.[1]).toEqual(expect.objectContaining({
|
|
242
|
-
|
|
270
|
+
session: 'default',
|
|
271
|
+
surface: 'browser',
|
|
243
272
|
}));
|
|
244
273
|
expect(evalCall?.[1]).not.toHaveProperty('page');
|
|
245
274
|
});
|
|
@@ -252,18 +281,19 @@ describe('Page.screenshot', () => {
|
|
|
252
281
|
});
|
|
253
282
|
it('forwards width / height / fullPage options to the bridge', async () => {
|
|
254
283
|
sendCommandMock.mockResolvedValueOnce('BASE64');
|
|
255
|
-
const page = new Page('
|
|
284
|
+
const page = new Page('default');
|
|
256
285
|
const data = await page.screenshot({ fullPage: true, width: 1080 });
|
|
257
286
|
expect(data).toBe('BASE64');
|
|
258
287
|
expect(sendCommandMock).toHaveBeenCalledWith('screenshot', expect.objectContaining({
|
|
259
|
-
|
|
288
|
+
session: 'default',
|
|
289
|
+
surface: 'browser',
|
|
260
290
|
fullPage: true,
|
|
261
291
|
width: 1080,
|
|
262
292
|
}));
|
|
263
293
|
});
|
|
264
294
|
it('omits viewport overrides when none are set', async () => {
|
|
265
295
|
sendCommandMock.mockResolvedValueOnce('BASE64');
|
|
266
|
-
const page = new Page('
|
|
296
|
+
const page = new Page('default');
|
|
267
297
|
await page.screenshot();
|
|
268
298
|
const call = sendCommandMock.mock.calls.at(-1);
|
|
269
299
|
expect(call?.[0]).toBe('screenshot');
|