codeam-cli 2.32.9 → 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 +26 -0
- package/dist/index.js +1187 -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",
|
|
@@ -614,6 +615,12 @@ function showError(msg) {
|
|
|
614
615
|
function showInfo(msg) {
|
|
615
616
|
out(` ${import_picocolors.default.dim("\xB7")} ${msg}`);
|
|
616
617
|
}
|
|
618
|
+
function showRelayNotice() {
|
|
619
|
+
out("");
|
|
620
|
+
out(` ${import_picocolors.default.bold(import_picocolors.default.yellow("\u26A0 This terminal is a relay \u2014 do not type here."))}`);
|
|
621
|
+
out(` ${import_picocolors.default.dim("Send your prompts from the CodeAgent Mobile app; replies stream in below.")}`);
|
|
622
|
+
out("");
|
|
623
|
+
}
|
|
617
624
|
var BOX_INTERIOR = 30;
|
|
618
625
|
var BOX_BORDER_TOP = ` \u250C${"\u2500".repeat(BOX_INTERIOR)}\u2510`;
|
|
619
626
|
var BOX_BORDER_BOT = ` \u2514${"\u2500".repeat(BOX_INTERIOR)}\u2518`;
|
|
@@ -701,8 +708,8 @@ async function requestCode(pluginId) {
|
|
|
701
708
|
});
|
|
702
709
|
let timer;
|
|
703
710
|
const timeoutSentinel = /* @__PURE__ */ Symbol("request-code-timeout");
|
|
704
|
-
const timeoutPromise = new Promise((
|
|
705
|
-
timer = setTimeout(() =>
|
|
711
|
+
const timeoutPromise = new Promise((resolve7) => {
|
|
712
|
+
timer = setTimeout(() => resolve7(timeoutSentinel), REQUEST_CODE_TIMEOUT_MS);
|
|
706
713
|
});
|
|
707
714
|
const result = await Promise.race([post2, timeoutPromise]);
|
|
708
715
|
clearTimeout(timer);
|
|
@@ -846,7 +853,7 @@ async function postPreviewEvent(input) {
|
|
|
846
853
|
}
|
|
847
854
|
}
|
|
848
855
|
async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
849
|
-
return new Promise((
|
|
856
|
+
return new Promise((resolve7, reject) => {
|
|
850
857
|
const data = JSON.stringify(body);
|
|
851
858
|
const u2 = new URL(url);
|
|
852
859
|
const transport = u2.protocol === "https:" ? https : http;
|
|
@@ -878,9 +885,9 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
|
878
885
|
return;
|
|
879
886
|
}
|
|
880
887
|
try {
|
|
881
|
-
|
|
888
|
+
resolve7(JSON.parse(responseBody));
|
|
882
889
|
} catch {
|
|
883
|
-
|
|
890
|
+
resolve7(null);
|
|
884
891
|
}
|
|
885
892
|
});
|
|
886
893
|
}
|
|
@@ -905,7 +912,7 @@ function makeHttpError(statusCode, retryAfterHeader, responseBody) {
|
|
|
905
912
|
return err;
|
|
906
913
|
}
|
|
907
914
|
async function _postJson(url, body) {
|
|
908
|
-
return new Promise((
|
|
915
|
+
return new Promise((resolve7, reject) => {
|
|
909
916
|
const data = JSON.stringify(body);
|
|
910
917
|
const u2 = new URL(url);
|
|
911
918
|
const transport = u2.protocol === "https:" ? https : http;
|
|
@@ -934,9 +941,9 @@ async function _postJson(url, body) {
|
|
|
934
941
|
return;
|
|
935
942
|
}
|
|
936
943
|
try {
|
|
937
|
-
|
|
944
|
+
resolve7(JSON.parse(body2));
|
|
938
945
|
} catch {
|
|
939
|
-
|
|
946
|
+
resolve7(null);
|
|
940
947
|
}
|
|
941
948
|
});
|
|
942
949
|
}
|
|
@@ -951,7 +958,7 @@ async function _postJson(url, body) {
|
|
|
951
958
|
});
|
|
952
959
|
}
|
|
953
960
|
async function _getJson(url) {
|
|
954
|
-
return new Promise((
|
|
961
|
+
return new Promise((resolve7, reject) => {
|
|
955
962
|
const u2 = new URL(url);
|
|
956
963
|
const transport = u2.protocol === "https:" ? https : http;
|
|
957
964
|
const req = transport.request(
|
|
@@ -975,9 +982,9 @@ async function _getJson(url) {
|
|
|
975
982
|
return;
|
|
976
983
|
}
|
|
977
984
|
try {
|
|
978
|
-
|
|
985
|
+
resolve7(JSON.parse(body));
|
|
979
986
|
} catch {
|
|
980
|
-
|
|
987
|
+
resolve7(null);
|
|
981
988
|
}
|
|
982
989
|
});
|
|
983
990
|
}
|
|
@@ -1155,8 +1162,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
1155
1162
|
return decodedFile;
|
|
1156
1163
|
};
|
|
1157
1164
|
}
|
|
1158
|
-
function normalizeWindowsPath(
|
|
1159
|
-
return
|
|
1165
|
+
function normalizeWindowsPath(path49) {
|
|
1166
|
+
return path49.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
1160
1167
|
}
|
|
1161
1168
|
|
|
1162
1169
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -3636,15 +3643,15 @@ async function addSourceContext(frames) {
|
|
|
3636
3643
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
3637
3644
|
return frames;
|
|
3638
3645
|
}
|
|
3639
|
-
function getContextLinesFromFile(
|
|
3640
|
-
return new Promise((
|
|
3641
|
-
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);
|
|
3642
3649
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
3643
3650
|
input: stream
|
|
3644
3651
|
});
|
|
3645
3652
|
function destroyStreamAndResolve() {
|
|
3646
3653
|
stream.destroy();
|
|
3647
|
-
|
|
3654
|
+
resolve7();
|
|
3648
3655
|
}
|
|
3649
3656
|
let lineNumber = 0;
|
|
3650
3657
|
let currentRangeIndex = 0;
|
|
@@ -3653,7 +3660,7 @@ function getContextLinesFromFile(path46, ranges, output) {
|
|
|
3653
3660
|
let rangeStart = range[0];
|
|
3654
3661
|
let rangeEnd = range[1];
|
|
3655
3662
|
function onStreamError() {
|
|
3656
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
3663
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path49, 1);
|
|
3657
3664
|
lineReaded.close();
|
|
3658
3665
|
lineReaded.removeAllListeners();
|
|
3659
3666
|
destroyStreamAndResolve();
|
|
@@ -3714,8 +3721,8 @@ function clearLineContext(frame) {
|
|
|
3714
3721
|
delete frame.context_line;
|
|
3715
3722
|
delete frame.post_context;
|
|
3716
3723
|
}
|
|
3717
|
-
function shouldSkipContextLinesForFile(
|
|
3718
|
-
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:");
|
|
3719
3726
|
}
|
|
3720
3727
|
function shouldSkipContextLinesForFrame(frame) {
|
|
3721
3728
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -4931,9 +4938,9 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4931
4938
|
if (!waitUntil) return;
|
|
4932
4939
|
if (this.disabled || this.optedOut) return;
|
|
4933
4940
|
if (!this._waitUntilCycle) {
|
|
4934
|
-
let
|
|
4941
|
+
let resolve7;
|
|
4935
4942
|
const promise = new Promise((r) => {
|
|
4936
|
-
|
|
4943
|
+
resolve7 = r;
|
|
4937
4944
|
});
|
|
4938
4945
|
try {
|
|
4939
4946
|
waitUntil(promise);
|
|
@@ -4941,7 +4948,7 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4941
4948
|
return;
|
|
4942
4949
|
}
|
|
4943
4950
|
this._waitUntilCycle = {
|
|
4944
|
-
resolve:
|
|
4951
|
+
resolve: resolve7,
|
|
4945
4952
|
startedAt: Date.now(),
|
|
4946
4953
|
timer: void 0
|
|
4947
4954
|
};
|
|
@@ -4965,12 +4972,12 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4965
4972
|
return cycle?.resolve;
|
|
4966
4973
|
}
|
|
4967
4974
|
async resolveWaitUntilFlush() {
|
|
4968
|
-
const
|
|
4975
|
+
const resolve7 = this._consumeWaitUntilCycle();
|
|
4969
4976
|
try {
|
|
4970
4977
|
await super.flush();
|
|
4971
4978
|
} catch {
|
|
4972
4979
|
} finally {
|
|
4973
|
-
|
|
4980
|
+
resolve7?.();
|
|
4974
4981
|
}
|
|
4975
4982
|
}
|
|
4976
4983
|
getPersistedProperty(key) {
|
|
@@ -5062,15 +5069,15 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
5062
5069
|
async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
|
|
5063
5070
|
if (this.isLocalEvaluationReady()) return true;
|
|
5064
5071
|
if (void 0 === this.featureFlagsPoller) return false;
|
|
5065
|
-
return new Promise((
|
|
5072
|
+
return new Promise((resolve7) => {
|
|
5066
5073
|
const timeout = setTimeout(() => {
|
|
5067
5074
|
cleanup();
|
|
5068
|
-
|
|
5075
|
+
resolve7(false);
|
|
5069
5076
|
}, timeoutMs);
|
|
5070
5077
|
const cleanup = this._events.on("localEvaluationFlagsLoaded", (count) => {
|
|
5071
5078
|
clearTimeout(timeout);
|
|
5072
5079
|
cleanup();
|
|
5073
|
-
|
|
5080
|
+
resolve7(count > 0);
|
|
5074
5081
|
});
|
|
5075
5082
|
});
|
|
5076
5083
|
}
|
|
@@ -5507,13 +5514,13 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
5507
5514
|
this.context?.enter(data, options);
|
|
5508
5515
|
}
|
|
5509
5516
|
async _shutdown(shutdownTimeoutMs) {
|
|
5510
|
-
const
|
|
5517
|
+
const resolve7 = this._consumeWaitUntilCycle();
|
|
5511
5518
|
await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
|
|
5512
5519
|
this.errorTracking.shutdown();
|
|
5513
5520
|
try {
|
|
5514
5521
|
return await super._shutdown(shutdownTimeoutMs);
|
|
5515
5522
|
} finally {
|
|
5516
|
-
|
|
5523
|
+
resolve7?.();
|
|
5517
5524
|
}
|
|
5518
5525
|
}
|
|
5519
5526
|
async _requestRemoteConfigPayload(flagKey) {
|
|
@@ -5869,7 +5876,7 @@ function readAnonId() {
|
|
|
5869
5876
|
}
|
|
5870
5877
|
function superProperties() {
|
|
5871
5878
|
return {
|
|
5872
|
-
cliVersion: true ? "2.
|
|
5879
|
+
cliVersion: true ? "2.33.0" : "0.0.0-dev",
|
|
5873
5880
|
nodeVersion: process.version,
|
|
5874
5881
|
platform: process.platform,
|
|
5875
5882
|
arch: process.arch,
|
|
@@ -7211,10 +7218,10 @@ function buildForPlatform(platform2) {
|
|
|
7211
7218
|
var import_node_crypto4 = require("crypto");
|
|
7212
7219
|
|
|
7213
7220
|
// src/agents/claude/resolver.ts
|
|
7214
|
-
function buildClaudeLaunch(extraArgs = [],
|
|
7215
|
-
const found =
|
|
7221
|
+
function buildClaudeLaunch(extraArgs = [], os30 = createOsStrategy()) {
|
|
7222
|
+
const found = os30.findInPath("claude") ?? os30.findInPath("claude-code");
|
|
7216
7223
|
if (!found) return null;
|
|
7217
|
-
return
|
|
7224
|
+
return os30.buildLaunch(found, extraArgs);
|
|
7218
7225
|
}
|
|
7219
7226
|
|
|
7220
7227
|
// src/agents/claude/installer.ts
|
|
@@ -9170,15 +9177,15 @@ function runInstaller() {
|
|
|
9170
9177
|
"-Command",
|
|
9171
9178
|
"irm https://claude.ai/install.ps1 | iex"
|
|
9172
9179
|
] : ["-c", "curl -fsSL https://claude.ai/install.sh | bash"];
|
|
9173
|
-
return new Promise((
|
|
9180
|
+
return new Promise((resolve7) => {
|
|
9174
9181
|
const proc = (0, import_child_process4.spawn)(cmd, args2, { stdio: "inherit" });
|
|
9175
9182
|
proc.on("error", (err) => {
|
|
9176
9183
|
console.error(`
|
|
9177
9184
|
\u2717 Installer failed to launch: ${err.message}`);
|
|
9178
|
-
|
|
9185
|
+
resolve7(false);
|
|
9179
9186
|
});
|
|
9180
9187
|
proc.on("exit", (code) => {
|
|
9181
|
-
|
|
9188
|
+
resolve7(code === 0);
|
|
9182
9189
|
});
|
|
9183
9190
|
});
|
|
9184
9191
|
}
|
|
@@ -9355,17 +9362,17 @@ function parseUsageOutput(raw) {
|
|
|
9355
9362
|
return { percent, resetAt };
|
|
9356
9363
|
}
|
|
9357
9364
|
async function fetchClaudeQuota() {
|
|
9358
|
-
return new Promise((
|
|
9365
|
+
return new Promise((resolve7) => {
|
|
9359
9366
|
const claudeCmd = findInPath("claude") ? "claude" : "claude-code";
|
|
9360
9367
|
if (!claudeCmd) {
|
|
9361
|
-
|
|
9368
|
+
resolve7(null);
|
|
9362
9369
|
return;
|
|
9363
9370
|
}
|
|
9364
9371
|
const helperPath = path11.join(os10.tmpdir(), "codeam-quota-helper.py");
|
|
9365
9372
|
fs8.writeFileSync(helperPath, HELPER_SCRIPT, { mode: 420 });
|
|
9366
9373
|
const python = findInPath("python3") ?? findInPath("python");
|
|
9367
9374
|
if (!python) {
|
|
9368
|
-
|
|
9375
|
+
resolve7(null);
|
|
9369
9376
|
return;
|
|
9370
9377
|
}
|
|
9371
9378
|
const proc = (0, import_child_process5.spawn)(python, [helperPath, claudeCmd, "--tools", ""], {
|
|
@@ -9392,13 +9399,13 @@ async function fetchClaudeQuota() {
|
|
|
9392
9399
|
fs8.unlinkSync(helperPath);
|
|
9393
9400
|
} catch {
|
|
9394
9401
|
}
|
|
9395
|
-
|
|
9402
|
+
resolve7(result);
|
|
9396
9403
|
}, 5e3);
|
|
9397
9404
|
}, 8e3);
|
|
9398
9405
|
setTimeout(() => {
|
|
9399
9406
|
if (!resolved) {
|
|
9400
9407
|
resolved = true;
|
|
9401
|
-
|
|
9408
|
+
resolve7(null);
|
|
9402
9409
|
}
|
|
9403
9410
|
try {
|
|
9404
9411
|
proc.kill();
|
|
@@ -9429,12 +9436,12 @@ function killActiveSpawnAndCaptureChildren() {
|
|
|
9429
9436
|
}
|
|
9430
9437
|
async function spawnAndCapture(cmd, args2, opts = {}) {
|
|
9431
9438
|
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
9432
|
-
return new Promise((
|
|
9439
|
+
return new Promise((resolve7) => {
|
|
9433
9440
|
let settled = false;
|
|
9434
9441
|
const settle = (value) => {
|
|
9435
9442
|
if (settled) return;
|
|
9436
9443
|
settled = true;
|
|
9437
|
-
|
|
9444
|
+
resolve7(value);
|
|
9438
9445
|
};
|
|
9439
9446
|
let child;
|
|
9440
9447
|
try {
|
|
@@ -9941,13 +9948,13 @@ function detectStartupBanner(lines) {
|
|
|
9941
9948
|
while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
|
|
9942
9949
|
if (metaIdx - artStart < 2) return null;
|
|
9943
9950
|
const pathLine = (lines[metaIdx + 1] ?? "").trim();
|
|
9944
|
-
const
|
|
9951
|
+
const path49 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
|
|
9945
9952
|
return {
|
|
9946
9953
|
title: "",
|
|
9947
9954
|
subtitle: lines[metaIdx].trim(),
|
|
9948
|
-
path:
|
|
9955
|
+
path: path49,
|
|
9949
9956
|
startIdx: artStart,
|
|
9950
|
-
endIdx: metaIdx + (
|
|
9957
|
+
endIdx: metaIdx + (path49 ? 1 : 0)
|
|
9951
9958
|
};
|
|
9952
9959
|
}
|
|
9953
9960
|
|
|
@@ -9957,8 +9964,8 @@ var ClaudeRuntimeStrategy = class {
|
|
|
9957
9964
|
meta = getAgent("claude");
|
|
9958
9965
|
mode = "interactive";
|
|
9959
9966
|
os;
|
|
9960
|
-
constructor(
|
|
9961
|
-
this.os =
|
|
9967
|
+
constructor(os30) {
|
|
9968
|
+
this.os = os30;
|
|
9962
9969
|
}
|
|
9963
9970
|
/**
|
|
9964
9971
|
* Claude Code's react-ink TUI enables bracketed-paste mode at
|
|
@@ -10966,8 +10973,8 @@ function codexCredentialLocator() {
|
|
|
10966
10973
|
function codexLoginLauncher() {
|
|
10967
10974
|
return {
|
|
10968
10975
|
async ensureInstalled() {
|
|
10969
|
-
const
|
|
10970
|
-
return
|
|
10976
|
+
const os30 = createOsStrategy();
|
|
10977
|
+
return os30.findInPath("codex") !== null;
|
|
10971
10978
|
},
|
|
10972
10979
|
launch() {
|
|
10973
10980
|
return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
@@ -10990,8 +10997,8 @@ var CodexRuntimeStrategy = class {
|
|
|
10990
10997
|
meta = getAgent("codex");
|
|
10991
10998
|
mode = "interactive";
|
|
10992
10999
|
os;
|
|
10993
|
-
constructor(
|
|
10994
|
-
this.os =
|
|
11000
|
+
constructor(os30) {
|
|
11001
|
+
this.os = os30;
|
|
10995
11002
|
}
|
|
10996
11003
|
async prepareLaunch() {
|
|
10997
11004
|
let binary = this.os.findInPath("codex");
|
|
@@ -11097,16 +11104,16 @@ var CodexRuntimeStrategy = class {
|
|
|
11097
11104
|
});
|
|
11098
11105
|
}
|
|
11099
11106
|
};
|
|
11100
|
-
function resolveNpm(
|
|
11101
|
-
return
|
|
11107
|
+
function resolveNpm(os30) {
|
|
11108
|
+
return os30.id === "win32" ? "npm.cmd" : "npm";
|
|
11102
11109
|
}
|
|
11103
|
-
async function installCodexViaNpm(
|
|
11104
|
-
return new Promise((
|
|
11105
|
-
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"], {
|
|
11106
11113
|
stdio: "inherit"
|
|
11107
11114
|
});
|
|
11108
11115
|
proc.on("close", (code) => {
|
|
11109
|
-
if (code === 0)
|
|
11116
|
+
if (code === 0) resolve7();
|
|
11110
11117
|
else reject(new Error(`npm install -g @openai/codex exited ${code}`));
|
|
11111
11118
|
});
|
|
11112
11119
|
proc.on("error", (err) => {
|
|
@@ -11119,16 +11126,16 @@ async function installCodexViaNpm(os29) {
|
|
|
11119
11126
|
});
|
|
11120
11127
|
});
|
|
11121
11128
|
}
|
|
11122
|
-
function augmentNpmGlobalBin(
|
|
11129
|
+
function augmentNpmGlobalBin(os30) {
|
|
11123
11130
|
try {
|
|
11124
|
-
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(
|
|
11131
|
+
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os30), ["prefix", "-g"], {
|
|
11125
11132
|
stdio: ["ignore", "pipe", "ignore"]
|
|
11126
11133
|
});
|
|
11127
11134
|
if (result.status !== 0) return;
|
|
11128
11135
|
const prefix = result.stdout.toString().trim();
|
|
11129
11136
|
if (!prefix) return;
|
|
11130
|
-
const binDir =
|
|
11131
|
-
|
|
11137
|
+
const binDir = os30.id === "win32" ? prefix : path17.join(prefix, "bin");
|
|
11138
|
+
os30.augmentPath([binDir]);
|
|
11132
11139
|
} catch {
|
|
11133
11140
|
}
|
|
11134
11141
|
}
|
|
@@ -11212,25 +11219,25 @@ var import_node_child_process7 = require("child_process");
|
|
|
11212
11219
|
// src/agents/coderabbit/installer.ts
|
|
11213
11220
|
var import_node_child_process5 = require("child_process");
|
|
11214
11221
|
var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
|
|
11215
|
-
async function ensureCoderabbitInstalled(
|
|
11216
|
-
if (
|
|
11217
|
-
if (
|
|
11222
|
+
async function ensureCoderabbitInstalled(os30) {
|
|
11223
|
+
if (os30.findInPath("coderabbit")) return true;
|
|
11224
|
+
if (os30.id === "win32") {
|
|
11218
11225
|
console.error(
|
|
11219
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"
|
|
11220
11227
|
);
|
|
11221
11228
|
return false;
|
|
11222
11229
|
}
|
|
11223
11230
|
console.log("\n CodeRabbit CLI not found \u2014 installing via the official script\u2026\n");
|
|
11224
|
-
const ok = await new Promise((
|
|
11231
|
+
const ok = await new Promise((resolve7) => {
|
|
11225
11232
|
const proc = (0, import_node_child_process5.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL} | sh`], {
|
|
11226
11233
|
stdio: "inherit"
|
|
11227
11234
|
});
|
|
11228
|
-
proc.on("close", (code) =>
|
|
11229
|
-
proc.on("error", () =>
|
|
11235
|
+
proc.on("close", (code) => resolve7(code === 0));
|
|
11236
|
+
proc.on("error", () => resolve7(false));
|
|
11230
11237
|
});
|
|
11231
11238
|
if (!ok) return false;
|
|
11232
|
-
|
|
11233
|
-
return
|
|
11239
|
+
os30.augmentPath([`${os30.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
11240
|
+
return os30.findInPath("coderabbit") !== null;
|
|
11234
11241
|
}
|
|
11235
11242
|
|
|
11236
11243
|
// src/agents/coderabbit/link.ts
|
|
@@ -11257,10 +11264,10 @@ function coderabbitCredentialLocator() {
|
|
|
11257
11264
|
extract: extractLocalCoderabbitToken
|
|
11258
11265
|
};
|
|
11259
11266
|
}
|
|
11260
|
-
function coderabbitLoginLauncher(
|
|
11267
|
+
function coderabbitLoginLauncher(os30) {
|
|
11261
11268
|
return {
|
|
11262
11269
|
async ensureInstalled() {
|
|
11263
|
-
return ensureCoderabbitInstalled(
|
|
11270
|
+
return ensureCoderabbitInstalled(os30);
|
|
11264
11271
|
},
|
|
11265
11272
|
launch() {
|
|
11266
11273
|
return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
|
|
@@ -11283,11 +11290,11 @@ function parseReview(stdout) {
|
|
|
11283
11290
|
for (const line of lines) {
|
|
11284
11291
|
const m = line.match(HUNK_LINE_RE);
|
|
11285
11292
|
if (!m) continue;
|
|
11286
|
-
const [,
|
|
11287
|
-
if (!
|
|
11293
|
+
const [, path49, lineNo, sevToken, message] = m;
|
|
11294
|
+
if (!path49 || !lineNo || !message) continue;
|
|
11288
11295
|
const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
|
|
11289
11296
|
hunks.push({
|
|
11290
|
-
path:
|
|
11297
|
+
path: path49.trim(),
|
|
11291
11298
|
line: Number(lineNo),
|
|
11292
11299
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
11293
11300
|
message: cleanedMessage
|
|
@@ -11306,8 +11313,8 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11306
11313
|
meta = getAgent("coderabbit");
|
|
11307
11314
|
mode = "batch";
|
|
11308
11315
|
os;
|
|
11309
|
-
constructor(
|
|
11310
|
-
this.os =
|
|
11316
|
+
constructor(os30) {
|
|
11317
|
+
this.os = os30;
|
|
11311
11318
|
}
|
|
11312
11319
|
getDefaultArgs() {
|
|
11313
11320
|
return ["review"];
|
|
@@ -11345,7 +11352,7 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11345
11352
|
}
|
|
11346
11353
|
async runOneShot(input) {
|
|
11347
11354
|
const launch = await this.prepareInvocation(input);
|
|
11348
|
-
return new Promise((
|
|
11355
|
+
return new Promise((resolve7, reject) => {
|
|
11349
11356
|
const stdoutBuf = [];
|
|
11350
11357
|
const stderrBuf = [];
|
|
11351
11358
|
const proc = (0, import_node_child_process7.spawn)(launch.cmd, launch.args, {
|
|
@@ -11356,7 +11363,7 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11356
11363
|
proc.stderr?.on("data", (b) => stderrBuf.push(b));
|
|
11357
11364
|
proc.on("error", (err) => reject(err));
|
|
11358
11365
|
proc.on("close", (code) => {
|
|
11359
|
-
|
|
11366
|
+
resolve7(
|
|
11360
11367
|
this.parseOutput({
|
|
11361
11368
|
exitCode: code ?? 0,
|
|
11362
11369
|
stdout: Buffer.concat(stdoutBuf).toString("utf8"),
|
|
@@ -11422,10 +11429,10 @@ function cursorCredentialLocator() {
|
|
|
11422
11429
|
extract: extractLocalCursorToken
|
|
11423
11430
|
};
|
|
11424
11431
|
}
|
|
11425
|
-
function cursorLoginLauncher(
|
|
11432
|
+
function cursorLoginLauncher(os30) {
|
|
11426
11433
|
return {
|
|
11427
11434
|
async ensureInstalled() {
|
|
11428
|
-
if (
|
|
11435
|
+
if (os30.findInPath("cursor-agent")) return true;
|
|
11429
11436
|
console.error(
|
|
11430
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"
|
|
11431
11438
|
);
|
|
@@ -11487,8 +11494,8 @@ var CursorRuntimeStrategy = class {
|
|
|
11487
11494
|
meta = getAgent("cursor");
|
|
11488
11495
|
mode = "interactive";
|
|
11489
11496
|
os;
|
|
11490
|
-
constructor(
|
|
11491
|
-
this.os =
|
|
11497
|
+
constructor(os30) {
|
|
11498
|
+
this.os = os30;
|
|
11492
11499
|
}
|
|
11493
11500
|
async prepareLaunch() {
|
|
11494
11501
|
const binary = this.os.findInPath("cursor-agent");
|
|
@@ -11608,10 +11615,10 @@ function aiderCredentialLocator() {
|
|
|
11608
11615
|
extract: extractLocalAiderToken
|
|
11609
11616
|
};
|
|
11610
11617
|
}
|
|
11611
|
-
function aiderLoginLauncher(
|
|
11618
|
+
function aiderLoginLauncher(os30) {
|
|
11612
11619
|
return {
|
|
11613
11620
|
async ensureInstalled() {
|
|
11614
|
-
if (
|
|
11621
|
+
if (os30.findInPath("aider")) return true;
|
|
11615
11622
|
console.error(
|
|
11616
11623
|
"\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
|
|
11617
11624
|
);
|
|
@@ -11621,7 +11628,7 @@ function aiderLoginLauncher(os29) {
|
|
|
11621
11628
|
console.error(
|
|
11622
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"
|
|
11623
11630
|
);
|
|
11624
|
-
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"], {
|
|
11625
11632
|
stdio: "ignore"
|
|
11626
11633
|
});
|
|
11627
11634
|
}
|
|
@@ -11693,8 +11700,8 @@ var AiderRuntimeStrategy = class {
|
|
|
11693
11700
|
meta = getAgent("aider");
|
|
11694
11701
|
mode = "interactive";
|
|
11695
11702
|
os;
|
|
11696
|
-
constructor(
|
|
11697
|
-
this.os =
|
|
11703
|
+
constructor(os30) {
|
|
11704
|
+
this.os = os30;
|
|
11698
11705
|
}
|
|
11699
11706
|
async prepareLaunch() {
|
|
11700
11707
|
const binary = this.os.findInPath("aider");
|
|
@@ -11823,8 +11830,8 @@ function geminiCredentialLocator() {
|
|
|
11823
11830
|
function geminiLoginLauncher() {
|
|
11824
11831
|
return {
|
|
11825
11832
|
async ensureInstalled() {
|
|
11826
|
-
const
|
|
11827
|
-
return
|
|
11833
|
+
const os30 = createOsStrategy();
|
|
11834
|
+
return os30.findInPath("gemini") !== null;
|
|
11828
11835
|
},
|
|
11829
11836
|
launch() {
|
|
11830
11837
|
return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
|
|
@@ -11857,8 +11864,8 @@ var GeminiRuntimeStrategy = class {
|
|
|
11857
11864
|
meta = getAgent("gemini");
|
|
11858
11865
|
mode = "interactive";
|
|
11859
11866
|
os;
|
|
11860
|
-
constructor(
|
|
11861
|
-
this.os =
|
|
11867
|
+
constructor(os30) {
|
|
11868
|
+
this.os = os30;
|
|
11862
11869
|
}
|
|
11863
11870
|
async prepareLaunch() {
|
|
11864
11871
|
const binary = this.os.findInPath("gemini");
|
|
@@ -11958,18 +11965,18 @@ var GeminiRuntimeStrategy = class {
|
|
|
11958
11965
|
|
|
11959
11966
|
// src/agents/registry.ts
|
|
11960
11967
|
var runtimeBuilders = {
|
|
11961
|
-
claude: (
|
|
11962
|
-
codex: (
|
|
11963
|
-
coderabbit: (
|
|
11964
|
-
cursor: (
|
|
11965
|
-
aider: (
|
|
11966
|
-
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)
|
|
11967
11974
|
};
|
|
11968
11975
|
var deployBuilders = {
|
|
11969
11976
|
claude: () => new ClaudeDeployStrategy(),
|
|
11970
11977
|
codex: () => new CodexDeployStrategy()
|
|
11971
11978
|
};
|
|
11972
|
-
function createAgentStrategy(agent,
|
|
11979
|
+
function createAgentStrategy(agent, os30 = createOsStrategy()) {
|
|
11973
11980
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
11974
11981
|
throw new Error(
|
|
11975
11982
|
`Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
|
|
@@ -11979,10 +11986,10 @@ function createAgentStrategy(agent, os29 = createOsStrategy()) {
|
|
|
11979
11986
|
if (!build) {
|
|
11980
11987
|
throw new Error(`No runtime strategy registered for agent "${agent}"`);
|
|
11981
11988
|
}
|
|
11982
|
-
return build(
|
|
11989
|
+
return build(os30);
|
|
11983
11990
|
}
|
|
11984
|
-
function createInteractiveAgentStrategy(agent,
|
|
11985
|
-
const s = createAgentStrategy(agent,
|
|
11991
|
+
function createInteractiveAgentStrategy(agent, os30 = createOsStrategy()) {
|
|
11992
|
+
const s = createAgentStrategy(agent, os30);
|
|
11986
11993
|
if (s.mode !== "interactive") {
|
|
11987
11994
|
throw new Error(
|
|
11988
11995
|
`Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
|
|
@@ -14262,8 +14269,8 @@ var Connection = class {
|
|
|
14262
14269
|
this.requestHandler = requestHandler;
|
|
14263
14270
|
this.notificationHandler = notificationHandler;
|
|
14264
14271
|
this.stream = stream;
|
|
14265
|
-
this.closedPromise = new Promise((
|
|
14266
|
-
this.abortController.signal.addEventListener("abort", () =>
|
|
14272
|
+
this.closedPromise = new Promise((resolve7) => {
|
|
14273
|
+
this.abortController.signal.addEventListener("abort", () => resolve7());
|
|
14267
14274
|
});
|
|
14268
14275
|
void this.receive();
|
|
14269
14276
|
}
|
|
@@ -14433,11 +14440,11 @@ var Connection = class {
|
|
|
14433
14440
|
return rejectedPromise(this.closedReason());
|
|
14434
14441
|
}
|
|
14435
14442
|
const id = this.nextRequestId++;
|
|
14436
|
-
const responsePromise = new Promise((
|
|
14443
|
+
const responsePromise = new Promise((resolve7, reject) => {
|
|
14437
14444
|
this.pendingResponses.set(id, {
|
|
14438
14445
|
resolve: (response) => {
|
|
14439
14446
|
try {
|
|
14440
|
-
|
|
14447
|
+
resolve7(mapResponse ? mapResponse(response) : response);
|
|
14441
14448
|
} catch (error) {
|
|
14442
14449
|
reject(error);
|
|
14443
14450
|
}
|
|
@@ -14758,17 +14765,17 @@ var AcpClient = class {
|
|
|
14758
14765
|
this.sessionId = null;
|
|
14759
14766
|
try {
|
|
14760
14767
|
child.kill("SIGTERM");
|
|
14761
|
-
const grace = new Promise((
|
|
14768
|
+
const grace = new Promise((resolve7) => {
|
|
14762
14769
|
const t2 = setTimeout(() => {
|
|
14763
14770
|
try {
|
|
14764
14771
|
child.kill("SIGKILL");
|
|
14765
14772
|
} catch {
|
|
14766
14773
|
}
|
|
14767
|
-
|
|
14774
|
+
resolve7();
|
|
14768
14775
|
}, 2e3);
|
|
14769
14776
|
child.once("exit", () => {
|
|
14770
14777
|
clearTimeout(t2);
|
|
14771
|
-
|
|
14778
|
+
resolve7();
|
|
14772
14779
|
});
|
|
14773
14780
|
});
|
|
14774
14781
|
await grace;
|
|
@@ -14906,7 +14913,7 @@ var _transport2 = {
|
|
|
14906
14913
|
get: _get
|
|
14907
14914
|
};
|
|
14908
14915
|
function _post(url, headers, payload) {
|
|
14909
|
-
return new Promise((
|
|
14916
|
+
return new Promise((resolve7, reject) => {
|
|
14910
14917
|
let settled = false;
|
|
14911
14918
|
const u2 = new URL(url);
|
|
14912
14919
|
const lib = u2.protocol === "https:" ? https3 : http3;
|
|
@@ -14931,7 +14938,7 @@ function _post(url, headers, payload) {
|
|
|
14931
14938
|
res.on("end", () => {
|
|
14932
14939
|
if (settled) return;
|
|
14933
14940
|
settled = true;
|
|
14934
|
-
|
|
14941
|
+
resolve7({ statusCode: res.statusCode ?? 0, body });
|
|
14935
14942
|
});
|
|
14936
14943
|
}
|
|
14937
14944
|
);
|
|
@@ -14948,7 +14955,7 @@ function _post(url, headers, payload) {
|
|
|
14948
14955
|
});
|
|
14949
14956
|
}
|
|
14950
14957
|
function _get(url, headers) {
|
|
14951
|
-
return new Promise((
|
|
14958
|
+
return new Promise((resolve7, reject) => {
|
|
14952
14959
|
let settled = false;
|
|
14953
14960
|
const u2 = new URL(url);
|
|
14954
14961
|
const lib = u2.protocol === "https:" ? https3 : http3;
|
|
@@ -14972,7 +14979,7 @@ function _get(url, headers) {
|
|
|
14972
14979
|
res.on("end", () => {
|
|
14973
14980
|
if (settled) return;
|
|
14974
14981
|
settled = true;
|
|
14975
|
-
|
|
14982
|
+
resolve7({ statusCode: res.statusCode ?? 0, body });
|
|
14976
14983
|
});
|
|
14977
14984
|
}
|
|
14978
14985
|
);
|
|
@@ -15681,11 +15688,11 @@ function extractSelectPrompt(text) {
|
|
|
15681
15688
|
}
|
|
15682
15689
|
|
|
15683
15690
|
// src/commands/start/handlers.ts
|
|
15684
|
-
var
|
|
15685
|
-
var
|
|
15686
|
-
var
|
|
15691
|
+
var fs31 = __toESM(require("fs"));
|
|
15692
|
+
var os25 = __toESM(require("os"));
|
|
15693
|
+
var path38 = __toESM(require("path"));
|
|
15687
15694
|
var import_crypto3 = require("crypto");
|
|
15688
|
-
var
|
|
15695
|
+
var import_child_process15 = require("child_process");
|
|
15689
15696
|
|
|
15690
15697
|
// src/lib/payload.ts
|
|
15691
15698
|
var import_zod = require("zod");
|
|
@@ -16338,12 +16345,12 @@ async function applyFileReview(workingDir, filePath, action) {
|
|
|
16338
16345
|
return { ok: true, action, filePath, repoRoot };
|
|
16339
16346
|
}
|
|
16340
16347
|
function runGit(cwd, args2) {
|
|
16341
|
-
return new Promise((
|
|
16348
|
+
return new Promise((resolve7) => {
|
|
16342
16349
|
let proc;
|
|
16343
16350
|
try {
|
|
16344
16351
|
proc = (0, import_child_process10.spawn)("git", args2, { cwd, env: process.env });
|
|
16345
16352
|
} catch (err) {
|
|
16346
|
-
|
|
16353
|
+
resolve7({ ok: false, code: -1, stdout: "", stderr: err.message });
|
|
16347
16354
|
return;
|
|
16348
16355
|
}
|
|
16349
16356
|
let stdout = "";
|
|
@@ -16356,11 +16363,11 @@ function runGit(cwd, args2) {
|
|
|
16356
16363
|
});
|
|
16357
16364
|
proc.on(
|
|
16358
16365
|
"error",
|
|
16359
|
-
(err) =>
|
|
16366
|
+
(err) => resolve7({ ok: false, code: -1, stdout, stderr: stderr + err.message })
|
|
16360
16367
|
);
|
|
16361
16368
|
proc.on(
|
|
16362
16369
|
"close",
|
|
16363
|
-
(code) =>
|
|
16370
|
+
(code) => resolve7({ ok: code === 0, code: code ?? -1, stdout, stderr })
|
|
16364
16371
|
);
|
|
16365
16372
|
});
|
|
16366
16373
|
}
|
|
@@ -16619,7 +16626,7 @@ async function link(args2 = []) {
|
|
|
16619
16626
|
waitSpin.start(waitMsg());
|
|
16620
16627
|
const countdown = setInterval(() => waitSpin.message(waitMsg()), 1e3);
|
|
16621
16628
|
countdown.unref?.();
|
|
16622
|
-
const paired = await new Promise((
|
|
16629
|
+
const paired = await new Promise((resolve7, reject) => {
|
|
16623
16630
|
let stopPoll = null;
|
|
16624
16631
|
const sigint = () => {
|
|
16625
16632
|
clearInterval(countdown);
|
|
@@ -16632,7 +16639,7 @@ async function link(args2 = []) {
|
|
|
16632
16639
|
process.removeListener("SIGINT", sigint);
|
|
16633
16640
|
clearInterval(countdown);
|
|
16634
16641
|
waitSpin.stop("Paired");
|
|
16635
|
-
|
|
16642
|
+
resolve7(info);
|
|
16636
16643
|
},
|
|
16637
16644
|
() => {
|
|
16638
16645
|
clearInterval(countdown);
|
|
@@ -16767,14 +16774,14 @@ async function captureFreshCredentials(ctx) {
|
|
|
16767
16774
|
}
|
|
16768
16775
|
};
|
|
16769
16776
|
try {
|
|
16770
|
-
const token = await new Promise((
|
|
16777
|
+
const token = await new Promise((resolve7, reject) => {
|
|
16771
16778
|
let settled = false;
|
|
16772
16779
|
const tryExtract = async () => {
|
|
16773
16780
|
if (settled) return;
|
|
16774
16781
|
const t2 = await ctx.locator.extract();
|
|
16775
16782
|
if (t2 && !settled) {
|
|
16776
16783
|
settled = true;
|
|
16777
|
-
|
|
16784
|
+
resolve7(t2);
|
|
16778
16785
|
}
|
|
16779
16786
|
};
|
|
16780
16787
|
watcher.on("add", () => void tryExtract());
|
|
@@ -17172,12 +17179,758 @@ function activePreviewSessionIds() {
|
|
|
17172
17179
|
return Array.from(activePreviews.keys());
|
|
17173
17180
|
}
|
|
17174
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
|
+
|
|
17175
17928
|
// src/commands/start/handlers.ts
|
|
17176
17929
|
var pendingAttachmentFiles = /* @__PURE__ */ new Set();
|
|
17177
17930
|
function cleanupAttachmentTempFiles() {
|
|
17178
17931
|
for (const p2 of pendingAttachmentFiles) {
|
|
17179
17932
|
try {
|
|
17180
|
-
|
|
17933
|
+
fs31.unlinkSync(p2);
|
|
17181
17934
|
} catch {
|
|
17182
17935
|
}
|
|
17183
17936
|
}
|
|
@@ -17186,8 +17939,8 @@ function cleanupAttachmentTempFiles() {
|
|
|
17186
17939
|
function saveFilesTemp(files) {
|
|
17187
17940
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
17188
17941
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
17189
|
-
const tmpPath =
|
|
17190
|
-
|
|
17942
|
+
const tmpPath = path38.join(os25.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
|
|
17943
|
+
fs31.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
17191
17944
|
pendingAttachmentFiles.add(tmpPath);
|
|
17192
17945
|
return tmpPath;
|
|
17193
17946
|
});
|
|
@@ -17207,7 +17960,7 @@ var startTask = (ctx, _cmd, parsed) => {
|
|
|
17207
17960
|
setTimeout(() => {
|
|
17208
17961
|
for (const p2 of paths) {
|
|
17209
17962
|
try {
|
|
17210
|
-
|
|
17963
|
+
fs31.unlinkSync(p2);
|
|
17211
17964
|
} catch {
|
|
17212
17965
|
}
|
|
17213
17966
|
pendingAttachmentFiles.delete(p2);
|
|
@@ -17332,7 +18085,7 @@ var sessionTerminated = async (ctx, cmd) => {
|
|
|
17332
18085
|
} catch {
|
|
17333
18086
|
}
|
|
17334
18087
|
try {
|
|
17335
|
-
const proc = (0,
|
|
18088
|
+
const proc = (0, import_child_process15.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
17336
18089
|
detached: true,
|
|
17337
18090
|
stdio: "ignore"
|
|
17338
18091
|
});
|
|
@@ -17354,7 +18107,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
17354
18107
|
}
|
|
17355
18108
|
if (ctx.keepAliveCtx.inCodespace && ctx.keepAliveCtx.codespaceName) {
|
|
17356
18109
|
try {
|
|
17357
|
-
const stopProc = (0,
|
|
18110
|
+
const stopProc = (0, import_child_process15.spawn)(
|
|
17358
18111
|
"bash",
|
|
17359
18112
|
["-lc", `sleep 1; gh codespace stop -c ${JSON.stringify(ctx.keepAliveCtx.codespaceName)} >/dev/null 2>&1 || true`],
|
|
17360
18113
|
{ detached: true, stdio: "ignore" }
|
|
@@ -17364,7 +18117,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
17364
18117
|
}
|
|
17365
18118
|
}
|
|
17366
18119
|
try {
|
|
17367
|
-
const proc = (0,
|
|
18120
|
+
const proc = (0, import_child_process15.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
17368
18121
|
detached: true,
|
|
17369
18122
|
stdio: "ignore"
|
|
17370
18123
|
});
|
|
@@ -17780,8 +18533,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
|
|
|
17780
18533
|
if (args2.length === 0) return detection;
|
|
17781
18534
|
const binName = args2[0];
|
|
17782
18535
|
if (binName.startsWith("-")) return detection;
|
|
17783
|
-
const binPath =
|
|
17784
|
-
if (!
|
|
18536
|
+
const binPath = path38.join(cwd, "node_modules", ".bin", binName);
|
|
18537
|
+
if (!fs31.existsSync(binPath)) return detection;
|
|
17785
18538
|
return {
|
|
17786
18539
|
...detection,
|
|
17787
18540
|
command: binPath,
|
|
@@ -17871,7 +18624,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
17871
18624
|
"BOOT_SEQUENCE",
|
|
17872
18625
|
`${spawnable.command} ${spawnable.args.join(" ")}`
|
|
17873
18626
|
);
|
|
17874
|
-
const devServer = (0,
|
|
18627
|
+
const devServer = (0, import_child_process15.spawn)(spawnable.command, spawnable.args, {
|
|
17875
18628
|
cwd: process.cwd(),
|
|
17876
18629
|
env: { ...process.env, ...spawnable.env ?? {} },
|
|
17877
18630
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -17997,7 +18750,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
17997
18750
|
});
|
|
17998
18751
|
return;
|
|
17999
18752
|
}
|
|
18000
|
-
tunnel = (0,
|
|
18753
|
+
tunnel = (0, import_child_process15.spawn)(bin, ["tunnel", "--url", `http://localhost:${detection.port}`], {
|
|
18001
18754
|
stdio: ["ignore", "pipe", "pipe"]
|
|
18002
18755
|
});
|
|
18003
18756
|
let parsedUrl = null;
|
|
@@ -18094,8 +18847,8 @@ var previewStopH = (ctx) => {
|
|
|
18094
18847
|
})();
|
|
18095
18848
|
};
|
|
18096
18849
|
function runOnce(cmd, args2, cwd, env) {
|
|
18097
|
-
return new Promise((
|
|
18098
|
-
const child = (0,
|
|
18850
|
+
return new Promise((resolve7) => {
|
|
18851
|
+
const child = (0, import_child_process15.spawn)(cmd, args2, {
|
|
18099
18852
|
cwd,
|
|
18100
18853
|
env: { ...process.env, ...env ?? {} },
|
|
18101
18854
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -18108,8 +18861,8 @@ function runOnce(cmd, args2, cwd, env) {
|
|
|
18108
18861
|
};
|
|
18109
18862
|
child.stdout?.on("data", onChunk);
|
|
18110
18863
|
child.stderr?.on("data", onChunk);
|
|
18111
|
-
child.once("exit", (code) =>
|
|
18112
|
-
child.once("error", () =>
|
|
18864
|
+
child.once("exit", (code) => resolve7(code));
|
|
18865
|
+
child.once("error", () => resolve7(-1));
|
|
18113
18866
|
});
|
|
18114
18867
|
}
|
|
18115
18868
|
var savePreviewConfigH = (_ctx, _cmd, parsed) => {
|
|
@@ -18163,6 +18916,23 @@ var handlers = {
|
|
|
18163
18916
|
save_preview_config: savePreviewConfigH
|
|
18164
18917
|
};
|
|
18165
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
|
+
}
|
|
18166
18936
|
const parsed = parsePayload2(startCommandSchema, cmd.payload);
|
|
18167
18937
|
if (!parsed) {
|
|
18168
18938
|
showInfo(`Ignoring malformed ${cmd.type} payload.`);
|
|
@@ -18174,10 +18944,10 @@ async function dispatchCommand(ctx, cmd) {
|
|
|
18174
18944
|
}
|
|
18175
18945
|
|
|
18176
18946
|
// src/services/file-watcher.service.ts
|
|
18177
|
-
var
|
|
18178
|
-
var
|
|
18179
|
-
var
|
|
18180
|
-
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"));
|
|
18181
18951
|
var import_ignore = __toESM(require("ignore"));
|
|
18182
18952
|
|
|
18183
18953
|
// src/services/file-watcher/diff-parser.ts
|
|
@@ -18266,58 +19036,9 @@ function isIgnoredFilePath(filePath) {
|
|
|
18266
19036
|
return IGNORED_PATH_PATTERN.test(filePath);
|
|
18267
19037
|
}
|
|
18268
19038
|
|
|
18269
|
-
// src/services/file-watcher/transport.ts
|
|
18270
|
-
var http5 = __toESM(require("http"));
|
|
18271
|
-
var https5 = __toESM(require("https"));
|
|
18272
|
-
var _transport3 = {
|
|
18273
|
-
post: _post2
|
|
18274
|
-
};
|
|
18275
|
-
function _post2(url, headers, payload) {
|
|
18276
|
-
return new Promise((resolve6, reject) => {
|
|
18277
|
-
let settled = false;
|
|
18278
|
-
const u2 = new URL(url);
|
|
18279
|
-
const lib = u2.protocol === "https:" ? https5 : http5;
|
|
18280
|
-
const req = lib.request(
|
|
18281
|
-
{
|
|
18282
|
-
hostname: u2.hostname,
|
|
18283
|
-
port: u2.port || (u2.protocol === "https:" ? 443 : 80),
|
|
18284
|
-
path: u2.pathname + u2.search,
|
|
18285
|
-
method: "POST",
|
|
18286
|
-
headers: {
|
|
18287
|
-
...headers,
|
|
18288
|
-
...vercelBypassHeader(),
|
|
18289
|
-
"Content-Length": Buffer.byteLength(payload)
|
|
18290
|
-
},
|
|
18291
|
-
timeout: 8e3
|
|
18292
|
-
},
|
|
18293
|
-
(res) => {
|
|
18294
|
-
let body = "";
|
|
18295
|
-
res.on("data", (c2) => {
|
|
18296
|
-
body += c2.toString();
|
|
18297
|
-
});
|
|
18298
|
-
res.on("end", () => {
|
|
18299
|
-
if (settled) return;
|
|
18300
|
-
settled = true;
|
|
18301
|
-
resolve6({ statusCode: res.statusCode ?? 0, body });
|
|
18302
|
-
});
|
|
18303
|
-
}
|
|
18304
|
-
);
|
|
18305
|
-
req.on("error", (err) => {
|
|
18306
|
-
if (settled) return;
|
|
18307
|
-
settled = true;
|
|
18308
|
-
reject(err);
|
|
18309
|
-
});
|
|
18310
|
-
req.on("timeout", () => {
|
|
18311
|
-
req.destroy();
|
|
18312
|
-
});
|
|
18313
|
-
req.write(payload);
|
|
18314
|
-
req.end();
|
|
18315
|
-
});
|
|
18316
|
-
}
|
|
18317
|
-
|
|
18318
19039
|
// src/services/file-watcher.service.ts
|
|
18319
|
-
var
|
|
18320
|
-
var
|
|
19040
|
+
var API_BASE5 = resolveApiBaseUrl();
|
|
19041
|
+
var DEBOUNCE_MS2 = 250;
|
|
18321
19042
|
var COALESCE_WINDOW_MS = 250;
|
|
18322
19043
|
var COALESCE_MAX_HOLD_MS = 2e3;
|
|
18323
19044
|
var MAX_RETRIES = 2;
|
|
@@ -18336,10 +19057,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
|
|
|
18336
19057
|
/[\\/]Start Menu([\\/]|$)/i,
|
|
18337
19058
|
/[\\/]Templates([\\/]|$)/i
|
|
18338
19059
|
];
|
|
18339
|
-
function isUnsafeWindowsWatchRoot(dir,
|
|
19060
|
+
function isUnsafeWindowsWatchRoot(dir, homedir22) {
|
|
18340
19061
|
const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
|
|
18341
19062
|
const cwd = norm(dir);
|
|
18342
|
-
const home = norm(
|
|
19063
|
+
const home = norm(homedir22);
|
|
18343
19064
|
if (cwd === home) return true;
|
|
18344
19065
|
if (/^[a-z]:$/.test(cwd)) return true;
|
|
18345
19066
|
const sysRoots = [
|
|
@@ -18353,7 +19074,7 @@ function isUnsafeWindowsWatchRoot(dir, homedir21) {
|
|
|
18353
19074
|
}
|
|
18354
19075
|
return false;
|
|
18355
19076
|
}
|
|
18356
|
-
var
|
|
19077
|
+
var _chokidarSeam2 = {
|
|
18357
19078
|
load: () => {
|
|
18358
19079
|
try {
|
|
18359
19080
|
return require("chokidar");
|
|
@@ -18369,18 +19090,18 @@ var _findGitRootSeam = {
|
|
|
18369
19090
|
resolve: _defaultFindGitRoot
|
|
18370
19091
|
};
|
|
18371
19092
|
function _defaultFindGitRoot(startDir) {
|
|
18372
|
-
let dir =
|
|
19093
|
+
let dir = path39.resolve(startDir);
|
|
18373
19094
|
const seen = /* @__PURE__ */ new Set();
|
|
18374
19095
|
for (let i = 0; i < 256; i++) {
|
|
18375
19096
|
if (seen.has(dir)) return null;
|
|
18376
19097
|
seen.add(dir);
|
|
18377
19098
|
try {
|
|
18378
|
-
const gitPath =
|
|
18379
|
-
const stat3 =
|
|
19099
|
+
const gitPath = path39.join(dir, ".git");
|
|
19100
|
+
const stat3 = fs32.statSync(gitPath, { throwIfNoEntry: false });
|
|
18380
19101
|
if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
|
|
18381
19102
|
} catch {
|
|
18382
19103
|
}
|
|
18383
|
-
const parent =
|
|
19104
|
+
const parent = path39.dirname(dir);
|
|
18384
19105
|
if (parent === dir) return null;
|
|
18385
19106
|
dir = parent;
|
|
18386
19107
|
}
|
|
@@ -18389,7 +19110,7 @@ function _defaultFindGitRoot(startDir) {
|
|
|
18389
19110
|
var FileWatcherService = class {
|
|
18390
19111
|
constructor(opts) {
|
|
18391
19112
|
this.opts = opts;
|
|
18392
|
-
this.apiBase = opts.apiBaseUrl ??
|
|
19113
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE5;
|
|
18393
19114
|
}
|
|
18394
19115
|
opts;
|
|
18395
19116
|
watcher = null;
|
|
@@ -18438,14 +19159,14 @@ var FileWatcherService = class {
|
|
|
18438
19159
|
throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
|
|
18439
19160
|
}
|
|
18440
19161
|
const isWin = process.platform === "win32";
|
|
18441
|
-
if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir,
|
|
19162
|
+
if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os26.homedir())) {
|
|
18442
19163
|
log.warn(
|
|
18443
19164
|
"fileWatcher",
|
|
18444
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.`
|
|
18445
19166
|
);
|
|
18446
19167
|
return;
|
|
18447
19168
|
}
|
|
18448
|
-
const chokidar2 =
|
|
19169
|
+
const chokidar2 = _chokidarSeam2.load();
|
|
18449
19170
|
if (!chokidar2) {
|
|
18450
19171
|
log.warn(
|
|
18451
19172
|
"fileWatcher",
|
|
@@ -18564,7 +19285,7 @@ var FileWatcherService = class {
|
|
|
18564
19285
|
const timer = setTimeout(() => {
|
|
18565
19286
|
this.pending.delete(absPath);
|
|
18566
19287
|
this.enqueueForCoalesce(absPath, changeType);
|
|
18567
|
-
},
|
|
19288
|
+
}, DEBOUNCE_MS2);
|
|
18568
19289
|
this.pending.set(absPath, {
|
|
18569
19290
|
lastEventAt: Date.now(),
|
|
18570
19291
|
timer,
|
|
@@ -18625,7 +19346,7 @@ var FileWatcherService = class {
|
|
|
18625
19346
|
}
|
|
18626
19347
|
async emitForFile(absPath, changeType) {
|
|
18627
19348
|
if (this.stopped) return;
|
|
18628
|
-
const fileDir =
|
|
19349
|
+
const fileDir = path39.dirname(absPath);
|
|
18629
19350
|
let gitRoot = this.gitRootByDir.get(fileDir);
|
|
18630
19351
|
if (gitRoot === void 0) {
|
|
18631
19352
|
gitRoot = findGitRoot2(fileDir);
|
|
@@ -18638,19 +19359,19 @@ var FileWatcherService = class {
|
|
|
18638
19359
|
);
|
|
18639
19360
|
return;
|
|
18640
19361
|
}
|
|
18641
|
-
const relPathInRepo =
|
|
19362
|
+
const relPathInRepo = path39.relative(gitRoot, absPath);
|
|
18642
19363
|
if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
|
|
18643
19364
|
const matcher = this.getGitIgnoreMatcher(gitRoot);
|
|
18644
19365
|
if (matcher && matcher.ignores(relPathInRepo)) {
|
|
18645
19366
|
log.trace(
|
|
18646
19367
|
"fileWatcher",
|
|
18647
|
-
`${relPathInRepo} ignored by ${
|
|
19368
|
+
`${relPathInRepo} ignored by ${path39.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
|
|
18648
19369
|
);
|
|
18649
19370
|
return;
|
|
18650
19371
|
}
|
|
18651
19372
|
this.opts.onRepoDirty?.(gitRoot);
|
|
18652
|
-
const repoPath =
|
|
18653
|
-
const repoName =
|
|
19373
|
+
const repoPath = path39.relative(this.opts.workingDir, gitRoot);
|
|
19374
|
+
const repoName = path39.basename(gitRoot);
|
|
18654
19375
|
let diffText = "";
|
|
18655
19376
|
let fileStatus = "modified";
|
|
18656
19377
|
if (changeType === "unlink") {
|
|
@@ -18825,7 +19546,7 @@ var FileWatcherService = class {
|
|
|
18825
19546
|
collectGitignoreFiles(repoRoot, dir, matcher) {
|
|
18826
19547
|
let entries;
|
|
18827
19548
|
try {
|
|
18828
|
-
entries =
|
|
19549
|
+
entries = fs32.readdirSync(dir, { withFileTypes: true });
|
|
18829
19550
|
} catch {
|
|
18830
19551
|
return;
|
|
18831
19552
|
}
|
|
@@ -18834,16 +19555,16 @@ var FileWatcherService = class {
|
|
|
18834
19555
|
);
|
|
18835
19556
|
if (gitignoreEntry) {
|
|
18836
19557
|
try {
|
|
18837
|
-
const body =
|
|
18838
|
-
const rel =
|
|
19558
|
+
const body = fs32.readFileSync(path39.join(dir, ".gitignore"), "utf8");
|
|
19559
|
+
const rel = path39.relative(repoRoot, dir).replace(/\\/g, "/");
|
|
18839
19560
|
const prefixed = body.split(/\r?\n/).map((line) => {
|
|
18840
19561
|
const trimmed = line.trim();
|
|
18841
19562
|
if (!trimmed || trimmed.startsWith("#")) return line;
|
|
18842
19563
|
if (!rel) return line;
|
|
18843
19564
|
if (trimmed.startsWith("!")) {
|
|
18844
|
-
return "!" +
|
|
19565
|
+
return "!" + path39.posix.join(rel, trimmed.slice(1));
|
|
18845
19566
|
}
|
|
18846
|
-
return
|
|
19567
|
+
return path39.posix.join(rel, trimmed);
|
|
18847
19568
|
}).join("\n");
|
|
18848
19569
|
matcher.add(prefixed);
|
|
18849
19570
|
} catch {
|
|
@@ -18852,7 +19573,7 @@ var FileWatcherService = class {
|
|
|
18852
19573
|
for (const entry of entries) {
|
|
18853
19574
|
if (!entry.isDirectory()) continue;
|
|
18854
19575
|
if (entry.name === ".git") continue;
|
|
18855
|
-
const childAbs =
|
|
19576
|
+
const childAbs = path39.join(dir, entry.name);
|
|
18856
19577
|
if (isIgnoredFilePath(childAbs)) continue;
|
|
18857
19578
|
this.collectGitignoreFiles(repoRoot, childAbs, matcher);
|
|
18858
19579
|
}
|
|
@@ -18986,12 +19707,12 @@ var _gitSeam = {
|
|
|
18986
19707
|
run: _runGitImpl
|
|
18987
19708
|
};
|
|
18988
19709
|
async function _runGitImpl(cwd, args2, opts = {}) {
|
|
18989
|
-
return new Promise((
|
|
19710
|
+
return new Promise((resolve7) => {
|
|
18990
19711
|
let proc;
|
|
18991
19712
|
try {
|
|
18992
|
-
proc = (0,
|
|
19713
|
+
proc = (0, import_child_process16.spawn)("git", args2, { cwd, env: process.env });
|
|
18993
19714
|
} catch {
|
|
18994
|
-
|
|
19715
|
+
resolve7(null);
|
|
18995
19716
|
return;
|
|
18996
19717
|
}
|
|
18997
19718
|
let stdout = "";
|
|
@@ -19002,13 +19723,13 @@ async function _runGitImpl(cwd, args2, opts = {}) {
|
|
|
19002
19723
|
proc.stderr?.on("data", (c2) => {
|
|
19003
19724
|
stderr += c2.toString();
|
|
19004
19725
|
});
|
|
19005
|
-
proc.on("error", () =>
|
|
19726
|
+
proc.on("error", () => resolve7(null));
|
|
19006
19727
|
proc.on("close", (code) => {
|
|
19007
19728
|
if (code === 0 || opts.allowNonZeroExit) {
|
|
19008
|
-
|
|
19729
|
+
resolve7(stdout);
|
|
19009
19730
|
} else {
|
|
19010
19731
|
log.trace("fileWatcher", `git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`);
|
|
19011
|
-
|
|
19732
|
+
resolve7(null);
|
|
19012
19733
|
}
|
|
19013
19734
|
});
|
|
19014
19735
|
});
|
|
@@ -19021,8 +19742,8 @@ function _runGit(cwd, args2, opts = {}) {
|
|
|
19021
19742
|
var import_crypto4 = require("crypto");
|
|
19022
19743
|
|
|
19023
19744
|
// src/services/turn-files/git-changeset.ts
|
|
19024
|
-
var
|
|
19025
|
-
var
|
|
19745
|
+
var import_child_process17 = require("child_process");
|
|
19746
|
+
var path40 = __toESM(require("path"));
|
|
19026
19747
|
async function collectRepoChangeset(opts) {
|
|
19027
19748
|
const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
|
|
19028
19749
|
if (status2 === null) return null;
|
|
@@ -19102,12 +19823,12 @@ function runGit3(cwd, args2) {
|
|
|
19102
19823
|
return _runGitImpl2.run(cwd, args2);
|
|
19103
19824
|
}
|
|
19104
19825
|
function defaultRunGit(cwd, args2) {
|
|
19105
|
-
return new Promise((
|
|
19826
|
+
return new Promise((resolve7) => {
|
|
19106
19827
|
let proc;
|
|
19107
19828
|
try {
|
|
19108
|
-
proc = (0,
|
|
19829
|
+
proc = (0, import_child_process17.spawn)("git", args2, { cwd, env: process.env });
|
|
19109
19830
|
} catch {
|
|
19110
|
-
|
|
19831
|
+
resolve7(null);
|
|
19111
19832
|
return;
|
|
19112
19833
|
}
|
|
19113
19834
|
let stdout = "";
|
|
@@ -19118,22 +19839,22 @@ function defaultRunGit(cwd, args2) {
|
|
|
19118
19839
|
proc.stderr?.on("data", (c2) => {
|
|
19119
19840
|
stderr += c2.toString();
|
|
19120
19841
|
});
|
|
19121
|
-
proc.on("error", () =>
|
|
19842
|
+
proc.on("error", () => resolve7(null));
|
|
19122
19843
|
proc.on("close", (code) => {
|
|
19123
19844
|
if (code === 0) {
|
|
19124
|
-
|
|
19845
|
+
resolve7(stdout);
|
|
19125
19846
|
} else {
|
|
19126
19847
|
log.trace(
|
|
19127
19848
|
"turnFiles",
|
|
19128
19849
|
`git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`
|
|
19129
19850
|
);
|
|
19130
|
-
|
|
19851
|
+
resolve7(null);
|
|
19131
19852
|
}
|
|
19132
19853
|
});
|
|
19133
19854
|
});
|
|
19134
19855
|
}
|
|
19135
19856
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
19136
|
-
const
|
|
19857
|
+
const fs38 = await import("fs/promises");
|
|
19137
19858
|
const out2 = [];
|
|
19138
19859
|
await walk(workingDir, 0);
|
|
19139
19860
|
return out2;
|
|
@@ -19141,7 +19862,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
19141
19862
|
if (depth > maxDepth) return;
|
|
19142
19863
|
let entries = [];
|
|
19143
19864
|
try {
|
|
19144
|
-
const dirents = await
|
|
19865
|
+
const dirents = await fs38.readdir(dir, { withFileTypes: true });
|
|
19145
19866
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
19146
19867
|
} catch {
|
|
19147
19868
|
return;
|
|
@@ -19152,8 +19873,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
19152
19873
|
if (hasGit) {
|
|
19153
19874
|
out2.push({
|
|
19154
19875
|
repoRoot: dir,
|
|
19155
|
-
repoPath:
|
|
19156
|
-
repoName:
|
|
19876
|
+
repoPath: path40.relative(workingDir, dir),
|
|
19877
|
+
repoName: path40.basename(dir)
|
|
19157
19878
|
});
|
|
19158
19879
|
return;
|
|
19159
19880
|
}
|
|
@@ -19161,14 +19882,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
19161
19882
|
if (!entry.isDirectory) continue;
|
|
19162
19883
|
if (entry.name === "node_modules") continue;
|
|
19163
19884
|
if (entry.name === "dist" || entry.name === "build") continue;
|
|
19164
|
-
await walk(
|
|
19885
|
+
await walk(path40.join(dir, entry.name), depth + 1);
|
|
19165
19886
|
}
|
|
19166
19887
|
}
|
|
19167
19888
|
}
|
|
19168
19889
|
|
|
19169
19890
|
// src/services/turn-files/files-outbox.ts
|
|
19170
|
-
var
|
|
19171
|
-
var
|
|
19891
|
+
var fs33 = __toESM(require("fs/promises"));
|
|
19892
|
+
var path41 = __toESM(require("path"));
|
|
19172
19893
|
var import_os7 = require("os");
|
|
19173
19894
|
var HOME_OUTBOX_DIR = ".codeam/outbox";
|
|
19174
19895
|
var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -19201,16 +19922,16 @@ var FilesOutbox = class {
|
|
|
19201
19922
|
backoffIndex = 0;
|
|
19202
19923
|
stopped = false;
|
|
19203
19924
|
constructor(opts) {
|
|
19204
|
-
const base = opts.baseDir ??
|
|
19205
|
-
this.filePath =
|
|
19925
|
+
const base = opts.baseDir ?? path41.join(homeDir(), HOME_OUTBOX_DIR);
|
|
19926
|
+
this.filePath = path41.join(base, `${opts.sessionId}.jsonl`);
|
|
19206
19927
|
this.post = opts.post;
|
|
19207
19928
|
this.autoSchedule = opts.autoSchedule !== false;
|
|
19208
19929
|
}
|
|
19209
19930
|
/** Persist the entry to disk and trigger a flush. Returns once the
|
|
19210
19931
|
* line is durable on disk (not once the POST succeeds). */
|
|
19211
19932
|
async enqueue(entry) {
|
|
19212
|
-
await
|
|
19213
|
-
await
|
|
19933
|
+
await fs33.mkdir(path41.dirname(this.filePath), { recursive: true });
|
|
19934
|
+
await fs33.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
|
|
19214
19935
|
this.backoffIndex = 0;
|
|
19215
19936
|
if (this.autoSchedule) this.scheduleFlush(0);
|
|
19216
19937
|
}
|
|
@@ -19299,7 +20020,7 @@ var FilesOutbox = class {
|
|
|
19299
20020
|
async readAll() {
|
|
19300
20021
|
let raw = "";
|
|
19301
20022
|
try {
|
|
19302
|
-
raw = await
|
|
20023
|
+
raw = await fs33.readFile(this.filePath, "utf8");
|
|
19303
20024
|
} catch {
|
|
19304
20025
|
return [];
|
|
19305
20026
|
}
|
|
@@ -19323,12 +20044,12 @@ var FilesOutbox = class {
|
|
|
19323
20044
|
async rewrite(entries) {
|
|
19324
20045
|
const tmpPath = `${this.filePath}.${process.pid}.tmp`;
|
|
19325
20046
|
if (entries.length === 0) {
|
|
19326
|
-
await
|
|
20047
|
+
await fs33.unlink(this.filePath).catch(() => void 0);
|
|
19327
20048
|
return;
|
|
19328
20049
|
}
|
|
19329
20050
|
const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
19330
|
-
await
|
|
19331
|
-
await
|
|
20051
|
+
await fs33.writeFile(tmpPath, payload, "utf8");
|
|
20052
|
+
await fs33.rename(tmpPath, this.filePath);
|
|
19332
20053
|
}
|
|
19333
20054
|
};
|
|
19334
20055
|
function applyJitter(ms) {
|
|
@@ -19340,13 +20061,13 @@ function homeDir() {
|
|
|
19340
20061
|
}
|
|
19341
20062
|
|
|
19342
20063
|
// src/services/turn-files/turn-file-aggregator.ts
|
|
19343
|
-
var
|
|
20064
|
+
var API_BASE6 = resolveApiBaseUrl();
|
|
19344
20065
|
var ENDPOINT = "/api/files/batch";
|
|
19345
20066
|
var MAX_BATCH_SIZE = 1e3;
|
|
19346
20067
|
var TurnFileAggregator = class {
|
|
19347
20068
|
constructor(opts) {
|
|
19348
20069
|
this.opts = opts;
|
|
19349
|
-
this.apiBase = opts.apiBaseUrl ??
|
|
20070
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE6;
|
|
19350
20071
|
this.outbox = new FilesOutbox({
|
|
19351
20072
|
sessionId: opts.sessionId,
|
|
19352
20073
|
baseDir: opts.outboxDir,
|
|
@@ -19538,7 +20259,7 @@ var StreamingState = class {
|
|
|
19538
20259
|
* default-reject. Caller is the SDK's `onRequestPermission`.
|
|
19539
20260
|
*/
|
|
19540
20261
|
registerPermission(args2) {
|
|
19541
|
-
return new Promise((
|
|
20262
|
+
return new Promise((resolve7) => {
|
|
19542
20263
|
const timeoutTimer = setTimeout(() => {
|
|
19543
20264
|
if (this.pending?.kind === "permission" && this.pending.questionId === args2.questionId) {
|
|
19544
20265
|
log.warn(
|
|
@@ -19546,7 +20267,7 @@ var StreamingState = class {
|
|
|
19546
20267
|
`permission ${args2.questionId.slice(0, 8)} TTL expired \u2014 auto-cancel`
|
|
19547
20268
|
);
|
|
19548
20269
|
this.pending = null;
|
|
19549
|
-
|
|
20270
|
+
resolve7({ outcome: { outcome: "cancelled" } });
|
|
19550
20271
|
}
|
|
19551
20272
|
}, PERMISSION_TIMEOUT_MS);
|
|
19552
20273
|
this.pending = {
|
|
@@ -19554,7 +20275,7 @@ var StreamingState = class {
|
|
|
19554
20275
|
questionId: args2.questionId,
|
|
19555
20276
|
labels: args2.labels,
|
|
19556
20277
|
optionIdByLabel: args2.optionIdByLabel,
|
|
19557
|
-
resolve:
|
|
20278
|
+
resolve: resolve7,
|
|
19558
20279
|
timeoutTimer
|
|
19559
20280
|
};
|
|
19560
20281
|
});
|
|
@@ -19586,14 +20307,14 @@ var StreamingState = class {
|
|
|
19586
20307
|
const label = this.pending.labels[index];
|
|
19587
20308
|
const optionId = label ? this.pending.optionIdByLabel[label] : void 0;
|
|
19588
20309
|
clearTimeout(this.pending.timeoutTimer);
|
|
19589
|
-
const
|
|
20310
|
+
const resolve7 = this.pending.resolve;
|
|
19590
20311
|
this.pending = null;
|
|
19591
20312
|
if (!optionId) {
|
|
19592
20313
|
log.warn("acpRunner", `select_option index=${index} out of bounds \u2014 cancel`);
|
|
19593
|
-
|
|
20314
|
+
resolve7({ outcome: { outcome: "cancelled" } });
|
|
19594
20315
|
return { kind: "resolved" };
|
|
19595
20316
|
}
|
|
19596
|
-
|
|
20317
|
+
resolve7({ outcome: { outcome: "selected", optionId } });
|
|
19597
20318
|
return { kind: "resolved" };
|
|
19598
20319
|
}
|
|
19599
20320
|
const text = this.pending.options[index];
|
|
@@ -19895,6 +20616,7 @@ async function runAcpSession(opts) {
|
|
|
19895
20616
|
`adapter handshake ok protocolVersion=${initialize.protocolVersion} sessionId=${acpSessionId.slice(0, 8)}`
|
|
19896
20617
|
);
|
|
19897
20618
|
showSuccess(`${opts.agent} online (ACP) \u2014 awaiting prompts from mobile.`);
|
|
20619
|
+
showRelayNotice();
|
|
19898
20620
|
void publisher.publishOutput({
|
|
19899
20621
|
type: "agent_banner",
|
|
19900
20622
|
agentId: opts.agent,
|
|
@@ -19948,6 +20670,16 @@ async function runAcpSession(opts) {
|
|
|
19948
20670
|
}).catch((err) => {
|
|
19949
20671
|
log.warn("acpRunner", `fileWatcher.start failed: ${describeError(err)}`);
|
|
19950
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
|
+
});
|
|
19951
20683
|
const relay = new CommandRelayService(
|
|
19952
20684
|
opts.pluginId,
|
|
19953
20685
|
async (cmd) => {
|
|
@@ -19961,7 +20693,8 @@ async function runAcpSession(opts) {
|
|
|
19961
20693
|
opts,
|
|
19962
20694
|
history,
|
|
19963
20695
|
initialize.agentCapabilities,
|
|
19964
|
-
turnFiles
|
|
20696
|
+
turnFiles,
|
|
20697
|
+
() => beads
|
|
19965
20698
|
);
|
|
19966
20699
|
},
|
|
19967
20700
|
{ id: opts.agent, name: opts.agent, displayName: opts.agent }
|
|
@@ -19972,6 +20705,7 @@ async function runAcpSession(opts) {
|
|
|
19972
20705
|
relay.stop();
|
|
19973
20706
|
void fileWatcher.stop();
|
|
19974
20707
|
turnFiles.stop();
|
|
20708
|
+
void beads?.watcher.stop();
|
|
19975
20709
|
closeAllTerminals();
|
|
19976
20710
|
await client2.stop();
|
|
19977
20711
|
process.exit(0);
|
|
@@ -19982,8 +20716,24 @@ async function runAcpSession(opts) {
|
|
|
19982
20716
|
await new Promise(() => {
|
|
19983
20717
|
});
|
|
19984
20718
|
}
|
|
19985
|
-
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) {
|
|
19986
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
|
+
}
|
|
19987
20737
|
case "start_task": {
|
|
19988
20738
|
const payload = cmd.payload;
|
|
19989
20739
|
const blocks = buildAcpPromptBlocks(payload ?? {});
|
|
@@ -20342,11 +21092,11 @@ var ChromeStepTracker = class {
|
|
|
20342
21092
|
// src/services/output/chunk-emitter.ts
|
|
20343
21093
|
var https6 = __toESM(require("https"));
|
|
20344
21094
|
var http6 = __toESM(require("http"));
|
|
20345
|
-
var
|
|
21095
|
+
var API_BASE7 = resolveApiBaseUrl();
|
|
20346
21096
|
async function refreshAuthToken(sessionId, pluginId) {
|
|
20347
21097
|
try {
|
|
20348
21098
|
const { statusCode, body } = await _transport4.post(
|
|
20349
|
-
`${
|
|
21099
|
+
`${API_BASE7}/api/pairing/reconnect`,
|
|
20350
21100
|
{
|
|
20351
21101
|
"Content-Type": "application/json",
|
|
20352
21102
|
"X-Codeam-Protocol-Version": PROTOCOL_VERSION,
|
|
@@ -20387,7 +21137,7 @@ var ChunkEmitter = class {
|
|
|
20387
21137
|
}
|
|
20388
21138
|
}
|
|
20389
21139
|
opts;
|
|
20390
|
-
url = `${
|
|
21140
|
+
url = `${API_BASE7}/api/commands/output`;
|
|
20391
21141
|
headers;
|
|
20392
21142
|
/**
|
|
20393
21143
|
* Send a chunk. `body` is the chunk fields minus `sessionId` /
|
|
@@ -20408,14 +21158,14 @@ var ChunkEmitter = class {
|
|
|
20408
21158
|
"chunkEmitter",
|
|
20409
21159
|
`send type=${body.type ?? "(clear)"} bytes=${payload.length} done=${body.done === true}`
|
|
20410
21160
|
);
|
|
20411
|
-
return new Promise((
|
|
21161
|
+
return new Promise((resolve7) => {
|
|
20412
21162
|
const attempt = (attemptsLeft) => {
|
|
20413
21163
|
_transport4.post(this.url, this.headers, payload).then(({ statusCode, body: resBody }) => {
|
|
20414
21164
|
const tookMs = Date.now() - t0;
|
|
20415
21165
|
if (statusCode === 410 || statusCode === 404 && /SESSION_NOT_FOUND|SESSION_GONE/.test(resBody)) {
|
|
20416
21166
|
process.stderr.write("[codeam] session was deleted/disconnected \u2014 stopping output stream.\n");
|
|
20417
21167
|
log.info("chunkEmitter", `dead status=${statusCode} took=${tookMs}ms`);
|
|
20418
|
-
|
|
21168
|
+
resolve7({ dead: true });
|
|
20419
21169
|
return;
|
|
20420
21170
|
}
|
|
20421
21171
|
if (statusCode === 401) {
|
|
@@ -20431,7 +21181,7 @@ var ChunkEmitter = class {
|
|
|
20431
21181
|
return;
|
|
20432
21182
|
}
|
|
20433
21183
|
}
|
|
20434
|
-
|
|
21184
|
+
resolve7({ dead: false });
|
|
20435
21185
|
})();
|
|
20436
21186
|
return;
|
|
20437
21187
|
}
|
|
@@ -20442,7 +21192,7 @@ var ChunkEmitter = class {
|
|
|
20442
21192
|
} else {
|
|
20443
21193
|
log.info("chunkEmitter", `ok status=${statusCode} took=${tookMs}ms`);
|
|
20444
21194
|
}
|
|
20445
|
-
|
|
21195
|
+
resolve7({ dead: false });
|
|
20446
21196
|
}).catch((err) => {
|
|
20447
21197
|
log.warn(
|
|
20448
21198
|
"chunkEmitter",
|
|
@@ -20453,7 +21203,7 @@ var ChunkEmitter = class {
|
|
|
20453
21203
|
const delay = 200 * (maxRetries - attemptsLeft + 1);
|
|
20454
21204
|
setTimeout(() => attempt(attemptsLeft - 1), delay);
|
|
20455
21205
|
} else {
|
|
20456
|
-
|
|
21206
|
+
resolve7({ dead: false });
|
|
20457
21207
|
}
|
|
20458
21208
|
});
|
|
20459
21209
|
};
|
|
@@ -20465,7 +21215,7 @@ var _transport4 = {
|
|
|
20465
21215
|
post: _post3
|
|
20466
21216
|
};
|
|
20467
21217
|
function _post3(url, headers, payload) {
|
|
20468
|
-
return new Promise((
|
|
21218
|
+
return new Promise((resolve7, reject) => {
|
|
20469
21219
|
let settled = false;
|
|
20470
21220
|
const u2 = new URL(url);
|
|
20471
21221
|
const transport = u2.protocol === "https:" ? https6 : http6;
|
|
@@ -20489,7 +21239,7 @@ function _post3(url, headers, payload) {
|
|
|
20489
21239
|
res.on("end", () => {
|
|
20490
21240
|
if (settled) return;
|
|
20491
21241
|
settled = true;
|
|
20492
|
-
|
|
21242
|
+
resolve7({ statusCode: res.statusCode ?? 0, body: resData });
|
|
20493
21243
|
});
|
|
20494
21244
|
}
|
|
20495
21245
|
);
|
|
@@ -21063,9 +21813,9 @@ var OutputService = class _OutputService {
|
|
|
21063
21813
|
};
|
|
21064
21814
|
|
|
21065
21815
|
// src/services/history.service.ts
|
|
21066
|
-
var
|
|
21067
|
-
var
|
|
21068
|
-
var
|
|
21816
|
+
var fs34 = __toESM(require("fs"));
|
|
21817
|
+
var path42 = __toESM(require("path"));
|
|
21818
|
+
var os27 = __toESM(require("os"));
|
|
21069
21819
|
var https7 = __toESM(require("https"));
|
|
21070
21820
|
var http7 = __toESM(require("http"));
|
|
21071
21821
|
var import_zod2 = require("zod");
|
|
@@ -21079,7 +21829,7 @@ var historyRecordSchema = import_zod2.z.object({
|
|
|
21079
21829
|
content: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.unknown())]).optional()
|
|
21080
21830
|
}).passthrough().optional()
|
|
21081
21831
|
}).passthrough();
|
|
21082
|
-
var
|
|
21832
|
+
var API_BASE8 = resolveApiBaseUrl();
|
|
21083
21833
|
function extractText3(content) {
|
|
21084
21834
|
if (typeof content === "string") return content;
|
|
21085
21835
|
if (Array.isArray(content)) {
|
|
@@ -21092,7 +21842,7 @@ function parseJsonl(filePath) {
|
|
|
21092
21842
|
const messages = [];
|
|
21093
21843
|
let raw;
|
|
21094
21844
|
try {
|
|
21095
|
-
raw =
|
|
21845
|
+
raw = fs34.readFileSync(filePath, "utf8");
|
|
21096
21846
|
} catch (err) {
|
|
21097
21847
|
if (err.code !== "ENOENT") {
|
|
21098
21848
|
log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
|
|
@@ -21129,9 +21879,9 @@ function parseJsonl(filePath) {
|
|
|
21129
21879
|
return messages;
|
|
21130
21880
|
}
|
|
21131
21881
|
function post(endpoint, body) {
|
|
21132
|
-
return new Promise((
|
|
21882
|
+
return new Promise((resolve7) => {
|
|
21133
21883
|
const payload = JSON.stringify(body);
|
|
21134
|
-
const u2 = new URL(`${
|
|
21884
|
+
const u2 = new URL(`${API_BASE8}${endpoint}`);
|
|
21135
21885
|
const transport = u2.protocol === "https:" ? https7 : http7;
|
|
21136
21886
|
const req = transport.request(
|
|
21137
21887
|
{
|
|
@@ -21150,17 +21900,17 @@ function post(endpoint, body) {
|
|
|
21150
21900
|
res.resume();
|
|
21151
21901
|
const ok = res.statusCode !== void 0 && res.statusCode >= 200 && res.statusCode < 300;
|
|
21152
21902
|
if (!ok) log.warn("history:post", `${endpoint} \u2192 HTTP ${res.statusCode}`);
|
|
21153
|
-
|
|
21903
|
+
resolve7(ok);
|
|
21154
21904
|
}
|
|
21155
21905
|
);
|
|
21156
21906
|
req.on("error", (err) => {
|
|
21157
21907
|
log.warn("history:post", `${endpoint} network error`, err);
|
|
21158
|
-
|
|
21908
|
+
resolve7(false);
|
|
21159
21909
|
});
|
|
21160
21910
|
req.on("timeout", () => {
|
|
21161
21911
|
log.warn("history:post", `${endpoint} timeout after 15s`);
|
|
21162
21912
|
req.destroy();
|
|
21163
|
-
|
|
21913
|
+
resolve7(false);
|
|
21164
21914
|
});
|
|
21165
21915
|
req.write(payload);
|
|
21166
21916
|
req.end();
|
|
@@ -21227,7 +21977,7 @@ var HistoryService = class _HistoryService {
|
|
|
21227
21977
|
return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
|
|
21228
21978
|
}
|
|
21229
21979
|
get projectDir() {
|
|
21230
|
-
return this.runtime.resolveHistoryDir(this.cwd) ??
|
|
21980
|
+
return this.runtime.resolveHistoryDir(this.cwd) ?? path42.join(os27.homedir(), ".claude", "projects", encodeCwd(this.cwd));
|
|
21231
21981
|
}
|
|
21232
21982
|
/** Set the current Claude conversation ID (extracted from /cost command or session start) */
|
|
21233
21983
|
setCurrentConversationId(id) {
|
|
@@ -21239,7 +21989,7 @@ var HistoryService = class _HistoryService {
|
|
|
21239
21989
|
/** Return the current message count in the active conversation. */
|
|
21240
21990
|
getCurrentMessageCount() {
|
|
21241
21991
|
if (!this.currentConversationId) return 0;
|
|
21242
|
-
const filePath =
|
|
21992
|
+
const filePath = path42.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
21243
21993
|
return parseJsonl(filePath).length;
|
|
21244
21994
|
}
|
|
21245
21995
|
/**
|
|
@@ -21250,7 +22000,7 @@ var HistoryService = class _HistoryService {
|
|
|
21250
22000
|
const deadline = Date.now() + timeoutMs;
|
|
21251
22001
|
while (Date.now() < deadline) {
|
|
21252
22002
|
if (!this.currentConversationId) return null;
|
|
21253
|
-
const filePath =
|
|
22003
|
+
const filePath = path42.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
21254
22004
|
const messages = parseJsonl(filePath);
|
|
21255
22005
|
if (messages.length > previousCount) {
|
|
21256
22006
|
for (let i = messages.length - 1; i >= previousCount; i--) {
|
|
@@ -21276,16 +22026,16 @@ var HistoryService = class _HistoryService {
|
|
|
21276
22026
|
const dir = this.projectDir;
|
|
21277
22027
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
21278
22028
|
try {
|
|
21279
|
-
const files =
|
|
22029
|
+
const files = fs34.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
21280
22030
|
try {
|
|
21281
|
-
const stat3 =
|
|
22031
|
+
const stat3 = fs34.statSync(path42.join(dir, e.name));
|
|
21282
22032
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
21283
22033
|
} catch {
|
|
21284
22034
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
21285
22035
|
}
|
|
21286
22036
|
}).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
|
|
21287
22037
|
if (files.length > 0) {
|
|
21288
|
-
this.currentConversationId =
|
|
22038
|
+
this.currentConversationId = path42.basename(files[0].name, ".jsonl");
|
|
21289
22039
|
}
|
|
21290
22040
|
} catch {
|
|
21291
22041
|
}
|
|
@@ -21319,13 +22069,13 @@ var HistoryService = class _HistoryService {
|
|
|
21319
22069
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
21320
22070
|
let entries;
|
|
21321
22071
|
try {
|
|
21322
|
-
entries =
|
|
22072
|
+
entries = fs34.readdirSync(dir, { withFileTypes: true });
|
|
21323
22073
|
} catch {
|
|
21324
22074
|
return null;
|
|
21325
22075
|
}
|
|
21326
22076
|
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
21327
22077
|
try {
|
|
21328
|
-
const stat3 =
|
|
22078
|
+
const stat3 = fs34.statSync(path42.join(dir, e.name));
|
|
21329
22079
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
21330
22080
|
} catch {
|
|
21331
22081
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
@@ -21334,12 +22084,12 @@ var HistoryService = class _HistoryService {
|
|
|
21334
22084
|
if (files.length === 0) return null;
|
|
21335
22085
|
const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
|
|
21336
22086
|
if (!files.some((f) => f.name === targetFile)) return null;
|
|
21337
|
-
return this.extractUsageFromFile(
|
|
22087
|
+
return this.extractUsageFromFile(path42.join(dir, targetFile));
|
|
21338
22088
|
}
|
|
21339
22089
|
extractUsageFromFile(filePath) {
|
|
21340
22090
|
let raw;
|
|
21341
22091
|
try {
|
|
21342
|
-
raw =
|
|
22092
|
+
raw = fs34.readFileSync(filePath, "utf8");
|
|
21343
22093
|
} catch {
|
|
21344
22094
|
return null;
|
|
21345
22095
|
}
|
|
@@ -21384,9 +22134,9 @@ var HistoryService = class _HistoryService {
|
|
|
21384
22134
|
let totalCost = 0;
|
|
21385
22135
|
let files;
|
|
21386
22136
|
try {
|
|
21387
|
-
files =
|
|
22137
|
+
files = fs34.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
21388
22138
|
try {
|
|
21389
|
-
return
|
|
22139
|
+
return fs34.statSync(path42.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
21390
22140
|
} catch {
|
|
21391
22141
|
return false;
|
|
21392
22142
|
}
|
|
@@ -21397,7 +22147,7 @@ var HistoryService = class _HistoryService {
|
|
|
21397
22147
|
for (const file of files) {
|
|
21398
22148
|
let raw;
|
|
21399
22149
|
try {
|
|
21400
|
-
raw =
|
|
22150
|
+
raw = fs34.readFileSync(path42.join(projectDir, file), "utf8");
|
|
21401
22151
|
} catch {
|
|
21402
22152
|
continue;
|
|
21403
22153
|
}
|
|
@@ -21461,7 +22211,7 @@ var HistoryService = class _HistoryService {
|
|
|
21461
22211
|
* showing an empty conversation.
|
|
21462
22212
|
*/
|
|
21463
22213
|
async loadConversation(sessionId) {
|
|
21464
|
-
const filePath =
|
|
22214
|
+
const filePath = path42.join(this.projectDir, `${sessionId}.jsonl`);
|
|
21465
22215
|
const messages = parseJsonl(filePath);
|
|
21466
22216
|
if (messages.length === 0) return;
|
|
21467
22217
|
const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
|
|
@@ -21515,7 +22265,7 @@ var HistoryService = class _HistoryService {
|
|
|
21515
22265
|
if (!this.currentConversationId) return 0;
|
|
21516
22266
|
}
|
|
21517
22267
|
const sessionId = this.currentConversationId;
|
|
21518
|
-
const filePath =
|
|
22268
|
+
const filePath = path42.join(this.projectDir, `${sessionId}.jsonl`);
|
|
21519
22269
|
const messages = parseJsonl(filePath);
|
|
21520
22270
|
if (messages.length === 0) return 0;
|
|
21521
22271
|
const marker = this.lastUploadedUuid.get(sessionId);
|
|
@@ -21580,7 +22330,7 @@ var RepoDirtyTracker = class {
|
|
|
21580
22330
|
|
|
21581
22331
|
// src/services/streaming-emitter.service.ts
|
|
21582
22332
|
var import_crypto5 = require("crypto");
|
|
21583
|
-
var
|
|
22333
|
+
var API_BASE9 = resolveApiBaseUrl();
|
|
21584
22334
|
var TICK_MS = 50;
|
|
21585
22335
|
var ANSWER_POLL_MS = 1500;
|
|
21586
22336
|
var SELECTOR_STABLE_MS = 800;
|
|
@@ -21591,7 +22341,7 @@ var TAIL_KEEP_BYTES2 = 1.5 * 1024 * 1024;
|
|
|
21591
22341
|
var StreamingEmitterService = class {
|
|
21592
22342
|
constructor(opts) {
|
|
21593
22343
|
this.opts = opts;
|
|
21594
|
-
this.apiBase = opts.apiBaseUrl ??
|
|
22344
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE9;
|
|
21595
22345
|
this.headers = {
|
|
21596
22346
|
"Content-Type": "application/json",
|
|
21597
22347
|
"X-Codeam-Protocol-Version": "2.0.0",
|
|
@@ -21941,13 +22691,13 @@ function fetchQuotaUsage(runtime, historySvc) {
|
|
|
21941
22691
|
}
|
|
21942
22692
|
|
|
21943
22693
|
// src/commands/start/keep-alive.ts
|
|
21944
|
-
var
|
|
22694
|
+
var import_child_process18 = require("child_process");
|
|
21945
22695
|
function buildKeepAlive(ctx) {
|
|
21946
22696
|
let timer = null;
|
|
21947
22697
|
async function setIdleTimeout(minutes) {
|
|
21948
22698
|
if (!ctx.inCodespace || !ctx.codespaceName) return;
|
|
21949
|
-
await new Promise((
|
|
21950
|
-
const proc = (0,
|
|
22699
|
+
await new Promise((resolve7) => {
|
|
22700
|
+
const proc = (0, import_child_process18.spawn)(
|
|
21951
22701
|
"gh",
|
|
21952
22702
|
[
|
|
21953
22703
|
"api",
|
|
@@ -21960,8 +22710,8 @@ function buildKeepAlive(ctx) {
|
|
|
21960
22710
|
{ stdio: "ignore", detached: true }
|
|
21961
22711
|
);
|
|
21962
22712
|
proc.unref();
|
|
21963
|
-
proc.on("exit", () =>
|
|
21964
|
-
proc.on("error", () =>
|
|
22713
|
+
proc.on("exit", () => resolve7());
|
|
22714
|
+
proc.on("error", () => resolve7());
|
|
21965
22715
|
});
|
|
21966
22716
|
}
|
|
21967
22717
|
return {
|
|
@@ -22109,6 +22859,7 @@ async function start(requestedAgent) {
|
|
|
22109
22859
|
dirtyTracker: dirtyTracker ?? void 0
|
|
22110
22860
|
}) : null;
|
|
22111
22861
|
let streamingEmitter = null;
|
|
22862
|
+
let beads = null;
|
|
22112
22863
|
const agent = new AgentService(
|
|
22113
22864
|
runtime,
|
|
22114
22865
|
{
|
|
@@ -22125,6 +22876,7 @@ async function start(requestedAgent) {
|
|
|
22125
22876
|
relay.stop();
|
|
22126
22877
|
void fileWatcher?.stop();
|
|
22127
22878
|
turnFiles?.stop();
|
|
22879
|
+
void beads?.watcher.stop();
|
|
22128
22880
|
void streamingEmitter?.stop();
|
|
22129
22881
|
closeAllTerminals();
|
|
22130
22882
|
cleanupAttachmentTempFiles();
|
|
@@ -22158,6 +22910,16 @@ async function start(requestedAgent) {
|
|
|
22158
22910
|
await dispatchCommand(ctx, cmd);
|
|
22159
22911
|
}, runtime.meta);
|
|
22160
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
|
+
});
|
|
22161
22923
|
registerTerminalHandlers({
|
|
22162
22924
|
onData: ({ sessionId, data }) => {
|
|
22163
22925
|
void outputSvc.sendTerminalChunk(sessionId, data);
|
|
@@ -22174,6 +22936,7 @@ async function start(requestedAgent) {
|
|
|
22174
22936
|
outputSvc.dispose();
|
|
22175
22937
|
relay.stop();
|
|
22176
22938
|
void fileWatcher?.stop();
|
|
22939
|
+
void beads?.watcher.stop();
|
|
22177
22940
|
void streamingEmitter?.stop();
|
|
22178
22941
|
closeAllTerminals();
|
|
22179
22942
|
cleanupAttachmentTempFiles();
|
|
@@ -22312,7 +23075,7 @@ async function pair(args2 = []) {
|
|
|
22312
23075
|
waitSpin.message(waitMessage());
|
|
22313
23076
|
}, 1e3);
|
|
22314
23077
|
countdownInterval.unref?.();
|
|
22315
|
-
await new Promise((
|
|
23078
|
+
await new Promise((resolve7) => {
|
|
22316
23079
|
let stopPolling = null;
|
|
22317
23080
|
function sigintHandler() {
|
|
22318
23081
|
clearInterval(countdownInterval);
|
|
@@ -22360,7 +23123,7 @@ async function pair(args2 = []) {
|
|
|
22360
23123
|
pluginAuthToken: info.pluginAuthToken
|
|
22361
23124
|
});
|
|
22362
23125
|
}
|
|
22363
|
-
|
|
23126
|
+
resolve7();
|
|
22364
23127
|
},
|
|
22365
23128
|
() => {
|
|
22366
23129
|
clearInterval(countdownInterval);
|
|
@@ -22412,8 +23175,8 @@ async function autoLinkAfterPair(opts) {
|
|
|
22412
23175
|
}
|
|
22413
23176
|
|
|
22414
23177
|
// src/commands/pair-auto.ts
|
|
22415
|
-
var
|
|
22416
|
-
var
|
|
23178
|
+
var fs35 = __toESM(require("fs"));
|
|
23179
|
+
var os28 = __toESM(require("os"));
|
|
22417
23180
|
var import_crypto7 = require("crypto");
|
|
22418
23181
|
|
|
22419
23182
|
// src/commands/start-infra-only.ts
|
|
@@ -22566,7 +23329,7 @@ async function startInfraOnly(agentId) {
|
|
|
22566
23329
|
}
|
|
22567
23330
|
|
|
22568
23331
|
// src/commands/pair-auto.ts
|
|
22569
|
-
var
|
|
23332
|
+
var API_BASE10 = resolveApiBaseUrl();
|
|
22570
23333
|
function fail(msg) {
|
|
22571
23334
|
console.error(`
|
|
22572
23335
|
${msg}
|
|
@@ -22581,12 +23344,12 @@ function readTokenFromArgs(args2) {
|
|
|
22581
23344
|
}
|
|
22582
23345
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
22583
23346
|
if (fileFlag) {
|
|
22584
|
-
const
|
|
23347
|
+
const path49 = fileFlag.slice("--token-file=".length);
|
|
22585
23348
|
try {
|
|
22586
|
-
const content =
|
|
22587
|
-
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`);
|
|
22588
23351
|
try {
|
|
22589
|
-
|
|
23352
|
+
fs35.unlinkSync(path49);
|
|
22590
23353
|
} catch {
|
|
22591
23354
|
}
|
|
22592
23355
|
return content;
|
|
@@ -22606,13 +23369,13 @@ function networkError(msg, cause) {
|
|
|
22606
23369
|
return err;
|
|
22607
23370
|
}
|
|
22608
23371
|
async function claimOnce(token, pluginId) {
|
|
22609
|
-
const url = `${
|
|
23372
|
+
const url = `${API_BASE10}/api/pairing/claim-auto-token`;
|
|
22610
23373
|
const body = {
|
|
22611
23374
|
token,
|
|
22612
23375
|
pluginId,
|
|
22613
23376
|
ideName: "codeam-cli (codespace)",
|
|
22614
23377
|
ideVersion: process.env.npm_package_version ?? "unknown",
|
|
22615
|
-
hostname:
|
|
23378
|
+
hostname: os28.hostname(),
|
|
22616
23379
|
codespaceName: process.env.CODESPACE_NAME ?? "",
|
|
22617
23380
|
// Current git branch of the codespace's working directory, so the
|
|
22618
23381
|
// backend can populate `PairedSession.branch` for the codespace pair.
|
|
@@ -22809,7 +23572,7 @@ function status() {
|
|
|
22809
23572
|
|
|
22810
23573
|
// src/commands/logout.ts
|
|
22811
23574
|
var import_picocolors7 = __toESM(require("picocolors"));
|
|
22812
|
-
var
|
|
23575
|
+
var API_BASE11 = resolveApiBaseUrl();
|
|
22813
23576
|
async function notifyBackendOffline() {
|
|
22814
23577
|
const cfg = loadCliConfig();
|
|
22815
23578
|
const pluginIds = /* @__PURE__ */ new Set([
|
|
@@ -22821,7 +23584,7 @@ async function notifyBackendOffline() {
|
|
|
22821
23584
|
try {
|
|
22822
23585
|
await Promise.all(
|
|
22823
23586
|
Array.from(pluginIds).map(
|
|
22824
|
-
(pluginId) => _postJson(`${
|
|
23587
|
+
(pluginId) => _postJson(`${API_BASE11}/api/plugin/heartbeat`, {
|
|
22825
23588
|
pluginId,
|
|
22826
23589
|
online: false
|
|
22827
23590
|
}).catch((err) => {
|
|
@@ -22849,11 +23612,11 @@ async function logout() {
|
|
|
22849
23612
|
var import_picocolors10 = __toESM(require("picocolors"));
|
|
22850
23613
|
|
|
22851
23614
|
// src/services/providers/github-codespaces.ts
|
|
22852
|
-
var
|
|
23615
|
+
var import_child_process19 = require("child_process");
|
|
22853
23616
|
var import_util4 = require("util");
|
|
22854
23617
|
var import_picocolors8 = __toESM(require("picocolors"));
|
|
22855
|
-
var
|
|
22856
|
-
var execFileP5 = (0, import_util4.promisify)(
|
|
23618
|
+
var path43 = __toESM(require("path"));
|
|
23619
|
+
var execFileP5 = (0, import_util4.promisify)(import_child_process19.execFile);
|
|
22857
23620
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
22858
23621
|
function resetStdinForChild() {
|
|
22859
23622
|
if (process.stdin.isTTY) {
|
|
@@ -22896,12 +23659,12 @@ var GitHubCodespacesProvider = class {
|
|
|
22896
23659
|
}
|
|
22897
23660
|
if (!isAuthed) {
|
|
22898
23661
|
resetStdinForChild();
|
|
22899
|
-
await new Promise((
|
|
22900
|
-
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"], {
|
|
22901
23664
|
stdio: "inherit"
|
|
22902
23665
|
});
|
|
22903
23666
|
proc.on("exit", (code) => {
|
|
22904
|
-
if (code === 0)
|
|
23667
|
+
if (code === 0) resolve7();
|
|
22905
23668
|
else reject(new Error("gh auth login failed."));
|
|
22906
23669
|
});
|
|
22907
23670
|
proc.on("error", reject);
|
|
@@ -22930,13 +23693,13 @@ var GitHubCodespacesProvider = class {
|
|
|
22930
23693
|
}
|
|
22931
23694
|
wt(noteLines.join("\n"), "One more permission needed");
|
|
22932
23695
|
resetStdinForChild();
|
|
22933
|
-
const refreshCode = await new Promise((
|
|
22934
|
-
const proc = (0,
|
|
23696
|
+
const refreshCode = await new Promise((resolve7, reject) => {
|
|
23697
|
+
const proc = (0, import_child_process19.spawn)(
|
|
22935
23698
|
"gh",
|
|
22936
23699
|
["auth", "refresh", "-h", "github.com", "-s", "codespace"],
|
|
22937
23700
|
{ stdio: "inherit" }
|
|
22938
23701
|
);
|
|
22939
|
-
proc.on("exit", (code) =>
|
|
23702
|
+
proc.on("exit", (code) => resolve7(code ?? 1));
|
|
22940
23703
|
proc.on("error", reject);
|
|
22941
23704
|
});
|
|
22942
23705
|
if (refreshCode !== 0) {
|
|
@@ -23080,10 +23843,10 @@ var GitHubCodespacesProvider = class {
|
|
|
23080
23843
|
if (q(proceed) || !proceed) return;
|
|
23081
23844
|
O2.step(`Installing gh via ${installCmd.describe}\u2026`);
|
|
23082
23845
|
resetStdinForChild();
|
|
23083
|
-
const ok = await new Promise((
|
|
23084
|
-
const proc = (0,
|
|
23085
|
-
proc.on("exit", (code) =>
|
|
23086
|
-
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));
|
|
23087
23850
|
});
|
|
23088
23851
|
if (ok) O2.success("gh installed");
|
|
23089
23852
|
else O2.error("gh install failed");
|
|
@@ -23107,14 +23870,14 @@ var GitHubCodespacesProvider = class {
|
|
|
23107
23870
|
"Expanding GitHub scopes"
|
|
23108
23871
|
);
|
|
23109
23872
|
resetStdinForChild();
|
|
23110
|
-
await new Promise((
|
|
23111
|
-
const proc = (0,
|
|
23873
|
+
await new Promise((resolve7, reject) => {
|
|
23874
|
+
const proc = (0, import_child_process19.spawn)(
|
|
23112
23875
|
"gh",
|
|
23113
23876
|
["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
|
|
23114
23877
|
{ stdio: "inherit" }
|
|
23115
23878
|
);
|
|
23116
23879
|
proc.on("exit", (code) => {
|
|
23117
|
-
if (code === 0)
|
|
23880
|
+
if (code === 0) resolve7();
|
|
23118
23881
|
else reject(new Error(
|
|
23119
23882
|
"gh auth refresh failed. Re-run `gh auth refresh -h github.com -s repo,read:org` manually."
|
|
23120
23883
|
));
|
|
@@ -23285,13 +24048,13 @@ var GitHubCodespacesProvider = class {
|
|
|
23285
24048
|
}
|
|
23286
24049
|
async streamCommand(workspaceId, command2) {
|
|
23287
24050
|
resetStdinForChild();
|
|
23288
|
-
return new Promise((
|
|
23289
|
-
const proc = (0,
|
|
24051
|
+
return new Promise((resolve7, reject) => {
|
|
24052
|
+
const proc = (0, import_child_process19.spawn)(
|
|
23290
24053
|
"gh",
|
|
23291
24054
|
["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
|
|
23292
24055
|
{ stdio: "inherit" }
|
|
23293
24056
|
);
|
|
23294
|
-
proc.on("exit", (code) =>
|
|
24057
|
+
proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
|
|
23295
24058
|
proc.on("error", reject);
|
|
23296
24059
|
});
|
|
23297
24060
|
}
|
|
@@ -23312,12 +24075,12 @@ var GitHubCodespacesProvider = class {
|
|
|
23312
24075
|
"--",
|
|
23313
24076
|
`mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
|
|
23314
24077
|
];
|
|
23315
|
-
await new Promise((
|
|
23316
|
-
const tar = (0,
|
|
24078
|
+
await new Promise((resolve7, reject) => {
|
|
24079
|
+
const tar = (0, import_child_process19.spawn)("tar", tarArgs, {
|
|
23317
24080
|
stdio: ["ignore", "pipe", "pipe"],
|
|
23318
24081
|
env: tarEnv
|
|
23319
24082
|
});
|
|
23320
|
-
const ssh = (0,
|
|
24083
|
+
const ssh = (0, import_child_process19.spawn)("gh", sshArgs, {
|
|
23321
24084
|
stdio: [tar.stdout, "pipe", "pipe"]
|
|
23322
24085
|
});
|
|
23323
24086
|
let tarErr = "";
|
|
@@ -23332,7 +24095,7 @@ var GitHubCodespacesProvider = class {
|
|
|
23332
24095
|
ssh.on("error", reject);
|
|
23333
24096
|
ssh.on("exit", (code) => {
|
|
23334
24097
|
if (code === 0) {
|
|
23335
|
-
|
|
24098
|
+
resolve7();
|
|
23336
24099
|
} else {
|
|
23337
24100
|
const reason = (sshErr || tarErr || `exit ${code}`).trim().slice(0, 500);
|
|
23338
24101
|
reject(new Error(`Remote tar failed: ${reason}`));
|
|
@@ -23341,7 +24104,7 @@ var GitHubCodespacesProvider = class {
|
|
|
23341
24104
|
});
|
|
23342
24105
|
}
|
|
23343
24106
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
23344
|
-
const remoteDir =
|
|
24107
|
+
const remoteDir = path43.posix.dirname(remotePath);
|
|
23345
24108
|
const parts = [
|
|
23346
24109
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
23347
24110
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -23350,8 +24113,8 @@ var GitHubCodespacesProvider = class {
|
|
|
23350
24113
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote(remotePath)}`);
|
|
23351
24114
|
}
|
|
23352
24115
|
const cmd = parts.join(" && ");
|
|
23353
|
-
await new Promise((
|
|
23354
|
-
const proc = (0,
|
|
24116
|
+
await new Promise((resolve7, reject) => {
|
|
24117
|
+
const proc = (0, import_child_process19.spawn)(
|
|
23355
24118
|
"gh",
|
|
23356
24119
|
["codespace", "ssh", "-c", workspaceId, "--", cmd],
|
|
23357
24120
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -23362,7 +24125,7 @@ var GitHubCodespacesProvider = class {
|
|
|
23362
24125
|
});
|
|
23363
24126
|
proc.on("error", reject);
|
|
23364
24127
|
proc.on("exit", (code) => {
|
|
23365
|
-
if (code === 0)
|
|
24128
|
+
if (code === 0) resolve7();
|
|
23366
24129
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
23367
24130
|
});
|
|
23368
24131
|
proc.stdin?.write(contents);
|
|
@@ -23409,11 +24172,11 @@ function shellQuote(s) {
|
|
|
23409
24172
|
}
|
|
23410
24173
|
|
|
23411
24174
|
// src/services/providers/gitpod.ts
|
|
23412
|
-
var
|
|
24175
|
+
var import_child_process20 = require("child_process");
|
|
23413
24176
|
var import_util5 = require("util");
|
|
23414
|
-
var
|
|
24177
|
+
var path44 = __toESM(require("path"));
|
|
23415
24178
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
23416
|
-
var execFileP6 = (0, import_util5.promisify)(
|
|
24179
|
+
var execFileP6 = (0, import_util5.promisify)(import_child_process20.execFile);
|
|
23417
24180
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
23418
24181
|
function resetStdinForChild2() {
|
|
23419
24182
|
if (process.stdin.isTTY) {
|
|
@@ -23452,10 +24215,10 @@ var GitpodProvider = class {
|
|
|
23452
24215
|
"Authenticating Gitpod"
|
|
23453
24216
|
);
|
|
23454
24217
|
resetStdinForChild2();
|
|
23455
|
-
await new Promise((
|
|
23456
|
-
const proc = (0,
|
|
24218
|
+
await new Promise((resolve7, reject) => {
|
|
24219
|
+
const proc = (0, import_child_process20.spawn)("gitpod", ["login"], { stdio: "inherit" });
|
|
23457
24220
|
proc.on("exit", (code) => {
|
|
23458
|
-
if (code === 0)
|
|
24221
|
+
if (code === 0) resolve7();
|
|
23459
24222
|
else reject(new Error("gitpod login failed."));
|
|
23460
24223
|
});
|
|
23461
24224
|
proc.on("error", reject);
|
|
@@ -23604,13 +24367,13 @@ var GitpodProvider = class {
|
|
|
23604
24367
|
}
|
|
23605
24368
|
async streamCommand(workspaceId, command2) {
|
|
23606
24369
|
resetStdinForChild2();
|
|
23607
|
-
return new Promise((
|
|
23608
|
-
const proc = (0,
|
|
24370
|
+
return new Promise((resolve7, reject) => {
|
|
24371
|
+
const proc = (0, import_child_process20.spawn)(
|
|
23609
24372
|
"gitpod",
|
|
23610
24373
|
["workspace", "ssh", workspaceId, "--", "-tt", command2],
|
|
23611
24374
|
{ stdio: "inherit" }
|
|
23612
24375
|
);
|
|
23613
|
-
proc.on("exit", (code) =>
|
|
24376
|
+
proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
|
|
23614
24377
|
proc.on("error", reject);
|
|
23615
24378
|
});
|
|
23616
24379
|
}
|
|
@@ -23624,12 +24387,12 @@ var GitpodProvider = class {
|
|
|
23624
24387
|
tarArgs.push(".");
|
|
23625
24388
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
23626
24389
|
const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
|
|
23627
|
-
await new Promise((
|
|
23628
|
-
const tar = (0,
|
|
24390
|
+
await new Promise((resolve7, reject) => {
|
|
24391
|
+
const tar = (0, import_child_process20.spawn)("tar", tarArgs, {
|
|
23629
24392
|
stdio: ["ignore", "pipe", "pipe"],
|
|
23630
24393
|
env: tarEnv
|
|
23631
24394
|
});
|
|
23632
|
-
const ssh = (0,
|
|
24395
|
+
const ssh = (0, import_child_process20.spawn)(
|
|
23633
24396
|
"gitpod",
|
|
23634
24397
|
["workspace", "ssh", workspaceId, "--", remoteCmd],
|
|
23635
24398
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -23645,13 +24408,13 @@ var GitpodProvider = class {
|
|
|
23645
24408
|
tar.on("error", reject);
|
|
23646
24409
|
ssh.on("error", reject);
|
|
23647
24410
|
ssh.on("exit", (code) => {
|
|
23648
|
-
if (code === 0)
|
|
24411
|
+
if (code === 0) resolve7();
|
|
23649
24412
|
else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
23650
24413
|
});
|
|
23651
24414
|
});
|
|
23652
24415
|
}
|
|
23653
24416
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
23654
|
-
const remoteDir =
|
|
24417
|
+
const remoteDir = path44.posix.dirname(remotePath);
|
|
23655
24418
|
const parts = [
|
|
23656
24419
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
23657
24420
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -23660,8 +24423,8 @@ var GitpodProvider = class {
|
|
|
23660
24423
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote2(remotePath)}`);
|
|
23661
24424
|
}
|
|
23662
24425
|
const cmd = parts.join(" && ");
|
|
23663
|
-
await new Promise((
|
|
23664
|
-
const proc = (0,
|
|
24426
|
+
await new Promise((resolve7, reject) => {
|
|
24427
|
+
const proc = (0, import_child_process20.spawn)(
|
|
23665
24428
|
"gitpod",
|
|
23666
24429
|
["workspace", "ssh", workspaceId, "--", cmd],
|
|
23667
24430
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -23672,7 +24435,7 @@ var GitpodProvider = class {
|
|
|
23672
24435
|
});
|
|
23673
24436
|
proc.on("error", reject);
|
|
23674
24437
|
proc.on("exit", (code) => {
|
|
23675
|
-
if (code === 0)
|
|
24438
|
+
if (code === 0) resolve7();
|
|
23676
24439
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
23677
24440
|
});
|
|
23678
24441
|
proc.stdin?.write(contents);
|
|
@@ -23685,10 +24448,10 @@ function shellQuote2(s) {
|
|
|
23685
24448
|
}
|
|
23686
24449
|
|
|
23687
24450
|
// src/services/providers/gitlab-workspaces.ts
|
|
23688
|
-
var
|
|
24451
|
+
var import_child_process21 = require("child_process");
|
|
23689
24452
|
var import_util6 = require("util");
|
|
23690
|
-
var
|
|
23691
|
-
var execFileP7 = (0, import_util6.promisify)(
|
|
24453
|
+
var path45 = __toESM(require("path"));
|
|
24454
|
+
var execFileP7 = (0, import_util6.promisify)(import_child_process21.execFile);
|
|
23692
24455
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
23693
24456
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
23694
24457
|
function resetStdinForChild3() {
|
|
@@ -23729,14 +24492,14 @@ var GitLabWorkspacesProvider = class {
|
|
|
23729
24492
|
"Authenticating GitLab"
|
|
23730
24493
|
);
|
|
23731
24494
|
resetStdinForChild3();
|
|
23732
|
-
await new Promise((
|
|
23733
|
-
const proc = (0,
|
|
24495
|
+
await new Promise((resolve7, reject) => {
|
|
24496
|
+
const proc = (0, import_child_process21.spawn)(
|
|
23734
24497
|
"glab",
|
|
23735
24498
|
["auth", "login", "--scopes", "api,read_user,read_repository"],
|
|
23736
24499
|
{ stdio: "inherit" }
|
|
23737
24500
|
);
|
|
23738
24501
|
proc.on("exit", (code) => {
|
|
23739
|
-
if (code === 0)
|
|
24502
|
+
if (code === 0) resolve7();
|
|
23740
24503
|
else reject(new Error("glab auth login failed."));
|
|
23741
24504
|
});
|
|
23742
24505
|
proc.on("error", reject);
|
|
@@ -23901,13 +24664,13 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
23901
24664
|
async streamCommand(workspaceId, command2) {
|
|
23902
24665
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
23903
24666
|
resetStdinForChild3();
|
|
23904
|
-
return new Promise((
|
|
23905
|
-
const proc = (0,
|
|
24667
|
+
return new Promise((resolve7, reject) => {
|
|
24668
|
+
const proc = (0, import_child_process21.spawn)(
|
|
23906
24669
|
"ssh",
|
|
23907
24670
|
["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
|
|
23908
24671
|
{ stdio: "inherit" }
|
|
23909
24672
|
);
|
|
23910
|
-
proc.on("exit", (code) =>
|
|
24673
|
+
proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
|
|
23911
24674
|
proc.on("error", reject);
|
|
23912
24675
|
});
|
|
23913
24676
|
}
|
|
@@ -23922,9 +24685,9 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
23922
24685
|
tarArgs.push(".");
|
|
23923
24686
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
23924
24687
|
const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
|
|
23925
|
-
await new Promise((
|
|
23926
|
-
const tar = (0,
|
|
23927
|
-
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)(
|
|
23928
24691
|
"ssh",
|
|
23929
24692
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, remoteCmd],
|
|
23930
24693
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -23940,21 +24703,21 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
23940
24703
|
tar.on("error", reject);
|
|
23941
24704
|
ssh.on("error", reject);
|
|
23942
24705
|
ssh.on("exit", (code) => {
|
|
23943
|
-
if (code === 0)
|
|
24706
|
+
if (code === 0) resolve7();
|
|
23944
24707
|
else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
23945
24708
|
});
|
|
23946
24709
|
});
|
|
23947
24710
|
}
|
|
23948
24711
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
23949
24712
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
23950
|
-
const remoteDir =
|
|
24713
|
+
const remoteDir = path45.posix.dirname(remotePath);
|
|
23951
24714
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
23952
24715
|
if (options.mode != null) {
|
|
23953
24716
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
23954
24717
|
}
|
|
23955
24718
|
const cmd = parts.join(" && ");
|
|
23956
|
-
await new Promise((
|
|
23957
|
-
const proc = (0,
|
|
24719
|
+
await new Promise((resolve7, reject) => {
|
|
24720
|
+
const proc = (0, import_child_process21.spawn)(
|
|
23958
24721
|
"ssh",
|
|
23959
24722
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
|
|
23960
24723
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -23965,7 +24728,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
23965
24728
|
});
|
|
23966
24729
|
proc.on("error", reject);
|
|
23967
24730
|
proc.on("exit", (code) => {
|
|
23968
|
-
if (code === 0)
|
|
24731
|
+
if (code === 0) resolve7();
|
|
23969
24732
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
23970
24733
|
});
|
|
23971
24734
|
proc.stdin?.write(contents);
|
|
@@ -24013,10 +24776,10 @@ function shellQuote3(s) {
|
|
|
24013
24776
|
}
|
|
24014
24777
|
|
|
24015
24778
|
// src/services/providers/railway.ts
|
|
24016
|
-
var
|
|
24779
|
+
var import_child_process22 = require("child_process");
|
|
24017
24780
|
var import_util7 = require("util");
|
|
24018
|
-
var
|
|
24019
|
-
var execFileP8 = (0, import_util7.promisify)(
|
|
24781
|
+
var path46 = __toESM(require("path"));
|
|
24782
|
+
var execFileP8 = (0, import_util7.promisify)(import_child_process22.execFile);
|
|
24020
24783
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
24021
24784
|
function resetStdinForChild4() {
|
|
24022
24785
|
if (process.stdin.isTTY) {
|
|
@@ -24056,10 +24819,10 @@ var RailwayProvider = class {
|
|
|
24056
24819
|
"Authenticating Railway"
|
|
24057
24820
|
);
|
|
24058
24821
|
resetStdinForChild4();
|
|
24059
|
-
await new Promise((
|
|
24060
|
-
const proc = (0,
|
|
24822
|
+
await new Promise((resolve7, reject) => {
|
|
24823
|
+
const proc = (0, import_child_process22.spawn)("railway", ["login"], { stdio: "inherit" });
|
|
24061
24824
|
proc.on("exit", (code) => {
|
|
24062
|
-
if (code === 0)
|
|
24825
|
+
if (code === 0) resolve7();
|
|
24063
24826
|
else reject(new Error("railway login failed."));
|
|
24064
24827
|
});
|
|
24065
24828
|
proc.on("error", reject);
|
|
@@ -24199,13 +24962,13 @@ var RailwayProvider = class {
|
|
|
24199
24962
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
24200
24963
|
}
|
|
24201
24964
|
resetStdinForChild4();
|
|
24202
|
-
return new Promise((
|
|
24203
|
-
const proc = (0,
|
|
24965
|
+
return new Promise((resolve7, reject) => {
|
|
24966
|
+
const proc = (0, import_child_process22.spawn)(
|
|
24204
24967
|
"railway",
|
|
24205
24968
|
["shell", "--project", projectId, "--service", serviceId, "--command", command2],
|
|
24206
24969
|
{ stdio: "inherit" }
|
|
24207
24970
|
);
|
|
24208
|
-
proc.on("exit", (code) =>
|
|
24971
|
+
proc.on("exit", (code) => resolve7({ code: code ?? 0 }));
|
|
24209
24972
|
proc.on("error", reject);
|
|
24210
24973
|
});
|
|
24211
24974
|
}
|
|
@@ -24223,9 +24986,9 @@ var RailwayProvider = class {
|
|
|
24223
24986
|
tarArgs.push(".");
|
|
24224
24987
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
24225
24988
|
const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
|
|
24226
|
-
await new Promise((
|
|
24227
|
-
const tar = (0,
|
|
24228
|
-
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)(
|
|
24229
24992
|
"railway",
|
|
24230
24993
|
["shell", "--project", projectId, "--service", serviceId, "--command", remoteCmd],
|
|
24231
24994
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -24241,7 +25004,7 @@ var RailwayProvider = class {
|
|
|
24241
25004
|
tar.on("error", reject);
|
|
24242
25005
|
sh.on("error", reject);
|
|
24243
25006
|
sh.on("exit", (code) => {
|
|
24244
|
-
if (code === 0)
|
|
25007
|
+
if (code === 0) resolve7();
|
|
24245
25008
|
else reject(new Error(`Remote tar failed: ${(shErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
24246
25009
|
});
|
|
24247
25010
|
});
|
|
@@ -24251,14 +25014,14 @@ var RailwayProvider = class {
|
|
|
24251
25014
|
if (!projectId || !serviceId) {
|
|
24252
25015
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
24253
25016
|
}
|
|
24254
|
-
const remoteDir =
|
|
25017
|
+
const remoteDir = path46.posix.dirname(remotePath);
|
|
24255
25018
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
24256
25019
|
if (options.mode != null) {
|
|
24257
25020
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
24258
25021
|
}
|
|
24259
25022
|
const cmd = parts.join(" && ");
|
|
24260
|
-
await new Promise((
|
|
24261
|
-
const proc = (0,
|
|
25023
|
+
await new Promise((resolve7, reject) => {
|
|
25024
|
+
const proc = (0, import_child_process22.spawn)(
|
|
24262
25025
|
"railway",
|
|
24263
25026
|
["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
|
|
24264
25027
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -24269,7 +25032,7 @@ var RailwayProvider = class {
|
|
|
24269
25032
|
});
|
|
24270
25033
|
proc.on("error", reject);
|
|
24271
25034
|
proc.on("exit", (code) => {
|
|
24272
|
-
if (code === 0)
|
|
25035
|
+
if (code === 0) resolve7();
|
|
24273
25036
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
24274
25037
|
});
|
|
24275
25038
|
proc.stdin?.write(contents);
|
|
@@ -24794,8 +25557,8 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
24794
25557
|
var import_node_dns = require("dns");
|
|
24795
25558
|
var import_node_util4 = require("util");
|
|
24796
25559
|
var import_node_crypto8 = require("crypto");
|
|
24797
|
-
var
|
|
24798
|
-
var
|
|
25560
|
+
var fs36 = __toESM(require("fs"));
|
|
25561
|
+
var path47 = __toESM(require("path"));
|
|
24799
25562
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
24800
25563
|
var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
|
|
24801
25564
|
async function checkDns(apiBase) {
|
|
@@ -24851,13 +25614,13 @@ async function checkHealth(apiBase) {
|
|
|
24851
25614
|
}
|
|
24852
25615
|
}
|
|
24853
25616
|
function checkConfigDir() {
|
|
24854
|
-
const dir =
|
|
25617
|
+
const dir = path47.join(require("os").homedir(), ".codeam");
|
|
24855
25618
|
try {
|
|
24856
|
-
|
|
24857
|
-
const probe =
|
|
24858
|
-
|
|
24859
|
-
const read =
|
|
24860
|
-
|
|
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);
|
|
24861
25624
|
if (read !== "ok") throw new Error("write/read round-trip mismatch");
|
|
24862
25625
|
return {
|
|
24863
25626
|
id: "config-dir",
|
|
@@ -24897,9 +25660,9 @@ function checkSessions() {
|
|
|
24897
25660
|
}
|
|
24898
25661
|
}
|
|
24899
25662
|
function checkAgentBinaries() {
|
|
24900
|
-
const
|
|
25663
|
+
const os30 = createOsStrategy();
|
|
24901
25664
|
return getEnabledAgents().map((meta) => {
|
|
24902
|
-
const found =
|
|
25665
|
+
const found = os30.findInPath(meta.binaryName);
|
|
24903
25666
|
return {
|
|
24904
25667
|
id: `agent-${meta.id}`,
|
|
24905
25668
|
label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
|
|
@@ -24921,7 +25684,7 @@ function checkNodePty() {
|
|
|
24921
25684
|
detail: "not required on this platform"
|
|
24922
25685
|
};
|
|
24923
25686
|
}
|
|
24924
|
-
const vendoredPath =
|
|
25687
|
+
const vendoredPath = path47.join(__dirname, "vendor", "node-pty");
|
|
24925
25688
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
24926
25689
|
try {
|
|
24927
25690
|
require(target);
|
|
@@ -24963,7 +25726,7 @@ function checkChokidar() {
|
|
|
24963
25726
|
}
|
|
24964
25727
|
async function doctor(args2 = []) {
|
|
24965
25728
|
const json = args2.includes("--json");
|
|
24966
|
-
const cliVersion = true ? "2.
|
|
25729
|
+
const cliVersion = true ? "2.33.0" : "0.0.0-dev";
|
|
24967
25730
|
const apiBase = resolveApiBaseUrl();
|
|
24968
25731
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
24969
25732
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -25162,7 +25925,7 @@ async function completion(args2) {
|
|
|
25162
25925
|
// src/commands/version.ts
|
|
25163
25926
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
25164
25927
|
function version2() {
|
|
25165
|
-
const v = true ? "2.
|
|
25928
|
+
const v = true ? "2.33.0" : "unknown";
|
|
25166
25929
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
25167
25930
|
}
|
|
25168
25931
|
|
|
@@ -25290,9 +26053,9 @@ function tryShowSubcommandHelp(cmd, args2) {
|
|
|
25290
26053
|
var _subcommandHelpKeys = Object.keys(HELPS);
|
|
25291
26054
|
|
|
25292
26055
|
// src/lib/updateNotifier.ts
|
|
25293
|
-
var
|
|
25294
|
-
var
|
|
25295
|
-
var
|
|
26056
|
+
var fs37 = __toESM(require("fs"));
|
|
26057
|
+
var os29 = __toESM(require("os"));
|
|
26058
|
+
var path48 = __toESM(require("path"));
|
|
25296
26059
|
var https8 = __toESM(require("https"));
|
|
25297
26060
|
var import_node_child_process12 = require("child_process");
|
|
25298
26061
|
var import_picocolors16 = __toESM(require("picocolors"));
|
|
@@ -25301,12 +26064,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
|
25301
26064
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
25302
26065
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
25303
26066
|
function cachePath() {
|
|
25304
|
-
const dir =
|
|
25305
|
-
return
|
|
26067
|
+
const dir = path48.join(os29.homedir(), ".codeam");
|
|
26068
|
+
return path48.join(dir, "update-check.json");
|
|
25306
26069
|
}
|
|
25307
26070
|
function readCache() {
|
|
25308
26071
|
try {
|
|
25309
|
-
const raw =
|
|
26072
|
+
const raw = fs37.readFileSync(cachePath(), "utf8");
|
|
25310
26073
|
const parsed = JSON.parse(raw);
|
|
25311
26074
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
25312
26075
|
return parsed;
|
|
@@ -25317,10 +26080,10 @@ function readCache() {
|
|
|
25317
26080
|
function writeCache(cache) {
|
|
25318
26081
|
try {
|
|
25319
26082
|
const file = cachePath();
|
|
25320
|
-
|
|
26083
|
+
fs37.mkdirSync(path48.dirname(file), { recursive: true });
|
|
25321
26084
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
25322
|
-
|
|
25323
|
-
|
|
26085
|
+
fs37.writeFileSync(tmp, JSON.stringify(cache));
|
|
26086
|
+
fs37.renameSync(tmp, file);
|
|
25324
26087
|
} catch {
|
|
25325
26088
|
}
|
|
25326
26089
|
}
|
|
@@ -25338,14 +26101,14 @@ function compareSemver(a, b) {
|
|
|
25338
26101
|
return 0;
|
|
25339
26102
|
}
|
|
25340
26103
|
function fetchLatest() {
|
|
25341
|
-
return new Promise((
|
|
26104
|
+
return new Promise((resolve7) => {
|
|
25342
26105
|
const req = https8.get(
|
|
25343
26106
|
REGISTRY_URL,
|
|
25344
26107
|
{ headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
|
|
25345
26108
|
(res) => {
|
|
25346
26109
|
if (res.statusCode !== 200) {
|
|
25347
26110
|
res.resume();
|
|
25348
|
-
|
|
26111
|
+
resolve7(null);
|
|
25349
26112
|
return;
|
|
25350
26113
|
}
|
|
25351
26114
|
let buf = "";
|
|
@@ -25357,21 +26120,21 @@ function fetchLatest() {
|
|
|
25357
26120
|
try {
|
|
25358
26121
|
const json = JSON.parse(buf);
|
|
25359
26122
|
if (typeof json.version === "string") {
|
|
25360
|
-
|
|
26123
|
+
resolve7(json.version);
|
|
25361
26124
|
} else {
|
|
25362
|
-
|
|
26125
|
+
resolve7(null);
|
|
25363
26126
|
}
|
|
25364
26127
|
} catch {
|
|
25365
|
-
|
|
26128
|
+
resolve7(null);
|
|
25366
26129
|
}
|
|
25367
26130
|
});
|
|
25368
26131
|
}
|
|
25369
26132
|
);
|
|
25370
26133
|
req.on("timeout", () => {
|
|
25371
26134
|
req.destroy();
|
|
25372
|
-
|
|
26135
|
+
resolve7(null);
|
|
25373
26136
|
});
|
|
25374
|
-
req.on("error", () =>
|
|
26137
|
+
req.on("error", () => resolve7(null));
|
|
25375
26138
|
});
|
|
25376
26139
|
}
|
|
25377
26140
|
function notifyIfStale(currentVersion, latest) {
|
|
@@ -25394,8 +26157,8 @@ function isLinkedInstall() {
|
|
|
25394
26157
|
timeout: 2e3
|
|
25395
26158
|
}).trim();
|
|
25396
26159
|
if (!root) return false;
|
|
25397
|
-
const pkgPath =
|
|
25398
|
-
return
|
|
26160
|
+
const pkgPath = path48.join(root, PKG_NAME);
|
|
26161
|
+
return fs37.lstatSync(pkgPath).isSymbolicLink();
|
|
25399
26162
|
} catch {
|
|
25400
26163
|
return false;
|
|
25401
26164
|
}
|
|
@@ -25431,7 +26194,7 @@ function maybeAutoUpdate(currentVersion, latest) {
|
|
|
25431
26194
|
return;
|
|
25432
26195
|
}
|
|
25433
26196
|
try {
|
|
25434
|
-
|
|
26197
|
+
fs37.unlinkSync(cachePath());
|
|
25435
26198
|
} catch {
|
|
25436
26199
|
}
|
|
25437
26200
|
process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
|
|
@@ -25448,7 +26211,7 @@ function checkForUpdates() {
|
|
|
25448
26211
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
25449
26212
|
if (process.env.CI) return;
|
|
25450
26213
|
if (!process.stdout.isTTY) return;
|
|
25451
|
-
const current = true ? "2.
|
|
26214
|
+
const current = true ? "2.33.0" : null;
|
|
25452
26215
|
if (!current) return;
|
|
25453
26216
|
const cache = readCache();
|
|
25454
26217
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|