@linzumi/cli 0.0.65-beta → 0.0.66-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,10 +33,6 @@ Paste this into your terminal:
33
33
  npx -y @linzumi/cli@latest signup
34
34
  ```
35
35
 
36
- ![Linzumi signup terminal flow showing local checks, selected repos, and started agents](docs/images/signup-terminal.png)
37
-
38
- ![Linzumi Mission Control with started agent work in a split-pane workspace](docs/images/signup-mission-control.png)
39
-
40
36
  Linzumi will ask for your email, send you a sign-in code, help you pick
41
37
  the repos where Codex may work, start useful first tasks, and open
42
38
  Mission Control in your browser with the work already running.
@@ -62,7 +58,7 @@ Install the CLI or run it with `npx`:
62
58
  ```bash
63
59
  npm install -g @linzumi/cli@latest
64
60
  npx -y @linzumi/cli@latest signup
65
- npx -y @linzumi/cli@0.0.65-beta --version
61
+ npx -y @linzumi/cli@0.0.66-beta --version
66
62
  linzumi --version
67
63
  ```
68
64
 
package/dist/index.js CHANGED
@@ -2175,6 +2175,7 @@ function startPortForwardWatcher(options) {
2175
2175
  const scanListenSockets = options.scanListenSockets ?? readListenSocketRows;
2176
2176
  const scanProcessCwds = options.scanProcessCwds ?? readProcessCwdRows;
2177
2177
  const nowMs = options.nowMs ?? Date.now;
2178
+ const commanderBoundPids = validPidSet(options.commanderBoundPids ?? []);
2178
2179
  const candidateStabilityByPort = /* @__PURE__ */ new Map();
2179
2180
  const emittedByPort = /* @__PURE__ */ new Map();
2180
2181
  const missingByPort = /* @__PURE__ */ new Map();
@@ -2187,11 +2188,13 @@ function startPortForwardWatcher(options) {
2187
2188
  void Promise.resolve().then(async () => {
2188
2189
  const descendants = descendantPidSet(scanProcesses(), rootPid);
2189
2190
  const sockets = scanListenSockets();
2190
- const candidatePids = sockets.filter((socket) => descendants.has(socket.pid)).map((socket) => socket.pid);
2191
+ const observedPids = /* @__PURE__ */ new Set([...descendants, ...commanderBoundPids]);
2192
+ const candidatePids = sockets.filter((socket) => observedPids.has(socket.pid)).map((socket) => socket.pid);
2191
2193
  const candidates = detectedForwardCandidates(
2192
2194
  sockets,
2193
- descendants,
2194
- scanProcessCwds(candidatePids)
2195
+ observedPids,
2196
+ scanProcessCwds(candidatePids),
2197
+ commanderBoundPids
2195
2198
  );
2196
2199
  const scanTimeMs = nowMs();
2197
2200
  const stable = stableForwardCandidates(
@@ -2289,7 +2292,7 @@ function stableForwardCandidates(previousObservedByPort, candidates, nowMs, debo
2289
2292
  return { nextObservedByPort, stableCandidates };
2290
2293
  }
2291
2294
  function sameForwardCandidate(left, right) {
2292
- return left.port === right.port && left.pid === right.pid;
2295
+ return left.port === right.port && left.pid === right.pid && normalizedPortKind(left.portKind) === normalizedPortKind(right.portKind);
2293
2296
  }
2294
2297
  function descendantPidSet(rows, rootPid) {
2295
2298
  const childrenByParent = /* @__PURE__ */ new Map();
@@ -2309,17 +2312,25 @@ function descendantPidSet(rows, rootPid) {
2309
2312
  }
2310
2313
  return descendants;
2311
2314
  }
2312
- function detectedForwardCandidates(sockets, descendantPids, processCwds = /* @__PURE__ */ new Map()) {
2315
+ function detectedForwardCandidates(sockets, descendantPids, processCwds = /* @__PURE__ */ new Map(), commanderBoundPids = /* @__PURE__ */ new Set()) {
2313
2316
  return sockets.filter((socket) => descendantPids.has(socket.pid)).filter((socket) => socket.port > 0 && socket.port < 65536).sort((left, right) => left.port - right.port).map((socket) => {
2314
2317
  const cwd = processCwds.get(socket.pid);
2318
+ const portKind = commanderBoundPids.size === 0 ? void 0 : commanderBoundPids.has(socket.pid) ? "commander_bound" : "descendant";
2315
2319
  return {
2316
2320
  port: socket.port,
2317
2321
  pid: socket.pid,
2318
2322
  command: socket.command,
2323
+ ...portKind === void 0 ? {} : { portKind },
2319
2324
  ...cwd === void 0 ? {} : { cwd }
2320
2325
  };
2321
2326
  });
2322
2327
  }
2328
+ function validPidSet(pids) {
2329
+ return new Set(pids.filter((pid) => Number.isInteger(pid) && pid > 0));
2330
+ }
2331
+ function normalizedPortKind(portKind) {
2332
+ return portKind ?? "descendant";
2333
+ }
2323
2334
  function parseProcessRows(output) {
2324
2335
  return output.split("\n").map((line) => line.trim()).filter((line) => line !== "").map((line) => {
2325
2336
  const match = line.match(/^(\d+)\s+(\d+)\s+(.*)$/);
@@ -2453,7 +2464,7 @@ var defaultIntervalMs, defaultDebounceMs;
2453
2464
  var init_portForwardWatcher = __esm({
2454
2465
  "src/portForwardWatcher.ts"() {
2455
2466
  "use strict";
2456
- defaultIntervalMs = 2e3;
2467
+ defaultIntervalMs = 1e3;
2457
2468
  defaultDebounceMs = 750;
2458
2469
  }
2459
2470
  });
@@ -2503,6 +2514,7 @@ function pendingRequestFromCandidate(options) {
2503
2514
  port: options.candidate.port,
2504
2515
  pid: options.candidate.pid,
2505
2516
  command: options.candidate.command,
2517
+ ...options.candidate.portKind === void 0 ? {} : { portKind: options.candidate.portKind },
2506
2518
  ...options.candidate.cwd === void 0 ? {} : { cwd: options.candidate.cwd },
2507
2519
  sourceSeq: options.sourceSeq
2508
2520
  };
@@ -2512,6 +2524,7 @@ function approvedTargetFromRequest(request) {
2512
2524
  port: request.port,
2513
2525
  pid: request.pid,
2514
2526
  command: request.command,
2527
+ ...request.portKind === void 0 ? {} : { portKind: request.portKind },
2515
2528
  ...request.cwd === void 0 ? {} : { cwd: request.cwd }
2516
2529
  };
2517
2530
  }
@@ -3726,13 +3739,7 @@ async function updateSessionSettings(args, state, payloadContext, control) {
3726
3739
  fast: state.runtimeSettings.fast ?? null,
3727
3740
  allow_port_forwarding_by_default: state.runtimeSettings.allowPortForwardingByDefault ?? null
3728
3741
  });
3729
- if (state.runtimeSettings.allowPortForwardingByDefault === true) {
3730
- await approvePendingPortForwardRequestsByDefault(
3731
- args,
3732
- state,
3733
- payloadContext
3734
- );
3735
- }
3742
+ await approvePendingPortForwardRequestsByDefault(args, state, payloadContext);
3736
3743
  await tryResumeCodexThreadForPendingRuntimeSettings(args, state);
3737
3744
  return {
3738
3745
  instanceId: args.instanceId,
@@ -3964,7 +3971,8 @@ async function approvePortForwardRequest(args, state, request, options) {
3964
3971
  codexThreadId: state.codexThreadId ?? null,
3965
3972
  channelSlug: args.options.channelSession.channelSlug ?? null,
3966
3973
  processName: processIdentity?.appName ?? null,
3967
- processIconKey: processIdentity?.iconKey ?? null
3974
+ processIconKey: processIdentity?.iconKey ?? null,
3975
+ linzumiCliManaged: request.portKind === "commander_bound"
3968
3976
  });
3969
3977
  await publishForwardPortResolvedEvent(args, state, request, {
3970
3978
  decision: "approve",
@@ -4015,7 +4023,7 @@ async function publishPortForwardPrompt(args, state, payloadContext, candidate)
4015
4023
  dismissedTargets: state.dismissedForwardTargets,
4016
4024
  pendingRequests: Array.from(state.pendingPortForwardRequests.values())
4017
4025
  });
4018
- const allowByDefault = state.runtimeSettings.allowPortForwardingByDefault === true;
4026
+ const allowByDefault = true;
4019
4027
  switch (review.type) {
4020
4028
  case "skip":
4021
4029
  return;
@@ -6969,7 +6977,7 @@ function mergeRuntimeSettings(current, update) {
6969
6977
  ),
6970
6978
  sandbox,
6971
6979
  fast: update.fast ?? current.fast,
6972
- allowPortForwardingByDefault: update.allowPortForwardingByDefault ?? current.allowPortForwardingByDefault
6980
+ allowPortForwardingByDefault: true
6973
6981
  };
6974
6982
  }
6975
6983
  function mergeOptionalApprovalPolicyRuntimeSetting(current, update, sandbox) {
@@ -7989,7 +7997,9 @@ function linzumiMcpServerConfig(options) {
7989
7997
  options.kandanUrl,
7990
7998
  ...options.authFilePath === void 0 ? [] : ["--auth-file", options.authFilePath],
7991
7999
  ...options.delegationAuthFilePath === void 0 ? [] : ["--delegation-auth-file", options.delegationAuthFilePath],
7992
- ...options.ownerUsername === void 0 ? [] : ["--owner-username", options.ownerUsername]
8000
+ ...options.ownerUsername === void 0 ? [] : ["--owner-username", options.ownerUsername],
8001
+ "--mode",
8002
+ options.operatingMode ?? "text"
7993
8003
  ],
7994
8004
  env: {
7995
8005
  ...options.accessToken === void 0 ? {} : { LINZUMI_MCP_ACCESS_TOKEN: options.accessToken }
@@ -11685,7 +11695,7 @@ var linzumiCliVersion, linzumiCliVersionText;
11685
11695
  var init_version = __esm({
11686
11696
  "src/version.ts"() {
11687
11697
  "use strict";
11688
- linzumiCliVersion = "0.0.65-beta";
11698
+ linzumiCliVersion = "0.0.66-beta";
11689
11699
  linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
11690
11700
  }
11691
11701
  });
@@ -12819,6 +12829,7 @@ import {
12819
12829
  rmSync as rmSync3,
12820
12830
  statSync
12821
12831
  } from "node:fs";
12832
+ import { createServer as createServer3 } from "node:http";
12822
12833
  import { homedir as homedir8, hostname as hostname2, tmpdir as tmpdir3 } from "node:os";
12823
12834
  import { dirname as dirname7, join as join11, resolve as resolve6 } from "node:path";
12824
12835
  async function runLocalCodexRunner(options) {
@@ -12876,7 +12887,8 @@ async function runThreadCodexWorker(options) {
12876
12887
  bindThreadCodexWorkerIpc(codex);
12877
12888
  process.send({
12878
12889
  type: "linzumi_thread_codex_worker_ready",
12879
- kandanThreadId: options.threadProcess.kandanThreadId
12890
+ kandanThreadId: options.threadProcess.kandanThreadId,
12891
+ commanderManagedPorts: commanderManagedPortsForStartedCodex(started)
12880
12892
  });
12881
12893
  await waitForThreadCodexWorkerStop(started.process);
12882
12894
  stop();
@@ -12888,6 +12900,12 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
12888
12900
  const managedForwardPorts = /* @__PURE__ */ new Set();
12889
12901
  const kandanControlPort = explicitUrlPort(options.kandanUrl);
12890
12902
  const suppressedForwardPorts = () => suppressedForwardPortsForRunner(kandanControlPort, managedForwardPorts);
12903
+ const commanderBoundE2eHttpProbe = shouldStartCommanderBoundForwardWatcher(
12904
+ options
12905
+ ) ? await startCommanderBoundE2eHttpProbe(log) : void 0;
12906
+ if (commanderBoundE2eHttpProbe !== void 0) {
12907
+ cleanup.actions.push(() => commanderBoundE2eHttpProbe.close());
12908
+ }
12891
12909
  const forwardPortAttributions = /* @__PURE__ */ new Map();
12892
12910
  const setForwardPortAttribution = (port, attribution) => {
12893
12911
  forwardPortAttributions.set(port, {
@@ -12897,12 +12915,30 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
12897
12915
  processName: attribution.processName ?? null,
12898
12916
  processIconKey: attribution.processIconKey ?? null,
12899
12917
  localEditor: attribution.localEditor === true,
12900
- agentProvider: attribution.agentProvider ?? null
12918
+ agentProvider: attribution.agentProvider ?? null,
12919
+ linzumiCliManaged: attribution.linzumiCliManaged === true
12901
12920
  });
12902
12921
  };
12903
12922
  const clearForwardPortAttribution = (port) => {
12904
12923
  forwardPortAttributions.delete(port);
12905
12924
  };
12925
+ const markCommanderManagedForwardPort = (port, attribution = {}) => {
12926
+ liveForwardPorts.add(port);
12927
+ managedForwardPorts.add(port);
12928
+ setForwardPortAttribution(port, {
12929
+ processName: attribution.processName ?? null,
12930
+ processIconKey: attribution.processIconKey ?? null,
12931
+ agentProvider: attribution.agentProvider ?? null,
12932
+ linzumiCliManaged: true
12933
+ });
12934
+ };
12935
+ const clearCommanderManagedForwardPort = (port) => {
12936
+ managedForwardPorts.delete(port);
12937
+ clearForwardPortAttribution(port);
12938
+ if (!allowedForwardPorts.includes(port)) {
12939
+ liveForwardPorts.delete(port);
12940
+ }
12941
+ };
12906
12942
  const buildForwardPortAttributionPayload = () => Array.from(liveForwardPorts).sort((left, right) => left - right).map((port) => {
12907
12943
  const attribution = forwardPortAttributions.get(port);
12908
12944
  return {
@@ -12913,7 +12949,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
12913
12949
  processName: attribution?.processName ?? null,
12914
12950
  processIconKey: attribution?.processIconKey ?? null,
12915
12951
  localEditor: attribution?.localEditor === true,
12916
- agentProvider: attribution?.agentProvider ?? null
12952
+ agentProvider: attribution?.agentProvider ?? null,
12953
+ linzumiCliManaged: attribution?.linzumiCliManaged === true || managedForwardPorts.has(port)
12917
12954
  };
12918
12955
  });
12919
12956
  const startupAllowedCwds = normalizeAllowedCwds(options.allowedCwds);
@@ -13034,6 +13071,16 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13034
13071
  if (codexUrl === void 0) {
13035
13072
  throw new Error("missing codex app-server websocket URL");
13036
13073
  }
13074
+ if (started !== void 0) {
13075
+ const appServerPort = explicitUrlPort(codexUrl);
13076
+ if (appServerPort !== void 0) {
13077
+ markCommanderManagedForwardPort(appServerPort, {
13078
+ processName: "Codex app-server",
13079
+ processIconKey: "codex",
13080
+ agentProvider: "codex"
13081
+ });
13082
+ }
13083
+ }
13037
13084
  const instanceId = `codex-${randomUUID3()}`;
13038
13085
  const publishLocalEditorStatus = (payload) => {
13039
13086
  void kandan.push(topic, "local_editor_status", payload).catch((error) => {
@@ -13049,6 +13096,18 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13049
13096
  });
13050
13097
  });
13051
13098
  };
13099
+ const commanderBoundForwardWatcher = shouldStartCommanderBoundForwardWatcher(
13100
+ options
13101
+ ) ? startCommanderBoundForwardWatcher({
13102
+ log,
13103
+ instanceId,
13104
+ markCommanderManagedForwardPort,
13105
+ clearCommanderManagedForwardPort,
13106
+ managedForwardPorts,
13107
+ capabilitiesPayload,
13108
+ pushForwardPortEvent: pushEditorPortForwardEvent
13109
+ }) : void 0;
13110
+ cleanup.actions.push(() => commanderBoundForwardWatcher?.close());
13052
13111
  const revokeEditorForwardPort = (port, reason) => {
13053
13112
  const target = localEditorForwardState.approvedTargets.get(port);
13054
13113
  localEditorForwardState.approvedPorts.delete(port);
@@ -13095,6 +13154,37 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13095
13154
  drainQueuedEditorPortForwardPrompt();
13096
13155
  }
13097
13156
  };
13157
+ const approveEditorPortForwardCandidate = (candidate) => {
13158
+ const request = pendingRequestFromCandidate({
13159
+ requestId: `editor-port-forward-auto-${randomUUID3()}`,
13160
+ sourceSeq: 0,
13161
+ candidate
13162
+ });
13163
+ localEditorForwardState.approvedPorts.add(request.port);
13164
+ localEditorForwardState.approvedTargets.set(
13165
+ request.port,
13166
+ approvedTargetFromRequest(request)
13167
+ );
13168
+ liveForwardPorts.add(request.port);
13169
+ const processIdentity = guessCanonicalProcessFromCommand(request.command);
13170
+ setForwardPortAttribution(request.port, {
13171
+ localEditor: true,
13172
+ processName: processIdentity?.appName ?? null,
13173
+ processIconKey: processIdentity?.iconKey ?? null,
13174
+ linzumiCliManaged: request.portKind === "commander_bound"
13175
+ });
13176
+ pushEditorPortForwardEvent("forward_port_resolved", {
13177
+ instanceId,
13178
+ requestId: request.requestId,
13179
+ source: "local_editor",
13180
+ port: request.port,
13181
+ pid: request.pid,
13182
+ command: request.command,
13183
+ ...request.cwd === void 0 ? {} : { cwd: request.cwd },
13184
+ decision: "approve",
13185
+ capabilities: capabilitiesPayload()
13186
+ });
13187
+ };
13098
13188
  const publishEditorPortForwardPrompt = (candidate) => {
13099
13189
  const review = reviewPortForwardCandidate({
13100
13190
  candidate,
@@ -13117,15 +13207,9 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13117
13207
  );
13118
13208
  return;
13119
13209
  case "revoke_and_prompt":
13120
- if (localEditorForwardState.pendingRequests.size > 0) {
13121
- localEditorForwardState.queuedCandidates.set(
13122
- candidate.port,
13123
- candidate
13124
- );
13125
- return;
13126
- }
13127
13210
  revokeEditorForwardPort(review.revoked.port, review.reason);
13128
- break;
13211
+ approveEditorPortForwardCandidate(candidate);
13212
+ return;
13129
13213
  case "replace_pending":
13130
13214
  localEditorForwardState.pendingRequests.delete(review.expired.port);
13131
13215
  pushEditorPortForwardEvent("forward_port_resolved", {
@@ -13140,44 +13224,12 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13140
13224
  reason: review.reason,
13141
13225
  capabilities: capabilitiesPayload()
13142
13226
  });
13143
- if (localEditorForwardState.pendingRequests.size > 0) {
13144
- localEditorForwardState.queuedCandidates.set(
13145
- review.candidate.port,
13146
- review.candidate
13147
- );
13148
- return;
13149
- }
13150
- break;
13227
+ approveEditorPortForwardCandidate(review.candidate);
13228
+ return;
13151
13229
  case "prompt":
13152
- if (localEditorForwardState.pendingRequests.size > 0) {
13153
- localEditorForwardState.queuedCandidates.set(
13154
- candidate.port,
13155
- candidate
13156
- );
13157
- return;
13158
- }
13159
- break;
13230
+ approveEditorPortForwardCandidate(candidate);
13231
+ return;
13160
13232
  }
13161
- const requestId = `editor-port-forward-${randomUUID3()}`;
13162
- const request = pendingRequestFromCandidate({
13163
- requestId,
13164
- sourceSeq: 0,
13165
- candidate
13166
- });
13167
- localEditorForwardState.pendingRequests.set(request.port, request);
13168
- const processIdentity = guessCanonicalProcessFromCommand(candidate.command);
13169
- pushEditorPortForwardEvent("forward_port_requested", {
13170
- instanceId,
13171
- requestId,
13172
- source: "local_editor",
13173
- port: request.port,
13174
- pid: request.pid,
13175
- command: request.command,
13176
- ...request.cwd === void 0 ? {} : { cwd: request.cwd },
13177
- ...processIdentity?.appName === void 0 ? {} : { processName: processIdentity.appName },
13178
- ...processIdentity?.iconKey === void 0 ? {} : { processIconKey: processIdentity.iconKey },
13179
- capabilities: capabilitiesPayload()
13180
- });
13181
13233
  };
13182
13234
  const expireLostEditorPortForwardCandidate = (candidate) => {
13183
13235
  const queuedCandidate = localEditorForwardState.queuedCandidates.get(
@@ -13248,7 +13300,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13248
13300
  setForwardPortAttribution(request.port, {
13249
13301
  localEditor: true,
13250
13302
  processName: processIdentity?.appName ?? null,
13251
- processIconKey: processIdentity?.iconKey ?? null
13303
+ processIconKey: processIdentity?.iconKey ?? null,
13304
+ linzumiCliManaged: request.portKind === "commander_bound"
13252
13305
  });
13253
13306
  pushEditorPortForwardEvent("forward_port_resolved", {
13254
13307
  instanceId,
@@ -13320,6 +13373,50 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13320
13373
  capabilities: revocationCapabilities(capabilitiesPayload(), port)
13321
13374
  });
13322
13375
  };
13376
+ const approveClaudeCodeForwardCandidate = async (session, candidate) => {
13377
+ const sourceSeq = session.currentSourceSeq() ?? session.rootSeq;
13378
+ if (sourceSeq === void 0) {
13379
+ log("port_forward.claude_code_auto_approval_skipped", {
13380
+ reason: "source_seq_missing",
13381
+ port: candidate.port,
13382
+ pid: candidate.pid
13383
+ });
13384
+ return;
13385
+ }
13386
+ const request = pendingRequestFromCandidate({
13387
+ requestId: `claude-port-forward-auto-${randomUUID3()}`,
13388
+ sourceSeq,
13389
+ candidate
13390
+ });
13391
+ session.approvedPorts.add(request.port);
13392
+ session.approvedTargets.set(
13393
+ request.port,
13394
+ approvedTargetFromRequest(request)
13395
+ );
13396
+ liveForwardPorts.add(request.port);
13397
+ const processIdentity = guessCanonicalProcessFromCommand(request.command);
13398
+ setForwardPortAttribution(request.port, {
13399
+ kandanThreadId: session.threadId,
13400
+ codexThreadId: session.sessionId,
13401
+ channelSlug: session.channel,
13402
+ processName: processIdentity?.appName ?? null,
13403
+ processIconKey: processIdentity?.iconKey ?? null,
13404
+ agentProvider: "claude-code",
13405
+ linzumiCliManaged: request.portKind === "commander_bound"
13406
+ });
13407
+ await kandan.push(topic, "forward_port_resolved", {
13408
+ instanceId,
13409
+ requestId: request.requestId,
13410
+ port: request.port,
13411
+ pid: request.pid,
13412
+ command: request.command,
13413
+ ...request.cwd === void 0 ? {} : { cwd: request.cwd },
13414
+ sourceSeq: request.sourceSeq,
13415
+ decision: "approve",
13416
+ agentProvider: "claude-code",
13417
+ capabilities: capabilitiesPayload()
13418
+ });
13419
+ };
13323
13420
  const publishClaudeCodeForwardPortPrompt = async (session, candidate) => {
13324
13421
  const review = reviewPortForwardCandidate({
13325
13422
  candidate,
@@ -13337,16 +13434,13 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13337
13434
  session.approvedTargets.set(review.target.port, review.target);
13338
13435
  return;
13339
13436
  case "revoke_and_prompt":
13340
- if (session.pendingRequests.size > 0) {
13341
- session.queuedCandidates.set(candidate.port, candidate);
13342
- return;
13343
- }
13344
13437
  await revokeClaudeCodeForwardPort(
13345
13438
  session,
13346
13439
  review.revoked.port,
13347
13440
  review.reason
13348
13441
  );
13349
- break;
13442
+ await approveClaudeCodeForwardCandidate(session, candidate);
13443
+ return;
13350
13444
  case "replace_pending":
13351
13445
  session.pendingRequests.delete(review.expired.requestId);
13352
13446
  await kandan.push(topic, "forward_port_resolved", {
@@ -13371,83 +13465,12 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13371
13465
  reason: "port_forward_listener_changed",
13372
13466
  sessionId: session.sessionId
13373
13467
  });
13374
- if (session.pendingRequests.size > 0) {
13375
- session.queuedCandidates.set(review.candidate.port, review.candidate);
13376
- return;
13377
- }
13378
- break;
13468
+ await approveClaudeCodeForwardCandidate(session, review.candidate);
13469
+ return;
13379
13470
  case "prompt":
13380
- if (session.pendingRequests.size > 0) {
13381
- session.queuedCandidates.set(candidate.port, candidate);
13382
- return;
13383
- }
13384
- break;
13385
- }
13386
- const sourceSeq = session.currentSourceSeq() ?? session.rootSeq;
13387
- if (sourceSeq === void 0) {
13388
- log("port_forward.claude_code_prompt_skipped", {
13389
- reason: "source_seq_missing",
13390
- port: candidate.port,
13391
- pid: candidate.pid
13392
- });
13393
- return;
13471
+ await approveClaudeCodeForwardCandidate(session, candidate);
13472
+ return;
13394
13473
  }
13395
- const requestId = `claude-port-forward-${randomUUID3()}`;
13396
- const request = pendingRequestFromCandidate({
13397
- requestId,
13398
- sourceSeq,
13399
- candidate
13400
- });
13401
- session.pendingRequests.set(requestId, request);
13402
- const processIdentity = guessCanonicalProcessFromCommand(candidate.command);
13403
- const processName = processIdentity?.appName ?? portForwardPromptLabel(candidate);
13404
- await kandan.push(topic, "message_state", {
13405
- workspace: session.workspace,
13406
- channel: session.channel,
13407
- thread_id: session.threadId,
13408
- seq: sourceSeq,
13409
- status: "processing",
13410
- reason: "awaiting approval",
13411
- codex_thread_id: session.sessionId,
13412
- agent_provider: "claude-code",
13413
- approval_request_id: requestId,
13414
- approval_kind: "local_runner_port_forward",
13415
- approval_summary: `Make ${processName} on port ${candidate.port} accessible on Linzumi?`,
13416
- approval_reason: portForwardPromptReason(candidate),
13417
- approval_port: candidate.port,
13418
- approval_pid: candidate.pid,
13419
- approval_command: candidate.command,
13420
- ...candidate.cwd === void 0 ? {} : { approval_cwd: candidate.cwd },
13421
- ...processIdentity?.appName === void 0 ? {} : { approval_process_name: processIdentity.appName },
13422
- ...processIdentity?.iconKey === void 0 ? {} : { approval_process_icon_key: processIdentity.iconKey },
13423
- approval_choices: [
13424
- {
13425
- decision: "approve",
13426
- label: "Enable",
13427
- description: `Allow Linzumi to proxy Claude Code preview port ${candidate.port}.`
13428
- },
13429
- {
13430
- decision: "deny",
13431
- label: "Deny",
13432
- description: `Keep Claude Code preview port ${candidate.port} private.`
13433
- }
13434
- ]
13435
- });
13436
- await kandan.push(topic, "forward_port_requested", {
13437
- instanceId,
13438
- requestId,
13439
- sourceSeq,
13440
- port: candidate.port,
13441
- pid: candidate.pid,
13442
- command: candidate.command,
13443
- codexThreadId: session.sessionId,
13444
- kandanThreadId: session.threadId,
13445
- channelSlug: session.channel,
13446
- agentProvider: "claude-code",
13447
- ...candidate.cwd === void 0 ? {} : { cwd: candidate.cwd },
13448
- ...processIdentity?.appName === void 0 ? {} : { processName: processIdentity.appName },
13449
- ...processIdentity?.iconKey === void 0 ? {} : { processIconKey: processIdentity.iconKey }
13450
- });
13451
13474
  };
13452
13475
  const expireLostClaudeCodeForwardCandidate = (session, candidate) => {
13453
13476
  const queuedCandidate = session.queuedCandidates.get(candidate.port);
@@ -13570,7 +13593,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13570
13593
  channelSlug: session.channel,
13571
13594
  processName: processIdentity?.appName ?? null,
13572
13595
  processIconKey: processIdentity?.iconKey ?? null,
13573
- agentProvider: "claude-code"
13596
+ agentProvider: "claude-code",
13597
+ linzumiCliManaged: request.portKind === "commander_bound"
13574
13598
  });
13575
13599
  void Promise.all([
13576
13600
  kandan.push(topic, "forward_port_resolved", {
@@ -13885,7 +13909,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13885
13909
  initialForwardPorts: allowedForwardPorts,
13886
13910
  portForwardWatcher: channelSessionPortForwardWatcherOptions({
13887
13911
  rootPid: portForwardWatcherRootPid,
13888
- start: options.portForwardWatcher
13912
+ start: options.portForwardWatcher,
13913
+ commanderBoundPids: args.commanderBoundPids
13889
13914
  }),
13890
13915
  suppressedForwardPorts,
13891
13916
  onForwardPortApproved: (port, attribution) => {
@@ -13999,6 +14024,13 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
13999
14024
  }
14000
14025
  throw error;
14001
14026
  }
14027
+ for (const port of handle.commanderManagedPorts ?? []) {
14028
+ markCommanderManagedForwardPort(port.port, {
14029
+ processName: port.processName,
14030
+ processIconKey: port.processIconKey,
14031
+ agentProvider: port.agentProvider
14032
+ });
14033
+ }
14002
14034
  try {
14003
14035
  const threadCodex = handle.codex;
14004
14036
  const closeThreadCodex = once(() => threadCodex.close());
@@ -14031,7 +14063,10 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
14031
14063
  cwd: startedCwd,
14032
14064
  codexThreadId,
14033
14065
  sessionCodex: threadCodex,
14034
- portForwardWatcherRootPid: handle.processPid
14066
+ portForwardWatcherRootPid: handle.processPid,
14067
+ commanderBoundPids: (handle.commanderManagedPorts ?? []).flatMap(
14068
+ (port) => port.pid === void 0 ? [] : [port.pid]
14069
+ )
14035
14070
  });
14036
14071
  switch (control.type) {
14037
14072
  case "start_instance": {
@@ -16742,18 +16777,138 @@ function startInstanceRuntimeSettings(options, control) {
16742
16777
  ),
16743
16778
  sandbox,
16744
16779
  fast: control.fast ?? options.fast,
16745
- allowPortForwardingByDefault: control.allowPortForwardingByDefault ?? defaults.allowPortForwardingByDefault
16780
+ allowPortForwardingByDefault: true
16746
16781
  };
16747
16782
  }
16748
16783
  function channelSessionPortForwardWatcherOptions(args) {
16749
16784
  if (args.rootPid === void 0 && args.start === void 0) {
16750
16785
  return void 0;
16751
16786
  }
16787
+ const commanderBoundPids = [
16788
+ process.pid,
16789
+ ...args.rootPid === void 0 ? [] : [args.rootPid],
16790
+ ...args.commanderBoundPids ?? []
16791
+ ];
16752
16792
  return {
16753
16793
  ...args.rootPid === void 0 ? {} : { rootPid: args.rootPid },
16794
+ ...commanderBoundPids.length === 0 ? {} : { commanderBoundPids },
16754
16795
  ...args.start === void 0 ? {} : { start: args.start }
16755
16796
  };
16756
16797
  }
16798
+ function shouldStartCommanderBoundForwardWatcher(options) {
16799
+ return options.threadProcess?.role !== "thread" && options.codexUrl === void 0;
16800
+ }
16801
+ async function startCommanderBoundE2eHttpProbe(log) {
16802
+ const rawPort = process.env.LINZUMI_E2E_COMMANDER_BOUND_HTTP_PORT;
16803
+ if (rawPort === void 0 || rawPort.trim() === "") {
16804
+ return void 0;
16805
+ }
16806
+ const port = strictTcpPortFromEnv(
16807
+ rawPort,
16808
+ "LINZUMI_E2E_COMMANDER_BOUND_HTTP_PORT"
16809
+ );
16810
+ const server = createServer3((_request, response) => {
16811
+ response.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
16812
+ response.end("linzumi commander-bound probe\n");
16813
+ });
16814
+ await listenOnLoopback(server, port);
16815
+ log("runner.e2e_commander_bound_http_probe_started", { port });
16816
+ return {
16817
+ port,
16818
+ close: () => closeHttpServer(server)
16819
+ };
16820
+ }
16821
+ function strictTcpPortFromEnv(rawValue, envName) {
16822
+ const trimmed = rawValue.trim();
16823
+ const port = Number.parseInt(trimmed, 10);
16824
+ if (!/^\d+$/u.test(trimmed) || !Number.isInteger(port)) {
16825
+ throw new Error(`${envName} must be an integer TCP port`);
16826
+ }
16827
+ if (port <= 0 || port > 65535) {
16828
+ throw new Error(`${envName} must be between 1 and 65535`);
16829
+ }
16830
+ return port;
16831
+ }
16832
+ function listenOnLoopback(server, port) {
16833
+ return new Promise((resolve11, reject) => {
16834
+ const onError = (error) => {
16835
+ server.off("listening", onListening);
16836
+ reject(error);
16837
+ };
16838
+ const onListening = () => {
16839
+ server.off("error", onError);
16840
+ resolve11();
16841
+ };
16842
+ server.once("error", onError);
16843
+ server.once("listening", onListening);
16844
+ server.listen(port, "127.0.0.1");
16845
+ });
16846
+ }
16847
+ function closeHttpServer(server) {
16848
+ if (!server.listening) {
16849
+ return Promise.resolve();
16850
+ }
16851
+ return new Promise((resolve11, reject) => {
16852
+ server.close((error) => {
16853
+ if (error !== void 0) {
16854
+ reject(error);
16855
+ return;
16856
+ }
16857
+ resolve11();
16858
+ });
16859
+ });
16860
+ }
16861
+ function startCommanderBoundForwardWatcher(args) {
16862
+ return startPortForwardWatcher({
16863
+ rootPid: process.pid,
16864
+ commanderBoundPids: [process.pid],
16865
+ onCandidate: (candidate) => {
16866
+ if (candidate.portKind !== "commander_bound") {
16867
+ return;
16868
+ }
16869
+ if (args.managedForwardPorts.has(candidate.port)) {
16870
+ return;
16871
+ }
16872
+ const processIdentity = guessCanonicalProcessFromCommand(
16873
+ candidate.command
16874
+ );
16875
+ args.markCommanderManagedForwardPort(candidate.port, {
16876
+ processName: processIdentity?.appName ?? portForwardPromptLabel(candidate),
16877
+ processIconKey: processIdentity?.iconKey ?? "terminal"
16878
+ });
16879
+ args.pushForwardPortEvent("forward_port_resolved", {
16880
+ instanceId: args.instanceId,
16881
+ requestId: `commander-bound-${candidate.pid}-${candidate.port}`,
16882
+ port: candidate.port,
16883
+ decision: "approve",
16884
+ capabilities: args.capabilitiesPayload()
16885
+ });
16886
+ },
16887
+ onCandidateLost: (candidate) => {
16888
+ if (candidate.portKind !== "commander_bound") {
16889
+ return;
16890
+ }
16891
+ if (!args.managedForwardPorts.has(candidate.port)) {
16892
+ return;
16893
+ }
16894
+ args.clearCommanderManagedForwardPort(candidate.port);
16895
+ args.pushForwardPortEvent("forward_port_revoked", {
16896
+ instanceId: args.instanceId,
16897
+ requestId: `commander-bound-${candidate.pid}-${candidate.port}`,
16898
+ port: candidate.port,
16899
+ decision: "revoked",
16900
+ reason: "listener_exited",
16901
+ capabilities: revocationCapabilities(
16902
+ args.capabilitiesPayload(),
16903
+ candidate.port
16904
+ )
16905
+ });
16906
+ },
16907
+ onError: (error) => args.log("port_forward.commander_bound_watch_failed", {
16908
+ message: error.message
16909
+ })
16910
+ });
16911
+ }
16757
16912
  function threadRunnerOptions(args) {
16758
16913
  const runtimeSettings = startInstanceRuntimeSettings(
16759
16914
  args.options,
@@ -16916,6 +17071,7 @@ async function spawnLocalThreadRunnerProcess(options) {
16916
17071
  kandanThreadId: ready2.kandanThreadId,
16917
17072
  codex: connectThreadCodexWorkerIpc(child),
16918
17073
  processPid: child.pid,
17074
+ commanderManagedPorts: ready2.commanderManagedPorts,
16919
17075
  onExit: (listener) => {
16920
17076
  if (exitState.exited) {
16921
17077
  queueMicrotask(listener);
@@ -16982,7 +17138,49 @@ function threadRunnerReadyMessage(message, expectedKandanThreadId) {
16982
17138
  if (kandanThreadId !== expectedKandanThreadId) {
16983
17139
  throw new Error("thread Codex worker reported invalid ready payload");
16984
17140
  }
16985
- return { kandanThreadId };
17141
+ return {
17142
+ kandanThreadId,
17143
+ commanderManagedPorts: commanderManagedPortRecords(
17144
+ message.commanderManagedPorts
17145
+ )
17146
+ };
17147
+ }
17148
+ function commanderManagedPortRecords(value) {
17149
+ if (!Array.isArray(value)) {
17150
+ return [];
17151
+ }
17152
+ return value.flatMap((entry) => {
17153
+ if (!isJsonObject(entry)) {
17154
+ return [];
17155
+ }
17156
+ const port = integerValue(entry.port);
17157
+ if (port === void 0 || port < 1 || port > 65535) {
17158
+ return [];
17159
+ }
17160
+ const pid = integerValue(entry.pid);
17161
+ const processName = stringValue(entry.processName);
17162
+ const processIconKey = stringValue(entry.processIconKey);
17163
+ const agentProvider = providerKindValue(entry.agentProvider);
17164
+ return [
17165
+ {
17166
+ port,
17167
+ ...pid === void 0 ? {} : { pid },
17168
+ ...processName === void 0 ? {} : { processName },
17169
+ ...processIconKey === void 0 ? {} : { processIconKey },
17170
+ ...agentProvider === void 0 ? {} : { agentProvider }
17171
+ }
17172
+ ];
17173
+ });
17174
+ }
17175
+ function providerKindValue(value) {
17176
+ switch (stringValue(value)) {
17177
+ case "codex":
17178
+ return "codex";
17179
+ case "claude-code":
17180
+ return "claude-code";
17181
+ default:
17182
+ return void 0;
17183
+ }
16986
17184
  }
16987
17185
  function waitForThreadCodexWorkerStop(codexProcess) {
16988
17186
  return new Promise((resolve11) => {
@@ -17070,7 +17268,7 @@ function threadRunnerCliArgs(options) {
17070
17268
  "--approval-policy",
17071
17269
  options.runtimeDefaults?.approvalPolicy
17072
17270
  ),
17073
- ...options.runtimeDefaults?.allowPortForwardingByDefault === true ? ["--allow-port-forwarding-by-default"] : []
17271
+ "--allow-port-forwarding-by-default"
17074
17272
  ];
17075
17273
  }
17076
17274
  function redactedThreadRunnerCliArgs(args) {
@@ -17107,7 +17305,8 @@ async function startOwnedCodexAppServer(options, args = { linzumiMcp: true }) {
17107
17305
  argsPrefix: mcpCommand.argsPrefix,
17108
17306
  kandanUrl: options.kandanUrl,
17109
17307
  authFilePath: mcpAuth.path,
17110
- ownerUsername: mcpOwnerUsername(options)
17308
+ ownerUsername: mcpOwnerUsername(options),
17309
+ operatingMode: "text"
17111
17310
  })
17112
17311
  ]
17113
17312
  });
@@ -17125,6 +17324,21 @@ async function startOwnedCodexAppServer(options, args = { linzumiMcp: true }) {
17125
17324
  throw error;
17126
17325
  }
17127
17326
  }
17327
+ function commanderManagedPortsForStartedCodex(started) {
17328
+ const port = explicitUrlPort(started.url);
17329
+ if (port === void 0) {
17330
+ return [];
17331
+ }
17332
+ return [
17333
+ {
17334
+ port,
17335
+ ...started.process.pid === void 0 ? {} : { pid: started.process.pid },
17336
+ processName: "Codex app-server",
17337
+ processIconKey: "codex",
17338
+ agentProvider: "codex"
17339
+ }
17340
+ ];
17341
+ }
17128
17342
  function mcpOwnerUsername(options) {
17129
17343
  return options.channelSession?.listenUser ?? identityFromAccessToken(options.token).actorUsername;
17130
17344
  }
@@ -54468,14 +54682,19 @@ function createLinzumiMcpApiClient(options) {
54468
54682
  const fetchImpl = options.fetchImpl ?? fetch;
54469
54683
  const baseUrl = kandanHttpBaseUrl(options.kandanUrl);
54470
54684
  const apiPrefix = options.authMode === "personal-agent-delegation" ? "/api/v2/personal-agent-mcp" : "/api/v2/local-runner-mcp";
54685
+ const operatingMode = options.operatingMode ?? "text";
54471
54686
  const request = async (method, path2, params) => {
54472
54687
  const url = new URL(path2, baseUrl);
54688
+ const paramsWithMode = {
54689
+ ...params,
54690
+ operating_mode: operatingMode
54691
+ };
54473
54692
  const requestInit = {
54474
54693
  method,
54475
54694
  headers: { authorization: `Bearer ${options.accessToken}` }
54476
54695
  };
54477
54696
  if (method === "GET") {
54478
- for (const [key, value] of Object.entries(params)) {
54697
+ for (const [key, value] of Object.entries(paramsWithMode)) {
54479
54698
  if (value !== void 0 && value !== null) {
54480
54699
  url.searchParams.set(key, String(value));
54481
54700
  }
@@ -54485,7 +54704,7 @@ function createLinzumiMcpApiClient(options) {
54485
54704
  ...requestInit.headers,
54486
54705
  "content-type": "application/json"
54487
54706
  };
54488
- requestInit.body = JSON.stringify(params);
54707
+ requestInit.body = JSON.stringify(paramsWithMode);
54489
54708
  }
54490
54709
  const response = await fetchImpl(url, requestInit);
54491
54710
  const parsed = await response.json();
@@ -54522,6 +54741,7 @@ var mcpFlagDefinitions = /* @__PURE__ */ new Map([
54522
54741
  ["workspace", { kind: "value" }],
54523
54742
  ["channel", { kind: "value" }],
54524
54743
  ["owner-username", { kind: "value" }],
54744
+ ["mode", { kind: "value" }],
54525
54745
  ["format", { kind: "value" }],
54526
54746
  ["command", { kind: "value" }],
54527
54747
  ["include-token", { kind: "boolean" }],
@@ -54552,8 +54772,8 @@ function mcpHelpText() {
54552
54772
  return `Linzumi MCP
