@linzumi/cli 0.0.52-beta → 0.0.53-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 +7 -1
  2. package/dist/index.js +35 -114
  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.52-beta --version
65
+ npx -y @linzumi/cli@0.0.53-beta --version
66
66
  linzumi --version
67
67
  ```
68
68
 
@@ -79,6 +79,12 @@ For explicit runner roots, pass a comma-separated allowlist:
79
79
  linzumi start ~/code/my-app --allowed-cwd <paths>
80
80
  ```
81
81
 
82
+ For non-production Linzumi servers, `connect` accepts either API URL flag:
83
+
84
+ ```bash
85
+ linzumi connect --linzumi-url ws://127.0.0.1:4140 --workspace default --allow-port-forwarding-by-default
86
+ ```
87
+
82
88
  ## Agent-first launch path
83
89
 
84
90
  The fastest path is the `npx -y @linzumi/cli@latest signup` command
package/dist/index.js CHANGED
@@ -10456,7 +10456,7 @@ function realpathOrResolved(pathValue) {
10456
10456
  }
10457
10457
 
10458
10458
  // src/version.ts
10459
- var linzumiCliVersion = "0.0.52-beta";
10459
+ var linzumiCliVersion = "0.0.53-beta";
10460
10460
  var linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
10461
10461
 
10462
10462
  // src/runnerLock.ts
@@ -11240,13 +11240,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
11240
11240
  const codex = await connectCodexAppServer(codexUrl);
11241
11241
  cleanup.actions.push(() => codex.close());
11242
11242
  const seq = { value: 0 };
11243
- const codexThreads = options.channelSession === undefined ? await discoverCodexThreads(codex, options.cwd).catch((error) => {
11244
- log("kandan.codex_threads_startup_discovery_failed", {
11245
- message: error instanceof Error ? error.message : String(error)
11246
- });
11247
- return [];
11248
- }) : [];
11249
- const discoveredCodexThreads = { value: codexThreads };
11243
+ const discoveredCodexThreads = { value: [] };
11250
11244
  const runtimeDefaults = runnerRuntimeDefaults(options);
11251
11245
  const instancePayload = {
11252
11246
  instanceId,
@@ -11255,7 +11249,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
11255
11249
  tuiLaunched: options.launchTui,
11256
11250
  cwd: options.cwd,
11257
11251
  hostname: runnerHost,
11258
- codexThreads,
11252
+ codexThreads: discoveredCodexThreads.value,
11259
11253
  workspace: runnerWorkspaceSlug(options) ?? null,
11260
11254
  channel: options.channelSession?.channelSlug ?? null,
11261
11255
  model: runtimeDefaults.model ?? null,
@@ -11399,19 +11393,11 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
11399
11393
  message: error instanceof Error ? error.message : String(error)
11400
11394
  });
11401
11395
  });
11402
- const refreshDiscoveredCodexThreads = () => discoverCodexThreads(codex, options.cwd).then((threads) => {
11403
- discoveredCodexThreads.value = threads;
11404
- return kandan.push(topic, "heartbeat", heartbeatPayload());
11405
- }).catch((error) => {
11406
- log("kandan.codex_threads_refresh_failed", {
11407
- message: error instanceof Error ? error.message : String(error)
11408
- });
11409
- });
11410
11396
  const heartbeatInterval = setInterval(() => {
11411
- channelSession === undefined ? refreshDiscoveredCodexThreads() : pushHeartbeat();
11397
+ pushHeartbeat();
11412
11398
  }, 15000);
11413
11399
  cleanup.actions.push(() => clearInterval(heartbeatInterval));
