codeam-cli 2.60.68 → 2.60.70
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 +370 -104
- 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.60.69] — 2026-07-15
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Provision uvx via the standalone uv installer and resolve per-user bin paths for MCP launchers
|
|
12
|
+
|
|
13
|
+
## [2.60.68] — 2026-07-15
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **shared:** 17 new COMING SOON integrations + official logos
|
|
18
|
+
|
|
7
19
|
## [2.60.67] — 2026-07-15
|
|
8
20
|
|
|
9
21
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -1068,11 +1068,11 @@ function quiet(fn) {
|
|
|
1068
1068
|
log.debug(TAG, "ignored sync error", err);
|
|
1069
1069
|
}
|
|
1070
1070
|
}
|
|
1071
|
-
function rmIfExistsQuiet(
|
|
1071
|
+
function rmIfExistsQuiet(path75) {
|
|
1072
1072
|
try {
|
|
1073
|
-
fs2.rmSync(
|
|
1073
|
+
fs2.rmSync(path75, { force: true });
|
|
1074
1074
|
} catch (err) {
|
|
1075
|
-
log.debug(TAG, `rmIfExists failed for ${
|
|
1075
|
+
log.debug(TAG, `rmIfExists failed for ${path75}`, err);
|
|
1076
1076
|
}
|
|
1077
1077
|
}
|
|
1078
1078
|
function killQuiet(target, signal = "SIGTERM") {
|
|
@@ -1256,8 +1256,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
1256
1256
|
return decodedFile;
|
|
1257
1257
|
};
|
|
1258
1258
|
}
|
|
1259
|
-
function normalizeWindowsPath(
|
|
1260
|
-
return
|
|
1259
|
+
function normalizeWindowsPath(path75) {
|
|
1260
|
+
return path75.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
1261
1261
|
}
|
|
1262
1262
|
|
|
1263
1263
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -3737,9 +3737,9 @@ async function addSourceContext(frames) {
|
|
|
3737
3737
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
3738
3738
|
return frames;
|
|
3739
3739
|
}
|
|
3740
|
-
function getContextLinesFromFile(
|
|
3740
|
+
function getContextLinesFromFile(path75, ranges, output) {
|
|
3741
3741
|
return new Promise((resolve7) => {
|
|
3742
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
3742
|
+
const stream = (0, import_node_fs.createReadStream)(path75);
|
|
3743
3743
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
3744
3744
|
input: stream
|
|
3745
3745
|
});
|
|
@@ -3754,7 +3754,7 @@ function getContextLinesFromFile(path74, ranges, output) {
|
|
|
3754
3754
|
let rangeStart = range[0];
|
|
3755
3755
|
let rangeEnd = range[1];
|
|
3756
3756
|
function onStreamError() {
|
|
3757
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
3757
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path75, 1);
|
|
3758
3758
|
lineReaded.close();
|
|
3759
3759
|
lineReaded.removeAllListeners();
|
|
3760
3760
|
destroyStreamAndResolve();
|
|
@@ -3815,8 +3815,8 @@ function clearLineContext(frame) {
|
|
|
3815
3815
|
delete frame.context_line;
|
|
3816
3816
|
delete frame.post_context;
|
|
3817
3817
|
}
|
|
3818
|
-
function shouldSkipContextLinesForFile(
|
|
3819
|
-
return
|
|
3818
|
+
function shouldSkipContextLinesForFile(path75) {
|
|
3819
|
+
return path75.startsWith("node:") || path75.endsWith(".min.js") || path75.endsWith(".min.cjs") || path75.endsWith(".min.mjs") || path75.startsWith("data:");
|
|
3820
3820
|
}
|
|
3821
3821
|
function shouldSkipContextLinesForFrame(frame) {
|
|
3822
3822
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -5970,7 +5970,7 @@ function readAnonId() {
|
|
|
5970
5970
|
}
|
|
5971
5971
|
function superProperties() {
|
|
5972
5972
|
return {
|
|
5973
|
-
cliVersion: true ? "2.60.
|
|
5973
|
+
cliVersion: true ? "2.60.70" : "0.0.0-dev",
|
|
5974
5974
|
nodeVersion: process.version,
|
|
5975
5975
|
platform: process.platform,
|
|
5976
5976
|
arch: process.arch,
|
|
@@ -6151,7 +6151,7 @@ var os4 = __toESM(require("os"));
|
|
|
6151
6151
|
// package.json
|
|
6152
6152
|
var package_default = {
|
|
6153
6153
|
name: "codeam-cli",
|
|
6154
|
-
version: "2.60.
|
|
6154
|
+
version: "2.60.70",
|
|
6155
6155
|
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.",
|
|
6156
6156
|
type: "commonjs",
|
|
6157
6157
|
main: "dist/index.js",
|
|
@@ -7294,7 +7294,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
7294
7294
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
7295
7295
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
7296
7296
|
// pair/reconnect). Older backends ignore the extra field.
|
|
7297
|
-
..."2.60.
|
|
7297
|
+
..."2.60.70" ? { ideVersion: "2.60.70" } : {}
|
|
7298
7298
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
7299
7299
|
}
|
|
7300
7300
|
/**
|
|
@@ -12127,10 +12127,10 @@ function buildForPlatform(platform3) {
|
|
|
12127
12127
|
var import_node_crypto4 = require("crypto");
|
|
12128
12128
|
|
|
12129
12129
|
// src/agents/claude/resolver.ts
|
|
12130
|
-
function buildClaudeLaunch(extraArgs = [],
|
|
12131
|
-
const found =
|
|
12130
|
+
function buildClaudeLaunch(extraArgs = [], os53 = createOsStrategy()) {
|
|
12131
|
+
const found = os53.findInPath("claude") ?? os53.findInPath("claude-code");
|
|
12132
12132
|
if (!found) return null;
|
|
12133
|
-
return
|
|
12133
|
+
return os53.buildLaunch(found, extraArgs);
|
|
12134
12134
|
}
|
|
12135
12135
|
|
|
12136
12136
|
// src/agents/claude/installer.ts
|
|
@@ -12720,8 +12720,8 @@ var ClaudeRuntimeStrategy = class {
|
|
|
12720
12720
|
meta = getAgent("claude");
|
|
12721
12721
|
mode = "interactive";
|
|
12722
12722
|
os;
|
|
12723
|
-
constructor(
|
|
12724
|
-
this.os =
|
|
12723
|
+
constructor(os53) {
|
|
12724
|
+
this.os = os53;
|
|
12725
12725
|
}
|
|
12726
12726
|
/**
|
|
12727
12727
|
* Claude Code's react-ink TUI enables bracketed-paste mode at
|
|
@@ -13501,8 +13501,8 @@ function codexCredentialLocator() {
|
|
|
13501
13501
|
function codexLoginLauncher() {
|
|
13502
13502
|
return {
|
|
13503
13503
|
async ensureInstalled() {
|
|
13504
|
-
const
|
|
13505
|
-
return
|
|
13504
|
+
const os53 = createOsStrategy();
|
|
13505
|
+
return os53.findInPath("codex") !== null;
|
|
13506
13506
|
},
|
|
13507
13507
|
launch() {
|
|
13508
13508
|
return (0, import_node_child_process4.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
@@ -13525,8 +13525,8 @@ var CodexRuntimeStrategy = class {
|
|
|
13525
13525
|
meta = getAgent("codex");
|
|
13526
13526
|
mode = "interactive";
|
|
13527
13527
|
os;
|
|
13528
|
-
constructor(
|
|
13529
|
-
this.os =
|
|
13528
|
+
constructor(os53) {
|
|
13529
|
+
this.os = os53;
|
|
13530
13530
|
}
|
|
13531
13531
|
async prepareLaunch() {
|
|
13532
13532
|
let binary = this.os.findInPath("codex");
|
|
@@ -13635,12 +13635,12 @@ var CodexRuntimeStrategy = class {
|
|
|
13635
13635
|
});
|
|
13636
13636
|
}
|
|
13637
13637
|
};
|
|
13638
|
-
function resolveNpm(
|
|
13639
|
-
return
|
|
13638
|
+
function resolveNpm(os53) {
|
|
13639
|
+
return os53.id === "win32" ? "npm.cmd" : "npm";
|
|
13640
13640
|
}
|
|
13641
|
-
async function installCodexViaNpm(
|
|
13641
|
+
async function installCodexViaNpm(os53) {
|
|
13642
13642
|
return new Promise((resolve7, reject) => {
|
|
13643
|
-
const proc = (0, import_node_child_process5.spawn)(resolveNpm(
|
|
13643
|
+
const proc = (0, import_node_child_process5.spawn)(resolveNpm(os53), ["install", "-g", "@openai/codex"], {
|
|
13644
13644
|
stdio: "inherit"
|
|
13645
13645
|
});
|
|
13646
13646
|
proc.on("close", (code) => {
|
|
@@ -13657,16 +13657,16 @@ async function installCodexViaNpm(os52) {
|
|
|
13657
13657
|
});
|
|
13658
13658
|
});
|
|
13659
13659
|
}
|
|
13660
|
-
function augmentNpmGlobalBin(
|
|
13660
|
+
function augmentNpmGlobalBin(os53) {
|
|
13661
13661
|
try {
|
|
13662
|
-
const result = (0, import_node_child_process5.spawnSync)(resolveNpm(
|
|
13662
|
+
const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os53), ["prefix", "-g"], {
|
|
13663
13663
|
stdio: ["ignore", "pipe", "ignore"]
|
|
13664
13664
|
});
|
|
13665
13665
|
if (result.status !== 0) return;
|
|
13666
13666
|
const prefix = result.stdout.toString().trim();
|
|
13667
13667
|
if (!prefix) return;
|
|
13668
|
-
const binDir =
|
|
13669
|
-
|
|
13668
|
+
const binDir = os53.id === "win32" ? prefix : path24.join(prefix, "bin");
|
|
13669
|
+
os53.augmentPath([binDir]);
|
|
13670
13670
|
} catch {
|
|
13671
13671
|
}
|
|
13672
13672
|
}
|
|
@@ -13750,9 +13750,9 @@ var import_node_child_process8 = require("child_process");
|
|
|
13750
13750
|
// src/agents/coderabbit/installer.ts
|
|
13751
13751
|
var import_node_child_process6 = require("child_process");
|
|
13752
13752
|
var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
|
|
13753
|
-
async function ensureCoderabbitInstalled(
|
|
13754
|
-
if (
|
|
13755
|
-
if (
|
|
13753
|
+
async function ensureCoderabbitInstalled(os53) {
|
|
13754
|
+
if (os53.findInPath("coderabbit")) return true;
|
|
13755
|
+
if (os53.id === "win32") {
|
|
13756
13756
|
console.error(
|
|
13757
13757
|
"\n \u2717 CodeRabbit on Windows requires WSL.\n Install the CLI inside your WSL distribution\n (curl -fsSL https://cli.coderabbit.ai/install.sh | sh)\n then re-run `codeam link coderabbit` from WSL.\n"
|
|
13758
13758
|
);
|
|
@@ -13767,8 +13767,8 @@ async function ensureCoderabbitInstalled(os52) {
|
|
|
13767
13767
|
proc.on("error", () => resolve7(false));
|
|
13768
13768
|
});
|
|
13769
13769
|
if (!ok) return false;
|
|
13770
|
-
|
|
13771
|
-
return
|
|
13770
|
+
os53.augmentPath([`${os53.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
13771
|
+
return os53.findInPath("coderabbit") !== null;
|
|
13772
13772
|
}
|
|
13773
13773
|
|
|
13774
13774
|
// src/agents/coderabbit/link.ts
|
|
@@ -13803,10 +13803,10 @@ function coderabbitCredentialLocator() {
|
|
|
13803
13803
|
validate: validateNonEmptyCredential
|
|
13804
13804
|
};
|
|
13805
13805
|
}
|
|
13806
|
-
function coderabbitLoginLauncher(
|
|
13806
|
+
function coderabbitLoginLauncher(os53) {
|
|
13807
13807
|
return {
|
|
13808
13808
|
async ensureInstalled() {
|
|
13809
|
-
return ensureCoderabbitInstalled(
|
|
13809
|
+
return ensureCoderabbitInstalled(os53);
|
|
13810
13810
|
},
|
|
13811
13811
|
launch() {
|
|
13812
13812
|
return (0, import_node_child_process7.spawn)("coderabbit", ["auth", "login"], { stdio: "inherit" });
|
|
@@ -13862,8 +13862,8 @@ function pickLine(obj) {
|
|
|
13862
13862
|
function toHunk(raw, groupSeverity) {
|
|
13863
13863
|
if (!raw || typeof raw !== "object") return null;
|
|
13864
13864
|
const o = raw;
|
|
13865
|
-
const
|
|
13866
|
-
if (!
|
|
13865
|
+
const path75 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
|
|
13866
|
+
if (!path75) return null;
|
|
13867
13867
|
const message = asString(
|
|
13868
13868
|
pick(o, [
|
|
13869
13869
|
"comment",
|
|
@@ -13880,7 +13880,7 @@ function toHunk(raw, groupSeverity) {
|
|
|
13880
13880
|
const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
|
|
13881
13881
|
const locObj = pick(o, ["location"]) ?? o;
|
|
13882
13882
|
return {
|
|
13883
|
-
path:
|
|
13883
|
+
path: path75.trim(),
|
|
13884
13884
|
line: pickLine(o) ?? pickLine(locObj),
|
|
13885
13885
|
severity,
|
|
13886
13886
|
message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
|
|
@@ -13963,10 +13963,10 @@ function parsePlain(stdout) {
|
|
|
13963
13963
|
for (const line of stdout.split(/\r?\n/)) {
|
|
13964
13964
|
const m = line.match(HUNK_LINE_RE);
|
|
13965
13965
|
if (!m) continue;
|
|
13966
|
-
const [,
|
|
13967
|
-
if (!
|
|
13966
|
+
const [, path75, lineNo, sevToken, message] = m;
|
|
13967
|
+
if (!path75 || !lineNo || !message) continue;
|
|
13968
13968
|
hunks.push({
|
|
13969
|
-
path:
|
|
13969
|
+
path: path75.trim(),
|
|
13970
13970
|
line: Number(lineNo),
|
|
13971
13971
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
13972
13972
|
message: message.trim().replace(/^[*-]\s+/, "")
|
|
@@ -14026,8 +14026,8 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
14026
14026
|
meta = getAgent("coderabbit");
|
|
14027
14027
|
mode = "batch";
|
|
14028
14028
|
os;
|
|
14029
|
-
constructor(
|
|
14030
|
-
this.os =
|
|
14029
|
+
constructor(os53) {
|
|
14030
|
+
this.os = os53;
|
|
14031
14031
|
}
|
|
14032
14032
|
getDefaultArgs() {
|
|
14033
14033
|
return ["review", "--agent"];
|
|
@@ -14298,10 +14298,10 @@ function cursorCredentialLocator() {
|
|
|
14298
14298
|
validate: validateNonEmptyCredential
|
|
14299
14299
|
};
|
|
14300
14300
|
}
|
|
14301
|
-
function cursorLoginLauncher(
|
|
14301
|
+
function cursorLoginLauncher(os53) {
|
|
14302
14302
|
return {
|
|
14303
14303
|
async ensureInstalled() {
|
|
14304
|
-
if (
|
|
14304
|
+
if (os53.findInPath("cursor-agent")) return true;
|
|
14305
14305
|
console.error(
|
|
14306
14306
|
"\n \u2717 cursor-agent binary not on PATH.\n Install Cursor (https://cursor.com/) and ensure the CLI\n plugin is enabled, then re-run `codeam link cursor`.\n"
|
|
14307
14307
|
);
|
|
@@ -14365,8 +14365,8 @@ var CursorRuntimeStrategy = class {
|
|
|
14365
14365
|
meta = getAgent("cursor");
|
|
14366
14366
|
mode = "interactive";
|
|
14367
14367
|
os;
|
|
14368
|
-
constructor(
|
|
14369
|
-
this.os =
|
|
14368
|
+
constructor(os53) {
|
|
14369
|
+
this.os = os53;
|
|
14370
14370
|
}
|
|
14371
14371
|
async prepareLaunch() {
|
|
14372
14372
|
const binary = this.os.findInPath("cursor-agent");
|
|
@@ -14582,10 +14582,10 @@ function aiderCredentialLocator() {
|
|
|
14582
14582
|
validate: validateNonEmptyCredential
|
|
14583
14583
|
};
|
|
14584
14584
|
}
|
|
14585
|
-
function aiderLoginLauncher(
|
|
14585
|
+
function aiderLoginLauncher(os53) {
|
|
14586
14586
|
return {
|
|
14587
14587
|
async ensureInstalled() {
|
|
14588
|
-
if (
|
|
14588
|
+
if (os53.findInPath("aider")) return true;
|
|
14589
14589
|
console.error(
|
|
14590
14590
|
"\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
|
|
14591
14591
|
);
|
|
@@ -14595,7 +14595,7 @@ function aiderLoginLauncher(os52) {
|
|
|
14595
14595
|
console.error(
|
|
14596
14596
|
"\n Aider has no interactive login flow.\n Set ANTHROPIC_API_KEY or OPENAI_API_KEY in your shell,\n or re-run `codeam link aider --api-key=<your-key>`.\n"
|
|
14597
14597
|
);
|
|
14598
|
-
return (0, import_node_child_process11.spawn)(
|
|
14598
|
+
return (0, import_node_child_process11.spawn)(os53.id === "win32" ? "cmd.exe" : "sh", os53.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
|
|
14599
14599
|
stdio: "ignore"
|
|
14600
14600
|
});
|
|
14601
14601
|
}
|
|
@@ -14667,8 +14667,8 @@ var AiderRuntimeStrategy = class {
|
|
|
14667
14667
|
meta = getAgent("aider");
|
|
14668
14668
|
mode = "interactive";
|
|
14669
14669
|
os;
|
|
14670
|
-
constructor(
|
|
14671
|
-
this.os =
|
|
14670
|
+
constructor(os53) {
|
|
14671
|
+
this.os = os53;
|
|
14672
14672
|
}
|
|
14673
14673
|
async prepareLaunch() {
|
|
14674
14674
|
const binary = this.os.findInPath("aider");
|
|
@@ -14800,8 +14800,8 @@ function geminiCredentialLocator() {
|
|
|
14800
14800
|
function geminiLoginLauncher() {
|
|
14801
14801
|
return {
|
|
14802
14802
|
async ensureInstalled() {
|
|
14803
|
-
const
|
|
14804
|
-
return
|
|
14803
|
+
const os53 = createOsStrategy();
|
|
14804
|
+
return os53.findInPath("gemini") !== null;
|
|
14805
14805
|
},
|
|
14806
14806
|
launch() {
|
|
14807
14807
|
return (0, import_node_child_process12.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
|
|
@@ -14991,8 +14991,8 @@ var GeminiRuntimeStrategy = class {
|
|
|
14991
14991
|
meta = getAgent("gemini");
|
|
14992
14992
|
mode = "interactive";
|
|
14993
14993
|
os;
|
|
14994
|
-
constructor(
|
|
14995
|
-
this.os =
|
|
14994
|
+
constructor(os53) {
|
|
14995
|
+
this.os = os53;
|
|
14996
14996
|
}
|
|
14997
14997
|
async prepareLaunch() {
|
|
14998
14998
|
const binary = this.os.findInPath("gemini");
|
|
@@ -15283,8 +15283,8 @@ var KimiRuntimeStrategy = class {
|
|
|
15283
15283
|
meta = getAgent("kimi");
|
|
15284
15284
|
mode = "interactive";
|
|
15285
15285
|
os;
|
|
15286
|
-
constructor(
|
|
15287
|
-
this.os =
|
|
15286
|
+
constructor(os53) {
|
|
15287
|
+
this.os = os53;
|
|
15288
15288
|
}
|
|
15289
15289
|
async prepareLaunch() {
|
|
15290
15290
|
const binary = this.os.findInPath("kimi");
|
|
@@ -15397,19 +15397,19 @@ var KimiRuntimeStrategy = class {
|
|
|
15397
15397
|
|
|
15398
15398
|
// src/agents/registry.ts
|
|
15399
15399
|
var runtimeBuilders = {
|
|
15400
|
-
claude: (
|
|
15401
|
-
codex: (
|
|
15402
|
-
coderabbit: (
|
|
15403
|
-
cursor: (
|
|
15404
|
-
aider: (
|
|
15405
|
-
gemini: (
|
|
15406
|
-
kimi: (
|
|
15400
|
+
claude: (os53) => new ClaudeRuntimeStrategy(os53),
|
|
15401
|
+
codex: (os53) => new CodexRuntimeStrategy(os53),
|
|
15402
|
+
coderabbit: (os53) => new CoderabbitRuntimeStrategy(os53),
|
|
15403
|
+
cursor: (os53) => new CursorRuntimeStrategy(os53),
|
|
15404
|
+
aider: (os53) => new AiderRuntimeStrategy(os53),
|
|
15405
|
+
gemini: (os53) => new GeminiRuntimeStrategy(os53),
|
|
15406
|
+
kimi: (os53) => new KimiRuntimeStrategy(os53)
|
|
15407
15407
|
};
|
|
15408
15408
|
var deployBuilders = {
|
|
15409
15409
|
claude: () => new ClaudeDeployStrategy(),
|
|
15410
15410
|
codex: () => new CodexDeployStrategy()
|
|
15411
15411
|
};
|
|
15412
|
-
function createAgentStrategy(agent,
|
|
15412
|
+
function createAgentStrategy(agent, os53 = createOsStrategy()) {
|
|
15413
15413
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
15414
15414
|
throw new Error(
|
|
15415
15415
|
`Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
|
|
@@ -15419,10 +15419,10 @@ function createAgentStrategy(agent, os52 = createOsStrategy()) {
|
|
|
15419
15419
|
if (!build) {
|
|
15420
15420
|
throw new Error(`No runtime strategy registered for agent "${agent}"`);
|
|
15421
15421
|
}
|
|
15422
|
-
return build(
|
|
15422
|
+
return build(os53);
|
|
15423
15423
|
}
|
|
15424
|
-
function createInteractiveAgentStrategy(agent,
|
|
15425
|
-
const s = createAgentStrategy(agent,
|
|
15424
|
+
function createInteractiveAgentStrategy(agent, os53 = createOsStrategy()) {
|
|
15425
|
+
const s = createAgentStrategy(agent, os53);
|
|
15426
15426
|
if (s.mode !== "interactive") {
|
|
15427
15427
|
throw new Error(
|
|
15428
15428
|
`Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
|
|
@@ -16119,26 +16119,26 @@ function restoreCoderabbitOauthBlob(value) {
|
|
|
16119
16119
|
(0, import_node_fs5.writeFileSync)(path36.join(dir, file), contents, { mode: 384 });
|
|
16120
16120
|
}
|
|
16121
16121
|
async function configureCoderabbit(input, deps = {}) {
|
|
16122
|
-
const
|
|
16122
|
+
const os53 = deps.os ?? createOsStrategy();
|
|
16123
16123
|
const ensureInstalled = deps.ensureInstalled ?? ensureCoderabbitInstalled;
|
|
16124
16124
|
const isLoggedIn = deps.isLoggedIn ?? defaultIsLoggedIn;
|
|
16125
16125
|
const runOAuth = deps.runOAuthLogin ?? runCoderabbitOAuthLogin;
|
|
16126
16126
|
const snapshot = deps.snapshotDir ?? (() => snapshotCredentialDir());
|
|
16127
16127
|
const capture2 = deps.captureCredential ?? ((b) => diffCapturedCredential(b));
|
|
16128
16128
|
const loginWithApiKey = deps.loginWithApiKey ?? defaultLoginWithApiKey;
|
|
16129
|
-
const home =
|
|
16130
|
-
|
|
16131
|
-
|
|
16129
|
+
const home = os53.homeDir();
|
|
16130
|
+
os53.augmentPath(
|
|
16131
|
+
os53.id === "win32" ? [
|
|
16132
16132
|
path36.join(home, ".local", "bin"),
|
|
16133
16133
|
path36.join(process.env.APPDATA ?? path36.join(home, "AppData", "Roaming"), "npm"),
|
|
16134
16134
|
path36.join(home, "scoop", "shims")
|
|
16135
16135
|
] : [path36.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
|
|
16136
16136
|
);
|
|
16137
|
-
const installed2 =
|
|
16137
|
+
const installed2 = os53.findInPath("coderabbit") !== null;
|
|
16138
16138
|
const base = () => ({
|
|
16139
16139
|
action: input.action,
|
|
16140
16140
|
supported: true,
|
|
16141
|
-
installed:
|
|
16141
|
+
installed: os53.findInPath("coderabbit") !== null,
|
|
16142
16142
|
loggedIn: false
|
|
16143
16143
|
});
|
|
16144
16144
|
if (input.action === "status") {
|
|
@@ -16152,7 +16152,7 @@ async function configureCoderabbit(input, deps = {}) {
|
|
|
16152
16152
|
const key = (input.apiKey ?? "").trim();
|
|
16153
16153
|
if (!key) return { ...res2, error: "No API key provided" };
|
|
16154
16154
|
if (!res2.installed) {
|
|
16155
|
-
const ok = await ensureInstalled(
|
|
16155
|
+
const ok = await ensureInstalled(os53);
|
|
16156
16156
|
res2.installed = ok;
|
|
16157
16157
|
if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
|
|
16158
16158
|
}
|
|
@@ -16176,7 +16176,7 @@ async function configureCoderabbit(input, deps = {}) {
|
|
|
16176
16176
|
}
|
|
16177
16177
|
if (!res2.installed) {
|
|
16178
16178
|
deps.onEvent?.({ kind: "installing" });
|
|
16179
|
-
const ok = await ensureInstalled(
|
|
16179
|
+
const ok = await ensureInstalled(os53);
|
|
16180
16180
|
res2.installed = ok;
|
|
16181
16181
|
if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
|
|
16182
16182
|
}
|
|
@@ -16206,7 +16206,7 @@ async function configureCoderabbit(input, deps = {}) {
|
|
|
16206
16206
|
const res2 = base();
|
|
16207
16207
|
if (!installed2) {
|
|
16208
16208
|
deps.onEvent?.({ kind: "installing" });
|
|
16209
|
-
const ok = await ensureInstalled(
|
|
16209
|
+
const ok = await ensureInstalled(os53);
|
|
16210
16210
|
res2.installed = ok;
|
|
16211
16211
|
if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
|
|
16212
16212
|
}
|
|
@@ -16246,7 +16246,7 @@ async function configureCoderabbit(input, deps = {}) {
|
|
|
16246
16246
|
}
|
|
16247
16247
|
const res = base();
|
|
16248
16248
|
if (!res.installed) {
|
|
16249
|
-
const ok = await ensureInstalled(
|
|
16249
|
+
const ok = await ensureInstalled(os53);
|
|
16250
16250
|
res.installed = ok;
|
|
16251
16251
|
if (!ok) return { ...res, error: "CodeRabbit CLI is not installed" };
|
|
16252
16252
|
}
|
|
@@ -17871,7 +17871,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
17871
17871
|
if (process.env.NODE_ENV === "test") return;
|
|
17872
17872
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17873
17873
|
if (process.env.CI) return;
|
|
17874
|
-
const current = true ? "2.60.
|
|
17874
|
+
const current = true ? "2.60.70" : null;
|
|
17875
17875
|
if (!current) return;
|
|
17876
17876
|
const cache = readCache();
|
|
17877
17877
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -17888,7 +17888,7 @@ function checkForUpdates() {
|
|
|
17888
17888
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17889
17889
|
if (process.env.CI) return;
|
|
17890
17890
|
if (!process.stdout.isTTY) return;
|
|
17891
|
-
const current = true ? "2.60.
|
|
17891
|
+
const current = true ? "2.60.70" : null;
|
|
17892
17892
|
if (!current) return;
|
|
17893
17893
|
const cache = readCache();
|
|
17894
17894
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -17908,7 +17908,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
17908
17908
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
17909
17909
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
17910
17910
|
function currentCliVersion() {
|
|
17911
|
-
return true ? "2.60.
|
|
17911
|
+
return true ? "2.60.70" : null;
|
|
17912
17912
|
}
|
|
17913
17913
|
function runCmd(cmd, args2, timeoutMs) {
|
|
17914
17914
|
return new Promise((resolve7) => {
|
|
@@ -18136,6 +18136,78 @@ function isDeployPayload(p2) {
|
|
|
18136
18136
|
function isStopPayload(p2) {
|
|
18137
18137
|
return typeof p2.sessionId === "string";
|
|
18138
18138
|
}
|
|
18139
|
+
var FLEET_CONTAINER_NAME_RE = /^codeam-box-[a-z0-9]+$/;
|
|
18140
|
+
function isFleetContainerName(v) {
|
|
18141
|
+
return typeof v === "string" && FLEET_CONTAINER_NAME_RE.test(v);
|
|
18142
|
+
}
|
|
18143
|
+
function isFiniteNumber(v) {
|
|
18144
|
+
return typeof v === "number" && Number.isFinite(v);
|
|
18145
|
+
}
|
|
18146
|
+
function isFleetLimits(v) {
|
|
18147
|
+
if (typeof v !== "object" || v === null) return false;
|
|
18148
|
+
const l = v;
|
|
18149
|
+
return isFiniteNumber(l.memoryMb) && isFiniteNumber(l.cpus) && isFiniteNumber(l.pidsLimit) && isFiniteNumber(l.diskGb);
|
|
18150
|
+
}
|
|
18151
|
+
function isFleetCreateBoxPayload(p2) {
|
|
18152
|
+
return typeof p2.boxId === "string" && isFleetContainerName(p2.containerName) && typeof p2.enrollToken === "string" && p2.enrollToken.length > 0 && typeof p2.apiOrigin === "string" && p2.apiOrigin.length > 0 && isFleetLimits(p2.limits);
|
|
18153
|
+
}
|
|
18154
|
+
function isFleetBoxRefPayload(p2) {
|
|
18155
|
+
if (typeof p2.boxId !== "string") return false;
|
|
18156
|
+
if (!isFleetContainerName(p2.containerName)) return false;
|
|
18157
|
+
if (p2.removeVolume !== void 0 && typeof p2.removeVolume !== "boolean") return false;
|
|
18158
|
+
return true;
|
|
18159
|
+
}
|
|
18160
|
+
function fleetUserIdFromContainerName(containerName) {
|
|
18161
|
+
return containerName.slice("codeam-box-".length);
|
|
18162
|
+
}
|
|
18163
|
+
function isMissingContainerError(stderr) {
|
|
18164
|
+
return /no such container/i.test(stderr);
|
|
18165
|
+
}
|
|
18166
|
+
function isMissingVolumeError(stderr) {
|
|
18167
|
+
return /no such volume/i.test(stderr);
|
|
18168
|
+
}
|
|
18169
|
+
function resolveFleetBoxImage() {
|
|
18170
|
+
return process.env.CODEAM_FLEET_BOX_IMAGE || "ghcr.io/edgar-durand/codeam-box:latest";
|
|
18171
|
+
}
|
|
18172
|
+
var DOCKER_RUN_TIMEOUT_MS = 12e4;
|
|
18173
|
+
var defaultDockerRunner = {
|
|
18174
|
+
run(args2, opts = {}) {
|
|
18175
|
+
return new Promise((resolve7) => {
|
|
18176
|
+
const child = (0, import_node_child_process23.spawn)("docker", args2, {
|
|
18177
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
18178
|
+
env: { ...process.env, ...opts.env }
|
|
18179
|
+
});
|
|
18180
|
+
let stdoutBuf = "";
|
|
18181
|
+
let stderrBuf = "";
|
|
18182
|
+
let settled = false;
|
|
18183
|
+
const timer = setTimeout(
|
|
18184
|
+
() => {
|
|
18185
|
+
if (settled) return;
|
|
18186
|
+
killQuiet(child);
|
|
18187
|
+
},
|
|
18188
|
+
opts.timeoutMs ?? DOCKER_RUN_TIMEOUT_MS
|
|
18189
|
+
);
|
|
18190
|
+
const done = (code) => {
|
|
18191
|
+
if (settled) return;
|
|
18192
|
+
settled = true;
|
|
18193
|
+
clearTimeout(timer);
|
|
18194
|
+
resolve7({ code, stderr: stderrBuf, stdout: stdoutBuf });
|
|
18195
|
+
};
|
|
18196
|
+
child.stdout?.on("data", (b) => {
|
|
18197
|
+
stdoutBuf += b.toString();
|
|
18198
|
+
});
|
|
18199
|
+
child.stderr?.on("data", (b) => {
|
|
18200
|
+
stderrBuf += b.toString();
|
|
18201
|
+
});
|
|
18202
|
+
child.once("error", (err) => {
|
|
18203
|
+
stderrBuf += stderrBuf ? `
|
|
18204
|
+
${err.message}` : err.message;
|
|
18205
|
+
done(null);
|
|
18206
|
+
});
|
|
18207
|
+
child.once("exit", (code) => done(code));
|
|
18208
|
+
});
|
|
18209
|
+
}
|
|
18210
|
+
};
|
|
18139
18211
|
var CONTROL_AGENT_META = {
|
|
18140
18212
|
id: "claude",
|
|
18141
18213
|
displayName: "CodeAgent Host Agent",
|
|
@@ -18177,6 +18249,7 @@ var HostAgentSupervisor = class {
|
|
|
18177
18249
|
this.teardownHeadroom = deps.teardownHeadroom ?? defaultTeardownHeadroom;
|
|
18178
18250
|
this.selfUpdate = deps.selfUpdate ?? runSelfUpdate;
|
|
18179
18251
|
this.onUpdated = deps.onUpdated ?? defaultOnUpdated;
|
|
18252
|
+
this.docker = deps.docker ?? defaultDockerRunner;
|
|
18180
18253
|
}
|
|
18181
18254
|
identity;
|
|
18182
18255
|
deps;
|
|
@@ -18213,6 +18286,8 @@ var HostAgentSupervisor = class {
|
|
|
18213
18286
|
/** Best-effort systemd de-provision used by `self_hosted_wipe`. */
|
|
18214
18287
|
disableService;
|
|
18215
18288
|
teardownHeadroom;
|
|
18289
|
+
/** Docker runner for the fleet `fleet_*` control-plane handlers. */
|
|
18290
|
+
docker;
|
|
18216
18291
|
/** Guards against firing the self-heal more than once. */
|
|
18217
18292
|
healing = false;
|
|
18218
18293
|
/**
|
|
@@ -18380,6 +18455,38 @@ var HostAgentSupervisor = class {
|
|
|
18380
18455
|
* arbitrary command surface).
|
|
18381
18456
|
*/
|
|
18382
18457
|
async handleCommand(cmd) {
|
|
18458
|
+
if (cmd.type === "fleet_create_box") {
|
|
18459
|
+
if (!isFleetCreateBoxPayload(cmd.payload)) {
|
|
18460
|
+
log.warn("host-agent", `ignoring malformed fleet_create_box id=${cmd.id}`);
|
|
18461
|
+
return;
|
|
18462
|
+
}
|
|
18463
|
+
await this.fleetCreateBox(cmd.payload);
|
|
18464
|
+
return;
|
|
18465
|
+
}
|
|
18466
|
+
if (cmd.type === "fleet_start_box") {
|
|
18467
|
+
if (!isFleetBoxRefPayload(cmd.payload)) {
|
|
18468
|
+
log.warn("host-agent", `ignoring malformed fleet_start_box id=${cmd.id}`);
|
|
18469
|
+
return;
|
|
18470
|
+
}
|
|
18471
|
+
await this.fleetStartBox(cmd.payload);
|
|
18472
|
+
return;
|
|
18473
|
+
}
|
|
18474
|
+
if (cmd.type === "fleet_stop_box") {
|
|
18475
|
+
if (!isFleetBoxRefPayload(cmd.payload)) {
|
|
18476
|
+
log.warn("host-agent", `ignoring malformed fleet_stop_box id=${cmd.id}`);
|
|
18477
|
+
return;
|
|
18478
|
+
}
|
|
18479
|
+
await this.fleetStopBox(cmd.payload);
|
|
18480
|
+
return;
|
|
18481
|
+
}
|
|
18482
|
+
if (cmd.type === "fleet_delete_box") {
|
|
18483
|
+
if (!isFleetBoxRefPayload(cmd.payload)) {
|
|
18484
|
+
log.warn("host-agent", `ignoring malformed fleet_delete_box id=${cmd.id}`);
|
|
18485
|
+
return;
|
|
18486
|
+
}
|
|
18487
|
+
await this.fleetDeleteBox(cmd.payload);
|
|
18488
|
+
return;
|
|
18489
|
+
}
|
|
18383
18490
|
if (cmd.type === "self_hosted_deploy") {
|
|
18384
18491
|
if (!isDeployPayload(cmd.payload)) {
|
|
18385
18492
|
log.warn("host-agent", `ignoring malformed self_hosted_deploy id=${cmd.id}`);
|
|
@@ -18417,6 +18524,131 @@ var HostAgentSupervisor = class {
|
|
|
18417
18524
|
}
|
|
18418
18525
|
log.trace("host-agent", `ignoring unsupported command type=${cmd.type}`);
|
|
18419
18526
|
}
|
|
18527
|
+
/**
|
|
18528
|
+
* `fleet_create_box` — `docker run` a per-user rescue box. Builds the FULL
|
|
18529
|
+
* argv from a fixed template (Global Constraints — nothing from the wire
|
|
18530
|
+
* is passed through as a raw docker argument beyond the already-validated
|
|
18531
|
+
* `containerName` and the numeric resource limits): hard isolation
|
|
18532
|
+
* (`--cap-drop ALL`, `--security-opt no-new-privileges`, resource caps,
|
|
18533
|
+
* the isolated `fleet-net` network, a SINGLE named volume mounted at
|
|
18534
|
+
* `/home/box` — named identically to the container, per the Global
|
|
18535
|
+
* Constraints — and the ops labels). NEVER `--privileged`, NEVER a
|
|
18536
|
+
* `docker.sock` mount, NEVER a host bind mount. The api origin (not a
|
|
18537
|
+
* secret) is delivered via a normal `-e KEY=value`. The enroll token IS a
|
|
18538
|
+
* secret — spec invariant #1 is "token via env, NEVER argv" — so it is
|
|
18539
|
+
* delivered as a BARE `-e CODEAM_ENROLL_TOKEN` (no `=value`) with the
|
|
18540
|
+
* actual value passed only through {@link DockerRunner.run}'s `env` map,
|
|
18541
|
+
* which the runner merges into the `docker` CLI process's OWN env; docker
|
|
18542
|
+
* then reads a bare `-e NAME` from its own env and forwards it into the
|
|
18543
|
+
* container. The value never appears in the `docker run` argv, so it's
|
|
18544
|
+
* never visible via `ps` on the shared fleet host; never logged either.
|
|
18545
|
+
*/
|
|
18546
|
+
async fleetCreateBox(payload) {
|
|
18547
|
+
const { containerName, limits } = payload;
|
|
18548
|
+
const userId = fleetUserIdFromContainerName(containerName);
|
|
18549
|
+
log.info(
|
|
18550
|
+
"host-agent",
|
|
18551
|
+
`fleet_create_box id=${payload.boxId} name=${containerName} mem=${limits.memoryMb}m cpus=${limits.cpus} pids=${limits.pidsLimit}`
|
|
18552
|
+
);
|
|
18553
|
+
const args2 = [
|
|
18554
|
+
"run",
|
|
18555
|
+
"-d",
|
|
18556
|
+
"--name",
|
|
18557
|
+
containerName,
|
|
18558
|
+
"--cap-drop",
|
|
18559
|
+
"ALL",
|
|
18560
|
+
"--security-opt",
|
|
18561
|
+
"no-new-privileges",
|
|
18562
|
+
"--memory",
|
|
18563
|
+
`${limits.memoryMb}m`,
|
|
18564
|
+
"--cpus",
|
|
18565
|
+
String(limits.cpus),
|
|
18566
|
+
"--pids-limit",
|
|
18567
|
+
String(limits.pidsLimit),
|
|
18568
|
+
"--network",
|
|
18569
|
+
"fleet-net",
|
|
18570
|
+
"--label",
|
|
18571
|
+
`com.codeagent.user-id=${userId}`,
|
|
18572
|
+
"--label",
|
|
18573
|
+
`com.codeagent.box-id=${payload.boxId}`,
|
|
18574
|
+
"--label",
|
|
18575
|
+
"com.codeagent.created-by=fleet",
|
|
18576
|
+
"-v",
|
|
18577
|
+
`${containerName}:/home/box`,
|
|
18578
|
+
// Bare `-e NAME` (no `=value`) — docker reads the value from ITS OWN
|
|
18579
|
+
// process env (supplied below via `opts.env`), never from this argv.
|
|
18580
|
+
"-e",
|
|
18581
|
+
"CODEAM_ENROLL_TOKEN",
|
|
18582
|
+
"-e",
|
|
18583
|
+
`CODEAM_API_URL=${payload.apiOrigin}`,
|
|
18584
|
+
resolveFleetBoxImage()
|
|
18585
|
+
];
|
|
18586
|
+
const res = await this.docker.run(args2, {
|
|
18587
|
+
timeoutMs: DOCKER_RUN_TIMEOUT_MS,
|
|
18588
|
+
env: { CODEAM_ENROLL_TOKEN: payload.enrollToken }
|
|
18589
|
+
});
|
|
18590
|
+
if (res.code === 0) {
|
|
18591
|
+
log.info(
|
|
18592
|
+
"host-agent",
|
|
18593
|
+
`fleet box ${containerName} created (${res.stdout.trim().slice(0, 12)})`
|
|
18594
|
+
);
|
|
18595
|
+
} else {
|
|
18596
|
+
log.warn(
|
|
18597
|
+
"host-agent",
|
|
18598
|
+
`fleet_create_box ${containerName} failed (code=${res.code}): ${res.stderr.trim().slice(-300)}`
|
|
18599
|
+
);
|
|
18600
|
+
}
|
|
18601
|
+
}
|
|
18602
|
+
/** `fleet_start_box` — wake a sleeping box (`docker start`). Idempotent: a
|
|
18603
|
+
* container the host already removed is treated as success. */
|
|
18604
|
+
async fleetStartBox(payload) {
|
|
18605
|
+
log.info("host-agent", `fleet_start_box id=${payload.boxId} name=${payload.containerName}`);
|
|
18606
|
+
const res = await this.docker.run(["start", payload.containerName]);
|
|
18607
|
+
if (res.code !== 0 && !isMissingContainerError(res.stderr)) {
|
|
18608
|
+
log.warn(
|
|
18609
|
+
"host-agent",
|
|
18610
|
+
`fleet_start_box ${payload.containerName} failed (code=${res.code}): ${res.stderr.trim().slice(-300)}`
|
|
18611
|
+
);
|
|
18612
|
+
}
|
|
18613
|
+
}
|
|
18614
|
+
/** `fleet_stop_box` — sleep an idle box (`docker stop`). MUST be
|
|
18615
|
+
* idempotent — the backend's reap sweeps may re-send a stop for a box
|
|
18616
|
+
* the host already stopped/removed; "No such container" is success. */
|
|
18617
|
+
async fleetStopBox(payload) {
|
|
18618
|
+
log.info("host-agent", `fleet_stop_box id=${payload.boxId} name=${payload.containerName}`);
|
|
18619
|
+
const res = await this.docker.run(["stop", payload.containerName]);
|
|
18620
|
+
if (res.code !== 0 && !isMissingContainerError(res.stderr)) {
|
|
18621
|
+
log.warn(
|
|
18622
|
+
"host-agent",
|
|
18623
|
+
`fleet_stop_box ${payload.containerName} failed (code=${res.code}): ${res.stderr.trim().slice(-300)}`
|
|
18624
|
+
);
|
|
18625
|
+
}
|
|
18626
|
+
}
|
|
18627
|
+
/** `fleet_delete_box` — `docker rm -f`, plus `docker volume rm` when the
|
|
18628
|
+
* backend asks for a reap (`removeVolume`). MUST be idempotent — deleting
|
|
18629
|
+
* an already-gone container/volume is success, never a failure. */
|
|
18630
|
+
async fleetDeleteBox(payload) {
|
|
18631
|
+
log.info(
|
|
18632
|
+
"host-agent",
|
|
18633
|
+
`fleet_delete_box id=${payload.boxId} name=${payload.containerName} removeVolume=${Boolean(payload.removeVolume)}`
|
|
18634
|
+
);
|
|
18635
|
+
const res = await this.docker.run(["rm", "-f", payload.containerName]);
|
|
18636
|
+
if (res.code !== 0 && !isMissingContainerError(res.stderr)) {
|
|
18637
|
+
log.warn(
|
|
18638
|
+
"host-agent",
|
|
18639
|
+
`fleet_delete_box ${payload.containerName} failed (code=${res.code}): ${res.stderr.trim().slice(-300)}`
|
|
18640
|
+
);
|
|
18641
|
+
}
|
|
18642
|
+
if (payload.removeVolume) {
|
|
18643
|
+
const volRes = await this.docker.run(["volume", "rm", payload.containerName]);
|
|
18644
|
+
if (volRes.code !== 0 && !isMissingVolumeError(volRes.stderr)) {
|
|
18645
|
+
log.warn(
|
|
18646
|
+
"host-agent",
|
|
18647
|
+
`fleet_delete_box volume rm ${payload.containerName} failed (code=${volRes.code}): ${volRes.stderr.trim().slice(-300)}`
|
|
18648
|
+
);
|
|
18649
|
+
}
|
|
18650
|
+
}
|
|
18651
|
+
}
|
|
18420
18652
|
/**
|
|
18421
18653
|
* Prepare the workspace, write the agent credential (same as codespace
|
|
18422
18654
|
* provisioning), and spawn a supervised `codeam pair-auto` child.
|
|
@@ -20440,11 +20672,11 @@ function resolveDoltInstallStrategy(platform3) {
|
|
|
20440
20672
|
}
|
|
20441
20673
|
var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
|
|
20442
20674
|
function doltPlatformTuple(platform3, arch2) {
|
|
20443
|
-
const
|
|
20675
|
+
const os53 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
|
|
20444
20676
|
const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
|
|
20445
20677
|
if (!a) return null;
|
|
20446
|
-
if (
|
|
20447
|
-
return `${
|
|
20678
|
+
if (os53 === "windows" && a !== "amd64") return null;
|
|
20679
|
+
return `${os53}-${a}`;
|
|
20448
20680
|
}
|
|
20449
20681
|
function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
|
|
20450
20682
|
const tuple = doltPlatformTuple(platform3, arch2);
|
|
@@ -23068,11 +23300,11 @@ function resolveTokenValue(args2) {
|
|
|
23068
23300
|
}
|
|
23069
23301
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
23070
23302
|
if (fileFlag) {
|
|
23071
|
-
const
|
|
23303
|
+
const path75 = fileFlag.slice("--token-file=".length);
|
|
23072
23304
|
try {
|
|
23073
|
-
const content = fs56.readFileSync(
|
|
23074
|
-
if (content.length === 0) fail(`--token-file ${
|
|
23075
|
-
rmIfExistsQuiet(
|
|
23305
|
+
const content = fs56.readFileSync(path75, "utf8").trim();
|
|
23306
|
+
if (content.length === 0) fail(`--token-file ${path75} is empty`);
|
|
23307
|
+
rmIfExistsQuiet(path75);
|
|
23076
23308
|
return content;
|
|
23077
23309
|
} catch (err) {
|
|
23078
23310
|
fail(`Could not read --token-file: ${err.message}`);
|
|
@@ -23712,14 +23944,14 @@ function defaultSdkDir() {
|
|
|
23712
23944
|
return resolveSdkDirViaRequire();
|
|
23713
23945
|
}
|
|
23714
23946
|
function resolveClaudeNativeBinary(deps = {}) {
|
|
23715
|
-
const
|
|
23947
|
+
const existsSync27 = deps.existsSync ?? import_fs4.default.existsSync;
|
|
23716
23948
|
const platformKey = deps.platformKey ?? currentPlatformKey();
|
|
23717
23949
|
const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
|
|
23718
23950
|
if (!sdkDir) return null;
|
|
23719
23951
|
const scopeDir = import_path8.default.dirname(sdkDir);
|
|
23720
23952
|
const binName = platformKey.startsWith("win32-") ? "claude.exe" : "claude";
|
|
23721
23953
|
const candidate = import_path8.default.join(scopeDir, `claude-agent-sdk-${platformKey}`, binName);
|
|
23722
|
-
return
|
|
23954
|
+
return existsSync27(candidate) ? candidate : null;
|
|
23723
23955
|
}
|
|
23724
23956
|
var realSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
23725
23957
|
async function waitForClaudeNativeBinary(opts = {}) {
|
|
@@ -23770,18 +24002,18 @@ async function waitForCommandOnPath(cmd, opts = {}) {
|
|
|
23770
24002
|
return check();
|
|
23771
24003
|
}
|
|
23772
24004
|
function resolveCursorAgentBinary(deps = {}) {
|
|
23773
|
-
const
|
|
24005
|
+
const existsSync27 = deps.existsSync ?? import_fs4.default.existsSync;
|
|
23774
24006
|
const platform3 = deps.platform ?? process.platform;
|
|
23775
24007
|
const env = deps.env ?? process.env;
|
|
23776
24008
|
if (platform3 === "win32") {
|
|
23777
24009
|
const localAppData = env.LOCALAPPDATA;
|
|
23778
24010
|
if (!localAppData) return null;
|
|
23779
24011
|
const exe = import_path8.default.win32.join(localAppData, "cursor-agent", "cursor-agent.exe");
|
|
23780
|
-
return
|
|
24012
|
+
return existsSync27(exe) ? exe : null;
|
|
23781
24013
|
}
|
|
23782
24014
|
const home = deps.homedir ?? import_os10.default.homedir();
|
|
23783
24015
|
const unix = import_path8.default.posix.join(home, ".local", "bin", "cursor-agent");
|
|
23784
|
-
return
|
|
24016
|
+
return existsSync27(unix) ? unix : null;
|
|
23785
24017
|
}
|
|
23786
24018
|
async function waitForCursorAgent(opts = {}) {
|
|
23787
24019
|
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
@@ -35271,9 +35503,9 @@ function checkSessions() {
|
|
|
35271
35503
|
}
|
|
35272
35504
|
}
|
|
35273
35505
|
function checkAgentBinaries() {
|
|
35274
|
-
const
|
|
35506
|
+
const os53 = createOsStrategy();
|
|
35275
35507
|
return getEnabledAgents().map((meta) => {
|
|
35276
|
-
const found =
|
|
35508
|
+
const found = os53.findInPath(meta.binaryName);
|
|
35277
35509
|
return {
|
|
35278
35510
|
id: `agent-${meta.id}`,
|
|
35279
35511
|
label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
|
|
@@ -35337,7 +35569,7 @@ function checkChokidar() {
|
|
|
35337
35569
|
}
|
|
35338
35570
|
async function doctor(args2 = []) {
|
|
35339
35571
|
const json = args2.includes("--json");
|
|
35340
|
-
const cliVersion = true ? "2.60.
|
|
35572
|
+
const cliVersion = true ? "2.60.70" : "0.0.0-dev";
|
|
35341
35573
|
const apiBase2 = resolveApiBaseUrl();
|
|
35342
35574
|
const diagnosticId = (0, import_node_crypto12.randomUUID)();
|
|
35343
35575
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -35535,6 +35767,9 @@ async function completion(args2) {
|
|
|
35535
35767
|
|
|
35536
35768
|
// src/integrations/mcp-run.ts
|
|
35537
35769
|
var import_node_child_process28 = require("child_process");
|
|
35770
|
+
var import_node_fs9 = require("fs");
|
|
35771
|
+
var import_node_os9 = __toESM(require("os"));
|
|
35772
|
+
var import_node_path8 = __toESM(require("path"));
|
|
35538
35773
|
|
|
35539
35774
|
// src/integrations/token-client.ts
|
|
35540
35775
|
var REFRESH_AHEAD_MS = 5 * 60 * 1e3;
|
|
@@ -35754,8 +35989,24 @@ function commandExists(command2) {
|
|
|
35754
35989
|
return false;
|
|
35755
35990
|
}
|
|
35756
35991
|
}
|
|
35992
|
+
function localBinCandidates(command2) {
|
|
35993
|
+
return [
|
|
35994
|
+
import_node_path8.default.join(import_node_os9.default.homedir(), ".local", "bin", command2),
|
|
35995
|
+
import_node_path8.default.join(import_node_os9.default.homedir(), ".cargo", "bin", command2)
|
|
35996
|
+
];
|
|
35997
|
+
}
|
|
35998
|
+
function resolveLauncherPath(command2, deps = {
|
|
35999
|
+
commandExists,
|
|
36000
|
+
existsSync: import_node_fs9.existsSync
|
|
36001
|
+
}) {
|
|
36002
|
+
if (deps.commandExists(command2)) return command2;
|
|
36003
|
+
for (const candidate of localBinCandidates(command2)) {
|
|
36004
|
+
if (deps.existsSync(candidate)) return candidate;
|
|
36005
|
+
}
|
|
36006
|
+
return command2;
|
|
36007
|
+
}
|
|
35757
36008
|
function ensureCommand(command2) {
|
|
35758
|
-
if (commandExists(command2)) return;
|
|
36009
|
+
if (resolveLauncherPath(command2) !== command2 || commandExists(command2)) return;
|
|
35759
36010
|
if (process.platform === "win32") {
|
|
35760
36011
|
process.stderr.write(
|
|
35761
36012
|
`[codeam mcp-run] '${command2}' not found on PATH \u2014 install it and retry.
|
|
@@ -35764,6 +36015,15 @@ function ensureCommand(command2) {
|
|
|
35764
36015
|
return;
|
|
35765
36016
|
}
|
|
35766
36017
|
if (command2 === "uvx") {
|
|
36018
|
+
try {
|
|
36019
|
+
(0, import_node_child_process28.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
|
|
36020
|
+
stdio: ["ignore", process.stderr, process.stderr],
|
|
36021
|
+
timeout: 18e4,
|
|
36022
|
+
env: { ...process.env, UV_NO_MODIFY_PATH: "1" }
|
|
36023
|
+
});
|
|
36024
|
+
} catch {
|
|
36025
|
+
}
|
|
36026
|
+
if (resolveLauncherPath(command2) !== command2) return;
|
|
35767
36027
|
try {
|
|
35768
36028
|
(0, import_node_child_process28.execSync)("python3 -m pip install --user --quiet uv", {
|
|
35769
36029
|
stdio: ["ignore", process.stderr, process.stderr],
|
|
@@ -35771,6 +36031,11 @@ function ensureCommand(command2) {
|
|
|
35771
36031
|
});
|
|
35772
36032
|
} catch {
|
|
35773
36033
|
}
|
|
36034
|
+
if (resolveLauncherPath(command2) !== command2) return;
|
|
36035
|
+
process.stderr.write(
|
|
36036
|
+
`[codeam mcp-run] could not provision '${command2}' (standalone installer + pip both failed) \u2014 the '${command2}'-launched MCP server will be unavailable.
|
|
36037
|
+
`
|
|
36038
|
+
);
|
|
35774
36039
|
}
|
|
35775
36040
|
}
|
|
35776
36041
|
async function mcpRun(args2) {
|
|
@@ -35789,6 +36054,7 @@ async function mcpRun(args2) {
|
|
|
35789
36054
|
process.exit(1);
|
|
35790
36055
|
}
|
|
35791
36056
|
ensureCommand(delivery.command);
|
|
36057
|
+
const launcher = resolveLauncherPath(delivery.command);
|
|
35792
36058
|
const client2 = new IntegrationTokenClient({
|
|
35793
36059
|
sessionId,
|
|
35794
36060
|
pluginId,
|
|
@@ -35804,7 +36070,7 @@ async function mcpRun(args2) {
|
|
|
35804
36070
|
const value = current[field];
|
|
35805
36071
|
if (typeof value === "string" && value) env[envVar] = value;
|
|
35806
36072
|
}
|
|
35807
|
-
return { command:
|
|
36073
|
+
return { command: launcher, args: delivery.args, env };
|
|
35808
36074
|
},
|
|
35809
36075
|
shouldRestartNow: () => current !== null && new Date(current.expiresAt).getTime() - Date.now() < RESTART_AHEAD_MS
|
|
35810
36076
|
});
|
|
@@ -35814,7 +36080,7 @@ async function mcpRun(args2) {
|
|
|
35814
36080
|
// src/commands/version.ts
|
|
35815
36081
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
35816
36082
|
function version2() {
|
|
35817
|
-
const v = true ? "2.60.
|
|
36083
|
+
const v = true ? "2.60.70" : "unknown";
|
|
35818
36084
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
35819
36085
|
}
|
|
35820
36086
|
|
|
@@ -35963,10 +36229,10 @@ var EXIT_CODE_NAMES = {
|
|
|
35963
36229
|
};
|
|
35964
36230
|
|
|
35965
36231
|
// src/index.ts
|
|
35966
|
-
var
|
|
36232
|
+
var os52 = __toESM(require("os"));
|
|
35967
36233
|
if (!process.env.HOME) {
|
|
35968
36234
|
try {
|
|
35969
|
-
const home =
|
|
36235
|
+
const home = os52.homedir();
|
|
35970
36236
|
if (home) process.env.HOME = home;
|
|
35971
36237
|
} catch {
|
|
35972
36238
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.60.
|
|
3
|
+
"version": "2.60.70",
|
|
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",
|