codeam-cli 2.16.2 → 2.17.0

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,27 @@ 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.16.2] — 2026-05-22
8
+
9
+ ### Chore
10
+
11
+ - **meta:** Expand issue templates with question + documentation forms
12
+
13
+ ### Documentation
14
+
15
+ - **shared:** Correct prod URL in api-url history comment
16
+
17
+ ### Fixed
18
+
19
+ - **cli:** Codeam link — auto-install, multi-probe creds, file-watcher login
20
+ - **cli:** Windows EPERM crash from chokidar watching user-profile junctions (#43)
21
+
22
+ ## [2.16.1] — 2026-05-21
23
+
24
+ ### Fixed
25
+
26
+ - **cli:** Codeam link — auto-install, multi-probe creds, file-watcher login (#42)
27
+
7
28
  ## [2.16.0] — 2026-05-21
8
29
 
9
30
  ### Added
package/dist/index.js CHANGED
@@ -424,7 +424,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
424
424
  // package.json
425
425
  var package_default = {
426
426
  name: "codeam-cli",
427
- version: "2.16.2",
427
+ version: "2.17.0",
428
428
  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.",
429
429
  type: "commonjs",
430
430
  main: "dist/index.js",
@@ -8592,8 +8592,9 @@ async function promptForAgent(initialValue) {
8592
8592
  // src/commands/pair.ts
8593
8593
  async function pair(args2 = []) {
8594
8594
  const config = loadCliConfig();
8595
+ const dryRun = args2.includes("--dry-run");
8595
8596
  const flagAgent = parseAgentFlag(args2);
8596
- const agentId = flagAgent ?? await promptForAgent(config.preferredAgent ?? "claude");
8597
+ const agentId = dryRun ? flagAgent ?? config.preferredAgent ?? "claude" : flagAgent ?? await promptForAgent(config.preferredAgent ?? "claude");
8597
8598
  showIntro();
8598
8599
  const pluginId = (0, import_crypto4.randomUUID)();
8599
8600
  const spin = dist_exports.spinner();
@@ -8605,6 +8606,20 @@ async function pair(args2 = []) {
8605
8606
  process.exit(1);
8606
8607
  }
8607
8608
  spin.stop("Got pairing code");
8609
+ if (dryRun) {
8610
+ const codeOk = typeof result.code === "string" && result.code.trim().length > 0;
8611
+ const expiresOk = typeof result.expiresAt === "number" && result.expiresAt > 0;
8612
+ if (!codeOk || !expiresOk) {
8613
+ showError(
8614
+ `Pair dry-run: backend response shape unexpected (codeType=${typeof result.code}, codeEmpty=${!codeOk}, expiresType=${typeof result.expiresAt}, expiresPositive=${expiresOk}).`
8615
+ );
8616
+ process.exit(1);
8617
+ }
8618
+ showSuccess(
8619
+ `Pair dry-run OK \u2014 backend reachable, response shape valid (codeLength=${result.code.length}, expiresAt=${result.expiresAt}, agent=${agentId}).`
8620
+ );
8621
+ process.exit(0);
8622
+ }
8608
8623
  showPairingCode(result.code);
8609
8624
  console.log(import_picocolors3.default.dim(" Scan the QR code or enter the code in CodeAgent Mobile."));
8610
8625
  console.log("");
@@ -10920,11 +10935,12 @@ function parseLinkArgs(args2) {
10920
10935
  );
10921
10936
  }
10922
10937
  const reuseExisting = args2.includes("--reuse-existing");
10938
+ const dryRun = args2.includes("--dry-run");
10923
10939
  const apiKeyArg = args2.find((a) => a.startsWith("--api-key="));
10924
10940
  const apiKey = apiKeyArg ? apiKeyArg.slice("--api-key=".length) : null;
10925
10941
  const tokenFileArg = args2.find((a) => a.startsWith("--token-file="));
10926
10942
  const tokenFile = tokenFileArg ? tokenFileArg.slice("--token-file=".length) : null;
10927
- return { agent: normalised, reuseExisting, apiKey, tokenFile };
10943
+ return { agent: normalised, reuseExisting, apiKey, tokenFile, dryRun };
10928
10944
  }
10929
10945
  async function link(args2 = []) {
10930
10946
  const parsed = parseLinkArgs(args2);
@@ -10934,6 +10950,10 @@ async function link(args2 = []) {
10934
10950
  import_picocolors11.default.bold(` Link ${meta.displayName}`) + import_picocolors11.default.dim(` \xB7 ${meta.vendor}`)
10935
10951
  );
10936
10952
  console.log("");
10953
+ if (parsed.dryRun) {
10954
+ await linkDryRunPreflight(meta);
10955
+ return;
10956
+ }
10937
10957
  const pluginId = (0, import_node_crypto.randomUUID)();
10938
10958
  const spin = dist_exports.spinner();
10939
10959
  spin.start("Requesting pairing code...");
@@ -11153,11 +11173,42 @@ async function uploadAndSucceed(meta, paired, pluginId, token) {
11153
11173
  );
11154
11174
  console.log("");
11155
11175
  }
11176
+ async function linkDryRunPreflight(meta) {
11177
+ const spin = dist_exports.spinner();
11178
+ spin.start(`Probing ${meta.publicId} link endpoint...`);
11179
+ const result = await postLinkCredential({
11180
+ agentId: meta.publicId,
11181
+ sessionId: "dryrun-session",
11182
+ pluginId: "dryrun-plugin",
11183
+ pluginAuthToken: "dryrun-token",
11184
+ method: "oauth",
11185
+ credential: "dryrun-credential"
11186
+ });
11187
+ if (result.ok) {
11188
+ spin.stop("Unexpected 2xx");
11189
+ showError(
11190
+ "Link dry-run: backend accepted a stub credential (2xx). PluginAuthGuard appears to be disabled \u2014 investigate api-v2."
11191
+ );
11192
+ process.exit(1);
11193
+ }
11194
+ if (result.status === 401) {
11195
+ spin.stop("Endpoint OK");
11196
+ showSuccess(
11197
+ `Link dry-run OK \u2014 /api/plugin/agents/${meta.publicId}/link reachable and auth-gated (401 as expected).`
11198
+ );
11199
+ process.exit(0);
11200
+ }
11201
+ spin.stop("Failed");
11202
+ showError(
11203
+ `Link dry-run: unexpected response from /api/plugin/agents/${meta.publicId}/link (status=${result.status}, message=${result.message}). Expected 401.`
11204
+ );
11205
+ process.exit(1);
11206
+ }
11156
11207
 
11157
11208
  // src/commands/version.ts
11158
11209
  var import_picocolors12 = __toESM(require("picocolors"));
11159
11210
  function version() {
11160
- const v = true ? "2.16.2" : "unknown";
11211
+ const v = true ? "2.17.0" : "unknown";
11161
11212
  console.log(`${import_picocolors12.default.bold("codeam-cli")} ${import_picocolors12.default.cyan(v)}`);
11162
11213
  }
11163
11214
 
@@ -11198,12 +11249,74 @@ function help() {
11198
11249
  process.stdout.write(lines.join("\n") + "\n");
11199
11250
  }
11200
11251
 
11252
+ // src/commands/subcommand-help.ts
11253
+ var import_picocolors14 = __toESM(require("picocolors"));
11254
+ var HELPS = {
11255
+ pair: () => print([
11256
+ ` ${import_picocolors14.default.bold("codeam pair")} ${import_picocolors14.default.dim("\u2014 pair a mobile device with this CLI")}`,
11257
+ "",
11258
+ ` ${import_picocolors14.default.cyan("codeam pair")} ${import_picocolors14.default.dim("interactive pairing (prompts for the agent)")}`,
11259
+ ` ${import_picocolors14.default.cyan("codeam pair --agent <id>")} ${import_picocolors14.default.dim("pair non-interactively (agent: claude | codex)")}`,
11260
+ ` ${import_picocolors14.default.cyan("codeam pair --dry-run")} ${import_picocolors14.default.dim("request a pairing code, validate the response, exit")}`
11261
+ ]),
11262
+ "pair-auto": () => print([
11263
+ ` ${import_picocolors14.default.bold("codeam pair-auto")} ${import_picocolors14.default.dim("\u2014 non-interactive variant of pair for scripted setups")}`,
11264
+ "",
11265
+ ` ${import_picocolors14.default.cyan("codeam pair-auto --agent <id>")} ${import_picocolors14.default.dim("pair using the supplied agent id; exit on success or timeout")}`
11266
+ ]),
11267
+ link: () => print([
11268
+ ` ${import_picocolors14.default.bold("codeam link <agent>")} ${import_picocolors14.default.dim("\u2014 upload a local agent token (Claude or Codex) to your vault")}`,
11269
+ "",
11270
+ ` ${import_picocolors14.default.cyan("codeam link claude")}`,
11271
+ ` ${import_picocolors14.default.cyan("codeam link codex")}`,
11272
+ "",
11273
+ ` ${import_picocolors14.default.white("--api-key=<key>")} ${import_picocolors14.default.dim("paste an API key directly (skip the local auth flow)")}`,
11274
+ ` ${import_picocolors14.default.white("--reuse-existing")} ${import_picocolors14.default.dim("upload existing creds without re-launching the agent login")}`,
11275
+ ` ${import_picocolors14.default.white("--token-file=<path>")} ${import_picocolors14.default.dim("manual credential blob path for unusual vendor locations")}`,
11276
+ ` ${import_picocolors14.default.white("--dry-run")} ${import_picocolors14.default.dim("probe the /api/plugin/agents/<agent>/link endpoint and exit")}`
11277
+ ]),
11278
+ sessions: () => print([
11279
+ ` ${import_picocolors14.default.bold("codeam sessions")} ${import_picocolors14.default.dim("\u2014 list, switch, or delete paired mobile sessions")}`,
11280
+ "",
11281
+ ` ${import_picocolors14.default.cyan("codeam sessions")} ${import_picocolors14.default.dim("list all paired sessions on this machine")}`,
11282
+ ` ${import_picocolors14.default.cyan("codeam sessions switch")} ${import_picocolors14.default.dim("interactively switch the active session")}`,
11283
+ ` ${import_picocolors14.default.cyan("codeam sessions delete <id>")} ${import_picocolors14.default.dim("remove a specific paired session")}`
11284
+ ]),
11285
+ deploy: () => print([
11286
+ ` ${import_picocolors14.default.bold("codeam deploy")} ${import_picocolors14.default.dim("\u2014 provision a cloud workspace (GitHub Codespaces) and pair it")}`,
11287
+ "",
11288
+ ` ${import_picocolors14.default.cyan("codeam deploy")} ${import_picocolors14.default.dim("start a new deploy (prompts for repo + agent)")}`,
11289
+ ` ${import_picocolors14.default.cyan("codeam deploy ls | list")} ${import_picocolors14.default.dim("list deployed cloud workspaces")}`,
11290
+ ` ${import_picocolors14.default.cyan("codeam deploy stop | remove")} ${import_picocolors14.default.dim("pick a workspace and stop its codeam-pair session")}`
11291
+ ]),
11292
+ status: () => print([
11293
+ ` ${import_picocolors14.default.bold("codeam status")} ${import_picocolors14.default.dim("\u2014 show the active session, agent, and connection info")}`
11294
+ ]),
11295
+ logout: () => print([
11296
+ ` ${import_picocolors14.default.bold("codeam logout")} ${import_picocolors14.default.dim("\u2014 remove every paired session from this machine")}`
11297
+ ])
11298
+ };
11299
+ function print(lines) {
11300
+ process.stdout.write(["", ...lines, ""].join("\n") + "\n");
11301
+ }
11302
+ function isHelpFlag(arg) {
11303
+ return arg === "--help" || arg === "-h";
11304
+ }
11305
+ function tryShowSubcommandHelp(cmd, args2) {
11306
+ if (!isHelpFlag(args2[0])) return false;
11307
+ const renderer = HELPS[cmd];
11308
+ if (!renderer) return false;
11309
+ renderer();
11310
+ return true;
11311
+ }
11312
+ var _subcommandHelpKeys = Object.keys(HELPS);
11313
+
11201
11314
  // src/lib/updateNotifier.ts
11202
11315
  var fs19 = __toESM(require("fs"));
11203
11316
  var os18 = __toESM(require("os"));
11204
11317
  var path27 = __toESM(require("path"));
11205
11318
  var https7 = __toESM(require("https"));
11206
- var import_picocolors14 = __toESM(require("picocolors"));
11319
+ var import_picocolors15 = __toESM(require("picocolors"));
11207
11320
  var PKG_NAME = "codeam-cli";
11208
11321
  var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
11209
11322
  var TTL_MS = 24 * 60 * 60 * 1e3;
@@ -11282,11 +11395,11 @@ function fetchLatest() {
11282
11395
  }
11283
11396
  function notifyIfStale(currentVersion, latest) {
11284
11397
  if (compareSemver(latest, currentVersion) <= 0) return;
11285
- const arrow = import_picocolors14.default.dim("\u2192");
11286
- const cmd = import_picocolors14.default.cyan("npm install -g codeam-cli");
11398
+ const arrow = import_picocolors15.default.dim("\u2192");
11399
+ const cmd = import_picocolors15.default.cyan("npm install -g codeam-cli");
11287
11400
  const lines = [
11288
11401
  "",
11289
- ` ${import_picocolors14.default.yellow("\u25CF")} ${import_picocolors14.default.bold("Update available")} ${import_picocolors14.default.dim(currentVersion)} ${arrow} ${import_picocolors14.default.green(latest)}`,
11402
+ ` ${import_picocolors15.default.yellow("\u25CF")} ${import_picocolors15.default.bold("Update available")} ${import_picocolors15.default.dim(currentVersion)} ${arrow} ${import_picocolors15.default.green(latest)}`,
11290
11403
  ` Run ${cmd} to upgrade.`,
11291
11404
  ""
11292
11405
  ];
@@ -11297,7 +11410,7 @@ function checkForUpdates() {
11297
11410
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
11298
11411
  if (process.env.CI) return;
11299
11412
  if (!process.stdout.isTTY) return;
11300
- const current = true ? "2.16.2" : null;
11413
+ const current = true ? "2.17.0" : null;
11301
11414
  if (!current) return;
11302
11415
  const cache = readCache();
11303
11416
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -11316,6 +11429,9 @@ var [, , command, ...args] = process.argv;
11316
11429
  async function main() {
11317
11430
  const isMetaCommand = command === "--version" || command === "-v" || command === "version" || command === "--help" || command === "-h" || command === "help";
11318
11431
  if (!isMetaCommand) checkForUpdates();
11432
+ if (typeof command === "string" && tryShowSubcommandHelp(command, args)) {
11433
+ return;
11434
+ }
11319
11435
  switch (command) {
11320
11436
  case "--version":
11321
11437
  case "-v":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.16.2",
3
+ "version": "2.17.0",
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",