@linzumi/cli 0.0.39-beta → 0.0.40-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 +345 -134
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
3
|
-
import { existsSync as existsSync10, readFileSync as readFileSync9, realpathSync as
|
|
3
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9, realpathSync as realpathSync6 } from "node:fs";
|
|
4
4
|
import { homedir as homedir9 } from "node:os";
|
|
5
|
-
import { resolve as
|
|
5
|
+
import { resolve as resolve9 } from "node:path";
|
|
6
6
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
7
7
|
|
|
8
8
|
// src/runner.ts
|
|
9
9
|
import { spawn as spawn6 } from "node:child_process";
|
|
10
10
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
11
|
+
import { realpathSync as realpathSync4 } from "node:fs";
|
|
11
12
|
import { hostname as hostname2 } from "node:os";
|
|
12
|
-
import { join as join6 } from "node:path";
|
|
13
|
+
import { join as join6, resolve as resolve5 } from "node:path";
|
|
13
14
|
|
|
14
15
|
// src/channelSessionSupport.ts
|
|
15
16
|
import { spawnSync } from "node:child_process";
|
|
@@ -2544,7 +2545,10 @@ function initialChannelSessionState(cursor, rootSeq, kandanThreadId, codexThread
|
|
|
2544
2545
|
webSearchProgressForwardChain: Promise.resolve(),
|
|
2545
2546
|
typingHeartbeat: undefined,
|
|
2546
2547
|
typingHeartbeatInFlight: false,
|
|
2547
|
-
runtimeSettings: runtimeSettingsFromOptions(options)
|
|
2548
|
+
runtimeSettings: runtimeSettingsFromOptions(options),
|
|
2549
|
+
pendingRuntimeSettingsResume: false,
|
|
2550
|
+
runtimeSettingsGeneration: 0,
|
|
2551
|
+
runtimeSettingsResumeChain: Promise.resolve()
|
|
2548
2552
|
};
|
|
2549
2553
|
}
|
|
2550
2554
|
async function handleLostPortForwardCandidate(args, state, payloadContext, candidate) {
|
|
@@ -2682,7 +2686,7 @@ async function handleChannelSessionControl(args, state, payloadContext, control)
|
|
|
2682
2686
|
interruptedQueuedMessages: interrupted.ok ? interrupted.selectedCount : 0
|
|
2683
2687
|
};
|
|
2684
2688
|
}
|
|
2685
|
-
function updateSessionSettings(args, state, control) {
|
|
2689
|
+
async function updateSessionSettings(args, state, control) {
|
|
2686
2690
|
if (state.codexThreadId !== control.threadId) {
|
|
2687
2691
|
return;
|
|
2688
2692
|
}
|
|
@@ -2694,6 +2698,8 @@ function updateSessionSettings(args, state, control) {
|
|
|
2694
2698
|
};
|
|
2695
2699
|
}
|
|
2696
2700
|
state.runtimeSettings = mergeRuntimeSettings(state.runtimeSettings, control);
|
|
2701
|
+
state.pendingRuntimeSettingsResume = true;
|
|
2702
|
+
state.runtimeSettingsGeneration += 1;
|
|
2697
2703
|
publishRuntimeSettings(args, state).catch((error) => {
|
|
2698
2704
|
args.log("kandan.session_settings_publish_failed", {
|
|
2699
2705
|
message: error instanceof Error ? error.message : String(error)
|
|
@@ -2706,6 +2712,7 @@ function updateSessionSettings(args, state, control) {
|
|
|
2706
2712
|
sandbox: state.runtimeSettings.sandbox ?? null,
|
|
2707
2713
|
fast: state.runtimeSettings.fast ?? null
|
|
2708
2714
|
});
|
|
2715
|
+
await tryResumeCodexThreadForPendingRuntimeSettings(args, state);
|
|
2709
2716
|
return {
|
|
2710
2717
|
instanceId: args.instanceId,
|
|
2711
2718
|
ok: true,
|
|
@@ -2716,6 +2723,71 @@ function updateSessionSettings(args, state, control) {
|
|
|
2716
2723
|
fast: state.runtimeSettings.fast ?? null
|
|
2717
2724
|
};
|
|
2718
2725
|
}
|
|
2726
|
+
async function resumeCodexThreadForPendingRuntimeSettings(args, state) {
|
|
2727
|
+
const requestedGeneration = state.runtimeSettingsGeneration;
|
|
2728
|
+
const previousResume = state.runtimeSettingsResumeChain.catch(() => {
|
|
2729
|
+
return;
|
|
2730
|
+
});
|
|
2731
|
+
const resume = previousResume.then(() => performCodexThreadResumeForPendingRuntimeSettings(args, state, requestedGeneration));
|
|
2732
|
+
state.runtimeSettingsResumeChain = resume.then(() => {
|
|
2733
|
+
return;
|
|
2734
|
+
}, () => {
|
|
2735
|
+
return;
|
|
2736
|
+
});
|
|
2737
|
+
return await resume;
|
|
2738
|
+
}
|
|
2739
|
+
async function performCodexThreadResumeForPendingRuntimeSettings(args, state, requestedGeneration) {
|
|
2740
|
+
if (state.pendingRuntimeSettingsResume !== true || state.closed || state.turn.status !== "idle" || localTuiTurnIsActive(state)) {
|
|
2741
|
+
return true;
|
|
2742
|
+
}
|
|
2743
|
+
const codexThreadId = state.codexThreadId;
|
|
2744
|
+
if (codexThreadId === undefined) {
|
|
2745
|
+
return true;
|
|
2746
|
+
}
|
|
2747
|
+
if (state.runtimeSettingsGeneration !== requestedGeneration) {
|
|
2748
|
+
return false;
|
|
2749
|
+
}
|
|
2750
|
+
const resumeGeneration = requestedGeneration;
|
|
2751
|
+
const resumeSettings = state.runtimeSettings;
|
|
2752
|
+
const runtimeOptions = runtimeOptionsForSettings(args.options, resumeSettings);
|
|
2753
|
+
const resumeParams = {
|
|
2754
|
+
threadId: codexThreadId,
|
|
2755
|
+
...codexThreadRuntimeOverrides(runtimeOptions)
|
|
2756
|
+
};
|
|
2757
|
+
args.log("codex.session_settings_resume_requested", {
|
|
2758
|
+
codex_thread_id: codexThreadId,
|
|
2759
|
+
model: resumeSettings.model ?? null,
|
|
2760
|
+
reasoning_effort: resumeSettings.reasoningEffort ?? null,
|
|
2761
|
+
approval_policy: resumeSettings.approvalPolicy ?? null,
|
|
2762
|
+
sandbox: resumeSettings.sandbox ?? null,
|
|
2763
|
+
fast: resumeSettings.fast ?? null,
|
|
2764
|
+
generation: resumeGeneration
|
|
2765
|
+
});
|
|
2766
|
+
const resumed = await args.codex.request("thread/resume", resumeParams);
|
|
2767
|
+
if ("error" in resumed) {
|
|
2768
|
+
throw new Error(`failed to resume Codex thread with updated settings: ${resumed.error.message}`);
|
|
2769
|
+
}
|
|
2770
|
+
if (state.pendingRuntimeSettingsResume === true && state.runtimeSettingsGeneration === resumeGeneration) {
|
|
2771
|
+
state.pendingRuntimeSettingsResume = false;
|
|
2772
|
+
}
|
|
2773
|
+
args.log("codex.session_settings_resume_completed", {
|
|
2774
|
+
codex_thread_id: codexThreadId,
|
|
2775
|
+
generation: resumeGeneration,
|
|
2776
|
+
current_generation: state.runtimeSettingsGeneration,
|
|
2777
|
+
pending: state.pendingRuntimeSettingsResume
|
|
2778
|
+
});
|
|
2779
|
+
return state.pendingRuntimeSettingsResume !== true;
|
|
2780
|
+
}
|
|
2781
|
+
async function tryResumeCodexThreadForPendingRuntimeSettings(args, state) {
|
|
2782
|
+
try {
|
|
2783
|
+
return await resumeCodexThreadForPendingRuntimeSettings(args, state);
|
|
2784
|
+
} catch (error) {
|
|
2785
|
+
args.log("codex.session_settings_resume_failed", {
|
|
2786
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2787
|
+
});
|
|
2788
|
+
return false;
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2719
2791
|
async function resolvePendingCodexApprovalRequest(args, state, control) {
|
|
2720
2792
|
if (state.codexThreadId !== control.threadId) {
|
|
2721
2793
|
return;
|
|
@@ -3277,6 +3349,10 @@ async function drainKandanMessageQueue(args, state, payloadContext) {
|
|
|
3277
3349
|
if (state.closed || state.turn.status !== "idle" || localTuiTurnIsActive(state)) {
|
|
3278
3350
|
return;
|
|
3279
3351
|
}
|
|
3352
|
+
const resumed = await tryResumeCodexThreadForPendingRuntimeSettings(args, state);
|
|
3353
|
+
if (!resumed) {
|
|
3354
|
+
return;
|
|
3355
|
+
}
|
|
3280
3356
|
const next = dequeuePendingKandanMessage(state.queue);
|
|
3281
3357
|
if (next === undefined) {
|
|
3282
3358
|
return;
|
|
@@ -3602,11 +3678,17 @@ async function forwardCompletedCodexTurn(args, state, turnId, payloadContext) {
|
|
|
3602
3678
|
if (completingActiveTurn && state.turn.status === "completing" && state.turn.turnId === turnId) {
|
|
3603
3679
|
state.turn = { status: "idle" };
|
|
3604
3680
|
await stopCodexTyping(args, state);
|
|
3605
|
-
await
|
|
3681
|
+
const resumed = await tryResumeCodexThreadForPendingRuntimeSettings(args, state);
|
|
3682
|
+
if (resumed) {
|
|
3683
|
+
await drainKandanMessageQueue(args, state, payloadContext);
|
|
3684
|
+
}
|
|
3606
3685
|
}
|
|
3607
3686
|
if (completingLocalTuiTurn && !completingActiveTurn) {
|
|
3608
3687
|
await stopCodexTyping(args, state);
|
|
3609
|
-
await
|
|
3688
|
+
const resumed = await tryResumeCodexThreadForPendingRuntimeSettings(args, state);
|
|
3689
|
+
if (resumed) {
|
|
3690
|
+
await drainKandanMessageQueue(args, state, payloadContext);
|
|
3691
|
+
}
|
|
3610
3692
|
}
|
|
3611
3693
|
}
|
|
3612
3694
|
}
|
|
@@ -6271,7 +6353,6 @@ function codeServerSandboxProfile(options, codeServerBinDir) {
|
|
|
6271
6353
|
"/etc",
|
|
6272
6354
|
"/private/etc",
|
|
6273
6355
|
"/opt/homebrew",
|
|
6274
|
-
"/dev",
|
|
6275
6356
|
...options.codeServerRuntimeRoot === undefined ? [] : sandboxPathAliases(options.codeServerRuntimeRoot),
|
|
6276
6357
|
codeServerBinDir
|
|
6277
6358
|
]);
|
|
@@ -6294,6 +6375,7 @@ function codeServerSandboxProfile(options, codeServerBinDir) {
|
|
|
6294
6375
|
"(allow file-map-executable)",
|
|
6295
6376
|
'(allow file-read* (literal "/") (literal "/private") (literal "/private/var"))',
|
|
6296
6377
|
`(allow file-read* ${readOnlyRoots.map(sandboxSubpath).join(" ")})`,
|
|
6378
|
+
'(allow file-read* file-write* (subpath "/dev"))',
|
|
6297
6379
|
`(allow file-read* file-write* ${readWriteRoots.map(sandboxSubpath).join(" ")})`
|
|
6298
6380
|
].join(`
|
|
6299
6381
|
`);
|
|
@@ -7955,6 +8037,9 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
7955
8037
|
};
|
|
7956
8038
|
});
|
|
7957
8039
|
const allowedCwds = { value: [...options.allowedCwds] };
|
|
8040
|
+
const missingAllowedCwds = {
|
|
8041
|
+
value: normalizeAllowedCwds(options.missingAllowedCwds ?? [])
|
|
8042
|
+
};
|
|
7958
8043
|
const localEditorState = {
|
|
7959
8044
|
value: { status: "disabled" }
|
|
7960
8045
|
};
|
|
@@ -7970,7 +8055,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
7970
8055
|
codexRemoteTui: true,
|
|
7971
8056
|
startInstance: allowedCwds.value.length > 0,
|
|
7972
8057
|
allowedCwds: allowedCwds.value,
|
|
7973
|
-
|
|
8058
|
+
missingAllowedCwds: missingAllowedCwds.value,
|
|
7974
8059
|
allowedCwdSuggestions: allowedCwdSuggestions(options.cwd, allowedCwds.value),
|
|
7975
8060
|
portForwarding: liveForwardPorts.size > 0,
|
|
7976
8061
|
allowedPorts: Array.from(liveForwardPorts).sort((left, right) => left - right),
|
|
@@ -7985,7 +8070,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
7985
8070
|
const joinPayload = () => ({
|
|
7986
8071
|
clientName: "kandan-local-codex-runner",
|
|
7987
8072
|
version: "0.0.1",
|
|
7988
|
-
workspace: options
|
|
8073
|
+
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
7989
8074
|
channel: options.channelSession?.channelSlug ?? null,
|
|
7990
8075
|
capabilities: capabilitiesPayload()
|
|
7991
8076
|
});
|
|
@@ -8055,6 +8140,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
8055
8140
|
const codexThreads = options.channelSession === undefined ? await discoverCodexThreads(codex, options.cwd) : [];
|
|
8056
8141
|
const discoveredCodexThreads = { value: codexThreads };
|
|
8057
8142
|
const runnerHost = hostname2();
|
|
8143
|
+
const runtimeDefaults = runnerRuntimeDefaults(options);
|
|
8058
8144
|
const instancePayload = {
|
|
8059
8145
|
instanceId,
|
|
8060
8146
|
codexUrl,
|
|
@@ -8062,8 +8148,10 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
8062
8148
|
cwd: options.cwd,
|
|
8063
8149
|
hostname: runnerHost,
|
|
8064
8150
|
codexThreads,
|
|
8065
|
-
|
|
8066
|
-
|
|
8151
|
+
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
8152
|
+
channel: options.channelSession?.channelSlug ?? null,
|
|
8153
|
+
model: runtimeDefaults.model ?? null,
|
|
8154
|
+
reasoningEffort: runtimeDefaults.reasoningEffort ?? null,
|
|
8067
8155
|
fast: options.fast ?? false
|
|
8068
8156
|
};
|
|
8069
8157
|
await kandan.push(topic, "instance_started", instancePayload);
|
|
@@ -8108,9 +8196,9 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
8108
8196
|
dynamicChannelSessions.clear();
|
|
8109
8197
|
});
|
|
8110
8198
|
const attachThreadSession = async (control, cwd, codexThreadId) => {
|
|
8111
|
-
const workspaceSlug =
|
|
8112
|
-
const channelSlug =
|
|
8113
|
-
const kandanThreadId =
|
|
8199
|
+
const workspaceSlug = optionalThreadControlField(control, "workspace");
|
|
8200
|
+
const channelSlug = optionalThreadControlField(control, "channel");
|
|
8201
|
+
const kandanThreadId = optionalThreadControlField(control, "threadId");
|
|
8114
8202
|
if (workspaceSlug === undefined || channelSlug === undefined || kandanThreadId === undefined) {
|
|
8115
8203
|
return;
|
|
8116
8204
|
}
|
|
@@ -8171,13 +8259,13 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
8171
8259
|
codexUrl,
|
|
8172
8260
|
cwd: options.cwd,
|
|
8173
8261
|
hostname: runnerHost,
|
|
8174
|
-
workspace: options
|
|
8262
|
+
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
8175
8263
|
channel: options.channelSession?.channelSlug ?? null,
|
|
8176
8264
|
threadId: channelSession?.currentKandanThreadId() ?? null,
|
|
8177
8265
|
codexThreadId: channelSession?.currentCodexThreadId() ?? null,
|
|
8178
8266
|
codexThreads: discoveredCodexThreads.value,
|
|
8179
|
-
model:
|
|
8180
|
-
reasoningEffort:
|
|
8267
|
+
model: runtimeDefaults.model ?? null,
|
|
8268
|
+
reasoningEffort: runtimeDefaults.reasoningEffort ?? null,
|
|
8181
8269
|
fast: options.fast ?? false,
|
|
8182
8270
|
capabilities: capabilitiesPayload()
|
|
8183
8271
|
});
|
|
@@ -8342,7 +8430,9 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
8342
8430
|
return;
|
|
8343
8431
|
}
|
|
8344
8432
|
if (isUpdateRunnerConfigControl(control)) {
|
|
8345
|
-
|
|
8433
|
+
const updatedAllowedCwds = configuredAllowedCwds(control.allowedCwds);
|
|
8434
|
+
allowedCwds.value = updatedAllowedCwds.allowedCwds;
|
|
8435
|
+
missingAllowedCwds.value = updatedAllowedCwds.missingAllowedCwds;
|
|
8346
8436
|
pushHeartbeat();
|
|
8347
8437
|
return;
|
|
8348
8438
|
}
|
|
@@ -8374,7 +8464,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
8374
8464
|
if (handled !== undefined) {
|
|
8375
8465
|
return handled;
|
|
8376
8466
|
}
|
|
8377
|
-
return applyControl(codex, kandan, topic, instanceId, options, allowedCwds.value, control, attachThreadSession);
|
|
8467
|
+
return applyControl(codex, kandan, topic, instanceId, options, allowedCwds.value, control, log, attachThreadSession);
|
|
8378
8468
|
}).then((response) => {
|
|
8379
8469
|
return kandan.push(topic, "codex_response", response);
|
|
8380
8470
|
}).catch((error) => {
|
|
@@ -8450,7 +8540,7 @@ async function discoverCodexThreads(codex, cwd) {
|
|
|
8450
8540
|
}
|
|
8451
8541
|
function extractStartedThreadId(response) {
|
|
8452
8542
|
if ("error" in response) {
|
|
8453
|
-
|
|
8543
|
+
throw new Error(`thread/start failed: ${response.error.message}`);
|
|
8454
8544
|
}
|
|
8455
8545
|
return stringValue(objectValue(objectValue(response.result)?.thread)?.id);
|
|
8456
8546
|
}
|
|
@@ -8560,7 +8650,7 @@ async function prepareCodexThreadForTuiResume(codex, codexThreadId) {
|
|
|
8560
8650
|
throw new Error(`failed to verify Codex TUI resume: ${verified.error.message}`);
|
|
8561
8651
|
}
|
|
8562
8652
|
}
|
|
8563
|
-
async function applyControl(codex, kandan, topic, instanceId, options, allowedCwds, control, onStartedThread) {
|
|
8653
|
+
async function applyControl(codex, kandan, topic, instanceId, options, allowedCwds, control, log, onStartedThread) {
|
|
8564
8654
|
switch (control.type) {
|
|
8565
8655
|
case "start_instance": {
|
|
8566
8656
|
const cwd = resolveAllowedCwd(control.cwd, allowedCwds);
|
|
@@ -8572,56 +8662,71 @@ async function applyControl(codex, kandan, topic, instanceId, options, allowedCw
|
|
|
8572
8662
|
error: cwd.reason
|
|
8573
8663
|
};
|
|
8574
8664
|
}
|
|
8575
|
-
|
|
8576
|
-
|
|
8665
|
+
const processingStatePayload = startInstanceMessageStatePayload(control, "processing", "starting Codex session");
|
|
8666
|
+
if (processingStatePayload !== undefined) {
|
|
8667
|
+
kandan.push(topic, "message_state", processingStatePayload).catch((error) => {
|
|
8668
|
+
log("kandan.start_instance_processing_state_push_failed", {
|
|
8669
|
+
message: error instanceof Error ? error.message : String(error)
|
|
8670
|
+
});
|
|
8671
|
+
});
|
|
8577
8672
|
}
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
-
|
|
8673
|
+
try {
|
|
8674
|
+
if (options.codexUrl === undefined) {
|
|
8675
|
+
ensureCodexProjectTrusted(cwd.cwd);
|
|
8676
|
+
}
|
|
8677
|
+
const developerPrompt = normalizedWorkDescription(control.developerPrompt);
|
|
8678
|
+
const runtimeSettings = startInstanceRuntimeSettings(options, control);
|
|
8679
|
+
const response = await codex.request("thread/start", {
|
|
8585
8680
|
cwd: cwd.cwd,
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
const sourceSeq = integerValue(control.sourceSeq) ?? rootSeq;
|
|
8603
|
-
if (startedThreadSession !== undefined && sourceSeq !== undefined) {
|
|
8604
|
-
const identity = identityFromAccessToken(options.token);
|
|
8605
|
-
await startedThreadSession.startThreadMessageTurn({
|
|
8606
|
-
seq: sourceSeq,
|
|
8607
|
-
body: workDescription,
|
|
8608
|
-
actorSlug: identity.actorUsername,
|
|
8609
|
-
actorUserId: identity.actorUserId
|
|
8610
|
-
});
|
|
8611
|
-
} else {
|
|
8612
|
-
await codex.request("turn/start", {
|
|
8613
|
-
threadId: codexThreadId,
|
|
8614
|
-
input: [{ type: "text", text: workDescription }]
|
|
8615
|
-
});
|
|
8681
|
+
serviceName: "kandan-local-runner",
|
|
8682
|
+
personality: "pragmatic",
|
|
8683
|
+
developerInstructions: commanderDeveloperInstructions({
|
|
8684
|
+
cwd: cwd.cwd,
|
|
8685
|
+
developerPrompt
|
|
8686
|
+
}),
|
|
8687
|
+
...runtimeSettings.model === undefined ? {} : { model: runtimeSettings.model },
|
|
8688
|
+
...runtimeSettings.reasoningEffort === undefined ? {} : { reasoningEffort: runtimeSettings.reasoningEffort },
|
|
8689
|
+
...runtimeSettings.approvalPolicy === undefined ? {} : { approvalPolicy: runtimeSettings.approvalPolicy },
|
|
8690
|
+
...runtimeSettings.sandbox === undefined ? {} : { sandbox: runtimeSettings.sandbox },
|
|
8691
|
+
...runtimeSettings.fast === true ? { serviceTier: "fast" } : {}
|
|
8692
|
+
});
|
|
8693
|
+
const codexThreadId = extractStartedThreadId(response);
|
|
8694
|
+
const workDescription = normalizedWorkDescription(control.workDescription);
|
|
8695
|
+
if (codexThreadId !== undefined && developerPrompt !== undefined) {
|
|
8696
|
+
await postVisibleDeveloperPrompt(kandan, topic, control, developerPrompt, codexThreadId);
|
|
8616
8697
|
}
|
|
8698
|
+
const startedThreadSession = codexThreadId !== undefined && onStartedThread !== undefined ? await onStartedThread(control, cwd.cwd, codexThreadId) : undefined;
|
|
8699
|
+
if (codexThreadId !== undefined && workDescription !== undefined) {
|
|
8700
|
+
const rootSeq = integerValue(control.rootSeq);
|
|
8701
|
+
const sourceSeq = integerValue(control.sourceSeq) ?? rootSeq;
|
|
8702
|
+
if (startedThreadSession !== undefined && sourceSeq !== undefined) {
|
|
8703
|
+
const identity = identityFromAccessToken(options.token);
|
|
8704
|
+
await startedThreadSession.startThreadMessageTurn({
|
|
8705
|
+
seq: sourceSeq,
|
|
8706
|
+
body: workDescription,
|
|
8707
|
+
actorSlug: identity.actorUsername,
|
|
8708
|
+
actorUserId: identity.actorUserId
|
|
8709
|
+
});
|
|
8710
|
+
} else {
|
|
8711
|
+
await codex.request("turn/start", {
|
|
8712
|
+
threadId: codexThreadId,
|
|
8713
|
+
input: [{ type: "text", text: workDescription }]
|
|
8714
|
+
});
|
|
8715
|
+
}
|
|
8716
|
+
}
|
|
8717
|
+
return {
|
|
8718
|
+
instanceId,
|
|
8719
|
+
controlType: control.type,
|
|
8720
|
+
cwd: cwd.cwd,
|
|
8721
|
+
matchedRoot: cwd.matchedRoot,
|
|
8722
|
+
response
|
|
8723
|
+
};
|
|
8724
|
+
} catch (error) {
|
|
8725
|
+
try {
|
|
8726
|
+
await publishStartInstanceMessageState(kandan, topic, control, "failed", "failed to start Codex session");
|
|
8727
|
+
} catch (_publishError) {}
|
|
8728
|
+
throw error;
|
|
8617
8729
|
}
|
|
8618
|
-
return {
|
|
8619
|
-
instanceId,
|
|
8620
|
-
controlType: control.type,
|
|
8621
|
-
cwd: cwd.cwd,
|
|
8622
|
-
matchedRoot: cwd.matchedRoot,
|
|
8623
|
-
response
|
|
8624
|
-
};
|
|
8625
8730
|
}
|
|
8626
8731
|
case "reconnect_thread": {
|
|
8627
8732
|
const cwd = resolveAllowedCwd(control.cwd, allowedCwds);
|
|
@@ -8786,9 +8891,9 @@ secure tunnel, and keep the Linzumi thread truthful.
|
|
|
8786
8891
|
</task_reminder>`;
|
|
8787
8892
|
}
|
|
8788
8893
|
async function postVisibleDeveloperPrompt(kandan, topic, control, developerPrompt, codexThreadId) {
|
|
8789
|
-
const workspace =
|
|
8790
|
-
const channel =
|
|
8791
|
-
const threadId =
|
|
8894
|
+
const workspace = optionalThreadControlField(control, "workspace");
|
|
8895
|
+
const channel = optionalThreadControlField(control, "channel");
|
|
8896
|
+
const threadId = optionalThreadControlField(control, "threadId");
|
|
8792
8897
|
if (workspace === undefined || channel === undefined || threadId === undefined) {
|
|
8793
8898
|
return;
|
|
8794
8899
|
}
|
|
@@ -8810,24 +8915,80 @@ ${developerPrompt}`,
|
|
|
8810
8915
|
client_message_id: `codex-start-instructions-${threadId}`
|
|
8811
8916
|
});
|
|
8812
8917
|
}
|
|
8918
|
+
async function publishStartInstanceMessageState(kandan, topic, control, status, reason) {
|
|
8919
|
+
const payload = startInstanceMessageStatePayload(control, status, reason);
|
|
8920
|
+
if (payload === undefined) {
|
|
8921
|
+
return;
|
|
8922
|
+
}
|
|
8923
|
+
await kandan.push(topic, "message_state", payload);
|
|
8924
|
+
}
|
|
8925
|
+
function startInstanceMessageStatePayload(control, status, reason) {
|
|
8926
|
+
const rootSeq = integerValue(control.rootSeq);
|
|
8927
|
+
const sourceSeq = integerValue(control.sourceSeq) ?? rootSeq;
|
|
8928
|
+
if (sourceSeq === undefined) {
|
|
8929
|
+
return;
|
|
8930
|
+
}
|
|
8931
|
+
const workspace = requiredStartInstanceControlField(control, "workspace");
|
|
8932
|
+
const channel = requiredStartInstanceControlField(control, "channel");
|
|
8933
|
+
const threadId = requiredStartInstanceControlField(control, "threadId");
|
|
8934
|
+
return {
|
|
8935
|
+
workspace,
|
|
8936
|
+
channel,
|
|
8937
|
+
thread_id: threadId,
|
|
8938
|
+
seq: sourceSeq,
|
|
8939
|
+
status,
|
|
8940
|
+
reason
|
|
8941
|
+
};
|
|
8942
|
+
}
|
|
8943
|
+
function requiredStartInstanceControlField(control, field) {
|
|
8944
|
+
return requiredThreadControlField(control, field);
|
|
8945
|
+
}
|
|
8946
|
+
function requiredThreadControlField(control, field) {
|
|
8947
|
+
const value = optionalThreadControlField(control, field);
|
|
8948
|
+
if (value === undefined) {
|
|
8949
|
+
throw new Error(`${control.type} control missing ${field}`);
|
|
8950
|
+
}
|
|
8951
|
+
return value;
|
|
8952
|
+
}
|
|
8953
|
+
function optionalThreadControlField(control, field) {
|
|
8954
|
+
const value = stringValue(control[field])?.trim();
|
|
8955
|
+
if (value === undefined || value === "") {
|
|
8956
|
+
return;
|
|
8957
|
+
}
|
|
8958
|
+
return value;
|
|
8959
|
+
}
|
|
8813
8960
|
function startInstanceRuntimeSettings(options, control) {
|
|
8814
|
-
const
|
|
8961
|
+
const defaults = runnerRuntimeDefaults(options);
|
|
8815
8962
|
return {
|
|
8816
|
-
model: control.model ??
|
|
8817
|
-
reasoningEffort: control.reasoningEffort ??
|
|
8818
|
-
approvalPolicy: control.approvalPolicy ??
|
|
8819
|
-
sandbox: control.sandbox ??
|
|
8963
|
+
model: control.model ?? defaults.model,
|
|
8964
|
+
reasoningEffort: control.reasoningEffort ?? defaults.reasoningEffort,
|
|
8965
|
+
approvalPolicy: control.approvalPolicy ?? defaults.approvalPolicy,
|
|
8966
|
+
sandbox: control.sandbox ?? defaults.sandbox,
|
|
8820
8967
|
fast: control.fast ?? options.fast
|
|
8821
8968
|
};
|
|
8822
8969
|
}
|
|
8823
8970
|
async function startOwnedCodexAppServer(options) {
|
|
8824
8971
|
ensureCodexProjectTrusted(options.cwd);
|
|
8972
|
+
const defaults = runnerRuntimeDefaults(options);
|
|
8825
8973
|
return await startCodexAppServer(options.codexBin, options.cwd, {
|
|
8826
|
-
model:
|
|
8827
|
-
reasoningEffort:
|
|
8974
|
+
model: defaults.model,
|
|
8975
|
+
reasoningEffort: defaults.reasoningEffort,
|
|
8828
8976
|
fast: options.fast
|
|
8829
8977
|
});
|
|
8830
8978
|
}
|
|
8979
|
+
function runnerWorkspaceSlug(options) {
|
|
8980
|
+
return options.channelSession?.workspaceSlug ?? options.workspaceSlug;
|
|
8981
|
+
}
|
|
8982
|
+
function runnerRuntimeDefaults(options) {
|
|
8983
|
+
const session = options.channelSession;
|
|
8984
|
+
const defaults = options.runtimeDefaults;
|
|
8985
|
+
return {
|
|
8986
|
+
model: defaults?.model ?? session?.model,
|
|
8987
|
+
reasoningEffort: defaults?.reasoningEffort ?? session?.reasoningEffort,
|
|
8988
|
+
approvalPolicy: defaults?.approvalPolicy ?? session?.approvalPolicy,
|
|
8989
|
+
sandbox: defaults?.sandbox ?? session?.sandbox
|
|
8990
|
+
};
|
|
8991
|
+
}
|
|
8831
8992
|
function isUpdateRunnerConfigControl(control) {
|
|
8832
8993
|
return control.type === "update_runner_config";
|
|
8833
8994
|
}
|
|
@@ -8840,6 +9001,30 @@ function normalizeAllowedCwds(values) {
|
|
|
8840
9001
|
return normalized === "" ? [] : [normalized];
|
|
8841
9002
|
})));
|
|
8842
9003
|
}
|
|
9004
|
+
function configuredAllowedCwds(values) {
|
|
9005
|
+
const allowedCwds = [];
|
|
9006
|
+
const missingAllowedCwds = [];
|
|
9007
|
+
for (const value of normalizeAllowedCwds(values)) {
|
|
9008
|
+
const absolutePath = resolve5(expandUserPath(value));
|
|
9009
|
+
try {
|
|
9010
|
+
const realPath = realpathSync4(absolutePath);
|
|
9011
|
+
allowedCwds.push(...realPath === absolutePath ? [realPath] : [realPath, absolutePath]);
|
|
9012
|
+
} catch (error) {
|
|
9013
|
+
if (isMissingAllowedCwdError(error)) {
|
|
9014
|
+
missingAllowedCwds.push(absolutePath);
|
|
9015
|
+
continue;
|
|
9016
|
+
}
|
|
9017
|
+
throw error;
|
|
9018
|
+
}
|
|
9019
|
+
}
|
|
9020
|
+
return {
|
|
9021
|
+
allowedCwds: normalizeAllowedCwds(allowedCwds),
|
|
9022
|
+
missingAllowedCwds: normalizeAllowedCwds(missingAllowedCwds)
|
|
9023
|
+
};
|
|
9024
|
+
}
|
|
9025
|
+
function isMissingAllowedCwdError(error) {
|
|
9026
|
+
return typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR" || error.code === "EACCES" || error.code === "ELOOP" || error.code === "EIO");
|
|
9027
|
+
}
|
|
8843
9028
|
function allowedCwdSuggestions(cwd, allowedCwds) {
|
|
8844
9029
|
return normalizeAllowedCwds([cwd, ...allowedCwds]);
|
|
8845
9030
|
}
|
|
@@ -8988,14 +9173,14 @@ import {
|
|
|
8988
9173
|
existsSync as existsSync5,
|
|
8989
9174
|
mkdirSync as mkdirSync6,
|
|
8990
9175
|
readFileSync as readFileSync4,
|
|
8991
|
-
realpathSync as
|
|
9176
|
+
realpathSync as realpathSync5,
|
|
8992
9177
|
writeFileSync as writeFileSync5
|
|
8993
9178
|
} from "node:fs";
|
|
8994
9179
|
import { homedir as homedir6 } from "node:os";
|
|
8995
|
-
import { dirname as dirname5, resolve as
|
|
9180
|
+
import { dirname as dirname5, resolve as resolve6 } from "node:path";
|
|
8996
9181
|
function localConfigPath(env = process.env) {
|
|
8997
9182
|
const override = env.LINZUMI_CONFIG_FILE;
|
|
8998
|
-
return override !== undefined && override.trim() !== "" ?
|
|
9183
|
+
return override !== undefined && override.trim() !== "" ? resolve6(expandUserPath(override)) : resolve6(homedir6(), ".linzumi", "config.json");
|
|
8999
9184
|
}
|
|
9000
9185
|
function readLocalConfig(path = localConfigPath()) {
|
|
9001
9186
|
if (!existsSync5(path)) {
|
|
@@ -9010,32 +9195,36 @@ function readLocalConfig(path = localConfigPath()) {
|
|
|
9010
9195
|
allowedCwds: uniqueStrings(parsed.allowedCwds)
|
|
9011
9196
|
};
|
|
9012
9197
|
}
|
|
9013
|
-
function
|
|
9198
|
+
function readConfiguredAllowedCwdDetails(path = localConfigPath()) {
|
|
9014
9199
|
const allowedCwds = [];
|
|
9015
|
-
const
|
|
9200
|
+
const missingAllowedCwds = [];
|
|
9016
9201
|
for (const cwd of readLocalConfig(path).allowedCwds) {
|
|
9202
|
+
const absolutePath = resolve6(expandUserPath(cwd));
|
|
9017
9203
|
try {
|
|
9018
|
-
const
|
|
9019
|
-
const realPath = realpathSync4(absolutePath);
|
|
9204
|
+
const realPath = realpathSync5(absolutePath);
|
|
9020
9205
|
allowedCwds.push(...realPath === absolutePath ? [realPath] : [realPath, absolutePath]);
|
|
9021
|
-
} catch (
|
|
9022
|
-
|
|
9206
|
+
} catch (error) {
|
|
9207
|
+
if (isMissingPathError(error)) {
|
|
9208
|
+
missingAllowedCwds.push(absolutePath);
|
|
9209
|
+
continue;
|
|
9210
|
+
}
|
|
9211
|
+
throw error;
|
|
9023
9212
|
}
|
|
9024
9213
|
}
|
|
9025
9214
|
return {
|
|
9026
9215
|
allowedCwds: uniqueStrings(allowedCwds),
|
|
9027
|
-
|
|
9216
|
+
missingAllowedCwds: uniqueStrings(missingAllowedCwds)
|
|
9028
9217
|
};
|
|
9029
9218
|
}
|
|
9030
9219
|
function addAllowedCwd(pathValue, path = localConfigPath()) {
|
|
9031
|
-
const normalizedPath =
|
|
9220
|
+
const normalizedPath = realpathSync5(resolve6(expandUserPath(pathValue)));
|
|
9032
9221
|
const config = readLocalConfig(path);
|
|
9033
9222
|
const allowedCwds = uniqueStrings([...config.allowedCwds, normalizedPath]);
|
|
9034
9223
|
writeLocalConfig({ version: 1, allowedCwds }, path);
|
|
9035
9224
|
return allowedCwds;
|
|
9036
9225
|
}
|
|
9037
9226
|
function removeAllowedCwd(pathValue, path = localConfigPath()) {
|
|
9038
|
-
const requestedPath =
|
|
9227
|
+
const requestedPath = resolve6(expandUserPath(pathValue));
|
|
9039
9228
|
const normalizedRequest = realpathOrResolved(requestedPath);
|
|
9040
9229
|
const config = readLocalConfig(path);
|
|
9041
9230
|
const allowedCwds = config.allowedCwds.filter((cwd) => {
|
|
@@ -9058,11 +9247,14 @@ function uniqueStrings(values) {
|
|
|
9058
9247
|
...new Set(values.map((value) => value.trim()).filter((value) => value !== ""))
|
|
9059
9248
|
];
|
|
9060
9249
|
}
|
|
9250
|
+
function isMissingPathError(error) {
|
|
9251
|
+
return typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR" || error.code === "EACCES" || error.code === "ELOOP" || error.code === "EIO");
|
|
9252
|
+
}
|
|
9061
9253
|
function realpathOrResolved(pathValue) {
|
|
9062
9254
|
try {
|
|
9063
|
-
return
|
|
9255
|
+
return realpathSync5(resolve6(expandUserPath(pathValue)));
|
|
9064
9256
|
} catch (_error) {
|
|
9065
|
-
return
|
|
9257
|
+
return resolve6(expandUserPath(pathValue));
|
|
9066
9258
|
}
|
|
9067
9259
|
}
|
|
9068
9260
|
|
|
@@ -9460,7 +9652,7 @@ async function runClaim(command, deps) {
|
|
|
9460
9652
|
workspaceName: stringValue(response.workspace_name),
|
|
9461
9653
|
channelId: stringValue(response.channel_id),
|
|
9462
9654
|
ownerUsername: stringValue(response.owner_username),
|
|
9463
|
-
channelUrl:
|
|
9655
|
+
channelUrl: stringValue(response.channel_url),
|
|
9464
9656
|
loginUrl: requiredString(response, "login_url"),
|
|
9465
9657
|
supportChannelId: requiredString(response, "support_channel_id"),
|
|
9466
9658
|
supportChannelUrl: requiredString(response, "support_channel_url"),
|
|
@@ -9479,8 +9671,10 @@ async function runClaim(command, deps) {
|
|
|
9479
9671
|
deps.stdout.write(`login_url: ${tokenFile.loginUrl}
|
|
9480
9672
|
`);
|
|
9481
9673
|
writeHumanLoginUrlWarning(deps);
|
|
9482
|
-
|
|
9674
|
+
if (tokenFile.channelUrl !== undefined) {
|
|
9675
|
+
deps.stdout.write(`channel_url: ${tokenFile.channelUrl}
|
|
9483
9676
|
`);
|
|
9677
|
+
}
|
|
9484
9678
|
deps.stdout.write(`support_channel_id: ${tokenFile.supportChannelId}
|
|
9485
9679
|
`);
|
|
9486
9680
|
deps.stdout.write(`support_channel_url: ${tokenFile.supportChannelUrl}
|
|
@@ -9749,7 +9943,7 @@ function readStoredAgentTokenFile(path, readTextFile = readOptionalTextFile) {
|
|
|
9749
9943
|
workspaceName: stringValue(parsed.workspaceName),
|
|
9750
9944
|
channelId: stringValue(parsed.channelId),
|
|
9751
9945
|
ownerUsername: stringValue(parsed.ownerUsername),
|
|
9752
|
-
channelUrl:
|
|
9946
|
+
channelUrl: stringValue(parsed.channelUrl),
|
|
9753
9947
|
loginUrl: requiredString(parsed, "loginUrl"),
|
|
9754
9948
|
supportChannelId: requiredString(parsed, "supportChannelId"),
|
|
9755
9949
|
supportChannelUrl: stringValue(parsed.supportChannelUrl),
|
|
@@ -9803,7 +9997,7 @@ Launch target:
|
|
|
9803
9997
|
|
|
9804
9998
|
// src/helloLinzumiProject.ts
|
|
9805
9999
|
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync7, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
9806
|
-
import { dirname as dirname7, join as join9, resolve as
|
|
10000
|
+
import { dirname as dirname7, join as join9, resolve as resolve7 } from "node:path";
|
|
9807
10001
|
import { fileURLToPath } from "node:url";
|
|
9808
10002
|
var defaultHelloLinzumiProjectDir = "/tmp/hello_linzumi";
|
|
9809
10003
|
var defaultHelloLinzumiProjectName = "hello_linzumi";
|
|
@@ -9837,10 +10031,10 @@ function resolveHelloProjectRoot(options) {
|
|
|
9837
10031
|
throw new Error("linzumi init-hello-linzumi-demo-app accepts either --dir or --parent-dir/--name, not both");
|
|
9838
10032
|
}
|
|
9839
10033
|
if (options.rootPath !== undefined) {
|
|
9840
|
-
return
|
|
10034
|
+
return resolve7(options.rootPath);
|
|
9841
10035
|
}
|
|
9842
10036
|
const name = normalizeProjectName(options.name ?? defaultHelloLinzumiProjectName);
|
|
9843
|
-
return
|
|
10037
|
+
return resolve7(options.parentDir ?? defaultHelloLinzumiParentDir, name);
|
|
9844
10038
|
}
|
|
9845
10039
|
function normalizeProjectName(value) {
|
|
9846
10040
|
const name = value.trim();
|
|
@@ -10375,7 +10569,7 @@ import {
|
|
|
10375
10569
|
writeFileSync as writeFileSync8
|
|
10376
10570
|
} from "node:fs";
|
|
10377
10571
|
import { homedir as homedir8 } from "node:os";
|
|
10378
|
-
import { dirname as dirname8, join as join10, resolve as
|
|
10572
|
+
import { dirname as dirname8, join as join10, resolve as resolve8 } from "node:path";
|
|
10379
10573
|
import { execFileSync, spawn as spawn7 } from "node:child_process";
|
|
10380
10574
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
10381
10575
|
var connectedMarker = "Runner connected:";
|
|
@@ -10391,7 +10585,7 @@ function defaultCommanderLogFile(runnerId, statusDir = commanderStatusDir()) {
|
|
|
10391
10585
|
function startCommanderDaemon(options) {
|
|
10392
10586
|
const statusDir = options.statusDir ?? commanderStatusDir();
|
|
10393
10587
|
const statusFile = commanderStatusFile(options.runnerId, statusDir);
|
|
10394
|
-
const logFile =
|
|
10588
|
+
const logFile = resolve8(options.logFile ?? defaultCommanderLogFile(options.runnerId, statusDir));
|
|
10395
10589
|
const entrypoint = options.entrypoint ?? currentEntrypoint();
|
|
10396
10590
|
const nodeBin = options.nodeBin ?? process.execPath;
|
|
10397
10591
|
const command = [
|
|
@@ -10588,7 +10782,7 @@ function safeRunnerId(runnerId) {
|
|
|
10588
10782
|
}
|
|
10589
10783
|
async function waitForFileChangeOrTimeout(path, deadline, now, ready2 = () => false) {
|
|
10590
10784
|
const remaining = Math.max(0, deadline - now());
|
|
10591
|
-
await new Promise((
|
|
10785
|
+
await new Promise((resolve9) => {
|
|
10592
10786
|
let resolved = false;
|
|
10593
10787
|
let watcher;
|
|
10594
10788
|
const finish = () => {
|
|
@@ -10598,7 +10792,7 @@ async function waitForFileChangeOrTimeout(path, deadline, now, ready2 = () => fa
|
|
|
10598
10792
|
resolved = true;
|
|
10599
10793
|
watcher?.close();
|
|
10600
10794
|
clearTimeout(timer);
|
|
10601
|
-
|
|
10795
|
+
resolve9();
|
|
10602
10796
|
};
|
|
10603
10797
|
const timer = setTimeout(finish, remaining);
|
|
10604
10798
|
try {
|
|
@@ -10678,7 +10872,7 @@ function isMainModule() {
|
|
|
10678
10872
|
if (scriptPath === undefined) {
|
|
10679
10873
|
return false;
|
|
10680
10874
|
}
|
|
10681
|
-
return fileURLToPath3(import.meta.url) ===
|
|
10875
|
+
return fileURLToPath3(import.meta.url) === resolve9(scriptPath);
|
|
10682
10876
|
}
|
|
10683
10877
|
async function main(args) {
|
|
10684
10878
|
const parsed = parseCommand(args);
|
|
@@ -10687,7 +10881,7 @@ async function main(args) {
|
|
|
10687
10881
|
process.stdout.write(connectGuideText());
|
|
10688
10882
|
return;
|
|
10689
10883
|
case "version":
|
|
10690
|
-
process.stdout.write(`linzumi 0.0.
|
|
10884
|
+
process.stdout.write(`linzumi 0.0.40-beta
|
|
10691
10885
|
`);
|
|
10692
10886
|
return;
|
|
10693
10887
|
case "auth":
|
|
@@ -10840,7 +11034,7 @@ function runPathsCommand(args) {
|
|
|
10840
11034
|
if (pathValue === undefined || pathValue.trim() === "") {
|
|
10841
11035
|
throw new Error("missing path for linzumi paths add");
|
|
10842
11036
|
}
|
|
10843
|
-
const trustedPath =
|
|
11037
|
+
const trustedPath = realpathSync6(resolve9(expandUserPath(pathValue)));
|
|
10844
11038
|
addAllowedCwd(pathValue);
|
|
10845
11039
|
process.stdout.write(`Trusted ${trustedPath}
|
|
10846
11040
|
`);
|
|
@@ -11030,6 +11224,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
11030
11224
|
kandanUrl,
|
|
11031
11225
|
token: targetToken,
|
|
11032
11226
|
runnerId: stringValue3(values, "runner-id") ?? `runner-${randomUUID3()}`,
|
|
11227
|
+
workspaceSlug: target.workspaceSlug,
|
|
11033
11228
|
cwd,
|
|
11034
11229
|
codexBin,
|
|
11035
11230
|
codexUrl: stringValue3(values, "codex-url"),
|
|
@@ -11042,6 +11237,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
11042
11237
|
editorRuntime: editorRuntime.runtime,
|
|
11043
11238
|
socketFactory: trustedWebSocketFactory(kandanTlsTrustFromEnv()),
|
|
11044
11239
|
dependencyStatus,
|
|
11240
|
+
runtimeDefaults: runnerRuntimeDefaultsFromValues(values),
|
|
11045
11241
|
channelSession: {
|
|
11046
11242
|
workspaceSlug: target.workspaceSlug,
|
|
11047
11243
|
channelSlug: target.channelSlug,
|
|
@@ -11073,12 +11269,23 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
11073
11269
|
const tokenFilePath = stringValue3(values, "agent-token-file") ?? defaultAgentTokenFilePath();
|
|
11074
11270
|
const tokenFile = readStoredAgentTokenFile(tokenFilePath, deps.readTextFile);
|
|
11075
11271
|
const channelSlug = tokenFile.channelId;
|
|
11076
|
-
|
|
11272
|
+
rejectWorkspaceCommanderThreadFlags(values, channelSlug);
|
|
11273
|
+
const channelSession = channelSlug === undefined ? undefined : {
|
|
11274
|
+
workspaceSlug: tokenFile.workspaceId,
|
|
11275
|
+
channelSlug,
|
|
11276
|
+
kandanThreadId: stringValue3(values, "linzumi-thread-id"),
|
|
11277
|
+
listenUser: stringValue3(values, "listen-user") ?? requiredStoredOwnerUsername(tokenFile.ownerUsername),
|
|
11278
|
+
model: stringValue3(values, "model"),
|
|
11279
|
+
reasoningEffort: stringValue3(values, "reasoning-effort"),
|
|
11280
|
+
sandbox: stringValue3(values, "sandbox"),
|
|
11281
|
+
approvalPolicy: stringValue3(values, "approval-policy"),
|
|
11282
|
+
streamFlushMs: positiveIntegerValue(values, "stream-flush-ms")
|
|
11283
|
+
};
|
|
11077
11284
|
const kandanUrl = stringValue3(values, "linzumi-url") ?? agentApiUrlToKandanUrl(tokenFile.apiUrl);
|
|
11078
11285
|
const requestedCwdValue = cwdArg ?? stringValue3(values, "cwd");
|
|
11079
11286
|
const requestedCwd = resolveUserPath(requestedCwdValue ?? process.cwd());
|
|
11080
|
-
const
|
|
11081
|
-
const allowedCwds = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(parseAllowedCwdList(stringValue3(values, "allowed-cwd"))) : requestedCwdValue === undefined ?
|
|
11287
|
+
const configuredAllowedCwds2 = requestedCwdValue === undefined && !values.has("allowed-cwd") ? readConfiguredAllowedCwdDetails() : { allowedCwds: [], missingAllowedCwds: [] };
|
|
11288
|
+
const allowedCwds = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(parseAllowedCwdList(stringValue3(values, "allowed-cwd"))) : requestedCwdValue === undefined ? configuredAllowedCwds2.allowedCwds.length > 0 ? [...configuredAllowedCwds2.allowedCwds] : assertConfiguredAllowedCwds([requestedCwd]) : assertConfiguredAllowedCwds([requestedCwd]);
|
|
11082
11289
|
const cwd = allowedCwds[0] ?? requestedCwd;
|
|
11083
11290
|
const codexBin = stringValue3(values, "codex-bin") ?? "codex";
|
|
11084
11291
|
const customCodeServerBin = stringValue3(values, "code-server-bin");
|
|
@@ -11105,6 +11312,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
11105
11312
|
kandanUrl,
|
|
11106
11313
|
token: tokenFile.commanderToken,
|
|
11107
11314
|
runnerId: stringValue3(values, "runner-id") ?? `agent-runner-${randomUUID3()}`,
|
|
11315
|
+
workspaceSlug: tokenFile.workspaceId,
|
|
11108
11316
|
cwd,
|
|
11109
11317
|
codexBin,
|
|
11110
11318
|
codexUrl: stringValue3(values, "codex-url"),
|
|
@@ -11112,24 +11320,14 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
11112
11320
|
fast: values.get("fast") === true,
|
|
11113
11321
|
logFile: stringValue3(values, "log-file"),
|
|
11114
11322
|
allowedCwds,
|
|
11115
|
-
|
|
11323
|
+
missingAllowedCwds: configuredAllowedCwds2.missingAllowedCwds,
|
|
11116
11324
|
allowedForwardPorts: parseAllowedPortList(stringValue3(values, "forward-port")),
|
|
11117
11325
|
codeServerBin: editorRuntime.codeServerBin,
|
|
11118
11326
|
editorRuntime: editorRuntime.runtime,
|
|
11119
11327
|
socketFactory: trustedWebSocketFactory(kandanTlsTrustFromEnv()),
|
|
11120
11328
|
dependencyStatus,
|
|
11121
|
-
|
|
11122
|
-
channelSession
|
|
11123
|
-
workspaceSlug: tokenFile.workspaceId,
|
|
11124
|
-
channelSlug,
|
|
11125
|
-
kandanThreadId: stringValue3(values, "linzumi-thread-id"),
|
|
11126
|
-
listenUser,
|
|
11127
|
-
model: stringValue3(values, "model"),
|
|
11128
|
-
reasoningEffort: stringValue3(values, "reasoning-effort"),
|
|
11129
|
-
sandbox: stringValue3(values, "sandbox"),
|
|
11130
|
-
approvalPolicy: stringValue3(values, "approval-policy"),
|
|
11131
|
-
streamFlushMs: positiveIntegerValue(values, "stream-flush-ms")
|
|
11132
|
-
}
|
|
11329
|
+
runtimeDefaults: runnerRuntimeDefaultsFromValues(values),
|
|
11330
|
+
channelSession
|
|
11133
11331
|
};
|
|
11134
11332
|
}
|
|
11135
11333
|
function readAgentTokenTextFile(path) {
|
|
@@ -11147,6 +11345,12 @@ function rejectAgentRunnerTargetingFlags(values) {
|
|
|
11147
11345
|
throw new Error(`linzumi commander uses the claimed human Commander token scope; remove ${unsupportedFlags.map((flag) => `--${flag}`).join(", ")}.`);
|
|
11148
11346
|
}
|
|
11149
11347
|
}
|
|
11348
|
+
function rejectWorkspaceCommanderThreadFlags(values, channelSlug) {
|
|
11349
|
+
if (channelSlug !== undefined || !values.has("linzumi-thread-id")) {
|
|
11350
|
+
return;
|
|
11351
|
+
}
|
|
11352
|
+
throw new Error("linzumi commander cannot bind --linzumi-thread-id because the agent token file has no channelId");
|
|
11353
|
+
}
|
|
11150
11354
|
function requiredStoredOwnerUsername(ownerUsername) {
|
|
11151
11355
|
if (ownerUsername !== undefined) {
|
|
11152
11356
|
return ownerUsername;
|
|
@@ -11203,7 +11407,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
11203
11407
|
process.exit(0);
|
|
11204
11408
|
}
|
|
11205
11409
|
if (values.get("version") === true) {
|
|
11206
|
-
process.stdout.write(`linzumi 0.0.
|
|
11410
|
+
process.stdout.write(`linzumi 0.0.40-beta
|
|
11207
11411
|
`);
|
|
11208
11412
|
process.exit(0);
|
|
11209
11413
|
}
|
|
@@ -11211,10 +11415,8 @@ async function parseRunnerArgs(args, deps = {
|
|
|
11211
11415
|
const kandanUrl = required(values, "linzumi-url");
|
|
11212
11416
|
const cwd = stringValue3(values, "cwd") ?? process.cwd();
|
|
11213
11417
|
const cwdAllowedCwds = assertConfiguredAllowedCwds([cwd]);
|
|
11214
|
-
const
|
|
11215
|
-
|
|
11216
|
-
missingCwds: []
|
|
11217
|
-
} : readConfiguredAllowedCwdState();
|
|
11418
|
+
const localConfiguredAllowedCwds = values.has("allowed-cwd") ? { allowedCwds: [], missingAllowedCwds: [] } : readConfiguredAllowedCwdDetails();
|
|
11419
|
+
const configuredAllowedCwds2 = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(parseAllowedCwdList(stringValue3(values, "allowed-cwd"))) : [...localConfiguredAllowedCwds.allowedCwds];
|
|
11218
11420
|
const codexBin = stringValue3(values, "codex-bin") ?? "codex";
|
|
11219
11421
|
const customCodeServerBin = stringValue3(values, "code-server-bin");
|
|
11220
11422
|
const explicitToken = stringValue3(values, "token");
|
|
@@ -11254,17 +11456,26 @@ async function parseRunnerArgs(args, deps = {
|
|
|
11254
11456
|
launchTui: values.get("launch-tui") === true,
|
|
11255
11457
|
fast: values.get("fast") === true,
|
|
11256
11458
|
logFile: stringValue3(values, "log-file"),
|
|
11257
|
-
allowedCwds: Array.from(new Set([...cwdAllowedCwds, ...
|
|
11258
|
-
|
|
11459
|
+
allowedCwds: Array.from(new Set([...cwdAllowedCwds, ...configuredAllowedCwds2])),
|
|
11460
|
+
missingAllowedCwds: localConfiguredAllowedCwds.missingAllowedCwds,
|
|
11259
11461
|
allowedForwardPorts: parseAllowedPortList(stringValue3(values, "forward-port")),
|
|
11260
11462
|
codeServerBin: editorRuntime.codeServerBin,
|
|
11261
11463
|
editorRuntime: editorRuntime.runtime,
|
|
11262
11464
|
socketFactory: trustedWebSocketFactory(kandanTlsTrustFromEnv()),
|
|
11263
11465
|
dependencyStatus,
|
|
11264
11466
|
workspaceSlug: channelSession?.workspaceSlug ?? singleWorkspaceScopeFromAccessToken(token),
|
|
11467
|
+
runtimeDefaults: runnerRuntimeDefaultsFromValues(values),
|
|
11265
11468
|
channelSession
|
|
11266
11469
|
};
|
|
11267
11470
|
}
|
|
11471
|
+
function runnerRuntimeDefaultsFromValues(values) {
|
|
11472
|
+
return {
|
|
11473
|
+
model: stringValue3(values, "model"),
|
|
11474
|
+
reasoningEffort: stringValue3(values, "reasoning-effort"),
|
|
11475
|
+
approvalPolicy: stringValue3(values, "approval-policy"),
|
|
11476
|
+
sandbox: stringValue3(values, "sandbox")
|
|
11477
|
+
};
|
|
11478
|
+
}
|
|
11268
11479
|
function strictFlagValues(args, definitions = flagDefinitions) {
|
|
11269
11480
|
const values = new Map;
|
|
11270
11481
|
for (let index = 0;index < args.length; index += 1) {
|
|
@@ -11359,9 +11570,9 @@ function resolveUserPath(pathValue) {
|
|
|
11359
11570
|
return homedir9();
|
|
11360
11571
|
}
|
|
11361
11572
|
if (pathValue.startsWith("~/")) {
|
|
11362
|
-
return
|
|
11573
|
+
return resolve9(homedir9(), pathValue.slice(2));
|
|
11363
11574
|
}
|
|
11364
|
-
return
|
|
11575
|
+
return resolve9(pathValue);
|
|
11365
11576
|
}
|
|
11366
11577
|
function parseChannelSession(values, token, target) {
|
|
11367
11578
|
if (target === undefined) {
|
|
@@ -11645,10 +11856,10 @@ Usage:
|
|
|
11645
11856
|
|
|
11646
11857
|
What it does:
|
|
11647
11858
|
Starts this computer as the claimed human's scoped Linzumi Commander. The command
|
|
11648
|
-
reads ~/.linzumi/agent-token.json,
|
|
11649
|
-
trusted folders from ~/.linzumi/config.json when no
|
|
11650
|
-
|
|
11651
|
-
|
|
11859
|
+
reads ~/.linzumi/agent-token.json, connects to its workspace even when no
|
|
11860
|
+
channel is assigned, reads trusted folders from ~/.linzumi/config.json when no
|
|
11861
|
+
folder is passed, and uses the token's channel scope for channel-bound startup
|
|
11862
|
+
when one is present.
|
|
11652
11863
|
|
|
11653
11864
|
Options:
|
|
11654
11865
|
--agent-token-file <path> Agent token cache, default ~/.linzumi/agent-token.json
|
package/package.json
CHANGED