codeam-cli 2.61.22 → 2.61.24

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 +23 -0
  2. package/dist/index.js +742 -472
  3. package/package.json +5 -4
package/dist/index.js CHANGED
@@ -806,6 +806,91 @@ function isKnownIntegrationId(id) {
806
806
  return id in INTEGRATION_REGISTRY;
807
807
  }
808
808
 
809
+ // ../../packages/shared/src/skills/registry.ts
810
+ var CODE_REVIEW_BODY = `Use this skill when reviewing a pull request. It defines what a high-signal
811
+ review looks like so your inline comments are worth the author's time.
812
+
813
+ ## Review priorities (in order)
814
+ 1. **Correctness** \u2014 does the change do what the PR says, and only that? Trace the
815
+ changed paths for logic errors, off-by-one, null/undefined, wrong branch, and
816
+ inverted conditions. State a concrete failure scenario (inputs \u2192 wrong output)
817
+ for anything you flag as a bug.
818
+ 2. **Security** \u2014 untrusted input reaching a sink (SQL, shell, path, HTML), secrets
819
+ in code/logs, authz gaps, credentials passed via argv instead of env.
820
+ 3. **Tests** \u2014 does the change carry tests that would fail without it? Missing
821
+ coverage on a bug-prone path is a finding.
822
+ 4. **Clarity / reuse** \u2014 duplicated logic, a simpler existing helper, a name that
823
+ misleads. Only raise these when they materially affect maintainability.
824
+
825
+ ## Comment discipline
826
+ - One finding per comment, anchored to the exact line.
827
+ - Lead with severity: **blocker**, **should-fix**, or **nit**.
828
+ - Say WHY (the failure or risk), not just WHAT. Propose the fix when it is short.
829
+ - Do NOT restate the diff, praise trivially, or nitpick style a formatter owns.
830
+ - If the PR is correct and well-tested, say so plainly and approve \u2014 a clean review
831
+ is a valid outcome, not a failure to find something.
832
+
833
+ ## Scope
834
+ Review only what the diff changes and its direct blast radius. Do not demand
835
+ unrelated refactors.`;
836
+ var CODE_REVIEW_INSTRUCTION = `When reviewing this PR, prioritize correctness first, then security, then test
837
+ coverage, then clarity/reuse. One finding per inline comment, anchored to the exact
838
+ line, each led by a severity tag (blocker/should-fix/nit) and a concrete reason
839
+ (the failure scenario or risk), not a restatement of the diff. If the change is
840
+ correct and well-tested, approve and say so \u2014 finding nothing is a valid outcome.
841
+ Review only the diff and its direct blast radius; do not demand unrelated refactors.`;
842
+ var RESOLVE_CONFLICTS_BODY = `Use this skill when resolving merge conflicts on a pull request. The goal is a
843
+ merge that preserves BOTH sides' intent, not one that just makes the file compile.
844
+
845
+ ## Method
846
+ 1. Understand each conflict hunk before editing: what did HEAD change, what did the
847
+ base branch change, and WHY. Read the surrounding function, not just the markers.
848
+ 2. Prefer a union of intents. Drop a side only when the two changes are genuinely
849
+ mutually exclusive \u2014 and when you do, keep the side that matches the PR's purpose.
850
+ 3. Never leave a conflict marker (\`<<<<<<<\`, \`=======\`, \`>>>>>>>\`) behind. Grep for
851
+ them before committing.
852
+ 4. After resolving, the code must build and its tests must pass. Run them. A merge
853
+ that resolves markers but breaks the build is not done.
854
+ 5. For lockfiles/generated files, regenerate rather than hand-merge.
855
+
856
+ ## Commit
857
+ One commit that explains what was reconciled and any intent you had to choose
858
+ between. Then push the branch.`;
859
+ var RESOLVE_CONFLICTS_INSTRUCTION = `When resolving these merge conflicts, preserve both sides' intent \u2014 read each hunk's
860
+ surrounding code to understand what HEAD and the base branch each changed and why,
861
+ and prefer a union of intents; drop a side only when the two are mutually exclusive,
862
+ keeping the side that matches the PR's purpose. Leave no conflict markers behind
863
+ (grep for them). Regenerate lockfiles rather than hand-merging them. The result must
864
+ build and pass tests \u2014 run them \u2014 before you commit and push.`;
865
+ var SKILL_REGISTRY = {
866
+ "code-review": {
867
+ id: "code-review",
868
+ name: "Code Review",
869
+ description: `High-signal PR review: prioritize correctness \u2192 security \u2192 tests \u2192 clarity, one anchored finding per comment.`,
870
+ source: "curated",
871
+ delivery: {
872
+ skillFile: { body: CODE_REVIEW_BODY },
873
+ instruction: { body: CODE_REVIEW_INSTRUCTION }
874
+ }
875
+ },
876
+ "resolve-conflicts": {
877
+ id: "resolve-conflicts",
878
+ name: "Resolve Conflicts",
879
+ description: `Merge-conflict resolution that preserves both sides' intent, leaves no markers, and keeps the build green.`,
880
+ source: "curated",
881
+ delivery: {
882
+ skillFile: { body: RESOLVE_CONFLICTS_BODY },
883
+ instruction: { body: RESOLVE_CONFLICTS_INSTRUCTION }
884
+ }
885
+ }
886
+ };
887
+ function isSkillId(id) {
888
+ return Object.prototype.hasOwnProperty.call(SKILL_REGISTRY, id);
889
+ }
890
+ function getSkillDefinition(id) {
891
+ return isSkillId(id) ? SKILL_REGISTRY[id] : null;
892
+ }
893
+
809
894
  // ../../packages/shared/src/api-url.ts
810
895
  var DEFAULT_API_BASE_URL = "https://api.codeagent-mobile.com";
811
896
  var DEV_API_BASE_URL = "https://dev-api.codeagent-mobile.com";
@@ -1130,11 +1215,11 @@ function quiet(fn) {
1130
1215
  log.debug(TAG, "ignored sync error", err);
1131
1216
  }
1132
1217
  }
1133
- function rmIfExistsQuiet(path76) {
1218
+ function rmIfExistsQuiet(path78) {
1134
1219
  try {
1135
- fs2.rmSync(path76, { force: true });
1220
+ fs2.rmSync(path78, { force: true });
1136
1221
  } catch (err) {
1137
- log.debug(TAG, `rmIfExists failed for ${path76}`, err);
1222
+ log.debug(TAG, `rmIfExists failed for ${path78}`, err);
1138
1223
  }
1139
1224
  }
1140
1225
  function killQuiet(target, signal = "SIGTERM") {
@@ -1280,9 +1365,9 @@ var _default = makeConfig();
1280
1365
  var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, setDisable1mContext, clearAll, saveCliConfig, loadCliConfig } = _default;
1281
1366
 
1282
1367
  // src/commands/pair-auto.ts
1283
- var fs56 = __toESM(require("fs"));
1284
- var os45 = __toESM(require("os"));
1285
- var path60 = __toESM(require("path"));
1368
+ var fs58 = __toESM(require("fs"));
1369
+ var os48 = __toESM(require("os"));
1370
+ var path62 = __toESM(require("path"));
1286
1371
  var import_crypto4 = require("crypto");
1287
1372
 
1288
1373
  // src/services/telemetry.service.ts
@@ -1318,8 +1403,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
1318
1403
  return decodedFile;
1319
1404
  };
1320
1405
  }
