spiracha 1.0.0 → 1.1.0

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 (88) hide show
  1. package/AGENTS.md +28 -1
  2. package/README.md +47 -7
  3. package/apps/ui/AGENTS.md +70 -0
  4. package/apps/ui/README.md +72 -0
  5. package/apps/ui/dist/client/assets/_threadId-CAIeH5mq.js +1 -0
  6. package/apps/ui/dist/client/assets/analytics-BjYaHqXk.js +1 -0
  7. package/apps/ui/dist/client/assets/checkbox-wPoGG3of.js +1 -0
  8. package/apps/ui/dist/client/assets/data-table-6yDgAdtf.js +4 -0
  9. package/apps/ui/dist/client/assets/delete-confirm-dialog-DJUAk7ha.js +11 -0
  10. package/apps/ui/dist/client/assets/download-BhWd-Pm5.js +1 -0
  11. package/apps/ui/dist/client/assets/es2015-BlyMI4CF.js +41 -0
  12. package/apps/ui/dist/client/assets/formatters-BxjZwWSE.js +1 -0
  13. package/apps/ui/dist/client/assets/index-T01rPkb4.js +22 -0
  14. package/apps/ui/dist/client/assets/input-B3YN8gzg.js +1 -0
  15. package/apps/ui/dist/client/assets/metric-card-BWW7TWER.js +1 -0
  16. package/apps/ui/dist/client/assets/page-header-BZ8Gnxgs.js +1 -0
  17. package/apps/ui/dist/client/assets/projects._project-B7XcpoLt.js +1 -0
  18. package/apps/ui/dist/client/assets/projects._project-EfBhCHPY.js +1 -0
  19. package/apps/ui/dist/client/assets/projects.index-4vfIwLjw.js +1 -0
  20. package/apps/ui/dist/client/assets/projects.index-DzEZ4pAJ.js +1 -0
  21. package/apps/ui/dist/client/assets/routes-CWCCZykE.js +1 -0
  22. package/apps/ui/dist/client/assets/select-DLXGsyZ4.js +1 -0
  23. package/apps/ui/dist/client/assets/settings-b0Xthfae.js +1 -0
  24. package/apps/ui/dist/client/assets/styles-8Wtc8YJw.css +1 -0
  25. package/apps/ui/dist/client/assets/threads._threadId-CgtoCqTb.js +1 -0
  26. package/apps/ui/dist/client/assets/threads._threadId-DBiDb38K.js +7 -0
  27. package/apps/ui/dist/client/favicon.ico +0 -0
  28. package/apps/ui/dist/client/logo192.png +0 -0
  29. package/apps/ui/dist/client/logo512.png +0 -0
  30. package/apps/ui/dist/client/manifest.json +25 -0
  31. package/apps/ui/dist/client/robots.txt +3 -0
  32. package/apps/ui/dist/server/assets/__23tanstack-start-plugin-adapters-BzCA6dXo.js +5 -0
  33. package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-BjsXNYgm.js +99 -0
  34. package/apps/ui/dist/server/assets/_threadId-B6SrBR9E.js +6 -0
  35. package/apps/ui/dist/server/assets/analytics-Br_fZB6a.js +139 -0
  36. package/apps/ui/dist/server/assets/button-CmTDnzOn.js +46 -0
  37. package/apps/ui/dist/server/assets/checkbox-C0hovF41.js +19 -0
  38. package/apps/ui/dist/server/assets/codex-queries-CAF6HYiG.js +109 -0
  39. package/apps/ui/dist/server/assets/codex-server-Cqh0hb93.js +1995 -0
  40. package/apps/ui/dist/server/assets/data-table-Cdct823O.js +189 -0
  41. package/apps/ui/dist/server/assets/delete-confirm-dialog-CWqcTXTF.js +139 -0
  42. package/apps/ui/dist/server/assets/download-CzHmFWGk.js +286 -0
  43. package/apps/ui/dist/server/assets/formatters-B6o5pTY9.js +72 -0
  44. package/apps/ui/dist/server/assets/input-B4tEzctc.js +46 -0
  45. package/apps/ui/dist/server/assets/loading-panel-DbLdvjtR.js +27 -0
  46. package/apps/ui/dist/server/assets/metric-card-ByEeLu0r.js +23 -0
  47. package/apps/ui/dist/server/assets/page-header-CxdZM86z.js +25 -0
  48. package/apps/ui/dist/server/assets/path-transforms-DD1e7rhY.js +31 -0
  49. package/apps/ui/dist/server/assets/projects._project-Bwf6iJC-.js +335 -0
  50. package/apps/ui/dist/server/assets/projects._project-CLSohrBp.js +26 -0
  51. package/apps/ui/dist/server/assets/projects._project-DdVSdfPe.js +18 -0
  52. package/apps/ui/dist/server/assets/projects.index-CaplpeMy.js +26 -0
  53. package/apps/ui/dist/server/assets/projects.index-DKeVeqUZ.js +171 -0
  54. package/apps/ui/dist/server/assets/router-ve2Hrl2Y.js +307 -0
  55. package/apps/ui/dist/server/assets/routes-BJyx5OmO.js +34 -0
  56. package/apps/ui/dist/server/assets/routes-pkOwjjYc.js +168 -0
  57. package/apps/ui/dist/server/assets/select-GW76p-ld.js +76 -0
  58. package/apps/ui/dist/server/assets/settings-MvWDgc1u.js +100 -0
  59. package/apps/ui/dist/server/assets/settings-store-DpEJEQ7M.js +52 -0
  60. package/apps/ui/dist/server/assets/sqlite-error-LZDrnxdd.js +13 -0
  61. package/apps/ui/dist/server/assets/start-BAvbjjfs.js +4 -0
  62. package/apps/ui/dist/server/assets/threads._threadId-BSSK4nkI.js +26 -0
  63. package/apps/ui/dist/server/assets/threads._threadId-D3PYZIwl.js +18 -0
  64. package/apps/ui/dist/server/assets/threads._threadId-D3xaWM86.js +1037 -0
  65. package/apps/ui/dist/server/assets/utils-C_uf36nf.js +8 -0
  66. package/apps/ui/dist/server/server.js +5678 -0
  67. package/package.json +47 -7
  68. package/src/export-chats.ts +1 -14
  69. package/src/lib/codex-analytics.ts +100 -0
  70. package/src/lib/codex-browser-db.ts +518 -0
  71. package/src/lib/codex-browser-export.ts +418 -0
  72. package/src/lib/codex-browser-types.ts +224 -0
  73. package/src/lib/codex-exporter-cli.ts +5 -0
  74. package/src/lib/codex-exporter-transcript.ts +143 -32
  75. package/src/lib/codex-exporter-types.ts +8 -0
  76. package/src/lib/codex-thread-cache.ts +58 -0
  77. package/src/lib/codex-thread-parser.ts +604 -0
  78. package/src/lib/interactive-cli.ts +5 -13
  79. package/src/lib/native-open.ts +54 -0
  80. package/src/lib/path-transforms.ts +45 -0
  81. package/src/lib/shared.ts +37 -1
  82. package/src/lib/sqlite-error.ts +14 -0
  83. package/src/lib/sqlite-retry.ts +39 -0
  84. package/src/lib/ui-cache.ts +96 -0
  85. package/src/lib/ui-export-files.ts +77 -0
  86. package/src/mcp-server.ts +1 -0
  87. package/src/spiracha.ts +14 -1
  88. package/src/ui-cli.ts +310 -0
