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,196 @@
1
+ /**
2
+ * Agent route — SSE streaming via Pi SDK session.
3
+ *
4
+ * Responsibilities:
5
+ * - Validate agent request
6
+ * - Resolve workbook/folder context
7
+ * - Build prompt with context
8
+ * - Stream SSE events to client
9
+ * - Manage cwd for Pi SDK tools
10
+ */
11
+ import { sendJson, sendError, parseJsonBody } from "../http.js";
12
+ import { isAuthenticated, getAuthProvider, getSession, abortSession, } from "../../agent/session.js";
13
+ import { getWorkbookFolderLink } from "../workbook-folder-store.js";
14
+ import { loadInventory } from "../folder-scanner.js";
15
+ import { buildFolderContext } from "../../agent/prompt/folder-context.js";
16
+ /**
17
+ * Parse and validate the agent request body, resolve folder/Excel context.
18
+ * Returns null if validation failed (error already sent to response).
19
+ */
20
+ async function resolveAgentRequestContext(req, res) {
21
+ const body = await parseJsonBody(req);
22
+ // Strict validation: message must be a non-empty string
23
+ if (!body ||
24
+ typeof body !== "object" ||
25
+ typeof body.message !== "string" ||
26
+ body.message.trim().length === 0) {
27
+ sendError(res, 400, "Missing 'message' in request body");
28
+ return null;
29
+ }
30
+ // Auth check
31
+ if (!isAuthenticated()) {
32
+ sendError(res, 401, "Not authenticated. Run 'agentxl login' to set up credentials.");
33
+ return null;
34
+ }
35
+ const b = body;
36
+ const context = b.context;
37
+ const workbookId = typeof b.workbookId === "string" ? b.workbookId.trim() : "";
38
+ const message = b.message.trim();
39
+ // Resolve folder context from workbookId
40
+ const contextParts = [];
41
+ let linkedFolderPath = null;
42
+ if (workbookId) {
43
+ const link = getWorkbookFolderLink(workbookId);
44
+ if (link) {
45
+ linkedFolderPath = link.folderPath;
46
+ const inventory = loadInventory(workbookId);
47
+ if (inventory) {
48
+ contextParts.push(buildFolderContext(link.folderPath, inventory));
49
+ }
50
+ else {
51
+ contextParts.push(`[Linked folder: ${link.folderPath}]\n[No file inventory available — folder has not been scanned yet]`);
52
+ }
53
+ }
54
+ }
55
+ // Add Excel context
56
+ if (context && (context.activeSheet || context.selectedRange)) {
57
+ const excelParts = [];
58
+ if (context.activeSheet)
59
+ excelParts.push(`Active sheet: ${context.activeSheet}`);
60
+ if (context.selectedRange)
61
+ excelParts.push(`Selected range: ${context.selectedRange}`);
62
+ contextParts.push(`[Excel: ${excelParts.join(", ")}]`);
63
+ }
64
+ console.log(`[agent] workbookId=${workbookId || "(none)"} linkedFolder=${linkedFolderPath || "(none)"} cwd=${process.cwd()}`);
65
+ return { message, linkedFolderPath, contextParts };
66
+ }
67
+ // ---------------------------------------------------------------------------
68
+ // Prompt assembly
69
+ // ---------------------------------------------------------------------------
70
+ /** Combine context parts and user message into a full prompt. */
71
+ function buildAgentPrompt(contextParts, message) {
72
+ return contextParts.length > 0
73
+ ? `${contextParts.join("\n\n")}\n\n${message}`
74
+ : message;
75
+ }
76
+ // ---------------------------------------------------------------------------
77
+ // Folder-scoped execution
78
+ // ---------------------------------------------------------------------------
79
+ /**
80
+ * Run a function with process.cwd() temporarily set to the linked folder.
81
+ *
82
+ * Pi SDK's built-in tools (ls, read, grep, find) resolve paths against
83
+ * process.cwd(). This ensures they operate on the user's documents,
84
+ * not the AgentXL project root.
85
+ *
86
+ * Safe because Node.js is single-threaded — no concurrent cwd races.
87
+ */
88
+ async function withLinkedFolderCwd(folderPath, fn) {
89
+ const originalCwd = process.cwd();
90
+ if (folderPath) {
91
+ try {
92
+ process.chdir(folderPath);
93
+ console.log(`[agent] chdir → ${process.cwd()}`);
94
+ }
95
+ catch (e) {
96
+ console.error(`[agent] chdir failed: ${e}`);
97
+ }
98
+ }
99
+ else {
100
+ console.log(`[agent] no linked folder — staying in ${process.cwd()}`);
101
+ }
102
+ try {
103
+ return await fn();
104
+ }
105
+ finally {
106
+ try {
107
+ process.chdir(originalCwd);
108
+ }
109
+ catch {
110
+ // Best effort restore
111
+ }
112
+ }
113
+ }
114
+ // ---------------------------------------------------------------------------
115
+ // SSE stream runner
116
+ // ---------------------------------------------------------------------------
117
+ /**
118
+ * Subscribe to session events and forward them as SSE to the HTTP response.
119
+ * Handles client disconnect and prompt abort.
120
+ */
121
+ async function runAgentStream(res, req, fullMessage, linkedFolderPath) {
122
+ let unsubscribe = null;
123
+ let completed = false;
124
+ const cleanup = () => {
125
+ if (unsubscribe) {
126
+ unsubscribe();
127
+ unsubscribe = null;
128
+ }
129
+ };
130
+ const sendSSE = (data) => {
131
+ if (!res.writableEnded) {
132
+ res.write(`data: ${JSON.stringify(data)}\n\n`);
133
+ }
134
+ };
135
+ try {
136
+ const session = await getSession(linkedFolderPath ?? undefined);
137
+ // Subscribe to session events and stream them as SSE
138
+ unsubscribe = session.subscribe((event) => {
139
+ sendSSE(event);
140
+ if (event.type === "agent_end") {
141
+ completed = true;
142
+ cleanup();
143
+ if (!res.writableEnded) {
144
+ res.end();
145
+ }
146
+ }
147
+ });
148
+ // Handle client disconnect mid-stream
149
+ req.on("close", () => {
150
+ if (!completed) {
151
+ cleanup();
152
+ abortSession();
153
+ }
154
+ });
155
+ // Abort any in-flight prompt before sending the new one
156
+ await abortSession();
157
+ // Execute the prompt with cwd set to the linked folder
158
+ await withLinkedFolderCwd(linkedFolderPath, () => session.prompt(fullMessage));
159
+ }
160
+ catch (err) {
161
+ completed = true;
162
+ cleanup();
163
+ const errMessage = err instanceof Error ? err.message : String(err);
164
+ sendSSE({ type: "error", error: errMessage });
165
+ if (!res.writableEnded) {
166
+ res.end();
167
+ }
168
+ }
169
+ }
170
+ // ---------------------------------------------------------------------------
171
+ // Route handlers
172
+ // ---------------------------------------------------------------------------
173
+ /** POST /api/agent — SSE streaming agent endpoint. */
174
+ export async function handleAgent(req, res) {
175
+ const ctx = await resolveAgentRequestContext(req, res);
176
+ if (!ctx)
177
+ return; // Validation error already sent
178
+ const fullMessage = buildAgentPrompt(ctx.contextParts, ctx.message);
179
+ // SSE headers
180
+ res.writeHead(200, {
181
+ "Content-Type": "text/event-stream; charset=utf-8",
182
+ "Cache-Control": "no-cache",
183
+ Connection: "keep-alive",
184
+ "Access-Control-Allow-Origin": "*",
185
+ });
186
+ await runAgentStream(res, req, fullMessage, ctx.linkedFolderPath);
187
+ }
188
+ /** GET /api/config/status */
189
+ export function handleConfigStatus(_req, res, getVersion) {
190
+ sendJson(res, 200, {
191
+ authenticated: isAuthenticated(),
192
+ provider: getAuthProvider(),
193
+ version: getVersion(),
194
+ });
195
+ }
196
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/server/routes/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Excel bridge route — receives execution results from the taskpane.
3
+ *
4
+ * POST /api/excel/result
5
+ * Body: { toolCallId: string, result?: string, error?: string }
6
+ */
7
+ import { IncomingMessage, ServerResponse } from "http";
8
+ /** POST /api/excel/result — taskpane sends Office.js execution result. */
9
+ export declare function handleExcelResult(req: IncomingMessage, res: ServerResponse): Promise<void>;
10
+ //# sourceMappingURL=excel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excel.d.ts","sourceRoot":"","sources":["../../../src/server/routes/excel.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAIvD,0EAA0E;AAC1E,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CAqCf"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Excel bridge route — receives execution results from the taskpane.
3
+ *
4
+ * POST /api/excel/result
5
+ * Body: { toolCallId: string, result?: string, error?: string }
6
+ */
7
+ import { sendJson, sendError, parseJsonBody } from "../http.js";
8
+ import { resolveExecution, rejectExecution } from "../excel-bridge.js";
9
+ /** POST /api/excel/result — taskpane sends Office.js execution result. */
10
+ export async function handleExcelResult(req, res) {
11
+ const body = await parseJsonBody(req);
12
+ if (!body || typeof body !== "object") {
13
+ sendError(res, 400, "Missing request body");
14
+ return;
15
+ }
16
+ const b = body;
17
+ const toolCallId = typeof b.toolCallId === "string" ? b.toolCallId.trim() : "";
18
+ if (!toolCallId) {
19
+ sendError(res, 400, "Missing toolCallId");
20
+ return;
21
+ }
22
+ // Handle error result
23
+ if (typeof b.error === "string") {
24
+ const found = rejectExecution(toolCallId, b.error);
25
+ if (!found) {
26
+ sendError(res, 404, "No pending execution found for this toolCallId");
27
+ return;
28
+ }
29
+ sendJson(res, 200, { ok: true, toolCallId, resolved: false });
30
+ return;
31
+ }
32
+ // Handle success result
33
+ const result = typeof b.result === "string" ? b.result : JSON.stringify(b.result ?? null);
34
+ const found = resolveExecution(toolCallId, result);
35
+ if (!found) {
36
+ sendError(res, 404, "No pending execution found for this toolCallId");
37
+ return;
38
+ }
39
+ sendJson(res, 200, { ok: true, toolCallId, resolved: true });
40
+ }
41
+ //# sourceMappingURL=excel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excel.js","sourceRoot":"","sources":["../../../src/server/routes/excel.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAEvE,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAoB,EACpB,GAAmB;IAEnB,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IAEtC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,MAAM,UAAU,GACd,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE9D,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,sBAAsB;IACtB,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,eAAe,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,gDAAgD,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QACD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IAED,wBAAwB;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC;IAC1F,MAAM,KAAK,GAAG,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,gDAAgD,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Folder linking, scanning, and inventory routes.
3
+ */
4
+ import { IncomingMessage, ServerResponse } from "http";
5
+ /** GET /api/folder/status */
6
+ export declare function handleFolderStatus(req: IncomingMessage, res: ServerResponse): void;
7
+ /** POST /api/folder/pick */
8
+ export declare function handleFolderPick(req: IncomingMessage, res: ServerResponse): Promise<void>;
9
+ /** POST /api/folder/select */
10
+ export declare function handleFolderSelect(req: IncomingMessage, res: ServerResponse): Promise<void>;
11
+ /** GET /api/folder/files */
12
+ export declare function handleFolderFiles(req: IncomingMessage, res: ServerResponse): void;
13
+ /** POST /api/folder/refresh */
14
+ export declare function handleFolderRefresh(req: IncomingMessage, res: ServerResponse): Promise<void>;
15
+ //# sourceMappingURL=folder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"folder.d.ts","sourceRoot":"","sources":["../../../src/server/routes/folder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAavD,6BAA6B;AAC7B,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,IAAI,CA6BN;AAED,4BAA4B;AAC5B,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,8BAA8B;AAC9B,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CA0Ef;AAED,4BAA4B;AAC5B,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,IAAI,CAsCN;AAED,+BAA+B;AAC/B,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CAkDf"}
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Folder linking, scanning, and inventory routes.
3
+ */
4
+ import { sendJson, sendError, parseJsonBody } from "../http.js";
5
+ import { getWorkbookFolderLink, setWorkbookFolderLink, } from "../workbook-folder-store.js";
6
+ import { pickLocalFolder } from "../folder-picker.js";
7
+ import { scanAndSaveInventory, loadInventory, } from "../folder-scanner.js";
8
+ import { convertDocuments } from "../document-converter.js";
9
+ /** GET /api/folder/status */
10
+ export function handleFolderStatus(req, res) {
11
+ const rawUrl = req.url ?? "/";
12
+ const url = new URL(rawUrl, "https://localhost");
13
+ const workbookId = url.searchParams.get("workbookId")?.trim();
14
+ if (!workbookId) {
15
+ sendError(res, 400, "Missing workbookId query parameter");
16
+ return;
17
+ }
18
+ const link = getWorkbookFolderLink(workbookId);
19
+ if (!link) {
20
+ sendJson(res, 200, { workbookId, linked: false });
21
+ return;
22
+ }
23
+ const inventory = loadInventory(workbookId);
24
+ sendJson(res, 200, {
25
+ workbookId,
26
+ linked: true,
27
+ folderPath: link.folderPath,
28
+ link,
29
+ ...(inventory
30
+ ? {
31
+ totalFiles: inventory.totalFiles,
32
+ supportedFiles: inventory.supportedFiles,
33
+ }
34
+ : {}),
35
+ });
36
+ }
37
+ /** POST /api/folder/pick */
38
+ export async function handleFolderPick(req, res) {
39
+ try {
40
+ const body = await parseJsonBody(req);
41
+ const b = body && typeof body === "object" ? body : null;
42
+ const initialPath = b && typeof b.initialPath === "string" ? b.initialPath : null;
43
+ const folderPath = await pickLocalFolder(initialPath);
44
+ sendJson(res, 200, {
45
+ picked: Boolean(folderPath),
46
+ folderPath,
47
+ });
48
+ }
49
+ catch (error) {
50
+ const message = error instanceof Error
51
+ ? error.message
52
+ : "Failed to open native folder picker";
53
+ const status = message.toLowerCase().includes("timed out") ? 504 : 500;
54
+ sendError(res, status, message);
55
+ }
56
+ }
57
+ /** POST /api/folder/select */
58
+ export async function handleFolderSelect(req, res) {
59
+ const body = await parseJsonBody(req);
60
+ if (!body || typeof body !== "object") {
61
+ sendError(res, 400, "Missing folder selection payload");
62
+ return;
63
+ }
64
+ const b = body;
65
+ const workbookId = typeof b.workbookId === "string" ? b.workbookId.trim() : "";
66
+ const folderPath = typeof b.folderPath === "string" ? b.folderPath.trim() : "";
67
+ if (!workbookId) {
68
+ sendError(res, 400, "Missing workbookId in request body");
69
+ return;
70
+ }
71
+ if (!folderPath) {
72
+ sendError(res, 400, "Missing folderPath in request body");
73
+ return;
74
+ }
75
+ try {
76
+ const link = setWorkbookFolderLink({
77
+ workbookId,
78
+ folderPath,
79
+ workbookName: typeof b.workbookName === "string" ? b.workbookName : null,
80
+ workbookUrl: typeof b.workbookUrl === "string" ? b.workbookUrl : null,
81
+ host: typeof b.host === "string" ? b.host : null,
82
+ source: typeof b.source === "string" ? b.source : null,
83
+ });
84
+ // Auto-scan the folder on link/update (fast — just reads directory)
85
+ let inventory = null;
86
+ try {
87
+ inventory = scanAndSaveInventory(workbookId, link.folderPath);
88
+ }
89
+ catch {
90
+ // Scan failure is non-fatal — folder is still linked
91
+ }
92
+ // Respond immediately so the user isn't blocked.
93
+ // PDF conversion runs in the background after the response.
94
+ sendJson(res, 200, {
95
+ workbookId,
96
+ linked: true,
97
+ folderPath: link.folderPath,
98
+ link,
99
+ ...(inventory
100
+ ? {
101
+ totalFiles: inventory.totalFiles,
102
+ supportedFiles: inventory.supportedFiles,
103
+ }
104
+ : {}),
105
+ });
106
+ // Fire-and-forget: convert PDFs to markdown in the background.
107
+ // The agent reads from .agentxl-cache/ at prompt time, so conversions
108
+ // that finish after this response are still picked up.
109
+ if (inventory) {
110
+ convertDocuments(inventory).catch((err) => {
111
+ console.error("[folder] background PDF conversion error:", err);
112
+ });
113
+ }
114
+ }
115
+ catch (error) {
116
+ sendError(res, 400, error instanceof Error ? error.message : "Failed to save folder mapping");
117
+ }
118
+ }
119
+ /** GET /api/folder/files */
120
+ export function handleFolderFiles(req, res) {
121
+ const rawUrl = req.url ?? "/";
122
+ const url = new URL(rawUrl, "https://localhost");
123
+ const workbookId = url.searchParams.get("workbookId")?.trim();
124
+ if (!workbookId) {
125
+ sendError(res, 400, "Missing workbookId query parameter");
126
+ return;
127
+ }
128
+ const link = getWorkbookFolderLink(workbookId);
129
+ if (!link) {
130
+ sendError(res, 404, "No folder linked for this workbook. Link a folder first.");
131
+ return;
132
+ }
133
+ const inventory = loadInventory(workbookId);
134
+ if (!inventory) {
135
+ sendError(res, 404, "No inventory available. Refresh the folder to scan files.");
136
+ return;
137
+ }
138
+ sendJson(res, 200, {
139
+ workbookId,
140
+ folderPath: inventory.folderPath,
141
+ scannedAt: inventory.scannedAt,
142
+ totalFiles: inventory.totalFiles,
143
+ supportedFiles: inventory.supportedFiles,
144
+ files: inventory.files,
145
+ });
146
+ }
147
+ /** POST /api/folder/refresh */
148
+ export async function handleFolderRefresh(req, res) {
149
+ const body = await parseJsonBody(req);
150
+ if (!body || typeof body !== "object") {
151
+ sendError(res, 400, "Missing request body");
152
+ return;
153
+ }
154
+ const b = body;
155
+ const workbookId = typeof b.workbookId === "string" ? b.workbookId.trim() : "";
156
+ if (!workbookId) {
157
+ sendError(res, 400, "Missing workbookId in request body");
158
+ return;
159
+ }
160
+ const link = getWorkbookFolderLink(workbookId);
161
+ if (!link) {
162
+ sendError(res, 404, "No folder linked for this workbook. Link a folder first.");
163
+ return;
164
+ }
165
+ try {
166
+ const inventory = scanAndSaveInventory(workbookId, link.folderPath);
167
+ // Respond immediately with the scan results
168
+ sendJson(res, 200, {
169
+ workbookId,
170
+ folderPath: inventory.folderPath,
171
+ scannedAt: inventory.scannedAt,
172
+ totalFiles: inventory.totalFiles,
173
+ supportedFiles: inventory.supportedFiles,
174
+ });
175
+ // Fire-and-forget: convert PDFs in the background
176
+ convertDocuments(inventory).catch((err) => {
177
+ console.error("[folder] background PDF conversion error:", err);
178
+ });
179
+ }
180
+ catch (error) {
181
+ sendError(res, 500, error instanceof Error ? error.message : "Failed to scan folder");
182
+ }
183
+ }
184
+ //# sourceMappingURL=folder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"folder.js","sourceRoot":"","sources":["../../../src/server/routes/folder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Workbook identity resolution routes.
3
+ */
4
+ import { IncomingMessage, ServerResponse } from "http";
5
+ /** POST /api/workbook/resolve */
6
+ export declare function handleWorkbookResolve(req: IncomingMessage, res: ServerResponse): Promise<void>;
7
+ //# sourceMappingURL=workbook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workbook.d.ts","sourceRoot":"","sources":["../../../src/server/routes/workbook.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAIvD,iCAAiC;AACjC,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CAgCf"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Workbook identity resolution routes.
3
+ */
4
+ import { sendJson, sendError, parseJsonBody } from "../http.js";
5
+ import { resolveWorkbookId } from "../workbook-identity.js";
6
+ /** POST /api/workbook/resolve */
7
+ export async function handleWorkbookResolve(req, res) {
8
+ const body = await parseJsonBody(req);
9
+ if (!body || typeof body !== "object") {
10
+ sendError(res, 400, "Missing workbook context in request body");
11
+ return;
12
+ }
13
+ const b = body;
14
+ const workbookName = typeof b.workbookName === "string" ? b.workbookName : null;
15
+ const workbookUrl = typeof b.workbookUrl === "string" ? b.workbookUrl : null;
16
+ const host = typeof b.host === "string" ? b.host : null;
17
+ const source = typeof b.source === "string" ? b.source : null;
18
+ if ((!workbookName || workbookName.trim().length === 0) &&
19
+ (!workbookUrl || workbookUrl.trim().length === 0)) {
20
+ sendError(res, 400, "Missing workbookName or workbookUrl in request body");
21
+ return;
22
+ }
23
+ const workbookId = resolveWorkbookId({
24
+ workbookName,
25
+ workbookUrl,
26
+ host,
27
+ source,
28
+ });
29
+ sendJson(res, 200, { workbookId });
30
+ }
31
+ //# sourceMappingURL=workbook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workbook.js","sourceRoot":"","sources":["../../../src/server/routes/workbook.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,iCAAiC;AACjC,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAoB,EACpB,GAAmB;IAEnB,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IAEtC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,0CAA0C,CAAC,CAAC;QAChE,OAAO;IACT,CAAC;IAED,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,MAAM,YAAY,GAChB,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,MAAM,WAAW,GACf,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3D,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAE9D,IACE,CAAC,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC;QACnD,CAAC,CAAC,WAAW,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,EACjD,CAAC;QACD,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,qDAAqD,CAAC,CAAC;QAC3E,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,iBAAiB,CAAC;QACnC,YAAY;QACZ,WAAW;QACX,IAAI;QACJ,MAAM;KACP,CAAC,CAAC;IAEH,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Static file serving for the taskpane UI.
3
+ *
4
+ * Serves pre-built React bundle from taskpane/dist/.
5
+ * Includes SPA fallback and security checks.
6
+ */
7
+ import { IncomingMessage, ServerResponse } from "http";
8
+ /** Resolve the taskpane dist directory. */
9
+ export declare function resolveTaskpaneRoot(): string;
10
+ /** Serve static files from the taskpane dist directory. */
11
+ export declare function handleTaskpane(req: IncomingMessage, res: ServerResponse, taskpaneRoot: string): void;
12
+ //# sourceMappingURL=static.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/server/static.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAyBvD,2CAA2C;AAC3C,wBAAgB,mBAAmB,IAAI,MAAM,CAS5C;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAC5B,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,YAAY,EAAE,MAAM,GACnB,IAAI,CAiDN"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Static file serving for the taskpane UI.
3
+ *
4
+ * Serves pre-built React bundle from taskpane/dist/.
5
+ * Includes SPA fallback and security checks.
6
+ */
7
+ import { readFileSync, existsSync } from "fs";
8
+ import { join, extname, dirname } from "path";
9
+ import { fileURLToPath } from "url";
10
+ import { sendError } from "./http.js";
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+ /** MIME types for static file serving. */
14
+ const MIME_TYPES = {
15
+ ".html": "text/html; charset=utf-8",
16
+ ".js": "application/javascript; charset=utf-8",
17
+ ".mjs": "application/javascript; charset=utf-8",
18
+ ".css": "text/css; charset=utf-8",
19
+ ".json": "application/json; charset=utf-8",
20
+ ".png": "image/png",
21
+ ".svg": "image/svg+xml",
22
+ ".ico": "image/x-icon",
23
+ ".webp": "image/webp",
24
+ ".woff": "font/woff",
25
+ ".woff2": "font/woff2",
26
+ ".map": "application/json",
27
+ };
28
+ /** Resolve the taskpane dist directory. */
29
+ export function resolveTaskpaneRoot() {
30
+ const candidates = [
31
+ join(__dirname, "..", "..", "taskpane", "dist"),
32
+ join(__dirname, "..", "..", "..", "taskpane", "dist"),
33
+ ];
34
+ for (const c of candidates) {
35
+ if (existsSync(c))
36
+ return c;
37
+ }
38
+ return join(__dirname, "..", "..", "taskpane", "dist");
39
+ }
40
+ /** Serve static files from the taskpane dist directory. */
41
+ export function handleTaskpane(req, res, taskpaneRoot) {
42
+ const url = req.url ?? "/";
43
+ // Strip /taskpane prefix to get relative path
44
+ let relativePath = url.replace(/^\/taskpane\/?/, "");
45
+ relativePath = relativePath.split("?")[0];
46
+ // Default to index.html
47
+ if (relativePath === "" || relativePath === "/") {
48
+ relativePath = "index.html";
49
+ }
50
+ const filePath = join(taskpaneRoot, relativePath);
51
+ // Security: ensure resolved path is within taskpaneRoot
52
+ if (!filePath.startsWith(taskpaneRoot)) {
53
+ sendError(res, 403, "Forbidden");
54
+ return;
55
+ }
56
+ if (!existsSync(filePath)) {
57
+ // SPA fallback: serve index.html for non-file paths
58
+ const indexPath = join(taskpaneRoot, "index.html");
59
+ if (existsSync(indexPath) && !extname(relativePath)) {
60
+ const content = readFileSync(indexPath);
61
+ res.writeHead(200, {
62
+ "Content-Type": "text/html; charset=utf-8",
63
+ "Content-Length": content.length,
64
+ "Access-Control-Allow-Origin": "*",
65
+ });
66
+ res.end(content);
67
+ return;
68
+ }
69
+ sendError(res, 404, "Not found");
70
+ return;
71
+ }
72
+ const ext = extname(filePath).toLowerCase();
73
+ const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
74
+ const content = readFileSync(filePath);
75
+ res.writeHead(200, {
76
+ "Content-Type": contentType,
77
+ "Content-Length": content.length,
78
+ "Access-Control-Allow-Origin": "*",
79
+ "Cache-Control": ext === ".html" ? "no-cache" : "public, max-age=31536000",
80
+ });
81
+ res.end(content);
82
+ }
83
+ //# sourceMappingURL=static.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static.js","sourceRoot":"","sources":["../../src/server/static.ts"],"names":[],"mappings":"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"}