1321
- function normalizeWindowsPath(path76) {
1322
- return path76.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1406
+ function normalizeWindowsPath(path78) {
1407
+ return path78.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1323
1408
  }
1324
1409
 
1325
1410
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3799,9 +3884,9 @@ async function addSourceContext(frames) {
3799
3884
  LRU_FILE_CONTENTS_CACHE.reduce();
3800
3885
  return frames;
3801
3886
  }
3802
- function getContextLinesFromFile(path76, ranges, output) {
3887
+ function getContextLinesFromFile(path78, ranges, output) {
3803
3888
  return new Promise((resolve8) => {
3804
- const stream = (0, import_node_fs.createReadStream)(path76);
3889
+ const stream = (0, import_node_fs.createReadStream)(path78);
3805
3890
  const lineReaded = (0, import_node_readline.createInterface)({
3806
3891
  input: stream
3807
3892
  });
@@ -3816,7 +3901,7 @@ function getContextLinesFromFile(path76, ranges, output) {
3816
3901
  let rangeStart = range[0];
3817
3902
  let rangeEnd = range[1];
3818
3903
  function onStreamError() {
3819
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path76, 1);
3904
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path78, 1);
3820
3905
  lineReaded.close();
3821
3906
  lineReaded.removeAllListeners();
3822
3907
  destroyStreamAndResolve();
@@ -3877,8 +3962,8 @@ function clearLineContext(frame) {
3877
3962
  delete frame.context_line;
3878
3963
  delete frame.post_context;
3879
3964
  }
3880
- function shouldSkipContextLinesForFile(path76) {
3881
- return path76.startsWith("node:") || path76.endsWith(".min.js") || path76.endsWith(".min.cjs") || path76.endsWith(".min.mjs") || path76.startsWith("data:");
3965
+ function shouldSkipContextLinesForFile(path78) {
3966
+ return path78.startsWith("node:") || path78.endsWith(".min.js") || path78.endsWith(".min.cjs") || path78.endsWith(".min.mjs") || path78.startsWith("data:");
3882
3967
  }
3883
3968
  function shouldSkipContextLinesForFrame(frame) {
3884
3969
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -6032,7 +6117,7 @@ function readAnonId() {
6032
6117
  }
6033
6118
  function superProperties() {
6034
6119
  return {
6035
- cliVersion: true ? "2.61.22" : "0.0.0-dev",
6120
+ cliVersion: true ? "2.61.24" : "0.0.0-dev",
6036
6121
  nodeVersion: process.version,
6037
6122
  platform: process.platform,
6038
6123
  arch: process.arch,
@@ -6213,7 +6298,7 @@ var os4 = __toESM(require("os"));
6213
6298
  // package.json
6214
6299
  var package_default = {
6215
6300
  name: "codeam-cli",
6216
- version: "2.61.22",
6301
+ version: "2.61.24",
6217
6302
  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.",
6218
6303
  type: "commonjs",
6219
6304
  main: "dist/index.js",
@@ -6290,7 +6375,7 @@ var package_default = {
6290
6375
  "@agentclientprotocol/sdk": "1.2.1",
6291
6376
  "@clack/prompts": "^1.2.0",
6292
6377
  chokidar: "^3.6.0",
6293
- ignore: "^5.3.2",
6378
+ ignore: "^7.0.6",
6294
6379
  picocolors: "^1.1.0",
6295
6380
  "qrcode-terminal": "^0.12.0",
6296
6381
  which: "^6.0.0",
@@ -6309,8 +6394,9 @@ var package_default = {
6309
6394
  "@vitest/coverage-v8": "^4.1.7",
6310
6395
  "node-pty": "^1.1.0",
6311
6396
  tsup: "^8.0.0",
6312
- typescript: "^6.0.3",
6313
- vitest: "^4.1.5"
6397
+ typescript: "^7.0.2",
6398
+ vitest: "^4.1.5",
6399
+ yaml: "^2.9.0"
6314
6400
  }
6315
6401
  };
6316
6402
 
@@ -7377,7 +7463,7 @@ var CommandRelayService = class _CommandRelayService {
7377
7463
  // fresh + clear the "CLI update available" banner after a self-update
7378
7464
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
7379
7465
  // pair/reconnect). Older backends ignore the extra field.
7380
- ..."2.61.22" ? { ideVersion: "2.61.22" } : {}
7466
+ ..."2.61.24" ? { ideVersion: "2.61.24" } : {}
7381
7467
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
7382
7468
  }
7383
7469
  /**
@@ -8751,9 +8837,9 @@ function closeAllTerminals() {
8751
8837
  }
8752
8838
 
8753
8839
  // src/commands/start/handlers.ts
8754
- var fs55 = __toESM(require("fs"));
8755
- var os44 = __toESM(require("os"));
8756
- var path59 = __toESM(require("path"));
8840
+ var fs57 = __toESM(require("fs"));
8841
+ var os47 = __toESM(require("os"));
8842
+ var path61 = __toESM(require("path"));
8757
8843
  var import_crypto3 = require("crypto");
8758
8844
  var import_child_process24 = require("child_process");
8759
8845
 
@@ -8831,7 +8917,12 @@ var startCommandSchema = import_zod.z.object({
8831
8917
  // Restore the caller's already-vaulted CodeRabbit credential onto this
8832
8918
  // session (no re-login) — fetches from the backend + installs + writes it.
8833
8919
  "provision",
8834
- "review"
8920
+ "review",
8921
+ // `skills_configure` — attach/detach a curated Agent Skill on a RUNNING
8922
+ // session (Claude hot-reloads ~/.claude/skills/), or list what's installed.
8923
+ "add",
8924
+ "remove",
8925
+ "list"
8835
8926
  ]).optional(),
8836
8927
  // `headroom_configure` — savings ingest URL delivered from the session
8837
8928
  // when enabling Headroom on-demand. Bounded to 2048 chars.
@@ -8938,7 +9029,11 @@ var startCommandSchema = import_zod.z.object({
8938
9029
  key: import_zod.z.string().min(1).max(256),
8939
9030
  value: import_zod.z.string().max(32768)
8940
9031
  })
8941
- ).max(512).optional()
9032
+ ).max(512).optional(),
9033
+ // `skills_configure` — the curated `SkillId` to add/remove. `list` (and a
9034
+ // malformed/unknown id on add/remove) sends no `skillId` or an invalid one;
9035
+ // `configureSkill` itself validates against the shared registry.
9036
+ skillId: import_zod.z.string().min(1).max(128).optional()
8942
9037
  });
8943
9038
  function parsePayload2(schema, raw) {
8944
9039
  const result = schema.safeParse(raw);
@@ -12224,10 +12319,10 @@ function buildForPlatform(platform3) {
12224
12319
  var import_node_crypto4 = require("crypto");
12225
12320
 
12226
12321
  // src/agents/claude/resolver.ts
12227
- function buildClaudeLaunch(extraArgs = [], os53 = createOsStrategy()) {
12228
- const found = os53.findInPath("claude") ?? os53.findInPath("claude-code");
12322
+ function buildClaudeLaunch(extraArgs = [], os57 = createOsStrategy()) {
12323
+ const found = os57.findInPath("claude") ?? os57.findInPath("claude-code");
12229
12324
  if (!found) return null;
12230
- return os53.buildLaunch(found, extraArgs);
12325
+ return os57.buildLaunch(found, extraArgs);
12231
12326
  }
12232
12327
 
12233
12328
  // src/agents/claude/installer.ts
@@ -12817,8 +12912,8 @@ var ClaudeRuntimeStrategy = class {
12817
12912
  meta = getAgent("claude");
12818
12913
  mode = "interactive";
12819
12914
  os;
12820
- constructor(os53) {
12821
- this.os = os53;
12915
+ constructor(os57) {
12916
+ this.os = os57;
12822
12917
  }
12823
12918
  /**
12824
12919
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -13598,8 +13693,8 @@ function codexCredentialLocator() {
13598
13693
  function codexLoginLauncher() {
13599
13694
  return {
13600
13695
  async ensureInstalled() {
13601
- const os53 = createOsStrategy();
13602
- return os53.findInPath("codex") !== null;
13696
+ const os57 = createOsStrategy();
13697
+ return os57.findInPath("codex") !== null;
13603
13698
  },
13604
13699
  launch() {
13605
13700
  return (0, import_node_child_process4.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -13622,8 +13717,8 @@ var CodexRuntimeStrategy = class {
13622
13717
  meta = getAgent("codex");
13623
13718
  mode = "interactive";
13624
13719
  os;
13625
- constructor(os53) {
13626
- this.os = os53;
13720
+ constructor(os57) {
13721
+ this.os = os57;
13627
13722
  }
13628
13723
  async prepareLaunch() {
13629
13724
  let binary = this.os.findInPath("codex");
@@ -13732,12 +13827,12 @@ var CodexRuntimeStrategy = class {
13732
13827
  });
13733
13828
  }
13734
13829
  };
13735
- function resolveNpm(os53) {
13736
- return os53.id === "win32" ? "npm.cmd" : "npm";
13830
+ function resolveNpm(os57) {
13831
+ return os57.id === "win32" ? "npm.cmd" : "npm";
13737
13832
  }
13738
- async function installCodexViaNpm(os53) {
13833
+ async function installCodexViaNpm(os57) {
13739
13834
  return new Promise((resolve8, reject) => {
13740
- const proc = (0, import_node_child_process5.spawn)(resolveNpm(os53), ["install", "-g", "@openai/codex"], {
13835
+ const proc = (0, import_node_child_process5.spawn)(resolveNpm(os57), ["install", "-g", "@openai/codex"], {
13741
13836
  stdio: "inherit"
13742
13837
  });
13743
13838
  proc.on("close", (code) => {
@@ -13754,16 +13849,16 @@ async function installCodexViaNpm(os53) {
13754
13849
  });
13755
13850
  });
13756
13851
  }
13757
- function augmentNpmGlobalBin(os53) {
13852
+ function augmentNpmGlobalBin(os57) {
13758
13853
  try {
13759
- const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os53), ["prefix", "-g"], {
13854
+ const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os57), ["prefix", "-g"], {
13760
13855
  stdio: ["ignore", "pipe", "ignore"]
13761
13856
  });
13762
13857
  if (result.status !== 0) return;
13763
13858
  const prefix = result.stdout.toString().trim();
13764
13859
  if (!prefix) return;
13765
- const binDir = os53.id === "win32" ? prefix : path24.join(prefix, "bin");
13766
- os53.augmentPath([binDir]);
13860
+ const binDir = os57.id === "win32" ? prefix : path24.join(prefix, "bin");
13861
+ os57.augmentPath([binDir]);
13767
13862
  } catch {
13768
13863
  }
13769
13864
  }
@@ -13847,9 +13942,9 @@ var import_node_child_process8 = require("child_process");
13847
13942
  // src/agents/coderabbit/installer.ts
13848
13943
  var import_node_child_process6 = require("child_process");
13849
13944
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
13850
- async function ensureCoderabbitInstalled(os53) {
13851
- if (os53.findInPath("coderabbit")) return true;
13852
- if (os53.id === "win32") {
13945
+ async function ensureCoderabbitInstalled(os57) {
13946
+ if (os57.findInPath("coderabbit")) return true;
13947
+ if (os57.id === "win32") {
13853
13948
  console.error(
13854
13949
  "\n \u2717 CodeRabbit on Windows requires WSL.\n Install the CLI inside your WSL distribution\n (curl -fsSL https://cli.coderabbit.ai/install.sh | sh)\n then re-run `codeam link coderabbit` from WSL.\n"
13855
13950
  );
@@ -13882,8 +13977,8 @@ async function ensureCoderabbitInstalled(os53) {
13882
13977
  proc.on("error", () => finish(false));
13883
13978
  });
13884
13979
  if (!ok) return false;
13885
- os53.augmentPath([`${os53.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
13886
- return os53.findInPath("coderabbit") !== null;
13980
+ os57.augmentPath([`${os57.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
13981
+ return os57.findInPath("coderabbit") !== null;
13887
13982
  }
13888
13983
 
13889
13984
  // src/agents/coderabbit/link.ts
@@ -13918,10 +14013,10 @@ function coderabbitCredentialLocator() {
13918
14013
  validate: validateNonEmptyCredential
13919
14014
  };
13920
14015
  }
13921
- function coderabbitLoginLauncher(os53) {
14016
+ function coderabbitLoginLauncher(os57) {
13922
14017
  return {
13923
14018
  async ensureInstalled() {
13924
- return ensureCoderabbitInstalled(os53);
14019
+ return ensureCoderabbitInstalled(os57);
13925
14020
  },
13926
14021
  launch() {
13927
14022
  return (0, import_node_child_process7.spawn)("coderabbit", ["auth", "login"], { stdio: "inherit" });
@@ -13977,8 +14072,8 @@ function pickLine(obj) {
13977
14072
  function toHunk(raw, groupSeverity) {
13978
14073
  if (!raw || typeof raw !== "object") return null;
13979
14074
  const o = raw;
13980
- const path76 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
13981
- if (!path76) return null;
14075
+ const path78 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
14076
+ if (!path78) return null;
13982
14077
  const message = asString(
13983
14078
  pick(o, [
13984
14079
  "comment",
@@ -13995,7 +14090,7 @@ function toHunk(raw, groupSeverity) {
13995
14090
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
13996
14091
  const locObj = pick(o, ["location"]) ?? o;
13997
14092
  return {
13998
- path: path76.trim(),
14093
+ path: path78.trim(),
13999
14094
  line: pickLine(o) ?? pickLine(locObj),
14000
14095
  severity,
14001
14096
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -14078,10 +14173,10 @@ function parsePlain(stdout) {
14078
14173
  for (const line of stdout.split(/\r?\n/)) {
14079
14174
  const m = line.match(HUNK_LINE_RE);
14080
14175
  if (!m) continue;
14081
- const [, path76, lineNo, sevToken, message] = m;
14082
- if (!path76 || !lineNo || !message) continue;
14176
+ const [, path78, lineNo, sevToken, message] = m;
14177
+ if (!path78 || !lineNo || !message) continue;
14083
14178
  hunks.push({
14084
- path: path76.trim(),
14179
+ path: path78.trim(),
14085
14180
  line: Number(lineNo),
14086
14181
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
14087
14182
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -14141,8 +14236,8 @@ var CoderabbitRuntimeStrategy = class {
14141
14236
  meta = getAgent("coderabbit");
14142
14237
  mode = "batch";
14143
14238
  os;
14144
- constructor(os53) {
14145
- this.os = os53;
14239
+ constructor(os57) {
14240
+ this.os = os57;
14146
14241
  }
14147
14242
  getDefaultArgs() {
14148
14243
  return ["review", "--agent"];
@@ -14413,10 +14508,10 @@ function cursorCredentialLocator() {
14413
14508
  validate: validateNonEmptyCredential
14414
14509
  };
14415
14510
  }
14416
- function cursorLoginLauncher(os53) {
14511
+ function cursorLoginLauncher(os57) {
14417
14512
  return {
14418
14513
  async ensureInstalled() {
14419
- if (os53.findInPath("cursor-agent")) return true;
14514
+ if (os57.findInPath("cursor-agent")) return true;
14420
14515
  console.error(
14421
14516
  "\n \u2717 cursor-agent binary not on PATH.\n Install Cursor (https://cursor.com/) and ensure the CLI\n plugin is enabled, then re-run `codeam link cursor`.\n"
14422
14517
  );
@@ -14480,8 +14575,8 @@ var CursorRuntimeStrategy = class {
14480
14575
  meta = getAgent("cursor");
14481
14576
  mode = "interactive";
14482
14577
  os;
14483
- constructor(os53) {
14484
- this.os = os53;
14578
+ constructor(os57) {
14579
+ this.os = os57;
14485
14580
  }
14486
14581
  async prepareLaunch() {
14487
14582
  const binary = this.os.findInPath("cursor-agent");
@@ -14697,10 +14792,10 @@ function aiderCredentialLocator() {
14697
14792
  validate: validateNonEmptyCredential
14698
14793
  };
14699
14794
  }
14700
- function aiderLoginLauncher(os53) {
14795
+ function aiderLoginLauncher(os57) {
14701
14796
  return {
14702
14797
  async ensureInstalled() {
14703
- if (os53.findInPath("aider")) return true;
14798
+ if (os57.findInPath("aider")) return true;
14704
14799
  console.error(
14705
14800
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
14706
14801
  );
@@ -14710,7 +14805,7 @@ function aiderLoginLauncher(os53) {
14710
14805
  console.error(
14711
14806
  "\n Aider has no interactive login flow.\n Set ANTHROPIC_API_KEY or OPENAI_API_KEY in your shell,\n or re-run `codeam link aider --api-key=<your-key>`.\n"
14712
14807
  );
14713
- return (0, import_node_child_process11.spawn)(os53.id === "win32" ? "cmd.exe" : "sh", os53.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
14808
+ return (0, import_node_child_process11.spawn)(os57.id === "win32" ? "cmd.exe" : "sh", os57.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
14714
14809
  stdio: "ignore"
14715
14810
  });
14716
14811
  }
@@ -14782,8 +14877,8 @@ var AiderRuntimeStrategy = class {
14782
14877
  meta = getAgent("aider");
14783
14878
  mode = "interactive";
14784
14879
  os;
14785
- constructor(os53) {
14786
- this.os = os53;
14880
+ constructor(os57) {
14881
+ this.os = os57;
14787
14882
  }
14788
14883
  async prepareLaunch() {
14789
14884
  const binary = this.os.findInPath("aider");
@@ -14915,8 +15010,8 @@ function geminiCredentialLocator() {
14915
15010
  function geminiLoginLauncher() {
14916
15011
  return {
14917
15012
  async ensureInstalled() {
14918
- const os53 = createOsStrategy();
14919
- return os53.findInPath("gemini") !== null;
15013
+ const os57 = createOsStrategy();
15014
+ return os57.findInPath("gemini") !== null;
14920
15015
  },
14921
15016
  launch() {
14922
15017
  return (0, import_node_child_process12.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -15106,8 +15201,8 @@ var GeminiRuntimeStrategy = class {
15106
15201
  meta = getAgent("gemini");
15107
15202
  mode = "interactive";
15108
15203
  os;
15109
- constructor(os53) {
15110
- this.os = os53;
15204
+ constructor(os57) {
15205
+ this.os = os57;
15111
15206
  }
15112
15207
  async prepareLaunch() {
15113
15208
  const binary = this.os.findInPath("gemini");
@@ -15398,8 +15493,8 @@ var KimiRuntimeStrategy = class {
15398
15493
  meta = getAgent("kimi");
15399
15494
  mode = "interactive";
15400
15495
  os;
15401
- constructor(os53) {
15402
- this.os = os53;
15496
+ constructor(os57) {
15497
+ this.os = os57;
15403
15498
  }
15404
15499
  async prepareLaunch() {
15405
15500
  const binary = this.os.findInPath("kimi");
@@ -15512,19 +15607,19 @@ var KimiRuntimeStrategy = class {
15512
15607
 
15513
15608
  // src/agents/registry.ts
15514
15609
  var runtimeBuilders = {
15515
- claude: (os53) => new ClaudeRuntimeStrategy(os53),
15516
- codex: (os53) => new CodexRuntimeStrategy(os53),
15517
- coderabbit: (os53) => new CoderabbitRuntimeStrategy(os53),
15518
- cursor: (os53) => new CursorRuntimeStrategy(os53),
15519
- aider: (os53) => new AiderRuntimeStrategy(os53),
15520
- gemini: (os53) => new GeminiRuntimeStrategy(os53),
15521
- kimi: (os53) => new KimiRuntimeStrategy(os53)
15610
+ claude: (os57) => new ClaudeRuntimeStrategy(os57),
15611
+ codex: (os57) => new CodexRuntimeStrategy(os57),
15612
+ coderabbit: (os57) => new CoderabbitRuntimeStrategy(os57),
15613
+ cursor: (os57) => new CursorRuntimeStrategy(os57),
15614
+ aider: (os57) => new AiderRuntimeStrategy(os57),
15615
+ gemini: (os57) => new GeminiRuntimeStrategy(os57),
15616
+ kimi: (os57) => new KimiRuntimeStrategy(os57)
15522
15617
  };
15523
15618
  var deployBuilders = {
15524
15619
  claude: () => new ClaudeDeployStrategy(),
15525
15620
  codex: () => new CodexDeployStrategy()
15526
15621
  };
15527
- function createAgentStrategy(agent, os53 = createOsStrategy()) {
15622
+ function createAgentStrategy(agent, os57 = createOsStrategy()) {
15528
15623
  if (!AGENT_REGISTRY[agent]?.enabled) {
15529
15624
  throw new Error(
15530
15625
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -15534,10 +15629,10 @@ function createAgentStrategy(agent, os53 = createOsStrategy()) {
15534
15629
  if (!build) {
15535
15630
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
15536
15631
  }
15537
- return build(os53);
15632
+ return build(os57);
15538
15633
  }
15539
- function createInteractiveAgentStrategy(agent, os53 = createOsStrategy()) {
15540
- const s = createAgentStrategy(agent, os53);
15634
+ function createInteractiveAgentStrategy(agent, os57 = createOsStrategy()) {
15635
+ const s = createAgentStrategy(agent, os57);
15541
15636
  if (s.mode !== "interactive") {
15542
15637
  throw new Error(
15543
15638
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -16234,26 +16329,26 @@ function restoreCoderabbitOauthBlob(value) {
16234
16329
  (0, import_node_fs5.writeFileSync)(path36.join(dir, file), contents, { mode: 384 });
16235
16330
  }
16236
16331
  async function configureCoderabbit(input, deps = {}) {
16237
- const os53 = deps.os ?? createOsStrategy();
16332
+ const os57 = deps.os ?? createOsStrategy();
16238
16333
  const ensureInstalled = deps.ensureInstalled ?? ensureCoderabbitInstalled;
16239
16334
  const isLoggedIn = deps.isLoggedIn ?? defaultIsLoggedIn;
16240
16335
  const runOAuth = deps.runOAuthLogin ?? runCoderabbitOAuthLogin;
16241
16336
  const snapshot = deps.snapshotDir ?? (() => snapshotCredentialDir());
16242
16337
  const capture2 = deps.captureCredential ?? ((b) => diffCapturedCredential(b));
16243
16338
  const loginWithApiKey = deps.loginWithApiKey ?? defaultLoginWithApiKey;
16244
- const home = os53.homeDir();
16245
- os53.augmentPath(
16246
- os53.id === "win32" ? [
16339
+ const home = os57.homeDir();
16340
+ os57.augmentPath(
16341
+ os57.id === "win32" ? [
16247
16342
  path36.join(home, ".local", "bin"),
16248
16343
  path36.join(process.env.APPDATA ?? path36.join(home, "AppData", "Roaming"), "npm"),
16249
16344
  path36.join(home, "scoop", "shims")
16250
16345
  ] : [path36.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
16251
16346
  );
16252
- const installed2 = os53.findInPath("coderabbit") !== null;
16347
+ const installed2 = os57.findInPath("coderabbit") !== null;
16253
16348
  const base = () => ({
16254
16349
  action: input.action,
16255
16350
  supported: true,
16256
- installed: os53.findInPath("coderabbit") !== null,
16351
+ installed: os57.findInPath("coderabbit") !== null,
16257
16352
  loggedIn: false
16258
16353
  });
16259
16354
  if (input.action === "status") {
@@ -16267,7 +16362,7 @@ async function configureCoderabbit(input, deps = {}) {
16267
16362
  const key = (input.apiKey ?? "").trim();
16268
16363
  if (!key) return { ...res2, error: "No API key provided" };
16269
16364
  if (!res2.installed) {
16270
- const ok = await ensureInstalled(os53);
16365
+ const ok = await ensureInstalled(os57);
16271
16366
  res2.installed = ok;
16272
16367
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
16273
16368
  }
@@ -16291,7 +16386,7 @@ async function configureCoderabbit(input, deps = {}) {
16291
16386
  }
16292
16387
  if (!res2.installed) {
16293
16388
  deps.onEvent?.({ kind: "installing" });
16294
- const ok = await ensureInstalled(os53);
16389
+ const ok = await ensureInstalled(os57);
16295
16390
  res2.installed = ok;
16296
16391
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
16297
16392
  }
@@ -16321,7 +16416,7 @@ async function configureCoderabbit(input, deps = {}) {
16321
16416
  const res2 = base();
16322
16417
  if (!installed2) {
16323
16418
  deps.onEvent?.({ kind: "installing" });
16324
- const ok = await ensureInstalled(os53);
16419
+ const ok = await ensureInstalled(os57);
16325
16420
  res2.installed = ok;
16326
16421
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
16327
16422
  }
@@ -16361,7 +16456,7 @@ async function configureCoderabbit(input, deps = {}) {
16361
16456
  }
16362
16457
  const res = base();
16363
16458
  if (!res.installed) {
16364
- const ok = await ensureInstalled(os53);
16459
+ const ok = await ensureInstalled(os57);
16365
16460
  res.installed = ok;
16366
16461
  if (!ok) return { ...res, error: "CodeRabbit CLI is not installed" };
16367
16462
  }
@@ -16545,9 +16640,9 @@ function defaultRunGh(args2) {
16545
16640
 
16546
16641
  // src/commands/host-agent.ts
16547
16642
  var import_node_child_process24 = require("child_process");
16548
- var os36 = __toESM(require("os"));
16549
- var fs42 = __toESM(require("fs"));
16550
- var path45 = __toESM(require("path"));
16643
+ var os37 = __toESM(require("os"));
16644
+ var fs43 = __toESM(require("fs"));
16645
+ var path46 = __toESM(require("path"));
16551
16646
 
16552
16647
  // src/integrations/manifest.ts
16553
16648
  var import_node_fs7 = __toESM(require("fs"));
@@ -16622,14 +16717,84 @@ function clearIntegrationsManifest() {
16622
16717
  }
16623
16718
  }
16624
16719
 
16720
+ // src/skills/manifest.ts
16721
+ var import_node_fs8 = __toESM(require("fs"));
16722
+ var import_node_os7 = __toESM(require("os"));
16723
+ var import_node_path6 = __toESM(require("path"));
16724
+ function skillsManifestPath() {
16725
+ return import_node_path6.default.join(import_node_os7.default.homedir(), ".codeam", "skills.json");
16726
+ }
16727
+ function readSkillsManifest() {
16728
+ try {
16729
+ const raw = JSON.parse(import_node_fs8.default.readFileSync(skillsManifestPath(), "utf8"));
16730
+ if (!Array.isArray(raw?.skills)) return null;
16731
+ raw.skills = raw.skills.filter(
16732
+ (s) => Boolean(s) && typeof s === "object" && typeof s.id === "string"
16733
+ );
16734
+ return raw;
16735
+ } catch {
16736
+ return null;
16737
+ }
16738
+ }
16739
+ function persistSkillsManifest(m) {
16740
+ try {
16741
+ const file = skillsManifestPath();
16742
+ import_node_fs8.default.mkdirSync(import_node_path6.default.dirname(file), { recursive: true, mode: 448 });
16743
+ const tmp = `${file}.tmp-${process.pid}`;
16744
+ import_node_fs8.default.writeFileSync(tmp, JSON.stringify(m, null, 2), { encoding: "utf8", mode: 384 });
16745
+ import_node_fs8.default.renameSync(tmp, file);
16746
+ restrictToOwner(file);
16747
+ } catch (err) {
16748
+ log.warn(
16749
+ "skills",
16750
+ `failed to persist skills manifest (best-effort): ${err instanceof Error ? err.message : String(err)}`
16751
+ );
16752
+ }
16753
+ }
16754
+ function clearSkillsManifest() {
16755
+ try {
16756
+ import_node_fs8.default.rmSync(skillsManifestPath(), { force: true });
16757
+ } catch {
16758
+ }
16759
+ }
16760
+
16761
+ // src/skills/persist-from-payload.ts
16762
+ function persistOrClearSkillsFromPayload(skills) {
16763
+ if (skills && skills.length > 0) persistSkillsManifest({ skills });
16764
+ else clearSkillsManifest();
16765
+ }
16766
+
16767
+ // src/lib/process-guards.ts
16768
+ var installed = false;
16769
+ function installRelayCrashGuards() {
16770
+ if (installed) return;
16771
+ installed = true;
16772
+ process.on("unhandledRejection", (reason) => {
16773
+ log.error("process", `unhandledRejection \u2014 relay kept alive \u2014 ${describeReason(reason)}`);
16774
+ });
16775
+ process.on("uncaughtException", (err) => {
16776
+ log.error("process", `uncaughtException \u2014 relay kept alive \u2014 ${describeReason(err)}`);
16777
+ });
16778
+ }
16779
+ function describeReason(reason) {
16780
+ if (reason instanceof Error) {
16781
+ return reason.stack ?? `${reason.name}: ${reason.message}`;
16782
+ }
16783
+ try {
16784
+ return typeof reason === "string" ? reason : JSON.stringify(reason);
16785
+ } catch {
16786
+ return String(reason);
16787
+ }
16788
+ }
16789
+
16625
16790
  // src/commands/host/host-client.ts
16626
- var fs34 = __toESM(require("fs"));
16627
- var os30 = __toESM(require("os"));
16628
- var path38 = __toESM(require("path"));
16791
+ var fs35 = __toESM(require("fs"));
16792
+ var os31 = __toESM(require("os"));
16793
+ var path39 = __toESM(require("path"));
16629
16794
  function sampleCpuTimes() {
16630
16795
  let idle = 0;
16631
16796
  let total = 0;
16632
- for (const cpu of os30.cpus()) {
16797
+ for (const cpu of os31.cpus()) {
16633
16798
  const t2 = cpu.times;
16634
16799
  idle += t2.idle;
16635
16800
  total += t2.user + t2.nice + t2.sys + t2.idle + t2.irq;
@@ -16648,8 +16813,8 @@ var MetricsCollector = class {
16648
16813
  const prev = this.prevCpu;
16649
16814
  this.prevCpu = current;
16650
16815
  if (!prev) {
16651
- const cores = os30.cpus().length || 1;
16652
- const proxy = os30.loadavg()[0] / cores * 100;
16816
+ const cores = os31.cpus().length || 1;
16817
+ const proxy = os31.loadavg()[0] / cores * 100;
16653
16818
  return Math.min(100, Math.max(0, Math.round(proxy)));
16654
16819
  }
16655
16820
  const idleDelta = current.idle - prev.idle;
@@ -16662,8 +16827,8 @@ var MetricsCollector = class {
16662
16827
  collect() {
16663
16828
  return {
16664
16829
  cpuPct: this.cpuPct(),
16665
- ramUsedMb: Math.round((os30.totalmem() - os30.freemem()) / 1048576),
16666
- ramTotalMb: Math.round(os30.totalmem() / 1048576),
16830
+ ramUsedMb: Math.round((os31.totalmem() - os31.freemem()) / 1048576),
16831
+ ramTotalMb: Math.round(os31.totalmem() / 1048576),
16667
16832
  latencyMs: this.lastLatencyMs
16668
16833
  };
16669
16834
  }
@@ -16672,19 +16837,19 @@ function apiBase() {
16672
16837
  return process.env.CODEAM_API_URL ?? resolveApiBaseUrl();
16673
16838
  }
16674
16839
  function hostIdentityPath() {
16675
- return path38.join(os30.homedir(), ".codeam", "host-agent.json");
16840
+ return path39.join(os31.homedir(), ".codeam", "host-agent.json");
16676
16841
  }
16677
16842
  function collectOsInfo() {
16678
16843
  return {
16679
- distro: os30.platform(),
16680
- arch: os30.arch(),
16681
- kernel: os30.release(),
16844
+ distro: os31.platform(),
16845
+ arch: os31.arch(),
16846
+ kernel: os31.release(),
16682
16847
  nodeVersion: process.versions.node
16683
16848
  };
16684
16849
  }
16685
16850
  function loadHostIdentity() {
16686
16851
  try {
16687
- const raw = fs34.readFileSync(hostIdentityPath(), "utf8");
16852
+ const raw = fs35.readFileSync(hostIdentityPath(), "utf8");
16688
16853
  const parsed = JSON.parse(raw);
16689
16854
  if (typeof parsed === "object" && parsed !== null && typeof parsed.hostId === "string" && typeof parsed.hostToken === "string" && typeof parsed.controlPluginId === "string") {
16690
16855
  const p2 = parsed;
@@ -16697,8 +16862,8 @@ function loadHostIdentity() {
16697
16862
  }
16698
16863
  function saveHostIdentity(identity) {
16699
16864
  const file = hostIdentityPath();
16700
- fs34.mkdirSync(path38.dirname(file), { recursive: true, mode: 448 });
16701
- fs34.writeFileSync(file, JSON.stringify(identity, null, 2), {
16865
+ fs35.mkdirSync(path39.dirname(file), { recursive: true, mode: 448 });
16866
+ fs35.writeFileSync(file, JSON.stringify(identity, null, 2), {
16702
16867
  encoding: "utf8",
16703
16868
  mode: 384
16704
16869
  });
@@ -16743,7 +16908,7 @@ function isTerminalEnrollError(err) {
16743
16908
  }
16744
16909
  function deleteHostIdentity() {
16745
16910
  try {
16746
- fs34.rmSync(hostIdentityPath(), { force: true });
16911
+ fs35.rmSync(hostIdentityPath(), { force: true });
16747
16912
  } catch {
16748
16913
  }
16749
16914
  }
@@ -16767,7 +16932,7 @@ async function postJson(pathname, body) {
16767
16932
  function resolveHostLabel(label) {
16768
16933
  const explicit = label?.trim();
16769
16934
  const envLabel = process.env.CODEAM_HOST_LABEL?.trim();
16770
- const resolved = explicit || envLabel || os30.hostname();
16935
+ const resolved = explicit || envLabel || os31.hostname();
16771
16936
  return resolved.slice(0, 80);
16772
16937
  }
16773
16938
  async function redeemEnrollToken(token, label) {
@@ -16872,17 +17037,17 @@ async function reportDeployProgress(auth, deployId, step, message, sessionId) {
16872
17037
  }
16873
17038
 
16874
17039
  // src/commands/host/workspace.ts
16875
- var fs35 = __toESM(require("fs"));
16876
- var os31 = __toESM(require("os"));
16877
- var path39 = __toESM(require("path"));
17040
+ var fs36 = __toESM(require("fs"));
17041
+ var os32 = __toESM(require("os"));
17042
+ var path40 = __toESM(require("path"));
16878
17043
  var import_node_child_process18 = require("child_process");
16879
17044
  var import_node_util4 = require("util");
16880
17045
  var execFileP4 = (0, import_node_util4.promisify)(import_node_child_process18.execFile);
16881
17046
  function isAbsolutePathTarget(target) {
16882
- return path39.isAbsolute(target);
17047
+ return path40.isAbsolute(target);
16883
17048
  }
16884
17049
  function selfHostedWorkspaceRoot() {
16885
- return path39.join(os31.homedir(), ".codeam", "self-hosted");
17050
+ return path40.join(os32.homedir(), ".codeam", "self-hosted");
16886
17051
  }
16887
17052
  function nonInteractiveGitEnv() {
16888
17053
  return {
@@ -16935,13 +17100,13 @@ async function fetchGithubIdentity(token) {
16935
17100
  async function configureGitCredentials(dest, repoRef, cloneToken) {
16936
17101
  const gh = githubOwnerRepo(repoRef.trim());
16937
17102
  if (!gh || !cloneToken) return;
16938
- const credFile = path39.join(dest, ".git", "codeam-credentials");
16939
- fs35.writeFileSync(credFile, `https://x-access-token:${cloneToken}@github.com
17103
+ const credFile = path40.join(dest, ".git", "codeam-credentials");
17104
+ fs36.writeFileSync(credFile, `https://x-access-token:${cloneToken}@github.com
16940
17105
  `, { mode: 384 });
16941
17106
  restrictToOwner(credFile);
16942
17107
  const env = nonInteractiveGitEnv();
16943
17108
  const git2 = (args2) => execFileP4("git", ["-C", dest, ...args2], { timeout: 3e4, env });
16944
- const credFilePosix = credFile.split(path39.sep).join("/");
17109
+ const credFilePosix = credFile.split(path40.sep).join("/");
16945
17110
  await git2(["config", "--local", "--replace-all", "credential.helper", ""]).catch(() => {
16946
17111
  });
16947
17112
  await git2([
@@ -16977,17 +17142,17 @@ function maskToken(text, cloneToken) {
16977
17142
  }
16978
17143
  async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
16979
17144
  if (isAbsolutePathTarget(repoOrPath)) {
16980
- if (!fs35.existsSync(repoOrPath)) {
17145
+ if (!fs36.existsSync(repoOrPath)) {
16981
17146
  throw new Error(`deploy target path does not exist: ${repoOrPath}`);
16982
17147
  }
16983
17148
  return repoOrPath;
16984
17149
  }
16985
- const dest = path39.join(selfHostedWorkspaceRoot(), deployId);
16986
- if (fs35.existsSync(path39.join(dest, ".git"))) {
17150
+ const dest = path40.join(selfHostedWorkspaceRoot(), deployId);
17151
+ if (fs36.existsSync(path40.join(dest, ".git"))) {
16987
17152
  if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken);
16988
17153
  return dest;
16989
17154
  }
16990
- fs35.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
17155
+ fs36.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
16991
17156
  const cloneUrl = repoCloneUrl(repoOrPath, cloneToken);
16992
17157
  try {
16993
17158
  await execFileP4("git", ["clone", "--depth", "1", cloneUrl, dest], {
@@ -17004,9 +17169,9 @@ async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
17004
17169
  }
17005
17170
 
17006
17171
  // src/commands/host/agent-provisioning.ts
17007
- var fs36 = __toESM(require("fs"));
17008
- var os32 = __toESM(require("os"));
17009
- var path40 = __toESM(require("path"));
17172
+ var fs37 = __toESM(require("fs"));
17173
+ var os33 = __toESM(require("os"));
17174
+ var path41 = __toESM(require("path"));
17010
17175
  var PUBLIC_TO_INTERNAL_AGENT = {
17011
17176
  claude_code: "claude",
17012
17177
  claude: "claude",
@@ -17022,22 +17187,22 @@ function toInternalAgentId(publicAgentId) {
17022
17187
  return PUBLIC_TO_INTERNAL_AGENT[publicAgentId] ?? null;
17023
17188
  }
17024
17189
  function ensureDir(dir) {
17025
- fs36.mkdirSync(dir, { recursive: true, mode: 448 });
17190
+ fs37.mkdirSync(dir, { recursive: true, mode: 448 });
17026
17191
  }
17027
17192
  function writeFile0600(filePath, contents) {
17028
- ensureDir(path40.dirname(filePath));
17029
- fs36.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
17193
+ ensureDir(path41.dirname(filePath));
17194
+ fs37.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
17030
17195
  restrictToOwner(filePath);
17031
17196
  }
17032
17197
  function rmIfExists(filePath) {
17033
17198
  try {
17034
- fs36.rmSync(filePath, { force: true });
17199
+ fs37.rmSync(filePath, { force: true });
17035
17200
  } catch {
17036
17201
  }
17037
17202
  }
17038
17203
  var claudeProvisioner = {
17039
17204
  write(auth, home) {
17040
- const credentialsJson = path40.join(home, ".claude", ".credentials.json");
17205
+ const credentialsJson = path41.join(home, ".claude", ".credentials.json");
17041
17206
  if (auth.kind === "api_key") {
17042
17207
  rmIfExists(credentialsJson);
17043
17208
  return { ANTHROPIC_API_KEY: auth.value };
@@ -17049,8 +17214,8 @@ var claudeProvisioner = {
17049
17214
  } else {
17050
17215
  rmIfExists(credentialsJson);
17051
17216
  }
17052
- const claudeJson = path40.join(home, ".claude.json");
17053
- if (!fs36.existsSync(claudeJson)) {
17217
+ const claudeJson = path41.join(home, ".claude.json");
17218
+ if (!fs37.existsSync(claudeJson)) {
17054
17219
  writeFile0600(
17055
17220
  claudeJson,
17056
17221
  JSON.stringify({ hasCompletedOnboarding: true, customApiKeyResponses: { approved: [] } })
@@ -17061,7 +17226,7 @@ var claudeProvisioner = {
17061
17226
  };
17062
17227
  var codexProvisioner = {
17063
17228
  write(auth, home) {
17064
- const authJson = path40.join(home, ".codex", "auth.json");
17229
+ const authJson = path41.join(home, ".codex", "auth.json");
17065
17230
  if (auth.kind === "api_key") {
17066
17231
  rmIfExists(authJson);
17067
17232
  return { OPENAI_API_KEY: auth.value };
@@ -17072,8 +17237,8 @@ var codexProvisioner = {
17072
17237
  };
17073
17238
  var geminiProvisioner = {
17074
17239
  write(auth, home) {
17075
- const settingsJson = path40.join(home, ".gemini", "settings.json");
17076
- const oauthCreds = path40.join(home, ".gemini", "oauth_creds.json");
17240
+ const settingsJson = path41.join(home, ".gemini", "settings.json");
17241
+ const oauthCreds = path41.join(home, ".gemini", "oauth_creds.json");
17077
17242
  if (auth.kind === "api_key") {
17078
17243
  rmIfExists(oauthCreds);
17079
17244
  writeFile0600(settingsJson, '{"security":{"auth":{"selectedType":"gemini-api-key"}}}');
@@ -17086,7 +17251,7 @@ var geminiProvisioner = {
17086
17251
  };
17087
17252
  var cursorProvisioner = {
17088
17253
  write(auth, home) {
17089
- const authJson = path40.join(home, ".config", "cursor", "auth.json");
17254
+ const authJson = path41.join(home, ".config", "cursor", "auth.json");
17090
17255
  if (auth.kind === "api_key") {
17091
17256
  rmIfExists(authJson);
17092
17257
  return { CURSOR_API_KEY: auth.value };
@@ -17128,22 +17293,22 @@ max_context_size = 262144
17128
17293
  var kimiProvisioner = {
17129
17294
  write(auth, home) {
17130
17295
  const credentialsFiles = [
17131
- path40.join(home, ".kimi", "credentials", "kimi-code.json"),
17132
- path40.join(home, ".kimi-code", "credentials", "kimi-code.json")
17296
+ path41.join(home, ".kimi", "credentials", "kimi-code.json"),
17297
+ path41.join(home, ".kimi-code", "credentials", "kimi-code.json")
17133
17298
  ];
17134
17299
  if (auth.kind === "api_key") {
17135
17300
  credentialsFiles.forEach(rmIfExists);
17136
17301
  return { KIMI_API_KEY: auth.value };
17137
17302
  }
17138
17303
  credentialsFiles.forEach((f) => writeFile0600(f, auth.value));
17139
- writeFile0600(path40.join(home, ".kimi-code", "config.toml"), KIMI_MANAGED_CONFIG_TOML);
17304
+ writeFile0600(path41.join(home, ".kimi-code", "config.toml"), KIMI_MANAGED_CONFIG_TOML);
17140
17305
  return {};
17141
17306
  }
17142
17307
  };
17143
17308
  var coderabbitProvisioner = {
17144
17309
  write(auth, home) {
17145
- const dir = path40.join(home, ".coderabbit");
17146
- const authJson = path40.join(dir, "auth.json");
17310
+ const dir = path41.join(home, ".coderabbit");
17311
+ const authJson = path41.join(dir, "auth.json");
17147
17312
  if (auth.kind === "api_key") {
17148
17313
  rmIfExists(authJson);
17149
17314
  return { CODERABBIT_API_KEY: auth.value };
@@ -17155,13 +17320,13 @@ var coderabbitProvisioner = {
17155
17320
  try {
17156
17321
  const parsed = JSON.parse(value);
17157
17322
  if (typeof parsed.file === "string" && typeof parsed.contents === "string") {
17158
- file = path40.basename(parsed.file);
17323
+ file = path41.basename(parsed.file);
17159
17324
  contents = parsed.contents;
17160
17325
  }
17161
17326
  } catch {
17162
17327
  }
17163
17328
  }
17164
- writeFile0600(path40.join(dir, file), contents);
17329
+ writeFile0600(path41.join(dir, file), contents);
17165
17330
  return {};
17166
17331
  }
17167
17332
  };
@@ -17181,7 +17346,7 @@ var UnsupportedAgentError = class extends Error {
17181
17346
  this.agentId = agentId;
17182
17347
  }
17183
17348
  };
17184
- function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os32.homedir()) {
17349
+ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os33.homedir()) {
17185
17350
  const internal = toInternalAgentId(publicAgentId);
17186
17351
  if (!internal) throw new UnsupportedAgentError(publicAgentId);
17187
17352
  const provisioner = PROVISIONERS[internal];
@@ -17191,11 +17356,11 @@ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os32.homedir(
17191
17356
 
17192
17357
  // src/commands/host/git-tooling.ts
17193
17358
  var import_node_child_process19 = require("child_process");
17194
- var fs37 = __toESM(require("fs"));
17195
- var os33 = __toESM(require("os"));
17196
- var path41 = __toESM(require("path"));
17359
+ var fs38 = __toESM(require("fs"));
17360
+ var os34 = __toESM(require("os"));
17361
+ var path42 = __toESM(require("path"));
17197
17362
  function codeamBinDir() {
17198
- return process.env.CODEAM_BIN_DIR ?? path41.join(os33.homedir(), ".codeam", "bin");
17363
+ return process.env.CODEAM_BIN_DIR ?? path42.join(os34.homedir(), ".codeam", "bin");
17199
17364
  }
17200
17365
  var FALLBACK_GH_VERSION = "2.62.0";
17201
17366
  var RELEASE_API = "https://api.github.com/repos/cli/cli/releases/latest";
@@ -17227,7 +17392,7 @@ async function download(url2, dest) {
17227
17392
  const res = await fetch(url2, { headers: { "User-Agent": "codeam-cli" } });
17228
17393
  if (!res.ok || !res.body) return false;
17229
17394
  const buf = Buffer.from(await res.arrayBuffer());
17230
- fs37.writeFileSync(dest, buf);
17395
+ fs38.writeFileSync(dest, buf);
17231
17396
  return true;
17232
17397
  } catch {
17233
17398
  return false;
@@ -17250,8 +17415,8 @@ async function ensureGhCli(runner, token, deps = {}) {
17250
17415
  const version3 = await resolveVersionFn(token);
17251
17416
  const asset = `gh_${version3}_${osToken}_${arch2}`;
17252
17417
  const url2 = `https://github.com/cli/cli/releases/download/v${version3}/${asset}.${ext}`;
17253
- const tmpRoot = fs37.mkdtempSync(path41.join(os33.tmpdir(), "codeam-gh-"));
17254
- const archive = path41.join(tmpRoot, `${asset}.${ext}`);
17418
+ const tmpRoot = fs38.mkdtempSync(path42.join(os34.tmpdir(), "codeam-gh-"));
17419
+ const archive = path42.join(tmpRoot, `${asset}.${ext}`);
17255
17420
  if (!await downloadFn(url2, archive)) {
17256
17421
  log.warn("host-agent", "gh download failed \u2014 skipping (git pull/push still work via the credential helper)");
17257
17422
  return null;
@@ -17261,16 +17426,16 @@ async function ensureGhCli(runner, token, deps = {}) {
17261
17426
  log.warn("host-agent", `gh archive extraction failed (code=${String(extract.code)}) \u2014 skipping`);
17262
17427
  return null;
17263
17428
  }
17264
- const extractedBin = path41.join(tmpRoot, asset, "bin", binaryName);
17265
- if (!fs37.existsSync(extractedBin)) {
17429
+ const extractedBin = path42.join(tmpRoot, asset, "bin", binaryName);
17430
+ if (!fs38.existsSync(extractedBin)) {
17266
17431
  log.warn("host-agent", "gh binary not found in the extracted archive \u2014 skipping");
17267
17432
  return null;
17268
17433
  }
17269
17434
  const binDir = codeamBinDir();
17270
- fs37.mkdirSync(binDir, { recursive: true });
17271
- const target = path41.join(binDir, binaryName);
17272
- fs37.copyFileSync(extractedBin, target);
17273
- fs37.chmodSync(target, 493);
17435
+ fs38.mkdirSync(binDir, { recursive: true });
17436
+ const target = path42.join(binDir, binaryName);
17437
+ fs38.copyFileSync(extractedBin, target);
17438
+ fs38.chmodSync(target, 493);
17274
17439
  log.info("host-agent", `gh installed to ${target} (v${version3})`);
17275
17440
  return target;
17276
17441
  } catch (e) {
@@ -17757,23 +17922,23 @@ async function ensureModernPython(runner) {
17757
17922
  }
17758
17923
 
17759
17924
  // src/commands/host/headroom-bootstrap.ts
17760
- var fs39 = __toESM(require("fs"));
17761
- var path43 = __toESM(require("path"));
17925
+ var fs40 = __toESM(require("fs"));
17926
+ var path44 = __toESM(require("path"));
17762
17927
 
17763
17928
  // src/commands/host/headroom-config.ts
17764
- var fs38 = __toESM(require("fs"));
17765
- var os34 = __toESM(require("os"));
17766
- var path42 = __toESM(require("path"));
17929
+ var fs39 = __toESM(require("fs"));
17930
+ var os35 = __toESM(require("os"));
17931
+ var path43 = __toESM(require("path"));
17767
17932
  function headroomConfigPath() {
17768
- return path42.join(os34.homedir(), ".codeam", "headroom-config.json");
17933
+ return path43.join(os35.homedir(), ".codeam", "headroom-config.json");
17769
17934
  }
17770
17935
  function persistHeadroomConfig(config) {
17771
17936
  try {
17772
17937
  const file = headroomConfigPath();
17773
- fs38.mkdirSync(path42.dirname(file), { recursive: true, mode: 448 });
17938
+ fs39.mkdirSync(path43.dirname(file), { recursive: true, mode: 448 });
17774
17939
  const tmp = `${file}.tmp-${process.pid}`;
17775
- fs38.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
17776
- fs38.renameSync(tmp, file);
17940
+ fs39.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
17941
+ fs39.renameSync(tmp, file);
17777
17942
  restrictToOwner(file);
17778
17943
  } catch (err) {
17779
17944
  log.warn(
@@ -17783,21 +17948,21 @@ function persistHeadroomConfig(config) {
17783
17948
  }
17784
17949
  }
17785
17950
  function agentSettingsPath(kind) {
17786
- const home = os34.homedir();
17787
- if (kind === "claude") return path42.join(home, ".claude", "settings.json");
17788
- if (kind === "codex") return path42.join(home, ".codex", "auth.json");
17789
- if (kind === "copilot") return path42.join(home, ".config", "github-copilot", "hosts.json");
17951
+ const home = os35.homedir();
17952
+ if (kind === "claude") return path43.join(home, ".claude", "settings.json");
17953
+ if (kind === "codex") return path43.join(home, ".codex", "auth.json");
17954
+ if (kind === "copilot") return path43.join(home, ".config", "github-copilot", "hosts.json");
17790
17955
  return null;
17791
17956
  }
17792
17957
  function backupAgentHeadroomConfig(kind) {
17793
17958
  const src = agentSettingsPath(kind);
17794
17959
  if (!src) return;
17795
17960
  try {
17796
- if (!fs38.existsSync(src)) return;
17797
- const dest = path42.join(os34.homedir(), ".codeam", `headroom-backup-${kind}.json`);
17798
- fs38.mkdirSync(path42.dirname(dest), { recursive: true, mode: 448 });
17799
- fs38.copyFileSync(src, dest);
17800
- fs38.chmodSync(dest, 384);
17961
+ if (!fs39.existsSync(src)) return;
17962
+ const dest = path43.join(os35.homedir(), ".codeam", `headroom-backup-${kind}.json`);
17963
+ fs39.mkdirSync(path43.dirname(dest), { recursive: true, mode: 448 });
17964
+ fs39.copyFileSync(src, dest);
17965
+ fs39.chmodSync(dest, 384);
17801
17966
  log.info("host-agent", `headroom config backup: ${src} \u2192 ${dest}`);
17802
17967
  } catch (err) {
17803
17968
  log.warn(
@@ -17809,12 +17974,12 @@ function backupAgentHeadroomConfig(kind) {
17809
17974
  function restoreAgentHeadroomConfig(kind) {
17810
17975
  const dest = agentSettingsPath(kind);
17811
17976
  if (!dest) return false;
17812
- const src = path42.join(os34.homedir(), ".codeam", `headroom-backup-${kind}.json`);
17813
- if (!fs38.existsSync(src)) return false;
17977
+ const src = path43.join(os35.homedir(), ".codeam", `headroom-backup-${kind}.json`);
17978
+ if (!fs39.existsSync(src)) return false;
17814
17979
  try {
17815
- fs38.mkdirSync(path42.dirname(dest), { recursive: true, mode: 448 });
17816
- fs38.copyFileSync(src, dest);
17817
- fs38.chmodSync(dest, 384);
17980
+ fs39.mkdirSync(path43.dirname(dest), { recursive: true, mode: 448 });
17981
+ fs39.copyFileSync(src, dest);
17982
+ fs39.chmodSync(dest, 384);
17818
17983
  log.info("host-agent", `headroom config restored: ${src} \u2192 ${dest}`);
17819
17984
  return true;
17820
17985
  } catch (err) {
@@ -17827,7 +17992,7 @@ function restoreAgentHeadroomConfig(kind) {
17827
17992
  }
17828
17993
  function readHeadroomChildEnv() {
17829
17994
  try {
17830
- const raw = fs38.readFileSync(headroomConfigPath(), "utf8");
17995
+ const raw = fs39.readFileSync(headroomConfigPath(), "utf8");
17831
17996
  const parsed = JSON.parse(raw);
17832
17997
  if (typeof parsed !== "object" || parsed === null) return {};
17833
17998
  const o = parsed;
@@ -17863,37 +18028,37 @@ function bundledClaudeBinDir() {
17863
18028
  const roots = /* @__PURE__ */ new Set();
17864
18029
  let dir = __dirname;
17865
18030
  for (let i = 0; i < 6; i++) {
17866
- roots.add(path43.join(dir, "node_modules"));
17867
- const parent = path43.dirname(dir);
18031
+ roots.add(path44.join(dir, "node_modules"));
18032
+ const parent = path44.dirname(dir);
17868
18033
  if (parent === dir) break;
17869
18034
  dir = parent;
17870
18035
  }
17871
18036
  try {
17872
18037
  const main2 = require.resolve("@anthropic-ai/claude-agent-sdk");
17873
- const marker = `${path43.sep}@anthropic-ai${path43.sep}`;
18038
+ const marker = `${path44.sep}@anthropic-ai${path44.sep}`;
17874
18039
  const idx = main2.lastIndexOf(marker);
17875
18040
  if (idx !== -1) roots.add(main2.slice(0, idx));
17876
18041
  } catch {
17877
18042
  }
17878
18043
  for (const nm of roots) {
17879
- const atAnthropic = path43.join(nm, "@anthropic-ai");
18044
+ const atAnthropic = path44.join(nm, "@anthropic-ai");
17880
18045
  let entries;
17881
18046
  try {
17882
- entries = fs39.readdirSync(atAnthropic);
18047
+ entries = fs40.readdirSync(atAnthropic);
17883
18048
  } catch {
17884
18049
  continue;
17885
18050
  }
17886
18051
  for (const entry of entries) {
17887
18052
  if (!entry.startsWith("claude-agent-sdk-")) continue;
17888
- const bin = path43.join(atAnthropic, entry, "claude");
17889
- if (fs39.existsSync(bin)) return path43.dirname(bin);
18053
+ const bin = path44.join(atAnthropic, entry, "claude");
18054
+ if (fs40.existsSync(bin)) return path44.dirname(bin);
17890
18055
  }
17891
18056
  }
17892
18057
  return null;
17893
18058
  }
17894
18059
  async function getFreeDiskBytes(dir) {
17895
18060
  try {
17896
- const s = await fs39.promises.statfs(dir);
18061
+ const s = await fs40.promises.statfs(dir);
17897
18062
  return s.bsize * s.bavail;
17898
18063
  } catch {
17899
18064
  return null;
@@ -17955,7 +18120,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
17955
18120
  if (initKind === "claude") {
17956
18121
  const claudeDir = bundledClaudeBinDir();
17957
18122
  if (claudeDir) {
17958
- initEnv.PATH = `${claudeDir}${path43.delimiter}${process.env["PATH"] ?? ""}`;
18123
+ initEnv.PATH = `${claudeDir}${path44.delimiter}${process.env["PATH"] ?? ""}`;
17959
18124
  log.info("host-agent", `headroom init: bundled claude on PATH (${claudeDir})`);
17960
18125
  } else {
17961
18126
  log.warn("host-agent", "headroom init: bundled claude binary not found \u2014 init may fail");
@@ -17990,9 +18155,9 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
17990
18155
  var import_node_child_process22 = require("child_process");
17991
18156
 
17992
18157
  // src/lib/updateNotifier.ts
17993
- var fs40 = __toESM(require("fs"));
17994
- var os35 = __toESM(require("os"));
17995
- var path44 = __toESM(require("path"));
18158
+ var fs41 = __toESM(require("fs"));
18159
+ var os36 = __toESM(require("os"));
18160
+ var path45 = __toESM(require("path"));
17996
18161
  var https6 = __toESM(require("https"));
17997
18162
  var import_node_child_process21 = require("child_process");
17998
18163
  var import_picocolors3 = __toESM(require("picocolors"));
@@ -18001,12 +18166,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
18001
18166
  var TTL_MS = 24 * 60 * 60 * 1e3;
18002
18167
  var REQUEST_TIMEOUT_MS = 1500;
18003
18168
  function cachePath() {
18004
- const dir = path44.join(os35.homedir(), ".codeam");
18005
- return path44.join(dir, "update-check.json");
18169
+ const dir = path45.join(os36.homedir(), ".codeam");
18170
+ return path45.join(dir, "update-check.json");
18006
18171
  }
18007
18172
  function readCache() {
18008
18173
  try {
18009
- const raw = fs40.readFileSync(cachePath(), "utf8");
18174
+ const raw = fs41.readFileSync(cachePath(), "utf8");
18010
18175
  const parsed = JSON.parse(raw);
18011
18176
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
18012
18177
  return parsed;
@@ -18017,10 +18182,10 @@ function readCache() {
18017
18182
  function writeCache(cache) {
18018
18183
  try {
18019
18184
  const file = cachePath();
18020
- fs40.mkdirSync(path44.dirname(file), { recursive: true });
18185
+ fs41.mkdirSync(path45.dirname(file), { recursive: true });
18021
18186
  const tmp = `${file}.${process.pid}.tmp`;
18022
- fs40.writeFileSync(tmp, JSON.stringify(cache));
18023
- fs40.renameSync(tmp, file);
18187
+ fs41.writeFileSync(tmp, JSON.stringify(cache));
18188
+ fs41.renameSync(tmp, file);
18024
18189
  } catch {
18025
18190
  }
18026
18191
  }
@@ -18094,8 +18259,8 @@ function isLinkedInstall() {
18094
18259
  timeout: 2e3
18095
18260
  }).trim();
18096
18261
  if (!root) return false;
18097
- const pkgPath = path44.join(root, PKG_NAME);
18098
- return fs40.lstatSync(pkgPath).isSymbolicLink();
18262
+ const pkgPath = path45.join(root, PKG_NAME);
18263
+ return fs41.lstatSync(pkgPath).isSymbolicLink();
18099
18264
  } catch {
18100
18265
  return false;
18101
18266
  }
@@ -18131,7 +18296,7 @@ function maybeAutoUpdate(currentVersion, latest) {
18131
18296
  return;
18132
18297
  }
18133
18298
  try {
18134
- fs40.unlinkSync(cachePath());
18299
+ fs41.unlinkSync(cachePath());
18135
18300
  } catch {
18136
18301
  }
18137
18302
  process.stderr.write(` ${import_picocolors3.default.green("\u2713")} Updated. Resuming session...
@@ -18147,7 +18312,7 @@ async function autoUpgradeBeforeCriticalCommand() {
18147
18312
  if (process.env.NODE_ENV === "test") return;
18148
18313
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
18149
18314
  if (process.env.CI) return;
18150
- const current = true ? "2.61.22" : null;
18315
+ const current = true ? "2.61.24" : null;
18151
18316
  if (!current) return;
18152
18317
  const cache = readCache();
18153
18318
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -18164,7 +18329,7 @@ function checkForUpdates() {
18164
18329
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
18165
18330
  if (process.env.CI) return;
18166
18331
  if (!process.stdout.isTTY) return;
18167
- const current = true ? "2.61.22" : null;
18332
+ const current = true ? "2.61.24" : null;
18168
18333
  if (!current) return;
18169
18334
  const cache = readCache();
18170
18335
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -18184,7 +18349,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
18184
18349
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
18185
18350
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
18186
18351
  function currentCliVersion() {
18187
- return true ? "2.61.22" : null;
18352
+ return true ? "2.61.24" : null;
18188
18353
  }
18189
18354
  function runCmd(cmd, args2, timeoutMs) {
18190
18355
  return new Promise((resolve8) => {
@@ -18251,7 +18416,7 @@ async function runSelfUpdate() {
18251
18416
 
18252
18417
  // src/commands/host/teardown.ts
18253
18418
  var import_node_child_process23 = require("child_process");
18254
- var fs41 = __toESM(require("fs"));
18419
+ var fs42 = __toESM(require("fs"));
18255
18420
  var defaultDisableService = () => {
18256
18421
  try {
18257
18422
  (0, import_node_child_process23.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
@@ -18260,7 +18425,7 @@ var defaultDisableService = () => {
18260
18425
  };
18261
18426
  var defaultTeardownHeadroom = () => {
18262
18427
  try {
18263
- const kind = JSON.parse(fs41.readFileSync(headroomConfigPath(), "utf8")).agent;
18428
+ const kind = JSON.parse(fs42.readFileSync(headroomConfigPath(), "utf8")).agent;
18264
18429
  if (kind) {
18265
18430
  (0, import_node_child_process23.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
18266
18431
  }
@@ -18328,8 +18493,8 @@ function maybeResumeLocalHeadroomReporter(ctx) {
18328
18493
  if (process.env["HEADROOM_ENABLED"] === "1") return null;
18329
18494
  try {
18330
18495
  const file = headroomConfigPath();
18331
- if (!fs42.existsSync(file)) return null;
18332
- const cfg = JSON.parse(fs42.readFileSync(file, "utf8"));
18496
+ if (!fs43.existsSync(file)) return null;
18497
+ const cfg = JSON.parse(fs43.readFileSync(file, "utf8"));
18333
18498
  if (!cfg?.enabled) return null;
18334
18499
  const agent = cfg.agent ?? "claude";
18335
18500
  const ingestUrl = `${resolveApiBaseUrl()}/api/sessions/${ctx.sessionId}/headroom-savings`;
@@ -18511,8 +18676,12 @@ var defaultResumeSpawner = (env, cwd) => (0, import_node_child_process24.spawn)(
18511
18676
  detached: false
18512
18677
  });
18513
18678
  var defaultOnIdentityRejected = () => {
18679
+ defaultDisableService();
18514
18680
  deleteHostIdentity();
18515
- log.warn("host-agent", "host identity rejected by backend \u2014 wiped sealed identity, exiting");
18681
+ log.warn(
18682
+ "host-agent",
18683
+ "host identity rejected by backend \u2014 disabled service + wiped sealed identity, exiting"
18684
+ );
18516
18685
  process.exit(1);
18517
18686
  };
18518
18687
  var defaultOnUpdated = (version3) => {
@@ -18830,13 +18999,13 @@ var HostAgentSupervisor = class {
18830
18999
  const relay = this.relay;
18831
19000
  if (!relay) return;
18832
19001
  const raw = cmd.payload?.path;
18833
- const target = typeof raw === "string" && raw.trim() ? path45.resolve(raw.trim()) : os36.homedir();
19002
+ const target = typeof raw === "string" && raw.trim() ? path46.resolve(raw.trim()) : os37.homedir();
18834
19003
  try {
18835
- const dirents = await fs42.promises.readdir(target, { withFileTypes: true });
19004
+ const dirents = await fs43.promises.readdir(target, { withFileTypes: true });
18836
19005
  const entries = dirents.filter((d3) => !d3.name.startsWith(".")).map((d3) => ({ name: d3.name, isDir: d3.isDirectory() })).sort(
18837
19006
  (a, b) => a.isDir === b.isDir ? a.name.localeCompare(b.name) : a.isDir ? -1 : 1
18838
19007
  );
18839
- const parent = path45.dirname(target);
19008
+ const parent = path46.dirname(target);
18840
19009
  await relay.sendResult(cmd.id, "completed", {
18841
19010
  path: target,
18842
19011
  // null at the filesystem root so the UI can hide the ".." affordance.
@@ -18931,10 +19100,13 @@ var HostAgentSupervisor = class {
18931
19100
  "CODEAM_HOST_LABEL=CodeAgent Box",
18932
19101
  // The enroll token above is a SINGLE-USE bootstrap, but it lives in the
18933
19102
  // container's fixed env — it can't be stripped after first boot like the
18934
- // self-hosted systemd unit does. This flag tells `resolveHostIdentity`
18935
- // that on a restart (docker restart / reboot / fleet_start_box wake) an
18936
- // expired-token redeem is EXPECTED: resume from the sealed identity
18937
- // instead of dying with "token expired". Not a secret → plain KEY=value.
19103
+ // self-hosted systemd unit does, so on every restart (docker restart /
19104
+ // reboot / fleet_start_box wake) the redeem terminally expires.
19105
+ // `resolveHostIdentity` now resumes from a sealed identity on ANY
19106
+ // terminal enroll-token rejection (not just ephemeral boxes see its
19107
+ // doc comment), so this flag is no longer load-bearing for that
19108
+ // decision; kept set for observability/back-compat with older CLI
19109
+ // builds that still gate on it. Not a secret → plain KEY=value.
18938
19110
  "-e",
18939
19111
  "CODEAM_ENROLL_EPHEMERAL=1",
18940
19112
  image
@@ -19049,9 +19221,9 @@ var HostAgentSupervisor = class {
19049
19221
  API_TIMEOUT_MS: "3000000",
19050
19222
  CODEAM_AUTO_TOKEN: payload.autoPairToken
19051
19223
  };
19052
- const houseConfigDir = path45.join(os36.homedir(), ".codeam", "house-claude");
19224
+ const houseConfigDir = path46.join(os37.homedir(), ".codeam", "house-claude");
19053
19225
  try {
19054
- fs42.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
19226
+ fs43.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
19055
19227
  } catch {
19056
19228
  }
19057
19229
  childEnv.CLAUDE_CONFIG_DIR = houseConfigDir;
@@ -19069,14 +19241,14 @@ var HostAgentSupervisor = class {
19069
19241
  report("installing", "installing agent CLI");
19070
19242
  await this.runAgentInstall(payload.agentInstallScript);
19071
19243
  }
19072
- const home = process.env.HOME || os36.homedir();
19244
+ const home = process.env.HOME || os37.homedir();
19073
19245
  childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
19074
19246
  if (payload.cloneToken) {
19075
19247
  try {
19076
19248
  report("preparing", "configuring git tooling");
19077
19249
  const ghCmd = await ensureGhCli(defaultGitToolingRunner, payload.cloneToken);
19078
19250
  if (ghCmd) {
19079
- childEnv.PATH = `${codeamBinDir()}${path45.delimiter}${childEnv.PATH}`;
19251
+ childEnv.PATH = `${codeamBinDir()}${path46.delimiter}${childEnv.PATH}`;
19080
19252
  await ensureGhAuth(defaultGitToolingRunner, ghCmd, payload.cloneToken);
19081
19253
  }
19082
19254
  } catch (e) {
@@ -19092,7 +19264,7 @@ var HostAgentSupervisor = class {
19092
19264
  }
19093
19265
  if (payload.headroomEnabled && payload.headroomAgent && payload.headroomSavingsIngestUrl && isHeadroomSupportedAgent(payload.headroomAgent)) {
19094
19266
  report("headroom", "setting up Headroom proxy");
19095
- const freeBytes = await this.getFreeDisk(os36.homedir());
19267
+ const freeBytes = await this.getFreeDisk(os37.homedir());
19096
19268
  const alreadyInstalled = this.isHeadroomInstalled();
19097
19269
  if (!alreadyInstalled && freeBytes !== null && freeBytes < HEADROOM_MIN_FREE_DISK_BYTES) {
19098
19270
  const freeGb = (freeBytes / 1e9).toFixed(1);
@@ -19146,6 +19318,9 @@ var HostAgentSupervisor = class {
19146
19318
  } else {
19147
19319
  clearIntegrationsManifest();
19148
19320
  }
19321
+ persistOrClearSkillsFromPayload(
19322
+ payload.skills
19323
+ );
19149
19324
  report("spawning", "starting agent");
19150
19325
  const proc = this.spawnSessionChild(childEnv, cwd, extraArgs);
19151
19326
  const child = {
@@ -19273,7 +19448,7 @@ var HostAgentSupervisor = class {
19273
19448
  */
19274
19449
  runAgentInstall(script) {
19275
19450
  return new Promise((resolve8) => {
19276
- const home = process.env.HOME || os36.homedir();
19451
+ const home = process.env.HOME || os37.homedir();
19277
19452
  const child = (0, import_node_child_process24.spawn)("sh", ["-c", script], {
19278
19453
  env: { ...process.env, HOME: home },
19279
19454
  stdio: ["ignore", "pipe", "pipe"]
@@ -19378,10 +19553,10 @@ async function resolveHostIdentity(enrollToken) {
19378
19553
  return identity;
19379
19554
  } catch (err) {
19380
19555
  if (isTerminalEnrollError(err)) {
19381
- if (existing && process.env.CODEAM_ENROLL_EPHEMERAL === "1") {
19556
+ if (existing) {
19382
19557
  log.info(
19383
19558
  "host-agent",
19384
- "ephemeral enroll token expired on restart; resuming from sealed identity"
19559
+ "enroll token terminally rejected (expired/replayed) but a sealed identity is present; resuming from it \u2014 likely a restart, not a re-enroll"
19385
19560
  );
19386
19561
  return existing;
19387
19562
  }
@@ -19405,6 +19580,7 @@ async function resolveHostIdentity(enrollToken) {
19405
19580
  return null;
19406
19581
  }
19407
19582
  async function hostAgent(args2 = []) {
19583
+ installRelayCrashGuards();
19408
19584
  const tokenArg = args2.find((a) => a.startsWith("--token="));
19409
19585
  const enrollToken = (tokenArg ? tokenArg.slice("--token=".length).trim() : "") || process.env.CODEAM_ENROLL_TOKEN || void 0;
19410
19586
  const identity = await resolveHostIdentity(enrollToken);
@@ -19464,9 +19640,9 @@ async function configureHeadroom(action, ctx, deps) {
19464
19640
  }
19465
19641
 
19466
19642
  // src/services/headroom/budget-relaunch.ts
19467
- var fs43 = __toESM(require("fs"));
19468
- var os37 = __toESM(require("os"));
19469
- var path46 = __toESM(require("path"));
19643
+ var fs44 = __toESM(require("fs"));
19644
+ var os38 = __toESM(require("os"));
19645
+ var path47 = __toESM(require("path"));
19470
19646
  var import_child_process13 = require("child_process");
19471
19647
  function amendDeploymentManifestBudget(manifest, budget) {
19472
19648
  const rawArgs = manifest.proxy_args ?? [];
@@ -19500,7 +19676,7 @@ function amendDeploymentManifestBudget(manifest, budget) {
19500
19676
  return { ...manifest, proxy_args: newArgs, base_env: newEnv };
19501
19677
  }
19502
19678
  function findHeadroomDeployments(homeDir2, deps) {
19503
- const deployDir = path46.join(homeDir2, ".headroom", "deploy");
19679
+ const deployDir = path47.join(homeDir2, ".headroom", "deploy");
19504
19680
  let profiles;
19505
19681
  try {
19506
19682
  profiles = deps.readDir(deployDir);
@@ -19509,7 +19685,7 @@ function findHeadroomDeployments(homeDir2, deps) {
19509
19685
  }
19510
19686
  const results = [];
19511
19687
  for (const profile of profiles) {
19512
- const manifestPath = path46.join(deployDir, profile, "manifest.json");
19688
+ const manifestPath = path47.join(deployDir, profile, "manifest.json");
19513
19689
  let raw;
19514
19690
  try {
19515
19691
  raw = deps.readJson(manifestPath);
@@ -19541,8 +19717,8 @@ async function applyBudgetToHeadroom(budget, deps) {
19541
19717
  }
19542
19718
  function writeManifestReal(manifestPath, manifest) {
19543
19719
  const tmp = manifestPath + ".codeam.tmp";
19544
- fs43.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
19545
- fs43.renameSync(tmp, manifestPath);
19720
+ fs44.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
19721
+ fs44.renameSync(tmp, manifestPath);
19546
19722
  }
19547
19723
  function restartDeploymentReal(profile) {
19548
19724
  try {
@@ -19572,11 +19748,11 @@ function spawnProxyReal2(_budget) {
19572
19748
  });
19573
19749
  }
19574
19750
  function makeRealApplyBudgetDeps() {
19575
- const homeDir2 = os37.homedir();
19751
+ const homeDir2 = os38.homedir();
19576
19752
  return {
19577
19753
  findDeployments: () => findHeadroomDeployments(homeDir2, {
19578
- readDir: (dir) => fs43.readdirSync(dir),
19579
- readJson: (filePath) => JSON.parse(fs43.readFileSync(filePath, "utf8"))
19754
+ readDir: (dir) => fs44.readdirSync(dir),
19755
+ readJson: (filePath) => JSON.parse(fs44.readFileSync(filePath, "utf8"))
19580
19756
  }),
19581
19757
  writeManifest: writeManifestReal,
19582
19758
  restartDeployment: restartDeploymentReal,
@@ -19586,16 +19762,16 @@ function makeRealApplyBudgetDeps() {
19586
19762
  }
19587
19763
 
19588
19764
  // src/services/preview/port-registry.ts
19589
- var fs44 = __toESM(require("fs"));
19590
- var os38 = __toESM(require("os"));
19591
- var path47 = __toESM(require("path"));
19765
+ var fs45 = __toESM(require("fs"));
19766
+ var os39 = __toESM(require("os"));
19767
+ var path48 = __toESM(require("path"));
19592
19768
  var import_child_process14 = require("child_process");
19593
19769
  function registryPath() {
19594
- return path47.join(os38.homedir(), ".codeam", "preview-ports.json");
19770
+ return path48.join(os39.homedir(), ".codeam", "preview-ports.json");
19595
19771
  }
19596
19772
  function readRegistry() {
19597
19773
  try {
19598
- const raw = fs44.readFileSync(registryPath(), "utf8");
19774
+ const raw = fs45.readFileSync(registryPath(), "utf8");
19599
19775
  const parsed = JSON.parse(raw);
19600
19776
  if (parsed && typeof parsed === "object") return parsed;
19601
19777
  } catch {
@@ -19605,10 +19781,10 @@ function readRegistry() {
19605
19781
  function writeRegistry(reg) {
19606
19782
  try {
19607
19783
  const file = registryPath();
19608
- fs44.mkdirSync(path47.dirname(file), { recursive: true });
19784
+ fs45.mkdirSync(path48.dirname(file), { recursive: true });
19609
19785
  const tmp = `${file}.tmp`;
19610
- fs44.writeFileSync(tmp, JSON.stringify(reg), "utf8");
19611
- fs44.renameSync(tmp, file);
19786
+ fs45.writeFileSync(tmp, JSON.stringify(reg), "utf8");
19787
+ fs45.renameSync(tmp, file);
19612
19788
  } catch (err) {
19613
19789
  log.warn("preview", `port-registry write failed: ${err instanceof Error ? err.message : String(err)}`);
19614
19790
  }
@@ -20344,8 +20520,8 @@ function activePreviewSessionIds() {
20344
20520
 
20345
20521
  // src/services/preview/start-orchestrator.ts
20346
20522
  var import_child_process18 = require("child_process");
20347
- var fs49 = __toESM(require("fs"));
20348
- var path52 = __toESM(require("path"));
20523
+ var fs50 = __toESM(require("fs"));
20524
+ var path53 = __toESM(require("path"));
20349
20525
  var import_which2 = __toESM(require("which"));
20350
20526
  var INSTALL_TIMEOUT_MS = 5 * 6e4;
20351
20527
  var SETUP_TIMEOUT_MS = 2 * 6e4;
@@ -20412,8 +20588,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
20412
20588
  if (args2.length === 0) return detection;
20413
20589
  const binName = args2[0];
20414
20590
  if (binName.startsWith("-")) return detection;
20415
- const binPath = path52.join(cwd, "node_modules", ".bin", binName);
20416
- if (!fs49.existsSync(binPath)) return detection;
20591
+ const binPath = path53.join(cwd, "node_modules", ".bin", binName);
20592
+ if (!fs50.existsSync(binPath)) return detection;
20417
20593
  return {
20418
20594
  ...detection,
20419
20595
  command: binPath,
@@ -20777,9 +20953,9 @@ async function establishTunnel(ctx, dev) {
20777
20953
 
20778
20954
  // src/beads/bd-adapter.ts
20779
20955
  var import_child_process19 = require("child_process");
20780
- var fs50 = __toESM(require("fs"));
20781
- var os40 = __toESM(require("os"));
20782
- var path53 = __toESM(require("path"));
20956
+ var fs51 = __toESM(require("fs"));
20957
+ var os41 = __toESM(require("os"));
20958
+ var path54 = __toESM(require("path"));
20783
20959
  var BD_PACKAGE = "@beads/bd";
20784
20960
  function resolveBundledBdBinary() {
20785
20961
  return _resolveSeam.resolveBundled();
@@ -20791,11 +20967,11 @@ function _defaultResolveBundled() {
20791
20967
  } catch {
20792
20968
  return null;
20793
20969
  }
20794
- const binDir = path53.join(path53.dirname(pkgJsonPath), "bin");
20970
+ const binDir = path54.join(path54.dirname(pkgJsonPath), "bin");
20795
20971
  const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
20796
- const binaryPath = path53.join(binDir, binaryName);
20972
+ const binaryPath = path54.join(binDir, binaryName);
20797
20973
  try {
20798
- fs50.accessSync(binaryPath, fs50.constants.F_OK);
20974
+ fs51.accessSync(binaryPath, fs51.constants.F_OK);
20799
20975
  return binaryPath;
20800
20976
  } catch {
20801
20977
  return null;
@@ -20805,13 +20981,13 @@ function resolveBdOnPath() {
20805
20981
  return _resolveSeam.resolveOnPath();
20806
20982
  }
20807
20983
  function _defaultResolveOnPath() {
20808
- const dirs = (process.env.PATH ?? "").split(path53.delimiter).filter(Boolean);
20984
+ const dirs = (process.env.PATH ?? "").split(path54.delimiter).filter(Boolean);
20809
20985
  const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
20810
20986
  for (const dir of dirs) {
20811
20987
  for (const candidate of candidates) {
20812
- const full = path53.join(dir, candidate);
20988
+ const full = path54.join(dir, candidate);
20813
20989
  try {
20814
- fs50.accessSync(full, fs50.constants.F_OK);
20990
+ fs51.accessSync(full, fs51.constants.F_OK);
20815
20991
  return full;
20816
20992
  } catch {
20817
20993
  }
@@ -20896,7 +21072,7 @@ var BdAdapter = class {
20896
21072
  const env = { ...process.env };
20897
21073
  if (!env.HOME) {
20898
21074
  try {
20899
- const home = os40.homedir();
21075
+ const home = os41.homedir();
20900
21076
  if (home) env.HOME = home;
20901
21077
  } catch {
20902
21078
  }
@@ -20988,9 +21164,9 @@ function coerceIssue(row, projectKey) {
20988
21164
 
20989
21165
  // src/beads/provisioner.ts
20990
21166
  var import_child_process23 = require("child_process");
20991
- var fs53 = __toESM(require("fs"));
20992
- var os42 = __toESM(require("os"));
20993
- var path56 = __toESM(require("path"));
21167
+ var fs54 = __toESM(require("fs"));
21168
+ var os43 = __toESM(require("os"));
21169
+ var path57 = __toESM(require("path"));
20994
21170
 
20995
21171
  // src/beads/install-bd.ts
20996
21172
  var import_child_process20 = require("child_process");
@@ -21055,9 +21231,9 @@ async function installBd(platform3 = process.platform) {
21055
21231
 
21056
21232
  // src/beads/install-dolt.ts
21057
21233
  var import_child_process21 = require("child_process");
21058
- var fs51 = __toESM(require("fs"));
21059
- var os41 = __toESM(require("os"));
21060
- var path54 = __toESM(require("path"));
21234
+ var fs52 = __toESM(require("fs"));
21235
+ var os42 = __toESM(require("os"));
21236
+ var path55 = __toESM(require("path"));
21061
21237
  var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
21062
21238
  var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
21063
21239
  function resolveDoltInstallStrategy(platform3) {
@@ -21097,11 +21273,11 @@ function resolveDoltInstallStrategy(platform3) {
21097
21273
  }
21098
21274
  var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
21099
21275
  function doltPlatformTuple(platform3, arch2) {
21100
- const os53 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
21276
+ const os57 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
21101
21277
  const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
21102
21278
  if (!a) return null;
21103
- if (os53 === "windows" && a !== "amd64") return null;
21104
- return `${os53}-${a}`;
21279
+ if (os57 === "windows" && a !== "amd64") return null;
21280
+ return `${os57}-${a}`;
21105
21281
  }
21106
21282
  function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
21107
21283
  const tuple = doltPlatformTuple(platform3, arch2);
@@ -21146,14 +21322,14 @@ async function installDoltToDir(targetDir, platform3 = process.platform, arch2 =
21146
21322
  return result;
21147
21323
  }
21148
21324
  var _doltPathSeam = {
21149
- homedir: () => os41.homedir(),
21325
+ homedir: () => os42.homedir(),
21150
21326
  getPath: () => process.env.PATH ?? "",
21151
21327
  setPath: (p2) => {
21152
21328
  process.env.PATH = p2;
21153
21329
  },
21154
21330
  exists: (p2) => {
21155
21331
  try {
21156
- fs51.accessSync(p2, fs51.constants.F_OK);
21332
+ fs52.accessSync(p2, fs52.constants.F_OK);
21157
21333
  return true;
21158
21334
  } catch {
21159
21335
  return false;
@@ -21164,7 +21340,7 @@ function doltBinaryNames(platform3) {
21164
21340
  return platform3 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
21165
21341
  }
21166
21342
  function knownDoltDirs(platform3) {
21167
- const P3 = platform3 === "win32" ? path54.win32 : path54.posix;
21343
+ const P3 = platform3 === "win32" ? path55.win32 : path55.posix;
21168
21344
  const home = _doltPathSeam.homedir();
21169
21345
  if (platform3 === "win32") {
21170
21346
  return [
@@ -21180,7 +21356,7 @@ function knownDoltDirs(platform3) {
21180
21356
  ].filter(Boolean);
21181
21357
  }
21182
21358
  function ensureDoltResolvable(platform3 = process.platform) {
21183
- const P3 = platform3 === "win32" ? path54.win32 : path54.posix;
21359
+ const P3 = platform3 === "win32" ? path55.win32 : path55.posix;
21184
21360
  const delim = platform3 === "win32" ? ";" : ":";
21185
21361
  const names = doltBinaryNames(platform3);
21186
21362
  const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
@@ -21316,8 +21492,8 @@ async function ensureSharedServer(adapter, options = {}) {
21316
21492
  // src/beads/project-key.ts
21317
21493
  var import_child_process22 = require("child_process");
21318
21494
  var crypto2 = __toESM(require("crypto"));
21319
- var fs52 = __toESM(require("fs"));
21320
- var path55 = __toESM(require("path"));
21495
+ var fs53 = __toESM(require("fs"));
21496
+ var path56 = __toESM(require("path"));
21321
21497
  function normalizeOrigin(raw) {
21322
21498
  const trimmed = raw.trim();
21323
21499
  if (!trimmed) return null;
@@ -21343,17 +21519,17 @@ function normalizeOrigin(raw) {
21343
21519
  return `${host2}/${pathPart}`;
21344
21520
  }
21345
21521
  function findRepoRoot(cwd) {
21346
- let dir = path55.resolve(cwd);
21522
+ let dir = path56.resolve(cwd);
21347
21523
  const seen = /* @__PURE__ */ new Set();
21348
21524
  for (let i = 0; i < 256; i++) {
21349
21525
  if (seen.has(dir)) return null;
21350
21526
  seen.add(dir);
21351
21527
  try {
21352
- const stat3 = fs52.statSync(path55.join(dir, ".git"), { throwIfNoEntry: false });
21528
+ const stat3 = fs53.statSync(path56.join(dir, ".git"), { throwIfNoEntry: false });
21353
21529
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
21354
21530
  } catch {
21355
21531
  }
21356
- const parent = path55.dirname(dir);
21532
+ const parent = path56.dirname(dir);
21357
21533
  if (parent === dir) return null;
21358
21534
  dir = parent;
21359
21535
  }
@@ -21364,7 +21540,7 @@ var _execSeam2 = {
21364
21540
  const out2 = (0, import_child_process22.execFileSync)(file, args2, opts);
21365
21541
  return typeof out2 === "string" ? out2 : out2.toString("utf8");
21366
21542
  },
21367
- realpath: (p2) => fs52.realpathSync(p2)
21543
+ realpath: (p2) => fs53.realpathSync(p2)
21368
21544
  };
21369
21545
  function readOrigin(cwd) {
21370
21546
  try {
@@ -21393,7 +21569,7 @@ function deriveProjectIdentity(cwd = process.cwd()) {
21393
21569
  } catch {
21394
21570
  }
21395
21571
  const hash = crypto2.createHash("sha256").update(real).digest("hex");
21396
- return { projectKey: `path:${hash}`, projectLabel: path55.basename(real) || "project" };
21572
+ return { projectKey: `path:${hash}`, projectLabel: path56.basename(real) || "project" };
21397
21573
  }
21398
21574
 
21399
21575
  // src/beads/project-prefix.ts
@@ -21438,17 +21614,17 @@ var _provisionSeam = {
21438
21614
  };
21439
21615
  var _linkSeam = {
21440
21616
  platform: () => process.platform,
21441
- homedir: () => os42.homedir(),
21617
+ homedir: () => os43.homedir(),
21442
21618
  isWritableDir: (dir) => {
21443
21619
  try {
21444
- fs53.accessSync(dir, fs53.constants.W_OK);
21620
+ fs54.accessSync(dir, fs54.constants.W_OK);
21445
21621
  return true;
21446
21622
  } catch {
21447
21623
  return false;
21448
21624
  }
21449
21625
  },
21450
21626
  ensureDir: (dir) => {
21451
- fs53.mkdirSync(dir, { recursive: true });
21627
+ fs54.mkdirSync(dir, { recursive: true });
21452
21628
  },
21453
21629
  /**
21454
21630
  * A directory to symlink `bd` into so the AGENT's shell + Claude Code's
@@ -21469,9 +21645,9 @@ var _linkSeam = {
21469
21645
  * which `linkBdOntoPath` creates if missing.
21470
21646
  */
21471
21647
  cliBinDir: () => {
21472
- const pathDirs = (process.env.PATH ?? "").split(path56.delimiter).filter(Boolean);
21648
+ const pathDirs = (process.env.PATH ?? "").split(path57.delimiter).filter(Boolean);
21473
21649
  const home = _linkSeam.homedir();
21474
- const localBin = home ? path56.join(home, ".local", "bin") : null;
21650
+ const localBin = home ? path57.join(home, ".local", "bin") : null;
21475
21651
  if (localBin) {
21476
21652
  try {
21477
21653
  _linkSeam.ensureDir(localBin);
@@ -21481,16 +21657,16 @@ var _linkSeam = {
21481
21657
  const candidates = [];
21482
21658
  if (localBin) candidates.push(localBin);
21483
21659
  try {
21484
- candidates.push(path56.dirname(process.execPath));
21660
+ candidates.push(path57.dirname(process.execPath));
21485
21661
  } catch {
21486
21662
  }
21487
21663
  candidates.push("/usr/local/bin");
21488
21664
  const entry = process.argv[1];
21489
21665
  if (entry) {
21490
21666
  try {
21491
- candidates.push(path56.dirname(fs53.realpathSync(entry)));
21667
+ candidates.push(path57.dirname(fs54.realpathSync(entry)));
21492
21668
  } catch {
21493
- candidates.push(path56.dirname(entry));
21669
+ candidates.push(path57.dirname(entry));
21494
21670
  }
21495
21671
  }
21496
21672
  const onPathWritable = candidates.find(
@@ -21502,20 +21678,20 @@ var _linkSeam = {
21502
21678
  /** Current symlink target at `linkPath`, or null when absent / not a link. */
21503
21679
  readlink: (linkPath) => {
21504
21680
  try {
21505
- return fs53.readlinkSync(linkPath);
21681
+ return fs54.readlinkSync(linkPath);
21506
21682
  } catch {
21507
21683
  return null;
21508
21684
  }
21509
21685
  },
21510
- unlink: (linkPath) => fs53.unlinkSync(linkPath),
21511
- symlink: (target, linkPath) => fs53.symlinkSync(target, linkPath)
21686
+ unlink: (linkPath) => fs54.unlinkSync(linkPath),
21687
+ symlink: (target, linkPath) => fs54.symlinkSync(target, linkPath)
21512
21688
  };
21513
21689
  function linkBdOntoPath(binaryPath) {
21514
21690
  if (_linkSeam.platform() === "win32") return;
21515
21691
  const binDir = _linkSeam.cliBinDir();
21516
21692
  if (!binDir) return;
21517
21693
  _linkSeam.ensureDir(binDir);
21518
- const linkPath = path56.join(binDir, "bd");
21694
+ const linkPath = path57.join(binDir, "bd");
21519
21695
  if (linkPath === binaryPath) return;
21520
21696
  const current = _linkSeam.readlink(linkPath);
21521
21697
  if (current === binaryPath) return;
@@ -21710,7 +21886,7 @@ function dedupeRecipes(agents) {
21710
21886
 
21711
21887
  // src/beads/watcher.ts
21712
21888
  var crypto4 = __toESM(require("crypto"));
21713
- var path57 = __toESM(require("path"));
21889
+ var path58 = __toESM(require("path"));
21714
21890
  var API_BASE6 = resolveApiBaseUrl();
21715
21891
  var DEBOUNCE_MS2 = 400;
21716
21892
  var ZERO_SUMMARY = {
@@ -21734,7 +21910,7 @@ var BeadsWatcher = class {
21734
21910
  constructor(opts) {
21735
21911
  this.opts = opts;
21736
21912
  this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
21737
- this.feedPath = opts.feedPath ?? path57.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
21913
+ this.feedPath = opts.feedPath ?? path58.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
21738
21914
  this.apiBase = opts.apiBaseUrl ?? API_BASE6;
21739
21915
  }
21740
21916
  opts;
@@ -21985,15 +22161,15 @@ async function handleBeadsActionCommand(action, started) {
21985
22161
  }
21986
22162
 
21987
22163
  // src/beads/config-store.ts
21988
- var import_node_fs8 = __toESM(require("fs"));
21989
- var import_node_os7 = __toESM(require("os"));
21990
- var import_node_path6 = __toESM(require("path"));
22164
+ var import_node_fs9 = __toESM(require("fs"));
22165
+ var import_node_os8 = __toESM(require("os"));
22166
+ var import_node_path7 = __toESM(require("path"));
21991
22167
  function beadsConfigPath() {
21992
- return import_node_path6.default.join(import_node_os7.default.homedir(), ".codeam", "beads-config.json");
22168
+ return import_node_path7.default.join(import_node_os8.default.homedir(), ".codeam", "beads-config.json");
21993
22169
  }
21994
22170
  function readBeadsEnabled() {
21995
22171
  try {
21996
- const raw = import_node_fs8.default.readFileSync(beadsConfigPath(), "utf8");
22172
+ const raw = import_node_fs9.default.readFileSync(beadsConfigPath(), "utf8");
21997
22173
  const cfg = JSON.parse(raw);
21998
22174
  return cfg.enabled !== false;
21999
22175
  } catch {
@@ -22002,10 +22178,10 @@ function readBeadsEnabled() {
22002
22178
  }
22003
22179
  function persistBeadsConfig(cfg) {
22004
22180
  const file = beadsConfigPath();
22005
- import_node_fs8.default.mkdirSync(import_node_path6.default.dirname(file), { recursive: true });
22181
+ import_node_fs9.default.mkdirSync(import_node_path7.default.dirname(file), { recursive: true });
22006
22182
  const tmp = `${file}.tmp`;
22007
- import_node_fs8.default.writeFileSync(tmp, JSON.stringify(cfg), { mode: 384 });
22008
- import_node_fs8.default.renameSync(tmp, file);
22183
+ import_node_fs9.default.writeFileSync(tmp, JSON.stringify(cfg), { mode: 384 });
22184
+ import_node_fs9.default.renameSync(tmp, file);
22009
22185
  restrictToOwner(file);
22010
22186
  }
22011
22187
 
@@ -22140,6 +22316,88 @@ async function configureBeads(action, ctx, deps) {
22140
22316
  return { enabled: true, running, ...p2 };
22141
22317
  }
22142
22318
 
22319
+ // src/skills/configure.ts
22320
+ var import_node_os10 = __toESM(require("os"));
22321
+
22322
+ // src/skills/materialize.ts
22323
+ var import_node_fs10 = __toESM(require("fs"));
22324
+ var import_node_os9 = __toESM(require("os"));
22325
+ var import_node_path8 = __toESM(require("path"));
22326
+ var NS = "codeam-";
22327
+ function skillDirFor(id, home = import_node_os9.default.homedir()) {
22328
+ return import_node_path8.default.join(home, ".claude", "skills", `${NS}${id}`);
22329
+ }
22330
+ function renderSkillMd(id, description, body) {
22331
+ const desc = description.replace(/\s*\n\s*/g, " ").trim();
22332
+ return `---
22333
+ name: ${NS}${id}
22334
+ description: ${JSON.stringify(desc)}
22335
+ ---
22336
+
22337
+ ${body.trim()}
22338
+ `;
22339
+ }
22340
+ function materializeSkill(id, home = import_node_os9.default.homedir()) {
22341
+ const def = getSkillDefinition(id);
22342
+ if (!def?.delivery.skillFile) return false;
22343
+ try {
22344
+ const dir = skillDirFor(id, home);
22345
+ import_node_fs10.default.mkdirSync(dir, { recursive: true, mode: 448 });
22346
+ import_node_fs10.default.writeFileSync(
22347
+ import_node_path8.default.join(dir, "SKILL.md"),
22348
+ renderSkillMd(id, def.description, def.delivery.skillFile.body),
22349
+ { encoding: "utf8", mode: 384 }
22350
+ );
22351
+ const baseDir = import_node_path8.default.resolve(dir);
22352
+ const baseDirWithSep = baseDir + import_node_path8.default.sep;
22353
+ for (const [rel, contents] of Object.entries(def.delivery.skillFile.files ?? {})) {
22354
+ const target = import_node_path8.default.join(dir, rel);
22355
+ if (!import_node_path8.default.resolve(target).startsWith(baseDirWithSep) && import_node_path8.default.resolve(target) !== baseDir) {
22356
+ continue;
22357
+ }
22358
+ import_node_fs10.default.mkdirSync(import_node_path8.default.dirname(target), { recursive: true, mode: 448 });
22359
+ import_node_fs10.default.writeFileSync(target, contents, { encoding: "utf8", mode: 384 });
22360
+ }
22361
+ return true;
22362
+ } catch (err) {
22363
+ log.warn("skills", `failed to materialize ${id} (best-effort): ${err instanceof Error ? err.message : String(err)}`);
22364
+ return false;
22365
+ }
22366
+ }
22367
+ function removeSkill(id, home = import_node_os9.default.homedir()) {
22368
+ try {
22369
+ import_node_fs10.default.rmSync(skillDirFor(id, home), { recursive: true, force: true });
22370
+ } catch {
22371
+ }
22372
+ }
22373
+
22374
+ // src/skills/configure.ts
22375
+ function currentInstalled() {
22376
+ const m = readSkillsManifest();
22377
+ return (m?.skills ?? []).map((s) => s.id).filter(isSkillId);
22378
+ }
22379
+ function configureSkill(action, skillId, home = import_node_os10.default.homedir()) {
22380
+ if (action === "list") return { ok: true, installed: currentInstalled() };
22381
+ if (!skillId || !isSkillId(skillId)) {
22382
+ return { ok: false, installed: currentInstalled(), error: `unknown skill: ${skillId ?? "(none)"}` };
22383
+ }
22384
+ const set = new Set(currentInstalled());
22385
+ if (action === "add") {
22386
+ if (!materializeSkill(skillId, home)) {
22387
+ return { ok: false, installed: [...set], error: `skill ${skillId} has no skillFile rail` };
22388
+ }
22389
+ set.add(skillId);
22390
+ } else if (action === "remove") {
22391
+ removeSkill(skillId, home);
22392
+ set.delete(skillId);
22393
+ } else {
22394
+ return { ok: false, installed: currentInstalled(), error: `unknown action: ${action}` };
22395
+ }
22396
+ const installed2 = [...set];
22397
+ persistSkillsManifest({ skills: installed2.map((id) => ({ id })) });
22398
+ return { ok: true, installed: installed2 };
22399
+ }
22400
+
22143
22401
  // src/commands/start/handlers.ts
22144
22402
  var pendingAttachmentFiles = /* @__PURE__ */ new Set();
22145
22403
  function cleanupAttachmentTempFiles() {
@@ -22151,8 +22409,8 @@ function cleanupAttachmentTempFiles() {
22151
22409
  function saveFilesTemp(files) {
22152
22410
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
22153
22411
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
22154
- const tmpPath = path59.join(os44.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
22155
- fs55.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
22412
+ const tmpPath = path61.join(os47.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
22413
+ fs57.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
22156
22414
  pendingAttachmentFiles.add(tmpPath);
22157
22415
  return tmpPath;
22158
22416
  });
@@ -22364,9 +22622,9 @@ var listFiles = async (ctx, cmd, parsed) => {
22364
22622
  await ctx.relay.sendResult(cmd.id, "completed", result);
22365
22623
  };
22366
22624
  var envReadH = async (ctx, cmd) => {
22367
- const envPath = path59.join(process.cwd(), ".env");
22625
+ const envPath = path61.join(process.cwd(), ".env");
22368
22626
  try {
22369
- const raw = await fs55.promises.readFile(envPath, "utf8");
22627
+ const raw = await fs57.promises.readFile(envPath, "utf8");
22370
22628
  await ctx.relay.sendResult(cmd.id, "completed", {
22371
22629
  exists: true,
22372
22630
  vars: parseDotenv(raw)
@@ -22397,17 +22655,22 @@ var envWriteH = async (ctx, cmd, parsed) => {
22397
22655
  }
22398
22656
  seen.add(v.key);
22399
22657
  }
22400
- const envPath = path59.join(process.cwd(), ".env");
22401
- const tmpPath = path59.join(process.cwd(), ".env.codeam.tmp");
22658
+ const envPath = path61.join(process.cwd(), ".env");
22659
+ const tmpPath = path61.join(process.cwd(), ".env.codeam.tmp");
22402
22660
  try {
22403
- await fs55.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
22404
- await fs55.promises.rename(tmpPath, envPath);
22661
+ await fs57.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
22662
+ await fs57.promises.rename(tmpPath, envPath);
22405
22663
  await ctx.relay.sendResult(cmd.id, "completed", { ok: true, count: vars.length });
22406
22664
  } catch (err) {
22407
- await fs55.promises.rm(tmpPath, { force: true }).catch(() => void 0);
22665
+ await fs57.promises.rm(tmpPath, { force: true }).catch(() => void 0);
22408
22666
  await ctx.relay.sendResult(cmd.id, "failed", { error: err.message });
22409
22667
  }
22410
22668
  };
22669
+ var skillsConfigureH = async (ctx, cmd, parsed) => {
22670
+ const action = parsed.action;
22671
+ const res = configureSkill(action ?? "list", parsed.skillId);
22672
+ await ctx.relay.sendResult(cmd.id, res.ok ? "completed" : "failed", res);
22673
+ };
22411
22674
  var takeControlH = async (ctx, cmd) => {
22412
22675
  if (!ctx.baton) {
22413
22676
  await ctx.relay.sendResult(cmd.id, "failed", { code: "NO_BATON" });
@@ -22448,7 +22711,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
22448
22711
  let configuredAgent = rawAgentId;
22449
22712
  if (!configuredAgent) {
22450
22713
  try {
22451
- const raw = JSON.parse(fs55.readFileSync(headroomConfigPath(), "utf8"));
22714
+ const raw = JSON.parse(fs57.readFileSync(headroomConfigPath(), "utf8"));
22452
22715
  configuredAgent = raw.agent ?? "";
22453
22716
  } catch {
22454
22717
  }
@@ -22482,7 +22745,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
22482
22745
  persist: persistHeadroomConfig,
22483
22746
  readEnabled: () => {
22484
22747
  try {
22485
- const raw = JSON.parse(fs55.readFileSync(headroomConfigPath(), "utf8"));
22748
+ const raw = JSON.parse(fs57.readFileSync(headroomConfigPath(), "utf8"));
22486
22749
  return raw.enabled === true;
22487
22750
  } catch {
22488
22751
  return false;
@@ -22739,7 +23002,7 @@ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
22739
23002
  });
22740
23003
  const token = ctx.pluginAuthToken;
22741
23004
  void (async () => {
22742
- const os53 = createOsStrategy();
23005
+ const os57 = createOsStrategy();
22743
23006
  try {
22744
23007
  const report = await reviewPullRequest(
22745
23008
  {
@@ -22748,7 +23011,7 @@ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
22748
23011
  baseBranch: parsed.baseBranch
22749
23012
  },
22750
23013
  {
22751
- runReview: (input) => new CoderabbitRuntimeStrategy(os53).runOneShot(input),
23014
+ runReview: (input) => new CoderabbitRuntimeStrategy(os57).runOneShot(input),
22752
23015
  runGh: (args2) => defaultRunGh(args2),
22753
23016
  postReport: async (r) => {
22754
23017
  if (!token) return;
@@ -22786,7 +23049,7 @@ var headroomBudgetH = async (ctx, cmd) => {
22786
23049
  }
22787
23050
  let headroomActive = false;
22788
23051
  try {
22789
- const raw = JSON.parse(fs55.readFileSync(headroomConfigPath(), "utf8"));
23052
+ const raw = JSON.parse(fs57.readFileSync(headroomConfigPath(), "utf8"));
22790
23053
  headroomActive = raw.enabled === true;
22791
23054
  } catch {
22792
23055
  }
@@ -22796,7 +23059,7 @@ var headroomBudgetH = async (ctx, cmd) => {
22796
23059
  }
22797
23060
  let existingConfig = { enabled: true };
22798
23061
  try {
22799
- existingConfig = JSON.parse(fs55.readFileSync(headroomConfigPath(), "utf8"));
23062
+ existingConfig = JSON.parse(fs57.readFileSync(headroomConfigPath(), "utf8"));
22800
23063
  } catch {
22801
23064
  }
22802
23065
  if (payload.budgetEnabled && payload.budgetUsd != null) {
@@ -22909,9 +23172,9 @@ var CLI_UPDATE_MAX_ATTEMPTS = 3;
22909
23172
  function buildNpmInstallInvocation(opts) {
22910
23173
  const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
22911
23174
  const execPath = opts?.execPath ?? process.execPath;
22912
- const exists2 = opts?.existsSync ?? fs55.existsSync;
23175
+ const exists2 = opts?.existsSync ?? fs57.existsSync;
22913
23176
  const platform3 = opts?.platform ?? process.platform;
22914
- const p2 = platform3 === "win32" ? path59.win32 : path59.posix;
23177
+ const p2 = platform3 === "win32" ? path61.win32 : path61.posix;
22915
23178
  const normalized = entryScript.split(/[\\/]/).join("/");
22916
23179
  const marker = "/lib/node_modules/codeam-cli/";
22917
23180
  const markerIdx = normalized.indexOf(marker);
@@ -23497,6 +23760,7 @@ var handlers = {
23497
23760
  save_preview_config: savePreviewConfigH,
23498
23761
  env_read: envReadH,
23499
23762
  env_write: envWriteH,
23763
+ skills_configure: skillsConfigureH,
23500
23764
  take_control: takeControlH,
23501
23765
  handback: handbackH,
23502
23766
  headroom_configure: headroomConfigureH,
@@ -23577,29 +23841,6 @@ function buildKeepAlive(ctx) {
23577
23841
  };
23578
23842
  }
23579
23843
 
23580
- // src/lib/process-guards.ts
23581
- var installed = false;
23582
- function installRelayCrashGuards() {
23583
- if (installed) return;
23584
- installed = true;
23585
- process.on("unhandledRejection", (reason) => {
23586
- log.error("process", `unhandledRejection \u2014 relay kept alive \u2014 ${describeReason(reason)}`);
23587
- });
23588
- process.on("uncaughtException", (err) => {
23589
- log.error("process", `uncaughtException \u2014 relay kept alive \u2014 ${describeReason(err)}`);
23590
- });
23591
- }
23592
- function describeReason(reason) {
23593
- if (reason instanceof Error) {
23594
- return reason.stack ?? `${reason.name}: ${reason.message}`;
23595
- }
23596
- try {
23597
- return typeof reason === "string" ? reason : JSON.stringify(reason);
23598
- } catch {
23599
- return String(reason);
23600
- }
23601
- }
23602
-
23603
23844
  // src/commands/start-infra-only.ts
23604
23845
  var INFRA_ONLY_COMMAND_TYPES = /* @__PURE__ */ new Set([
23605
23846
  // File ops (drive the dashboard's Files panel + open-file).
@@ -23796,11 +24037,11 @@ function resolveTokenValue(args2) {
23796
24037
  }
23797
24038
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
23798
24039
  if (fileFlag) {
23799
- const path76 = fileFlag.slice("--token-file=".length);
24040
+ const path78 = fileFlag.slice("--token-file=".length);
23800
24041
  try {
23801
- const content = fs56.readFileSync(path76, "utf8").trim();
23802
- if (content.length === 0) fail(`--token-file ${path76} is empty`);
23803
- rmIfExistsQuiet(path76);
24042
+ const content = fs58.readFileSync(path78, "utf8").trim();
24043
+ if (content.length === 0) fail(`--token-file ${path78} is empty`);
24044
+ rmIfExistsQuiet(path78);
23804
24045
  return content;
23805
24046
  } catch (err) {
23806
24047
  fail(`Could not read --token-file: ${err.message}`);
@@ -23829,7 +24070,7 @@ async function claimOnce(token, pluginId, pluginSecretHash) {
23829
24070
  pluginId,
23830
24071
  ideName: "codeam-cli (codespace)",
23831
24072
  ideVersion: process.env.npm_package_version ?? "unknown",
23832
- hostname: os45.hostname(),
24073
+ hostname: os48.hostname(),
23833
24074
  codespaceName: process.env.CODESPACE_NAME ?? "",
23834
24075
  // Current git branch of the codespace's working directory, so the
23835
24076
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -23890,7 +24131,7 @@ async function claim(token, pluginId, pluginSecretHash) {
23890
24131
  }
23891
24132
  }
23892
24133
  function pairAutoLockPath() {
23893
- return path60.join(os45.homedir(), ".codeam", "pair-auto.lock");
24134
+ return path62.join(os48.homedir(), ".codeam", "pair-auto.lock");
23894
24135
  }
23895
24136
  function isLivePairAuto(pid) {
23896
24137
  if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
@@ -23900,7 +24141,7 @@ function isLivePairAuto(pid) {
23900
24141
  if (e.code !== "EPERM") return false;
23901
24142
  }
23902
24143
  try {
23903
- return fs56.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
24144
+ return fs58.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
23904
24145
  } catch {
23905
24146
  return true;
23906
24147
  }
@@ -23910,24 +24151,24 @@ function isLiveCodeam(pid) {
23910
24151
  }
23911
24152
  function daemonLockPath(sessionId) {
23912
24153
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
23913
- return path60.join(os45.homedir(), ".codeam", `daemon-${safe}.lock`);
24154
+ return path62.join(os48.homedir(), ".codeam", `daemon-${safe}.lock`);
23914
24155
  }
23915
24156
  function acquireDaemonLock(sessionId) {
23916
24157
  const lockPath = daemonLockPath(sessionId);
23917
24158
  try {
23918
- fs56.mkdirSync(path60.dirname(lockPath), { recursive: true });
24159
+ fs58.mkdirSync(path62.dirname(lockPath), { recursive: true });
23919
24160
  try {
23920
- fs56.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
24161
+ fs58.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
23921
24162
  } catch (e) {
23922
24163
  if (e.code !== "EEXIST") throw e;
23923
- const holder = Number(fs56.readFileSync(lockPath, "utf8").trim());
24164
+ const holder = Number(fs58.readFileSync(lockPath, "utf8").trim());
23924
24165
  if (holder && holder !== process.pid && isLiveCodeam(holder)) return false;
23925
- fs56.writeFileSync(lockPath, String(process.pid));
24166
+ fs58.writeFileSync(lockPath, String(process.pid));
23926
24167
  }
23927
24168
  const release3 = () => {
23928
24169
  try {
23929
- if (fs56.existsSync(lockPath) && Number(fs56.readFileSync(lockPath, "utf8").trim()) === process.pid) {
23930
- fs56.unlinkSync(lockPath);
24170
+ if (fs58.existsSync(lockPath) && Number(fs58.readFileSync(lockPath, "utf8").trim()) === process.pid) {
24171
+ fs58.unlinkSync(lockPath);
23931
24172
  }
23932
24173
  } catch {
23933
24174
  }
@@ -23949,19 +24190,19 @@ function acquireDaemonLock(sessionId) {
23949
24190
  function acquireSingletonLock() {
23950
24191
  const lockPath = pairAutoLockPath();
23951
24192
  try {
23952
- fs56.mkdirSync(path60.dirname(lockPath), { recursive: true });
24193
+ fs58.mkdirSync(path62.dirname(lockPath), { recursive: true });
23953
24194
  try {
23954
- fs56.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
24195
+ fs58.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
23955
24196
  } catch (e) {
23956
24197
  if (e.code !== "EEXIST") throw e;
23957
- const holder = Number(fs56.readFileSync(lockPath, "utf8").trim());
24198
+ const holder = Number(fs58.readFileSync(lockPath, "utf8").trim());
23958
24199
  if (isLivePairAuto(holder)) return false;
23959
- fs56.writeFileSync(lockPath, String(process.pid));
24200
+ fs58.writeFileSync(lockPath, String(process.pid));
23960
24201
  }
23961
24202
  process.once("exit", () => {
23962
24203
  try {
23963
- if (fs56.existsSync(lockPath) && Number(fs56.readFileSync(lockPath, "utf8").trim()) === process.pid) {
23964
- fs56.unlinkSync(lockPath);
24204
+ if (fs58.existsSync(lockPath) && Number(fs58.readFileSync(lockPath, "utf8").trim()) === process.pid) {
24205
+ fs58.unlinkSync(lockPath);
23965
24206
  }
23966
24207
  } catch {
23967
24208
  }
@@ -24407,7 +24648,7 @@ var AgentService = class _AgentService {
24407
24648
  };
24408
24649
 
24409
24650
  // src/agents/acp/adapters.ts
24410
- var path62 = __toESM(require("path"));
24651
+ var path64 = __toESM(require("path"));
24411
24652
 
24412
24653
  // src/agents/acp/agent-binary.ts
24413
24654
  var import_fs4 = __toESM(require("fs"));
@@ -24583,11 +24824,11 @@ async function waitForAdapterModuleGraph(command2, args2, opts = {}) {
24583
24824
 
24584
24825
  // src/agents/kimi/installer.ts
24585
24826
  var import_node_child_process26 = require("child_process");
24586
- var import_node_os8 = require("os");
24587
- var import_node_path7 = require("path");
24827
+ var import_node_os11 = require("os");
24828
+ var import_node_path9 = require("path");
24588
24829
  var INSTALL_URL2 = "https://code.kimi.com/kimi-code/install.sh";
24589
24830
  function kimiBinDir() {
24590
- return (0, import_node_path7.join)(process.env.KIMI_CODE_HOME || (0, import_node_path7.join)((0, import_node_os8.homedir)(), ".kimi-code"), "bin");
24831
+ return (0, import_node_path9.join)(process.env.KIMI_CODE_HOME || (0, import_node_path9.join)((0, import_node_os11.homedir)(), ".kimi-code"), "bin");
24591
24832
  }
24592
24833
  function kimiRuns() {
24593
24834
  const r = (0, import_node_child_process26.spawnSync)("kimi", ["--version"], { stdio: "ignore", timeout: 15e3 });
@@ -24650,13 +24891,13 @@ function resolveBin(pkgName, binName) {
24650
24891
  try {
24651
24892
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
24652
24893
  const manifest = require_(`${pkgName}/package.json`);
24653
- const pkgDir = path62.dirname(manifestPath);
24894
+ const pkgDir = path64.dirname(manifestPath);
24654
24895
  const bin = manifest.bin;
24655
24896
  if (!bin) return null;
24656
- if (typeof bin === "string") return path62.resolve(pkgDir, bin);
24897
+ if (typeof bin === "string") return path64.resolve(pkgDir, bin);
24657
24898
  const target = binName ?? Object.keys(bin)[0];
24658
24899
  if (!target || !bin[target]) return null;
24659
- return path62.resolve(pkgDir, bin[target]);
24900
+ return path64.resolve(pkgDir, bin[target]);
24660
24901
  } catch {
24661
24902
  return null;
24662
24903
  }
@@ -24791,9 +25032,9 @@ async function resolveAcpAdapterWithRetry(agent, opts = {}) {
24791
25032
  var import_node_crypto10 = require("crypto");
24792
25033
 
24793
25034
  // src/services/history.service.ts
24794
- var fs58 = __toESM(require("fs"));
24795
- var path63 = __toESM(require("path"));
24796
- var os47 = __toESM(require("os"));
25035
+ var fs60 = __toESM(require("fs"));
25036
+ var path65 = __toESM(require("path"));
25037
+ var os50 = __toESM(require("os"));
24797
25038
  var https7 = __toESM(require("https"));
24798
25039
  var http6 = __toESM(require("http"));
24799
25040
  var import_zod2 = require("zod");
@@ -24820,7 +25061,7 @@ function parseJsonl(filePath) {
24820
25061
  const messages = [];
24821
25062
  let raw;
24822
25063
  try {
24823
- raw = fs58.readFileSync(filePath, "utf8");
25064
+ raw = fs60.readFileSync(filePath, "utf8");
24824
25065
  } catch (err) {
24825
25066
  if (err.code !== "ENOENT") {
24826
25067
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -24961,7 +25202,7 @@ var HistoryService = class _HistoryService {
24961
25202
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
24962
25203
  }
24963
25204
  get projectDir() {
24964
- return this.runtime.resolveHistoryDir(this.cwd) ?? path63.join(os47.homedir(), ".claude", "projects", encodeCwd(this.cwd));
25205
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path65.join(os50.homedir(), ".claude", "projects", encodeCwd(this.cwd));
24965
25206
  }
24966
25207
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
24967
25208
  setCurrentConversationId(id) {
@@ -24973,7 +25214,7 @@ var HistoryService = class _HistoryService {
24973
25214
  /** Return the current message count in the active conversation. */
24974
25215
  getCurrentMessageCount() {
24975
25216
  if (!this.currentConversationId) return 0;
24976
- const filePath = path63.join(this.projectDir, `${this.currentConversationId}.jsonl`);
25217
+ const filePath = path65.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24977
25218
  return parseJsonl(filePath).length;
24978
25219
  }
24979
25220
  /**
@@ -24984,7 +25225,7 @@ var HistoryService = class _HistoryService {
24984
25225
  const deadline = Date.now() + timeoutMs;
24985
25226
  while (Date.now() < deadline) {
24986
25227
  if (!this.currentConversationId) return null;
24987
- const filePath = path63.join(this.projectDir, `${this.currentConversationId}.jsonl`);
25228
+ const filePath = path65.join(this.projectDir, `${this.currentConversationId}.jsonl`);
24988
25229
  const messages = parseJsonl(filePath);
24989
25230
  if (messages.length > previousCount) {
24990
25231
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -25010,16 +25251,16 @@ var HistoryService = class _HistoryService {
25010
25251
  const dir = this.projectDir;
25011
25252
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
25012
25253
  try {
25013
- const files = fs58.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
25254
+ const files = fs60.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
25014
25255
  try {
25015
- const stat3 = fs58.statSync(path63.join(dir, e.name));
25256
+ const stat3 = fs60.statSync(path65.join(dir, e.name));
25016
25257
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
25017
25258
  } catch {
25018
25259
  return { name: e.name, mtime: 0, birthtime: 0 };
25019
25260
  }
25020
25261
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
25021
25262
  if (files.length > 0) {
25022
- this.currentConversationId = path63.basename(files[0].name, ".jsonl");
25263
+ this.currentConversationId = path65.basename(files[0].name, ".jsonl");
25023
25264
  }
25024
25265
  } catch {
25025
25266
  }
@@ -25053,13 +25294,13 @@ var HistoryService = class _HistoryService {
25053
25294
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
25054
25295
  let entries;
25055
25296
  try {
25056
- entries = fs58.readdirSync(dir, { withFileTypes: true });
25297
+ entries = fs60.readdirSync(dir, { withFileTypes: true });
25057
25298
  } catch {
25058
25299
  return null;
25059
25300
  }
25060
25301
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
25061
25302
  try {
25062
- const stat3 = fs58.statSync(path63.join(dir, e.name));
25303
+ const stat3 = fs60.statSync(path65.join(dir, e.name));
25063
25304
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
25064
25305
  } catch {
25065
25306
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -25068,12 +25309,12 @@ var HistoryService = class _HistoryService {
25068
25309
  if (files.length === 0) return null;
25069
25310
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
25070
25311
  if (!files.some((f) => f.name === targetFile)) return null;
25071
- return this.extractUsageFromFile(path63.join(dir, targetFile));
25312
+ return this.extractUsageFromFile(path65.join(dir, targetFile));
25072
25313
  }
25073
25314
  extractUsageFromFile(filePath) {
25074
25315
  let raw;
25075
25316
  try {
25076
- raw = fs58.readFileSync(filePath, "utf8");
25317
+ raw = fs60.readFileSync(filePath, "utf8");
25077
25318
  } catch {
25078
25319
  return null;
25079
25320
  }
@@ -25118,9 +25359,9 @@ var HistoryService = class _HistoryService {
25118
25359
  let totalCost = 0;
25119
25360
  let files;
25120
25361
  try {
25121
- files = fs58.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
25362
+ files = fs60.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
25122
25363
  try {
25123
- return fs58.statSync(path63.join(projectDir, f)).mtimeMs >= monthStartMs;
25364
+ return fs60.statSync(path65.join(projectDir, f)).mtimeMs >= monthStartMs;
25124
25365
  } catch {
25125
25366
  return false;
25126
25367
  }
@@ -25131,7 +25372,7 @@ var HistoryService = class _HistoryService {
25131
25372
  for (const file of files) {
25132
25373
  let raw;
25133
25374
  try {
25134
- raw = fs58.readFileSync(path63.join(projectDir, file), "utf8");
25375
+ raw = fs60.readFileSync(path65.join(projectDir, file), "utf8");
25135
25376
  } catch {
25136
25377
  continue;
25137
25378
  }
@@ -25210,7 +25451,7 @@ var HistoryService = class _HistoryService {
25210
25451
  if (this.runtime.resolveHistoryFile) {
25211
25452
  return this.runtime.resolveHistoryFile(this.cwd, sessionId);
25212
25453
  }
25213
- return path63.join(this.projectDir, `${sessionId}.jsonl`);
25454
+ return path65.join(this.projectDir, `${sessionId}.jsonl`);
25214
25455
  }
25215
25456
  /**
25216
25457
  * Parse a conversation's messages from disk, agent-aware. Claude uses the
@@ -25244,7 +25485,7 @@ var HistoryService = class _HistoryService {
25244
25485
  };
25245
25486
  });
25246
25487
  }
25247
- return parseJsonl(path63.join(this.projectDir, `${sessionId}.jsonl`));
25488
+ return parseJsonl(path65.join(this.projectDir, `${sessionId}.jsonl`));
25248
25489
  }
25249
25490
  async loadConversation(sessionId) {
25250
25491
  const messages = this.readConversation(sessionId);
@@ -25312,7 +25553,7 @@ var HistoryService = class _HistoryService {
25312
25553
  if (!filePath) return false;
25313
25554
  let mtimeMs;
25314
25555
  try {
25315
- mtimeMs = fs58.statSync(filePath).mtimeMs;
25556
+ mtimeMs = fs60.statSync(filePath).mtimeMs;
25316
25557
  } catch {
25317
25558
  return false;
25318
25559
  }
@@ -25387,10 +25628,10 @@ var HistoryService = class _HistoryService {
25387
25628
 
25388
25629
  // src/agents/acp/client.ts
25389
25630
  var import_node_child_process27 = require("child_process");
25390
- var fs59 = __toESM(require("fs/promises"));
25631
+ var fs61 = __toESM(require("fs/promises"));
25391
25632
  var fsSync = __toESM(require("fs"));
25392
- var os48 = __toESM(require("os"));
25393
- var path64 = __toESM(require("path"));
25633
+ var os51 = __toESM(require("os"));
25634
+ var path66 = __toESM(require("path"));
25394
25635
  var import_node_stream = require("stream");
25395
25636
 
25396
25637
  // ../../node_modules/@agentclientprotocol/sdk/dist/schema/index.js
@@ -30175,7 +30416,7 @@ var AcpClient = class {
30175
30416
  },
30176
30417
  readTextFile: async (params) => {
30177
30418
  try {
30178
- const content = await fs59.readFile(params.path, "utf8");
30419
+ const content = await fs61.readFile(params.path, "utf8");
30179
30420
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
30180
30421
  } catch (err) {
30181
30422
  const code = err.code;
@@ -30195,7 +30436,7 @@ var AcpClient = class {
30195
30436
  },
30196
30437
  writeTextFile: async (params) => {
30197
30438
  try {
30198
- await fs59.writeFile(params.path, params.content, "utf8");
30439
+ await fs61.writeFile(params.path, params.content, "utf8");
30199
30440
  return {};
30200
30441
  } catch (err) {
30201
30442
  const code = err.code;
@@ -30255,29 +30496,29 @@ function applyLineRange(content, line, limit) {
30255
30496
  return { content: lines.slice(start2, end).join("\n") };
30256
30497
  }
30257
30498
  function knownAgentBinaryDirs() {
30258
- const home = os48.homedir();
30499
+ const home = os51.homedir();
30259
30500
  const out2 = [];
30260
30501
  out2.push("/tmp/codeam-node20/bin");
30261
30502
  for (const root of [
30262
30503
  "/usr/local/share/nvm/versions/node",
30263
- path64.join(home, ".nvm/versions/node")
30504
+ path66.join(home, ".nvm/versions/node")
30264
30505
  ]) {
30265
30506
  try {
30266
30507
  for (const child of fsSync.readdirSync(root)) {
30267
- out2.push(path64.join(root, child, "bin"));
30508
+ out2.push(path66.join(root, child, "bin"));
30268
30509
  }
30269
30510
  } catch {
30270
30511
  }
30271
30512
  }
30272
- out2.push(path64.join(home, ".volta/bin"));
30513
+ out2.push(path66.join(home, ".volta/bin"));
30273
30514
  out2.push("/usr/local/bin");
30274
30515
  out2.push("/usr/bin");
30275
- out2.push(path64.join(home, ".local/bin"));
30276
- out2.push(path64.join(home, "bin"));
30516
+ out2.push(path66.join(home, ".local/bin"));
30517
+ out2.push(path66.join(home, "bin"));
30277
30518
  if (process.platform === "win32") {
30278
30519
  const { LOCALAPPDATA, APPDATA } = process.env;
30279
- if (LOCALAPPDATA) out2.push(path64.join(LOCALAPPDATA, "cursor-agent"));
30280
- if (APPDATA) out2.push(path64.join(APPDATA, "npm"));
30520
+ if (LOCALAPPDATA) out2.push(path66.join(LOCALAPPDATA, "cursor-agent"));
30521
+ if (APPDATA) out2.push(path66.join(APPDATA, "npm"));
30281
30522
  }
30282
30523
  return out2.filter((p2) => {
30283
30524
  try {
@@ -30289,7 +30530,7 @@ function knownAgentBinaryDirs() {
30289
30530
  }
30290
30531
  function expandPathForAgentBinaries(existingPath) {
30291
30532
  const existing = new Set(
30292
- existingPath.split(path64.delimiter).filter((p2) => p2.length > 0)
30533
+ existingPath.split(path66.delimiter).filter((p2) => p2.length > 0)
30293
30534
  );
30294
30535
  const additions = [];
30295
30536
  for (const dir of knownAgentBinaryDirs()) {
@@ -30299,7 +30540,7 @@ function expandPathForAgentBinaries(existingPath) {
30299
30540
  }
30300
30541
  }
30301
30542
  if (additions.length === 0) return existingPath;
30302
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path64.delimiter);
30543
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path66.delimiter);
30303
30544
  }
30304
30545
 
30305
30546
  // src/agents/acp/headroom-budget-proxy.ts
@@ -30781,15 +31022,15 @@ function commonPrefixLength(a, b) {
30781
31022
 
30782
31023
  // src/agents/acp/onboarding.ts
30783
31024
  var import_child_process27 = require("child_process");
30784
- var fs60 = __toESM(require("fs"));
30785
- var os49 = __toESM(require("os"));
30786
- var path65 = __toESM(require("path"));
31025
+ var fs62 = __toESM(require("fs"));
31026
+ var os52 = __toESM(require("os"));
31027
+ var path67 = __toESM(require("path"));
30787
31028
  var _onboardingSeam = {
30788
- markerPath: (sessionId) => path65.join(os49.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
30789
- exists: (p2) => fs60.existsSync(p2),
31029
+ markerPath: (sessionId) => path67.join(os52.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
31030
+ exists: (p2) => fs62.existsSync(p2),
30790
31031
  write: (p2) => {
30791
- fs60.mkdirSync(path65.dirname(p2), { recursive: true });
30792
- fs60.writeFileSync(p2, "");
31032
+ fs62.mkdirSync(path67.dirname(p2), { recursive: true });
31033
+ fs62.writeFileSync(p2, "");
30793
31034
  },
30794
31035
  disabled: () => {
30795
31036
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -30826,7 +31067,7 @@ function resolveRepoName(cwd) {
30826
31067
  if (name) return name;
30827
31068
  }
30828
31069
  }
30829
- const base = path65.basename(cwd || "");
31070
+ const base = path67.basename(cwd || "");
30830
31071
  if (base && !isUuid(base)) return base;
30831
31072
  return "this project";
30832
31073
  }
@@ -31078,13 +31319,13 @@ var import_crypto5 = require("crypto");
31078
31319
 
31079
31320
  // src/services/turn-files/git-changeset.ts
31080
31321
  var import_child_process28 = require("child_process");
31081
- var fs62 = __toESM(require("fs/promises"));
31082
- var path67 = __toESM(require("path"));
31322
+ var fs64 = __toESM(require("fs/promises"));
31323
+ var path69 = __toESM(require("path"));
31083
31324
 
31084
31325
  // src/services/turn-files/review-ignore.ts
31085
31326
  var import_ignore2 = __toESM(require("ignore"));
31086
- var fs61 = __toESM(require("fs"));
31087
- var path66 = __toESM(require("path"));
31327
+ var fs63 = __toESM(require("fs"));
31328
+ var path68 = __toESM(require("path"));
31088
31329
  var CURATED_REVIEW_IGNORE = [
31089
31330
  // Google Cloud SDK (the incident) — installs a huge python tree.
31090
31331
  "google-cloud-sdk/",
@@ -31123,7 +31364,7 @@ var CURATED_REVIEW_IGNORE = [
31123
31364
  function makeReviewIgnore(repoRoot) {
31124
31365
  const ig = (0, import_ignore2.default)().add(CURATED_REVIEW_IGNORE);
31125
31366
  try {
31126
- const custom = fs61.readFileSync(path66.join(repoRoot, ".codeam", "reviewignore"), "utf8");
31367
+ const custom = fs63.readFileSync(path68.join(repoRoot, ".codeam", "reviewignore"), "utf8");
31127
31368
  ig.add(custom);
31128
31369
  } catch {
31129
31370
  }
@@ -31168,7 +31409,7 @@ async function collectRepoChangeset(opts) {
31168
31409
  let stats;
31169
31410
  if (!truncated && row.fileStatus === "added" && numstatEntry === void 0) {
31170
31411
  const lineCount = await readUntrackedLineCount(
31171
- path67.join(opts.repoRoot, row.filePath)
31412
+ path69.join(opts.repoRoot, row.filePath)
31172
31413
  );
31173
31414
  stats = { added: lineCount, removed: 0 };
31174
31415
  } else {
@@ -31199,7 +31440,7 @@ function readUntrackedLineCount(absPath) {
31199
31440
  }
31200
31441
  async function defaultReadUntrackedLineCount(absPath) {
31201
31442
  try {
31202
- const content = await fs62.readFile(absPath, "utf8");
31443
+ const content = await fs64.readFile(absPath, "utf8");
31203
31444
  let count = 0;
31204
31445
  let pos = -1;
31205
31446
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -31291,7 +31532,7 @@ function defaultRunGit(cwd, args2) {
31291
31532
  });
31292
31533
  }
31293
31534
  async function discoverRepos(workingDir, maxDepth = 4) {
31294
- const fs67 = await import("fs/promises");
31535
+ const fs69 = await import("fs/promises");
31295
31536
  const out2 = [];
31296
31537
  await walk(workingDir, 0);
31297
31538
  return out2;
@@ -31299,7 +31540,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
31299
31540
  if (depth > maxDepth) return;
31300
31541
  let entries = [];
31301
31542
  try {
31302
- const dirents = await fs67.readdir(dir, { withFileTypes: true });
31543
+ const dirents = await fs69.readdir(dir, { withFileTypes: true });
31303
31544
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
31304
31545
  } catch {
31305
31546
  return;
@@ -31310,8 +31551,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
31310
31551
  if (hasGit) {
31311
31552
  out2.push({
31312
31553
  repoRoot: dir,
31313
- repoPath: path67.relative(workingDir, dir),
31314
- repoName: path67.basename(dir)
31554
+ repoPath: path69.relative(workingDir, dir),
31555
+ repoName: path69.basename(dir)
31315
31556
  });
31316
31557
  return;
31317
31558
  }
@@ -31319,14 +31560,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
31319
31560
  if (!entry.isDirectory) continue;
31320
31561
  if (entry.name === "node_modules") continue;
31321
31562
  if (entry.name === "dist" || entry.name === "build") continue;
31322
- await walk(path67.join(dir, entry.name), depth + 1);
31563
+ await walk(path69.join(dir, entry.name), depth + 1);
31323
31564
  }
31324
31565
  }
31325
31566
  }
31326
31567
 
31327
31568
  // src/services/turn-files/files-outbox.ts
31328
- var fs63 = __toESM(require("fs/promises"));
31329
- var path68 = __toESM(require("path"));
31569
+ var fs65 = __toESM(require("fs/promises"));
31570
+ var path70 = __toESM(require("path"));
31330
31571
  var import_os11 = require("os");
31331
31572
  var HOME_OUTBOX_DIR = ".codeam/outbox";
31332
31573
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -31359,16 +31600,16 @@ var FilesOutbox = class {
31359
31600
  backoffIndex = 0;
31360
31601
  stopped = false;
31361
31602
  constructor(opts) {
31362
- const base = opts.baseDir ?? path68.join(homeDir(), HOME_OUTBOX_DIR);
31363
- this.filePath = path68.join(base, `${opts.sessionId}.jsonl`);
31603
+ const base = opts.baseDir ?? path70.join(homeDir(), HOME_OUTBOX_DIR);
31604
+ this.filePath = path70.join(base, `${opts.sessionId}.jsonl`);
31364
31605
  this.post = opts.post;
31365
31606
  this.autoSchedule = opts.autoSchedule !== false;
31366
31607
  }
31367
31608
  /** Persist the entry to disk and trigger a flush. Returns once the
31368
31609
  * line is durable on disk (not once the POST succeeds). */
31369
31610
  async enqueue(entry) {
31370
- await fs63.mkdir(path68.dirname(this.filePath), { recursive: true });
31371
- await fs63.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
31611
+ await fs65.mkdir(path70.dirname(this.filePath), { recursive: true });
31612
+ await fs65.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
31372
31613
  this.backoffIndex = 0;
31373
31614
  if (this.autoSchedule) this.scheduleFlush(0);
31374
31615
  }
@@ -31459,7 +31700,7 @@ var FilesOutbox = class {
31459
31700
  async readAll() {
31460
31701
  let raw = "";
31461
31702
  try {
31462
- raw = await fs63.readFile(this.filePath, "utf8");
31703
+ raw = await fs65.readFile(this.filePath, "utf8");
31463
31704
  } catch {
31464
31705
  return [];
31465
31706
  }
@@ -31483,12 +31724,12 @@ var FilesOutbox = class {
31483
31724
  async rewrite(entries) {
31484
31725
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
31485
31726
  if (entries.length === 0) {
31486
- await fs63.unlink(this.filePath).catch(() => void 0);
31727
+ await fs65.unlink(this.filePath).catch(() => void 0);
31487
31728
  return;
31488
31729
  }
31489
31730
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
31490
- await fs63.writeFile(tmpPath, payload, "utf8");
31491
- await fs63.rename(tmpPath, this.filePath);
31731
+ await fs65.writeFile(tmpPath, payload, "utf8");
31732
+ await fs65.rename(tmpPath, this.filePath);
31492
31733
  }
31493
31734
  };
31494
31735
  function applyJitter(ms) {
@@ -32237,6 +32478,13 @@ async function setModeH(ctx) {
32237
32478
  }
32238
32479
  return;
32239
32480
  }
32481
+ async function skillsConfigureH2(ctx) {
32482
+ const { cmd, relay } = ctx;
32483
+ const payload = cmd.payload;
32484
+ const res = configureSkill(payload?.action ?? "list", payload?.skillId);
32485
+ await relay.sendResult(cmd.id, res.ok ? "completed" : "failed", res);
32486
+ return;
32487
+ }
32240
32488
  async function ackEmptyH(ctx) {
32241
32489
  const { cmd, relay } = ctx;
32242
32490
  await relay.sendResult(cmd.id, "completed", {});
@@ -32504,7 +32752,8 @@ var ACP_COMMAND_HANDLERS = {
32504
32752
  request_preview_detect: previewH,
32505
32753
  preview_start: previewH,
32506
32754
  preview_stop: previewH,
32507
- save_preview_config: previewH
32755
+ save_preview_config: previewH,
32756
+ skills_configure: skillsConfigureH2
32508
32757
  };
32509
32758
  async function dispatchAcpCommand(ctx) {
32510
32759
  const handler = ACP_COMMAND_HANDLERS[ctx.cmd.type];
@@ -34430,6 +34679,26 @@ function buildMcpServersForStart(ctx) {
34430
34679
  return servers;
34431
34680
  }
34432
34681
 
34682
+ // src/skills/provision.ts
34683
+ var import_node_os12 = __toESM(require("os"));
34684
+ function provisionSkillsForStart(home = import_node_os12.default.homedir()) {
34685
+ const materialized = [];
34686
+ try {
34687
+ const manifest = readSkillsManifest();
34688
+ if (!manifest || manifest.skills.length === 0) return { materialized };
34689
+ for (const entry of manifest.skills) {
34690
+ if (!isSkillId(entry.id)) continue;
34691
+ if (materializeSkill(entry.id, home)) materialized.push(entry.id);
34692
+ }
34693
+ if (materialized.length) {
34694
+ log.info("skills", `materialized ${materialized.length} skill(s): ${materialized.join(", ")}`);
34695
+ }
34696
+ } catch (err) {
34697
+ log.warn("skills", `provisionSkillsForStart failed (best-effort): ${err instanceof Error ? err.message : String(err)}`);
34698
+ }
34699
+ return { materialized };
34700
+ }
34701
+
34433
34702
  // src/baton/baton-controller.ts
34434
34703
  var BatonController = class {
34435
34704
  constructor(deps) {
@@ -34777,7 +35046,7 @@ var AcpDriver = class {
34777
35046
  };
34778
35047
 
34779
35048
  // src/baton/transcript-mirror.ts
34780
- var fs64 = __toESM(require("fs"));
35049
+ var fs66 = __toESM(require("fs"));
34781
35050
  var TranscriptMirror = class {
34782
35051
  constructor(deps) {
34783
35052
  this.deps = deps;
@@ -34844,7 +35113,7 @@ var TranscriptMirror = class {
34844
35113
  }
34845
35114
  };
34846
35115
  function defaultWatch(file, onChange) {
34847
- const w3 = fs64.watch(file, { persistent: false }, () => onChange());
35116
+ const w3 = fs66.watch(file, { persistent: false }, () => onChange());
34848
35117
  return () => w3.close();
34849
35118
  }
34850
35119
 
@@ -35106,16 +35375,16 @@ function toEpochMs(ts) {
35106
35375
  }
35107
35376
 
35108
35377
  // src/agents/claude/onboarding.ts
35109
- var fs65 = __toESM(require("fs"));
35110
- var os50 = __toESM(require("os"));
35111
- var path69 = __toESM(require("path"));
35378
+ var fs67 = __toESM(require("fs"));
35379
+ var os54 = __toESM(require("os"));
35380
+ var path71 = __toESM(require("path"));
35112
35381
  var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
35113
35382
  function ensureClaudeOnboarded(cwd) {
35114
35383
  try {
35115
- const file = path69.join(os50.homedir(), ".claude.json");
35384
+ const file = path71.join(os54.homedir(), ".claude.json");
35116
35385
  let config = {};
35117
35386
  try {
35118
- config = JSON.parse(fs65.readFileSync(file, "utf8"));
35387
+ config = JSON.parse(fs67.readFileSync(file, "utf8"));
35119
35388
  } catch {
35120
35389
  }
35121
35390
  let changed = false;
@@ -35140,8 +35409,8 @@ function ensureClaudeOnboarded(cwd) {
35140
35409
  }
35141
35410
  }
35142
35411
  if (!changed) return;
35143
- fs65.mkdirSync(path69.dirname(file), { recursive: true });
35144
- fs65.writeFileSync(file, JSON.stringify(config, null, 2));
35412
+ fs67.mkdirSync(path71.dirname(file), { recursive: true });
35413
+ fs67.writeFileSync(file, JSON.stringify(config, null, 2));
35145
35414
  log.info(
35146
35415
  "claude",
35147
35416
  `pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
@@ -35252,6 +35521,7 @@ async function start(requestedAgent) {
35252
35521
  pluginAuthToken: session.pluginAuthToken ?? void 0,
35253
35522
  pollSecret: session.pollSecret
35254
35523
  });
35524
+ provisionSkillsForStart();
35255
35525
  const depsReady = process.env.CODESPACES === "true" ? provisionProjectDependencies(cwd).catch(() => void 0) : Promise.resolve();
35256
35526
  if (process.env.CODESPACES === "true") {
35257
35527
  const GATE_TIMEOUT_MS = 24e4;
@@ -35857,7 +36127,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
35857
36127
  var import_child_process29 = require("child_process");
35858
36128
  var import_util4 = require("util");
35859
36129
  var import_picocolors9 = __toESM(require("picocolors"));
35860
- var path70 = __toESM(require("path"));
36130
+ var path72 = __toESM(require("path"));
35861
36131
  var execFileP6 = (0, import_util4.promisify)(import_child_process29.execFile);
35862
36132
  var MAX_BUFFER = 8 * 1024 * 1024;
35863
36133
  function resetStdinForChild() {
@@ -36346,7 +36616,7 @@ var GitHubCodespacesProvider = class {
36346
36616
  });
36347
36617
  }
36348
36618
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
36349
- const remoteDir = path70.posix.dirname(remotePath);
36619
+ const remoteDir = path72.posix.dirname(remotePath);
36350
36620
  const parts = [
36351
36621
  `mkdir -p ${shellQuote(remoteDir)}`,
36352
36622
  `cat > ${shellQuote(remotePath)}`
@@ -36416,7 +36686,7 @@ function shellQuote(s) {
36416
36686
  // src/services/providers/gitpod.ts
36417
36687
  var import_child_process30 = require("child_process");
36418
36688
  var import_util5 = require("util");
36419
- var path71 = __toESM(require("path"));
36689
+ var path73 = __toESM(require("path"));
36420
36690
  var import_picocolors10 = __toESM(require("picocolors"));
36421
36691
  var execFileP7 = (0, import_util5.promisify)(import_child_process30.execFile);
36422
36692
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -36656,7 +36926,7 @@ var GitpodProvider = class {
36656
36926
  });
36657
36927
  }
36658
36928
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
36659
- const remoteDir = path71.posix.dirname(remotePath);
36929
+ const remoteDir = path73.posix.dirname(remotePath);
36660
36930
  const parts = [
36661
36931
  `mkdir -p ${shellQuote2(remoteDir)}`,
36662
36932
  `cat > ${shellQuote2(remotePath)}`
@@ -36692,7 +36962,7 @@ function shellQuote2(s) {
36692
36962
  // src/services/providers/gitlab-workspaces.ts
36693
36963
  var import_child_process31 = require("child_process");
36694
36964
  var import_util6 = require("util");
36695
- var path72 = __toESM(require("path"));
36965
+ var path74 = __toESM(require("path"));
36696
36966
  var execFileP8 = (0, import_util6.promisify)(import_child_process31.execFile);
36697
36967
  var MAX_BUFFER3 = 8 * 1024 * 1024;
36698
36968
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -36952,7 +37222,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
36952
37222
  }
36953
37223
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
36954
37224
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
36955
- const remoteDir = path72.posix.dirname(remotePath);
37225
+ const remoteDir = path74.posix.dirname(remotePath);
36956
37226
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
36957
37227
  if (options.mode != null) {
36958
37228
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -37020,7 +37290,7 @@ function shellQuote3(s) {
37020
37290
  // src/services/providers/railway.ts
37021
37291
  var import_child_process32 = require("child_process");
37022
37292
  var import_util7 = require("util");
37023
- var path73 = __toESM(require("path"));
37293
+ var path75 = __toESM(require("path"));
37024
37294
  var execFileP9 = (0, import_util7.promisify)(import_child_process32.execFile);
37025
37295
  var MAX_BUFFER4 = 8 * 1024 * 1024;
37026
37296
  function resetStdinForChild4() {
@@ -37256,7 +37526,7 @@ var RailwayProvider = class {
37256
37526
  if (!projectId || !serviceId) {
37257
37527
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
37258
37528
  }
37259
- const remoteDir = path73.posix.dirname(remotePath);
37529
+ const remoteDir = path75.posix.dirname(remotePath);
37260
37530
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
37261
37531
  if (options.mode != null) {
37262
37532
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -37902,8 +38172,8 @@ async function invite() {
37902
38172
  var import_node_dns = require("dns");
37903
38173
  var import_node_util5 = require("util");
37904
38174
  var import_node_crypto12 = require("crypto");
37905
- var fs66 = __toESM(require("fs"));
37906
- var path74 = __toESM(require("path"));
38175
+ var fs68 = __toESM(require("fs"));
38176
+ var path76 = __toESM(require("path"));
37907
38177
  var import_picocolors14 = __toESM(require("picocolors"));
37908
38178
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
37909
38179
  async function checkDns(apiBase2) {
@@ -37959,13 +38229,13 @@ async function checkHealth(apiBase2) {
37959
38229
  }
37960
38230
  }
37961
38231
  function checkConfigDir() {
37962
- const dir = path74.join(require("os").homedir(), ".codeam");
38232
+ const dir = path76.join(require("os").homedir(), ".codeam");
37963
38233
  try {
37964
- fs66.mkdirSync(dir, { recursive: true, mode: 448 });
37965
- const probe = path74.join(dir, ".doctor-probe");
37966
- fs66.writeFileSync(probe, "ok", { mode: 384 });
37967
- const read2 = fs66.readFileSync(probe, "utf8");
37968
- fs66.unlinkSync(probe);
38234
+ fs68.mkdirSync(dir, { recursive: true, mode: 448 });
38235
+ const probe = path76.join(dir, ".doctor-probe");
38236
+ fs68.writeFileSync(probe, "ok", { mode: 384 });
38237
+ const read2 = fs68.readFileSync(probe, "utf8");
38238
+ fs68.unlinkSync(probe);
37969
38239
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
37970
38240
  return {
37971
38241
  id: "config-dir",
@@ -38005,9 +38275,9 @@ function checkSessions() {
38005
38275
  }
38006
38276
  }
38007
38277
  function checkAgentBinaries() {
38008
- const os53 = createOsStrategy();
38278
+ const os57 = createOsStrategy();
38009
38279
  return getEnabledAgents().map((meta) => {
38010
- const found = os53.findInPath(meta.binaryName);
38280
+ const found = os57.findInPath(meta.binaryName);
38011
38281
  return {
38012
38282
  id: `agent-${meta.id}`,
38013
38283
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -38029,7 +38299,7 @@ function checkNodePty() {
38029
38299
  detail: "not required on this platform"
38030
38300
  };
38031
38301
  }
38032
- const vendoredPath = path74.join(__dirname, "vendor", "node-pty");
38302
+ const vendoredPath = path76.join(__dirname, "vendor", "node-pty");
38033
38303
  for (const target of [vendoredPath, "node-pty"]) {
38034
38304
  try {
38035
38305
  require(target);
@@ -38071,7 +38341,7 @@ function checkChokidar() {
38071
38341
  }
38072
38342
  async function doctor(args2 = []) {
38073
38343
  const json = args2.includes("--json");
38074
- const cliVersion = true ? "2.61.22" : "0.0.0-dev";
38344
+ const cliVersion = true ? "2.61.24" : "0.0.0-dev";
38075
38345
  const apiBase2 = resolveApiBaseUrl();
38076
38346
  const diagnosticId = (0, import_node_crypto12.randomUUID)();
38077
38347
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -38269,9 +38539,9 @@ async function completion(args2) {
38269
38539
 
38270
38540
  // src/integrations/mcp-run.ts
38271
38541
  var import_node_child_process29 = require("child_process");
38272
- var import_node_fs9 = require("fs");
38273
- var import_node_os9 = __toESM(require("os"));
38274
- var import_node_path8 = __toESM(require("path"));
38542
+ var import_node_fs11 = require("fs");
38543
+ var import_node_os13 = __toESM(require("os"));
38544
+ var import_node_path10 = __toESM(require("path"));
38275
38545
 
38276
38546
  // src/integrations/token-client.ts
38277
38547
  var REFRESH_AHEAD_MS = 5 * 60 * 1e3;
@@ -38493,13 +38763,13 @@ function commandExists(command2) {
38493
38763
  }
38494
38764
  function localBinCandidates(command2) {
38495
38765
  return [
38496
- import_node_path8.default.join(import_node_os9.default.homedir(), ".local", "bin", command2),
38497
- import_node_path8.default.join(import_node_os9.default.homedir(), ".cargo", "bin", command2)
38766
+ import_node_path10.default.join(import_node_os13.default.homedir(), ".local", "bin", command2),
38767
+ import_node_path10.default.join(import_node_os13.default.homedir(), ".cargo", "bin", command2)
38498
38768
  ];
38499
38769
  }
38500
38770
  function resolveLauncherPath(command2, deps = {
38501
38771
  commandExists,
38502
- existsSync: import_node_fs9.existsSync
38772
+ existsSync: import_node_fs11.existsSync
38503
38773
  }) {
38504
38774
  if (deps.commandExists(command2)) return command2;
38505
38775
  for (const candidate of localBinCandidates(command2)) {
@@ -38582,7 +38852,7 @@ async function mcpRun(args2) {
38582
38852
  // src/commands/version.ts
38583
38853
  var import_picocolors15 = __toESM(require("picocolors"));
38584
38854
  function version2() {
38585
- const v = true ? "2.61.22" : "unknown";
38855
+ const v = true ? "2.61.24" : "unknown";
38586
38856
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
38587
38857
  }
38588
38858
 
@@ -38731,10 +39001,10 @@ var EXIT_CODE_NAMES = {
38731
39001
  };
38732
39002
 
38733
39003
  // src/index.ts
38734
- var os52 = __toESM(require("os"));
39004
+ var os56 = __toESM(require("os"));
38735
39005
  if (!process.env.HOME) {
38736
39006
  try {
38737
- const home = os52.homedir();
39007
+ const home = os56.homedir();
38738
39008
  if (home) process.env.HOME = home;
38739
39009
  } catch {
38740
39010
  }