codeam-cli 2.39.12 → 2.39.13

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.12] — 2026-06-13
8
+
9
+ ### Fixed
10
+
11
+ - **vsc-plugin,jetbrains-plugin:** Auto-reconnect the last session on IDE startup
12
+
7
13
  ## [2.39.11] — 2026-06-13
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.12",
501
+ version: "2.39.13",
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",
@@ -694,7 +694,7 @@ var _execSeam = {
694
694
  // src/services/pairing.service.ts
695
695
  var API_BASE = resolveApiBaseUrl();
696
696
  var REQUEST_CODE_TIMEOUT_MS = 1e4;
697
- async function requestCode(pluginId) {
697
+ async function requestCode(pluginId, pluginSecretHash) {
698
698
  try {
699
699
  const runtime = process.env.CODESPACES === "true" ? "github-codespaces" : "local";
700
700
  const codespaceName = process.env.CODESPACE_NAME;
@@ -706,7 +706,11 @@ async function requestCode(pluginId) {
706
706
  hostname: os2.hostname(),
707
707
  runtime,
708
708
  branch,
709
- ...codespaceName ? { codespaceName } : {}
709
+ ...codespaceName ? { codespaceName } : {},
710
+ // SEC: proof-of-possession enrollment. Backend carries this hash
711
+ // onto the session and requires the raw secret on /status +
712
+ // /reconnect. Older backends ignore the unknown field.
713
+ ...pluginSecretHash ? { pluginSecretHash } : {}
710
714
  });
711
715
  let timer;
712
716
  const timeoutSentinel = /* @__PURE__ */ Symbol("request-code-timeout");
@@ -738,11 +742,14 @@ async function requestCode(pluginId) {
738
742
  return { ok: false, reason: "network" };
739
743
  }
740
744
  }
741
- async function fetchCurrentPluginAuthToken(sessionId, pluginId) {
745
+ async function fetchCurrentPluginAuthToken(sessionId, pluginId, pollSecret) {
742
746
  try {
743
747
  const result = await _transport.postJson(
744
748
  `${API_BASE}/api/pairing/reconnect`,
745
- { sessionId, pluginId }
749
+ { sessionId, pluginId },
750
+ // SEC: prove possession so the gated /reconnect returns the token.
751
+ // Omitted for legacy sessions (no secret) → backend legacy path.
752
+ pollSecret ? { "X-Plugin-Poll-Secret": pollSecret } : void 0
746
753
  );
747
754
  const data = result?.data;
748
755
  if (!data?.paired) return null;
@@ -935,7 +942,7 @@ function makeHttpError(statusCode, retryAfterHeader, responseBody) {
935
942
  if (typeof retryAfterSeconds === "number") err.retryAfterSeconds = retryAfterSeconds;
936
943
  return err;
937
944
  }
938
- async function _postJson(url, body) {
945
+ async function _postJson(url, body, extraHeaders) {
939
946
  return new Promise((resolve7, reject) => {
940
947
  const data = JSON.stringify(body);
941
948
  const u2 = new URL(url);
@@ -949,7 +956,8 @@ async function _postJson(url, body) {
949
956
  headers: {
950
957
  "Content-Type": "application/json",
951
958
  "Content-Length": Buffer.byteLength(data),
952
- ...vercelBypassHeader()
959
+ ...vercelBypassHeader(),
960
+ ...extraHeaders ?? {}
953
961
  },
954
962
  timeout: 1e4
955
963
  },
@@ -5900,7 +5908,7 @@ function readAnonId() {
5900
5908
  }
5901
5909
  function superProperties() {
5902
5910
  return {
5903
- cliVersion: true ? "2.39.12" : "0.0.0-dev",
5911
+ cliVersion: true ? "2.39.13" : "0.0.0-dev",
5904
5912
  nodeVersion: process.version,
5905
5913
  platform: process.platform,
5906
5914
  arch: process.arch,
@@ -23938,7 +23946,11 @@ async function start(requestedAgent) {
23938
23946
  requestedAgent: requestedAgent ?? null
23939
23947
  });
23940
23948
  const cwd = process.cwd();
23941
- const refreshed = await fetchCurrentPluginAuthToken(session.id, pluginId);
23949
+ const refreshed = await fetchCurrentPluginAuthToken(
23950
+ session.id,
23951
+ pluginId,
23952
+ session.pollSecret
23953
+ );
23942
23954
  if (refreshed && refreshed !== session.pluginAuthToken) {
23943
23955
  addSession({ ...session, pluginAuthToken: refreshed });
23944
23956
  session.pluginAuthToken = refreshed;
@@ -24223,10 +24235,12 @@ async function pair(args2 = []) {
24223
24235
  const agentId = dryRun ? flagAgent ?? config.preferredAgent ?? "claude" : flagAgent ?? await promptForAgent(config.preferredAgent ?? "claude");
24224
24236
  showIntro();
24225
24237
  const pluginId = (0, import_crypto6.randomUUID)();
24238
+ const pollSecret = (0, import_crypto6.randomBytes)(32).toString("base64url");
24239
+ const pluginSecretHash = (0, import_crypto6.createHash)("sha256").update(pollSecret).digest("hex");
24226
24240
  capture("pair_started", { agentId, pluginId, dryRun });
24227
24241
  const spin = dist_exports.spinner();
24228
24242
  spin.start("Requesting pairing code...");
24229
- const result = await requestCode(pluginId);
24243
+ const result = await requestCode(pluginId, pluginSecretHash);
24230
24244
  if (!result.ok) {
24231
24245
  spin.stop("Failed");
24232
24246
  if (result.reason === "rate-limited") {
@@ -24289,6 +24303,9 @@ async function pair(args2 = []) {
24289
24303
  plan: info.plan,
24290
24304
  pairedAt: Date.now(),
24291
24305
  pluginAuthToken: info.pluginAuthToken,
24306
+ // SEC: persist the PoP secret so boot-time /reconnect can prove
24307
+ // possession and refresh the token on the gated endpoint.
24308
+ pollSecret,
24292
24309
  agent: agentId
24293
24310
  });
24294
24311
  saveCliConfig({ ...loadCliConfig(), preferredAgent: agentId });
@@ -26992,7 +27009,7 @@ function checkChokidar() {
26992
27009
  }
26993
27010
  async function doctor(args2 = []) {
26994
27011
  const json = args2.includes("--json");
26995
- const cliVersion = true ? "2.39.12" : "0.0.0-dev";
27012
+ const cliVersion = true ? "2.39.13" : "0.0.0-dev";
26996
27013
  const apiBase = resolveApiBaseUrl();
26997
27014
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
26998
27015
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -27191,7 +27208,7 @@ async function completion(args2) {
27191
27208
  // src/commands/version.ts
27192
27209
  var import_picocolors13 = __toESM(require("picocolors"));
27193
27210
  function version2() {
27194
- const v = true ? "2.39.12" : "unknown";
27211
+ const v = true ? "2.39.13" : "unknown";
27195
27212
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
27196
27213
  }
27197
27214
 
@@ -27477,7 +27494,7 @@ function checkForUpdates() {
27477
27494
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27478
27495
  if (process.env.CI) return;
27479
27496
  if (!process.stdout.isTTY) return;
27480
- const current = true ? "2.39.12" : null;
27497
+ const current = true ? "2.39.13" : null;
27481
27498
  if (!current) return;
27482
27499
  const cache = readCache();
27483
27500
  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.12",
3
+ "version": "2.39.13",
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",