codeam-cli 2.39.31 → 2.39.32
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 +6 -0
- package/dist/index.js +155 -50
- package/package.json +1 -1
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.31] — 2026-06-18
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Host-agent re-enrollment + self-heal on deleted host
|
|
12
|
+
|
|
7
13
|
## [2.39.30] — 2026-06-18
|
|
8
14
|
|
|
9
15
|
### Added
|
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.
|
|
501
|
+
version: "2.39.32",
|
|
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",
|
|
@@ -5908,7 +5908,7 @@ function readAnonId() {
|
|
|
5908
5908
|
}
|
|
5909
5909
|
function superProperties() {
|
|
5910
5910
|
return {
|
|
5911
|
-
cliVersion: true ? "2.39.
|
|
5911
|
+
cliVersion: true ? "2.39.32" : "0.0.0-dev",
|
|
5912
5912
|
nodeVersion: process.version,
|
|
5913
5913
|
platform: process.platform,
|
|
5914
5914
|
arch: process.arch,
|
|
@@ -26393,6 +26393,30 @@ async function reportProgress(auth, step, message) {
|
|
|
26393
26393
|
} catch {
|
|
26394
26394
|
}
|
|
26395
26395
|
}
|
|
26396
|
+
async function reportDeployProgress(auth, deployId, step, message, sessionId) {
|
|
26397
|
+
try {
|
|
26398
|
+
const controller = new AbortController();
|
|
26399
|
+
const timer = setTimeout(() => controller.abort(), PROGRESS_TIMEOUT_MS);
|
|
26400
|
+
timer.unref?.();
|
|
26401
|
+
try {
|
|
26402
|
+
await fetch(`${apiBase()}/api/self-hosted/deploy-progress`, {
|
|
26403
|
+
method: "POST",
|
|
26404
|
+
headers: { "Content-Type": "application/json", ...vercelBypassHeader() },
|
|
26405
|
+
body: JSON.stringify({
|
|
26406
|
+
...auth,
|
|
26407
|
+
deployId,
|
|
26408
|
+
step,
|
|
26409
|
+
message,
|
|
26410
|
+
...sessionId ? { sessionId } : {}
|
|
26411
|
+
}),
|
|
26412
|
+
signal: controller.signal
|
|
26413
|
+
});
|
|
26414
|
+
} finally {
|
|
26415
|
+
clearTimeout(timer);
|
|
26416
|
+
}
|
|
26417
|
+
} catch {
|
|
26418
|
+
}
|
|
26419
|
+
}
|
|
26396
26420
|
|
|
26397
26421
|
// src/commands/host.ts
|
|
26398
26422
|
function readTokenFlag(args2) {
|
|
@@ -26455,12 +26479,46 @@ function isAbsolutePathTarget(target) {
|
|
|
26455
26479
|
function selfHostedWorkspaceRoot() {
|
|
26456
26480
|
return path54.join(os33.homedir(), ".codeam", "self-hosted");
|
|
26457
26481
|
}
|
|
26458
|
-
function
|
|
26482
|
+
function nonInteractiveGitEnv() {
|
|
26483
|
+
return {
|
|
26484
|
+
...process.env,
|
|
26485
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
26486
|
+
GIT_ASKPASS: "",
|
|
26487
|
+
GCM_INTERACTIVE: "never"
|
|
26488
|
+
};
|
|
26489
|
+
}
|
|
26490
|
+
function githubOwnerRepo(repoRef) {
|
|
26491
|
+
const trimmed = repoRef.trim();
|
|
26492
|
+
const shorthand = /^([^/\s]+)\/([^/\s]+?)(?:\.git)?$/.exec(trimmed);
|
|
26493
|
+
if (shorthand && !/^https?:\/\//.test(trimmed) && !trimmed.startsWith("git@")) {
|
|
26494
|
+
return { owner: shorthand[1], repo: shorthand[2] };
|
|
26495
|
+
}
|
|
26496
|
+
const httpsMatch = /^https?:\/\/github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
26497
|
+
if (httpsMatch) return { owner: httpsMatch[1], repo: httpsMatch[2] };
|
|
26498
|
+
return null;
|
|
26499
|
+
}
|
|
26500
|
+
function repoCloneUrl(repoRef, cloneToken) {
|
|
26459
26501
|
const trimmed = repoRef.trim();
|
|
26502
|
+
if (cloneToken) {
|
|
26503
|
+
const gh = githubOwnerRepo(trimmed);
|
|
26504
|
+
if (gh) {
|
|
26505
|
+
return `https://x-access-token:${cloneToken}@github.com/${gh.owner}/${gh.repo}.git`;
|
|
26506
|
+
}
|
|
26507
|
+
}
|
|
26460
26508
|
if (/^https?:\/\//.test(trimmed) || trimmed.startsWith("git@")) return trimmed;
|
|
26461
26509
|
return `https://github.com/${trimmed.replace(/\.git$/, "")}.git`;
|
|
26462
26510
|
}
|
|
26463
|
-
|
|
26511
|
+
function maskCloneUrl(url) {
|
|
26512
|
+
return url.replace(/(https?:\/\/)[^@/]+@/, "$1***@");
|
|
26513
|
+
}
|
|
26514
|
+
function maskToken(text, cloneToken) {
|
|
26515
|
+
const masked = maskCloneUrl(text);
|
|
26516
|
+
if (cloneToken && cloneToken.length > 0) {
|
|
26517
|
+
return masked.split(cloneToken).join("***");
|
|
26518
|
+
}
|
|
26519
|
+
return masked;
|
|
26520
|
+
}
|
|
26521
|
+
async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
|
|
26464
26522
|
if (isAbsolutePathTarget(repoOrPath)) {
|
|
26465
26523
|
if (!fs42.existsSync(repoOrPath)) {
|
|
26466
26524
|
throw new Error(`deploy target path does not exist: ${repoOrPath}`);
|
|
@@ -26472,10 +26530,17 @@ async function prepareWorkspace(repoOrPath, deployId) {
|
|
|
26472
26530
|
return dest;
|
|
26473
26531
|
}
|
|
26474
26532
|
fs42.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
|
|
26475
|
-
|
|
26476
|
-
|
|
26477
|
-
|
|
26478
|
-
|
|
26533
|
+
const cloneUrl = repoCloneUrl(repoOrPath, cloneToken);
|
|
26534
|
+
try {
|
|
26535
|
+
await execFileP9("git", ["clone", "--depth", "1", cloneUrl, dest], {
|
|
26536
|
+
timeout: 12e4,
|
|
26537
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
26538
|
+
env: nonInteractiveGitEnv()
|
|
26539
|
+
});
|
|
26540
|
+
} catch (err) {
|
|
26541
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
26542
|
+
throw new Error(`git clone failed for ${maskCloneUrl(cloneUrl)}: ${maskToken(reason, cloneToken)}`);
|
|
26543
|
+
}
|
|
26479
26544
|
return dest;
|
|
26480
26545
|
}
|
|
26481
26546
|
|
|
@@ -26560,6 +26625,9 @@ function isDeployPayload(p2) {
|
|
|
26560
26625
|
if (typeof p2.deployId !== "string" || typeof p2.repoOrPath !== "string" || typeof p2.agentId !== "string" || typeof p2.autoPairToken !== "string") {
|
|
26561
26626
|
return false;
|
|
26562
26627
|
}
|
|
26628
|
+
if (p2.cloneToken !== void 0 && typeof p2.cloneToken !== "string") {
|
|
26629
|
+
return false;
|
|
26630
|
+
}
|
|
26563
26631
|
const hasHouse = isHouseProxy(p2.houseProxy);
|
|
26564
26632
|
const hasSealed = typeof p2.sealedAgentAuth === "string";
|
|
26565
26633
|
return hasHouse || hasSealed;
|
|
@@ -26578,7 +26646,7 @@ var CONTROL_AGENT_META = {
|
|
|
26578
26646
|
var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process13.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
|
|
26579
26647
|
cwd,
|
|
26580
26648
|
env: { ...process.env, ...env },
|
|
26581
|
-
stdio: "ignore",
|
|
26649
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
26582
26650
|
detached: false
|
|
26583
26651
|
});
|
|
26584
26652
|
var defaultOnIdentityRejected = () => {
|
|
@@ -26731,43 +26799,86 @@ var HostAgentSupervisor = class {
|
|
|
26731
26799
|
"host-agent",
|
|
26732
26800
|
`deploy id=${payload.deployId.slice(0, 8)} agent=${payload.agentId} target=${payload.repoOrPath}`
|
|
26733
26801
|
);
|
|
26734
|
-
const
|
|
26735
|
-
|
|
26736
|
-
|
|
26737
|
-
|
|
26738
|
-
|
|
26739
|
-
|
|
26740
|
-
|
|
26741
|
-
|
|
26742
|
-
|
|
26743
|
-
|
|
26744
|
-
|
|
26745
|
-
|
|
26746
|
-
|
|
26747
|
-
|
|
26748
|
-
|
|
26749
|
-
|
|
26750
|
-
|
|
26751
|
-
|
|
26752
|
-
|
|
26753
|
-
|
|
26754
|
-
|
|
26755
|
-
|
|
26756
|
-
|
|
26802
|
+
const report = (step, message) => {
|
|
26803
|
+
void reportDeployProgress(
|
|
26804
|
+
{ hostId: this.identity.hostId, hostToken: this.identity.hostToken },
|
|
26805
|
+
payload.deployId,
|
|
26806
|
+
step,
|
|
26807
|
+
message
|
|
26808
|
+
);
|
|
26809
|
+
};
|
|
26810
|
+
try {
|
|
26811
|
+
report("preparing", "preparing workspace");
|
|
26812
|
+
if (!isAbsolutePathTarget(payload.repoOrPath)) {
|
|
26813
|
+
report("cloning", "cloning repository");
|
|
26814
|
+
}
|
|
26815
|
+
const cwd = await prepareWorkspace(payload.repoOrPath, payload.deployId, payload.cloneToken);
|
|
26816
|
+
let childEnv;
|
|
26817
|
+
let extraArgs = [];
|
|
26818
|
+
if (payload.houseProxy) {
|
|
26819
|
+
const { baseUrl, token, agentKind } = payload.houseProxy;
|
|
26820
|
+
childEnv = {
|
|
26821
|
+
ANTHROPIC_BASE_URL: baseUrl,
|
|
26822
|
+
ANTHROPIC_AUTH_TOKEN: token,
|
|
26823
|
+
ANTHROPIC_MODEL: "MiniMax-M3",
|
|
26824
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL: "MiniMax-M3",
|
|
26825
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: "MiniMax-M3",
|
|
26826
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL: "MiniMax-M3",
|
|
26827
|
+
CLAUDE_CODE_AUTO_COMPACT_WINDOW: "512000",
|
|
26828
|
+
API_TIMEOUT_MS: "3000000",
|
|
26829
|
+
CODEAM_AUTO_TOKEN: payload.autoPairToken
|
|
26830
|
+
};
|
|
26831
|
+
extraArgs = [`--agent=${agentKind || "claude"}`];
|
|
26832
|
+
} else {
|
|
26833
|
+
const auth = await this.resolveAgentAuth(this.identity, payload.sealedAgentAuth);
|
|
26834
|
+
const credEnv = provisionAgentCredentials(payload.agentId, auth, void 0);
|
|
26835
|
+
childEnv = {
|
|
26836
|
+
...credEnv,
|
|
26837
|
+
CODEAM_AUTO_TOKEN: payload.autoPairToken
|
|
26838
|
+
};
|
|
26839
|
+
}
|
|
26840
|
+
report("spawning", "starting agent");
|
|
26841
|
+
const proc = this.spawnChild(childEnv, cwd, extraArgs);
|
|
26842
|
+
const child = { deployId: payload.deployId, proc };
|
|
26843
|
+
this.children.set(payload.deployId, child);
|
|
26844
|
+
let tail = "";
|
|
26845
|
+
const appendTail = (buf) => {
|
|
26846
|
+
tail = (tail + buf.toString("utf8")).slice(-2e3);
|
|
26757
26847
|
};
|
|
26758
|
-
|
|
26759
|
-
|
|
26760
|
-
|
|
26761
|
-
|
|
26762
|
-
|
|
26763
|
-
|
|
26848
|
+
proc.stdout?.on("data", appendTail);
|
|
26849
|
+
proc.stderr?.on("data", appendTail);
|
|
26850
|
+
report("agent_starting", "agent process started");
|
|
26851
|
+
proc.once("exit", (code) => {
|
|
26852
|
+
const tracked = this.children.get(payload.deployId)?.proc === proc;
|
|
26853
|
+
if (tracked) {
|
|
26854
|
+
this.children.delete(payload.deployId);
|
|
26855
|
+
}
|
|
26856
|
+
if (tracked && typeof code === "number" && code !== 0) {
|
|
26857
|
+
const detail = tail.trim().slice(-500);
|
|
26858
|
+
report("failed", detail ? `agent exited (${code}): ${detail}` : `agent exited (${code})`);
|
|
26859
|
+
}
|
|
26860
|
+
});
|
|
26861
|
+
} catch (err) {
|
|
26862
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
26863
|
+
log.warn("host-agent", `deploy ${payload.deployId.slice(0, 8)} failed: ${message}`);
|
|
26864
|
+
const existing = this.children.get(payload.deployId);
|
|
26865
|
+
if (existing) {
|
|
26866
|
+
try {
|
|
26867
|
+
existing.proc.kill("SIGTERM");
|
|
26868
|
+
} catch {
|
|
26869
|
+
}
|
|
26764
26870
|
this.children.delete(payload.deployId);
|
|
26765
26871
|
}
|
|
26766
|
-
|
|
26872
|
+
report("failed", message);
|
|
26873
|
+
}
|
|
26767
26874
|
}
|
|
26768
|
-
/**
|
|
26875
|
+
/**
|
|
26876
|
+
* Kill the child for the given id. The backend correlates the session it
|
|
26877
|
+
* sends to this deploy, so the id matches the deployId we keyed on. No-op
|
|
26878
|
+
* if absent.
|
|
26879
|
+
*/
|
|
26769
26880
|
stopChild(sessionId) {
|
|
26770
|
-
const child = this.children.get(sessionId)
|
|
26881
|
+
const child = this.children.get(sessionId);
|
|
26771
26882
|
if (!child) {
|
|
26772
26883
|
log.trace("host-agent", `stop: no child for sessionId=${sessionId}`);
|
|
26773
26884
|
return;
|
|
@@ -26779,12 +26890,6 @@ var HostAgentSupervisor = class {
|
|
|
26779
26890
|
}
|
|
26780
26891
|
this.children.delete(child.deployId);
|
|
26781
26892
|
}
|
|
26782
|
-
findBySessionId(sessionId) {
|
|
26783
|
-
for (const child of this.children.values()) {
|
|
26784
|
-
if (child.sessionId === sessionId) return child;
|
|
26785
|
-
}
|
|
26786
|
-
return void 0;
|
|
26787
|
-
}
|
|
26788
26893
|
};
|
|
26789
26894
|
async function resolveHostIdentity(enrollToken) {
|
|
26790
26895
|
const existing = loadHostIdentity();
|
|
@@ -27008,7 +27113,7 @@ function checkChokidar() {
|
|
|
27008
27113
|
}
|
|
27009
27114
|
async function doctor(args2 = []) {
|
|
27010
27115
|
const json = args2.includes("--json");
|
|
27011
|
-
const cliVersion = true ? "2.39.
|
|
27116
|
+
const cliVersion = true ? "2.39.32" : "0.0.0-dev";
|
|
27012
27117
|
const apiBase2 = resolveApiBaseUrl();
|
|
27013
27118
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
27014
27119
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -27207,7 +27312,7 @@ async function completion(args2) {
|
|
|
27207
27312
|
// src/commands/version.ts
|
|
27208
27313
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
27209
27314
|
function version2() {
|
|
27210
|
-
const v = true ? "2.39.
|
|
27315
|
+
const v = true ? "2.39.32" : "unknown";
|
|
27211
27316
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
27212
27317
|
}
|
|
27213
27318
|
|
|
@@ -27493,7 +27598,7 @@ function checkForUpdates() {
|
|
|
27493
27598
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
27494
27599
|
if (process.env.CI) return;
|
|
27495
27600
|
if (!process.stdout.isTTY) return;
|
|
27496
|
-
const current = true ? "2.39.
|
|
27601
|
+
const current = true ? "2.39.32" : null;
|
|
27497
27602
|
if (!current) return;
|
|
27498
27603
|
const cache = readCache();
|
|
27499
27604
|
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.
|
|
3
|
+
"version": "2.39.32",
|
|
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",
|