54553
54773
 
54554
54774
  Usage:
54555
- linzumi mcp server --api-url <url> [--workspace <slug> --channel <slug>]
54556
- linzumi mcp server --api-url <url> --delegation-auth-file <path>
54775
+ linzumi mcp server --api-url <url> [--mode voice|text] [--workspace <slug> --channel <slug>]
54776
+ linzumi mcp server --api-url <url> --delegation-auth-file <path> [--mode voice|text]
54557
54777
  linzumi mcp config --api-url <url> --format codex|claude-code [--include-token]
54558
54778
  linzumi mcp doctor --api-url <url> [--workspace <slug> --channel <slug>]
54559
54779
 
@@ -54589,10 +54809,12 @@ async function runMcpServer(args) {
54589
54809
  channelSlug: stringValue3(values, "channel")
54590
54810
  });
54591
54811
  const ownerUsername = stringValue3(values, "owner-username") ?? process.env.LINZUMI_MCP_OWNER_USERNAME;
54812
+ const operatingMode = mcpOperatingMode(stringValue3(values, "mode"));
54592
54813
  const client = createLinzumiMcpApiClient({
54593
54814
  kandanUrl,
54594
54815
  accessToken: auth.accessToken,
54595
- authMode: auth.mode
54816
+ authMode: auth.mode,
54817
+ operatingMode
54596
54818
  });
