codeam-cli 2.39.52 → 2.39.53
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 +196 -63
- 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.52] — 2026-06-20
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Set up Headroom on self-hosted deploys
|
|
12
|
+
|
|
7
13
|
## [2.39.51] — 2026-06-20
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -5388,7 +5388,7 @@ function readAnonId() {
|
|
|
5388
5388
|
}
|
|
5389
5389
|
function superProperties() {
|
|
5390
5390
|
return {
|
|
5391
|
-
cliVersion: true ? "2.39.
|
|
5391
|
+
cliVersion: true ? "2.39.53" : "0.0.0-dev",
|
|
5392
5392
|
nodeVersion: process.version,
|
|
5393
5393
|
platform: process.platform,
|
|
5394
5394
|
arch: process.arch,
|
|
@@ -5547,7 +5547,7 @@ var os4 = __toESM(require("os"));
|
|
|
5547
5547
|
// package.json
|
|
5548
5548
|
var package_default = {
|
|
5549
5549
|
name: "codeam-cli",
|
|
5550
|
-
version: "2.39.
|
|
5550
|
+
version: "2.39.53",
|
|
5551
5551
|
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.",
|
|
5552
5552
|
type: "commonjs",
|
|
5553
5553
|
main: "dist/index.js",
|
|
@@ -17269,79 +17269,212 @@ var CONTROL_AGENT_META = {
|
|
|
17269
17269
|
supportedAuthKinds: ["oauth_token"],
|
|
17270
17270
|
preferredAuthKind: "oauth_token"
|
|
17271
17271
|
};
|
|
17272
|
-
|
|
17273
|
-
|
|
17274
|
-
|
|
17275
|
-
|
|
17276
|
-
|
|
17277
|
-
|
|
17278
|
-
|
|
17279
|
-
|
|
17280
|
-
|
|
17281
|
-
|
|
17282
|
-
|
|
17283
|
-
|
|
17284
|
-
|
|
17285
|
-
|
|
17286
|
-
});
|
|
17272
|
+
var PEP668_MARKER = "externally-managed-environment";
|
|
17273
|
+
var PM_INSTALL_TIMEOUT_MS = 18e4;
|
|
17274
|
+
var PIP_INSTALL_TIMEOUT_MS = 12e4;
|
|
17275
|
+
var defaultHeadroomRunner = {
|
|
17276
|
+
which(cmd) {
|
|
17277
|
+
try {
|
|
17278
|
+
(0, import_node_child_process12.execFileSync)("which", [cmd], { stdio: "ignore" });
|
|
17279
|
+
return true;
|
|
17280
|
+
} catch {
|
|
17281
|
+
return false;
|
|
17282
|
+
}
|
|
17283
|
+
},
|
|
17284
|
+
run(cmd, args2, opts = {}) {
|
|
17285
|
+
return new Promise((resolve7) => {
|
|
17286
|
+
const child = (0, import_node_child_process12.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"] });
|
|
17287
|
+
let stderrBuf = "";
|
|
17287
17288
|
let settled = false;
|
|
17288
|
-
const done = (
|
|
17289
|
+
const done = (code) => {
|
|
17289
17290
|
if (settled) return;
|
|
17290
17291
|
settled = true;
|
|
17291
|
-
|
|
17292
|
+
resolve7({ code, stderr: stderrBuf });
|
|
17292
17293
|
};
|
|
17293
|
-
|
|
17294
|
-
const line = b.toString().replace(/\n
|
|
17295
|
-
if (line) log.info("host-agent", `headroom
|
|
17296
|
-
};
|
|
17297
|
-
child.
|
|
17298
|
-
|
|
17299
|
-
|
|
17300
|
-
|
|
17301
|
-
|
|
17302
|
-
|
|
17303
|
-
|
|
17304
|
-
|
|
17305
|
-
|
|
17306
|
-
|
|
17294
|
+
child.stdout?.on("data", (b) => {
|
|
17295
|
+
const line = b.toString().replace(/\n+$/, "");
|
|
17296
|
+
if (line) log.info("host-agent", `headroom[${cmd}]: ${line}`);
|
|
17297
|
+
});
|
|
17298
|
+
child.stderr?.on("data", (b) => {
|
|
17299
|
+
const chunk = b.toString();
|
|
17300
|
+
stderrBuf += chunk;
|
|
17301
|
+
const line = chunk.replace(/\n+$/, "");
|
|
17302
|
+
if (line) log.info("host-agent", `headroom[${cmd}]: ${line}`);
|
|
17303
|
+
});
|
|
17304
|
+
const timeoutMs = opts.timeoutMs;
|
|
17305
|
+
let timer;
|
|
17306
|
+
if (timeoutMs !== void 0) {
|
|
17307
|
+
timer = setTimeout(() => {
|
|
17308
|
+
log.warn("host-agent", `headroom[${cmd}] timed out after ${timeoutMs / 1e3}s \u2014 aborting`);
|
|
17309
|
+
try {
|
|
17310
|
+
child.kill("SIGTERM");
|
|
17311
|
+
} catch {
|
|
17312
|
+
}
|
|
17313
|
+
done(null);
|
|
17314
|
+
}, timeoutMs);
|
|
17315
|
+
}
|
|
17307
17316
|
child.once("exit", (code) => {
|
|
17308
|
-
clearTimeout(timer);
|
|
17309
|
-
|
|
17310
|
-
log.info("host-agent", "headroom pip install succeeded");
|
|
17311
|
-
} else {
|
|
17312
|
-
log.warn("host-agent", `headroom pip install exited code=${String(code)} \u2014 skipping Headroom`);
|
|
17313
|
-
}
|
|
17314
|
-
done(code === 0);
|
|
17317
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
17318
|
+
done(code);
|
|
17315
17319
|
});
|
|
17316
17320
|
child.once("error", (e) => {
|
|
17317
|
-
clearTimeout(timer);
|
|
17318
|
-
|
|
17319
|
-
|
|
17321
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
17322
|
+
log.trace("host-agent", `headroom[${cmd}] spawn error: ${e.message}`);
|
|
17323
|
+
done(null);
|
|
17320
17324
|
});
|
|
17321
17325
|
});
|
|
17322
|
-
|
|
17323
|
-
|
|
17326
|
+
}
|
|
17327
|
+
};
|
|
17328
|
+
var PACKAGE_MANAGERS = [
|
|
17329
|
+
"apt-get",
|
|
17330
|
+
"apk",
|
|
17331
|
+
"dnf",
|
|
17332
|
+
"yum",
|
|
17333
|
+
"pacman",
|
|
17334
|
+
"zypper"
|
|
17335
|
+
];
|
|
17336
|
+
var PROVISION_RECIPES = {
|
|
17337
|
+
"apt-get": {
|
|
17338
|
+
update: ["apt-get", "update"],
|
|
17339
|
+
install: ["apt-get", "install", "-y", "python3", "python3-pip", "python3-venv", "ca-certificates", "curl"]
|
|
17340
|
+
},
|
|
17341
|
+
apk: {
|
|
17342
|
+
install: ["apk", "add", "--no-cache", "python3", "py3-pip", "ca-certificates", "curl"]
|
|
17343
|
+
},
|
|
17344
|
+
dnf: {
|
|
17345
|
+
install: ["dnf", "install", "-y", "python3", "python3-pip", "ca-certificates", "curl"]
|
|
17346
|
+
},
|
|
17347
|
+
yum: {
|
|
17348
|
+
install: ["yum", "install", "-y", "python3", "python3-pip", "ca-certificates", "curl"]
|
|
17349
|
+
},
|
|
17350
|
+
pacman: {
|
|
17351
|
+
install: ["pacman", "-Sy", "--noconfirm", "python", "python-pip", "ca-certificates", "curl"]
|
|
17352
|
+
},
|
|
17353
|
+
zypper: {
|
|
17354
|
+
install: ["zypper", "--non-interactive", "install", "python3", "python3-pip", "ca-certificates", "curl"]
|
|
17355
|
+
}
|
|
17356
|
+
};
|
|
17357
|
+
function detectPackageManager(runner) {
|
|
17358
|
+
for (const pm of PACKAGE_MANAGERS) {
|
|
17359
|
+
if (runner.which(pm)) return pm;
|
|
17360
|
+
}
|
|
17361
|
+
return null;
|
|
17362
|
+
}
|
|
17363
|
+
async function ensurePip(runner) {
|
|
17364
|
+
if (runner.which("pip") || runner.which("pip3")) {
|
|
17365
|
+
return true;
|
|
17366
|
+
}
|
|
17367
|
+
const pm = detectPackageManager(runner);
|
|
17368
|
+
if (!pm) {
|
|
17369
|
+
log.warn(
|
|
17370
|
+
"host-agent",
|
|
17371
|
+
"pip is absent and no known package manager (apt-get/apk/dnf/yum/pacman/zypper) found \u2014 skipping Headroom"
|
|
17372
|
+
);
|
|
17373
|
+
return false;
|
|
17374
|
+
}
|
|
17375
|
+
const isRoot = process.getuid?.() === 0;
|
|
17376
|
+
const escalate = (argv) => isRoot ? { cmd: argv[0], args: argv.slice(1) } : { cmd: "sudo", args: argv };
|
|
17377
|
+
const recipe = PROVISION_RECIPES[pm];
|
|
17378
|
+
log.info(
|
|
17379
|
+
"host-agent",
|
|
17380
|
+
`pip absent \u2014 provisioning bare box (python3+pip+ca-certificates+curl) via ${pm}`
|
|
17381
|
+
);
|
|
17382
|
+
try {
|
|
17383
|
+
if (recipe.update) {
|
|
17384
|
+
const { cmd: cmd2, args: args3 } = escalate(recipe.update);
|
|
17385
|
+
const updateResult = await runner.run(cmd2, args3, { timeoutMs: PM_INSTALL_TIMEOUT_MS });
|
|
17386
|
+
if (updateResult.code !== 0) {
|
|
17387
|
+
log.warn(
|
|
17388
|
+
"host-agent",
|
|
17389
|
+
`${pm} update exited ${String(updateResult.code)} \u2014 attempting install anyway`
|
|
17390
|
+
);
|
|
17391
|
+
}
|
|
17392
|
+
}
|
|
17393
|
+
const { cmd, args: args2 } = escalate(recipe.install);
|
|
17394
|
+
const installResult = await runner.run(cmd, args2, { timeoutMs: PM_INSTALL_TIMEOUT_MS });
|
|
17395
|
+
if (installResult.code !== 0) {
|
|
17396
|
+
log.warn(
|
|
17397
|
+
"host-agent",
|
|
17398
|
+
`${pm} bare-box provision failed (code=${String(installResult.code)}) \u2014 skipping Headroom`
|
|
17399
|
+
);
|
|
17400
|
+
return false;
|
|
17401
|
+
}
|
|
17402
|
+
} catch (e) {
|
|
17403
|
+
log.warn(
|
|
17404
|
+
"host-agent",
|
|
17405
|
+
`bare-box provision threw unexpectedly: ${e instanceof Error ? e.message : String(e)} \u2014 skipping Headroom`
|
|
17406
|
+
);
|
|
17407
|
+
return false;
|
|
17408
|
+
}
|
|
17409
|
+
log.info("host-agent", `bare box provisioned via ${pm} (python3+pip+ca-certificates+curl)`);
|
|
17410
|
+
return true;
|
|
17411
|
+
}
|
|
17412
|
+
async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner) {
|
|
17413
|
+
const PIP_PACKAGES = [
|
|
17414
|
+
"headroom-ai",
|
|
17415
|
+
"fastapi",
|
|
17416
|
+
"uvicorn",
|
|
17417
|
+
"httpx[http2]",
|
|
17418
|
+
"websockets",
|
|
17419
|
+
"zstandard"
|
|
17420
|
+
];
|
|
17421
|
+
const pipAvailable = await ensurePip(runner);
|
|
17422
|
+
if (!pipAvailable) {
|
|
17423
|
+
return false;
|
|
17424
|
+
}
|
|
17425
|
+
const installOk = await (async () => {
|
|
17426
|
+
const baseArgs = ["-m", "pip", "install", "--quiet", ...PIP_PACKAGES];
|
|
17427
|
+
const firstResult = await runner.run("python3", baseArgs, {
|
|
17428
|
+
timeoutMs: PIP_INSTALL_TIMEOUT_MS
|
|
17429
|
+
});
|
|
17430
|
+
if (firstResult.code === 0) {
|
|
17431
|
+
log.info("host-agent", "headroom pip install succeeded");
|
|
17432
|
+
return true;
|
|
17433
|
+
}
|
|
17434
|
+
if (firstResult.stderr.includes(PEP668_MARKER)) {
|
|
17435
|
+
log.info(
|
|
17436
|
+
"host-agent",
|
|
17437
|
+
"PEP 668 externally-managed-environment detected \u2014 retrying with --break-system-packages"
|
|
17438
|
+
);
|
|
17439
|
+
const retryResult = await runner.run(
|
|
17440
|
+
"python3",
|
|
17441
|
+
[...baseArgs, "--break-system-packages"],
|
|
17442
|
+
{ timeoutMs: PIP_INSTALL_TIMEOUT_MS }
|
|
17443
|
+
);
|
|
17444
|
+
if (retryResult.code === 0) {
|
|
17445
|
+
log.info("host-agent", "headroom pip install succeeded (--break-system-packages)");
|
|
17446
|
+
return true;
|
|
17447
|
+
}
|
|
17448
|
+
log.warn(
|
|
17449
|
+
"host-agent",
|
|
17450
|
+
`headroom pip install failed even with --break-system-packages (code=${String(retryResult.code)}) \u2014 skipping Headroom`
|
|
17451
|
+
);
|
|
17452
|
+
return false;
|
|
17453
|
+
}
|
|
17454
|
+
log.warn(
|
|
17455
|
+
"host-agent",
|
|
17456
|
+
`headroom pip install exited code=${String(firstResult.code)} \u2014 skipping Headroom`
|
|
17457
|
+
);
|
|
17458
|
+
return false;
|
|
17459
|
+
})();
|
|
17324
17460
|
if (!installOk) {
|
|
17325
17461
|
return false;
|
|
17326
17462
|
}
|
|
17463
|
+
if (!runner.which("headroom")) {
|
|
17464
|
+
log.warn("host-agent", "headroom not found on PATH after install \u2014 skipping init");
|
|
17465
|
+
return false;
|
|
17466
|
+
}
|
|
17327
17467
|
const initOk = await new Promise((resolve7) => {
|
|
17328
|
-
(0, import_node_child_process12.execFile)("
|
|
17329
|
-
if (
|
|
17330
|
-
|
|
17468
|
+
(0, import_node_child_process12.execFile)("headroom", ["init", "--global", agent], (initErr, stdout, stderr) => {
|
|
17469
|
+
if (initErr) {
|
|
17470
|
+
const detail = (stderr || initErr.message).replace(/\n+$/g, "");
|
|
17471
|
+
log.warn("host-agent", `headroom init failed (best-effort): ${detail}`);
|
|
17331
17472
|
resolve7(false);
|
|
17332
|
-
|
|
17473
|
+
} else {
|
|
17474
|
+
if (stdout.trim()) log.info("host-agent", `headroom init: ${stdout.trim()}`);
|
|
17475
|
+
log.info("host-agent", "headroom init --global succeeded");
|
|
17476
|
+
resolve7(true);
|
|
17333
17477
|
}
|
|
17334
|
-
(0, import_node_child_process12.execFile)("headroom", ["init", "--global", agent], (initErr, stdout, stderr) => {
|
|
17335
|
-
if (initErr) {
|
|
17336
|
-
const detail = (stderr || initErr.message).replace(/\n+$/g, "");
|
|
17337
|
-
log.warn("host-agent", `headroom init failed (best-effort): ${detail}`);
|
|
17338
|
-
resolve7(false);
|
|
17339
|
-
} else {
|
|
17340
|
-
if (stdout.trim()) log.info("host-agent", `headroom init: ${stdout.trim()}`);
|
|
17341
|
-
log.info("host-agent", "headroom init --global succeeded");
|
|
17342
|
-
resolve7(true);
|
|
17343
|
-
}
|
|
17344
|
-
});
|
|
17345
17478
|
});
|
|
17346
17479
|
});
|
|
17347
17480
|
if (!initOk) {
|
|
@@ -27711,7 +27844,7 @@ function checkChokidar() {
|
|
|
27711
27844
|
}
|
|
27712
27845
|
async function doctor(args2 = []) {
|
|
27713
27846
|
const json = args2.includes("--json");
|
|
27714
|
-
const cliVersion = true ? "2.39.
|
|
27847
|
+
const cliVersion = true ? "2.39.53" : "0.0.0-dev";
|
|
27715
27848
|
const apiBase2 = resolveApiBaseUrl();
|
|
27716
27849
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
27717
27850
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -27910,7 +28043,7 @@ async function completion(args2) {
|
|
|
27910
28043
|
// src/commands/version.ts
|
|
27911
28044
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
27912
28045
|
function version2() {
|
|
27913
|
-
const v = true ? "2.39.
|
|
28046
|
+
const v = true ? "2.39.53" : "unknown";
|
|
27914
28047
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
27915
28048
|
}
|
|
27916
28049
|
|
|
@@ -28196,7 +28329,7 @@ function checkForUpdates() {
|
|
|
28196
28329
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
28197
28330
|
if (process.env.CI) return;
|
|
28198
28331
|
if (!process.stdout.isTTY) return;
|
|
28199
|
-
const current = true ? "2.39.
|
|
28332
|
+
const current = true ? "2.39.53" : null;
|
|
28200
28333
|
if (!current) return;
|
|
28201
28334
|
const cache = readCache();
|
|
28202
28335
|
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.53",
|
|
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",
|