@linzumi/cli 0.0.40-beta → 0.0.41-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 +230 -135
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -290,6 +290,9 @@ function codexSandboxPolicy(sandbox, cwd) {
|
|
|
290
290
|
// src/codexOutput.ts
|
|
291
291
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
292
292
|
var maxVisibleWebSearchQueries = 6;
|
|
293
|
+
var maxPersistedCommandOutputChars = 14000;
|
|
294
|
+
var maxPersistedCommandLabelChars = 512;
|
|
295
|
+
var commandOutputTruncationReason = "phoenix_insert_body_limit";
|
|
293
296
|
function codexOutputMessagesForTurn(response, turnId) {
|
|
294
297
|
if ("error" in response) {
|
|
295
298
|
return [];
|
|
@@ -355,21 +358,20 @@ function codexOutputMessagesForItem(item, index) {
|
|
|
355
358
|
case "commandExecution": {
|
|
356
359
|
const command = stringValue(item.command) ?? "command";
|
|
357
360
|
const output = nonBlankStringValue(item.aggregatedOutput) ?? "";
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
`);
|
|
361
|
+
const projection = codexCommandOutputProjection(command, output);
|
|
361
362
|
return [
|
|
362
363
|
{
|
|
363
364
|
itemKey,
|
|
364
|
-
body,
|
|
365
|
+
body: projection.body,
|
|
365
366
|
structured: baseStructured("codex_command_execution", {
|
|
366
|
-
command,
|
|
367
|
+
command: projection.command,
|
|
367
368
|
cwd: stringValue(item.cwd) ?? "",
|
|
368
369
|
status: stringValue(item.status) ?? "",
|
|
369
370
|
process_id: stringValue(item.processId) ?? "",
|
|
370
371
|
duration_ms: integerValue(item.durationMs) ?? null,
|
|
371
372
|
exit_code: integerValue(item.exitCode) ?? null,
|
|
372
|
-
output
|
|
373
|
+
output: projection.output,
|
|
374
|
+
...commandOutputTruncationMetadata(projection)
|
|
373
375
|
})
|
|
374
376
|
}
|
|
375
377
|
];
|
|
@@ -501,21 +503,29 @@ function codexCommandOutputDeltaFromNotification(params) {
|
|
|
501
503
|
};
|
|
502
504
|
}
|
|
503
505
|
function codexCommandExecutionStructuredMessage(itemKey, fields, streamState) {
|
|
506
|
+
const projection = codexCommandOutputProjection(fields.command, fields.output);
|
|
507
|
+
return codexCommandExecutionStructuredMessageFromProjection(itemKey, fields, streamState, projection);
|
|
508
|
+
}
|
|
509
|
+
function codexCommandExecutionStructuredMessageFromProjection(itemKey, fields, streamState, projection) {
|
|
504
510
|
return {
|
|
505
511
|
kind: "codex_command_execution",
|
|
506
512
|
item_id: itemKey,
|
|
507
513
|
transcript_unit_id: `codex_command_execution:${itemKey}`,
|
|
508
514
|
stream_state: streamState,
|
|
509
|
-
command:
|
|
515
|
+
command: projection.command,
|
|
510
516
|
cwd: fields.cwd ?? "",
|
|
511
517
|
status: fields.status ?? streamState,
|
|
512
518
|
process_id: fields.processId ?? "",
|
|
513
519
|
duration_ms: fields.durationMs ?? null,
|
|
514
520
|
exit_code: fields.exitCode ?? null,
|
|
515
521
|
stream: fields.stream ?? "",
|
|
516
|
-
output:
|
|
522
|
+
output: projection.output,
|
|
523
|
+
...commandOutputTruncationMetadata(projection)
|
|
517
524
|
};
|
|
518
525
|
}
|
|
526
|
+
function codexCommandOutputBody(command, output) {
|
|
527
|
+
return codexCommandOutputProjection(command, output).body;
|
|
528
|
+
}
|
|
519
529
|
function codexFileChangeDeltaFromNotification(params) {
|
|
520
530
|
const patchText = textDeltaFromParams(params);
|
|
521
531
|
if (patchText === undefined || patchText === "") {
|
|
@@ -618,6 +628,65 @@ function assistantVisibleText(item) {
|
|
|
618
628
|
function assistantDeltaText(params) {
|
|
619
629
|
return textDeltaFromParams(params);
|
|
620
630
|
}
|
|
631
|
+
function codexCommandOutputProjection(command, output) {
|
|
632
|
+
const normalizedCommand = truncatePersistedText(sanitizePersistedText(command), maxPersistedCommandLabelChars, "command label");
|
|
633
|
+
const normalizedOutput = truncateCommandOutput(sanitizePersistedText(output));
|
|
634
|
+
const body = commandOutputBodyForProjection(normalizedCommand.text, normalizedOutput.text);
|
|
635
|
+
return {
|
|
636
|
+
command: normalizedCommand.text,
|
|
637
|
+
output: normalizedOutput.text,
|
|
638
|
+
body,
|
|
639
|
+
truncated: normalizedCommand.truncated || normalizedOutput.truncated,
|
|
640
|
+
originalLength: output.length,
|
|
641
|
+
maxOutputChars: maxPersistedCommandOutputChars,
|
|
642
|
+
truncationReason: commandOutputTruncationReason
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
function commandOutputTruncationMetadata(projection) {
|
|
646
|
+
return projection.truncated ? {
|
|
647
|
+
output_truncated: true,
|
|
648
|
+
output_original_length: projection.originalLength,
|
|
649
|
+
output_max_chars: projection.maxOutputChars,
|
|
650
|
+
output_truncation_reason: projection.truncationReason
|
|
651
|
+
} : {};
|
|
652
|
+
}
|
|
653
|
+
function commandOutputBodyForProjection(command, output) {
|
|
654
|
+
return [`$ ${command}`, output].filter((part) => part.trim() !== "").join(`
|
|
655
|
+
|
|
656
|
+
`);
|
|
657
|
+
}
|
|
658
|
+
function truncateCommandOutput(output) {
|
|
659
|
+
if (output.length <= maxPersistedCommandOutputChars) {
|
|
660
|
+
return { text: output, truncated: false };
|
|
661
|
+
}
|
|
662
|
+
const marker = `
|
|
663
|
+
|
|
664
|
+
[Linzumi truncated command output: output was too large to persist fully. Owners should search runner logs for codex.command_output_truncated failure_class=phoenix_insert_body_limit.]
|
|
665
|
+
|
|
666
|
+
`;
|
|
667
|
+
const availableChars = Math.max(0, maxPersistedCommandOutputChars - marker.length);
|
|
668
|
+
const headChars = Math.min(2000, Math.floor(availableChars / 3));
|
|
669
|
+
const tailChars = availableChars - headChars;
|
|
670
|
+
const text = `${output.slice(0, headChars)}${marker}${output.slice(-tailChars)}`;
|
|
671
|
+
return {
|
|
672
|
+
text: text.slice(0, maxPersistedCommandOutputChars),
|
|
673
|
+
truncated: true
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
function truncatePersistedText(text, maxChars, label) {
|
|
677
|
+
if (text.length <= maxChars) {
|
|
678
|
+
return { text, truncated: false };
|
|
679
|
+
}
|
|
680
|
+
const marker = `[Linzumi truncated ${label}]`;
|
|
681
|
+
const availableChars = Math.max(0, maxChars - marker.length - 1);
|
|
682
|
+
return {
|
|
683
|
+
text: `${text.slice(0, availableChars)} ${marker}`.slice(0, maxChars),
|
|
684
|
+
truncated: true
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
function sanitizePersistedText(text) {
|
|
688
|
+
return text.replaceAll("\x00", "�");
|
|
689
|
+
}
|
|
621
690
|
function textDeltaFromParams(params) {
|
|
622
691
|
const delta = params.delta;
|
|
623
692
|
if (typeof delta === "string") {
|
|
@@ -641,57 +710,67 @@ function commandMessageForFunctionCall(item, output, index) {
|
|
|
641
710
|
const command = name === "exec_command" ? nonBlankStringValue(args?.cmd) ?? name : `${name}${toolArgumentsSummary(item.arguments)}`;
|
|
642
711
|
const cwd = nonBlankStringValue(args?.cwd) ?? "";
|
|
643
712
|
const outputText = toolOutputText(output);
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
}
|
|
656
|
-
|
|
713
|
+
const projection = codexCommandOutputProjection(command, outputText);
|
|
714
|
+
return [
|
|
715
|
+
{
|
|
716
|
+
itemKey,
|
|
717
|
+
body: projection.body,
|
|
718
|
+
structured: codexCommandExecutionStructuredMessage(itemKey, {
|
|
719
|
+
command,
|
|
720
|
+
cwd,
|
|
721
|
+
output: outputText,
|
|
722
|
+
status: output === undefined ? "started" : "completed"
|
|
723
|
+
}, "completed")
|
|
724
|
+
}
|
|
725
|
+
];
|
|
657
726
|
}
|
|
658
727
|
function messageForCustomToolCall(item, output, index) {
|
|
659
728
|
const name = stringValue(item.name) ?? "custom_tool_call";
|
|
660
729
|
const itemKey = stringValue(item.call_id) ?? stringValue(item.id) ?? `item-${index}`;
|
|
661
730
|
const input = nonBlankStringValue(item.input) ?? nonBlankStringValue(item.arguments) ?? "";
|
|
662
731
|
if (name === "apply_patch") {
|
|
663
|
-
return [
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
732
|
+
return [
|
|
733
|
+
{
|
|
734
|
+
itemKey,
|
|
735
|
+
body: input,
|
|
736
|
+
structured: {
|
|
737
|
+
kind: "codex_file_change",
|
|
738
|
+
item_id: itemKey,
|
|
739
|
+
transcript_unit_id: `codex_file_change:${itemKey}`,
|
|
740
|
+
stream_state: "completed",
|
|
741
|
+
status: output === undefined ? "started" : "completed",
|
|
742
|
+
patch_text: input,
|
|
743
|
+
changes: fileChangesFromPatch(input)
|
|
744
|
+
}
|
|
674
745
|
}
|
|
675
|
-
|
|
746
|
+
];
|
|
676
747
|
}
|
|
677
748
|
const outputText = toolOutputText(output);
|
|
678
749
|
const command = `${name}${toolArgumentsSummary(item.input)}`;
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
750
|
+
const projection = codexCommandOutputProjection(command, outputText);
|
|
751
|
+
return [
|
|
752
|
+
{
|
|
753
|
+
itemKey,
|
|
754
|
+
body: projection.body,
|
|
755
|
+
structured: codexCommandExecutionStructuredMessage(itemKey, {
|
|
756
|
+
command,
|
|
757
|
+
output: outputText,
|
|
758
|
+
status: output === undefined ? "started" : "completed"
|
|
759
|
+
}, "completed")
|
|
760
|
+
}
|
|
761
|
+
];
|
|
686
762
|
}
|
|
687
763
|
function commandMessageForUnpairedToolOutput(item, index) {
|
|
688
764
|
const itemKey = stringValue(item.call_id) ?? stringValue(item.id) ?? `item-${index}`;
|
|
689
765
|
const output = toolOutputText(item);
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
766
|
+
const projection = codexCommandOutputProjection("tool output", output);
|
|
767
|
+
return [
|
|
768
|
+
{
|
|
769
|
+
itemKey,
|
|
770
|
+
body: projection.output,
|
|
771
|
+
structured: codexCommandExecutionStructuredMessageFromProjection(itemKey, { status: "completed" }, "completed", projection)
|
|
772
|
+
}
|
|
773
|
+
];
|
|
695
774
|
}
|
|
696
775
|
function toolArgumentsSummary(value) {
|
|
697
776
|
const text = nonBlankStringValue(value);
|
|
@@ -710,13 +789,34 @@ function fileChangesFromPatch(patchText) {
|
|
|
710
789
|
const addPrefix = "*** Add File: ";
|
|
711
790
|
const deletePrefix = "*** Delete File: ";
|
|
712
791
|
if (line.startsWith(updatePrefix)) {
|
|
713
|
-
return [
|
|
792
|
+
return [
|
|
793
|
+
{
|
|
794
|
+
path: line.slice(updatePrefix.length).trim(),
|
|
795
|
+
diff: "",
|
|
796
|
+
kind: "update",
|
|
797
|
+
move_path: ""
|
|
798
|
+
}
|
|
799
|
+
];
|
|
714
800
|
}
|
|
715
801
|
if (line.startsWith(addPrefix)) {
|
|
716
|
-
return [
|
|
802
|
+
return [
|
|
803
|
+
{
|
|
804
|
+
path: line.slice(addPrefix.length).trim(),
|
|
805
|
+
diff: "",
|
|
806
|
+
kind: "add",
|
|
807
|
+
move_path: ""
|
|
808
|
+
}
|
|
809
|
+
];
|
|
717
810
|
}
|
|
718
811
|
if (line.startsWith(deletePrefix)) {
|
|
719
|
-
return [
|
|
812
|
+
return [
|
|
813
|
+
{
|
|
814
|
+
path: line.slice(deletePrefix.length).trim(),
|
|
815
|
+
diff: "",
|
|
816
|
+
kind: "delete",
|
|
817
|
+
move_path: ""
|
|
818
|
+
}
|
|
819
|
+
];
|
|
720
820
|
}
|
|
721
821
|
return [];
|
|
722
822
|
});
|
|
@@ -2345,8 +2445,8 @@ async function attachChannelSession(args) {
|
|
|
2345
2445
|
const session = args.options.channelSession;
|
|
2346
2446
|
const chatTopic = `chat:${session.workspaceSlug}:${session.channelSlug}`;
|
|
2347
2447
|
const state = initialChannelSessionState(0, session.rootSeq, session.kandanThreadId, session.codexThreadId, args.options);
|
|
2348
|
-
const joined = await args.kandan.join(chatTopic,
|
|
2349
|
-
rejoinPayload: () => (
|
|
2448
|
+
const joined = await args.kandan.join(chatTopic, chatJoinPayload(args.options.runnerId, state, 0), {
|
|
2449
|
+
rejoinPayload: () => chatJoinPayload(args.options.runnerId, state, state.minSeq)
|
|
2350
2450
|
});
|
|
2351
2451
|
const cursor = integerValue(joined.cursor) ?? 0;
|
|
2352
2452
|
const runnerIdentity = identityFromAccessToken(args.options.token);
|
|
@@ -2492,6 +2592,19 @@ async function attachChannelSession(args) {
|
|
|
2492
2592
|
}
|
|
2493
2593
|
};
|
|
2494
2594
|
}
|
|
2595
|
+
function chatJoinPayload(runnerId, state, lastSeq) {
|
|
2596
|
+
const base = { last_seq: lastSeq };
|
|
2597
|
+
switch (state.kandanThreadId) {
|
|
2598
|
+
case undefined:
|
|
2599
|
+
return base;
|
|
2600
|
+
default:
|
|
2601
|
+
return {
|
|
2602
|
+
...base,
|
|
2603
|
+
runner_id: runnerId,
|
|
2604
|
+
thread_id: state.kandanThreadId
|
|
2605
|
+
};
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2495
2608
|
async function bindCurrentCodexThread(args, state) {
|
|
2496
2609
|
if (state.codexThreadId === undefined) {
|
|
2497
2610
|
return;
|
|
@@ -3972,13 +4085,25 @@ async function forwardCommandOutputDeltaPayload(args, state, delta, payloadConte
|
|
|
3972
4085
|
}
|
|
3973
4086
|
const existing = findStreamingCommandOutput(state, delta.itemKey);
|
|
3974
4087
|
const output = `${existing?.output ?? ""}${delta.delta}`;
|
|
3975
|
-
const body = commandOutputBody("command output", output);
|
|
3976
4088
|
const structured = codexCommandExecutionStructuredMessage(delta.itemKey, {
|
|
3977
4089
|
command: "command output",
|
|
3978
4090
|
output,
|
|
3979
4091
|
processId: delta.processId,
|
|
3980
4092
|
stream: delta.stream
|
|
3981
4093
|
}, "streaming");
|
|
4094
|
+
const persistedOutput = typeof structured.output === "string" ? structured.output : output;
|
|
4095
|
+
const body = codexCommandOutputBody("command output", output);
|
|
4096
|
+
if (structured.output_truncated === true) {
|
|
4097
|
+
args.log("codex.command_output_truncated", {
|
|
4098
|
+
item_key: delta.itemKey,
|
|
4099
|
+
turn_id: turnId,
|
|
4100
|
+
process_id: delta.processId ?? null,
|
|
4101
|
+
stream: delta.stream,
|
|
4102
|
+
failure_class: stringValue(structured.output_truncation_reason) ?? null,
|
|
4103
|
+
original_length: integerValue(structured.output_original_length) ?? null,
|
|
4104
|
+
persisted_length: persistedOutput.length
|
|
4105
|
+
});
|
|
4106
|
+
}
|
|
3982
4107
|
if (existing === undefined) {
|
|
3983
4108
|
const session = args.options.channelSession;
|
|
3984
4109
|
const reply = await pushOk(args.kandan, args.topic, "session:post_thread_message", {
|
|
@@ -4002,7 +4127,7 @@ async function forwardCommandOutputDeltaPayload(args, state, delta, payloadConte
|
|
|
4002
4127
|
itemKey: delta.itemKey,
|
|
4003
4128
|
turnId,
|
|
4004
4129
|
seq,
|
|
4005
|
-
output,
|
|
4130
|
+
output: persistedOutput,
|
|
4006
4131
|
processId: delta.processId,
|
|
4007
4132
|
stream: delta.stream
|
|
4008
4133
|
});
|
|
@@ -4011,7 +4136,7 @@ async function forwardCommandOutputDeltaPayload(args, state, delta, payloadConte
|
|
|
4011
4136
|
await editCodexStructuredOutput(args, state, existing.seq, body, structured);
|
|
4012
4137
|
rememberStreamingCommandOutput(state, {
|
|
4013
4138
|
...existing,
|
|
4014
|
-
output,
|
|
4139
|
+
output: persistedOutput,
|
|
4015
4140
|
processId: delta.processId ?? existing.processId,
|
|
4016
4141
|
stream: delta.stream
|
|
4017
4142
|
});
|
|
@@ -4021,7 +4146,7 @@ async function forwardCommandOutputDeltaPayload(args, state, delta, payloadConte
|
|
|
4021
4146
|
turn_id: turnId,
|
|
4022
4147
|
process_id: delta.processId ?? null,
|
|
4023
4148
|
stream: delta.stream,
|
|
4024
|
-
output_length:
|
|
4149
|
+
output_length: persistedOutput.length
|
|
4025
4150
|
});
|
|
4026
4151
|
}
|
|
4027
4152
|
async function forwardFileChangeDeltaPayload(args, state, delta, payloadContext) {
|
|
@@ -4216,11 +4341,6 @@ function webSearchProgressClientMessageId(instanceId, turnId) {
|
|
|
4216
4341
|
function webSearchProgressItemKey(turnId) {
|
|
4217
4342
|
return `web-search:${turnId}`;
|
|
4218
4343
|
}
|
|
4219
|
-
function commandOutputBody(command, output) {
|
|
4220
|
-
return [`$ ${command}`, output].filter((part) => part.trim() !== "").join(`
|
|
4221
|
-
|
|
4222
|
-
`);
|
|
4223
|
-
}
|
|
4224
4344
|
async function streamCompletedCodexOutput(args, state, payloadContext, params) {
|
|
4225
4345
|
if (state.kandanThreadId === undefined || state.codexThreadId === undefined) {
|
|
4226
4346
|
return;
|
|
@@ -6249,30 +6369,14 @@ function prepareCodeServerLaunch(options) {
|
|
|
6249
6369
|
if (platform !== "darwin") {
|
|
6250
6370
|
return filesystemSandboxUnavailable();
|
|
6251
6371
|
}
|
|
6252
|
-
const sandboxExecBin = options.sandboxExecBin ?? "/usr/bin/sandbox-exec";
|
|
6253
|
-
if (!existsSync2(sandboxExecBin)) {
|
|
6254
|
-
return filesystemSandboxUnavailable();
|
|
6255
|
-
}
|
|
6256
6372
|
const codeServerExecutable = resolveCodeServerExecutable(options.codeServerBin, options.envPath ?? process.env.PATH ?? "");
|
|
6257
6373
|
if (!codeServerExecutable.ok) {
|
|
6258
6374
|
return filesystemSandboxUnavailable();
|
|
6259
6375
|
}
|
|
6260
6376
|
return {
|
|
6261
6377
|
ok: true,
|
|
6262
|
-
command:
|
|
6263
|
-
args:
|
|
6264
|
-
"-p",
|
|
6265
|
-
codeServerSandboxProfile(options, codeServerExecutable.directory),
|
|
6266
|
-
"--",
|
|
6267
|
-
"/bin/sh",
|
|
6268
|
-
"-c",
|
|
6269
|
-
'export HOME="$1"; export PWD="$1"; export TMPDIR="$2"; export TMP="$2"; export TEMP="$2"; shift 2; exec "$@"',
|
|
6270
|
-
"kandan-code-server-env",
|
|
6271
|
-
options.cwd,
|
|
6272
|
-
join4(options.userDataDir, "tmp"),
|
|
6273
|
-
codeServerExecutable.command,
|
|
6274
|
-
...codeServerArgs(options.port, options.cwd, options.userDataDir, options.extensionsDir)
|
|
6275
|
-
]
|
|
6378
|
+
command: codeServerExecutable.command,
|
|
6379
|
+
args: codeServerArgs(options.port, options.cwd, options.userDataDir, options.extensionsDir)
|
|
6276
6380
|
};
|
|
6277
6381
|
}
|
|
6278
6382
|
function prepareLinuxCodeServerLaunch(options) {
|
|
@@ -6343,43 +6447,6 @@ function filesystemSandboxUnavailable() {
|
|
|
6343
6447
|
reason: "local_editor_filesystem_sandbox_unavailable"
|
|
6344
6448
|
};
|
|
6345
6449
|
}
|
|
6346
|
-
function codeServerSandboxProfile(options, codeServerBinDir) {
|
|
6347
|
-
const readOnlyRoots = uniquePaths([
|
|
6348
|
-
"/System",
|
|
6349
|
-
"/Library",
|
|
6350
|
-
"/usr",
|
|
6351
|
-
"/bin",
|
|
6352
|
-
"/sbin",
|
|
6353
|
-
"/etc",
|
|
6354
|
-
"/private/etc",
|
|
6355
|
-
"/opt/homebrew",
|
|
6356
|
-
...options.codeServerRuntimeRoot === undefined ? [] : sandboxPathAliases(options.codeServerRuntimeRoot),
|
|
6357
|
-
codeServerBinDir
|
|
6358
|
-
]);
|
|
6359
|
-
const readWriteRoots = uniquePaths([
|
|
6360
|
-
...sandboxPathAliases(options.cwd),
|
|
6361
|
-
...sandboxPathAliases(options.userDataDir),
|
|
6362
|
-
...options.extensionsDir === undefined ? [] : sandboxPathAliases(options.extensionsDir)
|
|
6363
|
-
]);
|
|
6364
|
-
return [
|
|
6365
|
-
"(version 1)",
|
|
6366
|
-
"(deny default)",
|
|
6367
|
-
"(allow process*)",
|
|
6368
|
-
"(allow signal (target self))",
|
|
6369
|
-
"(allow signal (target same-sandbox))",
|
|
6370
|
-
"(allow sysctl*)",
|
|
6371
|
-
"(allow mach*)",
|
|
6372
|
-
"(allow ipc*)",
|
|
6373
|
-
"(allow network*)",
|
|
6374
|
-
"(allow file-read-metadata)",
|
|
6375
|
-
"(allow file-map-executable)",
|
|
6376
|
-
'(allow file-read* (literal "/") (literal "/private") (literal "/private/var"))',
|
|
6377
|
-
`(allow file-read* ${readOnlyRoots.map(sandboxSubpath).join(" ")})`,
|
|
6378
|
-
'(allow file-read* file-write* (subpath "/dev"))',
|
|
6379
|
-
`(allow file-read* file-write* ${readWriteRoots.map(sandboxSubpath).join(" ")})`
|
|
6380
|
-
].join(`
|
|
6381
|
-
`);
|
|
6382
|
-
}
|
|
6383
6450
|
function resolveCodeServerExecutable(command, envPath) {
|
|
6384
6451
|
if (hasPathSeparator(command)) {
|
|
6385
6452
|
const directory = safeRealpathDir(command);
|
|
@@ -6420,9 +6487,6 @@ function sandboxPathAliases(path) {
|
|
|
6420
6487
|
function uniquePaths(paths) {
|
|
6421
6488
|
return Array.from(new Set(paths.filter((path) => path.length > 0)));
|
|
6422
6489
|
}
|
|
6423
|
-
function sandboxSubpath(path) {
|
|
6424
|
-
return `(subpath "${path.replaceAll("\\", "\\\\").replaceAll('"', "\\\"")}")`;
|
|
6425
|
-
}
|
|
6426
6490
|
function prepareLocalEditorCollaboration(collaboration, runnerId, serverPort, browserBaseUrl) {
|
|
6427
6491
|
if (collaboration === undefined || serverPort === undefined) {
|
|
6428
6492
|
return;
|
|
@@ -6548,19 +6612,11 @@ function installDirectory(sourceDir, destinationDir) {
|
|
|
6548
6612
|
mkdirSync3(dirname2(destinationDir), { recursive: true });
|
|
6549
6613
|
cpSync(sourceDir, destinationDir, { recursive: true });
|
|
6550
6614
|
}
|
|
6551
|
-
function codeServerEnv(env, cwd,
|
|
6615
|
+
function codeServerEnv(env, cwd, _userDataDir, collaboration) {
|
|
6552
6616
|
const { PORT: _port, ...hostEnv } = env;
|
|
6553
|
-
const tempDir = join4(userDataDir, "tmp");
|
|
6554
6617
|
const base = {
|
|
6555
6618
|
...hostEnv,
|
|
6556
|
-
|
|
6557
|
-
PWD: cwd,
|
|
6558
|
-
TMPDIR: tempDir,
|
|
6559
|
-
TMP: tempDir,
|
|
6560
|
-
TEMP: tempDir,
|
|
6561
|
-
XDG_CACHE_HOME: join4(userDataDir, "xdg-cache"),
|
|
6562
|
-
XDG_CONFIG_HOME: join4(userDataDir, "xdg-config"),
|
|
6563
|
-
XDG_DATA_HOME: join4(userDataDir, "xdg-data")
|
|
6619
|
+
PWD: cwd
|
|
6564
6620
|
};
|
|
6565
6621
|
if (collaboration === undefined) {
|
|
6566
6622
|
return base;
|
|
@@ -8654,6 +8710,8 @@ async function applyControl(codex, kandan, topic, instanceId, options, allowedCw
|
|
|
8654
8710
|
switch (control.type) {
|
|
8655
8711
|
case "start_instance": {
|
|
8656
8712
|
const cwd = resolveAllowedCwd(control.cwd, allowedCwds);
|
|
8713
|
+
let startupStage = "starting_codex_session";
|
|
8714
|
+
let startedCodexThreadId;
|
|
8657
8715
|
if (!cwd.ok) {
|
|
8658
8716
|
return {
|
|
8659
8717
|
instanceId,
|
|
@@ -8672,8 +8730,10 @@ async function applyControl(codex, kandan, topic, instanceId, options, allowedCw
|
|
|
8672
8730
|
}
|
|
8673
8731
|
try {
|
|
8674
8732
|
if (options.codexUrl === undefined) {
|
|
8733
|
+
startupStage = "checking_project_trust";
|
|
8675
8734
|
ensureCodexProjectTrusted(cwd.cwd);
|
|
8676
8735
|
}
|
|
8736
|
+
startupStage = "starting_codex_session";
|
|
8677
8737
|
const developerPrompt = normalizedWorkDescription(control.developerPrompt);
|
|
8678
8738
|
const runtimeSettings = startInstanceRuntimeSettings(options, control);
|
|
8679
8739
|
const response = await codex.request("thread/start", {
|
|
@@ -8691,12 +8751,18 @@ async function applyControl(codex, kandan, topic, instanceId, options, allowedCw
|
|
|
8691
8751
|
...runtimeSettings.fast === true ? { serviceTier: "fast" } : {}
|
|
8692
8752
|
});
|
|
8693
8753
|
const codexThreadId = extractStartedThreadId(response);
|
|
8754
|
+
startedCodexThreadId = codexThreadId;
|
|
8694
8755
|
const workDescription = normalizedWorkDescription(control.workDescription);
|
|
8695
8756
|
if (codexThreadId !== undefined && developerPrompt !== undefined) {
|
|
8696
8757
|
await postVisibleDeveloperPrompt(kandan, topic, control, developerPrompt, codexThreadId);
|
|
8697
8758
|
}
|
|
8698
|
-
|
|
8759
|
+
let startedThreadSession;
|
|
8760
|
+
if (codexThreadId !== undefined && onStartedThread !== undefined) {
|
|
8761
|
+
startupStage = "binding_kandan_thread";
|
|
8762
|
+
startedThreadSession = await onStartedThread(control, cwd.cwd, codexThreadId);
|
|
8763
|
+
}
|
|
8699
8764
|
if (codexThreadId !== undefined && workDescription !== undefined) {
|
|
8765
|
+
startupStage = "starting_first_turn";
|
|
8700
8766
|
const rootSeq = integerValue(control.rootSeq);
|
|
8701
8767
|
const sourceSeq = integerValue(control.sourceSeq) ?? rootSeq;
|
|
8702
8768
|
if (startedThreadSession !== undefined && sourceSeq !== undefined) {
|
|
@@ -8722,8 +8788,16 @@ async function applyControl(codex, kandan, topic, instanceId, options, allowedCw
|
|
|
8722
8788
|
response
|
|
8723
8789
|
};
|
|
8724
8790
|
} catch (error) {
|
|
8791
|
+
const failureReason = startInstanceFailureReason(startupStage, error);
|
|
8792
|
+
log("kandan.start_instance_failed", {
|
|
8793
|
+
stage: startupStage,
|
|
8794
|
+
message: error instanceof Error ? error.message : String(error),
|
|
8795
|
+
thread_id: optionalThreadControlField(control, "threadId") ?? null,
|
|
8796
|
+
source_seq: integerValue(control.sourceSeq) ?? integerValue(control.rootSeq) ?? null,
|
|
8797
|
+
codex_thread_id: startedCodexThreadId ?? null
|
|
8798
|
+
});
|
|
8725
8799
|
try {
|
|
8726
|
-
await publishStartInstanceMessageState(kandan, topic, control, "failed",
|
|
8800
|
+
await publishStartInstanceMessageState(kandan, topic, control, "failed", failureReason, { codexThreadId: startedCodexThreadId });
|
|
8727
8801
|
} catch (_publishError) {}
|
|
8728
8802
|
throw error;
|
|
8729
8803
|
}
|
|
@@ -8835,6 +8909,26 @@ async function applyControl(codex, kandan, topic, instanceId, options, allowedCw
|
|
|
8835
8909
|
return { instanceId, controlType: control.type, skipped: true };
|
|
8836
8910
|
}
|
|
8837
8911
|
}
|
|
8912
|
+
function startInstanceFailureReason(stage, error) {
|
|
8913
|
+
const detail = truncateFailureDetail(error instanceof Error ? error.message : String(error));
|
|
8914
|
+
switch (stage) {
|
|
8915
|
+
case "checking_project_trust":
|
|
8916
|
+
return `Codex could not start because this folder is not trusted locally. Trust the folder with linzumi paths add, or restart the runner from a trusted folder. Detail: ${detail}`;
|
|
8917
|
+
case "starting_codex_session":
|
|
8918
|
+
return `Codex did not create a session. Restart the local runner and try again. Detail: ${detail}`;
|
|
8919
|
+
case "binding_kandan_thread":
|
|
8920
|
+
return `Codex started, but Linzumi could not attach it to this thread. Try starting the agent again; if it repeats, share this failed message with the runner owner. Detail: ${detail}`;
|
|
8921
|
+
case "starting_first_turn":
|
|
8922
|
+
return `Codex started, but the first prompt could not be delivered. Try sending the message again; if it repeats, reconnect the local runner. Detail: ${detail}`;
|
|
8923
|
+
}
|
|
8924
|
+
}
|
|
8925
|
+
function truncateFailureDetail(message) {
|
|
8926
|
+
const trimmed = message.trim();
|
|
8927
|
+
if (trimmed.length <= 240) {
|
|
8928
|
+
return trimmed;
|
|
8929
|
+
}
|
|
8930
|
+
return `${trimmed.slice(0, 237)}...`;
|
|
8931
|
+
}
|
|
8838
8932
|
function commanderDeveloperInstructions(args) {
|
|
8839
8933
|
const customPrompt = args.developerPrompt === undefined ? "" : `
|
|
8840
8934
|
<invoker_developer_prompt>
|
|
@@ -8915,14 +9009,14 @@ ${developerPrompt}`,
|
|
|
8915
9009
|
client_message_id: `codex-start-instructions-${threadId}`
|
|
8916
9010
|
});
|
|
8917
9011
|
}
|
|
8918
|
-
async function publishStartInstanceMessageState(kandan, topic, control, status, reason) {
|
|
8919
|
-
const payload = startInstanceMessageStatePayload(control, status, reason);
|
|
9012
|
+
async function publishStartInstanceMessageState(kandan, topic, control, status, reason, diagnostics = {}) {
|
|
9013
|
+
const payload = startInstanceMessageStatePayload(control, status, reason, diagnostics);
|
|
8920
9014
|
if (payload === undefined) {
|
|
8921
9015
|
return;
|
|
8922
9016
|
}
|
|
8923
9017
|
await kandan.push(topic, "message_state", payload);
|
|
8924
9018
|
}
|
|
8925
|
-
function startInstanceMessageStatePayload(control, status, reason) {
|
|
9019
|
+
function startInstanceMessageStatePayload(control, status, reason, diagnostics = {}) {
|
|
8926
9020
|
const rootSeq = integerValue(control.rootSeq);
|
|
8927
9021
|
const sourceSeq = integerValue(control.sourceSeq) ?? rootSeq;
|
|
8928
9022
|
if (sourceSeq === undefined) {
|
|
@@ -8937,7 +9031,8 @@ function startInstanceMessageStatePayload(control, status, reason) {
|
|
|
8937
9031
|
thread_id: threadId,
|
|
8938
9032
|
seq: sourceSeq,
|
|
8939
9033
|
status,
|
|
8940
|
-
reason
|
|
9034
|
+
reason,
|
|
9035
|
+
...diagnostics.codexThreadId === undefined ? {} : { codex_thread_id: diagnostics.codexThreadId }
|
|
8941
9036
|
};
|
|
8942
9037
|
}
|
|
8943
9038
|
function requiredStartInstanceControlField(control, field) {
|
|
@@ -10881,7 +10976,7 @@ async function main(args) {
|
|
|
10881
10976
|
process.stdout.write(connectGuideText());
|
|
10882
10977
|
return;
|
|
10883
10978
|
case "version":
|
|
10884
|
-
process.stdout.write(`linzumi 0.0.
|
|
10979
|
+
process.stdout.write(`linzumi 0.0.41-beta
|
|
10885
10980
|
`);
|
|
10886
10981
|
return;
|
|
10887
10982
|
case "auth":
|
|
@@ -11407,7 +11502,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
11407
11502
|
process.exit(0);
|
|
11408
11503
|
}
|
|
11409
11504
|
if (values.get("version") === true) {
|
|
11410
|
-
process.stdout.write(`linzumi 0.0.
|
|
11505
|
+
process.stdout.write(`linzumi 0.0.41-beta
|
|
11411
11506
|
`);
|
|
11412
11507
|
process.exit(0);
|
|
11413
11508
|
}
|
package/package.json
CHANGED