codeam-cli 2.15.8 → 2.16.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 +12 -0
- package/dist/index.js +389 -49
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ 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.15.8] — 2026-05-21
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Pairing-box alignment + countdown actually ticks (#39)
|
|
12
|
+
|
|
13
|
+
## [2.15.7] — 2026-05-21
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **clients:** Point default API URL at api.codeagent-mobile.com + centralize via shared constant (#38)
|
|
18
|
+
|
|
7
19
|
## [2.15.6] — 2026-05-20
|
|
8
20
|
|
|
9
21
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -389,7 +389,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
389
389
|
// package.json
|
|
390
390
|
var package_default = {
|
|
391
391
|
name: "codeam-cli",
|
|
392
|
-
version: "2.
|
|
392
|
+
version: "2.16.0",
|
|
393
393
|
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.",
|
|
394
394
|
type: "commonjs",
|
|
395
395
|
main: "dist/index.js",
|
|
@@ -646,8 +646,84 @@ function pollStatus(pluginId, onPaired, onTimeout) {
|
|
|
646
646
|
}
|
|
647
647
|
var _transport = {
|
|
648
648
|
postJson: _postJson,
|
|
649
|
-
getJson: _getJson
|
|
649
|
+
getJson: _getJson,
|
|
650
|
+
postJsonAuthed: _postJsonAuthed
|
|
650
651
|
};
|
|
652
|
+
async function postLinkCredential(input) {
|
|
653
|
+
const body = {
|
|
654
|
+
sessionId: input.sessionId,
|
|
655
|
+
pluginId: input.pluginId,
|
|
656
|
+
method: input.method,
|
|
657
|
+
credential: input.credential
|
|
658
|
+
};
|
|
659
|
+
if (input.modelPreference) {
|
|
660
|
+
body.modelPreference = input.modelPreference;
|
|
661
|
+
}
|
|
662
|
+
try {
|
|
663
|
+
await _transport.postJsonAuthed(
|
|
664
|
+
`${API_BASE}/api/plugin/agents/${input.agentId}/link`,
|
|
665
|
+
body,
|
|
666
|
+
input.pluginAuthToken
|
|
667
|
+
);
|
|
668
|
+
return { ok: true };
|
|
669
|
+
} catch (err) {
|
|
670
|
+
const e = err;
|
|
671
|
+
return {
|
|
672
|
+
ok: false,
|
|
673
|
+
status: typeof e.statusCode === "number" ? e.statusCode : 0,
|
|
674
|
+
message: e.message || "unknown"
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
679
|
+
return new Promise((resolve2, reject) => {
|
|
680
|
+
const data = JSON.stringify(body);
|
|
681
|
+
const u2 = new URL(url);
|
|
682
|
+
const transport = u2.protocol === "https:" ? https : http;
|
|
683
|
+
const req = transport.request(
|
|
684
|
+
{
|
|
685
|
+
hostname: u2.hostname,
|
|
686
|
+
port: u2.port || (u2.protocol === "https:" ? 443 : 80),
|
|
687
|
+
path: u2.pathname + u2.search,
|
|
688
|
+
method: "POST",
|
|
689
|
+
headers: {
|
|
690
|
+
"Content-Type": "application/json",
|
|
691
|
+
"Content-Length": Buffer.byteLength(data),
|
|
692
|
+
"X-Plugin-Auth-Token": pluginAuthToken,
|
|
693
|
+
...vercelBypassHeader()
|
|
694
|
+
},
|
|
695
|
+
timeout: 15e3
|
|
696
|
+
},
|
|
697
|
+
(res) => {
|
|
698
|
+
res.on("error", reject);
|
|
699
|
+
let responseBody = "";
|
|
700
|
+
res.on("data", (chunk) => {
|
|
701
|
+
responseBody += chunk.toString();
|
|
702
|
+
});
|
|
703
|
+
res.on("end", () => {
|
|
704
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
705
|
+
const err = new Error(`HTTP ${res.statusCode}: ${responseBody.slice(0, 200)}`);
|
|
706
|
+
err.statusCode = res.statusCode;
|
|
707
|
+
reject(err);
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
try {
|
|
711
|
+
resolve2(JSON.parse(responseBody));
|
|
712
|
+
} catch {
|
|
713
|
+
resolve2(null);
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
);
|
|
718
|
+
req.on("error", reject);
|
|
719
|
+
req.on("timeout", () => {
|
|
720
|
+
req.destroy();
|
|
721
|
+
reject(new Error("timeout"));
|
|
722
|
+
});
|
|
723
|
+
req.write(data);
|
|
724
|
+
req.end();
|
|
725
|
+
});
|
|
726
|
+
}
|
|
651
727
|
async function _postJson(url, body) {
|
|
652
728
|
return new Promise((resolve2, reject) => {
|
|
653
729
|
const data = JSON.stringify(body);
|
|
@@ -8521,12 +8597,12 @@ function readTokenFromArgs(args2) {
|
|
|
8521
8597
|
}
|
|
8522
8598
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
8523
8599
|
if (fileFlag) {
|
|
8524
|
-
const
|
|
8600
|
+
const path27 = fileFlag.slice("--token-file=".length);
|
|
8525
8601
|
try {
|
|
8526
|
-
const content = fs15.readFileSync(
|
|
8527
|
-
if (content.length === 0) fail(`--token-file ${
|
|
8602
|
+
const content = fs15.readFileSync(path27, "utf8").trim();
|
|
8603
|
+
if (content.length === 0) fail(`--token-file ${path27} is empty`);
|
|
8528
8604
|
try {
|
|
8529
|
-
fs15.unlinkSync(
|
|
8605
|
+
fs15.unlinkSync(path27);
|
|
8530
8606
|
} catch {
|
|
8531
8607
|
}
|
|
8532
8608
|
return content;
|
|
@@ -10630,74 +10706,336 @@ async function probeCodeamPair(provider, workspace) {
|
|
|
10630
10706
|
}
|
|
10631
10707
|
async function stopWorkspaceFromLocal(target) {
|
|
10632
10708
|
if (target.provider.id === "github-codespaces") {
|
|
10633
|
-
const { execFile:
|
|
10634
|
-
const { promisify:
|
|
10635
|
-
const
|
|
10636
|
-
await
|
|
10709
|
+
const { execFile: execFile8 } = await import("child_process");
|
|
10710
|
+
const { promisify: promisify8 } = await import("util");
|
|
10711
|
+
const execFileP8 = promisify8(execFile8);
|
|
10712
|
+
await execFileP8("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
|
|
10637
10713
|
return;
|
|
10638
10714
|
}
|
|
10639
10715
|
}
|
|
10640
10716
|
|
|
10641
|
-
// src/commands/
|
|
10717
|
+
// src/commands/link.ts
|
|
10718
|
+
var import_node_child_process3 = require("child_process");
|
|
10719
|
+
var import_node_crypto = require("crypto");
|
|
10642
10720
|
var import_picocolors11 = __toESM(require("picocolors"));
|
|
10721
|
+
|
|
10722
|
+
// src/agents/claude/local-token.ts
|
|
10723
|
+
var import_node_child_process2 = require("child_process");
|
|
10724
|
+
var fs16 = __toESM(require("fs"));
|
|
10725
|
+
var os15 = __toESM(require("os"));
|
|
10726
|
+
var path24 = __toESM(require("path"));
|
|
10727
|
+
var import_node_util3 = require("util");
|
|
10728
|
+
var execFileP7 = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
|
|
10729
|
+
function claudeCredentialsPath() {
|
|
10730
|
+
return path24.join(os15.homedir(), ".claude", ".credentials.json");
|
|
10731
|
+
}
|
|
10732
|
+
async function extractLocalClaudeToken() {
|
|
10733
|
+
const flat = claudeCredentialsPath();
|
|
10734
|
+
if (fs16.existsSync(flat)) {
|
|
10735
|
+
const credential = fs16.readFileSync(flat, "utf8").trim();
|
|
10736
|
+
if (credential.length > 0) {
|
|
10737
|
+
return { method: "oauth", credential, source: "flat-file" };
|
|
10738
|
+
}
|
|
10739
|
+
}
|
|
10740
|
+
if (process.platform === "darwin") {
|
|
10741
|
+
try {
|
|
10742
|
+
const { stdout } = await execFileP7(
|
|
10743
|
+
"security",
|
|
10744
|
+
["find-generic-password", "-s", "Claude Code-credentials", "-w"],
|
|
10745
|
+
{ maxBuffer: 1024 * 1024 }
|
|
10746
|
+
);
|
|
10747
|
+
const credential = stdout.trim();
|
|
10748
|
+
if (credential.length > 0) {
|
|
10749
|
+
return { method: "oauth", credential, source: "macos-keychain" };
|
|
10750
|
+
}
|
|
10751
|
+
} catch {
|
|
10752
|
+
}
|
|
10753
|
+
}
|
|
10754
|
+
return null;
|
|
10755
|
+
}
|
|
10756
|
+
function claudeCredentialsMtime() {
|
|
10757
|
+
const flat = claudeCredentialsPath();
|
|
10758
|
+
try {
|
|
10759
|
+
return fs16.statSync(flat).mtimeMs;
|
|
10760
|
+
} catch {
|
|
10761
|
+
return null;
|
|
10762
|
+
}
|
|
10763
|
+
}
|
|
10764
|
+
|
|
10765
|
+
// src/agents/codex/local-token.ts
|
|
10766
|
+
var fs17 = __toESM(require("fs"));
|
|
10767
|
+
var os16 = __toESM(require("os"));
|
|
10768
|
+
var path25 = __toESM(require("path"));
|
|
10769
|
+
function codexCredentialsPath() {
|
|
10770
|
+
return path25.join(os16.homedir(), ".codex", "auth.json");
|
|
10771
|
+
}
|
|
10772
|
+
async function extractLocalCodexToken() {
|
|
10773
|
+
const file = codexCredentialsPath();
|
|
10774
|
+
if (!fs17.existsSync(file)) return null;
|
|
10775
|
+
const credential = fs17.readFileSync(file, "utf8").trim();
|
|
10776
|
+
if (credential.length === 0) return null;
|
|
10777
|
+
return { method: "oauth", credential, source: "flat-file" };
|
|
10778
|
+
}
|
|
10779
|
+
function codexCredentialsMtime() {
|
|
10780
|
+
const file = codexCredentialsPath();
|
|
10781
|
+
try {
|
|
10782
|
+
return fs17.statSync(file).mtimeMs;
|
|
10783
|
+
} catch {
|
|
10784
|
+
return null;
|
|
10785
|
+
}
|
|
10786
|
+
}
|
|
10787
|
+
|
|
10788
|
+
// src/commands/link.ts
|
|
10789
|
+
var AGENT_META = {
|
|
10790
|
+
claude: {
|
|
10791
|
+
internalId: "claude",
|
|
10792
|
+
publicId: "claude_code",
|
|
10793
|
+
binary: "claude",
|
|
10794
|
+
loginArgs: ["login"],
|
|
10795
|
+
displayName: "Claude Code",
|
|
10796
|
+
vendor: "Anthropic",
|
|
10797
|
+
credentialsHint: "~/.claude/.credentials.json (or macOS Keychain)",
|
|
10798
|
+
extract: extractLocalClaudeToken,
|
|
10799
|
+
mtime: claudeCredentialsMtime
|
|
10800
|
+
},
|
|
10801
|
+
codex: {
|
|
10802
|
+
internalId: "codex",
|
|
10803
|
+
publicId: "codex",
|
|
10804
|
+
binary: "codex",
|
|
10805
|
+
loginArgs: ["login"],
|
|
10806
|
+
displayName: "Codex",
|
|
10807
|
+
vendor: "OpenAI",
|
|
10808
|
+
credentialsHint: "~/.codex/auth.json",
|
|
10809
|
+
extract: extractLocalCodexToken,
|
|
10810
|
+
mtime: codexCredentialsMtime
|
|
10811
|
+
}
|
|
10812
|
+
};
|
|
10813
|
+
function parseLinkArgs(args2) {
|
|
10814
|
+
const positional = args2.find((a) => !a.startsWith("--"));
|
|
10815
|
+
if (!positional) {
|
|
10816
|
+
throw new Error(
|
|
10817
|
+
`Usage: codeam link <agent>
|
|
10818
|
+
agent: ${Object.keys(AGENT_META).join(" | ")}`
|
|
10819
|
+
);
|
|
10820
|
+
}
|
|
10821
|
+
const normalised = positional === "claude_code" ? "claude" : positional;
|
|
10822
|
+
if (normalised !== "claude" && normalised !== "codex") {
|
|
10823
|
+
throw new Error(
|
|
10824
|
+
`Unknown agent "${positional}". Valid: ${Object.keys(AGENT_META).join(", ")}`
|
|
10825
|
+
);
|
|
10826
|
+
}
|
|
10827
|
+
const reuseExisting = args2.includes("--reuse-existing");
|
|
10828
|
+
return { agent: normalised, reuseExisting };
|
|
10829
|
+
}
|
|
10830
|
+
async function link(args2 = []) {
|
|
10831
|
+
const { agent, reuseExisting } = parseLinkArgs(args2);
|
|
10832
|
+
const meta = AGENT_META[agent];
|
|
10833
|
+
showIntro();
|
|
10834
|
+
console.log(
|
|
10835
|
+
import_picocolors11.default.bold(` Link ${meta.displayName}`) + import_picocolors11.default.dim(` \xB7 ${meta.vendor}`)
|
|
10836
|
+
);
|
|
10837
|
+
console.log("");
|
|
10838
|
+
const pluginId = (0, import_node_crypto.randomUUID)();
|
|
10839
|
+
const spin = dist_exports.spinner();
|
|
10840
|
+
spin.start("Requesting pairing code...");
|
|
10841
|
+
const pairing = await requestCode(pluginId);
|
|
10842
|
+
if (!pairing) {
|
|
10843
|
+
spin.stop("Failed");
|
|
10844
|
+
showError("Could not reach the server. Check your connection and try again.");
|
|
10845
|
+
process.exit(1);
|
|
10846
|
+
}
|
|
10847
|
+
spin.stop("Got pairing code");
|
|
10848
|
+
showPairingCode(pairing.code);
|
|
10849
|
+
console.log(import_picocolors11.default.dim(" Scan the QR or enter the code in CodeAgent Mobile."));
|
|
10850
|
+
console.log("");
|
|
10851
|
+
const waitSpin = dist_exports.spinner();
|
|
10852
|
+
const waitMsg = () => `Waiting for mobile pair... \xB7 expires in ${formatRemaining(pairing.expiresAt)}`;
|
|
10853
|
+
waitSpin.start(waitMsg());
|
|
10854
|
+
const countdown = setInterval(() => waitSpin.message(waitMsg()), 1e3);
|
|
10855
|
+
countdown.unref?.();
|
|
10856
|
+
const paired = await new Promise((resolve2, reject) => {
|
|
10857
|
+
let stopPoll = null;
|
|
10858
|
+
const sigint = () => {
|
|
10859
|
+
clearInterval(countdown);
|
|
10860
|
+
stopPoll?.();
|
|
10861
|
+
reject(new Error("cancelled"));
|
|
10862
|
+
};
|
|
10863
|
+
stopPoll = pollStatus(
|
|
10864
|
+
pluginId,
|
|
10865
|
+
(info) => {
|
|
10866
|
+
process.removeListener("SIGINT", sigint);
|
|
10867
|
+
clearInterval(countdown);
|
|
10868
|
+
waitSpin.stop("Paired");
|
|
10869
|
+
resolve2(info);
|
|
10870
|
+
},
|
|
10871
|
+
() => {
|
|
10872
|
+
clearInterval(countdown);
|
|
10873
|
+
waitSpin.stop("Timed out");
|
|
10874
|
+
reject(new Error("Pairing timed out after 5 minutes. Run codeam link again."));
|
|
10875
|
+
}
|
|
10876
|
+
);
|
|
10877
|
+
process.once("SIGINT", sigint);
|
|
10878
|
+
});
|
|
10879
|
+
if (!paired.pluginAuthToken) {
|
|
10880
|
+
showError(
|
|
10881
|
+
"Backend did not return a pluginAuthToken \u2014 upgrade api-v2 (deploy includes the link endpoint)."
|
|
10882
|
+
);
|
|
10883
|
+
process.exit(1);
|
|
10884
|
+
}
|
|
10885
|
+
addSession({
|
|
10886
|
+
id: paired.sessionId,
|
|
10887
|
+
pluginId,
|
|
10888
|
+
userName: paired.userName,
|
|
10889
|
+
userEmail: paired.userEmail,
|
|
10890
|
+
plan: paired.plan,
|
|
10891
|
+
pairedAt: Date.now(),
|
|
10892
|
+
pluginAuthToken: paired.pluginAuthToken,
|
|
10893
|
+
agent: meta.internalId
|
|
10894
|
+
});
|
|
10895
|
+
saveCliConfig({ ...loadCliConfig(), preferredAgent: meta.internalId });
|
|
10896
|
+
let token = await meta.extract();
|
|
10897
|
+
if (token && reuseExisting) {
|
|
10898
|
+
showInfo(`Reusing existing ${meta.displayName} token at ${import_picocolors11.default.bold(meta.credentialsHint)}.`);
|
|
10899
|
+
} else {
|
|
10900
|
+
const beforeMtime = meta.mtime();
|
|
10901
|
+
showInfo(`Launching ${import_picocolors11.default.bold(`${meta.binary} ${meta.loginArgs.join(" ")}`)} \u2014 complete the sign-in in your browser, then return here.`);
|
|
10902
|
+
console.log("");
|
|
10903
|
+
const code = await runAgentLogin(meta);
|
|
10904
|
+
console.log("");
|
|
10905
|
+
if (code !== 0) {
|
|
10906
|
+
showError(
|
|
10907
|
+
`${meta.binary} ${meta.loginArgs.join(" ")} exited with code ${code}. Re-run when ready.`
|
|
10908
|
+
);
|
|
10909
|
+
process.exit(1);
|
|
10910
|
+
}
|
|
10911
|
+
const refreshed = await meta.extract();
|
|
10912
|
+
const afterMtime = meta.mtime();
|
|
10913
|
+
if (!refreshed) {
|
|
10914
|
+
showError(
|
|
10915
|
+
`${meta.displayName} login finished but no credential was found at ${meta.credentialsHint}. Re-run when ready.`
|
|
10916
|
+
);
|
|
10917
|
+
process.exit(1);
|
|
10918
|
+
}
|
|
10919
|
+
if (token && refreshed.credential === token.credential && beforeMtime !== null && afterMtime !== null && afterMtime <= beforeMtime) {
|
|
10920
|
+
showError(
|
|
10921
|
+
`${meta.displayName} login didn't produce a fresh token. Re-run when ready, or pass --reuse-existing to keep the current one.`
|
|
10922
|
+
);
|
|
10923
|
+
process.exit(1);
|
|
10924
|
+
}
|
|
10925
|
+
token = refreshed;
|
|
10926
|
+
}
|
|
10927
|
+
const uploadSpin = dist_exports.spinner();
|
|
10928
|
+
uploadSpin.start("Sealing credential in your vault...");
|
|
10929
|
+
const result = await postLinkCredential({
|
|
10930
|
+
agentId: meta.publicId,
|
|
10931
|
+
sessionId: paired.sessionId,
|
|
10932
|
+
pluginId,
|
|
10933
|
+
pluginAuthToken: paired.pluginAuthToken,
|
|
10934
|
+
method: token.method,
|
|
10935
|
+
credential: token.credential
|
|
10936
|
+
});
|
|
10937
|
+
if (!result.ok) {
|
|
10938
|
+
uploadSpin.stop("Failed");
|
|
10939
|
+
if (result.status === 401) {
|
|
10940
|
+
showError(
|
|
10941
|
+
"Pair token rejected by the backend (401). Re-run `codeam link` to start fresh."
|
|
10942
|
+
);
|
|
10943
|
+
} else if (result.status === 404) {
|
|
10944
|
+
showError(
|
|
10945
|
+
`${meta.displayName} link endpoint not available on this backend (404). The api-v2 deployment may not yet include the /api/plugin/agents/:agentId/link route.`
|
|
10946
|
+
);
|
|
10947
|
+
} else {
|
|
10948
|
+
showError(`Upload failed: ${result.message}`);
|
|
10949
|
+
}
|
|
10950
|
+
process.exit(1);
|
|
10951
|
+
}
|
|
10952
|
+
uploadSpin.stop("Linked");
|
|
10953
|
+
console.log("");
|
|
10954
|
+
showSuccess(`${meta.displayName} is now linked to ${paired.userEmail || paired.userName}.`);
|
|
10955
|
+
showInfo(
|
|
10956
|
+
`Your codespaces and @codeagent mentions can now use ${meta.displayName} without you signing in again.`
|
|
10957
|
+
);
|
|
10958
|
+
console.log("");
|
|
10959
|
+
}
|
|
10960
|
+
function runAgentLogin(meta) {
|
|
10961
|
+
return new Promise((resolve2) => {
|
|
10962
|
+
const child = (0, import_node_child_process3.spawn)(meta.binary, meta.loginArgs, { stdio: "inherit" });
|
|
10963
|
+
child.on("error", (err) => {
|
|
10964
|
+
if (err.code === "ENOENT") {
|
|
10965
|
+
showError(
|
|
10966
|
+
`${meta.binary} binary not found on PATH. Install ${meta.displayName} first, then re-run \`codeam link ${meta.internalId}\`.`
|
|
10967
|
+
);
|
|
10968
|
+
resolve2(127);
|
|
10969
|
+
return;
|
|
10970
|
+
}
|
|
10971
|
+
showError(`Failed to launch ${meta.binary}: ${err.message}`);
|
|
10972
|
+
resolve2(1);
|
|
10973
|
+
});
|
|
10974
|
+
child.on("exit", (code) => resolve2(code ?? 1));
|
|
10975
|
+
});
|
|
10976
|
+
}
|
|
10977
|
+
|
|
10978
|
+
// src/commands/version.ts
|
|
10979
|
+
var import_picocolors12 = __toESM(require("picocolors"));
|
|
10643
10980
|
function version() {
|
|
10644
|
-
const v = true ? "2.
|
|
10645
|
-
console.log(`${
|
|
10981
|
+
const v = true ? "2.16.0" : "unknown";
|
|
10982
|
+
console.log(`${import_picocolors12.default.bold("codeam-cli")} ${import_picocolors12.default.cyan(v)}`);
|
|
10646
10983
|
}
|
|
10647
10984
|
|
|
10648
10985
|
// src/commands/help.ts
|
|
10649
|
-
var
|
|
10986
|
+
var import_picocolors13 = __toESM(require("picocolors"));
|
|
10650
10987
|
function help() {
|
|
10651
10988
|
const lines = [
|
|
10652
10989
|
"",
|
|
10653
|
-
` ${
|
|
10990
|
+
` ${import_picocolors13.default.bold(import_picocolors13.default.magenta("codeam-cli"))} ${import_picocolors13.default.dim("\u2014 remote-control AI coding agents from your phone")}`,
|
|
10654
10991
|
"",
|
|
10655
|
-
` ${
|
|
10656
|
-
` ${
|
|
10992
|
+
` ${import_picocolors13.default.bold("Usage")}`,
|
|
10993
|
+
` ${import_picocolors13.default.cyan("codeam")} ${import_picocolors13.default.dim("[command]")}`,
|
|
10657
10994
|
"",
|
|
10658
|
-
` ${
|
|
10659
|
-
` ${
|
|
10660
|
-
` ${
|
|
10661
|
-
` ${
|
|
10662
|
-
` ${
|
|
10663
|
-
` ${
|
|
10664
|
-
` ${
|
|
10665
|
-
` ${
|
|
10666
|
-
` ${
|
|
10667
|
-
` ${
|
|
10668
|
-
` ${
|
|
10669
|
-
` ${
|
|
10670
|
-
` ${
|
|
10995
|
+
` ${import_picocolors13.default.bold("Commands")}`,
|
|
10996
|
+
` ${import_picocolors13.default.white("codeam")} ${import_picocolors13.default.dim("start the active agent with mobile control")}`,
|
|
10997
|
+
` ${import_picocolors13.default.white("codeam <agent>")} ${import_picocolors13.default.dim("start a specific agent \u2014 e.g. claude, codex")}`,
|
|
10998
|
+
` ${import_picocolors13.default.white("codeam pair")} ${import_picocolors13.default.dim("pair a new mobile device (interactive)")}`,
|
|
10999
|
+
` ${import_picocolors13.default.white("codeam pair --agent <id>")} ${import_picocolors13.default.dim("pair non-interactively for a specific agent")}`,
|
|
11000
|
+
` ${import_picocolors13.default.white("codeam sessions")} ${import_picocolors13.default.dim("list paired devices")}`,
|
|
11001
|
+
` ${import_picocolors13.default.white("codeam sessions switch")} ${import_picocolors13.default.dim("switch the active paired session")}`,
|
|
11002
|
+
` ${import_picocolors13.default.white("codeam sessions delete <id>")} ${import_picocolors13.default.dim("remove a specific paired session")}`,
|
|
11003
|
+
` ${import_picocolors13.default.white("codeam status")} ${import_picocolors13.default.dim("show connection info")}`,
|
|
11004
|
+
` ${import_picocolors13.default.white("codeam logout")} ${import_picocolors13.default.dim("remove all paired sessions")}`,
|
|
11005
|
+
` ${import_picocolors13.default.white("codeam link <agent>")} ${import_picocolors13.default.dim("link an agent (claude, codex) to your CodeAgent account")}`,
|
|
11006
|
+
` ${import_picocolors13.default.white("codeam deploy")} ${import_picocolors13.default.dim("provision a cloud workspace (Codespaces) and pair it")}`,
|
|
11007
|
+
` ${import_picocolors13.default.white("codeam deploy ls | list")} ${import_picocolors13.default.dim("list deployed cloud workspaces")}`,
|
|
11008
|
+
` ${import_picocolors13.default.white("codeam deploy stop | remove")} ${import_picocolors13.default.dim("stop a deployed workspace session")}`,
|
|
10671
11009
|
"",
|
|
10672
|
-
` ${
|
|
10673
|
-
` ${
|
|
10674
|
-
` ${
|
|
11010
|
+
` ${import_picocolors13.default.bold("Flags")}`,
|
|
11011
|
+
` ${import_picocolors13.default.white("-v, --version")} ${import_picocolors13.default.dim("print the CLI version")}`,
|
|
11012
|
+
` ${import_picocolors13.default.white("-h, --help")} ${import_picocolors13.default.dim("show this help")}`,
|
|
10675
11013
|
"",
|
|
10676
|
-
` ${
|
|
10677
|
-
` ${
|
|
10678
|
-
` ${
|
|
11014
|
+
` ${import_picocolors13.default.bold("Links")}`,
|
|
11015
|
+
` ${import_picocolors13.default.dim("Docs:")} ${import_picocolors13.default.green("https://www.codeagent-mobile.com")}`,
|
|
11016
|
+
` ${import_picocolors13.default.dim("Issues:")} ${import_picocolors13.default.green("https://github.com/edgar-durand/codeagent-mobile-clients/issues")}`,
|
|
10679
11017
|
""
|
|
10680
11018
|
];
|
|
10681
11019
|
process.stdout.write(lines.join("\n") + "\n");
|
|
10682
11020
|
}
|
|
10683
11021
|
|
|
10684
11022
|
// src/lib/updateNotifier.ts
|
|
10685
|
-
var
|
|
10686
|
-
var
|
|
10687
|
-
var
|
|
11023
|
+
var fs18 = __toESM(require("fs"));
|
|
11024
|
+
var os17 = __toESM(require("os"));
|
|
11025
|
+
var path26 = __toESM(require("path"));
|
|
10688
11026
|
var https7 = __toESM(require("https"));
|
|
10689
|
-
var
|
|
11027
|
+
var import_picocolors14 = __toESM(require("picocolors"));
|
|
10690
11028
|
var PKG_NAME = "codeam-cli";
|
|
10691
11029
|
var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
10692
11030
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
10693
11031
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
10694
11032
|
function cachePath() {
|
|
10695
|
-
const dir =
|
|
10696
|
-
return
|
|
11033
|
+
const dir = path26.join(os17.homedir(), ".codeam");
|
|
11034
|
+
return path26.join(dir, "update-check.json");
|
|
10697
11035
|
}
|
|
10698
11036
|
function readCache() {
|
|
10699
11037
|
try {
|
|
10700
|
-
const raw =
|
|
11038
|
+
const raw = fs18.readFileSync(cachePath(), "utf8");
|
|
10701
11039
|
const parsed = JSON.parse(raw);
|
|
10702
11040
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
10703
11041
|
return parsed;
|
|
@@ -10708,8 +11046,8 @@ function readCache() {
|
|
|
10708
11046
|
function writeCache(cache) {
|
|
10709
11047
|
try {
|
|
10710
11048
|
const file = cachePath();
|
|
10711
|
-
|
|
10712
|
-
|
|
11049
|
+
fs18.mkdirSync(path26.dirname(file), { recursive: true });
|
|
11050
|
+
fs18.writeFileSync(file, JSON.stringify(cache));
|
|
10713
11051
|
} catch {
|
|
10714
11052
|
}
|
|
10715
11053
|
}
|
|
@@ -10765,11 +11103,11 @@ function fetchLatest() {
|
|
|
10765
11103
|
}
|
|
10766
11104
|
function notifyIfStale(currentVersion, latest) {
|
|
10767
11105
|
if (compareSemver(latest, currentVersion) <= 0) return;
|
|
10768
|
-
const arrow =
|
|
10769
|
-
const cmd =
|
|
11106
|
+
const arrow = import_picocolors14.default.dim("\u2192");
|
|
11107
|
+
const cmd = import_picocolors14.default.cyan("npm install -g codeam-cli");
|
|
10770
11108
|
const lines = [
|
|
10771
11109
|
"",
|
|
10772
|
-
` ${
|
|
11110
|
+
` ${import_picocolors14.default.yellow("\u25CF")} ${import_picocolors14.default.bold("Update available")} ${import_picocolors14.default.dim(currentVersion)} ${arrow} ${import_picocolors14.default.green(latest)}`,
|
|
10773
11111
|
` Run ${cmd} to upgrade.`,
|
|
10774
11112
|
""
|
|
10775
11113
|
];
|
|
@@ -10780,7 +11118,7 @@ function checkForUpdates() {
|
|
|
10780
11118
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
10781
11119
|
if (process.env.CI) return;
|
|
10782
11120
|
if (!process.stdout.isTTY) return;
|
|
10783
|
-
const current = true ? "2.
|
|
11121
|
+
const current = true ? "2.16.0" : null;
|
|
10784
11122
|
if (!current) return;
|
|
10785
11123
|
const cache = readCache();
|
|
10786
11124
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -10818,6 +11156,8 @@ async function main() {
|
|
|
10818
11156
|
return status();
|
|
10819
11157
|
case "logout":
|
|
10820
11158
|
return logout();
|
|
11159
|
+
case "link":
|
|
11160
|
+
return link(args);
|
|
10821
11161
|
case "deploy":
|
|
10822
11162
|
if (args[0] === "ls" || args[0] === "list") return deployList();
|
|
10823
11163
|
if (args[0] === "stop" || args[0] === "remove") return deployStop();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.16.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",
|