notebooklm-mcp-ultimate 2.3.1 → 2.3.2
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/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/operations/notebook-crud-operations.d.ts +5 -9
- package/dist/operations/notebook-crud-operations.d.ts.map +1 -1
- package/dist/operations/notebook-crud-operations.js +269 -73
- package/dist/operations/notebook-crud-operations.js.map +1 -1
- package/dist/session/browser-session.d.ts +20 -0
- package/dist/session/browser-session.d.ts.map +1 -1
- package/dist/session/browser-session.js +238 -77
- package/dist/session/browser-session.js.map +1 -1
- package/dist/tools/handlers/source-handlers.d.ts +78 -12
- package/dist/tools/handlers/source-handlers.d.ts.map +1 -1
- package/dist/tools/handlers/source-handlers.js +206 -173
- package/dist/tools/handlers/source-handlers.js.map +1 -1
- package/dist/tools/handlers.d.ts +76 -10
- package/dist/tools/handlers.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Source Management Tool Handlers
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Browser-only implementations for source management.
|
|
5
|
+
* Only addDriveSource uses API (requires Drive picker).
|
|
5
6
|
*/
|
|
6
7
|
import type { NotebookLibrary } from '../../library/notebook-library.js';
|
|
7
8
|
import type { SessionManager } from '../../session/session-manager.js';
|
|
8
9
|
import type { ProgressCallback } from '../../types.js';
|
|
9
|
-
import * as sourceOps from '../../operations/source-operations.js';
|
|
10
10
|
/**
|
|
11
11
|
* Dependencies for source handlers
|
|
12
12
|
*/
|
|
@@ -24,50 +24,116 @@ export type SourceHandlers = ReturnType<typeof createSourceHandlers>;
|
|
|
24
24
|
export declare function createSourceHandlers(deps: SourceHandlerDependencies): {
|
|
25
25
|
handleListSources: (args: {
|
|
26
26
|
notebook_id?: string;
|
|
27
|
-
}, sendProgress?: ProgressCallback) => Promise<
|
|
27
|
+
}, sendProgress?: ProgressCallback) => Promise<{
|
|
28
|
+
success: boolean;
|
|
29
|
+
error: string;
|
|
30
|
+
notebookId?: undefined;
|
|
31
|
+
sources?: undefined;
|
|
32
|
+
method?: undefined;
|
|
33
|
+
} | {
|
|
34
|
+
success: boolean;
|
|
35
|
+
error: string;
|
|
36
|
+
notebookId: string | null;
|
|
37
|
+
sources?: undefined;
|
|
38
|
+
method?: undefined;
|
|
39
|
+
} | {
|
|
28
40
|
success: boolean;
|
|
29
41
|
sources: {
|
|
30
42
|
title: string;
|
|
31
43
|
id: string | undefined;
|
|
32
44
|
}[];
|
|
33
45
|
method: string;
|
|
46
|
+
notebookId: string | null;
|
|
47
|
+
error?: undefined;
|
|
34
48
|
}>;
|
|
35
49
|
handleAddURLSource: (args: {
|
|
36
50
|
notebook_id?: string;
|
|
37
51
|
url: string;
|
|
38
|
-
}, sendProgress?: ProgressCallback) => Promise<
|
|
52
|
+
}, sendProgress?: ProgressCallback) => Promise<{
|
|
39
53
|
success: boolean;
|
|
40
|
-
|
|
54
|
+
error: string;
|
|
55
|
+
notebookId: string | null;
|
|
56
|
+
method?: undefined;
|
|
57
|
+
} | {
|
|
58
|
+
success: boolean;
|
|
59
|
+
notebookId: string | null;
|
|
41
60
|
method: string;
|
|
61
|
+
error?: undefined;
|
|
42
62
|
}>;
|
|
43
63
|
handleAddTextSource: (args: {
|
|
44
64
|
notebook_id?: string;
|
|
45
65
|
title: string;
|
|
46
66
|
content: string;
|
|
47
|
-
}, sendProgress?: ProgressCallback) => Promise<
|
|
67
|
+
}, sendProgress?: ProgressCallback) => Promise<{
|
|
68
|
+
success: boolean;
|
|
69
|
+
error: string;
|
|
70
|
+
notebookId: string | null;
|
|
71
|
+
method?: undefined;
|
|
72
|
+
} | {
|
|
48
73
|
success: boolean;
|
|
49
|
-
notebookId: string;
|
|
74
|
+
notebookId: string | null;
|
|
50
75
|
method: string;
|
|
76
|
+
error?: undefined;
|
|
51
77
|
}>;
|
|
52
78
|
handleAddYouTubeSource: (args: {
|
|
53
79
|
notebook_id?: string;
|
|
54
80
|
youtube_url: string;
|
|
55
|
-
}, sendProgress?: ProgressCallback) => Promise<
|
|
81
|
+
}, sendProgress?: ProgressCallback) => Promise<{
|
|
56
82
|
success: boolean;
|
|
57
|
-
|
|
83
|
+
error: string;
|
|
84
|
+
notebookId: string | null;
|
|
85
|
+
method?: undefined;
|
|
86
|
+
} | {
|
|
87
|
+
success: boolean;
|
|
88
|
+
notebookId: string | null;
|
|
58
89
|
method: string;
|
|
90
|
+
error?: undefined;
|
|
59
91
|
}>;
|
|
60
92
|
handleAddDriveSource: (args: {
|
|
61
93
|
notebook_id?: string;
|
|
62
94
|
file_id: string;
|
|
63
|
-
}, sendProgress?: ProgressCallback) => Promise<
|
|
95
|
+
}, sendProgress?: ProgressCallback) => Promise<{
|
|
96
|
+
notebookId: string | null;
|
|
97
|
+
success: boolean;
|
|
98
|
+
sources?: import("../../api/types.js").APISource[];
|
|
99
|
+
source?: import("../../api/types.js").APISource;
|
|
100
|
+
sourceId?: string;
|
|
101
|
+
error?: string;
|
|
102
|
+
}>;
|
|
64
103
|
handleDeleteSource: (args: {
|
|
65
104
|
notebook_id?: string;
|
|
66
105
|
source_id: string;
|
|
67
|
-
}, sendProgress?: ProgressCallback) => Promise<
|
|
106
|
+
}, sendProgress?: ProgressCallback) => Promise<{
|
|
107
|
+
success: boolean;
|
|
108
|
+
error: string;
|
|
109
|
+
notebookId: string | undefined;
|
|
110
|
+
method?: undefined;
|
|
111
|
+
} | {
|
|
112
|
+
success: boolean;
|
|
113
|
+
notebookId: string | undefined;
|
|
114
|
+
method: string;
|
|
115
|
+
error?: undefined;
|
|
116
|
+
}>;
|
|
68
117
|
handleSummarizeSource: (args: {
|
|
69
118
|
notebook_id?: string;
|
|
70
119
|
source_id: string;
|
|
71
|
-
}, sendProgress?: ProgressCallback) => Promise<
|
|
120
|
+
}, sendProgress?: ProgressCallback) => Promise<{
|
|
121
|
+
success: boolean;
|
|
122
|
+
error: string;
|
|
123
|
+
notebookId: string | undefined;
|
|
124
|
+
source?: undefined;
|
|
125
|
+
method?: undefined;
|
|
126
|
+
} | {
|
|
127
|
+
success: boolean;
|
|
128
|
+
source: {
|
|
129
|
+
title: string;
|
|
130
|
+
type?: string;
|
|
131
|
+
addedDate?: string;
|
|
132
|
+
summary?: string;
|
|
133
|
+
};
|
|
134
|
+
notebookId: string | undefined;
|
|
135
|
+
method: string;
|
|
136
|
+
error?: undefined;
|
|
137
|
+
}>;
|
|
72
138
|
};
|
|
73
139
|
//# sourceMappingURL=source-handlers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-handlers.d.ts","sourceRoot":"","sources":["../../../src/tools/handlers/source-handlers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"source-handlers.d.ts","sourceRoot":"","sources":["../../../src/tools/handlers/source-handlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIvD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACtC,OAAO,EAAE,eAAe,CAAC;IACzB,cAAc,CAAC,EAAE,cAAc,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAErE;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,yBAAyB;8BAwEtD;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,iBACf,gBAAgB;;;;;;;;;;;;;;;;;;;;;;+BA6CzB;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,iBAC5B,gBAAgB;;;;;;;;;;;gCAmCzB;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,iBAC/C,gBAAgB;;;;;;;;;;;mCAmCzB;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,iBACpC,gBAAgB;;;;;;;;;;;iCAmCzB;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,iBAChC,gBAAgB;;;;;;;;+BAyBzB;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,iBAClC,gBAAgB;;;;;;;;;;;kCA6CzB;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,iBAClC,gBAAgB;;;;;;;;;;;;;;;;;;EAwDtC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Source Management Tool Handlers
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Browser-only implementations for source management.
|
|
5
|
+
* Only addDriveSource uses API (requires Drive picker).
|
|
5
6
|
*/
|
|
6
7
|
import { log } from '../../utils/logger.js';
|
|
7
8
|
import * as sourceOps from '../../operations/source-operations.js';
|
|
@@ -11,261 +12,293 @@ import * as sourceOps from '../../operations/source-operations.js';
|
|
|
11
12
|
export function createSourceHandlers(deps) {
|
|
12
13
|
const { library, sessionManager } = deps;
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
+
* UUID regex pattern
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
18
|
+
/**
|
|
19
|
+
* Extract notebook UUID from URL
|
|
20
|
+
*/
|
|
21
|
+
function extractUuidFromUrl(url) {
|
|
22
|
+
const match = url.match(/\/notebook\/([0-9a-f-]{36})/i);
|
|
23
|
+
return match ? match[1] : null;
|
|
18
24
|
}
|
|
19
25
|
/**
|
|
20
|
-
*
|
|
26
|
+
* Resolve notebook to full URL (browser needs full URL)
|
|
21
27
|
*/
|
|
22
|
-
function
|
|
28
|
+
function resolveNotebookUrl(notebookId) {
|
|
29
|
+
// If UUID provided directly, build URL
|
|
30
|
+
if (notebookId && UUID_PATTERN.test(notebookId)) {
|
|
31
|
+
return `https://notebooklm.google.com/notebook/${notebookId}`;
|
|
32
|
+
}
|
|
33
|
+
// Get notebook from library (by alias or active)
|
|
34
|
+
const notebook = notebookId
|
|
35
|
+
? library.getNotebook(notebookId)
|
|
36
|
+
: library.getActiveNotebook();
|
|
37
|
+
if (!notebook) {
|
|
38
|
+
log.warning('No notebook specified and no active notebook selected');
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return notebook.url;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get notebook alias for user-facing responses
|
|
45
|
+
*/
|
|
46
|
+
function resolveNotebookAlias(notebookId) {
|
|
23
47
|
if (notebookId) {
|
|
48
|
+
const notebook = library.getNotebook(notebookId);
|
|
49
|
+
return notebook?.id || notebookId;
|
|
50
|
+
}
|
|
51
|
+
return library.getActiveNotebook()?.id || null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve notebook ID to UUID (for API calls)
|
|
55
|
+
*/
|
|
56
|
+
function resolveNotebookUuid(notebookId) {
|
|
57
|
+
if (notebookId && UUID_PATTERN.test(notebookId)) {
|
|
24
58
|
return notebookId;
|
|
25
59
|
}
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
60
|
+
const notebook = notebookId
|
|
61
|
+
? library.getNotebook(notebookId)
|
|
62
|
+
: library.getActiveNotebook();
|
|
63
|
+
if (!notebook) {
|
|
29
64
|
return null;
|
|
30
65
|
}
|
|
31
|
-
return
|
|
66
|
+
return extractUuidFromUrl(notebook.url);
|
|
32
67
|
}
|
|
33
68
|
/**
|
|
34
|
-
* Handle list_sources tool
|
|
69
|
+
* Handle list_sources tool (browser-only)
|
|
35
70
|
*/
|
|
36
71
|
async function handleListSources(args, sendProgress) {
|
|
37
|
-
const
|
|
38
|
-
|
|
72
|
+
const notebookUrl = resolveNotebookUrl(args.notebook_id);
|
|
73
|
+
const notebookAlias = resolveNotebookAlias(args.notebook_id);
|
|
74
|
+
if (!notebookUrl) {
|
|
39
75
|
return {
|
|
40
76
|
success: false,
|
|
41
77
|
error: 'No notebook specified and no active notebook selected',
|
|
42
78
|
};
|
|
43
79
|
}
|
|
44
|
-
if (
|
|
45
|
-
|
|
80
|
+
if (!sessionManager) {
|
|
81
|
+
return {
|
|
82
|
+
success: false,
|
|
83
|
+
error: 'Browser session manager not available',
|
|
84
|
+
notebookId: notebookAlias,
|
|
85
|
+
};
|
|
46
86
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
await sendProgress(`✅ Found ${sources.length} sources via browser`);
|
|
62
|
-
}
|
|
63
|
-
return {
|
|
64
|
-
success: true,
|
|
65
|
-
sources: sources.map(s => ({
|
|
66
|
-
title: s.title,
|
|
67
|
-
id: s.id,
|
|
68
|
-
})),
|
|
69
|
-
method: 'browser',
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
catch (browserError) {
|
|
73
|
-
log.error(`❌ Browser fallback failed: ${browserError}`);
|
|
74
|
-
}
|
|
87
|
+
if (sendProgress)
|
|
88
|
+
await sendProgress('Listing sources via browser...');
|
|
89
|
+
try {
|
|
90
|
+
const session = await sessionManager.getOrCreateSession(undefined, notebookUrl);
|
|
91
|
+
const sources = await session.listSourcesViaUI();
|
|
92
|
+
log.success(`Found ${sources.length} sources via browser`);
|
|
93
|
+
if (sendProgress)
|
|
94
|
+
await sendProgress(`Found ${sources.length} sources`);
|
|
95
|
+
return {
|
|
96
|
+
success: true,
|
|
97
|
+
sources: sources.map(s => ({ title: s.title, id: s.id })),
|
|
98
|
+
method: 'browser',
|
|
99
|
+
notebookId: notebookAlias,
|
|
100
|
+
};
|
|
75
101
|
}
|
|
76
|
-
|
|
77
|
-
|
|
102
|
+
catch (error) {
|
|
103
|
+
log.error(`Browser failed: ${error}`);
|
|
104
|
+
return { success: false, error: `Browser failed: ${error}`, notebookId: notebookAlias };
|
|
78
105
|
}
|
|
79
|
-
return result;
|
|
80
106
|
}
|
|
81
107
|
/**
|
|
82
|
-
* Handle add_url_source tool
|
|
108
|
+
* Handle add_url_source tool (browser-only)
|
|
83
109
|
*/
|
|
84
110
|
async function handleAddURLSource(args, sendProgress) {
|
|
85
|
-
const
|
|
86
|
-
|
|
111
|
+
const notebookUrl = resolveNotebookUrl(args.notebook_id);
|
|
112
|
+
const notebookAlias = resolveNotebookAlias(args.notebook_id);
|
|
113
|
+
if (!notebookUrl || !sessionManager) {
|
|
87
114
|
return {
|
|
88
115
|
success: false,
|
|
89
|
-
error: 'No notebook specified
|
|
116
|
+
error: !notebookUrl ? 'No notebook specified' : 'Browser session not available',
|
|
117
|
+
notebookId: notebookAlias,
|
|
90
118
|
};
|
|
91
119
|
}
|
|
92
|
-
if (sendProgress)
|
|
93
|
-
await sendProgress(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
try {
|
|
104
|
-
const notebookUrl = buildNotebookUrl(notebookId);
|
|
105
|
-
const session = await sessionManager.getOrCreateSession(undefined, notebookUrl);
|
|
106
|
-
const browserSuccess = await session.addURLSourceViaUI(args.url);
|
|
107
|
-
if (browserSuccess) {
|
|
108
|
-
log.success('✅ URL source added via browser automation');
|
|
109
|
-
if (sendProgress) {
|
|
110
|
-
await sendProgress('✅ URL source added via browser');
|
|
111
|
-
}
|
|
112
|
-
return { success: true, notebookId, method: 'browser' };
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
catch (browserError) {
|
|
116
|
-
log.error(`❌ Browser fallback failed: ${browserError}`);
|
|
120
|
+
if (sendProgress)
|
|
121
|
+
await sendProgress(`Adding URL source: ${args.url}`);
|
|
122
|
+
try {
|
|
123
|
+
const session = await sessionManager.getOrCreateSession(undefined, notebookUrl);
|
|
124
|
+
const success = await session.addURLSourceViaUI(args.url);
|
|
125
|
+
if (success) {
|
|
126
|
+
log.success('URL source added via browser');
|
|
127
|
+
if (sendProgress)
|
|
128
|
+
await sendProgress('URL source added');
|
|
129
|
+
return { success: true, notebookId: notebookAlias, method: 'browser' };
|
|
117
130
|
}
|
|
131
|
+
return { success: false, error: 'Browser failed to add URL source', notebookId: notebookAlias };
|
|
118
132
|
}
|
|
119
|
-
|
|
120
|
-
|
|
133
|
+
catch (error) {
|
|
134
|
+
log.error(`Browser failed: ${error}`);
|
|
135
|
+
return { success: false, error: `Browser failed: ${error}`, notebookId: notebookAlias };
|
|
121
136
|
}
|
|
122
|
-
return result;
|
|
123
137
|
}
|
|
124
138
|
/**
|
|
125
|
-
* Handle add_text_source tool
|
|
139
|
+
* Handle add_text_source tool (browser-only)
|
|
126
140
|
*/
|
|
127
141
|
async function handleAddTextSource(args, sendProgress) {
|
|
128
|
-
const
|
|
129
|
-
|
|
142
|
+
const notebookUrl = resolveNotebookUrl(args.notebook_id);
|
|
143
|
+
const notebookAlias = resolveNotebookAlias(args.notebook_id);
|
|
144
|
+
if (!notebookUrl || !sessionManager) {
|
|
130
145
|
return {
|
|
131
146
|
success: false,
|
|
132
|
-
error: 'No notebook specified
|
|
147
|
+
error: !notebookUrl ? 'No notebook specified' : 'Browser session not available',
|
|
148
|
+
notebookId: notebookAlias,
|
|
133
149
|
};
|
|
134
150
|
}
|
|
135
|
-
if (sendProgress)
|
|
136
|
-
await sendProgress(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
try {
|
|
147
|
-
const notebookUrl = buildNotebookUrl(notebookId);
|
|
148
|
-
const session = await sessionManager.getOrCreateSession(undefined, notebookUrl);
|
|
149
|
-
const browserSuccess = await session.addTextSourceViaUI(args.title, args.content);
|
|
150
|
-
if (browserSuccess) {
|
|
151
|
-
log.success('✅ Text source added via browser automation');
|
|
152
|
-
if (sendProgress) {
|
|
153
|
-
await sendProgress('✅ Text source added via browser');
|
|
154
|
-
}
|
|
155
|
-
return { success: true, notebookId, method: 'browser' };
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
catch (browserError) {
|
|
159
|
-
log.error(`❌ Browser fallback failed: ${browserError}`);
|
|
151
|
+
if (sendProgress)
|
|
152
|
+
await sendProgress(`Adding text source: ${args.title}`);
|
|
153
|
+
try {
|
|
154
|
+
const session = await sessionManager.getOrCreateSession(undefined, notebookUrl);
|
|
155
|
+
const success = await session.addTextSourceViaUI(args.title, args.content);
|
|
156
|
+
if (success) {
|
|
157
|
+
log.success('Text source added via browser');
|
|
158
|
+
if (sendProgress)
|
|
159
|
+
await sendProgress('Text source added');
|
|
160
|
+
return { success: true, notebookId: notebookAlias, method: 'browser' };
|
|
160
161
|
}
|
|
162
|
+
return { success: false, error: 'Browser failed to add text source', notebookId: notebookAlias };
|
|
161
163
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
+
catch (error) {
|
|
165
|
+
log.error(`Browser failed: ${error}`);
|
|
166
|
+
return { success: false, error: `Browser failed: ${error}`, notebookId: notebookAlias };
|
|
164
167
|
}
|
|
165
|
-
return result;
|
|
166
168
|
}
|
|
167
169
|
/**
|
|
168
|
-
* Handle add_youtube_source tool
|
|
170
|
+
* Handle add_youtube_source tool (browser-only)
|
|
169
171
|
*/
|
|
170
172
|
async function handleAddYouTubeSource(args, sendProgress) {
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
+
const notebookUrl = resolveNotebookUrl(args.notebook_id);
|
|
174
|
+
const notebookAlias = resolveNotebookAlias(args.notebook_id);
|
|
175
|
+
if (!notebookUrl || !sessionManager) {
|
|
173
176
|
return {
|
|
174
177
|
success: false,
|
|
175
|
-
error: 'No notebook specified
|
|
178
|
+
error: !notebookUrl ? 'No notebook specified' : 'Browser session not available',
|
|
179
|
+
notebookId: notebookAlias,
|
|
176
180
|
};
|
|
177
181
|
}
|
|
178
|
-
if (sendProgress)
|
|
179
|
-
await sendProgress(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
try {
|
|
190
|
-
const notebookUrl = buildNotebookUrl(notebookId);
|
|
191
|
-
const session = await sessionManager.getOrCreateSession(undefined, notebookUrl);
|
|
192
|
-
const browserSuccess = await session.addYouTubeSourceViaUI(args.youtube_url);
|
|
193
|
-
if (browserSuccess) {
|
|
194
|
-
log.success('✅ YouTube source added via browser automation');
|
|
195
|
-
if (sendProgress) {
|
|
196
|
-
await sendProgress('✅ YouTube source added via browser');
|
|
197
|
-
}
|
|
198
|
-
return { success: true, notebookId, method: 'browser' };
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
catch (browserError) {
|
|
202
|
-
log.error(`❌ Browser fallback failed: ${browserError}`);
|
|
182
|
+
if (sendProgress)
|
|
183
|
+
await sendProgress(`Adding YouTube source: ${args.youtube_url}`);
|
|
184
|
+
try {
|
|
185
|
+
const session = await sessionManager.getOrCreateSession(undefined, notebookUrl);
|
|
186
|
+
const success = await session.addYouTubeSourceViaUI(args.youtube_url);
|
|
187
|
+
if (success) {
|
|
188
|
+
log.success('YouTube source added via browser');
|
|
189
|
+
if (sendProgress)
|
|
190
|
+
await sendProgress('YouTube source added');
|
|
191
|
+
return { success: true, notebookId: notebookAlias, method: 'browser' };
|
|
203
192
|
}
|
|
193
|
+
return { success: false, error: 'Browser failed to add YouTube source', notebookId: notebookAlias };
|
|
204
194
|
}
|
|
205
|
-
|
|
206
|
-
|
|
195
|
+
catch (error) {
|
|
196
|
+
log.error(`Browser failed: ${error}`);
|
|
197
|
+
return { success: false, error: `Browser failed: ${error}`, notebookId: notebookAlias };
|
|
207
198
|
}
|
|
208
|
-
return result;
|
|
209
199
|
}
|
|
210
200
|
/**
|
|
211
|
-
* Handle add_drive_source tool
|
|
201
|
+
* Handle add_drive_source tool (API-only - requires Drive picker)
|
|
212
202
|
*/
|
|
213
203
|
async function handleAddDriveSource(args, sendProgress) {
|
|
214
|
-
const
|
|
215
|
-
|
|
204
|
+
const notebookUuid = resolveNotebookUuid(args.notebook_id);
|
|
205
|
+
const notebookAlias = resolveNotebookAlias(args.notebook_id);
|
|
206
|
+
if (!notebookUuid) {
|
|
216
207
|
return {
|
|
217
208
|
success: false,
|
|
218
209
|
error: 'No notebook specified and no active notebook selected',
|
|
210
|
+
notebookId: notebookAlias,
|
|
219
211
|
};
|
|
220
212
|
}
|
|
221
|
-
if (sendProgress)
|
|
222
|
-
await sendProgress(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
return result;
|
|
213
|
+
if (sendProgress)
|
|
214
|
+
await sendProgress(`Adding Google Drive source: ${args.file_id}`);
|
|
215
|
+
const result = await sourceOps.addDriveSource(notebookUuid, args.file_id);
|
|
216
|
+
if (result.success && sendProgress)
|
|
217
|
+
await sendProgress('Google Drive source added');
|
|
218
|
+
return { ...result, notebookId: notebookAlias };
|
|
229
219
|
}
|
|
230
220
|
/**
|
|
231
|
-
* Handle delete_source tool
|
|
221
|
+
* Handle delete_source tool (browser-only)
|
|
232
222
|
*/
|
|
233
223
|
async function handleDeleteSource(args, sendProgress) {
|
|
234
|
-
const
|
|
235
|
-
|
|
224
|
+
const notebookUrl = resolveNotebookUrl(args.notebook_id);
|
|
225
|
+
const notebookAlias = resolveNotebookAlias(args.notebook_id);
|
|
226
|
+
if (!notebookUrl || !sessionManager) {
|
|
236
227
|
return {
|
|
237
228
|
success: false,
|
|
238
|
-
error: 'No notebook specified
|
|
229
|
+
error: !notebookUrl ? 'No notebook specified' : 'Browser session not available',
|
|
230
|
+
notebookId: notebookAlias ?? undefined,
|
|
239
231
|
};
|
|
240
232
|
}
|
|
241
|
-
if (sendProgress)
|
|
242
|
-
await sendProgress(
|
|
233
|
+
if (sendProgress)
|
|
234
|
+
await sendProgress(`Deleting source: ${args.source_id}`);
|
|
235
|
+
try {
|
|
236
|
+
const session = await sessionManager.getOrCreateSession(undefined, notebookUrl);
|
|
237
|
+
// source_id can be title or ID - use as title for browser
|
|
238
|
+
let sourceTitle = args.source_id;
|
|
239
|
+
// If it looks like an API source ID (sources/xxx), find the actual title
|
|
240
|
+
if (args.source_id.startsWith('sources/')) {
|
|
241
|
+
const sources = await session.listSourcesViaUI();
|
|
242
|
+
const match = sources.find(s => s.id?.includes(args.source_id.replace('sources/', '')));
|
|
243
|
+
if (match)
|
|
244
|
+
sourceTitle = match.title;
|
|
245
|
+
}
|
|
246
|
+
const success = await session.deleteSourceViaUI(sourceTitle, sendProgress);
|
|
247
|
+
if (success) {
|
|
248
|
+
log.success('Source deleted via browser');
|
|
249
|
+
return { success: true, notebookId: notebookAlias ?? undefined, method: 'browser' };
|
|
250
|
+
}
|
|
251
|
+
return { success: false, error: 'Failed to delete source', notebookId: notebookAlias ?? undefined };
|
|
243
252
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
253
|
+
catch (error) {
|
|
254
|
+
log.error(`Browser failed: ${error}`);
|
|
255
|
+
return { success: false, error: `Browser failed: ${error}`, notebookId: notebookAlias ?? undefined };
|
|
247
256
|
}
|
|
248
|
-
return result;
|
|
249
257
|
}
|
|
250
258
|
/**
|
|
251
|
-
* Handle summarize_source tool
|
|
259
|
+
* Handle summarize_source tool (browser-only)
|
|
252
260
|
*/
|
|
253
261
|
async function handleSummarizeSource(args, sendProgress) {
|
|
254
|
-
const
|
|
255
|
-
|
|
262
|
+
const notebookUrl = resolveNotebookUrl(args.notebook_id);
|
|
263
|
+
const notebookAlias = resolveNotebookAlias(args.notebook_id);
|
|
264
|
+
if (!notebookUrl || !sessionManager) {
|
|
256
265
|
return {
|
|
257
266
|
success: false,
|
|
258
|
-
error: 'No notebook specified
|
|
267
|
+
error: !notebookUrl ? 'No notebook specified' : 'Browser session not available',
|
|
268
|
+
notebookId: notebookAlias ?? undefined,
|
|
259
269
|
};
|
|
260
270
|
}
|
|
261
|
-
if (sendProgress)
|
|
262
|
-
await sendProgress(
|
|
271
|
+
if (sendProgress)
|
|
272
|
+
await sendProgress(`Getting source details: ${args.source_id}`);
|
|
273
|
+
try {
|
|
274
|
+
const session = await sessionManager.getOrCreateSession(undefined, notebookUrl);
|
|
275
|
+
// source_id can be title or ID - use as title for browser
|
|
276
|
+
let sourceTitle = args.source_id;
|
|
277
|
+
// If it looks like an API source ID (sources/xxx), find the actual title
|
|
278
|
+
if (args.source_id.startsWith('sources/')) {
|
|
279
|
+
const sources = await session.listSourcesViaUI();
|
|
280
|
+
const match = sources.find(s => s.id?.includes(args.source_id.replace('sources/', '')));
|
|
281
|
+
if (match)
|
|
282
|
+
sourceTitle = match.title;
|
|
283
|
+
}
|
|
284
|
+
const details = await session.getSourceDetailsViaUI(sourceTitle);
|
|
285
|
+
if (details) {
|
|
286
|
+
log.success('Source details retrieved via browser');
|
|
287
|
+
if (sendProgress)
|
|
288
|
+
await sendProgress('Source details retrieved');
|
|
289
|
+
return {
|
|
290
|
+
success: true,
|
|
291
|
+
source: details,
|
|
292
|
+
notebookId: notebookAlias ?? undefined,
|
|
293
|
+
method: 'browser',
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
return { success: false, error: 'Source not found', notebookId: notebookAlias ?? undefined };
|
|
263
297
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
298
|
+
catch (error) {
|
|
299
|
+
log.error(`Browser failed: ${error}`);
|
|
300
|
+
return { success: false, error: `Browser failed: ${error}`, notebookId: notebookAlias ?? undefined };
|
|
267
301
|
}
|
|
268
|
-
return result;
|
|
269
302
|
}
|
|
270
303
|
return {
|
|
271
304
|
handleListSources,
|