opencodekit 0.15.18 → 0.15.20
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/index.js +16 -16
- package/dist/template/.opencode/memory/observations/2026-01-30-decision-github-copilot-claude-routing-keep-disab.md +32 -0
- package/dist/template/.opencode/memory/observations/2026-01-30-discovery-context-management-research-critical-gap.md +14 -0
- package/dist/template/.opencode/memory/observations/2026-01-31-decision-copilot-auth-plugin-updated-with-baseurl.md +63 -0
- package/dist/template/.opencode/memory/observations/2026-01-31-learning-opencode-copilot-auth-comparison-finding.md +61 -0
- package/dist/template/.opencode/memory/observations/2026-01-31-learning-opencode-copilot-reasoning-architecture-.md +66 -0
- package/dist/template/.opencode/memory/observations/2026-01-31-warning-copilot-claude-v1-endpoint-returns-404-c.md +48 -0
- package/dist/template/.opencode/memory/research/context-management-analysis.md +685 -0
- package/dist/template/.opencode/opencode.json +52 -156
- package/dist/template/.opencode/package.json +1 -1
- package/dist/template/.opencode/plugins/copilot-auth.ts +286 -29
- package/dist/template/.opencode/plugins/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +181 -0
- package/dist/template/.opencode/plugins/sdk/copilot/chat/get-response-metadata.ts +15 -0
- package/dist/template/.opencode/plugins/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +19 -0
- package/dist/template/.opencode/plugins/sdk/copilot/chat/openai-compatible-api-types.ts +72 -0
- package/dist/template/.opencode/plugins/sdk/copilot/chat/openai-compatible-chat-language-model.ts +823 -0
- package/dist/template/.opencode/plugins/sdk/copilot/chat/openai-compatible-chat-options.ts +30 -0
- package/dist/template/.opencode/plugins/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +48 -0
- package/dist/template/.opencode/plugins/sdk/copilot/chat/openai-compatible-prepare-tools.ts +92 -0
- package/dist/template/.opencode/plugins/sdk/copilot/copilot-provider.ts +94 -0
- package/dist/template/.opencode/plugins/sdk/copilot/index.ts +5 -0
- package/dist/template/.opencode/plugins/sdk/copilot/openai-compatible-error.ts +30 -0
- package/dist/template/.opencode/skills/notebooklm/SKILL.md +272 -0
- package/dist/template/.opencode/skills/notebooklm/references/setup.md +353 -0
- package/dist/template/.opencode/tools/notebooklm.ts +488 -0
- package/package.json +1 -1
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NotebookLM Tool for OpenCodeKit
|
|
3
|
+
*
|
|
4
|
+
* Wraps the Python NotebookLM skill for querying Google NotebookLM notebooks.
|
|
5
|
+
* Auto-clones the skill repository and manages the Python virtual environment.
|
|
6
|
+
*
|
|
7
|
+
* @module notebooklm
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
import { $ } from "bun";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Logger interface for OpenCode client app logging
|
|
16
|
+
* Falls back to console if client logger not available
|
|
17
|
+
*/
|
|
18
|
+
interface Logger {
|
|
19
|
+
debug: (message: string, extra?: Record<string, unknown>) => void;
|
|
20
|
+
info: (message: string, extra?: Record<string, unknown>) => void;
|
|
21
|
+
warn: (message: string, extra?: Record<string, unknown>) => void;
|
|
22
|
+
error: (message: string, extra?: Record<string, unknown>) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create a logger that uses OpenCode client.app.log() when available,
|
|
27
|
+
* otherwise falls back to console
|
|
28
|
+
*/
|
|
29
|
+
function createLogger(client?: {
|
|
30
|
+
app: {
|
|
31
|
+
log: (log: {
|
|
32
|
+
service: string;
|
|
33
|
+
level: "debug" | "info" | "warn" | "error";
|
|
34
|
+
message: string;
|
|
35
|
+
extra?: Record<string, unknown>;
|
|
36
|
+
}) => Promise<void>;
|
|
37
|
+
};
|
|
38
|
+
}): Logger {
|
|
39
|
+
const service = "notebooklm";
|
|
40
|
+
|
|
41
|
+
if (client?.app?.log) {
|
|
42
|
+
// Use OpenCode client logging
|
|
43
|
+
return {
|
|
44
|
+
debug: (message: string, extra?: Record<string, unknown>) => {
|
|
45
|
+
client.app
|
|
46
|
+
.log({ service, level: "debug", message, extra })
|
|
47
|
+
.catch(() => {});
|
|
48
|
+
},
|
|
49
|
+
info: (message: string, extra?: Record<string, unknown>) => {
|
|
50
|
+
client.app
|
|
51
|
+
.log({ service, level: "info", message, extra })
|
|
52
|
+
.catch(() => {});
|
|
53
|
+
},
|
|
54
|
+
warn: (message: string, extra?: Record<string, unknown>) => {
|
|
55
|
+
client.app
|
|
56
|
+
.log({ service, level: "warn", message, extra })
|
|
57
|
+
.catch(() => {});
|
|
58
|
+
},
|
|
59
|
+
error: (message: string, extra?: Record<string, unknown>) => {
|
|
60
|
+
client.app
|
|
61
|
+
.log({ service, level: "error", message, extra })
|
|
62
|
+
.catch(() => {});
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Fallback to console
|
|
68
|
+
return {
|
|
69
|
+
debug: (message: string, extra?: Record<string, unknown>) => {
|
|
70
|
+
console.log(`[DEBUG] ${message}`, extra ? JSON.stringify(extra) : "");
|
|
71
|
+
},
|
|
72
|
+
info: (message: string, extra?: Record<string, unknown>) => {
|
|
73
|
+
console.log(`[INFO] ${message}`, extra ? JSON.stringify(extra) : "");
|
|
74
|
+
},
|
|
75
|
+
warn: (message: string, extra?: Record<string, unknown>) => {
|
|
76
|
+
console.warn(`[WARN] ${message}`, extra ? JSON.stringify(extra) : "");
|
|
77
|
+
},
|
|
78
|
+
error: (message: string, extra?: Record<string, unknown>) => {
|
|
79
|
+
console.error(`[ERROR] ${message}`, extra ? JSON.stringify(extra) : "");
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Global logger instance (will be initialized with client if available)
|
|
85
|
+
let globalLogger: Logger = createLogger();
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Set the logger instance (called by plugin initialization)
|
|
89
|
+
*/
|
|
90
|
+
export function setNotebookLMLogger(client?: {
|
|
91
|
+
app: {
|
|
92
|
+
log: (log: {
|
|
93
|
+
service: string;
|
|
94
|
+
level: "debug" | "info" | "warn" | "error";
|
|
95
|
+
message: string;
|
|
96
|
+
extra?: Record<string, unknown>;
|
|
97
|
+
}) => Promise<void>;
|
|
98
|
+
};
|
|
99
|
+
}): void {
|
|
100
|
+
globalLogger = createLogger(client);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Detect Python command (python or python3)
|
|
104
|
+
async function getPythonCommand(): Promise<string> {
|
|
105
|
+
try {
|
|
106
|
+
await $`python --version`.quiet();
|
|
107
|
+
return "python";
|
|
108
|
+
} catch {
|
|
109
|
+
try {
|
|
110
|
+
await $`python3 --version`.quiet();
|
|
111
|
+
return "python3";
|
|
112
|
+
} catch {
|
|
113
|
+
throw new Error("Python not found. Please install Python 3.10+");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Skill repository URL
|
|
119
|
+
const SKILL_REPO = "https://github.com/PleasePrompto/notebooklm-skill";
|
|
120
|
+
|
|
121
|
+
// Skill installation directory
|
|
122
|
+
const SKILL_DIR = join(homedir(), ".opencode", "skills", "notebooklm");
|
|
123
|
+
|
|
124
|
+
// Scripts directory
|
|
125
|
+
const SCRIPTS_DIR = join(SKILL_DIR, "scripts");
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Input parameters for notebooklm tool
|
|
129
|
+
*/
|
|
130
|
+
export interface NotebookLMInput {
|
|
131
|
+
/** Operation to perform */
|
|
132
|
+
operation: "auth" | "query" | "library" | "setup";
|
|
133
|
+
|
|
134
|
+
/** Sub-operation for auth and library operations */
|
|
135
|
+
subOperation?:
|
|
136
|
+
| "setup"
|
|
137
|
+
| "status"
|
|
138
|
+
| "reauth"
|
|
139
|
+
| "clear"
|
|
140
|
+
| "validate"
|
|
141
|
+
| "add"
|
|
142
|
+
| "list"
|
|
143
|
+
| "search"
|
|
144
|
+
| "activate"
|
|
145
|
+
| "remove"
|
|
146
|
+
| "stats";
|
|
147
|
+
|
|
148
|
+
/** Question to ask (for query operation) */
|
|
149
|
+
question?: string;
|
|
150
|
+
|
|
151
|
+
/** Notebook URL (for add or query operations) */
|
|
152
|
+
notebookUrl?: string;
|
|
153
|
+
|
|
154
|
+
/** Notebook ID from library (for query or activate operations) */
|
|
155
|
+
notebookId?: string;
|
|
156
|
+
|
|
157
|
+
/** Notebook name (for add operation) */
|
|
158
|
+
name?: string;
|
|
159
|
+
|
|
160
|
+
/** Notebook description (for add operation) */
|
|
161
|
+
description?: string;
|
|
162
|
+
|
|
163
|
+
/** Topics/tags (for add operation) - array or comma-separated string */
|
|
164
|
+
topics?: string[] | string;
|
|
165
|
+
|
|
166
|
+
/** Search query (for library search) */
|
|
167
|
+
query?: string;
|
|
168
|
+
|
|
169
|
+
/** Show browser window (for auth setup or debugging) */
|
|
170
|
+
showBrowser?: boolean;
|
|
171
|
+
|
|
172
|
+
/** Timeout in minutes for authentication */
|
|
173
|
+
timeout?: number;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Result from notebooklm operation
|
|
178
|
+
*/
|
|
179
|
+
export interface NotebookLMResult {
|
|
180
|
+
/** Whether the operation succeeded */
|
|
181
|
+
success: boolean;
|
|
182
|
+
|
|
183
|
+
/** Output from the operation */
|
|
184
|
+
output: string;
|
|
185
|
+
|
|
186
|
+
/** Error message if failed */
|
|
187
|
+
error?: string;
|
|
188
|
+
|
|
189
|
+
/** Parsed data (for library operations) */
|
|
190
|
+
data?: unknown;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Ensure Python virtual environment is set up with dependencies
|
|
195
|
+
*/
|
|
196
|
+
async function ensureVirtualEnv(): Promise<void> {
|
|
197
|
+
const venvPath = join(SKILL_DIR, ".venv");
|
|
198
|
+
const venvPython = join(venvPath, "bin", "python");
|
|
199
|
+
const venvPip = join(venvPath, "bin", "pip");
|
|
200
|
+
|
|
201
|
+
// Check if venv exists with pip
|
|
202
|
+
const venvExists = await Bun.file(venvPython).exists();
|
|
203
|
+
const pipExists = await Bun.file(venvPip).exists();
|
|
204
|
+
|
|
205
|
+
if (venvExists && pipExists) {
|
|
206
|
+
// Check if patchright is installed
|
|
207
|
+
const checkResult =
|
|
208
|
+
await $`cd ${SKILL_DIR} && .venv/bin/python -c "import patchright" 2>&1`.nothrow();
|
|
209
|
+
if (checkResult.exitCode === 0) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
globalLogger.info("Setting up Python virtual environment...");
|
|
215
|
+
|
|
216
|
+
const pythonCmd = await getPythonCommand();
|
|
217
|
+
|
|
218
|
+
// Remove broken venv if exists
|
|
219
|
+
if (venvExists && !pipExists) {
|
|
220
|
+
globalLogger.warn("Removing incomplete virtual environment...");
|
|
221
|
+
await $`cd ${SKILL_DIR} && rm -rf .venv`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Create virtual environment with pip
|
|
225
|
+
globalLogger.info("Creating virtual environment...");
|
|
226
|
+
const venvResult =
|
|
227
|
+
await $`cd ${SKILL_DIR} && ${pythonCmd} -m venv .venv --without-pip`.nothrow();
|
|
228
|
+
if (venvResult.exitCode !== 0) {
|
|
229
|
+
throw new Error(
|
|
230
|
+
`Failed to create virtual environment: ${venvResult.stderr}`,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Install pip manually
|
|
235
|
+
globalLogger.info("Installing pip...");
|
|
236
|
+
const pipInstallResult =
|
|
237
|
+
await $`cd ${SKILL_DIR} && .venv/bin/python -m ensurepip --upgrade`.nothrow();
|
|
238
|
+
if (pipInstallResult.exitCode !== 0) {
|
|
239
|
+
// Try alternative method
|
|
240
|
+
await $`cd ${SKILL_DIR} && curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && .venv/bin/python get-pip.py && rm get-pip.py`.nothrow();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Install dependencies
|
|
244
|
+
globalLogger.info("Installing dependencies (this may take a minute)...");
|
|
245
|
+
const pipResult =
|
|
246
|
+
await $`cd ${SKILL_DIR} && .venv/bin/python -m pip install -r requirements.txt`.nothrow();
|
|
247
|
+
if (pipResult.exitCode !== 0) {
|
|
248
|
+
throw new Error(`Failed to install dependencies: ${pipResult.stderr}`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Install patchright browser
|
|
252
|
+
globalLogger.info("Installing browser automation...");
|
|
253
|
+
const browserResult =
|
|
254
|
+
await $`cd ${SKILL_DIR} && .venv/bin/python -m patchright install chromium`.nothrow();
|
|
255
|
+
if (browserResult.exitCode !== 0) {
|
|
256
|
+
globalLogger.warn("Browser install may have issues, but continuing...");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
globalLogger.info("Virtual environment ready");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Ensure the NotebookLM skill is installed
|
|
264
|
+
*/
|
|
265
|
+
async function ensureSkillInstalled(): Promise<void> {
|
|
266
|
+
const runPyPath = join(SCRIPTS_DIR, "run.py");
|
|
267
|
+
|
|
268
|
+
// Check if skill is already installed
|
|
269
|
+
const exists = await Bun.file(runPyPath).exists();
|
|
270
|
+
if (exists) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
globalLogger.info("NotebookLM skill not found. Installing...");
|
|
275
|
+
|
|
276
|
+
// Create parent directory
|
|
277
|
+
const parentDir = join(homedir(), ".opencode", "skills");
|
|
278
|
+
await $`mkdir -p ${parentDir}`;
|
|
279
|
+
|
|
280
|
+
// Clone the repository
|
|
281
|
+
globalLogger.info(`Cloning from ${SKILL_REPO}...`);
|
|
282
|
+
const result =
|
|
283
|
+
await $`cd ${parentDir} && git clone ${SKILL_REPO} notebooklm`.quiet();
|
|
284
|
+
|
|
285
|
+
if (result.exitCode !== 0) {
|
|
286
|
+
throw new Error(`Failed to clone NotebookLM skill: ${result.stderr}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
globalLogger.info("Skill installed successfully", { location: SKILL_DIR });
|
|
290
|
+
|
|
291
|
+
// Set up virtual environment
|
|
292
|
+
await ensureVirtualEnv();
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Build command arguments for run.py wrapper
|
|
297
|
+
*/
|
|
298
|
+
function buildCommandArgs(input: NotebookLMInput): string[] {
|
|
299
|
+
const args: string[] = [];
|
|
300
|
+
|
|
301
|
+
switch (input.operation) {
|
|
302
|
+
case "auth":
|
|
303
|
+
args.push(input.subOperation || "status");
|
|
304
|
+
|
|
305
|
+
if (input.subOperation === "setup" || input.subOperation === "reauth") {
|
|
306
|
+
if (!input.showBrowser) {
|
|
307
|
+
args.push("--headless");
|
|
308
|
+
}
|
|
309
|
+
if (input.timeout) {
|
|
310
|
+
args.push("--timeout", String(input.timeout));
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
break;
|
|
314
|
+
|
|
315
|
+
case "library":
|
|
316
|
+
args.push(input.subOperation || "list");
|
|
317
|
+
|
|
318
|
+
if (input.subOperation === "add") {
|
|
319
|
+
if (input.notebookUrl) args.push("--url", input.notebookUrl);
|
|
320
|
+
if (input.name) args.push("--name", input.name);
|
|
321
|
+
if (input.description) args.push("--description", input.description);
|
|
322
|
+
if (input.topics) {
|
|
323
|
+
const topicsStr = Array.isArray(input.topics)
|
|
324
|
+
? input.topics.join(",")
|
|
325
|
+
: input.topics;
|
|
326
|
+
args.push("--topics", topicsStr);
|
|
327
|
+
}
|
|
328
|
+
} else if (input.subOperation === "search") {
|
|
329
|
+
if (input.query) args.push("--query", input.query);
|
|
330
|
+
} else if (
|
|
331
|
+
input.subOperation === "activate" ||
|
|
332
|
+
input.subOperation === "remove"
|
|
333
|
+
) {
|
|
334
|
+
if (input.notebookId) args.push("--id", input.notebookId);
|
|
335
|
+
}
|
|
336
|
+
break;
|
|
337
|
+
|
|
338
|
+
case "query":
|
|
339
|
+
// ask_question.py is passed as script parameter
|
|
340
|
+
|
|
341
|
+
if (input.question) {
|
|
342
|
+
args.push("--question", input.question);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (input.notebookUrl) {
|
|
346
|
+
args.push("--notebook-url", input.notebookUrl);
|
|
347
|
+
} else if (input.notebookId) {
|
|
348
|
+
args.push("--notebook-id", input.notebookId);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (input.showBrowser) {
|
|
352
|
+
args.push("--show-browser");
|
|
353
|
+
}
|
|
354
|
+
break;
|
|
355
|
+
|
|
356
|
+
case "setup":
|
|
357
|
+
// Setup is handled by ensureSkillInstalled
|
|
358
|
+
return [];
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return args;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Execute a NotebookLM operation
|
|
366
|
+
*/
|
|
367
|
+
async function executeOperation(
|
|
368
|
+
script: string,
|
|
369
|
+
args: string[],
|
|
370
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
371
|
+
const runPyPath = join(SCRIPTS_DIR, "run.py");
|
|
372
|
+
const venvPython = join(SKILL_DIR, ".venv", "bin", "python");
|
|
373
|
+
|
|
374
|
+
// Use venv python if available, otherwise fall back to system
|
|
375
|
+
const pythonCmd = (await Bun.file(venvPython).exists())
|
|
376
|
+
? venvPython
|
|
377
|
+
: await getPythonCommand();
|
|
378
|
+
|
|
379
|
+
// Build full command
|
|
380
|
+
const cmd = [pythonCmd, runPyPath, script, ...args];
|
|
381
|
+
|
|
382
|
+
globalLogger.debug(`Executing: ${cmd.join(" ")}`);
|
|
383
|
+
|
|
384
|
+
// Execute with Bun
|
|
385
|
+
const result = await $`cd ${SKILL_DIR} && ${cmd}`.nothrow();
|
|
386
|
+
|
|
387
|
+
return {
|
|
388
|
+
stdout: result.stdout.toString(),
|
|
389
|
+
stderr: result.stderr.toString(),
|
|
390
|
+
exitCode: result.exitCode,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Main notebooklm tool function
|
|
396
|
+
*
|
|
397
|
+
* @param input - Operation parameters
|
|
398
|
+
* @returns Result of the operation
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
* // Check authentication status
|
|
402
|
+
* const status = await notebooklm({ operation: "auth", subOperation: "status" });
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* // Query a notebook
|
|
406
|
+
* const answer = await notebooklm({
|
|
407
|
+
* operation: "query",
|
|
408
|
+
* question: "What are the key findings?",
|
|
409
|
+
* notebookId: "my-notebook"
|
|
410
|
+
* });
|
|
411
|
+
*/
|
|
412
|
+
export default async function notebooklm(
|
|
413
|
+
input: NotebookLMInput,
|
|
414
|
+
): Promise<NotebookLMResult> {
|
|
415
|
+
try {
|
|
416
|
+
// Ensure skill is installed
|
|
417
|
+
await ensureSkillInstalled();
|
|
418
|
+
|
|
419
|
+
// Ensure virtual environment is set up (for non-setup operations)
|
|
420
|
+
if (input.operation !== "setup") {
|
|
421
|
+
await ensureVirtualEnv();
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Handle setup operation (just verify installation)
|
|
425
|
+
if (input.operation === "setup") {
|
|
426
|
+
return {
|
|
427
|
+
success: true,
|
|
428
|
+
output: `NotebookLM skill installed at: ${SKILL_DIR}\n\nPrerequisites:\n- Python 3.10+ must be installed\n- Google Chrome must be installed\n- Run auth setup before querying`,
|
|
429
|
+
data: { skillDir: SKILL_DIR },
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Build command arguments
|
|
434
|
+
const args = buildCommandArgs(input);
|
|
435
|
+
|
|
436
|
+
// Determine which script to run
|
|
437
|
+
let script: string;
|
|
438
|
+
switch (input.operation) {
|
|
439
|
+
case "auth":
|
|
440
|
+
script = "auth_manager.py";
|
|
441
|
+
break;
|
|
442
|
+
case "library":
|
|
443
|
+
script = "notebook_manager.py";
|
|
444
|
+
break;
|
|
445
|
+
case "query":
|
|
446
|
+
script = "ask_question.py";
|
|
447
|
+
break;
|
|
448
|
+
default:
|
|
449
|
+
throw new Error(`Unknown operation: ${input.operation}`);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Execute the operation
|
|
453
|
+
globalLogger.info(
|
|
454
|
+
`NotebookLM: ${input.operation}${input.subOperation ? `/${input.subOperation}` : ""}`,
|
|
455
|
+
);
|
|
456
|
+
const result = await executeOperation(script, args);
|
|
457
|
+
|
|
458
|
+
// Parse result
|
|
459
|
+
const success = result.exitCode === 0;
|
|
460
|
+
|
|
461
|
+
// Try to parse JSON data from output (for library operations)
|
|
462
|
+
let data: unknown = undefined;
|
|
463
|
+
try {
|
|
464
|
+
// Look for JSON in the output
|
|
465
|
+
const jsonMatch = result.stdout.match(/\{[\s\S]*\}/);
|
|
466
|
+
if (jsonMatch) {
|
|
467
|
+
data = JSON.parse(jsonMatch[0]);
|
|
468
|
+
}
|
|
469
|
+
} catch {
|
|
470
|
+
// Not JSON, that's fine
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return {
|
|
474
|
+
success,
|
|
475
|
+
output: result.stdout || result.stderr,
|
|
476
|
+
error: success ? undefined : result.stderr,
|
|
477
|
+
data,
|
|
478
|
+
};
|
|
479
|
+
} catch (error) {
|
|
480
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
481
|
+
|
|
482
|
+
return {
|
|
483
|
+
success: false,
|
|
484
|
+
output: "",
|
|
485
|
+
error: errorMessage,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
}
|
package/package.json
CHANGED