codeam-cli 2.32.9 → 2.33.0

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 +26 -0
  2. package/dist/index.js +1187 -424
  3. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
498
498
  // package.json
499
499
  var package_default = {
500
500
  name: "codeam-cli",
501
- version: "2.32.9",
501
+ version: "2.33.0",
502
502
  description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
503
503
  type: "commonjs",
504
504
  main: "dist/index.js",
@@ -569,6 +569,7 @@ var package_default = {
569
569
  },
570
570
  dependencies: {
571
571
  "@agentclientprotocol/claude-agent-acp": "^0.42.0",
572
+ "@beads/bd": "1.0.5",
572
573
  "@agentclientprotocol/codex-acp": "^0.0.45",
573
574
  "@agentclientprotocol/sdk": "^0.25.0",
574
575
  "@clack/prompts": "^1.2.0",
@@ -614,6 +615,12 @@ function showError(msg) {
614
615
  function showInfo(msg) {
615
616
  out(` ${import_picocolors.default.dim("\xB7")} ${msg}`);
616
617
  }
618
+ function showRelayNotice() {
619
+ out("");
620
+ out(` ${import_picocolors.default.bold(import_picocolors.default.yellow("\u26A0 This terminal is a relay \u2014 do not type here."))}`);
621
+ out(` ${import_picocolors.default.dim("Send your prompts from the CodeAgent Mobile app; replies stream in below.")}`);
622
+ out("");
623
+ }
617
624
  var BOX_INTERIOR = 30;
618
625
  var BOX_BORDER_TOP = ` \u250C${"\u2500".repeat(BOX_INTERIOR)}\u2510`;
619
626
  var BOX_BORDER_BOT = ` \u2514${"\u2500".repeat(BOX_INTERIOR)}\u2518`;
@@ -701,8 +708,8 @@ async function requestCode(pluginId) {
701
708
  });
702
709
  let timer;
703
710
  const timeoutSentinel = /* @__PURE__ */ Symbol("request-code-timeout");
704
- const timeoutPromise = new Promise((resolve6) => {
705
- timer = setTimeout(() => resolve6(timeoutSentinel), REQUEST_CODE_TIMEOUT_MS);
711
+ const timeoutPromise = new Promise((resolve7) => {
712
+ timer = setTimeout(() => resolve7(timeoutSentinel), REQUEST_CODE_TIMEOUT_MS);
706
713
  });
707
714
  const result = await Promise.race([post2, timeoutPromise]);
708
715
  clearTimeout(timer);
@@ -846,7 +853,7 @@ async function postPreviewEvent(input) {
846
853
  }
847
854
  }
848
855
  async function _postJsonAuthed(url, body, pluginAuthToken) {
849
- return new Promise((resolve6, reject) => {
856
+ return new Promise((resolve7, reject) => {
850
857
  const data = JSON.stringify(body);
851
858
  const u2 = new URL(url);
852
859
  const transport = u2.protocol === "https:" ? https : http;
@@ -878,9 +885,9 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
878
885
  return;
879
886
  }
880
887
  try {
881
- resolve6(JSON.parse(responseBody));
888
+ resolve7(JSON.parse(responseBody));
882
889
  } catch {
883
- resolve6(null);
890
+ resolve7(null);
884
891
  }
885
892
  });
886
893
  }
@@ -905,7 +912,7 @@ function makeHttpError(statusCode, retryAfterHeader, responseBody) {
905
912
  return err;
906
913
  }
907
914
  async function _postJson(url, body) {
908
- return new Promise((resolve6, reject) => {
915
+ return new Promise((resolve7, reject) => {
909
916
  const data = JSON.stringify(body);
910
917
  const u2 = new URL(url);
911
918
  const transport = u2.protocol === "https:" ? https : http;
@@ -934,9 +941,9 @@ async function _postJson(url, body) {
934
941
  return;
935
942
  }
936
943
  try {
937
- resolve6(JSON.parse(body2));
944
+ resolve7(JSON.parse(body2));
938
945
  } catch {
939
- resolve6(null);
946
+ resolve7(null);
940
947
  }
941
948
  });
942
949
  }
@@ -951,7 +958,7 @@ async function _postJson(url, body) {
951
958
  });
952
959
  }
953
960
  async function _getJson(url) {
954
- return new Promise((resolve6, reject) => {
961
+ return new Promise((resolve7, reject) => {
955
962
  const u2 = new URL(url);
956
963
  const transport = u2.protocol === "https:" ? https : http;
957
964
  const req = transport.request(
@@ -975,9 +982,9 @@ async function _getJson(url) {
975
982
  return;
976
983
  }
977
984
  try {
978
- resolve6(JSON.parse(body));
985
+ resolve7(JSON.parse(body));
979
986
  } catch {
980
- resolve6(null);
987
+ resolve7(null);
981
988
  }
982
989
  });
983
990
  }
@@ -1155,8 +1162,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
1155
1162
  return decodedFile;
1156
1163
  };
1157
1164
  }
1158
- function normalizeWindowsPath(path46) {
1159
- return path46.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1165
+ function normalizeWindowsPath(path49) {
1166
+ return path49.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1160
1167
  }
1161
1168
 
1162
1169
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3636,15 +3643,15 @@ async function addSourceContext(frames) {
3636
3643
  LRU_FILE_CONTENTS_CACHE.reduce();
3637
3644
  return frames;
3638
3645
  }
3639
- function getContextLinesFromFile(path46, ranges, output) {
3640
- return new Promise((resolve6) => {
3641
- const stream = (0, import_node_fs.createReadStream)(path46);
3646
+ function getContextLinesFromFile(path49, ranges, output) {
3647
+ return new Promise((resolve7) => {
3648
+ const stream = (0, import_node_fs.createReadStream)(path49);
3642
3649
  const lineReaded = (0, import_node_readline.createInterface)({
3643
3650
  input: stream
3644
3651
  });
3645
3652
  function destroyStreamAndResolve() {
3646
3653
  stream.destroy();
3647
- resolve6();
3654
+ resolve7();
3648
3655
  }
3649
3656
  let lineNumber = 0;
3650
3657
  let currentRangeIndex = 0;
@@ -3653,7 +3660,7 @@ function getContextLinesFromFile(path46, ranges, output) {
3653
3660
  let rangeStart = range[0];
3654
3661
  let rangeEnd = range[1];
3655
3662
  function onStreamError() {
3656
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path46, 1);
3663
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path49, 1);
3657
3664
  lineReaded.close();
3658
3665
  lineReaded.removeAllListeners();
3659
3666
  destroyStreamAndResolve();
@@ -3714,8 +3721,8 @@ function clearLineContext(frame) {
3714
3721
  delete frame.context_line;
3715
3722
  delete frame.post_context;
3716
3723
  }
3717
- function shouldSkipContextLinesForFile(path46) {
3718
- return path46.startsWith("node:") || path46.endsWith(".min.js") || path46.endsWith(".min.cjs") || path46.endsWith(".min.mjs") || path46.startsWith("data:");
3724
+ function shouldSkipContextLinesForFile(path49) {
3725
+ return path49.startsWith("node:") || path49.endsWith(".min.js") || path49.endsWith(".min.cjs") || path49.endsWith(".min.mjs") || path49.startsWith("data:");
3719
3726
  }
3720
3727
  function shouldSkipContextLinesForFrame(frame) {
3721
3728
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -4931,9 +4938,9 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
4931
4938
  if (!waitUntil) return;
4932
4939
  if (this.disabled || this.optedOut) return;
4933
4940
  if (!this._waitUntilCycle) {
4934
- let resolve6;
4941
+ let resolve7;
4935
4942
  const promise = new Promise((r) => {
4936
- resolve6 = r;
4943
+ resolve7 = r;
4937
4944
  });
4938
4945
  try {
4939
4946
  waitUntil(promise);
@@ -4941,7 +4948,7 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
4941
4948
  return;
4942
4949
  }
4943
4950
  this._waitUntilCycle = {
4944
- resolve: resolve6,
4951
+ resolve: resolve7,
4945
4952
  startedAt: Date.now(),
4946
4953
  timer: void 0
4947
4954
  };
@@ -4965,12 +4972,12 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
4965
4972
  return cycle?.resolve;
4966
4973
  }
4967
4974
  async resolveWaitUntilFlush() {
4968
- const resolve6 = this._consumeWaitUntilCycle();
4975
+ const resolve7 = this._consumeWaitUntilCycle();
4969
4976
  try {
4970
4977
  await super.flush();
4971
4978
  } catch {
4972
4979
  } finally {
4973
- resolve6?.();
4980
+ resolve7?.();
4974
4981
  }
4975
4982
  }
4976
4983
  getPersistedProperty(key) {
@@ -5062,15 +5069,15 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
5062
5069
  async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
5063
5070
  if (this.isLocalEvaluationReady()) return true;
5064
5071
  if (void 0 === this.featureFlagsPoller) return false;
5065
- return new Promise((resolve6) => {
5072
+ return new Promise((resolve7) => {
5066
5073
  const timeout = setTimeout(() => {
5067
5074
  cleanup();
5068
- resolve6(false);
5075
+ resolve7(false);
5069
5076
  }, timeoutMs);
5070
5077
  const cleanup = this._events.on("localEvaluationFlagsLoaded", (count) => {
5071
5078
  clearTimeout(timeout);
5072
5079
  cleanup();
5073
- resolve6(count > 0);
5080
+ resolve7(count > 0);
5074
5081
  });
5075
5082
  });
5076
5083
  }
@@ -5507,13 +5514,13 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
5507
5514
  this.context?.enter(data, options);
5508
5515
  }
5509
5516
  async _shutdown(shutdownTimeoutMs) {
5510
- const resolve6 = this._consumeWaitUntilCycle();
5517
+ const resolve7 = this._consumeWaitUntilCycle();
5511
5518
  await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
5512
5519
  this.errorTracking.shutdown();
5513
5520
  try {
5514
5521
  return await super._shutdown(shutdownTimeoutMs);
5515
5522
  } finally {
5516
- resolve6?.();
5523
+ resolve7?.();
5517
5524
  }
5518
5525
  }
5519
5526
  async _requestRemoteConfigPayload(flagKey) {
@@ -5869,7 +5876,7 @@ function readAnonId() {
5869
5876
  }
5870
5877
  function superProperties() {
5871
5878
  return {
5872
- cliVersion: true ? "2.32.9" : "0.0.0-dev",
5879
+ cliVersion: true ? "2.33.0" : "0.0.0-dev",
5873
5880
  nodeVersion: process.version,
5874
5881
  platform: process.platform,
5875
5882
  arch: process.arch,
@@ -7211,10 +7218,10 @@ function buildForPlatform(platform2) {
7211
7218
  var import_node_crypto4 = require("crypto");
7212
7219
 
7213
7220
  // src/agents/claude/resolver.ts
7214
- function buildClaudeLaunch(extraArgs = [], os29 = createOsStrategy()) {
7215
- const found = os29.findInPath("claude") ?? os29.findInPath("claude-code");
7221
+ function buildClaudeLaunch(extraArgs = [], os30 = createOsStrategy()) {
7222
+ const found = os30.findInPath("claude") ?? os30.findInPath("claude-code");
7216
7223
  if (!found) return null;
7217
- return os29.buildLaunch(found, extraArgs);
7224
+ return os30.buildLaunch(found, extraArgs);
7218
7225
  }
7219
7226
 
7220
7227
  // src/agents/claude/installer.ts
@@ -9170,15 +9177,15 @@ function runInstaller() {
9170
9177
  "-Command",
9171
9178
  "irm https://claude.ai/install.ps1 | iex"
9172
9179
  ] : ["-c", "curl -fsSL https://claude.ai/install.sh | bash"];
9173
- return new Promise((resolve6) => {
9180
+ return new Promise((resolve7) => {
9174
9181
  const proc = (0, import_child_process4.spawn)(cmd, args2, { stdio: "inherit" });
9175
9182
  proc.on("error", (err) => {
9176
9183
  console.error(`
9177
9184
  \u2717 Installer failed to launch: ${err.message}`);
9178
- resolve6(false);
9185
+ resolve7(false);
9179
9186
  });
9180
9187
  proc.on("exit", (code) => {
9181
- resolve6(code === 0);
9188
+ resolve7(code === 0);
9182
9189
  });
9183
9190
  });
9184
9191
  }
@@ -9355,17 +9362,17 @@ function parseUsageOutput(raw) {
9355
9362
  return { percent, resetAt };
9356
9363
  }
9357
9364
  async function fetchClaudeQuota() {
9358
- return new Promise((resolve6) => {
9365
+ return new Promise((resolve7) => {
9359
9366
  const claudeCmd = findInPath("claude") ? "claude" : "claude-code";
9360
9367
  if (!claudeCmd) {
9361
- resolve6(null);
9368
+ resolve7(null);
9362
9369
  return;
9363
9370
  }
9364
9371
  const helperPath = path11.join(os10.tmpdir(), "codeam-quota-helper.py");
9365
9372
  fs8.writeFileSync(helperPath, HELPER_SCRIPT, { mode: 420 });
9366
9373
  const python = findInPath("python3") ?? findInPath("python");
9367
9374
  if (!python) {
9368
- resolve6(null);
9375
+ resolve7(null);
9369
9376
  return;
9370
9377
  }
9371
9378
  const proc = (0, import_child_process5.spawn)(python, [helperPath, claudeCmd, "--tools", ""], {
@@ -9392,13 +9399,13 @@ async function fetchClaudeQuota() {
9392
9399
  fs8.unlinkSync(helperPath);
9393
9400
  } catch {
9394
9401
  }
9395
- resolve6(result);
9402
+ resolve7(result);
9396
9403
  }, 5e3);
9397
9404
  }, 8e3);
9398
9405
  setTimeout(() => {
9399
9406
  if (!resolved) {
9400
9407
  resolved = true;
9401
- resolve6(null);
9408
+ resolve7(null);
9402
9409
  }
9403
9410
  try {
9404
9411
  proc.kill();
@@ -9429,12 +9436,12 @@ function killActiveSpawnAndCaptureChildren() {
9429
9436
  }
9430
9437
  async function spawnAndCapture(cmd, args2, opts = {}) {
9431
9438
  const timeoutMs = opts.timeoutMs ?? 6e4;
9432
- return new Promise((resolve6) => {
9439
+ return new Promise((resolve7) => {
9433
9440
  let settled = false;
9434
9441
  const settle = (value) => {
9435
9442
  if (settled) return;
9436
9443
  settled = true;
9437
- resolve6(value);
9444
+ resolve7(value);
9438
9445
  };
9439
9446
  let child;
9440
9447
  try {
@@ -9941,13 +9948,13 @@ function detectStartupBanner(lines) {
9941
9948
  while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
9942
9949
  if (metaIdx - artStart < 2) return null;
9943
9950
  const pathLine = (lines[metaIdx + 1] ?? "").trim();
9944
- const path46 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9951
+ const path49 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9945
9952
  return {
9946
9953
  title: "",
9947
9954
  subtitle: lines[metaIdx].trim(),
9948
- path: path46,
9955
+ path: path49,
9949
9956
  startIdx: artStart,
9950
- endIdx: metaIdx + (path46 ? 1 : 0)
9957
+ endIdx: metaIdx + (path49 ? 1 : 0)
9951
9958
  };
9952
9959
  }
9953
9960
 
@@ -9957,8 +9964,8 @@ var ClaudeRuntimeStrategy = class {
9957
9964
  meta = getAgent("claude");
9958
9965
  mode = "interactive";
9959
9966
  os;
9960
- constructor(os29) {
9961
- this.os = os29;
9967
+ constructor(os30) {
9968
+ this.os = os30;
9962
9969
  }
9963
9970
  /**
9964
9971
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -10966,8 +10973,8 @@ function codexCredentialLocator() {
10966
10973
  function codexLoginLauncher() {
10967
10974
  return {
10968
10975
  async ensureInstalled() {
10969
- const os29 = createOsStrategy();
10970
- return os29.findInPath("codex") !== null;
10976
+ const os30 = createOsStrategy();
10977
+ return os30.findInPath("codex") !== null;
10971
10978
  },
10972
10979
  launch() {
10973
10980
  return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -10990,8 +10997,8 @@ var CodexRuntimeStrategy = class {
10990
10997
  meta = getAgent("codex");
10991
10998
  mode = "interactive";
10992
10999
  os;
10993
- constructor(os29) {
10994
- this.os = os29;
11000
+ constructor(os30) {
11001
+ this.os = os30;
10995
11002
  }
10996
11003
  async prepareLaunch() {
10997
11004
  let binary = this.os.findInPath("codex");
@@ -11097,16 +11104,16 @@ var CodexRuntimeStrategy = class {
11097
11104
  });
11098
11105
  }
11099
11106
  };
11100
- function resolveNpm(os29) {
11101
- return os29.id === "win32" ? "npm.cmd" : "npm";
11107
+ function resolveNpm(os30) {
11108
+ return os30.id === "win32" ? "npm.cmd" : "npm";
11102
11109
  }
11103
- async function installCodexViaNpm(os29) {
11104
- return new Promise((resolve6, reject) => {
11105
- const proc = (0, import_node_child_process4.spawn)(resolveNpm(os29), ["install", "-g", "@openai/codex"], {
11110
+ async function installCodexViaNpm(os30) {
11111
+ return new Promise((resolve7, reject) => {
11112
+ const proc = (0, import_node_child_process4.spawn)(resolveNpm(os30), ["install", "-g", "@openai/codex"], {
11106
11113
  stdio: "inherit"
11107
11114
  });
11108
11115
  proc.on("close", (code) => {
11109
- if (code === 0) resolve6();
11116
+ if (code === 0) resolve7();
11110
11117
  else reject(new Error(`npm install -g @openai/codex exited ${code}`));
11111
11118
  });
11112
11119
  proc.on("error", (err) => {
@@ -11119,16 +11126,16 @@ async function installCodexViaNpm(os29) {
11119
11126
  });
11120
11127
  });
11121
11128
  }
11122
- function augmentNpmGlobalBin(os29) {
11129
+ function augmentNpmGlobalBin(os30) {
11123
11130
  try {
11124
- const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os29), ["prefix", "-g"], {
11131
+ const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os30), ["prefix", "-g"], {
11125
11132
  stdio: ["ignore", "pipe", "ignore"]
11126
11133
  });
11127
11134
  if (result.status !== 0) return;
11128
11135
  const prefix = result.stdout.toString().trim();
11129
11136
  if (!prefix) return;
11130
- const binDir = os29.id === "win32" ? prefix : path17.join(prefix, "bin");
11131
- os29.augmentPath([binDir]);
11137
+ const binDir = os30.id === "win32" ? prefix : path17.join(prefix, "bin");
11138
+ os30.augmentPath([binDir]);
11132
11139
  } catch {
11133
11140
  }
11134
11141
  }
@@ -11212,25 +11219,25 @@ var import_node_child_process7 = require("child_process");
11212
11219
  // src/agents/coderabbit/installer.ts
11213
11220
  var import_node_child_process5 = require("child_process");
11214
11221
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
11215
- async function ensureCoderabbitInstalled(os29) {
11216
- if (os29.findInPath("coderabbit")) return true;
11217
- if (os29.id === "win32") {
11222
+ async function ensureCoderabbitInstalled(os30) {
11223
+ if (os30.findInPath("coderabbit")) return true;
11224
+ if (os30.id === "win32") {
11218
11225
  console.error(
11219
11226
  "\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"
11220
11227
  );
11221
11228
  return false;
11222
11229
  }
11223
11230
  console.log("\n CodeRabbit CLI not found \u2014 installing via the official script\u2026\n");
11224
- const ok = await new Promise((resolve6) => {
11231
+ const ok = await new Promise((resolve7) => {
11225
11232
  const proc = (0, import_node_child_process5.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL} | sh`], {
11226
11233
  stdio: "inherit"
11227
11234
  });
11228
- proc.on("close", (code) => resolve6(code === 0));
11229
- proc.on("error", () => resolve6(false));
11235
+ proc.on("close", (code) => resolve7(code === 0));
11236
+ proc.on("error", () => resolve7(false));
11230
11237
  });
11231
11238
  if (!ok) return false;
11232
- os29.augmentPath([`${os29.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11233
- return os29.findInPath("coderabbit") !== null;
11239
+ os30.augmentPath([`${os30.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11240
+ return os30.findInPath("coderabbit") !== null;
11234
11241
  }
11235
11242
 
11236
11243
  // src/agents/coderabbit/link.ts
@@ -11257,10 +11264,10 @@ function coderabbitCredentialLocator() {
11257
11264
  extract: extractLocalCoderabbitToken
11258
11265
  };
11259
11266
  }
11260
- function coderabbitLoginLauncher(os29) {
11267
+ function coderabbitLoginLauncher(os30) {
11261
11268
  return {
11262
11269
  async ensureInstalled() {
11263
- return ensureCoderabbitInstalled(os29);
11270
+ return ensureCoderabbitInstalled(os30);
11264
11271
  },
11265
11272
  launch() {
11266
11273
  return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
@@ -11283,11 +11290,11 @@ function parseReview(stdout) {
11283
11290
  for (const line of lines) {
11284
11291
  const m = line.match(HUNK_LINE_RE);
11285
11292
  if (!m) continue;
11286
- const [, path46, lineNo, sevToken, message] = m;
11287
- if (!path46 || !lineNo || !message) continue;
11293
+ const [, path49, lineNo, sevToken, message] = m;
11294
+ if (!path49 || !lineNo || !message) continue;
11288
11295
  const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
11289
11296
  hunks.push({
11290
- path: path46.trim(),
11297
+ path: path49.trim(),
11291
11298
  line: Number(lineNo),
11292
11299
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
11293
11300
  message: cleanedMessage
@@ -11306,8 +11313,8 @@ var CoderabbitRuntimeStrategy = class {
11306
11313
  meta = getAgent("coderabbit");
11307
11314
  mode = "batch";
11308
11315
  os;
11309
- constructor(os29) {
11310
- this.os = os29;
11316
+ constructor(os30) {
11317
+ this.os = os30;
11311
11318
  }
11312
11319
  getDefaultArgs() {
11313
11320
  return ["review"];
@@ -11345,7 +11352,7 @@ var CoderabbitRuntimeStrategy = class {
11345
11352
  }
11346
11353
  async runOneShot(input) {
11347
11354
  const launch = await this.prepareInvocation(input);
11348
- return new Promise((resolve6, reject) => {
11355
+ return new Promise((resolve7, reject) => {
11349
11356
  const stdoutBuf = [];
11350
11357
  const stderrBuf = [];
11351
11358
  const proc = (0, import_node_child_process7.spawn)(launch.cmd, launch.args, {
@@ -11356,7 +11363,7 @@ var CoderabbitRuntimeStrategy = class {
11356
11363
  proc.stderr?.on("data", (b) => stderrBuf.push(b));
11357
11364
  proc.on("error", (err) => reject(err));
11358
11365
  proc.on("close", (code) => {
11359
- resolve6(
11366
+ resolve7(
11360
11367
  this.parseOutput({
11361
11368
  exitCode: code ?? 0,
11362
11369
  stdout: Buffer.concat(stdoutBuf).toString("utf8"),
@@ -11422,10 +11429,10 @@ function cursorCredentialLocator() {
11422
11429
  extract: extractLocalCursorToken
11423
11430
  };
11424
11431
  }
11425
- function cursorLoginLauncher(os29) {
11432
+ function cursorLoginLauncher(os30) {
11426
11433
  return {
11427
11434
  async ensureInstalled() {
11428
- if (os29.findInPath("cursor-agent")) return true;
11435
+ if (os30.findInPath("cursor-agent")) return true;
11429
11436
  console.error(
11430
11437
  "\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"
11431
11438
  );
@@ -11487,8 +11494,8 @@ var CursorRuntimeStrategy = class {
11487
11494
  meta = getAgent("cursor");
11488
11495
  mode = "interactive";
11489
11496
  os;
11490
- constructor(os29) {
11491
- this.os = os29;
11497
+ constructor(os30) {
11498
+ this.os = os30;
11492
11499
  }
11493
11500
  async prepareLaunch() {
11494
11501
  const binary = this.os.findInPath("cursor-agent");
@@ -11608,10 +11615,10 @@ function aiderCredentialLocator() {
11608
11615
  extract: extractLocalAiderToken
11609
11616
  };
11610
11617
  }
11611
- function aiderLoginLauncher(os29) {
11618
+ function aiderLoginLauncher(os30) {
11612
11619
  return {
11613
11620
  async ensureInstalled() {
11614
- if (os29.findInPath("aider")) return true;
11621
+ if (os30.findInPath("aider")) return true;
11615
11622
  console.error(
11616
11623
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
11617
11624
  );
@@ -11621,7 +11628,7 @@ function aiderLoginLauncher(os29) {
11621
11628
  console.error(
11622
11629
  "\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"
11623
11630
  );
11624
- return (0, import_node_child_process9.spawn)(os29.id === "win32" ? "cmd.exe" : "sh", os29.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11631
+ return (0, import_node_child_process9.spawn)(os30.id === "win32" ? "cmd.exe" : "sh", os30.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11625
11632
  stdio: "ignore"
11626
11633
  });
11627
11634
  }
@@ -11693,8 +11700,8 @@ var AiderRuntimeStrategy = class {
11693
11700
  meta = getAgent("aider");
11694
11701
  mode = "interactive";
11695
11702
  os;
11696
- constructor(os29) {
11697
- this.os = os29;
11703
+ constructor(os30) {
11704
+ this.os = os30;
11698
11705
  }
11699
11706
  async prepareLaunch() {
11700
11707
  const binary = this.os.findInPath("aider");
@@ -11823,8 +11830,8 @@ function geminiCredentialLocator() {
11823
11830
  function geminiLoginLauncher() {
11824
11831
  return {
11825
11832
  async ensureInstalled() {
11826
- const os29 = createOsStrategy();
11827
- return os29.findInPath("gemini") !== null;
11833
+ const os30 = createOsStrategy();
11834
+ return os30.findInPath("gemini") !== null;
11828
11835
  },
11829
11836
  launch() {
11830
11837
  return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -11857,8 +11864,8 @@ var GeminiRuntimeStrategy = class {
11857
11864
  meta = getAgent("gemini");
11858
11865
  mode = "interactive";
11859
11866
  os;
11860
- constructor(os29) {
11861
- this.os = os29;
11867
+ constructor(os30) {
11868
+ this.os = os30;
11862
11869
  }
11863
11870
  async prepareLaunch() {
11864
11871
  const binary = this.os.findInPath("gemini");
@@ -11958,18 +11965,18 @@ var GeminiRuntimeStrategy = class {
11958
11965
 
11959
11966
  // src/agents/registry.ts
11960
11967
  var runtimeBuilders = {
11961
- claude: (os29) => new ClaudeRuntimeStrategy(os29),
11962
- codex: (os29) => new CodexRuntimeStrategy(os29),
11963
- coderabbit: (os29) => new CoderabbitRuntimeStrategy(os29),
11964
- cursor: (os29) => new CursorRuntimeStrategy(os29),
11965
- aider: (os29) => new AiderRuntimeStrategy(os29),
11966
- gemini: (os29) => new GeminiRuntimeStrategy(os29)
11968
+ claude: (os30) => new ClaudeRuntimeStrategy(os30),
11969
+ codex: (os30) => new CodexRuntimeStrategy(os30),
11970
+ coderabbit: (os30) => new CoderabbitRuntimeStrategy(os30),
11971
+ cursor: (os30) => new CursorRuntimeStrategy(os30),
11972
+ aider: (os30) => new AiderRuntimeStrategy(os30),
11973
+ gemini: (os30) => new GeminiRuntimeStrategy(os30)
11967
11974
  };
11968
11975
  var deployBuilders = {
11969
11976
  claude: () => new ClaudeDeployStrategy(),
11970
11977
  codex: () => new CodexDeployStrategy()
11971
11978
  };
11972
- function createAgentStrategy(agent, os29 = createOsStrategy()) {
11979
+ function createAgentStrategy(agent, os30 = createOsStrategy()) {
11973
11980
  if (!AGENT_REGISTRY[agent]?.enabled) {
11974
11981
  throw new Error(
11975
11982
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -11979,10 +11986,10 @@ function createAgentStrategy(agent, os29 = createOsStrategy()) {
11979
11986
  if (!build) {
11980
11987
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
11981
11988
  }
11982
- return build(os29);
11989
+ return build(os30);
11983
11990
  }
11984
- function createInteractiveAgentStrategy(agent, os29 = createOsStrategy()) {
11985
- const s = createAgentStrategy(agent, os29);
11991
+ function createInteractiveAgentStrategy(agent, os30 = createOsStrategy()) {
11992
+ const s = createAgentStrategy(agent, os30);
11986
11993
  if (s.mode !== "interactive") {
11987
11994
  throw new Error(
11988
11995
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -14262,8 +14269,8 @@ var Connection = class {
14262
14269
  this.requestHandler = requestHandler;
14263
14270
  this.notificationHandler = notificationHandler;
14264
14271
  this.stream = stream;
14265
- this.closedPromise = new Promise((resolve6) => {
14266
- this.abortController.signal.addEventListener("abort", () => resolve6());
14272
+ this.closedPromise = new Promise((resolve7) => {
14273
+ this.abortController.signal.addEventListener("abort", () => resolve7());
14267
14274
  });
14268
14275
  void this.receive();
14269
14276
  }
@@ -14433,11 +14440,11 @@ var Connection = class {
14433
14440
  return rejectedPromise(this.closedReason());
14434
14441
  }
14435
14442
  const id = this.nextRequestId++;
14436
- const responsePromise = new Promise((resolve6, reject) => {
14443
+ const responsePromise = new Promise((resolve7, reject) => {
14437
14444
  this.pendingResponses.set(id, {
14438
14445
  resolve: (response) => {
14439
14446
  try {
14440
- resolve6(mapResponse ? mapResponse(response) : response);
14447
+ resolve7(mapResponse ? mapResponse(response) : response);
14441
14448
  } catch (error) {
14442
14449
  reject(error);
14443
14450
  }
@@ -14758,17 +14765,17 @@ var AcpClient = class {
14758
14765
  this.sessionId = null;
14759
14766
  try {
14760
14767
  child.kill("SIGTERM");
14761
- const grace = new Promise((resolve6) => {
14768
+ const grace = new Promise((resolve7) => {
14762
14769
  const t2 = setTimeout(() => {
14763
14770
  try {
14764
14771
  child.kill("SIGKILL");
14765
14772
  } catch {
14766
14773
  }
14767
- resolve6();
14774
+ resolve7();
14768
14775
  }, 2e3);
14769
14776
  child.once("exit", () => {
14770
14777
  clearTimeout(t2);
14771
- resolve6();
14778
+ resolve7();
14772
14779
  });
14773
14780
  });
14774
14781
  await grace;
@@ -14906,7 +14913,7 @@ var _transport2 = {
14906
14913
  get: _get
14907
14914
  };
14908
14915
  function _post(url, headers, payload) {
14909
- return new Promise((resolve6, reject) => {
14916
+ return new Promise((resolve7, reject) => {
14910
14917
  let settled = false;
14911
14918
  const u2 = new URL(url);
14912
14919
  const lib = u2.protocol === "https:" ? https3 : http3;
@@ -14931,7 +14938,7 @@ function _post(url, headers, payload) {
14931
14938
  res.on("end", () => {
14932
14939
  if (settled) return;
14933
14940
  settled = true;
14934
- resolve6({ statusCode: res.statusCode ?? 0, body });
14941
+ resolve7({ statusCode: res.statusCode ?? 0, body });
14935
14942
  });
14936
14943
  }
14937
14944
  );
@@ -14948,7 +14955,7 @@ function _post(url, headers, payload) {
14948
14955
  });
14949
14956
  }
14950
14957
  function _get(url, headers) {
14951
- return new Promise((resolve6, reject) => {
14958
+ return new Promise((resolve7, reject) => {
14952
14959
  let settled = false;
14953
14960
  const u2 = new URL(url);
14954
14961
  const lib = u2.protocol === "https:" ? https3 : http3;
@@ -14972,7 +14979,7 @@ function _get(url, headers) {
14972
14979
  res.on("end", () => {
14973
14980
  if (settled) return;
14974
14981
  settled = true;
14975
- resolve6({ statusCode: res.statusCode ?? 0, body });
14982
+ resolve7({ statusCode: res.statusCode ?? 0, body });
14976
14983
  });
14977
14984
  }
14978
14985
  );
@@ -15681,11 +15688,11 @@ function extractSelectPrompt(text) {
15681
15688
  }
15682
15689
 
15683
15690
  // src/commands/start/handlers.ts
15684
- var fs29 = __toESM(require("fs"));
15685
- var os24 = __toESM(require("os"));
15686
- var path35 = __toESM(require("path"));
15691
+ var fs31 = __toESM(require("fs"));
15692
+ var os25 = __toESM(require("os"));
15693
+ var path38 = __toESM(require("path"));
15687
15694
  var import_crypto3 = require("crypto");
15688
- var import_child_process12 = require("child_process");
15695
+ var import_child_process15 = require("child_process");
15689
15696
 
15690
15697
  // src/lib/payload.ts
15691
15698
  var import_zod = require("zod");
@@ -16338,12 +16345,12 @@ async function applyFileReview(workingDir, filePath, action) {
16338
16345
  return { ok: true, action, filePath, repoRoot };
16339
16346
  }
16340
16347
  function runGit(cwd, args2) {
16341
- return new Promise((resolve6) => {
16348
+ return new Promise((resolve7) => {
16342
16349
  let proc;
16343
16350
  try {
16344
16351
  proc = (0, import_child_process10.spawn)("git", args2, { cwd, env: process.env });
16345
16352
  } catch (err) {
16346
- resolve6({ ok: false, code: -1, stdout: "", stderr: err.message });
16353
+ resolve7({ ok: false, code: -1, stdout: "", stderr: err.message });
16347
16354
  return;
16348
16355
  }
16349
16356
  let stdout = "";
@@ -16356,11 +16363,11 @@ function runGit(cwd, args2) {
16356
16363
  });
16357
16364
  proc.on(
16358
16365
  "error",
16359
- (err) => resolve6({ ok: false, code: -1, stdout, stderr: stderr + err.message })
16366
+ (err) => resolve7({ ok: false, code: -1, stdout, stderr: stderr + err.message })
16360
16367
  );
16361
16368
  proc.on(
16362
16369
  "close",
16363
- (code) => resolve6({ ok: code === 0, code: code ?? -1, stdout, stderr })
16370
+ (code) => resolve7({ ok: code === 0, code: code ?? -1, stdout, stderr })
16364
16371
  );
16365
16372
  });
16366
16373
  }
@@ -16619,7 +16626,7 @@ async function link(args2 = []) {
16619
16626
  waitSpin.start(waitMsg());
16620
16627
  const countdown = setInterval(() => waitSpin.message(waitMsg()), 1e3);
16621
16628
  countdown.unref?.();
16622
- const paired = await new Promise((resolve6, reject) => {
16629
+ const paired = await new Promise((resolve7, reject) => {
16623
16630
  let stopPoll = null;
16624
16631
  const sigint = () => {
16625
16632
  clearInterval(countdown);
@@ -16632,7 +16639,7 @@ async function link(args2 = []) {
16632
16639
  process.removeListener("SIGINT", sigint);
16633
16640
  clearInterval(countdown);
16634
16641
  waitSpin.stop("Paired");
16635
- resolve6(info);
16642
+ resolve7(info);
16636
16643
  },
16637
16644
  () => {
16638
16645
  clearInterval(countdown);
@@ -16767,14 +16774,14 @@ async function captureFreshCredentials(ctx) {
16767
16774
  }
16768
16775
  };
16769
16776
  try {
16770
- const token = await new Promise((resolve6, reject) => {
16777
+ const token = await new Promise((resolve7, reject) => {
16771
16778
  let settled = false;
16772
16779
  const tryExtract = async () => {
16773
16780
  if (settled) return;
16774
16781
  const t2 = await ctx.locator.extract();
16775
16782
  if (t2 && !settled) {
16776
16783
  settled = true;
16777
- resolve6(t2);
16784
+ resolve7(t2);
16778
16785
  }
16779
16786
  };
16780
16787
  watcher.on("add", () => void tryExtract());
@@ -17172,12 +17179,758 @@ function activePreviewSessionIds() {
17172
17179
  return Array.from(activePreviews.keys());
17173
17180
  }
17174
17181
 
17182
+ // src/beads/bd-adapter.ts
17183
+ var import_child_process12 = require("child_process");
17184
+ var fs29 = __toESM(require("fs"));
17185
+ var os24 = __toESM(require("os"));
17186
+ var path35 = __toESM(require("path"));
17187
+ var BD_PACKAGE = "@beads/bd";
17188
+ function resolveBundledBdBinary() {
17189
+ return _resolveSeam.resolveBundled();
17190
+ }
17191
+ function _defaultResolveBundled() {
17192
+ let pkgJsonPath;
17193
+ try {
17194
+ pkgJsonPath = require.resolve(`${BD_PACKAGE}/package.json`);
17195
+ } catch {
17196
+ return null;
17197
+ }
17198
+ const binDir = path35.join(path35.dirname(pkgJsonPath), "bin");
17199
+ const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
17200
+ const binaryPath = path35.join(binDir, binaryName);
17201
+ try {
17202
+ fs29.accessSync(binaryPath, fs29.constants.F_OK);
17203
+ return binaryPath;
17204
+ } catch {
17205
+ return null;
17206
+ }
17207
+ }
17208
+ function resolveBdOnPath() {
17209
+ return _resolveSeam.resolveOnPath();
17210
+ }
17211
+ function _defaultResolveOnPath() {
17212
+ const dirs = (process.env.PATH ?? "").split(path35.delimiter).filter(Boolean);
17213
+ const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
17214
+ for (const dir of dirs) {
17215
+ for (const candidate of candidates) {
17216
+ const full = path35.join(dir, candidate);
17217
+ try {
17218
+ fs29.accessSync(full, fs29.constants.F_OK);
17219
+ return full;
17220
+ } catch {
17221
+ }
17222
+ }
17223
+ }
17224
+ return null;
17225
+ }
17226
+ var _resolveSeam = {
17227
+ resolveBundled: _defaultResolveBundled,
17228
+ resolveOnPath: _defaultResolveOnPath
17229
+ };
17230
+ var _spawnSeam = {
17231
+ run: _defaultSpawn
17232
+ };
17233
+ function _defaultSpawn(binaryPath, args2, opts) {
17234
+ return new Promise((resolve7) => {
17235
+ let proc;
17236
+ try {
17237
+ proc = (0, import_child_process12.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
17238
+ } catch (err) {
17239
+ resolve7({ code: -1, stdout: "", stderr: err.message });
17240
+ return;
17241
+ }
17242
+ let stdout = "";
17243
+ let stderr = "";
17244
+ proc.stdout?.on("data", (c2) => {
17245
+ stdout += c2.toString();
17246
+ });
17247
+ proc.stderr?.on("data", (c2) => {
17248
+ stderr += c2.toString();
17249
+ });
17250
+ proc.on("error", (err) => resolve7({ code: -1, stdout, stderr: err.message }));
17251
+ proc.on("close", (code) => resolve7({ code: code ?? -1, stdout, stderr }));
17252
+ });
17253
+ }
17254
+ var BdAdapter = class {
17255
+ constructor(opts = {}) {
17256
+ this.opts = opts;
17257
+ this.resolved = opts.binaryPath ?? null;
17258
+ }
17259
+ opts;
17260
+ resolved;
17261
+ /**
17262
+ * Resolve the bd binary lazily, caching the result. Order:
17263
+ * bundled @beads/bd → PATH. Returns null when neither is available — the
17264
+ * caller offers the consented installer (`install-bd.ts`).
17265
+ */
17266
+ resolveBinary() {
17267
+ if (this.resolved) return this.resolved;
17268
+ const bundled = resolveBundledBdBinary();
17269
+ if (bundled) {
17270
+ this.resolved = bundled;
17271
+ return bundled;
17272
+ }
17273
+ const onPath = resolveBdOnPath();
17274
+ if (onPath) {
17275
+ this.resolved = onPath;
17276
+ return onPath;
17277
+ }
17278
+ return null;
17279
+ }
17280
+ /** True when a bd binary is resolvable without installing. */
17281
+ isAvailable() {
17282
+ return this.resolveBinary() !== null;
17283
+ }
17284
+ /**
17285
+ * Run an arbitrary bd subcommand. Always injects `--global` (the home brain)
17286
+ * unless a `beadsDir` override is set, in which case `BEADS_DIR` redirects bd
17287
+ * to that dir instead (tests). Returns the raw result; callers decide how to
17288
+ * interpret exit codes (e.g. `bd setup --check` uses 0/nonzero).
17289
+ */
17290
+ async run(args2) {
17291
+ const binary = this.resolveBinary();
17292
+ if (!binary) {
17293
+ return { code: -1, stdout: "", stderr: "bd binary not resolved" };
17294
+ }
17295
+ const env = { ...process.env };
17296
+ const finalArgs = [...args2];
17297
+ if (this.opts.beadsDir) {
17298
+ env.BEADS_DIR = this.opts.beadsDir;
17299
+ } else if (!finalArgs.includes("--global")) {
17300
+ finalArgs.push("--global");
17301
+ }
17302
+ log.trace("beads", `bd ${finalArgs.join(" ")}`);
17303
+ return _spawnSeam.run(binary, finalArgs, { cwd: this.opts.cwd, env });
17304
+ }
17305
+ /**
17306
+ * `bd ready --json` → typed issue array. `bd list --json` shares the shape,
17307
+ * so `listIssues` reuses the same parser. Bad JSON / non-zero exit → [].
17308
+ */
17309
+ async readyIssues(projectKey) {
17310
+ const res = await this.run(["ready", "--json"]);
17311
+ return parseIssues(res, projectKey);
17312
+ }
17313
+ async listIssues(projectKey) {
17314
+ const res = await this.run(["list", "--json"]);
17315
+ return parseIssues(res, projectKey);
17316
+ }
17317
+ /** `bd status --json` → summary block, or null on failure. */
17318
+ async statusSummary() {
17319
+ const res = await this.run(["status", "--json"]);
17320
+ if (res.code !== 0) return null;
17321
+ try {
17322
+ const parsed = JSON.parse(res.stdout);
17323
+ return parsed.summary ?? null;
17324
+ } catch {
17325
+ return null;
17326
+ }
17327
+ }
17328
+ };
17329
+ var VALID_STATUS = /* @__PURE__ */ new Set([
17330
+ "open",
17331
+ "in_progress",
17332
+ "blocked",
17333
+ "closed"
17334
+ ]);
17335
+ function parseIssues(res, projectKey) {
17336
+ if (res.code !== 0) return [];
17337
+ let parsed;
17338
+ try {
17339
+ parsed = JSON.parse(res.stdout);
17340
+ } catch {
17341
+ return [];
17342
+ }
17343
+ if (!Array.isArray(parsed)) return [];
17344
+ const out2 = [];
17345
+ for (const row of parsed) {
17346
+ const issue = coerceIssue(row, projectKey);
17347
+ if (issue) out2.push(issue);
17348
+ }
17349
+ return out2;
17350
+ }
17351
+ function coerceIssue(row, projectKey) {
17352
+ if (typeof row !== "object" || row === null) return null;
17353
+ const r = row;
17354
+ if (typeof r.id !== "string" || typeof r.title !== "string") return null;
17355
+ const status2 = typeof r.status === "string" && VALID_STATUS.has(r.status) ? r.status : "open";
17356
+ return {
17357
+ id: r.id,
17358
+ title: r.title,
17359
+ status: status2,
17360
+ priority: typeof r.priority === "number" ? r.priority : null,
17361
+ issue_type: typeof r.issue_type === "string" ? r.issue_type : "task",
17362
+ owner: typeof r.owner === "string" && r.owner.length > 0 ? r.owner : null,
17363
+ created_at: typeof r.created_at === "string" ? r.created_at : "",
17364
+ updated_at: typeof r.updated_at === "string" ? r.updated_at : "",
17365
+ dependency_count: typeof r.dependency_count === "number" ? r.dependency_count : void 0,
17366
+ dependent_count: typeof r.dependent_count === "number" ? r.dependent_count : void 0,
17367
+ comment_count: typeof r.comment_count === "number" ? r.comment_count : void 0,
17368
+ projectKey
17369
+ };
17370
+ }
17371
+ function defaultBeadsHomeDir() {
17372
+ return path35.join(os24.homedir(), ".beads");
17373
+ }
17374
+
17375
+ // src/beads/bootstrap.ts
17376
+ var SETUP_RECIPE = {
17377
+ claude: "claude",
17378
+ codex: "codex",
17379
+ cursor: "cursor",
17380
+ gemini: "gemini",
17381
+ aider: "aider",
17382
+ copilot: "copilot"
17383
+ };
17384
+ async function bootstrapBeads(opts) {
17385
+ const bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
17386
+ const result = {
17387
+ bdAvailable: false,
17388
+ serverUp: false,
17389
+ agentsConfigured: [],
17390
+ exportEnabled: false
17391
+ };
17392
+ if (!bd.isAvailable()) {
17393
+ log.warn("beads", "bd binary unavailable \u2014 skipping bootstrap");
17394
+ return result;
17395
+ }
17396
+ result.bdAvailable = true;
17397
+ result.serverUp = await ensureServer(bd);
17398
+ if (!result.serverUp) {
17399
+ log.warn("beads", "dolt sql-server not up after start \u2014 skipping wiring this run");
17400
+ return result;
17401
+ }
17402
+ for (const agent of opts.agents) {
17403
+ const recipe = SETUP_RECIPE[agent];
17404
+ if (!recipe) {
17405
+ log.trace("beads", `no bd setup recipe for agent ${agent} \u2014 skipping`);
17406
+ continue;
17407
+ }
17408
+ const applied = await ensureRecipe(bd, recipe);
17409
+ if (applied) result.agentsConfigured.push(agent);
17410
+ }
17411
+ result.exportEnabled = await ensureAutoExport(bd);
17412
+ log.info(
17413
+ "beads",
17414
+ `bootstrap done server=${result.serverUp} agents=[${result.agentsConfigured.join(",")}] export=${result.exportEnabled}`
17415
+ );
17416
+ return result;
17417
+ }
17418
+ async function ensureServer(bd) {
17419
+ const status2 = await bd.run(["dolt", "status"]);
17420
+ if (status2.code === 0) {
17421
+ log.trace("beads", "dolt sql-server already running");
17422
+ return true;
17423
+ }
17424
+ log.info("beads", "dolt sql-server down \u2014 starting detached");
17425
+ const start2 = await bd.run(["dolt", "start"]);
17426
+ if (start2.code !== 0) {
17427
+ log.warn("beads", `bd dolt start failed (code=${start2.code}): ${start2.stderr.slice(0, 200)}`);
17428
+ return false;
17429
+ }
17430
+ const recheck = await bd.run(["dolt", "status"]);
17431
+ return recheck.code === 0;
17432
+ }
17433
+ async function ensureRecipe(bd, recipe) {
17434
+ const check = await bd.run(["setup", recipe, "--check"]);
17435
+ if (check.code === 0) {
17436
+ log.trace("beads", `recipe ${recipe} already configured`);
17437
+ return false;
17438
+ }
17439
+ const setup = await bd.run(["setup", recipe]);
17440
+ if (setup.code !== 0) {
17441
+ log.warn("beads", `bd setup ${recipe} failed (code=${setup.code})`);
17442
+ return false;
17443
+ }
17444
+ log.info("beads", `configured agent recipe: ${recipe}`);
17445
+ return true;
17446
+ }
17447
+ async function ensureAutoExport(bd) {
17448
+ const res = await bd.run(["config", "set", "export.jsonl", "true"]);
17449
+ return res.code === 0;
17450
+ }
17451
+
17452
+ // src/beads/watcher.ts
17453
+ var crypto3 = __toESM(require("crypto"));
17454
+ var path37 = __toESM(require("path"));
17455
+
17456
+ // src/beads/project-key.ts
17457
+ var import_child_process13 = require("child_process");
17458
+ var crypto2 = __toESM(require("crypto"));
17459
+ var fs30 = __toESM(require("fs"));
17460
+ var path36 = __toESM(require("path"));
17461
+ function normalizeOrigin(raw) {
17462
+ const trimmed = raw.trim();
17463
+ if (!trimmed) return null;
17464
+ let host;
17465
+ let pathPart;
17466
+ const scpLike = /^[^/@]+@([^:]+):(.+)$/.exec(trimmed);
17467
+ if (scpLike && !trimmed.includes("://")) {
17468
+ host = scpLike[1];
17469
+ pathPart = scpLike[2];
17470
+ } else {
17471
+ let url;
17472
+ try {
17473
+ url = new URL(trimmed);
17474
+ } catch {
17475
+ return null;
17476
+ }
17477
+ host = url.hostname;
17478
+ pathPart = url.pathname;
17479
+ }
17480
+ host = host.toLowerCase();
17481
+ pathPart = pathPart.replace(/^\/+/, "").replace(/\.git$/i, "").replace(/\/+$/, "");
17482
+ if (!host || !pathPart) return null;
17483
+ return `${host}/${pathPart}`;
17484
+ }
17485
+ function findRepoRoot(cwd) {
17486
+ let dir = path36.resolve(cwd);
17487
+ const seen = /* @__PURE__ */ new Set();
17488
+ for (let i = 0; i < 256; i++) {
17489
+ if (seen.has(dir)) return null;
17490
+ seen.add(dir);
17491
+ try {
17492
+ const stat3 = fs30.statSync(path36.join(dir, ".git"), { throwIfNoEntry: false });
17493
+ if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
17494
+ } catch {
17495
+ }
17496
+ const parent = path36.dirname(dir);
17497
+ if (parent === dir) return null;
17498
+ dir = parent;
17499
+ }
17500
+ return null;
17501
+ }
17502
+ var _execSeam2 = {
17503
+ exec: (file, args2, opts) => {
17504
+ const out2 = (0, import_child_process13.execFileSync)(file, args2, opts);
17505
+ return typeof out2 === "string" ? out2 : out2.toString("utf8");
17506
+ },
17507
+ realpath: (p2) => fs30.realpathSync(p2)
17508
+ };
17509
+ function readOrigin(cwd) {
17510
+ try {
17511
+ const raw = _execSeam2.exec("git", ["remote", "get-url", "origin"], {
17512
+ cwd,
17513
+ timeout: 1e3,
17514
+ stdio: ["ignore", "pipe", "ignore"],
17515
+ encoding: "utf8"
17516
+ });
17517
+ return raw.trim() || null;
17518
+ } catch {
17519
+ return null;
17520
+ }
17521
+ }
17522
+ function deriveProjectIdentity(cwd = process.cwd()) {
17523
+ const repoRoot = findRepoRoot(cwd) ?? cwd;
17524
+ const origin = readOrigin(repoRoot);
17525
+ const normalized = origin ? normalizeOrigin(origin) : null;
17526
+ if (normalized) {
17527
+ const label = normalized.split("/").pop() || normalized;
17528
+ return { projectKey: normalized, projectLabel: label };
17529
+ }
17530
+ let real = repoRoot;
17531
+ try {
17532
+ real = _execSeam2.realpath(repoRoot);
17533
+ } catch {
17534
+ }
17535
+ const hash = crypto2.createHash("sha256").update(real).digest("hex");
17536
+ return { projectKey: `path:${hash}`, projectLabel: path36.basename(real) || "project" };
17537
+ }
17538
+
17539
+ // src/services/file-watcher/transport.ts
17540
+ var http5 = __toESM(require("http"));
17541
+ var https5 = __toESM(require("https"));
17542
+ var _transport3 = {
17543
+ post: _post2
17544
+ };
17545
+ function _post2(url, headers, payload) {
17546
+ return new Promise((resolve7, reject) => {
17547
+ let settled = false;
17548
+ const u2 = new URL(url);
17549
+ const lib = u2.protocol === "https:" ? https5 : http5;
17550
+ const req = lib.request(
17551
+ {
17552
+ hostname: u2.hostname,
17553
+ port: u2.port || (u2.protocol === "https:" ? 443 : 80),
17554
+ path: u2.pathname + u2.search,
17555
+ method: "POST",
17556
+ headers: {
17557
+ ...headers,
17558
+ ...vercelBypassHeader(),
17559
+ "Content-Length": Buffer.byteLength(payload)
17560
+ },
17561
+ timeout: 8e3
17562
+ },
17563
+ (res) => {
17564
+ let body = "";
17565
+ res.on("data", (c2) => {
17566
+ body += c2.toString();
17567
+ });
17568
+ res.on("end", () => {
17569
+ if (settled) return;
17570
+ settled = true;
17571
+ resolve7({ statusCode: res.statusCode ?? 0, body });
17572
+ });
17573
+ }
17574
+ );
17575
+ req.on("error", (err) => {
17576
+ if (settled) return;
17577
+ settled = true;
17578
+ reject(err);
17579
+ });
17580
+ req.on("timeout", () => {
17581
+ req.destroy();
17582
+ });
17583
+ req.write(payload);
17584
+ req.end();
17585
+ });
17586
+ }
17587
+
17588
+ // src/beads/watcher.ts
17589
+ var API_BASE4 = resolveApiBaseUrl();
17590
+ var DEBOUNCE_MS = 400;
17591
+ var _chokidarSeam = {
17592
+ load: () => {
17593
+ try {
17594
+ return require("chokidar");
17595
+ } catch {
17596
+ return null;
17597
+ }
17598
+ }
17599
+ };
17600
+ var BeadsWatcher = class {
17601
+ constructor(opts) {
17602
+ this.opts = opts;
17603
+ this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
17604
+ this.feedPath = opts.feedPath ?? path37.join(defaultBeadsHomeDir(), "issues.jsonl");
17605
+ this.apiBase = opts.apiBaseUrl ?? API_BASE4;
17606
+ }
17607
+ opts;
17608
+ watcher = null;
17609
+ debounceTimer = null;
17610
+ stopped = false;
17611
+ lastPushedHash = null;
17612
+ bd;
17613
+ feedPath;
17614
+ apiBase;
17615
+ /** Start tailing the change feed. Idempotent (second call is a no-op). */
17616
+ start() {
17617
+ if (this.watcher || this.stopped) return;
17618
+ const chokidar2 = _chokidarSeam.load();
17619
+ if (!chokidar2) {
17620
+ log.warn("beads", "chokidar unavailable \u2014 beads watcher disabled");
17621
+ return;
17622
+ }
17623
+ const watcher = chokidar2.watch(this.feedPath, {
17624
+ ignoreInitial: false,
17625
+ // push the current state once on start
17626
+ persistent: true,
17627
+ awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 100 }
17628
+ });
17629
+ watcher.on("add", () => this.scheduleSync());
17630
+ watcher.on("change", () => this.scheduleSync());
17631
+ watcher.on(
17632
+ "error",
17633
+ (err) => log.warn("beads", `feed watcher error \u2014 continuing: ${err}`)
17634
+ );
17635
+ this.watcher = watcher;
17636
+ log.info("beads", `watching ${this.feedPath} for session=${this.opts.sessionId.slice(0, 8)}`);
17637
+ }
17638
+ async stop() {
17639
+ if (this.stopped) return;
17640
+ this.stopped = true;
17641
+ if (this.debounceTimer) {
17642
+ clearTimeout(this.debounceTimer);
17643
+ this.debounceTimer = null;
17644
+ }
17645
+ if (this.watcher) {
17646
+ try {
17647
+ await this.watcher.close();
17648
+ } catch (err) {
17649
+ log.warn("beads", "error closing feed watcher", err);
17650
+ }
17651
+ this.watcher = null;
17652
+ }
17653
+ }
17654
+ /**
17655
+ * Debounce the filesystem event. Each fresh write resets the timer so a
17656
+ * burst of bd mutations coalesces into one snapshot push. NOT polling — the
17657
+ * timer only fires off the back of a real fs event.
17658
+ */
17659
+ scheduleSync() {
17660
+ if (this.stopped) return;
17661
+ if (this.debounceTimer) clearTimeout(this.debounceTimer);
17662
+ this.debounceTimer = setTimeout(() => {
17663
+ this.debounceTimer = null;
17664
+ void this.syncNow();
17665
+ }, DEBOUNCE_MS);
17666
+ }
17667
+ /** Visible for tests — pump a synthetic feed event through debounce → push. */
17668
+ /* @internal */
17669
+ _emitForTest() {
17670
+ this.scheduleSync();
17671
+ }
17672
+ /**
17673
+ * Build the full snapshot from bd and push it. Diffs against the last
17674
+ * pushed content hash so an identical rewrite is a no-op.
17675
+ */
17676
+ async syncNow() {
17677
+ if (this.stopped) return;
17678
+ const { projectKey, projectLabel } = deriveProjectIdentity(this.opts.cwd);
17679
+ const [issues, summary] = await Promise.all([
17680
+ this.bd.listIssues(projectKey),
17681
+ this.bd.statusSummary()
17682
+ ]);
17683
+ const payload = {
17684
+ sessionId: this.opts.sessionId,
17685
+ pluginId: this.opts.pluginId,
17686
+ projectKey,
17687
+ projectLabel,
17688
+ fullSnapshot: true,
17689
+ issues,
17690
+ memories: [],
17691
+ ...summary ? { summary } : {}
17692
+ };
17693
+ const body = JSON.stringify(payload);
17694
+ const hash = crypto3.createHash("sha256").update(body).digest("hex");
17695
+ if (hash === this.lastPushedHash) {
17696
+ log.trace("beads", "snapshot unchanged \u2014 skipping push");
17697
+ return;
17698
+ }
17699
+ try {
17700
+ const res = await _transport3.post(`${this.apiBase}/api/beads/ingest`, this.headers(), body);
17701
+ if (res.statusCode >= 200 && res.statusCode < 300) {
17702
+ this.lastPushedHash = hash;
17703
+ log.trace("beads", `pushed ${issues.length} issue(s) project=${projectLabel}`);
17704
+ } else if (res.statusCode === 404 || res.statusCode === 410) {
17705
+ log.warn("beads", `session dead (status=${res.statusCode}) \u2014 stopping watcher`);
17706
+ this.stopped = true;
17707
+ } else {
17708
+ log.warn("beads", `ingest failed status=${res.statusCode} body=${res.body.slice(0, 200)}`);
17709
+ }
17710
+ } catch (err) {
17711
+ log.warn("beads", "ingest POST error", err);
17712
+ }
17713
+ }
17714
+ headers() {
17715
+ return {
17716
+ "Content-Type": "application/json",
17717
+ "X-Codeam-Protocol-Version": "2.0.0",
17718
+ "X-Plugin-Auth-Token": this.opts.pluginAuthToken
17719
+ };
17720
+ }
17721
+ };
17722
+
17723
+ // src/beads/apply-actions.ts
17724
+ function buildBdArgs(action) {
17725
+ switch (action.kind) {
17726
+ case "claim": {
17727
+ if (!action.issueId) return null;
17728
+ const args2 = ["update", action.issueId, "--claim"];
17729
+ if (action.owner) args2.push("--owner", action.owner);
17730
+ return args2;
17731
+ }
17732
+ case "close": {
17733
+ if (!action.issueId) return null;
17734
+ const args2 = ["close", action.issueId];
17735
+ if (action.reason) args2.push("--reason", action.reason);
17736
+ return args2;
17737
+ }
17738
+ case "create": {
17739
+ const title = action.text?.trim();
17740
+ if (!title) return null;
17741
+ return ["create", title];
17742
+ }
17743
+ case "remember": {
17744
+ const body = action.text?.trim();
17745
+ if (!body) return null;
17746
+ return ["remember", body];
17747
+ }
17748
+ default:
17749
+ return null;
17750
+ }
17751
+ }
17752
+ async function applyBeadsAction(action, deps) {
17753
+ const args2 = buildBdArgs(action);
17754
+ if (!args2) {
17755
+ log.warn("beads", `malformed beads action: kind=${action.kind}`);
17756
+ return { ok: false, action: action.kind, code: -1, error: "malformed action" };
17757
+ }
17758
+ if (!deps.adapter.isAvailable()) {
17759
+ return { ok: false, action: action.kind, code: -1, error: "bd unavailable" };
17760
+ }
17761
+ const res = await deps.adapter.run(args2);
17762
+ if (res.code !== 0) {
17763
+ log.warn("beads", `bd ${args2.join(" ")} failed (code=${res.code}): ${res.stderr.slice(0, 200)}`);
17764
+ return { ok: false, action: action.kind, code: res.code, error: res.stderr };
17765
+ }
17766
+ log.info("beads", `applied action ${action.kind}${action.issueId ? ` (${action.issueId})` : ""}`);
17767
+ try {
17768
+ await deps.onApplied();
17769
+ } catch (err) {
17770
+ log.warn("beads", "post-action push failed (state still applied locally)", err);
17771
+ }
17772
+ return { ok: true, action: action.kind, code: 0 };
17773
+ }
17774
+
17775
+ // src/beads/install-bd.ts
17776
+ var import_child_process14 = require("child_process");
17777
+ var INSTALL_SH_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh";
17778
+ var INSTALL_PS1_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/install.ps1";
17779
+ function resolveInstallStrategy(platform2) {
17780
+ if (platform2 === "win32") {
17781
+ return {
17782
+ command: "powershell.exe",
17783
+ args: [
17784
+ "-NoProfile",
17785
+ "-NonInteractive",
17786
+ "-ExecutionPolicy",
17787
+ "Bypass",
17788
+ "-Command",
17789
+ `irm ${INSTALL_PS1_URL} | iex`
17790
+ ],
17791
+ description: `PowerShell: irm ${INSTALL_PS1_URL} | iex (requires Go 1.24+ and Git for Windows on PATH)`
17792
+ };
17793
+ }
17794
+ return {
17795
+ command: "bash",
17796
+ args: ["-c", `curl -fsSL ${INSTALL_SH_URL} | bash`],
17797
+ description: `curl -fsSL ${INSTALL_SH_URL} | bash`
17798
+ };
17799
+ }
17800
+ var _installSpawnSeam = {
17801
+ run: _defaultInstallSpawn
17802
+ };
17803
+ function _defaultInstallSpawn(strategy) {
17804
+ return new Promise((resolve7) => {
17805
+ let proc;
17806
+ try {
17807
+ proc = (0, import_child_process14.spawn)(strategy.command, strategy.args, { env: process.env });
17808
+ } catch (err) {
17809
+ resolve7({ ok: false, code: -1, stderr: err.message });
17810
+ return;
17811
+ }
17812
+ let stderr = "";
17813
+ proc.stderr?.on("data", (c2) => {
17814
+ stderr += c2.toString();
17815
+ });
17816
+ proc.on("error", (err) => resolve7({ ok: false, code: -1, stderr: err.message }));
17817
+ proc.on(
17818
+ "close",
17819
+ (code) => resolve7({ ok: code === 0, code: code ?? -1, stderr })
17820
+ );
17821
+ });
17822
+ }
17823
+ async function installBd(platform2 = process.platform) {
17824
+ const strategy = resolveInstallStrategy(platform2);
17825
+ log.info("beads", `installing bd via ${strategy.description}`);
17826
+ const result = await _installSpawnSeam.run(strategy);
17827
+ if (!result.ok) {
17828
+ log.warn(
17829
+ "beads",
17830
+ `bd install failed (code=${result.code}): ${result.stderr.slice(0, 200)}`
17831
+ );
17832
+ }
17833
+ return result;
17834
+ }
17835
+
17836
+ // src/beads/index.ts
17837
+ async function maybeStartBeads(opts) {
17838
+ if (!opts.enabled) {
17839
+ log.trace("beads", "beads flag off \u2014 skipping");
17840
+ return null;
17841
+ }
17842
+ const adapter = new BdAdapter({ cwd: opts.cwd });
17843
+ if (!adapter.isAvailable() && opts.allowInstall) {
17844
+ log.info("beads", "bd not found \u2014 running OS installer");
17845
+ await installBd();
17846
+ }
17847
+ if (!adapter.isAvailable()) {
17848
+ log.warn("beads", "bd unavailable \u2014 beads disabled for this session");
17849
+ return null;
17850
+ }
17851
+ const boot = await bootstrapBeads({ cwd: opts.cwd, agents: opts.agents, adapter });
17852
+ if (!boot.serverUp) {
17853
+ log.warn("beads", "beads server not up \u2014 watcher not started this run");
17854
+ return null;
17855
+ }
17856
+ const watcher = new BeadsWatcher({
17857
+ sessionId: opts.sessionId,
17858
+ pluginId: opts.pluginId,
17859
+ pluginAuthToken: opts.pluginAuthToken,
17860
+ cwd: opts.cwd,
17861
+ adapter
17862
+ });
17863
+ watcher.start();
17864
+ void watcher.syncNow();
17865
+ return { watcher, adapter };
17866
+ }
17867
+ async function handleBeadsActionCommand(action, started) {
17868
+ await applyBeadsAction(action, {
17869
+ adapter: started.adapter,
17870
+ onApplied: () => started.watcher.syncNow()
17871
+ });
17872
+ }
17873
+
17874
+ // src/beads/wiring.ts
17875
+ function beadsKilled() {
17876
+ const v = process.env.CODEAM_BEADS_DISABLED;
17877
+ return !!v && v !== "0" && v.toLowerCase() !== "false";
17878
+ }
17879
+ async function startBeadsForSession(ctx) {
17880
+ if (beadsKilled()) {
17881
+ log.trace("beads", "CODEAM_BEADS_DISABLED set \u2014 beads off for this session");
17882
+ return null;
17883
+ }
17884
+ if (!ctx.pluginAuthToken) {
17885
+ log.trace("beads", "no pluginAuthToken on session \u2014 beads off");
17886
+ return null;
17887
+ }
17888
+ try {
17889
+ return await maybeStartBeads({
17890
+ enabled: true,
17891
+ sessionId: ctx.sessionId,
17892
+ pluginId: ctx.pluginId,
17893
+ pluginAuthToken: ctx.pluginAuthToken,
17894
+ agents: ctx.agents,
17895
+ cwd: ctx.cwd
17896
+ });
17897
+ } catch (err) {
17898
+ log.warn("beads", "startBeadsForSession failed (non-fatal)", err);
17899
+ return null;
17900
+ }
17901
+ }
17902
+ var ACTION_KINDS = /* @__PURE__ */ new Set([
17903
+ "claim",
17904
+ "close",
17905
+ "create",
17906
+ "remember"
17907
+ ]);
17908
+ function isBeadsActionKind(v) {
17909
+ return typeof v === "string" && ACTION_KINDS.has(v);
17910
+ }
17911
+ function strOrUndefined(v) {
17912
+ return typeof v === "string" ? v : void 0;
17913
+ }
17914
+ function beadsActionFromPayload(payload) {
17915
+ const { action, args: args2 } = payload;
17916
+ if (!isBeadsActionKind(action)) return null;
17917
+ const a = args2 && typeof args2 === "object" ? args2 : {};
17918
+ return {
17919
+ kind: action,
17920
+ issueId: strOrUndefined(a.issueId),
17921
+ text: strOrUndefined(a.text),
17922
+ reason: strOrUndefined(a.reason),
17923
+ owner: strOrUndefined(a.owner),
17924
+ projectKey: strOrUndefined(a.projectKey)
17925
+ };
17926
+ }
17927
+
17175
17928
  // src/commands/start/handlers.ts
17176
17929
  var pendingAttachmentFiles = /* @__PURE__ */ new Set();
17177
17930
  function cleanupAttachmentTempFiles() {
17178
17931
  for (const p2 of pendingAttachmentFiles) {
17179
17932
  try {
17180
- fs29.unlinkSync(p2);
17933
+ fs31.unlinkSync(p2);
17181
17934
  } catch {
17182
17935
  }
17183
17936
  }
@@ -17186,8 +17939,8 @@ function cleanupAttachmentTempFiles() {
17186
17939
  function saveFilesTemp(files) {
17187
17940
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
17188
17941
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
17189
- const tmpPath = path35.join(os24.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
17190
- fs29.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
17942
+ const tmpPath = path38.join(os25.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
17943
+ fs31.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
17191
17944
  pendingAttachmentFiles.add(tmpPath);
17192
17945
  return tmpPath;
17193
17946
  });
@@ -17207,7 +17960,7 @@ var startTask = (ctx, _cmd, parsed) => {
17207
17960
  setTimeout(() => {
17208
17961
  for (const p2 of paths) {
17209
17962
  try {
17210
- fs29.unlinkSync(p2);
17963
+ fs31.unlinkSync(p2);
17211
17964
  } catch {
17212
17965
  }
17213
17966
  pendingAttachmentFiles.delete(p2);
@@ -17332,7 +18085,7 @@ var sessionTerminated = async (ctx, cmd) => {
17332
18085
  } catch {
17333
18086
  }
17334
18087
  try {
17335
- const proc = (0, import_child_process12.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18088
+ const proc = (0, import_child_process15.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
17336
18089
  detached: true,
17337
18090
  stdio: "ignore"
17338
18091
  });
@@ -17354,7 +18107,7 @@ var shutdownSession = async (ctx, cmd) => {
17354
18107
  }
17355
18108
  if (ctx.keepAliveCtx.inCodespace && ctx.keepAliveCtx.codespaceName) {
17356
18109
  try {
17357
- const stopProc = (0, import_child_process12.spawn)(
18110
+ const stopProc = (0, import_child_process15.spawn)(
17358
18111
  "bash",
17359
18112
  ["-lc", `sleep 1; gh codespace stop -c ${JSON.stringify(ctx.keepAliveCtx.codespaceName)} >/dev/null 2>&1 || true`],
17360
18113
  { detached: true, stdio: "ignore" }
@@ -17364,7 +18117,7 @@ var shutdownSession = async (ctx, cmd) => {
17364
18117
  }
17365
18118
  }
17366
18119
  try {
17367
- const proc = (0, import_child_process12.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18120
+ const proc = (0, import_child_process15.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
17368
18121
  detached: true,
17369
18122
  stdio: "ignore"
17370
18123
  });
@@ -17780,8 +18533,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
17780
18533
  if (args2.length === 0) return detection;
17781
18534
  const binName = args2[0];
17782
18535
  if (binName.startsWith("-")) return detection;
17783
- const binPath = path35.join(cwd, "node_modules", ".bin", binName);
17784
- if (!fs29.existsSync(binPath)) return detection;
18536
+ const binPath = path38.join(cwd, "node_modules", ".bin", binName);
18537
+ if (!fs31.existsSync(binPath)) return detection;
17785
18538
  return {
17786
18539
  ...detection,
17787
18540
  command: binPath,
@@ -17871,7 +18624,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
17871
18624
  "BOOT_SEQUENCE",
17872
18625
  `${spawnable.command} ${spawnable.args.join(" ")}`
17873
18626
  );
17874
- const devServer = (0, import_child_process12.spawn)(spawnable.command, spawnable.args, {
18627
+ const devServer = (0, import_child_process15.spawn)(spawnable.command, spawnable.args, {
17875
18628
  cwd: process.cwd(),
17876
18629
  env: { ...process.env, ...spawnable.env ?? {} },
17877
18630
  stdio: ["ignore", "pipe", "pipe"]
@@ -17997,7 +18750,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
17997
18750
  });
17998
18751
  return;
17999
18752
  }
18000
- tunnel = (0, import_child_process12.spawn)(bin, ["tunnel", "--url", `http://localhost:${detection.port}`], {
18753
+ tunnel = (0, import_child_process15.spawn)(bin, ["tunnel", "--url", `http://localhost:${detection.port}`], {
18001
18754
  stdio: ["ignore", "pipe", "pipe"]
18002
18755
  });
18003
18756
  let parsedUrl = null;
@@ -18094,8 +18847,8 @@ var previewStopH = (ctx) => {
18094
18847
  })();
18095
18848
  };
18096
18849
  function runOnce(cmd, args2, cwd, env) {
18097
- return new Promise((resolve6) => {
18098
- const child = (0, import_child_process12.spawn)(cmd, args2, {
18850
+ return new Promise((resolve7) => {
18851
+ const child = (0, import_child_process15.spawn)(cmd, args2, {
18099
18852
  cwd,
18100
18853
  env: { ...process.env, ...env ?? {} },
18101
18854
  stdio: ["ignore", "pipe", "pipe"]
@@ -18108,8 +18861,8 @@ function runOnce(cmd, args2, cwd, env) {
18108
18861
  };
18109
18862
  child.stdout?.on("data", onChunk);
18110
18863
  child.stderr?.on("data", onChunk);
18111
- child.once("exit", (code) => resolve6(code));
18112
- child.once("error", () => resolve6(-1));
18864
+ child.once("exit", (code) => resolve7(code));
18865
+ child.once("error", () => resolve7(-1));
18113
18866
  });
18114
18867
  }
18115
18868
  var savePreviewConfigH = (_ctx, _cmd, parsed) => {
@@ -18163,6 +18916,23 @@ var handlers = {
18163
18916
  save_preview_config: savePreviewConfigH
18164
18917
  };
18165
18918
  async function dispatchCommand(ctx, cmd) {
18919
+ if (cmd.type === "beads_action") {
18920
+ if (!ctx.beads) {
18921
+ log.trace("beads", "beads_action received but beads not running this session \u2014 dropping");
18922
+ return;
18923
+ }
18924
+ const action = beadsActionFromPayload(cmd.payload);
18925
+ if (!action) {
18926
+ log.warn("beads", "malformed beads_action payload \u2014 dropping");
18927
+ return;
18928
+ }
18929
+ try {
18930
+ await handleBeadsActionCommand(action, ctx.beads);
18931
+ } catch (err) {
18932
+ log.warn("beads", "handleBeadsActionCommand failed (non-fatal)", err);
18933
+ }
18934
+ return;
18935
+ }
18166
18936
  const parsed = parsePayload2(startCommandSchema, cmd.payload);
18167
18937
  if (!parsed) {
18168
18938
  showInfo(`Ignoring malformed ${cmd.type} payload.`);
@@ -18174,10 +18944,10 @@ async function dispatchCommand(ctx, cmd) {
18174
18944
  }
18175
18945
 
18176
18946
  // src/services/file-watcher.service.ts
18177
- var import_child_process13 = require("child_process");
18178
- var fs30 = __toESM(require("fs"));
18179
- var os25 = __toESM(require("os"));
18180
- var path36 = __toESM(require("path"));
18947
+ var import_child_process16 = require("child_process");
18948
+ var fs32 = __toESM(require("fs"));
18949
+ var os26 = __toESM(require("os"));
18950
+ var path39 = __toESM(require("path"));
18181
18951
  var import_ignore = __toESM(require("ignore"));
18182
18952
 
18183
18953
  // src/services/file-watcher/diff-parser.ts
@@ -18266,58 +19036,9 @@ function isIgnoredFilePath(filePath) {
18266
19036
  return IGNORED_PATH_PATTERN.test(filePath);
18267
19037
  }
18268
19038
 
18269
- // src/services/file-watcher/transport.ts
18270
- var http5 = __toESM(require("http"));
18271
- var https5 = __toESM(require("https"));
18272
- var _transport3 = {
18273
- post: _post2
18274
- };
18275
- function _post2(url, headers, payload) {
18276
- return new Promise((resolve6, reject) => {
18277
- let settled = false;
18278
- const u2 = new URL(url);
18279
- const lib = u2.protocol === "https:" ? https5 : http5;
18280
- const req = lib.request(
18281
- {
18282
- hostname: u2.hostname,
18283
- port: u2.port || (u2.protocol === "https:" ? 443 : 80),
18284
- path: u2.pathname + u2.search,
18285
- method: "POST",
18286
- headers: {
18287
- ...headers,
18288
- ...vercelBypassHeader(),
18289
- "Content-Length": Buffer.byteLength(payload)
18290
- },
18291
- timeout: 8e3
18292
- },
18293
- (res) => {
18294
- let body = "";
18295
- res.on("data", (c2) => {
18296
- body += c2.toString();
18297
- });
18298
- res.on("end", () => {
18299
- if (settled) return;
18300
- settled = true;
18301
- resolve6({ statusCode: res.statusCode ?? 0, body });
18302
- });
18303
- }
18304
- );
18305
- req.on("error", (err) => {
18306
- if (settled) return;
18307
- settled = true;
18308
- reject(err);
18309
- });
18310
- req.on("timeout", () => {
18311
- req.destroy();
18312
- });
18313
- req.write(payload);
18314
- req.end();
18315
- });
18316
- }
18317
-
18318
19039
  // src/services/file-watcher.service.ts
18319
- var API_BASE4 = resolveApiBaseUrl();
18320
- var DEBOUNCE_MS = 250;
19040
+ var API_BASE5 = resolveApiBaseUrl();
19041
+ var DEBOUNCE_MS2 = 250;
18321
19042
  var COALESCE_WINDOW_MS = 250;
18322
19043
  var COALESCE_MAX_HOLD_MS = 2e3;
18323
19044
  var MAX_RETRIES = 2;
@@ -18336,10 +19057,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
18336
19057
  /[\\/]Start Menu([\\/]|$)/i,
18337
19058
  /[\\/]Templates([\\/]|$)/i
18338
19059
  ];
18339
- function isUnsafeWindowsWatchRoot(dir, homedir21) {
19060
+ function isUnsafeWindowsWatchRoot(dir, homedir22) {
18340
19061
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
18341
19062
  const cwd = norm(dir);
18342
- const home = norm(homedir21);
19063
+ const home = norm(homedir22);
18343
19064
  if (cwd === home) return true;
18344
19065
  if (/^[a-z]:$/.test(cwd)) return true;
18345
19066
  const sysRoots = [
@@ -18353,7 +19074,7 @@ function isUnsafeWindowsWatchRoot(dir, homedir21) {
18353
19074
  }
18354
19075
  return false;
18355
19076
  }
18356
- var _chokidarSeam = {
19077
+ var _chokidarSeam2 = {
18357
19078
  load: () => {
18358
19079
  try {
18359
19080
  return require("chokidar");
@@ -18369,18 +19090,18 @@ var _findGitRootSeam = {
18369
19090
  resolve: _defaultFindGitRoot
18370
19091
  };
18371
19092
  function _defaultFindGitRoot(startDir) {
18372
- let dir = path36.resolve(startDir);
19093
+ let dir = path39.resolve(startDir);
18373
19094
  const seen = /* @__PURE__ */ new Set();
18374
19095
  for (let i = 0; i < 256; i++) {
18375
19096
  if (seen.has(dir)) return null;
18376
19097
  seen.add(dir);
18377
19098
  try {
18378
- const gitPath = path36.join(dir, ".git");
18379
- const stat3 = fs30.statSync(gitPath, { throwIfNoEntry: false });
19099
+ const gitPath = path39.join(dir, ".git");
19100
+ const stat3 = fs32.statSync(gitPath, { throwIfNoEntry: false });
18380
19101
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
18381
19102
  } catch {
18382
19103
  }
18383
- const parent = path36.dirname(dir);
19104
+ const parent = path39.dirname(dir);
18384
19105
  if (parent === dir) return null;
18385
19106
  dir = parent;
18386
19107
  }
@@ -18389,7 +19110,7 @@ function _defaultFindGitRoot(startDir) {
18389
19110
  var FileWatcherService = class {
18390
19111
  constructor(opts) {
18391
19112
  this.opts = opts;
18392
- this.apiBase = opts.apiBaseUrl ?? API_BASE4;
19113
+ this.apiBase = opts.apiBaseUrl ?? API_BASE5;
18393
19114
  }
18394
19115
  opts;
18395
19116
  watcher = null;
@@ -18438,14 +19159,14 @@ var FileWatcherService = class {
18438
19159
  throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
18439
19160
  }
18440
19161
  const isWin = process.platform === "win32";
18441
- if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os25.homedir())) {
19162
+ if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os26.homedir())) {
18442
19163
  log.warn(
18443
19164
  "fileWatcher",
18444
19165
  `refusing to watch ${this.opts.workingDir} \u2014 looks like a Windows user-profile or system path. Run codeam from your project folder to enable file change emission.`
18445
19166
  );
18446
19167
  return;
18447
19168
  }
18448
- const chokidar2 = _chokidarSeam.load();
19169
+ const chokidar2 = _chokidarSeam2.load();
18449
19170
  if (!chokidar2) {
18450
19171
  log.warn(
18451
19172
  "fileWatcher",
@@ -18564,7 +19285,7 @@ var FileWatcherService = class {
18564
19285
  const timer = setTimeout(() => {
18565
19286
  this.pending.delete(absPath);
18566
19287
  this.enqueueForCoalesce(absPath, changeType);
18567
- }, DEBOUNCE_MS);
19288
+ }, DEBOUNCE_MS2);
18568
19289
  this.pending.set(absPath, {
18569
19290
  lastEventAt: Date.now(),
18570
19291
  timer,
@@ -18625,7 +19346,7 @@ var FileWatcherService = class {
18625
19346
  }
18626
19347
  async emitForFile(absPath, changeType) {
18627
19348
  if (this.stopped) return;
18628
- const fileDir = path36.dirname(absPath);
19349
+ const fileDir = path39.dirname(absPath);
18629
19350
  let gitRoot = this.gitRootByDir.get(fileDir);
18630
19351
  if (gitRoot === void 0) {
18631
19352
  gitRoot = findGitRoot2(fileDir);
@@ -18638,19 +19359,19 @@ var FileWatcherService = class {
18638
19359
  );
18639
19360
  return;
18640
19361
  }
18641
- const relPathInRepo = path36.relative(gitRoot, absPath);
19362
+ const relPathInRepo = path39.relative(gitRoot, absPath);
18642
19363
  if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
18643
19364
  const matcher = this.getGitIgnoreMatcher(gitRoot);
18644
19365
  if (matcher && matcher.ignores(relPathInRepo)) {
18645
19366
  log.trace(
18646
19367
  "fileWatcher",
18647
- `${relPathInRepo} ignored by ${path36.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
19368
+ `${relPathInRepo} ignored by ${path39.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
18648
19369
  );
18649
19370
  return;
18650
19371
  }
18651
19372
  this.opts.onRepoDirty?.(gitRoot);
18652
- const repoPath = path36.relative(this.opts.workingDir, gitRoot);
18653
- const repoName = path36.basename(gitRoot);
19373
+ const repoPath = path39.relative(this.opts.workingDir, gitRoot);
19374
+ const repoName = path39.basename(gitRoot);
18654
19375
  let diffText = "";
18655
19376
  let fileStatus = "modified";
18656
19377
  if (changeType === "unlink") {
@@ -18825,7 +19546,7 @@ var FileWatcherService = class {
18825
19546
  collectGitignoreFiles(repoRoot, dir, matcher) {
18826
19547
  let entries;
18827
19548
  try {
18828
- entries = fs30.readdirSync(dir, { withFileTypes: true });
19549
+ entries = fs32.readdirSync(dir, { withFileTypes: true });
18829
19550
  } catch {
18830
19551
  return;
18831
19552
  }
@@ -18834,16 +19555,16 @@ var FileWatcherService = class {
18834
19555
  );
18835
19556
  if (gitignoreEntry) {
18836
19557
  try {
18837
- const body = fs30.readFileSync(path36.join(dir, ".gitignore"), "utf8");
18838
- const rel = path36.relative(repoRoot, dir).replace(/\\/g, "/");
19558
+ const body = fs32.readFileSync(path39.join(dir, ".gitignore"), "utf8");
19559
+ const rel = path39.relative(repoRoot, dir).replace(/\\/g, "/");
18839
19560
  const prefixed = body.split(/\r?\n/).map((line) => {
18840
19561
  const trimmed = line.trim();
18841
19562
  if (!trimmed || trimmed.startsWith("#")) return line;
18842
19563
  if (!rel) return line;
18843
19564
  if (trimmed.startsWith("!")) {
18844
- return "!" + path36.posix.join(rel, trimmed.slice(1));
19565
+ return "!" + path39.posix.join(rel, trimmed.slice(1));
18845
19566
  }
18846
- return path36.posix.join(rel, trimmed);
19567
+ return path39.posix.join(rel, trimmed);
18847
19568
  }).join("\n");
18848
19569
  matcher.add(prefixed);
18849
19570
  } catch {
@@ -18852,7 +19573,7 @@ var FileWatcherService = class {
18852
19573
  for (const entry of entries) {
18853
19574
  if (!entry.isDirectory()) continue;
18854
19575
  if (entry.name === ".git") continue;
18855
- const childAbs = path36.join(dir, entry.name);
19576
+ const childAbs = path39.join(dir, entry.name);
18856
19577
  if (isIgnoredFilePath(childAbs)) continue;
18857
19578
  this.collectGitignoreFiles(repoRoot, childAbs, matcher);
18858
19579
  }
@@ -18986,12 +19707,12 @@ var _gitSeam = {
18986
19707
  run: _runGitImpl
18987
19708
  };
18988
19709
  async function _runGitImpl(cwd, args2, opts = {}) {
18989
- return new Promise((resolve6) => {
19710
+ return new Promise((resolve7) => {
18990
19711
  let proc;
18991
19712
  try {
18992
- proc = (0, import_child_process13.spawn)("git", args2, { cwd, env: process.env });
19713
+ proc = (0, import_child_process16.spawn)("git", args2, { cwd, env: process.env });
18993
19714
  } catch {
18994
- resolve6(null);
19715
+ resolve7(null);
18995
19716
  return;
18996
19717
  }
18997
19718
  let stdout = "";
@@ -19002,13 +19723,13 @@ async function _runGitImpl(cwd, args2, opts = {}) {
19002
19723
  proc.stderr?.on("data", (c2) => {
19003
19724
  stderr += c2.toString();
19004
19725
  });
19005
- proc.on("error", () => resolve6(null));
19726
+ proc.on("error", () => resolve7(null));
19006
19727
  proc.on("close", (code) => {
19007
19728
  if (code === 0 || opts.allowNonZeroExit) {
19008
- resolve6(stdout);
19729
+ resolve7(stdout);
19009
19730
  } else {
19010
19731
  log.trace("fileWatcher", `git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`);
19011
- resolve6(null);
19732
+ resolve7(null);
19012
19733
  }
19013
19734
  });
19014
19735
  });
@@ -19021,8 +19742,8 @@ function _runGit(cwd, args2, opts = {}) {
19021
19742
  var import_crypto4 = require("crypto");
19022
19743
 
19023
19744
  // src/services/turn-files/git-changeset.ts
19024
- var import_child_process14 = require("child_process");
19025
- var path37 = __toESM(require("path"));
19745
+ var import_child_process17 = require("child_process");
19746
+ var path40 = __toESM(require("path"));
19026
19747
  async function collectRepoChangeset(opts) {
19027
19748
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
19028
19749
  if (status2 === null) return null;
@@ -19102,12 +19823,12 @@ function runGit3(cwd, args2) {
19102
19823
  return _runGitImpl2.run(cwd, args2);
19103
19824
  }
19104
19825
  function defaultRunGit(cwd, args2) {
19105
- return new Promise((resolve6) => {
19826
+ return new Promise((resolve7) => {
19106
19827
  let proc;
19107
19828
  try {
19108
- proc = (0, import_child_process14.spawn)("git", args2, { cwd, env: process.env });
19829
+ proc = (0, import_child_process17.spawn)("git", args2, { cwd, env: process.env });
19109
19830
  } catch {
19110
- resolve6(null);
19831
+ resolve7(null);
19111
19832
  return;
19112
19833
  }
19113
19834
  let stdout = "";
@@ -19118,22 +19839,22 @@ function defaultRunGit(cwd, args2) {
19118
19839
  proc.stderr?.on("data", (c2) => {
19119
19840
  stderr += c2.toString();
19120
19841
  });
19121
- proc.on("error", () => resolve6(null));
19842
+ proc.on("error", () => resolve7(null));
19122
19843
  proc.on("close", (code) => {
19123
19844
  if (code === 0) {
19124
- resolve6(stdout);
19845
+ resolve7(stdout);
19125
19846
  } else {
19126
19847
  log.trace(
19127
19848
  "turnFiles",
19128
19849
  `git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`
19129
19850
  );
19130
- resolve6(null);
19851
+ resolve7(null);
19131
19852
  }
19132
19853
  });
19133
19854
  });
19134
19855
  }
19135
19856
  async function discoverRepos(workingDir, maxDepth = 4) {
19136
- const fs36 = await import("fs/promises");
19857
+ const fs38 = await import("fs/promises");
19137
19858
  const out2 = [];
19138
19859
  await walk(workingDir, 0);
19139
19860
  return out2;
@@ -19141,7 +19862,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
19141
19862
  if (depth > maxDepth) return;
19142
19863
  let entries = [];
19143
19864
  try {
19144
- const dirents = await fs36.readdir(dir, { withFileTypes: true });
19865
+ const dirents = await fs38.readdir(dir, { withFileTypes: true });
19145
19866
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
19146
19867
  } catch {
19147
19868
  return;
@@ -19152,8 +19873,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
19152
19873
  if (hasGit) {
19153
19874
  out2.push({
19154
19875
  repoRoot: dir,
19155
- repoPath: path37.relative(workingDir, dir),
19156
- repoName: path37.basename(dir)
19876
+ repoPath: path40.relative(workingDir, dir),
19877
+ repoName: path40.basename(dir)
19157
19878
  });
19158
19879
  return;
19159
19880
  }
@@ -19161,14 +19882,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
19161
19882
  if (!entry.isDirectory) continue;
19162
19883
  if (entry.name === "node_modules") continue;
19163
19884
  if (entry.name === "dist" || entry.name === "build") continue;
19164
- await walk(path37.join(dir, entry.name), depth + 1);
19885
+ await walk(path40.join(dir, entry.name), depth + 1);
19165
19886
  }
19166
19887
  }
19167
19888
  }
19168
19889
 
19169
19890
  // src/services/turn-files/files-outbox.ts
19170
- var fs31 = __toESM(require("fs/promises"));
19171
- var path38 = __toESM(require("path"));
19891
+ var fs33 = __toESM(require("fs/promises"));
19892
+ var path41 = __toESM(require("path"));
19172
19893
  var import_os7 = require("os");
19173
19894
  var HOME_OUTBOX_DIR = ".codeam/outbox";
19174
19895
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -19201,16 +19922,16 @@ var FilesOutbox = class {
19201
19922
  backoffIndex = 0;
19202
19923
  stopped = false;
19203
19924
  constructor(opts) {
19204
- const base = opts.baseDir ?? path38.join(homeDir(), HOME_OUTBOX_DIR);
19205
- this.filePath = path38.join(base, `${opts.sessionId}.jsonl`);
19925
+ const base = opts.baseDir ?? path41.join(homeDir(), HOME_OUTBOX_DIR);
19926
+ this.filePath = path41.join(base, `${opts.sessionId}.jsonl`);
19206
19927
  this.post = opts.post;
19207
19928
  this.autoSchedule = opts.autoSchedule !== false;
19208
19929
  }
19209
19930
  /** Persist the entry to disk and trigger a flush. Returns once the
19210
19931
  * line is durable on disk (not once the POST succeeds). */
19211
19932
  async enqueue(entry) {
19212
- await fs31.mkdir(path38.dirname(this.filePath), { recursive: true });
19213
- await fs31.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
19933
+ await fs33.mkdir(path41.dirname(this.filePath), { recursive: true });
19934
+ await fs33.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
19214
19935
  this.backoffIndex = 0;
19215
19936
  if (this.autoSchedule) this.scheduleFlush(0);
19216
19937
  }
@@ -19299,7 +20020,7 @@ var FilesOutbox = class {
19299
20020
  async readAll() {
19300
20021
  let raw = "";
19301
20022
  try {
19302
- raw = await fs31.readFile(this.filePath, "utf8");
20023
+ raw = await fs33.readFile(this.filePath, "utf8");
19303
20024
  } catch {
19304
20025
  return [];
19305
20026
  }
@@ -19323,12 +20044,12 @@ var FilesOutbox = class {
19323
20044
  async rewrite(entries) {
19324
20045
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
19325
20046
  if (entries.length === 0) {
19326
- await fs31.unlink(this.filePath).catch(() => void 0);
20047
+ await fs33.unlink(this.filePath).catch(() => void 0);
19327
20048
  return;
19328
20049
  }
19329
20050
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
19330
- await fs31.writeFile(tmpPath, payload, "utf8");
19331
- await fs31.rename(tmpPath, this.filePath);
20051
+ await fs33.writeFile(tmpPath, payload, "utf8");
20052
+ await fs33.rename(tmpPath, this.filePath);
19332
20053
  }
19333
20054
  };
19334
20055
  function applyJitter(ms) {
@@ -19340,13 +20061,13 @@ function homeDir() {
19340
20061
  }
19341
20062
 
19342
20063
  // src/services/turn-files/turn-file-aggregator.ts
19343
- var API_BASE5 = resolveApiBaseUrl();
20064
+ var API_BASE6 = resolveApiBaseUrl();
19344
20065
  var ENDPOINT = "/api/files/batch";
19345
20066
  var MAX_BATCH_SIZE = 1e3;
19346
20067
  var TurnFileAggregator = class {
19347
20068
  constructor(opts) {
19348
20069
  this.opts = opts;
19349
- this.apiBase = opts.apiBaseUrl ?? API_BASE5;
20070
+ this.apiBase = opts.apiBaseUrl ?? API_BASE6;
19350
20071
  this.outbox = new FilesOutbox({
19351
20072
  sessionId: opts.sessionId,
19352
20073
  baseDir: opts.outboxDir,
@@ -19538,7 +20259,7 @@ var StreamingState = class {
19538
20259
  * default-reject. Caller is the SDK's `onRequestPermission`.
19539
20260
  */
19540
20261
  registerPermission(args2) {
19541
- return new Promise((resolve6) => {
20262
+ return new Promise((resolve7) => {
19542
20263
  const timeoutTimer = setTimeout(() => {
19543
20264
  if (this.pending?.kind === "permission" && this.pending.questionId === args2.questionId) {
19544
20265
  log.warn(
@@ -19546,7 +20267,7 @@ var StreamingState = class {
19546
20267
  `permission ${args2.questionId.slice(0, 8)} TTL expired \u2014 auto-cancel`
19547
20268
  );
19548
20269
  this.pending = null;
19549
- resolve6({ outcome: { outcome: "cancelled" } });
20270
+ resolve7({ outcome: { outcome: "cancelled" } });
19550
20271
  }
19551
20272
  }, PERMISSION_TIMEOUT_MS);
19552
20273
  this.pending = {
@@ -19554,7 +20275,7 @@ var StreamingState = class {
19554
20275
  questionId: args2.questionId,
19555
20276
  labels: args2.labels,
19556
20277
  optionIdByLabel: args2.optionIdByLabel,
19557
- resolve: resolve6,
20278
+ resolve: resolve7,
19558
20279
  timeoutTimer
19559
20280
  };
19560
20281
  });
@@ -19586,14 +20307,14 @@ var StreamingState = class {
19586
20307
  const label = this.pending.labels[index];
19587
20308
  const optionId = label ? this.pending.optionIdByLabel[label] : void 0;
19588
20309
  clearTimeout(this.pending.timeoutTimer);
19589
- const resolve6 = this.pending.resolve;
20310
+ const resolve7 = this.pending.resolve;
19590
20311
  this.pending = null;
19591
20312
  if (!optionId) {
19592
20313
  log.warn("acpRunner", `select_option index=${index} out of bounds \u2014 cancel`);
19593
- resolve6({ outcome: { outcome: "cancelled" } });
20314
+ resolve7({ outcome: { outcome: "cancelled" } });
19594
20315
  return { kind: "resolved" };
19595
20316
  }
19596
- resolve6({ outcome: { outcome: "selected", optionId } });
20317
+ resolve7({ outcome: { outcome: "selected", optionId } });
19597
20318
  return { kind: "resolved" };
19598
20319
  }
19599
20320
  const text = this.pending.options[index];
@@ -19895,6 +20616,7 @@ async function runAcpSession(opts) {
19895
20616
  `adapter handshake ok protocolVersion=${initialize.protocolVersion} sessionId=${acpSessionId.slice(0, 8)}`
19896
20617
  );
19897
20618
  showSuccess(`${opts.agent} online (ACP) \u2014 awaiting prompts from mobile.`);
20619
+ showRelayNotice();
19898
20620
  void publisher.publishOutput({
19899
20621
  type: "agent_banner",
19900
20622
  agentId: opts.agent,
@@ -19948,6 +20670,16 @@ async function runAcpSession(opts) {
19948
20670
  }).catch((err) => {
19949
20671
  log.warn("acpRunner", `fileWatcher.start failed: ${describeError(err)}`);
19950
20672
  });
20673
+ let beads = null;
20674
+ void startBeadsForSession({
20675
+ sessionId: opts.sessionId,
20676
+ pluginId: opts.pluginId,
20677
+ pluginAuthToken: opts.pluginAuthToken,
20678
+ agents: [opts.agent],
20679
+ cwd: opts.cwd
20680
+ }).then((started) => {
20681
+ beads = started;
20682
+ });
19951
20683
  const relay = new CommandRelayService(
19952
20684
  opts.pluginId,
19953
20685
  async (cmd) => {
@@ -19961,7 +20693,8 @@ async function runAcpSession(opts) {
19961
20693
  opts,
19962
20694
  history,
19963
20695
  initialize.agentCapabilities,
19964
- turnFiles
20696
+ turnFiles,
20697
+ () => beads
19965
20698
  );
19966
20699
  },
19967
20700
  { id: opts.agent, name: opts.agent, displayName: opts.agent }
@@ -19972,6 +20705,7 @@ async function runAcpSession(opts) {
19972
20705
  relay.stop();
19973
20706
  void fileWatcher.stop();
19974
20707
  turnFiles.stop();
20708
+ void beads?.watcher.stop();
19975
20709
  closeAllTerminals();
19976
20710
  await client2.stop();
19977
20711
  process.exit(0);
@@ -19982,8 +20716,24 @@ async function runAcpSession(opts) {
19982
20716
  await new Promise(() => {
19983
20717
  });
19984
20718
  }
19985
- async function handleCommand(cmd, client2, relay, acpSessionId, models, streaming, opts, history, agentCaps, turnFiles) {
20719
+ async function handleCommand(cmd, client2, relay, acpSessionId, models, streaming, opts, history, agentCaps, turnFiles, getBeads) {
19986
20720
  switch (cmd.type) {
20721
+ case "beads_action": {
20722
+ const beads = getBeads();
20723
+ const action = beadsActionFromPayload(cmd.payload);
20724
+ if (!beads || !action) {
20725
+ await relay.sendResult(cmd.id, "completed", { applied: false });
20726
+ return;
20727
+ }
20728
+ try {
20729
+ await handleBeadsActionCommand(action, beads);
20730
+ await relay.sendResult(cmd.id, "completed", { applied: true });
20731
+ } catch (err) {
20732
+ log.warn("acpRunner", `beads_action failed (non-fatal): ${describeError(err)}`);
20733
+ await relay.sendResult(cmd.id, "failed", { error: describeError(err) });
20734
+ }
20735
+ return;
20736
+ }
19987
20737
  case "start_task": {
19988
20738
  const payload = cmd.payload;
19989
20739
  const blocks = buildAcpPromptBlocks(payload ?? {});
@@ -20342,11 +21092,11 @@ var ChromeStepTracker = class {
20342
21092
  // src/services/output/chunk-emitter.ts
20343
21093
  var https6 = __toESM(require("https"));
20344
21094
  var http6 = __toESM(require("http"));
20345
- var API_BASE6 = resolveApiBaseUrl();
21095
+ var API_BASE7 = resolveApiBaseUrl();
20346
21096
  async function refreshAuthToken(sessionId, pluginId) {
20347
21097
  try {
20348
21098
  const { statusCode, body } = await _transport4.post(
20349
- `${API_BASE6}/api/pairing/reconnect`,
21099
+ `${API_BASE7}/api/pairing/reconnect`,
20350
21100
  {
20351
21101
  "Content-Type": "application/json",
20352
21102
  "X-Codeam-Protocol-Version": PROTOCOL_VERSION,
@@ -20387,7 +21137,7 @@ var ChunkEmitter = class {
20387
21137
  }
20388
21138
  }
20389
21139
  opts;
20390
- url = `${API_BASE6}/api/commands/output`;
21140
+ url = `${API_BASE7}/api/commands/output`;
20391
21141
  headers;
20392
21142
  /**
20393
21143
  * Send a chunk. `body` is the chunk fields minus `sessionId` /
@@ -20408,14 +21158,14 @@ var ChunkEmitter = class {
20408
21158
  "chunkEmitter",
20409
21159
  `send type=${body.type ?? "(clear)"} bytes=${payload.length} done=${body.done === true}`
20410
21160
  );
20411
- return new Promise((resolve6) => {
21161
+ return new Promise((resolve7) => {
20412
21162
  const attempt = (attemptsLeft) => {
20413
21163
  _transport4.post(this.url, this.headers, payload).then(({ statusCode, body: resBody }) => {
20414
21164
  const tookMs = Date.now() - t0;
20415
21165
  if (statusCode === 410 || statusCode === 404 && /SESSION_NOT_FOUND|SESSION_GONE/.test(resBody)) {
20416
21166
  process.stderr.write("[codeam] session was deleted/disconnected \u2014 stopping output stream.\n");
20417
21167
  log.info("chunkEmitter", `dead status=${statusCode} took=${tookMs}ms`);
20418
- resolve6({ dead: true });
21168
+ resolve7({ dead: true });
20419
21169
  return;
20420
21170
  }
20421
21171
  if (statusCode === 401) {
@@ -20431,7 +21181,7 @@ var ChunkEmitter = class {
20431
21181
  return;
20432
21182
  }
20433
21183
  }
20434
- resolve6({ dead: false });
21184
+ resolve7({ dead: false });
20435
21185
  })();
20436
21186
  return;
20437
21187
  }
@@ -20442,7 +21192,7 @@ var ChunkEmitter = class {
20442
21192
  } else {
20443
21193
  log.info("chunkEmitter", `ok status=${statusCode} took=${tookMs}ms`);
20444
21194
  }
20445
- resolve6({ dead: false });
21195
+ resolve7({ dead: false });
20446
21196
  }).catch((err) => {
20447
21197
  log.warn(
20448
21198
  "chunkEmitter",
@@ -20453,7 +21203,7 @@ var ChunkEmitter = class {
20453
21203
  const delay = 200 * (maxRetries - attemptsLeft + 1);
20454
21204
  setTimeout(() => attempt(attemptsLeft - 1), delay);
20455
21205
  } else {
20456
- resolve6({ dead: false });
21206
+ resolve7({ dead: false });
20457
21207
  }
20458
21208
  });
20459
21209
  };
@@ -20465,7 +21215,7 @@ var _transport4 = {
20465
21215
  post: _post3
20466
21216
  };
20467
21217
  function _post3(url, headers, payload) {
20468
- return new Promise((resolve6, reject) => {
21218
+ return new Promise((resolve7, reject) => {
20469
21219
  let settled = false;
20470
21220
  const u2 = new URL(url);
20471
21221
  const transport = u2.protocol === "https:" ? https6 : http6;
@@ -20489,7 +21239,7 @@ function _post3(url, headers, payload) {
20489
21239
  res.on("end", () => {
20490
21240
  if (settled) return;
20491
21241
  settled = true;
20492
- resolve6({ statusCode: res.statusCode ?? 0, body: resData });
21242
+ resolve7({ statusCode: res.statusCode ?? 0, body: resData });
20493
21243
  });
20494
21244
  }
20495
21245
  );
@@ -21063,9 +21813,9 @@ var OutputService = class _OutputService {
21063
21813
  };
21064
21814
 
21065
21815
  // src/services/history.service.ts
21066
- var fs32 = __toESM(require("fs"));
21067
- var path39 = __toESM(require("path"));
21068
- var os26 = __toESM(require("os"));
21816
+ var fs34 = __toESM(require("fs"));
21817
+ var path42 = __toESM(require("path"));
21818
+ var os27 = __toESM(require("os"));
21069
21819
  var https7 = __toESM(require("https"));
21070
21820
  var http7 = __toESM(require("http"));
21071
21821
  var import_zod2 = require("zod");
@@ -21079,7 +21829,7 @@ var historyRecordSchema = import_zod2.z.object({
21079
21829
  content: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.unknown())]).optional()
21080
21830
  }).passthrough().optional()
21081
21831
  }).passthrough();
21082
- var API_BASE7 = resolveApiBaseUrl();
21832
+ var API_BASE8 = resolveApiBaseUrl();
21083
21833
  function extractText3(content) {
21084
21834
  if (typeof content === "string") return content;
21085
21835
  if (Array.isArray(content)) {
@@ -21092,7 +21842,7 @@ function parseJsonl(filePath) {
21092
21842
  const messages = [];
21093
21843
  let raw;
21094
21844
  try {
21095
- raw = fs32.readFileSync(filePath, "utf8");
21845
+ raw = fs34.readFileSync(filePath, "utf8");
21096
21846
  } catch (err) {
21097
21847
  if (err.code !== "ENOENT") {
21098
21848
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -21129,9 +21879,9 @@ function parseJsonl(filePath) {
21129
21879
  return messages;
21130
21880
  }
21131
21881
  function post(endpoint, body) {
21132
- return new Promise((resolve6) => {
21882
+ return new Promise((resolve7) => {
21133
21883
  const payload = JSON.stringify(body);
21134
- const u2 = new URL(`${API_BASE7}${endpoint}`);
21884
+ const u2 = new URL(`${API_BASE8}${endpoint}`);
21135
21885
  const transport = u2.protocol === "https:" ? https7 : http7;
21136
21886
  const req = transport.request(
21137
21887
  {
@@ -21150,17 +21900,17 @@ function post(endpoint, body) {
21150
21900
  res.resume();
21151
21901
  const ok = res.statusCode !== void 0 && res.statusCode >= 200 && res.statusCode < 300;
21152
21902
  if (!ok) log.warn("history:post", `${endpoint} \u2192 HTTP ${res.statusCode}`);
21153
- resolve6(ok);
21903
+ resolve7(ok);
21154
21904
  }
21155
21905
  );
21156
21906
  req.on("error", (err) => {
21157
21907
  log.warn("history:post", `${endpoint} network error`, err);
21158
- resolve6(false);
21908
+ resolve7(false);
21159
21909
  });
21160
21910
  req.on("timeout", () => {
21161
21911
  log.warn("history:post", `${endpoint} timeout after 15s`);
21162
21912
  req.destroy();
21163
- resolve6(false);
21913
+ resolve7(false);
21164
21914
  });
21165
21915
  req.write(payload);
21166
21916
  req.end();
@@ -21227,7 +21977,7 @@ var HistoryService = class _HistoryService {
21227
21977
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
21228
21978
  }
21229
21979
  get projectDir() {
21230
- return this.runtime.resolveHistoryDir(this.cwd) ?? path39.join(os26.homedir(), ".claude", "projects", encodeCwd(this.cwd));
21980
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path42.join(os27.homedir(), ".claude", "projects", encodeCwd(this.cwd));
21231
21981
  }
21232
21982
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
21233
21983
  setCurrentConversationId(id) {
@@ -21239,7 +21989,7 @@ var HistoryService = class _HistoryService {
21239
21989
  /** Return the current message count in the active conversation. */
21240
21990
  getCurrentMessageCount() {
21241
21991
  if (!this.currentConversationId) return 0;
21242
- const filePath = path39.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21992
+ const filePath = path42.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21243
21993
  return parseJsonl(filePath).length;
21244
21994
  }
21245
21995
  /**
@@ -21250,7 +22000,7 @@ var HistoryService = class _HistoryService {
21250
22000
  const deadline = Date.now() + timeoutMs;
21251
22001
  while (Date.now() < deadline) {
21252
22002
  if (!this.currentConversationId) return null;
21253
- const filePath = path39.join(this.projectDir, `${this.currentConversationId}.jsonl`);
22003
+ const filePath = path42.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21254
22004
  const messages = parseJsonl(filePath);
21255
22005
  if (messages.length > previousCount) {
21256
22006
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -21276,16 +22026,16 @@ var HistoryService = class _HistoryService {
21276
22026
  const dir = this.projectDir;
21277
22027
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
21278
22028
  try {
21279
- const files = fs32.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
22029
+ const files = fs34.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
21280
22030
  try {
21281
- const stat3 = fs32.statSync(path39.join(dir, e.name));
22031
+ const stat3 = fs34.statSync(path42.join(dir, e.name));
21282
22032
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
21283
22033
  } catch {
21284
22034
  return { name: e.name, mtime: 0, birthtime: 0 };
21285
22035
  }
21286
22036
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
21287
22037
  if (files.length > 0) {
21288
- this.currentConversationId = path39.basename(files[0].name, ".jsonl");
22038
+ this.currentConversationId = path42.basename(files[0].name, ".jsonl");
21289
22039
  }
21290
22040
  } catch {
21291
22041
  }
@@ -21319,13 +22069,13 @@ var HistoryService = class _HistoryService {
21319
22069
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
21320
22070
  let entries;
21321
22071
  try {
21322
- entries = fs32.readdirSync(dir, { withFileTypes: true });
22072
+ entries = fs34.readdirSync(dir, { withFileTypes: true });
21323
22073
  } catch {
21324
22074
  return null;
21325
22075
  }
21326
22076
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
21327
22077
  try {
21328
- const stat3 = fs32.statSync(path39.join(dir, e.name));
22078
+ const stat3 = fs34.statSync(path42.join(dir, e.name));
21329
22079
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
21330
22080
  } catch {
21331
22081
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -21334,12 +22084,12 @@ var HistoryService = class _HistoryService {
21334
22084
  if (files.length === 0) return null;
21335
22085
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
21336
22086
  if (!files.some((f) => f.name === targetFile)) return null;
21337
- return this.extractUsageFromFile(path39.join(dir, targetFile));
22087
+ return this.extractUsageFromFile(path42.join(dir, targetFile));
21338
22088
  }
21339
22089
  extractUsageFromFile(filePath) {
21340
22090
  let raw;
21341
22091
  try {
21342
- raw = fs32.readFileSync(filePath, "utf8");
22092
+ raw = fs34.readFileSync(filePath, "utf8");
21343
22093
  } catch {
21344
22094
  return null;
21345
22095
  }
@@ -21384,9 +22134,9 @@ var HistoryService = class _HistoryService {
21384
22134
  let totalCost = 0;
21385
22135
  let files;
21386
22136
  try {
21387
- files = fs32.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
22137
+ files = fs34.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
21388
22138
  try {
21389
- return fs32.statSync(path39.join(projectDir, f)).mtimeMs >= monthStartMs;
22139
+ return fs34.statSync(path42.join(projectDir, f)).mtimeMs >= monthStartMs;
21390
22140
  } catch {
21391
22141
  return false;
21392
22142
  }
@@ -21397,7 +22147,7 @@ var HistoryService = class _HistoryService {
21397
22147
  for (const file of files) {
21398
22148
  let raw;
21399
22149
  try {
21400
- raw = fs32.readFileSync(path39.join(projectDir, file), "utf8");
22150
+ raw = fs34.readFileSync(path42.join(projectDir, file), "utf8");
21401
22151
  } catch {
21402
22152
  continue;
21403
22153
  }
@@ -21461,7 +22211,7 @@ var HistoryService = class _HistoryService {
21461
22211
  * showing an empty conversation.
21462
22212
  */
21463
22213
  async loadConversation(sessionId) {
21464
- const filePath = path39.join(this.projectDir, `${sessionId}.jsonl`);
22214
+ const filePath = path42.join(this.projectDir, `${sessionId}.jsonl`);
21465
22215
  const messages = parseJsonl(filePath);
21466
22216
  if (messages.length === 0) return;
21467
22217
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -21515,7 +22265,7 @@ var HistoryService = class _HistoryService {
21515
22265
  if (!this.currentConversationId) return 0;
21516
22266
  }
21517
22267
  const sessionId = this.currentConversationId;
21518
- const filePath = path39.join(this.projectDir, `${sessionId}.jsonl`);
22268
+ const filePath = path42.join(this.projectDir, `${sessionId}.jsonl`);
21519
22269
  const messages = parseJsonl(filePath);
21520
22270
  if (messages.length === 0) return 0;
21521
22271
  const marker = this.lastUploadedUuid.get(sessionId);
@@ -21580,7 +22330,7 @@ var RepoDirtyTracker = class {
21580
22330
 
21581
22331
  // src/services/streaming-emitter.service.ts
21582
22332
  var import_crypto5 = require("crypto");
21583
- var API_BASE8 = resolveApiBaseUrl();
22333
+ var API_BASE9 = resolveApiBaseUrl();
21584
22334
  var TICK_MS = 50;
21585
22335
  var ANSWER_POLL_MS = 1500;
21586
22336
  var SELECTOR_STABLE_MS = 800;
@@ -21591,7 +22341,7 @@ var TAIL_KEEP_BYTES2 = 1.5 * 1024 * 1024;
21591
22341
  var StreamingEmitterService = class {
21592
22342
  constructor(opts) {
21593
22343
  this.opts = opts;
21594
- this.apiBase = opts.apiBaseUrl ?? API_BASE8;
22344
+ this.apiBase = opts.apiBaseUrl ?? API_BASE9;
21595
22345
  this.headers = {
21596
22346
  "Content-Type": "application/json",
21597
22347
  "X-Codeam-Protocol-Version": "2.0.0",
@@ -21941,13 +22691,13 @@ function fetchQuotaUsage(runtime, historySvc) {
21941
22691
  }
21942
22692
 
21943
22693
  // src/commands/start/keep-alive.ts
21944
- var import_child_process15 = require("child_process");
22694
+ var import_child_process18 = require("child_process");
21945
22695
  function buildKeepAlive(ctx) {
21946
22696
  let timer = null;
21947
22697
  async function setIdleTimeout(minutes) {
21948
22698
  if (!ctx.inCodespace || !ctx.codespaceName) return;
21949
- await new Promise((resolve6) => {
21950
- const proc = (0, import_child_process15.spawn)(
22699
+ await new Promise((resolve7) => {
22700
+ const proc = (0, import_child_process18.spawn)(
21951
22701
  "gh",
21952
22702
  [
21953
22703
  "api",
@@ -21960,8 +22710,8 @@ function buildKeepAlive(ctx) {
21960
22710
  { stdio: "ignore", detached: true }
21961
22711
  );
21962
22712
  proc.unref();
21963
- proc.on("exit", () => resolve6());
21964
- proc.on("error", () => resolve6());
22713
+ proc.on("exit", () => resolve7());
22714
+ proc.on("error", () => resolve7());
21965
22715
  });
21966
22716
  }
21967
22717
  return {
@@ -22109,6 +22859,7 @@ async function start(requestedAgent) {
22109
22859
  dirtyTracker: dirtyTracker ?? void 0
22110
22860
  }) : null;
22111
22861
  let streamingEmitter = null;
22862
+ let beads = null;
22112
22863
  const agent = new AgentService(
22113
22864
  runtime,
22114
22865
  {
@@ -22125,6 +22876,7 @@ async function start(requestedAgent) {
22125
22876
  relay.stop();
22126
22877
  void fileWatcher?.stop();
22127
22878
  turnFiles?.stop();
22879
+ void beads?.watcher.stop();
22128
22880
  void streamingEmitter?.stop();
22129
22881
  closeAllTerminals();
22130
22882
  cleanupAttachmentTempFiles();
@@ -22158,6 +22910,16 @@ async function start(requestedAgent) {
22158
22910
  await dispatchCommand(ctx, cmd);
22159
22911
  }, runtime.meta);
22160
22912
  ctx.relay = relay;
22913
+ void startBeadsForSession({
22914
+ sessionId: session.id,
22915
+ pluginId,
22916
+ pluginAuthToken: session.pluginAuthToken ?? void 0,
22917
+ agents: [session.agent],
22918
+ cwd
22919
+ }).then((started) => {
22920
+ beads = started;
22921
+ ctx.beads = started;
22922
+ });
22161
22923
  registerTerminalHandlers({
22162
22924
  onData: ({ sessionId, data }) => {
22163
22925
  void outputSvc.sendTerminalChunk(sessionId, data);
@@ -22174,6 +22936,7 @@ async function start(requestedAgent) {
22174
22936
  outputSvc.dispose();
22175
22937
  relay.stop();
22176
22938
  void fileWatcher?.stop();
22939
+ void beads?.watcher.stop();
22177
22940
  void streamingEmitter?.stop();
22178
22941
  closeAllTerminals();
22179
22942
  cleanupAttachmentTempFiles();
@@ -22312,7 +23075,7 @@ async function pair(args2 = []) {
22312
23075
  waitSpin.message(waitMessage());
22313
23076
  }, 1e3);
22314
23077
  countdownInterval.unref?.();
22315
- await new Promise((resolve6) => {
23078
+ await new Promise((resolve7) => {
22316
23079
  let stopPolling = null;
22317
23080
  function sigintHandler() {
22318
23081
  clearInterval(countdownInterval);
@@ -22360,7 +23123,7 @@ async function pair(args2 = []) {
22360
23123
  pluginAuthToken: info.pluginAuthToken
22361
23124
  });
22362
23125
  }
22363
- resolve6();
23126
+ resolve7();
22364
23127
  },
22365
23128
  () => {
22366
23129
  clearInterval(countdownInterval);
@@ -22412,8 +23175,8 @@ async function autoLinkAfterPair(opts) {
22412
23175
  }
22413
23176
 
22414
23177
  // src/commands/pair-auto.ts
22415
- var fs33 = __toESM(require("fs"));
22416
- var os27 = __toESM(require("os"));
23178
+ var fs35 = __toESM(require("fs"));
23179
+ var os28 = __toESM(require("os"));
22417
23180
  var import_crypto7 = require("crypto");
22418
23181
 
22419
23182
  // src/commands/start-infra-only.ts
@@ -22566,7 +23329,7 @@ async function startInfraOnly(agentId) {
22566
23329
  }
22567
23330
 
22568
23331
  // src/commands/pair-auto.ts
22569
- var API_BASE9 = resolveApiBaseUrl();
23332
+ var API_BASE10 = resolveApiBaseUrl();
22570
23333
  function fail(msg) {
22571
23334
  console.error(`
22572
23335
  ${msg}
@@ -22581,12 +23344,12 @@ function readTokenFromArgs(args2) {
22581
23344
  }
22582
23345
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
22583
23346
  if (fileFlag) {
22584
- const path46 = fileFlag.slice("--token-file=".length);
23347
+ const path49 = fileFlag.slice("--token-file=".length);
22585
23348
  try {
22586
- const content = fs33.readFileSync(path46, "utf8").trim();
22587
- if (content.length === 0) fail(`--token-file ${path46} is empty`);
23349
+ const content = fs35.readFileSync(path49, "utf8").trim();
23350
+ if (content.length === 0) fail(`--token-file ${path49} is empty`);
22588
23351
  try {
22589
- fs33.unlinkSync(path46);
23352
+ fs35.unlinkSync(path49);
22590
23353
  } catch {
22591
23354
  }
22592
23355
  return content;
@@ -22606,13 +23369,13 @@ function networkError(msg, cause) {
22606
23369
  return err;
22607
23370
  }
22608
23371
  async function claimOnce(token, pluginId) {
22609
- const url = `${API_BASE9}/api/pairing/claim-auto-token`;
23372
+ const url = `${API_BASE10}/api/pairing/claim-auto-token`;
22610
23373
  const body = {
22611
23374
  token,
22612
23375
  pluginId,
22613
23376
  ideName: "codeam-cli (codespace)",
22614
23377
  ideVersion: process.env.npm_package_version ?? "unknown",
22615
- hostname: os27.hostname(),
23378
+ hostname: os28.hostname(),
22616
23379
  codespaceName: process.env.CODESPACE_NAME ?? "",
22617
23380
  // Current git branch of the codespace's working directory, so the
22618
23381
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -22809,7 +23572,7 @@ function status() {
22809
23572
 
22810
23573
  // src/commands/logout.ts
22811
23574
  var import_picocolors7 = __toESM(require("picocolors"));
22812
- var API_BASE10 = resolveApiBaseUrl();
23575
+ var API_BASE11 = resolveApiBaseUrl();
22813
23576
  async function notifyBackendOffline() {
22814
23577
  const cfg = loadCliConfig();
22815
23578
  const pluginIds = /* @__PURE__ */ new Set([
@@ -22821,7 +23584,7 @@ async function notifyBackendOffline() {
22821
23584
  try {
22822
23585
  await Promise.all(
22823
23586
  Array.from(pluginIds).map(
22824
- (pluginId) => _postJson(`${API_BASE10}/api/plugin/heartbeat`, {
23587
+ (pluginId) => _postJson(`${API_BASE11}/api/plugin/heartbeat`, {
22825
23588
  pluginId,
22826
23589
  online: false
22827
23590
  }).catch((err) => {
@@ -22849,11 +23612,11 @@ async function logout() {
22849
23612
  var import_picocolors10 = __toESM(require("picocolors"));
22850
23613
 
22851
23614
  // src/services/providers/github-codespaces.ts
22852
- var import_child_process16 = require("child_process");
23615
+ var import_child_process19 = require("child_process");
22853
23616
  var import_util4 = require("util");
22854
23617
  var import_picocolors8 = __toESM(require("picocolors"));
22855
- var path40 = __toESM(require("path"));
22856
- var execFileP5 = (0, import_util4.promisify)(import_child_process16.execFile);
23618
+ var path43 = __toESM(require("path"));
23619
+ var execFileP5 = (0, import_util4.promisify)(import_child_process19.execFile);
22857
23620
  var MAX_BUFFER = 8 * 1024 * 1024;
22858
23621
  function resetStdinForChild() {
22859
23622
  if (process.stdin.isTTY) {
@@ -22896,12 +23659,12 @@ var GitHubCodespacesProvider = class {
22896
23659
  }
22897
23660
  if (!isAuthed) {
22898
23661
  resetStdinForChild();
22899
- await new Promise((resolve6, reject) => {
22900
- const proc = (0, import_child_process16.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
23662
+ await new Promise((resolve7, reject) => {
23663
+ const proc = (0, import_child_process19.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
22901
23664
  stdio: "inherit"
22902
23665
  });
22903
23666
  proc.on("exit", (code) => {
22904
- if (code === 0) resolve6();
23667
+ if (code === 0) resolve7();
22905
23668
  else reject(new Error("gh auth login failed."));
22906
23669
  });
22907
23670
  proc.on("error", reject);
@@ -22930,13 +23693,13 @@ var GitHubCodespacesProvider = class {
22930
23693
  }
22931
23694
  wt(noteLines.join("\n"), "One more permission needed");
22932
23695
  resetStdinForChild();
22933
- const refreshCode = await new Promise((resolve6, reject) => {
22934
- const proc = (0, import_child_process16.spawn)(
23696
+ const refreshCode = await new Promise((resolve7, reject) => {
23697
+ const proc = (0, import_child_process19.spawn)(
22935
23698
  "gh",
22936
23699
  ["auth", "refresh", "-h", "github.com", "-s", "codespace"],
22937
23700
  { stdio: "inherit" }
22938
23701
  );
22939
- proc.on("exit", (code) => resolve6(code ?? 1));
23702
+ proc.on("exit", (code) => resolve7(code ?? 1));
22940
23703
  proc.on("error", reject);
22941
23704
  });
22942
23705
  if (refreshCode !== 0) {
@@ -23080,10 +23843,10 @@ var GitHubCodespacesProvider = class {
23080
23843
  if (q(proceed) || !proceed) return;
23081
23844
  O2.step(`Installing gh via ${installCmd.describe}\u2026`);
23082
23845
  resetStdinForChild();
23083
- const ok = await new Promise((resolve6) => {
23084
- const proc = (0, import_child_process16.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
23085
- proc.on("exit", (code) => resolve6(code === 0));
23086
- proc.on("error", () => resolve6(false));
23846
+ const ok = await new Promise((resolve7) => {
23847
+ const proc = (0, import_child_process19.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
23848
+ proc.on("exit", (code) => resolve7(code === 0));
23849
+ proc.on("error", () => resolve7(false));
23087
23850
  });
23088
23851
  if (ok) O2.success("gh installed");
23089
23852
  else O2.error("gh install failed");
@@ -23107,14 +23870,14 @@ var GitHubCodespacesProvider = class {
23107
23870
  "Expanding GitHub scopes"
23108
23871
  );
23109
23872
  resetStdinForChild();
23110
- await new Promise((resolve6, reject) => {
23111
- const proc = (0, import_child_process16.spawn)(
23873
+ await new Promise((resolve7, reject) => {
23874
+ const proc = (0, import_child_process19.spawn)(
23112
23875
  "gh",
23113
23876
  ["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
23114
23877
  { stdio: "inherit" }
23115
23878
  );
23116
23879
  proc.on("exit", (code) => {
23117
- if (code === 0) resolve6();
23880
+ if (code === 0) resolve7();
23118
23881
  else reject(new Error(
23119
23882
  "gh auth refresh failed. Re-run `gh auth refresh -h github.com -s repo,read:org` manually."
23120
23883
  ));
@@ -23285,13 +24048,13 @@ var GitHubCodespacesProvider = class {
23285
24048
  }
23286
24049
  async streamCommand(workspaceId, command2) {
23287
24050
  resetStdinForChild();
23288
- return new Promise((resolve6, reject) => {
23289
- const proc = (0, import_child_process16.spawn)(
24051
+ return new Promise((resolve7, reject) => {
24052
+ const proc = (0, import_child_process19.spawn)(
23290
24053
  "gh",
23291
24054
  ["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
23292
24055
  { stdio: "inherit" }
23293
24056
  );
23294
- proc.on("exit", (code) => resolve6({ code: code ?? 0 }));
24057
+ proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
23295
24058
  proc.on("error", reject);
23296
24059
  });
23297
24060
  }
@@ -23312,12 +24075,12 @@ var GitHubCodespacesProvider = class {
23312
24075
  "--",
23313
24076
  `mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
23314
24077
  ];
23315
- await new Promise((resolve6, reject) => {
23316
- const tar = (0, import_child_process16.spawn)("tar", tarArgs, {
24078
+ await new Promise((resolve7, reject) => {
24079
+ const tar = (0, import_child_process19.spawn)("tar", tarArgs, {
23317
24080
  stdio: ["ignore", "pipe", "pipe"],
23318
24081
  env: tarEnv
23319
24082
  });
23320
- const ssh = (0, import_child_process16.spawn)("gh", sshArgs, {
24083
+ const ssh = (0, import_child_process19.spawn)("gh", sshArgs, {
23321
24084
  stdio: [tar.stdout, "pipe", "pipe"]
23322
24085
  });
23323
24086
  let tarErr = "";
@@ -23332,7 +24095,7 @@ var GitHubCodespacesProvider = class {
23332
24095
  ssh.on("error", reject);
23333
24096
  ssh.on("exit", (code) => {
23334
24097
  if (code === 0) {
23335
- resolve6();
24098
+ resolve7();
23336
24099
  } else {
23337
24100
  const reason = (sshErr || tarErr || `exit ${code}`).trim().slice(0, 500);
23338
24101
  reject(new Error(`Remote tar failed: ${reason}`));
@@ -23341,7 +24104,7 @@ var GitHubCodespacesProvider = class {
23341
24104
  });
23342
24105
  }
23343
24106
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
23344
- const remoteDir = path40.posix.dirname(remotePath);
24107
+ const remoteDir = path43.posix.dirname(remotePath);
23345
24108
  const parts = [
23346
24109
  `mkdir -p ${shellQuote(remoteDir)}`,
23347
24110
  `cat > ${shellQuote(remotePath)}`
@@ -23350,8 +24113,8 @@ var GitHubCodespacesProvider = class {
23350
24113
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote(remotePath)}`);
23351
24114
  }
23352
24115
  const cmd = parts.join(" && ");
23353
- await new Promise((resolve6, reject) => {
23354
- const proc = (0, import_child_process16.spawn)(
24116
+ await new Promise((resolve7, reject) => {
24117
+ const proc = (0, import_child_process19.spawn)(
23355
24118
  "gh",
23356
24119
  ["codespace", "ssh", "-c", workspaceId, "--", cmd],
23357
24120
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -23362,7 +24125,7 @@ var GitHubCodespacesProvider = class {
23362
24125
  });
23363
24126
  proc.on("error", reject);
23364
24127
  proc.on("exit", (code) => {
23365
- if (code === 0) resolve6();
24128
+ if (code === 0) resolve7();
23366
24129
  else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
23367
24130
  });
23368
24131
  proc.stdin?.write(contents);
@@ -23409,11 +24172,11 @@ function shellQuote(s) {
23409
24172
  }
23410
24173
 
23411
24174
  // src/services/providers/gitpod.ts
23412
- var import_child_process17 = require("child_process");
24175
+ var import_child_process20 = require("child_process");
23413
24176
  var import_util5 = require("util");
23414
- var path41 = __toESM(require("path"));
24177
+ var path44 = __toESM(require("path"));
23415
24178
  var import_picocolors9 = __toESM(require("picocolors"));
23416
- var execFileP6 = (0, import_util5.promisify)(import_child_process17.execFile);
24179
+ var execFileP6 = (0, import_util5.promisify)(import_child_process20.execFile);
23417
24180
  var MAX_BUFFER2 = 8 * 1024 * 1024;
23418
24181
  function resetStdinForChild2() {
23419
24182
  if (process.stdin.isTTY) {
@@ -23452,10 +24215,10 @@ var GitpodProvider = class {
23452
24215
  "Authenticating Gitpod"
23453
24216
  );
23454
24217
  resetStdinForChild2();
23455
- await new Promise((resolve6, reject) => {
23456
- const proc = (0, import_child_process17.spawn)("gitpod", ["login"], { stdio: "inherit" });
24218
+ await new Promise((resolve7, reject) => {
24219
+ const proc = (0, import_child_process20.spawn)("gitpod", ["login"], { stdio: "inherit" });
23457
24220
  proc.on("exit", (code) => {
23458
- if (code === 0) resolve6();
24221
+ if (code === 0) resolve7();
23459
24222
  else reject(new Error("gitpod login failed."));
23460
24223
  });
23461
24224
  proc.on("error", reject);
@@ -23604,13 +24367,13 @@ var GitpodProvider = class {
23604
24367
  }
23605
24368
  async streamCommand(workspaceId, command2) {
23606
24369
  resetStdinForChild2();
23607
- return new Promise((resolve6, reject) => {
23608
- const proc = (0, import_child_process17.spawn)(
24370
+ return new Promise((resolve7, reject) => {
24371
+ const proc = (0, import_child_process20.spawn)(
23609
24372
  "gitpod",
23610
24373
  ["workspace", "ssh", workspaceId, "--", "-tt", command2],
23611
24374
  { stdio: "inherit" }
23612
24375
  );
23613
- proc.on("exit", (code) => resolve6({ code: code ?? 0 }));
24376
+ proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
23614
24377
  proc.on("error", reject);
23615
24378
  });
23616
24379
  }
@@ -23624,12 +24387,12 @@ var GitpodProvider = class {
23624
24387
  tarArgs.push(".");
23625
24388
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
23626
24389
  const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
23627
- await new Promise((resolve6, reject) => {
23628
- const tar = (0, import_child_process17.spawn)("tar", tarArgs, {
24390
+ await new Promise((resolve7, reject) => {
24391
+ const tar = (0, import_child_process20.spawn)("tar", tarArgs, {
23629
24392
  stdio: ["ignore", "pipe", "pipe"],
23630
24393
  env: tarEnv
23631
24394
  });
23632
- const ssh = (0, import_child_process17.spawn)(
24395
+ const ssh = (0, import_child_process20.spawn)(
23633
24396
  "gitpod",
23634
24397
  ["workspace", "ssh", workspaceId, "--", remoteCmd],
23635
24398
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -23645,13 +24408,13 @@ var GitpodProvider = class {
23645
24408
  tar.on("error", reject);
23646
24409
  ssh.on("error", reject);
23647
24410
  ssh.on("exit", (code) => {
23648
- if (code === 0) resolve6();
24411
+ if (code === 0) resolve7();
23649
24412
  else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
23650
24413
  });
23651
24414
  });
23652
24415
  }
23653
24416
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
23654
- const remoteDir = path41.posix.dirname(remotePath);
24417
+ const remoteDir = path44.posix.dirname(remotePath);
23655
24418
  const parts = [
23656
24419
  `mkdir -p ${shellQuote2(remoteDir)}`,
23657
24420
  `cat > ${shellQuote2(remotePath)}`
@@ -23660,8 +24423,8 @@ var GitpodProvider = class {
23660
24423
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote2(remotePath)}`);
23661
24424
  }
23662
24425
  const cmd = parts.join(" && ");
23663
- await new Promise((resolve6, reject) => {
23664
- const proc = (0, import_child_process17.spawn)(
24426
+ await new Promise((resolve7, reject) => {
24427
+ const proc = (0, import_child_process20.spawn)(
23665
24428
  "gitpod",
23666
24429
  ["workspace", "ssh", workspaceId, "--", cmd],
23667
24430
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -23672,7 +24435,7 @@ var GitpodProvider = class {
23672
24435
  });
23673
24436
  proc.on("error", reject);
23674
24437
  proc.on("exit", (code) => {
23675
- if (code === 0) resolve6();
24438
+ if (code === 0) resolve7();
23676
24439
  else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
23677
24440
  });
23678
24441
  proc.stdin?.write(contents);
@@ -23685,10 +24448,10 @@ function shellQuote2(s) {
23685
24448
  }
23686
24449
 
23687
24450
  // src/services/providers/gitlab-workspaces.ts
23688
- var import_child_process18 = require("child_process");
24451
+ var import_child_process21 = require("child_process");
23689
24452
  var import_util6 = require("util");
23690
- var path42 = __toESM(require("path"));
23691
- var execFileP7 = (0, import_util6.promisify)(import_child_process18.execFile);
24453
+ var path45 = __toESM(require("path"));
24454
+ var execFileP7 = (0, import_util6.promisify)(import_child_process21.execFile);
23692
24455
  var MAX_BUFFER3 = 8 * 1024 * 1024;
23693
24456
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
23694
24457
  function resetStdinForChild3() {
@@ -23729,14 +24492,14 @@ var GitLabWorkspacesProvider = class {
23729
24492
  "Authenticating GitLab"
23730
24493
  );
23731
24494
  resetStdinForChild3();
23732
- await new Promise((resolve6, reject) => {
23733
- const proc = (0, import_child_process18.spawn)(
24495
+ await new Promise((resolve7, reject) => {
24496
+ const proc = (0, import_child_process21.spawn)(
23734
24497
  "glab",
23735
24498
  ["auth", "login", "--scopes", "api,read_user,read_repository"],
23736
24499
  { stdio: "inherit" }
23737
24500
  );
23738
24501
  proc.on("exit", (code) => {
23739
- if (code === 0) resolve6();
24502
+ if (code === 0) resolve7();
23740
24503
  else reject(new Error("glab auth login failed."));
23741
24504
  });
23742
24505
  proc.on("error", reject);
@@ -23901,13 +24664,13 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
23901
24664
  async streamCommand(workspaceId, command2) {
23902
24665
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
23903
24666
  resetStdinForChild3();
23904
- return new Promise((resolve6, reject) => {
23905
- const proc = (0, import_child_process18.spawn)(
24667
+ return new Promise((resolve7, reject) => {
24668
+ const proc = (0, import_child_process21.spawn)(
23906
24669
  "ssh",
23907
24670
  ["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
23908
24671
  { stdio: "inherit" }
23909
24672
  );
23910
- proc.on("exit", (code) => resolve6({ code: code ?? 0 }));
24673
+ proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
23911
24674
  proc.on("error", reject);
23912
24675
  });
23913
24676
  }
@@ -23922,9 +24685,9 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
23922
24685
  tarArgs.push(".");
23923
24686
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
23924
24687
  const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
23925
- await new Promise((resolve6, reject) => {
23926
- const tar = (0, import_child_process18.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
23927
- const ssh = (0, import_child_process18.spawn)(
24688
+ await new Promise((resolve7, reject) => {
24689
+ const tar = (0, import_child_process21.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
24690
+ const ssh = (0, import_child_process21.spawn)(
23928
24691
  "ssh",
23929
24692
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, remoteCmd],
23930
24693
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -23940,21 +24703,21 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
23940
24703
  tar.on("error", reject);
23941
24704
  ssh.on("error", reject);
23942
24705
  ssh.on("exit", (code) => {
23943
- if (code === 0) resolve6();
24706
+ if (code === 0) resolve7();
23944
24707
  else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
23945
24708
  });
23946
24709
  });
23947
24710
  }
23948
24711
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
23949
24712
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
23950
- const remoteDir = path42.posix.dirname(remotePath);
24713
+ const remoteDir = path45.posix.dirname(remotePath);
23951
24714
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
23952
24715
  if (options.mode != null) {
23953
24716
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
23954
24717
  }
23955
24718
  const cmd = parts.join(" && ");
23956
- await new Promise((resolve6, reject) => {
23957
- const proc = (0, import_child_process18.spawn)(
24719
+ await new Promise((resolve7, reject) => {
24720
+ const proc = (0, import_child_process21.spawn)(
23958
24721
  "ssh",
23959
24722
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
23960
24723
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -23965,7 +24728,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
23965
24728
  });
23966
24729
  proc.on("error", reject);
23967
24730
  proc.on("exit", (code) => {
23968
- if (code === 0) resolve6();
24731
+ if (code === 0) resolve7();
23969
24732
  else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
23970
24733
  });
23971
24734
  proc.stdin?.write(contents);
@@ -24013,10 +24776,10 @@ function shellQuote3(s) {
24013
24776
  }
24014
24777
 
24015
24778
  // src/services/providers/railway.ts
24016
- var import_child_process19 = require("child_process");
24779
+ var import_child_process22 = require("child_process");
24017
24780
  var import_util7 = require("util");
24018
- var path43 = __toESM(require("path"));
24019
- var execFileP8 = (0, import_util7.promisify)(import_child_process19.execFile);
24781
+ var path46 = __toESM(require("path"));
24782
+ var execFileP8 = (0, import_util7.promisify)(import_child_process22.execFile);
24020
24783
  var MAX_BUFFER4 = 8 * 1024 * 1024;
24021
24784
  function resetStdinForChild4() {
24022
24785
  if (process.stdin.isTTY) {
@@ -24056,10 +24819,10 @@ var RailwayProvider = class {
24056
24819
  "Authenticating Railway"
24057
24820
  );
24058
24821
  resetStdinForChild4();
24059
- await new Promise((resolve6, reject) => {
24060
- const proc = (0, import_child_process19.spawn)("railway", ["login"], { stdio: "inherit" });
24822
+ await new Promise((resolve7, reject) => {
24823
+ const proc = (0, import_child_process22.spawn)("railway", ["login"], { stdio: "inherit" });
24061
24824
  proc.on("exit", (code) => {
24062
- if (code === 0) resolve6();
24825
+ if (code === 0) resolve7();
24063
24826
  else reject(new Error("railway login failed."));
24064
24827
  });
24065
24828
  proc.on("error", reject);
@@ -24199,13 +24962,13 @@ var RailwayProvider = class {
24199
24962
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
24200
24963
  }
24201
24964
  resetStdinForChild4();
24202
- return new Promise((resolve6, reject) => {
24203
- const proc = (0, import_child_process19.spawn)(
24965
+ return new Promise((resolve7, reject) => {
24966
+ const proc = (0, import_child_process22.spawn)(
24204
24967
  "railway",
24205
24968
  ["shell", "--project", projectId, "--service", serviceId, "--command", command2],
24206
24969
  { stdio: "inherit" }
24207
24970
  );
24208
- proc.on("exit", (code) => resolve6({ code: code ?? 0 }));
24971
+ proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
24209
24972
  proc.on("error", reject);
24210
24973
  });
24211
24974
  }
@@ -24223,9 +24986,9 @@ var RailwayProvider = class {
24223
24986
  tarArgs.push(".");
24224
24987
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
24225
24988
  const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
24226
- await new Promise((resolve6, reject) => {
24227
- const tar = (0, import_child_process19.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
24228
- const sh = (0, import_child_process19.spawn)(
24989
+ await new Promise((resolve7, reject) => {
24990
+ const tar = (0, import_child_process22.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
24991
+ const sh = (0, import_child_process22.spawn)(
24229
24992
  "railway",
24230
24993
  ["shell", "--project", projectId, "--service", serviceId, "--command", remoteCmd],
24231
24994
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -24241,7 +25004,7 @@ var RailwayProvider = class {
24241
25004
  tar.on("error", reject);
24242
25005
  sh.on("error", reject);
24243
25006
  sh.on("exit", (code) => {
24244
- if (code === 0) resolve6();
25007
+ if (code === 0) resolve7();
24245
25008
  else reject(new Error(`Remote tar failed: ${(shErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
24246
25009
  });
24247
25010
  });
@@ -24251,14 +25014,14 @@ var RailwayProvider = class {
24251
25014
  if (!projectId || !serviceId) {
24252
25015
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
24253
25016
  }
24254
- const remoteDir = path43.posix.dirname(remotePath);
25017
+ const remoteDir = path46.posix.dirname(remotePath);
24255
25018
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
24256
25019
  if (options.mode != null) {
24257
25020
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
24258
25021
  }
24259
25022
  const cmd = parts.join(" && ");
24260
- await new Promise((resolve6, reject) => {
24261
- const proc = (0, import_child_process19.spawn)(
25023
+ await new Promise((resolve7, reject) => {
25024
+ const proc = (0, import_child_process22.spawn)(
24262
25025
  "railway",
24263
25026
  ["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
24264
25027
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -24269,7 +25032,7 @@ var RailwayProvider = class {
24269
25032
  });
24270
25033
  proc.on("error", reject);
24271
25034
  proc.on("exit", (code) => {
24272
- if (code === 0) resolve6();
25035
+ if (code === 0) resolve7();
24273
25036
  else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
24274
25037
  });
24275
25038
  proc.stdin?.write(contents);
@@ -24794,8 +25557,8 @@ async function stopWorkspaceFromLocal(target) {
24794
25557
  var import_node_dns = require("dns");
24795
25558
  var import_node_util4 = require("util");
24796
25559
  var import_node_crypto8 = require("crypto");
24797
- var fs34 = __toESM(require("fs"));
24798
- var path44 = __toESM(require("path"));
25560
+ var fs36 = __toESM(require("fs"));
25561
+ var path47 = __toESM(require("path"));
24799
25562
  var import_picocolors12 = __toESM(require("picocolors"));
24800
25563
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
24801
25564
  async function checkDns(apiBase) {
@@ -24851,13 +25614,13 @@ async function checkHealth(apiBase) {
24851
25614
  }
24852
25615
  }
24853
25616
  function checkConfigDir() {
24854
- const dir = path44.join(require("os").homedir(), ".codeam");
25617
+ const dir = path47.join(require("os").homedir(), ".codeam");
24855
25618
  try {
24856
- fs34.mkdirSync(dir, { recursive: true, mode: 448 });
24857
- const probe = path44.join(dir, ".doctor-probe");
24858
- fs34.writeFileSync(probe, "ok", { mode: 384 });
24859
- const read = fs34.readFileSync(probe, "utf8");
24860
- fs34.unlinkSync(probe);
25619
+ fs36.mkdirSync(dir, { recursive: true, mode: 448 });
25620
+ const probe = path47.join(dir, ".doctor-probe");
25621
+ fs36.writeFileSync(probe, "ok", { mode: 384 });
25622
+ const read = fs36.readFileSync(probe, "utf8");
25623
+ fs36.unlinkSync(probe);
24861
25624
  if (read !== "ok") throw new Error("write/read round-trip mismatch");
24862
25625
  return {
24863
25626
  id: "config-dir",
@@ -24897,9 +25660,9 @@ function checkSessions() {
24897
25660
  }
24898
25661
  }
24899
25662
  function checkAgentBinaries() {
24900
- const os29 = createOsStrategy();
25663
+ const os30 = createOsStrategy();
24901
25664
  return getEnabledAgents().map((meta) => {
24902
- const found = os29.findInPath(meta.binaryName);
25665
+ const found = os30.findInPath(meta.binaryName);
24903
25666
  return {
24904
25667
  id: `agent-${meta.id}`,
24905
25668
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -24921,7 +25684,7 @@ function checkNodePty() {
24921
25684
  detail: "not required on this platform"
24922
25685
  };
24923
25686
  }
24924
- const vendoredPath = path44.join(__dirname, "vendor", "node-pty");
25687
+ const vendoredPath = path47.join(__dirname, "vendor", "node-pty");
24925
25688
  for (const target of [vendoredPath, "node-pty"]) {
24926
25689
  try {
24927
25690
  require(target);
@@ -24963,7 +25726,7 @@ function checkChokidar() {
24963
25726
  }
24964
25727
  async function doctor(args2 = []) {
24965
25728
  const json = args2.includes("--json");
24966
- const cliVersion = true ? "2.32.9" : "0.0.0-dev";
25729
+ const cliVersion = true ? "2.33.0" : "0.0.0-dev";
24967
25730
  const apiBase = resolveApiBaseUrl();
24968
25731
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
24969
25732
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -25162,7 +25925,7 @@ async function completion(args2) {
25162
25925
  // src/commands/version.ts
25163
25926
  var import_picocolors13 = __toESM(require("picocolors"));
25164
25927
  function version2() {
25165
- const v = true ? "2.32.9" : "unknown";
25928
+ const v = true ? "2.33.0" : "unknown";
25166
25929
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
25167
25930
  }
25168
25931
 
@@ -25290,9 +26053,9 @@ function tryShowSubcommandHelp(cmd, args2) {
25290
26053
  var _subcommandHelpKeys = Object.keys(HELPS);
25291
26054
 
25292
26055
  // src/lib/updateNotifier.ts
25293
- var fs35 = __toESM(require("fs"));
25294
- var os28 = __toESM(require("os"));
25295
- var path45 = __toESM(require("path"));
26056
+ var fs37 = __toESM(require("fs"));
26057
+ var os29 = __toESM(require("os"));
26058
+ var path48 = __toESM(require("path"));
25296
26059
  var https8 = __toESM(require("https"));
25297
26060
  var import_node_child_process12 = require("child_process");
25298
26061
  var import_picocolors16 = __toESM(require("picocolors"));
@@ -25301,12 +26064,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
25301
26064
  var TTL_MS = 24 * 60 * 60 * 1e3;
25302
26065
  var REQUEST_TIMEOUT_MS = 1500;
25303
26066
  function cachePath() {
25304
- const dir = path45.join(os28.homedir(), ".codeam");
25305
- return path45.join(dir, "update-check.json");
26067
+ const dir = path48.join(os29.homedir(), ".codeam");
26068
+ return path48.join(dir, "update-check.json");
25306
26069
  }
25307
26070
  function readCache() {
25308
26071
  try {
25309
- const raw = fs35.readFileSync(cachePath(), "utf8");
26072
+ const raw = fs37.readFileSync(cachePath(), "utf8");
25310
26073
  const parsed = JSON.parse(raw);
25311
26074
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
25312
26075
  return parsed;
@@ -25317,10 +26080,10 @@ function readCache() {
25317
26080
  function writeCache(cache) {
25318
26081
  try {
25319
26082
  const file = cachePath();
25320
- fs35.mkdirSync(path45.dirname(file), { recursive: true });
26083
+ fs37.mkdirSync(path48.dirname(file), { recursive: true });
25321
26084
  const tmp = `${file}.${process.pid}.tmp`;
25322
- fs35.writeFileSync(tmp, JSON.stringify(cache));
25323
- fs35.renameSync(tmp, file);
26085
+ fs37.writeFileSync(tmp, JSON.stringify(cache));
26086
+ fs37.renameSync(tmp, file);
25324
26087
  } catch {
25325
26088
  }
25326
26089
  }
@@ -25338,14 +26101,14 @@ function compareSemver(a, b) {
25338
26101
  return 0;
25339
26102
  }
25340
26103
  function fetchLatest() {
25341
- return new Promise((resolve6) => {
26104
+ return new Promise((resolve7) => {
25342
26105
  const req = https8.get(
25343
26106
  REGISTRY_URL,
25344
26107
  { headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
25345
26108
  (res) => {
25346
26109
  if (res.statusCode !== 200) {
25347
26110
  res.resume();
25348
- resolve6(null);
26111
+ resolve7(null);
25349
26112
  return;
25350
26113
  }
25351
26114
  let buf = "";
@@ -25357,21 +26120,21 @@ function fetchLatest() {
25357
26120
  try {
25358
26121
  const json = JSON.parse(buf);
25359
26122
  if (typeof json.version === "string") {
25360
- resolve6(json.version);
26123
+ resolve7(json.version);
25361
26124
  } else {
25362
- resolve6(null);
26125
+ resolve7(null);
25363
26126
  }
25364
26127
  } catch {
25365
- resolve6(null);
26128
+ resolve7(null);
25366
26129
  }
25367
26130
  });
25368
26131
  }
25369
26132
  );
25370
26133
  req.on("timeout", () => {
25371
26134
  req.destroy();
25372
- resolve6(null);
26135
+ resolve7(null);
25373
26136
  });
25374
- req.on("error", () => resolve6(null));
26137
+ req.on("error", () => resolve7(null));
25375
26138
  });
25376
26139
  }
25377
26140
  function notifyIfStale(currentVersion, latest) {
@@ -25394,8 +26157,8 @@ function isLinkedInstall() {
25394
26157
  timeout: 2e3
25395
26158
  }).trim();
25396
26159
  if (!root) return false;
25397
- const pkgPath = path45.join(root, PKG_NAME);
25398
- return fs35.lstatSync(pkgPath).isSymbolicLink();
26160
+ const pkgPath = path48.join(root, PKG_NAME);
26161
+ return fs37.lstatSync(pkgPath).isSymbolicLink();
25399
26162
  } catch {
25400
26163
  return false;
25401
26164
  }
@@ -25431,7 +26194,7 @@ function maybeAutoUpdate(currentVersion, latest) {
25431
26194
  return;
25432
26195
  }
25433
26196
  try {
25434
- fs35.unlinkSync(cachePath());
26197
+ fs37.unlinkSync(cachePath());
25435
26198
  } catch {
25436
26199
  }
25437
26200
  process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
@@ -25448,7 +26211,7 @@ function checkForUpdates() {
25448
26211
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
25449
26212
  if (process.env.CI) return;
25450
26213
  if (!process.stdout.isTTY) return;
25451
- const current = true ? "2.32.9" : null;
26214
+ const current = true ? "2.33.0" : null;
25452
26215
  if (!current) return;
25453
26216
  const cache = readCache();
25454
26217
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;