codeam-cli 2.39.54 → 2.39.55

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 +6 -0
  2. package/dist/index.js +674 -458
  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.55" : "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.55",
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"));
@@ -17199,8 +17201,185 @@ var HeadroomStatsReporter = class {
17199
17201
  }
17200
17202
  };
17201
17203
 
17204
+ // src/lib/updateNotifier.ts
17205
+ var fs38 = __toESM(require("fs"));
17206
+ var os31 = __toESM(require("os"));
17207
+ var path44 = __toESM(require("path"));
17208
+ var https6 = __toESM(require("https"));
17209
+ var import_node_child_process12 = require("child_process");
17210
+ var import_picocolors3 = __toESM(require("picocolors"));
17211
+ var PKG_NAME = "codeam-cli";
17212
+ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
17213
+ var TTL_MS = 24 * 60 * 60 * 1e3;
17214
+ var REQUEST_TIMEOUT_MS = 1500;
17215
+ function cachePath() {
17216
+ const dir = path44.join(os31.homedir(), ".codeam");
17217
+ return path44.join(dir, "update-check.json");
17218
+ }
17219
+ function readCache() {
17220
+ try {
17221
+ const raw = fs38.readFileSync(cachePath(), "utf8");
17222
+ const parsed = JSON.parse(raw);
17223
+ if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
17224
+ return parsed;
17225
+ } catch {
17226
+ return null;
17227
+ }
17228
+ }
17229
+ function writeCache(cache) {
17230
+ try {
17231
+ const file = cachePath();
17232
+ fs38.mkdirSync(path44.dirname(file), { recursive: true });
17233
+ const tmp = `${file}.${process.pid}.tmp`;
17234
+ fs38.writeFileSync(tmp, JSON.stringify(cache));
17235
+ fs38.renameSync(tmp, file);
17236
+ } catch {
17237
+ }
17238
+ }
17239
+ function compareSemver(a, b) {
17240
+ const stripPre = (s) => s.split("-")[0];
17241
+ const aParts = stripPre(a).split(".").map(Number);
17242
+ const bParts = stripPre(b).split(".").map(Number);
17243
+ for (let i = 0; i < 3; i++) {
17244
+ const ai = aParts[i] ?? 0;
17245
+ const bi = bParts[i] ?? 0;
17246
+ if (Number.isNaN(ai) || Number.isNaN(bi)) return 0;
17247
+ if (ai > bi) return 1;
17248
+ if (ai < bi) return -1;
17249
+ }
17250
+ return 0;
17251
+ }
17252
+ function fetchLatest() {
17253
+ return new Promise((resolve7) => {
17254
+ const req = https6.get(
17255
+ REGISTRY_URL,
17256
+ { headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
17257
+ (res) => {
17258
+ if (res.statusCode !== 200) {
17259
+ res.resume();
17260
+ resolve7(null);
17261
+ return;
17262
+ }
17263
+ let buf = "";
17264
+ res.setEncoding("utf8");
17265
+ res.on("data", (chunk) => {
17266
+ buf += chunk;
17267
+ });
17268
+ res.on("end", () => {
17269
+ try {
17270
+ const json = JSON.parse(buf);
17271
+ if (typeof json.version === "string") {
17272
+ resolve7(json.version);
17273
+ } else {
17274
+ resolve7(null);
17275
+ }
17276
+ } catch {
17277
+ resolve7(null);
17278
+ }
17279
+ });
17280
+ }
17281
+ );
17282
+ req.on("timeout", () => {
17283
+ req.destroy();
17284
+ resolve7(null);
17285
+ });
17286
+ req.on("error", () => resolve7(null));
17287
+ });
17288
+ }
17289
+ function notifyIfStale(currentVersion, latest) {
17290
+ if (compareSemver(latest, currentVersion) <= 0) return;
17291
+ const arrow = import_picocolors3.default.dim("\u2192");
17292
+ const cmd = import_picocolors3.default.cyan("npm install -g codeam-cli");
17293
+ const lines = [
17294
+ "",
17295
+ ` ${import_picocolors3.default.yellow("\u25CF")} ${import_picocolors3.default.bold("Update available")} ${import_picocolors3.default.dim(currentVersion)} ${arrow} ${import_picocolors3.default.green(latest)}`,
17296
+ ` Run ${cmd} to upgrade.`,
17297
+ ""
17298
+ ];
17299
+ process.stderr.write(lines.join("\n"));
17300
+ }
17301
+ function isLinkedInstall() {
17302
+ try {
17303
+ const root = (0, import_node_child_process12.execSync)("npm root -g", {
17304
+ encoding: "utf8",
17305
+ stdio: ["ignore", "pipe", "ignore"],
17306
+ timeout: 2e3
17307
+ }).trim();
17308
+ if (!root) return false;
17309
+ const pkgPath = path44.join(root, PKG_NAME);
17310
+ return fs38.lstatSync(pkgPath).isSymbolicLink();
17311
+ } catch {
17312
+ return false;
17313
+ }
17314
+ }
17315
+ function maybeAutoUpdate(currentVersion, latest) {
17316
+ if (compareSemver(latest, currentVersion) <= 0) return;
17317
+ if (process.env.CODEAM_NO_AUTO_UPDATE === "1") {
17318
+ notifyIfStale(currentVersion, latest);
17319
+ return;
17320
+ }
17321
+ if (isLinkedInstall()) {
17322
+ notifyIfStale(currentVersion, latest);
17323
+ return;
17324
+ }
17325
+ process.stderr.write(
17326
+ `
17327
+ ${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)}...
17328
+
17329
+ `
17330
+ );
17331
+ const install = (0, import_node_child_process12.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
17332
+ stdio: "inherit",
17333
+ env: process.env
17334
+ });
17335
+ if (install.status !== 0) {
17336
+ process.stderr.write(
17337
+ `
17338
+ ${import_picocolors3.default.red("!")} Update failed (exit ${install.status ?? "?"}). Continuing on ${currentVersion}.
17339
+ Run ${import_picocolors3.default.cyan("npm install -g codeam-cli")} manually to retry.
17340
+
17341
+ `
17342
+ );
17343
+ return;
17344
+ }
17345
+ try {
17346
+ fs38.unlinkSync(cachePath());
17347
+ } catch {
17348
+ }
17349
+ process.stderr.write(` ${import_picocolors3.default.green("\u2713")} Updated. Resuming session...
17350
+
17351
+ `);
17352
+ const child = (0, import_node_child_process12.spawnSync)("codeam", process.argv.slice(2), {
17353
+ stdio: "inherit",
17354
+ env: process.env
17355
+ });
17356
+ process.exit(child.status ?? 0);
17357
+ }
17358
+ function checkForUpdates() {
17359
+ if (process.env.NODE_ENV === "test") return;
17360
+ if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17361
+ if (process.env.CI) return;
17362
+ if (!process.stdout.isTTY) return;
17363
+ const current = true ? "2.39.55" : null;
17364
+ if (!current) return;
17365
+ const cache = readCache();
17366
+ const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
17367
+ if (fresh && cache) {
17368
+ maybeAutoUpdate(current, cache.latest);
17369
+ return;
17370
+ }
17371
+ void fetchLatest().then((latest) => {
17372
+ if (!latest) return;
17373
+ writeCache({ fetchedAt: Date.now(), latest });
17374
+ });
17375
+ }
17376
+
17202
17377
  // src/commands/host-agent.ts
17203
17378
  var HEARTBEAT_INTERVAL_MS = 2e4;