54597
54819
  const server = new McpServer({
54598
54820
  name: "linzumi",
@@ -54709,6 +54931,7 @@ async function runMcpConfig(args) {
54709
54931
  const values = strictFlagValues(args);
54710
54932
  const kandanUrl = required(values, "api-url");
54711
54933
  const format = stringValue3(values, "format") ?? "codex";
54934
+ const operatingMode = mcpOperatingMode(stringValue3(values, "mode"));
54712
54935
  const token = values.get("include-token") === true ? (await resolveMcpAuth({
54713
54936
  kandanUrl,
54714
54937
  explicitToken: stringValue3(values, "token") ?? process.env.LINZUMI_MCP_ACCESS_TOKEN,
@@ -54722,7 +54945,8 @@ async function runMcpConfig(args) {
54722
54945
  kandanUrl,
54723
54946
  accessToken: token,
54724
54947
  delegationAuthFilePath: stringValue3(values, "delegation-auth-file"),
54725
- ownerUsername: stringValue3(values, "owner-username") ?? process.env.LINZUMI_MCP_OWNER_USERNAME
54948
+ ownerUsername: stringValue3(values, "owner-username") ?? process.env.LINZUMI_MCP_OWNER_USERNAME,
54949
+ operatingMode
54726
54950
  });
54727
54951
  switch (format) {
54728
54952
  case "codex":
@@ -54763,7 +54987,8 @@ async function runMcpDoctor(args) {
54763
54987
  const client = createLinzumiMcpApiClient({
54764
54988
  kandanUrl,
54765
54989
  accessToken: auth.accessToken,
54766
- authMode: auth.mode
54990
+ authMode: auth.mode,
54991
+ operatingMode: mcpOperatingMode(stringValue3(values, "mode"))
54767
54992
  });
54768
54993
  await client.validateAuth();
54769
54994
  break;
@@ -54838,6 +55063,17 @@ function stringValue3(values, key) {
54838
55063
  const value = values.get(key);
54839
55064
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
54840
55065
  }
55066
+ function mcpOperatingMode(value) {
55067
+ switch (value) {
55068
+ case void 0:
55069
+ return "text";
55070
+ case "voice":
55071
+ case "text":
55072
+ return value;
55073
+ default:
55074
+ throw new Error("--mode must be voice or text");
55075
+ }
55076
+ }
54841
55077
  function required(values, key) {
54842
55078
  const value = stringValue3(values, key);
54843
55079
  if (value === void 0) {
@@ -55406,10 +55642,7 @@ async function parseStartRunnerArgs(args, deps = {
55406
55642
  reasoningEffort: stringValue5(values, "reasoning-effort"),
55407
55643
  sandbox: stringValue5(values, "sandbox"),
55408
55644
  approvalPolicy: stringValue5(values, "approval-policy"),
55409
- allowPortForwardingByDefault: booleanFlagValue(
55410
- values,
55411
- "allow-port-forwarding-by-default"
55412
- ),
55645
+ allowPortForwardingByDefault: true,
55413
55646
  streamFlushMs: positiveIntegerValue2(values, "stream-flush-ms")
55414
55647
  }
55415
55648
  };
@@ -55446,10 +55679,7 @@ async function parseAgentRunnerArgs(args, deps = {
55446
55679
  reasoningEffort: stringValue5(values, "reasoning-effort"),
55447
55680
  sandbox: stringValue5(values, "sandbox"),
55448
55681
  approvalPolicy: stringValue5(values, "approval-policy"),
55449
- allowPortForwardingByDefault: booleanFlagValue(
55450
- values,
55451
- "allow-port-forwarding-by-default"
55452
- ),
55682
+ allowPortForwardingByDefault: true,
55453
55683
  streamFlushMs: positiveIntegerValue2(values, "stream-flush-ms")
55454
55684
  };
55455
55685
  const kandanUrl = kandanUrlValue(values) ?? agentApiUrlToKandanUrl(tokenFile.apiUrl);
@@ -55689,10 +55919,7 @@ function runnerRuntimeDefaultsFromValues(values) {
55689
55919
  reasoningEffort: stringValue5(values, "reasoning-effort"),
55690
55920
  approvalPolicy: stringValue5(values, "approval-policy"),
55691
55921
  sandbox: stringValue5(values, "sandbox"),
55692
- allowPortForwardingByDefault: booleanFlagValue(
55693
- values,
55694
- "allow-port-forwarding-by-default"
55695
- )
55922
+ allowPortForwardingByDefault: true
55696
55923
  };
55697
55924
  }
55698
55925
  function kandanUrlValue(values) {
@@ -55710,9 +55937,6 @@ function requiredKandanUrl(values) {
55710
55937
  }
55711
55938
  return value;
55712
55939
  }
55713
- function booleanFlagValue(values, key) {
55714
- return values.get(key) === true ? true : void 0;
55715
- }
55716
55940
  function strictFlagValues2(args, definitions = flagDefinitions) {
55717
55941
  const values = /* @__PURE__ */ new Map();
55718
55942
  for (let index = 0; index < args.length; index += 1) {
@@ -56006,8 +56230,6 @@ Codex:
56006
56230
  --reasoning-effort <value> Reasoning effort requested for Codex and shown in Linzumi
56007
56231
  --sandbox <value> Sandbox metadata shown in Linzumi
56008
56232
  --approval-policy <value> Approval-policy metadata shown in Linzumi
56009
- --allow-port-forwarding-by-default
56010
- Auto-approve detected port-forward candidates for started sessions
56011
56233
  --stream-flush-ms <ms> Batch live Codex deltas before Linzumi persistence, default 150
56012
56234
  --fast Mark this runner as low-latency/fast in the availability message
56013
56235
  --log-file <path> JSONL event log path, default ~/.linzumi/logs/runner-events.jsonl
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "0.0.65-beta",
3
+ "version": "0.0.66-beta",
4
4
  "description": "Linzumi CLI — point a Codex agent at the real code on your laptop, with your team watching and steering from shared threads.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,7 +10,6 @@
10
10
  "README.md",
11
11
  "bin",
12
12
  "dist",
13
- "docs/images",
14
13
  "scripts"
15
14
  ],
16
15
  "scripts": {
Binary file