codeam-cli 2.35.8 → 2.36.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 +12 -0
  2. package/dist/index.js +633 -339
  3. package/package.json +1 -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.35.8",
501
+ version: "2.36.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",
@@ -1186,8 +1186,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
1186
1186
  return decodedFile;
1187
1187
  };
1188
1188
  }
1189
- function normalizeWindowsPath(path50) {
1190
- return path50.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1189
+ function normalizeWindowsPath(path51) {
1190
+ return path51.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1191
1191
  }
1192
1192
 
1193
1193
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3667,9 +3667,9 @@ async function addSourceContext(frames) {
3667
3667
  LRU_FILE_CONTENTS_CACHE.reduce();
3668
3668
  return frames;
3669
3669
  }
3670
- function getContextLinesFromFile(path50, ranges, output) {
3670
+ function getContextLinesFromFile(path51, ranges, output) {
3671
3671
  return new Promise((resolve7) => {
3672
- const stream = (0, import_node_fs.createReadStream)(path50);
3672
+ const stream = (0, import_node_fs.createReadStream)(path51);
3673
3673
  const lineReaded = (0, import_node_readline.createInterface)({
3674
3674
  input: stream
3675
3675
  });
@@ -3684,7 +3684,7 @@ function getContextLinesFromFile(path50, ranges, output) {
3684
3684
  let rangeStart = range[0];
3685
3685
  let rangeEnd = range[1];
3686
3686
  function onStreamError() {
3687
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path50, 1);
3687
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path51, 1);
3688
3688
  lineReaded.close();
3689
3689
  lineReaded.removeAllListeners();
3690
3690
  destroyStreamAndResolve();
@@ -3745,8 +3745,8 @@ function clearLineContext(frame) {
3745
3745
  delete frame.context_line;
3746
3746
  delete frame.post_context;
3747
3747
  }
3748
- function shouldSkipContextLinesForFile(path50) {
3749
- return path50.startsWith("node:") || path50.endsWith(".min.js") || path50.endsWith(".min.cjs") || path50.endsWith(".min.mjs") || path50.startsWith("data:");
3748
+ function shouldSkipContextLinesForFile(path51) {
3749
+ return path51.startsWith("node:") || path51.endsWith(".min.js") || path51.endsWith(".min.cjs") || path51.endsWith(".min.mjs") || path51.startsWith("data:");
3750
3750
  }
3751
3751
  function shouldSkipContextLinesForFrame(frame) {
3752
3752
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5900,7 +5900,7 @@ function readAnonId() {
5900
5900
  }
5901
5901
  function superProperties() {
5902
5902
  return {
5903
- cliVersion: true ? "2.35.8" : "0.0.0-dev",
5903
+ cliVersion: true ? "2.36.0" : "0.0.0-dev",
5904
5904
  nodeVersion: process.version,
5905
5905
  platform: process.platform,
5906
5906
  arch: process.arch,
@@ -7248,10 +7248,10 @@ function buildForPlatform(platform2) {
7248
7248
  var import_node_crypto4 = require("crypto");
7249
7249
 
7250
7250
  // src/agents/claude/resolver.ts
7251
- function buildClaudeLaunch(extraArgs = [], os31 = createOsStrategy()) {
7252
- const found = os31.findInPath("claude") ?? os31.findInPath("claude-code");
7251
+ function buildClaudeLaunch(extraArgs = [], os32 = createOsStrategy()) {
7252
+ const found = os32.findInPath("claude") ?? os32.findInPath("claude-code");
7253
7253
  if (!found) return null;
7254
- return os31.buildLaunch(found, extraArgs);
7254
+ return os32.buildLaunch(found, extraArgs);
7255
7255
  }
7256
7256
 
7257
7257
  // src/agents/claude/installer.ts
@@ -9978,13 +9978,13 @@ function detectStartupBanner(lines) {
9978
9978
  while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
9979
9979
  if (metaIdx - artStart < 2) return null;
9980
9980
  const pathLine = (lines[metaIdx + 1] ?? "").trim();
9981
- const path50 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9981
+ const path51 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9982
9982
  return {
9983
9983
  title: "",
9984
9984
  subtitle: lines[metaIdx].trim(),
9985
- path: path50,
9985
+ path: path51,
9986
9986
  startIdx: artStart,
9987
- endIdx: metaIdx + (path50 ? 1 : 0)
9987
+ endIdx: metaIdx + (path51 ? 1 : 0)
9988
9988
  };
9989
9989
  }
9990
9990
 
@@ -9994,8 +9994,8 @@ var ClaudeRuntimeStrategy = class {
9994
9994
  meta = getAgent("claude");
9995
9995
  mode = "interactive";
9996
9996
  os;
9997
- constructor(os31) {
9998
- this.os = os31;
9997
+ constructor(os32) {
9998
+ this.os = os32;
9999
9999
  }
10000
10000
  /**
10001
10001
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -11025,8 +11025,8 @@ function codexCredentialLocator() {
11025
11025
  function codexLoginLauncher() {
11026
11026
  return {
11027
11027
  async ensureInstalled() {
11028
- const os31 = createOsStrategy();
11029
- return os31.findInPath("codex") !== null;
11028
+ const os32 = createOsStrategy();
11029
+ return os32.findInPath("codex") !== null;
11030
11030
  },
11031
11031
  launch() {
11032
11032
  return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -11049,8 +11049,8 @@ var CodexRuntimeStrategy = class {
11049
11049
  meta = getAgent("codex");
11050
11050
  mode = "interactive";
11051
11051
  os;
11052
- constructor(os31) {
11053
- this.os = os31;
11052
+ constructor(os32) {
11053
+ this.os = os32;
11054
11054
  }
11055
11055
  async prepareLaunch() {
11056
11056
  let binary = this.os.findInPath("codex");
@@ -11156,12 +11156,12 @@ var CodexRuntimeStrategy = class {
11156
11156
  });
11157
11157
  }
11158
11158
  };
11159
- function resolveNpm(os31) {
11160
- return os31.id === "win32" ? "npm.cmd" : "npm";
11159
+ function resolveNpm(os32) {
11160
+ return os32.id === "win32" ? "npm.cmd" : "npm";
11161
11161
  }
11162
- async function installCodexViaNpm(os31) {
11162
+ async function installCodexViaNpm(os32) {
11163
11163
  return new Promise((resolve7, reject) => {
11164
- const proc = (0, import_node_child_process4.spawn)(resolveNpm(os31), ["install", "-g", "@openai/codex"], {
11164
+ const proc = (0, import_node_child_process4.spawn)(resolveNpm(os32), ["install", "-g", "@openai/codex"], {
11165
11165
  stdio: "inherit"
11166
11166
  });
11167
11167
  proc.on("close", (code) => {
@@ -11178,16 +11178,16 @@ async function installCodexViaNpm(os31) {
11178
11178
  });
11179
11179
  });
11180
11180
  }
11181
- function augmentNpmGlobalBin(os31) {
11181
+ function augmentNpmGlobalBin(os32) {
11182
11182
  try {
11183
- const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os31), ["prefix", "-g"], {
11183
+ const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os32), ["prefix", "-g"], {
11184
11184
  stdio: ["ignore", "pipe", "ignore"]
11185
11185
  });
11186
11186
  if (result.status !== 0) return;
11187
11187
  const prefix = result.stdout.toString().trim();
11188
11188
  if (!prefix) return;
11189
- const binDir = os31.id === "win32" ? prefix : path17.join(prefix, "bin");
11190
- os31.augmentPath([binDir]);
11189
+ const binDir = os32.id === "win32" ? prefix : path17.join(prefix, "bin");
11190
+ os32.augmentPath([binDir]);
11191
11191
  } catch {
11192
11192
  }
11193
11193
  }
@@ -11271,9 +11271,9 @@ var import_node_child_process7 = require("child_process");
11271
11271
  // src/agents/coderabbit/installer.ts
11272
11272
  var import_node_child_process5 = require("child_process");
11273
11273
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
11274
- async function ensureCoderabbitInstalled(os31) {
11275
- if (os31.findInPath("coderabbit")) return true;
11276
- if (os31.id === "win32") {
11274
+ async function ensureCoderabbitInstalled(os32) {
11275
+ if (os32.findInPath("coderabbit")) return true;
11276
+ if (os32.id === "win32") {
11277
11277
  console.error(
11278
11278
  "\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"
11279
11279
  );
@@ -11288,8 +11288,8 @@ async function ensureCoderabbitInstalled(os31) {
11288
11288
  proc.on("error", () => resolve7(false));
11289
11289
  });
11290
11290
  if (!ok) return false;
11291
- os31.augmentPath([`${os31.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11292
- return os31.findInPath("coderabbit") !== null;
11291
+ os32.augmentPath([`${os32.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11292
+ return os32.findInPath("coderabbit") !== null;
11293
11293
  }
11294
11294
 
11295
11295
  // src/agents/coderabbit/link.ts
@@ -11316,10 +11316,10 @@ function coderabbitCredentialLocator() {
11316
11316
  extract: extractLocalCoderabbitToken
11317
11317
  };
11318
11318
  }
11319
- function coderabbitLoginLauncher(os31) {
11319
+ function coderabbitLoginLauncher(os32) {
11320
11320
  return {
11321
11321
  async ensureInstalled() {
11322
- return ensureCoderabbitInstalled(os31);
11322
+ return ensureCoderabbitInstalled(os32);
11323
11323
  },
11324
11324
  launch() {
11325
11325
  return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
@@ -11342,11 +11342,11 @@ function parseReview(stdout) {
11342
11342
  for (const line of lines) {
11343
11343
  const m = line.match(HUNK_LINE_RE);
11344
11344
  if (!m) continue;
11345
- const [, path50, lineNo, sevToken, message] = m;
11346
- if (!path50 || !lineNo || !message) continue;
11345
+ const [, path51, lineNo, sevToken, message] = m;
11346
+ if (!path51 || !lineNo || !message) continue;
11347
11347
  const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
11348
11348
  hunks.push({
11349
- path: path50.trim(),
11349
+ path: path51.trim(),
11350
11350
  line: Number(lineNo),
11351
11351
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
11352
11352
  message: cleanedMessage
@@ -11365,8 +11365,8 @@ var CoderabbitRuntimeStrategy = class {
11365
11365
  meta = getAgent("coderabbit");
11366
11366
  mode = "batch";
11367
11367
  os;
11368
- constructor(os31) {
11369
- this.os = os31;
11368
+ constructor(os32) {
11369
+ this.os = os32;
11370
11370
  }
11371
11371
  getDefaultArgs() {
11372
11372
  return ["review"];
@@ -11481,10 +11481,10 @@ function cursorCredentialLocator() {
11481
11481
  extract: extractLocalCursorToken
11482
11482
  };
11483
11483
  }
11484
- function cursorLoginLauncher(os31) {
11484
+ function cursorLoginLauncher(os32) {
11485
11485
  return {
11486
11486
  async ensureInstalled() {
11487
- if (os31.findInPath("cursor-agent")) return true;
11487
+ if (os32.findInPath("cursor-agent")) return true;
11488
11488
  console.error(
11489
11489
  "\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"
11490
11490
  );
@@ -11546,8 +11546,8 @@ var CursorRuntimeStrategy = class {
11546
11546
  meta = getAgent("cursor");
11547
11547
  mode = "interactive";
11548
11548
  os;
11549
- constructor(os31) {
11550
- this.os = os31;
11549
+ constructor(os32) {
11550
+ this.os = os32;
11551
11551
  }
11552
11552
  async prepareLaunch() {
11553
11553
  const binary = this.os.findInPath("cursor-agent");
@@ -11667,10 +11667,10 @@ function aiderCredentialLocator() {
11667
11667
  extract: extractLocalAiderToken
11668
11668
  };
11669
11669
  }
11670
- function aiderLoginLauncher(os31) {
11670
+ function aiderLoginLauncher(os32) {
11671
11671
  return {
11672
11672
  async ensureInstalled() {
11673
- if (os31.findInPath("aider")) return true;
11673
+ if (os32.findInPath("aider")) return true;
11674
11674
  console.error(
11675
11675
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
11676
11676
  );
@@ -11680,7 +11680,7 @@ function aiderLoginLauncher(os31) {
11680
11680
  console.error(
11681
11681
  "\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"
11682
11682
  );
11683
- return (0, import_node_child_process9.spawn)(os31.id === "win32" ? "cmd.exe" : "sh", os31.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11683
+ return (0, import_node_child_process9.spawn)(os32.id === "win32" ? "cmd.exe" : "sh", os32.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11684
11684
  stdio: "ignore"
11685
11685
  });
11686
11686
  }
@@ -11752,8 +11752,8 @@ var AiderRuntimeStrategy = class {
11752
11752
  meta = getAgent("aider");
11753
11753
  mode = "interactive";
11754
11754
  os;
11755
- constructor(os31) {
11756
- this.os = os31;
11755
+ constructor(os32) {
11756
+ this.os = os32;
11757
11757
  }
11758
11758
  async prepareLaunch() {
11759
11759
  const binary = this.os.findInPath("aider");
@@ -11882,8 +11882,8 @@ function geminiCredentialLocator() {
11882
11882
  function geminiLoginLauncher() {
11883
11883
  return {
11884
11884
  async ensureInstalled() {
11885
- const os31 = createOsStrategy();
11886
- return os31.findInPath("gemini") !== null;
11885
+ const os32 = createOsStrategy();
11886
+ return os32.findInPath("gemini") !== null;
11887
11887
  },
11888
11888
  launch() {
11889
11889
  return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -11916,8 +11916,8 @@ var GeminiRuntimeStrategy = class {
11916
11916
  meta = getAgent("gemini");
11917
11917
  mode = "interactive";
11918
11918
  os;
11919
- constructor(os31) {
11920
- this.os = os31;
11919
+ constructor(os32) {
11920
+ this.os = os32;
11921
11921
  }
11922
11922
  async prepareLaunch() {
11923
11923
  const binary = this.os.findInPath("gemini");
@@ -12017,18 +12017,18 @@ var GeminiRuntimeStrategy = class {
12017
12017
 
12018
12018
  // src/agents/registry.ts
12019
12019
  var runtimeBuilders = {
12020
- claude: (os31) => new ClaudeRuntimeStrategy(os31),
12021
- codex: (os31) => new CodexRuntimeStrategy(os31),
12022
- coderabbit: (os31) => new CoderabbitRuntimeStrategy(os31),
12023
- cursor: (os31) => new CursorRuntimeStrategy(os31),
12024
- aider: (os31) => new AiderRuntimeStrategy(os31),
12025
- gemini: (os31) => new GeminiRuntimeStrategy(os31)
12020
+ claude: (os32) => new ClaudeRuntimeStrategy(os32),
12021
+ codex: (os32) => new CodexRuntimeStrategy(os32),
12022
+ coderabbit: (os32) => new CoderabbitRuntimeStrategy(os32),
12023
+ cursor: (os32) => new CursorRuntimeStrategy(os32),
12024
+ aider: (os32) => new AiderRuntimeStrategy(os32),
12025
+ gemini: (os32) => new GeminiRuntimeStrategy(os32)
12026
12026
  };
12027
12027
  var deployBuilders = {
12028
12028
  claude: () => new ClaudeDeployStrategy(),
12029
12029
  codex: () => new CodexDeployStrategy()
12030
12030
  };
12031
- function createAgentStrategy(agent, os31 = createOsStrategy()) {
12031
+ function createAgentStrategy(agent, os32 = createOsStrategy()) {
12032
12032
  if (!AGENT_REGISTRY[agent]?.enabled) {
12033
12033
  throw new Error(
12034
12034
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -12038,10 +12038,10 @@ function createAgentStrategy(agent, os31 = createOsStrategy()) {
12038
12038
  if (!build) {
12039
12039
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
12040
12040
  }
12041
- return build(os31);
12041
+ return build(os32);
12042
12042
  }
12043
- function createInteractiveAgentStrategy(agent, os31 = createOsStrategy()) {
12044
- const s = createAgentStrategy(agent, os31);
12043
+ function createInteractiveAgentStrategy(agent, os32 = createOsStrategy()) {
12044
+ const s = createAgentStrategy(agent, os32);
12045
12045
  if (s.mode !== "interactive") {
12046
12046
  throw new Error(
12047
12047
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -14664,6 +14664,14 @@ var AcpClient = class {
14664
14664
  * the turn alive while the adapter is demonstrably working. Null
14665
14665
  * between prompts. */
14666
14666
  promptIdle = null;
14667
+ /** Tool calls the adapter has started but not yet reported terminal
14668
+ * (`completed`/`failed`). A long-running tool — typecheck, build,
14669
+ * install, a big test run — emits NO `session/update` for its whole
14670
+ * duration, which can exceed the idle window and falsely trip the
14671
+ * watchdog. While ANY tool is outstanding we SUSPEND the watchdog
14672
+ * (the agent is demonstrably working, just blocked on the tool), and
14673
+ * re-arm only once the last one finishes. Reset per prompt. */
14674
+ pendingToolCalls = /* @__PURE__ */ new Set();
14667
14675
  /**
14668
14676
  * Spawn the adapter + perform the initial handshake (initialize
14669
14677
  * → newSession). Returns the ACP-assigned sessionId so the caller
@@ -14778,6 +14786,7 @@ var AcpClient = class {
14778
14786
  )
14779
14787
  );
14780
14788
  this.promptIdle = idle;
14789
+ this.pendingToolCalls.clear();
14781
14790
  try {
14782
14791
  const result = await Promise.race([send, idle.promise]);
14783
14792
  log.info(
@@ -14880,11 +14889,35 @@ var AcpClient = class {
14880
14889
  log.trace("acpClient", "stop teardown error", err);
14881
14890
  }
14882
14891
  }
14892
+ /**
14893
+ * Drive the idle watchdog off the tool-call lifecycle so a long but
14894
+ * alive tool (typecheck / build / install) can't trip it.
14895
+ *
14896
+ * - `tool_call` (a tool starts) → track + suspend
14897
+ * - `tool_call_update` completed/failed → untrack; re-arm iff
14898
+ * no tool still running
14899
+ * - anything else (thought / message / …) → re-arm, unless a tool
14900
+ * is still outstanding
14901
+ */
14902
+ trackToolCallIdle(params) {
14903
+ const u2 = params.update;
14904
+ if (u2.sessionUpdate === "tool_call" && typeof u2.toolCallId === "string") {
14905
+ this.pendingToolCalls.add(u2.toolCallId);
14906
+ this.promptIdle?.suspend();
14907
+ return;
14908
+ }
14909
+ if (u2.sessionUpdate === "tool_call_update" && (u2.status === "completed" || u2.status === "failed")) {
14910
+ if (typeof u2.toolCallId === "string") this.pendingToolCalls.delete(u2.toolCallId);
14911
+ if (this.pendingToolCalls.size === 0) this.promptIdle?.bump();
14912
+ return;
14913
+ }
14914
+ if (this.pendingToolCalls.size === 0) this.promptIdle?.bump();
14915
+ }
14883
14916
  // ─── Client surface (what the agent calls into) ───────────────────
14884
14917
  buildClient() {
14885
14918
  return {
14886
14919
  sessionUpdate: async (params) => {
14887
- this.promptIdle?.bump();
14920
+ this.trackToolCallIdle(params);
14888
14921
  this.opts.onSessionUpdate(params);
14889
14922
  },
14890
14923
  requestPermission: async (params) => {
@@ -15797,11 +15830,11 @@ function extractSelectPrompt(text) {
15797
15830
  }
15798
15831
 
15799
15832
  // src/commands/start/handlers.ts
15800
- var fs32 = __toESM(require("fs"));
15801
- var os26 = __toESM(require("os"));
15802
- var path39 = __toESM(require("path"));
15833
+ var fs33 = __toESM(require("fs"));
15834
+ var os27 = __toESM(require("os"));
15835
+ var path40 = __toESM(require("path"));
15803
15836
  var import_crypto3 = require("crypto");
15804
- var import_child_process17 = require("child_process");
15837
+ var import_child_process18 = require("child_process");
15805
15838
 
15806
15839
  // src/lib/payload.ts
15807
15840
  var import_zod = require("zod");
@@ -17476,7 +17509,8 @@ var BdAdapter = class {
17476
17509
  }
17477
17510
  const env = { ...process.env };
17478
17511
  env.BEADS_DIR = this.opts.beadsDir ?? defaultBeadsHomeDir();
17479
- log.trace("beads", `bd ${args2.join(" ")} (BEADS_DIR=${env.BEADS_DIR})`);
17512
+ env.BEADS_DOLT_SHARED_SERVER = "1";
17513
+ log.trace("beads", `bd ${args2.join(" ")} (BEADS_DIR=${env.BEADS_DIR}, shared-server)`);
17480
17514
  return _spawnSeam.run(binary, args2, { cwd: this.opts.cwd, env });
17481
17515
  }
17482
17516
  /**
@@ -17550,10 +17584,10 @@ function defaultBeadsHomeDir() {
17550
17584
  }
17551
17585
 
17552
17586
  // src/beads/provisioner.ts
17553
- var import_child_process15 = require("child_process");
17554
- var fs30 = __toESM(require("fs"));
17555
- var os25 = __toESM(require("os"));
17556
- var path36 = __toESM(require("path"));
17587
+ var import_child_process17 = require("child_process");
17588
+ var fs32 = __toESM(require("fs"));
17589
+ var os26 = __toESM(require("os"));
17590
+ var path38 = __toESM(require("path"));
17557
17591
 
17558
17592
  // src/beads/install-bd.ts
17559
17593
  var import_child_process14 = require("child_process");
@@ -17616,6 +17650,312 @@ async function installBd(platform2 = process.platform) {
17616
17650
  return result;
17617
17651
  }
17618
17652
 
17653
+ // src/beads/install-dolt.ts
17654
+ var import_child_process15 = require("child_process");
17655
+ var fs30 = __toESM(require("fs"));
17656
+ var os25 = __toESM(require("os"));
17657
+ var path36 = __toESM(require("path"));
17658
+ var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
17659
+ var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
17660
+ function resolveDoltInstallStrategy(platform2) {
17661
+ if (platform2 === "win32") {
17662
+ const script = [
17663
+ `$ErrorActionPreference='Stop';`,
17664
+ `$u='${DOLT_MSI_URL}';`,
17665
+ `$o="$env:TEMP\\dolt-install.msi";`,
17666
+ `Invoke-WebRequest -Uri $u -OutFile $o;`,
17667
+ `Start-Process msiexec.exe -ArgumentList '/i',('"'+$o+'"'),'/quiet','/norestart' -Wait`
17668
+ ].join(" ");
17669
+ return {
17670
+ command: "powershell.exe",
17671
+ args: [
17672
+ "-NoProfile",
17673
+ "-NonInteractive",
17674
+ "-ExecutionPolicy",
17675
+ "Bypass",
17676
+ "-Command",
17677
+ script
17678
+ ],
17679
+ description: "PowerShell: download official dolt MSI + silent msiexec"
17680
+ };
17681
+ }
17682
+ if (platform2 === "darwin") {
17683
+ return {
17684
+ command: "brew",
17685
+ args: ["install", "dolt"],
17686
+ description: "brew install dolt"
17687
+ };
17688
+ }
17689
+ return {
17690
+ command: "bash",
17691
+ args: ["-c", `curl -L ${DOLT_INSTALL_SH_URL} | sudo bash`],
17692
+ description: `curl -L ${DOLT_INSTALL_SH_URL} | sudo bash (\u2192 /usr/local/bin)`
17693
+ };
17694
+ }
17695
+ var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
17696
+ function doltPlatformTuple(platform2, arch) {
17697
+ const os32 = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "darwin" : "linux";
17698
+ const a = arch === "x64" ? "amd64" : arch === "arm64" ? "arm64" : null;
17699
+ if (!a) return null;
17700
+ if (os32 === "windows" && a !== "amd64") return null;
17701
+ return `${os32}-${a}`;
17702
+ }
17703
+ function resolveDoltTarballStrategy(targetDir, platform2, arch) {
17704
+ const tuple = doltPlatformTuple(platform2, arch);
17705
+ if (!tuple) return null;
17706
+ if (platform2 === "win32") {
17707
+ const url2 = `${DOLT_RELEASE_BASE}/dolt-${tuple}.zip`;
17708
+ const script = [
17709
+ `$ErrorActionPreference='Stop';`,
17710
+ `New-Item -ItemType Directory -Force -Path '${targetDir}' | Out-Null;`,
17711
+ `$u='${url2}';`,
17712
+ `$o="$env:TEMP\\dolt-cs.zip";`,
17713
+ `Invoke-WebRequest -Uri $u -OutFile $o;`,
17714
+ `$x="$env:TEMP\\dolt-cs";`,
17715
+ `Expand-Archive -Path $o -DestinationPath $x -Force;`,
17716
+ `Copy-Item "$x\\dolt-${tuple}\\bin\\dolt.exe" '${targetDir}\\dolt.exe' -Force`
17717
+ ].join(" ");
17718
+ return {
17719
+ command: "powershell.exe",
17720
+ args: ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", script],
17721
+ description: `download dolt ${tuple} zip \u2192 ${targetDir} (no sudo)`
17722
+ };
17723
+ }
17724
+ const url = `${DOLT_RELEASE_BASE}/dolt-${tuple}.tar.gz`;
17725
+ const cmd = `mkdir -p "${targetDir}" && curl -fsSL "${url}" | tar -xz -C "${targetDir}" --strip-components=2 "dolt-${tuple}/bin/dolt" && chmod +x "${targetDir}/dolt"`;
17726
+ return {
17727
+ command: "bash",
17728
+ args: ["-c", cmd],
17729
+ description: `download dolt ${tuple} tarball \u2192 ${targetDir} (no sudo)`
17730
+ };
17731
+ }
17732
+ async function installDoltToDir(targetDir, platform2 = process.platform, arch = process.arch) {
17733
+ const strategy = resolveDoltTarballStrategy(targetDir, platform2, arch);
17734
+ if (!strategy) {
17735
+ log.warn("beads", `no dolt prebuilt for ${platform2}/${arch} \u2014 cannot fall back`);
17736
+ return { ok: false, code: -1, stderr: `unsupported platform ${platform2}/${arch}` };
17737
+ }
17738
+ log.info("beads", `dolt fallback: ${strategy.description}`);
17739
+ const result = await _doltInstallSpawnSeam.run(strategy);
17740
+ if (!result.ok) {
17741
+ log.warn("beads", `dolt tarball fallback failed (code=${result.code}): ${result.stderr.slice(0, 200)}`);
17742
+ }
17743
+ return result;
17744
+ }
17745
+ var _doltPathSeam = {
17746
+ homedir: () => os25.homedir(),
17747
+ getPath: () => process.env.PATH ?? "",
17748
+ setPath: (p2) => {
17749
+ process.env.PATH = p2;
17750
+ },
17751
+ exists: (p2) => {
17752
+ try {
17753
+ fs30.accessSync(p2, fs30.constants.F_OK);
17754
+ return true;
17755
+ } catch {
17756
+ return false;
17757
+ }
17758
+ }
17759
+ };
17760
+ function doltBinaryNames(platform2) {
17761
+ return platform2 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
17762
+ }
17763
+ function knownDoltDirs(platform2) {
17764
+ const P3 = platform2 === "win32" ? path36.win32 : path36.posix;
17765
+ const home = _doltPathSeam.homedir();
17766
+ if (platform2 === "win32") {
17767
+ return [
17768
+ "C:\\Program Files\\Dolt\\bin",
17769
+ home ? P3.join(home, "AppData", "Local", "Programs", "dolt", "bin") : ""
17770
+ ].filter(Boolean);
17771
+ }
17772
+ return [
17773
+ "/usr/local/bin",
17774
+ "/opt/homebrew/bin",
17775
+ home ? P3.join(home, ".local", "bin") : "",
17776
+ home ? P3.join(home, "bin") : ""
17777
+ ].filter(Boolean);
17778
+ }
17779
+ function ensureDoltResolvable(platform2 = process.platform) {
17780
+ const P3 = platform2 === "win32" ? path36.win32 : path36.posix;
17781
+ const delim = platform2 === "win32" ? ";" : ":";
17782
+ const names = doltBinaryNames(platform2);
17783
+ const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
17784
+ for (const dir of pathDirs) {
17785
+ for (const n of names) {
17786
+ if (_doltPathSeam.exists(P3.join(dir, n))) return true;
17787
+ }
17788
+ }
17789
+ for (const dir of knownDoltDirs(platform2)) {
17790
+ for (const n of names) {
17791
+ if (_doltPathSeam.exists(P3.join(dir, n))) {
17792
+ _doltPathSeam.setPath(`${dir}${delim}${_doltPathSeam.getPath()}`);
17793
+ log.info("beads", `dolt found in ${dir} (not on PATH) \u2014 prepended to process PATH`);
17794
+ return true;
17795
+ }
17796
+ }
17797
+ }
17798
+ return false;
17799
+ }
17800
+ var _doltInstallSpawnSeam = {
17801
+ run: _defaultDoltInstallSpawn
17802
+ };
17803
+ function _defaultDoltInstallSpawn(strategy) {
17804
+ return new Promise((resolve7) => {
17805
+ let proc;
17806
+ try {
17807
+ proc = (0, import_child_process15.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("close", (code) => resolve7({ ok: code === 0, code: code ?? -1, stderr }));
17818
+ });
17819
+ }
17820
+ async function installDolt(platform2 = process.platform) {
17821
+ const strategy = resolveDoltInstallStrategy(platform2);
17822
+ log.info("beads", `installing dolt via ${strategy.description}`);
17823
+ const result = await _doltInstallSpawnSeam.run(strategy);
17824
+ if (!result.ok) {
17825
+ log.warn(
17826
+ "beads",
17827
+ `dolt install failed (code=${result.code}): ${result.stderr.slice(0, 200)}`
17828
+ );
17829
+ }
17830
+ return result;
17831
+ }
17832
+
17833
+ // src/beads/dolt-daemon.ts
17834
+ var _daemonSeam = {
17835
+ /**
17836
+ * Parse `bd dolt status` stdout. Running blocks lead with
17837
+ * `Dolt server: running`; down blocks say `Dolt server: not running`.
17838
+ * Match the affirmative form explicitly so "not running" can't false-positive.
17839
+ */
17840
+ isRunning: (statusStdout) => /Dolt server:\s*running/i.test(statusStdout)
17841
+ };
17842
+ async function ensureSharedServer(adapter) {
17843
+ const status2 = await adapter.run(["dolt", "status"]);
17844
+ if (status2.code === 0 && _daemonSeam.isRunning(status2.stdout)) {
17845
+ log.trace("beads", "shared dolt sql-server already running \u2014 reusing");
17846
+ return { up: true, started: false };
17847
+ }
17848
+ log.info("beads", "shared dolt sql-server not running \u2014 starting (detached)");
17849
+ const start2 = await adapter.run(["dolt", "start"]);
17850
+ if (start2.code !== 0) {
17851
+ log.warn(
17852
+ "beads",
17853
+ `bd dolt start failed (code=${start2.code}): ${start2.stderr.slice(0, 200)} \u2014 beads memory unavailable this run`
17854
+ );
17855
+ return { up: false, started: false };
17856
+ }
17857
+ const recheck = await adapter.run(["dolt", "status"]);
17858
+ const up = recheck.code === 0 && _daemonSeam.isRunning(recheck.stdout);
17859
+ if (!up) {
17860
+ log.warn("beads", "shared dolt sql-server still not reachable after start \u2014 non-fatal");
17861
+ }
17862
+ return { up, started: up };
17863
+ }
17864
+
17865
+ // src/beads/project-key.ts
17866
+ var import_child_process16 = require("child_process");
17867
+ var crypto2 = __toESM(require("crypto"));
17868
+ var fs31 = __toESM(require("fs"));
17869
+ var path37 = __toESM(require("path"));
17870
+ function normalizeOrigin(raw) {
17871
+ const trimmed = raw.trim();
17872
+ if (!trimmed) return null;
17873
+ let host;
17874
+ let pathPart;
17875
+ const scpLike = /^[^/@]+@([^:]+):(.+)$/.exec(trimmed);
17876
+ if (scpLike && !trimmed.includes("://")) {
17877
+ host = scpLike[1];
17878
+ pathPart = scpLike[2];
17879
+ } else {
17880
+ let url;
17881
+ try {
17882
+ url = new URL(trimmed);
17883
+ } catch {
17884
+ return null;
17885
+ }
17886
+ host = url.hostname;
17887
+ pathPart = url.pathname;
17888
+ }
17889
+ host = host.toLowerCase();
17890
+ pathPart = pathPart.replace(/^\/+/, "").replace(/\.git$/i, "").replace(/\/+$/, "");
17891
+ if (!host || !pathPart) return null;
17892
+ return `${host}/${pathPart}`;
17893
+ }
17894
+ function findRepoRoot(cwd) {
17895
+ let dir = path37.resolve(cwd);
17896
+ const seen = /* @__PURE__ */ new Set();
17897
+ for (let i = 0; i < 256; i++) {
17898
+ if (seen.has(dir)) return null;
17899
+ seen.add(dir);
17900
+ try {
17901
+ const stat3 = fs31.statSync(path37.join(dir, ".git"), { throwIfNoEntry: false });
17902
+ if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
17903
+ } catch {
17904
+ }
17905
+ const parent = path37.dirname(dir);
17906
+ if (parent === dir) return null;
17907
+ dir = parent;
17908
+ }
17909
+ return null;
17910
+ }
17911
+ var _execSeam2 = {
17912
+ exec: (file, args2, opts) => {
17913
+ const out2 = (0, import_child_process16.execFileSync)(file, args2, opts);
17914
+ return typeof out2 === "string" ? out2 : out2.toString("utf8");
17915
+ },
17916
+ realpath: (p2) => fs31.realpathSync(p2)
17917
+ };
17918
+ function readOrigin(cwd) {
17919
+ try {
17920
+ const raw = _execSeam2.exec("git", ["remote", "get-url", "origin"], {
17921
+ cwd,
17922
+ timeout: 1e3,
17923
+ stdio: ["ignore", "pipe", "ignore"],
17924
+ encoding: "utf8"
17925
+ });
17926
+ return raw.trim() || null;
17927
+ } catch {
17928
+ return null;
17929
+ }
17930
+ }
17931
+ function deriveProjectIdentity(cwd = process.cwd()) {
17932
+ const repoRoot = findRepoRoot(cwd) ?? cwd;
17933
+ const origin = readOrigin(repoRoot);
17934
+ const normalized = origin ? normalizeOrigin(origin) : null;
17935
+ if (normalized) {
17936
+ const label = normalized.split("/").pop() || normalized;
17937
+ return { projectKey: normalized, projectLabel: label };
17938
+ }
17939
+ let real = repoRoot;
17940
+ try {
17941
+ real = _execSeam2.realpath(repoRoot);
17942
+ } catch {
17943
+ }
17944
+ const hash = crypto2.createHash("sha256").update(real).digest("hex");
17945
+ return { projectKey: `path:${hash}`, projectLabel: path37.basename(real) || "project" };
17946
+ }
17947
+
17948
+ // src/beads/project-prefix.ts
17949
+ var crypto3 = __toESM(require("crypto"));
17950
+ function prefixForProjectKey(projectKey) {
17951
+ const tail = projectKey.split("/").pop() ?? projectKey;
17952
+ let slug = tail.toLowerCase().replace(/\.git$/, "").replace(/[^a-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
17953
+ if (!slug || !/^[a-z]/.test(slug)) slug = `p_${slug}`;
17954
+ slug = slug.replace(/_$/, "").slice(0, 24).replace(/_$/, "");
17955
+ const hash = crypto3.createHash("sha256").update(projectKey).digest("hex").slice(0, 8);
17956
+ return `${slug}_${hash}`;
17957
+ }
17958
+
17619
17959
  // src/beads/provisioner.ts
17620
17960
  var AGENT_SETUP_RECIPE = {
17621
17961
  claude: "claude",
@@ -17628,7 +17968,15 @@ var AGENT_SETUP_RECIPE = {
17628
17968
  };
17629
17969
  var _provisionSeam = {
17630
17970
  install: installBd,
17631
- homeBrainInitialized,
17971
+ installDolt,
17972
+ /** No-sudo fallback: extract the dolt tarball/zip into a user-writable dir. */
17973
+ installDoltToDir,
17974
+ // Probe dolt on PATH AND auto-prepend a known install dir if found off-PATH
17975
+ // (codespace: official install.sh drops dolt in /usr/local/bin, which the
17976
+ // bundled-node CLI's PATH can omit — mirrors the bd-on-PATH symlink fix).
17977
+ doltOnPath: ensureDoltResolvable,
17978
+ ensureSharedServer,
17979
+ deriveProjectIdentity,
17632
17980
  /** GAP 1 — symlink the resolved bd onto PATH for the agent's own shell. */
17633
17981
  linkBdOntoPath,
17634
17982
  /** Silence bd's `beads.role not configured` warning. */
@@ -17636,17 +17984,17 @@ var _provisionSeam = {
17636
17984
  };
17637
17985
  var _linkSeam = {
17638
17986
  platform: () => process.platform,
17639
- homedir: () => os25.homedir(),
17987
+ homedir: () => os26.homedir(),
17640
17988
  isWritableDir: (dir) => {
17641
17989
  try {
17642
- fs30.accessSync(dir, fs30.constants.W_OK);
17990
+ fs32.accessSync(dir, fs32.constants.W_OK);
17643
17991
  return true;
17644
17992
  } catch {
17645
17993
  return false;
17646
17994
  }
17647
17995
  },
17648
17996
  ensureDir: (dir) => {
17649
- fs30.mkdirSync(dir, { recursive: true });
17997
+ fs32.mkdirSync(dir, { recursive: true });
17650
17998
  },
17651
17999
  /**
17652
18000
  * A directory to symlink `bd` into so the AGENT's shell + Claude Code's
@@ -17667,12 +18015,12 @@ var _linkSeam = {
17667
18015
  * which `linkBdOntoPath` creates if missing.
17668
18016
  */
17669
18017
  cliBinDir: () => {
17670
- const pathDirs = (process.env.PATH ?? "").split(path36.delimiter).filter(Boolean);
18018
+ const pathDirs = (process.env.PATH ?? "").split(path38.delimiter).filter(Boolean);
17671
18019
  const home = _linkSeam.homedir();
17672
- const localBin = home ? path36.join(home, ".local", "bin") : null;
18020
+ const localBin = home ? path38.join(home, ".local", "bin") : null;
17673
18021
  const candidates = [];
17674
18022
  try {
17675
- candidates.push(path36.dirname(process.execPath));
18023
+ candidates.push(path38.dirname(process.execPath));
17676
18024
  } catch {
17677
18025
  }
17678
18026
  if (localBin) candidates.push(localBin);
@@ -17680,9 +18028,9 @@ var _linkSeam = {
17680
18028
  const entry = process.argv[1];
17681
18029
  if (entry) {
17682
18030
  try {
17683
- candidates.push(path36.dirname(fs30.realpathSync(entry)));
18031
+ candidates.push(path38.dirname(fs32.realpathSync(entry)));
17684
18032
  } catch {
17685
- candidates.push(path36.dirname(entry));
18033
+ candidates.push(path38.dirname(entry));
17686
18034
  }
17687
18035
  }
17688
18036
  const onPathWritable = candidates.find(
@@ -17694,20 +18042,20 @@ var _linkSeam = {
17694
18042
  /** Current symlink target at `linkPath`, or null when absent / not a link. */
17695
18043
  readlink: (linkPath) => {
17696
18044
  try {
17697
- return fs30.readlinkSync(linkPath);
18045
+ return fs32.readlinkSync(linkPath);
17698
18046
  } catch {
17699
18047
  return null;
17700
18048
  }
17701
18049
  },
17702
- unlink: (linkPath) => fs30.unlinkSync(linkPath),
17703
- symlink: (target, linkPath) => fs30.symlinkSync(target, linkPath)
18050
+ unlink: (linkPath) => fs32.unlinkSync(linkPath),
18051
+ symlink: (target, linkPath) => fs32.symlinkSync(target, linkPath)
17704
18052
  };
17705
18053
  function linkBdOntoPath(binaryPath) {
17706
18054
  if (_linkSeam.platform() === "win32") return;
17707
18055
  const binDir = _linkSeam.cliBinDir();
17708
18056
  if (!binDir) return;
17709
18057
  _linkSeam.ensureDir(binDir);
17710
- const linkPath = path36.join(binDir, "bd");
18058
+ const linkPath = path38.join(binDir, "bd");
17711
18059
  if (linkPath === binaryPath) return;
17712
18060
  const current = _linkSeam.readlink(linkPath);
17713
18061
  if (current === binaryPath) return;
@@ -17716,22 +18064,17 @@ function linkBdOntoPath(binaryPath) {
17716
18064
  log.info("beads", `linked bd onto PATH: ${linkPath} -> ${binaryPath}`);
17717
18065
  }
17718
18066
  function setGitBeadsRole() {
17719
- (0, import_child_process15.execFileSync)("git", ["config", "--global", "beads.role", "contributor"], {
18067
+ (0, import_child_process17.execFileSync)("git", ["config", "--global", "beads.role", "contributor"], {
17720
18068
  stdio: "ignore"
17721
18069
  });
17722
18070
  }
17723
- function homeBrainInitialized(beadsDir) {
17724
- try {
17725
- return fs30.statSync(path36.join(beadsDir, "embeddeddolt")).isDirectory();
17726
- } catch {
17727
- return false;
17728
- }
17729
- }
17730
18071
  async function provisionBeads(opts = {}) {
17731
18072
  const bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
17732
- const beadsDir = opts.beadsDir ?? defaultBeadsHomeDir();
17733
18073
  const result = {
17734
18074
  bdAvailable: false,
18075
+ doltAvailable: false,
18076
+ serverUp: false,
18077
+ prefix: null,
17735
18078
  initialized: false,
17736
18079
  exportEnabled: false,
17737
18080
  agentsWired: []
@@ -17762,24 +18105,57 @@ async function provisionBeads(opts = {}) {
17762
18105
  } catch (err) {
17763
18106
  log.trace("beads", `git config beads.role failed (non-fatal): ${err.message}`);
17764
18107
  }
17765
- if (_provisionSeam.homeBrainInitialized(beadsDir)) {
17766
- log.trace("beads", `home brain already initialized at ${beadsDir}`);
17767
- result.initialized = true;
17768
- } else {
17769
- log.info("beads", `initializing home brain at ${beadsDir}`);
17770
- const init = await bd.run(["init", "--skip-agents", "--skip-hooks", "--non-interactive"]);
17771
- if (init.code !== 0) {
17772
- log.warn("beads", `bd init failed (code=${init.code}): ${init.stderr.slice(0, 200)}`);
17773
- return result;
18108
+ if (!_provisionSeam.doltOnPath()) {
18109
+ log.info("beads", "dolt binary missing \u2014 running per-OS dolt installer");
18110
+ await _provisionSeam.installDolt();
18111
+ }
18112
+ if (!_provisionSeam.doltOnPath()) {
18113
+ const dir = _linkSeam.cliBinDir();
18114
+ if (dir) {
18115
+ try {
18116
+ _linkSeam.ensureDir(dir);
18117
+ } catch {
18118
+ }
18119
+ log.info("beads", `dolt still missing \u2014 no-sudo tarball fallback into ${dir}`);
18120
+ await _provisionSeam.installDoltToDir(dir);
17774
18121
  }
17775
- result.initialized = true;
17776
18122
  }
18123
+ if (!_provisionSeam.doltOnPath()) {
18124
+ log.warn("beads", "dolt unavailable after install + tarball fallback \u2014 beads memory disabled this run");
18125
+ return result;
18126
+ }
18127
+ result.doltAvailable = true;
18128
+ const server = await _provisionSeam.ensureSharedServer(bd);
18129
+ result.serverUp = server.up;
18130
+ if (!server.up) {
18131
+ log.warn("beads", "shared dolt sql-server not up \u2014 beads disabled this run");
18132
+ return result;
18133
+ }
18134
+ const { projectKey } = _provisionSeam.deriveProjectIdentity(opts.cwd);
18135
+ const prefix = prefixForProjectKey(projectKey);
18136
+ result.prefix = prefix;
18137
+ log.info("beads", `initializing shared-server prefix DB '${prefix}' (projectKey=${projectKey})`);
18138
+ const init = await bd.run([
18139
+ "init",
18140
+ "-p",
18141
+ prefix,
18142
+ "--shared-server",
18143
+ "--skip-agents",
18144
+ "--skip-hooks",
18145
+ "--non-interactive"
18146
+ ]);
18147
+ const alreadyInit = /already initialized|already exists/i.test(init.stderr + init.stdout);
18148
+ if (init.code !== 0 && !alreadyInit) {
18149
+ log.warn("beads", `bd init -p ${prefix} failed (code=${init.code}): ${init.stderr.slice(0, 200)}`);
18150
+ return result;
18151
+ }
18152
+ result.initialized = true;
17777
18153
  const exp = await bd.run(["config", "set", "export.auto", "true"]);
17778
18154
  result.exportEnabled = exp.code === 0;
17779
18155
  result.agentsWired = await setupAgents(bd, opts.agents ?? []);
17780
18156
  log.info(
17781
18157
  "beads",
17782
- `provision done initialized=${result.initialized} export=${result.exportEnabled} agentsWired=[${result.agentsWired.join(",")}]`
18158
+ `provision done dolt=${result.doltAvailable} server=${result.serverUp} prefix=${result.prefix} initialized=${result.initialized} export=${result.exportEnabled} agentsWired=[${result.agentsWired.join(",")}]`
17783
18159
  );
17784
18160
  return result;
17785
18161
  }
@@ -17819,91 +18195,8 @@ function dedupeRecipes(agents) {
17819
18195
  }
17820
18196
 
17821
18197
  // src/beads/watcher.ts
17822
- var crypto3 = __toESM(require("crypto"));
17823
- var path38 = __toESM(require("path"));
17824
-
17825
- // src/beads/project-key.ts
17826
- var import_child_process16 = require("child_process");
17827
- var crypto2 = __toESM(require("crypto"));
17828
- var fs31 = __toESM(require("fs"));
17829
- var path37 = __toESM(require("path"));
17830
- function normalizeOrigin(raw) {
17831
- const trimmed = raw.trim();
17832
- if (!trimmed) return null;
17833
- let host;
17834
- let pathPart;
17835
- const scpLike = /^[^/@]+@([^:]+):(.+)$/.exec(trimmed);
17836
- if (scpLike && !trimmed.includes("://")) {
17837
- host = scpLike[1];
17838
- pathPart = scpLike[2];
17839
- } else {
17840
- let url;
17841
- try {
17842
- url = new URL(trimmed);
17843
- } catch {
17844
- return null;
17845
- }
17846
- host = url.hostname;
17847
- pathPart = url.pathname;
17848
- }
17849
- host = host.toLowerCase();
17850
- pathPart = pathPart.replace(/^\/+/, "").replace(/\.git$/i, "").replace(/\/+$/, "");
17851
- if (!host || !pathPart) return null;
17852
- return `${host}/${pathPart}`;
17853
- }
17854
- function findRepoRoot(cwd) {
17855
- let dir = path37.resolve(cwd);
17856
- const seen = /* @__PURE__ */ new Set();
17857
- for (let i = 0; i < 256; i++) {
17858
- if (seen.has(dir)) return null;
17859
- seen.add(dir);
17860
- try {
17861
- const stat3 = fs31.statSync(path37.join(dir, ".git"), { throwIfNoEntry: false });
17862
- if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
17863
- } catch {
17864
- }
17865
- const parent = path37.dirname(dir);
17866
- if (parent === dir) return null;
17867
- dir = parent;
17868
- }
17869
- return null;
17870
- }
17871
- var _execSeam2 = {
17872
- exec: (file, args2, opts) => {
17873
- const out2 = (0, import_child_process16.execFileSync)(file, args2, opts);
17874
- return typeof out2 === "string" ? out2 : out2.toString("utf8");
17875
- },
17876
- realpath: (p2) => fs31.realpathSync(p2)
17877
- };
17878
- function readOrigin(cwd) {
17879
- try {
17880
- const raw = _execSeam2.exec("git", ["remote", "get-url", "origin"], {
17881
- cwd,
17882
- timeout: 1e3,
17883
- stdio: ["ignore", "pipe", "ignore"],
17884
- encoding: "utf8"
17885
- });
17886
- return raw.trim() || null;
17887
- } catch {
17888
- return null;
17889
- }
17890
- }
17891
- function deriveProjectIdentity(cwd = process.cwd()) {
17892
- const repoRoot = findRepoRoot(cwd) ?? cwd;
17893
- const origin = readOrigin(repoRoot);
17894
- const normalized = origin ? normalizeOrigin(origin) : null;
17895
- if (normalized) {
17896
- const label = normalized.split("/").pop() || normalized;
17897
- return { projectKey: normalized, projectLabel: label };
17898
- }
17899
- let real = repoRoot;
17900
- try {
17901
- real = _execSeam2.realpath(repoRoot);
17902
- } catch {
17903
- }
17904
- const hash = crypto2.createHash("sha256").update(real).digest("hex");
17905
- return { projectKey: `path:${hash}`, projectLabel: path37.basename(real) || "project" };
17906
- }
18198
+ var crypto4 = __toESM(require("crypto"));
18199
+ var path39 = __toESM(require("path"));
17907
18200
 
17908
18201
  // src/services/file-watcher/transport.ts
17909
18202
  var http5 = __toESM(require("http"));
@@ -17978,7 +18271,7 @@ var BeadsWatcher = class {
17978
18271
  constructor(opts) {
17979
18272
  this.opts = opts;
17980
18273
  this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
17981
- this.feedPath = opts.feedPath ?? path38.join(defaultBeadsHomeDir(), "issues.jsonl");
18274
+ this.feedPath = opts.feedPath ?? path39.join(defaultBeadsHomeDir(), "issues.jsonl");
17982
18275
  this.apiBase = opts.apiBaseUrl ?? API_BASE4;
17983
18276
  }
17984
18277
  opts;
@@ -18074,7 +18367,7 @@ var BeadsWatcher = class {
18074
18367
  summary: summary ?? ZERO_SUMMARY
18075
18368
  };
18076
18369
  const body = JSON.stringify(payload);
18077
- const hash = crypto3.createHash("sha256").update(body).digest("hex");
18370
+ const hash = crypto4.createHash("sha256").update(body).digest("hex");
18078
18371
  if (hash === this.lastPushedHash) {
18079
18372
  log.trace("beads", "snapshot unchanged \u2014 skipping push");
18080
18373
  return;
@@ -18192,6 +18485,7 @@ async function provisionBeadsForStart(ctx) {
18192
18485
  return null;
18193
18486
  }
18194
18487
  process.env.BEADS_DIR = defaultBeadsHomeDir();
18488
+ process.env.BEADS_DOLT_SHARED_SERVER = "1";
18195
18489
  if (!ctx.pluginAuthToken) {
18196
18490
  log.trace("beads", "no pluginAuthToken \u2014 beads off");
18197
18491
  return null;
@@ -18255,7 +18549,7 @@ var pendingAttachmentFiles = /* @__PURE__ */ new Set();
18255
18549
  function cleanupAttachmentTempFiles() {
18256
18550
  for (const p2 of pendingAttachmentFiles) {
18257
18551
  try {
18258
- fs32.unlinkSync(p2);
18552
+ fs33.unlinkSync(p2);
18259
18553
  } catch {
18260
18554
  }
18261
18555
  }
@@ -18264,8 +18558,8 @@ function cleanupAttachmentTempFiles() {
18264
18558
  function saveFilesTemp(files) {
18265
18559
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
18266
18560
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
18267
- const tmpPath = path39.join(os26.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
18268
- fs32.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
18561
+ const tmpPath = path40.join(os27.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
18562
+ fs33.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
18269
18563
  pendingAttachmentFiles.add(tmpPath);
18270
18564
  return tmpPath;
18271
18565
  });
@@ -18285,7 +18579,7 @@ var startTask = (ctx, _cmd, parsed) => {
18285
18579
  setTimeout(() => {
18286
18580
  for (const p2 of paths) {
18287
18581
  try {
18288
- fs32.unlinkSync(p2);
18582
+ fs33.unlinkSync(p2);
18289
18583
  } catch {
18290
18584
  }
18291
18585
  pendingAttachmentFiles.delete(p2);
@@ -18410,7 +18704,7 @@ var sessionTerminated = async (ctx, cmd) => {
18410
18704
  } catch {
18411
18705
  }
18412
18706
  try {
18413
- const proc = (0, import_child_process17.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18707
+ const proc = (0, import_child_process18.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18414
18708
  detached: true,
18415
18709
  stdio: "ignore"
18416
18710
  });
@@ -18432,7 +18726,7 @@ var shutdownSession = async (ctx, cmd) => {
18432
18726
  }
18433
18727
  if (ctx.keepAliveCtx.inCodespace && ctx.keepAliveCtx.codespaceName) {
18434
18728
  try {
18435
- const stopProc = (0, import_child_process17.spawn)(
18729
+ const stopProc = (0, import_child_process18.spawn)(
18436
18730
  "bash",
18437
18731
  ["-lc", `sleep 1; gh codespace stop -c ${JSON.stringify(ctx.keepAliveCtx.codespaceName)} >/dev/null 2>&1 || true`],
18438
18732
  { detached: true, stdio: "ignore" }
@@ -18442,7 +18736,7 @@ var shutdownSession = async (ctx, cmd) => {
18442
18736
  }
18443
18737
  }
18444
18738
  try {
18445
- const proc = (0, import_child_process17.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18739
+ const proc = (0, import_child_process18.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18446
18740
  detached: true,
18447
18741
  stdio: "ignore"
18448
18742
  });
@@ -18868,8 +19162,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
18868
19162
  if (args2.length === 0) return detection;
18869
19163
  const binName = args2[0];
18870
19164
  if (binName.startsWith("-")) return detection;
18871
- const binPath = path39.join(cwd, "node_modules", ".bin", binName);
18872
- if (!fs32.existsSync(binPath)) return detection;
19165
+ const binPath = path40.join(cwd, "node_modules", ".bin", binName);
19166
+ if (!fs33.existsSync(binPath)) return detection;
18873
19167
  return {
18874
19168
  ...detection,
18875
19169
  command: binPath,
@@ -18995,7 +19289,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
18995
19289
  "BOOT_SEQUENCE",
18996
19290
  `${spawnable.command} ${spawnable.args.join(" ")}`
18997
19291
  );
18998
- const devServer = (0, import_child_process17.spawn)(spawnable.command, spawnable.args, {
19292
+ const devServer = (0, import_child_process18.spawn)(spawnable.command, spawnable.args, {
18999
19293
  cwd: process.cwd(),
19000
19294
  env: { ...process.env, ...spawnable.env ?? {} },
19001
19295
  stdio: ["ignore", "pipe", "pipe"]
@@ -19123,7 +19417,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
19123
19417
  });
19124
19418
  return;
19125
19419
  }
19126
- tunnel = (0, import_child_process17.spawn)(bin, ["tunnel", "--url", `http://localhost:${detection.port}`], {
19420
+ tunnel = (0, import_child_process18.spawn)(bin, ["tunnel", "--url", `http://localhost:${detection.port}`], {
19127
19421
  stdio: ["ignore", "pipe", "pipe"]
19128
19422
  });
19129
19423
  let parsedUrl = null;
@@ -19298,10 +19592,10 @@ async function dispatchCommand(ctx, cmd) {
19298
19592
  }
19299
19593
 
19300
19594
  // src/services/file-watcher.service.ts
19301
- var import_child_process18 = require("child_process");
19302
- var fs33 = __toESM(require("fs"));
19303
- var os27 = __toESM(require("os"));
19304
- var path40 = __toESM(require("path"));
19595
+ var import_child_process19 = require("child_process");
19596
+ var fs34 = __toESM(require("fs"));
19597
+ var os28 = __toESM(require("os"));
19598
+ var path41 = __toESM(require("path"));
19305
19599
  var import_ignore = __toESM(require("ignore"));
19306
19600
 
19307
19601
  // src/services/file-watcher/diff-parser.ts
@@ -19411,10 +19705,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
19411
19705
  /[\\/]Start Menu([\\/]|$)/i,
19412
19706
  /[\\/]Templates([\\/]|$)/i
19413
19707
  ];
19414
- function isUnsafeWindowsWatchRoot(dir, homedir23) {
19708
+ function isUnsafeWindowsWatchRoot(dir, homedir24) {
19415
19709
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
19416
19710
  const cwd = norm(dir);
19417
- const home = norm(homedir23);
19711
+ const home = norm(homedir24);
19418
19712
  if (cwd === home) return true;
19419
19713
  if (/^[a-z]:$/.test(cwd)) return true;
19420
19714
  const sysRoots = [
@@ -19444,18 +19738,18 @@ var _findGitRootSeam = {
19444
19738
  resolve: _defaultFindGitRoot
19445
19739
  };
19446
19740
  function _defaultFindGitRoot(startDir) {
19447
- let dir = path40.resolve(startDir);
19741
+ let dir = path41.resolve(startDir);
19448
19742
  const seen = /* @__PURE__ */ new Set();
19449
19743
  for (let i = 0; i < 256; i++) {
19450
19744
  if (seen.has(dir)) return null;
19451
19745
  seen.add(dir);
19452
19746
  try {
19453
- const gitPath = path40.join(dir, ".git");
19454
- const stat3 = fs33.statSync(gitPath, { throwIfNoEntry: false });
19747
+ const gitPath = path41.join(dir, ".git");
19748
+ const stat3 = fs34.statSync(gitPath, { throwIfNoEntry: false });
19455
19749
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
19456
19750
  } catch {
19457
19751
  }
19458
- const parent = path40.dirname(dir);
19752
+ const parent = path41.dirname(dir);
19459
19753
  if (parent === dir) return null;
19460
19754
  dir = parent;
19461
19755
  }
@@ -19513,7 +19807,7 @@ var FileWatcherService = class {
19513
19807
  throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
19514
19808
  }
19515
19809
  const isWin = process.platform === "win32";
19516
- if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os27.homedir())) {
19810
+ if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os28.homedir())) {
19517
19811
  log.warn(
19518
19812
  "fileWatcher",
19519
19813
  `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.`
@@ -19700,7 +19994,7 @@ var FileWatcherService = class {
19700
19994
  }
19701
19995
  async emitForFile(absPath, changeType) {
19702
19996
  if (this.stopped) return;
19703
- const fileDir = path40.dirname(absPath);
19997
+ const fileDir = path41.dirname(absPath);
19704
19998
  let gitRoot = this.gitRootByDir.get(fileDir);
19705
19999
  if (gitRoot === void 0) {
19706
20000
  gitRoot = findGitRoot2(fileDir);
@@ -19713,19 +20007,19 @@ var FileWatcherService = class {
19713
20007
  );
19714
20008
  return;
19715
20009
  }
19716
- const relPathInRepo = path40.relative(gitRoot, absPath);
20010
+ const relPathInRepo = path41.relative(gitRoot, absPath);
19717
20011
  if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
19718
20012
  const matcher = this.getGitIgnoreMatcher(gitRoot);
19719
20013
  if (matcher && matcher.ignores(relPathInRepo)) {
19720
20014
  log.trace(
19721
20015
  "fileWatcher",
19722
- `${relPathInRepo} ignored by ${path40.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
20016
+ `${relPathInRepo} ignored by ${path41.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
19723
20017
  );
19724
20018
  return;
19725
20019
  }
19726
20020
  this.opts.onRepoDirty?.(gitRoot);
19727
- const repoPath = path40.relative(this.opts.workingDir, gitRoot);
19728
- const repoName = path40.basename(gitRoot);
20021
+ const repoPath = path41.relative(this.opts.workingDir, gitRoot);
20022
+ const repoName = path41.basename(gitRoot);
19729
20023
  let diffText = "";
19730
20024
  let fileStatus = "modified";
19731
20025
  if (changeType === "unlink") {
@@ -19900,7 +20194,7 @@ var FileWatcherService = class {
19900
20194
  collectGitignoreFiles(repoRoot, dir, matcher) {
19901
20195
  let entries;
19902
20196
  try {
19903
- entries = fs33.readdirSync(dir, { withFileTypes: true });
20197
+ entries = fs34.readdirSync(dir, { withFileTypes: true });
19904
20198
  } catch {
19905
20199
  return;
19906
20200
  }
@@ -19909,16 +20203,16 @@ var FileWatcherService = class {
19909
20203
  );
19910
20204
  if (gitignoreEntry) {
19911
20205
  try {
19912
- const body = fs33.readFileSync(path40.join(dir, ".gitignore"), "utf8");
19913
- const rel = path40.relative(repoRoot, dir).replace(/\\/g, "/");
20206
+ const body = fs34.readFileSync(path41.join(dir, ".gitignore"), "utf8");
20207
+ const rel = path41.relative(repoRoot, dir).replace(/\\/g, "/");
19914
20208
  const prefixed = body.split(/\r?\n/).map((line) => {
19915
20209
  const trimmed = line.trim();
19916
20210
  if (!trimmed || trimmed.startsWith("#")) return line;
19917
20211
  if (!rel) return line;
19918
20212
  if (trimmed.startsWith("!")) {
19919
- return "!" + path40.posix.join(rel, trimmed.slice(1));
20213
+ return "!" + path41.posix.join(rel, trimmed.slice(1));
19920
20214
  }
19921
- return path40.posix.join(rel, trimmed);
20215
+ return path41.posix.join(rel, trimmed);
19922
20216
  }).join("\n");
19923
20217
  matcher.add(prefixed);
19924
20218
  } catch {
@@ -19927,7 +20221,7 @@ var FileWatcherService = class {
19927
20221
  for (const entry of entries) {
19928
20222
  if (!entry.isDirectory()) continue;
19929
20223
  if (entry.name === ".git") continue;
19930
- const childAbs = path40.join(dir, entry.name);
20224
+ const childAbs = path41.join(dir, entry.name);
19931
20225
  if (isIgnoredFilePath(childAbs)) continue;
19932
20226
  this.collectGitignoreFiles(repoRoot, childAbs, matcher);
19933
20227
  }
@@ -20064,7 +20358,7 @@ async function _runGitImpl(cwd, args2, opts = {}) {
20064
20358
  return new Promise((resolve7) => {
20065
20359
  let proc;
20066
20360
  try {
20067
- proc = (0, import_child_process18.spawn)("git", args2, { cwd, env: process.env });
20361
+ proc = (0, import_child_process19.spawn)("git", args2, { cwd, env: process.env });
20068
20362
  } catch {
20069
20363
  resolve7(null);
20070
20364
  return;
@@ -20096,8 +20390,8 @@ function _runGit(cwd, args2, opts = {}) {
20096
20390
  var import_crypto4 = require("crypto");
20097
20391
 
20098
20392
  // src/services/turn-files/git-changeset.ts
20099
- var import_child_process19 = require("child_process");
20100
- var path41 = __toESM(require("path"));
20393
+ var import_child_process20 = require("child_process");
20394
+ var path42 = __toESM(require("path"));
20101
20395
  async function collectRepoChangeset(opts) {
20102
20396
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
20103
20397
  if (status2 === null) return null;
@@ -20180,7 +20474,7 @@ function defaultRunGit(cwd, args2) {
20180
20474
  return new Promise((resolve7) => {
20181
20475
  let proc;
20182
20476
  try {
20183
- proc = (0, import_child_process19.spawn)("git", args2, { cwd, env: process.env });
20477
+ proc = (0, import_child_process20.spawn)("git", args2, { cwd, env: process.env });
20184
20478
  } catch {
20185
20479
  resolve7(null);
20186
20480
  return;
@@ -20208,7 +20502,7 @@ function defaultRunGit(cwd, args2) {
20208
20502
  });
20209
20503
  }
20210
20504
  async function discoverRepos(workingDir, maxDepth = 4) {
20211
- const fs39 = await import("fs/promises");
20505
+ const fs40 = await import("fs/promises");
20212
20506
  const out2 = [];
20213
20507
  await walk(workingDir, 0);
20214
20508
  return out2;
@@ -20216,7 +20510,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
20216
20510
  if (depth > maxDepth) return;
20217
20511
  let entries = [];
20218
20512
  try {
20219
- const dirents = await fs39.readdir(dir, { withFileTypes: true });
20513
+ const dirents = await fs40.readdir(dir, { withFileTypes: true });
20220
20514
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
20221
20515
  } catch {
20222
20516
  return;
@@ -20227,8 +20521,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
20227
20521
  if (hasGit) {
20228
20522
  out2.push({
20229
20523
  repoRoot: dir,
20230
- repoPath: path41.relative(workingDir, dir),
20231
- repoName: path41.basename(dir)
20524
+ repoPath: path42.relative(workingDir, dir),
20525
+ repoName: path42.basename(dir)
20232
20526
  });
20233
20527
  return;
20234
20528
  }
@@ -20236,14 +20530,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
20236
20530
  if (!entry.isDirectory) continue;
20237
20531
  if (entry.name === "node_modules") continue;
20238
20532
  if (entry.name === "dist" || entry.name === "build") continue;
20239
- await walk(path41.join(dir, entry.name), depth + 1);
20533
+ await walk(path42.join(dir, entry.name), depth + 1);
20240
20534
  }
20241
20535
  }
20242
20536
  }
20243
20537
 
20244
20538
  // src/services/turn-files/files-outbox.ts
20245
- var fs34 = __toESM(require("fs/promises"));
20246
- var path42 = __toESM(require("path"));
20539
+ var fs35 = __toESM(require("fs/promises"));
20540
+ var path43 = __toESM(require("path"));
20247
20541
  var import_os7 = require("os");
20248
20542
  var HOME_OUTBOX_DIR = ".codeam/outbox";
20249
20543
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -20276,16 +20570,16 @@ var FilesOutbox = class {
20276
20570
  backoffIndex = 0;
20277
20571
  stopped = false;
20278
20572
  constructor(opts) {
20279
- const base = opts.baseDir ?? path42.join(homeDir(), HOME_OUTBOX_DIR);
20280
- this.filePath = path42.join(base, `${opts.sessionId}.jsonl`);
20573
+ const base = opts.baseDir ?? path43.join(homeDir(), HOME_OUTBOX_DIR);
20574
+ this.filePath = path43.join(base, `${opts.sessionId}.jsonl`);
20281
20575
  this.post = opts.post;
20282
20576
  this.autoSchedule = opts.autoSchedule !== false;
20283
20577
  }
20284
20578
  /** Persist the entry to disk and trigger a flush. Returns once the
20285
20579
  * line is durable on disk (not once the POST succeeds). */
20286
20580
  async enqueue(entry) {
20287
- await fs34.mkdir(path42.dirname(this.filePath), { recursive: true });
20288
- await fs34.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
20581
+ await fs35.mkdir(path43.dirname(this.filePath), { recursive: true });
20582
+ await fs35.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
20289
20583
  this.backoffIndex = 0;
20290
20584
  if (this.autoSchedule) this.scheduleFlush(0);
20291
20585
  }
@@ -20374,7 +20668,7 @@ var FilesOutbox = class {
20374
20668
  async readAll() {
20375
20669
  let raw = "";
20376
20670
  try {
20377
- raw = await fs34.readFile(this.filePath, "utf8");
20671
+ raw = await fs35.readFile(this.filePath, "utf8");
20378
20672
  } catch {
20379
20673
  return [];
20380
20674
  }
@@ -20398,12 +20692,12 @@ var FilesOutbox = class {
20398
20692
  async rewrite(entries) {
20399
20693
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
20400
20694
  if (entries.length === 0) {
20401
- await fs34.unlink(this.filePath).catch(() => void 0);
20695
+ await fs35.unlink(this.filePath).catch(() => void 0);
20402
20696
  return;
20403
20697
  }
20404
20698
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
20405
- await fs34.writeFile(tmpPath, payload, "utf8");
20406
- await fs34.rename(tmpPath, this.filePath);
20699
+ await fs35.writeFile(tmpPath, payload, "utf8");
20700
+ await fs35.rename(tmpPath, this.filePath);
20407
20701
  }
20408
20702
  };
20409
20703
  function applyJitter(ms) {
@@ -22210,9 +22504,9 @@ var OutputService = class _OutputService {
22210
22504
  };
22211
22505
 
22212
22506
  // src/services/history.service.ts
22213
- var fs35 = __toESM(require("fs"));
22214
- var path43 = __toESM(require("path"));
22215
- var os28 = __toESM(require("os"));
22507
+ var fs36 = __toESM(require("fs"));
22508
+ var path44 = __toESM(require("path"));
22509
+ var os29 = __toESM(require("os"));
22216
22510
  var https7 = __toESM(require("https"));
22217
22511
  var http7 = __toESM(require("http"));
22218
22512
  var import_zod2 = require("zod");
@@ -22239,7 +22533,7 @@ function parseJsonl(filePath) {
22239
22533
  const messages = [];
22240
22534
  let raw;
22241
22535
  try {
22242
- raw = fs35.readFileSync(filePath, "utf8");
22536
+ raw = fs36.readFileSync(filePath, "utf8");
22243
22537
  } catch (err) {
22244
22538
  if (err.code !== "ENOENT") {
22245
22539
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -22374,7 +22668,7 @@ var HistoryService = class _HistoryService {
22374
22668
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
22375
22669
  }
22376
22670
  get projectDir() {
22377
- return this.runtime.resolveHistoryDir(this.cwd) ?? path43.join(os28.homedir(), ".claude", "projects", encodeCwd(this.cwd));
22671
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path44.join(os29.homedir(), ".claude", "projects", encodeCwd(this.cwd));
22378
22672
  }
22379
22673
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
22380
22674
  setCurrentConversationId(id) {
@@ -22386,7 +22680,7 @@ var HistoryService = class _HistoryService {
22386
22680
  /** Return the current message count in the active conversation. */
22387
22681
  getCurrentMessageCount() {
22388
22682
  if (!this.currentConversationId) return 0;
22389
- const filePath = path43.join(this.projectDir, `${this.currentConversationId}.jsonl`);
22683
+ const filePath = path44.join(this.projectDir, `${this.currentConversationId}.jsonl`);
22390
22684
  return parseJsonl(filePath).length;
22391
22685
  }
22392
22686
  /**
@@ -22397,7 +22691,7 @@ var HistoryService = class _HistoryService {
22397
22691
  const deadline = Date.now() + timeoutMs;
22398
22692
  while (Date.now() < deadline) {
22399
22693
  if (!this.currentConversationId) return null;
22400
- const filePath = path43.join(this.projectDir, `${this.currentConversationId}.jsonl`);
22694
+ const filePath = path44.join(this.projectDir, `${this.currentConversationId}.jsonl`);
22401
22695
  const messages = parseJsonl(filePath);
22402
22696
  if (messages.length > previousCount) {
22403
22697
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -22423,16 +22717,16 @@ var HistoryService = class _HistoryService {
22423
22717
  const dir = this.projectDir;
22424
22718
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
22425
22719
  try {
22426
- const files = fs35.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
22720
+ const files = fs36.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
22427
22721
  try {
22428
- const stat3 = fs35.statSync(path43.join(dir, e.name));
22722
+ const stat3 = fs36.statSync(path44.join(dir, e.name));
22429
22723
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
22430
22724
  } catch {
22431
22725
  return { name: e.name, mtime: 0, birthtime: 0 };
22432
22726
  }
22433
22727
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
22434
22728
  if (files.length > 0) {
22435
- this.currentConversationId = path43.basename(files[0].name, ".jsonl");
22729
+ this.currentConversationId = path44.basename(files[0].name, ".jsonl");
22436
22730
  }
22437
22731
  } catch {
22438
22732
  }
@@ -22466,13 +22760,13 @@ var HistoryService = class _HistoryService {
22466
22760
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
22467
22761
  let entries;
22468
22762
  try {
22469
- entries = fs35.readdirSync(dir, { withFileTypes: true });
22763
+ entries = fs36.readdirSync(dir, { withFileTypes: true });
22470
22764
  } catch {
22471
22765
  return null;
22472
22766
  }
22473
22767
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
22474
22768
  try {
22475
- const stat3 = fs35.statSync(path43.join(dir, e.name));
22769
+ const stat3 = fs36.statSync(path44.join(dir, e.name));
22476
22770
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
22477
22771
  } catch {
22478
22772
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -22481,12 +22775,12 @@ var HistoryService = class _HistoryService {
22481
22775
  if (files.length === 0) return null;
22482
22776
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
22483
22777
  if (!files.some((f) => f.name === targetFile)) return null;
22484
- return this.extractUsageFromFile(path43.join(dir, targetFile));
22778
+ return this.extractUsageFromFile(path44.join(dir, targetFile));
22485
22779
  }
22486
22780
  extractUsageFromFile(filePath) {
22487
22781
  let raw;
22488
22782
  try {
22489
- raw = fs35.readFileSync(filePath, "utf8");
22783
+ raw = fs36.readFileSync(filePath, "utf8");
22490
22784
  } catch {
22491
22785
  return null;
22492
22786
  }
@@ -22531,9 +22825,9 @@ var HistoryService = class _HistoryService {
22531
22825
  let totalCost = 0;
22532
22826
  let files;
22533
22827
  try {
22534
- files = fs35.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
22828
+ files = fs36.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
22535
22829
  try {
22536
- return fs35.statSync(path43.join(projectDir, f)).mtimeMs >= monthStartMs;
22830
+ return fs36.statSync(path44.join(projectDir, f)).mtimeMs >= monthStartMs;
22537
22831
  } catch {
22538
22832
  return false;
22539
22833
  }
@@ -22544,7 +22838,7 @@ var HistoryService = class _HistoryService {
22544
22838
  for (const file of files) {
22545
22839
  let raw;
22546
22840
  try {
22547
- raw = fs35.readFileSync(path43.join(projectDir, file), "utf8");
22841
+ raw = fs36.readFileSync(path44.join(projectDir, file), "utf8");
22548
22842
  } catch {
22549
22843
  continue;
22550
22844
  }
@@ -22608,7 +22902,7 @@ var HistoryService = class _HistoryService {
22608
22902
  * showing an empty conversation.
22609
22903
  */
22610
22904
  async loadConversation(sessionId) {
22611
- const filePath = path43.join(this.projectDir, `${sessionId}.jsonl`);
22905
+ const filePath = path44.join(this.projectDir, `${sessionId}.jsonl`);
22612
22906
  const messages = parseJsonl(filePath);
22613
22907
  if (messages.length === 0) return;
22614
22908
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -22662,7 +22956,7 @@ var HistoryService = class _HistoryService {
22662
22956
  if (!this.currentConversationId) return 0;
22663
22957
  }
22664
22958
  const sessionId = this.currentConversationId;
22665
- const filePath = path43.join(this.projectDir, `${sessionId}.jsonl`);
22959
+ const filePath = path44.join(this.projectDir, `${sessionId}.jsonl`);
22666
22960
  const messages = parseJsonl(filePath);
22667
22961
  if (messages.length === 0) return 0;
22668
22962
  const marker = this.lastUploadedUuid.get(sessionId);
@@ -23088,13 +23382,13 @@ function fetchQuotaUsage(runtime, historySvc) {
23088
23382
  }
23089
23383
 
23090
23384
  // src/commands/start/keep-alive.ts
23091
- var import_child_process20 = require("child_process");
23385
+ var import_child_process21 = require("child_process");
23092
23386
  function buildKeepAlive(ctx) {
23093
23387
  let timer = null;
23094
23388
  async function setIdleTimeout(minutes) {
23095
23389
  if (!ctx.inCodespace || !ctx.codespaceName) return;
23096
23390
  await new Promise((resolve7) => {
23097
- const proc = (0, import_child_process20.spawn)(
23391
+ const proc = (0, import_child_process21.spawn)(
23098
23392
  "gh",
23099
23393
  [
23100
23394
  "api",
@@ -23579,8 +23873,8 @@ async function autoLinkAfterPair(opts) {
23579
23873
  }
23580
23874
 
23581
23875
  // src/commands/pair-auto.ts
23582
- var fs36 = __toESM(require("fs"));
23583
- var os29 = __toESM(require("os"));
23876
+ var fs37 = __toESM(require("fs"));
23877
+ var os30 = __toESM(require("os"));
23584
23878
  var import_crypto7 = require("crypto");
23585
23879
 
23586
23880
  // src/commands/start-infra-only.ts
@@ -23775,12 +24069,12 @@ function readTokenFromArgs(args2) {
23775
24069
  }
23776
24070
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
23777
24071
  if (fileFlag) {
23778
- const path50 = fileFlag.slice("--token-file=".length);
24072
+ const path51 = fileFlag.slice("--token-file=".length);
23779
24073
  try {
23780
- const content = fs36.readFileSync(path50, "utf8").trim();
23781
- if (content.length === 0) fail(`--token-file ${path50} is empty`);
24074
+ const content = fs37.readFileSync(path51, "utf8").trim();
24075
+ if (content.length === 0) fail(`--token-file ${path51} is empty`);
23782
24076
  try {
23783
- fs36.unlinkSync(path50);
24077
+ fs37.unlinkSync(path51);
23784
24078
  } catch {
23785
24079
  }
23786
24080
  return content;
@@ -23806,7 +24100,7 @@ async function claimOnce(token, pluginId) {
23806
24100
  pluginId,
23807
24101
  ideName: "codeam-cli (codespace)",
23808
24102
  ideVersion: process.env.npm_package_version ?? "unknown",
23809
- hostname: os29.hostname(),
24103
+ hostname: os30.hostname(),
23810
24104
  codespaceName: process.env.CODESPACE_NAME ?? "",
23811
24105
  // Current git branch of the codespace's working directory, so the
23812
24106
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -24043,11 +24337,11 @@ async function logout() {
24043
24337
  var import_picocolors10 = __toESM(require("picocolors"));
24044
24338
 
24045
24339
  // src/services/providers/github-codespaces.ts
24046
- var import_child_process21 = require("child_process");
24340
+ var import_child_process22 = require("child_process");
24047
24341
  var import_util4 = require("util");
24048
24342
  var import_picocolors8 = __toESM(require("picocolors"));
24049
- var path44 = __toESM(require("path"));
24050
- var execFileP5 = (0, import_util4.promisify)(import_child_process21.execFile);
24343
+ var path45 = __toESM(require("path"));
24344
+ var execFileP5 = (0, import_util4.promisify)(import_child_process22.execFile);
24051
24345
  var MAX_BUFFER = 8 * 1024 * 1024;
24052
24346
  function resetStdinForChild() {
24053
24347
  if (process.stdin.isTTY) {
@@ -24091,7 +24385,7 @@ var GitHubCodespacesProvider = class {
24091
24385
  if (!isAuthed) {
24092
24386
  resetStdinForChild();
24093
24387
  await new Promise((resolve7, reject) => {
24094
- const proc = (0, import_child_process21.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
24388
+ const proc = (0, import_child_process22.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
24095
24389
  stdio: "inherit"
24096
24390
  });
24097
24391
  proc.on("exit", (code) => {
@@ -24125,7 +24419,7 @@ var GitHubCodespacesProvider = class {
24125
24419
  wt(noteLines.join("\n"), "One more permission needed");
24126
24420
  resetStdinForChild();
24127
24421
  const refreshCode = await new Promise((resolve7, reject) => {
24128
- const proc = (0, import_child_process21.spawn)(
24422
+ const proc = (0, import_child_process22.spawn)(
24129
24423
  "gh",
24130
24424
  ["auth", "refresh", "-h", "github.com", "-s", "codespace"],
24131
24425
  { stdio: "inherit" }
@@ -24275,7 +24569,7 @@ var GitHubCodespacesProvider = class {
24275
24569
  O2.step(`Installing gh via ${installCmd.describe}\u2026`);
24276
24570
  resetStdinForChild();
24277
24571
  const ok = await new Promise((resolve7) => {
24278
- const proc = (0, import_child_process21.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
24572
+ const proc = (0, import_child_process22.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
24279
24573
  proc.on("exit", (code) => resolve7(code === 0));
24280
24574
  proc.on("error", () => resolve7(false));
24281
24575
  });
@@ -24302,7 +24596,7 @@ var GitHubCodespacesProvider = class {
24302
24596
  );
24303
24597
  resetStdinForChild();
24304
24598
  await new Promise((resolve7, reject) => {
24305
- const proc = (0, import_child_process21.spawn)(
24599
+ const proc = (0, import_child_process22.spawn)(
24306
24600
  "gh",
24307
24601
  ["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
24308
24602
  { stdio: "inherit" }
@@ -24480,7 +24774,7 @@ var GitHubCodespacesProvider = class {
24480
24774
  async streamCommand(workspaceId, command2) {
24481
24775
  resetStdinForChild();
24482
24776
  return new Promise((resolve7, reject) => {
24483
- const proc = (0, import_child_process21.spawn)(
24777
+ const proc = (0, import_child_process22.spawn)(
24484
24778
  "gh",
24485
24779
  ["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
24486
24780
  { stdio: "inherit" }
@@ -24507,11 +24801,11 @@ var GitHubCodespacesProvider = class {
24507
24801
  `mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
24508
24802
  ];
24509
24803
  await new Promise((resolve7, reject) => {
24510
- const tar = (0, import_child_process21.spawn)("tar", tarArgs, {
24804
+ const tar = (0, import_child_process22.spawn)("tar", tarArgs, {
24511
24805
  stdio: ["ignore", "pipe", "pipe"],
24512
24806
  env: tarEnv
24513
24807
  });
24514
- const ssh = (0, import_child_process21.spawn)("gh", sshArgs, {
24808
+ const ssh = (0, import_child_process22.spawn)("gh", sshArgs, {
24515
24809
  stdio: [tar.stdout, "pipe", "pipe"]
24516
24810
  });
24517
24811
  let tarErr = "";
@@ -24535,7 +24829,7 @@ var GitHubCodespacesProvider = class {
24535
24829
  });
24536
24830
  }
24537
24831
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
24538
- const remoteDir = path44.posix.dirname(remotePath);
24832
+ const remoteDir = path45.posix.dirname(remotePath);
24539
24833
  const parts = [
24540
24834
  `mkdir -p ${shellQuote(remoteDir)}`,
24541
24835
  `cat > ${shellQuote(remotePath)}`
@@ -24545,7 +24839,7 @@ var GitHubCodespacesProvider = class {
24545
24839
  }
24546
24840
  const cmd = parts.join(" && ");
24547
24841
  await new Promise((resolve7, reject) => {
24548
- const proc = (0, import_child_process21.spawn)(
24842
+ const proc = (0, import_child_process22.spawn)(
24549
24843
  "gh",
24550
24844
  ["codespace", "ssh", "-c", workspaceId, "--", cmd],
24551
24845
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -24603,11 +24897,11 @@ function shellQuote(s) {
24603
24897
  }
24604
24898
 
24605
24899
  // src/services/providers/gitpod.ts
24606
- var import_child_process22 = require("child_process");
24900
+ var import_child_process23 = require("child_process");
24607
24901
  var import_util5 = require("util");
24608
- var path45 = __toESM(require("path"));
24902
+ var path46 = __toESM(require("path"));
24609
24903
  var import_picocolors9 = __toESM(require("picocolors"));
24610
- var execFileP6 = (0, import_util5.promisify)(import_child_process22.execFile);
24904
+ var execFileP6 = (0, import_util5.promisify)(import_child_process23.execFile);
24611
24905
  var MAX_BUFFER2 = 8 * 1024 * 1024;
24612
24906
  function resetStdinForChild2() {
24613
24907
  if (process.stdin.isTTY) {
@@ -24647,7 +24941,7 @@ var GitpodProvider = class {
24647
24941
  );
24648
24942
  resetStdinForChild2();
24649
24943
  await new Promise((resolve7, reject) => {
24650
- const proc = (0, import_child_process22.spawn)("gitpod", ["login"], { stdio: "inherit" });
24944
+ const proc = (0, import_child_process23.spawn)("gitpod", ["login"], { stdio: "inherit" });
24651
24945
  proc.on("exit", (code) => {
24652
24946
  if (code === 0) resolve7();
24653
24947
  else reject(new Error("gitpod login failed."));
@@ -24799,7 +25093,7 @@ var GitpodProvider = class {
24799
25093
  async streamCommand(workspaceId, command2) {
24800
25094
  resetStdinForChild2();
24801
25095
  return new Promise((resolve7, reject) => {
24802
- const proc = (0, import_child_process22.spawn)(
25096
+ const proc = (0, import_child_process23.spawn)(
24803
25097
  "gitpod",
24804
25098
  ["workspace", "ssh", workspaceId, "--", "-tt", command2],
24805
25099
  { stdio: "inherit" }
@@ -24819,11 +25113,11 @@ var GitpodProvider = class {
24819
25113
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
24820
25114
  const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
24821
25115
  await new Promise((resolve7, reject) => {
24822
- const tar = (0, import_child_process22.spawn)("tar", tarArgs, {
25116
+ const tar = (0, import_child_process23.spawn)("tar", tarArgs, {
24823
25117
  stdio: ["ignore", "pipe", "pipe"],
24824
25118
  env: tarEnv
24825
25119
  });
24826
- const ssh = (0, import_child_process22.spawn)(
25120
+ const ssh = (0, import_child_process23.spawn)(
24827
25121
  "gitpod",
24828
25122
  ["workspace", "ssh", workspaceId, "--", remoteCmd],
24829
25123
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -24845,7 +25139,7 @@ var GitpodProvider = class {
24845
25139
  });
24846
25140
  }
24847
25141
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
24848
- const remoteDir = path45.posix.dirname(remotePath);
25142
+ const remoteDir = path46.posix.dirname(remotePath);
24849
25143
  const parts = [
24850
25144
  `mkdir -p ${shellQuote2(remoteDir)}`,
24851
25145
  `cat > ${shellQuote2(remotePath)}`
@@ -24855,7 +25149,7 @@ var GitpodProvider = class {
24855
25149
  }
24856
25150
  const cmd = parts.join(" && ");
24857
25151
  await new Promise((resolve7, reject) => {
24858
- const proc = (0, import_child_process22.spawn)(
25152
+ const proc = (0, import_child_process23.spawn)(
24859
25153
  "gitpod",
24860
25154
  ["workspace", "ssh", workspaceId, "--", cmd],
24861
25155
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -24879,10 +25173,10 @@ function shellQuote2(s) {
24879
25173
  }
24880
25174
 
24881
25175
  // src/services/providers/gitlab-workspaces.ts
24882
- var import_child_process23 = require("child_process");
25176
+ var import_child_process24 = require("child_process");
24883
25177
  var import_util6 = require("util");
24884
- var path46 = __toESM(require("path"));
24885
- var execFileP7 = (0, import_util6.promisify)(import_child_process23.execFile);
25178
+ var path47 = __toESM(require("path"));
25179
+ var execFileP7 = (0, import_util6.promisify)(import_child_process24.execFile);
24886
25180
  var MAX_BUFFER3 = 8 * 1024 * 1024;
24887
25181
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
24888
25182
  function resetStdinForChild3() {
@@ -24924,7 +25218,7 @@ var GitLabWorkspacesProvider = class {
24924
25218
  );
24925
25219
  resetStdinForChild3();
24926
25220
  await new Promise((resolve7, reject) => {
24927
- const proc = (0, import_child_process23.spawn)(
25221
+ const proc = (0, import_child_process24.spawn)(
24928
25222
  "glab",
24929
25223
  ["auth", "login", "--scopes", "api,read_user,read_repository"],
24930
25224
  { stdio: "inherit" }
@@ -25096,7 +25390,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25096
25390
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
25097
25391
  resetStdinForChild3();
25098
25392
  return new Promise((resolve7, reject) => {
25099
- const proc = (0, import_child_process23.spawn)(
25393
+ const proc = (0, import_child_process24.spawn)(
25100
25394
  "ssh",
25101
25395
  ["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
25102
25396
  { stdio: "inherit" }
@@ -25117,8 +25411,8 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25117
25411
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
25118
25412
  const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
25119
25413
  await new Promise((resolve7, reject) => {
25120
- const tar = (0, import_child_process23.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25121
- const ssh = (0, import_child_process23.spawn)(
25414
+ const tar = (0, import_child_process24.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25415
+ const ssh = (0, import_child_process24.spawn)(
25122
25416
  "ssh",
25123
25417
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, remoteCmd],
25124
25418
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -25141,14 +25435,14 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25141
25435
  }
25142
25436
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25143
25437
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
25144
- const remoteDir = path46.posix.dirname(remotePath);
25438
+ const remoteDir = path47.posix.dirname(remotePath);
25145
25439
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
25146
25440
  if (options.mode != null) {
25147
25441
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
25148
25442
  }
25149
25443
  const cmd = parts.join(" && ");
25150
25444
  await new Promise((resolve7, reject) => {
25151
- const proc = (0, import_child_process23.spawn)(
25445
+ const proc = (0, import_child_process24.spawn)(
25152
25446
  "ssh",
25153
25447
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
25154
25448
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -25207,10 +25501,10 @@ function shellQuote3(s) {
25207
25501
  }
25208
25502
 
25209
25503
  // src/services/providers/railway.ts
25210
- var import_child_process24 = require("child_process");
25504
+ var import_child_process25 = require("child_process");
25211
25505
  var import_util7 = require("util");
25212
- var path47 = __toESM(require("path"));
25213
- var execFileP8 = (0, import_util7.promisify)(import_child_process24.execFile);
25506
+ var path48 = __toESM(require("path"));
25507
+ var execFileP8 = (0, import_util7.promisify)(import_child_process25.execFile);
25214
25508
  var MAX_BUFFER4 = 8 * 1024 * 1024;
25215
25509
  function resetStdinForChild4() {
25216
25510
  if (process.stdin.isTTY) {
@@ -25251,7 +25545,7 @@ var RailwayProvider = class {
25251
25545
  );
25252
25546
  resetStdinForChild4();
25253
25547
  await new Promise((resolve7, reject) => {
25254
- const proc = (0, import_child_process24.spawn)("railway", ["login"], { stdio: "inherit" });
25548
+ const proc = (0, import_child_process25.spawn)("railway", ["login"], { stdio: "inherit" });
25255
25549
  proc.on("exit", (code) => {
25256
25550
  if (code === 0) resolve7();
25257
25551
  else reject(new Error("railway login failed."));
@@ -25394,7 +25688,7 @@ var RailwayProvider = class {
25394
25688
  }
25395
25689
  resetStdinForChild4();
25396
25690
  return new Promise((resolve7, reject) => {
25397
- const proc = (0, import_child_process24.spawn)(
25691
+ const proc = (0, import_child_process25.spawn)(
25398
25692
  "railway",
25399
25693
  ["shell", "--project", projectId, "--service", serviceId, "--command", command2],
25400
25694
  { stdio: "inherit" }
@@ -25418,8 +25712,8 @@ var RailwayProvider = class {
25418
25712
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
25419
25713
  const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
25420
25714
  await new Promise((resolve7, reject) => {
25421
- const tar = (0, import_child_process24.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25422
- const sh = (0, import_child_process24.spawn)(
25715
+ const tar = (0, import_child_process25.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25716
+ const sh = (0, import_child_process25.spawn)(
25423
25717
  "railway",
25424
25718
  ["shell", "--project", projectId, "--service", serviceId, "--command", remoteCmd],
25425
25719
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -25445,14 +25739,14 @@ var RailwayProvider = class {
25445
25739
  if (!projectId || !serviceId) {
25446
25740
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
25447
25741
  }
25448
- const remoteDir = path47.posix.dirname(remotePath);
25742
+ const remoteDir = path48.posix.dirname(remotePath);
25449
25743
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
25450
25744
  if (options.mode != null) {
25451
25745
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
25452
25746
  }
25453
25747
  const cmd = parts.join(" && ");
25454
25748
  await new Promise((resolve7, reject) => {
25455
- const proc = (0, import_child_process24.spawn)(
25749
+ const proc = (0, import_child_process25.spawn)(
25456
25750
  "railway",
25457
25751
  ["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
25458
25752
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -25988,8 +26282,8 @@ async function stopWorkspaceFromLocal(target) {
25988
26282
  var import_node_dns = require("dns");
25989
26283
  var import_node_util4 = require("util");
25990
26284
  var import_node_crypto8 = require("crypto");
25991
- var fs37 = __toESM(require("fs"));
25992
- var path48 = __toESM(require("path"));
26285
+ var fs38 = __toESM(require("fs"));
26286
+ var path49 = __toESM(require("path"));
25993
26287
  var import_picocolors12 = __toESM(require("picocolors"));
25994
26288
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
25995
26289
  async function checkDns(apiBase) {
@@ -26045,13 +26339,13 @@ async function checkHealth(apiBase) {
26045
26339
  }
26046
26340
  }
26047
26341
  function checkConfigDir() {
26048
- const dir = path48.join(require("os").homedir(), ".codeam");
26342
+ const dir = path49.join(require("os").homedir(), ".codeam");
26049
26343
  try {
26050
- fs37.mkdirSync(dir, { recursive: true, mode: 448 });
26051
- const probe = path48.join(dir, ".doctor-probe");
26052
- fs37.writeFileSync(probe, "ok", { mode: 384 });
26053
- const read = fs37.readFileSync(probe, "utf8");
26054
- fs37.unlinkSync(probe);
26344
+ fs38.mkdirSync(dir, { recursive: true, mode: 448 });
26345
+ const probe = path49.join(dir, ".doctor-probe");
26346
+ fs38.writeFileSync(probe, "ok", { mode: 384 });
26347
+ const read = fs38.readFileSync(probe, "utf8");
26348
+ fs38.unlinkSync(probe);
26055
26349
  if (read !== "ok") throw new Error("write/read round-trip mismatch");
26056
26350
  return {
26057
26351
  id: "config-dir",
@@ -26091,9 +26385,9 @@ function checkSessions() {
26091
26385
  }
26092
26386
  }
26093
26387
  function checkAgentBinaries() {
26094
- const os31 = createOsStrategy();
26388
+ const os32 = createOsStrategy();
26095
26389
  return getEnabledAgents().map((meta) => {
26096
- const found = os31.findInPath(meta.binaryName);
26390
+ const found = os32.findInPath(meta.binaryName);
26097
26391
  return {
26098
26392
  id: `agent-${meta.id}`,
26099
26393
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -26115,7 +26409,7 @@ function checkNodePty() {
26115
26409
  detail: "not required on this platform"
26116
26410
  };
26117
26411
  }
26118
- const vendoredPath = path48.join(__dirname, "vendor", "node-pty");
26412
+ const vendoredPath = path49.join(__dirname, "vendor", "node-pty");
26119
26413
  for (const target of [vendoredPath, "node-pty"]) {
26120
26414
  try {
26121
26415
  require(target);
@@ -26157,7 +26451,7 @@ function checkChokidar() {
26157
26451
  }
26158
26452
  async function doctor(args2 = []) {
26159
26453
  const json = args2.includes("--json");
26160
- const cliVersion = true ? "2.35.8" : "0.0.0-dev";
26454
+ const cliVersion = true ? "2.36.0" : "0.0.0-dev";
26161
26455
  const apiBase = resolveApiBaseUrl();
26162
26456
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
26163
26457
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -26356,7 +26650,7 @@ async function completion(args2) {
26356
26650
  // src/commands/version.ts
26357
26651
  var import_picocolors13 = __toESM(require("picocolors"));
26358
26652
  function version2() {
26359
- const v = true ? "2.35.8" : "unknown";
26653
+ const v = true ? "2.36.0" : "unknown";
26360
26654
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
26361
26655
  }
26362
26656
 
@@ -26484,9 +26778,9 @@ function tryShowSubcommandHelp(cmd, args2) {
26484
26778
  var _subcommandHelpKeys = Object.keys(HELPS);
26485
26779
 
26486
26780
  // src/lib/updateNotifier.ts
26487
- var fs38 = __toESM(require("fs"));
26488
- var os30 = __toESM(require("os"));
26489
- var path49 = __toESM(require("path"));
26781
+ var fs39 = __toESM(require("fs"));
26782
+ var os31 = __toESM(require("os"));
26783
+ var path50 = __toESM(require("path"));
26490
26784
  var https8 = __toESM(require("https"));
26491
26785
  var import_node_child_process12 = require("child_process");
26492
26786
  var import_picocolors16 = __toESM(require("picocolors"));
@@ -26495,12 +26789,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
26495
26789
  var TTL_MS = 24 * 60 * 60 * 1e3;
26496
26790
  var REQUEST_TIMEOUT_MS = 1500;
26497
26791
  function cachePath() {
26498
- const dir = path49.join(os30.homedir(), ".codeam");
26499
- return path49.join(dir, "update-check.json");
26792
+ const dir = path50.join(os31.homedir(), ".codeam");
26793
+ return path50.join(dir, "update-check.json");
26500
26794
  }
26501
26795
  function readCache() {
26502
26796
  try {
26503
- const raw = fs38.readFileSync(cachePath(), "utf8");
26797
+ const raw = fs39.readFileSync(cachePath(), "utf8");
26504
26798
  const parsed = JSON.parse(raw);
26505
26799
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
26506
26800
  return parsed;
@@ -26511,10 +26805,10 @@ function readCache() {
26511
26805
  function writeCache(cache) {
26512
26806
  try {
26513
26807
  const file = cachePath();
26514
- fs38.mkdirSync(path49.dirname(file), { recursive: true });
26808
+ fs39.mkdirSync(path50.dirname(file), { recursive: true });
26515
26809
  const tmp = `${file}.${process.pid}.tmp`;
26516
- fs38.writeFileSync(tmp, JSON.stringify(cache));
26517
- fs38.renameSync(tmp, file);
26810
+ fs39.writeFileSync(tmp, JSON.stringify(cache));
26811
+ fs39.renameSync(tmp, file);
26518
26812
  } catch {
26519
26813
  }
26520
26814
  }
@@ -26588,8 +26882,8 @@ function isLinkedInstall() {
26588
26882
  timeout: 2e3
26589
26883
  }).trim();
26590
26884
  if (!root) return false;
26591
- const pkgPath = path49.join(root, PKG_NAME);
26592
- return fs38.lstatSync(pkgPath).isSymbolicLink();
26885
+ const pkgPath = path50.join(root, PKG_NAME);
26886
+ return fs39.lstatSync(pkgPath).isSymbolicLink();
26593
26887
  } catch {
26594
26888
  return false;
26595
26889
  }
@@ -26625,7 +26919,7 @@ function maybeAutoUpdate(currentVersion, latest) {
26625
26919
  return;
26626
26920
  }
26627
26921
  try {
26628
- fs38.unlinkSync(cachePath());
26922
+ fs39.unlinkSync(cachePath());
26629
26923
  } catch {
26630
26924
  }
26631
26925
  process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
@@ -26642,7 +26936,7 @@ function checkForUpdates() {
26642
26936
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
26643
26937
  if (process.env.CI) return;
26644
26938
  if (!process.stdout.isTTY) return;
26645
- const current = true ? "2.35.8" : null;
26939
+ const current = true ? "2.36.0" : null;
26646
26940
  if (!current) return;
26647
26941
  const cache = readCache();
26648
26942
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;