@linzumi/cli 0.0.67-beta → 0.0.69-beta
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/README.md +1 -1
- package/dist/index.js +560 -98
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -286,6 +286,7 @@ var init_channelSessionSupport = __esm({
|
|
|
286
286
|
|
|
287
287
|
// src/commanderAttachments.ts
|
|
288
288
|
import { readFile, realpath, stat, writeFile, mkdir } from "node:fs/promises";
|
|
289
|
+
import { homedir } from "node:os";
|
|
289
290
|
import {
|
|
290
291
|
basename,
|
|
291
292
|
extname,
|
|
@@ -402,13 +403,14 @@ async function uploadedFileIdsForCommanderOutput(runtime, body, structured) {
|
|
|
402
403
|
return [];
|
|
403
404
|
}
|
|
404
405
|
const cwdRealPath = await realpath(runtime.cwd);
|
|
406
|
+
const uploadRoots = await commanderAttachmentUploadRoots(cwdRealPath);
|
|
405
407
|
const paths = await extractKandanAttachmentPaths(body, cwdRealPath);
|
|
406
408
|
if (paths.length === 0) {
|
|
407
409
|
return [];
|
|
408
410
|
}
|
|
409
411
|
const files = await Promise.all(
|
|
410
412
|
paths.map(async (path2) => {
|
|
411
|
-
assertCommanderAttachmentUploadAllowed(
|
|
413
|
+
assertCommanderAttachmentUploadAllowed(uploadRoots, path2);
|
|
412
414
|
const info = await stat(path2);
|
|
413
415
|
if (!info.isFile()) {
|
|
414
416
|
throw new Error(`Kandan attachment path is not a file: ${path2}`);
|
|
@@ -556,13 +558,19 @@ async function extractKandanAttachmentPaths(body, cwdRealPath) {
|
|
|
556
558
|
const paths = [];
|
|
557
559
|
for (const line of lines.slice(headingIndex + 1)) {
|
|
558
560
|
const trimmed = line.trim();
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
561
|
+
const rawPath = kandanAttachmentRawPath(trimmed);
|
|
562
|
+
if (rawPath === "") {
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
if (rawPath === void 0) {
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
if (commanderAttachmentRawPathHasHiddenSegment(rawPath)) {
|
|
563
569
|
continue;
|
|
564
570
|
}
|
|
565
|
-
|
|
571
|
+
if (!isCommanderAttachmentUploadPathCandidate(rawPath)) {
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
566
574
|
const resolvedPath = await resolveCommanderAttachmentPath(
|
|
567
575
|
cwdRealPath,
|
|
568
576
|
rawPath
|
|
@@ -575,27 +583,34 @@ async function extractKandanAttachmentPaths(body, cwdRealPath) {
|
|
|
575
583
|
}
|
|
576
584
|
return paths;
|
|
577
585
|
}
|
|
586
|
+
function kandanAttachmentRawPath(trimmedLine) {
|
|
587
|
+
if (trimmedLine === "") {
|
|
588
|
+
return "";
|
|
589
|
+
}
|
|
590
|
+
const rawPath = trimmedLine.startsWith("- ") ? trimmedLine.slice(2).trim() : trimmedLine;
|
|
591
|
+
if (rawPath === "") {
|
|
592
|
+
return void 0;
|
|
593
|
+
}
|
|
594
|
+
return rawPath.replace(/^`|`$/g, "");
|
|
595
|
+
}
|
|
578
596
|
async function resolveCommanderAttachmentPath(cwdRealPath, rawPath) {
|
|
579
597
|
if (rawPath === "") {
|
|
580
598
|
throw new Error("Kandan attachment path must not be empty");
|
|
581
599
|
}
|
|
582
600
|
const candidatePath = isAbsolute(rawPath) ? resolve(rawPath) : resolve(cwdRealPath, rawPath);
|
|
583
|
-
|
|
584
|
-
const relativePath = relative(cwdRealPath, path2);
|
|
585
|
-
if (relativePath.startsWith("..") || isAbsolute(relativePath)) {
|
|
586
|
-
throw new Error(
|
|
587
|
-
`Kandan attachment path must resolve inside the runner cwd: ${rawPath}`
|
|
588
|
-
);
|
|
589
|
-
}
|
|
590
|
-
return path2;
|
|
601
|
+
return await realpath(candidatePath);
|
|
591
602
|
}
|
|
592
|
-
function assertCommanderAttachmentUploadAllowed(
|
|
593
|
-
const
|
|
594
|
-
|
|
603
|
+
function assertCommanderAttachmentUploadAllowed(uploadRoots, filePath) {
|
|
604
|
+
const matchedRoot = uploadRoots.find(
|
|
605
|
+
(root) => pathIsInsideRoot(root.path, filePath)
|
|
606
|
+
);
|
|
607
|
+
if (matchedRoot === void 0) {
|
|
608
|
+
const rootLabels = uploadRoots.map((root) => root.label).join(", ");
|
|
595
609
|
throw new Error(
|
|
596
|
-
`Kandan attachment path must resolve inside
|
|
610
|
+
`Kandan attachment path must resolve inside an allowed upload root (${rootLabels}): ${filePath}`
|
|
597
611
|
);
|
|
598
612
|
}
|
|
613
|
+
const relativePath = relative(matchedRoot.path, filePath);
|
|
599
614
|
const hiddenSegment = relativePath.split(/[\\/]+/).find((segment) => segment.startsWith("."));
|
|
600
615
|
if (hiddenSegment !== void 0) {
|
|
601
616
|
throw new Error(
|
|
@@ -609,6 +624,25 @@ function assertCommanderAttachmentUploadAllowed(cwdRealPath, filePath) {
|
|
|
609
624
|
);
|
|
610
625
|
}
|
|
611
626
|
}
|
|
627
|
+
async function commanderAttachmentUploadRoots(cwdRealPath) {
|
|
628
|
+
const roots = [
|
|
629
|
+
{ path: cwdRealPath, label: "runner cwd" }
|
|
630
|
+
];
|
|
631
|
+
const downloadsPath = resolve(homedir(), "Downloads");
|
|
632
|
+
try {
|
|
633
|
+
const downloadsRealPath = await realpath(downloadsPath);
|
|
634
|
+
if (!roots.some((root) => root.path === downloadsRealPath)) {
|
|
635
|
+
roots.push({ path: downloadsRealPath, label: "~/Downloads" });
|
|
636
|
+
}
|
|
637
|
+
} catch (_error) {
|
|
638
|
+
return roots;
|
|
639
|
+
}
|
|
640
|
+
return roots;
|
|
641
|
+
}
|
|
642
|
+
function pathIsInsideRoot(rootPath, filePath) {
|
|
643
|
+
const relativePath = relative(rootPath, filePath);
|
|
644
|
+
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath);
|
|
645
|
+
}
|
|
612
646
|
function contentTypeForFileName(fileName) {
|
|
613
647
|
const lower = fileName.toLowerCase();
|
|
614
648
|
if (lower.endsWith(".png")) {
|
|
@@ -634,6 +668,69 @@ function contentTypeForFileName(fileName) {
|
|
|
634
668
|
}
|
|
635
669
|
return "application/octet-stream";
|
|
636
670
|
}
|
|
671
|
+
function bodyWithoutKandanAttachmentFooter(body) {
|
|
672
|
+
const lines = body.split(/\r?\n/);
|
|
673
|
+
const headingIndex = lines.findIndex(
|
|
674
|
+
(line) => line.trim().toLowerCase() === "kandan attachments:"
|
|
675
|
+
);
|
|
676
|
+
if (headingIndex === -1) {
|
|
677
|
+
return body;
|
|
678
|
+
}
|
|
679
|
+
const visibleAfterLines = [];
|
|
680
|
+
let sawVisibleAfterLine = false;
|
|
681
|
+
for (const line of lines.slice(headingIndex + 1)) {
|
|
682
|
+
if (line.trim() === "") {
|
|
683
|
+
switch (sawVisibleAfterLine) {
|
|
684
|
+
case true:
|
|
685
|
+
visibleAfterLines.push(line);
|
|
686
|
+
break;
|
|
687
|
+
case false:
|
|
688
|
+
break;
|
|
689
|
+
}
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
if (isKandanAttachmentDisplayDirectiveLine(line)) {
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
visibleAfterLines.push(line);
|
|
696
|
+
sawVisibleAfterLine = true;
|
|
697
|
+
}
|
|
698
|
+
const visibleLines = [...lines.slice(0, headingIndex), ...visibleAfterLines];
|
|
699
|
+
while (visibleLines.length > 0 && visibleLines[visibleLines.length - 1]?.trim() === "") {
|
|
700
|
+
visibleLines.pop();
|
|
701
|
+
}
|
|
702
|
+
return visibleLines.join("\n");
|
|
703
|
+
}
|
|
704
|
+
function displayBodyForCommanderOutput(body, uploadedFileIds) {
|
|
705
|
+
const displayBody = bodyWithoutKandanAttachmentFooter(body);
|
|
706
|
+
switch (displayBody.trim() === "" && uploadedFileIds.length > 0) {
|
|
707
|
+
case true:
|
|
708
|
+
return "Attached file.";
|
|
709
|
+
case false:
|
|
710
|
+
return displayBody;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
function structuredWithAssistantContent(structured, content) {
|
|
714
|
+
return stringValue(structured.kind) === "codex_assistant_message" ? { ...structured, content } : structured;
|
|
715
|
+
}
|
|
716
|
+
function isKandanAttachmentDisplayDirectiveLine(line) {
|
|
717
|
+
const rawPath = kandanAttachmentRawPath(line.trim());
|
|
718
|
+
if (rawPath === "") {
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
721
|
+
if (rawPath === void 0) {
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
return !commanderAttachmentRawPathHasHiddenSegment(rawPath) && commanderAttachmentUploadExtensions.has(extname(rawPath).toLowerCase());
|
|
725
|
+
}
|
|
726
|
+
function isCommanderAttachmentUploadPathCandidate(rawPath) {
|
|
727
|
+
return commanderAttachmentUploadExtensions.has(
|
|
728
|
+
extname(rawPath).toLowerCase()
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
function commanderAttachmentRawPathHasHiddenSegment(rawPath) {
|
|
732
|
+
return rawPath.split(/[\\/]+/).some((segment) => segment.startsWith("."));
|
|
733
|
+
}
|
|
637
734
|
async function pushOk(kandan, topic, event, payload) {
|
|
638
735
|
const reply = await kandan.push(topic, event, payload);
|
|
639
736
|
if (isJsonObject(reply) && reply.status === "ok" && isJsonObject(reply.response)) {
|
|
@@ -754,6 +851,7 @@ var init_codexRuntimeOptions = __esm({
|
|
|
754
851
|
|
|
755
852
|
// src/codexOutput.ts
|
|
756
853
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
854
|
+
import { fileURLToPath } from "node:url";
|
|
757
855
|
function codexOutputMessagesForTurn(response, turnId) {
|
|
758
856
|
if ("error" in response) {
|
|
759
857
|
return [];
|
|
@@ -803,19 +901,10 @@ function codexOutputMessagesForItem(item, index) {
|
|
|
803
901
|
}
|
|
804
902
|
];
|
|
805
903
|
}
|
|
806
|
-
case "agentMessage":
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
itemKey,
|
|
811
|
-
body: text2,
|
|
812
|
-
structured: baseStructured("codex_assistant_message", {
|
|
813
|
-
content: text2,
|
|
814
|
-
phase: stringValue(item.phase) ?? "final_answer"
|
|
815
|
-
})
|
|
816
|
-
}
|
|
817
|
-
];
|
|
818
|
-
}
|
|
904
|
+
case "agentMessage":
|
|
905
|
+
return codexAssistantMessageForItem(item, itemKey, baseStructured);
|
|
906
|
+
case "message":
|
|
907
|
+
return stringValue(item.role) === "assistant" ? codexAssistantMessageForItem(item, itemKey, baseStructured) : [];
|
|
819
908
|
case "commandExecution": {
|
|
820
909
|
const command = stringValue(item.command) ?? "command";
|
|
821
910
|
const output = nonBlankStringValue(item.aggregatedOutput) ?? "";
|
|
@@ -1121,7 +1210,26 @@ function codexUserInputMessageForItem(item, index) {
|
|
|
1121
1210
|
const body = textParts.length > 0 ? textParts.join("\n\n") : nonBlankStringValue(item.text) ?? nonBlankStringValue(item.message) ?? "";
|
|
1122
1211
|
return [{ itemKey, body }];
|
|
1123
1212
|
}
|
|
1213
|
+
function codexAssistantMessageForItem(item, itemKey, baseStructured) {
|
|
1214
|
+
const text2 = assistantVisibleText(item);
|
|
1215
|
+
const attachmentPaths = assistantImageAttachmentPaths(item);
|
|
1216
|
+
const body = assistantBodyWithAttachmentPaths(text2, attachmentPaths);
|
|
1217
|
+
return [
|
|
1218
|
+
{
|
|
1219
|
+
itemKey,
|
|
1220
|
+
body,
|
|
1221
|
+
structured: baseStructured("codex_assistant_message", {
|
|
1222
|
+
content: text2,
|
|
1223
|
+
phase: stringValue(item.phase) ?? "final_answer"
|
|
1224
|
+
})
|
|
1225
|
+
}
|
|
1226
|
+
];
|
|
1227
|
+
}
|
|
1124
1228
|
function assistantVisibleText(item) {
|
|
1229
|
+
const contentText = assistantContentText(item);
|
|
1230
|
+
if (contentText !== "") {
|
|
1231
|
+
return contentText;
|
|
1232
|
+
}
|
|
1125
1233
|
const direct = stringValue(item.reply) ?? stringValue(item.summary) ?? stringValue(item.content) ?? stringValue(item.text) ?? "";
|
|
1126
1234
|
const parsed = parseJsonObjectOrUndefined(direct);
|
|
1127
1235
|
if (parsed === void 0) {
|
|
@@ -1129,6 +1237,52 @@ function assistantVisibleText(item) {
|
|
|
1129
1237
|
}
|
|
1130
1238
|
return stringValue(parsed.reply) ?? stringValue(parsed.summary) ?? stringValue(parsed.content) ?? stringValue(parsed.message) ?? stringValue(parsed.output_text) ?? direct;
|
|
1131
1239
|
}
|
|
1240
|
+
function assistantContentText(item) {
|
|
1241
|
+
return (arrayValue(item.content) ?? []).filter(isJsonObject).flatMap((part) => {
|
|
1242
|
+
const type = stringValue(part.type);
|
|
1243
|
+
if (type !== "text" && type !== "output_text" && type !== "input_text") {
|
|
1244
|
+
return [];
|
|
1245
|
+
}
|
|
1246
|
+
const text2 = nonBlankStringValue(part.text) ?? nonBlankStringValue(part.content) ?? nonBlankStringValue(part.output_text);
|
|
1247
|
+
return text2 === void 0 ? [] : [text2];
|
|
1248
|
+
}).join("\n\n");
|
|
1249
|
+
}
|
|
1250
|
+
function assistantBodyWithAttachmentPaths(text2, attachmentPaths) {
|
|
1251
|
+
const uniqueAttachmentPaths = [...new Set(attachmentPaths)];
|
|
1252
|
+
if (uniqueAttachmentPaths.length === 0) {
|
|
1253
|
+
return text2;
|
|
1254
|
+
}
|
|
1255
|
+
const attachmentFooter = [
|
|
1256
|
+
"Kandan attachments:",
|
|
1257
|
+
...uniqueAttachmentPaths.map((path2) => `- ${path2}`)
|
|
1258
|
+
].join("\n");
|
|
1259
|
+
const normalizedText = text2.trim();
|
|
1260
|
+
return normalizedText === "" ? attachmentFooter : [text2, "", attachmentFooter].join("\n");
|
|
1261
|
+
}
|
|
1262
|
+
function assistantImageAttachmentPaths(item) {
|
|
1263
|
+
return (arrayValue(item.content) ?? []).filter(isJsonObject).flatMap((part) => {
|
|
1264
|
+
const type = stringValue(part.type)?.toLowerCase();
|
|
1265
|
+
if (type !== "image" && type !== "output_image" && type !== "input_image") {
|
|
1266
|
+
return [];
|
|
1267
|
+
}
|
|
1268
|
+
const rawPath = stringValue(part.path) ?? stringValue(part.file_path) ?? stringValue(part.filePath) ?? stringValue(part.image_url) ?? stringValue(part.imageUrl) ?? stringValue(part.url);
|
|
1269
|
+
const localPath = rawPath === void 0 ? void 0 : localAttachmentPath(rawPath);
|
|
1270
|
+
return localPath === void 0 ? [] : [localPath];
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
function localAttachmentPath(rawPath) {
|
|
1274
|
+
if (/^https?:\/\//i.test(rawPath) || /^data:/i.test(rawPath)) {
|
|
1275
|
+
return void 0;
|
|
1276
|
+
}
|
|
1277
|
+
if (/^file:\/\//i.test(rawPath)) {
|
|
1278
|
+
try {
|
|
1279
|
+
return fileURLToPath(rawPath);
|
|
1280
|
+
} catch (_error) {
|
|
1281
|
+
return void 0;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
return rawPath;
|
|
1285
|
+
}
|
|
1132
1286
|
function assistantDeltaText(params) {
|
|
1133
1287
|
return textDeltaFromParams(params);
|
|
1134
1288
|
}
|
|
@@ -3292,23 +3446,25 @@ async function attachChannelSession(args) {
|
|
|
3292
3446
|
});
|
|
3293
3447
|
}
|
|
3294
3448
|
break;
|
|
3295
|
-
case "turn/completed":
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3449
|
+
case "turn/completed": {
|
|
3450
|
+
const completedTurnId = turnId ?? inferThreadOnlyCompletedTurnId(args, state, threadId);
|
|
3451
|
+
if (completedTurnId !== void 0) {
|
|
3452
|
+
enqueueWebSearchProgressCompletion(args, state, completedTurnId);
|
|
3453
|
+
enqueueFileChangeCompletion(args, state, completedTurnId);
|
|
3299
3454
|
void forwardCompletedCodexTurn(
|
|
3300
3455
|
args,
|
|
3301
3456
|
state,
|
|
3302
|
-
|
|
3457
|
+
completedTurnId,
|
|
3303
3458
|
payloadContext
|
|
3304
3459
|
).catch((error) => {
|
|
3305
3460
|
args.log("codex.turn_forward_failed", {
|
|
3306
|
-
turn_id:
|
|
3461
|
+
turn_id: completedTurnId,
|
|
3307
3462
|
message: error instanceof Error ? error.message : String(error)
|
|
3308
3463
|
});
|
|
3309
3464
|
});
|
|
3310
3465
|
}
|
|
3311
3466
|
break;
|
|
3467
|
+
}
|
|
3312
3468
|
case "item/agentMessage/delta":
|
|
3313
3469
|
enqueueAssistantDelta(args, state, params, payloadContext);
|
|
3314
3470
|
break;
|
|
@@ -3331,6 +3487,32 @@ async function attachChannelSession(args) {
|
|
|
3331
3487
|
case "item/completed":
|
|
3332
3488
|
enqueueWebSearchProgress(args, state, params, payloadContext);
|
|
3333
3489
|
enqueueCompletedFileChange(args, state, params, payloadContext);
|
|
3490
|
+
const completedAssistantItemForward = forwardCompletedAssistantItem(
|
|
3491
|
+
args,
|
|
3492
|
+
state,
|
|
3493
|
+
params,
|
|
3494
|
+
payloadContext
|
|
3495
|
+
);
|
|
3496
|
+
if (turnId !== void 0) {
|
|
3497
|
+
rememberPendingCompletedAssistantItemForward(
|
|
3498
|
+
state,
|
|
3499
|
+
turnId,
|
|
3500
|
+
completedAssistantItemForward
|
|
3501
|
+
);
|
|
3502
|
+
}
|
|
3503
|
+
void completedAssistantItemForward.catch((error) => {
|
|
3504
|
+
args.log("codex.completed_assistant_item_forward_failed", {
|
|
3505
|
+
message: error instanceof Error ? error.message : String(error)
|
|
3506
|
+
});
|
|
3507
|
+
}).finally(() => {
|
|
3508
|
+
if (turnId !== void 0) {
|
|
3509
|
+
forgetPendingCompletedAssistantItemForward(
|
|
3510
|
+
state,
|
|
3511
|
+
turnId,
|
|
3512
|
+
completedAssistantItemForward
|
|
3513
|
+
);
|
|
3514
|
+
}
|
|
3515
|
+
});
|
|
3334
3516
|
if (turnId !== void 0) {
|
|
3335
3517
|
const promise = mirrorLocalTuiInputFromNotification(
|
|
3336
3518
|
args,
|
|
@@ -3424,6 +3606,8 @@ function initialChannelSessionState(cursor, rootSeq, kandanThreadId, codexThread
|
|
|
3424
3606
|
forwardedTurnIds: /* @__PURE__ */ new Set(),
|
|
3425
3607
|
forwardingTurnIds: /* @__PURE__ */ new Set(),
|
|
3426
3608
|
retryableTurnIds: /* @__PURE__ */ new Set(),
|
|
3609
|
+
completedAssistantItemKeys: /* @__PURE__ */ new Set(),
|
|
3610
|
+
pendingCompletedAssistantItemForwards: /* @__PURE__ */ new Map(),
|
|
3427
3611
|
claimedKandanMessageKeys: /* @__PURE__ */ new Set(),
|
|
3428
3612
|
localTuiTurnIds: /* @__PURE__ */ new Set(),
|
|
3429
3613
|
mirroredTuiInputProjections: createBoundedCache(maxForwardedTurnIds),
|
|
@@ -4695,7 +4879,16 @@ async function processKandanChatEvent(args, state, runnerIdentity, event, payloa
|
|
|
4695
4879
|
}
|
|
4696
4880
|
}
|
|
4697
4881
|
async function drainKandanMessageQueue(args, state, payloadContext) {
|
|
4698
|
-
if (state.closed
|
|
4882
|
+
if (state.closed) {
|
|
4883
|
+
logQueuedDrainBlocked(args, state, "session_closed");
|
|
4884
|
+
return;
|
|
4885
|
+
}
|
|
4886
|
+
if (state.turn.status !== "idle") {
|
|
4887
|
+
logQueuedDrainBlocked(args, state, "turn_not_idle");
|
|
4888
|
+
return;
|
|
4889
|
+
}
|
|
4890
|
+
if (localTuiTurnIsActive(state)) {
|
|
4891
|
+
logQueuedDrainBlocked(args, state, "local_tui_turn_active");
|
|
4699
4892
|
return;
|
|
4700
4893
|
}
|
|
4701
4894
|
const resumed = await tryResumeCodexThreadForPendingRuntimeSettings(
|
|
@@ -4703,6 +4896,7 @@ async function drainKandanMessageQueue(args, state, payloadContext) {
|
|
|
4703
4896
|
state
|
|
4704
4897
|
);
|
|
4705
4898
|
if (!resumed) {
|
|
4899
|
+
logQueuedDrainBlocked(args, state, "runtime_settings_resume_pending");
|
|
4706
4900
|
return;
|
|
4707
4901
|
}
|
|
4708
4902
|
const next = dequeuePendingKandanMessage(state.queue);
|
|
@@ -4823,6 +5017,22 @@ async function drainKandanMessageQueue(args, state, payloadContext) {
|
|
|
4823
5017
|
});
|
|
4824
5018
|
}
|
|
4825
5019
|
}
|
|
5020
|
+
function logQueuedDrainBlocked(args, state, reason) {
|
|
5021
|
+
const queueDepth = pendingKandanMessageQueueLength(state.queue);
|
|
5022
|
+
if (queueDepth === 0) {
|
|
5023
|
+
return;
|
|
5024
|
+
}
|
|
5025
|
+
args.log("kandan.queue_drain_blocked", {
|
|
5026
|
+
reason,
|
|
5027
|
+
queue_depth: queueDepth,
|
|
5028
|
+
turn_status: state.turn.status,
|
|
5029
|
+
active_turn_id: activeTurnId(state.turn) ?? null,
|
|
5030
|
+
active_queued_seq: state.turn.status === "active" || state.turn.status === "completing" ? state.turn.queuedSeq : state.turn.status === "starting" ? state.turn.queuedSeq : null,
|
|
5031
|
+
codex_thread_id: state.codexThreadId ?? null,
|
|
5032
|
+
kandan_thread_id: state.kandanThreadId ?? null,
|
|
5033
|
+
local_tui_turn_count: state.localTuiTurnIds.size
|
|
5034
|
+
});
|
|
5035
|
+
}
|
|
4826
5036
|
async function fetchReconnectContextInjection(args, state) {
|
|
4827
5037
|
if (state.kandanThreadId === void 0) {
|
|
4828
5038
|
throw new Error(
|
|
@@ -4986,6 +5196,7 @@ async function forwardCompletedCodexTurn(args, state, turnId, payloadContext) {
|
|
|
4986
5196
|
};
|
|
4987
5197
|
}
|
|
4988
5198
|
await waitForPendingTuiInputMirror(state, turnId);
|
|
5199
|
+
await waitForPendingCompletedAssistantItemForwards(state, turnId);
|
|
4989
5200
|
await waitForStreamingForwardChains(args, state, payloadContext);
|
|
4990
5201
|
rememberForwardingTurnId(state, turnId);
|
|
4991
5202
|
forgetRetryableTurnId(state, turnId);
|
|
@@ -5096,9 +5307,17 @@ async function forwardCompletedCodexTurn(args, state, turnId, payloadContext) {
|
|
|
5096
5307
|
}
|
|
5097
5308
|
}
|
|
5098
5309
|
function completedOutputProjectionsForTurn(state, turnId, messages) {
|
|
5099
|
-
const snapshotOutputs = messages.flatMap(
|
|
5100
|
-
|
|
5101
|
-
|
|
5310
|
+
const snapshotOutputs = messages.flatMap((message, snapshotIndex) => {
|
|
5311
|
+
if (completedAssistantItemForwarded(state, message.itemKey)) {
|
|
5312
|
+
return [];
|
|
5313
|
+
}
|
|
5314
|
+
return completedSnapshotOutputProjection(
|
|
5315
|
+
state,
|
|
5316
|
+
turnId,
|
|
5317
|
+
message,
|
|
5318
|
+
snapshotIndex
|
|
5319
|
+
);
|
|
5320
|
+
});
|
|
5102
5321
|
const matchedStructuredKeys = new Set(
|
|
5103
5322
|
snapshotOutputs.flatMap((output) => {
|
|
5104
5323
|
switch (output.match.kind) {
|
|
@@ -5367,7 +5586,101 @@ function logCompletedCodexOutput(args, turnId, message) {
|
|
|
5367
5586
|
file_paths: fileChangePaths(message.structured)
|
|
5368
5587
|
});
|
|
5369
5588
|
}
|
|
5589
|
+
async function forwardCompletedAssistantItem(args, state, params, payloadContext) {
|
|
5590
|
+
if (state.kandanThreadId === void 0 || state.codexThreadId === void 0) {
|
|
5591
|
+
return;
|
|
5592
|
+
}
|
|
5593
|
+
const turnId = stringValue(params.turnId) ?? stringValue(params.turn_id) ?? stringValue(objectValue(params.turn)?.id);
|
|
5594
|
+
const item = objectValue(params.item) ?? params;
|
|
5595
|
+
const completedItemKey = stringValue(params.itemId) ?? stringValue(params.item_id) ?? stringValue(objectValue(params.item)?.id);
|
|
5596
|
+
if (turnId !== void 0) {
|
|
5597
|
+
await waitForPendingTuiInputMirror(state, turnId);
|
|
5598
|
+
await waitForStreamingForwardChains(args, state, payloadContext);
|
|
5599
|
+
}
|
|
5600
|
+
const parsedMessage = codexOutputMessagesForItem(item, 0).find(
|
|
5601
|
+
(candidate) => stringValue(candidate.structured.kind) === "codex_assistant_message"
|
|
5602
|
+
);
|
|
5603
|
+
const fallbackStream = parsedMessage === void 0 ? resolveStreamingAssistantOutputForCompletedSignal(
|
|
5604
|
+
state,
|
|
5605
|
+
turnId,
|
|
5606
|
+
completedItemKey
|
|
5607
|
+
) : { status: "none" };
|
|
5608
|
+
if (fallbackStream.status === "ambiguous") {
|
|
5609
|
+
throw new LogicalProjectionError(
|
|
5610
|
+
`Cannot reconcile completed assistant item signal from item notification; ${fallbackStream.candidateCount} active streamed assistant outputs exist`
|
|
5611
|
+
);
|
|
5612
|
+
}
|
|
5613
|
+
const message = parsedMessage ?? (fallbackStream.status === "matched" ? {
|
|
5614
|
+
itemKey: fallbackStream.output.itemKey,
|
|
5615
|
+
body: fallbackStream.output.content,
|
|
5616
|
+
structured: codexAssistantStructuredMessage(
|
|
5617
|
+
fallbackStream.output.itemKey,
|
|
5618
|
+
fallbackStream.output.content,
|
|
5619
|
+
"completed"
|
|
5620
|
+
)
|
|
5621
|
+
} : void 0);
|
|
5622
|
+
const messageTurnId = turnId ?? (fallbackStream.status === "matched" ? fallbackStream.output.turnId : void 0);
|
|
5623
|
+
if (message === void 0 || completedAssistantItemForwarded(state, message.itemKey)) {
|
|
5624
|
+
return;
|
|
5625
|
+
}
|
|
5626
|
+
const sourceMessageSeq = messageTurnId === void 0 ? void 0 : sourceMessageSeqForTurn(state, messageTurnId);
|
|
5627
|
+
if (messageTurnId !== void 0 && sourceMessageSeq === void 0) {
|
|
5628
|
+
args.log("codex.completed_assistant_item_without_source_message", {
|
|
5629
|
+
turn_id: messageTurnId,
|
|
5630
|
+
item_key: message.itemKey
|
|
5631
|
+
});
|
|
5632
|
+
return;
|
|
5633
|
+
}
|
|
5634
|
+
const structured = codexAssistantStructuredMessage(
|
|
5635
|
+
message.itemKey,
|
|
5636
|
+
message.body,
|
|
5637
|
+
"completed"
|
|
5638
|
+
);
|
|
5639
|
+
const streamed = resolveStreamingAssistantOutputForCompletedMessage(
|
|
5640
|
+
state,
|
|
5641
|
+
messageTurnId ?? `item:${message.itemKey}`,
|
|
5642
|
+
message.itemKey,
|
|
5643
|
+
message.body,
|
|
5644
|
+
structured
|
|
5645
|
+
);
|
|
5646
|
+
switch (streamed.status) {
|
|
5647
|
+
case "none":
|
|
5648
|
+
await streamCompletedCodexOutput(args, state, payloadContext, {
|
|
5649
|
+
turnId: turnId ?? `item:${message.itemKey}`,
|
|
5650
|
+
sourceMessageSeq,
|
|
5651
|
+
rootSeq: state.rootSeq,
|
|
5652
|
+
message: {
|
|
5653
|
+
...message,
|
|
5654
|
+
structured
|
|
5655
|
+
}
|
|
5656
|
+
});
|
|
5657
|
+
break;
|
|
5658
|
+
case "matched":
|
|
5659
|
+
await editStreamedCodexOutput(
|
|
5660
|
+
args,
|
|
5661
|
+
state,
|
|
5662
|
+
streamed.output.seq,
|
|
5663
|
+
message.itemKey,
|
|
5664
|
+
message.body,
|
|
5665
|
+
"completed"
|
|
5666
|
+
);
|
|
5667
|
+
forgetStreamingAssistantOutput(state, streamed.output.itemKey);
|
|
5668
|
+
break;
|
|
5669
|
+
case "ambiguous":
|
|
5670
|
+
throw new LogicalProjectionError(
|
|
5671
|
+
`Cannot reconcile completed assistant item ${message.itemKey} from item notification; ${streamed.candidateCount} active streamed assistant outputs exist`
|
|
5672
|
+
);
|
|
5673
|
+
}
|
|
5674
|
+
rememberCompletedAssistantItemKey(state, message.itemKey);
|
|
5675
|
+
logCompletedCodexOutput(args, messageTurnId ?? `item:${message.itemKey}`, {
|
|
5676
|
+
...message,
|
|
5677
|
+
structured
|
|
5678
|
+
});
|
|
5679
|
+
}
|
|
5370
5680
|
function compareCompletedOutputProjection(left, right) {
|
|
5681
|
+
if (left.kind === "snapshot" && right.kind === "snapshot" && left.match.kind !== right.match.kind && (left.match.kind === "none" || right.match.kind === "none")) {
|
|
5682
|
+
return left.snapshotIndex - right.snapshotIndex;
|
|
5683
|
+
}
|
|
5371
5684
|
return left.sortOrder === right.sortOrder ? left.snapshotIndex - right.snapshotIndex : left.sortOrder - right.sortOrder;
|
|
5372
5685
|
}
|
|
5373
5686
|
function fallbackSnapshotOutputBase(sortOrders) {
|
|
@@ -6240,12 +6553,20 @@ async function streamCompletedCodexOutput(args, state, payloadContext, params) {
|
|
|
6240
6553
|
params.message.body,
|
|
6241
6554
|
structured
|
|
6242
6555
|
);
|
|
6556
|
+
const displayBody = displayBodyForCommanderOutput(
|
|
6557
|
+
params.message.body,
|
|
6558
|
+
uploadedFileIds
|
|
6559
|
+
);
|
|
6560
|
+
const displayStructured = structuredWithAssistantContent(
|
|
6561
|
+
structured,
|
|
6562
|
+
displayBody
|
|
6563
|
+
);
|
|
6243
6564
|
await pushOk2(args.kandan, args.topic, "session:stream_thread_message", {
|
|
6244
6565
|
workspace: session.workspaceSlug,
|
|
6245
6566
|
channel: session.channelSlug,
|
|
6246
6567
|
thread_id: state.kandanThreadId,
|
|
6247
6568
|
stream_key: streamKey,
|
|
6248
|
-
body:
|
|
6569
|
+
body: displayBody,
|
|
6249
6570
|
payload: {
|
|
6250
6571
|
...localRunnerPayload(
|
|
6251
6572
|
args.options,
|
|
@@ -6259,7 +6580,7 @@ async function streamCompletedCodexOutput(args, state, payloadContext, params) {
|
|
|
6259
6580
|
...params.rootSeq === void 0 ? {} : { reply_to_seq: params.rootSeq },
|
|
6260
6581
|
...params.sourceMessageSeq === void 0 ? {} : { source_message_seq: params.sourceMessageSeq },
|
|
6261
6582
|
...streamMetadata,
|
|
6262
|
-
structured
|
|
6583
|
+
structured: displayStructured
|
|
6263
6584
|
},
|
|
6264
6585
|
...uploadedFileIds.length === 0 ? {} : { uploaded_file_ids: uploadedFileIds },
|
|
6265
6586
|
client_message_id: streamKey
|
|
@@ -6282,13 +6603,36 @@ async function editCodexStructuredOutput(args, state, targetSeq, content, struct
|
|
|
6282
6603
|
return;
|
|
6283
6604
|
}
|
|
6284
6605
|
const session = args.options.channelSession;
|
|
6606
|
+
const uploadedFileIds = stringValue(structured.stream_state) === "completed" ? await uploadedFileIdsForCommanderOutput(
|
|
6607
|
+
{
|
|
6608
|
+
kandan: args.kandan,
|
|
6609
|
+
topic: args.topic,
|
|
6610
|
+
workspace: session.workspaceSlug,
|
|
6611
|
+
channel: session.channelSlug,
|
|
6612
|
+
cwd: args.options.cwd,
|
|
6613
|
+
kandanUrl: args.options.kandanUrl,
|
|
6614
|
+
token: args.options.token,
|
|
6615
|
+
fetch: args.options.fetch
|
|
6616
|
+
},
|
|
6617
|
+
content,
|
|
6618
|
+
structured
|
|
6619
|
+
) : [];
|
|
6620
|
+
const displayContent = displayBodyForCommanderOutput(
|
|
6621
|
+
content,
|
|
6622
|
+
uploadedFileIds
|
|
6623
|
+
);
|
|
6624
|
+
const displayStructured = structuredWithAssistantContent(
|
|
6625
|
+
structured,
|
|
6626
|
+
displayContent
|
|
6627
|
+
);
|
|
6285
6628
|
await pushOk2(args.kandan, args.topic, "session:edit_thread_message", {
|
|
6286
6629
|
workspace: session.workspaceSlug,
|
|
6287
6630
|
channel: session.channelSlug,
|
|
6288
6631
|
thread_id: state.kandanThreadId,
|
|
6289
6632
|
target_seq: targetSeq,
|
|
6290
|
-
body:
|
|
6291
|
-
structured
|
|
6633
|
+
body: displayContent,
|
|
6634
|
+
structured: displayStructured,
|
|
6635
|
+
...uploadedFileIds.length === 0 ? {} : { uploaded_file_ids: uploadedFileIds }
|
|
6292
6636
|
});
|
|
6293
6637
|
}
|
|
6294
6638
|
async function mirrorLocalTuiInputFromNotification(args, state, turnId, params, payloadContext) {
|
|
@@ -6464,6 +6808,30 @@ function resolveStreamingAssistantOutputForCompletedMessage(state, turnId, itemK
|
|
|
6464
6808
|
}
|
|
6465
6809
|
}
|
|
6466
6810
|
}
|
|
6811
|
+
function resolveStreamingAssistantOutputForCompletedSignal(state, turnId, itemKey) {
|
|
6812
|
+
if (itemKey !== void 0) {
|
|
6813
|
+
const exact = findStreamingAssistantOutput(state, itemKey);
|
|
6814
|
+
if (exact !== void 0) {
|
|
6815
|
+
return { status: "matched", output: exact };
|
|
6816
|
+
}
|
|
6817
|
+
}
|
|
6818
|
+
if (turnId === void 0) {
|
|
6819
|
+
return { status: "none" };
|
|
6820
|
+
}
|
|
6821
|
+
const candidates = boundedCacheValues(state.streamingAssistantOutputs).filter(
|
|
6822
|
+
(output) => output.turnId === turnId
|
|
6823
|
+
);
|
|
6824
|
+
switch (candidates.length) {
|
|
6825
|
+
case 0:
|
|
6826
|
+
return { status: "none" };
|
|
6827
|
+
case 1: {
|
|
6828
|
+
const [output] = candidates;
|
|
6829
|
+
return output === void 0 ? { status: "none" } : { status: "matched", output };
|
|
6830
|
+
}
|
|
6831
|
+
default:
|
|
6832
|
+
return { status: "ambiguous", candidateCount: candidates.length };
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6467
6835
|
function normalizedTranscriptText(value) {
|
|
6468
6836
|
return value.trim().replace(/\s+/g, " ");
|
|
6469
6837
|
}
|
|
@@ -6480,6 +6848,16 @@ function rememberStreamingAssistantOutput(state, output) {
|
|
|
6480
6848
|
function forgetStreamingAssistantOutput(state, itemKey) {
|
|
6481
6849
|
forgetBoundedCacheValue(state.streamingAssistantOutputs, itemKey);
|
|
6482
6850
|
}
|
|
6851
|
+
function completedAssistantItemForwarded(state, itemKey) {
|
|
6852
|
+
return state.completedAssistantItemKeys.has(itemKey);
|
|
6853
|
+
}
|
|
6854
|
+
function rememberCompletedAssistantItemKey(state, itemKey) {
|
|
6855
|
+
rememberBoundedStringSet(
|
|
6856
|
+
state.completedAssistantItemKeys,
|
|
6857
|
+
itemKey,
|
|
6858
|
+
maxForwardedTurnIds
|
|
6859
|
+
);
|
|
6860
|
+
}
|
|
6483
6861
|
function rememberStreamingReasoningOutput(state, output) {
|
|
6484
6862
|
rememberBoundedCacheValue(
|
|
6485
6863
|
state.streamingReasoningOutputs,
|
|
@@ -6559,6 +6937,30 @@ function codexNotificationBelongsToSession(state, threadId, turnId) {
|
|
|
6559
6937
|
}
|
|
6560
6938
|
return activeTurnId(state.turn) === turnId || isLocalTuiTurn(state, turnId);
|
|
6561
6939
|
}
|
|
6940
|
+
function inferThreadOnlyCompletedTurnId(args, state, threadId) {
|
|
6941
|
+
if (threadId === void 0 || state.codexThreadId !== threadId) {
|
|
6942
|
+
return void 0;
|
|
6943
|
+
}
|
|
6944
|
+
switch (state.turn.status) {
|
|
6945
|
+
case "active":
|
|
6946
|
+
case "completing":
|
|
6947
|
+
args.log("codex.turn_completion_inferred", {
|
|
6948
|
+
thread_id: threadId,
|
|
6949
|
+
turn_id: state.turn.turnId,
|
|
6950
|
+
queued_seq: state.turn.queuedSeq,
|
|
6951
|
+
turn_status: state.turn.status
|
|
6952
|
+
});
|
|
6953
|
+
return state.turn.turnId;
|
|
6954
|
+
case "idle":
|
|
6955
|
+
case "starting":
|
|
6956
|
+
args.log("codex.turn_completion_without_turn_id", {
|
|
6957
|
+
thread_id: threadId,
|
|
6958
|
+
turn_status: state.turn.status,
|
|
6959
|
+
queued_seq: state.turn.status === "starting" ? state.turn.queuedSeq : null
|
|
6960
|
+
});
|
|
6961
|
+
return void 0;
|
|
6962
|
+
}
|
|
6963
|
+
}
|
|
6562
6964
|
function codexNotificationActiveTurnFallback(method, state, params) {
|
|
6563
6965
|
if (method !== "response_item" || codexCompletedFileChangeFromNotification(params) === void 0) {
|
|
6564
6966
|
return void 0;
|
|
@@ -6607,6 +7009,32 @@ async function waitForPendingTuiInputMirror(state, turnId) {
|
|
|
6607
7009
|
await pending;
|
|
6608
7010
|
}
|
|
6609
7011
|
}
|
|
7012
|
+
function rememberPendingCompletedAssistantItemForward(state, turnId, promise) {
|
|
7013
|
+
const existing = state.pendingCompletedAssistantItemForwards.get(turnId);
|
|
7014
|
+
const pending = existing ?? /* @__PURE__ */ new Set();
|
|
7015
|
+
pending.add(promise);
|
|
7016
|
+
state.pendingCompletedAssistantItemForwards.set(turnId, pending);
|
|
7017
|
+
trimBoundedMap(
|
|
7018
|
+
state.pendingCompletedAssistantItemForwards,
|
|
7019
|
+
maxForwardedTurnIds
|
|
7020
|
+
);
|
|
7021
|
+
}
|
|
7022
|
+
function forgetPendingCompletedAssistantItemForward(state, turnId, promise) {
|
|
7023
|
+
const pending = state.pendingCompletedAssistantItemForwards.get(turnId);
|
|
7024
|
+
if (pending === void 0) {
|
|
7025
|
+
return;
|
|
7026
|
+
}
|
|
7027
|
+
pending.delete(promise);
|
|
7028
|
+
if (pending.size === 0) {
|
|
7029
|
+
state.pendingCompletedAssistantItemForwards.delete(turnId);
|
|
7030
|
+
}
|
|
7031
|
+
}
|
|
7032
|
+
async function waitForPendingCompletedAssistantItemForwards(state, turnId) {
|
|
7033
|
+
const pending = state.pendingCompletedAssistantItemForwards.get(turnId);
|
|
7034
|
+
if (pending !== void 0) {
|
|
7035
|
+
await Promise.allSettled([...pending]);
|
|
7036
|
+
}
|
|
7037
|
+
}
|
|
6610
7038
|
async function waitForStreamingForwardChains(args, state, payloadContext) {
|
|
6611
7039
|
flushPendingStreamingDeltas(args, state, payloadContext);
|
|
6612
7040
|
await Promise.all([
|
|
@@ -7120,7 +7548,7 @@ var init_channelSession = __esm({
|
|
|
7120
7548
|
|
|
7121
7549
|
// src/claudeCodeSession.ts
|
|
7122
7550
|
import { existsSync, readFileSync } from "node:fs";
|
|
7123
|
-
import { homedir } from "node:os";
|
|
7551
|
+
import { homedir as homedir2 } from "node:os";
|
|
7124
7552
|
import { join as join2 } from "node:path";
|
|
7125
7553
|
function claudeCodeSettingSources() {
|
|
7126
7554
|
return ["user", "project", "local"];
|
|
@@ -7128,7 +7556,7 @@ function claudeCodeSettingSources() {
|
|
|
7128
7556
|
async function probeClaudeCodeAvailability(args) {
|
|
7129
7557
|
if (!hasClaudeCodeAuthHint(process.env, {
|
|
7130
7558
|
cwd: args.cwd,
|
|
7131
|
-
homeDir:
|
|
7559
|
+
homeDir: homedir2(),
|
|
7132
7560
|
platform: process.platform,
|
|
7133
7561
|
fileExists: existsSync,
|
|
7134
7562
|
readTextFile: readTextFileIfPresent
|
|
@@ -7793,7 +8221,7 @@ var init_claudeCodeSession = __esm({
|
|
|
7793
8221
|
// src/runnerLogger.ts
|
|
7794
8222
|
import { appendFileSync, openSync } from "node:fs";
|
|
7795
8223
|
import { createWriteStream } from "node:fs";
|
|
7796
|
-
import { homedir as
|
|
8224
|
+
import { homedir as homedir3 } from "node:os";
|
|
7797
8225
|
import { dirname, join as join3 } from "node:path";
|
|
7798
8226
|
import { mkdirSync } from "node:fs";
|
|
7799
8227
|
function createRunnerLogger(logFile, consoleReporter) {
|
|
@@ -7835,10 +8263,10 @@ function writeCliAuditEvent(event, payload, options = {}) {
|
|
|
7835
8263
|
}
|
|
7836
8264
|
function defaultCliAuditLogFile() {
|
|
7837
8265
|
const override = process.env.LINZUMI_CLI_AUDIT_LOG?.trim();
|
|
7838
|
-
return override === void 0 || override === "" ? join3(
|
|
8266
|
+
return override === void 0 || override === "" ? join3(homedir3(), ".linzumi", "logs", "command-events.jsonl") : override;
|
|
7839
8267
|
}
|
|
7840
8268
|
function defaultRunnerLogFile() {
|
|
7841
|
-
return join3(
|
|
8269
|
+
return join3(homedir3(), ".linzumi", "logs", "runner-events.jsonl");
|
|
7842
8270
|
}
|
|
7843
8271
|
function redactForCliLog(value) {
|
|
7844
8272
|
return redactObject(value);
|
|
@@ -8498,11 +8926,11 @@ import {
|
|
|
8498
8926
|
realpathSync,
|
|
8499
8927
|
writeFileSync
|
|
8500
8928
|
} from "node:fs";
|
|
8501
|
-
import { homedir as
|
|
8929
|
+
import { homedir as homedir4 } from "node:os";
|
|
8502
8930
|
import { join as join4, resolve as resolve2 } from "node:path";
|
|
8503
8931
|
function ensureCodexProjectTrusted(projectPath, options = {}) {
|
|
8504
8932
|
const trustedPath = realpathSync(resolve2(projectPath));
|
|
8505
|
-
const configHome = options.configHome ?? process.env.CODEX_HOME ?? join4(
|
|
8933
|
+
const configHome = options.configHome ?? process.env.CODEX_HOME ?? join4(homedir4(), ".codex");
|
|
8506
8934
|
const configPath = join4(configHome, "config.toml");
|
|
8507
8935
|
const currentConfig = existsSync2(configPath) ? readFileSync2(configPath, "utf8") : "";
|
|
8508
8936
|
const nextConfig = codexConfigWithTrustedProject(currentConfig, trustedPath);
|
|
@@ -8557,7 +8985,7 @@ var init_codexProjectTrust = __esm({
|
|
|
8557
8985
|
|
|
8558
8986
|
// src/localCapabilities.ts
|
|
8559
8987
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
8560
|
-
import { homedir as
|
|
8988
|
+
import { homedir as homedir5 } from "node:os";
|
|
8561
8989
|
import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve3 } from "node:path";
|
|
8562
8990
|
function parseAllowedCwdList(value) {
|
|
8563
8991
|
if (value === void 0) {
|
|
@@ -8597,10 +9025,10 @@ function assertConfiguredAllowedCwds(paths) {
|
|
|
8597
9025
|
}
|
|
8598
9026
|
function expandUserPath(pathValue) {
|
|
8599
9027
|
if (pathValue === "~") {
|
|
8600
|
-
return
|
|
9028
|
+
return homedir5();
|
|
8601
9029
|
}
|
|
8602
9030
|
if (pathValue.startsWith("~/")) {
|
|
8603
|
-
return resolve3(
|
|
9031
|
+
return resolve3(homedir5(), pathValue.slice(2));
|
|
8604
9032
|
}
|
|
8605
9033
|
return pathValue;
|
|
8606
9034
|
}
|
|
@@ -8986,11 +9414,11 @@ import {
|
|
|
8986
9414
|
unlinkSync,
|
|
8987
9415
|
writeFileSync as writeFileSync2
|
|
8988
9416
|
} from "node:fs";
|
|
8989
|
-
import { homedir as
|
|
9417
|
+
import { homedir as homedir6 } from "node:os";
|
|
8990
9418
|
import { basename as basename3, dirname as dirname2, join as join5, resolve as resolve4 } from "node:path";
|
|
8991
9419
|
function localConfigPath(env = process.env) {
|
|
8992
9420
|
const override = env.LINZUMI_CONFIG_FILE;
|
|
8993
|
-
return override !== void 0 && override.trim() !== "" ? resolve4(expandUserPath(override)) : resolve4(
|
|
9421
|
+
return override !== void 0 && override.trim() !== "" ? resolve4(expandUserPath(override)) : resolve4(homedir6(), ".linzumi", "config.json");
|
|
8994
9422
|
}
|
|
8995
9423
|
function localConfigScopeKey(linzumiUrl) {
|
|
8996
9424
|
const normalizedUrl = kandanHttpBaseUrl(linzumiUrl);
|
|
@@ -10686,7 +11114,7 @@ import {
|
|
|
10686
11114
|
rmSync,
|
|
10687
11115
|
writeFileSync as writeFileSync4
|
|
10688
11116
|
} from "node:fs";
|
|
10689
|
-
import { homedir as
|
|
11117
|
+
import { homedir as homedir7 } from "node:os";
|
|
10690
11118
|
import { dirname as dirname4, join as join7, resolve as resolve5 } from "node:path";
|
|
10691
11119
|
import { Readable } from "node:stream";
|
|
10692
11120
|
import { pipeline } from "node:stream/promises";
|
|
@@ -11172,7 +11600,7 @@ function fileSha256Sync(path2) {
|
|
|
11172
11600
|
return createHash2("sha256").update(readFileSync5(path2)).digest("hex");
|
|
11173
11601
|
}
|
|
11174
11602
|
function defaultEditorRuntimeCacheRoot() {
|
|
11175
|
-
return join7(
|
|
11603
|
+
return join7(homedir7(), ".linzumi", "editor-runtimes");
|
|
11176
11604
|
}
|
|
11177
11605
|
function nonEmptyString(value) {
|
|
11178
11606
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
@@ -11695,7 +12123,7 @@ var linzumiCliVersion, linzumiCliVersionText;
|
|
|
11695
12123
|
var init_version = __esm({
|
|
11696
12124
|
"src/version.ts"() {
|
|
11697
12125
|
"use strict";
|
|
11698
|
-
linzumiCliVersion = "0.0.
|
|
12126
|
+
linzumiCliVersion = "0.0.69-beta";
|
|
11699
12127
|
linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
|
|
11700
12128
|
}
|
|
11701
12129
|
});
|
|
@@ -12124,10 +12552,10 @@ var init_runnerConsoleReporter = __esm({
|
|
|
12124
12552
|
|
|
12125
12553
|
// src/authCache.ts
|
|
12126
12554
|
import { existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
|
|
12127
|
-
import { homedir as
|
|
12555
|
+
import { homedir as homedir8 } from "node:os";
|
|
12128
12556
|
import { dirname as dirname6, join as join9 } from "node:path";
|
|
12129
12557
|
function defaultAuthFilePath() {
|
|
12130
|
-
const base = process.env.KANDAN_HOME ?? join9(
|
|
12558
|
+
const base = process.env.KANDAN_HOME ?? join9(homedir8(), ".kandan");
|
|
12131
12559
|
return join9(base, "auth.json");
|
|
12132
12560
|
}
|
|
12133
12561
|
function readCachedLocalRunnerToken(kandanUrl, authFilePath = defaultAuthFilePath()) {
|
|
@@ -12830,7 +13258,7 @@ import {
|
|
|
12830
13258
|
statSync
|
|
12831
13259
|
} from "node:fs";
|
|
12832
13260
|
import { createServer as createServer3 } from "node:http";
|
|
12833
|
-
import { homedir as
|
|
13261
|
+
import { homedir as homedir9, hostname as hostname2, tmpdir as tmpdir3 } from "node:os";
|
|
12834
13262
|
import { dirname as dirname7, join as join11, resolve as resolve6 } from "node:path";
|
|
12835
13263
|
async function runLocalCodexRunner(options) {
|
|
12836
13264
|
const log = makeRunnerLogger(options);
|
|
@@ -16501,16 +16929,24 @@ async function streamClaudeCodeStructuredMessage(args, sessionId, message) {
|
|
|
16501
16929
|
message.body,
|
|
16502
16930
|
message.structured
|
|
16503
16931
|
) : [];
|
|
16932
|
+
const displayBody = displayBodyForCommanderOutput(
|
|
16933
|
+
message.body,
|
|
16934
|
+
uploadedFileIds
|
|
16935
|
+
);
|
|
16936
|
+
const displayStructured = structuredWithAssistantContent(
|
|
16937
|
+
message.structured,
|
|
16938
|
+
displayBody
|
|
16939
|
+
);
|
|
16504
16940
|
await args.kandan.push(args.topic, "session:stream_thread_message", {
|
|
16505
16941
|
workspace: args.workspace,
|
|
16506
16942
|
channel: args.channel,
|
|
16507
16943
|
thread_id: args.threadId,
|
|
16508
16944
|
stream_key: streamKey,
|
|
16509
|
-
body:
|
|
16945
|
+
body: displayBody,
|
|
16510
16946
|
payload: claudeCodePayload(
|
|
16511
16947
|
{ ...args, sourceSeq: args.sourceSeq() },
|
|
16512
16948
|
sessionId,
|
|
16513
|
-
|
|
16949
|
+
displayStructured
|
|
16514
16950
|
),
|
|
16515
16951
|
...uploadedFileIds.length === 0 ? {} : { uploaded_file_ids: uploadedFileIds },
|
|
16516
16952
|
client_message_id: streamKey
|
|
@@ -16535,15 +16971,23 @@ async function postClaudeCodeStructuredMessage(args, sessionId, message) {
|
|
|
16535
16971
|
message.body,
|
|
16536
16972
|
message.structured
|
|
16537
16973
|
);
|
|
16974
|
+
const displayBody = displayBodyForCommanderOutput(
|
|
16975
|
+
message.body,
|
|
16976
|
+
uploadedFileIds
|
|
16977
|
+
);
|
|
16978
|
+
const displayStructured = structuredWithAssistantContent(
|
|
16979
|
+
message.structured,
|
|
16980
|
+
displayBody
|
|
16981
|
+
);
|
|
16538
16982
|
await args.kandan.push(args.topic, "session:post_thread_message", {
|
|
16539
16983
|
workspace: args.workspace,
|
|
16540
16984
|
channel: args.channel,
|
|
16541
16985
|
thread_id: args.threadId,
|
|
16542
|
-
body:
|
|
16986
|
+
body: displayBody,
|
|
16543
16987
|
payload: claudeCodePayload(
|
|
16544
16988
|
{ ...args, sourceSeq: args.sourceSeq() },
|
|
16545
16989
|
sessionId,
|
|
16546
|
-
|
|
16990
|
+
displayStructured
|
|
16547
16991
|
),
|
|
16548
16992
|
...uploadedFileIds.length === 0 ? {} : { uploaded_file_ids: uploadedFileIds },
|
|
16549
16993
|
client_message_id: claudeCodeMessageClientId(
|
|
@@ -17468,7 +17912,7 @@ function isGitProjectDirectory(cwd) {
|
|
|
17468
17912
|
}
|
|
17469
17913
|
function browseRunnerDirectory(control, options) {
|
|
17470
17914
|
const requestId = stringValue(control.requestId) ?? null;
|
|
17471
|
-
const requestedPath = stringValue(control.path) ??
|
|
17915
|
+
const requestedPath = stringValue(control.path) ?? homedir9();
|
|
17472
17916
|
try {
|
|
17473
17917
|
const currentPath = realpathSync5(resolve6(expandUserPath(requestedPath)));
|
|
17474
17918
|
const stats = statSync(currentPath);
|
|
@@ -17499,7 +17943,7 @@ function browseRunnerDirectory(control, options) {
|
|
|
17499
17943
|
ok: true,
|
|
17500
17944
|
currentPath,
|
|
17501
17945
|
parentPath: parent === currentPath ? null : parent,
|
|
17502
|
-
homePath:
|
|
17946
|
+
homePath: homedir9(),
|
|
17503
17947
|
runnerCwd: resolve6(options.cwd),
|
|
17504
17948
|
entries,
|
|
17505
17949
|
isGit: isGitProjectDirectory(currentPath)
|
|
@@ -17534,7 +17978,7 @@ function createRunnerProject(control, options, allowedCwds) {
|
|
|
17534
17978
|
error: "invalid_project_name"
|
|
17535
17979
|
};
|
|
17536
17980
|
}
|
|
17537
|
-
const projectsRoot = join11(
|
|
17981
|
+
const projectsRoot = join11(homedir9(), "linzumi");
|
|
17538
17982
|
const projectPath = join11(projectsRoot, projectDirName);
|
|
17539
17983
|
let createdProjectPath = false;
|
|
17540
17984
|
try {
|
|
@@ -17751,7 +18195,7 @@ var init_kandanTls = __esm({
|
|
|
17751
18195
|
// src/helloLinzumiProject.ts
|
|
17752
18196
|
import { existsSync as existsSync10, mkdirSync as mkdirSync10, readFileSync as readFileSync11, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "node:fs";
|
|
17753
18197
|
import { dirname as dirname9, join as join13, resolve as resolve7 } from "node:path";
|
|
17754
|
-
import { fileURLToPath } from "node:url";
|
|
18198
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
17755
18199
|
function createHelloLinzumiProject(input = {}) {
|
|
17756
18200
|
const options = typeof input === "string" ? { rootPath: input } : input;
|
|
17757
18201
|
const root = resolveHelloProjectRoot(options);
|
|
@@ -17840,7 +18284,7 @@ var init_helloLinzumiProject = __esm({
|
|
|
17840
18284
|
defaultHelloLinzumiPort = 8787;
|
|
17841
18285
|
defaultHelloLinzumiHost = "0.0.0.0";
|
|
17842
18286
|
markerFile = ".linzumi-demo-project";
|
|
17843
|
-
moduleDir = dirname9(
|
|
18287
|
+
moduleDir = dirname9(fileURLToPath2(import.meta.url));
|
|
17844
18288
|
linzumiLogoSvg = readFileSync11(join13(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
|
|
17845
18289
|
packageJson = `${JSON.stringify(
|
|
17846
18290
|
{
|
|
@@ -38571,7 +39015,7 @@ import {
|
|
|
38571
39015
|
writeFileSync as writeFileSync11
|
|
38572
39016
|
} from "node:fs";
|
|
38573
39017
|
import { access } from "node:fs/promises";
|
|
38574
|
-
import { homedir as
|
|
39018
|
+
import { homedir as homedir12, tmpdir as tmpdir4 } from "node:os";
|
|
38575
39019
|
import { delimiter as delimiter2, dirname as dirname11, join as join15, resolve as resolve9 } from "node:path";
|
|
38576
39020
|
import { stdin as defaultStdin, stdout as defaultStdout } from "node:process";
|
|
38577
39021
|
import { emitKeypressEvents } from "node:readline";
|
|
@@ -40874,7 +41318,7 @@ async function runSignupPreflights(runtime) {
|
|
|
40874
41318
|
function defaultPreflightRuntime() {
|
|
40875
41319
|
return {
|
|
40876
41320
|
cwd: process.cwd(),
|
|
40877
|
-
homeDir:
|
|
41321
|
+
homeDir: homedir12(),
|
|
40878
41322
|
probeTool,
|
|
40879
41323
|
readGitEmail,
|
|
40880
41324
|
discoverCodeRoots,
|
|
@@ -41083,7 +41527,7 @@ function codexTaskSuggestionProcess2(args) {
|
|
|
41083
41527
|
function signupCodexTaskSuggestionProcessForTest(args) {
|
|
41084
41528
|
return codexTaskSuggestionProcess2(args);
|
|
41085
41529
|
}
|
|
41086
|
-
async function resolveSignupCodexCommand(env = process.env, homeDir =
|
|
41530
|
+
async function resolveSignupCodexCommand(env = process.env, homeDir = homedir12(), executableExists = fileIsExecutable) {
|
|
41087
41531
|
const override = firstConfiguredValue([
|
|
41088
41532
|
env.LINZUMI_SIGNUP_CODEX_BIN,
|
|
41089
41533
|
env.LINZUMI_CODEX_BIN
|
|
@@ -41722,10 +42166,10 @@ function directoryExists(path2) {
|
|
|
41722
42166
|
}
|
|
41723
42167
|
function expandHomePath(path2) {
|
|
41724
42168
|
if (path2 === "~") {
|
|
41725
|
-
return
|
|
42169
|
+
return homedir12();
|
|
41726
42170
|
}
|
|
41727
42171
|
if (path2.startsWith("~/")) {
|
|
41728
|
-
return join15(
|
|
42172
|
+
return join15(homedir12(), path2.slice(2));
|
|
41729
42173
|
}
|
|
41730
42174
|
return resolve9(path2);
|
|
41731
42175
|
}
|
|
@@ -41813,9 +42257,9 @@ init_runner();
|
|
|
41813
42257
|
init_claudeCodeSession();
|
|
41814
42258
|
init_authCache();
|
|
41815
42259
|
import { existsSync as existsSync13, readFileSync as readFileSync15, realpathSync as realpathSync6 } from "node:fs";
|
|
41816
|
-
import { homedir as
|
|
42260
|
+
import { homedir as homedir13 } from "node:os";
|
|
41817
42261
|
import { resolve as resolve10 } from "node:path";
|
|
41818
|
-
import { fileURLToPath as
|
|
42262
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
41819
42263
|
|
|
41820
42264
|
// src/authResolution.ts
|
|
41821
42265
|
init_authCache();
|
|
@@ -41876,7 +42320,7 @@ init_json();
|
|
|
41876
42320
|
init_defaultUrls();
|
|
41877
42321
|
import { existsSync as existsSync9, mkdirSync as mkdirSync9, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
41878
42322
|
import { dirname as dirname8, join as join12 } from "node:path";
|
|
41879
|
-
import { homedir as
|
|
42323
|
+
import { homedir as homedir10 } from "node:os";
|
|
41880
42324
|
async function runAgentCliCommand(args, deps = {
|
|
41881
42325
|
fetchImpl: fetch,
|
|
41882
42326
|
stdout: process.stdout,
|
|
@@ -42584,7 +43028,7 @@ function agentTokenFile(flags) {
|
|
|
42584
43028
|
return flags.get("agent-token-file") ?? defaultAgentTokenFilePath();
|
|
42585
43029
|
}
|
|
42586
43030
|
function defaultAgentTokenFilePath() {
|
|
42587
|
-
return join12(
|
|
43031
|
+
return join12(homedir10(), ".linzumi", "agent-token.json");
|
|
42588
43032
|
}
|
|
42589
43033
|
function normalizedApiUrl(apiUrl) {
|
|
42590
43034
|
return apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`;
|
|
@@ -42692,13 +43136,13 @@ import {
|
|
|
42692
43136
|
watch,
|
|
42693
43137
|
writeFileSync as writeFileSync9
|
|
42694
43138
|
} from "node:fs";
|
|
42695
|
-
import { homedir as
|
|
43139
|
+
import { homedir as homedir11 } from "node:os";
|
|
42696
43140
|
import { dirname as dirname10, join as join14, resolve as resolve8 } from "node:path";
|
|
42697
43141
|
import { execFileSync, spawn as spawn8 } from "node:child_process";
|
|
42698
|
-
import { fileURLToPath as
|
|
43142
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
42699
43143
|
var connectedMarkers = ["Connected to Linzumi", "Runner connected:"];
|
|
42700
43144
|
function commanderStatusDir() {
|
|
42701
|
-
return join14(
|
|
43145
|
+
return join14(homedir11(), ".linzumi", "commanders");
|
|
42702
43146
|
}
|
|
42703
43147
|
function commanderStatusFile(runnerId, statusDir = commanderStatusDir()) {
|
|
42704
43148
|
return join14(statusDir, `${safeRunnerId(runnerId)}.json`);
|
|
@@ -42804,7 +43248,7 @@ async function waitForCommanderDaemon(options) {
|
|
|
42804
43248
|
if (commanderLogIsConnected(log)) {
|
|
42805
43249
|
return { ok: true, record: status.record };
|
|
42806
43250
|
}
|
|
42807
|
-
await waitForFileChangeOrTimeout(
|
|
43251
|
+
const readyAfterWait = await waitForFileChangeOrTimeout(
|
|
42808
43252
|
status.record.logFile,
|
|
42809
43253
|
deadline,
|
|
42810
43254
|
now,
|
|
@@ -42813,6 +43257,24 @@ async function waitForCommanderDaemon(options) {
|
|
|
42813
43257
|
return updatedLog !== void 0 && commanderLogIsConnected(updatedLog);
|
|
42814
43258
|
}
|
|
42815
43259
|
);
|
|
43260
|
+
if (readyAfterWait) {
|
|
43261
|
+
const refreshedStatus = statusImpl(
|
|
43262
|
+
options.runnerId,
|
|
43263
|
+
options.statusDir
|
|
43264
|
+
);
|
|
43265
|
+
switch (refreshedStatus.status) {
|
|
43266
|
+
case "missing":
|
|
43267
|
+
return { ok: false, reason: "missing" };
|
|
43268
|
+
case "stopped":
|
|
43269
|
+
return { ok: false, reason: "stopped" };
|
|
43270
|
+
case "running": {
|
|
43271
|
+
const refreshedLog = readTextFile(refreshedStatus.record.logFile);
|
|
43272
|
+
if (refreshedLog !== void 0 && commanderLogIsConnected(refreshedLog)) {
|
|
43273
|
+
return { ok: true, record: refreshedStatus.record };
|
|
43274
|
+
}
|
|
43275
|
+
}
|
|
43276
|
+
}
|
|
43277
|
+
}
|
|
42816
43278
|
}
|
|
42817
43279
|
}
|
|
42818
43280
|
}
|
|
@@ -42830,7 +43292,7 @@ function currentEntrypoint() {
|
|
|
42830
43292
|
if (scriptPath !== void 0) {
|
|
42831
43293
|
return scriptPath;
|
|
42832
43294
|
}
|
|
42833
|
-
return
|
|
43295
|
+
return fileURLToPath3(import.meta.url);
|
|
42834
43296
|
}
|
|
42835
43297
|
function parseRecord(content) {
|
|
42836
43298
|
const parsed = JSON.parse(content);
|
|
@@ -42936,31 +43398,31 @@ function safeRunnerId(runnerId) {
|
|
|
42936
43398
|
}
|
|
42937
43399
|
async function waitForFileChangeOrTimeout(path2, deadline, now, ready2 = () => false) {
|
|
42938
43400
|
const remaining = Math.max(0, deadline - now());
|
|
42939
|
-
|
|
43401
|
+
return new Promise((resolve11) => {
|
|
42940
43402
|
let resolved = false;
|
|
42941
43403
|
let watcher;
|
|
42942
|
-
const finish = () => {
|
|
43404
|
+
const finish = (connected) => {
|
|
42943
43405
|
if (resolved) {
|
|
42944
43406
|
return;
|
|
42945
43407
|
}
|
|
42946
43408
|
resolved = true;
|
|
42947
43409
|
watcher?.close();
|
|
42948
43410
|
clearTimeout(timer);
|
|
42949
|
-
resolve11();
|
|
43411
|
+
resolve11(connected);
|
|
42950
43412
|
};
|
|
42951
|
-
const timer = setTimeout(finish, remaining);
|
|
43413
|
+
const timer = setTimeout(() => finish(false), remaining);
|
|
42952
43414
|
try {
|
|
42953
|
-
watcher = watch(path2, finish);
|
|
42954
|
-
watcher.on("error", finish);
|
|
43415
|
+
watcher = watch(path2, () => finish(ready2()));
|
|
43416
|
+
watcher.on("error", () => finish(ready2()));
|
|
42955
43417
|
if (ready2()) {
|
|
42956
|
-
finish();
|
|
43418
|
+
finish(true);
|
|
42957
43419
|
}
|
|
42958
43420
|
} catch (_error) {
|
|
42959
43421
|
if (ready2()) {
|
|
42960
|
-
finish();
|
|
43422
|
+
finish(true);
|
|
42961
43423
|
return;
|
|
42962
43424
|
}
|
|
42963
|
-
finish();
|
|
43425
|
+
finish(false);
|
|
42964
43426
|
}
|
|
42965
43427
|
});
|
|
42966
43428
|
}
|
|
@@ -55142,7 +55604,7 @@ function isMainModule() {
|
|
|
55142
55604
|
if (scriptPath === void 0) {
|
|
55143
55605
|
return false;
|
|
55144
55606
|
}
|
|
55145
|
-
return
|
|
55607
|
+
return fileURLToPath4(import.meta.url) === resolve10(scriptPath);
|
|
55146
55608
|
}
|
|
55147
55609
|
async function main(args) {
|
|
55148
55610
|
const parsed = parseCommand(args);
|
|
@@ -56033,10 +56495,10 @@ function rejectStartTargetingFlags(values) {
|
|
|
56033
56495
|
}
|
|
56034
56496
|
function resolveUserPath(pathValue) {
|
|
56035
56497
|
if (pathValue === "~") {
|
|
56036
|
-
return
|
|
56498
|
+
return homedir13();
|
|
56037
56499
|
}
|
|
56038
56500
|
if (pathValue.startsWith("~/")) {
|
|
56039
|
-
return resolve10(
|
|
56501
|
+
return resolve10(homedir13(), pathValue.slice(2));
|
|
56040
56502
|
}
|
|
56041
56503
|
return resolve10(pathValue);
|
|
56042
56504
|
}
|
package/package.json
CHANGED