codeam-cli 2.26.14 → 2.26.16

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,25 @@ 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.26.15] — 2026-06-05
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Refuse to link Codex when local auth.json is already expired (#258)
12
+
13
+ ## [2.26.14] — 2026-06-04
14
+
15
+ ### Chore
16
+
17
+ - **deps:** Bump actions/setup-node from 4 to 6 (#246)
18
+ - **deps:** Bump actions/checkout from 4 to 6 (#247)
19
+ - **deps:** Bump org.jetbrains.kotlin.jvm in /apps/jetbrains-plugin (#248)
20
+ - **cli:** Bump which 2.0.2 → 5.0.0 (#251)
21
+
22
+ ### Fixed
23
+
24
+ - **cli:** Drop redundant install from agent setup_commands + warn agent (#256)
25
+
7
26
  ## [2.26.13] — 2026-06-04
8
27
 
9
28
  ### Added
package/dist/index.js CHANGED
@@ -486,7 +486,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
486
486
  // package.json
487
487
  var package_default = {
488
488
  name: "codeam-cli",
489
- version: "2.26.14",
489
+ version: "2.26.16",
490
490
  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.",
491
491
  type: "commonjs",
492
492
  main: "dist/index.js",
@@ -787,6 +787,21 @@ async function postLinkCredential(input) {
787
787
  };
788
788
  }
789
789
  }
790
+ async function postLinkErrorSignal(input) {
791
+ try {
792
+ await _transport.postJsonAuthed(
793
+ `${API_BASE}/api/plugin/agents/${input.agentId}/link-error`,
794
+ {
795
+ sessionId: input.sessionId,
796
+ pluginId: input.pluginId,
797
+ code: input.code,
798
+ reason: input.reason
799
+ },
800
+ input.pluginAuthToken
801
+ );
802
+ } catch {
803
+ }
804
+ }
790
805
  async function postAiResult(input) {
791
806
  const body = {
792
807
  sessionId: input.sessionId,
@@ -5843,7 +5858,7 @@ function readAnonId() {
5843
5858
  }
5844
5859
  function superProperties() {
5845
5860
  return {
5846
- cliVersion: true ? "2.26.14" : "0.0.0-dev",
5861
+ cliVersion: true ? "2.26.16" : "0.0.0-dev",
5847
5862
  nodeVersion: process.version,
5848
5863
  platform: process.platform,
5849
5864
  arch: process.arch,
@@ -10888,6 +10903,40 @@ async function extractLocalCodexToken() {
10888
10903
  function codexCredentialsPaths() {
10889
10904
  return [codexCredentialsPath()];
10890
10905
  }
10906
+ function validateLocalCodexToken(credential) {
10907
+ let parsed;
10908
+ try {
10909
+ parsed = JSON.parse(credential);
10910
+ } catch {
10911
+ return { status: "unknown" };
10912
+ }
10913
+ const directExp = typeof parsed.expires_at === "number" ? parsed.expires_at : typeof parsed.tokens?.expires_at === "number" ? parsed.tokens.expires_at : void 0;
10914
+ const jwtExp = decodeJwtExp(parsed.tokens?.id_token);
10915
+ const exp = directExp ?? jwtExp;
10916
+ if (exp === void 0) return { status: "unknown" };
10917
+ const expiresAt = exp < 1e12 ? exp * 1e3 : exp;
10918
+ if (Date.now() >= expiresAt) {
10919
+ return {
10920
+ status: "expired",
10921
+ reason: "Codex OAuth access token expired",
10922
+ expiresAt
10923
+ };
10924
+ }
10925
+ return { status: "valid", expiresAt };
10926
+ }
10927
+ function decodeJwtExp(jwt) {
10928
+ if (!jwt) return void 0;
10929
+ const parts = jwt.split(".");
10930
+ if (parts.length !== 3) return void 0;
10931
+ try {
10932
+ const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
10933
+ const padded = base64 + "===".slice((base64.length + 3) % 4);
10934
+ const payload = JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
10935
+ return typeof payload.exp === "number" ? payload.exp : void 0;
10936
+ } catch {
10937
+ return void 0;
10938
+ }
10939
+ }
10891
10940
 
10892
10941
  // src/agents/codex/link.ts
10893
10942
  function codexCredentialLocator() {
@@ -10896,7 +10945,11 @@ function codexCredentialLocator() {
10896
10945
  vendor: "OpenAI",
10897
10946
  hint: "~/.codex/auth.json",
10898
10947
  watchPaths: codexCredentialsPaths,
10899
- extract: extractLocalCodexToken
10948
+ extract: extractLocalCodexToken,
10949
+ validate: (token) => {
10950
+ const result = validateLocalCodexToken(token.credential);
10951
+ return { status: result.status, reason: result.reason };
10952
+ }
10900
10953
  };
10901
10954
  }
10902
10955
  function codexLoginLauncher() {
@@ -15907,6 +15960,7 @@ async function link(args2 = []) {
15907
15960
  installSpin.stop(`${ctx.displayName} is installed`);
15908
15961
  const existing = await ctx.locator.extract();
15909
15962
  if (existing) {
15963
+ if (await refuseIfStale(ctx, paired, pluginId, existing)) return;
15910
15964
  showInfo(`Found existing ${ctx.displayName} credentials at ${import_picocolors2.default.bold(existing.source)}.`);
15911
15965
  await uploadAndSucceed(ctx, paired, pluginId, existing);
15912
15966
  return;
@@ -15923,8 +15977,36 @@ async function link(args2 = []) {
15923
15977
  console.log("");
15924
15978
  const captured = await captureFreshCredentials(ctx);
15925
15979
  console.log("");
15980
+ if (await refuseIfStale(ctx, paired, pluginId, captured)) return;
15926
15981
  await uploadAndSucceed(ctx, paired, pluginId, captured);
15927
15982
  }
15983
+ async function refuseIfStale(ctx, paired, pluginId, token) {
15984
+ const verdict = ctx.locator.validate?.(token);
15985
+ if (!verdict || verdict.status !== "expired") return false;
15986
+ const reason = verdict.reason ?? "Token expired";
15987
+ if (paired.pluginAuthToken) {
15988
+ await postLinkErrorSignal({
15989
+ agentId: ctx.locator.publicId,
15990
+ sessionId: paired.sessionId,
15991
+ pluginId,
15992
+ pluginAuthToken: paired.pluginAuthToken,
15993
+ code: "credentials_expired",
15994
+ reason
15995
+ });
15996
+ }
15997
+ showError(
15998
+ `Your local ${ctx.displayName} credentials at ${import_picocolors2.default.bold(ctx.locator.hint)} are already expired:
15999
+ ${reason}
16000
+
16001
+ Uploading them would land a dead snapshot in the vault \u2014 every codespace bootstrapped from it would immediately return 401.
16002
+
16003
+ Run on your machine, then re-link:
16004
+ ${import_picocolors2.default.cyan(`${ctx.binary} logout`)}
16005
+ ${import_picocolors2.default.cyan(`${ctx.binary} login`)}
16006
+ ${import_picocolors2.default.cyan(`codeam link ${ctx.locator.publicId}`)}`
16007
+ );
16008
+ process.exit(1);
16009
+ }
15928
16010
  async function captureFreshCredentials(ctx) {
15929
16011
  const isWin = ctx.runtime.os.id === "win32";
15930
16012
  const watcher = import_chokidar.default.watch(ctx.locator.watchPaths(), {
@@ -20257,7 +20339,7 @@ function checkChokidar() {
20257
20339
  }
20258
20340
  async function doctor(args2 = []) {
20259
20341
  const json = args2.includes("--json");
20260
- const cliVersion = true ? "2.26.14" : "0.0.0-dev";
20342
+ const cliVersion = true ? "2.26.16" : "0.0.0-dev";
20261
20343
  const apiBase = resolveApiBaseUrl();
20262
20344
  const diagnosticId = (0, import_node_crypto6.randomUUID)();
20263
20345
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -20456,7 +20538,7 @@ async function completion(args2) {
20456
20538
  // src/commands/version.ts
20457
20539
  var import_picocolors13 = __toESM(require("picocolors"));
20458
20540
  function version2() {
20459
- const v = true ? "2.26.14" : "unknown";
20541
+ const v = true ? "2.26.16" : "unknown";
20460
20542
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
20461
20543
  }
20462
20544
 
@@ -20684,7 +20766,7 @@ function checkForUpdates() {
20684
20766
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
20685
20767
  if (process.env.CI) return;
20686
20768
  if (!process.stdout.isTTY) return;
20687
- const current = true ? "2.26.14" : null;
20769
+ const current = true ? "2.26.16" : null;
20688
20770
  if (!current) return;
20689
20771
  const cache = readCache();
20690
20772
  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.26.14",
3
+ "version": "2.26.16",
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",