codeam-cli 2.64.0 → 2.65.1
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 +38 -0
- package/dist/index.js +1557 -965
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2791,6 +2791,15 @@ function resolveApiBaseUrl() {
|
|
|
2791
2791
|
|
|
2792
2792
|
// ../../packages/shared/src/types/agent-squad.ts
|
|
2793
2793
|
var HANDOFF_FENCE_TAG = "codeam-handoff";
|
|
2794
|
+
var SQUAD_CONFIGURE_COMMAND = "squad_configure";
|
|
2795
|
+
var SQUAD_STATS_COMMAND = "squad_stats";
|
|
2796
|
+
var SQUAD_HOP_BUDGET_DEFAULT = 3;
|
|
2797
|
+
var SQUAD_HOP_BUDGET_MIN = 1;
|
|
2798
|
+
var SQUAD_HOP_BUDGET_MAX = 10;
|
|
2799
|
+
function clampHopBudget(value) {
|
|
2800
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return SQUAD_HOP_BUDGET_DEFAULT;
|
|
2801
|
+
return Math.min(SQUAD_HOP_BUDGET_MAX, Math.max(SQUAD_HOP_BUDGET_MIN, Math.round(value)));
|
|
2802
|
+
}
|
|
2794
2803
|
var SQUAD_SPECIALTIES = {
|
|
2795
2804
|
claude: "deep reasoning, refactors, and multi-step architecture work",
|
|
2796
2805
|
codex: "fast, focused implementation and test fixing",
|
|
@@ -3257,6 +3266,22 @@ function makeConfig(baseDir) {
|
|
|
3257
3266
|
s.agent = agent;
|
|
3258
3267
|
save(c2);
|
|
3259
3268
|
}
|
|
3269
|
+
function setSquadAuto2(pluginId, value) {
|
|
3270
|
+
const stored = {
|
|
3271
|
+
enabled: value.enabled === true,
|
|
3272
|
+
hopBudget: clampHopBudget(value.hopBudget)
|
|
3273
|
+
};
|
|
3274
|
+
const c2 = load();
|
|
3275
|
+
const s = c2.sessions.find((x) => x.pluginId === pluginId);
|
|
3276
|
+
if (!s) return null;
|
|
3277
|
+
s.squadAuto = stored;
|
|
3278
|
+
save(c2);
|
|
3279
|
+
return stored;
|
|
3280
|
+
}
|
|
3281
|
+
function getSquadAuto2(pluginId) {
|
|
3282
|
+
const s = load().sessions.find((x) => x.pluginId === pluginId);
|
|
3283
|
+
return s?.squadAuto ?? null;
|
|
3284
|
+
}
|
|
3260
3285
|
function clearAll2() {
|
|
3261
3286
|
try {
|
|
3262
3287
|
fs3.unlinkSync(file);
|
|
@@ -3269,7 +3294,7 @@ function makeConfig(baseDir) {
|
|
|
3269
3294
|
function loadCliConfig2() {
|
|
3270
3295
|
return load();
|
|
3271
3296
|
}
|
|
3272
|
-
return { getConfig: getConfig2, ensurePluginId: ensurePluginId2, addSession: addSession2, removeSession: removeSession2, setActiveSession: setActiveSession2, getActiveSession: getActiveSession2, getActiveSessionForAgent: getActiveSessionForAgent2, setDisable1mContext: setDisable1mContext2, setSessionAgent: setSessionAgent2, clearAll: clearAll2, saveCliConfig: saveCliConfig2, loadCliConfig: loadCliConfig2 };
|
|
3297
|
+
return { getConfig: getConfig2, ensurePluginId: ensurePluginId2, addSession: addSession2, removeSession: removeSession2, setActiveSession: setActiveSession2, getActiveSession: getActiveSession2, getActiveSessionForAgent: getActiveSessionForAgent2, setDisable1mContext: setDisable1mContext2, setSessionAgent: setSessionAgent2, setSquadAuto: setSquadAuto2, getSquadAuto: getSquadAuto2, clearAll: clearAll2, saveCliConfig: saveCliConfig2, loadCliConfig: loadCliConfig2 };
|
|
3273
3298
|
}
|
|
3274
3299
|
var CODESPACE_ENV_KEYS = [
|
|
3275
3300
|
"PREVIEW_TUNNEL_TOKEN",
|
|
@@ -3293,12 +3318,12 @@ function loadCodespaceEnv() {
|
|
|
3293
3318
|
}
|
|
3294
3319
|
}
|
|
3295
3320
|
var _default = makeConfig();
|
|
3296
|
-
var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, setDisable1mContext, setSessionAgent, clearAll, saveCliConfig, loadCliConfig } = _default;
|
|
3321
|
+
var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, setDisable1mContext, setSessionAgent, setSquadAuto, getSquadAuto, clearAll, saveCliConfig, loadCliConfig } = _default;
|
|
3297
3322
|
|
|
3298
3323
|
// src/commands/pair-auto.ts
|
|
3299
|
-
var
|
|
3300
|
-
var
|
|
3301
|
-
var
|
|
3324
|
+
var fs64 = __toESM(require("fs"));
|
|
3325
|
+
var os54 = __toESM(require("os"));
|
|
3326
|
+
var path69 = __toESM(require("path"));
|
|
3302
3327
|
var import_crypto4 = require("crypto");
|
|
3303
3328
|
|
|
3304
3329
|
// src/services/telemetry.service.ts
|
|
@@ -8048,7 +8073,7 @@ function readAnonId() {
|
|
|
8048
8073
|
}
|
|
8049
8074
|
function superProperties() {
|
|
8050
8075
|
return {
|
|
8051
|
-
cliVersion: true ? "2.
|
|
8076
|
+
cliVersion: true ? "2.65.1" : "0.0.0-dev",
|
|
8052
8077
|
nodeVersion: process.version,
|
|
8053
8078
|
platform: process.platform,
|
|
8054
8079
|
arch: process.arch,
|
|
@@ -8229,7 +8254,7 @@ var os4 = __toESM(require("os"));
|
|
|
8229
8254
|
// package.json
|
|
8230
8255
|
var package_default = {
|
|
8231
8256
|
name: "codeam-cli",
|
|
8232
|
-
version: "2.
|
|
8257
|
+
version: "2.65.1",
|
|
8233
8258
|
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.",
|
|
8234
8259
|
type: "commonjs",
|
|
8235
8260
|
main: "dist/index.js",
|
|
@@ -9681,7 +9706,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9681
9706
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
9682
9707
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
9683
9708
|
// pair/reconnect). Older backends ignore the extra field.
|
|
9684
|
-
..."2.
|
|
9709
|
+
..."2.65.1" ? { ideVersion: "2.65.1" } : {}
|
|
9685
9710
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
9686
9711
|
}
|
|
9687
9712
|
/**
|
|
@@ -11073,11 +11098,11 @@ function closeAllTerminals() {
|
|
|
11073
11098
|
}
|
|
11074
11099
|
|
|
11075
11100
|
// src/commands/start/handlers.ts
|
|
11076
|
-
var
|
|
11077
|
-
var
|
|
11078
|
-
var
|
|
11101
|
+
var fs63 = __toESM(require("fs"));
|
|
11102
|
+
var os53 = __toESM(require("os"));
|
|
11103
|
+
var path68 = __toESM(require("path"));
|
|
11079
11104
|
var import_crypto3 = require("crypto");
|
|
11080
|
-
var
|
|
11105
|
+
var import_child_process26 = require("child_process");
|
|
11081
11106
|
|
|
11082
11107
|
// src/lib/payload.ts
|
|
11083
11108
|
var import_zod = require("zod");
|
|
@@ -11907,8 +11932,8 @@ function findGitRoot2(startDir) {
|
|
|
11907
11932
|
|
|
11908
11933
|
// src/commands/link.ts
|
|
11909
11934
|
var import_node_crypto8 = require("crypto");
|
|
11910
|
-
var
|
|
11911
|
-
var
|
|
11935
|
+
var fs32 = __toESM(require("fs"));
|
|
11936
|
+
var path37 = __toESM(require("path"));
|
|
11912
11937
|
var import_chokidar = __toESM(require("chokidar"));
|
|
11913
11938
|
var import_picocolors2 = __toESM(require("picocolors"));
|
|
11914
11939
|
|
|
@@ -16518,6 +16543,18 @@ var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
|
|
|
16518
16543
|
var INSTALL_TIMEOUT_MS = 15e4;
|
|
16519
16544
|
var PREREQ_INSTALL_TIMEOUT_MS = 12e4;
|
|
16520
16545
|
var REQUIRED_TOOLS = ["unzip", "git"];
|
|
16546
|
+
function defaultRunVersionProbe(binary, env) {
|
|
16547
|
+
const r = (0, import_node_child_process7.spawnSync)(binary, ["--version"], { stdio: "ignore", timeout: 15e3, env });
|
|
16548
|
+
return !r.error && r.status === 0;
|
|
16549
|
+
}
|
|
16550
|
+
function probeRuns(binary, env, deps) {
|
|
16551
|
+
const probe = deps.runVersionProbe ?? defaultRunVersionProbe;
|
|
16552
|
+
try {
|
|
16553
|
+
return probe(binary, env);
|
|
16554
|
+
} catch {
|
|
16555
|
+
return false;
|
|
16556
|
+
}
|
|
16557
|
+
}
|
|
16521
16558
|
function manualInstallHint(runner, tools) {
|
|
16522
16559
|
const pkgs = tools.join(" ");
|
|
16523
16560
|
const argv = osPackageInstallArgv(detectPackageManager(runner), [...tools]);
|
|
@@ -16652,22 +16689,27 @@ async function ensureCoderabbitInstalled(os66, deps = {}) {
|
|
|
16652
16689
|
log.info("coderabbit", "CodeRabbit CLI not found \u2014 installing via the official script");
|
|
16653
16690
|
const run = deps.runInstallScript ?? defaultRunInstallScript;
|
|
16654
16691
|
const { code, output } = await run(env);
|
|
16655
|
-
|
|
16656
|
-
|
|
16692
|
+
os66.augmentPath([`${os66.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
16693
|
+
const binary = os66.findInPath("coderabbit");
|
|
16694
|
+
const detail = summarizeInstallFailure(output);
|
|
16695
|
+
if (binary !== null) {
|
|
16696
|
+
if (code === 0) return { ok: true };
|
|
16697
|
+
if (probeRuns(binary, env, deps)) return { ok: true };
|
|
16657
16698
|
return {
|
|
16658
16699
|
ok: false,
|
|
16659
|
-
error: detail ? `CodeRabbit CLI install failed: ${detail}` : "CodeRabbit CLI install failed \u2014 check this machine's network egress
|
|
16700
|
+
error: detail ? `CodeRabbit CLI install failed and the installed binary does not run: ${detail}` : "CodeRabbit CLI install failed \u2014 the installed `coderabbit` binary does not run. Re-run the install and check this machine's network egress."
|
|
16660
16701
|
};
|
|
16661
16702
|
}
|
|
16662
|
-
|
|
16663
|
-
if (os66.findInPath("coderabbit") === null) {
|
|
16664
|
-
const detail = summarizeInstallFailure(output);
|
|
16703
|
+
if (code !== 0) {
|
|
16665
16704
|
return {
|
|
16666
16705
|
ok: false,
|
|
16667
|
-
error: detail ? `CodeRabbit CLI install
|
|
16706
|
+
error: detail ? `CodeRabbit CLI install failed: ${detail}` : "CodeRabbit CLI install failed \u2014 check this machine's network egress and try again."
|
|
16668
16707
|
};
|
|
16669
16708
|
}
|
|
16670
|
-
return {
|
|
16709
|
+
return {
|
|
16710
|
+
ok: false,
|
|
16711
|
+
error: detail ? `CodeRabbit CLI install did not produce a binary: ${detail}` : "CodeRabbit CLI install reported success but no `coderabbit` binary was found on PATH."
|
|
16712
|
+
};
|
|
16671
16713
|
}
|
|
16672
16714
|
|
|
16673
16715
|
// src/agents/coderabbit/link.ts
|
|
@@ -17556,6 +17598,198 @@ function detectAiderSelector(_lines) {
|
|
|
17556
17598
|
return null;
|
|
17557
17599
|
}
|
|
17558
17600
|
|
|
17601
|
+
// src/agents/acp/agent-binary.ts
|
|
17602
|
+
var import_fs = __toESM(require("fs"));
|
|
17603
|
+
var import_os4 = __toESM(require("os"));
|
|
17604
|
+
var import_path4 = __toESM(require("path"));
|
|
17605
|
+
var import_child_process13 = require("child_process");
|
|
17606
|
+
function currentPlatformKey() {
|
|
17607
|
+
return `${process.platform}-${process.arch}`;
|
|
17608
|
+
}
|
|
17609
|
+
var SDK_PKG = "@anthropic-ai/claude-agent-sdk";
|
|
17610
|
+
function resolveSdkDirViaRequire(req = require) {
|
|
17611
|
+
try {
|
|
17612
|
+
return import_path4.default.dirname(req.resolve(`${SDK_PKG}/package.json`));
|
|
17613
|
+
} catch {
|
|
17614
|
+
}
|
|
17615
|
+
try {
|
|
17616
|
+
let dir = import_path4.default.dirname(req.resolve(SDK_PKG));
|
|
17617
|
+
for (let i = 0; i < 5; i++) {
|
|
17618
|
+
if (import_path4.default.basename(dir) === "claude-agent-sdk") return dir;
|
|
17619
|
+
const parent = import_path4.default.dirname(dir);
|
|
17620
|
+
if (parent === dir) break;
|
|
17621
|
+
dir = parent;
|
|
17622
|
+
}
|
|
17623
|
+
return null;
|
|
17624
|
+
} catch {
|
|
17625
|
+
return null;
|
|
17626
|
+
}
|
|
17627
|
+
}
|
|
17628
|
+
function defaultSdkDir() {
|
|
17629
|
+
return resolveSdkDirViaRequire();
|
|
17630
|
+
}
|
|
17631
|
+
function resolveClaudeNativeBinary(deps = {}) {
|
|
17632
|
+
const existsSync29 = deps.existsSync ?? import_fs.default.existsSync;
|
|
17633
|
+
const platformKey = deps.platformKey ?? currentPlatformKey();
|
|
17634
|
+
const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
|
|
17635
|
+
if (!sdkDir) return null;
|
|
17636
|
+
const scopeDir = import_path4.default.dirname(sdkDir);
|
|
17637
|
+
const binName = platformKey.startsWith("win32-") ? "claude.exe" : "claude";
|
|
17638
|
+
const candidate = import_path4.default.join(scopeDir, `claude-agent-sdk-${platformKey}`, binName);
|
|
17639
|
+
return existsSync29(candidate) ? candidate : null;
|
|
17640
|
+
}
|
|
17641
|
+
var realSleep = (ms) => new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
17642
|
+
async function waitForClaudeNativeBinary(opts = {}) {
|
|
17643
|
+
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
17644
|
+
const pollMs = opts.pollMs ?? 500;
|
|
17645
|
+
const now = opts.now ?? Date.now;
|
|
17646
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
17647
|
+
const deps = {
|
|
17648
|
+
sdkDir: opts.sdkDir,
|
|
17649
|
+
platformKey: opts.platformKey,
|
|
17650
|
+
existsSync: opts.existsSync
|
|
17651
|
+
};
|
|
17652
|
+
const deadline = now() + timeoutMs;
|
|
17653
|
+
let found = resolveClaudeNativeBinary(deps);
|
|
17654
|
+
if (found) return found;
|
|
17655
|
+
while (now() < deadline) {
|
|
17656
|
+
await sleep5(pollMs);
|
|
17657
|
+
found = resolveClaudeNativeBinary(deps);
|
|
17658
|
+
if (found) return found;
|
|
17659
|
+
}
|
|
17660
|
+
return resolveClaudeNativeBinary(deps);
|
|
17661
|
+
}
|
|
17662
|
+
function isCommandOnPath(cmd, probe = defaultWhich) {
|
|
17663
|
+
return probe(cmd);
|
|
17664
|
+
}
|
|
17665
|
+
function defaultWhich(cmd) {
|
|
17666
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
17667
|
+
try {
|
|
17668
|
+
const res = (0, import_child_process13.spawnSync)(finder, [cmd], { stdio: "ignore" });
|
|
17669
|
+
return res.status === 0;
|
|
17670
|
+
} catch {
|
|
17671
|
+
return false;
|
|
17672
|
+
}
|
|
17673
|
+
}
|
|
17674
|
+
async function waitForCommandOnPath(cmd, opts = {}) {
|
|
17675
|
+
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
17676
|
+
const pollMs = opts.pollMs ?? 500;
|
|
17677
|
+
const now = opts.now ?? Date.now;
|
|
17678
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
17679
|
+
const probe = opts.probe;
|
|
17680
|
+
const check = () => isCommandOnPath(cmd, probe);
|
|
17681
|
+
const deadline = now() + timeoutMs;
|
|
17682
|
+
if (check()) return true;
|
|
17683
|
+
while (now() < deadline) {
|
|
17684
|
+
await sleep5(pollMs);
|
|
17685
|
+
if (check()) return true;
|
|
17686
|
+
}
|
|
17687
|
+
return check();
|
|
17688
|
+
}
|
|
17689
|
+
function augmentUserLocalBinPaths() {
|
|
17690
|
+
const home = import_os4.default.homedir();
|
|
17691
|
+
const candidates = [
|
|
17692
|
+
// XDG-style per-user bin — npm's default global-prefix bin dir on most
|
|
17693
|
+
// Linux setups (`npm config set prefix ~/.local` or an nvm-less
|
|
17694
|
+
// per-user npm), and where curl-based agent installers commonly land.
|
|
17695
|
+
import_path4.default.join(home, ".local", "bin"),
|
|
17696
|
+
// Common explicit npm global-prefix conventions seen in the wild
|
|
17697
|
+
// (`npm config set prefix ~/.npm-global`, and Debian/Fedora's
|
|
17698
|
+
// `~/.local/share/npm` layout for `npm config set prefix
|
|
17699
|
+
// ~/.local/share/npm`).
|
|
17700
|
+
import_path4.default.join(home, ".npm-global", "bin"),
|
|
17701
|
+
import_path4.default.join(home, ".local", "share", "npm", "bin")
|
|
17702
|
+
];
|
|
17703
|
+
const parts = (process.env.PATH ?? "").split(import_path4.default.delimiter).filter((p2) => p2.length > 0);
|
|
17704
|
+
const existing = new Set(parts);
|
|
17705
|
+
const additions = candidates.filter((dir) => !existing.has(dir));
|
|
17706
|
+
if (additions.length === 0) return;
|
|
17707
|
+
process.env.PATH = [...additions, ...parts].join(import_path4.default.delimiter);
|
|
17708
|
+
}
|
|
17709
|
+
function resolveCursorAgentBinary(deps = {}) {
|
|
17710
|
+
const existsSync29 = deps.existsSync ?? import_fs.default.existsSync;
|
|
17711
|
+
const platform3 = deps.platform ?? process.platform;
|
|
17712
|
+
const env = deps.env ?? process.env;
|
|
17713
|
+
if (platform3 === "win32") {
|
|
17714
|
+
const localAppData = env.LOCALAPPDATA;
|
|
17715
|
+
if (!localAppData) return null;
|
|
17716
|
+
const exe = import_path4.default.win32.join(localAppData, "cursor-agent", "cursor-agent.exe");
|
|
17717
|
+
return existsSync29(exe) ? exe : null;
|
|
17718
|
+
}
|
|
17719
|
+
const home = deps.homedir ?? import_os4.default.homedir();
|
|
17720
|
+
const unix = import_path4.default.posix.join(home, ".local", "bin", "cursor-agent");
|
|
17721
|
+
return existsSync29(unix) ? unix : null;
|
|
17722
|
+
}
|
|
17723
|
+
async function waitForCursorAgent(opts = {}) {
|
|
17724
|
+
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
17725
|
+
const pollMs = opts.pollMs ?? 500;
|
|
17726
|
+
const now = opts.now ?? Date.now;
|
|
17727
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
17728
|
+
const check = () => resolveCursorAgentBinary(opts) !== null || isCommandOnPath("cursor-agent", opts.probe);
|
|
17729
|
+
const deadline = now() + timeoutMs;
|
|
17730
|
+
if (check()) return true;
|
|
17731
|
+
while (now() < deadline) {
|
|
17732
|
+
await sleep5(pollMs);
|
|
17733
|
+
if (check()) return true;
|
|
17734
|
+
}
|
|
17735
|
+
return check();
|
|
17736
|
+
}
|
|
17737
|
+
var ADAPTER_MODULE_LOAD_ERROR_RE = /ERR_MODULE_NOT_FOUND|Cannot find module|ERR_REQUIRE_ESM|ERR_UNKNOWN_BUILTIN_MODULE|ERR_UNSUPPORTED_DIR_IMPORT|ERR_PACKAGE_PATH_NOT_EXPORTED|ERR_INVALID_PACKAGE_CONFIG|ERR_INVALID_PACKAGE_TARGET|ERR_INVALID_MODULE_SPECIFIER|node:internal\/modules\/|Directory import|SyntaxError|Unexpected (token|end|identifier)|missing \) after argument list/i;
|
|
17738
|
+
var PERMANENT_ADAPTER_STARTUP_RE = /IneligibleTierError|UNSUPPORTED_CLIENT|no longer supported for Gemini Code Assist|not eligible for Gemini Code Assist|Error authenticating|ProjectIdRequiredError/i;
|
|
17739
|
+
function probeAdapterModuleGraph(command2, args2, opts = {}) {
|
|
17740
|
+
const livenessMs = opts.livenessMs ?? 400;
|
|
17741
|
+
const spawnFn = opts.spawnFn ?? import_child_process13.spawn;
|
|
17742
|
+
return new Promise((resolve9) => {
|
|
17743
|
+
let settled = false;
|
|
17744
|
+
let stderr = "";
|
|
17745
|
+
let timer;
|
|
17746
|
+
let child;
|
|
17747
|
+
const finish = (r) => {
|
|
17748
|
+
if (settled) return;
|
|
17749
|
+
settled = true;
|
|
17750
|
+
if (timer) clearTimeout(timer);
|
|
17751
|
+
try {
|
|
17752
|
+
child?.kill("SIGKILL");
|
|
17753
|
+
} catch {
|
|
17754
|
+
}
|
|
17755
|
+
resolve9(r);
|
|
17756
|
+
};
|
|
17757
|
+
try {
|
|
17758
|
+
child = spawnFn(command2, [...args2], { stdio: ["pipe", "ignore", "pipe"] });
|
|
17759
|
+
} catch {
|
|
17760
|
+
resolve9("ok");
|
|
17761
|
+
return;
|
|
17762
|
+
}
|
|
17763
|
+
child.stderr?.on("data", (d3) => {
|
|
17764
|
+
stderr += d3.toString();
|
|
17765
|
+
if (stderr.length > 8192) stderr = stderr.slice(-8192);
|
|
17766
|
+
});
|
|
17767
|
+
child.on("error", () => finish("ok"));
|
|
17768
|
+
child.on("exit", (code) => {
|
|
17769
|
+
if (code !== 0 && code !== null && !PERMANENT_ADAPTER_STARTUP_RE.test(stderr)) {
|
|
17770
|
+
finish("transient");
|
|
17771
|
+
} else {
|
|
17772
|
+
finish("ok");
|
|
17773
|
+
}
|
|
17774
|
+
});
|
|
17775
|
+
timer = setTimeout(() => finish("ok"), livenessMs);
|
|
17776
|
+
});
|
|
17777
|
+
}
|
|
17778
|
+
async function waitForAdapterModuleGraph(command2, args2, opts = {}) {
|
|
17779
|
+
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
17780
|
+
const pollMs = opts.pollMs ?? 500;
|
|
17781
|
+
const now = opts.now ?? Date.now;
|
|
17782
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
17783
|
+
const probeOpts = { livenessMs: opts.livenessMs, spawnFn: opts.spawnFn };
|
|
17784
|
+
const deadline = now() + timeoutMs;
|
|
17785
|
+
if (await probeAdapterModuleGraph(command2, args2, probeOpts) === "ok") return true;
|
|
17786
|
+
while (now() < deadline) {
|
|
17787
|
+
await sleep5(pollMs);
|
|
17788
|
+
if (await probeAdapterModuleGraph(command2, args2, probeOpts) === "ok") return true;
|
|
17789
|
+
}
|
|
17790
|
+
return false;
|
|
17791
|
+
}
|
|
17792
|
+
|
|
17559
17793
|
// src/agents/aider/runtime.ts
|
|
17560
17794
|
var AIDER_CONTEXT_WINDOW = 2e5;
|
|
17561
17795
|
var AIDER_MODELS = [
|
|
@@ -17574,6 +17808,7 @@ var AiderRuntimeStrategy = class {
|
|
|
17574
17808
|
this.os = os66;
|
|
17575
17809
|
}
|
|
17576
17810
|
async prepareLaunch() {
|
|
17811
|
+
augmentUserLocalBinPaths();
|
|
17577
17812
|
const binary = this.os.findInPath("aider");
|
|
17578
17813
|
if (!binary) {
|
|
17579
17814
|
throw new Error(
|
|
@@ -17645,19 +17880,19 @@ var import_node_crypto6 = require("crypto");
|
|
|
17645
17880
|
var import_node_child_process13 = require("child_process");
|
|
17646
17881
|
|
|
17647
17882
|
// src/agents/gemini/local-token.ts
|
|
17648
|
-
var
|
|
17649
|
-
var
|
|
17650
|
-
var
|
|
17883
|
+
var fs29 = __toESM(require("fs"));
|
|
17884
|
+
var os26 = __toESM(require("os"));
|
|
17885
|
+
var path34 = __toESM(require("path"));
|
|
17651
17886
|
function geminiCredentialsPath() {
|
|
17652
|
-
return
|
|
17887
|
+
return path34.join(os26.homedir(), ".gemini", "oauth_creds.json");
|
|
17653
17888
|
}
|
|
17654
17889
|
function geminiCredentialsPaths() {
|
|
17655
17890
|
return [geminiCredentialsPath()];
|
|
17656
17891
|
}
|
|
17657
17892
|
async function extractLocalGeminiToken() {
|
|
17658
17893
|
const file = geminiCredentialsPath();
|
|
17659
|
-
if (!
|
|
17660
|
-
const credential =
|
|
17894
|
+
if (!fs29.existsSync(file)) return null;
|
|
17895
|
+
const credential = fs29.readFileSync(file, "utf8").trim();
|
|
17661
17896
|
if (credential.length === 0) return null;
|
|
17662
17897
|
return { method: "oauth", credential, source: "flat-file" };
|
|
17663
17898
|
}
|
|
@@ -17713,20 +17948,20 @@ function geminiLoginLauncher() {
|
|
|
17713
17948
|
}
|
|
17714
17949
|
|
|
17715
17950
|
// src/agents/gemini/history.ts
|
|
17716
|
-
var
|
|
17717
|
-
var
|
|
17718
|
-
var
|
|
17719
|
-
var GEMINI_ROOT =
|
|
17951
|
+
var fs30 = __toESM(require("fs"));
|
|
17952
|
+
var os27 = __toESM(require("os"));
|
|
17953
|
+
var path35 = __toESM(require("path"));
|
|
17954
|
+
var GEMINI_ROOT = path35.join(os27.homedir(), ".gemini");
|
|
17720
17955
|
function projectNameForCwd(cwd, root) {
|
|
17721
17956
|
try {
|
|
17722
17957
|
const parsed = JSON.parse(
|
|
17723
|
-
|
|
17958
|
+
fs30.readFileSync(path35.join(root, "projects.json"), "utf8")
|
|
17724
17959
|
);
|
|
17725
17960
|
const map = parsed.projects;
|
|
17726
17961
|
if (map && typeof map === "object") {
|
|
17727
17962
|
if (typeof map[cwd] === "string") return map[cwd];
|
|
17728
17963
|
try {
|
|
17729
|
-
const rp =
|
|
17964
|
+
const rp = fs30.realpathSync(cwd);
|
|
17730
17965
|
if (typeof map[rp] === "string") return map[rp];
|
|
17731
17966
|
} catch {
|
|
17732
17967
|
}
|
|
@@ -17735,7 +17970,7 @@ function projectNameForCwd(cwd, root) {
|
|
|
17735
17970
|
} catch (err) {
|
|
17736
17971
|
log.debug("gemini", `projects.json unreadable at ${root} \u2014 using basename fallback`, err);
|
|
17737
17972
|
}
|
|
17738
|
-
return
|
|
17973
|
+
return path35.basename(cwd) || null;
|
|
17739
17974
|
}
|
|
17740
17975
|
function resolveHistoryDir5(cwd, root = GEMINI_ROOT) {
|
|
17741
17976
|
const name = projectNameForCwd(cwd, root);
|
|
@@ -17743,8 +17978,8 @@ function resolveHistoryDir5(cwd, root = GEMINI_ROOT) {
|
|
|
17743
17978
|
log.warn("gemini", `resolveHistoryDir \u2014 could not derive a project name for cwd=${cwd}`);
|
|
17744
17979
|
return null;
|
|
17745
17980
|
}
|
|
17746
|
-
const dir =
|
|
17747
|
-
if (!
|
|
17981
|
+
const dir = path35.join(root, "tmp", name, "chats");
|
|
17982
|
+
if (!fs30.existsSync(dir)) {
|
|
17748
17983
|
log.debug("gemini", `resolveHistoryDir \u2014 chats dir not present yet: ${dir} (project=${name})`);
|
|
17749
17984
|
return null;
|
|
17750
17985
|
}
|
|
@@ -17756,7 +17991,7 @@ function resolveHistoryFile4(cwd, sessionId, root = GEMINI_ROOT) {
|
|
|
17756
17991
|
if (!dir) return null;
|
|
17757
17992
|
let files;
|
|
17758
17993
|
try {
|
|
17759
|
-
files =
|
|
17994
|
+
files = fs30.readdirSync(dir).filter((f) => f.startsWith("session-") && f.endsWith(".jsonl"));
|
|
17760
17995
|
} catch (err) {
|
|
17761
17996
|
log.warn("gemini", `resolveHistoryFile \u2014 cannot read chats dir ${dir} (id8=${id8})`, err);
|
|
17762
17997
|
return null;
|
|
@@ -17768,12 +18003,12 @@ function resolveHistoryFile4(cwd, sessionId, root = GEMINI_ROOT) {
|
|
|
17768
18003
|
const byName = files.find((f) => id8.length > 0 && f.includes(id8));
|
|
17769
18004
|
if (byName) {
|
|
17770
18005
|
log.info("gemini", `resolveHistoryFile \u2014 matched by filename id8=${id8}: ${byName}`);
|
|
17771
|
-
return
|
|
18006
|
+
return path35.join(dir, byName);
|
|
17772
18007
|
}
|
|
17773
18008
|
for (const f of files) {
|
|
17774
|
-
const full =
|
|
18009
|
+
const full = path35.join(dir, f);
|
|
17775
18010
|
try {
|
|
17776
|
-
const firstLine =
|
|
18011
|
+
const firstLine = fs30.readFileSync(full, "utf8").split("\n", 1)[0] ?? "";
|
|
17777
18012
|
const hdr = JSON.parse(firstLine);
|
|
17778
18013
|
if (hdr.sessionId === sessionId) {
|
|
17779
18014
|
log.info("gemini", `resolveHistoryFile \u2014 matched by header sessionId: ${f}`);
|
|
@@ -17786,7 +18021,7 @@ function resolveHistoryFile4(cwd, sessionId, root = GEMINI_ROOT) {
|
|
|
17786
18021
|
let newest = null;
|
|
17787
18022
|
for (const f of files) {
|
|
17788
18023
|
try {
|
|
17789
|
-
const mtime =
|
|
18024
|
+
const mtime = fs30.statSync(path35.join(dir, f)).mtimeMs;
|
|
17790
18025
|
if (!newest || mtime > newest.mtime) newest = { file: f, mtime };
|
|
17791
18026
|
} catch {
|
|
17792
18027
|
}
|
|
@@ -17795,7 +18030,7 @@ function resolveHistoryFile4(cwd, sessionId, root = GEMINI_ROOT) {
|
|
|
17795
18030
|
"gemini",
|
|
17796
18031
|
`resolveHistoryFile \u2014 no id8=${id8} match among ${files.length} file(s) in ${dir}; falling back to newest=${newest?.file ?? "none"}`
|
|
17797
18032
|
);
|
|
17798
|
-
return newest ?
|
|
18033
|
+
return newest ? path35.join(dir, newest.file) : null;
|
|
17799
18034
|
}
|
|
17800
18035
|
function extractGeminiText(content) {
|
|
17801
18036
|
const fromParts = (arr) => Array.isArray(arr) ? arr.map((p2) => {
|
|
@@ -17823,7 +18058,7 @@ function isSyntheticGeminiTurn(text) {
|
|
|
17823
18058
|
function parseHistoryFile5(filePath) {
|
|
17824
18059
|
let raw;
|
|
17825
18060
|
try {
|
|
17826
|
-
raw =
|
|
18061
|
+
raw = fs30.readFileSync(filePath, "utf8");
|
|
17827
18062
|
} catch (err) {
|
|
17828
18063
|
log.warn("gemini", `parseHistoryFile \u2014 cannot read ${filePath}`, err);
|
|
17829
18064
|
return [];
|
|
@@ -17864,7 +18099,7 @@ function parseHistoryFile5(filePath) {
|
|
|
17864
18099
|
}
|
|
17865
18100
|
log.trace(
|
|
17866
18101
|
"gemini",
|
|
17867
|
-
`parseHistoryFile \u2014 ${out2.length} turn(s) from ${
|
|
18102
|
+
`parseHistoryFile \u2014 ${out2.length} turn(s) from ${path35.basename(filePath)}` + (malformed > 0 ? ` (${malformed} malformed line(s) skipped)` : "")
|
|
17868
18103
|
);
|
|
17869
18104
|
return out2;
|
|
17870
18105
|
}
|
|
@@ -18008,42 +18243,42 @@ var import_node_os3 = require("os");
|
|
|
18008
18243
|
var import_node_path4 = require("path");
|
|
18009
18244
|
|
|
18010
18245
|
// src/agents/kimi/history.ts
|
|
18011
|
-
var
|
|
18012
|
-
var
|
|
18013
|
-
var
|
|
18246
|
+
var fs31 = __toESM(require("fs"));
|
|
18247
|
+
var os28 = __toESM(require("os"));
|
|
18248
|
+
var path36 = __toESM(require("path"));
|
|
18014
18249
|
var import_node_crypto7 = require("crypto");
|
|
18015
18250
|
function kimiHome() {
|
|
18016
|
-
return process.env.KIMI_CODE_HOME ||
|
|
18251
|
+
return process.env.KIMI_CODE_HOME || path36.join(os28.homedir(), ".kimi-code");
|
|
18017
18252
|
}
|
|
18018
18253
|
function workDirKey(cwd) {
|
|
18019
18254
|
const hash = (0, import_node_crypto7.createHash)("sha256").update(cwd).digest("hex").slice(0, 12);
|
|
18020
|
-
return `wd_${
|
|
18255
|
+
return `wd_${path36.basename(cwd)}_${hash}`;
|
|
18021
18256
|
}
|
|
18022
18257
|
function resolveHistoryDir6(cwd) {
|
|
18023
|
-
const dir =
|
|
18024
|
-
if (!
|
|
18258
|
+
const dir = path36.join(kimiHome(), "sessions", workDirKey(cwd));
|
|
18259
|
+
if (!fs31.existsSync(dir)) {
|
|
18025
18260
|
log.debug("kimi", `resolveHistoryDir \u2014 session bucket not present yet: ${dir}`);
|
|
18026
18261
|
return null;
|
|
18027
18262
|
}
|
|
18028
18263
|
return dir;
|
|
18029
18264
|
}
|
|
18030
|
-
var WIRE_REL =
|
|
18265
|
+
var WIRE_REL = path36.join("agents", "main", "wire.jsonl");
|
|
18031
18266
|
function resolveHistoryFile5(cwd, sessionId) {
|
|
18032
18267
|
const fromIndex = sessionDirFromIndex(sessionId);
|
|
18033
18268
|
if (fromIndex) {
|
|
18034
|
-
const p2 =
|
|
18035
|
-
if (
|
|
18269
|
+
const p2 = path36.join(fromIndex, WIRE_REL);
|
|
18270
|
+
if (fs31.existsSync(p2)) return p2;
|
|
18036
18271
|
}
|
|
18037
|
-
const bucket2 =
|
|
18038
|
-
const computed =
|
|
18039
|
-
if (
|
|
18272
|
+
const bucket2 = path36.join(kimiHome(), "sessions", workDirKey(cwd));
|
|
18273
|
+
const computed = path36.join(bucket2, sessionId, WIRE_REL);
|
|
18274
|
+
if (fs31.existsSync(computed)) return computed;
|
|
18040
18275
|
const scanned = scanBucketsForSession(sessionId);
|
|
18041
18276
|
if (scanned) return scanned;
|
|
18042
18277
|
return null;
|
|
18043
18278
|
}
|
|
18044
18279
|
function sessionDirFromIndex(sessionId) {
|
|
18045
18280
|
try {
|
|
18046
|
-
const raw =
|
|
18281
|
+
const raw = fs31.readFileSync(path36.join(kimiHome(), "session_index.jsonl"), "utf8");
|
|
18047
18282
|
for (const line of raw.split("\n")) {
|
|
18048
18283
|
if (!line.includes(sessionId)) continue;
|
|
18049
18284
|
try {
|
|
@@ -18059,22 +18294,22 @@ function sessionDirFromIndex(sessionId) {
|
|
|
18059
18294
|
return null;
|
|
18060
18295
|
}
|
|
18061
18296
|
function scanBucketsForSession(sessionId) {
|
|
18062
|
-
const sessionsRoot =
|
|
18297
|
+
const sessionsRoot = path36.join(kimiHome(), "sessions");
|
|
18063
18298
|
let buckets;
|
|
18064
18299
|
try {
|
|
18065
|
-
buckets =
|
|
18300
|
+
buckets = fs31.readdirSync(sessionsRoot, { withFileTypes: true });
|
|
18066
18301
|
} catch {
|
|
18067
18302
|
return null;
|
|
18068
18303
|
}
|
|
18069
18304
|
for (const b of buckets) {
|
|
18070
18305
|
if (!b.isDirectory()) continue;
|
|
18071
|
-
const candidate =
|
|
18072
|
-
if (
|
|
18306
|
+
const candidate = path36.join(sessionsRoot, b.name, sessionId, WIRE_REL);
|
|
18307
|
+
if (fs31.existsSync(candidate)) return candidate;
|
|
18073
18308
|
}
|
|
18074
18309
|
return null;
|
|
18075
18310
|
}
|
|
18076
18311
|
async function discoverSessionId2(cwd, opts) {
|
|
18077
|
-
const bucket2 =
|
|
18312
|
+
const bucket2 = path36.join(kimiHome(), "sessions", workDirKey(cwd));
|
|
18078
18313
|
const floor = opts.sinceMs - 2e3;
|
|
18079
18314
|
const deadline = Date.now() + (opts.timeoutMs ?? 15e3);
|
|
18080
18315
|
for (; ; ) {
|
|
@@ -18087,7 +18322,7 @@ async function discoverSessionId2(cwd, opts) {
|
|
|
18087
18322
|
function newestSessionSince(bucket2, floorMs) {
|
|
18088
18323
|
let entries;
|
|
18089
18324
|
try {
|
|
18090
|
-
entries =
|
|
18325
|
+
entries = fs31.readdirSync(bucket2, { withFileTypes: true });
|
|
18091
18326
|
} catch {
|
|
18092
18327
|
return null;
|
|
18093
18328
|
}
|
|
@@ -18097,7 +18332,7 @@ function newestSessionSince(bucket2, floorMs) {
|
|
|
18097
18332
|
if (!e.isDirectory() || !e.name.startsWith("session_")) continue;
|
|
18098
18333
|
let mtime;
|
|
18099
18334
|
try {
|
|
18100
|
-
mtime =
|
|
18335
|
+
mtime = fs31.statSync(path36.join(bucket2, e.name)).mtimeMs;
|
|
18101
18336
|
} catch {
|
|
18102
18337
|
continue;
|
|
18103
18338
|
}
|
|
@@ -18118,7 +18353,7 @@ function joinTextParts(parts) {
|
|
|
18118
18353
|
function parseHistoryFile6(filePath) {
|
|
18119
18354
|
let raw;
|
|
18120
18355
|
try {
|
|
18121
|
-
raw =
|
|
18356
|
+
raw = fs31.readFileSync(filePath, "utf8");
|
|
18122
18357
|
} catch {
|
|
18123
18358
|
return [];
|
|
18124
18359
|
}
|
|
@@ -18496,7 +18731,7 @@ function parseLinkArgs(args2) {
|
|
|
18496
18731
|
if (apiKeyFileArg) {
|
|
18497
18732
|
const filePath = apiKeyFileArg.slice("--api-key-file=".length);
|
|
18498
18733
|
try {
|
|
18499
|
-
apiKey =
|
|
18734
|
+
apiKey = fs32.readFileSync(path37.resolve(filePath), "utf8").trim();
|
|
18500
18735
|
} catch (err) {
|
|
18501
18736
|
throw new Error(`Could not read --api-key-file ${filePath}: ${err.message}`);
|
|
18502
18737
|
}
|
|
@@ -18623,7 +18858,7 @@ async function link(args2 = []) {
|
|
|
18623
18858
|
return;
|
|
18624
18859
|
}
|
|
18625
18860
|
if (parsed.tokenFile) {
|
|
18626
|
-
const credential =
|
|
18861
|
+
const credential = fs32.readFileSync(path37.resolve(parsed.tokenFile), "utf8").trim();
|
|
18627
18862
|
if (!credential) {
|
|
18628
18863
|
showError(`--token-file ${parsed.tokenFile} is empty.`);
|
|
18629
18864
|
process.exit(1);
|
|
@@ -18842,13 +19077,13 @@ async function linkDryRunPreflight(ctx) {
|
|
|
18842
19077
|
// src/agents/coderabbit/configure.ts
|
|
18843
19078
|
var import_node_child_process17 = require("child_process");
|
|
18844
19079
|
var import_node_fs6 = require("fs");
|
|
18845
|
-
var
|
|
19080
|
+
var path39 = __toESM(require("path"));
|
|
18846
19081
|
|
|
18847
19082
|
// src/agents/coderabbit/oauth.ts
|
|
18848
19083
|
var import_node_child_process16 = require("child_process");
|
|
18849
|
-
var
|
|
18850
|
-
var
|
|
18851
|
-
var
|
|
19084
|
+
var fs33 = __toESM(require("fs"));
|
|
19085
|
+
var os29 = __toESM(require("os"));
|
|
19086
|
+
var path38 = __toESM(require("path"));
|
|
18852
19087
|
function parseCoderabbitAuthEvent(line) {
|
|
18853
19088
|
const l = line.replace(/\x1b\[[0-9;?]*[A-Za-z]/g, "").trim();
|
|
18854
19089
|
if (!l || l[0] !== "{") return null;
|
|
@@ -18897,8 +19132,8 @@ function resolvePython() {
|
|
|
18897
19132
|
function spawnCoderabbitLoginProc(cmd, args2) {
|
|
18898
19133
|
const python = resolvePython();
|
|
18899
19134
|
if (python) {
|
|
18900
|
-
const helper =
|
|
18901
|
-
|
|
19135
|
+
const helper = path38.join(os29.tmpdir(), "codeam-cr-pty.py");
|
|
19136
|
+
fs33.writeFileSync(helper, PYTHON_PTY_HELPER, { mode: 420 });
|
|
18902
19137
|
return (0, import_node_child_process16.spawn)(python, [helper, cmd, ...args2], {
|
|
18903
19138
|
stdio: ["pipe", "pipe", "pipe"],
|
|
18904
19139
|
env: { ...process.env, TERM: "xterm-256color", COLUMNS: "220", LINES: "50" },
|
|
@@ -19009,7 +19244,7 @@ function runCoderabbitOAuthLogin(deps) {
|
|
|
19009
19244
|
});
|
|
19010
19245
|
}
|
|
19011
19246
|
function coderabbitDir(home) {
|
|
19012
|
-
return
|
|
19247
|
+
return path38.join(home ?? os29.homedir(), ".coderabbit");
|
|
19013
19248
|
}
|
|
19014
19249
|
var NON_CREDENTIAL = /* @__PURE__ */ new Set(["doctor.json", "machine-id"]);
|
|
19015
19250
|
function snapshotCredentialDir(home) {
|
|
@@ -19017,14 +19252,14 @@ function snapshotCredentialDir(home) {
|
|
|
19017
19252
|
const snap = {};
|
|
19018
19253
|
let entries;
|
|
19019
19254
|
try {
|
|
19020
|
-
entries =
|
|
19255
|
+
entries = fs33.readdirSync(dir, { withFileTypes: true });
|
|
19021
19256
|
} catch {
|
|
19022
19257
|
return snap;
|
|
19023
19258
|
}
|
|
19024
19259
|
for (const e of entries) {
|
|
19025
19260
|
if (!e.isFile() || NON_CREDENTIAL.has(e.name)) continue;
|
|
19026
19261
|
try {
|
|
19027
|
-
const st3 =
|
|
19262
|
+
const st3 = fs33.statSync(path38.join(dir, e.name));
|
|
19028
19263
|
snap[e.name] = `${st3.mtimeMs}:${st3.size}`;
|
|
19029
19264
|
} catch {
|
|
19030
19265
|
}
|
|
@@ -19042,7 +19277,7 @@ function diffCapturedCredential(before, home) {
|
|
|
19042
19277
|
}
|
|
19043
19278
|
if (!best) return null;
|
|
19044
19279
|
try {
|
|
19045
|
-
return { file: best.file, contents:
|
|
19280
|
+
return { file: best.file, contents: fs33.readFileSync(path38.join(dir, best.file), "utf8") };
|
|
19046
19281
|
} catch {
|
|
19047
19282
|
return null;
|
|
19048
19283
|
}
|
|
@@ -19119,7 +19354,7 @@ function collectChangedFiles(cwd) {
|
|
|
19119
19354
|
return [...byPath.values()];
|
|
19120
19355
|
}
|
|
19121
19356
|
function restoreCoderabbitOauthBlob(os66, value) {
|
|
19122
|
-
const dir =
|
|
19357
|
+
const dir = path39.join(os66.homeDir(), ".coderabbit");
|
|
19123
19358
|
(0, import_node_fs6.mkdirSync)(dir, { recursive: true });
|
|
19124
19359
|
let file = "auth.json";
|
|
19125
19360
|
let contents = value.trim();
|
|
@@ -19127,13 +19362,13 @@ function restoreCoderabbitOauthBlob(os66, value) {
|
|
|
19127
19362
|
try {
|
|
19128
19363
|
const parsed = JSON.parse(contents);
|
|
19129
19364
|
if (typeof parsed.file === "string" && typeof parsed.contents === "string") {
|
|
19130
|
-
file =
|
|
19365
|
+
file = path39.basename(parsed.file);
|
|
19131
19366
|
contents = parsed.contents;
|
|
19132
19367
|
}
|
|
19133
19368
|
} catch {
|
|
19134
19369
|
}
|
|
19135
19370
|
}
|
|
19136
|
-
(0, import_node_fs6.writeFileSync)(
|
|
19371
|
+
(0, import_node_fs6.writeFileSync)(path39.join(dir, file), contents, { mode: 384 });
|
|
19137
19372
|
}
|
|
19138
19373
|
function installFailureMessage(result) {
|
|
19139
19374
|
return result.error ?? "CodeRabbit CLI could not be installed";
|
|
@@ -19149,10 +19384,10 @@ async function configureCoderabbit(input, deps = {}) {
|
|
|
19149
19384
|
const home = os66.homeDir();
|
|
19150
19385
|
os66.augmentPath(
|
|
19151
19386
|
os66.id === "win32" ? [
|
|
19152
|
-
|
|
19153
|
-
|
|
19154
|
-
|
|
19155
|
-
] : [
|
|
19387
|
+
path39.join(home, ".local", "bin"),
|
|
19388
|
+
path39.join(process.env.APPDATA ?? path39.join(home, "AppData", "Roaming"), "npm"),
|
|
19389
|
+
path39.join(home, "scoop", "shims")
|
|
19390
|
+
] : [path39.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
|
|
19156
19391
|
);
|
|
19157
19392
|
const installed2 = os66.findInPath("coderabbit") !== null;
|
|
19158
19393
|
const base = () => ({
|
|
@@ -19461,9 +19696,9 @@ function defaultRunGh(args2) {
|
|
|
19461
19696
|
|
|
19462
19697
|
// src/commands/host-agent.ts
|
|
19463
19698
|
var import_node_child_process25 = require("child_process");
|
|
19464
|
-
var
|
|
19465
|
-
var
|
|
19466
|
-
var
|
|
19699
|
+
var os42 = __toESM(require("os"));
|
|
19700
|
+
var fs46 = __toESM(require("fs"));
|
|
19701
|
+
var path50 = __toESM(require("path"));
|
|
19467
19702
|
|
|
19468
19703
|
// src/integrations/manifest.ts
|
|
19469
19704
|
var import_node_fs8 = __toESM(require("fs"));
|
|
@@ -19586,14 +19821,14 @@ function persistOrClearSkillsFromPayload(skills) {
|
|
|
19586
19821
|
}
|
|
19587
19822
|
|
|
19588
19823
|
// src/commands/host/agent-install.ts
|
|
19589
|
-
var
|
|
19590
|
-
var
|
|
19824
|
+
var import_child_process14 = require("child_process");
|
|
19825
|
+
var os33 = __toESM(require("os"));
|
|
19591
19826
|
function runAgentInstallScript(script, opts = {}) {
|
|
19592
19827
|
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
19593
19828
|
const scope = opts.logScope ?? "agent-install";
|
|
19594
19829
|
return new Promise((resolve9) => {
|
|
19595
|
-
const home = process.env.HOME ||
|
|
19596
|
-
const child = (0,
|
|
19830
|
+
const home = process.env.HOME || os33.homedir();
|
|
19831
|
+
const child = (0, import_child_process14.spawn)("sh", ["-c", script], {
|
|
19597
19832
|
env: { ...process.env, HOME: home },
|
|
19598
19833
|
stdio: ["ignore", "pipe", "pipe"]
|
|
19599
19834
|
});
|
|
@@ -19658,14 +19893,14 @@ function describeReason(reason) {
|
|
|
19658
19893
|
}
|
|
19659
19894
|
|
|
19660
19895
|
// src/commands/host/host-client.ts
|
|
19661
|
-
var
|
|
19662
|
-
var
|
|
19663
|
-
var
|
|
19896
|
+
var fs37 = __toESM(require("fs"));
|
|
19897
|
+
var os34 = __toESM(require("os"));
|
|
19898
|
+
var path42 = __toESM(require("path"));
|
|
19664
19899
|
var import_node_crypto9 = require("crypto");
|
|
19665
19900
|
function sampleCpuTimes() {
|
|
19666
19901
|
let idle = 0;
|
|
19667
19902
|
let total = 0;
|
|
19668
|
-
for (const cpu of
|
|
19903
|
+
for (const cpu of os34.cpus()) {
|
|
19669
19904
|
const t2 = cpu.times;
|
|
19670
19905
|
idle += t2.idle;
|
|
19671
19906
|
total += t2.user + t2.nice + t2.sys + t2.idle + t2.irq;
|
|
@@ -19684,8 +19919,8 @@ var MetricsCollector = class {
|
|
|
19684
19919
|
const prev = this.prevCpu;
|
|
19685
19920
|
this.prevCpu = current2;
|
|
19686
19921
|
if (!prev) {
|
|
19687
|
-
const cores =
|
|
19688
|
-
const proxy =
|
|
19922
|
+
const cores = os34.cpus().length || 1;
|
|
19923
|
+
const proxy = os34.loadavg()[0] / cores * 100;
|
|
19689
19924
|
return Math.min(100, Math.max(0, Math.round(proxy)));
|
|
19690
19925
|
}
|
|
19691
19926
|
const idleDelta = current2.idle - prev.idle;
|
|
@@ -19698,8 +19933,8 @@ var MetricsCollector = class {
|
|
|
19698
19933
|
collect() {
|
|
19699
19934
|
return {
|
|
19700
19935
|
cpuPct: this.cpuPct(),
|
|
19701
|
-
ramUsedMb: Math.round((
|
|
19702
|
-
ramTotalMb: Math.round(
|
|
19936
|
+
ramUsedMb: Math.round((os34.totalmem() - os34.freemem()) / 1048576),
|
|
19937
|
+
ramTotalMb: Math.round(os34.totalmem() / 1048576),
|
|
19703
19938
|
latencyMs: this.lastLatencyMs
|
|
19704
19939
|
};
|
|
19705
19940
|
}
|
|
@@ -19708,19 +19943,19 @@ function apiBase() {
|
|
|
19708
19943
|
return process.env.CODEAM_API_URL ?? resolveApiBaseUrl();
|
|
19709
19944
|
}
|
|
19710
19945
|
function hostIdentityPath() {
|
|
19711
|
-
return
|
|
19946
|
+
return path42.join(os34.homedir(), ".codeam", "host-agent.json");
|
|
19712
19947
|
}
|
|
19713
19948
|
function collectOsInfo() {
|
|
19714
19949
|
return {
|
|
19715
|
-
distro:
|
|
19716
|
-
arch:
|
|
19717
|
-
kernel:
|
|
19950
|
+
distro: os34.platform(),
|
|
19951
|
+
arch: os34.arch(),
|
|
19952
|
+
kernel: os34.release(),
|
|
19718
19953
|
nodeVersion: process.versions.node
|
|
19719
19954
|
};
|
|
19720
19955
|
}
|
|
19721
19956
|
function loadHostIdentity() {
|
|
19722
19957
|
try {
|
|
19723
|
-
const raw =
|
|
19958
|
+
const raw = fs37.readFileSync(hostIdentityPath(), "utf8");
|
|
19724
19959
|
const parsed = JSON.parse(raw);
|
|
19725
19960
|
if (typeof parsed === "object" && parsed !== null && typeof parsed.hostId === "string" && typeof parsed.hostToken === "string" && typeof parsed.controlPluginId === "string") {
|
|
19726
19961
|
const p2 = parsed;
|
|
@@ -19739,8 +19974,8 @@ function loadHostIdentity() {
|
|
|
19739
19974
|
}
|
|
19740
19975
|
function saveHostIdentity(identity) {
|
|
19741
19976
|
const file = hostIdentityPath();
|
|
19742
|
-
|
|
19743
|
-
|
|
19977
|
+
fs37.mkdirSync(path42.dirname(file), { recursive: true, mode: 448 });
|
|
19978
|
+
fs37.writeFileSync(file, JSON.stringify(identity, null, 2), {
|
|
19744
19979
|
encoding: "utf8",
|
|
19745
19980
|
mode: 384
|
|
19746
19981
|
});
|
|
@@ -19785,7 +20020,7 @@ function isTerminalEnrollError(err) {
|
|
|
19785
20020
|
}
|
|
19786
20021
|
function deleteHostIdentity() {
|
|
19787
20022
|
try {
|
|
19788
|
-
|
|
20023
|
+
fs37.rmSync(hostIdentityPath(), { force: true });
|
|
19789
20024
|
} catch {
|
|
19790
20025
|
}
|
|
19791
20026
|
}
|
|
@@ -19809,7 +20044,7 @@ async function postJson(pathname, body) {
|
|
|
19809
20044
|
function resolveHostLabel(label) {
|
|
19810
20045
|
const explicit = label?.trim();
|
|
19811
20046
|
const envLabel = process.env.CODEAM_HOST_LABEL?.trim();
|
|
19812
|
-
const resolved = explicit || envLabel ||
|
|
20047
|
+
const resolved = explicit || envLabel || os34.hostname();
|
|
19813
20048
|
return resolved.slice(0, 80);
|
|
19814
20049
|
}
|
|
19815
20050
|
async function redeemEnrollToken(token, label) {
|
|
@@ -19920,17 +20155,17 @@ async function reportDeployProgress(auth, deployId, step, message, sessionId) {
|
|
|
19920
20155
|
}
|
|
19921
20156
|
|
|
19922
20157
|
// src/commands/host/workspace.ts
|
|
19923
|
-
var
|
|
19924
|
-
var
|
|
19925
|
-
var
|
|
20158
|
+
var fs38 = __toESM(require("fs"));
|
|
20159
|
+
var os35 = __toESM(require("os"));
|
|
20160
|
+
var path43 = __toESM(require("path"));
|
|
19926
20161
|
var import_node_child_process20 = require("child_process");
|
|
19927
20162
|
var import_node_util4 = require("util");
|
|
19928
20163
|
var execFileP4 = (0, import_node_util4.promisify)(import_node_child_process20.execFile);
|
|
19929
20164
|
function isAbsolutePathTarget(target) {
|
|
19930
|
-
return
|
|
20165
|
+
return path43.isAbsolute(target);
|
|
19931
20166
|
}
|
|
19932
20167
|
function selfHostedWorkspaceRoot() {
|
|
19933
|
-
return
|
|
20168
|
+
return path43.join(os35.homedir(), ".codeam", "self-hosted");
|
|
19934
20169
|
}
|
|
19935
20170
|
function nonInteractiveGitEnv() {
|
|
19936
20171
|
return {
|
|
@@ -20000,15 +20235,15 @@ async function configureGitCredentials(dest, repoRef, cloneToken, provider = "gi
|
|
|
20000
20235
|
const isGitlab = provider === "gitlab";
|
|
20001
20236
|
if (isGitlab ? !gitlabProjectPath(repoRef.trim()) : !githubOwnerRepo(repoRef.trim())) return;
|
|
20002
20237
|
if (!cloneToken) return;
|
|
20003
|
-
const credFile =
|
|
20238
|
+
const credFile = path43.join(dest, ".git", "codeam-credentials");
|
|
20004
20239
|
const credLine = isGitlab ? `https://oauth2:${cloneToken}@gitlab.com
|
|
20005
20240
|
` : `https://x-access-token:${cloneToken}@github.com
|
|
20006
20241
|
`;
|
|
20007
|
-
|
|
20242
|
+
fs38.writeFileSync(credFile, credLine, { mode: 384 });
|
|
20008
20243
|
restrictToOwner(credFile);
|
|
20009
20244
|
const env = nonInteractiveGitEnv();
|
|
20010
20245
|
const git2 = (args2) => execFileP4("git", ["-C", dest, ...args2], { timeout: 3e4, env });
|
|
20011
|
-
const credFilePosix = credFile.split(
|
|
20246
|
+
const credFilePosix = credFile.split(path43.sep).join("/");
|
|
20012
20247
|
await git2(["config", "--local", "--replace-all", "credential.helper", ""]).catch(() => {
|
|
20013
20248
|
});
|
|
20014
20249
|
await git2([
|
|
@@ -20041,17 +20276,17 @@ function maskToken(text, cloneToken) {
|
|
|
20041
20276
|
}
|
|
20042
20277
|
async function prepareWorkspace(repoOrPath, deployId, cloneToken, provider = "github", branch) {
|
|
20043
20278
|
if (isAbsolutePathTarget(repoOrPath)) {
|
|
20044
|
-
if (!
|
|
20279
|
+
if (!fs38.existsSync(repoOrPath)) {
|
|
20045
20280
|
throw new Error(`deploy target path does not exist: ${repoOrPath}`);
|
|
20046
20281
|
}
|
|
20047
20282
|
return repoOrPath;
|
|
20048
20283
|
}
|
|
20049
|
-
const dest =
|
|
20050
|
-
if (
|
|
20284
|
+
const dest = path43.join(selfHostedWorkspaceRoot(), deployId);
|
|
20285
|
+
if (fs38.existsSync(path43.join(dest, ".git"))) {
|
|
20051
20286
|
if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken, provider);
|
|
20052
20287
|
return dest;
|
|
20053
20288
|
}
|
|
20054
|
-
|
|
20289
|
+
fs38.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
|
|
20055
20290
|
const cloneUrl = repoCloneUrl(repoOrPath, cloneToken, provider);
|
|
20056
20291
|
const cloneArgs = branch ? ["clone", "--depth", "1", "--branch", branch, cloneUrl, dest] : ["clone", "--depth", "1", cloneUrl, dest];
|
|
20057
20292
|
try {
|
|
@@ -20069,9 +20304,9 @@ async function prepareWorkspace(repoOrPath, deployId, cloneToken, provider = "gi
|
|
|
20069
20304
|
}
|
|
20070
20305
|
|
|
20071
20306
|
// src/commands/host/agent-provisioning.ts
|
|
20072
|
-
var
|
|
20073
|
-
var
|
|
20074
|
-
var
|
|
20307
|
+
var fs39 = __toESM(require("fs"));
|
|
20308
|
+
var os36 = __toESM(require("os"));
|
|
20309
|
+
var path44 = __toESM(require("path"));
|
|
20075
20310
|
var PUBLIC_TO_INTERNAL_AGENT = {
|
|
20076
20311
|
claude_code: "claude",
|
|
20077
20312
|
claude: "claude",
|
|
@@ -20088,22 +20323,22 @@ function toInternalAgentId(publicAgentId) {
|
|
|
20088
20323
|
return PUBLIC_TO_INTERNAL_AGENT[publicAgentId] ?? null;
|
|
20089
20324
|
}
|
|
20090
20325
|
function ensureDir(dir) {
|
|
20091
|
-
|
|
20326
|
+
fs39.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
20092
20327
|
}
|
|
20093
20328
|
function writeFile0600(filePath, contents) {
|
|
20094
|
-
ensureDir(
|
|
20095
|
-
|
|
20329
|
+
ensureDir(path44.dirname(filePath));
|
|
20330
|
+
fs39.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
|
|
20096
20331
|
restrictToOwner(filePath);
|
|
20097
20332
|
}
|
|
20098
20333
|
function rmIfExists(filePath) {
|
|
20099
20334
|
try {
|
|
20100
|
-
|
|
20335
|
+
fs39.rmSync(filePath, { force: true });
|
|
20101
20336
|
} catch {
|
|
20102
20337
|
}
|
|
20103
20338
|
}
|
|
20104
20339
|
var claudeProvisioner = {
|
|
20105
20340
|
write(auth, home) {
|
|
20106
|
-
const credentialsJson =
|
|
20341
|
+
const credentialsJson = path44.join(home, ".claude", ".credentials.json");
|
|
20107
20342
|
if (auth.kind === "api_key") {
|
|
20108
20343
|
rmIfExists(credentialsJson);
|
|
20109
20344
|
return { ANTHROPIC_API_KEY: auth.value };
|
|
@@ -20115,8 +20350,8 @@ var claudeProvisioner = {
|
|
|
20115
20350
|
} else {
|
|
20116
20351
|
rmIfExists(credentialsJson);
|
|
20117
20352
|
}
|
|
20118
|
-
const claudeJson =
|
|
20119
|
-
if (!
|
|
20353
|
+
const claudeJson = path44.join(home, ".claude.json");
|
|
20354
|
+
if (!fs39.existsSync(claudeJson)) {
|
|
20120
20355
|
writeFile0600(
|
|
20121
20356
|
claudeJson,
|
|
20122
20357
|
JSON.stringify({ hasCompletedOnboarding: true, customApiKeyResponses: { approved: [] } })
|
|
@@ -20127,7 +20362,7 @@ var claudeProvisioner = {
|
|
|
20127
20362
|
};
|
|
20128
20363
|
var codexProvisioner = {
|
|
20129
20364
|
write(auth, home) {
|
|
20130
|
-
const authJson =
|
|
20365
|
+
const authJson = path44.join(home, ".codex", "auth.json");
|
|
20131
20366
|
if (auth.kind === "api_key") {
|
|
20132
20367
|
rmIfExists(authJson);
|
|
20133
20368
|
return { OPENAI_API_KEY: auth.value };
|
|
@@ -20138,8 +20373,8 @@ var codexProvisioner = {
|
|
|
20138
20373
|
};
|
|
20139
20374
|
var geminiProvisioner = {
|
|
20140
20375
|
write(auth, home) {
|
|
20141
|
-
const settingsJson =
|
|
20142
|
-
const oauthCreds =
|
|
20376
|
+
const settingsJson = path44.join(home, ".gemini", "settings.json");
|
|
20377
|
+
const oauthCreds = path44.join(home, ".gemini", "oauth_creds.json");
|
|
20143
20378
|
if (auth.kind === "api_key") {
|
|
20144
20379
|
rmIfExists(oauthCreds);
|
|
20145
20380
|
writeFile0600(settingsJson, '{"security":{"auth":{"selectedType":"gemini-api-key"}}}');
|
|
@@ -20152,7 +20387,7 @@ var geminiProvisioner = {
|
|
|
20152
20387
|
};
|
|
20153
20388
|
var cursorProvisioner = {
|
|
20154
20389
|
write(auth, home) {
|
|
20155
|
-
const authJson =
|
|
20390
|
+
const authJson = path44.join(home, ".config", "cursor", "auth.json");
|
|
20156
20391
|
if (auth.kind === "api_key") {
|
|
20157
20392
|
rmIfExists(authJson);
|
|
20158
20393
|
return { CURSOR_API_KEY: auth.value };
|
|
@@ -20194,22 +20429,22 @@ max_context_size = 262144
|
|
|
20194
20429
|
var kimiProvisioner = {
|
|
20195
20430
|
write(auth, home) {
|
|
20196
20431
|
const credentialsFiles = [
|
|
20197
|
-
|
|
20198
|
-
|
|
20432
|
+
path44.join(home, ".kimi", "credentials", "kimi-code.json"),
|
|
20433
|
+
path44.join(home, ".kimi-code", "credentials", "kimi-code.json")
|
|
20199
20434
|
];
|
|
20200
20435
|
if (auth.kind === "api_key") {
|
|
20201
20436
|
credentialsFiles.forEach(rmIfExists);
|
|
20202
20437
|
return { KIMI_API_KEY: auth.value };
|
|
20203
20438
|
}
|
|
20204
20439
|
credentialsFiles.forEach((f) => writeFile0600(f, auth.value));
|
|
20205
|
-
writeFile0600(
|
|
20440
|
+
writeFile0600(path44.join(home, ".kimi-code", "config.toml"), KIMI_MANAGED_CONFIG_TOML);
|
|
20206
20441
|
return {};
|
|
20207
20442
|
}
|
|
20208
20443
|
};
|
|
20209
20444
|
var coderabbitProvisioner = {
|
|
20210
20445
|
write(auth, home) {
|
|
20211
|
-
const dir =
|
|
20212
|
-
const authJson =
|
|
20446
|
+
const dir = path44.join(home, ".coderabbit");
|
|
20447
|
+
const authJson = path44.join(dir, "auth.json");
|
|
20213
20448
|
if (auth.kind === "api_key") {
|
|
20214
20449
|
rmIfExists(authJson);
|
|
20215
20450
|
return { CODERABBIT_API_KEY: auth.value };
|
|
@@ -20221,13 +20456,13 @@ var coderabbitProvisioner = {
|
|
|
20221
20456
|
try {
|
|
20222
20457
|
const parsed = JSON.parse(value);
|
|
20223
20458
|
if (typeof parsed.file === "string" && typeof parsed.contents === "string") {
|
|
20224
|
-
file =
|
|
20459
|
+
file = path44.basename(parsed.file);
|
|
20225
20460
|
contents = parsed.contents;
|
|
20226
20461
|
}
|
|
20227
20462
|
} catch {
|
|
20228
20463
|
}
|
|
20229
20464
|
}
|
|
20230
|
-
writeFile0600(
|
|
20465
|
+
writeFile0600(path44.join(dir, file), contents);
|
|
20231
20466
|
return {};
|
|
20232
20467
|
}
|
|
20233
20468
|
};
|
|
@@ -20255,7 +20490,7 @@ var UnsupportedAgentError = class extends Error {
|
|
|
20255
20490
|
this.agentId = agentId;
|
|
20256
20491
|
}
|
|
20257
20492
|
};
|
|
20258
|
-
function provisionAgentCredentials(publicAgentId, auth, homeDir2 =
|
|
20493
|
+
function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os36.homedir()) {
|
|
20259
20494
|
const internal = toInternalAgentId(publicAgentId);
|
|
20260
20495
|
if (!internal) throw new UnsupportedAgentError(publicAgentId);
|
|
20261
20496
|
const provisioner = PROVISIONERS[internal];
|
|
@@ -20265,11 +20500,11 @@ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os35.homedir(
|
|
|
20265
20500
|
|
|
20266
20501
|
// src/commands/host/git-tooling.ts
|
|
20267
20502
|
var import_node_child_process21 = require("child_process");
|
|
20268
|
-
var
|
|
20269
|
-
var
|
|
20270
|
-
var
|
|
20503
|
+
var fs40 = __toESM(require("fs"));
|
|
20504
|
+
var os37 = __toESM(require("os"));
|
|
20505
|
+
var path45 = __toESM(require("path"));
|
|
20271
20506
|
function codeamBinDir() {
|
|
20272
|
-
return process.env.CODEAM_BIN_DIR ??
|
|
20507
|
+
return process.env.CODEAM_BIN_DIR ?? path45.join(os37.homedir(), ".codeam", "bin");
|
|
20273
20508
|
}
|
|
20274
20509
|
var FALLBACK_GH_VERSION = "2.62.0";
|
|
20275
20510
|
var RELEASE_API = "https://api.github.com/repos/cli/cli/releases/latest";
|
|
@@ -20301,7 +20536,7 @@ async function download(url2, dest) {
|
|
|
20301
20536
|
const res = await fetch(url2, { headers: { "User-Agent": "codeam-cli" } });
|
|
20302
20537
|
if (!res.ok || !res.body) return false;
|
|
20303
20538
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
20304
|
-
|
|
20539
|
+
fs40.writeFileSync(dest, buf);
|
|
20305
20540
|
return true;
|
|
20306
20541
|
} catch {
|
|
20307
20542
|
return false;
|
|
@@ -20324,8 +20559,8 @@ async function ensureGhCli(runner, token, deps = {}) {
|
|
|
20324
20559
|
const version3 = await resolveVersionFn(token);
|
|
20325
20560
|
const asset = `gh_${version3}_${osToken}_${arch2}`;
|
|
20326
20561
|
const url2 = `https://github.com/cli/cli/releases/download/v${version3}/${asset}.${ext}`;
|
|
20327
|
-
const tmpRoot =
|
|
20328
|
-
const archive =
|
|
20562
|
+
const tmpRoot = fs40.mkdtempSync(path45.join(os37.tmpdir(), "codeam-gh-"));
|
|
20563
|
+
const archive = path45.join(tmpRoot, `${asset}.${ext}`);
|
|
20329
20564
|
if (!await downloadFn(url2, archive)) {
|
|
20330
20565
|
log.warn("host-agent", "gh download failed \u2014 skipping (git pull/push still work via the credential helper)");
|
|
20331
20566
|
return null;
|
|
@@ -20335,16 +20570,16 @@ async function ensureGhCli(runner, token, deps = {}) {
|
|
|
20335
20570
|
log.warn("host-agent", `gh archive extraction failed (code=${String(extract.code)}) \u2014 skipping`);
|
|
20336
20571
|
return null;
|
|
20337
20572
|
}
|
|
20338
|
-
const extractedBin =
|
|
20339
|
-
if (!
|
|
20573
|
+
const extractedBin = path45.join(tmpRoot, asset, "bin", binaryName);
|
|
20574
|
+
if (!fs40.existsSync(extractedBin)) {
|
|
20340
20575
|
log.warn("host-agent", "gh binary not found in the extracted archive \u2014 skipping");
|
|
20341
20576
|
return null;
|
|
20342
20577
|
}
|
|
20343
20578
|
const binDir = codeamBinDir();
|
|
20344
|
-
|
|
20345
|
-
const target =
|
|
20346
|
-
|
|
20347
|
-
|
|
20579
|
+
fs40.mkdirSync(binDir, { recursive: true });
|
|
20580
|
+
const target = path45.join(binDir, binaryName);
|
|
20581
|
+
fs40.copyFileSync(extractedBin, target);
|
|
20582
|
+
fs40.chmodSync(target, 493);
|
|
20348
20583
|
log.info("host-agent", `gh installed to ${target} (v${version3})`);
|
|
20349
20584
|
return target;
|
|
20350
20585
|
} catch (e) {
|
|
@@ -20404,8 +20639,8 @@ async function ensureGlabCli(runner, deps = {}) {
|
|
|
20404
20639
|
const version3 = await resolveLatestGlabVersion();
|
|
20405
20640
|
const asset = `glab_${version3}_${osToken}_${arch2}`;
|
|
20406
20641
|
const url2 = `https://gitlab.com/gitlab-org/cli/-/releases/v${version3}/downloads/${asset}.${ext}`;
|
|
20407
|
-
const tmpRoot =
|
|
20408
|
-
const archive =
|
|
20642
|
+
const tmpRoot = fs40.mkdtempSync(path45.join(os37.tmpdir(), "codeam-glab-"));
|
|
20643
|
+
const archive = path45.join(tmpRoot, `${asset}.${ext}`);
|
|
20409
20644
|
if (!await downloadFn(url2, archive)) {
|
|
20410
20645
|
log.warn("host-agent", "glab download failed \u2014 skipping (git push/pull still work)");
|
|
20411
20646
|
return null;
|
|
@@ -20416,20 +20651,20 @@ async function ensureGlabCli(runner, deps = {}) {
|
|
|
20416
20651
|
return null;
|
|
20417
20652
|
}
|
|
20418
20653
|
const candidates = [
|
|
20419
|
-
|
|
20420
|
-
|
|
20421
|
-
|
|
20654
|
+
path45.join(tmpRoot, "bin", binaryName),
|
|
20655
|
+
path45.join(tmpRoot, asset, "bin", binaryName),
|
|
20656
|
+
path45.join(tmpRoot, binaryName)
|
|
20422
20657
|
];
|
|
20423
|
-
const extractedBin = candidates.find((c2) =>
|
|
20658
|
+
const extractedBin = candidates.find((c2) => fs40.existsSync(c2));
|
|
20424
20659
|
if (!extractedBin) {
|
|
20425
20660
|
log.warn("host-agent", "glab binary not found in the extracted archive \u2014 skipping");
|
|
20426
20661
|
return null;
|
|
20427
20662
|
}
|
|
20428
20663
|
const binDir = codeamBinDir();
|
|
20429
|
-
|
|
20430
|
-
const target =
|
|
20431
|
-
|
|
20432
|
-
|
|
20664
|
+
fs40.mkdirSync(binDir, { recursive: true });
|
|
20665
|
+
const target = path45.join(binDir, binaryName);
|
|
20666
|
+
fs40.copyFileSync(extractedBin, target);
|
|
20667
|
+
fs40.chmodSync(target, 493);
|
|
20433
20668
|
log.info("host-agent", `glab installed to ${target} (v${version3})`);
|
|
20434
20669
|
return target;
|
|
20435
20670
|
} catch (e) {
|
|
@@ -20626,24 +20861,24 @@ var HeadroomStatsReporter = class {
|
|
|
20626
20861
|
};
|
|
20627
20862
|
|
|
20628
20863
|
// src/commands/host/headroom-bootstrap.ts
|
|
20629
|
-
var
|
|
20630
|
-
var
|
|
20631
|
-
var
|
|
20864
|
+
var fs42 = __toESM(require("fs"));
|
|
20865
|
+
var path47 = __toESM(require("path"));
|
|
20866
|
+
var os39 = __toESM(require("os"));
|
|
20632
20867
|
|
|
20633
20868
|
// src/commands/host/headroom-config.ts
|
|
20634
|
-
var
|
|
20635
|
-
var
|
|
20636
|
-
var
|
|
20869
|
+
var fs41 = __toESM(require("fs"));
|
|
20870
|
+
var os38 = __toESM(require("os"));
|
|
20871
|
+
var path46 = __toESM(require("path"));
|
|
20637
20872
|
function headroomConfigPath() {
|
|
20638
|
-
return
|
|
20873
|
+
return path46.join(os38.homedir(), ".codeam", "headroom-config.json");
|
|
20639
20874
|
}
|
|
20640
20875
|
function persistHeadroomConfig(config) {
|
|
20641
20876
|
try {
|
|
20642
20877
|
const file = headroomConfigPath();
|
|
20643
|
-
|
|
20878
|
+
fs41.mkdirSync(path46.dirname(file), { recursive: true, mode: 448 });
|
|
20644
20879
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
20645
|
-
|
|
20646
|
-
|
|
20880
|
+
fs41.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
|
|
20881
|
+
fs41.renameSync(tmp, file);
|
|
20647
20882
|
restrictToOwner(file);
|
|
20648
20883
|
} catch (err) {
|
|
20649
20884
|
log.warn(
|
|
@@ -20653,21 +20888,21 @@ function persistHeadroomConfig(config) {
|
|
|
20653
20888
|
}
|
|
20654
20889
|
}
|
|
20655
20890
|
function agentSettingsPath(kind) {
|
|
20656
|
-
const home =
|
|
20657
|
-
if (kind === "claude") return
|
|
20658
|
-
if (kind === "codex") return
|
|
20659
|
-
if (kind === "copilot") return
|
|
20891
|
+
const home = os38.homedir();
|
|
20892
|
+
if (kind === "claude") return path46.join(home, ".claude", "settings.json");
|
|
20893
|
+
if (kind === "codex") return path46.join(home, ".codex", "auth.json");
|
|
20894
|
+
if (kind === "copilot") return path46.join(home, ".config", "github-copilot", "hosts.json");
|
|
20660
20895
|
return null;
|
|
20661
20896
|
}
|
|
20662
20897
|
function backupAgentHeadroomConfig(kind) {
|
|
20663
20898
|
const src = agentSettingsPath(kind);
|
|
20664
20899
|
if (!src) return;
|
|
20665
20900
|
try {
|
|
20666
|
-
if (!
|
|
20667
|
-
const dest =
|
|
20668
|
-
|
|
20669
|
-
|
|
20670
|
-
|
|
20901
|
+
if (!fs41.existsSync(src)) return;
|
|
20902
|
+
const dest = path46.join(os38.homedir(), ".codeam", `headroom-backup-${kind}.json`);
|
|
20903
|
+
fs41.mkdirSync(path46.dirname(dest), { recursive: true, mode: 448 });
|
|
20904
|
+
fs41.copyFileSync(src, dest);
|
|
20905
|
+
fs41.chmodSync(dest, 384);
|
|
20671
20906
|
log.info("host-agent", `headroom config backup: ${src} \u2192 ${dest}`);
|
|
20672
20907
|
} catch (err) {
|
|
20673
20908
|
log.warn(
|
|
@@ -20679,12 +20914,12 @@ function backupAgentHeadroomConfig(kind) {
|
|
|
20679
20914
|
function restoreAgentHeadroomConfig(kind) {
|
|
20680
20915
|
const dest = agentSettingsPath(kind);
|
|
20681
20916
|
if (!dest) return false;
|
|
20682
|
-
const src =
|
|
20683
|
-
if (!
|
|
20917
|
+
const src = path46.join(os38.homedir(), ".codeam", `headroom-backup-${kind}.json`);
|
|
20918
|
+
if (!fs41.existsSync(src)) return false;
|
|
20684
20919
|
try {
|
|
20685
|
-
|
|
20686
|
-
|
|
20687
|
-
|
|
20920
|
+
fs41.mkdirSync(path46.dirname(dest), { recursive: true, mode: 448 });
|
|
20921
|
+
fs41.copyFileSync(src, dest);
|
|
20922
|
+
fs41.chmodSync(dest, 384);
|
|
20688
20923
|
log.info("host-agent", `headroom config restored: ${src} \u2192 ${dest}`);
|
|
20689
20924
|
return true;
|
|
20690
20925
|
} catch (err) {
|
|
@@ -20697,7 +20932,7 @@ function restoreAgentHeadroomConfig(kind) {
|
|
|
20697
20932
|
}
|
|
20698
20933
|
function readHeadroomChildEnv() {
|
|
20699
20934
|
try {
|
|
20700
|
-
const raw =
|
|
20935
|
+
const raw = fs41.readFileSync(headroomConfigPath(), "utf8");
|
|
20701
20936
|
const parsed = JSON.parse(raw);
|
|
20702
20937
|
if (typeof parsed !== "object" || parsed === null) return {};
|
|
20703
20938
|
const o = parsed;
|
|
@@ -20733,49 +20968,49 @@ function bundledClaudeBinDir() {
|
|
|
20733
20968
|
const roots = /* @__PURE__ */ new Set();
|
|
20734
20969
|
let dir = __dirname;
|
|
20735
20970
|
for (let i = 0; i < 6; i++) {
|
|
20736
|
-
roots.add(
|
|
20737
|
-
const parent =
|
|
20971
|
+
roots.add(path47.join(dir, "node_modules"));
|
|
20972
|
+
const parent = path47.dirname(dir);
|
|
20738
20973
|
if (parent === dir) break;
|
|
20739
20974
|
dir = parent;
|
|
20740
20975
|
}
|
|
20741
20976
|
try {
|
|
20742
20977
|
const main2 = require.resolve("@anthropic-ai/claude-agent-sdk");
|
|
20743
|
-
const marker = `${
|
|
20978
|
+
const marker = `${path47.sep}@anthropic-ai${path47.sep}`;
|
|
20744
20979
|
const idx = main2.lastIndexOf(marker);
|
|
20745
20980
|
if (idx !== -1) roots.add(main2.slice(0, idx));
|
|
20746
20981
|
} catch {
|
|
20747
20982
|
}
|
|
20748
20983
|
for (const nm of roots) {
|
|
20749
|
-
const atAnthropic =
|
|
20984
|
+
const atAnthropic = path47.join(nm, "@anthropic-ai");
|
|
20750
20985
|
let entries;
|
|
20751
20986
|
try {
|
|
20752
|
-
entries =
|
|
20987
|
+
entries = fs42.readdirSync(atAnthropic);
|
|
20753
20988
|
} catch {
|
|
20754
20989
|
continue;
|
|
20755
20990
|
}
|
|
20756
20991
|
for (const entry of entries) {
|
|
20757
20992
|
if (!entry.startsWith("claude-agent-sdk-")) continue;
|
|
20758
|
-
const bin =
|
|
20759
|
-
if (
|
|
20993
|
+
const bin = path47.join(atAnthropic, entry, "claude");
|
|
20994
|
+
if (fs42.existsSync(bin)) return path47.dirname(bin);
|
|
20760
20995
|
}
|
|
20761
20996
|
}
|
|
20762
20997
|
return null;
|
|
20763
20998
|
}
|
|
20764
20999
|
async function getFreeDiskBytes(dir) {
|
|
20765
21000
|
try {
|
|
20766
|
-
const s = await
|
|
21001
|
+
const s = await fs42.promises.statfs(dir);
|
|
20767
21002
|
return s.bsize * s.bavail;
|
|
20768
21003
|
} catch {
|
|
20769
21004
|
return null;
|
|
20770
21005
|
}
|
|
20771
21006
|
}
|
|
20772
21007
|
function headroomModelsCached() {
|
|
20773
|
-
const hubDir = process.env.HUGGINGFACE_HUB_CACHE ||
|
|
20774
|
-
process.env.HF_HOME ||
|
|
21008
|
+
const hubDir = process.env.HUGGINGFACE_HUB_CACHE || path47.join(
|
|
21009
|
+
process.env.HF_HOME || path47.join(os39.homedir(), ".cache", "huggingface"),
|
|
20775
21010
|
"hub"
|
|
20776
21011
|
);
|
|
20777
21012
|
return HEADROOM_MODELS.every(
|
|
20778
|
-
(m) =>
|
|
21013
|
+
(m) => fs42.existsSync(path47.join(hubDir, `models--${m.repo.replace("/", "--")}`))
|
|
20779
21014
|
);
|
|
20780
21015
|
}
|
|
20781
21016
|
async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner, opts = {}) {
|
|
@@ -20844,7 +21079,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
|
|
|
20844
21079
|
if (initKind === "claude") {
|
|
20845
21080
|
const claudeDir = bundledClaudeBinDir();
|
|
20846
21081
|
if (claudeDir) {
|
|
20847
|
-
initEnv.PATH = `${claudeDir}${
|
|
21082
|
+
initEnv.PATH = `${claudeDir}${path47.delimiter}${process.env["PATH"] ?? ""}`;
|
|
20848
21083
|
log.info("host-agent", `headroom init: bundled claude on PATH (${claudeDir})`);
|
|
20849
21084
|
} else {
|
|
20850
21085
|
log.warn("host-agent", "headroom init: bundled claude binary not found \u2014 init may fail");
|
|
@@ -20881,19 +21116,19 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
|
|
|
20881
21116
|
}
|
|
20882
21117
|
|
|
20883
21118
|
// src/commands/host/house-proxy-config.ts
|
|
20884
|
-
var
|
|
20885
|
-
var
|
|
20886
|
-
var
|
|
21119
|
+
var fs43 = __toESM(require("fs"));
|
|
21120
|
+
var os40 = __toESM(require("os"));
|
|
21121
|
+
var path48 = __toESM(require("path"));
|
|
20887
21122
|
function houseProxyConfigPath() {
|
|
20888
|
-
return
|
|
21123
|
+
return path48.join(os40.homedir(), ".codeam", "house-proxy.json");
|
|
20889
21124
|
}
|
|
20890
21125
|
function persistHouseProxyConfig(config) {
|
|
20891
21126
|
try {
|
|
20892
21127
|
const file = houseProxyConfigPath();
|
|
20893
|
-
|
|
21128
|
+
fs43.mkdirSync(path48.dirname(file), { recursive: true, mode: 448 });
|
|
20894
21129
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
20895
|
-
|
|
20896
|
-
|
|
21130
|
+
fs43.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
|
|
21131
|
+
fs43.renameSync(tmp, file);
|
|
20897
21132
|
restrictToOwner(file);
|
|
20898
21133
|
} catch (err) {
|
|
20899
21134
|
log.warn(
|
|
@@ -20904,13 +21139,13 @@ function persistHouseProxyConfig(config) {
|
|
|
20904
21139
|
}
|
|
20905
21140
|
function clearHouseProxyConfig() {
|
|
20906
21141
|
try {
|
|
20907
|
-
|
|
21142
|
+
fs43.rmSync(houseProxyConfigPath(), { force: true });
|
|
20908
21143
|
} catch {
|
|
20909
21144
|
}
|
|
20910
21145
|
}
|
|
20911
21146
|
function readHouseProxyChildEnv() {
|
|
20912
21147
|
try {
|
|
20913
|
-
const raw =
|
|
21148
|
+
const raw = fs43.readFileSync(houseProxyConfigPath(), "utf8");
|
|
20914
21149
|
const parsed = JSON.parse(raw);
|
|
20915
21150
|
if (typeof parsed !== "object" || parsed === null) return {};
|
|
20916
21151
|
const o = parsed;
|
|
@@ -20943,9 +21178,9 @@ function readHouseProxyChildEnv() {
|
|
|
20943
21178
|
var import_node_child_process23 = require("child_process");
|
|
20944
21179
|
|
|
20945
21180
|
// src/lib/updateNotifier.ts
|
|
20946
|
-
var
|
|
20947
|
-
var
|
|
20948
|
-
var
|
|
21181
|
+
var fs44 = __toESM(require("fs"));
|
|
21182
|
+
var os41 = __toESM(require("os"));
|
|
21183
|
+
var path49 = __toESM(require("path"));
|
|
20949
21184
|
var https6 = __toESM(require("https"));
|
|
20950
21185
|
var import_node_child_process22 = require("child_process");
|
|
20951
21186
|
var import_picocolors3 = __toESM(require("picocolors"));
|
|
@@ -20954,12 +21189,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
|
20954
21189
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
20955
21190
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
20956
21191
|
function cachePath() {
|
|
20957
|
-
const dir =
|
|
20958
|
-
return
|
|
21192
|
+
const dir = path49.join(os41.homedir(), ".codeam");
|
|
21193
|
+
return path49.join(dir, "update-check.json");
|
|
20959
21194
|
}
|
|
20960
21195
|
function readCache() {
|
|
20961
21196
|
try {
|
|
20962
|
-
const raw =
|
|
21197
|
+
const raw = fs44.readFileSync(cachePath(), "utf8");
|
|
20963
21198
|
const parsed = JSON.parse(raw);
|
|
20964
21199
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
20965
21200
|
return parsed;
|
|
@@ -20970,10 +21205,10 @@ function readCache() {
|
|
|
20970
21205
|
function writeCache(cache) {
|
|
20971
21206
|
try {
|
|
20972
21207
|
const file = cachePath();
|
|
20973
|
-
|
|
21208
|
+
fs44.mkdirSync(path49.dirname(file), { recursive: true });
|
|
20974
21209
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
20975
|
-
|
|
20976
|
-
|
|
21210
|
+
fs44.writeFileSync(tmp, JSON.stringify(cache));
|
|
21211
|
+
fs44.renameSync(tmp, file);
|
|
20977
21212
|
} catch {
|
|
20978
21213
|
}
|
|
20979
21214
|
}
|
|
@@ -21047,8 +21282,8 @@ function isLinkedInstall() {
|
|
|
21047
21282
|
timeout: 2e3
|
|
21048
21283
|
}).trim();
|
|
21049
21284
|
if (!root) return false;
|
|
21050
|
-
const pkgPath =
|
|
21051
|
-
return
|
|
21285
|
+
const pkgPath = path49.join(root, PKG_NAME);
|
|
21286
|
+
return fs44.lstatSync(pkgPath).isSymbolicLink();
|
|
21052
21287
|
} catch {
|
|
21053
21288
|
return false;
|
|
21054
21289
|
}
|
|
@@ -21084,7 +21319,7 @@ function maybeAutoUpdate(currentVersion, latest) {
|
|
|
21084
21319
|
return;
|
|
21085
21320
|
}
|
|
21086
21321
|
try {
|
|
21087
|
-
|
|
21322
|
+
fs44.unlinkSync(cachePath());
|
|
21088
21323
|
} catch {
|
|
21089
21324
|
}
|
|
21090
21325
|
process.stderr.write(` ${import_picocolors3.default.green("\u2713")} Updated. Resuming session...
|
|
@@ -21100,7 +21335,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
21100
21335
|
if (process.env.NODE_ENV === "test") return;
|
|
21101
21336
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21102
21337
|
if (process.env.CI) return;
|
|
21103
|
-
const current2 = true ? "2.
|
|
21338
|
+
const current2 = true ? "2.65.1" : null;
|
|
21104
21339
|
if (!current2) return;
|
|
21105
21340
|
const cache = readCache();
|
|
21106
21341
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21117,7 +21352,7 @@ function checkForUpdates() {
|
|
|
21117
21352
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21118
21353
|
if (process.env.CI) return;
|
|
21119
21354
|
if (!process.stdout.isTTY) return;
|
|
21120
|
-
const current2 = true ? "2.
|
|
21355
|
+
const current2 = true ? "2.65.1" : null;
|
|
21121
21356
|
if (!current2) return;
|
|
21122
21357
|
const cache = readCache();
|
|
21123
21358
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21137,7 +21372,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
21137
21372
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
21138
21373
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
21139
21374
|
function currentCliVersion() {
|
|
21140
|
-
return true ? "2.
|
|
21375
|
+
return true ? "2.65.1" : null;
|
|
21141
21376
|
}
|
|
21142
21377
|
function runCmd(cmd, args2, timeoutMs) {
|
|
21143
21378
|
return new Promise((resolve9) => {
|
|
@@ -21204,7 +21439,7 @@ async function runSelfUpdate() {
|
|
|
21204
21439
|
|
|
21205
21440
|
// src/commands/host/teardown.ts
|
|
21206
21441
|
var import_node_child_process24 = require("child_process");
|
|
21207
|
-
var
|
|
21442
|
+
var fs45 = __toESM(require("fs"));
|
|
21208
21443
|
var defaultDisableService = () => {
|
|
21209
21444
|
try {
|
|
21210
21445
|
(0, import_node_child_process24.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
|
|
@@ -21213,7 +21448,7 @@ var defaultDisableService = () => {
|
|
|
21213
21448
|
};
|
|
21214
21449
|
var defaultTeardownHeadroom = () => {
|
|
21215
21450
|
try {
|
|
21216
|
-
const kind = JSON.parse(
|
|
21451
|
+
const kind = JSON.parse(fs45.readFileSync(headroomConfigPath(), "utf8")).agent;
|
|
21217
21452
|
if (kind) {
|
|
21218
21453
|
(0, import_node_child_process24.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
|
|
21219
21454
|
}
|
|
@@ -21281,8 +21516,8 @@ function maybeResumeLocalHeadroomReporter(ctx) {
|
|
|
21281
21516
|
if (process.env["HEADROOM_ENABLED"] === "1") return null;
|
|
21282
21517
|
try {
|
|
21283
21518
|
const file = headroomConfigPath();
|
|
21284
|
-
if (!
|
|
21285
|
-
const cfg = JSON.parse(
|
|
21519
|
+
if (!fs46.existsSync(file)) return null;
|
|
21520
|
+
const cfg = JSON.parse(fs46.readFileSync(file, "utf8"));
|
|
21286
21521
|
if (!cfg?.enabled) return null;
|
|
21287
21522
|
const agent = cfg.agent ?? "claude";
|
|
21288
21523
|
const ingestUrl = `${resolveApiBaseUrl()}/api/sessions/${ctx.sessionId}/headroom-savings`;
|
|
@@ -21869,13 +22104,13 @@ var HostAgentSupervisor = class {
|
|
|
21869
22104
|
const relay = this.relay;
|
|
21870
22105
|
if (!relay) return;
|
|
21871
22106
|
const raw = cmd.payload?.path;
|
|
21872
|
-
const target = typeof raw === "string" && raw.trim() ?
|
|
22107
|
+
const target = typeof raw === "string" && raw.trim() ? path50.resolve(raw.trim()) : os42.homedir();
|
|
21873
22108
|
try {
|
|
21874
|
-
const dirents = await
|
|
22109
|
+
const dirents = await fs46.promises.readdir(target, { withFileTypes: true });
|
|
21875
22110
|
const entries = dirents.filter((d3) => !d3.name.startsWith(".")).map((d3) => ({ name: d3.name, isDir: d3.isDirectory() })).sort(
|
|
21876
22111
|
(a, b) => a.isDir === b.isDir ? a.name.localeCompare(b.name) : a.isDir ? -1 : 1
|
|
21877
22112
|
);
|
|
21878
|
-
const parent =
|
|
22113
|
+
const parent = path50.dirname(target);
|
|
21879
22114
|
await relay.sendResult(cmd.id, "completed", {
|
|
21880
22115
|
path: target,
|
|
21881
22116
|
// null at the filesystem root so the UI can hide the ".." affordance.
|
|
@@ -22108,14 +22343,14 @@ var HostAgentSupervisor = class {
|
|
|
22108
22343
|
API_TIMEOUT_MS: "3000000",
|
|
22109
22344
|
CODEAM_AUTO_TOKEN: payload.autoPairToken
|
|
22110
22345
|
};
|
|
22111
|
-
const houseConfigDir =
|
|
22112
|
-
|
|
22346
|
+
const houseConfigDir = path50.join(
|
|
22347
|
+
os42.homedir(),
|
|
22113
22348
|
".codeam",
|
|
22114
22349
|
"house-claude",
|
|
22115
22350
|
payload.deployId
|
|
22116
22351
|
);
|
|
22117
22352
|
try {
|
|
22118
|
-
|
|
22353
|
+
fs46.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
|
|
22119
22354
|
} catch {
|
|
22120
22355
|
}
|
|
22121
22356
|
childEnv.CLAUDE_CONFIG_DIR = houseConfigDir;
|
|
@@ -22141,7 +22376,7 @@ var HostAgentSupervisor = class {
|
|
|
22141
22376
|
report("installing", "installing agent CLI");
|
|
22142
22377
|
await this.runAgentInstall(payload.agentInstallScript);
|
|
22143
22378
|
}
|
|
22144
|
-
const home = process.env.HOME ||
|
|
22379
|
+
const home = process.env.HOME || os42.homedir();
|
|
22145
22380
|
childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
|
|
22146
22381
|
if (payload.cloneToken) {
|
|
22147
22382
|
try {
|
|
@@ -22149,13 +22384,13 @@ var HostAgentSupervisor = class {
|
|
|
22149
22384
|
if ((payload.repoProvider ?? "github") === "gitlab") {
|
|
22150
22385
|
const glabCmd = await ensureGlabCli(defaultGitToolingRunner);
|
|
22151
22386
|
if (glabCmd) {
|
|
22152
|
-
childEnv.PATH = `${codeamBinDir()}${
|
|
22387
|
+
childEnv.PATH = `${codeamBinDir()}${path50.delimiter}${childEnv.PATH}`;
|
|
22153
22388
|
await ensureGlabAuth(defaultGitToolingRunner, glabCmd, payload.cloneToken);
|
|
22154
22389
|
}
|
|
22155
22390
|
} else {
|
|
22156
22391
|
const ghCmd = await ensureGhCli(defaultGitToolingRunner, payload.cloneToken);
|
|
22157
22392
|
if (ghCmd) {
|
|
22158
|
-
childEnv.PATH = `${codeamBinDir()}${
|
|
22393
|
+
childEnv.PATH = `${codeamBinDir()}${path50.delimiter}${childEnv.PATH}`;
|
|
22159
22394
|
await ensureGhAuth(defaultGitToolingRunner, ghCmd, payload.cloneToken);
|
|
22160
22395
|
}
|
|
22161
22396
|
}
|
|
@@ -22175,7 +22410,7 @@ var HostAgentSupervisor = class {
|
|
|
22175
22410
|
}
|
|
22176
22411
|
if (payload.headroomEnabled && payload.headroomAgent && payload.headroomSavingsIngestUrl && isHeadroomSupportedAgent(payload.headroomAgent)) {
|
|
22177
22412
|
report("headroom", "setting up Headroom proxy");
|
|
22178
|
-
const freeBytes = await this.getFreeDisk(
|
|
22413
|
+
const freeBytes = await this.getFreeDisk(os42.homedir());
|
|
22179
22414
|
const alreadyInstalled = this.isHeadroomInstalled();
|
|
22180
22415
|
if (!alreadyInstalled && freeBytes !== null && freeBytes < HEADROOM_MIN_FREE_DISK_BYTES) {
|
|
22181
22416
|
const freeGb = (freeBytes / 1e9).toFixed(1);
|
|
@@ -22234,9 +22469,9 @@ var HostAgentSupervisor = class {
|
|
|
22234
22469
|
);
|
|
22235
22470
|
if (!payload.suppressOnboardingWelcome) {
|
|
22236
22471
|
try {
|
|
22237
|
-
const cfgDir = childEnv.CLAUDE_CONFIG_DIR ||
|
|
22238
|
-
const projectDir =
|
|
22239
|
-
const hasPriorConversation =
|
|
22472
|
+
const cfgDir = childEnv.CLAUDE_CONFIG_DIR || path50.join(os42.homedir(), ".claude");
|
|
22473
|
+
const projectDir = path50.join(cfgDir, "projects", encodeCwd(cwd));
|
|
22474
|
+
const hasPriorConversation = fs46.existsSync(projectDir) && fs46.readdirSync(projectDir).some((f) => f.endsWith(".jsonl"));
|
|
22240
22475
|
if (hasPriorConversation) {
|
|
22241
22476
|
childEnv.CODEAM_RESUME_LATEST = "1";
|
|
22242
22477
|
log.info(
|
|
@@ -22335,7 +22570,7 @@ var HostAgentSupervisor = class {
|
|
|
22335
22570
|
if (this.children.size > 0) return;
|
|
22336
22571
|
const session = getActiveSession();
|
|
22337
22572
|
if (!session || !session.pluginId || !session.pollSecret || !session.agent) return;
|
|
22338
|
-
const cwd = session.cwd &&
|
|
22573
|
+
const cwd = session.cwd && fs46.existsSync(session.cwd) ? session.cwd : process.cwd();
|
|
22339
22574
|
const proc = this.resumeSpawner(
|
|
22340
22575
|
{ ...readHeadroomChildEnv(), ...readHouseProxyChildEnv() },
|
|
22341
22576
|
cwd
|
|
@@ -22432,12 +22667,12 @@ var HostAgentSupervisor = class {
|
|
|
22432
22667
|
this.children.delete(deployId);
|
|
22433
22668
|
}
|
|
22434
22669
|
const dirs = [
|
|
22435
|
-
|
|
22436
|
-
|
|
22670
|
+
path50.join(selfHostedWorkspaceRoot(), deployId),
|
|
22671
|
+
path50.join(os42.homedir(), ".codeam", "house-claude", deployId)
|
|
22437
22672
|
];
|
|
22438
22673
|
for (const dir of dirs) {
|
|
22439
22674
|
try {
|
|
22440
|
-
|
|
22675
|
+
fs46.rmSync(dir, { recursive: true, force: true });
|
|
22441
22676
|
} catch (err) {
|
|
22442
22677
|
log.warn(
|
|
22443
22678
|
"host-agent",
|
|
@@ -22574,10 +22809,10 @@ async function configureHeadroom(action, ctx, deps) {
|
|
|
22574
22809
|
}
|
|
22575
22810
|
|
|
22576
22811
|
// src/services/headroom/budget-relaunch.ts
|
|
22577
|
-
var
|
|
22578
|
-
var
|
|
22579
|
-
var
|
|
22580
|
-
var
|
|
22812
|
+
var fs47 = __toESM(require("fs"));
|
|
22813
|
+
var os43 = __toESM(require("os"));
|
|
22814
|
+
var path51 = __toESM(require("path"));
|
|
22815
|
+
var import_child_process15 = require("child_process");
|
|
22581
22816
|
function amendDeploymentManifestBudget(manifest, budget) {
|
|
22582
22817
|
const rawArgs = manifest.proxy_args ?? [];
|
|
22583
22818
|
const strippedArgs = [];
|
|
@@ -22610,7 +22845,7 @@ function amendDeploymentManifestBudget(manifest, budget) {
|
|
|
22610
22845
|
return { ...manifest, proxy_args: newArgs, base_env: newEnv };
|
|
22611
22846
|
}
|
|
22612
22847
|
function findHeadroomDeployments(homeDir2, deps) {
|
|
22613
|
-
const deployDir =
|
|
22848
|
+
const deployDir = path51.join(homeDir2, ".headroom", "deploy");
|
|
22614
22849
|
let profiles;
|
|
22615
22850
|
try {
|
|
22616
22851
|
profiles = deps.readDir(deployDir);
|
|
@@ -22619,7 +22854,7 @@ function findHeadroomDeployments(homeDir2, deps) {
|
|
|
22619
22854
|
}
|
|
22620
22855
|
const results = [];
|
|
22621
22856
|
for (const profile of profiles) {
|
|
22622
|
-
const manifestPath =
|
|
22857
|
+
const manifestPath = path51.join(deployDir, profile, "manifest.json");
|
|
22623
22858
|
let raw;
|
|
22624
22859
|
try {
|
|
22625
22860
|
raw = deps.readJson(manifestPath);
|
|
@@ -22651,12 +22886,12 @@ async function applyBudgetToHeadroom(budget, deps) {
|
|
|
22651
22886
|
}
|
|
22652
22887
|
function writeManifestReal(manifestPath, manifest) {
|
|
22653
22888
|
const tmp = manifestPath + ".codeam.tmp";
|
|
22654
|
-
|
|
22655
|
-
|
|
22889
|
+
fs47.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
|
|
22890
|
+
fs47.renameSync(tmp, manifestPath);
|
|
22656
22891
|
}
|
|
22657
22892
|
function restartDeploymentReal(profile) {
|
|
22658
22893
|
try {
|
|
22659
|
-
const proc = (0,
|
|
22894
|
+
const proc = (0, import_child_process15.spawn)("headroom", ["install", "restart", "--profile", profile], {
|
|
22660
22895
|
detached: true,
|
|
22661
22896
|
stdio: "ignore"
|
|
22662
22897
|
});
|
|
@@ -22687,11 +22922,11 @@ function spawnProxyReal2(_budget) {
|
|
|
22687
22922
|
);
|
|
22688
22923
|
}
|
|
22689
22924
|
function makeRealApplyBudgetDeps() {
|
|
22690
|
-
const homeDir2 =
|
|
22925
|
+
const homeDir2 = os43.homedir();
|
|
22691
22926
|
return {
|
|
22692
22927
|
findDeployments: () => findHeadroomDeployments(homeDir2, {
|
|
22693
|
-
readDir: (dir) =>
|
|
22694
|
-
readJson: (filePath) => JSON.parse(
|
|
22928
|
+
readDir: (dir) => fs47.readdirSync(dir),
|
|
22929
|
+
readJson: (filePath) => JSON.parse(fs47.readFileSync(filePath, "utf8"))
|
|
22695
22930
|
}),
|
|
22696
22931
|
writeManifest: writeManifestReal,
|
|
22697
22932
|
restartDeployment: restartDeploymentReal,
|
|
@@ -22824,47 +23059,47 @@ async function readUsageReport(deps = {}) {
|
|
|
22824
23059
|
}
|
|
22825
23060
|
|
|
22826
23061
|
// src/agents/acp/guardrail-config.ts
|
|
22827
|
-
var
|
|
22828
|
-
var
|
|
22829
|
-
var
|
|
23062
|
+
var fs48 = __toESM(require("fs"));
|
|
23063
|
+
var path52 = __toESM(require("path"));
|
|
23064
|
+
var os44 = __toESM(require("os"));
|
|
22830
23065
|
var current = null;
|
|
22831
|
-
function guardrailConfigPath(homeDir2 =
|
|
22832
|
-
return
|
|
23066
|
+
function guardrailConfigPath(homeDir2 = os44.homedir()) {
|
|
23067
|
+
return path52.join(homeDir2, ".codeam", "guardrails.json");
|
|
22833
23068
|
}
|
|
22834
|
-
function loadGuardrailPolicy(homeDir2 =
|
|
23069
|
+
function loadGuardrailPolicy(homeDir2 = os44.homedir()) {
|
|
22835
23070
|
try {
|
|
22836
|
-
current = normalizeGuardrailPolicy(JSON.parse(
|
|
23071
|
+
current = normalizeGuardrailPolicy(JSON.parse(fs48.readFileSync(guardrailConfigPath(homeDir2), "utf8")));
|
|
22837
23072
|
} catch {
|
|
22838
23073
|
current = { ...DEFAULT_GUARDRAIL_POLICY };
|
|
22839
23074
|
}
|
|
22840
23075
|
return current;
|
|
22841
23076
|
}
|
|
22842
|
-
function getGuardrailPolicy(homeDir2 =
|
|
23077
|
+
function getGuardrailPolicy(homeDir2 = os44.homedir()) {
|
|
22843
23078
|
return current ?? loadGuardrailPolicy(homeDir2);
|
|
22844
23079
|
}
|
|
22845
|
-
function setGuardrailPolicy(raw, homeDir2 =
|
|
23080
|
+
function setGuardrailPolicy(raw, homeDir2 = os44.homedir()) {
|
|
22846
23081
|
const next = normalizeGuardrailPolicy(raw);
|
|
22847
23082
|
current = next;
|
|
22848
23083
|
try {
|
|
22849
23084
|
const p2 = guardrailConfigPath(homeDir2);
|
|
22850
|
-
|
|
22851
|
-
|
|
23085
|
+
fs48.mkdirSync(path52.dirname(p2), { recursive: true });
|
|
23086
|
+
fs48.writeFileSync(p2, JSON.stringify(next, null, 2));
|
|
22852
23087
|
} catch {
|
|
22853
23088
|
}
|
|
22854
23089
|
return next;
|
|
22855
23090
|
}
|
|
22856
23091
|
|
|
22857
23092
|
// src/services/preview/port-registry.ts
|
|
22858
|
-
var
|
|
22859
|
-
var
|
|
22860
|
-
var
|
|
22861
|
-
var
|
|
23093
|
+
var fs49 = __toESM(require("fs"));
|
|
23094
|
+
var os45 = __toESM(require("os"));
|
|
23095
|
+
var path53 = __toESM(require("path"));
|
|
23096
|
+
var import_child_process16 = require("child_process");
|
|
22862
23097
|
function registryPath() {
|
|
22863
|
-
return
|
|
23098
|
+
return path53.join(os45.homedir(), ".codeam", "preview-ports.json");
|
|
22864
23099
|
}
|
|
22865
23100
|
function readRegistry() {
|
|
22866
23101
|
try {
|
|
22867
|
-
const raw =
|
|
23102
|
+
const raw = fs49.readFileSync(registryPath(), "utf8");
|
|
22868
23103
|
const parsed = JSON.parse(raw);
|
|
22869
23104
|
if (parsed && typeof parsed === "object") return parsed;
|
|
22870
23105
|
} catch {
|
|
@@ -22874,10 +23109,10 @@ function readRegistry() {
|
|
|
22874
23109
|
function writeRegistry(reg) {
|
|
22875
23110
|
try {
|
|
22876
23111
|
const file = registryPath();
|
|
22877
|
-
|
|
23112
|
+
fs49.mkdirSync(path53.dirname(file), { recursive: true });
|
|
22878
23113
|
const tmp = `${file}.tmp`;
|
|
22879
|
-
|
|
22880
|
-
|
|
23114
|
+
fs49.writeFileSync(tmp, JSON.stringify(reg), "utf8");
|
|
23115
|
+
fs49.renameSync(tmp, file);
|
|
22881
23116
|
} catch (err) {
|
|
22882
23117
|
log.warn("preview", `port-registry write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
22883
23118
|
}
|
|
@@ -22905,7 +23140,7 @@ function groupAlive(pgid) {
|
|
|
22905
23140
|
}
|
|
22906
23141
|
function killGroup(pgid) {
|
|
22907
23142
|
if (process.platform === "win32") {
|
|
22908
|
-
(0,
|
|
23143
|
+
(0, import_child_process16.spawnSync)("taskkill", ["/F", "/T", "/PID", String(pgid)], { stdio: "ignore" });
|
|
22909
23144
|
return;
|
|
22910
23145
|
}
|
|
22911
23146
|
try {
|
|
@@ -22942,8 +23177,8 @@ function reclaimOwnOrphanPort(port) {
|
|
|
22942
23177
|
}
|
|
22943
23178
|
|
|
22944
23179
|
// src/services/preview/host-allow.ts
|
|
22945
|
-
var
|
|
22946
|
-
var
|
|
23180
|
+
var import_fs2 = require("fs");
|
|
23181
|
+
var path54 = __toESM(require("path"));
|
|
22947
23182
|
var NEXT_ALLOWED_ORIGINS = [
|
|
22948
23183
|
"*.trycloudflare.com",
|
|
22949
23184
|
"*.preview.codeagent-mobile.com",
|
|
@@ -22963,11 +23198,11 @@ var MARKER_DIR = ".codeam";
|
|
|
22963
23198
|
var MARKER_FILE = "preview-host-allow.json";
|
|
22964
23199
|
var ORIG_INFIX = ".codeam-orig";
|
|
22965
23200
|
function markerPath(cwd) {
|
|
22966
|
-
return
|
|
23201
|
+
return path54.join(cwd, MARKER_DIR, MARKER_FILE);
|
|
22967
23202
|
}
|
|
22968
23203
|
async function fileExists(p2) {
|
|
22969
23204
|
try {
|
|
22970
|
-
await
|
|
23205
|
+
await import_fs2.promises.access(p2);
|
|
22971
23206
|
return true;
|
|
22972
23207
|
} catch {
|
|
22973
23208
|
return false;
|
|
@@ -22976,13 +23211,13 @@ async function fileExists(p2) {
|
|
|
22976
23211
|
async function findConfigFile(cwd, framework) {
|
|
22977
23212
|
const base = CONFIG_BASENAMES[framework];
|
|
22978
23213
|
for (const ext of CONFIG_EXTS) {
|
|
22979
|
-
if (await fileExists(
|
|
23214
|
+
if (await fileExists(path54.join(cwd, `${base}${ext}`))) return `${base}${ext}`;
|
|
22980
23215
|
}
|
|
22981
23216
|
return null;
|
|
22982
23217
|
}
|
|
22983
23218
|
async function dependsOn(cwd, pkgName) {
|
|
22984
23219
|
try {
|
|
22985
|
-
const raw = await
|
|
23220
|
+
const raw = await import_fs2.promises.readFile(path54.join(cwd, "package.json"), "utf8");
|
|
22986
23221
|
const pkg = JSON.parse(raw);
|
|
22987
23222
|
return !!(pkg.dependencies?.[pkgName] ?? pkg.devDependencies?.[pkgName]);
|
|
22988
23223
|
} catch {
|
|
@@ -22990,11 +23225,11 @@ async function dependsOn(cwd, pkgName) {
|
|
|
22990
23225
|
}
|
|
22991
23226
|
}
|
|
22992
23227
|
async function isEsmConfig(cwd, configFile) {
|
|
22993
|
-
const ext =
|
|
23228
|
+
const ext = path54.extname(configFile);
|
|
22994
23229
|
if (ext === ".mjs" || ext === ".mts" || ext === ".ts") return true;
|
|
22995
23230
|
if (ext === ".cjs") return false;
|
|
22996
23231
|
try {
|
|
22997
|
-
const raw = await
|
|
23232
|
+
const raw = await import_fs2.promises.readFile(path54.join(cwd, "package.json"), "utf8");
|
|
22998
23233
|
return JSON.parse(raw).type === "module";
|
|
22999
23234
|
} catch {
|
|
23000
23235
|
return false;
|
|
@@ -23077,12 +23312,12 @@ function shimFor(framework, origBasename, esm) {
|
|
|
23077
23312
|
return framework === "next" ? nextShim(origBasename, esm) : viteShim(origBasename, esm);
|
|
23078
23313
|
}
|
|
23079
23314
|
async function writeMarker(cwd, marker) {
|
|
23080
|
-
await
|
|
23081
|
-
await
|
|
23315
|
+
await import_fs2.promises.mkdir(path54.join(cwd, MARKER_DIR), { recursive: true });
|
|
23316
|
+
await import_fs2.promises.writeFile(markerPath(cwd), JSON.stringify(marker, null, 2), "utf8");
|
|
23082
23317
|
}
|
|
23083
23318
|
async function readMarker(cwd) {
|
|
23084
23319
|
try {
|
|
23085
|
-
const parsed = JSON.parse(await
|
|
23320
|
+
const parsed = JSON.parse(await import_fs2.promises.readFile(markerPath(cwd), "utf8"));
|
|
23086
23321
|
return parsed && parsed.configFile ? parsed : null;
|
|
23087
23322
|
} catch {
|
|
23088
23323
|
return null;
|
|
@@ -23092,20 +23327,20 @@ async function restorePreviewHostAllow(cwd) {
|
|
|
23092
23327
|
const marker = await readMarker(cwd);
|
|
23093
23328
|
if (!marker) return;
|
|
23094
23329
|
try {
|
|
23095
|
-
const configAbs =
|
|
23330
|
+
const configAbs = path54.join(cwd, marker.configFile);
|
|
23096
23331
|
if (marker.backupFile) {
|
|
23097
|
-
const backupAbs =
|
|
23332
|
+
const backupAbs = path54.join(cwd, marker.backupFile);
|
|
23098
23333
|
if (await fileExists(backupAbs)) {
|
|
23099
|
-
await
|
|
23100
|
-
await
|
|
23334
|
+
await import_fs2.promises.rm(configAbs, { force: true });
|
|
23335
|
+
await import_fs2.promises.rename(backupAbs, configAbs);
|
|
23101
23336
|
}
|
|
23102
23337
|
} else {
|
|
23103
|
-
await
|
|
23338
|
+
await import_fs2.promises.rm(configAbs, { force: true });
|
|
23104
23339
|
}
|
|
23105
23340
|
} catch (err) {
|
|
23106
23341
|
log.warn("preview", `host-allow restore failed: ${err instanceof Error ? err.message : err}`);
|
|
23107
23342
|
} finally {
|
|
23108
|
-
await
|
|
23343
|
+
await import_fs2.promises.rm(markerPath(cwd), { force: true }).catch(() => void 0);
|
|
23109
23344
|
}
|
|
23110
23345
|
}
|
|
23111
23346
|
async function applyPreviewHostAllow(cwd) {
|
|
@@ -23127,16 +23362,16 @@ async function applyPreviewHostAllow(cwd) {
|
|
|
23127
23362
|
}
|
|
23128
23363
|
if (!framework) return;
|
|
23129
23364
|
if (existing) {
|
|
23130
|
-
const ext =
|
|
23365
|
+
const ext = path54.extname(existing);
|
|
23131
23366
|
const origBasename = `${CONFIG_BASENAMES[framework]}${ORIG_INFIX}${ext}`;
|
|
23132
23367
|
const esm = await isEsmConfig(cwd, existing);
|
|
23133
|
-
await
|
|
23134
|
-
await
|
|
23368
|
+
await import_fs2.promises.rename(path54.join(cwd, existing), path54.join(cwd, origBasename));
|
|
23369
|
+
await import_fs2.promises.writeFile(path54.join(cwd, existing), shimFor(framework, origBasename, esm), "utf8");
|
|
23135
23370
|
await writeMarker(cwd, { framework, configFile: existing, backupFile: origBasename });
|
|
23136
23371
|
log.info("preview", `host-allow: wrapped ${existing} (${framework}) for tunnel access`);
|
|
23137
23372
|
} else {
|
|
23138
23373
|
const configFile = `${CONFIG_BASENAMES[framework]}.mjs`;
|
|
23139
|
-
await
|
|
23374
|
+
await import_fs2.promises.writeFile(path54.join(cwd, configFile), shimFor(framework, null, true), "utf8");
|
|
23140
23375
|
await writeMarker(cwd, { framework, configFile, backupFile: null });
|
|
23141
23376
|
log.info("preview", `host-allow: created ${configFile} (${framework}) for tunnel access`);
|
|
23142
23377
|
}
|
|
@@ -23146,14 +23381,14 @@ async function applyPreviewHostAllow(cwd) {
|
|
|
23146
23381
|
}
|
|
23147
23382
|
|
|
23148
23383
|
// src/services/preview/cloudflared.ts
|
|
23149
|
-
var
|
|
23150
|
-
var
|
|
23384
|
+
var import_child_process17 = require("child_process");
|
|
23385
|
+
var import_fs3 = require("fs");
|
|
23151
23386
|
var import_promises = __toESM(require("fs/promises"));
|
|
23152
|
-
var
|
|
23153
|
-
var
|
|
23387
|
+
var import_os10 = __toESM(require("os"));
|
|
23388
|
+
var import_path5 = __toESM(require("path"));
|
|
23154
23389
|
var import_promises2 = require("stream/promises");
|
|
23155
23390
|
var import_which = __toESM(require("which"));
|
|
23156
|
-
var CACHED_BINARY =
|
|
23391
|
+
var CACHED_BINARY = import_path5.default.join(import_os10.default.homedir(), ".codeam", "bin", "cloudflared");
|
|
23157
23392
|
async function resolveCloudflared(opts = {}) {
|
|
23158
23393
|
try {
|
|
23159
23394
|
return await (0, import_which.default)("cloudflared");
|
|
@@ -23177,7 +23412,7 @@ async function resolveCloudflared(opts = {}) {
|
|
|
23177
23412
|
}
|
|
23178
23413
|
async function downloadCloudflared(target) {
|
|
23179
23414
|
const url2 = downloadUrlForPlatform();
|
|
23180
|
-
await import_promises.default.mkdir(
|
|
23415
|
+
await import_promises.default.mkdir(import_path5.default.dirname(target), { recursive: true });
|
|
23181
23416
|
const response = await fetch(url2);
|
|
23182
23417
|
if (!response.ok || !response.body) {
|
|
23183
23418
|
throw new Error(
|
|
@@ -23188,10 +23423,10 @@ async function downloadCloudflared(target) {
|
|
|
23188
23423
|
const tmp = `${target}.download.tgz`;
|
|
23189
23424
|
await (0, import_promises2.pipeline)(
|
|
23190
23425
|
response.body,
|
|
23191
|
-
(0,
|
|
23426
|
+
(0, import_fs3.createWriteStream)(tmp)
|
|
23192
23427
|
);
|
|
23193
23428
|
try {
|
|
23194
|
-
await extractTgz(tmp,
|
|
23429
|
+
await extractTgz(tmp, import_path5.default.dirname(target));
|
|
23195
23430
|
await import_promises.default.access(target);
|
|
23196
23431
|
await import_promises.default.chmod(target, 493);
|
|
23197
23432
|
} catch (err) {
|
|
@@ -23205,7 +23440,7 @@ async function downloadCloudflared(target) {
|
|
|
23205
23440
|
}
|
|
23206
23441
|
await (0, import_promises2.pipeline)(
|
|
23207
23442
|
response.body,
|
|
23208
|
-
(0,
|
|
23443
|
+
(0, import_fs3.createWriteStream)(target, { mode: 493 })
|
|
23209
23444
|
);
|
|
23210
23445
|
}
|
|
23211
23446
|
async function isExecutableBinary(p2) {
|
|
@@ -23223,7 +23458,7 @@ async function isExecutableBinary(p2) {
|
|
|
23223
23458
|
}
|
|
23224
23459
|
function extractTgz(tgzPath, destDir) {
|
|
23225
23460
|
return new Promise((resolve9, reject) => {
|
|
23226
|
-
const child = (0,
|
|
23461
|
+
const child = (0, import_child_process17.spawn)("tar", ["-xzf", tgzPath, "-C", destDir], { stdio: "ignore" });
|
|
23227
23462
|
child.on("error", (err) => reject(err));
|
|
23228
23463
|
child.on(
|
|
23229
23464
|
"exit",
|
|
@@ -23253,11 +23488,11 @@ function decodeTunnelToken(token) {
|
|
|
23253
23488
|
}
|
|
23254
23489
|
async function spawnNamedTunnel(bin, token, port) {
|
|
23255
23490
|
const creds = decodeTunnelToken(token);
|
|
23256
|
-
const credDir =
|
|
23491
|
+
const credDir = import_path5.default.join(import_os10.default.homedir(), ".codeam");
|
|
23257
23492
|
await import_promises.default.mkdir(credDir, { recursive: true });
|
|
23258
|
-
const credFile =
|
|
23493
|
+
const credFile = import_path5.default.join(credDir, `tunnel-${creds.TunnelID}.json`);
|
|
23259
23494
|
await import_promises.default.writeFile(credFile, JSON.stringify(creds), { mode: 384 });
|
|
23260
|
-
return (0,
|
|
23495
|
+
return (0, import_child_process17.spawn)(
|
|
23261
23496
|
bin,
|
|
23262
23497
|
[
|
|
23263
23498
|
"tunnel",
|
|
@@ -23273,17 +23508,17 @@ async function spawnNamedTunnel(bin, token, port) {
|
|
|
23273
23508
|
}
|
|
23274
23509
|
|
|
23275
23510
|
// src/services/preview/codespace.ts
|
|
23276
|
-
var
|
|
23511
|
+
var import_child_process18 = require("child_process");
|
|
23277
23512
|
var import_util3 = require("util");
|
|
23278
|
-
var execFileP5 = (0, import_util3.promisify)(
|
|
23513
|
+
var execFileP5 = (0, import_util3.promisify)(import_child_process18.execFile);
|
|
23279
23514
|
|
|
23280
23515
|
// src/services/preview/config-file.ts
|
|
23281
23516
|
var import_promises3 = __toESM(require("fs/promises"));
|
|
23282
|
-
var
|
|
23517
|
+
var import_path6 = __toESM(require("path"));
|
|
23283
23518
|
var CONFIG_DIR = ".codeam";
|
|
23284
23519
|
var CONFIG_FILE = "preview.json";
|
|
23285
23520
|
function configPath(cwd) {
|
|
23286
|
-
return
|
|
23521
|
+
return import_path6.default.join(cwd, CONFIG_DIR, CONFIG_FILE);
|
|
23287
23522
|
}
|
|
23288
23523
|
var REQUIRED_FIELDS = [
|
|
23289
23524
|
"framework",
|
|
@@ -23314,7 +23549,7 @@ async function readPreviewConfig(cwd) {
|
|
|
23314
23549
|
}
|
|
23315
23550
|
async function writePreviewConfig(cwd, detection) {
|
|
23316
23551
|
const filePath = configPath(cwd);
|
|
23317
|
-
await import_promises3.default.mkdir(
|
|
23552
|
+
await import_promises3.default.mkdir(import_path6.default.dirname(filePath), { recursive: true });
|
|
23318
23553
|
await import_promises3.default.writeFile(filePath, JSON.stringify(detection, null, 2) + "\n", "utf-8");
|
|
23319
23554
|
}
|
|
23320
23555
|
|
|
@@ -23466,14 +23701,14 @@ async function waitForPortListening(port, opts) {
|
|
|
23466
23701
|
}
|
|
23467
23702
|
|
|
23468
23703
|
// src/services/preview/provision-deps.ts
|
|
23469
|
-
var
|
|
23470
|
-
var
|
|
23704
|
+
var import_fs4 = require("fs");
|
|
23705
|
+
var import_path7 = __toESM(require("path"));
|
|
23471
23706
|
|
|
23472
23707
|
// src/services/preview/run-setup.ts
|
|
23473
|
-
var
|
|
23708
|
+
var import_child_process19 = require("child_process");
|
|
23474
23709
|
function runSetupCommand(cmd, args2, cwd, env, opts) {
|
|
23475
23710
|
return new Promise((resolve9) => {
|
|
23476
|
-
const child = (0,
|
|
23711
|
+
const child = (0, import_child_process19.spawn)(cmd, args2, {
|
|
23477
23712
|
cwd,
|
|
23478
23713
|
env: { ...process.env, ...env ?? {} },
|
|
23479
23714
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -23614,37 +23849,37 @@ function pickMigrationScript(scripts) {
|
|
|
23614
23849
|
}
|
|
23615
23850
|
async function exists(p2) {
|
|
23616
23851
|
try {
|
|
23617
|
-
await
|
|
23852
|
+
await import_fs4.promises.access(p2);
|
|
23618
23853
|
return true;
|
|
23619
23854
|
} catch {
|
|
23620
23855
|
return false;
|
|
23621
23856
|
}
|
|
23622
23857
|
}
|
|
23623
23858
|
async function firstExisting(cwd, names) {
|
|
23624
|
-
for (const n of names) if (await exists(
|
|
23859
|
+
for (const n of names) if (await exists(import_path7.default.join(cwd, n))) return n;
|
|
23625
23860
|
return null;
|
|
23626
23861
|
}
|
|
23627
23862
|
async function ensureEnvFile(cwd, generated) {
|
|
23628
|
-
if (await exists(
|
|
23863
|
+
if (await exists(import_path7.default.join(cwd, ".env"))) {
|
|
23629
23864
|
log.info("provision", ".env already present \u2014 leaving it untouched");
|
|
23630
23865
|
return;
|
|
23631
23866
|
}
|
|
23632
23867
|
const sample = await firstExisting(cwd, ENV_SAMPLES);
|
|
23633
23868
|
if (sample) {
|
|
23634
|
-
const body = await
|
|
23635
|
-
await
|
|
23869
|
+
const body = await import_fs4.promises.readFile(import_path7.default.join(cwd, sample), "utf8");
|
|
23870
|
+
await import_fs4.promises.writeFile(import_path7.default.join(cwd, ".env"), body);
|
|
23636
23871
|
log.info("provision", `wrote .env from ${sample}`);
|
|
23637
23872
|
return;
|
|
23638
23873
|
}
|
|
23639
23874
|
if (generated.length > 0) {
|
|
23640
23875
|
const body = "# Generated by codeam \u2014 points at the auto-provisioned local services.\n" + generated.flatMap((s) => s.envLines).join("\n") + "\n";
|
|
23641
|
-
await
|
|
23876
|
+
await import_fs4.promises.writeFile(import_path7.default.join(cwd, ".env"), body);
|
|
23642
23877
|
log.info("provision", `generated .env for ${generated.map((s) => s.name).join("+")}`);
|
|
23643
23878
|
}
|
|
23644
23879
|
}
|
|
23645
23880
|
async function readPackageJson(cwd) {
|
|
23646
23881
|
try {
|
|
23647
|
-
return JSON.parse(await
|
|
23882
|
+
return JSON.parse(await import_fs4.promises.readFile(import_path7.default.join(cwd, "package.json"), "utf8"));
|
|
23648
23883
|
} catch {
|
|
23649
23884
|
return null;
|
|
23650
23885
|
}
|
|
@@ -23684,10 +23919,10 @@ async function provisionProjectDependencies(cwd) {
|
|
|
23684
23919
|
} else if (pkg) {
|
|
23685
23920
|
generated = detectServicesFromDeps(pkg);
|
|
23686
23921
|
if (generated.length > 0) {
|
|
23687
|
-
const dir =
|
|
23688
|
-
await
|
|
23689
|
-
const file =
|
|
23690
|
-
await
|
|
23922
|
+
const dir = import_path7.default.join(cwd, ".codeam", "provision");
|
|
23923
|
+
await import_fs4.promises.mkdir(dir, { recursive: true });
|
|
23924
|
+
const file = import_path7.default.join(dir, "compose.generated.yaml");
|
|
23925
|
+
await import_fs4.promises.writeFile(file, renderComposeYaml(generated));
|
|
23691
23926
|
log.info(
|
|
23692
23927
|
"provision",
|
|
23693
23928
|
`no compose in repo \u2014 generated ${generated.map((s) => s.name).join("+")}`
|
|
@@ -23708,12 +23943,12 @@ async function provisionProjectDependencies(cwd) {
|
|
|
23708
23943
|
}
|
|
23709
23944
|
|
|
23710
23945
|
// src/services/preview/setup-deps.ts
|
|
23711
|
-
var
|
|
23712
|
-
var
|
|
23946
|
+
var import_fs5 = __toESM(require("fs"));
|
|
23947
|
+
var import_path8 = __toESM(require("path"));
|
|
23713
23948
|
function detectMissingNodeDeps(cwd) {
|
|
23714
|
-
if (!
|
|
23715
|
-
if (
|
|
23716
|
-
if (
|
|
23949
|
+
if (!import_fs5.default.existsSync(import_path8.default.join(cwd, "package.json"))) return null;
|
|
23950
|
+
if (import_fs5.default.existsSync(import_path8.default.join(cwd, "node_modules"))) return null;
|
|
23951
|
+
if (import_fs5.default.existsSync(import_path8.default.join(cwd, "yarn.lock"))) {
|
|
23717
23952
|
return { cmd: "yarn", args: ["install"] };
|
|
23718
23953
|
}
|
|
23719
23954
|
return { cmd: "npm", args: ["install", "--legacy-peer-deps"] };
|
|
@@ -23817,20 +24052,20 @@ function activePreviewSessionIds() {
|
|
|
23817
24052
|
}
|
|
23818
24053
|
|
|
23819
24054
|
// src/services/preview/start-orchestrator.ts
|
|
23820
|
-
var
|
|
23821
|
-
var
|
|
23822
|
-
var
|
|
24055
|
+
var import_child_process21 = require("child_process");
|
|
24056
|
+
var fs57 = __toESM(require("fs"));
|
|
24057
|
+
var path61 = __toESM(require("path"));
|
|
23823
24058
|
var import_which2 = __toESM(require("which"));
|
|
23824
24059
|
|
|
23825
24060
|
// src/services/project-env/index.ts
|
|
23826
|
-
var
|
|
23827
|
-
var
|
|
24061
|
+
var import_fs6 = require("fs");
|
|
24062
|
+
var path60 = __toESM(require("path"));
|
|
23828
24063
|
|
|
23829
24064
|
// src/beads/project-key.ts
|
|
23830
|
-
var
|
|
24065
|
+
var import_child_process20 = require("child_process");
|
|
23831
24066
|
var crypto2 = __toESM(require("crypto"));
|
|
23832
|
-
var
|
|
23833
|
-
var
|
|
24067
|
+
var fs55 = __toESM(require("fs"));
|
|
24068
|
+
var path59 = __toESM(require("path"));
|
|
23834
24069
|
function normalizeOrigin(raw) {
|
|
23835
24070
|
const trimmed = raw.trim();
|
|
23836
24071
|
if (!trimmed) return null;
|
|
@@ -23856,17 +24091,17 @@ function normalizeOrigin(raw) {
|
|
|
23856
24091
|
return `${host2}/${pathPart}`;
|
|
23857
24092
|
}
|
|
23858
24093
|
function findRepoRoot(cwd) {
|
|
23859
|
-
let dir =
|
|
24094
|
+
let dir = path59.resolve(cwd);
|
|
23860
24095
|
const seen = /* @__PURE__ */ new Set();
|
|
23861
24096
|
for (let i = 0; i < 256; i++) {
|
|
23862
24097
|
if (seen.has(dir)) return null;
|
|
23863
24098
|
seen.add(dir);
|
|
23864
24099
|
try {
|
|
23865
|
-
const stat3 =
|
|
24100
|
+
const stat3 = fs55.statSync(path59.join(dir, ".git"), { throwIfNoEntry: false });
|
|
23866
24101
|
if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
|
|
23867
24102
|
} catch {
|
|
23868
24103
|
}
|
|
23869
|
-
const parent =
|
|
24104
|
+
const parent = path59.dirname(dir);
|
|
23870
24105
|
if (parent === dir) return null;
|
|
23871
24106
|
dir = parent;
|
|
23872
24107
|
}
|
|
@@ -23874,10 +24109,10 @@ function findRepoRoot(cwd) {
|
|
|
23874
24109
|
}
|
|
23875
24110
|
var _execSeam2 = {
|
|
23876
24111
|
exec: (file, args2, opts) => {
|
|
23877
|
-
const out2 = (0,
|
|
24112
|
+
const out2 = (0, import_child_process20.execFileSync)(file, args2, opts);
|
|
23878
24113
|
return typeof out2 === "string" ? out2 : out2.toString("utf8");
|
|
23879
24114
|
},
|
|
23880
|
-
realpath: (p2) =>
|
|
24115
|
+
realpath: (p2) => fs55.realpathSync(p2)
|
|
23881
24116
|
};
|
|
23882
24117
|
function readOrigin(cwd) {
|
|
23883
24118
|
try {
|
|
@@ -23906,20 +24141,20 @@ function deriveProjectIdentity(cwd = process.cwd()) {
|
|
|
23906
24141
|
} catch {
|
|
23907
24142
|
}
|
|
23908
24143
|
const hash = crypto2.createHash("sha256").update(real).digest("hex");
|
|
23909
|
-
return { projectKey: `path:${hash}`, projectLabel:
|
|
24144
|
+
return { projectKey: `path:${hash}`, projectLabel: path59.basename(real) || "project" };
|
|
23910
24145
|
}
|
|
23911
24146
|
|
|
23912
24147
|
// src/services/project-env/index.ts
|
|
23913
24148
|
async function readIfExists(p2) {
|
|
23914
24149
|
try {
|
|
23915
|
-
return await
|
|
24150
|
+
return await import_fs6.promises.readFile(p2, "utf8");
|
|
23916
24151
|
} catch {
|
|
23917
24152
|
return null;
|
|
23918
24153
|
}
|
|
23919
24154
|
}
|
|
23920
24155
|
async function syncProjectEnvUp(cwd, ctx) {
|
|
23921
24156
|
if (!ctx.pluginAuthToken) return;
|
|
23922
|
-
const content = await readIfExists(
|
|
24157
|
+
const content = await readIfExists(path60.join(cwd, ".env"));
|
|
23923
24158
|
if (content == null) return;
|
|
23924
24159
|
try {
|
|
23925
24160
|
const { projectKey, projectLabel } = deriveProjectIdentity(cwd);
|
|
@@ -23941,7 +24176,7 @@ async function syncProjectEnvUp(cwd, ctx) {
|
|
|
23941
24176
|
}
|
|
23942
24177
|
async function restoreProjectEnvIfMissing(cwd, ctx) {
|
|
23943
24178
|
if (!ctx.pluginAuthToken) return false;
|
|
23944
|
-
const envPath =
|
|
24179
|
+
const envPath = path60.join(cwd, ".env");
|
|
23945
24180
|
if (await readIfExists(envPath) != null) return false;
|
|
23946
24181
|
try {
|
|
23947
24182
|
const { projectKey, projectLabel } = deriveProjectIdentity(cwd);
|
|
@@ -23952,9 +24187,9 @@ async function restoreProjectEnvIfMissing(cwd, ctx) {
|
|
|
23952
24187
|
projectKey
|
|
23953
24188
|
});
|
|
23954
24189
|
if (!stored) return false;
|
|
23955
|
-
const tmp =
|
|
23956
|
-
await
|
|
23957
|
-
await
|
|
24190
|
+
const tmp = path60.join(cwd, ".env.codeam-restore.tmp");
|
|
24191
|
+
await import_fs6.promises.writeFile(tmp, stored.content, { encoding: "utf8", mode: 384 });
|
|
24192
|
+
await import_fs6.promises.rename(tmp, envPath);
|
|
23958
24193
|
log.info("project-env", `restored .env (${stored.keyCount} vars) for ${projectLabel}`);
|
|
23959
24194
|
return true;
|
|
23960
24195
|
} catch (err) {
|
|
@@ -24029,8 +24264,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
|
|
|
24029
24264
|
if (args2.length === 0) return detection;
|
|
24030
24265
|
const binName = args2[0];
|
|
24031
24266
|
if (binName.startsWith("-")) return detection;
|
|
24032
|
-
const binPath =
|
|
24033
|
-
if (!
|
|
24267
|
+
const binPath = path61.join(cwd, "node_modules", ".bin", binName);
|
|
24268
|
+
if (!fs57.existsSync(binPath)) return detection;
|
|
24034
24269
|
return {
|
|
24035
24270
|
...detection,
|
|
24036
24271
|
command: binPath,
|
|
@@ -24246,7 +24481,7 @@ async function startDevServer(ctx) {
|
|
|
24246
24481
|
await applyPreviewHostAllow(cwd);
|
|
24247
24482
|
const spawnable = normalizeDetectionForSpawn(detection, cwd);
|
|
24248
24483
|
emitProgress("BOOT_SEQUENCE", `${spawnable.command} ${spawnable.args.join(" ")}`);
|
|
24249
|
-
const devServer = (0,
|
|
24484
|
+
const devServer = (0, import_child_process21.spawn)(spawnable.command, spawnable.args, {
|
|
24250
24485
|
cwd,
|
|
24251
24486
|
env: { ...process.env, ...spawnable.env ?? {} },
|
|
24252
24487
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -24371,7 +24606,7 @@ async function establishTunnel(ctx, dev) {
|
|
|
24371
24606
|
`cloudflared quick tunnel (retry ${attempt}/${MAX_TUNNEL_ATTEMPTS})`
|
|
24372
24607
|
);
|
|
24373
24608
|
}
|
|
24374
|
-
const candidate = (0,
|
|
24609
|
+
const candidate = (0, import_child_process21.spawn)(
|
|
24375
24610
|
bin,
|
|
24376
24611
|
["tunnel", "--url", `http://localhost:${detection.port}`],
|
|
24377
24612
|
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
@@ -24402,10 +24637,10 @@ async function establishTunnel(ctx, dev) {
|
|
|
24402
24637
|
}
|
|
24403
24638
|
|
|
24404
24639
|
// src/beads/bd-adapter.ts
|
|
24405
|
-
var
|
|
24406
|
-
var
|
|
24407
|
-
var
|
|
24408
|
-
var
|
|
24640
|
+
var import_child_process22 = require("child_process");
|
|
24641
|
+
var fs58 = __toESM(require("fs"));
|
|
24642
|
+
var os47 = __toESM(require("os"));
|
|
24643
|
+
var path62 = __toESM(require("path"));
|
|
24409
24644
|
var BD_PACKAGE = "@beads/bd";
|
|
24410
24645
|
function resolveBundledBdBinary() {
|
|
24411
24646
|
return _resolveSeam.resolveBundled();
|
|
@@ -24417,11 +24652,11 @@ function _defaultResolveBundled() {
|
|
|
24417
24652
|
} catch {
|
|
24418
24653
|
return null;
|
|
24419
24654
|
}
|
|
24420
|
-
const binDir =
|
|
24655
|
+
const binDir = path62.join(path62.dirname(pkgJsonPath), "bin");
|
|
24421
24656
|
const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
|
|
24422
|
-
const binaryPath =
|
|
24657
|
+
const binaryPath = path62.join(binDir, binaryName);
|
|
24423
24658
|
try {
|
|
24424
|
-
|
|
24659
|
+
fs58.accessSync(binaryPath, fs58.constants.F_OK);
|
|
24425
24660
|
return binaryPath;
|
|
24426
24661
|
} catch {
|
|
24427
24662
|
return null;
|
|
@@ -24431,13 +24666,13 @@ function resolveBdOnPath() {
|
|
|
24431
24666
|
return _resolveSeam.resolveOnPath();
|
|
24432
24667
|
}
|
|
24433
24668
|
function _defaultResolveOnPath() {
|
|
24434
|
-
const dirs = (process.env.PATH ?? "").split(
|
|
24669
|
+
const dirs = (process.env.PATH ?? "").split(path62.delimiter).filter(Boolean);
|
|
24435
24670
|
const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
|
|
24436
24671
|
for (const dir of dirs) {
|
|
24437
24672
|
for (const candidate of candidates) {
|
|
24438
|
-
const full =
|
|
24673
|
+
const full = path62.join(dir, candidate);
|
|
24439
24674
|
try {
|
|
24440
|
-
|
|
24675
|
+
fs58.accessSync(full, fs58.constants.F_OK);
|
|
24441
24676
|
return full;
|
|
24442
24677
|
} catch {
|
|
24443
24678
|
}
|
|
@@ -24456,7 +24691,7 @@ function _defaultSpawn(binaryPath, args2, opts) {
|
|
|
24456
24691
|
return new Promise((resolve9) => {
|
|
24457
24692
|
let proc;
|
|
24458
24693
|
try {
|
|
24459
|
-
proc = (0,
|
|
24694
|
+
proc = (0, import_child_process22.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
|
|
24460
24695
|
} catch (err) {
|
|
24461
24696
|
resolve9({ code: -1, stdout: "", stderr: err.message });
|
|
24462
24697
|
return;
|
|
@@ -24522,7 +24757,7 @@ var BdAdapter = class {
|
|
|
24522
24757
|
const env = { ...process.env };
|
|
24523
24758
|
if (!env.HOME) {
|
|
24524
24759
|
try {
|
|
24525
|
-
const home =
|
|
24760
|
+
const home = os47.homedir();
|
|
24526
24761
|
if (home) env.HOME = home;
|
|
24527
24762
|
} catch {
|
|
24528
24763
|
}
|
|
@@ -24613,13 +24848,13 @@ function coerceIssue(row, projectKey) {
|
|
|
24613
24848
|
}
|
|
24614
24849
|
|
|
24615
24850
|
// src/beads/provisioner.ts
|
|
24616
|
-
var
|
|
24617
|
-
var
|
|
24618
|
-
var
|
|
24619
|
-
var
|
|
24851
|
+
var import_child_process25 = require("child_process");
|
|
24852
|
+
var fs60 = __toESM(require("fs"));
|
|
24853
|
+
var os49 = __toESM(require("os"));
|
|
24854
|
+
var path64 = __toESM(require("path"));
|
|
24620
24855
|
|
|
24621
24856
|
// src/beads/install-bd.ts
|
|
24622
|
-
var
|
|
24857
|
+
var import_child_process23 = require("child_process");
|
|
24623
24858
|
var INSTALL_SH_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh";
|
|
24624
24859
|
var INSTALL_PS1_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/install.ps1";
|
|
24625
24860
|
function resolveInstallStrategy(platform3) {
|
|
@@ -24650,7 +24885,7 @@ function _defaultInstallSpawn(strategy) {
|
|
|
24650
24885
|
return new Promise((resolve9) => {
|
|
24651
24886
|
let proc;
|
|
24652
24887
|
try {
|
|
24653
|
-
proc = (0,
|
|
24888
|
+
proc = (0, import_child_process23.spawn)(strategy.command, strategy.args, { env: process.env });
|
|
24654
24889
|
} catch (err) {
|
|
24655
24890
|
resolve9({ ok: false, code: -1, stderr: err.message });
|
|
24656
24891
|
return;
|
|
@@ -24680,10 +24915,10 @@ async function installBd(platform3 = process.platform) {
|
|
|
24680
24915
|
}
|
|
24681
24916
|
|
|
24682
24917
|
// src/beads/install-dolt.ts
|
|
24683
|
-
var
|
|
24684
|
-
var
|
|
24685
|
-
var
|
|
24686
|
-
var
|
|
24918
|
+
var import_child_process24 = require("child_process");
|
|
24919
|
+
var fs59 = __toESM(require("fs"));
|
|
24920
|
+
var os48 = __toESM(require("os"));
|
|
24921
|
+
var path63 = __toESM(require("path"));
|
|
24687
24922
|
var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
|
|
24688
24923
|
var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
|
|
24689
24924
|
function resolveDoltInstallStrategy(platform3) {
|
|
@@ -24772,14 +25007,14 @@ async function installDoltToDir(targetDir, platform3 = process.platform, arch2 =
|
|
|
24772
25007
|
return result;
|
|
24773
25008
|
}
|
|
24774
25009
|
var _doltPathSeam = {
|
|
24775
|
-
homedir: () =>
|
|
25010
|
+
homedir: () => os48.homedir(),
|
|
24776
25011
|
getPath: () => process.env.PATH ?? "",
|
|
24777
25012
|
setPath: (p2) => {
|
|
24778
25013
|
process.env.PATH = p2;
|
|
24779
25014
|
},
|
|
24780
25015
|
exists: (p2) => {
|
|
24781
25016
|
try {
|
|
24782
|
-
|
|
25017
|
+
fs59.accessSync(p2, fs59.constants.F_OK);
|
|
24783
25018
|
return true;
|
|
24784
25019
|
} catch {
|
|
24785
25020
|
return false;
|
|
@@ -24790,7 +25025,7 @@ function doltBinaryNames(platform3) {
|
|
|
24790
25025
|
return platform3 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
|
|
24791
25026
|
}
|
|
24792
25027
|
function knownDoltDirs(platform3) {
|
|
24793
|
-
const P3 = platform3 === "win32" ?
|
|
25028
|
+
const P3 = platform3 === "win32" ? path63.win32 : path63.posix;
|
|
24794
25029
|
const home = _doltPathSeam.homedir();
|
|
24795
25030
|
if (platform3 === "win32") {
|
|
24796
25031
|
return [
|
|
@@ -24806,7 +25041,7 @@ function knownDoltDirs(platform3) {
|
|
|
24806
25041
|
].filter(Boolean);
|
|
24807
25042
|
}
|
|
24808
25043
|
function ensureDoltResolvable(platform3 = process.platform) {
|
|
24809
|
-
const P3 = platform3 === "win32" ?
|
|
25044
|
+
const P3 = platform3 === "win32" ? path63.win32 : path63.posix;
|
|
24810
25045
|
const delim = platform3 === "win32" ? ";" : ":";
|
|
24811
25046
|
const names = doltBinaryNames(platform3);
|
|
24812
25047
|
const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
|
|
@@ -24842,7 +25077,7 @@ function _defaultDoltInstallSpawn(strategy) {
|
|
|
24842
25077
|
};
|
|
24843
25078
|
let proc;
|
|
24844
25079
|
try {
|
|
24845
|
-
proc = (0,
|
|
25080
|
+
proc = (0, import_child_process24.spawn)(strategy.command, strategy.args, {
|
|
24846
25081
|
env: process.env,
|
|
24847
25082
|
stdio: ["ignore", "pipe", "pipe"]
|
|
24848
25083
|
});
|
|
@@ -24983,17 +25218,17 @@ var _provisionSeam = {
|
|
|
24983
25218
|
};
|
|
24984
25219
|
var _linkSeam = {
|
|
24985
25220
|
platform: () => process.platform,
|
|
24986
|
-
homedir: () =>
|
|
25221
|
+
homedir: () => os49.homedir(),
|
|
24987
25222
|
isWritableDir: (dir) => {
|
|
24988
25223
|
try {
|
|
24989
|
-
|
|
25224
|
+
fs60.accessSync(dir, fs60.constants.W_OK);
|
|
24990
25225
|
return true;
|
|
24991
25226
|
} catch {
|
|
24992
25227
|
return false;
|
|
24993
25228
|
}
|
|
24994
25229
|
},
|
|
24995
25230
|
ensureDir: (dir) => {
|
|
24996
|
-
|
|
25231
|
+
fs60.mkdirSync(dir, { recursive: true });
|
|
24997
25232
|
},
|
|
24998
25233
|
/**
|
|
24999
25234
|
* A directory to symlink `bd` into so the AGENT's shell + Claude Code's
|
|
@@ -25014,9 +25249,9 @@ var _linkSeam = {
|
|
|
25014
25249
|
* which `linkBdOntoPath` creates if missing.
|
|
25015
25250
|
*/
|
|
25016
25251
|
cliBinDir: () => {
|
|
25017
|
-
const pathDirs = (process.env.PATH ?? "").split(
|
|
25252
|
+
const pathDirs = (process.env.PATH ?? "").split(path64.delimiter).filter(Boolean);
|
|
25018
25253
|
const home = _linkSeam.homedir();
|
|
25019
|
-
const localBin = home ?
|
|
25254
|
+
const localBin = home ? path64.join(home, ".local", "bin") : null;
|
|
25020
25255
|
if (localBin) {
|
|
25021
25256
|
try {
|
|
25022
25257
|
_linkSeam.ensureDir(localBin);
|
|
@@ -25026,16 +25261,16 @@ var _linkSeam = {
|
|
|
25026
25261
|
const candidates = [];
|
|
25027
25262
|
if (localBin) candidates.push(localBin);
|
|
25028
25263
|
try {
|
|
25029
|
-
candidates.push(
|
|
25264
|
+
candidates.push(path64.dirname(process.execPath));
|
|
25030
25265
|
} catch {
|
|
25031
25266
|
}
|
|
25032
25267
|
candidates.push("/usr/local/bin");
|
|
25033
25268
|
const entry = process.argv[1];
|
|
25034
25269
|
if (entry) {
|
|
25035
25270
|
try {
|
|
25036
|
-
candidates.push(
|
|
25271
|
+
candidates.push(path64.dirname(fs60.realpathSync(entry)));
|
|
25037
25272
|
} catch {
|
|
25038
|
-
candidates.push(
|
|
25273
|
+
candidates.push(path64.dirname(entry));
|
|
25039
25274
|
}
|
|
25040
25275
|
}
|
|
25041
25276
|
const onPathWritable = candidates.find(
|
|
@@ -25047,20 +25282,20 @@ var _linkSeam = {
|
|
|
25047
25282
|
/** Current symlink target at `linkPath`, or null when absent / not a link. */
|
|
25048
25283
|
readlink: (linkPath) => {
|
|
25049
25284
|
try {
|
|
25050
|
-
return
|
|
25285
|
+
return fs60.readlinkSync(linkPath);
|
|
25051
25286
|
} catch {
|
|
25052
25287
|
return null;
|
|
25053
25288
|
}
|
|
25054
25289
|
},
|
|
25055
|
-
unlink: (linkPath) =>
|
|
25056
|
-
symlink: (target, linkPath) =>
|
|
25290
|
+
unlink: (linkPath) => fs60.unlinkSync(linkPath),
|
|
25291
|
+
symlink: (target, linkPath) => fs60.symlinkSync(target, linkPath)
|
|
25057
25292
|
};
|
|
25058
25293
|
function linkBdOntoPath(binaryPath) {
|
|
25059
25294
|
if (_linkSeam.platform() === "win32") return;
|
|
25060
25295
|
const binDir = _linkSeam.cliBinDir();
|
|
25061
25296
|
if (!binDir) return;
|
|
25062
25297
|
_linkSeam.ensureDir(binDir);
|
|
25063
|
-
const linkPath =
|
|
25298
|
+
const linkPath = path64.join(binDir, "bd");
|
|
25064
25299
|
if (linkPath === binaryPath) return;
|
|
25065
25300
|
const current2 = _linkSeam.readlink(linkPath);
|
|
25066
25301
|
if (current2 === binaryPath) return;
|
|
@@ -25069,7 +25304,7 @@ function linkBdOntoPath(binaryPath) {
|
|
|
25069
25304
|
log.info("beads", `linked bd onto PATH: ${linkPath} -> ${binaryPath}`);
|
|
25070
25305
|
}
|
|
25071
25306
|
function setGitBeadsRole() {
|
|
25072
|
-
(0,
|
|
25307
|
+
(0, import_child_process25.execFileSync)("git", ["config", "--global", "beads.role", "contributor"], {
|
|
25073
25308
|
stdio: "ignore"
|
|
25074
25309
|
});
|
|
25075
25310
|
}
|
|
@@ -25255,7 +25490,7 @@ function dedupeRecipes(agents) {
|
|
|
25255
25490
|
|
|
25256
25491
|
// src/beads/watcher.ts
|
|
25257
25492
|
var crypto4 = __toESM(require("crypto"));
|
|
25258
|
-
var
|
|
25493
|
+
var path65 = __toESM(require("path"));
|
|
25259
25494
|
var API_BASE6 = resolveApiBaseUrl();
|
|
25260
25495
|
var DEBOUNCE_MS2 = 400;
|
|
25261
25496
|
var ZERO_SUMMARY = {
|
|
@@ -25279,7 +25514,7 @@ var BeadsWatcher = class {
|
|
|
25279
25514
|
constructor(opts) {
|
|
25280
25515
|
this.opts = opts;
|
|
25281
25516
|
this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
|
|
25282
|
-
this.feedPath = opts.feedPath ??
|
|
25517
|
+
this.feedPath = opts.feedPath ?? path65.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
|
|
25283
25518
|
this.apiBase = opts.apiBaseUrl ?? API_BASE6;
|
|
25284
25519
|
}
|
|
25285
25520
|
opts;
|
|
@@ -25778,8 +26013,8 @@ function cleanupAttachmentTempFiles() {
|
|
|
25778
26013
|
function saveFilesTemp(files) {
|
|
25779
26014
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
25780
26015
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
25781
|
-
const tmpPath =
|
|
25782
|
-
|
|
26016
|
+
const tmpPath = path68.join(os53.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
|
|
26017
|
+
fs63.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
25783
26018
|
pendingAttachmentFiles.add(tmpPath);
|
|
25784
26019
|
return tmpPath;
|
|
25785
26020
|
});
|
|
@@ -25924,7 +26159,7 @@ var sessionTerminated = async (ctx, cmd) => {
|
|
|
25924
26159
|
}
|
|
25925
26160
|
quiet(() => ctx.agent.kill());
|
|
25926
26161
|
try {
|
|
25927
|
-
const proc = (0,
|
|
26162
|
+
const proc = (0, import_child_process26.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
25928
26163
|
detached: true,
|
|
25929
26164
|
stdio: "ignore"
|
|
25930
26165
|
});
|
|
@@ -25943,7 +26178,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
25943
26178
|
quiet(() => ctx.agent.kill());
|
|
25944
26179
|
if (ctx.keepAliveCtx.inCodespace && ctx.keepAliveCtx.codespaceName) {
|
|
25945
26180
|
try {
|
|
25946
|
-
const stopProc = (0,
|
|
26181
|
+
const stopProc = (0, import_child_process26.spawn)(
|
|
25947
26182
|
"bash",
|
|
25948
26183
|
["-lc", `sleep 1; gh codespace stop -c ${JSON.stringify(ctx.keepAliveCtx.codespaceName)} >/dev/null 2>&1 || true`],
|
|
25949
26184
|
{ detached: true, stdio: "ignore" }
|
|
@@ -25953,7 +26188,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
25953
26188
|
}
|
|
25954
26189
|
}
|
|
25955
26190
|
try {
|
|
25956
|
-
const proc = (0,
|
|
26191
|
+
const proc = (0, import_child_process26.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
25957
26192
|
detached: true,
|
|
25958
26193
|
stdio: "ignore"
|
|
25959
26194
|
});
|
|
@@ -25997,10 +26232,10 @@ var listFiles = async (ctx, cmd, parsed) => {
|
|
|
25997
26232
|
await ctx.relay.sendResult(cmd.id, "completed", result);
|
|
25998
26233
|
};
|
|
25999
26234
|
var envReadH = async (ctx, cmd) => {
|
|
26000
|
-
const envPath =
|
|
26235
|
+
const envPath = path68.join(process.cwd(), ".env");
|
|
26001
26236
|
await restoreProjectEnvIfMissing(process.cwd(), ctx);
|
|
26002
26237
|
try {
|
|
26003
|
-
const raw = await
|
|
26238
|
+
const raw = await fs63.promises.readFile(envPath, "utf8");
|
|
26004
26239
|
await ctx.relay.sendResult(cmd.id, "completed", {
|
|
26005
26240
|
exists: true,
|
|
26006
26241
|
vars: parseDotenv(raw)
|
|
@@ -26031,15 +26266,15 @@ var envWriteH = async (ctx, cmd, parsed) => {
|
|
|
26031
26266
|
}
|
|
26032
26267
|
seen.add(v.key);
|
|
26033
26268
|
}
|
|
26034
|
-
const envPath =
|
|
26035
|
-
const tmpPath =
|
|
26269
|
+
const envPath = path68.join(process.cwd(), ".env");
|
|
26270
|
+
const tmpPath = path68.join(process.cwd(), ".env.codeam.tmp");
|
|
26036
26271
|
try {
|
|
26037
|
-
await
|
|
26038
|
-
await
|
|
26272
|
+
await fs63.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
|
|
26273
|
+
await fs63.promises.rename(tmpPath, envPath);
|
|
26039
26274
|
await ctx.relay.sendResult(cmd.id, "completed", { ok: true, count: vars.length });
|
|
26040
26275
|
void syncProjectEnvUp(process.cwd(), ctx);
|
|
26041
26276
|
} catch (err) {
|
|
26042
|
-
await
|
|
26277
|
+
await fs63.promises.rm(tmpPath, { force: true }).catch(() => void 0);
|
|
26043
26278
|
await ctx.relay.sendResult(cmd.id, "failed", { error: err.message });
|
|
26044
26279
|
}
|
|
26045
26280
|
};
|
|
@@ -26088,7 +26323,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
|
|
|
26088
26323
|
let configuredAgent = rawAgentId;
|
|
26089
26324
|
if (!configuredAgent) {
|
|
26090
26325
|
try {
|
|
26091
|
-
const raw = JSON.parse(
|
|
26326
|
+
const raw = JSON.parse(fs63.readFileSync(headroomConfigPath(), "utf8"));
|
|
26092
26327
|
configuredAgent = raw.agent ?? "";
|
|
26093
26328
|
} catch {
|
|
26094
26329
|
}
|
|
@@ -26122,7 +26357,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
|
|
|
26122
26357
|
persist: persistHeadroomConfig,
|
|
26123
26358
|
readEnabled: () => {
|
|
26124
26359
|
try {
|
|
26125
|
-
const raw = JSON.parse(
|
|
26360
|
+
const raw = JSON.parse(fs63.readFileSync(headroomConfigPath(), "utf8"));
|
|
26126
26361
|
return raw.enabled === true;
|
|
26127
26362
|
} catch {
|
|
26128
26363
|
return false;
|
|
@@ -26444,7 +26679,7 @@ var headroomBudgetH = async (ctx, cmd) => {
|
|
|
26444
26679
|
}
|
|
26445
26680
|
let headroomActive = false;
|
|
26446
26681
|
try {
|
|
26447
|
-
const raw = JSON.parse(
|
|
26682
|
+
const raw = JSON.parse(fs63.readFileSync(headroomConfigPath(), "utf8"));
|
|
26448
26683
|
headroomActive = raw.enabled === true;
|
|
26449
26684
|
} catch {
|
|
26450
26685
|
}
|
|
@@ -26454,7 +26689,7 @@ var headroomBudgetH = async (ctx, cmd) => {
|
|
|
26454
26689
|
}
|
|
26455
26690
|
let existingConfig = { enabled: true };
|
|
26456
26691
|
try {
|
|
26457
|
-
existingConfig = JSON.parse(
|
|
26692
|
+
existingConfig = JSON.parse(fs63.readFileSync(headroomConfigPath(), "utf8"));
|
|
26458
26693
|
} catch {
|
|
26459
26694
|
}
|
|
26460
26695
|
if (payload.budgetEnabled && payload.budgetUsd != null) {
|
|
@@ -26558,7 +26793,7 @@ var defaultCliUpdateDeps = {
|
|
|
26558
26793
|
// Only a truly local `codeam start` (neither marker) re-execs in place below.
|
|
26559
26794
|
isSupervised: () => process.env["CODEAM_AUTO_APPROVE"] === "1" || process.env["CODESPACES"] === "true",
|
|
26560
26795
|
relaunch: (args2) => {
|
|
26561
|
-
const child = (0,
|
|
26796
|
+
const child = (0, import_child_process26.spawnSync)("codeam", args2, { stdio: "inherit", env: process.env });
|
|
26562
26797
|
process.exit(child.status ?? 0);
|
|
26563
26798
|
}
|
|
26564
26799
|
};
|
|
@@ -26567,9 +26802,9 @@ var CLI_UPDATE_MAX_ATTEMPTS = 3;
|
|
|
26567
26802
|
function buildNpmInstallInvocation(opts) {
|
|
26568
26803
|
const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
|
|
26569
26804
|
const execPath = opts?.execPath ?? process.execPath;
|
|
26570
|
-
const exists2 = opts?.existsSync ??
|
|
26805
|
+
const exists2 = opts?.existsSync ?? fs63.existsSync;
|
|
26571
26806
|
const platform3 = opts?.platform ?? process.platform;
|
|
26572
|
-
const p2 = platform3 === "win32" ?
|
|
26807
|
+
const p2 = platform3 === "win32" ? path68.win32 : path68.posix;
|
|
26573
26808
|
const normalized = entryScript.split(/[\\/]/).join("/");
|
|
26574
26809
|
const marker = "/lib/node_modules/codeam-cli/";
|
|
26575
26810
|
const markerIdx = normalized.indexOf(marker);
|
|
@@ -26591,7 +26826,7 @@ function isPermissionError(stderr) {
|
|
|
26591
26826
|
function resolveGlobalNodeModulesDir(opts) {
|
|
26592
26827
|
const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
|
|
26593
26828
|
const platform3 = opts?.platform ?? process.platform;
|
|
26594
|
-
const p2 = platform3 === "win32" ?
|
|
26829
|
+
const p2 = platform3 === "win32" ? path68.win32 : path68.posix;
|
|
26595
26830
|
const marker = "/lib/node_modules/codeam-cli/";
|
|
26596
26831
|
const markerIdx = entryScript.split(/[\\/]/).join("/").indexOf(marker);
|
|
26597
26832
|
if (markerIdx <= 0) return null;
|
|
@@ -26601,9 +26836,9 @@ function resolveGlobalNodeModulesDir(opts) {
|
|
|
26601
26836
|
var STALE_STAGING_AGE_MS = CLI_UPDATE_INSTALL_TIMEOUT_MS;
|
|
26602
26837
|
function sweepStaleCliStagingDirs(nodeModulesDir, now = Date.now(), deps) {
|
|
26603
26838
|
if (!nodeModulesDir) return 0;
|
|
26604
|
-
const readdirSync15 = deps?.readdirSync ??
|
|
26605
|
-
const statSync17 = deps?.statSync ??
|
|
26606
|
-
const rmSync9 = deps?.rmSync ??
|
|
26839
|
+
const readdirSync15 = deps?.readdirSync ?? fs63.readdirSync;
|
|
26840
|
+
const statSync17 = deps?.statSync ?? fs63.statSync;
|
|
26841
|
+
const rmSync9 = deps?.rmSync ?? fs63.rmSync;
|
|
26607
26842
|
let removed = 0;
|
|
26608
26843
|
let entries;
|
|
26609
26844
|
try {
|
|
@@ -26613,7 +26848,7 @@ function sweepStaleCliStagingDirs(nodeModulesDir, now = Date.now(), deps) {
|
|
|
26613
26848
|
}
|
|
26614
26849
|
for (const name of entries) {
|
|
26615
26850
|
if (!/^\.codeam-cli-/.test(name)) continue;
|
|
26616
|
-
const full =
|
|
26851
|
+
const full = path68.join(nodeModulesDir, name);
|
|
26617
26852
|
try {
|
|
26618
26853
|
const st3 = statSync17(full);
|
|
26619
26854
|
if (now - st3.mtimeMs < STALE_STAGING_AGE_MS) continue;
|
|
@@ -26639,7 +26874,7 @@ async function runNpmInstallLatest() {
|
|
|
26639
26874
|
const useShell = process.platform === "win32";
|
|
26640
26875
|
const command2 = useShell && invocation.command.includes(" ") ? `"${invocation.command}"` : invocation.command;
|
|
26641
26876
|
const result = await new Promise((resolve9) => {
|
|
26642
|
-
(0,
|
|
26877
|
+
(0, import_child_process26.execFile)(
|
|
26643
26878
|
command2,
|
|
26644
26879
|
invocation.args,
|
|
26645
26880
|
{ timeout: CLI_UPDATE_INSTALL_TIMEOUT_MS, shell: useShell },
|
|
@@ -27253,13 +27488,13 @@ async function dispatchCommand(ctx, cmd) {
|
|
|
27253
27488
|
}
|
|
27254
27489
|
|
|
27255
27490
|
// src/commands/start/keep-alive.ts
|
|
27256
|
-
var
|
|
27491
|
+
var import_child_process27 = require("child_process");
|
|
27257
27492
|
function buildKeepAlive(ctx) {
|
|
27258
27493
|
let timer = null;
|
|
27259
27494
|
async function setIdleTimeout(minutes) {
|
|
27260
27495
|
if (!ctx.inCodespace || !ctx.codespaceName) return;
|
|
27261
27496
|
await new Promise((resolve9) => {
|
|
27262
|
-
const proc = (0,
|
|
27497
|
+
const proc = (0, import_child_process27.spawn)(
|
|
27263
27498
|
"gh",
|
|
27264
27499
|
[
|
|
27265
27500
|
"api",
|
|
@@ -27493,7 +27728,7 @@ function resolveTokenValue(args2) {
|
|
|
27493
27728
|
if (fileFlag) {
|
|
27494
27729
|
const path91 = fileFlag.slice("--token-file=".length);
|
|
27495
27730
|
try {
|
|
27496
|
-
const content =
|
|
27731
|
+
const content = fs64.readFileSync(path91, "utf8").trim();
|
|
27497
27732
|
if (content.length === 0) fail(`--token-file ${path91} is empty`);
|
|
27498
27733
|
rmIfExistsQuiet(path91);
|
|
27499
27734
|
return content;
|
|
@@ -27524,7 +27759,7 @@ async function claimOnce(token, pluginId, pluginSecretHash) {
|
|
|
27524
27759
|
pluginId,
|
|
27525
27760
|
ideName: "codeam-cli (codespace)",
|
|
27526
27761
|
ideVersion: process.env.npm_package_version ?? "unknown",
|
|
27527
|
-
hostname:
|
|
27762
|
+
hostname: os54.hostname(),
|
|
27528
27763
|
codespaceName: process.env.CODESPACE_NAME ?? "",
|
|
27529
27764
|
// Current git branch of the codespace's working directory, so the
|
|
27530
27765
|
// backend can populate `PairedSession.branch` for the codespace pair.
|
|
@@ -27585,7 +27820,7 @@ async function claim(token, pluginId, pluginSecretHash) {
|
|
|
27585
27820
|
}
|
|
27586
27821
|
}
|
|
27587
27822
|
function pairAutoLockPath() {
|
|
27588
|
-
return
|
|
27823
|
+
return path69.join(os54.homedir(), ".codeam", "pair-auto.lock");
|
|
27589
27824
|
}
|
|
27590
27825
|
function isLivePairAuto(pid) {
|
|
27591
27826
|
if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
|
|
@@ -27595,7 +27830,7 @@ function isLivePairAuto(pid) {
|
|
|
27595
27830
|
if (e.code !== "EPERM") return false;
|
|
27596
27831
|
}
|
|
27597
27832
|
try {
|
|
27598
|
-
return
|
|
27833
|
+
return fs64.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
|
|
27599
27834
|
} catch {
|
|
27600
27835
|
return true;
|
|
27601
27836
|
}
|
|
@@ -27605,24 +27840,24 @@ function isLiveCodeam(pid) {
|
|
|
27605
27840
|
}
|
|
27606
27841
|
function daemonLockPath(sessionId) {
|
|
27607
27842
|
const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
27608
|
-
return
|
|
27843
|
+
return path69.join(os54.homedir(), ".codeam", `daemon-${safe}.lock`);
|
|
27609
27844
|
}
|
|
27610
27845
|
function acquireDaemonLock(sessionId) {
|
|
27611
27846
|
const lockPath = daemonLockPath(sessionId);
|
|
27612
27847
|
try {
|
|
27613
|
-
|
|
27848
|
+
fs64.mkdirSync(path69.dirname(lockPath), { recursive: true });
|
|
27614
27849
|
try {
|
|
27615
|
-
|
|
27850
|
+
fs64.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
27616
27851
|
} catch (e) {
|
|
27617
27852
|
if (e.code !== "EEXIST") throw e;
|
|
27618
|
-
const holder = Number(
|
|
27853
|
+
const holder = Number(fs64.readFileSync(lockPath, "utf8").trim());
|
|
27619
27854
|
if (holder && holder !== process.pid && isLiveCodeam(holder)) return false;
|
|
27620
|
-
|
|
27855
|
+
fs64.writeFileSync(lockPath, String(process.pid));
|
|
27621
27856
|
}
|
|
27622
27857
|
const release3 = () => {
|
|
27623
27858
|
try {
|
|
27624
|
-
if (
|
|
27625
|
-
|
|
27859
|
+
if (fs64.existsSync(lockPath) && Number(fs64.readFileSync(lockPath, "utf8").trim()) === process.pid) {
|
|
27860
|
+
fs64.unlinkSync(lockPath);
|
|
27626
27861
|
}
|
|
27627
27862
|
} catch {
|
|
27628
27863
|
}
|
|
@@ -27644,19 +27879,19 @@ function acquireDaemonLock(sessionId) {
|
|
|
27644
27879
|
function acquireSingletonLock() {
|
|
27645
27880
|
const lockPath = pairAutoLockPath();
|
|
27646
27881
|
try {
|
|
27647
|
-
|
|
27882
|
+
fs64.mkdirSync(path69.dirname(lockPath), { recursive: true });
|
|
27648
27883
|
try {
|
|
27649
|
-
|
|
27884
|
+
fs64.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
27650
27885
|
} catch (e) {
|
|
27651
27886
|
if (e.code !== "EEXIST") throw e;
|
|
27652
|
-
const holder = Number(
|
|
27887
|
+
const holder = Number(fs64.readFileSync(lockPath, "utf8").trim());
|
|
27653
27888
|
if (isLivePairAuto(holder)) return false;
|
|
27654
|
-
|
|
27889
|
+
fs64.writeFileSync(lockPath, String(process.pid));
|
|
27655
27890
|
}
|
|
27656
27891
|
process.once("exit", () => {
|
|
27657
27892
|
try {
|
|
27658
|
-
if (
|
|
27659
|
-
|
|
27893
|
+
if (fs64.existsSync(lockPath) && Number(fs64.readFileSync(lockPath, "utf8").trim()) === process.pid) {
|
|
27894
|
+
fs64.unlinkSync(lockPath);
|
|
27660
27895
|
}
|
|
27661
27896
|
} catch {
|
|
27662
27897
|
}
|
|
@@ -28110,178 +28345,6 @@ var AgentService = class _AgentService {
|
|
|
28110
28345
|
// src/agents/acp/adapters.ts
|
|
28111
28346
|
var path70 = __toESM(require("path"));
|
|
28112
28347
|
|
|
28113
|
-
// src/agents/acp/agent-binary.ts
|
|
28114
|
-
var import_fs6 = __toESM(require("fs"));
|
|
28115
|
-
var import_os11 = __toESM(require("os"));
|
|
28116
|
-
var import_path8 = __toESM(require("path"));
|
|
28117
|
-
var import_child_process27 = require("child_process");
|
|
28118
|
-
function currentPlatformKey() {
|
|
28119
|
-
return `${process.platform}-${process.arch}`;
|
|
28120
|
-
}
|
|
28121
|
-
var SDK_PKG = "@anthropic-ai/claude-agent-sdk";
|
|
28122
|
-
function resolveSdkDirViaRequire(req = require) {
|
|
28123
|
-
try {
|
|
28124
|
-
return import_path8.default.dirname(req.resolve(`${SDK_PKG}/package.json`));
|
|
28125
|
-
} catch {
|
|
28126
|
-
}
|
|
28127
|
-
try {
|
|
28128
|
-
let dir = import_path8.default.dirname(req.resolve(SDK_PKG));
|
|
28129
|
-
for (let i = 0; i < 5; i++) {
|
|
28130
|
-
if (import_path8.default.basename(dir) === "claude-agent-sdk") return dir;
|
|
28131
|
-
const parent = import_path8.default.dirname(dir);
|
|
28132
|
-
if (parent === dir) break;
|
|
28133
|
-
dir = parent;
|
|
28134
|
-
}
|
|
28135
|
-
return null;
|
|
28136
|
-
} catch {
|
|
28137
|
-
return null;
|
|
28138
|
-
}
|
|
28139
|
-
}
|
|
28140
|
-
function defaultSdkDir() {
|
|
28141
|
-
return resolveSdkDirViaRequire();
|
|
28142
|
-
}
|
|
28143
|
-
function resolveClaudeNativeBinary(deps = {}) {
|
|
28144
|
-
const existsSync29 = deps.existsSync ?? import_fs6.default.existsSync;
|
|
28145
|
-
const platformKey = deps.platformKey ?? currentPlatformKey();
|
|
28146
|
-
const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
|
|
28147
|
-
if (!sdkDir) return null;
|
|
28148
|
-
const scopeDir = import_path8.default.dirname(sdkDir);
|
|
28149
|
-
const binName = platformKey.startsWith("win32-") ? "claude.exe" : "claude";
|
|
28150
|
-
const candidate = import_path8.default.join(scopeDir, `claude-agent-sdk-${platformKey}`, binName);
|
|
28151
|
-
return existsSync29(candidate) ? candidate : null;
|
|
28152
|
-
}
|
|
28153
|
-
var realSleep = (ms) => new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
28154
|
-
async function waitForClaudeNativeBinary(opts = {}) {
|
|
28155
|
-
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
28156
|
-
const pollMs = opts.pollMs ?? 500;
|
|
28157
|
-
const now = opts.now ?? Date.now;
|
|
28158
|
-
const sleep5 = opts.sleep ?? realSleep;
|
|
28159
|
-
const deps = {
|
|
28160
|
-
sdkDir: opts.sdkDir,
|
|
28161
|
-
platformKey: opts.platformKey,
|
|
28162
|
-
existsSync: opts.existsSync
|
|
28163
|
-
};
|
|
28164
|
-
const deadline = now() + timeoutMs;
|
|
28165
|
-
let found = resolveClaudeNativeBinary(deps);
|
|
28166
|
-
if (found) return found;
|
|
28167
|
-
while (now() < deadline) {
|
|
28168
|
-
await sleep5(pollMs);
|
|
28169
|
-
found = resolveClaudeNativeBinary(deps);
|
|
28170
|
-
if (found) return found;
|
|
28171
|
-
}
|
|
28172
|
-
return resolveClaudeNativeBinary(deps);
|
|
28173
|
-
}
|
|
28174
|
-
function isCommandOnPath(cmd, probe = defaultWhich) {
|
|
28175
|
-
return probe(cmd);
|
|
28176
|
-
}
|
|
28177
|
-
function defaultWhich(cmd) {
|
|
28178
|
-
const finder = process.platform === "win32" ? "where" : "which";
|
|
28179
|
-
try {
|
|
28180
|
-
const res = (0, import_child_process27.spawnSync)(finder, [cmd], { stdio: "ignore" });
|
|
28181
|
-
return res.status === 0;
|
|
28182
|
-
} catch {
|
|
28183
|
-
return false;
|
|
28184
|
-
}
|
|
28185
|
-
}
|
|
28186
|
-
async function waitForCommandOnPath(cmd, opts = {}) {
|
|
28187
|
-
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
28188
|
-
const pollMs = opts.pollMs ?? 500;
|
|
28189
|
-
const now = opts.now ?? Date.now;
|
|
28190
|
-
const sleep5 = opts.sleep ?? realSleep;
|
|
28191
|
-
const probe = opts.probe;
|
|
28192
|
-
const check = () => isCommandOnPath(cmd, probe);
|
|
28193
|
-
const deadline = now() + timeoutMs;
|
|
28194
|
-
if (check()) return true;
|
|
28195
|
-
while (now() < deadline) {
|
|
28196
|
-
await sleep5(pollMs);
|
|
28197
|
-
if (check()) return true;
|
|
28198
|
-
}
|
|
28199
|
-
return check();
|
|
28200
|
-
}
|
|
28201
|
-
function resolveCursorAgentBinary(deps = {}) {
|
|
28202
|
-
const existsSync29 = deps.existsSync ?? import_fs6.default.existsSync;
|
|
28203
|
-
const platform3 = deps.platform ?? process.platform;
|
|
28204
|
-
const env = deps.env ?? process.env;
|
|
28205
|
-
if (platform3 === "win32") {
|
|
28206
|
-
const localAppData = env.LOCALAPPDATA;
|
|
28207
|
-
if (!localAppData) return null;
|
|
28208
|
-
const exe = import_path8.default.win32.join(localAppData, "cursor-agent", "cursor-agent.exe");
|
|
28209
|
-
return existsSync29(exe) ? exe : null;
|
|
28210
|
-
}
|
|
28211
|
-
const home = deps.homedir ?? import_os11.default.homedir();
|
|
28212
|
-
const unix = import_path8.default.posix.join(home, ".local", "bin", "cursor-agent");
|
|
28213
|
-
return existsSync29(unix) ? unix : null;
|
|
28214
|
-
}
|
|
28215
|
-
async function waitForCursorAgent(opts = {}) {
|
|
28216
|
-
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
28217
|
-
const pollMs = opts.pollMs ?? 500;
|
|
28218
|
-
const now = opts.now ?? Date.now;
|
|
28219
|
-
const sleep5 = opts.sleep ?? realSleep;
|
|
28220
|
-
const check = () => resolveCursorAgentBinary(opts) !== null || isCommandOnPath("cursor-agent", opts.probe);
|
|
28221
|
-
const deadline = now() + timeoutMs;
|
|
28222
|
-
if (check()) return true;
|
|
28223
|
-
while (now() < deadline) {
|
|
28224
|
-
await sleep5(pollMs);
|
|
28225
|
-
if (check()) return true;
|
|
28226
|
-
}
|
|
28227
|
-
return check();
|
|
28228
|
-
}
|
|
28229
|
-
var ADAPTER_MODULE_LOAD_ERROR_RE = /ERR_MODULE_NOT_FOUND|Cannot find module|ERR_REQUIRE_ESM|ERR_UNKNOWN_BUILTIN_MODULE|ERR_UNSUPPORTED_DIR_IMPORT|ERR_PACKAGE_PATH_NOT_EXPORTED|ERR_INVALID_PACKAGE_CONFIG|ERR_INVALID_PACKAGE_TARGET|ERR_INVALID_MODULE_SPECIFIER|node:internal\/modules\/|Directory import|SyntaxError|Unexpected (token|end|identifier)|missing \) after argument list/i;
|
|
28230
|
-
var PERMANENT_ADAPTER_STARTUP_RE = /IneligibleTierError|UNSUPPORTED_CLIENT|no longer supported for Gemini Code Assist|not eligible for Gemini Code Assist|Error authenticating|ProjectIdRequiredError/i;
|
|
28231
|
-
function probeAdapterModuleGraph(command2, args2, opts = {}) {
|
|
28232
|
-
const livenessMs = opts.livenessMs ?? 400;
|
|
28233
|
-
const spawnFn = opts.spawnFn ?? import_child_process27.spawn;
|
|
28234
|
-
return new Promise((resolve9) => {
|
|
28235
|
-
let settled = false;
|
|
28236
|
-
let stderr = "";
|
|
28237
|
-
let timer;
|
|
28238
|
-
let child;
|
|
28239
|
-
const finish = (r) => {
|
|
28240
|
-
if (settled) return;
|
|
28241
|
-
settled = true;
|
|
28242
|
-
if (timer) clearTimeout(timer);
|
|
28243
|
-
try {
|
|
28244
|
-
child?.kill("SIGKILL");
|
|
28245
|
-
} catch {
|
|
28246
|
-
}
|
|
28247
|
-
resolve9(r);
|
|
28248
|
-
};
|
|
28249
|
-
try {
|
|
28250
|
-
child = spawnFn(command2, [...args2], { stdio: ["pipe", "ignore", "pipe"] });
|
|
28251
|
-
} catch {
|
|
28252
|
-
resolve9("ok");
|
|
28253
|
-
return;
|
|
28254
|
-
}
|
|
28255
|
-
child.stderr?.on("data", (d3) => {
|
|
28256
|
-
stderr += d3.toString();
|
|
28257
|
-
if (stderr.length > 8192) stderr = stderr.slice(-8192);
|
|
28258
|
-
});
|
|
28259
|
-
child.on("error", () => finish("ok"));
|
|
28260
|
-
child.on("exit", (code) => {
|
|
28261
|
-
if (code !== 0 && code !== null && !PERMANENT_ADAPTER_STARTUP_RE.test(stderr)) {
|
|
28262
|
-
finish("transient");
|
|
28263
|
-
} else {
|
|
28264
|
-
finish("ok");
|
|
28265
|
-
}
|
|
28266
|
-
});
|
|
28267
|
-
timer = setTimeout(() => finish("ok"), livenessMs);
|
|
28268
|
-
});
|
|
28269
|
-
}
|
|
28270
|
-
async function waitForAdapterModuleGraph(command2, args2, opts = {}) {
|
|
28271
|
-
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
28272
|
-
const pollMs = opts.pollMs ?? 500;
|
|
28273
|
-
const now = opts.now ?? Date.now;
|
|
28274
|
-
const sleep5 = opts.sleep ?? realSleep;
|
|
28275
|
-
const probeOpts = { livenessMs: opts.livenessMs, spawnFn: opts.spawnFn };
|
|
28276
|
-
const deadline = now() + timeoutMs;
|
|
28277
|
-
if (await probeAdapterModuleGraph(command2, args2, probeOpts) === "ok") return true;
|
|
28278
|
-
while (now() < deadline) {
|
|
28279
|
-
await sleep5(pollMs);
|
|
28280
|
-
if (await probeAdapterModuleGraph(command2, args2, probeOpts) === "ok") return true;
|
|
28281
|
-
}
|
|
28282
|
-
return false;
|
|
28283
|
-
}
|
|
28284
|
-
|
|
28285
28348
|
// src/agents/kimi/installer.ts
|
|
28286
28349
|
var import_node_child_process27 = require("child_process");
|
|
28287
28350
|
var import_node_os10 = require("os");
|
|
@@ -28430,7 +28493,10 @@ var REGISTRY = {
|
|
|
28430
28493
|
args: [bin],
|
|
28431
28494
|
requiresAgentBinary: "codex",
|
|
28432
28495
|
// codex ships via `npm install -g @openai/codex` → PATH binary.
|
|
28433
|
-
waitForBinary: (o) =>
|
|
28496
|
+
waitForBinary: (o) => {
|
|
28497
|
+
augmentUserLocalBinPaths();
|
|
28498
|
+
return waitForCommandOnPath("codex", o);
|
|
28499
|
+
}
|
|
28434
28500
|
};
|
|
28435
28501
|
},
|
|
28436
28502
|
// Cursor speaks ACP NATIVELY via `cursor-agent acp` ("Start the Cursor
|
|
@@ -28456,7 +28522,30 @@ var REGISTRY = {
|
|
|
28456
28522
|
command: resolveCursorAgentBinary() ?? "cursor-agent",
|
|
28457
28523
|
args: ["acp"],
|
|
28458
28524
|
requiresAgentBinary: "cursor-agent",
|
|
28459
|
-
|
|
28525
|
+
// Stale-PATH guard — same class as codex/gemini above, kept here so the
|
|
28526
|
+
// PROBE and the SPAWN agree about what "ready" means.
|
|
28527
|
+
//
|
|
28528
|
+
// On an in-session switch the adapter spec is resolved BEFORE the install
|
|
28529
|
+
// (`ensureAgentBinaryForSwitch`'s first step), so with no cursor-agent on
|
|
28530
|
+
// disk yet `resolveCursorAgentBinary()` returns null and the spec is
|
|
28531
|
+
// PERMANENTLY CACHED with the bare name `cursor-agent`. The installer then
|
|
28532
|
+
// drops the binary in ~/.local/bin, which a systemd-minimal PATH lacks,
|
|
28533
|
+
// yet `waitForCursorAgent` still reports READY (it probes the absolute
|
|
28534
|
+
// install location).
|
|
28535
|
+
//
|
|
28536
|
+
// ⚠️ Scope, honestly: this is defence in depth, NOT a live outage fix.
|
|
28537
|
+
// `AcpClient.start` already spawns with `expandPathForAgentBinaries(...)`
|
|
28538
|
+
// (client.ts), which folds the same dirs in, so the production ACP spawn
|
|
28539
|
+
// very likely resolved anyway. What was genuinely wrong is that a probe
|
|
28540
|
+
// could report ready while a *plain* spawn from the same process could not
|
|
28541
|
+
// find the binary — the real-install gate
|
|
28542
|
+
// (`__tests__/integration/agent-install.int.test.ts`) spawns without that
|
|
28543
|
+
// expansion and caught the divergence. Aligning the probe with codex/gemini
|
|
28544
|
+
// costs one idempotent call and removes the discrepancy.
|
|
28545
|
+
waitForBinary: (o) => {
|
|
28546
|
+
augmentUserLocalBinPaths();
|
|
28547
|
+
return waitForCursorAgent(o);
|
|
28548
|
+
}
|
|
28460
28549
|
}),
|
|
28461
28550
|
// Gemini speaks ACP natively via `gemini --acp` — no npm adapter
|
|
28462
28551
|
// package, just the user-installed `gemini` binary on PATH. Same
|
|
@@ -28474,7 +28563,12 @@ var REGISTRY = {
|
|
|
28474
28563
|
// codeam was launched from.
|
|
28475
28564
|
args: ["--skip-trust", "--acp"],
|
|
28476
28565
|
requiresAgentBinary: "gemini",
|
|
28477
|
-
|
|
28566
|
+
// gemini ships via `npm install -g @google/gemini-cli` → PATH binary,
|
|
28567
|
+
// same stale-PATH exposure as codex above.
|
|
28568
|
+
waitForBinary: (o) => {
|
|
28569
|
+
augmentUserLocalBinPaths();
|
|
28570
|
+
return waitForCommandOnPath("gemini", o);
|
|
28571
|
+
}
|
|
28478
28572
|
}),
|
|
28479
28573
|
// Kimi Code (Moonshot) speaks ACP natively via `kimi acp` — a stdio
|
|
28480
28574
|
// JSON-RPC server that answers `initialize` (agentInfo `Kimi Code CLI`,
|
|
@@ -28558,12 +28652,292 @@ async function resolveAcpAdapterWithRetry(agent, opts = {}) {
|
|
|
28558
28652
|
var import_node_crypto11 = require("crypto");
|
|
28559
28653
|
|
|
28560
28654
|
// src/services/history.service.ts
|
|
28561
|
-
var
|
|
28562
|
-
var
|
|
28563
|
-
var
|
|
28655
|
+
var fs66 = __toESM(require("fs"));
|
|
28656
|
+
var path72 = __toESM(require("path"));
|
|
28657
|
+
var os56 = __toESM(require("os"));
|
|
28564
28658
|
var https7 = __toESM(require("https"));
|
|
28565
28659
|
var http6 = __toESM(require("http"));
|
|
28566
28660
|
var import_zod2 = require("zod");
|
|
28661
|
+
|
|
28662
|
+
// src/agents/acp/squad-roster.ts
|
|
28663
|
+
var fs65 = __toESM(require("fs"));
|
|
28664
|
+
var os55 = __toESM(require("os"));
|
|
28665
|
+
var path71 = __toESM(require("path"));
|
|
28666
|
+
var PROMPT_MAX = 500;
|
|
28667
|
+
var REPLY_SUMMARY_MAX = 1e3;
|
|
28668
|
+
var PREAMBLE_MAX = 2e3;
|
|
28669
|
+
var BRIEFING_DEFAULT_MAX = 8e3;
|
|
28670
|
+
var GENERIC_SPECIALTY = "general implementation tasks";
|
|
28671
|
+
function clip(s, max) {
|
|
28672
|
+
return s.length > max ? s.slice(0, max) : s;
|
|
28673
|
+
}
|
|
28674
|
+
function defaultMember() {
|
|
28675
|
+
return {
|
|
28676
|
+
acpSessionId: null,
|
|
28677
|
+
provisioned: false,
|
|
28678
|
+
binaryVerified: false,
|
|
28679
|
+
lastTurnIndex: 0,
|
|
28680
|
+
contextTextFallback: false
|
|
28681
|
+
};
|
|
28682
|
+
}
|
|
28683
|
+
function journalPathFor(homeDir2, sessionId) {
|
|
28684
|
+
return path71.join(homeDir2, ".codeam", `squad-journal-${sessionId}.json`);
|
|
28685
|
+
}
|
|
28686
|
+
function loadJournal(journalPath) {
|
|
28687
|
+
try {
|
|
28688
|
+
const raw = JSON.parse(fs65.readFileSync(journalPath, "utf-8"));
|
|
28689
|
+
return Array.isArray(raw.turns) ? raw.turns : [];
|
|
28690
|
+
} catch {
|
|
28691
|
+
return [];
|
|
28692
|
+
}
|
|
28693
|
+
}
|
|
28694
|
+
var SquadState = class {
|
|
28695
|
+
/** Set by the caller after fetchSquadRoster; null until then. */
|
|
28696
|
+
roster = null;
|
|
28697
|
+
/**
|
|
28698
|
+
* Autonomous chained handoffs (P2-2, PRO). Seeded from the persisted
|
|
28699
|
+
* `SavedSession.squadAuto` at session start and rewritten by
|
|
28700
|
+
* `squad_configure`. Read-only to callers — mutate via {@link setAuto}, which
|
|
28701
|
+
* clamps the budget and re-arms the chain.
|
|
28702
|
+
*/
|
|
28703
|
+
autoConfig = { enabled: false, hopBudget: SQUAD_HOP_BUDGET_DEFAULT };
|
|
28704
|
+
/**
|
|
28705
|
+
* Hops left in the CURRENT chain. Reset to the budget on every USER-initiated
|
|
28706
|
+
* prompt (so a user turn always interrupts and re-arms) and decremented by
|
|
28707
|
+
* each self-accepted handoff.
|
|
28708
|
+
*/
|
|
28709
|
+
hopsLeft = 0;
|
|
28710
|
+
/** Lifetime handoff counters for `squad_stats` (in-memory, this process). */
|
|
28711
|
+
handoffCounters = { proposed: 0, accepted: 0, auto: 0 };
|
|
28712
|
+
journalPath;
|
|
28713
|
+
turns;
|
|
28714
|
+
members = /* @__PURE__ */ new Map();
|
|
28715
|
+
constructor(opts) {
|
|
28716
|
+
this.journalPath = journalPathFor(opts.homeDir ?? os55.homedir(), opts.sessionId);
|
|
28717
|
+
this.turns = loadJournal(this.journalPath);
|
|
28718
|
+
if (opts.auto) this.setAuto(opts.auto);
|
|
28719
|
+
}
|
|
28720
|
+
get auto() {
|
|
28721
|
+
return this.autoConfig;
|
|
28722
|
+
}
|
|
28723
|
+
/** Apply a new mode (clamping the budget) and re-arm the chain. */
|
|
28724
|
+
setAuto(value) {
|
|
28725
|
+
this.autoConfig = {
|
|
28726
|
+
enabled: value.enabled === true,
|
|
28727
|
+
hopBudget: clampHopBudget(value.hopBudget)
|
|
28728
|
+
};
|
|
28729
|
+
this.resetHops();
|
|
28730
|
+
return this.autoConfig;
|
|
28731
|
+
}
|
|
28732
|
+
hopsRemaining() {
|
|
28733
|
+
return this.hopsLeft;
|
|
28734
|
+
}
|
|
28735
|
+
/** Re-arm the chain — called at the start of every USER-initiated turn. */
|
|
28736
|
+
resetHops() {
|
|
28737
|
+
this.hopsLeft = this.autoConfig.enabled ? this.autoConfig.hopBudget : 0;
|
|
28738
|
+
}
|
|
28739
|
+
/** Spend one hop on a self-accepted handoff. */
|
|
28740
|
+
consumeHop() {
|
|
28741
|
+
if (this.hopsLeft > 0) this.hopsLeft -= 1;
|
|
28742
|
+
}
|
|
28743
|
+
countProposal(opts) {
|
|
28744
|
+
this.handoffCounters.proposed += 1;
|
|
28745
|
+
if (opts.auto) this.handoffCounters.auto += 1;
|
|
28746
|
+
}
|
|
28747
|
+
countAccepted() {
|
|
28748
|
+
this.handoffCounters.accepted += 1;
|
|
28749
|
+
}
|
|
28750
|
+
/**
|
|
28751
|
+
* Per-member activity for the `squad_stats` relay command, derived from the
|
|
28752
|
+
* journal (the same shared history the delta briefing reads) plus the
|
|
28753
|
+
* in-memory handoff counters. `filesTouched` counts DISTINCT paths — a member
|
|
28754
|
+
* that edited the same file across three turns touched ONE file.
|
|
28755
|
+
*/
|
|
28756
|
+
stats() {
|
|
28757
|
+
const byAgent = /* @__PURE__ */ new Map();
|
|
28758
|
+
for (const t2 of this.turns) {
|
|
28759
|
+
let row = byAgent.get(t2.agentId);
|
|
28760
|
+
if (!row) {
|
|
28761
|
+
row = { turns: 0, files: /* @__PURE__ */ new Set() };
|
|
28762
|
+
byAgent.set(t2.agentId, row);
|
|
28763
|
+
}
|
|
28764
|
+
row.turns += 1;
|
|
28765
|
+
for (const f of t2.filesTouched) row.files.add(f);
|
|
28766
|
+
}
|
|
28767
|
+
const members = [...byAgent.entries()].map(([agentId, row]) => ({
|
|
28768
|
+
agentId,
|
|
28769
|
+
turns: row.turns,
|
|
28770
|
+
filesTouched: row.files.size
|
|
28771
|
+
}));
|
|
28772
|
+
return { members, handoffs: { ...this.handoffCounters }, sinceTurn: 1 };
|
|
28773
|
+
}
|
|
28774
|
+
/** Returns (creating on first access) the mutable per-agent state. */
|
|
28775
|
+
member(agentId) {
|
|
28776
|
+
let m = this.members.get(agentId);
|
|
28777
|
+
if (!m) {
|
|
28778
|
+
m = defaultMember();
|
|
28779
|
+
this.members.set(agentId, m);
|
|
28780
|
+
}
|
|
28781
|
+
return m;
|
|
28782
|
+
}
|
|
28783
|
+
/** Appends a journal entry and persists (fire-and-forget durability). */
|
|
28784
|
+
recordTurn(entry) {
|
|
28785
|
+
const turn = {
|
|
28786
|
+
turn: this.turns.length + 1,
|
|
28787
|
+
agentId: entry.agentId,
|
|
28788
|
+
prompt: clip(entry.prompt, PROMPT_MAX),
|
|
28789
|
+
replySummary: clip(entry.replySummary, REPLY_SUMMARY_MAX),
|
|
28790
|
+
filesTouched: entry.filesTouched
|
|
28791
|
+
};
|
|
28792
|
+
this.turns.push(turn);
|
|
28793
|
+
this.persist();
|
|
28794
|
+
}
|
|
28795
|
+
turnCount() {
|
|
28796
|
+
return this.turns.length;
|
|
28797
|
+
}
|
|
28798
|
+
entriesSince(turnIndex) {
|
|
28799
|
+
return this.turns.filter((t2) => t2.turn > turnIndex);
|
|
28800
|
+
}
|
|
28801
|
+
persist() {
|
|
28802
|
+
try {
|
|
28803
|
+
fs65.mkdirSync(path71.dirname(this.journalPath), { recursive: true, mode: 448 });
|
|
28804
|
+
fs65.writeFileSync(this.journalPath, JSON.stringify({ turns: this.turns }), { mode: 384 });
|
|
28805
|
+
} catch {
|
|
28806
|
+
}
|
|
28807
|
+
}
|
|
28808
|
+
};
|
|
28809
|
+
function specialtyFor(agentId) {
|
|
28810
|
+
return SQUAD_SPECIALTIES[agentId] ?? GENERIC_SPECIALTY;
|
|
28811
|
+
}
|
|
28812
|
+
var TEAM_PREAMBLE_MARKER = "[Team context]";
|
|
28813
|
+
var TEAM_PREAMBLE_LINES = [
|
|
28814
|
+
"[Team context] You are the active agent in a CodeAgent Mobile session where the user",
|
|
28815
|
+
"has a squad of agents and can pass work between them. Your available teammates:",
|
|
28816
|
+
"If a task clearly fits a teammate better than you, you MAY propose a handoff by ending",
|
|
28817
|
+
`your reply with a fenced code block tagged ${HANDOFF_FENCE_TAG} containing ONE JSON object:`,
|
|
28818
|
+
'{"to":"<teammate id>","reason":"<one sentence>","prompt":"<the prompt they should run>"}',
|
|
28819
|
+
"Propose at most one handoff per reply, only when genuinely better, and never announce",
|
|
28820
|
+
"the block in prose \u2014 the app renders it as a card the user can accept."
|
|
28821
|
+
];
|
|
28822
|
+
var TEAM_PREAMBLE_BULLET_RE = /^- .+ — best at: /;
|
|
28823
|
+
var BRIEFING_MARKER = "[Team update]";
|
|
28824
|
+
var BRIEFING_HEADER = "[Team update] While you were away, other agents worked on this session:";
|
|
28825
|
+
var BRIEFING_FOOTER = "Continue from the CURRENT state of the working tree.";
|
|
28826
|
+
function buildTeamPreamble(roster, currentAgent, opts) {
|
|
28827
|
+
const others = roster.agents.filter((a) => a.agentId !== currentAgent);
|
|
28828
|
+
if (others.length === 0) return null;
|
|
28829
|
+
const lines = [
|
|
28830
|
+
TEAM_PREAMBLE_LINES[0],
|
|
28831
|
+
TEAM_PREAMBLE_LINES[1],
|
|
28832
|
+
...others.map((a) => `- ${a.displayName} \u2014 best at: ${specialtyFor(a.agentId)}`)
|
|
28833
|
+
];
|
|
28834
|
+
if (opts.handoffInstructions) {
|
|
28835
|
+
lines.push(...TEAM_PREAMBLE_LINES.slice(2));
|
|
28836
|
+
}
|
|
28837
|
+
return clip(lines.join("\n"), PREAMBLE_MAX);
|
|
28838
|
+
}
|
|
28839
|
+
function renderJournalEntry(e) {
|
|
28840
|
+
const filesClause = e.filesTouched.length > 0 ? ` (files: ${e.filesTouched.join(", ")})` : "";
|
|
28841
|
+
return `- turn ${e.turn} (${e.agentId}): ${e.prompt} \u2192 ${e.replySummary}${filesClause}`;
|
|
28842
|
+
}
|
|
28843
|
+
function buildDeltaBriefing(entries, maxChars = BRIEFING_DEFAULT_MAX) {
|
|
28844
|
+
if (entries.length === 0) return null;
|
|
28845
|
+
const header = BRIEFING_HEADER;
|
|
28846
|
+
const footer = BRIEFING_FOOTER;
|
|
28847
|
+
const envelope = header.length + 1 + footer.length + 1;
|
|
28848
|
+
const sorted = [...entries].sort((a, b) => a.turn - b.turn);
|
|
28849
|
+
const lines = [];
|
|
28850
|
+
let bodyLen = 0;
|
|
28851
|
+
for (let i = sorted.length - 1; i >= 0; i--) {
|
|
28852
|
+
const line = renderJournalEntry(sorted[i]);
|
|
28853
|
+
const addedLen = line.length + (lines.length > 0 ? 1 : 0);
|
|
28854
|
+
if (lines.length > 0 && envelope + bodyLen + addedLen > maxChars) break;
|
|
28855
|
+
lines.unshift(line);
|
|
28856
|
+
bodyLen += addedLen;
|
|
28857
|
+
}
|
|
28858
|
+
return [header, lines.join("\n"), footer].join("\n");
|
|
28859
|
+
}
|
|
28860
|
+
|
|
28861
|
+
// src/agents/acp/squad-context.ts
|
|
28862
|
+
var SQUAD_CONTEXT_URI = "codeam://squad-context";
|
|
28863
|
+
var HANDOFF_MARKER = "[Session handoff]";
|
|
28864
|
+
var HANDOFF_TERMINATOR = "--- End of handoff context ---";
|
|
28865
|
+
function buildSquadContextBlock(text) {
|
|
28866
|
+
return {
|
|
28867
|
+
type: "resource",
|
|
28868
|
+
resource: { uri: SQUAD_CONTEXT_URI, mimeType: "text/plain", text }
|
|
28869
|
+
};
|
|
28870
|
+
}
|
|
28871
|
+
function isSquadContextBlock(block) {
|
|
28872
|
+
return block.type === "resource" && block.resource.uri === SQUAD_CONTEXT_URI;
|
|
28873
|
+
}
|
|
28874
|
+
function looksLikeUnsupportedPromptShape(err) {
|
|
28875
|
+
const code = err?.code;
|
|
28876
|
+
if (code === -32602) return true;
|
|
28877
|
+
const message = err instanceof Error ? err.message : String(err ?? "");
|
|
28878
|
+
if (/invalid[ _]params|-32602/i.test(message)) return true;
|
|
28879
|
+
return /\bresource\b/i.test(message) && /unsupported|not supported/i.test(message);
|
|
28880
|
+
}
|
|
28881
|
+
function skipWhile(lines, start2, keepGoing) {
|
|
28882
|
+
let i = start2;
|
|
28883
|
+
while (i < lines.length && keepGoing(lines[i])) i++;
|
|
28884
|
+
return i;
|
|
28885
|
+
}
|
|
28886
|
+
function endOfTeamPreamble(lines, start2) {
|
|
28887
|
+
if (lines[start2] !== TEAM_PREAMBLE_LINES[0]) return -1;
|
|
28888
|
+
if (lines[start2 + 1] !== TEAM_PREAMBLE_LINES[1]) return -1;
|
|
28889
|
+
return skipWhile(
|
|
28890
|
+
lines,
|
|
28891
|
+
start2 + 2,
|
|
28892
|
+
(line) => TEAM_PREAMBLE_BULLET_RE.test(line) || TEAM_PREAMBLE_LINES.includes(line)
|
|
28893
|
+
);
|
|
28894
|
+
}
|
|
28895
|
+
function endOfTerminatedBlock(lines, start2, terminator) {
|
|
28896
|
+
for (let i = start2; i < lines.length; i++) {
|
|
28897
|
+
if (lines[i].trimEnd() === terminator) return i + 1;
|
|
28898
|
+
}
|
|
28899
|
+
return -1;
|
|
28900
|
+
}
|
|
28901
|
+
function stripSquadContext(text) {
|
|
28902
|
+
if (!text.includes(HANDOFF_MARKER) && !text.includes(BRIEFING_MARKER) && !text.includes(TEAM_PREAMBLE_MARKER)) {
|
|
28903
|
+
return text;
|
|
28904
|
+
}
|
|
28905
|
+
const lines = text.split("\n");
|
|
28906
|
+
const kept = [];
|
|
28907
|
+
let i = 0;
|
|
28908
|
+
let stripped = false;
|
|
28909
|
+
while (i < lines.length) {
|
|
28910
|
+
const line = lines[i];
|
|
28911
|
+
if (line.startsWith(HANDOFF_MARKER)) {
|
|
28912
|
+
const end = endOfTerminatedBlock(lines, i, HANDOFF_TERMINATOR);
|
|
28913
|
+
if (end !== -1) {
|
|
28914
|
+
i = end;
|
|
28915
|
+
stripped = true;
|
|
28916
|
+
continue;
|
|
28917
|
+
}
|
|
28918
|
+
} else if (line.startsWith(BRIEFING_MARKER)) {
|
|
28919
|
+
const end = endOfTerminatedBlock(lines, i, BRIEFING_FOOTER);
|
|
28920
|
+
if (end !== -1) {
|
|
28921
|
+
i = end;
|
|
28922
|
+
stripped = true;
|
|
28923
|
+
continue;
|
|
28924
|
+
}
|
|
28925
|
+
} else if (line.startsWith(TEAM_PREAMBLE_MARKER)) {
|
|
28926
|
+
const end = endOfTeamPreamble(lines, i);
|
|
28927
|
+
if (end !== -1) {
|
|
28928
|
+
i = end;
|
|
28929
|
+
stripped = true;
|
|
28930
|
+
continue;
|
|
28931
|
+
}
|
|
28932
|
+
}
|
|
28933
|
+
kept.push(line);
|
|
28934
|
+
i++;
|
|
28935
|
+
}
|
|
28936
|
+
if (!stripped) return text;
|
|
28937
|
+
return kept.join("\n").trim();
|
|
28938
|
+
}
|
|
28939
|
+
|
|
28940
|
+
// src/services/history.service.ts
|
|
28567
28941
|
var historyRecordSchema = import_zod2.z.object({
|
|
28568
28942
|
type: import_zod2.z.string().optional(),
|
|
28569
28943
|
timestamp: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.number()]).optional(),
|
|
@@ -28583,11 +28957,24 @@ function extractText3(content) {
|
|
|
28583
28957
|
return "";
|
|
28584
28958
|
}
|
|
28585
28959
|
var CONVERSATION_BATCH_SIZE = 30;
|
|
28960
|
+
function scrubSquadContext(messages) {
|
|
28961
|
+
const out2 = [];
|
|
28962
|
+
for (const m of messages) {
|
|
28963
|
+
const text = stripSquadContext(m.text);
|
|
28964
|
+
if (text === m.text) {
|
|
28965
|
+
out2.push(m);
|
|
28966
|
+
continue;
|
|
28967
|
+
}
|
|
28968
|
+
if (text.length === 0) continue;
|
|
28969
|
+
out2.push({ ...m, text });
|
|
28970
|
+
}
|
|
28971
|
+
return out2;
|
|
28972
|
+
}
|
|
28586
28973
|
function parseJsonl(filePath) {
|
|
28587
28974
|
const messages = [];
|
|
28588
28975
|
let raw;
|
|
28589
28976
|
try {
|
|
28590
|
-
raw =
|
|
28977
|
+
raw = fs66.readFileSync(filePath, "utf8");
|
|
28591
28978
|
} catch (err) {
|
|
28592
28979
|
if (err.code !== "ENOENT") {
|
|
28593
28980
|
log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
|
|
@@ -28728,7 +29115,7 @@ var HistoryService = class _HistoryService {
|
|
|
28728
29115
|
return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
|
|
28729
29116
|
}
|
|
28730
29117
|
get projectDir() {
|
|
28731
|
-
return this.runtime.resolveHistoryDir(this.cwd) ??
|
|
29118
|
+
return this.runtime.resolveHistoryDir(this.cwd) ?? path72.join(os56.homedir(), ".claude", "projects", encodeCwd(this.cwd));
|
|
28732
29119
|
}
|
|
28733
29120
|
/** Set the current Claude conversation ID (extracted from /cost command or session start) */
|
|
28734
29121
|
setCurrentConversationId(id) {
|
|
@@ -28740,7 +29127,7 @@ var HistoryService = class _HistoryService {
|
|
|
28740
29127
|
/** Return the current message count in the active conversation. */
|
|
28741
29128
|
getCurrentMessageCount() {
|
|
28742
29129
|
if (!this.currentConversationId) return 0;
|
|
28743
|
-
const filePath =
|
|
29130
|
+
const filePath = path72.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
28744
29131
|
return parseJsonl(filePath).length;
|
|
28745
29132
|
}
|
|
28746
29133
|
/**
|
|
@@ -28751,7 +29138,7 @@ var HistoryService = class _HistoryService {
|
|
|
28751
29138
|
const deadline = Date.now() + timeoutMs;
|
|
28752
29139
|
while (Date.now() < deadline) {
|
|
28753
29140
|
if (!this.currentConversationId) return null;
|
|
28754
|
-
const filePath =
|
|
29141
|
+
const filePath = path72.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
28755
29142
|
const messages = parseJsonl(filePath);
|
|
28756
29143
|
if (messages.length > previousCount) {
|
|
28757
29144
|
for (let i = messages.length - 1; i >= previousCount; i--) {
|
|
@@ -28777,16 +29164,16 @@ var HistoryService = class _HistoryService {
|
|
|
28777
29164
|
const dir = this.projectDir;
|
|
28778
29165
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
28779
29166
|
try {
|
|
28780
|
-
const files =
|
|
29167
|
+
const files = fs66.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
28781
29168
|
try {
|
|
28782
|
-
const stat3 =
|
|
29169
|
+
const stat3 = fs66.statSync(path72.join(dir, e.name));
|
|
28783
29170
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
28784
29171
|
} catch {
|
|
28785
29172
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
28786
29173
|
}
|
|
28787
29174
|
}).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
|
|
28788
29175
|
if (files.length > 0) {
|
|
28789
|
-
this.currentConversationId =
|
|
29176
|
+
this.currentConversationId = path72.basename(files[0].name, ".jsonl");
|
|
28790
29177
|
}
|
|
28791
29178
|
} catch {
|
|
28792
29179
|
}
|
|
@@ -28820,13 +29207,13 @@ var HistoryService = class _HistoryService {
|
|
|
28820
29207
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
28821
29208
|
let entries;
|
|
28822
29209
|
try {
|
|
28823
|
-
entries =
|
|
29210
|
+
entries = fs66.readdirSync(dir, { withFileTypes: true });
|
|
28824
29211
|
} catch {
|
|
28825
29212
|
return null;
|
|
28826
29213
|
}
|
|
28827
29214
|
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
28828
29215
|
try {
|
|
28829
|
-
const stat3 =
|
|
29216
|
+
const stat3 = fs66.statSync(path72.join(dir, e.name));
|
|
28830
29217
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
28831
29218
|
} catch {
|
|
28832
29219
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
@@ -28835,12 +29222,12 @@ var HistoryService = class _HistoryService {
|
|
|
28835
29222
|
if (files.length === 0) return null;
|
|
28836
29223
|
const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
|
|
28837
29224
|
if (!files.some((f) => f.name === targetFile)) return null;
|
|
28838
|
-
return this.extractUsageFromFile(
|
|
29225
|
+
return this.extractUsageFromFile(path72.join(dir, targetFile));
|
|
28839
29226
|
}
|
|
28840
29227
|
extractUsageFromFile(filePath) {
|
|
28841
29228
|
let raw;
|
|
28842
29229
|
try {
|
|
28843
|
-
raw =
|
|
29230
|
+
raw = fs66.readFileSync(filePath, "utf8");
|
|
28844
29231
|
} catch {
|
|
28845
29232
|
return null;
|
|
28846
29233
|
}
|
|
@@ -28885,9 +29272,9 @@ var HistoryService = class _HistoryService {
|
|
|
28885
29272
|
let totalCost = 0;
|
|
28886
29273
|
let files;
|
|
28887
29274
|
try {
|
|
28888
|
-
files =
|
|
29275
|
+
files = fs66.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
28889
29276
|
try {
|
|
28890
|
-
return
|
|
29277
|
+
return fs66.statSync(path72.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
28891
29278
|
} catch {
|
|
28892
29279
|
return false;
|
|
28893
29280
|
}
|
|
@@ -28898,7 +29285,7 @@ var HistoryService = class _HistoryService {
|
|
|
28898
29285
|
for (const file of files) {
|
|
28899
29286
|
let raw;
|
|
28900
29287
|
try {
|
|
28901
|
-
raw =
|
|
29288
|
+
raw = fs66.readFileSync(path72.join(projectDir, file), "utf8");
|
|
28902
29289
|
} catch {
|
|
28903
29290
|
continue;
|
|
28904
29291
|
}
|
|
@@ -28977,7 +29364,7 @@ var HistoryService = class _HistoryService {
|
|
|
28977
29364
|
if (this.runtime.resolveHistoryFile) {
|
|
28978
29365
|
return this.runtime.resolveHistoryFile(this.cwd, sessionId);
|
|
28979
29366
|
}
|
|
28980
|
-
return
|
|
29367
|
+
return path72.join(this.projectDir, `${sessionId}.jsonl`);
|
|
28981
29368
|
}
|
|
28982
29369
|
/**
|
|
28983
29370
|
* Parse a conversation's messages from disk, agent-aware. Claude uses the
|
|
@@ -28989,6 +29376,10 @@ var HistoryService = class _HistoryService {
|
|
|
28989
29376
|
* convention as parseJsonl.
|
|
28990
29377
|
*/
|
|
28991
29378
|
readConversation(sessionId) {
|
|
29379
|
+
const agentId = this.runtime.id;
|
|
29380
|
+
return scrubSquadContext(this.readConversationRaw(sessionId)).map((m) => ({ ...m, agentId }));
|
|
29381
|
+
}
|
|
29382
|
+
readConversationRaw(sessionId) {
|
|
28992
29383
|
if (this.runtime.resolveHistoryFile) {
|
|
28993
29384
|
const filePath = this.runtime.resolveHistoryFile(this.cwd, sessionId);
|
|
28994
29385
|
if (!filePath) return [];
|
|
@@ -29011,7 +29402,7 @@ var HistoryService = class _HistoryService {
|
|
|
29011
29402
|
};
|
|
29012
29403
|
});
|
|
29013
29404
|
}
|
|
29014
|
-
return parseJsonl(
|
|
29405
|
+
return parseJsonl(path72.join(this.projectDir, `${sessionId}.jsonl`));
|
|
29015
29406
|
}
|
|
29016
29407
|
async loadConversation(sessionId) {
|
|
29017
29408
|
const messages = this.readConversation(sessionId);
|
|
@@ -29079,7 +29470,7 @@ var HistoryService = class _HistoryService {
|
|
|
29079
29470
|
if (!filePath) return false;
|
|
29080
29471
|
let mtimeMs;
|
|
29081
29472
|
try {
|
|
29082
|
-
mtimeMs =
|
|
29473
|
+
mtimeMs = fs66.statSync(filePath).mtimeMs;
|
|
29083
29474
|
} catch {
|
|
29084
29475
|
return false;
|
|
29085
29476
|
}
|
|
@@ -29154,10 +29545,10 @@ var HistoryService = class _HistoryService {
|
|
|
29154
29545
|
|
|
29155
29546
|
// src/agents/acp/client.ts
|
|
29156
29547
|
var import_node_child_process29 = require("child_process");
|
|
29157
|
-
var
|
|
29548
|
+
var fs67 = __toESM(require("fs/promises"));
|
|
29158
29549
|
var fsSync = __toESM(require("fs"));
|
|
29159
|
-
var
|
|
29160
|
-
var
|
|
29550
|
+
var os58 = __toESM(require("os"));
|
|
29551
|
+
var path74 = __toESM(require("path"));
|
|
29161
29552
|
var import_node_stream = require("stream");
|
|
29162
29553
|
|
|
29163
29554
|
// ../../node_modules/@agentclientprotocol/sdk/dist/schema/index.js
|
|
@@ -33183,8 +33574,8 @@ function createIdleTimeout(idleMs, makeError, activeIdleMs = idleMs) {
|
|
|
33183
33574
|
}
|
|
33184
33575
|
|
|
33185
33576
|
// src/agents/acp/internal-paths.ts
|
|
33186
|
-
var
|
|
33187
|
-
var
|
|
33577
|
+
var path73 = __toESM(require("path"));
|
|
33578
|
+
var os57 = __toESM(require("os"));
|
|
33188
33579
|
var INTERNAL_TOKENS = [".codeam", "house-claude"];
|
|
33189
33580
|
var SELF_HOSTED_WORKSPACE_RE = /\.codeam[/\\]self-hosted/gi;
|
|
33190
33581
|
function textReferencesInternal(text) {
|
|
@@ -33192,13 +33583,13 @@ function textReferencesInternal(text) {
|
|
|
33192
33583
|
const scrubbed = text.replace(SELF_HOSTED_WORKSPACE_RE, " ");
|
|
33193
33584
|
return INTERNAL_TOKENS.some((t2) => scrubbed.includes(t2));
|
|
33194
33585
|
}
|
|
33195
|
-
function pathIsInternal(p2, homeDir2 =
|
|
33586
|
+
function pathIsInternal(p2, homeDir2 = os57.homedir()) {
|
|
33196
33587
|
if (!p2) return false;
|
|
33197
|
-
const abs =
|
|
33198
|
-
const home =
|
|
33199
|
-
const within = (root) => abs === root || abs.startsWith(root +
|
|
33200
|
-
if (within(
|
|
33201
|
-
return within(
|
|
33588
|
+
const abs = path73.resolve(p2);
|
|
33589
|
+
const home = path73.resolve(homeDir2);
|
|
33590
|
+
const within = (root) => abs === root || abs.startsWith(root + path73.sep);
|
|
33591
|
+
if (within(path73.join(home, ".codeam", "self-hosted"))) return false;
|
|
33592
|
+
return within(path73.join(home, ".codeam")) || within(path73.join(home, ".beads")) || abs === path73.join(home, ".codeam-host.log") || abs.includes(`${path73.sep}house-claude${path73.sep}`) || abs.endsWith(`${path73.sep}house-claude`);
|
|
33202
33593
|
}
|
|
33203
33594
|
function toolCallReferencesInternal(call) {
|
|
33204
33595
|
if (textReferencesInternal(call.title)) return true;
|
|
@@ -34157,7 +34548,7 @@ var AcpClient = class {
|
|
|
34157
34548
|
throw new RequestError(-32002, GUARDRAIL_SECRET_READ_BLOCK_REASON, { uri: params.path });
|
|
34158
34549
|
}
|
|
34159
34550
|
try {
|
|
34160
|
-
const content = await
|
|
34551
|
+
const content = await fs67.readFile(params.path, "utf8");
|
|
34161
34552
|
return applyLineRange(content, params.line ?? null, params.limit ?? null);
|
|
34162
34553
|
} catch (err) {
|
|
34163
34554
|
const code = err.code;
|
|
@@ -34180,7 +34571,7 @@ var AcpClient = class {
|
|
|
34180
34571
|
throw new RequestError(-32002, INTERNAL_BLOCK_REASON, { uri: params.path });
|
|
34181
34572
|
}
|
|
34182
34573
|
try {
|
|
34183
|
-
await
|
|
34574
|
+
await fs67.writeFile(params.path, params.content, "utf8");
|
|
34184
34575
|
return {};
|
|
34185
34576
|
} catch (err) {
|
|
34186
34577
|
const code = err.code;
|
|
@@ -34240,29 +34631,29 @@ function applyLineRange(content, line, limit) {
|
|
|
34240
34631
|
return { content: lines.slice(start2, end).join("\n") };
|
|
34241
34632
|
}
|
|
34242
34633
|
function knownAgentBinaryDirs() {
|
|
34243
|
-
const home =
|
|
34634
|
+
const home = os58.homedir();
|
|
34244
34635
|
const out2 = [];
|
|
34245
34636
|
out2.push("/tmp/codeam-node20/bin");
|
|
34246
34637
|
for (const root of [
|
|
34247
34638
|
"/usr/local/share/nvm/versions/node",
|
|
34248
|
-
|
|
34639
|
+
path74.join(home, ".nvm/versions/node")
|
|
34249
34640
|
]) {
|
|
34250
34641
|
try {
|
|
34251
34642
|
for (const child of fsSync.readdirSync(root)) {
|
|
34252
|
-
out2.push(
|
|
34643
|
+
out2.push(path74.join(root, child, "bin"));
|
|
34253
34644
|
}
|
|
34254
34645
|
} catch {
|
|
34255
34646
|
}
|
|
34256
34647
|
}
|
|
34257
|
-
out2.push(
|
|
34648
|
+
out2.push(path74.join(home, ".volta/bin"));
|
|
34258
34649
|
out2.push("/usr/local/bin");
|
|
34259
34650
|
out2.push("/usr/bin");
|
|
34260
|
-
out2.push(
|
|
34261
|
-
out2.push(
|
|
34651
|
+
out2.push(path74.join(home, ".local/bin"));
|
|
34652
|
+
out2.push(path74.join(home, "bin"));
|
|
34262
34653
|
if (process.platform === "win32") {
|
|
34263
34654
|
const { LOCALAPPDATA, APPDATA } = process.env;
|
|
34264
|
-
if (LOCALAPPDATA) out2.push(
|
|
34265
|
-
if (APPDATA) out2.push(
|
|
34655
|
+
if (LOCALAPPDATA) out2.push(path74.join(LOCALAPPDATA, "cursor-agent"));
|
|
34656
|
+
if (APPDATA) out2.push(path74.join(APPDATA, "npm"));
|
|
34266
34657
|
}
|
|
34267
34658
|
return out2.filter((p2) => {
|
|
34268
34659
|
try {
|
|
@@ -34274,7 +34665,7 @@ function knownAgentBinaryDirs() {
|
|
|
34274
34665
|
}
|
|
34275
34666
|
function expandPathForAgentBinaries(existingPath) {
|
|
34276
34667
|
const existing = new Set(
|
|
34277
|
-
existingPath.split(
|
|
34668
|
+
existingPath.split(path74.delimiter).filter((p2) => p2.length > 0)
|
|
34278
34669
|
);
|
|
34279
34670
|
const additions = [];
|
|
34280
34671
|
for (const dir of knownAgentBinaryDirs()) {
|
|
@@ -34284,7 +34675,7 @@ function expandPathForAgentBinaries(existingPath) {
|
|
|
34284
34675
|
}
|
|
34285
34676
|
}
|
|
34286
34677
|
if (additions.length === 0) return existingPath;
|
|
34287
|
-
return [...additions, existingPath].filter((p2) => p2.length > 0).join(
|
|
34678
|
+
return [...additions, existingPath].filter((p2) => p2.length > 0).join(path74.delimiter);
|
|
34288
34679
|
}
|
|
34289
34680
|
|
|
34290
34681
|
// src/agents/acp/headroom-budget-proxy.ts
|
|
@@ -34366,7 +34757,7 @@ async function ensureAgentBinaryForSwitch(agentId, installScript, deps = {}) {
|
|
|
34366
34757
|
};
|
|
34367
34758
|
}
|
|
34368
34759
|
log.info("switchAgent", `installing ${agentId} binary (missing on PATH)`);
|
|
34369
|
-
const res = await runInstall(installScript, { logScope: "switchAgent" });
|
|
34760
|
+
const res = await runInstall(installScript, { logScope: "switchAgent", timeoutMs: 3e5 });
|
|
34370
34761
|
if (!res.ok) {
|
|
34371
34762
|
return {
|
|
34372
34763
|
ok: false,
|
|
@@ -34374,6 +34765,22 @@ async function ensureAgentBinaryForSwitch(agentId, installScript, deps = {}) {
|
|
|
34374
34765
|
};
|
|
34375
34766
|
}
|
|
34376
34767
|
if (await spec.waitForBinary({ timeoutMs: 3e4 })) return { ok: true };
|
|
34768
|
+
log.info(
|
|
34769
|
+
"switchAgent",
|
|
34770
|
+
"install probe failed \u2014 retrying install once (half-finished bin link class)"
|
|
34771
|
+
);
|
|
34772
|
+
deps.onRetry?.();
|
|
34773
|
+
const retryRes = await runInstall(installScript, {
|
|
34774
|
+
logScope: "switchAgent",
|
|
34775
|
+
timeoutMs: 3e5
|
|
34776
|
+
});
|
|
34777
|
+
if (!retryRes.ok) {
|
|
34778
|
+
return {
|
|
34779
|
+
ok: false,
|
|
34780
|
+
error: retryRes.timedOut ? `${displayName(agentId)} install timed out.` : `${displayName(agentId)} install failed.`
|
|
34781
|
+
};
|
|
34782
|
+
}
|
|
34783
|
+
if (await spec.waitForBinary({ timeoutMs: 3e4 })) return { ok: true };
|
|
34377
34784
|
return {
|
|
34378
34785
|
ok: false,
|
|
34379
34786
|
error: `${displayName(agentId)} installed but its binary never appeared on PATH.`
|
|
@@ -34407,7 +34814,11 @@ async function performAgentSwitch(deps, rawAgentId, fastPath = {}) {
|
|
|
34407
34814
|
const from = deps.currentAgent();
|
|
34408
34815
|
const target = resolveSwitchTarget(rawAgentId, from);
|
|
34409
34816
|
if (!target.ok) {
|
|
34410
|
-
return {
|
|
34817
|
+
return {
|
|
34818
|
+
ok: false,
|
|
34819
|
+
agentId: typeof rawAgentId === "string" ? rawAgentId : "",
|
|
34820
|
+
error: target.error
|
|
34821
|
+
};
|
|
34411
34822
|
}
|
|
34412
34823
|
const agentId = target.agentId;
|
|
34413
34824
|
const emitStatus = (status2) => deps.postEvent("switch_agent_status", { ...status2 });
|
|
@@ -34438,7 +34849,9 @@ async function performAgentSwitch(deps, rawAgentId, fastPath = {}) {
|
|
|
34438
34849
|
}
|
|
34439
34850
|
if (!fastPath.skipInstall) {
|
|
34440
34851
|
void emitStep("install");
|
|
34441
|
-
const bin = await deps.ensureBinary(agentId, installScript)
|
|
34852
|
+
const bin = await deps.ensureBinary(agentId, installScript, () => {
|
|
34853
|
+
void emitStep("install");
|
|
34854
|
+
});
|
|
34442
34855
|
if (!bin.ok) return fail2(bin.error);
|
|
34443
34856
|
}
|
|
34444
34857
|
void emitStep("restart");
|
|
@@ -34454,7 +34867,9 @@ async function performAgentSwitch(deps, rawAgentId, fastPath = {}) {
|
|
|
34454
34867
|
`Switching to ${displayName(agentId)} failed and ${displayName(from)} couldn't be restored \u2014 restart the session.`
|
|
34455
34868
|
);
|
|
34456
34869
|
}
|
|
34457
|
-
return fail2(
|
|
34870
|
+
return fail2(
|
|
34871
|
+
`Couldn't start ${displayName(agentId)} \u2014 the session stays on ${displayName(from)}.`
|
|
34872
|
+
);
|
|
34458
34873
|
}
|
|
34459
34874
|
try {
|
|
34460
34875
|
deps.persistAgent(agentId);
|
|
@@ -34467,121 +34882,6 @@ async function performAgentSwitch(deps, rawAgentId, fastPath = {}) {
|
|
|
34467
34882
|
return { ok: true, agentId };
|
|
34468
34883
|
}
|
|
34469
34884
|
|
|
34470
|
-
// src/agents/acp/squad-roster.ts
|
|
34471
|
-
var fs67 = __toESM(require("fs"));
|
|
34472
|
-
var os58 = __toESM(require("os"));
|
|
34473
|
-
var path74 = __toESM(require("path"));
|
|
34474
|
-
var PROMPT_MAX = 500;
|
|
34475
|
-
var REPLY_SUMMARY_MAX = 1e3;
|
|
34476
|
-
var PREAMBLE_MAX = 2e3;
|
|
34477
|
-
var BRIEFING_DEFAULT_MAX = 8e3;
|
|
34478
|
-
var GENERIC_SPECIALTY = "general implementation tasks";
|
|
34479
|
-
function clip(s, max) {
|
|
34480
|
-
return s.length > max ? s.slice(0, max) : s;
|
|
34481
|
-
}
|
|
34482
|
-
function defaultMember() {
|
|
34483
|
-
return { acpSessionId: null, provisioned: false, binaryVerified: false, lastTurnIndex: 0 };
|
|
34484
|
-
}
|
|
34485
|
-
function journalPathFor(homeDir2, sessionId) {
|
|
34486
|
-
return path74.join(homeDir2, ".codeam", `squad-journal-${sessionId}.json`);
|
|
34487
|
-
}
|
|
34488
|
-
function loadJournal(journalPath) {
|
|
34489
|
-
try {
|
|
34490
|
-
const raw = JSON.parse(fs67.readFileSync(journalPath, "utf-8"));
|
|
34491
|
-
return Array.isArray(raw.turns) ? raw.turns : [];
|
|
34492
|
-
} catch {
|
|
34493
|
-
return [];
|
|
34494
|
-
}
|
|
34495
|
-
}
|
|
34496
|
-
var SquadState = class {
|
|
34497
|
-
/** Set by the caller after fetchSquadRoster; null until then. */
|
|
34498
|
-
roster = null;
|
|
34499
|
-
journalPath;
|
|
34500
|
-
turns;
|
|
34501
|
-
members = /* @__PURE__ */ new Map();
|
|
34502
|
-
constructor(opts) {
|
|
34503
|
-
this.journalPath = journalPathFor(opts.homeDir ?? os58.homedir(), opts.sessionId);
|
|
34504
|
-
this.turns = loadJournal(this.journalPath);
|
|
34505
|
-
}
|
|
34506
|
-
/** Returns (creating on first access) the mutable per-agent state. */
|
|
34507
|
-
member(agentId) {
|
|
34508
|
-
let m = this.members.get(agentId);
|
|
34509
|
-
if (!m) {
|
|
34510
|
-
m = defaultMember();
|
|
34511
|
-
this.members.set(agentId, m);
|
|
34512
|
-
}
|
|
34513
|
-
return m;
|
|
34514
|
-
}
|
|
34515
|
-
/** Appends a journal entry and persists (fire-and-forget durability). */
|
|
34516
|
-
recordTurn(entry) {
|
|
34517
|
-
const turn = {
|
|
34518
|
-
turn: this.turns.length + 1,
|
|
34519
|
-
agentId: entry.agentId,
|
|
34520
|
-
prompt: clip(entry.prompt, PROMPT_MAX),
|
|
34521
|
-
replySummary: clip(entry.replySummary, REPLY_SUMMARY_MAX),
|
|
34522
|
-
filesTouched: entry.filesTouched
|
|
34523
|
-
};
|
|
34524
|
-
this.turns.push(turn);
|
|
34525
|
-
this.persist();
|
|
34526
|
-
}
|
|
34527
|
-
turnCount() {
|
|
34528
|
-
return this.turns.length;
|
|
34529
|
-
}
|
|
34530
|
-
entriesSince(turnIndex) {
|
|
34531
|
-
return this.turns.filter((t2) => t2.turn > turnIndex);
|
|
34532
|
-
}
|
|
34533
|
-
persist() {
|
|
34534
|
-
try {
|
|
34535
|
-
fs67.mkdirSync(path74.dirname(this.journalPath), { recursive: true, mode: 448 });
|
|
34536
|
-
fs67.writeFileSync(this.journalPath, JSON.stringify({ turns: this.turns }), { mode: 384 });
|
|
34537
|
-
} catch {
|
|
34538
|
-
}
|
|
34539
|
-
}
|
|
34540
|
-
};
|
|
34541
|
-
function specialtyFor(agentId) {
|
|
34542
|
-
return SQUAD_SPECIALTIES[agentId] ?? GENERIC_SPECIALTY;
|
|
34543
|
-
}
|
|
34544
|
-
function buildTeamPreamble(roster, currentAgent, opts) {
|
|
34545
|
-
const others = roster.agents.filter((a) => a.agentId !== currentAgent);
|
|
34546
|
-
if (others.length === 0) return null;
|
|
34547
|
-
const lines = [
|
|
34548
|
-
"[Team context] You are the active agent in a CodeAgent Mobile session where the user",
|
|
34549
|
-
"has a squad of agents and can pass work between them. Your available teammates:",
|
|
34550
|
-
...others.map((a) => `- ${a.displayName} \u2014 best at: ${specialtyFor(a.agentId)}`)
|
|
34551
|
-
];
|
|
34552
|
-
if (opts.handoffInstructions) {
|
|
34553
|
-
lines.push(
|
|
34554
|
-
"If a task clearly fits a teammate better than you, you MAY propose a handoff by ending",
|
|
34555
|
-
`your reply with a fenced code block tagged ${HANDOFF_FENCE_TAG} containing ONE JSON object:`,
|
|
34556
|
-
'{"to":"<teammate id>","reason":"<one sentence>","prompt":"<the prompt they should run>"}',
|
|
34557
|
-
"Propose at most one handoff per reply, only when genuinely better, and never announce",
|
|
34558
|
-
"the block in prose \u2014 the app renders it as a card the user can accept."
|
|
34559
|
-
);
|
|
34560
|
-
}
|
|
34561
|
-
return clip(lines.join("\n"), PREAMBLE_MAX);
|
|
34562
|
-
}
|
|
34563
|
-
function renderJournalEntry(e) {
|
|
34564
|
-
const filesClause = e.filesTouched.length > 0 ? ` (files: ${e.filesTouched.join(", ")})` : "";
|
|
34565
|
-
return `- turn ${e.turn} (${e.agentId}): ${e.prompt} \u2192 ${e.replySummary}${filesClause}`;
|
|
34566
|
-
}
|
|
34567
|
-
function buildDeltaBriefing(entries, maxChars = BRIEFING_DEFAULT_MAX) {
|
|
34568
|
-
if (entries.length === 0) return null;
|
|
34569
|
-
const header = "[Team update] While you were away, other agents worked on this session:";
|
|
34570
|
-
const footer = "Continue from the CURRENT state of the working tree.";
|
|
34571
|
-
const envelope = header.length + 1 + footer.length + 1;
|
|
34572
|
-
const sorted = [...entries].sort((a, b) => a.turn - b.turn);
|
|
34573
|
-
const lines = [];
|
|
34574
|
-
let bodyLen = 0;
|
|
34575
|
-
for (let i = sorted.length - 1; i >= 0; i--) {
|
|
34576
|
-
const line = renderJournalEntry(sorted[i]);
|
|
34577
|
-
const addedLen = line.length + (lines.length > 0 ? 1 : 0);
|
|
34578
|
-
if (lines.length > 0 && envelope + bodyLen + addedLen > maxChars) break;
|
|
34579
|
-
lines.unshift(line);
|
|
34580
|
-
bodyLen += addedLen;
|
|
34581
|
-
}
|
|
34582
|
-
return [header, lines.join("\n"), footer].join("\n");
|
|
34583
|
-
}
|
|
34584
|
-
|
|
34585
34885
|
// src/services/streaming/transport.ts
|
|
34586
34886
|
var http7 = __toESM(require("http"));
|
|
34587
34887
|
var https8 = __toESM(require("https"));
|
|
@@ -34881,6 +35181,13 @@ var AcpPublisher = class {
|
|
|
34881
35181
|
* `mode: 'replace'` so a re-send overrides any stale persisted
|
|
34882
35182
|
* version — important for the ACP path because each turn we ship
|
|
34883
35183
|
* the cumulative messages, not a delta.
|
|
35184
|
+
*
|
|
35185
|
+
* Each message may carry its OWN `agentId` — the agent that PRODUCED that
|
|
35186
|
+
* turn. The top-level `agentId` only keys the backend's per-agent
|
|
35187
|
+
* conversation bucket, so without the per-message field a multi-agent
|
|
35188
|
+
* session's reloaded history collapsed to whichever agent happened to be
|
|
35189
|
+
* active (the v1 limitation, codeagent-egai). Additive: older backends
|
|
35190
|
+
* ignore it, older CLIs simply omit it.
|
|
34884
35191
|
*/
|
|
34885
35192
|
async pushConversation(args2) {
|
|
34886
35193
|
const url2 = `${this.apiBase}/api/sessions/conversation`;
|
|
@@ -35101,8 +35408,19 @@ function stripHandoffFences(text) {
|
|
|
35101
35408
|
}
|
|
35102
35409
|
return restore(stripFences(masked));
|
|
35103
35410
|
}
|
|
35104
|
-
function
|
|
35105
|
-
|
|
35411
|
+
function handoffFenceStartMasked(text) {
|
|
35412
|
+
const { masked } = maskOuterFences(text);
|
|
35413
|
+
if (masked.indexOf(FENCE_OPEN) === -1) return -1;
|
|
35414
|
+
const spans = [];
|
|
35415
|
+
for (const m of text.matchAll(OUTER_FENCE_RE)) {
|
|
35416
|
+
const start2 = m.index ?? 0;
|
|
35417
|
+
spans.push({ start: start2, end: start2 + m[0].length });
|
|
35418
|
+
}
|
|
35419
|
+
const insideSpan = (idx) => spans.some((s) => idx >= s.start && idx < s.end);
|
|
35420
|
+
for (let i = text.indexOf(FENCE_OPEN); i !== -1; i = text.indexOf(FENCE_OPEN, i + 1)) {
|
|
35421
|
+
if (!insideSpan(i)) return i;
|
|
35422
|
+
}
|
|
35423
|
+
return -1;
|
|
35106
35424
|
}
|
|
35107
35425
|
|
|
35108
35426
|
// src/agents/acp/onboarding.ts
|
|
@@ -35882,11 +36200,34 @@ var TurnFileAggregator = class {
|
|
|
35882
36200
|
*/
|
|
35883
36201
|
baselineByKey = /* @__PURE__ */ new Map();
|
|
35884
36202
|
baselineCaptured = false;
|
|
36203
|
+
/**
|
|
36204
|
+
* The file paths (relative to their repo root) that the MOST RECENT
|
|
36205
|
+
* `flushTurn()` call found novel — i.e. what it just enqueued (or would
|
|
36206
|
+
* have enqueued had the batch not exactly matched the baseline). Updated
|
|
36207
|
+
* unconditionally on every flush, including a no-op one (empties back
|
|
36208
|
+
* out), so `peekTurnPaths()` never returns paths from more than one
|
|
36209
|
+
* flush cycle ago. Not touched by the baseline-capture flush (it returns
|
|
36210
|
+
* before `novel` is computed), which is correct — pre-pair files aren't
|
|
36211
|
+
* "this session's" changes.
|
|
36212
|
+
*/
|
|
36213
|
+
lastTurnPaths = [];
|
|
35885
36214
|
/** Stop the outbox scheduler. Idempotent. */
|
|
35886
36215
|
stop() {
|
|
35887
36216
|
this.stopped = true;
|
|
35888
36217
|
this.outbox.stop();
|
|
35889
36218
|
}
|
|
36219
|
+
/**
|
|
36220
|
+
* Non-destructive read of the paths the MOST RECENT `flushTurn()` call
|
|
36221
|
+
* found novel — does NOT trigger a scan or clear anything itself. The
|
|
36222
|
+
* squad journal (`recordSquadTurn` in `command-handlers.ts`) `await`s
|
|
36223
|
+
* `flushTurn()` for the turn it's about to record BEFORE calling this, so
|
|
36224
|
+
* the read reflects THAT turn's paths, not a stale one left over from
|
|
36225
|
+
* whatever flushed previously. Empty on a session's very first turn
|
|
36226
|
+
* (still capturing the pre-pair baseline) or a chat-only turn.
|
|
36227
|
+
*/
|
|
36228
|
+
peekTurnPaths() {
|
|
36229
|
+
return [...this.lastTurnPaths];
|
|
36230
|
+
}
|
|
35890
36231
|
/**
|
|
35891
36232
|
* Run the discovery + git collection + POST pipeline for one
|
|
35892
36233
|
* turn. Errors are swallowed (logged) so an agent never blocks on a
|
|
@@ -35927,6 +36268,7 @@ var TurnFileAggregator = class {
|
|
|
35927
36268
|
if (!base) return true;
|
|
35928
36269
|
return base.linesAdded !== f.linesAdded || base.linesRemoved !== f.linesRemoved || base.fileStatus !== f.fileStatus;
|
|
35929
36270
|
});
|
|
36271
|
+
this.lastTurnPaths = novel.map((f) => f.filePath);
|
|
35930
36272
|
if (novel.length === 0) {
|
|
35931
36273
|
log.trace(
|
|
35932
36274
|
"turnFiles",
|
|
@@ -35946,10 +36288,7 @@ var TurnFileAggregator = class {
|
|
|
35946
36288
|
await this.outbox.enqueue(entry);
|
|
35947
36289
|
}
|
|
35948
36290
|
} catch (err) {
|
|
35949
|
-
log.warn(
|
|
35950
|
-
"turnFiles",
|
|
35951
|
-
`flushTurn failed: ${err.message ?? String(err)}`
|
|
35952
|
-
);
|
|
36291
|
+
log.warn("turnFiles", `flushTurn failed: ${err.message ?? String(err)}`);
|
|
35953
36292
|
}
|
|
35954
36293
|
}
|
|
35955
36294
|
/**
|
|
@@ -36945,6 +37284,56 @@ async function detectRepoStack(cwd, runtime) {
|
|
|
36945
37284
|
}
|
|
36946
37285
|
}
|
|
36947
37286
|
|
|
37287
|
+
// src/agents/acp/coderabbit-mention.ts
|
|
37288
|
+
var CODERABBIT_AGENT_ID = "coderabbit";
|
|
37289
|
+
var CODERABBIT_NOT_LINKED_MESSAGE = "Link CodeRabbit in Profile \u203A Your Squad first.";
|
|
37290
|
+
var CODERABBIT_NO_CUSTOM_INSTRUCTIONS_NOTICE = "CodeRabbit reviews your current changes \u2014 custom instructions aren't supported yet.";
|
|
37291
|
+
function hasCustomInstructions(prompt) {
|
|
37292
|
+
return prompt.replace(/@coderabbit\b/gi, "").trim().length > 0;
|
|
37293
|
+
}
|
|
37294
|
+
function composeReviewOutput(markdown, custom) {
|
|
37295
|
+
const body = markdown.trim().length > 0 ? markdown.trim() : "CodeRabbit found no issues to report.";
|
|
37296
|
+
return custom ? `${CODERABBIT_NO_CUSTOM_INSTRUCTIONS_NOTICE}
|
|
37297
|
+
|
|
37298
|
+
${body}` : body;
|
|
37299
|
+
}
|
|
37300
|
+
function defaultRunReview(input) {
|
|
37301
|
+
return new CoderabbitRuntimeStrategy(createOsStrategy()).runOneShot(input);
|
|
37302
|
+
}
|
|
37303
|
+
async function runCoderabbitMentionReview(deps = {}) {
|
|
37304
|
+
const configure = deps.configure ?? configureCoderabbit;
|
|
37305
|
+
const runReview = deps.runReview ?? defaultRunReview;
|
|
37306
|
+
try {
|
|
37307
|
+
const status2 = await configure({ action: "status" });
|
|
37308
|
+
if (!status2.loggedIn) {
|
|
37309
|
+
const cred = deps.fetchCredential ? await deps.fetchCredential() : null;
|
|
37310
|
+
if (!cred) return { ok: false, error: CODERABBIT_NOT_LINKED_MESSAGE };
|
|
37311
|
+
const provisioned = await configure({
|
|
37312
|
+
action: "provision",
|
|
37313
|
+
provisionCredential: cred
|
|
37314
|
+
});
|
|
37315
|
+
if (!provisioned.loggedIn) {
|
|
37316
|
+
return { ok: false, error: provisioned.error ?? CODERABBIT_NOT_LINKED_MESSAGE };
|
|
37317
|
+
}
|
|
37318
|
+
}
|
|
37319
|
+
const result = await configure({ action: "review" }, { runReview });
|
|
37320
|
+
if (result.error) return { ok: false, error: result.error };
|
|
37321
|
+
return { ok: true, markdown: result.review?.markdown ?? "" };
|
|
37322
|
+
} catch (err) {
|
|
37323
|
+
return {
|
|
37324
|
+
ok: false,
|
|
37325
|
+
error: err instanceof Error ? err.message : "CodeRabbit review failed"
|
|
37326
|
+
};
|
|
37327
|
+
}
|
|
37328
|
+
}
|
|
37329
|
+
function logMentionOutcome(result) {
|
|
37330
|
+
if (result.ok) {
|
|
37331
|
+
log.info("acpRunner", `squad: coderabbit review completed (${result.markdown.length} chars)`);
|
|
37332
|
+
} else {
|
|
37333
|
+
log.warn("acpRunner", `squad: coderabbit review failed: ${result.error}`);
|
|
37334
|
+
}
|
|
37335
|
+
}
|
|
37336
|
+
|
|
36948
37337
|
// src/agents/acp/command-handlers.ts
|
|
36949
37338
|
var import_node_child_process31 = require("child_process");
|
|
36950
37339
|
|
|
@@ -37143,39 +37532,72 @@ async function routeSquadTask(ctx, target) {
|
|
|
37143
37532
|
}
|
|
37144
37533
|
return { ok: true };
|
|
37145
37534
|
}
|
|
37146
|
-
function
|
|
37535
|
+
function collectSquadContext(ctx) {
|
|
37536
|
+
const pieces = [];
|
|
37537
|
+
const { squad, opts } = ctx;
|
|
37538
|
+
if (squad) {
|
|
37539
|
+
const member = squad.member(opts.agent);
|
|
37540
|
+
const roster = squad.roster;
|
|
37541
|
+
if (roster && member.lastTurnIndex === 0) {
|
|
37542
|
+
const preamble = buildTeamPreamble(roster, opts.agent, {
|
|
37543
|
+
handoffInstructions: roster.handoffsEnabled === true
|
|
37544
|
+
});
|
|
37545
|
+
if (preamble) pieces.push(preamble);
|
|
37546
|
+
}
|
|
37547
|
+
if (squad.turnCount() > member.lastTurnIndex) {
|
|
37548
|
+
const otherEntries = squad.entriesSince(member.lastTurnIndex).filter((e) => e.agentId !== opts.agent);
|
|
37549
|
+
const briefing = buildDeltaBriefing(otherEntries);
|
|
37550
|
+
if (briefing) pieces.push(briefing);
|
|
37551
|
+
}
|
|
37552
|
+
}
|
|
37147
37553
|
if (ctx.pendingHandoff?.current) {
|
|
37148
|
-
|
|
37554
|
+
pieces.push(ctx.pendingHandoff.current);
|
|
37149
37555
|
ctx.pendingHandoff.current = null;
|
|
37150
37556
|
}
|
|
37151
|
-
|
|
37152
|
-
|
|
37153
|
-
|
|
37154
|
-
|
|
37155
|
-
|
|
37156
|
-
|
|
37157
|
-
|
|
37557
|
+
return pieces;
|
|
37558
|
+
}
|
|
37559
|
+
function squadContextMode(ctx) {
|
|
37560
|
+
return ctx.squad?.member(ctx.opts.agent).contextTextFallback === true ? "text" : "resource";
|
|
37561
|
+
}
|
|
37562
|
+
function applySquadContext(blocks, pieces, mode) {
|
|
37563
|
+
if (pieces.length === 0) return;
|
|
37564
|
+
if (mode === "resource") {
|
|
37565
|
+
blocks.unshift(buildSquadContextBlock(pieces.join("\n\n")));
|
|
37566
|
+
return;
|
|
37158
37567
|
}
|
|
37159
|
-
|
|
37160
|
-
|
|
37161
|
-
|
|
37162
|
-
|
|
37163
|
-
|
|
37164
|
-
|
|
37568
|
+
for (let i = pieces.length - 1; i >= 0; i--) blocks.unshift({ type: "text", text: pieces[i] });
|
|
37569
|
+
}
|
|
37570
|
+
async function promptWithContextFallback(ctx, client3, blocks, pieces) {
|
|
37571
|
+
try {
|
|
37572
|
+
return await client3.prompt(blocks);
|
|
37573
|
+
} catch (err) {
|
|
37574
|
+
if (pieces.length === 0 || blocks.length === 0 || !isSquadContextBlock(blocks[0]) || !looksLikeUnsupportedPromptShape(err)) {
|
|
37575
|
+
throw err;
|
|
37576
|
+
}
|
|
37577
|
+
log.warn(
|
|
37578
|
+
"acpRunner",
|
|
37579
|
+
`squad: ${ctx.opts.agent} rejected the native squad-context resource block (${describeError(err)}) \u2014 retrying once with legacy text blocks`
|
|
37580
|
+
);
|
|
37581
|
+
if (ctx.squad) ctx.squad.member(ctx.opts.agent).contextTextFallback = true;
|
|
37582
|
+
blocks.shift();
|
|
37583
|
+
applySquadContext(blocks, pieces, "text");
|
|
37584
|
+
return await client3.prompt(blocks);
|
|
37165
37585
|
}
|
|
37166
37586
|
}
|
|
37167
37587
|
function recordSquadTurn(ctx, prompt, replySummary) {
|
|
37168
|
-
const { squad, opts } = ctx;
|
|
37588
|
+
const { squad, opts, turnFiles } = ctx;
|
|
37169
37589
|
if (!squad) return;
|
|
37170
37590
|
squad.recordTurn({
|
|
37171
37591
|
agentId: opts.agent,
|
|
37172
37592
|
prompt,
|
|
37173
37593
|
replySummary,
|
|
37174
37594
|
// TurnFileAggregator owns per-turn file changesets end-to-end (git diff →
|
|
37175
|
-
// outbox POST)
|
|
37176
|
-
//
|
|
37177
|
-
//
|
|
37178
|
-
|
|
37595
|
+
// outbox POST). The caller (`startTaskH`) AWAITS `turnFiles.flushTurn()`
|
|
37596
|
+
// for THIS turn before calling recordSquadTurn precisely so
|
|
37597
|
+
// `peekTurnPaths()` reflects THIS turn's novel files, not a stale read
|
|
37598
|
+
// of whatever the aggregator's PREVIOUS flush happened to find. Capped
|
|
37599
|
+
// so a pathological turn (mass refactor) doesn't bloat the journal.
|
|
37600
|
+
filesTouched: turnFiles.peekTurnPaths().slice(0, 20)
|
|
37179
37601
|
});
|
|
37180
37602
|
squad.member(opts.agent).lastTurnIndex = squad.turnCount();
|
|
37181
37603
|
}
|
|
@@ -37190,45 +37612,112 @@ function resolvePendingProposal(ctx, requestedAgentId) {
|
|
|
37190
37612
|
if (!slot || !pending) return;
|
|
37191
37613
|
slot.current = null;
|
|
37192
37614
|
const accepted = requestedAgentId === pending.toAgentId;
|
|
37615
|
+
if (accepted) ctx.squad?.countAccepted();
|
|
37193
37616
|
log.info(
|
|
37194
37617
|
"acpRunner",
|
|
37195
37618
|
`squad: handoff ${pending.proposalId} ${accepted ? "accepted" : "declined"}`
|
|
37196
37619
|
);
|
|
37197
|
-
|
|
37198
|
-
|
|
37199
|
-
|
|
37200
|
-
|
|
37620
|
+
const resolution = { proposalId: pending.proposalId, accepted };
|
|
37621
|
+
void ctx.postSquadEvent?.("handoff_resolved", { ...resolution });
|
|
37622
|
+
}
|
|
37623
|
+
function proposalIdFor(commandId, hop) {
|
|
37624
|
+
const id = hop <= 1 ? `hp-${commandId}` : `hp-${commandId}-h${hop}`;
|
|
37625
|
+
return id.length > 128 ? id.slice(0, 128) : id;
|
|
37201
37626
|
}
|
|
37202
|
-
function emitHandoffProposal(ctx, proposal) {
|
|
37627
|
+
function emitHandoffProposal(ctx, proposal, hop) {
|
|
37203
37628
|
const { squad, pendingProposal, postSquadEvent, opts, cmd } = ctx;
|
|
37204
|
-
if (!proposal || !pendingProposal || !postSquadEvent) return;
|
|
37205
|
-
if (squad?.roster?.handoffsEnabled !== true) return;
|
|
37629
|
+
if (!proposal || !pendingProposal || !postSquadEvent) return null;
|
|
37630
|
+
if (squad?.roster?.handoffsEnabled !== true) return null;
|
|
37206
37631
|
if (pendingProposal.current) {
|
|
37207
37632
|
log.info("acpRunner", "squad: dropping handoff proposal \u2014 one is already pending");
|
|
37208
|
-
return;
|
|
37633
|
+
return null;
|
|
37209
37634
|
}
|
|
37635
|
+
const auto = squad.auto.enabled && squad.hopsRemaining() > 0;
|
|
37636
|
+
if (auto) squad.consumeHop();
|
|
37210
37637
|
const record2 = {
|
|
37211
|
-
proposalId:
|
|
37638
|
+
proposalId: proposalIdFor(cmd.id, hop),
|
|
37212
37639
|
fromAgentId: opts.agent,
|
|
37213
37640
|
toAgentId: proposal.to,
|
|
37214
37641
|
reason: proposal.reason,
|
|
37215
|
-
prompt: proposal.prompt
|
|
37642
|
+
prompt: proposal.prompt,
|
|
37643
|
+
...auto ? { auto: true, hopsRemaining: squad.hopsRemaining() } : {}
|
|
37216
37644
|
};
|
|
37217
|
-
|
|
37218
|
-
log.info(
|
|
37645
|
+
squad.countProposal({ auto });
|
|
37646
|
+
log.info(
|
|
37647
|
+
"acpRunner",
|
|
37648
|
+
`squad: handoff proposed ${opts.agent} \u2192 ${record2.toAgentId}${auto ? " (auto)" : ""}`
|
|
37649
|
+
);
|
|
37219
37650
|
void postSquadEvent("handoff_proposed", { ...record2 });
|
|
37651
|
+
if (!auto) {
|
|
37652
|
+
pendingProposal.current = record2;
|
|
37653
|
+
return null;
|
|
37654
|
+
}
|
|
37655
|
+
return record2;
|
|
37656
|
+
}
|
|
37657
|
+
function resolveAutoHandoff(ctx, record2) {
|
|
37658
|
+
ctx.squad?.countAccepted();
|
|
37659
|
+
const resolution = {
|
|
37660
|
+
proposalId: record2.proposalId,
|
|
37661
|
+
accepted: true,
|
|
37662
|
+
auto: true
|
|
37663
|
+
};
|
|
37664
|
+
void ctx.postSquadEvent?.("handoff_resolved", { ...resolution });
|
|
37665
|
+
}
|
|
37666
|
+
async function runCoderabbitMention(ctx, promptText) {
|
|
37667
|
+
const { cmd, relay, streaming, opts, turnFiles } = ctx;
|
|
37668
|
+
const userText = promptText.length > 0 ? promptText : `@${CODERABBIT_AGENT_ID}`;
|
|
37669
|
+
await streaming.beginTurn();
|
|
37670
|
+
ctx.history.appendUserPrompt(userText);
|
|
37671
|
+
log.info("acpRunner", `squad: coderabbit one-shot review id=${cmd.id.slice(0, 8)}`);
|
|
37672
|
+
const review = await runCoderabbitMentionReview({
|
|
37673
|
+
fetchCredential: () => fetchProvisionCredential({
|
|
37674
|
+
agentId: CODERABBIT_AGENT_ID,
|
|
37675
|
+
sessionId: opts.sessionId,
|
|
37676
|
+
pluginId: opts.pluginId,
|
|
37677
|
+
pluginAuthToken: opts.pluginAuthToken
|
|
37678
|
+
})
|
|
37679
|
+
});
|
|
37680
|
+
logMentionOutcome(review);
|
|
37681
|
+
if (!review.ok) {
|
|
37682
|
+
await streaming.closeWithBubble(review.error);
|
|
37683
|
+
ctx.history.appendAgentReply(review.error, CODERABBIT_AGENT_ID);
|
|
37684
|
+
void ctx.history.flush();
|
|
37685
|
+
await relay.sendResult(cmd.id, "failed", { error: review.error });
|
|
37686
|
+
return;
|
|
37687
|
+
}
|
|
37688
|
+
const output = composeReviewOutput(review.markdown, hasCustomInstructions(promptText));
|
|
37689
|
+
await streaming.closeWithBubble(output);
|
|
37690
|
+
ctx.history.appendAgentReply(output, CODERABBIT_AGENT_ID);
|
|
37691
|
+
void ctx.history.flush();
|
|
37692
|
+
await turnFiles.flushTurn().catch((err) => {
|
|
37693
|
+
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
37694
|
+
});
|
|
37695
|
+
recordCoderabbitTurn(ctx, userText, output);
|
|
37696
|
+
await relay.sendResult(cmd.id, "completed", { agentId: CODERABBIT_AGENT_ID });
|
|
37697
|
+
}
|
|
37698
|
+
function recordCoderabbitTurn(ctx, prompt, replySummary) {
|
|
37699
|
+
ctx.squad?.recordTurn({
|
|
37700
|
+
agentId: CODERABBIT_AGENT_ID,
|
|
37701
|
+
prompt,
|
|
37702
|
+
replySummary,
|
|
37703
|
+
filesTouched: []
|
|
37704
|
+
});
|
|
37220
37705
|
}
|
|
37221
37706
|
async function startTaskH(ctx) {
|
|
37222
37707
|
const { cmd, relay, streaming, opts, turnFiles, publisher, recentStderr, budgetReachedFlag } = ctx;
|
|
37223
37708
|
const payload = cmd.payload;
|
|
37709
|
+
const requestedAgentId = typeof payload?.agentId === "string" ? payload.agentId.trim() : "";
|
|
37710
|
+
resolvePendingProposal(ctx, requestedAgentId);
|
|
37711
|
+
if (requestedAgentId === CODERABBIT_AGENT_ID) {
|
|
37712
|
+
await runCoderabbitMention(ctx, (payload?.prompt ?? "").trim());
|
|
37713
|
+
return;
|
|
37714
|
+
}
|
|
37224
37715
|
const blocks = buildAcpPromptBlocks(payload ?? {});
|
|
37225
37716
|
if (blocks.length === 0) {
|
|
37226
37717
|
log.warn("acpRunner", "start_task with empty prompt + no attachments; ignoring");
|
|
37227
37718
|
await relay.sendResult(cmd.id, "failed", { error: "empty prompt" });
|
|
37228
37719
|
return;
|
|
37229
37720
|
}
|
|
37230
|
-
const requestedAgentId = typeof payload?.agentId === "string" ? payload.agentId.trim() : "";
|
|
37231
|
-
resolvePendingProposal(ctx, requestedAgentId);
|
|
37232
37721
|
if (requestedAgentId.length > 0 && requestedAgentId !== opts.agent) {
|
|
37233
37722
|
const routed = await routeSquadTask(ctx, requestedAgentId);
|
|
37234
37723
|
if (!routed.ok) {
|
|
@@ -37237,7 +37726,6 @@ async function startTaskH(ctx) {
|
|
|
37237
37726
|
return;
|
|
37238
37727
|
}
|
|
37239
37728
|
}
|
|
37240
|
-
const { client: client3, history, budgetRecovery } = ctx;
|
|
37241
37729
|
const promptText = blocks.filter((b) => b.type === "text").map((b) => b.text).join("\n");
|
|
37242
37730
|
const imageCount = blocks.filter((b) => b.type === "image").length;
|
|
37243
37731
|
log.info(
|
|
@@ -37249,133 +37737,214 @@ async function startTaskH(ctx) {
|
|
|
37249
37737
|
showInfo(echoLine);
|
|
37250
37738
|
}
|
|
37251
37739
|
await streaming.beginTurn();
|
|
37252
|
-
history.appendUserPrompt(promptText);
|
|
37740
|
+
ctx.history.appendUserPrompt(promptText);
|
|
37253
37741
|
maybePrefaceAgentStandard(blocks, opts.agent, opts.sessionId);
|
|
37254
|
-
|
|
37255
|
-
|
|
37256
|
-
|
|
37257
|
-
|
|
37258
|
-
|
|
37259
|
-
|
|
37260
|
-
|
|
37261
|
-
|
|
37262
|
-
|
|
37263
|
-
|
|
37264
|
-
|
|
37265
|
-
await
|
|
37266
|
-
|
|
37267
|
-
|
|
37268
|
-
|
|
37269
|
-
|
|
37270
|
-
|
|
37271
|
-
|
|
37272
|
-
|
|
37273
|
-
|
|
37274
|
-
|
|
37275
|
-
|
|
37276
|
-
|
|
37277
|
-
|
|
37278
|
-
|
|
37279
|
-
|
|
37280
|
-
|
|
37281
|
-
|
|
37282
|
-
|
|
37283
|
-
|
|
37284
|
-
|
|
37285
|
-
|
|
37286
|
-
|
|
37287
|
-
|
|
37288
|
-
|
|
37289
|
-
|
|
37290
|
-
|
|
37291
|
-
|
|
37292
|
-
|
|
37293
|
-
|
|
37294
|
-
|
|
37295
|
-
|
|
37296
|
-
|
|
37297
|
-
|
|
37298
|
-
|
|
37299
|
-
|
|
37300
|
-
|
|
37301
|
-
|
|
37302
|
-
|
|
37303
|
-
|
|
37304
|
-
|
|
37305
|
-
|
|
37306
|
-
|
|
37307
|
-
|
|
37308
|
-
|
|
37309
|
-
|
|
37310
|
-
|
|
37311
|
-
|
|
37312
|
-
|
|
37313
|
-
|
|
37314
|
-
|
|
37315
|
-
|
|
37316
|
-
|
|
37317
|
-
|
|
37318
|
-
|
|
37319
|
-
|
|
37320
|
-
|
|
37321
|
-
|
|
37322
|
-
|
|
37323
|
-
|
|
37324
|
-
|
|
37325
|
-
|
|
37326
|
-
|
|
37327
|
-
|
|
37328
|
-
|
|
37329
|
-
|
|
37330
|
-
|
|
37331
|
-
if (turnClosed) {
|
|
37332
|
-
log.warn(
|
|
37333
|
-
"acpRunner",
|
|
37334
|
-
`post-close ack failed (turn already delivered) id=${cmd.id.slice(0, 8)}: ${describeError(err)}`
|
|
37335
|
-
);
|
|
37336
|
-
return;
|
|
37337
|
-
}
|
|
37338
|
-
const hadText = streaming.hasVisibleProgress();
|
|
37339
|
-
const detail = describeError(err);
|
|
37340
|
-
log.warn("acpRunner", `prompt failed: ${detail}`);
|
|
37341
|
-
await cancelStuckTurn(client3);
|
|
37342
|
-
if (looksLikeBudgetExceeded(`${detail}
|
|
37343
|
-
${recentStderr.join("\n")}`)) {
|
|
37344
|
-
await streaming.closeAll();
|
|
37345
|
-
if (!budgetReachedFlag.get()) {
|
|
37346
|
-
budgetReachedFlag.set(true);
|
|
37347
|
-
void postBudgetReached({
|
|
37348
|
-
sessionId: opts.sessionId,
|
|
37349
|
-
pluginId: opts.pluginId,
|
|
37350
|
-
pluginAuthToken: opts.pluginAuthToken,
|
|
37351
|
-
agent: opts.agent,
|
|
37352
|
-
period: extractBudgetPeriod(`${detail}
|
|
37353
|
-
${recentStderr.join("\n")}`)
|
|
37742
|
+
const squadContext = collectSquadContext(ctx);
|
|
37743
|
+
applySquadContext(blocks, squadContext, squadContextMode(ctx));
|
|
37744
|
+
ctx.squad?.resetHops();
|
|
37745
|
+
let turnBlocks = blocks;
|
|
37746
|
+
let turnPieces = squadContext;
|
|
37747
|
+
let turnPrompt = promptText;
|
|
37748
|
+
let hop = 1;
|
|
37749
|
+
for (; ; ) {
|
|
37750
|
+
const { client: client3, history, budgetRecovery } = ctx;
|
|
37751
|
+
let turnClosed = false;
|
|
37752
|
+
try {
|
|
37753
|
+
const reply = await promptWithContextFallback(ctx, client3, turnBlocks, turnPieces);
|
|
37754
|
+
const finalText = streaming.getCurrentText();
|
|
37755
|
+
if (agentHooks(opts.agent)?.classifyCompletedReply?.(finalText) === "upgrade_required") {
|
|
37756
|
+
await streaming.closeWithBubble(CURSOR_UPGRADE_MESSAGE);
|
|
37757
|
+
turnClosed = true;
|
|
37758
|
+
history.appendAgentReply(CURSOR_UPGRADE_MESSAGE);
|
|
37759
|
+
void history.flush();
|
|
37760
|
+
log.info("acpRunner", `start_task \u2190 cursor-plan-upgrade-required id=${cmd.id.slice(0, 8)}`);
|
|
37761
|
+
await relay.sendResult(cmd.id, "failed", { error: "cursor plan upgrade required" });
|
|
37762
|
+
return;
|
|
37763
|
+
} else if (replyIsHouseAgentLimit(finalText)) {
|
|
37764
|
+
const houseBubble = houseAgentLimitMessage(finalText);
|
|
37765
|
+
await streaming.closeWithBubble(houseBubble);
|
|
37766
|
+
turnClosed = true;
|
|
37767
|
+
history.appendAgentReply(houseBubble);
|
|
37768
|
+
void history.flush();
|
|
37769
|
+
turnFiles.flushTurn().catch((err) => {
|
|
37770
|
+
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
37771
|
+
});
|
|
37772
|
+
log.info("acpRunner", `start_task \u2190 house-agent-limit id=${cmd.id.slice(0, 8)}`);
|
|
37773
|
+
await relay.sendResult(cmd.id, "failed", {
|
|
37774
|
+
error: "house agent usage ceiling / temporarily unavailable"
|
|
37775
|
+
});
|
|
37776
|
+
return;
|
|
37777
|
+
} else if (replyIsAuthFailure(finalText)) {
|
|
37778
|
+
await streaming.closeWithBubble(AUTH_FAILURE_MESSAGE);
|
|
37779
|
+
turnClosed = true;
|
|
37780
|
+
history.appendAgentReply(AUTH_FAILURE_MESSAGE);
|
|
37781
|
+
void history.flush();
|
|
37782
|
+
turnFiles.flushTurn().catch((err) => {
|
|
37783
|
+
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
37784
|
+
});
|
|
37785
|
+
void reportCredentialInvalid(opts);
|
|
37786
|
+
log.info("acpRunner", `start_task \u2190 auth-failure-in-reply id=${cmd.id.slice(0, 8)}`);
|
|
37787
|
+
await relay.sendResult(cmd.id, "failed", { error: "agent reply reported auth failure" });
|
|
37788
|
+
return;
|
|
37789
|
+
} else if (shouldOfferOneMRecovery({ detail: "", recentStderr: recentStderr.join("\n"), finalText })) {
|
|
37790
|
+
await streaming.closeWithBubble(ONE_M_CREDITS_MESSAGE);
|
|
37791
|
+
turnClosed = true;
|
|
37792
|
+
history.appendAgentReply(ONE_M_CREDITS_MESSAGE);
|
|
37793
|
+
void history.flush();
|
|
37794
|
+
turnFiles.flushTurn().catch((err) => {
|
|
37795
|
+
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
37796
|
+
});
|
|
37797
|
+
void reportCredentialInvalid(opts);
|
|
37798
|
+
log.info("acpRunner", `start_task \u2190 1m-credits-reconnect id=${cmd.id.slice(0, 8)}`);
|
|
37799
|
+
await relay.sendResult(cmd.id, "failed", {
|
|
37800
|
+
error: "agent reply reported 1M-context usage-credits gate"
|
|
37801
|
+
});
|
|
37802
|
+
return;
|
|
37803
|
+
} else {
|
|
37804
|
+
await streaming.closeTurnWithInteractiveDetection();
|
|
37805
|
+
turnClosed = true;
|
|
37806
|
+
const { cleanText, proposal } = extractHandoffProposal(
|
|
37807
|
+
finalText,
|
|
37808
|
+
opts.agent,
|
|
37809
|
+
handoffTargets(ctx)
|
|
37810
|
+
);
|
|
37811
|
+
const replyLine = formatAgentReplyLine(cleanText);
|
|
37812
|
+
if (replyLine.length > 0) {
|
|
37813
|
+
showInfo(replyLine);
|
|
37814
|
+
}
|
|
37815
|
+
history.appendAgentReply(cleanText);
|
|
37816
|
+
void history.flush();
|
|
37817
|
+
const flush = turnFiles.flushTurn().catch((err) => {
|
|
37818
|
+
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
37354
37819
|
});
|
|
37820
|
+
if (ctx.squad) await flush;
|
|
37821
|
+
recordSquadTurn(ctx, turnPrompt, cleanText);
|
|
37822
|
+
const autoHop = emitHandoffProposal(ctx, proposal, hop);
|
|
37823
|
+
if (autoHop) {
|
|
37824
|
+
const routed = await routeSquadTask(ctx, autoHop.toAgentId);
|
|
37825
|
+
if (routed.ok) {
|
|
37826
|
+
resolveAutoHandoff(ctx, autoHop);
|
|
37827
|
+
hop += 1;
|
|
37828
|
+
turnPrompt = autoHop.prompt;
|
|
37829
|
+
turnPieces = collectSquadContext(ctx);
|
|
37830
|
+
turnBlocks = [{ type: "text", text: turnPrompt }];
|
|
37831
|
+
maybePrefaceAgentStandard(turnBlocks, opts.agent, opts.sessionId);
|
|
37832
|
+
applySquadContext(turnBlocks, turnPieces, squadContextMode(ctx));
|
|
37833
|
+
await streaming.beginTurn();
|
|
37834
|
+
ctx.history.appendUserPrompt(turnPrompt);
|
|
37835
|
+
continue;
|
|
37836
|
+
}
|
|
37837
|
+
log.warn(
|
|
37838
|
+
"acpRunner",
|
|
37839
|
+
`squad: auto-handoff to ${autoHop.toAgentId} failed: ${routed.error}`
|
|
37840
|
+
);
|
|
37841
|
+
}
|
|
37842
|
+
void publisher.publishOutput({
|
|
37843
|
+
type: "input_suggestion",
|
|
37844
|
+
content: ACP_QUICK_REPLIES,
|
|
37845
|
+
done: true
|
|
37846
|
+
});
|
|
37847
|
+
log.info(
|
|
37848
|
+
"acpRunner",
|
|
37849
|
+
`start_task \u2190 done stopReason=${reply.stopReason ?? "?"} id=${cmd.id.slice(0, 8)}`
|
|
37850
|
+
);
|
|
37851
|
+
await relay.sendResult(cmd.id, "completed", { stopReason: reply.stopReason });
|
|
37852
|
+
return;
|
|
37853
|
+
}
|
|
37854
|
+
} catch (err) {
|
|
37855
|
+
if (turnClosed) {
|
|
37856
|
+
log.warn(
|
|
37857
|
+
"acpRunner",
|
|
37858
|
+
`post-close ack failed (turn already delivered) id=${cmd.id.slice(0, 8)}: ${describeError(err)}`
|
|
37859
|
+
);
|
|
37860
|
+
return;
|
|
37355
37861
|
}
|
|
37356
|
-
|
|
37862
|
+
const hadText = streaming.hasVisibleProgress();
|
|
37863
|
+
const detail = describeError(err);
|
|
37864
|
+
log.warn("acpRunner", `prompt failed: ${detail}`);
|
|
37865
|
+
await cancelStuckTurn(client3);
|
|
37866
|
+
if (looksLikeBudgetExceeded(`${detail}
|
|
37867
|
+
${recentStderr.join("\n")}`)) {
|
|
37868
|
+
await streaming.closeAll();
|
|
37869
|
+
if (!budgetReachedFlag.get()) {
|
|
37870
|
+
budgetReachedFlag.set(true);
|
|
37871
|
+
void postBudgetReached({
|
|
37872
|
+
sessionId: opts.sessionId,
|
|
37873
|
+
pluginId: opts.pluginId,
|
|
37874
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
37875
|
+
agent: opts.agent,
|
|
37876
|
+
period: extractBudgetPeriod(`${detail}
|
|
37877
|
+
${recentStderr.join("\n")}`)
|
|
37878
|
+
});
|
|
37879
|
+
}
|
|
37880
|
+
await budgetRecovery.offer(cmd.id, turnBlocks, `${detail}
|
|
37357
37881
|
${recentStderr.join("\n")}`);
|
|
37882
|
+
return;
|
|
37883
|
+
}
|
|
37884
|
+
const bubble = failureBubble({
|
|
37885
|
+
detail,
|
|
37886
|
+
recentStderr: recentStderr.join("\n"),
|
|
37887
|
+
hadText,
|
|
37888
|
+
agent: opts.agent
|
|
37889
|
+
});
|
|
37890
|
+
if (bubble) {
|
|
37891
|
+
await streaming.closeWithBubble(bubble);
|
|
37892
|
+
history.appendAgentReply(bubble);
|
|
37893
|
+
void history.flush();
|
|
37894
|
+
} else {
|
|
37895
|
+
await streaming.closeAll();
|
|
37896
|
+
}
|
|
37897
|
+
if (bubble === AUTH_FAILURE_MESSAGE || bubble === ONE_M_CREDITS_MESSAGE) {
|
|
37898
|
+
void reportCredentialInvalid(opts);
|
|
37899
|
+
}
|
|
37900
|
+
await relay.sendResult(cmd.id, "failed", { error: detail });
|
|
37358
37901
|
return;
|
|
37359
37902
|
}
|
|
37360
|
-
|
|
37361
|
-
|
|
37362
|
-
|
|
37363
|
-
|
|
37364
|
-
|
|
37903
|
+
}
|
|
37904
|
+
}
|
|
37905
|
+
async function squadConfigureH(ctx) {
|
|
37906
|
+
const { cmd, relay, opts, squad } = ctx;
|
|
37907
|
+
if (!squad) {
|
|
37908
|
+
await relay.sendResult(cmd.id, "failed", {
|
|
37909
|
+
error: "Agent Squad is not available on this session."
|
|
37365
37910
|
});
|
|
37366
|
-
|
|
37367
|
-
await streaming.closeWithBubble(bubble);
|
|
37368
|
-
history.appendAgentReply(bubble);
|
|
37369
|
-
void history.flush();
|
|
37370
|
-
} else {
|
|
37371
|
-
await streaming.closeAll();
|
|
37372
|
-
}
|
|
37373
|
-
if (bubble === AUTH_FAILURE_MESSAGE || bubble === ONE_M_CREDITS_MESSAGE) {
|
|
37374
|
-
void reportCredentialInvalid(opts);
|
|
37375
|
-
}
|
|
37376
|
-
await relay.sendResult(cmd.id, "failed", { error: detail });
|
|
37911
|
+
return;
|
|
37377
37912
|
}
|
|
37378
|
-
|
|
37913
|
+
const payload = cmd.payload;
|
|
37914
|
+
if (payload?.action === "set") {
|
|
37915
|
+
const applied = squad.setAuto({
|
|
37916
|
+
enabled: payload.autoHandoffs === true,
|
|
37917
|
+
hopBudget: clampHopBudget(payload.hopBudget)
|
|
37918
|
+
});
|
|
37919
|
+
setSquadAuto(opts.pluginId, applied);
|
|
37920
|
+
log.info(
|
|
37921
|
+
"acpRunner",
|
|
37922
|
+
`squad: auto handoffs ${applied.enabled ? "ON" : "OFF"} budget=${applied.hopBudget}`
|
|
37923
|
+
);
|
|
37924
|
+
const result = { ...applied, hopsRemaining: squad.hopsRemaining() };
|
|
37925
|
+
await relay.sendResult(cmd.id, "completed", { ...result });
|
|
37926
|
+
return;
|
|
37927
|
+
}
|
|
37928
|
+
if (payload?.action === "status") {
|
|
37929
|
+
const result = {
|
|
37930
|
+
...squad.auto,
|
|
37931
|
+
hopsRemaining: squad.hopsRemaining()
|
|
37932
|
+
};
|
|
37933
|
+
await relay.sendResult(cmd.id, "completed", { ...result });
|
|
37934
|
+
return;
|
|
37935
|
+
}
|
|
37936
|
+
await relay.sendResult(cmd.id, "failed", { error: "squad_configure: unknown action" });
|
|
37937
|
+
}
|
|
37938
|
+
async function squadStatsH(ctx) {
|
|
37939
|
+
const { cmd, relay, squad } = ctx;
|
|
37940
|
+
if (!squad) {
|
|
37941
|
+
await relay.sendResult(cmd.id, "failed", {
|
|
37942
|
+
error: "Agent Squad is not available on this session."
|
|
37943
|
+
});
|
|
37944
|
+
return;
|
|
37945
|
+
}
|
|
37946
|
+
const stats = squad.stats();
|
|
37947
|
+
await relay.sendResult(cmd.id, "completed", { ...stats });
|
|
37379
37948
|
}
|
|
37380
37949
|
async function groupMentionTaskH(ctx) {
|
|
37381
37950
|
const { cmd, client: client3, relay, streaming, opts, history } = ctx;
|
|
@@ -37388,6 +37957,7 @@ async function groupMentionTaskH(ctx) {
|
|
|
37388
37957
|
});
|
|
37389
37958
|
return;
|
|
37390
37959
|
}
|
|
37960
|
+
ctx.squad?.resetHops();
|
|
37391
37961
|
await streaming.beginTurn();
|
|
37392
37962
|
history.appendUserPrompt(promptText);
|
|
37393
37963
|
let response = "";
|
|
@@ -37782,7 +38352,10 @@ async function integrationsSyncH(ctx) {
|
|
|
37782
38352
|
attached: manifest.integrations.map((e) => e.id)
|
|
37783
38353
|
});
|
|
37784
38354
|
} catch (err) {
|
|
37785
|
-
log.warn(
|
|
38355
|
+
log.warn(
|
|
38356
|
+
"acpRunner",
|
|
38357
|
+
`integrations_sync failed (tools apply next restart): ${describeError(err)}`
|
|
38358
|
+
);
|
|
37786
38359
|
await relay.sendResult(cmd.id, "completed", { synced: false, error: describeError(err) });
|
|
37787
38360
|
}
|
|
37788
38361
|
}
|
|
@@ -37852,7 +38425,9 @@ var ACP_COMMAND_HANDLERS = {
|
|
|
37852
38425
|
skills_configure: skillsConfigureH2,
|
|
37853
38426
|
pack_start: packStartH,
|
|
37854
38427
|
pack_action: packActionH,
|
|
37855
|
-
pack_status: packStatusH
|
|
38428
|
+
pack_status: packStatusH,
|
|
38429
|
+
[SQUAD_CONFIGURE_COMMAND]: squadConfigureH,
|
|
38430
|
+
[SQUAD_STATS_COMMAND]: squadStatsH
|
|
37856
38431
|
};
|
|
37857
38432
|
async function dispatchAcpCommand(ctx) {
|
|
37858
38433
|
const handler = ACP_COMMAND_HANDLERS[ctx.cmd.type];
|
|
@@ -38117,7 +38692,7 @@ var StreamingState = class {
|
|
|
38117
38692
|
let fenceCut = -1;
|
|
38118
38693
|
if (delta.kind === "text") {
|
|
38119
38694
|
this.recomputeText();
|
|
38120
|
-
fenceCut =
|
|
38695
|
+
fenceCut = handoffFenceStartMasked(this.text);
|
|
38121
38696
|
const visibleText = fenceCut === -1 ? this.text : this.text.slice(0, fenceCut).trimEnd();
|
|
38122
38697
|
void this.publisher.publishOutput({ type: "text", content: visibleText, done: false });
|
|
38123
38698
|
}
|
|
@@ -38165,11 +38740,12 @@ var StreamingState = class {
|
|
|
38165
38740
|
* {@link getCurrentText} keeps returning the RAW text so the turn-close
|
|
38166
38741
|
* extraction can parse the proposal out of it.
|
|
38167
38742
|
*
|
|
38168
|
-
* Masked-aware (`stripHandoffFences`),
|
|
38169
|
-
* cut (`
|
|
38743
|
+
* Masked-aware (`stripHandoffFences`), same as the live-stream `append()`
|
|
38744
|
+
* cut (`handoffFenceStartMasked`): a TERMINAL frame is the one that
|
|
38170
38745
|
* PERSISTS, so cutting on a fence quoted as an example inside a
|
|
38171
|
-
* 4+-backtick block here would permanently truncate the bubble
|
|
38172
|
-
* cut
|
|
38746
|
+
* 4+-backtick block here would permanently truncate the bubble — and an
|
|
38747
|
+
* unmasked live cut would truncate the LIVE view for the rest of the turn
|
|
38748
|
+
* the moment the quoted example's fence-open marker streams in.
|
|
38173
38749
|
*/
|
|
38174
38750
|
visible(text) {
|
|
38175
38751
|
return stripHandoffFences(text);
|
|
@@ -38345,16 +38921,24 @@ var AcpHistory = class {
|
|
|
38345
38921
|
id: (0, import_node_crypto11.randomUUID)(),
|
|
38346
38922
|
role: "user",
|
|
38347
38923
|
text,
|
|
38348
|
-
timestamp: Date.now()
|
|
38924
|
+
timestamp: Date.now(),
|
|
38925
|
+
agentId: this.opts.agent
|
|
38349
38926
|
});
|
|
38350
38927
|
}
|
|
38351
|
-
|
|
38928
|
+
/**
|
|
38929
|
+
* `agentId` overrides the producing agent for a turn this session's RESIDENT
|
|
38930
|
+
* agent did not author — today only the `@coderabbit` one-shot review, which
|
|
38931
|
+
* runs the batch reviewer inside the session without ever swapping. Defaults
|
|
38932
|
+
* to the resident agent.
|
|
38933
|
+
*/
|
|
38934
|
+
appendAgentReply(text, agentId = this.opts.agent) {
|
|
38352
38935
|
if (text.length === 0) return;
|
|
38353
38936
|
this.messages.push({
|
|
38354
38937
|
id: (0, import_node_crypto11.randomUUID)(),
|
|
38355
38938
|
role: "agent",
|
|
38356
38939
|
text,
|
|
38357
|
-
timestamp: Date.now()
|
|
38940
|
+
timestamp: Date.now(),
|
|
38941
|
+
agentId
|
|
38358
38942
|
});
|
|
38359
38943
|
}
|
|
38360
38944
|
/**
|
|
@@ -38694,6 +39278,8 @@ async function runAcpSession(opts) {
|
|
|
38694
39278
|
pluginAuthToken: opts.pluginAuthToken,
|
|
38695
39279
|
agentId: opts.agent
|
|
38696
39280
|
});
|
|
39281
|
+
void turnFiles.flushTurn().catch(() => {
|
|
39282
|
+
});
|
|
38697
39283
|
const REPO_DIRTY_FLUSH_DEBOUNCE_MS = 2e3;
|
|
38698
39284
|
let repoDirtyTimer = null;
|
|
38699
39285
|
const fileWatcher = new FileWatcherService({
|
|
@@ -38739,9 +39325,12 @@ async function runAcpSession(opts) {
|
|
|
38739
39325
|
publisher,
|
|
38740
39326
|
recentStderr,
|
|
38741
39327
|
budgetRecovery,
|
|
38742
|
-
{
|
|
38743
|
-
|
|
38744
|
-
|
|
39328
|
+
{
|
|
39329
|
+
get: () => _budgetReachedPosted,
|
|
39330
|
+
set: (v) => {
|
|
39331
|
+
_budgetReachedPosted = v;
|
|
39332
|
+
}
|
|
39333
|
+
},
|
|
38745
39334
|
// resume_session re-points the runner's active conversation: the
|
|
38746
39335
|
// relay callback reads `acpSessionId` per command, so every FUTURE
|
|
38747
39336
|
// get_conversation / upload / one-shot serves the RESUMED id — not
|
|
@@ -38765,7 +39354,10 @@ async function runAcpSession(opts) {
|
|
|
38765
39354
|
);
|
|
38766
39355
|
const HANDOFF_MAX_CHARS = 16e3;
|
|
38767
39356
|
const pendingHandoff = { current: null };
|
|
38768
|
-
const squad = new SquadState({
|
|
39357
|
+
const squad = new SquadState({
|
|
39358
|
+
sessionId: opts.sessionId,
|
|
39359
|
+
auto: getSquadAuto(opts.pluginId)
|
|
39360
|
+
});
|
|
38769
39361
|
const refreshSquadRoster = () => {
|
|
38770
39362
|
void fetchSquadRoster({
|
|
38771
39363
|
sessionId: opts.sessionId,
|
|
@@ -38849,7 +39441,7 @@ async function runAcpSession(opts) {
|
|
|
38849
39441
|
provisionCredential: (agentId, auth) => {
|
|
38850
39442
|
switchCredentialEnv = provisionAgentCredentials(agentId, auth);
|
|
38851
39443
|
},
|
|
38852
|
-
ensureBinary: (agentId, installScript) => ensureAgentBinaryForSwitch(agentId, installScript),
|
|
39444
|
+
ensureBinary: (agentId, installScript, onRetry) => ensureAgentBinaryForSwitch(agentId, installScript, { onRetry }),
|
|
38853
39445
|
swapRuntime: relaunchWith,
|
|
38854
39446
|
revertRuntime: relaunchWith,
|
|
38855
39447
|
persistAgent: (agentId) => setSessionAgent(opts.pluginId, agentId),
|
|
@@ -43765,7 +44357,7 @@ function checkChokidar() {
|
|
|
43765
44357
|
}
|
|
43766
44358
|
async function doctor(args2 = []) {
|
|
43767
44359
|
const json = args2.includes("--json");
|
|
43768
|
-
const cliVersion = true ? "2.
|
|
44360
|
+
const cliVersion = true ? "2.65.1" : "0.0.0-dev";
|
|
43769
44361
|
const apiBase2 = resolveApiBaseUrl();
|
|
43770
44362
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
43771
44363
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -44156,7 +44748,7 @@ async function mcpRun(args2) {
|
|
|
44156
44748
|
// src/commands/version.ts
|
|
44157
44749
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
44158
44750
|
function version2() {
|
|
44159
|
-
const v = true ? "2.
|
|
44751
|
+
const v = true ? "2.65.1" : "unknown";
|
|
44160
44752
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
44161
44753
|
}
|
|
44162
44754
|
|