11414
- kandan.onReconnect(() => (channelSession === undefined ? refreshDiscoveredCodexThreads() : pushHeartbeat()).then(() => {
11400
+ kandan.onReconnect(() => pushHeartbeat().then(() => {
11415
11401
  return;
11416
11402
  }));
11417
11403
  pushHeartbeat();
@@ -11681,96 +11667,6 @@ async function closeCleanupStack(cleanup) {
11681
11667
  })();
11682
11668
  return cleanup.closePromise;
11683
11669
  }
11684
- async function discoverCodexThreads(codex, _cwd) {
11685
- const rowsById = new Map;
11686
- const archivedModes = [false, true];
11687
- const sourcePasses = [
11688
- undefined,
11689
- [
11690
- "exec",
11691
- "appServer",
11692
- "subAgent",
11693
- "subAgentReview",
11694
- "subAgentCompact",
11695
- "subAgentThreadSpawn",
11696
- "subAgentOther",
11697
- "unknown"
11698
- ]
11699
- ];
11700
- for (const archived of archivedModes) {
11701
- for (const sourceKinds of sourcePasses) {
11702
- let cursor;
11703
- while (true) {
11704
- const response = await codex.request("thread/list", {
11705
- limit: 50,
11706
- sortKey: "updated_at",
11707
- sortDirection: "desc",
11708
- archived,
11709
- useStateDbOnly: true,
11710
- ...cursor === undefined ? {} : { cursor },
11711
- ...sourceKinds === undefined ? {} : { sourceKinds }
11712
- });
11713
- if ("error" in response) {
11714
- throw new Error(`thread/list failed: ${response.error.message}`);
11715
- }
11716
- const result = objectValue(response.result);
11717
- const data = arrayValue(result?.data)?.filter(isJsonObject) ?? [];
11718
- for (const thread of data) {
11719
- const row = codexThreadHistoryRow(thread, archived);
11720
- const id = stringValue(objectValue(row)?.id);
11721
- if (id !== undefined && id !== "" && !rowsById.has(id)) {
11722
- rowsById.set(id, row);
11723
- }
11724
- }
11725
- const nextCursor = stringValue(result?.nextCursor);
11726
- if (nextCursor === undefined || nextCursor === "" || data.length === 0) {
11727
- break;
11728
- }
11729
- cursor = nextCursor;
11730
- }
11731
- }
11732
- }
11733
- return Array.from(rowsById.values()).sort(compareCodexThreadHistoryRows);
11734
- }
11735
- function codexThreadHistoryRow(thread, archived) {
11736
- const gitInfo = objectValue(thread.gitInfo);
11737
- const preview = stringValue(thread.preview) ?? "";
11738
- const name = stringValue(thread.name) ?? "";
11739
- const title = stringValue(thread.title) ?? (name === "" ? preview : name);
11740
- const description = stringValue(thread.description) ?? stringValue(thread.summary) ?? preview;
11741
- return {
11742
- id: stringValue(thread.id) ?? "",
11743
- title: title ?? "",
11744
- description: description ?? "",
11745
- preview: preview.replace(/\s+/g, " ").trim(),
11746
- cwd: stringValue(thread.cwd) ?? "",
11747
- source: stringValue(thread.source) ?? "",
11748
- createdAt: codexTimestamp(thread.createdAt),
11749
- updatedAt: codexTimestamp(thread.updatedAt),
11750
- archived,
11751
- modelProvider: stringValue(thread.modelProvider) ?? "",
11752
- cliVersion: stringValue(thread.cliVersion) ?? "",
11753
- gitBranch: stringValue(gitInfo?.branch) ?? "",
11754
- gitOriginUrl: stringValue(gitInfo?.originUrl) ?? "",
11755
- path: stringValue(thread.path) ?? ""
11756
- };
11757
- }
11758
- function codexTimestamp(value) {
11759
- if (typeof value === "number" && Number.isFinite(value)) {
11760
- return new Date(value * 1000).toISOString();
11761
- }
11762
- return stringValue(value) ?? "";
11763
- }
11764
- function compareCodexThreadHistoryRows(left, right) {
11765
- const leftRow = objectValue(left);
11766
- const rightRow = objectValue(right);
11767
- const leftTime = Date.parse(stringValue(leftRow?.createdAt) ?? stringValue(leftRow?.updatedAt) ?? "");
11768
- const rightTime = Date.parse(stringValue(rightRow?.createdAt) ?? stringValue(rightRow?.updatedAt) ?? "");
11769
- return safeComparableTime(leftTime) - safeComparableTime(rightTime);
11770
- }
11771
- function safeComparableTime(value) {
11772
- return Number.isFinite(value) ? value : Number.MAX_SAFE_INTEGER;
11773
- }
11774
11670
  function extractStartedThreadId(response) {
11775
11671
  if ("error" in response) {
11776
11672
  throw new Error(`thread/start failed: ${response.error.message}`);
@@ -18340,6 +18236,7 @@ async function waitForFileChangeOrTimeout(path, deadline, now, ready2 = () => fa
18340
18236
  var flagDefinitions = new Map([
18341
18237
  ["version", { kind: "boolean" }],
18342
18238
  ["api-url", { kind: "value" }],
18239
+ ["linzumi-url", { kind: "value" }],
18343
18240
  ["token", { kind: "value" }],
18344
18241
  ["runner-id", { kind: "value" }],
18345
18242
  ["cwd", { kind: "value" }],
@@ -18354,6 +18251,7 @@ var flagDefinitions = new Map([
18354
18251
  ["reasoning-effort", { kind: "value" }],
18355
18252
  ["sandbox", { kind: "value" }],
18356
18253
  ["approval-policy", { kind: "value" }],
18254
+ ["allow-port-forwarding-by-default", { kind: "boolean" }],
18357
18255
  ["stream-flush-ms", { kind: "value" }],
18358
18256
  ["allowed-cwd", { kind: "value" }],
18359
18257
  ["forward-port", { kind: "value" }],
@@ -18733,7 +18631,7 @@ async function runAuthCommand(args) {
18733
18631
  process.stdout.write(helpText());
18734
18632
  return;
18735
18633
  }
18736
- const kandanUrl = required(values, "api-url");
18634
+ const kandanUrl = requiredKandanUrl(values);
18737
18635
  const target = parseOptionalChannelTarget(values);
18738
18636
  const token = await acquireLocalRunnerTokenDetails({
18739
18637
  kandanUrl,
@@ -18764,7 +18662,7 @@ async function parseStartRunnerArgs(args, deps = {
18764
18662
  process.exit(0);
18765
18663
  }
18766
18664
  rejectStartTargetingFlags(values);
18767
- const kandanUrl = stringValue4(values, "api-url") ?? defaultLinzumiWebSocketUrl;
18665
+ const kandanUrl = kandanUrlValue(values) ?? defaultLinzumiWebSocketUrl;
18768
18666
  const requestedCwd = resolveUserPath(cwdArg ?? process.cwd());
18769
18667
  const cwd = assertConfiguredAllowedCwds([requestedCwd])[0] ?? requestedCwd;
18770
18668
  const explicitAllowedCwds = values.has("allowed-cwd") ? assertConfiguredAllowedCwds(parseAllowedCwdList(stringValue4(values, "allowed-cwd"))) : [];
@@ -18848,6 +18746,7 @@ async function parseStartRunnerArgs(args, deps = {
18848
18746
  reasoningEffort: stringValue4(values, "reasoning-effort"),
18849
18747
  sandbox: stringValue4(values, "sandbox"),
18850
18748
  approvalPolicy: stringValue4(values, "approval-policy"),
18749
+ allowPortForwardingByDefault: booleanFlagValue(values, "allow-port-forwarding-by-default"),
18851
18750
  streamFlushMs: positiveIntegerValue2(values, "stream-flush-ms")
18852
18751
  }
18853
18752
  };
@@ -18880,9 +18779,10 @@ async function parseAgentRunnerArgs(args, deps = {
18880
18779
  reasoningEffort: stringValue4(values, "reasoning-effort"),
18881
18780
  sandbox: stringValue4(values, "sandbox"),
18882
18781
  approvalPolicy: stringValue4(values, "approval-policy"),
18782
+ allowPortForwardingByDefault: booleanFlagValue(values, "allow-port-forwarding-by-default"),
18883
18783
  streamFlushMs: positiveIntegerValue2(values, "stream-flush-ms")
18884
18784
  };
18885
- const kandanUrl = stringValue4(values, "api-url") ?? agentApiUrlToKandanUrl(tokenFile.apiUrl);
18785
+ const kandanUrl = kandanUrlValue(values) ?? agentApiUrlToKandanUrl(tokenFile.apiUrl);
18886
18786
  const requestedCwdValue = cwdArg ?? stringValue4(values, "cwd");
18887
18787
  const requestedCwd = resolveUserPath(requestedCwdValue ?? process.cwd());
18888
18788
  const configuredAllowedCwds2 = requestedCwdValue === undefined && !values.has("allowed-cwd") ? readConfiguredAllowedCwdDetailsForLinzumiUrl(kandanUrl) : { allowedCwds: [], missingAllowedCwds: [] };
@@ -19014,7 +18914,7 @@ async function parseRunnerArgs(args, deps = {
19014
18914
  }
19015
18915
  rejectConnectChannelFlags(values);
19016
18916
  const workspaceSlug = stringValue4(values, "workspace");
19017
- const kandanUrl = stringValue4(values, "api-url") ?? defaultLinzumiWebSocketUrl;
18917
+ const kandanUrl = kandanUrlValue(values) ?? defaultLinzumiWebSocketUrl;
19018
18918
  const cwd = stringValue4(values, "cwd") ?? process.cwd();
19019
18919
  const cwdAllowedCwds = assertConfiguredAllowedCwds([cwd]);
19020
18920
  const localConfiguredAllowedCwds = values.has("allowed-cwd") ? { allowedCwds: [], missingAllowedCwds: [] } : readConfiguredAllowedCwdDetailsForLinzumiUrl(kandanUrl);
@@ -19073,9 +18973,27 @@ function runnerRuntimeDefaultsFromValues(values) {
19073
18973
  reasoningEffort: stringValue4(values, "reasoning-effort"),
19074
18974
  approvalPolicy: stringValue4(values, "approval-policy"),
19075
18975
  sandbox: stringValue4(values, "sandbox"),
19076
- allowPortForwardingByDefault: undefined
18976
+ allowPortForwardingByDefault: booleanFlagValue(values, "allow-port-forwarding-by-default")
19077
18977
  };
19078
18978
  }
18979
+ function kandanUrlValue(values) {
18980
+ const apiUrl = stringValue4(values, "api-url");
18981
+ const linzumiUrl = stringValue4(values, "linzumi-url");
18982
+ if (apiUrl !== undefined && linzumiUrl !== undefined && apiUrl !== linzumiUrl) {
18983
+ throw new Error("use only one of --api-url or --linzumi-url");
18984
+ }
18985
+ return apiUrl ?? linzumiUrl;
18986
+ }
18987
+ function requiredKandanUrl(values) {
18988
+ const value = kandanUrlValue(values);
18989
+ if (value === undefined) {
18990
+ throw new Error("missing required flag: --api-url or --linzumi-url");
18991
+ }
18992
+ return value;
18993
+ }
18994
+ function booleanFlagValue(values, key) {
18995
+ return values.get(key) === true ? true : undefined;
18996
+ }
19079
18997
  function strictFlagValues(args, definitions = flagDefinitions) {
19080
18998
  const values = new Map;
19081
18999
  for (let index = 0;index < args.length; index += 1) {
@@ -19282,6 +19200,7 @@ Usage:
19282
19200
 
19283
19201
  Connection:
19284
19202
  --api-url <url> Linzumi API URL, default ${defaultLinzumiWebSocketUrl}
19203
+ --linzumi-url <url> Alias for --api-url
19285
19204
  --token <jwt> Optional override token. Otherwise ~/.linzumi/auth.json is validated or OAuth opens.
19286
19205
  --auth-file <path> Auth cache path, default ~/.linzumi/auth.json
19287
19206
  --oauth-callback-host <ip> Callback host reachable by your browser
@@ -19298,6 +19217,8 @@ Codex:
19298
19217
  --reasoning-effort <value> Reasoning effort requested for Codex and shown in Linzumi
19299
19218
  --sandbox <value> Sandbox metadata shown in Linzumi
19300
19219
  --approval-policy <value> Approval-policy metadata shown in Linzumi
19220
+ --allow-port-forwarding-by-default
19221
+ Auto-approve detected port-forward candidates for started sessions
19301
19222
  --stream-flush-ms <ms> Batch live Codex deltas before Linzumi persistence, default 150
19302
19223
  --fast Mark this runner as low-latency/fast in the availability message
19303
19224
  --log-file <path> JSONL event log path, default <cwd>/.linzumi-runner.log
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "0.0.52-beta",
3
+ "version": "0.0.53-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": {