agentxl 1.0.0 → 1.1.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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +352 -197
  3. package/bin/agentxl-folder-picker.exe +0 -0
  4. package/bin/agentxl.js +44 -8
  5. package/dist/agent/models.d.ts +9 -9
  6. package/dist/agent/models.d.ts.map +1 -1
  7. package/dist/agent/models.js +44 -8
  8. package/dist/agent/models.js.map +1 -1
  9. package/dist/agent/prompt/folder-context.d.ts +26 -0
  10. package/dist/agent/prompt/folder-context.d.ts.map +1 -0
  11. package/dist/agent/prompt/folder-context.js +105 -0
  12. package/dist/agent/prompt/folder-context.js.map +1 -0
  13. package/dist/agent/prompt/system-prompt.d.ts +21 -0
  14. package/dist/agent/prompt/system-prompt.d.ts.map +1 -0
  15. package/dist/agent/prompt/system-prompt.js +130 -0
  16. package/dist/agent/prompt/system-prompt.js.map +1 -0
  17. package/dist/agent/session.d.ts +10 -4
  18. package/dist/agent/session.d.ts.map +1 -1
  19. package/dist/agent/session.js +53 -15
  20. package/dist/agent/session.js.map +1 -1
  21. package/dist/agent/tools/excel.d.ts +24 -0
  22. package/dist/agent/tools/excel.d.ts.map +1 -0
  23. package/dist/agent/tools/excel.js +132 -0
  24. package/dist/agent/tools/excel.js.map +1 -0
  25. package/dist/server/document-converter.d.ts +71 -0
  26. package/dist/server/document-converter.d.ts.map +1 -0
  27. package/dist/server/document-converter.js +353 -0
  28. package/dist/server/document-converter.js.map +1 -0
  29. package/dist/server/excel-bridge.d.ts +38 -0
  30. package/dist/server/excel-bridge.d.ts.map +1 -0
  31. package/dist/server/excel-bridge.js +75 -0
  32. package/dist/server/excel-bridge.js.map +1 -0
  33. package/dist/server/folder-picker.d.ts +9 -0
  34. package/dist/server/folder-picker.d.ts.map +1 -0
  35. package/dist/server/folder-picker.js +204 -0
  36. package/dist/server/folder-picker.js.map +1 -0
  37. package/dist/server/folder-scanner.d.ts +43 -0
  38. package/dist/server/folder-scanner.d.ts.map +1 -0
  39. package/dist/server/folder-scanner.js +161 -0
  40. package/dist/server/folder-scanner.js.map +1 -0
  41. package/dist/server/http.d.ts +19 -0
  42. package/dist/server/http.d.ts.map +1 -0
  43. package/dist/server/http.js +62 -0
  44. package/dist/server/http.js.map +1 -0
  45. package/dist/server/index.d.ts +16 -4
  46. package/dist/server/index.d.ts.map +1 -1
  47. package/dist/server/index.js +70 -246
  48. package/dist/server/index.js.map +1 -1
  49. package/dist/server/json-store.d.ts +19 -0
  50. package/dist/server/json-store.d.ts.map +1 -0
  51. package/dist/server/json-store.js +37 -0
  52. package/dist/server/json-store.js.map +1 -0
  53. package/dist/server/routes/agent.d.ts +16 -0
  54. package/dist/server/routes/agent.d.ts.map +1 -0
  55. package/dist/server/routes/agent.js +196 -0
  56. package/dist/server/routes/agent.js.map +1 -0
  57. package/dist/server/routes/excel.d.ts +10 -0
  58. package/dist/server/routes/excel.d.ts.map +1 -0
  59. package/dist/server/routes/excel.js +41 -0
  60. package/dist/server/routes/excel.js.map +1 -0
  61. package/dist/server/routes/folder.d.ts +15 -0
  62. package/dist/server/routes/folder.d.ts.map +1 -0
  63. package/dist/server/routes/folder.js +184 -0
  64. package/dist/server/routes/folder.js.map +1 -0
  65. package/dist/server/routes/workbook.d.ts +7 -0
  66. package/dist/server/routes/workbook.d.ts.map +1 -0
  67. package/dist/server/routes/workbook.js +31 -0
  68. package/dist/server/routes/workbook.js.map +1 -0
  69. package/dist/server/static.d.ts +12 -0
  70. package/dist/server/static.d.ts.map +1 -0
  71. package/dist/server/static.js +83 -0
  72. package/dist/server/static.js.map +1 -0
  73. package/dist/server/workbook-folder-store.d.ts +24 -0
  74. package/dist/server/workbook-folder-store.d.ts.map +1 -0
  75. package/dist/server/workbook-folder-store.js +76 -0
  76. package/dist/server/workbook-folder-store.js.map +1 -0
  77. package/dist/server/workbook-identity.d.ts +8 -0
  78. package/dist/server/workbook-identity.d.ts.map +1 -0
  79. package/dist/server/workbook-identity.js +57 -0
  80. package/dist/server/workbook-identity.js.map +1 -0
  81. package/manifest/manifest-hosted.xml +107 -0
  82. package/package.json +24 -10
  83. package/taskpane/dist/assets/index-BnD8psE_.js +224 -0
  84. package/taskpane/dist/assets/index-BuAcDfRq.css +1 -0
  85. package/taskpane/dist/index.html +2 -2
  86. package/taskpane/dist/assets/index-6sMpIYxE.css +0 -1
  87. package/taskpane/dist/assets/index-DyLrQ3Aa.js +0 -164
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Document pre-converter — converts binary documents to readable Markdown.
3
+ *
4
+ * Runs at scan time (or on demand). Cached converted files live alongside
5
+ * the source files in a `.agentxl-cache/` directory inside the linked folder.
6
+ *
7
+ * PDF conversion strategy:
8
+ * 1. Try pdf-parse (fast, local, free) — extracts embedded text
9
+ * 2. Check if extracted text is meaningful (chars-per-page heuristic)
10
+ * 3. If scanned/image PDF → fall back to Mistral OCR API
11
+ *
12
+ * XLSX and DOCX are NOT pre-converted — the agent writes extraction code
13
+ * at runtime via bash, which is more powerful for structured data.
14
+ */
15
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync } from "fs";
16
+ import { join, dirname, basename, relative } from "path";
17
+ /** Name of the cache directory inside the linked folder. */
18
+ const CACHE_DIR = ".agentxl-cache";
19
+ /**
20
+ * Minimum average characters per page to consider text extraction successful.
21
+ * Below this threshold, the PDF is likely scanned/image-based and needs OCR.
22
+ */
23
+ const MIN_CHARS_PER_PAGE = 50;
24
+ /**
25
+ * Extract text from a PDF using pdf-parse (local, no API call).
26
+ * Returns null if the PDF has no meaningful embedded text.
27
+ */
28
+ async function extractPdfText(pdfPath) {
29
+ try {
30
+ const { PDFParse } = await import("pdf-parse");
31
+ const buffer = readFileSync(pdfPath);
32
+ const parser = new PDFParse({ data: new Uint8Array(buffer) });
33
+ const result = await parser.getText();
34
+ let title;
35
+ let author;
36
+ try {
37
+ const infoResult = await parser.getInfo();
38
+ const meta = infoResult?.info;
39
+ if (meta?.Title && typeof meta.Title === "string")
40
+ title = meta.Title;
41
+ if (meta?.Author && typeof meta.Author === "string")
42
+ author = meta.Author;
43
+ }
44
+ catch {
45
+ // Metadata is optional
46
+ }
47
+ await parser.destroy();
48
+ const cleanText = result.text.trim();
49
+ return {
50
+ text: cleanText,
51
+ pageCount: result.total,
52
+ title,
53
+ author,
54
+ };
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ }
60
+ /**
61
+ * Check if extracted text is meaningful (not just whitespace/control chars).
62
+ * Scanned PDFs often return empty or near-empty text.
63
+ */
64
+ function isTextMeaningful(text, pageCount) {
65
+ if (!text || pageCount === 0)
66
+ return false;
67
+ // Strip whitespace and control characters
68
+ const meaningful = text.replace(/[\s\x00-\x1f]/g, "");
69
+ const charsPerPage = meaningful.length / pageCount;
70
+ return charsPerPage >= MIN_CHARS_PER_PAGE;
71
+ }
72
+ /**
73
+ * Detect which OCR provider is available.
74
+ * Priority: Azure Mistral (enterprise) → direct Mistral → null
75
+ */
76
+ function getOcrConfig() {
77
+ // Azure Mistral (enterprise — Azure AI Services)
78
+ const azureEndpoint = process.env.AZURE_MISTRAL_ENDPOINT?.trim();
79
+ const azureKey = process.env.AZURE_MISTRAL_API_KEY?.trim();
80
+ if (azureEndpoint && azureKey) {
81
+ return { provider: "azure-mistral", endpoint: azureEndpoint, apiKey: azureKey };
82
+ }
83
+ // Direct Mistral API
84
+ const mistralKey = process.env.MISTRAL_API_KEY?.trim();
85
+ if (mistralKey) {
86
+ return { provider: "mistral", apiKey: mistralKey };
87
+ }
88
+ return null;
89
+ }
90
+ // ---------------------------------------------------------------------------
91
+ // Azure Mistral OCR
92
+ // ---------------------------------------------------------------------------
93
+ /**
94
+ * OCR a PDF using Azure-hosted Mistral OCR.
95
+ * Sends the PDF as a base64 data URL — no file upload step needed.
96
+ */
97
+ async function ocrWithAzureMistral(pdfPath, endpoint, apiKey) {
98
+ const buffer = readFileSync(pdfPath);
99
+ const base64 = buffer.toString("base64");
100
+ const dataUrl = `data:application/pdf;base64,${base64}`;
101
+ const response = await fetch(endpoint, {
102
+ method: "POST",
103
+ headers: {
104
+ "Content-Type": "application/json",
105
+ "api-key": apiKey,
106
+ },
107
+ body: JSON.stringify({
108
+ model: "mistral-ocr-latest",
109
+ document: {
110
+ type: "document_url",
111
+ document_url: dataUrl,
112
+ },
113
+ table_format: "markdown",
114
+ }),
115
+ });
116
+ if (!response.ok) {
117
+ const body = await response.text().catch(() => "");
118
+ throw new Error(`Azure Mistral OCR failed (${response.status}): ${body.slice(0, 200)}`);
119
+ }
120
+ const result = (await response.json());
121
+ return result.pages.map((p) => p.markdown).join("\n\n---\n\n");
122
+ }
123
+ // ---------------------------------------------------------------------------
124
+ // Direct Mistral OCR
125
+ // ---------------------------------------------------------------------------
126
+ /**
127
+ * OCR a PDF using Mistral's direct API.
128
+ * Uploads the file, runs OCR, returns markdown.
129
+ */
130
+ async function ocrWithDirectMistral(pdfPath, apiKey) {
131
+ const { Mistral } = await import("@mistralai/mistralai");
132
+ const client = new Mistral({ apiKey });
133
+ // Upload the PDF file
134
+ const buffer = readFileSync(pdfPath);
135
+ const fileName = basename(pdfPath);
136
+ const blob = new Blob([buffer], { type: "application/pdf" });
137
+ const file = new File([blob], fileName, { type: "application/pdf" });
138
+ const uploaded = await client.files.upload({
139
+ file,
140
+ purpose: "ocr",
141
+ });
142
+ // Run OCR
143
+ const ocrResult = await client.ocr.process({
144
+ model: "mistral-ocr-latest",
145
+ document: {
146
+ type: "file",
147
+ fileId: uploaded.id,
148
+ },
149
+ tableFormat: "markdown",
150
+ });
151
+ // Combine all pages into markdown
152
+ const pages = ocrResult.pages.map((page) => page.markdown);
153
+ // Clean up the uploaded file (best effort)
154
+ try {
155
+ await client.files.delete({ fileId: uploaded.id });
156
+ }
157
+ catch {
158
+ // Non-fatal
159
+ }
160
+ return pages.join("\n\n---\n\n");
161
+ }
162
+ // ---------------------------------------------------------------------------
163
+ // Unified OCR dispatcher
164
+ // ---------------------------------------------------------------------------
165
+ /**
166
+ * OCR a PDF using the best available provider.
167
+ */
168
+ async function ocrPdf(pdfPath) {
169
+ const config = getOcrConfig();
170
+ if (!config) {
171
+ throw new Error("No OCR provider configured. Scanned PDFs need Mistral OCR.\n" +
172
+ "Set AZURE_MISTRAL_ENDPOINT + AZURE_MISTRAL_API_KEY (Azure)\n" +
173
+ "or MISTRAL_API_KEY (direct) in .env to enable OCR.");
174
+ }
175
+ if (config.provider === "azure-mistral") {
176
+ return ocrWithAzureMistral(pdfPath, config.endpoint, config.apiKey);
177
+ }
178
+ return ocrWithDirectMistral(pdfPath, config.apiKey);
179
+ }
180
+ // ---------------------------------------------------------------------------
181
+ // PDF → Markdown (smart: text-first, OCR fallback)
182
+ // ---------------------------------------------------------------------------
183
+ /**
184
+ * Convert a single PDF to Markdown.
185
+ *
186
+ * Strategy:
187
+ * 1. Try local text extraction (pdf-parse) — fast, free
188
+ * 2. If text is empty/sparse → PDF is scanned → use Mistral OCR
189
+ * 3. If no Mistral key → return what we have with a warning
190
+ */
191
+ async function pdfToMarkdown(pdfPath) {
192
+ const fileName = basename(pdfPath);
193
+ // Step 1: Try local text extraction
194
+ const extraction = await extractPdfText(pdfPath);
195
+ if (extraction && isTextMeaningful(extraction.text, extraction.pageCount)) {
196
+ // Good text extraction — use it directly
197
+ return formatPdfMarkdown(fileName, extraction.text, extraction.pageCount, {
198
+ title: extraction.title,
199
+ author: extraction.author,
200
+ method: "text-extraction",
201
+ });
202
+ }
203
+ // Step 2: Text is empty/sparse — try OCR (Azure Mistral or direct Mistral)
204
+ const pageCount = extraction?.pageCount ?? 0;
205
+ const sparseText = extraction?.text ?? "";
206
+ try {
207
+ const ocrText = await ocrPdf(pdfPath);
208
+ const config = getOcrConfig();
209
+ return formatPdfMarkdown(fileName, ocrText, pageCount, {
210
+ title: extraction?.title,
211
+ author: extraction?.author,
212
+ method: config?.provider === "azure-mistral" ? "azure-mistral-ocr" : "mistral-ocr",
213
+ });
214
+ }
215
+ catch (err) {
216
+ const ocrError = err instanceof Error ? err.message : String(err);
217
+ // No OCR available — return whatever we got (possibly empty)
218
+ if (sparseText) {
219
+ return formatPdfMarkdown(fileName, sparseText, pageCount, {
220
+ title: extraction?.title,
221
+ author: extraction?.author,
222
+ method: "text-extraction (partial)",
223
+ warning: `This PDF appears to be scanned/image-based. Text extraction may be incomplete. OCR failed: ${ocrError}`,
224
+ });
225
+ }
226
+ return `# ${fileName}\n\n> ⚠️ This PDF is scanned/image-based and could not be read.\n> Text extraction returned no content.\n> OCR failed: ${ocrError}\n\nSet AZURE_MISTRAL_ENDPOINT + AZURE_MISTRAL_API_KEY or MISTRAL_API_KEY to enable OCR.`;
227
+ }
228
+ }
229
+ /**
230
+ * Format extracted PDF content as clean Markdown.
231
+ */
232
+ function formatPdfMarkdown(fileName, text, pageCount, opts) {
233
+ const lines = [
234
+ `# ${fileName}`,
235
+ "",
236
+ `> Extracted from PDF · ${pageCount} page${pageCount !== 1 ? "s" : ""} · ${opts.method}`,
237
+ "",
238
+ ];
239
+ if (opts.title)
240
+ lines.push(`**Title:** ${opts.title} `);
241
+ if (opts.author)
242
+ lines.push(`**Author:** ${opts.author} `);
243
+ if (opts.title || opts.author)
244
+ lines.push("");
245
+ if (opts.warning) {
246
+ lines.push(`> ⚠️ ${opts.warning}`, "");
247
+ }
248
+ lines.push("---", "", text.trim());
249
+ return lines.join("\n");
250
+ }
251
+ // ---------------------------------------------------------------------------
252
+ // Cache management
253
+ // ---------------------------------------------------------------------------
254
+ /**
255
+ * Get the cache path for a converted file.
256
+ * E.g., `subfolder/invoice.pdf` → `<folderRoot>/.agentxl-cache/subfolder/invoice.pdf.md`
257
+ */
258
+ function getCachePath(folderRoot, relativePath) {
259
+ return join(folderRoot, CACHE_DIR, `${relativePath}.md`);
260
+ }
261
+ /**
262
+ * Check if a cached conversion exists and is newer than the source file.
263
+ */
264
+ function isCacheValid(sourcePath, cachePath) {
265
+ if (!existsSync(cachePath))
266
+ return false;
267
+ try {
268
+ const sourceTime = statSync(sourcePath).mtimeMs;
269
+ const cacheTime = statSync(cachePath).mtimeMs;
270
+ return cacheTime >= sourceTime;
271
+ }
272
+ catch {
273
+ return false;
274
+ }
275
+ }
276
+ /**
277
+ * Pre-convert all PDFs in an inventory to Markdown.
278
+ * Skips files where the cache is still valid (source not modified).
279
+ *
280
+ * @param inventory - Folder inventory from scanner
281
+ * @returns Summary of conversion results
282
+ */
283
+ export async function convertDocuments(inventory) {
284
+ const result = {
285
+ converted: 0,
286
+ ocrConverted: 0,
287
+ cached: 0,
288
+ failed: 0,
289
+ errors: [],
290
+ };
291
+ const pdfs = inventory.files.filter((f) => f.extension === ".pdf" && f.supported);
292
+ if (pdfs.length === 0)
293
+ return result;
294
+ for (const file of pdfs) {
295
+ const cachePath = getCachePath(inventory.folderPath, file.relativePath);
296
+ // Skip if cache is still valid
297
+ if (isCacheValid(file.absolutePath, cachePath)) {
298
+ result.cached++;
299
+ continue;
300
+ }
301
+ try {
302
+ const markdown = await pdfToMarkdown(file.absolutePath);
303
+ // Detect which method was used
304
+ const usedOcr = markdown.includes("mistral-ocr");
305
+ // Ensure cache directory exists
306
+ const cacheDir = dirname(cachePath);
307
+ mkdirSync(cacheDir, { recursive: true });
308
+ writeFileSync(cachePath, markdown, "utf-8");
309
+ if (usedOcr) {
310
+ result.ocrConverted++;
311
+ }
312
+ else {
313
+ result.converted++;
314
+ }
315
+ }
316
+ catch (err) {
317
+ result.failed++;
318
+ result.errors.push(`${file.relativePath}: ${err instanceof Error ? err.message : String(err)}`);
319
+ }
320
+ }
321
+ return result;
322
+ }
323
+ /**
324
+ * Get the markdown path for a source file, if it has been converted.
325
+ * Returns null if no cached conversion exists.
326
+ */
327
+ export function getConvertedPath(folderRoot, relativePath) {
328
+ const cachePath = getCachePath(folderRoot, relativePath);
329
+ return existsSync(cachePath) ? cachePath : null;
330
+ }
331
+ /**
332
+ * Build a list of converted markdown files for agent context.
333
+ * Returns entries like: `invoice.pdf → .agentxl-cache/invoice.pdf.md`
334
+ */
335
+ export function listConvertedFiles(inventory) {
336
+ const entries = [];
337
+ for (const file of inventory.files) {
338
+ if (file.extension === ".pdf") {
339
+ const cachePath = getCachePath(inventory.folderPath, file.relativePath);
340
+ if (existsSync(cachePath)) {
341
+ const convertedRelative = relative(inventory.folderPath, cachePath).replace(/\\/g, "/");
342
+ entries.push({
343
+ source: file.relativePath,
344
+ converted: convertedRelative,
345
+ });
346
+ }
347
+ }
348
+ }
349
+ return entries;
350
+ }
351
+ // Exports for testing
352
+ export { isTextMeaningful, getOcrConfig, MIN_CHARS_PER_PAGE };
353
+ //# sourceMappingURL=document-converter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-converter.js","sourceRoot":"","sources":["../../src/server/document-converter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Excel execution bridge — bidirectional communication between
3
+ * server-side tool execution and browser-side Office.js.
4
+ *
5
+ * Flow:
6
+ * 1. Agent calls `excel` custom tool with Office.js code
7
+ * 2. Tool execute() registers a pending execution and waits
8
+ * 3. Pi SDK emits tool_execution_start SSE → taskpane receives it
9
+ * 4. Taskpane runs the code inside Excel.run() via Office.js
10
+ * 5. Taskpane POSTs result to /api/excel/result
11
+ * 6. Bridge resolves the pending promise → tool returns result to agent
12
+ */
13
+ /**
14
+ * Register a pending Excel execution and return a promise that resolves
15
+ * when the taskpane sends the result back.
16
+ *
17
+ * Called by the `excel` custom tool's execute function.
18
+ */
19
+ export declare function registerPendingExecution(toolCallId: string, timeoutMs?: number): Promise<string>;
20
+ /**
21
+ * Resolve a pending execution with a successful result.
22
+ * Called when the taskpane POSTs to /api/excel/result.
23
+ *
24
+ * @returns true if the execution was found and resolved.
25
+ */
26
+ export declare function resolveExecution(toolCallId: string, result: string): boolean;
27
+ /**
28
+ * Reject a pending execution with an error.
29
+ * Called when the taskpane reports an Office.js error.
30
+ *
31
+ * @returns true if the execution was found and rejected.
32
+ */
33
+ export declare function rejectExecution(toolCallId: string, errorMessage: string): boolean;
34
+ /** Get count of pending executions (for diagnostics). */
35
+ export declare function getPendingCount(): number;
36
+ /** Clear all pending executions (for cleanup/testing). */
37
+ export declare function clearAllPending(): void;
38
+ //# sourceMappingURL=excel-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excel-bridge.d.ts","sourceRoot":"","sources":["../../src/server/excel-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAcH;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAQT;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAQT;AAED,yDAAyD;AACzD,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,0DAA0D;AAC1D,wBAAgB,eAAe,IAAI,IAAI,CAMtC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Excel execution bridge — bidirectional communication between
3
+ * server-side tool execution and browser-side Office.js.
4
+ *
5
+ * Flow:
6
+ * 1. Agent calls `excel` custom tool with Office.js code
7
+ * 2. Tool execute() registers a pending execution and waits
8
+ * 3. Pi SDK emits tool_execution_start SSE → taskpane receives it
9
+ * 4. Taskpane runs the code inside Excel.run() via Office.js
10
+ * 5. Taskpane POSTs result to /api/excel/result
11
+ * 6. Bridge resolves the pending promise → tool returns result to agent
12
+ */
13
+ /** Default timeout for Excel execution (ms). */
14
+ const DEFAULT_TIMEOUT_MS = 30_000;
15
+ /** Map of toolCallId → pending execution promise. */
16
+ const pending = new Map();
17
+ /**
18
+ * Register a pending Excel execution and return a promise that resolves
19
+ * when the taskpane sends the result back.
20
+ *
21
+ * Called by the `excel` custom tool's execute function.
22
+ */
23
+ export function registerPendingExecution(toolCallId, timeoutMs = DEFAULT_TIMEOUT_MS) {
24
+ return new Promise((resolve, reject) => {
25
+ const timeout = setTimeout(() => {
26
+ pending.delete(toolCallId);
27
+ reject(new Error(`Excel execution timed out after ${timeoutMs / 1000}s. ` +
28
+ `The taskpane may not be connected or Excel may be unresponsive.`));
29
+ }, timeoutMs);
30
+ pending.set(toolCallId, { resolve, reject, timeout });
31
+ });
32
+ }
33
+ /**
34
+ * Resolve a pending execution with a successful result.
35
+ * Called when the taskpane POSTs to /api/excel/result.
36
+ *
37
+ * @returns true if the execution was found and resolved.
38
+ */
39
+ export function resolveExecution(toolCallId, result) {
40
+ const entry = pending.get(toolCallId);
41
+ if (!entry)
42
+ return false;
43
+ clearTimeout(entry.timeout);
44
+ pending.delete(toolCallId);
45
+ entry.resolve(result);
46
+ return true;
47
+ }
48
+ /**
49
+ * Reject a pending execution with an error.
50
+ * Called when the taskpane reports an Office.js error.
51
+ *
52
+ * @returns true if the execution was found and rejected.
53
+ */
54
+ export function rejectExecution(toolCallId, errorMessage) {
55
+ const entry = pending.get(toolCallId);
56
+ if (!entry)
57
+ return false;
58
+ clearTimeout(entry.timeout);
59
+ pending.delete(toolCallId);
60
+ entry.reject(new Error(`Excel error: ${errorMessage}`));
61
+ return true;
62
+ }
63
+ /** Get count of pending executions (for diagnostics). */
64
+ export function getPendingCount() {
65
+ return pending.size;
66
+ }
67
+ /** Clear all pending executions (for cleanup/testing). */
68
+ export function clearAllPending() {
69
+ for (const [id, entry] of pending) {
70
+ clearTimeout(entry.timeout);
71
+ entry.reject(new Error("Cleared"));
72
+ }
73
+ pending.clear();
74
+ }
75
+ //# sourceMappingURL=excel-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excel-bridge.js","sourceRoot":"","sources":["../../src/server/excel-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gDAAgD;AAChD,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAQlC,qDAAqD;AACrD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,UAAkB,EAClB,YAAoB,kBAAkB;IAEtC,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC3B,MAAM,CACJ,IAAI,KAAK,CACP,mCAAmC,SAAS,GAAG,IAAI,KAAK;gBACtD,iEAAiE,CACpE,CACF,CAAC;QACJ,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,UAAkB,EAClB,MAAc;IAEd,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC3B,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACtB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,UAAkB,EAClB,YAAoB;IAEpB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC3B,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,gBAAgB,YAAY,EAAE,CAAC,CAAC,CAAC;IACxD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,eAAe;IAC7B,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,eAAe;IAC7B,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QAClC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export interface FolderPickerStrategy {
2
+ platform: string;
3
+ method: "native-helper" | "powershell" | "osascript" | "manual-only";
4
+ helperPath: string | null;
5
+ }
6
+ /** Detect which folder picker strategy will be used at runtime. */
7
+ export declare function getFolderPickerStrategy(): FolderPickerStrategy;
8
+ export declare function pickLocalFolder(initialPath?: string | null): Promise<string | null>;
9
+ //# sourceMappingURL=folder-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"folder-picker.d.ts","sourceRoot":"","sources":["../../src/server/folder-picker.ts"],"names":[],"mappings":"AAyOA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,eAAe,GAAG,YAAY,GAAG,WAAW,GAAG,aAAa,CAAC;IACrE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,mEAAmE;AACnE,wBAAgB,uBAAuB,IAAI,oBAAoB,CAgB9D;AAED,wBAAsB,eAAe,CACnC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiExB"}