codeam-cli 2.39.43 → 2.39.45

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 +142 -97
  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.39.44] — 2026-06-19
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Surface untracked new files with real line counts in changeset
12
+
13
+ ## [2.39.43] — 2026-06-19
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** Extract macOS cloudflared .tgz + self-heal gzip-corrupt cache
18
+
7
19
  ## [2.39.42] — 2026-06-19
8
20
 
9
21
  ### Added
package/dist/index.js CHANGED
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
498
498
  // package.json
499
499
  var package_default = {
500
500
  name: "codeam-cli",
501
- version: "2.39.43",
501
+ version: "2.39.45",
502
502
  description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
503
503
  type: "commonjs",
504
504
  main: "dist/index.js",
@@ -5908,7 +5908,7 @@ function readAnonId() {
5908
5908
  }
5909
5909
  function superProperties() {
5910
5910
  return {
5911
- cliVersion: true ? "2.39.43" : "0.0.0-dev",
5911
+ cliVersion: true ? "2.39.45" : "0.0.0-dev",
5912
5912
  nodeVersion: process.version,
5913
5913
  platform: process.platform,
5914
5914
  arch: process.arch,
@@ -16173,9 +16173,11 @@ async function link(args2 = []) {
16173
16173
  return;
16174
16174
  }
16175
16175
  const pluginId = (0, import_node_crypto6.randomUUID)();
16176
+ const pollSecret = (0, import_node_crypto6.randomBytes)(32).toString("base64url");
16177
+ const pluginSecretHash = (0, import_node_crypto6.createHash)("sha256").update(pollSecret).digest("hex");
16176
16178
  const spin = dist_exports.spinner();
16177
16179
  spin.start("Requesting pairing code...");
16178
- const pairing = await requestCode(pluginId);
16180
+ const pairing = await requestCode(pluginId, pluginSecretHash);
16179
16181
  if (!pairing.ok) {
16180
16182
  spin.stop("Failed");
16181
16183
  if (pairing.reason === "rate-limited") {
@@ -16219,15 +16221,30 @@ async function link(args2 = []) {
16219
16221
  clearInterval(countdown);
16220
16222
  waitSpin.stop("Timed out");
16221
16223
  reject(new Error("Pairing timed out after 5 minutes. Run codeam link again."));
16222
- }
16224
+ },
16225
+ // SEC: replay the PoP secret so the pending-stream gate passes
16226
+ // under PoP enforcement.
16227
+ pollSecret
16223
16228
  );
16224
16229
  process.once("SIGINT", sigint);
16225
16230
  });
16226
- if (!paired.pluginAuthToken) {
16227
- showError(
16228
- "Backend did not return a pluginAuthToken \u2014 upgrade api-v2 (deploy includes the link endpoint)."
16229
- );
16230
- process.exit(1);
16231
+ let pluginAuthToken = paired.pluginAuthToken;
16232
+ if (!pluginAuthToken) {
16233
+ const fetchSpin = dist_exports.spinner();
16234
+ fetchSpin.start("Fetching plugin auth token via secure reconnect...");
16235
+ pluginAuthToken = await fetchCurrentPluginAuthToken(
16236
+ paired.sessionId,
16237
+ pluginId,
16238
+ pollSecret
16239
+ ) ?? void 0;
16240
+ if (!pluginAuthToken) {
16241
+ fetchSpin.stop("Failed");
16242
+ showError(
16243
+ "Could not obtain a pluginAuthToken \u2014 the pairing did not supply one and the /api/pairing/reconnect fallback also failed. Ensure api-v2 is deployed and try running codeam link again."
16244
+ );
16245
+ process.exit(1);
16246
+ }
16247
+ fetchSpin.stop("Token retrieved");
16231
16248
  }
16232
16249
  addSession({
16233
16250
  id: paired.sessionId,
@@ -16236,12 +16253,15 @@ async function link(args2 = []) {
16236
16253
  userEmail: paired.userEmail,
16237
16254
  plan: paired.plan,
16238
16255
  pairedAt: Date.now(),
16239
- pluginAuthToken: paired.pluginAuthToken,
16256
+ pluginAuthToken,
16257
+ // SEC: persist so command-relay and future reconnects can prove
16258
+ // possession on the gated endpoint.
16259
+ pollSecret,
16240
16260
  agent: ctx.runtime.id
16241
16261
  });
16242
16262
  saveCliConfig({ ...loadCliConfig(), preferredAgent: ctx.runtime.id });
16243
16263
  if (parsed.apiKey) {
16244
- await uploadAndSucceed(ctx, paired, pluginId, {
16264
+ await uploadAndSucceed(ctx, paired, pluginId, pluginAuthToken, {
16245
16265
  method: "api_key",
16246
16266
  credential: parsed.apiKey.trim(),
16247
16267
  source: "manual"
@@ -16254,7 +16274,7 @@ async function link(args2 = []) {
16254
16274
  showError(`--token-file ${parsed.tokenFile} is empty.`);
16255
16275
  process.exit(1);
16256
16276
  }
16257
- await uploadAndSucceed(ctx, paired, pluginId, {
16277
+ await uploadAndSucceed(ctx, paired, pluginId, pluginAuthToken, {
16258
16278
  method: "oauth",
16259
16279
  credential,
16260
16280
  source: "manual"
@@ -16272,9 +16292,9 @@ async function link(args2 = []) {
16272
16292
  installSpin.stop(`${ctx.displayName} is installed`);
16273
16293
  const existing = await ctx.locator.extract();
16274
16294
  if (existing) {
16275
- if (await refuseIfStale(ctx, paired, pluginId, existing)) return;
16295
+ if (await refuseIfStale(ctx, paired, pluginId, pluginAuthToken, existing)) return;
16276
16296
  showInfo(`Found existing ${ctx.displayName} credentials at ${import_picocolors2.default.bold(existing.source)}.`);
16277
- await uploadAndSucceed(ctx, paired, pluginId, existing);
16297
+ await uploadAndSucceed(ctx, paired, pluginId, pluginAuthToken, existing);
16278
16298
  return;
16279
16299
  }
16280
16300
  if (parsed.reuseExisting) {
@@ -16289,23 +16309,21 @@ async function link(args2 = []) {
16289
16309
  console.log("");
16290
16310
  const captured = await captureFreshCredentials(ctx);
16291
16311
  console.log("");
16292
- if (await refuseIfStale(ctx, paired, pluginId, captured)) return;
16293
- await uploadAndSucceed(ctx, paired, pluginId, captured);
16312
+ if (await refuseIfStale(ctx, paired, pluginId, pluginAuthToken, captured)) return;
16313
+ await uploadAndSucceed(ctx, paired, pluginId, pluginAuthToken, captured);
16294
16314
  }
16295
- async function refuseIfStale(ctx, paired, pluginId, token) {
16315
+ async function refuseIfStale(ctx, paired, pluginId, pluginAuthToken, token) {
16296
16316
  const verdict = ctx.locator.validate?.(token);
16297
16317
  if (!verdict || verdict.status !== "expired") return false;
16298
16318
  const reason = verdict.reason ?? "Token expired";
16299
- if (paired.pluginAuthToken) {
16300
- await postLinkErrorSignal({
16301
- agentId: ctx.locator.publicId,
16302
- sessionId: paired.sessionId,
16303
- pluginId,
16304
- pluginAuthToken: paired.pluginAuthToken,
16305
- code: "credentials_expired",
16306
- reason
16307
- });
16308
- }
16319
+ await postLinkErrorSignal({
16320
+ agentId: ctx.locator.publicId,
16321
+ sessionId: paired.sessionId,
16322
+ pluginId,
16323
+ pluginAuthToken,
16324
+ code: "credentials_expired",
16325
+ reason
16326
+ });
16309
16327
  showError(
16310
16328
  `Your local ${ctx.displayName} credentials at ${import_picocolors2.default.bold(ctx.locator.hint)} are already expired:
16311
16329
  ${reason}
@@ -16394,18 +16412,14 @@ async function captureFreshCredentials(ctx) {
16394
16412
  throw err;
16395
16413
  }
16396
16414
  }
16397
- async function uploadAndSucceed(ctx, paired, pluginId, token) {
16398
- if (!paired.pluginAuthToken) {
16399
- showError("Missing pluginAuthToken; re-run codeam link.");
16400
- process.exit(1);
16401
- }
16415
+ async function uploadAndSucceed(ctx, paired, pluginId, pluginAuthToken, token) {
16402
16416
  const uploadSpin = dist_exports.spinner();
16403
16417
  uploadSpin.start("Sealing credential in your vault...");
16404
16418
  const result = await postLinkCredential({
16405
16419
  agentId: ctx.locator.publicId,
16406
16420
  sessionId: paired.sessionId,
16407
16421
  pluginId,
16408
- pluginAuthToken: paired.pluginAuthToken,
16422
+ pluginAuthToken,
16409
16423
  method: token.method,
16410
16424
  credential: token.credential,
16411
16425
  agentState: token.agentState
@@ -20253,6 +20267,7 @@ var import_crypto4 = require("crypto");
20253
20267
 
20254
20268
  // src/services/turn-files/git-changeset.ts
20255
20269
  var import_child_process21 = require("child_process");
20270
+ var fs37 = __toESM(require("fs/promises"));
20256
20271
  var path44 = __toESM(require("path"));
20257
20272
  async function collectRepoChangeset(opts) {
20258
20273
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
@@ -20267,7 +20282,16 @@ async function collectRepoChangeset(opts) {
20267
20282
  const entries = [];
20268
20283
  for (const row of parseStatus(status2)) {
20269
20284
  if (isIgnoredFilePath(row.filePath)) continue;
20270
- const stats = numstat.get(row.filePath) ?? { added: 0, removed: 0 };
20285
+ const numstatEntry = numstat.get(row.filePath);
20286
+ let stats;
20287
+ if (row.fileStatus === "added" && numstatEntry === void 0) {
20288
+ const lineCount = await readUntrackedLineCount(
20289
+ path44.join(opts.repoRoot, row.filePath)
20290
+ );
20291
+ stats = { added: lineCount, removed: 0 };
20292
+ } else {
20293
+ stats = numstatEntry ?? { added: 0, removed: 0 };
20294
+ }
20271
20295
  entries.push({
20272
20296
  filePath: row.filePath,
20273
20297
  fileStatus: row.fileStatus,
@@ -20284,6 +20308,27 @@ async function collectRepoChangeset(opts) {
20284
20308
  }
20285
20309
  return entries;
20286
20310
  }
20311
+ var MAX_UNTRACKED_LINE_SCAN = 1e5;
20312
+ var _readUntrackedLineCountImpl = {
20313
+ read: defaultReadUntrackedLineCount
20314
+ };
20315
+ function readUntrackedLineCount(absPath) {
20316
+ return _readUntrackedLineCountImpl.read(absPath);
20317
+ }
20318
+ async function defaultReadUntrackedLineCount(absPath) {
20319
+ try {
20320
+ const content = await fs37.readFile(absPath, "utf8");
20321
+ let count = 0;
20322
+ let pos = -1;
20323
+ while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
20324
+ count += 1;
20325
+ if (count >= MAX_UNTRACKED_LINE_SCAN) return count;
20326
+ }
20327
+ return content.length > 0 ? Math.max(count, 1) : 0;
20328
+ } catch {
20329
+ return 0;
20330
+ }
20331
+ }
20287
20332
  function parseStatus(raw) {
20288
20333
  const tokens = raw.split("\0");
20289
20334
  const rows = [];
@@ -20364,7 +20409,7 @@ function defaultRunGit(cwd, args2) {
20364
20409
  });
20365
20410
  }
20366
20411
  async function discoverRepos(workingDir, maxDepth = 4) {
20367
- const fs46 = await import("fs/promises");
20412
+ const fs47 = await import("fs/promises");
20368
20413
  const out2 = [];
20369
20414
  await walk(workingDir, 0);
20370
20415
  return out2;
@@ -20372,7 +20417,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
20372
20417
  if (depth > maxDepth) return;
20373
20418
  let entries = [];
20374
20419
  try {
20375
- const dirents = await fs46.readdir(dir, { withFileTypes: true });
20420
+ const dirents = await fs47.readdir(dir, { withFileTypes: true });
20376
20421
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
20377
20422
  } catch {
20378
20423
  return;
@@ -20398,7 +20443,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
20398
20443
  }
20399
20444
 
20400
20445
  // src/services/turn-files/files-outbox.ts
20401
- var fs37 = __toESM(require("fs/promises"));
20446
+ var fs38 = __toESM(require("fs/promises"));
20402
20447
  var path45 = __toESM(require("path"));
20403
20448
  var import_os7 = require("os");
20404
20449
  var HOME_OUTBOX_DIR = ".codeam/outbox";
@@ -20440,8 +20485,8 @@ var FilesOutbox = class {
20440
20485
  /** Persist the entry to disk and trigger a flush. Returns once the
20441
20486
  * line is durable on disk (not once the POST succeeds). */
20442
20487
  async enqueue(entry) {
20443
- await fs37.mkdir(path45.dirname(this.filePath), { recursive: true });
20444
- await fs37.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
20488
+ await fs38.mkdir(path45.dirname(this.filePath), { recursive: true });
20489
+ await fs38.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
20445
20490
  this.backoffIndex = 0;
20446
20491
  if (this.autoSchedule) this.scheduleFlush(0);
20447
20492
  }
@@ -20530,7 +20575,7 @@ var FilesOutbox = class {
20530
20575
  async readAll() {
20531
20576
  let raw = "";
20532
20577
  try {
20533
- raw = await fs37.readFile(this.filePath, "utf8");
20578
+ raw = await fs38.readFile(this.filePath, "utf8");
20534
20579
  } catch {
20535
20580
  return [];
20536
20581
  }
@@ -20554,12 +20599,12 @@ var FilesOutbox = class {
20554
20599
  async rewrite(entries) {
20555
20600
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
20556
20601
  if (entries.length === 0) {
20557
- await fs37.unlink(this.filePath).catch(() => void 0);
20602
+ await fs38.unlink(this.filePath).catch(() => void 0);
20558
20603
  return;
20559
20604
  }
20560
20605
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
20561
- await fs37.writeFile(tmpPath, payload, "utf8");
20562
- await fs37.rename(tmpPath, this.filePath);
20606
+ await fs38.writeFile(tmpPath, payload, "utf8");
20607
+ await fs38.rename(tmpPath, this.filePath);
20563
20608
  }
20564
20609
  };
20565
20610
  function applyJitter(ms) {
@@ -22457,7 +22502,7 @@ var OutputService = class _OutputService {
22457
22502
  };
22458
22503
 
22459
22504
  // src/services/history.service.ts
22460
- var fs38 = __toESM(require("fs"));
22505
+ var fs39 = __toESM(require("fs"));
22461
22506
  var path46 = __toESM(require("path"));
22462
22507
  var os30 = __toESM(require("os"));
22463
22508
  var https7 = __toESM(require("https"));
@@ -22486,7 +22531,7 @@ function parseJsonl(filePath) {
22486
22531
  const messages = [];
22487
22532
  let raw;
22488
22533
  try {
22489
- raw = fs38.readFileSync(filePath, "utf8");
22534
+ raw = fs39.readFileSync(filePath, "utf8");
22490
22535
  } catch (err) {
22491
22536
  if (err.code !== "ENOENT") {
22492
22537
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -22676,9 +22721,9 @@ var HistoryService = class _HistoryService {
22676
22721
  const dir = this.projectDir;
22677
22722
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
22678
22723
  try {
22679
- const files = fs38.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
22724
+ const files = fs39.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
22680
22725
  try {
22681
- const stat3 = fs38.statSync(path46.join(dir, e.name));
22726
+ const stat3 = fs39.statSync(path46.join(dir, e.name));
22682
22727
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
22683
22728
  } catch {
22684
22729
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -22719,13 +22764,13 @@ var HistoryService = class _HistoryService {
22719
22764
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
22720
22765
  let entries;
22721
22766
  try {
22722
- entries = fs38.readdirSync(dir, { withFileTypes: true });
22767
+ entries = fs39.readdirSync(dir, { withFileTypes: true });
22723
22768
  } catch {
22724
22769
  return null;
22725
22770
  }
22726
22771
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
22727
22772
  try {
22728
- const stat3 = fs38.statSync(path46.join(dir, e.name));
22773
+ const stat3 = fs39.statSync(path46.join(dir, e.name));
22729
22774
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
22730
22775
  } catch {
22731
22776
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -22739,7 +22784,7 @@ var HistoryService = class _HistoryService {
22739
22784
  extractUsageFromFile(filePath) {
22740
22785
  let raw;
22741
22786
  try {
22742
- raw = fs38.readFileSync(filePath, "utf8");
22787
+ raw = fs39.readFileSync(filePath, "utf8");
22743
22788
  } catch {
22744
22789
  return null;
22745
22790
  }
@@ -22784,9 +22829,9 @@ var HistoryService = class _HistoryService {
22784
22829
  let totalCost = 0;
22785
22830
  let files;
22786
22831
  try {
22787
- files = fs38.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
22832
+ files = fs39.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
22788
22833
  try {
22789
- return fs38.statSync(path46.join(projectDir, f)).mtimeMs >= monthStartMs;
22834
+ return fs39.statSync(path46.join(projectDir, f)).mtimeMs >= monthStartMs;
22790
22835
  } catch {
22791
22836
  return false;
22792
22837
  }
@@ -22797,7 +22842,7 @@ var HistoryService = class _HistoryService {
22797
22842
  for (const file of files) {
22798
22843
  let raw;
22799
22844
  try {
22800
- raw = fs38.readFileSync(path46.join(projectDir, file), "utf8");
22845
+ raw = fs39.readFileSync(path46.join(projectDir, file), "utf8");
22801
22846
  } catch {
22802
22847
  continue;
22803
22848
  }
@@ -23388,7 +23433,7 @@ function buildKeepAlive(ctx) {
23388
23433
  }
23389
23434
 
23390
23435
  // src/agents/claude/onboarding.ts
23391
- var fs39 = __toESM(require("fs"));
23436
+ var fs40 = __toESM(require("fs"));
23392
23437
  var os31 = __toESM(require("os"));
23393
23438
  var path47 = __toESM(require("path"));
23394
23439
  function ensureClaudeOnboarded() {
@@ -23396,7 +23441,7 @@ function ensureClaudeOnboarded() {
23396
23441
  const file = path47.join(os31.homedir(), ".claude.json");
23397
23442
  let config = {};
23398
23443
  try {
23399
- config = JSON.parse(fs39.readFileSync(file, "utf8"));
23444
+ config = JSON.parse(fs40.readFileSync(file, "utf8"));
23400
23445
  } catch {
23401
23446
  }
23402
23447
  if (config.hasCompletedOnboarding === true && typeof config.theme === "string") {
@@ -23407,8 +23452,8 @@ function ensureClaudeOnboarded() {
23407
23452
  if (typeof config.lastOnboardingVersion !== "string") {
23408
23453
  config.lastOnboardingVersion = "2.1.177";
23409
23454
  }
23410
- fs39.mkdirSync(path47.dirname(file), { recursive: true });
23411
- fs39.writeFileSync(file, JSON.stringify(config, null, 2));
23455
+ fs40.mkdirSync(path47.dirname(file), { recursive: true });
23456
+ fs40.writeFileSync(file, JSON.stringify(config, null, 2));
23412
23457
  log.info("claude", "pre-completed Claude onboarding (skip first-run theme picker)");
23413
23458
  } catch (err) {
23414
23459
  log.warn("claude", `ensureClaudeOnboarded failed (non-fatal): ${err.message}`);
@@ -23899,7 +23944,7 @@ async function autoLinkAfterPair(opts) {
23899
23944
  }
23900
23945
 
23901
23946
  // src/commands/pair-auto.ts
23902
- var fs40 = __toESM(require("fs"));
23947
+ var fs41 = __toESM(require("fs"));
23903
23948
  var os32 = __toESM(require("os"));
23904
23949
  var path48 = __toESM(require("path"));
23905
23950
  var import_crypto7 = require("crypto");
@@ -24098,10 +24143,10 @@ function readTokenFromArgs(args2) {
24098
24143
  if (fileFlag) {
24099
24144
  const path58 = fileFlag.slice("--token-file=".length);
24100
24145
  try {
24101
- const content = fs40.readFileSync(path58, "utf8").trim();
24146
+ const content = fs41.readFileSync(path58, "utf8").trim();
24102
24147
  if (content.length === 0) fail(`--token-file ${path58} is empty`);
24103
24148
  try {
24104
- fs40.unlinkSync(path58);
24149
+ fs41.unlinkSync(path58);
24105
24150
  } catch {
24106
24151
  }
24107
24152
  return content;
@@ -24198,7 +24243,7 @@ function isLivePairAuto(pid) {
24198
24243
  if (e.code !== "EPERM") return false;
24199
24244
  }
24200
24245
  try {
24201
- return fs40.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
24246
+ return fs41.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
24202
24247
  } catch {
24203
24248
  return true;
24204
24249
  }
@@ -24206,19 +24251,19 @@ function isLivePairAuto(pid) {
24206
24251
  function acquireSingletonLock() {
24207
24252
  const lockPath = pairAutoLockPath();
24208
24253
  try {
24209
- fs40.mkdirSync(path48.dirname(lockPath), { recursive: true });
24254
+ fs41.mkdirSync(path48.dirname(lockPath), { recursive: true });
24210
24255
  try {
24211
- fs40.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
24256
+ fs41.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
24212
24257
  } catch (e) {
24213
24258
  if (e.code !== "EEXIST") throw e;
24214
- const holder = Number(fs40.readFileSync(lockPath, "utf8").trim());
24259
+ const holder = Number(fs41.readFileSync(lockPath, "utf8").trim());
24215
24260
  if (isLivePairAuto(holder)) return false;
24216
- fs40.writeFileSync(lockPath, String(process.pid));
24261
+ fs41.writeFileSync(lockPath, String(process.pid));
24217
24262
  }
24218
24263
  process.once("exit", () => {
24219
24264
  try {
24220
- if (fs40.existsSync(lockPath) && Number(fs40.readFileSync(lockPath, "utf8").trim()) === process.pid) {
24221
- fs40.unlinkSync(lockPath);
24265
+ if (fs41.existsSync(lockPath) && Number(fs41.readFileSync(lockPath, "utf8").trim()) === process.pid) {
24266
+ fs41.unlinkSync(lockPath);
24222
24267
  }
24223
24268
  } catch {
24224
24269
  }
@@ -26360,7 +26405,7 @@ async function stopWorkspaceFromLocal(target) {
26360
26405
  }
26361
26406
 
26362
26407
  // src/commands/host/host-client.ts
26363
- var fs41 = __toESM(require("fs"));
26408
+ var fs42 = __toESM(require("fs"));
26364
26409
  var os33 = __toESM(require("os"));
26365
26410
  var path53 = __toESM(require("path"));
26366
26411
  function sampleCpuTimes() {
@@ -26421,7 +26466,7 @@ function collectOsInfo() {
26421
26466
  }
26422
26467
  function loadHostIdentity() {
26423
26468
  try {
26424
- const raw = fs41.readFileSync(hostIdentityPath(), "utf8");
26469
+ const raw = fs42.readFileSync(hostIdentityPath(), "utf8");
26425
26470
  const parsed = JSON.parse(raw);
26426
26471
  if (typeof parsed === "object" && parsed !== null && typeof parsed.hostId === "string" && typeof parsed.hostToken === "string" && typeof parsed.controlPluginId === "string") {
26427
26472
  const p2 = parsed;
@@ -26434,12 +26479,12 @@ function loadHostIdentity() {
26434
26479
  }
26435
26480
  function saveHostIdentity(identity) {
26436
26481
  const file = hostIdentityPath();
26437
- fs41.mkdirSync(path53.dirname(file), { recursive: true, mode: 448 });
26438
- fs41.writeFileSync(file, JSON.stringify(identity, null, 2), {
26482
+ fs42.mkdirSync(path53.dirname(file), { recursive: true, mode: 448 });
26483
+ fs42.writeFileSync(file, JSON.stringify(identity, null, 2), {
26439
26484
  encoding: "utf8",
26440
26485
  mode: 384
26441
26486
  });
26442
- fs41.chmodSync(file, 384);
26487
+ fs42.chmodSync(file, 384);
26443
26488
  }
26444
26489
  var HostHttpError = class extends Error {
26445
26490
  constructor(message, status2) {
@@ -26462,7 +26507,7 @@ function isHostAuthRejection(err) {
26462
26507
  }
26463
26508
  function deleteHostIdentity() {
26464
26509
  try {
26465
- fs41.rmSync(hostIdentityPath(), { force: true });
26510
+ fs42.rmSync(hostIdentityPath(), { force: true });
26466
26511
  } catch {
26467
26512
  }
26468
26513
  }
@@ -26626,7 +26671,7 @@ var import_node_child_process13 = require("child_process");
26626
26671
  var os36 = __toESM(require("os"));
26627
26672
 
26628
26673
  // src/commands/host/workspace.ts
26629
- var fs42 = __toESM(require("fs"));
26674
+ var fs43 = __toESM(require("fs"));
26630
26675
  var os34 = __toESM(require("os"));
26631
26676
  var path54 = __toESM(require("path"));
26632
26677
  var import_node_child_process12 = require("child_process");
@@ -26679,16 +26724,16 @@ function maskToken(text, cloneToken) {
26679
26724
  }
26680
26725
  async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
26681
26726
  if (isAbsolutePathTarget(repoOrPath)) {
26682
- if (!fs42.existsSync(repoOrPath)) {
26727
+ if (!fs43.existsSync(repoOrPath)) {
26683
26728
  throw new Error(`deploy target path does not exist: ${repoOrPath}`);
26684
26729
  }
26685
26730
  return repoOrPath;
26686
26731
  }
26687
26732
  const dest = path54.join(selfHostedWorkspaceRoot(), deployId);
26688
- if (fs42.existsSync(path54.join(dest, ".git"))) {
26733
+ if (fs43.existsSync(path54.join(dest, ".git"))) {
26689
26734
  return dest;
26690
26735
  }
26691
- fs42.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
26736
+ fs43.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
26692
26737
  const cloneUrl = repoCloneUrl(repoOrPath, cloneToken);
26693
26738
  try {
26694
26739
  await execFileP9("git", ["clone", "--depth", "1", cloneUrl, dest], {
@@ -26704,7 +26749,7 @@ async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
26704
26749
  }
26705
26750
 
26706
26751
  // src/commands/host/agent-provisioning.ts
26707
- var fs43 = __toESM(require("fs"));
26752
+ var fs44 = __toESM(require("fs"));
26708
26753
  var os35 = __toESM(require("os"));
26709
26754
  var path55 = __toESM(require("path"));
26710
26755
  var PUBLIC_TO_INTERNAL_AGENT = {
@@ -26721,12 +26766,12 @@ function toInternalAgentId(publicAgentId) {
26721
26766
  return PUBLIC_TO_INTERNAL_AGENT[publicAgentId] ?? null;
26722
26767
  }
26723
26768
  function ensureDir(dir) {
26724
- fs43.mkdirSync(dir, { recursive: true, mode: 448 });
26769
+ fs44.mkdirSync(dir, { recursive: true, mode: 448 });
26725
26770
  }
26726
26771
  function writeFile0600(filePath, contents) {
26727
26772
  ensureDir(path55.dirname(filePath));
26728
- fs43.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
26729
- fs43.chmodSync(filePath, 384);
26773
+ fs44.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
26774
+ fs44.chmodSync(filePath, 384);
26730
26775
  }
26731
26776
  var claudeProvisioner = {
26732
26777
  write(auth, home) {
@@ -26735,7 +26780,7 @@ var claudeProvisioner = {
26735
26780
  }
26736
26781
  writeFile0600(path55.join(home, ".claude", ".credentials.json"), auth.value);
26737
26782
  const claudeJson = path55.join(home, ".claude.json");
26738
- if (!fs43.existsSync(claudeJson)) {
26783
+ if (!fs44.existsSync(claudeJson)) {
26739
26784
  writeFile0600(
26740
26785
  claudeJson,
26741
26786
  JSON.stringify({ hasCompletedOnboarding: true, customApiKeyResponses: { approved: [] } })
@@ -27165,7 +27210,7 @@ async function hostAgent(args2 = []) {
27165
27210
  var import_node_dns = require("dns");
27166
27211
  var import_node_util5 = require("util");
27167
27212
  var import_node_crypto8 = require("crypto");
27168
- var fs44 = __toESM(require("fs"));
27213
+ var fs45 = __toESM(require("fs"));
27169
27214
  var path56 = __toESM(require("path"));
27170
27215
  var import_picocolors12 = __toESM(require("picocolors"));
27171
27216
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
@@ -27224,11 +27269,11 @@ async function checkHealth(apiBase2) {
27224
27269
  function checkConfigDir() {
27225
27270
  const dir = path56.join(require("os").homedir(), ".codeam");
27226
27271
  try {
27227
- fs44.mkdirSync(dir, { recursive: true, mode: 448 });
27272
+ fs45.mkdirSync(dir, { recursive: true, mode: 448 });
27228
27273
  const probe = path56.join(dir, ".doctor-probe");
27229
- fs44.writeFileSync(probe, "ok", { mode: 384 });
27230
- const read = fs44.readFileSync(probe, "utf8");
27231
- fs44.unlinkSync(probe);
27274
+ fs45.writeFileSync(probe, "ok", { mode: 384 });
27275
+ const read = fs45.readFileSync(probe, "utf8");
27276
+ fs45.unlinkSync(probe);
27232
27277
  if (read !== "ok") throw new Error("write/read round-trip mismatch");
27233
27278
  return {
27234
27279
  id: "config-dir",
@@ -27334,7 +27379,7 @@ function checkChokidar() {
27334
27379
  }
27335
27380
  async function doctor(args2 = []) {
27336
27381
  const json = args2.includes("--json");
27337
- const cliVersion = true ? "2.39.43" : "0.0.0-dev";
27382
+ const cliVersion = true ? "2.39.45" : "0.0.0-dev";
27338
27383
  const apiBase2 = resolveApiBaseUrl();
27339
27384
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
27340
27385
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -27533,7 +27578,7 @@ async function completion(args2) {
27533
27578
  // src/commands/version.ts
27534
27579
  var import_picocolors13 = __toESM(require("picocolors"));
27535
27580
  function version2() {
27536
- const v = true ? "2.39.43" : "unknown";
27581
+ const v = true ? "2.39.45" : "unknown";
27537
27582
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
27538
27583
  }
27539
27584
 
@@ -27661,7 +27706,7 @@ function tryShowSubcommandHelp(cmd, args2) {
27661
27706
  var _subcommandHelpKeys = Object.keys(HELPS);
27662
27707
 
27663
27708
  // src/lib/updateNotifier.ts
27664
- var fs45 = __toESM(require("fs"));
27709
+ var fs46 = __toESM(require("fs"));
27665
27710
  var os37 = __toESM(require("os"));
27666
27711
  var path57 = __toESM(require("path"));
27667
27712
  var https8 = __toESM(require("https"));
@@ -27677,7 +27722,7 @@ function cachePath() {
27677
27722
  }
27678
27723
  function readCache() {
27679
27724
  try {
27680
- const raw = fs45.readFileSync(cachePath(), "utf8");
27725
+ const raw = fs46.readFileSync(cachePath(), "utf8");
27681
27726
  const parsed = JSON.parse(raw);
27682
27727
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
27683
27728
  return parsed;
@@ -27688,10 +27733,10 @@ function readCache() {
27688
27733
  function writeCache(cache) {
27689
27734
  try {
27690
27735
  const file = cachePath();
27691
- fs45.mkdirSync(path57.dirname(file), { recursive: true });
27736
+ fs46.mkdirSync(path57.dirname(file), { recursive: true });
27692
27737
  const tmp = `${file}.${process.pid}.tmp`;
27693
- fs45.writeFileSync(tmp, JSON.stringify(cache));
27694
- fs45.renameSync(tmp, file);
27738
+ fs46.writeFileSync(tmp, JSON.stringify(cache));
27739
+ fs46.renameSync(tmp, file);
27695
27740
  } catch {
27696
27741
  }
27697
27742
  }
@@ -27766,7 +27811,7 @@ function isLinkedInstall() {
27766
27811
  }).trim();
27767
27812
  if (!root) return false;
27768
27813
  const pkgPath = path57.join(root, PKG_NAME);
27769
- return fs45.lstatSync(pkgPath).isSymbolicLink();
27814
+ return fs46.lstatSync(pkgPath).isSymbolicLink();
27770
27815
  } catch {
27771
27816
  return false;
27772
27817
  }
@@ -27802,7 +27847,7 @@ function maybeAutoUpdate(currentVersion, latest) {
27802
27847
  return;
27803
27848
  }
27804
27849
  try {
27805
- fs45.unlinkSync(cachePath());
27850
+ fs46.unlinkSync(cachePath());
27806
27851
  } catch {
27807
27852
  }
27808
27853
  process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
@@ -27819,7 +27864,7 @@ function checkForUpdates() {
27819
27864
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27820
27865
  if (process.env.CI) return;
27821
27866
  if (!process.stdout.isTTY) return;
27822
- const current = true ? "2.39.43" : null;
27867
+ const current = true ? "2.39.45" : null;
27823
27868
  if (!current) return;
27824
27869
  const cache = readCache();
27825
27870
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.39.43",
3
+ "version": "2.39.45",
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",