codeam-cli 2.32.10 → 2.33.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 +6 -0
- package/dist/index.js +1180 -424
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
498
498
|
// package.json
|
|
499
499
|
var package_default = {
|
|
500
500
|
name: "codeam-cli",
|
|
501
|
-
version: "2.
|
|
501
|
+
version: "2.33.0",
|
|
502
502
|
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.",
|
|
503
503
|
type: "commonjs",
|
|
504
504
|
main: "dist/index.js",
|
|
@@ -569,6 +569,7 @@ var package_default = {
|
|
|
569
569
|
},
|
|
570
570
|
dependencies: {
|
|
571
571
|
"@agentclientprotocol/claude-agent-acp": "^0.42.0",
|
|
572
|
+
"@beads/bd": "1.0.5",
|
|
572
573
|
"@agentclientprotocol/codex-acp": "^0.0.45",
|
|
573
574
|
"@agentclientprotocol/sdk": "^0.25.0",
|
|
574
575
|
"@clack/prompts": "^1.2.0",
|
|
@@ -707,8 +708,8 @@ async function requestCode(pluginId) {
|
|
|
707
708
|
});
|
|
708
709
|
let timer;
|
|
709
710
|
const timeoutSentinel = /* @__PURE__ */ Symbol("request-code-timeout");
|
|
710
|
-
const timeoutPromise = new Promise((
|
|
711
|
-
timer = setTimeout(() =>
|
|
711
|
+
const timeoutPromise = new Promise((resolve7) => {
|
|
712
|
+
timer = setTimeout(() => resolve7(timeoutSentinel), REQUEST_CODE_TIMEOUT_MS);
|
|
712
713
|
});
|
|
713
714
|
const result = await Promise.race([post2, timeoutPromise]);
|
|
714
715
|
clearTimeout(timer);
|
|
@@ -852,7 +853,7 @@ async function postPreviewEvent(input) {
|
|
|
852
853
|
}
|
|
853
854
|
}
|
|
854
855
|
async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
855
|
-
return new Promise((
|
|
856
|
+
return new Promise((resolve7, reject) => {
|
|
856
857
|
const data = JSON.stringify(body);
|
|
857
858
|
const u2 = new URL(url);
|
|
858
859
|
const transport = u2.protocol === "https:" ? https : http;
|
|
@@ -884,9 +885,9 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
|
884
885
|
return;
|
|
885
886
|
}
|
|
886
887
|
try {
|
|
887
|
-
|
|
888
|
+
resolve7(JSON.parse(responseBody));
|
|
888
889
|
} catch {
|
|
889
|
-
|
|
890
|
+
resolve7(null);
|
|
890
891
|
}
|
|
891
892
|
});
|
|
892
893
|
}
|
|
@@ -911,7 +912,7 @@ function makeHttpError(statusCode, retryAfterHeader, responseBody) {
|
|
|
911
912
|
return err;
|
|
912
913
|
}
|
|
913
914
|
async function _postJson(url, body) {
|
|
914
|
-
return new Promise((
|
|
915
|
+
return new Promise((resolve7, reject) => {
|
|
915
916
|
const data = JSON.stringify(body);
|
|
916
917
|
const u2 = new URL(url);
|
|
917
918
|
const transport = u2.protocol === "https:" ? https : http;
|
|
@@ -940,9 +941,9 @@ async function _postJson(url, body) {
|
|
|
940
941
|
return;
|
|
941
942
|
}
|
|
942
943
|
try {
|
|
943
|
-
|
|
944
|
+
resolve7(JSON.parse(body2));
|
|
944
945
|
} catch {
|
|
945
|
-
|
|
946
|
+
resolve7(null);
|
|
946
947
|
}
|
|
947
948
|
});
|
|
948
949
|
}
|
|
@@ -957,7 +958,7 @@ async function _postJson(url, body) {
|
|
|
957
958
|
});
|
|
958
959
|
}
|
|
959
960
|
async function _getJson(url) {
|
|
960
|
-
return new Promise((
|
|
961
|
+
return new Promise((resolve7, reject) => {
|
|
961
962
|
const u2 = new URL(url);
|
|
962
963
|
const transport = u2.protocol === "https:" ? https : http;
|
|
963
964
|
const req = transport.request(
|
|
@@ -981,9 +982,9 @@ async function _getJson(url) {
|
|
|
981
982
|
return;
|
|
982
983
|
}
|
|
983
984
|
try {
|
|
984
|
-
|
|
985
|
+
resolve7(JSON.parse(body));
|
|
985
986
|
} catch {
|
|
986
|
-
|
|
987
|
+
resolve7(null);
|
|
987
988
|
}
|
|
988
989
|
});
|
|
989
990
|
}
|
|
@@ -1161,8 +1162,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
1161
1162
|
return decodedFile;
|
|
1162
1163
|
};
|
|
1163
1164
|
}
|
|
1164
|
-
function normalizeWindowsPath(
|
|
1165
|
-
return
|
|
1165
|
+
function normalizeWindowsPath(path49) {
|
|
1166
|
+
return path49.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
1166
1167
|
}
|
|
1167
1168
|
|
|
1168
1169
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -3642,15 +3643,15 @@ async function addSourceContext(frames) {
|
|
|
3642
3643
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
3643
3644
|
return frames;
|
|
3644
3645
|
}
|
|
3645
|
-
function getContextLinesFromFile(
|
|
3646
|
-
return new Promise((
|
|
3647
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
3646
|
+
function getContextLinesFromFile(path49, ranges, output) {
|
|
3647
|
+
return new Promise((resolve7) => {
|
|
3648
|
+
const stream = (0, import_node_fs.createReadStream)(path49);
|
|
3648
3649
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
3649
3650
|
input: stream
|
|
3650
3651
|
});
|
|
3651
3652
|
function destroyStreamAndResolve() {
|
|
3652
3653
|
stream.destroy();
|
|
3653
|
-
|
|
3654
|
+
resolve7();
|
|
3654
3655
|
}
|
|
3655
3656
|
let lineNumber = 0;
|
|
3656
3657
|
let currentRangeIndex = 0;
|
|
@@ -3659,7 +3660,7 @@ function getContextLinesFromFile(path46, ranges, output) {
|
|
|
3659
3660
|
let rangeStart = range[0];
|
|
3660
3661
|
let rangeEnd = range[1];
|
|
3661
3662
|
function onStreamError() {
|
|
3662
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
3663
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path49, 1);
|
|
3663
3664
|
lineReaded.close();
|
|
3664
3665
|
lineReaded.removeAllListeners();
|
|
3665
3666
|
destroyStreamAndResolve();
|
|
@@ -3720,8 +3721,8 @@ function clearLineContext(frame) {
|
|
|
3720
3721
|
delete frame.context_line;
|
|
3721
3722
|
delete frame.post_context;
|
|
3722
3723
|
}
|
|
3723
|
-
function shouldSkipContextLinesForFile(
|
|
3724
|
-
return
|
|
3724
|
+
function shouldSkipContextLinesForFile(path49) {
|
|
3725
|
+
return path49.startsWith("node:") || path49.endsWith(".min.js") || path49.endsWith(".min.cjs") || path49.endsWith(".min.mjs") || path49.startsWith("data:");
|
|
3725
3726
|
}
|
|
3726
3727
|
function shouldSkipContextLinesForFrame(frame) {
|
|
3727
3728
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -4937,9 +4938,9 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4937
4938
|
if (!waitUntil) return;
|
|
4938
4939
|
if (this.disabled || this.optedOut) return;
|
|
4939
4940
|
if (!this._waitUntilCycle) {
|
|
4940
|
-
let
|
|
4941
|
+
let resolve7;
|
|
4941
4942
|
const promise = new Promise((r) => {
|
|
4942
|
-
|
|
4943
|
+
resolve7 = r;
|
|
4943
4944
|
});
|
|
4944
4945
|
try {
|
|
4945
4946
|
waitUntil(promise);
|
|
@@ -4947,7 +4948,7 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4947
4948
|
return;
|
|
4948
4949
|
}
|
|
4949
4950
|
this._waitUntilCycle = {
|
|
4950
|
-
resolve:
|
|
4951
|
+
resolve: resolve7,
|
|
4951
4952
|
startedAt: Date.now(),
|
|
4952
4953
|
timer: void 0
|
|
4953
4954
|
};
|
|
@@ -4971,12 +4972,12 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4971
4972
|
return cycle?.resolve;
|
|
4972
4973
|
}
|
|
4973
4974
|
async resolveWaitUntilFlush() {
|
|
4974
|
-
const
|
|
4975
|
+
const resolve7 = this._consumeWaitUntilCycle();
|
|
4975
4976
|
try {
|
|
4976
4977
|
await super.flush();
|
|
4977
4978
|
} catch {
|
|
4978
4979
|
} finally {
|
|
4979
|
-
|
|
4980
|
+
resolve7?.();
|
|
4980
4981
|
}
|
|
4981
4982
|
}
|
|
4982
4983
|
getPersistedProperty(key) {
|
|
@@ -5068,15 +5069,15 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
5068
5069
|
async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
|
|
5069
5070
|
if (this.isLocalEvaluationReady()) return true;
|
|
5070
5071
|
if (void 0 === this.featureFlagsPoller) return false;
|
|
5071
|
-
return new Promise((
|
|
5072
|
+
return new Promise((resolve7) => {
|
|
5072
5073
|
const timeout = setTimeout(() => {
|
|
5073
5074
|
cleanup();
|
|
5074
|
-
|
|
5075
|
+
resolve7(false);
|
|
5075
5076
|
}, timeoutMs);
|
|
5076
5077
|
const cleanup = this._events.on("localEvaluationFlagsLoaded", (count) => {
|
|
5077
5078
|
clearTimeout(timeout);
|
|
5078
5079
|
cleanup();
|
|
5079
|
-
|
|
5080
|
+
resolve7(count > 0);
|
|
5080
5081
|
});
|
|
5081
5082
|
});
|
|
5082
5083
|
}
|
|
@@ -5513,13 +5514,13 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
5513
5514
|
this.context?.enter(data, options);
|
|
5514
5515
|
}
|
|
5515
5516
|
async _shutdown(shutdownTimeoutMs) {
|
|
5516
|
-
const
|
|
5517
|
+
const resolve7 = this._consumeWaitUntilCycle();
|
|
5517
5518
|
await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
|
|
5518
5519
|
this.errorTracking.shutdown();
|
|
5519
5520
|
try {
|
|
5520
5521
|
return await super._shutdown(shutdownTimeoutMs);
|
|
5521
5522
|
} finally {
|
|
5522
|
-
|
|
5523
|
+
resolve7?.();
|
|
5523
5524
|
}
|
|
5524
5525
|
}
|
|
5525
5526
|
async _requestRemoteConfigPayload(flagKey) {
|
|
@@ -5875,7 +5876,7 @@ function readAnonId() {
|
|
|
5875
5876
|
}
|
|
5876
5877
|
function superProperties() {
|
|
5877
5878
|
return {
|
|
5878
|
-
cliVersion: true ? "2.
|
|
5879
|
+
cliVersion: true ? "2.33.0" : "0.0.0-dev",
|
|
5879
5880
|
nodeVersion: process.version,
|
|
5880
5881
|
platform: process.platform,
|
|
5881
5882
|
arch: process.arch,
|
|
@@ -7217,10 +7218,10 @@ function buildForPlatform(platform2) {
|
|
|
7217
7218
|
var import_node_crypto4 = require("crypto");
|
|
7218
7219
|
|
|
7219
7220
|
// src/agents/claude/resolver.ts
|
|
7220
|
-
function buildClaudeLaunch(extraArgs = [],
|
|
7221
|
-
const found =
|
|
7221
|
+
function buildClaudeLaunch(extraArgs = [], os30 = createOsStrategy()) {
|
|
7222
|
+
const found = os30.findInPath("claude") ?? os30.findInPath("claude-code");
|
|
7222
7223
|
if (!found) return null;
|
|
7223
|
-
return
|
|
7224
|
+
return os30.buildLaunch(found, extraArgs);
|
|
7224
7225
|
}
|
|
7225
7226
|
|
|
7226
7227
|
// src/agents/claude/installer.ts
|
|
@@ -9176,15 +9177,15 @@ function runInstaller() {
|
|
|
9176
9177
|
"-Command",
|
|
9177
9178
|
"irm https://claude.ai/install.ps1 | iex"
|
|
9178
9179
|
] : ["-c", "curl -fsSL https://claude.ai/install.sh | bash"];
|
|
9179
|
-
return new Promise((
|
|
9180
|
+
return new Promise((resolve7) => {
|
|
9180
9181
|
const proc = (0, import_child_process4.spawn)(cmd, args2, { stdio: "inherit" });
|
|
9181
9182
|
proc.on("error", (err) => {
|
|
9182
9183
|
console.error(`
|
|
9183
9184
|
\u2717 Installer failed to launch: ${err.message}`);
|
|
9184
|
-
|
|
9185
|
+
resolve7(false);
|
|
9185
9186
|
});
|
|
9186
9187
|
proc.on("exit", (code) => {
|
|
9187
|
-
|
|
9188
|
+
resolve7(code === 0);
|
|
9188
9189
|
});
|
|
9189
9190
|
});
|
|
9190
9191
|
}
|
|
@@ -9361,17 +9362,17 @@ function parseUsageOutput(raw) {
|
|
|
9361
9362
|
return { percent, resetAt };
|
|
9362
9363
|
}
|
|
9363
9364
|
async function fetchClaudeQuota() {
|
|
9364
|
-
return new Promise((
|
|
9365
|
+
return new Promise((resolve7) => {
|
|
9365
9366
|
const claudeCmd = findInPath("claude") ? "claude" : "claude-code";
|
|
9366
9367
|
if (!claudeCmd) {
|
|
9367
|
-
|
|
9368
|
+
resolve7(null);
|
|
9368
9369
|
return;
|
|
9369
9370
|
}
|
|
9370
9371
|
const helperPath = path11.join(os10.tmpdir(), "codeam-quota-helper.py");
|
|
9371
9372
|
fs8.writeFileSync(helperPath, HELPER_SCRIPT, { mode: 420 });
|
|
9372
9373
|
const python = findInPath("python3") ?? findInPath("python");
|
|
9373
9374
|
if (!python) {
|
|
9374
|
-
|
|
9375
|
+
resolve7(null);
|
|
9375
9376
|
return;
|
|
9376
9377
|
}
|
|
9377
9378
|
const proc = (0, import_child_process5.spawn)(python, [helperPath, claudeCmd, "--tools", ""], {
|
|
@@ -9398,13 +9399,13 @@ async function fetchClaudeQuota() {
|
|
|
9398
9399
|
fs8.unlinkSync(helperPath);
|
|
9399
9400
|
} catch {
|
|
9400
9401
|
}
|
|
9401
|
-
|
|
9402
|
+
resolve7(result);
|
|
9402
9403
|
}, 5e3);
|
|
9403
9404
|
}, 8e3);
|
|
9404
9405
|
setTimeout(() => {
|
|
9405
9406
|
if (!resolved) {
|
|
9406
9407
|
resolved = true;
|
|
9407
|
-
|
|
9408
|
+
resolve7(null);
|
|
9408
9409
|
}
|
|
9409
9410
|
try {
|
|
9410
9411
|
proc.kill();
|
|
@@ -9435,12 +9436,12 @@ function killActiveSpawnAndCaptureChildren() {
|
|
|
9435
9436
|
}
|
|
9436
9437
|
async function spawnAndCapture(cmd, args2, opts = {}) {
|
|
9437
9438
|
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
9438
|
-
return new Promise((
|
|
9439
|
+
return new Promise((resolve7) => {
|
|
9439
9440
|
let settled = false;
|
|
9440
9441
|
const settle = (value) => {
|
|
9441
9442
|
if (settled) return;
|
|
9442
9443
|
settled = true;
|
|
9443
|
-
|
|
9444
|
+
resolve7(value);
|
|
9444
9445
|
};
|
|
9445
9446
|
let child;
|
|
9446
9447
|
try {
|
|
@@ -9947,13 +9948,13 @@ function detectStartupBanner(lines) {
|
|
|
9947
9948
|
while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
|
|
9948
9949
|
if (metaIdx - artStart < 2) return null;
|
|
9949
9950
|
const pathLine = (lines[metaIdx + 1] ?? "").trim();
|
|
9950
|
-
const
|
|
9951
|
+
const path49 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
|
|
9951
9952
|
return {
|
|
9952
9953
|
title: "",
|
|
9953
9954
|
subtitle: lines[metaIdx].trim(),
|
|
9954
|
-
path:
|
|
9955
|
+
path: path49,
|
|
9955
9956
|
startIdx: artStart,
|
|
9956
|
-
endIdx: metaIdx + (
|
|
9957
|
+
endIdx: metaIdx + (path49 ? 1 : 0)
|
|
9957
9958
|
};
|
|
9958
9959
|
}
|
|
9959
9960
|
|
|
@@ -9963,8 +9964,8 @@ var ClaudeRuntimeStrategy = class {
|
|
|
9963
9964
|
meta = getAgent("claude");
|
|
9964
9965
|
mode = "interactive";
|
|
9965
9966
|
os;
|
|
9966
|
-
constructor(
|
|
9967
|
-
this.os =
|
|
9967
|
+
constructor(os30) {
|
|
9968
|
+
this.os = os30;
|
|
9968
9969
|
}
|
|
9969
9970
|
/**
|
|
9970
9971
|
* Claude Code's react-ink TUI enables bracketed-paste mode at
|
|
@@ -10972,8 +10973,8 @@ function codexCredentialLocator() {
|
|
|
10972
10973
|
function codexLoginLauncher() {
|
|
10973
10974
|
return {
|
|
10974
10975
|
async ensureInstalled() {
|
|
10975
|
-
const
|
|
10976
|
-
return
|
|
10976
|
+
const os30 = createOsStrategy();
|
|
10977
|
+
return os30.findInPath("codex") !== null;
|
|
10977
10978
|
},
|
|
10978
10979
|
launch() {
|
|
10979
10980
|
return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
@@ -10996,8 +10997,8 @@ var CodexRuntimeStrategy = class {
|
|
|
10996
10997
|
meta = getAgent("codex");
|
|
10997
10998
|
mode = "interactive";
|
|
10998
10999
|
os;
|
|
10999
|
-
constructor(
|
|
11000
|
-
this.os =
|
|
11000
|
+
constructor(os30) {
|
|
11001
|
+
this.os = os30;
|
|
11001
11002
|
}
|
|
11002
11003
|
async prepareLaunch() {
|
|
11003
11004
|
let binary = this.os.findInPath("codex");
|
|
@@ -11103,16 +11104,16 @@ var CodexRuntimeStrategy = class {
|
|
|
11103
11104
|
});
|
|
11104
11105
|
}
|
|
11105
11106
|
};
|
|
11106
|
-
function resolveNpm(
|
|
11107
|
-
return
|
|
11107
|
+
function resolveNpm(os30) {
|
|
11108
|
+
return os30.id === "win32" ? "npm.cmd" : "npm";
|
|
11108
11109
|
}
|
|
11109
|
-
async function installCodexViaNpm(
|
|
11110
|
-
return new Promise((
|
|
11111
|
-
const proc = (0, import_node_child_process4.spawn)(resolveNpm(
|
|
11110
|
+
async function installCodexViaNpm(os30) {
|
|
11111
|
+
return new Promise((resolve7, reject) => {
|
|
11112
|
+
const proc = (0, import_node_child_process4.spawn)(resolveNpm(os30), ["install", "-g", "@openai/codex"], {
|
|
11112
11113
|
stdio: "inherit"
|
|
11113
11114
|
});
|
|
11114
11115
|
proc.on("close", (code) => {
|
|
11115
|
-
if (code === 0)
|
|
11116
|
+
if (code === 0) resolve7();
|
|
11116
11117
|
else reject(new Error(`npm install -g @openai/codex exited ${code}`));
|
|
11117
11118
|
});
|
|
11118
11119
|
proc.on("error", (err) => {
|
|
@@ -11125,16 +11126,16 @@ async function installCodexViaNpm(os29) {
|
|
|
11125
11126
|
});
|
|
11126
11127
|
});
|
|
11127
11128
|
}
|
|
11128
|
-
function augmentNpmGlobalBin(
|
|
11129
|
+
function augmentNpmGlobalBin(os30) {
|
|
11129
11130
|
try {
|
|
11130
|
-
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(
|
|
11131
|
+
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os30), ["prefix", "-g"], {
|
|
11131
11132
|
stdio: ["ignore", "pipe", "ignore"]
|
|
11132
11133
|
});
|
|
11133
11134
|
if (result.status !== 0) return;
|
|
11134
11135
|
const prefix = result.stdout.toString().trim();
|
|
11135
11136
|
if (!prefix) return;
|
|
11136
|
-
const binDir =
|
|
11137
|
-
|
|
11137
|
+
const binDir = os30.id === "win32" ? prefix : path17.join(prefix, "bin");
|
|
11138
|
+
os30.augmentPath([binDir]);
|
|
11138
11139
|
} catch {
|
|
11139
11140
|
}
|
|
11140
11141
|
}
|
|
@@ -11218,25 +11219,25 @@ var import_node_child_process7 = require("child_process");
|
|
|
11218
11219
|
// src/agents/coderabbit/installer.ts
|
|
11219
11220
|
var import_node_child_process5 = require("child_process");
|
|
11220
11221
|
var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
|
|
11221
|
-
async function ensureCoderabbitInstalled(
|
|
11222
|
-
if (
|
|
11223
|
-
if (
|
|
11222
|
+
async function ensureCoderabbitInstalled(os30) {
|
|
11223
|
+
if (os30.findInPath("coderabbit")) return true;
|
|
11224
|
+
if (os30.id === "win32") {
|
|
11224
11225
|
console.error(
|
|
11225
11226
|
"\n \u2717 CodeRabbit on Windows requires WSL.\n Install the CLI inside your WSL distribution\n (curl -fsSL https://cli.coderabbit.ai/install.sh | sh)\n then re-run `codeam link coderabbit` from WSL.\n"
|
|
11226
11227
|
);
|
|
11227
11228
|
return false;
|
|
11228
11229
|
}
|
|
11229
11230
|
console.log("\n CodeRabbit CLI not found \u2014 installing via the official script\u2026\n");
|
|
11230
|
-
const ok = await new Promise((
|
|
11231
|
+
const ok = await new Promise((resolve7) => {
|
|
11231
11232
|
const proc = (0, import_node_child_process5.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL} | sh`], {
|
|
11232
11233
|
stdio: "inherit"
|
|
11233
11234
|
});
|
|
11234
|
-
proc.on("close", (code) =>
|
|
11235
|
-
proc.on("error", () =>
|
|
11235
|
+
proc.on("close", (code) => resolve7(code === 0));
|
|
11236
|
+
proc.on("error", () => resolve7(false));
|
|
11236
11237
|
});
|
|
11237
11238
|
if (!ok) return false;
|
|
11238
|
-
|
|
11239
|
-
return
|
|
11239
|
+
os30.augmentPath([`${os30.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
11240
|
+
return os30.findInPath("coderabbit") !== null;
|
|
11240
11241
|
}
|
|
11241
11242
|
|
|
11242
11243
|
// src/agents/coderabbit/link.ts
|
|
@@ -11263,10 +11264,10 @@ function coderabbitCredentialLocator() {
|
|
|
11263
11264
|
extract: extractLocalCoderabbitToken
|
|
11264
11265
|
};
|
|
11265
11266
|
}
|
|
11266
|
-
function coderabbitLoginLauncher(
|
|
11267
|
+
function coderabbitLoginLauncher(os30) {
|
|
11267
11268
|
return {
|
|
11268
11269
|
async ensureInstalled() {
|
|
11269
|
-
return ensureCoderabbitInstalled(
|
|
11270
|
+
return ensureCoderabbitInstalled(os30);
|
|
11270
11271
|
},
|
|
11271
11272
|
launch() {
|
|
11272
11273
|
return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
|
|
@@ -11289,11 +11290,11 @@ function parseReview(stdout) {
|
|
|
11289
11290
|
for (const line of lines) {
|
|
11290
11291
|
const m = line.match(HUNK_LINE_RE);
|
|
11291
11292
|
if (!m) continue;
|
|
11292
|
-
const [,
|
|
11293
|
-
if (!
|
|
11293
|
+
const [, path49, lineNo, sevToken, message] = m;
|
|
11294
|
+
if (!path49 || !lineNo || !message) continue;
|
|
11294
11295
|
const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
|
|
11295
11296
|
hunks.push({
|
|
11296
|
-
path:
|
|
11297
|
+
path: path49.trim(),
|
|
11297
11298
|
line: Number(lineNo),
|
|
11298
11299
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
11299
11300
|
message: cleanedMessage
|
|
@@ -11312,8 +11313,8 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11312
11313
|
meta = getAgent("coderabbit");
|
|
11313
11314
|
mode = "batch";
|
|
11314
11315
|
os;
|
|
11315
|
-
constructor(
|
|
11316
|
-
this.os =
|
|
11316
|
+
constructor(os30) {
|
|
11317
|
+
this.os = os30;
|
|
11317
11318
|
}
|
|
11318
11319
|
getDefaultArgs() {
|
|
11319
11320
|
return ["review"];
|
|
@@ -11351,7 +11352,7 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11351
11352
|
}
|
|
11352
11353
|
async runOneShot(input) {
|
|
11353
11354
|
const launch = await this.prepareInvocation(input);
|
|
11354
|
-
return new Promise((
|
|
11355
|
+
return new Promise((resolve7, reject) => {
|
|
11355
11356
|
const stdoutBuf = [];
|
|
11356
11357
|
const stderrBuf = [];
|
|
11357
11358
|
const proc = (0, import_node_child_process7.spawn)(launch.cmd, launch.args, {
|
|
@@ -11362,7 +11363,7 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11362
11363
|
proc.stderr?.on("data", (b) => stderrBuf.push(b));
|
|
11363
11364
|
proc.on("error", (err) => reject(err));
|
|
11364
11365
|
proc.on("close", (code) => {
|
|
11365
|
-
|
|
11366
|
+
resolve7(
|
|
11366
11367
|
this.parseOutput({
|
|
11367
11368
|
exitCode: code ?? 0,
|
|
11368
11369
|
stdout: Buffer.concat(stdoutBuf).toString("utf8"),
|
|
@@ -11428,10 +11429,10 @@ function cursorCredentialLocator() {
|
|
|
11428
11429
|
extract: extractLocalCursorToken
|
|
11429
11430
|
};
|
|
11430
11431
|
}
|
|
11431
|
-
function cursorLoginLauncher(
|
|
11432
|
+
function cursorLoginLauncher(os30) {
|
|
11432
11433
|
return {
|
|
11433
11434
|
async ensureInstalled() {
|
|
11434
|
-
if (
|
|
11435
|
+
if (os30.findInPath("cursor-agent")) return true;
|
|
11435
11436
|
console.error(
|
|
11436
11437
|
"\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"
|
|
11437
11438
|
);
|
|
@@ -11493,8 +11494,8 @@ var CursorRuntimeStrategy = class {
|
|
|
11493
11494
|
meta = getAgent("cursor");
|
|
11494
11495
|
mode = "interactive";
|
|
11495
11496
|
os;
|
|
11496
|
-
constructor(
|
|
11497
|
-
this.os =
|
|
11497
|
+
constructor(os30) {
|
|
11498
|
+
this.os = os30;
|
|
11498
11499
|
}
|
|
11499
11500
|
async prepareLaunch() {
|
|
11500
11501
|
const binary = this.os.findInPath("cursor-agent");
|
|
@@ -11614,10 +11615,10 @@ function aiderCredentialLocator() {
|
|
|
11614
11615
|
extract: extractLocalAiderToken
|
|
11615
11616
|
};
|
|
11616
11617
|
}
|
|
11617
|
-
function aiderLoginLauncher(
|
|
11618
|
+
function aiderLoginLauncher(os30) {
|
|
11618
11619
|
return {
|
|
11619
11620
|
async ensureInstalled() {
|
|
11620
|
-
if (
|
|
11621
|
+
if (os30.findInPath("aider")) return true;
|
|
11621
11622
|
console.error(
|
|
11622
11623
|
"\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
|
|
11623
11624
|
);
|
|
@@ -11627,7 +11628,7 @@ function aiderLoginLauncher(os29) {
|
|
|
11627
11628
|
console.error(
|
|
11628
11629
|
"\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"
|
|
11629
11630
|
);
|
|
11630
|
-
return (0, import_node_child_process9.spawn)(
|
|
11631
|
+
return (0, import_node_child_process9.spawn)(os30.id === "win32" ? "cmd.exe" : "sh", os30.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
|
|
11631
11632
|
stdio: "ignore"
|
|
11632
11633
|
});
|
|
11633
11634
|
}
|
|
@@ -11699,8 +11700,8 @@ var AiderRuntimeStrategy = class {
|
|
|
11699
11700
|
meta = getAgent("aider");
|
|
11700
11701
|
mode = "interactive";
|
|
11701
11702
|
os;
|
|
11702
|
-
constructor(
|
|
11703
|
-
this.os =
|
|
11703
|
+
constructor(os30) {
|
|
11704
|
+
this.os = os30;
|
|
11704
11705
|
}
|
|
11705
11706
|
async prepareLaunch() {
|
|
11706
11707
|
const binary = this.os.findInPath("aider");
|
|
@@ -11829,8 +11830,8 @@ function geminiCredentialLocator() {
|
|
|
11829
11830
|
function geminiLoginLauncher() {
|
|
11830
11831
|
return {
|
|
11831
11832
|
async ensureInstalled() {
|
|
11832
|
-
const
|
|
11833
|
-
return
|
|
11833
|
+
const os30 = createOsStrategy();
|
|
11834
|
+
return os30.findInPath("gemini") !== null;
|
|
11834
11835
|
},
|
|
11835
11836
|
launch() {
|
|
11836
11837
|
return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
|
|
@@ -11863,8 +11864,8 @@ var GeminiRuntimeStrategy = class {
|
|
|
11863
11864
|
meta = getAgent("gemini");
|
|
11864
11865
|
mode = "interactive";
|
|
11865
11866
|
os;
|
|
11866
|
-
constructor(
|
|
11867
|
-
this.os =
|
|
11867
|
+
constructor(os30) {
|
|
11868
|
+
this.os = os30;
|
|
11868
11869
|
}
|
|
11869
11870
|
async prepareLaunch() {
|
|
11870
11871
|
const binary = this.os.findInPath("gemini");
|
|
@@ -11964,18 +11965,18 @@ var GeminiRuntimeStrategy = class {
|
|
|
11964
11965
|
|
|
11965
11966
|
// src/agents/registry.ts
|
|
11966
11967
|
var runtimeBuilders = {
|
|
11967
|
-
claude: (
|
|
11968
|
-
codex: (
|
|
11969
|
-
coderabbit: (
|
|
11970
|
-
cursor: (
|
|
11971
|
-
aider: (
|
|
11972
|
-
gemini: (
|
|
11968
|
+
claude: (os30) => new ClaudeRuntimeStrategy(os30),
|
|
11969
|
+
codex: (os30) => new CodexRuntimeStrategy(os30),
|
|
11970
|
+
coderabbit: (os30) => new CoderabbitRuntimeStrategy(os30),
|
|
11971
|
+
cursor: (os30) => new CursorRuntimeStrategy(os30),
|
|
11972
|
+
aider: (os30) => new AiderRuntimeStrategy(os30),
|
|
11973
|
+
gemini: (os30) => new GeminiRuntimeStrategy(os30)
|
|
11973
11974
|
};
|
|
11974
11975
|
var deployBuilders = {
|
|
11975
11976
|
claude: () => new ClaudeDeployStrategy(),
|
|
11976
11977
|
codex: () => new CodexDeployStrategy()
|
|
11977
11978
|
};
|
|
11978
|
-
function createAgentStrategy(agent,
|
|
11979
|
+
function createAgentStrategy(agent, os30 = createOsStrategy()) {
|
|
11979
11980
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
11980
11981
|
throw new Error(
|
|
11981
11982
|
`Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
|
|
@@ -11985,10 +11986,10 @@ function createAgentStrategy(agent, os29 = createOsStrategy()) {
|
|
|
11985
11986
|
if (!build) {
|
|
11986
11987
|
throw new Error(`No runtime strategy registered for agent "${agent}"`);
|
|
11987
11988
|
}
|
|
11988
|
-
return build(
|
|
11989
|
+
return build(os30);
|
|
11989
11990
|
}
|
|
11990
|
-
function createInteractiveAgentStrategy(agent,
|
|
11991
|
-
const s = createAgentStrategy(agent,
|
|
11991
|
+
function createInteractiveAgentStrategy(agent, os30 = createOsStrategy()) {
|
|
11992
|
+
const s = createAgentStrategy(agent, os30);
|
|
11992
11993
|
if (s.mode !== "interactive") {
|
|
11993
11994
|
throw new Error(
|
|
11994
11995
|
`Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
|
|
@@ -14268,8 +14269,8 @@ var Connection = class {
|
|
|
14268
14269
|
this.requestHandler = requestHandler;
|
|
14269
14270
|
this.notificationHandler = notificationHandler;
|
|
14270
14271
|
this.stream = stream;
|
|
14271
|
-
this.closedPromise = new Promise((
|
|
14272
|
-
this.abortController.signal.addEventListener("abort", () =>
|
|
14272
|
+
this.closedPromise = new Promise((resolve7) => {
|
|
14273
|
+
this.abortController.signal.addEventListener("abort", () => resolve7());
|
|
14273
14274
|
});
|
|
14274
14275
|
void this.receive();
|
|
14275
14276
|
}
|
|
@@ -14439,11 +14440,11 @@ var Connection = class {
|
|
|
14439
14440
|
return rejectedPromise(this.closedReason());
|
|
14440
14441
|
}
|
|
14441
14442
|
const id = this.nextRequestId++;
|
|
14442
|
-
const responsePromise = new Promise((
|
|
14443
|
+
const responsePromise = new Promise((resolve7, reject) => {
|
|
14443
14444
|
this.pendingResponses.set(id, {
|
|
14444
14445
|
resolve: (response) => {
|
|
14445
14446
|
try {
|
|
14446
|
-
|
|
14447
|
+
resolve7(mapResponse ? mapResponse(response) : response);
|
|
14447
14448
|
} catch (error) {
|
|
14448
14449
|
reject(error);
|
|
14449
14450
|
}
|
|
@@ -14764,17 +14765,17 @@ var AcpClient = class {
|
|
|
14764
14765
|
this.sessionId = null;
|
|
14765
14766
|
try {
|
|
14766
14767
|
child.kill("SIGTERM");
|
|
14767
|
-
const grace = new Promise((
|
|
14768
|
+
const grace = new Promise((resolve7) => {
|
|
14768
14769
|
const t2 = setTimeout(() => {
|
|
14769
14770
|
try {
|
|
14770
14771
|
child.kill("SIGKILL");
|
|
14771
14772
|
} catch {
|
|
14772
14773
|
}
|
|
14773
|
-
|
|
14774
|
+
resolve7();
|
|
14774
14775
|
}, 2e3);
|
|
14775
14776
|
child.once("exit", () => {
|
|
14776
14777
|
clearTimeout(t2);
|
|
14777
|
-
|
|
14778
|
+
resolve7();
|
|
14778
14779
|
});
|
|
14779
14780
|
});
|
|
14780
14781
|
await grace;
|
|
@@ -14912,7 +14913,7 @@ var _transport2 = {
|
|
|
14912
14913
|
get: _get
|
|
14913
14914
|
};
|
|
14914
14915
|
function _post(url, headers, payload) {
|
|
14915
|
-
return new Promise((
|
|
14916
|
+
return new Promise((resolve7, reject) => {
|
|
14916
14917
|
let settled = false;
|
|
14917
14918
|
const u2 = new URL(url);
|
|
14918
14919
|
const lib = u2.protocol === "https:" ? https3 : http3;
|
|
@@ -14937,7 +14938,7 @@ function _post(url, headers, payload) {
|
|
|
14937
14938
|
res.on("end", () => {
|
|
14938
14939
|
if (settled) return;
|
|
14939
14940
|
settled = true;
|
|
14940
|
-
|
|
14941
|
+
resolve7({ statusCode: res.statusCode ?? 0, body });
|
|
14941
14942
|
});
|
|
14942
14943
|
}
|
|
14943
14944
|
);
|
|
@@ -14954,7 +14955,7 @@ function _post(url, headers, payload) {
|
|
|
14954
14955
|
});
|
|
14955
14956
|
}
|
|
14956
14957
|
function _get(url, headers) {
|
|
14957
|
-
return new Promise((
|
|
14958
|
+
return new Promise((resolve7, reject) => {
|
|
14958
14959
|
let settled = false;
|
|
14959
14960
|
const u2 = new URL(url);
|
|
14960
14961
|
const lib = u2.protocol === "https:" ? https3 : http3;
|
|
@@ -14978,7 +14979,7 @@ function _get(url, headers) {
|
|
|
14978
14979
|
res.on("end", () => {
|
|
14979
14980
|
if (settled) return;
|
|
14980
14981
|
settled = true;
|
|
14981
|
-
|
|
14982
|
+
resolve7({ statusCode: res.statusCode ?? 0, body });
|
|
14982
14983
|
});
|
|
14983
14984
|
}
|
|
14984
14985
|
);
|
|
@@ -15687,11 +15688,11 @@ function extractSelectPrompt(text) {
|
|
|
15687
15688
|
}
|
|
15688
15689
|
|
|
15689
15690
|
// src/commands/start/handlers.ts
|
|
15690
|
-
var
|
|
15691
|
-
var
|
|
15692
|
-
var
|
|
15691
|
+
var fs31 = __toESM(require("fs"));
|
|
15692
|
+
var os25 = __toESM(require("os"));
|
|
15693
|
+
var path38 = __toESM(require("path"));
|
|
15693
15694
|
var import_crypto3 = require("crypto");
|
|
15694
|
-
var
|
|
15695
|
+
var import_child_process15 = require("child_process");
|
|
15695
15696
|
|
|
15696
15697
|
// src/lib/payload.ts
|
|
15697
15698
|
var import_zod = require("zod");
|
|
@@ -16344,12 +16345,12 @@ async function applyFileReview(workingDir, filePath, action) {
|
|
|
16344
16345
|
return { ok: true, action, filePath, repoRoot };
|
|
16345
16346
|
}
|
|
16346
16347
|
function runGit(cwd, args2) {
|
|
16347
|
-
return new Promise((
|
|
16348
|
+
return new Promise((resolve7) => {
|
|
16348
16349
|
let proc;
|
|
16349
16350
|
try {
|
|
16350
16351
|
proc = (0, import_child_process10.spawn)("git", args2, { cwd, env: process.env });
|
|
16351
16352
|
} catch (err) {
|
|
16352
|
-
|
|
16353
|
+
resolve7({ ok: false, code: -1, stdout: "", stderr: err.message });
|
|
16353
16354
|
return;
|
|
16354
16355
|
}
|
|
16355
16356
|
let stdout = "";
|
|
@@ -16362,11 +16363,11 @@ function runGit(cwd, args2) {
|
|
|
16362
16363
|
});
|
|
16363
16364
|
proc.on(
|
|
16364
16365
|
"error",
|
|
16365
|
-
(err) =>
|
|
16366
|
+
(err) => resolve7({ ok: false, code: -1, stdout, stderr: stderr + err.message })
|
|
16366
16367
|
);
|
|
16367
16368
|
proc.on(
|
|
16368
16369
|
"close",
|
|
16369
|
-
(code) =>
|
|
16370
|
+
(code) => resolve7({ ok: code === 0, code: code ?? -1, stdout, stderr })
|
|
16370
16371
|
);
|
|
16371
16372
|
});
|
|
16372
16373
|
}
|
|
@@ -16625,7 +16626,7 @@ async function link(args2 = []) {
|
|
|
16625
16626
|
waitSpin.start(waitMsg());
|
|
16626
16627
|
const countdown = setInterval(() => waitSpin.message(waitMsg()), 1e3);
|
|
16627
16628
|
countdown.unref?.();
|
|
16628
|
-
const paired = await new Promise((
|
|
16629
|
+
const paired = await new Promise((resolve7, reject) => {
|
|
16629
16630
|
let stopPoll = null;
|
|
16630
16631
|
const sigint = () => {
|
|
16631
16632
|
clearInterval(countdown);
|
|
@@ -16638,7 +16639,7 @@ async function link(args2 = []) {
|
|
|
16638
16639
|
process.removeListener("SIGINT", sigint);
|
|
16639
16640
|
clearInterval(countdown);
|
|
16640
16641
|
waitSpin.stop("Paired");
|
|
16641
|
-
|
|
16642
|
+
resolve7(info);
|
|
16642
16643
|
},
|
|
16643
16644
|
() => {
|
|
16644
16645
|
clearInterval(countdown);
|
|
@@ -16773,14 +16774,14 @@ async function captureFreshCredentials(ctx) {
|
|
|
16773
16774
|
}
|
|
16774
16775
|
};
|
|
16775
16776
|
try {
|
|
16776
|
-
const token = await new Promise((
|
|
16777
|
+
const token = await new Promise((resolve7, reject) => {
|
|
16777
16778
|
let settled = false;
|
|
16778
16779
|
const tryExtract = async () => {
|
|
16779
16780
|
if (settled) return;
|
|
16780
16781
|
const t2 = await ctx.locator.extract();
|
|
16781
16782
|
if (t2 && !settled) {
|
|
16782
16783
|
settled = true;
|
|
16783
|
-
|
|
16784
|
+
resolve7(t2);
|
|
16784
16785
|
}
|
|
16785
16786
|
};
|
|
16786
16787
|
watcher.on("add", () => void tryExtract());
|
|
@@ -17178,12 +17179,758 @@ function activePreviewSessionIds() {
|
|
|
17178
17179
|
return Array.from(activePreviews.keys());
|
|
17179
17180
|
}
|
|
17180
17181
|
|
|
17182
|
+
// src/beads/bd-adapter.ts
|
|
17183
|
+
var import_child_process12 = require("child_process");
|
|
17184
|
+
var fs29 = __toESM(require("fs"));
|
|
17185
|
+
var os24 = __toESM(require("os"));
|
|
17186
|
+
var path35 = __toESM(require("path"));
|
|
17187
|
+
var BD_PACKAGE = "@beads/bd";
|
|
17188
|
+
function resolveBundledBdBinary() {
|
|
17189
|
+
return _resolveSeam.resolveBundled();
|
|
17190
|
+
}
|
|
17191
|
+
function _defaultResolveBundled() {
|
|
17192
|
+
let pkgJsonPath;
|
|
17193
|
+
try {
|
|
17194
|
+
pkgJsonPath = require.resolve(`${BD_PACKAGE}/package.json`);
|
|
17195
|
+
} catch {
|
|
17196
|
+
return null;
|
|
17197
|
+
}
|
|
17198
|
+
const binDir = path35.join(path35.dirname(pkgJsonPath), "bin");
|
|
17199
|
+
const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
|
|
17200
|
+
const binaryPath = path35.join(binDir, binaryName);
|
|
17201
|
+
try {
|
|
17202
|
+
fs29.accessSync(binaryPath, fs29.constants.F_OK);
|
|
17203
|
+
return binaryPath;
|
|
17204
|
+
} catch {
|
|
17205
|
+
return null;
|
|
17206
|
+
}
|
|
17207
|
+
}
|
|
17208
|
+
function resolveBdOnPath() {
|
|
17209
|
+
return _resolveSeam.resolveOnPath();
|
|
17210
|
+
}
|
|
17211
|
+
function _defaultResolveOnPath() {
|
|
17212
|
+
const dirs = (process.env.PATH ?? "").split(path35.delimiter).filter(Boolean);
|
|
17213
|
+
const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
|
|
17214
|
+
for (const dir of dirs) {
|
|
17215
|
+
for (const candidate of candidates) {
|
|
17216
|
+
const full = path35.join(dir, candidate);
|
|
17217
|
+
try {
|
|
17218
|
+
fs29.accessSync(full, fs29.constants.F_OK);
|
|
17219
|
+
return full;
|
|
17220
|
+
} catch {
|
|
17221
|
+
}
|
|
17222
|
+
}
|
|
17223
|
+
}
|
|
17224
|
+
return null;
|
|
17225
|
+
}
|
|
17226
|
+
var _resolveSeam = {
|
|
17227
|
+
resolveBundled: _defaultResolveBundled,
|
|
17228
|
+
resolveOnPath: _defaultResolveOnPath
|
|
17229
|
+
};
|
|
17230
|
+
var _spawnSeam = {
|
|
17231
|
+
run: _defaultSpawn
|
|
17232
|
+
};
|
|
17233
|
+
function _defaultSpawn(binaryPath, args2, opts) {
|
|
17234
|
+
return new Promise((resolve7) => {
|
|
17235
|
+
let proc;
|
|
17236
|
+
try {
|
|
17237
|
+
proc = (0, import_child_process12.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
|
|
17238
|
+
} catch (err) {
|
|
17239
|
+
resolve7({ code: -1, stdout: "", stderr: err.message });
|
|
17240
|
+
return;
|
|
17241
|
+
}
|
|
17242
|
+
let stdout = "";
|
|
17243
|
+
let stderr = "";
|
|
17244
|
+
proc.stdout?.on("data", (c2) => {
|
|
17245
|
+
stdout += c2.toString();
|
|
17246
|
+
});
|
|
17247
|
+
proc.stderr?.on("data", (c2) => {
|
|
17248
|
+
stderr += c2.toString();
|
|
17249
|
+
});
|
|
17250
|
+
proc.on("error", (err) => resolve7({ code: -1, stdout, stderr: err.message }));
|
|
17251
|
+
proc.on("close", (code) => resolve7({ code: code ?? -1, stdout, stderr }));
|
|
17252
|
+
});
|
|
17253
|
+
}
|
|
17254
|
+
var BdAdapter = class {
|
|
17255
|
+
constructor(opts = {}) {
|
|
17256
|
+
this.opts = opts;
|
|
17257
|
+
this.resolved = opts.binaryPath ?? null;
|
|
17258
|
+
}
|
|
17259
|
+
opts;
|
|
17260
|
+
resolved;
|
|
17261
|
+
/**
|
|
17262
|
+
* Resolve the bd binary lazily, caching the result. Order:
|
|
17263
|
+
* bundled @beads/bd → PATH. Returns null when neither is available — the
|
|
17264
|
+
* caller offers the consented installer (`install-bd.ts`).
|
|
17265
|
+
*/
|
|
17266
|
+
resolveBinary() {
|
|
17267
|
+
if (this.resolved) return this.resolved;
|
|
17268
|
+
const bundled = resolveBundledBdBinary();
|
|
17269
|
+
if (bundled) {
|
|
17270
|
+
this.resolved = bundled;
|
|
17271
|
+
return bundled;
|
|
17272
|
+
}
|
|
17273
|
+
const onPath = resolveBdOnPath();
|
|
17274
|
+
if (onPath) {
|
|
17275
|
+
this.resolved = onPath;
|
|
17276
|
+
return onPath;
|
|
17277
|
+
}
|
|
17278
|
+
return null;
|
|
17279
|
+
}
|
|
17280
|
+
/** True when a bd binary is resolvable without installing. */
|
|
17281
|
+
isAvailable() {
|
|
17282
|
+
return this.resolveBinary() !== null;
|
|
17283
|
+
}
|
|
17284
|
+
/**
|
|
17285
|
+
* Run an arbitrary bd subcommand. Always injects `--global` (the home brain)
|
|
17286
|
+
* unless a `beadsDir` override is set, in which case `BEADS_DIR` redirects bd
|
|
17287
|
+
* to that dir instead (tests). Returns the raw result; callers decide how to
|
|
17288
|
+
* interpret exit codes (e.g. `bd setup --check` uses 0/nonzero).
|
|
17289
|
+
*/
|
|
17290
|
+
async run(args2) {
|
|
17291
|
+
const binary = this.resolveBinary();
|
|
17292
|
+
if (!binary) {
|
|
17293
|
+
return { code: -1, stdout: "", stderr: "bd binary not resolved" };
|
|
17294
|
+
}
|
|
17295
|
+
const env = { ...process.env };
|
|
17296
|
+
const finalArgs = [...args2];
|
|
17297
|
+
if (this.opts.beadsDir) {
|
|
17298
|
+
env.BEADS_DIR = this.opts.beadsDir;
|
|
17299
|
+
} else if (!finalArgs.includes("--global")) {
|
|
17300
|
+
finalArgs.push("--global");
|
|
17301
|
+
}
|
|
17302
|
+
log.trace("beads", `bd ${finalArgs.join(" ")}`);
|
|
17303
|
+
return _spawnSeam.run(binary, finalArgs, { cwd: this.opts.cwd, env });
|
|
17304
|
+
}
|
|
17305
|
+
/**
|
|
17306
|
+
* `bd ready --json` → typed issue array. `bd list --json` shares the shape,
|
|
17307
|
+
* so `listIssues` reuses the same parser. Bad JSON / non-zero exit → [].
|
|
17308
|
+
*/
|
|
17309
|
+
async readyIssues(projectKey) {
|
|
17310
|
+
const res = await this.run(["ready", "--json"]);
|
|
17311
|
+
return parseIssues(res, projectKey);
|
|
17312
|
+
}
|
|
17313
|
+
async listIssues(projectKey) {
|
|
17314
|
+
const res = await this.run(["list", "--json"]);
|
|
17315
|
+
return parseIssues(res, projectKey);
|
|
17316
|
+
}
|
|
17317
|
+
/** `bd status --json` → summary block, or null on failure. */
|
|
17318
|
+
async statusSummary() {
|
|
17319
|
+
const res = await this.run(["status", "--json"]);
|
|
17320
|
+
if (res.code !== 0) return null;
|
|
17321
|
+
try {
|
|
17322
|
+
const parsed = JSON.parse(res.stdout);
|
|
17323
|
+
return parsed.summary ?? null;
|
|
17324
|
+
} catch {
|
|
17325
|
+
return null;
|
|
17326
|
+
}
|
|
17327
|
+
}
|
|
17328
|
+
};
|
|
17329
|
+
var VALID_STATUS = /* @__PURE__ */ new Set([
|
|
17330
|
+
"open",
|
|
17331
|
+
"in_progress",
|
|
17332
|
+
"blocked",
|
|
17333
|
+
"closed"
|
|
17334
|
+
]);
|
|
17335
|
+
function parseIssues(res, projectKey) {
|
|
17336
|
+
if (res.code !== 0) return [];
|
|
17337
|
+
let parsed;
|
|
17338
|
+
try {
|
|
17339
|
+
parsed = JSON.parse(res.stdout);
|
|
17340
|
+
} catch {
|
|
17341
|
+
return [];
|
|
17342
|
+
}
|
|
17343
|
+
if (!Array.isArray(parsed)) return [];
|
|
17344
|
+
const out2 = [];
|
|
17345
|
+
for (const row of parsed) {
|
|
17346
|
+
const issue = coerceIssue(row, projectKey);
|
|
17347
|
+
if (issue) out2.push(issue);
|
|
17348
|
+
}
|
|
17349
|
+
return out2;
|
|
17350
|
+
}
|
|
17351
|
+
function coerceIssue(row, projectKey) {
|
|
17352
|
+
if (typeof row !== "object" || row === null) return null;
|
|
17353
|
+
const r = row;
|
|
17354
|
+
if (typeof r.id !== "string" || typeof r.title !== "string") return null;
|
|
17355
|
+
const status2 = typeof r.status === "string" && VALID_STATUS.has(r.status) ? r.status : "open";
|
|
17356
|
+
return {
|
|
17357
|
+
id: r.id,
|
|
17358
|
+
title: r.title,
|
|
17359
|
+
status: status2,
|
|
17360
|
+
priority: typeof r.priority === "number" ? r.priority : null,
|
|
17361
|
+
issue_type: typeof r.issue_type === "string" ? r.issue_type : "task",
|
|
17362
|
+
owner: typeof r.owner === "string" && r.owner.length > 0 ? r.owner : null,
|
|
17363
|
+
created_at: typeof r.created_at === "string" ? r.created_at : "",
|
|
17364
|
+
updated_at: typeof r.updated_at === "string" ? r.updated_at : "",
|
|
17365
|
+
dependency_count: typeof r.dependency_count === "number" ? r.dependency_count : void 0,
|
|
17366
|
+
dependent_count: typeof r.dependent_count === "number" ? r.dependent_count : void 0,
|
|
17367
|
+
comment_count: typeof r.comment_count === "number" ? r.comment_count : void 0,
|
|
17368
|
+
projectKey
|
|
17369
|
+
};
|
|
17370
|
+
}
|
|
17371
|
+
function defaultBeadsHomeDir() {
|
|
17372
|
+
return path35.join(os24.homedir(), ".beads");
|
|
17373
|
+
}
|
|
17374
|
+
|
|
17375
|
+
// src/beads/bootstrap.ts
|
|
17376
|
+
var SETUP_RECIPE = {
|
|
17377
|
+
claude: "claude",
|
|
17378
|
+
codex: "codex",
|
|
17379
|
+
cursor: "cursor",
|
|
17380
|
+
gemini: "gemini",
|
|
17381
|
+
aider: "aider",
|
|
17382
|
+
copilot: "copilot"
|
|
17383
|
+
};
|
|
17384
|
+
async function bootstrapBeads(opts) {
|
|
17385
|
+
const bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
|
|
17386
|
+
const result = {
|
|
17387
|
+
bdAvailable: false,
|
|
17388
|
+
serverUp: false,
|
|
17389
|
+
agentsConfigured: [],
|
|
17390
|
+
exportEnabled: false
|
|
17391
|
+
};
|
|
17392
|
+
if (!bd.isAvailable()) {
|
|
17393
|
+
log.warn("beads", "bd binary unavailable \u2014 skipping bootstrap");
|
|
17394
|
+
return result;
|
|
17395
|
+
}
|
|
17396
|
+
result.bdAvailable = true;
|
|
17397
|
+
result.serverUp = await ensureServer(bd);
|
|
17398
|
+
if (!result.serverUp) {
|
|
17399
|
+
log.warn("beads", "dolt sql-server not up after start \u2014 skipping wiring this run");
|
|
17400
|
+
return result;
|
|
17401
|
+
}
|
|
17402
|
+
for (const agent of opts.agents) {
|
|
17403
|
+
const recipe = SETUP_RECIPE[agent];
|
|
17404
|
+
if (!recipe) {
|
|
17405
|
+
log.trace("beads", `no bd setup recipe for agent ${agent} \u2014 skipping`);
|
|
17406
|
+
continue;
|
|
17407
|
+
}
|
|
17408
|
+
const applied = await ensureRecipe(bd, recipe);
|
|
17409
|
+
if (applied) result.agentsConfigured.push(agent);
|
|
17410
|
+
}
|
|
17411
|
+
result.exportEnabled = await ensureAutoExport(bd);
|
|
17412
|
+
log.info(
|
|
17413
|
+
"beads",
|
|
17414
|
+
`bootstrap done server=${result.serverUp} agents=[${result.agentsConfigured.join(",")}] export=${result.exportEnabled}`
|
|
17415
|
+
);
|
|
17416
|
+
return result;
|
|
17417
|
+
}
|
|
17418
|
+
async function ensureServer(bd) {
|
|
17419
|
+
const status2 = await bd.run(["dolt", "status"]);
|
|
17420
|
+
if (status2.code === 0) {
|
|
17421
|
+
log.trace("beads", "dolt sql-server already running");
|
|
17422
|
+
return true;
|
|
17423
|
+
}
|
|
17424
|
+
log.info("beads", "dolt sql-server down \u2014 starting detached");
|
|
17425
|
+
const start2 = await bd.run(["dolt", "start"]);
|
|
17426
|
+
if (start2.code !== 0) {
|
|
17427
|
+
log.warn("beads", `bd dolt start failed (code=${start2.code}): ${start2.stderr.slice(0, 200)}`);
|
|
17428
|
+
return false;
|
|
17429
|
+
}
|
|
17430
|
+
const recheck = await bd.run(["dolt", "status"]);
|
|
17431
|
+
return recheck.code === 0;
|
|
17432
|
+
}
|
|
17433
|
+
async function ensureRecipe(bd, recipe) {
|
|
17434
|
+
const check = await bd.run(["setup", recipe, "--check"]);
|
|
17435
|
+
if (check.code === 0) {
|
|
17436
|
+
log.trace("beads", `recipe ${recipe} already configured`);
|
|
17437
|
+
return false;
|
|
17438
|
+
}
|
|
17439
|
+
const setup = await bd.run(["setup", recipe]);
|
|
17440
|
+
if (setup.code !== 0) {
|
|
17441
|
+
log.warn("beads", `bd setup ${recipe} failed (code=${setup.code})`);
|
|
17442
|
+
return false;
|
|
17443
|
+
}
|
|
17444
|
+
log.info("beads", `configured agent recipe: ${recipe}`);
|
|
17445
|
+
return true;
|
|
17446
|
+
}
|
|
17447
|
+
async function ensureAutoExport(bd) {
|
|
17448
|
+
const res = await bd.run(["config", "set", "export.jsonl", "true"]);
|
|
17449
|
+
return res.code === 0;
|
|
17450
|
+
}
|
|
17451
|
+
|
|
17452
|
+
// src/beads/watcher.ts
|
|
17453
|
+
var crypto3 = __toESM(require("crypto"));
|
|
17454
|
+
var path37 = __toESM(require("path"));
|
|
17455
|
+
|
|
17456
|
+
// src/beads/project-key.ts
|
|
17457
|
+
var import_child_process13 = require("child_process");
|
|
17458
|
+
var crypto2 = __toESM(require("crypto"));
|
|
17459
|
+
var fs30 = __toESM(require("fs"));
|
|
17460
|
+
var path36 = __toESM(require("path"));
|
|
17461
|
+
function normalizeOrigin(raw) {
|
|
17462
|
+
const trimmed = raw.trim();
|
|
17463
|
+
if (!trimmed) return null;
|
|
17464
|
+
let host;
|
|
17465
|
+
let pathPart;
|
|
17466
|
+
const scpLike = /^[^/@]+@([^:]+):(.+)$/.exec(trimmed);
|
|
17467
|
+
if (scpLike && !trimmed.includes("://")) {
|
|
17468
|
+
host = scpLike[1];
|
|
17469
|
+
pathPart = scpLike[2];
|
|
17470
|
+
} else {
|
|
17471
|
+
let url;
|
|
17472
|
+
try {
|
|
17473
|
+
url = new URL(trimmed);
|
|
17474
|
+
} catch {
|
|
17475
|
+
return null;
|
|
17476
|
+
}
|
|
17477
|
+
host = url.hostname;
|
|
17478
|
+
pathPart = url.pathname;
|
|
17479
|
+
}
|
|
17480
|
+
host = host.toLowerCase();
|
|
17481
|
+
pathPart = pathPart.replace(/^\/+/, "").replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
17482
|
+
if (!host || !pathPart) return null;
|
|
17483
|
+
return `${host}/${pathPart}`;
|
|
17484
|
+
}
|
|
17485
|
+
function findRepoRoot(cwd) {
|
|
17486
|
+
let dir = path36.resolve(cwd);
|
|
17487
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17488
|
+
for (let i = 0; i < 256; i++) {
|
|
17489
|
+
if (seen.has(dir)) return null;
|
|
17490
|
+
seen.add(dir);
|
|
17491
|
+
try {
|
|
17492
|
+
const stat3 = fs30.statSync(path36.join(dir, ".git"), { throwIfNoEntry: false });
|
|
17493
|
+
if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
|
|
17494
|
+
} catch {
|
|
17495
|
+
}
|
|
17496
|
+
const parent = path36.dirname(dir);
|
|
17497
|
+
if (parent === dir) return null;
|
|
17498
|
+
dir = parent;
|
|
17499
|
+
}
|
|
17500
|
+
return null;
|
|
17501
|
+
}
|
|
17502
|
+
var _execSeam2 = {
|
|
17503
|
+
exec: (file, args2, opts) => {
|
|
17504
|
+
const out2 = (0, import_child_process13.execFileSync)(file, args2, opts);
|
|
17505
|
+
return typeof out2 === "string" ? out2 : out2.toString("utf8");
|
|
17506
|
+
},
|
|
17507
|
+
realpath: (p2) => fs30.realpathSync(p2)
|
|
17508
|
+
};
|
|
17509
|
+
function readOrigin(cwd) {
|
|
17510
|
+
try {
|
|
17511
|
+
const raw = _execSeam2.exec("git", ["remote", "get-url", "origin"], {
|
|
17512
|
+
cwd,
|
|
17513
|
+
timeout: 1e3,
|
|
17514
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
17515
|
+
encoding: "utf8"
|
|
17516
|
+
});
|
|
17517
|
+
return raw.trim() || null;
|
|
17518
|
+
} catch {
|
|
17519
|
+
return null;
|
|
17520
|
+
}
|
|
17521
|
+
}
|
|
17522
|
+
function deriveProjectIdentity(cwd = process.cwd()) {
|
|
17523
|
+
const repoRoot = findRepoRoot(cwd) ?? cwd;
|
|
17524
|
+
const origin = readOrigin(repoRoot);
|
|
17525
|
+
const normalized = origin ? normalizeOrigin(origin) : null;
|
|
17526
|
+
if (normalized) {
|
|
17527
|
+
const label = normalized.split("/").pop() || normalized;
|
|
17528
|
+
return { projectKey: normalized, projectLabel: label };
|
|
17529
|
+
}
|
|
17530
|
+
let real = repoRoot;
|
|
17531
|
+
try {
|
|
17532
|
+
real = _execSeam2.realpath(repoRoot);
|
|
17533
|
+
} catch {
|
|
17534
|
+
}
|
|
17535
|
+
const hash = crypto2.createHash("sha256").update(real).digest("hex");
|
|
17536
|
+
return { projectKey: `path:${hash}`, projectLabel: path36.basename(real) || "project" };
|
|
17537
|
+
}
|
|
17538
|
+
|
|
17539
|
+
// src/services/file-watcher/transport.ts
|
|
17540
|
+
var http5 = __toESM(require("http"));
|
|
17541
|
+
var https5 = __toESM(require("https"));
|
|
17542
|
+
var _transport3 = {
|
|
17543
|
+
post: _post2
|
|
17544
|
+
};
|
|
17545
|
+
function _post2(url, headers, payload) {
|
|
17546
|
+
return new Promise((resolve7, reject) => {
|
|
17547
|
+
let settled = false;
|
|
17548
|
+
const u2 = new URL(url);
|
|
17549
|
+
const lib = u2.protocol === "https:" ? https5 : http5;
|
|
17550
|
+
const req = lib.request(
|
|
17551
|
+
{
|
|
17552
|
+
hostname: u2.hostname,
|
|
17553
|
+
port: u2.port || (u2.protocol === "https:" ? 443 : 80),
|
|
17554
|
+
path: u2.pathname + u2.search,
|
|
17555
|
+
method: "POST",
|
|
17556
|
+
headers: {
|
|
17557
|
+
...headers,
|
|
17558
|
+
...vercelBypassHeader(),
|
|
17559
|
+
"Content-Length": Buffer.byteLength(payload)
|
|
17560
|
+
},
|
|
17561
|
+
timeout: 8e3
|
|
17562
|
+
},
|
|
17563
|
+
(res) => {
|
|
17564
|
+
let body = "";
|
|
17565
|
+
res.on("data", (c2) => {
|
|
17566
|
+
body += c2.toString();
|
|
17567
|
+
});
|
|
17568
|
+
res.on("end", () => {
|
|
17569
|
+
if (settled) return;
|
|
17570
|
+
settled = true;
|
|
17571
|
+
resolve7({ statusCode: res.statusCode ?? 0, body });
|
|
17572
|
+
});
|
|
17573
|
+
}
|
|
17574
|
+
);
|
|
17575
|
+
req.on("error", (err) => {
|
|
17576
|
+
if (settled) return;
|
|
17577
|
+
settled = true;
|
|
17578
|
+
reject(err);
|
|
17579
|
+
});
|
|
17580
|
+
req.on("timeout", () => {
|
|
17581
|
+
req.destroy();
|
|
17582
|
+
});
|
|
17583
|
+
req.write(payload);
|
|
17584
|
+
req.end();
|
|
17585
|
+
});
|
|
17586
|
+
}
|
|
17587
|
+
|
|
17588
|
+
// src/beads/watcher.ts
|
|
17589
|
+
var API_BASE4 = resolveApiBaseUrl();
|
|
17590
|
+
var DEBOUNCE_MS = 400;
|
|
17591
|
+
var _chokidarSeam = {
|
|
17592
|
+
load: () => {
|
|
17593
|
+
try {
|
|
17594
|
+
return require("chokidar");
|
|
17595
|
+
} catch {
|
|
17596
|
+
return null;
|
|
17597
|
+
}
|
|
17598
|
+
}
|
|
17599
|
+
};
|
|
17600
|
+
var BeadsWatcher = class {
|
|
17601
|
+
constructor(opts) {
|
|
17602
|
+
this.opts = opts;
|
|
17603
|
+
this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
|
|
17604
|
+
this.feedPath = opts.feedPath ?? path37.join(defaultBeadsHomeDir(), "issues.jsonl");
|
|
17605
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE4;
|
|
17606
|
+
}
|
|
17607
|
+
opts;
|
|
17608
|
+
watcher = null;
|
|
17609
|
+
debounceTimer = null;
|
|
17610
|
+
stopped = false;
|
|
17611
|
+
lastPushedHash = null;
|
|
17612
|
+
bd;
|
|
17613
|
+
feedPath;
|
|
17614
|
+
apiBase;
|
|
17615
|
+
/** Start tailing the change feed. Idempotent (second call is a no-op). */
|
|
17616
|
+
start() {
|
|
17617
|
+
if (this.watcher || this.stopped) return;
|
|
17618
|
+
const chokidar2 = _chokidarSeam.load();
|
|
17619
|
+
if (!chokidar2) {
|
|
17620
|
+
log.warn("beads", "chokidar unavailable \u2014 beads watcher disabled");
|
|
17621
|
+
return;
|
|
17622
|
+
}
|
|
17623
|
+
const watcher = chokidar2.watch(this.feedPath, {
|
|
17624
|
+
ignoreInitial: false,
|
|
17625
|
+
// push the current state once on start
|
|
17626
|
+
persistent: true,
|
|
17627
|
+
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 100 }
|
|
17628
|
+
});
|
|
17629
|
+
watcher.on("add", () => this.scheduleSync());
|
|
17630
|
+
watcher.on("change", () => this.scheduleSync());
|
|
17631
|
+
watcher.on(
|
|
17632
|
+
"error",
|
|
17633
|
+
(err) => log.warn("beads", `feed watcher error \u2014 continuing: ${err}`)
|
|
17634
|
+
);
|
|
17635
|
+
this.watcher = watcher;
|
|
17636
|
+
log.info("beads", `watching ${this.feedPath} for session=${this.opts.sessionId.slice(0, 8)}`);
|
|
17637
|
+
}
|
|
17638
|
+
async stop() {
|
|
17639
|
+
if (this.stopped) return;
|
|
17640
|
+
this.stopped = true;
|
|
17641
|
+
if (this.debounceTimer) {
|
|
17642
|
+
clearTimeout(this.debounceTimer);
|
|
17643
|
+
this.debounceTimer = null;
|
|
17644
|
+
}
|
|
17645
|
+
if (this.watcher) {
|
|
17646
|
+
try {
|
|
17647
|
+
await this.watcher.close();
|
|
17648
|
+
} catch (err) {
|
|
17649
|
+
log.warn("beads", "error closing feed watcher", err);
|
|
17650
|
+
}
|
|
17651
|
+
this.watcher = null;
|
|
17652
|
+
}
|
|
17653
|
+
}
|
|
17654
|
+
/**
|
|
17655
|
+
* Debounce the filesystem event. Each fresh write resets the timer so a
|
|
17656
|
+
* burst of bd mutations coalesces into one snapshot push. NOT polling — the
|
|
17657
|
+
* timer only fires off the back of a real fs event.
|
|
17658
|
+
*/
|
|
17659
|
+
scheduleSync() {
|
|
17660
|
+
if (this.stopped) return;
|
|
17661
|
+
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
17662
|
+
this.debounceTimer = setTimeout(() => {
|
|
17663
|
+
this.debounceTimer = null;
|
|
17664
|
+
void this.syncNow();
|
|
17665
|
+
}, DEBOUNCE_MS);
|
|
17666
|
+
}
|
|
17667
|
+
/** Visible for tests — pump a synthetic feed event through debounce → push. */
|
|
17668
|
+
/* @internal */
|
|
17669
|
+
_emitForTest() {
|
|
17670
|
+
this.scheduleSync();
|
|
17671
|
+
}
|
|
17672
|
+
/**
|
|
17673
|
+
* Build the full snapshot from bd and push it. Diffs against the last
|
|
17674
|
+
* pushed content hash so an identical rewrite is a no-op.
|
|
17675
|
+
*/
|
|
17676
|
+
async syncNow() {
|
|
17677
|
+
if (this.stopped) return;
|
|
17678
|
+
const { projectKey, projectLabel } = deriveProjectIdentity(this.opts.cwd);
|
|
17679
|
+
const [issues, summary] = await Promise.all([
|
|
17680
|
+
this.bd.listIssues(projectKey),
|
|
17681
|
+
this.bd.statusSummary()
|
|
17682
|
+
]);
|
|
17683
|
+
const payload = {
|
|
17684
|
+
sessionId: this.opts.sessionId,
|
|
17685
|
+
pluginId: this.opts.pluginId,
|
|
17686
|
+
projectKey,
|
|
17687
|
+
projectLabel,
|
|
17688
|
+
fullSnapshot: true,
|
|
17689
|
+
issues,
|
|
17690
|
+
memories: [],
|
|
17691
|
+
...summary ? { summary } : {}
|
|
17692
|
+
};
|
|
17693
|
+
const body = JSON.stringify(payload);
|
|
17694
|
+
const hash = crypto3.createHash("sha256").update(body).digest("hex");
|
|
17695
|
+
if (hash === this.lastPushedHash) {
|
|
17696
|
+
log.trace("beads", "snapshot unchanged \u2014 skipping push");
|
|
17697
|
+
return;
|
|
17698
|
+
}
|
|
17699
|
+
try {
|
|
17700
|
+
const res = await _transport3.post(`${this.apiBase}/api/beads/ingest`, this.headers(), body);
|
|
17701
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
17702
|
+
this.lastPushedHash = hash;
|
|
17703
|
+
log.trace("beads", `pushed ${issues.length} issue(s) project=${projectLabel}`);
|
|
17704
|
+
} else if (res.statusCode === 404 || res.statusCode === 410) {
|
|
17705
|
+
log.warn("beads", `session dead (status=${res.statusCode}) \u2014 stopping watcher`);
|
|
17706
|
+
this.stopped = true;
|
|
17707
|
+
} else {
|
|
17708
|
+
log.warn("beads", `ingest failed status=${res.statusCode} body=${res.body.slice(0, 200)}`);
|
|
17709
|
+
}
|
|
17710
|
+
} catch (err) {
|
|
17711
|
+
log.warn("beads", "ingest POST error", err);
|
|
17712
|
+
}
|
|
17713
|
+
}
|
|
17714
|
+
headers() {
|
|
17715
|
+
return {
|
|
17716
|
+
"Content-Type": "application/json",
|
|
17717
|
+
"X-Codeam-Protocol-Version": "2.0.0",
|
|
17718
|
+
"X-Plugin-Auth-Token": this.opts.pluginAuthToken
|
|
17719
|
+
};
|
|
17720
|
+
}
|
|
17721
|
+
};
|
|
17722
|
+
|
|
17723
|
+
// src/beads/apply-actions.ts
|
|
17724
|
+
function buildBdArgs(action) {
|
|
17725
|
+
switch (action.kind) {
|
|
17726
|
+
case "claim": {
|
|
17727
|
+
if (!action.issueId) return null;
|
|
17728
|
+
const args2 = ["update", action.issueId, "--claim"];
|
|
17729
|
+
if (action.owner) args2.push("--owner", action.owner);
|
|
17730
|
+
return args2;
|
|
17731
|
+
}
|
|
17732
|
+
case "close": {
|
|
17733
|
+
if (!action.issueId) return null;
|
|
17734
|
+
const args2 = ["close", action.issueId];
|
|
17735
|
+
if (action.reason) args2.push("--reason", action.reason);
|
|
17736
|
+
return args2;
|
|
17737
|
+
}
|
|
17738
|
+
case "create": {
|
|
17739
|
+
const title = action.text?.trim();
|
|
17740
|
+
if (!title) return null;
|
|
17741
|
+
return ["create", title];
|
|
17742
|
+
}
|
|
17743
|
+
case "remember": {
|
|
17744
|
+
const body = action.text?.trim();
|
|
17745
|
+
if (!body) return null;
|
|
17746
|
+
return ["remember", body];
|
|
17747
|
+
}
|
|
17748
|
+
default:
|
|
17749
|
+
return null;
|
|
17750
|
+
}
|
|
17751
|
+
}
|
|
17752
|
+
async function applyBeadsAction(action, deps) {
|
|
17753
|
+
const args2 = buildBdArgs(action);
|
|
17754
|
+
if (!args2) {
|
|
17755
|
+
log.warn("beads", `malformed beads action: kind=${action.kind}`);
|
|
17756
|
+
return { ok: false, action: action.kind, code: -1, error: "malformed action" };
|
|
17757
|
+
}
|
|
17758
|
+
if (!deps.adapter.isAvailable()) {
|
|
17759
|
+
return { ok: false, action: action.kind, code: -1, error: "bd unavailable" };
|
|
17760
|
+
}
|
|
17761
|
+
const res = await deps.adapter.run(args2);
|
|
17762
|
+
if (res.code !== 0) {
|
|
17763
|
+
log.warn("beads", `bd ${args2.join(" ")} failed (code=${res.code}): ${res.stderr.slice(0, 200)}`);
|
|
17764
|
+
return { ok: false, action: action.kind, code: res.code, error: res.stderr };
|
|
17765
|
+
}
|
|
17766
|
+
log.info("beads", `applied action ${action.kind}${action.issueId ? ` (${action.issueId})` : ""}`);
|
|
17767
|
+
try {
|
|
17768
|
+
await deps.onApplied();
|
|
17769
|
+
} catch (err) {
|
|
17770
|
+
log.warn("beads", "post-action push failed (state still applied locally)", err);
|
|
17771
|
+
}
|
|
17772
|
+
return { ok: true, action: action.kind, code: 0 };
|
|
17773
|
+
}
|
|
17774
|
+
|
|
17775
|
+
// src/beads/install-bd.ts
|
|
17776
|
+
var import_child_process14 = require("child_process");
|
|
17777
|
+
var INSTALL_SH_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh";
|
|
17778
|
+
var INSTALL_PS1_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/install.ps1";
|
|
17779
|
+
function resolveInstallStrategy(platform2) {
|
|
17780
|
+
if (platform2 === "win32") {
|
|
17781
|
+
return {
|
|
17782
|
+
command: "powershell.exe",
|
|
17783
|
+
args: [
|
|
17784
|
+
"-NoProfile",
|
|
17785
|
+
"-NonInteractive",
|
|
17786
|
+
"-ExecutionPolicy",
|
|
17787
|
+
"Bypass",
|
|
17788
|
+
"-Command",
|
|
17789
|
+
`irm ${INSTALL_PS1_URL} | iex`
|
|
17790
|
+
],
|
|
17791
|
+
description: `PowerShell: irm ${INSTALL_PS1_URL} | iex (requires Go 1.24+ and Git for Windows on PATH)`
|
|
17792
|
+
};
|
|
17793
|
+
}
|
|
17794
|
+
return {
|
|
17795
|
+
command: "bash",
|
|
17796
|
+
args: ["-c", `curl -fsSL ${INSTALL_SH_URL} | bash`],
|
|
17797
|
+
description: `curl -fsSL ${INSTALL_SH_URL} | bash`
|
|
17798
|
+
};
|
|
17799
|
+
}
|
|
17800
|
+
var _installSpawnSeam = {
|
|
17801
|
+
run: _defaultInstallSpawn
|
|
17802
|
+
};
|
|
17803
|
+
function _defaultInstallSpawn(strategy) {
|
|
17804
|
+
return new Promise((resolve7) => {
|
|
17805
|
+
let proc;
|
|
17806
|
+
try {
|
|
17807
|
+
proc = (0, import_child_process14.spawn)(strategy.command, strategy.args, { env: process.env });
|
|
17808
|
+
} catch (err) {
|
|
17809
|
+
resolve7({ ok: false, code: -1, stderr: err.message });
|
|
17810
|
+
return;
|
|
17811
|
+
}
|
|
17812
|
+
let stderr = "";
|
|
17813
|
+
proc.stderr?.on("data", (c2) => {
|
|
17814
|
+
stderr += c2.toString();
|
|
17815
|
+
});
|
|
17816
|
+
proc.on("error", (err) => resolve7({ ok: false, code: -1, stderr: err.message }));
|
|
17817
|
+
proc.on(
|
|
17818
|
+
"close",
|
|
17819
|
+
(code) => resolve7({ ok: code === 0, code: code ?? -1, stderr })
|
|
17820
|
+
);
|
|
17821
|
+
});
|
|
17822
|
+
}
|
|
17823
|
+
async function installBd(platform2 = process.platform) {
|
|
17824
|
+
const strategy = resolveInstallStrategy(platform2);
|
|
17825
|
+
log.info("beads", `installing bd via ${strategy.description}`);
|
|
17826
|
+
const result = await _installSpawnSeam.run(strategy);
|
|
17827
|
+
if (!result.ok) {
|
|
17828
|
+
log.warn(
|
|
17829
|
+
"beads",
|
|
17830
|
+
`bd install failed (code=${result.code}): ${result.stderr.slice(0, 200)}`
|
|
17831
|
+
);
|
|
17832
|
+
}
|
|
17833
|
+
return result;
|
|
17834
|
+
}
|
|
17835
|
+
|
|
17836
|
+
// src/beads/index.ts
|
|
17837
|
+
async function maybeStartBeads(opts) {
|
|
17838
|
+
if (!opts.enabled) {
|
|
17839
|
+
log.trace("beads", "beads flag off \u2014 skipping");
|
|
17840
|
+
return null;
|
|
17841
|
+
}
|
|
17842
|
+
const adapter = new BdAdapter({ cwd: opts.cwd });
|
|
17843
|
+
if (!adapter.isAvailable() && opts.allowInstall) {
|
|
17844
|
+
log.info("beads", "bd not found \u2014 running OS installer");
|
|
17845
|
+
await installBd();
|
|
17846
|
+
}
|
|
17847
|
+
if (!adapter.isAvailable()) {
|
|
17848
|
+
log.warn("beads", "bd unavailable \u2014 beads disabled for this session");
|
|
17849
|
+
return null;
|
|
17850
|
+
}
|
|
17851
|
+
const boot = await bootstrapBeads({ cwd: opts.cwd, agents: opts.agents, adapter });
|
|
17852
|
+
if (!boot.serverUp) {
|
|
17853
|
+
log.warn("beads", "beads server not up \u2014 watcher not started this run");
|
|
17854
|
+
return null;
|
|
17855
|
+
}
|
|
17856
|
+
const watcher = new BeadsWatcher({
|
|
17857
|
+
sessionId: opts.sessionId,
|
|
17858
|
+
pluginId: opts.pluginId,
|
|
17859
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
17860
|
+
cwd: opts.cwd,
|
|
17861
|
+
adapter
|
|
17862
|
+
});
|
|
17863
|
+
watcher.start();
|
|
17864
|
+
void watcher.syncNow();
|
|
17865
|
+
return { watcher, adapter };
|
|
17866
|
+
}
|
|
17867
|
+
async function handleBeadsActionCommand(action, started) {
|
|
17868
|
+
await applyBeadsAction(action, {
|
|
17869
|
+
adapter: started.adapter,
|
|
17870
|
+
onApplied: () => started.watcher.syncNow()
|
|
17871
|
+
});
|
|
17872
|
+
}
|
|
17873
|
+
|
|
17874
|
+
// src/beads/wiring.ts
|
|
17875
|
+
function beadsKilled() {
|
|
17876
|
+
const v = process.env.CODEAM_BEADS_DISABLED;
|
|
17877
|
+
return !!v && v !== "0" && v.toLowerCase() !== "false";
|
|
17878
|
+
}
|
|
17879
|
+
async function startBeadsForSession(ctx) {
|
|
17880
|
+
if (beadsKilled()) {
|
|
17881
|
+
log.trace("beads", "CODEAM_BEADS_DISABLED set \u2014 beads off for this session");
|
|
17882
|
+
return null;
|
|
17883
|
+
}
|
|
17884
|
+
if (!ctx.pluginAuthToken) {
|
|
17885
|
+
log.trace("beads", "no pluginAuthToken on session \u2014 beads off");
|
|
17886
|
+
return null;
|
|
17887
|
+
}
|
|
17888
|
+
try {
|
|
17889
|
+
return await maybeStartBeads({
|
|
17890
|
+
enabled: true,
|
|
17891
|
+
sessionId: ctx.sessionId,
|
|
17892
|
+
pluginId: ctx.pluginId,
|
|
17893
|
+
pluginAuthToken: ctx.pluginAuthToken,
|
|
17894
|
+
agents: ctx.agents,
|
|
17895
|
+
cwd: ctx.cwd
|
|
17896
|
+
});
|
|
17897
|
+
} catch (err) {
|
|
17898
|
+
log.warn("beads", "startBeadsForSession failed (non-fatal)", err);
|
|
17899
|
+
return null;
|
|
17900
|
+
}
|
|
17901
|
+
}
|
|
17902
|
+
var ACTION_KINDS = /* @__PURE__ */ new Set([
|
|
17903
|
+
"claim",
|
|
17904
|
+
"close",
|
|
17905
|
+
"create",
|
|
17906
|
+
"remember"
|
|
17907
|
+
]);
|
|
17908
|
+
function isBeadsActionKind(v) {
|
|
17909
|
+
return typeof v === "string" && ACTION_KINDS.has(v);
|
|
17910
|
+
}
|
|
17911
|
+
function strOrUndefined(v) {
|
|
17912
|
+
return typeof v === "string" ? v : void 0;
|
|
17913
|
+
}
|
|
17914
|
+
function beadsActionFromPayload(payload) {
|
|
17915
|
+
const { action, args: args2 } = payload;
|
|
17916
|
+
if (!isBeadsActionKind(action)) return null;
|
|
17917
|
+
const a = args2 && typeof args2 === "object" ? args2 : {};
|
|
17918
|
+
return {
|
|
17919
|
+
kind: action,
|
|
17920
|
+
issueId: strOrUndefined(a.issueId),
|
|
17921
|
+
text: strOrUndefined(a.text),
|
|
17922
|
+
reason: strOrUndefined(a.reason),
|
|
17923
|
+
owner: strOrUndefined(a.owner),
|
|
17924
|
+
projectKey: strOrUndefined(a.projectKey)
|
|
17925
|
+
};
|
|
17926
|
+
}
|
|
17927
|
+
|
|
17181
17928
|
// src/commands/start/handlers.ts
|
|
17182
17929
|
var pendingAttachmentFiles = /* @__PURE__ */ new Set();
|
|
17183
17930
|
function cleanupAttachmentTempFiles() {
|
|
17184
17931
|
for (const p2 of pendingAttachmentFiles) {
|
|
17185
17932
|
try {
|
|
17186
|
-
|
|
17933
|
+
fs31.unlinkSync(p2);
|
|
17187
17934
|
} catch {
|
|
17188
17935
|
}
|
|
17189
17936
|
}
|
|
@@ -17192,8 +17939,8 @@ function cleanupAttachmentTempFiles() {
|
|
|
17192
17939
|
function saveFilesTemp(files) {
|
|
17193
17940
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
17194
17941
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
17195
|
-
const tmpPath =
|
|
17196
|
-
|
|
17942
|
+
const tmpPath = path38.join(os25.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
|
|
17943
|
+
fs31.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
17197
17944
|
pendingAttachmentFiles.add(tmpPath);
|
|
17198
17945
|
return tmpPath;
|
|
17199
17946
|
});
|
|
@@ -17213,7 +17960,7 @@ var startTask = (ctx, _cmd, parsed) => {
|
|
|
17213
17960
|
setTimeout(() => {
|
|
17214
17961
|
for (const p2 of paths) {
|
|
17215
17962
|
try {
|
|
17216
|
-
|
|
17963
|
+
fs31.unlinkSync(p2);
|
|
17217
17964
|
} catch {
|
|
17218
17965
|
}
|
|
17219
17966
|
pendingAttachmentFiles.delete(p2);
|
|
@@ -17338,7 +18085,7 @@ var sessionTerminated = async (ctx, cmd) => {
|
|
|
17338
18085
|
} catch {
|
|
17339
18086
|
}
|
|
17340
18087
|
try {
|
|
17341
|
-
const proc = (0,
|
|
18088
|
+
const proc = (0, import_child_process15.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
17342
18089
|
detached: true,
|
|
17343
18090
|
stdio: "ignore"
|
|
17344
18091
|
});
|
|
@@ -17360,7 +18107,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
17360
18107
|
}
|
|
17361
18108
|
if (ctx.keepAliveCtx.inCodespace && ctx.keepAliveCtx.codespaceName) {
|
|
17362
18109
|
try {
|
|
17363
|
-
const stopProc = (0,
|
|
18110
|
+
const stopProc = (0, import_child_process15.spawn)(
|
|
17364
18111
|
"bash",
|
|
17365
18112
|
["-lc", `sleep 1; gh codespace stop -c ${JSON.stringify(ctx.keepAliveCtx.codespaceName)} >/dev/null 2>&1 || true`],
|
|
17366
18113
|
{ detached: true, stdio: "ignore" }
|
|
@@ -17370,7 +18117,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
17370
18117
|
}
|
|
17371
18118
|
}
|
|
17372
18119
|
try {
|
|
17373
|
-
const proc = (0,
|
|
18120
|
+
const proc = (0, import_child_process15.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
17374
18121
|
detached: true,
|
|
17375
18122
|
stdio: "ignore"
|
|
17376
18123
|
});
|
|
@@ -17786,8 +18533,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
|
|
|
17786
18533
|
if (args2.length === 0) return detection;
|
|
17787
18534
|
const binName = args2[0];
|
|
17788
18535
|
if (binName.startsWith("-")) return detection;
|
|
17789
|
-
const binPath =
|
|
17790
|
-
if (!
|
|
18536
|
+
const binPath = path38.join(cwd, "node_modules", ".bin", binName);
|
|
18537
|
+
if (!fs31.existsSync(binPath)) return detection;
|
|
17791
18538
|
return {
|
|
17792
18539
|
...detection,
|
|
17793
18540
|
command: binPath,
|
|
@@ -17877,7 +18624,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
17877
18624
|
"BOOT_SEQUENCE",
|
|
17878
18625
|
`${spawnable.command} ${spawnable.args.join(" ")}`
|
|
17879
18626
|
);
|
|
17880
|
-
const devServer = (0,
|
|
18627
|
+
const devServer = (0, import_child_process15.spawn)(spawnable.command, spawnable.args, {
|
|
17881
18628
|
cwd: process.cwd(),
|
|
17882
18629
|
env: { ...process.env, ...spawnable.env ?? {} },
|
|
17883
18630
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -18003,7 +18750,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
18003
18750
|
});
|
|
18004
18751
|
return;
|
|
18005
18752
|
}
|
|
18006
|
-
tunnel = (0,
|
|
18753
|
+
tunnel = (0, import_child_process15.spawn)(bin, ["tunnel", "--url", `http://localhost:${detection.port}`], {
|
|
18007
18754
|
stdio: ["ignore", "pipe", "pipe"]
|
|
18008
18755
|
});
|
|
18009
18756
|
let parsedUrl = null;
|
|
@@ -18100,8 +18847,8 @@ var previewStopH = (ctx) => {
|
|
|
18100
18847
|
})();
|
|
18101
18848
|
};
|
|
18102
18849
|
function runOnce(cmd, args2, cwd, env) {
|
|
18103
|
-
return new Promise((
|
|
18104
|
-
const child = (0,
|
|
18850
|
+
return new Promise((resolve7) => {
|
|
18851
|
+
const child = (0, import_child_process15.spawn)(cmd, args2, {
|
|
18105
18852
|
cwd,
|
|
18106
18853
|
env: { ...process.env, ...env ?? {} },
|
|
18107
18854
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -18114,8 +18861,8 @@ function runOnce(cmd, args2, cwd, env) {
|
|
|
18114
18861
|
};
|
|
18115
18862
|
child.stdout?.on("data", onChunk);
|
|
18116
18863
|
child.stderr?.on("data", onChunk);
|
|
18117
|
-
child.once("exit", (code) =>
|
|
18118
|
-
child.once("error", () =>
|
|
18864
|
+
child.once("exit", (code) => resolve7(code));
|
|
18865
|
+
child.once("error", () => resolve7(-1));
|
|
18119
18866
|
});
|
|
18120
18867
|
}
|
|
18121
18868
|
var savePreviewConfigH = (_ctx, _cmd, parsed) => {
|
|
@@ -18169,6 +18916,23 @@ var handlers = {
|
|
|
18169
18916
|
save_preview_config: savePreviewConfigH
|
|
18170
18917
|
};
|
|
18171
18918
|
async function dispatchCommand(ctx, cmd) {
|
|
18919
|
+
if (cmd.type === "beads_action") {
|
|
18920
|
+
if (!ctx.beads) {
|
|
18921
|
+
log.trace("beads", "beads_action received but beads not running this session \u2014 dropping");
|
|
18922
|
+
return;
|
|
18923
|
+
}
|
|
18924
|
+
const action = beadsActionFromPayload(cmd.payload);
|
|
18925
|
+
if (!action) {
|
|
18926
|
+
log.warn("beads", "malformed beads_action payload \u2014 dropping");
|
|
18927
|
+
return;
|
|
18928
|
+
}
|
|
18929
|
+
try {
|
|
18930
|
+
await handleBeadsActionCommand(action, ctx.beads);
|
|
18931
|
+
} catch (err) {
|
|
18932
|
+
log.warn("beads", "handleBeadsActionCommand failed (non-fatal)", err);
|
|
18933
|
+
}
|
|
18934
|
+
return;
|
|
18935
|
+
}
|
|
18172
18936
|
const parsed = parsePayload2(startCommandSchema, cmd.payload);
|
|
18173
18937
|
if (!parsed) {
|
|
18174
18938
|
showInfo(`Ignoring malformed ${cmd.type} payload.`);
|
|
@@ -18180,10 +18944,10 @@ async function dispatchCommand(ctx, cmd) {
|
|
|
18180
18944
|
}
|
|
18181
18945
|
|
|
18182
18946
|
// src/services/file-watcher.service.ts
|
|
18183
|
-
var
|
|
18184
|
-
var
|
|
18185
|
-
var
|
|
18186
|
-
var
|
|
18947
|
+
var import_child_process16 = require("child_process");
|
|
18948
|
+
var fs32 = __toESM(require("fs"));
|
|
18949
|
+
var os26 = __toESM(require("os"));
|
|
18950
|
+
var path39 = __toESM(require("path"));
|
|
18187
18951
|
var import_ignore = __toESM(require("ignore"));
|
|
18188
18952
|
|
|
18189
18953
|
// src/services/file-watcher/diff-parser.ts
|
|
@@ -18272,58 +19036,9 @@ function isIgnoredFilePath(filePath) {
|
|
|
18272
19036
|
return IGNORED_PATH_PATTERN.test(filePath);
|
|
18273
19037
|
}
|
|
18274
19038
|
|
|
18275
|
-
// src/services/file-watcher/transport.ts
|
|
18276
|
-
var http5 = __toESM(require("http"));
|
|
18277
|
-
var https5 = __toESM(require("https"));
|
|
18278
|
-
var _transport3 = {
|
|
18279
|
-
post: _post2
|
|
18280
|
-
};
|
|
18281
|
-
function _post2(url, headers, payload) {
|
|
18282
|
-
return new Promise((resolve6, reject) => {
|
|
18283
|
-
let settled = false;
|
|
18284
|
-
const u2 = new URL(url);
|
|
18285
|
-
const lib = u2.protocol === "https:" ? https5 : http5;
|
|
18286
|
-
const req = lib.request(
|
|
18287
|
-
{
|
|
18288
|
-
hostname: u2.hostname,
|
|
18289
|
-
port: u2.port || (u2.protocol === "https:" ? 443 : 80),
|
|
18290
|
-
path: u2.pathname + u2.search,
|
|
18291
|
-
method: "POST",
|
|
18292
|
-
headers: {
|
|
18293
|
-
...headers,
|
|
18294
|
-
...vercelBypassHeader(),
|
|
18295
|
-
"Content-Length": Buffer.byteLength(payload)
|
|
18296
|
-
},
|
|
18297
|
-
timeout: 8e3
|
|
18298
|
-
},
|
|
18299
|
-
(res) => {
|
|
18300
|
-
let body = "";
|
|
18301
|
-
res.on("data", (c2) => {
|
|
18302
|
-
body += c2.toString();
|
|
18303
|
-
});
|
|
18304
|
-
res.on("end", () => {
|
|
18305
|
-
if (settled) return;
|
|
18306
|
-
settled = true;
|
|
18307
|
-
resolve6({ statusCode: res.statusCode ?? 0, body });
|
|
18308
|
-
});
|
|
18309
|
-
}
|
|
18310
|
-
);
|
|
18311
|
-
req.on("error", (err) => {
|
|
18312
|
-
if (settled) return;
|
|
18313
|
-
settled = true;
|
|
18314
|
-
reject(err);
|
|
18315
|
-
});
|
|
18316
|
-
req.on("timeout", () => {
|
|
18317
|
-
req.destroy();
|
|
18318
|
-
});
|
|
18319
|
-
req.write(payload);
|
|
18320
|
-
req.end();
|
|
18321
|
-
});
|
|
18322
|
-
}
|
|
18323
|
-
|
|
18324
19039
|
// src/services/file-watcher.service.ts
|
|
18325
|
-
var
|
|
18326
|
-
var
|
|
19040
|
+
var API_BASE5 = resolveApiBaseUrl();
|
|
19041
|
+
var DEBOUNCE_MS2 = 250;
|
|
18327
19042
|
var COALESCE_WINDOW_MS = 250;
|
|
18328
19043
|
var COALESCE_MAX_HOLD_MS = 2e3;
|
|
18329
19044
|
var MAX_RETRIES = 2;
|
|
@@ -18342,10 +19057,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
|
|
|
18342
19057
|
/[\\/]Start Menu([\\/]|$)/i,
|
|
18343
19058
|
/[\\/]Templates([\\/]|$)/i
|
|
18344
19059
|
];
|
|
18345
|
-
function isUnsafeWindowsWatchRoot(dir,
|
|
19060
|
+
function isUnsafeWindowsWatchRoot(dir, homedir22) {
|
|
18346
19061
|
const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
|
|
18347
19062
|
const cwd = norm(dir);
|
|
18348
|
-
const home = norm(
|
|
19063
|
+
const home = norm(homedir22);
|
|
18349
19064
|
if (cwd === home) return true;
|
|
18350
19065
|
if (/^[a-z]:$/.test(cwd)) return true;
|
|
18351
19066
|
const sysRoots = [
|
|
@@ -18359,7 +19074,7 @@ function isUnsafeWindowsWatchRoot(dir, homedir21) {
|
|
|
18359
19074
|
}
|
|
18360
19075
|
return false;
|
|
18361
19076
|
}
|
|
18362
|
-
var
|
|
19077
|
+
var _chokidarSeam2 = {
|
|
18363
19078
|
load: () => {
|
|
18364
19079
|
try {
|
|
18365
19080
|
return require("chokidar");
|
|
@@ -18375,18 +19090,18 @@ var _findGitRootSeam = {
|
|
|
18375
19090
|
resolve: _defaultFindGitRoot
|
|
18376
19091
|
};
|
|
18377
19092
|
function _defaultFindGitRoot(startDir) {
|
|
18378
|
-
let dir =
|
|
19093
|
+
let dir = path39.resolve(startDir);
|
|
18379
19094
|
const seen = /* @__PURE__ */ new Set();
|
|
18380
19095
|
for (let i = 0; i < 256; i++) {
|
|
18381
19096
|
if (seen.has(dir)) return null;
|
|
18382
19097
|
seen.add(dir);
|
|
18383
19098
|
try {
|
|
18384
|
-
const gitPath =
|
|
18385
|
-
const stat3 =
|
|
19099
|
+
const gitPath = path39.join(dir, ".git");
|
|
19100
|
+
const stat3 = fs32.statSync(gitPath, { throwIfNoEntry: false });
|
|
18386
19101
|
if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
|
|
18387
19102
|
} catch {
|
|
18388
19103
|
}
|
|
18389
|
-
const parent =
|
|
19104
|
+
const parent = path39.dirname(dir);
|
|
18390
19105
|
if (parent === dir) return null;
|
|
18391
19106
|
dir = parent;
|
|
18392
19107
|
}
|
|
@@ -18395,7 +19110,7 @@ function _defaultFindGitRoot(startDir) {
|
|
|
18395
19110
|
var FileWatcherService = class {
|
|
18396
19111
|
constructor(opts) {
|
|
18397
19112
|
this.opts = opts;
|
|
18398
|
-
this.apiBase = opts.apiBaseUrl ??
|
|
19113
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE5;
|
|
18399
19114
|
}
|
|
18400
19115
|
opts;
|
|
18401
19116
|
watcher = null;
|
|
@@ -18444,14 +19159,14 @@ var FileWatcherService = class {
|
|
|
18444
19159
|
throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
|
|
18445
19160
|
}
|
|
18446
19161
|
const isWin = process.platform === "win32";
|
|
18447
|
-
if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir,
|
|
19162
|
+
if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os26.homedir())) {
|
|
18448
19163
|
log.warn(
|
|
18449
19164
|
"fileWatcher",
|
|
18450
19165
|
`refusing to watch ${this.opts.workingDir} \u2014 looks like a Windows user-profile or system path. Run codeam from your project folder to enable file change emission.`
|
|
18451
19166
|
);
|
|
18452
19167
|
return;
|
|
18453
19168
|
}
|
|
18454
|
-
const chokidar2 =
|
|
19169
|
+
const chokidar2 = _chokidarSeam2.load();
|
|
18455
19170
|
if (!chokidar2) {
|
|
18456
19171
|
log.warn(
|
|
18457
19172
|
"fileWatcher",
|
|
@@ -18570,7 +19285,7 @@ var FileWatcherService = class {
|
|
|
18570
19285
|
const timer = setTimeout(() => {
|
|
18571
19286
|
this.pending.delete(absPath);
|
|
18572
19287
|
this.enqueueForCoalesce(absPath, changeType);
|
|
18573
|
-
},
|
|
19288
|
+
}, DEBOUNCE_MS2);
|
|
18574
19289
|
this.pending.set(absPath, {
|
|
18575
19290
|
lastEventAt: Date.now(),
|
|
18576
19291
|
timer,
|
|
@@ -18631,7 +19346,7 @@ var FileWatcherService = class {
|
|
|
18631
19346
|
}
|
|
18632
19347
|
async emitForFile(absPath, changeType) {
|
|
18633
19348
|
if (this.stopped) return;
|
|
18634
|
-
const fileDir =
|
|
19349
|
+
const fileDir = path39.dirname(absPath);
|
|
18635
19350
|
let gitRoot = this.gitRootByDir.get(fileDir);
|
|
18636
19351
|
if (gitRoot === void 0) {
|
|
18637
19352
|
gitRoot = findGitRoot2(fileDir);
|
|
@@ -18644,19 +19359,19 @@ var FileWatcherService = class {
|
|
|
18644
19359
|
);
|
|
18645
19360
|
return;
|
|
18646
19361
|
}
|
|
18647
|
-
const relPathInRepo =
|
|
19362
|
+
const relPathInRepo = path39.relative(gitRoot, absPath);
|
|
18648
19363
|
if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
|
|
18649
19364
|
const matcher = this.getGitIgnoreMatcher(gitRoot);
|
|
18650
19365
|
if (matcher && matcher.ignores(relPathInRepo)) {
|
|
18651
19366
|
log.trace(
|
|
18652
19367
|
"fileWatcher",
|
|
18653
|
-
`${relPathInRepo} ignored by ${
|
|
19368
|
+
`${relPathInRepo} ignored by ${path39.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
|
|
18654
19369
|
);
|
|
18655
19370
|
return;
|
|
18656
19371
|
}
|
|
18657
19372
|
this.opts.onRepoDirty?.(gitRoot);
|
|
18658
|
-
const repoPath =
|
|
18659
|
-
const repoName =
|
|
19373
|
+
const repoPath = path39.relative(this.opts.workingDir, gitRoot);
|
|
19374
|
+
const repoName = path39.basename(gitRoot);
|
|
18660
19375
|
let diffText = "";
|
|
18661
19376
|
let fileStatus = "modified";
|
|
18662
19377
|
if (changeType === "unlink") {
|
|
@@ -18831,7 +19546,7 @@ var FileWatcherService = class {
|
|
|
18831
19546
|
collectGitignoreFiles(repoRoot, dir, matcher) {
|
|
18832
19547
|
let entries;
|
|
18833
19548
|
try {
|
|
18834
|
-
entries =
|
|
19549
|
+
entries = fs32.readdirSync(dir, { withFileTypes: true });
|
|
18835
19550
|
} catch {
|
|
18836
19551
|
return;
|
|
18837
19552
|
}
|
|
@@ -18840,16 +19555,16 @@ var FileWatcherService = class {
|
|
|
18840
19555
|
);
|
|
18841
19556
|
if (gitignoreEntry) {
|
|
18842
19557
|
try {
|
|
18843
|
-
const body =
|
|
18844
|
-
const rel =
|
|
19558
|
+
const body = fs32.readFileSync(path39.join(dir, ".gitignore"), "utf8");
|
|
19559
|
+
const rel = path39.relative(repoRoot, dir).replace(/\\/g, "/");
|
|
18845
19560
|
const prefixed = body.split(/\r?\n/).map((line) => {
|
|
18846
19561
|
const trimmed = line.trim();
|
|
18847
19562
|
if (!trimmed || trimmed.startsWith("#")) return line;
|
|
18848
19563
|
if (!rel) return line;
|
|
18849
19564
|
if (trimmed.startsWith("!")) {
|
|
18850
|
-
return "!" +
|
|
19565
|
+
return "!" + path39.posix.join(rel, trimmed.slice(1));
|
|
18851
19566
|
}
|
|
18852
|
-
return
|
|
19567
|
+
return path39.posix.join(rel, trimmed);
|
|
18853
19568
|
}).join("\n");
|
|
18854
19569
|
matcher.add(prefixed);
|
|
18855
19570
|
} catch {
|
|
@@ -18858,7 +19573,7 @@ var FileWatcherService = class {
|
|
|
18858
19573
|
for (const entry of entries) {
|
|
18859
19574
|
if (!entry.isDirectory()) continue;
|
|
18860
19575
|
if (entry.name === ".git") continue;
|
|
18861
|
-
const childAbs =
|
|
19576
|
+
const childAbs = path39.join(dir, entry.name);
|
|
18862
19577
|
if (isIgnoredFilePath(childAbs)) continue;
|
|
18863
19578
|
this.collectGitignoreFiles(repoRoot, childAbs, matcher);
|
|
18864
19579
|
}
|
|
@@ -18992,12 +19707,12 @@ var _gitSeam = {
|
|
|
18992
19707
|
run: _runGitImpl
|
|
18993
19708
|
};
|
|
18994
19709
|
async function _runGitImpl(cwd, args2, opts = {}) {
|
|
18995
|
-
return new Promise((
|
|
19710
|
+
return new Promise((resolve7) => {
|
|
18996
19711
|
let proc;
|
|
18997
19712
|
try {
|
|
18998
|
-
proc = (0,
|
|
19713
|
+
proc = (0, import_child_process16.spawn)("git", args2, { cwd, env: process.env });
|
|
18999
19714
|
} catch {
|
|
19000
|
-
|
|
19715
|
+
resolve7(null);
|
|
19001
19716
|
return;
|
|
19002
19717
|
}
|
|
19003
19718
|
let stdout = "";
|
|
@@ -19008,13 +19723,13 @@ async function _runGitImpl(cwd, args2, opts = {}) {
|
|
|
19008
19723
|
proc.stderr?.on("data", (c2) => {
|
|
19009
19724
|
stderr += c2.toString();
|
|
19010
19725
|
});
|
|
19011
|
-
proc.on("error", () =>
|
|
19726
|
+
proc.on("error", () => resolve7(null));
|
|
19012
19727
|
proc.on("close", (code) => {
|
|
19013
19728
|
if (code === 0 || opts.allowNonZeroExit) {
|
|
19014
|
-
|
|
19729
|
+
resolve7(stdout);
|
|
19015
19730
|
} else {
|
|
19016
19731
|
log.trace("fileWatcher", `git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`);
|
|
19017
|
-
|
|
19732
|
+
resolve7(null);
|
|
19018
19733
|
}
|
|
19019
19734
|
});
|
|
19020
19735
|
});
|
|
@@ -19027,8 +19742,8 @@ function _runGit(cwd, args2, opts = {}) {
|
|
|
19027
19742
|
var import_crypto4 = require("crypto");
|
|
19028
19743
|
|
|
19029
19744
|
// src/services/turn-files/git-changeset.ts
|
|
19030
|
-
var
|
|
19031
|
-
var
|
|
19745
|
+
var import_child_process17 = require("child_process");
|
|
19746
|
+
var path40 = __toESM(require("path"));
|
|
19032
19747
|
async function collectRepoChangeset(opts) {
|
|
19033
19748
|
const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
|
|
19034
19749
|
if (status2 === null) return null;
|
|
@@ -19108,12 +19823,12 @@ function runGit3(cwd, args2) {
|
|
|
19108
19823
|
return _runGitImpl2.run(cwd, args2);
|
|
19109
19824
|
}
|
|
19110
19825
|
function defaultRunGit(cwd, args2) {
|
|
19111
|
-
return new Promise((
|
|
19826
|
+
return new Promise((resolve7) => {
|
|
19112
19827
|
let proc;
|
|
19113
19828
|
try {
|
|
19114
|
-
proc = (0,
|
|
19829
|
+
proc = (0, import_child_process17.spawn)("git", args2, { cwd, env: process.env });
|
|
19115
19830
|
} catch {
|
|
19116
|
-
|
|
19831
|
+
resolve7(null);
|
|
19117
19832
|
return;
|
|
19118
19833
|
}
|
|
19119
19834
|
let stdout = "";
|
|
@@ -19124,22 +19839,22 @@ function defaultRunGit(cwd, args2) {
|
|
|
19124
19839
|
proc.stderr?.on("data", (c2) => {
|
|
19125
19840
|
stderr += c2.toString();
|
|
19126
19841
|
});
|
|
19127
|
-
proc.on("error", () =>
|
|
19842
|
+
proc.on("error", () => resolve7(null));
|
|
19128
19843
|
proc.on("close", (code) => {
|
|
19129
19844
|
if (code === 0) {
|
|
19130
|
-
|
|
19845
|
+
resolve7(stdout);
|
|
19131
19846
|
} else {
|
|
19132
19847
|
log.trace(
|
|
19133
19848
|
"turnFiles",
|
|
19134
19849
|
`git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`
|
|
19135
19850
|
);
|
|
19136
|
-
|
|
19851
|
+
resolve7(null);
|
|
19137
19852
|
}
|
|
19138
19853
|
});
|
|
19139
19854
|
});
|
|
19140
19855
|
}
|
|
19141
19856
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
19142
|
-
const
|
|
19857
|
+
const fs38 = await import("fs/promises");
|
|
19143
19858
|
const out2 = [];
|
|
19144
19859
|
await walk(workingDir, 0);
|
|
19145
19860
|
return out2;
|
|
@@ -19147,7 +19862,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
19147
19862
|
if (depth > maxDepth) return;
|
|
19148
19863
|
let entries = [];
|
|
19149
19864
|
try {
|
|
19150
|
-
const dirents = await
|
|
19865
|
+
const dirents = await fs38.readdir(dir, { withFileTypes: true });
|
|
19151
19866
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
19152
19867
|
} catch {
|
|
19153
19868
|
return;
|
|
@@ -19158,8 +19873,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
19158
19873
|
if (hasGit) {
|
|
19159
19874
|
out2.push({
|
|
19160
19875
|
repoRoot: dir,
|
|
19161
|
-
repoPath:
|
|
19162
|
-
repoName:
|
|
19876
|
+
repoPath: path40.relative(workingDir, dir),
|
|
19877
|
+
repoName: path40.basename(dir)
|
|
19163
19878
|
});
|
|
19164
19879
|
return;
|
|
19165
19880
|
}
|
|
@@ -19167,14 +19882,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
19167
19882
|
if (!entry.isDirectory) continue;
|
|
19168
19883
|
if (entry.name === "node_modules") continue;
|
|
19169
19884
|
if (entry.name === "dist" || entry.name === "build") continue;
|
|
19170
|
-
await walk(
|
|
19885
|
+
await walk(path40.join(dir, entry.name), depth + 1);
|
|
19171
19886
|
}
|
|
19172
19887
|
}
|
|
19173
19888
|
}
|
|
19174
19889
|
|
|
19175
19890
|
// src/services/turn-files/files-outbox.ts
|
|
19176
|
-
var
|
|
19177
|
-
var
|
|
19891
|
+
var fs33 = __toESM(require("fs/promises"));
|
|
19892
|
+
var path41 = __toESM(require("path"));
|
|
19178
19893
|
var import_os7 = require("os");
|
|
19179
19894
|
var HOME_OUTBOX_DIR = ".codeam/outbox";
|
|
19180
19895
|
var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -19207,16 +19922,16 @@ var FilesOutbox = class {
|
|
|
19207
19922
|
backoffIndex = 0;
|
|
19208
19923
|
stopped = false;
|
|
19209
19924
|
constructor(opts) {
|
|
19210
|
-
const base = opts.baseDir ??
|
|
19211
|
-
this.filePath =
|
|
19925
|
+
const base = opts.baseDir ?? path41.join(homeDir(), HOME_OUTBOX_DIR);
|
|
19926
|
+
this.filePath = path41.join(base, `${opts.sessionId}.jsonl`);
|
|
19212
19927
|
this.post = opts.post;
|
|
19213
19928
|
this.autoSchedule = opts.autoSchedule !== false;
|
|
19214
19929
|
}
|
|
19215
19930
|
/** Persist the entry to disk and trigger a flush. Returns once the
|
|
19216
19931
|
* line is durable on disk (not once the POST succeeds). */
|
|
19217
19932
|
async enqueue(entry) {
|
|
19218
|
-
await
|
|
19219
|
-
await
|
|
19933
|
+
await fs33.mkdir(path41.dirname(this.filePath), { recursive: true });
|
|
19934
|
+
await fs33.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
|
|
19220
19935
|
this.backoffIndex = 0;
|
|
19221
19936
|
if (this.autoSchedule) this.scheduleFlush(0);
|
|
19222
19937
|
}
|
|
@@ -19305,7 +20020,7 @@ var FilesOutbox = class {
|
|
|
19305
20020
|
async readAll() {
|
|
19306
20021
|
let raw = "";
|
|
19307
20022
|
try {
|
|
19308
|
-
raw = await
|
|
20023
|
+
raw = await fs33.readFile(this.filePath, "utf8");
|
|
19309
20024
|
} catch {
|
|
19310
20025
|
return [];
|
|
19311
20026
|
}
|
|
@@ -19329,12 +20044,12 @@ var FilesOutbox = class {
|
|
|
19329
20044
|
async rewrite(entries) {
|
|
19330
20045
|
const tmpPath = `${this.filePath}.${process.pid}.tmp`;
|
|
19331
20046
|
if (entries.length === 0) {
|
|
19332
|
-
await
|
|
20047
|
+
await fs33.unlink(this.filePath).catch(() => void 0);
|
|
19333
20048
|
return;
|
|
19334
20049
|
}
|
|
19335
20050
|
const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
19336
|
-
await
|
|
19337
|
-
await
|
|
20051
|
+
await fs33.writeFile(tmpPath, payload, "utf8");
|
|
20052
|
+
await fs33.rename(tmpPath, this.filePath);
|
|
19338
20053
|
}
|
|
19339
20054
|
};
|
|
19340
20055
|
function applyJitter(ms) {
|
|
@@ -19346,13 +20061,13 @@ function homeDir() {
|
|
|
19346
20061
|
}
|
|
19347
20062
|
|
|
19348
20063
|
// src/services/turn-files/turn-file-aggregator.ts
|
|
19349
|
-
var
|
|
20064
|
+
var API_BASE6 = resolveApiBaseUrl();
|
|
19350
20065
|
var ENDPOINT = "/api/files/batch";
|
|
19351
20066
|
var MAX_BATCH_SIZE = 1e3;
|
|
19352
20067
|
var TurnFileAggregator = class {
|
|
19353
20068
|
constructor(opts) {
|
|
19354
20069
|
this.opts = opts;
|
|
19355
|
-
this.apiBase = opts.apiBaseUrl ??
|
|
20070
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE6;
|
|
19356
20071
|
this.outbox = new FilesOutbox({
|
|
19357
20072
|
sessionId: opts.sessionId,
|
|
19358
20073
|
baseDir: opts.outboxDir,
|
|
@@ -19544,7 +20259,7 @@ var StreamingState = class {
|
|
|
19544
20259
|
* default-reject. Caller is the SDK's `onRequestPermission`.
|
|
19545
20260
|
*/
|
|
19546
20261
|
registerPermission(args2) {
|
|
19547
|
-
return new Promise((
|
|
20262
|
+
return new Promise((resolve7) => {
|
|
19548
20263
|
const timeoutTimer = setTimeout(() => {
|
|
19549
20264
|
if (this.pending?.kind === "permission" && this.pending.questionId === args2.questionId) {
|
|
19550
20265
|
log.warn(
|
|
@@ -19552,7 +20267,7 @@ var StreamingState = class {
|
|
|
19552
20267
|
`permission ${args2.questionId.slice(0, 8)} TTL expired \u2014 auto-cancel`
|
|
19553
20268
|
);
|
|
19554
20269
|
this.pending = null;
|
|
19555
|
-
|
|
20270
|
+
resolve7({ outcome: { outcome: "cancelled" } });
|
|
19556
20271
|
}
|
|
19557
20272
|
}, PERMISSION_TIMEOUT_MS);
|
|
19558
20273
|
this.pending = {
|
|
@@ -19560,7 +20275,7 @@ var StreamingState = class {
|
|
|
19560
20275
|
questionId: args2.questionId,
|
|
19561
20276
|
labels: args2.labels,
|
|
19562
20277
|
optionIdByLabel: args2.optionIdByLabel,
|
|
19563
|
-
resolve:
|
|
20278
|
+
resolve: resolve7,
|
|
19564
20279
|
timeoutTimer
|
|
19565
20280
|
};
|
|
19566
20281
|
});
|
|
@@ -19592,14 +20307,14 @@ var StreamingState = class {
|
|
|
19592
20307
|
const label = this.pending.labels[index];
|
|
19593
20308
|
const optionId = label ? this.pending.optionIdByLabel[label] : void 0;
|
|
19594
20309
|
clearTimeout(this.pending.timeoutTimer);
|
|
19595
|
-
const
|
|
20310
|
+
const resolve7 = this.pending.resolve;
|
|
19596
20311
|
this.pending = null;
|
|
19597
20312
|
if (!optionId) {
|
|
19598
20313
|
log.warn("acpRunner", `select_option index=${index} out of bounds \u2014 cancel`);
|
|
19599
|
-
|
|
20314
|
+
resolve7({ outcome: { outcome: "cancelled" } });
|
|
19600
20315
|
return { kind: "resolved" };
|
|
19601
20316
|
}
|
|
19602
|
-
|
|
20317
|
+
resolve7({ outcome: { outcome: "selected", optionId } });
|
|
19603
20318
|
return { kind: "resolved" };
|
|
19604
20319
|
}
|
|
19605
20320
|
const text = this.pending.options[index];
|
|
@@ -19955,6 +20670,16 @@ async function runAcpSession(opts) {
|
|
|
19955
20670
|
}).catch((err) => {
|
|
19956
20671
|
log.warn("acpRunner", `fileWatcher.start failed: ${describeError(err)}`);
|
|
19957
20672
|
});
|
|
20673
|
+
let beads = null;
|
|
20674
|
+
void startBeadsForSession({
|
|
20675
|
+
sessionId: opts.sessionId,
|
|
20676
|
+
pluginId: opts.pluginId,
|
|
20677
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
20678
|
+
agents: [opts.agent],
|
|
20679
|
+
cwd: opts.cwd
|
|
20680
|
+
}).then((started) => {
|
|
20681
|
+
beads = started;
|
|
20682
|
+
});
|
|
19958
20683
|
const relay = new CommandRelayService(
|
|
19959
20684
|
opts.pluginId,
|
|
19960
20685
|
async (cmd) => {
|
|
@@ -19968,7 +20693,8 @@ async function runAcpSession(opts) {
|
|
|
19968
20693
|
opts,
|
|
19969
20694
|
history,
|
|
19970
20695
|
initialize.agentCapabilities,
|
|
19971
|
-
turnFiles
|
|
20696
|
+
turnFiles,
|
|
20697
|
+
() => beads
|
|
19972
20698
|
);
|
|
19973
20699
|
},
|
|
19974
20700
|
{ id: opts.agent, name: opts.agent, displayName: opts.agent }
|
|
@@ -19979,6 +20705,7 @@ async function runAcpSession(opts) {
|
|
|
19979
20705
|
relay.stop();
|
|
19980
20706
|
void fileWatcher.stop();
|
|
19981
20707
|
turnFiles.stop();
|
|
20708
|
+
void beads?.watcher.stop();
|
|
19982
20709
|
closeAllTerminals();
|
|
19983
20710
|
await client2.stop();
|
|
19984
20711
|
process.exit(0);
|
|
@@ -19989,8 +20716,24 @@ async function runAcpSession(opts) {
|
|
|
19989
20716
|
await new Promise(() => {
|
|
19990
20717
|
});
|
|
19991
20718
|
}
|
|
19992
|
-
async function handleCommand(cmd, client2, relay, acpSessionId, models, streaming, opts, history, agentCaps, turnFiles) {
|
|
20719
|
+
async function handleCommand(cmd, client2, relay, acpSessionId, models, streaming, opts, history, agentCaps, turnFiles, getBeads) {
|
|
19993
20720
|
switch (cmd.type) {
|
|
20721
|
+
case "beads_action": {
|
|
20722
|
+
const beads = getBeads();
|
|
20723
|
+
const action = beadsActionFromPayload(cmd.payload);
|
|
20724
|
+
if (!beads || !action) {
|
|
20725
|
+
await relay.sendResult(cmd.id, "completed", { applied: false });
|
|
20726
|
+
return;
|
|
20727
|
+
}
|
|
20728
|
+
try {
|
|
20729
|
+
await handleBeadsActionCommand(action, beads);
|
|
20730
|
+
await relay.sendResult(cmd.id, "completed", { applied: true });
|
|
20731
|
+
} catch (err) {
|
|
20732
|
+
log.warn("acpRunner", `beads_action failed (non-fatal): ${describeError(err)}`);
|
|
20733
|
+
await relay.sendResult(cmd.id, "failed", { error: describeError(err) });
|
|
20734
|
+
}
|
|
20735
|
+
return;
|
|
20736
|
+
}
|
|
19994
20737
|
case "start_task": {
|
|
19995
20738
|
const payload = cmd.payload;
|
|
19996
20739
|
const blocks = buildAcpPromptBlocks(payload ?? {});
|
|
@@ -20349,11 +21092,11 @@ var ChromeStepTracker = class {
|
|
|
20349
21092
|
// src/services/output/chunk-emitter.ts
|
|
20350
21093
|
var https6 = __toESM(require("https"));
|
|
20351
21094
|
var http6 = __toESM(require("http"));
|
|
20352
|
-
var
|
|
21095
|
+
var API_BASE7 = resolveApiBaseUrl();
|
|
20353
21096
|
async function refreshAuthToken(sessionId, pluginId) {
|
|
20354
21097
|
try {
|
|
20355
21098
|
const { statusCode, body } = await _transport4.post(
|
|
20356
|
-
`${
|
|
21099
|
+
`${API_BASE7}/api/pairing/reconnect`,
|
|
20357
21100
|
{
|
|
20358
21101
|
"Content-Type": "application/json",
|
|
20359
21102
|
"X-Codeam-Protocol-Version": PROTOCOL_VERSION,
|
|
@@ -20394,7 +21137,7 @@ var ChunkEmitter = class {
|
|
|
20394
21137
|
}
|
|
20395
21138
|
}
|
|
20396
21139
|
opts;
|
|
20397
|
-
url = `${
|
|
21140
|
+
url = `${API_BASE7}/api/commands/output`;
|
|
20398
21141
|
headers;
|
|
20399
21142
|
/**
|
|
20400
21143
|
* Send a chunk. `body` is the chunk fields minus `sessionId` /
|
|
@@ -20415,14 +21158,14 @@ var ChunkEmitter = class {
|
|
|
20415
21158
|
"chunkEmitter",
|
|
20416
21159
|
`send type=${body.type ?? "(clear)"} bytes=${payload.length} done=${body.done === true}`
|
|
20417
21160
|
);
|
|
20418
|
-
return new Promise((
|
|
21161
|
+
return new Promise((resolve7) => {
|
|
20419
21162
|
const attempt = (attemptsLeft) => {
|
|
20420
21163
|
_transport4.post(this.url, this.headers, payload).then(({ statusCode, body: resBody }) => {
|
|
20421
21164
|
const tookMs = Date.now() - t0;
|
|
20422
21165
|
if (statusCode === 410 || statusCode === 404 && /SESSION_NOT_FOUND|SESSION_GONE/.test(resBody)) {
|
|
20423
21166
|
process.stderr.write("[codeam] session was deleted/disconnected \u2014 stopping output stream.\n");
|
|
20424
21167
|
log.info("chunkEmitter", `dead status=${statusCode} took=${tookMs}ms`);
|
|
20425
|
-
|
|
21168
|
+
resolve7({ dead: true });
|
|
20426
21169
|
return;
|
|
20427
21170
|
}
|
|
20428
21171
|
if (statusCode === 401) {
|
|
@@ -20438,7 +21181,7 @@ var ChunkEmitter = class {
|
|
|
20438
21181
|
return;
|
|
20439
21182
|
}
|
|
20440
21183
|
}
|
|
20441
|
-
|
|
21184
|
+
resolve7({ dead: false });
|
|
20442
21185
|
})();
|
|
20443
21186
|
return;
|
|
20444
21187
|
}
|
|
@@ -20449,7 +21192,7 @@ var ChunkEmitter = class {
|
|
|
20449
21192
|
} else {
|
|
20450
21193
|
log.info("chunkEmitter", `ok status=${statusCode} took=${tookMs}ms`);
|
|
20451
21194
|
}
|
|
20452
|
-
|
|
21195
|
+
resolve7({ dead: false });
|
|
20453
21196
|
}).catch((err) => {
|
|
20454
21197
|
log.warn(
|
|
20455
21198
|
"chunkEmitter",
|
|
@@ -20460,7 +21203,7 @@ var ChunkEmitter = class {
|
|
|
20460
21203
|
const delay = 200 * (maxRetries - attemptsLeft + 1);
|
|
20461
21204
|
setTimeout(() => attempt(attemptsLeft - 1), delay);
|
|
20462
21205
|
} else {
|
|
20463
|
-
|
|
21206
|
+
resolve7({ dead: false });
|
|
20464
21207
|
}
|
|
20465
21208
|
});
|
|
20466
21209
|
};
|
|
@@ -20472,7 +21215,7 @@ var _transport4 = {
|
|
|
20472
21215
|
post: _post3
|
|
20473
21216
|
};
|
|
20474
21217
|
function _post3(url, headers, payload) {
|
|
20475
|
-
return new Promise((
|
|
21218
|
+
return new Promise((resolve7, reject) => {
|
|
20476
21219
|
let settled = false;
|
|
20477
21220
|
const u2 = new URL(url);
|
|
20478
21221
|
const transport = u2.protocol === "https:" ? https6 : http6;
|
|
@@ -20496,7 +21239,7 @@ function _post3(url, headers, payload) {
|
|
|
20496
21239
|
res.on("end", () => {
|
|
20497
21240
|
if (settled) return;
|
|
20498
21241
|
settled = true;
|
|
20499
|
-
|
|
21242
|
+
resolve7({ statusCode: res.statusCode ?? 0, body: resData });
|
|
20500
21243
|
});
|
|
20501
21244
|
}
|
|
20502
21245
|
);
|
|
@@ -21070,9 +21813,9 @@ var OutputService = class _OutputService {
|
|
|
21070
21813
|
};
|
|
21071
21814
|
|
|
21072
21815
|
// src/services/history.service.ts
|
|
21073
|
-
var
|
|
21074
|
-
var
|
|
21075
|
-
var
|
|
21816
|
+
var fs34 = __toESM(require("fs"));
|
|
21817
|
+
var path42 = __toESM(require("path"));
|
|
21818
|
+
var os27 = __toESM(require("os"));
|
|
21076
21819
|
var https7 = __toESM(require("https"));
|
|
21077
21820
|
var http7 = __toESM(require("http"));
|
|
21078
21821
|
var import_zod2 = require("zod");
|
|
@@ -21086,7 +21829,7 @@ var historyRecordSchema = import_zod2.z.object({
|
|
|
21086
21829
|
content: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.unknown())]).optional()
|
|
21087
21830
|
}).passthrough().optional()
|
|
21088
21831
|
}).passthrough();
|
|
21089
|
-
var
|
|
21832
|
+
var API_BASE8 = resolveApiBaseUrl();
|
|
21090
21833
|
function extractText3(content) {
|
|
21091
21834
|
if (typeof content === "string") return content;
|
|
21092
21835
|
if (Array.isArray(content)) {
|
|
@@ -21099,7 +21842,7 @@ function parseJsonl(filePath) {
|
|
|
21099
21842
|
const messages = [];
|
|
21100
21843
|
let raw;
|
|
21101
21844
|
try {
|
|
21102
|
-
raw =
|
|
21845
|
+
raw = fs34.readFileSync(filePath, "utf8");
|
|
21103
21846
|
} catch (err) {
|
|
21104
21847
|
if (err.code !== "ENOENT") {
|
|
21105
21848
|
log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
|
|
@@ -21136,9 +21879,9 @@ function parseJsonl(filePath) {
|
|
|
21136
21879
|
return messages;
|
|
21137
21880
|
}
|
|
21138
21881
|
function post(endpoint, body) {
|
|
21139
|
-
return new Promise((
|
|
21882
|
+
return new Promise((resolve7) => {
|
|
21140
21883
|
const payload = JSON.stringify(body);
|
|
21141
|
-
const u2 = new URL(`${
|
|
21884
|
+
const u2 = new URL(`${API_BASE8}${endpoint}`);
|
|
21142
21885
|
const transport = u2.protocol === "https:" ? https7 : http7;
|
|
21143
21886
|
const req = transport.request(
|
|
21144
21887
|
{
|
|
@@ -21157,17 +21900,17 @@ function post(endpoint, body) {
|
|
|
21157
21900
|
res.resume();
|
|
21158
21901
|
const ok = res.statusCode !== void 0 && res.statusCode >= 200 && res.statusCode < 300;
|
|
21159
21902
|
if (!ok) log.warn("history:post", `${endpoint} \u2192 HTTP ${res.statusCode}`);
|
|
21160
|
-
|
|
21903
|
+
resolve7(ok);
|
|
21161
21904
|
}
|
|
21162
21905
|
);
|
|
21163
21906
|
req.on("error", (err) => {
|
|
21164
21907
|
log.warn("history:post", `${endpoint} network error`, err);
|
|
21165
|
-
|
|
21908
|
+
resolve7(false);
|
|
21166
21909
|
});
|
|
21167
21910
|
req.on("timeout", () => {
|
|
21168
21911
|
log.warn("history:post", `${endpoint} timeout after 15s`);
|
|
21169
21912
|
req.destroy();
|
|
21170
|
-
|
|
21913
|
+
resolve7(false);
|
|
21171
21914
|
});
|
|
21172
21915
|
req.write(payload);
|
|
21173
21916
|
req.end();
|
|
@@ -21234,7 +21977,7 @@ var HistoryService = class _HistoryService {
|
|
|
21234
21977
|
return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
|
|
21235
21978
|
}
|
|
21236
21979
|
get projectDir() {
|
|
21237
|
-
return this.runtime.resolveHistoryDir(this.cwd) ??
|
|
21980
|
+
return this.runtime.resolveHistoryDir(this.cwd) ?? path42.join(os27.homedir(), ".claude", "projects", encodeCwd(this.cwd));
|
|
21238
21981
|
}
|
|
21239
21982
|
/** Set the current Claude conversation ID (extracted from /cost command or session start) */
|
|
21240
21983
|
setCurrentConversationId(id) {
|
|
@@ -21246,7 +21989,7 @@ var HistoryService = class _HistoryService {
|
|
|
21246
21989
|
/** Return the current message count in the active conversation. */
|
|
21247
21990
|
getCurrentMessageCount() {
|
|
21248
21991
|
if (!this.currentConversationId) return 0;
|
|
21249
|
-
const filePath =
|
|
21992
|
+
const filePath = path42.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
21250
21993
|
return parseJsonl(filePath).length;
|
|
21251
21994
|
}
|
|
21252
21995
|
/**
|
|
@@ -21257,7 +22000,7 @@ var HistoryService = class _HistoryService {
|
|
|
21257
22000
|
const deadline = Date.now() + timeoutMs;
|
|
21258
22001
|
while (Date.now() < deadline) {
|
|
21259
22002
|
if (!this.currentConversationId) return null;
|
|
21260
|
-
const filePath =
|
|
22003
|
+
const filePath = path42.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
21261
22004
|
const messages = parseJsonl(filePath);
|
|
21262
22005
|
if (messages.length > previousCount) {
|
|
21263
22006
|
for (let i = messages.length - 1; i >= previousCount; i--) {
|
|
@@ -21283,16 +22026,16 @@ var HistoryService = class _HistoryService {
|
|
|
21283
22026
|
const dir = this.projectDir;
|
|
21284
22027
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
21285
22028
|
try {
|
|
21286
|
-
const files =
|
|
22029
|
+
const files = fs34.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
21287
22030
|
try {
|
|
21288
|
-
const stat3 =
|
|
22031
|
+
const stat3 = fs34.statSync(path42.join(dir, e.name));
|
|
21289
22032
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
21290
22033
|
} catch {
|
|
21291
22034
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
21292
22035
|
}
|
|
21293
22036
|
}).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
|
|
21294
22037
|
if (files.length > 0) {
|
|
21295
|
-
this.currentConversationId =
|
|
22038
|
+
this.currentConversationId = path42.basename(files[0].name, ".jsonl");
|
|
21296
22039
|
}
|
|
21297
22040
|
} catch {
|
|
21298
22041
|
}
|
|
@@ -21326,13 +22069,13 @@ var HistoryService = class _HistoryService {
|
|
|
21326
22069
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
21327
22070
|
let entries;
|
|
21328
22071
|
try {
|
|
21329
|
-
entries =
|
|
22072
|
+
entries = fs34.readdirSync(dir, { withFileTypes: true });
|
|
21330
22073
|
} catch {
|
|
21331
22074
|
return null;
|
|
21332
22075
|
}
|
|
21333
22076
|
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
21334
22077
|
try {
|
|
21335
|
-
const stat3 =
|
|
22078
|
+
const stat3 = fs34.statSync(path42.join(dir, e.name));
|
|
21336
22079
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
21337
22080
|
} catch {
|
|
21338
22081
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
@@ -21341,12 +22084,12 @@ var HistoryService = class _HistoryService {
|
|
|
21341
22084
|
if (files.length === 0) return null;
|
|
21342
22085
|
const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
|
|
21343
22086
|
if (!files.some((f) => f.name === targetFile)) return null;
|
|
21344
|
-
return this.extractUsageFromFile(
|
|
22087
|
+
return this.extractUsageFromFile(path42.join(dir, targetFile));
|
|
21345
22088
|
}
|
|
21346
22089
|
extractUsageFromFile(filePath) {
|
|
21347
22090
|
let raw;
|
|
21348
22091
|
try {
|
|
21349
|
-
raw =
|
|
22092
|
+
raw = fs34.readFileSync(filePath, "utf8");
|
|
21350
22093
|
} catch {
|
|
21351
22094
|
return null;
|
|
21352
22095
|
}
|
|
@@ -21391,9 +22134,9 @@ var HistoryService = class _HistoryService {
|
|
|
21391
22134
|
let totalCost = 0;
|
|
21392
22135
|
let files;
|
|
21393
22136
|
try {
|
|
21394
|
-
files =
|
|
22137
|
+
files = fs34.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
21395
22138
|
try {
|
|
21396
|
-
return
|
|
22139
|
+
return fs34.statSync(path42.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
21397
22140
|
} catch {
|
|
21398
22141
|
return false;
|
|
21399
22142
|
}
|
|
@@ -21404,7 +22147,7 @@ var HistoryService = class _HistoryService {
|
|
|
21404
22147
|
for (const file of files) {
|
|
21405
22148
|
let raw;
|
|
21406
22149
|
try {
|
|
21407
|
-
raw =
|
|
22150
|
+
raw = fs34.readFileSync(path42.join(projectDir, file), "utf8");
|
|
21408
22151
|
} catch {
|
|
21409
22152
|
continue;
|
|
21410
22153
|
}
|
|
@@ -21468,7 +22211,7 @@ var HistoryService = class _HistoryService {
|
|
|
21468
22211
|
* showing an empty conversation.
|
|
21469
22212
|
*/
|
|
21470
22213
|
async loadConversation(sessionId) {
|
|
21471
|
-
const filePath =
|
|
22214
|
+
const filePath = path42.join(this.projectDir, `${sessionId}.jsonl`);
|
|
21472
22215
|
const messages = parseJsonl(filePath);
|
|
21473
22216
|
if (messages.length === 0) return;
|
|
21474
22217
|
const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
|
|
@@ -21522,7 +22265,7 @@ var HistoryService = class _HistoryService {
|
|
|
21522
22265
|
if (!this.currentConversationId) return 0;
|
|
21523
22266
|
}
|
|
21524
22267
|
const sessionId = this.currentConversationId;
|
|
21525
|
-
const filePath =
|
|
22268
|
+
const filePath = path42.join(this.projectDir, `${sessionId}.jsonl`);
|
|
21526
22269
|
const messages = parseJsonl(filePath);
|
|
21527
22270
|
if (messages.length === 0) return 0;
|
|
21528
22271
|
const marker = this.lastUploadedUuid.get(sessionId);
|
|
@@ -21587,7 +22330,7 @@ var RepoDirtyTracker = class {
|
|
|
21587
22330
|
|
|
21588
22331
|
// src/services/streaming-emitter.service.ts
|
|
21589
22332
|
var import_crypto5 = require("crypto");
|
|
21590
|
-
var
|
|
22333
|
+
var API_BASE9 = resolveApiBaseUrl();
|
|
21591
22334
|
var TICK_MS = 50;
|
|
21592
22335
|
var ANSWER_POLL_MS = 1500;
|
|
21593
22336
|
var SELECTOR_STABLE_MS = 800;
|
|
@@ -21598,7 +22341,7 @@ var TAIL_KEEP_BYTES2 = 1.5 * 1024 * 1024;
|
|
|
21598
22341
|
var StreamingEmitterService = class {
|
|
21599
22342
|
constructor(opts) {
|
|
21600
22343
|
this.opts = opts;
|
|
21601
|
-
this.apiBase = opts.apiBaseUrl ??
|
|
22344
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE9;
|
|
21602
22345
|
this.headers = {
|
|
21603
22346
|
"Content-Type": "application/json",
|
|
21604
22347
|
"X-Codeam-Protocol-Version": "2.0.0",
|
|
@@ -21948,13 +22691,13 @@ function fetchQuotaUsage(runtime, historySvc) {
|
|
|
21948
22691
|
}
|
|
21949
22692
|
|
|
21950
22693
|
// src/commands/start/keep-alive.ts
|
|
21951
|
-
var
|
|
22694
|
+
var import_child_process18 = require("child_process");
|
|
21952
22695
|
function buildKeepAlive(ctx) {
|
|
21953
22696
|
let timer = null;
|
|
21954
22697
|
async function setIdleTimeout(minutes) {
|
|
21955
22698
|
if (!ctx.inCodespace || !ctx.codespaceName) return;
|
|
21956
|
-
await new Promise((
|
|
21957
|
-
const proc = (0,
|
|
22699
|
+
await new Promise((resolve7) => {
|
|
22700
|
+
const proc = (0, import_child_process18.spawn)(
|
|
21958
22701
|
"gh",
|
|
21959
22702
|
[
|
|
21960
22703
|
"api",
|
|
@@ -21967,8 +22710,8 @@ function buildKeepAlive(ctx) {
|
|
|
21967
22710
|
{ stdio: "ignore", detached: true }
|
|
21968
22711
|
);
|
|
21969
22712
|
proc.unref();
|
|
21970
|
-
proc.on("exit", () =>
|
|
21971
|
-
proc.on("error", () =>
|
|
22713
|
+
proc.on("exit", () => resolve7());
|
|
22714
|
+
proc.on("error", () => resolve7());
|
|
21972
22715
|
});
|
|
21973
22716
|
}
|
|
21974
22717
|
return {
|
|
@@ -22116,6 +22859,7 @@ async function start(requestedAgent) {
|
|
|
22116
22859
|
dirtyTracker: dirtyTracker ?? void 0
|
|
22117
22860
|
}) : null;
|
|
22118
22861
|
let streamingEmitter = null;
|
|
22862
|
+
let beads = null;
|
|
22119
22863
|
const agent = new AgentService(
|
|
22120
22864
|
runtime,
|
|
22121
22865
|
{
|
|
@@ -22132,6 +22876,7 @@ async function start(requestedAgent) {
|
|
|
22132
22876
|
relay.stop();
|
|
22133
22877
|
void fileWatcher?.stop();
|
|
22134
22878
|
turnFiles?.stop();
|
|
22879
|
+
void beads?.watcher.stop();
|
|
22135
22880
|
void streamingEmitter?.stop();
|
|
22136
22881
|
closeAllTerminals();
|
|
22137
22882
|
cleanupAttachmentTempFiles();
|
|
@@ -22165,6 +22910,16 @@ async function start(requestedAgent) {
|
|
|
22165
22910
|
await dispatchCommand(ctx, cmd);
|
|
22166
22911
|
}, runtime.meta);
|
|
22167
22912
|
ctx.relay = relay;
|
|
22913
|
+
void startBeadsForSession({
|
|
22914
|
+
sessionId: session.id,
|
|
22915
|
+
pluginId,
|
|
22916
|
+
pluginAuthToken: session.pluginAuthToken ?? void 0,
|
|
22917
|
+
agents: [session.agent],
|
|
22918
|
+
cwd
|
|
22919
|
+
}).then((started) => {
|
|
22920
|
+
beads = started;
|
|
22921
|
+
ctx.beads = started;
|
|
22922
|
+
});
|
|
22168
22923
|
registerTerminalHandlers({
|
|
22169
22924
|
onData: ({ sessionId, data }) => {
|
|
22170
22925
|
void outputSvc.sendTerminalChunk(sessionId, data);
|
|
@@ -22181,6 +22936,7 @@ async function start(requestedAgent) {
|
|
|
22181
22936
|
outputSvc.dispose();
|
|
22182
22937
|
relay.stop();
|
|
22183
22938
|
void fileWatcher?.stop();
|
|
22939
|
+
void beads?.watcher.stop();
|
|
22184
22940
|
void streamingEmitter?.stop();
|
|
22185
22941
|
closeAllTerminals();
|
|
22186
22942
|
cleanupAttachmentTempFiles();
|
|
@@ -22319,7 +23075,7 @@ async function pair(args2 = []) {
|
|
|
22319
23075
|
waitSpin.message(waitMessage());
|
|
22320
23076
|
}, 1e3);
|
|
22321
23077
|
countdownInterval.unref?.();
|
|
22322
|
-
await new Promise((
|
|
23078
|
+
await new Promise((resolve7) => {
|
|
22323
23079
|
let stopPolling = null;
|
|
22324
23080
|
function sigintHandler() {
|
|
22325
23081
|
clearInterval(countdownInterval);
|
|
@@ -22367,7 +23123,7 @@ async function pair(args2 = []) {
|
|
|
22367
23123
|
pluginAuthToken: info.pluginAuthToken
|
|
22368
23124
|
});
|
|
22369
23125
|
}
|
|
22370
|
-
|
|
23126
|
+
resolve7();
|
|
22371
23127
|
},
|
|
22372
23128
|
() => {
|
|
22373
23129
|
clearInterval(countdownInterval);
|
|
@@ -22419,8 +23175,8 @@ async function autoLinkAfterPair(opts) {
|
|
|
22419
23175
|
}
|
|
22420
23176
|
|
|
22421
23177
|
// src/commands/pair-auto.ts
|
|
22422
|
-
var
|
|
22423
|
-
var
|
|
23178
|
+
var fs35 = __toESM(require("fs"));
|
|
23179
|
+
var os28 = __toESM(require("os"));
|
|
22424
23180
|
var import_crypto7 = require("crypto");
|
|
22425
23181
|
|
|
22426
23182
|
// src/commands/start-infra-only.ts
|
|
@@ -22573,7 +23329,7 @@ async function startInfraOnly(agentId) {
|
|
|
22573
23329
|
}
|
|
22574
23330
|
|
|
22575
23331
|
// src/commands/pair-auto.ts
|
|
22576
|
-
var
|
|
23332
|
+
var API_BASE10 = resolveApiBaseUrl();
|
|
22577
23333
|
function fail(msg) {
|
|
22578
23334
|
console.error(`
|
|
22579
23335
|
${msg}
|
|
@@ -22588,12 +23344,12 @@ function readTokenFromArgs(args2) {
|
|
|
22588
23344
|
}
|
|
22589
23345
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
22590
23346
|
if (fileFlag) {
|
|
22591
|
-
const
|
|
23347
|
+
const path49 = fileFlag.slice("--token-file=".length);
|
|
22592
23348
|
try {
|
|
22593
|
-
const content =
|
|
22594
|
-
if (content.length === 0) fail(`--token-file ${
|
|
23349
|
+
const content = fs35.readFileSync(path49, "utf8").trim();
|
|
23350
|
+
if (content.length === 0) fail(`--token-file ${path49} is empty`);
|
|
22595
23351
|
try {
|
|
22596
|
-
|
|
23352
|
+
fs35.unlinkSync(path49);
|
|
22597
23353
|
} catch {
|
|
22598
23354
|
}
|
|
22599
23355
|
return content;
|
|
@@ -22613,13 +23369,13 @@ function networkError(msg, cause) {
|
|
|
22613
23369
|
return err;
|
|
22614
23370
|
}
|
|
22615
23371
|
async function claimOnce(token, pluginId) {
|
|
22616
|
-
const url = `${
|
|
23372
|
+
const url = `${API_BASE10}/api/pairing/claim-auto-token`;
|
|
22617
23373
|
const body = {
|
|
22618
23374
|
token,
|
|
22619
23375
|
pluginId,
|
|
22620
23376
|
ideName: "codeam-cli (codespace)",
|
|
22621
23377
|
ideVersion: process.env.npm_package_version ?? "unknown",
|
|
22622
|
-
hostname:
|
|
23378
|
+
hostname: os28.hostname(),
|
|
22623
23379
|
codespaceName: process.env.CODESPACE_NAME ?? "",
|
|
22624
23380
|
// Current git branch of the codespace's working directory, so the
|
|
22625
23381
|
// backend can populate `PairedSession.branch` for the codespace pair.
|
|
@@ -22816,7 +23572,7 @@ function status() {
|
|
|
22816
23572
|
|
|
22817
23573
|
// src/commands/logout.ts
|
|
22818
23574
|
var import_picocolors7 = __toESM(require("picocolors"));
|
|
22819
|
-
var
|
|
23575
|
+
var API_BASE11 = resolveApiBaseUrl();
|
|
22820
23576
|
async function notifyBackendOffline() {
|
|
22821
23577
|
const cfg = loadCliConfig();
|
|
22822
23578
|
const pluginIds = /* @__PURE__ */ new Set([
|
|
@@ -22828,7 +23584,7 @@ async function notifyBackendOffline() {
|
|
|
22828
23584
|
try {
|
|
22829
23585
|
await Promise.all(
|
|
22830
23586
|
Array.from(pluginIds).map(
|
|
22831
|
-
(pluginId) => _postJson(`${
|
|
23587
|
+
(pluginId) => _postJson(`${API_BASE11}/api/plugin/heartbeat`, {
|
|
22832
23588
|
pluginId,
|
|
22833
23589
|
online: false
|
|
22834
23590
|
}).catch((err) => {
|
|
@@ -22856,11 +23612,11 @@ async function logout() {
|
|
|
22856
23612
|
var import_picocolors10 = __toESM(require("picocolors"));
|
|
22857
23613
|
|
|
22858
23614
|
// src/services/providers/github-codespaces.ts
|
|
22859
|
-
var
|
|
23615
|
+
var import_child_process19 = require("child_process");
|
|
22860
23616
|
var import_util4 = require("util");
|
|
22861
23617
|
var import_picocolors8 = __toESM(require("picocolors"));
|
|
22862
|
-
var
|
|
22863
|
-
var execFileP5 = (0, import_util4.promisify)(
|
|
23618
|
+
var path43 = __toESM(require("path"));
|
|
23619
|
+
var execFileP5 = (0, import_util4.promisify)(import_child_process19.execFile);
|
|
22864
23620
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
22865
23621
|
function resetStdinForChild() {
|
|
22866
23622
|
if (process.stdin.isTTY) {
|
|
@@ -22903,12 +23659,12 @@ var GitHubCodespacesProvider = class {
|
|
|
22903
23659
|
}
|
|
22904
23660
|
if (!isAuthed) {
|
|
22905
23661
|
resetStdinForChild();
|
|
22906
|
-
await new Promise((
|
|
22907
|
-
const proc = (0,
|
|
23662
|
+
await new Promise((resolve7, reject) => {
|
|
23663
|
+
const proc = (0, import_child_process19.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
|
|
22908
23664
|
stdio: "inherit"
|
|
22909
23665
|
});
|
|
22910
23666
|
proc.on("exit", (code) => {
|
|
22911
|
-
if (code === 0)
|
|
23667
|
+
if (code === 0) resolve7();
|
|
22912
23668
|
else reject(new Error("gh auth login failed."));
|
|
22913
23669
|
});
|
|
22914
23670
|
proc.on("error", reject);
|
|
@@ -22937,13 +23693,13 @@ var GitHubCodespacesProvider = class {
|
|
|
22937
23693
|
}
|
|
22938
23694
|
wt(noteLines.join("\n"), "One more permission needed");
|
|
22939
23695
|
resetStdinForChild();
|
|
22940
|
-
const refreshCode = await new Promise((
|
|
22941
|
-
const proc = (0,
|
|
23696
|
+
const refreshCode = await new Promise((resolve7, reject) => {
|
|
23697
|
+
const proc = (0, import_child_process19.spawn)(
|
|
22942
23698
|
"gh",
|
|
22943
23699
|
["auth", "refresh", "-h", "github.com", "-s", "codespace"],
|
|
22944
23700
|
{ stdio: "inherit" }
|
|
22945
23701
|
);
|
|
22946
|
-
proc.on("exit", (code) =>
|
|
23702
|
+
proc.on("exit", (code) => resolve7(code ?? 1));
|
|
22947
23703
|
proc.on("error", reject);
|
|
22948
23704
|
});
|
|
22949
23705
|
if (refreshCode !== 0) {
|
|
@@ -23087,10 +23843,10 @@ var GitHubCodespacesProvider = class {
|
|
|
23087
23843
|
if (q(proceed) || !proceed) return;
|
|
23088
23844
|
O2.step(`Installing gh via ${installCmd.describe}\u2026`);
|
|
23089
23845
|
resetStdinForChild();
|
|
23090
|
-
const ok = await new Promise((
|
|
23091
|
-
const proc = (0,
|
|
23092
|
-
proc.on("exit", (code) =>
|
|
23093
|
-
proc.on("error", () =>
|
|
23846
|
+
const ok = await new Promise((resolve7) => {
|
|
23847
|
+
const proc = (0, import_child_process19.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
|
|
23848
|
+
proc.on("exit", (code) => resolve7(code === 0));
|
|
23849
|
+
proc.on("error", () => resolve7(false));
|
|
23094
23850
|
});
|
|
23095
23851
|
if (ok) O2.success("gh installed");
|
|
23096
23852
|
else O2.error("gh install failed");
|
|
@@ -23114,14 +23870,14 @@ var GitHubCodespacesProvider = class {
|
|
|
23114
23870
|
"Expanding GitHub scopes"
|
|
23115
23871
|
);
|
|
23116
23872
|
resetStdinForChild();
|
|
23117
|
-
await new Promise((
|
|
23118
|
-
const proc = (0,
|
|
23873
|
+
await new Promise((resolve7, reject) => {
|
|
23874
|
+
const proc = (0, import_child_process19.spawn)(
|
|
23119
23875
|
"gh",
|
|
23120
23876
|
["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
|
|
23121
23877
|
{ stdio: "inherit" }
|
|
23122
23878
|
);
|
|
23123
23879
|
proc.on("exit", (code) => {
|
|
23124
|
-
if (code === 0)
|
|
23880
|
+
if (code === 0) resolve7();
|
|
23125
23881
|
else reject(new Error(
|
|
23126
23882
|
"gh auth refresh failed. Re-run `gh auth refresh -h github.com -s repo,read:org` manually."
|
|
23127
23883
|
));
|
|
@@ -23292,13 +24048,13 @@ var GitHubCodespacesProvider = class {
|
|
|
23292
24048
|
}
|
|
23293
24049
|
async streamCommand(workspaceId, command2) {
|
|
23294
24050
|
resetStdinForChild();
|
|
23295
|
-
return new Promise((
|
|
23296
|
-
const proc = (0,
|
|
24051
|
+
return new Promise((resolve7, reject) => {
|
|
24052
|
+
const proc = (0, import_child_process19.spawn)(
|
|
23297
24053
|
"gh",
|
|
23298
24054
|
["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
|
|
23299
24055
|
{ stdio: "inherit" }
|
|
23300
24056
|
);
|
|
23301
|
-
proc.on("exit", (code) =>
|
|
24057
|
+
proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
|
|
23302
24058
|
proc.on("error", reject);
|
|
23303
24059
|
});
|
|
23304
24060
|
}
|
|
@@ -23319,12 +24075,12 @@ var GitHubCodespacesProvider = class {
|
|
|
23319
24075
|
"--",
|
|
23320
24076
|
`mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
|
|
23321
24077
|
];
|
|
23322
|
-
await new Promise((
|
|
23323
|
-
const tar = (0,
|
|
24078
|
+
await new Promise((resolve7, reject) => {
|
|
24079
|
+
const tar = (0, import_child_process19.spawn)("tar", tarArgs, {
|
|
23324
24080
|
stdio: ["ignore", "pipe", "pipe"],
|
|
23325
24081
|
env: tarEnv
|
|
23326
24082
|
});
|
|
23327
|
-
const ssh = (0,
|
|
24083
|
+
const ssh = (0, import_child_process19.spawn)("gh", sshArgs, {
|
|
23328
24084
|
stdio: [tar.stdout, "pipe", "pipe"]
|
|
23329
24085
|
});
|
|
23330
24086
|
let tarErr = "";
|
|
@@ -23339,7 +24095,7 @@ var GitHubCodespacesProvider = class {
|
|
|
23339
24095
|
ssh.on("error", reject);
|
|
23340
24096
|
ssh.on("exit", (code) => {
|
|
23341
24097
|
if (code === 0) {
|
|
23342
|
-
|
|
24098
|
+
resolve7();
|
|
23343
24099
|
} else {
|
|
23344
24100
|
const reason = (sshErr || tarErr || `exit ${code}`).trim().slice(0, 500);
|
|
23345
24101
|
reject(new Error(`Remote tar failed: ${reason}`));
|
|
@@ -23348,7 +24104,7 @@ var GitHubCodespacesProvider = class {
|
|
|
23348
24104
|
});
|
|
23349
24105
|
}
|
|
23350
24106
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
23351
|
-
const remoteDir =
|
|
24107
|
+
const remoteDir = path43.posix.dirname(remotePath);
|
|
23352
24108
|
const parts = [
|
|
23353
24109
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
23354
24110
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -23357,8 +24113,8 @@ var GitHubCodespacesProvider = class {
|
|
|
23357
24113
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote(remotePath)}`);
|
|
23358
24114
|
}
|
|
23359
24115
|
const cmd = parts.join(" && ");
|
|
23360
|
-
await new Promise((
|
|
23361
|
-
const proc = (0,
|
|
24116
|
+
await new Promise((resolve7, reject) => {
|
|
24117
|
+
const proc = (0, import_child_process19.spawn)(
|
|
23362
24118
|
"gh",
|
|
23363
24119
|
["codespace", "ssh", "-c", workspaceId, "--", cmd],
|
|
23364
24120
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -23369,7 +24125,7 @@ var GitHubCodespacesProvider = class {
|
|
|
23369
24125
|
});
|
|
23370
24126
|
proc.on("error", reject);
|
|
23371
24127
|
proc.on("exit", (code) => {
|
|
23372
|
-
if (code === 0)
|
|
24128
|
+
if (code === 0) resolve7();
|
|
23373
24129
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
23374
24130
|
});
|
|
23375
24131
|
proc.stdin?.write(contents);
|
|
@@ -23416,11 +24172,11 @@ function shellQuote(s) {
|
|
|
23416
24172
|
}
|
|
23417
24173
|
|
|
23418
24174
|
// src/services/providers/gitpod.ts
|
|
23419
|
-
var
|
|
24175
|
+
var import_child_process20 = require("child_process");
|
|
23420
24176
|
var import_util5 = require("util");
|
|
23421
|
-
var
|
|
24177
|
+
var path44 = __toESM(require("path"));
|
|
23422
24178
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
23423
|
-
var execFileP6 = (0, import_util5.promisify)(
|
|
24179
|
+
var execFileP6 = (0, import_util5.promisify)(import_child_process20.execFile);
|
|
23424
24180
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
23425
24181
|
function resetStdinForChild2() {
|
|
23426
24182
|
if (process.stdin.isTTY) {
|
|
@@ -23459,10 +24215,10 @@ var GitpodProvider = class {
|
|
|
23459
24215
|
"Authenticating Gitpod"
|
|
23460
24216
|
);
|
|
23461
24217
|
resetStdinForChild2();
|
|
23462
|
-
await new Promise((
|
|
23463
|
-
const proc = (0,
|
|
24218
|
+
await new Promise((resolve7, reject) => {
|
|
24219
|
+
const proc = (0, import_child_process20.spawn)("gitpod", ["login"], { stdio: "inherit" });
|
|
23464
24220
|
proc.on("exit", (code) => {
|
|
23465
|
-
if (code === 0)
|
|
24221
|
+
if (code === 0) resolve7();
|
|
23466
24222
|
else reject(new Error("gitpod login failed."));
|
|
23467
24223
|
});
|
|
23468
24224
|
proc.on("error", reject);
|
|
@@ -23611,13 +24367,13 @@ var GitpodProvider = class {
|
|
|
23611
24367
|
}
|
|
23612
24368
|
async streamCommand(workspaceId, command2) {
|
|
23613
24369
|
resetStdinForChild2();
|
|
23614
|
-
return new Promise((
|
|
23615
|
-
const proc = (0,
|
|
24370
|
+
return new Promise((resolve7, reject) => {
|
|
24371
|
+
const proc = (0, import_child_process20.spawn)(
|
|
23616
24372
|
"gitpod",
|
|
23617
24373
|
["workspace", "ssh", workspaceId, "--", "-tt", command2],
|
|
23618
24374
|
{ stdio: "inherit" }
|
|
23619
24375
|
);
|
|
23620
|
-
proc.on("exit", (code) =>
|
|
24376
|
+
proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
|
|
23621
24377
|
proc.on("error", reject);
|
|
23622
24378
|
});
|
|
23623
24379
|
}
|
|
@@ -23631,12 +24387,12 @@ var GitpodProvider = class {
|
|
|
23631
24387
|
tarArgs.push(".");
|
|
23632
24388
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
23633
24389
|
const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
|
|
23634
|
-
await new Promise((
|
|
23635
|
-
const tar = (0,
|
|
24390
|
+
await new Promise((resolve7, reject) => {
|
|
24391
|
+
const tar = (0, import_child_process20.spawn)("tar", tarArgs, {
|
|
23636
24392
|
stdio: ["ignore", "pipe", "pipe"],
|
|
23637
24393
|
env: tarEnv
|
|
23638
24394
|
});
|
|
23639
|
-
const ssh = (0,
|
|
24395
|
+
const ssh = (0, import_child_process20.spawn)(
|
|
23640
24396
|
"gitpod",
|
|
23641
24397
|
["workspace", "ssh", workspaceId, "--", remoteCmd],
|
|
23642
24398
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -23652,13 +24408,13 @@ var GitpodProvider = class {
|
|
|
23652
24408
|
tar.on("error", reject);
|
|
23653
24409
|
ssh.on("error", reject);
|
|
23654
24410
|
ssh.on("exit", (code) => {
|
|
23655
|
-
if (code === 0)
|
|
24411
|
+
if (code === 0) resolve7();
|
|
23656
24412
|
else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
23657
24413
|
});
|
|
23658
24414
|
});
|
|
23659
24415
|
}
|
|
23660
24416
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
23661
|
-
const remoteDir =
|
|
24417
|
+
const remoteDir = path44.posix.dirname(remotePath);
|
|
23662
24418
|
const parts = [
|
|
23663
24419
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
23664
24420
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -23667,8 +24423,8 @@ var GitpodProvider = class {
|
|
|
23667
24423
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote2(remotePath)}`);
|
|
23668
24424
|
}
|
|
23669
24425
|
const cmd = parts.join(" && ");
|
|
23670
|
-
await new Promise((
|
|
23671
|
-
const proc = (0,
|
|
24426
|
+
await new Promise((resolve7, reject) => {
|
|
24427
|
+
const proc = (0, import_child_process20.spawn)(
|
|
23672
24428
|
"gitpod",
|
|
23673
24429
|
["workspace", "ssh", workspaceId, "--", cmd],
|
|
23674
24430
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -23679,7 +24435,7 @@ var GitpodProvider = class {
|
|
|
23679
24435
|
});
|
|
23680
24436
|
proc.on("error", reject);
|
|
23681
24437
|
proc.on("exit", (code) => {
|
|
23682
|
-
if (code === 0)
|
|
24438
|
+
if (code === 0) resolve7();
|
|
23683
24439
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
23684
24440
|
});
|
|
23685
24441
|
proc.stdin?.write(contents);
|
|
@@ -23692,10 +24448,10 @@ function shellQuote2(s) {
|
|
|
23692
24448
|
}
|
|
23693
24449
|
|
|
23694
24450
|
// src/services/providers/gitlab-workspaces.ts
|
|
23695
|
-
var
|
|
24451
|
+
var import_child_process21 = require("child_process");
|
|
23696
24452
|
var import_util6 = require("util");
|
|
23697
|
-
var
|
|
23698
|
-
var execFileP7 = (0, import_util6.promisify)(
|
|
24453
|
+
var path45 = __toESM(require("path"));
|
|
24454
|
+
var execFileP7 = (0, import_util6.promisify)(import_child_process21.execFile);
|
|
23699
24455
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
23700
24456
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
23701
24457
|
function resetStdinForChild3() {
|
|
@@ -23736,14 +24492,14 @@ var GitLabWorkspacesProvider = class {
|
|
|
23736
24492
|
"Authenticating GitLab"
|
|
23737
24493
|
);
|
|
23738
24494
|
resetStdinForChild3();
|
|
23739
|
-
await new Promise((
|
|
23740
|
-
const proc = (0,
|
|
24495
|
+
await new Promise((resolve7, reject) => {
|
|
24496
|
+
const proc = (0, import_child_process21.spawn)(
|
|
23741
24497
|
"glab",
|
|
23742
24498
|
["auth", "login", "--scopes", "api,read_user,read_repository"],
|
|
23743
24499
|
{ stdio: "inherit" }
|
|
23744
24500
|
);
|
|
23745
24501
|
proc.on("exit", (code) => {
|
|
23746
|
-
if (code === 0)
|
|
24502
|
+
if (code === 0) resolve7();
|
|
23747
24503
|
else reject(new Error("glab auth login failed."));
|
|
23748
24504
|
});
|
|
23749
24505
|
proc.on("error", reject);
|
|
@@ -23908,13 +24664,13 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
23908
24664
|
async streamCommand(workspaceId, command2) {
|
|
23909
24665
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
23910
24666
|
resetStdinForChild3();
|
|
23911
|
-
return new Promise((
|
|
23912
|
-
const proc = (0,
|
|
24667
|
+
return new Promise((resolve7, reject) => {
|
|
24668
|
+
const proc = (0, import_child_process21.spawn)(
|
|
23913
24669
|
"ssh",
|
|
23914
24670
|
["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
|
|
23915
24671
|
{ stdio: "inherit" }
|
|
23916
24672
|
);
|
|
23917
|
-
proc.on("exit", (code) =>
|
|
24673
|
+
proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
|
|
23918
24674
|
proc.on("error", reject);
|
|
23919
24675
|
});
|
|
23920
24676
|
}
|
|
@@ -23929,9 +24685,9 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
23929
24685
|
tarArgs.push(".");
|
|
23930
24686
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
23931
24687
|
const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
|
|
23932
|
-
await new Promise((
|
|
23933
|
-
const tar = (0,
|
|
23934
|
-
const ssh = (0,
|
|
24688
|
+
await new Promise((resolve7, reject) => {
|
|
24689
|
+
const tar = (0, import_child_process21.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
24690
|
+
const ssh = (0, import_child_process21.spawn)(
|
|
23935
24691
|
"ssh",
|
|
23936
24692
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, remoteCmd],
|
|
23937
24693
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -23947,21 +24703,21 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
23947
24703
|
tar.on("error", reject);
|
|
23948
24704
|
ssh.on("error", reject);
|
|
23949
24705
|
ssh.on("exit", (code) => {
|
|
23950
|
-
if (code === 0)
|
|
24706
|
+
if (code === 0) resolve7();
|
|
23951
24707
|
else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
23952
24708
|
});
|
|
23953
24709
|
});
|
|
23954
24710
|
}
|
|
23955
24711
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
23956
24712
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
23957
|
-
const remoteDir =
|
|
24713
|
+
const remoteDir = path45.posix.dirname(remotePath);
|
|
23958
24714
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
23959
24715
|
if (options.mode != null) {
|
|
23960
24716
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
23961
24717
|
}
|
|
23962
24718
|
const cmd = parts.join(" && ");
|
|
23963
|
-
await new Promise((
|
|
23964
|
-
const proc = (0,
|
|
24719
|
+
await new Promise((resolve7, reject) => {
|
|
24720
|
+
const proc = (0, import_child_process21.spawn)(
|
|
23965
24721
|
"ssh",
|
|
23966
24722
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
|
|
23967
24723
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -23972,7 +24728,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
23972
24728
|
});
|
|
23973
24729
|
proc.on("error", reject);
|
|
23974
24730
|
proc.on("exit", (code) => {
|
|
23975
|
-
if (code === 0)
|
|
24731
|
+
if (code === 0) resolve7();
|
|
23976
24732
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
23977
24733
|
});
|
|
23978
24734
|
proc.stdin?.write(contents);
|
|
@@ -24020,10 +24776,10 @@ function shellQuote3(s) {
|
|
|
24020
24776
|
}
|
|
24021
24777
|
|
|
24022
24778
|
// src/services/providers/railway.ts
|
|
24023
|
-
var
|
|
24779
|
+
var import_child_process22 = require("child_process");
|
|
24024
24780
|
var import_util7 = require("util");
|
|
24025
|
-
var
|
|
24026
|
-
var execFileP8 = (0, import_util7.promisify)(
|
|
24781
|
+
var path46 = __toESM(require("path"));
|
|
24782
|
+
var execFileP8 = (0, import_util7.promisify)(import_child_process22.execFile);
|
|
24027
24783
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
24028
24784
|
function resetStdinForChild4() {
|
|
24029
24785
|
if (process.stdin.isTTY) {
|
|
@@ -24063,10 +24819,10 @@ var RailwayProvider = class {
|
|
|
24063
24819
|
"Authenticating Railway"
|
|
24064
24820
|
);
|
|
24065
24821
|
resetStdinForChild4();
|
|
24066
|
-
await new Promise((
|
|
24067
|
-
const proc = (0,
|
|
24822
|
+
await new Promise((resolve7, reject) => {
|
|
24823
|
+
const proc = (0, import_child_process22.spawn)("railway", ["login"], { stdio: "inherit" });
|
|
24068
24824
|
proc.on("exit", (code) => {
|
|
24069
|
-
if (code === 0)
|
|
24825
|
+
if (code === 0) resolve7();
|
|
24070
24826
|
else reject(new Error("railway login failed."));
|
|
24071
24827
|
});
|
|
24072
24828
|
proc.on("error", reject);
|
|
@@ -24206,13 +24962,13 @@ var RailwayProvider = class {
|
|
|
24206
24962
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
24207
24963
|
}
|
|
24208
24964
|
resetStdinForChild4();
|
|
24209
|
-
return new Promise((
|
|
24210
|
-
const proc = (0,
|
|
24965
|
+
return new Promise((resolve7, reject) => {
|
|
24966
|
+
const proc = (0, import_child_process22.spawn)(
|
|
24211
24967
|
"railway",
|
|
24212
24968
|
["shell", "--project", projectId, "--service", serviceId, "--command", command2],
|
|
24213
24969
|
{ stdio: "inherit" }
|
|
24214
24970
|
);
|
|
24215
|
-
proc.on("exit", (code) =>
|
|
24971
|
+
proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
|
|
24216
24972
|
proc.on("error", reject);
|
|
24217
24973
|
});
|
|
24218
24974
|
}
|
|
@@ -24230,9 +24986,9 @@ var RailwayProvider = class {
|
|
|
24230
24986
|
tarArgs.push(".");
|
|
24231
24987
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
24232
24988
|
const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
|
|
24233
|
-
await new Promise((
|
|
24234
|
-
const tar = (0,
|
|
24235
|
-
const sh = (0,
|
|
24989
|
+
await new Promise((resolve7, reject) => {
|
|
24990
|
+
const tar = (0, import_child_process22.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
24991
|
+
const sh = (0, import_child_process22.spawn)(
|
|
24236
24992
|
"railway",
|
|
24237
24993
|
["shell", "--project", projectId, "--service", serviceId, "--command", remoteCmd],
|
|
24238
24994
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -24248,7 +25004,7 @@ var RailwayProvider = class {
|
|
|
24248
25004
|
tar.on("error", reject);
|
|
24249
25005
|
sh.on("error", reject);
|
|
24250
25006
|
sh.on("exit", (code) => {
|
|
24251
|
-
if (code === 0)
|
|
25007
|
+
if (code === 0) resolve7();
|
|
24252
25008
|
else reject(new Error(`Remote tar failed: ${(shErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
24253
25009
|
});
|
|
24254
25010
|
});
|
|
@@ -24258,14 +25014,14 @@ var RailwayProvider = class {
|
|
|
24258
25014
|
if (!projectId || !serviceId) {
|
|
24259
25015
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
24260
25016
|
}
|
|
24261
|
-
const remoteDir =
|
|
25017
|
+
const remoteDir = path46.posix.dirname(remotePath);
|
|
24262
25018
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
24263
25019
|
if (options.mode != null) {
|
|
24264
25020
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
24265
25021
|
}
|
|
24266
25022
|
const cmd = parts.join(" && ");
|
|
24267
|
-
await new Promise((
|
|
24268
|
-
const proc = (0,
|
|
25023
|
+
await new Promise((resolve7, reject) => {
|
|
25024
|
+
const proc = (0, import_child_process22.spawn)(
|
|
24269
25025
|
"railway",
|
|
24270
25026
|
["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
|
|
24271
25027
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -24276,7 +25032,7 @@ var RailwayProvider = class {
|
|
|
24276
25032
|
});
|
|
24277
25033
|
proc.on("error", reject);
|
|
24278
25034
|
proc.on("exit", (code) => {
|
|
24279
|
-
if (code === 0)
|
|
25035
|
+
if (code === 0) resolve7();
|
|
24280
25036
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
24281
25037
|
});
|
|
24282
25038
|
proc.stdin?.write(contents);
|
|
@@ -24801,8 +25557,8 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
24801
25557
|
var import_node_dns = require("dns");
|
|
24802
25558
|
var import_node_util4 = require("util");
|
|
24803
25559
|
var import_node_crypto8 = require("crypto");
|
|
24804
|
-
var
|
|
24805
|
-
var
|
|
25560
|
+
var fs36 = __toESM(require("fs"));
|
|
25561
|
+
var path47 = __toESM(require("path"));
|
|
24806
25562
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
24807
25563
|
var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
|
|
24808
25564
|
async function checkDns(apiBase) {
|
|
@@ -24858,13 +25614,13 @@ async function checkHealth(apiBase) {
|
|
|
24858
25614
|
}
|
|
24859
25615
|
}
|
|
24860
25616
|
function checkConfigDir() {
|
|
24861
|
-
const dir =
|
|
25617
|
+
const dir = path47.join(require("os").homedir(), ".codeam");
|
|
24862
25618
|
try {
|
|
24863
|
-
|
|
24864
|
-
const probe =
|
|
24865
|
-
|
|
24866
|
-
const read =
|
|
24867
|
-
|
|
25619
|
+
fs36.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
25620
|
+
const probe = path47.join(dir, ".doctor-probe");
|
|
25621
|
+
fs36.writeFileSync(probe, "ok", { mode: 384 });
|
|
25622
|
+
const read = fs36.readFileSync(probe, "utf8");
|
|
25623
|
+
fs36.unlinkSync(probe);
|
|
24868
25624
|
if (read !== "ok") throw new Error("write/read round-trip mismatch");
|
|
24869
25625
|
return {
|
|
24870
25626
|
id: "config-dir",
|
|
@@ -24904,9 +25660,9 @@ function checkSessions() {
|
|
|
24904
25660
|
}
|
|
24905
25661
|
}
|
|
24906
25662
|
function checkAgentBinaries() {
|
|
24907
|
-
const
|
|
25663
|
+
const os30 = createOsStrategy();
|
|
24908
25664
|
return getEnabledAgents().map((meta) => {
|
|
24909
|
-
const found =
|
|
25665
|
+
const found = os30.findInPath(meta.binaryName);
|
|
24910
25666
|
return {
|
|
24911
25667
|
id: `agent-${meta.id}`,
|
|
24912
25668
|
label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
|
|
@@ -24928,7 +25684,7 @@ function checkNodePty() {
|
|
|
24928
25684
|
detail: "not required on this platform"
|
|
24929
25685
|
};
|
|
24930
25686
|
}
|
|
24931
|
-
const vendoredPath =
|
|
25687
|
+
const vendoredPath = path47.join(__dirname, "vendor", "node-pty");
|
|
24932
25688
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
24933
25689
|
try {
|
|
24934
25690
|
require(target);
|
|
@@ -24970,7 +25726,7 @@ function checkChokidar() {
|
|
|
24970
25726
|
}
|
|
24971
25727
|
async function doctor(args2 = []) {
|
|
24972
25728
|
const json = args2.includes("--json");
|
|
24973
|
-
const cliVersion = true ? "2.
|
|
25729
|
+
const cliVersion = true ? "2.33.0" : "0.0.0-dev";
|
|
24974
25730
|
const apiBase = resolveApiBaseUrl();
|
|
24975
25731
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
24976
25732
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -25169,7 +25925,7 @@ async function completion(args2) {
|
|
|
25169
25925
|
// src/commands/version.ts
|
|
25170
25926
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
25171
25927
|
function version2() {
|
|
25172
|
-
const v = true ? "2.
|
|
25928
|
+
const v = true ? "2.33.0" : "unknown";
|
|
25173
25929
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
25174
25930
|
}
|
|
25175
25931
|
|
|
@@ -25297,9 +26053,9 @@ function tryShowSubcommandHelp(cmd, args2) {
|
|
|
25297
26053
|
var _subcommandHelpKeys = Object.keys(HELPS);
|
|
25298
26054
|
|
|
25299
26055
|
// src/lib/updateNotifier.ts
|
|
25300
|
-
var
|
|
25301
|
-
var
|
|
25302
|
-
var
|
|
26056
|
+
var fs37 = __toESM(require("fs"));
|
|
26057
|
+
var os29 = __toESM(require("os"));
|
|
26058
|
+
var path48 = __toESM(require("path"));
|
|
25303
26059
|
var https8 = __toESM(require("https"));
|
|
25304
26060
|
var import_node_child_process12 = require("child_process");
|
|
25305
26061
|
var import_picocolors16 = __toESM(require("picocolors"));
|
|
@@ -25308,12 +26064,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
|
25308
26064
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
25309
26065
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
25310
26066
|
function cachePath() {
|
|
25311
|
-
const dir =
|
|
25312
|
-
return
|
|
26067
|
+
const dir = path48.join(os29.homedir(), ".codeam");
|
|
26068
|
+
return path48.join(dir, "update-check.json");
|
|
25313
26069
|
}
|
|
25314
26070
|
function readCache() {
|
|
25315
26071
|
try {
|
|
25316
|
-
const raw =
|
|
26072
|
+
const raw = fs37.readFileSync(cachePath(), "utf8");
|
|
25317
26073
|
const parsed = JSON.parse(raw);
|
|
25318
26074
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
25319
26075
|
return parsed;
|
|
@@ -25324,10 +26080,10 @@ function readCache() {
|
|
|
25324
26080
|
function writeCache(cache) {
|
|
25325
26081
|
try {
|
|
25326
26082
|
const file = cachePath();
|
|
25327
|
-
|
|
26083
|
+
fs37.mkdirSync(path48.dirname(file), { recursive: true });
|
|
25328
26084
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
25329
|
-
|
|
25330
|
-
|
|
26085
|
+
fs37.writeFileSync(tmp, JSON.stringify(cache));
|
|
26086
|
+
fs37.renameSync(tmp, file);
|
|
25331
26087
|
} catch {
|
|
25332
26088
|
}
|
|
25333
26089
|
}
|
|
@@ -25345,14 +26101,14 @@ function compareSemver(a, b) {
|
|
|
25345
26101
|
return 0;
|
|
25346
26102
|
}
|
|
25347
26103
|
function fetchLatest() {
|
|
25348
|
-
return new Promise((
|
|
26104
|
+
return new Promise((resolve7) => {
|
|
25349
26105
|
const req = https8.get(
|
|
25350
26106
|
REGISTRY_URL,
|
|
25351
26107
|
{ headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
|
|
25352
26108
|
(res) => {
|
|
25353
26109
|
if (res.statusCode !== 200) {
|
|
25354
26110
|
res.resume();
|
|
25355
|
-
|
|
26111
|
+
resolve7(null);
|
|
25356
26112
|
return;
|
|
25357
26113
|
}
|
|
25358
26114
|
let buf = "";
|
|
@@ -25364,21 +26120,21 @@ function fetchLatest() {
|
|
|
25364
26120
|
try {
|
|
25365
26121
|
const json = JSON.parse(buf);
|
|
25366
26122
|
if (typeof json.version === "string") {
|
|
25367
|
-
|
|
26123
|
+
resolve7(json.version);
|
|
25368
26124
|
} else {
|
|
25369
|
-
|
|
26125
|
+
resolve7(null);
|
|
25370
26126
|
}
|
|
25371
26127
|
} catch {
|
|
25372
|
-
|
|
26128
|
+
resolve7(null);
|
|
25373
26129
|
}
|
|
25374
26130
|
});
|
|
25375
26131
|
}
|
|
25376
26132
|
);
|
|
25377
26133
|
req.on("timeout", () => {
|
|
25378
26134
|
req.destroy();
|
|
25379
|
-
|
|
26135
|
+
resolve7(null);
|
|
25380
26136
|
});
|
|
25381
|
-
req.on("error", () =>
|
|
26137
|
+
req.on("error", () => resolve7(null));
|
|
25382
26138
|
});
|
|
25383
26139
|
}
|
|
25384
26140
|
function notifyIfStale(currentVersion, latest) {
|
|
@@ -25401,8 +26157,8 @@ function isLinkedInstall() {
|
|
|
25401
26157
|
timeout: 2e3
|
|
25402
26158
|
}).trim();
|
|
25403
26159
|
if (!root) return false;
|
|
25404
|
-
const pkgPath =
|
|
25405
|
-
return
|
|
26160
|
+
const pkgPath = path48.join(root, PKG_NAME);
|
|
26161
|
+
return fs37.lstatSync(pkgPath).isSymbolicLink();
|
|
25406
26162
|
} catch {
|
|
25407
26163
|
return false;
|
|
25408
26164
|
}
|
|
@@ -25438,7 +26194,7 @@ function maybeAutoUpdate(currentVersion, latest) {
|
|
|
25438
26194
|
return;
|
|
25439
26195
|
}
|
|
25440
26196
|
try {
|
|
25441
|
-
|
|
26197
|
+
fs37.unlinkSync(cachePath());
|
|
25442
26198
|
} catch {
|
|
25443
26199
|
}
|
|
25444
26200
|
process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
|
|
@@ -25455,7 +26211,7 @@ function checkForUpdates() {
|
|
|
25455
26211
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
25456
26212
|
if (process.env.CI) return;
|
|
25457
26213
|
if (!process.stdout.isTTY) return;
|
|
25458
|
-
const current = true ? "2.
|
|
26214
|
+
const current = true ? "2.33.0" : null;
|
|
25459
26215
|
if (!current) return;
|
|
25460
26216
|
const cache = readCache();
|
|
25461
26217
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|