codeam-cli 2.63.0 → 2.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.js +721 -286
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2789,6 +2789,17 @@ function resolveApiBaseUrl() {
|
|
|
2789
2789
|
return DEFAULT_API_BASE_URL;
|
|
2790
2790
|
}
|
|
2791
2791
|
|
|
2792
|
+
// ../../packages/shared/src/types/agent-squad.ts
|
|
2793
|
+
var HANDOFF_FENCE_TAG = "codeam-handoff";
|
|
2794
|
+
var SQUAD_SPECIALTIES = {
|
|
2795
|
+
claude: "deep reasoning, refactors, and multi-step architecture work",
|
|
2796
|
+
codex: "fast, focused implementation and test fixing",
|
|
2797
|
+
cursor: "multi-file edits and codebase-wide changes",
|
|
2798
|
+
gemini: "large-context analysis across big files and logs",
|
|
2799
|
+
kimi: "long-context code reading and summarization",
|
|
2800
|
+
opencode: "general implementation tasks"
|
|
2801
|
+
};
|
|
2802
|
+
|
|
2792
2803
|
// ../../packages/shared/src/headroom/manifest.ts
|
|
2793
2804
|
var HEADROOM_PROXY_PORT = 8787;
|
|
2794
2805
|
var HEADROOM_PIP_COMPANIONS = [
|
|
@@ -2921,6 +2932,9 @@ var USER_EVENTS = {
|
|
|
2921
2932
|
// the backend re-publishes them on the per-user SSE bus (mirrored in repo A).
|
|
2922
2933
|
SWITCH_AGENT_PROGRESS: "switch_agent_progress",
|
|
2923
2934
|
SWITCH_AGENT_STATUS: "switch_agent_status",
|
|
2935
|
+
// Agent Squad — the CLI posts these to /api/agent-switch/events; PRO-gated.
|
|
2936
|
+
HANDOFF_PROPOSED: "handoff_proposed",
|
|
2937
|
+
HANDOFF_RESOLVED: "handoff_resolved",
|
|
2924
2938
|
// VCS / PR Command Center — the backend publishes this after an agent finishes
|
|
2925
2939
|
// reviewing a PR (verdict + comment count + findings), driving the mobile
|
|
2926
2940
|
// completion screen + push. Mirrored in repo A's app-shared events.ts.
|
|
@@ -3125,11 +3139,11 @@ function quiet(fn) {
|
|
|
3125
3139
|
log.debug(TAG, "ignored sync error", err);
|
|
3126
3140
|
}
|
|
3127
3141
|
}
|
|
3128
|
-
function rmIfExistsQuiet(
|
|
3142
|
+
function rmIfExistsQuiet(path91) {
|
|
3129
3143
|
try {
|
|
3130
|
-
fs2.rmSync(
|
|
3144
|
+
fs2.rmSync(path91, { force: true });
|
|
3131
3145
|
} catch (err) {
|
|
3132
|
-
log.debug(TAG, `rmIfExists failed for ${
|
|
3146
|
+
log.debug(TAG, `rmIfExists failed for ${path91}`, err);
|
|
3133
3147
|
}
|
|
3134
3148
|
}
|
|
3135
3149
|
function killQuiet(target, signal = "SIGTERM") {
|
|
@@ -3320,8 +3334,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
3320
3334
|
return decodedFile;
|
|
3321
3335
|
};
|
|
3322
3336
|
}
|
|
3323
|
-
function normalizeWindowsPath(
|
|
3324
|
-
return
|
|
3337
|
+
function normalizeWindowsPath(path91) {
|
|
3338
|
+
return path91.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
3325
3339
|
}
|
|
3326
3340
|
|
|
3327
3341
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -5801,9 +5815,9 @@ async function addSourceContext(frames) {
|
|
|
5801
5815
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
5802
5816
|
return frames;
|
|
5803
5817
|
}
|
|
5804
|
-
function getContextLinesFromFile(
|
|
5818
|
+
function getContextLinesFromFile(path91, ranges, output) {
|
|
5805
5819
|
return new Promise((resolve9) => {
|
|
5806
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
5820
|
+
const stream = (0, import_node_fs.createReadStream)(path91);
|
|
5807
5821
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
5808
5822
|
input: stream
|
|
5809
5823
|
});
|
|
@@ -5818,7 +5832,7 @@ function getContextLinesFromFile(path90, ranges, output) {
|
|
|
5818
5832
|
let rangeStart = range[0];
|
|
5819
5833
|
let rangeEnd = range[1];
|
|
5820
5834
|
function onStreamError() {
|
|
5821
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
5835
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path91, 1);
|
|
5822
5836
|
lineReaded.close();
|
|
5823
5837
|
lineReaded.removeAllListeners();
|
|
5824
5838
|
destroyStreamAndResolve();
|
|
@@ -5879,8 +5893,8 @@ function clearLineContext(frame) {
|
|
|
5879
5893
|
delete frame.context_line;
|
|
5880
5894
|
delete frame.post_context;
|
|
5881
5895
|
}
|
|
5882
|
-
function shouldSkipContextLinesForFile(
|
|
5883
|
-
return
|
|
5896
|
+
function shouldSkipContextLinesForFile(path91) {
|
|
5897
|
+
return path91.startsWith("node:") || path91.endsWith(".min.js") || path91.endsWith(".min.cjs") || path91.endsWith(".min.mjs") || path91.startsWith("data:");
|
|
5884
5898
|
}
|
|
5885
5899
|
function shouldSkipContextLinesForFrame(frame) {
|
|
5886
5900
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -8034,7 +8048,7 @@ function readAnonId() {
|
|
|
8034
8048
|
}
|
|
8035
8049
|
function superProperties() {
|
|
8036
8050
|
return {
|
|
8037
|
-
cliVersion: true ? "2.
|
|
8051
|
+
cliVersion: true ? "2.64.0" : "0.0.0-dev",
|
|
8038
8052
|
nodeVersion: process.version,
|
|
8039
8053
|
platform: process.platform,
|
|
8040
8054
|
arch: process.arch,
|
|
@@ -8215,7 +8229,7 @@ var os4 = __toESM(require("os"));
|
|
|
8215
8229
|
// package.json
|
|
8216
8230
|
var package_default = {
|
|
8217
8231
|
name: "codeam-cli",
|
|
8218
|
-
version: "2.
|
|
8232
|
+
version: "2.64.0",
|
|
8219
8233
|
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.",
|
|
8220
8234
|
type: "commonjs",
|
|
8221
8235
|
main: "dist/index.js",
|
|
@@ -8611,6 +8625,20 @@ async function fetchProvisionCredential(input) {
|
|
|
8611
8625
|
return null;
|
|
8612
8626
|
}
|
|
8613
8627
|
}
|
|
8628
|
+
async function fetchSquadRoster(input) {
|
|
8629
|
+
try {
|
|
8630
|
+
const res = await _transport.postJsonAuthed(
|
|
8631
|
+
`${API_BASE}/api/plugin/agents/roster`,
|
|
8632
|
+
{ sessionId: input.sessionId, pluginId: input.pluginId },
|
|
8633
|
+
input.pluginAuthToken
|
|
8634
|
+
);
|
|
8635
|
+
const data = res?.data;
|
|
8636
|
+
if (!data || !Array.isArray(data.agents)) return null;
|
|
8637
|
+
return { agents: data.agents, handoffsEnabled: data.handoffsEnabled === true };
|
|
8638
|
+
} catch {
|
|
8639
|
+
return null;
|
|
8640
|
+
}
|
|
8641
|
+
}
|
|
8614
8642
|
async function postAgentSwitchEvent(input) {
|
|
8615
8643
|
try {
|
|
8616
8644
|
await _transport.postJsonAuthed(
|
|
@@ -8773,9 +8801,7 @@ async function _postJsonAuthed(url2, body, pluginAuthToken) {
|
|
|
8773
8801
|
});
|
|
8774
8802
|
res.on("end", () => {
|
|
8775
8803
|
if (res.statusCode && res.statusCode >= 400) {
|
|
8776
|
-
reject(
|
|
8777
|
-
makeHttpError(res.statusCode, res.headers["retry-after"], responseBody)
|
|
8778
|
-
);
|
|
8804
|
+
reject(makeHttpError(res.statusCode, res.headers["retry-after"], responseBody));
|
|
8779
8805
|
return;
|
|
8780
8806
|
}
|
|
8781
8807
|
try {
|
|
@@ -9655,7 +9681,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9655
9681
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
9656
9682
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
9657
9683
|
// pair/reconnect). Older backends ignore the extra field.
|
|
9658
|
-
..."2.
|
|
9684
|
+
..."2.64.0" ? { ideVersion: "2.64.0" } : {}
|
|
9659
9685
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
9660
9686
|
}
|
|
9661
9687
|
/**
|
|
@@ -9680,7 +9706,8 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9680
9706
|
];
|
|
9681
9707
|
_postJson(`${API_BASE2}/api/plugin/agents`, {
|
|
9682
9708
|
pluginId: this.pluginId,
|
|
9683
|
-
agents
|
|
9709
|
+
agents,
|
|
9710
|
+
capabilities: { squad: true }
|
|
9684
9711
|
}).then(() => {
|
|
9685
9712
|
this.agentsRegistered = true;
|
|
9686
9713
|
}).catch(() => {
|
|
@@ -9899,10 +9926,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
|
|
|
9899
9926
|
/[\\/]Start Menu([\\/]|$)/i,
|
|
9900
9927
|
/[\\/]Templates([\\/]|$)/i
|
|
9901
9928
|
];
|
|
9902
|
-
function isUnsafeWindowsWatchRoot(dir,
|
|
9929
|
+
function isUnsafeWindowsWatchRoot(dir, homedir53) {
|
|
9903
9930
|
const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
|
|
9904
9931
|
const cwd = norm(dir);
|
|
9905
|
-
const home = norm(
|
|
9932
|
+
const home = norm(homedir53);
|
|
9906
9933
|
if (cwd === home) return true;
|
|
9907
9934
|
if (/^[a-z]:$/.test(cwd)) return true;
|
|
9908
9935
|
const sysRoots = [
|
|
@@ -14558,10 +14585,10 @@ function buildForPlatform(platform3) {
|
|
|
14558
14585
|
var import_node_crypto4 = require("crypto");
|
|
14559
14586
|
|
|
14560
14587
|
// src/agents/claude/resolver.ts
|
|
14561
|
-
function buildClaudeLaunch(extraArgs = [],
|
|
14562
|
-
const found =
|
|
14588
|
+
function buildClaudeLaunch(extraArgs = [], os66 = createOsStrategy()) {
|
|
14589
|
+
const found = os66.findInPath("claude") ?? os66.findInPath("claude-code");
|
|
14563
14590
|
if (!found) return null;
|
|
14564
|
-
return
|
|
14591
|
+
return os66.buildLaunch(found, extraArgs);
|
|
14565
14592
|
}
|
|
14566
14593
|
|
|
14567
14594
|
// src/agents/claude/installer.ts
|
|
@@ -15151,8 +15178,8 @@ var ClaudeRuntimeStrategy = class {
|
|
|
15151
15178
|
meta = getAgent("claude");
|
|
15152
15179
|
mode = "interactive";
|
|
15153
15180
|
os;
|
|
15154
|
-
constructor(
|
|
15155
|
-
this.os =
|
|
15181
|
+
constructor(os66) {
|
|
15182
|
+
this.os = os66;
|
|
15156
15183
|
}
|
|
15157
15184
|
/**
|
|
15158
15185
|
* Claude Code's react-ink TUI enables bracketed-paste mode at
|
|
@@ -15932,8 +15959,8 @@ function codexCredentialLocator() {
|
|
|
15932
15959
|
function codexLoginLauncher() {
|
|
15933
15960
|
return {
|
|
15934
15961
|
async ensureInstalled() {
|
|
15935
|
-
const
|
|
15936
|
-
return
|
|
15962
|
+
const os66 = createOsStrategy();
|
|
15963
|
+
return os66.findInPath("codex") !== null;
|
|
15937
15964
|
},
|
|
15938
15965
|
launch() {
|
|
15939
15966
|
return (0, import_node_child_process4.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
@@ -15956,8 +15983,8 @@ var CodexRuntimeStrategy = class {
|
|
|
15956
15983
|
meta = getAgent("codex");
|
|
15957
15984
|
mode = "interactive";
|
|
15958
15985
|
os;
|
|
15959
|
-
constructor(
|
|
15960
|
-
this.os =
|
|
15986
|
+
constructor(os66) {
|
|
15987
|
+
this.os = os66;
|
|
15961
15988
|
}
|
|
15962
15989
|
async prepareLaunch() {
|
|
15963
15990
|
let binary = this.os.findInPath("codex");
|
|
@@ -16066,12 +16093,12 @@ var CodexRuntimeStrategy = class {
|
|
|
16066
16093
|
});
|
|
16067
16094
|
}
|
|
16068
16095
|
};
|
|
16069
|
-
function resolveNpm(
|
|
16070
|
-
return
|
|
16096
|
+
function resolveNpm(os66) {
|
|
16097
|
+
return os66.id === "win32" ? "npm.cmd" : "npm";
|
|
16071
16098
|
}
|
|
16072
|
-
async function installCodexViaNpm(
|
|
16099
|
+
async function installCodexViaNpm(os66) {
|
|
16073
16100
|
return new Promise((resolve9, reject) => {
|
|
16074
|
-
const proc = (0, import_node_child_process5.spawn)(resolveNpm(
|
|
16101
|
+
const proc = (0, import_node_child_process5.spawn)(resolveNpm(os66), ["install", "-g", "@openai/codex"], {
|
|
16075
16102
|
stdio: "inherit"
|
|
16076
16103
|
});
|
|
16077
16104
|
proc.on("close", (code) => {
|
|
@@ -16088,16 +16115,16 @@ async function installCodexViaNpm(os65) {
|
|
|
16088
16115
|
});
|
|
16089
16116
|
});
|
|
16090
16117
|
}
|
|
16091
|
-
function augmentNpmGlobalBin(
|
|
16118
|
+
function augmentNpmGlobalBin(os66) {
|
|
16092
16119
|
try {
|
|
16093
|
-
const result = (0, import_node_child_process5.spawnSync)(resolveNpm(
|
|
16120
|
+
const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os66), ["prefix", "-g"], {
|
|
16094
16121
|
stdio: ["ignore", "pipe", "ignore"]
|
|
16095
16122
|
});
|
|
16096
16123
|
if (result.status !== 0) return;
|
|
16097
16124
|
const prefix = result.stdout.toString().trim();
|
|
16098
16125
|
if (!prefix) return;
|
|
16099
|
-
const binDir =
|
|
16100
|
-
|
|
16126
|
+
const binDir = os66.id === "win32" ? prefix : path25.join(prefix, "bin");
|
|
16127
|
+
os66.augmentPath([binDir]);
|
|
16101
16128
|
} catch {
|
|
16102
16129
|
}
|
|
16103
16130
|
}
|
|
@@ -16496,10 +16523,10 @@ function manualInstallHint(runner, tools) {
|
|
|
16496
16523
|
const argv = osPackageInstallArgv(detectPackageManager(runner), [...tools]);
|
|
16497
16524
|
return argv ? `\`sudo ${argv.join(" ")}\`` : `your package manager (e.g. \`${pkgs}\`)`;
|
|
16498
16525
|
}
|
|
16499
|
-
function writeUnzipShim(
|
|
16526
|
+
function writeUnzipShim(os66, runner) {
|
|
16500
16527
|
const python = ["python3", "python"].find((p2) => runner.which(p2));
|
|
16501
16528
|
if (!python) return null;
|
|
16502
|
-
const dir =
|
|
16529
|
+
const dir = os66.scratchPath("codeam-cr-prereq");
|
|
16503
16530
|
const shim = path27.join(dir, "unzip");
|
|
16504
16531
|
const script = `#!/bin/sh
|
|
16505
16532
|
set -e
|
|
@@ -16521,9 +16548,9 @@ exec ${python} -m zipfile -e "$archive" "$dest"
|
|
|
16521
16548
|
(0, import_node_fs5.chmodSync)(shim, 448);
|
|
16522
16549
|
return dir;
|
|
16523
16550
|
}
|
|
16524
|
-
async function ensureInstallPrerequisites(
|
|
16551
|
+
async function ensureInstallPrerequisites(os66, deps = {}) {
|
|
16525
16552
|
const runner = deps.runner ?? defaultHeadroomRunner;
|
|
16526
|
-
const missing = REQUIRED_TOOLS.filter((t2) =>
|
|
16553
|
+
const missing = REQUIRED_TOOLS.filter((t2) => os66.findInPath(t2) === null);
|
|
16527
16554
|
if (missing.length === 0) return { ok: true, extraPath: [] };
|
|
16528
16555
|
log.info(
|
|
16529
16556
|
"coderabbit",
|
|
@@ -16542,10 +16569,10 @@ async function ensureInstallPrerequisites(os65, deps = {}) {
|
|
|
16542
16569
|
);
|
|
16543
16570
|
}
|
|
16544
16571
|
}
|
|
16545
|
-
const stillMissing = REQUIRED_TOOLS.filter((t2) =>
|
|
16572
|
+
const stillMissing = REQUIRED_TOOLS.filter((t2) => os66.findInPath(t2) === null);
|
|
16546
16573
|
if (stillMissing.length === 0) return { ok: true, extraPath: [] };
|
|
16547
16574
|
if (stillMissing.length === 1 && stillMissing[0] === "unzip") {
|
|
16548
|
-
const shimDir = writeUnzipShim(
|
|
16575
|
+
const shimDir = writeUnzipShim(os66, runner);
|
|
16549
16576
|
if (shimDir) {
|
|
16550
16577
|
log.info("coderabbit", "unzip is unavailable \u2014 using a scoped python zipfile shim");
|
|
16551
16578
|
return { ok: true, extraPath: [shimDir] };
|
|
@@ -16608,15 +16635,15 @@ function summarizeInstallFailure(output) {
|
|
|
16608
16635
|
}
|
|
16609
16636
|
return lines.length > 0 ? lines[lines.length - 1] : null;
|
|
16610
16637
|
}
|
|
16611
|
-
async function ensureCoderabbitInstalled(
|
|
16612
|
-
if (
|
|
16613
|
-
if (
|
|
16638
|
+
async function ensureCoderabbitInstalled(os66, deps = {}) {
|
|
16639
|
+
if (os66.findInPath("coderabbit")) return { ok: true };
|
|
16640
|
+
if (os66.id === "win32") {
|
|
16614
16641
|
return {
|
|
16615
16642
|
ok: false,
|
|
16616
16643
|
error: "CodeRabbit on Windows requires WSL. Install the CLI inside your WSL distribution (curl -fsSL https://cli.coderabbit.ai/install.sh | sh), then try again."
|
|
16617
16644
|
};
|
|
16618
16645
|
}
|
|
16619
|
-
const prereq = await ensureInstallPrerequisites(
|
|
16646
|
+
const prereq = await ensureInstallPrerequisites(os66, deps);
|
|
16620
16647
|
if (!prereq.ok) return { ok: false, error: prereq.error };
|
|
16621
16648
|
const env = { ...process.env };
|
|
16622
16649
|
if (prereq.extraPath.length > 0) {
|
|
@@ -16632,8 +16659,8 @@ async function ensureCoderabbitInstalled(os65, deps = {}) {
|
|
|
16632
16659
|
error: detail ? `CodeRabbit CLI install failed: ${detail}` : "CodeRabbit CLI install failed \u2014 check this machine's network egress and try again."
|
|
16633
16660
|
};
|
|
16634
16661
|
}
|
|
16635
|
-
|
|
16636
|
-
if (
|
|
16662
|
+
os66.augmentPath([`${os66.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
16663
|
+
if (os66.findInPath("coderabbit") === null) {
|
|
16637
16664
|
const detail = summarizeInstallFailure(output);
|
|
16638
16665
|
return {
|
|
16639
16666
|
ok: false,
|
|
@@ -16675,10 +16702,10 @@ function coderabbitCredentialLocator() {
|
|
|
16675
16702
|
validate: validateNonEmptyCredential
|
|
16676
16703
|
};
|
|
16677
16704
|
}
|
|
16678
|
-
function coderabbitLoginLauncher(
|
|
16705
|
+
function coderabbitLoginLauncher(os66) {
|
|
16679
16706
|
return {
|
|
16680
16707
|
async ensureInstalled() {
|
|
16681
|
-
const result = await ensureCoderabbitInstalled(
|
|
16708
|
+
const result = await ensureCoderabbitInstalled(os66);
|
|
16682
16709
|
if (!result.ok && result.error) console.error(`
|
|
16683
16710
|
\u2717 ${result.error}
|
|
16684
16711
|
`);
|
|
@@ -16738,8 +16765,8 @@ function pickLine(obj) {
|
|
|
16738
16765
|
function toHunk(raw, groupSeverity) {
|
|
16739
16766
|
if (!raw || typeof raw !== "object") return null;
|
|
16740
16767
|
const o = raw;
|
|
16741
|
-
const
|
|
16742
|
-
if (!
|
|
16768
|
+
const path91 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
|
|
16769
|
+
if (!path91) return null;
|
|
16743
16770
|
const message = asString(
|
|
16744
16771
|
pick(o, [
|
|
16745
16772
|
"comment",
|
|
@@ -16756,7 +16783,7 @@ function toHunk(raw, groupSeverity) {
|
|
|
16756
16783
|
const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
|
|
16757
16784
|
const locObj = pick(o, ["location"]) ?? o;
|
|
16758
16785
|
return {
|
|
16759
|
-
path:
|
|
16786
|
+
path: path91.trim(),
|
|
16760
16787
|
line: pickLine(o) ?? pickLine(locObj),
|
|
16761
16788
|
severity,
|
|
16762
16789
|
message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
|
|
@@ -16839,10 +16866,10 @@ function parsePlain(stdout) {
|
|
|
16839
16866
|
for (const line of stdout.split(/\r?\n/)) {
|
|
16840
16867
|
const m = line.match(HUNK_LINE_RE);
|
|
16841
16868
|
if (!m) continue;
|
|
16842
|
-
const [,
|
|
16843
|
-
if (!
|
|
16869
|
+
const [, path91, lineNo, sevToken, message] = m;
|
|
16870
|
+
if (!path91 || !lineNo || !message) continue;
|
|
16844
16871
|
hunks.push({
|
|
16845
|
-
path:
|
|
16872
|
+
path: path91.trim(),
|
|
16846
16873
|
line: Number(lineNo),
|
|
16847
16874
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
16848
16875
|
message: message.trim().replace(/^[*-]\s+/, "")
|
|
@@ -16902,8 +16929,8 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
16902
16929
|
meta = getAgent("coderabbit");
|
|
16903
16930
|
mode = "batch";
|
|
16904
16931
|
os;
|
|
16905
|
-
constructor(
|
|
16906
|
-
this.os =
|
|
16932
|
+
constructor(os66) {
|
|
16933
|
+
this.os = os66;
|
|
16907
16934
|
}
|
|
16908
16935
|
getDefaultArgs() {
|
|
16909
16936
|
return ["review", "--agent"];
|
|
@@ -17174,10 +17201,10 @@ function cursorCredentialLocator() {
|
|
|
17174
17201
|
validate: validateNonEmptyCredential
|
|
17175
17202
|
};
|
|
17176
17203
|
}
|
|
17177
|
-
function cursorLoginLauncher(
|
|
17204
|
+
function cursorLoginLauncher(os66) {
|
|
17178
17205
|
return {
|
|
17179
17206
|
async ensureInstalled() {
|
|
17180
|
-
if (
|
|
17207
|
+
if (os66.findInPath("cursor-agent")) return true;
|
|
17181
17208
|
console.error(
|
|
17182
17209
|
"\n \u2717 cursor-agent binary not on PATH.\n Install Cursor (https://cursor.com/) and ensure the CLI\n plugin is enabled, then re-run `codeam link cursor`.\n"
|
|
17183
17210
|
);
|
|
@@ -17241,8 +17268,8 @@ var CursorRuntimeStrategy = class {
|
|
|
17241
17268
|
meta = getAgent("cursor");
|
|
17242
17269
|
mode = "interactive";
|
|
17243
17270
|
os;
|
|
17244
|
-
constructor(
|
|
17245
|
-
this.os =
|
|
17271
|
+
constructor(os66) {
|
|
17272
|
+
this.os = os66;
|
|
17246
17273
|
}
|
|
17247
17274
|
async prepareLaunch() {
|
|
17248
17275
|
const binary = this.os.findInPath("cursor-agent");
|
|
@@ -17458,10 +17485,10 @@ function aiderCredentialLocator() {
|
|
|
17458
17485
|
validate: validateNonEmptyCredential
|
|
17459
17486
|
};
|
|
17460
17487
|
}
|
|
17461
|
-
function aiderLoginLauncher(
|
|
17488
|
+
function aiderLoginLauncher(os66) {
|
|
17462
17489
|
return {
|
|
17463
17490
|
async ensureInstalled() {
|
|
17464
|
-
if (
|
|
17491
|
+
if (os66.findInPath("aider")) return true;
|
|
17465
17492
|
console.error(
|
|
17466
17493
|
"\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
|
|
17467
17494
|
);
|
|
@@ -17471,7 +17498,7 @@ function aiderLoginLauncher(os65) {
|
|
|
17471
17498
|
console.error(
|
|
17472
17499
|
"\n Aider has no interactive login flow.\n Set ANTHROPIC_API_KEY or OPENAI_API_KEY in your shell,\n or re-run `codeam link aider --api-key=<your-key>`.\n"
|
|
17473
17500
|
);
|
|
17474
|
-
return (0, import_node_child_process12.spawn)(
|
|
17501
|
+
return (0, import_node_child_process12.spawn)(os66.id === "win32" ? "cmd.exe" : "sh", os66.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
|
|
17475
17502
|
stdio: "ignore"
|
|
17476
17503
|
});
|
|
17477
17504
|
}
|
|
@@ -17543,8 +17570,8 @@ var AiderRuntimeStrategy = class {
|
|
|
17543
17570
|
meta = getAgent("aider");
|
|
17544
17571
|
mode = "interactive";
|
|
17545
17572
|
os;
|
|
17546
|
-
constructor(
|
|
17547
|
-
this.os =
|
|
17573
|
+
constructor(os66) {
|
|
17574
|
+
this.os = os66;
|
|
17548
17575
|
}
|
|
17549
17576
|
async prepareLaunch() {
|
|
17550
17577
|
const binary = this.os.findInPath("aider");
|
|
@@ -17676,8 +17703,8 @@ function geminiCredentialLocator() {
|
|
|
17676
17703
|
function geminiLoginLauncher() {
|
|
17677
17704
|
return {
|
|
17678
17705
|
async ensureInstalled() {
|
|
17679
|
-
const
|
|
17680
|
-
return
|
|
17706
|
+
const os66 = createOsStrategy();
|
|
17707
|
+
return os66.findInPath("gemini") !== null;
|
|
17681
17708
|
},
|
|
17682
17709
|
launch() {
|
|
17683
17710
|
return (0, import_node_child_process13.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
|
|
@@ -17867,8 +17894,8 @@ var GeminiRuntimeStrategy = class {
|
|
|
17867
17894
|
meta = getAgent("gemini");
|
|
17868
17895
|
mode = "interactive";
|
|
17869
17896
|
os;
|
|
17870
|
-
constructor(
|
|
17871
|
-
this.os =
|
|
17897
|
+
constructor(os66) {
|
|
17898
|
+
this.os = os66;
|
|
17872
17899
|
}
|
|
17873
17900
|
async prepareLaunch() {
|
|
17874
17901
|
const binary = this.os.findInPath("gemini");
|
|
@@ -18159,8 +18186,8 @@ var KimiRuntimeStrategy = class {
|
|
|
18159
18186
|
meta = getAgent("kimi");
|
|
18160
18187
|
mode = "interactive";
|
|
18161
18188
|
os;
|
|
18162
|
-
constructor(
|
|
18163
|
-
this.os =
|
|
18189
|
+
constructor(os66) {
|
|
18190
|
+
this.os = os66;
|
|
18164
18191
|
}
|
|
18165
18192
|
async prepareLaunch() {
|
|
18166
18193
|
const binary = this.os.findInPath("kimi");
|
|
@@ -18302,8 +18329,8 @@ var OpencodeRuntimeStrategy = class {
|
|
|
18302
18329
|
meta = getAgent("opencode");
|
|
18303
18330
|
mode = "interactive";
|
|
18304
18331
|
os;
|
|
18305
|
-
constructor(
|
|
18306
|
-
this.os =
|
|
18332
|
+
constructor(os66) {
|
|
18333
|
+
this.os = os66;
|
|
18307
18334
|
}
|
|
18308
18335
|
async prepareLaunch() {
|
|
18309
18336
|
const binary = this.os.findInPath("opencode");
|
|
@@ -18387,20 +18414,20 @@ var OpencodeRuntimeStrategy = class {
|
|
|
18387
18414
|
|
|
18388
18415
|
// src/agents/registry.ts
|
|
18389
18416
|
var runtimeBuilders = {
|
|
18390
|
-
claude: (
|
|
18391
|
-
codex: (
|
|
18392
|
-
coderabbit: (
|
|
18393
|
-
cursor: (
|
|
18394
|
-
aider: (
|
|
18395
|
-
gemini: (
|
|
18396
|
-
kimi: (
|
|
18397
|
-
opencode: (
|
|
18417
|
+
claude: (os66) => new ClaudeRuntimeStrategy(os66),
|
|
18418
|
+
codex: (os66) => new CodexRuntimeStrategy(os66),
|
|
18419
|
+
coderabbit: (os66) => new CoderabbitRuntimeStrategy(os66),
|
|
18420
|
+
cursor: (os66) => new CursorRuntimeStrategy(os66),
|
|
18421
|
+
aider: (os66) => new AiderRuntimeStrategy(os66),
|
|
18422
|
+
gemini: (os66) => new GeminiRuntimeStrategy(os66),
|
|
18423
|
+
kimi: (os66) => new KimiRuntimeStrategy(os66),
|
|
18424
|
+
opencode: (os66) => new OpencodeRuntimeStrategy(os66)
|
|
18398
18425
|
};
|
|
18399
18426
|
var deployBuilders = {
|
|
18400
18427
|
claude: () => new ClaudeDeployStrategy(),
|
|
18401
18428
|
codex: () => new CodexDeployStrategy()
|
|
18402
18429
|
};
|
|
18403
|
-
function createAgentStrategy(agent,
|
|
18430
|
+
function createAgentStrategy(agent, os66 = createOsStrategy()) {
|
|
18404
18431
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
18405
18432
|
throw new Error(
|
|
18406
18433
|
`Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
|
|
@@ -18410,10 +18437,10 @@ function createAgentStrategy(agent, os65 = createOsStrategy()) {
|
|
|
18410
18437
|
if (!build) {
|
|
18411
18438
|
throw new Error(`No runtime strategy registered for agent "${agent}"`);
|
|
18412
18439
|
}
|
|
18413
|
-
return build(
|
|
18440
|
+
return build(os66);
|
|
18414
18441
|
}
|
|
18415
|
-
function createInteractiveAgentStrategy(agent,
|
|
18416
|
-
const s = createAgentStrategy(agent,
|
|
18442
|
+
function createInteractiveAgentStrategy(agent, os66 = createOsStrategy()) {
|
|
18443
|
+
const s = createAgentStrategy(agent, os66);
|
|
18417
18444
|
if (s.mode !== "interactive") {
|
|
18418
18445
|
throw new Error(
|
|
18419
18446
|
`Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
|
|
@@ -19091,8 +19118,8 @@ function collectChangedFiles(cwd) {
|
|
|
19091
19118
|
}
|
|
19092
19119
|
return [...byPath.values()];
|
|
19093
19120
|
}
|
|
19094
|
-
function restoreCoderabbitOauthBlob(
|
|
19095
|
-
const dir = path38.join(
|
|
19121
|
+
function restoreCoderabbitOauthBlob(os66, value) {
|
|
19122
|
+
const dir = path38.join(os66.homeDir(), ".coderabbit");
|
|
19096
19123
|
(0, import_node_fs6.mkdirSync)(dir, { recursive: true });
|
|
19097
19124
|
let file = "auth.json";
|
|
19098
19125
|
let contents = value.trim();
|
|
@@ -19112,26 +19139,26 @@ function installFailureMessage(result) {
|
|
|
19112
19139
|
return result.error ?? "CodeRabbit CLI could not be installed";
|
|
19113
19140
|
}
|
|
19114
19141
|
async function configureCoderabbit(input, deps = {}) {
|
|
19115
|
-
const
|
|
19142
|
+
const os66 = deps.os ?? createOsStrategy();
|
|
19116
19143
|
const ensureInstalled = deps.ensureInstalled ?? ensureCoderabbitInstalled;
|
|
19117
19144
|
const isLoggedIn = deps.isLoggedIn ?? defaultIsLoggedIn;
|
|
19118
19145
|
const runOAuth = deps.runOAuthLogin ?? runCoderabbitOAuthLogin;
|
|
19119
19146
|
const snapshot = deps.snapshotDir ?? (() => snapshotCredentialDir());
|
|
19120
19147
|
const capture2 = deps.captureCredential ?? ((b) => diffCapturedCredential(b));
|
|
19121
19148
|
const loginWithApiKey = deps.loginWithApiKey ?? defaultLoginWithApiKey;
|
|
19122
|
-
const home =
|
|
19123
|
-
|
|
19124
|
-
|
|
19149
|
+
const home = os66.homeDir();
|
|
19150
|
+
os66.augmentPath(
|
|
19151
|
+
os66.id === "win32" ? [
|
|
19125
19152
|
path38.join(home, ".local", "bin"),
|
|
19126
19153
|
path38.join(process.env.APPDATA ?? path38.join(home, "AppData", "Roaming"), "npm"),
|
|
19127
19154
|
path38.join(home, "scoop", "shims")
|
|
19128
19155
|
] : [path38.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
|
|
19129
19156
|
);
|
|
19130
|
-
const installed2 =
|
|
19157
|
+
const installed2 = os66.findInPath("coderabbit") !== null;
|
|
19131
19158
|
const base = () => ({
|
|
19132
19159
|
action: input.action,
|
|
19133
19160
|
supported: true,
|
|
19134
|
-
installed:
|
|
19161
|
+
installed: os66.findInPath("coderabbit") !== null,
|
|
19135
19162
|
loggedIn: false
|
|
19136
19163
|
});
|
|
19137
19164
|
if (input.action === "status") {
|
|
@@ -19145,7 +19172,7 @@ async function configureCoderabbit(input, deps = {}) {
|
|
|
19145
19172
|
const key = (input.apiKey ?? "").trim();
|
|
19146
19173
|
if (!key) return { ...res2, error: "No API key provided" };
|
|
19147
19174
|
if (!res2.installed) {
|
|
19148
|
-
const inst = await ensureInstalled(
|
|
19175
|
+
const inst = await ensureInstalled(os66);
|
|
19149
19176
|
res2.installed = inst.ok;
|
|
19150
19177
|
if (!inst.ok) return { ...res2, error: installFailureMessage(inst) };
|
|
19151
19178
|
}
|
|
@@ -19169,7 +19196,7 @@ async function configureCoderabbit(input, deps = {}) {
|
|
|
19169
19196
|
}
|
|
19170
19197
|
if (!res2.installed) {
|
|
19171
19198
|
deps.onEvent?.({ kind: "installing" });
|
|
19172
|
-
const inst = await ensureInstalled(
|
|
19199
|
+
const inst = await ensureInstalled(os66);
|
|
19173
19200
|
res2.installed = inst.ok;
|
|
19174
19201
|
if (!inst.ok) return { ...res2, error: installFailureMessage(inst) };
|
|
19175
19202
|
}
|
|
@@ -19186,7 +19213,7 @@ async function configureCoderabbit(input, deps = {}) {
|
|
|
19186
19213
|
return { ...res2, loggedIn: true, linked: true };
|
|
19187
19214
|
}
|
|
19188
19215
|
try {
|
|
19189
|
-
restoreCoderabbitOauthBlob(
|
|
19216
|
+
restoreCoderabbitOauthBlob(os66, cred.credential);
|
|
19190
19217
|
} catch (err) {
|
|
19191
19218
|
return {
|
|
19192
19219
|
...res2,
|
|
@@ -19210,7 +19237,7 @@ async function configureCoderabbit(input, deps = {}) {
|
|
|
19210
19237
|
const res2 = base();
|
|
19211
19238
|
if (!installed2) {
|
|
19212
19239
|
deps.onEvent?.({ kind: "installing" });
|
|
19213
|
-
const inst = await ensureInstalled(
|
|
19240
|
+
const inst = await ensureInstalled(os66);
|
|
19214
19241
|
res2.installed = inst.ok;
|
|
19215
19242
|
if (!inst.ok) return { ...res2, error: installFailureMessage(inst) };
|
|
19216
19243
|
}
|
|
@@ -19250,7 +19277,7 @@ async function configureCoderabbit(input, deps = {}) {
|
|
|
19250
19277
|
}
|
|
19251
19278
|
const res = base();
|
|
19252
19279
|
if (!res.installed) {
|
|
19253
|
-
const inst = await ensureInstalled(
|
|
19280
|
+
const inst = await ensureInstalled(os66);
|
|
19254
19281
|
res.installed = inst.ok;
|
|
19255
19282
|
if (!inst.ok) return { ...res, error: installFailureMessage(inst) };
|
|
19256
19283
|
}
|
|
@@ -21073,7 +21100,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
21073
21100
|
if (process.env.NODE_ENV === "test") return;
|
|
21074
21101
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21075
21102
|
if (process.env.CI) return;
|
|
21076
|
-
const current2 = true ? "2.
|
|
21103
|
+
const current2 = true ? "2.64.0" : null;
|
|
21077
21104
|
if (!current2) return;
|
|
21078
21105
|
const cache = readCache();
|
|
21079
21106
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21090,7 +21117,7 @@ function checkForUpdates() {
|
|
|
21090
21117
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21091
21118
|
if (process.env.CI) return;
|
|
21092
21119
|
if (!process.stdout.isTTY) return;
|
|
21093
|
-
const current2 = true ? "2.
|
|
21120
|
+
const current2 = true ? "2.64.0" : null;
|
|
21094
21121
|
if (!current2) return;
|
|
21095
21122
|
const cache = readCache();
|
|
21096
21123
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21110,7 +21137,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
21110
21137
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
21111
21138
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
21112
21139
|
function currentCliVersion() {
|
|
21113
|
-
return true ? "2.
|
|
21140
|
+
return true ? "2.64.0" : null;
|
|
21114
21141
|
}
|
|
21115
21142
|
function runCmd(cmd, args2, timeoutMs) {
|
|
21116
21143
|
return new Promise((resolve9) => {
|
|
@@ -22779,7 +22806,7 @@ async function defaultFetchJson(url2) {
|
|
|
22779
22806
|
async function readUsageReport(deps = {}) {
|
|
22780
22807
|
const port = deps.port ?? HEADROOM_PROXY_PORT;
|
|
22781
22808
|
const base = `http://127.0.0.1:${port}`;
|
|
22782
|
-
const get2 = deps.fetchJson ?? ((
|
|
22809
|
+
const get2 = deps.fetchJson ?? ((path91) => defaultFetchJson(`${base}${path91}`));
|
|
22783
22810
|
let history;
|
|
22784
22811
|
try {
|
|
22785
22812
|
history = await get2("/stats-history");
|
|
@@ -24696,11 +24723,11 @@ function resolveDoltInstallStrategy(platform3) {
|
|
|
24696
24723
|
}
|
|
24697
24724
|
var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
|
|
24698
24725
|
function doltPlatformTuple(platform3, arch2) {
|
|
24699
|
-
const
|
|
24726
|
+
const os66 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
|
|
24700
24727
|
const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
|
|
24701
24728
|
if (!a) return null;
|
|
24702
|
-
if (
|
|
24703
|
-
return `${
|
|
24729
|
+
if (os66 === "windows" && a !== "amd64") return null;
|
|
24730
|
+
return `${os66}-${a}`;
|
|
24704
24731
|
}
|
|
24705
24732
|
function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
|
|
24706
24733
|
const tuple = doltPlatformTuple(platform3, arch2);
|
|
@@ -25761,8 +25788,14 @@ function dispatchPrompt(ctx, prompt) {
|
|
|
25761
25788
|
ctx.outputSvc.newTurn();
|
|
25762
25789
|
ctx.agent.sendCommand(prompt);
|
|
25763
25790
|
}
|
|
25764
|
-
var startTask = (ctx,
|
|
25791
|
+
var startTask = async (ctx, cmd, parsed) => {
|
|
25765
25792
|
const { prompt, files } = parsed;
|
|
25793
|
+
if (parsed.agentId && parsed.agentId !== ctx.agentId) {
|
|
25794
|
+
await ctx.relay.sendResult(cmd.id, "failed", {
|
|
25795
|
+
error: "Switching agents isn't supported on this session."
|
|
25796
|
+
});
|
|
25797
|
+
return;
|
|
25798
|
+
}
|
|
25766
25799
|
const effectivePrompt = prompt ?? "";
|
|
25767
25800
|
if (files && files.length > 0) {
|
|
25768
25801
|
const paths = saveFilesTemp(files);
|
|
@@ -26346,7 +26379,7 @@ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
|
|
|
26346
26379
|
});
|
|
26347
26380
|
const token = ctx.pluginAuthToken;
|
|
26348
26381
|
void (async () => {
|
|
26349
|
-
const
|
|
26382
|
+
const os66 = createOsStrategy();
|
|
26350
26383
|
try {
|
|
26351
26384
|
const report = await reviewPullRequest(
|
|
26352
26385
|
{
|
|
@@ -26355,7 +26388,7 @@ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
|
|
|
26355
26388
|
baseBranch: parsed.baseBranch
|
|
26356
26389
|
},
|
|
26357
26390
|
{
|
|
26358
|
-
runReview: (input) => new CoderabbitRuntimeStrategy(
|
|
26391
|
+
runReview: (input) => new CoderabbitRuntimeStrategy(os66).runOneShot(input),
|
|
26359
26392
|
runGh: (args2) => defaultRunGh(args2),
|
|
26360
26393
|
postReport: async (r) => {
|
|
26361
26394
|
if (!token) return;
|
|
@@ -27458,11 +27491,11 @@ function resolveTokenValue(args2) {
|
|
|
27458
27491
|
}
|
|
27459
27492
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
27460
27493
|
if (fileFlag) {
|
|
27461
|
-
const
|
|
27494
|
+
const path91 = fileFlag.slice("--token-file=".length);
|
|
27462
27495
|
try {
|
|
27463
|
-
const content = fs63.readFileSync(
|
|
27464
|
-
if (content.length === 0) fail(`--token-file ${
|
|
27465
|
-
rmIfExistsQuiet(
|
|
27496
|
+
const content = fs63.readFileSync(path91, "utf8").trim();
|
|
27497
|
+
if (content.length === 0) fail(`--token-file ${path91} is empty`);
|
|
27498
|
+
rmIfExistsQuiet(path91);
|
|
27466
27499
|
return content;
|
|
27467
27500
|
} catch (err) {
|
|
27468
27501
|
fail(`Could not read --token-file: ${err.message}`);
|
|
@@ -28261,11 +28294,12 @@ function kimiRuns() {
|
|
|
28261
28294
|
const r = (0, import_node_child_process27.spawnSync)("kimi", ["--version"], { stdio: "ignore", timeout: 15e3 });
|
|
28262
28295
|
return !r.error && r.status === 0;
|
|
28263
28296
|
}
|
|
28264
|
-
function
|
|
28297
|
+
function augmentKimiPath() {
|
|
28265
28298
|
const dir = kimiBinDir();
|
|
28266
28299
|
const parts = (process.env.PATH ?? "").split(":");
|
|
28267
28300
|
if (!parts.includes(dir)) process.env.PATH = `${dir}:${process.env.PATH ?? ""}`;
|
|
28268
28301
|
}
|
|
28302
|
+
var augmentPath2 = augmentKimiPath;
|
|
28269
28303
|
async function runInstaller2() {
|
|
28270
28304
|
return new Promise((resolve9) => {
|
|
28271
28305
|
const proc = (0, import_node_child_process27.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL2} | bash`], { stdio: "inherit" });
|
|
@@ -28313,11 +28347,12 @@ function opencodeRuns() {
|
|
|
28313
28347
|
const r = (0, import_node_child_process28.spawnSync)("opencode", ["--version"], { stdio: "ignore", timeout: 15e3 });
|
|
28314
28348
|
return !r.error && r.status === 0;
|
|
28315
28349
|
}
|
|
28316
|
-
function
|
|
28350
|
+
function augmentOpencodePath() {
|
|
28317
28351
|
const dir = opencodeBinDir();
|
|
28318
28352
|
const parts = (process.env.PATH ?? "").split(":");
|
|
28319
28353
|
if (!parts.includes(dir)) process.env.PATH = `${dir}:${process.env.PATH ?? ""}`;
|
|
28320
28354
|
}
|
|
28355
|
+
var augmentPath3 = augmentOpencodePath;
|
|
28321
28356
|
async function runInstaller3() {
|
|
28322
28357
|
return new Promise((resolve9) => {
|
|
28323
28358
|
const proc = (0, import_node_child_process28.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL3} | bash`], { stdio: "inherit" });
|
|
@@ -28459,6 +28494,7 @@ var REGISTRY = {
|
|
|
28459
28494
|
// provisions it, so there we just wait for the binary to appear.
|
|
28460
28495
|
waitForBinary: async (o) => {
|
|
28461
28496
|
if (isLocalSession()) await ensureKimiInstalled();
|
|
28497
|
+
augmentKimiPath();
|
|
28462
28498
|
return waitForCommandOnPath("kimi", o);
|
|
28463
28499
|
}
|
|
28464
28500
|
}),
|
|
@@ -28474,6 +28510,7 @@ var REGISTRY = {
|
|
|
28474
28510
|
requiresAgentBinary: "opencode",
|
|
28475
28511
|
waitForBinary: async (o) => {
|
|
28476
28512
|
if (isLocalSession()) await ensureOpencodeInstalled();
|
|
28513
|
+
augmentOpencodePath();
|
|
28477
28514
|
return waitForCommandOnPath("opencode", o);
|
|
28478
28515
|
}
|
|
28479
28516
|
})
|
|
@@ -34366,7 +34403,7 @@ function makeSerializedSwitchEmitter(post2) {
|
|
|
34366
34403
|
return chain;
|
|
34367
34404
|
};
|
|
34368
34405
|
}
|
|
34369
|
-
async function performAgentSwitch(deps, rawAgentId) {
|
|
34406
|
+
async function performAgentSwitch(deps, rawAgentId, fastPath = {}) {
|
|
34370
34407
|
const from = deps.currentAgent();
|
|
34371
34408
|
const target = resolveSwitchTarget(rawAgentId, from);
|
|
34372
34409
|
if (!target.ok) {
|
|
@@ -34376,27 +34413,34 @@ async function performAgentSwitch(deps, rawAgentId) {
|
|
|
34376
34413
|
const emitStatus = (status2) => deps.postEvent("switch_agent_status", { ...status2 });
|
|
34377
34414
|
const emitStep = (step) => deps.postEvent("switch_agent_progress", { step, agentId });
|
|
34378
34415
|
const fail2 = (error) => {
|
|
34416
|
+
log.warn("switchAgent", `switch ${from} \u2192 ${agentId} failed: ${error}`);
|
|
34379
34417
|
void emitStatus({ state: "error", agentId, fromAgentId: from, error });
|
|
34380
34418
|
return { ok: false, agentId, error };
|
|
34381
34419
|
};
|
|
34382
34420
|
log.info("switchAgent", `switch requested ${from} \u2192 ${agentId}`);
|
|
34383
34421
|
void emitStatus({ state: "switching", agentId, fromAgentId: from });
|
|
34384
|
-
|
|
34385
|
-
|
|
34386
|
-
|
|
34387
|
-
|
|
34388
|
-
|
|
34389
|
-
|
|
34422
|
+
let installScript;
|
|
34423
|
+
if (!fastPath.skipProvision) {
|
|
34424
|
+
void emitStep("credential");
|
|
34425
|
+
const cred = await deps.fetchCredential(agentId);
|
|
34426
|
+
if (!cred) {
|
|
34427
|
+
return fail2(
|
|
34428
|
+
`No linked credential for ${displayName(agentId)}. Link it in Profile \u203A Agents first.`
|
|
34429
|
+
);
|
|
34430
|
+
}
|
|
34431
|
+
try {
|
|
34432
|
+
deps.provisionCredential(agentId, toAgentAuth(cred.method, cred.credential));
|
|
34433
|
+
} catch (err) {
|
|
34434
|
+
log.warn("switchAgent", `credential provisioning failed: ${err.message}`);
|
|
34435
|
+
return fail2(`Couldn't write the ${displayName(agentId)} credential on this machine.`);
|
|
34436
|
+
}
|
|
34437
|
+
installScript = cred.installScript;
|
|
34390
34438
|
}
|
|
34391
|
-
|
|
34392
|
-
|
|
34393
|
-
|
|
34394
|
-
|
|
34395
|
-
return fail2(`Couldn't write the ${displayName(agentId)} credential on this machine.`);
|
|
34439
|
+
if (!fastPath.skipInstall) {
|
|
34440
|
+
void emitStep("install");
|
|
34441
|
+
const bin = await deps.ensureBinary(agentId, installScript);
|
|
34442
|
+
if (!bin.ok) return fail2(bin.error);
|
|
34396
34443
|
}
|
|
34397
|
-
void emitStep("install");
|
|
34398
|
-
const bin = await deps.ensureBinary(agentId, cred.installScript);
|
|
34399
|
-
if (!bin.ok) return fail2(bin.error);
|
|
34400
34444
|
void emitStep("restart");
|
|
34401
34445
|
try {
|
|
34402
34446
|
await deps.swapRuntime(agentId);
|
|
@@ -34423,6 +34467,121 @@ async function performAgentSwitch(deps, rawAgentId) {
|
|
|
34423
34467
|
return { ok: true, agentId };
|
|
34424
34468
|
}
|
|
34425
34469
|
|
|
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
|
+
|
|
34426
34585
|
// src/services/streaming/transport.ts
|
|
34427
34586
|
var http7 = __toESM(require("http"));
|
|
34428
34587
|
var https8 = __toESM(require("https"));
|
|
@@ -34868,17 +35027,95 @@ function commonPrefixLength(a, b) {
|
|
|
34868
35027
|
return i;
|
|
34869
35028
|
}
|
|
34870
35029
|
|
|
35030
|
+
// src/agents/acp/handoff-protocol.ts
|
|
35031
|
+
var REASON_MAX = 1e3;
|
|
35032
|
+
var PROMPT_MAX2 = 8e3;
|
|
35033
|
+
var FENCE_OPEN = "```" + HANDOFF_FENCE_TAG;
|
|
35034
|
+
var FENCE_RE = new RegExp("```" + HANDOFF_FENCE_TAG + "\\s*\\n([\\s\\S]*?)\\n?```", "g");
|
|
35035
|
+
var OUTER_FENCE_RE = /(`{4,})[\s\S]*?\1/g;
|
|
35036
|
+
var outerFencePlaceholder = (i) => `@@HANDOFF_MASK_${i}@@`;
|
|
35037
|
+
function maskOuterFences(text) {
|
|
35038
|
+
const spans = [];
|
|
35039
|
+
const masked = text.replace(OUTER_FENCE_RE, (m) => {
|
|
35040
|
+
const token = outerFencePlaceholder(spans.length);
|
|
35041
|
+
spans.push(m);
|
|
35042
|
+
return token;
|
|
35043
|
+
});
|
|
35044
|
+
const restore = (s) => spans.reduce((acc, span, i) => acc.split(outerFencePlaceholder(i)).join(span), s);
|
|
35045
|
+
return { masked, restore };
|
|
35046
|
+
}
|
|
35047
|
+
function parseProposal(raw, currentAgent, validTargets) {
|
|
35048
|
+
let parsed;
|
|
35049
|
+
try {
|
|
35050
|
+
parsed = JSON.parse(raw);
|
|
35051
|
+
} catch {
|
|
35052
|
+
log.debug("handoffProtocol", "dropped proposal: malformed JSON");
|
|
35053
|
+
return null;
|
|
35054
|
+
}
|
|
35055
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
35056
|
+
log.debug("handoffProtocol", "dropped proposal: not a JSON object");
|
|
35057
|
+
return null;
|
|
35058
|
+
}
|
|
35059
|
+
const { to, reason, prompt } = parsed;
|
|
35060
|
+
if (typeof to !== "string" || to.length === 0) {
|
|
35061
|
+
log.debug("handoffProtocol", 'dropped proposal: missing/invalid "to"');
|
|
35062
|
+
return null;
|
|
35063
|
+
}
|
|
35064
|
+
if (!validTargets.has(to)) {
|
|
35065
|
+
log.debug("handoffProtocol", `dropped proposal: unknown target "${to}"`);
|
|
35066
|
+
return null;
|
|
35067
|
+
}
|
|
35068
|
+
if (to === currentAgent) {
|
|
35069
|
+
log.debug("handoffProtocol", "dropped proposal: target is the current agent");
|
|
35070
|
+
return null;
|
|
35071
|
+
}
|
|
35072
|
+
if (typeof reason !== "string" || reason.length === 0 || reason.length > REASON_MAX) {
|
|
35073
|
+
log.debug("handoffProtocol", 'dropped proposal: invalid "reason"');
|
|
35074
|
+
return null;
|
|
35075
|
+
}
|
|
35076
|
+
if (typeof prompt !== "string" || prompt.length === 0 || prompt.length > PROMPT_MAX2) {
|
|
35077
|
+
log.debug("handoffProtocol", 'dropped proposal: invalid "prompt"');
|
|
35078
|
+
return null;
|
|
35079
|
+
}
|
|
35080
|
+
return { to, reason, prompt };
|
|
35081
|
+
}
|
|
35082
|
+
function stripFences(masked) {
|
|
35083
|
+
const stripped = masked.replace(FENCE_RE, "");
|
|
35084
|
+
return stripped.replace(/(?:\r?\n){3,}/g, "\n\n").trim();
|
|
35085
|
+
}
|
|
35086
|
+
function extractHandoffProposal(text, currentAgent, validTargets) {
|
|
35087
|
+
const { masked, restore } = maskOuterFences(text);
|
|
35088
|
+
const matches = [...masked.matchAll(FENCE_RE)];
|
|
35089
|
+
if (matches.length === 0) {
|
|
35090
|
+
return { cleanText: text, proposal: null };
|
|
35091
|
+
}
|
|
35092
|
+
const last = matches[matches.length - 1];
|
|
35093
|
+
const proposal = parseProposal(last[1].trim(), currentAgent, validTargets);
|
|
35094
|
+
const cleanText = restore(stripFences(masked));
|
|
35095
|
+
return { cleanText, proposal };
|
|
35096
|
+
}
|
|
35097
|
+
function stripHandoffFences(text) {
|
|
35098
|
+
const { masked, restore } = maskOuterFences(text);
|
|
35099
|
+
if (masked.search(FENCE_RE) === -1) {
|
|
35100
|
+
return text;
|
|
35101
|
+
}
|
|
35102
|
+
return restore(stripFences(masked));
|
|
35103
|
+
}
|
|
35104
|
+
function handoffFenceStart(text) {
|
|
35105
|
+
return text.indexOf(FENCE_OPEN);
|
|
35106
|
+
}
|
|
35107
|
+
|
|
34871
35108
|
// src/agents/acp/onboarding.ts
|
|
34872
35109
|
var import_child_process28 = require("child_process");
|
|
34873
|
-
var
|
|
34874
|
-
var
|
|
34875
|
-
var
|
|
35110
|
+
var fs68 = __toESM(require("fs"));
|
|
35111
|
+
var os59 = __toESM(require("os"));
|
|
35112
|
+
var path75 = __toESM(require("path"));
|
|
34876
35113
|
var _onboardingSeam = {
|
|
34877
|
-
markerPath: (sessionId) =>
|
|
34878
|
-
exists: (p2) =>
|
|
35114
|
+
markerPath: (sessionId) => path75.join(os59.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
|
|
35115
|
+
exists: (p2) => fs68.existsSync(p2),
|
|
34879
35116
|
write: (p2) => {
|
|
34880
|
-
|
|
34881
|
-
|
|
35117
|
+
fs68.mkdirSync(path75.dirname(p2), { recursive: true });
|
|
35118
|
+
fs68.writeFileSync(p2, "");
|
|
34882
35119
|
},
|
|
34883
35120
|
disabled: () => {
|
|
34884
35121
|
const v = process.env.CODEAM_ONBOARDING_DISABLED;
|
|
@@ -34915,7 +35152,7 @@ function resolveRepoName(cwd) {
|
|
|
34915
35152
|
if (name) return name;
|
|
34916
35153
|
}
|
|
34917
35154
|
}
|
|
34918
|
-
const base =
|
|
35155
|
+
const base = path75.basename(cwd || "");
|
|
34919
35156
|
if (base && !isUuid(base)) return base;
|
|
34920
35157
|
return "this project";
|
|
34921
35158
|
}
|
|
@@ -35173,13 +35410,13 @@ var import_crypto5 = require("crypto");
|
|
|
35173
35410
|
|
|
35174
35411
|
// src/services/turn-files/git-changeset.ts
|
|
35175
35412
|
var import_child_process29 = require("child_process");
|
|
35176
|
-
var
|
|
35177
|
-
var
|
|
35413
|
+
var fs70 = __toESM(require("fs/promises"));
|
|
35414
|
+
var path77 = __toESM(require("path"));
|
|
35178
35415
|
|
|
35179
35416
|
// src/services/turn-files/review-ignore.ts
|
|
35180
35417
|
var import_ignore2 = __toESM(require("ignore"));
|
|
35181
|
-
var
|
|
35182
|
-
var
|
|
35418
|
+
var fs69 = __toESM(require("fs"));
|
|
35419
|
+
var path76 = __toESM(require("path"));
|
|
35183
35420
|
var CURATED_REVIEW_IGNORE = [
|
|
35184
35421
|
// Google Cloud SDK (the incident) — installs a huge python tree.
|
|
35185
35422
|
"google-cloud-sdk/",
|
|
@@ -35218,7 +35455,7 @@ var CURATED_REVIEW_IGNORE = [
|
|
|
35218
35455
|
function makeReviewIgnore(repoRoot) {
|
|
35219
35456
|
const ig = (0, import_ignore2.default)().add(CURATED_REVIEW_IGNORE);
|
|
35220
35457
|
try {
|
|
35221
|
-
const custom =
|
|
35458
|
+
const custom = fs69.readFileSync(path76.join(repoRoot, ".codeam", "reviewignore"), "utf8");
|
|
35222
35459
|
ig.add(custom);
|
|
35223
35460
|
} catch {
|
|
35224
35461
|
}
|
|
@@ -35263,7 +35500,7 @@ async function collectRepoChangeset(opts) {
|
|
|
35263
35500
|
let stats;
|
|
35264
35501
|
if (!truncated && row.fileStatus === "added" && numstatEntry === void 0) {
|
|
35265
35502
|
const lineCount = await readUntrackedLineCount(
|
|
35266
|
-
|
|
35503
|
+
path77.join(opts.repoRoot, row.filePath)
|
|
35267
35504
|
);
|
|
35268
35505
|
stats = { added: lineCount, removed: 0 };
|
|
35269
35506
|
} else {
|
|
@@ -35294,7 +35531,7 @@ function readUntrackedLineCount(absPath) {
|
|
|
35294
35531
|
}
|
|
35295
35532
|
async function defaultReadUntrackedLineCount(absPath) {
|
|
35296
35533
|
try {
|
|
35297
|
-
const content = await
|
|
35534
|
+
const content = await fs70.readFile(absPath, "utf8");
|
|
35298
35535
|
let count = 0;
|
|
35299
35536
|
let pos = -1;
|
|
35300
35537
|
while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
|
|
@@ -35386,7 +35623,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
35386
35623
|
});
|
|
35387
35624
|
}
|
|
35388
35625
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
35389
|
-
const
|
|
35626
|
+
const fs80 = await import("fs/promises");
|
|
35390
35627
|
const out2 = [];
|
|
35391
35628
|
await walk(workingDir, 0);
|
|
35392
35629
|
return out2;
|
|
@@ -35394,7 +35631,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
35394
35631
|
if (depth > maxDepth) return;
|
|
35395
35632
|
let entries = [];
|
|
35396
35633
|
try {
|
|
35397
|
-
const dirents = await
|
|
35634
|
+
const dirents = await fs80.readdir(dir, { withFileTypes: true });
|
|
35398
35635
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
35399
35636
|
} catch {
|
|
35400
35637
|
return;
|
|
@@ -35405,8 +35642,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
35405
35642
|
if (hasGit) {
|
|
35406
35643
|
out2.push({
|
|
35407
35644
|
repoRoot: dir,
|
|
35408
|
-
repoPath:
|
|
35409
|
-
repoName:
|
|
35645
|
+
repoPath: path77.relative(workingDir, dir),
|
|
35646
|
+
repoName: path77.basename(dir)
|
|
35410
35647
|
});
|
|
35411
35648
|
return;
|
|
35412
35649
|
}
|
|
@@ -35414,14 +35651,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
35414
35651
|
if (!entry.isDirectory) continue;
|
|
35415
35652
|
if (entry.name === "node_modules") continue;
|
|
35416
35653
|
if (entry.name === "dist" || entry.name === "build") continue;
|
|
35417
|
-
await walk(
|
|
35654
|
+
await walk(path77.join(dir, entry.name), depth + 1);
|
|
35418
35655
|
}
|
|
35419
35656
|
}
|
|
35420
35657
|
}
|
|
35421
35658
|
|
|
35422
35659
|
// src/services/turn-files/files-outbox.ts
|
|
35423
|
-
var
|
|
35424
|
-
var
|
|
35660
|
+
var fs71 = __toESM(require("fs/promises"));
|
|
35661
|
+
var path78 = __toESM(require("path"));
|
|
35425
35662
|
var import_os12 = require("os");
|
|
35426
35663
|
var HOME_OUTBOX_DIR = ".codeam/outbox";
|
|
35427
35664
|
var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -35454,16 +35691,16 @@ var FilesOutbox = class {
|
|
|
35454
35691
|
backoffIndex = 0;
|
|
35455
35692
|
stopped = false;
|
|
35456
35693
|
constructor(opts) {
|
|
35457
|
-
const base = opts.baseDir ??
|
|
35458
|
-
this.filePath =
|
|
35694
|
+
const base = opts.baseDir ?? path78.join(homeDir(), HOME_OUTBOX_DIR);
|
|
35695
|
+
this.filePath = path78.join(base, `${opts.sessionId}.jsonl`);
|
|
35459
35696
|
this.post = opts.post;
|
|
35460
35697
|
this.autoSchedule = opts.autoSchedule !== false;
|
|
35461
35698
|
}
|
|
35462
35699
|
/** Persist the entry to disk and trigger a flush. Returns once the
|
|
35463
35700
|
* line is durable on disk (not once the POST succeeds). */
|
|
35464
35701
|
async enqueue(entry) {
|
|
35465
|
-
await
|
|
35466
|
-
await
|
|
35702
|
+
await fs71.mkdir(path78.dirname(this.filePath), { recursive: true });
|
|
35703
|
+
await fs71.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
|
|
35467
35704
|
this.backoffIndex = 0;
|
|
35468
35705
|
if (this.autoSchedule) this.scheduleFlush(0);
|
|
35469
35706
|
}
|
|
@@ -35554,7 +35791,7 @@ var FilesOutbox = class {
|
|
|
35554
35791
|
async readAll() {
|
|
35555
35792
|
let raw = "";
|
|
35556
35793
|
try {
|
|
35557
|
-
raw = await
|
|
35794
|
+
raw = await fs71.readFile(this.filePath, "utf8");
|
|
35558
35795
|
} catch {
|
|
35559
35796
|
return [];
|
|
35560
35797
|
}
|
|
@@ -35578,12 +35815,12 @@ var FilesOutbox = class {
|
|
|
35578
35815
|
async rewrite(entries) {
|
|
35579
35816
|
const tmpPath = `${this.filePath}.${process.pid}.tmp`;
|
|
35580
35817
|
if (entries.length === 0) {
|
|
35581
|
-
await
|
|
35818
|
+
await fs71.unlink(this.filePath).catch(() => void 0);
|
|
35582
35819
|
return;
|
|
35583
35820
|
}
|
|
35584
35821
|
const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
35585
|
-
await
|
|
35586
|
-
await
|
|
35822
|
+
await fs71.writeFile(tmpPath, payload, "utf8");
|
|
35823
|
+
await fs71.rename(tmpPath, this.filePath);
|
|
35587
35824
|
}
|
|
35588
35825
|
};
|
|
35589
35826
|
function applyJitter(ms) {
|
|
@@ -36039,8 +36276,8 @@ async function postBudgetReached(opts, fetchImpl = fetch) {
|
|
|
36039
36276
|
|
|
36040
36277
|
// src/packs/gates.ts
|
|
36041
36278
|
var import_node_child_process30 = require("child_process");
|
|
36042
|
-
var
|
|
36043
|
-
var
|
|
36279
|
+
var fs72 = __toESM(require("fs"));
|
|
36280
|
+
var path79 = __toESM(require("path"));
|
|
36044
36281
|
var defaultCommandRunner = (file, args2, cwd, timeoutMs) => new Promise((resolve9) => {
|
|
36045
36282
|
(0, import_node_child_process30.execFile)(
|
|
36046
36283
|
file,
|
|
@@ -36077,14 +36314,14 @@ var NO_TEST_PLACEHOLDER = 'echo "Error: no test specified"';
|
|
|
36077
36314
|
var CHECKS_TIMEOUT_MS = 5 * 6e4;
|
|
36078
36315
|
function detectChecksCommand(cwd) {
|
|
36079
36316
|
try {
|
|
36080
|
-
const cfg = JSON.parse(
|
|
36317
|
+
const cfg = JSON.parse(fs72.readFileSync(path79.join(cwd, ".codeam", "pack.json"), "utf8"));
|
|
36081
36318
|
if (typeof cfg.checksCommand === "string" && cfg.checksCommand.trim().length > 0) {
|
|
36082
36319
|
return cfg.checksCommand.trim();
|
|
36083
36320
|
}
|
|
36084
36321
|
} catch {
|
|
36085
36322
|
}
|
|
36086
36323
|
try {
|
|
36087
|
-
const pkg = JSON.parse(
|
|
36324
|
+
const pkg = JSON.parse(fs72.readFileSync(path79.join(cwd, "package.json"), "utf8"));
|
|
36088
36325
|
const test = pkg.scripts?.test;
|
|
36089
36326
|
if (typeof test === "string" && test.trim().length > 0 && !test.includes(NO_TEST_PLACEHOLDER)) {
|
|
36090
36327
|
return "npm test";
|
|
@@ -36102,39 +36339,39 @@ ${res.stderr}`.trim();
|
|
|
36102
36339
|
}
|
|
36103
36340
|
|
|
36104
36341
|
// src/packs/run-store.ts
|
|
36105
|
-
var
|
|
36106
|
-
var
|
|
36342
|
+
var fs73 = __toESM(require("fs"));
|
|
36343
|
+
var path80 = __toESM(require("path"));
|
|
36107
36344
|
var crypto5 = __toESM(require("crypto"));
|
|
36108
36345
|
function packsDir(cwd) {
|
|
36109
|
-
return
|
|
36346
|
+
return path80.join(cwd, ".codeam", "packs");
|
|
36110
36347
|
}
|
|
36111
36348
|
function runDir(cwd, runId) {
|
|
36112
|
-
return
|
|
36349
|
+
return path80.join(packsDir(cwd), runId);
|
|
36113
36350
|
}
|
|
36114
36351
|
function newRunId() {
|
|
36115
36352
|
return `pk_${Date.now().toString(36)}_${crypto5.randomBytes(4).toString("hex")}`;
|
|
36116
36353
|
}
|
|
36117
36354
|
function writeJsonAtomic(file, value) {
|
|
36118
|
-
|
|
36355
|
+
fs73.mkdirSync(path80.dirname(file), { recursive: true });
|
|
36119
36356
|
const tmp = `${file}.tmp`;
|
|
36120
|
-
|
|
36121
|
-
|
|
36357
|
+
fs73.writeFileSync(tmp, JSON.stringify(value, null, 2));
|
|
36358
|
+
fs73.renameSync(tmp, file);
|
|
36122
36359
|
}
|
|
36123
36360
|
function saveRun(cwd, state) {
|
|
36124
|
-
writeJsonAtomic(
|
|
36361
|
+
writeJsonAtomic(path80.join(runDir(cwd, state.runId), "run.json"), state);
|
|
36125
36362
|
}
|
|
36126
36363
|
function saveStageHandoff(cwd, runId, stageIndex, role, handoff) {
|
|
36127
36364
|
const name = `${String(stageIndex + 1).padStart(2, "0")}-${role}.json`;
|
|
36128
|
-
writeJsonAtomic(
|
|
36365
|
+
writeJsonAtomic(path80.join(runDir(cwd, runId), name), handoff);
|
|
36129
36366
|
}
|
|
36130
36367
|
function loadLatestRun(cwd) {
|
|
36131
36368
|
try {
|
|
36132
36369
|
const dir = packsDir(cwd);
|
|
36133
|
-
const entries =
|
|
36370
|
+
const entries = fs73.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
36134
36371
|
for (let i = entries.length - 1; i >= 0; i--) {
|
|
36135
|
-
const file =
|
|
36372
|
+
const file = path80.join(dir, entries[i], "run.json");
|
|
36136
36373
|
try {
|
|
36137
|
-
const parsed = JSON.parse(
|
|
36374
|
+
const parsed = JSON.parse(fs73.readFileSync(file, "utf8"));
|
|
36138
36375
|
if (parsed && typeof parsed.runId === "string") return parsed;
|
|
36139
36376
|
} catch {
|
|
36140
36377
|
}
|
|
@@ -36145,17 +36382,17 @@ function loadLatestRun(cwd) {
|
|
|
36145
36382
|
}
|
|
36146
36383
|
function ensureLedgerIgnored(cwd) {
|
|
36147
36384
|
try {
|
|
36148
|
-
const gitDir =
|
|
36149
|
-
if (!
|
|
36150
|
-
const exclude =
|
|
36385
|
+
const gitDir = path80.join(cwd, ".git");
|
|
36386
|
+
if (!fs73.existsSync(gitDir)) return;
|
|
36387
|
+
const exclude = path80.join(gitDir, "info", "exclude");
|
|
36151
36388
|
let existing = "";
|
|
36152
36389
|
try {
|
|
36153
|
-
existing =
|
|
36390
|
+
existing = fs73.readFileSync(exclude, "utf8");
|
|
36154
36391
|
} catch {
|
|
36155
36392
|
}
|
|
36156
36393
|
if (existing.includes(".codeam/packs/")) return;
|
|
36157
|
-
|
|
36158
|
-
|
|
36394
|
+
fs73.mkdirSync(path80.dirname(exclude), { recursive: true });
|
|
36395
|
+
fs73.writeFileSync(exclude, `${existing.trimEnd()}
|
|
36159
36396
|
.codeam/packs/
|
|
36160
36397
|
`.trimStart());
|
|
36161
36398
|
} catch {
|
|
@@ -36746,35 +36983,35 @@ function buildAcpPromptBlocks(payload) {
|
|
|
36746
36983
|
}
|
|
36747
36984
|
|
|
36748
36985
|
// src/agents/agent-standard.ts
|
|
36749
|
-
var
|
|
36750
|
-
var
|
|
36751
|
-
var
|
|
36752
|
-
function ensureAgentStandard(homeDir2 =
|
|
36986
|
+
var fs75 = __toESM(require("fs"));
|
|
36987
|
+
var path82 = __toESM(require("path"));
|
|
36988
|
+
var os60 = __toESM(require("os"));
|
|
36989
|
+
function ensureAgentStandard(homeDir2 = os60.homedir()) {
|
|
36753
36990
|
try {
|
|
36754
|
-
const file =
|
|
36991
|
+
const file = path82.join(homeDir2, ".claude", "CLAUDE.md");
|
|
36755
36992
|
let existing = "";
|
|
36756
36993
|
try {
|
|
36757
|
-
existing =
|
|
36994
|
+
existing = fs75.readFileSync(file, "utf8");
|
|
36758
36995
|
} catch {
|
|
36759
36996
|
}
|
|
36760
36997
|
if (existing.includes(AGENT_STANDARD_MARKER)) return;
|
|
36761
|
-
|
|
36998
|
+
fs75.mkdirSync(path82.dirname(file), { recursive: true });
|
|
36762
36999
|
const next = existing.trim() ? `${existing.trimEnd()}
|
|
36763
37000
|
|
|
36764
37001
|
${AGENT_STANDARD_BLOCK}
|
|
36765
37002
|
` : `${AGENT_STANDARD_BLOCK}
|
|
36766
37003
|
`;
|
|
36767
|
-
|
|
37004
|
+
fs75.writeFileSync(file, next);
|
|
36768
37005
|
} catch {
|
|
36769
37006
|
}
|
|
36770
37007
|
}
|
|
36771
37008
|
var _agentStandardSeam = {
|
|
36772
37009
|
isLocalSession: () => isLocalSession(),
|
|
36773
|
-
markerPath: (sessionId) =>
|
|
36774
|
-
exists: (p2) =>
|
|
37010
|
+
markerPath: (sessionId) => path82.join(os60.homedir(), ".codeam", "agent-standard", `${sessionId}.done`),
|
|
37011
|
+
exists: (p2) => fs75.existsSync(p2),
|
|
36775
37012
|
write: (p2) => {
|
|
36776
|
-
|
|
36777
|
-
|
|
37013
|
+
fs75.mkdirSync(path82.dirname(p2), { recursive: true });
|
|
37014
|
+
fs75.writeFileSync(p2, "");
|
|
36778
37015
|
}
|
|
36779
37016
|
};
|
|
36780
37017
|
function isClaude(agent) {
|
|
@@ -36878,20 +37115,111 @@ async function beadsActionH(ctx) {
|
|
|
36878
37115
|
}
|
|
36879
37116
|
return;
|
|
36880
37117
|
}
|
|
37118
|
+
function rebindSessionHandles(ctx, outcome) {
|
|
37119
|
+
Object.assign(ctx, outcome.handles);
|
|
37120
|
+
return outcome;
|
|
37121
|
+
}
|
|
37122
|
+
async function routeSquadTask(ctx, target) {
|
|
37123
|
+
const { squad, routeToAgent } = ctx;
|
|
37124
|
+
if (!routeToAgent) {
|
|
37125
|
+
return { ok: false, error: "Routing to another agent is not supported on this session." };
|
|
37126
|
+
}
|
|
37127
|
+
const roster = squad?.roster;
|
|
37128
|
+
if (roster && !roster.agents.some((a) => a.agentId === target)) {
|
|
37129
|
+
return { ok: false, error: `Unknown agent '${target}' \u2014 not in your squad.` };
|
|
37130
|
+
}
|
|
37131
|
+
const member = squad?.member(target);
|
|
37132
|
+
const fastPathArmed = Boolean(member && (member.provisioned || member.binaryVerified));
|
|
37133
|
+
let { result } = rebindSessionHandles(ctx, await routeToAgent(target));
|
|
37134
|
+
if (!result.ok && fastPathArmed) {
|
|
37135
|
+
log.warn(
|
|
37136
|
+
"acpRunner",
|
|
37137
|
+
`squad: fast-path route to ${target} failed (${result.error}) \u2014 retrying full path`
|
|
37138
|
+
);
|
|
37139
|
+
({ result } = rebindSessionHandles(ctx, await routeToAgent(target, { skipFastPath: true })));
|
|
37140
|
+
}
|
|
37141
|
+
if (!result.ok) {
|
|
37142
|
+
return { ok: false, error: result.error ?? `Couldn't switch to ${target}.` };
|
|
37143
|
+
}
|
|
37144
|
+
return { ok: true };
|
|
37145
|
+
}
|
|
37146
|
+
function prefixSquadContext(ctx, blocks) {
|
|
37147
|
+
if (ctx.pendingHandoff?.current) {
|
|
37148
|
+
blocks.unshift({ type: "text", text: ctx.pendingHandoff.current });
|
|
37149
|
+
ctx.pendingHandoff.current = null;
|
|
37150
|
+
}
|
|
37151
|
+
const { squad, opts } = ctx;
|
|
37152
|
+
if (!squad) return;
|
|
37153
|
+
const member = squad.member(opts.agent);
|
|
37154
|
+
if (squad.turnCount() > member.lastTurnIndex) {
|
|
37155
|
+
const otherEntries = squad.entriesSince(member.lastTurnIndex).filter((e) => e.agentId !== opts.agent);
|
|
37156
|
+
const briefing = buildDeltaBriefing(otherEntries);
|
|
37157
|
+
if (briefing) blocks.unshift({ type: "text", text: briefing });
|
|
37158
|
+
}
|
|
37159
|
+
const roster = squad.roster;
|
|
37160
|
+
if (roster && member.lastTurnIndex === 0) {
|
|
37161
|
+
const preamble = buildTeamPreamble(roster, opts.agent, {
|
|
37162
|
+
handoffInstructions: roster.handoffsEnabled === true
|
|
37163
|
+
});
|
|
37164
|
+
if (preamble) blocks.unshift({ type: "text", text: preamble });
|
|
37165
|
+
}
|
|
37166
|
+
}
|
|
37167
|
+
function recordSquadTurn(ctx, prompt, replySummary) {
|
|
37168
|
+
const { squad, opts } = ctx;
|
|
37169
|
+
if (!squad) return;
|
|
37170
|
+
squad.recordTurn({
|
|
37171
|
+
agentId: opts.agent,
|
|
37172
|
+
prompt,
|
|
37173
|
+
replySummary,
|
|
37174
|
+
// TurnFileAggregator owns per-turn file changesets end-to-end (git diff →
|
|
37175
|
+
// outbox POST) and exposes no path list, and its flush is fire-and-forget,
|
|
37176
|
+
// so there is nothing accurate to attribute synchronously here. The
|
|
37177
|
+
// briefing simply omits the files clause rather than guessing.
|
|
37178
|
+
filesTouched: []
|
|
37179
|
+
});
|
|
37180
|
+
squad.member(opts.agent).lastTurnIndex = squad.turnCount();
|
|
37181
|
+
}
|
|
37182
|
+
function handoffTargets(ctx) {
|
|
37183
|
+
const roster = ctx.squad?.roster;
|
|
37184
|
+
if (!roster) return /* @__PURE__ */ new Set();
|
|
37185
|
+
return new Set(roster.agents.map((a) => a.agentId).filter((id) => id !== ctx.opts.agent));
|
|
37186
|
+
}
|
|
37187
|
+
function resolvePendingProposal(ctx, requestedAgentId) {
|
|
37188
|
+
const slot = ctx.pendingProposal;
|
|
37189
|
+
const pending = slot?.current;
|
|
37190
|
+
if (!slot || !pending) return;
|
|
37191
|
+
slot.current = null;
|
|
37192
|
+
const accepted = requestedAgentId === pending.toAgentId;
|
|
37193
|
+
log.info(
|
|
37194
|
+
"acpRunner",
|
|
37195
|
+
`squad: handoff ${pending.proposalId} ${accepted ? "accepted" : "declined"}`
|
|
37196
|
+
);
|
|
37197
|
+
void ctx.postSquadEvent?.("handoff_resolved", {
|
|
37198
|
+
proposalId: pending.proposalId,
|
|
37199
|
+
accepted
|
|
37200
|
+
});
|
|
37201
|
+
}
|
|
37202
|
+
function emitHandoffProposal(ctx, proposal) {
|
|
37203
|
+
const { squad, pendingProposal, postSquadEvent, opts, cmd } = ctx;
|
|
37204
|
+
if (!proposal || !pendingProposal || !postSquadEvent) return;
|
|
37205
|
+
if (squad?.roster?.handoffsEnabled !== true) return;
|
|
37206
|
+
if (pendingProposal.current) {
|
|
37207
|
+
log.info("acpRunner", "squad: dropping handoff proposal \u2014 one is already pending");
|
|
37208
|
+
return;
|
|
37209
|
+
}
|
|
37210
|
+
const record2 = {
|
|
37211
|
+
proposalId: `hp-${cmd.id}`,
|
|
37212
|
+
fromAgentId: opts.agent,
|
|
37213
|
+
toAgentId: proposal.to,
|
|
37214
|
+
reason: proposal.reason,
|
|
37215
|
+
prompt: proposal.prompt
|
|
37216
|
+
};
|
|
37217
|
+
pendingProposal.current = record2;
|
|
37218
|
+
log.info("acpRunner", `squad: handoff proposed ${opts.agent} \u2192 ${record2.toAgentId}`);
|
|
37219
|
+
void postSquadEvent("handoff_proposed", { ...record2 });
|
|
37220
|
+
}
|
|
36881
37221
|
async function startTaskH(ctx) {
|
|
36882
|
-
const {
|
|
36883
|
-
cmd,
|
|
36884
|
-
client: client3,
|
|
36885
|
-
relay,
|
|
36886
|
-
streaming,
|
|
36887
|
-
opts,
|
|
36888
|
-
history,
|
|
36889
|
-
turnFiles,
|
|
36890
|
-
publisher,
|
|
36891
|
-
recentStderr,
|
|
36892
|
-
budgetRecovery,
|
|
36893
|
-
budgetReachedFlag
|
|
36894
|
-
} = ctx;
|
|
37222
|
+
const { cmd, relay, streaming, opts, turnFiles, publisher, recentStderr, budgetReachedFlag } = ctx;
|
|
36895
37223
|
const payload = cmd.payload;
|
|
36896
37224
|
const blocks = buildAcpPromptBlocks(payload ?? {});
|
|
36897
37225
|
if (blocks.length === 0) {
|
|
@@ -36899,6 +37227,17 @@ async function startTaskH(ctx) {
|
|
|
36899
37227
|
await relay.sendResult(cmd.id, "failed", { error: "empty prompt" });
|
|
36900
37228
|
return;
|
|
36901
37229
|
}
|
|
37230
|
+
const requestedAgentId = typeof payload?.agentId === "string" ? payload.agentId.trim() : "";
|
|
37231
|
+
resolvePendingProposal(ctx, requestedAgentId);
|
|
37232
|
+
if (requestedAgentId.length > 0 && requestedAgentId !== opts.agent) {
|
|
37233
|
+
const routed = await routeSquadTask(ctx, requestedAgentId);
|
|
37234
|
+
if (!routed.ok) {
|
|
37235
|
+
log.warn("acpRunner", `start_task routing to ${requestedAgentId} failed: ${routed.error}`);
|
|
37236
|
+
await relay.sendResult(cmd.id, "failed", { error: routed.error });
|
|
37237
|
+
return;
|
|
37238
|
+
}
|
|
37239
|
+
}
|
|
37240
|
+
const { client: client3, history, budgetRecovery } = ctx;
|
|
36902
37241
|
const promptText = blocks.filter((b) => b.type === "text").map((b) => b.text).join("\n");
|
|
36903
37242
|
const imageCount = blocks.filter((b) => b.type === "image").length;
|
|
36904
37243
|
log.info(
|
|
@@ -36912,10 +37251,7 @@ async function startTaskH(ctx) {
|
|
|
36912
37251
|
await streaming.beginTurn();
|
|
36913
37252
|
history.appendUserPrompt(promptText);
|
|
36914
37253
|
maybePrefaceAgentStandard(blocks, opts.agent, opts.sessionId);
|
|
36915
|
-
|
|
36916
|
-
blocks.unshift({ type: "text", text: ctx.pendingHandoff.current });
|
|
36917
|
-
ctx.pendingHandoff.current = null;
|
|
36918
|
-
}
|
|
37254
|
+
prefixSquadContext(ctx, blocks);
|
|
36919
37255
|
let turnClosed = false;
|
|
36920
37256
|
try {
|
|
36921
37257
|
const reply = await client3.prompt(blocks);
|
|
@@ -36967,12 +37303,19 @@ async function startTaskH(ctx) {
|
|
|
36967
37303
|
} else {
|
|
36968
37304
|
await streaming.closeTurnWithInteractiveDetection();
|
|
36969
37305
|
turnClosed = true;
|
|
36970
|
-
const
|
|
37306
|
+
const { cleanText, proposal } = extractHandoffProposal(
|
|
37307
|
+
finalText,
|
|
37308
|
+
opts.agent,
|
|
37309
|
+
handoffTargets(ctx)
|
|
37310
|
+
);
|
|
37311
|
+
const replyLine = formatAgentReplyLine(cleanText);
|
|
36971
37312
|
if (replyLine.length > 0) {
|
|
36972
37313
|
showInfo(replyLine);
|
|
36973
37314
|
}
|
|
36974
|
-
history.appendAgentReply(
|
|
37315
|
+
history.appendAgentReply(cleanText);
|
|
36975
37316
|
void history.flush();
|
|
37317
|
+
recordSquadTurn(ctx, promptText, cleanText);
|
|
37318
|
+
emitHandoffProposal(ctx, proposal);
|
|
36976
37319
|
void publisher.publishOutput({
|
|
36977
37320
|
type: "input_suggestion",
|
|
36978
37321
|
content: ACP_QUICK_REPLIES,
|
|
@@ -37771,14 +38114,18 @@ var StreamingState = class {
|
|
|
37771
38114
|
}
|
|
37772
38115
|
const cumulativeContent = reconcileCumulative(existing?.content ?? "", delta.delta);
|
|
37773
38116
|
this.streamingChunks.set(chunkId, { kind: delta.kind, content: cumulativeContent });
|
|
38117
|
+
let fenceCut = -1;
|
|
37774
38118
|
if (delta.kind === "text") {
|
|
37775
38119
|
this.recomputeText();
|
|
37776
|
-
|
|
38120
|
+
fenceCut = handoffFenceStart(this.text);
|
|
38121
|
+
const visibleText = fenceCut === -1 ? this.text : this.text.slice(0, fenceCut).trimEnd();
|
|
38122
|
+
void this.publisher.publishOutput({ type: "text", content: visibleText, done: false });
|
|
37777
38123
|
}
|
|
38124
|
+
const visibleChunkContent = delta.kind === "text" && fenceCut !== -1 ? cumulativeContent.slice(0, fenceCut).trimEnd() : cumulativeContent;
|
|
37778
38125
|
void this.publisher.publishStreamingChunk({
|
|
37779
38126
|
chunkId,
|
|
37780
38127
|
kind: delta.kind,
|
|
37781
|
-
content:
|
|
38128
|
+
content: visibleChunkContent,
|
|
37782
38129
|
isFinal: false
|
|
37783
38130
|
});
|
|
37784
38131
|
}
|
|
@@ -37808,8 +38155,27 @@ var StreamingState = class {
|
|
|
37808
38155
|
* spuriously and strand the runner with a free-form pending state
|
|
37809
38156
|
* the user can't see / answer.
|
|
37810
38157
|
*/
|
|
38158
|
+
/**
|
|
38159
|
+
* Presentation-only view of a text buffer: everything BEFORE a
|
|
38160
|
+
* ```codeam-handoff fence. The fence is protocol litter the app renders as
|
|
38161
|
+
* a proposal card (see `handoff-protocol.ts`) — it must never reach the
|
|
38162
|
+
* user, and the TERMINAL frames (`done:true` / `isFinal:true`) are the ones
|
|
38163
|
+
* that persist, so suppressing it only while streaming would still leave it
|
|
38164
|
+
* pinned on the finished bubble. Internal state is untouched:
|
|
38165
|
+
* {@link getCurrentText} keeps returning the RAW text so the turn-close
|
|
38166
|
+
* extraction can parse the proposal out of it.
|
|
38167
|
+
*
|
|
38168
|
+
* Masked-aware (`stripHandoffFences`), unlike the live-stream `append()`
|
|
38169
|
+
* cut (`handoffFenceStart`, unmasked): a TERMINAL frame is the one that
|
|
38170
|
+
* PERSISTS, so cutting on a fence quoted as an example inside a
|
|
38171
|
+
* 4+-backtick block here would permanently truncate the bubble. The live
|
|
38172
|
+
* cut stays unmasked/cheap — a mid-stream example is never terminal.
|
|
38173
|
+
*/
|
|
38174
|
+
visible(text) {
|
|
38175
|
+
return stripHandoffFences(text);
|
|
38176
|
+
}
|
|
37811
38177
|
async closeAll() {
|
|
37812
|
-
const finalText = this.text;
|
|
38178
|
+
const finalText = this.visible(this.text);
|
|
37813
38179
|
this.text = "";
|
|
37814
38180
|
await Promise.all([
|
|
37815
38181
|
this.publisher.publishOutput({ type: "text", content: finalText, done: true }),
|
|
@@ -37853,7 +38219,9 @@ var StreamingState = class {
|
|
|
37853
38219
|
([chunkId, { kind, content }]) => this.publisher.publishStreamingChunk({
|
|
37854
38220
|
chunkId,
|
|
37855
38221
|
kind,
|
|
37856
|
-
|
|
38222
|
+
// Terminal frame — same fence suppression the live deltas apply, so
|
|
38223
|
+
// a proposal fence never survives on the finalised bubble.
|
|
38224
|
+
content: kind === "text" ? this.visible(content) : content,
|
|
37857
38225
|
isFinal: true
|
|
37858
38226
|
})
|
|
37859
38227
|
)
|
|
@@ -37880,7 +38248,7 @@ var StreamingState = class {
|
|
|
37880
38248
|
* text done:true chunk with the full cumulative).
|
|
37881
38249
|
*/
|
|
37882
38250
|
async closeTurnWithInteractiveDetection() {
|
|
37883
|
-
const finalText = this.text;
|
|
38251
|
+
const finalText = this.visible(this.text);
|
|
37884
38252
|
this.text = "";
|
|
37885
38253
|
const flushSc = this.flushStreamingChunks();
|
|
37886
38254
|
const extracted = extractSelectPrompt(finalText);
|
|
@@ -38383,13 +38751,32 @@ async function runAcpSession(opts) {
|
|
|
38383
38751
|
acpSessionId = id;
|
|
38384
38752
|
},
|
|
38385
38753
|
switchAgentForSession,
|
|
38386
|
-
pendingHandoff
|
|
38754
|
+
pendingHandoff,
|
|
38755
|
+
// Agent Squad: roster/journal state, the @-mention route, the
|
|
38756
|
+
// single-slot proposal, and the SAME serialized event chain the
|
|
38757
|
+
// switch uses (so proposal events can't overtake switch events).
|
|
38758
|
+
squad,
|
|
38759
|
+
routeToAgent,
|
|
38760
|
+
pendingProposal,
|
|
38761
|
+
emitSwitchEvent
|
|
38387
38762
|
);
|
|
38388
38763
|
},
|
|
38389
38764
|
{ id: opts.agent, name: opts.agent, displayName: opts.agent }
|
|
38390
38765
|
);
|
|
38391
38766
|
const HANDOFF_MAX_CHARS = 16e3;
|
|
38392
38767
|
const pendingHandoff = { current: null };
|
|
38768
|
+
const squad = new SquadState({ sessionId: opts.sessionId });
|
|
38769
|
+
const refreshSquadRoster = () => {
|
|
38770
|
+
void fetchSquadRoster({
|
|
38771
|
+
sessionId: opts.sessionId,
|
|
38772
|
+
pluginId: opts.pluginId,
|
|
38773
|
+
pluginAuthToken: opts.pluginAuthToken
|
|
38774
|
+
}).then((roster) => {
|
|
38775
|
+
if (roster) squad.roster = roster;
|
|
38776
|
+
});
|
|
38777
|
+
};
|
|
38778
|
+
refreshSquadRoster();
|
|
38779
|
+
const pendingProposal = { current: null };
|
|
38393
38780
|
let switchCredentialEnv = {};
|
|
38394
38781
|
const relaunchWith = async (nextAgent) => {
|
|
38395
38782
|
try {
|
|
@@ -38399,6 +38786,7 @@ async function runAcpSession(opts) {
|
|
|
38399
38786
|
await streaming.closeAll();
|
|
38400
38787
|
const prevAgent = opts.agent;
|
|
38401
38788
|
const transcript = history.recentTranscript(HANDOFF_MAX_CHARS);
|
|
38789
|
+
squad.member(prevAgent).acpSessionId = acpSessionId;
|
|
38402
38790
|
await client3.stop();
|
|
38403
38791
|
const adapter = await resolveAcpAdapterWithRetry(nextAgent);
|
|
38404
38792
|
if (!adapter) throw new Error(`no ACP adapter available for ${nextAgent}`);
|
|
@@ -38448,31 +38836,74 @@ async function runAcpSession(opts) {
|
|
|
38448
38836
|
payload
|
|
38449
38837
|
})
|
|
38450
38838
|
);
|
|
38451
|
-
const
|
|
38452
|
-
|
|
38453
|
-
|
|
38454
|
-
|
|
38455
|
-
|
|
38456
|
-
|
|
38457
|
-
|
|
38458
|
-
|
|
38459
|
-
|
|
38460
|
-
|
|
38461
|
-
|
|
38462
|
-
|
|
38463
|
-
switchCredentialEnv = provisionAgentCredentials(agentId, auth);
|
|
38464
|
-
},
|
|
38465
|
-
ensureBinary: (agentId, installScript) => ensureAgentBinaryForSwitch(agentId, installScript),
|
|
38466
|
-
swapRuntime: relaunchWith,
|
|
38467
|
-
revertRuntime: relaunchWith,
|
|
38468
|
-
persistAgent: (agentId) => setSessionAgent(opts.pluginId, agentId),
|
|
38469
|
-
reannounce: (agentId) => {
|
|
38470
|
-
relay.setAgentMeta({ id: agentId, name: agentId, displayName: agentId });
|
|
38471
|
-
relay.reannounceAgents();
|
|
38472
|
-
}
|
|
38839
|
+
const switchDeps = {
|
|
38840
|
+
currentAgent: () => opts.agent,
|
|
38841
|
+
postEvent: emitSwitchEvent,
|
|
38842
|
+
fetchCredential: (agentId) => fetchProvisionCredential({
|
|
38843
|
+
agentId,
|
|
38844
|
+
sessionId: opts.sessionId,
|
|
38845
|
+
pluginId: opts.pluginId,
|
|
38846
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
38847
|
+
includeInstallScript: true
|
|
38848
|
+
}),
|
|
38849
|
+
provisionCredential: (agentId, auth) => {
|
|
38850
|
+
switchCredentialEnv = provisionAgentCredentials(agentId, auth);
|
|
38473
38851
|
},
|
|
38474
|
-
|
|
38475
|
-
|
|
38852
|
+
ensureBinary: (agentId, installScript) => ensureAgentBinaryForSwitch(agentId, installScript),
|
|
38853
|
+
swapRuntime: relaunchWith,
|
|
38854
|
+
revertRuntime: relaunchWith,
|
|
38855
|
+
persistAgent: (agentId) => setSessionAgent(opts.pluginId, agentId),
|
|
38856
|
+
reannounce: (agentId) => {
|
|
38857
|
+
relay.setAgentMeta({ id: agentId, name: agentId, displayName: agentId });
|
|
38858
|
+
relay.reannounceAgents();
|
|
38859
|
+
}
|
|
38860
|
+
};
|
|
38861
|
+
const switchAgentForSession = async (rawAgentId) => {
|
|
38862
|
+
const result = await performAgentSwitch(switchDeps, rawAgentId);
|
|
38863
|
+
if (result.ok) refreshSquadRoster();
|
|
38864
|
+
return result;
|
|
38865
|
+
};
|
|
38866
|
+
const sessionHandles = () => ({
|
|
38867
|
+
client: client3,
|
|
38868
|
+
acpSessionId,
|
|
38869
|
+
history,
|
|
38870
|
+
jsonlHistory,
|
|
38871
|
+
agentCaps,
|
|
38872
|
+
budgetRecovery
|
|
38873
|
+
});
|
|
38874
|
+
const routeToAgent = async (target, routeOpts = {}) => {
|
|
38875
|
+
const m = squad.member(target);
|
|
38876
|
+
const fast = routeOpts.skipFastPath !== true;
|
|
38877
|
+
const result = await performAgentSwitch(switchDeps, target, {
|
|
38878
|
+
skipProvision: fast && m.provisioned,
|
|
38879
|
+
skipInstall: fast && m.binaryVerified
|
|
38880
|
+
});
|
|
38881
|
+
if (!result.ok) {
|
|
38882
|
+
if (fast) {
|
|
38883
|
+
m.provisioned = false;
|
|
38884
|
+
m.binaryVerified = false;
|
|
38885
|
+
}
|
|
38886
|
+
return { result, handles: sessionHandles() };
|
|
38887
|
+
}
|
|
38888
|
+
m.provisioned = true;
|
|
38889
|
+
m.binaryVerified = true;
|
|
38890
|
+
if (m.acpSessionId && agentCaps?.loadSession) {
|
|
38891
|
+
try {
|
|
38892
|
+
await client3.loadSession(m.acpSessionId);
|
|
38893
|
+
acpSessionId = m.acpSessionId;
|
|
38894
|
+
history.switchActiveSession(m.acpSessionId);
|
|
38895
|
+
pendingHandoff.current = null;
|
|
38896
|
+
log.info(
|
|
38897
|
+
"acpRunner",
|
|
38898
|
+
`squad: resumed ${target}'s conversation ${m.acpSessionId.slice(0, 8)}`
|
|
38899
|
+
);
|
|
38900
|
+
} catch (err) {
|
|
38901
|
+
log.warn("acpRunner", `squad: resume for ${target} failed: ${describeError(err)}`);
|
|
38902
|
+
}
|
|
38903
|
+
}
|
|
38904
|
+
refreshSquadRoster();
|
|
38905
|
+
return { result, handles: sessionHandles() };
|
|
38906
|
+
};
|
|
38476
38907
|
await onboardingWelcomeDone;
|
|
38477
38908
|
relay.start();
|
|
38478
38909
|
void createWakeCredentialProbe({
|
|
@@ -38503,7 +38934,7 @@ async function runAcpSession(opts) {
|
|
|
38503
38934
|
await new Promise(() => {
|
|
38504
38935
|
});
|
|
38505
38936
|
}
|
|
38506
|
-
async function handleCommand(cmd, client3, relay, acpSessionId, streaming, opts, history, jsonlHistory, agentCaps, turnFiles, getBeads, publisher, recentStderr, budgetRecovery, budgetReachedFlag, onActiveSessionChanged, switchAgent, pendingHandoff) {
|
|
38937
|
+
async function handleCommand(cmd, client3, relay, acpSessionId, streaming, opts, history, jsonlHistory, agentCaps, turnFiles, getBeads, publisher, recentStderr, budgetRecovery, budgetReachedFlag, onActiveSessionChanged, switchAgent, pendingHandoff, squad, routeToAgent, pendingProposal, postSquadEvent) {
|
|
38507
38938
|
const session = {
|
|
38508
38939
|
client: client3,
|
|
38509
38940
|
relay,
|
|
@@ -38521,7 +38952,11 @@ async function handleCommand(cmd, client3, relay, acpSessionId, streaming, opts,
|
|
|
38521
38952
|
budgetReachedFlag,
|
|
38522
38953
|
onActiveSessionChanged,
|
|
38523
38954
|
switchAgent,
|
|
38524
|
-
pendingHandoff
|
|
38955
|
+
pendingHandoff,
|
|
38956
|
+
squad,
|
|
38957
|
+
routeToAgent,
|
|
38958
|
+
pendingProposal,
|
|
38959
|
+
postSquadEvent
|
|
38525
38960
|
};
|
|
38526
38961
|
await dispatchAcpCommand(assembleAcpCommandContext(session, cmd));
|
|
38527
38962
|
}
|
|
@@ -39581,9 +40016,9 @@ function startClaudeCredentialSync(opts) {
|
|
|
39581
40016
|
}
|
|
39582
40017
|
|
|
39583
40018
|
// src/beads/workflow-hint.ts
|
|
39584
|
-
var
|
|
39585
|
-
var
|
|
39586
|
-
var
|
|
40019
|
+
var fs76 = __toESM(require("fs"));
|
|
40020
|
+
var path83 = __toESM(require("path"));
|
|
40021
|
+
var os61 = __toESM(require("os"));
|
|
39587
40022
|
var BEADS_HINT_MARKER = "<!-- codeam:beads-workflow -->";
|
|
39588
40023
|
var BEADS_HINT = `${BEADS_HINT_MARKER}
|
|
39589
40024
|
# Beads (bd) \u2014 task tracking + persistent memory (ALWAYS use it)
|
|
@@ -39597,22 +40032,22 @@ This environment uses **bd (beads)** for issue/task tracking and persistent memo
|
|
|
39597
40032
|
- \`bd ready\` (available work) \xB7 \`bd show <id>\` \xB7 \`bd update <id> --claim\` \xB7 \`bd close <id>\`.
|
|
39598
40033
|
- Use \`bd remember "..."\` for persistent knowledge \u2014 do NOT use MEMORY.md files.
|
|
39599
40034
|
${BEADS_HINT_MARKER}`;
|
|
39600
|
-
function ensureBeadsWorkflowHint(homeDir2 =
|
|
40035
|
+
function ensureBeadsWorkflowHint(homeDir2 = os61.homedir()) {
|
|
39601
40036
|
try {
|
|
39602
|
-
const file =
|
|
40037
|
+
const file = path83.join(homeDir2, ".claude", "CLAUDE.md");
|
|
39603
40038
|
let existing = "";
|
|
39604
40039
|
try {
|
|
39605
|
-
existing =
|
|
40040
|
+
existing = fs76.readFileSync(file, "utf8");
|
|
39606
40041
|
} catch {
|
|
39607
40042
|
}
|
|
39608
40043
|
if (existing.includes(BEADS_HINT_MARKER)) return;
|
|
39609
|
-
|
|
40044
|
+
fs76.mkdirSync(path83.dirname(file), { recursive: true });
|
|
39610
40045
|
const next = existing.trim() ? `${existing.trimEnd()}
|
|
39611
40046
|
|
|
39612
40047
|
${BEADS_HINT}
|
|
39613
40048
|
` : `${BEADS_HINT}
|
|
39614
40049
|
`;
|
|
39615
|
-
|
|
40050
|
+
fs76.writeFileSync(file, next);
|
|
39616
40051
|
} catch {
|
|
39617
40052
|
}
|
|
39618
40053
|
}
|
|
@@ -39984,7 +40419,7 @@ var AcpDriver = class {
|
|
|
39984
40419
|
};
|
|
39985
40420
|
|
|
39986
40421
|
// src/baton/transcript-mirror.ts
|
|
39987
|
-
var
|
|
40422
|
+
var fs77 = __toESM(require("fs"));
|
|
39988
40423
|
var TranscriptMirror = class {
|
|
39989
40424
|
constructor(deps) {
|
|
39990
40425
|
this.deps = deps;
|
|
@@ -40051,7 +40486,7 @@ var TranscriptMirror = class {
|
|
|
40051
40486
|
}
|
|
40052
40487
|
};
|
|
40053
40488
|
function defaultWatch(file, onChange) {
|
|
40054
|
-
const w3 =
|
|
40489
|
+
const w3 = fs77.watch(file, { persistent: false }, () => onChange());
|
|
40055
40490
|
return () => w3.close();
|
|
40056
40491
|
}
|
|
40057
40492
|
|
|
@@ -40349,16 +40784,16 @@ function keepDeviceAwake(deps = {}) {
|
|
|
40349
40784
|
}
|
|
40350
40785
|
|
|
40351
40786
|
// src/agents/claude/onboarding.ts
|
|
40352
|
-
var
|
|
40353
|
-
var
|
|
40354
|
-
var
|
|
40787
|
+
var fs78 = __toESM(require("fs"));
|
|
40788
|
+
var os63 = __toESM(require("os"));
|
|
40789
|
+
var path84 = __toESM(require("path"));
|
|
40355
40790
|
var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
|
|
40356
40791
|
function ensureClaudeOnboarded(cwd) {
|
|
40357
40792
|
try {
|
|
40358
|
-
const file =
|
|
40793
|
+
const file = path84.join(os63.homedir(), ".claude.json");
|
|
40359
40794
|
let config = {};
|
|
40360
40795
|
try {
|
|
40361
|
-
config = JSON.parse(
|
|
40796
|
+
config = JSON.parse(fs78.readFileSync(file, "utf8"));
|
|
40362
40797
|
} catch {
|
|
40363
40798
|
}
|
|
40364
40799
|
let changed = false;
|
|
@@ -40383,8 +40818,8 @@ function ensureClaudeOnboarded(cwd) {
|
|
|
40383
40818
|
}
|
|
40384
40819
|
}
|
|
40385
40820
|
if (!changed) return;
|
|
40386
|
-
|
|
40387
|
-
|
|
40821
|
+
fs78.mkdirSync(path84.dirname(file), { recursive: true });
|
|
40822
|
+
fs78.writeFileSync(file, JSON.stringify(config, null, 2));
|
|
40388
40823
|
log.info(
|
|
40389
40824
|
"claude",
|
|
40390
40825
|
`pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
|
|
@@ -41116,7 +41551,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
|
|
|
41116
41551
|
var import_child_process30 = require("child_process");
|
|
41117
41552
|
var import_util4 = require("util");
|
|
41118
41553
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
41119
|
-
var
|
|
41554
|
+
var path85 = __toESM(require("path"));
|
|
41120
41555
|
var execFileP6 = (0, import_util4.promisify)(import_child_process30.execFile);
|
|
41121
41556
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
41122
41557
|
function resetStdinForChild() {
|
|
@@ -41605,7 +42040,7 @@ var GitHubCodespacesProvider = class {
|
|
|
41605
42040
|
});
|
|
41606
42041
|
}
|
|
41607
42042
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
41608
|
-
const remoteDir =
|
|
42043
|
+
const remoteDir = path85.posix.dirname(remotePath);
|
|
41609
42044
|
const parts = [
|
|
41610
42045
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
41611
42046
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -41675,7 +42110,7 @@ function shellQuote(s) {
|
|
|
41675
42110
|
// src/services/providers/gitpod.ts
|
|
41676
42111
|
var import_child_process31 = require("child_process");
|
|
41677
42112
|
var import_util5 = require("util");
|
|
41678
|
-
var
|
|
42113
|
+
var path86 = __toESM(require("path"));
|
|
41679
42114
|
var import_picocolors10 = __toESM(require("picocolors"));
|
|
41680
42115
|
var execFileP7 = (0, import_util5.promisify)(import_child_process31.execFile);
|
|
41681
42116
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
@@ -41915,7 +42350,7 @@ var GitpodProvider = class {
|
|
|
41915
42350
|
});
|
|
41916
42351
|
}
|
|
41917
42352
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
41918
|
-
const remoteDir =
|
|
42353
|
+
const remoteDir = path86.posix.dirname(remotePath);
|
|
41919
42354
|
const parts = [
|
|
41920
42355
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
41921
42356
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -41951,7 +42386,7 @@ function shellQuote2(s) {
|
|
|
41951
42386
|
// src/services/providers/gitlab-workspaces.ts
|
|
41952
42387
|
var import_child_process32 = require("child_process");
|
|
41953
42388
|
var import_util6 = require("util");
|
|
41954
|
-
var
|
|
42389
|
+
var path87 = __toESM(require("path"));
|
|
41955
42390
|
var execFileP8 = (0, import_util6.promisify)(import_child_process32.execFile);
|
|
41956
42391
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
41957
42392
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
@@ -42211,7 +42646,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
42211
42646
|
}
|
|
42212
42647
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
42213
42648
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
42214
|
-
const remoteDir =
|
|
42649
|
+
const remoteDir = path87.posix.dirname(remotePath);
|
|
42215
42650
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
42216
42651
|
if (options.mode != null) {
|
|
42217
42652
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
@@ -42279,7 +42714,7 @@ function shellQuote3(s) {
|
|
|
42279
42714
|
// src/services/providers/railway.ts
|
|
42280
42715
|
var import_child_process33 = require("child_process");
|
|
42281
42716
|
var import_util7 = require("util");
|
|
42282
|
-
var
|
|
42717
|
+
var path88 = __toESM(require("path"));
|
|
42283
42718
|
var execFileP9 = (0, import_util7.promisify)(import_child_process33.execFile);
|
|
42284
42719
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
42285
42720
|
function resetStdinForChild4() {
|
|
@@ -42515,7 +42950,7 @@ var RailwayProvider = class {
|
|
|
42515
42950
|
if (!projectId || !serviceId) {
|
|
42516
42951
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
42517
42952
|
}
|
|
42518
|
-
const remoteDir =
|
|
42953
|
+
const remoteDir = path88.posix.dirname(remotePath);
|
|
42519
42954
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
42520
42955
|
if (options.mode != null) {
|
|
42521
42956
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
@@ -43161,8 +43596,8 @@ async function invite() {
|
|
|
43161
43596
|
var import_node_dns = require("dns");
|
|
43162
43597
|
var import_node_util5 = require("util");
|
|
43163
43598
|
var import_node_crypto13 = require("crypto");
|
|
43164
|
-
var
|
|
43165
|
-
var
|
|
43599
|
+
var fs79 = __toESM(require("fs"));
|
|
43600
|
+
var path89 = __toESM(require("path"));
|
|
43166
43601
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
43167
43602
|
var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
|
|
43168
43603
|
async function checkDns(apiBase2) {
|
|
@@ -43218,13 +43653,13 @@ async function checkHealth(apiBase2) {
|
|
|
43218
43653
|
}
|
|
43219
43654
|
}
|
|
43220
43655
|
function checkConfigDir() {
|
|
43221
|
-
const dir =
|
|
43656
|
+
const dir = path89.join(require("os").homedir(), ".codeam");
|
|
43222
43657
|
try {
|
|
43223
|
-
|
|
43224
|
-
const probe =
|
|
43225
|
-
|
|
43226
|
-
const read2 =
|
|
43227
|
-
|
|
43658
|
+
fs79.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
43659
|
+
const probe = path89.join(dir, ".doctor-probe");
|
|
43660
|
+
fs79.writeFileSync(probe, "ok", { mode: 384 });
|
|
43661
|
+
const read2 = fs79.readFileSync(probe, "utf8");
|
|
43662
|
+
fs79.unlinkSync(probe);
|
|
43228
43663
|
if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
|
|
43229
43664
|
return {
|
|
43230
43665
|
id: "config-dir",
|
|
@@ -43264,9 +43699,9 @@ function checkSessions() {
|
|
|
43264
43699
|
}
|
|
43265
43700
|
}
|
|
43266
43701
|
function checkAgentBinaries() {
|
|
43267
|
-
const
|
|
43702
|
+
const os66 = createOsStrategy();
|
|
43268
43703
|
return getEnabledAgents().map((meta) => {
|
|
43269
|
-
const found =
|
|
43704
|
+
const found = os66.findInPath(meta.binaryName);
|
|
43270
43705
|
return {
|
|
43271
43706
|
id: `agent-${meta.id}`,
|
|
43272
43707
|
label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
|
|
@@ -43288,7 +43723,7 @@ function checkNodePty() {
|
|
|
43288
43723
|
detail: "not required on this platform"
|
|
43289
43724
|
};
|
|
43290
43725
|
}
|
|
43291
|
-
const vendoredPath =
|
|
43726
|
+
const vendoredPath = path89.join(__dirname, "vendor", "node-pty");
|
|
43292
43727
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
43293
43728
|
try {
|
|
43294
43729
|
require(target);
|
|
@@ -43330,7 +43765,7 @@ function checkChokidar() {
|
|
|
43330
43765
|
}
|
|
43331
43766
|
async function doctor(args2 = []) {
|
|
43332
43767
|
const json = args2.includes("--json");
|
|
43333
|
-
const cliVersion = true ? "2.
|
|
43768
|
+
const cliVersion = true ? "2.64.0" : "0.0.0-dev";
|
|
43334
43769
|
const apiBase2 = resolveApiBaseUrl();
|
|
43335
43770
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
43336
43771
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -43721,7 +44156,7 @@ async function mcpRun(args2) {
|
|
|
43721
44156
|
// src/commands/version.ts
|
|
43722
44157
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
43723
44158
|
function version2() {
|
|
43724
|
-
const v = true ? "2.
|
|
44159
|
+
const v = true ? "2.64.0" : "unknown";
|
|
43725
44160
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
43726
44161
|
}
|
|
43727
44162
|
|
|
@@ -43870,10 +44305,10 @@ var EXIT_CODE_NAMES = {
|
|
|
43870
44305
|
};
|
|
43871
44306
|
|
|
43872
44307
|
// src/index.ts
|
|
43873
|
-
var
|
|
44308
|
+
var os65 = __toESM(require("os"));
|
|
43874
44309
|
if (!process.env.HOME) {
|
|
43875
44310
|
try {
|
|
43876
|
-
const home =
|
|
44311
|
+
const home = os65.homedir();
|
|
43877
44312
|
if (home) process.env.HOME = home;
|
|
43878
44313
|
} catch {
|
|
43879
44314
|
}
|