codeam-cli 2.39.53 → 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 +12 -0
  2. package/dist/index.js +682 -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.53" : "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.53",
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) => {
@@ -17409,6 +17588,48 @@ async function ensurePip(runner) {
17409
17588
  log.info("host-agent", `bare box provisioned via ${pm} (python3+pip+ca-certificates+curl)`);
17410
17589
  return true;
17411
17590
  }
17591
+ function agentIdToHeadroomKind(agentId) {
17592
+ const normalized = (agentId ?? "").toLowerCase().replace(/[_-]/g, "");
17593
+ if (normalized.startsWith("claude")) return "claude";
17594
+ if (normalized.startsWith("codex")) return "codex";
17595
+ if (normalized.startsWith("copilot")) return "copilot";
17596
+ return "claude";
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
+ }
17412
17633
  async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner) {
17413
17634
  const PIP_PACKAGES = [
17414
17635
  "headroom-ai",
@@ -17464,8 +17685,9 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17464
17685
  log.warn("host-agent", "headroom not found on PATH after install \u2014 skipping init");
17465
17686
  return false;
17466
17687
  }
17688
+ const initKind = agentIdToHeadroomKind(agent);
17467
17689
  const initOk = await new Promise((resolve7) => {
17468
- (0, import_node_child_process12.execFile)("headroom", ["init", "--global", agent], (initErr, stdout, stderr) => {
17690
+ (0, import_node_child_process13.execFile)("headroom", ["init", "--global", initKind], (initErr, stdout, stderr) => {
17469
17691
  if (initErr) {
17470
17692
  const detail = (stderr || initErr.message).replace(/\n+$/g, "");
17471
17693
  log.warn("host-agent", `headroom init failed (best-effort): ${detail}`);
@@ -17481,7 +17703,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17481
17703
  return false;
17482
17704
  }
17483
17705
  try {
17484
- 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"], {
17485
17707
  stdio: "ignore",
17486
17708
  detached: true
17487
17709
  });
@@ -17491,20 +17713,81 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17491
17713
  }
17492
17714
  return true;
17493
17715
  }
17494
- 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], {
17495
17717
  cwd,
17496
17718
  env: { ...process.env, ...env },
17497
17719
  stdio: ["ignore", "pipe", "pipe"],
17498
17720
  detached: false
17499
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
+ }
17500
17779
  var defaultOnIdentityRejected = () => {
17501
17780
  deleteHostIdentity();
17502
17781
  log.warn("host-agent", "host identity rejected by backend \u2014 wiped sealed identity, exiting");
17503
17782
  process.exit(1);
17504
17783
  };
17784
+ var defaultOnUpdated = (version3) => {
17785
+ log.info("host-agent", `self-update: installed ${version3}, restarting`);
17786
+ process.exit(0);
17787
+ };
17505
17788
  var defaultDisableService = () => {
17506
17789
  try {
17507
- (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" });
17508
17791
  } catch {
17509
17792
  }
17510
17793
  };
@@ -17518,6 +17801,8 @@ var HostAgentSupervisor = class {
17518
17801
  this.metrics = deps.metricsCollector ?? new MetricsCollector();
17519
17802
  this.onIdentityRejected = deps.onIdentityRejected ?? defaultOnIdentityRejected;
17520
17803
  this.disableService = deps.disableService ?? defaultDisableService;
17804
+ this.selfUpdate = deps.selfUpdate ?? runSelfUpdate;
17805
+ this.onUpdated = deps.onUpdated ?? defaultOnUpdated;
17521
17806
  }
17522
17807
  identity;
17523
17808
  deps;
@@ -17527,6 +17812,20 @@ var HostAgentSupervisor = class {
17527
17812
  setupHeadroom;
17528
17813
  relay = null;
17529
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;
17530
17829
  /** Guards the one-shot 'connected' telemetry on the first heartbeat. */
17531
17830
  reportedConnected = false;
17532
17831
  /** Live-metrics collector — stateful across beats (CPU delta + latency). */
@@ -17537,6 +17836,19 @@ var HostAgentSupervisor = class {
17537
17836
  disableService;
17538
17837
  /** Guards against firing the self-heal more than once. */
17539
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
+ }
17540
17852
  /** Open the control channel (reusing the relay) + start heartbeats. */
17541
17853
  start() {
17542
17854
  const make = this.deps.makeRelay ?? ((pluginId, onCommand, meta) => new CommandRelayService(pluginId, onCommand, meta));
@@ -17549,6 +17861,13 @@ var HostAgentSupervisor = class {
17549
17861
  void this.beat();
17550
17862
  this.heartbeatTimer = setInterval(() => void this.beat(), HEARTBEAT_INTERVAL_MS);
17551
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
+ }
17552
17871
  log.info("host-agent", `supervisor up host=${this.identity.hostId.slice(0, 8)}`);
17553
17872
  }
17554
17873
  /** Stop the control channel + heartbeats + kill every child. */
@@ -17557,6 +17876,10 @@ var HostAgentSupervisor = class {
17557
17876
  clearInterval(this.heartbeatTimer);
17558
17877
  this.heartbeatTimer = null;
17559
17878
  }
17879
+ if (this.selfUpdateTimer) {
17880
+ clearInterval(this.selfUpdateTimer);
17881
+ this.selfUpdateTimer = null;
17882
+ }
17560
17883
  this.relay?.stop();
17561
17884
  for (const child of this.children.values()) {
17562
17885
  try {
@@ -17596,6 +17919,61 @@ var HostAgentSupervisor = class {
17596
17919
  log.trace("host-agent", "heartbeat failed", err);
17597
17920
  }
17598
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
+ }
17599
17977
  /** Number of live children — for tests + diagnostics. */
17600
17978
  childCount() {
17601
17979
  return this.children.size;
@@ -17691,7 +18069,7 @@ var HostAgentSupervisor = class {
17691
18069
  report("installing", "installing agent CLI");
17692
18070
  await this.runAgentInstall(payload.agentInstallScript);
17693
18071
  }
17694
- const home = process.env.HOME || os31.homedir();
18072
+ const home = process.env.HOME || os32.homedir();
17695
18073
  childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
17696
18074
  if (payload.previewTunnelToken && payload.previewHostname) {
17697
18075
  childEnv.PREVIEW_TUNNEL_TOKEN = payload.previewTunnelToken;
@@ -17701,16 +18079,21 @@ var HostAgentSupervisor = class {
17701
18079
  report("headroom", "setting up Headroom proxy");
17702
18080
  const headroomOk = await this.setupHeadroom(payload.headroomAgent);
17703
18081
  if (headroomOk) {
17704
- childEnv.HEADROOM_ENABLED = "1";
17705
- childEnv.HEADROOM_AGENT = payload.headroomAgent;
17706
- childEnv.HEADROOM_SAVINGS_INGEST_URL = payload.headroomSavingsIngestUrl;
17707
- 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");
17708
18088
  } else {
18089
+ persistHeadroomConfig({ enabled: false });
17709
18090
  log.warn("host-agent", "Headroom setup failed (best-effort) \u2014 child will run without Headroom");
17710
18091
  }
18092
+ } else if (payload.headroomEnabled === false) {
18093
+ persistHeadroomConfig({ enabled: false });
17711
18094
  }
17712
18095
  report("spawning", "starting agent");
17713
- const proc = this.spawnChild(childEnv, cwd, extraArgs);
18096
+ const proc = this.spawnSessionChild(childEnv, cwd, extraArgs);
17714
18097
  const child = { deployId: payload.deployId, proc };
17715
18098
  this.children.set(payload.deployId, child);
17716
18099
  let tail = "";
@@ -17744,6 +18127,20 @@ var HostAgentSupervisor = class {
17744
18127
  report("failed", message);
17745
18128
  }
17746
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
+ }
17747
18144
  /**
17748
18145
  * Run the backend-supplied per-agent CLI install script (e.g.
17749
18146
  * `claude.ai/install.sh`, `npm i -g @openai/codex`). Best-effort + bounded:
@@ -17755,8 +18152,8 @@ var HostAgentSupervisor = class {
17755
18152
  */
17756
18153
  runAgentInstall(script) {
17757
18154
  return new Promise((resolve7) => {
17758
- const home = process.env.HOME || os31.homedir();
17759
- 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], {
17760
18157
  env: { ...process.env, HOME: home },
17761
18158
  stdio: ["ignore", "pipe", "pipe"]
17762
18159
  });
@@ -17880,12 +18277,12 @@ function readTokenFromArgs(args2) {
17880
18277
  }
17881
18278
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
17882
18279
  if (fileFlag) {
17883
- const path58 = fileFlag.slice("--token-file=".length);
18280
+ const path59 = fileFlag.slice("--token-file=".length);
17884
18281
  try {
17885
- const content = fs38.readFileSync(path58, "utf8").trim();
17886
- 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`);
17887
18284
  try {
17888
- fs38.unlinkSync(path58);
18285
+ fs40.unlinkSync(path59);
17889
18286
  } catch {
17890
18287
  }
17891
18288
  return content;
@@ -17911,7 +18308,7 @@ async function claimOnce(token, pluginId, pluginSecretHash) {
17911
18308
  pluginId,
17912
18309
  ideName: "codeam-cli (codespace)",
17913
18310
  ideVersion: process.env.npm_package_version ?? "unknown",
17914
- hostname: os32.hostname(),
18311
+ hostname: os33.hostname(),
17915
18312
  codespaceName: process.env.CODESPACE_NAME ?? "",
17916
18313
  // Current git branch of the codespace's working directory, so the
17917
18314
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -17972,7 +18369,7 @@ async function claim(token, pluginId, pluginSecretHash) {
17972
18369
  }
17973
18370
  }
17974
18371
  function pairAutoLockPath() {
17975
- return path44.join(os32.homedir(), ".codeam", "pair-auto.lock");
18372
+ return path46.join(os33.homedir(), ".codeam", "pair-auto.lock");
17976
18373
  }
17977
18374
  function isLivePairAuto(pid) {
17978
18375
  if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
@@ -17982,7 +18379,7 @@ function isLivePairAuto(pid) {
17982
18379
  if (e.code !== "EPERM") return false;
17983
18380
  }
17984
18381
  try {
17985
- return fs38.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
18382
+ return fs40.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
17986
18383
  } catch {
17987
18384
  return true;
17988
18385
  }
@@ -17992,24 +18389,24 @@ function isLiveCodeam(pid) {
17992
18389
  }
17993
18390
  function daemonLockPath(sessionId) {
17994
18391
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
17995
- return path44.join(os32.homedir(), ".codeam", `daemon-${safe}.lock`);
18392
+ return path46.join(os33.homedir(), ".codeam", `daemon-${safe}.lock`);
17996
18393
  }
17997
18394
  function acquireDaemonLock(sessionId) {
17998
18395
  const lockPath = daemonLockPath(sessionId);
17999
18396
  try {
18000
- fs38.mkdirSync(path44.dirname(lockPath), { recursive: true });
18397
+ fs40.mkdirSync(path46.dirname(lockPath), { recursive: true });
18001
18398
  try {
18002
- fs38.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18399
+ fs40.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18003
18400
  } catch (e) {
18004
18401
  if (e.code !== "EEXIST") throw e;
18005
- const holder = Number(fs38.readFileSync(lockPath, "utf8").trim());
18402
+ const holder = Number(fs40.readFileSync(lockPath, "utf8").trim());
18006
18403
  if (holder && holder !== process.pid && isLiveCodeam(holder)) return false;
18007
- fs38.writeFileSync(lockPath, String(process.pid));
18404
+ fs40.writeFileSync(lockPath, String(process.pid));
18008
18405
  }
18009
18406
  const release3 = () => {
18010
18407
  try {
18011
- if (fs38.existsSync(lockPath) && Number(fs38.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18012
- fs38.unlinkSync(lockPath);
18408
+ if (fs40.existsSync(lockPath) && Number(fs40.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18409
+ fs40.unlinkSync(lockPath);
18013
18410
  }
18014
18411
  } catch {
18015
18412
  }
@@ -18031,19 +18428,19 @@ function acquireDaemonLock(sessionId) {
18031
18428
  function acquireSingletonLock() {
18032
18429
  const lockPath = pairAutoLockPath();
18033
18430
  try {
18034
- fs38.mkdirSync(path44.dirname(lockPath), { recursive: true });
18431
+ fs40.mkdirSync(path46.dirname(lockPath), { recursive: true });
18035
18432
  try {
18036
- fs38.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18433
+ fs40.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
18037
18434
  } catch (e) {
18038
18435
  if (e.code !== "EEXIST") throw e;
18039
- const holder = Number(fs38.readFileSync(lockPath, "utf8").trim());
18436
+ const holder = Number(fs40.readFileSync(lockPath, "utf8").trim());
18040
18437
  if (isLivePairAuto(holder)) return false;
18041
- fs38.writeFileSync(lockPath, String(process.pid));
18438
+ fs40.writeFileSync(lockPath, String(process.pid));
18042
18439
  }
18043
18440
  process.once("exit", () => {
18044
18441
  try {
18045
- if (fs38.existsSync(lockPath) && Number(fs38.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18046
- fs38.unlinkSync(lockPath);
18442
+ if (fs40.existsSync(lockPath) && Number(fs40.readFileSync(lockPath, "utf8").trim()) === process.pid) {
18443
+ fs40.unlinkSync(lockPath);
18047
18444
  }
18048
18445
  } catch {
18049
18446
  }
@@ -18125,7 +18522,7 @@ async function pairAuto(args2) {
18125
18522
  }
18126
18523
 
18127
18524
  // src/services/headroom/wrap-launch.ts
18128
- var import_node_child_process13 = require("child_process");
18525
+ var import_node_child_process14 = require("child_process");
18129
18526
  function wrapWithHeadroom(launch, opts) {
18130
18527
  if (!opts.enabled || !opts.headroomPresent) return launch;
18131
18528
  return {
@@ -18138,7 +18535,7 @@ var _present;
18138
18535
  function headroomPresent() {
18139
18536
  if (_present !== void 0) return Promise.resolve(_present);
18140
18537
  return new Promise((resolve7) => {
18141
- (0, import_node_child_process13.execFile)("headroom", ["--version"], (err) => {
18538
+ (0, import_node_child_process14.execFile)("headroom", ["--version"], (err) => {
18142
18539
  _present = !err;
18143
18540
  resolve7(_present);
18144
18541
  });
@@ -18488,19 +18885,19 @@ var AgentService = class _AgentService {
18488
18885
  };
18489
18886
 
18490
18887
  // src/agents/acp/adapters.ts
18491
- var path45 = __toESM(require("path"));
18888
+ var path47 = __toESM(require("path"));
18492
18889
  var require_ = require;
18493
18890
  function resolveBin(pkgName, binName) {
18494
18891
  try {
18495
18892
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
18496
18893
  const manifest = require_(`${pkgName}/package.json`);
18497
- const pkgDir = path45.dirname(manifestPath);
18894
+ const pkgDir = path47.dirname(manifestPath);
18498
18895
  const bin = manifest.bin;
18499
18896
  if (!bin) return null;
18500
- if (typeof bin === "string") return path45.resolve(pkgDir, bin);
18897
+ if (typeof bin === "string") return path47.resolve(pkgDir, bin);
18501
18898
  const target = binName ?? Object.keys(bin)[0];
18502
18899
  if (!target || !bin[target]) return null;
18503
- return path45.resolve(pkgDir, bin[target]);
18900
+ return path47.resolve(pkgDir, bin[target]);
18504
18901
  } catch {
18505
18902
  return null;
18506
18903
  }
@@ -18576,11 +18973,11 @@ function requiresAcp(agent) {
18576
18973
  var import_node_crypto7 = require("crypto");
18577
18974
 
18578
18975
  // src/agents/acp/client.ts
18579
- var import_node_child_process14 = require("child_process");
18580
- var fs39 = __toESM(require("fs/promises"));
18976
+ var import_node_child_process15 = require("child_process");
18977
+ var fs41 = __toESM(require("fs/promises"));
18581
18978
  var fsSync = __toESM(require("fs"));
18582
- var os33 = __toESM(require("os"));
18583
- var path46 = __toESM(require("path"));
18979
+ var os34 = __toESM(require("os"));
18980
+ var path48 = __toESM(require("path"));
18584
18981
  var import_node_stream = require("stream");
18585
18982
 
18586
18983
  // ../../node_modules/@agentclientprotocol/sdk/dist/acp.js
@@ -21117,7 +21514,7 @@ var AcpClient = class {
21117
21514
  "acpClient",
21118
21515
  `spawn cmd=${adapter.command} args=[${adapter.args.join(",")}] cwd=${cwd}`
21119
21516
  );
21120
- 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, {
21121
21518
  cwd,
21122
21519
  env: { ...process.env, PATH: augmentedPath },
21123
21520
  stdio: ["pipe", "pipe", "pipe"]
@@ -21367,7 +21764,7 @@ var AcpClient = class {
21367
21764
  },
21368
21765
  readTextFile: async (params) => {
21369
21766
  try {
21370
- const content = await fs39.readFile(params.path, "utf8");
21767
+ const content = await fs41.readFile(params.path, "utf8");
21371
21768
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
21372
21769
  } catch (err) {
21373
21770
  const code = err.code;
@@ -21387,7 +21784,7 @@ var AcpClient = class {
21387
21784
  },
21388
21785
  writeTextFile: async (params) => {
21389
21786
  try {
21390
- await fs39.writeFile(params.path, params.content, "utf8");
21787
+ await fs41.writeFile(params.path, params.content, "utf8");
21391
21788
  return {};
21392
21789
  } catch (err) {
21393
21790
  const code = err.code;
@@ -21436,25 +21833,25 @@ function applyLineRange(content, line, limit) {
21436
21833
  return { content: lines.slice(start2, end).join("\n") };
21437
21834
  }
21438
21835
  function knownAgentBinaryDirs() {
21439
- const home = os33.homedir();
21836
+ const home = os34.homedir();
21440
21837
  const out2 = [];
21441
21838
  out2.push("/tmp/codeam-node20/bin");
21442
21839
  for (const root of [
21443
21840
  "/usr/local/share/nvm/versions/node",
21444
- path46.join(home, ".nvm/versions/node")
21841
+ path48.join(home, ".nvm/versions/node")
21445
21842
  ]) {
21446
21843
  try {
21447
21844
  for (const child of fsSync.readdirSync(root)) {
21448
- out2.push(path46.join(root, child, "bin"));
21845
+ out2.push(path48.join(root, child, "bin"));
21449
21846
  }
21450
21847
  } catch {
21451
21848
  }
21452
21849
  }
21453
- out2.push(path46.join(home, ".volta/bin"));
21850
+ out2.push(path48.join(home, ".volta/bin"));
21454
21851
  out2.push("/usr/local/bin");
21455
21852
  out2.push("/usr/bin");
21456
- out2.push(path46.join(home, ".local/bin"));
21457
- out2.push(path46.join(home, "bin"));
21853
+ out2.push(path48.join(home, ".local/bin"));
21854
+ out2.push(path48.join(home, "bin"));
21458
21855
  return out2.filter((p2) => {
21459
21856
  try {
21460
21857
  return fsSync.statSync(p2).isDirectory();
@@ -21465,7 +21862,7 @@ function knownAgentBinaryDirs() {
21465
21862
  }
21466
21863
  function expandPathForAgentBinaries(existingPath) {
21467
21864
  const existing = new Set(
21468
- existingPath.split(path46.delimiter).filter((p2) => p2.length > 0)
21865
+ existingPath.split(path48.delimiter).filter((p2) => p2.length > 0)
21469
21866
  );
21470
21867
  const additions = [];
21471
21868
  for (const dir of knownAgentBinaryDirs()) {
@@ -21475,12 +21872,12 @@ function expandPathForAgentBinaries(existingPath) {
21475
21872
  }
21476
21873
  }
21477
21874
  if (additions.length === 0) return existingPath;
21478
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path46.delimiter);
21875
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path48.delimiter);
21479
21876
  }
21480
21877
 
21481
21878
  // src/services/streaming/transport.ts
21482
21879
  var http6 = __toESM(require("http"));
21483
- var https6 = __toESM(require("https"));
21880
+ var https7 = __toESM(require("https"));
21484
21881
  var _transport4 = {
21485
21882
  post: _post3,
21486
21883
  get: _get
@@ -21489,7 +21886,7 @@ function _post3(url, headers, payload) {
21489
21886
  return new Promise((resolve7, reject) => {
21490
21887
  let settled = false;
21491
21888
  const u2 = new URL(url);
21492
- const lib = u2.protocol === "https:" ? https6 : http6;
21889
+ const lib = u2.protocol === "https:" ? https7 : http6;
21493
21890
  const req = lib.request(
21494
21891
  {
21495
21892
  hostname: u2.hostname,
@@ -21531,7 +21928,7 @@ function _get(url, headers) {
21531
21928
  return new Promise((resolve7, reject) => {
21532
21929
  let settled = false;
21533
21930
  const u2 = new URL(url);
21534
- const lib = u2.protocol === "https:" ? https6 : http6;
21931
+ const lib = u2.protocol === "https:" ? https7 : http6;
21535
21932
  const req = lib.request(
21536
21933
  {
21537
21934
  hostname: u2.hostname,
@@ -21802,15 +22199,15 @@ function reconcileCumulative(existing, incoming) {
21802
22199
  }
21803
22200
 
21804
22201
  // src/agents/acp/onboarding.ts
21805
- var fs40 = __toESM(require("fs"));
21806
- var os34 = __toESM(require("os"));
21807
- var path47 = __toESM(require("path"));
22202
+ var fs42 = __toESM(require("fs"));
22203
+ var os35 = __toESM(require("os"));
22204
+ var path49 = __toESM(require("path"));
21808
22205
  var _onboardingSeam = {
21809
- markerPath: (sessionId) => path47.join(os34.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
21810
- exists: (p2) => fs40.existsSync(p2),
22206
+ markerPath: (sessionId) => path49.join(os35.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
22207
+ exists: (p2) => fs42.existsSync(p2),
21811
22208
  write: (p2) => {
21812
- fs40.mkdirSync(path47.dirname(p2), { recursive: true });
21813
- fs40.writeFileSync(p2, "");
22209
+ fs42.mkdirSync(path49.dirname(p2), { recursive: true });
22210
+ fs42.writeFileSync(p2, "");
21814
22211
  },
21815
22212
  disabled: () => {
21816
22213
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -21818,7 +22215,7 @@ var _onboardingSeam = {
21818
22215
  }
21819
22216
  };
21820
22217
  function buildOnboardingWelcome(cwd) {
21821
- const repo = path47.basename(cwd || "") || "this project";
22218
+ const repo = path49.basename(cwd || "") || "this project";
21822
22219
  return [
21823
22220
  `Welcome to CodeAgent Mobile! \u{1F44B} You're now driving this agent from your phone \u2014 and it comes fully wired, zero setup:`,
21824
22221
  "",
@@ -22078,8 +22475,8 @@ var import_crypto5 = require("crypto");
22078
22475
 
22079
22476
  // src/services/turn-files/git-changeset.ts
22080
22477
  var import_child_process22 = require("child_process");
22081
- var fs41 = __toESM(require("fs/promises"));
22082
- var path48 = __toESM(require("path"));
22478
+ var fs43 = __toESM(require("fs/promises"));
22479
+ var path50 = __toESM(require("path"));
22083
22480
  async function collectRepoChangeset(opts) {
22084
22481
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
22085
22482
  if (status2 === null) return null;
@@ -22097,7 +22494,7 @@ async function collectRepoChangeset(opts) {
22097
22494
  let stats;
22098
22495
  if (row.fileStatus === "added" && numstatEntry === void 0) {
22099
22496
  const lineCount = await readUntrackedLineCount(
22100
- path48.join(opts.repoRoot, row.filePath)
22497
+ path50.join(opts.repoRoot, row.filePath)
22101
22498
  );
22102
22499
  stats = { added: lineCount, removed: 0 };
22103
22500
  } else {
@@ -22128,7 +22525,7 @@ function readUntrackedLineCount(absPath) {
22128
22525
  }
22129
22526
  async function defaultReadUntrackedLineCount(absPath) {
22130
22527
  try {
22131
- const content = await fs41.readFile(absPath, "utf8");
22528
+ const content = await fs43.readFile(absPath, "utf8");
22132
22529
  let count = 0;
22133
22530
  let pos = -1;
22134
22531
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -22220,7 +22617,7 @@ function defaultRunGit(cwd, args2) {
22220
22617
  });
22221
22618
  }
22222
22619
  async function discoverRepos(workingDir, maxDepth = 4) {
22223
- const fs47 = await import("fs/promises");
22620
+ const fs48 = await import("fs/promises");
22224
22621
  const out2 = [];
22225
22622
  await walk(workingDir, 0);
22226
22623
  return out2;
@@ -22228,7 +22625,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
22228
22625
  if (depth > maxDepth) return;
22229
22626
  let entries = [];
22230
22627
  try {
22231
- const dirents = await fs47.readdir(dir, { withFileTypes: true });
22628
+ const dirents = await fs48.readdir(dir, { withFileTypes: true });
22232
22629
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
22233
22630
  } catch {
22234
22631
  return;
@@ -22239,8 +22636,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
22239
22636
  if (hasGit) {
22240
22637
  out2.push({
22241
22638
  repoRoot: dir,
22242
- repoPath: path48.relative(workingDir, dir),
22243
- repoName: path48.basename(dir)
22639
+ repoPath: path50.relative(workingDir, dir),
22640
+ repoName: path50.basename(dir)
22244
22641
  });
22245
22642
  return;
22246
22643
  }
@@ -22248,14 +22645,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
22248
22645
  if (!entry.isDirectory) continue;
22249
22646
  if (entry.name === "node_modules") continue;
22250
22647
  if (entry.name === "dist" || entry.name === "build") continue;
22251
- await walk(path48.join(dir, entry.name), depth + 1);
22648
+ await walk(path50.join(dir, entry.name), depth + 1);
22252
22649
  }
22253
22650
  }
22254
22651
  }
22255
22652
 
22256
22653
  // src/services/turn-files/files-outbox.ts
22257
- var fs42 = __toESM(require("fs/promises"));
22258
- var path49 = __toESM(require("path"));
22654
+ var fs44 = __toESM(require("fs/promises"));
22655
+ var path51 = __toESM(require("path"));
22259
22656
  var import_os7 = require("os");
22260
22657
  var HOME_OUTBOX_DIR = ".codeam/outbox";
22261
22658
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -22288,16 +22685,16 @@ var FilesOutbox = class {
22288
22685
  backoffIndex = 0;
22289
22686
  stopped = false;
22290
22687
  constructor(opts) {
22291
- const base = opts.baseDir ?? path49.join(homeDir(), HOME_OUTBOX_DIR);
22292
- 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`);
22293
22690
  this.post = opts.post;
22294
22691
  this.autoSchedule = opts.autoSchedule !== false;
22295
22692
  }
22296
22693
  /** Persist the entry to disk and trigger a flush. Returns once the
22297
22694
  * line is durable on disk (not once the POST succeeds). */
22298
22695
  async enqueue(entry) {
22299
- await fs42.mkdir(path49.dirname(this.filePath), { recursive: true });
22300
- 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");
22301
22698
  this.backoffIndex = 0;
22302
22699
  if (this.autoSchedule) this.scheduleFlush(0);
22303
22700
  }
@@ -22386,7 +22783,7 @@ var FilesOutbox = class {
22386
22783
  async readAll() {
22387
22784
  let raw = "";
22388
22785
  try {
22389
- raw = await fs42.readFile(this.filePath, "utf8");
22786
+ raw = await fs44.readFile(this.filePath, "utf8");
22390
22787
  } catch {
22391
22788
  return [];
22392
22789
  }
@@ -22410,12 +22807,12 @@ var FilesOutbox = class {
22410
22807
  async rewrite(entries) {
22411
22808
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
22412
22809
  if (entries.length === 0) {
22413
- await fs42.unlink(this.filePath).catch(() => void 0);
22810
+ await fs44.unlink(this.filePath).catch(() => void 0);
22414
22811
  return;
22415
22812
  }
22416
22813
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
22417
- await fs42.writeFile(tmpPath, payload, "utf8");
22418
- await fs42.rename(tmpPath, this.filePath);
22814
+ await fs44.writeFile(tmpPath, payload, "utf8");
22815
+ await fs44.rename(tmpPath, this.filePath);
22419
22816
  }
22420
22817
  };
22421
22818
  function applyJitter(ms) {
@@ -24146,10 +24543,10 @@ var OutputService = class _OutputService {
24146
24543
  };
24147
24544
 
24148
24545
  // src/services/history.service.ts
24149
- var fs43 = __toESM(require("fs"));
24150
- var path50 = __toESM(require("path"));
24151
- var os35 = __toESM(require("os"));
24152
- 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"));
24153
24550
  var http7 = __toESM(require("http"));
24154
24551
  var import_zod2 = require("zod");
24155
24552
  var historyRecordSchema = import_zod2.z.object({
@@ -24175,7 +24572,7 @@ function parseJsonl(filePath) {
24175
24572
  const messages = [];
24176
24573
  let raw;
24177
24574
  try {
24178
- raw = fs43.readFileSync(filePath, "utf8");
24575
+ raw = fs45.readFileSync(filePath, "utf8");
24179
24576
  } catch (err) {
24180
24577
  if (err.code !== "ENOENT") {
24181
24578
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -24215,7 +24612,7 @@ function post(endpoint, body, pluginAuthToken) {
24215
24612
  return new Promise((resolve7) => {
24216
24613
  const payload = JSON.stringify(body);
24217
24614
  const u2 = new URL(`${API_BASE9}${endpoint}`);
24218
- const transport = u2.protocol === "https:" ? https7 : http7;
24615
+ const transport = u2.protocol === "https:" ? https8 : http7;
24219
24616
  const req = transport.request(
24220
24617
  {
24221
24618
  hostname: u2.hostname,
@@ -24316,7 +24713,7 @@ var HistoryService = class _HistoryService {
24316
24713
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
24317
24714
  }
24318
24715
  get projectDir() {
24319
- 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));
24320
24717
  }
24321
24718
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
24322
24719
  setCurrentConversationId(id) {
@@ -24328,7 +24725,7 @@ var HistoryService = class _HistoryService {
24328
24725
  /** Return the current message count in the active conversation. */
24329
24726
  getCurrentMessageCount() {
24330
24727
  if (!this.currentConversationId) return 0;
24331
- const filePath = path50.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24728
+ const filePath = path52.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24332
24729
  return parseJsonl(filePath).length;
24333
24730
  }
24334
24731
  /**
@@ -24339,7 +24736,7 @@ var HistoryService = class _HistoryService {
24339
24736
  const deadline = Date.now() + timeoutMs;
24340
24737
  while (Date.now() < deadline) {
24341
24738
  if (!this.currentConversationId) return null;
24342
- const filePath = path50.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24739
+ const filePath = path52.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24343
24740
  const messages = parseJsonl(filePath);
24344
24741
  if (messages.length > previousCount) {
24345
24742
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -24365,16 +24762,16 @@ var HistoryService = class _HistoryService {
24365
24762
  const dir = this.projectDir;
24366
24763
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
24367
24764
  try {
24368
- 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) => {
24369
24766
  try {
24370
- const stat3 = fs43.statSync(path50.join(dir, e.name));
24767
+ const stat3 = fs45.statSync(path52.join(dir, e.name));
24371
24768
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
24372
24769
  } catch {
24373
24770
  return { name: e.name, mtime: 0, birthtime: 0 };
24374
24771
  }
24375
24772
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
24376
24773
  if (files.length > 0) {
24377
- this.currentConversationId = path50.basename(files[0].name, ".jsonl");
24774
+ this.currentConversationId = path52.basename(files[0].name, ".jsonl");
24378
24775
  }
24379
24776
  } catch {
24380
24777
  }
@@ -24408,13 +24805,13 @@ var HistoryService = class _HistoryService {
24408
24805
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
24409
24806
  let entries;
24410
24807
  try {
24411
- entries = fs43.readdirSync(dir, { withFileTypes: true });
24808
+ entries = fs45.readdirSync(dir, { withFileTypes: true });
24412
24809
  } catch {
24413
24810
  return null;
24414
24811
  }
24415
24812
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
24416
24813
  try {
24417
- const stat3 = fs43.statSync(path50.join(dir, e.name));
24814
+ const stat3 = fs45.statSync(path52.join(dir, e.name));
24418
24815
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
24419
24816
  } catch {
24420
24817
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -24423,12 +24820,12 @@ var HistoryService = class _HistoryService {
24423
24820
  if (files.length === 0) return null;
24424
24821
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
24425
24822
  if (!files.some((f) => f.name === targetFile)) return null;
24426
- return this.extractUsageFromFile(path50.join(dir, targetFile));
24823
+ return this.extractUsageFromFile(path52.join(dir, targetFile));
24427
24824
  }
24428
24825
  extractUsageFromFile(filePath) {
24429
24826
  let raw;
24430
24827
  try {
24431
- raw = fs43.readFileSync(filePath, "utf8");
24828
+ raw = fs45.readFileSync(filePath, "utf8");
24432
24829
  } catch {
24433
24830
  return null;
24434
24831
  }
@@ -24473,9 +24870,9 @@ var HistoryService = class _HistoryService {
24473
24870
  let totalCost = 0;
24474
24871
  let files;
24475
24872
  try {
24476
- files = fs43.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
24873
+ files = fs45.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
24477
24874
  try {
24478
- return fs43.statSync(path50.join(projectDir, f)).mtimeMs >= monthStartMs;
24875
+ return fs45.statSync(path52.join(projectDir, f)).mtimeMs >= monthStartMs;
24479
24876
  } catch {
24480
24877
  return false;
24481
24878
  }
@@ -24486,7 +24883,7 @@ var HistoryService = class _HistoryService {
24486
24883
  for (const file of files) {
24487
24884
  let raw;
24488
24885
  try {
24489
- raw = fs43.readFileSync(path50.join(projectDir, file), "utf8");
24886
+ raw = fs45.readFileSync(path52.join(projectDir, file), "utf8");
24490
24887
  } catch {
24491
24888
  continue;
24492
24889
  }
@@ -24554,7 +24951,7 @@ var HistoryService = class _HistoryService {
24554
24951
  * showing an empty conversation.
24555
24952
  */
24556
24953
  async loadConversation(sessionId) {
24557
- const filePath = path50.join(this.projectDir, `${sessionId}.jsonl`);
24954
+ const filePath = path52.join(this.projectDir, `${sessionId}.jsonl`);
24558
24955
  const messages = parseJsonl(filePath);
24559
24956
  if (messages.length === 0) return;
24560
24957
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -24608,7 +25005,7 @@ var HistoryService = class _HistoryService {
24608
25005
  if (!this.currentConversationId) return 0;
24609
25006
  }
24610
25007
  const sessionId = this.currentConversationId;
24611
- const filePath = path50.join(this.projectDir, `${sessionId}.jsonl`);
25008
+ const filePath = path52.join(this.projectDir, `${sessionId}.jsonl`);
24612
25009
  const messages = parseJsonl(filePath);
24613
25010
  if (messages.length === 0) return 0;
24614
25011
  const marker = this.lastUploadedUuid.get(sessionId);
@@ -25034,15 +25431,15 @@ function fetchQuotaUsage(runtime, historySvc) {
25034
25431
  }
25035
25432
 
25036
25433
  // src/agents/claude/onboarding.ts
25037
- var fs44 = __toESM(require("fs"));
25038
- var os36 = __toESM(require("os"));
25039
- var path51 = __toESM(require("path"));
25434
+ var fs46 = __toESM(require("fs"));
25435
+ var os37 = __toESM(require("os"));
25436
+ var path53 = __toESM(require("path"));
25040
25437
  function ensureClaudeOnboarded() {
25041
25438
  try {
25042
- const file = path51.join(os36.homedir(), ".claude.json");
25439
+ const file = path53.join(os37.homedir(), ".claude.json");
25043
25440
  let config = {};
25044
25441
  try {
25045
- config = JSON.parse(fs44.readFileSync(file, "utf8"));
25442
+ config = JSON.parse(fs46.readFileSync(file, "utf8"));
25046
25443
  } catch {
25047
25444
  }
25048
25445
  if (config.hasCompletedOnboarding === true && typeof config.theme === "string") {
@@ -25053,8 +25450,8 @@ function ensureClaudeOnboarded() {
25053
25450
  if (typeof config.lastOnboardingVersion !== "string") {
25054
25451
  config.lastOnboardingVersion = "2.1.177";
25055
25452
  }
25056
- fs44.mkdirSync(path51.dirname(file), { recursive: true });
25057
- 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));
25058
25455
  log.info("claude", "pre-completed Claude onboarding (skip first-run theme picker)");
25059
25456
  } catch (err) {
25060
25457
  log.warn("claude", `ensureClaudeOnboarded failed (non-fatal): ${err.message}`);
@@ -25068,27 +25465,27 @@ async function start(requestedAgent) {
25068
25465
  if (!session) {
25069
25466
  if (requestedAgent) {
25070
25467
  const displayName = AGENT_REGISTRY[requestedAgent]?.displayName ?? requestedAgent;
25071
- console.log(` ${import_picocolors3.default.dim(`No paired ${displayName} session found.`)}`);
25468
+ console.log(` ${import_picocolors4.default.dim(`No paired ${displayName} session found.`)}`);
25072
25469
  console.log(
25073
- ` ${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.`)}
25074
25471
  `
25075
25472
  );
25076
25473
  } else {
25077
- console.log(` ${import_picocolors3.default.dim("No paired session found.")}`);
25078
- 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.`)}
25079
25476
  `);
25080
25477
  }
25081
25478
  process.exit(0);
25082
25479
  }
25083
25480
  if (!acquireDaemonLock(session.id)) {
25084
- 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.")}`);
25085
25482
  process.exit(0);
25086
25483
  }
25087
25484
  if (!session.agent) {
25088
25485
  throw new Error("Active session has no agent \u2014 re-pair with `codeam pair`.");
25089
25486
  }
25090
25487
  const pluginId = session.pluginId ?? ensurePluginId();
25091
- showInfo(`${session.userName} \xB7 ${import_picocolors3.default.cyan(session.plan)}`);
25488
+ showInfo(`${session.userName} \xB7 ${import_picocolors4.default.cyan(session.plan)}`);
25092
25489
  showInfo(`Launching ${AGENT_REGISTRY[session.agent].displayName}...
25093
25490
  `);
25094
25491
  identifyUser({
@@ -25362,7 +25759,7 @@ async function start(requestedAgent) {
25362
25759
 
25363
25760
  // src/commands/pair.ts
25364
25761
  var import_crypto7 = require("crypto");
25365
- var import_picocolors4 = __toESM(require("picocolors"));
25762
+ var import_picocolors5 = __toESM(require("picocolors"));
25366
25763
 
25367
25764
  // src/utils/agent-prompt.ts
25368
25765
  function parseAgentFlag(args2) {
@@ -25443,7 +25840,7 @@ async function pair(args2 = []) {
25443
25840
  process.exit(0);
25444
25841
  }
25445
25842
  showPairingCode(result.code);
25446
- 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."));
25447
25844
  console.log("");
25448
25845
  const waitSpin = dist_exports.spinner();
25449
25846
  const waitMessage = () => `Waiting for mobile app... \xB7 expires in ${formatRemaining(result.expiresAt)}`;
@@ -25558,7 +25955,7 @@ async function autoLinkAfterPair(opts) {
25558
25955
  }
25559
25956
 
25560
25957
  // src/commands/sessions.ts
25561
- var import_picocolors5 = __toESM(require("picocolors"));
25958
+ var import_picocolors6 = __toESM(require("picocolors"));
25562
25959
  async function sessions2(args2) {
25563
25960
  const [sub, id] = args2;
25564
25961
  if (sub === "switch") return switchSession();
@@ -25575,18 +25972,18 @@ function listSessions() {
25575
25972
  showIntro();
25576
25973
  const config = getConfig();
25577
25974
  if (config.sessions.length === 0) {
25578
- 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"));
25579
25976
  return;
25580
25977
  }
25581
- console.log(import_picocolors5.default.bold(" Paired sessions:\n"));
25978
+ console.log(import_picocolors6.default.bold(" Paired sessions:\n"));
25582
25979
  for (const s of config.sessions) {
25583
25980
  const isActive = s.id === config.activeSessionId;
25584
- const bullet = isActive ? import_picocolors5.default.green(" \u25CF") : import_picocolors5.default.dim(" \u25CB");
25585
- const name = isActive ? import_picocolors5.default.bold(s.userName) : s.userName;
25586
- const plan = import_picocolors5.default.cyan(s.plan);
25587
- 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());
25588
25985
  console.log(`${bullet} ${name} ${plan} ${date}`);
25589
- console.log(import_picocolors5.default.dim(` ${s.id}`));
25986
+ console.log(import_picocolors6.default.dim(` ${s.id}`));
25590
25987
  }
25591
25988
  console.log("");
25592
25989
  }
@@ -25604,7 +26001,7 @@ async function switchSession() {
25604
26001
  }
25605
26002
  setActiveSession(chosen);
25606
26003
  const s = config.sessions.find((x) => x.id === chosen);
25607
- console.log(import_picocolors5.default.green(`
26004
+ console.log(import_picocolors6.default.green(`
25608
26005
  \u2713 Switched to ${s?.userName ?? chosen}
25609
26006
  `));
25610
26007
  }
@@ -25622,29 +26019,29 @@ async function deleteSession(id) {
25622
26019
  return;
25623
26020
  }
25624
26021
  removeSession(id);
25625
- console.log(import_picocolors5.default.green("\n \u2713 Session deleted\n"));
26022
+ console.log(import_picocolors6.default.green("\n \u2713 Session deleted\n"));
25626
26023
  }
25627
26024
 
25628
26025
  // src/commands/status.ts
25629
- var import_picocolors6 = __toESM(require("picocolors"));
26026
+ var import_picocolors7 = __toESM(require("picocolors"));
25630
26027
  function status() {
25631
26028
  showIntro();
25632
26029
  const config = getConfig();
25633
26030
  const active = config.sessions.find((s) => s.id === config.activeSessionId) ?? null;
25634
- console.log(import_picocolors6.default.bold(" Status\n"));
25635
- 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")}`);
25636
26033
  console.log(` Sessions ${config.sessions.length} paired`);
25637
26034
  if (active) {
25638
- console.log(` Active ${import_picocolors6.default.bold(active.userName)} ${import_picocolors6.default.cyan(active.plan)}`);
25639
- 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)}`);
25640
26037
  } else {
25641
- 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")}`);
25642
26039
  }
25643
26040
  console.log("");
25644
26041
  }
25645
26042
 
25646
26043
  // src/commands/logout.ts
25647
- var import_picocolors7 = __toESM(require("picocolors"));
26044
+ var import_picocolors8 = __toESM(require("picocolors"));
25648
26045
  var API_BASE11 = resolveApiBaseUrl();
25649
26046
  async function notifyBackendOffline() {
25650
26047
  const cfg = loadCliConfig();
@@ -25678,17 +26075,17 @@ async function logout() {
25678
26075
  }
25679
26076
  await notifyBackendOffline();
25680
26077
  clearAll();
25681
- 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"));
25682
26079
  }
25683
26080
 
25684
26081
  // src/commands/deploy.ts
25685
- var import_picocolors10 = __toESM(require("picocolors"));
26082
+ var import_picocolors11 = __toESM(require("picocolors"));
25686
26083
 
25687
26084
  // src/services/providers/github-codespaces.ts
25688
26085
  var import_child_process23 = require("child_process");
25689
26086
  var import_util4 = require("util");
25690
- var import_picocolors8 = __toESM(require("picocolors"));
25691
- var path52 = __toESM(require("path"));
26087
+ var import_picocolors9 = __toESM(require("picocolors"));
26088
+ var path54 = __toESM(require("path"));
25692
26089
  var execFileP6 = (0, import_util4.promisify)(import_child_process23.execFile);
25693
26090
  var MAX_BUFFER = 8 * 1024 * 1024;
25694
26091
  function resetStdinForChild() {
@@ -25755,7 +26152,7 @@ var GitHubCodespacesProvider = class {
25755
26152
  if (expectedUser) {
25756
26153
  noteLines.push("");
25757
26154
  noteLines.push(
25758
- `${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.`
25759
26156
  );
25760
26157
  noteLines.push(
25761
26158
  " If a different GitHub account is already signed in, sign out"
@@ -25778,7 +26175,7 @@ var GitHubCodespacesProvider = class {
25778
26175
  if (refreshCode !== 0) {
25779
26176
  const lines = [
25780
26177
  "The browser approval came back for a different GitHub account",
25781
- `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)})` : ""}.`,
25782
26179
  "",
25783
26180
  "To recover:",
25784
26181
  " 1. Open https://github.com and sign out of any non-target",
@@ -25787,7 +26184,7 @@ var GitHubCodespacesProvider = class {
25787
26184
  "",
25788
26185
  "You can also grant the scope manually first and skip this step",
25789
26186
  "on the next run:",
25790
- ` ${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")}`
25791
26188
  ];
25792
26189
  throw new Error(lines.join("\n"));
25793
26190
  }
@@ -25854,7 +26251,7 @@ var GitHubCodespacesProvider = class {
25854
26251
  async tryInstallGh() {
25855
26252
  const platform3 = process.platform;
25856
26253
  wt(
25857
- `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.`,
25858
26255
  "Heads up"
25859
26256
  );
25860
26257
  if (platform3 === "linux") {
@@ -25910,7 +26307,7 @@ var GitHubCodespacesProvider = class {
25910
26307
  return;
25911
26308
  }
25912
26309
  const proceed = await ot2({
25913
- message: `Run ${import_picocolors8.default.cyan(installCmd.describe)} now?`,
26310
+ message: `Run ${import_picocolors9.default.cyan(installCmd.describe)} now?`,
25914
26311
  initialValue: true
25915
26312
  });
25916
26313
  if (q(proceed) || !proceed) return;
@@ -26177,7 +26574,7 @@ var GitHubCodespacesProvider = class {
26177
26574
  });
26178
26575
  }
26179
26576
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
26180
- const remoteDir = path52.posix.dirname(remotePath);
26577
+ const remoteDir = path54.posix.dirname(remotePath);
26181
26578
  const parts = [
26182
26579
  `mkdir -p ${shellQuote(remoteDir)}`,
26183
26580
  `cat > ${shellQuote(remotePath)}`
@@ -26247,8 +26644,8 @@ function shellQuote(s) {
26247
26644
  // src/services/providers/gitpod.ts
26248
26645
  var import_child_process24 = require("child_process");
26249
26646
  var import_util5 = require("util");
26250
- var path53 = __toESM(require("path"));
26251
- var import_picocolors9 = __toESM(require("picocolors"));
26647
+ var path55 = __toESM(require("path"));
26648
+ var import_picocolors10 = __toESM(require("picocolors"));
26252
26649
  var execFileP7 = (0, import_util5.promisify)(import_child_process24.execFile);
26253
26650
  var MAX_BUFFER2 = 8 * 1024 * 1024;
26254
26651
  function resetStdinForChild2() {
@@ -26487,7 +26884,7 @@ var GitpodProvider = class {
26487
26884
  });
26488
26885
  }
26489
26886
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
26490
- const remoteDir = path53.posix.dirname(remotePath);
26887
+ const remoteDir = path55.posix.dirname(remotePath);
26491
26888
  const parts = [
26492
26889
  `mkdir -p ${shellQuote2(remoteDir)}`,
26493
26890
  `cat > ${shellQuote2(remotePath)}`
@@ -26523,7 +26920,7 @@ function shellQuote2(s) {
26523
26920
  // src/services/providers/gitlab-workspaces.ts
26524
26921
  var import_child_process25 = require("child_process");
26525
26922
  var import_util6 = require("util");
26526
- var path54 = __toESM(require("path"));
26923
+ var path56 = __toESM(require("path"));
26527
26924
  var execFileP8 = (0, import_util6.promisify)(import_child_process25.execFile);
26528
26925
  var MAX_BUFFER3 = 8 * 1024 * 1024;
26529
26926
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -26783,7 +27180,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
26783
27180
  }
26784
27181
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
26785
27182
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
26786
- const remoteDir = path54.posix.dirname(remotePath);
27183
+ const remoteDir = path56.posix.dirname(remotePath);
26787
27184
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
26788
27185
  if (options.mode != null) {
26789
27186
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -26851,7 +27248,7 @@ function shellQuote3(s) {
26851
27248
  // src/services/providers/railway.ts
26852
27249
  var import_child_process26 = require("child_process");
26853
27250
  var import_util7 = require("util");
26854
- var path55 = __toESM(require("path"));
27251
+ var path57 = __toESM(require("path"));
26855
27252
  var execFileP9 = (0, import_util7.promisify)(import_child_process26.execFile);
26856
27253
  var MAX_BUFFER4 = 8 * 1024 * 1024;
26857
27254
  function resetStdinForChild4() {
@@ -27087,7 +27484,7 @@ var RailwayProvider = class {
27087
27484
  if (!projectId || !serviceId) {
27088
27485
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
27089
27486
  }
27090
- const remoteDir = path55.posix.dirname(remotePath);
27487
+ const remoteDir = path57.posix.dirname(remotePath);
27091
27488
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
27092
27489
  if (options.mode != null) {
27093
27490
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -27128,7 +27525,7 @@ var PROVIDERS = [
27128
27525
  // src/commands/deploy.ts
27129
27526
  async function deploy(args2 = []) {
27130
27527
  console.log();
27131
- mt(import_picocolors10.default.bgMagenta(import_picocolors10.default.white(" codeam deploy ")));
27528
+ mt(import_picocolors11.default.bgMagenta(import_picocolors11.default.white(" codeam deploy ")));
27132
27529
  const provider = await pickProvider();
27133
27530
  if (!provider) {
27134
27531
  pt("No provider selected.");
@@ -27165,7 +27562,7 @@ async function deploy(args2 = []) {
27165
27562
  if (provider.expandListScopes) {
27166
27563
  options.push({
27167
27564
  value: EXPAND_SCOPES,
27168
- 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"),
27169
27566
  hint: "Re-authorize with broader scopes (org / team repos)"
27170
27567
  });
27171
27568
  }
@@ -27213,7 +27610,7 @@ async function deploy(args2 = []) {
27213
27610
  label: w3.displayName ?? w3.id,
27214
27611
  hint: [w3.state, formatLastUsed(w3.lastUsedAt)].filter(Boolean).join(" \xB7 ")
27215
27612
  })),
27216
- { 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" }
27217
27614
  ]
27218
27615
  });
27219
27616
  if (q(choice)) {
@@ -27314,12 +27711,12 @@ async function deploy(args2 = []) {
27314
27711
  cliStep.stop("\u2713 codeam-cli installed");
27315
27712
  wt(
27316
27713
  [
27317
- `Workspace: ${import_picocolors10.default.cyan(workspace.displayName ?? workspace.id)}`,
27318
- 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)}` : "",
27319
27716
  "",
27320
27717
  `Starting \`codeam pair\` on the workspace (agent: ${AGENT_REGISTRY[agentId].displayName}).`,
27321
27718
  "Scan the QR code from your phone to pair.",
27322
- 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.)")
27323
27720
  ].filter(Boolean).join("\n"),
27324
27721
  "Almost there"
27325
27722
  );
@@ -27434,11 +27831,11 @@ async function deploy(args2 = []) {
27434
27831
  ].join("\n");
27435
27832
  const code = (await provider.streamCommand(workspace.id, `bash -lc ${shellQuoteSingle(wrapper)}`)).code;
27436
27833
  if (code === 0) {
27437
- 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."));
27438
27835
  } else if (code === 130) {
27439
- 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."));
27440
27837
  } else {
27441
- 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.'));
27442
27839
  }
27443
27840
  }
27444
27841
  function shellQuoteSingle(s) {
@@ -27472,7 +27869,7 @@ async function pickProvider() {
27472
27869
  message: "Where do you want to deploy?",
27473
27870
  options: PROVIDERS.map((prov) => ({
27474
27871
  value: prov.id,
27475
- 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)")}`,
27476
27873
  hint: prov.tagline
27477
27874
  }))
27478
27875
  });
@@ -27489,27 +27886,27 @@ async function pickProvider() {
27489
27886
  }
27490
27887
 
27491
27888
  // src/commands/deploy-manage.ts
27492
- var import_picocolors11 = __toESM(require("picocolors"));
27889
+ var import_picocolors12 = __toESM(require("picocolors"));
27493
27890
  async function deployList() {
27494
27891
  console.log();
27495
- 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 ")));
27496
27893
  const workspaces = await collectWorkspacesWithStatus();
27497
27894
  if (workspaces.length === 0) {
27498
- gt(import_picocolors11.default.dim("No deployed workspaces found."));
27895
+ gt(import_picocolors12.default.dim("No deployed workspaces found."));
27499
27896
  return;
27500
27897
  }
27501
27898
  for (const w3 of workspaces) {
27502
- 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"}`);
27503
- 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 + ")")}`);
27504
27901
  }
27505
- 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."));
27506
27903
  }
27507
27904
  async function deployStop() {
27508
27905
  console.log();
27509
- 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 ")));
27510
27907
  const workspaces = await collectWorkspacesWithStatus();
27511
27908
  if (workspaces.length === 0) {
27512
- gt(import_picocolors11.default.dim("No deployed workspaces found."));
27909
+ gt(import_picocolors12.default.dim("No deployed workspaces found."));
27513
27910
  return;
27514
27911
  }
27515
27912
  const choice = await _t({
@@ -27519,7 +27916,7 @@ async function deployStop() {
27519
27916
  label: w3.displayName ?? w3.id,
27520
27917
  hint: [
27521
27918
  w3.providerName,
27522
- 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"),
27523
27920
  w3.state ?? ""
27524
27921
  ].filter(Boolean).join(" \xB7 ")
27525
27922
  }))
@@ -27547,7 +27944,7 @@ async function deployStop() {
27547
27944
  O2.info("No codeam-pair process to stop on this workspace.");
27548
27945
  }
27549
27946
  const alsoStop = await ot2({
27550
- 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?`,
27551
27948
  initialValue: true
27552
27949
  });
27553
27950
  if (!q(alsoStop) && alsoStop) {
@@ -27569,7 +27966,7 @@ async function deployStop() {
27569
27966
  O2.warn(err instanceof Error ? err.message : String(err));
27570
27967
  }
27571
27968
  }
27572
- gt(import_picocolors11.default.green("\u2713 Done."));
27969
+ gt(import_picocolors12.default.green("\u2713 Done."));
27573
27970
  }
27574
27971
  async function collectWorkspacesWithStatus() {
27575
27972
  const out2 = [];
@@ -27675,9 +28072,9 @@ async function host(args2) {
27675
28072
  var import_node_dns = require("dns");
27676
28073
  var import_node_util5 = require("util");
27677
28074
  var import_node_crypto8 = require("crypto");
27678
- var fs45 = __toESM(require("fs"));
27679
- var path56 = __toESM(require("path"));
27680
- 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"));
27681
28078
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
27682
28079
  async function checkDns(apiBase2) {
27683
28080
  const host2 = (() => {
@@ -27732,13 +28129,13 @@ async function checkHealth(apiBase2) {
27732
28129
  }
27733
28130
  }
27734
28131
  function checkConfigDir() {
27735
- const dir = path56.join(require("os").homedir(), ".codeam");
28132
+ const dir = path58.join(require("os").homedir(), ".codeam");
27736
28133
  try {
27737
- fs45.mkdirSync(dir, { recursive: true, mode: 448 });
27738
- const probe = path56.join(dir, ".doctor-probe");
27739
- fs45.writeFileSync(probe, "ok", { mode: 384 });
27740
- const read2 = fs45.readFileSync(probe, "utf8");
27741
- 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);
27742
28139
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
27743
28140
  return {
27744
28141
  id: "config-dir",
@@ -27802,7 +28199,7 @@ function checkNodePty() {
27802
28199
  detail: "not required on this platform"
27803
28200
  };
27804
28201
  }
27805
- const vendoredPath = path56.join(__dirname, "vendor", "node-pty");
28202
+ const vendoredPath = path58.join(__dirname, "vendor", "node-pty");
27806
28203
  for (const target of [vendoredPath, "node-pty"]) {
27807
28204
  try {
27808
28205
  require(target);
@@ -27844,7 +28241,7 @@ function checkChokidar() {
27844
28241
  }
27845
28242
  async function doctor(args2 = []) {
27846
28243
  const json = args2.includes("--json");
27847
- const cliVersion = true ? "2.39.53" : "0.0.0-dev";
28244
+ const cliVersion = true ? "2.39.55" : "0.0.0-dev";
27848
28245
  const apiBase2 = resolveApiBaseUrl();
27849
28246
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
27850
28247
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -27884,46 +28281,46 @@ async function doctor(args2 = []) {
27884
28281
  function printHumanReport(r) {
27885
28282
  const out2 = process.stderr;
27886
28283
  out2.write(`
27887
- ${import_picocolors12.default.bold(" codeam doctor")}
28284
+ ${import_picocolors13.default.bold(" codeam doctor")}
27888
28285
 
27889
28286
  `);
27890
- out2.write(` ${import_picocolors12.default.dim("cli")} ${r.cliVersion}
28287
+ out2.write(` ${import_picocolors13.default.dim("cli")} ${r.cliVersion}
27891
28288
  `);
27892
- out2.write(` ${import_picocolors12.default.dim("node")} ${r.node}
28289
+ out2.write(` ${import_picocolors13.default.dim("node")} ${r.node}
27893
28290
  `);
27894
- out2.write(` ${import_picocolors12.default.dim("os")} ${r.platform} ${r.arch}
28291
+ out2.write(` ${import_picocolors13.default.dim("os")} ${r.platform} ${r.arch}
27895
28292
  `);
27896
- out2.write(` ${import_picocolors12.default.dim("api")} ${r.apiBase}
28293
+ out2.write(` ${import_picocolors13.default.dim("api")} ${r.apiBase}
27897
28294
  `);
27898
28295
  if (process.env.CODEAM_TEST_MODE === "1" || process.env.CODEAM_TEST_MODE?.toLowerCase() === "true") {
27899
- 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")}
27900
28297
  `);
27901
28298
  } else if (process.env.CODEAM_API_URL) {
27902
- 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")}
27903
28300
  `);
27904
28301
  }
27905
- out2.write(` ${import_picocolors12.default.dim("diag id")} ${r.diagnosticId}
28302
+ out2.write(` ${import_picocolors13.default.dim("diag id")} ${r.diagnosticId}
27906
28303
  `);
27907
28304
  out2.write("\n");
27908
28305
  for (const c2 of r.checks) {
27909
- const mark = c2.ok ? import_picocolors12.default.green("\u2713") : c2.optional ? import_picocolors12.default.yellow("!") : import_picocolors12.default.red("\u2717");
27910
- 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}`)}
27911
28308
  `);
27912
28309
  if (!c2.ok && c2.hint) {
27913
28310
  for (const line of c2.hint.split("\n")) {
27914
- out2.write(` ${import_picocolors12.default.dim(line)}
28311
+ out2.write(` ${import_picocolors13.default.dim(line)}
27915
28312
  `);
27916
28313
  }
27917
28314
  }
27918
28315
  }
27919
28316
  out2.write("\n");
27920
28317
  if (r.ok) {
27921
- out2.write(` ${import_picocolors12.default.green("All checks passed.")}
28318
+ out2.write(` ${import_picocolors13.default.green("All checks passed.")}
27922
28319
 
27923
28320
  `);
27924
28321
  } else {
27925
28322
  out2.write(
27926
- ` ${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.")}
27927
28324
 
27928
28325
  `
27929
28326
  );
@@ -28041,118 +28438,118 @@ async function completion(args2) {
28041
28438
  }
28042
28439
 
28043
28440
  // src/commands/version.ts
28044
- var import_picocolors13 = __toESM(require("picocolors"));
28441
+ var import_picocolors14 = __toESM(require("picocolors"));
28045
28442
  function version2() {
28046
- const v = true ? "2.39.53" : "unknown";
28047
- 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)}`);
28048
28445
  }
28049
28446
 
28050
28447
  // src/commands/help.ts
28051
- var import_picocolors14 = __toESM(require("picocolors"));
28448
+ var import_picocolors15 = __toESM(require("picocolors"));
28052
28449
  function help() {
28053
28450
  const lines = [
28054
28451
  "",
28055
- ` ${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")}`,
28056
28453
  "",
28057
- ` ${import_picocolors14.default.bold("Usage")}`,
28058
- ` ${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]")}`,
28059
28456
  "",
28060
- ` ${import_picocolors14.default.bold("Commands")}`,
28061
- ` ${import_picocolors14.default.white("codeam")} ${import_picocolors14.default.dim("start the active agent with mobile control")}`,
28062
- ` ${import_picocolors14.default.white("codeam <agent>")} ${import_picocolors14.default.dim("start a specific agent \u2014 e.g. claude, codex")}`,
28063
- ` ${import_picocolors14.default.white("codeam pair")} ${import_picocolors14.default.dim("pair a new mobile device (interactive)")}`,
28064
- ` ${import_picocolors14.default.white("codeam pair --agent <id>")} ${import_picocolors14.default.dim("pair non-interactively for a specific agent")}`,
28065
- ` ${import_picocolors14.default.white("codeam sessions")} ${import_picocolors14.default.dim("list paired devices")}`,
28066
- ` ${import_picocolors14.default.white("codeam sessions switch")} ${import_picocolors14.default.dim("switch the active paired session")}`,
28067
- ` ${import_picocolors14.default.white("codeam sessions delete <id>")} ${import_picocolors14.default.dim("remove a specific paired session")}`,
28068
- ` ${import_picocolors14.default.white("codeam status")} ${import_picocolors14.default.dim("show connection info")}`,
28069
- ` ${import_picocolors14.default.white("codeam logout")} ${import_picocolors14.default.dim("remove all paired sessions")}`,
28070
- ` ${import_picocolors14.default.white("codeam link <agent>")} ${import_picocolors14.default.dim("link an agent (claude, codex) to your CodeAgent account")}`,
28071
- ` ${import_picocolors14.default.white("codeam deploy")} ${import_picocolors14.default.dim("provision a cloud workspace (Codespaces) and pair it")}`,
28072
- ` ${import_picocolors14.default.white("codeam deploy ls | list")} ${import_picocolors14.default.dim("list deployed cloud workspaces")}`,
28073
- ` ${import_picocolors14.default.white("codeam deploy stop | remove")} ${import_picocolors14.default.dim("stop a deployed workspace session")}`,
28074
- ` ${import_picocolors14.default.white("codeam doctor")} ${import_picocolors14.default.dim("run diagnostic checks (DNS, /health, binaries, \u2026)")}`,
28075
- ` ${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")}`,
28076
28473
  "",
28077
- ` ${import_picocolors14.default.bold("Flags")}`,
28078
- ` ${import_picocolors14.default.white("-v, --version")} ${import_picocolors14.default.dim("print the CLI version")}`,
28079
- ` ${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")}`,
28080
28477
  "",
28081
- ` ${import_picocolors14.default.bold("Links")}`,
28082
- ` ${import_picocolors14.default.dim("Docs:")} ${import_picocolors14.default.green("https://www.codeagent-mobile.com")}`,
28083
- ` ${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")}`,
28084
28481
  ""
28085
28482
  ];
28086
28483
  process.stdout.write(lines.join("\n") + "\n");
28087
28484
  }
28088
28485
 
28089
28486
  // src/commands/subcommand-help.ts
28090
- var import_picocolors15 = __toESM(require("picocolors"));
28487
+ var import_picocolors16 = __toESM(require("picocolors"));
28091
28488
  var HELPS = {
28092
28489
  pair: () => print([
28093
- ` ${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")}`,
28094
28491
  "",
28095
- ` ${import_picocolors15.default.cyan("codeam pair")} ${import_picocolors15.default.dim("interactive pairing (prompts for the agent)")}`,
28096
- ` ${import_picocolors15.default.cyan("codeam pair --agent <id>")} ${import_picocolors15.default.dim("pair non-interactively (agent: claude | codex)")}`,
28097
- ` ${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")}`
28098
28495
  ]),
28099
28496
  "pair-auto": () => print([
28100
- ` ${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")}`,
28101
28498
  "",
28102
- ` ${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")}`
28103
28500
  ]),
28104
28501
  link: () => print([
28105
- ` ${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")}`,
28106
28503
  "",
28107
- ` ${import_picocolors15.default.cyan("codeam link claude")}`,
28108
- ` ${import_picocolors15.default.cyan("codeam link codex")}`,
28504
+ ` ${import_picocolors16.default.cyan("codeam link claude")}`,
28505
+ ` ${import_picocolors16.default.cyan("codeam link codex")}`,
28109
28506
  "",
28110
- ` ${import_picocolors15.default.white("--api-key=<key>")} ${import_picocolors15.default.dim("paste an API key directly (visible in `ps -ef`)")}`,
28111
- ` ${import_picocolors15.default.white("--api-key-file=<path>")} ${import_picocolors15.default.dim("read API key from a file (recommended for CI / scripts)")}`,
28112
- ` ${import_picocolors15.default.white("--reuse-existing")} ${import_picocolors15.default.dim("upload existing creds without re-launching the agent login")}`,
28113
- ` ${import_picocolors15.default.white("--token-file=<path>")} ${import_picocolors15.default.dim("manual credential blob path for unusual vendor locations")}`,
28114
- ` ${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")}`
28115
28512
  ]),
28116
28513
  sessions: () => print([
28117
- ` ${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")}`,
28118
28515
  "",
28119
- ` ${import_picocolors15.default.cyan("codeam sessions")} ${import_picocolors15.default.dim("list all paired sessions on this machine")}`,
28120
- ` ${import_picocolors15.default.cyan("codeam sessions switch")} ${import_picocolors15.default.dim("interactively switch the active session")}`,
28121
- ` ${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")}`
28122
28519
  ]),
28123
28520
  deploy: () => print([
28124
- ` ${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")}`,
28125
28522
  "",
28126
- ` ${import_picocolors15.default.cyan("codeam deploy")} ${import_picocolors15.default.dim("start a new deploy (prompts for repo + agent)")}`,
28127
- ` ${import_picocolors15.default.cyan("codeam deploy ls | list")} ${import_picocolors15.default.dim("list deployed cloud workspaces")}`,
28128
- ` ${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")}`
28129
28526
  ]),
28130
28527
  status: () => print([
28131
- ` ${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")}`
28132
28529
  ]),
28133
28530
  logout: () => print([
28134
- ` ${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")}`
28135
28532
  ]),
28136
28533
  doctor: () => print([
28137
- ` ${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")}`,
28138
28535
  "",
28139
- ` ${import_picocolors15.default.cyan("codeam doctor")} ${import_picocolors15.default.dim("human-readable report")}`,
28140
- ` ${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)")}`,
28141
28538
  "",
28142
- ` ${import_picocolors15.default.dim("Output never includes tokens or credentials. Paste the diagnostic id")}`,
28143
- ` ${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.")}`
28144
28541
  ]),
28145
28542
  completion: () => print([
28146
- ` ${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")}`,
28147
28544
  "",
28148
- ` ${import_picocolors15.default.cyan("codeam completion bash")} ${import_picocolors15.default.dim("print a bash completion function")}`,
28149
- ` ${import_picocolors15.default.cyan("codeam completion zsh")} ${import_picocolors15.default.dim("print a zsh completion function")}`,
28150
- ` ${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")}`,
28151
28548
  "",
28152
- ` ${import_picocolors15.default.dim("Examples:")}`,
28153
- ` ${import_picocolors15.default.dim(" bash: codeam completion bash >> ~/.bashrc")}`,
28154
- ` ${import_picocolors15.default.dim(" zsh: codeam completion zsh >> ~/.zshrc")}`,
28155
- ` ${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")}`
28156
28553
  ])
28157
28554
  };
28158
28555
  function print(lines) {
@@ -28170,179 +28567,6 @@ function tryShowSubcommandHelp(cmd, args2) {
28170
28567
  }
28171
28568
  var _subcommandHelpKeys = Object.keys(HELPS);
28172
28569
 
28173
- // src/lib/updateNotifier.ts
28174
- var fs46 = __toESM(require("fs"));
28175
- var os37 = __toESM(require("os"));
28176
- var path57 = __toESM(require("path"));
28177
- var https8 = __toESM(require("https"));
28178
- var import_node_child_process15 = require("child_process");
28179
- var import_picocolors16 = __toESM(require("picocolors"));
28180
- var PKG_NAME = "codeam-cli";
28181
- var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
28182
- var TTL_MS = 24 * 60 * 60 * 1e3;
28183
- var REQUEST_TIMEOUT_MS = 1500;
28184
- function cachePath() {
28185
- const dir = path57.join(os37.homedir(), ".codeam");
28186
- return path57.join(dir, "update-check.json");
28187
- }
28188
- function readCache() {
28189
- try {
28190
- const raw = fs46.readFileSync(cachePath(), "utf8");
28191
- const parsed = JSON.parse(raw);
28192
- if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
28193
- return parsed;
28194
- } catch {
28195
- return null;
28196
- }
28197
- }
28198
- function writeCache(cache) {
28199
- try {
28200
- const file = cachePath();
28201
- fs46.mkdirSync(path57.dirname(file), { recursive: true });
28202
- const tmp = `${file}.${process.pid}.tmp`;
28203
- fs46.writeFileSync(tmp, JSON.stringify(cache));
28204
- fs46.renameSync(tmp, file);
28205
- } catch {
28206
- }
28207
- }
28208
- function compareSemver(a, b) {
28209
- const stripPre = (s) => s.split("-")[0];
28210
- const aParts = stripPre(a).split(".").map(Number);
28211
- const bParts = stripPre(b).split(".").map(Number);
28212
- for (let i = 0; i < 3; i++) {
28213
- const ai = aParts[i] ?? 0;
28214
- const bi = bParts[i] ?? 0;
28215
- if (Number.isNaN(ai) || Number.isNaN(bi)) return 0;
28216
- if (ai > bi) return 1;
28217
- if (ai < bi) return -1;
28218
- }
28219
- return 0;
28220
- }
28221
- function fetchLatest() {
28222
- return new Promise((resolve7) => {
28223
- const req = https8.get(
28224
- REGISTRY_URL,
28225
- { headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
28226
- (res) => {
28227
- if (res.statusCode !== 200) {
28228
- res.resume();
28229
- resolve7(null);
28230
- return;
28231
- }
28232
- let buf = "";
28233
- res.setEncoding("utf8");
28234
- res.on("data", (chunk) => {
28235
- buf += chunk;
28236
- });
28237
- res.on("end", () => {
28238
- try {
28239
- const json = JSON.parse(buf);
28240
- if (typeof json.version === "string") {
28241
- resolve7(json.version);
28242
- } else {
28243
- resolve7(null);
28244
- }
28245
- } catch {
28246
- resolve7(null);
28247
- }
28248
- });
28249
- }
28250
- );
28251
- req.on("timeout", () => {
28252
- req.destroy();
28253
- resolve7(null);
28254
- });
28255
- req.on("error", () => resolve7(null));
28256
- });
28257
- }
28258
- function notifyIfStale(currentVersion, latest) {
28259
- if (compareSemver(latest, currentVersion) <= 0) return;
28260
- const arrow = import_picocolors16.default.dim("\u2192");
28261
- const cmd = import_picocolors16.default.cyan("npm install -g codeam-cli");
28262
- const lines = [
28263
- "",
28264
- ` ${import_picocolors16.default.yellow("\u25CF")} ${import_picocolors16.default.bold("Update available")} ${import_picocolors16.default.dim(currentVersion)} ${arrow} ${import_picocolors16.default.green(latest)}`,
28265
- ` Run ${cmd} to upgrade.`,
28266
- ""
28267
- ];
28268
- process.stderr.write(lines.join("\n"));
28269
- }
28270
- function isLinkedInstall() {
28271
- try {
28272
- const root = (0, import_node_child_process15.execSync)("npm root -g", {
28273
- encoding: "utf8",
28274
- stdio: ["ignore", "pipe", "ignore"],
28275
- timeout: 2e3
28276
- }).trim();
28277
- if (!root) return false;
28278
- const pkgPath = path57.join(root, PKG_NAME);
28279
- return fs46.lstatSync(pkgPath).isSymbolicLink();
28280
- } catch {
28281
- return false;
28282
- }
28283
- }
28284
- function maybeAutoUpdate(currentVersion, latest) {
28285
- if (compareSemver(latest, currentVersion) <= 0) return;
28286
- if (process.env.CODEAM_NO_AUTO_UPDATE === "1") {
28287
- notifyIfStale(currentVersion, latest);
28288
- return;
28289
- }
28290
- if (isLinkedInstall()) {
28291
- notifyIfStale(currentVersion, latest);
28292
- return;
28293
- }
28294
- process.stderr.write(
28295
- `
28296
- ${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)}...
28297
-
28298
- `
28299
- );
28300
- const install = (0, import_node_child_process15.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
28301
- stdio: "inherit",
28302
- env: process.env
28303
- });
28304
- if (install.status !== 0) {
28305
- process.stderr.write(
28306
- `
28307
- ${import_picocolors16.default.red("!")} Update failed (exit ${install.status ?? "?"}). Continuing on ${currentVersion}.
28308
- Run ${import_picocolors16.default.cyan("npm install -g codeam-cli")} manually to retry.
28309
-
28310
- `
28311
- );
28312
- return;
28313
- }
28314
- try {
28315
- fs46.unlinkSync(cachePath());
28316
- } catch {
28317
- }
28318
- process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
28319
-
28320
- `);
28321
- const child = (0, import_node_child_process15.spawnSync)("codeam", process.argv.slice(2), {
28322
- stdio: "inherit",
28323
- env: process.env
28324
- });
28325
- process.exit(child.status ?? 0);
28326
- }
28327
- function checkForUpdates() {
28328
- if (process.env.NODE_ENV === "test") return;
28329
- if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
28330
- if (process.env.CI) return;
28331
- if (!process.stdout.isTTY) return;
28332
- const current = true ? "2.39.53" : null;
28333
- if (!current) return;
28334
- const cache = readCache();
28335
- const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
28336
- if (fresh && cache) {
28337
- maybeAutoUpdate(current, cache.latest);
28338
- return;
28339
- }
28340
- void fetchLatest().then((latest) => {
28341
- if (!latest) return;
28342
- writeCache({ fetchedAt: Date.now(), latest });
28343
- });
28344
- }
28345
-
28346
28570
  // src/exit-codes.ts
28347
28571
  var EXIT_OK = 0;
28348
28572
  var EXIT_FAILURE = 1;