@linzumi/cli 0.0.82-beta → 0.0.84-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 +1398 -564
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11472,6 +11472,7 @@ function createClaudeCodeSessionPipeline(host) {
11472
11472
  return;
11473
11473
  }
11474
11474
  if (!event.isError && toolName2 === "TodoWrite") {
11475
+ host.onTodoWriteCompleted?.(input);
11475
11476
  const plan = claudePlanItem(itemId, input);
11476
11477
  if (plan !== void 0) {
11477
11478
  recordItem(turn, plan);
@@ -11563,6 +11564,21 @@ function createClaudeCodeSessionPipeline(host) {
11563
11564
  handleToolResult(ensureTurn(), event);
11564
11565
  return;
11565
11566
  }
11567
+ case "command_output_delta": {
11568
+ const turn = activeTurn;
11569
+ const pending = turn?.pendingTools.get(event.itemKey);
11570
+ if (turn === void 0 || pending === void 0) {
11571
+ return;
11572
+ }
11573
+ submit("item/commandExecution/outputDelta", {
11574
+ turnId: turn.turnId,
11575
+ itemId: `tool:${event.itemKey}`,
11576
+ command: claudeToolCommandLabel(pending.toolName, pending.input),
11577
+ stream: "stdout",
11578
+ delta: event.delta
11579
+ });
11580
+ return;
11581
+ }
11566
11582
  case "command_output": {
11567
11583
  const turn = ensureTurn();
11568
11584
  const item = {
@@ -11846,13 +11862,402 @@ var init_claudeCodePipeline = __esm({
11846
11862
  }
11847
11863
  });
11848
11864
 
11865
+ // src/claudeCodePlanMirror.ts
11866
+ function clamp(value, maxLength) {
11867
+ return value.length <= maxLength ? value : value.slice(0, maxLength);
11868
+ }
11869
+ function stringValue2(value) {
11870
+ return typeof value === "string" ? value : void 0;
11871
+ }
11872
+ function objectValue2(value) {
11873
+ return isJsonObject(value) ? value : void 0;
11874
+ }
11875
+ function claudeTodoWritePlanSteps(input) {
11876
+ const todos = Array.isArray(input.todos) ? input.todos : [];
11877
+ const steps = todos.flatMap((todo) => {
11878
+ const value = objectValue2(todo);
11879
+ if (value === void 0) {
11880
+ return [];
11881
+ }
11882
+ const title = clamp(
11883
+ (stringValue2(value.content) ?? stringValue2(value.subject) ?? stringValue2(value.activeForm) ?? "").trim(),
11884
+ planStepTitleMaxLength
11885
+ );
11886
+ if (title === "") {
11887
+ return [];
11888
+ }
11889
+ const activeForm = (stringValue2(value.activeForm) ?? "").trim();
11890
+ const description = clamp(
11891
+ activeForm === "" ? title : activeForm,
11892
+ planStepDescriptionMaxLength
11893
+ );
11894
+ const status = todoStatusToPlanStepStatus[stringValue2(value.status) ?? "pending"] ?? "pending";
11895
+ return status === "completed" ? [{ title, description, status, completed_debrief: description }] : [{ title, description, status }];
11896
+ });
11897
+ if (steps.length === 0) {
11898
+ return void 0;
11899
+ }
11900
+ return steps.length <= planStepsMaxCount ? steps : steps.slice(0, planStepsMaxCount);
11901
+ }
11902
+ function createClaudeCodePlanMirror(args) {
11903
+ let pendingSteps;
11904
+ let lastPushedSignature;
11905
+ let flight = Promise.resolve();
11906
+ let inFlight = false;
11907
+ const pushLoop = async () => {
11908
+ while (pendingSteps !== void 0) {
11909
+ const steps = pendingSteps;
11910
+ pendingSteps = void 0;
11911
+ const signature = JSON.stringify(steps);
11912
+ if (signature === lastPushedSignature) {
11913
+ continue;
11914
+ }
11915
+ try {
11916
+ await args.replacePlanSteps({
11917
+ thread_id: args.threadId,
11918
+ goal: args.goal,
11919
+ steps
11920
+ });
11921
+ lastPushedSignature = signature;
11922
+ } catch (error) {
11923
+ args.log("claude_code.plan_mirror_push_failed", {
11924
+ thread_id: args.threadId,
11925
+ message: error instanceof Error ? error.message : String(error)
11926
+ });
11927
+ }
11928
+ }
11929
+ };
11930
+ return {
11931
+ handleTodoWrite: (input) => {
11932
+ const steps = claudeTodoWritePlanSteps(input);
11933
+ if (steps === void 0) {
11934
+ return;
11935
+ }
11936
+ pendingSteps = steps;
11937
+ if (!inFlight) {
11938
+ inFlight = true;
11939
+ flight = pushLoop().finally(() => {
11940
+ inFlight = false;
11941
+ });
11942
+ }
11943
+ },
11944
+ settle: () => flight
11945
+ };
11946
+ }
11947
+ var todoStatusToPlanStepStatus, planStepTitleMaxLength, planStepDescriptionMaxLength, planStepsMaxCount;
11948
+ var init_claudeCodePlanMirror = __esm({
11949
+ "src/claudeCodePlanMirror.ts"() {
11950
+ "use strict";
11951
+ init_protocol();
11952
+ todoStatusToPlanStepStatus = {
11953
+ pending: "pending",
11954
+ in_progress: "active",
11955
+ completed: "completed"
11956
+ };
11957
+ planStepTitleMaxLength = 255;
11958
+ planStepDescriptionMaxLength = 1e4;
11959
+ planStepsMaxCount = 50;
11960
+ }
11961
+ });
11962
+
11963
+ // src/claudeCodeLiveBashOutput.ts
11964
+ import {
11965
+ mkdirSync as mkdirSync2,
11966
+ rmSync,
11967
+ writeFileSync,
11968
+ promises as fsPromises
11969
+ } from "node:fs";
11970
+ import { join as join6 } from "node:path";
11971
+ import { StringDecoder } from "node:string_decoder";
11972
+ function shellSingleQuoted(value) {
11973
+ return `'${value.replaceAll("'", `'\\''`)}'`;
11974
+ }
11975
+ function claudeLiveBashWrappedCommand(command, captureFile) {
11976
+ return `__lz_live_out=${shellSingleQuoted(captureFile)}; if ! : >> "$__lz_live_out" 2>/dev/null; then __lz_live_out=/dev/null; fi; { ${command}${wrapperTail}`;
11977
+ }
11978
+ function isClaudeLiveBashWrappedCommand(command) {
11979
+ return wrapperHeadPattern.test(command) && command.endsWith(wrapperTail);
11980
+ }
11981
+ function claudeLiveBashOriginalCommand(command) {
11982
+ const head = command.match(wrapperHeadPattern)?.[0];
11983
+ if (head === void 0 || !command.endsWith(wrapperTail)) {
11984
+ return command;
11985
+ }
11986
+ return command.slice(head.length, command.length - wrapperTail.length);
11987
+ }
11988
+ function claudeLiveBashCaptureEnabled(env) {
11989
+ const value = env.LINZUMI_CLAUDE_LIVE_BASH?.trim().toLowerCase();
11990
+ return !(value === "0" || value === "false" || value === "off" || value === "no");
11991
+ }
11992
+ function createClaudeCodeLiveBashCapture(host) {
11993
+ const pollIntervalMs = host.pollIntervalMs ?? defaultPollIntervalMs;
11994
+ const maxEmittedBytes = host.maxEmittedBytesPerTool ?? defaultMaxEmittedBytesPerTool;
11995
+ const tails = /* @__PURE__ */ new Map();
11996
+ let closed = false;
11997
+ const stopTail = (toolUseId) => {
11998
+ const tail = tails.get(toolUseId);
11999
+ if (tail === void 0) {
12000
+ return;
12001
+ }
12002
+ tails.delete(toolUseId);
12003
+ if (tail.timer !== void 0) {
12004
+ clearInterval(tail.timer);
12005
+ tail.timer = void 0;
12006
+ }
12007
+ try {
12008
+ rmSync(tail.file, { force: true });
12009
+ } catch (_error) {
12010
+ }
12011
+ };
12012
+ const pollTail = async (toolUseId, tail) => {
12013
+ if (tail.reading) {
12014
+ return;
12015
+ }
12016
+ tail.reading = true;
12017
+ try {
12018
+ const stat2 = await fsPromises.stat(tail.file);
12019
+ if (stat2.size <= tail.offset) {
12020
+ return;
12021
+ }
12022
+ const length = Math.min(
12023
+ stat2.size - tail.offset,
12024
+ maxReadBytesPerPoll,
12025
+ maxEmittedBytes - tail.emittedBytes
12026
+ );
12027
+ if (length <= 0) {
12028
+ stopTail(toolUseId);
12029
+ return;
12030
+ }
12031
+ const handle = await fsPromises.open(tail.file, "r");
12032
+ try {
12033
+ const buffer = Buffer.alloc(length);
12034
+ const { bytesRead } = await handle.read(buffer, 0, length, tail.offset);
12035
+ if (bytesRead <= 0) {
12036
+ return;
12037
+ }
12038
+ tail.offset += bytesRead;
12039
+ tail.emittedBytes += bytesRead;
12040
+ const delta = tail.decoder.write(buffer.subarray(0, bytesRead));
12041
+ if (delta !== "" && tails.get(toolUseId) === tail) {
12042
+ host.onOutputDelta(toolUseId, delta);
12043
+ }
12044
+ if (tail.emittedBytes >= maxEmittedBytes) {
12045
+ host.log?.("claude_live_bash.output_budget_exhausted", {
12046
+ tool_use_id: toolUseId,
12047
+ emitted_bytes: tail.emittedBytes
12048
+ });
12049
+ stopTail(toolUseId);
12050
+ }
12051
+ } finally {
12052
+ await handle.close();
12053
+ }
12054
+ } catch (error) {
12055
+ if (tails.get(toolUseId) === tail) {
12056
+ host.log?.("claude_live_bash.tail_read_failed", {
12057
+ tool_use_id: toolUseId,
12058
+ message: error instanceof Error ? error.message : String(error)
12059
+ });
12060
+ stopTail(toolUseId);
12061
+ }
12062
+ } finally {
12063
+ tail.reading = false;
12064
+ }
12065
+ };
12066
+ const startTail = (toolUseId, file) => {
12067
+ stopTail(toolUseId);
12068
+ const tail = {
12069
+ file,
12070
+ decoder: new StringDecoder("utf8"),
12071
+ offset: 0,
12072
+ emittedBytes: 0,
12073
+ reading: false,
12074
+ timer: void 0
12075
+ };
12076
+ tails.set(toolUseId, tail);
12077
+ const timer = setInterval(() => {
12078
+ void pollTail(toolUseId, tail);
12079
+ }, pollIntervalMs);
12080
+ timer.unref?.();
12081
+ tail.timer = timer;
12082
+ };
12083
+ const wrapToolInput = (toolUseId, toolInput) => {
12084
+ if (closed) {
12085
+ return void 0;
12086
+ }
12087
+ const command = toolInput.command;
12088
+ if (typeof command !== "string" || command.trim() === "" || // Background commands are polled by the model itself (TaskOutput);
12089
+ // the foreground live stream does not apply.
12090
+ toolInput.run_in_background === true || // Defensive: never double-wrap (e.g. a model echoing a wrapped
12091
+ // command back from its own transcript).
12092
+ isClaudeLiveBashWrappedCommand(command)) {
12093
+ return void 0;
12094
+ }
12095
+ const file = join6(
12096
+ host.captureDir,
12097
+ `${toolUseId.replaceAll(/[^\w-]/g, "_")}.out`
12098
+ );
12099
+ try {
12100
+ mkdirSync2(host.captureDir, { recursive: true });
12101
+ writeFileSync(file, "");
12102
+ } catch (error) {
12103
+ host.log?.("claude_live_bash.capture_file_failed", {
12104
+ tool_use_id: toolUseId,
12105
+ message: error instanceof Error ? error.message : String(error)
12106
+ });
12107
+ return void 0;
12108
+ }
12109
+ startTail(toolUseId, file);
12110
+ return {
12111
+ ...toolInput,
12112
+ command: claudeLiveBashWrappedCommand(command, file)
12113
+ };
12114
+ };
12115
+ const preToolUseHook = async (input) => {
12116
+ const passthrough = { continue: true };
12117
+ if (typeof input !== "object" || input === null) {
12118
+ return passthrough;
12119
+ }
12120
+ const hookInput = input;
12121
+ 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
12122
+ // auto-allows and the rewrite cannot perturb a permission decision.
12123
+ // In ask-capable modes, PreToolUse updatedInput propagates into rule
12124
+ // matching and sandbox auto-allow analysis (verified empirically
12125
+ // 2026-06-12: a sandbox-auto-allowed `false` started prompting once
12126
+ // wrapped), so those modes wrap at canUseTool-allow time instead
12127
+ // (wrapApprovedTool below) - the command was already being asked, so
12128
+ // wrapping there adds zero prompts.
12129
+ hookInput.permission_mode !== "bypassPermissions") {
12130
+ return passthrough;
12131
+ }
12132
+ const updatedInput = wrapToolInput(
12133
+ hookInput.tool_use_id,
12134
+ hookInput.tool_input
12135
+ );
12136
+ if (updatedInput === void 0) {
12137
+ return passthrough;
12138
+ }
12139
+ return {
12140
+ continue: true,
12141
+ hookSpecificOutput: {
12142
+ hookEventName: "PreToolUse",
12143
+ updatedInput
12144
+ }
12145
+ };
12146
+ };
12147
+ return {
12148
+ hookMatchers: [{ matcher: "Bash", hooks: [preToolUseHook] }],
12149
+ wrapApprovedTool: wrapToolInput,
12150
+ settleTool: stopTail,
12151
+ settleAll: () => {
12152
+ for (const toolUseId of [...tails.keys()]) {
12153
+ stopTail(toolUseId);
12154
+ }
12155
+ },
12156
+ close: () => {
12157
+ closed = true;
12158
+ for (const toolUseId of [...tails.keys()]) {
12159
+ stopTail(toolUseId);
12160
+ }
12161
+ try {
12162
+ rmSync(host.captureDir, { recursive: true, force: true });
12163
+ } catch (_error) {
12164
+ }
12165
+ }
12166
+ };
12167
+ }
12168
+ var wrapperHeadPattern, wrapperTail, defaultPollIntervalMs, defaultMaxEmittedBytesPerTool, maxReadBytesPerPoll;
12169
+ var init_claudeCodeLiveBashOutput = __esm({
12170
+ "src/claudeCodeLiveBashOutput.ts"() {
12171
+ "use strict";
12172
+ wrapperHeadPattern = /^__lz_live_out='(?:[^']|'\\'')*'; if ! : >> "\$__lz_live_out" 2>\/dev\/null; then __lz_live_out=\/dev\/null; fi; \{ /;
12173
+ wrapperTail = '\n} > >(tee -a -- "$__lz_live_out") 2> >(tee -a -- "$__lz_live_out" >&2)';
12174
+ defaultPollIntervalMs = 200;
12175
+ defaultMaxEmittedBytesPerTool = 262144;
12176
+ maxReadBytesPerPoll = 65536;
12177
+ }
12178
+ });
12179
+
11849
12180
  // src/claudeCodeSession.ts
11850
12181
  import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
11851
12182
  import { homedir as homedir5 } from "node:os";
11852
- import { join as join6 } from "node:path";
12183
+ import { join as join7 } from "node:path";
11853
12184
  function claudeCodeSettingSources() {
11854
12185
  return ["user", "project", "local"];
11855
12186
  }
12187
+ function claudeCodeTokenUsageSummaryText(usage) {
12188
+ const cached = usage.cacheReadInputTokens === void 0 && usage.cacheCreationInputTokens === void 0 ? void 0 : (usage.cacheReadInputTokens ?? 0) + (usage.cacheCreationInputTokens ?? 0);
12189
+ const parts = [
12190
+ usage.inputTokens === void 0 ? void 0 : `${usage.inputTokens} in`,
12191
+ usage.outputTokens === void 0 ? void 0 : `${usage.outputTokens} out`,
12192
+ cached === void 0 ? void 0 : `${cached} cached`,
12193
+ usage.totalCostUsd === void 0 ? void 0 : `$${usage.totalCostUsd.toFixed(4)}`
12194
+ ].filter((part) => part !== void 0);
12195
+ return parts.length === 0 ? void 0 : parts.join(" / ");
12196
+ }
12197
+ function createClaudeCodeStreamUsageTracker() {
12198
+ const completed = {
12199
+ inputTokens: 0,
12200
+ outputTokens: 0,
12201
+ cacheCreationInputTokens: 0,
12202
+ cacheReadInputTokens: 0
12203
+ };
12204
+ let current;
12205
+ let lastEmittedKey;
12206
+ const totalsFromUsage = (usage, previous) => ({
12207
+ inputTokens: integerValue(usage.input_tokens) ?? previous?.inputTokens ?? 0,
12208
+ outputTokens: integerValue(usage.output_tokens) ?? previous?.outputTokens ?? 0,
12209
+ cacheCreationInputTokens: integerValue(usage.cache_creation_input_tokens) ?? previous?.cacheCreationInputTokens ?? 0,
12210
+ cacheReadInputTokens: integerValue(usage.cache_read_input_tokens) ?? previous?.cacheReadInputTokens ?? 0
12211
+ });
12212
+ const snapshotIfChanged = () => {
12213
+ const inputTokens = completed.inputTokens + (current?.inputTokens ?? 0);
12214
+ const outputTokens = completed.outputTokens + (current?.outputTokens ?? 0);
12215
+ const cacheCreationInputTokens = completed.cacheCreationInputTokens + (current?.cacheCreationInputTokens ?? 0);
12216
+ const cacheReadInputTokens = completed.cacheReadInputTokens + (current?.cacheReadInputTokens ?? 0);
12217
+ const key = `${inputTokens}:${outputTokens}:${cacheCreationInputTokens}:${cacheReadInputTokens}`;
12218
+ if (key === lastEmittedKey) {
12219
+ return void 0;
12220
+ }
12221
+ lastEmittedKey = key;
12222
+ return {
12223
+ inputTokens,
12224
+ outputTokens,
12225
+ cacheCreationInputTokens,
12226
+ cacheReadInputTokens,
12227
+ totalCostUsd: void 0
12228
+ };
12229
+ };
12230
+ return {
12231
+ observeStreamEvent: (event) => {
12232
+ switch (stringValue(event?.type)) {
12233
+ case "message_start": {
12234
+ const usage = objectValue(objectValue(event?.message)?.usage);
12235
+ if (usage === void 0) {
12236
+ return void 0;
12237
+ }
12238
+ if (current !== void 0) {
12239
+ completed.inputTokens += current.inputTokens;
12240
+ completed.outputTokens += current.outputTokens;
12241
+ completed.cacheCreationInputTokens += current.cacheCreationInputTokens;
12242
+ completed.cacheReadInputTokens += current.cacheReadInputTokens;
12243
+ }
12244
+ current = totalsFromUsage(usage, void 0);
12245
+ return snapshotIfChanged();
12246
+ }
12247
+ case "message_delta": {
12248
+ const usage = objectValue(event?.usage);
12249
+ if (usage === void 0) {
12250
+ return void 0;
12251
+ }
12252
+ current = totalsFromUsage(usage, current);
12253
+ return snapshotIfChanged();
12254
+ }
12255
+ default:
12256
+ return void 0;
12257
+ }
12258
+ }
12259
+ };
12260
+ }
11856
12261
  function parseClaudeCodeRateLimitInfo(info) {
11857
12262
  if (info === void 0) {
11858
12263
  return void 0;
@@ -11952,7 +12357,7 @@ async function probeClaudeCodeAvailability(args) {
11952
12357
  }
11953
12358
  }
11954
12359
  function hasClaudeCodeAuthHint(env, deps) {
11955
- const configDir = env.CLAUDE_CONFIG_DIR ?? join6(deps.homeDir, ".claude");
12360
+ const configDir = env.CLAUDE_CONFIG_DIR ?? join7(deps.homeDir, ".claude");
11956
12361
  return hasAnthropicCredentialEnv(env) || hasClaudeCloudProviderEnv(env) || hasClaudeCodeFileCredential(configDir, deps) || hasClaudeCodeApiKeyHelper(configDir, deps) || hasMacClaudeCodeKeychainAnchor(deps);
11957
12362
  }
11958
12363
  function claudeCodePolicyDeferHooks() {
@@ -11987,14 +12392,14 @@ function hasClaudeCloudProviderEnv(env) {
11987
12392
  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);
11988
12393
  }
11989
12394
  function hasClaudeCodeFileCredential(configDir, deps) {
11990
- return deps.fileExists(join6(configDir, ".credentials.json")) || deps.fileExists(join6(configDir, ".claude.json")) || deps.fileExists(join6(deps.homeDir, ".claude.json"));
12395
+ return deps.fileExists(join7(configDir, ".credentials.json")) || deps.fileExists(join7(configDir, ".claude.json")) || deps.fileExists(join7(deps.homeDir, ".claude.json"));
11991
12396
  }
11992
12397
  function hasClaudeCodeApiKeyHelper(configDir, deps) {
11993
12398
  return [
11994
- join6(configDir, "settings.json"),
11995
- join6(configDir, "settings.local.json"),
11996
- join6(deps.cwd, ".claude", "settings.json"),
11997
- join6(deps.cwd, ".claude", "settings.local.json")
12399
+ join7(configDir, "settings.json"),
12400
+ join7(configDir, "settings.local.json"),
12401
+ join7(deps.cwd, ".claude", "settings.json"),
12402
+ join7(deps.cwd, ".claude", "settings.local.json")
11998
12403
  ].some((path2) => settingsFileHasApiKeyHelper(path2, deps));
11999
12404
  }
12000
12405
  function settingsFileHasApiKeyHelper(path2, deps) {
@@ -12014,9 +12419,9 @@ function hasMacClaudeCodeKeychainAnchor(deps) {
12014
12419
  return false;
12015
12420
  }
12016
12421
  return [
12017
- join6(deps.homeDir, "Library", "Application Support", "claude-cli-nodejs"),
12018
- join6(deps.homeDir, "Library", "Application Support", "Claude"),
12019
- join6(deps.homeDir, "Library", "Preferences", "claude-cli-nodejs")
12422
+ join7(deps.homeDir, "Library", "Application Support", "claude-cli-nodejs"),
12423
+ join7(deps.homeDir, "Library", "Application Support", "Claude"),
12424
+ join7(deps.homeDir, "Library", "Preferences", "claude-cli-nodejs")
12020
12425
  ].some((path2) => deps.fileExists(path2));
12021
12426
  }
12022
12427
  function readTextFileIfPresent(path2) {
@@ -12037,6 +12442,7 @@ async function startClaudeCodeSession(options) {
12037
12442
  startedSessionIds: /* @__PURE__ */ new Set(),
12038
12443
  completedTurnCount: 0
12039
12444
  };
12445
+ const streamUsageTracker = createClaudeCodeStreamUsageTracker();
12040
12446
  for await (const message of runner(options)) {
12041
12447
  state.sessionId = state.sessionId ?? extractClaudeSessionId(message);
12042
12448
  const sessionId = extractClaudeSessionId(message) ?? state.sessionId;
@@ -12044,7 +12450,11 @@ async function startClaudeCodeSession(options) {
12044
12450
  state.startedSessionIds.add(sessionId);
12045
12451
  await options.onTranscriptEvent?.({ type: "session_started", sessionId });
12046
12452
  }
12047
- for (const event of transcriptEventsForClaudeMessage(message, sessionId)) {
12453
+ for (const event of transcriptEventsForClaudeMessage(
12454
+ message,
12455
+ sessionId,
12456
+ streamUsageTracker
12457
+ )) {
12048
12458
  if (event.type === "assistant_message") {
12049
12459
  recordClaudeAssistantAggregate(state, event);
12050
12460
  }
@@ -12215,6 +12625,11 @@ async function failClaudeCodeSession(options, sessionId, reason) {
12215
12625
  async function* defaultClaudeCodeRunner(options) {
12216
12626
  const sdk = await import("@anthropic-ai/claude-agent-sdk");
12217
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 };
12218
12633
  const query = sdk.query({
12219
12634
  prompt,
12220
12635
  options: {
@@ -12235,7 +12650,13 @@ async function* defaultClaudeCodeRunner(options) {
12235
12650
  },
12236
12651
  ...options.allowedTools === void 0 ? {} : { allowedTools: [...options.allowedTools] },
12237
12652
  ...options.env === void 0 ? {} : { env: options.env },
12238
- ...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
+ },
12239
12660
  ...options.model === void 0 ? {} : { model: options.model }
12240
12661
  // exactOptionalPropertyTypes: the conditional spreads build a union the
12241
12662
  // SDK's Options cannot absorb verbatim; the shape is correct field-wise.
@@ -12326,7 +12747,7 @@ function boundedPositiveInteger(value, fallback, min, max) {
12326
12747
  }
12327
12748
  return value;
12328
12749
  }
12329
- function claudeCodeCanUseTool(handler) {
12750
+ function claudeCodeCanUseTool(handler, wrapApprovedToolInput) {
12330
12751
  return async (toolName2, input, options) => {
12331
12752
  const decision = await handler(
12332
12753
  {
@@ -12337,7 +12758,11 @@ function claudeCodeCanUseTool(handler) {
12337
12758
  description: options.description,
12338
12759
  decisionReason: options.decisionReason,
12339
12760
  blockedPath: options.blockedPath,
12340
- 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)
12341
12766
  },
12342
12767
  options.signal
12343
12768
  );
@@ -12346,7 +12771,11 @@ function claudeCodeCanUseTool(handler) {
12346
12771
  return {
12347
12772
  behavior: "allow",
12348
12773
  toolUseID: options.toolUseID,
12349
- 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
12350
12779
  };
12351
12780
  case "deny":
12352
12781
  return {
@@ -12357,6 +12786,17 @@ function claudeCodeCanUseTool(handler) {
12357
12786
  }
12358
12787
  };
12359
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
+ }
12360
12800
  function extractClaudeSessionId(message) {
12361
12801
  const messageObject = objectValue(message);
12362
12802
  const directSessionId = stringValue(messageObject?.session_id) ?? stringValue(messageObject?.sessionId);
@@ -12393,11 +12833,11 @@ function extractClaudeResultErrorReason(message, subtype) {
12393
12833
  const explicitErrors = arrayValue(message.errors)?.map((error) => stringValue(error)).filter((error) => nonEmptyText(error) !== void 0).join("; ");
12394
12834
  return nonEmptyText(explicitErrors) ?? nonEmptyText(stringValue(message.result)) ?? nonEmptyText(stringValue(message.error)) ?? subtype ?? "error";
12395
12835
  }
12396
- function transcriptEventsForClaudeMessage(message, sessionId) {
12836
+ function transcriptEventsForClaudeMessage(message, sessionId, usageTracker) {
12397
12837
  const messageObject = objectValue(message);
12398
12838
  switch (stringValue(messageObject?.type)) {
12399
12839
  case "stream_event":
12400
- return streamTranscriptEvents(messageObject, sessionId);
12840
+ return streamTranscriptEvents(messageObject, sessionId, usageTracker);
12401
12841
  case "assistant":
12402
12842
  return assistantTranscriptEvents(messageObject, sessionId);
12403
12843
  case "user":
@@ -12414,11 +12854,16 @@ function transcriptEventsForClaudeMessage(message, sessionId) {
12414
12854
  return unknownTranscriptEvent(messageObject, sessionId);
12415
12855
  }
12416
12856
  }
12417
- function streamTranscriptEvents(message, sessionId) {
12857
+ function streamTranscriptEvents(message, sessionId, usageTracker) {
12418
12858
  if (sessionId === void 0) {
12419
12859
  return [];
12420
12860
  }
12421
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) {
12422
12867
  switch (stringValue(event?.type)) {
12423
12868
  case "content_block_delta": {
12424
12869
  const delta = objectValue(event?.delta);
@@ -12620,6 +13065,7 @@ var init_claudeCodeSession = __esm({
12620
13065
  "src/claudeCodeSession.ts"() {
12621
13066
  "use strict";
12622
13067
  init_json();
13068
+ init_claudeCodeLiveBashOutput();
12623
13069
  claudeRateLimitWindowLabels = {
12624
13070
  five_hour: "5h window",
12625
13071
  seven_day: "7d window",
@@ -12634,10 +13080,10 @@ var init_claudeCodeSession = __esm({
12634
13080
  import { appendFileSync, openSync as openSync2 } from "node:fs";
12635
13081
  import { createWriteStream } from "node:fs";
12636
13082
  import { homedir as homedir6 } from "node:os";
12637
- import { dirname as dirname3, join as join7 } from "node:path";
12638
- 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";
12639
13085
  function createRunnerLogger(logFile, consoleReporter) {
12640
- mkdirSync2(dirname3(logFile), { recursive: true });
13086
+ mkdirSync3(dirname3(logFile), { recursive: true });
12641
13087
  const fd = openSync2(logFile, "a");
12642
13088
  const stream = createWriteStream("", { fd, flags: "a", autoClose: true });
12643
13089
  const logger = ((event, payload) => {
@@ -12657,7 +13103,7 @@ function createRunnerLogger(logFile, consoleReporter) {
12657
13103
  function writeCliAuditEvent(event, payload, options = {}) {
12658
13104
  const logFile = options.logFile ?? defaultCliAuditLogFile();
12659
13105
  try {
12660
- mkdirSync2(dirname3(logFile), { recursive: true });
13106
+ mkdirSync3(dirname3(logFile), { recursive: true });
12661
13107
  appendFileSync(
12662
13108
  logFile,
12663
13109
  `${JSON.stringify({
@@ -12675,10 +13121,10 @@ function writeCliAuditEvent(event, payload, options = {}) {
12675
13121
  }
12676
13122
  function defaultCliAuditLogFile() {
12677
13123
  const override = process.env.LINZUMI_CLI_AUDIT_LOG?.trim();
12678
- 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;
12679
13125
  }
12680
13126
  function defaultRunnerLogFile() {
12681
- return join7(homedir6(), ".linzumi", "logs", "linzumi-runner.log");
13127
+ return join8(homedir6(), ".linzumi", "logs", "linzumi-runner.log");
12682
13128
  }
12683
13129
  function redactForCliLog(value) {
12684
13130
  return redactObject(value);
@@ -12709,10 +13155,10 @@ function redactObject(value) {
12709
13155
  );
12710
13156
  }
12711
13157
  function runnerConsolePayload(redacted, original) {
12712
- const consoleFields = objectValue2(original.runner_console);
13158
+ const consoleFields = objectValue3(original.runner_console);
12713
13159
  return consoleFields === void 0 ? redacted : { ...redacted, ...redactForCliLog(consoleFields) };
12714
13160
  }
12715
- function objectValue2(value) {
13161
+ function objectValue3(value) {
12716
13162
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
12717
13163
  }
12718
13164
  function redactArgs(args) {
@@ -12961,7 +13407,10 @@ var init_mcpConfig = __esm({
12961
13407
  import {
12962
13408
  spawn as spawn2
12963
13409
  } from "node:child_process";
13410
+ import { readFileSync as readFileSync6 } from "node:fs";
12964
13411
  import { createServer } from "node:net";
13412
+ import { homedir as homedir7 } from "node:os";
13413
+ import { join as join9 } from "node:path";
12965
13414
  import { WebSocket as NodeWebSocket } from "ws";
12966
13415
  async function chooseLoopbackPort() {
12967
13416
  return new Promise((resolve12, reject) => {
@@ -13178,10 +13627,46 @@ function codexModelProviderConfigArgs(provider) {
13178
13627
  "-c",
13179
13628
  `model_providers.${provider.id}.http_headers.${header}=${JSON.stringify(value)}`
13180
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
+ ),
13181
13638
  "-c",
13182
13639
  `model_provider=${JSON.stringify(provider.id)}`
13183
13640
  ];
13184
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
+ }
13185
13670
  async function connectCodexAppServer(websocketUrl, socketFactory = (url) => new NodeWebSocket(url)) {
13186
13671
  const websocket = await openCodexAppServerWebSocket(
13187
13672
  websocketUrl,
@@ -13505,22 +13990,22 @@ var init_codexAppServer = __esm({
13505
13990
  // src/codexProjectTrust.ts
13506
13991
  import {
13507
13992
  existsSync as existsSync5,
13508
- mkdirSync as mkdirSync3,
13509
- readFileSync as readFileSync6,
13993
+ mkdirSync as mkdirSync4,
13994
+ readFileSync as readFileSync7,
13510
13995
  realpathSync,
13511
- writeFileSync
13996
+ writeFileSync as writeFileSync2
13512
13997
  } from "node:fs";
13513
- import { homedir as homedir7 } from "node:os";
13514
- 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";
13515
14000
  function ensureCodexProjectTrusted(projectPath, options = {}) {
13516
14001
  const trustedPath = realpathSync(resolve3(projectPath));
13517
- const configHome = options.configHome ?? process.env.CODEX_HOME ?? join8(homedir7(), ".codex");
13518
- const configPath = join8(configHome, "config.toml");
13519
- 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") : "";
13520
14005
  const nextConfig = codexConfigWithTrustedProject(currentConfig, trustedPath);
13521
14006
  if (nextConfig !== currentConfig) {
13522
- mkdirSync3(configHome, { recursive: true });
13523
- writeFileSync(configPath, nextConfig);
14007
+ mkdirSync4(configHome, { recursive: true });
14008
+ writeFileSync2(configPath, nextConfig);
13524
14009
  }
13525
14010
  return trustedPath;
13526
14011
  }
@@ -13582,11 +14067,11 @@ function codexNotificationDiagnosticDetails(method, params) {
13582
14067
  }
13583
14068
  }
13584
14069
  function codexNotificationDiagnosticSummary(method, params) {
13585
- const error = objectValue3(params.error);
13586
- const item = objectValue3(params.item);
13587
- const code = stringValue2(params.code) ?? numberStringValue(params.code) ?? stringValue2(error?.code) ?? numberStringValue(error?.code) ?? stringValue2(params.status) ?? numberStringValue(params.status);
13588
- const message = stringValue2(params.message) ?? stringValue2(params.detail) ?? stringValue2(params.reason) ?? stringValue2(error?.message) ?? stringValue2(error?.detail) ?? stringValue2(error?.reason);
13589
- const itemType = stringValue2(item?.type);
14070
+ const error = objectValue4(params.error);
14071
+ const item = objectValue4(params.item);
14072
+ const code = stringValue3(params.code) ?? numberStringValue(params.code) ?? stringValue3(error?.code) ?? numberStringValue(error?.code) ?? stringValue3(params.status) ?? numberStringValue(params.status);
14073
+ const message = stringValue3(params.message) ?? stringValue3(params.detail) ?? stringValue3(params.reason) ?? stringValue3(error?.message) ?? stringValue3(error?.detail) ?? stringValue3(error?.reason);
14074
+ const itemType = stringValue3(item?.type);
13590
14075
  const redactedCode = code === void 0 ? void 0 : redactedDiagnosticText(code);
13591
14076
  const prefix = redactedCode === void 0 ? method : `${method} ${redactedCode}`;
13592
14077
  const detail = message === void 0 ? itemType === void 0 ? void 0 : `item.type=${itemType}` : redactedDiagnosticText(message);
@@ -13670,10 +14155,10 @@ function redactedDiagnosticText(value) {
13670
14155
  }
13671
14156
  ).replace(/\bBearer\s+[^\s,;]+/gi, "Bearer [redacted]");
13672
14157
  }
13673
- function objectValue3(value) {
14158
+ function objectValue4(value) {
13674
14159
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
13675
14160
  }
13676
- function stringValue2(value) {
14161
+ function stringValue3(value) {
13677
14162
  return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
13678
14163
  }
13679
14164
  function numberStringValue(value) {
@@ -13748,7 +14233,7 @@ function diagnosticStrings(value, depth) {
13748
14233
  if (Array.isArray(value)) {
13749
14234
  return value.flatMap((entry) => diagnosticStrings(entry, depth + 1));
13750
14235
  }
13751
- const object = objectValue4(value);
14236
+ const object = objectValue5(value);
13752
14237
  if (object === void 0) {
13753
14238
  return [];
13754
14239
  }
@@ -13758,9 +14243,9 @@ function diagnosticStrings(value, depth) {
13758
14243
  ]);
13759
14244
  }
13760
14245
  function tokenUsageSummary(params) {
13761
- const usage = objectValue4(params.tokenUsage) ?? objectValue4(params.token_usage) ?? objectValue4(params.usage) ?? params;
13762
- const total = tokenUsageBreakdownSummary(objectValue4(usage.total)) ?? tokenUsageBreakdownSummary(objectValue4(usage.totalUsage)) ?? tokenUsageBreakdownSummary(objectValue4(usage.total_usage)) ?? tokenUsageBreakdownSummary(objectValue4(params.totalTokenUsage)) ?? tokenUsageBreakdownSummary(objectValue4(params.total_token_usage)) ?? tokenUsageBreakdownSummary(usage);
13763
- const last = tokenUsageBreakdownSummary(objectValue4(usage.last)) ?? tokenUsageBreakdownSummary(objectValue4(usage.lastUsage)) ?? tokenUsageBreakdownSummary(objectValue4(usage.last_usage)) ?? tokenUsageBreakdownSummary(objectValue4(params.lastTokenUsage)) ?? tokenUsageBreakdownSummary(objectValue4(params.last_token_usage));
14246
+ const usage = objectValue5(params.tokenUsage) ?? objectValue5(params.token_usage) ?? objectValue5(params.usage) ?? params;
14247
+ const total = tokenUsageBreakdownSummary(objectValue5(usage.total)) ?? tokenUsageBreakdownSummary(objectValue5(usage.totalUsage)) ?? tokenUsageBreakdownSummary(objectValue5(usage.total_usage)) ?? tokenUsageBreakdownSummary(objectValue5(params.totalTokenUsage)) ?? tokenUsageBreakdownSummary(objectValue5(params.total_token_usage)) ?? tokenUsageBreakdownSummary(usage);
14248
+ const last = tokenUsageBreakdownSummary(objectValue5(usage.last)) ?? tokenUsageBreakdownSummary(objectValue5(usage.lastUsage)) ?? tokenUsageBreakdownSummary(objectValue5(usage.last_usage)) ?? tokenUsageBreakdownSummary(objectValue5(params.lastTokenUsage)) ?? tokenUsageBreakdownSummary(objectValue5(params.last_token_usage));
13764
14249
  const summary = [
13765
14250
  total === void 0 ? void 0 : `total ${total}`,
13766
14251
  last === void 0 ? void 0 : `last ${last}`
@@ -13771,8 +14256,8 @@ function tokenUsageBreakdownSummary(breakdown) {
13771
14256
  if (breakdown === void 0) {
13772
14257
  return void 0;
13773
14258
  }
13774
- const inputDetails = objectValue4(breakdown.inputTokensDetails) ?? objectValue4(breakdown.input_tokens_details);
13775
- const outputDetails = objectValue4(breakdown.outputTokensDetails) ?? objectValue4(breakdown.output_tokens_details);
14259
+ const inputDetails = objectValue5(breakdown.inputTokensDetails) ?? objectValue5(breakdown.input_tokens_details);
14260
+ const outputDetails = objectValue5(breakdown.outputTokensDetails) ?? objectValue5(breakdown.output_tokens_details);
13776
14261
  const input = integerValue2(breakdown.inputTokens) ?? integerValue2(breakdown.input_tokens) ?? integerValue2(breakdown.promptTokens) ?? integerValue2(breakdown.prompt_tokens);
13777
14262
  const output = integerValue2(breakdown.outputTokens) ?? integerValue2(breakdown.output_tokens) ?? integerValue2(breakdown.completionTokens) ?? integerValue2(breakdown.completion_tokens);
13778
14263
  const total = integerValue2(breakdown.totalTokens) ?? integerValue2(breakdown.total_tokens);
@@ -13788,10 +14273,10 @@ function tokenUsageBreakdownSummary(breakdown) {
13788
14273
  return values.length === 0 ? void 0 : values.join(" / ");
13789
14274
  }
13790
14275
  function rateLimitSummary(params) {
13791
- const rateLimits = objectValue4(params.rateLimits) ?? objectValue4(params.rate_limits) ?? objectValue4(params.limits) ?? params;
14276
+ const rateLimits = objectValue5(params.rateLimits) ?? objectValue5(params.rate_limits) ?? objectValue5(params.limits) ?? params;
13792
14277
  const direct = rateLimitBucketSummary(rateLimits, void 0);
13793
14278
  const children = Object.entries(rateLimits).flatMap(([name, value]) => {
13794
- const bucket = objectValue4(value);
14279
+ const bucket = objectValue5(value);
13795
14280
  return bucket === void 0 ? [] : [rateLimitBucketSummary(bucket, name)];
13796
14281
  });
13797
14282
  const summaries = [direct, ...children].filter(
@@ -13800,11 +14285,11 @@ function rateLimitSummary(params) {
13800
14285
  return summaries.length === 0 ? void 0 : summaries.join(" | ");
13801
14286
  }
13802
14287
  function rateLimitBucketSummary(bucket, fallbackName) {
13803
- const name = stringValue3(bucket.limitName) ?? stringValue3(bucket.limit_name) ?? stringValue3(bucket.name) ?? stringValue3(bucket.type) ?? fallbackName;
13804
- const plan = stringValue3(bucket.planType) ?? stringValue3(bucket.plan_type) ?? stringValue3(bucket.plan);
14288
+ const name = stringValue4(bucket.limitName) ?? stringValue4(bucket.limit_name) ?? stringValue4(bucket.name) ?? stringValue4(bucket.type) ?? fallbackName;
14289
+ const plan = stringValue4(bucket.planType) ?? stringValue4(bucket.plan_type) ?? stringValue4(bucket.plan);
13805
14290
  const remaining = integerValue2(bucket.remaining) ?? integerValue2(bucket.remainingRequests) ?? integerValue2(bucket.remaining_requests) ?? integerValue2(bucket.remainingTokens) ?? integerValue2(bucket.remaining_tokens);
13806
14291
  const limit = integerValue2(bucket.limit) ?? integerValue2(bucket.requestLimit) ?? integerValue2(bucket.request_limit) ?? integerValue2(bucket.limitRequests) ?? integerValue2(bucket.limit_requests) ?? integerValue2(bucket.tokenLimit) ?? integerValue2(bucket.token_limit) ?? integerValue2(bucket.limitTokens) ?? integerValue2(bucket.limit_tokens);
13807
- const reset = stringValue3(bucket.resetAt) ?? stringValue3(bucket.reset_at) ?? stringValue3(bucket.resetsAt) ?? stringValue3(bucket.resets_at) ?? unixTimestampValue(bucket.resetsAt) ?? unixTimestampValue(bucket.resets_at) ?? secondsValue(bucket.resetAfterSeconds) ?? secondsValue(bucket.reset_after_seconds) ?? secondsValue(bucket.retryAfterSeconds) ?? secondsValue(bucket.retry_after_seconds);
14292
+ const reset = stringValue4(bucket.resetAt) ?? stringValue4(bucket.reset_at) ?? stringValue4(bucket.resetsAt) ?? stringValue4(bucket.resets_at) ?? unixTimestampValue(bucket.resetsAt) ?? unixTimestampValue(bucket.resets_at) ?? secondsValue(bucket.resetAfterSeconds) ?? secondsValue(bucket.reset_after_seconds) ?? secondsValue(bucket.retryAfterSeconds) ?? secondsValue(bucket.retry_after_seconds);
13808
14293
  const usedPercent = integerValue2(bucket.usedPercent) ?? integerValue2(bucket.used_percent);
13809
14294
  const windowDurationMins = integerValue2(bucket.windowDurationMins) ?? integerValue2(bucket.window_duration_mins);
13810
14295
  const label = [name, plan].filter((value) => value !== void 0).join(" ");
@@ -13831,10 +14316,10 @@ function unixTimestampValue(value) {
13831
14316
  const seconds = integerValue2(value);
13832
14317
  return seconds === void 0 ? void 0 : new Date(seconds * 1e3).toISOString();
13833
14318
  }
13834
- function objectValue4(value) {
14319
+ function objectValue5(value) {
13835
14320
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
13836
14321
  }
13837
- function stringValue3(value) {
14322
+ function stringValue4(value) {
13838
14323
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
13839
14324
  }
13840
14325
  function integerValue2(value) {
@@ -13865,7 +14350,7 @@ var init_codexNotificationConsoleStats = __esm({
13865
14350
 
13866
14351
  // src/localCapabilities.ts
13867
14352
  import { realpathSync as realpathSync2 } from "node:fs";
13868
- import { homedir as homedir8 } from "node:os";
14353
+ import { homedir as homedir9 } from "node:os";
13869
14354
  import { isAbsolute as isAbsolute3, relative as relative2, resolve as resolve4 } from "node:path";
13870
14355
  function parseAllowedCwdList(value) {
13871
14356
  if (value === void 0) {
@@ -13914,7 +14399,7 @@ function expandUserPath(pathValue) {
13914
14399
  }
13915
14400
  function currentHomeDirectory() {
13916
14401
  const configuredHome = process.env.HOME;
13917
- return configuredHome === void 0 || configuredHome.trim() === "" ? homedir8() : configuredHome;
14402
+ return configuredHome === void 0 || configuredHome.trim() === "" ? homedir9() : configuredHome;
13918
14403
  }
13919
14404
  function resolveAllowedCwd(requestedCwd, allowedRoots) {
13920
14405
  if (requestedCwd === void 0 || requestedCwd.trim() === "") {
@@ -14314,17 +14799,17 @@ import {
14314
14799
  chmodSync,
14315
14800
  existsSync as existsSync6,
14316
14801
  linkSync,
14317
- mkdirSync as mkdirSync4,
14318
- readFileSync as readFileSync7,
14802
+ mkdirSync as mkdirSync5,
14803
+ readFileSync as readFileSync8,
14319
14804
  realpathSync as realpathSync3,
14320
14805
  unlinkSync,
14321
- writeFileSync as writeFileSync2
14806
+ writeFileSync as writeFileSync3
14322
14807
  } from "node:fs";
14323
- import { homedir as homedir9 } from "node:os";
14324
- 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";
14325
14810
  function localConfigPath(env = process.env) {
14326
14811
  const override = env.LINZUMI_CONFIG_FILE;
14327
- 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");
14328
14813
  }
14329
14814
  function localConfigScopeKey(linzumiUrl) {
14330
14815
  const normalizedUrl = kandanHttpBaseUrl(linzumiUrl);
@@ -14405,21 +14890,21 @@ function ensureLocalRunnerId(path2 = localConfigPath(), createRunnerId = default
14405
14890
  }
14406
14891
  function localMachineIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
14407
14892
  if (linzumiUrl !== void 0 && localConfigScopeKey(linzumiUrl) !== prodConfigScope) {
14408
- return join9(
14893
+ return join11(
14409
14894
  dirname4(configPath),
14410
14895
  `${basename5(configPath)}.${localConfigScopeFileStem(linzumiUrl)}.machine-id`
14411
14896
  );
14412
14897
  }
14413
- return join9(dirname4(configPath), `${basename5(configPath)}.machine-id`);
14898
+ return join11(dirname4(configPath), `${basename5(configPath)}.machine-id`);
14414
14899
  }
14415
14900
  function localRunnerIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
14416
14901
  if (linzumiUrl !== void 0 && localConfigScopeKey(linzumiUrl) !== prodConfigScope) {
14417
- return join9(
14902
+ return join11(
14418
14903
  dirname4(configPath),
14419
14904
  `${basename5(configPath)}.${localConfigScopeFileStem(linzumiUrl)}.runner-id`
14420
14905
  );
14421
14906
  }
14422
- return join9(dirname4(configPath), `${basename5(configPath)}.runner-id`);
14907
+ return join11(dirname4(configPath), `${basename5(configPath)}.runner-id`);
14423
14908
  }
14424
14909
  function readConfiguredAllowedCwdDetailsForLinzumiUrl(linzumiUrl, path2 = localConfigPath()) {
14425
14910
  return readConfiguredAllowedCwdDetailsFromConfig(
@@ -14549,7 +15034,7 @@ function writeLocalSignupAuth(auth, path2 = localConfigPath()) {
14549
15034
  version: 1,
14550
15035
  signupAuth: nextSignupAuth
14551
15036
  };
14552
- mkdirSync4(dirname4(path2), { recursive: true });
15037
+ mkdirSync5(dirname4(path2), { recursive: true });
14553
15038
  writeLocalConfigJson(path2, next);
14554
15039
  return signupAuthFromJson(nextSignupAuth);
14555
15040
  }
@@ -14557,7 +15042,7 @@ function writeLocalConfigJson(path2, payload) {
14557
15042
  if (existsSync6(path2)) {
14558
15043
  chmodSync(path2, localConfigFileMode);
14559
15044
  }
14560
- writeFileSync2(path2, `${JSON.stringify(payload, null, 2)}
15045
+ writeFileSync3(path2, `${JSON.stringify(payload, null, 2)}
14561
15046
  `, {
14562
15047
  encoding: "utf8",
14563
15048
  mode: localConfigFileMode
@@ -14584,7 +15069,7 @@ function readLocalConfigFile(path2) {
14584
15069
  if (!existsSync6(path2)) {
14585
15070
  return { version: 1, allowedCwds: [] };
14586
15071
  }
14587
- const parsed = JSON.parse(readFileSync7(path2, "utf8"));
15072
+ const parsed = JSON.parse(readFileSync8(path2, "utf8"));
14588
15073
  if (!isConfigPayload(parsed)) {
14589
15074
  throw new Error(`invalid Linzumi config: ${path2}`);
14590
15075
  }
@@ -14613,7 +15098,7 @@ function writeLocalConfigSection(config, path2, linzumiUrl) {
14613
15098
  version: 1,
14614
15099
  [scopeKey]: nextSection
14615
15100
  };
14616
- mkdirSync4(dirname4(path2), { recursive: true });
15101
+ mkdirSync5(dirname4(path2), { recursive: true });
14617
15102
  writeLocalConfigJson(path2, next);
14618
15103
  }
14619
15104
  function isConfigPayload(value) {
@@ -14688,12 +15173,12 @@ function ensureLocalMachineIdSeed(configPath, createMachineId, linzumiUrl) {
14688
15173
  if (!machineIdValid(machineId)) {
14689
15174
  throw new Error(`invalid generated Linzumi machine id: ${machineId}`);
14690
15175
  }
14691
- mkdirSync4(dirname4(seedPath), { recursive: true });
14692
- const tempPath = join9(
15176
+ mkdirSync5(dirname4(seedPath), { recursive: true });
15177
+ const tempPath = join11(
14693
15178
  dirname4(seedPath),
14694
15179
  `.${basename5(seedPath)}.${process.pid}.${randomUUID2()}.tmp`
14695
15180
  );
14696
- writeFileSync2(tempPath, `${machineId}
15181
+ writeFileSync3(tempPath, `${machineId}
14697
15182
  `, { encoding: "utf8", flag: "wx" });
14698
15183
  try {
14699
15184
  linkSync(tempPath, seedPath);
@@ -14716,12 +15201,12 @@ function ensureLocalRunnerIdSeed(configPath, createRunnerId, linzumiUrl) {
14716
15201
  if (!runnerIdValid(runnerId)) {
14717
15202
  throw new Error(`invalid generated Linzumi runner id: ${runnerId}`);
14718
15203
  }
14719
- mkdirSync4(dirname4(seedPath), { recursive: true });
14720
- const tempPath = join9(
15204
+ mkdirSync5(dirname4(seedPath), { recursive: true });
15205
+ const tempPath = join11(
14721
15206
  dirname4(seedPath),
14722
15207
  `.${basename5(seedPath)}.${process.pid}.${randomUUID2()}.tmp`
14723
15208
  );
14724
- writeFileSync2(tempPath, `${runnerId}
15209
+ writeFileSync3(tempPath, `${runnerId}
14725
15210
  `, { encoding: "utf8", flag: "wx" });
14726
15211
  try {
14727
15212
  linkSync(tempPath, seedPath);
@@ -14736,14 +15221,14 @@ function ensureLocalRunnerIdSeed(configPath, createRunnerId, linzumiUrl) {
14736
15221
  }
14737
15222
  }
14738
15223
  function readMachineIdSeed(seedPath) {
14739
- const machineId = readFileSync7(seedPath, "utf8").trim();
15224
+ const machineId = readFileSync8(seedPath, "utf8").trim();
14740
15225
  if (!machineIdValid(machineId)) {
14741
15226
  throw new Error(`invalid Linzumi machine id seed: ${seedPath}`);
14742
15227
  }
14743
15228
  return machineId;
14744
15229
  }
14745
15230
  function readRunnerIdSeed(seedPath) {
14746
- const runnerId = readFileSync7(seedPath, "utf8").trim();
15231
+ const runnerId = readFileSync8(seedPath, "utf8").trim();
14747
15232
  if (!runnerIdValid(runnerId)) {
14748
15233
  throw new Error(`invalid Linzumi runner id seed: ${seedPath}`);
14749
15234
  }
@@ -15042,8 +15527,8 @@ var init_remoteCodexExecutionContext = __esm({
15042
15527
  });
15043
15528
 
15044
15529
  // src/helloLinzumiProject.ts
15045
- import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync8, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
15046
- 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";
15047
15532
  import { fileURLToPath as fileURLToPath2 } from "node:url";
15048
15533
  function createHelloLinzumiProject(input = {}) {
15049
15534
  const options = typeof input === "string" ? { rootPath: input } : input;
@@ -15052,9 +15537,9 @@ function createHelloLinzumiProject(input = {}) {
15052
15537
  const host = normalizeHost(options.host);
15053
15538
  assertTcpPort(port);
15054
15539
  assertWritableDemoRoot(root, options.reset === true);
15055
- mkdirSync5(join10(root, "src"), { recursive: true });
15540
+ mkdirSync6(join12(root, "src"), { recursive: true });
15056
15541
  for (const file of demoFiles({ root, port, host })) {
15057
- writeFileSync3(join10(root, file.path), file.content, "utf8");
15542
+ writeFileSync4(join12(root, file.path), file.content, "utf8");
15058
15543
  }
15059
15544
  return {
15060
15545
  root,
@@ -15098,10 +15583,10 @@ function assertWritableDemoRoot(root, reset) {
15098
15583
  if (!existsSync7(root)) {
15099
15584
  return;
15100
15585
  }
15101
- const markerPath = join10(root, markerFile);
15102
- 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";
15103
15588
  if (isDemoRoot && reset) {
15104
- rmSync(root, { recursive: true, force: true });
15589
+ rmSync2(root, { recursive: true, force: true });
15105
15590
  return;
15106
15591
  }
15107
15592
  if (isDemoRoot) {
@@ -15134,7 +15619,7 @@ var init_helloLinzumiProject = __esm({
15134
15619
  defaultHelloLinzumiHost = "0.0.0.0";
15135
15620
  markerFile = ".linzumi-demo-project";
15136
15621
  moduleDir = dirname5(fileURLToPath2(import.meta.url));
15137
- linzumiLogoSvg = readFileSync8(join10(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
15622
+ linzumiLogoSvg = readFileSync9(join12(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
15138
15623
  packageJson = `${JSON.stringify(
15139
15624
  {
15140
15625
  name: "hello-linzumi",
@@ -15936,14 +16421,14 @@ import {
15936
16421
  copyFileSync,
15937
16422
  cpSync,
15938
16423
  existsSync as existsSync8,
15939
- mkdirSync as mkdirSync6,
16424
+ mkdirSync as mkdirSync7,
15940
16425
  mkdtempSync,
15941
- readFileSync as readFileSync9,
16426
+ readFileSync as readFileSync10,
15942
16427
  realpathSync as realpathSync4,
15943
- writeFileSync as writeFileSync4
16428
+ writeFileSync as writeFileSync5
15944
16429
  } from "node:fs";
15945
16430
  import { tmpdir } from "node:os";
15946
- 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";
15947
16432
  function isStartLocalEditorControl(control) {
15948
16433
  return control.type === "start_local_editor";
15949
16434
  }
@@ -16161,24 +16646,24 @@ function codeServerArgs(port, cwd, userDataDir, extensionsDir) {
16161
16646
  }
16162
16647
  function prepareCodeServerProfile(collaboration, editorRuntime) {
16163
16648
  try {
16164
- const userDataDir = mkdtempSync(join11(tmpdir(), "kandan-local-editor-"));
16165
- const extensionsDir = join11(userDataDir, "extensions");
16166
- const collaborationServerDir = join11(userDataDir, "collaboration-server");
16167
- const tempDir = join11(userDataDir, "tmp");
16168
- const userSettingsDir = join11(userDataDir, "User");
16169
- mkdirSync6(userSettingsDir, { recursive: true });
16170
- mkdirSync6(extensionsDir, { recursive: true });
16171
- mkdirSync6(collaborationServerDir, { recursive: true });
16172
- 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 });
16173
16658
  if (editorRuntime !== void 0) {
16174
16659
  ensureCodeServerBrowserExtensionAssets(editorRuntime);
16175
16660
  installDirectory(
16176
16661
  editorRuntime.assets.documentStateExtensionDir,
16177
- join11(extensionsDir, "kandan.document-state-telemetry")
16662
+ join13(extensionsDir, "kandan.document-state-telemetry")
16178
16663
  );
16179
16664
  }
16180
- writeFileSync4(
16181
- join11(userSettingsDir, "settings.json"),
16665
+ writeFileSync5(
16666
+ join13(userSettingsDir, "settings.json"),
16182
16667
  JSON.stringify(codeServerSettings(collaboration), null, 2)
16183
16668
  );
16184
16669
  return { ok: true, userDataDir, extensionsDir, collaborationServerDir };
@@ -16190,14 +16675,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16190
16675
  const vscodeRoot = codeServerVscodeRoot(runtime);
16191
16676
  const repairs = [
16192
16677
  {
16193
- source: join11(
16678
+ source: join13(
16194
16679
  vscodeRoot,
16195
16680
  "extensions",
16196
16681
  "git-base",
16197
16682
  "dist",
16198
16683
  "extension.js"
16199
16684
  ),
16200
- target: join11(
16685
+ target: join13(
16201
16686
  vscodeRoot,
16202
16687
  "extensions",
16203
16688
  "git-base",
@@ -16208,14 +16693,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16208
16693
  required: true
16209
16694
  },
16210
16695
  {
16211
- source: join11(
16696
+ source: join13(
16212
16697
  vscodeRoot,
16213
16698
  "extensions",
16214
16699
  "git-base",
16215
16700
  "dist",
16216
16701
  "extension.js.map"
16217
16702
  ),
16218
- target: join11(
16703
+ target: join13(
16219
16704
  vscodeRoot,
16220
16705
  "extensions",
16221
16706
  "git-base",
@@ -16226,14 +16711,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16226
16711
  required: false
16227
16712
  },
16228
16713
  {
16229
- source: join11(
16714
+ source: join13(
16230
16715
  vscodeRoot,
16231
16716
  "extensions",
16232
16717
  "merge-conflict",
16233
16718
  "dist",
16234
16719
  "mergeConflictMain.js"
16235
16720
  ),
16236
- target: join11(
16721
+ target: join13(
16237
16722
  vscodeRoot,
16238
16723
  "extensions",
16239
16724
  "merge-conflict",
@@ -16244,14 +16729,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16244
16729
  required: true
16245
16730
  },
16246
16731
  {
16247
- source: join11(
16732
+ source: join13(
16248
16733
  vscodeRoot,
16249
16734
  "extensions",
16250
16735
  "merge-conflict",
16251
16736
  "dist",
16252
16737
  "mergeConflictMain.js.map"
16253
16738
  ),
16254
- target: join11(
16739
+ target: join13(
16255
16740
  vscodeRoot,
16256
16741
  "extensions",
16257
16742
  "merge-conflict",
@@ -16269,7 +16754,7 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16269
16754
  case (!required3 && !existsSync8(source)):
16270
16755
  return;
16271
16756
  default:
16272
- mkdirSync6(dirname6(target), { recursive: true });
16757
+ mkdirSync7(dirname6(target), { recursive: true });
16273
16758
  copyFileSync(source, target);
16274
16759
  return;
16275
16760
  }
@@ -16277,10 +16762,10 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16277
16762
  }
16278
16763
  function codeServerVscodeRoot(runtime) {
16279
16764
  const roots = uniquePaths([
16280
- join11(runtime.root, "lib", "vscode"),
16281
- join11(dirname6(dirname6(runtime.codeServerBin)), "lib", "vscode"),
16765
+ join13(runtime.root, "lib", "vscode"),
16766
+ join13(dirname6(dirname6(runtime.codeServerBin)), "lib", "vscode"),
16282
16767
  ...wrappedCodeServerBin(runtime.codeServerBin).map(
16283
- (codeServerBin) => join11(dirname6(dirname6(codeServerBin)), "lib", "vscode")
16768
+ (codeServerBin) => join13(dirname6(dirname6(codeServerBin)), "lib", "vscode")
16284
16769
  )
16285
16770
  ]);
16286
16771
  const rootWithRequiredAssets = roots.find(
@@ -16296,7 +16781,7 @@ function codeServerVscodeRoot(runtime) {
16296
16781
  }
16297
16782
  function wrappedCodeServerBin(codeServerBin) {
16298
16783
  try {
16299
- const script = readFileSync9(codeServerBin, "utf8");
16784
+ const script = readFileSync10(codeServerBin, "utf8");
16300
16785
  const match = script.match(
16301
16786
  /exec\s+(?:"([^"]+)"|'([^']+)'|([^\s]+))\s+"\$@"/u
16302
16787
  );
@@ -16308,8 +16793,8 @@ function wrappedCodeServerBin(codeServerBin) {
16308
16793
  }
16309
16794
  function codeServerBrowserAssetSources(vscodeRoot) {
16310
16795
  return [
16311
- join11(vscodeRoot, "extensions", "git-base", "dist", "extension.js"),
16312
- join11(
16796
+ join13(vscodeRoot, "extensions", "git-base", "dist", "extension.js"),
16797
+ join13(
16313
16798
  vscodeRoot,
16314
16799
  "extensions",
16315
16800
  "merge-conflict",
@@ -16388,10 +16873,10 @@ function prepareLinuxCodeServerLaunch(options) {
16388
16873
  options.cwd,
16389
16874
  "--setenv",
16390
16875
  "XDG_DATA_HOME",
16391
- join11(options.userDataDir, "data"),
16876
+ join13(options.userDataDir, "data"),
16392
16877
  "--setenv",
16393
16878
  "XDG_CONFIG_HOME",
16394
- join11(options.userDataDir, "config"),
16879
+ join13(options.userDataDir, "config"),
16395
16880
  ...readOnlyRoots.flatMap((path2) => ["--ro-bind-try", path2, path2]),
16396
16881
  "--bind",
16397
16882
  options.cwd,
@@ -16432,7 +16917,7 @@ function resolveCodeServerExecutable(command, envPath) {
16432
16917
  if (directory.trim() === "") {
16433
16918
  continue;
16434
16919
  }
16435
- const candidate = join11(directory, command);
16920
+ const candidate = join13(directory, command);
16436
16921
  if (!existsSync8(candidate)) {
16437
16922
  continue;
16438
16923
  }
@@ -16518,7 +17003,7 @@ async function startCollaborationSidecar(collaboration, profile, editorRuntime,
16518
17003
  ]);
16519
17004
  const command = nodeRuntimeExecutable();
16520
17005
  const args = [
16521
- join11(
17006
+ join13(
16522
17007
  profile.collaborationServerDir,
16523
17008
  "open-collaboration-server",
16524
17009
  "bundle",
@@ -16613,11 +17098,11 @@ function nodeRuntimeExecutable(env = process.env, execPath = process.execPath) {
16613
17098
  return basename6(execPath).toLowerCase().includes("bun") ? "node" : execPath;
16614
17099
  }
16615
17100
  async function installLocalTarball(archivePath, destinationDir) {
16616
- mkdirSync6(destinationDir, { recursive: true });
17101
+ mkdirSync7(destinationDir, { recursive: true });
16617
17102
  await runProcess("tar", ["-xzf", archivePath, "-C", destinationDir]);
16618
17103
  }
16619
17104
  function installDirectory(sourceDir, destinationDir) {
16620
- mkdirSync6(dirname6(destinationDir), { recursive: true });
17105
+ mkdirSync7(dirname6(destinationDir), { recursive: true });
16621
17106
  cpSync(sourceDir, destinationDir, { recursive: true });
16622
17107
  }
16623
17108
  function codeServerEnv(env, cwd, userDataDir, collaboration) {
@@ -16635,7 +17120,7 @@ function codeServerEnv(env, cwd, userDataDir, collaboration) {
16635
17120
  KANDAN_EDITOR_COLLABORATION_ENTRY_MODE: "kandan_auto_host_or_join",
16636
17121
  KANDAN_EDITOR_COLLABORATION_ROOM_ID: collaboration.roomId,
16637
17122
  KANDAN_EDITOR_COLLABORATION_SERVER_URL: collaboration.bootstrapServerUrl,
16638
- KANDAN_EDITOR_COLLABORATION_AUTO_HOST_CLAIM_PATH: join11(
17123
+ KANDAN_EDITOR_COLLABORATION_AUTO_HOST_CLAIM_PATH: join13(
16639
17124
  userDataDir,
16640
17125
  "kandan-oct-auto-host.lock"
16641
17126
  )
@@ -16844,15 +17329,15 @@ import {
16844
17329
  createReadStream,
16845
17330
  createWriteStream as createWriteStream2,
16846
17331
  existsSync as existsSync9,
16847
- mkdirSync as mkdirSync7,
17332
+ mkdirSync as mkdirSync8,
16848
17333
  mkdtempSync as mkdtempSync2,
16849
- readFileSync as readFileSync10,
17334
+ readFileSync as readFileSync11,
16850
17335
  renameSync,
16851
- rmSync as rmSync2,
16852
- writeFileSync as writeFileSync5
17336
+ rmSync as rmSync3,
17337
+ writeFileSync as writeFileSync6
16853
17338
  } from "node:fs";
16854
- import { homedir as homedir10 } from "node:os";
16855
- 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";
16856
17341
  import { Readable } from "node:stream";
16857
17342
  import { pipeline } from "node:stream/promises";
16858
17343
  async function resolveEditorRuntime(options) {
@@ -17043,14 +17528,14 @@ function normalizeRuntimeAssets(value) {
17043
17528
  }
17044
17529
  function installedRuntime(cacheRoot, manifest) {
17045
17530
  const runtimeRoot = runtimeInstallRoot(cacheRoot, manifest);
17046
- const manifestPath = join12(runtimeRoot, manifest.manifestPath);
17047
- const codeServerBin = join12(runtimeRoot, manifest.codeServerBinPath);
17531
+ const manifestPath = join14(runtimeRoot, manifest.manifestPath);
17532
+ const codeServerBin = join14(runtimeRoot, manifest.codeServerBinPath);
17048
17533
  const assets = verifiedRuntimeAssetPaths(runtimeRoot, manifest);
17049
17534
  if (!existsSync9(manifestPath) || !existsSync9(codeServerBin) || assets === void 0) {
17050
17535
  return { ok: false };
17051
17536
  }
17052
17537
  try {
17053
- const installed = JSON.parse(readFileSync10(manifestPath, "utf8"));
17538
+ const installed = JSON.parse(readFileSync11(manifestPath, "utf8"));
17054
17539
  if (isJsonObject(installed) && installed.version === manifest.version && installed.platform === manifest.platform && (installed.archiveSha256 === void 0 || installed.archiveSha256 === manifest.archiveSha256)) {
17055
17540
  return {
17056
17541
  ok: true,
@@ -17068,10 +17553,10 @@ function installedRuntime(cacheRoot, manifest) {
17068
17553
  return { ok: false };
17069
17554
  }
17070
17555
  async function installRuntime(args) {
17071
- mkdirSync7(args.cacheRoot, { recursive: true });
17072
- const tempRoot = mkdtempSync2(join12(args.cacheRoot, ".install-"));
17073
- const archivePath = join12(tempRoot, "runtime.tar.gz");
17074
- 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");
17075
17560
  try {
17076
17561
  const downloaded = await downloadArchive({
17077
17562
  kandanUrl: args.kandanUrl,
@@ -17083,7 +17568,7 @@ async function installRuntime(args) {
17083
17568
  if (!downloaded.ok) {
17084
17569
  return downloaded;
17085
17570
  }
17086
- mkdirSync7(extractRoot, { recursive: true });
17571
+ mkdirSync8(extractRoot, { recursive: true });
17087
17572
  if (!await args.extractArchive(archivePath, extractRoot)) {
17088
17573
  return { ok: false, reason: "archive_extract_failed" };
17089
17574
  }
@@ -17096,14 +17581,14 @@ async function installRuntime(args) {
17096
17581
  if (!assetsInstalled) {
17097
17582
  return { ok: false, reason: "install_failed" };
17098
17583
  }
17099
- const manifestPath = join12(extractRoot, args.manifest.manifestPath);
17100
- const codeServerBin = join12(extractRoot, args.manifest.codeServerBinPath);
17584
+ const manifestPath = join14(extractRoot, args.manifest.manifestPath);
17585
+ const codeServerBin = join14(extractRoot, args.manifest.codeServerBinPath);
17101
17586
  const assets = verifiedRuntimeAssetPaths(extractRoot, args.manifest);
17102
17587
  if (!existsSync9(codeServerBin) || assets === void 0) {
17103
17588
  return { ok: false, reason: "invalid_archive" };
17104
17589
  }
17105
- mkdirSync7(dirname7(manifestPath), { recursive: true });
17106
- writeFileSync5(
17590
+ mkdirSync8(dirname7(manifestPath), { recursive: true });
17591
+ writeFileSync6(
17107
17592
  manifestPath,
17108
17593
  JSON.stringify(
17109
17594
  {
@@ -17120,29 +17605,29 @@ async function installRuntime(args) {
17120
17605
  )
17121
17606
  );
17122
17607
  const targetRoot = runtimeInstallRoot(args.cacheRoot, args.manifest);
17123
- rmSync2(targetRoot, { recursive: true, force: true });
17124
- mkdirSync7(dirname7(targetRoot), { recursive: true });
17608
+ rmSync3(targetRoot, { recursive: true, force: true });
17609
+ mkdirSync8(dirname7(targetRoot), { recursive: true });
17125
17610
  renameSync(extractRoot, targetRoot);
17126
17611
  return {
17127
17612
  ok: true,
17128
17613
  runtime: {
17129
17614
  mode: "server_managed",
17130
17615
  root: targetRoot,
17131
- codeServerBin: join12(targetRoot, args.manifest.codeServerBinPath),
17616
+ codeServerBin: join14(targetRoot, args.manifest.codeServerBinPath),
17132
17617
  assets: {
17133
- collaborationExtensionTarball: join12(
17618
+ collaborationExtensionTarball: join14(
17134
17619
  targetRoot,
17135
17620
  "kandan",
17136
17621
  "editor_extensions",
17137
17622
  "typefox.open-collaboration-tools.tar.gz"
17138
17623
  ),
17139
- collaborationServerTarball: join12(
17624
+ collaborationServerTarball: join14(
17140
17625
  targetRoot,
17141
17626
  "kandan",
17142
17627
  "editor_servers",
17143
17628
  "open-collaboration-server.tar.gz"
17144
17629
  ),
17145
- documentStateExtensionDir: join12(
17630
+ documentStateExtensionDir: join14(
17146
17631
  targetRoot,
17147
17632
  "kandan",
17148
17633
  "editor_extensions",
@@ -17154,12 +17639,12 @@ async function installRuntime(args) {
17154
17639
  } catch (_error) {
17155
17640
  return { ok: false, reason: "install_failed" };
17156
17641
  } finally {
17157
- rmSync2(tempRoot, { recursive: true, force: true });
17642
+ rmSync3(tempRoot, { recursive: true, force: true });
17158
17643
  }
17159
17644
  }
17160
17645
  async function materializeRuntimeAssets(args) {
17161
17646
  for (const asset of args.manifest.assets) {
17162
- const targetPath = join12(args.runtimeRoot, asset.path);
17647
+ const targetPath = join14(args.runtimeRoot, asset.path);
17163
17648
  try {
17164
17649
  const bytes = await runtimeAssetBytes({
17165
17650
  kandanUrl: args.kandanUrl,
@@ -17169,8 +17654,8 @@ async function materializeRuntimeAssets(args) {
17169
17654
  if (bytes === void 0) {
17170
17655
  continue;
17171
17656
  }
17172
- mkdirSync7(dirname7(targetPath), { recursive: true });
17173
- writeFileSync5(targetPath, bytes);
17657
+ mkdirSync8(dirname7(targetPath), { recursive: true });
17658
+ writeFileSync6(targetPath, bytes);
17174
17659
  } catch (_error) {
17175
17660
  return false;
17176
17661
  }
@@ -17260,19 +17745,19 @@ function runtimeInstallRoot(cacheRoot, manifest) {
17260
17745
  return resolve7(cacheRoot, manifest.platform, manifest.archiveSha256);
17261
17746
  }
17262
17747
  function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17263
- const collaborationExtensionTarball = join12(
17748
+ const collaborationExtensionTarball = join14(
17264
17749
  runtimeRoot,
17265
17750
  "kandan",
17266
17751
  "editor_extensions",
17267
17752
  "typefox.open-collaboration-tools.tar.gz"
17268
17753
  );
17269
- const collaborationServerTarball = join12(
17754
+ const collaborationServerTarball = join14(
17270
17755
  runtimeRoot,
17271
17756
  "kandan",
17272
17757
  "editor_servers",
17273
17758
  "open-collaboration-server.tar.gz"
17274
17759
  );
17275
- const documentStateExtensionDir = join12(
17760
+ const documentStateExtensionDir = join14(
17276
17761
  runtimeRoot,
17277
17762
  "kandan",
17278
17763
  "editor_extensions",
@@ -17281,7 +17766,7 @@ function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17281
17766
  const codeServerRoot = codeServerRuntimeRoot(manifest.codeServerBinPath);
17282
17767
  const requiredPaths = [
17283
17768
  manifest.codeServerBinPath,
17284
- join12(
17769
+ join14(
17285
17770
  codeServerRoot,
17286
17771
  "lib",
17287
17772
  "vscode",
@@ -17291,7 +17776,7 @@ function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17291
17776
  "web",
17292
17777
  "vsda.js"
17293
17778
  ),
17294
- join12(
17779
+ join14(
17295
17780
  codeServerRoot,
17296
17781
  "lib",
17297
17782
  "vscode",
@@ -17312,7 +17797,7 @@ function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17312
17797
  if (expectedSha256 === void 0 && relativePath !== manifest.codeServerBinPath) {
17313
17798
  return void 0;
17314
17799
  }
17315
- const absolutePath = join12(runtimeRoot, relativePath);
17800
+ const absolutePath = join14(runtimeRoot, relativePath);
17316
17801
  if (!existsSync9(absolutePath)) {
17317
17802
  return void 0;
17318
17803
  }
@@ -17341,10 +17826,10 @@ function manifestAssetChecksums(assets) {
17341
17826
  return checksums;
17342
17827
  }
17343
17828
  function fileSha256Sync(path2) {
17344
- return createHash4("sha256").update(readFileSync10(path2)).digest("hex");
17829
+ return createHash4("sha256").update(readFileSync11(path2)).digest("hex");
17345
17830
  }
17346
17831
  function defaultEditorRuntimeCacheRoot() {
17347
- return join12(homedir10(), ".linzumi", "editor-runtimes");
17832
+ return join14(homedir11(), ".linzumi", "editor-runtimes");
17348
17833
  }
17349
17834
  function nonEmptyString(value) {
17350
17835
  return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
@@ -17364,7 +17849,7 @@ var init_localEditorRuntime = __esm({
17364
17849
 
17365
17850
  // src/dependencyStatus.ts
17366
17851
  import { spawn as spawn6, spawnSync as spawnSync4 } from "node:child_process";
17367
- 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";
17368
17853
  function probeTool(command, cwd) {
17369
17854
  return new Promise((resolve12) => {
17370
17855
  const args = ["--version"];
@@ -17521,8 +18006,8 @@ function voltaCommandCandidates(args) {
17521
18006
  new Set(
17522
18007
  [
17523
18008
  voltaBinBesideCodexShim(args.codexBin),
17524
- env.VOLTA_HOME === void 0 ? void 0 : join13(env.VOLTA_HOME, "bin", "volta"),
17525
- 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"),
17526
18011
  ...pathVoltaCandidates(env.PATH)
17527
18012
  ].filter((candidate) => candidate !== void 0)
17528
18013
  )
@@ -17530,10 +18015,10 @@ function voltaCommandCandidates(args) {
17530
18015
  }
17531
18016
  function voltaBinBesideCodexShim(codexBin) {
17532
18017
  const normalizedCodexBin = codexBin.replaceAll("\\", "/");
17533
- 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;
17534
18019
  }
17535
18020
  function pathVoltaCandidates(pathValue) {
17536
- 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"));
17537
18022
  }
17538
18023
  function codeServerDependencyStatus(args) {
17539
18024
  switch (args.editorRuntime?.status) {
@@ -17642,7 +18127,7 @@ var linzumiCliVersion, linzumiCliVersionText;
17642
18127
  var init_version = __esm({
17643
18128
  "src/version.ts"() {
17644
18129
  "use strict";
17645
- linzumiCliVersion = "0.0.82-beta";
18130
+ linzumiCliVersion = "0.0.84-beta";
17646
18131
  linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
17647
18132
  }
17648
18133
  });
@@ -17651,19 +18136,21 @@ var init_version = __esm({
17651
18136
  import {
17652
18137
  closeSync as closeSync2,
17653
18138
  existsSync as existsSync10,
17654
- mkdirSync as mkdirSync8,
18139
+ mkdirSync as mkdirSync9,
17655
18140
  openSync as openSync3,
17656
- readFileSync as readFileSync11,
18141
+ readFileSync as readFileSync12,
18142
+ renameSync as renameSync2,
17657
18143
  unlinkSync as unlinkSync2,
18144
+ writeFileSync as writeFileSync7,
17658
18145
  writeSync
17659
18146
  } from "node:fs";
17660
- import { dirname as dirname9, join as join14 } from "node:path";
18147
+ import { dirname as dirname9, join as join16 } from "node:path";
17661
18148
  function isRunnerLockHeldError(error) {
17662
18149
  return error instanceof RunnerLockHeldError || error instanceof Error && error.name === runnerLockHeldErrorName && "lockPath" in error && "heldBy" in error;
17663
18150
  }
17664
18151
  function runnerLockPath(machineId, configPath = localConfigPath(), linzumiUrl) {
17665
18152
  const lockName = linzumiUrl === void 0 ? encodeURIComponent(machineId) : localConfigScopeFileStem(linzumiUrl);
17666
- return join14(dirname9(configPath), "runners", `${lockName}.lock`);
18153
+ return join16(dirname9(configPath), "runners", `${lockName}.lock`);
17667
18154
  }
17668
18155
  function acquireRunnerLock(options) {
17669
18156
  const path2 = runnerLockPath(
@@ -17672,6 +18159,9 @@ function acquireRunnerLock(options) {
17672
18159
  options.linzumiUrl
17673
18160
  );
17674
18161
  const isPidAlive = options.isPidAlive ?? processIsAlive;
18162
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
18163
+ const killPid = options.killPid ?? sigkillProcess;
18164
+ const startedAt = now().toISOString();
17675
18165
  const record = {
17676
18166
  version: 1,
17677
18167
  machineId: options.machineId,
@@ -17681,29 +18171,95 @@ function acquireRunnerLock(options) {
17681
18171
  workspace: options.workspace,
17682
18172
  ...options.linzumiUrl === void 0 ? {} : { linzumiUrl: kandanHttpBaseUrl(options.linzumiUrl) },
17683
18173
  ...options.launchSource === void 0 ? {} : { launchSource: options.launchSource },
17684
- startedAt: (options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString(),
18174
+ startedAt,
18175
+ heartbeatAt: startedAt,
17685
18176
  cliVersion: options.cliVersion ?? linzumiCliVersion
17686
18177
  };
17687
18178
  rejectLiveLegacyProductionRunnerLock(
17688
18179
  options.machineId,
17689
18180
  options.configPath,
17690
18181
  options.linzumiUrl,
17691
- isPidAlive
18182
+ isPidAlive,
18183
+ now,
18184
+ killPid,
18185
+ options.onTakeover
17692
18186
  );
17693
18187
  writeLockOrHandleExisting(
17694
18188
  path2,
17695
18189
  record,
17696
18190
  isPidAlive,
18191
+ now,
18192
+ killPid,
18193
+ options.onTakeover,
17697
18194
  options.beforeReadExistingLock,
17698
18195
  options.beforeReplaceStaleLock
17699
18196
  );
18197
+ const heartbeat = () => stampRunnerLockHeartbeat(path2, record, now);
18198
+ const heartbeatTimer = setInterval(heartbeat, runnerLockHeartbeatIntervalMs);
18199
+ heartbeatTimer.unref();
17700
18200
  return {
17701
18201
  path: path2,
17702
18202
  record,
17703
- release: () => releaseRunnerLock(path2, record)
18203
+ heartbeat,
18204
+ release: () => {
18205
+ clearInterval(heartbeatTimer);
18206
+ releaseRunnerLock(path2, record);
18207
+ }
17704
18208
  };
17705
18209
  }
17706
- function rejectLiveLegacyProductionRunnerLock(machineId, configPath, linzumiUrl, isPidAlive) {
18210
+ function stampRunnerLockHeartbeat(path2, record, now) {
18211
+ try {
18212
+ const current = readRunnerLockIfPresent(path2);
18213
+ if (current === void 0 || current.machineId !== record.machineId || current.runnerId !== record.runnerId || current.pid !== record.pid || current.startedAt !== record.startedAt) {
18214
+ return;
18215
+ }
18216
+ const next = {
18217
+ ...current,
18218
+ heartbeatAt: now().toISOString()
18219
+ };
18220
+ const tmpPath = `${path2}.tmp`;
18221
+ writeFileSync7(tmpPath, `${JSON.stringify(next, null, 2)}
18222
+ `, "utf8");
18223
+ renameSync2(tmpPath, path2);
18224
+ } catch (_error) {
18225
+ }
18226
+ }
18227
+ function assessRunnerLockHolder(record, isPidAlive, now) {
18228
+ if (!isPidAlive(record.pid)) {
18229
+ return { state: "dead" };
18230
+ }
18231
+ const reference = record.heartbeatAt ?? record.startedAt;
18232
+ const referenceMs = Date.parse(reference);
18233
+ if (Number.isNaN(referenceMs) || now().getTime() - referenceMs > runnerLockTakeoverAfterMs) {
18234
+ return {
18235
+ state: "wedged",
18236
+ reason: record.heartbeatAt === void 0 ? "missing_heartbeat" : "stale_heartbeat"
18237
+ };
18238
+ }
18239
+ return { state: "live" };
18240
+ }
18241
+ function takeOverWedgedHolder(lockPath, holder, reason, killPid, onTakeover) {
18242
+ try {
18243
+ killPid(holder.pid);
18244
+ } catch (error) {
18245
+ const code = error !== null && typeof error === "object" && "code" in error ? error.code : void 0;
18246
+ if (code === "ESRCH") {
18247
+ } else if (code === "EPERM" || code === "EACCES") {
18248
+ throw new Error(
18249
+ `Cannot take over the runner lock at ${lockPath}: its holder process (pid ${holder.pid}) is owned by another user and cannot be stopped. Stop that process, or remove the lock file, then retry.`
18250
+ );
18251
+ } else {
18252
+ throw error;
18253
+ }
18254
+ }
18255
+ onTakeover?.({
18256
+ lockPath,
18257
+ holderPid: holder.pid,
18258
+ holderRunnerId: holder.runnerId,
18259
+ reason
18260
+ });
18261
+ }
18262
+ function rejectLiveLegacyProductionRunnerLock(machineId, configPath, linzumiUrl, isPidAlive, now, killPid, onTakeover) {
17707
18263
  if (linzumiUrl === void 0 || localConfigScopeKey(linzumiUrl) !== localConfigScopeKey(defaultLinzumiHttpUrl)) {
17708
18264
  return;
17709
18265
  }
@@ -17712,20 +18268,31 @@ function rejectLiveLegacyProductionRunnerLock(machineId, configPath, linzumiUrl,
17712
18268
  if (existing === void 0) {
17713
18269
  return;
17714
18270
  }
17715
- if (isPidAlive(existing.pid)) {
18271
+ if (assessRunnerLockHolder(existing, isPidAlive, now).state === "live") {
17716
18272
  throw new RunnerLockHeldError(legacyPath, existing);
17717
18273
  }
17718
18274
  withStaleReplacementLock(legacyPath, isPidAlive, () => {
17719
18275
  const latest = existsSync10(legacyPath) ? readRunnerLock(legacyPath) : void 0;
17720
- if (latest !== void 0 && isPidAlive(latest.pid)) {
18276
+ if (latest === void 0) {
18277
+ return;
18278
+ }
18279
+ const holder = assessRunnerLockHolder(latest, isPidAlive, now);
18280
+ if (holder.state === "live") {
17721
18281
  throw new RunnerLockHeldError(legacyPath, latest);
17722
18282
  }
17723
- if (latest !== void 0) {
17724
- unlinkSync2(legacyPath);
18283
+ if (holder.state === "wedged") {
18284
+ takeOverWedgedHolder(
18285
+ legacyPath,
18286
+ latest,
18287
+ holder.reason,
18288
+ killPid,
18289
+ onTakeover
18290
+ );
17725
18291
  }
18292
+ unlinkSync2(legacyPath);
17726
18293
  });
17727
18294
  }
17728
- function writeLockOrHandleExisting(path2, record, isPidAlive, beforeReadExistingLock, beforeReplaceStaleLock) {
18295
+ function writeLockOrHandleExisting(path2, record, isPidAlive, now, killPid, onTakeover, beforeReadExistingLock, beforeReplaceStaleLock) {
17729
18296
  if (tryCreateLock(path2, record)) {
17730
18297
  return;
17731
18298
  }
@@ -17739,16 +18306,20 @@ function writeLockOrHandleExisting(path2, record, isPidAlive, beforeReadExisting
17739
18306
  `another Linzumi runner lock appeared while starting: ${path2}`
17740
18307
  );
17741
18308
  }
17742
- if (isPidAlive(existing.pid)) {
18309
+ if (assessRunnerLockHolder(existing, isPidAlive, now).state === "live") {
17743
18310
  throw new RunnerLockHeldError(path2, existing);
17744
18311
  }
17745
18312
  beforeReplaceStaleLock?.();
17746
18313
  withStaleReplacementLock(path2, isPidAlive, () => {
17747
18314
  const latest = existsSync10(path2) ? readRunnerLock(path2) : void 0;
17748
- if (latest !== void 0 && isPidAlive(latest.pid)) {
17749
- throw new RunnerLockHeldError(path2, latest);
17750
- }
17751
18315
  if (latest !== void 0) {
18316
+ const holder = assessRunnerLockHolder(latest, isPidAlive, now);
18317
+ if (holder.state === "live") {
18318
+ throw new RunnerLockHeldError(path2, latest);
18319
+ }
18320
+ if (holder.state === "wedged") {
18321
+ takeOverWedgedHolder(path2, latest, holder.reason, killPid, onTakeover);
18322
+ }
17752
18323
  unlinkSync2(path2);
17753
18324
  }
17754
18325
  if (!tryCreateLock(path2, record)) {
@@ -17759,7 +18330,7 @@ function writeLockOrHandleExisting(path2, record, isPidAlive, beforeReadExisting
17759
18330
  });
17760
18331
  }
17761
18332
  function tryCreateLock(path2, record) {
17762
- mkdirSync8(dirname9(path2), { recursive: true });
18333
+ mkdirSync9(dirname9(path2), { recursive: true });
17763
18334
  try {
17764
18335
  const fd = openSync3(path2, "wx");
17765
18336
  try {
@@ -17815,7 +18386,7 @@ function withStaleReplacementLock(path2, isPidAlive, callback) {
17815
18386
  function readReplacementLockPidIfPresent(path2) {
17816
18387
  let value;
17817
18388
  try {
17818
- value = readFileSync11(path2, "utf8").trim();
18389
+ value = readFileSync12(path2, "utf8").trim();
17819
18390
  } catch (error) {
17820
18391
  if (isNodeErrorCode2(error, "ENOENT")) {
17821
18392
  return void 0;
@@ -17855,14 +18426,19 @@ function readRunnerLockIfPresent(path2) {
17855
18426
  }
17856
18427
  }
17857
18428
  function readRunnerLock(path2) {
17858
- const parsed = JSON.parse(readFileSync11(path2, "utf8"));
18429
+ const parsed = JSON.parse(readFileSync12(path2, "utf8"));
17859
18430
  if (!isRunnerLockRecord(parsed)) {
17860
18431
  throw new Error(`invalid Linzumi runner lock: ${path2}`);
17861
18432
  }
17862
18433
  return parsed;
17863
18434
  }
17864
18435
  function isRunnerLockRecord(value) {
17865
- return typeof value === "object" && value !== null && value.version === 1 && typeof value.machineId === "string" && value.machineId.trim() !== "" && typeof value.runnerId === "string" && value.runnerId.trim() !== "" && Number.isInteger(value.pid) && value.pid > 0 && typeof value.cwd === "string" && value.cwd.trim() !== "" && workspaceValid(value.workspace) && linzumiUrlValid(value.linzumiUrl) && typeof value.startedAt === "string" && value.startedAt.trim() !== "" && typeof value.cliVersion === "string" && value.cliVersion.trim() !== "";
18436
+ return typeof value === "object" && value !== null && value.version === 1 && typeof value.machineId === "string" && value.machineId.trim() !== "" && typeof value.runnerId === "string" && value.runnerId.trim() !== "" && Number.isInteger(value.pid) && value.pid > 0 && typeof value.cwd === "string" && value.cwd.trim() !== "" && workspaceValid(value.workspace) && linzumiUrlValid(value.linzumiUrl) && typeof value.startedAt === "string" && value.startedAt.trim() !== "" && heartbeatAtValid(
18437
+ value.heartbeatAt
18438
+ ) && typeof value.cliVersion === "string" && value.cliVersion.trim() !== "";
18439
+ }
18440
+ function heartbeatAtValid(value) {
18441
+ return value === void 0 || typeof value === "string" && value.trim() !== "";
17866
18442
  }
17867
18443
  function linzumiUrlValid(value) {
17868
18444
  return value === void 0 || typeof value === "string" && value.trim() !== "";
@@ -17878,6 +18454,15 @@ function processIsAlive(pid) {
17878
18454
  return isNodeErrorCode2(error, "ESRCH") ? false : true;
17879
18455
  }
17880
18456
  }
18457
+ function sigkillProcess(pid) {
18458
+ try {
18459
+ process.kill(pid, "SIGKILL");
18460
+ } catch (error) {
18461
+ if (!isNodeErrorCode2(error, "ESRCH")) {
18462
+ throw error;
18463
+ }
18464
+ }
18465
+ }
17881
18466
  function activeRunnerLockMessage(path2, record) {
17882
18467
  const workspace = record.workspace === null ? "workspace: unknown" : `workspace: ${record.workspace}`;
17883
18468
  const linzumiUrl = record.linzumiUrl === void 0 ? void 0 : `linzumi url: ${displayLinzumiUrl(record.linzumiUrl)}`;
@@ -17901,7 +18486,11 @@ function activeRunnerLockMessage(path2, record) {
17901
18486
  `CLI version: ${record.cliVersion}`,
17902
18487
  `started at: ${record.startedAt}`,
17903
18488
  `lock: ${path2}`,
17904
- "Stop that process first, then retry. If the process has already exited, remove the stale lock file and retry."
18489
+ "Stop that process first, then retry. If the process has already exited, remove the stale lock file and retry.",
18490
+ // Wedged-runner escape hatch: the holder above had a FRESH heartbeat, so
18491
+ // it really is running. A holder that stops heartbeating (wedged event
18492
+ // loop) is taken over automatically after 3 minutes - no kill -9 needed.
18493
+ "A runner whose lock heartbeat goes stale (no update for 3 minutes) is taken over automatically on the next connect."
17905
18494
  ].join("\n");
17906
18495
  }
17907
18496
  function displayLinzumiUrl(linzumiUrl) {
@@ -17913,7 +18502,7 @@ function displayLinzumiUrl(linzumiUrl) {
17913
18502
  function isNodeErrorCode2(error, code) {
17914
18503
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
17915
18504
  }
17916
- var runnerLockHeldErrorName, RunnerLockHeldError;
18505
+ var runnerLockHeartbeatIntervalMs, runnerLockTakeoverAfterMs, runnerLockHeldErrorName, RunnerLockHeldError;
17917
18506
  var init_runnerLock = __esm({
17918
18507
  "src/runnerLock.ts"() {
17919
18508
  "use strict";
@@ -17921,6 +18510,8 @@ var init_runnerLock = __esm({
17921
18510
  init_oauth();
17922
18511
  init_defaultUrls();
17923
18512
  init_version();
18513
+ runnerLockHeartbeatIntervalMs = 3e4;
18514
+ runnerLockTakeoverAfterMs = 3 * 6e4;
17924
18515
  runnerLockHeldErrorName = "RunnerLockHeldError";
17925
18516
  RunnerLockHeldError = class extends Error {
17926
18517
  lockPath;
@@ -17974,9 +18565,9 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
17974
18565
  const previousJobKey = latestDashboardJob(state)?.key;
17975
18566
  switch (event) {
17976
18567
  case "onboarding.discovery_agents_started":
17977
- state.browserUrl = stringValue4(payload.kandanUrl);
17978
- state.workspace = stringValue4(payload.workspace);
17979
- state.runnerId = stringValue4(payload.runnerId);
18568
+ state.browserUrl = stringValue5(payload.kandanUrl);
18569
+ state.workspace = stringValue5(payload.workspace);
18570
+ state.runnerId = stringValue5(payload.runnerId);
17980
18571
  break;
17981
18572
  // Half-open-socket signal (PR #1677 follow-up item 2 slice): the runner
17982
18573
  // logs these exactly once per stale/recovered transition.
@@ -17987,10 +18578,10 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
17987
18578
  state.connectionStale = false;
17988
18579
  break;
17989
18580
  case "onboarding.discovery_status": {
17990
- const phase = stringValue4(payload.phase);
17991
- const status = stringValue4(payload.status);
17992
- const metadata = objectValue5(payload.metadata);
17993
- const workerId = stringValue4(metadata?.worker_id);
18581
+ const phase = stringValue5(payload.phase);
18582
+ const status = stringValue5(payload.status);
18583
+ const metadata = objectValue6(payload.metadata);
18584
+ const workerId = stringValue5(metadata?.worker_id);
17994
18585
  if (phase !== void 0 && status !== void 0) {
17995
18586
  const isConversationPhase = phase === "conversations";
17996
18587
  const key = isConversationPhase ? phase : workerId ?? phase;
@@ -18004,10 +18595,10 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18004
18595
  previous?.placesSearched ?? 0,
18005
18596
  numberValue(payload.places_searched) ?? 0
18006
18597
  ),
18007
- message: stringValue4(payload.message) ?? (isConversationPhase ? previous?.message : void 0),
18008
- currentPlace: stringValue4(payload.current_place) ?? (isConversationPhase ? previous?.currentPlace : void 0),
18009
- currentSource: stringValue4(payload.current_source) ?? (isConversationPhase ? previous?.currentSource : void 0),
18010
- lastError: stringValue4(payload.last_error),
18598
+ message: stringValue5(payload.message) ?? (isConversationPhase ? previous?.message : void 0),
18599
+ currentPlace: stringValue5(payload.current_place) ?? (isConversationPhase ? previous?.currentPlace : void 0),
18600
+ currentSource: stringValue5(payload.current_source) ?? (isConversationPhase ? previous?.currentSource : void 0),
18601
+ lastError: stringValue5(payload.last_error),
18011
18602
  metadata: mergedMetadata,
18012
18603
  updatedAtMs: nowMs
18013
18604
  });
@@ -18017,10 +18608,10 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18017
18608
  case "kandan.message_queued":
18018
18609
  case "codex.turn_starting": {
18019
18610
  const job = dashboardJobForPayload(state, payload, nowMs);
18020
- job.linzumiThreadId = stringValue4(payload.linzumi_thread_id) ?? job.linzumiThreadId;
18611
+ job.linzumiThreadId = stringValue5(payload.linzumi_thread_id) ?? job.linzumiThreadId;
18021
18612
  job.linzumiThreadTitle = dashboardLinzumiThreadTitle(payload) ?? job.linzumiThreadTitle;
18022
- job.codexThreadId = stringValue4(payload.codex_thread_id) ?? job.codexThreadId;
18023
- job.lastIncomingPreview = stringValue4(payload.body_preview) ?? job.lastIncomingPreview;
18613
+ job.codexThreadId = stringValue5(payload.codex_thread_id) ?? job.codexThreadId;
18614
+ job.lastIncomingPreview = stringValue5(payload.body_preview) ?? job.lastIncomingPreview;
18024
18615
  job.lastIncomingAtMs = numberValue(payload.message_received_at_ms) ?? job.lastIncomingAtMs;
18025
18616
  job.queueDepth = numberValue(payload.queue_depth) ?? job.queueDepth;
18026
18617
  job.eventType = dashboardEventLabel(event);
@@ -18028,9 +18619,9 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18028
18619
  break;
18029
18620
  }
18030
18621
  case "codex.notification": {
18031
- const tokenUsage = stringValue4(payload.token_usage_summary);
18032
- const rateLimit = stringValue4(payload.rate_limit_summary);
18033
- const creditExhaustion = stringValue4(payload.credit_exhaustion_summary);
18622
+ const tokenUsage = stringValue5(payload.token_usage_summary);
18623
+ const rateLimit = stringValue5(payload.rate_limit_summary);
18624
+ const creditExhaustion = stringValue5(payload.credit_exhaustion_summary);
18034
18625
  if (tokenUsage !== void 0) {
18035
18626
  state.tokenUsage = tokenUsage;
18036
18627
  }
@@ -18040,13 +18631,13 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18040
18631
  if (creditExhaustion !== void 0) {
18041
18632
  state.creditExhaustion = creditExhaustion;
18042
18633
  }
18043
- const method = stringValue4(payload.method);
18044
- const metadata = objectValue5(payload.metadata);
18045
- const metadataHasJobSignal = stringValue4(metadata?.threadId) !== void 0 || stringValue4(metadata?.turnId) !== void 0 || stringValue4(metadata?.itemId) !== void 0;
18634
+ const method = stringValue5(payload.method);
18635
+ const metadata = objectValue6(payload.metadata);
18636
+ const metadataHasJobSignal = stringValue5(metadata?.threadId) !== void 0 || stringValue5(metadata?.turnId) !== void 0 || stringValue5(metadata?.itemId) !== void 0;
18046
18637
  if (!metadataHasJobSignal) {
18047
18638
  break;
18048
18639
  }
18049
- const codexThreadId = stringValue4(metadata?.threadId);
18640
+ const codexThreadId = stringValue5(metadata?.threadId);
18050
18641
  const job = codexThreadId === void 0 ? latestDashboardJob(state) : dashboardJobForKey(state, `codex:${codexThreadId}`, nowMs);
18051
18642
  if (job !== void 0) {
18052
18643
  job.codexThreadId = codexThreadId ?? job.codexThreadId;
@@ -18054,7 +18645,7 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18054
18645
  job.creditExhaustion = creditExhaustion ?? job.creditExhaustion;
18055
18646
  job.latestCodexEventId = codexEventId(payload);
18056
18647
  job.eventType = payload.credit_exhaustion_detected === true ? "credit_exhausted" : method ?? event;
18057
- job.turnId = stringValue4(metadata?.turnId) ?? job.turnId;
18648
+ job.turnId = stringValue5(metadata?.turnId) ?? job.turnId;
18058
18649
  job.updatedAtMs = nowMs;
18059
18650
  }
18060
18651
  break;
@@ -18066,11 +18657,11 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18066
18657
  case "kandan.codex_file_change_forwarded":
18067
18658
  case "kandan.codex_web_search_progress_forwarded": {
18068
18659
  const job = dashboardJobForPayload(state, payload, nowMs);
18069
- job.latestCodexEventId = stringValue4(payload.item_key) ?? job.latestCodexEventId;
18660
+ job.latestCodexEventId = stringValue5(payload.item_key) ?? job.latestCodexEventId;
18070
18661
  job.eventType = codexOutputDashboardLabel(event, payload);
18071
- job.turnId = stringValue4(payload.turn_id) ?? job.turnId;
18072
- if (stringValue4(payload.structured_kind) === "codex_assistant_message") {
18073
- job.lastAssistantPreview = stringValue4(payload.body_preview) ?? job.lastAssistantPreview;
18662
+ job.turnId = stringValue5(payload.turn_id) ?? job.turnId;
18663
+ if (stringValue5(payload.structured_kind) === "codex_assistant_message") {
18664
+ job.lastAssistantPreview = stringValue5(payload.body_preview) ?? job.lastAssistantPreview;
18074
18665
  job.lastAssistantAtMs = nowMs;
18075
18666
  }
18076
18667
  job.updatedAtMs = nowMs;
@@ -18085,7 +18676,7 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18085
18676
  case "claude_code.turn_starting":
18086
18677
  case "claude_code.message_queued": {
18087
18678
  const job = claudeDashboardJob(state, payload, nowMs);
18088
- job.lastIncomingPreview = stringValue4(payload.body_preview) ?? job.lastIncomingPreview;
18679
+ job.lastIncomingPreview = stringValue5(payload.body_preview) ?? job.lastIncomingPreview;
18089
18680
  job.lastIncomingAtMs = numberValue(payload.message_received_at_ms) ?? job.lastIncomingAtMs;
18090
18681
  job.eventType = event === "claude_code.message_queued" ? "message_queued" : "turn_starting";
18091
18682
  job.updatedAtMs = nowMs;
@@ -18099,7 +18690,7 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18099
18690
  }
18100
18691
  case "claude_code.turn_completed": {
18101
18692
  const job = claudeDashboardJob(state, payload, nowMs);
18102
- job.lastAssistantPreview = stringValue4(payload.body_preview) ?? job.lastAssistantPreview;
18693
+ job.lastAssistantPreview = stringValue5(payload.body_preview) ?? job.lastAssistantPreview;
18103
18694
  job.lastAssistantAtMs = nowMs;
18104
18695
  job.eventType = "turn_completed";
18105
18696
  job.updatedAtMs = nowMs;
@@ -18107,13 +18698,13 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18107
18698
  }
18108
18699
  case "claude_code.turn_terminal": {
18109
18700
  const job = claudeDashboardJob(state, payload, nowMs);
18110
- job.turnId = stringValue4(payload.turn_id) ?? job.turnId;
18111
- job.eventType = `turn_${stringValue4(payload.outcome) ?? "terminal"}`;
18701
+ job.turnId = stringValue5(payload.turn_id) ?? job.turnId;
18702
+ job.eventType = `turn_${stringValue5(payload.outcome) ?? "terminal"}`;
18112
18703
  job.updatedAtMs = nowMs;
18113
18704
  break;
18114
18705
  }
18115
18706
  case "claude_code.rate_limit": {
18116
- const rateLimit = stringValue4(payload.rate_limit_summary);
18707
+ const rateLimit = stringValue5(payload.rate_limit_summary);
18117
18708
  if (rateLimit !== void 0) {
18118
18709
  state.rateLimit = mergeRateLimitSummary(state.rateLimit, rateLimit);
18119
18710
  }
@@ -18122,6 +18713,19 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18122
18713
  job.updatedAtMs = nowMs;
18123
18714
  break;
18124
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
+ }
18125
18729
  default:
18126
18730
  break;
18127
18731
  }
@@ -18279,7 +18883,7 @@ function conversationImportProgressText(status) {
18279
18883
  )}] ${reportedCount} / ${totalCount} Codex/Claude Code conversations`;
18280
18884
  }
18281
18885
  function conversationImportMetadata(metadata) {
18282
- return stringValue4(metadata?.worker_id) === "conversations-local-import" || numberValue(metadata?.imported_count) !== void 0 || numberValue(metadata?.failed_import_count) !== void 0 || numberValue(metadata?.total_count) !== void 0;
18886
+ return stringValue5(metadata?.worker_id) === "conversations-local-import" || numberValue(metadata?.imported_count) !== void 0 || numberValue(metadata?.failed_import_count) !== void 0 || numberValue(metadata?.total_count) !== void 0;
18283
18887
  }
18284
18888
  function conversationImportProgressBar(reportedCount, totalCount) {
18285
18889
  const width = 10;
@@ -18538,12 +19142,12 @@ function formatRunnerConsoleEvent(event, payload) {
18538
19142
  case "codex.turn_started":
18539
19143
  return `Codex turn started: id=${text(payload.turn_id)}`;
18540
19144
  case "codex.notification": {
18541
- const creditExhaustion = stringValue4(payload.credit_exhaustion_summary);
19145
+ const creditExhaustion = stringValue5(payload.credit_exhaustion_summary);
18542
19146
  const summary = [
18543
19147
  creditExhaustion === void 0 ? void 0 : `URGENT ${creditExhaustion}`,
18544
- stringValue4(payload.token_usage_summary),
18545
- stringValue4(payload.rate_limit_summary),
18546
- stringValue4(payload.diagnostic_summary)
19148
+ stringValue5(payload.token_usage_summary),
19149
+ stringValue5(payload.rate_limit_summary),
19150
+ stringValue5(payload.diagnostic_summary)
18547
19151
  ].filter((value) => value !== void 0).join(" | ");
18548
19152
  const suffix = summary === "" ? "" : ` ${summary}`;
18549
19153
  return `Codex event [id=${codexEventId(payload)}]: ${text(payload.method)}${suffix}`;
@@ -18581,7 +19185,9 @@ function formatRunnerConsoleEvent(event, payload) {
18581
19185
  case "claude_code.turn_terminal":
18582
19186
  return `Claude Code turn ${text(payload.outcome)}: id=${text(payload.turn_id)}`;
18583
19187
  case "claude_code.rate_limit":
18584
- return `Claude Code rate limit: ${stringValue4(payload.rate_limit_summary) ?? "seen (no details)"}`;
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)"}`;
18585
19191
  default:
18586
19192
  return void 0;
18587
19193
  }
@@ -18605,12 +19211,12 @@ function secondsLabel(value) {
18605
19211
  return ms === void 0 ? "?" : `${(ms / 1e3).toFixed(1)}s`;
18606
19212
  }
18607
19213
  function onboardingDiscoveryStatusLine(payload) {
18608
- const phase = discoveryPhaseLabel(stringValue4(payload.phase) ?? "discovery");
18609
- const status = discoveryStatusLabel(stringValue4(payload.status) ?? "unknown");
19214
+ const phase = discoveryPhaseLabel(stringValue5(payload.phase) ?? "discovery");
19215
+ const status = discoveryStatusLabel(stringValue5(payload.status) ?? "unknown");
18610
19216
  const placesSearched = numberValue(payload.places_searched) ?? 0;
18611
- const currentPlace = stringValue4(payload.current_place);
18612
- const message = stringValue4(payload.message);
18613
- const detail = stringValue4(payload.last_error) ?? currentPlace ?? message ?? "Checking local context";
19217
+ const currentPlace = stringValue5(payload.current_place);
19218
+ const message = stringValue5(payload.message);
19219
+ const detail = stringValue5(payload.last_error) ?? currentPlace ?? message ?? "Checking local context";
18614
19220
  return `Onboarding discovery: ${phase} ${status} checked=${placesSearched} current=${detail}`;
18615
19221
  }
18616
19222
  function onboardingDiscoveryInitialSearchCompletedLine(payload) {
@@ -18630,11 +19236,11 @@ function connectedRunnerMessage(payload) {
18630
19236
  ].filter((line) => line !== void 0).join("\n");
18631
19237
  }
18632
19238
  function optionalLine(label, value) {
18633
- const normalized = stringValue4(value) ?? numberValue(value)?.toString();
19239
+ const normalized = stringValue5(value) ?? numberValue(value)?.toString();
18634
19240
  return normalized === void 0 ? void 0 : `${label}: ${normalized}`;
18635
19241
  }
18636
19242
  function optionalField(label, value) {
18637
- const normalized = stringValue4(value) ?? numberValue(value)?.toString();
19243
+ const normalized = stringValue5(value) ?? numberValue(value)?.toString();
18638
19244
  return normalized === void 0 ? void 0 : `${label}=${normalized}`;
18639
19245
  }
18640
19246
  function ignoredMessage(payload) {
@@ -18658,17 +19264,17 @@ function replacementLines(value) {
18658
19264
  return [];
18659
19265
  }
18660
19266
  const record = entry;
18661
- const runnerId = stringValue4(record.runnerId);
19267
+ const runnerId = stringValue5(record.runnerId);
18662
19268
  if (runnerId === void 0) {
18663
19269
  return [];
18664
19270
  }
18665
- const version = stringValue4(record.version);
19271
+ const version = stringValue5(record.version);
18666
19272
  const suffix = version === void 0 ? "" : ` (CLI ${version})`;
18667
19273
  return [`Replaced older runner from this machine: ${runnerId}${suffix}`];
18668
19274
  });
18669
19275
  }
18670
19276
  function sender(payload) {
18671
- const slug = stringValue4(payload.actor_slug);
19277
+ const slug = stringValue5(payload.actor_slug);
18672
19278
  const userId = numberValue(payload.actor_user_id);
18673
19279
  if (slug !== void 0 && userId !== void 0) {
18674
19280
  return `${slug}#${userId}`;
@@ -18676,7 +19282,7 @@ function sender(payload) {
18676
19282
  return slug ?? (userId === void 0 ? "unknown" : `user#${userId}`);
18677
19283
  }
18678
19284
  function codexOutputLabel(payload) {
18679
- const kind = stringValue4(payload.structured_kind) ?? "output";
19285
+ const kind = stringValue5(payload.structured_kind) ?? "output";
18680
19286
  switch (kind) {
18681
19287
  case "codex_assistant_message":
18682
19288
  return "assistant_message";
@@ -18702,7 +19308,7 @@ function codexEventId(payload) {
18702
19308
  const metadata = payload.metadata;
18703
19309
  if (typeof metadata === "object" && metadata !== null && !Array.isArray(metadata)) {
18704
19310
  const record = metadata;
18705
- return stringValue4(record.turnId) ?? stringValue4(record.itemId) ?? stringValue4(record.threadId) ?? "?";
19311
+ return stringValue5(record.turnId) ?? stringValue5(record.itemId) ?? stringValue5(record.threadId) ?? "?";
18706
19312
  }
18707
19313
  return "?";
18708
19314
  }
@@ -18718,8 +19324,8 @@ function rememberRawLine(state, event, payload, previousJobKey) {
18718
19324
  }
18719
19325
  }
18720
19326
  function dashboardRawLineJobKey(state, payload, previousJobKey) {
18721
- const linzumiThreadId = stringValue4(payload.linzumi_thread_id);
18722
- const codexThreadId = stringValue4(payload.codex_thread_id);
19327
+ const linzumiThreadId = stringValue5(payload.linzumi_thread_id);
19328
+ const codexThreadId = stringValue5(payload.codex_thread_id);
18723
19329
  if (linzumiThreadId !== void 0) {
18724
19330
  return `linzumi:${linzumiThreadId}`;
18725
19331
  }
@@ -18728,7 +19334,7 @@ function dashboardRawLineJobKey(state, payload, previousJobKey) {
18728
19334
  (job) => job.codexThreadId === codexThreadId
18729
19335
  )?.key;
18730
19336
  }
18731
- const claudeSessionId = stringValue4(payload.claude_session_id);
19337
+ const claudeSessionId = stringValue5(payload.claude_session_id);
18732
19338
  if (claudeSessionId !== void 0) {
18733
19339
  const claudeJobKey = Array.from(state.jobs.values()).find(
18734
19340
  (job) => job.codexThreadId === claudeSessionId
@@ -18737,8 +19343,8 @@ function dashboardRawLineJobKey(state, payload, previousJobKey) {
18737
19343
  return claudeJobKey;
18738
19344
  }
18739
19345
  }
18740
- const metadata = objectValue5(payload.metadata);
18741
- const metadataCodexThreadId = stringValue4(metadata?.threadId);
19346
+ const metadata = objectValue6(payload.metadata);
19347
+ const metadataCodexThreadId = stringValue5(metadata?.threadId);
18742
19348
  if (metadataCodexThreadId !== void 0) {
18743
19349
  return Array.from(state.jobs.values()).find(
18744
19350
  (job) => job.codexThreadId === metadataCodexThreadId
@@ -19197,13 +19803,13 @@ function updateRunnerConsoleDashboardMode(state, key) {
19197
19803
  }
19198
19804
  }
19199
19805
  function claudeDashboardJob(state, payload, nowMs) {
19200
- const claudeSessionId = stringValue4(payload.claude_session_id);
19806
+ const claudeSessionId = stringValue5(payload.claude_session_id);
19201
19807
  const job = dashboardJobForPayload(
19202
19808
  state,
19203
19809
  {
19204
19810
  ...payload,
19205
- linzumi_thread_id: stringValue4(payload.linzumi_thread_id) ?? stringValue4(payload.thread_id),
19206
- codex_thread_id: stringValue4(payload.codex_thread_id) ?? claudeSessionId
19811
+ linzumi_thread_id: stringValue5(payload.linzumi_thread_id) ?? stringValue5(payload.thread_id),
19812
+ codex_thread_id: stringValue5(payload.codex_thread_id) ?? claudeSessionId
19207
19813
  },
19208
19814
  nowMs
19209
19815
  );
@@ -19214,8 +19820,8 @@ function claudeDashboardJob(state, payload, nowMs) {
19214
19820
  return job;
19215
19821
  }
19216
19822
  function dashboardJobForPayload(state, payload, nowMs) {
19217
- const linzumiThreadId = stringValue4(payload.linzumi_thread_id);
19218
- const codexThreadId = stringValue4(payload.codex_thread_id);
19823
+ const linzumiThreadId = stringValue5(payload.linzumi_thread_id);
19824
+ const codexThreadId = stringValue5(payload.codex_thread_id);
19219
19825
  const existingByCodex = codexThreadId !== void 0 ? Array.from(state.jobs.values()).find(
19220
19826
  (job) => job.codexThreadId === codexThreadId
19221
19827
  ) : void 0;
@@ -19388,7 +19994,7 @@ function linzumiThreadLabel(job) {
19388
19994
  return firstN(job.linzumiThreadTitle, 30);
19389
19995
  }
19390
19996
  function dashboardLinzumiThreadTitle(payload) {
19391
- return stringValue4(payload.linzumi_thread_title) ?? stringValue4(payload.thread_title) ?? stringValue4(payload.threadTitle) ?? stringValue4(payload.title);
19997
+ return stringValue5(payload.linzumi_thread_title) ?? stringValue5(payload.thread_title) ?? stringValue5(payload.threadTitle) ?? stringValue5(payload.title);
19392
19998
  }
19393
19999
  function agentId(codexThreadId, provider) {
19394
20000
  if (codexThreadId === void 0) {
@@ -19432,13 +20038,13 @@ function timeAgo(valueMs, nowMs) {
19432
20038
  }
19433
20039
  return `${Math.floor(minutes / 60)}h`;
19434
20040
  }
19435
- function objectValue5(value) {
20041
+ function objectValue6(value) {
19436
20042
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
19437
20043
  }
19438
20044
  function text(value) {
19439
- return stringValue4(value) ?? numberValue(value)?.toString() ?? "?";
20045
+ return stringValue5(value) ?? numberValue(value)?.toString() ?? "?";
19440
20046
  }
19441
- function stringValue4(value) {
20047
+ function stringValue5(value) {
19442
20048
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
19443
20049
  }
19444
20050
  function numberValue(value) {
@@ -19525,8 +20131,8 @@ var init_runnerConsoleReporter = __esm({
19525
20131
  });
19526
20132
 
19527
20133
  // src/telemetry.ts
19528
- import { mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "node:fs";
19529
- import { dirname as dirname10, basename as basename7, join as join15 } from "node:path";
20134
+ import { mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
20135
+ import { dirname as dirname10, basename as basename7, join as join17 } from "node:path";
19530
20136
  import { randomUUID as randomUUID3 } from "node:crypto";
19531
20137
  function peekFlagValue(args, flags) {
19532
20138
  for (let index = 0; index < args.length; index += 1) {
@@ -19565,12 +20171,12 @@ function telemetryBaseUrl(apiUrl, env = process.env) {
19565
20171
  }
19566
20172
  }
19567
20173
  function telemetryInstallIdPath(env = process.env) {
19568
- return join15(dirname10(localConfigPath(env)), "install-id");
20174
+ return join17(dirname10(localConfigPath(env)), "install-id");
19569
20175
  }
19570
20176
  function ensureTelemetryInstallId(env = process.env) {
19571
20177
  const path2 = telemetryInstallIdPath(env);
19572
20178
  try {
19573
- const existing = readFileSync12(path2, "utf8").trim();
20179
+ const existing = readFileSync13(path2, "utf8").trim();
19574
20180
  if (existing !== "" && existing.length <= 128) {
19575
20181
  return existing;
19576
20182
  }
@@ -19578,8 +20184,8 @@ function ensureTelemetryInstallId(env = process.env) {
19578
20184
  }
19579
20185
  const installId = randomUUID3();
19580
20186
  try {
19581
- mkdirSync9(dirname10(path2), { recursive: true });
19582
- writeFileSync6(path2, `${installId}
20187
+ mkdirSync10(dirname10(path2), { recursive: true });
20188
+ writeFileSync8(path2, `${installId}
19583
20189
  `, { mode: 384 });
19584
20190
  } catch {
19585
20191
  }
@@ -19766,17 +20372,17 @@ var init_linzumiApiClient = __esm({
19766
20372
  });
19767
20373
 
19768
20374
  // src/authCache.ts
19769
- import { existsSync as existsSync11, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
19770
- import { homedir as homedir11 } from "node:os";
19771
- import { dirname as dirname11, join as join16 } from "node:path";
20375
+ import { existsSync as existsSync11, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "node:fs";
20376
+ import { homedir as homedir12 } from "node:os";
20377
+ import { dirname as dirname11, join as join18 } from "node:path";
19772
20378
  function defaultAuthFilePath() {
19773
- return join16(homedir11(), ".linzumi", "auth.json");
20379
+ return join18(homedir12(), ".linzumi", "auth.json");
19774
20380
  }
19775
20381
  function readCachedLocalRunnerToken(kandanUrl, authFilePath = defaultAuthFilePath()) {
19776
20382
  if (!existsSync11(authFilePath)) {
19777
20383
  return void 0;
19778
20384
  }
19779
- const authFile = parseAuthFile(readFileSync13(authFilePath, "utf8"));
20385
+ const authFile = parseAuthFile(readFileSync14(authFilePath, "utf8"));
19780
20386
  const kandanBaseUrl = kandanHttpBaseUrl(kandanUrl);
19781
20387
  const entry = authFile.local_codex_runner?.[kandanBaseUrl];
19782
20388
  if (entry === void 0 || entry.access_token.trim() === "") {
@@ -19798,7 +20404,7 @@ function readPersonalAgentDelegationToken(authFilePath) {
19798
20404
  `missing personal-agent delegation auth file: ${authFilePath}`
19799
20405
  );
19800
20406
  }
19801
- const authFile = parseAuthFile(readFileSync13(authFilePath, "utf8"));
20407
+ const authFile = parseAuthFile(readFileSync14(authFilePath, "utf8"));
19802
20408
  const entry = authFile.personal_agent_delegation;
19803
20409
  if (entry === void 0 || entry.access_token.trim() === "") {
19804
20410
  throw new Error(
@@ -19816,7 +20422,7 @@ function readPersonalAgentDelegationToken(authFilePath) {
19816
20422
  }
19817
20423
  function writeCachedLocalRunnerToken(args) {
19818
20424
  const authFilePath = args.authFilePath ?? defaultAuthFilePath();
19819
- const existing = existsSync11(authFilePath) ? parseAuthFile(readFileSync13(authFilePath, "utf8")) : { version: 1 };
20425
+ const existing = existsSync11(authFilePath) ? parseAuthFile(readFileSync14(authFilePath, "utf8")) : { version: 1 };
19820
20426
  const kandanBaseUrl = kandanHttpBaseUrl(args.kandanUrl);
19821
20427
  const issuedAt = /* @__PURE__ */ new Date();
19822
20428
  const expiresAt = args.expiresInSeconds === void 0 ? void 0 : new Date(
@@ -19834,8 +20440,8 @@ function writeCachedLocalRunnerToken(args) {
19834
20440
  }
19835
20441
  }
19836
20442
  };
19837
- mkdirSync10(dirname11(authFilePath), { recursive: true });
19838
- writeFileSync7(authFilePath, `${JSON.stringify(next, null, 2)}
20443
+ mkdirSync11(dirname11(authFilePath), { recursive: true });
20444
+ writeFileSync9(authFilePath, `${JSON.stringify(next, null, 2)}
19839
20445
  `, "utf8");
19840
20446
  return {
19841
20447
  accessToken: args.accessToken,
@@ -20280,9 +20886,9 @@ var init_threadCodexWorkerIpc = __esm({
20280
20886
 
20281
20887
  // src/signupTaskSuggestions.ts
20282
20888
  import { spawn as spawn7 } from "node:child_process";
20283
- import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync14, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
20889
+ import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync15, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
20284
20890
  import { tmpdir as tmpdir2 } from "node:os";
20285
- import { join as join17 } from "node:path";
20891
+ import { join as join19 } from "node:path";
20286
20892
  async function suggestSignupTasksWithCodex(args) {
20287
20893
  const attempts = 2;
20288
20894
  let previousResponse;
@@ -20304,11 +20910,11 @@ async function suggestSignupTasksWithCodex(args) {
20304
20910
  );
20305
20911
  }
20306
20912
  async function runCodexTaskSuggestion(args) {
20307
- const tempRoot = mkdtempSync3(join17(tmpdir2(), "linzumi-signup-codex-tasks-"));
20308
- const schemaPath = join17(tempRoot, "task-suggestions.schema.json");
20309
- const outputPath = join17(tempRoot, "task-suggestions.json");
20913
+ const tempRoot = mkdtempSync3(join19(tmpdir2(), "linzumi-signup-codex-tasks-"));
20914
+ const schemaPath = join19(tempRoot, "task-suggestions.schema.json");
20915
+ const outputPath = join19(tempRoot, "task-suggestions.json");
20310
20916
  const prompt = taskSuggestionPrompt(args.previousResponse);
20311
- writeFileSync8(
20917
+ writeFileSync10(
20312
20918
  schemaPath,
20313
20919
  `${JSON.stringify(taskSuggestionJsonSchema(), null, 2)}
20314
20920
  `,
@@ -20325,9 +20931,9 @@ async function runCodexTaskSuggestion(args) {
20325
20931
  prompt
20326
20932
  })
20327
20933
  );
20328
- return readFileSync14(outputPath, "utf8");
20934
+ return readFileSync15(outputPath, "utf8");
20329
20935
  } finally {
20330
- rmSync3(tempRoot, { recursive: true, force: true });
20936
+ rmSync4(tempRoot, { recursive: true, force: true });
20331
20937
  }
20332
20938
  }
20333
20939
  function codexTaskSuggestionProcess(args) {
@@ -20774,25 +21380,25 @@ import { createHash as createHash5, randomUUID as randomUUID4 } from "node:crypt
20774
21380
  import {
20775
21381
  chmodSync as chmodSync2,
20776
21382
  lstatSync,
20777
- mkdirSync as mkdirSync11,
21383
+ mkdirSync as mkdirSync12,
20778
21384
  mkdtempSync as mkdtempSync4,
20779
21385
  readdirSync as readdirSync4,
20780
- readFileSync as readFileSync15,
21386
+ readFileSync as readFileSync16,
20781
21387
  realpathSync as realpathSync6,
20782
- renameSync as renameSync2,
20783
- rmSync as rmSync4,
21388
+ renameSync as renameSync3,
21389
+ rmSync as rmSync5,
20784
21390
  statSync as statSync3,
20785
- writeFileSync as writeFileSync9
21391
+ writeFileSync as writeFileSync11
20786
21392
  } from "node:fs";
20787
21393
  import { readFile as readFile2 } from "node:fs/promises";
20788
21394
  import { createServer as createServer3 } from "node:http";
20789
- import { homedir as homedir12, hostname as hostname2, tmpdir as tmpdir3 } from "node:os";
21395
+ import { homedir as homedir13, hostname as hostname2, tmpdir as tmpdir3 } from "node:os";
20790
21396
  import {
20791
21397
  basename as basename8,
20792
21398
  dirname as dirname13,
20793
21399
  extname as extname2,
20794
21400
  isAbsolute as isAbsolute5,
20795
- join as join18,
21401
+ join as join20,
20796
21402
  resolve as resolve8
20797
21403
  } from "node:path";
20798
21404
  async function runLocalCodexRunner(options) {
@@ -20820,7 +21426,21 @@ async function runLocalCodexRunner(options) {
20820
21426
  workspace: runnerWorkspaceSlug(options) ?? null,
20821
21427
  linzumiUrl: options.kandanUrl,
20822
21428
  launchSource: options.launchSource,
20823
- configPath: options.runnerLockConfigPath
21429
+ configPath: options.runnerLockConfigPath,
21430
+ // Wedged-runner takeover: a lock holder whose pid is alive but
21431
+ // whose lock heartbeat went stale (>3 min) gets SIGKILLed and its
21432
+ // lock replaced, instead of blocking recovery until someone runs
21433
+ // kill -9 by hand. Log it so the runner log explains where the old
21434
+ // pid went.
21435
+ onTakeover: (takeover) => {
21436
+ log2("runner.lock_takeover", {
21437
+ runnerId: options.runnerId,
21438
+ holderRunnerId: takeover.holderRunnerId,
21439
+ holderPid: takeover.holderPid,
21440
+ reason: takeover.reason,
21441
+ lockPath: takeover.lockPath
21442
+ });
21443
+ }
20824
21444
  });
20825
21445
  } catch (error) {
20826
21446
  if (isRunnerLockHeldError(error)) {
@@ -21024,6 +21644,9 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
21024
21644
  defaultAgentProvider: "codex",
21025
21645
  startInstance: allowedCwds.value.length > 0,
21026
21646
  durableClaudeSessionStore: true,
21647
+ // Honest capability: no faithful Claude Code rewind exists yet; the
21648
+ // rewind_thread control responds with a clean rejection (spec:
21649
+ // plans/2026-06-12-claude-steer-rewind-parity-note.md item B).
21027
21650
  claudeCodeCheckpointRewind: false,
21028
21651
  allowedCwds: allowedCwds.value,
21029
21652
  missingAllowedCwds: missingAllowedCwds.value,
@@ -22114,13 +22737,14 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
22114
22737
  if (workspaceSlug === void 0 || channelSlug === void 0 || kandanThreadId === void 0) {
22115
22738
  return void 0;
22116
22739
  }
22117
- const waferResolution = resolveControlWaferModelProvider(control);
22118
- if (waferResolution.type === "error") {
22740
+ const providerResolution = resolveControlCodexModelProvider(control);
22741
+ const providerResolutionError = codexModelProviderResolutionError(providerResolution);
22742
+ if (providerResolutionError !== void 0) {
22119
22743
  return {
22120
22744
  instanceId,
22121
22745
  controlType: control.type,
22122
22746
  ok: false,
22123
- error: waferResolution.error,
22747
+ error: providerResolutionError,
22124
22748
  kandanThreadId,
22125
22749
  cwd
22126
22750
  };
@@ -22735,14 +23359,14 @@ function commanderOutboxPersistDir() {
22735
23359
  if (override !== void 0 && override !== "") {
22736
23360
  return override;
22737
23361
  }
22738
- return join18(homedir12(), ".linzumi", "commander-outbox");
23362
+ return join20(homedir13(), ".linzumi", "commander-outbox");
22739
23363
  }
22740
23364
  function controlCursorStorePath(runnerId) {
22741
23365
  const sanitized = runnerId.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 80);
22742
23366
  const digest = createHash5("sha256").update(runnerId).digest("hex").slice(0, 8);
22743
23367
  const stem = sanitized === "" ? "runner" : sanitized;
22744
- return join18(
22745
- homedir12(),
23368
+ return join20(
23369
+ homedir13(),
22746
23370
  ".linzumi",
22747
23371
  "control-cursors",
22748
23372
  `${stem}.${digest}.json`
@@ -22752,8 +23376,8 @@ function appliedStartTurnStorePath(runnerId) {
22752
23376
  const sanitized = runnerId.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 80);
22753
23377
  const digest = createHash5("sha256").update(runnerId).digest("hex").slice(0, 8);
22754
23378
  const stem = sanitized === "" ? "runner" : sanitized;
22755
- return join18(
22756
- homedir12(),
23379
+ return join20(
23380
+ homedir13(),
22757
23381
  ".linzumi",
22758
23382
  "control-cursors",
22759
23383
  `${stem}.${digest}.start-turn.json`
@@ -22875,9 +23499,9 @@ function createControlCursorFileStore(path2, log2, options) {
22875
23499
  }
22876
23500
  dirty = false;
22877
23501
  try {
22878
- mkdirSync11(dirname13(path2), { recursive: true });
23502
+ mkdirSync12(dirname13(path2), { recursive: true });
22879
23503
  const tmpPath = `${path2}.tmp`;
22880
- writeFileSync9(
23504
+ writeFileSync11(
22881
23505
  tmpPath,
22882
23506
  `${JSON.stringify({
22883
23507
  ...epoch === void 0 ? {} : { [controlCursorEpochKey]: epoch },
@@ -22886,7 +23510,7 @@ function createControlCursorFileStore(path2, log2, options) {
22886
23510
  `,
22887
23511
  "utf8"
22888
23512
  );
22889
- renameSync2(tmpPath, path2);
23513
+ renameSync3(tmpPath, path2);
22890
23514
  } catch (error) {
22891
23515
  log2("control_cursor_store.write_failed", {
22892
23516
  path: path2,
@@ -22985,7 +23609,7 @@ function readControlCursorFile(path2, log2) {
22985
23609
  const cursors = /* @__PURE__ */ new Map();
22986
23610
  let raw;
22987
23611
  try {
22988
- raw = readFileSync15(path2, "utf8");
23612
+ raw = readFileSync16(path2, "utf8");
22989
23613
  } catch (error) {
22990
23614
  if (!isErrnoCode2(error, "ENOENT")) {
22991
23615
  log2("control_cursor_store.read_failed", {
@@ -23579,18 +24203,18 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
23579
24203
  return delegated;
23580
24204
  }
23581
24205
  if (agentProvider === "codex") {
23582
- const waferControlError = waferModelProviderControlError(
24206
+ const providerControlError = codexModelProviderControlError(
23583
24207
  options,
23584
24208
  control
23585
24209
  );
23586
- if (waferControlError !== void 0) {
24210
+ if (providerControlError !== void 0) {
23587
24211
  try {
23588
24212
  await publishStartInstanceMessageState(
23589
24213
  kandan,
23590
24214
  topic,
23591
24215
  control,
23592
24216
  "failed",
23593
- waferControlError,
24217
+ providerControlError,
23594
24218
  { instanceId }
23595
24219
  );
23596
24220
  } catch (error) {
@@ -23602,7 +24226,7 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
23602
24226
  instanceId,
23603
24227
  controlType: control.type,
23604
24228
  ok: false,
23605
- error: waferControlError
24229
+ error: providerControlError
23606
24230
  };
23607
24231
  }
23608
24232
  }
@@ -23750,16 +24374,16 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
23750
24374
  return delegated;
23751
24375
  }
23752
24376
  if (agentProvider === "codex") {
23753
- const waferControlError = waferModelProviderControlError(
24377
+ const providerControlError = codexModelProviderControlError(
23754
24378
  options,
23755
24379
  control
23756
24380
  );
23757
- if (waferControlError !== void 0) {
24381
+ if (providerControlError !== void 0) {
23758
24382
  return {
23759
24383
  instanceId,
23760
24384
  controlType: control.type,
23761
24385
  ok: false,
23762
- error: waferControlError
24386
+ error: providerControlError
23763
24387
  };
23764
24388
  }
23765
24389
  }
@@ -24080,18 +24704,30 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
24080
24704
  error: "claude_code_steer_requires_text_input"
24081
24705
  };
24082
24706
  }
24083
- await claudeSession.interruptTurn("Steered by Linzumi");
24084
- claudeSession.enqueueInput({
24085
- content: `You were interrupted mid-task. Updated guidance from the user - continue the task with this in mind:
24086
-
24087
- ${steerText}`,
24088
- sourceSeq: claudeSession.currentSourceSeq()
24089
- });
24707
+ let steered;
24708
+ try {
24709
+ steered = claudeSession.steerTurn(steerText);
24710
+ } catch (steerError) {
24711
+ const message = steerError instanceof Error ? steerError.message : String(steerError);
24712
+ log2("claude_code.steer_failed", {
24713
+ thread_id: control.threadId,
24714
+ message
24715
+ });
24716
+ return {
24717
+ instanceId,
24718
+ controlType: control.type,
24719
+ agentProvider: "claude-code",
24720
+ ok: false,
24721
+ error: "claude_code_steer_failed",
24722
+ message,
24723
+ threadId: control.threadId
24724
+ };
24725
+ }
24090
24726
  return {
24091
24727
  instanceId,
24092
24728
  controlType: control.type,
24093
24729
  agentProvider: "claude-code",
24094
- steered: "steered_via_restart",
24730
+ steered,
24095
24731
  threadId: control.threadId
24096
24732
  };
24097
24733
  }
@@ -24130,6 +24766,30 @@ ${steerText}`,
24130
24766
  response
24131
24767
  };
24132
24768
  }
24769
+ case "rewind_thread": {
24770
+ const claudeSession = activeClaudeCodeSessions.get(control.threadId);
24771
+ if (claudeSession !== void 0 || control.agentProvider === "claude-code") {
24772
+ return {
24773
+ instanceId,
24774
+ controlType: control.type,
24775
+ agentProvider: "claude-code",
24776
+ requestId: stringValue(control.requestId) ?? null,
24777
+ threadId: control.threadId,
24778
+ ok: false,
24779
+ error: "claude_code_rewind_unsupported",
24780
+ message: "Claude Code does not support rewind yet"
24781
+ };
24782
+ }
24783
+ return {
24784
+ instanceId,
24785
+ controlType: control.type,
24786
+ requestId: stringValue(control.requestId) ?? null,
24787
+ threadId: control.threadId,
24788
+ ok: false,
24789
+ error: "rewind_not_supported",
24790
+ message: "This runner does not support rewinding threads yet"
24791
+ };
24792
+ }
24133
24793
  case "interrupt_queued_messages": {
24134
24794
  const agentProvider = stringValue(control.agentProvider)?.trim();
24135
24795
  if (agentProvider !== "claude-code") {
@@ -24397,6 +25057,15 @@ function truncateFailureDetail(message) {
24397
25057
  }
24398
25058
  function commanderDeveloperInstructions(args) {
24399
25059
  const agentLabel = args.agentLabel ?? "Codex";
25060
+ const planStepsInstruction = args.planTool === "todo-write" ? `For coding-job threads, start by setting the current goal with
25061
+ linzumi_upsert_coding_job_plan, then record the plan steps with the TodoWrite
25062
+ tool. Linzumi mirrors your TodoWrite list into the coding-job plan steps
25063
+ automatically, one TodoWrite item per plan step.` : `For coding-job threads, start by setting the current goal with
25064
+ linzumi_upsert_coding_job_plan, then replace the plan steps with
25065
+ linzumi_replace_coding_job_plan_steps.`;
25066
+ const planUpdateInstruction = args.planTool === "todo-write" ? `As work proceeds, update each step's status with TodoWrite. Do not call
25067
+ linzumi_replace_coding_job_plan_steps or linzumi_update_coding_job_plan_step
25068
+ directly; TodoWrite is the source of truth for the plan steps.` : `As work proceeds, update each step with linzumi_update_coding_job_plan_step.`;
24400
25069
  const customPrompt = args.developerPrompt === void 0 ? "" : `
24401
25070
  <invoker_developer_prompt>
24402
25071
  ${args.developerPrompt}
@@ -24446,13 +25115,11 @@ something else in the Linzumi thread. Start, inspect, and modify the local app
24446
25115
  from that folder. Report concise progress and exact blockers in the thread.
24447
25116
  Use the Linzumi MCP server named "linzumi" when you need authenticated
24448
25117
  workspace context or coding-job metadata tools.
24449
- For coding-job threads, start by setting the current goal with
24450
- linzumi_upsert_coding_job_plan, then replace the plan steps with
24451
- linzumi_replace_coding_job_plan_steps.
25118
+ ${planStepsInstruction}
24452
25119
  When the coding-job scope changes materially, call linzumi_rename_coding_job
24453
25120
  with a concise title so the Linzumi thread title and workflow-facing title
24454
25121
  match the work.
24455
- As work proceeds, update each step with linzumi_update_coding_job_plan_step.
25122
+ ${planUpdateInstruction}
24456
25123
  When you open, discover, or choose the primary pull request, link it with
24457
25124
  linzumi_link_coding_job_pull_request.
24458
25125
  Before stopping, confirm the metadata overview tells the truth for a user who
@@ -24590,10 +25257,24 @@ function startInstanceAgentLabel(provider) {
24590
25257
  return "Claude Code";
24591
25258
  }
24592
25259
  }
24593
- function resolveControlWaferModelProvider(control) {
25260
+ function resolveControlCodexModelProvider(control) {
24594
25261
  const modelProvider = stringValue(control.modelProvider)?.trim();
25262
+ const llmProxy = objectValue(control.llmProxy);
25263
+ const baseUrl = stringValue(llmProxy?.baseUrl)?.trim();
25264
+ const token = stringValue(llmProxy?.token)?.trim();
25265
+ const binding = baseUrl !== void 0 && baseUrl !== "" && token !== void 0 && token !== "" ? { baseUrl, token } : void 0;
24595
25266
  if (modelProvider === void 0 || modelProvider === "") {
24596
- return { type: "none" };
25267
+ if (binding === void 0) {
25268
+ return { type: "none" };
25269
+ }
25270
+ return {
25271
+ type: "provider",
25272
+ runtime: {
25273
+ provider: "openai-proxy",
25274
+ llmProxyBaseUrl: binding.baseUrl,
25275
+ llmProxyToken: binding.token
25276
+ }
25277
+ };
24597
25278
  }
24598
25279
  if (modelProvider !== "wafer") {
24599
25280
  return {
@@ -24601,40 +25282,84 @@ function resolveControlWaferModelProvider(control) {
24601
25282
  error: `model_provider_unsupported:${modelProvider}`
24602
25283
  };
24603
25284
  }
24604
- const llmProxy = objectValue(control.llmProxy);
24605
- const baseUrl = stringValue(llmProxy?.baseUrl)?.trim();
24606
- const token = stringValue(llmProxy?.token)?.trim();
24607
- if (baseUrl === void 0 || baseUrl === "" || token === void 0 || token === "") {
25285
+ if (binding === void 0) {
24608
25286
  return { type: "error", error: "wafer_model_provider_missing_llm_proxy" };
24609
25287
  }
24610
25288
  return {
24611
- type: "wafer",
25289
+ type: "provider",
24612
25290
  runtime: {
24613
25291
  provider: "wafer",
24614
- llmProxyBaseUrl: baseUrl,
24615
- llmProxyToken: token
25292
+ llmProxyBaseUrl: binding.baseUrl,
25293
+ llmProxyToken: binding.token
24616
25294
  }
24617
25295
  };
24618
25296
  }
24619
- function waferModelProviderControlError(options, control) {
24620
- const resolution = resolveControlWaferModelProvider(control);
25297
+ function codexModelProviderResolutionError(resolution) {
25298
+ if (resolution.type === "error") {
25299
+ return resolution.error;
25300
+ }
25301
+ if (resolution.type === "provider" && resolution.runtime.provider === "openai-proxy" && resolveForwardableOpenAiApiKey() === void 0) {
25302
+ return "codex_llm_proxy_requires_openai_api_key";
25303
+ }
25304
+ return void 0;
25305
+ }
25306
+ function codexModelProviderControlError(options, control) {
25307
+ const resolution = resolveControlCodexModelProvider(control);
24621
25308
  switch (resolution.type) {
24622
25309
  case "none":
24623
25310
  return void 0;
24624
25311
  case "error":
24625
25312
  return resolution.error;
24626
- case "wafer":
24627
- return options.codexModelProvider?.provider === "wafer" ? void 0 : "wafer_model_provider_requires_thread_worker";
25313
+ case "provider": {
25314
+ const gateError = codexModelProviderResolutionError(resolution);
25315
+ if (gateError !== void 0) {
25316
+ return gateError;
25317
+ }
25318
+ 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";
25319
+ }
24628
25320
  }
24629
25321
  }
24630
25322
  function linzumiCodexModelProviderConfig(runtime) {
24631
- return {
24632
- id: "linzumi",
24633
- name: "Linzumi Proxy",
24634
- baseUrl: `${runtime.llmProxyBaseUrl.replace(/\/+$/, "")}/v1`,
24635
- envKey: "LINZUMI_LLM_PROXY_TOKEN",
24636
- wireApi: "responses"
24637
- };
25323
+ const baseUrl = `${runtime.llmProxyBaseUrl.replace(/\/+$/, "")}/v1`;
25324
+ switch (runtime.provider) {
25325
+ case "wafer":
25326
+ return {
25327
+ id: "linzumi",
25328
+ name: "Linzumi Proxy",
25329
+ baseUrl,
25330
+ envKey: "LINZUMI_LLM_PROXY_TOKEN",
25331
+ wireApi: "responses"
25332
+ };
25333
+ case "openai-proxy":
25334
+ return {
25335
+ id: "linzumi",
25336
+ name: "Linzumi Proxy",
25337
+ baseUrl,
25338
+ envKey: "OPENAI_API_KEY",
25339
+ wireApi: "responses",
25340
+ envHttpHeaders: {
25341
+ "x-linzumi-llm-proxy-token": "LINZUMI_LLM_PROXY_TOKEN"
25342
+ }
25343
+ };
25344
+ }
25345
+ }
25346
+ function codexModelProviderAppServerEnv(runtime) {
25347
+ switch (runtime.provider) {
25348
+ case "wafer":
25349
+ return { LINZUMI_LLM_PROXY_TOKEN: runtime.llmProxyToken };
25350
+ case "openai-proxy": {
25351
+ const openAiApiKey = resolveForwardableOpenAiApiKey();
25352
+ if (openAiApiKey === void 0) {
25353
+ throw new Error(
25354
+ "codex llm proxy requires API-key auth (OPENAI_API_KEY in the environment or $CODEX_HOME/auth.json); ChatGPT OAuth credentials cannot be forwarded"
25355
+ );
25356
+ }
25357
+ return {
25358
+ LINZUMI_LLM_PROXY_TOKEN: runtime.llmProxyToken,
25359
+ OPENAI_API_KEY: openAiApiKey
25360
+ };
25361
+ }
25362
+ }
24638
25363
  }
24639
25364
  async function startCodexProviderInstance(args) {
24640
25365
  if (args.options.codexUrl === void 0) {
@@ -24658,6 +25383,7 @@ async function startCodexProviderInstance(args) {
24658
25383
  personality: "pragmatic",
24659
25384
  developerInstructions: commanderDeveloperInstructions({
24660
25385
  cwd: args.cwd,
25386
+ planTool: "linzumi-mcp",
24661
25387
  developerPrompt,
24662
25388
  linzumiContext
24663
25389
  }),
@@ -24758,6 +25484,23 @@ function createClaudeCodeInputQueue(input) {
24758
25484
  }
24759
25485
  waiter({ done: false, value: message });
24760
25486
  };
25487
+ const enqueueSteer = (content) => {
25488
+ if (state.closed) {
25489
+ throw new Error("Claude Code streaming input is closed");
25490
+ }
25491
+ if (pendingSourceSeqs.length === 0) {
25492
+ enqueue({ content, sourceSeq: void 0 });
25493
+ return "steered_queued";
25494
+ }
25495
+ const message = claudeCodeUserInputMessage(content);
25496
+ const waiter = waiters.shift();
25497
+ if (waiter === void 0) {
25498
+ pendingMessages.push(message);
25499
+ } else {
25500
+ waiter({ done: false, value: message });
25501
+ }
25502
+ return "steered_live";
25503
+ };
24761
25504
  return {
24762
25505
  messages: {
24763
25506
  [Symbol.asyncIterator]() {
@@ -24783,6 +25526,7 @@ function createClaudeCodeInputQueue(input) {
24783
25526
  drainClosedWaiters();
24784
25527
  },
24785
25528
  enqueue,
25529
+ enqueueSteer,
24786
25530
  completeTurn: () => pendingSourceSeqs.shift(),
24787
25531
  currentSourceSeq: () => pendingSourceSeqs[0]
24788
25532
  };
@@ -25033,6 +25777,18 @@ async function startClaudeCodeProviderInstance(args) {
25033
25777
  const abortController = new AbortController();
25034
25778
  let activeSessionId;
25035
25779
  let sessionControls;
25780
+ const planMirrorClient = createLinzumiMcpApiClient({
25781
+ kandanUrl: args.options.kandanUrl,
25782
+ accessToken: args.options.token,
25783
+ fetchImpl: args.options.fetch,
25784
+ operatingMode: "text"
25785
+ });
25786
+ const planMirror = createClaudeCodePlanMirror({
25787
+ replacePlanSteps: planMirrorClient.replaceCodingJobPlanSteps,
25788
+ threadId,
25789
+ goal: workDescription.trim().slice(0, 2e3),
25790
+ log: args.log
25791
+ });
25036
25792
  const adapter = createClaudeCodeSessionPipeline({
25037
25793
  instanceId: args.instanceId,
25038
25794
  cwd: args.cwd,
@@ -25089,8 +25845,27 @@ async function startClaudeCodeProviderInstance(args) {
25089
25845
  claude_session_id: activeSessionId ?? null
25090
25846
  });
25091
25847
  },
25848
+ onTodoWriteCompleted: planMirror.handleTodoWrite,
25092
25849
  log: args.log
25093
25850
  });
25851
+ const liveBashCapture = args.options.claudeCodeRunner === void 0 && claudeLiveBashCaptureEnabled(process.env) ? createClaudeCodeLiveBashCapture({
25852
+ captureDir: join20(
25853
+ tmpdir3(),
25854
+ `linzumi-claude-live-bash-${args.instanceId}`
25855
+ ),
25856
+ onOutputDelta: (toolUseId, delta) => {
25857
+ if (activeSessionId === void 0) {
25858
+ return;
25859
+ }
25860
+ adapter.handleTranscriptEvent({
25861
+ type: "command_output_delta",
25862
+ sessionId: activeSessionId,
25863
+ itemKey: toolUseId,
25864
+ delta
25865
+ });
25866
+ },
25867
+ log: (event, fields) => args.log(event, fields)
25868
+ }) : void 0;
25094
25869
  let mcpAuthCleanup;
25095
25870
  let mcpServers;
25096
25871
  try {
@@ -25195,6 +25970,7 @@ async function startClaudeCodeProviderInstance(args) {
25195
25970
  threadId,
25196
25971
  currentSourceSeq: inputQueue.currentSourceSeq,
25197
25972
  enqueueInput: inputQueue.enqueue,
25973
+ steerTurn: inputQueue.enqueueSteer,
25198
25974
  interruptTurn: async (reason) => {
25199
25975
  const aborted = adapter.interruptActiveTurn(reason);
25200
25976
  await sessionControls?.interrupt();
@@ -25253,16 +26029,36 @@ async function startClaudeCodeProviderInstance(args) {
25253
26029
  if (event.type === "rate_limit") {
25254
26030
  await reportClaudeCodeRateLimit(event);
25255
26031
  }
26032
+ if (event.type === "tool_result") {
26033
+ liveBashCapture?.settleTool(event.itemKey);
26034
+ }
26035
+ if (event.type === "turn_interrupted" || event.type === "session_failed") {
26036
+ liveBashCapture?.settleAll();
26037
+ }
26038
+ if (event.type === "usage") {
26039
+ const summary = claudeCodeTokenUsageSummaryText(event.usage);
26040
+ if (summary !== void 0) {
26041
+ args.log("claude_code.token_usage", {
26042
+ linzumi_thread_id: threadId,
26043
+ claude_session_id: event.sessionId,
26044
+ token_usage_summary: summary
26045
+ });
26046
+ }
26047
+ }
25256
26048
  adapter.handleTranscriptEvent(event);
25257
26049
  };
25258
26050
  const llmProxy = objectValue(args.control.llmProxy);
25259
26051
  const llmProxyBaseUrl = stringValue(llmProxy?.baseUrl)?.trim();
25260
26052
  const llmProxyToken = stringValue(llmProxy?.token)?.trim();
25261
- const sessionEnv = llmProxyBaseUrl !== void 0 && llmProxyBaseUrl !== "" && llmProxyToken !== void 0 && llmProxyToken !== "" ? claudeCodeLlmProxyEnv(
26053
+ const baseSessionEnv = llmProxyBaseUrl !== void 0 && llmProxyBaseUrl !== "" && llmProxyToken !== void 0 && llmProxyToken !== "" ? claudeCodeLlmProxyEnv(
25262
26054
  process.env,
25263
26055
  { baseUrl: llmProxyBaseUrl, token: llmProxyToken },
25264
26056
  runtimeSettings.model
25265
- ) : void 0;
26057
+ ) : definedProcessEnv(process.env);
26058
+ const sessionEnv = {
26059
+ ...baseSessionEnv,
26060
+ CLAUDE_CODE_ENABLE_TASKS: "0"
26061
+ };
25266
26062
  const canUseTool = (request, signal) => waitForClaudeCodeToolApproval({
25267
26063
  kandan: args.kandan,
25268
26064
  topic: args.topic,
@@ -25284,6 +26080,7 @@ async function startClaudeCodeProviderInstance(args) {
25284
26080
  developerInstructions: commanderDeveloperInstructions({
25285
26081
  cwd: args.cwd,
25286
26082
  agentLabel: "Claude Code",
26083
+ planTool: "todo-write",
25287
26084
  developerPrompt,
25288
26085
  linzumiContext
25289
26086
  }),
@@ -25294,7 +26091,11 @@ async function startClaudeCodeProviderInstance(args) {
25294
26091
  runner: args.options.claudeCodeRunner,
25295
26092
  canUseTool,
25296
26093
  ...mcpServers === void 0 ? {} : { mcpServers },
25297
- ...sessionEnv === void 0 ? {} : { env: sessionEnv },
26094
+ ...liveBashCapture === void 0 ? {} : {
26095
+ preToolUseHookMatchers: liveBashCapture.hookMatchers,
26096
+ wrapApprovedToolInput: (toolUseId, toolName2, input) => toolName2 === "Bash" ? liveBashCapture.wrapApprovedTool(toolUseId, input) : void 0
26097
+ },
26098
+ env: sessionEnv,
25298
26099
  // The built-in Linzumi MCP is trusted like the codex side: its tools
25299
26100
  // run without an approval round-trip. SDK allowedTools matches MCP
25300
26101
  // tools as mcp__<server>__<tool>; the __* suffix covers the server.
@@ -25310,6 +26111,7 @@ async function startClaudeCodeProviderInstance(args) {
25310
26111
  } finally {
25311
26112
  inputQueue.close();
25312
26113
  mcpAuthCleanup?.();
26114
+ liveBashCapture?.close();
25313
26115
  if (activeSessionId !== void 0) {
25314
26116
  args.activeClaudeCodeSessions.delete(activeSessionId);
25315
26117
  await args.disposeClaudeCodeForwardPortSession?.(activeSessionId);
@@ -25321,6 +26123,12 @@ async function startClaudeCodeProviderInstance(args) {
25321
26123
  error instanceof Error ? error.message : String(error)
25322
26124
  );
25323
26125
  await adapter.close(5e3).catch(() => void 0);
26126
+ await Promise.race([
26127
+ planMirror.settle().catch(() => void 0),
26128
+ new Promise((resolve12) => {
26129
+ setTimeout(resolve12, 5e3).unref?.();
26130
+ })
26131
+ ]);
25324
26132
  logStartFailureTerminal(
25325
26133
  error instanceof Error ? error.message : String(error)
25326
26134
  );
@@ -25330,6 +26138,12 @@ async function startClaudeCodeProviderInstance(args) {
25330
26138
  args.setStartupStage("posting_claude_code_output");
25331
26139
  await adapter.awaitTurnsSettled(3e4);
25332
26140
  await adapter.close(3e4);
26141
+ await Promise.race([
26142
+ planMirror.settle(),
26143
+ new Promise((resolve12) => {
26144
+ setTimeout(resolve12, 1e4).unref?.();
26145
+ })
26146
+ ]);
25333
26147
  return {
25334
26148
  controlResponse: {
25335
26149
  instanceId: args.instanceId,
@@ -25453,6 +26267,8 @@ function claudeSessionStoreEntryPayload(args, event) {
25453
26267
  itemKey: event.itemKey,
25454
26268
  body: event.content
25455
26269
  };
26270
+ case "command_output_delta":
26271
+ return void 0;
25456
26272
  case "usage":
25457
26273
  return { usage: event.usage };
25458
26274
  case "rate_limit":
@@ -25483,6 +26299,15 @@ function claudeSessionStoreEntryPayload(args, event) {
25483
26299
  return { body: event.reason };
25484
26300
  }
25485
26301
  }
26302
+ function definedProcessEnv(baseEnv) {
26303
+ const env = {};
26304
+ for (const [key, value] of Object.entries(baseEnv)) {
26305
+ if (value !== void 0) {
26306
+ env[key] = value;
26307
+ }
26308
+ }
26309
+ return env;
26310
+ }
25486
26311
  function claudeCodeLlmProxyEnv(baseEnv, proxy, model) {
25487
26312
  const env = {};
25488
26313
  for (const [key, value] of Object.entries(baseEnv)) {
@@ -25514,6 +26339,7 @@ function claudeCodeRoutedProxyModel(model) {
25514
26339
  case "haiku":
25515
26340
  case "sonnet":
25516
26341
  case "opus":
26342
+ case "fable-5":
25517
26343
  return void 0;
25518
26344
  default:
25519
26345
  return trimmed.startsWith("claude") ? void 0 : trimmed;
@@ -25530,6 +26356,8 @@ function claudeCodeModelForRuntimeModel(model) {
25530
26356
  case "sonnet":
25531
26357
  case "opus":
25532
26358
  return trimmed;
26359
+ case "fable-5":
26360
+ return "claude-fable-5";
25533
26361
  default:
25534
26362
  return isCodexRuntimeModel(trimmed) ? "sonnet" : trimmed;
25535
26363
  }
@@ -25859,7 +26687,7 @@ function threadRunnerOptions(args) {
25859
26687
  args.options,
25860
26688
  args.control
25861
26689
  );
25862
- const waferResolution = resolveControlWaferModelProvider(args.control);
26690
+ const providerResolution = resolveControlCodexModelProvider(args.control);
25863
26691
  return {
25864
26692
  ...args.options,
25865
26693
  clientId: void 0,
@@ -25876,7 +26704,7 @@ function threadRunnerOptions(args) {
25876
26704
  role: "thread",
25877
26705
  kandanThreadId: args.kandanThreadId
25878
26706
  },
25879
- codexModelProvider: waferResolution.type === "wafer" ? waferResolution.runtime : void 0,
26707
+ codexModelProvider: providerResolution.type === "provider" ? providerResolution.runtime : void 0,
25880
26708
  spawnThreadRunner: void 0,
25881
26709
  threadRunnerReadyTimeoutMs: args.options.threadRunnerReadyTimeoutMs,
25882
26710
  runtimeDefaults: {
@@ -25913,6 +26741,7 @@ async function spawnLocalThreadRunnerProcess(options) {
25913
26741
  scriptPath,
25914
26742
  redactedThreadRunnerCliArgs(args)
25915
26743
  );
26744
+ const forwardableOpenAiApiKey = options.codexModelProvider?.provider === "openai-proxy" ? resolveForwardableOpenAiApiKey() : void 0;
25916
26745
  const env = {
25917
26746
  ...process.env,
25918
26747
  LINZUMI_THREAD_RUNNER_ROLE: "thread",
@@ -25920,7 +26749,8 @@ async function spawnLocalThreadRunnerProcess(options) {
25920
26749
  LINZUMI_THREAD_RUNNER_TOKEN: options.token,
25921
26750
  // The LLM proxy credential travels via env (like the runner token), not
25922
26751
  // argv, so the spawned worker's command line never carries it.
25923
- ...options.codexModelProvider === void 0 ? {} : { LINZUMI_LLM_PROXY_TOKEN: options.codexModelProvider.llmProxyToken }
26752
+ ...options.codexModelProvider === void 0 ? {} : { LINZUMI_LLM_PROXY_TOKEN: options.codexModelProvider.llmProxyToken },
26753
+ ...forwardableOpenAiApiKey === void 0 ? {} : { OPENAI_API_KEY: forwardableOpenAiApiKey }
25924
26754
  };
25925
26755
  writeCliAuditEvent("process.spawn", {
25926
26756
  command: process.execPath,
@@ -27126,16 +27956,16 @@ async function startOwnedCodexAppServer(options, args = { linzumiMcp: true }) {
27126
27956
  model: defaults.model,
27127
27957
  reasoningEffort: defaults.reasoningEffort,
27128
27958
  fast: options.fast,
27129
- // Wafer-routed thread workers point their owned app-server at the
27130
- // Kandan LLM proxy via a custom Linzumi model provider; the proxy
27131
- // credential rides env_key plus the session header.
27959
+ // Proxy-routed thread workers point their owned app-server at the
27960
+ // Kandan LLM proxy via a custom Linzumi model provider. Wafer routes
27961
+ // ride the session token as the bearer; openai-proxy routes (parity
27962
+ // backlog item 50) additionally materialize the user's own
27963
+ // OPENAI_API_KEY as the passthrough upstream credential.
27132
27964
  ...options.codexModelProvider === void 0 ? {} : {
27133
27965
  modelProvider: linzumiCodexModelProviderConfig(
27134
27966
  options.codexModelProvider
27135
27967
  ),
27136
- env: {
27137
- LINZUMI_LLM_PROXY_TOKEN: options.codexModelProvider.llmProxyToken
27138
- }
27968
+ env: codexModelProviderAppServerEnv(options.codexModelProvider)
27139
27969
  },
27140
27970
  mcpServers: mcpAuth === void 0 ? [] : [
27141
27971
  linzumiMcpServerConfig({
@@ -27183,9 +28013,9 @@ function mcpOwnerUsername(options) {
27183
28013
  return options.channelSession?.listenUser ?? identityFromAccessToken(options.token).actorUsername;
27184
28014
  }
27185
28015
  function writeEphemeralMcpAuthFile(options) {
27186
- const directory = mkdtempSync4(join18(tmpdir3(), "linzumi-mcp-auth-"));
28016
+ const directory = mkdtempSync4(join20(tmpdir3(), "linzumi-mcp-auth-"));
27187
28017
  chmodSync2(directory, 448);
27188
- const path2 = join18(directory, "auth.json");
28018
+ const path2 = join20(directory, "auth.json");
27189
28019
  writeCachedLocalRunnerToken({
27190
28020
  kandanUrl: options.kandanUrl,
27191
28021
  accessToken: options.token,
@@ -27194,7 +28024,7 @@ function writeEphemeralMcpAuthFile(options) {
27194
28024
  chmodSync2(path2, 384);
27195
28025
  return {
27196
28026
  path: path2,
27197
- cleanup: () => rmSync4(directory, { recursive: true, force: true })
28027
+ cleanup: () => rmSync5(directory, { recursive: true, force: true })
27198
28028
  };
27199
28029
  }
27200
28030
  function once(action) {
@@ -27261,7 +28091,7 @@ function configuredAllowedCwds(values, options = {}) {
27261
28091
  const absolutePath = resolve8(expandUserPath(value));
27262
28092
  try {
27263
28093
  if (options.createMissing === true) {
27264
- mkdirSync11(absolutePath, { recursive: true });
28094
+ mkdirSync12(absolutePath, { recursive: true });
27265
28095
  }
27266
28096
  const realPath = realpathSync6(absolutePath);
27267
28097
  allowedCwds.push(
@@ -27298,7 +28128,7 @@ function allowedCwdProjects(allowedCwds) {
27298
28128
  });
27299
28129
  }
27300
28130
  function isGitProjectDirectory(cwd) {
27301
- const gitPath = join18(cwd, ".git");
28131
+ const gitPath = join20(cwd, ".git");
27302
28132
  try {
27303
28133
  const gitPathStats = statSync3(gitPath);
27304
28134
  return gitPathStats.isDirectory() || gitPathStats.isFile();
@@ -27323,7 +28153,7 @@ function browseRunnerDirectory(control, options) {
27323
28153
  }
27324
28154
  const parent = dirname13(currentPath);
27325
28155
  const entries = readdirSync4(currentPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => visibleRunnerDirectoryEntryName(entry.name)).map((entry) => {
27326
- const path2 = join18(currentPath, entry.name);
28156
+ const path2 = join20(currentPath, entry.name);
27327
28157
  return {
27328
28158
  name: entry.name,
27329
28159
  path: path2,
@@ -27364,7 +28194,7 @@ function projectDirectoryName(name) {
27364
28194
  function availableProjectDirectoryName(projectsRoot, baseName, suffix = 0) {
27365
28195
  for (let nextSuffix = suffix; ; nextSuffix += 1) {
27366
28196
  const candidate = nextSuffix === 0 ? baseName : `${baseName}-${nextSuffix}`;
27367
- if (!projectPathExists(join18(projectsRoot, candidate))) {
28197
+ if (!projectPathExists(join20(projectsRoot, candidate))) {
27368
28198
  return candidate;
27369
28199
  }
27370
28200
  }
@@ -27392,9 +28222,9 @@ function createRunnerProject(control, options, allowedCwds) {
27392
28222
  error: "invalid_project_template"
27393
28223
  };
27394
28224
  }
27395
- const projectsRoot = join18(currentHomeDirectory(), "linzumi");
28225
+ const projectsRoot = join20(currentHomeDirectory(), "linzumi");
27396
28226
  const resolvedProjectDirName = template === "hello_linzumi_demo" ? availableProjectDirectoryName(projectsRoot, projectDirName) : projectDirName;
27397
- const projectPath = join18(projectsRoot, resolvedProjectDirName);
28227
+ const projectPath = join20(projectsRoot, resolvedProjectDirName);
27398
28228
  let createdProjectPath = false;
27399
28229
  try {
27400
28230
  if (template !== "hello_linzumi_demo" && projectPathExists(projectPath)) {
@@ -27406,7 +28236,7 @@ function createRunnerProject(control, options, allowedCwds) {
27406
28236
  error: "project_directory_exists"
27407
28237
  };
27408
28238
  }
27409
- mkdirSync11(projectsRoot, { recursive: true });
28239
+ mkdirSync12(projectsRoot, { recursive: true });
27410
28240
  if (template === "hello_linzumi_demo") {
27411
28241
  createdProjectPath = true;
27412
28242
  createHelloLinzumiProject({
@@ -27414,7 +28244,7 @@ function createRunnerProject(control, options, allowedCwds) {
27414
28244
  name: resolvedProjectDirName
27415
28245
  });
27416
28246
  } else {
27417
- mkdirSync11(projectPath, { recursive: false });
28247
+ mkdirSync12(projectPath, { recursive: false });
27418
28248
  createdProjectPath = true;
27419
28249
  }
27420
28250
  const git = spawnSync5("git", ["init"], {
@@ -27472,7 +28302,7 @@ function createRunnerProject(control, options, allowedCwds) {
27472
28302
  }
27473
28303
  function removeCreatedProjectDirectory(projectPath) {
27474
28304
  try {
27475
- rmSync4(projectPath, { recursive: true, force: true });
28305
+ rmSync5(projectPath, { recursive: true, force: true });
27476
28306
  return void 0;
27477
28307
  } catch (error) {
27478
28308
  return error instanceof Error ? error.message : "cleanup_failed";
@@ -27535,6 +28365,8 @@ var init_runner = __esm({
27535
28365
  init_channelSessionSupport();
27536
28366
  init_commanderAttachments();
27537
28367
  init_claudeCodePipeline();
28368
+ init_claudeCodePlanMirror();
28369
+ init_claudeCodeLiveBashOutput();
27538
28370
  init_claudeCodeSession();
27539
28371
  init_codexAppServer();
27540
28372
  init_codexProjectTrust();
@@ -27596,7 +28428,7 @@ var init_runner = __esm({
27596
28428
  });
27597
28429
 
27598
28430
  // src/kandanTls.ts
27599
- import { existsSync as existsSync13, readFileSync as readFileSync16 } from "node:fs";
28431
+ import { existsSync as existsSync13, readFileSync as readFileSync17 } from "node:fs";
27600
28432
  import { Agent } from "undici";
27601
28433
  import WsWebSocket from "ws";
27602
28434
  function kandanTlsTrustFromEnv() {
@@ -27610,7 +28442,7 @@ function kandanTlsTrustFromCaFile(caFile) {
27610
28442
  if (!existsSync13(trimmed)) {
27611
28443
  throw new Error(`KANDAN_TLS_CA_FILE does not exist: ${trimmed}`);
27612
28444
  }
27613
- const ca = readFileSync16(trimmed, "utf8");
28445
+ const ca = readFileSync17(trimmed, "utf8");
27614
28446
  return {
27615
28447
  caFile: trimmed,
27616
28448
  ca,
@@ -42719,9 +43551,9 @@ var require_internal = __commonJS({
42719
43551
  }
42720
43552
  InternalCodec.prototype.encoder = InternalEncoder;
42721
43553
  InternalCodec.prototype.decoder = InternalDecoder;
42722
- var StringDecoder = __require("string_decoder").StringDecoder;
43554
+ var StringDecoder2 = __require("string_decoder").StringDecoder;
42723
43555
  function InternalDecoder(options, codec) {
42724
- this.decoder = new StringDecoder(codec.enc);
43556
+ this.decoder = new StringDecoder2(codec.enc);
42725
43557
  }
42726
43558
  InternalDecoder.prototype.write = function(buf) {
42727
43559
  if (!Buffer4.isBuffer(buf)) {
@@ -46394,7 +47226,7 @@ var init_RemoveFileError = __esm({
46394
47226
 
46395
47227
  // ../../node_modules/@inquirer/external-editor/dist/esm/index.js
46396
47228
  import { spawn as spawn11, spawnSync as spawnSync6 } from "child_process";
46397
- import { readFileSync as readFileSync19, unlinkSync as unlinkSync3, writeFileSync as writeFileSync12 } from "fs";
47229
+ import { readFileSync as readFileSync20, unlinkSync as unlinkSync3, writeFileSync as writeFileSync14 } from "fs";
46398
47230
  import path from "node:path";
46399
47231
  import os from "node:os";
46400
47232
  import { randomUUID as randomUUID5 } from "node:crypto";
@@ -46511,14 +47343,14 @@ var init_esm5 = __esm({
46511
47343
  if (Object.prototype.hasOwnProperty.call(this.fileOptions, "mode")) {
46512
47344
  opt.mode = this.fileOptions.mode;
46513
47345
  }
46514
- writeFileSync12(this.tempFile, this.text, opt);
47346
+ writeFileSync14(this.tempFile, this.text, opt);
46515
47347
  } catch (createFileError) {
46516
47348
  throw new CreateFileError(createFileError);
46517
47349
  }
46518
47350
  }
46519
47351
  readTemporaryFile() {
46520
47352
  try {
46521
- const tempFileBuffer = readFileSync19(this.tempFile);
47353
+ const tempFileBuffer = readFileSync20(this.tempFile);
46522
47354
  if (tempFileBuffer.length === 0) {
46523
47355
  this.text = "";
46524
47356
  } else {
@@ -47657,15 +48489,15 @@ function signupErrorCodeFromResponseText(text2) {
47657
48489
  function renderEmailCodeStart(value) {
47658
48490
  const body = objectRecord(value, "signup email-code start response");
47659
48491
  return {
47660
- pendingId: stringValue6(body, "pending_id"),
47661
- email: stringValue6(body, "email")
48492
+ pendingId: stringValue7(body, "pending_id"),
48493
+ email: stringValue7(body, "email")
47662
48494
  };
47663
48495
  }
47664
48496
  function renderEmailCodeVerify(value) {
47665
48497
  const body = objectRecord(value, "signup email-code verify response");
47666
48498
  return {
47667
- accessToken: stringValue6(body, "access_token"),
47668
- refreshToken: stringValue6(body, "refresh_token"),
48499
+ accessToken: stringValue7(body, "access_token"),
48500
+ refreshToken: stringValue7(body, "refresh_token"),
47669
48501
  expiresInSeconds: positiveIntegerValue(body, "expires_in"),
47670
48502
  user: renderUserRef(requiredValue(body, "user")),
47671
48503
  isNewUser: booleanValue(body, "is_new_user"),
@@ -47705,7 +48537,7 @@ function renderMissionControlComplete(value) {
47705
48537
  localRunnerToken: renderLocalRunnerToken(
47706
48538
  requiredValue(body, "local_runner_token")
47707
48539
  ),
47708
- launchUrl: stringValue6(body, "launch_url"),
48540
+ launchUrl: stringValue7(body, "launch_url"),
47709
48541
  ...missionControlUrl === void 0 ? {} : { missionControlUrl },
47710
48542
  config: {
47711
48543
  allowedCwds: arrayValue2(config, "allowed_cwds").map(
@@ -47725,21 +48557,21 @@ function renderLocalRunnerToken(value) {
47725
48557
  const body = objectRecord(value, "signup local runner token");
47726
48558
  const expiresInSeconds = optionalPositiveIntegerValue(body, "expires_in");
47727
48559
  return {
47728
- accessToken: stringValue6(body, "access_token"),
48560
+ accessToken: stringValue7(body, "access_token"),
47729
48561
  ...expiresInSeconds === void 0 ? {} : { expiresInSeconds },
47730
- workspaceSlug: stringValue6(body, "workspace"),
47731
- channelSlug: stringValue6(body, "channel")
48562
+ workspaceSlug: stringValue7(body, "workspace"),
48563
+ channelSlug: stringValue7(body, "channel")
47732
48564
  };
47733
48565
  }
47734
48566
  function renderTaskStartResult(value) {
47735
48567
  const body = objectRecord(value, "signup task start");
47736
- const status = stringValue6(body, "status");
48568
+ const status = stringValue7(body, "status");
47737
48569
  if (status !== "queued" && status !== "started" && status !== "failed") {
47738
48570
  throw new Error("signup task start status was incomplete");
47739
48571
  }
47740
48572
  return {
47741
- threadId: stringValue6(body, "thread_id"),
47742
- title: stringValue6(body, "title"),
48573
+ threadId: stringValue7(body, "thread_id"),
48574
+ title: stringValue7(body, "title"),
47743
48575
  status,
47744
48576
  ...optionalStringValue(body, "runner_id") === void 0 ? {} : { runnerId: optionalStringValue(body, "runner_id") },
47745
48577
  ...optionalStringValue(body, "error") === void 0 ? {} : { error: optionalStringValue(body, "error") }
@@ -47749,7 +48581,7 @@ function renderUserRef(value) {
47749
48581
  const body = objectRecord(value, "signup user");
47750
48582
  return {
47751
48583
  id: positiveIntegerValue(body, "id"),
47752
- username: stringValue6(body, "username"),
48584
+ username: stringValue7(body, "username"),
47753
48585
  ...optionalStringValue(body, "display_name") === void 0 ? {} : { displayName: optionalStringValue(body, "display_name") },
47754
48586
  ...optionalStringValue(body, "primary_email") === void 0 ? {} : { primaryEmail: optionalStringValue(body, "primary_email") }
47755
48587
  };
@@ -47758,23 +48590,23 @@ function renderWorkspaceRef(value) {
47758
48590
  const body = objectRecord(value, "signup workspace");
47759
48591
  return {
47760
48592
  id: positiveIntegerValue(body, "id"),
47761
- slug: stringValue6(body, "slug"),
47762
- name: stringValue6(body, "name")
48593
+ slug: stringValue7(body, "slug"),
48594
+ name: stringValue7(body, "name")
47763
48595
  };
47764
48596
  }
47765
48597
  function renderChannelRef(value) {
47766
48598
  const body = objectRecord(value, "signup channel");
47767
48599
  return {
47768
48600
  id: positiveIntegerValue(body, "id"),
47769
- slug: stringValue6(body, "slug"),
47770
- name: stringValue6(body, "name")
48601
+ slug: stringValue7(body, "slug"),
48602
+ name: stringValue7(body, "name")
47771
48603
  };
47772
48604
  }
47773
48605
  function renderThreadRef(value) {
47774
48606
  const body = objectRecord(value, "signup thread");
47775
48607
  return {
47776
- threadId: stringValue6(body, "thread_id"),
47777
- title: stringValue6(body, "title"),
48608
+ threadId: stringValue7(body, "thread_id"),
48609
+ title: stringValue7(body, "title"),
47778
48610
  rootSeq: positiveIntegerValue(body, "root_seq"),
47779
48611
  threadSeq: positiveIntegerValue(body, "thread_seq")
47780
48612
  };
@@ -47792,7 +48624,7 @@ function requiredValue(record, key) {
47792
48624
  }
47793
48625
  return value;
47794
48626
  }
47795
- function stringValue6(record, key) {
48627
+ function stringValue7(record, key) {
47796
48628
  return stringFromUnknown(requiredValue(record, key), `signup ${key}`);
47797
48629
  }
47798
48630
  function optionalStringValue(record, key) {
@@ -47887,17 +48719,17 @@ import { spawn as spawn12, spawnSync as spawnSync7 } from "node:child_process";
47887
48719
  import {
47888
48720
  existsSync as existsSync16,
47889
48721
  constants as fsConstants,
47890
- mkdirSync as mkdirSync14,
48722
+ mkdirSync as mkdirSync15,
47891
48723
  mkdtempSync as mkdtempSync5,
47892
- readFileSync as readFileSync20,
48724
+ readFileSync as readFileSync21,
47893
48725
  readdirSync as readdirSync5,
47894
- rmSync as rmSync5,
48726
+ rmSync as rmSync6,
47895
48727
  statSync as statSync4,
47896
- writeFileSync as writeFileSync13
48728
+ writeFileSync as writeFileSync15
47897
48729
  } from "node:fs";
47898
48730
  import { access } from "node:fs/promises";
47899
- import { homedir as homedir15, tmpdir as tmpdir4 } from "node:os";
47900
- import { delimiter as delimiter3, dirname as dirname16, join as join21, resolve as resolve10 } from "node:path";
48731
+ import { homedir as homedir16, tmpdir as tmpdir4 } from "node:os";
48732
+ import { delimiter as delimiter3, dirname as dirname16, join as join23, resolve as resolve10 } from "node:path";
47901
48733
  import { stdin as defaultStdin, stdout as defaultStdout } from "node:process";
47902
48734
  import { emitKeypressEvents } from "node:readline";
47903
48735
  function signupHelpText() {
@@ -48018,7 +48850,7 @@ function defaultSignupDraftStore(serviceUrl) {
48018
48850
  }
48019
48851
  let parsed;
48020
48852
  try {
48021
- parsed = JSON.parse(readFileSync20(path2, "utf8"));
48853
+ parsed = JSON.parse(readFileSync21(path2, "utf8"));
48022
48854
  } catch (_error) {
48023
48855
  return void 0;
48024
48856
  }
@@ -48028,20 +48860,20 @@ function defaultSignupDraftStore(serviceUrl) {
48028
48860
  return comparableServiceUrl(parsed.serviceUrl) === comparableServiceUrl(serviceUrl) ? parsed : void 0;
48029
48861
  },
48030
48862
  write: (draft) => {
48031
- mkdirSync14(dirname16(path2), { recursive: true });
48032
- writeFileSync13(path2, `${JSON.stringify(draft, null, 2)}
48863
+ mkdirSync15(dirname16(path2), { recursive: true });
48864
+ writeFileSync15(path2, `${JSON.stringify(draft, null, 2)}
48033
48865
  `, {
48034
48866
  encoding: "utf8",
48035
48867
  mode: 384
48036
48868
  });
48037
48869
  },
48038
48870
  clear: () => {
48039
- rmSync5(path2, { force: true });
48871
+ rmSync6(path2, { force: true });
48040
48872
  }
48041
48873
  };
48042
48874
  }
48043
48875
  function defaultSignupDraftPath(serviceUrl) {
48044
- return join21(
48876
+ return join23(
48045
48877
  dirname16(localConfigPath()),
48046
48878
  `signup-draft.${localConfigScopeFileStem(serviceUrl)}.json`
48047
48879
  );
@@ -48076,8 +48908,8 @@ function defaultSignupTaskCacheStore(serviceUrl) {
48076
48908
  }
48077
48909
  }
48078
48910
  };
48079
- mkdirSync14(dirname16(path2), { recursive: true });
48080
- writeFileSync13(path2, `${JSON.stringify(next, null, 2)}
48911
+ mkdirSync15(dirname16(path2), { recursive: true });
48912
+ writeFileSync15(path2, `${JSON.stringify(next, null, 2)}
48081
48913
  `, {
48082
48914
  encoding: "utf8",
48083
48915
  mode: 384
@@ -48086,7 +48918,7 @@ function defaultSignupTaskCacheStore(serviceUrl) {
48086
48918
  };
48087
48919
  }
48088
48920
  function defaultSignupTaskCachePath(serviceUrl) {
48089
- return join21(
48921
+ return join23(
48090
48922
  dirname16(localConfigPath()),
48091
48923
  `signup-task-cache.${localConfigScopeFileStem(serviceUrl)}.json`
48092
48924
  );
@@ -48097,7 +48929,7 @@ function readSignupTaskCache(path2) {
48097
48929
  }
48098
48930
  let parsed;
48099
48931
  try {
48100
- parsed = JSON.parse(readFileSync20(path2, "utf8"));
48932
+ parsed = JSON.parse(readFileSync21(path2, "utf8"));
48101
48933
  } catch (_error) {
48102
48934
  return { version: 1, entries: {} };
48103
48935
  }
@@ -49982,7 +50814,7 @@ function autocompletePathSuggestions(pathInput) {
49982
50814
  try {
49983
50815
  const showHidden = prefix.startsWith(".");
49984
50816
  const currentPath = directoryExists(normalizedInput) ? [normalizedInput.replace(/\/$/, "") || "/"] : [];
49985
- const childPaths = readdirSync5(directoryPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => showHidden || !entry.name.startsWith(".")).map((entry) => join21(directoryPath, entry.name)).map((path2) => ({
50817
+ const childPaths = readdirSync5(directoryPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => showHidden || !entry.name.startsWith(".")).map((entry) => join23(directoryPath, entry.name)).map((path2) => ({
49986
50818
  path: path2,
49987
50819
  score: fuzzyPathSegmentScore(path2.split("/").at(-1) ?? path2, prefix)
49988
50820
  })).filter((candidate) => candidate.score !== void 0).sort((left, right) => {
@@ -50228,7 +51060,7 @@ async function runSignupPreflights(runtime) {
50228
51060
  function defaultPreflightRuntime() {
50229
51061
  return {
50230
51062
  cwd: process.cwd(),
50231
- homeDir: homedir15(),
51063
+ homeDir: homedir16(),
50232
51064
  probeTool,
50233
51065
  readGitEmail,
50234
51066
  discoverCodeRoots,
@@ -50373,13 +51205,13 @@ async function suggestTasksWithCodex(projectPath, retryPolicy) {
50373
51205
  );
50374
51206
  }
50375
51207
  async function runCodexTaskSuggestion2(projectPath, previousResponse, retryPolicy) {
50376
- const tempRoot = mkdtempSync5(join21(tmpdir4(), "linzumi-signup-codex-tasks-"));
50377
- const schemaPath = join21(tempRoot, "task-suggestions.schema.json");
50378
- const outputPath = join21(tempRoot, "task-suggestions.json");
51208
+ const tempRoot = mkdtempSync5(join23(tmpdir4(), "linzumi-signup-codex-tasks-"));
51209
+ const schemaPath = join23(tempRoot, "task-suggestions.schema.json");
51210
+ const outputPath = join23(tempRoot, "task-suggestions.json");
50379
51211
  const model = process.env.LINZUMI_SIGNUP_TASK_MODEL ?? "gpt-5.4-mini";
50380
51212
  const prompt = taskSuggestionPrompt2(previousResponse);
50381
51213
  const codexCommand = await resolveSignupCodexCommand();
50382
- writeFileSync13(
51214
+ writeFileSync15(
50383
51215
  schemaPath,
50384
51216
  `${JSON.stringify(taskSuggestionJsonSchema2(), null, 2)}
50385
51217
  `,
@@ -50400,9 +51232,9 @@ async function runCodexTaskSuggestion2(projectPath, previousResponse, retryPolic
50400
51232
  ),
50401
51233
  retryPolicy
50402
51234
  );
50403
- return readFileSync20(outputPath, "utf8");
51235
+ return readFileSync21(outputPath, "utf8");
50404
51236
  } finally {
50405
- rmSync5(tempRoot, { recursive: true, force: true });
51237
+ rmSync6(tempRoot, { recursive: true, force: true });
50406
51238
  }
50407
51239
  }
50408
51240
  function codexTaskSuggestionProcess2(args) {
@@ -50437,7 +51269,7 @@ function codexTaskSuggestionProcess2(args) {
50437
51269
  function signupCodexTaskSuggestionProcessForTest(args) {
50438
51270
  return codexTaskSuggestionProcess2(args);
50439
51271
  }
50440
- async function resolveSignupCodexCommand(env = process.env, homeDir = homedir15(), executableExists = fileIsExecutable) {
51272
+ async function resolveSignupCodexCommand(env = process.env, homeDir = homedir16(), executableExists = fileIsExecutable) {
50441
51273
  const override = firstConfiguredValue([
50442
51274
  env.LINZUMI_SIGNUP_CODEX_BIN,
50443
51275
  env.LINZUMI_CODEX_BIN
@@ -50492,7 +51324,7 @@ function resolveHomePath(path2, homeDir) {
50492
51324
  return homeDir;
50493
51325
  }
50494
51326
  if (path2.startsWith("~/")) {
50495
- return join21(homeDir, path2.slice(2));
51327
+ return join23(homeDir, path2.slice(2));
50496
51328
  }
50497
51329
  return resolve10(path2);
50498
51330
  }
@@ -50505,9 +51337,9 @@ function commandLooksPathLike(command) {
50505
51337
  }
50506
51338
  function homeManagedCodexCandidates(homeDir) {
50507
51339
  return [
50508
- join21(homeDir, ".volta", "bin", "codex"),
50509
- join21(homeDir, ".local", "bin", "codex"),
50510
- join21(homeDir, "bin", "codex")
51340
+ join23(homeDir, ".volta", "bin", "codex"),
51341
+ join23(homeDir, ".local", "bin", "codex"),
51342
+ join23(homeDir, "bin", "codex")
50511
51343
  ];
50512
51344
  }
50513
51345
  async function firstExecutablePath(paths, executableExists) {
@@ -50522,7 +51354,7 @@ function commandPathCandidates(path2) {
50522
51354
  if (path2 === void 0 || path2.trim() === "") {
50523
51355
  return [];
50524
51356
  }
50525
- return path2.split(delimiter3).filter((entry) => entry.trim() !== "").map((entry) => join21(entry, "codex"));
51357
+ return path2.split(delimiter3).filter((entry) => entry.trim() !== "").map((entry) => join23(entry, "codex"));
50526
51358
  }
50527
51359
  async function fileIsExecutable(path2) {
50528
51360
  try {
@@ -50755,11 +51587,11 @@ function codexPreflightLocation(command, homeDir) {
50755
51587
  switch (command) {
50756
51588
  case "codex":
50757
51589
  return "on PATH";
50758
- case join21(homeDir, ".volta", "bin", "codex"):
51590
+ case join23(homeDir, ".volta", "bin", "codex"):
50759
51591
  return "via Volta";
50760
- case join21(homeDir, ".local", "bin", "codex"):
51592
+ case join23(homeDir, ".local", "bin", "codex"):
50761
51593
  return "via ~/.local/bin";
50762
- case join21(homeDir, "bin", "codex"):
51594
+ case join23(homeDir, "bin", "codex"):
50763
51595
  return "via ~/bin";
50764
51596
  default:
50765
51597
  return "from configured path";
@@ -50918,7 +51750,7 @@ function probeToolWithArgs(command, args, cwd) {
50918
51750
  }
50919
51751
  async function discoverCodeRoots(homeDir) {
50920
51752
  const candidates = ["src", "code", "projects"].map(
50921
- (name) => join21(homeDir, name)
51753
+ (name) => join23(homeDir, name)
50922
51754
  );
50923
51755
  return candidates.filter((path2) => existsSync16(path2)).flatMap((path2) => discoveredProjectNames(path2));
50924
51756
  }
@@ -50972,7 +51804,7 @@ function discoverProjectsFromCurrentDirectory(cwd) {
50972
51804
  }
50973
51805
  function discoverProjectsFromGuessedRoots(homeDir) {
50974
51806
  const guessedRoots = ["src", "code", "projects"].map(
50975
- (name) => join21(homeDir, name)
51807
+ (name) => join23(homeDir, name)
50976
51808
  );
50977
51809
  const projects = guessedRoots.flatMap(
50978
51810
  (root) => discoverProjectsUnderRoot(root)
@@ -51024,25 +51856,25 @@ function looksLikeProject(path2) {
51024
51856
  "pnpm-lock.yaml",
51025
51857
  "yarn.lock",
51026
51858
  "package-lock.json"
51027
- ].some((name) => existsSync16(join21(path2, name)));
51859
+ ].some((name) => existsSync16(join23(path2, name)));
51028
51860
  }
51029
51861
  function detectProjectLanguage(path2) {
51030
- if (existsSync16(join21(path2, "pyproject.toml")) || existsSync16(join21(path2, "requirements.txt"))) {
51862
+ if (existsSync16(join23(path2, "pyproject.toml")) || existsSync16(join23(path2, "requirements.txt"))) {
51031
51863
  return "Python";
51032
51864
  }
51033
- if (existsSync16(join21(path2, "Cargo.toml"))) {
51865
+ if (existsSync16(join23(path2, "Cargo.toml"))) {
51034
51866
  return "Rust";
51035
51867
  }
51036
- if (existsSync16(join21(path2, "go.mod"))) {
51868
+ if (existsSync16(join23(path2, "go.mod"))) {
51037
51869
  return "Go";
51038
51870
  }
51039
- if (existsSync16(join21(path2, "mix.exs"))) {
51871
+ if (existsSync16(join23(path2, "mix.exs"))) {
51040
51872
  return "Elixir";
51041
51873
  }
51042
- if (existsSync16(join21(path2, "tsconfig.json")) || packageJsonMentionsTypeScript(path2)) {
51874
+ if (existsSync16(join23(path2, "tsconfig.json")) || packageJsonMentionsTypeScript(path2)) {
51043
51875
  return "TypeScript";
51044
51876
  }
51045
- if (existsSync16(join21(path2, "package.json"))) {
51877
+ if (existsSync16(join23(path2, "package.json"))) {
51046
51878
  return "JavaScript";
51047
51879
  }
51048
51880
  return "Project";
@@ -51050,7 +51882,7 @@ function detectProjectLanguage(path2) {
51050
51882
  function packageJsonMentionsTypeScript(path2) {
51051
51883
  try {
51052
51884
  const packageJson2 = JSON.parse(
51053
- readFileSync20(join21(path2, "package.json"), "utf8")
51885
+ readFileSync21(join23(path2, "package.json"), "utf8")
51054
51886
  );
51055
51887
  return packageJson2.dependencies?.typescript !== void 0 || packageJson2.devDependencies?.typescript !== void 0;
51056
51888
  } catch {
@@ -51058,11 +51890,11 @@ function packageJsonMentionsTypeScript(path2) {
51058
51890
  }
51059
51891
  }
51060
51892
  function hasGitMetadata(path2) {
51061
- return existsSync16(join21(path2, ".git"));
51893
+ return existsSync16(join23(path2, ".git"));
51062
51894
  }
51063
51895
  function childDirectories(root) {
51064
51896
  try {
51065
- return readdirSync5(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join21(root, entry.name));
51897
+ return readdirSync5(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join23(root, entry.name));
51066
51898
  } catch {
51067
51899
  return [];
51068
51900
  }
@@ -51088,10 +51920,10 @@ function directoryExists(path2) {
51088
51920
  }
51089
51921
  function expandHomePath(path2) {
51090
51922
  if (path2 === "~") {
51091
- return homedir15();
51923
+ return homedir16();
51092
51924
  }
51093
51925
  if (path2.startsWith("~/")) {
51094
- return join21(homedir15(), path2.slice(2));
51926
+ return join23(homedir16(), path2.slice(2));
51095
51927
  }
51096
51928
  return resolve10(path2);
51097
51929
  }
@@ -51181,8 +52013,8 @@ init_onboardingDiscoveryChildProcess();
51181
52013
  init_runner();
51182
52014
  init_claudeCodeSession();
51183
52015
  init_authCache();
51184
- import { existsSync as existsSync17, readFileSync as readFileSync21, realpathSync as realpathSync7 } from "node:fs";
51185
- import { homedir as homedir16 } from "node:os";
52016
+ import { existsSync as existsSync17, readFileSync as readFileSync22, realpathSync as realpathSync7 } from "node:fs";
52017
+ import { homedir as homedir17 } from "node:os";
51186
52018
  import { resolve as resolve11 } from "node:path";
51187
52019
  import { fileURLToPath as fileURLToPath4 } from "node:url";
51188
52020
 
@@ -51277,9 +52109,9 @@ init_kandanTls();
51277
52109
  init_protocol();
51278
52110
  init_json();
51279
52111
  init_defaultUrls();
51280
- import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync17, writeFileSync as writeFileSync10 } from "node:fs";
51281
- import { dirname as dirname14, join as join19 } from "node:path";
51282
- import { homedir as homedir13 } from "node:os";
52112
+ import { existsSync as existsSync14, mkdirSync as mkdirSync13, readFileSync as readFileSync18, writeFileSync as writeFileSync12 } from "node:fs";
52113
+ import { dirname as dirname14, join as join21 } from "node:path";
52114
+ import { homedir as homedir14 } from "node:os";
51283
52115
  async function runAgentCliCommand(args, deps = {
51284
52116
  fetchImpl: fetch,
51285
52117
  stdout: process.stdout,
@@ -51987,7 +52819,7 @@ function agentTokenFile(flags) {
51987
52819
  return flags.get("agent-token-file") ?? defaultAgentTokenFilePath();
51988
52820
  }
51989
52821
  function defaultAgentTokenFilePath() {
51990
- return join19(homedir13(), ".linzumi", "agent-token.json");
52822
+ return join21(homedir14(), ".linzumi", "agent-token.json");
51991
52823
  }
51992
52824
  function normalizedApiUrl(apiUrl) {
51993
52825
  return apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`;
@@ -51996,11 +52828,11 @@ function authorizationHeaders(token) {
51996
52828
  return { authorization: `Bearer ${token}` };
51997
52829
  }
51998
52830
  function readOptionalTextFile(path2) {
51999
- return existsSync14(path2) ? readFileSync17(path2, "utf8") : void 0;
52831
+ return existsSync14(path2) ? readFileSync18(path2, "utf8") : void 0;
52000
52832
  }
52001
52833
  function writeTextFile(path2, content) {
52002
- mkdirSync12(dirname14(path2), { recursive: true });
52003
- writeFileSync10(path2, content);
52834
+ mkdirSync13(dirname14(path2), { recursive: true });
52835
+ writeFileSync12(path2, content);
52004
52836
  }
52005
52837
  function readStoredAgentTokenFile(path2, readTextFile = readOptionalTextFile) {
52006
52838
  const content = readTextFile(path2);
@@ -52089,25 +52921,25 @@ init_runnerLogger();
52089
52921
  import {
52090
52922
  existsSync as existsSync15,
52091
52923
  closeSync as closeSync3,
52092
- mkdirSync as mkdirSync13,
52924
+ mkdirSync as mkdirSync14,
52093
52925
  openSync as openSync4,
52094
- readFileSync as readFileSync18,
52926
+ readFileSync as readFileSync19,
52095
52927
  watch,
52096
- writeFileSync as writeFileSync11
52928
+ writeFileSync as writeFileSync13
52097
52929
  } from "node:fs";
52098
- import { homedir as homedir14 } from "node:os";
52099
- import { dirname as dirname15, join as join20, resolve as resolve9 } from "node:path";
52930
+ import { homedir as homedir15 } from "node:os";
52931
+ import { dirname as dirname15, join as join22, resolve as resolve9 } from "node:path";
52100
52932
  import { execFileSync, spawn as spawn10 } from "node:child_process";
52101
52933
  import { fileURLToPath as fileURLToPath3 } from "node:url";
52102
52934
  var connectedMarkers = ["Connected to Linzumi", "Runner connected:"];
52103
52935
  function commanderStatusDir() {
52104
- return join20(homedir14(), ".linzumi", "commanders");
52936
+ return join22(homedir15(), ".linzumi", "commanders");
52105
52937
  }
52106
52938
  function commanderStatusFile(runnerId, statusDir = commanderStatusDir()) {
52107
- return join20(statusDir, `${safeRunnerId(runnerId)}.json`);
52939
+ return join22(statusDir, `${safeRunnerId(runnerId)}.json`);
52108
52940
  }
52109
52941
  function defaultCommanderLogFile(runnerId) {
52110
- return join20(homedir14(), ".linzumi", "logs", `${safeRunnerId(runnerId)}.log`);
52942
+ return join22(homedir15(), ".linzumi", "logs", `${safeRunnerId(runnerId)}.log`);
52111
52943
  }
52112
52944
  function commanderLogIsConnected(log2) {
52113
52945
  return connectedMarkers.some((marker) => log2.includes(marker));
@@ -52128,8 +52960,8 @@ function startCommanderDaemon(options) {
52128
52960
  "--log-file",
52129
52961
  logFile
52130
52962
  ];
52131
- mkdirSync13(statusDir, { recursive: true });
52132
- mkdirSync13(dirname15(logFile), { recursive: true });
52963
+ mkdirSync14(statusDir, { recursive: true });
52964
+ mkdirSync14(dirname15(logFile), { recursive: true });
52133
52965
  const out = openSync4(logFile, "a");
52134
52966
  const err = openSync4(logFile, "a");
52135
52967
  writeCliAuditEvent(
@@ -52175,7 +53007,7 @@ function startCommanderDaemon(options) {
52175
53007
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
52176
53008
  command: [nodeBin, ...command]
52177
53009
  };
52178
- writeFileSync11(statusFile, `${JSON.stringify(record, null, 2)}
53010
+ writeFileSync13(statusFile, `${JSON.stringify(record, null, 2)}
52179
53011
  `);
52180
53012
  return record;
52181
53013
  }
@@ -52184,12 +53016,12 @@ function commanderDaemonStatus(runnerId, statusDir = commanderStatusDir(), proce
52184
53016
  if (!existsSync15(statusFile)) {
52185
53017
  return { status: "missing", runnerId, statusFile };
52186
53018
  }
52187
- const record = parseRecord(readFileSync18(statusFile, "utf8"));
53019
+ const record = parseRecord(readFileSync19(statusFile, "utf8"));
52188
53020
  return processIsRunning(record.pid) && processMatchesRecord(record, processIdentityReader) ? { status: "running", record } : { status: "stopped", record };
52189
53021
  }
52190
53022
  async function waitForCommanderDaemon(options) {
52191
53023
  const now = options.now ?? (() => Date.now());
52192
- const readTextFile = options.readTextFile ?? ((path2) => existsSync15(path2) ? readFileSync18(path2, "utf8") : void 0);
53024
+ const readTextFile = options.readTextFile ?? ((path2) => existsSync15(path2) ? readFileSync19(path2, "utf8") : void 0);
52193
53025
  const statusImpl = options.statusImpl ?? commanderDaemonStatus;
52194
53026
  const deadline = now() + options.timeoutMs;
52195
53027
  while (now() <= deadline) {
@@ -64221,17 +65053,17 @@ async function runMcpServer(args) {
64221
65053
  const kandanUrl = required(values, "api-url");
64222
65054
  const auth = await resolveMcpAuth({
64223
65055
  kandanUrl,
64224
- explicitToken: stringValue5(values, "token") ?? process.env.LINZUMI_MCP_ACCESS_TOKEN,
64225
- authFilePath: stringValue5(values, "auth-file"),
64226
- delegationAuthFilePath: stringValue5(values, "delegation-auth-file"),
64227
- workspaceSlug: stringValue5(values, "workspace"),
64228
- channelSlug: stringValue5(values, "channel")
65056
+ explicitToken: stringValue6(values, "token") ?? process.env.LINZUMI_MCP_ACCESS_TOKEN,
65057
+ authFilePath: stringValue6(values, "auth-file"),
65058
+ delegationAuthFilePath: stringValue6(values, "delegation-auth-file"),
65059
+ workspaceSlug: stringValue6(values, "workspace"),
65060
+ channelSlug: stringValue6(values, "channel")
64229
65061
  });
64230
- const ownerUsername = stringValue5(values, "owner-username") ?? process.env.LINZUMI_MCP_OWNER_USERNAME;
64231
- const operatingMode = mcpOperatingMode(stringValue5(values, "mode"));
64232
- const toolScope = mcpToolScope(stringValue5(values, "tool-scope"));
64233
- const cwd = stringValue5(values, "cwd") ?? process.cwd();
64234
- const defaultThreadId = stringValue5(values, "thread-id") ?? process.env.LINZUMI_THREAD_RUNNER_KANDAN_THREAD_ID;
65062
+ const ownerUsername = stringValue6(values, "owner-username") ?? process.env.LINZUMI_MCP_OWNER_USERNAME;
65063
+ const operatingMode = mcpOperatingMode(stringValue6(values, "mode"));
65064
+ const toolScope = mcpToolScope(stringValue6(values, "tool-scope"));
65065
+ const cwd = stringValue6(values, "cwd") ?? process.cwd();
65066
+ const defaultThreadId = stringValue6(values, "thread-id") ?? process.env.LINZUMI_THREAD_RUNNER_KANDAN_THREAD_ID;
64235
65067
  const client = createLinzumiMcpApiClient({
64236
65068
  kandanUrl,
64237
65069
  accessToken: auth.accessToken,
@@ -64852,24 +65684,24 @@ function registerEmptyMcpResources(server) {
64852
65684
  async function runMcpConfig(args) {
64853
65685
  const values = strictFlagValues(args);
64854
65686
  const kandanUrl = required(values, "api-url");
64855
- const format = stringValue5(values, "format") ?? "codex";
64856
- const operatingMode = mcpOperatingMode(stringValue5(values, "mode"));
65687
+ const format = stringValue6(values, "format") ?? "codex";
65688
+ const operatingMode = mcpOperatingMode(stringValue6(values, "mode"));
64857
65689
  const token = values.get("include-token") === true ? (await resolveMcpAuth({
64858
65690
  kandanUrl,
64859
- explicitToken: stringValue5(values, "token") ?? process.env.LINZUMI_MCP_ACCESS_TOKEN,
64860
- authFilePath: stringValue5(values, "auth-file"),
64861
- delegationAuthFilePath: stringValue5(values, "delegation-auth-file"),
64862
- workspaceSlug: stringValue5(values, "workspace"),
64863
- channelSlug: stringValue5(values, "channel")
65691
+ explicitToken: stringValue6(values, "token") ?? process.env.LINZUMI_MCP_ACCESS_TOKEN,
65692
+ authFilePath: stringValue6(values, "auth-file"),
65693
+ delegationAuthFilePath: stringValue6(values, "delegation-auth-file"),
65694
+ workspaceSlug: stringValue6(values, "workspace"),
65695
+ channelSlug: stringValue6(values, "channel")
64864
65696
  })).accessToken : void 0;
64865
65697
  const config = linzumiMcpServerConfig({
64866
- command: stringValue5(values, "command"),
65698
+ command: stringValue6(values, "command"),
64867
65699
  kandanUrl,
64868
65700
  accessToken: token,
64869
- delegationAuthFilePath: stringValue5(values, "delegation-auth-file"),
64870
- ownerUsername: stringValue5(values, "owner-username") ?? process.env.LINZUMI_MCP_OWNER_USERNAME,
65701
+ delegationAuthFilePath: stringValue6(values, "delegation-auth-file"),
65702
+ ownerUsername: stringValue6(values, "owner-username") ?? process.env.LINZUMI_MCP_OWNER_USERNAME,
64871
65703
  operatingMode,
64872
- toolScope: mcpToolScope(stringValue5(values, "tool-scope"))
65704
+ toolScope: mcpToolScope(stringValue6(values, "tool-scope"))
64873
65705
  });
64874
65706
  switch (format) {
64875
65707
  case "codex":
@@ -64887,19 +65719,19 @@ async function runMcpDoctor(args) {
64887
65719
  const kandanUrl = required(values, "api-url");
64888
65720
  const auth = await resolveMcpAuth({
64889
65721
  kandanUrl,
64890
- explicitToken: stringValue5(values, "token") ?? process.env.LINZUMI_MCP_ACCESS_TOKEN,
64891
- authFilePath: stringValue5(values, "auth-file"),
64892
- delegationAuthFilePath: stringValue5(values, "delegation-auth-file"),
64893
- workspaceSlug: stringValue5(values, "workspace"),
64894
- channelSlug: stringValue5(values, "channel")
65722
+ explicitToken: stringValue6(values, "token") ?? process.env.LINZUMI_MCP_ACCESS_TOKEN,
65723
+ authFilePath: stringValue6(values, "auth-file"),
65724
+ delegationAuthFilePath: stringValue6(values, "delegation-auth-file"),
65725
+ workspaceSlug: stringValue6(values, "workspace"),
65726
+ channelSlug: stringValue6(values, "channel")
64895
65727
  });
64896
65728
  switch (auth.mode) {
64897
65729
  case "local-runner": {
64898
65730
  const ok = await validateLocalRunnerToken({
64899
65731
  kandanUrl,
64900
65732
  accessToken: auth.accessToken,
64901
- workspaceSlug: stringValue5(values, "workspace"),
64902
- channelSlug: stringValue5(values, "channel")
65733
+ workspaceSlug: stringValue6(values, "workspace"),
65734
+ channelSlug: stringValue6(values, "channel")
64903
65735
  });
64904
65736
  if (!ok) {
64905
65737
  throw new Error("Linzumi MCP auth validation failed");
@@ -64911,7 +65743,7 @@ async function runMcpDoctor(args) {
64911
65743
  kandanUrl,
64912
65744
  accessToken: auth.accessToken,
64913
65745
  authMode: auth.mode,
64914
- operatingMode: mcpOperatingMode(stringValue5(values, "mode"))
65746
+ operatingMode: mcpOperatingMode(stringValue6(values, "mode"))
64915
65747
  });
64916
65748
  await client.validateAuth();
64917
65749
  break;
@@ -64982,7 +65814,7 @@ function strictFlagValues(args) {
64982
65814
  }
64983
65815
  return values;
64984
65816
  }
64985
- function stringValue5(values, key) {
65817
+ function stringValue6(values, key) {
64986
65818
  const value = values.get(key);
64987
65819
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
64988
65820
  }
@@ -65009,7 +65841,7 @@ function mcpToolScope(value) {
65009
65841
  }
65010
65842
  }
65011
65843
  function required(values, key) {
65012
- const value = stringValue5(values, key);
65844
+ const value = stringValue6(values, key);
65013
65845
  if (value === void 0) {
65014
65846
  throw new Error(`--${key} is required`);
65015
65847
  }
@@ -65635,11 +66467,11 @@ function runHelloCommand(args) {
65635
66467
  process.stdout.write(helloHelpText());
65636
66468
  return;
65637
66469
  }
65638
- const rootPath = stringValue7(values, "dir");
65639
- const parentDir = stringValue7(values, "parent-dir");
65640
- const name = stringValue7(values, "name");
66470
+ const rootPath = stringValue8(values, "dir");
66471
+ const parentDir = stringValue8(values, "parent-dir");
66472
+ const name = stringValue8(values, "name");
65641
66473
  const port = tcpPortValue(values, "port");
65642
- const host = stringValue7(values, "host");
66474
+ const host = stringValue8(values, "host");
65643
66475
  const project = createHelloLinzumiProject({
65644
66476
  ...rootPath === void 0 ? {} : { rootPath },
65645
66477
  ...parentDir === void 0 ? {} : { parentDir: resolveUserPath(parentDir) },
@@ -65779,8 +66611,8 @@ async function runCommanderDaemonCommand(args) {
65779
66611
  runnerId,
65780
66612
  cwd,
65781
66613
  args: stripDaemonSupervisorFlags(flagArgs),
65782
- logFile: stringValue7(values, "log-file"),
65783
- statusDir: stringValue7(values, "status-dir")
66614
+ logFile: stringValue8(values, "log-file"),
66615
+ statusDir: stringValue8(values, "status-dir")
65784
66616
  });
65785
66617
  process.stdout.write("commander_status: daemon_started\n");
65786
66618
  process.stdout.write(`runner_id: ${record.runnerId}
@@ -65801,7 +66633,7 @@ async function runCommanderDaemonCommand(args) {
65801
66633
  const runnerId = ensureLocalRunnerIdForLinzumiUrl(kandanUrl);
65802
66634
  const status = commanderDaemonStatus(
65803
66635
  runnerId,
65804
- stringValue7(values, "status-dir")
66636
+ stringValue8(values, "status-dir")
65805
66637
  );
65806
66638
  process.stdout.write(`${JSON.stringify(status)}
65807
66639
  `);
@@ -65815,7 +66647,7 @@ async function runCommanderDaemonCommand(args) {
65815
66647
  const result = await waitForCommanderDaemon({
65816
66648
  runnerId,
65817
66649
  timeoutMs,
65818
- statusDir: stringValue7(values, "status-dir")
66650
+ statusDir: stringValue8(values, "status-dir")
65819
66651
  });
65820
66652
  if (result.ok) {
65821
66653
  process.stdout.write("commander_status: connected\n");
@@ -65833,7 +66665,7 @@ async function runCommanderDaemonCommand(args) {
65833
66665
  const runnerId = ensureLocalRunnerIdForLinzumiUrl(kandanUrl);
65834
66666
  const status = stopCommanderDaemon(
65835
66667
  runnerId,
65836
- stringValue7(values, "status-dir")
66668
+ stringValue8(values, "status-dir")
65837
66669
  );
65838
66670
  process.stdout.write(`${JSON.stringify(status)}
65839
66671
  `);
@@ -65862,13 +66694,13 @@ async function runAuthCommand(args) {
65862
66694
  kandanUrl,
65863
66695
  workspaceSlug: target?.workspaceSlug,
65864
66696
  channelSlug: target?.channelSlug,
65865
- callbackHost: stringValue7(values, "oauth-callback-host")
66697
+ callbackHost: stringValue8(values, "oauth-callback-host")
65866
66698
  });
65867
66699
  const cached = writeCachedLocalRunnerToken({
65868
66700
  kandanUrl,
65869
66701
  accessToken: token.accessToken,
65870
66702
  expiresInSeconds: token.expiresInSeconds,
65871
- authFilePath: stringValue7(values, "auth-file")
66703
+ authFilePath: stringValue8(values, "auth-file")
65872
66704
  });
65873
66705
  process.stdout.write(
65874
66706
  `Saved Linzumi local runner auth for ${cached.kandanBaseUrl}
@@ -65888,7 +66720,7 @@ async function runPublishTokenCommand(args) {
65888
66720
  const token = await acquireLocalRunnerTokenDetails({
65889
66721
  kandanUrl,
65890
66722
  purpose: "persisted_documents_publish",
65891
- callbackHost: stringValue7(values, "oauth-callback-host")
66723
+ callbackHost: stringValue8(values, "oauth-callback-host")
65892
66724
  });
65893
66725
  process.stdout.write(`${token.accessToken}
65894
66726
  `);
@@ -65936,11 +66768,11 @@ async function parseStartRunnerArgs(args, deps = {
65936
66768
  const requestedCwd = resolveUserPath(cwdArg ?? process.cwd());
65937
66769
  const cwd = assertConfiguredAllowedCwds([requestedCwd])[0] ?? requestedCwd;
65938
66770
  const explicitAllowedCwds = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(
65939
- parseAllowedCwdList(stringValue7(values, "allowed-cwd"))
66771
+ parseAllowedCwdList(stringValue8(values, "allowed-cwd"))
65940
66772
  ) : [];
65941
66773
  const allowedCwds = Array.from(/* @__PURE__ */ new Set([cwd, ...explicitAllowedCwds]));
65942
- const requestedCodexBin = stringValue7(values, "codex-bin") ?? "codex";
65943
- const customCodeServerBin = stringValue7(values, "code-server-bin");
66774
+ const requestedCodexBin = stringValue8(values, "codex-bin") ?? "codex";
66775
+ const customCodeServerBin = stringValue8(values, "code-server-bin");
65944
66776
  const onboardingDiscovery = values.get("no-onboarding-discovery") === true ? void 0 : "start";
65945
66777
  const initialDependencyStatus = await deps.buildDependencyStatus({
65946
66778
  cwd,
@@ -65949,9 +66781,9 @@ async function parseStartRunnerArgs(args, deps = {
65949
66781
  });
65950
66782
  assertRunnerConnectionDependencies(initialDependencyStatus);
65951
66783
  const codexBin = initialDependencyStatus.codex.command;
65952
- const explicitToken = stringValue7(values, "token");
65953
- const authFilePath = stringValue7(values, "auth-file");
65954
- const callbackHost = stringValue7(values, "oauth-callback-host");
66784
+ const explicitToken = stringValue8(values, "token");
66785
+ const authFilePath = stringValue8(values, "auth-file");
66786
+ const callbackHost = stringValue8(values, "oauth-callback-host");
65955
66787
  const reportRejectedCachedToken = (outcome) => {
65956
66788
  process.stderr.write(`${unusableCachedTokenNotice(outcome)}
65957
66789
  `);
@@ -66006,14 +66838,14 @@ async function parseStartRunnerArgs(args, deps = {
66006
66838
  workspaceSlug: target.workspaceSlug,
66007
66839
  cwd,
66008
66840
  codexBin,
66009
- codexUrl: stringValue7(values, "codex-url"),
66841
+ codexUrl: stringValue8(values, "codex-url"),
66010
66842
  launchSource: electronAutoConnectLaunchSource(),
66011
66843
  launchTui: values.get("launch-tui") === true,
66012
66844
  fast: values.get("fast") === true,
66013
- logFile: stringValue7(values, "log-file"),
66845
+ logFile: stringValue8(values, "log-file"),
66014
66846
  allowedCwds,
66015
66847
  allowedForwardPorts: parseAllowedPortList(
66016
- stringValue7(values, "forward-port")
66848
+ stringValue8(values, "forward-port")
66017
66849
  ),
66018
66850
  codeServerBin: editorRuntime.codeServerBin,
66019
66851
  editorRuntime: editorRuntime.runtime,
@@ -66025,12 +66857,12 @@ async function parseStartRunnerArgs(args, deps = {
66025
66857
  channelSession: {
66026
66858
  workspaceSlug: target.workspaceSlug,
66027
66859
  channelSlug: target.channelSlug,
66028
- kandanThreadId: stringValue7(values, "linzumi-thread-id"),
66029
- listenUser: stringValue7(values, "listen-user") ?? defaultListenUserFromToken(targetToken),
66030
- model: stringValue7(values, "model"),
66031
- reasoningEffort: stringValue7(values, "reasoning-effort"),
66032
- sandbox: stringValue7(values, "sandbox"),
66033
- approvalPolicy: stringValue7(values, "approval-policy"),
66860
+ kandanThreadId: stringValue8(values, "linzumi-thread-id"),
66861
+ listenUser: stringValue8(values, "listen-user") ?? defaultListenUserFromToken(targetToken),
66862
+ model: stringValue8(values, "model"),
66863
+ reasoningEffort: stringValue8(values, "reasoning-effort"),
66864
+ sandbox: stringValue8(values, "sandbox"),
66865
+ approvalPolicy: stringValue8(values, "approval-policy"),
66034
66866
  allowPortForwardingByDefault: true,
66035
66867
  streamFlushMs: positiveIntegerValue2(values, "stream-flush-ms")
66036
66868
  }
@@ -66055,32 +66887,32 @@ async function parseAgentRunnerArgs(args, deps = {
66055
66887
  "linzumi commander accepts either <folder> or --cwd, not both"
66056
66888
  );
66057
66889
  }
66058
- const tokenFilePath = stringValue7(values, "agent-token-file") ?? defaultAgentTokenFilePath();
66890
+ const tokenFilePath = stringValue8(values, "agent-token-file") ?? defaultAgentTokenFilePath();
66059
66891
  const tokenFile = readStoredAgentTokenFile(tokenFilePath, deps.readTextFile);
66060
66892
  const channelSlug = tokenFile.channelId;
66061
66893
  rejectWorkspaceCommanderThreadFlags(values, channelSlug);
66062
66894
  const channelSession = channelSlug === void 0 ? void 0 : {
66063
66895
  workspaceSlug: tokenFile.workspaceId,
66064
66896
  channelSlug,
66065
- kandanThreadId: stringValue7(values, "linzumi-thread-id"),
66066
- listenUser: stringValue7(values, "listen-user") ?? requiredStoredOwnerUsername(tokenFile.ownerUsername),
66067
- model: stringValue7(values, "model"),
66068
- reasoningEffort: stringValue7(values, "reasoning-effort"),
66069
- sandbox: stringValue7(values, "sandbox"),
66070
- approvalPolicy: stringValue7(values, "approval-policy"),
66897
+ kandanThreadId: stringValue8(values, "linzumi-thread-id"),
66898
+ listenUser: stringValue8(values, "listen-user") ?? requiredStoredOwnerUsername(tokenFile.ownerUsername),
66899
+ model: stringValue8(values, "model"),
66900
+ reasoningEffort: stringValue8(values, "reasoning-effort"),
66901
+ sandbox: stringValue8(values, "sandbox"),
66902
+ approvalPolicy: stringValue8(values, "approval-policy"),
66071
66903
  allowPortForwardingByDefault: true,
66072
66904
  streamFlushMs: positiveIntegerValue2(values, "stream-flush-ms")
66073
66905
  };
66074
66906
  const kandanUrl = kandanUrlValue(values) ?? agentApiUrlToKandanUrl(tokenFile.apiUrl);
66075
- const requestedCwdValue = cwdArg ?? stringValue7(values, "cwd");
66907
+ const requestedCwdValue = cwdArg ?? stringValue8(values, "cwd");
66076
66908
  const requestedCwd = resolveUserPath(requestedCwdValue ?? process.cwd());
66077
66909
  const configuredAllowedCwds2 = requestedCwdValue === void 0 && !values.has("allowed-cwd") ? readConfiguredAllowedCwdDetailsForLinzumiUrl(kandanUrl) : { allowedCwds: [], missingAllowedCwds: [] };
66078
66910
  const allowedCwds = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(
66079
- parseAllowedCwdList(stringValue7(values, "allowed-cwd"))
66911
+ parseAllowedCwdList(stringValue8(values, "allowed-cwd"))
66080
66912
  ) : requestedCwdValue === void 0 ? configuredAllowedCwds2.allowedCwds.length > 0 ? [...configuredAllowedCwds2.allowedCwds] : assertConfiguredAllowedCwds([requestedCwd]) : assertConfiguredAllowedCwds([requestedCwd]);
66081
66913
  const cwd = allowedCwds[0] ?? requestedCwd;
66082
- const requestedCodexBin = stringValue7(values, "codex-bin") ?? "codex";
66083
- const customCodeServerBin = stringValue7(values, "code-server-bin");
66914
+ const requestedCodexBin = stringValue8(values, "codex-bin") ?? "codex";
66915
+ const customCodeServerBin = stringValue8(values, "code-server-bin");
66084
66916
  const initialDependencyStatus = await deps.buildDependencyStatus({
66085
66917
  cwd,
66086
66918
  codexBin: requestedCodexBin,
@@ -66111,15 +66943,15 @@ async function parseAgentRunnerArgs(args, deps = {
66111
66943
  workspaceSlug: tokenFile.workspaceId,
66112
66944
  cwd,
66113
66945
  codexBin,
66114
- codexUrl: stringValue7(values, "codex-url"),
66946
+ codexUrl: stringValue8(values, "codex-url"),
66115
66947
  launchSource: electronAutoConnectLaunchSource(),
66116
66948
  launchTui: values.get("launch-tui") === true,
66117
66949
  fast: values.get("fast") === true,
66118
- logFile: stringValue7(values, "log-file"),
66950
+ logFile: stringValue8(values, "log-file"),
66119
66951
  allowedCwds,
66120
66952
  missingAllowedCwds: configuredAllowedCwds2.missingAllowedCwds,
66121
66953
  allowedForwardPorts: parseAllowedPortList(
66122
- stringValue7(values, "forward-port")
66954
+ stringValue8(values, "forward-port")
66123
66955
  ),
66124
66956
  codeServerBin: editorRuntime.codeServerBin,
66125
66957
  editorRuntime: editorRuntime.runtime,
@@ -66131,7 +66963,7 @@ async function parseAgentRunnerArgs(args, deps = {
66131
66963
  };
66132
66964
  }
66133
66965
  function readAgentTokenTextFile(path2) {
66134
- return existsSync17(path2) ? readFileSync21(path2, "utf8") : void 0;
66966
+ return existsSync17(path2) ? readFileSync22(path2, "utf8") : void 0;
66135
66967
  }
66136
66968
  function rejectAgentRunnerTargetingFlags(values) {
66137
66969
  const unsupportedFlags = [
@@ -66233,16 +67065,16 @@ async function parseRunnerArgs(args, deps = {
66233
67065
  process.exit(0);
66234
67066
  }
66235
67067
  rejectConnectChannelFlags(values);
66236
- const workspaceSlug = stringValue7(values, "workspace");
67068
+ const workspaceSlug = stringValue8(values, "workspace");
66237
67069
  const kandanUrl = kandanUrlValue(values) ?? defaultLinzumiWebSocketUrl;
66238
- const cwd = stringValue7(values, "cwd") ?? process.cwd();
67070
+ const cwd = stringValue8(values, "cwd") ?? process.cwd();
66239
67071
  const cwdAllowedCwds = assertConfiguredAllowedCwds([cwd]);
66240
67072
  const localConfiguredAllowedCwds = values.has("allowed-cwd") ? { allowedCwds: [], missingAllowedCwds: [] } : readConfiguredAllowedCwdDetailsForLinzumiUrl(kandanUrl);
66241
67073
  const configuredAllowedCwds2 = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(
66242
- parseAllowedCwdList(stringValue7(values, "allowed-cwd"))
67074
+ parseAllowedCwdList(stringValue8(values, "allowed-cwd"))
66243
67075
  ) : [...localConfiguredAllowedCwds.allowedCwds];
66244
- const requestedCodexBin = stringValue7(values, "codex-bin") ?? "codex";
66245
- const customCodeServerBin = stringValue7(values, "code-server-bin");
67076
+ const requestedCodexBin = stringValue8(values, "codex-bin") ?? "codex";
67077
+ const customCodeServerBin = stringValue8(values, "code-server-bin");
66246
67078
  const onboardingDiscovery = values.get("no-onboarding-discovery") === true ? void 0 : "start";
66247
67079
  const initialDependencyStatus = await deps.buildDependencyStatus({
66248
67080
  cwd,
@@ -66251,13 +67083,13 @@ async function parseRunnerArgs(args, deps = {
66251
67083
  });
66252
67084
  assertRunnerConnectionDependencies(initialDependencyStatus);
66253
67085
  const codexBin = initialDependencyStatus.codex.command;
66254
- const explicitToken = stringValue7(values, "token");
67086
+ const explicitToken = stringValue8(values, "token");
66255
67087
  const token = await deps.resolveToken({
66256
67088
  kandanUrl,
66257
67089
  explicitToken,
66258
67090
  workspaceSlug,
66259
- authFilePath: stringValue7(values, "auth-file"),
66260
- callbackHost: stringValue7(values, "oauth-callback-host"),
67091
+ authFilePath: stringValue8(values, "auth-file"),
67092
+ callbackHost: stringValue8(values, "oauth-callback-host"),
66261
67093
  requiredScopes: onboardingDiscovery === "start" ? onboardingDiscoveryRequiredScopes : void 0,
66262
67094
  reportRejectedCachedToken: (outcome) => {
66263
67095
  process.stderr.write(`${unusableCachedTokenNotice(outcome)}
@@ -66286,17 +67118,17 @@ async function parseRunnerArgs(args, deps = {
66286
67118
  ),
66287
67119
  cwd,
66288
67120
  codexBin,
66289
- codexUrl: stringValue7(values, "codex-url"),
67121
+ codexUrl: stringValue8(values, "codex-url"),
66290
67122
  launchSource: electronAutoConnectLaunchSource(),
66291
67123
  launchTui: values.get("launch-tui") === true,
66292
67124
  fast: values.get("fast") === true,
66293
- logFile: stringValue7(values, "log-file"),
67125
+ logFile: stringValue8(values, "log-file"),
66294
67126
  allowedCwds: Array.from(
66295
67127
  /* @__PURE__ */ new Set([...cwdAllowedCwds, ...configuredAllowedCwds2])
66296
67128
  ),
66297
67129
  missingAllowedCwds: localConfiguredAllowedCwds.missingAllowedCwds,
66298
67130
  allowedForwardPorts: parseAllowedPortList(
66299
- stringValue7(values, "forward-port")
67131
+ stringValue8(values, "forward-port")
66300
67132
  ),
66301
67133
  codeServerBin: editorRuntime.codeServerBin,
66302
67134
  editorRuntime: editorRuntime.runtime,
@@ -66311,10 +67143,10 @@ async function parseRunnerArgs(args, deps = {
66311
67143
  }
66312
67144
  function runnerRuntimeDefaultsFromValues(values) {
66313
67145
  return {
66314
- model: stringValue7(values, "model"),
66315
- reasoningEffort: stringValue7(values, "reasoning-effort"),
66316
- approvalPolicy: stringValue7(values, "approval-policy"),
66317
- sandbox: stringValue7(values, "sandbox"),
67146
+ model: stringValue8(values, "model"),
67147
+ reasoningEffort: stringValue8(values, "reasoning-effort"),
67148
+ approvalPolicy: stringValue8(values, "approval-policy"),
67149
+ sandbox: stringValue8(values, "sandbox"),
66318
67150
  allowPortForwardingByDefault: true
66319
67151
  };
66320
67152
  }
@@ -66331,8 +67163,8 @@ function isHelpOrVersionInvocation(args) {
66331
67163
  return args.some((arg) => ["--help", "-h", "--version"].includes(arg));
66332
67164
  }
66333
67165
  function kandanUrlValue(values) {
66334
- const apiUrl = stringValue7(values, "api-url");
66335
- const linzumiUrl = stringValue7(values, "linzumi-url");
67166
+ const apiUrl = stringValue8(values, "api-url");
67167
+ const linzumiUrl = stringValue8(values, "linzumi-url");
66336
67168
  if (apiUrl !== void 0 && linzumiUrl !== void 0 && apiUrl !== linzumiUrl) {
66337
67169
  throw new Error("use only one of --api-url or --linzumi-url");
66338
67170
  }
@@ -66441,10 +67273,10 @@ function rejectStartTargetingFlags(values) {
66441
67273
  }
66442
67274
  function resolveUserPath(pathValue) {
66443
67275
  if (pathValue === "~") {
66444
- return homedir16();
67276
+ return homedir17();
66445
67277
  }
66446
67278
  if (pathValue.startsWith("~/")) {
66447
- return resolve11(homedir16(), pathValue.slice(2));
67279
+ return resolve11(homedir17(), pathValue.slice(2));
66448
67280
  }
66449
67281
  return resolve11(pathValue);
66450
67282
  }
@@ -66471,8 +67303,8 @@ function rejectConnectChannelFlags(values) {
66471
67303
  );
66472
67304
  }
66473
67305
  function parseOptionalChannelTarget(values) {
66474
- const channel = stringValue7(values, "channel");
66475
- const workspace = stringValue7(values, "workspace");
67306
+ const channel = stringValue8(values, "channel");
67307
+ const workspace = stringValue8(values, "workspace");
66476
67308
  if (channel === void 0) {
66477
67309
  if (workspace === void 0) {
66478
67310
  return void 0;
@@ -66506,9 +67338,9 @@ function withLocalMachineId(options) {
66506
67338
  function parseThreadCodexWorkerArgs(args) {
66507
67339
  const values = strictFlagValues2(args);
66508
67340
  const kandanUrl = kandanUrlValue(values) ?? defaultLinzumiWebSocketUrl;
66509
- const cwd = stringValue7(values, "cwd") ?? process.cwd();
67341
+ const cwd = stringValue8(values, "cwd") ?? process.cwd();
66510
67342
  const configuredAllowedCwds2 = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(
66511
- parseAllowedCwdList(stringValue7(values, "allowed-cwd"))
67343
+ parseAllowedCwdList(stringValue8(values, "allowed-cwd"))
66512
67344
  ) : assertConfiguredAllowedCwds([cwd]);
66513
67345
  const kandanThreadId = requiredThreadRunnerKandanThreadId();
66514
67346
  const token = requiredThreadRunnerToken();
@@ -66518,17 +67350,17 @@ function parseThreadCodexWorkerArgs(args) {
66518
67350
  runnerId: `thread-codex-worker:${kandanThreadId}`,
66519
67351
  machineId: void 0,
66520
67352
  runnerLockConfigPath: void 0,
66521
- workspaceSlug: stringValue7(values, "workspace"),
67353
+ workspaceSlug: stringValue8(values, "workspace"),
66522
67354
  cwd,
66523
- codexBin: stringValue7(values, "codex-bin") ?? "codex",
67355
+ codexBin: stringValue8(values, "codex-bin") ?? "codex",
66524
67356
  codexUrl: void 0,
66525
67357
  launchTui: false,
66526
67358
  fast: values.get("fast") === true ? true : void 0,
66527
- logFile: stringValue7(values, "log-file"),
67359
+ logFile: stringValue8(values, "log-file"),
66528
67360
  allowedCwds: configuredAllowedCwds2.allowedCwds,
66529
67361
  missingAllowedCwds: configuredAllowedCwds2.missingAllowedCwds,
66530
67362
  allowedForwardPorts: parseAllowedPortList(
66531
- stringValue7(values, "forward-port")
67363
+ stringValue8(values, "forward-port")
66532
67364
  ),
66533
67365
  codeServerBin: void 0,
66534
67366
  editorRuntime: void 0,
@@ -66543,25 +67375,27 @@ function parseThreadCodexWorkerArgs(args) {
66543
67375
  };
66544
67376
  }
66545
67377
  function threadRunnerCodexModelProvider(values) {
66546
- const modelProvider = stringValue7(values, "model-provider");
67378
+ const modelProvider = stringValue8(values, "model-provider");
66547
67379
  if (modelProvider === void 0) {
66548
67380
  return void 0;
66549
67381
  }
66550
- if (modelProvider !== "wafer") {
67382
+ if (modelProvider !== "wafer" && modelProvider !== "openai-proxy") {
66551
67383
  throw new Error(`unsupported --model-provider: ${modelProvider}`);
66552
67384
  }
66553
- const llmProxyBaseUrl = stringValue7(values, "llm-proxy-base-url");
67385
+ const llmProxyBaseUrl = stringValue8(values, "llm-proxy-base-url");
66554
67386
  const llmProxyToken = process.env.LINZUMI_LLM_PROXY_TOKEN?.trim();
66555
67387
  if (llmProxyBaseUrl === void 0) {
66556
- throw new Error("--model-provider wafer requires --llm-proxy-base-url");
67388
+ throw new Error(
67389
+ `--model-provider ${modelProvider} requires --llm-proxy-base-url`
67390
+ );
66557
67391
  }
66558
67392
  if (llmProxyToken === void 0 || llmProxyToken === "") {
66559
67393
  throw new Error(
66560
- "--model-provider wafer requires the LINZUMI_LLM_PROXY_TOKEN env credential"
67394
+ `--model-provider ${modelProvider} requires the LINZUMI_LLM_PROXY_TOKEN env credential`
66561
67395
  );
66562
67396
  }
66563
67397
  return {
66564
- provider: "wafer",
67398
+ provider: modelProvider,
66565
67399
  llmProxyBaseUrl,
66566
67400
  llmProxyToken
66567
67401
  };
@@ -66583,13 +67417,13 @@ function requiredThreadRunnerToken() {
66583
67417
  return token;
66584
67418
  }
66585
67419
  function required2(values, key) {
66586
- const value = stringValue7(values, key);
67420
+ const value = stringValue8(values, key);
66587
67421
  if (value === void 0) {
66588
67422
  throw new Error(`missing --${key}`);
66589
67423
  }
66590
67424
  return value;
66591
67425
  }
66592
- function stringValue7(values, key) {
67426
+ function stringValue8(values, key) {
66593
67427
  const value = values.get(key);
66594
67428
  if (typeof value === "string" && value.trim() !== "") {
66595
67429
  return value;
@@ -66597,7 +67431,7 @@ function stringValue7(values, key) {
66597
67431
  return void 0;
66598
67432
  }
66599
67433
  function positiveIntegerValue2(values, key) {
66600
- const value = stringValue7(values, key);
67434
+ const value = stringValue8(values, key);
66601
67435
  if (value === void 0) {
66602
67436
  return void 0;
66603
67437
  }
@@ -66608,7 +67442,7 @@ function positiveIntegerValue2(values, key) {
66608
67442
  throw new Error(`--${key} must be a positive integer`);
66609
67443
  }
66610
67444
  function tcpPortValue(values, key) {
66611
- const value = stringValue7(values, key);
67445
+ const value = stringValue8(values, key);
66612
67446
  if (value === void 0) {
66613
67447
  return void 0;
66614
67448
  }