@linzumi/cli 0.0.83-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 +897 -333
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11564,6 +11564,21 @@ function createClaudeCodeSessionPipeline(host) {
11564
11564
  handleToolResult(ensureTurn(), event);
11565
11565
  return;
11566
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
+ }
11567
11582
  case "command_output": {
11568
11583
  const turn = ensureTurn();
11569
11584
  const item = {
@@ -11945,13 +11960,304 @@ var init_claudeCodePlanMirror = __esm({
11945
11960
  }
11946
11961
  });
11947
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
+
11948
12180
  // src/claudeCodeSession.ts
11949
12181
  import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
11950
12182
  import { homedir as homedir5 } from "node:os";
11951
- import { join as join6 } from "node:path";
12183
+ import { join as join7 } from "node:path";
11952
12184
  function claudeCodeSettingSources() {
11953
12185
  return ["user", "project", "local"];
11954
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
+ }
11955
12261
  function parseClaudeCodeRateLimitInfo(info) {
11956
12262
  if (info === void 0) {
11957
12263
  return void 0;
@@ -12051,7 +12357,7 @@ async function probeClaudeCodeAvailability(args) {
12051
12357
  }
12052
12358
  }
12053
12359
  function hasClaudeCodeAuthHint(env, deps) {
12054
- const configDir = env.CLAUDE_CONFIG_DIR ?? join6(deps.homeDir, ".claude");
12360
+ const configDir = env.CLAUDE_CONFIG_DIR ?? join7(deps.homeDir, ".claude");
12055
12361
  return hasAnthropicCredentialEnv(env) || hasClaudeCloudProviderEnv(env) || hasClaudeCodeFileCredential(configDir, deps) || hasClaudeCodeApiKeyHelper(configDir, deps) || hasMacClaudeCodeKeychainAnchor(deps);
12056
12362
  }
12057
12363
  function claudeCodePolicyDeferHooks() {
@@ -12086,14 +12392,14 @@ function hasClaudeCloudProviderEnv(env) {
12086
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);
12087
12393
  }
12088
12394
  function hasClaudeCodeFileCredential(configDir, deps) {
12089
- return deps.fileExists(join6(configDir, ".credentials.json")) || deps.fileExists(join6(configDir, ".claude.json")) || deps.fileExists(join6(deps.homeDir, ".claude.json"));
12395
+ return deps.fileExists(join7(configDir, ".credentials.json")) || deps.fileExists(join7(configDir, ".claude.json")) || deps.fileExists(join7(deps.homeDir, ".claude.json"));
12090
12396
  }
12091
12397
  function hasClaudeCodeApiKeyHelper(configDir, deps) {
12092
12398
  return [
12093
- join6(configDir, "settings.json"),
12094
- join6(configDir, "settings.local.json"),
12095
- join6(deps.cwd, ".claude", "settings.json"),
12096
- join6(deps.cwd, ".claude", "settings.local.json")
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")
12097
12403
  ].some((path2) => settingsFileHasApiKeyHelper(path2, deps));
12098
12404
  }
12099
12405
  function settingsFileHasApiKeyHelper(path2, deps) {
@@ -12113,9 +12419,9 @@ function hasMacClaudeCodeKeychainAnchor(deps) {
12113
12419
  return false;
12114
12420
  }
12115
12421
  return [
12116
- join6(deps.homeDir, "Library", "Application Support", "claude-cli-nodejs"),
12117
- join6(deps.homeDir, "Library", "Application Support", "Claude"),
12118
- join6(deps.homeDir, "Library", "Preferences", "claude-cli-nodejs")
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")
12119
12425
  ].some((path2) => deps.fileExists(path2));
12120
12426
  }
12121
12427
  function readTextFileIfPresent(path2) {
@@ -12136,6 +12442,7 @@ async function startClaudeCodeSession(options) {
12136
12442
  startedSessionIds: /* @__PURE__ */ new Set(),
12137
12443
  completedTurnCount: 0
12138
12444
  };
12445
+ const streamUsageTracker = createClaudeCodeStreamUsageTracker();
12139
12446
  for await (const message of runner(options)) {
12140
12447
  state.sessionId = state.sessionId ?? extractClaudeSessionId(message);
12141
12448
  const sessionId = extractClaudeSessionId(message) ?? state.sessionId;
@@ -12143,7 +12450,11 @@ async function startClaudeCodeSession(options) {
12143
12450
  state.startedSessionIds.add(sessionId);
12144
12451
  await options.onTranscriptEvent?.({ type: "session_started", sessionId });
12145
12452
  }
12146
- for (const event of transcriptEventsForClaudeMessage(message, sessionId)) {
12453
+ for (const event of transcriptEventsForClaudeMessage(
12454
+ message,
12455
+ sessionId,
12456
+ streamUsageTracker
12457
+ )) {
12147
12458
  if (event.type === "assistant_message") {
12148
12459
  recordClaudeAssistantAggregate(state, event);
12149
12460
  }
@@ -12314,6 +12625,11 @@ async function failClaudeCodeSession(options, sessionId, reason) {
12314
12625
  async function* defaultClaudeCodeRunner(options) {
12315
12626
  const sdk = await import("@anthropic-ai/claude-agent-sdk");
12316
12627
  const prompt = options.streamingInput?.messages ?? options.prompt;
12628
+ const preToolUseMatchers = [
12629
+ ...options.preToolUseHookMatchers ?? [],
12630
+ ...options.canUseTool === void 0 ? claudeCodePolicyDeferHooks().PreToolUse ?? [] : []
12631
+ ];
12632
+ const hooks = preToolUseMatchers.length === 0 ? void 0 : { PreToolUse: preToolUseMatchers };
12317
12633
  const query = sdk.query({
12318
12634
  prompt,
12319
12635
  options: {
@@ -12334,7 +12650,13 @@ async function* defaultClaudeCodeRunner(options) {
12334
12650
  },
12335
12651
  ...options.allowedTools === void 0 ? {} : { allowedTools: [...options.allowedTools] },
12336
12652
  ...options.env === void 0 ? {} : { env: options.env },
12337
- ...options.canUseTool === void 0 ? { hooks: claudeCodePolicyDeferHooks() } : { canUseTool: claudeCodeCanUseTool(options.canUseTool) },
12653
+ ...hooks === void 0 ? {} : { hooks },
12654
+ ...options.canUseTool === void 0 ? {} : {
12655
+ canUseTool: claudeCodeCanUseTool(
12656
+ options.canUseTool,
12657
+ options.wrapApprovedToolInput
12658
+ )
12659
+ },
12338
12660
  ...options.model === void 0 ? {} : { model: options.model }
12339
12661
  // exactOptionalPropertyTypes: the conditional spreads build a union the
12340
12662
  // SDK's Options cannot absorb verbatim; the shape is correct field-wise.
@@ -12425,7 +12747,7 @@ function boundedPositiveInteger(value, fallback, min, max) {
12425
12747
  }
12426
12748
  return value;
12427
12749
  }
12428
- function claudeCodeCanUseTool(handler) {
12750
+ function claudeCodeCanUseTool(handler, wrapApprovedToolInput) {
12429
12751
  return async (toolName2, input, options) => {
12430
12752
  const decision = await handler(
12431
12753
  {
@@ -12436,7 +12758,11 @@ function claudeCodeCanUseTool(handler) {
12436
12758
  description: options.description,
12437
12759
  decisionReason: options.decisionReason,
12438
12760
  blockedPath: options.blockedPath,
12439
- input
12761
+ // Approval prompts render the human-facing command: when the live
12762
+ // Bash output capture wrapped it (PreToolUse updatedInput), show
12763
+ // the original. The SDK still receives the raw input on allow so
12764
+ // the wrapped (live-streaming) command is what executes.
12765
+ input: displayClaudeToolInput(toolName2, input)
12440
12766
  },
12441
12767
  options.signal
12442
12768
  );
@@ -12445,7 +12771,11 @@ function claudeCodeCanUseTool(handler) {
12445
12771
  return {
12446
12772
  behavior: "allow",
12447
12773
  toolUseID: options.toolUseID,
12448
- updatedInput: input
12774
+ // Live Bash output for ask-capable permission modes: the approved
12775
+ // command gains the tee wrapper HERE (it was already prompting,
12776
+ // so wrapping at this point can never add a prompt - see
12777
+ // claudeCodeLiveBashOutput).
12778
+ updatedInput: wrapApprovedToolInput?.(options.toolUseID, toolName2, input) ?? input
12449
12779
  };
12450
12780
  case "deny":
12451
12781
  return {
@@ -12456,6 +12786,17 @@ function claudeCodeCanUseTool(handler) {
12456
12786
  }
12457
12787
  };
12458
12788
  }
12789
+ function displayClaudeToolInput(toolName2, input) {
12790
+ if (toolName2 !== "Bash") {
12791
+ return input;
12792
+ }
12793
+ const command = stringValue(input.command);
12794
+ if (command === void 0) {
12795
+ return input;
12796
+ }
12797
+ const original = claudeLiveBashOriginalCommand(command);
12798
+ return original === command ? input : { ...input, command: original };
12799
+ }
12459
12800
  function extractClaudeSessionId(message) {
12460
12801
  const messageObject = objectValue(message);
12461
12802
  const directSessionId = stringValue(messageObject?.session_id) ?? stringValue(messageObject?.sessionId);
@@ -12492,11 +12833,11 @@ function extractClaudeResultErrorReason(message, subtype) {
12492
12833
  const explicitErrors = arrayValue(message.errors)?.map((error) => stringValue(error)).filter((error) => nonEmptyText(error) !== void 0).join("; ");
12493
12834
  return nonEmptyText(explicitErrors) ?? nonEmptyText(stringValue(message.result)) ?? nonEmptyText(stringValue(message.error)) ?? subtype ?? "error";
12494
12835
  }
12495
- function transcriptEventsForClaudeMessage(message, sessionId) {
12836
+ function transcriptEventsForClaudeMessage(message, sessionId, usageTracker) {
12496
12837
  const messageObject = objectValue(message);
12497
12838
  switch (stringValue(messageObject?.type)) {
12498
12839
  case "stream_event":
12499
- return streamTranscriptEvents(messageObject, sessionId);
12840
+ return streamTranscriptEvents(messageObject, sessionId, usageTracker);
12500
12841
  case "assistant":
12501
12842
  return assistantTranscriptEvents(messageObject, sessionId);
12502
12843
  case "user":
@@ -12513,11 +12854,16 @@ function transcriptEventsForClaudeMessage(message, sessionId) {
12513
12854
  return unknownTranscriptEvent(messageObject, sessionId);
12514
12855
  }
12515
12856
  }
12516
- function streamTranscriptEvents(message, sessionId) {
12857
+ function streamTranscriptEvents(message, sessionId, usageTracker) {
12517
12858
  if (sessionId === void 0) {
12518
12859
  return [];
12519
12860
  }
12520
12861
  const event = objectValue(message?.event);
12862
+ const runningUsage = usageTracker?.observeStreamEvent(event);
12863
+ const usageEvents = runningUsage === void 0 ? [] : [{ type: "usage", sessionId, usage: runningUsage }];
12864
+ return [...usageEvents, ...streamContentEvents(event, message, sessionId)];
12865
+ }
12866
+ function streamContentEvents(event, message, sessionId) {
12521
12867
  switch (stringValue(event?.type)) {
12522
12868
  case "content_block_delta": {
12523
12869
  const delta = objectValue(event?.delta);
@@ -12719,6 +13065,7 @@ var init_claudeCodeSession = __esm({
12719
13065
  "src/claudeCodeSession.ts"() {
12720
13066
  "use strict";
12721
13067
  init_json();
13068
+ init_claudeCodeLiveBashOutput();
12722
13069
  claudeRateLimitWindowLabels = {
12723
13070
  five_hour: "5h window",
12724
13071
  seven_day: "7d window",
@@ -12733,10 +13080,10 @@ var init_claudeCodeSession = __esm({
12733
13080
  import { appendFileSync, openSync as openSync2 } from "node:fs";
12734
13081
  import { createWriteStream } from "node:fs";
12735
13082
  import { homedir as homedir6 } from "node:os";
12736
- import { dirname as dirname3, join as join7 } from "node:path";
12737
- import { mkdirSync as mkdirSync2 } from "node:fs";
13083
+ import { dirname as dirname3, join as join8 } from "node:path";
13084
+ import { mkdirSync as mkdirSync3 } from "node:fs";
12738
13085
  function createRunnerLogger(logFile, consoleReporter) {
12739
- mkdirSync2(dirname3(logFile), { recursive: true });
13086
+ mkdirSync3(dirname3(logFile), { recursive: true });
12740
13087
  const fd = openSync2(logFile, "a");
12741
13088
  const stream = createWriteStream("", { fd, flags: "a", autoClose: true });
12742
13089
  const logger = ((event, payload) => {
@@ -12756,7 +13103,7 @@ function createRunnerLogger(logFile, consoleReporter) {
12756
13103
  function writeCliAuditEvent(event, payload, options = {}) {
12757
13104
  const logFile = options.logFile ?? defaultCliAuditLogFile();
12758
13105
  try {
12759
- mkdirSync2(dirname3(logFile), { recursive: true });
13106
+ mkdirSync3(dirname3(logFile), { recursive: true });
12760
13107
  appendFileSync(
12761
13108
  logFile,
12762
13109
  `${JSON.stringify({
@@ -12774,10 +13121,10 @@ function writeCliAuditEvent(event, payload, options = {}) {
12774
13121
  }
12775
13122
  function defaultCliAuditLogFile() {
12776
13123
  const override = process.env.LINZUMI_CLI_AUDIT_LOG?.trim();
12777
- return override === void 0 || override === "" ? join7(homedir6(), ".linzumi", "logs", "command-events.jsonl") : override;
13124
+ return override === void 0 || override === "" ? join8(homedir6(), ".linzumi", "logs", "command-events.jsonl") : override;
12778
13125
  }
12779
13126
  function defaultRunnerLogFile() {
12780
- return join7(homedir6(), ".linzumi", "logs", "linzumi-runner.log");
13127
+ return join8(homedir6(), ".linzumi", "logs", "linzumi-runner.log");
12781
13128
  }
12782
13129
  function redactForCliLog(value) {
12783
13130
  return redactObject(value);
@@ -13060,7 +13407,10 @@ var init_mcpConfig = __esm({
13060
13407
  import {
13061
13408
  spawn as spawn2
13062
13409
  } from "node:child_process";
13410
+ import { readFileSync as readFileSync6 } from "node:fs";
13063
13411
  import { createServer } from "node:net";
13412
+ import { homedir as homedir7 } from "node:os";
13413
+ import { join as join9 } from "node:path";
13064
13414
  import { WebSocket as NodeWebSocket } from "ws";
13065
13415
  async function chooseLoopbackPort() {
13066
13416
  return new Promise((resolve12, reject) => {
@@ -13277,10 +13627,46 @@ function codexModelProviderConfigArgs(provider) {
13277
13627
  "-c",
13278
13628
  `model_providers.${provider.id}.http_headers.${header}=${JSON.stringify(value)}`
13279
13629
  ]),
13630
+ // env_http_headers values are env var NAMES, not secrets: codex resolves
13631
+ // them from its environment per request, keeping tokens out of argv.
13632
+ ...Object.entries(provider.envHttpHeaders ?? {}).flatMap(
13633
+ ([header, envVar]) => [
13634
+ "-c",
13635
+ `model_providers.${provider.id}.env_http_headers.${header}=${JSON.stringify(envVar)}`
13636
+ ]
13637
+ ),
13280
13638
  "-c",
13281
13639
  `model_provider=${JSON.stringify(provider.id)}`
13282
13640
  ];
13283
13641
  }
13642
+ function resolveForwardableOpenAiApiKey(env = process.env) {
13643
+ const fromEnv = env.OPENAI_API_KEY?.trim();
13644
+ if (fromEnv !== void 0 && fromEnv !== "") {
13645
+ return fromEnv;
13646
+ }
13647
+ const codexHomeRaw = env.CODEX_HOME?.trim();
13648
+ const codexHome = codexHomeRaw !== void 0 && codexHomeRaw !== "" ? codexHomeRaw : join9(homedir7(), ".codex");
13649
+ let raw;
13650
+ try {
13651
+ raw = readFileSync6(join9(codexHome, "auth.json"), "utf8");
13652
+ } catch (_error) {
13653
+ return void 0;
13654
+ }
13655
+ let parsed;
13656
+ try {
13657
+ parsed = JSON.parse(raw);
13658
+ } catch (_error) {
13659
+ return void 0;
13660
+ }
13661
+ if (!isJsonObject(parsed)) {
13662
+ return void 0;
13663
+ }
13664
+ const apiKey = parsed.OPENAI_API_KEY;
13665
+ if (typeof apiKey === "string" && apiKey.trim() !== "") {
13666
+ return apiKey.trim();
13667
+ }
13668
+ return void 0;
13669
+ }
13284
13670
  async function connectCodexAppServer(websocketUrl, socketFactory = (url) => new NodeWebSocket(url)) {
13285
13671
  const websocket = await openCodexAppServerWebSocket(
13286
13672
  websocketUrl,
@@ -13604,22 +13990,22 @@ var init_codexAppServer = __esm({
13604
13990
  // src/codexProjectTrust.ts
13605
13991
  import {
13606
13992
  existsSync as existsSync5,
13607
- mkdirSync as mkdirSync3,
13608
- readFileSync as readFileSync6,
13993
+ mkdirSync as mkdirSync4,
13994
+ readFileSync as readFileSync7,
13609
13995
  realpathSync,
13610
- writeFileSync
13996
+ writeFileSync as writeFileSync2
13611
13997
  } from "node:fs";
13612
- import { homedir as homedir7 } from "node:os";
13613
- import { join as join8, resolve as resolve3 } from "node:path";
13998
+ import { homedir as homedir8 } from "node:os";
13999
+ import { join as join10, resolve as resolve3 } from "node:path";
13614
14000
  function ensureCodexProjectTrusted(projectPath, options = {}) {
13615
14001
  const trustedPath = realpathSync(resolve3(projectPath));
13616
- const configHome = options.configHome ?? process.env.CODEX_HOME ?? join8(homedir7(), ".codex");
13617
- const configPath = join8(configHome, "config.toml");
13618
- const currentConfig = existsSync5(configPath) ? readFileSync6(configPath, "utf8") : "";
14002
+ const configHome = options.configHome ?? process.env.CODEX_HOME ?? join10(homedir8(), ".codex");
14003
+ const configPath = join10(configHome, "config.toml");
14004
+ const currentConfig = existsSync5(configPath) ? readFileSync7(configPath, "utf8") : "";
13619
14005
  const nextConfig = codexConfigWithTrustedProject(currentConfig, trustedPath);
13620
14006
  if (nextConfig !== currentConfig) {
13621
- mkdirSync3(configHome, { recursive: true });
13622
- writeFileSync(configPath, nextConfig);
14007
+ mkdirSync4(configHome, { recursive: true });
14008
+ writeFileSync2(configPath, nextConfig);
13623
14009
  }
13624
14010
  return trustedPath;
13625
14011
  }
@@ -13964,7 +14350,7 @@ var init_codexNotificationConsoleStats = __esm({
13964
14350
 
13965
14351
  // src/localCapabilities.ts
13966
14352
  import { realpathSync as realpathSync2 } from "node:fs";
13967
- import { homedir as homedir8 } from "node:os";
14353
+ import { homedir as homedir9 } from "node:os";
13968
14354
  import { isAbsolute as isAbsolute3, relative as relative2, resolve as resolve4 } from "node:path";
13969
14355
  function parseAllowedCwdList(value) {
13970
14356
  if (value === void 0) {
@@ -14013,7 +14399,7 @@ function expandUserPath(pathValue) {
14013
14399
  }
14014
14400
  function currentHomeDirectory() {
14015
14401
  const configuredHome = process.env.HOME;
14016
- return configuredHome === void 0 || configuredHome.trim() === "" ? homedir8() : configuredHome;
14402
+ return configuredHome === void 0 || configuredHome.trim() === "" ? homedir9() : configuredHome;
14017
14403
  }
14018
14404
  function resolveAllowedCwd(requestedCwd, allowedRoots) {
14019
14405
  if (requestedCwd === void 0 || requestedCwd.trim() === "") {
@@ -14413,17 +14799,17 @@ import {
14413
14799
  chmodSync,
14414
14800
  existsSync as existsSync6,
14415
14801
  linkSync,
14416
- mkdirSync as mkdirSync4,
14417
- readFileSync as readFileSync7,
14802
+ mkdirSync as mkdirSync5,
14803
+ readFileSync as readFileSync8,
14418
14804
  realpathSync as realpathSync3,
14419
14805
  unlinkSync,
14420
- writeFileSync as writeFileSync2
14806
+ writeFileSync as writeFileSync3
14421
14807
  } from "node:fs";
14422
- import { homedir as homedir9 } from "node:os";
14423
- import { basename as basename5, dirname as dirname4, join as join9, resolve as resolve5 } from "node:path";
14808
+ import { homedir as homedir10 } from "node:os";
14809
+ import { basename as basename5, dirname as dirname4, join as join11, resolve as resolve5 } from "node:path";
14424
14810
  function localConfigPath(env = process.env) {
14425
14811
  const override = env.LINZUMI_CONFIG_FILE;
14426
- return override !== void 0 && override.trim() !== "" ? resolve5(expandUserPath(override)) : resolve5(homedir9(), ".linzumi", "config.json");
14812
+ return override !== void 0 && override.trim() !== "" ? resolve5(expandUserPath(override)) : resolve5(homedir10(), ".linzumi", "config.json");
14427
14813
  }
14428
14814
  function localConfigScopeKey(linzumiUrl) {
14429
14815
  const normalizedUrl = kandanHttpBaseUrl(linzumiUrl);
@@ -14504,21 +14890,21 @@ function ensureLocalRunnerId(path2 = localConfigPath(), createRunnerId = default
14504
14890
  }
14505
14891
  function localMachineIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
14506
14892
  if (linzumiUrl !== void 0 && localConfigScopeKey(linzumiUrl) !== prodConfigScope) {
14507
- return join9(
14893
+ return join11(
14508
14894
  dirname4(configPath),
14509
14895
  `${basename5(configPath)}.${localConfigScopeFileStem(linzumiUrl)}.machine-id`
14510
14896
  );
14511
14897
  }
14512
- return join9(dirname4(configPath), `${basename5(configPath)}.machine-id`);
14898
+ return join11(dirname4(configPath), `${basename5(configPath)}.machine-id`);
14513
14899
  }
14514
14900
  function localRunnerIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
14515
14901
  if (linzumiUrl !== void 0 && localConfigScopeKey(linzumiUrl) !== prodConfigScope) {
14516
- return join9(
14902
+ return join11(
14517
14903
  dirname4(configPath),
14518
14904
  `${basename5(configPath)}.${localConfigScopeFileStem(linzumiUrl)}.runner-id`
14519
14905
  );
14520
14906
  }
14521
- return join9(dirname4(configPath), `${basename5(configPath)}.runner-id`);
14907
+ return join11(dirname4(configPath), `${basename5(configPath)}.runner-id`);
14522
14908
  }
14523
14909
  function readConfiguredAllowedCwdDetailsForLinzumiUrl(linzumiUrl, path2 = localConfigPath()) {
14524
14910
  return readConfiguredAllowedCwdDetailsFromConfig(
@@ -14648,7 +15034,7 @@ function writeLocalSignupAuth(auth, path2 = localConfigPath()) {
14648
15034
  version: 1,
14649
15035
  signupAuth: nextSignupAuth
14650
15036
  };
14651
- mkdirSync4(dirname4(path2), { recursive: true });
15037
+ mkdirSync5(dirname4(path2), { recursive: true });
14652
15038
  writeLocalConfigJson(path2, next);
14653
15039
  return signupAuthFromJson(nextSignupAuth);
14654
15040
  }
@@ -14656,7 +15042,7 @@ function writeLocalConfigJson(path2, payload) {
14656
15042
  if (existsSync6(path2)) {
14657
15043
  chmodSync(path2, localConfigFileMode);
14658
15044
  }
14659
- writeFileSync2(path2, `${JSON.stringify(payload, null, 2)}
15045
+ writeFileSync3(path2, `${JSON.stringify(payload, null, 2)}
14660
15046
  `, {
14661
15047
  encoding: "utf8",
14662
15048
  mode: localConfigFileMode
@@ -14683,7 +15069,7 @@ function readLocalConfigFile(path2) {
14683
15069
  if (!existsSync6(path2)) {
14684
15070
  return { version: 1, allowedCwds: [] };
14685
15071
  }
14686
- const parsed = JSON.parse(readFileSync7(path2, "utf8"));
15072
+ const parsed = JSON.parse(readFileSync8(path2, "utf8"));
14687
15073
  if (!isConfigPayload(parsed)) {
14688
15074
  throw new Error(`invalid Linzumi config: ${path2}`);
14689
15075
  }
@@ -14712,7 +15098,7 @@ function writeLocalConfigSection(config, path2, linzumiUrl) {
14712
15098
  version: 1,
14713
15099
  [scopeKey]: nextSection
14714
15100
  };
14715
- mkdirSync4(dirname4(path2), { recursive: true });
15101
+ mkdirSync5(dirname4(path2), { recursive: true });
14716
15102
  writeLocalConfigJson(path2, next);
14717
15103
  }
14718
15104
  function isConfigPayload(value) {
@@ -14787,12 +15173,12 @@ function ensureLocalMachineIdSeed(configPath, createMachineId, linzumiUrl) {
14787
15173
  if (!machineIdValid(machineId)) {
14788
15174
  throw new Error(`invalid generated Linzumi machine id: ${machineId}`);
14789
15175
  }
14790
- mkdirSync4(dirname4(seedPath), { recursive: true });
14791
- const tempPath = join9(
15176
+ mkdirSync5(dirname4(seedPath), { recursive: true });
15177
+ const tempPath = join11(
14792
15178
  dirname4(seedPath),
14793
15179
  `.${basename5(seedPath)}.${process.pid}.${randomUUID2()}.tmp`
14794
15180
  );
14795
- writeFileSync2(tempPath, `${machineId}
15181
+ writeFileSync3(tempPath, `${machineId}
14796
15182
  `, { encoding: "utf8", flag: "wx" });
14797
15183
  try {
14798
15184
  linkSync(tempPath, seedPath);
@@ -14815,12 +15201,12 @@ function ensureLocalRunnerIdSeed(configPath, createRunnerId, linzumiUrl) {
14815
15201
  if (!runnerIdValid(runnerId)) {
14816
15202
  throw new Error(`invalid generated Linzumi runner id: ${runnerId}`);
14817
15203
  }
14818
- mkdirSync4(dirname4(seedPath), { recursive: true });
14819
- const tempPath = join9(
15204
+ mkdirSync5(dirname4(seedPath), { recursive: true });
15205
+ const tempPath = join11(
14820
15206
  dirname4(seedPath),
14821
15207
  `.${basename5(seedPath)}.${process.pid}.${randomUUID2()}.tmp`
14822
15208
  );
14823
- writeFileSync2(tempPath, `${runnerId}
15209
+ writeFileSync3(tempPath, `${runnerId}
14824
15210
  `, { encoding: "utf8", flag: "wx" });
14825
15211
  try {
14826
15212
  linkSync(tempPath, seedPath);
@@ -14835,14 +15221,14 @@ function ensureLocalRunnerIdSeed(configPath, createRunnerId, linzumiUrl) {
14835
15221
  }
14836
15222
  }
14837
15223
  function readMachineIdSeed(seedPath) {
14838
- const machineId = readFileSync7(seedPath, "utf8").trim();
15224
+ const machineId = readFileSync8(seedPath, "utf8").trim();
14839
15225
  if (!machineIdValid(machineId)) {
14840
15226
  throw new Error(`invalid Linzumi machine id seed: ${seedPath}`);
14841
15227
  }
14842
15228
  return machineId;
14843
15229
  }
14844
15230
  function readRunnerIdSeed(seedPath) {
14845
- const runnerId = readFileSync7(seedPath, "utf8").trim();
15231
+ const runnerId = readFileSync8(seedPath, "utf8").trim();
14846
15232
  if (!runnerIdValid(runnerId)) {
14847
15233
  throw new Error(`invalid Linzumi runner id seed: ${seedPath}`);
14848
15234
  }
@@ -15141,8 +15527,8 @@ var init_remoteCodexExecutionContext = __esm({
15141
15527
  });
15142
15528
 
15143
15529
  // src/helloLinzumiProject.ts
15144
- import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync8, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
15145
- import { dirname as dirname5, join as join10, resolve as resolve6 } from "node:path";
15530
+ import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync9, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
15531
+ import { dirname as dirname5, join as join12, resolve as resolve6 } from "node:path";
15146
15532
  import { fileURLToPath as fileURLToPath2 } from "node:url";
15147
15533
  function createHelloLinzumiProject(input = {}) {
15148
15534
  const options = typeof input === "string" ? { rootPath: input } : input;
@@ -15151,9 +15537,9 @@ function createHelloLinzumiProject(input = {}) {
15151
15537
  const host = normalizeHost(options.host);
15152
15538
  assertTcpPort(port);
15153
15539
  assertWritableDemoRoot(root, options.reset === true);
15154
- mkdirSync5(join10(root, "src"), { recursive: true });
15540
+ mkdirSync6(join12(root, "src"), { recursive: true });
15155
15541
  for (const file of demoFiles({ root, port, host })) {
15156
- writeFileSync3(join10(root, file.path), file.content, "utf8");
15542
+ writeFileSync4(join12(root, file.path), file.content, "utf8");
15157
15543
  }
15158
15544
  return {
15159
15545
  root,
@@ -15197,10 +15583,10 @@ function assertWritableDemoRoot(root, reset) {
15197
15583
  if (!existsSync7(root)) {
15198
15584
  return;
15199
15585
  }
15200
- const markerPath = join10(root, markerFile);
15201
- const isDemoRoot = existsSync7(markerPath) && readFileSync8(markerPath, "utf8").trim() === "hello-linzumi";
15586
+ const markerPath = join12(root, markerFile);
15587
+ const isDemoRoot = existsSync7(markerPath) && readFileSync9(markerPath, "utf8").trim() === "hello-linzumi";
15202
15588
  if (isDemoRoot && reset) {
15203
- rmSync(root, { recursive: true, force: true });
15589
+ rmSync2(root, { recursive: true, force: true });
15204
15590
  return;
15205
15591
  }
15206
15592
  if (isDemoRoot) {
@@ -15233,7 +15619,7 @@ var init_helloLinzumiProject = __esm({
15233
15619
  defaultHelloLinzumiHost = "0.0.0.0";
15234
15620
  markerFile = ".linzumi-demo-project";
15235
15621
  moduleDir = dirname5(fileURLToPath2(import.meta.url));
15236
- linzumiLogoSvg = readFileSync8(join10(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
15622
+ linzumiLogoSvg = readFileSync9(join12(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
15237
15623
  packageJson = `${JSON.stringify(
15238
15624
  {
15239
15625
  name: "hello-linzumi",
@@ -16035,14 +16421,14 @@ import {
16035
16421
  copyFileSync,
16036
16422
  cpSync,
16037
16423
  existsSync as existsSync8,
16038
- mkdirSync as mkdirSync6,
16424
+ mkdirSync as mkdirSync7,
16039
16425
  mkdtempSync,
16040
- readFileSync as readFileSync9,
16426
+ readFileSync as readFileSync10,
16041
16427
  realpathSync as realpathSync4,
16042
- writeFileSync as writeFileSync4
16428
+ writeFileSync as writeFileSync5
16043
16429
  } from "node:fs";
16044
16430
  import { tmpdir } from "node:os";
16045
- import { basename as basename6, delimiter, dirname as dirname6, join as join11 } from "node:path";
16431
+ import { basename as basename6, delimiter, dirname as dirname6, join as join13 } from "node:path";
16046
16432
  function isStartLocalEditorControl(control) {
16047
16433
  return control.type === "start_local_editor";
16048
16434
  }
@@ -16260,24 +16646,24 @@ function codeServerArgs(port, cwd, userDataDir, extensionsDir) {
16260
16646
  }
16261
16647
  function prepareCodeServerProfile(collaboration, editorRuntime) {
16262
16648
  try {
16263
- const userDataDir = mkdtempSync(join11(tmpdir(), "kandan-local-editor-"));
16264
- const extensionsDir = join11(userDataDir, "extensions");
16265
- const collaborationServerDir = join11(userDataDir, "collaboration-server");
16266
- const tempDir = join11(userDataDir, "tmp");
16267
- const userSettingsDir = join11(userDataDir, "User");
16268
- mkdirSync6(userSettingsDir, { recursive: true });
16269
- mkdirSync6(extensionsDir, { recursive: true });
16270
- mkdirSync6(collaborationServerDir, { recursive: true });
16271
- mkdirSync6(tempDir, { recursive: true });
16649
+ const userDataDir = mkdtempSync(join13(tmpdir(), "kandan-local-editor-"));
16650
+ const extensionsDir = join13(userDataDir, "extensions");
16651
+ const collaborationServerDir = join13(userDataDir, "collaboration-server");
16652
+ const tempDir = join13(userDataDir, "tmp");
16653
+ const userSettingsDir = join13(userDataDir, "User");
16654
+ mkdirSync7(userSettingsDir, { recursive: true });
16655
+ mkdirSync7(extensionsDir, { recursive: true });
16656
+ mkdirSync7(collaborationServerDir, { recursive: true });
16657
+ mkdirSync7(tempDir, { recursive: true });
16272
16658
  if (editorRuntime !== void 0) {
16273
16659
  ensureCodeServerBrowserExtensionAssets(editorRuntime);
16274
16660
  installDirectory(
16275
16661
  editorRuntime.assets.documentStateExtensionDir,
16276
- join11(extensionsDir, "kandan.document-state-telemetry")
16662
+ join13(extensionsDir, "kandan.document-state-telemetry")
16277
16663
  );
16278
16664
  }
16279
- writeFileSync4(
16280
- join11(userSettingsDir, "settings.json"),
16665
+ writeFileSync5(
16666
+ join13(userSettingsDir, "settings.json"),
16281
16667
  JSON.stringify(codeServerSettings(collaboration), null, 2)
16282
16668
  );
16283
16669
  return { ok: true, userDataDir, extensionsDir, collaborationServerDir };
@@ -16289,14 +16675,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16289
16675
  const vscodeRoot = codeServerVscodeRoot(runtime);
16290
16676
  const repairs = [
16291
16677
  {
16292
- source: join11(
16678
+ source: join13(
16293
16679
  vscodeRoot,
16294
16680
  "extensions",
16295
16681
  "git-base",
16296
16682
  "dist",
16297
16683
  "extension.js"
16298
16684
  ),
16299
- target: join11(
16685
+ target: join13(
16300
16686
  vscodeRoot,
16301
16687
  "extensions",
16302
16688
  "git-base",
@@ -16307,14 +16693,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16307
16693
  required: true
16308
16694
  },
16309
16695
  {
16310
- source: join11(
16696
+ source: join13(
16311
16697
  vscodeRoot,
16312
16698
  "extensions",
16313
16699
  "git-base",
16314
16700
  "dist",
16315
16701
  "extension.js.map"
16316
16702
  ),
16317
- target: join11(
16703
+ target: join13(
16318
16704
  vscodeRoot,
16319
16705
  "extensions",
16320
16706
  "git-base",
@@ -16325,14 +16711,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16325
16711
  required: false
16326
16712
  },
16327
16713
  {
16328
- source: join11(
16714
+ source: join13(
16329
16715
  vscodeRoot,
16330
16716
  "extensions",
16331
16717
  "merge-conflict",
16332
16718
  "dist",
16333
16719
  "mergeConflictMain.js"
16334
16720
  ),
16335
- target: join11(
16721
+ target: join13(
16336
16722
  vscodeRoot,
16337
16723
  "extensions",
16338
16724
  "merge-conflict",
@@ -16343,14 +16729,14 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16343
16729
  required: true
16344
16730
  },
16345
16731
  {
16346
- source: join11(
16732
+ source: join13(
16347
16733
  vscodeRoot,
16348
16734
  "extensions",
16349
16735
  "merge-conflict",
16350
16736
  "dist",
16351
16737
  "mergeConflictMain.js.map"
16352
16738
  ),
16353
- target: join11(
16739
+ target: join13(
16354
16740
  vscodeRoot,
16355
16741
  "extensions",
16356
16742
  "merge-conflict",
@@ -16368,7 +16754,7 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16368
16754
  case (!required3 && !existsSync8(source)):
16369
16755
  return;
16370
16756
  default:
16371
- mkdirSync6(dirname6(target), { recursive: true });
16757
+ mkdirSync7(dirname6(target), { recursive: true });
16372
16758
  copyFileSync(source, target);
16373
16759
  return;
16374
16760
  }
@@ -16376,10 +16762,10 @@ function ensureCodeServerBrowserExtensionAssets(runtime) {
16376
16762
  }
16377
16763
  function codeServerVscodeRoot(runtime) {
16378
16764
  const roots = uniquePaths([
16379
- join11(runtime.root, "lib", "vscode"),
16380
- join11(dirname6(dirname6(runtime.codeServerBin)), "lib", "vscode"),
16765
+ join13(runtime.root, "lib", "vscode"),
16766
+ join13(dirname6(dirname6(runtime.codeServerBin)), "lib", "vscode"),
16381
16767
  ...wrappedCodeServerBin(runtime.codeServerBin).map(
16382
- (codeServerBin) => join11(dirname6(dirname6(codeServerBin)), "lib", "vscode")
16768
+ (codeServerBin) => join13(dirname6(dirname6(codeServerBin)), "lib", "vscode")
16383
16769
  )
16384
16770
  ]);
16385
16771
  const rootWithRequiredAssets = roots.find(
@@ -16395,7 +16781,7 @@ function codeServerVscodeRoot(runtime) {
16395
16781
  }
16396
16782
  function wrappedCodeServerBin(codeServerBin) {
16397
16783
  try {
16398
- const script = readFileSync9(codeServerBin, "utf8");
16784
+ const script = readFileSync10(codeServerBin, "utf8");
16399
16785
  const match = script.match(
16400
16786
  /exec\s+(?:"([^"]+)"|'([^']+)'|([^\s]+))\s+"\$@"/u
16401
16787
  );
@@ -16407,8 +16793,8 @@ function wrappedCodeServerBin(codeServerBin) {
16407
16793
  }
16408
16794
  function codeServerBrowserAssetSources(vscodeRoot) {
16409
16795
  return [
16410
- join11(vscodeRoot, "extensions", "git-base", "dist", "extension.js"),
16411
- join11(
16796
+ join13(vscodeRoot, "extensions", "git-base", "dist", "extension.js"),
16797
+ join13(
16412
16798
  vscodeRoot,
16413
16799
  "extensions",
16414
16800
  "merge-conflict",
@@ -16487,10 +16873,10 @@ function prepareLinuxCodeServerLaunch(options) {
16487
16873
  options.cwd,
16488
16874
  "--setenv",
16489
16875
  "XDG_DATA_HOME",
16490
- join11(options.userDataDir, "data"),
16876
+ join13(options.userDataDir, "data"),
16491
16877
  "--setenv",
16492
16878
  "XDG_CONFIG_HOME",
16493
- join11(options.userDataDir, "config"),
16879
+ join13(options.userDataDir, "config"),
16494
16880
  ...readOnlyRoots.flatMap((path2) => ["--ro-bind-try", path2, path2]),
16495
16881
  "--bind",
16496
16882
  options.cwd,
@@ -16531,7 +16917,7 @@ function resolveCodeServerExecutable(command, envPath) {
16531
16917
  if (directory.trim() === "") {
16532
16918
  continue;
16533
16919
  }
16534
- const candidate = join11(directory, command);
16920
+ const candidate = join13(directory, command);
16535
16921
  if (!existsSync8(candidate)) {
16536
16922
  continue;
16537
16923
  }
@@ -16617,7 +17003,7 @@ async function startCollaborationSidecar(collaboration, profile, editorRuntime,
16617
17003
  ]);
16618
17004
  const command = nodeRuntimeExecutable();
16619
17005
  const args = [
16620
- join11(
17006
+ join13(
16621
17007
  profile.collaborationServerDir,
16622
17008
  "open-collaboration-server",
16623
17009
  "bundle",
@@ -16712,11 +17098,11 @@ function nodeRuntimeExecutable(env = process.env, execPath = process.execPath) {
16712
17098
  return basename6(execPath).toLowerCase().includes("bun") ? "node" : execPath;
16713
17099
  }
16714
17100
  async function installLocalTarball(archivePath, destinationDir) {
16715
- mkdirSync6(destinationDir, { recursive: true });
17101
+ mkdirSync7(destinationDir, { recursive: true });
16716
17102
  await runProcess("tar", ["-xzf", archivePath, "-C", destinationDir]);
16717
17103
  }
16718
17104
  function installDirectory(sourceDir, destinationDir) {
16719
- mkdirSync6(dirname6(destinationDir), { recursive: true });
17105
+ mkdirSync7(dirname6(destinationDir), { recursive: true });
16720
17106
  cpSync(sourceDir, destinationDir, { recursive: true });
16721
17107
  }
16722
17108
  function codeServerEnv(env, cwd, userDataDir, collaboration) {
@@ -16734,7 +17120,7 @@ function codeServerEnv(env, cwd, userDataDir, collaboration) {
16734
17120
  KANDAN_EDITOR_COLLABORATION_ENTRY_MODE: "kandan_auto_host_or_join",
16735
17121
  KANDAN_EDITOR_COLLABORATION_ROOM_ID: collaboration.roomId,
16736
17122
  KANDAN_EDITOR_COLLABORATION_SERVER_URL: collaboration.bootstrapServerUrl,
16737
- KANDAN_EDITOR_COLLABORATION_AUTO_HOST_CLAIM_PATH: join11(
17123
+ KANDAN_EDITOR_COLLABORATION_AUTO_HOST_CLAIM_PATH: join13(
16738
17124
  userDataDir,
16739
17125
  "kandan-oct-auto-host.lock"
16740
17126
  )
@@ -16943,15 +17329,15 @@ import {
16943
17329
  createReadStream,
16944
17330
  createWriteStream as createWriteStream2,
16945
17331
  existsSync as existsSync9,
16946
- mkdirSync as mkdirSync7,
17332
+ mkdirSync as mkdirSync8,
16947
17333
  mkdtempSync as mkdtempSync2,
16948
- readFileSync as readFileSync10,
17334
+ readFileSync as readFileSync11,
16949
17335
  renameSync,
16950
- rmSync as rmSync2,
16951
- writeFileSync as writeFileSync5
17336
+ rmSync as rmSync3,
17337
+ writeFileSync as writeFileSync6
16952
17338
  } from "node:fs";
16953
- import { homedir as homedir10 } from "node:os";
16954
- import { dirname as dirname7, join as join12, resolve as resolve7 } from "node:path";
17339
+ import { homedir as homedir11 } from "node:os";
17340
+ import { dirname as dirname7, join as join14, resolve as resolve7 } from "node:path";
16955
17341
  import { Readable } from "node:stream";
16956
17342
  import { pipeline } from "node:stream/promises";
16957
17343
  async function resolveEditorRuntime(options) {
@@ -17142,14 +17528,14 @@ function normalizeRuntimeAssets(value) {
17142
17528
  }
17143
17529
  function installedRuntime(cacheRoot, manifest) {
17144
17530
  const runtimeRoot = runtimeInstallRoot(cacheRoot, manifest);
17145
- const manifestPath = join12(runtimeRoot, manifest.manifestPath);
17146
- const codeServerBin = join12(runtimeRoot, manifest.codeServerBinPath);
17531
+ const manifestPath = join14(runtimeRoot, manifest.manifestPath);
17532
+ const codeServerBin = join14(runtimeRoot, manifest.codeServerBinPath);
17147
17533
  const assets = verifiedRuntimeAssetPaths(runtimeRoot, manifest);
17148
17534
  if (!existsSync9(manifestPath) || !existsSync9(codeServerBin) || assets === void 0) {
17149
17535
  return { ok: false };
17150
17536
  }
17151
17537
  try {
17152
- const installed = JSON.parse(readFileSync10(manifestPath, "utf8"));
17538
+ const installed = JSON.parse(readFileSync11(manifestPath, "utf8"));
17153
17539
  if (isJsonObject(installed) && installed.version === manifest.version && installed.platform === manifest.platform && (installed.archiveSha256 === void 0 || installed.archiveSha256 === manifest.archiveSha256)) {
17154
17540
  return {
17155
17541
  ok: true,
@@ -17167,10 +17553,10 @@ function installedRuntime(cacheRoot, manifest) {
17167
17553
  return { ok: false };
17168
17554
  }
17169
17555
  async function installRuntime(args) {
17170
- mkdirSync7(args.cacheRoot, { recursive: true });
17171
- const tempRoot = mkdtempSync2(join12(args.cacheRoot, ".install-"));
17172
- const archivePath = join12(tempRoot, "runtime.tar.gz");
17173
- const extractRoot = join12(tempRoot, "runtime");
17556
+ mkdirSync8(args.cacheRoot, { recursive: true });
17557
+ const tempRoot = mkdtempSync2(join14(args.cacheRoot, ".install-"));
17558
+ const archivePath = join14(tempRoot, "runtime.tar.gz");
17559
+ const extractRoot = join14(tempRoot, "runtime");
17174
17560
  try {
17175
17561
  const downloaded = await downloadArchive({
17176
17562
  kandanUrl: args.kandanUrl,
@@ -17182,7 +17568,7 @@ async function installRuntime(args) {
17182
17568
  if (!downloaded.ok) {
17183
17569
  return downloaded;
17184
17570
  }
17185
- mkdirSync7(extractRoot, { recursive: true });
17571
+ mkdirSync8(extractRoot, { recursive: true });
17186
17572
  if (!await args.extractArchive(archivePath, extractRoot)) {
17187
17573
  return { ok: false, reason: "archive_extract_failed" };
17188
17574
  }
@@ -17195,14 +17581,14 @@ async function installRuntime(args) {
17195
17581
  if (!assetsInstalled) {
17196
17582
  return { ok: false, reason: "install_failed" };
17197
17583
  }
17198
- const manifestPath = join12(extractRoot, args.manifest.manifestPath);
17199
- const codeServerBin = join12(extractRoot, args.manifest.codeServerBinPath);
17584
+ const manifestPath = join14(extractRoot, args.manifest.manifestPath);
17585
+ const codeServerBin = join14(extractRoot, args.manifest.codeServerBinPath);
17200
17586
  const assets = verifiedRuntimeAssetPaths(extractRoot, args.manifest);
17201
17587
  if (!existsSync9(codeServerBin) || assets === void 0) {
17202
17588
  return { ok: false, reason: "invalid_archive" };
17203
17589
  }
17204
- mkdirSync7(dirname7(manifestPath), { recursive: true });
17205
- writeFileSync5(
17590
+ mkdirSync8(dirname7(manifestPath), { recursive: true });
17591
+ writeFileSync6(
17206
17592
  manifestPath,
17207
17593
  JSON.stringify(
17208
17594
  {
@@ -17219,29 +17605,29 @@ async function installRuntime(args) {
17219
17605
  )
17220
17606
  );
17221
17607
  const targetRoot = runtimeInstallRoot(args.cacheRoot, args.manifest);
17222
- rmSync2(targetRoot, { recursive: true, force: true });
17223
- mkdirSync7(dirname7(targetRoot), { recursive: true });
17608
+ rmSync3(targetRoot, { recursive: true, force: true });
17609
+ mkdirSync8(dirname7(targetRoot), { recursive: true });
17224
17610
  renameSync(extractRoot, targetRoot);
17225
17611
  return {
17226
17612
  ok: true,
17227
17613
  runtime: {
17228
17614
  mode: "server_managed",
17229
17615
  root: targetRoot,
17230
- codeServerBin: join12(targetRoot, args.manifest.codeServerBinPath),
17616
+ codeServerBin: join14(targetRoot, args.manifest.codeServerBinPath),
17231
17617
  assets: {
17232
- collaborationExtensionTarball: join12(
17618
+ collaborationExtensionTarball: join14(
17233
17619
  targetRoot,
17234
17620
  "kandan",
17235
17621
  "editor_extensions",
17236
17622
  "typefox.open-collaboration-tools.tar.gz"
17237
17623
  ),
17238
- collaborationServerTarball: join12(
17624
+ collaborationServerTarball: join14(
17239
17625
  targetRoot,
17240
17626
  "kandan",
17241
17627
  "editor_servers",
17242
17628
  "open-collaboration-server.tar.gz"
17243
17629
  ),
17244
- documentStateExtensionDir: join12(
17630
+ documentStateExtensionDir: join14(
17245
17631
  targetRoot,
17246
17632
  "kandan",
17247
17633
  "editor_extensions",
@@ -17253,12 +17639,12 @@ async function installRuntime(args) {
17253
17639
  } catch (_error) {
17254
17640
  return { ok: false, reason: "install_failed" };
17255
17641
  } finally {
17256
- rmSync2(tempRoot, { recursive: true, force: true });
17642
+ rmSync3(tempRoot, { recursive: true, force: true });
17257
17643
  }
17258
17644
  }
17259
17645
  async function materializeRuntimeAssets(args) {
17260
17646
  for (const asset of args.manifest.assets) {
17261
- const targetPath = join12(args.runtimeRoot, asset.path);
17647
+ const targetPath = join14(args.runtimeRoot, asset.path);
17262
17648
  try {
17263
17649
  const bytes = await runtimeAssetBytes({
17264
17650
  kandanUrl: args.kandanUrl,
@@ -17268,8 +17654,8 @@ async function materializeRuntimeAssets(args) {
17268
17654
  if (bytes === void 0) {
17269
17655
  continue;
17270
17656
  }
17271
- mkdirSync7(dirname7(targetPath), { recursive: true });
17272
- writeFileSync5(targetPath, bytes);
17657
+ mkdirSync8(dirname7(targetPath), { recursive: true });
17658
+ writeFileSync6(targetPath, bytes);
17273
17659
  } catch (_error) {
17274
17660
  return false;
17275
17661
  }
@@ -17359,19 +17745,19 @@ function runtimeInstallRoot(cacheRoot, manifest) {
17359
17745
  return resolve7(cacheRoot, manifest.platform, manifest.archiveSha256);
17360
17746
  }
17361
17747
  function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17362
- const collaborationExtensionTarball = join12(
17748
+ const collaborationExtensionTarball = join14(
17363
17749
  runtimeRoot,
17364
17750
  "kandan",
17365
17751
  "editor_extensions",
17366
17752
  "typefox.open-collaboration-tools.tar.gz"
17367
17753
  );
17368
- const collaborationServerTarball = join12(
17754
+ const collaborationServerTarball = join14(
17369
17755
  runtimeRoot,
17370
17756
  "kandan",
17371
17757
  "editor_servers",
17372
17758
  "open-collaboration-server.tar.gz"
17373
17759
  );
17374
- const documentStateExtensionDir = join12(
17760
+ const documentStateExtensionDir = join14(
17375
17761
  runtimeRoot,
17376
17762
  "kandan",
17377
17763
  "editor_extensions",
@@ -17380,7 +17766,7 @@ function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17380
17766
  const codeServerRoot = codeServerRuntimeRoot(manifest.codeServerBinPath);
17381
17767
  const requiredPaths = [
17382
17768
  manifest.codeServerBinPath,
17383
- join12(
17769
+ join14(
17384
17770
  codeServerRoot,
17385
17771
  "lib",
17386
17772
  "vscode",
@@ -17390,7 +17776,7 @@ function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17390
17776
  "web",
17391
17777
  "vsda.js"
17392
17778
  ),
17393
- join12(
17779
+ join14(
17394
17780
  codeServerRoot,
17395
17781
  "lib",
17396
17782
  "vscode",
@@ -17411,7 +17797,7 @@ function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
17411
17797
  if (expectedSha256 === void 0 && relativePath !== manifest.codeServerBinPath) {
17412
17798
  return void 0;
17413
17799
  }
17414
- const absolutePath = join12(runtimeRoot, relativePath);
17800
+ const absolutePath = join14(runtimeRoot, relativePath);
17415
17801
  if (!existsSync9(absolutePath)) {
17416
17802
  return void 0;
17417
17803
  }
@@ -17440,10 +17826,10 @@ function manifestAssetChecksums(assets) {
17440
17826
  return checksums;
17441
17827
  }
17442
17828
  function fileSha256Sync(path2) {
17443
- return createHash4("sha256").update(readFileSync10(path2)).digest("hex");
17829
+ return createHash4("sha256").update(readFileSync11(path2)).digest("hex");
17444
17830
  }
17445
17831
  function defaultEditorRuntimeCacheRoot() {
17446
- return join12(homedir10(), ".linzumi", "editor-runtimes");
17832
+ return join14(homedir11(), ".linzumi", "editor-runtimes");
17447
17833
  }
17448
17834
  function nonEmptyString(value) {
17449
17835
  return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
@@ -17463,7 +17849,7 @@ var init_localEditorRuntime = __esm({
17463
17849
 
17464
17850
  // src/dependencyStatus.ts
17465
17851
  import { spawn as spawn6, spawnSync as spawnSync4 } from "node:child_process";
17466
- import { delimiter as delimiter2, dirname as dirname8, join as join13 } from "node:path";
17852
+ import { delimiter as delimiter2, dirname as dirname8, join as join15 } from "node:path";
17467
17853
  function probeTool(command, cwd) {
17468
17854
  return new Promise((resolve12) => {
17469
17855
  const args = ["--version"];
@@ -17620,8 +18006,8 @@ function voltaCommandCandidates(args) {
17620
18006
  new Set(
17621
18007
  [
17622
18008
  voltaBinBesideCodexShim(args.codexBin),
17623
- env.VOLTA_HOME === void 0 ? void 0 : join13(env.VOLTA_HOME, "bin", "volta"),
17624
- env.HOME === void 0 ? void 0 : join13(env.HOME, ".volta", "bin", "volta"),
18009
+ env.VOLTA_HOME === void 0 ? void 0 : join15(env.VOLTA_HOME, "bin", "volta"),
18010
+ env.HOME === void 0 ? void 0 : join15(env.HOME, ".volta", "bin", "volta"),
17625
18011
  ...pathVoltaCandidates(env.PATH)
17626
18012
  ].filter((candidate) => candidate !== void 0)
17627
18013
  )
@@ -17629,10 +18015,10 @@ function voltaCommandCandidates(args) {
17629
18015
  }
17630
18016
  function voltaBinBesideCodexShim(codexBin) {
17631
18017
  const normalizedCodexBin = codexBin.replaceAll("\\", "/");
17632
- return normalizedCodexBin.endsWith("/.volta/bin/codex") ? join13(dirname8(codexBin), "volta") : void 0;
18018
+ return normalizedCodexBin.endsWith("/.volta/bin/codex") ? join15(dirname8(codexBin), "volta") : void 0;
17633
18019
  }
17634
18020
  function pathVoltaCandidates(pathValue) {
17635
- return pathValue === void 0 ? [] : pathValue.split(delimiter2).filter((entry) => entry !== "").map((entry) => join13(entry, "volta"));
18021
+ return pathValue === void 0 ? [] : pathValue.split(delimiter2).filter((entry) => entry !== "").map((entry) => join15(entry, "volta"));
17636
18022
  }
17637
18023
  function codeServerDependencyStatus(args) {
17638
18024
  switch (args.editorRuntime?.status) {
@@ -17741,7 +18127,7 @@ var linzumiCliVersion, linzumiCliVersionText;
17741
18127
  var init_version = __esm({
17742
18128
  "src/version.ts"() {
17743
18129
  "use strict";
17744
- linzumiCliVersion = "0.0.83-beta";
18130
+ linzumiCliVersion = "0.0.84-beta";
17745
18131
  linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
17746
18132
  }
17747
18133
  });
@@ -17750,21 +18136,21 @@ var init_version = __esm({
17750
18136
  import {
17751
18137
  closeSync as closeSync2,
17752
18138
  existsSync as existsSync10,
17753
- mkdirSync as mkdirSync8,
18139
+ mkdirSync as mkdirSync9,
17754
18140
  openSync as openSync3,
17755
- readFileSync as readFileSync11,
18141
+ readFileSync as readFileSync12,
17756
18142
  renameSync as renameSync2,
17757
18143
  unlinkSync as unlinkSync2,
17758
- writeFileSync as writeFileSync6,
18144
+ writeFileSync as writeFileSync7,
17759
18145
  writeSync
17760
18146
  } from "node:fs";
17761
- import { dirname as dirname9, join as join14 } from "node:path";
18147
+ import { dirname as dirname9, join as join16 } from "node:path";
17762
18148
  function isRunnerLockHeldError(error) {
17763
18149
  return error instanceof RunnerLockHeldError || error instanceof Error && error.name === runnerLockHeldErrorName && "lockPath" in error && "heldBy" in error;
17764
18150
  }
17765
18151
  function runnerLockPath(machineId, configPath = localConfigPath(), linzumiUrl) {
17766
18152
  const lockName = linzumiUrl === void 0 ? encodeURIComponent(machineId) : localConfigScopeFileStem(linzumiUrl);
17767
- return join14(dirname9(configPath), "runners", `${lockName}.lock`);
18153
+ return join16(dirname9(configPath), "runners", `${lockName}.lock`);
17768
18154
  }
17769
18155
  function acquireRunnerLock(options) {
17770
18156
  const path2 = runnerLockPath(
@@ -17832,7 +18218,7 @@ function stampRunnerLockHeartbeat(path2, record, now) {
17832
18218
  heartbeatAt: now().toISOString()
17833
18219
  };
17834
18220
  const tmpPath = `${path2}.tmp`;
17835
- writeFileSync6(tmpPath, `${JSON.stringify(next, null, 2)}
18221
+ writeFileSync7(tmpPath, `${JSON.stringify(next, null, 2)}
17836
18222
  `, "utf8");
17837
18223
  renameSync2(tmpPath, path2);
17838
18224
  } catch (_error) {
@@ -17944,7 +18330,7 @@ function writeLockOrHandleExisting(path2, record, isPidAlive, now, killPid, onTa
17944
18330
  });
17945
18331
  }
17946
18332
  function tryCreateLock(path2, record) {
17947
- mkdirSync8(dirname9(path2), { recursive: true });
18333
+ mkdirSync9(dirname9(path2), { recursive: true });
17948
18334
  try {
17949
18335
  const fd = openSync3(path2, "wx");
17950
18336
  try {
@@ -18000,7 +18386,7 @@ function withStaleReplacementLock(path2, isPidAlive, callback) {
18000
18386
  function readReplacementLockPidIfPresent(path2) {
18001
18387
  let value;
18002
18388
  try {
18003
- value = readFileSync11(path2, "utf8").trim();
18389
+ value = readFileSync12(path2, "utf8").trim();
18004
18390
  } catch (error) {
18005
18391
  if (isNodeErrorCode2(error, "ENOENT")) {
18006
18392
  return void 0;
@@ -18040,7 +18426,7 @@ function readRunnerLockIfPresent(path2) {
18040
18426
  }
18041
18427
  }
18042
18428
  function readRunnerLock(path2) {
18043
- const parsed = JSON.parse(readFileSync11(path2, "utf8"));
18429
+ const parsed = JSON.parse(readFileSync12(path2, "utf8"));
18044
18430
  if (!isRunnerLockRecord(parsed)) {
18045
18431
  throw new Error(`invalid Linzumi runner lock: ${path2}`);
18046
18432
  }
@@ -18327,6 +18713,19 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
18327
18713
  job.updatedAtMs = nowMs;
18328
18714
  break;
18329
18715
  }
18716
+ // Live token counter parity with codex.notification token_usage_summary:
18717
+ // mid-turn usage events advance the dashboard counters per model round.
18718
+ case "claude_code.token_usage": {
18719
+ const tokenUsage = stringValue5(payload.token_usage_summary);
18720
+ const job = claudeDashboardJob(state, payload, nowMs);
18721
+ if (tokenUsage !== void 0) {
18722
+ state.tokenUsage = tokenUsage;
18723
+ job.tokenUsage = tokenUsage;
18724
+ }
18725
+ job.eventType = "token_usage";
18726
+ job.updatedAtMs = nowMs;
18727
+ break;
18728
+ }
18330
18729
  default:
18331
18730
  break;
18332
18731
  }
@@ -18787,6 +19186,8 @@ function formatRunnerConsoleEvent(event, payload) {
18787
19186
  return `Claude Code turn ${text(payload.outcome)}: id=${text(payload.turn_id)}`;
18788
19187
  case "claude_code.rate_limit":
18789
19188
  return `Claude Code rate limit: ${stringValue5(payload.rate_limit_summary) ?? "seen (no details)"}`;
19189
+ case "claude_code.token_usage":
19190
+ return `Claude Code token usage: ${stringValue5(payload.token_usage_summary) ?? "seen (no details)"}`;
18790
19191
  default:
18791
19192
  return void 0;
18792
19193
  }
@@ -19730,8 +20131,8 @@ var init_runnerConsoleReporter = __esm({
19730
20131
  });
19731
20132
 
19732
20133
  // src/telemetry.ts
19733
- import { mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
19734
- import { dirname as dirname10, basename as basename7, join as join15 } from "node:path";
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";
19735
20136
  import { randomUUID as randomUUID3 } from "node:crypto";
19736
20137
  function peekFlagValue(args, flags) {
19737
20138
  for (let index = 0; index < args.length; index += 1) {
@@ -19770,12 +20171,12 @@ function telemetryBaseUrl(apiUrl, env = process.env) {
19770
20171
  }
19771
20172
  }
19772
20173
  function telemetryInstallIdPath(env = process.env) {
19773
- return join15(dirname10(localConfigPath(env)), "install-id");
20174
+ return join17(dirname10(localConfigPath(env)), "install-id");
19774
20175
  }
19775
20176
  function ensureTelemetryInstallId(env = process.env) {
19776
20177
  const path2 = telemetryInstallIdPath(env);
19777
20178
  try {
19778
- const existing = readFileSync12(path2, "utf8").trim();
20179
+ const existing = readFileSync13(path2, "utf8").trim();
19779
20180
  if (existing !== "" && existing.length <= 128) {
19780
20181
  return existing;
19781
20182
  }
@@ -19783,8 +20184,8 @@ function ensureTelemetryInstallId(env = process.env) {
19783
20184
  }
19784
20185
  const installId = randomUUID3();
19785
20186
  try {
19786
- mkdirSync9(dirname10(path2), { recursive: true });
19787
- writeFileSync7(path2, `${installId}
20187
+ mkdirSync10(dirname10(path2), { recursive: true });
20188
+ writeFileSync8(path2, `${installId}
19788
20189
  `, { mode: 384 });
19789
20190
  } catch {
19790
20191
  }
@@ -19971,17 +20372,17 @@ var init_linzumiApiClient = __esm({
19971
20372
  });
19972
20373
 
19973
20374
  // src/authCache.ts
19974
- import { existsSync as existsSync11, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
19975
- import { homedir as homedir11 } from "node:os";
19976
- import { dirname as dirname11, join as join16 } from "node:path";
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";
19977
20378
  function defaultAuthFilePath() {
19978
- return join16(homedir11(), ".linzumi", "auth.json");
20379
+ return join18(homedir12(), ".linzumi", "auth.json");
19979
20380
  }
19980
20381
  function readCachedLocalRunnerToken(kandanUrl, authFilePath = defaultAuthFilePath()) {
19981
20382
  if (!existsSync11(authFilePath)) {
19982
20383
  return void 0;
19983
20384
  }
19984
- const authFile = parseAuthFile(readFileSync13(authFilePath, "utf8"));
20385
+ const authFile = parseAuthFile(readFileSync14(authFilePath, "utf8"));
19985
20386
  const kandanBaseUrl = kandanHttpBaseUrl(kandanUrl);
19986
20387
  const entry = authFile.local_codex_runner?.[kandanBaseUrl];
19987
20388
  if (entry === void 0 || entry.access_token.trim() === "") {
@@ -20003,7 +20404,7 @@ function readPersonalAgentDelegationToken(authFilePath) {
20003
20404
  `missing personal-agent delegation auth file: ${authFilePath}`
20004
20405
  );
20005
20406
  }
20006
- const authFile = parseAuthFile(readFileSync13(authFilePath, "utf8"));
20407
+ const authFile = parseAuthFile(readFileSync14(authFilePath, "utf8"));
20007
20408
  const entry = authFile.personal_agent_delegation;
20008
20409
  if (entry === void 0 || entry.access_token.trim() === "") {
20009
20410
  throw new Error(
@@ -20021,7 +20422,7 @@ function readPersonalAgentDelegationToken(authFilePath) {
20021
20422
  }
20022
20423
  function writeCachedLocalRunnerToken(args) {
20023
20424
  const authFilePath = args.authFilePath ?? defaultAuthFilePath();
20024
- const existing = existsSync11(authFilePath) ? parseAuthFile(readFileSync13(authFilePath, "utf8")) : { version: 1 };
20425
+ const existing = existsSync11(authFilePath) ? parseAuthFile(readFileSync14(authFilePath, "utf8")) : { version: 1 };
20025
20426
  const kandanBaseUrl = kandanHttpBaseUrl(args.kandanUrl);
20026
20427
  const issuedAt = /* @__PURE__ */ new Date();
20027
20428
  const expiresAt = args.expiresInSeconds === void 0 ? void 0 : new Date(
@@ -20039,8 +20440,8 @@ function writeCachedLocalRunnerToken(args) {
20039
20440
  }
20040
20441
  }
20041
20442
  };
20042
- mkdirSync10(dirname11(authFilePath), { recursive: true });
20043
- writeFileSync8(authFilePath, `${JSON.stringify(next, null, 2)}
20443
+ mkdirSync11(dirname11(authFilePath), { recursive: true });
20444
+ writeFileSync9(authFilePath, `${JSON.stringify(next, null, 2)}
20044
20445
  `, "utf8");
20045
20446
  return {
20046
20447
  accessToken: args.accessToken,
@@ -20485,9 +20886,9 @@ var init_threadCodexWorkerIpc = __esm({
20485
20886
 
20486
20887
  // src/signupTaskSuggestions.ts
20487
20888
  import { spawn as spawn7 } from "node:child_process";
20488
- import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync14, rmSync as rmSync3, writeFileSync as writeFileSync9 } from "node:fs";
20889
+ import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync15, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
20489
20890
  import { tmpdir as tmpdir2 } from "node:os";
20490
- import { join as join17 } from "node:path";
20891
+ import { join as join19 } from "node:path";
20491
20892
  async function suggestSignupTasksWithCodex(args) {
20492
20893
  const attempts = 2;
20493
20894
  let previousResponse;
@@ -20509,11 +20910,11 @@ async function suggestSignupTasksWithCodex(args) {
20509
20910
  );
20510
20911
  }
20511
20912
  async function runCodexTaskSuggestion(args) {
20512
- const tempRoot = mkdtempSync3(join17(tmpdir2(), "linzumi-signup-codex-tasks-"));
20513
- const schemaPath = join17(tempRoot, "task-suggestions.schema.json");
20514
- const outputPath = join17(tempRoot, "task-suggestions.json");
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");
20515
20916
  const prompt = taskSuggestionPrompt(args.previousResponse);
20516
- writeFileSync9(
20917
+ writeFileSync10(
20517
20918
  schemaPath,
20518
20919
  `${JSON.stringify(taskSuggestionJsonSchema(), null, 2)}
20519
20920
  `,
@@ -20530,9 +20931,9 @@ async function runCodexTaskSuggestion(args) {
20530
20931
  prompt
20531
20932
  })
20532
20933
  );
20533
- return readFileSync14(outputPath, "utf8");
20934
+ return readFileSync15(outputPath, "utf8");
20534
20935
  } finally {
20535
- rmSync3(tempRoot, { recursive: true, force: true });
20936
+ rmSync4(tempRoot, { recursive: true, force: true });
20536
20937
  }
20537
20938
  }
20538
20939
  function codexTaskSuggestionProcess(args) {
@@ -20979,25 +21380,25 @@ import { createHash as createHash5, randomUUID as randomUUID4 } from "node:crypt
20979
21380
  import {
20980
21381
  chmodSync as chmodSync2,
20981
21382
  lstatSync,
20982
- mkdirSync as mkdirSync11,
21383
+ mkdirSync as mkdirSync12,
20983
21384
  mkdtempSync as mkdtempSync4,
20984
21385
  readdirSync as readdirSync4,
20985
- readFileSync as readFileSync15,
21386
+ readFileSync as readFileSync16,
20986
21387
  realpathSync as realpathSync6,
20987
21388
  renameSync as renameSync3,
20988
- rmSync as rmSync4,
21389
+ rmSync as rmSync5,
20989
21390
  statSync as statSync3,
20990
- writeFileSync as writeFileSync10
21391
+ writeFileSync as writeFileSync11
20991
21392
  } from "node:fs";
20992
21393
  import { readFile as readFile2 } from "node:fs/promises";
20993
21394
  import { createServer as createServer3 } from "node:http";
20994
- 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";
20995
21396
  import {
20996
21397
  basename as basename8,
20997
21398
  dirname as dirname13,
20998
21399
  extname as extname2,
20999
21400
  isAbsolute as isAbsolute5,
21000
- join as join18,
21401
+ join as join20,
21001
21402
  resolve as resolve8
21002
21403
  } from "node:path";
21003
21404
  async function runLocalCodexRunner(options) {
@@ -21243,6 +21644,9 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
21243
21644
  defaultAgentProvider: "codex",
21244
21645
  startInstance: allowedCwds.value.length > 0,
21245
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).
21246
21650
  claudeCodeCheckpointRewind: false,
21247
21651
  allowedCwds: allowedCwds.value,
21248
21652
  missingAllowedCwds: missingAllowedCwds.value,
@@ -22333,13 +22737,14 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
22333
22737
  if (workspaceSlug === void 0 || channelSlug === void 0 || kandanThreadId === void 0) {
22334
22738
  return void 0;
22335
22739
  }
22336
- const waferResolution = resolveControlWaferModelProvider(control);
22337
- if (waferResolution.type === "error") {
22740
+ const providerResolution = resolveControlCodexModelProvider(control);
22741
+ const providerResolutionError = codexModelProviderResolutionError(providerResolution);
22742
+ if (providerResolutionError !== void 0) {
22338
22743
  return {
22339
22744
  instanceId,
22340
22745
  controlType: control.type,
22341
22746
  ok: false,
22342
- error: waferResolution.error,
22747
+ error: providerResolutionError,
22343
22748
  kandanThreadId,
22344
22749
  cwd
22345
22750
  };
@@ -22954,14 +23359,14 @@ function commanderOutboxPersistDir() {
22954
23359
  if (override !== void 0 && override !== "") {
22955
23360
  return override;
22956
23361
  }
22957
- return join18(homedir12(), ".linzumi", "commander-outbox");
23362
+ return join20(homedir13(), ".linzumi", "commander-outbox");
22958
23363
  }
22959
23364
  function controlCursorStorePath(runnerId) {
22960
23365
  const sanitized = runnerId.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 80);
22961
23366
  const digest = createHash5("sha256").update(runnerId).digest("hex").slice(0, 8);
22962
23367
  const stem = sanitized === "" ? "runner" : sanitized;
22963
- return join18(
22964
- homedir12(),
23368
+ return join20(
23369
+ homedir13(),
22965
23370
  ".linzumi",
22966
23371
  "control-cursors",
22967
23372
  `${stem}.${digest}.json`
@@ -22971,8 +23376,8 @@ function appliedStartTurnStorePath(runnerId) {
22971
23376
  const sanitized = runnerId.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 80);
22972
23377
  const digest = createHash5("sha256").update(runnerId).digest("hex").slice(0, 8);
22973
23378
  const stem = sanitized === "" ? "runner" : sanitized;
22974
- return join18(
22975
- homedir12(),
23379
+ return join20(
23380
+ homedir13(),
22976
23381
  ".linzumi",
22977
23382
  "control-cursors",
22978
23383
  `${stem}.${digest}.start-turn.json`
@@ -23094,9 +23499,9 @@ function createControlCursorFileStore(path2, log2, options) {
23094
23499
  }
23095
23500
  dirty = false;
23096
23501
  try {
23097
- mkdirSync11(dirname13(path2), { recursive: true });
23502
+ mkdirSync12(dirname13(path2), { recursive: true });
23098
23503
  const tmpPath = `${path2}.tmp`;
23099
- writeFileSync10(
23504
+ writeFileSync11(
23100
23505
  tmpPath,
23101
23506
  `${JSON.stringify({
23102
23507
  ...epoch === void 0 ? {} : { [controlCursorEpochKey]: epoch },
@@ -23204,7 +23609,7 @@ function readControlCursorFile(path2, log2) {
23204
23609
  const cursors = /* @__PURE__ */ new Map();
23205
23610
  let raw;
23206
23611
  try {
23207
- raw = readFileSync15(path2, "utf8");
23612
+ raw = readFileSync16(path2, "utf8");
23208
23613
  } catch (error) {
23209
23614
  if (!isErrnoCode2(error, "ENOENT")) {
23210
23615
  log2("control_cursor_store.read_failed", {
@@ -23798,18 +24203,18 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
23798
24203
  return delegated;
23799
24204
  }
23800
24205
  if (agentProvider === "codex") {
23801
- const waferControlError = waferModelProviderControlError(
24206
+ const providerControlError = codexModelProviderControlError(
23802
24207
  options,
23803
24208
  control
23804
24209
  );
23805
- if (waferControlError !== void 0) {
24210
+ if (providerControlError !== void 0) {
23806
24211
  try {
23807
24212
  await publishStartInstanceMessageState(
23808
24213
  kandan,
23809
24214
  topic,
23810
24215
  control,
23811
24216
  "failed",
23812
- waferControlError,
24217
+ providerControlError,
23813
24218
  { instanceId }
23814
24219
  );
23815
24220
  } catch (error) {
@@ -23821,7 +24226,7 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
23821
24226
  instanceId,
23822
24227
  controlType: control.type,
23823
24228
  ok: false,
23824
- error: waferControlError
24229
+ error: providerControlError
23825
24230
  };
23826
24231
  }
23827
24232
  }
@@ -23969,16 +24374,16 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
23969
24374
  return delegated;
23970
24375
  }
23971
24376
  if (agentProvider === "codex") {
23972
- const waferControlError = waferModelProviderControlError(
24377
+ const providerControlError = codexModelProviderControlError(
23973
24378
  options,
23974
24379
  control
23975
24380
  );
23976
- if (waferControlError !== void 0) {
24381
+ if (providerControlError !== void 0) {
23977
24382
  return {
23978
24383
  instanceId,
23979
24384
  controlType: control.type,
23980
24385
  ok: false,
23981
- error: waferControlError
24386
+ error: providerControlError
23982
24387
  };
23983
24388
  }
23984
24389
  }
@@ -24299,18 +24704,30 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
24299
24704
  error: "claude_code_steer_requires_text_input"
24300
24705
  };
24301
24706
  }
24302
- await claudeSession.interruptTurn("Steered by Linzumi");
24303
- claudeSession.enqueueInput({
24304
- content: `You were interrupted mid-task. Updated guidance from the user - continue the task with this in mind:
24305
-
24306
- ${steerText}`,
24307
- sourceSeq: claudeSession.currentSourceSeq()
24308
- });
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
+ }
24309
24726
  return {
24310
24727
  instanceId,
24311
24728
  controlType: control.type,
24312
24729
  agentProvider: "claude-code",
24313
- steered: "steered_via_restart",
24730
+ steered,
24314
24731
  threadId: control.threadId
24315
24732
  };
24316
24733
  }
@@ -24349,6 +24766,30 @@ ${steerText}`,
24349
24766
  response
24350
24767
  };
24351
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
+ }
24352
24793
  case "interrupt_queued_messages": {
24353
24794
  const agentProvider = stringValue(control.agentProvider)?.trim();
24354
24795
  if (agentProvider !== "claude-code") {
@@ -24816,10 +25257,24 @@ function startInstanceAgentLabel(provider) {
24816
25257
  return "Claude Code";
24817
25258
  }
24818
25259
  }
24819
- function resolveControlWaferModelProvider(control) {
25260
+ function resolveControlCodexModelProvider(control) {
24820
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;
24821
25266
  if (modelProvider === void 0 || modelProvider === "") {
24822
- 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
+ };
24823
25278
  }
24824
25279
  if (modelProvider !== "wafer") {
24825
25280
  return {
@@ -24827,40 +25282,84 @@ function resolveControlWaferModelProvider(control) {
24827
25282
  error: `model_provider_unsupported:${modelProvider}`
24828
25283
  };
24829
25284
  }
24830
- const llmProxy = objectValue(control.llmProxy);
24831
- const baseUrl = stringValue(llmProxy?.baseUrl)?.trim();
24832
- const token = stringValue(llmProxy?.token)?.trim();
24833
- if (baseUrl === void 0 || baseUrl === "" || token === void 0 || token === "") {
25285
+ if (binding === void 0) {
24834
25286
  return { type: "error", error: "wafer_model_provider_missing_llm_proxy" };
24835
25287
  }
24836
25288
  return {
24837
- type: "wafer",
25289
+ type: "provider",
24838
25290
  runtime: {
24839
25291
  provider: "wafer",
24840
- llmProxyBaseUrl: baseUrl,
24841
- llmProxyToken: token
25292
+ llmProxyBaseUrl: binding.baseUrl,
25293
+ llmProxyToken: binding.token
24842
25294
  }
24843
25295
  };
24844
25296
  }
24845
- function waferModelProviderControlError(options, control) {
24846
- 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);
24847
25308
  switch (resolution.type) {
24848
25309
  case "none":
24849
25310
  return void 0;
24850
25311
  case "error":
24851
25312
  return resolution.error;
24852
- case "wafer":
24853
- 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
+ }
24854
25320
  }
24855
25321
  }
24856
25322
  function linzumiCodexModelProviderConfig(runtime) {
24857
- return {
24858
- id: "linzumi",
24859
- name: "Linzumi Proxy",
24860
- baseUrl: `${runtime.llmProxyBaseUrl.replace(/\/+$/, "")}/v1`,
24861
- envKey: "LINZUMI_LLM_PROXY_TOKEN",
24862
- wireApi: "responses"
24863
- };
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
+ }
24864
25363
  }
24865
25364
  async function startCodexProviderInstance(args) {
24866
25365
  if (args.options.codexUrl === void 0) {
@@ -24985,6 +25484,23 @@ function createClaudeCodeInputQueue(input) {
24985
25484
  }
24986
25485
  waiter({ done: false, value: message });
24987
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
+ };
24988
25504
  return {
24989
25505
  messages: {
24990
25506
  [Symbol.asyncIterator]() {
@@ -25010,6 +25526,7 @@ function createClaudeCodeInputQueue(input) {
25010
25526
  drainClosedWaiters();
25011
25527
  },
25012
25528
  enqueue,
25529
+ enqueueSteer,
25013
25530
  completeTurn: () => pendingSourceSeqs.shift(),
25014
25531
  currentSourceSeq: () => pendingSourceSeqs[0]
25015
25532
  };
@@ -25331,6 +25848,24 @@ async function startClaudeCodeProviderInstance(args) {
25331
25848
  onTodoWriteCompleted: planMirror.handleTodoWrite,
25332
25849
  log: args.log
25333
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;
25334
25869
  let mcpAuthCleanup;
25335
25870
  let mcpServers;
25336
25871
  try {
@@ -25435,6 +25970,7 @@ async function startClaudeCodeProviderInstance(args) {
25435
25970
  threadId,
25436
25971
  currentSourceSeq: inputQueue.currentSourceSeq,
25437
25972
  enqueueInput: inputQueue.enqueue,
25973
+ steerTurn: inputQueue.enqueueSteer,
25438
25974
  interruptTurn: async (reason) => {
25439
25975
  const aborted = adapter.interruptActiveTurn(reason);
25440
25976
  await sessionControls?.interrupt();
@@ -25493,6 +26029,22 @@ async function startClaudeCodeProviderInstance(args) {
25493
26029
  if (event.type === "rate_limit") {
25494
26030
  await reportClaudeCodeRateLimit(event);
25495
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
+ }
25496
26048
  adapter.handleTranscriptEvent(event);
25497
26049
  };
25498
26050
  const llmProxy = objectValue(args.control.llmProxy);
@@ -25539,6 +26091,10 @@ async function startClaudeCodeProviderInstance(args) {
25539
26091
  runner: args.options.claudeCodeRunner,
25540
26092
  canUseTool,
25541
26093
  ...mcpServers === void 0 ? {} : { mcpServers },
26094
+ ...liveBashCapture === void 0 ? {} : {
26095
+ preToolUseHookMatchers: liveBashCapture.hookMatchers,
26096
+ wrapApprovedToolInput: (toolUseId, toolName2, input) => toolName2 === "Bash" ? liveBashCapture.wrapApprovedTool(toolUseId, input) : void 0
26097
+ },
25542
26098
  env: sessionEnv,
25543
26099
  // The built-in Linzumi MCP is trusted like the codex side: its tools
25544
26100
  // run without an approval round-trip. SDK allowedTools matches MCP
@@ -25555,6 +26111,7 @@ async function startClaudeCodeProviderInstance(args) {
25555
26111
  } finally {
25556
26112
  inputQueue.close();
25557
26113
  mcpAuthCleanup?.();
26114
+ liveBashCapture?.close();
25558
26115
  if (activeSessionId !== void 0) {
25559
26116
  args.activeClaudeCodeSessions.delete(activeSessionId);
25560
26117
  await args.disposeClaudeCodeForwardPortSession?.(activeSessionId);
@@ -25710,6 +26267,8 @@ function claudeSessionStoreEntryPayload(args, event) {
25710
26267
  itemKey: event.itemKey,
25711
26268
  body: event.content
25712
26269
  };
26270
+ case "command_output_delta":
26271
+ return void 0;
25713
26272
  case "usage":
25714
26273
  return { usage: event.usage };
25715
26274
  case "rate_limit":
@@ -26128,7 +26687,7 @@ function threadRunnerOptions(args) {
26128
26687
  args.options,
26129
26688
  args.control
26130
26689
  );
26131
- const waferResolution = resolveControlWaferModelProvider(args.control);
26690
+ const providerResolution = resolveControlCodexModelProvider(args.control);
26132
26691
  return {
26133
26692
  ...args.options,
26134
26693
  clientId: void 0,
@@ -26145,7 +26704,7 @@ function threadRunnerOptions(args) {
26145
26704
  role: "thread",
26146
26705
  kandanThreadId: args.kandanThreadId
26147
26706
  },
26148
- codexModelProvider: waferResolution.type === "wafer" ? waferResolution.runtime : void 0,
26707
+ codexModelProvider: providerResolution.type === "provider" ? providerResolution.runtime : void 0,
26149
26708
  spawnThreadRunner: void 0,
26150
26709
  threadRunnerReadyTimeoutMs: args.options.threadRunnerReadyTimeoutMs,
26151
26710
  runtimeDefaults: {
@@ -26182,6 +26741,7 @@ async function spawnLocalThreadRunnerProcess(options) {
26182
26741
  scriptPath,
26183
26742
  redactedThreadRunnerCliArgs(args)
26184
26743
  );
26744
+ const forwardableOpenAiApiKey = options.codexModelProvider?.provider === "openai-proxy" ? resolveForwardableOpenAiApiKey() : void 0;
26185
26745
  const env = {
26186
26746
  ...process.env,
26187
26747
  LINZUMI_THREAD_RUNNER_ROLE: "thread",
@@ -26189,7 +26749,8 @@ async function spawnLocalThreadRunnerProcess(options) {
26189
26749
  LINZUMI_THREAD_RUNNER_TOKEN: options.token,
26190
26750
  // The LLM proxy credential travels via env (like the runner token), not
26191
26751
  // argv, so the spawned worker's command line never carries it.
26192
- ...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 }
26193
26754
  };
26194
26755
  writeCliAuditEvent("process.spawn", {
26195
26756
  command: process.execPath,
@@ -27395,16 +27956,16 @@ async function startOwnedCodexAppServer(options, args = { linzumiMcp: true }) {
27395
27956
  model: defaults.model,
27396
27957
  reasoningEffort: defaults.reasoningEffort,
27397
27958
  fast: options.fast,
27398
- // Wafer-routed thread workers point their owned app-server at the
27399
- // Kandan LLM proxy via a custom Linzumi model provider; the proxy
27400
- // credential rides env_key plus the session header.
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.
27401
27964
  ...options.codexModelProvider === void 0 ? {} : {
27402
27965
  modelProvider: linzumiCodexModelProviderConfig(
27403
27966
  options.codexModelProvider
27404
27967
  ),
27405
- env: {
27406
- LINZUMI_LLM_PROXY_TOKEN: options.codexModelProvider.llmProxyToken
27407
- }
27968
+ env: codexModelProviderAppServerEnv(options.codexModelProvider)
27408
27969
  },
27409
27970
  mcpServers: mcpAuth === void 0 ? [] : [
27410
27971
  linzumiMcpServerConfig({
@@ -27452,9 +28013,9 @@ function mcpOwnerUsername(options) {
27452
28013
  return options.channelSession?.listenUser ?? identityFromAccessToken(options.token).actorUsername;
27453
28014
  }
27454
28015
  function writeEphemeralMcpAuthFile(options) {
27455
- const directory = mkdtempSync4(join18(tmpdir3(), "linzumi-mcp-auth-"));
28016
+ const directory = mkdtempSync4(join20(tmpdir3(), "linzumi-mcp-auth-"));
27456
28017
  chmodSync2(directory, 448);
27457
- const path2 = join18(directory, "auth.json");
28018
+ const path2 = join20(directory, "auth.json");
27458
28019
  writeCachedLocalRunnerToken({
27459
28020
  kandanUrl: options.kandanUrl,
27460
28021
  accessToken: options.token,
@@ -27463,7 +28024,7 @@ function writeEphemeralMcpAuthFile(options) {
27463
28024
  chmodSync2(path2, 384);
27464
28025
  return {
27465
28026
  path: path2,
27466
- cleanup: () => rmSync4(directory, { recursive: true, force: true })
28027
+ cleanup: () => rmSync5(directory, { recursive: true, force: true })
27467
28028
  };
27468
28029
  }
27469
28030
  function once(action) {
@@ -27530,7 +28091,7 @@ function configuredAllowedCwds(values, options = {}) {
27530
28091
  const absolutePath = resolve8(expandUserPath(value));
27531
28092
  try {
27532
28093
  if (options.createMissing === true) {
27533
- mkdirSync11(absolutePath, { recursive: true });
28094
+ mkdirSync12(absolutePath, { recursive: true });
27534
28095
  }
27535
28096
  const realPath = realpathSync6(absolutePath);
27536
28097
  allowedCwds.push(
@@ -27567,7 +28128,7 @@ function allowedCwdProjects(allowedCwds) {
27567
28128
  });
27568
28129
  }
27569
28130
  function isGitProjectDirectory(cwd) {
27570
- const gitPath = join18(cwd, ".git");
28131
+ const gitPath = join20(cwd, ".git");
27571
28132
  try {
27572
28133
  const gitPathStats = statSync3(gitPath);
27573
28134
  return gitPathStats.isDirectory() || gitPathStats.isFile();
@@ -27592,7 +28153,7 @@ function browseRunnerDirectory(control, options) {
27592
28153
  }
27593
28154
  const parent = dirname13(currentPath);
27594
28155
  const entries = readdirSync4(currentPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => visibleRunnerDirectoryEntryName(entry.name)).map((entry) => {
27595
- const path2 = join18(currentPath, entry.name);
28156
+ const path2 = join20(currentPath, entry.name);
27596
28157
  return {
27597
28158
  name: entry.name,
27598
28159
  path: path2,
@@ -27633,7 +28194,7 @@ function projectDirectoryName(name) {
27633
28194
  function availableProjectDirectoryName(projectsRoot, baseName, suffix = 0) {
27634
28195
  for (let nextSuffix = suffix; ; nextSuffix += 1) {
27635
28196
  const candidate = nextSuffix === 0 ? baseName : `${baseName}-${nextSuffix}`;
27636
- if (!projectPathExists(join18(projectsRoot, candidate))) {
28197
+ if (!projectPathExists(join20(projectsRoot, candidate))) {
27637
28198
  return candidate;
27638
28199
  }
27639
28200
  }
@@ -27661,9 +28222,9 @@ function createRunnerProject(control, options, allowedCwds) {
27661
28222
  error: "invalid_project_template"
27662
28223
  };
27663
28224
  }
27664
- const projectsRoot = join18(currentHomeDirectory(), "linzumi");
28225
+ const projectsRoot = join20(currentHomeDirectory(), "linzumi");
27665
28226
  const resolvedProjectDirName = template === "hello_linzumi_demo" ? availableProjectDirectoryName(projectsRoot, projectDirName) : projectDirName;
27666
- const projectPath = join18(projectsRoot, resolvedProjectDirName);
28227
+ const projectPath = join20(projectsRoot, resolvedProjectDirName);
27667
28228
  let createdProjectPath = false;
27668
28229
  try {
27669
28230
  if (template !== "hello_linzumi_demo" && projectPathExists(projectPath)) {
@@ -27675,7 +28236,7 @@ function createRunnerProject(control, options, allowedCwds) {
27675
28236
  error: "project_directory_exists"
27676
28237
  };
27677
28238
  }
27678
- mkdirSync11(projectsRoot, { recursive: true });
28239
+ mkdirSync12(projectsRoot, { recursive: true });
27679
28240
  if (template === "hello_linzumi_demo") {
27680
28241
  createdProjectPath = true;
27681
28242
  createHelloLinzumiProject({
@@ -27683,7 +28244,7 @@ function createRunnerProject(control, options, allowedCwds) {
27683
28244
  name: resolvedProjectDirName
27684
28245
  });
27685
28246
  } else {
27686
- mkdirSync11(projectPath, { recursive: false });
28247
+ mkdirSync12(projectPath, { recursive: false });
27687
28248
  createdProjectPath = true;
27688
28249
  }
27689
28250
  const git = spawnSync5("git", ["init"], {
@@ -27741,7 +28302,7 @@ function createRunnerProject(control, options, allowedCwds) {
27741
28302
  }
27742
28303
  function removeCreatedProjectDirectory(projectPath) {
27743
28304
  try {
27744
- rmSync4(projectPath, { recursive: true, force: true });
28305
+ rmSync5(projectPath, { recursive: true, force: true });
27745
28306
  return void 0;
27746
28307
  } catch (error) {
27747
28308
  return error instanceof Error ? error.message : "cleanup_failed";
@@ -27805,6 +28366,7 @@ var init_runner = __esm({
27805
28366
  init_commanderAttachments();
27806
28367
  init_claudeCodePipeline();
27807
28368
  init_claudeCodePlanMirror();
28369
+ init_claudeCodeLiveBashOutput();
27808
28370
  init_claudeCodeSession();
27809
28371
  init_codexAppServer();
27810
28372
  init_codexProjectTrust();
@@ -27866,7 +28428,7 @@ var init_runner = __esm({
27866
28428
  });
27867
28429
 
27868
28430
  // src/kandanTls.ts
27869
- import { existsSync as existsSync13, readFileSync as readFileSync16 } from "node:fs";
28431
+ import { existsSync as existsSync13, readFileSync as readFileSync17 } from "node:fs";
27870
28432
  import { Agent } from "undici";
27871
28433
  import WsWebSocket from "ws";
27872
28434
  function kandanTlsTrustFromEnv() {
@@ -27880,7 +28442,7 @@ function kandanTlsTrustFromCaFile(caFile) {
27880
28442
  if (!existsSync13(trimmed)) {
27881
28443
  throw new Error(`KANDAN_TLS_CA_FILE does not exist: ${trimmed}`);
27882
28444
  }
27883
- const ca = readFileSync16(trimmed, "utf8");
28445
+ const ca = readFileSync17(trimmed, "utf8");
27884
28446
  return {
27885
28447
  caFile: trimmed,
27886
28448
  ca,
@@ -42989,9 +43551,9 @@ var require_internal = __commonJS({
42989
43551
  }
42990
43552
  InternalCodec.prototype.encoder = InternalEncoder;
42991
43553
  InternalCodec.prototype.decoder = InternalDecoder;
42992
- var StringDecoder = __require("string_decoder").StringDecoder;
43554
+ var StringDecoder2 = __require("string_decoder").StringDecoder;
42993
43555
  function InternalDecoder(options, codec) {
42994
- this.decoder = new StringDecoder(codec.enc);
43556
+ this.decoder = new StringDecoder2(codec.enc);
42995
43557
  }
42996
43558
  InternalDecoder.prototype.write = function(buf) {
42997
43559
  if (!Buffer4.isBuffer(buf)) {
@@ -46664,7 +47226,7 @@ var init_RemoveFileError = __esm({
46664
47226
 
46665
47227
  // ../../node_modules/@inquirer/external-editor/dist/esm/index.js
46666
47228
  import { spawn as spawn11, spawnSync as spawnSync6 } from "child_process";
46667
- import { readFileSync as readFileSync19, unlinkSync as unlinkSync3, writeFileSync as writeFileSync13 } from "fs";
47229
+ import { readFileSync as readFileSync20, unlinkSync as unlinkSync3, writeFileSync as writeFileSync14 } from "fs";
46668
47230
  import path from "node:path";
46669
47231
  import os from "node:os";
46670
47232
  import { randomUUID as randomUUID5 } from "node:crypto";
@@ -46781,14 +47343,14 @@ var init_esm5 = __esm({
46781
47343
  if (Object.prototype.hasOwnProperty.call(this.fileOptions, "mode")) {
46782
47344
  opt.mode = this.fileOptions.mode;
46783
47345
  }
46784
- writeFileSync13(this.tempFile, this.text, opt);
47346
+ writeFileSync14(this.tempFile, this.text, opt);
46785
47347
  } catch (createFileError) {
46786
47348
  throw new CreateFileError(createFileError);
46787
47349
  }
46788
47350
  }
46789
47351
  readTemporaryFile() {
46790
47352
  try {
46791
- const tempFileBuffer = readFileSync19(this.tempFile);
47353
+ const tempFileBuffer = readFileSync20(this.tempFile);
46792
47354
  if (tempFileBuffer.length === 0) {
46793
47355
  this.text = "";
46794
47356
  } else {
@@ -48157,17 +48719,17 @@ import { spawn as spawn12, spawnSync as spawnSync7 } from "node:child_process";
48157
48719
  import {
48158
48720
  existsSync as existsSync16,
48159
48721
  constants as fsConstants,
48160
- mkdirSync as mkdirSync14,
48722
+ mkdirSync as mkdirSync15,
48161
48723
  mkdtempSync as mkdtempSync5,
48162
- readFileSync as readFileSync20,
48724
+ readFileSync as readFileSync21,
48163
48725
  readdirSync as readdirSync5,
48164
- rmSync as rmSync5,
48726
+ rmSync as rmSync6,
48165
48727
  statSync as statSync4,
48166
- writeFileSync as writeFileSync14
48728
+ writeFileSync as writeFileSync15
48167
48729
  } from "node:fs";
48168
48730
  import { access } from "node:fs/promises";
48169
- import { homedir as homedir15, tmpdir as tmpdir4 } from "node:os";
48170
- import { delimiter as delimiter3, dirname as dirname16, join as join21, resolve as resolve10 } from "node:path";
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";
48171
48733
  import { stdin as defaultStdin, stdout as defaultStdout } from "node:process";
48172
48734
  import { emitKeypressEvents } from "node:readline";
48173
48735
  function signupHelpText() {
@@ -48288,7 +48850,7 @@ function defaultSignupDraftStore(serviceUrl) {
48288
48850
  }
48289
48851
  let parsed;
48290
48852
  try {
48291
- parsed = JSON.parse(readFileSync20(path2, "utf8"));
48853
+ parsed = JSON.parse(readFileSync21(path2, "utf8"));
48292
48854
  } catch (_error) {
48293
48855
  return void 0;
48294
48856
  }
@@ -48298,20 +48860,20 @@ function defaultSignupDraftStore(serviceUrl) {
48298
48860
  return comparableServiceUrl(parsed.serviceUrl) === comparableServiceUrl(serviceUrl) ? parsed : void 0;
48299
48861
  },
48300
48862
  write: (draft) => {
48301
- mkdirSync14(dirname16(path2), { recursive: true });
48302
- writeFileSync14(path2, `${JSON.stringify(draft, null, 2)}
48863
+ mkdirSync15(dirname16(path2), { recursive: true });
48864
+ writeFileSync15(path2, `${JSON.stringify(draft, null, 2)}
48303
48865
  `, {
48304
48866
  encoding: "utf8",
48305
48867
  mode: 384
48306
48868
  });
48307
48869
  },
48308
48870
  clear: () => {
48309
- rmSync5(path2, { force: true });
48871
+ rmSync6(path2, { force: true });
48310
48872
  }
48311
48873
  };
48312
48874
  }
48313
48875
  function defaultSignupDraftPath(serviceUrl) {
48314
- return join21(
48876
+ return join23(
48315
48877
  dirname16(localConfigPath()),
48316
48878
  `signup-draft.${localConfigScopeFileStem(serviceUrl)}.json`
48317
48879
  );
@@ -48346,8 +48908,8 @@ function defaultSignupTaskCacheStore(serviceUrl) {
48346
48908
  }
48347
48909
  }
48348
48910
  };
48349
- mkdirSync14(dirname16(path2), { recursive: true });
48350
- writeFileSync14(path2, `${JSON.stringify(next, null, 2)}
48911
+ mkdirSync15(dirname16(path2), { recursive: true });
48912
+ writeFileSync15(path2, `${JSON.stringify(next, null, 2)}
48351
48913
  `, {
48352
48914
  encoding: "utf8",
48353
48915
  mode: 384
@@ -48356,7 +48918,7 @@ function defaultSignupTaskCacheStore(serviceUrl) {
48356
48918
  };
48357
48919
  }
48358
48920
  function defaultSignupTaskCachePath(serviceUrl) {
48359
- return join21(
48921
+ return join23(
48360
48922
  dirname16(localConfigPath()),
48361
48923
  `signup-task-cache.${localConfigScopeFileStem(serviceUrl)}.json`
48362
48924
  );
@@ -48367,7 +48929,7 @@ function readSignupTaskCache(path2) {
48367
48929
  }
48368
48930
  let parsed;
48369
48931
  try {
48370
- parsed = JSON.parse(readFileSync20(path2, "utf8"));
48932
+ parsed = JSON.parse(readFileSync21(path2, "utf8"));
48371
48933
  } catch (_error) {
48372
48934
  return { version: 1, entries: {} };
48373
48935
  }
@@ -50252,7 +50814,7 @@ function autocompletePathSuggestions(pathInput) {
50252
50814
  try {
50253
50815
  const showHidden = prefix.startsWith(".");
50254
50816
  const currentPath = directoryExists(normalizedInput) ? [normalizedInput.replace(/\/$/, "") || "/"] : [];
50255
- const childPaths = readdirSync5(directoryPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => showHidden || !entry.name.startsWith(".")).map((entry) => join21(directoryPath, entry.name)).map((path2) => ({
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) => ({
50256
50818
  path: path2,
50257
50819
  score: fuzzyPathSegmentScore(path2.split("/").at(-1) ?? path2, prefix)
50258
50820
  })).filter((candidate) => candidate.score !== void 0).sort((left, right) => {
@@ -50498,7 +51060,7 @@ async function runSignupPreflights(runtime) {
50498
51060
  function defaultPreflightRuntime() {
50499
51061
  return {
50500
51062
  cwd: process.cwd(),
50501
- homeDir: homedir15(),
51063
+ homeDir: homedir16(),
50502
51064
  probeTool,
50503
51065
  readGitEmail,
50504
51066
  discoverCodeRoots,
@@ -50643,13 +51205,13 @@ async function suggestTasksWithCodex(projectPath, retryPolicy) {
50643
51205
  );
50644
51206
  }
50645
51207
  async function runCodexTaskSuggestion2(projectPath, previousResponse, retryPolicy) {
50646
- const tempRoot = mkdtempSync5(join21(tmpdir4(), "linzumi-signup-codex-tasks-"));
50647
- const schemaPath = join21(tempRoot, "task-suggestions.schema.json");
50648
- const outputPath = join21(tempRoot, "task-suggestions.json");
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");
50649
51211
  const model = process.env.LINZUMI_SIGNUP_TASK_MODEL ?? "gpt-5.4-mini";
50650
51212
  const prompt = taskSuggestionPrompt2(previousResponse);
50651
51213
  const codexCommand = await resolveSignupCodexCommand();
50652
- writeFileSync14(
51214
+ writeFileSync15(
50653
51215
  schemaPath,
50654
51216
  `${JSON.stringify(taskSuggestionJsonSchema2(), null, 2)}
50655
51217
  `,
@@ -50670,9 +51232,9 @@ async function runCodexTaskSuggestion2(projectPath, previousResponse, retryPolic
50670
51232
  ),
50671
51233
  retryPolicy
50672
51234
  );
50673
- return readFileSync20(outputPath, "utf8");
51235
+ return readFileSync21(outputPath, "utf8");
50674
51236
  } finally {
50675
- rmSync5(tempRoot, { recursive: true, force: true });
51237
+ rmSync6(tempRoot, { recursive: true, force: true });
50676
51238
  }
50677
51239
  }
50678
51240
  function codexTaskSuggestionProcess2(args) {
@@ -50707,7 +51269,7 @@ function codexTaskSuggestionProcess2(args) {
50707
51269
  function signupCodexTaskSuggestionProcessForTest(args) {
50708
51270
  return codexTaskSuggestionProcess2(args);
50709
51271
  }
50710
- async function resolveSignupCodexCommand(env = process.env, homeDir = homedir15(), executableExists = fileIsExecutable) {
51272
+ async function resolveSignupCodexCommand(env = process.env, homeDir = homedir16(), executableExists = fileIsExecutable) {
50711
51273
  const override = firstConfiguredValue([
50712
51274
  env.LINZUMI_SIGNUP_CODEX_BIN,
50713
51275
  env.LINZUMI_CODEX_BIN
@@ -50762,7 +51324,7 @@ function resolveHomePath(path2, homeDir) {
50762
51324
  return homeDir;
50763
51325
  }
50764
51326
  if (path2.startsWith("~/")) {
50765
- return join21(homeDir, path2.slice(2));
51327
+ return join23(homeDir, path2.slice(2));
50766
51328
  }
50767
51329
  return resolve10(path2);
50768
51330
  }
@@ -50775,9 +51337,9 @@ function commandLooksPathLike(command) {
50775
51337
  }
50776
51338
  function homeManagedCodexCandidates(homeDir) {
50777
51339
  return [
50778
- join21(homeDir, ".volta", "bin", "codex"),
50779
- join21(homeDir, ".local", "bin", "codex"),
50780
- join21(homeDir, "bin", "codex")
51340
+ join23(homeDir, ".volta", "bin", "codex"),
51341
+ join23(homeDir, ".local", "bin", "codex"),
51342
+ join23(homeDir, "bin", "codex")
50781
51343
  ];
50782
51344
  }
50783
51345
  async function firstExecutablePath(paths, executableExists) {
@@ -50792,7 +51354,7 @@ function commandPathCandidates(path2) {
50792
51354
  if (path2 === void 0 || path2.trim() === "") {
50793
51355
  return [];
50794
51356
  }
50795
- 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"));
50796
51358
  }
50797
51359
  async function fileIsExecutable(path2) {
50798
51360
  try {
@@ -51025,11 +51587,11 @@ function codexPreflightLocation(command, homeDir) {
51025
51587
  switch (command) {
51026
51588
  case "codex":
51027
51589
  return "on PATH";
51028
- case join21(homeDir, ".volta", "bin", "codex"):
51590
+ case join23(homeDir, ".volta", "bin", "codex"):
51029
51591
  return "via Volta";
51030
- case join21(homeDir, ".local", "bin", "codex"):
51592
+ case join23(homeDir, ".local", "bin", "codex"):
51031
51593
  return "via ~/.local/bin";
51032
- case join21(homeDir, "bin", "codex"):
51594
+ case join23(homeDir, "bin", "codex"):
51033
51595
  return "via ~/bin";
51034
51596
  default:
51035
51597
  return "from configured path";
@@ -51188,7 +51750,7 @@ function probeToolWithArgs(command, args, cwd) {
51188
51750
  }
51189
51751
  async function discoverCodeRoots(homeDir) {
51190
51752
  const candidates = ["src", "code", "projects"].map(
51191
- (name) => join21(homeDir, name)
51753
+ (name) => join23(homeDir, name)
51192
51754
  );
51193
51755
  return candidates.filter((path2) => existsSync16(path2)).flatMap((path2) => discoveredProjectNames(path2));
51194
51756
  }
@@ -51242,7 +51804,7 @@ function discoverProjectsFromCurrentDirectory(cwd) {
51242
51804
  }
51243
51805
  function discoverProjectsFromGuessedRoots(homeDir) {
51244
51806
  const guessedRoots = ["src", "code", "projects"].map(
51245
- (name) => join21(homeDir, name)
51807
+ (name) => join23(homeDir, name)
51246
51808
  );
51247
51809
  const projects = guessedRoots.flatMap(
51248
51810
  (root) => discoverProjectsUnderRoot(root)
@@ -51294,25 +51856,25 @@ function looksLikeProject(path2) {
51294
51856
  "pnpm-lock.yaml",
51295
51857
  "yarn.lock",
51296
51858
  "package-lock.json"
51297
- ].some((name) => existsSync16(join21(path2, name)));
51859
+ ].some((name) => existsSync16(join23(path2, name)));
51298
51860
  }
51299
51861
  function detectProjectLanguage(path2) {
51300
- if (existsSync16(join21(path2, "pyproject.toml")) || existsSync16(join21(path2, "requirements.txt"))) {
51862
+ if (existsSync16(join23(path2, "pyproject.toml")) || existsSync16(join23(path2, "requirements.txt"))) {
51301
51863
  return "Python";
51302
51864
  }
51303
- if (existsSync16(join21(path2, "Cargo.toml"))) {
51865
+ if (existsSync16(join23(path2, "Cargo.toml"))) {
51304
51866
  return "Rust";
51305
51867
  }
51306
- if (existsSync16(join21(path2, "go.mod"))) {
51868
+ if (existsSync16(join23(path2, "go.mod"))) {
51307
51869
  return "Go";
51308
51870
  }
51309
- if (existsSync16(join21(path2, "mix.exs"))) {
51871
+ if (existsSync16(join23(path2, "mix.exs"))) {
51310
51872
  return "Elixir";
51311
51873
  }
51312
- if (existsSync16(join21(path2, "tsconfig.json")) || packageJsonMentionsTypeScript(path2)) {
51874
+ if (existsSync16(join23(path2, "tsconfig.json")) || packageJsonMentionsTypeScript(path2)) {
51313
51875
  return "TypeScript";
51314
51876
  }
51315
- if (existsSync16(join21(path2, "package.json"))) {
51877
+ if (existsSync16(join23(path2, "package.json"))) {
51316
51878
  return "JavaScript";
51317
51879
  }
51318
51880
  return "Project";
@@ -51320,7 +51882,7 @@ function detectProjectLanguage(path2) {
51320
51882
  function packageJsonMentionsTypeScript(path2) {
51321
51883
  try {
51322
51884
  const packageJson2 = JSON.parse(
51323
- readFileSync20(join21(path2, "package.json"), "utf8")
51885
+ readFileSync21(join23(path2, "package.json"), "utf8")
51324
51886
  );
51325
51887
  return packageJson2.dependencies?.typescript !== void 0 || packageJson2.devDependencies?.typescript !== void 0;
51326
51888
  } catch {
@@ -51328,11 +51890,11 @@ function packageJsonMentionsTypeScript(path2) {
51328
51890
  }
51329
51891
  }
51330
51892
  function hasGitMetadata(path2) {
51331
- return existsSync16(join21(path2, ".git"));
51893
+ return existsSync16(join23(path2, ".git"));
51332
51894
  }
51333
51895
  function childDirectories(root) {
51334
51896
  try {
51335
- 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));
51336
51898
  } catch {
51337
51899
  return [];
51338
51900
  }
@@ -51358,10 +51920,10 @@ function directoryExists(path2) {
51358
51920
  }
51359
51921
  function expandHomePath(path2) {
51360
51922
  if (path2 === "~") {
51361
- return homedir15();
51923
+ return homedir16();
51362
51924
  }
51363
51925
  if (path2.startsWith("~/")) {
51364
- return join21(homedir15(), path2.slice(2));
51926
+ return join23(homedir16(), path2.slice(2));
51365
51927
  }
51366
51928
  return resolve10(path2);
51367
51929
  }
@@ -51451,8 +52013,8 @@ init_onboardingDiscoveryChildProcess();
51451
52013
  init_runner();
51452
52014
  init_claudeCodeSession();
51453
52015
  init_authCache();
51454
- import { existsSync as existsSync17, readFileSync as readFileSync21, realpathSync as realpathSync7 } from "node:fs";
51455
- 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";
51456
52018
  import { resolve as resolve11 } from "node:path";
51457
52019
  import { fileURLToPath as fileURLToPath4 } from "node:url";
51458
52020
 
@@ -51547,9 +52109,9 @@ init_kandanTls();
51547
52109
  init_protocol();
51548
52110
  init_json();
51549
52111
  init_defaultUrls();
51550
- import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "node:fs";
51551
- import { dirname as dirname14, join as join19 } from "node:path";
51552
- import { homedir as homedir13 } from "node:os";
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";
51553
52115
  async function runAgentCliCommand(args, deps = {
51554
52116
  fetchImpl: fetch,
51555
52117
  stdout: process.stdout,
@@ -52257,7 +52819,7 @@ function agentTokenFile(flags) {
52257
52819
  return flags.get("agent-token-file") ?? defaultAgentTokenFilePath();
52258
52820
  }
52259
52821
  function defaultAgentTokenFilePath() {
52260
- return join19(homedir13(), ".linzumi", "agent-token.json");
52822
+ return join21(homedir14(), ".linzumi", "agent-token.json");
52261
52823
  }
52262
52824
  function normalizedApiUrl(apiUrl) {
52263
52825
  return apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`;
@@ -52266,11 +52828,11 @@ function authorizationHeaders(token) {
52266
52828
  return { authorization: `Bearer ${token}` };
52267
52829
  }
52268
52830
  function readOptionalTextFile(path2) {
52269
- return existsSync14(path2) ? readFileSync17(path2, "utf8") : void 0;
52831
+ return existsSync14(path2) ? readFileSync18(path2, "utf8") : void 0;
52270
52832
  }
52271
52833
  function writeTextFile(path2, content) {
52272
- mkdirSync12(dirname14(path2), { recursive: true });
52273
- writeFileSync11(path2, content);
52834
+ mkdirSync13(dirname14(path2), { recursive: true });
52835
+ writeFileSync12(path2, content);
52274
52836
  }
52275
52837
  function readStoredAgentTokenFile(path2, readTextFile = readOptionalTextFile) {
52276
52838
  const content = readTextFile(path2);
@@ -52359,25 +52921,25 @@ init_runnerLogger();
52359
52921
  import {
52360
52922
  existsSync as existsSync15,
52361
52923
  closeSync as closeSync3,
52362
- mkdirSync as mkdirSync13,
52924
+ mkdirSync as mkdirSync14,
52363
52925
  openSync as openSync4,
52364
- readFileSync as readFileSync18,
52926
+ readFileSync as readFileSync19,
52365
52927
  watch,
52366
- writeFileSync as writeFileSync12
52928
+ writeFileSync as writeFileSync13
52367
52929
  } from "node:fs";
52368
- import { homedir as homedir14 } from "node:os";
52369
- import { dirname as dirname15, join as join20, resolve as resolve9 } from "node:path";
52930
+ import { homedir as homedir15 } from "node:os";
52931
+ import { dirname as dirname15, join as join22, resolve as resolve9 } from "node:path";
52370
52932
  import { execFileSync, spawn as spawn10 } from "node:child_process";
52371
52933
  import { fileURLToPath as fileURLToPath3 } from "node:url";
52372
52934
  var connectedMarkers = ["Connected to Linzumi", "Runner connected:"];
52373
52935
  function commanderStatusDir() {
52374
- return join20(homedir14(), ".linzumi", "commanders");
52936
+ return join22(homedir15(), ".linzumi", "commanders");
52375
52937
  }
52376
52938
  function commanderStatusFile(runnerId, statusDir = commanderStatusDir()) {
52377
- return join20(statusDir, `${safeRunnerId(runnerId)}.json`);
52939
+ return join22(statusDir, `${safeRunnerId(runnerId)}.json`);
52378
52940
  }
52379
52941
  function defaultCommanderLogFile(runnerId) {
52380
- return join20(homedir14(), ".linzumi", "logs", `${safeRunnerId(runnerId)}.log`);
52942
+ return join22(homedir15(), ".linzumi", "logs", `${safeRunnerId(runnerId)}.log`);
52381
52943
  }
52382
52944
  function commanderLogIsConnected(log2) {
52383
52945
  return connectedMarkers.some((marker) => log2.includes(marker));
@@ -52398,8 +52960,8 @@ function startCommanderDaemon(options) {
52398
52960
  "--log-file",
52399
52961
  logFile
52400
52962
  ];
52401
- mkdirSync13(statusDir, { recursive: true });
52402
- mkdirSync13(dirname15(logFile), { recursive: true });
52963
+ mkdirSync14(statusDir, { recursive: true });
52964
+ mkdirSync14(dirname15(logFile), { recursive: true });
52403
52965
  const out = openSync4(logFile, "a");
52404
52966
  const err = openSync4(logFile, "a");
52405
52967
  writeCliAuditEvent(
@@ -52445,7 +53007,7 @@ function startCommanderDaemon(options) {
52445
53007
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
52446
53008
  command: [nodeBin, ...command]
52447
53009
  };
52448
- writeFileSync12(statusFile, `${JSON.stringify(record, null, 2)}
53010
+ writeFileSync13(statusFile, `${JSON.stringify(record, null, 2)}
52449
53011
  `);
52450
53012
  return record;
52451
53013
  }
@@ -52454,12 +53016,12 @@ function commanderDaemonStatus(runnerId, statusDir = commanderStatusDir(), proce
52454
53016
  if (!existsSync15(statusFile)) {
52455
53017
  return { status: "missing", runnerId, statusFile };
52456
53018
  }
52457
- const record = parseRecord(readFileSync18(statusFile, "utf8"));
53019
+ const record = parseRecord(readFileSync19(statusFile, "utf8"));
52458
53020
  return processIsRunning(record.pid) && processMatchesRecord(record, processIdentityReader) ? { status: "running", record } : { status: "stopped", record };
52459
53021
  }
52460
53022
  async function waitForCommanderDaemon(options) {
52461
53023
  const now = options.now ?? (() => Date.now());
52462
- 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);
52463
53025
  const statusImpl = options.statusImpl ?? commanderDaemonStatus;
52464
53026
  const deadline = now() + options.timeoutMs;
52465
53027
  while (now() <= deadline) {
@@ -66401,7 +66963,7 @@ async function parseAgentRunnerArgs(args, deps = {
66401
66963
  };
66402
66964
  }
66403
66965
  function readAgentTokenTextFile(path2) {
66404
- return existsSync17(path2) ? readFileSync21(path2, "utf8") : void 0;
66966
+ return existsSync17(path2) ? readFileSync22(path2, "utf8") : void 0;
66405
66967
  }
66406
66968
  function rejectAgentRunnerTargetingFlags(values) {
66407
66969
  const unsupportedFlags = [
@@ -66711,10 +67273,10 @@ function rejectStartTargetingFlags(values) {
66711
67273
  }
66712
67274
  function resolveUserPath(pathValue) {
66713
67275
  if (pathValue === "~") {
66714
- return homedir16();
67276
+ return homedir17();
66715
67277
  }
66716
67278
  if (pathValue.startsWith("~/")) {
66717
- return resolve11(homedir16(), pathValue.slice(2));
67279
+ return resolve11(homedir17(), pathValue.slice(2));
66718
67280
  }
66719
67281
  return resolve11(pathValue);
66720
67282
  }
@@ -66817,21 +67379,23 @@ function threadRunnerCodexModelProvider(values) {
66817
67379
  if (modelProvider === void 0) {
66818
67380
  return void 0;
66819
67381
  }
66820
- if (modelProvider !== "wafer") {
67382
+ if (modelProvider !== "wafer" && modelProvider !== "openai-proxy") {
66821
67383
  throw new Error(`unsupported --model-provider: ${modelProvider}`);
66822
67384
  }
66823
67385
  const llmProxyBaseUrl = stringValue8(values, "llm-proxy-base-url");
66824
67386
  const llmProxyToken = process.env.LINZUMI_LLM_PROXY_TOKEN?.trim();
66825
67387
  if (llmProxyBaseUrl === void 0) {
66826
- 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
+ );
66827
67391
  }
66828
67392
  if (llmProxyToken === void 0 || llmProxyToken === "") {
66829
67393
  throw new Error(
66830
- "--model-provider wafer requires the LINZUMI_LLM_PROXY_TOKEN env credential"
67394
+ `--model-provider ${modelProvider} requires the LINZUMI_LLM_PROXY_TOKEN env credential`
66831
67395
  );
66832
67396
  }
66833
67397
  return {
66834
- provider: "wafer",
67398
+ provider: modelProvider,
66835
67399
  llmProxyBaseUrl,
66836
67400
  llmProxyToken
66837
67401
  };