@linzumi/cli 0.0.24-beta → 0.0.26-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 +12 -9
  2. package/dist/index.js +236 -164
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -132,10 +132,11 @@ npx -y @linzumi/cli@latest channel post <support_channel_id> "Hello @sean, start
132
132
  npx -y @linzumi/cli@latest thread new "Hello Linzumi confetti" --message "Preparing the Hello Linzumi demo. Next I will generate /tmp/hello_linzumi, start its hot-reload server bound to 0.0.0.0 on port 8787, and ask Linzumi Codex to add confetti when the page loads."
133
133
  commander_id="hello-linzumi-commander-${thread_id%%-*}"
134
134
  npx -y @linzumi/cli@latest init-hello-linzumi-demo-app --parent-dir /tmp --name hello_linzumi --host 0.0.0.0 --port 8787 --reset --json
135
- (cd /tmp/hello_linzumi && npm run dev > /tmp/hello_linzumi/dev.log 2>&1 &)
136
- npx -y @linzumi/cli@latest commander /tmp/hello_linzumi \
135
+ project_dir="$(cd /tmp/hello_linzumi && pwd -P)"
136
+ (cd "$project_dir" && npm run dev > "$project_dir/dev.log" 2>&1 &)
137
+ npx -y @linzumi/cli@latest commander "$project_dir" \
137
138
  --runner-id "$commander_id" \
138
- --allowed-cwd /tmp/hello_linzumi \
139
+ --allowed-cwd "$project_dir" \
139
140
  --forward-port 8787 \
140
141
  --sandbox danger-full-access \
141
142
  --approval-policy never
@@ -143,8 +144,10 @@ npx -y @linzumi/cli@latest commander /tmp/hello_linzumi \
143
144
 
144
145
  The agent-owned Commander reads `~/.linzumi/agent-token.json`, uses the
145
146
  workspace/channel scope from the approval flow, trusts only the selected
146
- folder, advertises the explicit preview port, and listens only to the
147
- approving human unless `--listen-user` is explicitly passed. Use a unique
147
+ folder, marks that same folder trusted in Codex's normal project config so
148
+ Codex does not stop for an interactive trust prompt, advertises the explicit
149
+ preview port, and listens only to the approving human unless `--listen-user` is
150
+ explicitly passed. Use a unique
148
151
  Commander id per launch thread; Linzumi stores trusted-folder config per
149
152
  Commander id, so reusing an old fixed id can pick up stale allowed-cwd config.
150
153
  The bootstrap agent waits for `Runner connected:` before starting Codex in the Linzumi
@@ -170,12 +173,12 @@ Codex and open the browser editor for the same thread and folder:
170
173
  ```bash
171
174
  npx -y @linzumi/cli@latest codex start <thread_id> \
172
175
  --runner "$commander_id" \
173
- --cwd /tmp/hello_linzumi \
174
- --work-description "Work only in /tmp/hello_linzumi. Add tasteful confetti when the Hello Linzumi page loads, keep the hot-reload app working on port 8787, and post the exact files changed."
176
+ --cwd "$project_dir" \
177
+ --work-description "Work only in the canonical Hello Linzumi project directory printed by pwd -P for /tmp/hello_linzumi. Add tasteful confetti when the Hello Linzumi page loads, keep the hot-reload app working on port 8787, and post the exact files changed."
175
178
 
176
179
  npx -y @linzumi/cli@latest editor open <thread_id> \
177
180
  --runner "$commander_id" \
178
- --cwd /tmp/hello_linzumi
181
+ --cwd "$project_dir"
179
182
  ```
180
183
 
181
184
  The launch target for this path is zero-to-Hello-Linzumi-editor+preview in
@@ -276,7 +279,7 @@ intentionally. Every action is auditable from the thread.
276
279
  ## Pinning a version
277
280
 
278
281
  ```bash
279
- npm install -g @linzumi/cli@0.0.24-beta
282
+ npm install -g @linzumi/cli@0.0.26-beta
280
283
  linzumi --version
281
284
  ```
282
285
 
package/dist/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  // src/index.ts
2
2
  import { randomUUID as randomUUID3 } from "node:crypto";
3
- import { existsSync as existsSync8, readFileSync as readFileSync7, realpathSync as realpathSync4 } from "node:fs";
4
- import { homedir as homedir6 } from "node:os";
5
- import { resolve as resolve6 } from "node:path";
3
+ import { existsSync as existsSync9, readFileSync as readFileSync8, realpathSync as realpathSync5 } from "node:fs";
4
+ import { homedir as homedir7 } from "node:os";
5
+ import { resolve as resolve7 } from "node:path";
6
6
  import { fileURLToPath as fileURLToPath2 } from "node:url";
7
7
 
8
8
  // src/runner.ts
9
9
  import { spawn as spawn6 } from "node:child_process";
10
10
  import { randomUUID as randomUUID2 } from "node:crypto";
11
11
  import { hostname as hostname2 } from "node:os";
12
- import { join as join4 } from "node:path";
12
+ import { join as join5 } from "node:path";
13
13
 
14
14
  // src/channelSessionSupport.ts
15
15
  import { spawnSync } from "node:child_process";
@@ -4209,10 +4209,72 @@ function readyzUrlForWebsocket(websocketUrl) {
4209
4209
  return parsed.toString();
4210
4210
  }
4211
4211
 
4212
- // src/localCapabilities.ts
4213
- import { realpathSync } from "node:fs";
4212
+ // src/codexProjectTrust.ts
4213
+ import {
4214
+ existsSync,
4215
+ mkdirSync,
4216
+ readFileSync,
4217
+ realpathSync,
4218
+ writeFileSync
4219
+ } from "node:fs";
4214
4220
  import { homedir } from "node:os";