@@ -0,0 +1,1995 @@
1
+ import { n as TSS_SERVER_FUNCTION, t as createServerFn } from "../server.js";
2
+ import { t as isRetryableSqliteError } from "./sqlite-error-LZDrnxdd.js";
3
+ import { t as applyPathTransforms } from "./path-transforms-DD1e7rhY.js";
4
+ import { finished } from "node:stream/promises";
5
+ import { Database } from "bun:sqlite";
6
+ import { mkdir, mkdtemp, readdir, rename, rm, stat } from "node:fs/promises";
7
+ import os from "node:os";
8
+ import path from "node:path";
9
+ import { createReadStream, createWriteStream } from "node:fs";
10
+ import { createInterface } from "node:readline";
11
+ import { createHash, randomUUID } from "node:crypto";
12
+ import { z } from "zod";
13
+ //#region ../../node_modules/.bun/@tanstack+start-server-core@1.169.3/node_modules/@tanstack/start-server-core/dist/esm/createServerRpc.js
14
+ var createServerRpc = (serverFnMeta, splitImportFn) => {
15
+ const url = "/_serverFn/" + serverFnMeta.id;
16
+ return Object.assign(splitImportFn, {
17
+ url,
18
+ serverFnMeta,
19
+ [TSS_SERVER_FUNCTION]: true
20
+ });
21
+ };
22
+ //#endregion
23
+ //#region ../../src/lib/codex-exporter-types.ts
24
+ var DEFAULT_CODEX_DIR = path.join(os.homedir(), ".codex");
25
+ var DEFAULT_DB_PATH = path.join(DEFAULT_CODEX_DIR, "state_5.sqlite");
26
+ path.join(DEFAULT_CODEX_DIR, "sessions");
27
+ path.join(process.cwd(), "exports");
28
+ //#endregion
29
+ //#region ../../src/lib/shared.ts
30
+ var getPortablePathBasename = (value) => {
31
+ const trimmed = value.replace(/[\\/]+$/u, "");
32
+ if (!trimmed) return "";
33
+ return path.win32.basename(path.posix.basename(trimmed));
34
+ };
35
+ var cleanInlineTitle = (value) => {
36
+ const compact = (value.split("\n").map((line) => line.trim()).find((line) => line.length > 0) ?? "").replace(/\s+/g, " ").trim();
37
+ if (compact.length <= 160) return compact;
38
+ return `${compact.slice(0, 157).trimEnd()}...`;
39
+ };
40
+ var cleanExtractedText = (text) => {
41
+ return text.replace(/^\s*<\/?image>\s*$/gm, "").replace(/\n{3,}/g, "\n\n");
42
+ };
43
+ var formatModelLabel = (value) => {
44
+ if (!value) return "Assistant";
45
+ return value.split(/[-_\s]+/u).filter(Boolean).map((part) => {
46
+ const lower = part.toLowerCase();
47
+ if (lower === "gpt") return "GPT";
48
+ if (/^[a-z]\d$/u.test(lower)) return lower.toUpperCase();
49
+ if (/^\d+(\.\d+)*$/u.test(part)) return part;
50
+ return `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`;
51
+ }).join(" ");
52
+ };
53
+ var asObject = (value) => {
54
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
55
+ return value;
56
+ };
57
+ var asString = (value) => {
58
+ return typeof value === "string" ? value : null;
59
+ };
60
+ var asNumber = (value) => {
61
+ return typeof value === "number" ? value : null;
62
+ };
63
+ var readJsonlObjects = (filePath) => {
64
+ const stream = createReadStream(filePath, { encoding: "utf8" });
65
+ const lines = createInterface({
66
+ crlfDelay: Infinity,
67
+ input: stream
68
+ });
69
+ const lineIterator = lines[Symbol.asyncIterator]();
70
+ let closed = false;
71
+ const close = () => {
72
+ if (closed) return;
73
+ closed = true;
74
+ lines.close();
75
+ stream.destroy();
76
+ };
77
+ const readNext = async () => {
78
+ while (true) {
79
+ const nextLine = await lineIterator.next();
80
+ if (nextLine.done) {
81
+ close();
82
+ return {
83
+ done: true,
84
+ value: void 0
85
+ };
86
+ }
87
+ const trimmed = nextLine.value.trim();
88
+ if (!trimmed) continue;
89
+ try {
90
+ return {
91
+ done: false,
92
+ value: JSON.parse(trimmed)
93
+ };
94
+ } catch {}
95
+ }
96
+ };
97
+ const iterator = {
98
+ [Symbol.asyncIterator]: () => iterator,
99
+ next: async () => readNext(),
100
+ return: async () => {
101
+ close();
102
+ return {
103
+ done: true,
104
+ value: void 0
105
+ };
106
+ },
107
+ throw: async (error) => {
108
+ close();
109
+ throw error;
110
+ }
111
+ };
112
+ return iterator;
113
+ };
114
+ var renderDocumentTitle = (title, format) => {
115
+ if (format === "md") return `# ${title}`;
116
+ return [title, "=".repeat(Math.max(title.length, 3))].join("\n");
117
+ };
118
+ var renderMetadataBlock = (entries, format) => {
119
+ const filteredEntries = entries.filter((entry) => entry.value !== null && entry.value !== void 0 && entry.value !== "");
120
+ if (filteredEntries.length === 0) return "";
121
+ if (format === "md") {
122
+ const lines = ["---"];
123
+ for (const entry of filteredEntries) lines.push(`${entry.key}: ${toMetadataValue(entry.value, "md")}`);
124
+ lines.push("---");
125
+ return `${lines.join("\n")}\n`;
126
+ }
127
+ const lines = ["Metadata", "--------"];
128
+ for (const entry of filteredEntries) lines.push(`${entry.key}: ${toMetadataValue(entry.value, "txt")}`);
129
+ return `${lines.join("\n")}\n`;
130
+ };
131
+ var renderSection = (title, body, format) => {
132
+ const trimmedBody = body.trimEnd();
133
+ if (!trimmedBody) return "";
134
+ if (format === "md") return `## ${title}\n\n${trimmedBody}\n`;
135
+ return `${title}\n${"-".repeat(Math.max(title.length, 3))}\n${trimmedBody}\n`;
136
+ };
137
+ var formatInlineLiteral = (value, format) => {
138
+ return format === "md" ? inlineCode(value) : value;
139
+ };
140
+ var inlineCode = (value) => {
141
+ const maxRunLength = (value.match(/`+/g) ?? []).reduce((max, run) => Math.max(max, run.length), 0);
142
+ const fence = "`".repeat(maxRunLength + 1);
143
+ return `${fence}${value.startsWith("`") || value.endsWith("`") ? ` ${value} ` : value}${fence}`;
144
+ };
145
+ var createExportWriteStream = async (outputPath) => {
146
+ await mkdir(path.dirname(outputPath), { recursive: true });
147
+ return createWriteStream(outputPath, { encoding: "utf8" });
148
+ };
149
+ var finalizeExportWriteStream = async (stream) => {
150
+ stream.end();
151
+ await finished(stream);
152
+ };
153
+ var toMetadataValue = (value, format) => {
154
+ if (Array.isArray(value) || value && typeof value === "object") return JSON.stringify(value);
155
+ if (typeof value === "string") return format === "md" ? JSON.stringify(value) : value;
156
+ if (typeof value === "boolean" || typeof value === "number") return String(value);
157
+ return format === "md" ? JSON.stringify(String(value)) : String(value);
158
+ };
159
+ //#endregion
160
+ //#region ../../src/lib/codex-thread-parser.ts
161
+ var createEmptyStats = () => {
162
+ return {
163
+ assistantMessageCount: 0,
164
+ commentaryCount: 0,
165
+ execCommandCount: 0,
166
+ finalAnswerCount: 0,
167
+ messageCount: 0,
168
+ toolCallCount: 0,
169
+ toolOutputCount: 0,
170
+ userMessageCount: 0,
171
+ webSearchEventCount: 0
172
+ };
173
+ };
174
+ var createEmptySessionMeta = () => {
175
+ return {
176
+ baseInstructions: null,
177
+ cli_version: void 0,
178
+ cwd: void 0,
179
+ dynamicTools: [],
180
+ git: null,
181
+ id: void 0,
182
+ modelProvider: null,
183
+ originator: void 0,
184
+ source: void 0,
185
+ threadSource: null,
186
+ timestamp: void 0
187
+ };
188
+ };
189
+ var parseCodexTranscriptFile = async (sessionFile, options = {}) => {
190
+ const sessionMeta = createEmptySessionMeta();
191
+ const turnContexts = [];
192
+ const events = [];
193
+ const stats = createEmptyStats();
194
+ const includeRaw = options.includeRaw ?? true;
195
+ const maxEvents = options.maxEvents ?? Number.POSITIVE_INFINITY;
196
+ const maxTurnContexts = options.maxTurnContexts ?? Number.POSITIVE_INFINITY;
197
+ let sequence = 0;
198
+ for await (const parsed of readJsonlObjects(sessionFile)) {
199
+ captureSessionMeta$1(parsed, sessionMeta);
200
+ if (asString(parsed.type) === "turn_context") {
201
+ if (turnContexts.length < maxTurnContexts) captureTurnContext(parsed, turnContexts);
202
+ continue;
203
+ }
204
+ const event = toThreadEvent(parsed, sequence, includeRaw);
205
+ if (!event) continue;
206
+ events.push(event);
207
+ updateTranscriptStats(stats, event);
208
+ sequence += 1;
209
+ if (events.length >= maxEvents) break;
210
+ }
211
+ return {
212
+ events,
213
+ isPartial: Number.isFinite(maxEvents) || Number.isFinite(maxTurnContexts),
214
+ rawIncluded: includeRaw,
215
+ sessionMeta,
216
+ sourceFileSizeBytes: options.sourceFileSizeBytes ?? null,
217
+ stats,
218
+ statsArePartial: Number.isFinite(maxEvents),
219
+ turnContexts
220
+ };
221
+ };
222
+ var captureSessionMeta$1 = (parsed, sessionMeta) => {
223
+ if (parsed.type !== "session_meta") return;
224
+ const payload = asObject(parsed.payload);
225
+ if (!payload) return;
226
+ sessionMeta.baseInstructions = payload.base_instructions ?? sessionMeta.baseInstructions;
227
+ sessionMeta.cli_version = asString(payload.cli_version) ?? sessionMeta.cli_version;
228
+ sessionMeta.cwd = asString(payload.cwd) ?? sessionMeta.cwd;
229
+ sessionMeta.dynamicTools = parseDynamicTools(payload.dynamic_tools) ?? sessionMeta.dynamicTools;
230
+ sessionMeta.git = asObject(payload.git) ?? sessionMeta.git;
231
+ sessionMeta.id = asString(payload.id) ?? sessionMeta.id;
232
+ sessionMeta.modelProvider = asString(payload.model_provider) ?? sessionMeta.modelProvider;
233
+ sessionMeta.originator = asString(payload.originator) ?? sessionMeta.originator;
234
+ sessionMeta.source = asString(payload.source) ?? sessionMeta.source;
235
+ sessionMeta.threadSource = asString(payload.thread_source) ?? sessionMeta.threadSource;
236
+ sessionMeta.timestamp = asString(payload.timestamp) ?? sessionMeta.timestamp;
237
+ };
238
+ var parseDynamicTools = (value) => {
239
+ if (!Array.isArray(value)) return null;
240
+ return value.flatMap((entry) => {
241
+ const tool = asObject(entry);
242
+ if (!tool) return [];
243
+ return [{
244
+ deferLoading: tool.deferLoading === true || tool.defer_loading === true,
245
+ description: asString(tool.description) ?? "",
246
+ inputSchema: asObject(tool.inputSchema) ?? asObject(tool.input_schema) ?? null,
247
+ name: asString(tool.name) ?? "unknown",
248
+ namespace: asString(tool.namespace)
249
+ }];
250
+ });
251
+ };
252
+ var captureTurnContext = (parsed, turnContexts) => {
253
+ const payload = asObject(parsed.payload);
254
+ if (!payload) return;
255
+ turnContexts.push({
256
+ payload,
257
+ timestamp: asString(parsed.timestamp)
258
+ });
259
+ };
260
+ var toThreadEvent = (parsed, sequence, includeRaw) => {
261
+ const payload = asObject(parsed.payload);
262
+ if (!payload) return null;
263
+ const payloadType = asString(payload.type);
264
+ const timestamp = asString(parsed.timestamp);
265
+ if (parsed.type === "event_msg") return buildEventMessage(payload, payloadType, includeRaw ? parsed : {}, sequence, timestamp);
266
+ if (parsed.type !== "response_item") return null;
267
+ return buildResponseItemEvent(payload, payloadType, includeRaw ? parsed : {}, sequence, timestamp);
268
+ };
269
+ var buildEventMessage = (payload, payloadType, raw, sequence, timestamp) => {
270
+ if (payloadType === "task_started") return createTaskStartedEvent(payload, raw, sequence, timestamp);
271
+ if (payloadType === "task_complete") return createTaskCompleteEvent(payload, raw, sequence, timestamp);
272
+ return null;
273
+ };
274
+ var buildResponseItemEvent = (payload, payloadType, raw, sequence, timestamp) => {
275
+ if (payloadType === "message") return createMessageEvent(payload, raw, sequence, timestamp);
276
+ if (payloadType === "user_message") return createUserMessageEvent(payload, raw, sequence, timestamp);
277
+ if (payloadType === "agent_message") return createAgentMessageEvent(payload, raw, sequence, timestamp);
278
+ if (payloadType === "function_call") return createToolCallEvent(payload, raw, sequence, timestamp);
279
+ if (payloadType === "function_call_output") return createToolOutputEvent(payload, raw, sequence, timestamp);
280
+ if (payloadType === "reasoning") return createReasoningEvent(payload, raw, sequence, timestamp);
281
+ if (payloadType === "token_count") return createTokenCountEvent(payload, raw, sequence, timestamp);
282
+ if (payloadType === "web_search_call" || payloadType === "web_search_end") return createWebSearchEvent(payload, raw, sequence, timestamp);
283
+ if (payloadType === "task_started") return createTaskStartedEvent(payload, raw, sequence, timestamp);
284
+ if (payloadType === "task_complete") return createTaskCompleteEvent(payload, raw, sequence, timestamp);
285
+ return null;
286
+ };
287
+ var createMessageEvent = (payload, raw, sequence, timestamp) => {
288
+ const role = asString(payload.role);
289
+ const content = payload.content;
290
+ if (!role || content === void 0) return null;
291
+ return {
292
+ isHiddenByDefault: shouldHideTranscriptText(role, extractText$1(content)),
293
+ kind: "message",
294
+ memoryCitation: null,
295
+ model: asString(payload.model),
296
+ phase: asString(payload.phase),
297
+ raw,
298
+ role,
299
+ sequence,
300
+ text: extractText$1(content),
301
+ timestamp,
302
+ variant: "message"
303
+ };
304
+ };
305
+ var createUserMessageEvent = (payload, raw, sequence, timestamp) => {
306
+ return {
307
+ isHiddenByDefault: shouldHideTranscriptText("user", asString(payload.message)?.trim() ?? ""),
308
+ kind: "message",
309
+ memoryCitation: null,
310
+ model: null,
311
+ phase: null,
312
+ raw,
313
+ role: "user",
314
+ sequence,
315
+ text: asString(payload.message)?.trim() ?? "",
316
+ timestamp,
317
+ variant: "user_message"
318
+ };
319
+ };
320
+ var createAgentMessageEvent = (payload, raw, sequence, timestamp) => {
321
+ return {
322
+ isHiddenByDefault: false,
323
+ kind: "message",
324
+ memoryCitation: payload.memory_citation ?? null,
325
+ model: asString(payload.model),
326
+ phase: asString(payload.phase),
327
+ raw,
328
+ role: "assistant",
329
+ sequence,
330
+ text: asString(payload.message)?.trim() ?? "",
331
+ timestamp,
332
+ variant: "agent_message"
333
+ };
334
+ };
335
+ var createToolCallEvent = (payload, raw, sequence, timestamp) => {
336
+ const name = asString(payload.name) ?? "unknown";
337
+ const argumentsText = asString(payload.arguments);
338
+ const parsedArguments = parseExecCommandArguments$1(argumentsText);
339
+ return {
340
+ argumentsParseFailed: parsedArguments.argumentsParseFailed,
341
+ argumentsText,
342
+ callId: asString(payload.call_id),
343
+ command: parsedArguments.cmd,
344
+ kind: "tool_call",
345
+ name,
346
+ raw,
347
+ sequence,
348
+ timestamp,
349
+ workdir: parsedArguments.workdir
350
+ };
351
+ };
352
+ var createToolOutputEvent = (payload, raw, sequence, timestamp) => {
353
+ const outputText = asString(payload.output) ?? "";
354
+ return {
355
+ callId: asString(payload.call_id),
356
+ exitCode: parseExitCode(outputText),
357
+ kind: "tool_output",
358
+ outputText,
359
+ raw,
360
+ sequence,
361
+ summary: formatToolOutputSummary$1(outputText),
362
+ timestamp,
363
+ wallTime: parseWallTime(outputText)
364
+ };
365
+ };
366
+ var createReasoningEvent = (payload, raw, sequence, timestamp) => {
367
+ return {
368
+ content: payload.content ?? null,
369
+ hasEncryptedContent: Boolean(asString(payload.encrypted_content)),
370
+ kind: "reasoning",
371
+ raw,
372
+ sequence,
373
+ summary: toStringArray(payload.summary),
374
+ timestamp
375
+ };
376
+ };
377
+ var createTokenCountEvent = (payload, raw, sequence, timestamp) => {
378
+ return {
379
+ info: payload.info ?? null,
380
+ kind: "token_count",
381
+ rateLimits: payload.rate_limits ?? null,
382
+ raw,
383
+ sequence,
384
+ timestamp
385
+ };
386
+ };
387
+ var createTaskStartedEvent = (payload, raw, sequence, timestamp) => {
388
+ return {
389
+ collaborationModeKind: asString(payload.collaboration_mode_kind),
390
+ kind: "task_started",
391
+ modelContextWindow: asNumber(payload.model_context_window),
392
+ raw,
393
+ sequence,
394
+ startedAt: asNumber(payload.started_at),
395
+ timestamp,
396
+ turnId: asString(payload.turn_id)
397
+ };
398
+ };
399
+ var createTaskCompleteEvent = (payload, raw, sequence, timestamp) => {
400
+ return {
401
+ completedAt: asNumber(payload.completed_at),
402
+ durationMs: asNumber(payload.duration_ms),
403
+ kind: "task_complete",
404
+ lastAgentMessage: asString(payload.last_agent_message),
405
+ raw,
406
+ sequence,
407
+ timestamp,
408
+ timeToFirstTokenMs: asNumber(payload.time_to_first_token_ms),
409
+ turnId: asString(payload.turn_id)
410
+ };
411
+ };
412
+ var createWebSearchEvent = (payload, raw, sequence, timestamp) => {
413
+ const payloadType = asString(payload.type);
414
+ return {
415
+ action: payload.action ?? null,
416
+ callId: asString(payload.call_id),
417
+ kind: "web_search",
418
+ phase: payloadType === "web_search_end" ? "end" : "call",
419
+ query: asString(payload.query),
420
+ raw,
421
+ sequence,
422
+ status: asString(payload.status),
423
+ timestamp
424
+ };
425
+ };
426
+ var updateTranscriptStats = (stats, event) => {
427
+ if (event.kind === "message") {
428
+ stats.messageCount += 1;
429
+ if (event.role === "assistant") stats.assistantMessageCount += 1;
430
+ if (event.role === "user") stats.userMessageCount += 1;
431
+ if (event.phase === "commentary") stats.commentaryCount += 1;
432
+ if (event.phase === "final_answer") stats.finalAnswerCount += 1;
433
+ return;
434
+ }
435
+ if (event.kind === "tool_call") {
436
+ stats.toolCallCount += 1;
437
+ if (event.name === "exec_command") stats.execCommandCount += 1;
438
+ return;
439
+ }
440
+ if (event.kind === "tool_output") {
441
+ stats.toolOutputCount += 1;
442
+ return;
443
+ }
444
+ if (event.kind === "web_search") stats.webSearchEventCount += 1;
445
+ };
446
+ var toStringArray = (value) => {
447
+ if (!Array.isArray(value)) return [];
448
+ return value.map((entry) => asString(entry)).filter((entry) => Boolean(entry));
449
+ };
450
+ var parseExitCode = (outputText) => {
451
+ const match = /Process exited with code (\d+)/u.exec(outputText);
452
+ return match ? Number(match[1]) : null;
453
+ };
454
+ var parseWallTime = (outputText) => {
455
+ return /Wall time: ([^\n]+)/u.exec(outputText)?.[1] ?? null;
456
+ };
457
+ var formatToolOutputSummary$1 = (outputText) => {
458
+ return outputText.split("\n").map((line) => line.trim()).filter(Boolean).filter((line) => {
459
+ return line.startsWith("Command: ") || line.startsWith("Process exited with code ") || line.startsWith("Wall time: ");
460
+ }).join("\n");
461
+ };
462
+ var parseExecCommandArguments$1 = (argumentsText) => {
463
+ if (!argumentsText) return {
464
+ argumentsParseFailed: false,
465
+ cmd: null,
466
+ workdir: null
467
+ };
468
+ try {
469
+ const parsed = JSON.parse(argumentsText);
470
+ return {
471
+ argumentsParseFailed: false,
472
+ cmd: typeof parsed.cmd === "string" ? parsed.cmd : null,
473
+ workdir: typeof parsed.workdir === "string" ? parsed.workdir : null
474
+ };
475
+ } catch {
476
+ return {
477
+ argumentsParseFailed: true,
478
+ cmd: null,
479
+ workdir: null
480
+ };
481
+ }
482
+ };
483
+ var extractText$1 = (content) => {
484
+ if (typeof content === "string") return content.trim();
485
+ if (Array.isArray(content)) return content.map((entry) => extractTextPart(entry)).filter(Boolean).join("\n\n").trim();
486
+ if (content && typeof content === "object") return asString(content.text)?.trim() ?? "";
487
+ return "";
488
+ };
489
+ var extractTextPart = (entry) => {
490
+ const objectValue = asObject(entry);
491
+ if (!objectValue) return "";
492
+ const type = asString(objectValue.type);
493
+ const text = asString(objectValue.text);
494
+ if (type === "input_image") return "[Image attached]";
495
+ return text ?? "";
496
+ };
497
+ var shouldHideTranscriptText = (role, text) => {
498
+ if (!text) return true;
499
+ if (role === "developer") return true;
500
+ return text.startsWith("# AGENTS.md instructions for ") || text.startsWith("<permissions instructions>") || text.startsWith("<app-context>") || text.startsWith("<environment_context>") || text.startsWith("<collaboration_mode>") || text.startsWith("<skills_instructions>") || text.startsWith("<plugins_instructions>") || text.includes("Filesystem sandboxing defines which files can be read or written.");
501
+ };
502
+ //#endregion
503
+ //#region ../../src/lib/ui-cache.ts
504
+ var CACHE_DIR = path.join(os.tmpdir(), "spiracha-ui-cache");
505
+ var CACHE_ENVELOPE_VERSION = 1;
506
+ var ensureCacheDir = async () => {
507
+ await mkdir(CACHE_DIR, { recursive: true });
508
+ };
509
+ var toCachePath = (key) => {
510
+ const safeKey = key.replace(/[^a-zA-Z0-9._-]/gu, "_");
511
+ return path.join(CACHE_DIR, `${safeKey}-${hashCacheKeyParts(key)}.json`);
512
+ };
513
+ var hashCacheKeyParts = (...parts) => {
514
+ return createHash("sha1").update(parts.join("|")).digest("hex");
515
+ };
516
+ var getFileFingerprint = async (filePath) => {
517
+ const metadata = await stat(filePath);
518
+ return `${filePath}:${metadata.size}:${metadata.mtimeMs}`;
519
+ };
520
+ var getCachedJson = async (key) => {
521
+ await ensureCacheDir();
522
+ const filePath = toCachePath(key);
523
+ const file = Bun.file(filePath);
524
+ if (!await file.exists()) return null;
525
+ let parsed;
526
+ try {
527
+ parsed = await file.json();
528
+ } catch {
529
+ await rm(filePath, { force: true });
530
+ return null;
531
+ }
532
+ if (parsed && typeof parsed === "object" && "version" in parsed && parsed.version === CACHE_ENVELOPE_VERSION && "value" in parsed) return parsed.value;
533
+ return parsed;
534
+ };
535
+ var setCachedJson = async (key, value) => {
536
+ await ensureCacheDir();
537
+ const filePath = toCachePath(key);
538
+ const tempPath = `${filePath}.${randomUUID()}.tmp`;
539
+ const envelope = {
540
+ value,
541
+ version: CACHE_ENVELOPE_VERSION
542
+ };
543
+ await Bun.write(tempPath, JSON.stringify(envelope));
544
+ await rename(tempPath, filePath);
545
+ };
546
+ var withCachedJson = async (key, loader) => {
547
+ const filePath = toCachePath(key);
548
+ const existedBeforeRead = await Bun.file(filePath).exists();
549
+ const cached = await getCachedJson(key);
550
+ if (cached !== null || existedBeforeRead && await Bun.file(filePath).exists()) return cached;
551
+ const value = await loader();
552
+ await setCachedJson(key, value);
553
+ return value;
554
+ };
555
+ var invalidateCacheByPrefix = async (...prefixes) => {
556
+ await ensureCacheDir();
557
+ const entries = await readdir(CACHE_DIR);
558
+ await Promise.all(entries.filter((entry) => prefixes.some((prefix) => entry.startsWith(prefix))).map((entry) => rm(path.join(CACHE_DIR, entry), { force: true })));
559
+ };
560
+ //#endregion
561
+ //#region ../../src/lib/codex-thread-cache.ts
562
+ var LARGE_THREAD_SIZE_BYTES = 100 * 1024 * 1024;
563
+ var getCachedParsedCodexTranscript = async (sessionFile) => {
564
+ const fingerprint = await getFileFingerprint(sessionFile);
565
+ return withCachedJson(`thread-${hashCacheKeyParts(path.basename(sessionFile), fingerprint)}`, async () => parseCodexTranscriptFile(sessionFile));
566
+ };
567
+ var getThreadRolloutLoadState = async (sessionFile, largeTranscriptThresholdBytes = LARGE_THREAD_SIZE_BYTES) => {
568
+ const metadata = await stat(sessionFile);
569
+ return {
570
+ fileSizeBytes: metadata.size,
571
+ shouldDeferTranscriptLoad: metadata.size > largeTranscriptThresholdBytes
572
+ };
573
+ };
574
+ var getCachedThreadTranscriptPreview = async (sessionFile, options = {}) => {
575
+ const threshold = options.largeTranscriptThresholdBytes ?? 104857600;
576
+ const previewEventLimit = options.previewEventLimit ?? 200;
577
+ const fingerprint = await getFileFingerprint(sessionFile);
578
+ const { fileSizeBytes, shouldDeferTranscriptLoad } = await getThreadRolloutLoadState(sessionFile, threshold);
579
+ return withCachedJson(`thread-preview-${hashCacheKeyParts(path.basename(sessionFile), fingerprint, String(threshold), String(previewEventLimit))}`, async () => {
580
+ if (!shouldDeferTranscriptLoad) return parseCodexTranscriptFile(sessionFile, { sourceFileSizeBytes: fileSizeBytes });
581
+ return parseCodexTranscriptFile(sessionFile, {
582
+ includeRaw: false,
583
+ maxEvents: previewEventLimit,
584
+ maxTurnContexts: 0,
585
+ sourceFileSizeBytes: fileSizeBytes
586
+ });
587
+ });
588
+ };
589
+ //#endregion
590
+ //#region ../../src/lib/sqlite-retry.ts
591
+ var DEFAULT_RETRY_DELAYS_MS = [
592
+ 40,
593
+ 120,
594
+ 250
595
+ ];
596
+ var SLEEP_BUFFER = new Int32Array(new SharedArrayBuffer(4));
597
+ var sleepSync = (delayMs) => {
598
+ if (delayMs <= 0) return;
599
+ Atomics.wait(SLEEP_BUFFER, 0, 0, delayMs);
600
+ };
601
+ var runWithSqliteRetry = ({ action, delaysMs = DEFAULT_RETRY_DELAYS_MS, sleep = sleepSync }) => {
602
+ let attempt = 0;
603
+ while (true) try {
604
+ return action();
605
+ } catch (error) {
606
+ if (!isRetryableSqliteError(error) || attempt >= delaysMs.length) throw error;
607
+ sleep(delaysMs[attempt] ?? 0);
608
+ attempt += 1;
609
+ }
610
+ };
611
+ //#endregion
612
+ //#region ../../src/lib/codex-browser-db.ts
613
+ var toTimestampMs = (thread) => {
614
+ return thread.updated_at_ms ?? thread.updated_at * 1e3;
615
+ };
616
+ var parseDynamicToolRow = (row) => {
617
+ return {
618
+ deferLoading: Number(row.defer_loading ?? 0) === 1,
619
+ description: String(row.description ?? ""),
620
+ inputSchema: parseJsonSafely$1(typeof row.input_schema === "string" ? row.input_schema : null),
621
+ name: String(row.name ?? "unknown"),
622
+ namespace: typeof row.namespace === "string" ? row.namespace : null,
623
+ position: Number(row.position ?? 0),
624
+ threadId: String(row.thread_id)
625
+ };
626
+ };
627
+ var parseJsonSafely$1 = (value) => {
628
+ if (!value) return null;
629
+ try {
630
+ return JSON.parse(value);
631
+ } catch {
632
+ return null;
633
+ }
634
+ };
635
+ var withReadonlyDb = (dbPath, callback) => {
636
+ return runWithSqliteRetry({ action: () => {
637
+ const db = new Database(dbPath, { readonly: true });
638
+ db.exec("PRAGMA busy_timeout = 5000");
639
+ try {
640
+ return callback(db);
641
+ } finally {
642
+ db.close();
643
+ }
644
+ } });
645
+ };
646
+ var withWritableDb = (dbPath, callback) => {
647
+ const db = runWithSqliteRetry({ action: () => {
648
+ const connection = new Database(dbPath);
649
+ connection.exec("PRAGMA busy_timeout = 5000");
650
+ return connection;
651
+ } });
652
+ try {
653
+ return callback(db);
654
+ } finally {
655
+ db.close();
656
+ }
657
+ };
658
+ var resolveCodexThreadDbPath = () => {
659
+ const configuredDbPath = process.env.SPIRACHA_CODEX_DB?.trim();
660
+ if (configuredDbPath) return configuredDbPath;
661
+ const candidates = [
662
+ DEFAULT_DB_PATH,
663
+ path.join(DEFAULT_CODEX_DIR, "sqlite", "state_5.sqlite"),
664
+ path.join(os.homedir(), ".codex", "state_5.sqlite")
665
+ ];
666
+ for (const candidate of candidates) try {
667
+ runWithSqliteRetry({ action: () => {
668
+ const connection = new Database(candidate, { readonly: true });
669
+ connection.exec("PRAGMA busy_timeout = 1500");
670
+ return connection;
671
+ } }).close();
672
+ return candidate;
673
+ } catch {}
674
+ throw new Error(`Unable to open Codex thread database. Tried: ${candidates.join(", ")}`);
675
+ };
676
+ var readAllThreads = (dbPath) => {
677
+ return withReadonlyDb(dbPath, (db) => {
678
+ return db.query("SELECT * FROM threads ORDER BY COALESCE(updated_at_ms, updated_at * 1000) DESC, id DESC").all();
679
+ });
680
+ };
681
+ var filterThreadsByProject = (threads, projectName) => {
682
+ if (!projectName) return threads;
683
+ return threads.filter((thread) => getPortablePathBasename(thread.cwd) === projectName);
684
+ };
685
+ var buildProjectSummaryMap = (threads) => {
686
+ const projectMap = /* @__PURE__ */ new Map();
687
+ for (const thread of threads) {
688
+ const projectName = getPortablePathBasename(thread.cwd);
689
+ if (!projectName) continue;
690
+ const current = projectMap.get(projectName) ?? {
691
+ archivedThreadCount: 0,
692
+ cwdPaths: /* @__PURE__ */ new Set(),
693
+ lastUpdatedAtMs: null,
694
+ modelNames: /* @__PURE__ */ new Set(),
695
+ name: projectName,
696
+ threadCount: 0,
697
+ totalTokens: 0
698
+ };
699
+ current.archivedThreadCount += thread.archived ? 1 : 0;
700
+ current.cwdPaths.add(thread.cwd);
701
+ current.lastUpdatedAtMs = Math.max(current.lastUpdatedAtMs ?? 0, toTimestampMs(thread));
702
+ if (thread.model) current.modelNames.add(thread.model);
703
+ current.threadCount += 1;
704
+ current.totalTokens += thread.tokens_used;
705
+ projectMap.set(projectName, current);
706
+ }
707
+ return projectMap;
708
+ };
709
+ var mapProjectSummaries = (projectMap) => {
710
+ return [...projectMap.values()].map((project) => {
711
+ return {
712
+ archivedThreadCount: project.archivedThreadCount,
713
+ cwdPaths: [...project.cwdPaths].sort(),
714
+ lastUpdatedAtMs: project.lastUpdatedAtMs,
715
+ modelNames: [...project.modelNames].sort(),
716
+ name: project.name,
717
+ threadCount: project.threadCount,
718
+ totalTokens: project.totalTokens
719
+ };
720
+ }).sort((left, right) => {
721
+ if (left.totalTokens !== right.totalTokens) return right.totalTokens - left.totalTokens;
722
+ return left.name.localeCompare(right.name);
723
+ });
724
+ };
725
+ var getRelationsForThread = (db, threadId, existingTableNames) => {
726
+ if (!existingTableNames.has("thread_spawn_edges")) return {
727
+ childEdges: [],
728
+ parentThreadId: null
729
+ };
730
+ const parentRow = db.query("SELECT parent_thread_id, child_thread_id, status FROM thread_spawn_edges WHERE child_thread_id = ? LIMIT 1").get(threadId);
731
+ return {
732
+ childEdges: db.query("SELECT parent_thread_id, child_thread_id, status FROM thread_spawn_edges WHERE parent_thread_id = ? ORDER BY child_thread_id ASC").all(threadId),
733
+ parentThreadId: parentRow?.parent_thread_id ?? null
734
+ };
735
+ };
736
+ var getExistingTableNames = (db) => {
737
+ const rows = db.query("SELECT name FROM sqlite_master WHERE type = ?").all("table");
738
+ return new Set(rows.map((row) => row.name));
739
+ };
740
+ var getThreadDeleteTargets = (db, threadIds) => {
741
+ if (threadIds.length === 0) return [];
742
+ const placeholders = threadIds.map(() => "?").join(", ");
743
+ return db.query(`SELECT id, rollout_path FROM threads WHERE id IN (${placeholders})`).all(...threadIds);
744
+ };
745
+ var deleteThreadIds = (db, threadIds) => {
746
+ if (threadIds.length === 0) return {
747
+ deletedSessionFiles: [],
748
+ deletedThreadIds: []
749
+ };
750
+ const existingTableNames = getExistingTableNames(db);
751
+ const threadTargets = getThreadDeleteTargets(db, threadIds);
752
+ const existingIds = threadTargets.map((target) => target.id);
753
+ if (existingIds.length === 0) return {
754
+ deletedSessionFiles: [],
755
+ deletedThreadIds: []
756
+ };
757
+ db.transaction((ids) => {
758
+ const placeholders = ids.map(() => "?").join(", ");
759
+ if (existingTableNames.has("thread_dynamic_tools")) db.query(`DELETE FROM thread_dynamic_tools WHERE thread_id IN (${placeholders})`).run(...ids);
760
+ if (existingTableNames.has("thread_goals")) db.query(`DELETE FROM thread_goals WHERE thread_id IN (${placeholders})`).run(...ids);
761
+ if (existingTableNames.has("stage1_outputs")) db.query(`DELETE FROM stage1_outputs WHERE thread_id IN (${placeholders})`).run(...ids);
762
+ if (existingTableNames.has("thread_spawn_edges")) db.query(`DELETE FROM thread_spawn_edges WHERE parent_thread_id IN (${placeholders}) OR child_thread_id IN (${placeholders})`).run(...ids, ...ids);
763
+ db.query(`DELETE FROM threads WHERE id IN (${placeholders})`).run(...ids);
764
+ })(existingIds);
765
+ return {
766
+ deletedSessionFiles: threadTargets.map((target) => target.rollout_path),
767
+ deletedThreadIds: existingIds
768
+ };
769
+ };
770
+ var deleteThreadSessionFiles = async (sessionFiles) => {
771
+ const uniqueSessionFiles = [...new Set(sessionFiles)];
772
+ await Promise.all(uniqueSessionFiles.map((sessionFile) => rm(sessionFile, { force: true })));
773
+ return uniqueSessionFiles;
774
+ };
775
+ var listCodexProjects = (dbPath) => {
776
+ return mapProjectSummaries(buildProjectSummaryMap(readAllThreads(dbPath)));
777
+ };
778
+ var compactThreadListRow = (thread) => {
779
+ return {
780
+ ...thread,
781
+ preview: cleanInlineTitle(thread.preview || thread.first_user_message || ""),
782
+ title: cleanInlineTitle(thread.title)
783
+ };
784
+ };
785
+ var listProjectThreads = async (dbPath, projectName, options = {}) => {
786
+ const threads = filterThreadsByProject(readAllThreads(dbPath), projectName);
787
+ return (await Promise.all(threads.map(async (thread) => {
788
+ const rollout = await getThreadRolloutLoadState(thread.rollout_path, options.largeTranscriptThresholdBytes);
789
+ if (rollout.shouldDeferTranscriptLoad) return {
790
+ project: projectName,
791
+ rolloutSizeBytes: rollout.fileSizeBytes,
792
+ stats: {
793
+ deferred: true,
794
+ execCommandCount: 0,
795
+ toolCallCount: 0,
796
+ webSearchEventCount: 0
797
+ },
798
+ thread: compactThreadListRow(thread)
799
+ };
800
+ const transcript = await getCachedParsedCodexTranscript(thread.rollout_path);
801
+ return {
802
+ project: projectName,
803
+ rolloutSizeBytes: rollout.fileSizeBytes,
804
+ stats: {
805
+ deferred: false,
806
+ execCommandCount: transcript.stats.execCommandCount,
807
+ toolCallCount: transcript.stats.toolCallCount,
808
+ webSearchEventCount: transcript.stats.webSearchEventCount
809
+ },
810
+ thread: compactThreadListRow(thread)
811
+ };
812
+ }))).sort((left, right) => toTimestampMs(right.thread) - toTimestampMs(left.thread));
813
+ };
814
+ var getThreadBrowseData = (dbPath, threadId) => {
815
+ return withReadonlyDb(dbPath, (db) => {
816
+ const existingTableNames = getExistingTableNames(db);
817
+ const thread = db.query("SELECT * FROM threads WHERE id = ? LIMIT 1").get(threadId);
818
+ if (!thread) throw new Error(`Thread not found: ${threadId}`);
819
+ return {
820
+ dynamicTools: (existingTableNames.has("thread_dynamic_tools") ? db.query("SELECT thread_id, position, name, description, input_schema, defer_loading, namespace FROM thread_dynamic_tools WHERE thread_id = ? ORDER BY position ASC").all(threadId) : []).map((row) => parseDynamicToolRow(row)),
821
+ project: getPortablePathBasename(thread.cwd),
822
+ relations: getRelationsForThread(db, threadId, existingTableNames),
823
+ thread
824
+ };
825
+ });
826
+ };
827
+ var getCodexDashboardSummary = (dbPath) => {
828
+ const threads = readAllThreads(dbPath);
829
+ const projects = mapProjectSummaries(buildProjectSummaryMap(threads));
830
+ const threadsWithRelations = withReadonlyDb(dbPath, (db) => {
831
+ if (!getExistingTableNames(db).has("thread_spawn_edges")) return 0;
832
+ const rows = db.query("SELECT parent_thread_id, child_thread_id FROM thread_spawn_edges").all();
833
+ return new Set(rows.flatMap((row) => [row.parent_thread_id, row.child_thread_id])).size;
834
+ });
835
+ return {
836
+ activeThreads: threads.filter((thread) => !thread.archived).length,
837
+ archivedThreads: threads.filter((thread) => Boolean(thread.archived)).length,
838
+ recentThreads: threads.slice(0, 5),
839
+ threadsWithRelations,
840
+ topProjectsByThreadCount: [...projects].sort((left, right) => {
841
+ if (left.threadCount !== right.threadCount) return right.threadCount - left.threadCount;
842
+ return left.name.localeCompare(right.name);
843
+ }).slice(0, 5),
844
+ topProjectsByTokens: projects.slice(0, 5),
845
+ totalProjects: projects.length,
846
+ totalThreads: threads.length,
847
+ totalTokens: threads.reduce((sum, thread) => sum + thread.tokens_used, 0)
848
+ };
849
+ };
850
+ var deleteCodexThread = async (dbPath, threadId, options = {}) => {
851
+ const result = withWritableDb(dbPath, (db) => {
852
+ return deleteThreadIds(db, [threadId]);
853
+ });
854
+ try {
855
+ if (options.deleteSessionFiles) return {
856
+ ...result,
857
+ deletedSessionFiles: await deleteThreadSessionFiles(result.deletedSessionFiles)
858
+ };
859
+ return {
860
+ ...result,
861
+ deletedSessionFiles: []
862
+ };
863
+ } finally {
864
+ await invalidateCodexUiCaches();
865
+ }
866
+ };
867
+ var deleteCodexThreads = async (dbPath, threadIds, options = {}) => {
868
+ const result = withWritableDb(dbPath, (db) => {
869
+ return deleteThreadIds(db, threadIds);
870
+ });
871
+ try {
872
+ if (options.deleteSessionFiles) return {
873
+ ...result,
874
+ deletedSessionFiles: await deleteThreadSessionFiles(result.deletedSessionFiles)
875
+ };
876
+ return {
877
+ ...result,
878
+ deletedSessionFiles: []
879
+ };
880
+ } finally {
881
+ await invalidateCodexUiCaches();
882
+ }
883
+ };
884
+ var deleteCodexProject = async (dbPath, projectName, options = {}) => {
885
+ const result = withWritableDb(dbPath, (db) => {
886
+ return {
887
+ ...deleteThreadIds(db, db.query("SELECT id, cwd FROM threads").all().filter((thread) => getPortablePathBasename(thread.cwd) === projectName).map((thread) => thread.id)),
888
+ projectName
889
+ };
890
+ });
891
+ try {
892
+ if (options.deleteSessionFiles) return {
893
+ ...result,
894
+ deletedSessionFiles: await deleteThreadSessionFiles(result.deletedSessionFiles)
895
+ };
896
+ return {
897
+ ...result,
898
+ deletedSessionFiles: []
899
+ };
900
+ } finally {
901
+ await invalidateCodexUiCaches();
902
+ }
903
+ };
904
+ var listScopedThreads = (dbPath, projectName) => {
905
+ return filterThreadsByProject(readAllThreads(dbPath), projectName);
906
+ };
907
+ var invalidateCodexUiCaches = async () => {
908
+ await invalidateCacheByPrefix("analytics-", "thread-");
909
+ };
910
+ //#endregion
911
+ //#region ../../src/lib/codex-analytics.ts
912
+ var roundToTwoDecimals = (value) => {
913
+ return Number(value.toFixed(2));
914
+ };
915
+ var incrementCount = (counts, key) => {
916
+ counts.set(key, (counts.get(key) ?? 0) + 1);
917
+ };
918
+ var toDistribution = (counts) => {
919
+ return [...counts.entries()].map(([label, count]) => ({
920
+ count,
921
+ label
922
+ })).sort((left, right) => {
923
+ if (left.count !== right.count) return right.count - left.count;
924
+ return left.label.localeCompare(right.label);
925
+ });
926
+ };
927
+ var buildModelsByTokens = (threads) => {
928
+ const models = /* @__PURE__ */ new Map();
929
+ for (const thread of threads) {
930
+ const model = thread.model ?? "unknown";
931
+ const current = models.get(model) ?? {
932
+ threadCount: 0,
933
+ totalTokens: 0
934
+ };
935
+ current.threadCount += 1;
936
+ current.totalTokens += thread.tokens_used;
937
+ models.set(model, current);
938
+ }
939
+ return [...models.entries()].map(([model, value]) => ({
940
+ model,
941
+ ...value
942
+ })).sort((left, right) => {
943
+ if (left.totalTokens !== right.totalTokens) return right.totalTokens - left.totalTokens;
944
+ return left.model.localeCompare(right.model);
945
+ });
946
+ };
947
+ var buildAnalyticsCacheKey = async (dbPath, threads, project) => {
948
+ const dbFingerprint = await getFileFingerprint(dbPath);
949
+ const rolloutFingerprints = await Promise.all(threads.map((thread) => getFileFingerprint(thread.rollout_path)));
950
+ return `analytics-${hashCacheKeyParts(dbFingerprint, project ?? "all", ...rolloutFingerprints)}`;
951
+ };
952
+ var computeCodexAnalytics = async (threads) => {
953
+ const totalTokens = threads.reduce((sum, thread) => sum + thread.tokens_used, 0);
954
+ const projectNames = new Set(threads.map((thread) => getPortablePathBasename(thread.cwd)).filter(Boolean));
955
+ const toolUsage = /* @__PURE__ */ new Map();
956
+ const transcripts = await Promise.all(threads.map((thread) => getCachedParsedCodexTranscript(thread.rollout_path)));
957
+ let threadsWithWebSearch = 0;
958
+ for (const transcript of transcripts) {
959
+ if (transcript.stats.webSearchEventCount > 0) threadsWithWebSearch += 1;
960
+ for (const event of transcript.events) if (event.kind === "tool_call") incrementCount(toolUsage, event.name);
961
+ }
962
+ return {
963
+ modelsByTokens: buildModelsByTokens(threads),
964
+ summary: {
965
+ archivedThreads: threads.filter((thread) => Boolean(thread.archived)).length,
966
+ averageTokensPerThread: threads.length === 0 ? 0 : roundToTwoDecimals(totalTokens / threads.length),
967
+ distinctToolNames: toolUsage.size,
968
+ threadsWithWebSearch,
969
+ totalProjects: projectNames.size,
970
+ totalThreads: threads.length,
971
+ totalTokens
972
+ },
973
+ toolUsage: toDistribution(toolUsage).map((item) => ({
974
+ count: item.count,
975
+ name: item.label
976
+ }))
977
+ };
978
+ };
979
+ var getCodexAnalytics = async (input) => {
980
+ const threads = listScopedThreads(input.dbPath, input.project);
981
+ return withCachedJson(await buildAnalyticsCacheKey(input.dbPath, threads, input.project), async () => computeCodexAnalytics(threads));
982
+ };
983
+ //#endregion
984
+ //#region ../../src/lib/codex-exporter-db.ts
985
+ var matchesFilters = (value, options) => {
986
+ return matchesCwdFilter(value, options.cwdFilter) && matchesProjectFilter(value, options.projectFilter);
987
+ };
988
+ var toCodexRelativePath = (targetPath) => {
989
+ const codexRoot = path.resolve(DEFAULT_CODEX_DIR);
990
+ const normalized = path.resolve(targetPath);
991
+ if (normalized.startsWith(`${codexRoot}${path.sep}`)) return path.relative(codexRoot, normalized);
992
+ return normalized;
993
+ };
994
+ var matchesCwdFilter = (value, cwdFilter) => {
995
+ if (!cwdFilter) return true;
996
+ return value === cwdFilter;
997
+ };
998
+ var matchesProjectFilter = (value, projectFilter) => {
999
+ if (!projectFilter) return true;
1000
+ if (!value) return false;
1001
+ return getPortablePathBasename(value) === projectFilter;
1002
+ };
1003
+ //#endregion
1004
+ //#region ../../src/lib/codex-exporter-transcript.ts
1005
+ var convertSessionFile = async (target, options) => {
1006
+ let transcriptState;
1007
+ try {
1008
+ transcriptState = await collectCodexTranscript(target.sessionFile, options);
1009
+ } catch (error) {
1010
+ const message = error instanceof Error ? error.message : String(error);
1011
+ throw new Error(`Failed to read Codex transcript ${target.sessionFile}: ${message}`);
1012
+ }
1013
+ if (!matchesFilters(target.thread?.cwd ?? transcriptState.sessionMeta.cwd ?? null, options)) return null;
1014
+ if (transcriptState.sections.length === 0) return null;
1015
+ if (options.optimized) return transcriptState.sections.join("\n\n").trimEnd() + "\n";
1016
+ const title = getTitle(target, transcriptState.sessionMeta);
1017
+ const metadata = buildMetadataEntries(target, transcriptState.sessionMeta, options);
1018
+ return [
1019
+ renderDocumentTitle(title, options.outputFormat),
1020
+ "",
1021
+ renderMetadataBlock(metadata, options.outputFormat),
1022
+ ...transcriptState.sections
1023
+ ].filter(Boolean).join("\n").trimEnd() + "\n";
1024
+ };
1025
+ var writeSessionFileExport = async (target, options, outputPath, transform = (text) => text) => {
1026
+ const transcriptOutputPath = `${outputPath}.transcript.tmp`;
1027
+ const transcriptStream = await createExportWriteStream(transcriptOutputPath);
1028
+ const state = {
1029
+ assistantModel: target.thread?.model ?? null,
1030
+ sections: [],
1031
+ sessionMeta: {},
1032
+ startedTranscript: false
1033
+ };
1034
+ let wroteSection = false;
1035
+ try {
1036
+ for await (const parsed of readJsonlObjects(target.sessionFile)) {
1037
+ captureSessionMeta(parsed, state.sessionMeta);
1038
+ const block = renderCodexTranscriptRecord(parsed, options, state);
1039
+ if (!block) continue;
1040
+ transcriptStream.write(transform(wroteSection ? `${getSectionSeparator(options)}${block}` : block));
1041
+ wroteSection = true;
1042
+ }
1043
+ } catch (error) {
1044
+ transcriptStream.destroy();
1045
+ throw error;
1046
+ }
1047
+ await finalizeExportWriteStream(transcriptStream);
1048
+ if (!matchesFilters(target.thread?.cwd ?? state.sessionMeta.cwd ?? null, options) || !wroteSection) {
1049
+ await rm(transcriptOutputPath, { force: true });
1050
+ return false;
1051
+ }
1052
+ const outputStream = await createExportWriteStream(outputPath);
1053
+ const prefix = buildStreamExportPrefix(target, state.sessionMeta, options);
1054
+ if (prefix) outputStream.write(transform(prefix));
1055
+ const transcriptReadStream = createReadStream(transcriptOutputPath, { encoding: "utf8" });
1056
+ transcriptReadStream.pipe(outputStream, { end: false });
1057
+ await finished(transcriptReadStream);
1058
+ outputStream.write("\n");
1059
+ await finalizeExportWriteStream(outputStream);
1060
+ await rm(transcriptOutputPath, { force: true });
1061
+ return true;
1062
+ };
1063
+ var collectCodexTranscript = async (sessionFile, options) => {
1064
+ const state = {
1065
+ assistantModel: null,
1066
+ sections: [],
1067
+ sessionMeta: {},
1068
+ startedTranscript: false
1069
+ };
1070
+ for await (const parsed of readJsonlObjects(sessionFile)) processCodexTranscriptRecord(parsed, options, state);
1071
+ return state;
1072
+ };
1073
+ var getSectionSeparator = (options) => {
1074
+ return options.optimized ? "\n\n" : "\n";
1075
+ };
1076
+ var processCodexTranscriptRecord = (parsed, options, state) => {
1077
+ captureSessionMeta(parsed, state.sessionMeta);
1078
+ const block = renderCodexTranscriptRecord(parsed, options, state);
1079
+ if (block) state.sections.push(block);
1080
+ };
1081
+ var renderCodexTranscriptRecord = (parsed, options, state) => {
1082
+ const message = extractMessageRecord(parsed);
1083
+ if (message) return processCodexMessageRecord(message, options, state);
1084
+ if (!options.includeTools) return "";
1085
+ const tool = extractToolRecord(parsed);
1086
+ if (!tool) return "";
1087
+ return options.optimized ? renderCompactToolBlock(tool, options.outputFormat) : renderToolBlock(tool, options.outputFormat);
1088
+ };
1089
+ var processCodexMessageRecord = (message, options, state) => {
1090
+ if (options.optimized) return processOptimizedCodexMessageRecord(message, options, state);
1091
+ return renderMessageBlock(message, options.outputFormat, state.assistantModel, options.includeCommentary);
1092
+ };
1093
+ var processOptimizedCodexMessageRecord = (message, options, state) => {
1094
+ if (message.role !== "user" && message.role !== "assistant") return "";
1095
+ if (message.role === "assistant" && message.phase === "commentary" && !options.includeCommentary) return "";
1096
+ const compact = compactMessageText(message, true);
1097
+ if (!compact) return "";
1098
+ if (!state.startedTranscript) {
1099
+ if (shouldSkipOptimizedPrelude(message.role, compact)) return "";
1100
+ state.startedTranscript = true;
1101
+ }
1102
+ return renderCompactBlock(message, compact, options.outputFormat, state.assistantModel);
1103
+ };
1104
+ var buildStreamExportPrefix = (target, sessionMeta, options) => {
1105
+ if (options.optimized) return "";
1106
+ const title = getTitle(target, sessionMeta);
1107
+ const metadata = buildMetadataEntries(target, sessionMeta, options);
1108
+ return `${[
1109
+ renderDocumentTitle(title, options.outputFormat),
1110
+ "",
1111
+ renderMetadataBlock(metadata, options.outputFormat)
1112
+ ].filter(Boolean).join("\n")}\n`;
1113
+ };
1114
+ var compactMessageText = (message, optimized) => {
1115
+ const cleaned = stripPreviewBlock(extractText(message.content));
1116
+ return optimized ? optimizePlainText(optimizeRenderedText(cleaned)) : cleaned.trim();
1117
+ };
1118
+ var formatToolOutputSummary = (outputText, outputFormat) => {
1119
+ if (!outputText) return "";
1120
+ const lines = outputText.split("\n").map((line) => line.trim()).filter(Boolean);
1121
+ if (lines.length === 0) return "";
1122
+ const summaryLines = [];
1123
+ const command = lines.find((line) => line.startsWith("Command: "));
1124
+ const exit = lines.find((line) => line.startsWith("Process exited with code "));
1125
+ const wall = lines.find((line) => line.startsWith("Wall time: "));
1126
+ if (command) summaryLines.push(command);
1127
+ if (exit) summaryLines.push(exit);
1128
+ if (wall) summaryLines.push(wall);
1129
+ if (outputFormat === "md") return summaryLines.map((line) => `*${line}*`).join("\n");
1130
+ return summaryLines.join("\n");
1131
+ };
1132
+ var parseExecCommandArguments = (argumentsText) => {
1133
+ if (!argumentsText) return {
1134
+ argumentsParseFailed: false,
1135
+ cmd: null,
1136
+ workdir: null
1137
+ };
1138
+ try {
1139
+ const parsed = JSON.parse(argumentsText);
1140
+ return {
1141
+ argumentsParseFailed: false,
1142
+ cmd: typeof parsed.cmd === "string" ? parsed.cmd : null,
1143
+ workdir: typeof parsed.workdir === "string" ? parsed.workdir : null
1144
+ };
1145
+ } catch {
1146
+ return {
1147
+ argumentsParseFailed: true,
1148
+ cmd: null,
1149
+ workdir: null
1150
+ };
1151
+ }
1152
+ };
1153
+ var getTitle = (target, sessionMeta) => {
1154
+ if (target.thread?.title) return cleanInlineTitle(target.thread.title);
1155
+ return sessionMeta.id ?? path.basename(target.sessionFile, ".jsonl");
1156
+ };
1157
+ var shouldSkipOptimizedPrelude = (role, text) => {
1158
+ if (role !== "user") return true;
1159
+ return text.startsWith("AGENTS.md instructions for ") || text.startsWith("# AGENTS.md instructions for ") || text.startsWith("<permissions instructions>") || text.startsWith("<environment_context>") || text.startsWith("<app-context>") || text.startsWith("<collaboration_mode>") || text.startsWith("<skills_instructions>") || text.startsWith("You are Codex, a coding agent based on GPT-5.") || text.startsWith("Read this before making changes.") || text.includes("Filesystem sandboxing defines which files can be read or written.") || text.includes("approval_policy") || text.includes("base_instructions");
1160
+ };
1161
+ var buildMetadataEntries = (target, sessionMeta, options) => {
1162
+ return [
1163
+ ...buildCodexExportIdentityMetadata(target, sessionMeta),
1164
+ ...buildCodexExportPathMetadata(target, options),
1165
+ ...buildCodexRelationMetadata(target),
1166
+ ...buildCodexThreadMetadata(target, sessionMeta),
1167
+ ...buildCodexAgentMetadata(target)
1168
+ ];
1169
+ };
1170
+ var buildCodexExportIdentityMetadata = (target, sessionMeta) => {
1171
+ const thread = target.thread;
1172
+ return [
1173
+ {
1174
+ key: "exported_from",
1175
+ value: thread ? "thread_db_and_session_jsonl" : "session_jsonl_fallback"
1176
+ },
1177
+ {
1178
+ key: "fallback_reason",
1179
+ value: target.fallbackReason
1180
+ },
1181
+ {
1182
+ key: "thread_id",
1183
+ value: thread?.id ?? sessionMeta.id ?? null
1184
+ },
1185
+ {
1186
+ key: "title",
1187
+ value: thread?.title || null
1188
+ }
1189
+ ];
1190
+ };
1191
+ var buildCodexExportPathMetadata = (target, options) => {
1192
+ const relativeOutputPath = target.outputRelativePath;
1193
+ return [
1194
+ {
1195
+ key: "source_output_relative_path",
1196
+ value: relativeOutputPath
1197
+ },
1198
+ {
1199
+ key: options.outputFormat === "md" ? "source_markdown_path" : "source_text_path",
1200
+ value: relativeOutputPath
1201
+ },
1202
+ {
1203
+ key: "rollout_path",
1204
+ value: target.sessionFile
1205
+ },
1206
+ {
1207
+ key: "rollout_path_relative_to_codex",
1208
+ value: toCodexRelativePath(target.sessionFile)
1209
+ }
1210
+ ];
1211
+ };
1212
+ var buildCodexRelationMetadata = (target) => {
1213
+ const childThreadIds = target.relations.childEdges.map((edge) => edge.child_thread_id);
1214
+ const childEdges = target.relations.childEdges.map((edge) => ({
1215
+ child_thread_id: edge.child_thread_id,
1216
+ status: edge.status
1217
+ }));
1218
+ return [
1219
+ {
1220
+ key: "parent_thread_id",
1221
+ value: target.relations.parentThreadId
1222
+ },
1223
+ {
1224
+ key: "child_thread_ids",
1225
+ value: childThreadIds
1226
+ },
1227
+ {
1228
+ key: "spawn_edges",
1229
+ value: childEdges
1230
+ }
1231
+ ];
1232
+ };
1233
+ var buildCodexThreadMetadata = (target, sessionMeta) => {
1234
+ return [...buildCodexThreadTimingMetadata(target, sessionMeta), ...buildCodexThreadIdentityMetadata(target, sessionMeta)];
1235
+ };
1236
+ var buildCodexThreadTimingMetadata = (target, sessionMeta) => {
1237
+ const thread = target.thread;
1238
+ return [
1239
+ {
1240
+ key: "created_at_unix",
1241
+ value: thread?.created_at ?? null
1242
+ },
1243
+ {
1244
+ key: "created_at_iso",
1245
+ value: formatUnixSeconds(thread?.created_at ?? null)
1246
+ },
1247
+ {
1248
+ key: "updated_at_unix",
1249
+ value: thread?.updated_at ?? null
1250
+ },
1251
+ {
1252
+ key: "updated_at_iso",
1253
+ value: formatUnixSeconds(thread?.updated_at ?? null)
1254
+ },
1255
+ {
1256
+ key: "archived_at_unix",
1257
+ value: thread?.archived_at ?? null
1258
+ },
1259
+ {
1260
+ key: "archived_at_iso",
1261
+ value: formatUnixSeconds(thread?.archived_at ?? null)
1262
+ },
1263
+ {
1264
+ key: "session_started_at_iso",
1265
+ value: sessionMeta.timestamp ?? null
1266
+ }
1267
+ ];
1268
+ };
1269
+ var buildCodexThreadIdentityMetadata = (target, sessionMeta) => {
1270
+ const thread = target.thread;
1271
+ return [
1272
+ {
1273
+ key: "archived",
1274
+ value: thread ? Boolean(thread.archived) : null
1275
+ },
1276
+ {
1277
+ key: "source",
1278
+ value: thread?.source ?? sessionMeta.source ?? null
1279
+ },
1280
+ {
1281
+ key: "originator",
1282
+ value: sessionMeta.originator ?? null
1283
+ },
1284
+ {
1285
+ key: "model_provider",
1286
+ value: thread?.model_provider ?? null
1287
+ },
1288
+ {
1289
+ key: "model",
1290
+ value: thread?.model ?? null
1291
+ },
1292
+ {
1293
+ key: "reasoning_effort",
1294
+ value: thread?.reasoning_effort ?? null
1295
+ },
1296
+ {
1297
+ key: "cli_version",
1298
+ value: thread?.cli_version || sessionMeta.cli_version || null
1299
+ },
1300
+ {
1301
+ key: "cwd",
1302
+ value: thread?.cwd || sessionMeta.cwd || null
1303
+ },
1304
+ {
1305
+ key: "approval_mode",
1306
+ value: thread?.approval_mode ?? null
1307
+ },
1308
+ {
1309
+ key: "sandbox_policy",
1310
+ value: parseJsonSafely(thread?.sandbox_policy ?? null)
1311
+ },
1312
+ {
1313
+ key: "memory_mode",
1314
+ value: thread?.memory_mode ?? null
1315
+ },
1316
+ {
1317
+ key: "tokens_used",
1318
+ value: thread?.tokens_used ?? null
1319
+ },
1320
+ {
1321
+ key: "has_user_event",
1322
+ value: thread ? Boolean(thread.has_user_event) : null
1323
+ }
1324
+ ];
1325
+ };
1326
+ var buildCodexAgentMetadata = (target) => {
1327
+ const thread = target.thread;
1328
+ return [
1329
+ {
1330
+ key: "git_sha",
1331
+ value: thread?.git_sha ?? null
1332
+ },
1333
+ {
1334
+ key: "git_branch",
1335
+ value: thread?.git_branch ?? null
1336
+ },
1337
+ {
1338
+ key: "git_origin_url",
1339
+ value: thread?.git_origin_url ?? null
1340
+ },
1341
+ {
1342
+ key: "agent_nickname",
1343
+ value: thread?.agent_nickname ?? null
1344
+ },
1345
+ {
1346
+ key: "agent_role",
1347
+ value: thread?.agent_role ?? null
1348
+ },
1349
+ {
1350
+ key: "agent_path",
1351
+ value: thread?.agent_path ?? null
1352
+ },
1353
+ {
1354
+ key: "first_user_message",
1355
+ value: thread?.first_user_message || null
1356
+ }
1357
+ ];
1358
+ };
1359
+ var parseJsonSafely = (value) => {
1360
+ if (!value) return null;
1361
+ try {
1362
+ return JSON.parse(value);
1363
+ } catch {
1364
+ return value;
1365
+ }
1366
+ };
1367
+ var formatUnixSeconds = (value) => {
1368
+ if (value === null || value === void 0) return null;
1369
+ return (/* @__PURE__ */ new Date(value * 1e3)).toISOString();
1370
+ };
1371
+ var captureSessionMeta = (parsed, meta) => {
1372
+ if (parsed.type !== "session_meta") return;
1373
+ const payload = asObject(parsed.payload);
1374
+ if (!payload) return;
1375
+ meta.id = asString(payload.id) ?? meta.id;
1376
+ meta.timestamp = asString(payload.timestamp) ?? meta.timestamp;
1377
+ meta.cwd = asString(payload.cwd) ?? meta.cwd;
1378
+ meta.source = asString(payload.source) ?? meta.source;
1379
+ meta.originator = asString(payload.originator) ?? meta.originator;
1380
+ meta.cli_version = asString(payload.cli_version) ?? meta.cli_version;
1381
+ };
1382
+ var extractMessageRecord = (parsed) => {
1383
+ if (parsed.type === "message") {
1384
+ const directMessage = normalizeMessage(parsed);
1385
+ if (directMessage) return directMessage;
1386
+ }
1387
+ if (parsed.type !== "response_item") return null;
1388
+ const payload = asObject(parsed.payload);
1389
+ if (!payload) return null;
1390
+ if (payload.type !== "message" && payload.type !== "agent_message" && payload.type !== "user_message") return null;
1391
+ return normalizeMessage(payload);
1392
+ };
1393
+ var normalizeMessage = (value) => {
1394
+ const type = asString(value.type);
1395
+ const role = asString(value.role) ?? (type === "agent_message" ? "assistant" : type === "user_message" ? "user" : null);
1396
+ const content = value.content ?? asString(value.message);
1397
+ const phase = asString(value.phase);
1398
+ if (!role || content === void 0) return null;
1399
+ return {
1400
+ content,
1401
+ model: asString(value.model),
1402
+ phase: phase ?? void 0,
1403
+ role
1404
+ };
1405
+ };
1406
+ var extractToolRecord = (parsed) => {
1407
+ if (parsed.type !== "response_item") return null;
1408
+ const payload = asObject(parsed.payload);
1409
+ if (!payload) return null;
1410
+ if (payload.type === "function_call") {
1411
+ const name = asString(payload.name);
1412
+ const argumentsText = asString(payload.arguments);
1413
+ const callId = asString(payload.call_id);
1414
+ if (name !== "exec_command") return null;
1415
+ return {
1416
+ argumentsText: argumentsText ?? void 0,
1417
+ callId,
1418
+ kind: "call",
1419
+ name
1420
+ };
1421
+ }
1422
+ if (payload.type === "function_call_output") {
1423
+ const callId = asString(payload.call_id);
1424
+ const outputText = asString(payload.output);
1425
+ if (!outputText?.includes("Command: ")) return null;
1426
+ return {
1427
+ callId,
1428
+ kind: "output",
1429
+ name: "function_call_output",
1430
+ outputText: outputText ?? void 0
1431
+ };
1432
+ }
1433
+ return null;
1434
+ };
1435
+ var renderMessageBlock = (message, outputFormat, assistantModel, includeCommentary) => {
1436
+ if (message.role !== "user" && message.role !== "assistant") return "";
1437
+ if (message.role === "assistant" && message.phase === "commentary" && !includeCommentary) return "";
1438
+ const text = cleanExtractedText(extractText(message.content)).trim();
1439
+ if (!text || shouldSkipMessage(message.role, text)) return "";
1440
+ return renderSection(message.role === "user" ? "User" : formatModelLabel(message.model ?? assistantModel), message.phase ? `Phase: ${message.phase}\n\n${text}` : text, outputFormat);
1441
+ };
1442
+ var renderToolBlock = (tool, outputFormat) => {
1443
+ if (tool.kind === "call") {
1444
+ const details = formatToolCallDetails(tool, outputFormat);
1445
+ return details ? renderSection("Tool", details, outputFormat) : "";
1446
+ }
1447
+ const summary = formatToolOutputSummary(tool.outputText ?? "", outputFormat);
1448
+ return summary ? renderSection("Tool Output", summary, outputFormat) : "";
1449
+ };
1450
+ var renderCompactBlock = (message, text, outputFormat, assistantModel) => {
1451
+ const prefix = message.role === "user" ? "U:" : `${formatModelLabel(message.model ?? assistantModel)}:`;
1452
+ const [firstLine, ...rest] = text.split("\n");
1453
+ if (rest.length === 0) return `${prefix} ${normalizeCompactLiteral(firstLine, outputFormat)}`;
1454
+ return [`${prefix} ${normalizeCompactLiteral(firstLine, outputFormat)}`, ...rest.map((line) => normalizeCompactLiteral(line, outputFormat))].join("\n");
1455
+ };
1456
+ var renderCompactToolBlock = (tool, outputFormat) => {
1457
+ if (tool.kind === "call") {
1458
+ const details = formatCompactToolCall(tool, outputFormat);
1459
+ return details ? `T: ${details}` : "";
1460
+ }
1461
+ const summary = formatCompactToolOutput(tool.outputText ?? "");
1462
+ return summary ? `R: ${summary}` : "";
1463
+ };
1464
+ var stripPreviewBlock = (text) => {
1465
+ const parts = text.split(/\n{2,}/).map((part) => part.trim()).filter(Boolean);
1466
+ if (parts.length < 2) return text.trim();
1467
+ const first = parts[0];
1468
+ const second = parts[1];
1469
+ const isTranscriptHeading = (value) => /^##\s+.+$/i.test(value);
1470
+ if (!(!/^([UA]):/i.test(first) && !isTranscriptHeading(first) && /^([UA]):/i.test(second) === false && isTranscriptHeading(second))) return text.trim();
1471
+ return parts.slice(1).join("\n\n");
1472
+ };
1473
+ var optimizeRenderedText = (text) => {
1474
+ return text.replace(/^\*Phase:\s+`[^`]+`\*\s*\n*/gm, "").replace(/^\s*<image\b[^>]*>\s*$/gim, "").replace(/^\s*<\/image>\s*$/gim, "").replace(/^\s*\[Image attached\]\s*$/gim, "").replace(/^#{1,6}\s+/gm, "").replace(/^```[^\n]*\n?/gm, "").replace(/\n```$/gm, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^##\s+User\s*$/gm, "User:").replace(/^##\s+Assistant\s*$/gm, "Assistant:").replace(/`([^`]+)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*\n]+)\*/g, "$1").replace(/\n{3,}/g, "\n\n").trim();
1475
+ };
1476
+ var optimizePlainText = (text) => {
1477
+ return text.replace(/\r/g, "").replace(/^\s*<image\b[^>]*>\s*$/gim, "").replace(/^\s*<\/image>\s*$/gim, "").replace(/^\s*\[Image attached\]\s*$/gim, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*\n]+)\*/g, "$1").split("\n").map((line) => line.replace(/[ \t]+$/g, "")).join("\n").replace(/\n{3,}/g, "\n\n").trim();
1478
+ };
1479
+ var shouldSkipMessage = (role, text) => {
1480
+ if (text.startsWith("<environment_context>")) return true;
1481
+ if (text.startsWith("# AGENTS.md instructions for ")) return true;
1482
+ if (role === "user" && text.includes("<environment_context>")) return true;
1483
+ return false;
1484
+ };
1485
+ var formatToolCallDetails = (tool, outputFormat) => {
1486
+ if (tool.name !== "exec_command") return "";
1487
+ const details = parseExecCommandArguments(tool.argumentsText);
1488
+ return details.cmd ? `Command: ${formatInlineLiteral(details.cmd, outputFormat)}` : "";
1489
+ };
1490
+ var formatCompactToolCall = (tool, outputFormat) => {
1491
+ if (tool.name === "exec_command") {
1492
+ const details = parseExecCommandArguments(tool.argumentsText);
1493
+ if (!details.cmd) return "exec_command";
1494
+ const command = formatInlineLiteral(details.cmd, outputFormat);
1495
+ return details.workdir ? `exec_command ${command} @ ${details.workdir}` : `exec_command ${command}`;
1496
+ }
1497
+ return tool.callId ? `${tool.name} (${tool.callId})` : tool.name;
1498
+ };
1499
+ var formatCompactToolOutput = (outputText) => {
1500
+ if (!outputText) return "";
1501
+ const lines = outputText.split("\n").map((line) => line.trim()).filter(Boolean);
1502
+ const exit = lines.find((line) => line.startsWith("Process exited with code "));
1503
+ const wall = lines.find((line) => line.startsWith("Wall time: "));
1504
+ if (exit && wall) return `${exit.replace("Process ", "")}; ${wall.toLowerCase()}`;
1505
+ if (exit) return exit.replace("Process ", "");
1506
+ return "";
1507
+ };
1508
+ var extractText = (content) => {
1509
+ if (typeof content === "string") return content;
1510
+ if (Array.isArray(content)) return content.map((item) => extractContentPart(item)).filter((part) => part.length > 0).join("\n\n");
1511
+ if (content && typeof content === "object") {
1512
+ const text = asString(content.text);
1513
+ if (text) return text;
1514
+ }
1515
+ return "";
1516
+ };
1517
+ var extractContentPart = (value) => {
1518
+ if (!value || typeof value !== "object" || Array.isArray(value)) return "";
1519
+ const item = value;
1520
+ const type = asString(item.type);
1521
+ const text = asString(item.text);
1522
+ if ((type === "input_text" || type === "output_text" || type === "text") && text) return text;
1523
+ if (type === "input_image") return "[Image attached]";
1524
+ return text ?? "";
1525
+ };
1526
+ var normalizeCompactLiteral = (value, outputFormat) => {
1527
+ return outputFormat === "md" ? value : value.replace(/`([^`]+)`/g, "$1");
1528
+ };
1529
+ var UI_EXPORT_URL_PREFIX = "/__exports/";
1530
+ var DEFAULT_UI_EXPORT_DIR = path.join(os.tmpdir(), "spiracha-ui-exports");
1531
+ var DEFAULT_EXPORT_MAX_AGE_MS = 1440 * 60 * 1e3;
1532
+ var getUiExportDir = () => {
1533
+ return process.env["SPIRACHA_UI_EXPORT_DIR"]?.trim() || DEFAULT_UI_EXPORT_DIR;
1534
+ };
1535
+ var ensureUiExportDir = async () => {
1536
+ const exportDir = getUiExportDir();
1537
+ await mkdir(exportDir, { recursive: true });
1538
+ await purgeStaleUiExports(exportDir);
1539
+ return exportDir;
1540
+ };
1541
+ var buildUiExportDownloadUrl = (filePath) => {
1542
+ return `${UI_EXPORT_URL_PREFIX}${encodeURIComponent(path.basename(filePath))}`;
1543
+ };
1544
+ var purgeStaleUiExports = async (exportDir = getUiExportDir(), maxAgeMs = DEFAULT_EXPORT_MAX_AGE_MS) => {
1545
+ const entries = await readdir(exportDir, { withFileTypes: true });
1546
+ const cutoff = Date.now() - maxAgeMs;
1547
+ await Promise.all(entries.filter((entry) => entry.isFile()).map(async (entry) => {
1548
+ const filePath = path.join(exportDir, entry.name);
1549
+ if ((await stat(filePath)).mtimeMs >= cutoff) return;
1550
+ await rm(filePath, { force: true });
1551
+ }));
1552
+ };
1553
+ //#endregion
1554
+ //#region ../../src/lib/codex-browser-export.ts
1555
+ var LARGE_BROWSER_EXPORT_THRESHOLD_BYTES = 128 * 1024 * 1024;
1556
+ var toSanitizedFileName = (value) => {
1557
+ return value.replace(/[<>:"/\\|?*\u0000-\u001f]/gu, " ").replace(/\.\.+/gu, " ").replace(/\s+/gu, " ").trim();
1558
+ };
1559
+ var formatReadableExportDate = (value) => {
1560
+ const date = new Date(value);
1561
+ return `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, "0")}-${String(date.getUTCDate()).padStart(2, "0")}-${String(date.getUTCHours()).padStart(2, "0")}${String(date.getUTCMinutes()).padStart(2, "0")}`;
1562
+ };
1563
+ var buildExportBaseName = (thread) => {
1564
+ return `${toSanitizedFileName(getPortablePathBasename(thread.cwd) || "thread") || "thread"}-${formatReadableExportDate(thread.updated_at_ms ?? thread.updated_at * 1e3)}-${thread.id.slice(0, 8)}`;
1565
+ };
1566
+ var buildBatchExportBaseName = (threads) => {
1567
+ const firstThread = threads[0];
1568
+ if (!firstThread) throw new Error("No threads selected for export");
1569
+ return `${toSanitizedFileName(getPortablePathBasename(firstThread.cwd) || "threads") || "threads"}-${formatReadableExportDate(Math.max(...threads.map((thread) => thread.updated_at_ms ?? thread.updated_at * 1e3)))}-threads-${threads.length}`;
1570
+ };
1571
+ var buildUniqueArchivePath = (exportDir, exportBaseName) => {
1572
+ return path.join(exportDir, `${exportBaseName}-${randomUUID()}.zip`);
1573
+ };
1574
+ var toDownloadOptions = (input) => {
1575
+ return {
1576
+ cwdFilter: null,
1577
+ dbPath: input.dbPath,
1578
+ flat: false,
1579
+ includeCommentary: input.includeCommentary,
1580
+ includeTools: input.includeTools,
1581
+ inputDir: "",
1582
+ optimized: input.optimized,
1583
+ outputDir: "",
1584
+ outputFormat: input.outputFormat,
1585
+ projectFilter: null,
1586
+ threadIds: [input.threadId]
1587
+ };
1588
+ };
1589
+ var getMimeType = (outputFormat) => {
1590
+ return outputFormat === "md" ? "text/markdown; charset=utf-8" : "text/plain; charset=utf-8";
1591
+ };
1592
+ var resolvePublicExportDir = async (publicExportDir) => {
1593
+ if (publicExportDir) {
1594
+ await ensureDirectory(publicExportDir);
1595
+ return publicExportDir;
1596
+ }
1597
+ return ensureUiExportDir();
1598
+ };
1599
+ var ensureDirectory = async (directoryPath) => {
1600
+ await mkdir(directoryPath, { recursive: true });
1601
+ };
1602
+ var createExportWorkspace = async (exportDir, exportBaseName) => {
1603
+ return mkdtemp(path.join(exportDir, `${exportBaseName}-`));
1604
+ };
1605
+ var getRolloutSnapshot = async (rolloutPath) => {
1606
+ const metadata = await stat(rolloutPath);
1607
+ return {
1608
+ mtimeMs: metadata.mtimeMs,
1609
+ sizeBytes: metadata.size
1610
+ };
1611
+ };
1612
+ var logExportEvent = (level, event, details) => {
1613
+ console[level](`[spiracha:export] ${event}`, details);
1614
+ };
1615
+ var logRolloutChangeIfDetected = (threadId, rolloutPath, beforeSnapshot, afterSnapshot) => {
1616
+ if (beforeSnapshot.mtimeMs === afterSnapshot.mtimeMs && beforeSnapshot.sizeBytes === afterSnapshot.sizeBytes) return;
1617
+ logExportEvent("warn", "rollout_changed_during_export", {
1618
+ afterMtimeMs: afterSnapshot.mtimeMs,
1619
+ afterSizeBytes: afterSnapshot.sizeBytes,
1620
+ beforeMtimeMs: beforeSnapshot.mtimeMs,
1621
+ beforeSizeBytes: beforeSnapshot.sizeBytes,
1622
+ rolloutPath,
1623
+ threadId
1624
+ });
1625
+ };
1626
+ var zipExportFile = async (sourcePath, zipPath) => {
1627
+ const proc = Bun.spawn([
1628
+ "zip",
1629
+ "-9",
1630
+ "-j",
1631
+ zipPath,
1632
+ sourcePath
1633
+ ], {
1634
+ stderr: "pipe",
1635
+ stdout: "pipe"
1636
+ });
1637
+ const [stdoutText, stderrText, exitCode] = await Promise.all([
1638
+ new Response(proc.stdout).text(),
1639
+ new Response(proc.stderr).text(),
1640
+ proc.exited
1641
+ ]);
1642
+ if (exitCode !== 0) throw new Error(`zip failed (${exitCode}): ${(stderrText || stdoutText).trim()}`);
1643
+ };
1644
+ var zipExportDirectory = async (sourceDirectory, zipPath) => {
1645
+ const proc = Bun.spawn([
1646
+ "zip",
1647
+ "-9",
1648
+ "-r",
1649
+ zipPath,
1650
+ "."
1651
+ ], {
1652
+ cwd: sourceDirectory,
1653
+ stderr: "pipe",
1654
+ stdout: "pipe"
1655
+ });
1656
+ const [stdoutText, stderrText, exitCode] = await Promise.all([
1657
+ new Response(proc.stdout).text(),
1658
+ new Response(proc.stderr).text(),
1659
+ proc.exited
1660
+ ]);
1661
+ if (exitCode !== 0) throw new Error(`zip failed (${exitCode}): ${(stderrText || stdoutText).trim()}`);
1662
+ };
1663
+ var renderCodexThreadDownload = async (input) => {
1664
+ const startedAt = Date.now();
1665
+ const browseData = getThreadBrowseData(input.dbPath, input.threadId);
1666
+ const extension = input.outputFormat === "md" ? "md" : "txt";
1667
+ const fileBaseName = buildExportBaseName(browseData.thread);
1668
+ const fileName = `${fileBaseName}.${extension}`;
1669
+ const mimeType = getMimeType(input.outputFormat);
1670
+ const transform = (text) => input.pathDisplaySettings ? applyPathTransforms(text, {
1671
+ ...input.pathDisplaySettings,
1672
+ projectPath: browseData.thread.cwd
1673
+ }) : text;
1674
+ const rolloutSnapshotBefore = await getRolloutSnapshot(browseData.thread.rollout_path);
1675
+ logExportEvent("info", "single_start", {
1676
+ fileName,
1677
+ rolloutPath: browseData.thread.rollout_path,
1678
+ sizeBytes: rolloutSnapshotBefore.sizeBytes,
1679
+ threadId: input.threadId
1680
+ });
1681
+ try {
1682
+ if (rolloutSnapshotBefore.sizeBytes > (input.largeExportThresholdBytes ?? LARGE_BROWSER_EXPORT_THRESHOLD_BYTES)) {
1683
+ const exportBaseName = fileBaseName;
1684
+ const exportDir = await resolvePublicExportDir(input.publicExportDir);
1685
+ const workspaceDir = await createExportWorkspace(exportDir, exportBaseName);
1686
+ const savedPath = path.join(workspaceDir, `${exportBaseName}.${extension}`);
1687
+ const zipPath = buildUniqueArchivePath(exportDir, exportBaseName);
1688
+ try {
1689
+ if (!await writeSessionFileExport({
1690
+ fallbackReason: null,
1691
+ outputRelativePath: fileName,
1692
+ relations: browseData.relations,
1693
+ sessionFile: browseData.thread.rollout_path,
1694
+ thread: browseData.thread
1695
+ }, toDownloadOptions(input), savedPath, transform)) throw new Error(`Thread ${input.threadId} produced no exportable content`);
1696
+ await zipExportFile(savedPath, zipPath);
1697
+ } finally {
1698
+ await rm(workspaceDir, {
1699
+ force: true,
1700
+ recursive: true
1701
+ });
1702
+ }
1703
+ const rolloutSnapshotAfter = await getRolloutSnapshot(browseData.thread.rollout_path);
1704
+ logRolloutChangeIfDetected(input.threadId, browseData.thread.rollout_path, rolloutSnapshotBefore, rolloutSnapshotAfter);
1705
+ const zipStat = await Bun.file(zipPath).stat();
1706
+ logExportEvent("info", "single_zip_ready", {
1707
+ downloadUrl: buildUiExportDownloadUrl(zipPath),
1708
+ durationMs: Date.now() - startedAt,
1709
+ fileName: `${exportBaseName}.zip`,
1710
+ sizeBytes: zipStat.size,
1711
+ threadId: input.threadId,
1712
+ zipPath
1713
+ });
1714
+ return {
1715
+ downloadUrl: buildUiExportDownloadUrl(zipPath),
1716
+ fileName: `${exportBaseName}.zip`,
1717
+ mimeType: "application/zip",
1718
+ mode: "download_url"
1719
+ };
1720
+ }
1721
+ const content = await convertSessionFile({
1722
+ fallbackReason: null,
1723
+ outputRelativePath: fileName,
1724
+ relations: browseData.relations,
1725
+ sessionFile: browseData.thread.rollout_path,
1726
+ thread: browseData.thread
1727
+ }, toDownloadOptions(input));
1728
+ if (!content) throw new Error(`Thread ${input.threadId} produced no exportable content`);
1729
+ const rolloutSnapshotAfter = await getRolloutSnapshot(browseData.thread.rollout_path);
1730
+ logRolloutChangeIfDetected(input.threadId, browseData.thread.rollout_path, rolloutSnapshotBefore, rolloutSnapshotAfter);
1731
+ logExportEvent("info", "single_inline_ready", {
1732
+ durationMs: Date.now() - startedAt,
1733
+ fileName,
1734
+ sizeBytes: content.length,
1735
+ threadId: input.threadId
1736
+ });
1737
+ return {
1738
+ content: transform(content),
1739
+ fileName,
1740
+ mimeType,
1741
+ mode: "download"
1742
+ };
1743
+ } catch (error) {
1744
+ logExportEvent("error", "single_error", {
1745
+ error: error instanceof Error ? error.message : String(error),
1746
+ fileName,
1747
+ threadId: input.threadId
1748
+ });
1749
+ throw error;
1750
+ }
1751
+ };
1752
+ var renderCodexThreadsDownload = async (input) => {
1753
+ const startedAt = Date.now();
1754
+ const threadIds = [...new Set(input.threadIds)];
1755
+ if (threadIds.length === 0) throw new Error("No threads selected for export");
1756
+ const browseEntries = threadIds.map((threadId) => getThreadBrowseData(input.dbPath, threadId));
1757
+ const threads = browseEntries.map((entry) => entry.thread);
1758
+ const exportDir = await resolvePublicExportDir(input.publicExportDir);
1759
+ const exportBaseName = buildBatchExportBaseName(threads);
1760
+ const bundleDirectory = await createExportWorkspace(exportDir, exportBaseName);
1761
+ const zipPath = buildUniqueArchivePath(exportDir, exportBaseName);
1762
+ logExportEvent("info", "batch_start", {
1763
+ exportBaseName,
1764
+ selectedThreadCount: threadIds.length,
1765
+ selectedThreadIds: threadIds,
1766
+ zipPath
1767
+ });
1768
+ try {
1769
+ for (const entry of browseEntries) {
1770
+ const rolloutSnapshotBefore = await getRolloutSnapshot(entry.thread.rollout_path);
1771
+ const relativeFileName = `${buildExportBaseName(entry.thread)}.${input.outputFormat === "md" ? "md" : "txt"}`;
1772
+ const savedPath = path.join(bundleDirectory, relativeFileName);
1773
+ const transform = (text) => input.pathDisplaySettings ? applyPathTransforms(text, {
1774
+ ...input.pathDisplaySettings,
1775
+ projectPath: entry.thread.cwd
1776
+ }) : text;
1777
+ if (!await writeSessionFileExport({
1778
+ fallbackReason: null,
1779
+ outputRelativePath: relativeFileName,
1780
+ relations: entry.relations,
1781
+ sessionFile: entry.thread.rollout_path,
1782
+ thread: entry.thread
1783
+ }, {
1784
+ ...toDownloadOptions({
1785
+ ...input,
1786
+ threadId: entry.thread.id
1787
+ }),
1788
+ threadIds: [entry.thread.id]
1789
+ }, savedPath, transform)) throw new Error(`Thread ${entry.thread.id} produced no exportable content`);
1790
+ const rolloutSnapshotAfter = await getRolloutSnapshot(entry.thread.rollout_path);
1791
+ logRolloutChangeIfDetected(entry.thread.id, entry.thread.rollout_path, rolloutSnapshotBefore, rolloutSnapshotAfter);
1792
+ }
1793
+ await zipExportDirectory(bundleDirectory, zipPath);
1794
+ } catch (error) {
1795
+ logExportEvent("error", "batch_error", {
1796
+ error: error instanceof Error ? error.message : String(error),
1797
+ exportBaseName,
1798
+ selectedThreadCount: threadIds.length,
1799
+ selectedThreadIds: threadIds,
1800
+ zipPath
1801
+ });
1802
+ throw error;
1803
+ } finally {
1804
+ await rm(bundleDirectory, {
1805
+ force: true,
1806
+ recursive: true
1807
+ });
1808
+ }
1809
+ const zipStat = await Bun.file(zipPath).stat();
1810
+ logExportEvent("info", "batch_ready", {
1811
+ downloadUrl: buildUiExportDownloadUrl(zipPath),
1812
+ durationMs: Date.now() - startedAt,
1813
+ fileName: `${exportBaseName}.zip`,
1814
+ selectedThreadCount: threadIds.length,
1815
+ selectedThreadIds: threadIds,
1816
+ sizeBytes: zipStat.size,
1817
+ zipPath
1818
+ });
1819
+ return {
1820
+ downloadUrl: buildUiExportDownloadUrl(zipPath),
1821
+ fileName: `${exportBaseName}.zip`,
1822
+ mimeType: "application/zip",
1823
+ mode: "download_url"
1824
+ };
1825
+ };
1826
+ //#endregion
1827
+ //#region src/lib/codex-server.ts?tss-serverfn-split
1828
+ var projectSchema = z.object({ project: z.string().min(1) });
1829
+ var deleteProjectSchema = z.object({
1830
+ deleteSessionFiles: z.boolean().default(false),
1831
+ project: z.string().min(1)
1832
+ });
1833
+ var threadSchema = z.object({ threadId: z.string().min(1) });
1834
+ var deleteThreadSchema = z.object({
1835
+ deleteSessionFiles: z.boolean().default(false),
1836
+ threadId: z.string().min(1)
1837
+ });
1838
+ var deleteThreadsSchema = z.object({
1839
+ deleteSessionFiles: z.boolean().default(false),
1840
+ threadIds: z.array(z.string().min(1)).min(1)
1841
+ });
1842
+ var analyticsSchema = z.object({ project: z.string().min(1).nullable() });
1843
+ var exportSchema = z.object({
1844
+ convertToProjectRoot: z.boolean(),
1845
+ includeCommentary: z.boolean(),
1846
+ includeTools: z.boolean(),
1847
+ optimized: z.boolean(),
1848
+ outputFormat: z.enum(["md", "txt"]),
1849
+ redactUsername: z.boolean(),
1850
+ threadId: z.string().min(1)
1851
+ });
1852
+ var exportThreadsSchema = z.object({
1853
+ convertToProjectRoot: z.boolean(),
1854
+ includeCommentary: z.boolean(),
1855
+ includeTools: z.boolean(),
1856
+ optimized: z.boolean(),
1857
+ outputFormat: z.enum(["md", "txt"]),
1858
+ redactUsername: z.boolean(),
1859
+ threadIds: z.array(z.string().min(1)).min(1)
1860
+ });
1861
+ var getDbPath = () => process.env.SPIRACHA_CODEX_DB?.trim() || resolveCodexThreadDbPath();
1862
+ var isMissingFileError = (error) => {
1863
+ return error instanceof Error && /ENOENT|no such file/i.test(error.message);
1864
+ };
1865
+ var getDashboardSummaryFn_createServerFn_handler = createServerRpc({
1866
+ id: "792690638a3b10035a5b7368c3d98bdc70cbfe1e36a4aa5f45b1c49b8b1025b0",
1867
+ name: "getDashboardSummaryFn",
1868
+ filename: "src/lib/codex-server.ts"
1869
+ }, (opts) => getDashboardSummaryFn.__executeServer(opts));
1870
+ var getDashboardSummaryFn = createServerFn({ method: "GET" }).handler(getDashboardSummaryFn_createServerFn_handler, async () => {
1871
+ return getCodexDashboardSummary(getDbPath());
1872
+ });
1873
+ var listProjectsFn_createServerFn_handler = createServerRpc({
1874
+ id: "ccefccb816ba13508f23db4e31067b3403e750225257592d3ae11071ffc3fd6f",
1875
+ name: "listProjectsFn",
1876
+ filename: "src/lib/codex-server.ts"
1877
+ }, (opts) => listProjectsFn.__executeServer(opts));
1878
+ var listProjectsFn = createServerFn({ method: "GET" }).handler(listProjectsFn_createServerFn_handler, async () => {
1879
+ return listCodexProjects(getDbPath());
1880
+ });
1881
+ var listProjectThreadsFn_createServerFn_handler = createServerRpc({
1882
+ id: "59fb2cb4d60c8e7d47e0afcc914ee6f9d9f4bf076c8e66eab1693066753655b3",
1883
+ name: "listProjectThreadsFn",
1884
+ filename: "src/lib/codex-server.ts"
1885
+ }, (opts) => listProjectThreadsFn.__executeServer(opts));
1886
+ var listProjectThreadsFn = createServerFn({ method: "GET" }).inputValidator(projectSchema).handler(listProjectThreadsFn_createServerFn_handler, async ({ data }) => {
1887
+ return listProjectThreads(getDbPath(), data.project);
1888
+ });
1889
+ var getThreadSnapshotFn_createServerFn_handler = createServerRpc({
1890
+ id: "72991e2b6e0adbf8d63bb8b139dad88a00b77b7030ec28ceac36c3cce7846b4c",
1891
+ name: "getThreadSnapshotFn",
1892
+ filename: "src/lib/codex-server.ts"
1893
+ }, (opts) => getThreadSnapshotFn.__executeServer(opts));
1894
+ var getThreadSnapshotFn = createServerFn({ method: "GET" }).inputValidator(threadSchema).handler(getThreadSnapshotFn_createServerFn_handler, async ({ data }) => {
1895
+ const browseData = getThreadBrowseData(getDbPath(), data.threadId);
1896
+ const rollout = await getThreadRolloutLoadState(browseData.thread.rollout_path);
1897
+ let transcript = null;
1898
+ let transcriptState = rollout.shouldDeferTranscriptLoad ? "deferred" : "available";
1899
+ if (!rollout.shouldDeferTranscriptLoad) try {
1900
+ transcript = await getCachedParsedCodexTranscript(browseData.thread.rollout_path);
1901
+ } catch (error) {
1902
+ if (!isMissingFileError(error)) throw error;
1903
+ transcriptState = "missing";
1904
+ }
1905
+ return {
1906
+ ...browseData,
1907
+ availableTools: browseData.dynamicTools.length > 0 ? browseData.dynamicTools : transcript?.sessionMeta.dynamicTools ?? [],
1908
+ rollout,
1909
+ transcript,
1910
+ transcriptState
1911
+ };
1912
+ });
1913
+ var getThreadTranscriptFn_createServerFn_handler = createServerRpc({
1914
+ id: "5da27045f7e28ded6353bc16aace284af7ef1b4010ef04d0186a6feadb466497",
1915
+ name: "getThreadTranscriptFn",
1916
+ filename: "src/lib/codex-server.ts"
1917
+ }, (opts) => getThreadTranscriptFn.__executeServer(opts));
1918
+ var getThreadTranscriptFn = createServerFn({ method: "GET" }).inputValidator(threadSchema).handler(getThreadTranscriptFn_createServerFn_handler, async ({ data }) => {
1919
+ return getCachedThreadTranscriptPreview(getThreadBrowseData(getDbPath(), data.threadId).thread.rollout_path);
1920
+ });
1921
+ var getAnalyticsFn_createServerFn_handler = createServerRpc({
1922
+ id: "4712520da0f07bbd1f0907e5a162fe518516ff4caca3fd23876cc65539d87d7a",
1923
+ name: "getAnalyticsFn",
1924
+ filename: "src/lib/codex-server.ts"
1925
+ }, (opts) => getAnalyticsFn.__executeServer(opts));
1926
+ var getAnalyticsFn = createServerFn({ method: "GET" }).inputValidator(analyticsSchema).handler(getAnalyticsFn_createServerFn_handler, async ({ data }) => {
1927
+ return getCodexAnalytics({
1928
+ dbPath: getDbPath(),
1929
+ project: data.project
1930
+ });
1931
+ });
1932
+ var exportThreadFn_createServerFn_handler = createServerRpc({
1933
+ id: "0814663c3bdc58135f97d210d145ef0be5ca54ef9a5f1e3030be9b1bfc901e30",
1934
+ name: "exportThreadFn",
1935
+ filename: "src/lib/codex-server.ts"
1936
+ }, (opts) => exportThreadFn.__executeServer(opts));
1937
+ var exportThreadFn = createServerFn({ method: "POST" }).inputValidator(exportSchema).handler(exportThreadFn_createServerFn_handler, async ({ data }) => {
1938
+ return renderCodexThreadDownload({
1939
+ dbPath: getDbPath(),
1940
+ includeCommentary: data.includeCommentary,
1941
+ includeTools: data.includeTools,
1942
+ optimized: data.optimized,
1943
+ outputFormat: data.outputFormat,
1944
+ pathDisplaySettings: {
1945
+ convertToProjectRoot: data.convertToProjectRoot,
1946
+ redactUsername: data.redactUsername
1947
+ },
1948
+ threadId: data.threadId
1949
+ });
1950
+ });
1951
+ var exportThreadsFn_createServerFn_handler = createServerRpc({
1952
+ id: "b4e15c006e9a277470958bb008f89b5b0acc7256109581de44cf17d587d174a5",
1953
+ name: "exportThreadsFn",
1954
+ filename: "src/lib/codex-server.ts"
1955
+ }, (opts) => exportThreadsFn.__executeServer(opts));
1956
+ var exportThreadsFn = createServerFn({ method: "POST" }).inputValidator(exportThreadsSchema).handler(exportThreadsFn_createServerFn_handler, async ({ data }) => {
1957
+ return renderCodexThreadsDownload({
1958
+ dbPath: getDbPath(),
1959
+ includeCommentary: data.includeCommentary,
1960
+ includeTools: data.includeTools,
1961
+ optimized: data.optimized,
1962
+ outputFormat: data.outputFormat,
1963
+ pathDisplaySettings: {
1964
+ convertToProjectRoot: data.convertToProjectRoot,
1965
+ redactUsername: data.redactUsername
1966
+ },
1967
+ threadIds: data.threadIds
1968
+ });
1969
+ });
1970
+ var deleteThreadFn_createServerFn_handler = createServerRpc({
1971
+ id: "29727b7ad5b8fe42e83817376653e064d9fe8888799f056b2e59296b3396568b",
1972
+ name: "deleteThreadFn",
1973
+ filename: "src/lib/codex-server.ts"
1974
+ }, (opts) => deleteThreadFn.__executeServer(opts));
1975
+ var deleteThreadFn = createServerFn({ method: "POST" }).inputValidator(deleteThreadSchema).handler(deleteThreadFn_createServerFn_handler, async ({ data }) => {
1976
+ return deleteCodexThread(getDbPath(), data.threadId, { deleteSessionFiles: data.deleteSessionFiles });
1977
+ });
1978
+ var deleteThreadsFn_createServerFn_handler = createServerRpc({
1979
+ id: "96aa60bf7dd9b5bde415bcf3ad6f6955a975eecd9aa0516cf401cc39bebebe6c",
1980
+ name: "deleteThreadsFn",
1981
+ filename: "src/lib/codex-server.ts"
1982
+ }, (opts) => deleteThreadsFn.__executeServer(opts));
1983
+ var deleteThreadsFn = createServerFn({ method: "POST" }).inputValidator(deleteThreadsSchema).handler(deleteThreadsFn_createServerFn_handler, async ({ data }) => {
1984
+ return deleteCodexThreads(getDbPath(), data.threadIds, { deleteSessionFiles: data.deleteSessionFiles });
1985
+ });
1986
+ var deleteProjectFn_createServerFn_handler = createServerRpc({
1987
+ id: "164ee82cdd565ed96591a64312f0f7bd961040baf066a89d9f5636330d11360b",
1988
+ name: "deleteProjectFn",
1989
+ filename: "src/lib/codex-server.ts"
1990
+ }, (opts) => deleteProjectFn.__executeServer(opts));
1991
+ var deleteProjectFn = createServerFn({ method: "POST" }).inputValidator(deleteProjectSchema).handler(deleteProjectFn_createServerFn_handler, async ({ data }) => {
1992
+ return deleteCodexProject(getDbPath(), data.project, { deleteSessionFiles: data.deleteSessionFiles });
1993
+ });
1994
+ //#endregion
1995
+ export { deleteProjectFn_createServerFn_handler, deleteThreadFn_createServerFn_handler, deleteThreadsFn_createServerFn_handler, exportThreadFn_createServerFn_handler, exportThreadsFn_createServerFn_handler, getAnalyticsFn_createServerFn_handler, getDashboardSummaryFn_createServerFn_handler, getThreadSnapshotFn_createServerFn_handler, getThreadTranscriptFn_createServerFn_handler, listProjectThreadsFn_createServerFn_handler, listProjectsFn_createServerFn_handler };