codeam-cli 2.35.1 → 2.35.3

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/CHANGELOG.md +18 -0
  2. package/dist/index.js +316 -162
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,24 @@ All notable changes to `codeam-cli` are documented here.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.35.2] — 2026-06-10
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Bound preview install + add port-listening ready fallback
12
+ - **cli:** Stop resume_session from killing the agent dead
13
+
14
+ ### Tests
15
+
16
+ - **cli:** Make linkBdOntoPath/cliBinDir provisioner tests OS-independent
17
+
18
+ ## [2.35.1] — 2026-06-10
19
+
20
+ ### Fixed
21
+
22
+ - **cli:** Sync package-lock with @beads/bd@1.0.5 (npm ci was failing on main CI)
23
+ - **cli:** Symlink bd into a dir that is actually on PATH
24
+
7
25
  ## [2.35.0] — 2026-06-10
8
26
 
9
27
  ### Fixed
package/dist/index.js CHANGED
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
498
498
  // package.json
499
499
  var package_default = {
500
500
  name: "codeam-cli",
501
- version: "2.35.1",
501
+ version: "2.35.3",
502
502
  description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
503
503
  type: "commonjs",
504
504
  main: "dist/index.js",
@@ -5898,7 +5898,7 @@ function readAnonId() {
5898
5898
  }
5899
5899
  function superProperties() {
5900
5900
  return {
5901
- cliVersion: true ? "2.35.1" : "0.0.0-dev",
5901
+ cliVersion: true ? "2.35.3" : "0.0.0-dev",
5902
5902
  nodeVersion: process.version,
5903
5903
  platform: process.platform,
5904
5904
  arch: process.arch,
@@ -6630,11 +6630,17 @@ var AgentService = class _AgentService {
6630
6630
  restart(sessionId, auto = false) {
6631
6631
  if (!this.strategy || !this.initialLaunch) return;
6632
6632
  const resumeArgs = this.runtime.resumeLaunchArgs(sessionId, { auto });
6633
+ const launch = this.runtime.prepareResumeLaunch?.(sessionId, { auto }) ?? {
6634
+ cmd: this.initialLaunch.cmd,
6635
+ args: [...this.initialLaunch.args, ...resumeArgs]
6636
+ };
6637
+ this.agentBusy = false;
6638
+ if (this.quietTimer) {
6639
+ clearTimeout(this.quietTimer);
6640
+ this.quietTimer = null;
6641
+ }
6633
6642
  this.strategy.kill();
6634
- this.strategy.spawn(this.initialLaunch.cmd, this.opts.cwd, [
6635
- ...this.initialLaunch.args,
6636
- ...resumeArgs
6637
- ]);
6643
+ this.strategy.spawn(launch.cmd, this.opts.cwd, launch.args);
6638
6644
  if (resumeArgs.length === 0 && this.runtime.postSpawnInstruction) {
6639
6645
  const { ptyInput } = this.runtime.postSpawnInstruction(sessionId);
6640
6646
  setTimeout(() => {
@@ -7240,10 +7246,10 @@ function buildForPlatform(platform2) {
7240
7246
  var import_node_crypto4 = require("crypto");
7241
7247
 
7242
7248
  // src/agents/claude/resolver.ts
7243
- function buildClaudeLaunch(extraArgs = [], os30 = createOsStrategy()) {
7244
- const found = os30.findInPath("claude") ?? os30.findInPath("claude-code");
7249
+ function buildClaudeLaunch(extraArgs = [], os31 = createOsStrategy()) {
7250
+ const found = os31.findInPath("claude") ?? os31.findInPath("claude-code");
7245
7251
  if (!found) return null;
7246
- return os30.buildLaunch(found, extraArgs);
7252
+ return os31.buildLaunch(found, extraArgs);
7247
7253
  }
7248
7254
 
7249
7255
  // src/agents/claude/installer.ts
@@ -9986,8 +9992,8 @@ var ClaudeRuntimeStrategy = class {
9986
9992
  meta = getAgent("claude");
9987
9993
  mode = "interactive";
9988
9994
  os;
9989
- constructor(os30) {
9990
- this.os = os30;
9995
+ constructor(os31) {
9996
+ this.os = os31;
9991
9997
  }
9992
9998
  /**
9993
9999
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -10037,6 +10043,28 @@ var ClaudeRuntimeStrategy = class {
10037
10043
  if (opts?.auto) args2.push("--dangerously-skip-permissions");
10038
10044
  return args2;
10039
10045
  }
10046
+ /**
10047
+ * Resume relaunch as a COMPLETE command. We deliberately rebuild the
10048
+ * launch from scratch with `--resume <id>` rather than appending it
10049
+ * onto the spawn-time args, because those carried `--session-id
10050
+ * <uuid>` (the conversation binding from the initial spawn). Claude
10051
+ * Code rejects `--session-id` together with `--resume` and exits
10052
+ * immediately — that was the "resume → agent fully dead, even new
10053
+ * prompts get no response" bug. Building a fresh launch drops the
10054
+ * conflicting flag by construction.
10055
+ *
10056
+ * Synchronous on purpose: by the time a resume happens the binary
10057
+ * was already resolved (the initial spawn succeeded), so
10058
+ * `buildClaudeLaunch` re-probes PATH without needing the async
10059
+ * installer fallback.
10060
+ */
10061
+ prepareResumeLaunch(sessionId, opts) {
10062
+ const launch = buildClaudeLaunch(this.resumeLaunchArgs(sessionId, opts), this.os);
10063
+ if (!launch) {
10064
+ return { cmd: this.meta.binaryName, args: this.resumeLaunchArgs(sessionId, opts) };
10065
+ }
10066
+ return launch;
10067
+ }
10040
10068
  resolveHistoryDir(cwd) {
10041
10069
  return resolveHistoryDir(cwd);
10042
10070
  }
@@ -10995,8 +11023,8 @@ function codexCredentialLocator() {
10995
11023
  function codexLoginLauncher() {
10996
11024
  return {
10997
11025
  async ensureInstalled() {
10998
- const os30 = createOsStrategy();
10999
- return os30.findInPath("codex") !== null;
11026
+ const os31 = createOsStrategy();
11027
+ return os31.findInPath("codex") !== null;
11000
11028
  },
11001
11029
  launch() {
11002
11030
  return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -11019,8 +11047,8 @@ var CodexRuntimeStrategy = class {
11019
11047
  meta = getAgent("codex");
11020
11048
  mode = "interactive";
11021
11049
  os;
11022
- constructor(os30) {
11023
- this.os = os30;
11050
+ constructor(os31) {
11051
+ this.os = os31;
11024
11052
  }
11025
11053
  async prepareLaunch() {
11026
11054
  let binary = this.os.findInPath("codex");
@@ -11126,12 +11154,12 @@ var CodexRuntimeStrategy = class {
11126
11154
  });
11127
11155
  }
11128
11156
  };
11129
- function resolveNpm(os30) {
11130
- return os30.id === "win32" ? "npm.cmd" : "npm";
11157
+ function resolveNpm(os31) {
11158
+ return os31.id === "win32" ? "npm.cmd" : "npm";
11131
11159
  }
11132
- async function installCodexViaNpm(os30) {
11160
+ async function installCodexViaNpm(os31) {
11133
11161
  return new Promise((resolve7, reject) => {
11134
- const proc = (0, import_node_child_process4.spawn)(resolveNpm(os30), ["install", "-g", "@openai/codex"], {
11162
+ const proc = (0, import_node_child_process4.spawn)(resolveNpm(os31), ["install", "-g", "@openai/codex"], {
11135
11163
  stdio: "inherit"
11136
11164
  });
11137
11165
  proc.on("close", (code) => {
@@ -11148,16 +11176,16 @@ async function installCodexViaNpm(os30) {
11148
11176
  });
11149
11177
  });
11150
11178
  }
11151
- function augmentNpmGlobalBin(os30) {
11179
+ function augmentNpmGlobalBin(os31) {
11152
11180
  try {
11153
- const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os30), ["prefix", "-g"], {
11181
+ const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os31), ["prefix", "-g"], {
11154
11182
  stdio: ["ignore", "pipe", "ignore"]
11155
11183
  });
11156
11184
  if (result.status !== 0) return;
11157
11185
  const prefix = result.stdout.toString().trim();
11158
11186
  if (!prefix) return;
11159
- const binDir = os30.id === "win32" ? prefix : path17.join(prefix, "bin");
11160
- os30.augmentPath([binDir]);
11187
+ const binDir = os31.id === "win32" ? prefix : path17.join(prefix, "bin");
11188
+ os31.augmentPath([binDir]);
11161
11189
  } catch {
11162
11190
  }
11163
11191
  }
@@ -11241,9 +11269,9 @@ var import_node_child_process7 = require("child_process");
11241
11269
  // src/agents/coderabbit/installer.ts
11242
11270
  var import_node_child_process5 = require("child_process");
11243
11271
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
11244
- async function ensureCoderabbitInstalled(os30) {
11245
- if (os30.findInPath("coderabbit")) return true;
11246
- if (os30.id === "win32") {
11272
+ async function ensureCoderabbitInstalled(os31) {
11273
+ if (os31.findInPath("coderabbit")) return true;
11274
+ if (os31.id === "win32") {
11247
11275
  console.error(
11248
11276
  "\n \u2717 CodeRabbit on Windows requires WSL.\n Install the CLI inside your WSL distribution\n (curl -fsSL https://cli.coderabbit.ai/install.sh | sh)\n then re-run `codeam link coderabbit` from WSL.\n"
11249
11277
  );
@@ -11258,8 +11286,8 @@ async function ensureCoderabbitInstalled(os30) {
11258
11286
  proc.on("error", () => resolve7(false));
11259
11287
  });
11260
11288
  if (!ok) return false;
11261
- os30.augmentPath([`${os30.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11262
- return os30.findInPath("coderabbit") !== null;
11289
+ os31.augmentPath([`${os31.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11290
+ return os31.findInPath("coderabbit") !== null;
11263
11291
  }
11264
11292
 
11265
11293
  // src/agents/coderabbit/link.ts
@@ -11286,10 +11314,10 @@ function coderabbitCredentialLocator() {
11286
11314
  extract: extractLocalCoderabbitToken
11287
11315
  };
11288
11316
  }
11289
- function coderabbitLoginLauncher(os30) {
11317
+ function coderabbitLoginLauncher(os31) {
11290
11318
  return {
11291
11319
  async ensureInstalled() {
11292
- return ensureCoderabbitInstalled(os30);
11320
+ return ensureCoderabbitInstalled(os31);
11293
11321
  },
11294
11322
  launch() {
11295
11323
  return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
@@ -11335,8 +11363,8 @@ var CoderabbitRuntimeStrategy = class {
11335
11363
  meta = getAgent("coderabbit");
11336
11364
  mode = "batch";
11337
11365
  os;
11338
- constructor(os30) {
11339
- this.os = os30;
11366
+ constructor(os31) {
11367
+ this.os = os31;
11340
11368
  }
11341
11369
  getDefaultArgs() {
11342
11370
  return ["review"];
@@ -11451,10 +11479,10 @@ function cursorCredentialLocator() {
11451
11479
  extract: extractLocalCursorToken
11452
11480
  };
11453
11481
  }
11454
- function cursorLoginLauncher(os30) {
11482
+ function cursorLoginLauncher(os31) {
11455
11483
  return {
11456
11484
  async ensureInstalled() {
11457
- if (os30.findInPath("cursor-agent")) return true;
11485
+ if (os31.findInPath("cursor-agent")) return true;
11458
11486
  console.error(
11459
11487
  "\n \u2717 cursor-agent binary not on PATH.\n Install Cursor (https://cursor.com/) and ensure the CLI\n plugin is enabled, then re-run `codeam link cursor`.\n"
11460
11488
  );
@@ -11516,8 +11544,8 @@ var CursorRuntimeStrategy = class {
11516
11544
  meta = getAgent("cursor");
11517
11545
  mode = "interactive";
11518
11546
  os;
11519
- constructor(os30) {
11520
- this.os = os30;
11547
+ constructor(os31) {
11548
+ this.os = os31;
11521
11549
  }
11522
11550
  async prepareLaunch() {
11523
11551
  const binary = this.os.findInPath("cursor-agent");
@@ -11637,10 +11665,10 @@ function aiderCredentialLocator() {
11637
11665
  extract: extractLocalAiderToken
11638
11666
  };
11639
11667
  }
11640
- function aiderLoginLauncher(os30) {
11668
+ function aiderLoginLauncher(os31) {
11641
11669
  return {
11642
11670
  async ensureInstalled() {
11643
- if (os30.findInPath("aider")) return true;
11671
+ if (os31.findInPath("aider")) return true;
11644
11672
  console.error(
11645
11673
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
11646
11674
  );
@@ -11650,7 +11678,7 @@ function aiderLoginLauncher(os30) {
11650
11678
  console.error(
11651
11679
  "\n Aider has no interactive login flow.\n Set ANTHROPIC_API_KEY or OPENAI_API_KEY in your shell,\n or re-run `codeam link aider --api-key=<your-key>`.\n"
11652
11680
  );
11653
- return (0, import_node_child_process9.spawn)(os30.id === "win32" ? "cmd.exe" : "sh", os30.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11681
+ return (0, import_node_child_process9.spawn)(os31.id === "win32" ? "cmd.exe" : "sh", os31.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11654
11682
  stdio: "ignore"
11655
11683
  });
11656
11684
  }
@@ -11722,8 +11750,8 @@ var AiderRuntimeStrategy = class {
11722
11750
  meta = getAgent("aider");
11723
11751
  mode = "interactive";
11724
11752
  os;
11725
- constructor(os30) {
11726
- this.os = os30;
11753
+ constructor(os31) {
11754
+ this.os = os31;
11727
11755
  }
11728
11756
  async prepareLaunch() {
11729
11757
  const binary = this.os.findInPath("aider");
@@ -11852,8 +11880,8 @@ function geminiCredentialLocator() {
11852
11880
  function geminiLoginLauncher() {
11853
11881
  return {
11854
11882
  async ensureInstalled() {
11855
- const os30 = createOsStrategy();
11856
- return os30.findInPath("gemini") !== null;
11883
+ const os31 = createOsStrategy();
11884
+ return os31.findInPath("gemini") !== null;
11857
11885
  },
11858
11886
  launch() {
11859
11887
  return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -11886,8 +11914,8 @@ var GeminiRuntimeStrategy = class {
11886
11914
  meta = getAgent("gemini");
11887
11915
  mode = "interactive";
11888
11916
  os;
11889
- constructor(os30) {
11890
- this.os = os30;
11917
+ constructor(os31) {
11918
+ this.os = os31;
11891
11919
  }
11892
11920
  async prepareLaunch() {
11893
11921
  const binary = this.os.findInPath("gemini");
@@ -11987,18 +12015,18 @@ var GeminiRuntimeStrategy = class {
11987
12015
 
11988
12016
  // src/agents/registry.ts
11989
12017
  var runtimeBuilders = {
11990
- claude: (os30) => new ClaudeRuntimeStrategy(os30),
11991
- codex: (os30) => new CodexRuntimeStrategy(os30),
11992
- coderabbit: (os30) => new CoderabbitRuntimeStrategy(os30),
11993
- cursor: (os30) => new CursorRuntimeStrategy(os30),
11994
- aider: (os30) => new AiderRuntimeStrategy(os30),
11995
- gemini: (os30) => new GeminiRuntimeStrategy(os30)
12018
+ claude: (os31) => new ClaudeRuntimeStrategy(os31),
12019
+ codex: (os31) => new CodexRuntimeStrategy(os31),
12020
+ coderabbit: (os31) => new CoderabbitRuntimeStrategy(os31),
12021
+ cursor: (os31) => new CursorRuntimeStrategy(os31),
12022
+ aider: (os31) => new AiderRuntimeStrategy(os31),
12023
+ gemini: (os31) => new GeminiRuntimeStrategy(os31)
11996
12024
  };
11997
12025
  var deployBuilders = {
11998
12026
  claude: () => new ClaudeDeployStrategy(),
11999
12027
  codex: () => new CodexDeployStrategy()
12000
12028
  };
12001
- function createAgentStrategy(agent, os30 = createOsStrategy()) {
12029
+ function createAgentStrategy(agent, os31 = createOsStrategy()) {
12002
12030
  if (!AGENT_REGISTRY[agent]?.enabled) {
12003
12031
  throw new Error(
12004
12032
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -12008,10 +12036,10 @@ function createAgentStrategy(agent, os30 = createOsStrategy()) {
12008
12036
  if (!build) {
12009
12037
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
12010
12038
  }
12011
- return build(os30);
12039
+ return build(os31);
12012
12040
  }
12013
- function createInteractiveAgentStrategy(agent, os30 = createOsStrategy()) {
12014
- const s = createAgentStrategy(agent, os30);
12041
+ function createInteractiveAgentStrategy(agent, os31 = createOsStrategy()) {
12042
+ const s = createAgentStrategy(agent, os31);
12015
12043
  if (s.mode !== "interactive") {
12016
12044
  throw new Error(
12017
12045
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -15711,10 +15739,10 @@ function extractSelectPrompt(text) {
15711
15739
 
15712
15740
  // src/commands/start/handlers.ts
15713
15741
  var fs32 = __toESM(require("fs"));
15714
- var os25 = __toESM(require("os"));
15742
+ var os26 = __toESM(require("os"));
15715
15743
  var path39 = __toESM(require("path"));
15716
15744
  var import_crypto3 = require("crypto");
15717
- var import_child_process16 = require("child_process");
15745
+ var import_child_process17 = require("child_process");
15718
15746
 
15719
15747
  // src/lib/payload.ts
15720
15748
  var import_zod = require("zod");
@@ -17136,6 +17164,77 @@ function parseExpoUrl(stdout) {
17136
17164
  return match ? match[0] : null;
17137
17165
  }
17138
17166
 
17167
+ // src/services/preview/port-ready.ts
17168
+ var net = __toESM(require("net"));
17169
+ function isPortListening(port, host = "127.0.0.1") {
17170
+ return new Promise((resolve7) => {
17171
+ const socket = new net.Socket();
17172
+ const done = (result) => {
17173
+ socket.removeAllListeners();
17174
+ socket.destroy();
17175
+ resolve7(result);
17176
+ };
17177
+ socket.setTimeout(1e3);
17178
+ socket.once("connect", () => done(true));
17179
+ socket.once("timeout", () => done(false));
17180
+ socket.once("error", () => done(false));
17181
+ socket.connect(port, host);
17182
+ });
17183
+ }
17184
+ async function waitForPortListening(port, opts) {
17185
+ const interval = opts.intervalMs ?? 500;
17186
+ const deadline = Date.now() + opts.timeoutMs;
17187
+ for (; ; ) {
17188
+ if (await isPortListening(port)) return true;
17189
+ if (Date.now() >= deadline) return false;
17190
+ await new Promise((r) => setTimeout(r, interval));
17191
+ }
17192
+ }
17193
+
17194
+ // src/services/preview/run-setup.ts
17195
+ var import_child_process12 = require("child_process");
17196
+ function runSetupCommand(cmd, args2, cwd, env, opts) {
17197
+ return new Promise((resolve7) => {
17198
+ const child = (0, import_child_process12.spawn)(cmd, args2, {
17199
+ cwd,
17200
+ env: { ...process.env, ...env ?? {} },
17201
+ stdio: ["ignore", "pipe", "pipe"]
17202
+ });
17203
+ let settled = false;
17204
+ const tag = `setup:${cmd}`;
17205
+ const onChunk = (chunk) => {
17206
+ const text = chunk.toString().replace(/\n+$/g, "");
17207
+ if (text.length === 0) return;
17208
+ log.info("preview", `${tag}: ${text}`);
17209
+ };
17210
+ child.stdout?.on("data", onChunk);
17211
+ child.stderr?.on("data", onChunk);
17212
+ const timer = setTimeout(() => {
17213
+ if (settled) return;
17214
+ settled = true;
17215
+ log.info("preview", `${tag}: timed out after ${opts.timeoutMs}ms \u2014 killing`);
17216
+ try {
17217
+ child.kill("SIGTERM");
17218
+ } catch {
17219
+ }
17220
+ resolve7({ status: "timeout", code: null });
17221
+ }, opts.timeoutMs);
17222
+ child.once("exit", (code) => {
17223
+ if (settled) return;
17224
+ settled = true;
17225
+ clearTimeout(timer);
17226
+ if (code === 0) resolve7({ status: "ok", code: 0 });
17227
+ else resolve7({ status: "failed", code });
17228
+ });
17229
+ child.once("error", () => {
17230
+ if (settled) return;
17231
+ settled = true;
17232
+ clearTimeout(timer);
17233
+ resolve7({ status: "failed", code: null });
17234
+ });
17235
+ });
17236
+ }
17237
+
17139
17238
  // src/services/preview/setup-deps.ts
17140
17239
  var import_fs2 = __toESM(require("fs"));
17141
17240
  var import_path6 = __toESM(require("path"));
@@ -17202,7 +17301,7 @@ function activePreviewSessionIds() {
17202
17301
  }
17203
17302
 
17204
17303
  // src/beads/bd-adapter.ts
17205
- var import_child_process12 = require("child_process");
17304
+ var import_child_process13 = require("child_process");
17206
17305
  var fs29 = __toESM(require("fs"));
17207
17306
  var os24 = __toESM(require("os"));
17208
17307
  var path35 = __toESM(require("path"));
@@ -17256,7 +17355,7 @@ function _defaultSpawn(binaryPath, args2, opts) {
17256
17355
  return new Promise((resolve7) => {
17257
17356
  let proc;
17258
17357
  try {
17259
- proc = (0, import_child_process12.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
17358
+ proc = (0, import_child_process13.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
17260
17359
  } catch (err) {
17261
17360
  resolve7({ code: -1, stdout: "", stderr: err.message });
17262
17361
  return;
@@ -17392,12 +17491,13 @@ function defaultBeadsHomeDir() {
17392
17491
  }
17393
17492
 
17394
17493
  // src/beads/provisioner.ts
17395
- var import_child_process14 = require("child_process");
17494
+ var import_child_process15 = require("child_process");
17396
17495
  var fs30 = __toESM(require("fs"));
17496
+ var os25 = __toESM(require("os"));
17397
17497
  var path36 = __toESM(require("path"));
17398
17498
 
17399
17499
  // src/beads/install-bd.ts
17400
- var import_child_process13 = require("child_process");
17500
+ var import_child_process14 = require("child_process");
17401
17501
  var INSTALL_SH_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh";
17402
17502
  var INSTALL_PS1_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/install.ps1";
17403
17503
  function resolveInstallStrategy(platform2) {
@@ -17428,7 +17528,7 @@ function _defaultInstallSpawn(strategy) {
17428
17528
  return new Promise((resolve7) => {
17429
17529
  let proc;
17430
17530
  try {
17431
- proc = (0, import_child_process13.spawn)(strategy.command, strategy.args, { env: process.env });
17531
+ proc = (0, import_child_process14.spawn)(strategy.command, strategy.args, { env: process.env });
17432
17532
  } catch (err) {
17433
17533
  resolve7({ ok: false, code: -1, stderr: err.message });
17434
17534
  return;
@@ -17477,26 +17577,47 @@ var _provisionSeam = {
17477
17577
  };
17478
17578
  var _linkSeam = {
17479
17579
  platform: () => process.platform,
17580
+ homedir: () => os25.homedir(),
17581
+ isWritableDir: (dir) => {
17582
+ try {
17583
+ fs30.accessSync(dir, fs30.constants.W_OK);
17584
+ return true;
17585
+ } catch {
17586
+ return false;
17587
+ }
17588
+ },
17589
+ ensureDir: (dir) => {
17590
+ fs30.mkdirSync(dir, { recursive: true });
17591
+ },
17480
17592
  /**
17481
- * A directory ON PATH to symlink `bd` into, so the AGENT's shell + the
17482
- * SessionStart `bd prime` hook resolve `bd` by name.
17593
+ * A directory to symlink `bd` into so the AGENT's shell + Claude Code's
17594
+ * SessionStart `bd prime` hook resolve `bd` by name. The dir MUST be on the
17595
+ * persistent shell PATH those processes use AND be writable.
17483
17596
  *
17484
- * Earlier this used `dirname(realpath(process.argv[1]))` but for a GLOBAL
17485
- * npm install that resolves to the package's own `dist/` dir (e.g.
17486
- * `…/node_modules/codeam-cli/dist`), which is NOT on PATH. The symlink landed
17487
- * somewhere nothing sees, so `which bd` and the hook still failed (observed
17488
- * live in a codespace). `dirname(process.execPath)` is the dir the `node`
17489
- * binary lives in for a global install that's the npm prefix `bin/` where
17490
- * the `codeam` launcher also lives, and IS on PATH. We prefer the first
17491
- * candidate that actually appears in `$PATH`, falling back to node's bin dir.
17597
+ * History: v2.35.1 used `dirname(realpath(argv[1]))` (the package `dist/`,
17598
+ * not on PATH); v2.35.2 used `dirname(process.execPath)` correct for a
17599
+ * normal global npm install, but in a GitHub Codespace `node` lives in a
17600
+ * TRANSIENT bootstrap prefix (`/tmp/codeam-node20/bin`) that is NOT on the
17601
+ * persistent shell PATH, so the hook still failed (validated live). The
17602
+ * dir that IS on PATH and writable in a codespace is `~/.local/bin`.
17603
+ *
17604
+ * Strategy: among [node's bin, ~/.local/bin, /usr/local/bin, entry dir],
17605
+ * pick the first that is BOTH on `$PATH` AND writable. If none qualifies
17606
+ * (codespace: node prefix off-PATH, /usr/local/bin read-only), fall back to
17607
+ * `~/.local/bin` — the standard user bin, on PATH for login shells —
17608
+ * which `linkBdOntoPath` creates if missing.
17492
17609
  */
17493
17610
  cliBinDir: () => {
17494
17611
  const pathDirs = (process.env.PATH ?? "").split(path36.delimiter).filter(Boolean);
17612
+ const home = _linkSeam.homedir();
17613
+ const localBin = home ? path36.join(home, ".local", "bin") : null;
17495
17614
  const candidates = [];
17496
17615
  try {
17497
17616
  candidates.push(path36.dirname(process.execPath));
17498
17617
  } catch {
17499
17618
  }
17619
+ if (localBin) candidates.push(localBin);
17620
+ candidates.push("/usr/local/bin");
17500
17621
  const entry = process.argv[1];
17501
17622
  if (entry) {
17502
17623
  try {
@@ -17505,8 +17626,11 @@ var _linkSeam = {
17505
17626
  candidates.push(path36.dirname(entry));
17506
17627
  }
17507
17628
  }
17508
- if (candidates.length === 0) return null;
17509
- return candidates.find((d3) => pathDirs.includes(d3)) ?? candidates[0];
17629
+ const onPathWritable = candidates.find(
17630
+ (d3) => pathDirs.includes(d3) && _linkSeam.isWritableDir(d3)
17631
+ );
17632
+ if (onPathWritable) return onPathWritable;
17633
+ return localBin ?? candidates[0] ?? null;
17510
17634
  },
17511
17635
  /** Current symlink target at `linkPath`, or null when absent / not a link. */
17512
17636
  readlink: (linkPath) => {
@@ -17523,6 +17647,7 @@ function linkBdOntoPath(binaryPath) {
17523
17647
  if (_linkSeam.platform() === "win32") return;
17524
17648
  const binDir = _linkSeam.cliBinDir();
17525
17649
  if (!binDir) return;
17650
+ _linkSeam.ensureDir(binDir);
17526
17651
  const linkPath = path36.join(binDir, "bd");
17527
17652
  if (linkPath === binaryPath) return;
17528
17653
  const current = _linkSeam.readlink(linkPath);
@@ -17532,7 +17657,7 @@ function linkBdOntoPath(binaryPath) {
17532
17657
  log.info("beads", `linked bd onto PATH: ${linkPath} -> ${binaryPath}`);
17533
17658
  }
17534
17659
  function setGitBeadsRole() {
17535
- (0, import_child_process14.execFileSync)("git", ["config", "--global", "beads.role", "contributor"], {
17660
+ (0, import_child_process15.execFileSync)("git", ["config", "--global", "beads.role", "contributor"], {
17536
17661
  stdio: "ignore"
17537
17662
  });
17538
17663
  }
@@ -17639,7 +17764,7 @@ var crypto3 = __toESM(require("crypto"));
17639
17764
  var path38 = __toESM(require("path"));
17640
17765
 
17641
17766
  // src/beads/project-key.ts
17642
- var import_child_process15 = require("child_process");
17767
+ var import_child_process16 = require("child_process");
17643
17768
  var crypto2 = __toESM(require("crypto"));
17644
17769
  var fs31 = __toESM(require("fs"));
17645
17770
  var path37 = __toESM(require("path"));
@@ -17686,7 +17811,7 @@ function findRepoRoot(cwd) {
17686
17811
  }
17687
17812
  var _execSeam2 = {
17688
17813
  exec: (file, args2, opts) => {
17689
- const out2 = (0, import_child_process15.execFileSync)(file, args2, opts);
17814
+ const out2 = (0, import_child_process16.execFileSync)(file, args2, opts);
17690
17815
  return typeof out2 === "string" ? out2 : out2.toString("utf8");
17691
17816
  },
17692
17817
  realpath: (p2) => fs31.realpathSync(p2)
@@ -18080,7 +18205,7 @@ function cleanupAttachmentTempFiles() {
18080
18205
  function saveFilesTemp(files) {
18081
18206
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
18082
18207
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
18083
- const tmpPath = path39.join(os25.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
18208
+ const tmpPath = path39.join(os26.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
18084
18209
  fs32.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
18085
18210
  pendingAttachmentFiles.add(tmpPath);
18086
18211
  return tmpPath;
@@ -18226,7 +18351,7 @@ var sessionTerminated = async (ctx, cmd) => {
18226
18351
  } catch {
18227
18352
  }
18228
18353
  try {
18229
- const proc = (0, import_child_process16.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18354
+ const proc = (0, import_child_process17.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18230
18355
  detached: true,
18231
18356
  stdio: "ignore"
18232
18357
  });
@@ -18248,7 +18373,7 @@ var shutdownSession = async (ctx, cmd) => {
18248
18373
  }
18249
18374
  if (ctx.keepAliveCtx.inCodespace && ctx.keepAliveCtx.codespaceName) {
18250
18375
  try {
18251
- const stopProc = (0, import_child_process16.spawn)(
18376
+ const stopProc = (0, import_child_process17.spawn)(
18252
18377
  "bash",
18253
18378
  ["-lc", `sleep 1; gh codespace stop -c ${JSON.stringify(ctx.keepAliveCtx.codespaceName)} >/dev/null 2>&1 || true`],
18254
18379
  { detached: true, stdio: "ignore" }
@@ -18258,7 +18383,7 @@ var shutdownSession = async (ctx, cmd) => {
18258
18383
  }
18259
18384
  }
18260
18385
  try {
18261
- const proc = (0, import_child_process16.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18386
+ const proc = (0, import_child_process17.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18262
18387
  detached: true,
18263
18388
  stdio: "ignore"
18264
18389
  });
@@ -18658,11 +18783,21 @@ async function waitForDevServerReady(devServer, readyRe, opts = {
18658
18783
  };
18659
18784
  devServer.stdout?.on("data", consume);
18660
18785
  devServer.stderr?.on("data", consume);
18786
+ let probeInFlight = false;
18661
18787
  const deadline = Date.now() + opts.timeoutMs;
18662
18788
  while (!readyMatched && Date.now() < deadline) {
18663
18789
  if (devServer.exitCode !== null) {
18664
18790
  return { kind: "exited", code: devServer.exitCode };
18665
18791
  }
18792
+ if (opts.portProbe && !probeInFlight) {
18793
+ probeInFlight = true;
18794
+ void opts.portProbe().then((up) => {
18795
+ if (up) readyMatched = true;
18796
+ }).catch(() => {
18797
+ }).finally(() => {
18798
+ probeInFlight = false;
18799
+ });
18800
+ }
18666
18801
  await new Promise((r) => setTimeout(r, 250));
18667
18802
  }
18668
18803
  if (readyMatched) return { kind: "ready" };
@@ -18682,6 +18817,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
18682
18817
  args: args2.slice(1)
18683
18818
  };
18684
18819
  }
18820
+ var INSTALL_TIMEOUT_MS = 5 * 6e4;
18821
+ var SETUP_TIMEOUT_MS = 2 * 6e4;
18685
18822
  var previewStartH = (ctx, _cmd, parsed) => {
18686
18823
  if (!ctx.pluginAuthToken) {
18687
18824
  log.info("preview", "no pluginAuthToken \u2014 skipping start");
@@ -18719,13 +18856,27 @@ var previewStartH = (ctx, _cmd, parsed) => {
18719
18856
  "SETUP_RUN",
18720
18857
  `${missingDeps.cmd} ${missingDeps.args.join(" ")} (pre-flight \u2014 node_modules missing)`
18721
18858
  );
18722
- const exitCode = await runOnce(
18859
+ const result = await runSetupCommand(
18723
18860
  missingDeps.cmd,
18724
18861
  missingDeps.args,
18725
18862
  process.cwd(),
18726
- detection.env
18863
+ detection.env,
18864
+ { timeoutMs: INSTALL_TIMEOUT_MS }
18727
18865
  );
18728
- if (exitCode !== 0) {
18866
+ if (result.status === "timeout") {
18867
+ void postPreviewEvent({
18868
+ sessionId: ctx.sessionId,
18869
+ pluginId: ctx.pluginId,
18870
+ pluginAuthToken,
18871
+ type: "preview_error",
18872
+ payload: {
18873
+ stage: "ready_timeout",
18874
+ message: `Dependency install (${missingDeps.cmd} ${missingDeps.args.join(" ")}) didn't finish within ${Math.round(INSTALL_TIMEOUT_MS / 1e3)}s and was stopped. Run it manually in this project, then try the preview again.`
18875
+ }
18876
+ });
18877
+ return;
18878
+ }
18879
+ if (result.status === "failed") {
18729
18880
  void postPreviewEvent({
18730
18881
  sessionId: ctx.sessionId,
18731
18882
  pluginId: ctx.pluginId,
@@ -18733,7 +18884,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
18733
18884
  type: "preview_error",
18734
18885
  payload: {
18735
18886
  stage: "spawn",
18736
- message: `Dependency install failed (${missingDeps.cmd} ${missingDeps.args.join(" ")}, exit ${exitCode}). Run it manually in this project and try again.`
18887
+ message: `Dependency install failed (${missingDeps.cmd} ${missingDeps.args.join(" ")}, exit ${result.code}). Run it manually in this project and try again.`
18737
18888
  }
18738
18889
  });
18739
18890
  return;
@@ -18745,8 +18896,28 @@ var previewStartH = (ctx, _cmd, parsed) => {
18745
18896
  ) : detection.setup_commands ?? [];
18746
18897
  for (const setup of agentSetupCommands) {
18747
18898
  emitProgress("SETUP_RUN", `${setup.cmd} ${setup.args.join(" ")}`);
18748
- const exitCode = await runOnce(setup.cmd, setup.args, process.cwd(), detection.env);
18749
- if (exitCode !== 0) {
18899
+ const timeoutMs = isJsInstallCommand(setup.cmd, setup.args) ? INSTALL_TIMEOUT_MS : SETUP_TIMEOUT_MS;
18900
+ const result = await runSetupCommand(
18901
+ setup.cmd,
18902
+ setup.args,
18903
+ process.cwd(),
18904
+ detection.env,
18905
+ { timeoutMs }
18906
+ );
18907
+ if (result.status === "timeout") {
18908
+ void postPreviewEvent({
18909
+ sessionId: ctx.sessionId,
18910
+ pluginId: ctx.pluginId,
18911
+ pluginAuthToken,
18912
+ type: "preview_error",
18913
+ payload: {
18914
+ stage: "ready_timeout",
18915
+ message: `Setup step (${setup.cmd} ${setup.args.join(" ")}) didn't finish within ${Math.round(timeoutMs / 1e3)}s and was stopped.`
18916
+ }
18917
+ });
18918
+ return;
18919
+ }
18920
+ if (result.status === "failed") {
18750
18921
  void postPreviewEvent({
18751
18922
  sessionId: ctx.sessionId,
18752
18923
  pluginId: ctx.pluginId,
@@ -18754,7 +18925,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
18754
18925
  type: "preview_error",
18755
18926
  payload: {
18756
18927
  stage: "spawn",
18757
- message: `Setup failed (${setup.cmd} ${setup.args.join(" ")}, exit ${exitCode}).`
18928
+ message: `Setup failed (${setup.cmd} ${setup.args.join(" ")}, exit ${result.code}).`
18758
18929
  }
18759
18930
  });
18760
18931
  return;
@@ -18765,7 +18936,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
18765
18936
  "BOOT_SEQUENCE",
18766
18937
  `${spawnable.command} ${spawnable.args.join(" ")}`
18767
18938
  );
18768
- const devServer = (0, import_child_process16.spawn)(spawnable.command, spawnable.args, {
18939
+ const devServer = (0, import_child_process17.spawn)(spawnable.command, spawnable.args, {
18769
18940
  cwd: process.cwd(),
18770
18941
  env: { ...process.env, ...spawnable.env ?? {} },
18771
18942
  stdio: ["ignore", "pipe", "pipe"]
@@ -18774,13 +18945,15 @@ var previewStartH = (ctx, _cmd, parsed) => {
18774
18945
  emitProgress("WAITING_FOR_READY", detection.ready_pattern);
18775
18946
  let expoUrl = null;
18776
18947
  const readyRe = compileReadyPattern(detection.ready_pattern);
18948
+ const isNextJs = /next/i.test(detection.framework);
18777
18949
  const outcome = await waitForDevServerReady(devServer, readyRe, {
18778
18950
  timeoutMs: 12e4,
18779
18951
  onChunk: (s) => {
18780
18952
  if (!expoUrl && detection.framework === "Expo") {
18781
18953
  expoUrl = parseExpoUrl(s);
18782
18954
  }
18783
- }
18955
+ },
18956
+ portProbe: isNextJs ? () => waitForPortListening(detection.port, { timeoutMs: 1e3, intervalMs: 250 }) : void 0
18784
18957
  });
18785
18958
  if (outcome.kind === "exited") {
18786
18959
  void postPreviewEvent({
@@ -18891,7 +19064,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
18891
19064
  });
18892
19065
  return;
18893
19066
  }
18894
- tunnel = (0, import_child_process16.spawn)(bin, ["tunnel", "--url", `http://localhost:${detection.port}`], {
19067
+ tunnel = (0, import_child_process17.spawn)(bin, ["tunnel", "--url", `http://localhost:${detection.port}`], {
18895
19068
  stdio: ["ignore", "pipe", "pipe"]
18896
19069
  });
18897
19070
  let parsedUrl = null;
@@ -18987,25 +19160,6 @@ var previewStopH = (ctx) => {
18987
19160
  });
18988
19161
  })();
18989
19162
  };
18990
- function runOnce(cmd, args2, cwd, env) {
18991
- return new Promise((resolve7) => {
18992
- const child = (0, import_child_process16.spawn)(cmd, args2, {
18993
- cwd,
18994
- env: { ...process.env, ...env ?? {} },
18995
- stdio: ["ignore", "pipe", "pipe"]
18996
- });
18997
- const tag = `setup:${cmd}`;
18998
- const onChunk = (chunk) => {
18999
- const text = chunk.toString().replace(/\n+$/g, "");
19000
- if (text.length === 0) return;
19001
- log.info("preview", `${tag}: ${text}`);
19002
- };
19003
- child.stdout?.on("data", onChunk);
19004
- child.stderr?.on("data", onChunk);
19005
- child.once("exit", (code) => resolve7(code));
19006
- child.once("error", () => resolve7(-1));
19007
- });
19008
- }
19009
19163
  var savePreviewConfigH = (_ctx, _cmd, parsed) => {
19010
19164
  const detection = parsed.detection;
19011
19165
  if (!detection) {
@@ -19085,9 +19239,9 @@ async function dispatchCommand(ctx, cmd) {
19085
19239
  }
19086
19240
 
19087
19241
  // src/services/file-watcher.service.ts
19088
- var import_child_process17 = require("child_process");
19242
+ var import_child_process18 = require("child_process");
19089
19243
  var fs33 = __toESM(require("fs"));
19090
- var os26 = __toESM(require("os"));
19244
+ var os27 = __toESM(require("os"));
19091
19245
  var path40 = __toESM(require("path"));
19092
19246
  var import_ignore = __toESM(require("ignore"));
19093
19247
 
@@ -19198,10 +19352,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
19198
19352
  /[\\/]Start Menu([\\/]|$)/i,
19199
19353
  /[\\/]Templates([\\/]|$)/i
19200
19354
  ];
19201
- function isUnsafeWindowsWatchRoot(dir, homedir22) {
19355
+ function isUnsafeWindowsWatchRoot(dir, homedir23) {
19202
19356
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
19203
19357
  const cwd = norm(dir);
19204
- const home = norm(homedir22);
19358
+ const home = norm(homedir23);
19205
19359
  if (cwd === home) return true;
19206
19360
  if (/^[a-z]:$/.test(cwd)) return true;
19207
19361
  const sysRoots = [
@@ -19300,7 +19454,7 @@ var FileWatcherService = class {
19300
19454
  throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
19301
19455
  }
19302
19456
  const isWin = process.platform === "win32";
19303
- if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os26.homedir())) {
19457
+ if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os27.homedir())) {
19304
19458
  log.warn(
19305
19459
  "fileWatcher",
19306
19460
  `refusing to watch ${this.opts.workingDir} \u2014 looks like a Windows user-profile or system path. Run codeam from your project folder to enable file change emission.`
@@ -19851,7 +20005,7 @@ async function _runGitImpl(cwd, args2, opts = {}) {
19851
20005
  return new Promise((resolve7) => {
19852
20006
  let proc;
19853
20007
  try {
19854
- proc = (0, import_child_process17.spawn)("git", args2, { cwd, env: process.env });
20008
+ proc = (0, import_child_process18.spawn)("git", args2, { cwd, env: process.env });
19855
20009
  } catch {
19856
20010
  resolve7(null);
19857
20011
  return;
@@ -19883,7 +20037,7 @@ function _runGit(cwd, args2, opts = {}) {
19883
20037
  var import_crypto4 = require("crypto");
19884
20038
 
19885
20039
  // src/services/turn-files/git-changeset.ts
19886
- var import_child_process18 = require("child_process");
20040
+ var import_child_process19 = require("child_process");
19887
20041
  var path41 = __toESM(require("path"));
19888
20042
  async function collectRepoChangeset(opts) {
19889
20043
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
@@ -19967,7 +20121,7 @@ function defaultRunGit(cwd, args2) {
19967
20121
  return new Promise((resolve7) => {
19968
20122
  let proc;
19969
20123
  try {
19970
- proc = (0, import_child_process18.spawn)("git", args2, { cwd, env: process.env });
20124
+ proc = (0, import_child_process19.spawn)("git", args2, { cwd, env: process.env });
19971
20125
  } catch {
19972
20126
  resolve7(null);
19973
20127
  return;
@@ -21946,7 +22100,7 @@ var OutputService = class _OutputService {
21946
22100
  // src/services/history.service.ts
21947
22101
  var fs35 = __toESM(require("fs"));
21948
22102
  var path43 = __toESM(require("path"));
21949
- var os27 = __toESM(require("os"));
22103
+ var os28 = __toESM(require("os"));
21950
22104
  var https7 = __toESM(require("https"));
21951
22105
  var http7 = __toESM(require("http"));
21952
22106
  var import_zod2 = require("zod");
@@ -22108,7 +22262,7 @@ var HistoryService = class _HistoryService {
22108
22262
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
22109
22263
  }
22110
22264
  get projectDir() {
22111
- return this.runtime.resolveHistoryDir(this.cwd) ?? path43.join(os27.homedir(), ".claude", "projects", encodeCwd(this.cwd));
22265
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path43.join(os28.homedir(), ".claude", "projects", encodeCwd(this.cwd));
22112
22266
  }
22113
22267
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
22114
22268
  setCurrentConversationId(id) {
@@ -22822,13 +22976,13 @@ function fetchQuotaUsage(runtime, historySvc) {
22822
22976
  }
22823
22977
 
22824
22978
  // src/commands/start/keep-alive.ts
22825
- var import_child_process19 = require("child_process");
22979
+ var import_child_process20 = require("child_process");
22826
22980
  function buildKeepAlive(ctx) {
22827
22981
  let timer = null;
22828
22982
  async function setIdleTimeout(minutes) {
22829
22983
  if (!ctx.inCodespace || !ctx.codespaceName) return;
22830
22984
  await new Promise((resolve7) => {
22831
- const proc = (0, import_child_process19.spawn)(
22985
+ const proc = (0, import_child_process20.spawn)(
22832
22986
  "gh",
22833
22987
  [
22834
22988
  "api",
@@ -23314,7 +23468,7 @@ async function autoLinkAfterPair(opts) {
23314
23468
 
23315
23469
  // src/commands/pair-auto.ts
23316
23470
  var fs36 = __toESM(require("fs"));
23317
- var os28 = __toESM(require("os"));
23471
+ var os29 = __toESM(require("os"));
23318
23472
  var import_crypto7 = require("crypto");
23319
23473
 
23320
23474
  // src/commands/start-infra-only.ts
@@ -23540,7 +23694,7 @@ async function claimOnce(token, pluginId) {
23540
23694
  pluginId,
23541
23695
  ideName: "codeam-cli (codespace)",
23542
23696
  ideVersion: process.env.npm_package_version ?? "unknown",
23543
- hostname: os28.hostname(),
23697
+ hostname: os29.hostname(),
23544
23698
  codespaceName: process.env.CODESPACE_NAME ?? "",
23545
23699
  // Current git branch of the codespace's working directory, so the
23546
23700
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -23777,11 +23931,11 @@ async function logout() {
23777
23931
  var import_picocolors10 = __toESM(require("picocolors"));
23778
23932
 
23779
23933
  // src/services/providers/github-codespaces.ts
23780
- var import_child_process20 = require("child_process");
23934
+ var import_child_process21 = require("child_process");
23781
23935
  var import_util4 = require("util");
23782
23936
  var import_picocolors8 = __toESM(require("picocolors"));
23783
23937
  var path44 = __toESM(require("path"));
23784
- var execFileP5 = (0, import_util4.promisify)(import_child_process20.execFile);
23938
+ var execFileP5 = (0, import_util4.promisify)(import_child_process21.execFile);
23785
23939
  var MAX_BUFFER = 8 * 1024 * 1024;
23786
23940
  function resetStdinForChild() {
23787
23941
  if (process.stdin.isTTY) {
@@ -23825,7 +23979,7 @@ var GitHubCodespacesProvider = class {
23825
23979
  if (!isAuthed) {
23826
23980
  resetStdinForChild();
23827
23981
  await new Promise((resolve7, reject) => {
23828
- const proc = (0, import_child_process20.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
23982
+ const proc = (0, import_child_process21.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
23829
23983
  stdio: "inherit"
23830
23984
  });
23831
23985
  proc.on("exit", (code) => {
@@ -23859,7 +24013,7 @@ var GitHubCodespacesProvider = class {
23859
24013
  wt(noteLines.join("\n"), "One more permission needed");
23860
24014
  resetStdinForChild();
23861
24015
  const refreshCode = await new Promise((resolve7, reject) => {
23862
- const proc = (0, import_child_process20.spawn)(
24016
+ const proc = (0, import_child_process21.spawn)(
23863
24017
  "gh",
23864
24018
  ["auth", "refresh", "-h", "github.com", "-s", "codespace"],
23865
24019
  { stdio: "inherit" }
@@ -24009,7 +24163,7 @@ var GitHubCodespacesProvider = class {
24009
24163
  O2.step(`Installing gh via ${installCmd.describe}\u2026`);
24010
24164
  resetStdinForChild();
24011
24165
  const ok = await new Promise((resolve7) => {
24012
- const proc = (0, import_child_process20.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
24166
+ const proc = (0, import_child_process21.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
24013
24167
  proc.on("exit", (code) => resolve7(code === 0));
24014
24168
  proc.on("error", () => resolve7(false));
24015
24169
  });
@@ -24036,7 +24190,7 @@ var GitHubCodespacesProvider = class {
24036
24190
  );
24037
24191
  resetStdinForChild();
24038
24192
  await new Promise((resolve7, reject) => {
24039
- const proc = (0, import_child_process20.spawn)(
24193
+ const proc = (0, import_child_process21.spawn)(
24040
24194
  "gh",
24041
24195
  ["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
24042
24196
  { stdio: "inherit" }
@@ -24214,7 +24368,7 @@ var GitHubCodespacesProvider = class {
24214
24368
  async streamCommand(workspaceId, command2) {
24215
24369
  resetStdinForChild();
24216
24370
  return new Promise((resolve7, reject) => {
24217
- const proc = (0, import_child_process20.spawn)(
24371
+ const proc = (0, import_child_process21.spawn)(
24218
24372
  "gh",
24219
24373
  ["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
24220
24374
  { stdio: "inherit" }
@@ -24241,11 +24395,11 @@ var GitHubCodespacesProvider = class {
24241
24395
  `mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
24242
24396
  ];
24243
24397
  await new Promise((resolve7, reject) => {
24244
- const tar = (0, import_child_process20.spawn)("tar", tarArgs, {
24398
+ const tar = (0, import_child_process21.spawn)("tar", tarArgs, {
24245
24399
  stdio: ["ignore", "pipe", "pipe"],
24246
24400
  env: tarEnv
24247
24401
  });
24248
- const ssh = (0, import_child_process20.spawn)("gh", sshArgs, {
24402
+ const ssh = (0, import_child_process21.spawn)("gh", sshArgs, {
24249
24403
  stdio: [tar.stdout, "pipe", "pipe"]
24250
24404
  });
24251
24405
  let tarErr = "";
@@ -24279,7 +24433,7 @@ var GitHubCodespacesProvider = class {
24279
24433
  }
24280
24434
  const cmd = parts.join(" && ");
24281
24435
  await new Promise((resolve7, reject) => {
24282
- const proc = (0, import_child_process20.spawn)(
24436
+ const proc = (0, import_child_process21.spawn)(
24283
24437
  "gh",
24284
24438
  ["codespace", "ssh", "-c", workspaceId, "--", cmd],
24285
24439
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -24337,11 +24491,11 @@ function shellQuote(s) {
24337
24491
  }
24338
24492
 
24339
24493
  // src/services/providers/gitpod.ts
24340
- var import_child_process21 = require("child_process");
24494
+ var import_child_process22 = require("child_process");
24341
24495
  var import_util5 = require("util");
24342
24496
  var path45 = __toESM(require("path"));
24343
24497
  var import_picocolors9 = __toESM(require("picocolors"));
24344
- var execFileP6 = (0, import_util5.promisify)(import_child_process21.execFile);
24498
+ var execFileP6 = (0, import_util5.promisify)(import_child_process22.execFile);
24345
24499
  var MAX_BUFFER2 = 8 * 1024 * 1024;
24346
24500
  function resetStdinForChild2() {
24347
24501
  if (process.stdin.isTTY) {
@@ -24381,7 +24535,7 @@ var GitpodProvider = class {
24381
24535
  );
24382
24536
  resetStdinForChild2();
24383
24537
  await new Promise((resolve7, reject) => {
24384
- const proc = (0, import_child_process21.spawn)("gitpod", ["login"], { stdio: "inherit" });
24538
+ const proc = (0, import_child_process22.spawn)("gitpod", ["login"], { stdio: "inherit" });
24385
24539
  proc.on("exit", (code) => {
24386
24540
  if (code === 0) resolve7();
24387
24541
  else reject(new Error("gitpod login failed."));
@@ -24533,7 +24687,7 @@ var GitpodProvider = class {
24533
24687
  async streamCommand(workspaceId, command2) {
24534
24688
  resetStdinForChild2();
24535
24689
  return new Promise((resolve7, reject) => {
24536
- const proc = (0, import_child_process21.spawn)(
24690
+ const proc = (0, import_child_process22.spawn)(
24537
24691
  "gitpod",
24538
24692
  ["workspace", "ssh", workspaceId, "--", "-tt", command2],
24539
24693
  { stdio: "inherit" }
@@ -24553,11 +24707,11 @@ var GitpodProvider = class {
24553
24707
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
24554
24708
  const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
24555
24709
  await new Promise((resolve7, reject) => {
24556
- const tar = (0, import_child_process21.spawn)("tar", tarArgs, {
24710
+ const tar = (0, import_child_process22.spawn)("tar", tarArgs, {
24557
24711
  stdio: ["ignore", "pipe", "pipe"],
24558
24712
  env: tarEnv
24559
24713
  });
24560
- const ssh = (0, import_child_process21.spawn)(
24714
+ const ssh = (0, import_child_process22.spawn)(
24561
24715
  "gitpod",
24562
24716
  ["workspace", "ssh", workspaceId, "--", remoteCmd],
24563
24717
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -24589,7 +24743,7 @@ var GitpodProvider = class {
24589
24743
  }
24590
24744
  const cmd = parts.join(" && ");
24591
24745
  await new Promise((resolve7, reject) => {
24592
- const proc = (0, import_child_process21.spawn)(
24746
+ const proc = (0, import_child_process22.spawn)(
24593
24747
  "gitpod",
24594
24748
  ["workspace", "ssh", workspaceId, "--", cmd],
24595
24749
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -24613,10 +24767,10 @@ function shellQuote2(s) {
24613
24767
  }
24614
24768
 
24615
24769
  // src/services/providers/gitlab-workspaces.ts
24616
- var import_child_process22 = require("child_process");
24770
+ var import_child_process23 = require("child_process");
24617
24771
  var import_util6 = require("util");
24618
24772
  var path46 = __toESM(require("path"));
24619
- var execFileP7 = (0, import_util6.promisify)(import_child_process22.execFile);
24773
+ var execFileP7 = (0, import_util6.promisify)(import_child_process23.execFile);
24620
24774
  var MAX_BUFFER3 = 8 * 1024 * 1024;
24621
24775
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
24622
24776
  function resetStdinForChild3() {
@@ -24658,7 +24812,7 @@ var GitLabWorkspacesProvider = class {
24658
24812
  );
24659
24813
  resetStdinForChild3();
24660
24814
  await new Promise((resolve7, reject) => {
24661
- const proc = (0, import_child_process22.spawn)(
24815
+ const proc = (0, import_child_process23.spawn)(
24662
24816
  "glab",
24663
24817
  ["auth", "login", "--scopes", "api,read_user,read_repository"],
24664
24818
  { stdio: "inherit" }
@@ -24830,7 +24984,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
24830
24984
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
24831
24985
  resetStdinForChild3();
24832
24986
  return new Promise((resolve7, reject) => {
24833
- const proc = (0, import_child_process22.spawn)(
24987
+ const proc = (0, import_child_process23.spawn)(
24834
24988
  "ssh",
24835
24989
  ["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
24836
24990
  { stdio: "inherit" }
@@ -24851,8 +25005,8 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
24851
25005
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
24852
25006
  const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
24853
25007
  await new Promise((resolve7, reject) => {
24854
- const tar = (0, import_child_process22.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
24855
- const ssh = (0, import_child_process22.spawn)(
25008
+ const tar = (0, import_child_process23.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25009
+ const ssh = (0, import_child_process23.spawn)(
24856
25010
  "ssh",
24857
25011
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, remoteCmd],
24858
25012
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -24882,7 +25036,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
24882
25036
  }
24883
25037
  const cmd = parts.join(" && ");
24884
25038
  await new Promise((resolve7, reject) => {
24885
- const proc = (0, import_child_process22.spawn)(
25039
+ const proc = (0, import_child_process23.spawn)(
24886
25040
  "ssh",
24887
25041
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
24888
25042
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -24941,10 +25095,10 @@ function shellQuote3(s) {
24941
25095
  }
24942
25096
 
24943
25097
  // src/services/providers/railway.ts
24944
- var import_child_process23 = require("child_process");
25098
+ var import_child_process24 = require("child_process");
24945
25099
  var import_util7 = require("util");
24946
25100
  var path47 = __toESM(require("path"));
24947
- var execFileP8 = (0, import_util7.promisify)(import_child_process23.execFile);
25101
+ var execFileP8 = (0, import_util7.promisify)(import_child_process24.execFile);
24948
25102
  var MAX_BUFFER4 = 8 * 1024 * 1024;
24949
25103
  function resetStdinForChild4() {
24950
25104
  if (process.stdin.isTTY) {
@@ -24985,7 +25139,7 @@ var RailwayProvider = class {
24985
25139
  );
24986
25140
  resetStdinForChild4();
24987
25141
  await new Promise((resolve7, reject) => {
24988
- const proc = (0, import_child_process23.spawn)("railway", ["login"], { stdio: "inherit" });
25142
+ const proc = (0, import_child_process24.spawn)("railway", ["login"], { stdio: "inherit" });
24989
25143
  proc.on("exit", (code) => {
24990
25144
  if (code === 0) resolve7();
24991
25145
  else reject(new Error("railway login failed."));
@@ -25128,7 +25282,7 @@ var RailwayProvider = class {
25128
25282
  }
25129
25283
  resetStdinForChild4();
25130
25284
  return new Promise((resolve7, reject) => {
25131
- const proc = (0, import_child_process23.spawn)(
25285
+ const proc = (0, import_child_process24.spawn)(
25132
25286
  "railway",
25133
25287
  ["shell", "--project", projectId, "--service", serviceId, "--command", command2],
25134
25288
  { stdio: "inherit" }
@@ -25152,8 +25306,8 @@ var RailwayProvider = class {
25152
25306
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
25153
25307
  const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
25154
25308
  await new Promise((resolve7, reject) => {
25155
- const tar = (0, import_child_process23.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25156
- const sh = (0, import_child_process23.spawn)(
25309
+ const tar = (0, import_child_process24.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25310
+ const sh = (0, import_child_process24.spawn)(
25157
25311
  "railway",
25158
25312
  ["shell", "--project", projectId, "--service", serviceId, "--command", remoteCmd],
25159
25313
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -25186,7 +25340,7 @@ var RailwayProvider = class {
25186
25340
  }
25187
25341
  const cmd = parts.join(" && ");
25188
25342
  await new Promise((resolve7, reject) => {
25189
- const proc = (0, import_child_process23.spawn)(
25343
+ const proc = (0, import_child_process24.spawn)(
25190
25344
  "railway",
25191
25345
  ["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
25192
25346
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -25825,9 +25979,9 @@ function checkSessions() {
25825
25979
  }
25826
25980
  }
25827
25981
  function checkAgentBinaries() {
25828
- const os30 = createOsStrategy();
25982
+ const os31 = createOsStrategy();
25829
25983
  return getEnabledAgents().map((meta) => {
25830
- const found = os30.findInPath(meta.binaryName);
25984
+ const found = os31.findInPath(meta.binaryName);
25831
25985
  return {
25832
25986
  id: `agent-${meta.id}`,
25833
25987
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -25891,7 +26045,7 @@ function checkChokidar() {
25891
26045
  }
25892
26046
  async function doctor(args2 = []) {
25893
26047
  const json = args2.includes("--json");
25894
- const cliVersion = true ? "2.35.1" : "0.0.0-dev";
26048
+ const cliVersion = true ? "2.35.3" : "0.0.0-dev";
25895
26049
  const apiBase = resolveApiBaseUrl();
25896
26050
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
25897
26051
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -26090,7 +26244,7 @@ async function completion(args2) {
26090
26244
  // src/commands/version.ts
26091
26245
  var import_picocolors13 = __toESM(require("picocolors"));
26092
26246
  function version2() {
26093
- const v = true ? "2.35.1" : "unknown";
26247
+ const v = true ? "2.35.3" : "unknown";
26094
26248
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
26095
26249
  }
26096
26250
 
@@ -26219,7 +26373,7 @@ var _subcommandHelpKeys = Object.keys(HELPS);
26219
26373
 
26220
26374
  // src/lib/updateNotifier.ts
26221
26375
  var fs38 = __toESM(require("fs"));
26222
- var os29 = __toESM(require("os"));
26376
+ var os30 = __toESM(require("os"));
26223
26377
  var path49 = __toESM(require("path"));
26224
26378
  var https8 = __toESM(require("https"));
26225
26379
  var import_node_child_process12 = require("child_process");
@@ -26229,7 +26383,7 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
26229
26383
  var TTL_MS = 24 * 60 * 60 * 1e3;
26230
26384
  var REQUEST_TIMEOUT_MS = 1500;
26231
26385
  function cachePath() {
26232
- const dir = path49.join(os29.homedir(), ".codeam");
26386
+ const dir = path49.join(os30.homedir(), ".codeam");
26233
26387
  return path49.join(dir, "update-check.json");
26234
26388
  }
26235
26389
  function readCache() {
@@ -26376,7 +26530,7 @@ function checkForUpdates() {
26376
26530
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
26377
26531
  if (process.env.CI) return;
26378
26532
  if (!process.stdout.isTTY) return;
26379
- const current = true ? "2.35.1" : null;
26533
+ const current = true ? "2.35.3" : null;
26380
26534
  if (!current) return;
26381
26535
  const cache = readCache();
26382
26536
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.35.1",
3
+ "version": "2.35.3",
4
4
  "description": "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device — async. The terminal companion for CodeAgent Mobile.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",