codeam-cli 2.27.1 → 2.27.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.js +1054 -438
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -300,6 +300,18 @@ var AGENT_REGISTRY = {
|
|
|
300
300
|
// this via the existing --api-key escape hatch in commands/link.ts.
|
|
301
301
|
supportedAuthKinds: ["api_key"],
|
|
302
302
|
preferredAuthKind: "api_key"
|
|
303
|
+
},
|
|
304
|
+
gemini: {
|
|
305
|
+
id: "gemini",
|
|
306
|
+
displayName: "Gemini CLI",
|
|
307
|
+
binaryName: "gemini",
|
|
308
|
+
enabled: true,
|
|
309
|
+
// Gemini speaks ACP natively via `gemini --acp` — pairing flows
|
|
310
|
+
// through the ACP runtime, not a PTY parser. Auth is the user's
|
|
311
|
+
// existing `gemini auth login` (OAuth) or GEMINI_API_KEY env var,
|
|
312
|
+
// both managed by the gemini binary itself.
|
|
313
|
+
supportedAuthKinds: ["api_key"],
|
|
314
|
+
preferredAuthKind: "api_key"
|
|
303
315
|
}
|
|
304
316
|
};
|
|
305
317
|
function getEnabledAgents() {
|
|
@@ -311,7 +323,7 @@ function getAgent(id) {
|
|
|
311
323
|
return meta;
|
|
312
324
|
}
|
|
313
325
|
function isKnownAgentId(id) {
|
|
314
|
-
return id === "claude" || id === "codex" || id === "copilot" || id === "coderabbit" || id === "cursor" || id === "aider";
|
|
326
|
+
return id === "claude" || id === "codex" || id === "copilot" || id === "coderabbit" || id === "cursor" || id === "aider" || id === "gemini";
|
|
315
327
|
}
|
|
316
328
|
|
|
317
329
|
// ../../packages/shared/src/api-url.ts
|
|
@@ -486,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
486
498
|
// package.json
|
|
487
499
|
var package_default = {
|
|
488
500
|
name: "codeam-cli",
|
|
489
|
-
version: "2.27.
|
|
501
|
+
version: "2.27.2",
|
|
490
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.",
|
|
491
503
|
type: "commonjs",
|
|
492
504
|
main: "dist/index.js",
|
|
@@ -556,8 +568,12 @@ var package_default = {
|
|
|
556
568
|
node: ">=18.0.0"
|
|
557
569
|
},
|
|
558
570
|
dependencies: {
|
|
571
|
+
"@agentclientprotocol/claude-agent-acp": "^0.42.0",
|
|
572
|
+
"@agentclientprotocol/codex-acp": "^0.0.45",
|
|
573
|
+
"@agentclientprotocol/sdk": "^0.25.0",
|
|
559
574
|
"@clack/prompts": "^1.2.0",
|
|
560
575
|
chokidar: "^3.6.0",
|
|
576
|
+
"cursor-agent-acp": "^0.1.1",
|
|
561
577
|
picocolors: "^1.1.0",
|
|
562
578
|
"qrcode-terminal": "^0.12.0",
|
|
563
579
|
which: "^5.0.0",
|
|
@@ -853,7 +869,7 @@ async function postPreviewEvent(input) {
|
|
|
853
869
|
}
|
|
854
870
|
}
|
|
855
871
|
async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
856
|
-
return new Promise((
|
|
872
|
+
return new Promise((resolve6, reject) => {
|
|
857
873
|
const data = JSON.stringify(body);
|
|
858
874
|
const u2 = new URL(url);
|
|
859
875
|
const transport = u2.protocol === "https:" ? https : http;
|
|
@@ -874,8 +890,8 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
|
874
890
|
(res) => {
|
|
875
891
|
res.on("error", reject);
|
|
876
892
|
let responseBody = "";
|
|
877
|
-
res.on("data", (
|
|
878
|
-
responseBody +=
|
|
893
|
+
res.on("data", (chunk2) => {
|
|
894
|
+
responseBody += chunk2.toString();
|
|
879
895
|
});
|
|
880
896
|
res.on("end", () => {
|
|
881
897
|
if (res.statusCode && res.statusCode >= 400) {
|
|
@@ -885,9 +901,9 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
|
885
901
|
return;
|
|
886
902
|
}
|
|
887
903
|
try {
|
|
888
|
-
|
|
904
|
+
resolve6(JSON.parse(responseBody));
|
|
889
905
|
} catch {
|
|
890
|
-
|
|
906
|
+
resolve6(null);
|
|
891
907
|
}
|
|
892
908
|
});
|
|
893
909
|
}
|
|
@@ -902,7 +918,7 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
|
902
918
|
});
|
|
903
919
|
}
|
|
904
920
|
async function _postJson(url, body) {
|
|
905
|
-
return new Promise((
|
|
921
|
+
return new Promise((resolve6, reject) => {
|
|
906
922
|
const data = JSON.stringify(body);
|
|
907
923
|
const u2 = new URL(url);
|
|
908
924
|
const transport = u2.protocol === "https:" ? https : http;
|
|
@@ -922,8 +938,8 @@ async function _postJson(url, body) {
|
|
|
922
938
|
(res) => {
|
|
923
939
|
res.on("error", reject);
|
|
924
940
|
let body2 = "";
|
|
925
|
-
res.on("data", (
|
|
926
|
-
body2 +=
|
|
941
|
+
res.on("data", (chunk2) => {
|
|
942
|
+
body2 += chunk2.toString();
|
|
927
943
|
});
|
|
928
944
|
res.on("end", () => {
|
|
929
945
|
if (res.statusCode && res.statusCode >= 400) {
|
|
@@ -931,9 +947,9 @@ async function _postJson(url, body) {
|
|
|
931
947
|
return;
|
|
932
948
|
}
|
|
933
949
|
try {
|
|
934
|
-
|
|
950
|
+
resolve6(JSON.parse(body2));
|
|
935
951
|
} catch {
|
|
936
|
-
|
|
952
|
+
resolve6(null);
|
|
937
953
|
}
|
|
938
954
|
});
|
|
939
955
|
}
|
|
@@ -948,7 +964,7 @@ async function _postJson(url, body) {
|
|
|
948
964
|
});
|
|
949
965
|
}
|
|
950
966
|
async function _getJson(url) {
|
|
951
|
-
return new Promise((
|
|
967
|
+
return new Promise((resolve6, reject) => {
|
|
952
968
|
const u2 = new URL(url);
|
|
953
969
|
const transport = u2.protocol === "https:" ? https : http;
|
|
954
970
|
const req = transport.request(
|
|
@@ -963,8 +979,8 @@ async function _getJson(url) {
|
|
|
963
979
|
(res) => {
|
|
964
980
|
res.on("error", reject);
|
|
965
981
|
let body = "";
|
|
966
|
-
res.on("data", (
|
|
967
|
-
body +=
|
|
982
|
+
res.on("data", (chunk2) => {
|
|
983
|
+
body += chunk2.toString();
|
|
968
984
|
});
|
|
969
985
|
res.on("end", () => {
|
|
970
986
|
if (res.statusCode && res.statusCode >= 400) {
|
|
@@ -972,9 +988,9 @@ async function _getJson(url) {
|
|
|
972
988
|
return;
|
|
973
989
|
}
|
|
974
990
|
try {
|
|
975
|
-
|
|
991
|
+
resolve6(JSON.parse(body));
|
|
976
992
|
} catch {
|
|
977
|
-
|
|
993
|
+
resolve6(null);
|
|
978
994
|
}
|
|
979
995
|
});
|
|
980
996
|
}
|
|
@@ -1144,8 +1160,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
1144
1160
|
return decodedFile;
|
|
1145
1161
|
};
|
|
1146
1162
|
}
|
|
1147
|
-
function normalizeWindowsPath(
|
|
1148
|
-
return
|
|
1163
|
+
function normalizeWindowsPath(path44) {
|
|
1164
|
+
return path44.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
1149
1165
|
}
|
|
1150
1166
|
|
|
1151
1167
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -3625,15 +3641,15 @@ async function addSourceContext(frames) {
|
|
|
3625
3641
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
3626
3642
|
return frames;
|
|
3627
3643
|
}
|
|
3628
|
-
function getContextLinesFromFile(
|
|
3629
|
-
return new Promise((
|
|
3630
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
3644
|
+
function getContextLinesFromFile(path44, ranges, output) {
|
|
3645
|
+
return new Promise((resolve6) => {
|
|
3646
|
+
const stream = (0, import_node_fs.createReadStream)(path44);
|
|
3631
3647
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
3632
3648
|
input: stream
|
|
3633
3649
|
});
|
|
3634
3650
|
function destroyStreamAndResolve() {
|
|
3635
3651
|
stream.destroy();
|
|
3636
|
-
|
|
3652
|
+
resolve6();
|
|
3637
3653
|
}
|
|
3638
3654
|
let lineNumber = 0;
|
|
3639
3655
|
let currentRangeIndex = 0;
|
|
@@ -3642,7 +3658,7 @@ function getContextLinesFromFile(path43, ranges, output) {
|
|
|
3642
3658
|
let rangeStart = range[0];
|
|
3643
3659
|
let rangeEnd = range[1];
|
|
3644
3660
|
function onStreamError() {
|
|
3645
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
3661
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path44, 1);
|
|
3646
3662
|
lineReaded.close();
|
|
3647
3663
|
lineReaded.removeAllListeners();
|
|
3648
3664
|
destroyStreamAndResolve();
|
|
@@ -3703,8 +3719,8 @@ function clearLineContext(frame) {
|
|
|
3703
3719
|
delete frame.context_line;
|
|
3704
3720
|
delete frame.post_context;
|
|
3705
3721
|
}
|
|
3706
|
-
function shouldSkipContextLinesForFile(
|
|
3707
|
-
return
|
|
3722
|
+
function shouldSkipContextLinesForFile(path44) {
|
|
3723
|
+
return path44.startsWith("node:") || path44.endsWith(".min.js") || path44.endsWith(".min.cjs") || path44.endsWith(".min.mjs") || path44.startsWith("data:");
|
|
3708
3724
|
}
|
|
3709
3725
|
function shouldSkipContextLinesForFrame(frame) {
|
|
3710
3726
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -4920,9 +4936,9 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4920
4936
|
if (!waitUntil) return;
|
|
4921
4937
|
if (this.disabled || this.optedOut) return;
|
|
4922
4938
|
if (!this._waitUntilCycle) {
|
|
4923
|
-
let
|
|
4939
|
+
let resolve6;
|
|
4924
4940
|
const promise = new Promise((r) => {
|
|
4925
|
-
|
|
4941
|
+
resolve6 = r;
|
|
4926
4942
|
});
|
|
4927
4943
|
try {
|
|
4928
4944
|
waitUntil(promise);
|
|
@@ -4930,7 +4946,7 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4930
4946
|
return;
|
|
4931
4947
|
}
|
|
4932
4948
|
this._waitUntilCycle = {
|
|
4933
|
-
resolve:
|
|
4949
|
+
resolve: resolve6,
|
|
4934
4950
|
startedAt: Date.now(),
|
|
4935
4951
|
timer: void 0
|
|
4936
4952
|
};
|
|
@@ -4954,12 +4970,12 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4954
4970
|
return cycle?.resolve;
|
|
4955
4971
|
}
|
|
4956
4972
|
async resolveWaitUntilFlush() {
|
|
4957
|
-
const
|
|
4973
|
+
const resolve6 = this._consumeWaitUntilCycle();
|
|
4958
4974
|
try {
|
|
4959
4975
|
await super.flush();
|
|
4960
4976
|
} catch {
|
|
4961
4977
|
} finally {
|
|
4962
|
-
|
|
4978
|
+
resolve6?.();
|
|
4963
4979
|
}
|
|
4964
4980
|
}
|
|
4965
4981
|
getPersistedProperty(key) {
|
|
@@ -5051,15 +5067,15 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
5051
5067
|
async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
|
|
5052
5068
|
if (this.isLocalEvaluationReady()) return true;
|
|
5053
5069
|
if (void 0 === this.featureFlagsPoller) return false;
|
|
5054
|
-
return new Promise((
|
|
5070
|
+
return new Promise((resolve6) => {
|
|
5055
5071
|
const timeout = setTimeout(() => {
|
|
5056
5072
|
cleanup();
|
|
5057
|
-
|
|
5073
|
+
resolve6(false);
|
|
5058
5074
|
}, timeoutMs);
|
|
5059
5075
|
const cleanup = this._events.on("localEvaluationFlagsLoaded", (count) => {
|
|
5060
5076
|
clearTimeout(timeout);
|
|
5061
5077
|
cleanup();
|
|
5062
|
-
|
|
5078
|
+
resolve6(count > 0);
|
|
5063
5079
|
});
|
|
5064
5080
|
});
|
|
5065
5081
|
}
|
|
@@ -5496,13 +5512,13 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
5496
5512
|
this.context?.enter(data, options);
|
|
5497
5513
|
}
|
|
5498
5514
|
async _shutdown(shutdownTimeoutMs) {
|
|
5499
|
-
const
|
|
5515
|
+
const resolve6 = this._consumeWaitUntilCycle();
|
|
5500
5516
|
await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
|
|
5501
5517
|
this.errorTracking.shutdown();
|
|
5502
5518
|
try {
|
|
5503
5519
|
return await super._shutdown(shutdownTimeoutMs);
|
|
5504
5520
|
} finally {
|
|
5505
|
-
|
|
5521
|
+
resolve6?.();
|
|
5506
5522
|
}
|
|
5507
5523
|
}
|
|
5508
5524
|
async _requestRemoteConfigPayload(flagKey) {
|
|
@@ -5858,7 +5874,7 @@ function readAnonId() {
|
|
|
5858
5874
|
}
|
|
5859
5875
|
function superProperties() {
|
|
5860
5876
|
return {
|
|
5861
|
-
cliVersion: true ? "2.27.
|
|
5877
|
+
cliVersion: true ? "2.27.2" : "0.0.0-dev",
|
|
5862
5878
|
nodeVersion: process.version,
|
|
5863
5879
|
platform: process.platform,
|
|
5864
5880
|
arch: process.arch,
|
|
@@ -6065,9 +6081,9 @@ var CommandRelayService = class {
|
|
|
6065
6081
|
this.armSseWatchdog();
|
|
6066
6082
|
let buffer = "";
|
|
6067
6083
|
res.setEncoding("utf8");
|
|
6068
|
-
res.on("data", (
|
|
6084
|
+
res.on("data", (chunk2) => {
|
|
6069
6085
|
this.sseLastByteAt = Date.now();
|
|
6070
|
-
buffer +=
|
|
6086
|
+
buffer += chunk2;
|
|
6071
6087
|
let frameEnd;
|
|
6072
6088
|
while ((frameEnd = buffer.indexOf("\n\n")) !== -1) {
|
|
6073
6089
|
const frame = buffer.slice(0, frameEnd);
|
|
@@ -6736,9 +6752,9 @@ var UnixPtyStrategy = class {
|
|
|
6736
6752
|
);
|
|
6737
6753
|
process.exit(1);
|
|
6738
6754
|
});
|
|
6739
|
-
this.proc.stdout?.on("data", (
|
|
6740
|
-
process.stdout.write(
|
|
6741
|
-
this.opts.onData(
|
|
6755
|
+
this.proc.stdout?.on("data", (chunk2) => {
|
|
6756
|
+
process.stdout.write(chunk2);
|
|
6757
|
+
this.opts.onData(chunk2.toString("utf8"));
|
|
6742
6758
|
});
|
|
6743
6759
|
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
6744
6760
|
process.stdin.resume();
|
|
@@ -6830,8 +6846,8 @@ var UnixPtyStrategy = class {
|
|
|
6830
6846
|
}
|
|
6831
6847
|
}
|
|
6832
6848
|
}
|
|
6833
|
-
stdinHandler = (
|
|
6834
|
-
this.proc?.stdin?.write(
|
|
6849
|
+
stdinHandler = (chunk2) => {
|
|
6850
|
+
this.proc?.stdin?.write(chunk2);
|
|
6835
6851
|
};
|
|
6836
6852
|
handleResize = () => {
|
|
6837
6853
|
if (this.proc?.pid) {
|
|
@@ -7017,8 +7033,8 @@ var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
|
|
|
7017
7033
|
}
|
|
7018
7034
|
this.pty = null;
|
|
7019
7035
|
}
|
|
7020
|
-
stdinHandler = (
|
|
7021
|
-
this.pty?.write(
|
|
7036
|
+
stdinHandler = (chunk2) => {
|
|
7037
|
+
this.pty?.write(chunk2.toString("utf8"));
|
|
7022
7038
|
};
|
|
7023
7039
|
};
|
|
7024
7040
|
|
|
@@ -7051,9 +7067,9 @@ var WindowsPtyStrategy = class {
|
|
|
7051
7067
|
);
|
|
7052
7068
|
process.exit(1);
|
|
7053
7069
|
});
|
|
7054
|
-
this.proc.stdout?.on("data", (
|
|
7055
|
-
process.stdout.write(
|
|
7056
|
-
this.opts.onData(
|
|
7070
|
+
this.proc.stdout?.on("data", (chunk2) => {
|
|
7071
|
+
process.stdout.write(chunk2);
|
|
7072
|
+
this.opts.onData(chunk2.toString("utf8"));
|
|
7057
7073
|
});
|
|
7058
7074
|
this.proc.stdin?.write("");
|
|
7059
7075
|
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
@@ -7080,8 +7096,8 @@ var WindowsPtyStrategy = class {
|
|
|
7080
7096
|
}
|
|
7081
7097
|
}
|
|
7082
7098
|
}
|
|
7083
|
-
stdinHandler = (
|
|
7084
|
-
this.proc?.stdin?.write(
|
|
7099
|
+
stdinHandler = (chunk2) => {
|
|
7100
|
+
this.proc?.stdin?.write(chunk2);
|
|
7085
7101
|
};
|
|
7086
7102
|
};
|
|
7087
7103
|
|
|
@@ -9159,15 +9175,15 @@ function runInstaller() {
|
|
|
9159
9175
|
"-Command",
|
|
9160
9176
|
"irm https://claude.ai/install.ps1 | iex"
|
|
9161
9177
|
] : ["-c", "curl -fsSL https://claude.ai/install.sh | bash"];
|
|
9162
|
-
return new Promise((
|
|
9178
|
+
return new Promise((resolve6) => {
|
|
9163
9179
|
const proc = (0, import_child_process4.spawn)(cmd, args2, { stdio: "inherit" });
|
|
9164
9180
|
proc.on("error", (err) => {
|
|
9165
9181
|
console.error(`
|
|
9166
9182
|
\u2717 Installer failed to launch: ${err.message}`);
|
|
9167
|
-
|
|
9183
|
+
resolve6(false);
|
|
9168
9184
|
});
|
|
9169
9185
|
proc.on("exit", (code) => {
|
|
9170
|
-
|
|
9186
|
+
resolve6(code === 0);
|
|
9171
9187
|
});
|
|
9172
9188
|
});
|
|
9173
9189
|
}
|
|
@@ -9344,17 +9360,17 @@ function parseUsageOutput(raw) {
|
|
|
9344
9360
|
return { percent, resetAt };
|
|
9345
9361
|
}
|
|
9346
9362
|
async function fetchClaudeQuota() {
|
|
9347
|
-
return new Promise((
|
|
9363
|
+
return new Promise((resolve6) => {
|
|
9348
9364
|
const claudeCmd = findInPath("claude") ? "claude" : "claude-code";
|
|
9349
9365
|
if (!claudeCmd) {
|
|
9350
|
-
|
|
9366
|
+
resolve6(null);
|
|
9351
9367
|
return;
|
|
9352
9368
|
}
|
|
9353
9369
|
const helperPath = path11.join(os10.tmpdir(), "codeam-quota-helper.py");
|
|
9354
9370
|
fs8.writeFileSync(helperPath, HELPER_SCRIPT, { mode: 420 });
|
|
9355
9371
|
const python = findInPath("python3") ?? findInPath("python");
|
|
9356
9372
|
if (!python) {
|
|
9357
|
-
|
|
9373
|
+
resolve6(null);
|
|
9358
9374
|
return;
|
|
9359
9375
|
}
|
|
9360
9376
|
const proc = (0, import_child_process5.spawn)(python, [helperPath, claudeCmd, "--tools", ""], {
|
|
@@ -9364,8 +9380,8 @@ async function fetchClaudeQuota() {
|
|
|
9364
9380
|
});
|
|
9365
9381
|
let output = "";
|
|
9366
9382
|
let resolved = false;
|
|
9367
|
-
proc.stdout?.on("data", (
|
|
9368
|
-
output +=
|
|
9383
|
+
proc.stdout?.on("data", (chunk2) => {
|
|
9384
|
+
output += chunk2.toString("utf8");
|
|
9369
9385
|
});
|
|
9370
9386
|
setTimeout(() => {
|
|
9371
9387
|
proc.stdin?.write("/usage\r");
|
|
@@ -9381,13 +9397,13 @@ async function fetchClaudeQuota() {
|
|
|
9381
9397
|
fs8.unlinkSync(helperPath);
|
|
9382
9398
|
} catch {
|
|
9383
9399
|
}
|
|
9384
|
-
|
|
9400
|
+
resolve6(result);
|
|
9385
9401
|
}, 5e3);
|
|
9386
9402
|
}, 8e3);
|
|
9387
9403
|
setTimeout(() => {
|
|
9388
9404
|
if (!resolved) {
|
|
9389
9405
|
resolved = true;
|
|
9390
|
-
|
|
9406
|
+
resolve6(null);
|
|
9391
9407
|
}
|
|
9392
9408
|
try {
|
|
9393
9409
|
proc.kill();
|
|
@@ -9418,12 +9434,12 @@ function killActiveSpawnAndCaptureChildren() {
|
|
|
9418
9434
|
}
|
|
9419
9435
|
async function spawnAndCapture(cmd, args2, opts = {}) {
|
|
9420
9436
|
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
9421
|
-
return new Promise((
|
|
9437
|
+
return new Promise((resolve6) => {
|
|
9422
9438
|
let settled = false;
|
|
9423
9439
|
const settle = (value) => {
|
|
9424
9440
|
if (settled) return;
|
|
9425
9441
|
settled = true;
|
|
9426
|
-
|
|
9442
|
+
resolve6(value);
|
|
9427
9443
|
};
|
|
9428
9444
|
let child;
|
|
9429
9445
|
try {
|
|
@@ -9438,11 +9454,11 @@ async function spawnAndCapture(cmd, args2, opts = {}) {
|
|
|
9438
9454
|
}
|
|
9439
9455
|
activeChildren.add(child);
|
|
9440
9456
|
let stdout = "";
|
|
9441
|
-
child.stdout?.on("data", (
|
|
9442
|
-
stdout +=
|
|
9457
|
+
child.stdout?.on("data", (chunk2) => {
|
|
9458
|
+
stdout += chunk2.toString("utf8");
|
|
9443
9459
|
});
|
|
9444
|
-
child.stderr?.on("data", (
|
|
9445
|
-
opts.onStderr?.(
|
|
9460
|
+
child.stderr?.on("data", (chunk2) => {
|
|
9461
|
+
opts.onStderr?.(chunk2.toString("utf8"));
|
|
9446
9462
|
});
|
|
9447
9463
|
const timer = setTimeout(() => {
|
|
9448
9464
|
try {
|
|
@@ -9930,13 +9946,13 @@ function detectStartupBanner(lines) {
|
|
|
9930
9946
|
while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
|
|
9931
9947
|
if (metaIdx - artStart < 2) return null;
|
|
9932
9948
|
const pathLine = (lines[metaIdx + 1] ?? "").trim();
|
|
9933
|
-
const
|
|
9949
|
+
const path44 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
|
|
9934
9950
|
return {
|
|
9935
9951
|
title: "",
|
|
9936
9952
|
subtitle: lines[metaIdx].trim(),
|
|
9937
|
-
path:
|
|
9953
|
+
path: path44,
|
|
9938
9954
|
startIdx: artStart,
|
|
9939
|
-
endIdx: metaIdx + (
|
|
9955
|
+
endIdx: metaIdx + (path44 ? 1 : 0)
|
|
9940
9956
|
};
|
|
9941
9957
|
}
|
|
9942
9958
|
|
|
@@ -11090,12 +11106,12 @@ function resolveNpm(os27) {
|
|
|
11090
11106
|
return os27.id === "win32" ? "npm.cmd" : "npm";
|
|
11091
11107
|
}
|
|
11092
11108
|
async function installCodexViaNpm(os27) {
|
|
11093
|
-
return new Promise((
|
|
11109
|
+
return new Promise((resolve6, reject) => {
|
|
11094
11110
|
const proc = (0, import_node_child_process4.spawn)(resolveNpm(os27), ["install", "-g", "@openai/codex"], {
|
|
11095
11111
|
stdio: "inherit"
|
|
11096
11112
|
});
|
|
11097
11113
|
proc.on("close", (code) => {
|
|
11098
|
-
if (code === 0)
|
|
11114
|
+
if (code === 0) resolve6();
|
|
11099
11115
|
else reject(new Error(`npm install -g @openai/codex exited ${code}`));
|
|
11100
11116
|
});
|
|
11101
11117
|
proc.on("error", (err) => {
|
|
@@ -11210,12 +11226,12 @@ async function ensureCoderabbitInstalled(os27) {
|
|
|
11210
11226
|
return false;
|
|
11211
11227
|
}
|
|
11212
11228
|
console.log("\n CodeRabbit CLI not found \u2014 installing via the official script\u2026\n");
|
|
11213
|
-
const ok = await new Promise((
|
|
11229
|
+
const ok = await new Promise((resolve6) => {
|
|
11214
11230
|
const proc = (0, import_node_child_process5.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL} | sh`], {
|
|
11215
11231
|
stdio: "inherit"
|
|
11216
11232
|
});
|
|
11217
|
-
proc.on("close", (code) =>
|
|
11218
|
-
proc.on("error", () =>
|
|
11233
|
+
proc.on("close", (code) => resolve6(code === 0));
|
|
11234
|
+
proc.on("error", () => resolve6(false));
|
|
11219
11235
|
});
|
|
11220
11236
|
if (!ok) return false;
|
|
11221
11237
|
os27.augmentPath([`${os27.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
@@ -11272,11 +11288,11 @@ function parseReview(stdout) {
|
|
|
11272
11288
|
for (const line of lines) {
|
|
11273
11289
|
const m = line.match(HUNK_LINE_RE);
|
|
11274
11290
|
if (!m) continue;
|
|
11275
|
-
const [,
|
|
11276
|
-
if (!
|
|
11291
|
+
const [, path44, lineNo, sevToken, message] = m;
|
|
11292
|
+
if (!path44 || !lineNo || !message) continue;
|
|
11277
11293
|
const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
|
|
11278
11294
|
hunks.push({
|
|
11279
|
-
path:
|
|
11295
|
+
path: path44.trim(),
|
|
11280
11296
|
line: Number(lineNo),
|
|
11281
11297
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
11282
11298
|
message: cleanedMessage
|
|
@@ -11334,7 +11350,7 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11334
11350
|
}
|
|
11335
11351
|
async runOneShot(input) {
|
|
11336
11352
|
const launch = await this.prepareInvocation(input);
|
|
11337
|
-
return new Promise((
|
|
11353
|
+
return new Promise((resolve6, reject) => {
|
|
11338
11354
|
const stdoutBuf = [];
|
|
11339
11355
|
const stderrBuf = [];
|
|
11340
11356
|
const proc = (0, import_node_child_process7.spawn)(launch.cmd, launch.args, {
|
|
@@ -11345,7 +11361,7 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11345
11361
|
proc.stderr?.on("data", (b) => stderrBuf.push(b));
|
|
11346
11362
|
proc.on("error", (err) => reject(err));
|
|
11347
11363
|
proc.on("close", (code) => {
|
|
11348
|
-
|
|
11364
|
+
resolve6(
|
|
11349
11365
|
this.parseOutput({
|
|
11350
11366
|
exitCode: code ?? 0,
|
|
11351
11367
|
stdout: Buffer.concat(stdoutBuf).toString("utf8"),
|
|
@@ -11795,6 +11811,681 @@ function createDeployStrategy(agent) {
|
|
|
11795
11811
|
return build();
|
|
11796
11812
|
}
|
|
11797
11813
|
|
|
11814
|
+
// src/agents/acp/adapters.ts
|
|
11815
|
+
var path24 = __toESM(require("path"));
|
|
11816
|
+
var require_ = require;
|
|
11817
|
+
function resolveBin(pkgName, binName) {
|
|
11818
|
+
try {
|
|
11819
|
+
const manifestPath = require_.resolve(`${pkgName}/package.json`);
|
|
11820
|
+
const manifest = require_(`${pkgName}/package.json`);
|
|
11821
|
+
const pkgDir = path24.dirname(manifestPath);
|
|
11822
|
+
const bin = manifest.bin;
|
|
11823
|
+
if (!bin) return null;
|
|
11824
|
+
if (typeof bin === "string") return path24.resolve(pkgDir, bin);
|
|
11825
|
+
const target = binName ?? Object.keys(bin)[0];
|
|
11826
|
+
if (!target || !bin[target]) return null;
|
|
11827
|
+
return path24.resolve(pkgDir, bin[target]);
|
|
11828
|
+
} catch {
|
|
11829
|
+
return null;
|
|
11830
|
+
}
|
|
11831
|
+
}
|
|
11832
|
+
var REGISTRY = {
|
|
11833
|
+
claude: () => {
|
|
11834
|
+
const bin = resolveBin("@agentclientprotocol/claude-agent-acp", "claude-agent-acp");
|
|
11835
|
+
if (!bin) return null;
|
|
11836
|
+
return {
|
|
11837
|
+
command: process.execPath,
|
|
11838
|
+
args: [bin],
|
|
11839
|
+
requiresAgentBinary: "claude"
|
|
11840
|
+
};
|
|
11841
|
+
},
|
|
11842
|
+
codex: () => {
|
|
11843
|
+
const bin = resolveBin("@agentclientprotocol/codex-acp", "codex-acp");
|
|
11844
|
+
if (!bin) return null;
|
|
11845
|
+
return {
|
|
11846
|
+
command: process.execPath,
|
|
11847
|
+
args: [bin],
|
|
11848
|
+
requiresAgentBinary: "codex"
|
|
11849
|
+
};
|
|
11850
|
+
},
|
|
11851
|
+
cursor: () => {
|
|
11852
|
+
const bin = resolveBin("cursor-agent-acp", "cursor-agent-acp");
|
|
11853
|
+
if (!bin) return null;
|
|
11854
|
+
return {
|
|
11855
|
+
command: process.execPath,
|
|
11856
|
+
args: [bin],
|
|
11857
|
+
requiresAgentBinary: "cursor-agent"
|
|
11858
|
+
};
|
|
11859
|
+
},
|
|
11860
|
+
// Gemini speaks ACP natively via `gemini --acp` — no npm adapter
|
|
11861
|
+
// package, just the user-installed `gemini` binary on PATH. Same
|
|
11862
|
+
// {@link AdapterSpec} shape; the only difference is `command` is
|
|
11863
|
+
// resolved from PATH at spawn time instead of being absolute.
|
|
11864
|
+
gemini: () => ({
|
|
11865
|
+
command: "gemini",
|
|
11866
|
+
args: ["--acp"],
|
|
11867
|
+
requiresAgentBinary: "gemini"
|
|
11868
|
+
})
|
|
11869
|
+
};
|
|
11870
|
+
function getAcpAdapter(agent) {
|
|
11871
|
+
const factory = REGISTRY[agent];
|
|
11872
|
+
return factory ? factory() : null;
|
|
11873
|
+
}
|
|
11874
|
+
|
|
11875
|
+
// src/agents/acp/runner.ts
|
|
11876
|
+
var import_node_crypto6 = require("crypto");
|
|
11877
|
+
|
|
11878
|
+
// src/agents/acp/client.ts
|
|
11879
|
+
var import_node_child_process10 = require("child_process");
|
|
11880
|
+
var fs20 = __toESM(require("fs/promises"));
|
|
11881
|
+
var import_node_stream = require("stream");
|
|
11882
|
+
var import_sdk = require("@agentclientprotocol/sdk");
|
|
11883
|
+
var PROTOCOL_VERSION2 = 1;
|
|
11884
|
+
var CLIENT_CAPABILITIES = {
|
|
11885
|
+
fs: { readTextFile: true, writeTextFile: true },
|
|
11886
|
+
terminal: false
|
|
11887
|
+
};
|
|
11888
|
+
var AcpClient = class {
|
|
11889
|
+
constructor(opts) {
|
|
11890
|
+
this.opts = opts;
|
|
11891
|
+
}
|
|
11892
|
+
opts;
|
|
11893
|
+
child = null;
|
|
11894
|
+
connection = null;
|
|
11895
|
+
stopping = false;
|
|
11896
|
+
sessionId = null;
|
|
11897
|
+
/**
|
|
11898
|
+
* Spawn the adapter + perform the initial handshake (initialize
|
|
11899
|
+
* → newSession). Returns the ACP-assigned sessionId so the
|
|
11900
|
+
* caller can route subsequent prompts.
|
|
11901
|
+
*/
|
|
11902
|
+
async start() {
|
|
11903
|
+
if (this.child) throw new Error("AcpClient already started");
|
|
11904
|
+
const { adapter, cwd } = this.opts;
|
|
11905
|
+
const child = (0, import_node_child_process10.spawn)(adapter.command, adapter.args, {
|
|
11906
|
+
cwd,
|
|
11907
|
+
env: process.env,
|
|
11908
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
11909
|
+
});
|
|
11910
|
+
this.child = child;
|
|
11911
|
+
child.stderr?.setEncoding("utf8");
|
|
11912
|
+
child.stderr?.on("data", (chunk2) => {
|
|
11913
|
+
for (const line of chunk2.split(/\r?\n/)) {
|
|
11914
|
+
const trimmed = line.trim();
|
|
11915
|
+
if (trimmed) this.opts.onStderr?.(trimmed);
|
|
11916
|
+
}
|
|
11917
|
+
});
|
|
11918
|
+
child.on("exit", (code, signal) => {
|
|
11919
|
+
if (this.stopping) return;
|
|
11920
|
+
log.warn("acpClient", `adapter exited unexpectedly code=${code} signal=${signal}`);
|
|
11921
|
+
this.opts.onUnexpectedExit?.(code, signal);
|
|
11922
|
+
});
|
|
11923
|
+
if (!child.stdin || !child.stdout) {
|
|
11924
|
+
throw new Error("Spawned ACP adapter is missing stdio handles");
|
|
11925
|
+
}
|
|
11926
|
+
const input = import_node_stream.Readable.toWeb(child.stdout);
|
|
11927
|
+
const output = import_node_stream.Writable.toWeb(child.stdin);
|
|
11928
|
+
const stream = (0, import_sdk.ndJsonStream)(output, input);
|
|
11929
|
+
this.connection = new import_sdk.ClientSideConnection(
|
|
11930
|
+
(_agent) => this.buildClient(),
|
|
11931
|
+
stream
|
|
11932
|
+
);
|
|
11933
|
+
const initialize = await this.connection.initialize({
|
|
11934
|
+
protocolVersion: PROTOCOL_VERSION2,
|
|
11935
|
+
clientCapabilities: CLIENT_CAPABILITIES
|
|
11936
|
+
});
|
|
11937
|
+
const newSession = await this.connection.newSession({
|
|
11938
|
+
cwd,
|
|
11939
|
+
mcpServers: []
|
|
11940
|
+
});
|
|
11941
|
+
this.sessionId = newSession.sessionId;
|
|
11942
|
+
return { sessionId: newSession.sessionId, initialize };
|
|
11943
|
+
}
|
|
11944
|
+
/**
|
|
11945
|
+
* Send a user prompt to the active session. Returns the
|
|
11946
|
+
* {@link PromptResponse} which carries the agent's stop reason
|
|
11947
|
+
* once the turn finishes. Session/update notifications keep
|
|
11948
|
+
* arriving on `onSessionUpdate` while the turn streams.
|
|
11949
|
+
*/
|
|
11950
|
+
async prompt(text) {
|
|
11951
|
+
if (!this.connection || !this.sessionId) {
|
|
11952
|
+
throw new Error("AcpClient.prompt called before start()");
|
|
11953
|
+
}
|
|
11954
|
+
return this.connection.prompt({
|
|
11955
|
+
sessionId: this.sessionId,
|
|
11956
|
+
prompt: [{ type: "text", text }]
|
|
11957
|
+
});
|
|
11958
|
+
}
|
|
11959
|
+
/**
|
|
11960
|
+
* Cancel the in-flight prompt turn. Notification — no response.
|
|
11961
|
+
* Safe to call when nothing is in flight (the adapter no-ops).
|
|
11962
|
+
*/
|
|
11963
|
+
async cancel() {
|
|
11964
|
+
if (!this.connection || !this.sessionId) return;
|
|
11965
|
+
await this.connection.cancel({ sessionId: this.sessionId });
|
|
11966
|
+
}
|
|
11967
|
+
/**
|
|
11968
|
+
* Kill the adapter process and tear down the connection. Safe
|
|
11969
|
+
* to call multiple times. Suppresses the unexpected-exit
|
|
11970
|
+
* callback for this teardown.
|
|
11971
|
+
*/
|
|
11972
|
+
async stop() {
|
|
11973
|
+
this.stopping = true;
|
|
11974
|
+
const child = this.child;
|
|
11975
|
+
if (!child) return;
|
|
11976
|
+
this.child = null;
|
|
11977
|
+
this.connection = null;
|
|
11978
|
+
this.sessionId = null;
|
|
11979
|
+
try {
|
|
11980
|
+
child.kill("SIGTERM");
|
|
11981
|
+
const grace = new Promise((resolve6) => {
|
|
11982
|
+
const t2 = setTimeout(() => {
|
|
11983
|
+
try {
|
|
11984
|
+
child.kill("SIGKILL");
|
|
11985
|
+
} catch {
|
|
11986
|
+
}
|
|
11987
|
+
resolve6();
|
|
11988
|
+
}, 2e3);
|
|
11989
|
+
child.once("exit", () => {
|
|
11990
|
+
clearTimeout(t2);
|
|
11991
|
+
resolve6();
|
|
11992
|
+
});
|
|
11993
|
+
});
|
|
11994
|
+
await grace;
|
|
11995
|
+
} catch (err) {
|
|
11996
|
+
log.trace("acpClient", "stop teardown error", err);
|
|
11997
|
+
}
|
|
11998
|
+
}
|
|
11999
|
+
// ─── Client surface (what the agent calls into) ───────────────────
|
|
12000
|
+
buildClient() {
|
|
12001
|
+
return {
|
|
12002
|
+
sessionUpdate: async (params) => {
|
|
12003
|
+
this.opts.onSessionUpdate(params);
|
|
12004
|
+
},
|
|
12005
|
+
requestPermission: (params) => {
|
|
12006
|
+
return this.opts.onRequestPermission(params);
|
|
12007
|
+
},
|
|
12008
|
+
readTextFile: async (params) => {
|
|
12009
|
+
const content = await fs20.readFile(params.path, "utf8");
|
|
12010
|
+
return applyLineRange(content, params.line ?? null, params.limit ?? null);
|
|
12011
|
+
},
|
|
12012
|
+
writeTextFile: async (params) => {
|
|
12013
|
+
await fs20.writeFile(params.path, params.content, "utf8");
|
|
12014
|
+
return {};
|
|
12015
|
+
},
|
|
12016
|
+
// Terminal capability is declared `false` above so adapters
|
|
12017
|
+
// shouldn't call these; provide explicit "not implemented"
|
|
12018
|
+
// stubs so a misbehaving adapter gets a clean error instead
|
|
12019
|
+
// of a hung promise.
|
|
12020
|
+
createTerminal: async () => {
|
|
12021
|
+
throw new Error("terminal capability not implemented in this client (Phase 1)");
|
|
12022
|
+
},
|
|
12023
|
+
terminalOutput: async () => {
|
|
12024
|
+
throw new Error("terminal capability not implemented in this client (Phase 1)");
|
|
12025
|
+
},
|
|
12026
|
+
releaseTerminal: async () => {
|
|
12027
|
+
throw new Error("terminal capability not implemented in this client (Phase 1)");
|
|
12028
|
+
},
|
|
12029
|
+
waitForTerminalExit: async () => {
|
|
12030
|
+
throw new Error("terminal capability not implemented in this client (Phase 1)");
|
|
12031
|
+
},
|
|
12032
|
+
killTerminal: async () => {
|
|
12033
|
+
throw new Error("terminal capability not implemented in this client (Phase 1)");
|
|
12034
|
+
}
|
|
12035
|
+
};
|
|
12036
|
+
}
|
|
12037
|
+
};
|
|
12038
|
+
function applyLineRange(content, line, limit) {
|
|
12039
|
+
if (line === null && limit === null) return { content };
|
|
12040
|
+
const lines = content.split("\n");
|
|
12041
|
+
const start2 = Math.max(0, (line ?? 1) - 1);
|
|
12042
|
+
const end = limit !== null ? start2 + limit : lines.length;
|
|
12043
|
+
return { content: lines.slice(start2, end).join("\n") };
|
|
12044
|
+
}
|
|
12045
|
+
|
|
12046
|
+
// src/services/streaming/transport.ts
|
|
12047
|
+
var http3 = __toESM(require("http"));
|
|
12048
|
+
var https3 = __toESM(require("https"));
|
|
12049
|
+
var _transport2 = {
|
|
12050
|
+
post: _post,
|
|
12051
|
+
get: _get
|
|
12052
|
+
};
|
|
12053
|
+
function _post(url, headers, payload) {
|
|
12054
|
+
return new Promise((resolve6, reject) => {
|
|
12055
|
+
let settled = false;
|
|
12056
|
+
const u2 = new URL(url);
|
|
12057
|
+
const lib = u2.protocol === "https:" ? https3 : http3;
|
|
12058
|
+
const req = lib.request(
|
|
12059
|
+
{
|
|
12060
|
+
hostname: u2.hostname,
|
|
12061
|
+
port: u2.port || (u2.protocol === "https:" ? 443 : 80),
|
|
12062
|
+
path: u2.pathname + u2.search,
|
|
12063
|
+
method: "POST",
|
|
12064
|
+
headers: {
|
|
12065
|
+
...headers,
|
|
12066
|
+
...vercelBypassHeader(),
|
|
12067
|
+
"Content-Length": Buffer.byteLength(payload)
|
|
12068
|
+
},
|
|
12069
|
+
timeout: 8e3
|
|
12070
|
+
},
|
|
12071
|
+
(res) => {
|
|
12072
|
+
let body = "";
|
|
12073
|
+
res.on("data", (c2) => {
|
|
12074
|
+
body += c2.toString();
|
|
12075
|
+
});
|
|
12076
|
+
res.on("end", () => {
|
|
12077
|
+
if (settled) return;
|
|
12078
|
+
settled = true;
|
|
12079
|
+
resolve6({ statusCode: res.statusCode ?? 0, body });
|
|
12080
|
+
});
|
|
12081
|
+
}
|
|
12082
|
+
);
|
|
12083
|
+
req.on("error", (err) => {
|
|
12084
|
+
if (settled) return;
|
|
12085
|
+
settled = true;
|
|
12086
|
+
reject(err);
|
|
12087
|
+
});
|
|
12088
|
+
req.on("timeout", () => {
|
|
12089
|
+
req.destroy();
|
|
12090
|
+
});
|
|
12091
|
+
req.write(payload);
|
|
12092
|
+
req.end();
|
|
12093
|
+
});
|
|
12094
|
+
}
|
|
12095
|
+
function _get(url, headers) {
|
|
12096
|
+
return new Promise((resolve6, reject) => {
|
|
12097
|
+
let settled = false;
|
|
12098
|
+
const u2 = new URL(url);
|
|
12099
|
+
const lib = u2.protocol === "https:" ? https3 : http3;
|
|
12100
|
+
const req = lib.request(
|
|
12101
|
+
{
|
|
12102
|
+
hostname: u2.hostname,
|
|
12103
|
+
port: u2.port || (u2.protocol === "https:" ? 443 : 80),
|
|
12104
|
+
path: u2.pathname + u2.search,
|
|
12105
|
+
method: "GET",
|
|
12106
|
+
headers: {
|
|
12107
|
+
...headers,
|
|
12108
|
+
...vercelBypassHeader()
|
|
12109
|
+
},
|
|
12110
|
+
timeout: 8e3
|
|
12111
|
+
},
|
|
12112
|
+
(res) => {
|
|
12113
|
+
let body = "";
|
|
12114
|
+
res.on("data", (c2) => {
|
|
12115
|
+
body += c2.toString();
|
|
12116
|
+
});
|
|
12117
|
+
res.on("end", () => {
|
|
12118
|
+
if (settled) return;
|
|
12119
|
+
settled = true;
|
|
12120
|
+
resolve6({ statusCode: res.statusCode ?? 0, body });
|
|
12121
|
+
});
|
|
12122
|
+
}
|
|
12123
|
+
);
|
|
12124
|
+
req.on("error", (err) => {
|
|
12125
|
+
if (settled) return;
|
|
12126
|
+
settled = true;
|
|
12127
|
+
reject(err);
|
|
12128
|
+
});
|
|
12129
|
+
req.on("timeout", () => {
|
|
12130
|
+
req.destroy();
|
|
12131
|
+
});
|
|
12132
|
+
req.end();
|
|
12133
|
+
});
|
|
12134
|
+
}
|
|
12135
|
+
|
|
12136
|
+
// src/agents/acp/publisher.ts
|
|
12137
|
+
var AcpPublisher = class {
|
|
12138
|
+
constructor(opts) {
|
|
12139
|
+
this.opts = opts;
|
|
12140
|
+
this.apiBase = opts.apiBaseUrl ?? resolveApiBaseUrl();
|
|
12141
|
+
this.headers = {
|
|
12142
|
+
"Content-Type": "application/json",
|
|
12143
|
+
"X-Codeam-Protocol-Version": "2.0.0",
|
|
12144
|
+
"X-Plugin-Auth-Token": opts.pluginAuthToken
|
|
12145
|
+
};
|
|
12146
|
+
}
|
|
12147
|
+
opts;
|
|
12148
|
+
apiBase;
|
|
12149
|
+
headers;
|
|
12150
|
+
/**
|
|
12151
|
+
* Fire-and-forget chunk POST. The backend's per-user SSE bus
|
|
12152
|
+
* forwards each chunk to mobile/landing within ~20 ms (PRO) /
|
|
12153
|
+
* ~80 ms (FREE). Errors are logged but never thrown — a missed
|
|
12154
|
+
* chunk shouldn't bring down the whole session.
|
|
12155
|
+
*/
|
|
12156
|
+
async publishChunk(event) {
|
|
12157
|
+
const url = `${this.apiBase}/api/sessions/${encodeURIComponent(this.opts.sessionId)}/streaming-chunk`;
|
|
12158
|
+
try {
|
|
12159
|
+
const { statusCode, body } = await _transport2.post(
|
|
12160
|
+
url,
|
|
12161
|
+
this.headers,
|
|
12162
|
+
JSON.stringify(event)
|
|
12163
|
+
);
|
|
12164
|
+
if (statusCode < 200 || statusCode >= 300) {
|
|
12165
|
+
log.warn("acpPublisher", `chunk status=${statusCode} body=${body.slice(0, 200)}`);
|
|
12166
|
+
}
|
|
12167
|
+
} catch (err) {
|
|
12168
|
+
log.trace("acpPublisher", "chunk post failed", err);
|
|
12169
|
+
}
|
|
12170
|
+
}
|
|
12171
|
+
/**
|
|
12172
|
+
* Publish an awaiting-answer event so the mobile renders the
|
|
12173
|
+
* pending-prompt sheet. The CLI follows up with
|
|
12174
|
+
* {@link pollPendingAnswer} until the user replies (or the
|
|
12175
|
+
* 5 min Redis TTL expires upstream).
|
|
12176
|
+
*/
|
|
12177
|
+
async publishAwaitingAnswer(event) {
|
|
12178
|
+
const url = `${this.apiBase}/api/sessions/${encodeURIComponent(this.opts.sessionId)}/awaiting-answer`;
|
|
12179
|
+
try {
|
|
12180
|
+
const { statusCode, body } = await _transport2.post(
|
|
12181
|
+
url,
|
|
12182
|
+
this.headers,
|
|
12183
|
+
JSON.stringify(event)
|
|
12184
|
+
);
|
|
12185
|
+
if (statusCode < 200 || statusCode >= 300) {
|
|
12186
|
+
log.warn("acpPublisher", `awaiting-answer status=${statusCode} body=${body.slice(0, 200)}`);
|
|
12187
|
+
}
|
|
12188
|
+
} catch (err) {
|
|
12189
|
+
log.trace("acpPublisher", "awaiting-answer post failed", err);
|
|
12190
|
+
}
|
|
12191
|
+
}
|
|
12192
|
+
/**
|
|
12193
|
+
* Drain the pending-answer endpoint. Returns the resolved answer
|
|
12194
|
+
* when the user has replied, `null` otherwise. The caller polls
|
|
12195
|
+
* this on a 1.5 s cadence (same as the legacy emitter) until a
|
|
12196
|
+
* non-null result lands.
|
|
12197
|
+
*/
|
|
12198
|
+
async pollPendingAnswer(questionId) {
|
|
12199
|
+
const url = `${this.apiBase}/api/sessions/${encodeURIComponent(this.opts.sessionId)}/pending-answer?questionId=${encodeURIComponent(questionId)}&pluginId=${encodeURIComponent(this.opts.pluginId)}`;
|
|
12200
|
+
try {
|
|
12201
|
+
const { statusCode, body } = await _transport2.get(url, this.headers);
|
|
12202
|
+
if (statusCode === 204 || statusCode === 404) return null;
|
|
12203
|
+
if (statusCode < 200 || statusCode >= 300) {
|
|
12204
|
+
log.warn("acpPublisher", `pending-answer status=${statusCode} body=${body.slice(0, 200)}`);
|
|
12205
|
+
return null;
|
|
12206
|
+
}
|
|
12207
|
+
return parsePendingAnswerResponse(body, questionId);
|
|
12208
|
+
} catch (err) {
|
|
12209
|
+
log.trace("acpPublisher", "pending-answer poll failed", err);
|
|
12210
|
+
return null;
|
|
12211
|
+
}
|
|
12212
|
+
}
|
|
12213
|
+
};
|
|
12214
|
+
function parsePendingAnswerResponse(body, questionId) {
|
|
12215
|
+
if (!body) return null;
|
|
12216
|
+
let parsed;
|
|
12217
|
+
try {
|
|
12218
|
+
parsed = JSON.parse(body);
|
|
12219
|
+
} catch {
|
|
12220
|
+
return null;
|
|
12221
|
+
}
|
|
12222
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
12223
|
+
const root = parsed;
|
|
12224
|
+
const candidate = root.data && typeof root.data === "object" ? root.data : root;
|
|
12225
|
+
const qid = candidate.questionId;
|
|
12226
|
+
const answer = candidate.answer;
|
|
12227
|
+
const optionIndex = candidate.optionIndex;
|
|
12228
|
+
if (typeof qid !== "string" || qid !== questionId) return null;
|
|
12229
|
+
if (typeof answer !== "string") return null;
|
|
12230
|
+
const result = { questionId: qid, answer };
|
|
12231
|
+
if (typeof optionIndex === "number" && Number.isInteger(optionIndex)) {
|
|
12232
|
+
result.optionIndex = optionIndex;
|
|
12233
|
+
}
|
|
12234
|
+
return result;
|
|
12235
|
+
}
|
|
12236
|
+
|
|
12237
|
+
// src/agents/acp/mappers.ts
|
|
12238
|
+
var import_node_crypto5 = require("crypto");
|
|
12239
|
+
function mapSessionUpdate(notification) {
|
|
12240
|
+
const update = notification.update;
|
|
12241
|
+
switch (update.sessionUpdate) {
|
|
12242
|
+
case "agent_message_chunk": {
|
|
12243
|
+
const text = extractText2(update.content);
|
|
12244
|
+
if (!text) return [];
|
|
12245
|
+
return [chunk(messageChunkId(update.messageId), "text", text)];
|
|
12246
|
+
}
|
|
12247
|
+
case "agent_thought_chunk": {
|
|
12248
|
+
const text = extractText2(update.content);
|
|
12249
|
+
if (!text) return [];
|
|
12250
|
+
return [chunk(messageChunkId(update.messageId), "thinking", text)];
|
|
12251
|
+
}
|
|
12252
|
+
case "tool_call": {
|
|
12253
|
+
const summary = describeToolCall(update);
|
|
12254
|
+
if (!summary) return [];
|
|
12255
|
+
return [chunk(update.toolCallId, "tool_use", summary)];
|
|
12256
|
+
}
|
|
12257
|
+
case "tool_call_update": {
|
|
12258
|
+
if (update.status !== "completed" && update.status !== "failed") {
|
|
12259
|
+
return [];
|
|
12260
|
+
}
|
|
12261
|
+
const body = describeToolCallUpdate(update);
|
|
12262
|
+
if (!body) return [];
|
|
12263
|
+
const prefix = update.status === "failed" ? "[failed] " : "";
|
|
12264
|
+
return [chunk(update.toolCallId, "tool_result", prefix + body)];
|
|
12265
|
+
}
|
|
12266
|
+
case "user_message_chunk":
|
|
12267
|
+
return [];
|
|
12268
|
+
case "plan":
|
|
12269
|
+
case "plan_update":
|
|
12270
|
+
case "plan_removed":
|
|
12271
|
+
case "available_commands_update":
|
|
12272
|
+
case "current_mode_update":
|
|
12273
|
+
case "config_option_update":
|
|
12274
|
+
case "session_info_update":
|
|
12275
|
+
case "usage_update":
|
|
12276
|
+
return [];
|
|
12277
|
+
default:
|
|
12278
|
+
return [];
|
|
12279
|
+
}
|
|
12280
|
+
}
|
|
12281
|
+
function mapPermissionRequest(request) {
|
|
12282
|
+
const prompt = describeToolCall(request.toolCall) ?? "The agent requested permission to continue.";
|
|
12283
|
+
const optionIdByLabel = {};
|
|
12284
|
+
const kindByLabel = {};
|
|
12285
|
+
const labels = [];
|
|
12286
|
+
for (const opt of request.options) {
|
|
12287
|
+
const label = opt.name?.trim() || humanizeKind(opt.kind);
|
|
12288
|
+
if (label in optionIdByLabel) continue;
|
|
12289
|
+
optionIdByLabel[label] = opt.optionId;
|
|
12290
|
+
kindByLabel[label] = opt.kind;
|
|
12291
|
+
labels.push(label);
|
|
12292
|
+
}
|
|
12293
|
+
return {
|
|
12294
|
+
event: {
|
|
12295
|
+
questionId: (0, import_node_crypto5.randomUUID)(),
|
|
12296
|
+
prompt,
|
|
12297
|
+
options: labels.length > 0 ? labels : void 0
|
|
12298
|
+
},
|
|
12299
|
+
optionIdByLabel,
|
|
12300
|
+
kindByLabel
|
|
12301
|
+
};
|
|
12302
|
+
}
|
|
12303
|
+
function chunk(chunkId, kind, content) {
|
|
12304
|
+
return { chunkId, kind, content, isFinal: true };
|
|
12305
|
+
}
|
|
12306
|
+
function messageChunkId(messageId) {
|
|
12307
|
+
if (typeof messageId === "string" && messageId.length > 0) return messageId;
|
|
12308
|
+
return (0, import_node_crypto5.randomUUID)();
|
|
12309
|
+
}
|
|
12310
|
+
function extractText2(content) {
|
|
12311
|
+
if (!content || typeof content !== "object") return null;
|
|
12312
|
+
if ("type" in content && content.type === "text") {
|
|
12313
|
+
const t2 = content.text;
|
|
12314
|
+
return typeof t2 === "string" && t2.length > 0 ? t2 : null;
|
|
12315
|
+
}
|
|
12316
|
+
return null;
|
|
12317
|
+
}
|
|
12318
|
+
function describeToolCall(call) {
|
|
12319
|
+
const title = call.title?.trim();
|
|
12320
|
+
const kind = call.kind?.trim();
|
|
12321
|
+
if (title && title.length > 0) return title;
|
|
12322
|
+
if (kind && kind.length > 0) return kind;
|
|
12323
|
+
if (call.rawInput && typeof call.rawInput === "object") {
|
|
12324
|
+
try {
|
|
12325
|
+
const summary = JSON.stringify(call.rawInput);
|
|
12326
|
+
if (summary.length > 240) return `${summary.slice(0, 240)}\u2026`;
|
|
12327
|
+
return summary;
|
|
12328
|
+
} catch {
|
|
12329
|
+
return null;
|
|
12330
|
+
}
|
|
12331
|
+
}
|
|
12332
|
+
return null;
|
|
12333
|
+
}
|
|
12334
|
+
function describeToolCallUpdate(update) {
|
|
12335
|
+
const parts = [];
|
|
12336
|
+
if (Array.isArray(update.content)) {
|
|
12337
|
+
for (const item of update.content) {
|
|
12338
|
+
if (!item || typeof item !== "object") continue;
|
|
12339
|
+
if (item.type === "content" && item.content) {
|
|
12340
|
+
const text = extractText2(item.content);
|
|
12341
|
+
if (text) parts.push(text);
|
|
12342
|
+
} else if (item.type === "diff") {
|
|
12343
|
+
const p2 = item.path;
|
|
12344
|
+
parts.push(p2 ? `diff: ${p2}` : "diff");
|
|
12345
|
+
} else if (item.type === "terminal") {
|
|
12346
|
+
const id = item.terminalId;
|
|
12347
|
+
parts.push(id ? `terminal: ${id}` : "terminal");
|
|
12348
|
+
}
|
|
12349
|
+
}
|
|
12350
|
+
}
|
|
12351
|
+
if (parts.length > 0) return parts.join("\n");
|
|
12352
|
+
const title = update.title?.trim();
|
|
12353
|
+
return title && title.length > 0 ? title : null;
|
|
12354
|
+
}
|
|
12355
|
+
function humanizeKind(kind) {
|
|
12356
|
+
switch (kind) {
|
|
12357
|
+
case "allow_once":
|
|
12358
|
+
return "Allow once";
|
|
12359
|
+
case "allow_always":
|
|
12360
|
+
return "Always allow";
|
|
12361
|
+
case "reject_once":
|
|
12362
|
+
return "Reject";
|
|
12363
|
+
case "reject_always":
|
|
12364
|
+
return "Always reject";
|
|
12365
|
+
default:
|
|
12366
|
+
return kind;
|
|
12367
|
+
}
|
|
12368
|
+
}
|
|
12369
|
+
|
|
12370
|
+
// src/agents/acp/runner.ts
|
|
12371
|
+
var ANSWER_POLL_MS = 1500;
|
|
12372
|
+
var PERMISSION_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
12373
|
+
async function runAcpSession(opts) {
|
|
12374
|
+
const publisher = new AcpPublisher({
|
|
12375
|
+
sessionId: opts.sessionId,
|
|
12376
|
+
pluginId: opts.pluginId,
|
|
12377
|
+
pluginAuthToken: opts.pluginAuthToken
|
|
12378
|
+
});
|
|
12379
|
+
const client2 = new AcpClient({
|
|
12380
|
+
adapter: opts.adapter,
|
|
12381
|
+
cwd: opts.cwd,
|
|
12382
|
+
onSessionUpdate: (notification) => {
|
|
12383
|
+
const chunks = mapSessionUpdate(notification);
|
|
12384
|
+
for (const chunk2 of chunks) {
|
|
12385
|
+
void publisher.publishChunk(chunk2);
|
|
12386
|
+
}
|
|
12387
|
+
},
|
|
12388
|
+
onRequestPermission: async (request) => {
|
|
12389
|
+
const { event, optionIdByLabel } = mapPermissionRequest(request);
|
|
12390
|
+
await publisher.publishAwaitingAnswer(event);
|
|
12391
|
+
const answer = await waitForAnswer(publisher, event.questionId);
|
|
12392
|
+
if (!answer) {
|
|
12393
|
+
return { outcome: { outcome: "cancelled" } };
|
|
12394
|
+
}
|
|
12395
|
+
const optionId = optionIdByLabel[answer.answer];
|
|
12396
|
+
if (!optionId) {
|
|
12397
|
+
log.warn(
|
|
12398
|
+
"acpRunner",
|
|
12399
|
+
`pending-answer label not in option map; reply="${answer.answer.slice(0, 80)}"`
|
|
12400
|
+
);
|
|
12401
|
+
return { outcome: { outcome: "cancelled" } };
|
|
12402
|
+
}
|
|
12403
|
+
return { outcome: { outcome: "selected", optionId } };
|
|
12404
|
+
},
|
|
12405
|
+
onStderr: (line) => {
|
|
12406
|
+
log.trace("acpAdapter", line);
|
|
12407
|
+
},
|
|
12408
|
+
onUnexpectedExit: (code, signal) => {
|
|
12409
|
+
log.warn("acpRunner", `adapter died code=${code} signal=${signal}; shutting down session`);
|
|
12410
|
+
void publisher.publishChunk({
|
|
12411
|
+
chunkId: (0, import_node_crypto6.randomUUID)(),
|
|
12412
|
+
kind: "text",
|
|
12413
|
+
content: `Agent adapter exited unexpectedly (code=${code ?? "null"} signal=${signal ?? "null"}).`,
|
|
12414
|
+
isFinal: true
|
|
12415
|
+
});
|
|
12416
|
+
process.exit(1);
|
|
12417
|
+
}
|
|
12418
|
+
});
|
|
12419
|
+
showInfo(`Starting ${opts.agent} via ACP adapter (${opts.adapter.requiresAgentBinary})\u2026`);
|
|
12420
|
+
const { sessionId: acpSessionId, initialize } = await client2.start();
|
|
12421
|
+
log.trace(
|
|
12422
|
+
"acpRunner",
|
|
12423
|
+
`adapter handshake ok protocolVersion=${initialize.protocolVersion} sessionId=${acpSessionId.slice(0, 8)}`
|
|
12424
|
+
);
|
|
12425
|
+
const relay = new CommandRelayService(
|
|
12426
|
+
opts.pluginId,
|
|
12427
|
+
async (cmd) => {
|
|
12428
|
+
await handleCommand(cmd, client2);
|
|
12429
|
+
},
|
|
12430
|
+
{ id: opts.agent, name: opts.agent, displayName: opts.agent }
|
|
12431
|
+
);
|
|
12432
|
+
relay.start();
|
|
12433
|
+
const shutdown = async (signal) => {
|
|
12434
|
+
showInfo(`Shutting down ACP session (${signal})\u2026`);
|
|
12435
|
+
relay.stop();
|
|
12436
|
+
await client2.stop();
|
|
12437
|
+
process.exit(0);
|
|
12438
|
+
};
|
|
12439
|
+
process.once("SIGINT", () => void shutdown("SIGINT"));
|
|
12440
|
+
process.once("SIGTERM", () => void shutdown("SIGTERM"));
|
|
12441
|
+
process.once("SIGHUP", () => void shutdown("SIGHUP"));
|
|
12442
|
+
await new Promise(() => {
|
|
12443
|
+
});
|
|
12444
|
+
}
|
|
12445
|
+
async function handleCommand(cmd, client2) {
|
|
12446
|
+
switch (cmd.type) {
|
|
12447
|
+
case "start_task": {
|
|
12448
|
+
const payload = cmd.payload;
|
|
12449
|
+
const prompt = payload?.prompt?.trim();
|
|
12450
|
+
if (!prompt) {
|
|
12451
|
+
log.warn("acpRunner", "start_task with empty prompt; ignoring");
|
|
12452
|
+
return;
|
|
12453
|
+
}
|
|
12454
|
+
try {
|
|
12455
|
+
await client2.prompt(prompt);
|
|
12456
|
+
} catch (err) {
|
|
12457
|
+
log.warn("acpRunner", `prompt failed: ${describeError(err)}`);
|
|
12458
|
+
}
|
|
12459
|
+
return;
|
|
12460
|
+
}
|
|
12461
|
+
case "stop_task":
|
|
12462
|
+
case "escape_key": {
|
|
12463
|
+
try {
|
|
12464
|
+
await client2.cancel();
|
|
12465
|
+
} catch (err) {
|
|
12466
|
+
log.warn("acpRunner", `cancel failed: ${describeError(err)}`);
|
|
12467
|
+
}
|
|
12468
|
+
return;
|
|
12469
|
+
}
|
|
12470
|
+
default:
|
|
12471
|
+
log.trace("acpRunner", `command type "${cmd.type}" not supported in Phase 1 ACP mode`);
|
|
12472
|
+
return;
|
|
12473
|
+
}
|
|
12474
|
+
}
|
|
12475
|
+
async function waitForAnswer(publisher, questionId) {
|
|
12476
|
+
const deadline = Date.now() + PERMISSION_TIMEOUT_MS;
|
|
12477
|
+
while (Date.now() < deadline) {
|
|
12478
|
+
const reply = await publisher.pollPendingAnswer(questionId);
|
|
12479
|
+
if (reply) return { answer: reply.answer };
|
|
12480
|
+
await new Promise((r) => setTimeout(r, ANSWER_POLL_MS));
|
|
12481
|
+
}
|
|
12482
|
+
return null;
|
|
12483
|
+
}
|
|
12484
|
+
function describeError(err) {
|
|
12485
|
+
if (err instanceof Error) return err.message;
|
|
12486
|
+
return String(err);
|
|
12487
|
+
}
|
|
12488
|
+
|
|
11798
12489
|
// src/services/output/chrome-tracker.ts
|
|
11799
12490
|
var ChromeStepTracker = class {
|
|
11800
12491
|
history = [];
|
|
@@ -11841,12 +12532,12 @@ var ChromeStepTracker = class {
|
|
|
11841
12532
|
};
|
|
11842
12533
|
|
|
11843
12534
|
// src/services/output/chunk-emitter.ts
|
|
11844
|
-
var
|
|
11845
|
-
var
|
|
12535
|
+
var https4 = __toESM(require("https"));
|
|
12536
|
+
var http4 = __toESM(require("http"));
|
|
11846
12537
|
var API_BASE3 = resolveApiBaseUrl();
|
|
11847
12538
|
async function refreshAuthToken(sessionId, pluginId) {
|
|
11848
12539
|
try {
|
|
11849
|
-
const { statusCode, body } = await
|
|
12540
|
+
const { statusCode, body } = await _transport3.post(
|
|
11850
12541
|
`${API_BASE3}/api/pairing/reconnect`,
|
|
11851
12542
|
{
|
|
11852
12543
|
"Content-Type": "application/json",
|
|
@@ -11909,14 +12600,14 @@ var ChunkEmitter = class {
|
|
|
11909
12600
|
"chunkEmitter",
|
|
11910
12601
|
`send type=${body.type ?? "(clear)"} bytes=${payload.length} done=${body.done === true}`
|
|
11911
12602
|
);
|
|
11912
|
-
return new Promise((
|
|
12603
|
+
return new Promise((resolve6) => {
|
|
11913
12604
|
const attempt = (attemptsLeft) => {
|
|
11914
|
-
|
|
12605
|
+
_transport3.post(this.url, this.headers, payload).then(({ statusCode, body: resBody }) => {
|
|
11915
12606
|
const tookMs = Date.now() - t0;
|
|
11916
12607
|
if (statusCode === 410 || statusCode === 404 && /SESSION_NOT_FOUND|SESSION_GONE/.test(resBody)) {
|
|
11917
12608
|
process.stderr.write("[codeam] session was deleted/disconnected \u2014 stopping output stream.\n");
|
|
11918
12609
|
log.info("chunkEmitter", `dead status=${statusCode} took=${tookMs}ms`);
|
|
11919
|
-
|
|
12610
|
+
resolve6({ dead: true });
|
|
11920
12611
|
return;
|
|
11921
12612
|
}
|
|
11922
12613
|
if (statusCode === 401) {
|
|
@@ -11932,7 +12623,7 @@ var ChunkEmitter = class {
|
|
|
11932
12623
|
return;
|
|
11933
12624
|
}
|
|
11934
12625
|
}
|
|
11935
|
-
|
|
12626
|
+
resolve6({ dead: false });
|
|
11936
12627
|
})();
|
|
11937
12628
|
return;
|
|
11938
12629
|
}
|
|
@@ -11943,7 +12634,7 @@ var ChunkEmitter = class {
|
|
|
11943
12634
|
} else {
|
|
11944
12635
|
log.info("chunkEmitter", `ok status=${statusCode} took=${tookMs}ms`);
|
|
11945
12636
|
}
|
|
11946
|
-
|
|
12637
|
+
resolve6({ dead: false });
|
|
11947
12638
|
}).catch((err) => {
|
|
11948
12639
|
log.warn(
|
|
11949
12640
|
"chunkEmitter",
|
|
@@ -11954,7 +12645,7 @@ var ChunkEmitter = class {
|
|
|
11954
12645
|
const delay = 200 * (maxRetries - attemptsLeft + 1);
|
|
11955
12646
|
setTimeout(() => attempt(attemptsLeft - 1), delay);
|
|
11956
12647
|
} else {
|
|
11957
|
-
|
|
12648
|
+
resolve6({ dead: false });
|
|
11958
12649
|
}
|
|
11959
12650
|
});
|
|
11960
12651
|
};
|
|
@@ -11962,14 +12653,14 @@ var ChunkEmitter = class {
|
|
|
11962
12653
|
});
|
|
11963
12654
|
}
|
|
11964
12655
|
};
|
|
11965
|
-
var
|
|
11966
|
-
post:
|
|
12656
|
+
var _transport3 = {
|
|
12657
|
+
post: _post2
|
|
11967
12658
|
};
|
|
11968
|
-
function
|
|
11969
|
-
return new Promise((
|
|
12659
|
+
function _post2(url, headers, payload) {
|
|
12660
|
+
return new Promise((resolve6, reject) => {
|
|
11970
12661
|
let settled = false;
|
|
11971
12662
|
const u2 = new URL(url);
|
|
11972
|
-
const transport = u2.protocol === "https:" ?
|
|
12663
|
+
const transport = u2.protocol === "https:" ? https4 : http4;
|
|
11973
12664
|
const req = transport.request(
|
|
11974
12665
|
{
|
|
11975
12666
|
hostname: u2.hostname,
|
|
@@ -11990,7 +12681,7 @@ function _post(url, headers, payload) {
|
|
|
11990
12681
|
res.on("end", () => {
|
|
11991
12682
|
if (settled) return;
|
|
11992
12683
|
settled = true;
|
|
11993
|
-
|
|
12684
|
+
resolve6({ statusCode: res.statusCode ?? 0, body: resData });
|
|
11994
12685
|
});
|
|
11995
12686
|
}
|
|
11996
12687
|
);
|
|
@@ -12564,11 +13255,11 @@ var OutputService = class _OutputService {
|
|
|
12564
13255
|
};
|
|
12565
13256
|
|
|
12566
13257
|
// src/services/history.service.ts
|
|
12567
|
-
var
|
|
12568
|
-
var
|
|
13258
|
+
var fs21 = __toESM(require("fs"));
|
|
13259
|
+
var path25 = __toESM(require("path"));
|
|
12569
13260
|
var os21 = __toESM(require("os"));
|
|
12570
|
-
var
|
|
12571
|
-
var
|
|
13261
|
+
var https5 = __toESM(require("https"));
|
|
13262
|
+
var http5 = __toESM(require("http"));
|
|
12572
13263
|
var import_zod = require("zod");
|
|
12573
13264
|
var historyRecordSchema = import_zod.z.object({
|
|
12574
13265
|
type: import_zod.z.string().optional(),
|
|
@@ -12581,7 +13272,7 @@ var historyRecordSchema = import_zod.z.object({
|
|
|
12581
13272
|
}).passthrough().optional()
|
|
12582
13273
|
}).passthrough();
|
|
12583
13274
|
var API_BASE4 = resolveApiBaseUrl();
|
|
12584
|
-
function
|
|
13275
|
+
function extractText3(content) {
|
|
12585
13276
|
if (typeof content === "string") return content;
|
|
12586
13277
|
if (Array.isArray(content)) {
|
|
12587
13278
|
return content.filter((b) => b["type"] === "text").map((b) => b["text"]).join("\n");
|
|
@@ -12593,7 +13284,7 @@ function parseJsonl(filePath) {
|
|
|
12593
13284
|
const messages = [];
|
|
12594
13285
|
let raw;
|
|
12595
13286
|
try {
|
|
12596
|
-
raw =
|
|
13287
|
+
raw = fs21.readFileSync(filePath, "utf8");
|
|
12597
13288
|
} catch (err) {
|
|
12598
13289
|
if (err.code !== "ENOENT") {
|
|
12599
13290
|
log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
|
|
@@ -12620,20 +13311,20 @@ function parseJsonl(filePath) {
|
|
|
12620
13311
|
const uuid = record.uuid ?? `${Date.now()}-${Math.random()}`;
|
|
12621
13312
|
const msg = record.message;
|
|
12622
13313
|
if (record.type === "user" && msg) {
|
|
12623
|
-
const text =
|
|
13314
|
+
const text = extractText3(msg.content).trim();
|
|
12624
13315
|
if (text) messages.push({ id: uuid, role: "user", text, timestamp });
|
|
12625
13316
|
} else if (record.type === "assistant" && msg) {
|
|
12626
|
-
const text =
|
|
13317
|
+
const text = extractText3(msg.content).trim();
|
|
12627
13318
|
if (text) messages.push({ id: uuid, role: "agent", text, timestamp });
|
|
12628
13319
|
}
|
|
12629
13320
|
}
|
|
12630
13321
|
return messages;
|
|
12631
13322
|
}
|
|
12632
13323
|
function post(endpoint, body) {
|
|
12633
|
-
return new Promise((
|
|
13324
|
+
return new Promise((resolve6) => {
|
|
12634
13325
|
const payload = JSON.stringify(body);
|
|
12635
13326
|
const u2 = new URL(`${API_BASE4}${endpoint}`);
|
|
12636
|
-
const transport = u2.protocol === "https:" ?
|
|
13327
|
+
const transport = u2.protocol === "https:" ? https5 : http5;
|
|
12637
13328
|
const req = transport.request(
|
|
12638
13329
|
{
|
|
12639
13330
|
hostname: u2.hostname,
|
|
@@ -12651,17 +13342,17 @@ function post(endpoint, body) {
|
|
|
12651
13342
|
res.resume();
|
|
12652
13343
|
const ok = res.statusCode !== void 0 && res.statusCode >= 200 && res.statusCode < 300;
|
|
12653
13344
|
if (!ok) log.warn("history:post", `${endpoint} \u2192 HTTP ${res.statusCode}`);
|
|
12654
|
-
|
|
13345
|
+
resolve6(ok);
|
|
12655
13346
|
}
|
|
12656
13347
|
);
|
|
12657
13348
|
req.on("error", (err) => {
|
|
12658
13349
|
log.warn("history:post", `${endpoint} network error`, err);
|
|
12659
|
-
|
|
13350
|
+
resolve6(false);
|
|
12660
13351
|
});
|
|
12661
13352
|
req.on("timeout", () => {
|
|
12662
13353
|
log.warn("history:post", `${endpoint} timeout after 15s`);
|
|
12663
13354
|
req.destroy();
|
|
12664
|
-
|
|
13355
|
+
resolve6(false);
|
|
12665
13356
|
});
|
|
12666
13357
|
req.write(payload);
|
|
12667
13358
|
req.end();
|
|
@@ -12728,7 +13419,7 @@ var HistoryService = class _HistoryService {
|
|
|
12728
13419
|
return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
|
|
12729
13420
|
}
|
|
12730
13421
|
get projectDir() {
|
|
12731
|
-
return this.runtime.resolveHistoryDir(this.cwd) ??
|
|
13422
|
+
return this.runtime.resolveHistoryDir(this.cwd) ?? path25.join(os21.homedir(), ".claude", "projects", encodeCwd(this.cwd));
|
|
12732
13423
|
}
|
|
12733
13424
|
/** Set the current Claude conversation ID (extracted from /cost command or session start) */
|
|
12734
13425
|
setCurrentConversationId(id) {
|
|
@@ -12740,7 +13431,7 @@ var HistoryService = class _HistoryService {
|
|
|
12740
13431
|
/** Return the current message count in the active conversation. */
|
|
12741
13432
|
getCurrentMessageCount() {
|
|
12742
13433
|
if (!this.currentConversationId) return 0;
|
|
12743
|
-
const filePath =
|
|
13434
|
+
const filePath = path25.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
12744
13435
|
return parseJsonl(filePath).length;
|
|
12745
13436
|
}
|
|
12746
13437
|
/**
|
|
@@ -12751,7 +13442,7 @@ var HistoryService = class _HistoryService {
|
|
|
12751
13442
|
const deadline = Date.now() + timeoutMs;
|
|
12752
13443
|
while (Date.now() < deadline) {
|
|
12753
13444
|
if (!this.currentConversationId) return null;
|
|
12754
|
-
const filePath =
|
|
13445
|
+
const filePath = path25.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
12755
13446
|
const messages = parseJsonl(filePath);
|
|
12756
13447
|
if (messages.length > previousCount) {
|
|
12757
13448
|
for (let i = messages.length - 1; i >= previousCount; i--) {
|
|
@@ -12777,16 +13468,16 @@ var HistoryService = class _HistoryService {
|
|
|
12777
13468
|
const dir = this.projectDir;
|
|
12778
13469
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
12779
13470
|
try {
|
|
12780
|
-
const files =
|
|
13471
|
+
const files = fs21.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
12781
13472
|
try {
|
|
12782
|
-
const stat3 =
|
|
13473
|
+
const stat3 = fs21.statSync(path25.join(dir, e.name));
|
|
12783
13474
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
12784
13475
|
} catch {
|
|
12785
13476
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
12786
13477
|
}
|
|
12787
13478
|
}).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
|
|
12788
13479
|
if (files.length > 0) {
|
|
12789
|
-
this.currentConversationId =
|
|
13480
|
+
this.currentConversationId = path25.basename(files[0].name, ".jsonl");
|
|
12790
13481
|
}
|
|
12791
13482
|
} catch {
|
|
12792
13483
|
}
|
|
@@ -12820,13 +13511,13 @@ var HistoryService = class _HistoryService {
|
|
|
12820
13511
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
12821
13512
|
let entries;
|
|
12822
13513
|
try {
|
|
12823
|
-
entries =
|
|
13514
|
+
entries = fs21.readdirSync(dir, { withFileTypes: true });
|
|
12824
13515
|
} catch {
|
|
12825
13516
|
return null;
|
|
12826
13517
|
}
|
|
12827
13518
|
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
12828
13519
|
try {
|
|
12829
|
-
const stat3 =
|
|
13520
|
+
const stat3 = fs21.statSync(path25.join(dir, e.name));
|
|
12830
13521
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
12831
13522
|
} catch {
|
|
12832
13523
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
@@ -12835,12 +13526,12 @@ var HistoryService = class _HistoryService {
|
|
|
12835
13526
|
if (files.length === 0) return null;
|
|
12836
13527
|
const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
|
|
12837
13528
|
if (!files.some((f) => f.name === targetFile)) return null;
|
|
12838
|
-
return this.extractUsageFromFile(
|
|
13529
|
+
return this.extractUsageFromFile(path25.join(dir, targetFile));
|
|
12839
13530
|
}
|
|
12840
13531
|
extractUsageFromFile(filePath) {
|
|
12841
13532
|
let raw;
|
|
12842
13533
|
try {
|
|
12843
|
-
raw =
|
|
13534
|
+
raw = fs21.readFileSync(filePath, "utf8");
|
|
12844
13535
|
} catch {
|
|
12845
13536
|
return null;
|
|
12846
13537
|
}
|
|
@@ -12885,9 +13576,9 @@ var HistoryService = class _HistoryService {
|
|
|
12885
13576
|
let totalCost = 0;
|
|
12886
13577
|
let files;
|
|
12887
13578
|
try {
|
|
12888
|
-
files =
|
|
13579
|
+
files = fs21.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
12889
13580
|
try {
|
|
12890
|
-
return
|
|
13581
|
+
return fs21.statSync(path25.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
12891
13582
|
} catch {
|
|
12892
13583
|
return false;
|
|
12893
13584
|
}
|
|
@@ -12898,7 +13589,7 @@ var HistoryService = class _HistoryService {
|
|
|
12898
13589
|
for (const file of files) {
|
|
12899
13590
|
let raw;
|
|
12900
13591
|
try {
|
|
12901
|
-
raw =
|
|
13592
|
+
raw = fs21.readFileSync(path25.join(projectDir, file), "utf8");
|
|
12902
13593
|
} catch {
|
|
12903
13594
|
continue;
|
|
12904
13595
|
}
|
|
@@ -12962,7 +13653,7 @@ var HistoryService = class _HistoryService {
|
|
|
12962
13653
|
* showing an empty conversation.
|
|
12963
13654
|
*/
|
|
12964
13655
|
async loadConversation(sessionId) {
|
|
12965
|
-
const filePath =
|
|
13656
|
+
const filePath = path25.join(this.projectDir, `${sessionId}.jsonl`);
|
|
12966
13657
|
const messages = parseJsonl(filePath);
|
|
12967
13658
|
if (messages.length === 0) return;
|
|
12968
13659
|
const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
|
|
@@ -13016,7 +13707,7 @@ var HistoryService = class _HistoryService {
|
|
|
13016
13707
|
if (!this.currentConversationId) return 0;
|
|
13017
13708
|
}
|
|
13018
13709
|
const sessionId = this.currentConversationId;
|
|
13019
|
-
const filePath =
|
|
13710
|
+
const filePath = path25.join(this.projectDir, `${sessionId}.jsonl`);
|
|
13020
13711
|
const messages = parseJsonl(filePath);
|
|
13021
13712
|
if (messages.length === 0) return 0;
|
|
13022
13713
|
const marker = this.lastUploadedUuid.get(sessionId);
|
|
@@ -13047,9 +13738,9 @@ var HistoryService = class _HistoryService {
|
|
|
13047
13738
|
|
|
13048
13739
|
// src/services/file-watcher.service.ts
|
|
13049
13740
|
var import_child_process8 = require("child_process");
|
|
13050
|
-
var
|
|
13741
|
+
var fs22 = __toESM(require("fs"));
|
|
13051
13742
|
var os22 = __toESM(require("os"));
|
|
13052
|
-
var
|
|
13743
|
+
var path26 = __toESM(require("path"));
|
|
13053
13744
|
|
|
13054
13745
|
// src/services/file-watcher/diff-parser.ts
|
|
13055
13746
|
var HUNK_HEADER_RE = /^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
|
|
@@ -13138,16 +13829,16 @@ function isIgnoredFilePath(filePath) {
|
|
|
13138
13829
|
}
|
|
13139
13830
|
|
|
13140
13831
|
// src/services/file-watcher/transport.ts
|
|
13141
|
-
var
|
|
13142
|
-
var
|
|
13143
|
-
var
|
|
13144
|
-
post:
|
|
13832
|
+
var http6 = __toESM(require("http"));
|
|
13833
|
+
var https6 = __toESM(require("https"));
|
|
13834
|
+
var _transport4 = {
|
|
13835
|
+
post: _post3
|
|
13145
13836
|
};
|
|
13146
|
-
function
|
|
13147
|
-
return new Promise((
|
|
13837
|
+
function _post3(url, headers, payload) {
|
|
13838
|
+
return new Promise((resolve6, reject) => {
|
|
13148
13839
|
let settled = false;
|
|
13149
13840
|
const u2 = new URL(url);
|
|
13150
|
-
const lib = u2.protocol === "https:" ?
|
|
13841
|
+
const lib = u2.protocol === "https:" ? https6 : http6;
|
|
13151
13842
|
const req = lib.request(
|
|
13152
13843
|
{
|
|
13153
13844
|
hostname: u2.hostname,
|
|
@@ -13169,7 +13860,7 @@ function _post2(url, headers, payload) {
|
|
|
13169
13860
|
res.on("end", () => {
|
|
13170
13861
|
if (settled) return;
|
|
13171
13862
|
settled = true;
|
|
13172
|
-
|
|
13863
|
+
resolve6({ statusCode: res.statusCode ?? 0, body });
|
|
13173
13864
|
});
|
|
13174
13865
|
}
|
|
13175
13866
|
);
|
|
@@ -13240,18 +13931,18 @@ var _findGitRootSeam = {
|
|
|
13240
13931
|
resolve: _defaultFindGitRoot
|
|
13241
13932
|
};
|
|
13242
13933
|
function _defaultFindGitRoot(startDir) {
|
|
13243
|
-
let dir =
|
|
13934
|
+
let dir = path26.resolve(startDir);
|
|
13244
13935
|
const seen = /* @__PURE__ */ new Set();
|
|
13245
13936
|
for (let i = 0; i < 256; i++) {
|
|
13246
13937
|
if (seen.has(dir)) return null;
|
|
13247
13938
|
seen.add(dir);
|
|
13248
13939
|
try {
|
|
13249
|
-
const gitPath =
|
|
13250
|
-
const stat3 =
|
|
13940
|
+
const gitPath = path26.join(dir, ".git");
|
|
13941
|
+
const stat3 = fs22.statSync(gitPath, { throwIfNoEntry: false });
|
|
13251
13942
|
if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
|
|
13252
13943
|
} catch {
|
|
13253
13944
|
}
|
|
13254
|
-
const parent =
|
|
13945
|
+
const parent = path26.dirname(dir);
|
|
13255
13946
|
if (parent === dir) return null;
|
|
13256
13947
|
dir = parent;
|
|
13257
13948
|
}
|
|
@@ -13485,7 +14176,7 @@ var FileWatcherService = class {
|
|
|
13485
14176
|
}
|
|
13486
14177
|
async emitForFile(absPath, changeType) {
|
|
13487
14178
|
if (this.stopped) return;
|
|
13488
|
-
const fileDir =
|
|
14179
|
+
const fileDir = path26.dirname(absPath);
|
|
13489
14180
|
let gitRoot = this.gitRootByDir.get(fileDir);
|
|
13490
14181
|
if (gitRoot === void 0) {
|
|
13491
14182
|
gitRoot = findGitRoot(fileDir);
|
|
@@ -13499,10 +14190,10 @@ var FileWatcherService = class {
|
|
|
13499
14190
|
return;
|
|
13500
14191
|
}
|
|
13501
14192
|
this.opts.onRepoDirty?.(gitRoot);
|
|
13502
|
-
const relPathInRepo =
|
|
14193
|
+
const relPathInRepo = path26.relative(gitRoot, absPath);
|
|
13503
14194
|
if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
|
|
13504
|
-
const repoPath =
|
|
13505
|
-
const repoName =
|
|
14195
|
+
const repoPath = path26.relative(this.opts.workingDir, gitRoot);
|
|
14196
|
+
const repoName = path26.basename(gitRoot);
|
|
13506
14197
|
let diffText = "";
|
|
13507
14198
|
let fileStatus = "modified";
|
|
13508
14199
|
if (changeType === "unlink") {
|
|
@@ -13646,7 +14337,7 @@ var FileWatcherService = class {
|
|
|
13646
14337
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt += 1) {
|
|
13647
14338
|
if (this.stopped) return;
|
|
13648
14339
|
try {
|
|
13649
|
-
const { statusCode, body: resBody } = await
|
|
14340
|
+
const { statusCode, body: resBody } = await _transport4.post(url, headers, payload);
|
|
13650
14341
|
if (statusCode >= 200 && statusCode < 300) {
|
|
13651
14342
|
log.trace(
|
|
13652
14343
|
"fileWatcher",
|
|
@@ -13765,12 +14456,12 @@ var _gitSeam = {
|
|
|
13765
14456
|
run: _runGitImpl
|
|
13766
14457
|
};
|
|
13767
14458
|
async function _runGitImpl(cwd, args2, opts = {}) {
|
|
13768
|
-
return new Promise((
|
|
14459
|
+
return new Promise((resolve6) => {
|
|
13769
14460
|
let proc;
|
|
13770
14461
|
try {
|
|
13771
14462
|
proc = (0, import_child_process8.spawn)("git", args2, { cwd, env: process.env });
|
|
13772
14463
|
} catch {
|
|
13773
|
-
|
|
14464
|
+
resolve6(null);
|
|
13774
14465
|
return;
|
|
13775
14466
|
}
|
|
13776
14467
|
let stdout = "";
|
|
@@ -13781,13 +14472,13 @@ async function _runGitImpl(cwd, args2, opts = {}) {
|
|
|
13781
14472
|
proc.stderr?.on("data", (c2) => {
|
|
13782
14473
|
stderr += c2.toString();
|
|
13783
14474
|
});
|
|
13784
|
-
proc.on("error", () =>
|
|
14475
|
+
proc.on("error", () => resolve6(null));
|
|
13785
14476
|
proc.on("close", (code) => {
|
|
13786
14477
|
if (code === 0 || opts.allowNonZeroExit) {
|
|
13787
|
-
|
|
14478
|
+
resolve6(stdout);
|
|
13788
14479
|
} else {
|
|
13789
14480
|
log.trace("fileWatcher", `git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`);
|
|
13790
|
-
|
|
14481
|
+
resolve6(null);
|
|
13791
14482
|
}
|
|
13792
14483
|
});
|
|
13793
14484
|
});
|
|
@@ -13801,7 +14492,7 @@ var import_crypto2 = require("crypto");
|
|
|
13801
14492
|
|
|
13802
14493
|
// src/services/turn-files/git-changeset.ts
|
|
13803
14494
|
var import_child_process9 = require("child_process");
|
|
13804
|
-
var
|
|
14495
|
+
var path27 = __toESM(require("path"));
|
|
13805
14496
|
async function collectRepoChangeset(opts) {
|
|
13806
14497
|
const status2 = await runGit2(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
|
|
13807
14498
|
if (status2 === null) return null;
|
|
@@ -13881,12 +14572,12 @@ function runGit2(cwd, args2) {
|
|
|
13881
14572
|
return _runGitImpl2.run(cwd, args2);
|
|
13882
14573
|
}
|
|
13883
14574
|
function defaultRunGit(cwd, args2) {
|
|
13884
|
-
return new Promise((
|
|
14575
|
+
return new Promise((resolve6) => {
|
|
13885
14576
|
let proc;
|
|
13886
14577
|
try {
|
|
13887
14578
|
proc = (0, import_child_process9.spawn)("git", args2, { cwd, env: process.env });
|
|
13888
14579
|
} catch {
|
|
13889
|
-
|
|
14580
|
+
resolve6(null);
|
|
13890
14581
|
return;
|
|
13891
14582
|
}
|
|
13892
14583
|
let stdout = "";
|
|
@@ -13897,22 +14588,22 @@ function defaultRunGit(cwd, args2) {
|
|
|
13897
14588
|
proc.stderr?.on("data", (c2) => {
|
|
13898
14589
|
stderr += c2.toString();
|
|
13899
14590
|
});
|
|
13900
|
-
proc.on("error", () =>
|
|
14591
|
+
proc.on("error", () => resolve6(null));
|
|
13901
14592
|
proc.on("close", (code) => {
|
|
13902
14593
|
if (code === 0) {
|
|
13903
|
-
|
|
14594
|
+
resolve6(stdout);
|
|
13904
14595
|
} else {
|
|
13905
14596
|
log.trace(
|
|
13906
14597
|
"turnFiles",
|
|
13907
14598
|
`git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`
|
|
13908
14599
|
);
|
|
13909
|
-
|
|
14600
|
+
resolve6(null);
|
|
13910
14601
|
}
|
|
13911
14602
|
});
|
|
13912
14603
|
});
|
|
13913
14604
|
}
|
|
13914
14605
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
13915
|
-
const
|
|
14606
|
+
const fs35 = await import("fs/promises");
|
|
13916
14607
|
const out2 = [];
|
|
13917
14608
|
await walk(workingDir, 0);
|
|
13918
14609
|
return out2;
|
|
@@ -13920,7 +14611,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
13920
14611
|
if (depth > maxDepth) return;
|
|
13921
14612
|
let entries = [];
|
|
13922
14613
|
try {
|
|
13923
|
-
const dirents = await
|
|
14614
|
+
const dirents = await fs35.readdir(dir, { withFileTypes: true });
|
|
13924
14615
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
13925
14616
|
} catch {
|
|
13926
14617
|
return;
|
|
@@ -13931,8 +14622,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
13931
14622
|
if (hasGit) {
|
|
13932
14623
|
out2.push({
|
|
13933
14624
|
repoRoot: dir,
|
|
13934
|
-
repoPath:
|
|
13935
|
-
repoName:
|
|
14625
|
+
repoPath: path27.relative(workingDir, dir),
|
|
14626
|
+
repoName: path27.basename(dir)
|
|
13936
14627
|
});
|
|
13937
14628
|
return;
|
|
13938
14629
|
}
|
|
@@ -13940,14 +14631,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
13940
14631
|
if (!entry.isDirectory) continue;
|
|
13941
14632
|
if (entry.name === "node_modules") continue;
|
|
13942
14633
|
if (entry.name === "dist" || entry.name === "build") continue;
|
|
13943
|
-
await walk(
|
|
14634
|
+
await walk(path27.join(dir, entry.name), depth + 1);
|
|
13944
14635
|
}
|
|
13945
14636
|
}
|
|
13946
14637
|
}
|
|
13947
14638
|
|
|
13948
14639
|
// src/services/turn-files/files-outbox.ts
|
|
13949
|
-
var
|
|
13950
|
-
var
|
|
14640
|
+
var fs23 = __toESM(require("fs/promises"));
|
|
14641
|
+
var path28 = __toESM(require("path"));
|
|
13951
14642
|
var import_os6 = require("os");
|
|
13952
14643
|
var HOME_OUTBOX_DIR = ".codeam/outbox";
|
|
13953
14644
|
var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -13980,16 +14671,16 @@ var FilesOutbox = class {
|
|
|
13980
14671
|
backoffIndex = 0;
|
|
13981
14672
|
stopped = false;
|
|
13982
14673
|
constructor(opts) {
|
|
13983
|
-
const base = opts.baseDir ??
|
|
13984
|
-
this.filePath =
|
|
14674
|
+
const base = opts.baseDir ?? path28.join(homeDir(), HOME_OUTBOX_DIR);
|
|
14675
|
+
this.filePath = path28.join(base, `${opts.sessionId}.jsonl`);
|
|
13985
14676
|
this.post = opts.post;
|
|
13986
14677
|
this.autoSchedule = opts.autoSchedule !== false;
|
|
13987
14678
|
}
|
|
13988
14679
|
/** Persist the entry to disk and trigger a flush. Returns once the
|
|
13989
14680
|
* line is durable on disk (not once the POST succeeds). */
|
|
13990
14681
|
async enqueue(entry) {
|
|
13991
|
-
await
|
|
13992
|
-
await
|
|
14682
|
+
await fs23.mkdir(path28.dirname(this.filePath), { recursive: true });
|
|
14683
|
+
await fs23.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
|
|
13993
14684
|
this.backoffIndex = 0;
|
|
13994
14685
|
if (this.autoSchedule) this.scheduleFlush(0);
|
|
13995
14686
|
}
|
|
@@ -14078,7 +14769,7 @@ var FilesOutbox = class {
|
|
|
14078
14769
|
async readAll() {
|
|
14079
14770
|
let raw = "";
|
|
14080
14771
|
try {
|
|
14081
|
-
raw = await
|
|
14772
|
+
raw = await fs23.readFile(this.filePath, "utf8");
|
|
14082
14773
|
} catch {
|
|
14083
14774
|
return [];
|
|
14084
14775
|
}
|
|
@@ -14102,12 +14793,12 @@ var FilesOutbox = class {
|
|
|
14102
14793
|
async rewrite(entries) {
|
|
14103
14794
|
const tmpPath = `${this.filePath}.${process.pid}.tmp`;
|
|
14104
14795
|
if (entries.length === 0) {
|
|
14105
|
-
await
|
|
14796
|
+
await fs23.unlink(this.filePath).catch(() => void 0);
|
|
14106
14797
|
return;
|
|
14107
14798
|
}
|
|
14108
14799
|
const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
14109
|
-
await
|
|
14110
|
-
await
|
|
14800
|
+
await fs23.writeFile(tmpPath, payload, "utf8");
|
|
14801
|
+
await fs23.rename(tmpPath, this.filePath);
|
|
14111
14802
|
}
|
|
14112
14803
|
};
|
|
14113
14804
|
function applyJitter(ms) {
|
|
@@ -14222,13 +14913,13 @@ var TurnFileAggregator = class {
|
|
|
14222
14913
|
return;
|
|
14223
14914
|
}
|
|
14224
14915
|
const chunks = chunkArray(novel, MAX_BATCH_SIZE);
|
|
14225
|
-
for (const
|
|
14916
|
+
for (const chunk2 of chunks) {
|
|
14226
14917
|
const entry = {
|
|
14227
14918
|
turnId: (0, import_crypto2.randomUUID)(),
|
|
14228
14919
|
sessionId: this.opts.sessionId,
|
|
14229
14920
|
pluginId: this.opts.pluginId,
|
|
14230
14921
|
enqueuedAt: Date.now(),
|
|
14231
|
-
files:
|
|
14922
|
+
files: chunk2
|
|
14232
14923
|
};
|
|
14233
14924
|
await this.outbox.enqueue(entry);
|
|
14234
14925
|
}
|
|
@@ -14267,7 +14958,7 @@ var TurnFileAggregator = class {
|
|
|
14267
14958
|
files: entry.files
|
|
14268
14959
|
});
|
|
14269
14960
|
try {
|
|
14270
|
-
const res = await
|
|
14961
|
+
const res = await _transport4.post(url, headers, body);
|
|
14271
14962
|
return { ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode };
|
|
14272
14963
|
} catch (err) {
|
|
14273
14964
|
log.trace(
|
|
@@ -14326,101 +15017,9 @@ var RepoDirtyTracker = class {
|
|
|
14326
15017
|
|
|
14327
15018
|
// src/services/streaming-emitter.service.ts
|
|
14328
15019
|
var import_crypto3 = require("crypto");
|
|
14329
|
-
|
|
14330
|
-
// src/services/streaming/transport.ts
|
|
14331
|
-
var http6 = __toESM(require("http"));
|
|
14332
|
-
var https6 = __toESM(require("https"));
|
|
14333
|
-
var _transport4 = {
|
|
14334
|
-
post: _post3,
|
|
14335
|
-
get: _get
|
|
14336
|
-
};
|
|
14337
|
-
function _post3(url, headers, payload) {
|
|
14338
|
-
return new Promise((resolve5, reject) => {
|
|
14339
|
-
let settled = false;
|
|
14340
|
-
const u2 = new URL(url);
|
|
14341
|
-
const lib = u2.protocol === "https:" ? https6 : http6;
|
|
14342
|
-
const req = lib.request(
|
|
14343
|
-
{
|
|
14344
|
-
hostname: u2.hostname,
|
|
14345
|
-
port: u2.port || (u2.protocol === "https:" ? 443 : 80),
|
|
14346
|
-
path: u2.pathname + u2.search,
|
|
14347
|
-
method: "POST",
|
|
14348
|
-
headers: {
|
|
14349
|
-
...headers,
|
|
14350
|
-
...vercelBypassHeader(),
|
|
14351
|
-
"Content-Length": Buffer.byteLength(payload)
|
|
14352
|
-
},
|
|
14353
|
-
timeout: 8e3
|
|
14354
|
-
},
|
|
14355
|
-
(res) => {
|
|
14356
|
-
let body = "";
|
|
14357
|
-
res.on("data", (c2) => {
|
|
14358
|
-
body += c2.toString();
|
|
14359
|
-
});
|
|
14360
|
-
res.on("end", () => {
|
|
14361
|
-
if (settled) return;
|
|
14362
|
-
settled = true;
|
|
14363
|
-
resolve5({ statusCode: res.statusCode ?? 0, body });
|
|
14364
|
-
});
|
|
14365
|
-
}
|
|
14366
|
-
);
|
|
14367
|
-
req.on("error", (err) => {
|
|
14368
|
-
if (settled) return;
|
|
14369
|
-
settled = true;
|
|
14370
|
-
reject(err);
|
|
14371
|
-
});
|
|
14372
|
-
req.on("timeout", () => {
|
|
14373
|
-
req.destroy();
|
|
14374
|
-
});
|
|
14375
|
-
req.write(payload);
|
|
14376
|
-
req.end();
|
|
14377
|
-
});
|
|
14378
|
-
}
|
|
14379
|
-
function _get(url, headers) {
|
|
14380
|
-
return new Promise((resolve5, reject) => {
|
|
14381
|
-
let settled = false;
|
|
14382
|
-
const u2 = new URL(url);
|
|
14383
|
-
const lib = u2.protocol === "https:" ? https6 : http6;
|
|
14384
|
-
const req = lib.request(
|
|
14385
|
-
{
|
|
14386
|
-
hostname: u2.hostname,
|
|
14387
|
-
port: u2.port || (u2.protocol === "https:" ? 443 : 80),
|
|
14388
|
-
path: u2.pathname + u2.search,
|
|
14389
|
-
method: "GET",
|
|
14390
|
-
headers: {
|
|
14391
|
-
...headers,
|
|
14392
|
-
...vercelBypassHeader()
|
|
14393
|
-
},
|
|
14394
|
-
timeout: 8e3
|
|
14395
|
-
},
|
|
14396
|
-
(res) => {
|
|
14397
|
-
let body = "";
|
|
14398
|
-
res.on("data", (c2) => {
|
|
14399
|
-
body += c2.toString();
|
|
14400
|
-
});
|
|
14401
|
-
res.on("end", () => {
|
|
14402
|
-
if (settled) return;
|
|
14403
|
-
settled = true;
|
|
14404
|
-
resolve5({ statusCode: res.statusCode ?? 0, body });
|
|
14405
|
-
});
|
|
14406
|
-
}
|
|
14407
|
-
);
|
|
14408
|
-
req.on("error", (err) => {
|
|
14409
|
-
if (settled) return;
|
|
14410
|
-
settled = true;
|
|
14411
|
-
reject(err);
|
|
14412
|
-
});
|
|
14413
|
-
req.on("timeout", () => {
|
|
14414
|
-
req.destroy();
|
|
14415
|
-
});
|
|
14416
|
-
req.end();
|
|
14417
|
-
});
|
|
14418
|
-
}
|
|
14419
|
-
|
|
14420
|
-
// src/services/streaming-emitter.service.ts
|
|
14421
15020
|
var API_BASE7 = resolveApiBaseUrl();
|
|
14422
15021
|
var TICK_MS = 50;
|
|
14423
|
-
var
|
|
15022
|
+
var ANSWER_POLL_MS2 = 1500;
|
|
14424
15023
|
var SELECTOR_STABLE_MS = 800;
|
|
14425
15024
|
var MAX_RETRIES2 = 1;
|
|
14426
15025
|
var RETRY_BACKOFF_MS2 = 200;
|
|
@@ -14460,7 +15059,7 @@ var StreamingEmitterService = class {
|
|
|
14460
15059
|
this.tickTimer = setInterval(() => this.tick(), TICK_MS);
|
|
14461
15060
|
this.answerPollTimer = setInterval(() => {
|
|
14462
15061
|
void this.pollPendingAnswer();
|
|
14463
|
-
},
|
|
15062
|
+
}, ANSWER_POLL_MS2);
|
|
14464
15063
|
log.trace("streamingEmitter", `started session=${this.opts.sessionId.slice(0, 8)}`);
|
|
14465
15064
|
}
|
|
14466
15065
|
/**
|
|
@@ -14481,11 +15080,11 @@ var StreamingEmitterService = class {
|
|
|
14481
15080
|
}
|
|
14482
15081
|
if (this.activeChunk) {
|
|
14483
15082
|
const finalContent = this.activeChunk.currentContent;
|
|
14484
|
-
const
|
|
15083
|
+
const chunk2 = this.activeChunk;
|
|
14485
15084
|
this.activeChunk = null;
|
|
14486
15085
|
await this.postChunk({
|
|
14487
|
-
chunkId:
|
|
14488
|
-
kind:
|
|
15086
|
+
chunkId: chunk2.chunkId,
|
|
15087
|
+
kind: chunk2.kind,
|
|
14489
15088
|
content: finalContent,
|
|
14490
15089
|
isFinal: true
|
|
14491
15090
|
});
|
|
@@ -14557,17 +15156,17 @@ var StreamingEmitterService = class {
|
|
|
14557
15156
|
this.maybeFlushActive(false);
|
|
14558
15157
|
}
|
|
14559
15158
|
maybeFlushActive(force) {
|
|
14560
|
-
const
|
|
14561
|
-
if (!
|
|
15159
|
+
const chunk2 = this.activeChunk;
|
|
15160
|
+
if (!chunk2) return;
|
|
14562
15161
|
const now = Date.now();
|
|
14563
|
-
if (!force && now -
|
|
14564
|
-
if (
|
|
14565
|
-
|
|
14566
|
-
|
|
15162
|
+
if (!force && now - chunk2.lastEmitAt < TICK_MS) return;
|
|
15163
|
+
if (chunk2.currentContent === chunk2.emittedContent) return;
|
|
15164
|
+
chunk2.emittedContent = chunk2.currentContent;
|
|
15165
|
+
chunk2.lastEmitAt = now;
|
|
14567
15166
|
void this.postChunk({
|
|
14568
|
-
chunkId:
|
|
14569
|
-
kind:
|
|
14570
|
-
content:
|
|
15167
|
+
chunkId: chunk2.chunkId,
|
|
15168
|
+
kind: chunk2.kind,
|
|
15169
|
+
content: chunk2.currentContent,
|
|
14571
15170
|
isFinal: false
|
|
14572
15171
|
});
|
|
14573
15172
|
}
|
|
@@ -14634,7 +15233,7 @@ var StreamingEmitterService = class {
|
|
|
14634
15233
|
if (!this.pendingAnswer) return;
|
|
14635
15234
|
const questionId = this.pendingAnswer.questionId;
|
|
14636
15235
|
try {
|
|
14637
|
-
const { statusCode, body } = await
|
|
15236
|
+
const { statusCode, body } = await _transport2.get(
|
|
14638
15237
|
`${this.apiBase}/api/sessions/${encodeURIComponent(this.opts.sessionId)}/pending-answer?questionId=${encodeURIComponent(questionId)}&pluginId=${encodeURIComponent(this.opts.pluginId)}`,
|
|
14639
15238
|
this.headers
|
|
14640
15239
|
);
|
|
@@ -14645,7 +15244,7 @@ var StreamingEmitterService = class {
|
|
|
14645
15244
|
log.warn("streamingEmitter", `pending-answer status=${statusCode} body=${body.slice(0, 200)}`);
|
|
14646
15245
|
return;
|
|
14647
15246
|
}
|
|
14648
|
-
const parsed =
|
|
15247
|
+
const parsed = parsePendingAnswerResponse2(body);
|
|
14649
15248
|
if (!parsed || parsed.questionId !== questionId) return;
|
|
14650
15249
|
const pending = this.pendingAnswer;
|
|
14651
15250
|
this.pendingAnswer = null;
|
|
@@ -14695,7 +15294,7 @@ var StreamingEmitterService = class {
|
|
|
14695
15294
|
});
|
|
14696
15295
|
for (let attempt = 0; attempt <= MAX_RETRIES2; attempt += 1) {
|
|
14697
15296
|
try {
|
|
14698
|
-
const { statusCode, body: resBody } = await
|
|
15297
|
+
const { statusCode, body: resBody } = await _transport2.post(url, this.headers, payload);
|
|
14699
15298
|
if (statusCode >= 200 && statusCode < 300) {
|
|
14700
15299
|
log.trace("streamingEmitter", `post ok url=${url} status=${statusCode}`);
|
|
14701
15300
|
return;
|
|
@@ -14742,7 +15341,7 @@ function classifyLine(line, parseChrome, runtime) {
|
|
|
14742
15341
|
if (filtered.length === 0) return null;
|
|
14743
15342
|
return "text";
|
|
14744
15343
|
}
|
|
14745
|
-
function
|
|
15344
|
+
function parsePendingAnswerResponse2(body) {
|
|
14746
15345
|
if (!body) return null;
|
|
14747
15346
|
let parsed;
|
|
14748
15347
|
try {
|
|
@@ -14784,7 +15383,7 @@ function buildKeepAlive(ctx) {
|
|
|
14784
15383
|
let timer = null;
|
|
14785
15384
|
async function setIdleTimeout(minutes) {
|
|
14786
15385
|
if (!ctx.inCodespace || !ctx.codespaceName) return;
|
|
14787
|
-
await new Promise((
|
|
15386
|
+
await new Promise((resolve6) => {
|
|
14788
15387
|
const proc = (0, import_child_process10.spawn)(
|
|
14789
15388
|
"gh",
|
|
14790
15389
|
[
|
|
@@ -14798,8 +15397,8 @@ function buildKeepAlive(ctx) {
|
|
|
14798
15397
|
{ stdio: "ignore", detached: true }
|
|
14799
15398
|
);
|
|
14800
15399
|
proc.unref();
|
|
14801
|
-
proc.on("exit", () =>
|
|
14802
|
-
proc.on("error", () =>
|
|
15400
|
+
proc.on("exit", () => resolve6());
|
|
15401
|
+
proc.on("error", () => resolve6());
|
|
14803
15402
|
});
|
|
14804
15403
|
}
|
|
14805
15404
|
return {
|
|
@@ -14822,9 +15421,9 @@ function buildKeepAlive(ctx) {
|
|
|
14822
15421
|
}
|
|
14823
15422
|
|
|
14824
15423
|
// src/commands/start/handlers.ts
|
|
14825
|
-
var
|
|
15424
|
+
var fs31 = __toESM(require("fs"));
|
|
14826
15425
|
var os24 = __toESM(require("os"));
|
|
14827
|
-
var
|
|
15426
|
+
var path37 = __toESM(require("path"));
|
|
14828
15427
|
var import_crypto5 = require("crypto");
|
|
14829
15428
|
var import_child_process15 = require("child_process");
|
|
14830
15429
|
|
|
@@ -14948,8 +15547,8 @@ function parsePayload2(schema, raw) {
|
|
|
14948
15547
|
}
|
|
14949
15548
|
|
|
14950
15549
|
// src/services/file-ops.service.ts
|
|
14951
|
-
var
|
|
14952
|
-
var
|
|
15550
|
+
var fs24 = __toESM(require("fs/promises"));
|
|
15551
|
+
var path29 = __toESM(require("path"));
|
|
14953
15552
|
var MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
14954
15553
|
var MAX_WALK_DEPTH = 6;
|
|
14955
15554
|
var MAX_VISITED_DIRS = 5e3;
|
|
@@ -14984,12 +15583,12 @@ var SUBDIR_IGNORE = /* @__PURE__ */ new Set([
|
|
|
14984
15583
|
"__pycache__"
|
|
14985
15584
|
]);
|
|
14986
15585
|
function isUnder(parent, candidate) {
|
|
14987
|
-
const rel =
|
|
14988
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
15586
|
+
const rel = path29.relative(parent, candidate);
|
|
15587
|
+
return rel === "" || !rel.startsWith("..") && !path29.isAbsolute(rel);
|
|
14989
15588
|
}
|
|
14990
15589
|
async function isExistingFile(absPath) {
|
|
14991
15590
|
try {
|
|
14992
|
-
const stat3 = await
|
|
15591
|
+
const stat3 = await fs24.stat(absPath);
|
|
14993
15592
|
return stat3.isFile();
|
|
14994
15593
|
} catch {
|
|
14995
15594
|
return false;
|
|
@@ -15002,13 +15601,13 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
|
|
|
15002
15601
|
ctx.visited++;
|
|
15003
15602
|
let entries = [];
|
|
15004
15603
|
try {
|
|
15005
|
-
entries = await
|
|
15604
|
+
entries = await fs24.readdir(dir, { withFileTypes: true });
|
|
15006
15605
|
} catch {
|
|
15007
15606
|
return;
|
|
15008
15607
|
}
|
|
15009
15608
|
for (const e of entries) {
|
|
15010
15609
|
if (!e.isFile()) continue;
|
|
15011
|
-
const full =
|
|
15610
|
+
const full = path29.join(dir, e.name);
|
|
15012
15611
|
if (needleVariants.some((needle) => full.endsWith(needle))) {
|
|
15013
15612
|
ctx.matches.push(full);
|
|
15014
15613
|
if (ctx.matches.length >= ctx.cap) return;
|
|
@@ -15018,21 +15617,21 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
|
|
|
15018
15617
|
if (!e.isDirectory()) continue;
|
|
15019
15618
|
if (SUBDIR_IGNORE.has(e.name)) continue;
|
|
15020
15619
|
if (e.name.startsWith(".") && SUBDIR_IGNORE.has(e.name)) continue;
|
|
15021
|
-
await walkForSuffix(
|
|
15620
|
+
await walkForSuffix(path29.join(dir, e.name), needleVariants, depth + 1, ctx);
|
|
15022
15621
|
if (ctx.matches.length >= ctx.cap) return;
|
|
15023
15622
|
}
|
|
15024
15623
|
}
|
|
15025
15624
|
async function findFile(rawPath) {
|
|
15026
15625
|
const cwd = process.cwd();
|
|
15027
|
-
if (
|
|
15028
|
-
const abs =
|
|
15626
|
+
if (path29.isAbsolute(rawPath)) {
|
|
15627
|
+
const abs = path29.normalize(rawPath);
|
|
15029
15628
|
if (isUnder(cwd, abs) && await isExistingFile(abs)) return abs;
|
|
15030
15629
|
}
|
|
15031
|
-
const direct =
|
|
15630
|
+
const direct = path29.resolve(cwd, rawPath);
|
|
15032
15631
|
if (isUnder(cwd, direct) && await isExistingFile(direct)) return direct;
|
|
15033
|
-
const normalized =
|
|
15632
|
+
const normalized = path29.normalize(rawPath).replace(/^[./\\]+/, "");
|
|
15034
15633
|
const needles = [
|
|
15035
|
-
`${
|
|
15634
|
+
`${path29.sep}${normalized}`,
|
|
15036
15635
|
`/${normalized}`
|
|
15037
15636
|
].filter((v, i, a) => a.indexOf(v) === i);
|
|
15038
15637
|
const ctx = { visited: 0, matches: [], cap: 16 };
|
|
@@ -15046,7 +15645,7 @@ async function findWriteTarget(rawPath) {
|
|
|
15046
15645
|
const found = await findFile(rawPath);
|
|
15047
15646
|
if (found) return found;
|
|
15048
15647
|
const cwd = process.cwd();
|
|
15049
|
-
const fallback =
|
|
15648
|
+
const fallback = path29.isAbsolute(rawPath) ? path29.normalize(rawPath) : path29.resolve(cwd, rawPath);
|
|
15050
15649
|
if (!isUnder(cwd, fallback)) return null;
|
|
15051
15650
|
return fallback;
|
|
15052
15651
|
}
|
|
@@ -15063,11 +15662,11 @@ async function readProjectFile(rawPath) {
|
|
|
15063
15662
|
if (!abs) {
|
|
15064
15663
|
return { error: `File not found in the project tree: ${rawPath}` };
|
|
15065
15664
|
}
|
|
15066
|
-
const stat3 = await
|
|
15665
|
+
const stat3 = await fs24.stat(abs);
|
|
15067
15666
|
if (stat3.size > MAX_FILE_BYTES) {
|
|
15068
15667
|
return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
|
|
15069
15668
|
}
|
|
15070
|
-
const buf = await
|
|
15669
|
+
const buf = await fs24.readFile(abs);
|
|
15071
15670
|
if (looksBinary(buf)) {
|
|
15072
15671
|
return { error: "Binary file \u2014 refusing to open in a code editor." };
|
|
15073
15672
|
}
|
|
@@ -15086,8 +15685,8 @@ async function writeProjectFile(rawPath, content) {
|
|
|
15086
15685
|
if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
|
|
15087
15686
|
return { error: "Content too large." };
|
|
15088
15687
|
}
|
|
15089
|
-
await
|
|
15090
|
-
await
|
|
15688
|
+
await fs24.mkdir(path29.dirname(abs), { recursive: true });
|
|
15689
|
+
await fs24.writeFile(abs, content, "utf-8");
|
|
15091
15690
|
return { ok: true };
|
|
15092
15691
|
} catch (e) {
|
|
15093
15692
|
const msg = e instanceof Error ? e.message : "Write failed";
|
|
@@ -15098,8 +15697,8 @@ async function writeProjectFile(rawPath, content) {
|
|
|
15098
15697
|
// src/services/project-ops.service.ts
|
|
15099
15698
|
var import_child_process11 = require("child_process");
|
|
15100
15699
|
var import_util2 = require("util");
|
|
15101
|
-
var
|
|
15102
|
-
var
|
|
15700
|
+
var fs25 = __toESM(require("fs/promises"));
|
|
15701
|
+
var path30 = __toESM(require("path"));
|
|
15103
15702
|
var execFileP3 = (0, import_util2.promisify)(import_child_process11.execFile);
|
|
15104
15703
|
var PROJECT_IGNORE = /* @__PURE__ */ new Set([
|
|
15105
15704
|
"node_modules",
|
|
@@ -15147,7 +15746,7 @@ async function listProjectFiles(opts = {}) {
|
|
|
15147
15746
|
}
|
|
15148
15747
|
let entries = [];
|
|
15149
15748
|
try {
|
|
15150
|
-
entries = await
|
|
15749
|
+
entries = await fs25.readdir(dir, { withFileTypes: true });
|
|
15151
15750
|
} catch {
|
|
15152
15751
|
return;
|
|
15153
15752
|
}
|
|
@@ -15157,18 +15756,18 @@ async function listProjectFiles(opts = {}) {
|
|
|
15157
15756
|
return;
|
|
15158
15757
|
}
|
|
15159
15758
|
if (PROJECT_IGNORE.has(e.name)) continue;
|
|
15160
|
-
const full =
|
|
15759
|
+
const full = path30.join(dir, e.name);
|
|
15161
15760
|
if (e.isDirectory()) {
|
|
15162
15761
|
if (depth >= 12) continue;
|
|
15163
15762
|
await walk(full, depth + 1);
|
|
15164
15763
|
} else if (e.isFile()) {
|
|
15165
|
-
const rel =
|
|
15764
|
+
const rel = path30.relative(root, full);
|
|
15166
15765
|
if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
|
|
15167
15766
|
continue;
|
|
15168
15767
|
}
|
|
15169
15768
|
let size = 0;
|
|
15170
15769
|
try {
|
|
15171
|
-
const st3 = await
|
|
15770
|
+
const st3 = await fs25.stat(full);
|
|
15172
15771
|
size = st3.size;
|
|
15173
15772
|
} catch {
|
|
15174
15773
|
}
|
|
@@ -15270,8 +15869,8 @@ async function gitStatus(cwd) {
|
|
|
15270
15869
|
let hasMergeInProgress = false;
|
|
15271
15870
|
try {
|
|
15272
15871
|
const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
|
|
15273
|
-
const mergeHead =
|
|
15274
|
-
await
|
|
15872
|
+
const mergeHead = path30.isAbsolute(gitDir) ? path30.join(gitDir, "MERGE_HEAD") : path30.join(root, gitDir, "MERGE_HEAD");
|
|
15873
|
+
await fs25.access(mergeHead);
|
|
15275
15874
|
hasMergeInProgress = true;
|
|
15276
15875
|
} catch {
|
|
15277
15876
|
}
|
|
@@ -15417,7 +16016,7 @@ async function jsSearchFiles(opts, cwd, cap) {
|
|
|
15417
16016
|
}
|
|
15418
16017
|
let content = "";
|
|
15419
16018
|
try {
|
|
15420
|
-
content = await
|
|
16019
|
+
content = await fs25.readFile(path30.join(cwd, f.path), "utf8");
|
|
15421
16020
|
} catch {
|
|
15422
16021
|
continue;
|
|
15423
16022
|
}
|
|
@@ -15698,14 +16297,14 @@ function closeAllTerminals() {
|
|
|
15698
16297
|
|
|
15699
16298
|
// src/services/apply-file-review.service.ts
|
|
15700
16299
|
var import_child_process13 = require("child_process");
|
|
15701
|
-
var
|
|
15702
|
-
var
|
|
16300
|
+
var fs26 = __toESM(require("fs"));
|
|
16301
|
+
var path32 = __toESM(require("path"));
|
|
15703
16302
|
async function applyFileReview(workingDir, filePath, action) {
|
|
15704
|
-
if (filePath.includes("..") ||
|
|
16303
|
+
if (filePath.includes("..") || path32.isAbsolute(filePath)) {
|
|
15705
16304
|
return { ok: false, action, filePath, error: "invalid file path" };
|
|
15706
16305
|
}
|
|
15707
|
-
const absFile =
|
|
15708
|
-
const repoRoot = findGitRoot2(
|
|
16306
|
+
const absFile = path32.resolve(workingDir, filePath);
|
|
16307
|
+
const repoRoot = findGitRoot2(path32.dirname(absFile));
|
|
15709
16308
|
if (!repoRoot) {
|
|
15710
16309
|
return {
|
|
15711
16310
|
ok: false,
|
|
@@ -15714,7 +16313,7 @@ async function applyFileReview(workingDir, filePath, action) {
|
|
|
15714
16313
|
error: `no enclosing git repo for ${filePath}`
|
|
15715
16314
|
};
|
|
15716
16315
|
}
|
|
15717
|
-
const relInRepo =
|
|
16316
|
+
const relInRepo = path32.relative(repoRoot, absFile);
|
|
15718
16317
|
if (!relInRepo || relInRepo.startsWith("..")) {
|
|
15719
16318
|
return { ok: false, action, filePath, error: "path escapes repo root" };
|
|
15720
16319
|
}
|
|
@@ -15736,12 +16335,12 @@ async function applyFileReview(workingDir, filePath, action) {
|
|
|
15736
16335
|
return { ok: true, action, filePath, repoRoot };
|
|
15737
16336
|
}
|
|
15738
16337
|
function runGit3(cwd, args2) {
|
|
15739
|
-
return new Promise((
|
|
16338
|
+
return new Promise((resolve6) => {
|
|
15740
16339
|
let proc;
|
|
15741
16340
|
try {
|
|
15742
16341
|
proc = (0, import_child_process13.spawn)("git", args2, { cwd, env: process.env });
|
|
15743
16342
|
} catch (err) {
|
|
15744
|
-
|
|
16343
|
+
resolve6({ ok: false, code: -1, stdout: "", stderr: err.message });
|
|
15745
16344
|
return;
|
|
15746
16345
|
}
|
|
15747
16346
|
let stdout = "";
|
|
@@ -15754,26 +16353,26 @@ function runGit3(cwd, args2) {
|
|
|
15754
16353
|
});
|
|
15755
16354
|
proc.on(
|
|
15756
16355
|
"error",
|
|
15757
|
-
(err) =>
|
|
16356
|
+
(err) => resolve6({ ok: false, code: -1, stdout, stderr: stderr + err.message })
|
|
15758
16357
|
);
|
|
15759
16358
|
proc.on(
|
|
15760
16359
|
"close",
|
|
15761
|
-
(code) =>
|
|
16360
|
+
(code) => resolve6({ ok: code === 0, code: code ?? -1, stdout, stderr })
|
|
15762
16361
|
);
|
|
15763
16362
|
});
|
|
15764
16363
|
}
|
|
15765
16364
|
function findGitRoot2(startDir) {
|
|
15766
|
-
let dir =
|
|
16365
|
+
let dir = path32.resolve(startDir);
|
|
15767
16366
|
const seen = /* @__PURE__ */ new Set();
|
|
15768
16367
|
for (let i = 0; i < 256; i++) {
|
|
15769
16368
|
if (seen.has(dir)) return null;
|
|
15770
16369
|
seen.add(dir);
|
|
15771
16370
|
try {
|
|
15772
|
-
const stat3 =
|
|
16371
|
+
const stat3 = fs26.statSync(path32.join(dir, ".git"), { throwIfNoEntry: false });
|
|
15773
16372
|
if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
|
|
15774
16373
|
} catch {
|
|
15775
16374
|
}
|
|
15776
|
-
const parent =
|
|
16375
|
+
const parent = path32.dirname(dir);
|
|
15777
16376
|
if (parent === dir) return null;
|
|
15778
16377
|
dir = parent;
|
|
15779
16378
|
}
|
|
@@ -15781,9 +16380,9 @@ function findGitRoot2(startDir) {
|
|
|
15781
16380
|
}
|
|
15782
16381
|
|
|
15783
16382
|
// src/commands/link.ts
|
|
15784
|
-
var
|
|
15785
|
-
var
|
|
15786
|
-
var
|
|
16383
|
+
var import_node_crypto7 = require("crypto");
|
|
16384
|
+
var fs27 = __toESM(require("fs"));
|
|
16385
|
+
var path33 = __toESM(require("path"));
|
|
15787
16386
|
var import_chokidar = __toESM(require("chokidar"));
|
|
15788
16387
|
var import_picocolors2 = __toESM(require("picocolors"));
|
|
15789
16388
|
|
|
@@ -15843,7 +16442,7 @@ function parseLinkArgs(args2) {
|
|
|
15843
16442
|
if (apiKeyFileArg) {
|
|
15844
16443
|
const filePath = apiKeyFileArg.slice("--api-key-file=".length);
|
|
15845
16444
|
try {
|
|
15846
|
-
apiKey =
|
|
16445
|
+
apiKey = fs27.readFileSync(path33.resolve(filePath), "utf8").trim();
|
|
15847
16446
|
} catch (err) {
|
|
15848
16447
|
throw new Error(`Could not read --api-key-file ${filePath}: ${err.message}`);
|
|
15849
16448
|
}
|
|
@@ -15870,7 +16469,7 @@ async function link(args2 = []) {
|
|
|
15870
16469
|
await linkDryRunPreflight(ctx);
|
|
15871
16470
|
return;
|
|
15872
16471
|
}
|
|
15873
|
-
const pluginId = (0,
|
|
16472
|
+
const pluginId = (0, import_node_crypto7.randomUUID)();
|
|
15874
16473
|
const spin = dist_exports.spinner();
|
|
15875
16474
|
spin.start("Requesting pairing code...");
|
|
15876
16475
|
const pairing = await requestCode(pluginId);
|
|
@@ -15888,7 +16487,7 @@ async function link(args2 = []) {
|
|
|
15888
16487
|
waitSpin.start(waitMsg());
|
|
15889
16488
|
const countdown = setInterval(() => waitSpin.message(waitMsg()), 1e3);
|
|
15890
16489
|
countdown.unref?.();
|
|
15891
|
-
const paired = await new Promise((
|
|
16490
|
+
const paired = await new Promise((resolve6, reject) => {
|
|
15892
16491
|
let stopPoll = null;
|
|
15893
16492
|
const sigint = () => {
|
|
15894
16493
|
clearInterval(countdown);
|
|
@@ -15901,7 +16500,7 @@ async function link(args2 = []) {
|
|
|
15901
16500
|
process.removeListener("SIGINT", sigint);
|
|
15902
16501
|
clearInterval(countdown);
|
|
15903
16502
|
waitSpin.stop("Paired");
|
|
15904
|
-
|
|
16503
|
+
resolve6(info);
|
|
15905
16504
|
},
|
|
15906
16505
|
() => {
|
|
15907
16506
|
clearInterval(countdown);
|
|
@@ -15937,7 +16536,7 @@ async function link(args2 = []) {
|
|
|
15937
16536
|
return;
|
|
15938
16537
|
}
|
|
15939
16538
|
if (parsed.tokenFile) {
|
|
15940
|
-
const credential =
|
|
16539
|
+
const credential = fs27.readFileSync(path33.resolve(parsed.tokenFile), "utf8").trim();
|
|
15941
16540
|
if (!credential) {
|
|
15942
16541
|
showError(`--token-file ${parsed.tokenFile} is empty.`);
|
|
15943
16542
|
process.exit(1);
|
|
@@ -16036,14 +16635,14 @@ async function captureFreshCredentials(ctx) {
|
|
|
16036
16635
|
}
|
|
16037
16636
|
};
|
|
16038
16637
|
try {
|
|
16039
|
-
const token = await new Promise((
|
|
16638
|
+
const token = await new Promise((resolve6, reject) => {
|
|
16040
16639
|
let settled = false;
|
|
16041
16640
|
const tryExtract = async () => {
|
|
16042
16641
|
if (settled) return;
|
|
16043
16642
|
const t2 = await ctx.locator.extract();
|
|
16044
16643
|
if (t2 && !settled) {
|
|
16045
16644
|
settled = true;
|
|
16046
|
-
|
|
16645
|
+
resolve6(t2);
|
|
16047
16646
|
}
|
|
16048
16647
|
};
|
|
16049
16648
|
watcher.on("add", () => void tryExtract());
|
|
@@ -16447,7 +17046,7 @@ var pendingAttachmentFiles = /* @__PURE__ */ new Set();
|
|
|
16447
17046
|
function cleanupAttachmentTempFiles() {
|
|
16448
17047
|
for (const p2 of pendingAttachmentFiles) {
|
|
16449
17048
|
try {
|
|
16450
|
-
|
|
17049
|
+
fs31.unlinkSync(p2);
|
|
16451
17050
|
} catch {
|
|
16452
17051
|
}
|
|
16453
17052
|
}
|
|
@@ -16456,8 +17055,8 @@ function cleanupAttachmentTempFiles() {
|
|
|
16456
17055
|
function saveFilesTemp(files) {
|
|
16457
17056
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
16458
17057
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
16459
|
-
const tmpPath =
|
|
16460
|
-
|
|
17058
|
+
const tmpPath = path37.join(os24.tmpdir(), `codeam-${(0, import_crypto5.randomUUID)()}-${safeName}`);
|
|
17059
|
+
fs31.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
16461
17060
|
pendingAttachmentFiles.add(tmpPath);
|
|
16462
17061
|
return tmpPath;
|
|
16463
17062
|
});
|
|
@@ -16477,7 +17076,7 @@ var startTask = (ctx, _cmd, parsed) => {
|
|
|
16477
17076
|
setTimeout(() => {
|
|
16478
17077
|
for (const p2 of paths) {
|
|
16479
17078
|
try {
|
|
16480
|
-
|
|
17079
|
+
fs31.unlinkSync(p2);
|
|
16481
17080
|
} catch {
|
|
16482
17081
|
}
|
|
16483
17082
|
pendingAttachmentFiles.delete(p2);
|
|
@@ -16645,7 +17244,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
16645
17244
|
ctx.relay.stop();
|
|
16646
17245
|
process.exit(0);
|
|
16647
17246
|
};
|
|
16648
|
-
var
|
|
17247
|
+
var readFile5 = async (ctx, cmd, parsed) => {
|
|
16649
17248
|
if (!parsed.path) {
|
|
16650
17249
|
await ctx.relay.sendResult(cmd.id, "failed", { error: "Missing path" });
|
|
16651
17250
|
return;
|
|
@@ -16653,7 +17252,7 @@ var readFile4 = async (ctx, cmd, parsed) => {
|
|
|
16653
17252
|
const result = await readProjectFile(parsed.path);
|
|
16654
17253
|
await ctx.relay.sendResult(cmd.id, "completed", result);
|
|
16655
17254
|
};
|
|
16656
|
-
var
|
|
17255
|
+
var writeFile4 = async (ctx, cmd, parsed) => {
|
|
16657
17256
|
if (!parsed.path || typeof parsed.content !== "string") {
|
|
16658
17257
|
await ctx.relay.sendResult(cmd.id, "failed", { error: "Missing path or content" });
|
|
16659
17258
|
return;
|
|
@@ -17104,8 +17703,8 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
17104
17703
|
let readyMatched = false;
|
|
17105
17704
|
let expoUrl = null;
|
|
17106
17705
|
const readyRe = new RegExp(detection.ready_pattern);
|
|
17107
|
-
const onChunk = (
|
|
17108
|
-
const s =
|
|
17706
|
+
const onChunk = (chunk2) => {
|
|
17707
|
+
const s = chunk2.toString();
|
|
17109
17708
|
if (!readyMatched && readyRe.test(s)) readyMatched = true;
|
|
17110
17709
|
if (!expoUrl && detection.framework === "Expo") expoUrl = parseExpoUrl(s);
|
|
17111
17710
|
};
|
|
@@ -17228,8 +17827,8 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
17228
17827
|
stdio: ["ignore", "pipe", "pipe"]
|
|
17229
17828
|
});
|
|
17230
17829
|
let parsedUrl = null;
|
|
17231
|
-
const onTunnelChunk = (
|
|
17232
|
-
const s =
|
|
17830
|
+
const onTunnelChunk = (chunk2) => {
|
|
17831
|
+
const s = chunk2.toString();
|
|
17233
17832
|
if (!parsedUrl) parsedUrl = parseCloudflaredUrl(s);
|
|
17234
17833
|
const trimmed = s.replace(/\n+$/g, "");
|
|
17235
17834
|
if (trimmed.length > 0) log.info("preview", `cloudflared: ${trimmed}`);
|
|
@@ -17321,22 +17920,22 @@ var previewStopH = (ctx) => {
|
|
|
17321
17920
|
})();
|
|
17322
17921
|
};
|
|
17323
17922
|
function runOnce(cmd, args2, cwd, env) {
|
|
17324
|
-
return new Promise((
|
|
17923
|
+
return new Promise((resolve6) => {
|
|
17325
17924
|
const child = (0, import_child_process15.spawn)(cmd, args2, {
|
|
17326
17925
|
cwd,
|
|
17327
17926
|
env: { ...process.env, ...env ?? {} },
|
|
17328
17927
|
stdio: ["ignore", "pipe", "pipe"]
|
|
17329
17928
|
});
|
|
17330
17929
|
const tag = `setup:${cmd}`;
|
|
17331
|
-
const onChunk = (
|
|
17332
|
-
const text =
|
|
17930
|
+
const onChunk = (chunk2) => {
|
|
17931
|
+
const text = chunk2.toString().replace(/\n+$/g, "");
|
|
17333
17932
|
if (text.length === 0) return;
|
|
17334
17933
|
log.info("preview", `${tag}: ${text}`);
|
|
17335
17934
|
};
|
|
17336
17935
|
child.stdout?.on("data", onChunk);
|
|
17337
17936
|
child.stderr?.on("data", onChunk);
|
|
17338
|
-
child.once("exit", (code) =>
|
|
17339
|
-
child.once("error", () =>
|
|
17937
|
+
child.once("exit", (code) => resolve6(code));
|
|
17938
|
+
child.once("error", () => resolve6(-1));
|
|
17340
17939
|
});
|
|
17341
17940
|
}
|
|
17342
17941
|
var savePreviewConfigH = (_ctx, _cmd, parsed) => {
|
|
@@ -17364,8 +17963,8 @@ var handlers = {
|
|
|
17364
17963
|
set_keep_alive: setKeepAlive,
|
|
17365
17964
|
session_terminated: sessionTerminated,
|
|
17366
17965
|
shutdown_session: shutdownSession,
|
|
17367
|
-
read_file:
|
|
17368
|
-
write_file:
|
|
17966
|
+
read_file: readFile5,
|
|
17967
|
+
write_file: writeFile4,
|
|
17369
17968
|
list_files: listFiles,
|
|
17370
17969
|
search_files: searchFilesH,
|
|
17371
17970
|
terminal_open: terminalOpenH,
|
|
@@ -17441,6 +18040,23 @@ async function start(requestedAgent) {
|
|
|
17441
18040
|
requestedAgent: requestedAgent ?? null
|
|
17442
18041
|
});
|
|
17443
18042
|
const cwd = process.cwd();
|
|
18043
|
+
if (process.env.CODEAM_ACP_ENABLED === "1" && session.pluginAuthToken) {
|
|
18044
|
+
const adapter = getAcpAdapter(session.agent);
|
|
18045
|
+
if (adapter) {
|
|
18046
|
+
await runAcpSession({
|
|
18047
|
+
agent: session.agent,
|
|
18048
|
+
sessionId: session.id,
|
|
18049
|
+
pluginId,
|
|
18050
|
+
pluginAuthToken: session.pluginAuthToken,
|
|
18051
|
+
adapter,
|
|
18052
|
+
cwd
|
|
18053
|
+
});
|
|
18054
|
+
return;
|
|
18055
|
+
}
|
|
18056
|
+
showInfo(
|
|
18057
|
+
`CODEAM_ACP_ENABLED is set but no ACP adapter is registered for "${session.agent}" \u2014 falling back to PTY runtime.`
|
|
18058
|
+
);
|
|
18059
|
+
}
|
|
17444
18060
|
const runtime = createRuntimeStrategy(session.agent);
|
|
17445
18061
|
const historySvc = new HistoryService(runtime, pluginId, cwd);
|
|
17446
18062
|
const keepAliveCtx = {
|
|
@@ -17688,7 +18304,7 @@ async function pair(args2 = []) {
|
|
|
17688
18304
|
waitSpin.message(waitMessage());
|
|
17689
18305
|
}, 1e3);
|
|
17690
18306
|
countdownInterval.unref?.();
|
|
17691
|
-
await new Promise((
|
|
18307
|
+
await new Promise((resolve6) => {
|
|
17692
18308
|
let stopPolling = null;
|
|
17693
18309
|
function sigintHandler() {
|
|
17694
18310
|
clearInterval(countdownInterval);
|
|
@@ -17736,7 +18352,7 @@ async function pair(args2 = []) {
|
|
|
17736
18352
|
pluginAuthToken: info.pluginAuthToken
|
|
17737
18353
|
});
|
|
17738
18354
|
}
|
|
17739
|
-
|
|
18355
|
+
resolve6();
|
|
17740
18356
|
},
|
|
17741
18357
|
() => {
|
|
17742
18358
|
clearInterval(countdownInterval);
|
|
@@ -17788,7 +18404,7 @@ async function autoLinkAfterPair(opts) {
|
|
|
17788
18404
|
}
|
|
17789
18405
|
|
|
17790
18406
|
// src/commands/pair-auto.ts
|
|
17791
|
-
var
|
|
18407
|
+
var fs32 = __toESM(require("fs"));
|
|
17792
18408
|
var os25 = __toESM(require("os"));
|
|
17793
18409
|
var import_crypto7 = require("crypto");
|
|
17794
18410
|
|
|
@@ -17957,12 +18573,12 @@ function readTokenFromArgs(args2) {
|
|
|
17957
18573
|
}
|
|
17958
18574
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
17959
18575
|
if (fileFlag) {
|
|
17960
|
-
const
|
|
18576
|
+
const path44 = fileFlag.slice("--token-file=".length);
|
|
17961
18577
|
try {
|
|
17962
|
-
const content =
|
|
17963
|
-
if (content.length === 0) fail(`--token-file ${
|
|
18578
|
+
const content = fs32.readFileSync(path44, "utf8").trim();
|
|
18579
|
+
if (content.length === 0) fail(`--token-file ${path44} is empty`);
|
|
17964
18580
|
try {
|
|
17965
|
-
|
|
18581
|
+
fs32.unlinkSync(path44);
|
|
17966
18582
|
} catch {
|
|
17967
18583
|
}
|
|
17968
18584
|
return content;
|
|
@@ -18228,7 +18844,7 @@ var import_picocolors10 = __toESM(require("picocolors"));
|
|
|
18228
18844
|
var import_child_process16 = require("child_process");
|
|
18229
18845
|
var import_util4 = require("util");
|
|
18230
18846
|
var import_picocolors8 = __toESM(require("picocolors"));
|
|
18231
|
-
var
|
|
18847
|
+
var path38 = __toESM(require("path"));
|
|
18232
18848
|
var execFileP5 = (0, import_util4.promisify)(import_child_process16.execFile);
|
|
18233
18849
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
18234
18850
|
function resetStdinForChild() {
|
|
@@ -18272,12 +18888,12 @@ var GitHubCodespacesProvider = class {
|
|
|
18272
18888
|
}
|
|
18273
18889
|
if (!isAuthed) {
|
|
18274
18890
|
resetStdinForChild();
|
|
18275
|
-
await new Promise((
|
|
18891
|
+
await new Promise((resolve6, reject) => {
|
|
18276
18892
|
const proc = (0, import_child_process16.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
|
|
18277
18893
|
stdio: "inherit"
|
|
18278
18894
|
});
|
|
18279
18895
|
proc.on("exit", (code) => {
|
|
18280
|
-
if (code === 0)
|
|
18896
|
+
if (code === 0) resolve6();
|
|
18281
18897
|
else reject(new Error("gh auth login failed."));
|
|
18282
18898
|
});
|
|
18283
18899
|
proc.on("error", reject);
|
|
@@ -18306,13 +18922,13 @@ var GitHubCodespacesProvider = class {
|
|
|
18306
18922
|
}
|
|
18307
18923
|
wt(noteLines.join("\n"), "One more permission needed");
|
|
18308
18924
|
resetStdinForChild();
|
|
18309
|
-
const refreshCode = await new Promise((
|
|
18925
|
+
const refreshCode = await new Promise((resolve6, reject) => {
|
|
18310
18926
|
const proc = (0, import_child_process16.spawn)(
|
|
18311
18927
|
"gh",
|
|
18312
18928
|
["auth", "refresh", "-h", "github.com", "-s", "codespace"],
|
|
18313
18929
|
{ stdio: "inherit" }
|
|
18314
18930
|
);
|
|
18315
|
-
proc.on("exit", (code) =>
|
|
18931
|
+
proc.on("exit", (code) => resolve6(code ?? 1));
|
|
18316
18932
|
proc.on("error", reject);
|
|
18317
18933
|
});
|
|
18318
18934
|
if (refreshCode !== 0) {
|
|
@@ -18456,10 +19072,10 @@ var GitHubCodespacesProvider = class {
|
|
|
18456
19072
|
if (q(proceed) || !proceed) return;
|
|
18457
19073
|
O2.step(`Installing gh via ${installCmd.describe}\u2026`);
|
|
18458
19074
|
resetStdinForChild();
|
|
18459
|
-
const ok = await new Promise((
|
|
19075
|
+
const ok = await new Promise((resolve6) => {
|
|
18460
19076
|
const proc = (0, import_child_process16.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
|
|
18461
|
-
proc.on("exit", (code) =>
|
|
18462
|
-
proc.on("error", () =>
|
|
19077
|
+
proc.on("exit", (code) => resolve6(code === 0));
|
|
19078
|
+
proc.on("error", () => resolve6(false));
|
|
18463
19079
|
});
|
|
18464
19080
|
if (ok) O2.success("gh installed");
|
|
18465
19081
|
else O2.error("gh install failed");
|
|
@@ -18483,14 +19099,14 @@ var GitHubCodespacesProvider = class {
|
|
|
18483
19099
|
"Expanding GitHub scopes"
|
|
18484
19100
|
);
|
|
18485
19101
|
resetStdinForChild();
|
|
18486
|
-
await new Promise((
|
|
19102
|
+
await new Promise((resolve6, reject) => {
|
|
18487
19103
|
const proc = (0, import_child_process16.spawn)(
|
|
18488
19104
|
"gh",
|
|
18489
19105
|
["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
|
|
18490
19106
|
{ stdio: "inherit" }
|
|
18491
19107
|
);
|
|
18492
19108
|
proc.on("exit", (code) => {
|
|
18493
|
-
if (code === 0)
|
|
19109
|
+
if (code === 0) resolve6();
|
|
18494
19110
|
else reject(new Error(
|
|
18495
19111
|
"gh auth refresh failed. Re-run `gh auth refresh -h github.com -s repo,read:org` manually."
|
|
18496
19112
|
));
|
|
@@ -18661,13 +19277,13 @@ var GitHubCodespacesProvider = class {
|
|
|
18661
19277
|
}
|
|
18662
19278
|
async streamCommand(workspaceId, command2) {
|
|
18663
19279
|
resetStdinForChild();
|
|
18664
|
-
return new Promise((
|
|
19280
|
+
return new Promise((resolve6, reject) => {
|
|
18665
19281
|
const proc = (0, import_child_process16.spawn)(
|
|
18666
19282
|
"gh",
|
|
18667
19283
|
["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
|
|
18668
19284
|
{ stdio: "inherit" }
|
|
18669
19285
|
);
|
|
18670
|
-
proc.on("exit", (code) =>
|
|
19286
|
+
proc.on("exit", (code) => resolve6({ code: code ?? 0 }));
|
|
18671
19287
|
proc.on("error", reject);
|
|
18672
19288
|
});
|
|
18673
19289
|
}
|
|
@@ -18688,7 +19304,7 @@ var GitHubCodespacesProvider = class {
|
|
|
18688
19304
|
"--",
|
|
18689
19305
|
`mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
|
|
18690
19306
|
];
|
|
18691
|
-
await new Promise((
|
|
19307
|
+
await new Promise((resolve6, reject) => {
|
|
18692
19308
|
const tar = (0, import_child_process16.spawn)("tar", tarArgs, {
|
|
18693
19309
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18694
19310
|
env: tarEnv
|
|
@@ -18708,7 +19324,7 @@ var GitHubCodespacesProvider = class {
|
|
|
18708
19324
|
ssh.on("error", reject);
|
|
18709
19325
|
ssh.on("exit", (code) => {
|
|
18710
19326
|
if (code === 0) {
|
|
18711
|
-
|
|
19327
|
+
resolve6();
|
|
18712
19328
|
} else {
|
|
18713
19329
|
const reason = (sshErr || tarErr || `exit ${code}`).trim().slice(0, 500);
|
|
18714
19330
|
reject(new Error(`Remote tar failed: ${reason}`));
|
|
@@ -18717,7 +19333,7 @@ var GitHubCodespacesProvider = class {
|
|
|
18717
19333
|
});
|
|
18718
19334
|
}
|
|
18719
19335
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
18720
|
-
const remoteDir =
|
|
19336
|
+
const remoteDir = path38.posix.dirname(remotePath);
|
|
18721
19337
|
const parts = [
|
|
18722
19338
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
18723
19339
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -18726,7 +19342,7 @@ var GitHubCodespacesProvider = class {
|
|
|
18726
19342
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote(remotePath)}`);
|
|
18727
19343
|
}
|
|
18728
19344
|
const cmd = parts.join(" && ");
|
|
18729
|
-
await new Promise((
|
|
19345
|
+
await new Promise((resolve6, reject) => {
|
|
18730
19346
|
const proc = (0, import_child_process16.spawn)(
|
|
18731
19347
|
"gh",
|
|
18732
19348
|
["codespace", "ssh", "-c", workspaceId, "--", cmd],
|
|
@@ -18738,7 +19354,7 @@ var GitHubCodespacesProvider = class {
|
|
|
18738
19354
|
});
|
|
18739
19355
|
proc.on("error", reject);
|
|
18740
19356
|
proc.on("exit", (code) => {
|
|
18741
|
-
if (code === 0)
|
|
19357
|
+
if (code === 0) resolve6();
|
|
18742
19358
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
18743
19359
|
});
|
|
18744
19360
|
proc.stdin?.write(contents);
|
|
@@ -18787,7 +19403,7 @@ function shellQuote(s) {
|
|
|
18787
19403
|
// src/services/providers/gitpod.ts
|
|
18788
19404
|
var import_child_process17 = require("child_process");
|
|
18789
19405
|
var import_util5 = require("util");
|
|
18790
|
-
var
|
|
19406
|
+
var path39 = __toESM(require("path"));
|
|
18791
19407
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
18792
19408
|
var execFileP6 = (0, import_util5.promisify)(import_child_process17.execFile);
|
|
18793
19409
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
@@ -18828,10 +19444,10 @@ var GitpodProvider = class {
|
|
|
18828
19444
|
"Authenticating Gitpod"
|
|
18829
19445
|
);
|
|
18830
19446
|
resetStdinForChild2();
|
|
18831
|
-
await new Promise((
|
|
19447
|
+
await new Promise((resolve6, reject) => {
|
|
18832
19448
|
const proc = (0, import_child_process17.spawn)("gitpod", ["login"], { stdio: "inherit" });
|
|
18833
19449
|
proc.on("exit", (code) => {
|
|
18834
|
-
if (code === 0)
|
|
19450
|
+
if (code === 0) resolve6();
|
|
18835
19451
|
else reject(new Error("gitpod login failed."));
|
|
18836
19452
|
});
|
|
18837
19453
|
proc.on("error", reject);
|
|
@@ -18980,13 +19596,13 @@ var GitpodProvider = class {
|
|
|
18980
19596
|
}
|
|
18981
19597
|
async streamCommand(workspaceId, command2) {
|
|
18982
19598
|
resetStdinForChild2();
|
|
18983
|
-
return new Promise((
|
|
19599
|
+
return new Promise((resolve6, reject) => {
|
|
18984
19600
|
const proc = (0, import_child_process17.spawn)(
|
|
18985
19601
|
"gitpod",
|
|
18986
19602
|
["workspace", "ssh", workspaceId, "--", "-tt", command2],
|
|
18987
19603
|
{ stdio: "inherit" }
|
|
18988
19604
|
);
|
|
18989
|
-
proc.on("exit", (code) =>
|
|
19605
|
+
proc.on("exit", (code) => resolve6({ code: code ?? 0 }));
|
|
18990
19606
|
proc.on("error", reject);
|
|
18991
19607
|
});
|
|
18992
19608
|
}
|
|
@@ -19000,7 +19616,7 @@ var GitpodProvider = class {
|
|
|
19000
19616
|
tarArgs.push(".");
|
|
19001
19617
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
19002
19618
|
const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
|
|
19003
|
-
await new Promise((
|
|
19619
|
+
await new Promise((resolve6, reject) => {
|
|
19004
19620
|
const tar = (0, import_child_process17.spawn)("tar", tarArgs, {
|
|
19005
19621
|
stdio: ["ignore", "pipe", "pipe"],
|
|
19006
19622
|
env: tarEnv
|
|
@@ -19021,13 +19637,13 @@ var GitpodProvider = class {
|
|
|
19021
19637
|
tar.on("error", reject);
|
|
19022
19638
|
ssh.on("error", reject);
|
|
19023
19639
|
ssh.on("exit", (code) => {
|
|
19024
|
-
if (code === 0)
|
|
19640
|
+
if (code === 0) resolve6();
|
|
19025
19641
|
else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
19026
19642
|
});
|
|
19027
19643
|
});
|
|
19028
19644
|
}
|
|
19029
19645
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
19030
|
-
const remoteDir =
|
|
19646
|
+
const remoteDir = path39.posix.dirname(remotePath);
|
|
19031
19647
|
const parts = [
|
|
19032
19648
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
19033
19649
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -19036,7 +19652,7 @@ var GitpodProvider = class {
|
|
|
19036
19652
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote2(remotePath)}`);
|
|
19037
19653
|
}
|
|
19038
19654
|
const cmd = parts.join(" && ");
|
|
19039
|
-
await new Promise((
|
|
19655
|
+
await new Promise((resolve6, reject) => {
|
|
19040
19656
|
const proc = (0, import_child_process17.spawn)(
|
|
19041
19657
|
"gitpod",
|
|
19042
19658
|
["workspace", "ssh", workspaceId, "--", cmd],
|
|
@@ -19048,7 +19664,7 @@ var GitpodProvider = class {
|
|
|
19048
19664
|
});
|
|
19049
19665
|
proc.on("error", reject);
|
|
19050
19666
|
proc.on("exit", (code) => {
|
|
19051
|
-
if (code === 0)
|
|
19667
|
+
if (code === 0) resolve6();
|
|
19052
19668
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
19053
19669
|
});
|
|
19054
19670
|
proc.stdin?.write(contents);
|
|
@@ -19063,7 +19679,7 @@ function shellQuote2(s) {
|
|
|
19063
19679
|
// src/services/providers/gitlab-workspaces.ts
|
|
19064
19680
|
var import_child_process18 = require("child_process");
|
|
19065
19681
|
var import_util6 = require("util");
|
|
19066
|
-
var
|
|
19682
|
+
var path40 = __toESM(require("path"));
|
|
19067
19683
|
var execFileP7 = (0, import_util6.promisify)(import_child_process18.execFile);
|
|
19068
19684
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
19069
19685
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
@@ -19105,14 +19721,14 @@ var GitLabWorkspacesProvider = class {
|
|
|
19105
19721
|
"Authenticating GitLab"
|
|
19106
19722
|
);
|
|
19107
19723
|
resetStdinForChild3();
|
|
19108
|
-
await new Promise((
|
|
19724
|
+
await new Promise((resolve6, reject) => {
|
|
19109
19725
|
const proc = (0, import_child_process18.spawn)(
|
|
19110
19726
|
"glab",
|
|
19111
19727
|
["auth", "login", "--scopes", "api,read_user,read_repository"],
|
|
19112
19728
|
{ stdio: "inherit" }
|
|
19113
19729
|
);
|
|
19114
19730
|
proc.on("exit", (code) => {
|
|
19115
|
-
if (code === 0)
|
|
19731
|
+
if (code === 0) resolve6();
|
|
19116
19732
|
else reject(new Error("glab auth login failed."));
|
|
19117
19733
|
});
|
|
19118
19734
|
proc.on("error", reject);
|
|
@@ -19277,13 +19893,13 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
19277
19893
|
async streamCommand(workspaceId, command2) {
|
|
19278
19894
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
19279
19895
|
resetStdinForChild3();
|
|
19280
|
-
return new Promise((
|
|
19896
|
+
return new Promise((resolve6, reject) => {
|
|
19281
19897
|
const proc = (0, import_child_process18.spawn)(
|
|
19282
19898
|
"ssh",
|
|
19283
19899
|
["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
|
|
19284
19900
|
{ stdio: "inherit" }
|
|
19285
19901
|
);
|
|
19286
|
-
proc.on("exit", (code) =>
|
|
19902
|
+
proc.on("exit", (code) => resolve6({ code: code ?? 0 }));
|
|
19287
19903
|
proc.on("error", reject);
|
|
19288
19904
|
});
|
|
19289
19905
|
}
|
|
@@ -19298,7 +19914,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
19298
19914
|
tarArgs.push(".");
|
|
19299
19915
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
19300
19916
|
const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
|
|
19301
|
-
await new Promise((
|
|
19917
|
+
await new Promise((resolve6, reject) => {
|
|
19302
19918
|
const tar = (0, import_child_process18.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
19303
19919
|
const ssh = (0, import_child_process18.spawn)(
|
|
19304
19920
|
"ssh",
|
|
@@ -19316,20 +19932,20 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
19316
19932
|
tar.on("error", reject);
|
|
19317
19933
|
ssh.on("error", reject);
|
|
19318
19934
|
ssh.on("exit", (code) => {
|
|
19319
|
-
if (code === 0)
|
|
19935
|
+
if (code === 0) resolve6();
|
|
19320
19936
|
else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
19321
19937
|
});
|
|
19322
19938
|
});
|
|
19323
19939
|
}
|
|
19324
19940
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
19325
19941
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
19326
|
-
const remoteDir =
|
|
19942
|
+
const remoteDir = path40.posix.dirname(remotePath);
|
|
19327
19943
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
19328
19944
|
if (options.mode != null) {
|
|
19329
19945
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
19330
19946
|
}
|
|
19331
19947
|
const cmd = parts.join(" && ");
|
|
19332
|
-
await new Promise((
|
|
19948
|
+
await new Promise((resolve6, reject) => {
|
|
19333
19949
|
const proc = (0, import_child_process18.spawn)(
|
|
19334
19950
|
"ssh",
|
|
19335
19951
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
|
|
@@ -19341,7 +19957,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
19341
19957
|
});
|
|
19342
19958
|
proc.on("error", reject);
|
|
19343
19959
|
proc.on("exit", (code) => {
|
|
19344
|
-
if (code === 0)
|
|
19960
|
+
if (code === 0) resolve6();
|
|
19345
19961
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
19346
19962
|
});
|
|
19347
19963
|
proc.stdin?.write(contents);
|
|
@@ -19391,7 +20007,7 @@ function shellQuote3(s) {
|
|
|
19391
20007
|
// src/services/providers/railway.ts
|
|
19392
20008
|
var import_child_process19 = require("child_process");
|
|
19393
20009
|
var import_util7 = require("util");
|
|
19394
|
-
var
|
|
20010
|
+
var path41 = __toESM(require("path"));
|
|
19395
20011
|
var execFileP8 = (0, import_util7.promisify)(import_child_process19.execFile);
|
|
19396
20012
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
19397
20013
|
function resetStdinForChild4() {
|
|
@@ -19432,10 +20048,10 @@ var RailwayProvider = class {
|
|
|
19432
20048
|
"Authenticating Railway"
|
|
19433
20049
|
);
|
|
19434
20050
|
resetStdinForChild4();
|
|
19435
|
-
await new Promise((
|
|
20051
|
+
await new Promise((resolve6, reject) => {
|
|
19436
20052
|
const proc = (0, import_child_process19.spawn)("railway", ["login"], { stdio: "inherit" });
|
|
19437
20053
|
proc.on("exit", (code) => {
|
|
19438
|
-
if (code === 0)
|
|
20054
|
+
if (code === 0) resolve6();
|
|
19439
20055
|
else reject(new Error("railway login failed."));
|
|
19440
20056
|
});
|
|
19441
20057
|
proc.on("error", reject);
|
|
@@ -19575,13 +20191,13 @@ var RailwayProvider = class {
|
|
|
19575
20191
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
19576
20192
|
}
|
|
19577
20193
|
resetStdinForChild4();
|
|
19578
|
-
return new Promise((
|
|
20194
|
+
return new Promise((resolve6, reject) => {
|
|
19579
20195
|
const proc = (0, import_child_process19.spawn)(
|
|
19580
20196
|
"railway",
|
|
19581
20197
|
["shell", "--project", projectId, "--service", serviceId, "--command", command2],
|
|
19582
20198
|
{ stdio: "inherit" }
|
|
19583
20199
|
);
|
|
19584
|
-
proc.on("exit", (code) =>
|
|
20200
|
+
proc.on("exit", (code) => resolve6({ code: code ?? 0 }));
|
|
19585
20201
|
proc.on("error", reject);
|
|
19586
20202
|
});
|
|
19587
20203
|
}
|
|
@@ -19599,7 +20215,7 @@ var RailwayProvider = class {
|
|
|
19599
20215
|
tarArgs.push(".");
|
|
19600
20216
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
19601
20217
|
const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
|
|
19602
|
-
await new Promise((
|
|
20218
|
+
await new Promise((resolve6, reject) => {
|
|
19603
20219
|
const tar = (0, import_child_process19.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
19604
20220
|
const sh = (0, import_child_process19.spawn)(
|
|
19605
20221
|
"railway",
|
|
@@ -19617,7 +20233,7 @@ var RailwayProvider = class {
|
|
|
19617
20233
|
tar.on("error", reject);
|
|
19618
20234
|
sh.on("error", reject);
|
|
19619
20235
|
sh.on("exit", (code) => {
|
|
19620
|
-
if (code === 0)
|
|
20236
|
+
if (code === 0) resolve6();
|
|
19621
20237
|
else reject(new Error(`Remote tar failed: ${(shErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
19622
20238
|
});
|
|
19623
20239
|
});
|
|
@@ -19627,13 +20243,13 @@ var RailwayProvider = class {
|
|
|
19627
20243
|
if (!projectId || !serviceId) {
|
|
19628
20244
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
19629
20245
|
}
|
|
19630
|
-
const remoteDir =
|
|
20246
|
+
const remoteDir = path41.posix.dirname(remotePath);
|
|
19631
20247
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
19632
20248
|
if (options.mode != null) {
|
|
19633
20249
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
19634
20250
|
}
|
|
19635
20251
|
const cmd = parts.join(" && ");
|
|
19636
|
-
await new Promise((
|
|
20252
|
+
await new Promise((resolve6, reject) => {
|
|
19637
20253
|
const proc = (0, import_child_process19.spawn)(
|
|
19638
20254
|
"railway",
|
|
19639
20255
|
["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
|
|
@@ -19645,7 +20261,7 @@ var RailwayProvider = class {
|
|
|
19645
20261
|
});
|
|
19646
20262
|
proc.on("error", reject);
|
|
19647
20263
|
proc.on("exit", (code) => {
|
|
19648
|
-
if (code === 0)
|
|
20264
|
+
if (code === 0) resolve6();
|
|
19649
20265
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
19650
20266
|
});
|
|
19651
20267
|
proc.stdin?.write(contents);
|
|
@@ -20169,9 +20785,9 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
20169
20785
|
// src/commands/doctor.ts
|
|
20170
20786
|
var import_node_dns = require("dns");
|
|
20171
20787
|
var import_node_util4 = require("util");
|
|
20172
|
-
var
|
|
20173
|
-
var
|
|
20174
|
-
var
|
|
20788
|
+
var import_node_crypto8 = require("crypto");
|
|
20789
|
+
var fs33 = __toESM(require("fs"));
|
|
20790
|
+
var path42 = __toESM(require("path"));
|
|
20175
20791
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
20176
20792
|
var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
|
|
20177
20793
|
async function checkDns(apiBase) {
|
|
@@ -20227,13 +20843,13 @@ async function checkHealth(apiBase) {
|
|
|
20227
20843
|
}
|
|
20228
20844
|
}
|
|
20229
20845
|
function checkConfigDir() {
|
|
20230
|
-
const dir =
|
|
20846
|
+
const dir = path42.join(require("os").homedir(), ".codeam");
|
|
20231
20847
|
try {
|
|
20232
|
-
|
|
20233
|
-
const probe =
|
|
20234
|
-
|
|
20235
|
-
const read =
|
|
20236
|
-
|
|
20848
|
+
fs33.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
20849
|
+
const probe = path42.join(dir, ".doctor-probe");
|
|
20850
|
+
fs33.writeFileSync(probe, "ok", { mode: 384 });
|
|
20851
|
+
const read = fs33.readFileSync(probe, "utf8");
|
|
20852
|
+
fs33.unlinkSync(probe);
|
|
20237
20853
|
if (read !== "ok") throw new Error("write/read round-trip mismatch");
|
|
20238
20854
|
return {
|
|
20239
20855
|
id: "config-dir",
|
|
@@ -20297,7 +20913,7 @@ function checkNodePty() {
|
|
|
20297
20913
|
detail: "not required on this platform"
|
|
20298
20914
|
};
|
|
20299
20915
|
}
|
|
20300
|
-
const vendoredPath =
|
|
20916
|
+
const vendoredPath = path42.join(__dirname, "vendor", "node-pty");
|
|
20301
20917
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
20302
20918
|
try {
|
|
20303
20919
|
require(target);
|
|
@@ -20339,9 +20955,9 @@ function checkChokidar() {
|
|
|
20339
20955
|
}
|
|
20340
20956
|
async function doctor(args2 = []) {
|
|
20341
20957
|
const json = args2.includes("--json");
|
|
20342
|
-
const cliVersion = true ? "2.27.
|
|
20958
|
+
const cliVersion = true ? "2.27.2" : "0.0.0-dev";
|
|
20343
20959
|
const apiBase = resolveApiBaseUrl();
|
|
20344
|
-
const diagnosticId = (0,
|
|
20960
|
+
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
20345
20961
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
20346
20962
|
const [dns, health] = await Promise.all([
|
|
20347
20963
|
checkDns(apiBase),
|
|
@@ -20538,7 +21154,7 @@ async function completion(args2) {
|
|
|
20538
21154
|
// src/commands/version.ts
|
|
20539
21155
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
20540
21156
|
function version2() {
|
|
20541
|
-
const v = true ? "2.27.
|
|
21157
|
+
const v = true ? "2.27.2" : "unknown";
|
|
20542
21158
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
20543
21159
|
}
|
|
20544
21160
|
|
|
@@ -20666,9 +21282,9 @@ function tryShowSubcommandHelp(cmd, args2) {
|
|
|
20666
21282
|
var _subcommandHelpKeys = Object.keys(HELPS);
|
|
20667
21283
|
|
|
20668
21284
|
// src/lib/updateNotifier.ts
|
|
20669
|
-
var
|
|
21285
|
+
var fs34 = __toESM(require("fs"));
|
|
20670
21286
|
var os26 = __toESM(require("os"));
|
|
20671
|
-
var
|
|
21287
|
+
var path43 = __toESM(require("path"));
|
|
20672
21288
|
var https7 = __toESM(require("https"));
|
|
20673
21289
|
var import_picocolors16 = __toESM(require("picocolors"));
|
|
20674
21290
|
var PKG_NAME = "codeam-cli";
|
|
@@ -20676,12 +21292,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
|
20676
21292
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
20677
21293
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
20678
21294
|
function cachePath() {
|
|
20679
|
-
const dir =
|
|
20680
|
-
return
|
|
21295
|
+
const dir = path43.join(os26.homedir(), ".codeam");
|
|
21296
|
+
return path43.join(dir, "update-check.json");
|
|
20681
21297
|
}
|
|
20682
21298
|
function readCache() {
|
|
20683
21299
|
try {
|
|
20684
|
-
const raw =
|
|
21300
|
+
const raw = fs34.readFileSync(cachePath(), "utf8");
|
|
20685
21301
|
const parsed = JSON.parse(raw);
|
|
20686
21302
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
20687
21303
|
return parsed;
|
|
@@ -20692,10 +21308,10 @@ function readCache() {
|
|
|
20692
21308
|
function writeCache(cache) {
|
|
20693
21309
|
try {
|
|
20694
21310
|
const file = cachePath();
|
|
20695
|
-
|
|
21311
|
+
fs34.mkdirSync(path43.dirname(file), { recursive: true });
|
|
20696
21312
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
20697
|
-
|
|
20698
|
-
|
|
21313
|
+
fs34.writeFileSync(tmp, JSON.stringify(cache));
|
|
21314
|
+
fs34.renameSync(tmp, file);
|
|
20699
21315
|
} catch {
|
|
20700
21316
|
}
|
|
20701
21317
|
}
|
|
@@ -20713,40 +21329,40 @@ function compareSemver(a, b) {
|
|
|
20713
21329
|
return 0;
|
|
20714
21330
|
}
|
|
20715
21331
|
function fetchLatest() {
|
|
20716
|
-
return new Promise((
|
|
21332
|
+
return new Promise((resolve6) => {
|
|
20717
21333
|
const req = https7.get(
|
|
20718
21334
|
REGISTRY_URL,
|
|
20719
21335
|
{ headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
|
|
20720
21336
|
(res) => {
|
|
20721
21337
|
if (res.statusCode !== 200) {
|
|
20722
21338
|
res.resume();
|
|
20723
|
-
|
|
21339
|
+
resolve6(null);
|
|
20724
21340
|
return;
|
|
20725
21341
|
}
|
|
20726
21342
|
let buf = "";
|
|
20727
21343
|
res.setEncoding("utf8");
|
|
20728
|
-
res.on("data", (
|
|
20729
|
-
buf +=
|
|
21344
|
+
res.on("data", (chunk2) => {
|
|
21345
|
+
buf += chunk2;
|
|
20730
21346
|
});
|
|
20731
21347
|
res.on("end", () => {
|
|
20732
21348
|
try {
|
|
20733
21349
|
const json = JSON.parse(buf);
|
|
20734
21350
|
if (typeof json.version === "string") {
|
|
20735
|
-
|
|
21351
|
+
resolve6(json.version);
|
|
20736
21352
|
} else {
|
|
20737
|
-
|
|
21353
|
+
resolve6(null);
|
|
20738
21354
|
}
|
|
20739
21355
|
} catch {
|
|
20740
|
-
|
|
21356
|
+
resolve6(null);
|
|
20741
21357
|
}
|
|
20742
21358
|
});
|
|
20743
21359
|
}
|
|
20744
21360
|
);
|
|
20745
21361
|
req.on("timeout", () => {
|
|
20746
21362
|
req.destroy();
|
|
20747
|
-
|
|
21363
|
+
resolve6(null);
|
|
20748
21364
|
});
|
|
20749
|
-
req.on("error", () =>
|
|
21365
|
+
req.on("error", () => resolve6(null));
|
|
20750
21366
|
});
|
|
20751
21367
|
}
|
|
20752
21368
|
function notifyIfStale(currentVersion, latest) {
|
|
@@ -20766,7 +21382,7 @@ function checkForUpdates() {
|
|
|
20766
21382
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
20767
21383
|
if (process.env.CI) return;
|
|
20768
21384
|
if (!process.stdout.isTTY) return;
|
|
20769
|
-
const current = true ? "2.27.
|
|
21385
|
+
const current = true ? "2.27.2" : null;
|
|
20770
21386
|
if (!current) return;
|
|
20771
21387
|
const cache = readCache();
|
|
20772
21388
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|