codeam-cli 2.16.1 → 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 +21 -0
- package/dist/index.js +215 -27
- package/package.json +1 -1
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.
|
|
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",
|
|
@@ -6262,6 +6262,7 @@ var HistoryService = class _HistoryService {
|
|
|
6262
6262
|
|
|
6263
6263
|
// src/services/file-watcher.service.ts
|
|
6264
6264
|
var import_child_process7 = require("child_process");
|
|
6265
|
+
var os13 = __toESM(require("os"));
|
|
6265
6266
|
var path15 = __toESM(require("path"));
|
|
6266
6267
|
|
|
6267
6268
|
// src/services/file-watcher/diff-parser.ts
|
|
@@ -6397,6 +6398,44 @@ var API_BASE5 = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
|
6397
6398
|
var DEBOUNCE_MS = 250;
|
|
6398
6399
|
var MAX_RETRIES = 2;
|
|
6399
6400
|
var RETRY_BACKOFF_MS = 300;
|
|
6401
|
+
var WINDOWS_LEGACY_JUNCTIONS = [
|
|
6402
|
+
/[\\/]Application Data([\\/]|$)/i,
|
|
6403
|
+
/[\\/]Cookies([\\/]|$)/i,
|
|
6404
|
+
/[\\/]Local Settings([\\/]|$)/i,
|
|
6405
|
+
/[\\/]My Documents([\\/]|$)/i,
|
|
6406
|
+
/[\\/]NetHood([\\/]|$)/i,
|
|
6407
|
+
/[\\/]PrintHood([\\/]|$)/i,
|
|
6408
|
+
/[\\/]Recent([\\/]|$)/i,
|
|
6409
|
+
/[\\/]SendTo([\\/]|$)/i,
|
|
6410
|
+
/[\\/]Start Menu([\\/]|$)/i,
|
|
6411
|
+
/[\\/]Templates([\\/]|$)/i
|
|
6412
|
+
];
|
|
6413
|
+
function isUnsafeWindowsWatchRoot(dir, homedir12) {
|
|
6414
|
+
const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
|
|
6415
|
+
const cwd = norm(dir);
|
|
6416
|
+
const home = norm(homedir12);
|
|
6417
|
+
if (cwd === home) return true;
|
|
6418
|
+
if (/^[a-z]:$/.test(cwd)) return true;
|
|
6419
|
+
const sysRoots = [
|
|
6420
|
+
"c:\\windows",
|
|
6421
|
+
"c:\\program files",
|
|
6422
|
+
"c:\\program files (x86)",
|
|
6423
|
+
"c:\\programdata"
|
|
6424
|
+
];
|
|
6425
|
+
for (const root of sysRoots) {
|
|
6426
|
+
if (cwd === root || cwd.startsWith(root + "\\")) return true;
|
|
6427
|
+
}
|
|
6428
|
+
return false;
|
|
6429
|
+
}
|
|
6430
|
+
var _chokidarSeam = {
|
|
6431
|
+
load: () => {
|
|
6432
|
+
try {
|
|
6433
|
+
return require("chokidar");
|
|
6434
|
+
} catch {
|
|
6435
|
+
return null;
|
|
6436
|
+
}
|
|
6437
|
+
}
|
|
6438
|
+
};
|
|
6400
6439
|
var FileWatcherService = class {
|
|
6401
6440
|
constructor(opts) {
|
|
6402
6441
|
this.opts = opts;
|
|
@@ -6419,14 +6458,19 @@ var FileWatcherService = class {
|
|
|
6419
6458
|
if (this.stopped) {
|
|
6420
6459
|
throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
|
|
6421
6460
|
}
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6461
|
+
const isWin = process.platform === "win32";
|
|
6462
|
+
if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os13.homedir())) {
|
|
6463
|
+
log.warn(
|
|
6464
|
+
"fileWatcher",
|
|
6465
|
+
`refusing to watch ${this.opts.workingDir} \u2014 looks like a Windows user-profile or system path. Run codeam from your project folder to enable file change emission.`
|
|
6466
|
+
);
|
|
6467
|
+
return;
|
|
6468
|
+
}
|
|
6469
|
+
const chokidar2 = _chokidarSeam.load();
|
|
6470
|
+
if (!chokidar2) {
|
|
6426
6471
|
log.warn(
|
|
6427
6472
|
"fileWatcher",
|
|
6428
|
-
`chokidar unavailable \u2014 file change emission disabled
|
|
6429
|
-
err
|
|
6473
|
+
`chokidar unavailable \u2014 file change emission disabled`
|
|
6430
6474
|
);
|
|
6431
6475
|
return;
|
|
6432
6476
|
}
|
|
@@ -6444,11 +6488,22 @@ var FileWatcherService = class {
|
|
|
6444
6488
|
/\.parcel-cache/,
|
|
6445
6489
|
// Build outputs that aren't a typical "dist" target
|
|
6446
6490
|
/target\//,
|
|
6447
|
-
/__pycache__
|
|
6491
|
+
/__pycache__/,
|
|
6492
|
+
// Windows-only: skip legacy user-profile junctions whose ACLs
|
|
6493
|
+
// throw EPERM during chokidar's recursive traversal.
|
|
6494
|
+
...isWin ? WINDOWS_LEGACY_JUNCTIONS : []
|
|
6448
6495
|
],
|
|
6449
6496
|
ignoreInitial: true,
|
|
6450
6497
|
// we only care about post-start changes
|
|
6451
6498
|
persistent: true,
|
|
6499
|
+
// Windows-only safety net: don't follow reparse points, and let
|
|
6500
|
+
// chokidar swallow EPERM/EACCES on unreadable paths instead of
|
|
6501
|
+
// bubbling them up as fatal errors. Both are no-ops on macOS
|
|
6502
|
+
// (fsevents traversal doesn't fail on permission errors).
|
|
6503
|
+
...isWin ? {
|
|
6504
|
+
followSymlinks: false,
|
|
6505
|
+
ignorePermissionErrors: true
|
|
6506
|
+
} : {},
|
|
6452
6507
|
awaitWriteFinish: {
|
|
6453
6508
|
// Coalesces rapid sequential writes (npm install spam, build
|
|
6454
6509
|
// tools emitting bursts). Lower than chokidar's default so
|
|
@@ -6461,6 +6516,13 @@ var FileWatcherService = class {
|
|
|
6461
6516
|
watcher.on("add", (filePath) => this.schedule(filePath, "add"));
|
|
6462
6517
|
watcher.on("change", (filePath) => this.schedule(filePath, "change"));
|
|
6463
6518
|
watcher.on("unlink", (filePath) => this.schedule(filePath, "unlink"));
|
|
6519
|
+
watcher.on("error", (err) => {
|
|
6520
|
+
const code = err?.code ?? "unknown";
|
|
6521
|
+
log.warn(
|
|
6522
|
+
"fileWatcher",
|
|
6523
|
+
`chokidar error (code=${code}) \u2014 watcher continues: ${err}`
|
|
6524
|
+
);
|
|
6525
|
+
});
|
|
6464
6526
|
this.watcher = watcher;
|
|
6465
6527
|
log.info(
|
|
6466
6528
|
"fileWatcher",
|
|
@@ -7199,7 +7261,7 @@ function buildKeepAlive(ctx) {
|
|
|
7199
7261
|
|
|
7200
7262
|
// src/commands/start/handlers.ts
|
|
7201
7263
|
var fs14 = __toESM(require("fs"));
|
|
7202
|
-
var
|
|
7264
|
+
var os14 = __toESM(require("os"));
|
|
7203
7265
|
var path19 = __toESM(require("path"));
|
|
7204
7266
|
var import_crypto3 = require("crypto");
|
|
7205
7267
|
var import_child_process11 = require("child_process");
|
|
@@ -8007,7 +8069,7 @@ function closeTerminal(sessionId) {
|
|
|
8007
8069
|
function saveFilesTemp(files) {
|
|
8008
8070
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
8009
8071
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
8010
|
-
const tmpPath = path19.join(
|
|
8072
|
+
const tmpPath = path19.join(os14.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
|
|
8011
8073
|
fs14.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
8012
8074
|
return tmpPath;
|
|
8013
8075
|
});
|
|
@@ -8530,8 +8592,9 @@ async function promptForAgent(initialValue) {
|
|
|
8530
8592
|
// src/commands/pair.ts
|
|
8531
8593
|
async function pair(args2 = []) {
|
|
8532
8594
|
const config = loadCliConfig();
|
|
8595
|
+
const dryRun = args2.includes("--dry-run");
|
|
8533
8596
|
const flagAgent = parseAgentFlag(args2);
|
|
8534
|
-
const agentId = flagAgent ?? await promptForAgent(config.preferredAgent ?? "claude");
|
|
8597
|
+
const agentId = dryRun ? flagAgent ?? config.preferredAgent ?? "claude" : flagAgent ?? await promptForAgent(config.preferredAgent ?? "claude");
|
|
8535
8598
|
showIntro();
|
|
8536
8599
|
const pluginId = (0, import_crypto4.randomUUID)();
|
|
8537
8600
|
const spin = dist_exports.spinner();
|
|
@@ -8543,6 +8606,20 @@ async function pair(args2 = []) {
|
|
|
8543
8606
|
process.exit(1);
|
|
8544
8607
|
}
|
|
8545
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
|
+
}
|
|
8546
8623
|
showPairingCode(result.code);
|
|
8547
8624
|
console.log(import_picocolors3.default.dim(" Scan the QR code or enter the code in CodeAgent Mobile."));
|
|
8548
8625
|
console.log("");
|
|
@@ -8596,7 +8673,7 @@ async function pair(args2 = []) {
|
|
|
8596
8673
|
|
|
8597
8674
|
// src/commands/pair-auto.ts
|
|
8598
8675
|
var fs15 = __toESM(require("fs"));
|
|
8599
|
-
var
|
|
8676
|
+
var os15 = __toESM(require("os"));
|
|
8600
8677
|
var import_crypto5 = require("crypto");
|
|
8601
8678
|
var API_BASE7 = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
8602
8679
|
function fail(msg) {
|
|
@@ -8636,7 +8713,7 @@ async function claim(token, pluginId) {
|
|
|
8636
8713
|
pluginId,
|
|
8637
8714
|
ideName: "codeam-cli (codespace)",
|
|
8638
8715
|
ideVersion: process.env.npm_package_version ?? "unknown",
|
|
8639
|
-
hostname:
|
|
8716
|
+
hostname: os15.hostname(),
|
|
8640
8717
|
codespaceName: process.env.CODESPACE_NAME ?? "",
|
|
8641
8718
|
// Current git branch of the codespace's working directory, so the
|
|
8642
8719
|
// backend can populate `PairedSession.branch` for the codespace pair.
|
|
@@ -10741,7 +10818,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
|
|
|
10741
10818
|
// src/agents/claude/local-token.ts
|
|
10742
10819
|
var import_node_child_process2 = require("child_process");
|
|
10743
10820
|
var fs16 = __toESM(require("fs"));
|
|
10744
|
-
var
|
|
10821
|
+
var os16 = __toESM(require("os"));
|
|
10745
10822
|
var path24 = __toESM(require("path"));
|
|
10746
10823
|
var import_node_util3 = require("util");
|
|
10747
10824
|
var execFileP7 = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
|
|
@@ -10752,7 +10829,7 @@ var KEYCHAIN_SERVICE_NAMES = [
|
|
|
10752
10829
|
"Anthropic Claude"
|
|
10753
10830
|
];
|
|
10754
10831
|
function claudeCredentialsPaths() {
|
|
10755
|
-
const home =
|
|
10832
|
+
const home = os16.homedir();
|
|
10756
10833
|
return [
|
|
10757
10834
|
path24.join(home, ".claude", ".credentials.json"),
|
|
10758
10835
|
path24.join(home, ".config", "claude", ".credentials.json")
|
|
@@ -10787,10 +10864,10 @@ async function extractLocalClaudeToken() {
|
|
|
10787
10864
|
|
|
10788
10865
|
// src/agents/codex/local-token.ts
|
|
10789
10866
|
var fs17 = __toESM(require("fs"));
|
|
10790
|
-
var
|
|
10867
|
+
var os17 = __toESM(require("os"));
|
|
10791
10868
|
var path25 = __toESM(require("path"));
|
|
10792
10869
|
function codexCredentialsPath() {
|
|
10793
|
-
return path25.join(
|
|
10870
|
+
return path25.join(os17.homedir(), ".codex", "auth.json");
|
|
10794
10871
|
}
|
|
10795
10872
|
async function extractLocalCodexToken() {
|
|
10796
10873
|
const file = codexCredentialsPath();
|
|
@@ -10858,11 +10935,12 @@ function parseLinkArgs(args2) {
|
|
|
10858
10935
|
);
|
|
10859
10936
|
}
|
|
10860
10937
|
const reuseExisting = args2.includes("--reuse-existing");
|
|
10938
|
+
const dryRun = args2.includes("--dry-run");
|
|
10861
10939
|
const apiKeyArg = args2.find((a) => a.startsWith("--api-key="));
|
|
10862
10940
|
const apiKey = apiKeyArg ? apiKeyArg.slice("--api-key=".length) : null;
|
|
10863
10941
|
const tokenFileArg = args2.find((a) => a.startsWith("--token-file="));
|
|
10864
10942
|
const tokenFile = tokenFileArg ? tokenFileArg.slice("--token-file=".length) : null;
|
|
10865
|
-
return { agent: normalised, reuseExisting, apiKey, tokenFile };
|
|
10943
|
+
return { agent: normalised, reuseExisting, apiKey, tokenFile, dryRun };
|
|
10866
10944
|
}
|
|
10867
10945
|
async function link(args2 = []) {
|
|
10868
10946
|
const parsed = parseLinkArgs(args2);
|
|
@@ -10872,6 +10950,10 @@ async function link(args2 = []) {
|
|
|
10872
10950
|
import_picocolors11.default.bold(` Link ${meta.displayName}`) + import_picocolors11.default.dim(` \xB7 ${meta.vendor}`)
|
|
10873
10951
|
);
|
|
10874
10952
|
console.log("");
|
|
10953
|
+
if (parsed.dryRun) {
|
|
10954
|
+
await linkDryRunPreflight(meta);
|
|
10955
|
+
return;
|
|
10956
|
+
}
|
|
10875
10957
|
const pluginId = (0, import_node_crypto.randomUUID)();
|
|
10876
10958
|
const spin = dist_exports.spinner();
|
|
10877
10959
|
spin.start("Requesting pairing code...");
|
|
@@ -10981,10 +11063,20 @@ async function link(args2 = []) {
|
|
|
10981
11063
|
await uploadAndSucceed(meta, paired, pluginId, captured);
|
|
10982
11064
|
}
|
|
10983
11065
|
async function captureFreshCredentials(meta) {
|
|
11066
|
+
const isWin = process.platform === "win32";
|
|
10984
11067
|
const watcher = import_chokidar.default.watch(meta.watchPaths(), {
|
|
10985
11068
|
persistent: true,
|
|
10986
11069
|
ignoreInitial: false,
|
|
10987
|
-
awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 }
|
|
11070
|
+
awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 },
|
|
11071
|
+
// Windows-only: when a credential file's ancestor is missing,
|
|
11072
|
+
// chokidar walks up to the closest existing parent and starts
|
|
11073
|
+
// traversing it. On a default Windows shell that ancestor is
|
|
11074
|
+
// `C:\Users\<u>`, which contains legacy junctions whose ACL makes
|
|
11075
|
+
// `fs.watch` throw EPERM (#43). These flags are no-ops on macOS,
|
|
11076
|
+
// where the user has read access to their entire home.
|
|
11077
|
+
...isWin ? { followSymlinks: false, ignorePermissionErrors: true } : {}
|
|
11078
|
+
});
|
|
11079
|
+
watcher.on("error", () => {
|
|
10988
11080
|
});
|
|
10989
11081
|
let child = null;
|
|
10990
11082
|
let keychainPoll = null;
|
|
@@ -11081,11 +11173,42 @@ async function uploadAndSucceed(meta, paired, pluginId, token) {
|
|
|
11081
11173
|
);
|
|
11082
11174
|
console.log("");
|
|
11083
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
|
+
}
|
|
11084
11207
|
|
|
11085
11208
|
// src/commands/version.ts
|
|
11086
11209
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
11087
11210
|
function version() {
|
|
11088
|
-
const v = true ? "2.
|
|
11211
|
+
const v = true ? "2.17.0" : "unknown";
|
|
11089
11212
|
console.log(`${import_picocolors12.default.bold("codeam-cli")} ${import_picocolors12.default.cyan(v)}`);
|
|
11090
11213
|
}
|
|
11091
11214
|
|
|
@@ -11126,18 +11249,80 @@ function help() {
|
|
|
11126
11249
|
process.stdout.write(lines.join("\n") + "\n");
|
|
11127
11250
|
}
|
|
11128
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
|
+
|
|
11129
11314
|
// src/lib/updateNotifier.ts
|
|
11130
11315
|
var fs19 = __toESM(require("fs"));
|
|
11131
|
-
var
|
|
11316
|
+
var os18 = __toESM(require("os"));
|
|
11132
11317
|
var path27 = __toESM(require("path"));
|
|
11133
11318
|
var https7 = __toESM(require("https"));
|
|
11134
|
-
var
|
|
11319
|
+
var import_picocolors15 = __toESM(require("picocolors"));
|
|
11135
11320
|
var PKG_NAME = "codeam-cli";
|
|
11136
11321
|
var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
11137
11322
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
11138
11323
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
11139
11324
|
function cachePath() {
|
|
11140
|
-
const dir = path27.join(
|
|
11325
|
+
const dir = path27.join(os18.homedir(), ".codeam");
|
|
11141
11326
|
return path27.join(dir, "update-check.json");
|
|
11142
11327
|
}
|
|
11143
11328
|
function readCache() {
|
|
@@ -11210,11 +11395,11 @@ function fetchLatest() {
|
|
|
11210
11395
|
}
|
|
11211
11396
|
function notifyIfStale(currentVersion, latest) {
|
|
11212
11397
|
if (compareSemver(latest, currentVersion) <= 0) return;
|
|
11213
|
-
const arrow =
|
|
11214
|
-
const cmd =
|
|
11398
|
+
const arrow = import_picocolors15.default.dim("\u2192");
|
|
11399
|
+
const cmd = import_picocolors15.default.cyan("npm install -g codeam-cli");
|
|
11215
11400
|
const lines = [
|
|
11216
11401
|
"",
|
|
11217
|
-
` ${
|
|
11402
|
+
` ${import_picocolors15.default.yellow("\u25CF")} ${import_picocolors15.default.bold("Update available")} ${import_picocolors15.default.dim(currentVersion)} ${arrow} ${import_picocolors15.default.green(latest)}`,
|
|
11218
11403
|
` Run ${cmd} to upgrade.`,
|
|
11219
11404
|
""
|
|
11220
11405
|
];
|
|
@@ -11225,7 +11410,7 @@ function checkForUpdates() {
|
|
|
11225
11410
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
11226
11411
|
if (process.env.CI) return;
|
|
11227
11412
|
if (!process.stdout.isTTY) return;
|
|
11228
|
-
const current = true ? "2.
|
|
11413
|
+
const current = true ? "2.17.0" : null;
|
|
11229
11414
|
if (!current) return;
|
|
11230
11415
|
const cache = readCache();
|
|
11231
11416
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -11244,6 +11429,9 @@ var [, , command, ...args] = process.argv;
|
|
|
11244
11429
|
async function main() {
|
|
11245
11430
|
const isMetaCommand = command === "--version" || command === "-v" || command === "version" || command === "--help" || command === "-h" || command === "help";
|
|
11246
11431
|
if (!isMetaCommand) checkForUpdates();
|
|
11432
|
+
if (typeof command === "string" && tryShowSubcommandHelp(command, args)) {
|
|
11433
|
+
return;
|
|
11434
|
+
}
|
|
11247
11435
|
switch (command) {
|
|
11248
11436
|
case "--version":
|
|
11249
11437
|
case "-v":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "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",
|