@linzumi/cli 0.0.83-beta → 0.0.85-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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +1216 -516
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9822,7 +9822,11 @@ async function handleKandanChatEvent(args, state, runnerIdentity, payloadContext
9822
9822
  seq: event.seq,
9823
9823
  actor_slug: event.actorSlug ?? null,
9824
9824
  actor_user_id: event.actorUserId ?? null,
9825
- reason: "different_thread"
9825
+ reason: "different_thread",
9826
+ thread_id: event.threadId ?? null,
9827
+ bound_thread_id: state.kandanThreadId ?? null,
9828
+ codex_thread_id: state.codexThreadId ?? null,
9829
+ body_preview: runnerConsoleBodyPreview(event.body)
9826
9830
  });
9827
9831
  return;
9828
9832
  }
@@ -11564,6 +11568,21 @@ function createClaudeCodeSessionPipeline(host) {
11564
11568
  handleToolResult(ensureTurn(), event);
11565
11569
  return;
11566
11570
  }
11571
+ case "command_output_delta": {
11572
+ const turn = activeTurn;
11573
+ const pending = turn?.pendingTools.get(event.itemKey);
11574
+ if (turn === void 0 || pending === void 0) {
11575
+ return;
11576
+ }
11577
+ submit("item/commandExecution/outputDelta", {
11578
+ turnId: turn.turnId,
11579
+ itemId: `tool:${event.itemKey}`,
11580
+ command: claudeToolCommandLabel(pending.toolName, pending.input),
11581
+ stream: "stdout",
11582
+ delta: event.delta
11583
+ });
11584
+ return;
11585
+ }
11567
11586
  case "command_output": {
11568
11587
  const turn = ensureTurn();
11569
11588
  const item = {
@@ -11945,13 +11964,304 @@ var init_claudeCodePlanMirror = __esm({
11945
11964
  }
11946
11965
  });
11947
11966
 
11967
+ // src/claudeCodeLiveBashOutput.ts
11968
+ import {
11969
+ mkdirSync as mkdirSync2,
11970
+ rmSync,
11971
+ writeFileSync,
11972
+ promises as fsPromises
11973
+ } from "node:fs";
11974
+ import { join as join6 } from "node:path";
11975
+ import { StringDecoder } from "node:string_decoder";
11976
+ function shellSingleQuoted(value) {
11977
+ return `'${value.replaceAll("'", `'\\''`)}'`;
11978
+ }
11979
+ function claudeLiveBashWrappedCommand(command, captureFile) {
11980
+ return `__lz_live_out=${shellSingleQuoted(captureFile)}; if ! : >> "$__lz_live_out" 2>/dev/null; then __lz_live_out=/dev/null; fi; { ${command}${wrapperTail}`;
11981
+ }
11982
+ function isClaudeLiveBashWrappedCommand(command) {
11983
+ return wrapperHeadPattern.test(command) && command.endsWith(wrapperTail);
11984
+ }
11985
+ function claudeLiveBashOriginalCommand(command) {
11986
+ const head = command.match(wrapperHeadPattern)?.[0];
11987
+ if (head === void 0 || !command.endsWith(wrapperTail)) {
11988
+ return command;
11989
+ }
11990
+ return command.slice(head.length, command.length - wrapperTail.length);
11991
+ }
11992
+ function claudeLiveBashCaptureEnabled(env) {
11993
+ const value = env.LINZUMI_CLAUDE_LIVE_BASH?.trim().toLowerCase();
11994
+ return !(value === "0" || value === "false" || value === "off" || value === "no");
11995
+ }
11996
+ function createClaudeCodeLiveBashCapture(host) {
11997
+ const pollIntervalMs = host.pollIntervalMs ?? defaultPollIntervalMs;
11998
+ const maxEmittedBytes = host.maxEmittedBytesPerTool ?? defaultMaxEmittedBytesPerTool;
11999
+ const tails = /* @__PURE__ */ new Map();
12000
+ let closed = false;
12001
+ const stopTail = (toolUseId) => {
12002
+ const tail = tails.get(toolUseId);
12003
+ if (tail === void 0) {
12004
+ return;
12005
+ }
12006
+ tails.delete(toolUseId);
12007
+ if (tail.timer !== void 0) {
12008
+ clearInterval(tail.timer);
12009
+ tail.timer = void 0;
12010
+ }
12011
+ try {
12012
+ rmSync(tail.file, { force: true });
12013
+ } catch (_error) {
12014
+ }
12015
+ };
12016
+ const pollTail = async (toolUseId, tail) => {
12017
+ if (tail.reading) {
12018
+ return;
12019
+ }
12020
+ tail.reading = true;
12021
+ try {
12022
+ const stat2 = await fsPromises.stat(tail.file);
12023
+ if (stat2.size <= tail.offset) {
12024
+ return;
12025
+ }
12026
+ const length = Math.min(
12027
+ stat2.size - tail.offset,
12028
+ maxReadBytesPerPoll,
12029
+ maxEmittedBytes - tail.emittedBytes
12030
+ );
12031
+ if (length <= 0) {
12032
+ stopTail(toolUseId);
12033
+ return;
12034
+ }
12035
+ const handle = await fsPromises.open(tail.file, "r");
12036
+ try {
12037
+ const buffer = Buffer.alloc(length);
12038
+ const { bytesRead } = await handle.read(buffer, 0, length, tail.offset);
12039
+ if (bytesRead <= 0) {
12040
+ return;
12041
+ }
12042
+ tail.offset += bytesRead;
12043
+ tail.emittedBytes += bytesRead;
12044
+ const delta = tail.decoder.write(buffer.subarray(0, bytesRead));
12045
+ if (delta !== "" && tails.get(toolUseId) === tail) {
12046
+ host.onOutputDelta(toolUseId, delta);
12047
+ }
12048
+ if (tail.emittedBytes >= maxEmittedBytes) {
12049
+ host.log?.("claude_live_bash.output_budget_exhausted", {
12050
+ tool_use_id: toolUseId,
12051
+ emitted_bytes: tail.emittedBytes
12052
+ });
12053
+ stopTail(toolUseId);
12054
+ }
12055
+ } finally {
12056
+ await handle.close();
12057
+ }
12058
+ } catch (error) {
12059
+ if (tails.get(toolUseId) === tail) {
12060
+ host.log?.("claude_live_bash.tail_read_failed", {
12061
+ tool_use_id: toolUseId,
12062
+ message: error instanceof Error ? error.message : String(error)
12063
+ });
12064
+ stopTail(toolUseId);
12065
+ }
12066
+ } finally {
12067
+ tail.reading = false;
12068
+ }
12069
+ };
12070
+ const startTail = (toolUseId, file) => {
12071
+ stopTail(toolUseId);
12072
+ const tail = {
12073
+ file,
12074
+ decoder: new StringDecoder("utf8"),
12075
+ offset: 0,
12076
+ emittedBytes: 0,
12077
+ reading: false,
12078
+ timer: void 0
12079
+ };
12080
+ tails.set(toolUseId, tail);
12081
+ const timer = setInterval(() => {
12082
+ void pollTail(toolUseId, tail);
12083
+ }, pollIntervalMs);
12084
+ timer.unref?.();
12085
+ tail.timer = timer;
12086
+ };
12087
+ const wrapToolInput = (toolUseId, toolInput) => {
12088
+ if (closed) {
12089
+ return void 0;
12090
+ }
12091
+ const command = toolInput.command;
12092
+ if (typeof command !== "string" || command.trim() === "" || // Background commands are polled by the model itself (TaskOutput);
12093
+ // the foreground live stream does not apply.
12094
+ toolInput.run_in_background === true || // Defensive: never double-wrap (e.g. a model echoing a wrapped
12095
+ // command back from its own transcript).
12096
+ isClaudeLiveBashWrappedCommand(command)) {
12097
+ return void 0;
12098
+ }
12099
+ const file = join6(
12100
+ host.captureDir,
12101
+ `${toolUseId.replaceAll(/[^\w-]/g, "_")}.out`
12102
+ );
12103
+ try {
12104
+ mkdirSync2(host.captureDir, { recursive: true });
12105
+ writeFileSync(file, "");
12106
+ } catch (error) {
12107
+ host.log?.("claude_live_bash.capture_file_failed", {
12108
+ tool_use_id: toolUseId,
12109
+ message: error instanceof Error ? error.message : String(error)
12110
+ });
12111
+ return void 0;
12112
+ }
12113
+ startTail(toolUseId, file);
12114
+ return {
12115
+ ...toolInput,
12116
+ command: claudeLiveBashWrappedCommand(command, file)
12117
+ };
12118
+ };
12119
+ const preToolUseHook = async (input) => {
12120
+ const passthrough = { continue: true };
12121
+ if (typeof input !== "object" || input === null) {
12122
+ return passthrough;
12123
+ }
12124
+ const hookInput = input;
12125
+ if (hookInput.hook_event_name !== "PreToolUse" || hookInput.tool_name !== "Bash" || typeof hookInput.tool_use_id !== "string" || hookInput.tool_use_id === "" || typeof hookInput.tool_input !== "object" || hookInput.tool_input === null || // Hook-path wrapping ONLY in bypassPermissions, where every command
12126
+ // auto-allows and the rewrite cannot perturb a permission decision.
12127
+ // In ask-capable modes, PreToolUse updatedInput propagates into rule
12128
+ // matching and sandbox auto-allow analysis (verified empirically
12129
+ // 2026-06-12: a sandbox-auto-allowed `false` started prompting once
12130
+ // wrapped), so those modes wrap at canUseTool-allow time instead
12131
+ // (wrapApprovedTool below) - the command was already being asked, so
12132
+ // wrapping there adds zero prompts.
12133
+ hookInput.permission_mode !== "bypassPermissions") {
12134
+ return passthrough;
12135
+ }
12136
+ const updatedInput = wrapToolInput(
12137
+ hookInput.tool_use_id,
12138
+ hookInput.tool_input
12139
+ );
12140
+ if (updatedInput === void 0) {
12141
+ return passthrough;
12142
+ }
12143
+ return {
12144
+ continue: true,
12145
+ hookSpecificOutput: {
12146
+ hookEventName: "PreToolUse",
12147
+ updatedInput
12148
+ }
12149
+ };
12150
+ };
12151
+ return {
12152
+ hookMatchers: [{ matcher: "Bash", hooks: [preToolUseHook] }],
12153
+ wrapApprovedTool: wrapToolInput,
12154
+ settleTool: stopTail,
12155
+ settleAll: () => {
12156
+ for (const toolUseId of [...tails.keys()]) {
12157
+ stopTail(toolUseId);
12158
+ }
12159
+ },
12160
+ close: () => {
12161
+ closed = true;
12162
+ for (const toolUseId of [...tails.keys()]) {
12163
+ stopTail(toolUseId);
12164
+ }
12165
+ try {
12166
+ rmSync(host.captureDir, { recursive: true, force: true });
12167
+ } catch (_error) {
12168
+ }
12169
+ }
12170
+ };
12171
+ }
12172
+ var wrapperHeadPattern, wrapperTail, defaultPollIntervalMs, defaultMaxEmittedBytesPerTool, maxReadBytesPerPoll;
12173
+ var init_claudeCodeLiveBashOutput = __esm({
12174
+ "src/claudeCodeLiveBashOutput.ts"() {
12175
+ "use strict";
12176
+ wrapperHeadPattern = /^__lz_live_out='(?:[^']|'\\'')*'; if ! : >> "\$__lz_live_out" 2>\/dev\/null; then __lz_live_out=\/dev\/null; fi; \{ /;
12177
+ wrapperTail = '\n} > >(tee -a -- "$__lz_live_out") 2> >(tee -a -- "$__lz_live_out" >&2)';
12178
+ defaultPollIntervalMs = 200;
12179
+ defaultMaxEmittedBytesPerTool = 262144;
12180
+ maxReadBytesPerPoll = 65536;
12181
+ }
12182
+ });
12183
+
11948
12184
  // src/claudeCodeSession.ts
11949
12185
  import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
11950
12186
  import { homedir as homedir5 } from "node:os";
11951
- import { join as join6 } from "node:path";
12187
+ import { join as join7 } from "node:path";
11952
12188
  function claudeCodeSettingSources() {
11953
12189
  return ["user", "project", "local"];
11954
12190
  }
12191
+ function claudeCodeTokenUsageSummaryText(usage) {
12192
+ const cached = usage.cacheReadInputTokens === void 0 && usage.cacheCreationInputTokens === void 0 ? void 0 : (usage.cacheReadInputTokens ?? 0) + (usage.cacheCreationInputTokens ?? 0);
12193
+ const parts = [
12194
+ usage.inputTokens === void 0 ? void 0 : `${usage.inputTokens} in`,
12195
+ usage.outputTokens === void 0 ? void 0 : `${usage.outputTokens} out`,
12196
+ cached === void 0 ? void 0 : `${cached} cached`,
12197
+ usage.totalCostUsd === void 0 ? void 0 : `$${usage.totalCostUsd.toFixed(4)}`
12198
+ ].filter((part) => part !== void 0);
12199
+ return parts.length === 0 ? void 0 : parts.join(" / ");
12200
+ }
12201
+ function createClaudeCodeStreamUsageTracker() {
12202
+ const completed = {
12203
+ inputTokens: 0,
12204
+ outputTokens: 0,
12205
+ cacheCreationInputTokens: 0,
12206
+ cacheReadInputTokens: 0
12207
+ };
12208
+ let current;
12209
+ let lastEmittedKey;
12210
+ const totalsFromUsage = (usage, previous) => ({
12211
+ inputTokens: integerValue(usage.input_tokens) ?? previous?.inputTokens ?? 0,
12212
+ outputTokens: integerValue(usage.output_tokens) ?? previous?.outputTokens ?? 0,
12213
+ cacheCreationInputTokens: integerValue(usage.cache_creation_input_tokens) ?? previous?.cacheCreationInputTokens ?? 0,
12214
+ cacheReadInputTokens: integerValue(usage.cache_read_input_tokens) ?? previous?.cacheReadInputTokens ?? 0
12215
+ });
12216
+ const snapshotIfChanged = () => {
12217
+ const inputTokens = completed.inputTokens + (current?.inputTokens ?? 0);
12218
+ const outputTokens = completed.outputTokens + (current?.outputTokens ?? 0);
12219
+ const cacheCreationInputTokens = completed.cacheCreationInputTokens + (current?.cacheCreationInputTokens ?? 0);
12220
+ const cacheReadInputTokens = completed.cacheReadInputTokens + (current?.cacheReadInputTokens ?? 0);
12221
+ const key = `${inputTokens}:${outputTokens}:${cacheCreationInputTokens}:${cacheReadInputTokens}`;
12222
+ if (key === lastEmittedKey) {
12223
+ return void 0;
12224
+ }
12225
+ lastEmittedKey = key;
12226
+ return {
12227
+ inputTokens,
12228
+ outputTokens,
12229
+ cacheCreationInputTokens,
12230
+ cacheReadInputTokens,
12231
+ totalCostUsd: void 0
12232
+ };
12233
+ };
12234
+ return {
12235
+ observeStreamEvent: (event) => {
12236
+ switch (stringValue(event?.type)) {
12237
+ case "message_start": {
12238
+ const usage = objectValue(objectValue(event?.message)?.usage);
12239
+ if (usage === void 0) {
12240
+ return void 0;
12241
+ }
12242
+ if (current !== void 0) {
12243
+ completed.inputTokens += current.inputTokens;
12244
+ completed.outputTokens += current.outputTokens;
12245
+ completed.cacheCreationInputTokens += current.cacheCreationInputTokens;
12246
+ completed.cacheReadInputTokens += current.cacheReadInputTokens;
12247
+ }
12248
+ current = totalsFromUsage(usage, void 0);
12249
+ return snapshotIfChanged();
12250
+ }
12251
+ case "message_delta": {
12252
+ const usage = objectValue(event?.usage);
12253
+ if (usage === void 0) {
12254
+ return void 0;
12255
+ }
12256
+ current = totalsFromUsage(usage, current);
12257
+ return snapshotIfChanged();
12258
+ }
12259
+ default:
12260
+ return void 0;
12261
+ }
12262
+ }
12263
+ };
12264
+ }
11955
12265
  function parseClaudeCodeRateLimitInfo(info) {
11956
12266
  if (info === void 0) {
11957
12267
  return void 0;
@@ -12051,7 +12361,7 @@ async function probeClaudeCodeAvailability(args) {
12051
12361
  }
12052
12362
  }
12053
12363
  function hasClaudeCodeAuthHint(env, deps) {
12054
- const configDir = env.CLAUDE_CONFIG_DIR ?? join6(deps.homeDir, ".claude");
12364
+ const configDir = env.CLAUDE_CONFIG_DIR ?? join7(deps.homeDir, ".claude");
12055
12365
  return hasAnthropicCredentialEnv(env) || hasClaudeCloudProviderEnv(env) || hasClaudeCodeFileCredential(configDir, deps) || hasClaudeCodeApiKeyHelper(configDir, deps) || hasMacClaudeCodeKeychainAnchor(deps);
12056
12366
  }
12057
12367
  function claudeCodePolicyDeferHooks() {
@@ -12086,14 +12396,14 @@ function hasClaudeCloudProviderEnv(env) {
12086
12396
  return trueishEnv(env.CLAUDE_CODE_USE_BEDROCK) || trueishEnv(env.CLAUDE_CODE_USE_VERTEX) || trueishEnv(env.CLAUDE_CODE_USE_FOUNDRY) || trueishEnv(env.CLAUDE_CODE_USE_ANTHROPIC_AWS) || trueishEnv(env.CLAUDE_CODE_USE_MANTLE);
12087
12397
  }
12088
12398
  function hasClaudeCodeFileCredential(configDir, deps) {
12089
- return deps.fileExists(join6(configDir, ".credentials.json")) || deps.fileExists(join6(configDir, ".claude.json")) || deps.fileExists(join6(deps.homeDir, ".claude.json"));
12399
+ return deps.fileExists(join7(configDir, ".credentials.json")) || deps.fileExists(join7(configDir, ".claude.json")) || deps.fileExists(join7(deps.homeDir, ".claude.json"));
12090
12400
  }
12091
12401
  function hasClaudeCodeApiKeyHelper(configDir, deps) {
12092
12402
  return [
12093
- join6(configDir, "settings.json"),
12094
- join6(configDir, "settings.local.json"),
12095
- join6(deps.cwd, ".claude", "settings.json"),
12096
- join6(deps.cwd, ".claude", "settings.local.json")
12403
+ join7(configDir, "settings.json"),
12404
+ join7(configDir, "settings.local.json"),
12405
+ join7(deps.cwd, ".claude", "settings.json"),
12406
+ join7(deps.cwd, ".claude", "settings.local.json")
12097
12407
  ].some((path2) => settingsFileHasApiKeyHelper(path2, deps));
12098
12408
  }
12099
12409
  function settingsFileHasApiKeyHelper(path2, deps) {
@@ -12113,9 +12423,9 @@ function hasMacClaudeCodeKeychainAnchor(deps) {
12113
12423
  return false;
12114
12424
  }
12115
12425
  return [
12116
- join6(deps.homeDir, "Library", "Application Support", "claude-cli-nodejs"),
12117
- join6(deps.homeDir, "Library", "Application Support", "Claude"),
12118
- join6(deps.homeDir, "Library", "Preferences", "claude-cli-nodejs")
12426
+ join7(deps.homeDir, "Library", "Application Support", "claude-cli-nodejs"),
12427
+ join7(deps.homeDir, "Library", "Application Support", "Claude"),
12428
+ join7(deps.homeDir, "Library", "Preferences", "claude-cli-nodejs")
12119
12429
  ].some((path2) => deps.fileExists(path2));
12120
12430
  }
12121
12431
  function readTextFileIfPresent(path2) {
@@ -12134,82 +12444,83 @@ async function startClaudeCodeSession(options) {
12134
12444
  assistantTextByKey: /* @__PURE__ */ new Map(),
12135
12445
  usage: void 0,
12136
12446
  startedSessionIds: /* @__PURE__ */ new Set(),
12137
- completedTurnCount: 0
12447
+ completedTurnCount: 0,
12448
+ lastCompletedTurnBody: void 0
12138
12449
  };
12139
- for await (const message of runner(options)) {
12140
- state.sessionId = state.sessionId ?? extractClaudeSessionId(message);
12141
- const sessionId = extractClaudeSessionId(message) ?? state.sessionId;
12142
- if (sessionId !== void 0 && !state.startedSessionIds.has(sessionId)) {
12143
- state.startedSessionIds.add(sessionId);
12144
- await options.onTranscriptEvent?.({ type: "session_started", sessionId });
12145
- }
12146
- for (const event of transcriptEventsForClaudeMessage(message, sessionId)) {
12147
- if (event.type === "assistant_message") {
12148
- recordClaudeAssistantAggregate(state, event);
12149
- }
12150
- if (event.type === "usage") {
12151
- state.usage = event.usage;
12152
- }
12153
- await options.onTranscriptEvent?.(event);
12154
- }
12155
- const resultOutcome = extractClaudeResultOutcome(message);
12156
- switch (resultOutcome.type) {
12157
- case "success": {
12158
- if (resultOutcome.text !== void 0) {
12159
- state.resultText = resultOutcome.text;
12160
- }
12161
- state.usage = extractClaudeUsage(message) ?? state.usage;
12162
- state.completedTurnCount += 1;
12163
- const queuedTurnCountBeforeTranscript = options.streamingInput === void 0 ? void 0 : options.streamingInput.queuedTurnCount();
12164
- if (options.streamingInput !== void 0) {
12165
- await emitClaudeCodeTurnCompleted(options, state);
12166
- }
12167
- if (options.streamingInput !== void 0 && queuedTurnCountBeforeTranscript !== void 0 && state.completedTurnCount >= Math.max(
12168
- queuedTurnCountBeforeTranscript,
12169
- options.streamingInput.queuedTurnCount()
12170
- )) {
12171
- options.streamingInput.close();
12172
- return completeClaudeCodeSession(options, state);
12173
- }
12174
- if (options.streamingInput !== void 0) {
12175
- await options.onTurnCompleted?.();
12176
- resetClaudeAssistantAggregate(state);
12177
- state.resultText = void 0;
12450
+ const streamUsageTracker = createClaudeCodeStreamUsageTracker();
12451
+ try {
12452
+ for await (const message of runner(options)) {
12453
+ state.sessionId = state.sessionId ?? extractClaudeSessionId(message);
12454
+ const sessionId = extractClaudeSessionId(message) ?? state.sessionId;
12455
+ if (sessionId !== void 0 && !state.startedSessionIds.has(sessionId)) {
12456
+ state.startedSessionIds.add(sessionId);
12457
+ await options.onTranscriptEvent?.({
12458
+ type: "session_started",
12459
+ sessionId
12460
+ });
12461
+ }
12462
+ for (const event of transcriptEventsForClaudeMessage(
12463
+ message,
12464
+ sessionId,
12465
+ streamUsageTracker
12466
+ )) {
12467
+ if (event.type === "assistant_message") {
12468
+ recordClaudeAssistantAggregate(state, event);
12178
12469
  }
12179
- break;
12470
+ if (event.type === "usage") {
12471
+ state.usage = event.usage;
12472
+ }
12473
+ await options.onTranscriptEvent?.(event);
12180
12474
  }
12181
- case "interrupted": {
12182
- state.completedTurnCount += 1;
12183
- if (state.sessionId !== void 0) {
12184
- await options.onTranscriptEvent?.({
12185
- type: "turn_interrupted",
12186
- sessionId: state.sessionId
12187
- });
12475
+ const resultOutcome = extractClaudeResultOutcome(message);
12476
+ switch (resultOutcome.type) {
12477
+ case "success": {
12478
+ if (resultOutcome.text !== void 0) {
12479
+ state.resultText = resultOutcome.text;
12480
+ }
12481
+ state.usage = extractClaudeUsage(message) ?? state.usage;
12482
+ state.completedTurnCount += 1;
12483
+ if (options.streamingInput !== void 0) {
12484
+ await emitClaudeCodeTurnCompleted(options, state);
12485
+ state.lastCompletedTurnBody = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state)) ?? "";
12486
+ await options.onTurnCompleted?.();
12487
+ resetClaudeAssistantAggregate(state);
12488
+ state.resultText = void 0;
12489
+ }
12490
+ break;
12188
12491
  }
12189
- if (options.streamingInput !== void 0) {
12190
- await options.onTurnCompleted?.();
12191
- resetClaudeAssistantAggregate(state);
12192
- state.resultText = void 0;
12492
+ case "interrupted": {
12493
+ state.completedTurnCount += 1;
12494
+ if (state.sessionId !== void 0) {
12495
+ await options.onTranscriptEvent?.({
12496
+ type: "turn_interrupted",
12497
+ sessionId: state.sessionId
12498
+ });
12499
+ }
12500
+ if (options.streamingInput !== void 0) {
12501
+ await options.onTurnCompleted?.();
12502
+ resetClaudeAssistantAggregate(state);
12503
+ state.resultText = void 0;
12504
+ }
12505
+ break;
12193
12506
  }
12194
- break;
12507
+ case "error":
12508
+ return await failClaudeCodeSession(
12509
+ options,
12510
+ state.sessionId,
12511
+ `Claude Code failed: ${resultOutcome.reason}`
12512
+ );
12513
+ case "none":
12514
+ break;
12195
12515
  }
12196
- case "error":
12197
- return await failClaudeCodeSession(
12198
- options,
12199
- state.sessionId,
12200
- `Claude Code failed: ${resultOutcome.reason}`
12201
- );
12202
- case "none":
12203
- break;
12204
12516
  }
12517
+ } finally {
12518
+ options.streamingInput?.close();
12205
12519
  }
12206
12520
  return completeClaudeCodeSession(options, state);
12207
12521
  }
12208
12522
  async function emitClaudeCodeTurnCompleted(options, state) {
12209
- const body = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state));
12210
- if (body === void 0) {
12211
- return;
12212
- }
12523
+ const body = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state)) ?? "";
12213
12524
  if (state.sessionId === void 0) {
12214
12525
  return;
12215
12526
  }
@@ -12221,7 +12532,7 @@ async function emitClaudeCodeTurnCompleted(options, state) {
12221
12532
  });
12222
12533
  }
12223
12534
  async function completeClaudeCodeSession(options, state) {
12224
- const body = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state));
12535
+ const body = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state)) ?? state.lastCompletedTurnBody;
12225
12536
  if (body === void 0) {
12226
12537
  return await failClaudeCodeSession(
12227
12538
  options,
@@ -12314,6 +12625,11 @@ async function failClaudeCodeSession(options, sessionId, reason) {
12314
12625
  async function* defaultClaudeCodeRunner(options) {
12315
12626
  const sdk = await import("@anthropic-ai/claude-agent-sdk");
12316
12627
  const prompt = options.streamingInput?.messages ?? options.prompt;
12628
+ const preToolUseMatchers = [
12629
+ ...options.preToolUseHookMatchers ?? [],
12630
+ ...options.canUseTool === void 0 ? claudeCodePolicyDeferHooks().PreToolUse ?? [] : []
12631
+ ];
12632
+ const hooks = preToolUseMatchers.length === 0 ? void 0 : { PreToolUse: preToolUseMatchers };
12317
12633
  const query = sdk.query({
12318
12634
  prompt,
12319
12635
  options: {
@@ -12334,7 +12650,13 @@ async function* defaultClaudeCodeRunner(options) {
12334
12650
  },
12335
12651
  ...options.allowedTools === void 0 ? {} : { allowedTools: [...options.allowedTools] },
12336
12652
  ...options.env === void 0 ? {} : { env: options.env },
12337
- ...options.canUseTool === void 0 ? { hooks: claudeCodePolicyDeferHooks() } : { canUseTool: claudeCodeCanUseTool(options.canUseTool) },
12653
+ ...hooks === void 0 ? {} : { hooks },
12654
+ ...options.canUseTool === void 0 ? {} : {
12655
+ canUseTool: claudeCodeCanUseTool(
12656
+ options.canUseTool,
12657
+ options.wrapApprovedToolInput
12658
+ )
12659
+ },
12338
12660
  ...options.model === void 0 ? {} : { model: options.model }
12339
12661
  // exactOptionalPropertyTypes: the conditional spreads build a union the
12340
12662
  // SDK's Options cannot absorb verbatim; the shape is correct field-wise.
@@ -12425,7 +12747,7 @@ function boundedPositiveInteger(value, fallback, min, max) {
12425
12747
  }
12426
12748
  return value;
12427
12749
  }
12428
- function claudeCodeCanUseTool(handler) {
12750
+ function claudeCodeCanUseTool(handler, wrapApprovedToolInput) {
12429
12751
  return async (toolName2, input, options) => {
12430
12752
  const decision = await handler(
12431
12753
  {
@@ -12436,7 +12758,11 @@ function claudeCodeCanUseTool(handler) {
12436
12758
  description: options.description,
12437
12759
  decisionReason: options.decisionReason,
12438
12760
  blockedPath: options.blockedPath,
12439
- input
12761
+ // Approval prompts render the human-facing command: when the live
12762
+ // Bash output capture wrapped it (PreToolUse updatedInput), show
12763
+ // the original. The SDK still receives the raw input on allow so
12764
+ // the wrapped (live-streaming) command is what executes.
12765
+ input: displayClaudeToolInput(toolName2, input)
12440
12766
  },
12441
12767
  options.signal
12442
12768
  );
@@ -12445,7 +12771,11 @@ function claudeCodeCanUseTool(handler) {
12445
12771
  return {
12446
12772
  behavior: "allow",
12447
12773
  toolUseID: options.toolUseID,
12448
- updatedInput: input
12774
+ // Live Bash output for ask-capable permission modes: the approved
12775
+ // command gains the tee wrapper HERE (it was already prompting,
12776
+ // so wrapping at this point can never add a prompt - see
12777
+ // claudeCodeLiveBashOutput).
12778
+ updatedInput: wrapApprovedToolInput?.(options.toolUseID, toolName2, input) ?? input
12449
12779
  };
12450
12780
  case "deny":
12451
12781
  return {
@@ -12456,6 +12786,17 @@ function claudeCodeCanUseTool(handler) {
12456
12786
  }
12457
12787
  };
12458
12788
  }
12789
+ function displayClaudeToolInput(toolName2, input) {
12790
+ if (toolName2 !== "Bash") {
12791
+ return input;
12792
+ }
12793
+ const command = stringValue(input.command);
12794
+ if (command === void 0) {
12795
+ return input;
12796
+ }
12797
+ const original = claudeLiveBashOriginalCommand(command);
12798
+ return original === command ? input : { ...input, command: original };
12799
+ }
12459
12800
  function extractClaudeSessionId(message) {
12460
12801
  const messageObject = objectValue(message);
12461
12802
  const directSessionId = stringValue(messageObject?.session_id) ?? stringValue(messageObject?.sessionId);
@@ -12492,11 +12833,11 @@ function extractClaudeResultErrorReason(message, subtype) {
12492
12833
  const explicitErrors = arrayValue(message.errors)?.map((error) => stringValue(error)).filter((error) => nonEmptyText(error) !== void 0).join("; ");
12493
12834
  return nonEmptyText(explicitErrors) ?? nonEmptyText(stringValue(message.result)) ?? nonEmptyText(stringValue(message.error)) ?? subtype ?? "error";
12494
12835
  }
12495
- function transcriptEventsForClaudeMessage(message, sessionId) {
12836
+ function transcriptEventsForClaudeMessage(message, sessionId, usageTracker) {
12496
12837
  const messageObject = objectValue(message);
12497
12838
  switch (stringValue(messageObject?.type)) {
12498
12839
  case "stream_event":
12499
- return streamTranscriptEvents(messageObject, sessionId);
12840
+ return streamTranscriptEvents(messageObject, sessionId, usageTracker);
12500
12841
  case "assistant":
12501
12842
  return assistantTranscriptEvents(messageObject, sessionId);
12502
12843
  case "user":
@@ -12513,11 +12854,16 @@ function transcriptEventsForClaudeMessage(message, sessionId) {
12513
12854
  return unknownTranscriptEvent(messageObject, sessionId);
12514
12855
  }
12515
12856
  }
12516
- function streamTranscriptEvents(message, sessionId) {
12857
+ function streamTranscriptEvents(message, sessionId, usageTracker) {
12517
12858
  if (sessionId === void 0) {
12518
12859
  return [];
12519
12860
  }
12520
12861
  const event = objectValue(message?.event);
12862
+ const runningUsage = usageTracker?.observeStreamEvent(event);
12863
+ const usageEvents = runningUsage === void 0 ? [] : [{ type: "usage", sessionId, usage: runningUsage }];
12864
+ return [...usageEvents, ...streamContentEvents(event, message, sessionId)];
12865
+ }
12866
+ function streamContentEvents(event, message, sessionId) {
12521
12867
  switch (stringValue(event?.type)) {
12522
12868
  case "content_block_delta": {
12523
12869
  const delta = objectValue(event?.delta);
@@ -12719,6 +13065,7 @@ var init_claudeCodeSession = __esm({
12719
13065
  "src/claudeCodeSession.ts"() {
12720
13066
  "use strict";
12721
13067
  init_json();
13068
+ init_claudeCodeLiveBashOutput();
12722
13069
  claudeRateLimitWindowLabels = {
12723
13070
  five_hour: "5h window",
12724
13071
  seven_day: "7d window",
@@ -12733,10 +13080,10 @@ var init_claudeCodeSession = __esm({
12733
13080
  import { appendFileSync, openSync as openSync2 } from "node:fs";
12734
13081
  import { createWriteStream } from "node:fs";
12735
13082
  import { homedir as homedir6 } from "node:os";
12736
- import { dirname as dirname3, join as join7 } from "node:path";
12737
- import { mkdirSync as mkdirSync2 } from "node:fs";
13083
+ import { dirname as dirname3, join as join8 } from "node:path";
13084
+ import { mkdirSync as mkdirSync3 } from "node:fs";
12738
13085
  function createRunnerLogger(logFile, consoleReporter) {
12739
- mkdirSync2(dirname3(logFile), { recursive: true });
13086
+ mkdirSync3(dirname3(logFile), { recursive: true });
12740
13087
  const fd = openSync2(logFile, "a");
12741
13088
  const stream = createWriteStream("", { fd, flags: "a", autoClose: true });
12742
13089
  const logger = ((event, payload) => {
@@ -12756,7 +13103,7 @@ function createRunnerLogger(logFile, consoleReporter) {
12756
13103
  function writeCliAuditEvent(event, payload, options = {}) {
12757
13104
  const logFile = options.logFile ?? defaultCliAuditLogFile();
12758
13105
  try {
12759
- mkdirSync2(dirname3(logFile), { recursive: true });
13106
+ mkdirSync3(dirname3(logFile), { recursive: true });
12760
13107
  appendFileSync(
12761
13108
  logFile,
12762
13109
  `${JSON.stringify({
@@ -12774,10 +13121,10 @@ function writeCliAuditEvent(event, payload, options = {}) {
12774
13121
  }
12775
13122
  function defaultCliAuditLogFile() {
12776
13123
  const override = process.env.LINZUMI_CLI_AUDIT_LOG?.trim();
12777
- return override === void 0 || override === "" ? join7(homedir6(), ".linzumi", "logs", "command-events.jsonl") : override;
13124
+ return override === void 0 || override === "" ? join8(homedir6(), ".linzumi", "logs", "command-events.jsonl") : override;
12778
13125
  }
12779
13126
  function defaultRunnerLogFile() {
12780
- return join7(homedir6(), ".linzumi", "logs", "linzumi-runner.log");
13127
+ return join8(homedir6(), ".linzumi", "logs", "linzumi-runner.log");
12781
13128
  }
12782
13129
  function redactForCliLog(value) {
12783
13130
  return redactObject(value);
@@ -13060,7 +13407,10 @@ var init_mcpConfig = __esm({
13060
13407
  import {
13061
13408
  spawn as spawn2
13062
13409
  } from "node:child_process";
13410
+ import { readFileSync as readFileSync6 } from "node:fs";
13063
13411
  import { createServer } from "node:net";
13412
+ import { homedir as homedir7 } from "node:os";
13413
+ import { join as join9 } from "node:path";
13064
13414
  import { WebSocket as NodeWebSocket } from "ws";
13065
13415
  async function chooseLoopbackPort() {
13066
13416
  return new Promise((resolve12, reject) => {
@@ -13277,10 +13627,46 @@ function codexModelProviderConfigArgs(provider) {
13277
13627
  "-c",
13278
13628
  `model_providers.${provider.id}.http_headers.${header}=${JSON.stringify(value)}`
13279
13629
  ]),
13630
+ // env_http_headers values are env var NAMES, not secrets: codex resolves
13631
+ // them from its environment per request, keeping tokens out of argv.
13632
+ ...Object.entries(provider.envHttpHeaders ?? {}).flatMap(
13633
+ ([header, envVar]) => [
13634
+ "-c",
13635
+ `model_providers.${provider.id}.env_http_headers.${header}=${JSON.stringify(envVar)}`
13636
+ ]
13637
+ ),
13280
13638
  "-c",
13281
13639
  `model_provider=${JSON.stringify(provider.id)}`
13282
13640
  ];
13283
13641
  }
13642
+ function resolveForwardableOpenAiApiKey(env = process.env) {
13643
+ const fromEnv = env.OPENAI_API_KEY?.trim();
13644
+ if (fromEnv !== void 0 && fromEnv !== "") {
13645
+ return fromEnv;
13646
+ }
13647
+ const codexHomeRaw = env.CODEX_HOME?.trim();
13648
+ const codexHome = codexHomeRaw !== void 0 && codexHomeRaw !== "" ? codexHomeRaw : join9(homedir7(), ".codex");
13649
+ let raw;
13650
+ try {
13651
+ raw = readFileSync6(join9(codexHome, "auth.json"), "utf8");
13652
+ } catch (_error) {
13653
+ return void 0;
13654
+ }
13655
+ let parsed;
13656
+ try {
13657
+ parsed = JSON.parse(raw);
13658
+ } catch (_error) {
13659
+ return void 0;
13660
+ }
13661
+ if (!isJsonObject(parsed)) {
13662
+ return void 0;
13663
+ }
13664
+ const apiKey = parsed.OPENAI_API_KEY;
13665
+ if (typeof apiKey === "string" && apiKey.trim() !== "") {
13666
+ return apiKey.trim();
13667
+ }
13668
+ return void 0;
13669
+ }
13284
13670
  async function connectCodexAppServer(websocketUrl, socketFactory = (url) => new NodeWebSocket(url)) {
13285
13671
  const websocket = await openCodexAppServerWebSocket(
13286
13672
  websocketUrl,
@@ -13604,22 +13990,22 @@ var init_codexAppServer = __esm({
13604
13990
  // src/codexProjectTrust.ts
13605
13991
  import {
13606
13992
  existsSync as existsSync5,
13607
- mkdirSync as mkdirSync3,
13608
- readFileSync as readFileSync6,
13993
+ mkdirSync as mkdirSync4,
13994
+ readFileSync as readFileSync7,
13609
13995
  realpathSync,
13610
- writeFileSync
13996
+ writeFileSync as writeFileSync2
13611
13997
  } from "node:fs";
13612
- import { homedir as homedir7 } from "node:os";
13613
- import { join as join8, resolve as resolve3 } from "node:path";
13998
+ import { homedir as homedir8 } from "node:os";
13999
+ import { join as join10, resolve as resolve3 } from "node:path";
13614
14000
  function ensureCodexProjectTrusted(projectPath, options = {}) {
13615
14001
  const trustedPath = realpathSync(resolve3(projectPath));
13616
- const configHome = options.configHome ?? process.env.CODEX_HOME ?? join8(homedir7(), ".codex");
13617
- const configPath = join8(configHome, "config.toml");
13618
- const currentConfig = existsSync5(configPath) ? readFileSync6(configPath, "utf8") : "";
14002
+ const configHome = options.configHome ?? process.env.CODEX_HOME ?? join10(homedir8(), ".codex");
14003
+ const configPath = join10(configHome, "config.toml");
14004
+ const currentConfig = existsSync5(configPath) ? readFileSync7(configPath, "utf8") : "";
13619
14005
  const nextConfig = codexConfigWithTrustedProject(currentConfig, trustedPath);
13620
14006
  if (nextConfig !== currentConfig) {
13621
- mkdirSync3(configHome, { recursive: true });
13622
- writeFileSync(configPath, nextConfig);
14007
+ mkdirSync4(configHome, { recursive: true });
14008
+ writeFileSync2(configPath, nextConfig);
13623
14009
  }
13624
14010
  return trustedPath;
13625
14011
  }
@@ -13964,7 +14350,7 @@ var init_codexNotificationConsoleStats = __esm({
13964
14350
 
13965
14351
  // src/localCapabilities.ts
13966
14352
  import { realpathSync as realpathSync2 } from "node:fs";
13967
- import { homedir as homedir8 } from "node:os";
14353
+ import { homedir as homedir9 } from "node:os";
13968
14354
  import { isAbsolute as isAbsolute3, relative as relative2, resolve as resolve4 } from "node:path";
13969
14355
  function parseAllowedCwdList(value) {
13970
14356
  if (value === void 0) {
@@ -14013,7 +14399,7 @@ function expandUserPath(pathValue) {
14013
14399
  }
14014
14400
  function currentHomeDirectory() {
14015
14401
  const configuredHome = process.env.HOME;
14016
- return configuredHome === void 0 || configuredHome.trim() === "" ? homedir8() : configuredHome;
14402
+ return configuredHome === void 0 || configuredHome.trim() === "" ? homedir9() : configuredHome;
14017
14403
  }
14018
14404
  function resolveAllowedCwd(requestedCwd, allowedRoots) {
14019
14405
  if (requestedCwd === void 0 || requestedCwd.trim() === "") {
@@ -14413,17 +14799,17 @@ import {
14413
14799
  chmodSync,
14414
14800
  existsSync as existsSync6,
14415
14801
  linkSync,
14416
- mkdirSync as mkdirSync4,
14417
- readFileSync as readFileSync7,
14802
+ mkdirSync as mkdirSync5,
14803
+ readFileSync as readFileSync8,
14418
14804
  realpathSync as realpathSync3,
14419
14805
  unlinkSync,
14420
- writeFileSync as writeFileSync2
14806
+ writeFileSync as writeFileSync3
14421
14807
  } from "node:fs";
14422
- import { homedir as homedir9 } from "node:os";
14423
- import { basename as basename5, dirname as dirname4, join as join9, resolve as resolve5 } from "node:path";
14808
+ import { homedir as homedir10 } from "node:os";
14809
+ import { basename as basename5, dirname as dirname4, join as join11, resolve as resolve5 } from "node:path";
14424
14810
  function localConfigPath(env = process.env) {
14425
14811
  const override = env.LINZUMI_CONFIG_FILE;
14426
- return override !== void 0 && override.trim() !== "" ? resolve5(expandUserPath(override)) : resolve5(homedir9(), ".linzumi", "config.json");
14812
+ return override !== void 0 && override.trim() !== "" ? resolve5(expandUserPath(override)) : resolve5(homedir10(), ".linzumi", "config.json");
14427
14813
  }
14428
14814
  function localConfigScopeKey(linzumiUrl) {
14429
14815
  const normalizedUrl = kandanHttpBaseUrl(linzumiUrl);
@@ -14504,21 +14890,21 @@ function ensureLocalRunnerId(path2 = localConfigPath(), createRunnerId = default
14504
14890
  }
14505
14891
  function localMachineIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
14506
14892
  if (linzumiUrl !== void 0 && localConfigScopeKey(linzumiUrl) !== prodConfigScope) {
14507
- return join9(
14893
+ return join11(
14508
14894
  dirname4(configPath),
14509
14895
  `${basename5(configPath)}.${localConfigScopeFileStem(linzumiUrl)}.machine-id`
14510
14896
  );
14511
14897
  }
14512
- return join9(dirname4(configPath), `${basename5(configPath)}.machine-id`);
14898
+ return join11(dirname4(configPath), `${basename5(configPath)}.machine-id`);
14513
14899
  }
14514
14900
  function localRunnerIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
14515
14901
  if (linzumiUrl !== void 0 && localConfigScopeKey(linzumiUrl) !== prodConfigScope) {
14516
- return join9(
14902
+ return join11(
14517
14903
  dirname4(configPath),
14518
14904
  `${basename5(configPath)}.${localConfigScopeFileStem(linzumiUrl)}.runner-id`
14519
14905
  );
14520
14906
  }
14521
- return join9(dirname4(configPath), `${basename5(configPath)}.runner-id`);
14907
+ return join11(dirname4(configPath), `${basename5(configPath)}.runner-id`);
14522
14908
  }
14523
14909
  function readConfiguredAllowedCwdDetailsForLinzumiUrl(linzumiUrl, path2 = localConfigPath()) {
14524
14910
  return readConfiguredAllowedCwdDetailsFromConfig(
@@ -14648,7 +15034,7 @@ function writeLocalSignupAuth(auth, path2 = localConfigPath()) {
14648
15034
  version: 1,
14649
15035
  signupAuth: nextSignupAuth
14650
15036
  };
14651
- mkdirSync4(dirname4(path2), { recursive: true });
15037
+ mkdirSync5(dirname4(path2), { recursive: true });
14652
15038
  writeLocalConfigJson(path2, next);
14653
15039
  return signupAuthFromJson(nextSignupAuth);
14654
15040
  }
@@ -14656,7 +15042,7 @@ function writeLocalConfigJson(path2, payload) {
14656
15042
  if (existsSync6(path2)) {
14657
15043
  chmodSync(path2, localConfigFileMode);
14658
15044
  }
14659
- writeFileSync2(path2, `${JSON.stringify(payload, null, 2)}
15045
+ writeFileSync3(path2, `${JSON.stringify(payload, null, 2)}
14660
15046
  `, {
14661
15047
  encoding: "utf8",
14662
15048
  mode: localConfigFileMode
@@ -14683,7 +15069,7 @@ function readLocalConfigFile(path2) {
14683
15069
  if (!existsSync6(path2)) {
14684
15070
  return { version: 1, allowedCwds: [] };
14685
15071
  }
14686
- const parsed = JSON.parse(readFileSync7(path2, "utf8"));
15072
+ const parsed = JSON.parse(readFileSync8(path2, "utf8"));
14687
15073
  if (!isConfigPayload(parsed)) {
14688
15074
  throw new Error(`invalid Linzumi config: ${path2}`);
14689
15075
  }
@@ -14712,7 +15098,7 @@ function writeLocalConfigSection(config, path2, linzumiUrl) {
14712
15098
  version: 1,
14713
15099
  [scopeKey]: nextSection
14714
15100
  };
14715
- mkdirSync4(dirname4(path2), { recursive: true });
15101
+ mkdirSync5(dirname4(path2), { recursive: true });
14716
15102
  writeLocalConfigJson(path2, next);
14717
15103
  }
14718
15104
  function isConfigPayload(value) {
@@ -14787,12 +15173,12 @@ function ensureLocalMachineIdSeed(configPath, createMachineId, linzumiUrl) {
14787
15173
  if (!machineIdValid(machineId)) {
14788
15174
  throw new Error(`invalid generated Linzumi machine id: ${machineId}`);
14789
15175
  }
14790
- mkdirSync4(dirname4(seedPath), { recursive: true });
14791
- const tempPath = join9(
15176
+ mkdirSync5(dirname4(seedPath), { recursive: true });
15177
+ const tempPath = join11(
14792
15178
  dirname4(seedPath),
14793
15179
  `.${basename5(seedPath)}.${process.pid}.${randomUUID2()}.tmp`
14794
15180
  );
14795
- writeFileSync2(tempPath, `${machineId}
15181
+ writeFileSync3(tempPath, `${machineId}
14796
15182
  `, { encoding: "utf8", flag: "wx" });
14797
15183
  try {
14798
15184
  linkSync(tempPath, seedPath);
@@ -14815,12 +15201,12 @@ function ensureLocalRunnerIdSeed(configPath, createRunnerId, linzumiUrl) {
14815
15201
  if (!runnerIdValid(runnerId)) {
14816
15202
  throw new Error(`invalid generated Linzumi runner id: ${runnerId}`);
14817
15203
  }
14818
- mkdirSync4(dirname4(seedPath), { recursive: true });
14819
- const tempPath = join9(
15204
+ mkdirSync5(dirname4(seedPath), { recursive: true });
15205
+ const tempPath = join11(
14820
15206
  dirname4(seedPath),
14821
15207
  `.${basename5(seedPath)}.${process.pid}.${randomUUID2()}.tmp`
14822
15208
  );
14823
- writeFileSync2(tempPath, `${runnerId}
15209
+ writeFileSync3(tempPath, `${runnerId}
14824
15210
  `, { encoding: "utf8", flag: "wx" });
14825
15211
  try {
14826
15212
  linkSync(tempPath, seedPath);
@@ -14835,14 +15221,14 @@ function ensureLocalRunnerIdSeed(configPath, createRunnerId, linzumiUrl) {
14835
15221
  }
14836
15222
  }
14837
15223
  function readMachineIdSeed(seedPath) {
14838
- const machineId = readFileSync7(seedPath, "utf8").trim();
15224
+ const machineId = readFileSync8(seedPath, "utf8").trim();
14839
15225
  if (!machineIdValid(machineId)) {
14840
15226
  throw new Error(`invalid Linzumi machine id seed: ${seedPath}`);
14841
15227
  }
14842
15228
  return machineId;
14843
15229
  }
14844
15230
  function readRunnerIdSeed(seedPath) {
14845
- const runnerId = readFileSync7(seedPath, "utf8").trim();
15231
+ const runnerId = readFileSync8(seedPath, "utf8").trim();
14846
15232
  if (!runnerIdValid(runnerId)) {
14847
15233
  throw new Error(`invalid Linzumi runner id seed: ${seedPath}`);
14848
15234
  }
@@ -15141,8 +15527,8 @@ var init_remoteCodexExecutionContext = __esm({
15141
15527
  });
15142
15528
 
15143
15529
  // src/helloLinzumiProject.ts
15144
- import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync8, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
15145
- import { dirname as dirname5, join as join10, resolve as resolve6 } from "node:path";
15530
+ import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync9, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
15531
+ import { dirname as dirname5, join as join12, resolve as resolve6 } from "node:path";
15146
15532
  import { fileURLToPath as fileURLToPath2 } from "node:url";
15147
15533
  function createHelloLinzumiProject(input = {}) {
15148
15534
  const options = typeof input === "string" ? { rootPath: input } : input;
@@ -15151,9 +15537,9 @@ function createHelloLinzumiProject(input = {}) {
15151
15537
  const host = normalizeHost(options.host);
15152
15538
  assertTcpPort(port);
15153
15539
  assertWritableDemoRoot(root, options.reset === true);
15154
- mkdirSync5(join10(root, "src"), { recursive: true });
15540
+ mkdirSync6(join12(root, "src"), { recursive: true });
15155
15541
  for (const file of demoFiles({ root, port, host })) {
15156
- writeFileSync3(join10(root, file.path), file.content, "utf8");
15542
+ writeFileSync4(join12(root, file.path), file.content, "utf8");
15157
15543
  }
15158
15544
  return {
15159
15545
  root,
@@ -15197,10 +15583,10 @@ function assertWritableDemoRoot(root, reset) {
15197
15583
  if (!existsSync7(root)) {
15198
15584
  return;
15199
15585
  }
15200
- const markerPath = join10(root, markerFile);
15201
- const isDemoRoot = existsSync7(markerPath) && readFileSync8(markerPath, "utf8").trim() === "hello-linzumi";
15586
+ const markerPath = join12(root, markerFile);
15587
+ const isDemoRoot = existsSync7(markerPath) && readFileSync9(markerPath, "utf8").trim() === "hello-linzumi";
15202
15588
  if (isDemoRoot && reset) {
15203
- rmSync(root, { recursive: true, force: true });
15589
+ rmSync2(root, { recursive: true, force: true });
15204
15590
  return;
15205
15591
  }
15206
15592
  if (isDemoRoot) {
@@ -15233,7 +15619,7 @@ var init_helloLinzumiProject = __esm({
15233
15619
  defaultHelloLinzumiHost = "0.0.0.0";
15234
15620
  markerFile = ".linzumi-demo-project";
15235
15621
  moduleDir = dirname5(fileURLToPath2(import.meta.url));
15236
- linzumiLogoSvg = readFileSync8(join10(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
15622
+ linzumiLogoSvg = readFileSync9(join12(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
15237
15623
  packageJson = `${JSON.stringify(
15238
15624
  {
15239
15625
  name: "hello-linzumi",
@@ -16035,14 +16421,14 @@ import {
16035
16421
  copyFileSync,
16036
16422
  cpSync,
16037
16423
  existsSync as existsSync8,
16038
- mkdirSync as mkdirSync6,
16424
+ mkdirSync as mkdirSync7,
16039
16425
  mkdtempSync,
16040
- readFileSync as readFileSync9,
16426
+ readFileSync as readFileSync10,
16041
16427
  realpathSync as realpathSync4,
16042
- writeFileSync as writeFileSync4
16428
+ writeFileSync as writeFileSync5
16043
16429
  } from "node:fs";
16044
16430
  import { tmpdir } from "node:os";
16045
- import { basename as basename6, delimiter, dirname as dirname6, join as join11 } from "node:path";
16431
+ import { basename as basename6, delimiter, dirname as dirname6, join as join13 } from "node:path";
16046
16432
  function isStartLocalEditorControl(control) {
16047
16433
  return control.type === "start_local_editor";
16048
16434
  }
@@ -16260,24 +16646,24 @@ function codeServerArgs(port, cwd, userDataDir, extensionsDir) {
16260
16646
  }
16261
16647
  function prepareCodeServerProfile(collaboration, editorRuntime) {
16262
16648
  try {
16263
- const userDataDir = mkdtempSync(join11(tmpdir(), "kandan-local-editor-"));
16264
- const extensionsDir = join11(userDataDir, "extensions");
16265
- const collaborationServerDir = join11(userDataDir, "collaboration-server");
16266
- const tempDir = join11(userDataDir, "tmp");
16267
- const userSettingsDir = join11(userDataDir, "User");
16268
- mkdirSync6(userSettingsDir, { recursive: true });
16269
- mkdirSync6(extensionsDir, { recursive: true });
16270
- mkdirSync6(collaborationServerDir, { recursive: true });
16271
- mkdirSync6(tempDir, { recursive: true });
16649
+ const userDataDir = mkdtempSync(join13(tmpdir(), "kandan-local-editor-"));
16650
+ const extensionsDir = join13(userDataDir, "extensions");
16651
+ const collaborationServerDir = join13(userDataDir, "collaboration-server");
16652
+ const tempDir = join13(userDataDir, "tmp");
16653
+ const userSettingsDir = join13(userDataDir, "User");
16654
+ mkdirSync7(userSettingsDir, { recursive: true });
16655
+ mkdirSync7(extensionsDir, { recursive: true });
16656
+ mkdirSync7(collaborationServerDir, { recursive: true });
16657
+ mkdirSync7(tempDir, { recursive: true });
16272
16658
  if (editorRuntime !== void 0) {
16273
16659
  ensureCodeServerBrowserExtensionAssets(editorRuntime);
16274
16660
  installDirectory(
16275
16661
  editorRuntime.assets.documentStateExtensionDir,
16276
- join11(extensionsDir, "kandan.document-state-telemetry")
16662
+ join13(extensionsDir, "kandan.document-state-telemetry")
16277
16663
  );
16278
16664
  }
16279
- writeFileSync4(
16280
- join11(userSettingsDir, "settings.json"),
16665
+ writeFileSync5(
16666
+ join13(userSettingsDir, "settings.json"),
16281
16667
  JSON.stringify(codeServerSettings(collaboration), null, 2)
16282
16668
  );
16283
16669
  return { ok: true, userDataDir, extensionsDir, collaborationServerDir };
@@ -16289,14 +16675,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16289
16675
  const vscodeRoot = codeServerVscodeRoot(runtime);
16290
16676
  const repairs = [
16291
16677
  {
16292
- source: join11(
16678
+ source: join13(
16293
16679
  vscodeRoot,
16294
16680
  "extensions",
16295
16681
  "git-base",
16296
16682
  "dist",
16297
16683
  "extension.js"
16298
16684
  ),
16299
- target: join11(
16685
+ target: join13(
16300
16686
  vscodeRoot,
16301
16687
  "extensions",
16302
16688
  "git-base",
@@ -16307,14 +16693,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16307
16693
  required: true
16308
16694
  },
16309
16695
  {
16310
- source: join11(
16696
+ source: join13(
16311
16697
  vscodeRoot,
16312
16698
  "extensions",
16313
16699
  "git-base",
16314
16700
  "dist",
16315
16701
  "extension.js.map"
16316
16702
  ),
16317
- target: join11(
16703
+ target: join13(
16318
16704
  vscodeRoot,
16319
16705
  "extensions",
16320
16706
  "git-base",
@@ -16325,14 +16711,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16325
16711
  required: false
16326
16712
  },
16327
16713
  {
16328
- source: join11(
16714
+ source: join13(
16329
16715
  vscodeRoot,
16330
16716
  "extensions",
16331
16717
  "merge-conflict",
16332
16718
  "dist",
16333
16719
  "mergeConflictMain.js"
16334
16720
  ),
16335
- target: join11(
16721
+ target: join13(
16336
16722
  vscodeRoot,
16337
16723
  "extensions",
16338
16724
  "merge-conflict",
@@ -16343,14 +16729,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16343
16729
  required: true
16344
16730
  },
16345
16731
  {
16346
- source: join11(
16732
+ source: join13(
16347
16733
  vscodeRoot,
16348
16734
  "extensions",
16349
16735
  "merge-conflict",
16350
16736
  "dist",
16351
16737
  "mergeConflictMain.js.map"
16352
16738
  ),
16353
- target: join11(
16739
+ target: join13(
16354
16740
  vscodeRoot,
16355
16741
  "extensions",
16356
16742
  "merge-conflict",
@@ -16368,7 +16754,7 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16368
16754
  case (!required3 && !existsSync8(source)):
16369
16755
  return;
16370
16756
  default:
16371
- mkdirSync6(dirname6(target), { recursive: true });
16757
+ mkdirSync7(dirname6(target), { recursive: true });
16372
16758
  copyFileSync(source, target);
16373
16759
  return;
16374
16760
  }
@@ -16376,10 +16762,10 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16376
16762
  }
16377
16763
  function codeServerVscodeRoot(runtime) {
16378
16764
  const roots = uniquePaths([
16379
- join11(runtime.root, "lib", "vscode"),
16380
- join11(dirname6(dirname6(runtime.codeServerBin)), "lib", "vscode"),
16765
+ join13(runtime.root, "lib", "vscode"),
16766
+ join13(dirname6(dirname6(runtime.codeServerBin)), "lib", "vscode"),
16381
16767
  ...wrappedCodeServerBin(runtime.codeServerBin).map(
16382
- (codeServerBin) => join11(dirname6(dirname6(codeServerBin)), "lib", "vscode")
16768
+ (codeServerBin) => join13(dirname6(dirname6(codeServerBin)), "lib", "vscode")
16383
16769
  )
16384
16770
  ]);
16385
16771
  const rootWithRequiredAssets = roots.find(
@@ -16395,7 +16781,7 @@ function codeServerVscodeRoot(runtime) {
16395
16781
  }
16396
16782
  function wrappedCodeServerBin(codeServerBin) {
16397
16783
  try {
16398
- const script = readFileSync9(codeServerBin, "utf8");
16784
+ const script = readFileSync10(codeServerBin, "utf8");
16399
16785
  const match = script.match(
16400
16786
  /exec\s+(?:"([^"]+)"|'([^']+)'|([^\s]+))\s+"\$@"/u
16401
16787
  );
@@ -16407,8 +16793,8 @@ function wrappedCodeServerBin(codeServerBin) {
16407
16793
  }
16408
16794
  function codeServerBrowserAssetSources(vscodeRoot) {
16409
16795
  return [
16410
- join11(vscodeRoot, "extensions", "git-base", "dist", "extension.js"),
16411
- join11(
16796
+ join13(vscodeRoot, "extensions", "git-base", "dist", "extension.js"),
16797
+ join13(
16412
16798
  vscodeRoot,
16413
16799
  "extensions",
16414
16800
  "merge-conflict",
@@ -16487,10 +16873,10 @@ function prepareLinuxCodeServerLaunch(options) {
16487
16873
  options.cwd,
16488
16874
  "--setenv",
16489
16875
  "XDG_DATA_HOME",
16490
- join11(options.userDataDir, "data"),
16876
+ join13(options.userDataDir, "data"),
16491
16877
  "--setenv",
16492
16878
  "XDG_CONFIG_HOME",
16493
- join11(options.userDataDir, "config"),
16879
+ join13(options.userDataDir, "config"),
16494
16880
  ...readOnlyRoots.flatMap((path2) => ["--ro-bind-try", path2, path2]),
16495
16881
  "--bind",
16496
16882
  options.cwd,
@@ -16531,7 +16917,7 @@ function resolveCodeServerExecutable(command, envPath) {
16531
16917
  if (directory.trim() === "") {
16532
16918
  continue;
16533
16919
  }
16534
- const candidate = join11(directory, command);
16920
+ const candidate = join13(directory, command);
16535
16921
  if (!existsSync8(candidate)) {
16536
16922
  continue;
16537
16923
  }
@@ -16617,7 +17003,7 @@ async function startCollaborationSidecar(collaboration, profile, editorRuntime,
16617
17003
  ]);
16618
17004
  const command = nodeRuntimeExecutable();
16619
17005
  const args = [
16620
- join11(
17006
+ join13(
16621
17007
  profile.collaborationServerDir,
16622
17008
  "open-collaboration-server",
16623
17009
  "bundle",
@@ -16712,11 +17098,11 @@ function nodeRuntimeExecutable(env = process.env, execPath = process.execPath) {
16712
17098
  return basename6(execPath).toLowerCase().includes("bun") ? "node" : execPath;
16713
17099
  }
16714
17100
  async function installLocalTarball(archivePath, destinationDir) {
16715
- mkdirSync6(destinationDir, { recursive: true });
17101
+ mkdirSync7(destinationDir, { recursive: true });
16716
17102
  await runProcess("tar", ["-xzf", archivePath, "-C", destinationDir]);
16717
17103
  }
16718
17104
  function installDirectory(sourceDir, destinationDir) {
16719
- mkdirSync6(dirname6(destinationDir), { recursive: true });
17105
+ mkdirSync7(dirname6(destinationDir), { recursive: true });
16720
17106
  cpSync(sourceDir, destinationDir, { recursive: true });
16721
17107
  }
16722
17108
  function codeServerEnv(env, cwd, userDataDir, collaboration) {
@@ -16734,7 +17120,7 @@ function codeServerEnv(env, cwd, userDataDir, collaboration) {
16734
17120
  KANDAN_EDITOR_COLLABORATION_ENTRY_MODE: "kandan_auto_host_or_join",
16735
17121
  KANDAN_EDITOR_COLLABORATION_ROOM_ID: collaboration.roomId,
16736
17122
  KANDAN_EDITOR_COLLABORATION_SERVER_URL: collaboration.bootstrapServerUrl,
16737
- KANDAN_EDITOR_COLLABORATION_AUTO_HOST_CLAIM_PATH: join11(
17123
+ KANDAN_EDITOR_COLLABORATION_AUTO_HOST_CLAIM_PATH: join13(
16738
17124
  userDataDir,
16739
17125
  "kandan-oct-auto-host.lock"
16740
17126
  )
@@ -16943,15 +17329,15 @@ import {
16943
17329
  createReadStream,
16944
17330
  createWriteStream as createWriteStream2,
16945
17331
  existsSync as existsSync9,
16946
- mkdirSync as mkdirSync7,
17332
+ mkdirSync as mkdirSync8,
16947
17333
  mkdtempSync as mkdtempSync2,
16948
- readFileSync as readFileSync10,
17334
+ readFileSync as readFileSync11,
16949
17335
  renameSync,
16950
- rmSync as rmSync2,
16951
- writeFileSync as writeFileSync5
17336
+ rmSync as rmSync3,
17337
+ writeFileSync as writeFileSync6
16952
17338
  } from "node:fs";
16953
- import { homedir as homedir10 } from "node:os";
16954
- import { dirname as dirname7, join as join12, resolve as resolve7 } from "node:path";
17339
+ import { homedir as homedir11 } from "node:os";
17340
+ import { dirname as dirname7, join as join14, resolve as resolve7 } from "node:path";
16955
17341
  import { Readable } from "node:stream";
16956
17342
  import { pipeline } from "node:stream/promises";
16957
17343
  async function resolveEditorRuntime(options) {
@@ -17142,14 +17528,14 @@ function normalizeRuntimeAssets(value) {
17142
17528
  }
17143
17529
  function installedRuntime(cacheRoot, manifest) {
17144
17530
  const runtimeRoot = runtimeInstallRoot(cacheRoot, manifest);
17145
- const manifestPath = join12(runtimeRoot, manifest.manifestPath);
17146
- const codeServerBin = join12(runtimeRoot, manifest.codeServerBinPath);
17531
+ const manifestPath = join14(runtimeRoot, manifest.manifestPath);
17532
+ const codeServerBin = join14(runtimeRoot, manifest.codeServerBinPath);
17147
17533
  const assets = verifiedRuntimeAssetPaths(runtimeRoot, manifest);
17148
17534
  if (!existsSync9(manifestPath) || !existsSync9(codeServerBin) || assets === void 0) {
17149
17535
  return { ok: false };
17150
17536
  }
17151
17537
  try {
17152
- const installed = JSON.parse(readFileSync10(manifestPath, "utf8"));
17538
+ const installed = JSON.parse(readFileSync11(manifestPath, "utf8"));
17153
17539
  if (isJsonObject(installed) && installed.version === manifest.version && installed.platform === manifest.platform && (installed.archiveSha256 === void 0 || installed.archiveSha256 === manifest.archiveSha256)) {
17154
17540
  return {
17155
17541
  ok: true,
@@ -17167,10 +17553,10 @@ function installedRuntime(cacheRoot, manifest) {
17167
17553
  return { ok: false };
17168
17554
  }
17169
17555
  async function installRuntime(args) {
17170
- mkdirSync7(args.cacheRoot, { recursive: true });
17171
- const tempRoot = mkdtempSync2(join12(args.cacheRoot, ".install-"));
17172
- const archivePath = join12(tempRoot, "runtime.tar.gz");
17173
- const extractRoot = join12(tempRoot, "runtime");
17556
+ mkdirSync8(args.cacheRoot, { recursive: true });
17557
+ const tempRoot = mkdtempSync2(join14(args.cacheRoot, ".install-"));
17558
+ const archivePath = join14(tempRoot, "runtime.tar.gz");
17559
+ const extractRoot = join14(tempRoot, "runtime");
17174
17560
  try {
17175
17561
  const downloaded = await downloadArchive({
17176
17562
  kandanUrl: args.kandanUrl,
@@ -17182,7 +17568,7 @@ async function installRuntime(args) {
17182
17568
  if (!downloaded.ok) {
17183
17569
  return downloaded;
17184
17570
  }
17185
- mkdirSync7(extractRoot, { recursive: true });
17571
+ mkdirSync8(extractRoot, { recursive: true });
17186
17572
  if (!await args.extractArchive(archivePath, extractRoot)) {
17187
17573
  return { ok: false, reason: "archive_extract_failed" };
17188
17574
  }
@@ -17195,14 +17581,14 @@ async function installRuntime(args) {
17195
17581
  if (!assetsInstalled) {
17196
17582
  return { ok: false, reason: "install_failed" };
17197
17583
  }
17198
- const manifestPath = join12(extractRoot, args.manifest.manifestPath);
17199
- const codeServerBin = join12(extractRoot, args.manifest.codeServerBinPath);
17584
+ const manifestPath = join14(extractRoot, args.manifest.manifestPath);
17585
+ const codeServerBin = join14(extractRoot, args.manifest.codeServerBinPath);
17200
17586
  const assets = verifiedRuntimeAssetPaths(extractRoot, args.manifest);
17201
17587
  if (!existsSync9(codeServerBin) || assets === void 0) {
17202
17588
  return { ok: false, reason: "invalid_archive" };
17203
17589
  }
17204
- mkdirSync7(dirname7(manifestPath), { recursive: true });
17205
- writeFileSync5(
17590
+ mkdirSync8(dirname7(manifestPath), { recursive: true });
17591
+ writeFileSync6(
17206
17592
  manifestPath,
17207
17593
  JSON.stringify(
17208
17594
  {
@@ -17219,29 +17605,29 @@ async function installRuntime(args) {
17219
17605
  )
17220
17606
  );
17221
17607
  const targetRoot = runtimeInstallRoot(args.cacheRoot, args.manifest);
17222
- rmSync2(targetRoot, { recursive: true, force: true });
17223
- mkdirSync7(dirname7(targetRoot), { recursive: true });
17608
+ rmSync3(targetRoot, { recursive: true, force: true });
17609
+ mkdirSync8(dirname7(targetRoot), { recursive: true });
17224
17610
  renameSync(extractRoot, targetRoot);
17225
17611
  return {
17226
17612
  ok: true,
17227
17613
  runtime: {
17228
17614
  mode: "server_managed",
17229
17615
  root: targetRoot,
17230
- codeServerBin: join12(targetRoot, args.manifest.codeServerBinPath),
17616
+ codeServerBin: join14(targetRoot, args.manifest.codeServerBinPath),
17231
17617
  assets: {
17232
- collaborationExtensionTarball: join12(
17618
+ collaborationExtensionTarball: join14(
17233
17619
  targetRoot,
17234
17620
  "kandan",
17235
17621
  "editor_extensions",
17236
17622
  "typefox.open-collaboration-tools.tar.gz"
17237
17623
  ),
17238
- collaborationServerTarball: join12(
17624
+ collaborationServerTarball: join14(
17239
17625
  targetRoot,
17240
17626
  "kandan",
17241
17627
  "editor_servers",
17242
17628
  "open-collaboration-server.tar.gz"
17243
17629
  ),
17244
- documentStateExtensionDir: join12(
17630
+ documentStateExtensionDir: join14(
17245
17631
  targetRoot,
17246
17632
  "kandan",
17247
17633
  "editor_extensions",
@@ -17253,12 +17639,12 @@ async function installRuntime(args) {
17253
17639
  } catch (_error) {
17254
17640
  return { ok: false, reason: "install_failed" };
17255
17641
  } finally {
17256
- rmSync2(tempRoot, { recursive: true, force: true });
17642
+ rmSync3(tempRoot, { recursive: true, force: true });
17257
17643
  }
17258
17644
  }
17259
17645
  async function materializeRuntimeAssets(args) {
17260
17646
  for (const asset of args.manifest.assets) {
17261
- const targetPath = join12(args.runtimeRoot, asset.path);
17647
+ const targetPath = join14(args.runtimeRoot, asset.path);
17262
17648
  try {
17263
17649
  const bytes = await runtimeAssetBytes({
17264
17650
  kandanUrl: args.kandanUrl,
@@ -17268,8 +17654,8 @@ async function materializeRuntimeAssets(args) {
17268
17654
  if (bytes === void 0) {
17269
17655
  continue;
17270
17656
  }
17271
- mkdirSync7(dirname7(targetPath), { recursive: true });
17272
- writeFileSync5(targetPath, bytes);
17657
+ mkdirSync8(dirname7(targetPath), { recursive: true });
17658
+ writeFileSync6(targetPath, bytes);
17273
17659
  } catch (_error) {
17274
17660
  return false;
17275
17661
  }
@@ -17359,19 +17745,19 @@ function runtimeInstallRoot(cacheRoot, manifest) {
17359
17745
  return resolve7(cacheRoot, manifest.platform, manifest.archiveSha256);
17360
17746
  }
17361
17747
  function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17362
- const collaborationExtensionTarball = join12(
17748
+ const collaborationExtensionTarball = join14(
17363
17749
  runtimeRoot,
17364
17750
  "kandan",
17365
17751
  "editor_extensions",
17366
17752
  "typefox.open-collaboration-tools.tar.gz"
17367
17753
  );
17368
- const collaborationServerTarball = join12(
17754
+ const collaborationServerTarball = join14(
17369
17755
  runtimeRoot,
17370
17756
  "kandan",
17371
17757
  "editor_servers",
17372
17758
  "open-collaboration-server.tar.gz"
17373
17759
  );
17374
- const documentStateExtensionDir = join12(
17760
+ const documentStateExtensionDir = join14(
17375
17761
  runtimeRoot,
17376
17762
  "kandan",
17377
17763
  "editor_extensions",
@@ -17380,7 +17766,7 @@ function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17380
17766
  const codeServerRoot = codeServerRuntimeRoot(manifest.codeServerBinPath);
17381
17767
  const requiredPaths = [
17382
17768
  manifest.codeServerBinPath,
17383
- join12(
17769
+ join14(
17384
17770
  codeServerRoot,
17385
17771
  "lib",
17386
17772
  "vscode",
@@ -17390,7 +17776,7 @@ function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17390
17776
  "web",
17391
17777
  "vsda.js"
17392
17778
  ),
17393
- join12(
17779
+ join14(
17394
17780
  codeServerRoot,
17395
17781
  "lib",
17396
17782
  "vscode",
@@ -17411,7 +17797,7 @@ function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17411
17797
  if (expectedSha256 === void 0 && relativePath !== manifest.codeServerBinPath) {
17412
17798
  return void 0;
17413
17799
  }
17414
- const absolutePath = join12(runtimeRoot, relativePath);
17800
+ const absolutePath = join14(runtimeRoot, relativePath);
17415
17801
  if (!existsSync9(absolutePath)) {
17416
17802
  return void 0;
17417
17803
  }
@@ -17440,10 +17826,10 @@ function manifestAssetChecksums(assets) {
17440
17826
  return checksums;
17441
17827
  }
17442
17828
  function fileSha256Sync(path2) {
17443
- return createHash4("sha256").update(readFileSync10(path2)).digest("hex");
17829
+ return createHash4("sha256").update(readFileSync11(path2)).digest("hex");
17444
17830
  }
17445
17831
  function defaultEditorRuntimeCacheRoot() {
17446
- return join12(homedir10(), ".linzumi", "editor-runtimes");
17832
+ return join14(homedir11(), ".linzumi", "editor-runtimes");
17447
17833
  }
17448
17834
  function nonEmptyString(value) {
17449
17835
  return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
@@ -17463,7 +17849,7 @@ var init_localEditorRuntime = __esm({
17463
17849
 
17464
17850
  // src/dependencyStatus.ts
17465
17851
  import { spawn as spawn6, spawnSync as spawnSync4 } from "node:child_process";
17466
- import { delimiter as delimiter2, dirname as dirname8, join as join13 } from "node:path";
17852
+ import { delimiter as delimiter2, dirname as dirname8, join as join15 } from "node:path";
17467
17853
  function probeTool(command, cwd) {
17468
17854
  return new Promise((resolve12) => {
17469
17855
  const args = ["--version"];
@@ -17620,8 +18006,8 @@ function voltaCommandCandidates(args) {
17620
18006
  new Set(
17621
18007
  [
17622
18008
  voltaBinBesideCodexShim(args.codexBin),
17623
- env.VOLTA_HOME === void 0 ? void 0 : join13(env.VOLTA_HOME, "bin", "volta"),
17624
- env.HOME === void 0 ? void 0 : join13(env.HOME, ".volta", "bin", "volta"),
18009
+ env.VOLTA_HOME === void 0 ? void 0 : join15(env.VOLTA_HOME, "bin", "volta"),
18010
+ env.HOME === void 0 ? void 0 : join15(env.HOME, ".volta", "bin", "volta"),
17625
18011
  ...pathVoltaCandidates(env.PATH)
17626
18012
  ].filter((candidate) => candidate !== void 0)
17627
18013
  )
@@ -17629,10 +18015,10 @@ function voltaCommandCandidates(args) {
17629
18015
  }
17630
18016
  function voltaBinBesideCodexShim(codexBin) {
17631
18017
  const normalizedCodexBin = codexBin.replaceAll("\\", "/");
17632
- return normalizedCodexBin.endsWith("/.volta/bin/codex") ? join13(dirname8(codexBin), "volta") : void 0;
18018
+ return normalizedCodexBin.endsWith("/.volta/bin/codex") ? join15(dirname8(codexBin), "volta") : void 0;
17633
18019
  }
17634
18020
  function pathVoltaCandidates(pathValue) {
17635
- return pathValue === void 0 ? [] : pathValue.split(delimiter2).filter((entry) => entry !== "").map((entry) => join13(entry, "volta"));
18021
+ return pathValue === void 0 ? [] : pathValue.split(delimiter2).filter((entry) => entry !== "").map((entry) => join15(entry, "volta"));
17636
18022
  }
17637
18023
  function codeServerDependencyStatus(args) {
17638
18024
  switch (args.editorRuntime?.status) {
@@ -17741,7 +18127,7 @@ var linzumiCliVersion, linzumiCliVersionText;
17741
18127
  var init_version = __esm({
17742
18128
  "src/version.ts"() {
17743
18129
  "use strict";
17744
- linzumiCliVersion = "0.0.83-beta";
18130
+ linzumiCliVersion = "0.0.85-beta";
17745
18131
  linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
17746
18132
  }
17747
18133
  });
@@ -17750,21 +18136,21 @@ var init_version = __esm({
17750
18136
  import {
17751
18137
  closeSync as closeSync2,
17752
18138
  existsSync as existsSync10,
17753
- mkdirSync as mkdirSync8,
18139
+ mkdirSync as mkdirSync9,
17754
18140
  openSync as openSync3,
17755
- readFileSync as readFileSync11,
18141
+ readFileSync as readFileSync12,
17756
18142
  renameSync as renameSync2,
17757
18143
  unlinkSync as unlinkSync2,
17758
- writeFileSync as writeFileSync6,
18144
+ writeFileSync as writeFileSync7,
17759
18145
  writeSync
17760
18146
  } from "node:fs";
17761
- import { dirname as dirname9, join as join14 } from "node:path";
18147
+ import { dirname as dirname9, join as join16 } from "node:path";
17762
18148
  function isRunnerLockHeldError(error) {
17763
18149
  return error instanceof RunnerLockHeldError || error instanceof Error && error.name === runnerLockHeldErrorName && "lockPath" in error && "heldBy" in error;
17764
18150
  }
17765
18151
  function runnerLockPath(machineId, configPath = localConfigPath(), linzumiUrl) {
17766
18152
  const lockName = linzumiUrl === void 0 ? encodeURIComponent(machineId) : localConfigScopeFileStem(linzumiUrl);
17767
- return join14(dirname9(configPath), "runners", `${lockName}.lock`);
18153
+ return join16(dirname9(configPath), "runners", `${lockName}.lock`);
17768
18154
  }
17769
18155
  function acquireRunnerLock(options) {
17770
18156
  const path2 = runnerLockPath(
@@ -17832,7 +18218,7 @@ function stampRunnerLockHeartbeat(path2, record, now) {
17832
18218
  heartbeatAt: now().toISOString()
17833
18219
  };
17834
18220
  const tmpPath = `${path2}.tmp`;
17835
- writeFileSync6(tmpPath, `${JSON.stringify(next, null, 2)}
18221
+ writeFileSync7(tmpPath, `${JSON.stringify(next, null, 2)}
17836
18222
  `, "utf8");
17837
18223
  renameSync2(tmpPath, path2);
17838
18224
  } catch (_error) {
@@ -17944,7 +18330,7 @@ function writeLockOrHandleExisting(path2, record, isPidAlive, now, killPid, onTa
17944
18330
  });
17945
18331
  }
17946
18332
  function tryCreateLock(path2, record) {
17947
- mkdirSync8(dirname9(path2), { recursive: true });
18333
+ mkdirSync9(dirname9(path2), { recursive: true });
17948
18334
  try {
17949
18335
  const fd = openSync3(path2, "wx");
17950
18336
  try {
@@ -18000,7 +18386,7 @@ function withStaleReplacementLock(path2, isPidAlive, callback) {
18000
18386
  function readReplacementLockPidIfPresent(path2) {
18001
18387
  let value;
18002
18388
  try {
18003
- value = readFileSync11(path2, "utf8").trim();
18389
+ value = readFileSync12(path2, "utf8").trim();
18004
18390
  } catch (error) {
18005
18391
  if (isNodeErrorCode2(error, "ENOENT")) {
18006
18392
  return void 0;
@@ -18040,7 +18426,7 @@ function readRunnerLockIfPresent(path2) {
18040
18426
  }
18041
18427
  }
18042
18428
  function readRunnerLock(path2) {
18043
- const parsed = JSON.parse(readFileSync11(path2, "utf8"));
18429
+ const parsed = JSON.parse(readFileSync12(path2, "utf8"));
18044
18430
  if (!isRunnerLockRecord(parsed)) {
18045
18431
  throw new Error(`invalid Linzumi runner lock: ${path2}`);
18046
18432
  }
@@ -18327,6 +18713,19 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18327
18713
  job.updatedAtMs = nowMs;
18328
18714
  break;
18329
18715
  }
18716
+ // Live token counter parity with codex.notification token_usage_summary:
18717
+ // mid-turn usage events advance the dashboard counters per model round.
18718
+ case "claude_code.token_usage": {
18719
+ const tokenUsage = stringValue5(payload.token_usage_summary);
18720
+ const job = claudeDashboardJob(state, payload, nowMs);
18721
+ if (tokenUsage !== void 0) {
18722
+ state.tokenUsage = tokenUsage;
18723
+ job.tokenUsage = tokenUsage;
18724
+ }
18725
+ job.eventType = "token_usage";
18726
+ job.updatedAtMs = nowMs;
18727
+ break;
18728
+ }
18330
18729
  default:
18331
18730
  break;
18332
18731
  }
@@ -18787,6 +19186,8 @@ function formatRunnerConsoleEvent(event, payload) {
18787
19186
  return `Claude Code turn ${text(payload.outcome)}: id=${text(payload.turn_id)}`;
18788
19187
  case "claude_code.rate_limit":
18789
19188
  return `Claude Code rate limit: ${stringValue5(payload.rate_limit_summary) ?? "seen (no details)"}`;
19189
+ case "claude_code.token_usage":
19190
+ return `Claude Code token usage: ${stringValue5(payload.token_usage_summary) ?? "seen (no details)"}`;
18790
19191
  default:
18791
19192
  return void 0;
18792
19193
  }
@@ -18849,7 +19250,9 @@ function ignoredMessage(payload) {
18849
19250
  `reason=${text(payload.reason)}`,
18850
19251
  optionalField("type", payload.type),
18851
19252
  optionalField("thread", payload.thread_id),
19253
+ optionalField("bound_thread", payload.bound_thread_id),
18852
19254
  optionalField("body_chars", payload.body_length),
19255
+ optionalField("body", payload.body_preview),
18853
19256
  optionalField("attachments", payload.attachment_count),
18854
19257
  optionalField("local_event", payload.local_runner_event_type)
18855
19258
  ].filter((part) => part !== void 0).join(" ");
@@ -19730,8 +20133,8 @@ var init_runnerConsoleReporter = __esm({
19730
20133
  });
19731
20134
 
19732
20135
  // src/telemetry.ts
19733
- import { mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
19734
- import { dirname as dirname10, basename as basename7, join as join15 } from "node:path";
20136
+ import { mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
20137
+ import { dirname as dirname10, basename as basename7, join as join17 } from "node:path";
19735
20138
  import { randomUUID as randomUUID3 } from "node:crypto";
19736
20139
  function peekFlagValue(args, flags) {
19737
20140
  for (let index = 0; index < args.length; index += 1) {
@@ -19770,12 +20173,12 @@ function telemetryBaseUrl(apiUrl, env = process.env) {
19770
20173
  }
19771
20174
  }
19772
20175
  function telemetryInstallIdPath(env = process.env) {
19773
- return join15(dirname10(localConfigPath(env)), "install-id");
20176
+ return join17(dirname10(localConfigPath(env)), "install-id");
19774
20177
  }
19775
20178
  function ensureTelemetryInstallId(env = process.env) {
19776
20179
  const path2 = telemetryInstallIdPath(env);
19777
20180
  try {
19778
- const existing = readFileSync12(path2, "utf8").trim();
20181
+ const existing = readFileSync13(path2, "utf8").trim();
19779
20182
  if (existing !== "" && existing.length <= 128) {
19780
20183
  return existing;
19781
20184
  }
@@ -19783,8 +20186,8 @@ function ensureTelemetryInstallId(env = process.env) {
19783
20186
  }
19784
20187
  const installId = randomUUID3();
19785
20188
  try {
19786
- mkdirSync9(dirname10(path2), { recursive: true });
19787
- writeFileSync7(path2, `${installId}
20189
+ mkdirSync10(dirname10(path2), { recursive: true });
20190
+ writeFileSync8(path2, `${installId}
19788
20191
  `, { mode: 384 });
19789
20192
  } catch {
19790
20193
  }
@@ -19971,17 +20374,17 @@ var init_linzumiApiClient = __esm({
19971
20374
  });
19972
20375
 
19973
20376
  // src/authCache.ts
19974
- import { existsSync as existsSync11, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
19975
- import { homedir as homedir11 } from "node:os";
19976
- import { dirname as dirname11, join as join16 } from "node:path";
20377
+ import { existsSync as existsSync11, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "node:fs";
20378
+ import { homedir as homedir12 } from "node:os";
20379
+ import { dirname as dirname11, join as join18 } from "node:path";
19977
20380
  function defaultAuthFilePath() {
19978
- return join16(homedir11(), ".linzumi", "auth.json");
20381
+ return join18(homedir12(), ".linzumi", "auth.json");
19979
20382
  }
19980
20383
  function readCachedLocalRunnerToken(kandanUrl, authFilePath = defaultAuthFilePath()) {
19981
20384
  if (!existsSync11(authFilePath)) {
19982
20385
  return void 0;
19983
20386
  }
19984
- const authFile = parseAuthFile(readFileSync13(authFilePath, "utf8"));
20387
+ const authFile = parseAuthFile(readFileSync14(authFilePath, "utf8"));
19985
20388
  const kandanBaseUrl = kandanHttpBaseUrl(kandanUrl);
19986
20389
  const entry = authFile.local_codex_runner?.[kandanBaseUrl];
19987
20390
  if (entry === void 0 || entry.access_token.trim() === "") {
@@ -20003,7 +20406,7 @@ function readPersonalAgentDelegationToken(authFilePath) {
20003
20406
  `missing personal-agent delegation auth file: ${authFilePath}`
20004
20407
  );
20005
20408
  }
20006
- const authFile = parseAuthFile(readFileSync13(authFilePath, "utf8"));
20409
+ const authFile = parseAuthFile(readFileSync14(authFilePath, "utf8"));
20007
20410
  const entry = authFile.personal_agent_delegation;
20008
20411
  if (entry === void 0 || entry.access_token.trim() === "") {
20009
20412
  throw new Error(
@@ -20021,7 +20424,7 @@ function readPersonalAgentDelegationToken(authFilePath) {
20021
20424
  }
20022
20425
  function writeCachedLocalRunnerToken(args) {
20023
20426
  const authFilePath = args.authFilePath ?? defaultAuthFilePath();
20024
- const existing = existsSync11(authFilePath) ? parseAuthFile(readFileSync13(authFilePath, "utf8")) : { version: 1 };
20427
+ const existing = existsSync11(authFilePath) ? parseAuthFile(readFileSync14(authFilePath, "utf8")) : { version: 1 };
20025
20428
  const kandanBaseUrl = kandanHttpBaseUrl(args.kandanUrl);
20026
20429
  const issuedAt = /* @__PURE__ */ new Date();
20027
20430
  const expiresAt = args.expiresInSeconds === void 0 ? void 0 : new Date(
@@ -20039,8 +20442,8 @@ function writeCachedLocalRunnerToken(args) {
20039
20442
  }
20040
20443
  }
20041
20444
  };
20042
- mkdirSync10(dirname11(authFilePath), { recursive: true });
20043
- writeFileSync8(authFilePath, `${JSON.stringify(next, null, 2)}
20445
+ mkdirSync11(dirname11(authFilePath), { recursive: true });
20446
+ writeFileSync9(authFilePath, `${JSON.stringify(next, null, 2)}
20044
20447
  `, "utf8");
20045
20448
  return {
20046
20449
  accessToken: args.accessToken,
@@ -20485,9 +20888,9 @@ var init_threadCodexWorkerIpc = __esm({
20485
20888
 
20486
20889
  // src/signupTaskSuggestions.ts
20487
20890
  import { spawn as spawn7 } from "node:child_process";
20488
- import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync14, rmSync as rmSync3, writeFileSync as writeFileSync9 } from "node:fs";
20891
+ import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync15, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
20489
20892
  import { tmpdir as tmpdir2 } from "node:os";
20490
- import { join as join17 } from "node:path";
20893
+ import { join as join19 } from "node:path";
20491
20894
  async function suggestSignupTasksWithCodex(args) {
20492
20895
  const attempts = 2;
20493
20896
  let previousResponse;
@@ -20509,11 +20912,11 @@ async function suggestSignupTasksWithCodex(args) {
20509
20912
  );
20510
20913
  }
20511
20914
  async function runCodexTaskSuggestion(args) {
20512
- const tempRoot = mkdtempSync3(join17(tmpdir2(), "linzumi-signup-codex-tasks-"));
20513
- const schemaPath = join17(tempRoot, "task-suggestions.schema.json");
20514
- const outputPath = join17(tempRoot, "task-suggestions.json");
20915
+ const tempRoot = mkdtempSync3(join19(tmpdir2(), "linzumi-signup-codex-tasks-"));
20916
+ const schemaPath = join19(tempRoot, "task-suggestions.schema.json");
20917
+ const outputPath = join19(tempRoot, "task-suggestions.json");
20515
20918
  const prompt = taskSuggestionPrompt(args.previousResponse);
20516
- writeFileSync9(
20919
+ writeFileSync10(
20517
20920
  schemaPath,
20518
20921
  `${JSON.stringify(taskSuggestionJsonSchema(), null, 2)}
20519
20922
  `,
@@ -20530,9 +20933,9 @@ async function runCodexTaskSuggestion(args) {
20530
20933
  prompt
20531
20934
  })
20532
20935
  );
20533
- return readFileSync14(outputPath, "utf8");
20936
+ return readFileSync15(outputPath, "utf8");
20534
20937
  } finally {
20535
- rmSync3(tempRoot, { recursive: true, force: true });
20938
+ rmSync4(tempRoot, { recursive: true, force: true });
20536
20939
  }
20537
20940
  }
20538
20941
  function codexTaskSuggestionProcess(args) {
@@ -20979,25 +21382,25 @@ import { createHash as createHash5, randomUUID as randomUUID4 } from "node:crypt
20979
21382
  import {
20980
21383
  chmodSync as chmodSync2,
20981
21384
  lstatSync,
20982
- mkdirSync as mkdirSync11,
21385
+ mkdirSync as mkdirSync12,
20983
21386
  mkdtempSync as mkdtempSync4,
20984
21387
  readdirSync as readdirSync4,
20985
- readFileSync as readFileSync15,
21388
+ readFileSync as readFileSync16,
20986
21389
  realpathSync as realpathSync6,
20987
21390
  renameSync as renameSync3,
20988
- rmSync as rmSync4,
21391
+ rmSync as rmSync5,
20989
21392
  statSync as statSync3,
20990
- writeFileSync as writeFileSync10
21393
+ writeFileSync as writeFileSync11
20991
21394
  } from "node:fs";
20992
21395
  import { readFile as readFile2 } from "node:fs/promises";
20993
21396
  import { createServer as createServer3 } from "node:http";
20994
- import { homedir as homedir12, hostname as hostname2, tmpdir as tmpdir3 } from "node:os";
21397
+ import { homedir as homedir13, hostname as hostname2, tmpdir as tmpdir3 } from "node:os";
20995
21398
  import {
20996
21399
  basename as basename8,
20997
21400
  dirname as dirname13,
20998
21401
  extname as extname2,
20999
21402
  isAbsolute as isAbsolute5,
21000
- join as join18,
21403
+ join as join20,
21001
21404
  resolve as resolve8
21002
21405
  } from "node:path";
21003
21406
  async function runLocalCodexRunner(options) {
@@ -21243,6 +21646,9 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
21243
21646
  defaultAgentProvider: "codex",
21244
21647
  startInstance: allowedCwds.value.length > 0,
21245
21648
  durableClaudeSessionStore: true,
21649
+ // Honest capability: no faithful Claude Code rewind exists yet; the
21650
+ // rewind_thread control responds with a clean rejection (spec:
21651
+ // plans/2026-06-12-claude-steer-rewind-parity-note.md item B).
21246
21652
  claudeCodeCheckpointRewind: false,
21247
21653
  allowedCwds: allowedCwds.value,
21248
21654
  missingAllowedCwds: missingAllowedCwds.value,
@@ -22188,7 +22594,29 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
22188
22594
  );
22189
22595
  dynamicChannelSessions.clear();
22190
22596
  dynamicChannelSessionCodexClients.clear();
22191
- for (const session of activeClaudeCodeSessions.values()) {
22597
+ const claudeSessions = [...activeClaudeCodeSessions.values()];
22598
+ for (const session of claudeSessions) {
22599
+ try {
22600
+ session.closeInput();
22601
+ } catch (error) {
22602
+ log2("claude_code.session_input_close_failed", {
22603
+ linzumi_thread_id: session.threadId,
22604
+ message: error instanceof Error ? error.message : String(error)
22605
+ });
22606
+ }
22607
+ }
22608
+ await Promise.race([
22609
+ Promise.allSettled(
22610
+ claudeSessions.flatMap((session) => {
22611
+ const work = session.sessionWork();
22612
+ return work === void 0 ? [] : [work];
22613
+ })
22614
+ ),
22615
+ new Promise((resolve12) => {
22616
+ setTimeout(resolve12, 1e4).unref?.();
22617
+ })
22618
+ ]);
22619
+ for (const session of claudeSessions) {
22192
22620
  session.abortController.abort(new Error("local runner stopped"));
22193
22621
  }
22194
22622
  activeClaudeCodeSessions.clear();
@@ -22333,13 +22761,14 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
22333
22761
  if (workspaceSlug === void 0 || channelSlug === void 0 || kandanThreadId === void 0) {
22334
22762
  return void 0;
22335
22763
  }
22336
- const waferResolution = resolveControlWaferModelProvider(control);
22337
- if (waferResolution.type === "error") {
22764
+ const providerResolution = resolveControlCodexModelProvider(control);
22765
+ const providerResolutionError = codexModelProviderResolutionError(providerResolution);
22766
+ if (providerResolutionError !== void 0) {
22338
22767
  return {
22339
22768
  instanceId,
22340
22769
  controlType: control.type,
22341
22770
  ok: false,
22342
- error: waferResolution.error,
22771
+ error: providerResolutionError,
22343
22772
  kandanThreadId,
22344
22773
  cwd
22345
22774
  };
@@ -22954,14 +23383,14 @@ function commanderOutboxPersistDir() {
22954
23383
  if (override !== void 0 && override !== "") {
22955
23384
  return override;
22956
23385
  }
22957
- return join18(homedir12(), ".linzumi", "commander-outbox");
23386
+ return join20(homedir13(), ".linzumi", "commander-outbox");
22958
23387
  }
22959
23388
  function controlCursorStorePath(runnerId) {
22960
23389
  const sanitized = runnerId.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 80);
22961
23390
  const digest = createHash5("sha256").update(runnerId).digest("hex").slice(0, 8);
22962
23391
  const stem = sanitized === "" ? "runner" : sanitized;
22963
- return join18(
22964
- homedir12(),
23392
+ return join20(
23393
+ homedir13(),
22965
23394
  ".linzumi",
22966
23395
  "control-cursors",
22967
23396
  `${stem}.${digest}.json`
@@ -22971,8 +23400,8 @@ function appliedStartTurnStorePath(runnerId) {
22971
23400
  const sanitized = runnerId.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 80);
22972
23401
  const digest = createHash5("sha256").update(runnerId).digest("hex").slice(0, 8);
22973
23402
  const stem = sanitized === "" ? "runner" : sanitized;
22974
- return join18(
22975
- homedir12(),
23403
+ return join20(
23404
+ homedir13(),
22976
23405
  ".linzumi",
22977
23406
  "control-cursors",
22978
23407
  `${stem}.${digest}.start-turn.json`
@@ -23094,9 +23523,9 @@ function createControlCursorFileStore(path2, log2, options) {
23094
23523
  }
23095
23524
  dirty = false;
23096
23525
  try {
23097
- mkdirSync11(dirname13(path2), { recursive: true });
23526
+ mkdirSync12(dirname13(path2), { recursive: true });
23098
23527
  const tmpPath = `${path2}.tmp`;
23099
- writeFileSync10(
23528
+ writeFileSync11(
23100
23529
  tmpPath,
23101
23530
  `${JSON.stringify({
23102
23531
  ...epoch === void 0 ? {} : { [controlCursorEpochKey]: epoch },
@@ -23204,7 +23633,7 @@ function readControlCursorFile(path2, log2) {
23204
23633
  const cursors = /* @__PURE__ */ new Map();
23205
23634
  let raw;
23206
23635
  try {
23207
- raw = readFileSync15(path2, "utf8");
23636
+ raw = readFileSync16(path2, "utf8");
23208
23637
  } catch (error) {
23209
23638
  if (!isErrnoCode2(error, "ENOENT")) {
23210
23639
  log2("control_cursor_store.read_failed", {
@@ -23798,18 +24227,18 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
23798
24227
  return delegated;
23799
24228
  }
23800
24229
  if (agentProvider === "codex") {
23801
- const waferControlError = waferModelProviderControlError(
24230
+ const providerControlError = codexModelProviderControlError(
23802
24231
  options,
23803
24232
  control
23804
24233
  );
23805
- if (waferControlError !== void 0) {
24234
+ if (providerControlError !== void 0) {
23806
24235
  try {
23807
24236
  await publishStartInstanceMessageState(
23808
24237
  kandan,
23809
24238
  topic,
23810
24239
  control,
23811
24240
  "failed",
23812
- waferControlError,
24241
+ providerControlError,
23813
24242
  { instanceId }
23814
24243
  );
23815
24244
  } catch (error) {
@@ -23821,7 +24250,7 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
23821
24250
  instanceId,
23822
24251
  controlType: control.type,
23823
24252
  ok: false,
23824
- error: waferControlError
24253
+ error: providerControlError
23825
24254
  };
23826
24255
  }
23827
24256
  }
@@ -23969,16 +24398,16 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
23969
24398
  return delegated;
23970
24399
  }
23971
24400
  if (agentProvider === "codex") {
23972
- const waferControlError = waferModelProviderControlError(
24401
+ const providerControlError = codexModelProviderControlError(
23973
24402
  options,
23974
24403
  control
23975
24404
  );
23976
- if (waferControlError !== void 0) {
24405
+ if (providerControlError !== void 0) {
23977
24406
  return {
23978
24407
  instanceId,
23979
24408
  controlType: control.type,
23980
24409
  ok: false,
23981
- error: waferControlError
24410
+ error: providerControlError
23982
24411
  };
23983
24412
  }
23984
24413
  }
@@ -24044,10 +24473,28 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
24044
24473
  };
24045
24474
  }
24046
24475
  try {
24047
- activeSession.enqueueInput({
24476
+ const enqueueResult = activeSession.enqueueInput({
24048
24477
  content: contentResult.content,
24049
24478
  sourceSeq
24050
24479
  });
24480
+ if (enqueueResult === "duplicate") {
24481
+ log2("claude_code.message_duplicate_ignored", {
24482
+ linzumi_thread_id: optionalThreadControlField(control, "threadId") ?? null,
24483
+ claude_session_id: codexThreadId,
24484
+ body_preview: claudeConsoleBodyPreview(workDescription),
24485
+ source_seq: sourceSeq ?? null
24486
+ });
24487
+ return {
24488
+ instanceId,
24489
+ controlType: control.type,
24490
+ agentProvider: "claude-code",
24491
+ cwd: cwd.cwd,
24492
+ matchedRoot: cwd.matchedRoot,
24493
+ codexThreadId,
24494
+ queuedInput: true,
24495
+ duplicate: true
24496
+ };
24497
+ }
24051
24498
  log2("claude_code.message_queued", {
24052
24499
  linzumi_thread_id: optionalThreadControlField(control, "threadId") ?? null,
24053
24500
  claude_session_id: codexThreadId,
@@ -24299,18 +24746,30 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
24299
24746
  error: "claude_code_steer_requires_text_input"
24300
24747
  };
24301
24748
  }
24302
- await claudeSession.interruptTurn("Steered by Linzumi");
24303
- claudeSession.enqueueInput({
24304
- content: `You were interrupted mid-task. Updated guidance from the user - continue the task with this in mind:
24305
-
24306
- ${steerText}`,
24307
- sourceSeq: claudeSession.currentSourceSeq()
24308
- });
24749
+ let steered;
24750
+ try {
24751
+ steered = claudeSession.steerTurn(steerText);
24752
+ } catch (steerError) {
24753
+ const message = steerError instanceof Error ? steerError.message : String(steerError);
24754
+ log2("claude_code.steer_failed", {
24755
+ thread_id: control.threadId,
24756
+ message
24757
+ });
24758
+ return {
24759
+ instanceId,
24760
+ controlType: control.type,
24761
+ agentProvider: "claude-code",
24762
+ ok: false,
24763
+ error: "claude_code_steer_failed",
24764
+ message,
24765
+ threadId: control.threadId
24766
+ };
24767
+ }
24309
24768
  return {
24310
24769
  instanceId,
24311
24770
  controlType: control.type,
24312
24771
  agentProvider: "claude-code",
24313
- steered: "steered_via_restart",
24772
+ steered,
24314
24773
  threadId: control.threadId
24315
24774
  };
24316
24775
  }
@@ -24349,6 +24808,30 @@ ${steerText}`,
24349
24808
  response
24350
24809
  };
24351
24810
  }
24811
+ case "rewind_thread": {
24812
+ const claudeSession = activeClaudeCodeSessions.get(control.threadId);
24813
+ if (claudeSession !== void 0 || control.agentProvider === "claude-code") {
24814
+ return {
24815
+ instanceId,
24816
+ controlType: control.type,
24817
+ agentProvider: "claude-code",
24818
+ requestId: stringValue(control.requestId) ?? null,
24819
+ threadId: control.threadId,
24820
+ ok: false,
24821
+ error: "claude_code_rewind_unsupported",
24822
+ message: "Claude Code does not support rewind yet"
24823
+ };
24824
+ }
24825
+ return {
24826
+ instanceId,
24827
+ controlType: control.type,
24828
+ requestId: stringValue(control.requestId) ?? null,
24829
+ threadId: control.threadId,
24830
+ ok: false,
24831
+ error: "rewind_not_supported",
24832
+ message: "This runner does not support rewinding threads yet"
24833
+ };
24834
+ }
24352
24835
  case "interrupt_queued_messages": {
24353
24836
  const agentProvider = stringValue(control.agentProvider)?.trim();
24354
24837
  if (agentProvider !== "claude-code") {
@@ -24515,7 +24998,24 @@ ${steerText}`,
24515
24998
  };
24516
24999
  }
24517
25000
  case "stop_instance":
24518
- case "kill_instance":
25001
+ case "kill_instance": {
25002
+ const controlThreadId2 = "threadId" in control && typeof control.threadId === "string" ? control.threadId : void 0;
25003
+ const activeSession = controlThreadId2 === void 0 ? void 0 : activeClaudeCodeSessions.get(controlThreadId2);
25004
+ if (activeSession !== void 0) {
25005
+ await activeSession.interruptTurn("Claude Code stopped by Linzumi");
25006
+ activeSession.abortController.abort(
25007
+ new Error("Claude Code stopped by Linzumi")
25008
+ );
25009
+ return {
25010
+ instanceId,
25011
+ controlType: control.type,
25012
+ agentProvider: "claude-code",
25013
+ threadId: controlThreadId2,
25014
+ stopped: true
25015
+ };
25016
+ }
25017
+ return { instanceId, controlType: control.type, skipped: true };
25018
+ }
24519
25019
  case "resolve_port_forward_request":
24520
25020
  case "update_thread_interaction_access":
24521
25021
  case "set_port_forward_enabled":
@@ -24816,10 +25316,24 @@ function startInstanceAgentLabel(provider) {
24816
25316
  return "Claude Code";
24817
25317
  }
24818
25318
  }
24819
- function resolveControlWaferModelProvider(control) {
25319
+ function resolveControlCodexModelProvider(control) {
24820
25320
  const modelProvider = stringValue(control.modelProvider)?.trim();
25321
+ const llmProxy = objectValue(control.llmProxy);
25322
+ const baseUrl = stringValue(llmProxy?.baseUrl)?.trim();
25323
+ const token = stringValue(llmProxy?.token)?.trim();
25324
+ const binding = baseUrl !== void 0 && baseUrl !== "" && token !== void 0 && token !== "" ? { baseUrl, token } : void 0;
24821
25325
  if (modelProvider === void 0 || modelProvider === "") {
24822
- return { type: "none" };
25326
+ if (binding === void 0) {
25327
+ return { type: "none" };
25328
+ }
25329
+ return {
25330
+ type: "provider",
25331
+ runtime: {
25332
+ provider: "openai-proxy",
25333
+ llmProxyBaseUrl: binding.baseUrl,
25334
+ llmProxyToken: binding.token
25335
+ }
25336
+ };
24823
25337
  }
24824
25338
  if (modelProvider !== "wafer") {
24825
25339
  return {
@@ -24827,40 +25341,84 @@ function resolveControlWaferModelProvider(control) {
24827
25341
  error: `model_provider_unsupported:${modelProvider}`
24828
25342
  };
24829
25343
  }
24830
- const llmProxy = objectValue(control.llmProxy);
24831
- const baseUrl = stringValue(llmProxy?.baseUrl)?.trim();
24832
- const token = stringValue(llmProxy?.token)?.trim();
24833
- if (baseUrl === void 0 || baseUrl === "" || token === void 0 || token === "") {
25344
+ if (binding === void 0) {
24834
25345
  return { type: "error", error: "wafer_model_provider_missing_llm_proxy" };
24835
25346
  }
24836
25347
  return {
24837
- type: "wafer",
25348
+ type: "provider",
24838
25349
  runtime: {
24839
25350
  provider: "wafer",
24840
- llmProxyBaseUrl: baseUrl,
24841
- llmProxyToken: token
25351
+ llmProxyBaseUrl: binding.baseUrl,
25352
+ llmProxyToken: binding.token
24842
25353
  }
24843
25354
  };
24844
25355
  }
24845
- function waferModelProviderControlError(options, control) {
24846
- const resolution = resolveControlWaferModelProvider(control);
25356
+ function codexModelProviderResolutionError(resolution) {
25357
+ if (resolution.type === "error") {
25358
+ return resolution.error;
25359
+ }
25360
+ if (resolution.type === "provider" && resolution.runtime.provider === "openai-proxy" && resolveForwardableOpenAiApiKey() === void 0) {
25361
+ return "codex_llm_proxy_requires_openai_api_key";
25362
+ }
25363
+ return void 0;
25364
+ }
25365
+ function codexModelProviderControlError(options, control) {
25366
+ const resolution = resolveControlCodexModelProvider(control);
24847
25367
  switch (resolution.type) {
24848
25368
  case "none":
24849
25369
  return void 0;
24850
25370
  case "error":
24851
25371
  return resolution.error;
24852
- case "wafer":
24853
- return options.codexModelProvider?.provider === "wafer" ? void 0 : "wafer_model_provider_requires_thread_worker";
25372
+ case "provider": {
25373
+ const gateError = codexModelProviderResolutionError(resolution);
25374
+ if (gateError !== void 0) {
25375
+ return gateError;
25376
+ }
25377
+ return options.codexModelProvider?.provider === resolution.runtime.provider ? void 0 : resolution.runtime.provider === "wafer" ? "wafer_model_provider_requires_thread_worker" : "llm_proxy_model_provider_requires_thread_worker";
25378
+ }
24854
25379
  }
24855
25380
  }
24856
25381
  function linzumiCodexModelProviderConfig(runtime) {
24857
- return {
24858
- id: "linzumi",
24859
- name: "Linzumi Proxy",
24860
- baseUrl: `${runtime.llmProxyBaseUrl.replace(/\/+$/, "")}/v1`,
24861
- envKey: "LINZUMI_LLM_PROXY_TOKEN",
24862
- wireApi: "responses"
24863
- };
25382
+ const baseUrl = `${runtime.llmProxyBaseUrl.replace(/\/+$/, "")}/v1`;
25383
+ switch (runtime.provider) {
25384
+ case "wafer":
25385
+ return {
25386
+ id: "linzumi",
25387
+ name: "Linzumi Proxy",
25388
+ baseUrl,
25389
+ envKey: "LINZUMI_LLM_PROXY_TOKEN",
25390
+ wireApi: "responses"
25391
+ };
25392
+ case "openai-proxy":
25393
+ return {
25394
+ id: "linzumi",
25395
+ name: "Linzumi Proxy",
25396
+ baseUrl,
25397
+ envKey: "OPENAI_API_KEY",
25398
+ wireApi: "responses",
25399
+ envHttpHeaders: {
25400
+ "x-linzumi-llm-proxy-token": "LINZUMI_LLM_PROXY_TOKEN"
25401
+ }
25402
+ };
25403
+ }
25404
+ }
25405
+ function codexModelProviderAppServerEnv(runtime) {
25406
+ switch (runtime.provider) {
25407
+ case "wafer":
25408
+ return { LINZUMI_LLM_PROXY_TOKEN: runtime.llmProxyToken };
25409
+ case "openai-proxy": {
25410
+ const openAiApiKey = resolveForwardableOpenAiApiKey();
25411
+ if (openAiApiKey === void 0) {
25412
+ throw new Error(
25413
+ "codex llm proxy requires API-key auth (OPENAI_API_KEY in the environment or $CODEX_HOME/auth.json); ChatGPT OAuth credentials cannot be forwarded"
25414
+ );
25415
+ }
25416
+ return {
25417
+ LINZUMI_LLM_PROXY_TOKEN: runtime.llmProxyToken,
25418
+ OPENAI_API_KEY: openAiApiKey
25419
+ };
25420
+ }
25421
+ }
24864
25422
  }
24865
25423
  async function startCodexProviderInstance(args) {
24866
25424
  if (args.options.codexUrl === void 0) {
@@ -24957,10 +25515,10 @@ function createClaudeCodeInputQueue(input) {
24957
25515
  claudeCodeUserInputMessage(input.content)
24958
25516
  ];
24959
25517
  const pendingSourceSeqs = [input.sourceSeq];
25518
+ const deferredFollowUps = [];
24960
25519
  const waiters = [];
24961
25520
  const state = {
24962
- closed: false,
24963
- queuedTurnCount: 1
25521
+ closed: false
24964
25522
  };
24965
25523
  const drainClosedWaiters = () => {
24966
25524
  while (state.closed) {
@@ -24971,19 +25529,42 @@ function createClaudeCodeInputQueue(input) {
24971
25529
  waiter({ done: true, value: void 0 });
24972
25530
  }
24973
25531
  };
25532
+ const deliverNow = (message, sourceSeq) => {
25533
+ pendingSourceSeqs.push(sourceSeq);
25534
+ const waiter = waiters.shift();
25535
+ if (waiter === void 0) {
25536
+ pendingMessages.push(message);
25537
+ return;
25538
+ }
25539
+ waiter({ done: false, value: message });
25540
+ };
24974
25541
  const enqueue = (next) => {
24975
25542
  if (state.closed) {
24976
25543
  throw new Error("Claude Code streaming input is closed");
24977
25544
  }
24978
25545
  const message = claudeCodeUserInputMessage(next.content);
24979
- pendingSourceSeqs.push(next.sourceSeq);
24980
- state.queuedTurnCount += 1;
25546
+ if (pendingSourceSeqs.length > 0) {
25547
+ deferredFollowUps.push({ message, sourceSeq: next.sourceSeq });
25548
+ return;
25549
+ }
25550
+ deliverNow(message, next.sourceSeq);
25551
+ };
25552
+ const enqueueSteer = (content) => {
25553
+ if (state.closed) {
25554
+ throw new Error("Claude Code streaming input is closed");
25555
+ }
25556
+ if (pendingSourceSeqs.length === 0) {
25557
+ enqueue({ content, sourceSeq: void 0 });
25558
+ return "steered_queued";
25559
+ }
25560
+ const message = claudeCodeUserInputMessage(content);
24981
25561
  const waiter = waiters.shift();
24982
25562
  if (waiter === void 0) {
24983
25563
  pendingMessages.push(message);
24984
- return;
25564
+ } else {
25565
+ waiter({ done: false, value: message });
24985
25566
  }
24986
- waiter({ done: false, value: message });
25567
+ return "steered_live";
24987
25568
  };
24988
25569
  return {
24989
25570
  messages: {
@@ -25004,13 +25585,30 @@ function createClaudeCodeInputQueue(input) {
25004
25585
  };
25005
25586
  }
25006
25587
  },
25007
- queuedTurnCount: () => state.queuedTurnCount,
25008
25588
  close: () => {
25589
+ if (pendingSourceSeqs.length === 0) {
25590
+ while (deferredFollowUps.length > 0) {
25591
+ const followUp = deferredFollowUps.shift();
25592
+ if (followUp !== void 0) {
25593
+ deliverNow(followUp.message, followUp.sourceSeq);
25594
+ }
25595
+ }
25596
+ }
25009
25597
  state.closed = true;
25010
25598
  drainClosedWaiters();
25011
25599
  },
25012
25600
  enqueue,
25013
- completeTurn: () => pendingSourceSeqs.shift(),
25601
+ enqueueSteer,
25602
+ completeTurn: () => {
25603
+ const completed = pendingSourceSeqs.shift();
25604
+ if (!state.closed && pendingSourceSeqs.length === 0) {
25605
+ const nextFollowUp = deferredFollowUps.shift();
25606
+ if (nextFollowUp !== void 0) {
25607
+ deliverNow(nextFollowUp.message, nextFollowUp.sourceSeq);
25608
+ }
25609
+ }
25610
+ return completed;
25611
+ },
25014
25612
  currentSourceSeq: () => pendingSourceSeqs[0]
25015
25613
  };
25016
25614
  }
@@ -25258,6 +25856,11 @@ async function startClaudeCodeProviderInstance(args) {
25258
25856
  codexVersion: void 0
25259
25857
  };
25260
25858
  const abortController = new AbortController();
25859
+ const acceptedSourceSeqs = new Set(
25860
+ sourceSeq === void 0 ? [] : [sourceSeq]
25861
+ );
25862
+ const sessionWorkHandle = { value: void 0 };
25863
+ let startControlResponded = false;
25261
25864
  let activeSessionId;
25262
25865
  let sessionControls;
25263
25866
  const planMirrorClient = createLinzumiMcpApiClient({
@@ -25331,6 +25934,24 @@ async function startClaudeCodeProviderInstance(args) {
25331
25934
  onTodoWriteCompleted: planMirror.handleTodoWrite,
25332
25935
  log: args.log
25333
25936
  });
25937
+ const liveBashCapture = args.options.claudeCodeRunner === void 0 && claudeLiveBashCaptureEnabled(process.env) ? createClaudeCodeLiveBashCapture({
25938
+ captureDir: join20(
25939
+ tmpdir3(),
25940
+ `linzumi-claude-live-bash-${args.instanceId}`
25941
+ ),
25942
+ onOutputDelta: (toolUseId, delta) => {
25943
+ if (activeSessionId === void 0) {
25944
+ return;
25945
+ }
25946
+ adapter.handleTranscriptEvent({
25947
+ type: "command_output_delta",
25948
+ sessionId: activeSessionId,
25949
+ itemKey: toolUseId,
25950
+ delta
25951
+ });
25952
+ },
25953
+ log: (event, fields) => args.log(event, fields)
25954
+ }) : void 0;
25334
25955
  let mcpAuthCleanup;
25335
25956
  let mcpServers;
25336
25957
  try {
@@ -25374,7 +25995,7 @@ async function startClaudeCodeProviderInstance(args) {
25374
25995
  rootSeq,
25375
25996
  log: args.log
25376
25997
  };
25377
- let lastRateLimitSignature;
25998
+ const lastRateLimitSignatureByWindow = /* @__PURE__ */ new Map();
25378
25999
  const reportClaudeCodeRateLimit = async (event) => {
25379
26000
  const nowMs = Date.now();
25380
26001
  const summary = claudeCodeRateLimitSummaryText(event.rateLimit, nowMs);
@@ -25390,13 +26011,13 @@ async function startClaudeCodeProviderInstance(args) {
25390
26011
  utilization_percent: event.rateLimit.utilizationPercent ?? null,
25391
26012
  resets_at_ms: event.rateLimit.resetsAtMs ?? null
25392
26013
  });
26014
+ const windowKey = event.rateLimit.rateLimitType ?? "account";
25393
26015
  const signature = claudeRateLimitSignature(event.rateLimit);
25394
- if (signature === lastRateLimitSignature) {
26016
+ if (signature === lastRateLimitSignatureByWindow.get(windowKey)) {
25395
26017
  return;
25396
26018
  }
25397
- lastRateLimitSignature = signature;
25398
26019
  try {
25399
- await postClaudeCodeRateLimitMessage({
26020
+ await publishClaudeCodeRateLimitState({
25400
26021
  kandan: args.kandan,
25401
26022
  topic: args.topic,
25402
26023
  workspace,
@@ -25405,6 +26026,7 @@ async function startClaudeCodeProviderInstance(args) {
25405
26026
  claudeSessionId: event.sessionId ?? activeSessionId,
25406
26027
  rateLimit: event.rateLimit
25407
26028
  });
26029
+ lastRateLimitSignatureByWindow.set(windowKey, signature);
25408
26030
  } catch (error) {
25409
26031
  args.log("claude_code.rate_limit_post_failed", {
25410
26032
  thread_id: threadId,
@@ -25412,6 +26034,10 @@ async function startClaudeCodeProviderInstance(args) {
25412
26034
  });
25413
26035
  }
25414
26036
  };
26037
+ let settleFirstTurn = () => void 0;
26038
+ const firstTurnSettled = new Promise((resolve12) => {
26039
+ settleFirstTurn = resolve12;
26040
+ });
25415
26041
  const onTranscriptEvent = async (event) => {
25416
26042
  try {
25417
26043
  await mirrorClaudeSessionStoreAppend(mirrorArgs, event);
@@ -25434,7 +26060,20 @@ async function startClaudeCodeProviderInstance(args) {
25434
26060
  channel,
25435
26061
  threadId,
25436
26062
  currentSourceSeq: inputQueue.currentSourceSeq,
25437
- enqueueInput: inputQueue.enqueue,
26063
+ enqueueInput: (input) => {
26064
+ if (input.sourceSeq !== void 0 && acceptedSourceSeqs.has(input.sourceSeq)) {
26065
+ return "duplicate";
26066
+ }
26067
+ inputQueue.enqueue(input);
26068
+ if (input.sourceSeq !== void 0) {
26069
+ acceptedSourceSeqs.add(input.sourceSeq);
26070
+ }
26071
+ return "queued";
26072
+ },
26073
+ closeInput: inputQueue.close,
26074
+ hasActiveTurn: () => adapter.activeTurnId() !== void 0,
26075
+ sessionWork: () => sessionWorkHandle.value,
26076
+ steerTurn: inputQueue.enqueueSteer,
25438
26077
  interruptTurn: async (reason) => {
25439
26078
  const aborted = adapter.interruptActiveTurn(reason);
25440
26079
  await sessionControls?.interrupt();
@@ -25489,10 +26128,30 @@ async function startClaudeCodeProviderInstance(args) {
25489
26128
  claude_session_id: event.sessionId,
25490
26129
  body_preview: claudeConsoleBodyPreview(event.body)
25491
26130
  });
26131
+ settleFirstTurn();
26132
+ }
26133
+ if (event.type === "turn_interrupted") {
26134
+ settleFirstTurn();
25492
26135
  }
25493
26136
  if (event.type === "rate_limit") {
25494
26137
  await reportClaudeCodeRateLimit(event);
25495
26138
  }
26139
+ if (event.type === "tool_result") {
26140
+ liveBashCapture?.settleTool(event.itemKey);
26141
+ }
26142
+ if (event.type === "turn_interrupted" || event.type === "session_failed") {
26143
+ liveBashCapture?.settleAll();
26144
+ }
26145
+ if (event.type === "usage") {
26146
+ const summary = claudeCodeTokenUsageSummaryText(event.usage);
26147
+ if (summary !== void 0) {
26148
+ args.log("claude_code.token_usage", {
26149
+ linzumi_thread_id: threadId,
26150
+ claude_session_id: event.sessionId,
26151
+ token_usage_summary: summary
26152
+ });
26153
+ }
26154
+ }
25496
26155
  adapter.handleTranscriptEvent(event);
25497
26156
  };
25498
26157
  const llmProxy = objectValue(args.control.llmProxy);
@@ -25519,75 +26178,97 @@ async function startClaudeCodeProviderInstance(args) {
25519
26178
  request,
25520
26179
  signal
25521
26180
  });
25522
- let result;
25523
- try {
26181
+ const runSession = async () => {
26182
+ let result2;
25524
26183
  try {
25525
- result = await startClaudeCodeSession({
25526
- cwd: args.cwd,
25527
- prompt: workDescription,
25528
- developerInstructions: commanderDeveloperInstructions({
26184
+ try {
26185
+ result2 = await startClaudeCodeSession({
25529
26186
  cwd: args.cwd,
25530
- agentLabel: "Claude Code",
25531
- planTool: "todo-write",
25532
- developerPrompt,
25533
- linzumiContext
25534
- }),
25535
- model: claudeCodeModelForRuntimeModel(runtimeSettings.model),
25536
- resumeSessionId: args.resumeSessionId,
25537
- abortController,
25538
- streamingInput: inputQueue,
25539
- runner: args.options.claudeCodeRunner,
25540
- canUseTool,
25541
- ...mcpServers === void 0 ? {} : { mcpServers },
25542
- env: sessionEnv,
25543
- // The built-in Linzumi MCP is trusted like the codex side: its tools
25544
- // run without an approval round-trip. SDK allowedTools matches MCP
25545
- // tools as mcp__<server>__<tool>; the __* suffix covers the server.
25546
- allowedTools: ["mcp__linzumi__*"],
25547
- onSessionControls: (controls) => {
25548
- sessionControls = controls;
25549
- },
25550
- onTurnCompleted: () => {
25551
- inputQueue.completeTurn();
25552
- },
25553
- onTranscriptEvent
25554
- });
25555
- } finally {
25556
- inputQueue.close();
25557
- mcpAuthCleanup?.();
25558
- if (activeSessionId !== void 0) {
25559
- args.activeClaudeCodeSessions.delete(activeSessionId);
25560
- await args.disposeClaudeCodeForwardPortSession?.(activeSessionId);
26187
+ prompt: workDescription,
26188
+ developerInstructions: commanderDeveloperInstructions({
26189
+ cwd: args.cwd,
26190
+ agentLabel: "Claude Code",
26191
+ planTool: "todo-write",
26192
+ developerPrompt,
26193
+ linzumiContext
26194
+ }),
26195
+ model: claudeCodeModelForRuntimeModel(runtimeSettings.model),
26196
+ resumeSessionId: args.resumeSessionId,
26197
+ abortController,
26198
+ streamingInput: inputQueue,
26199
+ runner: args.options.claudeCodeRunner,
26200
+ canUseTool,
26201
+ ...mcpServers === void 0 ? {} : { mcpServers },
26202
+ ...liveBashCapture === void 0 ? {} : {
26203
+ preToolUseHookMatchers: liveBashCapture.hookMatchers,
26204
+ wrapApprovedToolInput: (toolUseId, toolName2, input) => toolName2 === "Bash" ? liveBashCapture.wrapApprovedTool(toolUseId, input) : void 0
26205
+ },
26206
+ env: sessionEnv,
26207
+ // The built-in Linzumi MCP is trusted like the codex side: its tools
26208
+ // run without an approval round-trip. SDK allowedTools matches MCP
26209
+ // tools as mcp__<server>__<tool>; the __* suffix covers the server.
26210
+ allowedTools: ["mcp__linzumi__*"],
26211
+ onSessionControls: (controls) => {
26212
+ sessionControls = controls;
26213
+ },
26214
+ onTurnCompleted: () => {
26215
+ inputQueue.completeTurn();
26216
+ settleFirstTurn();
26217
+ },
26218
+ onTranscriptEvent
26219
+ });
26220
+ } finally {
26221
+ inputQueue.close();
26222
+ mcpAuthCleanup?.();
26223
+ liveBashCapture?.close();
26224
+ if (activeSessionId !== void 0) {
26225
+ args.activeClaudeCodeSessions.delete(activeSessionId);
26226
+ await args.disposeClaudeCodeForwardPortSession?.(activeSessionId);
26227
+ }
25561
26228
  }
26229
+ } catch (error) {
26230
+ adapter.submitLifecycle(
26231
+ "codexDied",
26232
+ error instanceof Error ? error.message : String(error)
26233
+ );
26234
+ await adapter.close(5e3).catch(() => void 0);
26235
+ await Promise.race([
26236
+ planMirror.settle().catch(() => void 0),
26237
+ new Promise((resolve12) => {
26238
+ setTimeout(resolve12, 5e3).unref?.();
26239
+ })
26240
+ ]);
26241
+ logStartFailureTerminal(
26242
+ error instanceof Error ? error.message : String(error)
26243
+ );
26244
+ if (!startControlResponded) {
26245
+ args.setStartupStage("claude_code_session_failed");
26246
+ }
26247
+ throw error;
25562
26248
  }
25563
- } catch (error) {
25564
- adapter.submitLifecycle(
25565
- "codexDied",
25566
- error instanceof Error ? error.message : String(error)
25567
- );
25568
- await adapter.close(5e3).catch(() => void 0);
26249
+ if (!startControlResponded) {
26250
+ args.setStartupStage("posting_claude_code_output");
26251
+ }
26252
+ await adapter.awaitTurnsSettled(3e4);
26253
+ await adapter.close(3e4);
25569
26254
  await Promise.race([
25570
- planMirror.settle().catch(() => void 0),
26255
+ planMirror.settle(),
25571
26256
  new Promise((resolve12) => {
25572
- setTimeout(resolve12, 5e3).unref?.();
26257
+ setTimeout(resolve12, 1e4).unref?.();
25573
26258
  })
25574
26259
  ]);
25575
- logStartFailureTerminal(
25576
- error instanceof Error ? error.message : String(error)
25577
- );
25578
- args.setStartupStage("claude_code_session_failed");
25579
- throw error;
25580
- }
25581
- args.setStartupStage("posting_claude_code_output");
25582
- await adapter.awaitTurnsSettled(3e4);
25583
- await adapter.close(3e4);
25584
- await Promise.race([
25585
- planMirror.settle(),
25586
- new Promise((resolve12) => {
25587
- setTimeout(resolve12, 1e4).unref?.();
25588
- })
26260
+ return result2;
26261
+ };
26262
+ const sessionWork = runSession();
26263
+ sessionWorkHandle.value = sessionWork;
26264
+ const settled = await Promise.race([
26265
+ sessionWork.then((result2) => ({
26266
+ type: "session_ended",
26267
+ result: result2
26268
+ })),
26269
+ firstTurnSettled.then(() => ({ type: "first_turn_settled" }))
25589
26270
  ]);
25590
- return {
26271
+ const respondWithSessionId = (sessionId) => ({
25591
26272
  controlResponse: {
25592
26273
  instanceId: args.instanceId,
25593
26274
  controlType: args.control.type,
@@ -25595,16 +26276,52 @@ async function startClaudeCodeProviderInstance(args) {
25595
26276
  cwd: args.cwd,
25596
26277
  matchedRoot: args.matchedRoot,
25597
26278
  response: {
25598
- session: { id: result.sessionId }
26279
+ session: { id: sessionId }
25599
26280
  }
25600
26281
  },
25601
26282
  providerSession: {
25602
26283
  provider: "claude-code",
25603
26284
  cwd: args.cwd,
25604
26285
  matchedRoot: args.matchedRoot,
25605
- sessionId: result.sessionId
26286
+ sessionId
25606
26287
  }
25607
- };
26288
+ });
26289
+ if (settled.type === "session_ended") {
26290
+ return respondWithSessionId(settled.result.sessionId);
26291
+ }
26292
+ args.setStartupStage("posting_claude_code_output");
26293
+ startControlResponded = true;
26294
+ await adapter.awaitTurnsSettled(3e4);
26295
+ try {
26296
+ await adapter.flush(3e4);
26297
+ } catch (error) {
26298
+ args.log("claude_code.first_turn_flush_timeout", {
26299
+ linzumi_thread_id: threadId,
26300
+ claude_session_id: activeSessionId ?? null,
26301
+ message: error instanceof Error ? error.message : String(error)
26302
+ });
26303
+ }
26304
+ void sessionWork.then(
26305
+ () => {
26306
+ args.log("claude_code.session_loop_ended", {
26307
+ linzumi_thread_id: threadId,
26308
+ claude_session_id: activeSessionId ?? null
26309
+ });
26310
+ },
26311
+ (error) => {
26312
+ args.log("claude_code.session_loop_failed", {
26313
+ linzumi_thread_id: threadId,
26314
+ claude_session_id: activeSessionId ?? null,
26315
+ message: error instanceof Error ? error.message : String(error)
26316
+ });
26317
+ }
26318
+ );
26319
+ const liveSessionId = activeSessionId ?? args.resumeSessionId;
26320
+ if (liveSessionId !== void 0) {
26321
+ return respondWithSessionId(liveSessionId);
26322
+ }
26323
+ const result = await sessionWork;
26324
+ return respondWithSessionId(result.sessionId);
25608
26325
  }
25609
26326
  function claudePermissionModeForApprovalPolicy(approvalPolicy) {
25610
26327
  switch (approvalPolicy) {
@@ -25710,6 +26427,8 @@ function claudeSessionStoreEntryPayload(args, event) {
25710
26427
  itemKey: event.itemKey,
25711
26428
  body: event.content
25712
26429
  };
26430
+ case "command_output_delta":
26431
+ return void 0;
25713
26432
  case "usage":
25714
26433
  return { usage: event.usage };
25715
26434
  case "rate_limit":
@@ -25844,50 +26563,26 @@ function claudeRateLimitSignature(rateLimit) {
25844
26563
  rateLimit.resetsAtMs ?? "na"
25845
26564
  ].join(":");
25846
26565
  }
25847
- async function postClaudeCodeRateLimitMessage(args) {
25848
- const nowMs = Date.now();
25849
- const summary = claudeCodeRateLimitSummaryText(args.rateLimit, nowMs);
25850
- const headline = `Claude Code rate limit: ${summary}`;
25851
- const resetLabel = claudeCodeRateLimitResetLabel(
25852
- args.rateLimit.resetsAtMs,
25853
- nowMs
25854
- );
25855
- const richUi = args.rateLimit.utilizationPercent === void 0 ? [{ primitive: "label", label: headline }] : [
25856
- {
25857
- primitive: "progress",
25858
- value: Math.min(
25859
- 100,
25860
- Math.max(0, Math.round(args.rateLimit.utilizationPercent))
25861
- ),
25862
- max: 100,
25863
- label: `Claude Code rate limit${resetLabel === void 0 ? "" : ` - ${resetLabel}`}`
25864
- }
25865
- ];
25866
- await args.kandan.push(args.topic, "session:post_thread_message", {
26566
+ async function publishClaudeCodeRateLimitState(args) {
26567
+ await args.kandan.push(args.topic, "claude_rate_limit_state", {
25867
26568
  workspace: args.workspace,
25868
26569
  channel: args.channel,
25869
26570
  thread_id: args.threadId,
25870
- body: headline,
25871
- payload: {
25872
- rich_ui: richUi,
25873
- metadata: {
25874
- local_codex_runner: {
25875
- event_type: "claude_code_rate_limit",
25876
- agent_provider: "claude-code",
25877
- ...args.claudeSessionId === void 0 ? {} : { claude_session_id: args.claudeSessionId }
25878
- }
25879
- }
26571
+ agent_provider: "claude-code",
26572
+ ...args.claudeSessionId === void 0 ? {} : { claude_session_id: args.claudeSessionId },
26573
+ // "account" mirrors the server-side default for SDK frames that omit a
26574
+ // window type; sending it explicitly keeps the wire contract obvious.
26575
+ rate_limit_type: args.rateLimit.rateLimitType ?? "account",
26576
+ status: args.rateLimit.status ?? "allowed",
26577
+ ...args.rateLimit.utilizationPercent === void 0 ? {} : {
26578
+ utilization_percent: Math.min(
26579
+ 100,
26580
+ Math.max(0, Math.round(args.rateLimit.utilizationPercent))
26581
+ )
25880
26582
  },
25881
- client_message_id: claudeRateLimitClientMessageId(
25882
- args.threadId,
25883
- args.rateLimit
25884
- )
26583
+ ...args.rateLimit.resetsAtMs === void 0 ? {} : { resets_at_ms: args.rateLimit.resetsAtMs }
25885
26584
  });
25886
26585
  }
25887
- function claudeRateLimitClientMessageId(threadId, rateLimit) {
25888
- const digest = createHash5("sha256").update(`${threadId}:${claudeRateLimitSignature(rateLimit)}`).digest("hex").slice(0, 32);
25889
- return `claude-rate-limit-${digest}`;
25890
- }
25891
26586
  async function publishStartInstanceMessageState(kandan, topic, control, status, reason, diagnostics = {}) {
25892
26587
  const payload = startInstanceMessageStatePayload(
25893
26588
  control,
@@ -26128,7 +26823,7 @@ function threadRunnerOptions(args) {
26128
26823
  args.options,
26129
26824
  args.control
26130
26825
  );
26131
- const waferResolution = resolveControlWaferModelProvider(args.control);
26826
+ const providerResolution = resolveControlCodexModelProvider(args.control);
26132
26827
  return {
26133
26828
  ...args.options,
26134
26829
  clientId: void 0,
@@ -26145,7 +26840,7 @@ function threadRunnerOptions(args) {
26145
26840
  role: "thread",
26146
26841
  kandanThreadId: args.kandanThreadId
26147
26842
  },
26148
- codexModelProvider: waferResolution.type === "wafer" ? waferResolution.runtime : void 0,
26843
+ codexModelProvider: providerResolution.type === "provider" ? providerResolution.runtime : void 0,
26149
26844
  spawnThreadRunner: void 0,
26150
26845
  threadRunnerReadyTimeoutMs: args.options.threadRunnerReadyTimeoutMs,
26151
26846
  runtimeDefaults: {
@@ -26182,6 +26877,7 @@ async function spawnLocalThreadRunnerProcess(options) {
26182
26877
  scriptPath,
26183
26878
  redactedThreadRunnerCliArgs(args)
26184
26879
  );
26880
+ const forwardableOpenAiApiKey = options.codexModelProvider?.provider === "openai-proxy" ? resolveForwardableOpenAiApiKey() : void 0;
26185
26881
  const env = {
26186
26882
  ...process.env,
26187
26883
  LINZUMI_THREAD_RUNNER_ROLE: "thread",
@@ -26189,7 +26885,8 @@ async function spawnLocalThreadRunnerProcess(options) {
26189
26885
  LINZUMI_THREAD_RUNNER_TOKEN: options.token,
26190
26886
  // The LLM proxy credential travels via env (like the runner token), not
26191
26887
  // argv, so the spawned worker's command line never carries it.
26192
- ...options.codexModelProvider === void 0 ? {} : { LINZUMI_LLM_PROXY_TOKEN: options.codexModelProvider.llmProxyToken }
26888
+ ...options.codexModelProvider === void 0 ? {} : { LINZUMI_LLM_PROXY_TOKEN: options.codexModelProvider.llmProxyToken },
26889
+ ...forwardableOpenAiApiKey === void 0 ? {} : { OPENAI_API_KEY: forwardableOpenAiApiKey }
26193
26890
  };
26194
26891
  writeCliAuditEvent("process.spawn", {
26195
26892
  command: process.execPath,
@@ -27395,16 +28092,16 @@ async function startOwnedCodexAppServer(options, args = { linzumiMcp: true }) {
27395
28092
  model: defaults.model,
27396
28093
  reasoningEffort: defaults.reasoningEffort,
27397
28094
  fast: options.fast,
27398
- // Wafer-routed thread workers point their owned app-server at the
27399
- // Kandan LLM proxy via a custom Linzumi model provider; the proxy
27400
- // credential rides env_key plus the session header.
28095
+ // Proxy-routed thread workers point their owned app-server at the
28096
+ // Kandan LLM proxy via a custom Linzumi model provider. Wafer routes
28097
+ // ride the session token as the bearer; openai-proxy routes (parity
28098
+ // backlog item 50) additionally materialize the user's own
28099
+ // OPENAI_API_KEY as the passthrough upstream credential.
27401
28100
  ...options.codexModelProvider === void 0 ? {} : {
27402
28101
  modelProvider: linzumiCodexModelProviderConfig(
27403
28102
  options.codexModelProvider
27404
28103
  ),
27405
- env: {
27406
- LINZUMI_LLM_PROXY_TOKEN: options.codexModelProvider.llmProxyToken
27407
- }
28104
+ env: codexModelProviderAppServerEnv(options.codexModelProvider)
27408
28105
  },
27409
28106
  mcpServers: mcpAuth === void 0 ? [] : [
27410
28107
  linzumiMcpServerConfig({
@@ -27452,9 +28149,9 @@ function mcpOwnerUsername(options) {
27452
28149
  return options.channelSession?.listenUser ?? identityFromAccessToken(options.token).actorUsername;
27453
28150
  }
27454
28151
  function writeEphemeralMcpAuthFile(options) {
27455
- const directory = mkdtempSync4(join18(tmpdir3(), "linzumi-mcp-auth-"));
28152
+ const directory = mkdtempSync4(join20(tmpdir3(), "linzumi-mcp-auth-"));
27456
28153
  chmodSync2(directory, 448);
27457
- const path2 = join18(directory, "auth.json");
28154
+ const path2 = join20(directory, "auth.json");
27458
28155
  writeCachedLocalRunnerToken({
27459
28156
  kandanUrl: options.kandanUrl,
27460
28157
  accessToken: options.token,
@@ -27463,7 +28160,7 @@ function writeEphemeralMcpAuthFile(options) {
27463
28160
  chmodSync2(path2, 384);
27464
28161
  return {
27465
28162
  path: path2,
27466
- cleanup: () => rmSync4(directory, { recursive: true, force: true })
28163
+ cleanup: () => rmSync5(directory, { recursive: true, force: true })
27467
28164
  };
27468
28165
  }
27469
28166
  function once(action) {
@@ -27530,7 +28227,7 @@ function configuredAllowedCwds(values, options = {}) {
27530
28227
  const absolutePath = resolve8(expandUserPath(value));
27531
28228
  try {
27532
28229
  if (options.createMissing === true) {
27533
- mkdirSync11(absolutePath, { recursive: true });
28230
+ mkdirSync12(absolutePath, { recursive: true });
27534
28231
  }
27535
28232
  const realPath = realpathSync6(absolutePath);
27536
28233
  allowedCwds.push(
@@ -27567,7 +28264,7 @@ function allowedCwdProjects(allowedCwds) {
27567
28264
  });
27568
28265
  }
27569
28266
  function isGitProjectDirectory(cwd) {
27570
- const gitPath = join18(cwd, ".git");
28267
+ const gitPath = join20(cwd, ".git");
27571
28268
  try {
27572
28269
  const gitPathStats = statSync3(gitPath);
27573
28270
  return gitPathStats.isDirectory() || gitPathStats.isFile();
@@ -27592,7 +28289,7 @@ function browseRunnerDirectory(control, options) {
27592
28289
  }
27593
28290
  const parent = dirname13(currentPath);
27594
28291
  const entries = readdirSync4(currentPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => visibleRunnerDirectoryEntryName(entry.name)).map((entry) => {
27595
- const path2 = join18(currentPath, entry.name);
28292
+ const path2 = join20(currentPath, entry.name);
27596
28293
  return {
27597
28294
  name: entry.name,
27598
28295
  path: path2,
@@ -27633,7 +28330,7 @@ function projectDirectoryName(name) {
27633
28330
  function availableProjectDirectoryName(projectsRoot, baseName, suffix = 0) {
27634
28331
  for (let nextSuffix = suffix; ; nextSuffix += 1) {
27635
28332
  const candidate = nextSuffix === 0 ? baseName : `${baseName}-${nextSuffix}`;
27636
- if (!projectPathExists(join18(projectsRoot, candidate))) {
28333
+ if (!projectPathExists(join20(projectsRoot, candidate))) {
27637
28334
  return candidate;
27638
28335
  }
27639
28336
  }
@@ -27661,9 +28358,9 @@ function createRunnerProject(control, options, allowedCwds) {
27661
28358
  error: "invalid_project_template"
27662
28359
  };
27663
28360
  }
27664
- const projectsRoot = join18(currentHomeDirectory(), "linzumi");
28361
+ const projectsRoot = join20(currentHomeDirectory(), "linzumi");
27665
28362
  const resolvedProjectDirName = template === "hello_linzumi_demo" ? availableProjectDirectoryName(projectsRoot, projectDirName) : projectDirName;
27666
- const projectPath = join18(projectsRoot, resolvedProjectDirName);
28363
+ const projectPath = join20(projectsRoot, resolvedProjectDirName);
27667
28364
  let createdProjectPath = false;
27668
28365
  try {
27669
28366
  if (template !== "hello_linzumi_demo" && projectPathExists(projectPath)) {
@@ -27675,7 +28372,7 @@ function createRunnerProject(control, options, allowedCwds) {
27675
28372
  error: "project_directory_exists"
27676
28373
  };
27677
28374
  }
27678
- mkdirSync11(projectsRoot, { recursive: true });
28375
+ mkdirSync12(projectsRoot, { recursive: true });
27679
28376
  if (template === "hello_linzumi_demo") {
27680
28377
  createdProjectPath = true;
27681
28378
  createHelloLinzumiProject({
@@ -27683,7 +28380,7 @@ function createRunnerProject(control, options, allowedCwds) {
27683
28380
  name: resolvedProjectDirName
27684
28381
  });
27685
28382
  } else {
27686
- mkdirSync11(projectPath, { recursive: false });
28383
+ mkdirSync12(projectPath, { recursive: false });
27687
28384
  createdProjectPath = true;
27688
28385
  }
27689
28386
  const git = spawnSync5("git", ["init"], {
@@ -27741,7 +28438,7 @@ function createRunnerProject(control, options, allowedCwds) {
27741
28438
  }
27742
28439
  function removeCreatedProjectDirectory(projectPath) {
27743
28440
  try {
27744
- rmSync4(projectPath, { recursive: true, force: true });
28441
+ rmSync5(projectPath, { recursive: true, force: true });
27745
28442
  return void 0;
27746
28443
  } catch (error) {
27747
28444
  return error instanceof Error ? error.message : "cleanup_failed";
@@ -27805,6 +28502,7 @@ var init_runner = __esm({
27805
28502
  init_commanderAttachments();
27806
28503
  init_claudeCodePipeline();
27807
28504
  init_claudeCodePlanMirror();
28505
+ init_claudeCodeLiveBashOutput();
27808
28506
  init_claudeCodeSession();
27809
28507
  init_codexAppServer();
27810
28508
  init_codexProjectTrust();
@@ -27866,7 +28564,7 @@ var init_runner = __esm({
27866
28564
  });
27867
28565
 
27868
28566
  // src/kandanTls.ts
27869
- import { existsSync as existsSync13, readFileSync as readFileSync16 } from "node:fs";
28567
+ import { existsSync as existsSync13, readFileSync as readFileSync17 } from "node:fs";
27870
28568
  import { Agent } from "undici";
27871
28569
  import WsWebSocket from "ws";
27872
28570
  function kandanTlsTrustFromEnv() {
@@ -27880,7 +28578,7 @@ function kandanTlsTrustFromCaFile(caFile) {
27880
28578
  if (!existsSync13(trimmed)) {
27881
28579
  throw new Error(`KANDAN_TLS_CA_FILE does not exist: ${trimmed}`);
27882
28580
  }
27883
- const ca = readFileSync16(trimmed, "utf8");
28581
+ const ca = readFileSync17(trimmed, "utf8");
27884
28582
  return {
27885
28583
  caFile: trimmed,
27886
28584
  ca,
@@ -42989,9 +43687,9 @@ var require_internal = __commonJS({
42989
43687
  }
42990
43688
  InternalCodec.prototype.encoder = InternalEncoder;
42991
43689
  InternalCodec.prototype.decoder = InternalDecoder;
42992
- var StringDecoder = __require("string_decoder").StringDecoder;
43690
+ var StringDecoder2 = __require("string_decoder").StringDecoder;
42993
43691
  function InternalDecoder(options, codec) {
42994
- this.decoder = new StringDecoder(codec.enc);
43692
+ this.decoder = new StringDecoder2(codec.enc);
42995
43693
  }
42996
43694
  InternalDecoder.prototype.write = function(buf) {
42997
43695
  if (!Buffer4.isBuffer(buf)) {
@@ -46664,7 +47362,7 @@ var init_RemoveFileError = __esm({
46664
47362
 
46665
47363
  // ../../node_modules/@inquirer/external-editor/dist/esm/index.js
46666
47364
  import { spawn as spawn11, spawnSync as spawnSync6 } from "child_process";
46667
- import { readFileSync as readFileSync19, unlinkSync as unlinkSync3, writeFileSync as writeFileSync13 } from "fs";
47365
+ import { readFileSync as readFileSync20, unlinkSync as unlinkSync3, writeFileSync as writeFileSync14 } from "fs";
46668
47366
  import path from "node:path";
46669
47367
  import os from "node:os";
46670
47368
  import { randomUUID as randomUUID5 } from "node:crypto";
@@ -46781,14 +47479,14 @@ var init_esm5 = __esm({
46781
47479
  if (Object.prototype.hasOwnProperty.call(this.fileOptions, "mode")) {
46782
47480
  opt.mode = this.fileOptions.mode;
46783
47481
  }
46784
- writeFileSync13(this.tempFile, this.text, opt);
47482
+ writeFileSync14(this.tempFile, this.text, opt);
46785
47483
  } catch (createFileError) {
46786
47484
  throw new CreateFileError(createFileError);
46787
47485
  }
46788
47486
  }
46789
47487
  readTemporaryFile() {
46790
47488
  try {
46791
- const tempFileBuffer = readFileSync19(this.tempFile);
47489
+ const tempFileBuffer = readFileSync20(this.tempFile);
46792
47490
  if (tempFileBuffer.length === 0) {
46793
47491
  this.text = "";
46794
47492
  } else {
@@ -48157,17 +48855,17 @@ import { spawn as spawn12, spawnSync as spawnSync7 } from "node:child_process";
48157
48855
  import {
48158
48856
  existsSync as existsSync16,
48159
48857
  constants as fsConstants,
48160
- mkdirSync as mkdirSync14,
48858
+ mkdirSync as mkdirSync15,
48161
48859
  mkdtempSync as mkdtempSync5,
48162
- readFileSync as readFileSync20,
48860
+ readFileSync as readFileSync21,
48163
48861
  readdirSync as readdirSync5,
48164
- rmSync as rmSync5,
48862
+ rmSync as rmSync6,
48165
48863
  statSync as statSync4,
48166
- writeFileSync as writeFileSync14
48864
+ writeFileSync as writeFileSync15
48167
48865
  } from "node:fs";
48168
48866
  import { access } from "node:fs/promises";
48169
- import { homedir as homedir15, tmpdir as tmpdir4 } from "node:os";
48170
- import { delimiter as delimiter3, dirname as dirname16, join as join21, resolve as resolve10 } from "node:path";
48867
+ import { homedir as homedir16, tmpdir as tmpdir4 } from "node:os";
48868
+ import { delimiter as delimiter3, dirname as dirname16, join as join23, resolve as resolve10 } from "node:path";
48171
48869
  import { stdin as defaultStdin, stdout as defaultStdout } from "node:process";
48172
48870
  import { emitKeypressEvents } from "node:readline";
48173
48871
  function signupHelpText() {
@@ -48288,7 +48986,7 @@ function defaultSignupDraftStore(serviceUrl) {
48288
48986
  }
48289
48987
  let parsed;
48290
48988
  try {
48291
- parsed = JSON.parse(readFileSync20(path2, "utf8"));
48989
+ parsed = JSON.parse(readFileSync21(path2, "utf8"));
48292
48990
  } catch (_error) {
48293
48991
  return void 0;
48294
48992
  }
@@ -48298,20 +48996,20 @@ function defaultSignupDraftStore(serviceUrl) {
48298
48996
  return comparableServiceUrl(parsed.serviceUrl) === comparableServiceUrl(serviceUrl) ? parsed : void 0;
48299
48997
  },
48300
48998
  write: (draft) => {
48301
- mkdirSync14(dirname16(path2), { recursive: true });
48302
- writeFileSync14(path2, `${JSON.stringify(draft, null, 2)}
48999
+ mkdirSync15(dirname16(path2), { recursive: true });
49000
+ writeFileSync15(path2, `${JSON.stringify(draft, null, 2)}
48303
49001
  `, {
48304
49002
  encoding: "utf8",
48305
49003
  mode: 384
48306
49004
  });
48307
49005
  },
48308
49006
  clear: () => {
48309
- rmSync5(path2, { force: true });
49007
+ rmSync6(path2, { force: true });
48310
49008
  }
48311
49009
  };
48312
49010
  }
48313
49011
  function defaultSignupDraftPath(serviceUrl) {
48314
- return join21(
49012
+ return join23(
48315
49013
  dirname16(localConfigPath()),
48316
49014
  `signup-draft.${localConfigScopeFileStem(serviceUrl)}.json`
48317
49015
  );
@@ -48346,8 +49044,8 @@ function defaultSignupTaskCacheStore(serviceUrl) {
48346
49044
  }
48347
49045
  }
48348
49046
  };
48349
- mkdirSync14(dirname16(path2), { recursive: true });
48350
- writeFileSync14(path2, `${JSON.stringify(next, null, 2)}
49047
+ mkdirSync15(dirname16(path2), { recursive: true });
49048
+ writeFileSync15(path2, `${JSON.stringify(next, null, 2)}
48351
49049
  `, {
48352
49050
  encoding: "utf8",
48353
49051
  mode: 384
@@ -48356,7 +49054,7 @@ function defaultSignupTaskCacheStore(serviceUrl) {
48356
49054
  };
48357
49055
  }
48358
49056
  function defaultSignupTaskCachePath(serviceUrl) {
48359
- return join21(
49057
+ return join23(
48360
49058
  dirname16(localConfigPath()),
48361
49059
  `signup-task-cache.${localConfigScopeFileStem(serviceUrl)}.json`
48362
49060
  );
@@ -48367,7 +49065,7 @@ function readSignupTaskCache(path2) {
48367
49065
  }
48368
49066
  let parsed;
48369
49067
  try {
48370
- parsed = JSON.parse(readFileSync20(path2, "utf8"));
49068
+ parsed = JSON.parse(readFileSync21(path2, "utf8"));
48371
49069
  } catch (_error) {
48372
49070
  return { version: 1, entries: {} };
48373
49071
  }
@@ -50252,7 +50950,7 @@ function autocompletePathSuggestions(pathInput) {
50252
50950
  try {
50253
50951
  const showHidden = prefix.startsWith(".");
50254
50952
  const currentPath = directoryExists(normalizedInput) ? [normalizedInput.replace(/\/$/, "") || "/"] : [];
50255
- const childPaths = readdirSync5(directoryPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => showHidden || !entry.name.startsWith(".")).map((entry) => join21(directoryPath, entry.name)).map((path2) => ({
50953
+ const childPaths = readdirSync5(directoryPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => showHidden || !entry.name.startsWith(".")).map((entry) => join23(directoryPath, entry.name)).map((path2) => ({
50256
50954
  path: path2,
50257
50955
  score: fuzzyPathSegmentScore(path2.split("/").at(-1) ?? path2, prefix)
50258
50956
  })).filter((candidate) => candidate.score !== void 0).sort((left, right) => {
@@ -50498,7 +51196,7 @@ async function runSignupPreflights(runtime) {
50498
51196
  function defaultPreflightRuntime() {
50499
51197
  return {
50500
51198
  cwd: process.cwd(),
50501
- homeDir: homedir15(),
51199
+ homeDir: homedir16(),
50502
51200
  probeTool,
50503
51201
  readGitEmail,
50504
51202
  discoverCodeRoots,
@@ -50643,13 +51341,13 @@ async function suggestTasksWithCodex(projectPath, retryPolicy) {
50643
51341
  );
50644
51342
  }
50645
51343
  async function runCodexTaskSuggestion2(projectPath, previousResponse, retryPolicy) {
50646
- const tempRoot = mkdtempSync5(join21(tmpdir4(), "linzumi-signup-codex-tasks-"));
50647
- const schemaPath = join21(tempRoot, "task-suggestions.schema.json");
50648
- const outputPath = join21(tempRoot, "task-suggestions.json");
51344
+ const tempRoot = mkdtempSync5(join23(tmpdir4(), "linzumi-signup-codex-tasks-"));
51345
+ const schemaPath = join23(tempRoot, "task-suggestions.schema.json");
51346
+ const outputPath = join23(tempRoot, "task-suggestions.json");
50649
51347
  const model = process.env.LINZUMI_SIGNUP_TASK_MODEL ?? "gpt-5.4-mini";
50650
51348
  const prompt = taskSuggestionPrompt2(previousResponse);
50651
51349
  const codexCommand = await resolveSignupCodexCommand();
50652
- writeFileSync14(
51350
+ writeFileSync15(
50653
51351
  schemaPath,
50654
51352
  `${JSON.stringify(taskSuggestionJsonSchema2(), null, 2)}
50655
51353
  `,
@@ -50670,9 +51368,9 @@ async function runCodexTaskSuggestion2(projectPath, previousResponse, retryPolic
50670
51368
  ),
50671
51369
  retryPolicy
50672
51370
  );
50673
- return readFileSync20(outputPath, "utf8");
51371
+ return readFileSync21(outputPath, "utf8");
50674
51372
  } finally {
50675
- rmSync5(tempRoot, { recursive: true, force: true });
51373
+ rmSync6(tempRoot, { recursive: true, force: true });
50676
51374
  }
50677
51375
  }
50678
51376
  function codexTaskSuggestionProcess2(args) {
@@ -50707,7 +51405,7 @@ function codexTaskSuggestionProcess2(args) {
50707
51405
  function signupCodexTaskSuggestionProcessForTest(args) {
50708
51406
  return codexTaskSuggestionProcess2(args);
50709
51407
  }
50710
- async function resolveSignupCodexCommand(env = process.env, homeDir = homedir15(), executableExists = fileIsExecutable) {
51408
+ async function resolveSignupCodexCommand(env = process.env, homeDir = homedir16(), executableExists = fileIsExecutable) {
50711
51409
  const override = firstConfiguredValue([
50712
51410
  env.LINZUMI_SIGNUP_CODEX_BIN,
50713
51411
  env.LINZUMI_CODEX_BIN
@@ -50762,7 +51460,7 @@ function resolveHomePath(path2, homeDir) {
50762
51460
  return homeDir;
50763
51461
  }
50764
51462
  if (path2.startsWith("~/")) {
50765
- return join21(homeDir, path2.slice(2));
51463
+ return join23(homeDir, path2.slice(2));
50766
51464
  }
50767
51465
  return resolve10(path2);
50768
51466
  }
@@ -50775,9 +51473,9 @@ function commandLooksPathLike(command) {
50775
51473
  }
50776
51474
  function homeManagedCodexCandidates(homeDir) {
50777
51475
  return [
50778
- join21(homeDir, ".volta", "bin", "codex"),
50779
- join21(homeDir, ".local", "bin", "codex"),
50780
- join21(homeDir, "bin", "codex")
51476
+ join23(homeDir, ".volta", "bin", "codex"),
51477
+ join23(homeDir, ".local", "bin", "codex"),
51478
+ join23(homeDir, "bin", "codex")
50781
51479
  ];
50782
51480
  }
50783
51481
  async function firstExecutablePath(paths, executableExists) {
@@ -50792,7 +51490,7 @@ function commandPathCandidates(path2) {
50792
51490
  if (path2 === void 0 || path2.trim() === "") {
50793
51491
  return [];
50794
51492
  }
50795
- return path2.split(delimiter3).filter((entry) => entry.trim() !== "").map((entry) => join21(entry, "codex"));
51493
+ return path2.split(delimiter3).filter((entry) => entry.trim() !== "").map((entry) => join23(entry, "codex"));
50796
51494
  }
50797
51495
  async function fileIsExecutable(path2) {
50798
51496
  try {
@@ -51025,11 +51723,11 @@ function codexPreflightLocation(command, homeDir) {
51025
51723
  switch (command) {
51026
51724
  case "codex":
51027
51725
  return "on PATH";
51028
- case join21(homeDir, ".volta", "bin", "codex"):
51726
+ case join23(homeDir, ".volta", "bin", "codex"):
51029
51727
  return "via Volta";
51030
- case join21(homeDir, ".local", "bin", "codex"):
51728
+ case join23(homeDir, ".local", "bin", "codex"):
51031
51729
  return "via ~/.local/bin";
51032
- case join21(homeDir, "bin", "codex"):
51730
+ case join23(homeDir, "bin", "codex"):
51033
51731
  return "via ~/bin";
51034
51732
  default:
51035
51733
  return "from configured path";
@@ -51188,7 +51886,7 @@ function probeToolWithArgs(command, args, cwd) {
51188
51886
  }
51189
51887
  async function discoverCodeRoots(homeDir) {
51190
51888
  const candidates = ["src", "code", "projects"].map(
51191
- (name) => join21(homeDir, name)
51889
+ (name) => join23(homeDir, name)
51192
51890
  );
51193
51891
  return candidates.filter((path2) => existsSync16(path2)).flatMap((path2) => discoveredProjectNames(path2));
51194
51892
  }
@@ -51242,7 +51940,7 @@ function discoverProjectsFromCurrentDirectory(cwd) {
51242
51940
  }
51243
51941
  function discoverProjectsFromGuessedRoots(homeDir) {
51244
51942
  const guessedRoots = ["src", "code", "projects"].map(
51245
- (name) => join21(homeDir, name)
51943
+ (name) => join23(homeDir, name)
51246
51944
  );
51247
51945
  const projects = guessedRoots.flatMap(
51248
51946
  (root) => discoverProjectsUnderRoot(root)
@@ -51294,25 +51992,25 @@ function looksLikeProject(path2) {
51294
51992
  "pnpm-lock.yaml",
51295
51993
  "yarn.lock",
51296
51994
  "package-lock.json"
51297
- ].some((name) => existsSync16(join21(path2, name)));
51995
+ ].some((name) => existsSync16(join23(path2, name)));
51298
51996
  }
51299
51997
  function detectProjectLanguage(path2) {
51300
- if (existsSync16(join21(path2, "pyproject.toml")) || existsSync16(join21(path2, "requirements.txt"))) {
51998
+ if (existsSync16(join23(path2, "pyproject.toml")) || existsSync16(join23(path2, "requirements.txt"))) {
51301
51999
  return "Python";
51302
52000
  }
51303
- if (existsSync16(join21(path2, "Cargo.toml"))) {
52001
+ if (existsSync16(join23(path2, "Cargo.toml"))) {
51304
52002
  return "Rust";
51305
52003
  }
51306
- if (existsSync16(join21(path2, "go.mod"))) {
52004
+ if (existsSync16(join23(path2, "go.mod"))) {
51307
52005
  return "Go";
51308
52006
  }
51309
- if (existsSync16(join21(path2, "mix.exs"))) {
52007
+ if (existsSync16(join23(path2, "mix.exs"))) {
51310
52008
  return "Elixir";
51311
52009
  }
51312
- if (existsSync16(join21(path2, "tsconfig.json")) || packageJsonMentionsTypeScript(path2)) {
52010
+ if (existsSync16(join23(path2, "tsconfig.json")) || packageJsonMentionsTypeScript(path2)) {
51313
52011
  return "TypeScript";
51314
52012
  }
51315
- if (existsSync16(join21(path2, "package.json"))) {
52013
+ if (existsSync16(join23(path2, "package.json"))) {
51316
52014
  return "JavaScript";
51317
52015
  }
51318
52016
  return "Project";
@@ -51320,7 +52018,7 @@ function detectProjectLanguage(path2) {
51320
52018
  function packageJsonMentionsTypeScript(path2) {
51321
52019
  try {
51322
52020
  const packageJson2 = JSON.parse(
51323
- readFileSync20(join21(path2, "package.json"), "utf8")
52021
+ readFileSync21(join23(path2, "package.json"), "utf8")
51324
52022
  );
51325
52023
  return packageJson2.dependencies?.typescript !== void 0 || packageJson2.devDependencies?.typescript !== void 0;
51326
52024
  } catch {
@@ -51328,11 +52026,11 @@ function packageJsonMentionsTypeScript(path2) {
51328
52026
  }
51329
52027
  }
51330
52028
  function hasGitMetadata(path2) {
51331
- return existsSync16(join21(path2, ".git"));
52029
+ return existsSync16(join23(path2, ".git"));
51332
52030
  }
51333
52031
  function childDirectories(root) {
51334
52032
  try {
51335
- return readdirSync5(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join21(root, entry.name));
52033
+ return readdirSync5(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join23(root, entry.name));
51336
52034
  } catch {
51337
52035
  return [];
51338
52036
  }
@@ -51358,10 +52056,10 @@ function directoryExists(path2) {
51358
52056
  }
51359
52057
  function expandHomePath(path2) {
51360
52058
  if (path2 === "~") {
51361
- return homedir15();
52059
+ return homedir16();
51362
52060
  }
51363
52061
  if (path2.startsWith("~/")) {
51364
- return join21(homedir15(), path2.slice(2));
52062
+ return join23(homedir16(), path2.slice(2));
51365
52063
  }
51366
52064
  return resolve10(path2);
51367
52065
  }
@@ -51451,8 +52149,8 @@ init_onboardingDiscoveryChildProcess();
51451
52149
  init_runner();
51452
52150
  init_claudeCodeSession();
51453
52151
  init_authCache();
51454
- import { existsSync as existsSync17, readFileSync as readFileSync21, realpathSync as realpathSync7 } from "node:fs";
51455
- import { homedir as homedir16 } from "node:os";
52152
+ import { existsSync as existsSync17, readFileSync as readFileSync22, realpathSync as realpathSync7 } from "node:fs";
52153
+ import { homedir as homedir17 } from "node:os";
51456
52154
  import { resolve as resolve11 } from "node:path";
51457
52155
  import { fileURLToPath as fileURLToPath4 } from "node:url";
51458
52156
 
@@ -51547,9 +52245,9 @@ init_kandanTls();
51547
52245
  init_protocol();
51548
52246
  init_json();
51549
52247
  init_defaultUrls();
51550
- import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "node:fs";
51551
- import { dirname as dirname14, join as join19 } from "node:path";
51552
- import { homedir as homedir13 } from "node:os";
52248
+ import { existsSync as existsSync14, mkdirSync as mkdirSync13, readFileSync as readFileSync18, writeFileSync as writeFileSync12 } from "node:fs";
52249
+ import { dirname as dirname14, join as join21 } from "node:path";
52250
+ import { homedir as homedir14 } from "node:os";
51553
52251
  async function runAgentCliCommand(args, deps = {
51554
52252
  fetchImpl: fetch,
51555
52253
  stdout: process.stdout,
@@ -52257,7 +52955,7 @@ function agentTokenFile(flags) {
52257
52955
  return flags.get("agent-token-file") ?? defaultAgentTokenFilePath();
52258
52956
  }
52259
52957
  function defaultAgentTokenFilePath() {
52260
- return join19(homedir13(), ".linzumi", "agent-token.json");
52958
+ return join21(homedir14(), ".linzumi", "agent-token.json");
52261
52959
  }
52262
52960
  function normalizedApiUrl(apiUrl) {
52263
52961
  return apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`;
@@ -52266,11 +52964,11 @@ function authorizationHeaders(token) {
52266
52964
  return { authorization: `Bearer ${token}` };
52267
52965
  }
52268
52966
  function readOptionalTextFile(path2) {
52269
- return existsSync14(path2) ? readFileSync17(path2, "utf8") : void 0;
52967
+ return existsSync14(path2) ? readFileSync18(path2, "utf8") : void 0;
52270
52968
  }
52271
52969
  function writeTextFile(path2, content) {
52272
- mkdirSync12(dirname14(path2), { recursive: true });
52273
- writeFileSync11(path2, content);
52970
+ mkdirSync13(dirname14(path2), { recursive: true });
52971
+ writeFileSync12(path2, content);
52274
52972
  }
52275
52973
  function readStoredAgentTokenFile(path2, readTextFile = readOptionalTextFile) {
52276
52974
  const content = readTextFile(path2);
@@ -52359,25 +53057,25 @@ init_runnerLogger();
52359
53057
  import {
52360
53058
  existsSync as existsSync15,
52361
53059
  closeSync as closeSync3,
52362
- mkdirSync as mkdirSync13,
53060
+ mkdirSync as mkdirSync14,
52363
53061
  openSync as openSync4,
52364
- readFileSync as readFileSync18,
53062
+ readFileSync as readFileSync19,
52365
53063
  watch,
52366
- writeFileSync as writeFileSync12
53064
+ writeFileSync as writeFileSync13
52367
53065
  } from "node:fs";
52368
- import { homedir as homedir14 } from "node:os";
52369
- import { dirname as dirname15, join as join20, resolve as resolve9 } from "node:path";
53066
+ import { homedir as homedir15 } from "node:os";
53067
+ import { dirname as dirname15, join as join22, resolve as resolve9 } from "node:path";
52370
53068
  import { execFileSync, spawn as spawn10 } from "node:child_process";
52371
53069
  import { fileURLToPath as fileURLToPath3 } from "node:url";
52372
53070
  var connectedMarkers = ["Connected to Linzumi", "Runner connected:"];
52373
53071
  function commanderStatusDir() {
52374
- return join20(homedir14(), ".linzumi", "commanders");
53072
+ return join22(homedir15(), ".linzumi", "commanders");
52375
53073
  }
52376
53074
  function commanderStatusFile(runnerId, statusDir = commanderStatusDir()) {
52377
- return join20(statusDir, `${safeRunnerId(runnerId)}.json`);
53075
+ return join22(statusDir, `${safeRunnerId(runnerId)}.json`);
52378
53076
  }
52379
53077
  function defaultCommanderLogFile(runnerId) {
52380
- return join20(homedir14(), ".linzumi", "logs", `${safeRunnerId(runnerId)}.log`);
53078
+ return join22(homedir15(), ".linzumi", "logs", `${safeRunnerId(runnerId)}.log`);
52381
53079
  }
52382
53080
  function commanderLogIsConnected(log2) {
52383
53081
  return connectedMarkers.some((marker) => log2.includes(marker));
@@ -52398,8 +53096,8 @@ function startCommanderDaemon(options) {
52398
53096
  "--log-file",
52399
53097
  logFile
52400
53098
  ];
52401
- mkdirSync13(statusDir, { recursive: true });
52402
- mkdirSync13(dirname15(logFile), { recursive: true });
53099
+ mkdirSync14(statusDir, { recursive: true });
53100
+ mkdirSync14(dirname15(logFile), { recursive: true });
52403
53101
  const out = openSync4(logFile, "a");
52404
53102
  const err = openSync4(logFile, "a");
52405
53103
  writeCliAuditEvent(
@@ -52445,7 +53143,7 @@ function startCommanderDaemon(options) {
52445
53143
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
52446
53144
  command: [nodeBin, ...command]
52447
53145
  };
52448
- writeFileSync12(statusFile, `${JSON.stringify(record, null, 2)}
53146
+ writeFileSync13(statusFile, `${JSON.stringify(record, null, 2)}
52449
53147
  `);
52450
53148
  return record;
52451
53149
  }
@@ -52454,12 +53152,12 @@ function commanderDaemonStatus(runnerId, statusDir = commanderStatusDir(), proce
52454
53152
  if (!existsSync15(statusFile)) {
52455
53153
  return { status: "missing", runnerId, statusFile };
52456
53154
  }
52457
- const record = parseRecord(readFileSync18(statusFile, "utf8"));
53155
+ const record = parseRecord(readFileSync19(statusFile, "utf8"));
52458
53156
  return processIsRunning(record.pid) && processMatchesRecord(record, processIdentityReader) ? { status: "running", record } : { status: "stopped", record };
52459
53157
  }
52460
53158
  async function waitForCommanderDaemon(options) {
52461
53159
  const now = options.now ?? (() => Date.now());
52462
- const readTextFile = options.readTextFile ?? ((path2) => existsSync15(path2) ? readFileSync18(path2, "utf8") : void 0);
53160
+ const readTextFile = options.readTextFile ?? ((path2) => existsSync15(path2) ? readFileSync19(path2, "utf8") : void 0);
52463
53161
  const statusImpl = options.statusImpl ?? commanderDaemonStatus;
52464
53162
  const deadline = now() + options.timeoutMs;
52465
53163
  while (now() <= deadline) {
@@ -66401,7 +67099,7 @@ async function parseAgentRunnerArgs(args, deps = {
66401
67099
  };
66402
67100
  }
66403
67101
  function readAgentTokenTextFile(path2) {
66404
- return existsSync17(path2) ? readFileSync21(path2, "utf8") : void 0;
67102
+ return existsSync17(path2) ? readFileSync22(path2, "utf8") : void 0;
66405
67103
  }
66406
67104
  function rejectAgentRunnerTargetingFlags(values) {
66407
67105
  const unsupportedFlags = [
@@ -66711,10 +67409,10 @@ function rejectStartTargetingFlags(values) {
66711
67409
  }
66712
67410
  function resolveUserPath(pathValue) {
66713
67411
  if (pathValue === "~") {
66714
- return homedir16();
67412
+ return homedir17();
66715
67413
  }
66716
67414
  if (pathValue.startsWith("~/")) {
66717
- return resolve11(homedir16(), pathValue.slice(2));
67415
+ return resolve11(homedir17(), pathValue.slice(2));
66718
67416
  }
66719
67417
  return resolve11(pathValue);
66720
67418
  }
@@ -66817,21 +67515,23 @@ function threadRunnerCodexModelProvider(values) {
66817
67515
  if (modelProvider === void 0) {
66818
67516
  return void 0;
66819
67517
  }
66820
- if (modelProvider !== "wafer") {
67518
+ if (modelProvider !== "wafer" && modelProvider !== "openai-proxy") {
66821
67519
  throw new Error(`unsupported --model-provider: ${modelProvider}`);
66822
67520
  }
66823
67521
  const llmProxyBaseUrl = stringValue8(values, "llm-proxy-base-url");
66824
67522
  const llmProxyToken = process.env.LINZUMI_LLM_PROXY_TOKEN?.trim();
66825
67523
  if (llmProxyBaseUrl === void 0) {
66826
- throw new Error("--model-provider wafer requires --llm-proxy-base-url");
67524
+ throw new Error(
67525
+ `--model-provider ${modelProvider} requires --llm-proxy-base-url`
67526
+ );
66827
67527
  }
66828
67528
  if (llmProxyToken === void 0 || llmProxyToken === "") {
66829
67529
  throw new Error(
66830
- "--model-provider wafer requires the LINZUMI_LLM_PROXY_TOKEN env credential"
67530
+ `--model-provider ${modelProvider} requires the LINZUMI_LLM_PROXY_TOKEN env credential`
66831
67531
  );
66832
67532
  }
66833
67533
  return {
66834
- provider: "wafer",
67534
+ provider: modelProvider,
66835
67535
  llmProxyBaseUrl,
66836
67536
  llmProxyToken
66837
67537
  };