codeam-cli 2.39.23 → 2.39.25
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 +16 -0
- package/dist/index.js +688 -961
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
498
498
|
// package.json
|
|
499
499
|
var package_default = {
|
|
500
500
|
name: "codeam-cli",
|
|
501
|
-
version: "2.39.
|
|
501
|
+
version: "2.39.25",
|
|
502
502
|
description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
|
|
503
503
|
type: "commonjs",
|
|
504
504
|
main: "dist/index.js",
|
|
@@ -1194,8 +1194,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
1194
1194
|
return decodedFile;
|
|
1195
1195
|
};
|
|
1196
1196
|
}
|
|
1197
|
-
function normalizeWindowsPath(
|
|
1198
|
-
return
|
|
1197
|
+
function normalizeWindowsPath(path58) {
|
|
1198
|
+
return path58.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
1199
1199
|
}
|
|
1200
1200
|
|
|
1201
1201
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -2347,10 +2347,10 @@ var PostHogCoreStateless = class {
|
|
|
2347
2347
|
}
|
|
2348
2348
|
async getRemoteConfig() {
|
|
2349
2349
|
await this._initPromise;
|
|
2350
|
-
let
|
|
2351
|
-
if ("https://us.i.posthog.com" ===
|
|
2352
|
-
else if ("https://eu.i.posthog.com" ===
|
|
2353
|
-
const url = `${
|
|
2350
|
+
let host2 = this.host;
|
|
2351
|
+
if ("https://us.i.posthog.com" === host2) host2 = "https://us-assets.i.posthog.com";
|
|
2352
|
+
else if ("https://eu.i.posthog.com" === host2) host2 = "https://eu-assets.i.posthog.com";
|
|
2353
|
+
const url = `${host2}/array/${this.apiKey}/config`;
|
|
2354
2354
|
const fetchOptions = {
|
|
2355
2355
|
method: "GET",
|
|
2356
2356
|
headers: {
|
|
@@ -3030,9 +3030,9 @@ var ErrorPropertiesBuilder = class {
|
|
|
3030
3030
|
|
|
3031
3031
|
// ../../node_modules/@posthog/core/dist/error-tracking/parsers/base.mjs
|
|
3032
3032
|
var UNKNOWN_FUNCTION = "?";
|
|
3033
|
-
function createFrame(
|
|
3033
|
+
function createFrame(platform3, filename, func, lineno, colno) {
|
|
3034
3034
|
const frame = {
|
|
3035
|
-
platform:
|
|
3035
|
+
platform: platform3,
|
|
3036
3036
|
filename,
|
|
3037
3037
|
function: "<anonymous>" === func ? UNKNOWN_FUNCTION : func,
|
|
3038
3038
|
in_app: true
|
|
@@ -3059,11 +3059,11 @@ var extractSafariExtensionDetails = (func, filename) => {
|
|
|
3059
3059
|
var chromeRegexNoFnName = /^\s*at (\S+?)(?::(\d+))(?::(\d+))\s*$/i;
|
|
3060
3060
|
var chromeRegex = /^\s*at (?:(.+?\)(?: \[.+\])?|.*?) ?\((?:address at )?)?(?:async )?((?:<anonymous>|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
|
|
3061
3061
|
var chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
|
|
3062
|
-
var chromeStackLineParser = (line,
|
|
3062
|
+
var chromeStackLineParser = (line, platform3) => {
|
|
3063
3063
|
const noFnParts = chromeRegexNoFnName.exec(line);
|
|
3064
3064
|
if (noFnParts) {
|
|
3065
3065
|
const [, filename, line2, col] = noFnParts;
|
|
3066
|
-
return createFrame(
|
|
3066
|
+
return createFrame(platform3, filename, UNKNOWN_FUNCTION, +line2, +col);
|
|
3067
3067
|
}
|
|
3068
3068
|
const parts = chromeRegex.exec(line);
|
|
3069
3069
|
if (parts) {
|
|
@@ -3077,14 +3077,14 @@ var chromeStackLineParser = (line, platform2) => {
|
|
|
3077
3077
|
}
|
|
3078
3078
|
}
|
|
3079
3079
|
const [func, filename] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]);
|
|
3080
|
-
return createFrame(
|
|
3080
|
+
return createFrame(platform3, filename, func, parts[3] ? +parts[3] : void 0, parts[4] ? +parts[4] : void 0);
|
|
3081
3081
|
}
|
|
3082
3082
|
};
|
|
3083
3083
|
|
|
3084
3084
|
// ../../node_modules/@posthog/core/dist/error-tracking/parsers/gecko.mjs
|
|
3085
3085
|
var geckoREgex = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:[-a-z]+)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
|
|
3086
3086
|
var geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
|
|
3087
|
-
var geckoStackLineParser = (line,
|
|
3087
|
+
var geckoStackLineParser = (line, platform3) => {
|
|
3088
3088
|
const parts = geckoREgex.exec(line);
|
|
3089
3089
|
if (parts) {
|
|
3090
3090
|
const isEval = parts[3] && parts[3].indexOf(" > eval") > -1;
|
|
@@ -3100,33 +3100,33 @@ var geckoStackLineParser = (line, platform2) => {
|
|
|
3100
3100
|
let filename = parts[3];
|
|
3101
3101
|
let func = parts[1] || UNKNOWN_FUNCTION;
|
|
3102
3102
|
[func, filename] = extractSafariExtensionDetails(func, filename);
|
|
3103
|
-
return createFrame(
|
|
3103
|
+
return createFrame(platform3, filename, func, parts[4] ? +parts[4] : void 0, parts[5] ? +parts[5] : void 0);
|
|
3104
3104
|
}
|
|
3105
3105
|
};
|
|
3106
3106
|
|
|
3107
3107
|
// ../../node_modules/@posthog/core/dist/error-tracking/parsers/winjs.mjs
|
|
3108
3108
|
var winjsRegex = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:[-a-z]+):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
|
|
3109
|
-
var winjsStackLineParser = (line,
|
|
3109
|
+
var winjsStackLineParser = (line, platform3) => {
|
|
3110
3110
|
const parts = winjsRegex.exec(line);
|
|
3111
|
-
return parts ? createFrame(
|
|
3111
|
+
return parts ? createFrame(platform3, parts[2], parts[1] || UNKNOWN_FUNCTION, +parts[3], parts[4] ? +parts[4] : void 0) : void 0;
|
|
3112
3112
|
};
|
|
3113
3113
|
|
|
3114
3114
|
// ../../node_modules/@posthog/core/dist/error-tracking/parsers/opera.mjs
|
|
3115
3115
|
var opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
|
|
3116
|
-
var opera10StackLineParser = (line,
|
|
3116
|
+
var opera10StackLineParser = (line, platform3) => {
|
|
3117
3117
|
const parts = opera10Regex.exec(line);
|
|
3118
|
-
return parts ? createFrame(
|
|
3118
|
+
return parts ? createFrame(platform3, parts[2], parts[3] || UNKNOWN_FUNCTION, +parts[1]) : void 0;
|
|
3119
3119
|
};
|
|
3120
3120
|
var opera11Regex = / line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^)]+))\(.*\))? in (.*):\s*$/i;
|
|
3121
|
-
var opera11StackLineParser = (line,
|
|
3121
|
+
var opera11StackLineParser = (line, platform3) => {
|
|
3122
3122
|
const parts = opera11Regex.exec(line);
|
|
3123
|
-
return parts ? createFrame(
|
|
3123
|
+
return parts ? createFrame(platform3, parts[5], parts[3] || parts[4] || UNKNOWN_FUNCTION, +parts[1], +parts[2]) : void 0;
|
|
3124
3124
|
};
|
|
3125
3125
|
|
|
3126
3126
|
// ../../node_modules/@posthog/core/dist/error-tracking/parsers/node.mjs
|
|
3127
3127
|
var FILENAME_MATCH = /^\s*[-]{4,}$/;
|
|
3128
3128
|
var FULL_MATCH = /at (?:async )?(?:(.+?)\s+\()?(?:(.+):(\d+):(\d+)?|([^)]+))\)?/;
|
|
3129
|
-
var nodeStackLineParser = (line,
|
|
3129
|
+
var nodeStackLineParser = (line, platform3) => {
|
|
3130
3130
|
const lineMatch = line.match(FULL_MATCH);
|
|
3131
3131
|
if (lineMatch) {
|
|
3132
3132
|
let object;
|
|
@@ -3172,12 +3172,12 @@ var nodeStackLineParser = (line, platform2) => {
|
|
|
3172
3172
|
lineno: _parseIntOrUndefined(lineMatch[3]),
|
|
3173
3173
|
colno: _parseIntOrUndefined(lineMatch[4]),
|
|
3174
3174
|
in_app: filenameIsInApp(filename || "", isNative),
|
|
3175
|
-
platform:
|
|
3175
|
+
platform: platform3
|
|
3176
3176
|
};
|
|
3177
3177
|
}
|
|
3178
3178
|
if (line.match(FILENAME_MATCH)) return {
|
|
3179
3179
|
filename: line,
|
|
3180
|
-
platform:
|
|
3180
|
+
platform: platform3
|
|
3181
3181
|
};
|
|
3182
3182
|
};
|
|
3183
3183
|
function filenameIsInApp(filename, isNative = false) {
|
|
@@ -3207,7 +3207,7 @@ function getLastStackFrame(arr) {
|
|
|
3207
3207
|
function createDefaultStackParser() {
|
|
3208
3208
|
return createStackParser("web:javascript", chromeStackLineParser, geckoStackLineParser);
|
|
3209
3209
|
}
|
|
3210
|
-
function createStackParser(
|
|
3210
|
+
function createStackParser(platform3, ...parsers) {
|
|
3211
3211
|
return (stack, skipFirstLines = 0) => {
|
|
3212
3212
|
const frames = [];
|
|
3213
3213
|
const lines = stack.split("\n");
|
|
@@ -3217,7 +3217,7 @@ function createStackParser(platform2, ...parsers) {
|
|
|
3217
3217
|
const cleanedLine = WEBPACK_ERROR_REGEXP.test(line) ? line.replace(WEBPACK_ERROR_REGEXP, "$1") : line;
|
|
3218
3218
|
if (!cleanedLine.match(/\S*Error: /)) {
|
|
3219
3219
|
for (const parser of parsers) {
|
|
3220
|
-
const frame = parser(cleanedLine,
|
|
3220
|
+
const frame = parser(cleanedLine, platform3);
|
|
3221
3221
|
if (frame) {
|
|
3222
3222
|
frames.push(frame);
|
|
3223
3223
|
break;
|
|
@@ -3675,9 +3675,9 @@ async function addSourceContext(frames) {
|
|
|
3675
3675
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
3676
3676
|
return frames;
|
|
3677
3677
|
}
|
|
3678
|
-
function getContextLinesFromFile(
|
|
3678
|
+
function getContextLinesFromFile(path58, ranges, output) {
|
|
3679
3679
|
return new Promise((resolve7) => {
|
|
3680
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
3680
|
+
const stream = (0, import_node_fs.createReadStream)(path58);
|
|
3681
3681
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
3682
3682
|
input: stream
|
|
3683
3683
|
});
|
|
@@ -3692,7 +3692,7 @@ function getContextLinesFromFile(path55, ranges, output) {
|
|
|
3692
3692
|
let rangeStart = range[0];
|
|
3693
3693
|
let rangeEnd = range[1];
|
|
3694
3694
|
function onStreamError() {
|
|
3695
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
3695
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path58, 1);
|
|
3696
3696
|
lineReaded.close();
|
|
3697
3697
|
lineReaded.removeAllListeners();
|
|
3698
3698
|
destroyStreamAndResolve();
|
|
@@ -3753,8 +3753,8 @@ function clearLineContext(frame) {
|
|
|
3753
3753
|
delete frame.context_line;
|
|
3754
3754
|
delete frame.post_context;
|
|
3755
3755
|
}
|
|
3756
|
-
function shouldSkipContextLinesForFile(
|
|
3757
|
-
return
|
|
3756
|
+
function shouldSkipContextLinesForFile(path58) {
|
|
3757
|
+
return path58.startsWith("node:") || path58.endsWith(".min.js") || path58.endsWith(".min.cjs") || path58.endsWith(".min.mjs") || path58.startsWith("data:");
|
|
3758
3758
|
}
|
|
3759
3759
|
function shouldSkipContextLinesForFrame(frame) {
|
|
3760
3760
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -4109,7 +4109,7 @@ var RequiresServerEvaluation = class _RequiresServerEvaluation extends Error {
|
|
|
4109
4109
|
}
|
|
4110
4110
|
};
|
|
4111
4111
|
var FeatureFlagsPoller = class {
|
|
4112
|
-
constructor({ pollingInterval, personalApiKey, projectApiKey, timeout, host, customHeaders, ...options }) {
|
|
4112
|
+
constructor({ pollingInterval, personalApiKey, projectApiKey, timeout, host: host2, customHeaders, ...options }) {
|
|
4113
4113
|
this.debugMode = false;
|
|
4114
4114
|
this.shouldBeginExponentialBackoff = false;
|
|
4115
4115
|
this.backOffCount = 0;
|
|
@@ -4122,7 +4122,7 @@ var FeatureFlagsPoller = class {
|
|
|
4122
4122
|
this.loadedSuccessfullyOnce = false;
|
|
4123
4123
|
this.timeout = timeout;
|
|
4124
4124
|
this.projectApiKey = projectApiKey;
|
|
4125
|
-
this.host =
|
|
4125
|
+
this.host = host2;
|
|
4126
4126
|
this.poller = void 0;
|
|
4127
4127
|
this.fetch = options.fetch || fetch;
|
|
4128
4128
|
this.onError = options.onError;
|
|
@@ -5908,7 +5908,7 @@ function readAnonId() {
|
|
|
5908
5908
|
}
|
|
5909
5909
|
function superProperties() {
|
|
5910
5910
|
return {
|
|
5911
|
-
cliVersion: true ? "2.39.
|
|
5911
|
+
cliVersion: true ? "2.39.25" : "0.0.0-dev",
|
|
5912
5912
|
nodeVersion: process.version,
|
|
5913
5913
|
platform: process.platform,
|
|
5914
5914
|
arch: process.arch,
|
|
@@ -5942,10 +5942,10 @@ function initTelemetry() {
|
|
|
5942
5942
|
log.trace("telemetry", "no PostHog API key baked into build \u2014 disabled");
|
|
5943
5943
|
return false;
|
|
5944
5944
|
}
|
|
5945
|
-
const
|
|
5945
|
+
const host2 = true ? "https://us.i.posthog.com" : "https://us.i.posthog.com";
|
|
5946
5946
|
distinctId = readAnonId();
|
|
5947
5947
|
client = new PostHog(apiKey, {
|
|
5948
|
-
host,
|
|
5948
|
+
host: host2,
|
|
5949
5949
|
// 10s flush is generous for a CLI — most commands run < 30s
|
|
5950
5950
|
// and we shutdown() before exit anyway. Per-batch size caps
|
|
5951
5951
|
// memory growth on long-lived `codeam start` sessions.
|
|
@@ -5960,7 +5960,7 @@ function initTelemetry() {
|
|
|
5960
5960
|
log.trace("telemetry", "posthog error (ignored)", err);
|
|
5961
5961
|
});
|
|
5962
5962
|
client.register(superProperties());
|
|
5963
|
-
log.trace("telemetry", `posthog client initialised host=${
|
|
5963
|
+
log.trace("telemetry", `posthog client initialised host=${host2} distinctId=${distinctId}`);
|
|
5964
5964
|
return true;
|
|
5965
5965
|
}
|
|
5966
5966
|
function identifyUser(params) {
|
|
@@ -7287,8 +7287,8 @@ function createOsStrategy() {
|
|
|
7287
7287
|
cached = buildForPlatform(process.platform);
|
|
7288
7288
|
return cached;
|
|
7289
7289
|
}
|
|
7290
|
-
function buildForPlatform(
|
|
7291
|
-
switch (
|
|
7290
|
+
function buildForPlatform(platform3) {
|
|
7291
|
+
switch (platform3) {
|
|
7292
7292
|
case "darwin":
|
|
7293
7293
|
return new DarwinOsStrategy();
|
|
7294
7294
|
case "win32":
|
|
@@ -7302,10 +7302,10 @@ function buildForPlatform(platform2) {
|
|
|
7302
7302
|
var import_node_crypto4 = require("crypto");
|
|
7303
7303
|
|
|
7304
7304
|
// src/agents/claude/resolver.ts
|
|
7305
|
-
function buildClaudeLaunch(extraArgs = [],
|
|
7306
|
-
const found =
|
|
7305
|
+
function buildClaudeLaunch(extraArgs = [], os36 = createOsStrategy()) {
|
|
7306
|
+
const found = os36.findInPath("claude") ?? os36.findInPath("claude-code");
|
|
7307
7307
|
if (!found) return null;
|
|
7308
|
-
return
|
|
7308
|
+
return os36.buildLaunch(found, extraArgs);
|
|
7309
7309
|
}
|
|
7310
7310
|
|
|
7311
7311
|
// src/agents/claude/installer.ts
|
|
@@ -9748,308 +9748,14 @@ function listResumableSessions(cwd) {
|
|
|
9748
9748
|
return out2;
|
|
9749
9749
|
}
|
|
9750
9750
|
|
|
9751
|
-
// src/agents/claude/parsing.ts
|
|
9752
|
-
function filterChrome(lines) {
|
|
9753
|
-
const result = [];
|
|
9754
|
-
let skipEchoContinuation = false;
|
|
9755
|
-
for (const line of lines) {
|
|
9756
|
-
const t2 = line.trim();
|
|
9757
|
-
if (!t2) {
|
|
9758
|
-
skipEchoContinuation = false;
|
|
9759
|
-
continue;
|
|
9760
|
-
}
|
|
9761
|
-
if (/^[─━—═─\-]{3,}$/.test(t2)) {
|
|
9762
|
-
skipEchoContinuation = false;
|
|
9763
|
-
continue;
|
|
9764
|
-
}
|
|
9765
|
-
if (/^[●⏺]\s/.test(t2)) skipEchoContinuation = false;
|
|
9766
|
-
if (/^[✳✢✶✻✽✴✷✸✹⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◑◒◓▁▂▃▄▅▆▇█]\s/.test(t2)) continue;
|
|
9767
|
-
if (/esc.{0,5}to.{0,5}interrupt/i.test(t2)) continue;
|
|
9768
|
-
if (/high\s*[·•]\s*\/effort/i.test(t2)) continue;
|
|
9769
|
-
if (/^[❯>]\s*$/.test(t2)) continue;
|
|
9770
|
-
if (/^\(thinking\)\s*$/.test(t2)) continue;
|
|
9771
|
-
if (/^\?\s.*shortcut/i.test(t2)) continue;
|
|
9772
|
-
if (/spending limit|usage limit/i.test(t2) && t2.length < 80) continue;
|
|
9773
|
-
if (/↑\s*\/?\s*↓\s*to\s*navigate/i.test(t2)) continue;
|
|
9774
|
-
if (t2.replace(/\s/g, "").length === 1) continue;
|
|
9775
|
-
if ((t2.match(/─/g)?.length ?? 0) >= 6) continue;
|
|
9776
|
-
if (/ctrl\+?o\s+to\s+expand/i.test(t2)) continue;
|
|
9777
|
-
if (/^•\s+(?:Read(?:ing)?|Edit(?:ing)?|Writ(?:e|ing)|Bash|Runn(?:ing)?|Search(?:ing)?|Glob(?:bing)?|Grep(?:ping)?|Creat(?:e|ing)|Execut(?:e|ing)|Task|Agent|NotebookEdit)\b/i.test(
|
|
9778
|
-
t2
|
|
9779
|
-
))
|
|
9780
|
-
continue;
|
|
9781
|
-
if (/^└\s/.test(t2)) continue;
|
|
9782
|
-
if (/^\+\s/.test(t2) && /\d+\s*s\s*[·•]|\bthought\s+for\b|\d+\s*tokens|\(thinking\)/i.test(t2)) continue;
|
|
9783
|
-
if (/^↓\s*\d+\s*tokens/i.test(t2)) continue;
|
|
9784
|
-
if (/^\bthought\s+for\s+\d+/i.test(t2)) continue;
|
|
9785
|
-
const stripped = t2.replace(/^[│╭╰╮╯┌└┐┘├┤┬┴┼]\s?/, "");
|
|
9786
|
-
if (/^[❯>]\s+\S/.test(stripped) && !/^[❯>]\s*\d+\./.test(stripped)) {
|
|
9787
|
-
skipEchoContinuation = true;
|
|
9788
|
-
continue;
|
|
9789
|
-
}
|
|
9790
|
-
if (skipEchoContinuation) continue;
|
|
9791
|
-
result.push(line);
|
|
9792
|
-
}
|
|
9793
|
-
return result;
|
|
9794
|
-
}
|
|
9795
|
-
var SPINNER_RE = /^(?:[✳✢✶✻✽✴✷✸✹⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◑◒◓▁▂▃▄▅▆▇█]|🔴|🟠|🟡|🟢|🔵|🟣|🟤|⚫|⚪|🌀|💭|✨)\s/u;
|
|
9796
|
-
var BULLET_TOOL_RE = /^•\s+(?:Read(?:ing)?|Edit(?:ing)?|Writ(?:e|ing)|Bash|Runn(?:ing)?|Search(?:ing)?|Glob(?:bing)?|Grep(?:ping)?|Creat(?:e|ing)|Execut(?:e|ing)|Task|Agent|NotebookEdit)\b/i;
|
|
9797
|
-
var TREE_LINE_RE = /^└\s/;
|
|
9798
|
-
var STATUS_LINE_RE = /^(?:\+|[🔴🟠🟡🟢🔵🟣🟤⚫⚪🌀💭✨])\s/u;
|
|
9799
|
-
function isChromeLine(line) {
|
|
9800
|
-
const t2 = line.replace(/️/g, "").trim();
|
|
9801
|
-
if (!t2) return false;
|
|
9802
|
-
if (/^[─━—═─\-]{3,}$/.test(t2)) return true;
|
|
9803
|
-
if (SPINNER_RE.test(t2)) return true;
|
|
9804
|
-
if (BULLET_TOOL_RE.test(t2)) return true;
|
|
9805
|
-
if (TREE_LINE_RE.test(t2)) return true;
|
|
9806
|
-
if (STATUS_LINE_RE.test(t2) && /\d+\s*s\s*[·•]|\bthought\s+for\b|\d+\s*tokens|\(thinking\)/i.test(t2)) return true;
|
|
9807
|
-
if (/^↓\s*\d+\s*tokens/i.test(t2)) return true;
|
|
9808
|
-
if (/^\bthought\s+for\s+\d+/i.test(t2)) return true;
|
|
9809
|
-
if (/esc.{0,5}to.{0,5}interrupt/i.test(t2)) return true;
|
|
9810
|
-
if (/high\s*[·•]\s*\/effort/i.test(t2)) return true;
|
|
9811
|
-
if (/^[❯>]\s*$/.test(t2)) return true;
|
|
9812
|
-
if (/^\(thinking\)\s*$/.test(t2)) return true;
|
|
9813
|
-
if (/^\?\s.*shortcut/i.test(t2)) return true;
|
|
9814
|
-
if (/spending limit|usage limit/i.test(t2) && t2.length < 80) return true;
|
|
9815
|
-
if (/↑\s*\/?\s*↓\s*to\s*navigate/i.test(t2)) return true;
|
|
9816
|
-
if (t2.replace(/\s/g, "").length === 1) return true;
|
|
9817
|
-
if ((t2.match(/─/g)?.length ?? 0) >= 6) return true;
|
|
9818
|
-
if (/ctrl\+?o\s+to\s+expand/i.test(t2)) return true;
|
|
9819
|
-
const hasBoxPrefix = /^[│╭╰╮╯┌└┐┘├┤┬┴┼]/.test(t2);
|
|
9820
|
-
const stripped = t2.replace(/^[│╭╰╮╯┌└┐┘├┤┬┴┼]\s?/, "");
|
|
9821
|
-
if (hasBoxPrefix && /^[❯>]\s+\S/.test(stripped) && !/^[❯>]\s*\d+\./.test(stripped)) return true;
|
|
9822
|
-
return false;
|
|
9823
|
-
}
|
|
9824
|
-
function parseChromeLine(line) {
|
|
9825
|
-
const t2 = line.replace(/️/g, "").trim();
|
|
9826
|
-
if (!t2) return null;
|
|
9827
|
-
if (/^[─━—═─\-]{3,}$/.test(t2)) return null;
|
|
9828
|
-
if (/^[❯>]\s*$/.test(t2)) return null;
|
|
9829
|
-
if (t2.replace(/\s/g, "").length === 1) return null;
|
|
9830
|
-
if ((t2.match(/─/g)?.length ?? 0) >= 6) return null;
|
|
9831
|
-
if (/esc.{0,5}to.{0,5}interrupt/i.test(t2)) return null;
|
|
9832
|
-
if (/high\s*[·•]\s*\/effort/i.test(t2)) return null;
|
|
9833
|
-
if (/↑\s*\/?\s*↓\s*to\s*navigate/i.test(t2)) return null;
|
|
9834
|
-
if (/ctrl\+?o\s+to\s+expand/i.test(t2)) return null;
|
|
9835
|
-
if (/spending limit|usage limit/i.test(t2)) return null;
|
|
9836
|
-
if (/^\(thinking\)\s*$/.test(t2)) {
|
|
9837
|
-
return { tool: "thinking", label: "Thinking\u2026", status: "running" };
|
|
9838
|
-
}
|
|
9839
|
-
if (TREE_LINE_RE.test(t2)) return null;
|
|
9840
|
-
if (STATUS_LINE_RE.test(t2)) {
|
|
9841
|
-
const label = t2.slice(2).replace(/….*/s, "").trim() || "Thinking\u2026";
|
|
9842
|
-
return { tool: "thinking", label, status: "running" };
|
|
9843
|
-
}
|
|
9844
|
-
let text = t2;
|
|
9845
|
-
if (SPINNER_RE.test(t2)) {
|
|
9846
|
-
text = t2.slice(2).trim().replace(/….*/s, "").trim();
|
|
9847
|
-
} else if (BULLET_TOOL_RE.test(t2)) {
|
|
9848
|
-
text = t2.slice(2).trim();
|
|
9849
|
-
text = text.replace(/\s*\(ctrl\+?o[^)]*\)/gi, "").replace(/,\s*reading\s+\d+\s+files?\s*…?/gi, "").replace(/,\s*\d+\s+files?\s*…?/gi, "").replace(/…$/, "").trim();
|
|
9850
|
-
}
|
|
9851
|
-
if (!text) return null;
|
|
9852
|
-
return classifyStep(text);
|
|
9853
|
-
}
|
|
9854
|
-
function classifyStep(text) {
|
|
9855
|
-
if (/^Read(?:ing)?\s+/i.test(text)) {
|
|
9856
|
-
const label2 = text.replace(/^Read(?:ing)?\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
9857
|
-
return { tool: "read", label: label2, status: "running" };
|
|
9858
|
-
}
|
|
9859
|
-
if (/^Edit(?:ing)?\s+|^Writ(?:e|ing|ing to)\s+|^Creat(?:e|ing)\s+/i.test(text)) {
|
|
9860
|
-
const label2 = text.replace(/^(?:Edit(?:ing)?|Writ(?:e|ing(?: to)?)|Creat(?:e|ing))\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
9861
|
-
return { tool: "edit", label: label2, status: "running" };
|
|
9862
|
-
}
|
|
9863
|
-
if (/^Runn(?:ing)?\s+|^Execut(?:e|ing)\s+|^Bash(?:ing)?\s*:|^\$\s+/i.test(text)) {
|
|
9864
|
-
const label2 = text.replace(/^(?:Runn(?:ing)?|Execut(?:e|ing)|Bash(?:ing)?:|\$)\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
9865
|
-
return { tool: "bash", label: label2, status: "running" };
|
|
9866
|
-
}
|
|
9867
|
-
if (/^Search(?:ing)?\s+for\s+|^Grep(?:ping)?\s*:/i.test(text)) {
|
|
9868
|
-
const label2 = text.replace(/^(?:Search(?:ing)?\s+for|Grep(?:ping)?:)\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
9869
|
-
return { tool: "search", label: label2, status: "running" };
|
|
9870
|
-
}
|
|
9871
|
-
const label = text.replace(/\.\.\.$/, "").trim();
|
|
9872
|
-
return { tool: "other", label, status: "running" };
|
|
9873
|
-
}
|
|
9874
|
-
function detectSelector(lines) {
|
|
9875
|
-
if (lines.some((l) => /\?\s+for\s+shortcuts/i.test(l.trim()))) return null;
|
|
9876
|
-
const clean = lines.map(
|
|
9877
|
-
(l) => l.replace(/^[│╭╰╮╯┌└┐┘├┤┬┴┼]\s?/, "").replace(/\s*[│╭╰╮╯┌└┐┘├┤┬┴┼─━═]+\s*$/, "")
|
|
9878
|
-
);
|
|
9879
|
-
const hasCursor = clean.some((l) => /^[❯>]\s*\d+\./.test(l.trim()));
|
|
9880
|
-
const looksLikeTrust = clean.some(
|
|
9881
|
-
(l) => /\b(?:trust\s+the\s+files|trust\s+this\s+folder|safety\s+check)\b/i.test(l)
|
|
9882
|
-
);
|
|
9883
|
-
if (!hasCursor && !looksLikeTrust) return null;
|
|
9884
|
-
const OPTION_RE = /^(?:[❯>]\s*)?(\d+)\.(\s+|(?=\D))(.+)/;
|
|
9885
|
-
let optionStartIdx = -1;
|
|
9886
|
-
for (let i = 0; i < clean.length; i++) {
|
|
9887
|
-
if (OPTION_RE.test(clean[i].trim())) {
|
|
9888
|
-
optionStartIdx = i;
|
|
9889
|
-
break;
|
|
9890
|
-
}
|
|
9891
|
-
}
|
|
9892
|
-
if (optionStartIdx === -1) return null;
|
|
9893
|
-
const questionParts = [];
|
|
9894
|
-
for (let i = 0; i < optionStartIdx; i++) {
|
|
9895
|
-
const t2 = clean[i].trim();
|
|
9896
|
-
if (!t2) continue;
|
|
9897
|
-
if (/^[─━—═\-]{3,}$/.test(t2)) continue;
|
|
9898
|
-
if (/^\[.*\]$/.test(t2)) continue;
|
|
9899
|
-
if (/^[>❯]\s/.test(t2)) continue;
|
|
9900
|
-
if (!t2.includes(" ") && t2.length > 15) continue;
|
|
9901
|
-
questionParts.push(t2);
|
|
9902
|
-
}
|
|
9903
|
-
const question = questionParts.filter((line, i, arr) => !arr.some((other, j2) => j2 !== i && other.includes(line))).join("\n").trim();
|
|
9904
|
-
const optionLabels = /* @__PURE__ */ new Map();
|
|
9905
|
-
const optionDescs = /* @__PURE__ */ new Map();
|
|
9906
|
-
let currentNum = -1;
|
|
9907
|
-
for (let i = optionStartIdx; i < clean.length; i++) {
|
|
9908
|
-
const t2 = clean[i].trim();
|
|
9909
|
-
if (!t2) continue;
|
|
9910
|
-
const m = t2.match(OPTION_RE);
|
|
9911
|
-
if (m) {
|
|
9912
|
-
const num = parseInt(m[1], 10);
|
|
9913
|
-
if (!optionLabels.has(num)) {
|
|
9914
|
-
optionLabels.set(num, m[3].trim());
|
|
9915
|
-
optionDescs.set(num, []);
|
|
9916
|
-
}
|
|
9917
|
-
currentNum = num;
|
|
9918
|
-
} else if (currentNum !== -1 && !/^Enter to/i.test(t2) && !/^[─━—═\-]{3,}$/.test(t2) && !/↑.*↓.*navigate/i.test(t2) && !/Esc to/i.test(t2)) {
|
|
9919
|
-
optionDescs.get(currentNum)?.push(t2);
|
|
9920
|
-
}
|
|
9921
|
-
}
|
|
9922
|
-
const keys = [...optionLabels.keys()].sort((a, b) => a - b);
|
|
9923
|
-
if (keys.length < 2 || keys[0] !== 1) return null;
|
|
9924
|
-
return {
|
|
9925
|
-
question,
|
|
9926
|
-
options: keys.map((k2) => optionLabels.get(k2)),
|
|
9927
|
-
optionDescriptions: keys.map((k2) => (optionDescs.get(k2) ?? []).join(" ").trim()),
|
|
9928
|
-
currentIndex: 0
|
|
9929
|
-
};
|
|
9930
|
-
}
|
|
9931
|
-
function detectInputSuggestion(lines) {
|
|
9932
|
-
let hintIdx = -1;
|
|
9933
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
9934
|
-
if (/\?\s+for\s+shortcuts/i.test(lines[i].trim())) {
|
|
9935
|
-
hintIdx = i;
|
|
9936
|
-
break;
|
|
9937
|
-
}
|
|
9938
|
-
}
|
|
9939
|
-
if (hintIdx === -1) return null;
|
|
9940
|
-
if (lines.some((l) => /^[❯>]\s*\d+\./.test(l.trim()))) return null;
|
|
9941
|
-
const windowStart = Math.max(0, hintIdx - 5);
|
|
9942
|
-
for (let i = hintIdx - 1; i >= windowStart; i--) {
|
|
9943
|
-
const t2 = lines[i].trim();
|
|
9944
|
-
if (!t2) continue;
|
|
9945
|
-
if (/^[─━═│┌┐└┘├┤┬┴┼]+$/u.test(t2)) continue;
|
|
9946
|
-
const m = t2.match(/^[❯>]\s+(\S.*)$/);
|
|
9947
|
-
if (!m) return null;
|
|
9948
|
-
if (/^\d+\.\s/.test(m[1])) return null;
|
|
9949
|
-
if (/^for\s/i.test(m[1])) return null;
|
|
9950
|
-
const text = m[1].trim();
|
|
9951
|
-
if (text.length === 0) return null;
|
|
9952
|
-
return text;
|
|
9953
|
-
}
|
|
9954
|
-
return null;
|
|
9955
|
-
}
|
|
9956
|
-
function detectListSelector(lines) {
|
|
9957
|
-
if (!lines.some((l) => /[↑↓].*navigate/i.test(l.trim()))) return null;
|
|
9958
|
-
if (lines.some((l) => /^❯\s*\d+\./.test(l.trim()))) return null;
|
|
9959
|
-
if (!lines.some((l) => /^\s+❯\s+\S/.test(l))) return null;
|
|
9960
|
-
const isSelected = (line) => /^\s+❯\s+\S/.test(line);
|
|
9961
|
-
const isUnselected = (line) => /^ \S/.test(line);
|
|
9962
|
-
const isItem = (line) => isSelected(line) || isUnselected(line);
|
|
9963
|
-
let optionStartIdx = -1;
|
|
9964
|
-
for (let i = 0; i < lines.length; i++) {
|
|
9965
|
-
if (isItem(lines[i])) {
|
|
9966
|
-
optionStartIdx = i;
|
|
9967
|
-
break;
|
|
9968
|
-
}
|
|
9969
|
-
}
|
|
9970
|
-
if (optionStartIdx === -1) return null;
|
|
9971
|
-
const questionParts = [];
|
|
9972
|
-
for (let i = 0; i < optionStartIdx; i++) {
|
|
9973
|
-
const t2 = lines[i].trim();
|
|
9974
|
-
if (!t2) continue;
|
|
9975
|
-
if (/^[─━—═\-]{3,}$/.test(t2)) continue;
|
|
9976
|
-
if (/[┌└│┐┘├┤┬┴┼]/.test(t2)) {
|
|
9977
|
-
const inner = t2.replace(/[│┌└┐┘├┤┬┴┼─]/g, "").trim();
|
|
9978
|
-
if (inner) questionParts.push(inner);
|
|
9979
|
-
continue;
|
|
9980
|
-
}
|
|
9981
|
-
if (/^[>❯]\s/.test(t2)) continue;
|
|
9982
|
-
if (/[↑↓].*navigate/i.test(t2)) continue;
|
|
9983
|
-
if (!t2.includes(" ") && t2.length > 15) continue;
|
|
9984
|
-
questionParts.push(t2);
|
|
9985
|
-
}
|
|
9986
|
-
const question = questionParts.filter((line, i, arr) => !arr.some((other, j2) => j2 !== i && other.includes(line))).join("\n").trim();
|
|
9987
|
-
const options = [];
|
|
9988
|
-
let currentIndex = 0;
|
|
9989
|
-
for (const line of lines.slice(optionStartIdx)) {
|
|
9990
|
-
const t2 = line.trim();
|
|
9991
|
-
if (!t2) continue;
|
|
9992
|
-
if (/[↑↓].*navigate/i.test(t2)) break;
|
|
9993
|
-
if (/^[─━—═\-]{3,}$/.test(t2)) continue;
|
|
9994
|
-
if (isSelected(line)) {
|
|
9995
|
-
currentIndex = options.length;
|
|
9996
|
-
options.push(t2.replace(/^❯\s+/, "").trim());
|
|
9997
|
-
} else if (isUnselected(line)) {
|
|
9998
|
-
options.push(t2);
|
|
9999
|
-
}
|
|
10000
|
-
}
|
|
10001
|
-
if (options.length < 2) return null;
|
|
10002
|
-
return {
|
|
10003
|
-
question,
|
|
10004
|
-
options,
|
|
10005
|
-
optionDescriptions: options.map(() => ""),
|
|
10006
|
-
currentIndex
|
|
10007
|
-
};
|
|
10008
|
-
}
|
|
10009
|
-
var BANNER_ART_RE = /[█▀▄▌▐▝▘▛▜▙▟▖▗▔▕▮▯▰▱▓▒░◆◇]/;
|
|
10010
|
-
var BANNER_META_RE = /(?:Sonnet|Opus|Haiku|Claude)(?:\s|·|-|\(|$)/i;
|
|
10011
|
-
function detectStartupBanner(lines) {
|
|
10012
|
-
for (let i = 0; i + 2 < lines.length; i++) {
|
|
10013
|
-
if (!/▐▛[█]+▜▌/.test(lines[i])) continue;
|
|
10014
|
-
if (!/▝▜[█]+▛▘/.test(lines[i + 1])) continue;
|
|
10015
|
-
if (!lines[i + 2].includes("\u2598\u2598")) continue;
|
|
10016
|
-
const inArtTitle = lines[i].replace(/^▐▛[█]+▜▌\s*/, "").trim();
|
|
10017
|
-
const inArtSubtitle = lines[i + 1].replace(/^▝▜[█]+▛▘\s*/, "").trim();
|
|
10018
|
-
const inArtPath = lines[i + 2].replace(/.*▝▝\s*/, "").trim();
|
|
10019
|
-
return {
|
|
10020
|
-
title: inArtTitle === lines[i].trim() ? "" : inArtTitle,
|
|
10021
|
-
subtitle: inArtSubtitle === lines[i + 1].trim() ? "" : inArtSubtitle,
|
|
10022
|
-
path: inArtPath === lines[i + 2].trim() ? "" : inArtPath,
|
|
10023
|
-
startIdx: i,
|
|
10024
|
-
endIdx: i + 2
|
|
10025
|
-
};
|
|
10026
|
-
}
|
|
10027
|
-
const metaIdx = lines.findIndex(
|
|
10028
|
-
(l) => BANNER_META_RE.test(l) && /(?:Claude|API|Console)/i.test(l) && !BANNER_ART_RE.test(l)
|
|
10029
|
-
);
|
|
10030
|
-
if (metaIdx === -1) return null;
|
|
10031
|
-
let artStart = metaIdx;
|
|
10032
|
-
while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
|
|
10033
|
-
if (metaIdx - artStart < 2) return null;
|
|
10034
|
-
const pathLine = (lines[metaIdx + 1] ?? "").trim();
|
|
10035
|
-
const path55 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
|
|
10036
|
-
return {
|
|
10037
|
-
title: "",
|
|
10038
|
-
subtitle: lines[metaIdx].trim(),
|
|
10039
|
-
path: path55,
|
|
10040
|
-
startIdx: artStart,
|
|
10041
|
-
endIdx: metaIdx + (path55 ? 1 : 0)
|
|
10042
|
-
};
|
|
10043
|
-
}
|
|
10044
|
-
|
|
10045
9751
|
// src/agents/claude/runtime.ts
|
|
10046
9752
|
var ClaudeRuntimeStrategy = class {
|
|
10047
9753
|
id = "claude";
|
|
10048
9754
|
meta = getAgent("claude");
|
|
10049
9755
|
mode = "interactive";
|
|
10050
9756
|
os;
|
|
10051
|
-
constructor(
|
|
10052
|
-
this.os =
|
|
9757
|
+
constructor(os36) {
|
|
9758
|
+
this.os = os36;
|
|
10053
9759
|
}
|
|
10054
9760
|
/**
|
|
10055
9761
|
* Claude Code's react-ink TUI enables bracketed-paste mode at
|
|
@@ -10152,24 +9858,17 @@ var ClaudeRuntimeStrategy = class {
|
|
|
10152
9858
|
return { ptyInput: "/compact\r" };
|
|
10153
9859
|
}
|
|
10154
9860
|
// ─── TUI parser strategy methods ─────────────────────────────────
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
9861
|
+
// Claude runs ACP-only (see the `requiresAcp` dispatch in start.ts),
|
|
9862
|
+
// so the legacy PTY-spawn pipeline never reaches these. They remain
|
|
9863
|
+
// as inert stubs purely to satisfy the InteractiveAgentStrategy
|
|
9864
|
+
// contract; the React-Ink TUI parsers were removed with the PTY path.
|
|
9865
|
+
// The optional TUI hooks (parseTuiChrome / detectReadyPrompt /
|
|
9866
|
+
// detectStartupBanner / detectInputSuggestion) are dropped entirely.
|
|
10159
9867
|
filterTuiOutput(lines) {
|
|
10160
|
-
return
|
|
10161
|
-
}
|
|
10162
|
-
detectInteractivePrompt(lines) {
|
|
10163
|
-
return detectSelector(lines) ?? detectListSelector(lines);
|
|
10164
|
-
}
|
|
10165
|
-
detectReadyPrompt(lines) {
|
|
10166
|
-
return lines.some((l) => /^\?\s.*shortcut/i.test(l.trim()));
|
|
10167
|
-
}
|
|
10168
|
-
detectStartupBanner(lines) {
|
|
10169
|
-
return detectStartupBanner(lines);
|
|
9868
|
+
return lines;
|
|
10170
9869
|
}
|
|
10171
|
-
|
|
10172
|
-
return
|
|
9870
|
+
detectInteractivePrompt(_lines) {
|
|
9871
|
+
return null;
|
|
10173
9872
|
}
|
|
10174
9873
|
credentialLocator() {
|
|
10175
9874
|
return claudeCredentialLocator();
|
|
@@ -10603,410 +10302,6 @@ function getCurrentUsage2(historyDir) {
|
|
|
10603
10302
|
};
|
|
10604
10303
|
}
|
|
10605
10304
|
|
|
10606
|
-
// src/agents/codex/parsing.ts
|
|
10607
|
-
var BOX_DRAW_RE = /^[╭─╮│╰╯]/u;
|
|
10608
|
-
var BULLET_CHARS = "\u2022\xB7\u2027\u2219\u22C5";
|
|
10609
|
-
var CODEX_AGENT_REPLY_RE = new RegExp(`^[${BULLET_CHARS}]\\s`, "u");
|
|
10610
|
-
var STRIP_BULLET_RE = new RegExp(`^(\\s*)[${BULLET_CHARS}]\\s`, "u");
|
|
10611
|
-
var CODEX_USER_ECHO_RE = /^[›>]\s+(?!\d+\.\s)\S/u;
|
|
10612
|
-
var TIP_RE = /^\s*Tip:\s/i;
|
|
10613
|
-
var LEARN_MORE_RE = /^\s*Learn more:\s/i;
|
|
10614
|
-
var CODEX_STATUS_FOOTER_RE = /\bdefault\s+[·•]\s+\S+/i;
|
|
10615
|
-
var CODEAM_BANNER_RES = [
|
|
10616
|
-
// Bullet-prefixed banner entries (any role / launch label).
|
|
10617
|
-
new RegExp(`^[${BULLET_CHARS}]\\s+(Launching|Edgar|PRO|FREE|ENTERPRISE)\\b`, "i"),
|
|
10618
|
-
/^Paired\b/,
|
|
10619
|
-
/^codeam\b\s+v\d/,
|
|
10620
|
-
/^✓\s+Paired/,
|
|
10621
|
-
/^◇\s+Paired/
|
|
10622
|
-
];
|
|
10623
|
-
function filterCodexChrome(lines) {
|
|
10624
|
-
const out2 = [];
|
|
10625
|
-
for (const line of lines) {
|
|
10626
|
-
const t2 = line.trimEnd();
|
|
10627
|
-
const trimmed = t2.trimStart();
|
|
10628
|
-
if (!trimmed) continue;
|
|
10629
|
-
if (BOX_DRAW_RE.test(trimmed)) continue;
|
|
10630
|
-
if (/^OpenAI Codex\b/i.test(trimmed) || /^>_\s+OpenAI Codex\b/i.test(trimmed) || /^model:\s/i.test(trimmed) || /^directory:\s/i.test(trimmed)) continue;
|
|
10631
|
-
if (TIP_RE.test(t2) || LEARN_MORE_RE.test(t2)) continue;
|
|
10632
|
-
if (CODEX_STATUS_FOOTER_RE.test(trimmed)) continue;
|
|
10633
|
-
if (CODEAM_BANNER_RES.some((re2) => re2.test(trimmed))) continue;
|
|
10634
|
-
if (CODEX_USER_ECHO_RE.test(trimmed)) continue;
|
|
10635
|
-
if (CODEX_AGENT_REPLY_RE.test(trimmed)) {
|
|
10636
|
-
out2.push(t2.replace(STRIP_BULLET_RE, "$1"));
|
|
10637
|
-
continue;
|
|
10638
|
-
}
|
|
10639
|
-
out2.push(t2);
|
|
10640
|
-
}
|
|
10641
|
-
const dedented = dedentCodexStructuredLines(out2);
|
|
10642
|
-
const wrapped = wrapCodexCodeBlocks(dedented);
|
|
10643
|
-
const hasRealInput = lines.some((l) => /\w/.test(l));
|
|
10644
|
-
if (out2.length > 0 || hasRealInput) {
|
|
10645
|
-
const sampleIn = lines.slice(-50).map((l, i) => ` in[${i}] ${JSON.stringify(l)}`).join("\n");
|
|
10646
|
-
const sampleOut = dedented.map((l, i) => ` out[${i}] ${JSON.stringify(l)}`).join("\n");
|
|
10647
|
-
log.info("codex-parse", `in=${lines.length} out=${dedented.length}
|
|
10648
|
-
${sampleIn}
|
|
10649
|
-
---
|
|
10650
|
-
${sampleOut}`);
|
|
10651
|
-
} else {
|
|
10652
|
-
log.trace("codex-parse", `filterCodexChrome in=${lines.length} out=${out2.length}`);
|
|
10653
|
-
}
|
|
10654
|
-
return wrapped;
|
|
10655
|
-
}
|
|
10656
|
-
var CODE_CHAR_RE = /[;{}]|=>|^\s*(?:import|public|private|static|class|function|interface|type|const|let|var|def|return|if|else|for|while)\b/;
|
|
10657
|
-
var DIFF_HUNK_RE = /^@@\s+-\d+(?:,\d+)?\s+\+\d+(?:,\d+)?\s+@@/;
|
|
10658
|
-
var DIFF_GIT_RE = /^diff\s+--git\s+/;
|
|
10659
|
-
var DIFF_OLD_RE = /^---\s+(?:a\/)?\S/;
|
|
10660
|
-
var DIFF_NEW_RE = /^\+\+\+\s+(?:b\/)?\S/;
|
|
10661
|
-
var COMMIT_HEAD_RE = /^\[[\w./@-]+\s+[0-9a-f]{7,40}\]\s+/;
|
|
10662
|
-
var COMMIT_STATS_RE = /\d+\s+files?\s+changed/;
|
|
10663
|
-
var PUSH_TO_RE = /^To\s+(?:https?:\/\/|git@)/;
|
|
10664
|
-
var PUSH_NEW_RE = /\[new branch\]\s+\S+\s*->\s*\S+/;
|
|
10665
|
-
var PUSH_UPDATE_RE = /^\s*[0-9a-f]{7,40}\.\.[0-9a-f]{7,40}\s+\S+\s*->\s*\S+/;
|
|
10666
|
-
var MERGE_UPD_RE = /^Updating\s+[0-9a-f]{7,40}\.\.[0-9a-f]{7,40}/;
|
|
10667
|
-
var MERGE_FF_RE = /^Fast-forward\s*$/;
|
|
10668
|
-
var PR_TITLE_RE = /^title:\s+\S/;
|
|
10669
|
-
var PR_STATE_RE = /^state:\s+(?:OPEN|CLOSED|MERGED|DRAFT)/i;
|
|
10670
|
-
var PR_URL_RE = /https?:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/\d+/;
|
|
10671
|
-
var PR_BANNER_RE = /^\s*[✓✔]?\s*Pull request created\s*$/i;
|
|
10672
|
-
function dedentCodexStructuredLines(lines) {
|
|
10673
|
-
const MARKER_RE = /^( +)(?:diff --git |@@ |--- |\+\+\+ |Updating [0-9a-f]|Fast-forward|Merge made by |To (?:https?:\/\/|git@|github\.com|[\w.-]+[:/])|From (?:https?:\/\/|git@|github\.com|[\w.-]+[:/])|\[[\w./@-]+\s+[0-9a-f]{7,40}\])/;
|
|
10674
|
-
let margin = -1;
|
|
10675
|
-
for (const line of lines) {
|
|
10676
|
-
const m = line.match(MARKER_RE);
|
|
10677
|
-
if (m) {
|
|
10678
|
-
const w3 = m[1].length;
|
|
10679
|
-
if (margin === -1 || w3 < margin) margin = w3;
|
|
10680
|
-
}
|
|
10681
|
-
}
|
|
10682
|
-
if (margin <= 0) return lines;
|
|
10683
|
-
return lines.map((line) => {
|
|
10684
|
-
if (line.length === 0) return line;
|
|
10685
|
-
const lead = line.match(/^ */)?.[0].length ?? 0;
|
|
10686
|
-
const strip = Math.min(margin, lead);
|
|
10687
|
-
return strip > 0 ? line.slice(strip) : line;
|
|
10688
|
-
});
|
|
10689
|
-
}
|
|
10690
|
-
function isStructuredBlock(block) {
|
|
10691
|
-
if (block.some((l) => DIFF_HUNK_RE.test(l))) return true;
|
|
10692
|
-
if (block.some((l) => DIFF_GIT_RE.test(l))) return true;
|
|
10693
|
-
if (block.some((l) => DIFF_OLD_RE.test(l)) && block.some((l) => DIFF_NEW_RE.test(l))) return true;
|
|
10694
|
-
if (block.some((l) => COMMIT_HEAD_RE.test(l))) return true;
|
|
10695
|
-
if (block.some((l) => COMMIT_STATS_RE.test(l))) return true;
|
|
10696
|
-
if (block.some((l) => PUSH_TO_RE.test(l))) return true;
|
|
10697
|
-
if (block.some((l) => PUSH_NEW_RE.test(l))) return true;
|
|
10698
|
-
if (block.some((l) => PUSH_UPDATE_RE.test(l))) return true;
|
|
10699
|
-
if (block.some((l) => MERGE_UPD_RE.test(l))) return true;
|
|
10700
|
-
if (block.some((l) => MERGE_FF_RE.test(l))) return true;
|
|
10701
|
-
if (block.some((l) => PR_TITLE_RE.test(l)) && block.some((l) => PR_STATE_RE.test(l))) return true;
|
|
10702
|
-
if (block.some((l) => PR_URL_RE.test(l))) return true;
|
|
10703
|
-
if (block.some((l) => PR_BANNER_RE.test(l))) return true;
|
|
10704
|
-
return false;
|
|
10705
|
-
}
|
|
10706
|
-
function inferLanguage(block) {
|
|
10707
|
-
const head = block.slice(0, 10).join("\n");
|
|
10708
|
-
if (/\bpublic\s+(?:static\s+)?(?:class|void|int|String)\b|System\.out\.println|\bjava\.util/.test(head)) return "java";
|
|
10709
|
-
if (/\b(?:interface|type)\s+\w+\s*=?\s*[{<]|\bas\s+(?:string|number|boolean)\b|\b(?:string|number|boolean)\s*[;,)\]]/.test(head)) return "typescript";
|
|
10710
|
-
if (/\bimport\s+\w+\s+from\s+['"]|=>\s*[{(]|\bconst\s+\w+\s*=\s*(?:async\s+)?\(/.test(head)) return "javascript";
|
|
10711
|
-
if (/^\s*def\s+\w+\(|^\s*from\s+\w+\s+import|print\(/m.test(head)) return "python";
|
|
10712
|
-
if (/^\s*package\s+\w+|^\s*func\s+\w+\(|\binterface\s*{/m.test(head)) return "go";
|
|
10713
|
-
if (/^\s*fn\s+\w+\(|^\s*use\s+\w+::|^\s*impl\s+/m.test(head)) return "rust";
|
|
10714
|
-
if (/#include\s*<|int\s+main\s*\(/.test(head)) return "cpp";
|
|
10715
|
-
return "";
|
|
10716
|
-
}
|
|
10717
|
-
function wrapCodexCodeBlocks(lines) {
|
|
10718
|
-
if (isStructuredBlock(lines)) {
|
|
10719
|
-
return lines;
|
|
10720
|
-
}
|
|
10721
|
-
const result = [];
|
|
10722
|
-
let i = 0;
|
|
10723
|
-
while (i < lines.length) {
|
|
10724
|
-
const line = lines[i];
|
|
10725
|
-
if (!CODE_CHAR_RE.test(line)) {
|
|
10726
|
-
result.push(line);
|
|
10727
|
-
i++;
|
|
10728
|
-
continue;
|
|
10729
|
-
}
|
|
10730
|
-
const start2 = i;
|
|
10731
|
-
let end = i;
|
|
10732
|
-
let j2 = i + 1;
|
|
10733
|
-
while (j2 < lines.length) {
|
|
10734
|
-
const l = lines[j2];
|
|
10735
|
-
if (CODE_CHAR_RE.test(l)) {
|
|
10736
|
-
end = j2;
|
|
10737
|
-
j2++;
|
|
10738
|
-
continue;
|
|
10739
|
-
}
|
|
10740
|
-
if (l.trim() === "") {
|
|
10741
|
-
let k2 = j2 + 1;
|
|
10742
|
-
while (k2 < lines.length && lines[k2].trim() === "") k2++;
|
|
10743
|
-
if (k2 < lines.length && CODE_CHAR_RE.test(lines[k2])) {
|
|
10744
|
-
end = k2;
|
|
10745
|
-
j2 = k2 + 1;
|
|
10746
|
-
continue;
|
|
10747
|
-
}
|
|
10748
|
-
break;
|
|
10749
|
-
}
|
|
10750
|
-
if (/^\s{2,}\S/.test(l)) {
|
|
10751
|
-
end = j2;
|
|
10752
|
-
j2++;
|
|
10753
|
-
continue;
|
|
10754
|
-
}
|
|
10755
|
-
break;
|
|
10756
|
-
}
|
|
10757
|
-
const runLen = end - start2 + 1;
|
|
10758
|
-
const body = lines.slice(start2, end + 1);
|
|
10759
|
-
if (isStructuredBlock(body)) {
|
|
10760
|
-
for (const l of body) result.push(l);
|
|
10761
|
-
i = end + 1;
|
|
10762
|
-
continue;
|
|
10763
|
-
}
|
|
10764
|
-
const codeShapedCount = body.filter((l) => CODE_CHAR_RE.test(l)).length;
|
|
10765
|
-
if (codeShapedCount >= 3) {
|
|
10766
|
-
const lang = inferLanguage(body);
|
|
10767
|
-
result.push("```" + lang);
|
|
10768
|
-
for (const l of body) result.push(l);
|
|
10769
|
-
while (result.length > 0 && result[result.length - 1].trim() === "") {
|
|
10770
|
-
result.pop();
|
|
10771
|
-
}
|
|
10772
|
-
result.push("```");
|
|
10773
|
-
i = end + 1;
|
|
10774
|
-
} else {
|
|
10775
|
-
for (let k2 = start2; k2 <= end && k2 < lines.length; k2++) result.push(lines[k2]);
|
|
10776
|
-
i = end + 1;
|
|
10777
|
-
if (i === start2) i++;
|
|
10778
|
-
}
|
|
10779
|
-
void runLen;
|
|
10780
|
-
}
|
|
10781
|
-
return result;
|
|
10782
|
-
}
|
|
10783
|
-
function parseCodexChrome(_line) {
|
|
10784
|
-
return null;
|
|
10785
|
-
}
|
|
10786
|
-
var CODEX_OPTION_RE = /^\s*([>›]\s+)?(\d+)\.\s+(.+)/;
|
|
10787
|
-
var CODEX_OPTION_START_RE = /^\s*(?:[>›]\s+)?\d+\.\s/;
|
|
10788
|
-
var CODEX_FOOTER_RE = /\bpress\s+enter\s+to\s+(?:confirm|continue|select)\b/i;
|
|
10789
|
-
function detectCodexSelector(lines) {
|
|
10790
|
-
let optionStartIdx = -1;
|
|
10791
|
-
for (let i = 0; i < lines.length; i++) {
|
|
10792
|
-
if (CODEX_OPTION_START_RE.test(lines[i])) {
|
|
10793
|
-
optionStartIdx = i;
|
|
10794
|
-
break;
|
|
10795
|
-
}
|
|
10796
|
-
}
|
|
10797
|
-
if (optionStartIdx === -1) return null;
|
|
10798
|
-
const optionLabels = /* @__PURE__ */ new Map();
|
|
10799
|
-
let cursorIndex = 0;
|
|
10800
|
-
let hasCursor = false;
|
|
10801
|
-
let footerAfterOptions = false;
|
|
10802
|
-
let lastOptionLineIdx = optionStartIdx;
|
|
10803
|
-
for (let i = optionStartIdx; i < lines.length; i++) {
|
|
10804
|
-
const raw = lines[i];
|
|
10805
|
-
const t2 = raw.trim();
|
|
10806
|
-
if (!t2) continue;
|
|
10807
|
-
if (CODEX_FOOTER_RE.test(t2)) {
|
|
10808
|
-
footerAfterOptions = true;
|
|
10809
|
-
break;
|
|
10810
|
-
}
|
|
10811
|
-
const m = t2.match(CODEX_OPTION_RE);
|
|
10812
|
-
if (!m) {
|
|
10813
|
-
if (i - lastOptionLineIdx > 2) break;
|
|
10814
|
-
continue;
|
|
10815
|
-
}
|
|
10816
|
-
const num = parseInt(m[2], 10);
|
|
10817
|
-
if (!optionLabels.has(num)) {
|
|
10818
|
-
optionLabels.set(num, m[3].trim());
|
|
10819
|
-
if (m[1]) {
|
|
10820
|
-
cursorIndex = optionLabels.size - 1;
|
|
10821
|
-
hasCursor = true;
|
|
10822
|
-
}
|
|
10823
|
-
}
|
|
10824
|
-
lastOptionLineIdx = i;
|
|
10825
|
-
}
|
|
10826
|
-
const keys = [...optionLabels.keys()].sort((a, b) => a - b);
|
|
10827
|
-
if (keys.length < 2 || keys[0] !== 1) return null;
|
|
10828
|
-
const questionParts = [];
|
|
10829
|
-
for (let i = 0; i < optionStartIdx; i++) {
|
|
10830
|
-
const t2 = lines[i].trim();
|
|
10831
|
-
if (!t2) continue;
|
|
10832
|
-
if (/^[>›]\s*$/.test(t2)) continue;
|
|
10833
|
-
questionParts.push(t2);
|
|
10834
|
-
}
|
|
10835
|
-
const question = questionParts.join("\n").trim();
|
|
10836
|
-
const questionEndsWithQuery = /\?\s*$/.test(question);
|
|
10837
|
-
if (!hasCursor && !(questionEndsWithQuery && footerAfterOptions)) {
|
|
10838
|
-
return null;
|
|
10839
|
-
}
|
|
10840
|
-
return {
|
|
10841
|
-
question,
|
|
10842
|
-
options: keys.map((k2) => optionLabels.get(k2)),
|
|
10843
|
-
optionDescriptions: keys.map(() => ""),
|
|
10844
|
-
currentIndex: hasCursor ? cursorIndex : 0
|
|
10845
|
-
};
|
|
10846
|
-
}
|
|
10847
|
-
|
|
10848
|
-
// src/agents/codex/renderer.ts
|
|
10849
|
-
function renderCodexBuffer(raw) {
|
|
10850
|
-
const scrollback = [];
|
|
10851
|
-
const screen = [""];
|
|
10852
|
-
let row = 0;
|
|
10853
|
-
let col = 0;
|
|
10854
|
-
let scrollTop = null;
|
|
10855
|
-
let scrollBottom = null;
|
|
10856
|
-
function ensureRow() {
|
|
10857
|
-
while (screen.length <= row) screen.push("");
|
|
10858
|
-
}
|
|
10859
|
-
function writeChar(ch) {
|
|
10860
|
-
ensureRow();
|
|
10861
|
-
if (col < screen[row].length) {
|
|
10862
|
-
screen[row] = screen[row].slice(0, col) + ch + screen[row].slice(col + 1);
|
|
10863
|
-
} else {
|
|
10864
|
-
while (screen[row].length < col) screen[row] += " ";
|
|
10865
|
-
screen[row] += ch;
|
|
10866
|
-
}
|
|
10867
|
-
col++;
|
|
10868
|
-
}
|
|
10869
|
-
function scrollRegionUp() {
|
|
10870
|
-
if (scrollTop === null || scrollBottom === null) {
|
|
10871
|
-
ensureRow();
|
|
10872
|
-
return;
|
|
10873
|
-
}
|
|
10874
|
-
while (screen.length <= scrollBottom) screen.push("");
|
|
10875
|
-
if (screen[scrollTop].trim() !== "") {
|
|
10876
|
-
scrollback.push(screen[scrollTop]);
|
|
10877
|
-
}
|
|
10878
|
-
for (let r = scrollTop; r < scrollBottom; r++) {
|
|
10879
|
-
screen[r] = screen[r + 1];
|
|
10880
|
-
}
|
|
10881
|
-
screen[scrollBottom] = "";
|
|
10882
|
-
}
|
|
10883
|
-
function scrollRegionDown() {
|
|
10884
|
-
if (scrollTop === null || scrollBottom === null) {
|
|
10885
|
-
return;
|
|
10886
|
-
}
|
|
10887
|
-
while (screen.length <= scrollBottom) screen.push("");
|
|
10888
|
-
if (screen[scrollBottom].trim() !== "") {
|
|
10889
|
-
scrollback.push(screen[scrollBottom]);
|
|
10890
|
-
}
|
|
10891
|
-
for (let r = scrollBottom; r > scrollTop; r--) {
|
|
10892
|
-
screen[r] = screen[r - 1];
|
|
10893
|
-
}
|
|
10894
|
-
screen[scrollTop] = "";
|
|
10895
|
-
}
|
|
10896
|
-
let i = 0;
|
|
10897
|
-
while (i < raw.length) {
|
|
10898
|
-
const ch = raw[i];
|
|
10899
|
-
if (ch === "\x1B") {
|
|
10900
|
-
i++;
|
|
10901
|
-
if (i >= raw.length) break;
|
|
10902
|
-
if (raw[i] === "[") {
|
|
10903
|
-
i++;
|
|
10904
|
-
let param = "";
|
|
10905
|
-
while (i < raw.length && !/[@-~]/.test(raw[i])) param += raw[i++];
|
|
10906
|
-
const cmd = raw[i] ?? "";
|
|
10907
|
-
const n = parseInt(param) || 1;
|
|
10908
|
-
if (cmd === "A") {
|
|
10909
|
-
row = Math.max(0, row - n);
|
|
10910
|
-
} else if (cmd === "B") {
|
|
10911
|
-
row += n;
|
|
10912
|
-
ensureRow();
|
|
10913
|
-
} else if (cmd === "C") {
|
|
10914
|
-
col += n;
|
|
10915
|
-
} else if (cmd === "D") {
|
|
10916
|
-
col = Math.max(0, col - n);
|
|
10917
|
-
} else if (cmd === "G") {
|
|
10918
|
-
col = Math.max(0, n - 1);
|
|
10919
|
-
} else if (cmd === "H" || cmd === "f") {
|
|
10920
|
-
const p2 = param.split(";");
|
|
10921
|
-
row = Math.max(0, (parseInt(p2[0] ?? "1") || 1) - 1);
|
|
10922
|
-
col = Math.max(0, (parseInt(p2[1] ?? "1") || 1) - 1);
|
|
10923
|
-
ensureRow();
|
|
10924
|
-
} else if (cmd === "J") {
|
|
10925
|
-
if (param === "2" || param === "3") {
|
|
10926
|
-
for (let r = 0; r < screen.length; r++) {
|
|
10927
|
-
if (screen[r].trim() !== "") scrollback.push(screen[r]);
|
|
10928
|
-
}
|
|
10929
|
-
screen.length = 1;
|
|
10930
|
-
screen[0] = "";
|
|
10931
|
-
row = 0;
|
|
10932
|
-
col = 0;
|
|
10933
|
-
} else if (param === "1") {
|
|
10934
|
-
for (let r = 0; r < row; r++) screen[r] = "";
|
|
10935
|
-
screen[row] = " ".repeat(col) + screen[row].slice(col);
|
|
10936
|
-
} else {
|
|
10937
|
-
screen[row] = screen[row].slice(0, col);
|
|
10938
|
-
screen.splice(row + 1);
|
|
10939
|
-
}
|
|
10940
|
-
} else if (cmd === "K") {
|
|
10941
|
-
ensureRow();
|
|
10942
|
-
if (param === "" || param === "0") screen[row] = screen[row].slice(0, col);
|
|
10943
|
-
else if (param === "1") screen[row] = " ".repeat(col) + screen[row].slice(col);
|
|
10944
|
-
else if (param === "2") screen[row] = "";
|
|
10945
|
-
} else if (cmd === "r") {
|
|
10946
|
-
if (param === "" || param === ";") {
|
|
10947
|
-
scrollTop = null;
|
|
10948
|
-
scrollBottom = null;
|
|
10949
|
-
} else {
|
|
10950
|
-
const p2 = param.split(";");
|
|
10951
|
-
const top = parseInt(p2[0] ?? "1") || 1;
|
|
10952
|
-
const bot = parseInt(p2[1] ?? "1") || 1;
|
|
10953
|
-
scrollTop = Math.max(0, top - 1);
|
|
10954
|
-
scrollBottom = Math.max(scrollTop, bot - 1);
|
|
10955
|
-
}
|
|
10956
|
-
}
|
|
10957
|
-
} else if (raw[i] === "]") {
|
|
10958
|
-
i++;
|
|
10959
|
-
while (i < raw.length) {
|
|
10960
|
-
if (raw[i] === "\x07") break;
|
|
10961
|
-
if (raw[i] === "\x1B" && i + 1 < raw.length && raw[i + 1] === "\\") {
|
|
10962
|
-
i++;
|
|
10963
|
-
break;
|
|
10964
|
-
}
|
|
10965
|
-
i++;
|
|
10966
|
-
}
|
|
10967
|
-
} else if (raw[i] === "M") {
|
|
10968
|
-
if (scrollTop !== null && row === scrollTop) {
|
|
10969
|
-
scrollRegionDown();
|
|
10970
|
-
} else {
|
|
10971
|
-
row = Math.max(0, row - 1);
|
|
10972
|
-
}
|
|
10973
|
-
} else if (raw[i] === "D") {
|
|
10974
|
-
if (scrollBottom !== null && row === scrollBottom) {
|
|
10975
|
-
scrollRegionUp();
|
|
10976
|
-
} else {
|
|
10977
|
-
row++;
|
|
10978
|
-
ensureRow();
|
|
10979
|
-
}
|
|
10980
|
-
}
|
|
10981
|
-
} else if (ch === "\r") {
|
|
10982
|
-
if (i + 1 < raw.length && raw[i + 1] === "\n") {
|
|
10983
|
-
if (scrollBottom !== null && row === scrollBottom) {
|
|
10984
|
-
scrollRegionUp();
|
|
10985
|
-
} else {
|
|
10986
|
-
row++;
|
|
10987
|
-
ensureRow();
|
|
10988
|
-
}
|
|
10989
|
-
col = 0;
|
|
10990
|
-
i++;
|
|
10991
|
-
} else {
|
|
10992
|
-
col = 0;
|
|
10993
|
-
}
|
|
10994
|
-
} else if (ch === "\n") {
|
|
10995
|
-
if (scrollBottom !== null && row === scrollBottom) {
|
|
10996
|
-
scrollRegionUp();
|
|
10997
|
-
} else {
|
|
10998
|
-
row++;
|
|
10999
|
-
ensureRow();
|
|
11000
|
-
}
|
|
11001
|
-
col = 0;
|
|
11002
|
-
} else if (ch >= " " || ch === " ") {
|
|
11003
|
-
writeChar(ch);
|
|
11004
|
-
}
|
|
11005
|
-
i++;
|
|
11006
|
-
}
|
|
11007
|
-
return [...scrollback, ...screen];
|
|
11008
|
-
}
|
|
11009
|
-
|
|
11010
10305
|
// src/agents/codex/link.ts
|
|
11011
10306
|
var import_node_child_process3 = require("child_process");
|
|
11012
10307
|
|
|
@@ -11079,8 +10374,8 @@ function codexCredentialLocator() {
|
|
|
11079
10374
|
function codexLoginLauncher() {
|
|
11080
10375
|
return {
|
|
11081
10376
|
async ensureInstalled() {
|
|
11082
|
-
const
|
|
11083
|
-
return
|
|
10377
|
+
const os36 = createOsStrategy();
|
|
10378
|
+
return os36.findInPath("codex") !== null;
|
|
11084
10379
|
},
|
|
11085
10380
|
launch() {
|
|
11086
10381
|
return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
@@ -11103,8 +10398,8 @@ var CodexRuntimeStrategy = class {
|
|
|
11103
10398
|
meta = getAgent("codex");
|
|
11104
10399
|
mode = "interactive";
|
|
11105
10400
|
os;
|
|
11106
|
-
constructor(
|
|
11107
|
-
this.os =
|
|
10401
|
+
constructor(os36) {
|
|
10402
|
+
this.os = os36;
|
|
11108
10403
|
}
|
|
11109
10404
|
async prepareLaunch() {
|
|
11110
10405
|
let binary = this.os.findInPath("codex");
|
|
@@ -11172,27 +10467,17 @@ var CodexRuntimeStrategy = class {
|
|
|
11172
10467
|
return { ptyInput: "/compact\r" };
|
|
11173
10468
|
}
|
|
11174
10469
|
// ─── TUI parser strategy methods ─────────────────────────────────
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
*/
|
|
11182
|
-
renderToLines(buffer) {
|
|
11183
|
-
return renderCodexBuffer(buffer);
|
|
11184
|
-
}
|
|
11185
|
-
parseTuiChrome(line) {
|
|
11186
|
-
return parseCodexChrome(line);
|
|
11187
|
-
}
|
|
10470
|
+
// Codex runs ACP-only (see the `requiresAcp` dispatch in start.ts);
|
|
10471
|
+
// the legacy PTY-spawn pipeline never reaches these. Inert stubs to
|
|
10472
|
+
// satisfy the InteractiveAgentStrategy contract — the Codex ratatui
|
|
10473
|
+
// parsers + scroll-region renderer were removed with the PTY path.
|
|
10474
|
+
// The optional TUI hooks (renderToLines / parseTuiChrome /
|
|
10475
|
+
// detectReadyPrompt) are dropped entirely.
|
|
11188
10476
|
filterTuiOutput(lines) {
|
|
11189
|
-
return
|
|
11190
|
-
}
|
|
11191
|
-
detectInteractivePrompt(lines) {
|
|
11192
|
-
return detectCodexSelector(lines);
|
|
10477
|
+
return lines;
|
|
11193
10478
|
}
|
|
11194
|
-
|
|
11195
|
-
return
|
|
10479
|
+
detectInteractivePrompt(_lines) {
|
|
10480
|
+
return null;
|
|
11196
10481
|
}
|
|
11197
10482
|
credentialLocator() {
|
|
11198
10483
|
return codexCredentialLocator();
|
|
@@ -11210,12 +10495,12 @@ var CodexRuntimeStrategy = class {
|
|
|
11210
10495
|
});
|
|
11211
10496
|
}
|
|
11212
10497
|
};
|
|
11213
|
-
function resolveNpm(
|
|
11214
|
-
return
|
|
10498
|
+
function resolveNpm(os36) {
|
|
10499
|
+
return os36.id === "win32" ? "npm.cmd" : "npm";
|
|
11215
10500
|
}
|
|
11216
|
-
async function installCodexViaNpm(
|
|
10501
|
+
async function installCodexViaNpm(os36) {
|
|
11217
10502
|
return new Promise((resolve7, reject) => {
|
|
11218
|
-
const proc = (0, import_node_child_process4.spawn)(resolveNpm(
|
|
10503
|
+
const proc = (0, import_node_child_process4.spawn)(resolveNpm(os36), ["install", "-g", "@openai/codex"], {
|
|
11219
10504
|
stdio: "inherit"
|
|
11220
10505
|
});
|
|
11221
10506
|
proc.on("close", (code) => {
|
|
@@ -11232,16 +10517,16 @@ async function installCodexViaNpm(os33) {
|
|
|
11232
10517
|
});
|
|
11233
10518
|
});
|
|
11234
10519
|
}
|
|
11235
|
-
function augmentNpmGlobalBin(
|
|
10520
|
+
function augmentNpmGlobalBin(os36) {
|
|
11236
10521
|
try {
|
|
11237
|
-
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(
|
|
10522
|
+
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os36), ["prefix", "-g"], {
|
|
11238
10523
|
stdio: ["ignore", "pipe", "ignore"]
|
|
11239
10524
|
});
|
|
11240
10525
|
if (result.status !== 0) return;
|
|
11241
10526
|
const prefix = result.stdout.toString().trim();
|
|
11242
10527
|
if (!prefix) return;
|
|
11243
|
-
const binDir =
|
|
11244
|
-
|
|
10528
|
+
const binDir = os36.id === "win32" ? prefix : path17.join(prefix, "bin");
|
|
10529
|
+
os36.augmentPath([binDir]);
|
|
11245
10530
|
} catch {
|
|
11246
10531
|
}
|
|
11247
10532
|
}
|
|
@@ -11325,9 +10610,9 @@ var import_node_child_process7 = require("child_process");
|
|
|
11325
10610
|
// src/agents/coderabbit/installer.ts
|
|
11326
10611
|
var import_node_child_process5 = require("child_process");
|
|
11327
10612
|
var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
|
|
11328
|
-
async function ensureCoderabbitInstalled(
|
|
11329
|
-
if (
|
|
11330
|
-
if (
|
|
10613
|
+
async function ensureCoderabbitInstalled(os36) {
|
|
10614
|
+
if (os36.findInPath("coderabbit")) return true;
|
|
10615
|
+
if (os36.id === "win32") {
|
|
11331
10616
|
console.error(
|
|
11332
10617
|
"\n \u2717 CodeRabbit on Windows requires WSL.\n Install the CLI inside your WSL distribution\n (curl -fsSL https://cli.coderabbit.ai/install.sh | sh)\n then re-run `codeam link coderabbit` from WSL.\n"
|
|
11333
10618
|
);
|
|
@@ -11342,8 +10627,8 @@ async function ensureCoderabbitInstalled(os33) {
|
|
|
11342
10627
|
proc.on("error", () => resolve7(false));
|
|
11343
10628
|
});
|
|
11344
10629
|
if (!ok) return false;
|
|
11345
|
-
|
|
11346
|
-
return
|
|
10630
|
+
os36.augmentPath([`${os36.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
10631
|
+
return os36.findInPath("coderabbit") !== null;
|
|
11347
10632
|
}
|
|
11348
10633
|
|
|
11349
10634
|
// src/agents/coderabbit/link.ts
|
|
@@ -11370,10 +10655,10 @@ function coderabbitCredentialLocator() {
|
|
|
11370
10655
|
extract: extractLocalCoderabbitToken
|
|
11371
10656
|
};
|
|
11372
10657
|
}
|
|
11373
|
-
function coderabbitLoginLauncher(
|
|
10658
|
+
function coderabbitLoginLauncher(os36) {
|
|
11374
10659
|
return {
|
|
11375
10660
|
async ensureInstalled() {
|
|
11376
|
-
return ensureCoderabbitInstalled(
|
|
10661
|
+
return ensureCoderabbitInstalled(os36);
|
|
11377
10662
|
},
|
|
11378
10663
|
launch() {
|
|
11379
10664
|
return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
|
|
@@ -11396,11 +10681,11 @@ function parseReview(stdout) {
|
|
|
11396
10681
|
for (const line of lines) {
|
|
11397
10682
|
const m = line.match(HUNK_LINE_RE);
|
|
11398
10683
|
if (!m) continue;
|
|
11399
|
-
const [,
|
|
11400
|
-
if (!
|
|
10684
|
+
const [, path58, lineNo, sevToken, message] = m;
|
|
10685
|
+
if (!path58 || !lineNo || !message) continue;
|
|
11401
10686
|
const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
|
|
11402
10687
|
hunks.push({
|
|
11403
|
-
path:
|
|
10688
|
+
path: path58.trim(),
|
|
11404
10689
|
line: Number(lineNo),
|
|
11405
10690
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
11406
10691
|
message: cleanedMessage
|
|
@@ -11419,8 +10704,8 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11419
10704
|
meta = getAgent("coderabbit");
|
|
11420
10705
|
mode = "batch";
|
|
11421
10706
|
os;
|
|
11422
|
-
constructor(
|
|
11423
|
-
this.os =
|
|
10707
|
+
constructor(os36) {
|
|
10708
|
+
this.os = os36;
|
|
11424
10709
|
}
|
|
11425
10710
|
getDefaultArgs() {
|
|
11426
10711
|
return ["review"];
|
|
@@ -11535,10 +10820,10 @@ function cursorCredentialLocator() {
|
|
|
11535
10820
|
extract: extractLocalCursorToken
|
|
11536
10821
|
};
|
|
11537
10822
|
}
|
|
11538
|
-
function cursorLoginLauncher(
|
|
10823
|
+
function cursorLoginLauncher(os36) {
|
|
11539
10824
|
return {
|
|
11540
10825
|
async ensureInstalled() {
|
|
11541
|
-
if (
|
|
10826
|
+
if (os36.findInPath("cursor-agent")) return true;
|
|
11542
10827
|
console.error(
|
|
11543
10828
|
"\n \u2717 cursor-agent binary not on PATH.\n Install Cursor (https://cursor.com/) and ensure the CLI\n plugin is enabled, then re-run `codeam link cursor`.\n"
|
|
11544
10829
|
);
|
|
@@ -11600,8 +10885,8 @@ var CursorRuntimeStrategy = class {
|
|
|
11600
10885
|
meta = getAgent("cursor");
|
|
11601
10886
|
mode = "interactive";
|
|
11602
10887
|
os;
|
|
11603
|
-
constructor(
|
|
11604
|
-
this.os =
|
|
10888
|
+
constructor(os36) {
|
|
10889
|
+
this.os = os36;
|
|
11605
10890
|
}
|
|
11606
10891
|
async prepareLaunch() {
|
|
11607
10892
|
const binary = this.os.findInPath("cursor-agent");
|
|
@@ -11721,10 +11006,10 @@ function aiderCredentialLocator() {
|
|
|
11721
11006
|
extract: extractLocalAiderToken
|
|
11722
11007
|
};
|
|
11723
11008
|
}
|
|
11724
|
-
function aiderLoginLauncher(
|
|
11009
|
+
function aiderLoginLauncher(os36) {
|
|
11725
11010
|
return {
|
|
11726
11011
|
async ensureInstalled() {
|
|
11727
|
-
if (
|
|
11012
|
+
if (os36.findInPath("aider")) return true;
|
|
11728
11013
|
console.error(
|
|
11729
11014
|
"\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
|
|
11730
11015
|
);
|
|
@@ -11734,7 +11019,7 @@ function aiderLoginLauncher(os33) {
|
|
|
11734
11019
|
console.error(
|
|
11735
11020
|
"\n Aider has no interactive login flow.\n Set ANTHROPIC_API_KEY or OPENAI_API_KEY in your shell,\n or re-run `codeam link aider --api-key=<your-key>`.\n"
|
|
11736
11021
|
);
|
|
11737
|
-
return (0, import_node_child_process9.spawn)(
|
|
11022
|
+
return (0, import_node_child_process9.spawn)(os36.id === "win32" ? "cmd.exe" : "sh", os36.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
|
|
11738
11023
|
stdio: "ignore"
|
|
11739
11024
|
});
|
|
11740
11025
|
}
|
|
@@ -11806,8 +11091,8 @@ var AiderRuntimeStrategy = class {
|
|
|
11806
11091
|
meta = getAgent("aider");
|
|
11807
11092
|
mode = "interactive";
|
|
11808
11093
|
os;
|
|
11809
|
-
constructor(
|
|
11810
|
-
this.os =
|
|
11094
|
+
constructor(os36) {
|
|
11095
|
+
this.os = os36;
|
|
11811
11096
|
}
|
|
11812
11097
|
async prepareLaunch() {
|
|
11813
11098
|
const binary = this.os.findInPath("aider");
|
|
@@ -11936,8 +11221,8 @@ function geminiCredentialLocator() {
|
|
|
11936
11221
|
function geminiLoginLauncher() {
|
|
11937
11222
|
return {
|
|
11938
11223
|
async ensureInstalled() {
|
|
11939
|
-
const
|
|
11940
|
-
return
|
|
11224
|
+
const os36 = createOsStrategy();
|
|
11225
|
+
return os36.findInPath("gemini") !== null;
|
|
11941
11226
|
},
|
|
11942
11227
|
launch() {
|
|
11943
11228
|
return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
|
|
@@ -11970,14 +11255,14 @@ var GeminiRuntimeStrategy = class {
|
|
|
11970
11255
|
meta = getAgent("gemini");
|
|
11971
11256
|
mode = "interactive";
|
|
11972
11257
|
os;
|
|
11973
|
-
constructor(
|
|
11974
|
-
this.os =
|
|
11258
|
+
constructor(os36) {
|
|
11259
|
+
this.os = os36;
|
|
11975
11260
|
}
|
|
11976
11261
|
async prepareLaunch() {
|
|
11977
11262
|
const binary = this.os.findInPath("gemini");
|
|
11978
11263
|
if (!binary) {
|
|
11979
11264
|
throw new Error(
|
|
11980
|
-
"Gemini CLI is not on PATH. Install it with:\n npm install -g @google/gemini-cli\n Then run `codeam pair` again
|
|
11265
|
+
"Gemini CLI is not on PATH. Install it with:\n npm install -g @google/gemini-cli\n Then run `codeam pair` again."
|
|
11981
11266
|
);
|
|
11982
11267
|
}
|
|
11983
11268
|
return this.os.buildLaunch(binary);
|
|
@@ -12018,11 +11303,10 @@ var GeminiRuntimeStrategy = class {
|
|
|
12018
11303
|
return { ptyInput: "/compress\r" };
|
|
12019
11304
|
}
|
|
12020
11305
|
/**
|
|
12021
|
-
* Pass-through filter. Gemini
|
|
12022
|
-
*
|
|
12023
|
-
*
|
|
12024
|
-
*
|
|
12025
|
-
* showing whatever the REPL prints.
|
|
11306
|
+
* Pass-through filter. Gemini runs over ACP, so this is never hit
|
|
11307
|
+
* in production — it exists only to satisfy the contract's
|
|
11308
|
+
* idempotency assertion. Returning the input verbatim keeps the
|
|
11309
|
+
* stub trivially idempotent.
|
|
12026
11310
|
*/
|
|
12027
11311
|
filterTuiOutput(lines) {
|
|
12028
11312
|
return lines;
|
|
@@ -12071,18 +11355,18 @@ var GeminiRuntimeStrategy = class {
|
|
|
12071
11355
|
|
|
12072
11356
|
// src/agents/registry.ts
|
|
12073
11357
|
var runtimeBuilders = {
|
|
12074
|
-
claude: (
|
|
12075
|
-
codex: (
|
|
12076
|
-
coderabbit: (
|
|
12077
|
-
cursor: (
|
|
12078
|
-
aider: (
|
|
12079
|
-
gemini: (
|
|
11358
|
+
claude: (os36) => new ClaudeRuntimeStrategy(os36),
|
|
11359
|
+
codex: (os36) => new CodexRuntimeStrategy(os36),
|
|
11360
|
+
coderabbit: (os36) => new CoderabbitRuntimeStrategy(os36),
|
|
11361
|
+
cursor: (os36) => new CursorRuntimeStrategy(os36),
|
|
11362
|
+
aider: (os36) => new AiderRuntimeStrategy(os36),
|
|
11363
|
+
gemini: (os36) => new GeminiRuntimeStrategy(os36)
|
|
12080
11364
|
};
|
|
12081
11365
|
var deployBuilders = {
|
|
12082
11366
|
claude: () => new ClaudeDeployStrategy(),
|
|
12083
11367
|
codex: () => new CodexDeployStrategy()
|
|
12084
11368
|
};
|
|
12085
|
-
function createAgentStrategy(agent,
|
|
11369
|
+
function createAgentStrategy(agent, os36 = createOsStrategy()) {
|
|
12086
11370
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
12087
11371
|
throw new Error(
|
|
12088
11372
|
`Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
|
|
@@ -12092,10 +11376,10 @@ function createAgentStrategy(agent, os33 = createOsStrategy()) {
|
|
|
12092
11376
|
if (!build) {
|
|
12093
11377
|
throw new Error(`No runtime strategy registered for agent "${agent}"`);
|
|
12094
11378
|
}
|
|
12095
|
-
return build(
|
|
11379
|
+
return build(os36);
|
|
12096
11380
|
}
|
|
12097
|
-
function createInteractiveAgentStrategy(agent,
|
|
12098
|
-
const s = createAgentStrategy(agent,
|
|
11381
|
+
function createInteractiveAgentStrategy(agent, os36 = createOsStrategy()) {
|
|
11382
|
+
const s = createAgentStrategy(agent, os36);
|
|
12099
11383
|
if (s.mode !== "interactive") {
|
|
12100
11384
|
throw new Error(
|
|
12101
11385
|
`Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
|
|
@@ -12172,8 +11456,8 @@ var REGISTRY = {
|
|
|
12172
11456
|
// },
|
|
12173
11457
|
//
|
|
12174
11458
|
// Until then `getAcpAdapter('cursor')` returns null and the dispatch
|
|
12175
|
-
// in start.ts
|
|
12176
|
-
// cursor users had before ACP was added.
|
|
11459
|
+
// in start.ts runs cursor over the legacy PTY runtime — same
|
|
11460
|
+
// behaviour cursor users had before ACP was added.
|
|
12177
11461
|
// Gemini speaks ACP natively via `gemini --acp` — no npm adapter
|
|
12178
11462
|
// package, just the user-installed `gemini` binary on PATH. Same
|
|
12179
11463
|
// {@link AdapterSpec} shape; the only difference is `command` is
|
|
@@ -12196,6 +11480,9 @@ function getAcpAdapter(agent) {
|
|
|
12196
11480
|
const factory = REGISTRY[agent];
|
|
12197
11481
|
return factory ? factory() : null;
|
|
12198
11482
|
}
|
|
11483
|
+
function requiresAcp(agent) {
|
|
11484
|
+
return getAcpAdapter(agent) !== null;
|
|
11485
|
+
}
|
|
12199
11486
|
|
|
12200
11487
|
// src/agents/acp/runner.ts
|
|
12201
11488
|
var import_node_crypto7 = require("crypto");
|
|
@@ -17221,16 +16508,16 @@ async function downloadCloudflared(target) {
|
|
|
17221
16508
|
);
|
|
17222
16509
|
}
|
|
17223
16510
|
function downloadUrlForPlatform() {
|
|
17224
|
-
const
|
|
17225
|
-
const
|
|
16511
|
+
const platform3 = process.platform;
|
|
16512
|
+
const arch2 = process.arch;
|
|
17226
16513
|
const base = "https://github.com/cloudflare/cloudflared/releases/latest/download";
|
|
17227
|
-
if (
|
|
17228
|
-
if (
|
|
17229
|
-
if (
|
|
17230
|
-
if (
|
|
17231
|
-
if (
|
|
16514
|
+
if (platform3 === "darwin" && arch2 === "arm64") return `${base}/cloudflared-darwin-arm64.tgz`;
|
|
16515
|
+
if (platform3 === "darwin" && arch2 === "x64") return `${base}/cloudflared-darwin-amd64.tgz`;
|
|
16516
|
+
if (platform3 === "linux" && arch2 === "x64") return `${base}/cloudflared-linux-amd64`;
|
|
16517
|
+
if (platform3 === "linux" && arch2 === "arm64") return `${base}/cloudflared-linux-arm64`;
|
|
16518
|
+
if (platform3 === "win32") return `${base}/cloudflared-windows-amd64.exe`;
|
|
17232
16519
|
throw new Error(
|
|
17233
|
-
`cloudflared auto-install not supported on ${
|
|
16520
|
+
`cloudflared auto-install not supported on ${platform3}/${arch2}. Install manually from https://github.com/cloudflare/cloudflared/releases.`
|
|
17234
16521
|
);
|
|
17235
16522
|
}
|
|
17236
16523
|
|
|
@@ -17389,7 +16676,7 @@ function parseExpoUrl(stdout) {
|
|
|
17389
16676
|
|
|
17390
16677
|
// src/services/preview/port-ready.ts
|
|
17391
16678
|
var net = __toESM(require("net"));
|
|
17392
|
-
function isPortListening(port,
|
|
16679
|
+
function isPortListening(port, host2 = "127.0.0.1") {
|
|
17393
16680
|
return new Promise((resolve7) => {
|
|
17394
16681
|
const socket = new net.Socket();
|
|
17395
16682
|
const done = (result) => {
|
|
@@ -17401,7 +16688,7 @@ function isPortListening(port, host = "127.0.0.1") {
|
|
|
17401
16688
|
socket.once("connect", () => done(true));
|
|
17402
16689
|
socket.once("timeout", () => done(false));
|
|
17403
16690
|
socket.once("error", () => done(false));
|
|
17404
|
-
socket.connect(port,
|
|
16691
|
+
socket.connect(port, host2);
|
|
17405
16692
|
});
|
|
17406
16693
|
}
|
|
17407
16694
|
async function waitForPortListening(port, opts) {
|
|
@@ -17934,8 +17221,8 @@ var path40 = __toESM(require("path"));
|
|
|
17934
17221
|
var import_child_process14 = require("child_process");
|
|
17935
17222
|
var INSTALL_SH_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh";
|
|
17936
17223
|
var INSTALL_PS1_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/install.ps1";
|
|
17937
|
-
function resolveInstallStrategy(
|
|
17938
|
-
if (
|
|
17224
|
+
function resolveInstallStrategy(platform3) {
|
|
17225
|
+
if (platform3 === "win32") {
|
|
17939
17226
|
return {
|
|
17940
17227
|
command: "powershell.exe",
|
|
17941
17228
|
args: [
|
|
@@ -17978,8 +17265,8 @@ function _defaultInstallSpawn(strategy) {
|
|
|
17978
17265
|
);
|
|
17979
17266
|
});
|
|
17980
17267
|
}
|
|
17981
|
-
async function installBd(
|
|
17982
|
-
const strategy = resolveInstallStrategy(
|
|
17268
|
+
async function installBd(platform3 = process.platform) {
|
|
17269
|
+
const strategy = resolveInstallStrategy(platform3);
|
|
17983
17270
|
log.info("beads", `installing bd via ${strategy.description}`);
|
|
17984
17271
|
const result = await _installSpawnSeam.run(strategy);
|
|
17985
17272
|
if (!result.ok) {
|
|
@@ -17998,8 +17285,8 @@ var os25 = __toESM(require("os"));
|
|
|
17998
17285
|
var path38 = __toESM(require("path"));
|
|
17999
17286
|
var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
|
|
18000
17287
|
var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
|
|
18001
|
-
function resolveDoltInstallStrategy(
|
|
18002
|
-
if (
|
|
17288
|
+
function resolveDoltInstallStrategy(platform3) {
|
|
17289
|
+
if (platform3 === "win32") {
|
|
18003
17290
|
const script = [
|
|
18004
17291
|
`$ErrorActionPreference='Stop';`,
|
|
18005
17292
|
`$u='${DOLT_MSI_URL}';`,
|
|
@@ -18020,7 +17307,7 @@ function resolveDoltInstallStrategy(platform2) {
|
|
|
18020
17307
|
description: "PowerShell: download official dolt MSI + silent msiexec"
|
|
18021
17308
|
};
|
|
18022
17309
|
}
|
|
18023
|
-
if (
|
|
17310
|
+
if (platform3 === "darwin") {
|
|
18024
17311
|
return {
|
|
18025
17312
|
command: "brew",
|
|
18026
17313
|
args: ["install", "dolt"],
|
|
@@ -18034,17 +17321,17 @@ function resolveDoltInstallStrategy(platform2) {
|
|
|
18034
17321
|
};
|
|
18035
17322
|
}
|
|
18036
17323
|
var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
|
|
18037
|
-
function doltPlatformTuple(
|
|
18038
|
-
const
|
|
18039
|
-
const a =
|
|
17324
|
+
function doltPlatformTuple(platform3, arch2) {
|
|
17325
|
+
const os36 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
|
|
17326
|
+
const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
|
|
18040
17327
|
if (!a) return null;
|
|
18041
|
-
if (
|
|
18042
|
-
return `${
|
|
17328
|
+
if (os36 === "windows" && a !== "amd64") return null;
|
|
17329
|
+
return `${os36}-${a}`;
|
|
18043
17330
|
}
|
|
18044
|
-
function resolveDoltTarballStrategy(targetDir,
|
|
18045
|
-
const tuple = doltPlatformTuple(
|
|
17331
|
+
function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
|
|
17332
|
+
const tuple = doltPlatformTuple(platform3, arch2);
|
|
18046
17333
|
if (!tuple) return null;
|
|
18047
|
-
if (
|
|
17334
|
+
if (platform3 === "win32") {
|
|
18048
17335
|
const url2 = `${DOLT_RELEASE_BASE}/dolt-${tuple}.zip`;
|
|
18049
17336
|
const script = [
|
|
18050
17337
|
`$ErrorActionPreference='Stop';`,
|
|
@@ -18070,11 +17357,11 @@ function resolveDoltTarballStrategy(targetDir, platform2, arch) {
|
|
|
18070
17357
|
description: `download dolt ${tuple} tarball \u2192 ${targetDir} (no sudo)`
|
|
18071
17358
|
};
|
|
18072
17359
|
}
|
|
18073
|
-
async function installDoltToDir(targetDir,
|
|
18074
|
-
const strategy = resolveDoltTarballStrategy(targetDir,
|
|
17360
|
+
async function installDoltToDir(targetDir, platform3 = process.platform, arch2 = process.arch) {
|
|
17361
|
+
const strategy = resolveDoltTarballStrategy(targetDir, platform3, arch2);
|
|
18075
17362
|
if (!strategy) {
|
|
18076
|
-
log.warn("beads", `no dolt prebuilt for ${
|
|
18077
|
-
return { ok: false, code: -1, stderr: `unsupported platform ${
|
|
17363
|
+
log.warn("beads", `no dolt prebuilt for ${platform3}/${arch2} \u2014 cannot fall back`);
|
|
17364
|
+
return { ok: false, code: -1, stderr: `unsupported platform ${platform3}/${arch2}` };
|
|
18078
17365
|
}
|
|
18079
17366
|
log.info("beads", `dolt fallback: ${strategy.description}`);
|
|
18080
17367
|
const result = await _doltInstallSpawnSeam.run(strategy);
|
|
@@ -18098,13 +17385,13 @@ var _doltPathSeam = {
|
|
|
18098
17385
|
}
|
|
18099
17386
|
}
|
|
18100
17387
|
};
|
|
18101
|
-
function doltBinaryNames(
|
|
18102
|
-
return
|
|
17388
|
+
function doltBinaryNames(platform3) {
|
|
17389
|
+
return platform3 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
|
|
18103
17390
|
}
|
|
18104
|
-
function knownDoltDirs(
|
|
18105
|
-
const P3 =
|
|
17391
|
+
function knownDoltDirs(platform3) {
|
|
17392
|
+
const P3 = platform3 === "win32" ? path38.win32 : path38.posix;
|
|
18106
17393
|
const home = _doltPathSeam.homedir();
|
|
18107
|
-
if (
|
|
17394
|
+
if (platform3 === "win32") {
|
|
18108
17395
|
return [
|
|
18109
17396
|
"C:\\Program Files\\Dolt\\bin",
|
|
18110
17397
|
home ? P3.join(home, "AppData", "Local", "Programs", "dolt", "bin") : ""
|
|
@@ -18117,17 +17404,17 @@ function knownDoltDirs(platform2) {
|
|
|
18117
17404
|
home ? P3.join(home, "bin") : ""
|
|
18118
17405
|
].filter(Boolean);
|
|
18119
17406
|
}
|
|
18120
|
-
function ensureDoltResolvable(
|
|
18121
|
-
const P3 =
|
|
18122
|
-
const delim =
|
|
18123
|
-
const names = doltBinaryNames(
|
|
17407
|
+
function ensureDoltResolvable(platform3 = process.platform) {
|
|
17408
|
+
const P3 = platform3 === "win32" ? path38.win32 : path38.posix;
|
|
17409
|
+
const delim = platform3 === "win32" ? ";" : ":";
|
|
17410
|
+
const names = doltBinaryNames(platform3);
|
|
18124
17411
|
const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
|
|
18125
17412
|
for (const dir of pathDirs) {
|
|
18126
17413
|
for (const n of names) {
|
|
18127
17414
|
if (_doltPathSeam.exists(P3.join(dir, n))) return true;
|
|
18128
17415
|
}
|
|
18129
17416
|
}
|
|
18130
|
-
for (const dir of knownDoltDirs(
|
|
17417
|
+
for (const dir of knownDoltDirs(platform3)) {
|
|
18131
17418
|
for (const n of names) {
|
|
18132
17419
|
if (_doltPathSeam.exists(P3.join(dir, n))) {
|
|
18133
17420
|
_doltPathSeam.setPath(`${dir}${delim}${_doltPathSeam.getPath()}`);
|
|
@@ -18181,8 +17468,8 @@ function _defaultDoltInstallSpawn(strategy) {
|
|
|
18181
17468
|
proc.on("close", (code) => finish({ ok: code === 0, code: code ?? -1, stderr }));
|
|
18182
17469
|
});
|
|
18183
17470
|
}
|
|
18184
|
-
async function installDolt(
|
|
18185
|
-
const strategy = resolveDoltInstallStrategy(
|
|
17471
|
+
async function installDolt(platform3 = process.platform) {
|
|
17472
|
+
const strategy = resolveDoltInstallStrategy(platform3);
|
|
18186
17473
|
log.info("beads", `installing dolt via ${strategy.description}`);
|
|
18187
17474
|
const result = await _doltInstallSpawnSeam.run(strategy);
|
|
18188
17475
|
if (!result.ok) {
|
|
@@ -18234,11 +17521,11 @@ var path39 = __toESM(require("path"));
|
|
|
18234
17521
|
function normalizeOrigin(raw) {
|
|
18235
17522
|
const trimmed = raw.trim();
|
|
18236
17523
|
if (!trimmed) return null;
|
|
18237
|
-
let
|
|
17524
|
+
let host2;
|
|
18238
17525
|
let pathPart;
|
|
18239
17526
|
const scpLike = /^[^/@]+@([^:]+):(.+)$/.exec(trimmed);
|
|
18240
17527
|
if (scpLike && !trimmed.includes("://")) {
|
|
18241
|
-
|
|
17528
|
+
host2 = scpLike[1];
|
|
18242
17529
|
pathPart = scpLike[2];
|
|
18243
17530
|
} else {
|
|
18244
17531
|
let url;
|
|
@@ -18247,13 +17534,13 @@ function normalizeOrigin(raw) {
|
|
|
18247
17534
|
} catch {
|
|
18248
17535
|
return null;
|
|
18249
17536
|
}
|
|
18250
|
-
|
|
17537
|
+
host2 = url.hostname;
|
|
18251
17538
|
pathPart = url.pathname;
|
|
18252
17539
|
}
|
|
18253
|
-
|
|
17540
|
+
host2 = host2.toLowerCase();
|
|
18254
17541
|
pathPart = pathPart.replace(/^\/+/, "").replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
18255
|
-
if (!
|
|
18256
|
-
return `${
|
|
17542
|
+
if (!host2 || !pathPart) return null;
|
|
17543
|
+
return `${host2}/${pathPart}`;
|
|
18257
17544
|
}
|
|
18258
17545
|
function findRepoRoot(cwd) {
|
|
18259
17546
|
let dir = path39.resolve(cwd);
|
|
@@ -18769,11 +18056,11 @@ var BeadsWatcher = class {
|
|
|
18769
18056
|
|
|
18770
18057
|
// src/beads/inherit-team-memories.ts
|
|
18771
18058
|
async function inheritTeamMemories(opts) {
|
|
18772
|
-
const
|
|
18059
|
+
const apiBase2 = opts.apiBaseUrl ?? resolveApiBaseUrl();
|
|
18773
18060
|
let memories = [];
|
|
18774
18061
|
try {
|
|
18775
18062
|
const res = await _transport3.post(
|
|
18776
|
-
`${
|
|
18063
|
+
`${apiBase2}/api/beads/team-memories`,
|
|
18777
18064
|
{
|
|
18778
18065
|
"Content-Type": "application/json",
|
|
18779
18066
|
"X-Codeam-Protocol-Version": "2.0.0",
|
|
@@ -20153,10 +19440,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
|
|
|
20153
19440
|
/[\\/]Start Menu([\\/]|$)/i,
|
|
20154
19441
|
/[\\/]Templates([\\/]|$)/i
|
|
20155
19442
|
];
|
|
20156
|
-
function isUnsafeWindowsWatchRoot(dir,
|
|
19443
|
+
function isUnsafeWindowsWatchRoot(dir, homedir29) {
|
|
20157
19444
|
const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
|
|
20158
19445
|
const cwd = norm(dir);
|
|
20159
|
-
const home = norm(
|
|
19446
|
+
const home = norm(homedir29);
|
|
20160
19447
|
if (cwd === home) return true;
|
|
20161
19448
|
if (/^[a-z]:$/.test(cwd)) return true;
|
|
20162
19449
|
const sysRoots = [
|
|
@@ -20950,7 +20237,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
20950
20237
|
});
|
|
20951
20238
|
}
|
|
20952
20239
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
20953
|
-
const
|
|
20240
|
+
const fs46 = await import("fs/promises");
|
|
20954
20241
|
const out2 = [];
|
|
20955
20242
|
await walk(workingDir, 0);
|
|
20956
20243
|
return out2;
|
|
@@ -20958,7 +20245,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
20958
20245
|
if (depth > maxDepth) return;
|
|
20959
20246
|
let entries = [];
|
|
20960
20247
|
try {
|
|
20961
|
-
const dirents = await
|
|
20248
|
+
const dirents = await fs46.readdir(dir, { withFileTypes: true });
|
|
20962
20249
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
20963
20250
|
} catch {
|
|
20964
20251
|
return;
|
|
@@ -24041,28 +23328,28 @@ async function start(requestedAgent) {
|
|
|
24041
23328
|
`agent-spawn gate released \u2014 beads ${beads ? "ready" : "pending"}; project deps provisioned`
|
|
24042
23329
|
);
|
|
24043
23330
|
}
|
|
24044
|
-
|
|
24045
|
-
if (!acpDisabled && session.pluginAuthToken) {
|
|
23331
|
+
if (requiresAcp(session.agent)) {
|
|
24046
23332
|
const adapter = getAcpAdapter(session.agent);
|
|
24047
|
-
if (adapter) {
|
|
24048
|
-
|
|
24049
|
-
agent
|
|
24050
|
-
|
|
24051
|
-
|
|
24052
|
-
pluginAuthToken: session.pluginAuthToken,
|
|
24053
|
-
adapter,
|
|
24054
|
-
cwd,
|
|
24055
|
-
getBeads,
|
|
24056
|
-
// AUTO mode in a headless GitHub Codespace: no human at the phone to
|
|
24057
|
-
// answer permission prompts, so auto-approve them rather than stall the
|
|
24058
|
-
// turn (the agent-agnostic equivalent of --dangerously-skip-permissions).
|
|
24059
|
-
autoApprovePermissions: process.env.CODESPACES === "true"
|
|
24060
|
-
});
|
|
24061
|
-
return;
|
|
23333
|
+
if (!adapter || !session.pluginAuthToken) {
|
|
23334
|
+
showError(
|
|
23335
|
+
`${AGENT_REGISTRY[session.agent].displayName} requires a paired session with an auth token. Re-pair with \`codeam pair\` to continue.`
|
|
23336
|
+
);
|
|
23337
|
+
process.exit(1);
|
|
24062
23338
|
}
|
|
24063
|
-
|
|
24064
|
-
|
|
24065
|
-
|
|
23339
|
+
await runAcpSession({
|
|
23340
|
+
agent: session.agent,
|
|
23341
|
+
sessionId: session.id,
|
|
23342
|
+
pluginId,
|
|
23343
|
+
pluginAuthToken: session.pluginAuthToken,
|
|
23344
|
+
adapter,
|
|
23345
|
+
cwd,
|
|
23346
|
+
getBeads,
|
|
23347
|
+
// AUTO mode in a headless GitHub Codespace: no human at the phone to
|
|
23348
|
+
// answer permission prompts, so auto-approve them rather than stall the
|
|
23349
|
+
// turn (the agent-agnostic equivalent of --dangerously-skip-permissions).
|
|
23350
|
+
autoApprovePermissions: process.env.CODESPACES === "true"
|
|
23351
|
+
});
|
|
23352
|
+
return;
|
|
24066
23353
|
}
|
|
24067
23354
|
const runtime = createRuntimeStrategy(session.agent);
|
|
24068
23355
|
const historySvc = new HistoryService(runtime, pluginId, cwd, {
|
|
@@ -24633,12 +23920,12 @@ function readTokenFromArgs(args2) {
|
|
|
24633
23920
|
}
|
|
24634
23921
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
24635
23922
|
if (fileFlag) {
|
|
24636
|
-
const
|
|
23923
|
+
const path58 = fileFlag.slice("--token-file=".length);
|
|
24637
23924
|
try {
|
|
24638
|
-
const content = fs40.readFileSync(
|
|
24639
|
-
if (content.length === 0) fail(`--token-file ${
|
|
23925
|
+
const content = fs40.readFileSync(path58, "utf8").trim();
|
|
23926
|
+
if (content.length === 0) fail(`--token-file ${path58} is empty`);
|
|
24640
23927
|
try {
|
|
24641
|
-
fs40.unlinkSync(
|
|
23928
|
+
fs40.unlinkSync(path58);
|
|
24642
23929
|
} catch {
|
|
24643
23930
|
}
|
|
24644
23931
|
return content;
|
|
@@ -25122,12 +24409,12 @@ var GitHubCodespacesProvider = class {
|
|
|
25122
24409
|
* install error if it's still missing.
|
|
25123
24410
|
*/
|
|
25124
24411
|
async tryInstallGh() {
|
|
25125
|
-
const
|
|
24412
|
+
const platform3 = process.platform;
|
|
25126
24413
|
wt(
|
|
25127
24414
|
`GitHub CLI (${import_picocolors8.default.cyan("gh")}) is required for Codespaces deploys but isn't on your PATH.`,
|
|
25128
24415
|
"Heads up"
|
|
25129
24416
|
);
|
|
25130
|
-
if (
|
|
24417
|
+
if (platform3 === "linux") {
|
|
25131
24418
|
wt(
|
|
25132
24419
|
[
|
|
25133
24420
|
"On Linux, please install gh from the official guide:",
|
|
@@ -25139,7 +24426,7 @@ var GitHubCodespacesProvider = class {
|
|
|
25139
24426
|
return;
|
|
25140
24427
|
}
|
|
25141
24428
|
let installCmd = null;
|
|
25142
|
-
if (
|
|
24429
|
+
if (platform3 === "darwin") {
|
|
25143
24430
|
try {
|
|
25144
24431
|
await execFileP5("brew", ["--version"], { maxBuffer: MAX_BUFFER });
|
|
25145
24432
|
} catch {
|
|
@@ -25158,7 +24445,7 @@ var GitHubCodespacesProvider = class {
|
|
|
25158
24445
|
args: ["install", "gh"],
|
|
25159
24446
|
describe: "brew install gh"
|
|
25160
24447
|
};
|
|
25161
|
-
} else if (
|
|
24448
|
+
} else if (platform3 === "win32") {
|
|
25162
24449
|
try {
|
|
25163
24450
|
await execFileP5("winget", ["--version"], { maxBuffer: MAX_BUFFER });
|
|
25164
24451
|
} catch {
|
|
@@ -26888,50 +26175,488 @@ async function probeCodeamPair(provider, workspace) {
|
|
|
26888
26175
|
}
|
|
26889
26176
|
async function stopWorkspaceFromLocal(target) {
|
|
26890
26177
|
if (target.provider.id === "github-codespaces") {
|
|
26891
|
-
const { execFile:
|
|
26892
|
-
const { promisify:
|
|
26893
|
-
const
|
|
26894
|
-
await
|
|
26178
|
+
const { execFile: execFile10 } = await import("child_process");
|
|
26179
|
+
const { promisify: promisify11 } = await import("util");
|
|
26180
|
+
const execFileP10 = promisify11(execFile10);
|
|
26181
|
+
await execFileP10("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
|
|
26895
26182
|
return;
|
|
26896
26183
|
}
|
|
26897
26184
|
}
|
|
26898
26185
|
|
|
26186
|
+
// src/commands/host/host-client.ts
|
|
26187
|
+
var fs41 = __toESM(require("fs"));
|
|
26188
|
+
var os32 = __toESM(require("os"));
|
|
26189
|
+
var path53 = __toESM(require("path"));
|
|
26190
|
+
function apiBase() {
|
|
26191
|
+
return process.env.CODEAM_API_URL ?? resolveApiBaseUrl();
|
|
26192
|
+
}
|
|
26193
|
+
function hostIdentityPath() {
|
|
26194
|
+
return path53.join(os32.homedir(), ".codeam", "host-agent.json");
|
|
26195
|
+
}
|
|
26196
|
+
function collectOsInfo() {
|
|
26197
|
+
return {
|
|
26198
|
+
distro: os32.platform(),
|
|
26199
|
+
arch: os32.arch(),
|
|
26200
|
+
kernel: os32.release(),
|
|
26201
|
+
nodeVersion: process.versions.node
|
|
26202
|
+
};
|
|
26203
|
+
}
|
|
26204
|
+
function loadHostIdentity() {
|
|
26205
|
+
try {
|
|
26206
|
+
const raw = fs41.readFileSync(hostIdentityPath(), "utf8");
|
|
26207
|
+
const parsed = JSON.parse(raw);
|
|
26208
|
+
if (typeof parsed === "object" && parsed !== null && typeof parsed.hostId === "string" && typeof parsed.hostToken === "string" && typeof parsed.controlPluginId === "string") {
|
|
26209
|
+
const p2 = parsed;
|
|
26210
|
+
return { hostId: p2.hostId, hostToken: p2.hostToken, controlPluginId: p2.controlPluginId };
|
|
26211
|
+
}
|
|
26212
|
+
return null;
|
|
26213
|
+
} catch {
|
|
26214
|
+
return null;
|
|
26215
|
+
}
|
|
26216
|
+
}
|
|
26217
|
+
function saveHostIdentity(identity) {
|
|
26218
|
+
const file = hostIdentityPath();
|
|
26219
|
+
fs41.mkdirSync(path53.dirname(file), { recursive: true, mode: 448 });
|
|
26220
|
+
fs41.writeFileSync(file, JSON.stringify(identity, null, 2), {
|
|
26221
|
+
encoding: "utf8",
|
|
26222
|
+
mode: 384
|
|
26223
|
+
});
|
|
26224
|
+
fs41.chmodSync(file, 384);
|
|
26225
|
+
}
|
|
26226
|
+
async function postJson(pathname, body) {
|
|
26227
|
+
const res = await fetch(`${apiBase()}${pathname}`, {
|
|
26228
|
+
method: "POST",
|
|
26229
|
+
headers: { "Content-Type": "application/json", ...vercelBypassHeader() },
|
|
26230
|
+
body: JSON.stringify(body)
|
|
26231
|
+
});
|
|
26232
|
+
const json = await res.json();
|
|
26233
|
+
if (!res.ok || !json.success) {
|
|
26234
|
+
const err = !json.success ? json.error : void 0;
|
|
26235
|
+
throw new Error(
|
|
26236
|
+
`${pathname} failed (${err?.code ?? `HTTP_${res.status}`}): ${err?.message ?? res.statusText}`
|
|
26237
|
+
);
|
|
26238
|
+
}
|
|
26239
|
+
return json.data;
|
|
26240
|
+
}
|
|
26241
|
+
async function redeemEnrollToken(token, label) {
|
|
26242
|
+
const data = await postJson("/api/self-hosted/redeem", {
|
|
26243
|
+
token,
|
|
26244
|
+
...label ? { label } : {},
|
|
26245
|
+
osInfo: collectOsInfo()
|
|
26246
|
+
});
|
|
26247
|
+
return {
|
|
26248
|
+
hostId: data.hostId,
|
|
26249
|
+
hostToken: data.hostToken,
|
|
26250
|
+
controlPluginId: data.controlPluginId
|
|
26251
|
+
};
|
|
26252
|
+
}
|
|
26253
|
+
async function sendHostHeartbeat(identity) {
|
|
26254
|
+
await postJson("/api/self-hosted/heartbeat", {
|
|
26255
|
+
hostId: identity.hostId,
|
|
26256
|
+
hostToken: identity.hostToken
|
|
26257
|
+
});
|
|
26258
|
+
}
|
|
26259
|
+
function isSealedEnvelope(v) {
|
|
26260
|
+
if (typeof v !== "object" || v === null) return false;
|
|
26261
|
+
const o = v;
|
|
26262
|
+
return typeof o.ciphertext === "string" && typeof o.iv === "string" && typeof o.authTag === "string" && typeof o.keyVersion === "number";
|
|
26263
|
+
}
|
|
26264
|
+
function isAgentAuth(v) {
|
|
26265
|
+
if (typeof v !== "object" || v === null) return false;
|
|
26266
|
+
const o = v;
|
|
26267
|
+
return (o.kind === "oauth_token" || o.kind === "api_key") && typeof o.value === "string";
|
|
26268
|
+
}
|
|
26269
|
+
async function unsealAgentAuth(identity, sealedAgentAuth) {
|
|
26270
|
+
const envelope = JSON.parse(sealedAgentAuth);
|
|
26271
|
+
if (!isSealedEnvelope(envelope)) {
|
|
26272
|
+
throw new Error("sealedAgentAuth is not a valid vault envelope");
|
|
26273
|
+
}
|
|
26274
|
+
const data = await postJson(
|
|
26275
|
+
"/api/self-hosted/unseal-agent-auth",
|
|
26276
|
+
{
|
|
26277
|
+
hostId: identity.hostId,
|
|
26278
|
+
hostToken: identity.hostToken,
|
|
26279
|
+
sealedAgentAuth
|
|
26280
|
+
}
|
|
26281
|
+
);
|
|
26282
|
+
if (!isAgentAuth(data)) {
|
|
26283
|
+
throw new Error("unseal-agent-auth returned an unexpected shape");
|
|
26284
|
+
}
|
|
26285
|
+
return data;
|
|
26286
|
+
}
|
|
26287
|
+
|
|
26288
|
+
// src/commands/host.ts
|
|
26289
|
+
function readTokenFlag(args2) {
|
|
26290
|
+
const flag = args2.find((a) => a.startsWith("--token="));
|
|
26291
|
+
if (!flag) return void 0;
|
|
26292
|
+
const value = flag.slice("--token=".length).trim();
|
|
26293
|
+
return value.length > 0 ? value : void 0;
|
|
26294
|
+
}
|
|
26295
|
+
function readLabelFlag(args2) {
|
|
26296
|
+
const flag = args2.find((a) => a.startsWith("--label="));
|
|
26297
|
+
if (!flag) return void 0;
|
|
26298
|
+
const value = flag.slice("--label=".length).trim();
|
|
26299
|
+
return value.length > 0 ? value : void 0;
|
|
26300
|
+
}
|
|
26301
|
+
async function hostEnroll(args2) {
|
|
26302
|
+
const existing = loadHostIdentity();
|
|
26303
|
+
if (existing) {
|
|
26304
|
+
console.log(
|
|
26305
|
+
` Already enrolled (host ${existing.hostId}). Run \`codeam host-agent\` to connect.`
|
|
26306
|
+
);
|
|
26307
|
+
return;
|
|
26308
|
+
}
|
|
26309
|
+
const token = readTokenFlag(args2);
|
|
26310
|
+
if (!token) {
|
|
26311
|
+
throw new Error(
|
|
26312
|
+
"codeam host enroll requires --token=<EPHEMERAL>. Copy the command from the app."
|
|
26313
|
+
);
|
|
26314
|
+
}
|
|
26315
|
+
const identity = await redeemEnrollToken(token, readLabelFlag(args2));
|
|
26316
|
+
saveHostIdentity(identity);
|
|
26317
|
+
console.log(
|
|
26318
|
+
` Enrolled host ${identity.hostId}. Sealed credentials to ~/.codeam/host-agent.json (0600).`
|
|
26319
|
+
);
|
|
26320
|
+
console.log(" Run `codeam host-agent` (or let systemd start it) to connect.");
|
|
26321
|
+
}
|
|
26322
|
+
async function host(args2) {
|
|
26323
|
+
const sub = args2[0];
|
|
26324
|
+
if (sub === "enroll") {
|
|
26325
|
+
await hostEnroll(args2.slice(1));
|
|
26326
|
+
return;
|
|
26327
|
+
}
|
|
26328
|
+
throw new Error(
|
|
26329
|
+
`Unknown 'codeam host' subcommand: ${sub ?? "(none)"}. Try: codeam host enroll --token=<EPHEMERAL>`
|
|
26330
|
+
);
|
|
26331
|
+
}
|
|
26332
|
+
|
|
26333
|
+
// src/commands/host-agent.ts
|
|
26334
|
+
var import_node_child_process13 = require("child_process");
|
|
26335
|
+
|
|
26336
|
+
// src/commands/host/workspace.ts
|
|
26337
|
+
var fs42 = __toESM(require("fs"));
|
|
26338
|
+
var os33 = __toESM(require("os"));
|
|
26339
|
+
var path54 = __toESM(require("path"));
|
|
26340
|
+
var import_node_child_process12 = require("child_process");
|
|
26341
|
+
var import_node_util4 = require("util");
|
|
26342
|
+
var execFileP9 = (0, import_node_util4.promisify)(import_node_child_process12.execFile);
|
|
26343
|
+
function isAbsolutePathTarget(target) {
|
|
26344
|
+
return path54.isAbsolute(target);
|
|
26345
|
+
}
|
|
26346
|
+
function selfHostedWorkspaceRoot() {
|
|
26347
|
+
return path54.join(os33.homedir(), ".codeam", "self-hosted");
|
|
26348
|
+
}
|
|
26349
|
+
function repoCloneUrl(repoRef) {
|
|
26350
|
+
const trimmed = repoRef.trim();
|
|
26351
|
+
if (/^https?:\/\//.test(trimmed) || trimmed.startsWith("git@")) return trimmed;
|
|
26352
|
+
return `https://github.com/${trimmed.replace(/\.git$/, "")}.git`;
|
|
26353
|
+
}
|
|
26354
|
+
async function prepareWorkspace(repoOrPath, deployId) {
|
|
26355
|
+
if (isAbsolutePathTarget(repoOrPath)) {
|
|
26356
|
+
if (!fs42.existsSync(repoOrPath)) {
|
|
26357
|
+
throw new Error(`deploy target path does not exist: ${repoOrPath}`);
|
|
26358
|
+
}
|
|
26359
|
+
return repoOrPath;
|
|
26360
|
+
}
|
|
26361
|
+
const dest = path54.join(selfHostedWorkspaceRoot(), deployId);
|
|
26362
|
+
if (fs42.existsSync(path54.join(dest, ".git"))) {
|
|
26363
|
+
return dest;
|
|
26364
|
+
}
|
|
26365
|
+
fs42.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
|
|
26366
|
+
await execFileP9("git", ["clone", "--depth", "1", repoCloneUrl(repoOrPath), dest], {
|
|
26367
|
+
timeout: 12e4,
|
|
26368
|
+
maxBuffer: 16 * 1024 * 1024
|
|
26369
|
+
});
|
|
26370
|
+
return dest;
|
|
26371
|
+
}
|
|
26372
|
+
|
|
26373
|
+
// src/commands/host/agent-provisioning.ts
|
|
26374
|
+
var fs43 = __toESM(require("fs"));
|
|
26375
|
+
var os34 = __toESM(require("os"));
|
|
26376
|
+
var path55 = __toESM(require("path"));
|
|
26377
|
+
var PUBLIC_TO_INTERNAL_AGENT = {
|
|
26378
|
+
claude_code: "claude",
|
|
26379
|
+
claude: "claude",
|
|
26380
|
+
codex: "codex",
|
|
26381
|
+
copilot: "copilot",
|
|
26382
|
+
cursor: "cursor",
|
|
26383
|
+
aider: "aider",
|
|
26384
|
+
coderabbit: "coderabbit",
|
|
26385
|
+
gemini: "gemini"
|
|
26386
|
+
};
|
|
26387
|
+
function toInternalAgentId(publicAgentId) {
|
|
26388
|
+
return PUBLIC_TO_INTERNAL_AGENT[publicAgentId] ?? null;
|
|
26389
|
+
}
|
|
26390
|
+
function ensureDir(dir) {
|
|
26391
|
+
fs43.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
26392
|
+
}
|
|
26393
|
+
function writeFile0600(filePath, contents) {
|
|
26394
|
+
ensureDir(path55.dirname(filePath));
|
|
26395
|
+
fs43.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
|
|
26396
|
+
fs43.chmodSync(filePath, 384);
|
|
26397
|
+
}
|
|
26398
|
+
var claudeProvisioner = {
|
|
26399
|
+
write(auth, home) {
|
|
26400
|
+
if (auth.kind === "api_key") {
|
|
26401
|
+
return { ANTHROPIC_API_KEY: auth.value };
|
|
26402
|
+
}
|
|
26403
|
+
writeFile0600(path55.join(home, ".claude", ".credentials.json"), auth.value);
|
|
26404
|
+
const claudeJson = path55.join(home, ".claude.json");
|
|
26405
|
+
if (!fs43.existsSync(claudeJson)) {
|
|
26406
|
+
writeFile0600(
|
|
26407
|
+
claudeJson,
|
|
26408
|
+
JSON.stringify({ hasCompletedOnboarding: true, customApiKeyResponses: { approved: [] } })
|
|
26409
|
+
);
|
|
26410
|
+
}
|
|
26411
|
+
return {};
|
|
26412
|
+
}
|
|
26413
|
+
};
|
|
26414
|
+
var codexProvisioner = {
|
|
26415
|
+
write(auth, home) {
|
|
26416
|
+
if (auth.kind === "api_key") {
|
|
26417
|
+
return { OPENAI_API_KEY: auth.value };
|
|
26418
|
+
}
|
|
26419
|
+
writeFile0600(path55.join(home, ".codex", "auth.json"), auth.value);
|
|
26420
|
+
return {};
|
|
26421
|
+
}
|
|
26422
|
+
};
|
|
26423
|
+
var PROVISIONERS = {
|
|
26424
|
+
claude: claudeProvisioner,
|
|
26425
|
+
codex: codexProvisioner
|
|
26426
|
+
};
|
|
26427
|
+
var UnsupportedAgentError = class extends Error {
|
|
26428
|
+
agentId;
|
|
26429
|
+
constructor(agentId) {
|
|
26430
|
+
super(`Self-hosted provisioning is not implemented for agent "${agentId}"`);
|
|
26431
|
+
this.name = "UnsupportedAgentError";
|
|
26432
|
+
this.agentId = agentId;
|
|
26433
|
+
}
|
|
26434
|
+
};
|
|
26435
|
+
function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os34.homedir()) {
|
|
26436
|
+
const internal = toInternalAgentId(publicAgentId);
|
|
26437
|
+
if (!internal) throw new UnsupportedAgentError(publicAgentId);
|
|
26438
|
+
const provisioner = PROVISIONERS[internal];
|
|
26439
|
+
if (!provisioner) throw new UnsupportedAgentError(publicAgentId);
|
|
26440
|
+
return provisioner.write(auth, homeDir2);
|
|
26441
|
+
}
|
|
26442
|
+
|
|
26443
|
+
// src/commands/host-agent.ts
|
|
26444
|
+
var HEARTBEAT_INTERVAL_MS = 2e4;
|
|
26445
|
+
function isDeployPayload(p2) {
|
|
26446
|
+
return typeof p2.deployId === "string" && typeof p2.repoOrPath === "string" && typeof p2.agentId === "string" && typeof p2.sealedAgentAuth === "string" && typeof p2.autoPairToken === "string";
|
|
26447
|
+
}
|
|
26448
|
+
function isStopPayload(p2) {
|
|
26449
|
+
return typeof p2.sessionId === "string";
|
|
26450
|
+
}
|
|
26451
|
+
var CONTROL_AGENT_META = {
|
|
26452
|
+
id: "claude",
|
|
26453
|
+
displayName: "CodeAgent Host Agent",
|
|
26454
|
+
binaryName: "codeam",
|
|
26455
|
+
enabled: true,
|
|
26456
|
+
supportedAuthKinds: ["oauth_token"],
|
|
26457
|
+
preferredAuthKind: "oauth_token"
|
|
26458
|
+
};
|
|
26459
|
+
var defaultSpawner = (env, cwd) => (0, import_node_child_process13.spawn)(process.execPath, [process.argv[1], "pair-auto"], {
|
|
26460
|
+
cwd,
|
|
26461
|
+
env: { ...process.env, ...env },
|
|
26462
|
+
stdio: "ignore",
|
|
26463
|
+
detached: false
|
|
26464
|
+
});
|
|
26465
|
+
var HostAgentSupervisor = class {
|
|
26466
|
+
constructor(identity, deps = {}) {
|
|
26467
|
+
this.identity = identity;
|
|
26468
|
+
this.deps = deps;
|
|
26469
|
+
this.spawnChild = deps.spawnChild ?? defaultSpawner;
|
|
26470
|
+
this.resolveAgentAuth = deps.resolveAgentAuth ?? unsealAgentAuth;
|
|
26471
|
+
}
|
|
26472
|
+
identity;
|
|
26473
|
+
deps;
|
|
26474
|
+
children = /* @__PURE__ */ new Map();
|
|
26475
|
+
spawnChild;
|
|
26476
|
+
resolveAgentAuth;
|
|
26477
|
+
relay = null;
|
|
26478
|
+
heartbeatTimer = null;
|
|
26479
|
+
/** Open the control channel (reusing the relay) + start heartbeats. */
|
|
26480
|
+
start() {
|
|
26481
|
+
const make = this.deps.makeRelay ?? ((pluginId, onCommand, meta) => new CommandRelayService(pluginId, onCommand, meta));
|
|
26482
|
+
this.relay = make(
|
|
26483
|
+
this.identity.controlPluginId,
|
|
26484
|
+
(cmd) => this.handleCommand(cmd),
|
|
26485
|
+
CONTROL_AGENT_META
|
|
26486
|
+
);
|
|
26487
|
+
this.relay.start();
|
|
26488
|
+
void this.beat();
|
|
26489
|
+
this.heartbeatTimer = setInterval(() => void this.beat(), HEARTBEAT_INTERVAL_MS);
|
|
26490
|
+
this.heartbeatTimer.unref?.();
|
|
26491
|
+
log.info("host-agent", `supervisor up host=${this.identity.hostId.slice(0, 8)}`);
|
|
26492
|
+
}
|
|
26493
|
+
/** Stop the control channel + heartbeats + kill every child. */
|
|
26494
|
+
stop() {
|
|
26495
|
+
if (this.heartbeatTimer) {
|
|
26496
|
+
clearInterval(this.heartbeatTimer);
|
|
26497
|
+
this.heartbeatTimer = null;
|
|
26498
|
+
}
|
|
26499
|
+
this.relay?.stop();
|
|
26500
|
+
for (const child of this.children.values()) {
|
|
26501
|
+
try {
|
|
26502
|
+
child.proc.kill("SIGTERM");
|
|
26503
|
+
} catch {
|
|
26504
|
+
}
|
|
26505
|
+
}
|
|
26506
|
+
this.children.clear();
|
|
26507
|
+
}
|
|
26508
|
+
async beat() {
|
|
26509
|
+
try {
|
|
26510
|
+
await sendHostHeartbeat(this.identity);
|
|
26511
|
+
} catch (err) {
|
|
26512
|
+
log.trace("host-agent", "heartbeat failed", err);
|
|
26513
|
+
}
|
|
26514
|
+
}
|
|
26515
|
+
/** Number of live children — for tests + diagnostics. */
|
|
26516
|
+
childCount() {
|
|
26517
|
+
return this.children.size;
|
|
26518
|
+
}
|
|
26519
|
+
/**
|
|
26520
|
+
* Route a relay command. Only `self_hosted_deploy` / `self_hosted_stop`
|
|
26521
|
+
* are understood; anything else is ignored (the box accepts no
|
|
26522
|
+
* arbitrary command surface).
|
|
26523
|
+
*/
|
|
26524
|
+
async handleCommand(cmd) {
|
|
26525
|
+
if (cmd.type === "self_hosted_deploy") {
|
|
26526
|
+
if (!isDeployPayload(cmd.payload)) {
|
|
26527
|
+
log.warn("host-agent", `ignoring malformed self_hosted_deploy id=${cmd.id}`);
|
|
26528
|
+
return;
|
|
26529
|
+
}
|
|
26530
|
+
await this.deploy(cmd.payload);
|
|
26531
|
+
return;
|
|
26532
|
+
}
|
|
26533
|
+
if (cmd.type === "self_hosted_stop") {
|
|
26534
|
+
if (!isStopPayload(cmd.payload)) {
|
|
26535
|
+
log.warn("host-agent", `ignoring malformed self_hosted_stop id=${cmd.id}`);
|
|
26536
|
+
return;
|
|
26537
|
+
}
|
|
26538
|
+
this.stopChild(cmd.payload.sessionId);
|
|
26539
|
+
return;
|
|
26540
|
+
}
|
|
26541
|
+
log.trace("host-agent", `ignoring unsupported command type=${cmd.type}`);
|
|
26542
|
+
}
|
|
26543
|
+
/**
|
|
26544
|
+
* Prepare the workspace, write the agent credential (same as codespace
|
|
26545
|
+
* provisioning), and spawn a supervised `codeam pair-auto` child.
|
|
26546
|
+
*
|
|
26547
|
+
* The child claims its session via `CODEAM_AUTO_TOKEN`; the backend's
|
|
26548
|
+
* claim response is what binds the sessionId on the server side. We key
|
|
26549
|
+
* the child by `deployId` immediately (and adopt the sessionId — which
|
|
26550
|
+
* for self-hosted equals the deployId-correlated session) so a
|
|
26551
|
+
* subsequent `self_hosted_stop` can find it.
|
|
26552
|
+
*/
|
|
26553
|
+
async deploy(payload) {
|
|
26554
|
+
log.info(
|
|
26555
|
+
"host-agent",
|
|
26556
|
+
`deploy id=${payload.deployId.slice(0, 8)} agent=${payload.agentId} target=${payload.repoOrPath}`
|
|
26557
|
+
);
|
|
26558
|
+
const cwd = await prepareWorkspace(payload.repoOrPath, payload.deployId);
|
|
26559
|
+
const auth = await this.resolveAgentAuth(this.identity, payload.sealedAgentAuth);
|
|
26560
|
+
const credEnv = provisionAgentCredentials(payload.agentId, auth, void 0);
|
|
26561
|
+
const childEnv = {
|
|
26562
|
+
...credEnv,
|
|
26563
|
+
CODEAM_AUTO_TOKEN: payload.autoPairToken
|
|
26564
|
+
};
|
|
26565
|
+
const proc = this.spawnChild(childEnv, cwd);
|
|
26566
|
+
const child = { deployId: payload.deployId, sessionId: payload.deployId, proc };
|
|
26567
|
+
this.children.set(payload.deployId, child);
|
|
26568
|
+
proc.once("exit", () => {
|
|
26569
|
+
if (this.children.get(payload.deployId)?.proc === proc) {
|
|
26570
|
+
this.children.delete(payload.deployId);
|
|
26571
|
+
}
|
|
26572
|
+
});
|
|
26573
|
+
}
|
|
26574
|
+
/** Kill the child matching `sessionId` (or its deployId). No-op if absent. */
|
|
26575
|
+
stopChild(sessionId) {
|
|
26576
|
+
const child = this.children.get(sessionId) ?? this.findBySessionId(sessionId);
|
|
26577
|
+
if (!child) {
|
|
26578
|
+
log.trace("host-agent", `stop: no child for sessionId=${sessionId}`);
|
|
26579
|
+
return;
|
|
26580
|
+
}
|
|
26581
|
+
log.info("host-agent", `stopping child deploy=${child.deployId.slice(0, 8)}`);
|
|
26582
|
+
try {
|
|
26583
|
+
child.proc.kill("SIGTERM");
|
|
26584
|
+
} catch {
|
|
26585
|
+
}
|
|
26586
|
+
this.children.delete(child.deployId);
|
|
26587
|
+
}
|
|
26588
|
+
findBySessionId(sessionId) {
|
|
26589
|
+
for (const child of this.children.values()) {
|
|
26590
|
+
if (child.sessionId === sessionId) return child;
|
|
26591
|
+
}
|
|
26592
|
+
return void 0;
|
|
26593
|
+
}
|
|
26594
|
+
};
|
|
26595
|
+
async function resolveHostIdentity(enrollToken) {
|
|
26596
|
+
const existing = loadHostIdentity();
|
|
26597
|
+
if (existing) return existing;
|
|
26598
|
+
if (!enrollToken) return null;
|
|
26599
|
+
const identity = await redeemEnrollToken(enrollToken);
|
|
26600
|
+
saveHostIdentity(identity);
|
|
26601
|
+
return identity;
|
|
26602
|
+
}
|
|
26603
|
+
async function hostAgent(args2 = []) {
|
|
26604
|
+
const tokenArg = args2.find((a) => a.startsWith("--token="));
|
|
26605
|
+
const enrollToken = (tokenArg ? tokenArg.slice("--token=".length).trim() : "") || process.env.CODEAM_ENROLL_TOKEN || void 0;
|
|
26606
|
+
const identity = await resolveHostIdentity(enrollToken);
|
|
26607
|
+
if (!identity) {
|
|
26608
|
+
throw new Error(
|
|
26609
|
+
"host-agent: no sealed host identity and no enroll token. Re-run the installer from the app (tokens expire after 15 min)."
|
|
26610
|
+
);
|
|
26611
|
+
}
|
|
26612
|
+
const supervisor = new HostAgentSupervisor(identity);
|
|
26613
|
+
supervisor.start();
|
|
26614
|
+
const shutdown = () => {
|
|
26615
|
+
supervisor.stop();
|
|
26616
|
+
process.exit(0);
|
|
26617
|
+
};
|
|
26618
|
+
process.once("SIGINT", shutdown);
|
|
26619
|
+
process.once("SIGTERM", shutdown);
|
|
26620
|
+
await new Promise(() => {
|
|
26621
|
+
});
|
|
26622
|
+
}
|
|
26623
|
+
|
|
26899
26624
|
// src/commands/doctor.ts
|
|
26900
26625
|
var import_node_dns = require("dns");
|
|
26901
|
-
var
|
|
26626
|
+
var import_node_util5 = require("util");
|
|
26902
26627
|
var import_node_crypto8 = require("crypto");
|
|
26903
|
-
var
|
|
26904
|
-
var
|
|
26628
|
+
var fs44 = __toESM(require("fs"));
|
|
26629
|
+
var path56 = __toESM(require("path"));
|
|
26905
26630
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
26906
|
-
var dnsResolveP = (0,
|
|
26907
|
-
async function checkDns(
|
|
26908
|
-
const
|
|
26631
|
+
var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
|
|
26632
|
+
async function checkDns(apiBase2) {
|
|
26633
|
+
const host2 = (() => {
|
|
26909
26634
|
try {
|
|
26910
|
-
return new URL(
|
|
26635
|
+
return new URL(apiBase2).host;
|
|
26911
26636
|
} catch {
|
|
26912
|
-
return
|
|
26637
|
+
return apiBase2;
|
|
26913
26638
|
}
|
|
26914
26639
|
})();
|
|
26915
26640
|
try {
|
|
26916
|
-
const addrs = await dnsResolveP(
|
|
26641
|
+
const addrs = await dnsResolveP(host2);
|
|
26917
26642
|
return {
|
|
26918
26643
|
id: "dns",
|
|
26919
|
-
label: `DNS resolves ${
|
|
26644
|
+
label: `DNS resolves ${host2}`,
|
|
26920
26645
|
ok: true,
|
|
26921
26646
|
detail: `${addrs.length} record(s)`
|
|
26922
26647
|
};
|
|
26923
26648
|
} catch (err) {
|
|
26924
26649
|
return {
|
|
26925
26650
|
id: "dns",
|
|
26926
|
-
label: `DNS resolves ${
|
|
26651
|
+
label: `DNS resolves ${host2}`,
|
|
26927
26652
|
ok: false,
|
|
26928
26653
|
detail: err.message,
|
|
26929
26654
|
hint: "Check your network connection / DNS configuration. The backend host MUST resolve before `codeam pair` can succeed."
|
|
26930
26655
|
};
|
|
26931
26656
|
}
|
|
26932
26657
|
}
|
|
26933
|
-
async function checkHealth(
|
|
26934
|
-
const url = `${
|
|
26658
|
+
async function checkHealth(apiBase2) {
|
|
26659
|
+
const url = `${apiBase2}/health`;
|
|
26935
26660
|
const controller = new AbortController();
|
|
26936
26661
|
const timer = setTimeout(() => controller.abort(), 5e3);
|
|
26937
26662
|
try {
|
|
@@ -26957,13 +26682,13 @@ async function checkHealth(apiBase) {
|
|
|
26957
26682
|
}
|
|
26958
26683
|
}
|
|
26959
26684
|
function checkConfigDir() {
|
|
26960
|
-
const dir =
|
|
26685
|
+
const dir = path56.join(require("os").homedir(), ".codeam");
|
|
26961
26686
|
try {
|
|
26962
|
-
|
|
26963
|
-
const probe =
|
|
26964
|
-
|
|
26965
|
-
const read =
|
|
26966
|
-
|
|
26687
|
+
fs44.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
26688
|
+
const probe = path56.join(dir, ".doctor-probe");
|
|
26689
|
+
fs44.writeFileSync(probe, "ok", { mode: 384 });
|
|
26690
|
+
const read = fs44.readFileSync(probe, "utf8");
|
|
26691
|
+
fs44.unlinkSync(probe);
|
|
26967
26692
|
if (read !== "ok") throw new Error("write/read round-trip mismatch");
|
|
26968
26693
|
return {
|
|
26969
26694
|
id: "config-dir",
|
|
@@ -27003,9 +26728,9 @@ function checkSessions() {
|
|
|
27003
26728
|
}
|
|
27004
26729
|
}
|
|
27005
26730
|
function checkAgentBinaries() {
|
|
27006
|
-
const
|
|
26731
|
+
const os36 = createOsStrategy();
|
|
27007
26732
|
return getEnabledAgents().map((meta) => {
|
|
27008
|
-
const found =
|
|
26733
|
+
const found = os36.findInPath(meta.binaryName);
|
|
27009
26734
|
return {
|
|
27010
26735
|
id: `agent-${meta.id}`,
|
|
27011
26736
|
label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
|
|
@@ -27027,7 +26752,7 @@ function checkNodePty() {
|
|
|
27027
26752
|
detail: "not required on this platform"
|
|
27028
26753
|
};
|
|
27029
26754
|
}
|
|
27030
|
-
const vendoredPath =
|
|
26755
|
+
const vendoredPath = path56.join(__dirname, "vendor", "node-pty");
|
|
27031
26756
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
27032
26757
|
try {
|
|
27033
26758
|
require(target);
|
|
@@ -27069,13 +26794,13 @@ function checkChokidar() {
|
|
|
27069
26794
|
}
|
|
27070
26795
|
async function doctor(args2 = []) {
|
|
27071
26796
|
const json = args2.includes("--json");
|
|
27072
|
-
const cliVersion = true ? "2.39.
|
|
27073
|
-
const
|
|
26797
|
+
const cliVersion = true ? "2.39.25" : "0.0.0-dev";
|
|
26798
|
+
const apiBase2 = resolveApiBaseUrl();
|
|
27074
26799
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
27075
26800
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
27076
26801
|
const [dns2, health] = await Promise.all([
|
|
27077
|
-
checkDns(
|
|
27078
|
-
checkHealth(
|
|
26802
|
+
checkDns(apiBase2),
|
|
26803
|
+
checkHealth(apiBase2)
|
|
27079
26804
|
]);
|
|
27080
26805
|
const checks = [
|
|
27081
26806
|
dns2,
|
|
@@ -27092,7 +26817,7 @@ async function doctor(args2 = []) {
|
|
|
27092
26817
|
node: process.version,
|
|
27093
26818
|
platform: process.platform,
|
|
27094
26819
|
arch: process.arch,
|
|
27095
|
-
apiBase,
|
|
26820
|
+
apiBase: apiBase2,
|
|
27096
26821
|
checks,
|
|
27097
26822
|
// Optional checks (e.g. agent-binary probes) report status but
|
|
27098
26823
|
// don't gate exit code — see CheckResult.optional.
|
|
@@ -27268,7 +26993,7 @@ async function completion(args2) {
|
|
|
27268
26993
|
// src/commands/version.ts
|
|
27269
26994
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
27270
26995
|
function version2() {
|
|
27271
|
-
const v = true ? "2.39.
|
|
26996
|
+
const v = true ? "2.39.25" : "unknown";
|
|
27272
26997
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
27273
26998
|
}
|
|
27274
26999
|
|
|
@@ -27396,23 +27121,23 @@ function tryShowSubcommandHelp(cmd, args2) {
|
|
|
27396
27121
|
var _subcommandHelpKeys = Object.keys(HELPS);
|
|
27397
27122
|
|
|
27398
27123
|
// src/lib/updateNotifier.ts
|
|
27399
|
-
var
|
|
27400
|
-
var
|
|
27401
|
-
var
|
|
27124
|
+
var fs45 = __toESM(require("fs"));
|
|
27125
|
+
var os35 = __toESM(require("os"));
|
|
27126
|
+
var path57 = __toESM(require("path"));
|
|
27402
27127
|
var https8 = __toESM(require("https"));
|
|
27403
|
-
var
|
|
27128
|
+
var import_node_child_process14 = require("child_process");
|
|
27404
27129
|
var import_picocolors16 = __toESM(require("picocolors"));
|
|
27405
27130
|
var PKG_NAME = "codeam-cli";
|
|
27406
27131
|
var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
27407
27132
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
27408
27133
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
27409
27134
|
function cachePath() {
|
|
27410
|
-
const dir =
|
|
27411
|
-
return
|
|
27135
|
+
const dir = path57.join(os35.homedir(), ".codeam");
|
|
27136
|
+
return path57.join(dir, "update-check.json");
|
|
27412
27137
|
}
|
|
27413
27138
|
function readCache() {
|
|
27414
27139
|
try {
|
|
27415
|
-
const raw =
|
|
27140
|
+
const raw = fs45.readFileSync(cachePath(), "utf8");
|
|
27416
27141
|
const parsed = JSON.parse(raw);
|
|
27417
27142
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
27418
27143
|
return parsed;
|
|
@@ -27423,10 +27148,10 @@ function readCache() {
|
|
|
27423
27148
|
function writeCache(cache) {
|
|
27424
27149
|
try {
|
|
27425
27150
|
const file = cachePath();
|
|
27426
|
-
|
|
27151
|
+
fs45.mkdirSync(path57.dirname(file), { recursive: true });
|
|
27427
27152
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
27428
|
-
|
|
27429
|
-
|
|
27153
|
+
fs45.writeFileSync(tmp, JSON.stringify(cache));
|
|
27154
|
+
fs45.renameSync(tmp, file);
|
|
27430
27155
|
} catch {
|
|
27431
27156
|
}
|
|
27432
27157
|
}
|
|
@@ -27494,14 +27219,14 @@ function notifyIfStale(currentVersion, latest) {
|
|
|
27494
27219
|
}
|
|
27495
27220
|
function isLinkedInstall() {
|
|
27496
27221
|
try {
|
|
27497
|
-
const root = (0,
|
|
27222
|
+
const root = (0, import_node_child_process14.execSync)("npm root -g", {
|
|
27498
27223
|
encoding: "utf8",
|
|
27499
27224
|
stdio: ["ignore", "pipe", "ignore"],
|
|
27500
27225
|
timeout: 2e3
|
|
27501
27226
|
}).trim();
|
|
27502
27227
|
if (!root) return false;
|
|
27503
|
-
const pkgPath =
|
|
27504
|
-
return
|
|
27228
|
+
const pkgPath = path57.join(root, PKG_NAME);
|
|
27229
|
+
return fs45.lstatSync(pkgPath).isSymbolicLink();
|
|
27505
27230
|
} catch {
|
|
27506
27231
|
return false;
|
|
27507
27232
|
}
|
|
@@ -27522,7 +27247,7 @@ function maybeAutoUpdate(currentVersion, latest) {
|
|
|
27522
27247
|
|
|
27523
27248
|
`
|
|
27524
27249
|
);
|
|
27525
|
-
const install = (0,
|
|
27250
|
+
const install = (0, import_node_child_process14.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
|
|
27526
27251
|
stdio: "inherit",
|
|
27527
27252
|
env: process.env
|
|
27528
27253
|
});
|
|
@@ -27537,13 +27262,13 @@ function maybeAutoUpdate(currentVersion, latest) {
|
|
|
27537
27262
|
return;
|
|
27538
27263
|
}
|
|
27539
27264
|
try {
|
|
27540
|
-
|
|
27265
|
+
fs45.unlinkSync(cachePath());
|
|
27541
27266
|
} catch {
|
|
27542
27267
|
}
|
|
27543
27268
|
process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
|
|
27544
27269
|
|
|
27545
27270
|
`);
|
|
27546
|
-
const child = (0,
|
|
27271
|
+
const child = (0, import_node_child_process14.spawnSync)("codeam", process.argv.slice(2), {
|
|
27547
27272
|
stdio: "inherit",
|
|
27548
27273
|
env: process.env
|
|
27549
27274
|
});
|
|
@@ -27554,7 +27279,7 @@ function checkForUpdates() {
|
|
|
27554
27279
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
27555
27280
|
if (process.env.CI) return;
|
|
27556
27281
|
if (!process.stdout.isTTY) return;
|
|
27557
|
-
const current = true ? "2.39.
|
|
27282
|
+
const current = true ? "2.39.25" : null;
|
|
27558
27283
|
if (!current) return;
|
|
27559
27284
|
const cache = readCache();
|
|
27560
27285
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -27599,6 +27324,8 @@ async function main() {
|
|
|
27599
27324
|
const commands = {
|
|
27600
27325
|
"pair": () => pair(args),
|
|
27601
27326
|
"pair-auto": () => pairAuto(args),
|
|
27327
|
+
"host-agent": () => hostAgent(args),
|
|
27328
|
+
"host": () => host(args),
|
|
27602
27329
|
"sessions": () => sessions2(args),
|
|
27603
27330
|
"status": () => status(),
|
|
27604
27331
|
"logout": () => logout(),
|