@linzumi/cli 0.0.55-beta → 0.0.57-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 +321 -365
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -62,7 +62,7 @@ Install the CLI or run it with `npx`:
62
62
  ```bash
63
63
  npm install -g @linzumi/cli@latest
64
64
  npx -y @linzumi/cli@latest signup
65
- npx -y @linzumi/cli@0.0.55-beta --version
65
+ npx -y @linzumi/cli@0.0.57-beta --version
66
66
  linzumi --version
67
67
  ```
68
68
 
package/dist/index.js CHANGED
@@ -11028,7 +11028,6 @@ var require_lib3 = __commonJS({
11028
11028
  });
11029
11029
 
11030
11030
  // src/index.ts
11031
- import { randomUUID as randomUUID5 } from "node:crypto";
11032
11031
  import { existsSync as existsSync12, readFileSync as readFileSync13, realpathSync as realpathSync6 } from "node:fs";
11033
11032
  import { homedir as homedir10 } from "node:os";
11034
11033
  import { resolve as resolve10 } from "node:path";
@@ -18203,8 +18202,8 @@ function pathLooksAbsolute(pathValue) {
18203
18202
  }
18204
18203
 
18205
18204
  // src/localForwarding.ts
18205
+ import { connect as connectTcp } from "node:net";
18206
18206
  import { gzipSync } from "node:zlib";
18207
- import NodeWebSocket from "ws";
18208
18207
  var maxForwardBodyBytes = 64 * 1024 * 1024;
18209
18208
  var gzipForwardThresholdBytes = 32 * 1024;
