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.
- package/LICENSE +21 -0
- package/README.md +352 -197
- package/bin/agentxl-folder-picker.exe +0 -0
- package/bin/agentxl.js +44 -8
- package/dist/agent/models.d.ts +9 -9
- package/dist/agent/models.d.ts.map +1 -1
- package/dist/agent/models.js +44 -8
- package/dist/agent/models.js.map +1 -1
- package/dist/agent/prompt/folder-context.d.ts +26 -0
- package/dist/agent/prompt/folder-context.d.ts.map +1 -0
- package/dist/agent/prompt/folder-context.js +105 -0
- package/dist/agent/prompt/folder-context.js.map +1 -0
- package/dist/agent/prompt/system-prompt.d.ts +21 -0
- package/dist/agent/prompt/system-prompt.d.ts.map +1 -0
- package/dist/agent/prompt/system-prompt.js +130 -0
- package/dist/agent/prompt/system-prompt.js.map +1 -0
- package/dist/agent/session.d.ts +10 -4
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +53 -15
- package/dist/agent/session.js.map +1 -1
- package/dist/agent/tools/excel.d.ts +24 -0
- package/dist/agent/tools/excel.d.ts.map +1 -0
- package/dist/agent/tools/excel.js +132 -0
- package/dist/agent/tools/excel.js.map +1 -0
- package/dist/server/document-converter.d.ts +71 -0
- package/dist/server/document-converter.d.ts.map +1 -0
- package/dist/server/document-converter.js +353 -0
- package/dist/server/document-converter.js.map +1 -0
- package/dist/server/excel-bridge.d.ts +38 -0
- package/dist/server/excel-bridge.d.ts.map +1 -0
- package/dist/server/excel-bridge.js +75 -0
- package/dist/server/excel-bridge.js.map +1 -0
- package/dist/server/folder-picker.d.ts +9 -0
- package/dist/server/folder-picker.d.ts.map +1 -0
- package/dist/server/folder-picker.js +204 -0
- package/dist/server/folder-picker.js.map +1 -0
- package/dist/server/folder-scanner.d.ts +43 -0
- package/dist/server/folder-scanner.d.ts.map +1 -0
- package/dist/server/folder-scanner.js +161 -0
- package/dist/server/folder-scanner.js.map +1 -0
- package/dist/server/http.d.ts +19 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +62 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/index.d.ts +16 -4
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +70 -246
- package/dist/server/index.js.map +1 -1
- package/dist/server/json-store.d.ts +19 -0
- package/dist/server/json-store.d.ts.map +1 -0
- package/dist/server/json-store.js +37 -0
- package/dist/server/json-store.js.map +1 -0
- package/dist/server/routes/agent.d.ts +16 -0
- package/dist/server/routes/agent.d.ts.map +1 -0
- package/dist/server/routes/agent.js +196 -0
- package/dist/server/routes/agent.js.map +1 -0
- package/dist/server/routes/excel.d.ts +10 -0
- package/dist/server/routes/excel.d.ts.map +1 -0
- package/dist/server/routes/excel.js +41 -0
- package/dist/server/routes/excel.js.map +1 -0
- package/dist/server/routes/folder.d.ts +15 -0
- package/dist/server/routes/folder.d.ts.map +1 -0
- package/dist/server/routes/folder.js +184 -0
- package/dist/server/routes/folder.js.map +1 -0
- package/dist/server/routes/workbook.d.ts +7 -0
- package/dist/server/routes/workbook.d.ts.map +1 -0
- package/dist/server/routes/workbook.js +31 -0
- package/dist/server/routes/workbook.js.map +1 -0
- package/dist/server/static.d.ts +12 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +83 -0
- package/dist/server/static.js.map +1 -0
- package/dist/server/workbook-folder-store.d.ts +24 -0
- package/dist/server/workbook-folder-store.d.ts.map +1 -0
- package/dist/server/workbook-folder-store.js +76 -0
- package/dist/server/workbook-folder-store.js.map +1 -0
- package/dist/server/workbook-identity.d.ts +8 -0
- package/dist/server/workbook-identity.d.ts.map +1 -0
- package/dist/server/workbook-identity.js +57 -0
- package/dist/server/workbook-identity.js.map +1 -0
- package/manifest/manifest-hosted.xml +107 -0
- package/package.json +24 -10
- package/taskpane/dist/assets/index-BnD8psE_.js +224 -0
- package/taskpane/dist/assets/index-BuAcDfRq.css +1 -0
- package/taskpane/dist/index.html +2 -2
- package/taskpane/dist/assets/index-6sMpIYxE.css +0 -1
- 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":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,0CAA0C;AAC1C,MAAM,UAAU,GAA2B;IACzC,OAAO,EAAE,0BAA0B;IACnC,KAAK,EAAE,uCAAuC;IAC9C,MAAM,EAAE,uCAAuC;IAC/C,MAAM,EAAE,yBAAyB;IACjC,OAAO,EAAE,iCAAiC;IAC1C,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,WAAW;IACpB,QAAQ,EAAE,YAAY;IACtB,MAAM,EAAE,kBAAkB;CAC3B,CAAC;AAEF,2CAA2C;AAC3C,MAAM,UAAU,mBAAmB;IACjC,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC;QAC/C,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC;KACtD,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;AACzD,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,cAAc,CAC5B,GAAoB,EACpB,GAAmB,EACnB,YAAoB;IAEpB,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC;IAE3B,8CAA8C;IAC9C,IAAI,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IACrD,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE1C,wBAAwB;IACxB,IAAI,YAAY,KAAK,EAAE,IAAI,YAAY,KAAK,GAAG,EAAE,CAAC;QAChD,YAAY,GAAG,YAAY,CAAC;IAC9B,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAElD,wDAAwD;IACxD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACvC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,oDAAoD;QACpD,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QACnD,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YACpD,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;YACxC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;gBACjB,cAAc,EAAE,0BAA0B;gBAC1C,gBAAgB,EAAE,OAAO,CAAC,MAAM;gBAChC,6BAA6B,EAAE,GAAG;aACnC,CAAC,CAAC;YACH,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACjB,OAAO;QACT,CAAC;QACD,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5C,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;IAClE,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEvC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,cAAc,EAAE,WAAW;QAC3B,gBAAgB,EAAE,OAAO,CAAC,MAAM;QAChC,6BAA6B,EAAE,GAAG;QAClC,eAAe,EACb,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,0BAA0B;KAC5D,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC"}
|