17379
+ var SELF_UPDATE_PKG = "codeam-cli";
17380
+ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17381
+ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17382
+ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17204
17383
  function maybeStartHeadroomReporter(ctx) {
17205
17384
  if (process.env["HEADROOM_ENABLED"] !== "1") return null;
17206
17385
  try {
@@ -17275,7 +17454,7 @@ var PIP_INSTALL_TIMEOUT_MS = 12e4;
17275
17454
  var defaultHeadroomRunner = {
17276
17455
  which(cmd) {
17277
17456
  try {
17278
- (0, import_node_child_process12.execFileSync)("which", [cmd], { stdio: "ignore" });
17457
+ (0, import_node_child_process13.execFileSync)("which", [cmd], { stdio: "ignore" });
17279
17458
  return true;
17280
17459
  } catch {
17281
17460
  return false;
@@ -17283,7 +17462,7 @@ var defaultHeadroomRunner = {
17283
17462
  },
17284
17463
  run(cmd, args2, opts = {}) {
17285
17464
  return new Promise((resolve7) => {
17286
- const child = (0, import_node_child_process12.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"] });
17465
+ const child = (0, import_node_child_process13.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"] });
17287
17466
  let stderrBuf = "";
17288
17467
  let settled = false;
17289
17468
  const done = (code) => {
@@ -17416,6 +17595,41 @@ function agentIdToHeadroomKind(agentId) {
17416
17595
  if (normalized.startsWith("copilot")) return "copilot";
17417
17596
  return "claude";
17418
17597
  }
17598
+ function headroomConfigPath() {
17599
+ return path45.join(os32.homedir(), ".codeam", "headroom-config.json");
17600
+ }
17601
+ function persistHeadroomConfig(config) {
17602
+ try {
17603
+ const file = headroomConfigPath();
17604
+ fs39.mkdirSync(path45.dirname(file), { recursive: true, mode: 448 });
17605
+ const tmp = `${file}.tmp-${process.pid}`;
17606
+ fs39.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
17607
+ fs39.renameSync(tmp, file);
17608
+ } catch (err) {
17609
+ log.warn(
17610
+ "host-agent",
17611
+ `failed to persist headroom config (best-effort): ${err instanceof Error ? err.message : String(err)}`
17612
+ );
17613
+ }
17614
+ }
17615
+ function readHeadroomChildEnv() {
17616
+ try {
17617
+ const raw = fs39.readFileSync(headroomConfigPath(), "utf8");
17618
+ const parsed = JSON.parse(raw);
17619
+ if (typeof parsed !== "object" || parsed === null) return {};
17620
+ const o = parsed;
17621
+ if (o.enabled === true && typeof o.agent === "string" && o.agent.length > 0 && typeof o.ingestUrl === "string" && o.ingestUrl.length > 0) {
17622
+ return {
17623
+ HEADROOM_ENABLED: "1",
17624
+ HEADROOM_AGENT: o.agent,
17625
+ HEADROOM_SAVINGS_INGEST_URL: o.ingestUrl
17626
+ };
17627
+ }
17628
+ return {};
17629
+ } catch {
17630
+ return {};
17631
+ }
17632
+ }
17419
17633
  async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner) {
17420
17634
  const PIP_PACKAGES = [
17421
17635
  "headroom-ai",
@@ -17473,7 +17687,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17473
17687
  }
17474
17688
  const initKind = agentIdToHeadroomKind(agent);
17475
17689
  const initOk = await new Promise((resolve7) => {
17476
- (0, import_node_child_process12.execFile)("headroom", ["init", "--global", initKind], (initErr, stdout, stderr) => {
17690
+ (0, import_node_child_process13.execFile)("headroom", ["init", "--global", initKind], (initErr, stdout, stderr) => {
17477
17691
  if (initErr) {
17478
17692
  const detail = (stderr || initErr.message).replace(/\n+$/g, "");
17479
17693
  log.warn("host-agent", `headroom init failed (best-effort): ${detail}`);
@@ -17489,7 +17703,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17489
17703
  return false;
17490
17704
  }
17491
17705
  try {
17492
- const proxy = (0, import_node_child_process12.spawn)("headroom", ["proxy", "--port", "8787"], {
17706
+ const proxy = (0, import_node_child_process13.spawn)("headroom", ["proxy", "--port", "8787"], {
17493
17707
  stdio: "ignore",
17494
17708
  detached: true
17495
17709
  });
@@ -17499,20 +17713,81 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17499
17713
  }
17500
17714
  return true;
17501
17715
  }
17502
- var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process12.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
17716
+ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process13.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
17503
17717
  cwd,
17504
17718
  env: { ...process.env, ...env },
17505
17719
  stdio: ["ignore", "pipe", "pipe"],
17506
17720
  detached: false
17507
17721
  });
17722
+ function currentCliVersion() {
17723
+ return true ? "2.39.55" : null;
17724
+ }
17725
+ function runCmd(cmd, args2, timeoutMs) {
17726
+ return new Promise((resolve7) => {
17727
+ (0, import_node_child_process13.execFile)(cmd, args2, { timeout: timeoutMs }, (err, stdout, stderr) => {
17728
+ const code = err && typeof err.code === "number" ? err.code : err ? null : 0;
17729
+ resolve7({ code, stdout: stdout ?? "", stderr: stderr ?? "" });
17730
+ });
17731
+ });
17732
+ }
17733
+ async function runSelfUpdate() {
17734
+ try {
17735
+ const current = currentCliVersion();
17736
+ if (!current) {
17737
+ log.trace("host-agent", "self-update: no __CLI_VERSION__ \u2014 skipping");
17738
+ return { status: "skipped" };
17739
+ }
17740
+ const view = await runCmd("npm", ["view", SELF_UPDATE_PKG, "version"], SELF_UPDATE_VIEW_TIMEOUT_MS);
17741
+ if (view.code !== 0) {
17742
+ log.trace("host-agent", `self-update: npm view exited ${String(view.code)} \u2014 skipping`);
17743
+ return { status: "skipped" };
17744
+ }
17745
+ const latest = view.stdout.trim();
17746
+ if (!latest) {
17747
+ log.trace("host-agent", "self-update: empty npm view output \u2014 skipping");
17748
+ return { status: "skipped" };
17749
+ }
17750
+ if (compareSemver(latest, current) <= 0) {
17751
+ return { status: "current" };
17752
+ }
17753
+ log.info("host-agent", `self-update: ${current} \u2192 ${latest} available \u2014 installing`);
17754
+ const installArgs = ["install", "-g", `${SELF_UPDATE_PKG}@latest`];
17755
+ let install = await runCmd("npm", installArgs, SELF_UPDATE_INSTALL_TIMEOUT_MS);
17756
+ const isRoot = process.getuid?.() === 0;
17757
+ if (install.code !== 0 && !isRoot && /EACCES/i.test(install.stderr)) {
17758
+ log.info("host-agent", "self-update: install hit EACCES \u2014 retrying with sudo");
17759
+ install = await runCmd("sudo", ["npm", ...installArgs], SELF_UPDATE_INSTALL_TIMEOUT_MS);
17760
+ }
17761
+ if (install.code !== 0) {
17762
+ log.warn(
17763
+ "host-agent",
17764
+ `self-update: install exited ${String(install.code)} \u2014 staying on ${current}`
17765
+ );
17766
+ return { status: "skipped" };
17767
+ }
17768
+ const after = await runCmd("npm", ["view", SELF_UPDATE_PKG, "version"], SELF_UPDATE_VIEW_TIMEOUT_MS);
17769
+ const installed = after.code === 0 ? after.stdout.trim() || latest : latest;
17770
+ return { status: "updated", version: installed };
17771
+ } catch (err) {
17772
+ log.warn(
17773
+ "host-agent",
17774
+ `self-update: unexpected error: ${err instanceof Error ? err.message : String(err)}`
17775
+ );
17776
+ return { status: "skipped" };
17777
+ }
17778
+ }
17508
17779
  var defaultOnIdentityRejected = () => {
17509
17780
  deleteHostIdentity();
17510
17781
  log.warn("host-agent", "host identity rejected by backend \u2014 wiped sealed identity, exiting");
17511
17782
  process.exit(1);
17512
17783
  };
17784
+ var defaultOnUpdated = (version3) => {
17785
+ log.info("host-agent", `self-update: installed ${version3}, restarting`);
17786
+ process.exit(0);
17787
+ };
17513
17788
  var defaultDisableService = () => {
17514
17789
  try {
17515
- (0, import_node_child_process12.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
17790
+ (0, import_node_child_process13.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
17516
17791
  } catch {
17517
17792
  }
17518
17793
  };
@@ -17526,6 +17801,8 @@ var HostAgentSupervisor = class {
17526
17801
  this.metrics = deps.metricsCollector ?? new MetricsCollector();
17527
17802
  this.onIdentityRejected = deps.onIdentityRejected ?? defaultOnIdentityRejected;
17528
17803
  this.disableService = deps.disableService ?? defaultDisableService;
17804
+ this.selfUpdate = deps.selfUpdate ?? runSelfUpdate;
17805
+ this.onUpdated = deps.onUpdated ?? defaultOnUpdated;
17529
17806
  }
17530
17807
  identity;
17531
17808
  deps;
@@ -17535,6 +17812,20 @@ var HostAgentSupervisor = class {
17535
17812
  setupHeadroom;
17536
17813
  relay = null;
17537
17814
  heartbeatTimer = null;
17815
+ /** Periodic self-update timer (npm check + install + restart). */
17816
+ selfUpdateTimer = null;
17817
+ /** Self-update check + install (injectable; defaults to runSelfUpdate). */
17818
+ selfUpdate;
17819
+ /** Restart action after a successful self-update (defaults to process.exit). */
17820
+ onUpdated;
17821
+ /** Guards against overlapping self-update ticks (a slow npm install). */
17822
+ selfUpdating = false;
17823
+ /**
17824
+ * Set once a self-update installed a newer version but a child was busy,
17825
+ * so the next idle tick restarts WITHOUT re-installing. Carries the
17826
+ * already-installed version for the restart log.
17827
+ */
17828
+ pendingRestartVersion = null;
17538
17829
  /** Guards the one-shot 'connected' telemetry on the first heartbeat. */
17539
17830
  reportedConnected = false;
17540
17831
  /** Live-metrics collector — stateful across beats (CPU delta + latency). */
@@ -17545,6 +17836,19 @@ var HostAgentSupervisor = class {
17545
17836
  disableService;
17546
17837
  /** Guards against firing the self-heal more than once. */
17547
17838
  healing = false;
17839
+ /**
17840
+ * Resolve the self-update interval, honoring `CODEAM_HOST_SELF_UPDATE_MS`.
17841
+ * A finite value > 0 overrides the default; 0 or negative DISABLES the
17842
+ * periodic self-update (tests / pinned boxes); a non-numeric/absent value
17843
+ * falls back to {@link SELF_UPDATE_INTERVAL_MS}.
17844
+ */
17845
+ selfUpdateIntervalMs() {
17846
+ const raw = process.env.CODEAM_HOST_SELF_UPDATE_MS;
17847
+ if (raw === void 0 || raw === "") return SELF_UPDATE_INTERVAL_MS;
17848
+ const parsed = Number(raw);
17849
+ if (!Number.isFinite(parsed)) return SELF_UPDATE_INTERVAL_MS;
17850
+ return parsed;
17851
+ }
17548
17852
  /** Open the control channel (reusing the relay) + start heartbeats. */
17549
17853
  start() {
17550
17854
  const make = this.deps.makeRelay ?? ((pluginId, onCommand, meta) => new CommandRelayService(pluginId, onCommand, meta));
@@ -17557,6 +17861,13 @@ var HostAgentSupervisor = class {
17557
17861
  void this.beat();
17558
17862
  this.heartbeatTimer = setInterval(() => void this.beat(), HEARTBEAT_INTERVAL_MS);
17559
17863
  this.heartbeatTimer.unref?.();
17864
+ const updateMs = this.selfUpdateIntervalMs();
17865
+ if (updateMs > 0) {
17866
+ this.selfUpdateTimer = setInterval(() => void this.selfUpdateTick(), updateMs);
17867
+ this.selfUpdateTimer.unref?.();
17868
+ } else {
17869
+ log.info("host-agent", "self-update disabled (CODEAM_HOST_SELF_UPDATE_MS<=0)");
17870
+ }
17560
17871
  log.info("host-agent", `supervisor up host=${this.identity.hostId.slice(0, 8)}`);
17561
17872
  }
17562
17873
  /** Stop the control channel + heartbeats + kill every child. */
@@ -17565,6 +17876,10 @@ var HostAgentSupervisor = class {
17565
17876
  clearInterval(this.heartbeatTimer);
17566
17877
  this.heartbeatTimer = null;
17567
17878
  }
17879
+ if (this.selfUpdateTimer) {
17880
+ clearInterval(this.selfUpdateTimer);
17881
+ this.selfUpdateTimer = null;
17882
+ }
17568
17883
  this.relay?.stop();
17569
17884
  for (const child of this.children.values()) {
17570
17885
  try {
@@ -17604,6 +17919,61 @@ var HostAgentSupervisor = class {
17604
17919
  log.trace("host-agent", "heartbeat failed", err);
17605
17920
  }
17606
17921
  }
17922
+ /**
17923
+ * One self-update tick. Best-effort + never crashes the supervisor: the
17924
+ * whole body is wrapped in try/catch and the injected updater never
17925
+ * rejects. Sequence:
17926
+ *
17927
+ * 1. If a restart is already PENDING (a prior tick installed a newer
17928
+ * version while a child was busy), skip the npm work and just try to
17929
+ * restart now — no re-install.
17930
+ * 2. Otherwise run the injected `selfUpdate`. On `'updated'`, remember
17931
+ * the new version as pending; on anything else, do nothing.
17932
+ * 3. SAFETY: only restart when no child turn is in flight. If a child is
17933
+ * mid-work, DEFER — the install already happened, so a later idle
17934
+ * tick just restarts. (We prefer deferring to yanking an active turn;
17935
+ * systemd would restart in ~5s but the mobile would drop the turn.)
17936
+ *
17937
+ * `selfUpdating` guards against a slow npm install overlapping the next
17938
+ * tick (the timer keeps firing on its interval).
17939
+ */
17940
+ async selfUpdateTick() {
17941
+ if (this.selfUpdating) return;
17942
+ this.selfUpdating = true;
17943
+ try {
17944
+ if (this.pendingRestartVersion !== null) {
17945
+ this.maybeRestartForUpdate(this.pendingRestartVersion);
17946
+ return;
17947
+ }
17948
+ const result = await this.selfUpdate();
17949
+ if (result.status !== "updated") return;
17950
+ const version3 = result.version ?? "latest";
17951
+ this.pendingRestartVersion = version3;
17952
+ this.maybeRestartForUpdate(version3);
17953
+ } catch (err) {
17954
+ log.warn(
17955
+ "host-agent",
17956
+ `self-update tick failed: ${err instanceof Error ? err.message : String(err)}`
17957
+ );
17958
+ } finally {
17959
+ this.selfUpdating = false;
17960
+ }
17961
+ }
17962
+ /**
17963
+ * Restart for an already-installed update IFF no child turn is in flight.
17964
+ * When a child is busy we DEFER (the version stays pending for the next
17965
+ * idle tick) rather than yank an active turn.
17966
+ */
17967
+ maybeRestartForUpdate(version3) {
17968
+ if (this.children.size > 0) {
17969
+ log.info(
17970
+ "host-agent",
17971
+ `self-update: ${version3} installed but ${this.children.size} child(ren) busy \u2014 deferring restart`
17972
+ );
17973
+ return;
17974
+ }
17975
+ this.onUpdated(version3);
17976
+ }
17607
17977
  /** Number of live children — for tests + diagnostics. */
17608
17978
  childCount() {
17609
17979
  return this.children.size;
@@ -17699,7 +18069,7 @@ var HostAgentSupervisor = class {
17699
18069
  report("installing", "installing agent CLI");
17700
18070
  await this.runAgentInstall(payload.agentInstallScript);
17701
18071
  }
17702
- const home = process.env.HOME || os31.homedir();
18072
+ const home = process.env.HOME || os32.homedir();
17703
18073
  childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
17704
18074
  if (payload.previewTunnelToken && payload.previewHostname) {
17705
18075
  childEnv.PREVIEW_TUNNEL_TOKEN = payload.previewTunnelToken;
@@ -17709,16 +18079,21 @@ var HostAgentSupervisor = class {
17709
18079
  report("headroom", "setting up Headroom proxy");
17710
18080
  const headroomOk = await this.setupHeadroom(payload.headroomAgent);
17711
18081
  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");
18082
+ persistHeadroomConfig({
18083
+ enabled: true,
18084
+ agent: agentIdToHeadroomKind(payload.headroomAgent),
18085
+ ingestUrl: payload.headroomSavingsIngestUrl
18086
+ });
18087
+ log.info("host-agent", "Headroom proxy ready; persisted headroom config for child spawns");
17716
18088
  } else {
18089
+ persistHeadroomConfig({ enabled: false });
17717
18090
  log.warn("host-agent", "Headroom setup failed (best-effort) \u2014 child will run without Headroom");
17718
18091
  }
18092
+ } else if (payload.headroomEnabled === false) {
18093
+ persistHeadroomConfig({ enabled: false });
17719
18094
  }
17720
18095
  report("spawning", "starting agent");
17721
- const proc = this.spawnChild(childEnv, cwd, extraArgs);
18096
+ const proc = this.spawnSessionChild(childEnv, cwd, extraArgs);
17722
18097
  const child = { deployId: payload.deployId, proc };
17723
18098
  this.children.set(payload.deployId, child);
17724
18099
  let tail = "";
@@ -17752,6 +18127,20 @@ var HostAgentSupervisor = class {
17752
18127
  report("failed", message);
17753
18128
  }
17754
18129
  }
18130
+ /**
18131
+ * Spawn a supervised `pair-auto` session child, merging the persisted
18132
+ * Headroom env on top of the caller's env. This is the SINGLE spawn site for
18133
+ * session children: the fresh-deploy path and any future resume / restart
18134
+ * path both go through here, so the HEADROOM_* env (read from
18135
+ * `~/.codeam/headroom-config.json`, the source of truth a prior deploy wrote)
18136
+ * is injected on EVERY spawn — reporting survives session resumes and
18137
+ * supervisor restarts (systemd / periodic self-update), not just fresh
18138
+ * deploys. `readHeadroomChildEnv()` returns `{}` when Headroom is disabled or
18139
+ * was never set up, so this is a no-op there (never-break).
18140
+ */
18141
+ spawnSessionChild(env, cwd, args2 = []) {
18142
+ return this.spawnChild({ ...env, ...readHeadroomChildEnv() }, cwd, args2);
18143
+ }
17755
18144
  /**
17756
18145
  * Run the backend-supplied per-agent CLI install script (e.g.
17757
18146
  * `claude.ai/install.sh`, `npm i -g @openai/codex`). Best-effort + bounded:
@@ -17763,8 +18152,8 @@ var HostAgentSupervisor = class {
17763
18152
  */
17764
18153
  runAgentInstall(script) {
17765
18154
  return new Promise((resolve7) => {
17766
- const home = process.env.HOME || os31.homedir();
17767
- const child = (0, import_node_child_process12.spawn)("sh", ["-c", script], {
18155
+ const home = process.env.HOME || os32.homedir();
18156
+ const child = (0, import_node_child_process13.spawn)("sh", ["-c", script], {
17768
18157
  env: { ...process.env, HOME: home },
17769
18158
  stdio: ["ignore", "pipe", "pipe"]
17770
18159
  });
@@ -17888,12 +18277,12 @@ function readTokenFromArgs(args2) {
17888
18277
  }
17889
18278
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
17890
18279
  if (fileFlag) {
17891
- const path58 = fileFlag.slice("--token-file=".length);
18280
+ const path59 = fileFlag.slice("--token-file=".length);
17892
18281
  try {
17893
- const content = fs38.readFileSync(path58, "utf8").trim();
17894
- if (content.length === 0) fail(`--token-file ${path58} is empty`);
18282
+ const content = fs40.readFileSync(path59, "utf8").trim();
18283
+ if (content.length === 0) fail(`--token-file ${path59} is empty`);
17895
18284
  try {
17896
- fs38.unlinkSync(path58);
18285
+ fs40.unlinkSync(path59);
17897
18286
  } catch {
17898
18287
  }
17899
18288
  return content;
@@ -17919,7 +18308,7 @@ async function claimOnce(token, pluginId, pluginSecretHash) {
17919
18308
  pluginId,
17920
18309
  ideName: "codeam-cli (codespace)",
17921
18310
  ideVersion: process.env.npm_package_version ?? "unknown",
17922
- hostname: os32.hostname(),
18311
+ hostname: os33.hostname(),
17923
18312
  codespaceName: process.env.CODESPACE_NAME ?? "",
17924
18313
  // Current git branch of the codespace's working directory, so the
17925
18314
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -17980,7 +18369,7 @@ async function claim(token, pluginId, pluginSecretHash) {
17980
18369
  }
17981
18370
  }
17982
18371
  function pairAutoLockPath() {
17983
- return path44.join(os32.homedir(), ".codeam", "pair-auto.lock");
18372
+ return path46.join(os33.homedir(), ".codeam", "pair-auto.lock");
17984
18373
  }
17985
18374
  function isLivePairAuto(pid) {
17986
18375
  if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
@@ -17990,7 +18379,7 @@ function isLivePairAuto(pid) {
17990
18379
  if (e.code !== "EPERM") return false;
17991
18380
  }
17992
18381
  try {
17993
- return fs38.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
18382
+ return fs40.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
17994
18383
  } catch {
17995
18384
  return true;
17996
18385
  }
@@ -18000,24 +18389,24 @@ function isLiveCodeam(pid) {
18000
18389
  }
18001
18390
  function daemonLockPath(sessionId) {
18002
18391
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
18003
- return path44.join(os32.homedir(), ".codeam", `daemon-${safe}.lock`);
18392
+ return path46.join(os33.homedir(), ".codeam", `daemon-${safe}.lock`);
18004
18393
  }
18005
18394
  function acquireDaemonLock(sessionId) {
18006
18395
  const lockPath = daemonLockPath(sessionId);
18007
18396
  try {
18008
- fs38.mkdirSync(path44.dirname(lockPath), { recursive: true });
18397
+ fs40.mkdirSync(path46.dirname(lockPath), { recursive: true });
18009
18398
  try {
18010
- fs38.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18399
+ fs40.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18011
18400
  } catch (e) {
18012
18401
  if (e.code !== "EEXIST") throw e;
18013
- const holder = Number(fs38.readFileSync(lockPath, "utf8").trim());
18402
+ const holder = Number(fs40.readFileSync(lockPath, "utf8").trim());
18014
18403
  if (holder && holder !== process.pid && isLiveCodeam(holder)) return false;
18015
- fs38.writeFileSync(lockPath, String(process.pid));
18404
+ fs40.writeFileSync(lockPath, String(process.pid));
18016
18405
  }
18017
18406
  const release3 = () => {
18018
18407
  try {
18019
- if (fs38.existsSync(lockPath) && Number(fs38.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18020
- fs38.unlinkSync(lockPath);
18408
+ if (fs40.existsSync(lockPath) && Number(fs40.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18409
+ fs40.unlinkSync(lockPath);
18021
18410
  }
18022
18411
  } catch {
18023
18412
  }
@@ -18039,19 +18428,19 @@ function acquireDaemonLock(sessionId) {
18039
18428
  function acquireSingletonLock() {
18040
18429
  const lockPath = pairAutoLockPath();
18041
18430
  try {
18042
- fs38.mkdirSync(path44.dirname(lockPath), { recursive: true });
18431
+ fs40.mkdirSync(path46.dirname(lockPath), { recursive: true });
18043
18432
  try {
18044
- fs38.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18433
+ fs40.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18045
18434
  } catch (e) {
18046
18435
  if (e.code !== "EEXIST") throw e;
18047
- const holder = Number(fs38.readFileSync(lockPath, "utf8").trim());
18436
+ const holder = Number(fs40.readFileSync(lockPath, "utf8").trim());
18048
18437
  if (isLivePairAuto(holder)) return false;
18049
- fs38.writeFileSync(lockPath, String(process.pid));
18438
+ fs40.writeFileSync(lockPath, String(process.pid));
18050
18439
  }
18051
18440
  process.once("exit", () => {
18052
18441
  try {
18053
- if (fs38.existsSync(lockPath) && Number(fs38.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18054
- fs38.unlinkSync(lockPath);
18442
+ if (fs40.existsSync(lockPath) && Number(fs40.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18443
+ fs40.unlinkSync(lockPath);
18055
18444
  }
18056
18445
  } catch {
18057
18446
  }
@@ -18133,7 +18522,7 @@ async function pairAuto(args2) {
18133
18522
  }
18134
18523
 
18135
18524
  // src/services/headroom/wrap-launch.ts
18136
- var import_node_child_process13 = require("child_process");
18525
+ var import_node_child_process14 = require("child_process");
18137
18526
  function wrapWithHeadroom(launch, opts) {
18138
18527
  if (!opts.enabled || !opts.headroomPresent) return launch;
18139
18528
  return {
@@ -18146,7 +18535,7 @@ var _present;
18146
18535
  function headroomPresent() {
18147
18536
  if (_present !== void 0) return Promise.resolve(_present);
18148
18537
  return new Promise((resolve7) => {
18149
- (0, import_node_child_process13.execFile)("headroom", ["--version"], (err) => {
18538
+ (0, import_node_child_process14.execFile)("headroom", ["--version"], (err) => {
18150
18539
  _present = !err;
18151
18540
  resolve7(_present);
18152
18541
  });
@@ -18496,19 +18885,19 @@ var AgentService = class _AgentService {
18496
18885
  };
18497
18886
 
18498
18887
  // src/agents/acp/adapters.ts
18499
- var path45 = __toESM(require("path"));
18888
+ var path47 = __toESM(require("path"));
18500
18889
  var require_ = require;
18501
18890
  function resolveBin(pkgName, binName) {
18502
18891
  try {
18503
18892
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
18504
18893
  const manifest = require_(`${pkgName}/package.json`);
18505
- const pkgDir = path45.dirname(manifestPath);
18894
+ const pkgDir = path47.dirname(manifestPath);
18506
18895
  const bin = manifest.bin;
18507
18896
  if (!bin) return null;
18508
- if (typeof bin === "string") return path45.resolve(pkgDir, bin);
18897
+ if (typeof bin === "string") return path47.resolve(pkgDir, bin);
18509
18898
  const target = binName ?? Object.keys(bin)[0];
18510
18899
  if (!target || !bin[target]) return null;
18511
- return path45.resolve(pkgDir, bin[target]);
18900
+ return path47.resolve(pkgDir, bin[target]);
18512
18901
  } catch {
18513
18902
  return null;
18514
18903
  }
@@ -18584,11 +18973,11 @@ function requiresAcp(agent) {
18584
18973
  var import_node_crypto7 = require("crypto");
18585
18974
 
18586
18975
  // src/agents/acp/client.ts
18587
- var import_node_child_process14 = require("child_process");
18588
- var fs39 = __toESM(require("fs/promises"));
18976
+ var import_node_child_process15 = require("child_process");
18977
+ var fs41 = __toESM(require("fs/promises"));
18589
18978
  var fsSync = __toESM(require("fs"));
18590
- var os33 = __toESM(require("os"));
18591
- var path46 = __toESM(require("path"));
18979
+ var os34 = __toESM(require("os"));
18980
+ var path48 = __toESM(require("path"));
18592
18981
  var import_node_stream = require("stream");
18593
18982
 
18594
18983
  // ../../node_modules/@agentclientprotocol/sdk/dist/acp.js
@@ -21125,7 +21514,7 @@ var AcpClient = class {
21125
21514
  "acpClient",
21126
21515
  `spawn cmd=${adapter.command} args=[${adapter.args.join(",")}] cwd=${cwd}`
21127
21516
  );
21128
- const child = (0, import_node_child_process14.spawn)(adapter.command, adapter.args, {
21517
+ const child = (0, import_node_child_process15.spawn)(adapter.command, adapter.args, {
21129
21518
  cwd,
21130
21519
  env: { ...process.env, PATH: augmentedPath },
21131
21520
  stdio: ["pipe", "pipe", "pipe"]
@@ -21375,7 +21764,7 @@ var AcpClient = class {
21375
21764
  },
21376
21765
  readTextFile: async (params) => {
21377
21766
  try {
21378
- const content = await fs39.readFile(params.path, "utf8");
21767
+ const content = await fs41.readFile(params.path, "utf8");
21379
21768
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
21380
21769
  } catch (err) {
21381
21770
  const code = err.code;
@@ -21395,7 +21784,7 @@ var AcpClient = class {
21395
21784
  },
21396
21785
  writeTextFile: async (params) => {
21397
21786
  try {
21398
- await fs39.writeFile(params.path, params.content, "utf8");
21787
+ await fs41.writeFile(params.path, params.content, "utf8");
21399
21788
  return {};
21400
21789
  } catch (err) {
21401
21790
  const code = err.code;
@@ -21444,25 +21833,25 @@ function applyLineRange(content, line, limit) {
21444
21833
  return { content: lines.slice(start2, end).join("\n") };
21445
21834
  }
21446
21835
  function knownAgentBinaryDirs() {
21447
- const home = os33.homedir();
21836
+ const home = os34.homedir();
21448
21837
  const out2 = [];
21449
21838
  out2.push("/tmp/codeam-node20/bin");
21450
21839
  for (const root of [
21451
21840
  "/usr/local/share/nvm/versions/node",
21452
- path46.join(home, ".nvm/versions/node")
21841
+ path48.join(home, ".nvm/versions/node")
21453
21842
  ]) {
21454
21843
  try {
21455
21844
  for (const child of fsSync.readdirSync(root)) {
21456
- out2.push(path46.join(root, child, "bin"));
21845
+ out2.push(path48.join(root, child, "bin"));
21457
21846
  }
21458
21847
  } catch {
21459
21848
  }
21460
21849
  }
21461
- out2.push(path46.join(home, ".volta/bin"));
21850
+ out2.push(path48.join(home, ".volta/bin"));
21462
21851
  out2.push("/usr/local/bin");
21463
21852
  out2.push("/usr/bin");
21464
- out2.push(path46.join(home, ".local/bin"));
21465
- out2.push(path46.join(home, "bin"));
21853
+ out2.push(path48.join(home, ".local/bin"));
21854
+ out2.push(path48.join(home, "bin"));
21466
21855
  return out2.filter((p2) => {
21467
21856
  try {
21468
21857
  return fsSync.statSync(p2).isDirectory();
@@ -21473,7 +21862,7 @@ function knownAgentBinaryDirs() {
21473
21862
  }
21474
21863
  function expandPathForAgentBinaries(existingPath) {
21475
21864
  const existing = new Set(
21476
- existingPath.split(path46.delimiter).filter((p2) => p2.length > 0)
21865
+ existingPath.split(path48.delimiter).filter((p2) => p2.length > 0)
21477
21866
  );
21478
21867
  const additions = [];
21479
21868
  for (const dir of knownAgentBinaryDirs()) {
@@ -21483,12 +21872,12 @@ function expandPathForAgentBinaries(existingPath) {
21483
21872
  }
21484
21873
  }
21485
21874
  if (additions.length === 0) return existingPath;
21486
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path46.delimiter);
21875
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path48.delimiter);
21487
21876
  }
21488
21877
 
21489
21878
  // src/services/streaming/transport.ts
21490
21879
  var http6 = __toESM(require("http"));
21491
- var https6 = __toESM(require("https"));
21880
+ var https7 = __toESM(require("https"));
21492
21881
  var _transport4 = {
21493
21882
  post: _post3,
21494
21883
  get: _get
@@ -21497,7 +21886,7 @@ function _post3(url, headers, payload) {
21497
21886
  return new Promise((resolve7, reject) => {
21498
21887
  let settled = false;
21499
21888
  const u2 = new URL(url);
21500
- const lib = u2.protocol === "https:" ? https6 : http6;
21889
+ const lib = u2.protocol === "https:" ? https7 : http6;
21501
21890
  const req = lib.request(
21502
21891
  {
21503
21892
  hostname: u2.hostname,
@@ -21539,7 +21928,7 @@ function _get(url, headers) {
21539
21928
  return new Promise((resolve7, reject) => {
21540
21929
  let settled = false;
21541
21930
  const u2 = new URL(url);
21542
- const lib = u2.protocol === "https:" ? https6 : http6;
21931
+ const lib = u2.protocol === "https:" ? https7 : http6;
21543
21932
  const req = lib.request(
21544
21933
  {
21545
21934
  hostname: u2.hostname,
@@ -21810,15 +22199,15 @@ function reconcileCumulative(existing, incoming) {
21810
22199
  }
21811
22200
 
21812
22201
  // src/agents/acp/onboarding.ts
21813
- var fs40 = __toESM(require("fs"));
21814
- var os34 = __toESM(require("os"));
21815
- var path47 = __toESM(require("path"));
22202
+ var fs42 = __toESM(require("fs"));
22203
+ var os35 = __toESM(require("os"));
22204
+ var path49 = __toESM(require("path"));
21816
22205
  var _onboardingSeam = {
21817
- markerPath: (sessionId) => path47.join(os34.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
21818
- exists: (p2) => fs40.existsSync(p2),
22206
+ markerPath: (sessionId) => path49.join(os35.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
22207
+ exists: (p2) => fs42.existsSync(p2),
21819
22208
  write: (p2) => {
21820
- fs40.mkdirSync(path47.dirname(p2), { recursive: true });
21821
- fs40.writeFileSync(p2, "");
22209
+ fs42.mkdirSync(path49.dirname(p2), { recursive: true });
22210
+ fs42.writeFileSync(p2, "");
21822
22211
  },
21823
22212
  disabled: () => {
21824
22213
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -21826,7 +22215,7 @@ var _onboardingSeam = {
21826
22215
  }
21827
22216
  };
21828
22217
  function buildOnboardingWelcome(cwd) {
21829
- const repo = path47.basename(cwd || "") || "this project";
22218
+ const repo = path49.basename(cwd || "") || "this project";
21830
22219
  return [
21831
22220
  `Welcome to CodeAgent Mobile! \u{1F44B} You're now driving this agent from your phone \u2014 and it comes fully wired, zero setup:`,
21832
22221
  "",
@@ -22086,8 +22475,8 @@ var import_crypto5 = require("crypto");
22086
22475
 
22087
22476
  // src/services/turn-files/git-changeset.ts
22088
22477
  var import_child_process22 = require("child_process");
22089
- var fs41 = __toESM(require("fs/promises"));
22090
- var path48 = __toESM(require("path"));
22478
+ var fs43 = __toESM(require("fs/promises"));
22479
+ var path50 = __toESM(require("path"));
22091
22480
  async function collectRepoChangeset(opts) {
22092
22481
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
22093
22482
  if (status2 === null) return null;
@@ -22105,7 +22494,7 @@ async function collectRepoChangeset(opts) {
22105
22494
  let stats;
22106
22495
  if (row.fileStatus === "added" && numstatEntry === void 0) {
22107
22496
  const lineCount = await readUntrackedLineCount(
22108
- path48.join(opts.repoRoot, row.filePath)
22497
+ path50.join(opts.repoRoot, row.filePath)
22109
22498
  );
22110
22499
  stats = { added: lineCount, removed: 0 };
22111
22500
  } else {
@@ -22136,7 +22525,7 @@ function readUntrackedLineCount(absPath) {
22136
22525
  }
22137
22526
  async function defaultReadUntrackedLineCount(absPath) {
22138
22527
  try {
22139
- const content = await fs41.readFile(absPath, "utf8");
22528
+ const content = await fs43.readFile(absPath, "utf8");
22140
22529
  let count = 0;
22141
22530
  let pos = -1;
22142
22531
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -22228,7 +22617,7 @@ function defaultRunGit(cwd, args2) {
22228
22617
  });
22229
22618
  }
22230
22619
  async function discoverRepos(workingDir, maxDepth = 4) {
22231
- const fs47 = await import("fs/promises");
22620
+ const fs48 = await import("fs/promises");
22232
22621
  const out2 = [];
22233
22622
  await walk(workingDir, 0);
22234
22623
  return out2;
@@ -22236,7 +22625,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
22236
22625
  if (depth > maxDepth) return;
22237
22626
  let entries = [];
22238
22627
  try {
22239
- const dirents = await fs47.readdir(dir, { withFileTypes: true });
22628
+ const dirents = await fs48.readdir(dir, { withFileTypes: true });
22240
22629
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
22241
22630
  } catch {
22242
22631
  return;
@@ -22247,8 +22636,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
22247
22636
  if (hasGit) {
22248
22637
  out2.push({
22249
22638
  repoRoot: dir,
22250
- repoPath: path48.relative(workingDir, dir),
22251
- repoName: path48.basename(dir)
22639
+ repoPath: path50.relative(workingDir, dir),
22640
+ repoName: path50.basename(dir)
22252
22641
  });
22253
22642
  return;
22254
22643
  }
@@ -22256,14 +22645,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
22256
22645
  if (!entry.isDirectory) continue;
22257
22646
  if (entry.name === "node_modules") continue;
22258
22647
  if (entry.name === "dist" || entry.name === "build") continue;
22259
- await walk(path48.join(dir, entry.name), depth + 1);
22648
+ await walk(path50.join(dir, entry.name), depth + 1);
22260
22649
  }
22261
22650
  }
22262
22651
  }
22263
22652
 
22264
22653
  // src/services/turn-files/files-outbox.ts
22265
- var fs42 = __toESM(require("fs/promises"));
22266
- var path49 = __toESM(require("path"));
22654
+ var fs44 = __toESM(require("fs/promises"));
22655
+ var path51 = __toESM(require("path"));
22267
22656
  var import_os7 = require("os");
22268
22657
  var HOME_OUTBOX_DIR = ".codeam/outbox";
22269
22658
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -22296,16 +22685,16 @@ var FilesOutbox = class {
22296
22685
  backoffIndex = 0;
22297
22686
  stopped = false;
22298
22687
  constructor(opts) {
22299
- const base = opts.baseDir ?? path49.join(homeDir(), HOME_OUTBOX_DIR);
22300
- this.filePath = path49.join(base, `${opts.sessionId}.jsonl`);
22688
+ const base = opts.baseDir ?? path51.join(homeDir(), HOME_OUTBOX_DIR);
22689
+ this.filePath = path51.join(base, `${opts.sessionId}.jsonl`);
22301
22690
  this.post = opts.post;
22302
22691
  this.autoSchedule = opts.autoSchedule !== false;
22303
22692
  }
22304
22693
  /** Persist the entry to disk and trigger a flush. Returns once the
22305
22694
  * line is durable on disk (not once the POST succeeds). */
22306
22695
  async enqueue(entry) {
22307
- await fs42.mkdir(path49.dirname(this.filePath), { recursive: true });
22308
- await fs42.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
22696
+ await fs44.mkdir(path51.dirname(this.filePath), { recursive: true });
22697
+ await fs44.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
22309
22698
  this.backoffIndex = 0;
22310
22699
  if (this.autoSchedule) this.scheduleFlush(0);
22311
22700
  }
@@ -22394,7 +22783,7 @@ var FilesOutbox = class {
22394
22783
  async readAll() {
22395
22784
  let raw = "";
22396
22785
  try {
22397
- raw = await fs42.readFile(this.filePath, "utf8");
22786
+ raw = await fs44.readFile(this.filePath, "utf8");
22398
22787
  } catch {
22399
22788
  return [];
22400
22789
  }
@@ -22418,12 +22807,12 @@ var FilesOutbox = class {
22418
22807
  async rewrite(entries) {
22419
22808
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
22420
22809
  if (entries.length === 0) {
22421
- await fs42.unlink(this.filePath).catch(() => void 0);
22810
+ await fs44.unlink(this.filePath).catch(() => void 0);
22422
22811
  return;
22423
22812
  }
22424
22813
  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);
22814
+ await fs44.writeFile(tmpPath, payload, "utf8");
22815
+ await fs44.rename(tmpPath, this.filePath);
22427
22816
  }
22428
22817
  };
22429
22818
  function applyJitter(ms) {
@@ -24154,10 +24543,10 @@ var OutputService = class _OutputService {
24154
24543
  };
24155
24544
 
24156
24545
  // 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"));
24546
+ var fs45 = __toESM(require("fs"));
24547
+ var path52 = __toESM(require("path"));
24548
+ var os36 = __toESM(require("os"));
24549
+ var https8 = __toESM(require("https"));
24161
24550
  var http7 = __toESM(require("http"));
24162
24551
  var import_zod2 = require("zod");
24163
24552
  var historyRecordSchema = import_zod2.z.object({
@@ -24183,7 +24572,7 @@ function parseJsonl(filePath) {
24183
24572
  const messages = [];
24184
24573
  let raw;
24185
24574
  try {
24186
- raw = fs43.readFileSync(filePath, "utf8");
24575
+ raw = fs45.readFileSync(filePath, "utf8");
24187
24576
  } catch (err) {
24188
24577
  if (err.code !== "ENOENT") {
24189
24578
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -24223,7 +24612,7 @@ function post(endpoint, body, pluginAuthToken) {
24223
24612
  return new Promise((resolve7) => {
24224
24613
  const payload = JSON.stringify(body);
24225
24614
  const u2 = new URL(`${API_BASE9}${endpoint}`);
24226
- const transport = u2.protocol === "https:" ? https7 : http7;
24615
+ const transport = u2.protocol === "https:" ? https8 : http7;
24227
24616
  const req = transport.request(
24228
24617
  {
24229
24618
  hostname: u2.hostname,
@@ -24324,7 +24713,7 @@ var HistoryService = class _HistoryService {
24324
24713
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
24325
24714
  }
24326
24715
  get projectDir() {
24327
- return this.runtime.resolveHistoryDir(this.cwd) ?? path50.join(os35.homedir(), ".claude", "projects", encodeCwd(this.cwd));
24716
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path52.join(os36.homedir(), ".claude", "projects", encodeCwd(this.cwd));
24328
24717
  }
24329
24718
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
24330
24719
  setCurrentConversationId(id) {
@@ -24336,7 +24725,7 @@ var HistoryService = class _HistoryService {
24336
24725
  /** Return the current message count in the active conversation. */
24337
24726
  getCurrentMessageCount() {
24338
24727
  if (!this.currentConversationId) return 0;
24339
- const filePath = path50.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24728
+ const filePath = path52.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24340
24729
  return parseJsonl(filePath).length;
24341
24730
  }
24342
24731
  /**
@@ -24347,7 +24736,7 @@ var HistoryService = class _HistoryService {
24347
24736
  const deadline = Date.now() + timeoutMs;
24348
24737
  while (Date.now() < deadline) {
24349
24738
  if (!this.currentConversationId) return null;
24350
- const filePath = path50.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24739
+ const filePath = path52.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24351
24740
  const messages = parseJsonl(filePath);
24352
24741
  if (messages.length > previousCount) {
24353
24742
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -24373,16 +24762,16 @@ var HistoryService = class _HistoryService {
24373
24762
  const dir = this.projectDir;
24374
24763
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
24375
24764
  try {
24376
- const files = fs43.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
24765
+ const files = fs45.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
24377
24766
  try {
24378
- const stat3 = fs43.statSync(path50.join(dir, e.name));
24767
+ const stat3 = fs45.statSync(path52.join(dir, e.name));
24379
24768
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
24380
24769
  } catch {
24381
24770
  return { name: e.name, mtime: 0, birthtime: 0 };
24382
24771
  }
24383
24772
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
24384
24773
  if (files.length > 0) {
24385
- this.currentConversationId = path50.basename(files[0].name, ".jsonl");
24774
+ this.currentConversationId = path52.basename(files[0].name, ".jsonl");
24386
24775
  }
24387
24776
  } catch {
24388
24777
  }
@@ -24416,13 +24805,13 @@ var HistoryService = class _HistoryService {
24416
24805
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
24417
24806
  let entries;
24418
24807
  try {
24419
- entries = fs43.readdirSync(dir, { withFileTypes: true });
24808
+ entries = fs45.readdirSync(dir, { withFileTypes: true });
24420
24809
  } catch {
24421
24810
  return null;
24422
24811
  }
24423
24812
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
24424
24813
  try {
24425
- const stat3 = fs43.statSync(path50.join(dir, e.name));
24814
+ const stat3 = fs45.statSync(path52.join(dir, e.name));
24426
24815
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
24427
24816
  } catch {
24428
24817
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -24431,12 +24820,12 @@ var HistoryService = class _HistoryService {
24431
24820
  if (files.length === 0) return null;
24432
24821
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
24433
24822
  if (!files.some((f) => f.name === targetFile)) return null;
24434
- return this.extractUsageFromFile(path50.join(dir, targetFile));
24823
+ return this.extractUsageFromFile(path52.join(dir, targetFile));
24435
24824
  }
24436
24825
  extractUsageFromFile(filePath) {
24437
24826
  let raw;
24438
24827
  try {
24439
- raw = fs43.readFileSync(filePath, "utf8");
24828
+ raw = fs45.readFileSync(filePath, "utf8");
24440
24829
  } catch {
24441
24830
  return null;
24442
24831
  }
@@ -24481,9 +24870,9 @@ var HistoryService = class _HistoryService {
24481
24870
  let totalCost = 0;
24482
24871
  let files;
24483
24872
  try {
24484
- files = fs43.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
24873
+ files = fs45.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
24485
24874
  try {
24486
- return fs43.statSync(path50.join(projectDir, f)).mtimeMs >= monthStartMs;
24875
+ return fs45.statSync(path52.join(projectDir, f)).mtimeMs >= monthStartMs;
24487
24876
  } catch {
24488
24877
  return false;
24489
24878
  }
@@ -24494,7 +24883,7 @@ var HistoryService = class _HistoryService {
24494
24883
  for (const file of files) {
24495
24884
  let raw;
24496
24885
  try {
24497
- raw = fs43.readFileSync(path50.join(projectDir, file), "utf8");
24886
+ raw = fs45.readFileSync(path52.join(projectDir, file), "utf8");
24498
24887
  } catch {
24499
24888
  continue;
24500
24889
  }
@@ -24562,7 +24951,7 @@ var HistoryService = class _HistoryService {
24562
24951
  * showing an empty conversation.
24563
24952
  */
24564
24953
  async loadConversation(sessionId) {
24565
- const filePath = path50.join(this.projectDir, `${sessionId}.jsonl`);
24954
+ const filePath = path52.join(this.projectDir, `${sessionId}.jsonl`);
24566
24955
  const messages = parseJsonl(filePath);
24567
24956
  if (messages.length === 0) return;
24568
24957
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -24616,7 +25005,7 @@ var HistoryService = class _HistoryService {
24616
25005
  if (!this.currentConversationId) return 0;
24617
25006
  }
24618
25007
  const sessionId = this.currentConversationId;
24619
- const filePath = path50.join(this.projectDir, `${sessionId}.jsonl`);
25008
+ const filePath = path52.join(this.projectDir, `${sessionId}.jsonl`);
24620
25009
  const messages = parseJsonl(filePath);
24621
25010
  if (messages.length === 0) return 0;
24622
25011
  const marker = this.lastUploadedUuid.get(sessionId);
@@ -25042,15 +25431,15 @@ function fetchQuotaUsage(runtime, historySvc) {
25042
25431
  }
25043
25432
 
25044
25433
  // src/agents/claude/onboarding.ts
25045
- var fs44 = __toESM(require("fs"));
25046
- var os36 = __toESM(require("os"));
25047
- var path51 = __toESM(require("path"));
25434
+ var fs46 = __toESM(require("fs"));
25435
+ var os37 = __toESM(require("os"));
25436
+ var path53 = __toESM(require("path"));
25048
25437
  function ensureClaudeOnboarded() {
25049
25438
  try {
25050
- const file = path51.join(os36.homedir(), ".claude.json");
25439
+ const file = path53.join(os37.homedir(), ".claude.json");
25051
25440
  let config = {};
25052
25441
  try {
25053
- config = JSON.parse(fs44.readFileSync(file, "utf8"));
25442
+ config = JSON.parse(fs46.readFileSync(file, "utf8"));
25054
25443
  } catch {
25055
25444
  }
25056
25445
  if (config.hasCompletedOnboarding === true && typeof config.theme === "string") {
@@ -25061,8 +25450,8 @@ function ensureClaudeOnboarded() {
25061
25450
  if (typeof config.lastOnboardingVersion !== "string") {
25062
25451
  config.lastOnboardingVersion = "2.1.177";
25063
25452
  }
25064
- fs44.mkdirSync(path51.dirname(file), { recursive: true });
25065
- fs44.writeFileSync(file, JSON.stringify(config, null, 2));
25453
+ fs46.mkdirSync(path53.dirname(file), { recursive: true });
25454
+ fs46.writeFileSync(file, JSON.stringify(config, null, 2));
25066
25455
  log.info("claude", "pre-completed Claude onboarding (skip first-run theme picker)");
25067
25456
  } catch (err) {
25068
25457
  log.warn("claude", `ensureClaudeOnboarded failed (non-fatal): ${err.message}`);
@@ -25076,27 +25465,27 @@ async function start(requestedAgent) {
25076
25465
  if (!session) {
25077
25466
  if (requestedAgent) {
25078
25467
  const displayName = AGENT_REGISTRY[requestedAgent]?.displayName ?? requestedAgent;
25079
- console.log(` ${import_picocolors3.default.dim(`No paired ${displayName} session found.`)}`);
25468
+ console.log(` ${import_picocolors4.default.dim(`No paired ${displayName} session found.`)}`);
25080
25469
  console.log(
25081
- ` ${import_picocolors3.default.dim(`Run ${import_picocolors3.default.white("codeam pair")} from a ${displayName} setup to connect your mobile app.`)}
25470
+ ` ${import_picocolors4.default.dim(`Run ${import_picocolors4.default.white("codeam pair")} from a ${displayName} setup to connect your mobile app.`)}
25082
25471
  `
25083
25472
  );
25084
25473
  } 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.`)}
25474
+ console.log(` ${import_picocolors4.default.dim("No paired session found.")}`);
25475
+ console.log(` ${import_picocolors4.default.dim(`Run ${import_picocolors4.default.white("codeam pair")} to connect your mobile app.`)}
25087
25476
  `);
25088
25477
  }
25089
25478
  process.exit(0);
25090
25479
  }
25091
25480
  if (!acquireDaemonLock(session.id)) {
25092
- console.log(` ${import_picocolors3.default.dim("A codeam daemon for this session is already running \u2014 deferring to it.")}`);
25481
+ console.log(` ${import_picocolors4.default.dim("A codeam daemon for this session is already running \u2014 deferring to it.")}`);
25093
25482
  process.exit(0);
25094
25483
  }
25095
25484
  if (!session.agent) {
25096
25485
  throw new Error("Active session has no agent \u2014 re-pair with `codeam pair`.");
25097
25486
  }
25098
25487
  const pluginId = session.pluginId ?? ensurePluginId();
25099
- showInfo(`${session.userName} \xB7 ${import_picocolors3.default.cyan(session.plan)}`);
25488
+ showInfo(`${session.userName} \xB7 ${import_picocolors4.default.cyan(session.plan)}`);
25100
25489
  showInfo(`Launching ${AGENT_REGISTRY[session.agent].displayName}...
25101
25490
  `);
25102
25491
  identifyUser({
@@ -25370,7 +25759,7 @@ async function start(requestedAgent) {
25370
25759
 
25371
25760
  // src/commands/pair.ts
25372
25761
  var import_crypto7 = require("crypto");
25373
- var import_picocolors4 = __toESM(require("picocolors"));
25762
+ var import_picocolors5 = __toESM(require("picocolors"));
25374
25763
 
25375
25764
  // src/utils/agent-prompt.ts
25376
25765
  function parseAgentFlag(args2) {
@@ -25451,7 +25840,7 @@ async function pair(args2 = []) {
25451
25840
  process.exit(0);
25452
25841
  }
25453
25842
  showPairingCode(result.code);
25454
- console.log(import_picocolors4.default.dim(" Scan the QR code or enter the code in CodeAgent Mobile."));
25843
+ console.log(import_picocolors5.default.dim(" Scan the QR code or enter the code in CodeAgent Mobile."));
25455
25844
  console.log("");
25456
25845
  const waitSpin = dist_exports.spinner();
25457
25846
  const waitMessage = () => `Waiting for mobile app... \xB7 expires in ${formatRemaining(result.expiresAt)}`;
@@ -25566,7 +25955,7 @@ async function autoLinkAfterPair(opts) {
25566
25955
  }
25567
25956
 
25568
25957
  // src/commands/sessions.ts
25569
- var import_picocolors5 = __toESM(require("picocolors"));
25958
+ var import_picocolors6 = __toESM(require("picocolors"));
25570
25959
  async function sessions2(args2) {
25571
25960
  const [sub, id] = args2;
25572
25961
  if (sub === "switch") return switchSession();
@@ -25583,18 +25972,18 @@ function listSessions() {
25583
25972
  showIntro();
25584
25973
  const config = getConfig();
25585
25974
  if (config.sessions.length === 0) {
25586
- console.log(import_picocolors5.default.dim(" No paired sessions. Run codeam pair to connect.\n"));
25975
+ console.log(import_picocolors6.default.dim(" No paired sessions. Run codeam pair to connect.\n"));
25587
25976
  return;
25588
25977
  }
25589
- console.log(import_picocolors5.default.bold(" Paired sessions:\n"));
25978
+ console.log(import_picocolors6.default.bold(" Paired sessions:\n"));
25590
25979
  for (const s of config.sessions) {
25591
25980
  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());
25981
+ const bullet = isActive ? import_picocolors6.default.green(" \u25CF") : import_picocolors6.default.dim(" \u25CB");
25982
+ const name = isActive ? import_picocolors6.default.bold(s.userName) : s.userName;
25983
+ const plan = import_picocolors6.default.cyan(s.plan);
25984
+ const date = import_picocolors6.default.dim(new Date(s.pairedAt).toLocaleDateString());
25596
25985
  console.log(`${bullet} ${name} ${plan} ${date}`);
25597
- console.log(import_picocolors5.default.dim(` ${s.id}`));
25986
+ console.log(import_picocolors6.default.dim(` ${s.id}`));
25598
25987
  }
25599
25988
  console.log("");
25600
25989
  }
@@ -25612,7 +26001,7 @@ async function switchSession() {
25612
26001
  }
25613
26002
  setActiveSession(chosen);
25614
26003
  const s = config.sessions.find((x) => x.id === chosen);
25615
- console.log(import_picocolors5.default.green(`
26004
+ console.log(import_picocolors6.default.green(`
25616
26005
  \u2713 Switched to ${s?.userName ?? chosen}
25617
26006
  `));
25618
26007
  }
@@ -25630,29 +26019,29 @@ async function deleteSession(id) {
25630
26019
  return;
25631
26020
  }
25632
26021
  removeSession(id);
25633
- console.log(import_picocolors5.default.green("\n \u2713 Session deleted\n"));
26022
+ console.log(import_picocolors6.default.green("\n \u2713 Session deleted\n"));
25634
26023
  }
25635
26024
 
25636
26025
  // src/commands/status.ts
25637
- var import_picocolors6 = __toESM(require("picocolors"));
26026
+ var import_picocolors7 = __toESM(require("picocolors"));
25638
26027
  function status() {
25639
26028
  showIntro();
25640
26029
  const config = getConfig();
25641
26030
  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")}`);
26031
+ console.log(import_picocolors7.default.bold(" Status\n"));
26032
+ console.log(` Plugin ID ${import_picocolors7.default.dim(config.pluginId || "not generated yet")}`);
25644
26033
  console.log(` Sessions ${config.sessions.length} paired`);
25645
26034
  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)}`);
26035
+ console.log(` Active ${import_picocolors7.default.bold(active.userName)} ${import_picocolors7.default.cyan(active.plan)}`);
26036
+ console.log(` Session ID ${import_picocolors7.default.dim(active.id)}`);
25648
26037
  } else {
25649
- console.log(` Active ${import_picocolors6.default.yellow("none")} ${import_picocolors6.default.dim("run codeam pair to connect")}`);
26038
+ console.log(` Active ${import_picocolors7.default.yellow("none")} ${import_picocolors7.default.dim("run codeam pair to connect")}`);
25650
26039
  }
25651
26040
  console.log("");
25652
26041
  }
25653
26042
 
25654
26043
  // src/commands/logout.ts
25655
- var import_picocolors7 = __toESM(require("picocolors"));
26044
+ var import_picocolors8 = __toESM(require("picocolors"));
25656
26045
  var API_BASE11 = resolveApiBaseUrl();
25657
26046
  async function notifyBackendOffline() {
25658
26047
  const cfg = loadCliConfig();
@@ -25686,17 +26075,17 @@ async function logout() {
25686
26075
  }
25687
26076
  await notifyBackendOffline();
25688
26077
  clearAll();
25689
- console.log(import_picocolors7.default.green("\n \u2713 Done. All sessions removed.\n"));
26078
+ console.log(import_picocolors8.default.green("\n \u2713 Done. All sessions removed.\n"));
25690
26079
  }
25691
26080
 
25692
26081
  // src/commands/deploy.ts
25693
- var import_picocolors10 = __toESM(require("picocolors"));
26082
+ var import_picocolors11 = __toESM(require("picocolors"));
25694
26083
 
25695
26084
  // src/services/providers/github-codespaces.ts
25696
26085
  var import_child_process23 = require("child_process");
25697
26086
  var import_util4 = require("util");
25698
- var import_picocolors8 = __toESM(require("picocolors"));
25699
- var path52 = __toESM(require("path"));
26087
+ var import_picocolors9 = __toESM(require("picocolors"));
26088
+ var path54 = __toESM(require("path"));
25700
26089
  var execFileP6 = (0, import_util4.promisify)(import_child_process23.execFile);
25701
26090
  var MAX_BUFFER = 8 * 1024 * 1024;
25702
26091
  function resetStdinForChild() {
@@ -25763,7 +26152,7 @@ var GitHubCodespacesProvider = class {
25763
26152
  if (expectedUser) {
25764
26153
  noteLines.push("");
25765
26154
  noteLines.push(
25766
- `${import_picocolors8.default.yellow("\u26A0")} Sign in as ${import_picocolors8.default.cyan(expectedUser)} in the browser.`
26155
+ `${import_picocolors9.default.yellow("\u26A0")} Sign in as ${import_picocolors9.default.cyan(expectedUser)} in the browser.`
25767
26156
  );
25768
26157
  noteLines.push(
25769
26158
  " If a different GitHub account is already signed in, sign out"
@@ -25786,7 +26175,7 @@ var GitHubCodespacesProvider = class {
25786
26175
  if (refreshCode !== 0) {
25787
26176
  const lines = [
25788
26177
  "The browser approval came back for a different GitHub account",
25789
- `than the one gh is configured for${expectedUser ? ` (${import_picocolors8.default.cyan(expectedUser)})` : ""}.`,
26178
+ `than the one gh is configured for${expectedUser ? ` (${import_picocolors9.default.cyan(expectedUser)})` : ""}.`,
25790
26179
  "",
25791
26180
  "To recover:",
25792
26181
  " 1. Open https://github.com and sign out of any non-target",
@@ -25795,7 +26184,7 @@ var GitHubCodespacesProvider = class {
25795
26184
  "",
25796
26185
  "You can also grant the scope manually first and skip this step",
25797
26186
  "on the next run:",
25798
- ` ${import_picocolors8.default.cyan("gh auth refresh -h github.com -s codespace")}`
26187
+ ` ${import_picocolors9.default.cyan("gh auth refresh -h github.com -s codespace")}`
25799
26188
  ];
25800
26189
  throw new Error(lines.join("\n"));
25801
26190
  }
@@ -25862,7 +26251,7 @@ var GitHubCodespacesProvider = class {
25862
26251
  async tryInstallGh() {
25863
26252
  const platform3 = process.platform;
25864
26253
  wt(
25865
- `GitHub CLI (${import_picocolors8.default.cyan("gh")}) is required for Codespaces deploys but isn't on your PATH.`,
26254
+ `GitHub CLI (${import_picocolors9.default.cyan("gh")}) is required for Codespaces deploys but isn't on your PATH.`,
25866
26255
  "Heads up"
25867
26256
  );
25868
26257
  if (platform3 === "linux") {
@@ -25918,7 +26307,7 @@ var GitHubCodespacesProvider = class {
25918
26307
  return;
25919
26308
  }
25920
26309
  const proceed = await ot2({
25921
- message: `Run ${import_picocolors8.default.cyan(installCmd.describe)} now?`,
26310
+ message: `Run ${import_picocolors9.default.cyan(installCmd.describe)} now?`,
25922
26311
  initialValue: true
25923
26312
  });
25924
26313
  if (q(proceed) || !proceed) return;
@@ -26185,7 +26574,7 @@ var GitHubCodespacesProvider = class {
26185
26574
  });
26186
26575
  }
26187
26576
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
26188
- const remoteDir = path52.posix.dirname(remotePath);
26577
+ const remoteDir = path54.posix.dirname(remotePath);
26189
26578
  const parts = [
26190
26579
  `mkdir -p ${shellQuote(remoteDir)}`,
26191
26580
  `cat > ${shellQuote(remotePath)}`
@@ -26255,8 +26644,8 @@ function shellQuote(s) {
26255
26644
  // src/services/providers/gitpod.ts
26256
26645
  var import_child_process24 = require("child_process");
26257
26646
  var import_util5 = require("util");
26258
- var path53 = __toESM(require("path"));
26259
- var import_picocolors9 = __toESM(require("picocolors"));
26647
+ var path55 = __toESM(require("path"));
26648
+ var import_picocolors10 = __toESM(require("picocolors"));
26260
26649
  var execFileP7 = (0, import_util5.promisify)(import_child_process24.execFile);
26261
26650
  var MAX_BUFFER2 = 8 * 1024 * 1024;
26262
26651
  function resetStdinForChild2() {
@@ -26495,7 +26884,7 @@ var GitpodProvider = class {
26495
26884
  });
26496
26885
  }
26497
26886
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
26498
- const remoteDir = path53.posix.dirname(remotePath);
26887
+ const remoteDir = path55.posix.dirname(remotePath);
26499
26888
  const parts = [
26500
26889
  `mkdir -p ${shellQuote2(remoteDir)}`,
26501
26890
  `cat > ${shellQuote2(remotePath)}`
@@ -26531,7 +26920,7 @@ function shellQuote2(s) {
26531
26920
  // src/services/providers/gitlab-workspaces.ts
26532
26921
  var import_child_process25 = require("child_process");
26533
26922
  var import_util6 = require("util");
26534
- var path54 = __toESM(require("path"));
26923
+ var path56 = __toESM(require("path"));
26535
26924
  var execFileP8 = (0, import_util6.promisify)(import_child_process25.execFile);
26536
26925
  var MAX_BUFFER3 = 8 * 1024 * 1024;
26537
26926
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -26791,7 +27180,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
26791
27180
  }
26792
27181
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
26793
27182
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
26794
- const remoteDir = path54.posix.dirname(remotePath);
27183
+ const remoteDir = path56.posix.dirname(remotePath);
26795
27184
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
26796
27185
  if (options.mode != null) {
26797
27186
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -26859,7 +27248,7 @@ function shellQuote3(s) {
26859
27248
  // src/services/providers/railway.ts
26860
27249
  var import_child_process26 = require("child_process");
26861
27250
  var import_util7 = require("util");
26862
- var path55 = __toESM(require("path"));
27251
+ var path57 = __toESM(require("path"));
26863
27252
  var execFileP9 = (0, import_util7.promisify)(import_child_process26.execFile);
26864
27253
  var MAX_BUFFER4 = 8 * 1024 * 1024;
26865
27254
  function resetStdinForChild4() {
@@ -27095,7 +27484,7 @@ var RailwayProvider = class {
27095
27484
  if (!projectId || !serviceId) {
27096
27485
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
27097
27486
  }
27098
- const remoteDir = path55.posix.dirname(remotePath);
27487
+ const remoteDir = path57.posix.dirname(remotePath);
27099
27488
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
27100
27489
  if (options.mode != null) {
27101
27490
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -27136,7 +27525,7 @@ var PROVIDERS = [
27136
27525
  // src/commands/deploy.ts
27137
27526
  async function deploy(args2 = []) {
27138
27527
  console.log();
27139
- mt(import_picocolors10.default.bgMagenta(import_picocolors10.default.white(" codeam deploy ")));
27528
+ mt(import_picocolors11.default.bgMagenta(import_picocolors11.default.white(" codeam deploy ")));
27140
27529
  const provider = await pickProvider();
27141
27530
  if (!provider) {
27142
27531
  pt("No provider selected.");
@@ -27173,7 +27562,7 @@ async function deploy(args2 = []) {
27173
27562
  if (provider.expandListScopes) {
27174
27563
  options.push({
27175
27564
  value: EXPAND_SCOPES,
27176
- label: import_picocolors10.default.cyan("+ Don't see your project? Expand scopes\u2026"),
27565
+ label: import_picocolors11.default.cyan("+ Don't see your project? Expand scopes\u2026"),
27177
27566
  hint: "Re-authorize with broader scopes (org / team repos)"
27178
27567
  });
27179
27568
  }
@@ -27221,7 +27610,7 @@ async function deploy(args2 = []) {
27221
27610
  label: w3.displayName ?? w3.id,
27222
27611
  hint: [w3.state, formatLastUsed(w3.lastUsedAt)].filter(Boolean).join(" \xB7 ")
27223
27612
  })),
27224
- { value: "__new__", label: import_picocolors10.default.green("+ Create a new workspace"), hint: "fresh codespace" }
27613
+ { value: "__new__", label: import_picocolors11.default.green("+ Create a new workspace"), hint: "fresh codespace" }
27225
27614
  ]
27226
27615
  });
27227
27616
  if (q(choice)) {
@@ -27322,12 +27711,12 @@ async function deploy(args2 = []) {
27322
27711
  cliStep.stop("\u2713 codeam-cli installed");
27323
27712
  wt(
27324
27713
  [
27325
- `Workspace: ${import_picocolors10.default.cyan(workspace.displayName ?? workspace.id)}`,
27326
- workspace.webUrl ? `Web: ${import_picocolors10.default.cyan(workspace.webUrl)}` : "",
27714
+ `Workspace: ${import_picocolors11.default.cyan(workspace.displayName ?? workspace.id)}`,
27715
+ workspace.webUrl ? `Web: ${import_picocolors11.default.cyan(workspace.webUrl)}` : "",
27327
27716
  "",
27328
27717
  `Starting \`codeam pair\` on the workspace (agent: ${AGENT_REGISTRY[agentId].displayName}).`,
27329
27718
  "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.)")
27719
+ import_picocolors11.default.dim("(Once paired, this terminal disconnects automatically; the session stays alive on the codespace.)")
27331
27720
  ].filter(Boolean).join("\n"),
27332
27721
  "Almost there"
27333
27722
  );
@@ -27442,11 +27831,11 @@ async function deploy(args2 = []) {
27442
27831
  ].join("\n");
27443
27832
  const code = (await provider.streamCommand(workspace.id, `bash -lc ${shellQuoteSingle(wrapper)}`)).code;
27444
27833
  if (code === 0) {
27445
- gt(import_picocolors10.default.green("\u2713 Workspace deployed and paired. Drive from your phone, anywhere."));
27834
+ gt(import_picocolors11.default.green("\u2713 Workspace deployed and paired. Drive from your phone, anywhere."));
27446
27835
  } else if (code === 130) {
27447
- gt(import_picocolors10.default.yellow("Disconnected from local terminal. Mobile session keeps running on the codespace."));
27836
+ gt(import_picocolors11.default.yellow("Disconnected from local terminal. Mobile session keeps running on the codespace."));
27448
27837
  } else {
27449
- gt(import_picocolors10.default.yellow('Pairing did not complete. Run "codeam pair" inside the codespace if needed.'));
27838
+ gt(import_picocolors11.default.yellow('Pairing did not complete. Run "codeam pair" inside the codespace if needed.'));
27450
27839
  }
27451
27840
  }
27452
27841
  function shellQuoteSingle(s) {
@@ -27480,7 +27869,7 @@ async function pickProvider() {
27480
27869
  message: "Where do you want to deploy?",
27481
27870
  options: PROVIDERS.map((prov) => ({
27482
27871
  value: prov.id,
27483
- label: prov.available ? prov.displayName : `${prov.displayName} ${import_picocolors10.default.dim("(coming soon)")}`,
27872
+ label: prov.available ? prov.displayName : `${prov.displayName} ${import_picocolors11.default.dim("(coming soon)")}`,
27484
27873
  hint: prov.tagline
27485
27874
  }))
27486
27875
  });
@@ -27497,27 +27886,27 @@ async function pickProvider() {
27497
27886
  }
27498
27887
 
27499
27888
  // src/commands/deploy-manage.ts
27500
- var import_picocolors11 = __toESM(require("picocolors"));
27889
+ var import_picocolors12 = __toESM(require("picocolors"));
27501
27890
  async function deployList() {
27502
27891
  console.log();
27503
- mt(import_picocolors11.default.bgMagenta(import_picocolors11.default.white(" codeam deploy ls ")));
27892
+ mt(import_picocolors12.default.bgMagenta(import_picocolors12.default.white(" codeam deploy ls ")));
27504
27893
  const workspaces = await collectWorkspacesWithStatus();
27505
27894
  if (workspaces.length === 0) {
27506
- gt(import_picocolors11.default.dim("No deployed workspaces found."));
27895
+ gt(import_picocolors12.default.dim("No deployed workspaces found."));
27507
27896
  return;
27508
27897
  }
27509
27898
  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 + ")")}`);
27899
+ 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"}`);
27900
+ console.log(` ${tag} ${import_picocolors12.default.cyan(w3.displayName ?? w3.id)} ${import_picocolors12.default.dim("(" + w3.providerName + ")")}`);
27512
27901
  }
27513
- gt(import_picocolors11.default.dim("Use `codeam deploy stop` to terminate a session."));
27902
+ gt(import_picocolors12.default.dim("Use `codeam deploy stop` to terminate a session."));
27514
27903
  }
27515
27904
  async function deployStop() {
27516
27905
  console.log();
27517
- mt(import_picocolors11.default.bgMagenta(import_picocolors11.default.white(" codeam deploy stop ")));
27906
+ mt(import_picocolors12.default.bgMagenta(import_picocolors12.default.white(" codeam deploy stop ")));
27518
27907
  const workspaces = await collectWorkspacesWithStatus();
27519
27908
  if (workspaces.length === 0) {
27520
- gt(import_picocolors11.default.dim("No deployed workspaces found."));
27909
+ gt(import_picocolors12.default.dim("No deployed workspaces found."));
27521
27910
  return;
27522
27911
  }
27523
27912
  const choice = await _t({
@@ -27527,7 +27916,7 @@ async function deployStop() {
27527
27916
  label: w3.displayName ?? w3.id,
27528
27917
  hint: [
27529
27918
  w3.providerName,
27530
- w3.codeamRunning ? import_picocolors11.default.green("\u25CF codeam-pair running") : import_picocolors11.default.dim("\u25CB no codeam-pair"),
27919
+ w3.codeamRunning ? import_picocolors12.default.green("\u25CF codeam-pair running") : import_picocolors12.default.dim("\u25CB no codeam-pair"),
27531
27920
  w3.state ?? ""
27532
27921
  ].filter(Boolean).join(" \xB7 ")
27533
27922
  }))
@@ -27555,7 +27944,7 @@ async function deployStop() {
27555
27944
  O2.info("No codeam-pair process to stop on this workspace.");
27556
27945
  }
27557
27946
  const alsoStop = await ot2({
27558
- message: `Also stop the workspace ${import_picocolors11.default.cyan(target.displayName ?? target.id)} to save compute hours?`,
27947
+ message: `Also stop the workspace ${import_picocolors12.default.cyan(target.displayName ?? target.id)} to save compute hours?`,
27559
27948
  initialValue: true
27560
27949
  });
27561
27950
  if (!q(alsoStop) && alsoStop) {
@@ -27577,7 +27966,7 @@ async function deployStop() {
27577
27966
  O2.warn(err instanceof Error ? err.message : String(err));
27578
27967
  }
27579
27968
  }
27580
- gt(import_picocolors11.default.green("\u2713 Done."));
27969
+ gt(import_picocolors12.default.green("\u2713 Done."));
27581
27970
  }
27582
27971
  async function collectWorkspacesWithStatus() {
27583
27972
  const out2 = [];
@@ -27683,9 +28072,9 @@ async function host(args2) {
27683
28072
  var import_node_dns = require("dns");
27684
28073
  var import_node_util5 = require("util");
27685
28074
  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"));
28075
+ var fs47 = __toESM(require("fs"));
28076
+ var path58 = __toESM(require("path"));
28077
+ var import_picocolors13 = __toESM(require("picocolors"));
27689
28078
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
27690
28079
  async function checkDns(apiBase2) {
27691
28080
  const host2 = (() => {
@@ -27740,13 +28129,13 @@ async function checkHealth(apiBase2) {
27740
28129
  }
27741
28130
  }
27742
28131
  function checkConfigDir() {
27743
- const dir = path56.join(require("os").homedir(), ".codeam");
28132
+ const dir = path58.join(require("os").homedir(), ".codeam");
27744
28133
  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);
28134
+ fs47.mkdirSync(dir, { recursive: true, mode: 448 });
28135
+ const probe = path58.join(dir, ".doctor-probe");
28136
+ fs47.writeFileSync(probe, "ok", { mode: 384 });
28137
+ const read2 = fs47.readFileSync(probe, "utf8");
28138
+ fs47.unlinkSync(probe);
27750
28139
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
27751
28140
  return {
27752
28141
  id: "config-dir",
@@ -27810,7 +28199,7 @@ function checkNodePty() {
27810
28199
  detail: "not required on this platform"
27811
28200
  };
27812
28201
  }
27813
- const vendoredPath = path56.join(__dirname, "vendor", "node-pty");
28202
+ const vendoredPath = path58.join(__dirname, "vendor", "node-pty");
27814
28203
  for (const target of [vendoredPath, "node-pty"]) {
27815
28204
  try {
27816
28205
  require(target);
@@ -27852,7 +28241,7 @@ function checkChokidar() {
27852
28241
  }
27853
28242
  async function doctor(args2 = []) {
27854
28243
  const json = args2.includes("--json");
27855
- const cliVersion = true ? "2.39.54" : "0.0.0-dev";
28244
+ const cliVersion = true ? "2.39.55" : "0.0.0-dev";
27856
28245
  const apiBase2 = resolveApiBaseUrl();
27857
28246
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
27858
28247
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -27892,46 +28281,46 @@ async function doctor(args2 = []) {
27892
28281
  function printHumanReport(r) {
27893
28282
  const out2 = process.stderr;
27894
28283
  out2.write(`
27895
- ${import_picocolors12.default.bold(" codeam doctor")}
28284
+ ${import_picocolors13.default.bold(" codeam doctor")}
27896
28285
 
27897
28286
  `);
27898
- out2.write(` ${import_picocolors12.default.dim("cli")} ${r.cliVersion}
28287
+ out2.write(` ${import_picocolors13.default.dim("cli")} ${r.cliVersion}
27899
28288
  `);
27900
- out2.write(` ${import_picocolors12.default.dim("node")} ${r.node}
28289
+ out2.write(` ${import_picocolors13.default.dim("node")} ${r.node}
27901
28290
  `);
27902
- out2.write(` ${import_picocolors12.default.dim("os")} ${r.platform} ${r.arch}
28291
+ out2.write(` ${import_picocolors13.default.dim("os")} ${r.platform} ${r.arch}
27903
28292
  `);
27904
- out2.write(` ${import_picocolors12.default.dim("api")} ${r.apiBase}
28293
+ out2.write(` ${import_picocolors13.default.dim("api")} ${r.apiBase}
27905
28294
  `);
27906
28295
  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")}
28296
+ out2.write(` ${import_picocolors13.default.dim("mode")} ${import_picocolors13.default.yellow("TEST_MODE \u2014 using dev preview")}
27908
28297
  `);
27909
28298
  } else if (process.env.CODEAM_API_URL) {
27910
- out2.write(` ${import_picocolors12.default.dim("mode")} ${import_picocolors12.default.yellow("CODEAM_API_URL override")}
28299
+ out2.write(` ${import_picocolors13.default.dim("mode")} ${import_picocolors13.default.yellow("CODEAM_API_URL override")}
27911
28300
  `);
27912
28301
  }
27913
- out2.write(` ${import_picocolors12.default.dim("diag id")} ${r.diagnosticId}
28302
+ out2.write(` ${import_picocolors13.default.dim("diag id")} ${r.diagnosticId}
27914
28303
  `);
27915
28304
  out2.write("\n");
27916
28305
  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}`)}
28306
+ const mark = c2.ok ? import_picocolors13.default.green("\u2713") : c2.optional ? import_picocolors13.default.yellow("!") : import_picocolors13.default.red("\u2717");
28307
+ out2.write(` ${mark} ${c2.label}${import_picocolors13.default.dim(` \u2014 ${c2.detail}`)}
27919
28308
  `);
27920
28309
  if (!c2.ok && c2.hint) {
27921
28310
  for (const line of c2.hint.split("\n")) {
27922
- out2.write(` ${import_picocolors12.default.dim(line)}
28311
+ out2.write(` ${import_picocolors13.default.dim(line)}
27923
28312
  `);
27924
28313
  }
27925
28314
  }
27926
28315
  }
27927
28316
  out2.write("\n");
27928
28317
  if (r.ok) {
27929
- out2.write(` ${import_picocolors12.default.green("All checks passed.")}
28318
+ out2.write(` ${import_picocolors13.default.green("All checks passed.")}
27930
28319
 
27931
28320
  `);
27932
28321
  } else {
27933
28322
  out2.write(
27934
- ` ${import_picocolors12.default.red("Some checks failed.")} ${import_picocolors12.default.dim("Paste the diagnostic id above when opening a bug report.")}
28323
+ ` ${import_picocolors13.default.red("Some checks failed.")} ${import_picocolors13.default.dim("Paste the diagnostic id above when opening a bug report.")}
27935
28324
 
27936
28325
  `
27937
28326
  );
@@ -28049,118 +28438,118 @@ async function completion(args2) {
28049
28438
  }
28050
28439
 
28051
28440
  // src/commands/version.ts
28052
- var import_picocolors13 = __toESM(require("picocolors"));
28441
+ var import_picocolors14 = __toESM(require("picocolors"));
28053
28442
  function version2() {
28054
- const v = true ? "2.39.54" : "unknown";
28055
- console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
28443
+ const v = true ? "2.39.55" : "unknown";
28444
+ console.log(`${import_picocolors14.default.bold("codeam-cli")} ${import_picocolors14.default.cyan(v)}`);
28056
28445
  }
28057
28446
 
28058
28447
  // src/commands/help.ts
28059
- var import_picocolors14 = __toESM(require("picocolors"));
28448
+ var import_picocolors15 = __toESM(require("picocolors"));
28060
28449
  function help() {
28061
28450
  const lines = [
28062
28451
  "",
28063
- ` ${import_picocolors14.default.bold(import_picocolors14.default.magenta("codeam-cli"))} ${import_picocolors14.default.dim("\u2014 remote-control AI coding agents from your phone")}`,
28452
+ ` ${import_picocolors15.default.bold(import_picocolors15.default.magenta("codeam-cli"))} ${import_picocolors15.default.dim("\u2014 remote-control AI coding agents from your phone")}`,
28064
28453
  "",
28065
- ` ${import_picocolors14.default.bold("Usage")}`,
28066
- ` ${import_picocolors14.default.cyan("codeam")} ${import_picocolors14.default.dim("[command]")}`,
28454
+ ` ${import_picocolors15.default.bold("Usage")}`,
28455
+ ` ${import_picocolors15.default.cyan("codeam")} ${import_picocolors15.default.dim("[command]")}`,
28067
28456
  "",
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")}`,
28457
+ ` ${import_picocolors15.default.bold("Commands")}`,
28458
+ ` ${import_picocolors15.default.white("codeam")} ${import_picocolors15.default.dim("start the active agent with mobile control")}`,
28459
+ ` ${import_picocolors15.default.white("codeam <agent>")} ${import_picocolors15.default.dim("start a specific agent \u2014 e.g. claude, codex")}`,
28460
+ ` ${import_picocolors15.default.white("codeam pair")} ${import_picocolors15.default.dim("pair a new mobile device (interactive)")}`,
28461
+ ` ${import_picocolors15.default.white("codeam pair --agent <id>")} ${import_picocolors15.default.dim("pair non-interactively for a specific agent")}`,
28462
+ ` ${import_picocolors15.default.white("codeam sessions")} ${import_picocolors15.default.dim("list paired devices")}`,
28463
+ ` ${import_picocolors15.default.white("codeam sessions switch")} ${import_picocolors15.default.dim("switch the active paired session")}`,
28464
+ ` ${import_picocolors15.default.white("codeam sessions delete <id>")} ${import_picocolors15.default.dim("remove a specific paired session")}`,
28465
+ ` ${import_picocolors15.default.white("codeam status")} ${import_picocolors15.default.dim("show connection info")}`,
28466
+ ` ${import_picocolors15.default.white("codeam logout")} ${import_picocolors15.default.dim("remove all paired sessions")}`,
28467
+ ` ${import_picocolors15.default.white("codeam link <agent>")} ${import_picocolors15.default.dim("link an agent (claude, codex) to your CodeAgent account")}`,
28468
+ ` ${import_picocolors15.default.white("codeam deploy")} ${import_picocolors15.default.dim("provision a cloud workspace (Codespaces) and pair it")}`,
28469
+ ` ${import_picocolors15.default.white("codeam deploy ls | list")} ${import_picocolors15.default.dim("list deployed cloud workspaces")}`,
28470
+ ` ${import_picocolors15.default.white("codeam deploy stop | remove")} ${import_picocolors15.default.dim("stop a deployed workspace session")}`,
28471
+ ` ${import_picocolors15.default.white("codeam doctor")} ${import_picocolors15.default.dim("run diagnostic checks (DNS, /health, binaries, \u2026)")}`,
28472
+ ` ${import_picocolors15.default.white("codeam completion <shell>")} ${import_picocolors15.default.dim("emit a bash/zsh/fish completion script")}`,
28084
28473
  "",
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")}`,
28474
+ ` ${import_picocolors15.default.bold("Flags")}`,
28475
+ ` ${import_picocolors15.default.white("-v, --version")} ${import_picocolors15.default.dim("print the CLI version")}`,
28476
+ ` ${import_picocolors15.default.white("-h, --help")} ${import_picocolors15.default.dim("show this help")}`,
28088
28477
  "",
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")}`,
28478
+ ` ${import_picocolors15.default.bold("Links")}`,
28479
+ ` ${import_picocolors15.default.dim("Docs:")} ${import_picocolors15.default.green("https://www.codeagent-mobile.com")}`,
28480
+ ` ${import_picocolors15.default.dim("Issues:")} ${import_picocolors15.default.green("https://github.com/edgar-durand/codeagent-mobile-clients/issues")}`,
28092
28481
  ""
28093
28482
  ];
28094
28483
  process.stdout.write(lines.join("\n") + "\n");
28095
28484
  }
28096
28485
 
28097
28486
  // src/commands/subcommand-help.ts
28098
- var import_picocolors15 = __toESM(require("picocolors"));
28487
+ var import_picocolors16 = __toESM(require("picocolors"));
28099
28488
  var HELPS = {
28100
28489
  pair: () => print([
28101
- ` ${import_picocolors15.default.bold("codeam pair")} ${import_picocolors15.default.dim("\u2014 pair a mobile device with this CLI")}`,
28490
+ ` ${import_picocolors16.default.bold("codeam pair")} ${import_picocolors16.default.dim("\u2014 pair a mobile device with this CLI")}`,
28102
28491
  "",
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")}`
28492
+ ` ${import_picocolors16.default.cyan("codeam pair")} ${import_picocolors16.default.dim("interactive pairing (prompts for the agent)")}`,
28493
+ ` ${import_picocolors16.default.cyan("codeam pair --agent <id>")} ${import_picocolors16.default.dim("pair non-interactively (agent: claude | codex)")}`,
28494
+ ` ${import_picocolors16.default.cyan("codeam pair --dry-run")} ${import_picocolors16.default.dim("request a pairing code, validate the response, exit")}`
28106
28495
  ]),
28107
28496
  "pair-auto": () => print([
28108
- ` ${import_picocolors15.default.bold("codeam pair-auto")} ${import_picocolors15.default.dim("\u2014 non-interactive variant of pair for scripted setups")}`,
28497
+ ` ${import_picocolors16.default.bold("codeam pair-auto")} ${import_picocolors16.default.dim("\u2014 non-interactive variant of pair for scripted setups")}`,
28109
28498
  "",
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")}`
28499
+ ` ${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
28500
  ]),
28112
28501
  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")}`,
28502
+ ` ${import_picocolors16.default.bold("codeam link <agent>")} ${import_picocolors16.default.dim("\u2014 upload a local agent token (Claude or Codex) to your vault")}`,
28114
28503
  "",
28115
- ` ${import_picocolors15.default.cyan("codeam link claude")}`,
28116
- ` ${import_picocolors15.default.cyan("codeam link codex")}`,
28504
+ ` ${import_picocolors16.default.cyan("codeam link claude")}`,
28505
+ ` ${import_picocolors16.default.cyan("codeam link codex")}`,
28117
28506
  "",
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")}`
28507
+ ` ${import_picocolors16.default.white("--api-key=<key>")} ${import_picocolors16.default.dim("paste an API key directly (visible in `ps -ef`)")}`,
28508
+ ` ${import_picocolors16.default.white("--api-key-file=<path>")} ${import_picocolors16.default.dim("read API key from a file (recommended for CI / scripts)")}`,
28509
+ ` ${import_picocolors16.default.white("--reuse-existing")} ${import_picocolors16.default.dim("upload existing creds without re-launching the agent login")}`,
28510
+ ` ${import_picocolors16.default.white("--token-file=<path>")} ${import_picocolors16.default.dim("manual credential blob path for unusual vendor locations")}`,
28511
+ ` ${import_picocolors16.default.white("--dry-run")} ${import_picocolors16.default.dim("probe the /api/plugin/agents/<agent>/link endpoint and exit")}`
28123
28512
  ]),
28124
28513
  sessions: () => print([
28125
- ` ${import_picocolors15.default.bold("codeam sessions")} ${import_picocolors15.default.dim("\u2014 list, switch, or delete paired mobile sessions")}`,
28514
+ ` ${import_picocolors16.default.bold("codeam sessions")} ${import_picocolors16.default.dim("\u2014 list, switch, or delete paired mobile sessions")}`,
28126
28515
  "",
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")}`
28516
+ ` ${import_picocolors16.default.cyan("codeam sessions")} ${import_picocolors16.default.dim("list all paired sessions on this machine")}`,
28517
+ ` ${import_picocolors16.default.cyan("codeam sessions switch")} ${import_picocolors16.default.dim("interactively switch the active session")}`,
28518
+ ` ${import_picocolors16.default.cyan("codeam sessions delete <id>")} ${import_picocolors16.default.dim("remove a specific paired session")}`
28130
28519
  ]),
28131
28520
  deploy: () => print([
28132
- ` ${import_picocolors15.default.bold("codeam deploy")} ${import_picocolors15.default.dim("\u2014 provision a cloud workspace (GitHub Codespaces) and pair it")}`,
28521
+ ` ${import_picocolors16.default.bold("codeam deploy")} ${import_picocolors16.default.dim("\u2014 provision a cloud workspace (GitHub Codespaces) and pair it")}`,
28133
28522
  "",
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")}`
28523
+ ` ${import_picocolors16.default.cyan("codeam deploy")} ${import_picocolors16.default.dim("start a new deploy (prompts for repo + agent)")}`,
28524
+ ` ${import_picocolors16.default.cyan("codeam deploy ls | list")} ${import_picocolors16.default.dim("list deployed cloud workspaces")}`,
28525
+ ` ${import_picocolors16.default.cyan("codeam deploy stop | remove")} ${import_picocolors16.default.dim("pick a workspace and stop its codeam-pair session")}`
28137
28526
  ]),
28138
28527
  status: () => print([
28139
- ` ${import_picocolors15.default.bold("codeam status")} ${import_picocolors15.default.dim("\u2014 show the active session, agent, and connection info")}`
28528
+ ` ${import_picocolors16.default.bold("codeam status")} ${import_picocolors16.default.dim("\u2014 show the active session, agent, and connection info")}`
28140
28529
  ]),
28141
28530
  logout: () => print([
28142
- ` ${import_picocolors15.default.bold("codeam logout")} ${import_picocolors15.default.dim("\u2014 remove every paired session from this machine")}`
28531
+ ` ${import_picocolors16.default.bold("codeam logout")} ${import_picocolors16.default.dim("\u2014 remove every paired session from this machine")}`
28143
28532
  ]),
28144
28533
  doctor: () => print([
28145
- ` ${import_picocolors15.default.bold("codeam doctor")} ${import_picocolors15.default.dim("\u2014 run diagnostic checks for support triage")}`,
28534
+ ` ${import_picocolors16.default.bold("codeam doctor")} ${import_picocolors16.default.dim("\u2014 run diagnostic checks for support triage")}`,
28146
28535
  "",
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)")}`,
28536
+ ` ${import_picocolors16.default.cyan("codeam doctor")} ${import_picocolors16.default.dim("human-readable report")}`,
28537
+ ` ${import_picocolors16.default.cyan("codeam doctor --json")} ${import_picocolors16.default.dim("machine-parseable report (single JSON document on stdout)")}`,
28149
28538
  "",
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.")}`
28539
+ ` ${import_picocolors16.default.dim("Output never includes tokens or credentials. Paste the diagnostic id")}`,
28540
+ ` ${import_picocolors16.default.dim("into a bug report so support can grep the server-side logs.")}`
28152
28541
  ]),
28153
28542
  completion: () => print([
28154
- ` ${import_picocolors15.default.bold("codeam completion <shell>")} ${import_picocolors15.default.dim("\u2014 emit a shell-completion script for sourcing")}`,
28543
+ ` ${import_picocolors16.default.bold("codeam completion <shell>")} ${import_picocolors16.default.dim("\u2014 emit a shell-completion script for sourcing")}`,
28155
28544
  "",
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")}`,
28545
+ ` ${import_picocolors16.default.cyan("codeam completion bash")} ${import_picocolors16.default.dim("print a bash completion function")}`,
28546
+ ` ${import_picocolors16.default.cyan("codeam completion zsh")} ${import_picocolors16.default.dim("print a zsh completion function")}`,
28547
+ ` ${import_picocolors16.default.cyan("codeam completion fish")} ${import_picocolors16.default.dim("print a fish completion file")}`,
28159
28548
  "",
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")}`
28549
+ ` ${import_picocolors16.default.dim("Examples:")}`,
28550
+ ` ${import_picocolors16.default.dim(" bash: codeam completion bash >> ~/.bashrc")}`,
28551
+ ` ${import_picocolors16.default.dim(" zsh: codeam completion zsh >> ~/.zshrc")}`,
28552
+ ` ${import_picocolors16.default.dim(" fish: codeam completion fish > ~/.config/fish/completions/codeam.fish")}`
28164
28553
  ])
28165
28554
  };
28166
28555
  function print(lines) {
@@ -28178,179 +28567,6 @@ function tryShowSubcommandHelp(cmd, args2) {
28178
28567
  }
28179
28568
  var _subcommandHelpKeys = Object.keys(HELPS);
28180
28569
 
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
28570
  // src/exit-codes.ts
28355
28571
  var EXIT_OK = 0;
28356
28572
  var EXIT_FAILURE = 1;