codeam-cli 2.52.5 → 2.52.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/index.js +253 -125
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ All notable changes to `codeam-cli` are documented here.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.52.6] — 2026-07-03
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** An invalid pairing latches the output pipeline — no more silent dead-token spam
12
+
13
+ ## [2.52.5] — 2026-07-02
14
+
15
+ ### CI
16
+
17
+ - **workflow:** Free runner disk before the JetBrains publish job
18
+
7
19
  ## [2.52.3] — 2026-06-30
8
20
 
9
21
  ### Added
package/dist/index.js CHANGED
@@ -560,8 +560,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
560
560
  return decodedFile;
561
561
  };
562
562
  }
563
- function normalizeWindowsPath(path62) {
564
- return path62.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
563
+ function normalizeWindowsPath(path63) {
564
+ return path63.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
565
565
  }
566
566
 
567
567
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3041,9 +3041,9 @@ async function addSourceContext(frames) {
3041
3041
  LRU_FILE_CONTENTS_CACHE.reduce();
3042
3042
  return frames;
3043
3043
  }
3044
- function getContextLinesFromFile(path62, ranges, output) {
3044
+ function getContextLinesFromFile(path63, ranges, output) {
3045
3045
  return new Promise((resolve7) => {
3046
- const stream = (0, import_node_fs.createReadStream)(path62);
3046
+ const stream = (0, import_node_fs.createReadStream)(path63);
3047
3047
  const lineReaded = (0, import_node_readline.createInterface)({
3048
3048
  input: stream
3049
3049
  });
@@ -3058,7 +3058,7 @@ function getContextLinesFromFile(path62, ranges, output) {
3058
3058
  let rangeStart = range[0];
3059
3059
  let rangeEnd = range[1];
3060
3060
  function onStreamError() {
3061
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path62, 1);
3061
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path63, 1);
3062
3062
  lineReaded.close();
3063
3063
  lineReaded.removeAllListeners();
3064
3064
  destroyStreamAndResolve();
@@ -3119,8 +3119,8 @@ function clearLineContext(frame) {
3119
3119
  delete frame.context_line;
3120
3120
  delete frame.post_context;
3121
3121
  }
3122
- function shouldSkipContextLinesForFile(path62) {
3123
- return path62.startsWith("node:") || path62.endsWith(".min.js") || path62.endsWith(".min.cjs") || path62.endsWith(".min.mjs") || path62.startsWith("data:");
3122
+ function shouldSkipContextLinesForFile(path63) {
3123
+ return path63.startsWith("node:") || path63.endsWith(".min.js") || path63.endsWith(".min.cjs") || path63.endsWith(".min.mjs") || path63.startsWith("data:");
3124
3124
  }
3125
3125
  function shouldSkipContextLinesForFrame(frame) {
3126
3126
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5397,7 +5397,7 @@ function readAnonId() {
5397
5397
  }
5398
5398
  function superProperties() {
5399
5399
  return {
5400
- cliVersion: true ? "2.52.5" : "0.0.0-dev",
5400
+ cliVersion: true ? "2.52.7" : "0.0.0-dev",
5401
5401
  nodeVersion: process.version,
5402
5402
  platform: process.platform,
5403
5403
  arch: process.arch,
@@ -5578,7 +5578,7 @@ var os4 = __toESM(require("os"));
5578
5578
  // package.json
5579
5579
  var package_default = {
5580
5580
  name: "codeam-cli",
5581
- version: "2.52.5",
5581
+ version: "2.52.7",
5582
5582
  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
5583
  type: "commonjs",
5584
5584
  main: "dist/index.js",
@@ -6105,6 +6105,13 @@ function computePollDelay({ baseMs, failures }) {
6105
6105
  }
6106
6106
 
6107
6107
  // src/services/command-relay.service.ts
6108
+ function httpStatusOf(err) {
6109
+ if (typeof err === "object" && err !== null && "statusCode" in err) {
6110
+ const status2 = err.statusCode;
6111
+ if (typeof status2 === "number") return status2;
6112
+ }
6113
+ return null;
6114
+ }
6108
6115
  var API_BASE2 = resolveApiBaseUrl();
6109
6116
  var SSE_LIVENESS_TIMEOUT_MS = 45e3;
6110
6117
  var SSE_WATCHDOG_INTERVAL_MS = 1e4;
@@ -6120,6 +6127,7 @@ var CommandRelayService = class {
6120
6127
  agentMeta;
6121
6128
  agentsOverride;
6122
6129
  _running = false;
6130
+ pairingInvalid = false;
6123
6131
  heartbeatTimer = null;
6124
6132
  agentsTimer = null;
6125
6133
  /** True once `/api/plugin/agents` has accepted at least one report. */
@@ -6197,7 +6205,22 @@ var CommandRelayService = class {
6197
6205
  });
6198
6206
  }
6199
6207
  async sendResult(commandId, status2, result) {
6200
- await _postJson(`${API_BASE2}/api/commands/result`, { commandId, status: status2, result });
6208
+ if (this.pairingInvalid) return;
6209
+ try {
6210
+ await _postJson(`${API_BASE2}/api/commands/result`, { commandId, status: status2, result });
6211
+ } catch (err) {
6212
+ const statusCode = httpStatusOf(err);
6213
+ if (statusCode === 401 || statusCode === 403) {
6214
+ this.pairingInvalid = true;
6215
+ process.stderr.write(
6216
+ "[codeam] This pairing is no longer valid \u2014 run `codeam pair` again to reconnect this session.\n"
6217
+ );
6218
+ log.warn("relay", `pairing invalid (status=${statusCode}) \u2014 relay stopped`);
6219
+ this.stop();
6220
+ return;
6221
+ }
6222
+ throw err;
6223
+ }
6201
6224
  }
6202
6225
  // ─── SSE pull (primary) ──────────────────────────────────────────
6203
6226
  connectSSE() {
@@ -7340,24 +7363,24 @@ async function refreshAuthToken(sessionId, pluginId) {
7340
7363
  },
7341
7364
  JSON.stringify({ sessionId, pluginId })
7342
7365
  );
7343
- if (statusCode === 404) {
7344
- log.warn("chunkEmitter", "[auth] reconnect 404 \u2014 session gone server-side");
7345
- return null;
7366
+ if (statusCode === 404 || statusCode === 401 || statusCode === 403) {
7367
+ log.warn("chunkEmitter", `[auth] reconnect ${statusCode} \u2014 session gone server-side`);
7368
+ return { kind: "gone" };
7346
7369
  }
7347
7370
  if (statusCode >= 400) {
7348
7371
  log.warn("chunkEmitter", `[auth] reconnect failed status=${statusCode}`);
7349
- return null;
7372
+ return { kind: "transient" };
7350
7373
  }
7351
7374
  const parsed = JSON.parse(body);
7352
7375
  const fresh = parsed.data?.pluginAuthToken;
7353
7376
  if (typeof fresh !== "string" || fresh.length === 0) {
7354
7377
  log.warn("chunkEmitter", "[auth] reconnect response missing pluginAuthToken");
7355
- return null;
7378
+ return { kind: "transient" };
7356
7379
  }
7357
- return fresh;
7380
+ return { kind: "fresh", token: fresh };
7358
7381
  } catch (err) {
7359
7382
  log.warn("chunkEmitter", `[auth] reconnect threw: ${String(err)}`);
7360
- return null;
7383
+ return { kind: "transient" };
7361
7384
  }
7362
7385
  }
7363
7386
  var ChunkEmitter = class {
@@ -7375,6 +7398,11 @@ var ChunkEmitter = class {
7375
7398
  opts;
7376
7399
  url = `${API_BASE4}/api/commands/output`;
7377
7400
  headers;
7401
+ /** Latched when the pairing is unrecoverable (401/403 whose refresh
7402
+ * says the session is gone, or a fresh token still rejected) —
7403
+ * every later send short-circuits (2026-06-28 incident: 401 ×34
7404
+ * with a dead token while the user saw nothing). */
7405
+ pairingInvalid = false;
7378
7406
  /**
7379
7407
  * Send a chunk. `body` is the chunk fields minus `sessionId` /
7380
7408
  * `pluginId` — the emitter splices those in. `critical = true`
@@ -7394,7 +7422,11 @@ var ChunkEmitter = class {
7394
7422
  "chunkEmitter",
7395
7423
  `send type=${body.type ?? "(clear)"} bytes=${payload.length} done=${body.done === true}`
7396
7424
  );
7425
+ if (this.pairingInvalid) {
7426
+ return Promise.resolve({ dead: true });
7427
+ }
7397
7428
  return new Promise((resolve7) => {
7429
+ let refreshedOnce = false;
7398
7430
  const attempt = (attemptsLeft) => {
7399
7431
  _transport3.post(this.url, this.headers, payload).then(({ statusCode, body: resBody }) => {
7400
7432
  const tookMs = Date.now() - t0;
@@ -7404,18 +7436,27 @@ var ChunkEmitter = class {
7404
7436
  resolve7({ dead: true });
7405
7437
  return;
7406
7438
  }
7407
- if (statusCode === 401) {
7408
- log.warn("chunkEmitter", `auth 401 took=${tookMs}ms \u2014 attempting silent refresh`);
7439
+ if (statusCode === 401 || statusCode === 403) {
7440
+ if (refreshedOnce) {
7441
+ this.markPairingInvalid(statusCode, tookMs);
7442
+ resolve7({ dead: true });
7443
+ return;
7444
+ }
7445
+ log.warn("chunkEmitter", `auth ${statusCode} took=${tookMs}ms \u2014 attempting silent refresh`);
7409
7446
  void (async () => {
7410
- const fresh = await refreshAuthToken(this.opts.sessionId, this.opts.pluginId);
7411
- if (fresh) {
7412
- this.headers["X-Plugin-Auth-Token"] = fresh;
7413
- this.opts.pluginAuthToken = fresh;
7447
+ const refresh = await refreshAuthToken(this.opts.sessionId, this.opts.pluginId);
7448
+ if (refresh.kind === "fresh") {
7449
+ this.headers["X-Plugin-Auth-Token"] = refresh.token;
7450
+ this.opts.pluginAuthToken = refresh.token;
7451
+ refreshedOnce = true;
7414
7452
  log.info("chunkEmitter", "auth refreshed silently");
7415
- if (attemptsLeft > 0 || opts.critical) {
7416
- attempt(Math.max(attemptsLeft, 1));
7417
- return;
7418
- }
7453
+ attempt(Math.max(attemptsLeft, 1));
7454
+ return;
7455
+ }
7456
+ if (refresh.kind === "gone") {
7457
+ this.markPairingInvalid(statusCode, tookMs);
7458
+ resolve7({ dead: true });
7459
+ return;
7419
7460
  }
7420
7461
  resolve7({ dead: false });
7421
7462
  })();
@@ -7446,6 +7487,17 @@ var ChunkEmitter = class {
7446
7487
  attempt(maxRetries);
7447
7488
  });
7448
7489
  }
7490
+ markPairingInvalid(statusCode, tookMs) {
7491
+ if (this.pairingInvalid) return;
7492
+ this.pairingInvalid = true;
7493
+ process.stderr.write(
7494
+ "[codeam] This pairing is no longer valid \u2014 run `codeam pair` again to reconnect this session.\n"
7495
+ );
7496
+ log.warn(
7497
+ "chunkEmitter",
7498
+ `pairing invalid (status=${statusCode}) took=${tookMs}ms \u2014 emitter latched, no further posts`
7499
+ );
7500
+ }
7449
7501
  };
7450
7502
  var _transport3 = {
7451
7503
  post: _post2
@@ -12790,11 +12842,11 @@ function parseReview(stdout) {
12790
12842
  for (const line of lines) {
12791
12843
  const m = line.match(HUNK_LINE_RE);
12792
12844
  if (!m) continue;
12793
- const [, path62, lineNo, sevToken, message] = m;
12794
- if (!path62 || !lineNo || !message) continue;
12845
+ const [, path63, lineNo, sevToken, message] = m;
12846
+ if (!path63 || !lineNo || !message) continue;
12795
12847
  const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
12796
12848
  hunks.push({
12797
- path: path62.trim(),
12849
+ path: path63.trim(),
12798
12850
  line: Number(lineNo),
12799
12851
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
12800
12852
  message: cleanedMessage
@@ -14876,7 +14928,7 @@ async function autoUpgradeBeforeCriticalCommand() {
14876
14928
  if (process.env.NODE_ENV === "test") return;
14877
14929
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
14878
14930
  if (process.env.CI) return;
14879
- const current = true ? "2.52.5" : null;
14931
+ const current = true ? "2.52.7" : null;
14880
14932
  if (!current) return;
14881
14933
  const cache = readCache();
14882
14934
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -14893,7 +14945,7 @@ function checkForUpdates() {
14893
14945
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
14894
14946
  if (process.env.CI) return;
14895
14947
  if (!process.stdout.isTTY) return;
14896
- const current = true ? "2.52.5" : null;
14948
+ const current = true ? "2.52.7" : null;
14897
14949
  if (!current) return;
14898
14950
  const cache = readCache();
14899
14951
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -15595,7 +15647,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process15.s
15595
15647
  detached: false
15596
15648
  });
15597
15649
  function currentCliVersion() {
15598
- return true ? "2.52.5" : null;
15650
+ return true ? "2.52.7" : null;
15599
15651
  }
15600
15652
  function runCmd(cmd, args2, timeoutMs) {
15601
15653
  return new Promise((resolve7) => {
@@ -20337,12 +20389,12 @@ function readTokenFromArgs(args2) {
20337
20389
  }
20338
20390
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
20339
20391
  if (fileFlag) {
20340
- const path62 = fileFlag.slice("--token-file=".length);
20392
+ const path63 = fileFlag.slice("--token-file=".length);
20341
20393
  try {
20342
- const content = fs44.readFileSync(path62, "utf8").trim();
20343
- if (content.length === 0) fail(`--token-file ${path62} is empty`);
20394
+ const content = fs44.readFileSync(path63, "utf8").trim();
20395
+ if (content.length === 0) fail(`--token-file ${path63} is empty`);
20344
20396
  try {
20345
- fs44.unlinkSync(path62);
20397
+ fs44.unlinkSync(path63);
20346
20398
  } catch {
20347
20399
  }
20348
20400
  return content;
@@ -21023,12 +21075,58 @@ function requiresAcp(agent) {
21023
21075
  return getAcpAdapter(agent) !== null;
21024
21076
  }
21025
21077
 
21078
+ // src/agents/acp/claude-binary.ts
21079
+ var import_fs4 = __toESM(require("fs"));
21080
+ var import_path8 = __toESM(require("path"));
21081
+ function currentPlatformKey() {
21082
+ return `${process.platform}-${process.arch}`;
21083
+ }
21084
+ function defaultSdkDir() {
21085
+ try {
21086
+ const manifest = require.resolve("@anthropic-ai/claude-agent-sdk/package.json");
21087
+ return import_path8.default.dirname(manifest);
21088
+ } catch {
21089
+ return null;
21090
+ }
21091
+ }
21092
+ function resolveClaudeNativeBinary(deps = {}) {
21093
+ const existsSync21 = deps.existsSync ?? import_fs4.default.existsSync;
21094
+ const platformKey = deps.platformKey ?? currentPlatformKey();
21095
+ const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
21096
+ if (!sdkDir) return null;
21097
+ const scopeDir = import_path8.default.dirname(sdkDir);
21098
+ const binName = process.platform === "win32" ? "claude.exe" : "claude";
21099
+ const candidate = import_path8.default.join(scopeDir, `claude-agent-sdk-${platformKey}`, binName);
21100
+ return existsSync21(candidate) ? candidate : null;
21101
+ }
21102
+ var realSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
21103
+ async function waitForClaudeNativeBinary(opts = {}) {
21104
+ const timeoutMs = opts.timeoutMs ?? 18e4;
21105
+ const pollMs = opts.pollMs ?? 500;
21106
+ const now = opts.now ?? Date.now;
21107
+ const sleep3 = opts.sleep ?? realSleep;
21108
+ const deps = {
21109
+ sdkDir: opts.sdkDir,
21110
+ platformKey: opts.platformKey,
21111
+ existsSync: opts.existsSync
21112
+ };
21113
+ const deadline = now() + timeoutMs;
21114
+ let found = resolveClaudeNativeBinary(deps);
21115
+ if (found) return found;
21116
+ while (now() < deadline) {
21117
+ await sleep3(pollMs);
21118
+ found = resolveClaudeNativeBinary(deps);
21119
+ if (found) return found;
21120
+ }
21121
+ return resolveClaudeNativeBinary(deps);
21122
+ }
21123
+
21026
21124
  // src/agents/acp/runner.ts
21027
21125
  var import_node_crypto7 = require("crypto");
21028
21126
 
21029
21127
  // src/services/history.service.ts
21030
- var fs45 = __toESM(require("fs"));
21031
- var path51 = __toESM(require("path"));
21128
+ var fs46 = __toESM(require("fs"));
21129
+ var path52 = __toESM(require("path"));
21032
21130
  var os38 = __toESM(require("os"));
21033
21131
  var https7 = __toESM(require("https"));
21034
21132
  var http6 = __toESM(require("http"));
@@ -21056,7 +21154,7 @@ function parseJsonl(filePath) {
21056
21154
  const messages = [];
21057
21155
  let raw;
21058
21156
  try {
21059
- raw = fs45.readFileSync(filePath, "utf8");
21157
+ raw = fs46.readFileSync(filePath, "utf8");
21060
21158
  } catch (err) {
21061
21159
  if (err.code !== "ENOENT") {
21062
21160
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -21197,7 +21295,7 @@ var HistoryService = class _HistoryService {
21197
21295
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
21198
21296
  }
21199
21297
  get projectDir() {
21200
- return this.runtime.resolveHistoryDir(this.cwd) ?? path51.join(os38.homedir(), ".claude", "projects", encodeCwd(this.cwd));
21298
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path52.join(os38.homedir(), ".claude", "projects", encodeCwd(this.cwd));
21201
21299
  }
21202
21300
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
21203
21301
  setCurrentConversationId(id) {
@@ -21209,7 +21307,7 @@ var HistoryService = class _HistoryService {
21209
21307
  /** Return the current message count in the active conversation. */
21210
21308
  getCurrentMessageCount() {
21211
21309
  if (!this.currentConversationId) return 0;
21212
- const filePath = path51.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21310
+ const filePath = path52.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21213
21311
  return parseJsonl(filePath).length;
21214
21312
  }
21215
21313
  /**
@@ -21220,7 +21318,7 @@ var HistoryService = class _HistoryService {
21220
21318
  const deadline = Date.now() + timeoutMs;
21221
21319
  while (Date.now() < deadline) {
21222
21320
  if (!this.currentConversationId) return null;
21223
- const filePath = path51.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21321
+ const filePath = path52.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21224
21322
  const messages = parseJsonl(filePath);
21225
21323
  if (messages.length > previousCount) {
21226
21324
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -21246,16 +21344,16 @@ var HistoryService = class _HistoryService {
21246
21344
  const dir = this.projectDir;
21247
21345
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
21248
21346
  try {
21249
- const files = fs45.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
21347
+ const files = fs46.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
21250
21348
  try {
21251
- const stat3 = fs45.statSync(path51.join(dir, e.name));
21349
+ const stat3 = fs46.statSync(path52.join(dir, e.name));
21252
21350
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
21253
21351
  } catch {
21254
21352
  return { name: e.name, mtime: 0, birthtime: 0 };
21255
21353
  }
21256
21354
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
21257
21355
  if (files.length > 0) {
21258
- this.currentConversationId = path51.basename(files[0].name, ".jsonl");
21356
+ this.currentConversationId = path52.basename(files[0].name, ".jsonl");
21259
21357
  }
21260
21358
  } catch {
21261
21359
  }
@@ -21289,13 +21387,13 @@ var HistoryService = class _HistoryService {
21289
21387
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
21290
21388
  let entries;
21291
21389
  try {
21292
- entries = fs45.readdirSync(dir, { withFileTypes: true });
21390
+ entries = fs46.readdirSync(dir, { withFileTypes: true });
21293
21391
  } catch {
21294
21392
  return null;
21295
21393
  }
21296
21394
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
21297
21395
  try {
21298
- const stat3 = fs45.statSync(path51.join(dir, e.name));
21396
+ const stat3 = fs46.statSync(path52.join(dir, e.name));
21299
21397
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
21300
21398
  } catch {
21301
21399
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -21304,12 +21402,12 @@ var HistoryService = class _HistoryService {
21304
21402
  if (files.length === 0) return null;
21305
21403
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
21306
21404
  if (!files.some((f) => f.name === targetFile)) return null;
21307
- return this.extractUsageFromFile(path51.join(dir, targetFile));
21405
+ return this.extractUsageFromFile(path52.join(dir, targetFile));
21308
21406
  }
21309
21407
  extractUsageFromFile(filePath) {
21310
21408
  let raw;
21311
21409
  try {
21312
- raw = fs45.readFileSync(filePath, "utf8");
21410
+ raw = fs46.readFileSync(filePath, "utf8");
21313
21411
  } catch {
21314
21412
  return null;
21315
21413
  }
@@ -21354,9 +21452,9 @@ var HistoryService = class _HistoryService {
21354
21452
  let totalCost = 0;
21355
21453
  let files;
21356
21454
  try {
21357
- files = fs45.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
21455
+ files = fs46.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
21358
21456
  try {
21359
- return fs45.statSync(path51.join(projectDir, f)).mtimeMs >= monthStartMs;
21457
+ return fs46.statSync(path52.join(projectDir, f)).mtimeMs >= monthStartMs;
21360
21458
  } catch {
21361
21459
  return false;
21362
21460
  }
@@ -21367,7 +21465,7 @@ var HistoryService = class _HistoryService {
21367
21465
  for (const file of files) {
21368
21466
  let raw;
21369
21467
  try {
21370
- raw = fs45.readFileSync(path51.join(projectDir, file), "utf8");
21468
+ raw = fs46.readFileSync(path52.join(projectDir, file), "utf8");
21371
21469
  } catch {
21372
21470
  continue;
21373
21471
  }
@@ -21446,7 +21544,7 @@ var HistoryService = class _HistoryService {
21446
21544
  if (this.runtime.resolveHistoryFile) {
21447
21545
  return this.runtime.resolveHistoryFile(this.cwd, sessionId);
21448
21546
  }
21449
- return path51.join(this.projectDir, `${sessionId}.jsonl`);
21547
+ return path52.join(this.projectDir, `${sessionId}.jsonl`);
21450
21548
  }
21451
21549
  /**
21452
21550
  * Parse a conversation's messages from disk, agent-aware. Claude uses the
@@ -21480,7 +21578,7 @@ var HistoryService = class _HistoryService {
21480
21578
  };
21481
21579
  });
21482
21580
  }
21483
- return parseJsonl(path51.join(this.projectDir, `${sessionId}.jsonl`));
21581
+ return parseJsonl(path52.join(this.projectDir, `${sessionId}.jsonl`));
21484
21582
  }
21485
21583
  async loadConversation(sessionId) {
21486
21584
  const messages = this.readConversation(sessionId);
@@ -21536,7 +21634,7 @@ var HistoryService = class _HistoryService {
21536
21634
  if (!filePath) return false;
21537
21635
  let mtimeMs;
21538
21636
  try {
21539
- mtimeMs = fs45.statSync(filePath).mtimeMs;
21637
+ mtimeMs = fs46.statSync(filePath).mtimeMs;
21540
21638
  } catch {
21541
21639
  return false;
21542
21640
  }
@@ -21605,10 +21703,10 @@ var HistoryService = class _HistoryService {
21605
21703
 
21606
21704
  // src/agents/acp/client.ts
21607
21705
  var import_node_child_process17 = require("child_process");
21608
- var fs46 = __toESM(require("fs/promises"));
21706
+ var fs47 = __toESM(require("fs/promises"));
21609
21707
  var fsSync = __toESM(require("fs"));
21610
21708
  var os39 = __toESM(require("os"));
21611
- var path52 = __toESM(require("path"));
21709
+ var path53 = __toESM(require("path"));
21612
21710
  var import_node_stream = require("stream");
21613
21711
 
21614
21712
  // ../../node_modules/@agentclientprotocol/sdk/dist/acp.js
@@ -24441,7 +24539,7 @@ var AcpClient = class {
24441
24539
  },
24442
24540
  readTextFile: async (params) => {
24443
24541
  try {
24444
- const content = await fs46.readFile(params.path, "utf8");
24542
+ const content = await fs47.readFile(params.path, "utf8");
24445
24543
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
24446
24544
  } catch (err) {
24447
24545
  const code = err.code;
@@ -24461,7 +24559,7 @@ var AcpClient = class {
24461
24559
  },
24462
24560
  writeTextFile: async (params) => {
24463
24561
  try {
24464
- await fs46.writeFile(params.path, params.content, "utf8");
24562
+ await fs47.writeFile(params.path, params.content, "utf8");
24465
24563
  return {};
24466
24564
  } catch (err) {
24467
24565
  const code = err.code;
@@ -24515,20 +24613,20 @@ function knownAgentBinaryDirs() {
24515
24613
  out2.push("/tmp/codeam-node20/bin");
24516
24614
  for (const root of [
24517
24615
  "/usr/local/share/nvm/versions/node",
24518
- path52.join(home, ".nvm/versions/node")
24616
+ path53.join(home, ".nvm/versions/node")
24519
24617
  ]) {
24520
24618
  try {
24521
24619
  for (const child of fsSync.readdirSync(root)) {
24522
- out2.push(path52.join(root, child, "bin"));
24620
+ out2.push(path53.join(root, child, "bin"));
24523
24621
  }
24524
24622
  } catch {
24525
24623
  }
24526
24624
  }
24527
- out2.push(path52.join(home, ".volta/bin"));
24625
+ out2.push(path53.join(home, ".volta/bin"));
24528
24626
  out2.push("/usr/local/bin");
24529
24627
  out2.push("/usr/bin");
24530
- out2.push(path52.join(home, ".local/bin"));
24531
- out2.push(path52.join(home, "bin"));
24628
+ out2.push(path53.join(home, ".local/bin"));
24629
+ out2.push(path53.join(home, "bin"));
24532
24630
  return out2.filter((p2) => {
24533
24631
  try {
24534
24632
  return fsSync.statSync(p2).isDirectory();
@@ -24539,7 +24637,7 @@ function knownAgentBinaryDirs() {
24539
24637
  }
24540
24638
  function expandPathForAgentBinaries(existingPath) {
24541
24639
  const existing = new Set(
24542
- existingPath.split(path52.delimiter).filter((p2) => p2.length > 0)
24640
+ existingPath.split(path53.delimiter).filter((p2) => p2.length > 0)
24543
24641
  );
24544
24642
  const additions = [];
24545
24643
  for (const dir of knownAgentBinaryDirs()) {
@@ -24549,7 +24647,7 @@ function expandPathForAgentBinaries(existingPath) {
24549
24647
  }
24550
24648
  }
24551
24649
  if (additions.length === 0) return existingPath;
24552
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path52.delimiter);
24650
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path53.delimiter);
24553
24651
  }
24554
24652
 
24555
24653
  // src/services/streaming/transport.ts
@@ -24652,6 +24750,10 @@ var AcpPublisher = class {
24652
24750
  opts;
24653
24751
  apiBase;
24654
24752
  token;
24753
+ /** Latched on an unrecoverable 401/403 — every surface stops posting
24754
+ * (2026-06-28 incident: a dead-token publisher spammed 401 ×34 while
24755
+ * the agent's replies silently never reached the phone). */
24756
+ pairingInvalid = false;
24655
24757
  authHeaders() {
24656
24758
  return {
24657
24759
  "Content-Type": "application/json",
@@ -24667,14 +24769,39 @@ var AcpPublisher = class {
24667
24769
  * response unchanged — callers log non-2xx but never throw.
24668
24770
  */
24669
24771
  async postWithReauth(url, payload) {
24772
+ if (this.pairingInvalid) {
24773
+ return { statusCode: 401, body: "PAIRING_INVALID" };
24774
+ }
24670
24775
  const first = await _transport4.post(url, this.authHeaders(), payload);
24671
24776
  if (first.statusCode !== 401 && first.statusCode !== 403) return first;
24672
- if (!this.opts.refreshAuthToken) return first;
24673
- const fresh = await this.opts.refreshAuthToken();
24674
- if (!fresh) return first;
24675
- this.token = fresh;
24676
- log.info("acpPublisher", `plugin-auth token refreshed after ${first.statusCode}; retrying POST`);
24677
- return _transport4.post(url, this.authHeaders(), payload);
24777
+ if (this.opts.refreshAuthToken) {
24778
+ const fresh = await this.opts.refreshAuthToken();
24779
+ if (fresh) {
24780
+ this.token = fresh;
24781
+ log.info("acpPublisher", `plugin-auth token refreshed after ${first.statusCode}; retrying POST`);
24782
+ const second = await _transport4.post(url, this.authHeaders(), payload);
24783
+ if (second.statusCode !== 401 && second.statusCode !== 403) return second;
24784
+ this.markPairingInvalid(second.statusCode);
24785
+ return second;
24786
+ }
24787
+ }
24788
+ this.markPairingInvalid(first.statusCode);
24789
+ return first;
24790
+ }
24791
+ markPairingInvalid(statusCode) {
24792
+ if (this.pairingInvalid) return;
24793
+ this.pairingInvalid = true;
24794
+ process.stderr.write(
24795
+ "[codeam] This pairing is no longer valid \u2014 run `codeam pair` again to reconnect this session.\n"
24796
+ );
24797
+ log.warn(
24798
+ "acpPublisher",
24799
+ `pairing invalid (status=${statusCode}) \u2014 publisher latched, no further posts`
24800
+ );
24801
+ try {
24802
+ this.opts.onPairingInvalid?.();
24803
+ } catch {
24804
+ }
24678
24805
  }
24679
24806
  /**
24680
24807
  * Wrap the body with `sessionId` + `pluginId` at the top level.
@@ -25034,15 +25161,15 @@ function commonPrefixLength(a, b) {
25034
25161
 
25035
25162
  // src/agents/acp/onboarding.ts
25036
25163
  var import_child_process23 = require("child_process");
25037
- var fs47 = __toESM(require("fs"));
25164
+ var fs48 = __toESM(require("fs"));
25038
25165
  var os40 = __toESM(require("os"));
25039
- var path53 = __toESM(require("path"));
25166
+ var path54 = __toESM(require("path"));
25040
25167
  var _onboardingSeam = {
25041
- markerPath: (sessionId) => path53.join(os40.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
25042
- exists: (p2) => fs47.existsSync(p2),
25168
+ markerPath: (sessionId) => path54.join(os40.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
25169
+ exists: (p2) => fs48.existsSync(p2),
25043
25170
  write: (p2) => {
25044
- fs47.mkdirSync(path53.dirname(p2), { recursive: true });
25045
- fs47.writeFileSync(p2, "");
25171
+ fs48.mkdirSync(path54.dirname(p2), { recursive: true });
25172
+ fs48.writeFileSync(p2, "");
25046
25173
  },
25047
25174
  disabled: () => {
25048
25175
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -25079,7 +25206,7 @@ function resolveRepoName(cwd) {
25079
25206
  if (name) return name;
25080
25207
  }
25081
25208
  }
25082
- const base = path53.basename(cwd || "");
25209
+ const base = path54.basename(cwd || "");
25083
25210
  if (base && !isUuid(base)) return base;
25084
25211
  return "this project";
25085
25212
  }
@@ -25357,8 +25484,8 @@ var import_crypto5 = require("crypto");
25357
25484
 
25358
25485
  // src/services/turn-files/git-changeset.ts
25359
25486
  var import_child_process24 = require("child_process");
25360
- var fs48 = __toESM(require("fs/promises"));
25361
- var path54 = __toESM(require("path"));
25487
+ var fs49 = __toESM(require("fs/promises"));
25488
+ var path55 = __toESM(require("path"));
25362
25489
  async function collectRepoChangeset(opts) {
25363
25490
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
25364
25491
  if (status2 === null) return null;
@@ -25376,7 +25503,7 @@ async function collectRepoChangeset(opts) {
25376
25503
  let stats;
25377
25504
  if (row.fileStatus === "added" && numstatEntry === void 0) {
25378
25505
  const lineCount = await readUntrackedLineCount(
25379
- path54.join(opts.repoRoot, row.filePath)
25506
+ path55.join(opts.repoRoot, row.filePath)
25380
25507
  );
25381
25508
  stats = { added: lineCount, removed: 0 };
25382
25509
  } else {
@@ -25407,7 +25534,7 @@ function readUntrackedLineCount(absPath) {
25407
25534
  }
25408
25535
  async function defaultReadUntrackedLineCount(absPath) {
25409
25536
  try {
25410
- const content = await fs48.readFile(absPath, "utf8");
25537
+ const content = await fs49.readFile(absPath, "utf8");
25411
25538
  let count = 0;
25412
25539
  let pos = -1;
25413
25540
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -25499,7 +25626,7 @@ function defaultRunGit(cwd, args2) {
25499
25626
  });
25500
25627
  }
25501
25628
  async function discoverRepos(workingDir, maxDepth = 4) {
25502
- const fs52 = await import("fs/promises");
25629
+ const fs53 = await import("fs/promises");
25503
25630
  const out2 = [];
25504
25631
  await walk(workingDir, 0);
25505
25632
  return out2;
@@ -25507,7 +25634,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
25507
25634
  if (depth > maxDepth) return;
25508
25635
  let entries = [];
25509
25636
  try {
25510
- const dirents = await fs52.readdir(dir, { withFileTypes: true });
25637
+ const dirents = await fs53.readdir(dir, { withFileTypes: true });
25511
25638
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
25512
25639
  } catch {
25513
25640
  return;
@@ -25518,8 +25645,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
25518
25645
  if (hasGit) {
25519
25646
  out2.push({
25520
25647
  repoRoot: dir,
25521
- repoPath: path54.relative(workingDir, dir),
25522
- repoName: path54.basename(dir)
25648
+ repoPath: path55.relative(workingDir, dir),
25649
+ repoName: path55.basename(dir)
25523
25650
  });
25524
25651
  return;
25525
25652
  }
@@ -25527,14 +25654,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
25527
25654
  if (!entry.isDirectory) continue;
25528
25655
  if (entry.name === "node_modules") continue;
25529
25656
  if (entry.name === "dist" || entry.name === "build") continue;
25530
- await walk(path54.join(dir, entry.name), depth + 1);
25657
+ await walk(path55.join(dir, entry.name), depth + 1);
25531
25658
  }
25532
25659
  }
25533
25660
  }
25534
25661
 
25535
25662
  // src/services/turn-files/files-outbox.ts
25536
- var fs49 = __toESM(require("fs/promises"));
25537
- var path55 = __toESM(require("path"));
25663
+ var fs50 = __toESM(require("fs/promises"));
25664
+ var path56 = __toESM(require("path"));
25538
25665
  var import_os7 = require("os");
25539
25666
  var HOME_OUTBOX_DIR = ".codeam/outbox";
25540
25667
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -25567,16 +25694,16 @@ var FilesOutbox = class {
25567
25694
  backoffIndex = 0;
25568
25695
  stopped = false;
25569
25696
  constructor(opts) {
25570
- const base = opts.baseDir ?? path55.join(homeDir(), HOME_OUTBOX_DIR);
25571
- this.filePath = path55.join(base, `${opts.sessionId}.jsonl`);
25697
+ const base = opts.baseDir ?? path56.join(homeDir(), HOME_OUTBOX_DIR);
25698
+ this.filePath = path56.join(base, `${opts.sessionId}.jsonl`);
25572
25699
  this.post = opts.post;
25573
25700
  this.autoSchedule = opts.autoSchedule !== false;
25574
25701
  }
25575
25702
  /** Persist the entry to disk and trigger a flush. Returns once the
25576
25703
  * line is durable on disk (not once the POST succeeds). */
25577
25704
  async enqueue(entry) {
25578
- await fs49.mkdir(path55.dirname(this.filePath), { recursive: true });
25579
- await fs49.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
25705
+ await fs50.mkdir(path56.dirname(this.filePath), { recursive: true });
25706
+ await fs50.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
25580
25707
  this.backoffIndex = 0;
25581
25708
  if (this.autoSchedule) this.scheduleFlush(0);
25582
25709
  }
@@ -25665,7 +25792,7 @@ var FilesOutbox = class {
25665
25792
  async readAll() {
25666
25793
  let raw = "";
25667
25794
  try {
25668
- raw = await fs49.readFile(this.filePath, "utf8");
25795
+ raw = await fs50.readFile(this.filePath, "utf8");
25669
25796
  } catch {
25670
25797
  return [];
25671
25798
  }
@@ -25689,12 +25816,12 @@ var FilesOutbox = class {
25689
25816
  async rewrite(entries) {
25690
25817
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
25691
25818
  if (entries.length === 0) {
25692
- await fs49.unlink(this.filePath).catch(() => void 0);
25819
+ await fs50.unlink(this.filePath).catch(() => void 0);
25693
25820
  return;
25694
25821
  }
25695
25822
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
25696
- await fs49.writeFile(tmpPath, payload, "utf8");
25697
- await fs49.rename(tmpPath, this.filePath);
25823
+ await fs50.writeFile(tmpPath, payload, "utf8");
25824
+ await fs50.rename(tmpPath, this.filePath);
25698
25825
  }
25699
25826
  };
25700
25827
  function applyJitter(ms) {
@@ -28323,15 +28450,15 @@ function fetchQuotaUsage(runtime, historySvc) {
28323
28450
  }
28324
28451
 
28325
28452
  // src/agents/claude/onboarding.ts
28326
- var fs50 = __toESM(require("fs"));
28453
+ var fs51 = __toESM(require("fs"));
28327
28454
  var os41 = __toESM(require("os"));
28328
- var path56 = __toESM(require("path"));
28455
+ var path57 = __toESM(require("path"));
28329
28456
  function ensureClaudeOnboarded() {
28330
28457
  try {
28331
- const file = path56.join(os41.homedir(), ".claude.json");
28458
+ const file = path57.join(os41.homedir(), ".claude.json");
28332
28459
  let config = {};
28333
28460
  try {
28334
- config = JSON.parse(fs50.readFileSync(file, "utf8"));
28461
+ config = JSON.parse(fs51.readFileSync(file, "utf8"));
28335
28462
  } catch {
28336
28463
  }
28337
28464
  if (config.hasCompletedOnboarding === true && typeof config.theme === "string") {
@@ -28342,8 +28469,8 @@ function ensureClaudeOnboarded() {
28342
28469
  if (typeof config.lastOnboardingVersion !== "string") {
28343
28470
  config.lastOnboardingVersion = "2.1.177";
28344
28471
  }
28345
- fs50.mkdirSync(path56.dirname(file), { recursive: true });
28346
- fs50.writeFileSync(file, JSON.stringify(config, null, 2));
28472
+ fs51.mkdirSync(path57.dirname(file), { recursive: true });
28473
+ fs51.writeFileSync(file, JSON.stringify(config, null, 2));
28347
28474
  log.info("claude", "pre-completed Claude onboarding (skip first-run theme picker)");
28348
28475
  } catch (err) {
28349
28476
  log.warn("claude", `ensureClaudeOnboarded failed (non-fatal): ${err.message}`);
@@ -28447,9 +28574,10 @@ async function start(requestedAgent) {
28447
28574
  const depsReady = process.env.CODESPACES === "true" ? provisionProjectDependencies(cwd).catch(() => void 0) : Promise.resolve();
28448
28575
  if (process.env.CODESPACES === "true") {
28449
28576
  const GATE_TIMEOUT_MS = 24e4;
28577
+ const claudeBinaryReady = session.agent === "claude" ? waitForClaudeNativeBinary({ timeoutMs: GATE_TIMEOUT_MS }).catch(() => null) : Promise.resolve();
28450
28578
  let gateTimer;
28451
28579
  await Promise.race([
28452
- Promise.all([beadsReady.catch(() => null), depsReady]),
28580
+ Promise.all([beadsReady.catch(() => null), depsReady, claudeBinaryReady]),
28453
28581
  new Promise((resolve7) => {
28454
28582
  gateTimer = setTimeout(resolve7, GATE_TIMEOUT_MS);
28455
28583
  })
@@ -28993,7 +29121,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
28993
29121
  var import_child_process25 = require("child_process");
28994
29122
  var import_util4 = require("util");
28995
29123
  var import_picocolors9 = __toESM(require("picocolors"));
28996
- var path57 = __toESM(require("path"));
29124
+ var path58 = __toESM(require("path"));
28997
29125
  var execFileP6 = (0, import_util4.promisify)(import_child_process25.execFile);
28998
29126
  var MAX_BUFFER = 8 * 1024 * 1024;
28999
29127
  function resetStdinForChild() {
@@ -29482,7 +29610,7 @@ var GitHubCodespacesProvider = class {
29482
29610
  });
29483
29611
  }
29484
29612
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
29485
- const remoteDir = path57.posix.dirname(remotePath);
29613
+ const remoteDir = path58.posix.dirname(remotePath);
29486
29614
  const parts = [
29487
29615
  `mkdir -p ${shellQuote(remoteDir)}`,
29488
29616
  `cat > ${shellQuote(remotePath)}`
@@ -29552,7 +29680,7 @@ function shellQuote(s) {
29552
29680
  // src/services/providers/gitpod.ts
29553
29681
  var import_child_process26 = require("child_process");
29554
29682
  var import_util5 = require("util");
29555
- var path58 = __toESM(require("path"));
29683
+ var path59 = __toESM(require("path"));
29556
29684
  var import_picocolors10 = __toESM(require("picocolors"));
29557
29685
  var execFileP7 = (0, import_util5.promisify)(import_child_process26.execFile);
29558
29686
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -29792,7 +29920,7 @@ var GitpodProvider = class {
29792
29920
  });
29793
29921
  }
29794
29922
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
29795
- const remoteDir = path58.posix.dirname(remotePath);
29923
+ const remoteDir = path59.posix.dirname(remotePath);
29796
29924
  const parts = [
29797
29925
  `mkdir -p ${shellQuote2(remoteDir)}`,
29798
29926
  `cat > ${shellQuote2(remotePath)}`
@@ -29828,7 +29956,7 @@ function shellQuote2(s) {
29828
29956
  // src/services/providers/gitlab-workspaces.ts
29829
29957
  var import_child_process27 = require("child_process");
29830
29958
  var import_util6 = require("util");
29831
- var path59 = __toESM(require("path"));
29959
+ var path60 = __toESM(require("path"));
29832
29960
  var execFileP8 = (0, import_util6.promisify)(import_child_process27.execFile);
29833
29961
  var MAX_BUFFER3 = 8 * 1024 * 1024;
29834
29962
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -30088,7 +30216,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
30088
30216
  }
30089
30217
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
30090
30218
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
30091
- const remoteDir = path59.posix.dirname(remotePath);
30219
+ const remoteDir = path60.posix.dirname(remotePath);
30092
30220
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
30093
30221
  if (options.mode != null) {
30094
30222
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -30156,7 +30284,7 @@ function shellQuote3(s) {
30156
30284
  // src/services/providers/railway.ts
30157
30285
  var import_child_process28 = require("child_process");
30158
30286
  var import_util7 = require("util");
30159
- var path60 = __toESM(require("path"));
30287
+ var path61 = __toESM(require("path"));
30160
30288
  var execFileP9 = (0, import_util7.promisify)(import_child_process28.execFile);
30161
30289
  var MAX_BUFFER4 = 8 * 1024 * 1024;
30162
30290
  function resetStdinForChild4() {
@@ -30392,7 +30520,7 @@ var RailwayProvider = class {
30392
30520
  if (!projectId || !serviceId) {
30393
30521
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
30394
30522
  }
30395
- const remoteDir = path60.posix.dirname(remotePath);
30523
+ const remoteDir = path61.posix.dirname(remotePath);
30396
30524
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
30397
30525
  if (options.mode != null) {
30398
30526
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -31038,8 +31166,8 @@ async function invite() {
31038
31166
  var import_node_dns = require("dns");
31039
31167
  var import_node_util5 = require("util");
31040
31168
  var import_node_crypto8 = require("crypto");
31041
- var fs51 = __toESM(require("fs"));
31042
- var path61 = __toESM(require("path"));
31169
+ var fs52 = __toESM(require("fs"));
31170
+ var path62 = __toESM(require("path"));
31043
31171
  var import_picocolors14 = __toESM(require("picocolors"));
31044
31172
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
31045
31173
  async function checkDns(apiBase2) {
@@ -31095,13 +31223,13 @@ async function checkHealth(apiBase2) {
31095
31223
  }
31096
31224
  }
31097
31225
  function checkConfigDir() {
31098
- const dir = path61.join(require("os").homedir(), ".codeam");
31226
+ const dir = path62.join(require("os").homedir(), ".codeam");
31099
31227
  try {
31100
- fs51.mkdirSync(dir, { recursive: true, mode: 448 });
31101
- const probe = path61.join(dir, ".doctor-probe");
31102
- fs51.writeFileSync(probe, "ok", { mode: 384 });
31103
- const read2 = fs51.readFileSync(probe, "utf8");
31104
- fs51.unlinkSync(probe);
31228
+ fs52.mkdirSync(dir, { recursive: true, mode: 448 });
31229
+ const probe = path62.join(dir, ".doctor-probe");
31230
+ fs52.writeFileSync(probe, "ok", { mode: 384 });
31231
+ const read2 = fs52.readFileSync(probe, "utf8");
31232
+ fs52.unlinkSync(probe);
31105
31233
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
31106
31234
  return {
31107
31235
  id: "config-dir",
@@ -31165,7 +31293,7 @@ function checkNodePty() {
31165
31293
  detail: "not required on this platform"
31166
31294
  };
31167
31295
  }
31168
- const vendoredPath = path61.join(__dirname, "vendor", "node-pty");
31296
+ const vendoredPath = path62.join(__dirname, "vendor", "node-pty");
31169
31297
  for (const target of [vendoredPath, "node-pty"]) {
31170
31298
  try {
31171
31299
  require(target);
@@ -31207,7 +31335,7 @@ function checkChokidar() {
31207
31335
  }
31208
31336
  async function doctor(args2 = []) {
31209
31337
  const json = args2.includes("--json");
31210
- const cliVersion = true ? "2.52.5" : "0.0.0-dev";
31338
+ const cliVersion = true ? "2.52.7" : "0.0.0-dev";
31211
31339
  const apiBase2 = resolveApiBaseUrl();
31212
31340
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
31213
31341
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -31406,7 +31534,7 @@ async function completion(args2) {
31406
31534
  // src/commands/version.ts
31407
31535
  var import_picocolors15 = __toESM(require("picocolors"));
31408
31536
  function version2() {
31409
- const v = true ? "2.52.5" : "unknown";
31537
+ const v = true ? "2.52.7" : "unknown";
31410
31538
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
31411
31539
  }
31412
31540
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.52.5",
3
+ "version": "2.52.7",
4
4
  "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 — async. The terminal companion for CodeAgent Mobile.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",