codeam-cli 2.39.44 → 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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ 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
+
7
13
  ## [2.39.43] — 2026-06-19
8
14
 
9
15
  ### Fixed
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.44",
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.44" : "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
@@ -27365,7 +27379,7 @@ function checkChokidar() {
27365
27379
  }
27366
27380
  async function doctor(args2 = []) {
27367
27381
  const json = args2.includes("--json");
27368
- const cliVersion = true ? "2.39.44" : "0.0.0-dev";
27382
+ const cliVersion = true ? "2.39.45" : "0.0.0-dev";
27369
27383
  const apiBase2 = resolveApiBaseUrl();
27370
27384
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
27371
27385
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -27564,7 +27578,7 @@ async function completion(args2) {
27564
27578
  // src/commands/version.ts
27565
27579
  var import_picocolors13 = __toESM(require("picocolors"));
27566
27580
  function version2() {
27567
- const v = true ? "2.39.44" : "unknown";
27581
+ const v = true ? "2.39.45" : "unknown";
27568
27582
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
27569
27583
  }
27570
27584
 
@@ -27850,7 +27864,7 @@ function checkForUpdates() {
27850
27864
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27851
27865
  if (process.env.CI) return;
27852
27866
  if (!process.stdout.isTTY) return;
27853
- const current = true ? "2.39.44" : null;
27867
+ const current = true ? "2.39.45" : null;
27854
27868
  if (!current) return;
27855
27869
  const cache = readCache();
27856
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.44",
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",