codeam-cli 2.49.2 → 2.49.3
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 -14
- 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.49.2] — 2026-06-27
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Set agentId in ACP HandlerContext so headroom enable works for claude/codex
|
|
12
|
+
|
|
7
13
|
## [2.49.1] — 2026-06-27
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -5397,7 +5397,7 @@ function readAnonId() {
|
|
|
5397
5397
|
}
|
|
5398
5398
|
function superProperties() {
|
|
5399
5399
|
return {
|
|
5400
|
-
cliVersion: true ? "2.49.
|
|
5400
|
+
cliVersion: true ? "2.49.3" : "0.0.0-dev",
|
|
5401
5401
|
nodeVersion: process.version,
|
|
5402
5402
|
platform: process.platform,
|
|
5403
5403
|
arch: process.arch,
|
|
@@ -5578,7 +5578,7 @@ var os4 = __toESM(require("os"));
|
|
|
5578
5578
|
// package.json
|
|
5579
5579
|
var package_default = {
|
|
5580
5580
|
name: "codeam-cli",
|
|
5581
|
-
version: "2.49.
|
|
5581
|
+
version: "2.49.3",
|
|
5582
5582
|
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.",
|
|
5583
5583
|
type: "commonjs",
|
|
5584
5584
|
main: "dist/index.js",
|
|
@@ -14747,7 +14747,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
14747
14747
|
if (process.env.NODE_ENV === "test") return;
|
|
14748
14748
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
14749
14749
|
if (process.env.CI) return;
|
|
14750
|
-
const current = true ? "2.49.
|
|
14750
|
+
const current = true ? "2.49.3" : null;
|
|
14751
14751
|
if (!current) return;
|
|
14752
14752
|
const cache = readCache();
|
|
14753
14753
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -14764,7 +14764,7 @@ function checkForUpdates() {
|
|
|
14764
14764
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
14765
14765
|
if (process.env.CI) return;
|
|
14766
14766
|
if (!process.stdout.isTTY) return;
|
|
14767
|
-
const current = true ? "2.49.
|
|
14767
|
+
const current = true ? "2.49.3" : null;
|
|
14768
14768
|
if (!current) return;
|
|
14769
14769
|
const cache = readCache();
|
|
14770
14770
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -14884,14 +14884,17 @@ var defaultHeadroomRunner = {
|
|
|
14884
14884
|
const spawnEnv = opts.env ?? process.env;
|
|
14885
14885
|
const child = (0, import_node_child_process14.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"], env: spawnEnv });
|
|
14886
14886
|
let stderrBuf = "";
|
|
14887
|
+
let stdoutBuf = "";
|
|
14887
14888
|
let settled = false;
|
|
14888
14889
|
const done = (code) => {
|
|
14889
14890
|
if (settled) return;
|
|
14890
14891
|
settled = true;
|
|
14891
|
-
resolve7({ code, stderr: stderrBuf });
|
|
14892
|
+
resolve7({ code, stderr: stderrBuf, stdout: stdoutBuf });
|
|
14892
14893
|
};
|
|
14893
14894
|
child.stdout?.on("data", (b) => {
|
|
14894
|
-
const
|
|
14895
|
+
const chunk = b.toString();
|
|
14896
|
+
stdoutBuf += chunk;
|
|
14897
|
+
const line = chunk.replace(/\n+$/, "");
|
|
14895
14898
|
if (line) log.info("host-agent", `headroom[${cmd}]: ${line}`);
|
|
14896
14899
|
});
|
|
14897
14900
|
child.stderr?.on("data", (b) => {
|
|
@@ -14979,6 +14982,10 @@ function detectPackageManager(runner) {
|
|
|
14979
14982
|
}
|
|
14980
14983
|
return null;
|
|
14981
14984
|
}
|
|
14985
|
+
function escalateCommand(argv) {
|
|
14986
|
+
const isRoot = process.getuid?.() === 0;
|
|
14987
|
+
return isRoot ? { cmd: argv[0], args: argv.slice(1) } : { cmd: "sudo", args: argv };
|
|
14988
|
+
}
|
|
14982
14989
|
async function ensurePip(runner) {
|
|
14983
14990
|
if (runner.which("pip") || runner.which("pip3")) {
|
|
14984
14991
|
return true;
|
|
@@ -14991,8 +14998,7 @@ async function ensurePip(runner) {
|
|
|
14991
14998
|
);
|
|
14992
14999
|
return false;
|
|
14993
15000
|
}
|
|
14994
|
-
const
|
|
14995
|
-
const escalate = (argv) => isRoot ? { cmd: argv[0], args: argv.slice(1) } : { cmd: "sudo", args: argv };
|
|
15001
|
+
const escalate = escalateCommand;
|
|
14996
15002
|
const recipe = PROVISION_RECIPES[pm];
|
|
14997
15003
|
log.info(
|
|
14998
15004
|
"host-agent",
|
|
@@ -15157,6 +15163,132 @@ async function getFreeDiskBytes(dir) {
|
|
|
15157
15163
|
return null;
|
|
15158
15164
|
}
|
|
15159
15165
|
}
|
|
15166
|
+
async function resolveHeadroomPython(runner) {
|
|
15167
|
+
const PROBE_TIMEOUT_MS = 5e3;
|
|
15168
|
+
const SUFFIXES = ["python3.13", "python3.12", "python3.11", "python3.10"];
|
|
15169
|
+
const PREFIX_DIRS = ["/opt/homebrew/bin", "/usr/local/bin"];
|
|
15170
|
+
const probe = async (candidate) => {
|
|
15171
|
+
try {
|
|
15172
|
+
const r = await runner.run(
|
|
15173
|
+
candidate,
|
|
15174
|
+
["-c", 'import sys; print("%d.%d" % sys.version_info[:2])'],
|
|
15175
|
+
{ timeoutMs: PROBE_TIMEOUT_MS }
|
|
15176
|
+
);
|
|
15177
|
+
if (r.code !== 0) return false;
|
|
15178
|
+
const parts = (r.stdout ?? "").trim().split(".");
|
|
15179
|
+
const major = parseInt(parts[0] ?? "", 10);
|
|
15180
|
+
const minor = parseInt(parts[1] ?? "", 10);
|
|
15181
|
+
if (!(major === 3 && minor >= 10)) return false;
|
|
15182
|
+
const pipCheck = await runner.run(candidate, ["-m", "pip", "--version"], {
|
|
15183
|
+
timeoutMs: PROBE_TIMEOUT_MS
|
|
15184
|
+
});
|
|
15185
|
+
return pipCheck.code === 0;
|
|
15186
|
+
} catch {
|
|
15187
|
+
return false;
|
|
15188
|
+
}
|
|
15189
|
+
};
|
|
15190
|
+
for (const suffix of SUFFIXES) {
|
|
15191
|
+
try {
|
|
15192
|
+
if (await probe(suffix)) return suffix;
|
|
15193
|
+
} catch {
|
|
15194
|
+
}
|
|
15195
|
+
}
|
|
15196
|
+
for (const suffix of SUFFIXES) {
|
|
15197
|
+
for (const dir of PREFIX_DIRS) {
|
|
15198
|
+
const candidate = `${dir}/${suffix}`;
|
|
15199
|
+
try {
|
|
15200
|
+
if (await probe(candidate)) return candidate;
|
|
15201
|
+
} catch {
|
|
15202
|
+
}
|
|
15203
|
+
}
|
|
15204
|
+
}
|
|
15205
|
+
try {
|
|
15206
|
+
if (await probe("python3")) return "python3";
|
|
15207
|
+
} catch {
|
|
15208
|
+
}
|
|
15209
|
+
return null;
|
|
15210
|
+
}
|
|
15211
|
+
var PY_INSTALL_TIMEOUT_MS = 6e5;
|
|
15212
|
+
var MODERN_PYTHON_RECIPES = {
|
|
15213
|
+
"apt-get": [
|
|
15214
|
+
["apt-get", "install", "-y", "python3.12"],
|
|
15215
|
+
["apt-get", "install", "-y", "python3.11"],
|
|
15216
|
+
["apt-get", "install", "-y", "python3"]
|
|
15217
|
+
],
|
|
15218
|
+
dnf: [
|
|
15219
|
+
["dnf", "install", "-y", "python3.12"],
|
|
15220
|
+
["dnf", "install", "-y", "python3"]
|
|
15221
|
+
],
|
|
15222
|
+
yum: [
|
|
15223
|
+
["yum", "install", "-y", "python3.12"],
|
|
15224
|
+
["yum", "install", "-y", "python3"]
|
|
15225
|
+
],
|
|
15226
|
+
apk: [["apk", "add", "--no-cache", "python3"]],
|
|
15227
|
+
pacman: [["pacman", "-Sy", "--noconfirm", "python"]],
|
|
15228
|
+
zypper: [
|
|
15229
|
+
["zypper", "--non-interactive", "install", "python311"],
|
|
15230
|
+
["zypper", "--non-interactive", "install", "python3"]
|
|
15231
|
+
]
|
|
15232
|
+
};
|
|
15233
|
+
async function ensureModernPython(runner) {
|
|
15234
|
+
let py = await resolveHeadroomPython(runner);
|
|
15235
|
+
if (py !== null) return py;
|
|
15236
|
+
try {
|
|
15237
|
+
if (process.platform === "darwin") {
|
|
15238
|
+
if (runner.which("brew")) {
|
|
15239
|
+
log.info("host-agent", "no Python \u22653.10 found \u2014 installing python@3.12 via Homebrew");
|
|
15240
|
+
const r = await runner.run("brew", ["install", "python@3.12"], {
|
|
15241
|
+
timeoutMs: PY_INSTALL_TIMEOUT_MS
|
|
15242
|
+
});
|
|
15243
|
+
if (r.code !== 0) {
|
|
15244
|
+
log.warn(
|
|
15245
|
+
"host-agent",
|
|
15246
|
+
`brew install python@3.12 exited ${String(r.code)} \u2014 will re-probe anyway`
|
|
15247
|
+
);
|
|
15248
|
+
}
|
|
15249
|
+
} else {
|
|
15250
|
+
log.warn(
|
|
15251
|
+
"host-agent",
|
|
15252
|
+
"no Python \u22653.10 and Homebrew is absent \u2014 cannot auto-install Python on macOS"
|
|
15253
|
+
);
|
|
15254
|
+
}
|
|
15255
|
+
} else if (process.platform === "linux") {
|
|
15256
|
+
const pm = detectPackageManager(runner);
|
|
15257
|
+
if (!pm) {
|
|
15258
|
+
log.warn(
|
|
15259
|
+
"host-agent",
|
|
15260
|
+
"no Python \u22653.10 and no known package manager (apt-get/apk/dnf/yum/pacman/zypper) \u2014 cannot auto-install Python"
|
|
15261
|
+
);
|
|
15262
|
+
} else {
|
|
15263
|
+
log.info("host-agent", `no Python \u22653.10 found \u2014 installing a modern Python via ${pm}`);
|
|
15264
|
+
for (const argv of MODERN_PYTHON_RECIPES[pm]) {
|
|
15265
|
+
const { cmd, args: args2 } = escalateCommand(argv);
|
|
15266
|
+
const r = await runner.run(cmd, args2, { timeoutMs: PY_INSTALL_TIMEOUT_MS });
|
|
15267
|
+
if (r.code === 0) {
|
|
15268
|
+
log.info("host-agent", `installed Python package via ${pm}: ${argv.join(" ")}`);
|
|
15269
|
+
break;
|
|
15270
|
+
}
|
|
15271
|
+
log.warn(
|
|
15272
|
+
"host-agent",
|
|
15273
|
+
`${pm} install '${argv.join(" ")}' exited ${String(r.code)} \u2014 trying next`
|
|
15274
|
+
);
|
|
15275
|
+
}
|
|
15276
|
+
}
|
|
15277
|
+
} else {
|
|
15278
|
+
log.warn(
|
|
15279
|
+
"host-agent",
|
|
15280
|
+
`no Python \u22653.10 and platform '${process.platform}' has no auto-install path`
|
|
15281
|
+
);
|
|
15282
|
+
}
|
|
15283
|
+
} catch (e) {
|
|
15284
|
+
log.warn(
|
|
15285
|
+
"host-agent",
|
|
15286
|
+
`Python auto-install threw unexpectedly (best-effort): ${e instanceof Error ? e.message : String(e)}`
|
|
15287
|
+
);
|
|
15288
|
+
}
|
|
15289
|
+
py = await resolveHeadroomPython(runner);
|
|
15290
|
+
return py;
|
|
15291
|
+
}
|
|
15160
15292
|
async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner, opts = {}) {
|
|
15161
15293
|
const extras = opts.extras ?? ["proxy", "code"];
|
|
15162
15294
|
const onProgress = opts.onProgress ?? (() => {
|
|
@@ -15166,12 +15298,21 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
|
|
|
15166
15298
|
if (!pipAvailable) {
|
|
15167
15299
|
return false;
|
|
15168
15300
|
}
|
|
15301
|
+
const py = await ensureModernPython(runner);
|
|
15302
|
+
if (py === null) {
|
|
15303
|
+
log.warn(
|
|
15304
|
+
"host-agent",
|
|
15305
|
+
"Headroom needs Python \u22653.10 and auto-install failed (no brew on macOS / package manager couldn\u2019t provide it) \u2014 skipping Headroom"
|
|
15306
|
+
);
|
|
15307
|
+
return false;
|
|
15308
|
+
}
|
|
15309
|
+
log.info("host-agent", `Headroom will use interpreter: ${py}`);
|
|
15169
15310
|
const pipInstall = async (pkgs, extraArgs, timeoutMs) => {
|
|
15170
15311
|
const base = ["-m", "pip", "install", "--quiet", ...extraArgs, ...pkgs];
|
|
15171
|
-
const r = await runner.run(
|
|
15312
|
+
const r = await runner.run(py, base, { timeoutMs });
|
|
15172
15313
|
if (r.code === 0) return true;
|
|
15173
15314
|
if (r.stderr.includes(PEP668_MARKER)) {
|
|
15174
|
-
const r2 = await runner.run(
|
|
15315
|
+
const r2 = await runner.run(py, [...base, "--break-system-packages"], { timeoutMs });
|
|
15175
15316
|
return r2.code === 0;
|
|
15176
15317
|
}
|
|
15177
15318
|
return false;
|
|
@@ -15190,7 +15331,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
|
|
|
15190
15331
|
'snapshot_download("chopratejas/kompress-v2-base", allow_patterns=["*.json","onnx/*.onnx","kompress-int8-wo.onnx"])',
|
|
15191
15332
|
'snapshot_download("answerdotai/ModernBERT-base", allow_patterns=["*.json","tokenizer*","*.txt","vocab*","merges*"])'
|
|
15192
15333
|
].join("\n");
|
|
15193
|
-
const dl = await runner.run(
|
|
15334
|
+
const dl = await runner.run(py, ["-c", predownloadPy], {
|
|
15194
15335
|
timeoutMs: ENGINE_INSTALL_TIMEOUT_MS
|
|
15195
15336
|
});
|
|
15196
15337
|
log.info(
|
|
@@ -15259,7 +15400,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process14.s
|
|
|
15259
15400
|
detached: false
|
|
15260
15401
|
});
|
|
15261
15402
|
function currentCliVersion() {
|
|
15262
|
-
return true ? "2.49.
|
|
15403
|
+
return true ? "2.49.3" : null;
|
|
15263
15404
|
}
|
|
15264
15405
|
function runCmd(cmd, args2, timeoutMs) {
|
|
15265
15406
|
return new Promise((resolve7) => {
|
|
@@ -30201,7 +30342,7 @@ function checkChokidar() {
|
|
|
30201
30342
|
}
|
|
30202
30343
|
async function doctor(args2 = []) {
|
|
30203
30344
|
const json = args2.includes("--json");
|
|
30204
|
-
const cliVersion = true ? "2.49.
|
|
30345
|
+
const cliVersion = true ? "2.49.3" : "0.0.0-dev";
|
|
30205
30346
|
const apiBase2 = resolveApiBaseUrl();
|
|
30206
30347
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
30207
30348
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -30400,7 +30541,7 @@ async function completion(args2) {
|
|
|
30400
30541
|
// src/commands/version.ts
|
|
30401
30542
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
30402
30543
|
function version2() {
|
|
30403
|
-
const v = true ? "2.49.
|
|
30544
|
+
const v = true ? "2.49.3" : "unknown";
|
|
30404
30545
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
30405
30546
|
}
|
|
30406
30547
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.49.
|
|
3
|
+
"version": "2.49.3",
|
|
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",
|