4215
- import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 } from "node:path";
4221
+ import { join as join2, resolve as resolve2 } from "node:path";
4222
+ function ensureCodexProjectTrusted(projectPath, options = {}) {
4223
+ const trustedPath = realpathSync(resolve2(projectPath));
4224
+ const configHome = options.configHome ?? process.env.CODEX_HOME ?? join2(homedir(), ".codex");
4225
+ const configPath = join2(configHome, "config.toml");
4226
+ const currentConfig = existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
4227
+ const nextConfig = codexConfigWithTrustedProject(currentConfig, trustedPath);
4228
+ if (nextConfig !== currentConfig) {
4229
+ mkdirSync(configHome, { recursive: true });
4230
+ writeFileSync(configPath, nextConfig);
4231
+ }
4232
+ return trustedPath;
4233
+ }
4234
+ function codexConfigWithTrustedProject(config, projectPath) {
4235
+ const header = `[projects.${tomlString(projectPath)}]`;
4236
+ const range = findTableRange(config, header);
4237
+ if (range === undefined) {
4238
+ const separator = config.trim() === "" ? "" : `
4239
+
4240
+ `;
4241
+ return `${trimTrailingNewlines(config)}${separator}${header}
4242
+ trust_level = "trusted"
4243
+ `;
4244
+ }
4245
+ const table = config.slice(range.start, range.end);
4246
+ const trustLine = /^(\s*trust_level\s*=\s*).*(\r?)$/m;
4247
+ const nextTable = trustLine.test(table) ? table.replace(trustLine, '$1"trusted"$2') : `${trimTrailingNewlines(table)}
4248
+ trust_level = "trusted"
4249
+ `;
4250
+ return `${config.slice(0, range.start)}${nextTable}${config.slice(range.end)}`;
4251
+ }
4252
+ function findTableRange(config, header) {
4253
+ const tableHeader = /^\s*\[[^\]]+\]\s*$/gm;
4254
+ let match;
4255
+ while ((match = tableHeader.exec(config)) !== null) {
4256
+ if (match[0].trim() !== header) {
4257
+ continue;
4258
+ }
4259
+ const nextMatch = tableHeader.exec(config);
4260
+ return {
4261
+ start: match.index,
4262
+ end: nextMatch?.index ?? config.length
4263
+ };
4264
+ }
4265
+ return;
4266
+ }
4267
+ function tomlString(value) {
4268
+ return JSON.stringify(value);
4269
+ }
4270
+ function trimTrailingNewlines(value) {
4271
+ return value.replace(/\r?\n+$/, "");
4272
+ }
4273
+
4274
+ // src/localCapabilities.ts
4275
+ import { realpathSync as realpathSync2 } from "node:fs";
4276
+ import { homedir as homedir2 } from "node:os";
4277
+ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve3 } from "node:path";
4216
4278
  function parseAllowedCwdList(value) {
4217
4279
  if (value === undefined) {
4218
4280
  return [];
@@ -4238,20 +4300,23 @@ function parseAllowedPortList(value) {
4238
4300
  return [...ports].sort((left, right) => left - right);
4239
4301
  }
4240
4302
  function assertConfiguredAllowedCwds(paths) {
4241
- return paths.map((path) => {
4303
+ const allowed = paths.flatMap((path) => {
4242
4304
  try {
4243
- return realpathSync(resolve2(expandUserPath(path)));
4305
+ const absolutePath = resolve3(expandUserPath(path));
4306
+ const realPath = realpathSync2(absolutePath);
4307
+ return realPath === absolutePath ? [realPath] : [realPath, absolutePath];
4244
4308
  } catch (_error) {
4245
4309
  throw new Error(`invalid --allowed-cwd: ${path} does not exist`);
4246
4310
  }
4247
4311
  });
4312
+ return Array.from(new Set(allowed));
4248
4313
  }
4249
4314
  function expandUserPath(pathValue) {
4250
4315
  if (pathValue === "~") {
4251
- return homedir();
4316
+ return homedir2();
4252
4317
  }
4253
4318
  if (pathValue.startsWith("~/")) {
4254
- return resolve2(homedir(), pathValue.slice(2));
4319
+ return resolve3(homedir2(), pathValue.slice(2));
4255
4320
  }
4256
4321
  return pathValue;
4257
4322
  }
@@ -4264,7 +4329,7 @@ function resolveAllowedCwd(requestedCwd, allowedRoots) {
4264
4329
  }
4265
4330
  let cwd;
4266
4331
  try {
4267
- cwd = realpathSync(resolve2(requestedCwd));
4332
+ cwd = realpathSync2(resolve3(requestedCwd));
4268
4333
  } catch (_error) {
4269
4334
  return { ok: false, reason: "cwd_not_found" };
4270
4335
  }
@@ -4569,14 +4634,14 @@ var blockedForwardHeaderNames = new Set([
4569
4634
  import { spawn as spawn2 } from "node:child_process";
4570
4635
  import {
4571
4636
  cpSync,
4572
- existsSync,
4573
- mkdirSync,
4637
+ existsSync as existsSync2,
4638
+ mkdirSync as mkdirSync2,
4574
4639
  mkdtempSync,
4575
- realpathSync as realpathSync2,
4576
- writeFileSync
4640
+ realpathSync as realpathSync3,
4641
+ writeFileSync as writeFileSync2
4577
4642
  } from "node:fs";
4578
4643
  import { tmpdir } from "node:os";
4579
- import { basename as basename3, delimiter, dirname, join as join2 } from "node:path";
4644
+ import { basename as basename3, delimiter, dirname, join as join3 } from "node:path";
4580
4645
  function isStartLocalEditorControl(control) {
4581
4646
  return control.type === "start_local_editor";
4582
4647
  }
@@ -4739,17 +4804,17 @@ function codeServerArgs(port, cwd, userDataDir, extensionsDir) {
4739
4804
  }
4740
4805
  function prepareCodeServerProfile(collaboration, editorRuntime) {
4741
4806
  try {
4742
- const userDataDir = mkdtempSync(join2(tmpdir(), "kandan-local-editor-"));
4743
- const extensionsDir = join2(userDataDir, "extensions");
4744
- const collaborationServerDir = join2(userDataDir, "collaboration-server");
4745
- const userSettingsDir = join2(userDataDir, "User");
4746
- mkdirSync(userSettingsDir, { recursive: true });
4747
- mkdirSync(extensionsDir, { recursive: true });
4748
- mkdirSync(collaborationServerDir, { recursive: true });
4807
+ const userDataDir = mkdtempSync(join3(tmpdir(), "kandan-local-editor-"));
4808
+ const extensionsDir = join3(userDataDir, "extensions");
4809
+ const collaborationServerDir = join3(userDataDir, "collaboration-server");
4810
+ const userSettingsDir = join3(userDataDir, "User");
4811
+ mkdirSync2(userSettingsDir, { recursive: true });
4812
+ mkdirSync2(extensionsDir, { recursive: true });
4813
+ mkdirSync2(collaborationServerDir, { recursive: true });
4749
4814
  if (editorRuntime !== undefined) {
4750
- installDirectory(editorRuntime.assets.documentStateExtensionDir, join2(extensionsDir, "kandan.document-state-telemetry"));
4815
+ installDirectory(editorRuntime.assets.documentStateExtensionDir, join3(extensionsDir, "kandan.document-state-telemetry"));
4751
4816
  }
4752
- writeFileSync(join2(userSettingsDir, "settings.json"), JSON.stringify(codeServerSettings(collaboration), null, 2));
4817
+ writeFileSync2(join3(userSettingsDir, "settings.json"), JSON.stringify(codeServerSettings(collaboration), null, 2));
4753
4818
  return { ok: true, userDataDir, extensionsDir, collaborationServerDir };
4754
4819
  } catch (_error) {
4755
4820
  return { ok: false, reason: "code_server_spawn_failed" };
@@ -4764,7 +4829,7 @@ function prepareCodeServerLaunch(options) {
4764
4829
  return filesystemSandboxUnavailable();
4765
4830
  }
4766
4831
  const sandboxExecBin = options.sandboxExecBin ?? "/usr/bin/sandbox-exec";
4767
- if (!existsSync(sandboxExecBin)) {
4832
+ if (!existsSync2(sandboxExecBin)) {
4768
4833
  return filesystemSandboxUnavailable();
4769
4834
  }
4770
4835
  const codeServerExecutable = resolveCodeServerExecutable(options.codeServerBin, options.envPath ?? process.env.PATH ?? "");
@@ -4818,10 +4883,10 @@ function prepareLinuxCodeServerLaunch(options) {
4818
4883
  options.userDataDir,
4819
4884
  "--setenv",
4820
4885
  "XDG_DATA_HOME",
4821
- join2(options.userDataDir, "data"),
4886
+ join3(options.userDataDir, "data"),
4822
4887
  "--setenv",
4823
4888
  "XDG_CONFIG_HOME",
4824
- join2(options.userDataDir, "config"),
4889
+ join3(options.userDataDir, "config"),
4825
4890
  ...readOnlyRoots.flatMap((path) => ["--ro-bind-try", path, path]),
4826
4891
  "--bind",
4827
4892
  options.cwd,
@@ -4894,11 +4959,11 @@ function resolveCodeServerExecutable(command, envPath) {
4894
4959
  if (directory.trim() === "") {
4895
4960
  continue;
4896
4961
  }
4897
- const candidate = join2(directory, command);
4898
- if (!existsSync(candidate)) {
4962
+ const candidate = join3(directory, command);
4963
+ if (!existsSync2(candidate)) {
4899
4964
  continue;
4900
4965
  }
4901
- const realpath = realpathSync2(candidate);
4966
+ const realpath = realpathSync3(candidate);
4902
4967
  return { ok: true, command: realpath, directory: dirname(realpath) };
4903
4968
  }
4904
4969
  return { ok: false };
@@ -4908,7 +4973,7 @@ function hasPathSeparator(path) {
4908
4973
  }
4909
4974
  function safeRealpathDir(path) {
4910
4975
  try {
4911
- const directory = dirname(realpathSync2(path));
4976
+ const directory = dirname(realpathSync3(path));
4912
4977
  return directory === "/" ? undefined : directory;
4913
4978
  } catch (_error) {
4914
4979
  const directory = dirname(path);
@@ -4917,7 +4982,7 @@ function safeRealpathDir(path) {
4917
4982
  }
4918
4983
  function sandboxPathAliases(path) {
4919
4984
  try {
4920
- return [path, realpathSync2(path)];
4985
+ return [path, realpathSync3(path)];
4921
4986
  } catch (_error) {
4922
4987
  return [path];
4923
4988
  }
@@ -4971,7 +5036,7 @@ async function startCollaborationSidecar(collaboration, profile, editorRuntime)
4971
5036
  installLocalTarball(editorRuntime.assets.collaborationServerTarball, profile.collaborationServerDir)
4972
5037
  ]);
4973
5038
  const child = spawn2(nodeRuntimeExecutable(), [
4974
- join2(profile.collaborationServerDir, "open-collaboration-server", "bundle", "app.js"),
5039
+ join3(profile.collaborationServerDir, "open-collaboration-server", "bundle", "app.js"),
4975
5040
  "--hostname",
4976
5041
  "127.0.0.1",
4977
5042
  "--port",
@@ -5017,11 +5082,11 @@ function nodeRuntimeExecutable(env = process.env, execPath = process.execPath) {
5017
5082
  return basename3(execPath).toLowerCase().includes("bun") ? "node" : execPath;
5018
5083
  }
5019
5084
  async function installLocalTarball(archivePath, destinationDir) {
5020
- mkdirSync(destinationDir, { recursive: true });
5085
+ mkdirSync2(destinationDir, { recursive: true });
5021
5086
  await runProcess("tar", ["-xzf", archivePath, "-C", destinationDir]);
5022
5087
  }
5023
5088
  function installDirectory(sourceDir, destinationDir) {
5024
- mkdirSync(dirname(destinationDir), { recursive: true });
5089
+ mkdirSync2(dirname(destinationDir), { recursive: true });
5025
5090
  cpSync(sourceDir, destinationDir, { recursive: true });
5026
5091
  }
5027
5092
  function codeServerEnv(env, userDataDir, collaboration) {
@@ -5029,9 +5094,9 @@ function codeServerEnv(env, userDataDir, collaboration) {
5029
5094
  const base = {
5030
5095
  ...hostEnv,
5031
5096
  HOME: userDataDir,
5032
- XDG_CACHE_HOME: join2(userDataDir, "xdg-cache"),
5033
- XDG_CONFIG_HOME: join2(userDataDir, "xdg-config"),
5034
- XDG_DATA_HOME: join2(userDataDir, "xdg-data")
5097
+ XDG_CACHE_HOME: join3(userDataDir, "xdg-cache"),
5098
+ XDG_CONFIG_HOME: join3(userDataDir, "xdg-config"),
5099
+ XDG_DATA_HOME: join3(userDataDir, "xdg-data")
5035
5100
  };
5036
5101
  if (collaboration === undefined) {
5037
5102
  return base;
@@ -5064,14 +5129,14 @@ function sameCollaboration(running, requested) {
5064
5129
  return running.editorSessionId === requested.editorSessionId && running.runtimeSessionId === requested.runtimeSessionId && running.roomId === requested.roomId;
5065
5130
  }
5066
5131
  function runProcess(command, args) {
5067
- return new Promise((resolve3, reject) => {
5132
+ return new Promise((resolve4, reject) => {
5068
5133
  const child = spawn2(command, [...args], {
5069
5134
  stdio: ["ignore", "ignore", "inherit"]
5070
5135
  });
5071
5136
  child.once("error", reject);
5072
5137
  child.once("exit", (code) => {
5073
5138
  if (code === 0) {
5074
- resolve3();
5139
+ resolve4();
5075
5140
  } else {
5076
5141
  reject(new Error(`${command} exited with ${code ?? "unknown"}`));
5077
5142
  }
@@ -5079,7 +5144,7 @@ function runProcess(command, args) {
5079
5144
  });
5080
5145
  }
5081
5146
  function waitForCodeServerExit(child) {
5082
- return new Promise((resolve3) => {
5147
+ return new Promise((resolve4) => {
5083
5148
  let settled = false;
5084
5149
  const cleanup = () => {
5085
5150
  child.off("exit", onDone);
@@ -5091,7 +5156,7 @@ function waitForCodeServerExit(child) {
5091
5156
  }
5092
5157
  settled = true;
5093
5158
  cleanup();
5094
- resolve3();
5159
+ resolve4();
5095
5160
  };
5096
5161
  child.once("exit", onDone);
5097
5162
  child.once("close", onDone);
@@ -5103,7 +5168,7 @@ function waitForCodeServerExit(child) {
5103
5168
  function waitForCodeServerReady(port, exited, timeoutMs = 1e4) {
5104
5169
  const deadline = Date.now() + timeoutMs;
5105
5170
  const readyUrl = `http://127.0.0.1:${port}/`;
5106
- return new Promise((resolve3) => {
5171
+ return new Promise((resolve4) => {
5107
5172
  let settled = false;
5108
5173
  let timer;
5109
5174
  const finish = (result) => {
@@ -5114,7 +5179,7 @@ function waitForCodeServerReady(port, exited, timeoutMs = 1e4) {
5114
5179
  if (timer !== undefined) {
5115
5180
  clearTimeout(timer);
5116
5181
  }
5117
- resolve3(result);
5182
+ resolve4(result);
5118
5183
  };
5119
5184
  const scheduleCheck = () => {
5120
5185
  timer = setTimeout(checkReady, 50);
@@ -5143,7 +5208,7 @@ function waitForCodeServerReady(port, exited, timeoutMs = 1e4) {
5143
5208
  function waitForCollaborationServerReady(port, exited, timeoutMs = 1e4) {
5144
5209
  const deadline = Date.now() + timeoutMs;
5145
5210
  const readyUrl = `http://127.0.0.1:${port}/api/login/initial`;
5146
- return new Promise((resolve3) => {
5211
+ return new Promise((resolve4) => {
5147
5212
  let settled = false;
5148
5213
  let timer;
5149
5214
  const finish = (result) => {
@@ -5154,7 +5219,7 @@ function waitForCollaborationServerReady(port, exited, timeoutMs = 1e4) {
5154
5219
  if (timer !== undefined) {
5155
5220
  clearTimeout(timer);
5156
5221
  }
5157
- resolve3(result);
5222
+ resolve4(result);
5158
5223
  };
5159
5224
  const scheduleCheck = () => {
5160
5225
  timer = setTimeout(checkReady, 50);
@@ -5181,7 +5246,7 @@ function waitForCollaborationServerReady(port, exited, timeoutMs = 1e4) {
5181
5246
  });
5182
5247
  }
5183
5248
  function waitForCodeServerSpawn(child) {
5184
- return new Promise((resolve3) => {
5249
+ return new Promise((resolve4) => {
5185
5250
  let settled = false;
5186
5251
  const cleanup = () => {
5187
5252
  child.off("spawn", onSpawn);
@@ -5193,7 +5258,7 @@ function waitForCodeServerSpawn(child) {
5193
5258
  }
5194
5259
  settled = true;
5195
5260
  cleanup();
5196
- resolve3("spawned");
5261
+ resolve4("spawned");
5197
5262
  };
5198
5263
  const onError = () => {
5199
5264
  if (settled) {
@@ -5201,7 +5266,7 @@ function waitForCodeServerSpawn(child) {
5201
5266
  }
5202
5267
  settled = true;
5203
5268
  cleanup();
5204
- resolve3("failed");
5269
+ resolve4("failed");
5205
5270
  };
5206
5271
  child.once("spawn", onSpawn);
5207
5272
  child.once("error", onError);
@@ -5222,16 +5287,16 @@ import { createHash as createHash2 } from "node:crypto";
5222
5287
  import {
5223
5288
  createReadStream,
5224
5289
  createWriteStream,
5225
- existsSync as existsSync2,
5226
- mkdirSync as mkdirSync2,
5290
+ existsSync as existsSync3,
5291
+ mkdirSync as mkdirSync3,
5227
5292
  mkdtempSync as mkdtempSync2,
5228
- readFileSync,
5293
+ readFileSync as readFileSync2,
5229
5294
  renameSync,
5230
5295
  rmSync,
5231
- writeFileSync as writeFileSync2
5296
+ writeFileSync as writeFileSync3
5232
5297
  } from "node:fs";
5233
- import { homedir as homedir2 } from "node:os";
5234
- import { dirname as dirname2, join as join3, resolve as resolve3 } from "node:path";
5298
+ import { homedir as homedir3 } from "node:os";
5299
+ import { dirname as dirname2, join as join4, resolve as resolve4 } from "node:path";
5235
5300
  import { Readable } from "node:stream";
5236
5301
  import { pipeline } from "node:stream/promises";
5237
5302
 
@@ -5402,7 +5467,7 @@ function stringBodyField(body, key) {
5402
5467
  return typeof value === "string" && value.trim() !== "" ? value : undefined;
5403
5468
  }
5404
5469
  function startCallbackServer(args) {
5405
- return new Promise((resolve3, reject) => {
5470
+ return new Promise((resolve4, reject) => {
5406
5471
  let resolveCallback;
5407
5472
  let rejectCallback;
5408
5473
  const callbackPromise = new Promise((callbackResolve, callbackReject) => {
@@ -5454,7 +5519,7 @@ function startCallbackServer(args) {
5454
5519
  reject(new Error("local runner OAuth callback server did not bind to a TCP port"));
5455
5520
  return;
5456
5521
  }
5457
- resolve3({
5522
+ resolve4({
5458
5523
  redirectUri: `http://${args.host}:${address.port}/callback`,
5459
5524
  waitForCallback: () => callbackPromise,
5460
5525
  close: () => {
@@ -5505,12 +5570,12 @@ function escapeHtml(value) {
5505
5570
  function openBrowser(url) {
5506
5571
  const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
5507
5572
  const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
5508
- return new Promise((resolve3) => {
5573
+ return new Promise((resolve4) => {
5509
5574
  const child = spawn3(command, args, { stdio: "ignore", detached: true });
5510
- child.on("error", () => resolve3());
5575
+ child.on("error", () => resolve4());
5511
5576
  child.on("spawn", () => {
5512
5577
  child.unref();
5513
- resolve3();
5578
+ resolve4();
5514
5579
  });
5515
5580
  });
5516
5581
  }
@@ -5693,14 +5758,14 @@ function normalizeRuntimeAssets(value) {
5693
5758
  }
5694
5759
  function installedRuntime(cacheRoot, manifest) {
5695
5760
  const runtimeRoot = runtimeInstallRoot(cacheRoot, manifest);
5696
- const manifestPath = join3(runtimeRoot, manifest.manifestPath);
5697
- const codeServerBin = join3(runtimeRoot, manifest.codeServerBinPath);
5761
+ const manifestPath = join4(runtimeRoot, manifest.manifestPath);
5762
+ const codeServerBin = join4(runtimeRoot, manifest.codeServerBinPath);
5698
5763
  const assets = verifiedRuntimeAssetPaths(runtimeRoot, manifest);
5699
- if (!existsSync2(manifestPath) || !existsSync2(codeServerBin) || assets === undefined) {
5764
+ if (!existsSync3(manifestPath) || !existsSync3(codeServerBin) || assets === undefined) {
5700
5765
  return { ok: false };
5701
5766
  }
5702
5767
  try {
5703
- const installed = JSON.parse(readFileSync(manifestPath, "utf8"));
5768
+ const installed = JSON.parse(readFileSync2(manifestPath, "utf8"));
5704
5769
  if (isJsonObject(installed) && installed.version === manifest.version && installed.platform === manifest.platform && (installed.archiveSha256 === undefined || installed.archiveSha256 === manifest.archiveSha256)) {
5705
5770
  return {
5706
5771
  ok: true,
@@ -5718,10 +5783,10 @@ function installedRuntime(cacheRoot, manifest) {
5718
5783
  return { ok: false };
5719
5784
  }
5720
5785
  async function installRuntime(args) {
5721
- mkdirSync2(args.cacheRoot, { recursive: true });
5722
- const tempRoot = mkdtempSync2(join3(args.cacheRoot, ".install-"));
5723
- const archivePath = join3(tempRoot, "runtime.tar.gz");
5724
- const extractRoot = join3(tempRoot, "runtime");
5786
+ mkdirSync3(args.cacheRoot, { recursive: true });
5787
+ const tempRoot = mkdtempSync2(join4(args.cacheRoot, ".install-"));
5788
+ const archivePath = join4(tempRoot, "runtime.tar.gz");
5789
+ const extractRoot = join4(tempRoot, "runtime");
5725
5790
  try {
5726
5791
  const downloaded = await downloadArchive({
5727
5792
  kandanUrl: args.kandanUrl,
@@ -5733,7 +5798,7 @@ async function installRuntime(args) {
5733
5798
  if (!downloaded.ok) {
5734
5799
  return downloaded;
5735
5800
  }
5736
- mkdirSync2(extractRoot, { recursive: true });
5801
+ mkdirSync3(extractRoot, { recursive: true });
5737
5802
  if (!await args.extractArchive(archivePath, extractRoot)) {
5738
5803
  return { ok: false, reason: "archive_extract_failed" };
5739
5804
  }
@@ -5746,14 +5811,14 @@ async function installRuntime(args) {
5746
5811
  if (!assetsInstalled) {
5747
5812
  return { ok: false, reason: "install_failed" };
5748
5813
  }
5749
- const manifestPath = join3(extractRoot, args.manifest.manifestPath);
5750
- const codeServerBin = join3(extractRoot, args.manifest.codeServerBinPath);
5814
+ const manifestPath = join4(extractRoot, args.manifest.manifestPath);
5815
+ const codeServerBin = join4(extractRoot, args.manifest.codeServerBinPath);
5751
5816
  const assets = verifiedRuntimeAssetPaths(extractRoot, args.manifest);
5752
- if (!existsSync2(codeServerBin) || assets === undefined) {
5817
+ if (!existsSync3(codeServerBin) || assets === undefined) {
5753
5818
  return { ok: false, reason: "invalid_archive" };
5754
5819
  }
5755
- mkdirSync2(dirname2(manifestPath), { recursive: true });
5756
- writeFileSync2(manifestPath, JSON.stringify({
5820
+ mkdirSync3(dirname2(manifestPath), { recursive: true });
5821
+ writeFileSync3(manifestPath, JSON.stringify({
5757
5822
  version: args.manifest.version,
5758
5823
  platform: args.manifest.platform,
5759
5824
  archiveSha256: args.manifest.archiveSha256,
@@ -5764,18 +5829,18 @@ async function installRuntime(args) {
5764
5829
  }, null, 2));
5765
5830
  const targetRoot = runtimeInstallRoot(args.cacheRoot, args.manifest);
5766
5831
  rmSync(targetRoot, { recursive: true, force: true });
5767
- mkdirSync2(dirname2(targetRoot), { recursive: true });
5832
+ mkdirSync3(dirname2(targetRoot), { recursive: true });
5768
5833
  renameSync(extractRoot, targetRoot);
5769
5834
  return {
5770
5835
  ok: true,
5771
5836
  runtime: {
5772
5837
  mode: "server_managed",
5773
5838
  root: targetRoot,
5774
- codeServerBin: join3(targetRoot, args.manifest.codeServerBinPath),
5839
+ codeServerBin: join4(targetRoot, args.manifest.codeServerBinPath),
5775
5840
  assets: {
5776
- collaborationExtensionTarball: join3(targetRoot, "kandan", "editor_extensions", "typefox.open-collaboration-tools.tar.gz"),
5777
- collaborationServerTarball: join3(targetRoot, "kandan", "editor_servers", "open-collaboration-server.tar.gz"),
5778
- documentStateExtensionDir: join3(targetRoot, "kandan", "editor_extensions", "kandan.document-state-telemetry")
5841
+ collaborationExtensionTarball: join4(targetRoot, "kandan", "editor_extensions", "typefox.open-collaboration-tools.tar.gz"),
5842
+ collaborationServerTarball: join4(targetRoot, "kandan", "editor_servers", "open-collaboration-server.tar.gz"),
5843
+ documentStateExtensionDir: join4(targetRoot, "kandan", "editor_extensions", "kandan.document-state-telemetry")
5779
5844
  }
5780
5845
  }
5781
5846
  };
@@ -5787,7 +5852,7 @@ async function installRuntime(args) {
5787
5852
  }
5788
5853
  async function materializeRuntimeAssets(args) {
5789
5854
  for (const asset of args.manifest.assets) {
5790
- const targetPath = join3(args.runtimeRoot, asset.path);
5855
+ const targetPath = join4(args.runtimeRoot, asset.path);
5791
5856
  try {
5792
5857
  const bytes = await runtimeAssetBytes({
5793
5858
  kandanUrl: args.kandanUrl,
@@ -5797,8 +5862,8 @@ async function materializeRuntimeAssets(args) {
5797
5862
  if (bytes === undefined) {
5798
5863
  continue;
5799
5864
  }
5800
- mkdirSync2(dirname2(targetPath), { recursive: true });
5801
- writeFileSync2(targetPath, bytes);
5865
+ mkdirSync3(dirname2(targetPath), { recursive: true });
5866
+ writeFileSync3(targetPath, bytes);
5802
5867
  } catch (_error) {
5803
5868
  return false;
5804
5869
  }
@@ -5857,17 +5922,17 @@ function fileSha256(path) {
5857
5922
  });
5858
5923
  }
5859
5924
  function runtimeInstallRoot(cacheRoot, manifest) {
5860
- return resolve3(cacheRoot, manifest.platform, manifest.archiveSha256);
5925
+ return resolve4(cacheRoot, manifest.platform, manifest.archiveSha256);
5861
5926
  }
5862
5927
  function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
5863
- const collaborationExtensionTarball = join3(runtimeRoot, "kandan", "editor_extensions", "typefox.open-collaboration-tools.tar.gz");
5864
- const collaborationServerTarball = join3(runtimeRoot, "kandan", "editor_servers", "open-collaboration-server.tar.gz");
5865
- const documentStateExtensionDir = join3(runtimeRoot, "kandan", "editor_extensions", "kandan.document-state-telemetry");
5928
+ const collaborationExtensionTarball = join4(runtimeRoot, "kandan", "editor_extensions", "typefox.open-collaboration-tools.tar.gz");
5929
+ const collaborationServerTarball = join4(runtimeRoot, "kandan", "editor_servers", "open-collaboration-server.tar.gz");
5930
+ const documentStateExtensionDir = join4(runtimeRoot, "kandan", "editor_extensions", "kandan.document-state-telemetry");
5866
5931
  const codeServerRoot = codeServerRuntimeRoot(manifest.codeServerBinPath);
5867
5932
  const requiredPaths = [
5868
5933
  manifest.codeServerBinPath,
5869
- join3(codeServerRoot, "lib", "vscode", "node_modules", "vsda", "rust", "web", "vsda.js"),
5870
- join3(codeServerRoot, "lib", "vscode", "node_modules", "vsda", "rust", "web", "vsda_bg.wasm"),
5934
+ join4(codeServerRoot, "lib", "vscode", "node_modules", "vsda", "rust", "web", "vsda.js"),
5935
+ join4(codeServerRoot, "lib", "vscode", "node_modules", "vsda", "rust", "web", "vsda_bg.wasm"),
5871
5936
  "kandan/editor_extensions/typefox.open-collaboration-tools.tar.gz",
5872
5937
  "kandan/editor_servers/open-collaboration-server.tar.gz",
5873
5938
  "kandan/editor_extensions/kandan.document-state-telemetry/package.json",
@@ -5879,15 +5944,15 @@ function verifiedRuntimeAssetPaths(runtimeRoot, manifest) {
5879
5944
  if (expectedSha256 === undefined && relativePath !== manifest.codeServerBinPath) {
5880
5945
  return;
5881
5946
  }
5882
- const absolutePath = join3(runtimeRoot, relativePath);
5883
- if (!existsSync2(absolutePath)) {
5947
+ const absolutePath = join4(runtimeRoot, relativePath);
5948
+ if (!existsSync3(absolutePath)) {
5884
5949
  return;
5885
5950
  }
5886
5951
  if (expectedSha256 !== undefined && fileSha256Sync(absolutePath) !== expectedSha256) {
5887
5952
  return;
5888
5953
  }
5889
5954
  }
5890
- if (!existsSync2(collaborationExtensionTarball) || !existsSync2(collaborationServerTarball)) {
5955
+ if (!existsSync3(collaborationExtensionTarball) || !existsSync3(collaborationServerTarball)) {
5891
5956
  return;
5892
5957
  }
5893
5958
  return {
@@ -5908,10 +5973,10 @@ function manifestAssetChecksums(assets) {
5908
5973
  return checksums;
5909
5974
  }
5910
5975
  function fileSha256Sync(path) {
5911
- return createHash2("sha256").update(readFileSync(path)).digest("hex");
5976
+ return createHash2("sha256").update(readFileSync2(path)).digest("hex");
5912
5977
  }
5913
5978
  function defaultEditorRuntimeCacheRoot() {
5914
- return join3(homedir2(), ".linzumi", "editor-runtimes");
5979
+ return join4(homedir3(), ".linzumi", "editor-runtimes");
5915
5980
  }
5916
5981
  function nonEmptyString(value) {
5917
5982
  return typeof value === "string" && value.trim() !== "" ? value.trim() : undefined;
@@ -5923,7 +5988,7 @@ function sha256String(value) {
5923
5988
 
5924
5989
  // src/dependencyStatus.ts
5925
5990
  function probeTool(command, cwd) {
5926
- return new Promise((resolve4) => {
5991
+ return new Promise((resolve5) => {
5927
5992
  const child = spawn5(command, ["--version"], {
5928
5993
  cwd,
5929
5994
  stdio: ["ignore", "pipe", "pipe"]
@@ -5937,7 +6002,7 @@ function probeTool(command, cwd) {
5937
6002
  }
5938
6003
  resolved = true;
5939
6004
  clearTimeout(timeout);
5940
- resolve4(status);
6005
+ resolve5(status);
5941
6006
  };
5942
6007
  const timeout = setTimeout(() => {
5943
6008
  child.kill("SIGKILL");
@@ -6084,8 +6149,8 @@ async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new
6084
6149
  pending.clear();
6085
6150
  };
6086
6151
  const resetReady = () => {
6087
- state.ready = new Promise((resolve4, reject) => {
6088
- state.resolveReady = resolve4;
6152
+ state.ready = new Promise((resolve5, reject) => {
6153
+ state.resolveReady = resolve5;
6089
6154
  state.rejectReady = reject;
6090
6155
  });
6091
6156
  };
@@ -6120,8 +6185,8 @@ async function connectPhoenixClient(baseUrl, token, socketFactory = (url) => new
6120
6185
  const ref = String(state.nextRef);
6121
6186
  state.nextRef += 1;
6122
6187
  const frame = [null, ref, topic, event, payload];
6123
- return new Promise((resolve4, reject) => {
6124
- pending.set(ref, { event, resolve: resolve4, reject });
6188
+ return new Promise((resolve5, reject) => {
6189
+ pending.set(ref, { event, resolve: resolve5, reject });
6125
6190
  websocket.send(JSON.stringify(frame));
6126
6191
  });
6127
6192
  };
@@ -6257,8 +6322,8 @@ function isKandanControl(value) {
6257
6322
  return isJsonObject(value) && typeof value.type === "string";
6258
6323
  }
6259
6324
  function waitForOpen2(websocket) {
6260
- return new Promise((resolve4, reject) => {
6261
- websocket.addEventListener("open", () => resolve4(), { once: true });
6325
+ return new Promise((resolve5, reject) => {
6326
+ websocket.addEventListener("open", () => resolve5(), { once: true });
6262
6327
  websocket.addEventListener("error", () => reject(new Error("websocket open failed")), {
6263
6328
  once: true
6264
6329
  });
@@ -6269,9 +6334,9 @@ function waitForOpen2(websocket) {
6269
6334
  import { openSync } from "node:fs";
6270
6335
  import { createWriteStream as createWriteStream2 } from "node:fs";
6271
6336
  import { dirname as dirname3 } from "node:path";
6272
- import { mkdirSync as mkdirSync3 } from "node:fs";
6337
+ import { mkdirSync as mkdirSync4 } from "node:fs";
6273
6338
  function createRunnerLogger(logFile, consoleReporter) {
6274
- mkdirSync3(dirname3(logFile), { recursive: true });
6339
+ mkdirSync4(dirname3(logFile), { recursive: true });
6275
6340
  const fd = openSync(logFile, "a");
6276
6341
  const stream = createWriteStream2("", { fd, flags: "a", autoClose: true });
6277
6342
  const logger = (event, payload) => {
@@ -6288,9 +6353,9 @@ function closeStream(stream) {
6288
6353
  if (stream.closed || stream.destroyed) {
6289
6354
  return Promise.resolve();
6290
6355
  }
6291
- return new Promise((resolve4, reject) => {
6356
+ return new Promise((resolve5, reject) => {
6292
6357
  stream.once("error", reject);
6293
- stream.end(resolve4);
6358
+ stream.end(resolve5);
6294
6359
  });
6295
6360
  }
6296
6361
 
@@ -6459,11 +6524,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
6459
6524
  dispatcher(control);
6460
6525
  });
6461
6526
  await kandan.join(topic, joinPayload(), { rejoinPayload: joinPayload });
6462
- const started = options.codexUrl === undefined ? await startCodexAppServer(options.codexBin, options.cwd, {
6463
- model: options.channelSession?.model,
6464
- reasoningEffort: options.channelSession?.reasoningEffort,
6465
- fast: options.fast
6466
- }) : undefined;
6527
+ const started = options.codexUrl === undefined ? await startOwnedCodexAppServer(options) : undefined;
6467
6528
  if (started !== undefined) {
6468
6529
  cleanup.actions.push(() => {
6469
6530
  started.process.kill("SIGINT");
@@ -6790,7 +6851,7 @@ function normalizedWorkDescription(value) {
6790
6851
  return normalized === undefined || normalized === "" ? undefined : normalized;
6791
6852
  }
6792
6853
  function makeRunnerLogger(options) {
6793
- return createRunnerLogger(options.logFile ?? join4(options.cwd, ".linzumi-runner.log"), options.launchTui ? undefined : reportRunnerConsoleEvent);
6854
+ return createRunnerLogger(options.logFile ?? join5(options.cwd, ".linzumi-runner.log"), options.launchTui ? undefined : reportRunnerConsoleEvent);
6794
6855
  }
6795
6856
  function installCleanupHandlers(close) {
6796
6857
  const closeAndExit = () => {
@@ -6867,6 +6928,9 @@ async function applyControl(codex, instanceId, options, allowedCwds, control) {
6867
6928
  error: cwd.reason
6868
6929
  };
6869
6930
  }
6931
+ if (options.codexUrl === undefined) {
6932
+ ensureCodexProjectTrusted(cwd.cwd);
6933
+ }
6870
6934
  const response = await codex.request("thread/start", {
6871
6935
  cwd: cwd.cwd,
6872
6936
  serviceName: "kandan-local-runner",
@@ -6951,6 +7015,14 @@ async function applyControl(codex, instanceId, options, allowedCwds, control) {
6951
7015
  return { instanceId, controlType: control.type, skipped: true };
6952
7016
  }
6953
7017
  }
7018
+ async function startOwnedCodexAppServer(options) {
7019
+ ensureCodexProjectTrusted(options.cwd);
7020
+ return await startCodexAppServer(options.codexBin, options.cwd, {
7021
+ model: options.channelSession?.model,
7022
+ reasoningEffort: options.channelSession?.reasoningEffort,
7023
+ fast: options.fast
7024
+ });
7025
+ }
6954
7026
  function isUpdateRunnerConfigControl(control) {
6955
7027
  return control.type === "update_runner_config";
6956
7028
  }
@@ -6965,18 +7037,18 @@ function allowedCwdSuggestions(cwd, allowedCwds) {
6965
7037
  }
6966
7038
 
6967
7039
  // src/authCache.ts
6968
- import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
6969
- import { homedir as homedir3 } from "node:os";
6970
- import { dirname as dirname4, join as join5 } from "node:path";
7040
+ import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
7041
+ import { homedir as homedir4 } from "node:os";
7042
+ import { dirname as dirname4, join as join6 } from "node:path";
6971
7043
  function defaultAuthFilePath() {
6972
- const base = process.env.KANDAN_HOME ?? join5(homedir3(), ".kandan");
6973
- return join5(base, "auth.json");
7044
+ const base = process.env.KANDAN_HOME ?? join6(homedir4(), ".kandan");
7045
+ return join6(base, "auth.json");
6974
7046
  }
6975
7047
  function readCachedLocalRunnerToken(kandanUrl, authFilePath = defaultAuthFilePath()) {
6976
- if (!existsSync3(authFilePath)) {
7048
+ if (!existsSync4(authFilePath)) {
6977
7049
  return;
6978
7050
  }
6979
- const authFile = parseAuthFile(readFileSync2(authFilePath, "utf8"));
7051
+ const authFile = parseAuthFile(readFileSync3(authFilePath, "utf8"));
6980
7052
  const kandanBaseUrl = kandanHttpBaseUrl(kandanUrl);
6981
7053
  const entry = authFile.local_codex_runner?.[kandanBaseUrl];
6982
7054
  if (entry === undefined || entry.access_token.trim() === "") {
@@ -6994,7 +7066,7 @@ function readCachedLocalRunnerToken(kandanUrl, authFilePath = defaultAuthFilePat
6994
7066
  }
6995
7067
  function writeCachedLocalRunnerToken(args) {
6996
7068
  const authFilePath = args.authFilePath ?? defaultAuthFilePath();
6997
- const existing = existsSync3(authFilePath) ? parseAuthFile(readFileSync2(authFilePath, "utf8")) : { version: 1 };
7069
+ const existing = existsSync4(authFilePath) ? parseAuthFile(readFileSync3(authFilePath, "utf8")) : { version: 1 };
6998
7070
  const kandanBaseUrl = kandanHttpBaseUrl(args.kandanUrl);
6999
7071
  const issuedAt = new Date;
7000
7072
  const expiresAt = args.expiresInSeconds === undefined ? undefined : new Date(issuedAt.getTime() + args.expiresInSeconds * 1000).toISOString();
@@ -7010,8 +7082,8 @@ function writeCachedLocalRunnerToken(args) {
7010
7082
  }
7011
7083
  }
7012
7084
  };
7013
- mkdirSync4(dirname4(authFilePath), { recursive: true });
7014
- writeFileSync3(authFilePath, `${JSON.stringify(next, null, 2)}
7085
+ mkdirSync5(dirname4(authFilePath), { recursive: true });
7086
+ writeFileSync4(authFilePath, `${JSON.stringify(next, null, 2)}
7015
7087
  `, "utf8");
7016
7088
  return {
7017
7089
  accessToken: args.accessToken,
@@ -7104,18 +7176,18 @@ async function acquireAndCacheToken(args) {
7104
7176
  }
7105
7177
 
7106
7178
  // src/localConfig.ts
7107
- import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync3, realpathSync as realpathSync3, writeFileSync as writeFileSync4 } from "node:fs";
7108
- import { homedir as homedir4 } from "node:os";
7109
- import { dirname as dirname5, resolve as resolve4 } from "node:path";
7179
+ import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync4, realpathSync as realpathSync4, writeFileSync as writeFileSync5 } from "node:fs";
7180
+ import { homedir as homedir5 } from "node:os";
7181
+ import { dirname as dirname5, resolve as resolve5 } from "node:path";
7110
7182
  function localConfigPath(env = process.env) {
7111
7183
  const override = env.LINZUMI_CONFIG_FILE;
7112
- return override !== undefined && override.trim() !== "" ? resolve4(expandUserPath(override)) : resolve4(homedir4(), ".linzumi", "config.json");
7184
+ return override !== undefined && override.trim() !== "" ? resolve5(expandUserPath(override)) : resolve5(homedir5(), ".linzumi", "config.json");
7113
7185
  }
7114
7186
  function readLocalConfig(path = localConfigPath()) {
7115
- if (!existsSync4(path)) {
7187
+ if (!existsSync5(path)) {
7116
7188
  return { version: 1, allowedCwds: [] };
7117
7189
  }
7118
- const parsed = JSON.parse(readFileSync3(path, "utf8"));
7190
+ const parsed = JSON.parse(readFileSync4(path, "utf8"));
7119
7191
  if (!isConfigPayload(parsed)) {
7120
7192
  throw new Error(`invalid Linzumi config: ${path}`);
7121
7193
  }
@@ -7127,21 +7199,21 @@ function readLocalConfig(path = localConfigPath()) {
7127
7199
  function readConfiguredAllowedCwds(path = localConfigPath()) {
7128
7200
  return readLocalConfig(path).allowedCwds.map((cwd) => {
7129
7201
  try {
7130
- return realpathSync3(resolve4(expandUserPath(cwd)));
7202
+ return realpathSync4(resolve5(expandUserPath(cwd)));
7131
7203
  } catch (_error) {
7132
7204
  throw new Error(`invalid Linzumi config allowed path: ${cwd} does not exist`);
7133
7205
  }
7134
7206
  });
7135
7207
  }
7136
7208
  function addAllowedCwd(pathValue, path = localConfigPath()) {
7137
- const normalizedPath = realpathSync3(resolve4(expandUserPath(pathValue)));
7209
+ const normalizedPath = realpathSync4(resolve5(expandUserPath(pathValue)));
7138
7210
  const config = readLocalConfig(path);
7139
7211
  const allowedCwds = uniqueStrings([...config.allowedCwds, normalizedPath]);
7140
7212
  writeLocalConfig({ version: 1, allowedCwds }, path);
7141
7213
  return allowedCwds;
7142
7214
  }
7143
7215
  function removeAllowedCwd(pathValue, path = localConfigPath()) {
7144
- const requestedPath = resolve4(expandUserPath(pathValue));
7216
+ const requestedPath = resolve5(expandUserPath(pathValue));
7145
7217
  const normalizedRequest = realpathOrResolved(requestedPath);
7146
7218
  const config = readLocalConfig(path);
7147
7219
  const allowedCwds = config.allowedCwds.filter((cwd) => {
@@ -7152,8 +7224,8 @@ function removeAllowedCwd(pathValue, path = localConfigPath()) {
7152
7224
  return allowedCwds;
7153
7225
  }
7154
7226
  function writeLocalConfig(config, path = localConfigPath()) {
7155
- mkdirSync5(dirname5(path), { recursive: true });
7156
- writeFileSync4(path, `${JSON.stringify(config, null, 2)}
7227
+ mkdirSync6(dirname5(path), { recursive: true });
7228
+ writeFileSync5(path, `${JSON.stringify(config, null, 2)}
7157
7229
  `, "utf8");
7158
7230
  }
7159
7231
  function isConfigPayload(value) {
@@ -7164,14 +7236,14 @@ function uniqueStrings(values) {
7164
7236
  }
7165
7237
  function realpathOrResolved(pathValue) {
7166
7238
  try {
7167
- return realpathSync3(resolve4(expandUserPath(pathValue)));
7239
+ return realpathSync4(resolve5(expandUserPath(pathValue)));
7168
7240
  } catch (_error) {
7169
- return resolve4(expandUserPath(pathValue));
7241
+ return resolve5(expandUserPath(pathValue));
7170
7242
  }
7171
7243
  }
7172
7244
 
7173
7245
  // src/kandanTls.ts
7174
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
7246
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
7175
7247
  import { Agent } from "undici";
7176
7248
  import { WebSocket as WsWebSocket } from "ws";
7177
7249
  function kandanTlsTrustFromEnv() {
@@ -7182,10 +7254,10 @@ function kandanTlsTrustFromCaFile(caFile) {
7182
7254
  return;
7183
7255
  }
7184
7256
  const trimmed = caFile.trim();
7185
- if (!existsSync5(trimmed)) {
7257
+ if (!existsSync6(trimmed)) {
7186
7258
  throw new Error(`KANDAN_TLS_CA_FILE does not exist: ${trimmed}`);
7187
7259
  }
7188
- const ca = readFileSync4(trimmed, "utf8");
7260
+ const ca = readFileSync5(trimmed, "utf8");
7189
7261
  return {
7190
7262
  caFile: trimmed,
7191
7263
  ca,
@@ -7214,9 +7286,9 @@ function trustedWebSocketFactory(trust, WebSocketImpl = WsWebSocket) {
7214
7286
  }
7215
7287
 
7216
7288
  // src/agentBootstrap.ts
7217
- import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
7218
- import { dirname as dirname6, join as join6 } from "node:path";
7219
- import { homedir as homedir5 } from "node:os";
7289
+ import { existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
7290
+ import { dirname as dirname6, join as join7 } from "node:path";
7291
+ import { homedir as homedir6 } from "node:os";
7220
7292
  var defaultApiUrl = "https://serve.linzumi.com";
7221
7293
  async function runAgentCliCommand(args, deps = {
7222
7294
  fetchImpl: fetch,
@@ -7699,7 +7771,7 @@ function agentTokenFile(flags) {
7699
7771
  return flags.get("agent-token-file") ?? defaultAgentTokenFilePath();
7700
7772
  }
7701
7773
  function defaultAgentTokenFilePath() {
7702
- return join6(homedir5(), ".linzumi", "agent-token.json");
7774
+ return join7(homedir6(), ".linzumi", "agent-token.json");
7703
7775
  }
7704
7776
  function normalizedApiUrl(apiUrl) {
7705
7777
  return apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`;
@@ -7708,11 +7780,11 @@ function authorizationHeaders(token) {
7708
7780
  return { authorization: `Bearer ${token}` };
7709
7781
  }
7710
7782
  function readOptionalTextFile(path) {
7711
- return existsSync6(path) ? readFileSync5(path, "utf8") : undefined;
7783
+ return existsSync7(path) ? readFileSync6(path, "utf8") : undefined;
7712
7784
  }
7713
7785
  function writeTextFile(path, content) {
7714
- mkdirSync6(dirname6(path), { recursive: true });
7715
- writeFileSync5(path, content);
7786
+ mkdirSync7(dirname6(path), { recursive: true });
7787
+ writeFileSync6(path, content);
7716
7788
  }
7717
7789
  function readStoredAgentTokenFile(path, readTextFile = readOptionalTextFile) {
7718
7790
  const content = readTextFile(path);
@@ -7773,8 +7845,8 @@ Launch target:
7773
7845
  }
7774
7846
 
7775
7847
  // src/helloLinzumiProject.ts
7776
- import { existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
7777
- import { dirname as dirname7, join as join7, resolve as resolve5 } from "node:path";
7848
+ import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync7, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
7849
+ import { dirname as dirname7, join as join8, resolve as resolve6 } from "node:path";
7778
7850
  import { fileURLToPath } from "node:url";
7779
7851
  var defaultHelloLinzumiProjectDir = "/tmp/hello_linzumi";
7780
7852
  var defaultHelloLinzumiProjectName = "hello_linzumi";
@@ -7783,7 +7855,7 @@ var defaultHelloLinzumiPort = 8787;
7783
7855
  var defaultHelloLinzumiHost = "0.0.0.0";
7784
7856
  var markerFile = ".linzumi-demo-project";
7785
7857
  var moduleDir = dirname7(fileURLToPath(import.meta.url));
7786
- var linzumiLogoSvg = readFileSync6(join7(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
7858
+ var linzumiLogoSvg = readFileSync7(join8(moduleDir, "assets", "linzumi-logo.svg"), "utf8");
7787
7859
  function createHelloLinzumiProject(input = {}) {
7788
7860
  const options = typeof input === "string" ? { rootPath: input } : input;
7789
7861
  const root = resolveHelloProjectRoot(options);
@@ -7791,9 +7863,9 @@ function createHelloLinzumiProject(input = {}) {
7791
7863
  const host = normalizeHost(options.host);
7792
7864
  assertTcpPort(port);
7793
7865
  assertWritableDemoRoot(root, options.reset === true);
7794
- mkdirSync7(join7(root, "src"), { recursive: true });
7866
+ mkdirSync8(join8(root, "src"), { recursive: true });
7795
7867
  for (const file of demoFiles({ root, port, host })) {
7796
- writeFileSync6(join7(root, file.path), file.content, "utf8");
7868
+ writeFileSync7(join8(root, file.path), file.content, "utf8");
7797
7869
  }
7798
7870
  return {
7799
7871
  root,
@@ -7808,10 +7880,10 @@ function resolveHelloProjectRoot(options) {
7808
7880
  throw new Error("linzumi init-hello-linzumi-demo-app accepts either --dir or --parent-dir/--name, not both");
7809
7881
  }
7810
7882
  if (options.rootPath !== undefined) {
7811
- return resolve5(options.rootPath);
7883
+ return resolve6(options.rootPath);
7812
7884
  }
7813
7885
  const name = normalizeProjectName(options.name ?? defaultHelloLinzumiProjectName);
7814
- return resolve5(options.parentDir ?? defaultHelloLinzumiParentDir, name);
7886
+ return resolve6(options.parentDir ?? defaultHelloLinzumiParentDir, name);
7815
7887
  }
7816
7888
  function normalizeProjectName(value) {
7817
7889
  const name = value.trim();
@@ -7834,11 +7906,11 @@ function assertTcpPort(port) {
7834
7906
  throw new Error("--port must be a TCP port from 1 to 65535");
7835
7907
  }
7836
7908
  function assertWritableDemoRoot(root, reset) {
7837
- if (!existsSync7(root)) {
7909
+ if (!existsSync8(root)) {
7838
7910
  return;
7839
7911
  }
7840
- const markerPath = join7(root, markerFile);
7841
- const isDemoRoot = existsSync7(markerPath) && readFileSync6(markerPath, "utf8").trim() === "hello-linzumi";
7912
+ const markerPath = join8(root, markerFile);
7913
+ const isDemoRoot = existsSync8(markerPath) && readFileSync7(markerPath, "utf8").trim() === "hello-linzumi";
7842
7914
  if (isDemoRoot && reset) {
7843
7915
  rmSync2(root, { recursive: true, force: true });
7844
7916
  return;
@@ -8388,7 +8460,7 @@ function isMainModule() {
8388
8460
  if (scriptPath === undefined) {
8389
8461
  return false;
8390
8462
  }
8391
- return fileURLToPath2(import.meta.url) === resolve6(scriptPath);
8463
+ return fileURLToPath2(import.meta.url) === resolve7(scriptPath);
8392
8464
  }
8393
8465
  async function main(args) {
8394
8466
  const parsed = parseCommand(args);
@@ -8397,7 +8469,7 @@ async function main(args) {
8397
8469
  process.stdout.write(connectGuideText());
8398
8470
  return;
8399
8471
  case "version":
8400
- process.stdout.write(`linzumi 0.0.24-beta
8472
+ process.stdout.write(`linzumi 0.0.26-beta
8401
8473
  `);
8402
8474
  return;
8403
8475
  case "auth":
@@ -8532,7 +8604,7 @@ function runPathsCommand(args) {
8532
8604
  if (pathValue === undefined || pathValue.trim() === "") {
8533
8605
  throw new Error("missing path for linzumi paths add");
8534
8606
  }
8535
- const trustedPath = realpathSync4(resolve6(expandUserPath(pathValue)));
8607
+ const trustedPath = realpathSync5(resolve7(expandUserPath(pathValue)));
8536
8608
  addAllowedCwd(pathValue);
8537
8609
  process.stdout.write(`Trusted ${trustedPath}
8538
8610
  `);
@@ -8748,7 +8820,7 @@ async function parseAgentRunnerArgs(args, deps = {
8748
8820
  };
8749
8821
  }
8750
8822
  function readAgentTokenTextFile(path) {
8751
- return existsSync8(path) ? readFileSync7(path, "utf8") : undefined;
8823
+ return existsSync9(path) ? readFileSync8(path, "utf8") : undefined;
8752
8824
  }
8753
8825
  function rejectAgentRunnerTargetingFlags(values) {
8754
8826
  const unsupportedFlags = ["workspace", "channel", "token", "auth-file", "oauth-callback-host"].filter((flag) => values.has(flag));
@@ -8818,7 +8890,7 @@ async function parseRunnerArgs(args, deps = {
8818
8890
  process.exit(0);
8819
8891
  }
8820
8892
  if (values.get("version") === true) {
8821
- process.stdout.write(`linzumi 0.0.24-beta
8893
+ process.stdout.write(`linzumi 0.0.26-beta
8822
8894
  `);
8823
8895
  process.exit(0);
8824
8896
  }
@@ -8937,12 +9009,12 @@ function rejectStartTargetingFlags(values) {
8937
9009
  }
8938
9010
  function resolveUserPath(pathValue) {
8939
9011
  if (pathValue === "~") {
8940
- return homedir6();
9012
+ return homedir7();
8941
9013
  }
8942
9014
  if (pathValue.startsWith("~/")) {
8943
- return resolve6(homedir6(), pathValue.slice(2));
9015
+ return resolve7(homedir7(), pathValue.slice(2));
8944
9016
  }
8945
- return resolve6(pathValue);
9017
+ return resolve7(pathValue);
8946
9018
  }
8947
9019
  function parseChannelSession(values, token, target) {
8948
9020
  if (target === undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "0.0.24-beta",
3
+ "version": "0.0.26-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": {