18210
18209
  async function handleForwardHttpRequest(control, allowedPorts) {
@@ -18261,21 +18260,21 @@ async function handleForwardHttpRequest(control, allowedPorts) {
18261
18260
  function isForwardHttpRequestControl(control) {
18262
18261
  return control.type === "forward_http_request";
18263
18262
  }
18264
- function isForwardWebSocketControl(control) {
18265
- return control.type === "forward_websocket_open" || control.type === "forward_websocket_send" || control.type === "forward_websocket_close";
18263
+ function isForwardTcpControl(control) {
18264
+ return control.type === "forward_tcp_open" || control.type === "forward_tcp_send" || control.type === "forward_tcp_close";
18266
18265
  }
18267
- function createForwardWebSocketManager(kandan, topic, allowedPorts, socketFactory = defaultForwardWebSocketFactory) {
18266
+ function createForwardTcpManager(kandan, topic, allowedPorts, socketFactory = defaultForwardTcpFactory) {
18268
18267
  const sockets = /* @__PURE__ */ new Map();
18269
- const pushEvent = (payload) => kandan.push(topic, "forward:websocket_event", payload).catch(() => void 0);
18268
+ const pushEvent = (payload) => kandan.push(topic, "forward:tcp_event", payload).catch(() => void 0);
18270
18269
  const closeSocket = (socketId) => {
18271
18270
  const stream = sockets.get(socketId);
18272
18271
  sockets.delete(socketId);
18273
- stream?.socket.close();
18272
+ stream?.socket.end();
18274
18273
  };
18275
18274
  return {
18276
18275
  handle: (control) => {
18277
18276
  switch (control.type) {
18278
- case "forward_websocket_open": {
18277
+ case "forward_tcp_open": {
18279
18278
  if (!allowedPorts().includes(control.port)) {
18280
18279
  void pushEvent({
18281
18280
  socketId: control.socketId,
@@ -18284,32 +18283,70 @@ function createForwardWebSocketManager(kandan, topic, allowedPorts, socketFactor
18284
18283
  });
18285
18284
  return;
18286
18285
  }
18287
- openLocalWebSocket(control, sockets, pushEvent, socketFactory, "ws");
18286
+ const previous = sockets.get(control.socketId);
18287
+ previous?.socket.destroy();
18288
+ const socket = socketFactory(control.port);
18289
+ sockets.set(control.socketId, { socket });
18290
+ socket.on("connect", () => {
18291
+ if (!currentTcpSocket(sockets, control.socketId, socket)) {
18292
+ return;
18293
+ }
18294
+ void pushEvent({ socketId: control.socketId, type: "open" });
18295
+ });
18296
+ socket.on("data", (data) => {
18297
+ if (!currentTcpSocket(sockets, control.socketId, socket) || !(data instanceof Uint8Array)) {
18298
+ return;
18299
+ }
18300
+ void pushEvent({
18301
+ socketId: control.socketId,
18302
+ type: "data",
18303
+ bodyBase64: Buffer.from(data).toString("base64")
18304
+ });
18305
+ });
18306
+ socket.on("close", () => {
18307
+ if (!currentTcpSocket(sockets, control.socketId, socket)) {
18308
+ return;
18309
+ }
18310
+ sockets.delete(control.socketId);
18311
+ void pushEvent({ socketId: control.socketId, type: "close" });
18312
+ });
18313
+ socket.on("error", () => {
18314
+ if (!currentTcpSocket(sockets, control.socketId, socket)) {
18315
+ return;
18316
+ }
18317
+ sockets.delete(control.socketId);
18318
+ void pushEvent({
18319
+ socketId: control.socketId,
18320
+ type: "error",
18321
+ error: "forward_target_unavailable"
18322
+ });
18323
+ socket.destroy();
18324
+ });
18288
18325
  return;
18289
18326
  }
18290
- case "forward_websocket_send": {
18327
+ case "forward_tcp_send": {
18291
18328
  const stream = sockets.get(control.socketId);
18292
- if (stream === void 0 || stream.socket.readyState !== WebSocket.OPEN) {
18329
+ const body = decodeBase64Body(control.bodyBase64);
18330
+ if (body === void 0) {
18293
18331
  void pushEvent({
18294
18332
  socketId: control.socketId,
18295
18333
  type: "error",
18296
- error: "websocket_not_open"
18334
+ error: "invalid_forward_request"
18297
18335
  });
18298
18336
  return;
18299
18337
  }
18300
- const body = Buffer.from(control.bodyBase64, "base64");
18301
- switch (control.opcode) {
18302
- case "text":
18303
- stream.socket.send(body.toString());
18304
- return;
18305
- case "binary":
18306
- case "ping":
18307
- case "pong":
18308
- stream.socket.send(body);
18309
- return;
18338
+ if (stream === void 0 || stream.socket.destroyed === true || stream.socket.writable === false) {
18339
+ void pushEvent({
18340
+ socketId: control.socketId,
18341
+ type: "error",
18342
+ error: "tcp_socket_not_open"
18343
+ });
18344
+ return;
18310
18345
  }
18346
+ stream.socket.write(body);
18347
+ return;
18311
18348
  }
18312
- case "forward_websocket_close":
18349
+ case "forward_tcp_close":
18313
18350
  closeSocket(control.socketId);
18314
18351
  return;
18315
18352
  }
@@ -18321,105 +18358,11 @@ function createForwardWebSocketManager(kandan, topic, allowedPorts, socketFactor
18321
18358
  }
18322
18359
  };
18323
18360
  }
18324
- function openLocalWebSocket(control, sockets, pushEvent, socketFactory, scheme) {
18325
- let opened = false;
18326
- const url = localForwardWebSocketUrl(
18327
- scheme,
18328
- control.port,
18329
- control.path,
18330
- control.queryString
18331
- );
18332
- const protocols = webSocketProtocols(control.headers);
18333
- const headers = webSocketHeaders(control.headers);
18334
- const websocket = socketFactory(url, protocols, headers);
18335
- websocket.binaryType = "arraybuffer";
18336
- const previousStream = sockets.get(control.socketId);
18337
- previousStream?.socket.close();
18338
- sockets.set(control.socketId, { socket: websocket });
18339
- websocket.addEventListener("open", () => {
18340
- if (!currentWebSocket(sockets, control.socketId, websocket)) {
18341
- return;
18342
- }
18343
- opened = true;
18344
- void pushEvent({ socketId: control.socketId, type: "open" });
18345
- });
18346
- websocket.addEventListener("message", (event) => {
18347
- if (!currentWebSocket(sockets, control.socketId, websocket)) {
18348
- return;
18349
- }
18350
- const body = typeof event.data === "string" ? Buffer.from(event.data) : Buffer.from(event.data);
18351
- void pushEvent({
18352
- socketId: control.socketId,
18353
- type: "message",
18354
- opcode: typeof event.data === "string" ? "text" : "binary",
18355
- bodyBase64: body.toString("base64")
18356
- });
18357
- });
18358
- websocket.addEventListener("close", (event) => {
18359
- if (!currentWebSocket(sockets, control.socketId, websocket)) {
18360
- return;
18361
- }
18362
- sockets.delete(control.socketId);
18363
- void pushEvent({
18364
- socketId: control.socketId,
18365
- type: "close",
18366
- code: event.code,
18367
- reason: event.reason
18368
- });
18369
- });
18370
- websocket.addEventListener("error", () => {
18371
- if (!currentWebSocket(sockets, control.socketId, websocket)) {
18372
- return;
18373
- }
18374
- sockets.delete(control.socketId);
18375
- if (!opened && scheme === "ws") {
18376
- openLocalWebSocket(control, sockets, pushEvent, socketFactory, "wss");
18377
- return;
18378
- }
18379
- void pushEvent({
18380
- socketId: control.socketId,
18381
- type: "error",
18382
- error: "websocket_error",
18383
- attemptedScheme: scheme
18384
- });
18385
- });
18386
- }
18387
- function defaultForwardWebSocketFactory(url, protocols, headers) {
18388
- if (headers === void 0) {
18389
- return protocols === void 0 ? new WebSocket(url) : new WebSocket(url, protocols);
18390
- }
18391
- const options = { headers };
18392
- return protocols === void 0 ? new NodeWebSocket(url, options) : new NodeWebSocket(url, protocols, options);
18393
- }
18394
- function currentWebSocket(sockets, socketId, socket) {
18361
+ function currentTcpSocket(sockets, socketId, socket) {
18395
18362
  return sockets.get(socketId)?.socket === socket;
18396
18363
  }
18397
- function webSocketProtocols(headers) {
18398
- if (!Array.isArray(headers)) {
18399
- return void 0;
18400
- }
18401
- const protocols = headers.flatMap((header) => {
18402
- if (!isWireHeader(header) || header.name.toLowerCase() !== "sec-websocket-protocol") {
18403
- return [];
18404
- }
18405
- return header.value.split(",").map((protocol) => protocol.trim()).filter((protocol) => protocol !== "");
18406
- });
18407
- return protocols.length === 0 ? void 0 : protocols;
18408
- }
18409
- function webSocketHeaders(headers) {
18410
- if (!Array.isArray(headers)) {
18411
- return void 0;
18412
- }
18413
- const forwarded = headers.reduce((acc, header) => {
18414
- if (isOctWebSocketHeader(header)) {
18415
- acc[header.name] = header.value;
18416
- }
18417
- return acc;
18418
- }, {});
18419
- return Object.keys(forwarded).length === 0 ? void 0 : forwarded;
18420
- }
18421
- function isOctWebSocketHeader(value) {
18422
- return isHeader(value) && value.name.toLowerCase().startsWith("x-oct-");
18364
+ function defaultForwardTcpFactory(port) {
18365
+ return connectTcp({ host: "127.0.0.1", port });
18423
18366
  }
18424
18367
  function localForwardUrl(scheme, port, path2, queryString) {
18425
18368
  const normalizedPath = path2.startsWith("/") ? path2 : `/${path2}`;
@@ -18429,12 +18372,6 @@ function localForwardUrl(scheme, port, path2, queryString) {
18429
18372
  }
18430
18373
  return url.toString();
18431
18374
  }
18432
- function localForwardWebSocketUrl(scheme, port, path2, queryString) {
18433
- const httpScheme = scheme === "ws" ? "http" : "https";
18434
- const url = new URL(localForwardUrl(httpScheme, port, path2, queryString));
18435
- url.protocol = `${scheme}:`;
18436
- return url.toString();
18437
- }
18438
18375
  async function fetchWithHttpsFallback(port, path2, queryString, request) {
18439
18376
  try {
18440
18377
  return await fetch(
@@ -20862,6 +20799,37 @@ function ensureLocalMachineIdForLinzumiUrl(linzumiUrl, path2 = localConfigPath()
20862
20799
  writeLocalConfigSection({ ...latestConfig, machineId }, path2, linzumiUrl);
20863
20800
  return machineId;
20864
20801
  }
20802
+ function ensureLocalRunnerIdForLinzumiUrl(linzumiUrl, path2 = localConfigPath(), createRunnerId = defaultLocalRunnerId) {
20803
+ if (localConfigScopeKey(linzumiUrl) === prodConfigScope) {
20804
+ return ensureLocalRunnerId(path2, createRunnerId);
20805
+ }
20806
+ const config = readLocalConfigForLinzumiUrl(linzumiUrl, path2);
20807
+ if (config.runnerId !== void 0) {
20808
+ return config.runnerId;
20809
+ }
20810
+ const runnerId = ensureLocalRunnerIdSeed(path2, createRunnerId, linzumiUrl);
20811
+ const latestConfig = readLocalConfigForLinzumiUrl(linzumiUrl, path2);
20812
+ const latestRunnerId = latestConfig.runnerId;
20813
+ if (latestRunnerId !== void 0) {
20814
+ return latestRunnerId;
20815
+ }
20816
+ writeLocalConfigSection({ ...latestConfig, runnerId }, path2, linzumiUrl);
20817
+ return runnerId;
20818
+ }
20819
+ function ensureLocalRunnerId(path2 = localConfigPath(), createRunnerId = defaultLocalRunnerId) {
20820
+ const config = readLocalConfig(path2);
20821
+ if (config.runnerId !== void 0) {
20822
+ return config.runnerId;
20823
+ }
20824
+ const runnerId = ensureLocalRunnerIdSeed(path2, createRunnerId);
20825
+ const latestConfig = readLocalConfig(path2);
20826
+ const latestRunnerId = latestConfig.runnerId;
20827
+ if (latestRunnerId !== void 0) {
20828
+ return latestRunnerId;
20829
+ }
20830
+ writeLocalConfig({ ...latestConfig, runnerId }, path2);
20831
+ return runnerId;
20832
+ }
20865
20833
  function localMachineIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
20866
20834
  if (linzumiUrl !== void 0 && localConfigScopeKey(linzumiUrl) !== prodConfigScope) {
20867
20835
  return join6(
@@ -20871,6 +20839,15 @@ function localMachineIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
20871
20839
  }
20872
20840
  return join6(dirname4(configPath), `${basename4(configPath)}.machine-id`);
20873
20841
  }
20842
+ function localRunnerIdSeedPath(configPath = localConfigPath(), linzumiUrl) {
20843
+ if (linzumiUrl !== void 0 && localConfigScopeKey(linzumiUrl) !== prodConfigScope) {
20844
+ return join6(
20845
+ dirname4(configPath),
20846
+ `${basename4(configPath)}.${localConfigScopeFileStem(linzumiUrl)}.runner-id`
20847
+ );
20848
+ }
20849
+ return join6(dirname4(configPath), `${basename4(configPath)}.runner-id`);
20850
+ }
20874
20851
  function readConfiguredAllowedCwdDetailsForLinzumiUrl(linzumiUrl, path2 = localConfigPath()) {
20875
20852
  return readConfiguredAllowedCwdDetailsFromConfig(
20876
20853
  readLocalConfigForLinzumiUrl(linzumiUrl, path2)
@@ -21033,7 +21010,12 @@ function readLocalConfigSection(path2, linzumiUrl) {
21033
21010
  throw new Error(`invalid Linzumi config section ${scopeKey}: ${path2}`);
21034
21011
  }
21035
21012
  const allowedCwds = uniqueStrings(section.allowedCwds);
21036
- return section.machineId === void 0 ? { version: 1, allowedCwds } : { version: 1, machineId: section.machineId, allowedCwds };
21013
+ return {
21014
+ version: 1,
21015
+ ...section.machineId === void 0 ? {} : { machineId: section.machineId },
21016
+ ...section.runnerId === void 0 ? {} : { runnerId: section.runnerId },
21017
+ allowedCwds
21018
+ };
21037
21019
  }
21038
21020
  function writeLocalConfigSection(config, path2, linzumiUrl) {
21039
21021
  const scopeKey = linzumiUrl === void 0 ? prodConfigScope : localConfigScopeKey(linzumiUrl);
@@ -21050,7 +21032,7 @@ function isConfigPayload(value) {
21050
21032
  return typeof value === "object" && value !== null && value.version === 1 && isConfigSection(value);
21051
21033
  }
21052
21034
  function isConfigSection(value) {
21053
- return typeof value === "object" && value !== null && Array.isArray(value.allowedCwds) && machineIdValid(value.machineId) && value.allowedCwds.every(
21035
+ return typeof value === "object" && value !== null && Array.isArray(value.allowedCwds) && machineIdValid(value.machineId) && runnerIdValid(value.runnerId) && value.allowedCwds.every(
21054
21036
  (cwd) => typeof cwd === "string" && cwd.trim() !== ""
21055
21037
  );
21056
21038
  }
@@ -21092,7 +21074,11 @@ function normalizedConfigSection(config) {
21092
21074
  throw new Error("invalid Linzumi config");
21093
21075
  }
21094
21076
  const allowedCwds = uniqueStrings(config.allowedCwds);
21095
- return config.machineId === void 0 ? { allowedCwds } : { machineId: config.machineId, allowedCwds };
21077
+ return {
21078
+ ...config.machineId === void 0 ? {} : { machineId: config.machineId },
21079
+ ...config.runnerId === void 0 ? {} : { runnerId: config.runnerId },
21080
+ allowedCwds
21081
+ };
21096
21082
  }
21097
21083
  function emptySection() {
21098
21084
  return { allowedCwds: [] };
@@ -21102,6 +21088,9 @@ function machineIdValid(value) {
21102
21088
  value
21103
21089
  );
21104
21090
  }
21091
+ function runnerIdValid(value) {
21092
+ return value === void 0 || typeof value === "string" && /^[a-zA-Z0-9_.-]+$/.test(value);
21093
+ }
21105
21094
  function ensureLocalMachineIdSeed(configPath, createMachineId, linzumiUrl) {
21106
21095
  const seedPath = localMachineIdSeedPath(configPath, linzumiUrl);
21107
21096
  if (existsSync4(seedPath)) {
@@ -21130,6 +21119,34 @@ function ensureLocalMachineIdSeed(configPath, createMachineId, linzumiUrl) {
21130
21119
  unlinkSync(tempPath);
21131
21120
  }
21132
21121
  }
21122
+ function ensureLocalRunnerIdSeed(configPath, createRunnerId, linzumiUrl) {
21123
+ const seedPath = localRunnerIdSeedPath(configPath, linzumiUrl);
21124
+ if (existsSync4(seedPath)) {
21125
+ return readRunnerIdSeed(seedPath);
21126
+ }
21127
+ const runnerId = createRunnerId();
21128
+ if (!runnerIdValid(runnerId)) {
21129
+ throw new Error(`invalid generated Linzumi runner id: ${runnerId}`);
21130
+ }
21131
+ mkdirSync5(dirname4(seedPath), { recursive: true });
21132
+ const tempPath = join6(
21133
+ dirname4(seedPath),
21134
+ `.${basename4(seedPath)}.${process.pid}.${randomUUID2()}.tmp`
21135
+ );
21136
+ writeFileSync4(tempPath, `${runnerId}
21137
+ `, { encoding: "utf8", flag: "wx" });
21138
+ try {
21139
+ linkSync(tempPath, seedPath);
21140
+ return runnerId;
21141
+ } catch (error) {
21142
+ if (isNodeErrorCode(error, "EEXIST")) {
21143
+ return readRunnerIdSeed(seedPath);
21144
+ }
21145
+ throw error;
21146
+ } finally {
21147
+ unlinkSync(tempPath);
21148
+ }
21149
+ }
21133
21150
  function readMachineIdSeed(seedPath) {
21134
21151
  const machineId = readFileSync4(seedPath, "utf8").trim();
21135
21152
  if (!machineIdValid(machineId)) {
@@ -21137,6 +21154,16 @@ function readMachineIdSeed(seedPath) {
21137
21154
  }
21138
21155
  return machineId;
21139
21156
  }
21157
+ function readRunnerIdSeed(seedPath) {
21158
+ const runnerId = readFileSync4(seedPath, "utf8").trim();
21159
+ if (!runnerIdValid(runnerId)) {
21160
+ throw new Error(`invalid Linzumi runner id seed: ${seedPath}`);
21161
+ }
21162
+ return runnerId;
21163
+ }
21164
+ function defaultLocalRunnerId() {
21165
+ return `runner-${randomUUID2()}`;
21166
+ }
21140
21167
  function uniqueStrings(values) {
21141
21168
  return [
21142
21169
  ...new Set(
@@ -21159,7 +21186,7 @@ function realpathOrResolved(pathValue) {
21159
21186
  }
21160
21187
 
21161
21188
  // src/version.ts
21162
- var linzumiCliVersion = "0.0.55-beta";
21189
+ var linzumiCliVersion = "0.0.57-beta";
21163
21190
  var linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
21164
21191
 
21165
21192
  // src/runnerLock.ts
@@ -21665,6 +21692,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
21665
21692
  allowedCwds.value
21666
21693
  ),
21667
21694
  portForwarding: liveForwardPorts.size > 0,
21695
+ tcpForwarding: true,
21668
21696
  allowedPorts: Array.from(liveForwardPorts).sort(
21669
21697
  (left, right) => left - right
21670
21698
  ),
@@ -22013,64 +22041,6 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
22013
22041
  cleanup.actions.push(() => codex.close());
22014
22042
  const seq = { value: 0 };
22015
22043
  const discoveredCodexThreads = { value: [] };
22016
- const lastReportedDiscoveryFailure = { value: void 0 };
22017
- const reportClientError = async (args) => {
22018
- await kandan.push(topic, "client_error_report", {
22019
- id: `client-error-${randomUUID3()}`,
22020
- severity: args.severity ?? "error",
22021
- code: args.code,
22022
- operation: args.operation,
22023
- message: args.message,
22024
- occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
22025
- instanceId,
22026
- clientId,
22027
- runnerId: options.runnerId,
22028
- hostname: runnerHost,
22029
- cwd: options.cwd,
22030
- codexUrl,
22031
- workspace: runnerWorkspaceSlug(options) ?? null,
22032
- channel: options.channelSession?.channelSlug ?? null,
22033
- cliVersion: linzumiCliVersion,
22034
- details: args.details ?? {}
22035
- }).catch((error) => {
22036
- log("kandan.client_error_report_push_failed", {
22037
- code: args.code,
22038
- operation: args.operation,
22039
- message: error instanceof Error ? error.message : String(error)
22040
- });
22041
- });
22042
- };
22043
- const loadDiscoveredCodexThreads = async (phase) => {
22044
- try {
22045
- const threads = await discoverCodexThreads(codex, options.cwd);
22046
- lastReportedDiscoveryFailure.value = void 0;
22047
- return threads;
22048
- } catch (error) {
22049
- const message = error instanceof Error ? error.message : String(error);
22050
- const signature = `codex_thread_discovery_failed:${message}`;
22051
- log("codex.thread_discovery_failed", {
22052
- phase,
22053
- message
22054
- });
22055
- if (lastReportedDiscoveryFailure.value !== signature) {
22056
- lastReportedDiscoveryFailure.value = signature;
22057
- await reportClientError({
22058
- code: "codex_thread_discovery_failed",
22059
- operation: "codex_thread_discovery",
22060
- message,
22061
- details: {
22062
- phase,
22063
- codexUrl,
22064
- cwd: options.cwd
22065
- }
22066
- });
22067
- }
22068
- return discoveredCodexThreads.value;
22069
- }
22070
- };
22071
- if (options.channelSession === void 0) {
22072
- discoveredCodexThreads.value = await loadDiscoveredCodexThreads("initial");
22073
- }
22074
22044
  const runtimeDefaults = runnerRuntimeDefaults(options);
22075
22045
  const instancePayload = {
22076
22046
  instanceId,
@@ -22229,24 +22199,18 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
22229
22199
  message: error instanceof Error ? error.message : String(error)
22230
22200
  });
22231
22201
  });
22232
- const refreshDiscoveredCodexThreads = async (phase) => {
22233
- discoveredCodexThreads.value = await loadDiscoveredCodexThreads(phase);
22234
- await pushHeartbeat();
22235
- };
22236
22202
  const heartbeatInterval = setInterval(() => {
22237
- void (channelSession === void 0 ? refreshDiscoveredCodexThreads("heartbeat") : pushHeartbeat());
22203
+ void pushHeartbeat();
22238
22204
  }, 15e3);
22239
22205
  cleanup.actions.push(() => clearInterval(heartbeatInterval));
22240
- kandan.onReconnect(
22241
- () => channelSession === void 0 ? refreshDiscoveredCodexThreads("reconnect").then(() => void 0) : pushHeartbeat().then(() => void 0)
22242
- );
22206
+ kandan.onReconnect(() => pushHeartbeat().then(() => void 0));
22243
22207
  void pushHeartbeat();
22244
- const forwardWebSockets = createForwardWebSocketManager(
22208
+ const forwardTcp = createForwardTcpManager(
22245
22209
  kandan,
22246
22210
  topic,
22247
22211
  () => Array.from(liveForwardPorts)
22248
22212
  );
22249
- cleanup.actions.push(() => forwardWebSockets.close());
22213
+ cleanup.actions.push(() => forwardTcp.close());
22250
22214
  const channelCodexThreadId = channelSession?.currentCodexThreadId();
22251
22215
  if (options.launchTui && channelCodexThreadId !== void 0) {
22252
22216
  await prepareCodexThreadForTuiResume(codex, channelCodexThreadId);
@@ -22282,9 +22246,6 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
22282
22246
  });
22283
22247
  });
22284
22248
  }
22285
- if (channelSession === void 0 && notification.method === "thread/started") {
22286
- void refreshDiscoveredCodexThreads("thread_started");
22287
- }
22288
22249
  log("codex.notification", {
22289
22250
  method: notification.method,
22290
22251
  metadata
@@ -22343,8 +22304,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
22343
22304
  });
22344
22305
  return;
22345
22306
  }
22346
- if (isForwardWebSocketControl(control)) {
22347
- forwardWebSockets.handle(control);
22307
+ if (isForwardTcpControl(control)) {
22308
+ forwardTcp.handle(control);
22348
22309
  return;
22349
22310
  }
22350
22311
  if (isStartLocalEditorControl(control)) {
@@ -22548,99 +22509,6 @@ async function closeCleanupStack(cleanup) {
22548
22509
  })();
22549
22510
  return cleanup.closePromise;
22550
22511
  }
22551
- async function discoverCodexThreads(codex, _cwd) {
22552
- const response = await codex.request("thread/list", {
22553
- limit: CODEX_THREAD_DISCOVERY_LIMIT,
22554
- sortKey: "updated_at",
22555
- sortDirection: "desc",
22556
- archived: false,
22557
- useStateDbOnly: true
22558
- });
22559
- if ("error" in response) {
22560
- throw new Error(`thread/list failed: ${response.error.message}`);
22561
- }
22562
- const result = objectValue(response.result);
22563
- const data = arrayValue(result?.data)?.filter(isJsonObject) ?? [];
22564
- const rowsById = /* @__PURE__ */ new Map();
22565
- for (const thread of data.slice(0, CODEX_THREAD_DISCOVERY_LIMIT)) {
22566
- const row = codexThreadHistoryRow(thread, false);
22567
- const id = stringValue(objectValue(row)?.id);
22568
- if (id !== void 0 && id !== "" && !rowsById.has(id)) {
22569
- rowsById.set(id, row);
22570
- }
22571
- }
22572
- return Array.from(rowsById.values()).sort(compareCodexThreadHistoryRows);
22573
- }
22574
- var CODEX_THREAD_DISCOVERY_LIMIT = 50;
22575
- var CODEX_THREAD_TITLE_FIELD_LIMIT = 500;
22576
- var CODEX_THREAD_TEXT_FIELD_LIMIT = 2e3;
22577
- var CODEX_THREAD_PATH_FIELD_LIMIT = 1e3;
22578
- function codexThreadHistoryRow(thread, archived) {
22579
- const gitInfo = objectValue(thread.gitInfo);
22580
- const preview = codexThreadText(thread.preview, CODEX_THREAD_TEXT_FIELD_LIMIT).replace(/\s+/g, " ").trim();
22581
- const name = codexThreadText(thread.name, CODEX_THREAD_TITLE_FIELD_LIMIT);
22582
- const directTitle = codexThreadText(
22583
- thread.title,
22584
- CODEX_THREAD_TITLE_FIELD_LIMIT
22585
- );
22586
- const title = directTitle === "" ? name === "" ? preview : name : directTitle;
22587
- const description = codexThreadText(thread.description, CODEX_THREAD_TEXT_FIELD_LIMIT) || codexThreadText(thread.summary, CODEX_THREAD_TEXT_FIELD_LIMIT) || preview;
22588
- return {
22589
- id: codexThreadText(thread.id, CODEX_THREAD_PATH_FIELD_LIMIT),
22590
- title: title ?? "",
22591
- description: description ?? "",
22592
- preview,
22593
- cwd: codexThreadText(thread.cwd, CODEX_THREAD_PATH_FIELD_LIMIT),
22594
- source: codexThreadText(thread.source, CODEX_THREAD_TITLE_FIELD_LIMIT),
22595
- createdAt: codexTimestamp(thread.createdAt),
22596
- updatedAt: codexTimestamp(thread.updatedAt),
22597
- archived,
22598
- modelProvider: codexThreadText(
22599
- thread.modelProvider,
22600
- CODEX_THREAD_TITLE_FIELD_LIMIT
22601
- ),
22602
- cliVersion: codexThreadText(
22603
- thread.cliVersion,
22604
- CODEX_THREAD_TITLE_FIELD_LIMIT
22605
- ),
22606
- gitBranch: codexThreadText(
22607
- gitInfo?.branch,
22608
- CODEX_THREAD_TITLE_FIELD_LIMIT
22609
- ),
22610
- gitOriginUrl: codexThreadText(
22611
- gitInfo?.originUrl,
22612
- CODEX_THREAD_PATH_FIELD_LIMIT
22613
- ),
22614
- path: codexThreadText(thread.path, CODEX_THREAD_PATH_FIELD_LIMIT)
22615
- };
22616
- }
22617
- function codexThreadText(value, maxLength) {
22618
- const text2 = stringValue(value) ?? "";
22619
- if (text2.length <= maxLength) {
22620
- return text2;
22621
- }
22622
- return `${text2.slice(0, Math.max(0, maxLength - 3))}...`;
22623
- }
22624
- function codexTimestamp(value) {
22625
- if (typeof value === "number" && Number.isFinite(value)) {
22626
- return new Date(value * 1e3).toISOString();
22627
- }
22628
- return stringValue(value) ?? "";
22629
- }
22630
- function compareCodexThreadHistoryRows(left, right) {
22631
- const leftRow = objectValue(left);
22632
- const rightRow = objectValue(right);
22633
- const leftTime = Date.parse(
22634
- stringValue(leftRow?.createdAt) ?? stringValue(leftRow?.updatedAt) ?? ""
22635
- );
22636
- const rightTime = Date.parse(
22637
- stringValue(rightRow?.createdAt) ?? stringValue(rightRow?.updatedAt) ?? ""
22638
- );
22639
- return safeComparableTime(leftTime) - safeComparableTime(rightTime);
22640
- }
22641
- function safeComparableTime(value) {
22642
- return Number.isFinite(value) ? value : Number.MAX_SAFE_INTEGER;
22643
- }
22644
22512
  function extractStartedThreadId(response) {
22645
22513
  if ("error" in response) {
22646
22514
  throw new Error(`thread/start failed: ${response.error.message}`);
@@ -23023,9 +22891,9 @@ async function applyControl(codex, kandan, topic, instanceId, options, allowedCw
23023
22891
  case "update_session_settings":
23024
22892
  case "set_port_forward_enabled":
23025
22893
  case "forward_http_request":
23026
- case "forward_websocket_open":
23027
- case "forward_websocket_send":
23028
- case "forward_websocket_close":
22894
+ case "forward_tcp_open":
22895
+ case "forward_tcp_send":
22896
+ case "forward_tcp_close":
23029
22897
  case "start_local_editor":
23030
22898
  case "update_runner_config":
23031
22899
  return { instanceId, controlType: control.type, skipped: true };
@@ -27278,6 +27146,16 @@ import { stdin as defaultStdin, stdout as defaultStdout } from "node:process";
27278
27146
  import { emitKeypressEvents } from "node:readline";
27279
27147
 
27280
27148
  // src/signupServerClient.ts
27149
+ var SignupServerError = class extends Error {
27150
+ status;
27151
+ code;
27152
+ constructor(args) {
27153
+ super(args.message);
27154
+ this.name = "SignupServerError";
27155
+ this.status = args.status;
27156
+ this.code = args.code;
27157
+ }
27158
+ };
27281
27159
  function createSignupServerClient(args) {
27282
27160
  const serviceUrl = args.serviceUrl ?? defaultLinzumiHttpUrl;
27283
27161
  const fetchImpl = args.fetchImpl ?? fetch;
@@ -27368,9 +27246,7 @@ async function signupJsonRequest(args) {
27368
27246
  });
27369
27247
  const responseText = await response.text();
27370
27248
  if (!response.ok) {
27371
- throw new Error(
27372
- `Linzumi signup request failed with HTTP ${response.status}${errorResponseDetail(responseText)}`
27373
- );
27249
+ throw signupResponseError(response.status, responseText);
27374
27250
  }
27375
27251
  const body = parseJsonResponse(responseText, "Linzumi signup response");
27376
27252
  return args.render(body);
@@ -27389,6 +27265,38 @@ function errorResponseDetail(text2) {
27389
27265
  }
27390
27266
  return `: ${trimmed.slice(0, 240)}`;
27391
27267
  }
27268
+ function signupResponseError(status, text2) {
27269
+ const code = signupErrorCodeFromResponseText(text2);
27270
+ if (code !== void 0) {
27271
+ return new SignupServerError({
27272
+ status,
27273
+ code,
27274
+ message: code
27275
+ });
27276
+ }
27277
+ return new Error(
27278
+ `Linzumi signup request failed with HTTP ${status}${errorResponseDetail(text2)}`
27279
+ );
27280
+ }
27281
+ function signupErrorCodeFromResponseText(text2) {
27282
+ const trimmed = text2.trim();
27283
+ if (trimmed === "") {
27284
+ return void 0;
27285
+ }
27286
+ try {
27287
+ const value = JSON.parse(trimmed);
27288
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
27289
+ return void 0;
27290
+ }
27291
+ const error = value.error;
27292
+ if (typeof error === "string" && error.trim() !== "") {
27293
+ return error;
27294
+ }
27295
+ return void 0;
27296
+ } catch (_error) {
27297
+ return void 0;
27298
+ }
27299
+ }
27392
27300
  function renderEmailCodeStart(value) {
27393
27301
  const body = objectRecord(value, "signup email-code start response");
27394
27302
  return {
@@ -27576,6 +27484,7 @@ function booleanValue(record, key) {
27576
27484
  }
27577
27485
 
27578
27486
  // src/signupFlow.ts
27487
+ var maxSignupVerificationCodeAttempts = 3;
27579
27488
  var blue = (value) => `\x1B[38;5;75m${value}\x1B[0m`;
27580
27489
  var green = (value) => `\x1B[38;5;114m${value}\x1B[0m`;
27581
27490
  var red = (value) => `\x1B[38;5;203m${value}\x1B[0m`;
@@ -28108,22 +28017,19 @@ async function runSignupFlow(deps = {}) {
28108
28017
  writeDebugLaunchPayload(output, state, debugLaunchPayload);
28109
28018
  return;
28110
28019
  }
28111
- writeVerificationPrompt(output, codeRequest.request.email);
28112
- const code = await prompts.input({
28113
- message: "Enter your Linzumi verification code",
28114
- defaultValue: signupServerClient === void 0 ? "482931" : ""
28115
- });
28116
- const verifyResult = signupServerClient === void 0 ? void 0 : await verifyEmailCodeForSignup(signupServerClient, {
28020
+ const verificationResult = await promptForVerifiedEmailCode({
28021
+ prompts,
28022
+ output,
28023
+ signupServerClient,
28117
28024
  pendingId: codeRequest.request.pendingId,
28118
- code
28025
+ email: codeRequest.request.email
28119
28026
  });
28120
- if (verifyResult?.type === "failed") {
28027
+ if (verificationResult.type === "failed") {
28121
28028
  state = updateSignupState(state, {
28122
28029
  currentStep: "launch",
28123
- verificationCode: code,
28124
- launchFailure: verifyResult.message
28030
+ verificationCode: verificationResult.code,
28031
+ launchFailure: verificationResult.message
28125
28032
  });
28126
- writeCodeEntry(output, code);
28127
28033
  writeSignupScreen(output, state);
28128
28034
  writePreflightSummary(output, state);
28129
28035
  writeSelectedProjectsSummary(output, state);
@@ -28132,14 +28038,13 @@ async function runSignupFlow(deps = {}) {
28132
28038
  writeDebugLaunchPayload(output, state, debugLaunchPayload);
28133
28039
  return;
28134
28040
  }
28135
- verifiedAuth = verifyResult?.auth;
28041
+ verifiedAuth = verificationResult.verifiedAuth;
28136
28042
  const storedSignupAuth = verifiedAuth === void 0 ? writeSignupAuth({ email }) : signupAuthFromVerification(verifiedAuth, serviceUrl);
28137
28043
  state = updateSignupState(state, {
28138
28044
  currentStep: "launch",
28139
28045
  storedSignupAuth,
28140
- verificationCode: code
28046
+ verificationCode: verificationResult.code
28141
28047
  });
28142
- writeCodeEntry(output, code);
28143
28048
  }
28144
28049
  if (signupServerClient !== void 0 && verifiedAuth !== void 0) {
28145
28050
  const defaultWorkspaceName = verifiedAuth.privateWorkspaceDefault.name || defaultWorkspaceNameForEmail(
@@ -28288,7 +28193,7 @@ async function launchSignupCommanderForCompletedSignup(commanderLauncher, args)
28288
28193
  } catch (error) {
28289
28194
  return {
28290
28195
  status: "failed",
28291
- runnerId: signupCommanderRunnerId(args.workspaceSlug),
28196
+ runnerId: signupCommanderRunnerId(args.serviceUrl),
28292
28197
  restartCommand: signupConnectRestartCommand(args),
28293
28198
  error: error instanceof Error ? error.message : String(error)
28294
28199
  };
@@ -28335,7 +28240,8 @@ async function verifyEmailCodeForSignup(signupServerClient, args) {
28335
28240
  message: signupServerFailureMessage(
28336
28241
  "We couldn't verify your Linzumi email code",
28337
28242
  error
28338
- )
28243
+ ),
28244
+ code: signupServerFailureCode(error)
28339
28245
  };
28340
28246
  }
28341
28247
  }
@@ -28343,6 +28249,43 @@ function signupServerFailureMessage(prefix, error) {
28343
28249
  const message = error instanceof Error ? error.message : String(error);
28344
28250
  return `${prefix}: ${message}`;
28345
28251
  }
28252
+ function signupServerFailureCode(error) {
28253
+ if (error instanceof SignupServerError) {
28254
+ return error.code;
28255
+ }
28256
+ if (error instanceof Error && error.message === "invalid_signup_code") {
28257
+ return "invalid_signup_code";
28258
+ }
28259
+ return void 0;
28260
+ }
28261
+ async function promptForVerifiedEmailCode(args) {
28262
+ writeVerificationPrompt(args.output, args.email);
28263
+ return verifyPromptAttempt(args, 1);
28264
+ }
28265
+ async function verifyPromptAttempt(args, attempt) {
28266
+ const code = await args.prompts.input({
28267
+ message: "Enter your Linzumi verification code",
28268
+ defaultValue: args.signupServerClient === void 0 ? "482931" : ""
28269
+ });
28270
+ const verifyResult = args.signupServerClient === void 0 ? void 0 : await verifyEmailCodeForSignup(args.signupServerClient, {
28271
+ pendingId: args.pendingId,
28272
+ code
28273
+ });
28274
+ writeCodeEntry(args.output, code);
28275
+ if (verifyResult?.type === "failed") {
28276
+ if (verifyResult.code === "invalid_signup_code" && attempt < maxSignupVerificationCodeAttempts) {
28277
+ writeBoundedLine(
28278
+ args.output,
28279
+ muted(
28280
+ " That code was not valid. Enter the newest 6-digit code from your email."
28281
+ )
28282
+ );
28283
+ return verifyPromptAttempt(args, attempt + 1);
28284
+ }
28285
+ return { type: "failed", message: verifyResult.message, code };
28286
+ }
28287
+ return verifyResult === void 0 ? { type: "completed", code } : { type: "completed", code, verifiedAuth: verifyResult.auth };
28288
+ }
28346
28289
  async function refreshExistingSignupAuth(prompts, output, auth, writeSignupAuth, signupServerClient, serviceUrl) {
28347
28290
  output.write(
28348
28291
  `${green("\u2713")} You're already logged in!
@@ -28361,25 +28304,29 @@ ${muted(
28361
28304
  if (codeRequest.type === "failed") {
28362
28305
  return codeRequest;
28363
28306
  }
28364
- writeVerificationPrompt(output, codeRequest.request.email);
28365
- const code = await prompts.input({
28366
- message: "Enter your Linzumi verification code",
28367
- defaultValue: signupServerClient === void 0 ? "482931" : ""
28368
- });
28369
- const verifyResult = signupServerClient === void 0 ? void 0 : await verifyEmailCodeForSignup(signupServerClient, {
28307
+ const verificationResult = await promptForVerifiedEmailCode({
28308
+ prompts,
28309
+ output,
28310
+ signupServerClient,
28370
28311
  pendingId: codeRequest.request.pendingId,
28371
- code
28312
+ email: codeRequest.request.email
28372
28313
  });
28373
- if (verifyResult?.type === "failed") {
28374
- writeCodeEntry(output, code);
28314
+ if (verificationResult.type === "failed") {
28375
28315
  output.write("\n");
28376
- return verifyResult;
28316
+ return {
28317
+ type: "failed",
28318
+ message: verificationResult.message
28319
+ };
28377
28320
  }
28378
- const verifiedAuth = verifyResult?.auth;
28321
+ const verifiedAuth = verificationResult.verifiedAuth;
28379
28322
  const refreshedAuth = verifiedAuth === void 0 ? writeSignupAuth({ email: auth.email }) : signupAuthFromVerification(verifiedAuth, serviceUrl);
28380
- writeCodeEntry(output, code);
28381
28323
  output.write("\n");
28382
- return { type: "completed", auth: refreshedAuth, code, verifiedAuth };
28324
+ return {
28325
+ type: "completed",
28326
+ auth: refreshedAuth,
28327
+ code: verificationResult.code,
28328
+ verifiedAuth
28329
+ };
28383
28330
  }
28384
28331
  async function validateExistingSignupAuth(signupServerClient, auth, retryPolicy) {
28385
28332
  if (signupServerClient === void 0 || auth.accessToken === void 0) {
@@ -28855,7 +28802,7 @@ async function defaultSignupCommanderLauncher(args) {
28855
28802
  accessToken: args.localRunnerAccessToken,
28856
28803
  expiresInSeconds: args.localRunnerExpiresInSeconds
28857
28804
  });
28858
- const runnerId = signupCommanderRunnerId(args.workspaceSlug);
28805
+ const runnerId = signupCommanderRunnerId(args.serviceUrl);
28859
28806
  const restartCommand = signupConnectRestartCommand(args);
28860
28807
  try {
28861
28808
  const handle = await runLocalCodexRunner(
@@ -28878,13 +28825,13 @@ async function defaultSignupCommanderLauncher(args) {
28878
28825
  };
28879
28826
  }
28880
28827
  }
28881
- function signupCommanderRunnerId(workspaceSlug) {
28882
- return `signup-${workspaceSlug}-commander`;
28828
+ function signupCommanderRunnerId(serviceUrl) {
28829
+ return ensureLocalRunnerIdForLinzumiUrl(serviceUrl);
28883
28830
  }
28884
28831
  function failedSignupCommanderLaunchForMissingCodex(args) {
28885
28832
  return {
28886
28833
  status: "failed",
28887
- runnerId: signupCommanderRunnerId(args.workspaceSlug),
28834
+ runnerId: "commander-not-started",
28888
28835
  restartCommand: signupConnectRestartCommand(args),
28889
28836
  error: "Codex preflight did not resolve a verified Codex command. Install Codex or fix the Codex CLI on PATH, then rerun signup."
28890
28837
  };
@@ -30251,7 +30198,7 @@ function runProcessCapture(args) {
30251
30198
  child.on("error", () => {
30252
30199
  finish("");
30253
30200
  });
30254
- child.on("exit", (code) => {
30201
+ child.on("close", (code) => {
30255
30202
  finish(code === 0 ? stdout : "");
30256
30203
  });
30257
30204
  });
@@ -30714,8 +30661,6 @@ function startCommanderDaemon(options) {
30714
30661
  "commander",
30715
30662
  ...options.cwd === void 0 ? [] : [options.cwd],
30716
30663
  ...options.args,
30717
- "--runner-id",
30718
- options.runnerId,
30719
30664
  "--log-file",
30720
30665
  logFile
30721
30666
  ];
@@ -30965,7 +30910,6 @@ var flagDefinitions = /* @__PURE__ */ new Map([
30965
30910
  ["api-url", { kind: "value" }],
30966
30911
  ["linzumi-url", { kind: "value" }],
30967
30912
  ["token", { kind: "value" }],
30968
- ["runner-id", { kind: "value" }],
30969
30913
  ["cwd", { kind: "value" }],
30970
30914
  ["codex-bin", { kind: "value" }],
30971
30915
  ["codex-url", { kind: "value" }],
@@ -31291,7 +31235,8 @@ async function runCommanderDaemonCommand(args) {
31291
31235
  process.stdout.write(commanderDaemonHelpText());
31292
31236
  return;
31293
31237
  }
31294
- const runnerId = required(values, "runner-id");
31238
+ const kandanUrl = kandanUrlValue(values) ?? defaultLinzumiWebSocketUrl;
31239
+ const runnerId = ensureLocalRunnerIdForLinzumiUrl(kandanUrl);
31295
31240
  const cwd = cwdArg === void 0 || cwdArg.trim() === "" ? void 0 : resolveUserPath(cwdArg);
31296
31241
  const record = startCommanderDaemon({
31297
31242
  runnerId,
@@ -31315,7 +31260,8 @@ async function runCommanderDaemonCommand(args) {
31315
31260
  }
31316
31261
  case "status": {
31317
31262
  const values = strictFlagValues(rest);
31318
- const runnerId = required(values, "runner-id");
31263
+ const kandanUrl = kandanUrlValue(values) ?? defaultLinzumiWebSocketUrl;
31264
+ const runnerId = ensureLocalRunnerIdForLinzumiUrl(kandanUrl);
31319
31265
  const status = commanderDaemonStatus(
31320
31266
  runnerId,
31321
31267
  stringValue4(values, "status-dir")
@@ -31326,7 +31272,8 @@ async function runCommanderDaemonCommand(args) {
31326
31272
  }
31327
31273
  case "wait": {
31328
31274
  const values = strictFlagValues(rest);
31329
- const runnerId = required(values, "runner-id");
31275
+ const kandanUrl = kandanUrlValue(values) ?? defaultLinzumiWebSocketUrl;
31276
+ const runnerId = ensureLocalRunnerIdForLinzumiUrl(kandanUrl);
31330
31277
  const timeoutMs = positiveIntegerValue2(values, "timeout-ms") ?? 3e4;
31331
31278
  const result = await waitForCommanderDaemon({
31332
31279
  runnerId,
@@ -31345,7 +31292,8 @@ async function runCommanderDaemonCommand(args) {
31345
31292
  }
31346
31293
  case "stop": {
31347
31294
  const values = strictFlagValues(rest);
31348
- const runnerId = required(values, "runner-id");
31295
+ const kandanUrl = kandanUrlValue(values) ?? defaultLinzumiWebSocketUrl;
31296
+ const runnerId = ensureLocalRunnerIdForLinzumiUrl(kandanUrl);
31349
31297
  const status = stopCommanderDaemon(
31350
31298
  runnerId,
31351
31299
  stringValue4(values, "status-dir")
@@ -31391,7 +31339,8 @@ async function parseStartRunnerArgs(args, deps = {
31391
31339
  fetchStartTarget: fetchLocalRunnerStartTarget,
31392
31340
  validateToken: validateLocalRunnerToken,
31393
31341
  buildDependencyStatus: buildRunnerDependencyStatus,
31394
- resolveEditorRuntime
31342
+ resolveEditorRuntime,
31343
+ ensureRunnerId: ensureLocalRunnerIdForLinzumiUrl
31395
31344
  }) {
31396
31345
  const { cwdArg, flagArgs } = splitStartArgs(args);
31397
31346
  const values = strictFlagValues(flagArgs);
@@ -31463,7 +31412,9 @@ async function parseStartRunnerArgs(args, deps = {
31463
31412
  return {
31464
31413
  kandanUrl,
31465
31414
  token: targetToken,
31466
- runnerId: stringValue4(values, "runner-id") ?? `runner-${randomUUID5()}`,
31415
+ runnerId: (deps.ensureRunnerId ?? ensureLocalRunnerIdForLinzumiUrl)(
31416
+ kandanUrl
31417
+ ),
31467
31418
  workspaceSlug: target.workspaceSlug,
31468
31419
  cwd,
31469
31420
  codexBin,
@@ -31500,7 +31451,8 @@ async function parseStartRunnerArgs(args, deps = {
31500
31451
  async function parseAgentRunnerArgs(args, deps = {
31501
31452
  readTextFile: readAgentTokenTextFile,
31502
31453
  buildDependencyStatus: buildRunnerDependencyStatus,
31503
- resolveEditorRuntime
31454
+ resolveEditorRuntime,
31455
+ ensureRunnerId: ensureLocalRunnerIdForLinzumiUrl
31504
31456
  }) {
31505
31457
  const { cwdArg, flagArgs } = splitStartArgs(args);
31506
31458
  const values = strictFlagValues(flagArgs);
@@ -31565,7 +31517,9 @@ async function parseAgentRunnerArgs(args, deps = {
31565
31517
  return {
31566
31518
  kandanUrl,
31567
31519
  token: tokenFile.commanderToken,
31568
- runnerId: stringValue4(values, "runner-id") ?? `agent-runner-${randomUUID5()}`,
31520
+ runnerId: (deps.ensureRunnerId ?? ensureLocalRunnerIdForLinzumiUrl)(
31521
+ kandanUrl
31522
+ ),
31569
31523
  workspaceSlug: tokenFile.workspaceId,
31570
31524
  cwd,
31571
31525
  codexBin,
@@ -31665,7 +31619,8 @@ async function resolveStartTargetToken(args) {
31665
31619
  async function parseRunnerArgs(args, deps = {
31666
31620
  resolveToken: resolveLocalRunnerToken,
31667
31621
  buildDependencyStatus: buildRunnerDependencyStatus,
31668
- resolveEditorRuntime
31622
+ resolveEditorRuntime,
31623
+ ensureRunnerId: ensureLocalRunnerIdForLinzumiUrl
31669
31624
  }) {
31670
31625
  const values = strictFlagValues(args);
31671
31626
  if (values.get("help") === true) {
@@ -31717,7 +31672,9 @@ async function parseRunnerArgs(args, deps = {
31717
31672
  return {
31718
31673
  kandanUrl,
31719
31674
  token,
31720
- runnerId: stringValue4(values, "runner-id") ?? `runner-${randomUUID5()}`,
31675
+ runnerId: (deps.ensureRunnerId ?? ensureLocalRunnerIdForLinzumiUrl)(
31676
+ kandanUrl
31677
+ ),
31721
31678
  cwd,
31722
31679
  codexBin,
31723
31680
  codexUrl: stringValue4(values, "codex-url"),
@@ -31835,7 +31792,7 @@ function stripDaemonSupervisorFlags(args) {
31835
31792
  }
31836
31793
  const key = arg.startsWith("--") ? arg.slice(2) : void 0;
31837
31794
  const definition = key === void 0 ? void 0 : flagDefinitions.get(key);
31838
- if (key === "runner-id" || key === "log-file" || key === "status-dir") {
31795
+ if (key === "log-file" || key === "status-dir") {
31839
31796
  if (definition?.kind === "value") {
31840
31797
  index += 1;
31841
31798
  }
@@ -31976,8 +31933,8 @@ Usage:
31976
31933
  linzumi done <thread_id> --message <message>
31977
31934
  linzumi init-hello-linzumi-demo-app
31978
31935
  linzumi codex start-new --title <title> --runner <runner_id> --cwd <path> --work-description <text>
31979
- linzumi commander daemon --runner-id <id>
31980
- linzumi commander wait --runner-id <id>
31936
+ linzumi commander daemon
31937
+ linzumi commander wait
31981
31938
  linzumi commander <folder> [options]
31982
31939
  linzumi start <folder> [options]
31983
31940
  linzumi paths list|add|remove [path]
@@ -32021,7 +31978,7 @@ Examples:
32021
31978
  linzumi done thr_abc123 --message "Done: https://github.com/example/repo/pull/1"
32022
31979
  linzumi init-hello-linzumi-demo-app
32023
31980
  linzumi paths add ~/code/my-app
32024
- linzumi commander daemon --runner-id launch-commander
31981
+ linzumi commander daemon
32025
31982
  linzumi start ~/
32026
31983
  linzumi start ~/code/my-app
32027
31984
  linzumi connect --workspace <your-workspace> --launch-tui
@@ -32072,11 +32029,11 @@ function commanderDaemonHelpText() {
32072
32029
  return `Linzumi Commander daemon
32073
32030
 
32074
32031
  Usage:
32075
- linzumi commander daemon --runner-id <id> [options]
32076
- linzumi commander daemon <folder> --runner-id <id> [options]
32077
- linzumi commander status --runner-id <id>
32078
- linzumi commander wait --runner-id <id> [--timeout-ms <ms>]
32079
- linzumi commander stop --runner-id <id>
32032
+ linzumi commander daemon [options]
32033
+ linzumi commander daemon <folder> [options]
32034
+ linzumi commander status [options]
32035
+ linzumi commander wait [--timeout-ms <ms>] [options]
32036
+ linzumi commander stop [options]
32080
32037
 
32081
32038
  What it does:
32082
32039
  Starts the workspace Commander as a detached process, writes a status file,
@@ -32086,7 +32043,7 @@ What it does:
32086
32043
  configured folder.
32087
32044
 
32088
32045
  Options:
32089
- --runner-id <id> Stable Commander id, required
32046
+ --api-url <url> Linzumi API URL used to select the stored scoped runner id
32090
32047
  --status-dir <path> Status directory, default ~/.linzumi/commanders
32091
32048
  --log-file <path> Commander log path, default in the status dir
32092
32049
  --timeout-ms <ms> Wait timeout, default 30000
@@ -32149,9 +32106,9 @@ Usage:
32149
32106
  linzumi commander <folder> [options]
32150
32107
  linzumi commander daemon [options]
32151
32108
  linzumi commander daemon <folder> [options]
32152
- linzumi commander status --runner-id <id>
32153
- linzumi commander wait --runner-id <id>
32154
- linzumi commander stop --runner-id <id>
32109
+ linzumi commander status [options]
32110
+ linzumi commander wait [options]
32111
+ linzumi commander stop [options]
32155
32112
  linzumi agent runner <folder> [options]
32156
32113
 
32157
32114
  What it does:
@@ -32164,7 +32121,6 @@ What it does:
32164
32121
  Options:
32165
32122
  --agent-token-file <path> Agent token cache, default ~/.linzumi/agent-token.json
32166
32123
  --api-url <url> Linzumi API URL. Defaults deterministically from the stored apiUrl.
32167
- --runner-id <id> Stable Commander id
32168
32124
  --codex-bin <path> Codex executable, default codex
32169
32125
  --code-server-bin <path> Custom development code-server executable. By default Linzumi installs the approved editor runtime.
32170
32126
  --listen-user <user> Human whose replies Codex may accept, default owner from claim
@@ -32178,8 +32134,8 @@ Options:
32178
32134
 
32179
32135
  Examples:
32180
32136
  linzumi paths add "$PWD"
32181
- linzumi commander daemon --runner-id hello-world-commander
32182
- linzumi commander ~/code/my-app --api-url http://127.0.0.1:4162 --runner-id local-qa-commander
32137
+ linzumi commander daemon
32138
+ linzumi commander ~/code/my-app --api-url http://127.0.0.1:4162
32183
32139
  `;
32184
32140
  }
32185
32141
  function connectGuideText() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "0.0.55-beta",
3
+ "version": "0.0.57-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": {