codeam-cli 2.53.2 → 2.53.4

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 +13 -0
  2. package/dist/index.js +979 -787
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -199,9 +199,35 @@ function renderToLines(raw) {
199
199
  return screen;
200
200
  }
201
201
 
202
+ // ../../packages/shared/src/protocol/remote-command.ts
203
+ var import_zod = require("zod");
204
+ var remoteCommandSchema = import_zod.z.object({
205
+ id: import_zod.z.string(),
206
+ sessionId: import_zod.z.string(),
207
+ pluginId: import_zod.z.string(),
208
+ type: import_zod.z.string(),
209
+ // The backend may omit `payload` (or send null) for payload-less commands;
210
+ // clients have always normalized that to `{}` — keep that behavior here.
211
+ payload: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).nullish(),
212
+ status: import_zod.z.string(),
213
+ createdAt: import_zod.z.number()
214
+ });
215
+
202
216
  // ../../packages/shared/src/models/pricing.ts
203
217
  var MODEL_PRICING = {
204
218
  // ── Anthropic / Claude ────────────────────────────────────
219
+ // The 4.x rows below cover the model ids actually emitted by the CLI
220
+ // (apps/cli/src/agents/claude/runtime.ts listModels) and the JetBrains
221
+ // fallback catalog (RemoteCommandRouter.kt). Prices are copied from the
222
+ // same-family base rows (claude-opus-4 / claude-sonnet-4 /
223
+ // claude-3-5-haiku) until distinct published rates land.
224
+ "claude-opus-4-7": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
225
+ "claude-opus-4-6": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
226
+ "claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
227
+ // Haiku-tier prices copied from claude-3-5-haiku (closest same-tier
228
+ // sibling in this table) — previously this id matched NO row and was
229
+ // silently billed at sonnet rates via the unknown-model fallback.
230
+ "claude-haiku-4-5": { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 },
205
231
  "claude-sonnet-4": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
206
232
  "claude-opus-4": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
207
233
  "claude-3-5-sonnet": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
@@ -220,6 +246,10 @@ var MODEL_PRICING = {
220
246
  };
221
247
  var MODEL_CONTEXT_WINDOW = {
222
248
  // ── Anthropic / Claude ────────────────────────────────────
249
+ "claude-opus-4-7": 1e6,
250
+ "claude-opus-4-6": 1e6,
251
+ "claude-sonnet-4-6": 1e6,
252
+ "claude-haiku-4-5": 2e5,
223
253
  "claude-opus-4": 1e6,
224
254
  "claude-sonnet-4": 1e6,
225
255
  "claude-3-5-sonnet": 2e5,
@@ -234,18 +264,23 @@ var MODEL_CONTEXT_WINDOW = {
234
264
  "codex-auto-review": 272e3
235
265
  };
236
266
  var DEFAULT_CONTEXT_WINDOW = 2e5;
237
- function getPricing(model) {
238
- for (const [prefix, pricing] of Object.entries(MODEL_PRICING)) {
239
- if (model.startsWith(prefix)) return pricing;
267
+ function longestPrefixMatch(table, model) {
268
+ let best;
269
+ let bestLen = -1;
270
+ for (const [prefix, value] of Object.entries(table)) {
271
+ if (prefix.length > bestLen && model.startsWith(prefix)) {
272
+ best = value;
273
+ bestLen = prefix.length;
274
+ }
240
275
  }
241
- return MODEL_PRICING["claude-sonnet-4"];
276
+ return best;
277
+ }
278
+ function getPricing(model) {
279
+ return longestPrefixMatch(MODEL_PRICING, model) ?? MODEL_PRICING["claude-sonnet-4"];
242
280
  }
243
281
  function getContextWindow(model) {
244
282
  if (!model) return DEFAULT_CONTEXT_WINDOW;
245
- for (const [prefix, size] of Object.entries(MODEL_CONTEXT_WINDOW)) {
246
- if (model.startsWith(prefix)) return size;
247
- }
248
- return DEFAULT_CONTEXT_WINDOW;
283
+ return longestPrefixMatch(MODEL_CONTEXT_WINDOW, model) ?? DEFAULT_CONTEXT_WINDOW;
249
284
  }
250
285
 
251
286
  // ../../packages/shared/src/agents/registry.ts
@@ -255,8 +290,12 @@ var AGENT_REGISTRY = {
255
290
  displayName: "Claude Code",
256
291
  binaryName: "claude",
257
292
  enabled: true,
258
- supportedAuthKinds: ["oauth_token", "api_key"],
259
- preferredAuthKind: "oauth_token"
293
+ // Mirrors the backend registry (codeagent-mobile
294
+ // apps/api-v2/src/codespaces/agent.ts — authoritative for auth
295
+ // capabilities). `setup_token` is the bare `sk-ant-oat01-…` from
296
+ // `claude setup-token` → delivered via CLAUDE_CODE_OAUTH_TOKEN.
297
+ supportedAuthKinds: ["setup_token", "oauth_token", "api_key"],
298
+ preferredAuthKind: "setup_token"
260
299
  },
261
300
  codex: {
262
301
  id: "codex",
@@ -279,15 +318,22 @@ var AGENT_REGISTRY = {
279
318
  displayName: "CodeRabbit",
280
319
  binaryName: "coderabbit",
281
320
  enabled: true,
282
- supportedAuthKinds: ["oauth_token", "api_key"],
283
- preferredAuthKind: "oauth_token"
321
+ // Backend registry is authoritative: CodeRabbit links via a real
322
+ // API key only (no OAuth flow exists in api-v2).
323
+ supportedAuthKinds: ["api_key"],
324
+ preferredAuthKind: "api_key"
284
325
  },
285
326
  cursor: {
286
327
  id: "cursor",
287
328
  displayName: "Cursor Agent",
288
329
  binaryName: "cursor-agent",
289
330
  enabled: true,
290
- supportedAuthKinds: ["oauth_token", "api_key"],
331
+ // Backend registry is authoritative: since the Cursor OAuth
332
+ // device-flow shipped, new links are oauth_token only (the login
333
+ // blob written to ~/.config/cursor/auth.json). Legacy vaulted
334
+ // api_key rows may still exist server-side, but the link surface
335
+ // no longer offers api_key.
336
+ supportedAuthKinds: ["oauth_token"],
291
337
  preferredAuthKind: "oauth_token"
292
338
  },
293
339
  aider: {
@@ -323,7 +369,7 @@ function getAgent(id) {
323
369
  return meta;
324
370
  }
325
371
  function isKnownAgentId(id) {
326
- return id === "claude" || id === "codex" || id === "copilot" || id === "coderabbit" || id === "cursor" || id === "aider" || id === "gemini";
372
+ return id in AGENT_REGISTRY;
327
373
  }
328
374
 
329
375
  // ../../packages/shared/src/api-url.ts
@@ -338,6 +384,74 @@ function resolveApiBaseUrl() {
338
384
  return DEFAULT_API_BASE_URL;
339
385
  }
340
386
 
387
+ // ../../packages/shared/src/types/events.ts
388
+ var USER_EVENTS = {
389
+ PAIRED_SESSION_STATUS: "paired_session_status",
390
+ PAIRED_SESSION_ADDED: "paired_session_added",
391
+ PAIRED_SESSION_REMOVED: "paired_session_removed",
392
+ PAIRED_SESSION_BRANCH_CHANGED: "paired_session_branch_changed",
393
+ SHARED_WITH_ME_ADDED: "shared_with_me_added",
394
+ SHARED_WITH_ME_REVOKED: "shared_with_me_revoked",
395
+ USAGE_CHANGED: "usage_changed",
396
+ TASK_DONE: "task_done",
397
+ HUNK_PENDING_REVIEW_ADDED: "hunk_pending_review_added",
398
+ HUNK_REVIEW_RESOLVED: "hunk_review_resolved",
399
+ FILE_CHANGED: "file_changed",
400
+ FILES_BATCH_CHANGED: "files_batch_changed",
401
+ AGENT_STREAMING_CHUNK: "agent_streaming_chunk",
402
+ AGENT_AWAITING_ANSWER: "agent_awaiting_answer",
403
+ AWAITING_INPUT_ADDED: "awaiting_input_added",
404
+ AGENT_ANSWER_RESOLVED: "agent_answer_resolved",
405
+ TEMPLATE_ADDED: "template_added",
406
+ TEMPLATE_REMOVED: "template_removed",
407
+ TEMPLATE_UPDATED: "template_updated",
408
+ AGENT_TASK_DISPATCHED: "agent_task_dispatched",
409
+ AGENT_TASK_COMPLETED: "agent_task_completed",
410
+ LINKED_AGENT_ADDED: "linked_agent_added",
411
+ QUOTA_REACHED: "quota_reached",
412
+ LINKED_AGENT_LINK_FAILED: "linked_agent_link_failed",
413
+ CODESPACE_AGENT_INSTALLED: "codespace_agent_installed",
414
+ AGENT_CREDENTIALS_REFRESHED: "agent_credentials_refreshed",
415
+ CREDENTIAL_INVALID: "credential_invalid",
416
+ CODESPACE_WAKING: "codespace_waking",
417
+ CODESPACE_BILLING_BLOCKED: "codespace_billing_blocked",
418
+ COST_SAVING_UPDATED: "cost_saving_updated",
419
+ COMMAND_COMPLETED: "command_completed",
420
+ AI_SUMMARY_PENDING: "ai_summary_pending",
421
+ AI_SUMMARY_READY: "ai_summary_ready",
422
+ AI_INSIGHT_PENDING: "ai_insight_pending",
423
+ AI_INSIGHT_READY: "ai_insight_ready",
424
+ PUSH_TOKEN_INVALIDATED: "push_token_invalidated",
425
+ PREVIEW_DETECTION_PENDING: "preview_detection_pending",
426
+ PREVIEW_DETECTION_READY: "preview_detection_ready",
427
+ PREVIEW_STARTING: "preview_starting",
428
+ PREVIEW_READY: "preview_ready",
429
+ PREVIEW_STOPPED: "preview_stopped",
430
+ PREVIEW_ERROR: "preview_error",
431
+ PREVIEW_PROGRESS: "preview_progress",
432
+ BEADS_STATE_CHANGED: "beads_state_changed",
433
+ BEADS_PROVISIONING: "beads_provisioning",
434
+ BEADS_TEAM_MEMORY_CHANGED: "beads_team_memory_changed",
435
+ AUDIT_EVENT_ADDED: "audit_event_added",
436
+ SELF_HOSTED_HOST_ADDED: "self_hosted_host_added",
437
+ SELF_HOSTED_HOST_STATUS: "self_hosted_host_status",
438
+ SELF_HOSTED_HOST_REMOVED: "self_hosted_host_removed",
439
+ SELF_HOSTED_HOST_TELEMETRY: "self_hosted_host_telemetry",
440
+ SELF_HOSTED_HOST_METRICS: "self_hosted_host_metrics",
441
+ SELF_HOSTED_HOST_SESSIONS: "self_hosted_host_sessions",
442
+ SELF_HOSTED_DEPLOY_PROGRESS: "self_hosted_deploy_progress",
443
+ REFERRAL_REWARD_EARNED: "referral_reward_earned",
444
+ HEADROOM_PROGRESS: "headroom_progress",
445
+ HEADROOM_STATUS: "headroom_status",
446
+ BEADS_STATUS: "beads_status",
447
+ LINKED_AGENT_HEADROOM_BUDGET_UPDATED: "linked_agent_headroom_budget_updated",
448
+ CLI_UPDATE_AVAILABLE: "cli_update_available",
449
+ AGENT_INSTALL_PROGRESS: "agent_install_progress",
450
+ AGENT_INSTALL_FAILED: "agent_install_failed",
451
+ CLI_UPDATE_PROGRESS: "cli_update_progress",
452
+ CLI_UPDATE_FAILED: "cli_update_failed"
453
+ };
454
+
341
455
  // ../../packages/shared/src/preview-prompts.ts
342
456
  var PREVIEW_DETECT_PROMPT = `
343
457
  Analyze the project in the current working directory and return how to start
@@ -522,9 +636,9 @@ var _default = makeConfig();
522
636
  var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, setDisable1mContext, clearAll, saveCliConfig, loadCliConfig } = _default;
523
637
 
524
638
  // src/commands/pair-auto.ts
525
- var fs45 = __toESM(require("fs"));
526
- var os38 = __toESM(require("os"));
527
- var path50 = __toESM(require("path"));
639
+ var fs46 = __toESM(require("fs"));
640
+ var os39 = __toESM(require("os"));
641
+ var path51 = __toESM(require("path"));
528
642
  var import_crypto4 = require("crypto");
529
643
 
530
644
  // src/services/telemetry.service.ts
@@ -560,8 +674,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
560
674
  return decodedFile;
561
675
  };
562
676
  }
563
- function normalizeWindowsPath(path64) {
564
- return path64.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
677
+ function normalizeWindowsPath(path65) {
678
+ return path65.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
565
679
  }
566
680
 
567
681
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3041,9 +3155,9 @@ async function addSourceContext(frames) {
3041
3155
  LRU_FILE_CONTENTS_CACHE.reduce();
3042
3156
  return frames;
3043
3157
  }
3044
- function getContextLinesFromFile(path64, ranges, output) {
3158
+ function getContextLinesFromFile(path65, ranges, output) {
3045
3159
  return new Promise((resolve7) => {
3046
- const stream = (0, import_node_fs.createReadStream)(path64);
3160
+ const stream = (0, import_node_fs.createReadStream)(path65);
3047
3161
  const lineReaded = (0, import_node_readline.createInterface)({
3048
3162
  input: stream
3049
3163
  });
@@ -3058,7 +3172,7 @@ function getContextLinesFromFile(path64, ranges, output) {
3058
3172
  let rangeStart = range[0];
3059
3173
  let rangeEnd = range[1];
3060
3174
  function onStreamError() {
3061
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path64, 1);
3175
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path65, 1);
3062
3176
  lineReaded.close();
3063
3177
  lineReaded.removeAllListeners();
3064
3178
  destroyStreamAndResolve();
@@ -3119,8 +3233,8 @@ function clearLineContext(frame) {
3119
3233
  delete frame.context_line;
3120
3234
  delete frame.post_context;
3121
3235
  }
3122
- function shouldSkipContextLinesForFile(path64) {
3123
- return path64.startsWith("node:") || path64.endsWith(".min.js") || path64.endsWith(".min.cjs") || path64.endsWith(".min.mjs") || path64.startsWith("data:");
3236
+ function shouldSkipContextLinesForFile(path65) {
3237
+ return path65.startsWith("node:") || path65.endsWith(".min.js") || path65.endsWith(".min.cjs") || path65.endsWith(".min.mjs") || path65.startsWith("data:");
3124
3238
  }
3125
3239
  function shouldSkipContextLinesForFrame(frame) {
3126
3240
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5397,7 +5511,7 @@ function readAnonId() {
5397
5511
  }
5398
5512
  function superProperties() {
5399
5513
  return {
5400
- cliVersion: true ? "2.53.2" : "0.0.0-dev",
5514
+ cliVersion: true ? "2.53.4" : "0.0.0-dev",
5401
5515
  nodeVersion: process.version,
5402
5516
  platform: process.platform,
5403
5517
  arch: process.arch,
@@ -5578,7 +5692,7 @@ var os4 = __toESM(require("os"));
5578
5692
  // package.json
5579
5693
  var package_default = {
5580
5694
  name: "codeam-cli",
5581
- version: "2.53.2",
5695
+ version: "2.53.4",
5582
5696
  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.",
5583
5697
  type: "commonjs",
5584
5698
  main: "dist/index.js",
@@ -6106,9 +6220,9 @@ function computePollDelay({ baseMs, failures }) {
6106
6220
 
6107
6221
  // src/services/headroom/proxy-supervisor.ts
6108
6222
  var import_child_process2 = require("child_process");
6109
- var fs4 = __toESM(require("fs"));
6110
- var os5 = __toESM(require("os"));
6111
- var path4 = __toESM(require("path"));
6223
+ var fs5 = __toESM(require("fs"));
6224
+ var os6 = __toESM(require("os"));
6225
+ var path5 = __toESM(require("path"));
6112
6226
 
6113
6227
  // src/services/headroom/budget-args.ts
6114
6228
  function buildBudgetProxyArgs(env) {
@@ -6118,6 +6232,74 @@ function buildBudgetProxyArgs(env) {
6118
6232
  return ["--budget", budget, "--budget-period", period];
6119
6233
  }
6120
6234
 
6235
+ // src/services/headroom/proxy-pid.ts
6236
+ var import_node_child_process = require("child_process");
6237
+ var fs4 = __toESM(require("fs"));
6238
+ var os5 = __toESM(require("os"));
6239
+ var path4 = __toESM(require("path"));
6240
+ function headroomProxyPidfilePath() {
6241
+ return path4.join(os5.homedir(), ".codeam", "headroom-proxy.pid");
6242
+ }
6243
+ function writeHeadroomProxyPidfile(pid) {
6244
+ if (!pid) return;
6245
+ try {
6246
+ const file = headroomProxyPidfilePath();
6247
+ fs4.mkdirSync(path4.dirname(file), { recursive: true, mode: 448 });
6248
+ fs4.writeFileSync(file, `${pid}
6249
+ `, { encoding: "utf8", mode: 384 });
6250
+ } catch {
6251
+ }
6252
+ }
6253
+ function readHeadroomProxyPidfile() {
6254
+ try {
6255
+ const pid = Number(fs4.readFileSync(headroomProxyPidfilePath(), "utf8").trim());
6256
+ return Number.isInteger(pid) && pid > 0 ? pid : null;
6257
+ } catch {
6258
+ return null;
6259
+ }
6260
+ }
6261
+ function isPidAlive(pid) {
6262
+ try {
6263
+ process.kill(pid, 0);
6264
+ return true;
6265
+ } catch {
6266
+ return false;
6267
+ }
6268
+ }
6269
+ function pkillFallback() {
6270
+ try {
6271
+ const killer = (0, import_node_child_process.spawn)("pkill", ["-TERM", "-f", "headroom.*proxy"], {
6272
+ detached: true,
6273
+ stdio: "ignore"
6274
+ });
6275
+ killer.once("error", () => {
6276
+ });
6277
+ killer.unref();
6278
+ } catch {
6279
+ }
6280
+ }
6281
+ function killHeadroomProxy() {
6282
+ const pid = readHeadroomProxyPidfile();
6283
+ if (pid !== null && isPidAlive(pid)) {
6284
+ try {
6285
+ process.kill(pid, "SIGTERM");
6286
+ try {
6287
+ fs4.rmSync(headroomProxyPidfilePath(), { force: true });
6288
+ } catch {
6289
+ }
6290
+ return;
6291
+ } catch {
6292
+ }
6293
+ }
6294
+ if (pid !== null) {
6295
+ try {
6296
+ fs4.rmSync(headroomProxyPidfilePath(), { force: true });
6297
+ } catch {
6298
+ }
6299
+ }
6300
+ pkillFallback();
6301
+ }
6302
+
6121
6303
  // src/services/headroom/proxy-supervisor.ts
6122
6304
  async function ensureHeadroomProxy(deps) {
6123
6305
  if (!deps.isConfigured()) return "skip";
@@ -6132,17 +6314,17 @@ async function ensureHeadroomProxy(deps) {
6132
6314
  deps.spawnProxy();
6133
6315
  return "respawned";
6134
6316
  }
6135
- function isHeadroomConfiguredReal(homeDir2 = os5.homedir()) {
6317
+ function isHeadroomConfiguredReal(homeDir2 = os6.homedir()) {
6136
6318
  if (process.env.HEADROOM_ENABLED === "1") return true;
6137
- const csEnv = path4.join(homeDir2, ".codeam", "codespace-env.json");
6319
+ const csEnv = path5.join(homeDir2, ".codeam", "codespace-env.json");
6138
6320
  try {
6139
- const j2 = JSON.parse(fs4.readFileSync(csEnv, "utf8"));
6321
+ const j2 = JSON.parse(fs5.readFileSync(csEnv, "utf8"));
6140
6322
  if (j2.HEADROOM_ENABLED === "1" || j2.HEADROOM_ENABLED === 1) return true;
6141
6323
  } catch {
6142
6324
  }
6143
- const settings = path4.join(homeDir2, ".claude", "settings.json");
6325
+ const settings = path5.join(homeDir2, ".claude", "settings.json");
6144
6326
  try {
6145
- if (fs4.readFileSync(settings, "utf8").includes("127.0.0.1:8787")) return true;
6327
+ if (fs5.readFileSync(settings, "utf8").includes("127.0.0.1:8787")) return true;
6146
6328
  } catch {
6147
6329
  }
6148
6330
  return false;
@@ -6176,6 +6358,7 @@ function spawnProxyReal() {
6176
6358
  log.warn("headroom-supervisor", `respawn error (best-effort): ${e.message}`);
6177
6359
  });
6178
6360
  proxy.unref();
6361
+ writeHeadroomProxyPidfile(proxy.pid);
6179
6362
  } catch (e) {
6180
6363
  log.warn(
6181
6364
  "headroom-supervisor",
@@ -6543,7 +6726,7 @@ var CommandRelayService = class {
6543
6726
  // fresh + clear the "CLI update available" banner after a self-update
6544
6727
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
6545
6728
  // pair/reconnect). Older backends ignore the extra field.
6546
- ..."2.53.2" ? { ideVersion: "2.53.2" } : {}
6729
+ ..."2.53.4" ? { ideVersion: "2.53.4" } : {}
6547
6730
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
6548
6731
  }
6549
6732
  /**
@@ -6609,9 +6792,9 @@ var CommandRelayService = class {
6609
6792
 
6610
6793
  // src/services/file-watcher.service.ts
6611
6794
  var import_child_process3 = require("child_process");
6612
- var fs5 = __toESM(require("fs"));
6613
- var os6 = __toESM(require("os"));
6614
- var path5 = __toESM(require("path"));
6795
+ var fs6 = __toESM(require("fs"));
6796
+ var os7 = __toESM(require("os"));
6797
+ var path6 = __toESM(require("path"));
6615
6798
  var import_ignore = __toESM(require("ignore"));
6616
6799
 
6617
6800
  // src/services/file-watcher/diff-parser.ts
@@ -6770,10 +6953,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
6770
6953
  /[\\/]Start Menu([\\/]|$)/i,
6771
6954
  /[\\/]Templates([\\/]|$)/i
6772
6955
  ];
6773
- function isUnsafeWindowsWatchRoot(dir, homedir35) {
6956
+ function isUnsafeWindowsWatchRoot(dir, homedir36) {
6774
6957
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
6775
6958
  const cwd = norm(dir);
6776
- const home = norm(homedir35);
6959
+ const home = norm(homedir36);
6777
6960
  if (cwd === home) return true;
6778
6961
  if (/^[a-z]:$/.test(cwd)) return true;
6779
6962
  const sysRoots = [
@@ -6803,18 +6986,18 @@ var _findGitRootSeam = {
6803
6986
  resolve: _defaultFindGitRoot
6804
6987
  };
6805
6988
  function _defaultFindGitRoot(startDir) {
6806
- let dir = path5.resolve(startDir);
6989
+ let dir = path6.resolve(startDir);
6807
6990
  const seen = /* @__PURE__ */ new Set();
6808
6991
  for (let i = 0; i < 256; i++) {
6809
6992
  if (seen.has(dir)) return null;
6810
6993
  seen.add(dir);
6811
6994
  try {
6812
- const gitPath = path5.join(dir, ".git");
6813
- const stat3 = fs5.statSync(gitPath, { throwIfNoEntry: false });
6995
+ const gitPath = path6.join(dir, ".git");
6996
+ const stat3 = fs6.statSync(gitPath, { throwIfNoEntry: false });
6814
6997
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
6815
6998
  } catch {
6816
6999
  }
6817
- const parent = path5.dirname(dir);
7000
+ const parent = path6.dirname(dir);
6818
7001
  if (parent === dir) return null;
6819
7002
  dir = parent;
6820
7003
  }
@@ -6872,7 +7055,7 @@ var FileWatcherService = class {
6872
7055
  throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
6873
7056
  }
6874
7057
  const isWin = process.platform === "win32";
6875
- if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os6.homedir())) {
7058
+ if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os7.homedir())) {
6876
7059
  log.warn(
6877
7060
  "fileWatcher",
6878
7061
  `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.`
@@ -7059,7 +7242,7 @@ var FileWatcherService = class {
7059
7242
  }
7060
7243
  async emitForFile(absPath, changeType) {
7061
7244
  if (this.stopped) return;
7062
- const fileDir = path5.dirname(absPath);
7245
+ const fileDir = path6.dirname(absPath);
7063
7246
  let gitRoot = this.gitRootByDir.get(fileDir);
7064
7247
  if (gitRoot === void 0) {
7065
7248
  gitRoot = findGitRoot(fileDir);
@@ -7072,19 +7255,19 @@ var FileWatcherService = class {
7072
7255
  );
7073
7256
  return;
7074
7257
  }
7075
- const relPathInRepo = path5.relative(gitRoot, absPath);
7258
+ const relPathInRepo = path6.relative(gitRoot, absPath);
7076
7259
  if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
7077
7260
  const matcher = this.getGitIgnoreMatcher(gitRoot);
7078
7261
  if (matcher && matcher.ignores(relPathInRepo)) {
7079
7262
  log.trace(
7080
7263
  "fileWatcher",
7081
- `${relPathInRepo} ignored by ${path5.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
7264
+ `${relPathInRepo} ignored by ${path6.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
7082
7265
  );
7083
7266
  return;
7084
7267
  }
7085
7268
  this.opts.onRepoDirty?.(gitRoot);
7086
- const repoPath = path5.relative(this.opts.workingDir, gitRoot);
7087
- const repoName = path5.basename(gitRoot);
7269
+ const repoPath = path6.relative(this.opts.workingDir, gitRoot);
7270
+ const repoName = path6.basename(gitRoot);
7088
7271
  let diffText = "";
7089
7272
  let fileStatus = "modified";
7090
7273
  if (changeType === "unlink") {
@@ -7259,7 +7442,7 @@ var FileWatcherService = class {
7259
7442
  collectGitignoreFiles(repoRoot, dir, matcher) {
7260
7443
  let entries;
7261
7444
  try {
7262
- entries = fs5.readdirSync(dir, { withFileTypes: true });
7445
+ entries = fs6.readdirSync(dir, { withFileTypes: true });
7263
7446
  } catch {
7264
7447
  return;
7265
7448
  }
@@ -7268,16 +7451,16 @@ var FileWatcherService = class {
7268
7451
  );
7269
7452
  if (gitignoreEntry) {
7270
7453
  try {
7271
- const body = fs5.readFileSync(path5.join(dir, ".gitignore"), "utf8");
7272
- const rel = path5.relative(repoRoot, dir).replace(/\\/g, "/");
7454
+ const body = fs6.readFileSync(path6.join(dir, ".gitignore"), "utf8");
7455
+ const rel = path6.relative(repoRoot, dir).replace(/\\/g, "/");
7273
7456
  const prefixed = body.split(/\r?\n/).map((line) => {
7274
7457
  const trimmed = line.trim();
7275
7458
  if (!trimmed || trimmed.startsWith("#")) return line;
7276
7459
  if (!rel) return line;
7277
7460
  if (trimmed.startsWith("!")) {
7278
- return "!" + path5.posix.join(rel, trimmed.slice(1));
7461
+ return "!" + path6.posix.join(rel, trimmed.slice(1));
7279
7462
  }
7280
- return path5.posix.join(rel, trimmed);
7463
+ return path6.posix.join(rel, trimmed);
7281
7464
  }).join("\n");
7282
7465
  matcher.add(prefixed);
7283
7466
  } catch {
@@ -7286,7 +7469,7 @@ var FileWatcherService = class {
7286
7469
  for (const entry of entries) {
7287
7470
  if (!entry.isDirectory()) continue;
7288
7471
  if (entry.name === ".git") continue;
7289
- const childAbs = path5.join(dir, entry.name);
7472
+ const childAbs = path6.join(dir, entry.name);
7290
7473
  if (isIgnoredFilePath(childAbs)) continue;
7291
7474
  this.collectGitignoreFiles(repoRoot, childAbs, matcher);
7292
7475
  }
@@ -7917,76 +8100,76 @@ function closeAllTerminals() {
7917
8100
  }
7918
8101
 
7919
8102
  // src/commands/start/handlers.ts
7920
- var fs44 = __toESM(require("fs"));
7921
- var os37 = __toESM(require("os"));
7922
- var path49 = __toESM(require("path"));
8103
+ var fs45 = __toESM(require("fs"));
8104
+ var os38 = __toESM(require("os"));
8105
+ var path50 = __toESM(require("path"));
7923
8106
  var import_crypto3 = require("crypto");
7924
8107
  var import_child_process22 = require("child_process");
7925
8108
  var import_which2 = __toESM(require("which"));
7926
8109
 
7927
8110
  // src/lib/payload.ts
7928
- var import_zod = require("zod");
7929
- var fileEntrySchema = import_zod.z.object({
7930
- filename: import_zod.z.string().min(1).max(256),
7931
- mimeType: import_zod.z.string(),
7932
- base64: import_zod.z.string()
8111
+ var import_zod2 = require("zod");
8112
+ var fileEntrySchema = import_zod2.z.object({
8113
+ filename: import_zod2.z.string().min(1).max(256),
8114
+ mimeType: import_zod2.z.string(),
8115
+ base64: import_zod2.z.string()
7933
8116
  });
7934
- var startCommandSchema = import_zod.z.object({
7935
- prompt: import_zod.z.string().optional(),
7936
- files: import_zod.z.array(fileEntrySchema).optional(),
7937
- input: import_zod.z.string().optional(),
7938
- index: import_zod.z.number().optional(),
7939
- from: import_zod.z.number().optional(),
7940
- id: import_zod.z.string().optional(),
7941
- auto: import_zod.z.boolean().optional(),
8117
+ var startCommandSchema = import_zod2.z.object({
8118
+ prompt: import_zod2.z.string().optional(),
8119
+ files: import_zod2.z.array(fileEntrySchema).optional(),
8120
+ input: import_zod2.z.string().optional(),
8121
+ index: import_zod2.z.number().optional(),
8122
+ from: import_zod2.z.number().optional(),
8123
+ id: import_zod2.z.string().optional(),
8124
+ auto: import_zod2.z.boolean().optional(),
7942
8125
  // `read_file` / `write_file` for the mobile + landing mini-IDE modal.
7943
8126
  // `path` is bounded to 4096 chars (a comfortable POSIX path max) so a
7944
8127
  // malformed payload can't blow up the disk-side validator.
7945
- path: import_zod.z.string().min(1).max(4096).optional(),
7946
- content: import_zod.z.string().optional(),
8128
+ path: import_zod2.z.string().min(1).max(4096).optional(),
8129
+ content: import_zod2.z.string().optional(),
7947
8130
  // Mini-IDE / project ops. `paths` (plural, strings) is used for
7948
8131
  // git_commit's optional file selection — distinct from `files`
7949
8132
  // (FileEntry[]) used by `start_task` for attachments.
7950
- query: import_zod.z.string().max(256).optional(),
7951
- message: import_zod.z.string().max(8e3).optional(),
7952
- paths: import_zod.z.array(import_zod.z.string().max(4096)).optional(),
8133
+ query: import_zod2.z.string().max(256).optional(),
8134
+ message: import_zod2.z.string().max(8e3).optional(),
8135
+ paths: import_zod2.z.array(import_zod2.z.string().max(4096)).optional(),
7953
8136
  // `show_install_command` — backend pushes the self-hosted install
7954
8137
  // one-liner the user copies onto their own box. DISPLAY-ONLY: the
7955
8138
  // CLI prints it to the terminal and never executes it. Bounded to
7956
8139
  // 8192 chars so a malformed payload can't flood the terminal.
7957
- command: import_zod.z.string().min(1).max(8192).optional(),
7958
- side: import_zod.z.enum(["ours", "theirs"]).optional(),
7959
- limit: import_zod.z.number().int().min(1).max(500).optional(),
8140
+ command: import_zod2.z.string().min(1).max(8192).optional(),
8141
+ side: import_zod2.z.enum(["ours", "theirs"]).optional(),
8142
+ limit: import_zod2.z.number().int().min(1).max(500).optional(),
7960
8143
  // search_files options. `query` is the haystack/needle string,
7961
8144
  // declared above for list_files. The rest mirror VS Code's
7962
8145
  // search panel toggles + the @codeam/ide-core SearchOptions
7963
8146
  // contract.
7964
- caseSensitive: import_zod.z.boolean().optional(),
7965
- wholeWord: import_zod.z.boolean().optional(),
7966
- regex: import_zod.z.boolean().optional(),
7967
- include: import_zod.z.array(import_zod.z.string().max(512)).max(64).optional(),
7968
- exclude: import_zod.z.array(import_zod.z.string().max(512)).max(64).optional(),
7969
- maxResults: import_zod.z.number().int().min(1).max(500).optional(),
8147
+ caseSensitive: import_zod2.z.boolean().optional(),
8148
+ wholeWord: import_zod2.z.boolean().optional(),
8149
+ regex: import_zod2.z.boolean().optional(),
8150
+ include: import_zod2.z.array(import_zod2.z.string().max(512)).max(64).optional(),
8151
+ exclude: import_zod2.z.array(import_zod2.z.string().max(512)).max(64).optional(),
8152
+ maxResults: import_zod2.z.number().int().min(1).max(500).optional(),
7970
8153
  // terminal_open / _write / _resize / _close. `sessionId` is the
7971
8154
  // opaque uuid returned by `terminal_open` and required by every
7972
8155
  // subsequent op. `data` carries keystrokes (any UTF-8 string).
7973
8156
  // `cwd` lets the host pin the spawn directory.
7974
- sessionId: import_zod.z.string().min(1).max(128).optional(),
7975
- data: import_zod.z.string().max(64 * 1024).optional(),
7976
- cwd: import_zod.z.string().max(4096).optional(),
7977
- cols: import_zod.z.number().int().min(1).max(500).optional(),
7978
- rows: import_zod.z.number().int().min(1).max(200).optional(),
8157
+ sessionId: import_zod2.z.string().min(1).max(128).optional(),
8158
+ data: import_zod2.z.string().max(64 * 1024).optional(),
8159
+ cwd: import_zod2.z.string().max(4096).optional(),
8160
+ cols: import_zod2.z.number().int().min(1).max(500).optional(),
8161
+ rows: import_zod2.z.number().int().min(1).max(200).optional(),
7979
8162
  // `apply_file_review` (Epic B follow-up — backend pushes this when
7980
8163
  // the user clicks APPROVE_CHANGES / REJECT_CHANGES in the diff
7981
8164
  // drawer). `filePath` is relative to the enclosing git repo; the
7982
8165
  // handler walks up from it to find `.git/` and runs `git add` or
7983
8166
  // `git restore` from there. `action='approved'` stages the edit,
7984
8167
  // `action='rejected'` discards every worktree change on the file.
7985
- filePath: import_zod.z.string().min(1).max(4096).optional(),
7986
- action: import_zod.z.enum(["approved", "rejected", "enable", "disable", "status"]).optional(),
8168
+ filePath: import_zod2.z.string().min(1).max(4096).optional(),
8169
+ action: import_zod2.z.enum(["approved", "rejected", "enable", "disable", "status"]).optional(),
7987
8170
  // `headroom_configure` — savings ingest URL delivered from the session
7988
8171
  // when enabling Headroom on-demand. Bounded to 2048 chars.
7989
- savingsIngestUrl: import_zod.z.string().url().max(2048).optional(),
8172
+ savingsIngestUrl: import_zod2.z.string().url().max(2048).optional(),
7990
8173
  // `request_link_credentials` — backend fires this from the
7991
8174
  // heartbeat handler when it notices the user is running an agent
7992
8175
  // they haven't vaulted yet. Also reused by `get_context` /
@@ -8002,7 +8185,7 @@ var startCommandSchema = import_zod.z.object({
8002
8185
  // Without nullable() zod rejects the whole payload, the dispatcher
8003
8186
  // logs "Ignoring malformed list_models payload" and the model
8004
8187
  // picker / context never load.
8005
- agentId: import_zod.z.string().max(64).nullable().optional(),
8188
+ agentId: import_zod2.z.string().max(64).nullable().optional(),
8006
8189
  // `request_ai_summary` / `request_ai_insight` — backend fires
8007
8190
  // these on turn-end (+ file selection) when LinkedAgent.
8008
8191
  // aiInsightsEnabled is true. The CLI spawns the agent in
@@ -8016,12 +8199,12 @@ var startCommandSchema = import_zod.z.object({
8016
8199
  // unchanged on the result POST so the backend doesn't have to
8017
8200
  // recompute (numbers came from file_changes; the agent only
8018
8201
  // writes the narrative).
8019
- turnId: import_zod.z.string().max(128).optional(),
8020
- fileChangeId: import_zod.z.string().max(128).optional(),
8021
- stats: import_zod.z.object({
8022
- added: import_zod.z.number().int(),
8023
- removed: import_zod.z.number().int(),
8024
- complexityShift: import_zod.z.number().int()
8202
+ turnId: import_zod2.z.string().max(128).optional(),
8203
+ fileChangeId: import_zod2.z.string().max(128).optional(),
8204
+ stats: import_zod2.z.object({
8205
+ added: import_zod2.z.number().int(),
8206
+ removed: import_zod2.z.number().int(),
8207
+ complexityShift: import_zod2.z.number().int()
8025
8208
  }).optional(),
8026
8209
  // `preview_start` carries the agent-detected `PreviewDetection`
8027
8210
  // shape from the mobile / web confirmation sheet. Mirrors
@@ -8030,23 +8213,23 @@ var startCommandSchema = import_zod.z.object({
8030
8213
  // running against a newer backend that adds optional fields still
8031
8214
  // accepts the payload; the handler validates the shape it needs
8032
8215
  // before spawning.
8033
- detection: import_zod.z.object({
8034
- framework: import_zod.z.string().max(64),
8035
- command: import_zod.z.string().min(1).max(256),
8036
- args: import_zod.z.array(import_zod.z.string().max(1024)).max(64),
8037
- port: import_zod.z.number().int().min(1).max(65535),
8038
- ready_pattern: import_zod.z.string().min(1).max(4096),
8039
- env: import_zod.z.record(import_zod.z.string(), import_zod.z.string().max(8192)).optional(),
8216
+ detection: import_zod2.z.object({
8217
+ framework: import_zod2.z.string().max(64),
8218
+ command: import_zod2.z.string().min(1).max(256),
8219
+ args: import_zod2.z.array(import_zod2.z.string().max(1024)).max(64),
8220
+ port: import_zod2.z.number().int().min(1).max(65535),
8221
+ ready_pattern: import_zod2.z.string().min(1).max(4096),
8222
+ env: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string().max(8192)).optional(),
8040
8223
  // The agent emits entries as either {cmd,args} objects OR bare command
8041
8224
  // strings ("npx prisma generate"). Accept both and normalize strings to
8042
8225
  // {cmd,args} so a string entry doesn't reject the whole detection (which
8043
8226
  // would silently drop the preview) and downstream always gets objects.
8044
- setup_commands: import_zod.z.array(
8045
- import_zod.z.union([
8046
- import_zod.z.string().min(1).max(1024),
8047
- import_zod.z.object({
8048
- cmd: import_zod.z.string().min(1).max(256),
8049
- args: import_zod.z.array(import_zod.z.string().max(1024)).max(64)
8227
+ setup_commands: import_zod2.z.array(
8228
+ import_zod2.z.union([
8229
+ import_zod2.z.string().min(1).max(1024),
8230
+ import_zod2.z.object({
8231
+ cmd: import_zod2.z.string().min(1).max(256),
8232
+ args: import_zod2.z.array(import_zod2.z.string().max(1024)).max(64)
8050
8233
  })
8051
8234
  ]).transform((entry) => {
8052
8235
  if (typeof entry !== "string") return entry;
@@ -8054,15 +8237,15 @@ var startCommandSchema = import_zod.z.object({
8054
8237
  return { cmd: parts[0] ?? "", args: parts.slice(1) };
8055
8238
  })
8056
8239
  ).max(32).optional(),
8057
- notes: import_zod.z.string().max(4096).nullable().optional()
8240
+ notes: import_zod2.z.string().max(4096).nullable().optional()
8058
8241
  }).optional(),
8059
8242
  // `env_write` carries the full desired set of environment variables
8060
8243
  // for the project `.env`. Bounded so a malformed payload can't flood
8061
8244
  // the disk-side serializer. `env_read` / `preview_restart` send no payload.
8062
- vars: import_zod.z.array(
8063
- import_zod.z.object({
8064
- key: import_zod.z.string().min(1).max(256),
8065
- value: import_zod.z.string().max(32768)
8245
+ vars: import_zod2.z.array(
8246
+ import_zod2.z.object({
8247
+ key: import_zod2.z.string().min(1).max(256),
8248
+ value: import_zod2.z.string().max(32768)
8066
8249
  })
8067
8250
  ).max(512).optional()
8068
8251
  });
@@ -8072,8 +8255,8 @@ function parsePayload2(schema, raw) {
8072
8255
  }
8073
8256
 
8074
8257
  // src/services/file-ops.service.ts
8075
- var fs6 = __toESM(require("fs/promises"));
8076
- var path7 = __toESM(require("path"));
8258
+ var fs7 = __toESM(require("fs/promises"));
8259
+ var path8 = __toESM(require("path"));
8077
8260
  var MAX_FILE_BYTES = 5 * 1024 * 1024;
8078
8261
  var MAX_WALK_DEPTH = 6;
8079
8262
  var MAX_VISITED_DIRS = 5e3;
@@ -8108,12 +8291,12 @@ var SUBDIR_IGNORE = /* @__PURE__ */ new Set([
8108
8291
  "__pycache__"
8109
8292
  ]);
8110
8293
  function isUnder(parent, candidate) {
8111
- const rel = path7.relative(parent, candidate);
8112
- return rel === "" || !rel.startsWith("..") && !path7.isAbsolute(rel);
8294
+ const rel = path8.relative(parent, candidate);
8295
+ return rel === "" || !rel.startsWith("..") && !path8.isAbsolute(rel);
8113
8296
  }
8114
8297
  async function isExistingFile(absPath) {
8115
8298
  try {
8116
- const stat3 = await fs6.stat(absPath);
8299
+ const stat3 = await fs7.stat(absPath);
8117
8300
  return stat3.isFile();
8118
8301
  } catch {
8119
8302
  return false;
@@ -8126,13 +8309,13 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
8126
8309
  ctx.visited++;
8127
8310
  let entries = [];
8128
8311
  try {
8129
- entries = await fs6.readdir(dir, { withFileTypes: true });
8312
+ entries = await fs7.readdir(dir, { withFileTypes: true });
8130
8313
  } catch {
8131
8314
  return;
8132
8315
  }
8133
8316
  for (const e of entries) {
8134
8317
  if (!e.isFile()) continue;
8135
- const full = path7.join(dir, e.name);
8318
+ const full = path8.join(dir, e.name);
8136
8319
  if (needleVariants.some((needle) => full.endsWith(needle))) {
8137
8320
  ctx.matches.push(full);
8138
8321
  if (ctx.matches.length >= ctx.cap) return;
@@ -8142,21 +8325,21 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
8142
8325
  if (!e.isDirectory()) continue;
8143
8326
  if (SUBDIR_IGNORE.has(e.name)) continue;
8144
8327
  if (e.name.startsWith(".") && SUBDIR_IGNORE.has(e.name)) continue;
8145
- await walkForSuffix(path7.join(dir, e.name), needleVariants, depth + 1, ctx);
8328
+ await walkForSuffix(path8.join(dir, e.name), needleVariants, depth + 1, ctx);
8146
8329
  if (ctx.matches.length >= ctx.cap) return;
8147
8330
  }
8148
8331
  }
8149
8332
  async function findFile(rawPath) {
8150
8333
  const cwd = process.cwd();
8151
- if (path7.isAbsolute(rawPath)) {
8152
- const abs = path7.normalize(rawPath);
8334
+ if (path8.isAbsolute(rawPath)) {
8335
+ const abs = path8.normalize(rawPath);
8153
8336
  if (isUnder(cwd, abs) && await isExistingFile(abs)) return abs;
8154
8337
  }
8155
- const direct = path7.resolve(cwd, rawPath);
8338
+ const direct = path8.resolve(cwd, rawPath);
8156
8339
  if (isUnder(cwd, direct) && await isExistingFile(direct)) return direct;
8157
- const normalized = path7.normalize(rawPath).replace(/^[./\\]+/, "");
8340
+ const normalized = path8.normalize(rawPath).replace(/^[./\\]+/, "");
8158
8341
  const needles = [
8159
- `${path7.sep}${normalized}`,
8342
+ `${path8.sep}${normalized}`,
8160
8343
  `/${normalized}`
8161
8344
  ].filter((v, i, a) => a.indexOf(v) === i);
8162
8345
  const ctx = { visited: 0, matches: [], cap: 16 };
@@ -8170,7 +8353,7 @@ async function findWriteTarget(rawPath) {
8170
8353
  const found = await findFile(rawPath);
8171
8354
  if (found) return found;
8172
8355
  const cwd = process.cwd();
8173
- const fallback = path7.isAbsolute(rawPath) ? path7.normalize(rawPath) : path7.resolve(cwd, rawPath);
8356
+ const fallback = path8.isAbsolute(rawPath) ? path8.normalize(rawPath) : path8.resolve(cwd, rawPath);
8174
8357
  if (!isUnder(cwd, fallback)) return null;
8175
8358
  return fallback;
8176
8359
  }
@@ -8187,11 +8370,11 @@ async function readProjectFile(rawPath) {
8187
8370
  if (!abs) {
8188
8371
  return { error: `File not found in the project tree: ${rawPath}` };
8189
8372
  }
8190
- const stat3 = await fs6.stat(abs);
8373
+ const stat3 = await fs7.stat(abs);
8191
8374
  if (stat3.size > MAX_FILE_BYTES) {
8192
8375
  return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
8193
8376
  }
8194
- const buf = await fs6.readFile(abs);
8377
+ const buf = await fs7.readFile(abs);
8195
8378
  if (looksBinary(buf)) {
8196
8379
  return { error: "Binary file \u2014 refusing to open in a code editor." };
8197
8380
  }
@@ -8210,8 +8393,8 @@ async function writeProjectFile(rawPath, content) {
8210
8393
  if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
8211
8394
  return { error: "Content too large." };
8212
8395
  }
8213
- await fs6.mkdir(path7.dirname(abs), { recursive: true });
8214
- await fs6.writeFile(abs, content, "utf-8");
8396
+ await fs7.mkdir(path8.dirname(abs), { recursive: true });
8397
+ await fs7.writeFile(abs, content, "utf-8");
8215
8398
  return { ok: true };
8216
8399
  } catch (e) {
8217
8400
  const msg = e instanceof Error ? e.message : "Write failed";
@@ -8222,8 +8405,8 @@ async function writeProjectFile(rawPath, content) {
8222
8405
  // src/services/project-ops.service.ts
8223
8406
  var import_child_process5 = require("child_process");
8224
8407
  var import_util = require("util");
8225
- var fs7 = __toESM(require("fs/promises"));
8226
- var path8 = __toESM(require("path"));
8408
+ var fs8 = __toESM(require("fs/promises"));
8409
+ var path9 = __toESM(require("path"));
8227
8410
  var execFileP = (0, import_util.promisify)(import_child_process5.execFile);
8228
8411
  var PROJECT_IGNORE = /* @__PURE__ */ new Set([
8229
8412
  "node_modules",
@@ -8271,7 +8454,7 @@ async function listProjectFiles(opts = {}) {
8271
8454
  }
8272
8455
  let entries = [];
8273
8456
  try {
8274
- entries = await fs7.readdir(dir, { withFileTypes: true });
8457
+ entries = await fs8.readdir(dir, { withFileTypes: true });
8275
8458
  } catch {
8276
8459
  return;
8277
8460
  }
@@ -8281,18 +8464,18 @@ async function listProjectFiles(opts = {}) {
8281
8464
  return;
8282
8465
  }
8283
8466
  if (PROJECT_IGNORE.has(e.name)) continue;
8284
- const full = path8.join(dir, e.name);
8467
+ const full = path9.join(dir, e.name);
8285
8468
  if (e.isDirectory()) {
8286
8469
  if (depth >= 12) continue;
8287
8470
  await walk(full, depth + 1);
8288
8471
  } else if (e.isFile()) {
8289
- const rel = path8.relative(root, full);
8472
+ const rel = path9.relative(root, full);
8290
8473
  if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
8291
8474
  continue;
8292
8475
  }
8293
8476
  let size = 0;
8294
8477
  try {
8295
- const st3 = await fs7.stat(full);
8478
+ const st3 = await fs8.stat(full);
8296
8479
  size = st3.size;
8297
8480
  } catch {
8298
8481
  }
@@ -8394,8 +8577,8 @@ async function gitStatus(cwd) {
8394
8577
  let hasMergeInProgress = false;
8395
8578
  try {
8396
8579
  const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
8397
- const mergeHead = path8.isAbsolute(gitDir) ? path8.join(gitDir, "MERGE_HEAD") : path8.join(root, gitDir, "MERGE_HEAD");
8398
- await fs7.access(mergeHead);
8580
+ const mergeHead = path9.isAbsolute(gitDir) ? path9.join(gitDir, "MERGE_HEAD") : path9.join(root, gitDir, "MERGE_HEAD");
8581
+ await fs8.access(mergeHead);
8399
8582
  hasMergeInProgress = true;
8400
8583
  } catch {
8401
8584
  }
@@ -8541,7 +8724,7 @@ async function jsSearchFiles(opts, cwd, cap) {
8541
8724
  }
8542
8725
  let content = "";
8543
8726
  try {
8544
- content = await fs7.readFile(path8.join(cwd, f.path), "utf8");
8727
+ content = await fs8.readFile(path9.join(cwd, f.path), "utf8");
8545
8728
  } catch {
8546
8729
  continue;
8547
8730
  }
@@ -8618,14 +8801,14 @@ function formatRemaining(expiresAt) {
8618
8801
 
8619
8802
  // src/services/apply-file-review.service.ts
8620
8803
  var import_child_process6 = require("child_process");
8621
- var fs8 = __toESM(require("fs"));
8622
- var path9 = __toESM(require("path"));
8804
+ var fs9 = __toESM(require("fs"));
8805
+ var path10 = __toESM(require("path"));
8623
8806
  async function applyFileReview(workingDir, filePath, action) {
8624
- if (filePath.includes("..") || path9.isAbsolute(filePath)) {
8807
+ if (filePath.includes("..") || path10.isAbsolute(filePath)) {
8625
8808
  return { ok: false, action, filePath, error: "invalid file path" };
8626
8809
  }
8627
- const absFile = path9.resolve(workingDir, filePath);
8628
- const repoRoot = findGitRoot2(path9.dirname(absFile));
8810
+ const absFile = path10.resolve(workingDir, filePath);
8811
+ const repoRoot = findGitRoot2(path10.dirname(absFile));
8629
8812
  if (!repoRoot) {
8630
8813
  return {
8631
8814
  ok: false,
@@ -8634,7 +8817,7 @@ async function applyFileReview(workingDir, filePath, action) {
8634
8817
  error: `no enclosing git repo for ${filePath}`
8635
8818
  };
8636
8819
  }
8637
- const relInRepo = path9.relative(repoRoot, absFile);
8820
+ const relInRepo = path10.relative(repoRoot, absFile);
8638
8821
  if (!relInRepo || relInRepo.startsWith("..")) {
8639
8822
  return { ok: false, action, filePath, error: "path escapes repo root" };
8640
8823
  }
@@ -8683,17 +8866,17 @@ function runGit2(cwd, args2) {
8683
8866
  });
8684
8867
  }
8685
8868
  function findGitRoot2(startDir) {
8686
- let dir = path9.resolve(startDir);
8869
+ let dir = path10.resolve(startDir);
8687
8870
  const seen = /* @__PURE__ */ new Set();
8688
8871
  for (let i = 0; i < 256; i++) {
8689
8872
  if (seen.has(dir)) return null;
8690
8873
  seen.add(dir);
8691
8874
  try {
8692
- const stat3 = fs8.statSync(path9.join(dir, ".git"), { throwIfNoEntry: false });
8875
+ const stat3 = fs9.statSync(path10.join(dir, ".git"), { throwIfNoEntry: false });
8693
8876
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
8694
8877
  } catch {
8695
8878
  }
8696
- const parent = path9.dirname(dir);
8879
+ const parent = path10.dirname(dir);
8697
8880
  if (parent === dir) return null;
8698
8881
  dir = parent;
8699
8882
  }
@@ -8702,8 +8885,8 @@ function findGitRoot2(startDir) {
8702
8885
 
8703
8886
  // src/commands/link.ts
8704
8887
  var import_node_crypto5 = require("crypto");
8705
- var fs26 = __toESM(require("fs"));
8706
- var path31 = __toESM(require("path"));
8888
+ var fs27 = __toESM(require("fs"));
8889
+ var path32 = __toESM(require("path"));
8707
8890
  var import_chokidar = __toESM(require("chokidar"));
8708
8891
  var import_picocolors2 = __toESM(require("picocolors"));
8709
8892
 
@@ -8727,7 +8910,7 @@ __export(dist_exports, {
8727
8910
  S_ERROR: () => ge,
8728
8911
  S_INFO: () => he,
8729
8912
  S_PASSWORD_MASK: () => xe,
8730
- S_RADIO_ACTIVE: () => z3,
8913
+ S_RADIO_ACTIVE: () => z4,
8731
8914
  S_RADIO_INACTIVE: () => H2,
8732
8915
  S_STEP_ACTIVE: () => _e,
8733
8916
  S_STEP_CANCEL: () => oe,
@@ -9206,7 +9389,7 @@ function w(r, t2) {
9206
9389
  const e = r;
9207
9390
  e.isTTY && e.setRawMode(t2);
9208
9391
  }
9209
- function z2({ input: r = import_node_process.stdin, output: t2 = import_node_process.stdout, overwrite: e = true, hideCursor: s = true } = {}) {
9392
+ function z3({ input: r = import_node_process.stdin, output: t2 = import_node_process.stdout, overwrite: e = true, hideCursor: s = true } = {}) {
9210
9393
  const i = _.createInterface({ input: r, output: t2, prompt: "", tabSize: 1 });
9211
9394
  _.emitKeypressEvents(r, i), r instanceof import_node_tty.ReadStream && r.isTTY && r.setRawMode(true);
9212
9395
  const n = (o, { name: a, sequence: h }) => {
@@ -9818,7 +10001,7 @@ var d2 = w2("\u2502", "|");
9818
10001
  var E2 = w2("\u2514", "\u2014");
9819
10002
  var Ie = w2("\u2510", "T");
9820
10003
  var Ee = w2("\u2518", "\u2014");
9821
- var z3 = w2("\u25CF", ">");
10004
+ var z4 = w2("\u25CF", ">");
9822
10005
  var H2 = w2("\u25CB", " ");
9823
10006
  var te = w2("\u25FB", "[\u2022]");
9824
10007
  var U = w2("\u25FC", "[+]");
@@ -9910,7 +10093,7 @@ var Ae = (e) => new H({ options: e.options, initialValue: e.initialValue ? [e.in
9910
10093
  const $2 = Me(a), y2 = a.hint && a.value === this.focusedValue ? (0, import_node_util2.styleText)("dim", ` (${a.hint})`) : "";
9911
10094
  switch (l) {
9912
10095
  case "active":
9913
- return `${(0, import_node_util2.styleText)("green", z3)} ${$2}${y2}`;
10096
+ return `${(0, import_node_util2.styleText)("green", z4)} ${$2}${y2}`;
9914
10097
  case "inactive":
9915
10098
  return `${(0, import_node_util2.styleText)("dim", H2)} ${(0, import_node_util2.styleText)("dim", $2)}`;
9916
10099
  case "disabled":
@@ -10023,9 +10206,9 @@ ${(0, import_node_util2.styleText)("gray", d2)}` : ""}`;
10023
10206
  }
10024
10207
  default: {
10025
10208
  const l = r ? `${(0, import_node_util2.styleText)("cyan", d2)} ` : "", $2 = r ? (0, import_node_util2.styleText)("cyan", E2) : "";
10026
- return `${c2}${l}${this.value ? `${(0, import_node_util2.styleText)("green", z3)} ${i}` : `${(0, import_node_util2.styleText)("dim", H2)} ${(0, import_node_util2.styleText)("dim", i)}`}${e.vertical ? r ? `
10209
+ return `${c2}${l}${this.value ? `${(0, import_node_util2.styleText)("green", z4)} ${i}` : `${(0, import_node_util2.styleText)("dim", H2)} ${(0, import_node_util2.styleText)("dim", i)}`}${e.vertical ? r ? `
10027
10210
  ${(0, import_node_util2.styleText)("cyan", d2)} ` : `
10028
- ` : ` ${(0, import_node_util2.styleText)("dim", "/")} `}${this.value ? `${(0, import_node_util2.styleText)("dim", H2)} ${(0, import_node_util2.styleText)("dim", s)}` : `${(0, import_node_util2.styleText)("green", z3)} ${s}`}
10211
+ ` : ` ${(0, import_node_util2.styleText)("dim", "/")} `}${this.value ? `${(0, import_node_util2.styleText)("dim", H2)} ${(0, import_node_util2.styleText)("dim", s)}` : `${(0, import_node_util2.styleText)("green", z4)} ${s}`}
10029
10212
  ${$2}
10030
10213
  `;
10031
10214
  }
@@ -10356,7 +10539,7 @@ var fe = ({ indicator: e = "dots", onCancel: i, output: s = process.stdout, canc
10356
10539
  const A2 = (performance.now() - _2) / 1e3, k2 = Math.floor(A2 / 60), L2 = Math.floor(A2 % 60);
10357
10540
  return k2 > 0 ? `[${k2}m ${L2}s]` : `[${L2}s]`;
10358
10541
  }, D2 = a.withGuide ?? u.withGuide, ie = (_2 = "") => {
10359
- p2 = true, $2 = z2({ output: s }), g = R2(_2), h = performance.now(), D2 && s.write(`${(0, import_node_util2.styleText)("gray", d2)}
10542
+ p2 = true, $2 = z3({ output: s }), g = R2(_2), h = performance.now(), D2 && s.write(`${(0, import_node_util2.styleText)("gray", d2)}
10360
10543
  `);
10361
10544
  let A2 = 0, k2 = 0;
10362
10545
  x(), y2 = setInterval(() => {
@@ -10427,7 +10610,7 @@ var _t = (e) => {
10427
10610
  case "selected":
10428
10611
  return `${re(u2, (n) => (0, import_node_util2.styleText)("dim", n))}`;
10429
10612
  case "active":
10430
- return `${(0, import_node_util2.styleText)("green", z3)} ${u2}${s.hint ? ` ${(0, import_node_util2.styleText)("dim", `(${s.hint})`)}` : ""}`;
10613
+ return `${(0, import_node_util2.styleText)("green", z4)} ${u2}${s.hint ? ` ${(0, import_node_util2.styleText)("dim", `(${s.hint})`)}` : ""}`;
10431
10614
  case "cancelled":
10432
10615
  return `${re(u2, (n) => (0, import_node_util2.styleText)(["strikethrough", "dim"], n))}`;
10433
10616
  default:
@@ -10758,19 +10941,19 @@ function parseFrame(frame, dispatch) {
10758
10941
  }
10759
10942
 
10760
10943
  // src/os/posix.ts
10761
- var fs10 = __toESM(require("fs"));
10762
- var os8 = __toESM(require("os"));
10763
- var path12 = __toESM(require("path"));
10944
+ var fs11 = __toESM(require("fs"));
10945
+ var os9 = __toESM(require("os"));
10946
+ var path13 = __toESM(require("path"));
10764
10947
  var import_node_crypto2 = require("crypto");
10765
10948
 
10766
10949
  // src/os/strategy.ts
10767
- var path10 = __toESM(require("path"));
10950
+ var path11 = __toESM(require("path"));
10768
10951
  function findInPathFor(name, opts) {
10769
- const dirs = (process.env.PATH ?? "").split(path10.delimiter).filter(Boolean);
10952
+ const dirs = (process.env.PATH ?? "").split(path11.delimiter).filter(Boolean);
10770
10953
  const candidates = opts.candidates(name);
10771
10954
  for (const dir of dirs) {
10772
10955
  for (const candidate of candidates) {
10773
- const full = path10.join(dir, candidate);
10956
+ const full = path11.join(dir, candidate);
10774
10957
  try {
10775
10958
  opts.accessSync(full, opts.accessFlag);
10776
10959
  return full;
@@ -10783,9 +10966,9 @@ function findInPathFor(name, opts) {
10783
10966
 
10784
10967
  // src/services/pty/unix.strategy.ts
10785
10968
  var import_child_process7 = require("child_process");
10786
- var fs9 = __toESM(require("fs"));
10787
- var os7 = __toESM(require("os"));
10788
- var path11 = __toESM(require("path"));
10969
+ var fs10 = __toESM(require("fs"));
10970
+ var os8 = __toESM(require("os"));
10971
+ var path12 = __toESM(require("path"));
10789
10972
 
10790
10973
  // src/services/pty/types.ts
10791
10974
  function findInPath(name) {
@@ -10867,8 +11050,8 @@ var UnixPtyStrategy = class {
10867
11050
  }
10868
11051
  const cols = process.stdout.columns || 220;
10869
11052
  const rows = process.stdout.rows || 50;
10870
- this.helperPath = path11.join(os7.tmpdir(), "codeam-pty-helper.py");
10871
- fs9.writeFileSync(this.helperPath, PYTHON_PTY_HELPER, { mode: 420 });
11053
+ this.helperPath = path12.join(os8.tmpdir(), "codeam-pty-helper.py");
11054
+ fs10.writeFileSync(this.helperPath, PYTHON_PTY_HELPER, { mode: 420 });
10872
11055
  this.proc = (0, import_child_process7.spawn)(python, [this.helperPath, cmd, ...args2], {
10873
11056
  stdio: ["pipe", "pipe", "inherit"],
10874
11057
  cwd,
@@ -10997,7 +11180,7 @@ var UnixPtyStrategy = class {
10997
11180
  removeTempFile() {
10998
11181
  if (this.helperPath) {
10999
11182
  try {
11000
- fs9.unlinkSync(this.helperPath);
11183
+ fs10.unlinkSync(this.helperPath);
11001
11184
  } catch {
11002
11185
  }
11003
11186
  this.helperPath = null;
@@ -11008,11 +11191,11 @@ var UnixPtyStrategy = class {
11008
11191
  // src/os/posix.ts
11009
11192
  var PosixOsStrategy = class {
11010
11193
  homeDir() {
11011
- return os8.homedir();
11194
+ return os9.homedir();
11012
11195
  }
11013
11196
  scratchPath(prefix) {
11014
11197
  const tag = `${process.pid}-${(0, import_node_crypto2.randomBytes)(4).toString("hex")}`;
11015
- return path12.join(os8.tmpdir(), `${prefix}-${tag}`);
11198
+ return path13.join(os9.tmpdir(), `${prefix}-${tag}`);
11016
11199
  }
11017
11200
  devNull() {
11018
11201
  return "/dev/null";
@@ -11020,8 +11203,8 @@ var PosixOsStrategy = class {
11020
11203
  findInPath(name) {
11021
11204
  return findInPathFor(name, {
11022
11205
  candidates: () => [name],
11023
- accessFlag: fs10.constants.X_OK,
11024
- accessSync: fs10.accessSync
11206
+ accessFlag: fs11.constants.X_OK,
11207
+ accessSync: fs11.accessSync
11025
11208
  });
11026
11209
  }
11027
11210
  augmentPath(dirs) {
@@ -11049,15 +11232,15 @@ var LinuxOsStrategy = class extends PosixOsStrategy {
11049
11232
  };
11050
11233
 
11051
11234
  // src/os/win32.ts
11052
- var fs11 = __toESM(require("fs"));
11053
- var os9 = __toESM(require("os"));
11054
- var path14 = __toESM(require("path"));
11235
+ var fs12 = __toESM(require("fs"));
11236
+ var os10 = __toESM(require("os"));
11237
+ var path15 = __toESM(require("path"));
11055
11238
  var import_node_crypto3 = require("crypto");
11056
11239
 
11057
11240
  // src/services/pty/windows-conpty.strategy.ts
11058
- var path13 = __toESM(require("path"));
11241
+ var path14 = __toESM(require("path"));
11059
11242
  function loadNodePty2() {
11060
- const vendoredPath = path13.join(__dirname, "vendor", "node-pty");
11243
+ const vendoredPath = path14.join(__dirname, "vendor", "node-pty");
11061
11244
  try {
11062
11245
  return require(vendoredPath);
11063
11246
  } catch (vendorErr) {
@@ -11243,25 +11426,25 @@ var WINDOWS_EXEC_EXTS = [".exe", ".cmd", ".bat", ".ps1"];
11243
11426
  var Win32OsStrategy = class {
11244
11427
  id = "win32";
11245
11428
  homeDir() {
11246
- return os9.homedir();
11429
+ return os10.homedir();
11247
11430
  }
11248
11431
  scratchPath(prefix) {
11249
11432
  const tag = `${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}`;
11250
- return path14.join(os9.tmpdir(), `${prefix}-${tag}`);
11433
+ return path15.join(os10.tmpdir(), `${prefix}-${tag}`);
11251
11434
  }
11252
11435
  devNull() {
11253
11436
  return "NUL";
11254
11437
  }
11255
11438
  findInPath(name) {
11256
- const hasExt = path14.extname(name).length > 0;
11439
+ const hasExt = path15.extname(name).length > 0;
11257
11440
  return findInPathFor(name, {
11258
11441
  candidates: (n) => hasExt ? [n] : [...WINDOWS_EXEC_EXTS.map((ext) => `${n}${ext}`), n],
11259
11442
  // Windows has no Unix execute bit; presence + matching extension
11260
11443
  // IS the executability check. X_OK on Windows is a no-op alias
11261
11444
  // for F_OK at the libuv layer anyway, but F_OK makes intent
11262
11445
  // explicit.
11263
- accessFlag: fs11.constants.F_OK,
11264
- accessSync: fs11.accessSync
11446
+ accessFlag: fs12.constants.F_OK,
11447
+ accessSync: fs12.accessSync
11265
11448
  });
11266
11449
  }
11267
11450
  augmentPath(dirs) {
@@ -11298,7 +11481,7 @@ var Win32OsStrategy = class {
11298
11481
  return `"${escaped.replace(/[&|^<>()%!]/g, "^$&")}"`;
11299
11482
  }
11300
11483
  buildLaunch(binaryPath, extraArgs = []) {
11301
- const ext = path14.extname(binaryPath).toLowerCase();
11484
+ const ext = path15.extname(binaryPath).toLowerCase();
11302
11485
  if (ext === ".cmd" || ext === ".bat") {
11303
11486
  return { cmd: "cmd.exe", args: ["/c", binaryPath, ...extraArgs] };
11304
11487
  }
@@ -11353,28 +11536,28 @@ function buildForPlatform(platform3) {
11353
11536
  var import_node_crypto4 = require("crypto");
11354
11537
 
11355
11538
  // src/agents/claude/resolver.ts
11356
- function buildClaudeLaunch(extraArgs = [], os44 = createOsStrategy()) {
11357
- const found = os44.findInPath("claude") ?? os44.findInPath("claude-code");
11539
+ function buildClaudeLaunch(extraArgs = [], os45 = createOsStrategy()) {
11540
+ const found = os45.findInPath("claude") ?? os45.findInPath("claude-code");
11358
11541
  if (!found) return null;
11359
- return os44.buildLaunch(found, extraArgs);
11542
+ return os45.buildLaunch(found, extraArgs);
11360
11543
  }
11361
11544
 
11362
11545
  // src/agents/claude/installer.ts
11363
11546
  var import_child_process9 = require("child_process");
11364
- var path15 = __toESM(require("path"));
11365
- var os10 = __toESM(require("os"));
11547
+ var path16 = __toESM(require("path"));
11548
+ var os11 = __toESM(require("os"));
11366
11549
  function probeInstallDirs() {
11367
- const home = os10.homedir();
11550
+ const home = os11.homedir();
11368
11551
  if (process.platform === "win32") {
11369
11552
  return [
11370
- path15.join(home, ".claude", "local"),
11371
- path15.join(home, "AppData", "Local", "AnthropicClaude"),
11372
- path15.join(home, "AppData", "Local", "Programs", "AnthropicClaude")
11553
+ path16.join(home, ".claude", "local"),
11554
+ path16.join(home, "AppData", "Local", "AnthropicClaude"),
11555
+ path16.join(home, "AppData", "Local", "Programs", "AnthropicClaude")
11373
11556
  ];
11374
11557
  }
11375
11558
  return [
11376
- path15.join(home, ".local", "bin"),
11377
- path15.join(home, ".claude", "local"),
11559
+ path16.join(home, ".local", "bin"),
11560
+ path16.join(home, ".claude", "local"),
11378
11561
  "/usr/local/bin"
11379
11562
  ];
11380
11563
  }
@@ -11383,7 +11566,7 @@ function isAvailable() {
11383
11566
  }
11384
11567
  function augmentPath() {
11385
11568
  const dirs = probeInstallDirs();
11386
- const sep7 = path15.delimiter;
11569
+ const sep7 = path16.delimiter;
11387
11570
  const current = process.env.PATH ?? "";
11388
11571
  const existing = new Set(current.split(sep7).filter(Boolean));
11389
11572
  const additions = dirs.filter((d3) => !existing.has(d3));
@@ -11441,15 +11624,15 @@ async function ensureClaudeInstalled() {
11441
11624
  }
11442
11625
 
11443
11626
  // src/agents/claude/link.ts
11444
- var import_node_child_process2 = require("child_process");
11627
+ var import_node_child_process3 = require("child_process");
11445
11628
 
11446
11629
  // src/agents/claude/local-token.ts
11447
- var import_node_child_process = require("child_process");
11448
- var fs12 = __toESM(require("fs"));
11449
- var os11 = __toESM(require("os"));
11450
- var path16 = __toESM(require("path"));
11630
+ var import_node_child_process2 = require("child_process");
11631
+ var fs13 = __toESM(require("fs"));
11632
+ var os12 = __toESM(require("os"));
11633
+ var path17 = __toESM(require("path"));
11451
11634
  var import_node_util3 = require("util");
11452
- var execFileP2 = (0, import_node_util3.promisify)(import_node_child_process.execFile);
11635
+ var execFileP2 = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
11453
11636
  var KEYCHAIN_SERVICE_NAMES = [
11454
11637
  "Claude Code-credentials",
11455
11638
  "claude-code-credentials",
@@ -11457,17 +11640,17 @@ var KEYCHAIN_SERVICE_NAMES = [
11457
11640
  "Anthropic Claude"
11458
11641
  ];
11459
11642
  function claudeCredentialsPaths() {
11460
- const home = os11.homedir();
11643
+ const home = os12.homedir();
11461
11644
  return [
11462
- path16.join(home, ".claude", ".credentials.json"),
11463
- path16.join(home, ".config", "claude", ".credentials.json")
11645
+ path17.join(home, ".claude", ".credentials.json"),
11646
+ path17.join(home, ".config", "claude", ".credentials.json")
11464
11647
  ];
11465
11648
  }
11466
11649
  async function extractLocalClaudeToken() {
11467
11650
  const agentState = readClaudeAgentState();
11468
11651
  for (const flat of claudeCredentialsPaths()) {
11469
- if (!fs12.existsSync(flat)) continue;
11470
- const credential = fs12.readFileSync(flat, "utf8").trim();
11652
+ if (!fs13.existsSync(flat)) continue;
11653
+ const credential = fs13.readFileSync(flat, "utf8").trim();
11471
11654
  if (credential.length > 0) {
11472
11655
  return { method: "oauth", credential, source: "flat-file", agentState };
11473
11656
  }
@@ -11492,10 +11675,10 @@ async function extractLocalClaudeToken() {
11492
11675
  }
11493
11676
  function readClaudeAgentState() {
11494
11677
  const STATE_MAX_BYTES = 256 * 1024;
11495
- const candidate = path16.join(os11.homedir(), ".claude.json");
11678
+ const candidate = path17.join(os12.homedir(), ".claude.json");
11496
11679
  try {
11497
- if (!fs12.existsSync(candidate)) return void 0;
11498
- const buf = fs12.readFileSync(candidate);
11680
+ if (!fs13.existsSync(candidate)) return void 0;
11681
+ const buf = fs13.readFileSync(candidate);
11499
11682
  if (buf.length === 0 || buf.length > STATE_MAX_BYTES) return void 0;
11500
11683
  const text = buf.toString("utf8").trim();
11501
11684
  return text.length > 0 ? text : void 0;
@@ -11542,7 +11725,7 @@ function extractSetupTokenFromOutput(output) {
11542
11725
  }
11543
11726
  function captureClaudeSetupToken() {
11544
11727
  return new Promise((resolve7, reject) => {
11545
- const child = (0, import_node_child_process2.spawn)("claude", ["setup-token"], {
11728
+ const child = (0, import_node_child_process3.spawn)("claude", ["setup-token"], {
11546
11729
  stdio: ["inherit", "pipe", "inherit"]
11547
11730
  });
11548
11731
  let out2 = "";
@@ -11570,7 +11753,7 @@ function claudeLoginLauncher() {
11570
11753
  return {
11571
11754
  ensureInstalled: ensureClaudeInstalled,
11572
11755
  launch() {
11573
- const child = (0, import_node_child_process2.spawn)("claude", [], { stdio: ["pipe", "inherit", "inherit"] });
11756
+ const child = (0, import_node_child_process3.spawn)("claude", [], { stdio: ["pipe", "inherit", "inherit"] });
11574
11757
  child.stdin?.write("/login\n");
11575
11758
  return child;
11576
11759
  },
@@ -11582,9 +11765,9 @@ function claudeLoginLauncher() {
11582
11765
  }
11583
11766
 
11584
11767
  // src/agents/claude/quota.ts
11585
- var fs13 = __toESM(require("fs"));
11586
- var os12 = __toESM(require("os"));
11587
- var path17 = __toESM(require("path"));
11768
+ var fs14 = __toESM(require("fs"));
11769
+ var os13 = __toESM(require("os"));
11770
+ var path18 = __toESM(require("path"));
11588
11771
  var import_child_process10 = require("child_process");
11589
11772
  var HELPER_SCRIPT = `import os,pty,sys,select,signal,struct,fcntl,termios,errno
11590
11773
  m,s=pty.openpty()
@@ -11647,8 +11830,8 @@ async function fetchClaudeQuota() {
11647
11830
  resolve7(null);
11648
11831
  return;
11649
11832
  }
11650
- const helperPath = path17.join(os12.tmpdir(), "codeam-quota-helper.py");
11651
- fs13.writeFileSync(helperPath, HELPER_SCRIPT, { mode: 420 });
11833
+ const helperPath = path18.join(os13.tmpdir(), "codeam-quota-helper.py");
11834
+ fs14.writeFileSync(helperPath, HELPER_SCRIPT, { mode: 420 });
11652
11835
  const python = findInPath("python3") ?? findInPath("python");
11653
11836
  if (!python) {
11654
11837
  resolve7(null);
@@ -11675,7 +11858,7 @@ async function fetchClaudeQuota() {
11675
11858
  } catch {
11676
11859
  }
11677
11860
  try {
11678
- fs13.unlinkSync(helperPath);
11861
+ fs14.unlinkSync(helperPath);
11679
11862
  } catch {
11680
11863
  }
11681
11864
  resolve7(result);
@@ -11768,24 +11951,24 @@ async function spawnAndCapture(cmd, args2, opts = {}) {
11768
11951
  }
11769
11952
 
11770
11953
  // src/agents/claude/history.ts
11771
- var fs14 = __toESM(require("fs"));
11772
- var path18 = __toESM(require("path"));
11773
- var os13 = __toESM(require("os"));
11954
+ var fs15 = __toESM(require("fs"));
11955
+ var path19 = __toESM(require("path"));
11956
+ var os14 = __toESM(require("os"));
11774
11957
  function encodeCwd(cwd) {
11775
11958
  return cwd.replace(/[\\/:]/g, "-");
11776
11959
  }
11777
11960
  function resolveHistoryDir(cwd, projectsRoot) {
11778
- const root = projectsRoot ?? path18.join(os13.homedir(), ".claude", "projects");
11779
- const primary = path18.join(root, encodeCwd(cwd));
11780
- if (fs14.existsSync(primary)) return primary;
11961
+ const root = projectsRoot ?? path19.join(os14.homedir(), ".claude", "projects");
11962
+ const primary = path19.join(root, encodeCwd(cwd));
11963
+ if (fs15.existsSync(primary)) return primary;
11781
11964
  try {
11782
- const entries = fs14.readdirSync(root, { withFileTypes: true });
11965
+ const entries = fs15.readdirSync(root, { withFileTypes: true });
11783
11966
  const wanted = encodeCwd(cwd);
11784
11967
  for (const e of entries) {
11785
11968
  if (!e.isDirectory()) continue;
11786
11969
  const candidate = e.name.replace(/-+/g, "-");
11787
11970
  if (candidate === wanted.replace(/-+/g, "-")) {
11788
- return path18.join(root, e.name);
11971
+ return path19.join(root, e.name);
11789
11972
  }
11790
11973
  }
11791
11974
  } catch {
@@ -11797,23 +11980,23 @@ function getCurrentUsage(historyDir, bootTimeMs = 0) {
11797
11980
  const cutoff = bootTimeMs > 0 ? bootTimeMs - GRACE_MS : 0;
11798
11981
  let entries;
11799
11982
  try {
11800
- entries = fs14.readdirSync(historyDir, { withFileTypes: true });
11983
+ entries = fs15.readdirSync(historyDir, { withFileTypes: true });
11801
11984
  } catch {
11802
11985
  return null;
11803
11986
  }
11804
11987
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
11805
11988
  try {
11806
- const stat3 = fs14.statSync(path18.join(historyDir, e.name));
11989
+ const stat3 = fs15.statSync(path19.join(historyDir, e.name));
11807
11990
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
11808
11991
  } catch {
11809
11992
  return { name: e.name, mtime: 0, birthtime: 0 };
11810
11993
  }
11811
11994
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
11812
11995
  if (files.length === 0) return null;
11813
- const filePath = path18.join(historyDir, files[0].name);
11996
+ const filePath = path19.join(historyDir, files[0].name);
11814
11997
  let raw;
11815
11998
  try {
11816
- raw = fs14.readFileSync(filePath, "utf8");
11999
+ raw = fs15.readFileSync(filePath, "utf8");
11817
12000
  } catch {
11818
12001
  return null;
11819
12002
  }
@@ -11858,7 +12041,7 @@ function parseHistoryFile(filePath) {
11858
12041
  const out2 = [];
11859
12042
  let raw;
11860
12043
  try {
11861
- raw = fs14.readFileSync(filePath, "utf8");
12044
+ raw = fs15.readFileSync(filePath, "utf8");
11862
12045
  } catch {
11863
12046
  return out2;
11864
12047
  }
@@ -11903,7 +12086,7 @@ function listResumableSessions(cwd) {
11903
12086
  if (!dir) return [];
11904
12087
  let entries;
11905
12088
  try {
11906
- entries = fs14.readdirSync(dir, { withFileTypes: true });
12089
+ entries = fs15.readdirSync(dir, { withFileTypes: true });
11907
12090
  } catch {
11908
12091
  return [];
11909
12092
  }
@@ -11911,15 +12094,15 @@ function listResumableSessions(cwd) {
11911
12094
  for (const entry of entries) {
11912
12095
  if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
11913
12096
  const id = entry.name.slice(0, -".jsonl".length);
11914
- const filePath = path18.join(dir, entry.name);
12097
+ const filePath = path19.join(dir, entry.name);
11915
12098
  let timestamp = Date.now();
11916
12099
  try {
11917
- timestamp = fs14.statSync(filePath).mtimeMs;
12100
+ timestamp = fs15.statSync(filePath).mtimeMs;
11918
12101
  } catch {
11919
12102
  }
11920
12103
  let summary = "";
11921
12104
  try {
11922
- const raw = fs14.readFileSync(filePath, "utf8");
12105
+ const raw = fs15.readFileSync(filePath, "utf8");
11923
12106
  for (const line of raw.split("\n")) {
11924
12107
  if (!line.trim()) continue;
11925
12108
  try {
@@ -11949,8 +12132,8 @@ var ClaudeRuntimeStrategy = class {
11949
12132
  meta = getAgent("claude");
11950
12133
  mode = "interactive";
11951
12134
  os;
11952
- constructor(os44) {
11953
- this.os = os44;
12135
+ constructor(os45) {
12136
+ this.os = os45;
11954
12137
  }
11955
12138
  /**
11956
12139
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -12082,24 +12265,24 @@ var ClaudeRuntimeStrategy = class {
12082
12265
  };
12083
12266
 
12084
12267
  // src/agents/claude/deploy.ts
12085
- var fs16 = __toESM(require("fs"));
12086
- var os15 = __toESM(require("os"));
12087
- var path20 = __toESM(require("path"));
12268
+ var fs17 = __toESM(require("fs"));
12269
+ var os16 = __toESM(require("os"));
12270
+ var path21 = __toESM(require("path"));
12088
12271
 
12089
12272
  // src/agents/claude/credentials.ts
12090
12273
  var import_child_process12 = require("child_process");
12091
- var fs15 = __toESM(require("fs"));
12092
- var os14 = __toESM(require("os"));
12093
- var path19 = __toESM(require("path"));
12274
+ var fs16 = __toESM(require("fs"));
12275
+ var os15 = __toESM(require("os"));
12276
+ var path20 = __toESM(require("path"));
12094
12277
  var import_util2 = require("util");
12095
12278
  var execFileP3 = (0, import_util2.promisify)(import_child_process12.execFile);
12096
12279
  async function detectLocalClaudeCredentials() {
12097
- const localClaudeDir = path19.join(os14.homedir(), ".claude");
12098
- const flat = path19.join(localClaudeDir, ".credentials.json");
12099
- if (fs15.existsSync(flat)) {
12280
+ const localClaudeDir = path20.join(os15.homedir(), ".claude");
12281
+ const flat = path20.join(localClaudeDir, ".credentials.json");
12282
+ if (fs16.existsSync(flat)) {
12100
12283
  return { source: "flat-file", description: "~/.claude/.credentials.json" };
12101
12284
  }
12102
- if (os14.platform() === "darwin") {
12285
+ if (os15.platform() === "darwin") {
12103
12286
  try {
12104
12287
  await execFileP3(
12105
12288
  "security",
@@ -12114,9 +12297,9 @@ async function detectLocalClaudeCredentials() {
12114
12297
  return { source: "none", description: "" };
12115
12298
  }
12116
12299
  async function bridgeClaudeCredentials(provider, workspaceId) {
12117
- const localClaudeDir = path19.join(os14.homedir(), ".claude");
12118
- const fileBased = path19.join(localClaudeDir, ".credentials.json");
12119
- if (fs15.existsSync(fileBased)) {
12300
+ const localClaudeDir = path20.join(os15.homedir(), ".claude");
12301
+ const fileBased = path20.join(localClaudeDir, ".credentials.json");
12302
+ if (fs16.existsSync(fileBased)) {
12120
12303
  return { source: "flat-file", description: "~/.claude/.credentials.json" };
12121
12304
  }
12122
12305
  if (process.platform === "darwin") {
@@ -12208,8 +12391,8 @@ var ClaudeDeployStrategy = class {
12208
12391
  process.exit(1);
12209
12392
  }
12210
12393
  claudeStep.stop("\u2713 Claude CLI installed");
12211
- const localClaudeDir = path20.join(os15.homedir(), ".claude");
12212
- const haveLocalClaude = fs16.existsSync(localClaudeDir) && fs16.statSync(localClaudeDir).isDirectory();
12394
+ const localClaudeDir = path21.join(os16.homedir(), ".claude");
12395
+ const haveLocalClaude = fs17.existsSync(localClaudeDir) && fs17.statSync(localClaudeDir).isDirectory();
12213
12396
  if (haveLocalClaude) {
12214
12397
  const copyStep = fe();
12215
12398
  copyStep.start("Copying local Claude config to workspace\u2026");
@@ -12263,10 +12446,10 @@ var ClaudeDeployStrategy = class {
12263
12446
  }
12264
12447
  }
12265
12448
  if (opts.bridged !== "none") {
12266
- const localClaudeJson = path20.join(os15.homedir(), ".claude.json");
12267
- if (fs16.existsSync(localClaudeJson)) {
12449
+ const localClaudeJson = path21.join(os16.homedir(), ".claude.json");
12450
+ if (fs17.existsSync(localClaudeJson)) {
12268
12451
  try {
12269
- const contents = fs16.readFileSync(localClaudeJson);
12452
+ const contents = fs17.readFileSync(localClaudeJson);
12270
12453
  await provider.uploadFile(
12271
12454
  workspaceId,
12272
12455
  "/home/codespace/.claude.json",
@@ -12298,8 +12481,8 @@ var ClaudeDeployStrategy = class {
12298
12481
  };
12299
12482
 
12300
12483
  // src/agents/codex/runtime.ts
12301
- var import_node_child_process4 = require("child_process");
12302
- var path23 = __toESM(require("path"));
12484
+ var import_node_child_process5 = require("child_process");
12485
+ var path24 = __toESM(require("path"));
12303
12486
 
12304
12487
  // src/agents/codex/history.ts
12305
12488
  var import_node_fs3 = __toESM(require("fs"));
@@ -12556,19 +12739,19 @@ function getCurrentUsage2(historyDir) {
12556
12739
  }
12557
12740
 
12558
12741
  // src/agents/codex/link.ts
12559
- var import_node_child_process3 = require("child_process");
12742
+ var import_node_child_process4 = require("child_process");
12560
12743
 
12561
12744
  // src/agents/codex/local-token.ts
12562
- var fs18 = __toESM(require("fs"));
12563
- var os17 = __toESM(require("os"));
12564
- var path22 = __toESM(require("path"));
12745
+ var fs19 = __toESM(require("fs"));
12746
+ var os18 = __toESM(require("os"));
12747
+ var path23 = __toESM(require("path"));
12565
12748
  function codexCredentialsPath() {
12566
- return path22.join(os17.homedir(), ".codex", "auth.json");
12749
+ return path23.join(os18.homedir(), ".codex", "auth.json");
12567
12750
  }
12568
12751
  async function extractLocalCodexToken() {
12569
12752
  const file = codexCredentialsPath();
12570
- if (!fs18.existsSync(file)) return null;
12571
- const credential = fs18.readFileSync(file, "utf8").trim();
12753
+ if (!fs19.existsSync(file)) return null;
12754
+ const credential = fs19.readFileSync(file, "utf8").trim();
12572
12755
  if (credential.length === 0) return null;
12573
12756
  return { method: "oauth", credential, source: "flat-file" };
12574
12757
  }
@@ -12627,11 +12810,11 @@ function codexCredentialLocator() {
12627
12810
  function codexLoginLauncher() {
12628
12811
  return {
12629
12812
  async ensureInstalled() {
12630
- const os44 = createOsStrategy();
12631
- return os44.findInPath("codex") !== null;
12813
+ const os45 = createOsStrategy();
12814
+ return os45.findInPath("codex") !== null;
12632
12815
  },
12633
12816
  launch() {
12634
- return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
12817
+ return (0, import_node_child_process4.spawn)("codex", ["login"], { stdio: "inherit" });
12635
12818
  }
12636
12819
  };
12637
12820
  }
@@ -12651,8 +12834,8 @@ var CodexRuntimeStrategy = class {
12651
12834
  meta = getAgent("codex");
12652
12835
  mode = "interactive";
12653
12836
  os;
12654
- constructor(os44) {
12655
- this.os = os44;
12837
+ constructor(os45) {
12838
+ this.os = os45;
12656
12839
  }
12657
12840
  async prepareLaunch() {
12658
12841
  let binary = this.os.findInPath("codex");
@@ -12751,12 +12934,12 @@ var CodexRuntimeStrategy = class {
12751
12934
  });
12752
12935
  }
12753
12936
  };
12754
- function resolveNpm(os44) {
12755
- return os44.id === "win32" ? "npm.cmd" : "npm";
12937
+ function resolveNpm(os45) {
12938
+ return os45.id === "win32" ? "npm.cmd" : "npm";
12756
12939
  }
12757
- async function installCodexViaNpm(os44) {
12940
+ async function installCodexViaNpm(os45) {
12758
12941
  return new Promise((resolve7, reject) => {
12759
- const proc = (0, import_node_child_process4.spawn)(resolveNpm(os44), ["install", "-g", "@openai/codex"], {
12942
+ const proc = (0, import_node_child_process5.spawn)(resolveNpm(os45), ["install", "-g", "@openai/codex"], {
12760
12943
  stdio: "inherit"
12761
12944
  });
12762
12945
  proc.on("close", (code) => {
@@ -12773,16 +12956,16 @@ async function installCodexViaNpm(os44) {
12773
12956
  });
12774
12957
  });
12775
12958
  }
12776
- function augmentNpmGlobalBin(os44) {
12959
+ function augmentNpmGlobalBin(os45) {
12777
12960
  try {
12778
- const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os44), ["prefix", "-g"], {
12961
+ const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os45), ["prefix", "-g"], {
12779
12962
  stdio: ["ignore", "pipe", "ignore"]
12780
12963
  });
12781
12964
  if (result.status !== 0) return;
12782
12965
  const prefix = result.stdout.toString().trim();
12783
12966
  if (!prefix) return;
12784
- const binDir = os44.id === "win32" ? prefix : path23.join(prefix, "bin");
12785
- os44.augmentPath([binDir]);
12967
+ const binDir = os45.id === "win32" ? prefix : path24.join(prefix, "bin");
12968
+ os45.augmentPath([binDir]);
12786
12969
  } catch {
12787
12970
  }
12788
12971
  }
@@ -12861,14 +13044,14 @@ var CodexDeployStrategy = class {
12861
13044
  };
12862
13045
 
12863
13046
  // src/agents/coderabbit/runtime.ts
12864
- var import_node_child_process7 = require("child_process");
13047
+ var import_node_child_process8 = require("child_process");
12865
13048
 
12866
13049
  // src/agents/coderabbit/installer.ts
12867
- var import_node_child_process5 = require("child_process");
13050
+ var import_node_child_process6 = require("child_process");
12868
13051
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
12869
- async function ensureCoderabbitInstalled(os44) {
12870
- if (os44.findInPath("coderabbit")) return true;
12871
- if (os44.id === "win32") {
13052
+ async function ensureCoderabbitInstalled(os45) {
13053
+ if (os45.findInPath("coderabbit")) return true;
13054
+ if (os45.id === "win32") {
12872
13055
  console.error(
12873
13056
  "\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"
12874
13057
  );
@@ -12876,22 +13059,22 @@ async function ensureCoderabbitInstalled(os44) {
12876
13059
  }
12877
13060
  console.log("\n CodeRabbit CLI not found \u2014 installing via the official script\u2026\n");
12878
13061
  const ok = await new Promise((resolve7) => {
12879
- const proc = (0, import_node_child_process5.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL} | sh`], {
13062
+ const proc = (0, import_node_child_process6.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL} | sh`], {
12880
13063
  stdio: "inherit"
12881
13064
  });
12882
13065
  proc.on("close", (code) => resolve7(code === 0));
12883
13066
  proc.on("error", () => resolve7(false));
12884
13067
  });
12885
13068
  if (!ok) return false;
12886
- os44.augmentPath([`${os44.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
12887
- return os44.findInPath("coderabbit") !== null;
13069
+ os45.augmentPath([`${os45.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
13070
+ return os45.findInPath("coderabbit") !== null;
12888
13071
  }
12889
13072
 
12890
13073
  // src/agents/coderabbit/link.ts
12891
- var import_node_child_process6 = require("child_process");
12892
- var fs20 = __toESM(require("fs"));
12893
- var os19 = __toESM(require("os"));
12894
- var path25 = __toESM(require("path"));
13074
+ var import_node_child_process7 = require("child_process");
13075
+ var fs21 = __toESM(require("fs"));
13076
+ var os20 = __toESM(require("os"));
13077
+ var path26 = __toESM(require("path"));
12895
13078
 
12896
13079
  // src/agents/strategy.ts
12897
13080
  function validateNonEmptyCredential(token) {
@@ -12900,12 +13083,12 @@ function validateNonEmptyCredential(token) {
12900
13083
 
12901
13084
  // src/agents/coderabbit/link.ts
12902
13085
  function authPath() {
12903
- return path25.join(os19.homedir(), ".coderabbit", "auth.json");
13086
+ return path26.join(os20.homedir(), ".coderabbit", "auth.json");
12904
13087
  }
12905
13088
  async function extractLocalCoderabbitToken() {
12906
13089
  const file = authPath();
12907
- if (!fs20.existsSync(file)) return null;
12908
- const credential = fs20.readFileSync(file, "utf8").trim();
13090
+ if (!fs21.existsSync(file)) return null;
13091
+ const credential = fs21.readFileSync(file, "utf8").trim();
12909
13092
  if (credential.length === 0) return null;
12910
13093
  return { method: "oauth", credential, source: "flat-file" };
12911
13094
  }
@@ -12919,13 +13102,13 @@ function coderabbitCredentialLocator() {
12919
13102
  validate: validateNonEmptyCredential
12920
13103
  };
12921
13104
  }
12922
- function coderabbitLoginLauncher(os44) {
13105
+ function coderabbitLoginLauncher(os45) {
12923
13106
  return {
12924
13107
  async ensureInstalled() {
12925
- return ensureCoderabbitInstalled(os44);
13108
+ return ensureCoderabbitInstalled(os45);
12926
13109
  },
12927
13110
  launch() {
12928
- return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
13111
+ return (0, import_node_child_process7.spawn)("coderabbit", ["login"], { stdio: "inherit" });
12929
13112
  }
12930
13113
  };
12931
13114
  }
@@ -12945,11 +13128,11 @@ function parseReview(stdout) {
12945
13128
  for (const line of lines) {
12946
13129
  const m = line.match(HUNK_LINE_RE);
12947
13130
  if (!m) continue;
12948
- const [, path64, lineNo, sevToken, message] = m;
12949
- if (!path64 || !lineNo || !message) continue;
13131
+ const [, path65, lineNo, sevToken, message] = m;
13132
+ if (!path65 || !lineNo || !message) continue;
12950
13133
  const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
12951
13134
  hunks.push({
12952
- path: path64.trim(),
13135
+ path: path65.trim(),
12953
13136
  line: Number(lineNo),
12954
13137
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
12955
13138
  message: cleanedMessage
@@ -12968,8 +13151,8 @@ var CoderabbitRuntimeStrategy = class {
12968
13151
  meta = getAgent("coderabbit");
12969
13152
  mode = "batch";
12970
13153
  os;
12971
- constructor(os44) {
12972
- this.os = os44;
13154
+ constructor(os45) {
13155
+ this.os = os45;
12973
13156
  }
12974
13157
  getDefaultArgs() {
12975
13158
  return ["review"];
@@ -13010,7 +13193,7 @@ var CoderabbitRuntimeStrategy = class {
13010
13193
  return new Promise((resolve7, reject) => {
13011
13194
  const stdoutBuf = [];
13012
13195
  const stderrBuf = [];
13013
- const proc = (0, import_node_child_process7.spawn)(launch.cmd, launch.args, {
13196
+ const proc = (0, import_node_child_process8.spawn)(launch.cmd, launch.args, {
13014
13197
  env: { ...process.env, ...launch.env ?? {} },
13015
13198
  stdio: ["ignore", "pipe", "pipe"]
13016
13199
  });
@@ -13037,12 +13220,12 @@ var CoderabbitRuntimeStrategy = class {
13037
13220
  };
13038
13221
 
13039
13222
  // src/agents/cursor/history.ts
13040
- var fs21 = __toESM(require("fs"));
13041
- var os20 = __toESM(require("os"));
13042
- var path26 = __toESM(require("path"));
13043
- var HISTORY_ROOT = path26.join(os20.homedir(), ".cursor", "projects");
13223
+ var fs22 = __toESM(require("fs"));
13224
+ var os21 = __toESM(require("os"));
13225
+ var path27 = __toESM(require("path"));
13226
+ var HISTORY_ROOT = path27.join(os21.homedir(), ".cursor", "projects");
13044
13227
  function resolveHistoryDir3(cwd) {
13045
- if (!fs21.existsSync(HISTORY_ROOT)) return null;
13228
+ if (!fs22.existsSync(HISTORY_ROOT)) return null;
13046
13229
  void cwd;
13047
13230
  return HISTORY_ROOT;
13048
13231
  }
@@ -13054,19 +13237,19 @@ function getCurrentUsage3(_historyDir) {
13054
13237
  }
13055
13238
 
13056
13239
  // src/agents/cursor/link.ts
13057
- var import_node_child_process8 = require("child_process");
13240
+ var import_node_child_process9 = require("child_process");
13058
13241
 
13059
13242
  // src/agents/cursor/local-token.ts
13060
- var fs22 = __toESM(require("fs"));
13061
- var os21 = __toESM(require("os"));
13062
- var path27 = __toESM(require("path"));
13243
+ var fs23 = __toESM(require("fs"));
13244
+ var os22 = __toESM(require("os"));
13245
+ var path28 = __toESM(require("path"));
13063
13246
  function cursorCredentialsPath() {
13064
- return path27.join(os21.homedir(), ".cursor", "auth.json");
13247
+ return path28.join(os22.homedir(), ".cursor", "auth.json");
13065
13248
  }
13066
13249
  async function extractLocalCursorToken() {
13067
13250
  const file = cursorCredentialsPath();
13068
- if (!fs22.existsSync(file)) return null;
13069
- const credential = fs22.readFileSync(file, "utf8").trim();
13251
+ if (!fs23.existsSync(file)) return null;
13252
+ const credential = fs23.readFileSync(file, "utf8").trim();
13070
13253
  if (credential.length === 0) return null;
13071
13254
  return { method: "oauth", credential, source: "flat-file" };
13072
13255
  }
@@ -13085,17 +13268,17 @@ function cursorCredentialLocator() {
13085
13268
  validate: validateNonEmptyCredential
13086
13269
  };
13087
13270
  }
13088
- function cursorLoginLauncher(os44) {
13271
+ function cursorLoginLauncher(os45) {
13089
13272
  return {
13090
13273
  async ensureInstalled() {
13091
- if (os44.findInPath("cursor-agent")) return true;
13274
+ if (os45.findInPath("cursor-agent")) return true;
13092
13275
  console.error(
13093
13276
  "\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"
13094
13277
  );
13095
13278
  return false;
13096
13279
  },
13097
13280
  launch() {
13098
- return (0, import_node_child_process8.spawn)("cursor-agent", ["login"], { stdio: "inherit" });
13281
+ return (0, import_node_child_process9.spawn)("cursor-agent", ["login"], { stdio: "inherit" });
13099
13282
  }
13100
13283
  };
13101
13284
  }
@@ -13150,8 +13333,8 @@ var CursorRuntimeStrategy = class {
13150
13333
  meta = getAgent("cursor");
13151
13334
  mode = "interactive";
13152
13335
  os;
13153
- constructor(os44) {
13154
- this.os = os44;
13336
+ constructor(os45) {
13337
+ this.os = os45;
13155
13338
  }
13156
13339
  async prepareLaunch() {
13157
13340
  const binary = this.os.findInPath("cursor-agent");
@@ -13230,12 +13413,12 @@ var CursorRuntimeStrategy = class {
13230
13413
  };
13231
13414
 
13232
13415
  // src/agents/aider/history.ts
13233
- var fs23 = __toESM(require("fs"));
13234
- var path28 = __toESM(require("path"));
13416
+ var fs24 = __toESM(require("fs"));
13417
+ var path29 = __toESM(require("path"));
13235
13418
  var AIDER_HISTORY_FILE = ".aider.chat.history.md";
13236
13419
  function resolveHistoryDir4(cwd) {
13237
- const candidate = path28.join(cwd, AIDER_HISTORY_FILE);
13238
- return fs23.existsSync(candidate) ? cwd : null;
13420
+ const candidate = path29.join(cwd, AIDER_HISTORY_FILE);
13421
+ return fs24.existsSync(candidate) ? cwd : null;
13239
13422
  }
13240
13423
  function parseHistoryFile4(_filePath) {
13241
13424
  return [];
@@ -13245,13 +13428,13 @@ function getCurrentUsage4(_historyDir) {
13245
13428
  }
13246
13429
 
13247
13430
  // src/agents/aider/link.ts
13248
- var import_node_child_process9 = require("child_process");
13431
+ var import_node_child_process10 = require("child_process");
13249
13432
 
13250
13433
  // src/agents/aider/local-token.ts
13251
- var fs24 = __toESM(require("fs"));
13252
- var os22 = __toESM(require("os"));
13253
- var path29 = __toESM(require("path"));
13254
- var AIDER_CONF_FILE = path29.join(os22.homedir(), ".aider.conf.yml");
13434
+ var fs25 = __toESM(require("fs"));
13435
+ var os23 = __toESM(require("os"));
13436
+ var path30 = __toESM(require("path"));
13437
+ var AIDER_CONF_FILE = path30.join(os23.homedir(), ".aider.conf.yml");
13255
13438
  var API_KEY_ENV_VARS = [
13256
13439
  "ANTHROPIC_API_KEY",
13257
13440
  "OPENAI_API_KEY",
@@ -13266,8 +13449,8 @@ async function extractLocalAiderToken() {
13266
13449
  return { method: "api_key", credential: value.trim(), source: "flat-file" };
13267
13450
  }
13268
13451
  }
13269
- if (fs24.existsSync(AIDER_CONF_FILE)) {
13270
- const conf = fs24.readFileSync(AIDER_CONF_FILE, "utf8");
13452
+ if (fs25.existsSync(AIDER_CONF_FILE)) {
13453
+ const conf = fs25.readFileSync(AIDER_CONF_FILE, "utf8");
13271
13454
  const match = conf.match(/^api-key:\s*['"]?([^'"\n]+)['"]?\s*$/m);
13272
13455
  if (match) {
13273
13456
  return { method: "api_key", credential: match[1].trim(), source: "flat-file" };
@@ -13290,10 +13473,10 @@ function aiderCredentialLocator() {
13290
13473
  validate: validateNonEmptyCredential
13291
13474
  };
13292
13475
  }
13293
- function aiderLoginLauncher(os44) {
13476
+ function aiderLoginLauncher(os45) {
13294
13477
  return {
13295
13478
  async ensureInstalled() {
13296
- if (os44.findInPath("aider")) return true;
13479
+ if (os45.findInPath("aider")) return true;
13297
13480
  console.error(
13298
13481
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
13299
13482
  );
@@ -13303,7 +13486,7 @@ function aiderLoginLauncher(os44) {
13303
13486
  console.error(
13304
13487
  "\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"
13305
13488
  );
13306
- return (0, import_node_child_process9.spawn)(os44.id === "win32" ? "cmd.exe" : "sh", os44.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
13489
+ return (0, import_node_child_process10.spawn)(os45.id === "win32" ? "cmd.exe" : "sh", os45.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
13307
13490
  stdio: "ignore"
13308
13491
  });
13309
13492
  }
@@ -13375,8 +13558,8 @@ var AiderRuntimeStrategy = class {
13375
13558
  meta = getAgent("aider");
13376
13559
  mode = "interactive";
13377
13560
  os;
13378
- constructor(os44) {
13379
- this.os = os44;
13561
+ constructor(os45) {
13562
+ this.os = os45;
13380
13563
  }
13381
13564
  async prepareLaunch() {
13382
13565
  const binary = this.os.findInPath("aider");
@@ -13444,22 +13627,22 @@ var AiderRuntimeStrategy = class {
13444
13627
  };
13445
13628
 
13446
13629
  // src/agents/gemini/link.ts
13447
- var import_node_child_process10 = require("child_process");
13630
+ var import_node_child_process11 = require("child_process");
13448
13631
 
13449
13632
  // src/agents/gemini/local-token.ts
13450
- var fs25 = __toESM(require("fs"));
13451
- var os23 = __toESM(require("os"));
13452
- var path30 = __toESM(require("path"));
13633
+ var fs26 = __toESM(require("fs"));
13634
+ var os24 = __toESM(require("os"));
13635
+ var path31 = __toESM(require("path"));
13453
13636
  function geminiCredentialsPath() {
13454
- return path30.join(os23.homedir(), ".gemini", "oauth_creds.json");
13637
+ return path31.join(os24.homedir(), ".gemini", "oauth_creds.json");
13455
13638
  }
13456
13639
  function geminiCredentialsPaths() {
13457
13640
  return [geminiCredentialsPath()];
13458
13641
  }
13459
13642
  async function extractLocalGeminiToken() {
13460
13643
  const file = geminiCredentialsPath();
13461
- if (!fs25.existsSync(file)) return null;
13462
- const credential = fs25.readFileSync(file, "utf8").trim();
13644
+ if (!fs26.existsSync(file)) return null;
13645
+ const credential = fs26.readFileSync(file, "utf8").trim();
13463
13646
  if (credential.length === 0) return null;
13464
13647
  return { method: "oauth", credential, source: "flat-file" };
13465
13648
  }
@@ -13505,11 +13688,11 @@ function geminiCredentialLocator() {
13505
13688
  function geminiLoginLauncher() {
13506
13689
  return {
13507
13690
  async ensureInstalled() {
13508
- const os44 = createOsStrategy();
13509
- return os44.findInPath("gemini") !== null;
13691
+ const os45 = createOsStrategy();
13692
+ return os45.findInPath("gemini") !== null;
13510
13693
  },
13511
13694
  launch() {
13512
- return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
13695
+ return (0, import_node_child_process11.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
13513
13696
  }
13514
13697
  };
13515
13698
  }
@@ -13539,8 +13722,8 @@ var GeminiRuntimeStrategy = class {
13539
13722
  meta = getAgent("gemini");
13540
13723
  mode = "interactive";
13541
13724
  os;
13542
- constructor(os44) {
13543
- this.os = os44;
13725
+ constructor(os45) {
13726
+ this.os = os45;
13544
13727
  }
13545
13728
  async prepareLaunch() {
13546
13729
  const binary = this.os.findInPath("gemini");
@@ -13639,18 +13822,18 @@ var GeminiRuntimeStrategy = class {
13639
13822
 
13640
13823
  // src/agents/registry.ts
13641
13824
  var runtimeBuilders = {
13642
- claude: (os44) => new ClaudeRuntimeStrategy(os44),
13643
- codex: (os44) => new CodexRuntimeStrategy(os44),
13644
- coderabbit: (os44) => new CoderabbitRuntimeStrategy(os44),
13645
- cursor: (os44) => new CursorRuntimeStrategy(os44),
13646
- aider: (os44) => new AiderRuntimeStrategy(os44),
13647
- gemini: (os44) => new GeminiRuntimeStrategy(os44)
13825
+ claude: (os45) => new ClaudeRuntimeStrategy(os45),
13826
+ codex: (os45) => new CodexRuntimeStrategy(os45),
13827
+ coderabbit: (os45) => new CoderabbitRuntimeStrategy(os45),
13828
+ cursor: (os45) => new CursorRuntimeStrategy(os45),
13829
+ aider: (os45) => new AiderRuntimeStrategy(os45),
13830
+ gemini: (os45) => new GeminiRuntimeStrategy(os45)
13648
13831
  };
13649
13832
  var deployBuilders = {
13650
13833
  claude: () => new ClaudeDeployStrategy(),
13651
13834
  codex: () => new CodexDeployStrategy()
13652
13835
  };
13653
- function createAgentStrategy(agent, os44 = createOsStrategy()) {
13836
+ function createAgentStrategy(agent, os45 = createOsStrategy()) {
13654
13837
  if (!AGENT_REGISTRY[agent]?.enabled) {
13655
13838
  throw new Error(
13656
13839
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -13660,10 +13843,10 @@ function createAgentStrategy(agent, os44 = createOsStrategy()) {
13660
13843
  if (!build) {
13661
13844
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
13662
13845
  }
13663
- return build(os44);
13846
+ return build(os45);
13664
13847
  }
13665
- function createInteractiveAgentStrategy(agent, os44 = createOsStrategy()) {
13666
- const s = createAgentStrategy(agent, os44);
13848
+ function createInteractiveAgentStrategy(agent, os45 = createOsStrategy()) {
13849
+ const s = createAgentStrategy(agent, os45);
13667
13850
  if (s.mode !== "interactive") {
13668
13851
  throw new Error(
13669
13852
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -13719,7 +13902,7 @@ function parseLinkArgs(args2) {
13719
13902
  if (apiKeyFileArg) {
13720
13903
  const filePath = apiKeyFileArg.slice("--api-key-file=".length);
13721
13904
  try {
13722
- apiKey = fs26.readFileSync(path31.resolve(filePath), "utf8").trim();
13905
+ apiKey = fs27.readFileSync(path32.resolve(filePath), "utf8").trim();
13723
13906
  } catch (err) {
13724
13907
  throw new Error(`Could not read --api-key-file ${filePath}: ${err.message}`);
13725
13908
  }
@@ -13846,7 +14029,7 @@ async function link(args2 = []) {
13846
14029
  return;
13847
14030
  }
13848
14031
  if (parsed.tokenFile) {
13849
- const credential = fs26.readFileSync(path31.resolve(parsed.tokenFile), "utf8").trim();
14032
+ const credential = fs27.readFileSync(path32.resolve(parsed.tokenFile), "utf8").trim();
13850
14033
  if (!credential) {
13851
14034
  showError(`--token-file ${parsed.tokenFile} is empty.`);
13852
14035
  process.exit(1);
@@ -14066,15 +14249,15 @@ async function linkDryRunPreflight(ctx) {
14066
14249
  }
14067
14250
 
14068
14251
  // src/commands/host-agent.ts
14069
- var import_node_child_process15 = require("child_process");
14070
- var os30 = __toESM(require("os"));
14071
- var fs33 = __toESM(require("fs"));
14072
- var path37 = __toESM(require("path"));
14252
+ var import_node_child_process16 = require("child_process");
14253
+ var os31 = __toESM(require("os"));
14254
+ var fs34 = __toESM(require("fs"));
14255
+ var path38 = __toESM(require("path"));
14073
14256
 
14074
14257
  // src/util/restrict-to-owner.ts
14075
14258
  var import_node_fs5 = __toESM(require("fs"));
14076
14259
  var import_node_os3 = __toESM(require("os"));
14077
- var import_node_child_process11 = require("child_process");
14260
+ var import_node_child_process12 = require("child_process");
14078
14261
  var BROAD_WINDOWS_SIDS = [
14079
14262
  "*S-1-1-0",
14080
14263
  "*S-1-5-11",
@@ -14086,7 +14269,7 @@ function restrictToOwner(filePath) {
14086
14269
  try {
14087
14270
  if (process.platform === "win32") {
14088
14271
  const username = import_node_os3.default.userInfo().username;
14089
- (0, import_node_child_process11.execFileSync)(
14272
+ (0, import_node_child_process12.execFileSync)(
14090
14273
  "icacls",
14091
14274
  [
14092
14275
  filePath,
@@ -14105,13 +14288,13 @@ function restrictToOwner(filePath) {
14105
14288
  }
14106
14289
 
14107
14290
  // src/commands/host/host-client.ts
14108
- var fs28 = __toESM(require("fs"));
14109
- var os25 = __toESM(require("os"));
14110
- var path32 = __toESM(require("path"));
14291
+ var fs29 = __toESM(require("fs"));
14292
+ var os26 = __toESM(require("os"));
14293
+ var path33 = __toESM(require("path"));
14111
14294
  function sampleCpuTimes() {
14112
14295
  let idle = 0;
14113
14296
  let total = 0;
14114
- for (const cpu of os25.cpus()) {
14297
+ for (const cpu of os26.cpus()) {
14115
14298
  const t2 = cpu.times;
14116
14299
  idle += t2.idle;
14117
14300
  total += t2.user + t2.nice + t2.sys + t2.idle + t2.irq;
@@ -14130,8 +14313,8 @@ var MetricsCollector = class {
14130
14313
  const prev = this.prevCpu;
14131
14314
  this.prevCpu = current;
14132
14315
  if (!prev) {
14133
- const cores = os25.cpus().length || 1;
14134
- const proxy = os25.loadavg()[0] / cores * 100;
14316
+ const cores = os26.cpus().length || 1;
14317
+ const proxy = os26.loadavg()[0] / cores * 100;
14135
14318
  return Math.min(100, Math.max(0, Math.round(proxy)));
14136
14319
  }
14137
14320
  const idleDelta = current.idle - prev.idle;
@@ -14144,8 +14327,8 @@ var MetricsCollector = class {
14144
14327
  collect() {
14145
14328
  return {
14146
14329
  cpuPct: this.cpuPct(),
14147
- ramUsedMb: Math.round((os25.totalmem() - os25.freemem()) / 1048576),
14148
- ramTotalMb: Math.round(os25.totalmem() / 1048576),
14330
+ ramUsedMb: Math.round((os26.totalmem() - os26.freemem()) / 1048576),
14331
+ ramTotalMb: Math.round(os26.totalmem() / 1048576),
14149
14332
  latencyMs: this.lastLatencyMs
14150
14333
  };
14151
14334
  }
@@ -14154,19 +14337,19 @@ function apiBase() {
14154
14337
  return process.env.CODEAM_API_URL ?? resolveApiBaseUrl();
14155
14338
  }
14156
14339
  function hostIdentityPath() {
14157
- return path32.join(os25.homedir(), ".codeam", "host-agent.json");
14340
+ return path33.join(os26.homedir(), ".codeam", "host-agent.json");
14158
14341
  }
14159
14342
  function collectOsInfo() {
14160
14343
  return {
14161
- distro: os25.platform(),
14162
- arch: os25.arch(),
14163
- kernel: os25.release(),
14344
+ distro: os26.platform(),
14345
+ arch: os26.arch(),
14346
+ kernel: os26.release(),
14164
14347
  nodeVersion: process.versions.node
14165
14348
  };
14166
14349
  }
14167
14350
  function loadHostIdentity() {
14168
14351
  try {
14169
- const raw = fs28.readFileSync(hostIdentityPath(), "utf8");
14352
+ const raw = fs29.readFileSync(hostIdentityPath(), "utf8");
14170
14353
  const parsed = JSON.parse(raw);
14171
14354
  if (typeof parsed === "object" && parsed !== null && typeof parsed.hostId === "string" && typeof parsed.hostToken === "string" && typeof parsed.controlPluginId === "string") {
14172
14355
  const p2 = parsed;
@@ -14179,8 +14362,8 @@ function loadHostIdentity() {
14179
14362
  }
14180
14363
  function saveHostIdentity(identity) {
14181
14364
  const file = hostIdentityPath();
14182
- fs28.mkdirSync(path32.dirname(file), { recursive: true, mode: 448 });
14183
- fs28.writeFileSync(file, JSON.stringify(identity, null, 2), {
14365
+ fs29.mkdirSync(path33.dirname(file), { recursive: true, mode: 448 });
14366
+ fs29.writeFileSync(file, JSON.stringify(identity, null, 2), {
14184
14367
  encoding: "utf8",
14185
14368
  mode: 384
14186
14369
  });
@@ -14225,7 +14408,7 @@ function isTerminalEnrollError(err) {
14225
14408
  }
14226
14409
  function deleteHostIdentity() {
14227
14410
  try {
14228
- fs28.rmSync(hostIdentityPath(), { force: true });
14411
+ fs29.rmSync(hostIdentityPath(), { force: true });
14229
14412
  } catch {
14230
14413
  }
14231
14414
  }
@@ -14348,17 +14531,17 @@ async function reportDeployProgress(auth, deployId, step, message, sessionId) {
14348
14531
  }
14349
14532
 
14350
14533
  // src/commands/host/workspace.ts
14351
- var fs29 = __toESM(require("fs"));
14352
- var os26 = __toESM(require("os"));
14353
- var path33 = __toESM(require("path"));
14354
- var import_node_child_process12 = require("child_process");
14534
+ var fs30 = __toESM(require("fs"));
14535
+ var os27 = __toESM(require("os"));
14536
+ var path34 = __toESM(require("path"));
14537
+ var import_node_child_process13 = require("child_process");
14355
14538
  var import_node_util4 = require("util");
14356
- var execFileP4 = (0, import_node_util4.promisify)(import_node_child_process12.execFile);
14539
+ var execFileP4 = (0, import_node_util4.promisify)(import_node_child_process13.execFile);
14357
14540
  function isAbsolutePathTarget(target) {
14358
- return path33.isAbsolute(target);
14541
+ return path34.isAbsolute(target);
14359
14542
  }
14360
14543
  function selfHostedWorkspaceRoot() {
14361
- return path33.join(os26.homedir(), ".codeam", "self-hosted");
14544
+ return path34.join(os27.homedir(), ".codeam", "self-hosted");
14362
14545
  }
14363
14546
  function nonInteractiveGitEnv() {
14364
14547
  return {
@@ -14411,13 +14594,13 @@ async function fetchGithubIdentity(token) {
14411
14594
  async function configureGitCredentials(dest, repoRef, cloneToken) {
14412
14595
  const gh = githubOwnerRepo(repoRef.trim());
14413
14596
  if (!gh || !cloneToken) return;
14414
- const credFile = path33.join(dest, ".git", "codeam-credentials");
14415
- fs29.writeFileSync(credFile, `https://x-access-token:${cloneToken}@github.com
14597
+ const credFile = path34.join(dest, ".git", "codeam-credentials");
14598
+ fs30.writeFileSync(credFile, `https://x-access-token:${cloneToken}@github.com
14416
14599
  `, { mode: 384 });
14417
14600
  restrictToOwner(credFile);
14418
14601
  const env = nonInteractiveGitEnv();
14419
14602
  const git2 = (args2) => execFileP4("git", ["-C", dest, ...args2], { timeout: 3e4, env });
14420
- const credFilePosix = credFile.split(path33.sep).join("/");
14603
+ const credFilePosix = credFile.split(path34.sep).join("/");
14421
14604
  await git2(["config", "--local", "--replace-all", "credential.helper", ""]).catch(() => {
14422
14605
  });
14423
14606
  await git2([
@@ -14453,17 +14636,17 @@ function maskToken(text, cloneToken) {
14453
14636
  }
14454
14637
  async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
14455
14638
  if (isAbsolutePathTarget(repoOrPath)) {
14456
- if (!fs29.existsSync(repoOrPath)) {
14639
+ if (!fs30.existsSync(repoOrPath)) {
14457
14640
  throw new Error(`deploy target path does not exist: ${repoOrPath}`);
14458
14641
  }
14459
14642
  return repoOrPath;
14460
14643
  }
14461
- const dest = path33.join(selfHostedWorkspaceRoot(), deployId);
14462
- if (fs29.existsSync(path33.join(dest, ".git"))) {
14644
+ const dest = path34.join(selfHostedWorkspaceRoot(), deployId);
14645
+ if (fs30.existsSync(path34.join(dest, ".git"))) {
14463
14646
  if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken);
14464
14647
  return dest;
14465
14648
  }
14466
- fs29.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
14649
+ fs30.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
14467
14650
  const cloneUrl = repoCloneUrl(repoOrPath, cloneToken);
14468
14651
  try {
14469
14652
  await execFileP4("git", ["clone", "--depth", "1", cloneUrl, dest], {
@@ -14480,9 +14663,9 @@ async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
14480
14663
  }
14481
14664
 
14482
14665
  // src/commands/host/agent-provisioning.ts
14483
- var fs30 = __toESM(require("fs"));
14484
- var os27 = __toESM(require("os"));
14485
- var path34 = __toESM(require("path"));
14666
+ var fs31 = __toESM(require("fs"));
14667
+ var os28 = __toESM(require("os"));
14668
+ var path35 = __toESM(require("path"));
14486
14669
  var PUBLIC_TO_INTERNAL_AGENT = {
14487
14670
  claude_code: "claude",
14488
14671
  claude: "claude",
@@ -14497,22 +14680,22 @@ function toInternalAgentId(publicAgentId) {
14497
14680
  return PUBLIC_TO_INTERNAL_AGENT[publicAgentId] ?? null;
14498
14681
  }
14499
14682
  function ensureDir(dir) {
14500
- fs30.mkdirSync(dir, { recursive: true, mode: 448 });
14683
+ fs31.mkdirSync(dir, { recursive: true, mode: 448 });
14501
14684
  }
14502
14685
  function writeFile0600(filePath, contents) {
14503
- ensureDir(path34.dirname(filePath));
14504
- fs30.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
14686
+ ensureDir(path35.dirname(filePath));
14687
+ fs31.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
14505
14688
  restrictToOwner(filePath);
14506
14689
  }
14507
14690
  function rmIfExists(filePath) {
14508
14691
  try {
14509
- fs30.rmSync(filePath, { force: true });
14692
+ fs31.rmSync(filePath, { force: true });
14510
14693
  } catch {
14511
14694
  }
14512
14695
  }
14513
14696
  var claudeProvisioner = {
14514
14697
  write(auth, home) {
14515
- const credentialsJson = path34.join(home, ".claude", ".credentials.json");
14698
+ const credentialsJson = path35.join(home, ".claude", ".credentials.json");
14516
14699
  if (auth.kind === "api_key") {
14517
14700
  rmIfExists(credentialsJson);
14518
14701
  return { ANTHROPIC_API_KEY: auth.value };
@@ -14524,8 +14707,8 @@ var claudeProvisioner = {
14524
14707
  } else {
14525
14708
  rmIfExists(credentialsJson);
14526
14709
  }
14527
- const claudeJson = path34.join(home, ".claude.json");
14528
- if (!fs30.existsSync(claudeJson)) {
14710
+ const claudeJson = path35.join(home, ".claude.json");
14711
+ if (!fs31.existsSync(claudeJson)) {
14529
14712
  writeFile0600(
14530
14713
  claudeJson,
14531
14714
  JSON.stringify({ hasCompletedOnboarding: true, customApiKeyResponses: { approved: [] } })
@@ -14536,7 +14719,7 @@ var claudeProvisioner = {
14536
14719
  };
14537
14720
  var codexProvisioner = {
14538
14721
  write(auth, home) {
14539
- const authJson = path34.join(home, ".codex", "auth.json");
14722
+ const authJson = path35.join(home, ".codex", "auth.json");
14540
14723
  if (auth.kind === "api_key") {
14541
14724
  rmIfExists(authJson);
14542
14725
  return { OPENAI_API_KEY: auth.value };
@@ -14547,8 +14730,8 @@ var codexProvisioner = {
14547
14730
  };
14548
14731
  var geminiProvisioner = {
14549
14732
  write(auth, home) {
14550
- const settingsJson = path34.join(home, ".gemini", "settings.json");
14551
- const oauthCreds = path34.join(home, ".gemini", "oauth_creds.json");
14733
+ const settingsJson = path35.join(home, ".gemini", "settings.json");
14734
+ const oauthCreds = path35.join(home, ".gemini", "oauth_creds.json");
14552
14735
  if (auth.kind === "api_key") {
14553
14736
  rmIfExists(oauthCreds);
14554
14737
  writeFile0600(settingsJson, '{"security":{"auth":{"selectedType":"gemini-api-key"}}}');
@@ -14561,7 +14744,7 @@ var geminiProvisioner = {
14561
14744
  };
14562
14745
  var cursorProvisioner = {
14563
14746
  write(auth, home) {
14564
- const authJson = path34.join(home, ".config", "cursor", "auth.json");
14747
+ const authJson = path35.join(home, ".config", "cursor", "auth.json");
14565
14748
  if (auth.kind === "api_key") {
14566
14749
  rmIfExists(authJson);
14567
14750
  return { CURSOR_API_KEY: auth.value };
@@ -14598,7 +14781,7 @@ var UnsupportedAgentError = class extends Error {
14598
14781
  this.agentId = agentId;
14599
14782
  }
14600
14783
  };
14601
- function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os27.homedir()) {
14784
+ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os28.homedir()) {
14602
14785
  const internal = toInternalAgentId(publicAgentId);
14603
14786
  if (!internal) throw new UnsupportedAgentError(publicAgentId);
14604
14787
  const provisioner = PROVISIONERS[internal];
@@ -14607,12 +14790,12 @@ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os27.homedir(
14607
14790
  }
14608
14791
 
14609
14792
  // src/commands/host/git-tooling.ts
14610
- var import_node_child_process13 = require("child_process");
14611
- var fs31 = __toESM(require("fs"));
14612
- var os28 = __toESM(require("os"));
14613
- var path35 = __toESM(require("path"));
14793
+ var import_node_child_process14 = require("child_process");
14794
+ var fs32 = __toESM(require("fs"));
14795
+ var os29 = __toESM(require("os"));
14796
+ var path36 = __toESM(require("path"));
14614
14797
  function codeamBinDir() {
14615
- return process.env.CODEAM_BIN_DIR ?? path35.join(os28.homedir(), ".codeam", "bin");
14798
+ return process.env.CODEAM_BIN_DIR ?? path36.join(os29.homedir(), ".codeam", "bin");
14616
14799
  }
14617
14800
  var FALLBACK_GH_VERSION = "2.62.0";
14618
14801
  var RELEASE_API = "https://api.github.com/repos/cli/cli/releases/latest";
@@ -14644,7 +14827,7 @@ async function download(url, dest) {
14644
14827
  const res = await fetch(url, { headers: { "User-Agent": "codeam-cli" } });
14645
14828
  if (!res.ok || !res.body) return false;
14646
14829
  const buf = Buffer.from(await res.arrayBuffer());
14647
- fs31.writeFileSync(dest, buf);
14830
+ fs32.writeFileSync(dest, buf);
14648
14831
  return true;
14649
14832
  } catch {
14650
14833
  return false;
@@ -14667,8 +14850,8 @@ async function ensureGhCli(runner, token, deps = {}) {
14667
14850
  const version3 = await resolveVersionFn(token);
14668
14851
  const asset = `gh_${version3}_${osToken}_${arch2}`;
14669
14852
  const url = `https://github.com/cli/cli/releases/download/v${version3}/${asset}.${ext}`;
14670
- const tmpRoot = fs31.mkdtempSync(path35.join(os28.tmpdir(), "codeam-gh-"));
14671
- const archive = path35.join(tmpRoot, `${asset}.${ext}`);
14853
+ const tmpRoot = fs32.mkdtempSync(path36.join(os29.tmpdir(), "codeam-gh-"));
14854
+ const archive = path36.join(tmpRoot, `${asset}.${ext}`);
14672
14855
  if (!await downloadFn(url, archive)) {
14673
14856
  log.warn("host-agent", "gh download failed \u2014 skipping (git pull/push still work via the credential helper)");
14674
14857
  return null;
@@ -14678,16 +14861,16 @@ async function ensureGhCli(runner, token, deps = {}) {
14678
14861
  log.warn("host-agent", `gh archive extraction failed (code=${String(extract.code)}) \u2014 skipping`);
14679
14862
  return null;
14680
14863
  }
14681
- const extractedBin = path35.join(tmpRoot, asset, "bin", binaryName);
14682
- if (!fs31.existsSync(extractedBin)) {
14864
+ const extractedBin = path36.join(tmpRoot, asset, "bin", binaryName);
14865
+ if (!fs32.existsSync(extractedBin)) {
14683
14866
  log.warn("host-agent", "gh binary not found in the extracted archive \u2014 skipping");
14684
14867
  return null;
14685
14868
  }
14686
14869
  const binDir = codeamBinDir();
14687
- fs31.mkdirSync(binDir, { recursive: true });
14688
- const target = path35.join(binDir, binaryName);
14689
- fs31.copyFileSync(extractedBin, target);
14690
- fs31.chmodSync(target, 493);
14870
+ fs32.mkdirSync(binDir, { recursive: true });
14871
+ const target = path36.join(binDir, binaryName);
14872
+ fs32.copyFileSync(extractedBin, target);
14873
+ fs32.chmodSync(target, 493);
14691
14874
  log.info("host-agent", `gh installed to ${target} (v${version3})`);
14692
14875
  return target;
14693
14876
  } catch (e) {
@@ -14721,7 +14904,7 @@ var defaultGitToolingRunner = {
14721
14904
  which(cmd) {
14722
14905
  try {
14723
14906
  const probe = process.platform === "win32" ? "where" : "which";
14724
- (0, import_node_child_process13.execFileSync)(probe, [cmd], { stdio: "ignore" });
14907
+ (0, import_node_child_process14.execFileSync)(probe, [cmd], { stdio: "ignore" });
14725
14908
  return true;
14726
14909
  } catch {
14727
14910
  return false;
@@ -14729,7 +14912,7 @@ var defaultGitToolingRunner = {
14729
14912
  },
14730
14913
  run(cmd, args2, opts = {}) {
14731
14914
  return new Promise((resolve7) => {
14732
- const child = (0, import_node_child_process13.spawn)(cmd, args2, {
14915
+ const child = (0, import_node_child_process14.spawn)(cmd, args2, {
14733
14916
  stdio: [opts.input !== void 0 ? "pipe" : "ignore", "ignore", "pipe"]
14734
14917
  });
14735
14918
  let stderr = "";
@@ -14769,6 +14952,16 @@ var defaultGitToolingRunner = {
14769
14952
 
14770
14953
  // src/services/headroom/stats-reporter.ts
14771
14954
  var DEFAULT_INPUT_PRICE_PER_MILLION = 3;
14955
+ var HEADROOM_FETCH_TIMEOUT_MS = 1e4;
14956
+ async function fetchWithTimeout(url, init, timeoutMs = HEADROOM_FETCH_TIMEOUT_MS) {
14957
+ const controller = new AbortController();
14958
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
14959
+ try {
14960
+ return await fetch(url, { ...init, signal: controller.signal });
14961
+ } finally {
14962
+ clearTimeout(timer);
14963
+ }
14964
+ }
14772
14965
  var ZERO = {
14773
14966
  rawTokensEst: 0,
14774
14967
  sentTokensEst: 0,
@@ -14831,6 +15024,9 @@ var HeadroomStatsReporter = class {
14831
15024
  deps;
14832
15025
  timer = null;
14833
15026
  prev = ZERO;
15027
+ /** Period spend observed on the previous budgeted post — lets `budgetReached`
15028
+ * fire once per crossing instead of on every post while over the cap. */
15029
+ prevPeriodSpendUsd = null;
14834
15030
  start() {
14835
15031
  const ms = this.deps.intervalMs ?? (Number(process.env.HEADROOM_STATS_POLL_INTERVAL_MS ?? "30000") || 3e4);
14836
15032
  this.timer = setInterval(() => void this.tick(), ms);
@@ -14847,11 +15043,18 @@ var HeadroomStatsReporter = class {
14847
15043
  if (delta.compressionTokens > 0 || delta.compressionSavingsUsd > 0 || delta.rawTokensEst > 0 || delta.cacheReadTokens > 0 || delta.cacheSavingsUsd > 0) {
14848
15044
  const getBudgetEnv = this.deps.getBudgetEnv ?? defaultGetBudgetEnv;
14849
15045
  const budgetEnv = getBudgetEnv();
14850
- const budget = budgetEnv ? {
14851
- periodSpendUsd: stats.cost?.cost_with_headroom_usd ?? 0,
14852
- budgetUsd: budgetEnv.budgetUsd,
14853
- budgetPeriod: budgetEnv.budgetPeriod
14854
- } : void 0;
15046
+ let budget;
15047
+ if (budgetEnv) {
15048
+ const periodSpendUsd = stats.cost?.cost_with_headroom_usd ?? 0;
15049
+ const crossed = periodSpendUsd >= budgetEnv.budgetUsd && (this.prevPeriodSpendUsd === null || this.prevPeriodSpendUsd < budgetEnv.budgetUsd);
15050
+ this.prevPeriodSpendUsd = periodSpendUsd;
15051
+ budget = {
15052
+ periodSpendUsd,
15053
+ budgetUsd: budgetEnv.budgetUsd,
15054
+ budgetPeriod: budgetEnv.budgetPeriod,
15055
+ ...crossed ? { budgetReached: true } : {}
15056
+ };
15057
+ }
14855
15058
  await this.deps.postSavings(delta, budget);
14856
15059
  }
14857
15060
  } catch {
@@ -14866,23 +15069,23 @@ var HeadroomStatsReporter = class {
14866
15069
  };
14867
15070
 
14868
15071
  // src/lib/updateNotifier.ts
14869
- var fs32 = __toESM(require("fs"));
14870
- var os29 = __toESM(require("os"));
14871
- var path36 = __toESM(require("path"));
15072
+ var fs33 = __toESM(require("fs"));
15073
+ var os30 = __toESM(require("os"));
15074
+ var path37 = __toESM(require("path"));
14872
15075
  var https6 = __toESM(require("https"));
14873
- var import_node_child_process14 = require("child_process");
15076
+ var import_node_child_process15 = require("child_process");
14874
15077
  var import_picocolors3 = __toESM(require("picocolors"));
14875
15078
  var PKG_NAME = "codeam-cli";
14876
15079
  var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
14877
15080
  var TTL_MS = 24 * 60 * 60 * 1e3;
14878
15081
  var REQUEST_TIMEOUT_MS = 1500;
14879
15082
  function cachePath() {
14880
- const dir = path36.join(os29.homedir(), ".codeam");
14881
- return path36.join(dir, "update-check.json");
15083
+ const dir = path37.join(os30.homedir(), ".codeam");
15084
+ return path37.join(dir, "update-check.json");
14882
15085
  }
14883
15086
  function readCache() {
14884
15087
  try {
14885
- const raw = fs32.readFileSync(cachePath(), "utf8");
15088
+ const raw = fs33.readFileSync(cachePath(), "utf8");
14886
15089
  const parsed = JSON.parse(raw);
14887
15090
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
14888
15091
  return parsed;
@@ -14893,10 +15096,10 @@ function readCache() {
14893
15096
  function writeCache(cache) {
14894
15097
  try {
14895
15098
  const file = cachePath();
14896
- fs32.mkdirSync(path36.dirname(file), { recursive: true });
15099
+ fs33.mkdirSync(path37.dirname(file), { recursive: true });
14897
15100
  const tmp = `${file}.${process.pid}.tmp`;
14898
- fs32.writeFileSync(tmp, JSON.stringify(cache));
14899
- fs32.renameSync(tmp, file);
15101
+ fs33.writeFileSync(tmp, JSON.stringify(cache));
15102
+ fs33.renameSync(tmp, file);
14900
15103
  } catch {
14901
15104
  }
14902
15105
  }
@@ -14964,14 +15167,14 @@ function notifyIfStale(currentVersion, latest) {
14964
15167
  }
14965
15168
  function isLinkedInstall() {
14966
15169
  try {
14967
- const root = (0, import_node_child_process14.execSync)("npm root -g", {
15170
+ const root = (0, import_node_child_process15.execSync)("npm root -g", {
14968
15171
  encoding: "utf8",
14969
15172
  stdio: ["ignore", "pipe", "ignore"],
14970
15173
  timeout: 2e3
14971
15174
  }).trim();
14972
15175
  if (!root) return false;
14973
- const pkgPath = path36.join(root, PKG_NAME);
14974
- return fs32.lstatSync(pkgPath).isSymbolicLink();
15176
+ const pkgPath = path37.join(root, PKG_NAME);
15177
+ return fs33.lstatSync(pkgPath).isSymbolicLink();
14975
15178
  } catch {
14976
15179
  return false;
14977
15180
  }
@@ -14992,7 +15195,7 @@ function maybeAutoUpdate(currentVersion, latest) {
14992
15195
 
14993
15196
  `
14994
15197
  );
14995
- const install = (0, import_node_child_process14.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
15198
+ const install = (0, import_node_child_process15.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
14996
15199
  stdio: "inherit",
14997
15200
  env: process.env
14998
15201
  });
@@ -15007,13 +15210,13 @@ function maybeAutoUpdate(currentVersion, latest) {
15007
15210
  return;
15008
15211
  }
15009
15212
  try {
15010
- fs32.unlinkSync(cachePath());
15213
+ fs33.unlinkSync(cachePath());
15011
15214
  } catch {
15012
15215
  }
15013
15216
  process.stderr.write(` ${import_picocolors3.default.green("\u2713")} Updated. Resuming session...
15014
15217
 
15015
15218
  `);
15016
- const child = (0, import_node_child_process14.spawnSync)("codeam", process.argv.slice(2), {
15219
+ const child = (0, import_node_child_process15.spawnSync)("codeam", process.argv.slice(2), {
15017
15220
  stdio: "inherit",
15018
15221
  env: process.env
15019
15222
  });
@@ -15023,7 +15226,7 @@ async function autoUpgradeBeforeCriticalCommand() {
15023
15226
  if (process.env.NODE_ENV === "test") return;
15024
15227
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
15025
15228
  if (process.env.CI) return;
15026
- const current = true ? "2.53.2" : null;
15229
+ const current = true ? "2.53.4" : null;
15027
15230
  if (!current) return;
15028
15231
  const cache = readCache();
15029
15232
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -15040,7 +15243,7 @@ function checkForUpdates() {
15040
15243
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
15041
15244
  if (process.env.CI) return;
15042
15245
  if (!process.stdout.isTTY) return;
15043
- const current = true ? "2.53.2" : null;
15246
+ const current = true ? "2.53.4" : null;
15044
15247
  if (!current) return;
15045
15248
  const cache = readCache();
15046
15249
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -15074,11 +15277,11 @@ function maybeStartHeadroomReporter(ctx) {
15074
15277
  process.env["HEADROOM_AGENT"] ?? "claude"
15075
15278
  ),
15076
15279
  fetchStats: async () => {
15077
- const res = await fetch("http://localhost:8787/stats");
15280
+ const res = await fetchWithTimeout("http://localhost:8787/stats");
15078
15281
  return res.json();
15079
15282
  },
15080
15283
  postSavings: async (delta, budget) => {
15081
- await fetch(ingestUrl, {
15284
+ const res = await fetchWithTimeout(ingestUrl, {
15082
15285
  method: "POST",
15083
15286
  headers: {
15084
15287
  "Content-Type": "application/json",
@@ -15092,10 +15295,14 @@ function maybeStartHeadroomReporter(ctx) {
15092
15295
  ...budget ? {
15093
15296
  periodSpendUsd: budget.periodSpendUsd,
15094
15297
  budgetUsd: budget.budgetUsd,
15095
- budgetPeriod: budget.budgetPeriod
15298
+ budgetPeriod: budget.budgetPeriod,
15299
+ budgetReached: budget.budgetReached
15096
15300
  } : {}
15097
15301
  })
15098
15302
  });
15303
+ if (!res.ok) {
15304
+ log.warn("headroom", `savings POST rejected ${res.status} \u2014 delta not credited`);
15305
+ }
15099
15306
  }
15100
15307
  });
15101
15308
  reporter.start();
@@ -15112,22 +15319,22 @@ function maybeResumeLocalHeadroomReporter(ctx) {
15112
15319
  if (process.env["HEADROOM_ENABLED"] === "1") return null;
15113
15320
  try {
15114
15321
  const file = headroomConfigPath();
15115
- if (!fs33.existsSync(file)) return null;
15116
- const cfg = JSON.parse(fs33.readFileSync(file, "utf8"));
15322
+ if (!fs34.existsSync(file)) return null;
15323
+ const cfg = JSON.parse(fs34.readFileSync(file, "utf8"));
15117
15324
  if (!cfg?.enabled) return null;
15118
15325
  const agent = cfg.agent ?? "claude";
15119
15326
  const ingestUrl = `${resolveApiBaseUrl()}/api/sessions/${ctx.sessionId}/headroom-savings`;
15120
15327
  const reporter = new HeadroomStatsReporter({
15121
15328
  inputPricePerMillionUsd: resolveInputPricePerMillion(agent),
15122
15329
  fetchStats: async () => {
15123
- const res = await fetch("http://localhost:8787/stats");
15330
+ const res = await fetchWithTimeout("http://localhost:8787/stats");
15124
15331
  return res.json();
15125
15332
  },
15126
15333
  // Body MUST match HeadroomSavingsDto + PluginAuthGuard (sessionId +
15127
15334
  // pluginId in the body) — same shape as the codespace reporter above and
15128
15335
  // the on-demand `startReporter` in handlers.ts.
15129
15336
  postSavings: async (delta, budget) => {
15130
- await fetch(ingestUrl, {
15337
+ const res = await fetchWithTimeout(ingestUrl, {
15131
15338
  method: "POST",
15132
15339
  headers: {
15133
15340
  "Content-Type": "application/json",
@@ -15141,10 +15348,14 @@ function maybeResumeLocalHeadroomReporter(ctx) {
15141
15348
  ...budget ? {
15142
15349
  periodSpendUsd: budget.periodSpendUsd,
15143
15350
  budgetUsd: budget.budgetUsd,
15144
- budgetPeriod: budget.budgetPeriod
15351
+ budgetPeriod: budget.budgetPeriod,
15352
+ budgetReached: budget.budgetReached
15145
15353
  } : {}
15146
15354
  })
15147
15355
  });
15356
+ if (!res.ok) {
15357
+ log.warn("headroom", `savings POST rejected ${res.status} \u2014 delta not credited`);
15358
+ }
15148
15359
  }
15149
15360
  });
15150
15361
  reporter.start();
@@ -15204,7 +15415,7 @@ var HEADROOM_MIN_FREE_DISK_BYTES = 2 * 1024 * 1024 * 1024;
15204
15415
  var defaultHeadroomRunner = {
15205
15416
  which(cmd) {
15206
15417
  try {
15207
- (0, import_node_child_process15.execFileSync)("which", [cmd], { stdio: "ignore" });
15418
+ (0, import_node_child_process16.execFileSync)("which", [cmd], { stdio: "ignore" });
15208
15419
  return true;
15209
15420
  } catch {
15210
15421
  return false;
@@ -15213,7 +15424,7 @@ var defaultHeadroomRunner = {
15213
15424
  run(cmd, args2, opts = {}) {
15214
15425
  return new Promise((resolve7) => {
15215
15426
  const spawnEnv = opts.env ?? process.env;
15216
- const child = (0, import_node_child_process15.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"], env: spawnEnv });
15427
+ const child = (0, import_node_child_process16.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"], env: spawnEnv });
15217
15428
  let stderrBuf = "";
15218
15429
  let stdoutBuf = "";
15219
15430
  let settled = false;
@@ -15377,15 +15588,15 @@ function isHeadroomSupportedAgent(agentId) {
15377
15588
  return n.startsWith("claude") || n.startsWith("codex") || n.startsWith("copilot");
15378
15589
  }
15379
15590
  function headroomConfigPath() {
15380
- return path37.join(os30.homedir(), ".codeam", "headroom-config.json");
15591
+ return path38.join(os31.homedir(), ".codeam", "headroom-config.json");
15381
15592
  }
15382
15593
  function persistHeadroomConfig(config) {
15383
15594
  try {
15384
15595
  const file = headroomConfigPath();
15385
- fs33.mkdirSync(path37.dirname(file), { recursive: true, mode: 448 });
15596
+ fs34.mkdirSync(path38.dirname(file), { recursive: true, mode: 448 });
15386
15597
  const tmp = `${file}.tmp-${process.pid}`;
15387
- fs33.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
15388
- fs33.renameSync(tmp, file);
15598
+ fs34.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
15599
+ fs34.renameSync(tmp, file);
15389
15600
  restrictToOwner(file);
15390
15601
  } catch (err) {
15391
15602
  log.warn(
@@ -15395,21 +15606,21 @@ function persistHeadroomConfig(config) {
15395
15606
  }
15396
15607
  }
15397
15608
  function agentSettingsPath(kind) {
15398
- const home = os30.homedir();
15399
- if (kind === "claude") return path37.join(home, ".claude", "settings.json");
15400
- if (kind === "codex") return path37.join(home, ".codex", "auth.json");
15401
- if (kind === "copilot") return path37.join(home, ".config", "github-copilot", "hosts.json");
15609
+ const home = os31.homedir();
15610
+ if (kind === "claude") return path38.join(home, ".claude", "settings.json");
15611
+ if (kind === "codex") return path38.join(home, ".codex", "auth.json");
15612
+ if (kind === "copilot") return path38.join(home, ".config", "github-copilot", "hosts.json");
15402
15613
  return null;
15403
15614
  }
15404
15615
  function backupAgentHeadroomConfig(kind) {
15405
15616
  const src = agentSettingsPath(kind);
15406
15617
  if (!src) return;
15407
15618
  try {
15408
- if (!fs33.existsSync(src)) return;
15409
- const dest = path37.join(os30.homedir(), ".codeam", `headroom-backup-${kind}.json`);
15410
- fs33.mkdirSync(path37.dirname(dest), { recursive: true, mode: 448 });
15411
- fs33.copyFileSync(src, dest);
15412
- fs33.chmodSync(dest, 384);
15619
+ if (!fs34.existsSync(src)) return;
15620
+ const dest = path38.join(os31.homedir(), ".codeam", `headroom-backup-${kind}.json`);
15621
+ fs34.mkdirSync(path38.dirname(dest), { recursive: true, mode: 448 });
15622
+ fs34.copyFileSync(src, dest);
15623
+ fs34.chmodSync(dest, 384);
15413
15624
  log.info("host-agent", `headroom config backup: ${src} \u2192 ${dest}`);
15414
15625
  } catch (err) {
15415
15626
  log.warn(
@@ -15421,12 +15632,12 @@ function backupAgentHeadroomConfig(kind) {
15421
15632
  function restoreAgentHeadroomConfig(kind) {
15422
15633
  const dest = agentSettingsPath(kind);
15423
15634
  if (!dest) return false;
15424
- const src = path37.join(os30.homedir(), ".codeam", `headroom-backup-${kind}.json`);
15425
- if (!fs33.existsSync(src)) return false;
15635
+ const src = path38.join(os31.homedir(), ".codeam", `headroom-backup-${kind}.json`);
15636
+ if (!fs34.existsSync(src)) return false;
15426
15637
  try {
15427
- fs33.mkdirSync(path37.dirname(dest), { recursive: true, mode: 448 });
15428
- fs33.copyFileSync(src, dest);
15429
- fs33.chmodSync(dest, 384);
15638
+ fs34.mkdirSync(path38.dirname(dest), { recursive: true, mode: 448 });
15639
+ fs34.copyFileSync(src, dest);
15640
+ fs34.chmodSync(dest, 384);
15430
15641
  log.info("host-agent", `headroom config restored: ${src} \u2192 ${dest}`);
15431
15642
  return true;
15432
15643
  } catch (err) {
@@ -15439,7 +15650,7 @@ function restoreAgentHeadroomConfig(kind) {
15439
15650
  }
15440
15651
  function readHeadroomChildEnv() {
15441
15652
  try {
15442
- const raw = fs33.readFileSync(headroomConfigPath(), "utf8");
15653
+ const raw = fs34.readFileSync(headroomConfigPath(), "utf8");
15443
15654
  const parsed = JSON.parse(raw);
15444
15655
  if (typeof parsed !== "object" || parsed === null) return {};
15445
15656
  const o = parsed;
@@ -15464,37 +15675,37 @@ function bundledClaudeBinDir() {
15464
15675
  const roots = /* @__PURE__ */ new Set();
15465
15676
  let dir = __dirname;
15466
15677
  for (let i = 0; i < 6; i++) {
15467
- roots.add(path37.join(dir, "node_modules"));
15468
- const parent = path37.dirname(dir);
15678
+ roots.add(path38.join(dir, "node_modules"));
15679
+ const parent = path38.dirname(dir);
15469
15680
  if (parent === dir) break;
15470
15681
  dir = parent;
15471
15682
  }
15472
15683
  try {
15473
15684
  const main2 = require.resolve("@anthropic-ai/claude-agent-sdk");
15474
- const marker = `${path37.sep}@anthropic-ai${path37.sep}`;
15685
+ const marker = `${path38.sep}@anthropic-ai${path38.sep}`;
15475
15686
  const idx = main2.lastIndexOf(marker);
15476
15687
  if (idx !== -1) roots.add(main2.slice(0, idx));
15477
15688
  } catch {
15478
15689
  }
15479
15690
  for (const nm of roots) {
15480
- const atAnthropic = path37.join(nm, "@anthropic-ai");
15691
+ const atAnthropic = path38.join(nm, "@anthropic-ai");
15481
15692
  let entries;
15482
15693
  try {
15483
- entries = fs33.readdirSync(atAnthropic);
15694
+ entries = fs34.readdirSync(atAnthropic);
15484
15695
  } catch {
15485
15696
  continue;
15486
15697
  }
15487
15698
  for (const entry of entries) {
15488
15699
  if (!entry.startsWith("claude-agent-sdk-")) continue;
15489
- const bin = path37.join(atAnthropic, entry, "claude");
15490
- if (fs33.existsSync(bin)) return path37.dirname(bin);
15700
+ const bin = path38.join(atAnthropic, entry, "claude");
15701
+ if (fs34.existsSync(bin)) return path38.dirname(bin);
15491
15702
  }
15492
15703
  }
15493
15704
  return null;
15494
15705
  }
15495
15706
  async function getFreeDiskBytes(dir) {
15496
15707
  try {
15497
- const s = await fs33.promises.statfs(dir);
15708
+ const s = await fs34.promises.statfs(dir);
15498
15709
  return s.bsize * s.bavail;
15499
15710
  } catch {
15500
15711
  return null;
@@ -15686,7 +15897,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
15686
15897
  if (initKind === "claude") {
15687
15898
  const claudeDir = bundledClaudeBinDir();
15688
15899
  if (claudeDir) {
15689
- initEnv.PATH = `${claudeDir}${path37.delimiter}${process.env["PATH"] ?? ""}`;
15900
+ initEnv.PATH = `${claudeDir}${path38.delimiter}${process.env["PATH"] ?? ""}`;
15690
15901
  log.info("host-agent", `headroom init: bundled claude on PATH (${claudeDir})`);
15691
15902
  } else {
15692
15903
  log.warn("host-agent", "headroom init: bundled claude binary not found \u2014 init may fail");
@@ -15710,7 +15921,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
15710
15921
  onProgress("proxy");
15711
15922
  try {
15712
15923
  const proxyEnv = { ...process.env, HEADROOM_KOMPRESS_BACKEND: "onnx_cpu" };
15713
- const proxy = (0, import_node_child_process15.spawn)(
15924
+ const proxy = (0, import_node_child_process16.spawn)(
15714
15925
  "headroom",
15715
15926
  ["proxy", "--port", "8787", ...buildBudgetProxyArgs(proxyEnv)],
15716
15927
  {
@@ -15726,6 +15937,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
15726
15937
  );
15727
15938
  });
15728
15939
  proxy.unref();
15940
+ writeHeadroomProxyPidfile(proxy.pid);
15729
15941
  } catch (e) {
15730
15942
  log.warn(
15731
15943
  "host-agent",
@@ -15735,18 +15947,18 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
15735
15947
  onProgress("ready");
15736
15948
  return true;
15737
15949
  }
15738
- var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process15.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
15950
+ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process16.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
15739
15951
  cwd,
15740
15952
  env: { ...process.env, ...env },
15741
15953
  stdio: ["ignore", "pipe", "pipe"],
15742
15954
  detached: false
15743
15955
  });
15744
15956
  function currentCliVersion() {
15745
- return true ? "2.53.2" : null;
15957
+ return true ? "2.53.4" : null;
15746
15958
  }
15747
15959
  function runCmd(cmd, args2, timeoutMs) {
15748
15960
  return new Promise((resolve7) => {
15749
- (0, import_node_child_process15.execFile)(cmd, args2, { timeout: timeoutMs }, (err, stdout, stderr) => {
15961
+ (0, import_node_child_process16.execFile)(cmd, args2, { timeout: timeoutMs }, (err, stdout, stderr) => {
15750
15962
  const code = err && typeof err.code === "number" ? err.code : err ? null : 0;
15751
15963
  resolve7({ code, stdout: stdout ?? "", stderr: stderr ?? "" });
15752
15964
  });
@@ -15817,22 +16029,19 @@ var defaultOnUpdated = (version3) => {
15817
16029
  };
15818
16030
  var defaultDisableService = () => {
15819
16031
  try {
15820
- (0, import_node_child_process15.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
16032
+ (0, import_node_child_process16.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
15821
16033
  } catch {
15822
16034
  }
15823
16035
  };
15824
16036
  var defaultTeardownHeadroom = () => {
15825
16037
  try {
15826
- const kind = JSON.parse(fs33.readFileSync(headroomConfigPath(), "utf8")).agent;
16038
+ const kind = JSON.parse(fs34.readFileSync(headroomConfigPath(), "utf8")).agent;
15827
16039
  if (kind) {
15828
- (0, import_node_child_process15.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
16040
+ (0, import_node_child_process16.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
15829
16041
  }
15830
16042
  } catch {
15831
16043
  }
15832
- try {
15833
- (0, import_node_child_process15.execFileSync)("pkill", ["-TERM", "-f", "headroom.*proxy"], { stdio: "ignore" });
15834
- } catch {
15835
- }
16044
+ killHeadroomProxy();
15836
16045
  persistHeadroomConfig({ enabled: false });
15837
16046
  };
15838
16047
  var HostAgentSupervisor = class {
@@ -16137,9 +16346,9 @@ var HostAgentSupervisor = class {
16137
16346
  API_TIMEOUT_MS: "3000000",
16138
16347
  CODEAM_AUTO_TOKEN: payload.autoPairToken
16139
16348
  };
16140
- const houseConfigDir = path37.join(os30.homedir(), ".codeam", "house-claude");
16349
+ const houseConfigDir = path38.join(os31.homedir(), ".codeam", "house-claude");
16141
16350
  try {
16142
- fs33.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
16351
+ fs34.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
16143
16352
  } catch {
16144
16353
  }
16145
16354
  childEnv.CLAUDE_CONFIG_DIR = houseConfigDir;
@@ -16157,14 +16366,14 @@ var HostAgentSupervisor = class {
16157
16366
  report("installing", "installing agent CLI");
16158
16367
  await this.runAgentInstall(payload.agentInstallScript);
16159
16368
  }
16160
- const home = process.env.HOME || os30.homedir();
16369
+ const home = process.env.HOME || os31.homedir();
16161
16370
  childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
16162
16371
  if (payload.cloneToken) {
16163
16372
  try {
16164
16373
  report("preparing", "configuring git tooling");
16165
16374
  const ghCmd = await ensureGhCli(defaultGitToolingRunner, payload.cloneToken);
16166
16375
  if (ghCmd) {
16167
- childEnv.PATH = `${codeamBinDir()}${path37.delimiter}${childEnv.PATH}`;
16376
+ childEnv.PATH = `${codeamBinDir()}${path38.delimiter}${childEnv.PATH}`;
16168
16377
  await ensureGhAuth(defaultGitToolingRunner, ghCmd, payload.cloneToken);
16169
16378
  }
16170
16379
  } catch (e) {
@@ -16180,7 +16389,7 @@ var HostAgentSupervisor = class {
16180
16389
  }
16181
16390
  if (payload.headroomEnabled && payload.headroomAgent && payload.headroomSavingsIngestUrl && isHeadroomSupportedAgent(payload.headroomAgent)) {
16182
16391
  report("headroom", "setting up Headroom proxy");
16183
- const freeBytes = await this.getFreeDisk(os30.homedir());
16392
+ const freeBytes = await this.getFreeDisk(os31.homedir());
16184
16393
  const alreadyInstalled = this.isHeadroomInstalled();
16185
16394
  if (!alreadyInstalled && freeBytes !== null && freeBytes < HEADROOM_MIN_FREE_DISK_BYTES) {
16186
16395
  const freeGb = (freeBytes / 1e9).toFixed(1);
@@ -16302,8 +16511,8 @@ var HostAgentSupervisor = class {
16302
16511
  */
16303
16512
  runAgentInstall(script) {
16304
16513
  return new Promise((resolve7) => {
16305
- const home = process.env.HOME || os30.homedir();
16306
- const child = (0, import_node_child_process15.spawn)("sh", ["-c", script], {
16514
+ const home = process.env.HOME || os31.homedir();
16515
+ const child = (0, import_node_child_process16.spawn)("sh", ["-c", script], {
16307
16516
  env: { ...process.env, HOME: home },
16308
16517
  stdio: ["ignore", "pipe", "pipe"]
16309
16518
  });
@@ -16458,10 +16667,10 @@ async function configureHeadroom(action, ctx, deps) {
16458
16667
  if (!isHeadroomSupportedAgent(ctx.agent)) return { supported: false };
16459
16668
  const ok = await deps.setup(ctx.agent, void 0, {
16460
16669
  extras: ["proxy", "code", "image"],
16461
- onProgress: (step) => deps.emit({ type: "headroom_progress", step })
16670
+ onProgress: (step) => deps.emit({ type: USER_EVENTS.HEADROOM_PROGRESS, step })
16462
16671
  });
16463
16672
  if (!ok) {
16464
- deps.emit({ type: "headroom_status", state: "error" });
16673
+ deps.emit({ type: USER_EVENTS.HEADROOM_STATUS, state: "error" });
16465
16674
  return { enabled: false };
16466
16675
  }
16467
16676
  deps.persist({ enabled: true, agent: kind, ingestUrl: ctx.savingsIngestUrl });
@@ -16472,21 +16681,21 @@ async function configureHeadroom(action, ctx, deps) {
16472
16681
  pluginAuthToken: ctx.pluginAuthToken
16473
16682
  });
16474
16683
  }
16475
- deps.emit({ type: "headroom_status", state: "enabled" });
16684
+ deps.emit({ type: USER_EVENTS.HEADROOM_STATUS, state: "enabled" });
16476
16685
  return { enabled: true };
16477
16686
  }
16478
16687
  deps.restoreAgentHeadroomConfig(kind);
16479
16688
  deps.stopProxy();
16480
16689
  deps.persist({ enabled: false });
16481
16690
  deps.stopReporter();
16482
- deps.emit({ type: "headroom_status", state: "disabled" });
16691
+ deps.emit({ type: USER_EVENTS.HEADROOM_STATUS, state: "disabled" });
16483
16692
  return { enabled: false };
16484
16693
  }
16485
16694
 
16486
16695
  // src/services/headroom/budget-relaunch.ts
16487
- var fs34 = __toESM(require("fs"));
16488
- var os31 = __toESM(require("os"));
16489
- var path38 = __toESM(require("path"));
16696
+ var fs35 = __toESM(require("fs"));
16697
+ var os32 = __toESM(require("os"));
16698
+ var path39 = __toESM(require("path"));
16490
16699
  var import_child_process13 = require("child_process");
16491
16700
  function amendDeploymentManifestBudget(manifest, budget) {
16492
16701
  const rawArgs = manifest.proxy_args ?? [];
@@ -16520,7 +16729,7 @@ function amendDeploymentManifestBudget(manifest, budget) {
16520
16729
  return { ...manifest, proxy_args: newArgs, base_env: newEnv };
16521
16730
  }
16522
16731
  function findHeadroomDeployments(homeDir2, deps) {
16523
- const deployDir = path38.join(homeDir2, ".headroom", "deploy");
16732
+ const deployDir = path39.join(homeDir2, ".headroom", "deploy");
16524
16733
  let profiles;
16525
16734
  try {
16526
16735
  profiles = deps.readDir(deployDir);
@@ -16529,7 +16738,7 @@ function findHeadroomDeployments(homeDir2, deps) {
16529
16738
  }
16530
16739
  const results = [];
16531
16740
  for (const profile of profiles) {
16532
- const manifestPath = path38.join(deployDir, profile, "manifest.json");
16741
+ const manifestPath = path39.join(deployDir, profile, "manifest.json");
16533
16742
  let raw;
16534
16743
  try {
16535
16744
  raw = deps.readJson(manifestPath);
@@ -16561,8 +16770,8 @@ async function applyBudgetToHeadroom(budget, deps) {
16561
16770
  }
16562
16771
  function writeManifestReal(manifestPath, manifest) {
16563
16772
  const tmp = manifestPath + ".codeam.tmp";
16564
- fs34.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
16565
- fs34.renameSync(tmp, manifestPath);
16773
+ fs35.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
16774
+ fs35.renameSync(tmp, manifestPath);
16566
16775
  }
16567
16776
  function restartDeploymentReal(profile) {
16568
16777
  try {
@@ -16582,16 +16791,7 @@ function restartDeploymentReal(profile) {
16582
16791
  }
16583
16792
  }
16584
16793
  function killProxyReal() {
16585
- try {
16586
- const killer = (0, import_child_process13.spawn)("pkill", ["-TERM", "-f", "headroom.*proxy"], {
16587
- detached: true,
16588
- stdio: "ignore"
16589
- });
16590
- killer.once("error", () => {
16591
- });
16592
- killer.unref();
16593
- } catch {
16594
- }
16794
+ killHeadroomProxy();
16595
16795
  }
16596
16796
  function spawnProxyReal2(budget) {
16597
16797
  try {
@@ -16612,6 +16812,7 @@ function spawnProxyReal2(budget) {
16612
16812
  log.warn("headroom-budget", `proxy relaunch error (best-effort): ${e.message}`);
16613
16813
  });
16614
16814
  proxy.unref();
16815
+ writeHeadroomProxyPidfile(proxy.pid);
16615
16816
  } catch (e) {
16616
16817
  log.warn(
16617
16818
  "headroom-budget",
@@ -16620,11 +16821,11 @@ function spawnProxyReal2(budget) {
16620
16821
  }
16621
16822
  }
16622
16823
  function makeRealApplyBudgetDeps() {
16623
- const homeDir2 = os31.homedir();
16824
+ const homeDir2 = os32.homedir();
16624
16825
  return {
16625
16826
  findDeployments: () => findHeadroomDeployments(homeDir2, {
16626
- readDir: (dir) => fs34.readdirSync(dir),
16627
- readJson: (filePath) => JSON.parse(fs34.readFileSync(filePath, "utf8"))
16827
+ readDir: (dir) => fs35.readdirSync(dir),
16828
+ readJson: (filePath) => JSON.parse(fs35.readFileSync(filePath, "utf8"))
16628
16829
  }),
16629
16830
  writeManifest: writeManifestReal,
16630
16831
  restartDeployment: restartDeploymentReal,
@@ -17268,9 +17469,9 @@ function activePreviewSessionIds() {
17268
17469
 
17269
17470
  // src/beads/bd-adapter.ts
17270
17471
  var import_child_process17 = require("child_process");
17271
- var fs39 = __toESM(require("fs"));
17272
- var os33 = __toESM(require("os"));
17273
- var path43 = __toESM(require("path"));
17472
+ var fs40 = __toESM(require("fs"));
17473
+ var os34 = __toESM(require("os"));
17474
+ var path44 = __toESM(require("path"));
17274
17475
  var BD_PACKAGE = "@beads/bd";
17275
17476
  function resolveBundledBdBinary() {
17276
17477
  return _resolveSeam.resolveBundled();
@@ -17282,11 +17483,11 @@ function _defaultResolveBundled() {
17282
17483
  } catch {
17283
17484
  return null;
17284
17485
  }
17285
- const binDir = path43.join(path43.dirname(pkgJsonPath), "bin");
17486
+ const binDir = path44.join(path44.dirname(pkgJsonPath), "bin");
17286
17487
  const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
17287
- const binaryPath = path43.join(binDir, binaryName);
17488
+ const binaryPath = path44.join(binDir, binaryName);
17288
17489
  try {
17289
- fs39.accessSync(binaryPath, fs39.constants.F_OK);
17490
+ fs40.accessSync(binaryPath, fs40.constants.F_OK);
17290
17491
  return binaryPath;
17291
17492
  } catch {
17292
17493
  return null;
@@ -17296,13 +17497,13 @@ function resolveBdOnPath() {
17296
17497
  return _resolveSeam.resolveOnPath();
17297
17498
  }
17298
17499
  function _defaultResolveOnPath() {
17299
- const dirs = (process.env.PATH ?? "").split(path43.delimiter).filter(Boolean);
17500
+ const dirs = (process.env.PATH ?? "").split(path44.delimiter).filter(Boolean);
17300
17501
  const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
17301
17502
  for (const dir of dirs) {
17302
17503
  for (const candidate of candidates) {
17303
- const full = path43.join(dir, candidate);
17504
+ const full = path44.join(dir, candidate);
17304
17505
  try {
17305
- fs39.accessSync(full, fs39.constants.F_OK);
17506
+ fs40.accessSync(full, fs40.constants.F_OK);
17306
17507
  return full;
17307
17508
  } catch {
17308
17509
  }
@@ -17387,7 +17588,7 @@ var BdAdapter = class {
17387
17588
  const env = { ...process.env };
17388
17589
  if (!env.HOME) {
17389
17590
  try {
17390
- const home = os33.homedir();
17591
+ const home = os34.homedir();
17391
17592
  if (home) env.HOME = home;
17392
17593
  } catch {
17393
17594
  }
@@ -17467,18 +17668,21 @@ function coerceIssue(row, projectKey) {
17467
17668
  owner: typeof r.owner === "string" && r.owner.length > 0 ? r.owner : null,
17468
17669
  created_at: typeof r.created_at === "string" ? r.created_at : "",
17469
17670
  updated_at: typeof r.updated_at === "string" ? r.updated_at : "",
17470
- dependency_count: typeof r.dependency_count === "number" ? r.dependency_count : void 0,
17471
- dependent_count: typeof r.dependent_count === "number" ? r.dependent_count : void 0,
17472
- comment_count: typeof r.comment_count === "number" ? r.comment_count : void 0,
17671
+ // The backend ingest DTO validates the counts as REQUIRED ints — an
17672
+ // omitted count would 400 the whole snapshot. Default to 0 when a bd
17673
+ // version omits one instead of dropping the field.
17674
+ dependency_count: typeof r.dependency_count === "number" ? r.dependency_count : 0,
17675
+ dependent_count: typeof r.dependent_count === "number" ? r.dependent_count : 0,
17676
+ comment_count: typeof r.comment_count === "number" ? r.comment_count : 0,
17473
17677
  projectKey
17474
17678
  };
17475
17679
  }
17476
17680
 
17477
17681
  // src/beads/provisioner.ts
17478
17682
  var import_child_process21 = require("child_process");
17479
- var fs42 = __toESM(require("fs"));
17480
- var os35 = __toESM(require("os"));
17481
- var path46 = __toESM(require("path"));
17683
+ var fs43 = __toESM(require("fs"));
17684
+ var os36 = __toESM(require("os"));
17685
+ var path47 = __toESM(require("path"));
17482
17686
 
17483
17687
  // src/beads/install-bd.ts
17484
17688
  var import_child_process18 = require("child_process");
@@ -17543,9 +17747,9 @@ async function installBd(platform3 = process.platform) {
17543
17747
 
17544
17748
  // src/beads/install-dolt.ts
17545
17749
  var import_child_process19 = require("child_process");
17546
- var fs40 = __toESM(require("fs"));
17547
- var os34 = __toESM(require("os"));
17548
- var path44 = __toESM(require("path"));
17750
+ var fs41 = __toESM(require("fs"));
17751
+ var os35 = __toESM(require("os"));
17752
+ var path45 = __toESM(require("path"));
17549
17753
  var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
17550
17754
  var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
17551
17755
  function resolveDoltInstallStrategy(platform3) {
@@ -17585,11 +17789,11 @@ function resolveDoltInstallStrategy(platform3) {
17585
17789
  }
17586
17790
  var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
17587
17791
  function doltPlatformTuple(platform3, arch2) {
17588
- const os44 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
17792
+ const os45 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
17589
17793
  const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
17590
17794
  if (!a) return null;
17591
- if (os44 === "windows" && a !== "amd64") return null;
17592
- return `${os44}-${a}`;
17795
+ if (os45 === "windows" && a !== "amd64") return null;
17796
+ return `${os45}-${a}`;
17593
17797
  }
17594
17798
  function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
17595
17799
  const tuple = doltPlatformTuple(platform3, arch2);
@@ -17634,14 +17838,14 @@ async function installDoltToDir(targetDir, platform3 = process.platform, arch2 =
17634
17838
  return result;
17635
17839
  }
17636
17840
  var _doltPathSeam = {
17637
- homedir: () => os34.homedir(),
17841
+ homedir: () => os35.homedir(),
17638
17842
  getPath: () => process.env.PATH ?? "",
17639
17843
  setPath: (p2) => {
17640
17844
  process.env.PATH = p2;
17641
17845
  },
17642
17846
  exists: (p2) => {
17643
17847
  try {
17644
- fs40.accessSync(p2, fs40.constants.F_OK);
17848
+ fs41.accessSync(p2, fs41.constants.F_OK);
17645
17849
  return true;
17646
17850
  } catch {
17647
17851
  return false;
@@ -17652,7 +17856,7 @@ function doltBinaryNames(platform3) {
17652
17856
  return platform3 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
17653
17857
  }
17654
17858
  function knownDoltDirs(platform3) {
17655
- const P3 = platform3 === "win32" ? path44.win32 : path44.posix;
17859
+ const P3 = platform3 === "win32" ? path45.win32 : path45.posix;
17656
17860
  const home = _doltPathSeam.homedir();
17657
17861
  if (platform3 === "win32") {
17658
17862
  return [
@@ -17668,7 +17872,7 @@ function knownDoltDirs(platform3) {
17668
17872
  ].filter(Boolean);
17669
17873
  }
17670
17874
  function ensureDoltResolvable(platform3 = process.platform) {
17671
- const P3 = platform3 === "win32" ? path44.win32 : path44.posix;
17875
+ const P3 = platform3 === "win32" ? path45.win32 : path45.posix;
17672
17876
  const delim = platform3 === "win32" ? ";" : ":";
17673
17877
  const names = doltBinaryNames(platform3);
17674
17878
  const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
@@ -17804,8 +18008,8 @@ async function ensureSharedServer(adapter, options = {}) {
17804
18008
  // src/beads/project-key.ts
17805
18009
  var import_child_process20 = require("child_process");
17806
18010
  var crypto2 = __toESM(require("crypto"));
17807
- var fs41 = __toESM(require("fs"));
17808
- var path45 = __toESM(require("path"));
18011
+ var fs42 = __toESM(require("fs"));
18012
+ var path46 = __toESM(require("path"));
17809
18013
  function normalizeOrigin(raw) {
17810
18014
  const trimmed = raw.trim();
17811
18015
  if (!trimmed) return null;
@@ -17831,17 +18035,17 @@ function normalizeOrigin(raw) {
17831
18035
  return `${host2}/${pathPart}`;
17832
18036
  }
17833
18037
  function findRepoRoot(cwd) {
17834
- let dir = path45.resolve(cwd);
18038
+ let dir = path46.resolve(cwd);
17835
18039
  const seen = /* @__PURE__ */ new Set();
17836
18040
  for (let i = 0; i < 256; i++) {
17837
18041
  if (seen.has(dir)) return null;
17838
18042
  seen.add(dir);
17839
18043
  try {
17840
- const stat3 = fs41.statSync(path45.join(dir, ".git"), { throwIfNoEntry: false });
18044
+ const stat3 = fs42.statSync(path46.join(dir, ".git"), { throwIfNoEntry: false });
17841
18045
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
17842
18046
  } catch {
17843
18047
  }
17844
- const parent = path45.dirname(dir);
18048
+ const parent = path46.dirname(dir);
17845
18049
  if (parent === dir) return null;
17846
18050
  dir = parent;
17847
18051
  }
@@ -17852,7 +18056,7 @@ var _execSeam2 = {
17852
18056
  const out2 = (0, import_child_process20.execFileSync)(file, args2, opts);
17853
18057
  return typeof out2 === "string" ? out2 : out2.toString("utf8");
17854
18058
  },
17855
- realpath: (p2) => fs41.realpathSync(p2)
18059
+ realpath: (p2) => fs42.realpathSync(p2)
17856
18060
  };
17857
18061
  function readOrigin(cwd) {
17858
18062
  try {
@@ -17881,7 +18085,7 @@ function deriveProjectIdentity(cwd = process.cwd()) {
17881
18085
  } catch {
17882
18086
  }
17883
18087
  const hash = crypto2.createHash("sha256").update(real).digest("hex");
17884
- return { projectKey: `path:${hash}`, projectLabel: path45.basename(real) || "project" };
18088
+ return { projectKey: `path:${hash}`, projectLabel: path46.basename(real) || "project" };
17885
18089
  }
17886
18090
 
17887
18091
  // src/beads/project-prefix.ts
@@ -17923,17 +18127,17 @@ var _provisionSeam = {
17923
18127
  };
17924
18128
  var _linkSeam = {
17925
18129
  platform: () => process.platform,
17926
- homedir: () => os35.homedir(),
18130
+ homedir: () => os36.homedir(),
17927
18131
  isWritableDir: (dir) => {
17928
18132
  try {
17929
- fs42.accessSync(dir, fs42.constants.W_OK);
18133
+ fs43.accessSync(dir, fs43.constants.W_OK);
17930
18134
  return true;
17931
18135
  } catch {
17932
18136
  return false;
17933
18137
  }
17934
18138
  },
17935
18139
  ensureDir: (dir) => {
17936
- fs42.mkdirSync(dir, { recursive: true });
18140
+ fs43.mkdirSync(dir, { recursive: true });
17937
18141
  },
17938
18142
  /**
17939
18143
  * A directory to symlink `bd` into so the AGENT's shell + Claude Code's
@@ -17954,9 +18158,9 @@ var _linkSeam = {
17954
18158
  * which `linkBdOntoPath` creates if missing.
17955
18159
  */
17956
18160
  cliBinDir: () => {
17957
- const pathDirs = (process.env.PATH ?? "").split(path46.delimiter).filter(Boolean);
18161
+ const pathDirs = (process.env.PATH ?? "").split(path47.delimiter).filter(Boolean);
17958
18162
  const home = _linkSeam.homedir();
17959
- const localBin = home ? path46.join(home, ".local", "bin") : null;
18163
+ const localBin = home ? path47.join(home, ".local", "bin") : null;
17960
18164
  if (localBin) {
17961
18165
  try {
17962
18166
  _linkSeam.ensureDir(localBin);
@@ -17966,16 +18170,16 @@ var _linkSeam = {
17966
18170
  const candidates = [];
17967
18171
  if (localBin) candidates.push(localBin);
17968
18172
  try {
17969
- candidates.push(path46.dirname(process.execPath));
18173
+ candidates.push(path47.dirname(process.execPath));
17970
18174
  } catch {
17971
18175
  }
17972
18176
  candidates.push("/usr/local/bin");
17973
18177
  const entry = process.argv[1];
17974
18178
  if (entry) {
17975
18179
  try {
17976
- candidates.push(path46.dirname(fs42.realpathSync(entry)));
18180
+ candidates.push(path47.dirname(fs43.realpathSync(entry)));
17977
18181
  } catch {
17978
- candidates.push(path46.dirname(entry));
18182
+ candidates.push(path47.dirname(entry));
17979
18183
  }
17980
18184
  }
17981
18185
  const onPathWritable = candidates.find(
@@ -17987,20 +18191,20 @@ var _linkSeam = {
17987
18191
  /** Current symlink target at `linkPath`, or null when absent / not a link. */
17988
18192
  readlink: (linkPath) => {
17989
18193
  try {
17990
- return fs42.readlinkSync(linkPath);
18194
+ return fs43.readlinkSync(linkPath);
17991
18195
  } catch {
17992
18196
  return null;
17993
18197
  }
17994
18198
  },
17995
- unlink: (linkPath) => fs42.unlinkSync(linkPath),
17996
- symlink: (target, linkPath) => fs42.symlinkSync(target, linkPath)
18199
+ unlink: (linkPath) => fs43.unlinkSync(linkPath),
18200
+ symlink: (target, linkPath) => fs43.symlinkSync(target, linkPath)
17997
18201
  };
17998
18202
  function linkBdOntoPath(binaryPath) {
17999
18203
  if (_linkSeam.platform() === "win32") return;
18000
18204
  const binDir = _linkSeam.cliBinDir();
18001
18205
  if (!binDir) return;
18002
18206
  _linkSeam.ensureDir(binDir);
18003
- const linkPath = path46.join(binDir, "bd");
18207
+ const linkPath = path47.join(binDir, "bd");
18004
18208
  if (linkPath === binaryPath) return;
18005
18209
  const current = _linkSeam.readlink(linkPath);
18006
18210
  if (current === binaryPath) return;
@@ -18195,7 +18399,7 @@ function dedupeRecipes(agents) {
18195
18399
 
18196
18400
  // src/beads/watcher.ts
18197
18401
  var crypto4 = __toESM(require("crypto"));
18198
- var path47 = __toESM(require("path"));
18402
+ var path48 = __toESM(require("path"));
18199
18403
  var API_BASE6 = resolveApiBaseUrl();
18200
18404
  var DEBOUNCE_MS2 = 400;
18201
18405
  var ZERO_SUMMARY = {
@@ -18219,7 +18423,7 @@ var BeadsWatcher = class {
18219
18423
  constructor(opts) {
18220
18424
  this.opts = opts;
18221
18425
  this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
18222
- this.feedPath = opts.feedPath ?? path47.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
18426
+ this.feedPath = opts.feedPath ?? path48.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
18223
18427
  this.apiBase = opts.apiBaseUrl ?? API_BASE6;
18224
18428
  }
18225
18429
  opts;
@@ -18306,9 +18510,10 @@ var BeadsWatcher = class {
18306
18510
  projectLabel,
18307
18511
  fullSnapshot: true,
18308
18512
  issues,
18309
- // The backend DTO requires `dependencies` (not `deps`). We don't track
18310
- // edges in the P0 snapshot yet, so always send an empty array rather than
18311
- // omitting the field (an omitted/conditional field 400s the ingest).
18513
+ // We don't track edges in the P0 snapshot yet, so send an empty array.
18514
+ // (The backend DTO marks `dependencies` optional and tolerates absence,
18515
+ // but the wire contract in @codeagent/shared says "always sent" — keep
18516
+ // the payload deterministic.)
18312
18517
  dependencies: [],
18313
18518
  memories: [],
18314
18519
  // Always send a summary — a null `bd status` yields a zeroed block rather
@@ -18629,7 +18834,7 @@ var pendingAttachmentFiles = /* @__PURE__ */ new Set();
18629
18834
  function cleanupAttachmentTempFiles() {
18630
18835
  for (const p2 of pendingAttachmentFiles) {
18631
18836
  try {
18632
- fs44.unlinkSync(p2);
18837
+ fs45.unlinkSync(p2);
18633
18838
  } catch {
18634
18839
  }
18635
18840
  }
@@ -18638,8 +18843,8 @@ function cleanupAttachmentTempFiles() {
18638
18843
  function saveFilesTemp(files) {
18639
18844
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
18640
18845
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
18641
- const tmpPath = path49.join(os37.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
18642
- fs44.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
18846
+ const tmpPath = path50.join(os38.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
18847
+ fs45.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
18643
18848
  pendingAttachmentFiles.add(tmpPath);
18644
18849
  return tmpPath;
18645
18850
  });
@@ -18659,7 +18864,7 @@ var startTask = (ctx, _cmd, parsed) => {
18659
18864
  setTimeout(() => {
18660
18865
  for (const p2 of paths) {
18661
18866
  try {
18662
- fs44.unlinkSync(p2);
18867
+ fs45.unlinkSync(p2);
18663
18868
  } catch {
18664
18869
  }
18665
18870
  pendingAttachmentFiles.delete(p2);
@@ -18860,9 +19065,9 @@ var listFiles = async (ctx, cmd, parsed) => {
18860
19065
  await ctx.relay.sendResult(cmd.id, "completed", result);
18861
19066
  };
18862
19067
  var envReadH = async (ctx, cmd) => {
18863
- const envPath = path49.join(process.cwd(), ".env");
19068
+ const envPath = path50.join(process.cwd(), ".env");
18864
19069
  try {
18865
- const raw = await fs44.promises.readFile(envPath, "utf8");
19070
+ const raw = await fs45.promises.readFile(envPath, "utf8");
18866
19071
  await ctx.relay.sendResult(cmd.id, "completed", {
18867
19072
  exists: true,
18868
19073
  vars: parseDotenv(raw)
@@ -18893,14 +19098,14 @@ var envWriteH = async (ctx, cmd, parsed) => {
18893
19098
  }
18894
19099
  seen.add(v.key);
18895
19100
  }
18896
- const envPath = path49.join(process.cwd(), ".env");
18897
- const tmpPath = path49.join(process.cwd(), ".env.codeam.tmp");
19101
+ const envPath = path50.join(process.cwd(), ".env");
19102
+ const tmpPath = path50.join(process.cwd(), ".env.codeam.tmp");
18898
19103
  try {
18899
- await fs44.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
18900
- await fs44.promises.rename(tmpPath, envPath);
19104
+ await fs45.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
19105
+ await fs45.promises.rename(tmpPath, envPath);
18901
19106
  await ctx.relay.sendResult(cmd.id, "completed", { ok: true, count: vars.length });
18902
19107
  } catch (err) {
18903
- await fs44.promises.rm(tmpPath, { force: true }).catch(() => void 0);
19108
+ await fs45.promises.rm(tmpPath, { force: true }).catch(() => void 0);
18904
19109
  await ctx.relay.sendResult(cmd.id, "failed", { error: err.message });
18905
19110
  }
18906
19111
  };
@@ -18918,7 +19123,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
18918
19123
  let configuredAgent = rawAgentId;
18919
19124
  if (!configuredAgent) {
18920
19125
  try {
18921
- const raw = JSON.parse(fs44.readFileSync(headroomConfigPath(), "utf8"));
19126
+ const raw = JSON.parse(fs45.readFileSync(headroomConfigPath(), "utf8"));
18922
19127
  configuredAgent = raw.agent ?? "";
18923
19128
  } catch {
18924
19129
  }
@@ -18931,7 +19136,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
18931
19136
  setup: setupHeadroomForSelfHosted,
18932
19137
  probeStats: async () => {
18933
19138
  try {
18934
- const res = await fetch("http://localhost:8787/stats");
19139
+ const res = await fetchWithTimeout("http://localhost:8787/stats");
18935
19140
  if (!res.ok) return null;
18936
19141
  const raw = await res.json();
18937
19142
  return mapStatsToSavings(raw, {
@@ -18952,7 +19157,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
18952
19157
  persist: persistHeadroomConfig,
18953
19158
  readEnabled: () => {
18954
19159
  try {
18955
- const raw = JSON.parse(fs44.readFileSync(headroomConfigPath(), "utf8"));
19160
+ const raw = JSON.parse(fs45.readFileSync(headroomConfigPath(), "utf8"));
18956
19161
  return raw.enabled === true;
18957
19162
  } catch {
18958
19163
  return false;
@@ -18962,12 +19167,12 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
18962
19167
  _activeReporter?.stop();
18963
19168
  const reporter = new HeadroomStatsReporter({
18964
19169
  fetchStats: async () => {
18965
- const res = await fetch("http://localhost:8787/stats");
19170
+ const res = await fetchWithTimeout("http://localhost:8787/stats");
18966
19171
  return res.json();
18967
19172
  },
18968
19173
  postSavings: async (delta, budget) => {
18969
19174
  if (!opts.ingestUrl) return;
18970
- await fetch(opts.ingestUrl, {
19175
+ const res = await fetchWithTimeout(opts.ingestUrl, {
18971
19176
  method: "POST",
18972
19177
  headers: {
18973
19178
  "Content-Type": "application/json",
@@ -18988,10 +19193,14 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
18988
19193
  ...budget ? {
18989
19194
  periodSpendUsd: budget.periodSpendUsd,
18990
19195
  budgetUsd: budget.budgetUsd,
18991
- budgetPeriod: budget.budgetPeriod
19196
+ budgetPeriod: budget.budgetPeriod,
19197
+ budgetReached: budget.budgetReached
18992
19198
  } : {}
18993
19199
  })
18994
19200
  });
19201
+ if (!res.ok) {
19202
+ log.warn("headroom", `savings POST rejected ${res.status} \u2014 delta not credited`);
19203
+ }
18995
19204
  }
18996
19205
  });
18997
19206
  reporter.start();
@@ -19002,18 +19211,9 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
19002
19211
  _activeReporter = null;
19003
19212
  },
19004
19213
  restoreAgentHeadroomConfig: (kind) => restoreAgentHeadroomConfig(kind),
19005
- stopProxy: () => {
19006
- try {
19007
- const p2 = (0, import_child_process22.spawn)("pkill", ["-TERM", "-f", "headroom.*proxy"], {
19008
- detached: true,
19009
- stdio: "ignore"
19010
- });
19011
- p2.on("error", () => {
19012
- });
19013
- p2.unref();
19014
- } catch {
19015
- }
19016
- },
19214
+ // Targeted pidfile kill; falls back to the legacy pkill pattern only when
19215
+ // no live recorded pid exists. Best-effort — never throws.
19216
+ stopProxy: () => killHeadroomProxy(),
19017
19217
  emit: (event) => {
19018
19218
  const token = ctx.pluginAuthToken;
19019
19219
  if (!token) return;
@@ -19046,7 +19246,7 @@ var headroomBudgetH = async (ctx, cmd) => {
19046
19246
  }
19047
19247
  let headroomActive = false;
19048
19248
  try {
19049
- const raw = JSON.parse(fs44.readFileSync(headroomConfigPath(), "utf8"));
19249
+ const raw = JSON.parse(fs45.readFileSync(headroomConfigPath(), "utf8"));
19050
19250
  headroomActive = raw.enabled === true;
19051
19251
  } catch {
19052
19252
  }
@@ -19056,7 +19256,7 @@ var headroomBudgetH = async (ctx, cmd) => {
19056
19256
  }
19057
19257
  let existingConfig = { enabled: true };
19058
19258
  try {
19059
- existingConfig = JSON.parse(fs44.readFileSync(headroomConfigPath(), "utf8"));
19259
+ existingConfig = JSON.parse(fs45.readFileSync(headroomConfigPath(), "utf8"));
19060
19260
  } catch {
19061
19261
  }
19062
19262
  if (payload.budgetEnabled && payload.budgetUsd != null) {
@@ -19135,7 +19335,7 @@ var beadsConfigureH = async (ctx, cmd, parsed) => {
19135
19335
  sessionId: ctx.sessionId,
19136
19336
  pluginId: ctx.pluginId,
19137
19337
  pluginAuthToken: token,
19138
- type: "beads_status",
19338
+ type: USER_EVENTS.BEADS_STATUS,
19139
19339
  payload: Object.fromEntries(
19140
19340
  Object.entries(event).filter(([k2]) => k2 !== "type")
19141
19341
  )
@@ -19174,13 +19374,13 @@ var CLI_UPDATE_MAX_ATTEMPTS = 3;
19174
19374
  function buildNpmInstallInvocation(opts) {
19175
19375
  const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
19176
19376
  const execPath = opts?.execPath ?? process.execPath;
19177
- const exists2 = opts?.existsSync ?? fs44.existsSync;
19178
- const normalized = entryScript.split(path49.sep).join("/");
19377
+ const exists2 = opts?.existsSync ?? fs45.existsSync;
19378
+ const normalized = entryScript.split(path50.sep).join("/");
19179
19379
  const marker = "/lib/node_modules/codeam-cli/";
19180
19380
  const markerIdx = normalized.indexOf(marker);
19181
19381
  const prefix = markerIdx > 0 ? entryScript.slice(0, markerIdx) : null;
19182
- const siblingNpm = path49.join(
19183
- path49.dirname(execPath),
19382
+ const siblingNpm = path50.join(
19383
+ path50.dirname(execPath),
19184
19384
  process.platform === "win32" ? "npm.cmd" : "npm"
19185
19385
  );
19186
19386
  const command2 = exists2(siblingNpm) ? siblingNpm : "npm";
@@ -19526,7 +19726,7 @@ var requestPreviewDetectH = (ctx) => {
19526
19726
  sessionId: ctx.sessionId,
19527
19727
  pluginId: ctx.pluginId,
19528
19728
  pluginAuthToken: ctx.pluginAuthToken,
19529
- type: "preview_error",
19729
+ type: USER_EVENTS.PREVIEW_ERROR,
19530
19730
  payload: {
19531
19731
  stage: "detection",
19532
19732
  message: `Preview detection isn't available on ${ctx.runtime.id} sessions yet \u2014 link a Claude or Codex agent.`
@@ -19543,7 +19743,7 @@ var requestPreviewDetectH = (ctx) => {
19543
19743
  sessionId: ctx.sessionId,
19544
19744
  pluginId: ctx.pluginId,
19545
19745
  pluginAuthToken,
19546
- type: "preview_detection_ready",
19746
+ type: USER_EVENTS.PREVIEW_DETECTION_READY,
19547
19747
  payload: { detection: fromFile }
19548
19748
  });
19549
19749
  return;
@@ -19552,7 +19752,7 @@ var requestPreviewDetectH = (ctx) => {
19552
19752
  sessionId: ctx.sessionId,
19553
19753
  pluginId: ctx.pluginId,
19554
19754
  pluginAuthToken,
19555
- type: "preview_detection_pending"
19755
+ type: USER_EVENTS.PREVIEW_DETECTION_PENDING
19556
19756
  });
19557
19757
  log.info("preview", "detect: invoking generateOneShot");
19558
19758
  const startedAt = Date.now();
@@ -19568,7 +19768,7 @@ var requestPreviewDetectH = (ctx) => {
19568
19768
  sessionId: ctx.sessionId,
19569
19769
  pluginId: ctx.pluginId,
19570
19770
  pluginAuthToken,
19571
- type: "preview_error",
19771
+ type: USER_EVENTS.PREVIEW_ERROR,
19572
19772
  payload: {
19573
19773
  stage: "detection",
19574
19774
  message: "Agent returned invalid JSON. Try again, or add a .codeam/preview.json override."
@@ -19582,7 +19782,7 @@ var requestPreviewDetectH = (ctx) => {
19582
19782
  sessionId: ctx.sessionId,
19583
19783
  pluginId: ctx.pluginId,
19584
19784
  pluginAuthToken,
19585
- type: "preview_error",
19785
+ type: USER_EVENTS.PREVIEW_ERROR,
19586
19786
  payload: {
19587
19787
  stage: "unsupported",
19588
19788
  message: detection.notes ?? "No dev server applies to this project."
@@ -19598,7 +19798,7 @@ var requestPreviewDetectH = (ctx) => {
19598
19798
  sessionId: ctx.sessionId,
19599
19799
  pluginId: ctx.pluginId,
19600
19800
  pluginAuthToken,
19601
- type: "preview_detection_ready",
19801
+ type: USER_EVENTS.PREVIEW_DETECTION_READY,
19602
19802
  payload: { detection }
19603
19803
  });
19604
19804
  })();
@@ -19687,8 +19887,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
19687
19887
  if (args2.length === 0) return detection;
19688
19888
  const binName = args2[0];
19689
19889
  if (binName.startsWith("-")) return detection;
19690
- const binPath = path49.join(cwd, "node_modules", ".bin", binName);
19691
- if (!fs44.existsSync(binPath)) return detection;
19890
+ const binPath = path50.join(cwd, "node_modules", ".bin", binName);
19891
+ if (!fs45.existsSync(binPath)) return detection;
19692
19892
  return {
19693
19893
  ...detection,
19694
19894
  command: binPath,
@@ -19715,7 +19915,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19715
19915
  sessionId: ctx.sessionId,
19716
19916
  pluginId: ctx.pluginId,
19717
19917
  pluginAuthToken,
19718
- type: "preview_progress",
19918
+ type: USER_EVENTS.PREVIEW_PROGRESS,
19719
19919
  payload: { step, message, timestamp: Date.now() }
19720
19920
  });
19721
19921
  };
@@ -19731,7 +19931,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19731
19931
  sessionId: ctx.sessionId,
19732
19932
  pluginId: ctx.pluginId,
19733
19933
  pluginAuthToken,
19734
- type: "preview_ready",
19934
+ type: USER_EVENTS.PREVIEW_READY,
19735
19935
  payload: { url: existing.url, framework: existing.framework, port: detection.port }
19736
19936
  });
19737
19937
  return;
@@ -19740,7 +19940,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19740
19940
  sessionId: ctx.sessionId,
19741
19941
  pluginId: ctx.pluginId,
19742
19942
  pluginAuthToken,
19743
- type: "preview_starting",
19943
+ type: USER_EVENTS.PREVIEW_STARTING,
19744
19944
  payload: { framework: detection.framework, port: detection.port }
19745
19945
  });
19746
19946
  emitProgress("ENV_DETECTED", `${detection.framework}`);
@@ -19767,7 +19967,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19767
19967
  sessionId: ctx.sessionId,
19768
19968
  pluginId: ctx.pluginId,
19769
19969
  pluginAuthToken,
19770
- type: "preview_error",
19970
+ type: USER_EVENTS.PREVIEW_ERROR,
19771
19971
  payload: {
19772
19972
  stage: "spawn",
19773
19973
  message: `This project uses yarn but yarn isn't installed, and installing it automatically failed (npm install -g yarn, exit ${ensured.code}). Install yarn in this environment and try the preview again.`
@@ -19792,7 +19992,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19792
19992
  sessionId: ctx.sessionId,
19793
19993
  pluginId: ctx.pluginId,
19794
19994
  pluginAuthToken,
19795
- type: "preview_error",
19995
+ type: USER_EVENTS.PREVIEW_ERROR,
19796
19996
  payload: {
19797
19997
  stage: "ready_timeout",
19798
19998
  message: `Dependency install (${missingDeps.cmd} ${missingDeps.args.join(" ")}) didn't finish within ${Math.round(INSTALL_TIMEOUT_MS / 1e3)}s and was stopped. Run it manually in this project, then try the preview again.`
@@ -19805,7 +20005,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19805
20005
  sessionId: ctx.sessionId,
19806
20006
  pluginId: ctx.pluginId,
19807
20007
  pluginAuthToken,
19808
- type: "preview_error",
20008
+ type: USER_EVENTS.PREVIEW_ERROR,
19809
20009
  payload: {
19810
20010
  stage: "spawn",
19811
20011
  message: `Dependency install failed (${missingDeps.cmd} ${missingDeps.args.join(" ")}, exit ${result.code}). Run it manually in this project and try again.`
@@ -19842,7 +20042,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19842
20042
  sessionId: ctx.sessionId,
19843
20043
  pluginId: ctx.pluginId,
19844
20044
  pluginAuthToken,
19845
- type: "preview_error",
20045
+ type: USER_EVENTS.PREVIEW_ERROR,
19846
20046
  payload: {
19847
20047
  stage: "ready_timeout",
19848
20048
  message: `Setup step (${setup.cmd} ${setup.args.join(" ")}) didn't finish within ${Math.round(timeoutMs / 1e3)}s and was stopped.`
@@ -19855,7 +20055,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19855
20055
  sessionId: ctx.sessionId,
19856
20056
  pluginId: ctx.pluginId,
19857
20057
  pluginAuthToken,
19858
- type: "preview_error",
20058
+ type: USER_EVENTS.PREVIEW_ERROR,
19859
20059
  payload: {
19860
20060
  stage: "spawn",
19861
20061
  message: `Setup failed (${setup.cmd} ${setup.args.join(" ")}, exit ${result.code}).`
@@ -19876,7 +20076,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19876
20076
  sessionId: ctx.sessionId,
19877
20077
  pluginId: ctx.pluginId,
19878
20078
  pluginAuthToken,
19879
- type: "preview_ready",
20079
+ type: USER_EVENTS.PREVIEW_READY,
19880
20080
  payload: { url: raceExisting.url, framework: raceExisting.framework, port: detection.port }
19881
20081
  });
19882
20082
  return;
@@ -19896,7 +20096,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19896
20096
  sessionId: ctx.sessionId,
19897
20097
  pluginId: ctx.pluginId,
19898
20098
  pluginAuthToken,
19899
- type: "preview_error",
20099
+ type: USER_EVENTS.PREVIEW_ERROR,
19900
20100
  payload: {
19901
20101
  stage: "spawn",
19902
20102
  message: `Port ${detection.port} is still in use after stopping the previous preview. Wait a moment and try again.`
@@ -19909,7 +20109,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19909
20109
  sessionId: ctx.sessionId,
19910
20110
  pluginId: ctx.pluginId,
19911
20111
  pluginAuthToken,
19912
- type: "preview_error",
20112
+ type: USER_EVENTS.PREVIEW_ERROR,
19913
20113
  payload: {
19914
20114
  stage: "spawn",
19915
20115
  message: `Port ${detection.port} is already in use by another process, so the dev server can't start there. Stop whatever is listening on port ${detection.port} and try the preview again.`
@@ -19957,7 +20157,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19957
20157
  sessionId: ctx.sessionId,
19958
20158
  pluginId: ctx.pluginId,
19959
20159
  pluginAuthToken,
19960
- type: "preview_error",
20160
+ type: USER_EVENTS.PREVIEW_ERROR,
19961
20161
  payload: {
19962
20162
  stage: "spawn",
19963
20163
  message: `The dev server exited (code ${outcome.code}) before it was ready. It may need a database or other services.`,
@@ -19972,7 +20172,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
19972
20172
  sessionId: ctx.sessionId,
19973
20173
  pluginId: ctx.pluginId,
19974
20174
  pluginAuthToken,
19975
- type: "preview_error",
20175
+ type: USER_EVENTS.PREVIEW_ERROR,
19976
20176
  payload: {
19977
20177
  stage: "ready_timeout",
19978
20178
  message: "The dev server didn't become ready in time. It may be stuck waiting on a database or other service.",
@@ -20001,7 +20201,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
20001
20201
  sessionId: ctx.sessionId,
20002
20202
  pluginId: ctx.pluginId,
20003
20203
  pluginAuthToken,
20004
- type: "preview_error",
20204
+ type: USER_EVENTS.PREVIEW_ERROR,
20005
20205
  payload: { stage: "tunnel", message: "Expo did not report a tunnel URL." }
20006
20206
  });
20007
20207
  return;
@@ -20017,7 +20217,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
20017
20217
  sessionId: ctx.sessionId,
20018
20218
  pluginId: ctx.pluginId,
20019
20219
  pluginAuthToken,
20020
- type: "preview_error",
20220
+ type: USER_EVENTS.PREVIEW_ERROR,
20021
20221
  payload: { stage: "tunnel", message: e.message }
20022
20222
  });
20023
20223
  return;
@@ -20111,7 +20311,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
20111
20311
  sessionId: ctx.sessionId,
20112
20312
  pluginId: ctx.pluginId,
20113
20313
  pluginAuthToken,
20114
- type: "preview_error",
20314
+ type: USER_EVENTS.PREVIEW_ERROR,
20115
20315
  payload: {
20116
20316
  stage: "tunnel",
20117
20317
  message: `Tunnel did not become reachable after ${MAX_TUNNEL_ATTEMPTS} attempts (${lastTunnelErr}). Cloudflare Quick Tunnels occasionally fail to register \u2014 please retry.`
@@ -20135,7 +20335,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
20135
20335
  sessionId: ctx.sessionId,
20136
20336
  pluginId: ctx.pluginId,
20137
20337
  pluginAuthToken,
20138
- type: "preview_ready",
20338
+ type: USER_EVENTS.PREVIEW_READY,
20139
20339
  payload: { url, framework: detection.framework, port: detection.port }
20140
20340
  });
20141
20341
  })().catch((err) => {
@@ -20145,7 +20345,7 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
20145
20345
  sessionId: ctx.sessionId,
20146
20346
  pluginId: ctx.pluginId,
20147
20347
  pluginAuthToken,
20148
- type: "preview_error",
20348
+ type: USER_EVENTS.PREVIEW_ERROR,
20149
20349
  payload: { stage: "spawn", message: `Preview failed to start: ${message}` }
20150
20350
  });
20151
20351
  });
@@ -20163,7 +20363,7 @@ var previewStopH = (ctx) => {
20163
20363
  sessionId: ctx.sessionId,
20164
20364
  pluginId: ctx.pluginId,
20165
20365
  pluginAuthToken,
20166
- type: "preview_stopped",
20366
+ type: USER_EVENTS.PREVIEW_STOPPED,
20167
20367
  payload: { reason: "user" }
20168
20368
  });
20169
20369
  })();
@@ -20507,12 +20707,12 @@ function readTokenFromArgs(args2) {
20507
20707
  }
20508
20708
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
20509
20709
  if (fileFlag) {
20510
- const path64 = fileFlag.slice("--token-file=".length);
20710
+ const path65 = fileFlag.slice("--token-file=".length);
20511
20711
  try {
20512
- const content = fs45.readFileSync(path64, "utf8").trim();
20513
- if (content.length === 0) fail(`--token-file ${path64} is empty`);
20712
+ const content = fs46.readFileSync(path65, "utf8").trim();
20713
+ if (content.length === 0) fail(`--token-file ${path65} is empty`);
20514
20714
  try {
20515
- fs45.unlinkSync(path64);
20715
+ fs46.unlinkSync(path65);
20516
20716
  } catch {
20517
20717
  }
20518
20718
  return content;
@@ -20538,7 +20738,7 @@ async function claimOnce(token, pluginId, pluginSecretHash) {
20538
20738
  pluginId,
20539
20739
  ideName: "codeam-cli (codespace)",
20540
20740
  ideVersion: process.env.npm_package_version ?? "unknown",
20541
- hostname: os38.hostname(),
20741
+ hostname: os39.hostname(),
20542
20742
  codespaceName: process.env.CODESPACE_NAME ?? "",
20543
20743
  // Current git branch of the codespace's working directory, so the
20544
20744
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -20599,7 +20799,7 @@ async function claim(token, pluginId, pluginSecretHash) {
20599
20799
  }
20600
20800
  }
20601
20801
  function pairAutoLockPath() {
20602
- return path50.join(os38.homedir(), ".codeam", "pair-auto.lock");
20802
+ return path51.join(os39.homedir(), ".codeam", "pair-auto.lock");
20603
20803
  }
20604
20804
  function isLivePairAuto(pid) {
20605
20805
  if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
@@ -20609,7 +20809,7 @@ function isLivePairAuto(pid) {
20609
20809
  if (e.code !== "EPERM") return false;
20610
20810
  }
20611
20811
  try {
20612
- return fs45.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
20812
+ return fs46.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
20613
20813
  } catch {
20614
20814
  return true;
20615
20815
  }
@@ -20619,24 +20819,24 @@ function isLiveCodeam(pid) {
20619
20819
  }
20620
20820
  function daemonLockPath(sessionId) {
20621
20821
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
20622
- return path50.join(os38.homedir(), ".codeam", `daemon-${safe}.lock`);
20822
+ return path51.join(os39.homedir(), ".codeam", `daemon-${safe}.lock`);
20623
20823
  }
20624
20824
  function acquireDaemonLock(sessionId) {
20625
20825
  const lockPath = daemonLockPath(sessionId);
20626
20826
  try {
20627
- fs45.mkdirSync(path50.dirname(lockPath), { recursive: true });
20827
+ fs46.mkdirSync(path51.dirname(lockPath), { recursive: true });
20628
20828
  try {
20629
- fs45.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
20829
+ fs46.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
20630
20830
  } catch (e) {
20631
20831
  if (e.code !== "EEXIST") throw e;
20632
- const holder = Number(fs45.readFileSync(lockPath, "utf8").trim());
20832
+ const holder = Number(fs46.readFileSync(lockPath, "utf8").trim());
20633
20833
  if (holder && holder !== process.pid && isLiveCodeam(holder)) return false;
20634
- fs45.writeFileSync(lockPath, String(process.pid));
20834
+ fs46.writeFileSync(lockPath, String(process.pid));
20635
20835
  }
20636
20836
  const release3 = () => {
20637
20837
  try {
20638
- if (fs45.existsSync(lockPath) && Number(fs45.readFileSync(lockPath, "utf8").trim()) === process.pid) {
20639
- fs45.unlinkSync(lockPath);
20838
+ if (fs46.existsSync(lockPath) && Number(fs46.readFileSync(lockPath, "utf8").trim()) === process.pid) {
20839
+ fs46.unlinkSync(lockPath);
20640
20840
  }
20641
20841
  } catch {
20642
20842
  }
@@ -20658,19 +20858,19 @@ function acquireDaemonLock(sessionId) {
20658
20858
  function acquireSingletonLock() {
20659
20859
  const lockPath = pairAutoLockPath();
20660
20860
  try {
20661
- fs45.mkdirSync(path50.dirname(lockPath), { recursive: true });
20861
+ fs46.mkdirSync(path51.dirname(lockPath), { recursive: true });
20662
20862
  try {
20663
- fs45.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
20863
+ fs46.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
20664
20864
  } catch (e) {
20665
20865
  if (e.code !== "EEXIST") throw e;
20666
- const holder = Number(fs45.readFileSync(lockPath, "utf8").trim());
20866
+ const holder = Number(fs46.readFileSync(lockPath, "utf8").trim());
20667
20867
  if (isLivePairAuto(holder)) return false;
20668
- fs45.writeFileSync(lockPath, String(process.pid));
20868
+ fs46.writeFileSync(lockPath, String(process.pid));
20669
20869
  }
20670
20870
  process.once("exit", () => {
20671
20871
  try {
20672
- if (fs45.existsSync(lockPath) && Number(fs45.readFileSync(lockPath, "utf8").trim()) === process.pid) {
20673
- fs45.unlinkSync(lockPath);
20872
+ if (fs46.existsSync(lockPath) && Number(fs46.readFileSync(lockPath, "utf8").trim()) === process.pid) {
20873
+ fs46.unlinkSync(lockPath);
20674
20874
  }
20675
20875
  } catch {
20676
20876
  }
@@ -20752,7 +20952,7 @@ async function pairAuto(args2) {
20752
20952
  }
20753
20953
 
20754
20954
  // src/services/headroom/wrap-launch.ts
20755
- var import_node_child_process16 = require("child_process");
20955
+ var import_node_child_process17 = require("child_process");
20756
20956
  function wrapWithHeadroom(launch, opts) {
20757
20957
  if (!opts.enabled || !opts.headroomPresent) return launch;
20758
20958
  return {
@@ -20765,7 +20965,7 @@ var _present;
20765
20965
  function headroomPresent() {
20766
20966
  if (_present !== void 0) return Promise.resolve(_present);
20767
20967
  return new Promise((resolve7) => {
20768
- (0, import_node_child_process16.execFile)("headroom", ["--version"], (err) => {
20968
+ (0, import_node_child_process17.execFile)("headroom", ["--version"], (err) => {
20769
20969
  _present = !err;
20770
20970
  resolve7(_present);
20771
20971
  });
@@ -21115,7 +21315,7 @@ var AgentService = class _AgentService {
21115
21315
  };
21116
21316
 
21117
21317
  // src/agents/acp/adapters.ts
21118
- var path52 = __toESM(require("path"));
21318
+ var path53 = __toESM(require("path"));
21119
21319
 
21120
21320
  // src/agents/acp/agent-binary.ts
21121
21321
  var import_fs4 = __toESM(require("fs"));
@@ -21268,13 +21468,13 @@ function resolveBin(pkgName, binName) {
21268
21468
  try {
21269
21469
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
21270
21470
  const manifest = require_(`${pkgName}/package.json`);
21271
- const pkgDir = path52.dirname(manifestPath);
21471
+ const pkgDir = path53.dirname(manifestPath);
21272
21472
  const bin = manifest.bin;
21273
21473
  if (!bin) return null;
21274
- if (typeof bin === "string") return path52.resolve(pkgDir, bin);
21474
+ if (typeof bin === "string") return path53.resolve(pkgDir, bin);
21275
21475
  const target = binName ?? Object.keys(bin)[0];
21276
21476
  if (!target || !bin[target]) return null;
21277
- return path52.resolve(pkgDir, bin[target]);
21477
+ return path53.resolve(pkgDir, bin[target]);
21278
21478
  } catch {
21279
21479
  return null;
21280
21480
  }
@@ -21349,20 +21549,20 @@ function requiresAcp(agent) {
21349
21549
  var import_node_crypto7 = require("crypto");
21350
21550
 
21351
21551
  // src/services/history.service.ts
21352
- var fs47 = __toESM(require("fs"));
21353
- var path53 = __toESM(require("path"));
21354
- var os39 = __toESM(require("os"));
21552
+ var fs48 = __toESM(require("fs"));
21553
+ var path54 = __toESM(require("path"));
21554
+ var os40 = __toESM(require("os"));
21355
21555
  var https7 = __toESM(require("https"));
21356
21556
  var http6 = __toESM(require("http"));
21357
- var import_zod2 = require("zod");
21358
- var historyRecordSchema = import_zod2.z.object({
21359
- type: import_zod2.z.string().optional(),
21360
- timestamp: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.number()]).optional(),
21361
- uuid: import_zod2.z.string().optional(),
21362
- isMeta: import_zod2.z.boolean().optional(),
21363
- message: import_zod2.z.object({
21557
+ var import_zod3 = require("zod");
21558
+ var historyRecordSchema = import_zod3.z.object({
21559
+ type: import_zod3.z.string().optional(),
21560
+ timestamp: import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number()]).optional(),
21561
+ uuid: import_zod3.z.string().optional(),
21562
+ isMeta: import_zod3.z.boolean().optional(),
21563
+ message: import_zod3.z.object({
21364
21564
  // Claude content is either a string or an array of typed blocks.
21365
- content: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.unknown())]).optional()
21565
+ content: import_zod3.z.union([import_zod3.z.string(), import_zod3.z.array(import_zod3.z.unknown())]).optional()
21366
21566
  }).passthrough().optional()
21367
21567
  }).passthrough();
21368
21568
  var API_BASE8 = resolveApiBaseUrl();
@@ -21378,7 +21578,7 @@ function parseJsonl(filePath) {
21378
21578
  const messages = [];
21379
21579
  let raw;
21380
21580
  try {
21381
- raw = fs47.readFileSync(filePath, "utf8");
21581
+ raw = fs48.readFileSync(filePath, "utf8");
21382
21582
  } catch (err) {
21383
21583
  if (err.code !== "ENOENT") {
21384
21584
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -21519,7 +21719,7 @@ var HistoryService = class _HistoryService {
21519
21719
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
21520
21720
  }
21521
21721
  get projectDir() {
21522
- return this.runtime.resolveHistoryDir(this.cwd) ?? path53.join(os39.homedir(), ".claude", "projects", encodeCwd(this.cwd));
21722
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path54.join(os40.homedir(), ".claude", "projects", encodeCwd(this.cwd));
21523
21723
  }
21524
21724
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
21525
21725
  setCurrentConversationId(id) {
@@ -21531,7 +21731,7 @@ var HistoryService = class _HistoryService {
21531
21731
  /** Return the current message count in the active conversation. */
21532
21732
  getCurrentMessageCount() {
21533
21733
  if (!this.currentConversationId) return 0;
21534
- const filePath = path53.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21734
+ const filePath = path54.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21535
21735
  return parseJsonl(filePath).length;
21536
21736
  }
21537
21737
  /**
@@ -21542,7 +21742,7 @@ var HistoryService = class _HistoryService {
21542
21742
  const deadline = Date.now() + timeoutMs;
21543
21743
  while (Date.now() < deadline) {
21544
21744
  if (!this.currentConversationId) return null;
21545
- const filePath = path53.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21745
+ const filePath = path54.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21546
21746
  const messages = parseJsonl(filePath);
21547
21747
  if (messages.length > previousCount) {
21548
21748
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -21568,16 +21768,16 @@ var HistoryService = class _HistoryService {
21568
21768
  const dir = this.projectDir;
21569
21769
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
21570
21770
  try {
21571
- const files = fs47.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
21771
+ const files = fs48.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
21572
21772
  try {
21573
- const stat3 = fs47.statSync(path53.join(dir, e.name));
21773
+ const stat3 = fs48.statSync(path54.join(dir, e.name));
21574
21774
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
21575
21775
  } catch {
21576
21776
  return { name: e.name, mtime: 0, birthtime: 0 };
21577
21777
  }
21578
21778
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
21579
21779
  if (files.length > 0) {
21580
- this.currentConversationId = path53.basename(files[0].name, ".jsonl");
21780
+ this.currentConversationId = path54.basename(files[0].name, ".jsonl");
21581
21781
  }
21582
21782
  } catch {
21583
21783
  }
@@ -21611,13 +21811,13 @@ var HistoryService = class _HistoryService {
21611
21811
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
21612
21812
  let entries;
21613
21813
  try {
21614
- entries = fs47.readdirSync(dir, { withFileTypes: true });
21814
+ entries = fs48.readdirSync(dir, { withFileTypes: true });
21615
21815
  } catch {
21616
21816
  return null;
21617
21817
  }
21618
21818
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
21619
21819
  try {
21620
- const stat3 = fs47.statSync(path53.join(dir, e.name));
21820
+ const stat3 = fs48.statSync(path54.join(dir, e.name));
21621
21821
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
21622
21822
  } catch {
21623
21823
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -21626,12 +21826,12 @@ var HistoryService = class _HistoryService {
21626
21826
  if (files.length === 0) return null;
21627
21827
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
21628
21828
  if (!files.some((f) => f.name === targetFile)) return null;
21629
- return this.extractUsageFromFile(path53.join(dir, targetFile));
21829
+ return this.extractUsageFromFile(path54.join(dir, targetFile));
21630
21830
  }
21631
21831
  extractUsageFromFile(filePath) {
21632
21832
  let raw;
21633
21833
  try {
21634
- raw = fs47.readFileSync(filePath, "utf8");
21834
+ raw = fs48.readFileSync(filePath, "utf8");
21635
21835
  } catch {
21636
21836
  return null;
21637
21837
  }
@@ -21676,9 +21876,9 @@ var HistoryService = class _HistoryService {
21676
21876
  let totalCost = 0;
21677
21877
  let files;
21678
21878
  try {
21679
- files = fs47.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
21879
+ files = fs48.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
21680
21880
  try {
21681
- return fs47.statSync(path53.join(projectDir, f)).mtimeMs >= monthStartMs;
21881
+ return fs48.statSync(path54.join(projectDir, f)).mtimeMs >= monthStartMs;
21682
21882
  } catch {
21683
21883
  return false;
21684
21884
  }
@@ -21689,7 +21889,7 @@ var HistoryService = class _HistoryService {
21689
21889
  for (const file of files) {
21690
21890
  let raw;
21691
21891
  try {
21692
- raw = fs47.readFileSync(path53.join(projectDir, file), "utf8");
21892
+ raw = fs48.readFileSync(path54.join(projectDir, file), "utf8");
21693
21893
  } catch {
21694
21894
  continue;
21695
21895
  }
@@ -21768,7 +21968,7 @@ var HistoryService = class _HistoryService {
21768
21968
  if (this.runtime.resolveHistoryFile) {
21769
21969
  return this.runtime.resolveHistoryFile(this.cwd, sessionId);
21770
21970
  }
21771
- return path53.join(this.projectDir, `${sessionId}.jsonl`);
21971
+ return path54.join(this.projectDir, `${sessionId}.jsonl`);
21772
21972
  }
21773
21973
  /**
21774
21974
  * Parse a conversation's messages from disk, agent-aware. Claude uses the
@@ -21802,7 +22002,7 @@ var HistoryService = class _HistoryService {
21802
22002
  };
21803
22003
  });
21804
22004
  }
21805
- return parseJsonl(path53.join(this.projectDir, `${sessionId}.jsonl`));
22005
+ return parseJsonl(path54.join(this.projectDir, `${sessionId}.jsonl`));
21806
22006
  }
21807
22007
  async loadConversation(sessionId) {
21808
22008
  const messages = this.readConversation(sessionId);
@@ -21858,7 +22058,7 @@ var HistoryService = class _HistoryService {
21858
22058
  if (!filePath) return false;
21859
22059
  let mtimeMs;
21860
22060
  try {
21861
- mtimeMs = fs47.statSync(filePath).mtimeMs;
22061
+ mtimeMs = fs48.statSync(filePath).mtimeMs;
21862
22062
  } catch {
21863
22063
  return false;
21864
22064
  }
@@ -21926,11 +22126,11 @@ var HistoryService = class _HistoryService {
21926
22126
  };
21927
22127
 
21928
22128
  // src/agents/acp/client.ts
21929
- var import_node_child_process17 = require("child_process");
21930
- var fs48 = __toESM(require("fs/promises"));
22129
+ var import_node_child_process18 = require("child_process");
22130
+ var fs49 = __toESM(require("fs/promises"));
21931
22131
  var fsSync = __toESM(require("fs"));
21932
- var os40 = __toESM(require("os"));
21933
- var path54 = __toESM(require("path"));
22132
+ var os41 = __toESM(require("os"));
22133
+ var path55 = __toESM(require("path"));
21934
22134
  var import_node_stream = require("stream");
21935
22135
 
21936
22136
  // ../../node_modules/@agentclientprotocol/sdk/dist/acp.js
@@ -24477,7 +24677,7 @@ var AcpClient = class {
24477
24677
  "acpClient",
24478
24678
  `spawn cmd=${adapter.command} args=[${adapter.args.join(",")}] cwd=${cwd}`
24479
24679
  );
24480
- const child = (0, import_node_child_process17.spawn)(adapter.command, adapter.args, {
24680
+ const child = (0, import_node_child_process18.spawn)(adapter.command, adapter.args, {
24481
24681
  cwd,
24482
24682
  // extraEnv (e.g. CLAUDE_CODE_DISABLE_1M_CONTEXT=1 on an on-demand
24483
24683
  // re-spawn) layers over process.env; PATH stays last so the augmented
@@ -24763,7 +24963,7 @@ var AcpClient = class {
24763
24963
  },
24764
24964
  readTextFile: async (params) => {
24765
24965
  try {
24766
- const content = await fs48.readFile(params.path, "utf8");
24966
+ const content = await fs49.readFile(params.path, "utf8");
24767
24967
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
24768
24968
  } catch (err) {
24769
24969
  const code = err.code;
@@ -24783,7 +24983,7 @@ var AcpClient = class {
24783
24983
  },
24784
24984
  writeTextFile: async (params) => {
24785
24985
  try {
24786
- await fs48.writeFile(params.path, params.content, "utf8");
24986
+ await fs49.writeFile(params.path, params.content, "utf8");
24787
24987
  return {};
24788
24988
  } catch (err) {
24789
24989
  const code = err.code;
@@ -24832,25 +25032,25 @@ function applyLineRange(content, line, limit) {
24832
25032
  return { content: lines.slice(start2, end).join("\n") };
24833
25033
  }
24834
25034
  function knownAgentBinaryDirs() {
24835
- const home = os40.homedir();
25035
+ const home = os41.homedir();
24836
25036
  const out2 = [];
24837
25037
  out2.push("/tmp/codeam-node20/bin");
24838
25038
  for (const root of [
24839
25039
  "/usr/local/share/nvm/versions/node",
24840
- path54.join(home, ".nvm/versions/node")
25040
+ path55.join(home, ".nvm/versions/node")
24841
25041
  ]) {
24842
25042
  try {
24843
25043
  for (const child of fsSync.readdirSync(root)) {
24844
- out2.push(path54.join(root, child, "bin"));
25044
+ out2.push(path55.join(root, child, "bin"));
24845
25045
  }
24846
25046
  } catch {
24847
25047
  }
24848
25048
  }
24849
- out2.push(path54.join(home, ".volta/bin"));
25049
+ out2.push(path55.join(home, ".volta/bin"));
24850
25050
  out2.push("/usr/local/bin");
24851
25051
  out2.push("/usr/bin");
24852
- out2.push(path54.join(home, ".local/bin"));
24853
- out2.push(path54.join(home, "bin"));
25052
+ out2.push(path55.join(home, ".local/bin"));
25053
+ out2.push(path55.join(home, "bin"));
24854
25054
  return out2.filter((p2) => {
24855
25055
  try {
24856
25056
  return fsSync.statSync(p2).isDirectory();
@@ -24861,7 +25061,7 @@ function knownAgentBinaryDirs() {
24861
25061
  }
24862
25062
  function expandPathForAgentBinaries(existingPath) {
24863
25063
  const existing = new Set(
24864
- existingPath.split(path54.delimiter).filter((p2) => p2.length > 0)
25064
+ existingPath.split(path55.delimiter).filter((p2) => p2.length > 0)
24865
25065
  );
24866
25066
  const additions = [];
24867
25067
  for (const dir of knownAgentBinaryDirs()) {
@@ -24871,7 +25071,7 @@ function expandPathForAgentBinaries(existingPath) {
24871
25071
  }
24872
25072
  }
24873
25073
  if (additions.length === 0) return existingPath;
24874
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path54.delimiter);
25074
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path55.delimiter);
24875
25075
  }
24876
25076
 
24877
25077
  // src/services/streaming/transport.ts
@@ -25416,15 +25616,15 @@ function commonPrefixLength(a, b) {
25416
25616
 
25417
25617
  // src/agents/acp/onboarding.ts
25418
25618
  var import_child_process25 = require("child_process");
25419
- var fs49 = __toESM(require("fs"));
25420
- var os41 = __toESM(require("os"));
25421
- var path55 = __toESM(require("path"));
25619
+ var fs50 = __toESM(require("fs"));
25620
+ var os42 = __toESM(require("os"));
25621
+ var path56 = __toESM(require("path"));
25422
25622
  var _onboardingSeam = {
25423
- markerPath: (sessionId) => path55.join(os41.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
25424
- exists: (p2) => fs49.existsSync(p2),
25623
+ markerPath: (sessionId) => path56.join(os42.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
25624
+ exists: (p2) => fs50.existsSync(p2),
25425
25625
  write: (p2) => {
25426
- fs49.mkdirSync(path55.dirname(p2), { recursive: true });
25427
- fs49.writeFileSync(p2, "");
25626
+ fs50.mkdirSync(path56.dirname(p2), { recursive: true });
25627
+ fs50.writeFileSync(p2, "");
25428
25628
  },
25429
25629
  disabled: () => {
25430
25630
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -25461,7 +25661,7 @@ function resolveRepoName(cwd) {
25461
25661
  if (name) return name;
25462
25662
  }
25463
25663
  }
25464
- const base = path55.basename(cwd || "");
25664
+ const base = path56.basename(cwd || "");
25465
25665
  if (base && !isUuid(base)) return base;
25466
25666
  return "this project";
25467
25667
  }
@@ -25739,8 +25939,8 @@ var import_crypto5 = require("crypto");
25739
25939
 
25740
25940
  // src/services/turn-files/git-changeset.ts
25741
25941
  var import_child_process26 = require("child_process");
25742
- var fs50 = __toESM(require("fs/promises"));
25743
- var path56 = __toESM(require("path"));
25942
+ var fs51 = __toESM(require("fs/promises"));
25943
+ var path57 = __toESM(require("path"));
25744
25944
  async function collectRepoChangeset(opts) {
25745
25945
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
25746
25946
  if (status2 === null) return null;
@@ -25758,7 +25958,7 @@ async function collectRepoChangeset(opts) {
25758
25958
  let stats;
25759
25959
  if (row.fileStatus === "added" && numstatEntry === void 0) {
25760
25960
  const lineCount = await readUntrackedLineCount(
25761
- path56.join(opts.repoRoot, row.filePath)
25961
+ path57.join(opts.repoRoot, row.filePath)
25762
25962
  );
25763
25963
  stats = { added: lineCount, removed: 0 };
25764
25964
  } else {
@@ -25789,7 +25989,7 @@ function readUntrackedLineCount(absPath) {
25789
25989
  }
25790
25990
  async function defaultReadUntrackedLineCount(absPath) {
25791
25991
  try {
25792
- const content = await fs50.readFile(absPath, "utf8");
25992
+ const content = await fs51.readFile(absPath, "utf8");
25793
25993
  let count = 0;
25794
25994
  let pos = -1;
25795
25995
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -25881,7 +26081,7 @@ function defaultRunGit(cwd, args2) {
25881
26081
  });
25882
26082
  }
25883
26083
  async function discoverRepos(workingDir, maxDepth = 4) {
25884
- const fs54 = await import("fs/promises");
26084
+ const fs55 = await import("fs/promises");
25885
26085
  const out2 = [];
25886
26086
  await walk(workingDir, 0);
25887
26087
  return out2;
@@ -25889,7 +26089,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
25889
26089
  if (depth > maxDepth) return;
25890
26090
  let entries = [];
25891
26091
  try {
25892
- const dirents = await fs54.readdir(dir, { withFileTypes: true });
26092
+ const dirents = await fs55.readdir(dir, { withFileTypes: true });
25893
26093
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
25894
26094
  } catch {
25895
26095
  return;
@@ -25900,8 +26100,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
25900
26100
  if (hasGit) {
25901
26101
  out2.push({
25902
26102
  repoRoot: dir,
25903
- repoPath: path56.relative(workingDir, dir),
25904
- repoName: path56.basename(dir)
26103
+ repoPath: path57.relative(workingDir, dir),
26104
+ repoName: path57.basename(dir)
25905
26105
  });
25906
26106
  return;
25907
26107
  }
@@ -25909,14 +26109,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
25909
26109
  if (!entry.isDirectory) continue;
25910
26110
  if (entry.name === "node_modules") continue;
25911
26111
  if (entry.name === "dist" || entry.name === "build") continue;
25912
- await walk(path56.join(dir, entry.name), depth + 1);
26112
+ await walk(path57.join(dir, entry.name), depth + 1);
25913
26113
  }
25914
26114
  }
25915
26115
  }
25916
26116
 
25917
26117
  // src/services/turn-files/files-outbox.ts
25918
- var fs51 = __toESM(require("fs/promises"));
25919
- var path57 = __toESM(require("path"));
26118
+ var fs52 = __toESM(require("fs/promises"));
26119
+ var path58 = __toESM(require("path"));
25920
26120
  var import_os7 = require("os");
25921
26121
  var HOME_OUTBOX_DIR = ".codeam/outbox";
25922
26122
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -25949,16 +26149,16 @@ var FilesOutbox = class {
25949
26149
  backoffIndex = 0;
25950
26150
  stopped = false;
25951
26151
  constructor(opts) {
25952
- const base = opts.baseDir ?? path57.join(homeDir(), HOME_OUTBOX_DIR);
25953
- this.filePath = path57.join(base, `${opts.sessionId}.jsonl`);
26152
+ const base = opts.baseDir ?? path58.join(homeDir(), HOME_OUTBOX_DIR);
26153
+ this.filePath = path58.join(base, `${opts.sessionId}.jsonl`);
25954
26154
  this.post = opts.post;
25955
26155
  this.autoSchedule = opts.autoSchedule !== false;
25956
26156
  }
25957
26157
  /** Persist the entry to disk and trigger a flush. Returns once the
25958
26158
  * line is durable on disk (not once the POST succeeds). */
25959
26159
  async enqueue(entry) {
25960
- await fs51.mkdir(path57.dirname(this.filePath), { recursive: true });
25961
- await fs51.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
26160
+ await fs52.mkdir(path58.dirname(this.filePath), { recursive: true });
26161
+ await fs52.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
25962
26162
  this.backoffIndex = 0;
25963
26163
  if (this.autoSchedule) this.scheduleFlush(0);
25964
26164
  }
@@ -26047,7 +26247,7 @@ var FilesOutbox = class {
26047
26247
  async readAll() {
26048
26248
  let raw = "";
26049
26249
  try {
26050
- raw = await fs51.readFile(this.filePath, "utf8");
26250
+ raw = await fs52.readFile(this.filePath, "utf8");
26051
26251
  } catch {
26052
26252
  return [];
26053
26253
  }
@@ -26071,12 +26271,12 @@ var FilesOutbox = class {
26071
26271
  async rewrite(entries) {
26072
26272
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
26073
26273
  if (entries.length === 0) {
26074
- await fs51.unlink(this.filePath).catch(() => void 0);
26274
+ await fs52.unlink(this.filePath).catch(() => void 0);
26075
26275
  return;
26076
26276
  }
26077
26277
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
26078
- await fs51.writeFile(tmpPath, payload, "utf8");
26079
- await fs51.rename(tmpPath, this.filePath);
26278
+ await fs52.writeFile(tmpPath, payload, "utf8");
26279
+ await fs52.rename(tmpPath, this.filePath);
26080
26280
  }
26081
26281
  };
26082
26282
  function applyJitter(ms) {
@@ -27066,21 +27266,12 @@ async function runAcpSession(opts) {
27066
27266
  });
27067
27267
  let _budgetReachedPosted = false;
27068
27268
  const relaunchProxyWithoutBudget = async () => {
27069
- const { spawn: spawn35 } = await import("child_process");
27070
- try {
27071
- const killer = spawn35("pkill", ["-TERM", "-f", "headroom.*proxy"], {
27072
- detached: true,
27073
- stdio: "ignore"
27074
- });
27075
- killer.once("error", () => {
27076
- });
27077
- killer.unref();
27078
- } catch {
27079
- }
27269
+ const { spawn: spawn36 } = await import("child_process");
27270
+ killHeadroomProxy();
27080
27271
  await new Promise((r) => setTimeout(r, 500));
27081
27272
  const proxyEnv = buildRelaunchProxyEnv(process.env);
27082
27273
  try {
27083
- const proxy = spawn35(
27274
+ const proxy = spawn36(
27084
27275
  "headroom",
27085
27276
  ["proxy", "--port", "8787"],
27086
27277
  { stdio: "ignore", detached: true, env: proxyEnv }
@@ -27089,6 +27280,7 @@ async function runAcpSession(opts) {
27089
27280
  log.warn("acpRunner", `budget recovery proxy relaunch error (best-effort): ${e.message}`);
27090
27281
  });
27091
27282
  proxy.unref();
27283
+ writeHeadroomProxyPidfile(proxy.pid);
27092
27284
  } catch (e) {
27093
27285
  log.warn(
27094
27286
  "acpRunner",
@@ -28733,15 +28925,15 @@ function fetchQuotaUsage(runtime, historySvc) {
28733
28925
  }
28734
28926
 
28735
28927
  // src/agents/claude/onboarding.ts
28736
- var fs52 = __toESM(require("fs"));
28737
- var os42 = __toESM(require("os"));
28738
- var path58 = __toESM(require("path"));
28928
+ var fs53 = __toESM(require("fs"));
28929
+ var os43 = __toESM(require("os"));
28930
+ var path59 = __toESM(require("path"));
28739
28931
  function ensureClaudeOnboarded() {
28740
28932
  try {
28741
- const file = path58.join(os42.homedir(), ".claude.json");
28933
+ const file = path59.join(os43.homedir(), ".claude.json");
28742
28934
  let config = {};
28743
28935
  try {
28744
- config = JSON.parse(fs52.readFileSync(file, "utf8"));
28936
+ config = JSON.parse(fs53.readFileSync(file, "utf8"));
28745
28937
  } catch {
28746
28938
  }
28747
28939
  if (config.hasCompletedOnboarding === true && typeof config.theme === "string") {
@@ -28752,8 +28944,8 @@ function ensureClaudeOnboarded() {
28752
28944
  if (typeof config.lastOnboardingVersion !== "string") {
28753
28945
  config.lastOnboardingVersion = "2.1.177";
28754
28946
  }
28755
- fs52.mkdirSync(path58.dirname(file), { recursive: true });
28756
- fs52.writeFileSync(file, JSON.stringify(config, null, 2));
28947
+ fs53.mkdirSync(path59.dirname(file), { recursive: true });
28948
+ fs53.writeFileSync(file, JSON.stringify(config, null, 2));
28757
28949
  log.info("claude", "pre-completed Claude onboarding (skip first-run theme picker)");
28758
28950
  } catch (err) {
28759
28951
  log.warn("claude", `ensureClaudeOnboarded failed (non-fatal): ${err.message}`);
@@ -29410,7 +29602,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
29410
29602
  var import_child_process27 = require("child_process");
29411
29603
  var import_util4 = require("util");
29412
29604
  var import_picocolors9 = __toESM(require("picocolors"));
29413
- var path59 = __toESM(require("path"));
29605
+ var path60 = __toESM(require("path"));
29414
29606
  var execFileP6 = (0, import_util4.promisify)(import_child_process27.execFile);
29415
29607
  var MAX_BUFFER = 8 * 1024 * 1024;
29416
29608
  function resetStdinForChild() {
@@ -29899,7 +30091,7 @@ var GitHubCodespacesProvider = class {
29899
30091
  });
29900
30092
  }
29901
30093
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
29902
- const remoteDir = path59.posix.dirname(remotePath);
30094
+ const remoteDir = path60.posix.dirname(remotePath);
29903
30095
  const parts = [
29904
30096
  `mkdir -p ${shellQuote(remoteDir)}`,
29905
30097
  `cat > ${shellQuote(remotePath)}`
@@ -29969,7 +30161,7 @@ function shellQuote(s) {
29969
30161
  // src/services/providers/gitpod.ts
29970
30162
  var import_child_process28 = require("child_process");
29971
30163
  var import_util5 = require("util");
29972
- var path60 = __toESM(require("path"));
30164
+ var path61 = __toESM(require("path"));
29973
30165
  var import_picocolors10 = __toESM(require("picocolors"));
29974
30166
  var execFileP7 = (0, import_util5.promisify)(import_child_process28.execFile);
29975
30167
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -30209,7 +30401,7 @@ var GitpodProvider = class {
30209
30401
  });
30210
30402
  }
30211
30403
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
30212
- const remoteDir = path60.posix.dirname(remotePath);
30404
+ const remoteDir = path61.posix.dirname(remotePath);
30213
30405
  const parts = [
30214
30406
  `mkdir -p ${shellQuote2(remoteDir)}`,
30215
30407
  `cat > ${shellQuote2(remotePath)}`
@@ -30245,7 +30437,7 @@ function shellQuote2(s) {
30245
30437
  // src/services/providers/gitlab-workspaces.ts
30246
30438
  var import_child_process29 = require("child_process");
30247
30439
  var import_util6 = require("util");
30248
- var path61 = __toESM(require("path"));
30440
+ var path62 = __toESM(require("path"));
30249
30441
  var execFileP8 = (0, import_util6.promisify)(import_child_process29.execFile);
30250
30442
  var MAX_BUFFER3 = 8 * 1024 * 1024;
30251
30443
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -30505,7 +30697,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
30505
30697
  }
30506
30698
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
30507
30699
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
30508
- const remoteDir = path61.posix.dirname(remotePath);
30700
+ const remoteDir = path62.posix.dirname(remotePath);
30509
30701
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
30510
30702
  if (options.mode != null) {
30511
30703
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -30573,7 +30765,7 @@ function shellQuote3(s) {
30573
30765
  // src/services/providers/railway.ts
30574
30766
  var import_child_process30 = require("child_process");
30575
30767
  var import_util7 = require("util");
30576
- var path62 = __toESM(require("path"));
30768
+ var path63 = __toESM(require("path"));
30577
30769
  var execFileP9 = (0, import_util7.promisify)(import_child_process30.execFile);
30578
30770
  var MAX_BUFFER4 = 8 * 1024 * 1024;
30579
30771
  function resetStdinForChild4() {
@@ -30809,7 +31001,7 @@ var RailwayProvider = class {
30809
31001
  if (!projectId || !serviceId) {
30810
31002
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
30811
31003
  }
30812
- const remoteDir = path62.posix.dirname(remotePath);
31004
+ const remoteDir = path63.posix.dirname(remotePath);
30813
31005
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
30814
31006
  if (options.mode != null) {
30815
31007
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -31455,8 +31647,8 @@ async function invite() {
31455
31647
  var import_node_dns = require("dns");
31456
31648
  var import_node_util5 = require("util");
31457
31649
  var import_node_crypto8 = require("crypto");
31458
- var fs53 = __toESM(require("fs"));
31459
- var path63 = __toESM(require("path"));
31650
+ var fs54 = __toESM(require("fs"));
31651
+ var path64 = __toESM(require("path"));
31460
31652
  var import_picocolors14 = __toESM(require("picocolors"));
31461
31653
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
31462
31654
  async function checkDns(apiBase2) {
@@ -31512,13 +31704,13 @@ async function checkHealth(apiBase2) {
31512
31704
  }
31513
31705
  }
31514
31706
  function checkConfigDir() {
31515
- const dir = path63.join(require("os").homedir(), ".codeam");
31707
+ const dir = path64.join(require("os").homedir(), ".codeam");
31516
31708
  try {
31517
- fs53.mkdirSync(dir, { recursive: true, mode: 448 });
31518
- const probe = path63.join(dir, ".doctor-probe");
31519
- fs53.writeFileSync(probe, "ok", { mode: 384 });
31520
- const read2 = fs53.readFileSync(probe, "utf8");
31521
- fs53.unlinkSync(probe);
31709
+ fs54.mkdirSync(dir, { recursive: true, mode: 448 });
31710
+ const probe = path64.join(dir, ".doctor-probe");
31711
+ fs54.writeFileSync(probe, "ok", { mode: 384 });
31712
+ const read2 = fs54.readFileSync(probe, "utf8");
31713
+ fs54.unlinkSync(probe);
31522
31714
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
31523
31715
  return {
31524
31716
  id: "config-dir",
@@ -31558,9 +31750,9 @@ function checkSessions() {
31558
31750
  }
31559
31751
  }
31560
31752
  function checkAgentBinaries() {
31561
- const os44 = createOsStrategy();
31753
+ const os45 = createOsStrategy();
31562
31754
  return getEnabledAgents().map((meta) => {
31563
- const found = os44.findInPath(meta.binaryName);
31755
+ const found = os45.findInPath(meta.binaryName);
31564
31756
  return {
31565
31757
  id: `agent-${meta.id}`,
31566
31758
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -31582,7 +31774,7 @@ function checkNodePty() {
31582
31774
  detail: "not required on this platform"
31583
31775
  };
31584
31776
  }
31585
- const vendoredPath = path63.join(__dirname, "vendor", "node-pty");
31777
+ const vendoredPath = path64.join(__dirname, "vendor", "node-pty");
31586
31778
  for (const target of [vendoredPath, "node-pty"]) {
31587
31779
  try {
31588
31780
  require(target);
@@ -31624,7 +31816,7 @@ function checkChokidar() {
31624
31816
  }
31625
31817
  async function doctor(args2 = []) {
31626
31818
  const json = args2.includes("--json");
31627
- const cliVersion = true ? "2.53.2" : "0.0.0-dev";
31819
+ const cliVersion = true ? "2.53.4" : "0.0.0-dev";
31628
31820
  const apiBase2 = resolveApiBaseUrl();
31629
31821
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
31630
31822
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -31823,7 +32015,7 @@ async function completion(args2) {
31823
32015
  // src/commands/version.ts
31824
32016
  var import_picocolors15 = __toESM(require("picocolors"));
31825
32017
  function version2() {
31826
- const v = true ? "2.53.2" : "unknown";
32018
+ const v = true ? "2.53.4" : "unknown";
31827
32019
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
31828
32020
  }
31829
32021
 
@@ -31972,10 +32164,10 @@ var EXIT_CODE_NAMES = {
31972
32164
  };
31973
32165
 
31974
32166
  // src/index.ts
31975
- var os43 = __toESM(require("os"));
32167
+ var os44 = __toESM(require("os"));
31976
32168
  if (!process.env.HOME) {
31977
32169
  try {
31978
- const home = os43.homedir();
32170
+ const home = os44.homedir();
31979
32171
  if (home) process.env.HOME = home;
31980
32172
  } catch {
31981
32173
  }