codeam-cli 2.39.54 → 2.39.56

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 +12 -0
  2. package/dist/index.js +701 -462
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -87,7 +87,7 @@ var require_src = __commonJS({
87
87
  });
88
88
 
89
89
  // src/commands/start.ts
90
- var import_picocolors3 = __toESM(require("picocolors"));
90
+ var import_picocolors4 = __toESM(require("picocolors"));
91
91
 
92
92
  // ../../packages/shared/src/protocol/constants.ts
93
93
  var PROTOCOL_VERSION = "2.0.0";
@@ -513,9 +513,9 @@ var _default = makeConfig();
513
513
  var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, clearAll, saveCliConfig, loadCliConfig } = _default;
514
514
 
515
515
  // src/commands/pair-auto.ts
516
- var fs38 = __toESM(require("fs"));
517
- var os32 = __toESM(require("os"));
518
- var path44 = __toESM(require("path"));
516
+ var fs40 = __toESM(require("fs"));
517
+ var os33 = __toESM(require("os"));
518
+ var path46 = __toESM(require("path"));
519
519
  var import_crypto4 = require("crypto");
520
520
 
521
521
  // src/services/telemetry.service.ts
@@ -551,8 +551,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
551
551
  return decodedFile;
552
552
  };
553
553
  }
554
- function normalizeWindowsPath(path58) {
555
- return path58.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
554
+ function normalizeWindowsPath(path59) {
555
+ return path59.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
556
556
  }
557
557
 
558
558
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3032,9 +3032,9 @@ async function addSourceContext(frames) {
3032
3032
  LRU_FILE_CONTENTS_CACHE.reduce();
3033
3033
  return frames;
3034
3034
  }
3035
- function getContextLinesFromFile(path58, ranges, output) {
3035
+ function getContextLinesFromFile(path59, ranges, output) {
3036
3036
  return new Promise((resolve7) => {
3037
- const stream = (0, import_node_fs.createReadStream)(path58);
3037
+ const stream = (0, import_node_fs.createReadStream)(path59);
3038
3038
  const lineReaded = (0, import_node_readline.createInterface)({
3039
3039
  input: stream
3040
3040
  });
@@ -3049,7 +3049,7 @@ function getContextLinesFromFile(path58, ranges, output) {
3049
3049
  let rangeStart = range[0];
3050
3050
  let rangeEnd = range[1];
3051
3051
  function onStreamError() {
3052
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path58, 1);
3052
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path59, 1);
3053
3053
  lineReaded.close();
3054
3054
  lineReaded.removeAllListeners();
3055
3055
  destroyStreamAndResolve();
@@ -3110,8 +3110,8 @@ function clearLineContext(frame) {
3110
3110
  delete frame.context_line;
3111
3111
  delete frame.post_context;
3112
3112
  }
3113
- function shouldSkipContextLinesForFile(path58) {
3114
- return path58.startsWith("node:") || path58.endsWith(".min.js") || path58.endsWith(".min.cjs") || path58.endsWith(".min.mjs") || path58.startsWith("data:");
3113
+ function shouldSkipContextLinesForFile(path59) {
3114
+ return path59.startsWith("node:") || path59.endsWith(".min.js") || path59.endsWith(".min.cjs") || path59.endsWith(".min.mjs") || path59.startsWith("data:");
3115
3115
  }
3116
3116
  function shouldSkipContextLinesForFrame(frame) {
3117
3117
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5388,7 +5388,7 @@ function readAnonId() {
5388
5388
  }
5389
5389
  function superProperties() {
5390
5390
  return {
5391
- cliVersion: true ? "2.39.54" : "0.0.0-dev",
5391
+ cliVersion: true ? "2.39.56" : "0.0.0-dev",
5392
5392
  nodeVersion: process.version,
5393
5393
  platform: process.platform,
5394
5394
  arch: process.arch,
@@ -5547,7 +5547,7 @@ var os4 = __toESM(require("os"));
5547
5547
  // package.json
5548
5548
  var package_default = {
5549
5549
  name: "codeam-cli",
5550
- version: "2.39.54",
5550
+ version: "2.39.56",
5551
5551
  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.",
5552
5552
  type: "commonjs",
5553
5553
  main: "dist/index.js",
@@ -12502,11 +12502,11 @@ function parseReview(stdout) {
12502
12502
  for (const line of lines) {
12503
12503
  const m = line.match(HUNK_LINE_RE);
12504
12504
  if (!m) continue;
12505
- const [, path58, lineNo, sevToken, message] = m;
12506
- if (!path58 || !lineNo || !message) continue;
12505
+ const [, path59, lineNo, sevToken, message] = m;
12506
+ if (!path59 || !lineNo || !message) continue;
12507
12507
  const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
12508
12508
  hunks.push({
12509
- path: path58.trim(),
12509
+ path: path59.trim(),
12510
12510
  line: Number(lineNo),
12511
12511
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
12512
12512
  message: cleanedMessage
@@ -16779,8 +16779,10 @@ async function startInfraOnly(agentId) {
16779
16779
  }
16780
16780
 
16781
16781
  // src/commands/host-agent.ts
16782
- var import_node_child_process12 = require("child_process");
16783
- var os31 = __toESM(require("os"));
16782
+ var import_node_child_process13 = require("child_process");
16783
+ var os32 = __toESM(require("os"));
16784
+ var fs39 = __toESM(require("fs"));
16785
+ var path45 = __toESM(require("path"));
16784
16786
 
16785
16787
  // src/commands/host/host-client.ts
16786
16788
  var fs35 = __toESM(require("fs"));
@@ -16917,12 +16919,13 @@ async function redeemEnrollToken(token, label) {
16917
16919
  controlPluginId: data.controlPluginId
16918
16920
  };
16919
16921
  }
16920
- async function sendHostHeartbeat(identity, metrics) {
16922
+ async function sendHostHeartbeat(identity, metrics, sessions3) {
16921
16923
  const start2 = process.hrtime.bigint();
16922
16924
  await postJson("/api/self-hosted/heartbeat", {
16923
16925
  hostId: identity.hostId,
16924
16926
  hostToken: identity.hostToken,
16925
- ...metrics ? { metrics } : {}
16927
+ ...metrics ? { metrics } : {},
16928
+ ...sessions3 ? { sessions: sessions3 } : {}
16926
16929
  });
16927
16930
  const elapsedNs = process.hrtime.bigint() - start2;
16928
16931
  return Math.round(Number(elapsedNs) / 1e6);
@@ -17199,8 +17202,185 @@ var HeadroomStatsReporter = class {
17199
17202
  }
17200
17203
  };
17201
17204
 
17205
+ // src/lib/updateNotifier.ts
17206
+ var fs38 = __toESM(require("fs"));
17207
+ var os31 = __toESM(require("os"));
17208
+ var path44 = __toESM(require("path"));
17209
+ var https6 = __toESM(require("https"));
17210
+ var import_node_child_process12 = require("child_process");
17211
+ var import_picocolors3 = __toESM(require("picocolors"));
17212
+ var PKG_NAME = "codeam-cli";
17213
+ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
17214
+ var TTL_MS = 24 * 60 * 60 * 1e3;
17215
+ var REQUEST_TIMEOUT_MS = 1500;
17216
+ function cachePath() {
17217
+ const dir = path44.join(os31.homedir(), ".codeam");
17218
+ return path44.join(dir, "update-check.json");
17219
+ }
17220
+ function readCache() {
17221
+ try {
17222
+ const raw = fs38.readFileSync(cachePath(), "utf8");
17223
+ const parsed = JSON.parse(raw);
17224
+ if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
17225
+ return parsed;
17226
+ } catch {
17227
+ return null;
17228
+ }
17229
+ }
17230
+ function writeCache(cache) {
17231
+ try {
17232
+ const file = cachePath();
17233
+ fs38.mkdirSync(path44.dirname(file), { recursive: true });
17234
+ const tmp = `${file}.${process.pid}.tmp`;
17235
+ fs38.writeFileSync(tmp, JSON.stringify(cache));
17236
+ fs38.renameSync(tmp, file);
17237
+ } catch {
17238
+ }
17239
+ }
17240
+ function compareSemver(a, b) {
17241
+ const stripPre = (s) => s.split("-")[0];
17242
+ const aParts = stripPre(a).split(".").map(Number);
17243
+ const bParts = stripPre(b).split(".").map(Number);
17244
+ for (let i = 0; i < 3; i++) {
17245
+ const ai = aParts[i] ?? 0;
17246
+ const bi = bParts[i] ?? 0;
17247
+ if (Number.isNaN(ai) || Number.isNaN(bi)) return 0;
17248
+ if (ai > bi) return 1;
17249
+ if (ai < bi) return -1;
17250
+ }
17251
+ return 0;
17252
+ }
17253
+ function fetchLatest() {
17254
+ return new Promise((resolve7) => {
17255
+ const req = https6.get(
17256
+ REGISTRY_URL,
17257
+ { headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
17258
+ (res) => {
17259
+ if (res.statusCode !== 200) {
17260
+ res.resume();
17261
+ resolve7(null);
17262
+ return;
17263
+ }
17264
+ let buf = "";
17265
+ res.setEncoding("utf8");
17266
+ res.on("data", (chunk) => {
17267
+ buf += chunk;
17268
+ });
17269
+ res.on("end", () => {
17270
+ try {
17271
+ const json = JSON.parse(buf);
17272
+ if (typeof json.version === "string") {
17273
+ resolve7(json.version);
17274
+ } else {
17275
+ resolve7(null);
17276
+ }
17277
+ } catch {
17278
+ resolve7(null);
17279
+ }
17280
+ });
17281
+ }
17282
+ );
17283
+ req.on("timeout", () => {
17284
+ req.destroy();
17285
+ resolve7(null);
17286
+ });
17287
+ req.on("error", () => resolve7(null));
17288
+ });
17289
+ }
17290
+ function notifyIfStale(currentVersion, latest) {
17291
+ if (compareSemver(latest, currentVersion) <= 0) return;
17292
+ const arrow = import_picocolors3.default.dim("\u2192");
17293
+ const cmd = import_picocolors3.default.cyan("npm install -g codeam-cli");
17294
+ const lines = [
17295
+ "",
17296
+ ` ${import_picocolors3.default.yellow("\u25CF")} ${import_picocolors3.default.bold("Update available")} ${import_picocolors3.default.dim(currentVersion)} ${arrow} ${import_picocolors3.default.green(latest)}`,
17297
+ ` Run ${cmd} to upgrade.`,
17298
+ ""
17299
+ ];
17300
+ process.stderr.write(lines.join("\n"));
17301
+ }
17302
+ function isLinkedInstall() {
17303
+ try {
17304
+ const root = (0, import_node_child_process12.execSync)("npm root -g", {
17305
+ encoding: "utf8",
17306
+ stdio: ["ignore", "pipe", "ignore"],
17307
+ timeout: 2e3
17308
+ }).trim();
17309
+ if (!root) return false;
17310
+ const pkgPath = path44.join(root, PKG_NAME);
17311
+ return fs38.lstatSync(pkgPath).isSymbolicLink();
17312
+ } catch {
17313
+ return false;
17314
+ }
17315
+ }
17316
+ function maybeAutoUpdate(currentVersion, latest) {
17317
+ if (compareSemver(latest, currentVersion) <= 0) return;
17318
+ if (process.env.CODEAM_NO_AUTO_UPDATE === "1") {
17319
+ notifyIfStale(currentVersion, latest);
17320
+ return;
17321
+ }
17322
+ if (isLinkedInstall()) {
17323
+ notifyIfStale(currentVersion, latest);
17324
+ return;
17325
+ }
17326
+ process.stderr.write(
17327
+ `
17328
+ ${import_picocolors3.default.yellow("\u25CF")} ${import_picocolors3.default.bold("Updating codeam-cli")} ${import_picocolors3.default.dim(currentVersion)} ${import_picocolors3.default.dim("\u2192")} ${import_picocolors3.default.green(latest)}...
17329
+
17330
+ `
17331
+ );
17332
+ const install = (0, import_node_child_process12.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
17333
+ stdio: "inherit",
17334
+ env: process.env
17335
+ });
17336
+ if (install.status !== 0) {
17337
+ process.stderr.write(
17338
+ `
17339
+ ${import_picocolors3.default.red("!")} Update failed (exit ${install.status ?? "?"}). Continuing on ${currentVersion}.
17340
+ Run ${import_picocolors3.default.cyan("npm install -g codeam-cli")} manually to retry.
17341
+
17342
+ `
17343
+ );
17344
+ return;
17345
+ }
17346
+ try {
17347
+ fs38.unlinkSync(cachePath());
17348
+ } catch {
17349
+ }
17350
+ process.stderr.write(` ${import_picocolors3.default.green("\u2713")} Updated. Resuming session...
17351
+
17352
+ `);
17353
+ const child = (0, import_node_child_process12.spawnSync)("codeam", process.argv.slice(2), {
17354
+ stdio: "inherit",
17355
+ env: process.env
17356
+ });
17357
+ process.exit(child.status ?? 0);
17358
+ }
17359
+ function checkForUpdates() {
17360
+ if (process.env.NODE_ENV === "test") return;
17361
+ if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17362
+ if (process.env.CI) return;
17363
+ if (!process.stdout.isTTY) return;
17364
+ const current = true ? "2.39.56" : null;
17365
+ if (!current) return;
17366
+ const cache = readCache();
17367
+ const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
17368
+ if (fresh && cache) {
17369
+ maybeAutoUpdate(current, cache.latest);
17370
+ return;
17371
+ }
17372
+ void fetchLatest().then((latest) => {
17373
+ if (!latest) return;
17374
+ writeCache({ fetchedAt: Date.now(), latest });
17375
+ });
17376
+ }
17377
+
17202
17378
  // src/commands/host-agent.ts
17203
17379
  var HEARTBEAT_INTERVAL_MS = 2e4;
17380
+ var SELF_UPDATE_PKG = "codeam-cli";
17381
+ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17382
+ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17383
+ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17204
17384
  function maybeStartHeadroomReporter(ctx) {
17205
17385
  if (process.env["HEADROOM_ENABLED"] !== "1") return null;
17206
17386
  try {
@@ -17275,7 +17455,7 @@ var PIP_INSTALL_TIMEOUT_MS = 12e4;
17275
17455
  var defaultHeadroomRunner = {
17276
17456
  which(cmd) {
17277
17457
  try {
17278
- (0, import_node_child_process12.execFileSync)("which", [cmd], { stdio: "ignore" });
17458
+ (0, import_node_child_process13.execFileSync)("which", [cmd], { stdio: "ignore" });
17279
17459
  return true;
17280
17460
  } catch {
17281
17461
  return false;
@@ -17283,7 +17463,7 @@ var defaultHeadroomRunner = {
17283
17463
  },
17284
17464
  run(cmd, args2, opts = {}) {
17285
17465
  return new Promise((resolve7) => {
17286
- const child = (0, import_node_child_process12.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"] });
17466
+ const child = (0, import_node_child_process13.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"] });
17287
17467
  let stderrBuf = "";
17288
17468
  let settled = false;
17289
17469
  const done = (code) => {
@@ -17416,6 +17596,41 @@ function agentIdToHeadroomKind(agentId) {
17416
17596
  if (normalized.startsWith("copilot")) return "copilot";
17417
17597
  return "claude";
17418
17598
  }
17599
+ function headroomConfigPath() {
17600
+ return path45.join(os32.homedir(), ".codeam", "headroom-config.json");
17601
+ }
17602
+ function persistHeadroomConfig(config) {
17603
+ try {
17604
+ const file = headroomConfigPath();
17605
+ fs39.mkdirSync(path45.dirname(file), { recursive: true, mode: 448 });
17606
+ const tmp = `${file}.tmp-${process.pid}`;
17607
+ fs39.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
17608
+ fs39.renameSync(tmp, file);
17609
+ } catch (err) {
17610
+ log.warn(
17611
+ "host-agent",
17612
+ `failed to persist headroom config (best-effort): ${err instanceof Error ? err.message : String(err)}`
17613
+ );
17614
+ }
17615
+ }
17616
+ function readHeadroomChildEnv() {
17617
+ try {
17618
+ const raw = fs39.readFileSync(headroomConfigPath(), "utf8");
17619
+ const parsed = JSON.parse(raw);
17620
+ if (typeof parsed !== "object" || parsed === null) return {};
17621
+ const o = parsed;
17622
+ if (o.enabled === true && typeof o.agent === "string" && o.agent.length > 0 && typeof o.ingestUrl === "string" && o.ingestUrl.length > 0) {
17623
+ return {
17624
+ HEADROOM_ENABLED: "1",
17625
+ HEADROOM_AGENT: o.agent,
17626
+ HEADROOM_SAVINGS_INGEST_URL: o.ingestUrl
17627
+ };
17628
+ }
17629
+ return {};
17630
+ } catch {
17631
+ return {};
17632
+ }
17633
+ }
17419
17634
  async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner) {
17420
17635
  const PIP_PACKAGES = [
17421
17636
  "headroom-ai",
@@ -17473,7 +17688,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17473
17688
  }
17474
17689
  const initKind = agentIdToHeadroomKind(agent);
17475
17690
  const initOk = await new Promise((resolve7) => {
17476
- (0, import_node_child_process12.execFile)("headroom", ["init", "--global", initKind], (initErr, stdout, stderr) => {
17691
+ (0, import_node_child_process13.execFile)("headroom", ["init", "--global", initKind], (initErr, stdout, stderr) => {
17477
17692
  if (initErr) {
17478
17693
  const detail = (stderr || initErr.message).replace(/\n+$/g, "");
17479
17694
  log.warn("host-agent", `headroom init failed (best-effort): ${detail}`);
@@ -17489,7 +17704,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17489
17704
  return false;
17490
17705
  }
17491
17706
  try {
17492
- const proxy = (0, import_node_child_process12.spawn)("headroom", ["proxy", "--port", "8787"], {
17707
+ const proxy = (0, import_node_child_process13.spawn)("headroom", ["proxy", "--port", "8787"], {
17493
17708
  stdio: "ignore",
17494
17709
  detached: true
17495
17710
  });
@@ -17499,20 +17714,81 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17499
17714
  }
17500
17715
  return true;
17501
17716
  }
17502
- var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process12.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
17717
+ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process13.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
17503
17718
  cwd,
17504
17719
  env: { ...process.env, ...env },
17505
17720
  stdio: ["ignore", "pipe", "pipe"],
17506
17721
  detached: false
17507
17722
  });
17723
+ function currentCliVersion() {
17724
+ return true ? "2.39.56" : null;
17725
+ }
17726
+ function runCmd(cmd, args2, timeoutMs) {
17727
+ return new Promise((resolve7) => {
17728
+ (0, import_node_child_process13.execFile)(cmd, args2, { timeout: timeoutMs }, (err, stdout, stderr) => {
17729
+ const code = err && typeof err.code === "number" ? err.code : err ? null : 0;
17730
+ resolve7({ code, stdout: stdout ?? "", stderr: stderr ?? "" });
17731
+ });
17732
+ });
17733
+ }
17734
+ async function runSelfUpdate() {
17735
+ try {
17736
+ const current = currentCliVersion();
17737
+ if (!current) {
17738
+ log.trace("host-agent", "self-update: no __CLI_VERSION__ \u2014 skipping");
17739
+ return { status: "skipped" };
17740
+ }
17741
+ const view = await runCmd("npm", ["view", SELF_UPDATE_PKG, "version"], SELF_UPDATE_VIEW_TIMEOUT_MS);
17742
+ if (view.code !== 0) {
17743
+ log.trace("host-agent", `self-update: npm view exited ${String(view.code)} \u2014 skipping`);
17744
+ return { status: "skipped" };
17745
+ }
17746
+ const latest = view.stdout.trim();
17747
+ if (!latest) {
17748
+ log.trace("host-agent", "self-update: empty npm view output \u2014 skipping");
17749
+ return { status: "skipped" };
17750
+ }
17751
+ if (compareSemver(latest, current) <= 0) {
17752
+ return { status: "current" };
17753
+ }
17754
+ log.info("host-agent", `self-update: ${current} \u2192 ${latest} available \u2014 installing`);
17755
+ const installArgs = ["install", "-g", `${SELF_UPDATE_PKG}@latest`];
17756
+ let install = await runCmd("npm", installArgs, SELF_UPDATE_INSTALL_TIMEOUT_MS);
17757
+ const isRoot = process.getuid?.() === 0;
17758
+ if (install.code !== 0 && !isRoot && /EACCES/i.test(install.stderr)) {
17759
+ log.info("host-agent", "self-update: install hit EACCES \u2014 retrying with sudo");
17760
+ install = await runCmd("sudo", ["npm", ...installArgs], SELF_UPDATE_INSTALL_TIMEOUT_MS);
17761
+ }
17762
+ if (install.code !== 0) {
17763
+ log.warn(
17764
+ "host-agent",
17765
+ `self-update: install exited ${String(install.code)} \u2014 staying on ${current}`
17766
+ );
17767
+ return { status: "skipped" };
17768
+ }
17769
+ const after = await runCmd("npm", ["view", SELF_UPDATE_PKG, "version"], SELF_UPDATE_VIEW_TIMEOUT_MS);
17770
+ const installed = after.code === 0 ? after.stdout.trim() || latest : latest;
17771
+ return { status: "updated", version: installed };
17772
+ } catch (err) {
17773
+ log.warn(
17774
+ "host-agent",
17775
+ `self-update: unexpected error: ${err instanceof Error ? err.message : String(err)}`
17776
+ );
17777
+ return { status: "skipped" };
17778
+ }
17779
+ }
17508
17780
  var defaultOnIdentityRejected = () => {
17509
17781
  deleteHostIdentity();
17510
17782
  log.warn("host-agent", "host identity rejected by backend \u2014 wiped sealed identity, exiting");
17511
17783
  process.exit(1);
17512
17784
  };
17785
+ var defaultOnUpdated = (version3) => {
17786
+ log.info("host-agent", `self-update: installed ${version3}, restarting`);
17787
+ process.exit(0);
17788
+ };
17513
17789
  var defaultDisableService = () => {
17514
17790
  try {
17515
- (0, import_node_child_process12.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
17791
+ (0, import_node_child_process13.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
17516
17792
  } catch {
17517
17793
  }
17518
17794
  };
@@ -17526,6 +17802,8 @@ var HostAgentSupervisor = class {
17526
17802
  this.metrics = deps.metricsCollector ?? new MetricsCollector();
17527
17803
  this.onIdentityRejected = deps.onIdentityRejected ?? defaultOnIdentityRejected;
17528
17804
  this.disableService = deps.disableService ?? defaultDisableService;
17805
+ this.selfUpdate = deps.selfUpdate ?? runSelfUpdate;
17806
+ this.onUpdated = deps.onUpdated ?? defaultOnUpdated;
17529
17807
  }
17530
17808
  identity;
17531
17809
  deps;
@@ -17535,6 +17813,20 @@ var HostAgentSupervisor = class {
17535
17813
  setupHeadroom;
17536
17814
  relay = null;
17537
17815
  heartbeatTimer = null;
17816
+ /** Periodic self-update timer (npm check + install + restart). */
17817
+ selfUpdateTimer = null;
17818
+ /** Self-update check + install (injectable; defaults to runSelfUpdate). */
17819
+ selfUpdate;
17820
+ /** Restart action after a successful self-update (defaults to process.exit). */
17821
+ onUpdated;
17822
+ /** Guards against overlapping self-update ticks (a slow npm install). */
17823
+ selfUpdating = false;
17824
+ /**
17825
+ * Set once a self-update installed a newer version but a child was busy,
17826
+ * so the next idle tick restarts WITHOUT re-installing. Carries the
17827
+ * already-installed version for the restart log.
17828
+ */
17829
+ pendingRestartVersion = null;
17538
17830
  /** Guards the one-shot 'connected' telemetry on the first heartbeat. */
17539
17831
  reportedConnected = false;
17540
17832
  /** Live-metrics collector — stateful across beats (CPU delta + latency). */
@@ -17545,6 +17837,19 @@ var HostAgentSupervisor = class {
17545
17837
  disableService;
17546
17838
  /** Guards against firing the self-heal more than once. */
17547
17839
  healing = false;
17840
+ /**
17841
+ * Resolve the self-update interval, honoring `CODEAM_HOST_SELF_UPDATE_MS`.
17842
+ * A finite value > 0 overrides the default; 0 or negative DISABLES the
17843
+ * periodic self-update (tests / pinned boxes); a non-numeric/absent value
17844
+ * falls back to {@link SELF_UPDATE_INTERVAL_MS}.
17845
+ */
17846
+ selfUpdateIntervalMs() {
17847
+ const raw = process.env.CODEAM_HOST_SELF_UPDATE_MS;
17848
+ if (raw === void 0 || raw === "") return SELF_UPDATE_INTERVAL_MS;
17849
+ const parsed = Number(raw);
17850
+ if (!Number.isFinite(parsed)) return SELF_UPDATE_INTERVAL_MS;
17851
+ return parsed;
17852
+ }
17548
17853
  /** Open the control channel (reusing the relay) + start heartbeats. */
17549
17854
  start() {
17550
17855
  const make = this.deps.makeRelay ?? ((pluginId, onCommand, meta) => new CommandRelayService(pluginId, onCommand, meta));
@@ -17557,6 +17862,13 @@ var HostAgentSupervisor = class {
17557
17862
  void this.beat();
17558
17863
  this.heartbeatTimer = setInterval(() => void this.beat(), HEARTBEAT_INTERVAL_MS);
17559
17864
  this.heartbeatTimer.unref?.();
17865
+ const updateMs = this.selfUpdateIntervalMs();
17866
+ if (updateMs > 0) {
17867
+ this.selfUpdateTimer = setInterval(() => void this.selfUpdateTick(), updateMs);
17868
+ this.selfUpdateTimer.unref?.();
17869
+ } else {
17870
+ log.info("host-agent", "self-update disabled (CODEAM_HOST_SELF_UPDATE_MS<=0)");
17871
+ }
17560
17872
  log.info("host-agent", `supervisor up host=${this.identity.hostId.slice(0, 8)}`);
17561
17873
  }
17562
17874
  /** Stop the control channel + heartbeats + kill every child. */
@@ -17565,6 +17877,10 @@ var HostAgentSupervisor = class {
17565
17877
  clearInterval(this.heartbeatTimer);
17566
17878
  this.heartbeatTimer = null;
17567
17879
  }
17880
+ if (this.selfUpdateTimer) {
17881
+ clearInterval(this.selfUpdateTimer);
17882
+ this.selfUpdateTimer = null;
17883
+ }
17568
17884
  this.relay?.stop();
17569
17885
  for (const child of this.children.values()) {
17570
17886
  try {
@@ -17582,7 +17898,8 @@ var HostAgentSupervisor = class {
17582
17898
  } catch (err) {
17583
17899
  log.trace("host-agent", "metrics collection failed", err);
17584
17900
  }
17585
- const latencyMs = await sendHostHeartbeat(this.identity, metrics);
17901
+ const sessions3 = this.activeSessions();
17902
+ const latencyMs = await sendHostHeartbeat(this.identity, metrics, sessions3);
17586
17903
  this.metrics.recordLatency(latencyMs);
17587
17904
  if (!this.reportedConnected) {
17588
17905
  this.reportedConnected = true;
@@ -17604,10 +17921,81 @@ var HostAgentSupervisor = class {
17604
17921
  log.trace("host-agent", "heartbeat failed", err);
17605
17922
  }
17606
17923
  }
17924
+ /**
17925
+ * One self-update tick. Best-effort + never crashes the supervisor: the
17926
+ * whole body is wrapped in try/catch and the injected updater never
17927
+ * rejects. Sequence:
17928
+ *
17929
+ * 1. If a restart is already PENDING (a prior tick installed a newer
17930
+ * version while a child was busy), skip the npm work and just try to
17931
+ * restart now — no re-install.
17932
+ * 2. Otherwise run the injected `selfUpdate`. On `'updated'`, remember
17933
+ * the new version as pending; on anything else, do nothing.
17934
+ * 3. SAFETY: only restart when no child turn is in flight. If a child is
17935
+ * mid-work, DEFER — the install already happened, so a later idle
17936
+ * tick just restarts. (We prefer deferring to yanking an active turn;
17937
+ * systemd would restart in ~5s but the mobile would drop the turn.)
17938
+ *
17939
+ * `selfUpdating` guards against a slow npm install overlapping the next
17940
+ * tick (the timer keeps firing on its interval).
17941
+ */
17942
+ async selfUpdateTick() {
17943
+ if (this.selfUpdating) return;
17944
+ this.selfUpdating = true;
17945
+ try {
17946
+ if (this.pendingRestartVersion !== null) {
17947
+ this.maybeRestartForUpdate(this.pendingRestartVersion);
17948
+ return;
17949
+ }
17950
+ const result = await this.selfUpdate();
17951
+ if (result.status !== "updated") return;
17952
+ const version3 = result.version ?? "latest";
17953
+ this.pendingRestartVersion = version3;
17954
+ this.maybeRestartForUpdate(version3);
17955
+ } catch (err) {
17956
+ log.warn(
17957
+ "host-agent",
17958
+ `self-update tick failed: ${err instanceof Error ? err.message : String(err)}`
17959
+ );
17960
+ } finally {
17961
+ this.selfUpdating = false;
17962
+ }
17963
+ }
17964
+ /**
17965
+ * Restart for an already-installed update IFF no child turn is in flight.
17966
+ * When a child is busy we DEFER (the version stays pending for the next
17967
+ * idle tick) rather than yank an active turn.
17968
+ */
17969
+ maybeRestartForUpdate(version3) {
17970
+ if (this.children.size > 0) {
17971
+ log.info(
17972
+ "host-agent",
17973
+ `self-update: ${version3} installed but ${this.children.size} child(ren) busy \u2014 deferring restart`
17974
+ );
17975
+ return;
17976
+ }
17977
+ this.onUpdated(version3);
17978
+ }
17607
17979
  /** Number of live children — for tests + diagnostics. */
17608
17980
  childCount() {
17609
17981
  return this.children.size;
17610
17982
  }
17983
+ /**
17984
+ * Snapshot the supervisor's live children as heartbeat session entries.
17985
+ *
17986
+ * Each entry's `id` is the deployId-correlated sessionId the backend
17987
+ * recognizes (the supervisor keys its children by it — the same id a
17988
+ * `self_hosted_stop` arrives with, see `stopChild`). `agent` is the deploy's
17989
+ * `agentId`; `startedAt` is the epoch-ms spawn time tracked on the child.
17990
+ * Returns `[]` when no children are active so the backend reflects "0 active".
17991
+ */
17992
+ activeSessions() {
17993
+ return [...this.children.values()].map((child) => ({
17994
+ id: child.deployId,
17995
+ agent: child.agent,
17996
+ startedAt: child.startedAt
17997
+ }));
17998
+ }
17611
17999
  /**
17612
18000
  * Route a relay command. Only `self_hosted_deploy` / `self_hosted_stop`
17613
18001
  * are understood; anything else is ignored (the box accepts no
@@ -17699,7 +18087,7 @@ var HostAgentSupervisor = class {
17699
18087
  report("installing", "installing agent CLI");
17700
18088
  await this.runAgentInstall(payload.agentInstallScript);
17701
18089
  }
17702
- const home = process.env.HOME || os31.homedir();
18090
+ const home = process.env.HOME || os32.homedir();
17703
18091
  childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
17704
18092
  if (payload.previewTunnelToken && payload.previewHostname) {
17705
18093
  childEnv.PREVIEW_TUNNEL_TOKEN = payload.previewTunnelToken;
@@ -17709,17 +18097,27 @@ var HostAgentSupervisor = class {
17709
18097
  report("headroom", "setting up Headroom proxy");
17710
18098
  const headroomOk = await this.setupHeadroom(payload.headroomAgent);
17711
18099
  if (headroomOk) {
17712
- childEnv.HEADROOM_ENABLED = "1";
17713
- childEnv.HEADROOM_AGENT = agentIdToHeadroomKind(payload.headroomAgent);
17714
- childEnv.HEADROOM_SAVINGS_INGEST_URL = payload.headroomSavingsIngestUrl;
17715
- log.info("host-agent", "Headroom proxy ready; HEADROOM_* env injected into child");
18100
+ persistHeadroomConfig({
18101
+ enabled: true,
18102
+ agent: agentIdToHeadroomKind(payload.headroomAgent),
18103
+ ingestUrl: payload.headroomSavingsIngestUrl
18104
+ });
18105
+ log.info("host-agent", "Headroom proxy ready; persisted headroom config for child spawns");
17716
18106
  } else {
18107
+ persistHeadroomConfig({ enabled: false });
17717
18108
  log.warn("host-agent", "Headroom setup failed (best-effort) \u2014 child will run without Headroom");
17718
18109
  }
18110
+ } else if (payload.headroomEnabled === false) {
18111
+ persistHeadroomConfig({ enabled: false });
17719
18112
  }
17720
18113
  report("spawning", "starting agent");
17721
- const proc = this.spawnChild(childEnv, cwd, extraArgs);
17722
- const child = { deployId: payload.deployId, proc };
18114
+ const proc = this.spawnSessionChild(childEnv, cwd, extraArgs);
18115
+ const child = {
18116
+ deployId: payload.deployId,
18117
+ proc,
18118
+ agent: payload.agentId,
18119
+ startedAt: Date.now()
18120
+ };
17723
18121
  this.children.set(payload.deployId, child);
17724
18122
  let tail = "";
17725
18123
  const appendTail = (buf) => {
@@ -17752,6 +18150,20 @@ var HostAgentSupervisor = class {
17752
18150
  report("failed", message);
17753
18151
  }
17754
18152
  }
18153
+ /**
18154
+ * Spawn a supervised `pair-auto` session child, merging the persisted
18155
+ * Headroom env on top of the caller's env. This is the SINGLE spawn site for
18156
+ * session children: the fresh-deploy path and any future resume / restart
18157
+ * path both go through here, so the HEADROOM_* env (read from
18158
+ * `~/.codeam/headroom-config.json`, the source of truth a prior deploy wrote)
18159
+ * is injected on EVERY spawn — reporting survives session resumes and
18160
+ * supervisor restarts (systemd / periodic self-update), not just fresh
18161
+ * deploys. `readHeadroomChildEnv()` returns `{}` when Headroom is disabled or
18162
+ * was never set up, so this is a no-op there (never-break).
18163
+ */
18164
+ spawnSessionChild(env, cwd, args2 = []) {
18165
+ return this.spawnChild({ ...env, ...readHeadroomChildEnv() }, cwd, args2);
18166
+ }
17755
18167
  /**
17756
18168
  * Run the backend-supplied per-agent CLI install script (e.g.
17757
18169
  * `claude.ai/install.sh`, `npm i -g @openai/codex`). Best-effort + bounded:
@@ -17763,8 +18175,8 @@ var HostAgentSupervisor = class {
17763
18175
  */
17764
18176
  runAgentInstall(script) {
17765
18177
  return new Promise((resolve7) => {
17766
- const home = process.env.HOME || os31.homedir();
17767
- const child = (0, import_node_child_process12.spawn)("sh", ["-c", script], {
18178
+ const home = process.env.HOME || os32.homedir();
18179
+ const child = (0, import_node_child_process13.spawn)("sh", ["-c", script], {
17768
18180
  env: { ...process.env, HOME: home },
17769
18181
  stdio: ["ignore", "pipe", "pipe"]
17770
18182
  });
@@ -17888,12 +18300,12 @@ function readTokenFromArgs(args2) {
17888
18300
  }
17889
18301
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
17890
18302
  if (fileFlag) {
17891
- const path58 = fileFlag.slice("--token-file=".length);
18303
+ const path59 = fileFlag.slice("--token-file=".length);
17892
18304
  try {
17893
- const content = fs38.readFileSync(path58, "utf8").trim();
17894
- if (content.length === 0) fail(`--token-file ${path58} is empty`);
18305
+ const content = fs40.readFileSync(path59, "utf8").trim();
18306
+ if (content.length === 0) fail(`--token-file ${path59} is empty`);
17895
18307
  try {
17896
- fs38.unlinkSync(path58);
18308
+ fs40.unlinkSync(path59);
17897
18309
  } catch {
17898
18310
  }
17899
18311
  return content;
@@ -17919,7 +18331,7 @@ async function claimOnce(token, pluginId, pluginSecretHash) {
17919
18331
  pluginId,
17920
18332
  ideName: "codeam-cli (codespace)",
17921
18333
  ideVersion: process.env.npm_package_version ?? "unknown",
17922
- hostname: os32.hostname(),
18334
+ hostname: os33.hostname(),
17923
18335
  codespaceName: process.env.CODESPACE_NAME ?? "",
17924
18336
  // Current git branch of the codespace's working directory, so the
17925
18337
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -17980,7 +18392,7 @@ async function claim(token, pluginId, pluginSecretHash) {
17980
18392
  }
17981
18393
  }
17982
18394
  function pairAutoLockPath() {
17983
- return path44.join(os32.homedir(), ".codeam", "pair-auto.lock");
18395
+ return path46.join(os33.homedir(), ".codeam", "pair-auto.lock");
17984
18396
  }
17985
18397
  function isLivePairAuto(pid) {
17986
18398
  if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
@@ -17990,7 +18402,7 @@ function isLivePairAuto(pid) {
17990
18402
  if (e.code !== "EPERM") return false;
17991
18403
  }
17992
18404
  try {
17993
- return fs38.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
18405
+ return fs40.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
17994
18406
  } catch {
17995
18407
  return true;
17996
18408
  }
@@ -18000,24 +18412,24 @@ function isLiveCodeam(pid) {
18000
18412
  }
18001
18413
  function daemonLockPath(sessionId) {
18002
18414
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
18003
- return path44.join(os32.homedir(), ".codeam", `daemon-${safe}.lock`);
18415
+ return path46.join(os33.homedir(), ".codeam", `daemon-${safe}.lock`);
18004
18416
  }
18005
18417
  function acquireDaemonLock(sessionId) {
18006
18418
  const lockPath = daemonLockPath(sessionId);
18007
18419
  try {
18008
- fs38.mkdirSync(path44.dirname(lockPath), { recursive: true });
18420
+ fs40.mkdirSync(path46.dirname(lockPath), { recursive: true });
18009
18421
  try {
18010
- fs38.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18422
+ fs40.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18011
18423
  } catch (e) {
18012
18424
  if (e.code !== "EEXIST") throw e;
18013
- const holder = Number(fs38.readFileSync(lockPath, "utf8").trim());
18425
+ const holder = Number(fs40.readFileSync(lockPath, "utf8").trim());
18014
18426
  if (holder && holder !== process.pid && isLiveCodeam(holder)) return false;
18015
- fs38.writeFileSync(lockPath, String(process.pid));
18427
+ fs40.writeFileSync(lockPath, String(process.pid));
18016
18428
  }
18017
18429
  const release3 = () => {
18018
18430
  try {
18019
- if (fs38.existsSync(lockPath) && Number(fs38.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18020
- fs38.unlinkSync(lockPath);
18431
+ if (fs40.existsSync(lockPath) && Number(fs40.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18432
+ fs40.unlinkSync(lockPath);
18021
18433
  }
18022
18434
  } catch {
18023
18435
  }
@@ -18039,19 +18451,19 @@ function acquireDaemonLock(sessionId) {
18039
18451
  function acquireSingletonLock() {
18040
18452
  const lockPath = pairAutoLockPath();
18041
18453
  try {
18042
- fs38.mkdirSync(path44.dirname(lockPath), { recursive: true });
18454
+ fs40.mkdirSync(path46.dirname(lockPath), { recursive: true });
18043
18455
  try {
18044
- fs38.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18456
+ fs40.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18045
18457
  } catch (e) {
18046
18458
  if (e.code !== "EEXIST") throw e;
18047
- const holder = Number(fs38.readFileSync(lockPath, "utf8").trim());
18459
+ const holder = Number(fs40.readFileSync(lockPath, "utf8").trim());
18048
18460
  if (isLivePairAuto(holder)) return false;
18049
- fs38.writeFileSync(lockPath, String(process.pid));
18461
+ fs40.writeFileSync(lockPath, String(process.pid));
18050
18462
  }
18051
18463
  process.once("exit", () => {
18052
18464
  try {
18053
- if (fs38.existsSync(lockPath) && Number(fs38.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18054
- fs38.unlinkSync(lockPath);
18465
+ if (fs40.existsSync(lockPath) && Number(fs40.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18466
+ fs40.unlinkSync(lockPath);
18055
18467
  }
18056
18468
  } catch {
18057
18469
  }
@@ -18133,7 +18545,7 @@ async function pairAuto(args2) {
18133
18545
  }
18134
18546
 
18135
18547
  // src/services/headroom/wrap-launch.ts
18136
- var import_node_child_process13 = require("child_process");
18548
+ var import_node_child_process14 = require("child_process");
18137
18549
  function wrapWithHeadroom(launch, opts) {
18138
18550
  if (!opts.enabled || !opts.headroomPresent) return launch;
18139
18551
  return {
@@ -18146,7 +18558,7 @@ var _present;
18146
18558
  function headroomPresent() {
18147
18559
  if (_present !== void 0) return Promise.resolve(_present);
18148
18560
  return new Promise((resolve7) => {
18149
- (0, import_node_child_process13.execFile)("headroom", ["--version"], (err) => {
18561
+ (0, import_node_child_process14.execFile)("headroom", ["--version"], (err) => {
18150
18562
  _present = !err;
18151
18563
  resolve7(_present);
18152
18564
  });
@@ -18496,19 +18908,19 @@ var AgentService = class _AgentService {
18496
18908
  };
18497
18909
 
18498
18910
  // src/agents/acp/adapters.ts
18499
- var path45 = __toESM(require("path"));
18911
+ var path47 = __toESM(require("path"));
18500
18912
  var require_ = require;
18501
18913
  function resolveBin(pkgName, binName) {
18502
18914
  try {
18503
18915
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
18504
18916
  const manifest = require_(`${pkgName}/package.json`);
18505
- const pkgDir = path45.dirname(manifestPath);
18917
+ const pkgDir = path47.dirname(manifestPath);
18506
18918
  const bin = manifest.bin;
18507
18919
  if (!bin) return null;
18508
- if (typeof bin === "string") return path45.resolve(pkgDir, bin);
18920
+ if (typeof bin === "string") return path47.resolve(pkgDir, bin);
18509
18921
  const target = binName ?? Object.keys(bin)[0];
18510
18922
  if (!target || !bin[target]) return null;
18511
- return path45.resolve(pkgDir, bin[target]);
18923
+ return path47.resolve(pkgDir, bin[target]);
18512
18924
  } catch {
18513
18925
  return null;
18514
18926
  }
@@ -18584,11 +18996,11 @@ function requiresAcp(agent) {
18584
18996
  var import_node_crypto7 = require("crypto");
18585
18997
 
18586
18998
  // src/agents/acp/client.ts
18587
- var import_node_child_process14 = require("child_process");
18588
- var fs39 = __toESM(require("fs/promises"));
18999
+ var import_node_child_process15 = require("child_process");
19000
+ var fs41 = __toESM(require("fs/promises"));
18589
19001
  var fsSync = __toESM(require("fs"));
18590
- var os33 = __toESM(require("os"));
18591
- var path46 = __toESM(require("path"));
19002
+ var os34 = __toESM(require("os"));
19003
+ var path48 = __toESM(require("path"));
18592
19004
  var import_node_stream = require("stream");
18593
19005
 
18594
19006
  // ../../node_modules/@agentclientprotocol/sdk/dist/acp.js
@@ -21125,7 +21537,7 @@ var AcpClient = class {
21125
21537
  "acpClient",
21126
21538
  `spawn cmd=${adapter.command} args=[${adapter.args.join(",")}] cwd=${cwd}`
21127
21539
  );
21128
- const child = (0, import_node_child_process14.spawn)(adapter.command, adapter.args, {
21540
+ const child = (0, import_node_child_process15.spawn)(adapter.command, adapter.args, {
21129
21541
  cwd,
21130
21542
  env: { ...process.env, PATH: augmentedPath },
21131
21543
  stdio: ["pipe", "pipe", "pipe"]
@@ -21375,7 +21787,7 @@ var AcpClient = class {
21375
21787
  },
21376
21788
  readTextFile: async (params) => {
21377
21789
  try {
21378
- const content = await fs39.readFile(params.path, "utf8");
21790
+ const content = await fs41.readFile(params.path, "utf8");
21379
21791
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
21380
21792
  } catch (err) {
21381
21793
  const code = err.code;
@@ -21395,7 +21807,7 @@ var AcpClient = class {
21395
21807
  },
21396
21808
  writeTextFile: async (params) => {
21397
21809
  try {
21398
- await fs39.writeFile(params.path, params.content, "utf8");
21810
+ await fs41.writeFile(params.path, params.content, "utf8");
21399
21811
  return {};
21400
21812
  } catch (err) {
21401
21813
  const code = err.code;
@@ -21444,25 +21856,25 @@ function applyLineRange(content, line, limit) {
21444
21856
  return { content: lines.slice(start2, end).join("\n") };
21445
21857
  }
21446
21858
  function knownAgentBinaryDirs() {
21447
- const home = os33.homedir();
21859
+ const home = os34.homedir();
21448
21860
  const out2 = [];
21449
21861
  out2.push("/tmp/codeam-node20/bin");
21450
21862
  for (const root of [
21451
21863
  "/usr/local/share/nvm/versions/node",
21452
- path46.join(home, ".nvm/versions/node")
21864
+ path48.join(home, ".nvm/versions/node")
21453
21865
  ]) {
21454
21866
  try {
21455
21867
  for (const child of fsSync.readdirSync(root)) {
21456
- out2.push(path46.join(root, child, "bin"));
21868
+ out2.push(path48.join(root, child, "bin"));
21457
21869
  }
21458
21870
  } catch {
21459
21871
  }
21460
21872
  }
21461
- out2.push(path46.join(home, ".volta/bin"));
21873
+ out2.push(path48.join(home, ".volta/bin"));
21462
21874
  out2.push("/usr/local/bin");
21463
21875
  out2.push("/usr/bin");
21464
- out2.push(path46.join(home, ".local/bin"));
21465
- out2.push(path46.join(home, "bin"));
21876
+ out2.push(path48.join(home, ".local/bin"));
21877
+ out2.push(path48.join(home, "bin"));
21466
21878
  return out2.filter((p2) => {
21467
21879
  try {
21468
21880
  return fsSync.statSync(p2).isDirectory();
@@ -21473,7 +21885,7 @@ function knownAgentBinaryDirs() {
21473
21885
  }
21474
21886
  function expandPathForAgentBinaries(existingPath) {
21475
21887
  const existing = new Set(
21476
- existingPath.split(path46.delimiter).filter((p2) => p2.length > 0)
21888
+ existingPath.split(path48.delimiter).filter((p2) => p2.length > 0)
21477
21889
  );
21478
21890
  const additions = [];
21479
21891
  for (const dir of knownAgentBinaryDirs()) {
@@ -21483,12 +21895,12 @@ function expandPathForAgentBinaries(existingPath) {
21483
21895
  }
21484
21896
  }
21485
21897
  if (additions.length === 0) return existingPath;
21486
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path46.delimiter);
21898
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path48.delimiter);
21487
21899
  }
21488
21900
 
21489
21901
  // src/services/streaming/transport.ts
21490
21902
  var http6 = __toESM(require("http"));
21491
- var https6 = __toESM(require("https"));
21903
+ var https7 = __toESM(require("https"));
21492
21904
  var _transport4 = {
21493
21905
  post: _post3,
21494
21906
  get: _get
@@ -21497,7 +21909,7 @@ function _post3(url, headers, payload) {
21497
21909
  return new Promise((resolve7, reject) => {
21498
21910
  let settled = false;
21499
21911
  const u2 = new URL(url);
21500
- const lib = u2.protocol === "https:" ? https6 : http6;
21912
+ const lib = u2.protocol === "https:" ? https7 : http6;
21501
21913
  const req = lib.request(
21502
21914
  {
21503
21915
  hostname: u2.hostname,
@@ -21539,7 +21951,7 @@ function _get(url, headers) {
21539
21951
  return new Promise((resolve7, reject) => {
21540
21952
  let settled = false;
21541
21953
  const u2 = new URL(url);
21542
- const lib = u2.protocol === "https:" ? https6 : http6;
21954
+ const lib = u2.protocol === "https:" ? https7 : http6;
21543
21955
  const req = lib.request(
21544
21956
  {
21545
21957
  hostname: u2.hostname,
@@ -21810,15 +22222,15 @@ function reconcileCumulative(existing, incoming) {
21810
22222
  }
21811
22223
 
21812
22224
  // src/agents/acp/onboarding.ts
21813
- var fs40 = __toESM(require("fs"));
21814
- var os34 = __toESM(require("os"));
21815
- var path47 = __toESM(require("path"));
22225
+ var fs42 = __toESM(require("fs"));
22226
+ var os35 = __toESM(require("os"));
22227
+ var path49 = __toESM(require("path"));
21816
22228
  var _onboardingSeam = {
21817
- markerPath: (sessionId) => path47.join(os34.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
21818
- exists: (p2) => fs40.existsSync(p2),
22229
+ markerPath: (sessionId) => path49.join(os35.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
22230
+ exists: (p2) => fs42.existsSync(p2),
21819
22231
  write: (p2) => {
21820
- fs40.mkdirSync(path47.dirname(p2), { recursive: true });
21821
- fs40.writeFileSync(p2, "");
22232
+ fs42.mkdirSync(path49.dirname(p2), { recursive: true });
22233
+ fs42.writeFileSync(p2, "");
21822
22234
  },
21823
22235
  disabled: () => {
21824
22236
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -21826,7 +22238,7 @@ var _onboardingSeam = {
21826
22238
  }
21827
22239
  };
21828
22240
  function buildOnboardingWelcome(cwd) {
21829
- const repo = path47.basename(cwd || "") || "this project";
22241
+ const repo = path49.basename(cwd || "") || "this project";
21830
22242
  return [
21831
22243
  `Welcome to CodeAgent Mobile! \u{1F44B} You're now driving this agent from your phone \u2014 and it comes fully wired, zero setup:`,
21832
22244
  "",
@@ -22086,8 +22498,8 @@ var import_crypto5 = require("crypto");
22086
22498
 
22087
22499
  // src/services/turn-files/git-changeset.ts
22088
22500
  var import_child_process22 = require("child_process");
22089
- var fs41 = __toESM(require("fs/promises"));
22090
- var path48 = __toESM(require("path"));
22501
+ var fs43 = __toESM(require("fs/promises"));
22502
+ var path50 = __toESM(require("path"));
22091
22503
  async function collectRepoChangeset(opts) {
22092
22504
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
22093
22505
  if (status2 === null) return null;
@@ -22105,7 +22517,7 @@ async function collectRepoChangeset(opts) {
22105
22517
  let stats;
22106
22518
  if (row.fileStatus === "added" && numstatEntry === void 0) {
22107
22519
  const lineCount = await readUntrackedLineCount(
22108
- path48.join(opts.repoRoot, row.filePath)
22520
+ path50.join(opts.repoRoot, row.filePath)
22109
22521
  );
22110
22522
  stats = { added: lineCount, removed: 0 };
22111
22523
  } else {
@@ -22136,7 +22548,7 @@ function readUntrackedLineCount(absPath) {
22136
22548
  }
22137
22549
  async function defaultReadUntrackedLineCount(absPath) {
22138
22550
  try {
22139
- const content = await fs41.readFile(absPath, "utf8");
22551
+ const content = await fs43.readFile(absPath, "utf8");
22140
22552
  let count = 0;
22141
22553
  let pos = -1;
22142
22554
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -22228,7 +22640,7 @@ function defaultRunGit(cwd, args2) {
22228
22640
  });
22229
22641
  }
22230
22642
  async function discoverRepos(workingDir, maxDepth = 4) {
22231
- const fs47 = await import("fs/promises");
22643
+ const fs48 = await import("fs/promises");
22232
22644
  const out2 = [];
22233
22645
  await walk(workingDir, 0);
22234
22646
  return out2;
@@ -22236,7 +22648,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
22236
22648
  if (depth > maxDepth) return;
22237
22649
  let entries = [];
22238
22650
  try {
22239
- const dirents = await fs47.readdir(dir, { withFileTypes: true });
22651
+ const dirents = await fs48.readdir(dir, { withFileTypes: true });
22240
22652
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
22241
22653
  } catch {
22242
22654
  return;
@@ -22247,8 +22659,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
22247
22659
  if (hasGit) {
22248
22660
  out2.push({
22249
22661
  repoRoot: dir,
22250
- repoPath: path48.relative(workingDir, dir),
22251
- repoName: path48.basename(dir)
22662
+ repoPath: path50.relative(workingDir, dir),
22663
+ repoName: path50.basename(dir)
22252
22664
  });
22253
22665
  return;
22254
22666
  }
@@ -22256,14 +22668,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
22256
22668
  if (!entry.isDirectory) continue;
22257
22669
  if (entry.name === "node_modules") continue;
22258
22670
  if (entry.name === "dist" || entry.name === "build") continue;
22259
- await walk(path48.join(dir, entry.name), depth + 1);
22671
+ await walk(path50.join(dir, entry.name), depth + 1);
22260
22672
  }
22261
22673
  }
22262
22674
  }
22263
22675
 
22264
22676
  // src/services/turn-files/files-outbox.ts
22265
- var fs42 = __toESM(require("fs/promises"));
22266
- var path49 = __toESM(require("path"));
22677
+ var fs44 = __toESM(require("fs/promises"));
22678
+ var path51 = __toESM(require("path"));
22267
22679
  var import_os7 = require("os");
22268
22680
  var HOME_OUTBOX_DIR = ".codeam/outbox";
22269
22681
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -22296,16 +22708,16 @@ var FilesOutbox = class {
22296
22708
  backoffIndex = 0;
22297
22709
  stopped = false;
22298
22710
  constructor(opts) {
22299
- const base = opts.baseDir ?? path49.join(homeDir(), HOME_OUTBOX_DIR);
22300
- this.filePath = path49.join(base, `${opts.sessionId}.jsonl`);
22711
+ const base = opts.baseDir ?? path51.join(homeDir(), HOME_OUTBOX_DIR);
22712
+ this.filePath = path51.join(base, `${opts.sessionId}.jsonl`);
22301
22713
  this.post = opts.post;
22302
22714
  this.autoSchedule = opts.autoSchedule !== false;
22303
22715
  }
22304
22716
  /** Persist the entry to disk and trigger a flush. Returns once the
22305
22717
  * line is durable on disk (not once the POST succeeds). */
22306
22718
  async enqueue(entry) {
22307
- await fs42.mkdir(path49.dirname(this.filePath), { recursive: true });
22308
- await fs42.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
22719
+ await fs44.mkdir(path51.dirname(this.filePath), { recursive: true });
22720
+ await fs44.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
22309
22721
  this.backoffIndex = 0;
22310
22722
  if (this.autoSchedule) this.scheduleFlush(0);
22311
22723
  }
@@ -22394,7 +22806,7 @@ var FilesOutbox = class {
22394
22806
  async readAll() {
22395
22807
  let raw = "";
22396
22808
  try {
22397
- raw = await fs42.readFile(this.filePath, "utf8");
22809
+ raw = await fs44.readFile(this.filePath, "utf8");
22398
22810
  } catch {
22399
22811
  return [];
22400
22812
  }
@@ -22418,12 +22830,12 @@ var FilesOutbox = class {
22418
22830
  async rewrite(entries) {
22419
22831
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
22420
22832
  if (entries.length === 0) {
22421
- await fs42.unlink(this.filePath).catch(() => void 0);
22833
+ await fs44.unlink(this.filePath).catch(() => void 0);
22422
22834
  return;
22423
22835
  }
22424
22836
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
22425
- await fs42.writeFile(tmpPath, payload, "utf8");
22426
- await fs42.rename(tmpPath, this.filePath);
22837
+ await fs44.writeFile(tmpPath, payload, "utf8");
22838
+ await fs44.rename(tmpPath, this.filePath);
22427
22839
  }
22428
22840
  };
22429
22841
  function applyJitter(ms) {
@@ -24154,10 +24566,10 @@ var OutputService = class _OutputService {
24154
24566
  };
24155
24567
 
24156
24568
  // src/services/history.service.ts
24157
- var fs43 = __toESM(require("fs"));
24158
- var path50 = __toESM(require("path"));
24159
- var os35 = __toESM(require("os"));
24160
- var https7 = __toESM(require("https"));
24569
+ var fs45 = __toESM(require("fs"));
24570
+ var path52 = __toESM(require("path"));
24571
+ var os36 = __toESM(require("os"));
24572
+ var https8 = __toESM(require("https"));
24161
24573
  var http7 = __toESM(require("http"));
24162
24574
  var import_zod2 = require("zod");
24163
24575
  var historyRecordSchema = import_zod2.z.object({
@@ -24183,7 +24595,7 @@ function parseJsonl(filePath) {
24183
24595
  const messages = [];
24184
24596
  let raw;
24185
24597
  try {
24186
- raw = fs43.readFileSync(filePath, "utf8");
24598
+ raw = fs45.readFileSync(filePath, "utf8");
24187
24599
  } catch (err) {
24188
24600
  if (err.code !== "ENOENT") {
24189
24601
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -24223,7 +24635,7 @@ function post(endpoint, body, pluginAuthToken) {
24223
24635
  return new Promise((resolve7) => {
24224
24636
  const payload = JSON.stringify(body);
24225
24637
  const u2 = new URL(`${API_BASE9}${endpoint}`);
24226
- const transport = u2.protocol === "https:" ? https7 : http7;
24638
+ const transport = u2.protocol === "https:" ? https8 : http7;
24227
24639
  const req = transport.request(
24228
24640
  {
24229
24641
  hostname: u2.hostname,
@@ -24324,7 +24736,7 @@ var HistoryService = class _HistoryService {
24324
24736
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
24325
24737
  }
24326
24738
  get projectDir() {
24327
- return this.runtime.resolveHistoryDir(this.cwd) ?? path50.join(os35.homedir(), ".claude", "projects", encodeCwd(this.cwd));
24739
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path52.join(os36.homedir(), ".claude", "projects", encodeCwd(this.cwd));
24328
24740
  }
24329
24741
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
24330
24742
  setCurrentConversationId(id) {
@@ -24336,7 +24748,7 @@ var HistoryService = class _HistoryService {
24336
24748
  /** Return the current message count in the active conversation. */
24337
24749
  getCurrentMessageCount() {
24338
24750
  if (!this.currentConversationId) return 0;
24339
- const filePath = path50.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24751
+ const filePath = path52.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24340
24752
  return parseJsonl(filePath).length;
24341
24753
  }
24342
24754
  /**
@@ -24347,7 +24759,7 @@ var HistoryService = class _HistoryService {
24347
24759
  const deadline = Date.now() + timeoutMs;
24348
24760
  while (Date.now() < deadline) {
24349
24761
  if (!this.currentConversationId) return null;
24350
- const filePath = path50.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24762
+ const filePath = path52.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24351
24763
  const messages = parseJsonl(filePath);
24352
24764
  if (messages.length > previousCount) {
24353
24765
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -24373,16 +24785,16 @@ var HistoryService = class _HistoryService {
24373
24785
  const dir = this.projectDir;
24374
24786
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
24375
24787
  try {
24376
- const files = fs43.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
24788
+ const files = fs45.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
24377
24789
  try {
24378
- const stat3 = fs43.statSync(path50.join(dir, e.name));
24790
+ const stat3 = fs45.statSync(path52.join(dir, e.name));
24379
24791
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
24380
24792
  } catch {
24381
24793
  return { name: e.name, mtime: 0, birthtime: 0 };
24382
24794
  }
24383
24795
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
24384
24796
  if (files.length > 0) {
24385
- this.currentConversationId = path50.basename(files[0].name, ".jsonl");
24797
+ this.currentConversationId = path52.basename(files[0].name, ".jsonl");
24386
24798
  }
24387
24799
  } catch {
24388
24800
  }
@@ -24416,13 +24828,13 @@ var HistoryService = class _HistoryService {
24416
24828
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
24417
24829
  let entries;
24418
24830
  try {
24419
- entries = fs43.readdirSync(dir, { withFileTypes: true });
24831
+ entries = fs45.readdirSync(dir, { withFileTypes: true });
24420
24832
  } catch {
24421
24833
  return null;
24422
24834
  }
24423
24835
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
24424
24836
  try {
24425
- const stat3 = fs43.statSync(path50.join(dir, e.name));
24837
+ const stat3 = fs45.statSync(path52.join(dir, e.name));
24426
24838
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
24427
24839
  } catch {
24428
24840
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -24431,12 +24843,12 @@ var HistoryService = class _HistoryService {
24431
24843
  if (files.length === 0) return null;
24432
24844
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
24433
24845
  if (!files.some((f) => f.name === targetFile)) return null;
24434
- return this.extractUsageFromFile(path50.join(dir, targetFile));
24846
+ return this.extractUsageFromFile(path52.join(dir, targetFile));
24435
24847
  }
24436
24848
  extractUsageFromFile(filePath) {
24437
24849
  let raw;
24438
24850
  try {
24439
- raw = fs43.readFileSync(filePath, "utf8");
24851
+ raw = fs45.readFileSync(filePath, "utf8");
24440
24852
  } catch {
24441
24853
  return null;
24442
24854
  }
@@ -24481,9 +24893,9 @@ var HistoryService = class _HistoryService {
24481
24893
  let totalCost = 0;
24482
24894
  let files;
24483
24895
  try {
24484
- files = fs43.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
24896
+ files = fs45.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
24485
24897
  try {
24486
- return fs43.statSync(path50.join(projectDir, f)).mtimeMs >= monthStartMs;
24898
+ return fs45.statSync(path52.join(projectDir, f)).mtimeMs >= monthStartMs;
24487
24899
  } catch {
24488
24900
  return false;
24489
24901
  }
@@ -24494,7 +24906,7 @@ var HistoryService = class _HistoryService {
24494
24906
  for (const file of files) {
24495
24907
  let raw;
24496
24908
  try {
24497
- raw = fs43.readFileSync(path50.join(projectDir, file), "utf8");
24909
+ raw = fs45.readFileSync(path52.join(projectDir, file), "utf8");
24498
24910
  } catch {
24499
24911
  continue;
24500
24912
  }
@@ -24562,7 +24974,7 @@ var HistoryService = class _HistoryService {
24562
24974
  * showing an empty conversation.
24563
24975
  */
24564
24976
  async loadConversation(sessionId) {
24565
- const filePath = path50.join(this.projectDir, `${sessionId}.jsonl`);
24977
+ const filePath = path52.join(this.projectDir, `${sessionId}.jsonl`);
24566
24978
  const messages = parseJsonl(filePath);
24567
24979
  if (messages.length === 0) return;
24568
24980
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -24616,7 +25028,7 @@ var HistoryService = class _HistoryService {
24616
25028
  if (!this.currentConversationId) return 0;
24617
25029
  }
24618
25030
  const sessionId = this.currentConversationId;
24619
- const filePath = path50.join(this.projectDir, `${sessionId}.jsonl`);
25031
+ const filePath = path52.join(this.projectDir, `${sessionId}.jsonl`);
24620
25032
  const messages = parseJsonl(filePath);
24621
25033
  if (messages.length === 0) return 0;
24622
25034
  const marker = this.lastUploadedUuid.get(sessionId);
@@ -25042,15 +25454,15 @@ function fetchQuotaUsage(runtime, historySvc) {
25042
25454
  }
25043
25455
 
25044
25456
  // src/agents/claude/onboarding.ts
25045
- var fs44 = __toESM(require("fs"));
25046
- var os36 = __toESM(require("os"));
25047
- var path51 = __toESM(require("path"));
25457
+ var fs46 = __toESM(require("fs"));
25458
+ var os37 = __toESM(require("os"));
25459
+ var path53 = __toESM(require("path"));
25048
25460
  function ensureClaudeOnboarded() {
25049
25461
  try {
25050
- const file = path51.join(os36.homedir(), ".claude.json");
25462
+ const file = path53.join(os37.homedir(), ".claude.json");
25051
25463
  let config = {};
25052
25464
  try {
25053
- config = JSON.parse(fs44.readFileSync(file, "utf8"));
25465
+ config = JSON.parse(fs46.readFileSync(file, "utf8"));
25054
25466
  } catch {
25055
25467
  }
25056
25468
  if (config.hasCompletedOnboarding === true && typeof config.theme === "string") {
@@ -25061,8 +25473,8 @@ function ensureClaudeOnboarded() {
25061
25473
  if (typeof config.lastOnboardingVersion !== "string") {
25062
25474
  config.lastOnboardingVersion = "2.1.177";
25063
25475
  }
25064
- fs44.mkdirSync(path51.dirname(file), { recursive: true });
25065
- fs44.writeFileSync(file, JSON.stringify(config, null, 2));
25476
+ fs46.mkdirSync(path53.dirname(file), { recursive: true });
25477
+ fs46.writeFileSync(file, JSON.stringify(config, null, 2));
25066
25478
  log.info("claude", "pre-completed Claude onboarding (skip first-run theme picker)");
25067
25479
  } catch (err) {
25068
25480
  log.warn("claude", `ensureClaudeOnboarded failed (non-fatal): ${err.message}`);
@@ -25076,27 +25488,27 @@ async function start(requestedAgent) {
25076
25488
  if (!session) {
25077
25489
  if (requestedAgent) {
25078
25490
  const displayName = AGENT_REGISTRY[requestedAgent]?.displayName ?? requestedAgent;
25079
- console.log(` ${import_picocolors3.default.dim(`No paired ${displayName} session found.`)}`);
25491
+ console.log(` ${import_picocolors4.default.dim(`No paired ${displayName} session found.`)}`);
25080
25492
  console.log(
25081
- ` ${import_picocolors3.default.dim(`Run ${import_picocolors3.default.white("codeam pair")} from a ${displayName} setup to connect your mobile app.`)}
25493
+ ` ${import_picocolors4.default.dim(`Run ${import_picocolors4.default.white("codeam pair")} from a ${displayName} setup to connect your mobile app.`)}
25082
25494
  `
25083
25495
  );
25084
25496
  } else {
25085
- console.log(` ${import_picocolors3.default.dim("No paired session found.")}`);
25086
- console.log(` ${import_picocolors3.default.dim(`Run ${import_picocolors3.default.white("codeam pair")} to connect your mobile app.`)}
25497
+ console.log(` ${import_picocolors4.default.dim("No paired session found.")}`);
25498
+ console.log(` ${import_picocolors4.default.dim(`Run ${import_picocolors4.default.white("codeam pair")} to connect your mobile app.`)}
25087
25499
  `);
25088
25500
  }
25089
25501
  process.exit(0);
25090
25502
  }
25091
25503
  if (!acquireDaemonLock(session.id)) {
25092
- console.log(` ${import_picocolors3.default.dim("A codeam daemon for this session is already running \u2014 deferring to it.")}`);
25504
+ console.log(` ${import_picocolors4.default.dim("A codeam daemon for this session is already running \u2014 deferring to it.")}`);
25093
25505
  process.exit(0);
25094
25506
  }
25095
25507
  if (!session.agent) {
25096
25508
  throw new Error("Active session has no agent \u2014 re-pair with `codeam pair`.");
25097
25509
  }
25098
25510
  const pluginId = session.pluginId ?? ensurePluginId();
25099
- showInfo(`${session.userName} \xB7 ${import_picocolors3.default.cyan(session.plan)}`);
25511
+ showInfo(`${session.userName} \xB7 ${import_picocolors4.default.cyan(session.plan)}`);
25100
25512
  showInfo(`Launching ${AGENT_REGISTRY[session.agent].displayName}...
25101
25513
  `);
25102
25514
  identifyUser({
@@ -25370,7 +25782,7 @@ async function start(requestedAgent) {
25370
25782
 
25371
25783
  // src/commands/pair.ts
25372
25784
  var import_crypto7 = require("crypto");
25373
- var import_picocolors4 = __toESM(require("picocolors"));
25785
+ var import_picocolors5 = __toESM(require("picocolors"));
25374
25786
 
25375
25787
  // src/utils/agent-prompt.ts
25376
25788
  function parseAgentFlag(args2) {
@@ -25451,7 +25863,7 @@ async function pair(args2 = []) {
25451
25863
  process.exit(0);
25452
25864
  }
25453
25865
  showPairingCode(result.code);
25454
- console.log(import_picocolors4.default.dim(" Scan the QR code or enter the code in CodeAgent Mobile."));
25866
+ console.log(import_picocolors5.default.dim(" Scan the QR code or enter the code in CodeAgent Mobile."));
25455
25867
  console.log("");
25456
25868
  const waitSpin = dist_exports.spinner();
25457
25869
  const waitMessage = () => `Waiting for mobile app... \xB7 expires in ${formatRemaining(result.expiresAt)}`;
@@ -25566,7 +25978,7 @@ async function autoLinkAfterPair(opts) {
25566
25978
  }
25567
25979
 
25568
25980
  // src/commands/sessions.ts
25569
- var import_picocolors5 = __toESM(require("picocolors"));
25981
+ var import_picocolors6 = __toESM(require("picocolors"));
25570
25982
  async function sessions2(args2) {
25571
25983
  const [sub, id] = args2;
25572
25984
  if (sub === "switch") return switchSession();
@@ -25583,18 +25995,18 @@ function listSessions() {
25583
25995
  showIntro();
25584
25996
  const config = getConfig();
25585
25997
  if (config.sessions.length === 0) {
25586
- console.log(import_picocolors5.default.dim(" No paired sessions. Run codeam pair to connect.\n"));
25998
+ console.log(import_picocolors6.default.dim(" No paired sessions. Run codeam pair to connect.\n"));
25587
25999
  return;
25588
26000
  }
25589
- console.log(import_picocolors5.default.bold(" Paired sessions:\n"));
26001
+ console.log(import_picocolors6.default.bold(" Paired sessions:\n"));
25590
26002
  for (const s of config.sessions) {
25591
26003
  const isActive = s.id === config.activeSessionId;
25592
- const bullet = isActive ? import_picocolors5.default.green(" \u25CF") : import_picocolors5.default.dim(" \u25CB");
25593
- const name = isActive ? import_picocolors5.default.bold(s.userName) : s.userName;
25594
- const plan = import_picocolors5.default.cyan(s.plan);
25595
- const date = import_picocolors5.default.dim(new Date(s.pairedAt).toLocaleDateString());
26004
+ const bullet = isActive ? import_picocolors6.default.green(" \u25CF") : import_picocolors6.default.dim(" \u25CB");
26005
+ const name = isActive ? import_picocolors6.default.bold(s.userName) : s.userName;
26006
+ const plan = import_picocolors6.default.cyan(s.plan);
26007
+ const date = import_picocolors6.default.dim(new Date(s.pairedAt).toLocaleDateString());
25596
26008
  console.log(`${bullet} ${name} ${plan} ${date}`);
25597
- console.log(import_picocolors5.default.dim(` ${s.id}`));
26009
+ console.log(import_picocolors6.default.dim(` ${s.id}`));
25598
26010
  }
25599
26011
  console.log("");
25600
26012
  }
@@ -25612,7 +26024,7 @@ async function switchSession() {
25612
26024
  }
25613
26025
  setActiveSession(chosen);
25614
26026
  const s = config.sessions.find((x) => x.id === chosen);
25615
- console.log(import_picocolors5.default.green(`
26027
+ console.log(import_picocolors6.default.green(`
25616
26028
  \u2713 Switched to ${s?.userName ?? chosen}
25617
26029
  `));
25618
26030
  }
@@ -25630,29 +26042,29 @@ async function deleteSession(id) {
25630
26042
  return;
25631
26043
  }
25632
26044
  removeSession(id);
25633
- console.log(import_picocolors5.default.green("\n \u2713 Session deleted\n"));
26045
+ console.log(import_picocolors6.default.green("\n \u2713 Session deleted\n"));
25634
26046
  }
25635
26047
 
25636
26048
  // src/commands/status.ts
25637
- var import_picocolors6 = __toESM(require("picocolors"));
26049
+ var import_picocolors7 = __toESM(require("picocolors"));
25638
26050
  function status() {
25639
26051
  showIntro();
25640
26052
  const config = getConfig();
25641
26053
  const active = config.sessions.find((s) => s.id === config.activeSessionId) ?? null;
25642
- console.log(import_picocolors6.default.bold(" Status\n"));
25643
- console.log(` Plugin ID ${import_picocolors6.default.dim(config.pluginId || "not generated yet")}`);
26054
+ console.log(import_picocolors7.default.bold(" Status\n"));
26055
+ console.log(` Plugin ID ${import_picocolors7.default.dim(config.pluginId || "not generated yet")}`);
25644
26056
  console.log(` Sessions ${config.sessions.length} paired`);
25645
26057
  if (active) {
25646
- console.log(` Active ${import_picocolors6.default.bold(active.userName)} ${import_picocolors6.default.cyan(active.plan)}`);
25647
- console.log(` Session ID ${import_picocolors6.default.dim(active.id)}`);
26058
+ console.log(` Active ${import_picocolors7.default.bold(active.userName)} ${import_picocolors7.default.cyan(active.plan)}`);
26059
+ console.log(` Session ID ${import_picocolors7.default.dim(active.id)}`);
25648
26060
  } else {
25649
- console.log(` Active ${import_picocolors6.default.yellow("none")} ${import_picocolors6.default.dim("run codeam pair to connect")}`);
26061
+ console.log(` Active ${import_picocolors7.default.yellow("none")} ${import_picocolors7.default.dim("run codeam pair to connect")}`);
25650
26062
  }
25651
26063
  console.log("");
25652
26064
  }
25653
26065
 
25654
26066
  // src/commands/logout.ts
25655
- var import_picocolors7 = __toESM(require("picocolors"));
26067
+ var import_picocolors8 = __toESM(require("picocolors"));
25656
26068
  var API_BASE11 = resolveApiBaseUrl();
25657
26069
  async function notifyBackendOffline() {
25658
26070
  const cfg = loadCliConfig();
@@ -25686,17 +26098,17 @@ async function logout() {
25686
26098
  }
25687
26099
  await notifyBackendOffline();
25688
26100
  clearAll();
25689
- console.log(import_picocolors7.default.green("\n \u2713 Done. All sessions removed.\n"));
26101
+ console.log(import_picocolors8.default.green("\n \u2713 Done. All sessions removed.\n"));
25690
26102
  }
25691
26103
 
25692
26104
  // src/commands/deploy.ts
25693
- var import_picocolors10 = __toESM(require("picocolors"));
26105
+ var import_picocolors11 = __toESM(require("picocolors"));
25694
26106
 
25695
26107
  // src/services/providers/github-codespaces.ts
25696
26108
  var import_child_process23 = require("child_process");
25697
26109
  var import_util4 = require("util");
25698
- var import_picocolors8 = __toESM(require("picocolors"));
25699
- var path52 = __toESM(require("path"));
26110
+ var import_picocolors9 = __toESM(require("picocolors"));
26111
+ var path54 = __toESM(require("path"));
25700
26112
  var execFileP6 = (0, import_util4.promisify)(import_child_process23.execFile);
25701
26113
  var MAX_BUFFER = 8 * 1024 * 1024;
25702
26114
  function resetStdinForChild() {
@@ -25763,7 +26175,7 @@ var GitHubCodespacesProvider = class {
25763
26175
  if (expectedUser) {
25764
26176
  noteLines.push("");
25765
26177
  noteLines.push(
25766
- `${import_picocolors8.default.yellow("\u26A0")} Sign in as ${import_picocolors8.default.cyan(expectedUser)} in the browser.`
26178
+ `${import_picocolors9.default.yellow("\u26A0")} Sign in as ${import_picocolors9.default.cyan(expectedUser)} in the browser.`
25767
26179
  );
25768
26180
  noteLines.push(
25769
26181
  " If a different GitHub account is already signed in, sign out"
@@ -25786,7 +26198,7 @@ var GitHubCodespacesProvider = class {
25786
26198
  if (refreshCode !== 0) {
25787
26199
  const lines = [
25788
26200
  "The browser approval came back for a different GitHub account",
25789
- `than the one gh is configured for${expectedUser ? ` (${import_picocolors8.default.cyan(expectedUser)})` : ""}.`,
26201
+ `than the one gh is configured for${expectedUser ? ` (${import_picocolors9.default.cyan(expectedUser)})` : ""}.`,
25790
26202
  "",
25791
26203
  "To recover:",
25792
26204
  " 1. Open https://github.com and sign out of any non-target",
@@ -25795,7 +26207,7 @@ var GitHubCodespacesProvider = class {
25795
26207
  "",
25796
26208
  "You can also grant the scope manually first and skip this step",
25797
26209
  "on the next run:",
25798
- ` ${import_picocolors8.default.cyan("gh auth refresh -h github.com -s codespace")}`
26210
+ ` ${import_picocolors9.default.cyan("gh auth refresh -h github.com -s codespace")}`
25799
26211
  ];
25800
26212
  throw new Error(lines.join("\n"));
25801
26213
  }
@@ -25862,7 +26274,7 @@ var GitHubCodespacesProvider = class {
25862
26274
  async tryInstallGh() {
25863
26275
  const platform3 = process.platform;
25864
26276
  wt(
25865
- `GitHub CLI (${import_picocolors8.default.cyan("gh")}) is required for Codespaces deploys but isn't on your PATH.`,
26277
+ `GitHub CLI (${import_picocolors9.default.cyan("gh")}) is required for Codespaces deploys but isn't on your PATH.`,
25866
26278
  "Heads up"
25867
26279
  );
25868
26280
  if (platform3 === "linux") {
@@ -25918,7 +26330,7 @@ var GitHubCodespacesProvider = class {
25918
26330
  return;
25919
26331
  }
25920
26332
  const proceed = await ot2({
25921
- message: `Run ${import_picocolors8.default.cyan(installCmd.describe)} now?`,
26333
+ message: `Run ${import_picocolors9.default.cyan(installCmd.describe)} now?`,
25922
26334
  initialValue: true
25923
26335
  });
25924
26336
  if (q(proceed) || !proceed) return;
@@ -26185,7 +26597,7 @@ var GitHubCodespacesProvider = class {
26185
26597
  });
26186
26598
  }
26187
26599
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
26188
- const remoteDir = path52.posix.dirname(remotePath);
26600
+ const remoteDir = path54.posix.dirname(remotePath);
26189
26601
  const parts = [
26190
26602
  `mkdir -p ${shellQuote(remoteDir)}`,
26191
26603
  `cat > ${shellQuote(remotePath)}`
@@ -26255,8 +26667,8 @@ function shellQuote(s) {
26255
26667
  // src/services/providers/gitpod.ts
26256
26668
  var import_child_process24 = require("child_process");
26257
26669
  var import_util5 = require("util");
26258
- var path53 = __toESM(require("path"));
26259
- var import_picocolors9 = __toESM(require("picocolors"));
26670
+ var path55 = __toESM(require("path"));
26671
+ var import_picocolors10 = __toESM(require("picocolors"));
26260
26672
  var execFileP7 = (0, import_util5.promisify)(import_child_process24.execFile);
26261
26673
  var MAX_BUFFER2 = 8 * 1024 * 1024;
26262
26674
  function resetStdinForChild2() {
@@ -26495,7 +26907,7 @@ var GitpodProvider = class {
26495
26907
  });
26496
26908
  }
26497
26909
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
26498
- const remoteDir = path53.posix.dirname(remotePath);
26910
+ const remoteDir = path55.posix.dirname(remotePath);
26499
26911
  const parts = [
26500
26912
  `mkdir -p ${shellQuote2(remoteDir)}`,
26501
26913
  `cat > ${shellQuote2(remotePath)}`
@@ -26531,7 +26943,7 @@ function shellQuote2(s) {
26531
26943
  // src/services/providers/gitlab-workspaces.ts
26532
26944
  var import_child_process25 = require("child_process");
26533
26945
  var import_util6 = require("util");
26534
- var path54 = __toESM(require("path"));
26946
+ var path56 = __toESM(require("path"));
26535
26947
  var execFileP8 = (0, import_util6.promisify)(import_child_process25.execFile);
26536
26948
  var MAX_BUFFER3 = 8 * 1024 * 1024;
26537
26949
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -26791,7 +27203,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
26791
27203
  }
26792
27204
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
26793
27205
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
26794
- const remoteDir = path54.posix.dirname(remotePath);
27206
+ const remoteDir = path56.posix.dirname(remotePath);
26795
27207
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
26796
27208
  if (options.mode != null) {
26797
27209
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -26859,7 +27271,7 @@ function shellQuote3(s) {
26859
27271
  // src/services/providers/railway.ts
26860
27272
  var import_child_process26 = require("child_process");
26861
27273
  var import_util7 = require("util");
26862
- var path55 = __toESM(require("path"));
27274
+ var path57 = __toESM(require("path"));
26863
27275
  var execFileP9 = (0, import_util7.promisify)(import_child_process26.execFile);
26864
27276
  var MAX_BUFFER4 = 8 * 1024 * 1024;
26865
27277
  function resetStdinForChild4() {
@@ -27095,7 +27507,7 @@ var RailwayProvider = class {
27095
27507
  if (!projectId || !serviceId) {
27096
27508
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
27097
27509
  }
27098
- const remoteDir = path55.posix.dirname(remotePath);
27510
+ const remoteDir = path57.posix.dirname(remotePath);
27099
27511
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
27100
27512
  if (options.mode != null) {
27101
27513
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -27136,7 +27548,7 @@ var PROVIDERS = [
27136
27548
  // src/commands/deploy.ts
27137
27549
  async function deploy(args2 = []) {
27138
27550
  console.log();
27139
- mt(import_picocolors10.default.bgMagenta(import_picocolors10.default.white(" codeam deploy ")));
27551
+ mt(import_picocolors11.default.bgMagenta(import_picocolors11.default.white(" codeam deploy ")));
27140
27552
  const provider = await pickProvider();
27141
27553
  if (!provider) {
27142
27554
  pt("No provider selected.");
@@ -27173,7 +27585,7 @@ async function deploy(args2 = []) {
27173
27585
  if (provider.expandListScopes) {
27174
27586
  options.push({
27175
27587
  value: EXPAND_SCOPES,
27176
- label: import_picocolors10.default.cyan("+ Don't see your project? Expand scopes\u2026"),
27588
+ label: import_picocolors11.default.cyan("+ Don't see your project? Expand scopes\u2026"),
27177
27589
  hint: "Re-authorize with broader scopes (org / team repos)"
27178
27590
  });
27179
27591
  }
@@ -27221,7 +27633,7 @@ async function deploy(args2 = []) {
27221
27633
  label: w3.displayName ?? w3.id,
27222
27634
  hint: [w3.state, formatLastUsed(w3.lastUsedAt)].filter(Boolean).join(" \xB7 ")
27223
27635
  })),
27224
- { value: "__new__", label: import_picocolors10.default.green("+ Create a new workspace"), hint: "fresh codespace" }
27636
+ { value: "__new__", label: import_picocolors11.default.green("+ Create a new workspace"), hint: "fresh codespace" }
27225
27637
  ]
27226
27638
  });
27227
27639
  if (q(choice)) {
@@ -27322,12 +27734,12 @@ async function deploy(args2 = []) {
27322
27734
  cliStep.stop("\u2713 codeam-cli installed");
27323
27735
  wt(
27324
27736
  [
27325
- `Workspace: ${import_picocolors10.default.cyan(workspace.displayName ?? workspace.id)}`,
27326
- workspace.webUrl ? `Web: ${import_picocolors10.default.cyan(workspace.webUrl)}` : "",
27737
+ `Workspace: ${import_picocolors11.default.cyan(workspace.displayName ?? workspace.id)}`,
27738
+ workspace.webUrl ? `Web: ${import_picocolors11.default.cyan(workspace.webUrl)}` : "",
27327
27739
  "",
27328
27740
  `Starting \`codeam pair\` on the workspace (agent: ${AGENT_REGISTRY[agentId].displayName}).`,
27329
27741
  "Scan the QR code from your phone to pair.",
27330
- import_picocolors10.default.dim("(Once paired, this terminal disconnects automatically; the session stays alive on the codespace.)")
27742
+ import_picocolors11.default.dim("(Once paired, this terminal disconnects automatically; the session stays alive on the codespace.)")
27331
27743
  ].filter(Boolean).join("\n"),
27332
27744
  "Almost there"
27333
27745
  );
@@ -27442,11 +27854,11 @@ async function deploy(args2 = []) {
27442
27854
  ].join("\n");
27443
27855
  const code = (await provider.streamCommand(workspace.id, `bash -lc ${shellQuoteSingle(wrapper)}`)).code;
27444
27856
  if (code === 0) {
27445
- gt(import_picocolors10.default.green("\u2713 Workspace deployed and paired. Drive from your phone, anywhere."));
27857
+ gt(import_picocolors11.default.green("\u2713 Workspace deployed and paired. Drive from your phone, anywhere."));
27446
27858
  } else if (code === 130) {
27447
- gt(import_picocolors10.default.yellow("Disconnected from local terminal. Mobile session keeps running on the codespace."));
27859
+ gt(import_picocolors11.default.yellow("Disconnected from local terminal. Mobile session keeps running on the codespace."));
27448
27860
  } else {
27449
- gt(import_picocolors10.default.yellow('Pairing did not complete. Run "codeam pair" inside the codespace if needed.'));
27861
+ gt(import_picocolors11.default.yellow('Pairing did not complete. Run "codeam pair" inside the codespace if needed.'));
27450
27862
  }
27451
27863
  }
27452
27864
  function shellQuoteSingle(s) {
@@ -27480,7 +27892,7 @@ async function pickProvider() {
27480
27892
  message: "Where do you want to deploy?",
27481
27893
  options: PROVIDERS.map((prov) => ({
27482
27894
  value: prov.id,
27483
- label: prov.available ? prov.displayName : `${prov.displayName} ${import_picocolors10.default.dim("(coming soon)")}`,
27895
+ label: prov.available ? prov.displayName : `${prov.displayName} ${import_picocolors11.default.dim("(coming soon)")}`,
27484
27896
  hint: prov.tagline
27485
27897
  }))
27486
27898
  });
@@ -27497,27 +27909,27 @@ async function pickProvider() {
27497
27909
  }
27498
27910
 
27499
27911
  // src/commands/deploy-manage.ts
27500
- var import_picocolors11 = __toESM(require("picocolors"));
27912
+ var import_picocolors12 = __toESM(require("picocolors"));
27501
27913
  async function deployList() {
27502
27914
  console.log();
27503
- mt(import_picocolors11.default.bgMagenta(import_picocolors11.default.white(" codeam deploy ls ")));
27915
+ mt(import_picocolors12.default.bgMagenta(import_picocolors12.default.white(" codeam deploy ls ")));
27504
27916
  const workspaces = await collectWorkspacesWithStatus();
27505
27917
  if (workspaces.length === 0) {
27506
- gt(import_picocolors11.default.dim("No deployed workspaces found."));
27918
+ gt(import_picocolors12.default.dim("No deployed workspaces found."));
27507
27919
  return;
27508
27920
  }
27509
27921
  for (const w3 of workspaces) {
27510
- const tag = w3.codeamRunning ? import_picocolors11.default.green("\u25CF running") : w3.state === "Available" ? import_picocolors11.default.dim("\u25CB idle") : import_picocolors11.default.dim(`\u25CB ${w3.state ?? "stopped"}`);
27511
- console.log(` ${tag} ${import_picocolors11.default.cyan(w3.displayName ?? w3.id)} ${import_picocolors11.default.dim("(" + w3.providerName + ")")}`);
27922
+ const tag = w3.codeamRunning ? import_picocolors12.default.green("\u25CF running") : w3.state === "Available" ? import_picocolors12.default.dim("\u25CB idle") : import_picocolors12.default.dim(`\u25CB ${w3.state ?? "stopped"}`);
27923
+ console.log(` ${tag} ${import_picocolors12.default.cyan(w3.displayName ?? w3.id)} ${import_picocolors12.default.dim("(" + w3.providerName + ")")}`);
27512
27924
  }
27513
- gt(import_picocolors11.default.dim("Use `codeam deploy stop` to terminate a session."));
27925
+ gt(import_picocolors12.default.dim("Use `codeam deploy stop` to terminate a session."));
27514
27926
  }
27515
27927
  async function deployStop() {
27516
27928
  console.log();
27517
- mt(import_picocolors11.default.bgMagenta(import_picocolors11.default.white(" codeam deploy stop ")));
27929
+ mt(import_picocolors12.default.bgMagenta(import_picocolors12.default.white(" codeam deploy stop ")));
27518
27930
  const workspaces = await collectWorkspacesWithStatus();
27519
27931
  if (workspaces.length === 0) {
27520
- gt(import_picocolors11.default.dim("No deployed workspaces found."));
27932
+ gt(import_picocolors12.default.dim("No deployed workspaces found."));
27521
27933
  return;
27522
27934
  }
27523
27935
  const choice = await _t({
@@ -27527,7 +27939,7 @@ async function deployStop() {
27527
27939
  label: w3.displayName ?? w3.id,
27528
27940
  hint: [
27529
27941
  w3.providerName,
27530
- w3.codeamRunning ? import_picocolors11.default.green("\u25CF codeam-pair running") : import_picocolors11.default.dim("\u25CB no codeam-pair"),
27942
+ w3.codeamRunning ? import_picocolors12.default.green("\u25CF codeam-pair running") : import_picocolors12.default.dim("\u25CB no codeam-pair"),
27531
27943
  w3.state ?? ""
27532
27944
  ].filter(Boolean).join(" \xB7 ")
27533
27945
  }))
@@ -27555,7 +27967,7 @@ async function deployStop() {
27555
27967
  O2.info("No codeam-pair process to stop on this workspace.");
27556
27968
  }
27557
27969
  const alsoStop = await ot2({
27558
- message: `Also stop the workspace ${import_picocolors11.default.cyan(target.displayName ?? target.id)} to save compute hours?`,
27970
+ message: `Also stop the workspace ${import_picocolors12.default.cyan(target.displayName ?? target.id)} to save compute hours?`,
27559
27971
  initialValue: true
27560
27972
  });
27561
27973
  if (!q(alsoStop) && alsoStop) {
@@ -27577,7 +27989,7 @@ async function deployStop() {
27577
27989
  O2.warn(err instanceof Error ? err.message : String(err));
27578
27990
  }
27579
27991
  }
27580
- gt(import_picocolors11.default.green("\u2713 Done."));
27992
+ gt(import_picocolors12.default.green("\u2713 Done."));
27581
27993
  }
27582
27994
  async function collectWorkspacesWithStatus() {
27583
27995
  const out2 = [];
@@ -27683,9 +28095,9 @@ async function host(args2) {
27683
28095
  var import_node_dns = require("dns");
27684
28096
  var import_node_util5 = require("util");
27685
28097
  var import_node_crypto8 = require("crypto");
27686
- var fs45 = __toESM(require("fs"));
27687
- var path56 = __toESM(require("path"));
27688
- var import_picocolors12 = __toESM(require("picocolors"));
28098
+ var fs47 = __toESM(require("fs"));
28099
+ var path58 = __toESM(require("path"));
28100
+ var import_picocolors13 = __toESM(require("picocolors"));
27689
28101
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
27690
28102
  async function checkDns(apiBase2) {
27691
28103
  const host2 = (() => {
@@ -27740,13 +28152,13 @@ async function checkHealth(apiBase2) {
27740
28152
  }
27741
28153
  }
27742
28154
  function checkConfigDir() {
27743
- const dir = path56.join(require("os").homedir(), ".codeam");
28155
+ const dir = path58.join(require("os").homedir(), ".codeam");
27744
28156
  try {
27745
- fs45.mkdirSync(dir, { recursive: true, mode: 448 });
27746
- const probe = path56.join(dir, ".doctor-probe");
27747
- fs45.writeFileSync(probe, "ok", { mode: 384 });
27748
- const read2 = fs45.readFileSync(probe, "utf8");
27749
- fs45.unlinkSync(probe);
28157
+ fs47.mkdirSync(dir, { recursive: true, mode: 448 });
28158
+ const probe = path58.join(dir, ".doctor-probe");
28159
+ fs47.writeFileSync(probe, "ok", { mode: 384 });
28160
+ const read2 = fs47.readFileSync(probe, "utf8");
28161
+ fs47.unlinkSync(probe);
27750
28162
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
27751
28163
  return {
27752
28164
  id: "config-dir",
@@ -27810,7 +28222,7 @@ function checkNodePty() {
27810
28222
  detail: "not required on this platform"
27811
28223
  };
27812
28224
  }
27813
- const vendoredPath = path56.join(__dirname, "vendor", "node-pty");
28225
+ const vendoredPath = path58.join(__dirname, "vendor", "node-pty");
27814
28226
  for (const target of [vendoredPath, "node-pty"]) {
27815
28227
  try {
27816
28228
  require(target);
@@ -27852,7 +28264,7 @@ function checkChokidar() {
27852
28264
  }
27853
28265
  async function doctor(args2 = []) {
27854
28266
  const json = args2.includes("--json");
27855
- const cliVersion = true ? "2.39.54" : "0.0.0-dev";
28267
+ const cliVersion = true ? "2.39.56" : "0.0.0-dev";
27856
28268
  const apiBase2 = resolveApiBaseUrl();
27857
28269
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
27858
28270
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -27892,46 +28304,46 @@ async function doctor(args2 = []) {
27892
28304
  function printHumanReport(r) {
27893
28305
  const out2 = process.stderr;
27894
28306
  out2.write(`
27895
- ${import_picocolors12.default.bold(" codeam doctor")}
28307
+ ${import_picocolors13.default.bold(" codeam doctor")}
27896
28308
 
27897
28309
  `);
27898
- out2.write(` ${import_picocolors12.default.dim("cli")} ${r.cliVersion}
28310
+ out2.write(` ${import_picocolors13.default.dim("cli")} ${r.cliVersion}
27899
28311
  `);
27900
- out2.write(` ${import_picocolors12.default.dim("node")} ${r.node}
28312
+ out2.write(` ${import_picocolors13.default.dim("node")} ${r.node}
27901
28313
  `);
27902
- out2.write(` ${import_picocolors12.default.dim("os")} ${r.platform} ${r.arch}
28314
+ out2.write(` ${import_picocolors13.default.dim("os")} ${r.platform} ${r.arch}
27903
28315
  `);
27904
- out2.write(` ${import_picocolors12.default.dim("api")} ${r.apiBase}
28316
+ out2.write(` ${import_picocolors13.default.dim("api")} ${r.apiBase}
27905
28317
  `);
27906
28318
  if (process.env.CODEAM_TEST_MODE === "1" || process.env.CODEAM_TEST_MODE?.toLowerCase() === "true") {
27907
- out2.write(` ${import_picocolors12.default.dim("mode")} ${import_picocolors12.default.yellow("TEST_MODE \u2014 using dev preview")}
28319
+ out2.write(` ${import_picocolors13.default.dim("mode")} ${import_picocolors13.default.yellow("TEST_MODE \u2014 using dev preview")}
27908
28320
  `);
27909
28321
  } else if (process.env.CODEAM_API_URL) {
27910
- out2.write(` ${import_picocolors12.default.dim("mode")} ${import_picocolors12.default.yellow("CODEAM_API_URL override")}
28322
+ out2.write(` ${import_picocolors13.default.dim("mode")} ${import_picocolors13.default.yellow("CODEAM_API_URL override")}
27911
28323
  `);
27912
28324
  }
27913
- out2.write(` ${import_picocolors12.default.dim("diag id")} ${r.diagnosticId}
28325
+ out2.write(` ${import_picocolors13.default.dim("diag id")} ${r.diagnosticId}
27914
28326
  `);
27915
28327
  out2.write("\n");
27916
28328
  for (const c2 of r.checks) {
27917
- const mark = c2.ok ? import_picocolors12.default.green("\u2713") : c2.optional ? import_picocolors12.default.yellow("!") : import_picocolors12.default.red("\u2717");
27918
- out2.write(` ${mark} ${c2.label}${import_picocolors12.default.dim(` \u2014 ${c2.detail}`)}
28329
+ const mark = c2.ok ? import_picocolors13.default.green("\u2713") : c2.optional ? import_picocolors13.default.yellow("!") : import_picocolors13.default.red("\u2717");
28330
+ out2.write(` ${mark} ${c2.label}${import_picocolors13.default.dim(` \u2014 ${c2.detail}`)}
27919
28331
  `);
27920
28332
  if (!c2.ok && c2.hint) {
27921
28333
  for (const line of c2.hint.split("\n")) {
27922
- out2.write(` ${import_picocolors12.default.dim(line)}
28334
+ out2.write(` ${import_picocolors13.default.dim(line)}
27923
28335
  `);
27924
28336
  }
27925
28337
  }
27926
28338
  }
27927
28339
  out2.write("\n");
27928
28340
  if (r.ok) {
27929
- out2.write(` ${import_picocolors12.default.green("All checks passed.")}
28341
+ out2.write(` ${import_picocolors13.default.green("All checks passed.")}
27930
28342
 
27931
28343
  `);
27932
28344
  } else {
27933
28345
  out2.write(
27934
- ` ${import_picocolors12.default.red("Some checks failed.")} ${import_picocolors12.default.dim("Paste the diagnostic id above when opening a bug report.")}
28346
+ ` ${import_picocolors13.default.red("Some checks failed.")} ${import_picocolors13.default.dim("Paste the diagnostic id above when opening a bug report.")}
27935
28347
 
27936
28348
  `
27937
28349
  );
@@ -28049,118 +28461,118 @@ async function completion(args2) {
28049
28461
  }
28050
28462
 
28051
28463
  // src/commands/version.ts
28052
- var import_picocolors13 = __toESM(require("picocolors"));
28464
+ var import_picocolors14 = __toESM(require("picocolors"));
28053
28465
  function version2() {
28054
- const v = true ? "2.39.54" : "unknown";
28055
- console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
28466
+ const v = true ? "2.39.56" : "unknown";
28467
+ console.log(`${import_picocolors14.default.bold("codeam-cli")} ${import_picocolors14.default.cyan(v)}`);
28056
28468
  }
28057
28469
 
28058
28470
  // src/commands/help.ts
28059
- var import_picocolors14 = __toESM(require("picocolors"));
28471
+ var import_picocolors15 = __toESM(require("picocolors"));
28060
28472
  function help() {
28061
28473
  const lines = [
28062
28474
  "",
28063
- ` ${import_picocolors14.default.bold(import_picocolors14.default.magenta("codeam-cli"))} ${import_picocolors14.default.dim("\u2014 remote-control AI coding agents from your phone")}`,
28475
+ ` ${import_picocolors15.default.bold(import_picocolors15.default.magenta("codeam-cli"))} ${import_picocolors15.default.dim("\u2014 remote-control AI coding agents from your phone")}`,
28064
28476
  "",
28065
- ` ${import_picocolors14.default.bold("Usage")}`,
28066
- ` ${import_picocolors14.default.cyan("codeam")} ${import_picocolors14.default.dim("[command]")}`,
28477
+ ` ${import_picocolors15.default.bold("Usage")}`,
28478
+ ` ${import_picocolors15.default.cyan("codeam")} ${import_picocolors15.default.dim("[command]")}`,
28067
28479
  "",
28068
- ` ${import_picocolors14.default.bold("Commands")}`,
28069
- ` ${import_picocolors14.default.white("codeam")} ${import_picocolors14.default.dim("start the active agent with mobile control")}`,
28070
- ` ${import_picocolors14.default.white("codeam <agent>")} ${import_picocolors14.default.dim("start a specific agent \u2014 e.g. claude, codex")}`,
28071
- ` ${import_picocolors14.default.white("codeam pair")} ${import_picocolors14.default.dim("pair a new mobile device (interactive)")}`,
28072
- ` ${import_picocolors14.default.white("codeam pair --agent <id>")} ${import_picocolors14.default.dim("pair non-interactively for a specific agent")}`,
28073
- ` ${import_picocolors14.default.white("codeam sessions")} ${import_picocolors14.default.dim("list paired devices")}`,
28074
- ` ${import_picocolors14.default.white("codeam sessions switch")} ${import_picocolors14.default.dim("switch the active paired session")}`,
28075
- ` ${import_picocolors14.default.white("codeam sessions delete <id>")} ${import_picocolors14.default.dim("remove a specific paired session")}`,
28076
- ` ${import_picocolors14.default.white("codeam status")} ${import_picocolors14.default.dim("show connection info")}`,
28077
- ` ${import_picocolors14.default.white("codeam logout")} ${import_picocolors14.default.dim("remove all paired sessions")}`,
28078
- ` ${import_picocolors14.default.white("codeam link <agent>")} ${import_picocolors14.default.dim("link an agent (claude, codex) to your CodeAgent account")}`,
28079
- ` ${import_picocolors14.default.white("codeam deploy")} ${import_picocolors14.default.dim("provision a cloud workspace (Codespaces) and pair it")}`,
28080
- ` ${import_picocolors14.default.white("codeam deploy ls | list")} ${import_picocolors14.default.dim("list deployed cloud workspaces")}`,
28081
- ` ${import_picocolors14.default.white("codeam deploy stop | remove")} ${import_picocolors14.default.dim("stop a deployed workspace session")}`,
28082
- ` ${import_picocolors14.default.white("codeam doctor")} ${import_picocolors14.default.dim("run diagnostic checks (DNS, /health, binaries, \u2026)")}`,
28083
- ` ${import_picocolors14.default.white("codeam completion <shell>")} ${import_picocolors14.default.dim("emit a bash/zsh/fish completion script")}`,
28480
+ ` ${import_picocolors15.default.bold("Commands")}`,
28481
+ ` ${import_picocolors15.default.white("codeam")} ${import_picocolors15.default.dim("start the active agent with mobile control")}`,
28482
+ ` ${import_picocolors15.default.white("codeam <agent>")} ${import_picocolors15.default.dim("start a specific agent \u2014 e.g. claude, codex")}`,
28483
+ ` ${import_picocolors15.default.white("codeam pair")} ${import_picocolors15.default.dim("pair a new mobile device (interactive)")}`,
28484
+ ` ${import_picocolors15.default.white("codeam pair --agent <id>")} ${import_picocolors15.default.dim("pair non-interactively for a specific agent")}`,
28485
+ ` ${import_picocolors15.default.white("codeam sessions")} ${import_picocolors15.default.dim("list paired devices")}`,
28486
+ ` ${import_picocolors15.default.white("codeam sessions switch")} ${import_picocolors15.default.dim("switch the active paired session")}`,
28487
+ ` ${import_picocolors15.default.white("codeam sessions delete <id>")} ${import_picocolors15.default.dim("remove a specific paired session")}`,
28488
+ ` ${import_picocolors15.default.white("codeam status")} ${import_picocolors15.default.dim("show connection info")}`,
28489
+ ` ${import_picocolors15.default.white("codeam logout")} ${import_picocolors15.default.dim("remove all paired sessions")}`,
28490
+ ` ${import_picocolors15.default.white("codeam link <agent>")} ${import_picocolors15.default.dim("link an agent (claude, codex) to your CodeAgent account")}`,
28491
+ ` ${import_picocolors15.default.white("codeam deploy")} ${import_picocolors15.default.dim("provision a cloud workspace (Codespaces) and pair it")}`,
28492
+ ` ${import_picocolors15.default.white("codeam deploy ls | list")} ${import_picocolors15.default.dim("list deployed cloud workspaces")}`,
28493
+ ` ${import_picocolors15.default.white("codeam deploy stop | remove")} ${import_picocolors15.default.dim("stop a deployed workspace session")}`,
28494
+ ` ${import_picocolors15.default.white("codeam doctor")} ${import_picocolors15.default.dim("run diagnostic checks (DNS, /health, binaries, \u2026)")}`,
28495
+ ` ${import_picocolors15.default.white("codeam completion <shell>")} ${import_picocolors15.default.dim("emit a bash/zsh/fish completion script")}`,
28084
28496
  "",
28085
- ` ${import_picocolors14.default.bold("Flags")}`,
28086
- ` ${import_picocolors14.default.white("-v, --version")} ${import_picocolors14.default.dim("print the CLI version")}`,
28087
- ` ${import_picocolors14.default.white("-h, --help")} ${import_picocolors14.default.dim("show this help")}`,
28497
+ ` ${import_picocolors15.default.bold("Flags")}`,
28498
+ ` ${import_picocolors15.default.white("-v, --version")} ${import_picocolors15.default.dim("print the CLI version")}`,
28499
+ ` ${import_picocolors15.default.white("-h, --help")} ${import_picocolors15.default.dim("show this help")}`,
28088
28500
  "",
28089
- ` ${import_picocolors14.default.bold("Links")}`,
28090
- ` ${import_picocolors14.default.dim("Docs:")} ${import_picocolors14.default.green("https://www.codeagent-mobile.com")}`,
28091
- ` ${import_picocolors14.default.dim("Issues:")} ${import_picocolors14.default.green("https://github.com/edgar-durand/codeagent-mobile-clients/issues")}`,
28501
+ ` ${import_picocolors15.default.bold("Links")}`,
28502
+ ` ${import_picocolors15.default.dim("Docs:")} ${import_picocolors15.default.green("https://www.codeagent-mobile.com")}`,
28503
+ ` ${import_picocolors15.default.dim("Issues:")} ${import_picocolors15.default.green("https://github.com/edgar-durand/codeagent-mobile-clients/issues")}`,
28092
28504
  ""
28093
28505
  ];
28094
28506
  process.stdout.write(lines.join("\n") + "\n");
28095
28507
  }
28096
28508
 
28097
28509
  // src/commands/subcommand-help.ts
28098
- var import_picocolors15 = __toESM(require("picocolors"));
28510
+ var import_picocolors16 = __toESM(require("picocolors"));
28099
28511
  var HELPS = {
28100
28512
  pair: () => print([
28101
- ` ${import_picocolors15.default.bold("codeam pair")} ${import_picocolors15.default.dim("\u2014 pair a mobile device with this CLI")}`,
28513
+ ` ${import_picocolors16.default.bold("codeam pair")} ${import_picocolors16.default.dim("\u2014 pair a mobile device with this CLI")}`,
28102
28514
  "",
28103
- ` ${import_picocolors15.default.cyan("codeam pair")} ${import_picocolors15.default.dim("interactive pairing (prompts for the agent)")}`,
28104
- ` ${import_picocolors15.default.cyan("codeam pair --agent <id>")} ${import_picocolors15.default.dim("pair non-interactively (agent: claude | codex)")}`,
28105
- ` ${import_picocolors15.default.cyan("codeam pair --dry-run")} ${import_picocolors15.default.dim("request a pairing code, validate the response, exit")}`
28515
+ ` ${import_picocolors16.default.cyan("codeam pair")} ${import_picocolors16.default.dim("interactive pairing (prompts for the agent)")}`,
28516
+ ` ${import_picocolors16.default.cyan("codeam pair --agent <id>")} ${import_picocolors16.default.dim("pair non-interactively (agent: claude | codex)")}`,
28517
+ ` ${import_picocolors16.default.cyan("codeam pair --dry-run")} ${import_picocolors16.default.dim("request a pairing code, validate the response, exit")}`
28106
28518
  ]),
28107
28519
  "pair-auto": () => print([
28108
- ` ${import_picocolors15.default.bold("codeam pair-auto")} ${import_picocolors15.default.dim("\u2014 non-interactive variant of pair for scripted setups")}`,
28520
+ ` ${import_picocolors16.default.bold("codeam pair-auto")} ${import_picocolors16.default.dim("\u2014 non-interactive variant of pair for scripted setups")}`,
28109
28521
  "",
28110
- ` ${import_picocolors15.default.cyan("codeam pair-auto --agent <id>")} ${import_picocolors15.default.dim("pair using the supplied agent id; exit on success or timeout")}`
28522
+ ` ${import_picocolors16.default.cyan("codeam pair-auto --agent <id>")} ${import_picocolors16.default.dim("pair using the supplied agent id; exit on success or timeout")}`
28111
28523
  ]),
28112
28524
  link: () => print([
28113
- ` ${import_picocolors15.default.bold("codeam link <agent>")} ${import_picocolors15.default.dim("\u2014 upload a local agent token (Claude or Codex) to your vault")}`,
28525
+ ` ${import_picocolors16.default.bold("codeam link <agent>")} ${import_picocolors16.default.dim("\u2014 upload a local agent token (Claude or Codex) to your vault")}`,
28114
28526
  "",
28115
- ` ${import_picocolors15.default.cyan("codeam link claude")}`,
28116
- ` ${import_picocolors15.default.cyan("codeam link codex")}`,
28527
+ ` ${import_picocolors16.default.cyan("codeam link claude")}`,
28528
+ ` ${import_picocolors16.default.cyan("codeam link codex")}`,
28117
28529
  "",
28118
- ` ${import_picocolors15.default.white("--api-key=<key>")} ${import_picocolors15.default.dim("paste an API key directly (visible in `ps -ef`)")}`,
28119
- ` ${import_picocolors15.default.white("--api-key-file=<path>")} ${import_picocolors15.default.dim("read API key from a file (recommended for CI / scripts)")}`,
28120
- ` ${import_picocolors15.default.white("--reuse-existing")} ${import_picocolors15.default.dim("upload existing creds without re-launching the agent login")}`,
28121
- ` ${import_picocolors15.default.white("--token-file=<path>")} ${import_picocolors15.default.dim("manual credential blob path for unusual vendor locations")}`,
28122
- ` ${import_picocolors15.default.white("--dry-run")} ${import_picocolors15.default.dim("probe the /api/plugin/agents/<agent>/link endpoint and exit")}`
28530
+ ` ${import_picocolors16.default.white("--api-key=<key>")} ${import_picocolors16.default.dim("paste an API key directly (visible in `ps -ef`)")}`,
28531
+ ` ${import_picocolors16.default.white("--api-key-file=<path>")} ${import_picocolors16.default.dim("read API key from a file (recommended for CI / scripts)")}`,
28532
+ ` ${import_picocolors16.default.white("--reuse-existing")} ${import_picocolors16.default.dim("upload existing creds without re-launching the agent login")}`,
28533
+ ` ${import_picocolors16.default.white("--token-file=<path>")} ${import_picocolors16.default.dim("manual credential blob path for unusual vendor locations")}`,
28534
+ ` ${import_picocolors16.default.white("--dry-run")} ${import_picocolors16.default.dim("probe the /api/plugin/agents/<agent>/link endpoint and exit")}`
28123
28535
  ]),
28124
28536
  sessions: () => print([
28125
- ` ${import_picocolors15.default.bold("codeam sessions")} ${import_picocolors15.default.dim("\u2014 list, switch, or delete paired mobile sessions")}`,
28537
+ ` ${import_picocolors16.default.bold("codeam sessions")} ${import_picocolors16.default.dim("\u2014 list, switch, or delete paired mobile sessions")}`,
28126
28538
  "",
28127
- ` ${import_picocolors15.default.cyan("codeam sessions")} ${import_picocolors15.default.dim("list all paired sessions on this machine")}`,
28128
- ` ${import_picocolors15.default.cyan("codeam sessions switch")} ${import_picocolors15.default.dim("interactively switch the active session")}`,
28129
- ` ${import_picocolors15.default.cyan("codeam sessions delete <id>")} ${import_picocolors15.default.dim("remove a specific paired session")}`
28539
+ ` ${import_picocolors16.default.cyan("codeam sessions")} ${import_picocolors16.default.dim("list all paired sessions on this machine")}`,
28540
+ ` ${import_picocolors16.default.cyan("codeam sessions switch")} ${import_picocolors16.default.dim("interactively switch the active session")}`,
28541
+ ` ${import_picocolors16.default.cyan("codeam sessions delete <id>")} ${import_picocolors16.default.dim("remove a specific paired session")}`
28130
28542
  ]),
28131
28543
  deploy: () => print([
28132
- ` ${import_picocolors15.default.bold("codeam deploy")} ${import_picocolors15.default.dim("\u2014 provision a cloud workspace (GitHub Codespaces) and pair it")}`,
28544
+ ` ${import_picocolors16.default.bold("codeam deploy")} ${import_picocolors16.default.dim("\u2014 provision a cloud workspace (GitHub Codespaces) and pair it")}`,
28133
28545
  "",
28134
- ` ${import_picocolors15.default.cyan("codeam deploy")} ${import_picocolors15.default.dim("start a new deploy (prompts for repo + agent)")}`,
28135
- ` ${import_picocolors15.default.cyan("codeam deploy ls | list")} ${import_picocolors15.default.dim("list deployed cloud workspaces")}`,
28136
- ` ${import_picocolors15.default.cyan("codeam deploy stop | remove")} ${import_picocolors15.default.dim("pick a workspace and stop its codeam-pair session")}`
28546
+ ` ${import_picocolors16.default.cyan("codeam deploy")} ${import_picocolors16.default.dim("start a new deploy (prompts for repo + agent)")}`,
28547
+ ` ${import_picocolors16.default.cyan("codeam deploy ls | list")} ${import_picocolors16.default.dim("list deployed cloud workspaces")}`,
28548
+ ` ${import_picocolors16.default.cyan("codeam deploy stop | remove")} ${import_picocolors16.default.dim("pick a workspace and stop its codeam-pair session")}`
28137
28549
  ]),
28138
28550
  status: () => print([
28139
- ` ${import_picocolors15.default.bold("codeam status")} ${import_picocolors15.default.dim("\u2014 show the active session, agent, and connection info")}`
28551
+ ` ${import_picocolors16.default.bold("codeam status")} ${import_picocolors16.default.dim("\u2014 show the active session, agent, and connection info")}`
28140
28552
  ]),
28141
28553
  logout: () => print([
28142
- ` ${import_picocolors15.default.bold("codeam logout")} ${import_picocolors15.default.dim("\u2014 remove every paired session from this machine")}`
28554
+ ` ${import_picocolors16.default.bold("codeam logout")} ${import_picocolors16.default.dim("\u2014 remove every paired session from this machine")}`
28143
28555
  ]),
28144
28556
  doctor: () => print([
28145
- ` ${import_picocolors15.default.bold("codeam doctor")} ${import_picocolors15.default.dim("\u2014 run diagnostic checks for support triage")}`,
28557
+ ` ${import_picocolors16.default.bold("codeam doctor")} ${import_picocolors16.default.dim("\u2014 run diagnostic checks for support triage")}`,
28146
28558
  "",
28147
- ` ${import_picocolors15.default.cyan("codeam doctor")} ${import_picocolors15.default.dim("human-readable report")}`,
28148
- ` ${import_picocolors15.default.cyan("codeam doctor --json")} ${import_picocolors15.default.dim("machine-parseable report (single JSON document on stdout)")}`,
28559
+ ` ${import_picocolors16.default.cyan("codeam doctor")} ${import_picocolors16.default.dim("human-readable report")}`,
28560
+ ` ${import_picocolors16.default.cyan("codeam doctor --json")} ${import_picocolors16.default.dim("machine-parseable report (single JSON document on stdout)")}`,
28149
28561
  "",
28150
- ` ${import_picocolors15.default.dim("Output never includes tokens or credentials. Paste the diagnostic id")}`,
28151
- ` ${import_picocolors15.default.dim("into a bug report so support can grep the server-side logs.")}`
28562
+ ` ${import_picocolors16.default.dim("Output never includes tokens or credentials. Paste the diagnostic id")}`,
28563
+ ` ${import_picocolors16.default.dim("into a bug report so support can grep the server-side logs.")}`
28152
28564
  ]),
28153
28565
  completion: () => print([
28154
- ` ${import_picocolors15.default.bold("codeam completion <shell>")} ${import_picocolors15.default.dim("\u2014 emit a shell-completion script for sourcing")}`,
28566
+ ` ${import_picocolors16.default.bold("codeam completion <shell>")} ${import_picocolors16.default.dim("\u2014 emit a shell-completion script for sourcing")}`,
28155
28567
  "",
28156
- ` ${import_picocolors15.default.cyan("codeam completion bash")} ${import_picocolors15.default.dim("print a bash completion function")}`,
28157
- ` ${import_picocolors15.default.cyan("codeam completion zsh")} ${import_picocolors15.default.dim("print a zsh completion function")}`,
28158
- ` ${import_picocolors15.default.cyan("codeam completion fish")} ${import_picocolors15.default.dim("print a fish completion file")}`,
28568
+ ` ${import_picocolors16.default.cyan("codeam completion bash")} ${import_picocolors16.default.dim("print a bash completion function")}`,
28569
+ ` ${import_picocolors16.default.cyan("codeam completion zsh")} ${import_picocolors16.default.dim("print a zsh completion function")}`,
28570
+ ` ${import_picocolors16.default.cyan("codeam completion fish")} ${import_picocolors16.default.dim("print a fish completion file")}`,
28159
28571
  "",
28160
- ` ${import_picocolors15.default.dim("Examples:")}`,
28161
- ` ${import_picocolors15.default.dim(" bash: codeam completion bash >> ~/.bashrc")}`,
28162
- ` ${import_picocolors15.default.dim(" zsh: codeam completion zsh >> ~/.zshrc")}`,
28163
- ` ${import_picocolors15.default.dim(" fish: codeam completion fish > ~/.config/fish/completions/codeam.fish")}`
28572
+ ` ${import_picocolors16.default.dim("Examples:")}`,
28573
+ ` ${import_picocolors16.default.dim(" bash: codeam completion bash >> ~/.bashrc")}`,
28574
+ ` ${import_picocolors16.default.dim(" zsh: codeam completion zsh >> ~/.zshrc")}`,
28575
+ ` ${import_picocolors16.default.dim(" fish: codeam completion fish > ~/.config/fish/completions/codeam.fish")}`
28164
28576
  ])
28165
28577
  };
28166
28578
  function print(lines) {
@@ -28178,179 +28590,6 @@ function tryShowSubcommandHelp(cmd, args2) {
28178
28590
  }
28179
28591
  var _subcommandHelpKeys = Object.keys(HELPS);
28180
28592
 
28181
- // src/lib/updateNotifier.ts
28182
- var fs46 = __toESM(require("fs"));
28183
- var os37 = __toESM(require("os"));
28184
- var path57 = __toESM(require("path"));
28185
- var https8 = __toESM(require("https"));
28186
- var import_node_child_process15 = require("child_process");
28187
- var import_picocolors16 = __toESM(require("picocolors"));
28188
- var PKG_NAME = "codeam-cli";
28189
- var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
28190
- var TTL_MS = 24 * 60 * 60 * 1e3;
28191
- var REQUEST_TIMEOUT_MS = 1500;
28192
- function cachePath() {
28193
- const dir = path57.join(os37.homedir(), ".codeam");
28194
- return path57.join(dir, "update-check.json");
28195
- }
28196
- function readCache() {
28197
- try {
28198
- const raw = fs46.readFileSync(cachePath(), "utf8");
28199
- const parsed = JSON.parse(raw);
28200
- if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
28201
- return parsed;
28202
- } catch {
28203
- return null;
28204
- }
28205
- }
28206
- function writeCache(cache) {
28207
- try {
28208
- const file = cachePath();
28209
- fs46.mkdirSync(path57.dirname(file), { recursive: true });
28210
- const tmp = `${file}.${process.pid}.tmp`;
28211
- fs46.writeFileSync(tmp, JSON.stringify(cache));
28212
- fs46.renameSync(tmp, file);
28213
- } catch {
28214
- }
28215
- }
28216
- function compareSemver(a, b) {
28217
- const stripPre = (s) => s.split("-")[0];
28218
- const aParts = stripPre(a).split(".").map(Number);
28219
- const bParts = stripPre(b).split(".").map(Number);
28220
- for (let i = 0; i < 3; i++) {
28221
- const ai = aParts[i] ?? 0;
28222
- const bi = bParts[i] ?? 0;
28223
- if (Number.isNaN(ai) || Number.isNaN(bi)) return 0;
28224
- if (ai > bi) return 1;
28225
- if (ai < bi) return -1;
28226
- }
28227
- return 0;
28228
- }
28229
- function fetchLatest() {
28230
- return new Promise((resolve7) => {
28231
- const req = https8.get(
28232
- REGISTRY_URL,
28233
- { headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
28234
- (res) => {
28235
- if (res.statusCode !== 200) {
28236
- res.resume();
28237
- resolve7(null);
28238
- return;
28239
- }
28240
- let buf = "";
28241
- res.setEncoding("utf8");
28242
- res.on("data", (chunk) => {
28243
- buf += chunk;
28244
- });
28245
- res.on("end", () => {
28246
- try {
28247
- const json = JSON.parse(buf);
28248
- if (typeof json.version === "string") {
28249
- resolve7(json.version);
28250
- } else {
28251
- resolve7(null);
28252
- }
28253
- } catch {
28254
- resolve7(null);
28255
- }
28256
- });
28257
- }
28258
- );
28259
- req.on("timeout", () => {
28260
- req.destroy();
28261
- resolve7(null);
28262
- });
28263
- req.on("error", () => resolve7(null));
28264
- });
28265
- }
28266
- function notifyIfStale(currentVersion, latest) {
28267
- if (compareSemver(latest, currentVersion) <= 0) return;
28268
- const arrow = import_picocolors16.default.dim("\u2192");
28269
- const cmd = import_picocolors16.default.cyan("npm install -g codeam-cli");
28270
- const lines = [
28271
- "",
28272
- ` ${import_picocolors16.default.yellow("\u25CF")} ${import_picocolors16.default.bold("Update available")} ${import_picocolors16.default.dim(currentVersion)} ${arrow} ${import_picocolors16.default.green(latest)}`,
28273
- ` Run ${cmd} to upgrade.`,
28274
- ""
28275
- ];
28276
- process.stderr.write(lines.join("\n"));
28277
- }
28278
- function isLinkedInstall() {
28279
- try {
28280
- const root = (0, import_node_child_process15.execSync)("npm root -g", {
28281
- encoding: "utf8",
28282
- stdio: ["ignore", "pipe", "ignore"],
28283
- timeout: 2e3
28284
- }).trim();
28285
- if (!root) return false;
28286
- const pkgPath = path57.join(root, PKG_NAME);
28287
- return fs46.lstatSync(pkgPath).isSymbolicLink();
28288
- } catch {
28289
- return false;
28290
- }
28291
- }
28292
- function maybeAutoUpdate(currentVersion, latest) {
28293
- if (compareSemver(latest, currentVersion) <= 0) return;
28294
- if (process.env.CODEAM_NO_AUTO_UPDATE === "1") {
28295
- notifyIfStale(currentVersion, latest);
28296
- return;
28297
- }
28298
- if (isLinkedInstall()) {
28299
- notifyIfStale(currentVersion, latest);
28300
- return;
28301
- }
28302
- process.stderr.write(
28303
- `
28304
- ${import_picocolors16.default.yellow("\u25CF")} ${import_picocolors16.default.bold("Updating codeam-cli")} ${import_picocolors16.default.dim(currentVersion)} ${import_picocolors16.default.dim("\u2192")} ${import_picocolors16.default.green(latest)}...
28305
-
28306
- `
28307
- );
28308
- const install = (0, import_node_child_process15.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
28309
- stdio: "inherit",
28310
- env: process.env
28311
- });
28312
- if (install.status !== 0) {
28313
- process.stderr.write(
28314
- `
28315
- ${import_picocolors16.default.red("!")} Update failed (exit ${install.status ?? "?"}). Continuing on ${currentVersion}.
28316
- Run ${import_picocolors16.default.cyan("npm install -g codeam-cli")} manually to retry.
28317
-
28318
- `
28319
- );
28320
- return;
28321
- }
28322
- try {
28323
- fs46.unlinkSync(cachePath());
28324
- } catch {
28325
- }
28326
- process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
28327
-
28328
- `);
28329
- const child = (0, import_node_child_process15.spawnSync)("codeam", process.argv.slice(2), {
28330
- stdio: "inherit",
28331
- env: process.env
28332
- });
28333
- process.exit(child.status ?? 0);
28334
- }
28335
- function checkForUpdates() {
28336
- if (process.env.NODE_ENV === "test") return;
28337
- if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
28338
- if (process.env.CI) return;
28339
- if (!process.stdout.isTTY) return;
28340
- const current = true ? "2.39.54" : null;
28341
- if (!current) return;
28342
- const cache = readCache();
28343
- const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
28344
- if (fresh && cache) {
28345
- maybeAutoUpdate(current, cache.latest);
28346
- return;
28347
- }
28348
- void fetchLatest().then((latest) => {
28349
- if (!latest) return;
28350
- writeCache({ fetchedAt: Date.now(), latest });
28351
- });
28352
- }
28353
-
28354
28593
  // src/exit-codes.ts
28355
28594
  var EXIT_OK = 0;
28356
28595
  var EXIT_FAILURE = 1;