@tryarcanist/cli 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +235 -70
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
import { createRequire } from "module";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
|
|
7
|
+
// ../../shared/utils/url.ts
|
|
8
|
+
function normalizeBaseUrl(url) {
|
|
9
|
+
return url.replace(/\/+$/, "");
|
|
10
|
+
}
|
|
11
|
+
|
|
7
12
|
// src/api.ts
|
|
8
13
|
async function apiRequest(config, path, init) {
|
|
9
|
-
const res = await fetch(`${config.apiUrl}${path}`, {
|
|
14
|
+
const res = await fetch(`${normalizeBaseUrl(config.apiUrl)}${path}`, {
|
|
10
15
|
...init,
|
|
11
16
|
headers: {
|
|
12
17
|
"Content-Type": "application/json",
|
|
@@ -40,14 +45,15 @@ var CONFIG_DIR = join(homedir(), ".arcanist");
|
|
|
40
45
|
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
41
46
|
function loadConfig() {
|
|
42
47
|
try {
|
|
43
|
-
|
|
48
|
+
const config = JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
49
|
+
return { ...config, apiUrl: normalizeBaseUrl(config.apiUrl) };
|
|
44
50
|
} catch {
|
|
45
51
|
return null;
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
54
|
function saveConfig(config) {
|
|
49
55
|
mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
50
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
56
|
+
writeFileSync(CONFIG_FILE, JSON.stringify({ ...config, apiUrl: normalizeBaseUrl(config.apiUrl) }, null, 2) + "\n", { mode: 384 });
|
|
51
57
|
}
|
|
52
58
|
function requireConfig() {
|
|
53
59
|
const config = loadConfig();
|
|
@@ -146,7 +152,7 @@ async function loginCommand(options) {
|
|
|
146
152
|
process.exit(1);
|
|
147
153
|
}
|
|
148
154
|
}
|
|
149
|
-
const apiUrl = options.apiUrl ?? loadConfig()?.apiUrl ?? "https://app.tryarcanist.com";
|
|
155
|
+
const apiUrl = normalizeBaseUrl(options.apiUrl ?? loadConfig()?.apiUrl ?? "https://app.tryarcanist.com");
|
|
150
156
|
saveConfig({ apiUrl, token });
|
|
151
157
|
console.log(`Logged in. API: ${apiUrl}`);
|
|
152
158
|
try {
|
|
@@ -219,151 +225,285 @@ async function stopCommand(sessionId) {
|
|
|
219
225
|
}
|
|
220
226
|
}
|
|
221
227
|
|
|
222
|
-
//
|
|
228
|
+
// ../../shared/transcript/projector.ts
|
|
229
|
+
var DUPLICATE_TEXT_DELTA_MIN_CHARS = 24;
|
|
230
|
+
var RAW_OPENCODE_NOISE = /* @__PURE__ */ new Set([
|
|
231
|
+
"session.updated",
|
|
232
|
+
"session.diff",
|
|
233
|
+
"server.heartbeat",
|
|
234
|
+
"session.idle",
|
|
235
|
+
"lsp.updated",
|
|
236
|
+
"lsp.client.diagnostics"
|
|
237
|
+
]);
|
|
238
|
+
function shouldAppendTextDelta(existingText, incomingText) {
|
|
239
|
+
if (!incomingText) return false;
|
|
240
|
+
if (incomingText.length < DUPLICATE_TEXT_DELTA_MIN_CHARS) return true;
|
|
241
|
+
return !existingText.endsWith(incomingText);
|
|
242
|
+
}
|
|
243
|
+
function isRecord(value) {
|
|
244
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
245
|
+
}
|
|
246
|
+
function resolveEventId(data, prefix, index) {
|
|
247
|
+
return typeof data?.id === "string" ? data.id : `${prefix}-${index}`;
|
|
248
|
+
}
|
|
249
|
+
function resolveTextValue(data) {
|
|
250
|
+
const text = data?.text;
|
|
251
|
+
if (typeof text === "string") return text;
|
|
252
|
+
const content = data?.content;
|
|
253
|
+
return typeof content === "string" ? content : "";
|
|
254
|
+
}
|
|
255
|
+
function resolvePromptId(data) {
|
|
256
|
+
return typeof data?.promptId === "string" ? data.promptId : void 0;
|
|
257
|
+
}
|
|
258
|
+
function mergeToolCall(previous, incoming) {
|
|
259
|
+
return {
|
|
260
|
+
...incoming,
|
|
261
|
+
...incoming.promptId === void 0 && previous.promptId !== void 0 ? { promptId: previous.promptId } : {},
|
|
262
|
+
...incoming.input === void 0 && previous.input !== void 0 ? { input: previous.input } : {},
|
|
263
|
+
...incoming.toolStatus === void 0 && previous.toolStatus !== void 0 ? { toolStatus: previous.toolStatus } : {},
|
|
264
|
+
...incoming.truncated === void 0 && previous.truncated !== void 0 ? { truncated: previous.truncated } : {},
|
|
265
|
+
...incoming.inputEstimatedTokens === void 0 && previous.inputEstimatedTokens !== void 0 ? { inputEstimatedTokens: previous.inputEstimatedTokens } : {},
|
|
266
|
+
...incoming.outputEstimatedTokens === void 0 && previous.outputEstimatedTokens !== void 0 ? { outputEstimatedTokens: previous.outputEstimatedTokens } : {},
|
|
267
|
+
...incoming.outputChars === void 0 && previous.outputChars !== void 0 ? { outputChars: previous.outputChars } : {},
|
|
268
|
+
...incoming.duplicateCount === void 0 && previous.duplicateCount !== void 0 ? { duplicateCount: previous.duplicateCount } : {}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function normalizeToolStatus(value) {
|
|
272
|
+
return value === "running" || value === "completed" || value === "error" ? value : void 0;
|
|
273
|
+
}
|
|
223
274
|
function flattenSessionEvents(raw) {
|
|
224
275
|
const merged = [];
|
|
225
276
|
const streamableIndexById = /* @__PURE__ */ new Map();
|
|
226
277
|
const toolCallIndexById = /* @__PURE__ */ new Map();
|
|
278
|
+
const questionIndexById = /* @__PURE__ */ new Map();
|
|
227
279
|
for (const event of raw) {
|
|
228
|
-
const data = event.data
|
|
280
|
+
const data = isRecord(event.data) ? event.data : void 0;
|
|
229
281
|
if (event.type === "sandbox_compaction_start") {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
282
|
+
merged.push({
|
|
283
|
+
type: "compaction_start",
|
|
284
|
+
id: `cs-${data?.timestamp ?? merged.length}`,
|
|
285
|
+
...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {},
|
|
286
|
+
...typeof data?.contextTokens === "number" ? { contextTokens: data.contextTokens } : {}
|
|
287
|
+
});
|
|
233
288
|
continue;
|
|
234
289
|
}
|
|
235
290
|
if (event.type === "sandbox_compaction_complete") {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
291
|
+
merged.push({
|
|
292
|
+
type: "compaction_complete",
|
|
293
|
+
id: `cc-${data?.timestamp ?? merged.length}`,
|
|
294
|
+
...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {},
|
|
295
|
+
...typeof data?.contextTokensBefore === "number" ? { contextTokensBefore: data.contextTokensBefore } : {},
|
|
296
|
+
...typeof data?.contextTokensAfter === "number" ? { contextTokensAfter: data.contextTokensAfter } : {}
|
|
297
|
+
});
|
|
240
298
|
continue;
|
|
241
299
|
}
|
|
242
300
|
if (event.type === "sandbox_context_fill_warning") {
|
|
243
|
-
|
|
301
|
+
merged.push({
|
|
244
302
|
type: "context_fill_warning",
|
|
245
|
-
id: `cfw-${data
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
303
|
+
id: `cfw-${data?.timestamp ?? merged.length}`,
|
|
304
|
+
...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {},
|
|
305
|
+
fillPercent: typeof data?.fillPercent === "number" ? data.fillPercent : Number(data?.fillPercent ?? 0),
|
|
306
|
+
...typeof data?.contextTokens === "number" ? { contextTokens: data.contextTokens } : {},
|
|
307
|
+
...typeof data?.contextWindow === "number" ? { contextWindow: data.contextWindow } : {}
|
|
308
|
+
});
|
|
251
309
|
continue;
|
|
252
310
|
}
|
|
253
311
|
if (event.type === "sandbox_tool_truncated") {
|
|
254
312
|
merged.push({
|
|
255
313
|
type: "tool_truncated",
|
|
256
|
-
id:
|
|
257
|
-
tool:
|
|
314
|
+
id: typeof data?.callId === "string" ? data.callId : String(merged.length),
|
|
315
|
+
tool: typeof data?.tool === "string" ? data.tool : "",
|
|
316
|
+
...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {}
|
|
317
|
+
});
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if (event.type === "retry_status") {
|
|
321
|
+
merged.push({
|
|
322
|
+
type: "retry_status",
|
|
323
|
+
id: `rs-${data?.timestamp ?? merged.length}`,
|
|
324
|
+
...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {},
|
|
325
|
+
attempt: typeof data?.attempt === "number" ? data.attempt : Number(data?.attempt ?? 0),
|
|
326
|
+
message: typeof data?.message === "string" ? data.message : "Retrying...",
|
|
327
|
+
...typeof data?.nextRetryAt === "string" ? { nextRetryAt: data.nextRetryAt } : {},
|
|
328
|
+
...typeof data?.provider === "string" ? { provider: data.provider } : {},
|
|
329
|
+
...typeof data?.errorCode === "string" ? { errorCode: data.errorCode } : {}
|
|
258
330
|
});
|
|
259
331
|
continue;
|
|
260
332
|
}
|
|
261
333
|
if (event.type === "branch_changed") {
|
|
262
|
-
merged.push({
|
|
334
|
+
merged.push({
|
|
335
|
+
type: "branch_changed",
|
|
336
|
+
id: `bc-${data?.timestamp ?? merged.length}`,
|
|
337
|
+
branch: typeof data?.branch === "string" ? data.branch : "",
|
|
338
|
+
...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {}
|
|
339
|
+
});
|
|
263
340
|
continue;
|
|
264
341
|
}
|
|
265
342
|
if (event.type === "session_error") {
|
|
266
|
-
|
|
343
|
+
merged.push({
|
|
267
344
|
type: "session_error",
|
|
268
|
-
id:
|
|
269
|
-
error:
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
345
|
+
id: resolveEventId(data, "err", merged.length),
|
|
346
|
+
error: typeof data?.error === "string" ? data.error : "Unknown error",
|
|
347
|
+
...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {},
|
|
348
|
+
...typeof data?.code === "string" ? { code: data.code } : {}
|
|
349
|
+
});
|
|
273
350
|
continue;
|
|
274
351
|
}
|
|
275
352
|
if (event.type === "raw_opencode") {
|
|
276
|
-
|
|
353
|
+
const partType = typeof data?.partType === "string" ? data.partType : void 0;
|
|
354
|
+
const eventType = typeof data?.eventType === "string" ? data.eventType : void 0;
|
|
355
|
+
if (partType === "text") continue;
|
|
356
|
+
if (eventType && RAW_OPENCODE_NOISE.has(eventType)) continue;
|
|
357
|
+
merged.push({
|
|
358
|
+
type: "raw_opencode",
|
|
359
|
+
id: resolveEventId(data, "raw", merged.length),
|
|
360
|
+
...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {},
|
|
361
|
+
...partType ? { partType } : {},
|
|
362
|
+
...eventType ? { eventType } : {},
|
|
363
|
+
data: data ?? {}
|
|
364
|
+
});
|
|
277
365
|
continue;
|
|
278
366
|
}
|
|
279
367
|
if (event.type === "reasoning") {
|
|
280
|
-
const id =
|
|
281
|
-
const text =
|
|
368
|
+
const id = resolveEventId(data, "reasoning", merged.length);
|
|
369
|
+
const text = resolveTextValue(data);
|
|
370
|
+
const promptId = resolvePromptId(data);
|
|
282
371
|
const existingIdx = streamableIndexById.get(id);
|
|
283
372
|
if (existingIdx !== void 0) {
|
|
284
373
|
const existing = merged[existingIdx];
|
|
285
|
-
if (existing.type === "reasoning"
|
|
374
|
+
if (existing.type === "reasoning" && shouldAppendTextDelta(existing.text, text)) {
|
|
375
|
+
existing.text += text;
|
|
376
|
+
if (!existing.promptId && promptId) existing.promptId = promptId;
|
|
377
|
+
}
|
|
286
378
|
} else {
|
|
287
379
|
streamableIndexById.set(id, merged.length);
|
|
288
|
-
merged.push({
|
|
380
|
+
merged.push({
|
|
381
|
+
type: "reasoning",
|
|
382
|
+
id,
|
|
383
|
+
text,
|
|
384
|
+
...promptId ? { promptId } : {}
|
|
385
|
+
});
|
|
289
386
|
}
|
|
290
387
|
continue;
|
|
291
388
|
}
|
|
292
389
|
if (event.type === "patch") {
|
|
293
|
-
const files = Array.isArray(data
|
|
294
|
-
if (files.length > 0)
|
|
390
|
+
const files = Array.isArray(data?.files) ? data.files.filter((item) => typeof item === "string") : [];
|
|
391
|
+
if (files.length > 0) {
|
|
392
|
+
merged.push({ type: "patch", id: `patch-${merged.length}`, files });
|
|
393
|
+
if (resolvePromptId(data)) {
|
|
394
|
+
const last = merged[merged.length - 1];
|
|
395
|
+
if (last?.type === "patch") last.promptId = resolvePromptId(data);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
295
398
|
continue;
|
|
296
399
|
}
|
|
297
400
|
if (event.type === "todo_update") {
|
|
298
|
-
const todos = Array.isArray(data
|
|
401
|
+
const todos = Array.isArray(data?.todos) ? data.todos : [];
|
|
299
402
|
if (todos.length > 0) {
|
|
300
|
-
for (let
|
|
301
|
-
const existing = merged[
|
|
403
|
+
for (let index = merged.length - 1; index >= 0; index--) {
|
|
404
|
+
const existing = merged[index];
|
|
302
405
|
if (existing.type === "tool_call" && existing.tool.toLowerCase() === "todowrite") {
|
|
303
|
-
|
|
406
|
+
merged[index] = { ...existing, input: { ...existing.input, todos } };
|
|
304
407
|
break;
|
|
305
408
|
}
|
|
306
409
|
}
|
|
307
410
|
}
|
|
308
411
|
continue;
|
|
309
412
|
}
|
|
413
|
+
if (event.type === "answer") {
|
|
414
|
+
const questionId = typeof data?.id === "string" ? data.id : void 0;
|
|
415
|
+
if (!questionId) continue;
|
|
416
|
+
const existingIdx = questionIndexById.get(questionId);
|
|
417
|
+
if (existingIdx !== void 0) {
|
|
418
|
+
const existing = merged[existingIdx];
|
|
419
|
+
if (existing?.type === "question") {
|
|
420
|
+
merged[existingIdx] = {
|
|
421
|
+
...existing,
|
|
422
|
+
answer: data?.answer == null ? null : String(data.answer)
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
310
428
|
if (event.type !== "text" && event.type !== "tool_call" && event.type !== "tool_update" && event.type !== "question") {
|
|
311
429
|
continue;
|
|
312
430
|
}
|
|
313
431
|
if (event.type === "text") {
|
|
314
|
-
const id =
|
|
315
|
-
const text =
|
|
432
|
+
const id = resolveEventId(data, "text", merged.length);
|
|
433
|
+
const text = resolveTextValue(data);
|
|
434
|
+
const promptId = resolvePromptId(data);
|
|
316
435
|
const existingIdx = streamableIndexById.get(id);
|
|
317
436
|
if (existingIdx !== void 0) {
|
|
318
437
|
const existing = merged[existingIdx];
|
|
319
|
-
if (existing.type === "text"
|
|
438
|
+
if (existing.type === "text" && shouldAppendTextDelta(existing.text, text)) {
|
|
439
|
+
existing.text += text;
|
|
440
|
+
if (!existing.promptId && promptId) existing.promptId = promptId;
|
|
441
|
+
}
|
|
320
442
|
} else {
|
|
321
443
|
streamableIndexById.set(id, merged.length);
|
|
322
|
-
merged.push({
|
|
444
|
+
merged.push({
|
|
445
|
+
type: "text",
|
|
446
|
+
id,
|
|
447
|
+
text,
|
|
448
|
+
...promptId ? { promptId } : {}
|
|
449
|
+
});
|
|
323
450
|
}
|
|
324
451
|
continue;
|
|
325
452
|
}
|
|
326
453
|
if (event.type === "tool_call") {
|
|
327
|
-
const id =
|
|
328
|
-
const
|
|
454
|
+
const id = resolveEventId(data, "tool", merged.length);
|
|
455
|
+
const nextEntry = {
|
|
329
456
|
type: "tool_call",
|
|
330
457
|
id,
|
|
331
|
-
tool:
|
|
332
|
-
summary:
|
|
458
|
+
tool: typeof data?.tool === "string" ? data.tool : typeof data?.toolName === "string" ? data.toolName : "unknown",
|
|
459
|
+
summary: typeof data?.summary === "string" ? data.summary : "",
|
|
460
|
+
...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {},
|
|
461
|
+
...isRecord(data?.input) ? { input: data.input } : {},
|
|
462
|
+
...normalizeToolStatus(data?.toolStatus) ? { toolStatus: normalizeToolStatus(data?.toolStatus) } : {},
|
|
463
|
+
...typeof data?.truncated === "boolean" ? { truncated: data.truncated } : {},
|
|
464
|
+
...typeof data?.inputEstimatedTokens === "number" ? { inputEstimatedTokens: data.inputEstimatedTokens } : {},
|
|
465
|
+
...typeof data?.outputEstimatedTokens === "number" ? { outputEstimatedTokens: data.outputEstimatedTokens } : {},
|
|
466
|
+
...typeof data?.outputChars === "number" ? { outputChars: data.outputChars } : {}
|
|
333
467
|
};
|
|
334
|
-
if (data.input && typeof data.input === "object") entry2.input = data.input;
|
|
335
468
|
const existingIdx = toolCallIndexById.get(id);
|
|
336
469
|
if (existingIdx !== void 0) {
|
|
337
|
-
const
|
|
338
|
-
if (
|
|
339
|
-
|
|
340
|
-
merged[existingIdx] = entry2;
|
|
470
|
+
const previous = merged[existingIdx];
|
|
471
|
+
if (previous.type === "tool_call") {
|
|
472
|
+
merged[existingIdx] = mergeToolCall(previous, nextEntry);
|
|
341
473
|
}
|
|
342
474
|
} else {
|
|
343
475
|
toolCallIndexById.set(id, merged.length);
|
|
344
|
-
merged.push(
|
|
476
|
+
merged.push(nextEntry);
|
|
345
477
|
}
|
|
346
478
|
continue;
|
|
347
479
|
}
|
|
348
480
|
if (event.type === "tool_update") {
|
|
349
|
-
const id =
|
|
481
|
+
const id = typeof data?.id === "string" ? data.id : "";
|
|
350
482
|
const existingIdx = toolCallIndexById.get(id);
|
|
351
483
|
if (existingIdx !== void 0) {
|
|
352
|
-
const
|
|
353
|
-
if (
|
|
354
|
-
|
|
484
|
+
const previous = merged[existingIdx];
|
|
485
|
+
if (previous.type === "tool_call") {
|
|
486
|
+
merged[existingIdx] = {
|
|
487
|
+
...previous,
|
|
488
|
+
...normalizeToolStatus(data?.status) ? { toolStatus: normalizeToolStatus(data?.status) } : {},
|
|
489
|
+
...typeof data?.outputEstimatedTokens === "number" ? { outputEstimatedTokens: data.outputEstimatedTokens } : {},
|
|
490
|
+
...typeof data?.outputChars === "number" ? { outputChars: data.outputChars } : {},
|
|
491
|
+
...typeof data?.truncated === "boolean" ? { truncated: data.truncated } : {}
|
|
492
|
+
};
|
|
355
493
|
}
|
|
356
494
|
}
|
|
357
495
|
continue;
|
|
358
496
|
}
|
|
359
|
-
const
|
|
497
|
+
const question = {
|
|
360
498
|
type: "question",
|
|
361
|
-
id:
|
|
362
|
-
question:
|
|
363
|
-
answer: data
|
|
499
|
+
id: resolveEventId(data, "question", merged.length),
|
|
500
|
+
question: typeof data?.question === "string" ? data.question : "",
|
|
501
|
+
answer: data?.answer == null ? null : String(data.answer),
|
|
502
|
+
...resolvePromptId(data) ? { promptId: resolvePromptId(data) } : {},
|
|
503
|
+
...Array.isArray(data?.options) ? { options: data.options } : {}
|
|
364
504
|
};
|
|
365
|
-
|
|
366
|
-
merged.push(
|
|
505
|
+
questionIndexById.set(question.id, merged.length);
|
|
506
|
+
merged.push(question);
|
|
367
507
|
}
|
|
368
508
|
return merged;
|
|
369
509
|
}
|
|
@@ -372,17 +512,39 @@ function partitionEventsByPrompt(allEvents, promptIds) {
|
|
|
372
512
|
const buckets = new Map(promptIds.map((id) => [id, []]));
|
|
373
513
|
let currentPromptId = null;
|
|
374
514
|
for (const event of allEvents) {
|
|
515
|
+
const explicitPromptId = typeof event.data?.promptId === "string" && promptSet.has(event.data.promptId) ? event.data.promptId : null;
|
|
375
516
|
if (event.type === "prompt_processing") {
|
|
376
|
-
|
|
377
|
-
currentPromptId = promptId && promptSet.has(promptId) ? promptId : null;
|
|
517
|
+
currentPromptId = explicitPromptId;
|
|
378
518
|
}
|
|
379
|
-
|
|
380
|
-
|
|
519
|
+
const targetPromptId = explicitPromptId ?? currentPromptId;
|
|
520
|
+
if (targetPromptId) {
|
|
521
|
+
const bucket = buckets.get(targetPromptId);
|
|
381
522
|
if (bucket) bucket.push(event);
|
|
382
523
|
}
|
|
383
524
|
}
|
|
384
525
|
return buckets;
|
|
385
526
|
}
|
|
527
|
+
function getEmbeddedTerminalHistory(raw) {
|
|
528
|
+
for (let index = raw.length - 1; index >= 0; index--) {
|
|
529
|
+
const event = raw[index];
|
|
530
|
+
if (event.type !== "prompt_completed" && event.type !== "prompt_failed") continue;
|
|
531
|
+
const history = event.data?.history;
|
|
532
|
+
if (!Array.isArray(history) || history.length === 0) return null;
|
|
533
|
+
return history;
|
|
534
|
+
}
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
function resolveAuthoritativePromptEvents(raw) {
|
|
538
|
+
return getEmbeddedTerminalHistory(raw) ?? raw;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/utils/session-output.ts
|
|
542
|
+
function flattenSessionEvents2(raw) {
|
|
543
|
+
return flattenSessionEvents(raw);
|
|
544
|
+
}
|
|
545
|
+
function partitionEventsByPrompt2(allEvents, promptIds) {
|
|
546
|
+
return partitionEventsByPrompt(allEvents, promptIds);
|
|
547
|
+
}
|
|
386
548
|
function formatDate(value) {
|
|
387
549
|
const date = new Date(value);
|
|
388
550
|
if (Number.isNaN(date.getTime())) return value;
|
|
@@ -408,6 +570,9 @@ ${event.text}
|
|
|
408
570
|
return `**Question:** ${event.question}
|
|
409
571
|
${event.answer ? `**Answer:** ${event.answer}
|
|
410
572
|
` : ""}`;
|
|
573
|
+
case "retry_status":
|
|
574
|
+
return `*[retry ${event.attempt}: ${event.message}]*
|
|
575
|
+
`;
|
|
411
576
|
case "compaction_start":
|
|
412
577
|
return event.contextTokens ? `*[compacting context at ${Math.round(event.contextTokens / 1e3)}k tokens]*
|
|
413
578
|
` : "*[compacting context]*\n";
|
|
@@ -440,7 +605,7 @@ function formatNumber(value) {
|
|
|
440
605
|
function renderSessionTranscript(exportData) {
|
|
441
606
|
const lines = [];
|
|
442
607
|
const promptIds = exportData.prompts.map((prompt) => prompt.id);
|
|
443
|
-
const eventBuckets =
|
|
608
|
+
const eventBuckets = partitionEventsByPrompt2(exportData.events, promptIds);
|
|
444
609
|
lines.push("# Session transcript\n");
|
|
445
610
|
if (exportData.session.repoUrl) lines.push(`**Repo:** ${exportData.session.repoUrl} `);
|
|
446
611
|
lines.push(`**Session:** ${exportData.session.id.slice(0, 8)} `);
|
|
@@ -454,7 +619,7 @@ function renderSessionTranscript(exportData) {
|
|
|
454
619
|
for (let i = 0; i < exportData.prompts.length; i++) {
|
|
455
620
|
const prompt = exportData.prompts[i];
|
|
456
621
|
const rawEvents = eventBuckets.get(prompt.id) ?? [];
|
|
457
|
-
const events =
|
|
622
|
+
const events = flattenSessionEvents2(resolveAuthoritativePromptEvents(rawEvents));
|
|
458
623
|
lines.push("---\n");
|
|
459
624
|
lines.push(`## Turn ${i + 1}
|
|
460
625
|
`);
|