codeam-cli 2.39.24 → 2.39.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +24 -2
- package/dist/index.js +640 -200
- 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.26",
|
|
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.26" : "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
|
|
@@ -9754,8 +9754,8 @@ var ClaudeRuntimeStrategy = class {
|
|
|
9754
9754
|
meta = getAgent("claude");
|
|
9755
9755
|
mode = "interactive";
|
|
9756
9756
|
os;
|
|
9757
|
-
constructor(
|
|
9758
|
-
this.os =
|
|
9757
|
+
constructor(os36) {
|
|
9758
|
+
this.os = os36;
|
|
9759
9759
|
}
|
|
9760
9760
|
/**
|
|
9761
9761
|
* Claude Code's react-ink TUI enables bracketed-paste mode at
|
|
@@ -10374,8 +10374,8 @@ function codexCredentialLocator() {
|
|
|
10374
10374
|
function codexLoginLauncher() {
|
|
10375
10375
|
return {
|
|
10376
10376
|
async ensureInstalled() {
|
|
10377
|
-
const
|
|
10378
|
-
return
|
|
10377
|
+
const os36 = createOsStrategy();
|
|
10378
|
+
return os36.findInPath("codex") !== null;
|
|
10379
10379
|
},
|
|
10380
10380
|
launch() {
|
|
10381
10381
|
return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
@@ -10398,8 +10398,8 @@ var CodexRuntimeStrategy = class {
|
|
|
10398
10398
|
meta = getAgent("codex");
|
|
10399
10399
|
mode = "interactive";
|
|
10400
10400
|
os;
|
|
10401
|
-
constructor(
|
|
10402
|
-
this.os =
|
|
10401
|
+
constructor(os36) {
|
|
10402
|
+
this.os = os36;
|
|
10403
10403
|
}
|
|
10404
10404
|
async prepareLaunch() {
|
|
10405
10405
|
let binary = this.os.findInPath("codex");
|
|
@@ -10495,12 +10495,12 @@ var CodexRuntimeStrategy = class {
|
|
|
10495
10495
|
});
|
|
10496
10496
|
}
|
|
10497
10497
|
};
|
|
10498
|
-
function resolveNpm(
|
|
10499
|
-
return
|
|
10498
|
+
function resolveNpm(os36) {
|
|
10499
|
+
return os36.id === "win32" ? "npm.cmd" : "npm";
|
|
10500
10500
|
}
|
|
10501
|
-
async function installCodexViaNpm(
|
|
10501
|
+
async function installCodexViaNpm(os36) {
|
|
10502
10502
|
return new Promise((resolve7, reject) => {
|
|
10503
|
-
const proc = (0, import_node_child_process4.spawn)(resolveNpm(
|
|
10503
|
+
const proc = (0, import_node_child_process4.spawn)(resolveNpm(os36), ["install", "-g", "@openai/codex"], {
|
|
10504
10504
|
stdio: "inherit"
|
|
10505
10505
|
});
|
|
10506
10506
|
proc.on("close", (code) => {
|
|
@@ -10517,16 +10517,16 @@ async function installCodexViaNpm(os33) {
|
|
|
10517
10517
|
});
|
|
10518
10518
|
});
|
|
10519
10519
|
}
|
|
10520
|
-
function augmentNpmGlobalBin(
|
|
10520
|
+
function augmentNpmGlobalBin(os36) {
|
|
10521
10521
|
try {
|
|
10522
|
-
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(
|
|
10522
|
+
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os36), ["prefix", "-g"], {
|
|
10523
10523
|
stdio: ["ignore", "pipe", "ignore"]
|
|
10524
10524
|
});
|
|
10525
10525
|
if (result.status !== 0) return;
|
|
10526
10526
|
const prefix = result.stdout.toString().trim();
|
|
10527
10527
|
if (!prefix) return;
|
|
10528
|
-
const binDir =
|
|
10529
|
-
|
|
10528
|
+
const binDir = os36.id === "win32" ? prefix : path17.join(prefix, "bin");
|
|
10529
|
+
os36.augmentPath([binDir]);
|
|
10530
10530
|
} catch {
|
|
10531
10531
|
}
|
|
10532
10532
|
}
|
|
@@ -10610,9 +10610,9 @@ var import_node_child_process7 = require("child_process");
|
|
|
10610
10610
|
// src/agents/coderabbit/installer.ts
|
|
10611
10611
|
var import_node_child_process5 = require("child_process");
|
|
10612
10612
|
var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
|
|
10613
|
-
async function ensureCoderabbitInstalled(
|
|
10614
|
-
if (
|
|
10615
|
-
if (
|
|
10613
|
+
async function ensureCoderabbitInstalled(os36) {
|
|
10614
|
+
if (os36.findInPath("coderabbit")) return true;
|
|
10615
|
+
if (os36.id === "win32") {
|
|
10616
10616
|
console.error(
|
|
10617
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"
|
|
10618
10618
|
);
|
|
@@ -10627,8 +10627,8 @@ async function ensureCoderabbitInstalled(os33) {
|
|
|
10627
10627
|
proc.on("error", () => resolve7(false));
|
|
10628
10628
|
});
|
|
10629
10629
|
if (!ok) return false;
|
|
10630
|
-
|
|
10631
|
-
return
|
|
10630
|
+
os36.augmentPath([`${os36.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
10631
|
+
return os36.findInPath("coderabbit") !== null;
|
|
10632
10632
|
}
|
|
10633
10633
|
|
|
10634
10634
|
// src/agents/coderabbit/link.ts
|
|
@@ -10655,10 +10655,10 @@ function coderabbitCredentialLocator() {
|
|
|
10655
10655
|
extract: extractLocalCoderabbitToken
|
|
10656
10656
|
};
|
|
10657
10657
|
}
|
|
10658
|
-
function coderabbitLoginLauncher(
|
|
10658
|
+
function coderabbitLoginLauncher(os36) {
|
|
10659
10659
|
return {
|
|
10660
10660
|
async ensureInstalled() {
|
|
10661
|
-
return ensureCoderabbitInstalled(
|
|
10661
|
+
return ensureCoderabbitInstalled(os36);
|
|
10662
10662
|
},
|
|
10663
10663
|
launch() {
|
|
10664
10664
|
return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
|
|
@@ -10681,11 +10681,11 @@ function parseReview(stdout) {
|
|
|
10681
10681
|
for (const line of lines) {
|
|
10682
10682
|
const m = line.match(HUNK_LINE_RE);
|
|
10683
10683
|
if (!m) continue;
|
|
10684
|
-
const [,
|
|
10685
|
-
if (!
|
|
10684
|
+
const [, path58, lineNo, sevToken, message] = m;
|
|
10685
|
+
if (!path58 || !lineNo || !message) continue;
|
|
10686
10686
|
const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
|
|
10687
10687
|
hunks.push({
|
|
10688
|
-
path:
|
|
10688
|
+
path: path58.trim(),
|
|
10689
10689
|
line: Number(lineNo),
|
|
10690
10690
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
10691
10691
|
message: cleanedMessage
|
|
@@ -10704,8 +10704,8 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
10704
10704
|
meta = getAgent("coderabbit");
|
|
10705
10705
|
mode = "batch";
|
|
10706
10706
|
os;
|
|
10707
|
-
constructor(
|
|
10708
|
-
this.os =
|
|
10707
|
+
constructor(os36) {
|
|
10708
|
+
this.os = os36;
|
|
10709
10709
|
}
|
|
10710
10710
|
getDefaultArgs() {
|
|
10711
10711
|
return ["review"];
|
|
@@ -10820,10 +10820,10 @@ function cursorCredentialLocator() {
|
|
|
10820
10820
|
extract: extractLocalCursorToken
|
|
10821
10821
|
};
|
|
10822
10822
|
}
|
|
10823
|
-
function cursorLoginLauncher(
|
|
10823
|
+
function cursorLoginLauncher(os36) {
|
|
10824
10824
|
return {
|
|
10825
10825
|
async ensureInstalled() {
|
|
10826
|
-
if (
|
|
10826
|
+
if (os36.findInPath("cursor-agent")) return true;
|
|
10827
10827
|
console.error(
|
|
10828
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"
|
|
10829
10829
|
);
|
|
@@ -10885,8 +10885,8 @@ var CursorRuntimeStrategy = class {
|
|
|
10885
10885
|
meta = getAgent("cursor");
|
|
10886
10886
|
mode = "interactive";
|
|
10887
10887
|
os;
|
|
10888
|
-
constructor(
|
|
10889
|
-
this.os =
|
|
10888
|
+
constructor(os36) {
|
|
10889
|
+
this.os = os36;
|
|
10890
10890
|
}
|
|
10891
10891
|
async prepareLaunch() {
|
|
10892
10892
|
const binary = this.os.findInPath("cursor-agent");
|
|
@@ -11006,10 +11006,10 @@ function aiderCredentialLocator() {
|
|
|
11006
11006
|
extract: extractLocalAiderToken
|
|
11007
11007
|
};
|
|
11008
11008
|
}
|
|
11009
|
-
function aiderLoginLauncher(
|
|
11009
|
+
function aiderLoginLauncher(os36) {
|
|
11010
11010
|
return {
|
|
11011
11011
|
async ensureInstalled() {
|
|
11012
|
-
if (
|
|
11012
|
+
if (os36.findInPath("aider")) return true;
|
|
11013
11013
|
console.error(
|
|
11014
11014
|
"\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
|
|
11015
11015
|
);
|
|
@@ -11019,7 +11019,7 @@ function aiderLoginLauncher(os33) {
|
|
|
11019
11019
|
console.error(
|
|
11020
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"
|
|
11021
11021
|
);
|
|
11022
|
-
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"], {
|
|
11023
11023
|
stdio: "ignore"
|
|
11024
11024
|
});
|
|
11025
11025
|
}
|
|
@@ -11091,8 +11091,8 @@ var AiderRuntimeStrategy = class {
|
|
|
11091
11091
|
meta = getAgent("aider");
|
|
11092
11092
|
mode = "interactive";
|
|
11093
11093
|
os;
|
|
11094
|
-
constructor(
|
|
11095
|
-
this.os =
|
|
11094
|
+
constructor(os36) {
|
|
11095
|
+
this.os = os36;
|
|
11096
11096
|
}
|
|
11097
11097
|
async prepareLaunch() {
|
|
11098
11098
|
const binary = this.os.findInPath("aider");
|
|
@@ -11221,8 +11221,8 @@ function geminiCredentialLocator() {
|
|
|
11221
11221
|
function geminiLoginLauncher() {
|
|
11222
11222
|
return {
|
|
11223
11223
|
async ensureInstalled() {
|
|
11224
|
-
const
|
|
11225
|
-
return
|
|
11224
|
+
const os36 = createOsStrategy();
|
|
11225
|
+
return os36.findInPath("gemini") !== null;
|
|
11226
11226
|
},
|
|
11227
11227
|
launch() {
|
|
11228
11228
|
return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
|
|
@@ -11255,8 +11255,8 @@ var GeminiRuntimeStrategy = class {
|
|
|
11255
11255
|
meta = getAgent("gemini");
|
|
11256
11256
|
mode = "interactive";
|
|
11257
11257
|
os;
|
|
11258
|
-
constructor(
|
|
11259
|
-
this.os =
|
|
11258
|
+
constructor(os36) {
|
|
11259
|
+
this.os = os36;
|
|
11260
11260
|
}
|
|
11261
11261
|
async prepareLaunch() {
|
|
11262
11262
|
const binary = this.os.findInPath("gemini");
|
|
@@ -11355,18 +11355,18 @@ var GeminiRuntimeStrategy = class {
|
|
|
11355
11355
|
|
|
11356
11356
|
// src/agents/registry.ts
|
|
11357
11357
|
var runtimeBuilders = {
|
|
11358
|
-
claude: (
|
|
11359
|
-
codex: (
|
|
11360
|
-
coderabbit: (
|
|
11361
|
-
cursor: (
|
|
11362
|
-
aider: (
|
|
11363
|
-
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)
|
|
11364
11364
|
};
|
|
11365
11365
|
var deployBuilders = {
|
|
11366
11366
|
claude: () => new ClaudeDeployStrategy(),
|
|
11367
11367
|
codex: () => new CodexDeployStrategy()
|
|
11368
11368
|
};
|
|
11369
|
-
function createAgentStrategy(agent,
|
|
11369
|
+
function createAgentStrategy(agent, os36 = createOsStrategy()) {
|
|
11370
11370
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
11371
11371
|
throw new Error(
|
|
11372
11372
|
`Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
|
|
@@ -11376,10 +11376,10 @@ function createAgentStrategy(agent, os33 = createOsStrategy()) {
|
|
|
11376
11376
|
if (!build) {
|
|
11377
11377
|
throw new Error(`No runtime strategy registered for agent "${agent}"`);
|
|
11378
11378
|
}
|
|
11379
|
-
return build(
|
|
11379
|
+
return build(os36);
|
|
11380
11380
|
}
|
|
11381
|
-
function createInteractiveAgentStrategy(agent,
|
|
11382
|
-
const s = createAgentStrategy(agent,
|
|
11381
|
+
function createInteractiveAgentStrategy(agent, os36 = createOsStrategy()) {
|
|
11382
|
+
const s = createAgentStrategy(agent, os36);
|
|
11383
11383
|
if (s.mode !== "interactive") {
|
|
11384
11384
|
throw new Error(
|
|
11385
11385
|
`Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
|
|
@@ -16508,16 +16508,16 @@ async function downloadCloudflared(target) {
|
|
|
16508
16508
|
);
|
|
16509
16509
|
}
|
|
16510
16510
|
function downloadUrlForPlatform() {
|
|
16511
|
-
const
|
|
16512
|
-
const
|
|
16511
|
+
const platform3 = process.platform;
|
|
16512
|
+
const arch2 = process.arch;
|
|
16513
16513
|
const base = "https://github.com/cloudflare/cloudflared/releases/latest/download";
|
|
16514
|
-
if (
|
|
16515
|
-
if (
|
|
16516
|
-
if (
|
|
16517
|
-
if (
|
|
16518
|
-
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`;
|
|
16519
16519
|
throw new Error(
|
|
16520
|
-
`cloudflared auto-install not supported on ${
|
|
16520
|
+
`cloudflared auto-install not supported on ${platform3}/${arch2}. Install manually from https://github.com/cloudflare/cloudflared/releases.`
|
|
16521
16521
|
);
|
|
16522
16522
|
}
|
|
16523
16523
|
|
|
@@ -16676,7 +16676,7 @@ function parseExpoUrl(stdout) {
|
|
|
16676
16676
|
|
|
16677
16677
|
// src/services/preview/port-ready.ts
|
|
16678
16678
|
var net = __toESM(require("net"));
|
|
16679
|
-
function isPortListening(port,
|
|
16679
|
+
function isPortListening(port, host2 = "127.0.0.1") {
|
|
16680
16680
|
return new Promise((resolve7) => {
|
|
16681
16681
|
const socket = new net.Socket();
|
|
16682
16682
|
const done = (result) => {
|
|
@@ -16688,7 +16688,7 @@ function isPortListening(port, host = "127.0.0.1") {
|
|
|
16688
16688
|
socket.once("connect", () => done(true));
|
|
16689
16689
|
socket.once("timeout", () => done(false));
|
|
16690
16690
|
socket.once("error", () => done(false));
|
|
16691
|
-
socket.connect(port,
|
|
16691
|
+
socket.connect(port, host2);
|
|
16692
16692
|
});
|
|
16693
16693
|
}
|
|
16694
16694
|
async function waitForPortListening(port, opts) {
|
|
@@ -17221,8 +17221,8 @@ var path40 = __toESM(require("path"));
|
|
|
17221
17221
|
var import_child_process14 = require("child_process");
|
|
17222
17222
|
var INSTALL_SH_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh";
|
|
17223
17223
|
var INSTALL_PS1_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/install.ps1";
|
|
17224
|
-
function resolveInstallStrategy(
|
|
17225
|
-
if (
|
|
17224
|
+
function resolveInstallStrategy(platform3) {
|
|
17225
|
+
if (platform3 === "win32") {
|
|
17226
17226
|
return {
|
|
17227
17227
|
command: "powershell.exe",
|
|
17228
17228
|
args: [
|
|
@@ -17265,8 +17265,8 @@ function _defaultInstallSpawn(strategy) {
|
|
|
17265
17265
|
);
|
|
17266
17266
|
});
|
|
17267
17267
|
}
|
|
17268
|
-
async function installBd(
|
|
17269
|
-
const strategy = resolveInstallStrategy(
|
|
17268
|
+
async function installBd(platform3 = process.platform) {
|
|
17269
|
+
const strategy = resolveInstallStrategy(platform3);
|
|
17270
17270
|
log.info("beads", `installing bd via ${strategy.description}`);
|
|
17271
17271
|
const result = await _installSpawnSeam.run(strategy);
|
|
17272
17272
|
if (!result.ok) {
|
|
@@ -17285,8 +17285,8 @@ var os25 = __toESM(require("os"));
|
|
|
17285
17285
|
var path38 = __toESM(require("path"));
|
|
17286
17286
|
var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
|
|
17287
17287
|
var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
|
|
17288
|
-
function resolveDoltInstallStrategy(
|
|
17289
|
-
if (
|
|
17288
|
+
function resolveDoltInstallStrategy(platform3) {
|
|
17289
|
+
if (platform3 === "win32") {
|
|
17290
17290
|
const script = [
|
|
17291
17291
|
`$ErrorActionPreference='Stop';`,
|
|
17292
17292
|
`$u='${DOLT_MSI_URL}';`,
|
|
@@ -17307,7 +17307,7 @@ function resolveDoltInstallStrategy(platform2) {
|
|
|
17307
17307
|
description: "PowerShell: download official dolt MSI + silent msiexec"
|
|
17308
17308
|
};
|
|
17309
17309
|
}
|
|
17310
|
-
if (
|
|
17310
|
+
if (platform3 === "darwin") {
|
|
17311
17311
|
return {
|
|
17312
17312
|
command: "brew",
|
|
17313
17313
|
args: ["install", "dolt"],
|
|
@@ -17321,17 +17321,17 @@ function resolveDoltInstallStrategy(platform2) {
|
|
|
17321
17321
|
};
|
|
17322
17322
|
}
|
|
17323
17323
|
var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
|
|
17324
|
-
function doltPlatformTuple(
|
|
17325
|
-
const
|
|
17326
|
-
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;
|
|
17327
17327
|
if (!a) return null;
|
|
17328
|
-
if (
|
|
17329
|
-
return `${
|
|
17328
|
+
if (os36 === "windows" && a !== "amd64") return null;
|
|
17329
|
+
return `${os36}-${a}`;
|
|
17330
17330
|
}
|
|
17331
|
-
function resolveDoltTarballStrategy(targetDir,
|
|
17332
|
-
const tuple = doltPlatformTuple(
|
|
17331
|
+
function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
|
|
17332
|
+
const tuple = doltPlatformTuple(platform3, arch2);
|
|
17333
17333
|
if (!tuple) return null;
|
|
17334
|
-
if (
|
|
17334
|
+
if (platform3 === "win32") {
|
|
17335
17335
|
const url2 = `${DOLT_RELEASE_BASE}/dolt-${tuple}.zip`;
|
|
17336
17336
|
const script = [
|
|
17337
17337
|
`$ErrorActionPreference='Stop';`,
|
|
@@ -17357,11 +17357,11 @@ function resolveDoltTarballStrategy(targetDir, platform2, arch) {
|
|
|
17357
17357
|
description: `download dolt ${tuple} tarball \u2192 ${targetDir} (no sudo)`
|
|
17358
17358
|
};
|
|
17359
17359
|
}
|
|
17360
|
-
async function installDoltToDir(targetDir,
|
|
17361
|
-
const strategy = resolveDoltTarballStrategy(targetDir,
|
|
17360
|
+
async function installDoltToDir(targetDir, platform3 = process.platform, arch2 = process.arch) {
|
|
17361
|
+
const strategy = resolveDoltTarballStrategy(targetDir, platform3, arch2);
|
|
17362
17362
|
if (!strategy) {
|
|
17363
|
-
log.warn("beads", `no dolt prebuilt for ${
|
|
17364
|
-
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}` };
|
|
17365
17365
|
}
|
|
17366
17366
|
log.info("beads", `dolt fallback: ${strategy.description}`);
|
|
17367
17367
|
const result = await _doltInstallSpawnSeam.run(strategy);
|
|
@@ -17385,13 +17385,13 @@ var _doltPathSeam = {
|
|
|
17385
17385
|
}
|
|
17386
17386
|
}
|
|
17387
17387
|
};
|
|
17388
|
-
function doltBinaryNames(
|
|
17389
|
-
return
|
|
17388
|
+
function doltBinaryNames(platform3) {
|
|
17389
|
+
return platform3 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
|
|
17390
17390
|
}
|
|
17391
|
-
function knownDoltDirs(
|
|
17392
|
-
const P3 =
|
|
17391
|
+
function knownDoltDirs(platform3) {
|
|
17392
|
+
const P3 = platform3 === "win32" ? path38.win32 : path38.posix;
|
|
17393
17393
|
const home = _doltPathSeam.homedir();
|
|
17394
|
-
if (
|
|
17394
|
+
if (platform3 === "win32") {
|
|
17395
17395
|
return [
|
|
17396
17396
|
"C:\\Program Files\\Dolt\\bin",
|
|
17397
17397
|
home ? P3.join(home, "AppData", "Local", "Programs", "dolt", "bin") : ""
|
|
@@ -17404,17 +17404,17 @@ function knownDoltDirs(platform2) {
|
|
|
17404
17404
|
home ? P3.join(home, "bin") : ""
|
|
17405
17405
|
].filter(Boolean);
|
|
17406
17406
|
}
|
|
17407
|
-
function ensureDoltResolvable(
|
|
17408
|
-
const P3 =
|
|
17409
|
-
const delim =
|
|
17410
|
-
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);
|
|
17411
17411
|
const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
|
|
17412
17412
|
for (const dir of pathDirs) {
|
|
17413
17413
|
for (const n of names) {
|
|
17414
17414
|
if (_doltPathSeam.exists(P3.join(dir, n))) return true;
|
|
17415
17415
|
}
|
|
17416
17416
|
}
|
|
17417
|
-
for (const dir of knownDoltDirs(
|
|
17417
|
+
for (const dir of knownDoltDirs(platform3)) {
|
|
17418
17418
|
for (const n of names) {
|
|
17419
17419
|
if (_doltPathSeam.exists(P3.join(dir, n))) {
|
|
17420
17420
|
_doltPathSeam.setPath(`${dir}${delim}${_doltPathSeam.getPath()}`);
|
|
@@ -17468,8 +17468,8 @@ function _defaultDoltInstallSpawn(strategy) {
|
|
|
17468
17468
|
proc.on("close", (code) => finish({ ok: code === 0, code: code ?? -1, stderr }));
|
|
17469
17469
|
});
|
|
17470
17470
|
}
|
|
17471
|
-
async function installDolt(
|
|
17472
|
-
const strategy = resolveDoltInstallStrategy(
|
|
17471
|
+
async function installDolt(platform3 = process.platform) {
|
|
17472
|
+
const strategy = resolveDoltInstallStrategy(platform3);
|
|
17473
17473
|
log.info("beads", `installing dolt via ${strategy.description}`);
|
|
17474
17474
|
const result = await _doltInstallSpawnSeam.run(strategy);
|
|
17475
17475
|
if (!result.ok) {
|
|
@@ -17521,11 +17521,11 @@ var path39 = __toESM(require("path"));
|
|
|
17521
17521
|
function normalizeOrigin(raw) {
|
|
17522
17522
|
const trimmed = raw.trim();
|
|
17523
17523
|
if (!trimmed) return null;
|
|
17524
|
-
let
|
|
17524
|
+
let host2;
|
|
17525
17525
|
let pathPart;
|
|
17526
17526
|
const scpLike = /^[^/@]+@([^:]+):(.+)$/.exec(trimmed);
|
|
17527
17527
|
if (scpLike && !trimmed.includes("://")) {
|
|
17528
|
-
|
|
17528
|
+
host2 = scpLike[1];
|
|
17529
17529
|
pathPart = scpLike[2];
|
|
17530
17530
|
} else {
|
|
17531
17531
|
let url;
|
|
@@ -17534,13 +17534,13 @@ function normalizeOrigin(raw) {
|
|
|
17534
17534
|
} catch {
|
|
17535
17535
|
return null;
|
|
17536
17536
|
}
|
|
17537
|
-
|
|
17537
|
+
host2 = url.hostname;
|
|
17538
17538
|
pathPart = url.pathname;
|
|
17539
17539
|
}
|
|
17540
|
-
|
|
17540
|
+
host2 = host2.toLowerCase();
|
|
17541
17541
|
pathPart = pathPart.replace(/^\/+/, "").replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
17542
|
-
if (!
|
|
17543
|
-
return `${
|
|
17542
|
+
if (!host2 || !pathPart) return null;
|
|
17543
|
+
return `${host2}/${pathPart}`;
|
|
17544
17544
|
}
|
|
17545
17545
|
function findRepoRoot(cwd) {
|
|
17546
17546
|
let dir = path39.resolve(cwd);
|
|
@@ -18056,11 +18056,11 @@ var BeadsWatcher = class {
|
|
|
18056
18056
|
|
|
18057
18057
|
// src/beads/inherit-team-memories.ts
|
|
18058
18058
|
async function inheritTeamMemories(opts) {
|
|
18059
|
-
const
|
|
18059
|
+
const apiBase2 = opts.apiBaseUrl ?? resolveApiBaseUrl();
|
|
18060
18060
|
let memories = [];
|
|
18061
18061
|
try {
|
|
18062
18062
|
const res = await _transport3.post(
|
|
18063
|
-
`${
|
|
18063
|
+
`${apiBase2}/api/beads/team-memories`,
|
|
18064
18064
|
{
|
|
18065
18065
|
"Content-Type": "application/json",
|
|
18066
18066
|
"X-Codeam-Protocol-Version": "2.0.0",
|
|
@@ -19440,10 +19440,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
|
|
|
19440
19440
|
/[\\/]Start Menu([\\/]|$)/i,
|
|
19441
19441
|
/[\\/]Templates([\\/]|$)/i
|
|
19442
19442
|
];
|
|
19443
|
-
function isUnsafeWindowsWatchRoot(dir,
|
|
19443
|
+
function isUnsafeWindowsWatchRoot(dir, homedir29) {
|
|
19444
19444
|
const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
|
|
19445
19445
|
const cwd = norm(dir);
|
|
19446
|
-
const home = norm(
|
|
19446
|
+
const home = norm(homedir29);
|
|
19447
19447
|
if (cwd === home) return true;
|
|
19448
19448
|
if (/^[a-z]:$/.test(cwd)) return true;
|
|
19449
19449
|
const sysRoots = [
|
|
@@ -20237,7 +20237,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
20237
20237
|
});
|
|
20238
20238
|
}
|
|
20239
20239
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
20240
|
-
const
|
|
20240
|
+
const fs46 = await import("fs/promises");
|
|
20241
20241
|
const out2 = [];
|
|
20242
20242
|
await walk(workingDir, 0);
|
|
20243
20243
|
return out2;
|
|
@@ -20245,7 +20245,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
20245
20245
|
if (depth > maxDepth) return;
|
|
20246
20246
|
let entries = [];
|
|
20247
20247
|
try {
|
|
20248
|
-
const dirents = await
|
|
20248
|
+
const dirents = await fs46.readdir(dir, { withFileTypes: true });
|
|
20249
20249
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
20250
20250
|
} catch {
|
|
20251
20251
|
return;
|
|
@@ -23920,12 +23920,12 @@ function readTokenFromArgs(args2) {
|
|
|
23920
23920
|
}
|
|
23921
23921
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
23922
23922
|
if (fileFlag) {
|
|
23923
|
-
const
|
|
23923
|
+
const path58 = fileFlag.slice("--token-file=".length);
|
|
23924
23924
|
try {
|
|
23925
|
-
const content = fs40.readFileSync(
|
|
23926
|
-
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`);
|
|
23927
23927
|
try {
|
|
23928
|
-
fs40.unlinkSync(
|
|
23928
|
+
fs40.unlinkSync(path58);
|
|
23929
23929
|
} catch {
|
|
23930
23930
|
}
|
|
23931
23931
|
return content;
|
|
@@ -24409,12 +24409,12 @@ var GitHubCodespacesProvider = class {
|
|
|
24409
24409
|
* install error if it's still missing.
|
|
24410
24410
|
*/
|
|
24411
24411
|
async tryInstallGh() {
|
|
24412
|
-
const
|
|
24412
|
+
const platform3 = process.platform;
|
|
24413
24413
|
wt(
|
|
24414
24414
|
`GitHub CLI (${import_picocolors8.default.cyan("gh")}) is required for Codespaces deploys but isn't on your PATH.`,
|
|
24415
24415
|
"Heads up"
|
|
24416
24416
|
);
|
|
24417
|
-
if (
|
|
24417
|
+
if (platform3 === "linux") {
|
|
24418
24418
|
wt(
|
|
24419
24419
|
[
|
|
24420
24420
|
"On Linux, please install gh from the official guide:",
|
|
@@ -24426,7 +24426,7 @@ var GitHubCodespacesProvider = class {
|
|
|
24426
24426
|
return;
|
|
24427
24427
|
}
|
|
24428
24428
|
let installCmd = null;
|
|
24429
|
-
if (
|
|
24429
|
+
if (platform3 === "darwin") {
|
|
24430
24430
|
try {
|
|
24431
24431
|
await execFileP5("brew", ["--version"], { maxBuffer: MAX_BUFFER });
|
|
24432
24432
|
} catch {
|
|
@@ -24445,7 +24445,7 @@ var GitHubCodespacesProvider = class {
|
|
|
24445
24445
|
args: ["install", "gh"],
|
|
24446
24446
|
describe: "brew install gh"
|
|
24447
24447
|
};
|
|
24448
|
-
} else if (
|
|
24448
|
+
} else if (platform3 === "win32") {
|
|
24449
24449
|
try {
|
|
24450
24450
|
await execFileP5("winget", ["--version"], { maxBuffer: MAX_BUFFER });
|
|
24451
24451
|
} catch {
|
|
@@ -26175,50 +26175,488 @@ async function probeCodeamPair(provider, workspace) {
|
|
|
26175
26175
|
}
|
|
26176
26176
|
async function stopWorkspaceFromLocal(target) {
|
|
26177
26177
|
if (target.provider.id === "github-codespaces") {
|
|
26178
|
-
const { execFile:
|
|
26179
|
-
const { promisify:
|
|
26180
|
-
const
|
|
26181
|
-
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 });
|
|
26182
26182
|
return;
|
|
26183
26183
|
}
|
|
26184
26184
|
}
|
|
26185
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
|
+
|
|
26186
26624
|
// src/commands/doctor.ts
|
|
26187
26625
|
var import_node_dns = require("dns");
|
|
26188
|
-
var
|
|
26626
|
+
var import_node_util5 = require("util");
|
|
26189
26627
|
var import_node_crypto8 = require("crypto");
|
|
26190
|
-
var
|
|
26191
|
-
var
|
|
26628
|
+
var fs44 = __toESM(require("fs"));
|
|
26629
|
+
var path56 = __toESM(require("path"));
|
|
26192
26630
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
26193
|
-
var dnsResolveP = (0,
|
|
26194
|
-
async function checkDns(
|
|
26195
|
-
const
|
|
26631
|
+
var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
|
|
26632
|
+
async function checkDns(apiBase2) {
|
|
26633
|
+
const host2 = (() => {
|
|
26196
26634
|
try {
|
|
26197
|
-
return new URL(
|
|
26635
|
+
return new URL(apiBase2).host;
|
|
26198
26636
|
} catch {
|
|
26199
|
-
return
|
|
26637
|
+
return apiBase2;
|
|
26200
26638
|
}
|
|
26201
26639
|
})();
|
|
26202
26640
|
try {
|
|
26203
|
-
const addrs = await dnsResolveP(
|
|
26641
|
+
const addrs = await dnsResolveP(host2);
|
|
26204
26642
|
return {
|
|
26205
26643
|
id: "dns",
|
|
26206
|
-
label: `DNS resolves ${
|
|
26644
|
+
label: `DNS resolves ${host2}`,
|
|
26207
26645
|
ok: true,
|
|
26208
26646
|
detail: `${addrs.length} record(s)`
|
|
26209
26647
|
};
|
|
26210
26648
|
} catch (err) {
|
|
26211
26649
|
return {
|
|
26212
26650
|
id: "dns",
|
|
26213
|
-
label: `DNS resolves ${
|
|
26651
|
+
label: `DNS resolves ${host2}`,
|
|
26214
26652
|
ok: false,
|
|
26215
26653
|
detail: err.message,
|
|
26216
26654
|
hint: "Check your network connection / DNS configuration. The backend host MUST resolve before `codeam pair` can succeed."
|
|
26217
26655
|
};
|
|
26218
26656
|
}
|
|
26219
26657
|
}
|
|
26220
|
-
async function checkHealth(
|
|
26221
|
-
const url = `${
|
|
26658
|
+
async function checkHealth(apiBase2) {
|
|
26659
|
+
const url = `${apiBase2}/health`;
|
|
26222
26660
|
const controller = new AbortController();
|
|
26223
26661
|
const timer = setTimeout(() => controller.abort(), 5e3);
|
|
26224
26662
|
try {
|
|
@@ -26244,13 +26682,13 @@ async function checkHealth(apiBase) {
|
|
|
26244
26682
|
}
|
|
26245
26683
|
}
|
|
26246
26684
|
function checkConfigDir() {
|
|
26247
|
-
const dir =
|
|
26685
|
+
const dir = path56.join(require("os").homedir(), ".codeam");
|
|
26248
26686
|
try {
|
|
26249
|
-
|
|
26250
|
-
const probe =
|
|
26251
|
-
|
|
26252
|
-
const read =
|
|
26253
|
-
|
|
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);
|
|
26254
26692
|
if (read !== "ok") throw new Error("write/read round-trip mismatch");
|
|
26255
26693
|
return {
|
|
26256
26694
|
id: "config-dir",
|
|
@@ -26290,9 +26728,9 @@ function checkSessions() {
|
|
|
26290
26728
|
}
|
|
26291
26729
|
}
|
|
26292
26730
|
function checkAgentBinaries() {
|
|
26293
|
-
const
|
|
26731
|
+
const os36 = createOsStrategy();
|
|
26294
26732
|
return getEnabledAgents().map((meta) => {
|
|
26295
|
-
const found =
|
|
26733
|
+
const found = os36.findInPath(meta.binaryName);
|
|
26296
26734
|
return {
|
|
26297
26735
|
id: `agent-${meta.id}`,
|
|
26298
26736
|
label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
|
|
@@ -26314,7 +26752,7 @@ function checkNodePty() {
|
|
|
26314
26752
|
detail: "not required on this platform"
|
|
26315
26753
|
};
|
|
26316
26754
|
}
|
|
26317
|
-
const vendoredPath =
|
|
26755
|
+
const vendoredPath = path56.join(__dirname, "vendor", "node-pty");
|
|
26318
26756
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
26319
26757
|
try {
|
|
26320
26758
|
require(target);
|
|
@@ -26356,13 +26794,13 @@ function checkChokidar() {
|
|
|
26356
26794
|
}
|
|
26357
26795
|
async function doctor(args2 = []) {
|
|
26358
26796
|
const json = args2.includes("--json");
|
|
26359
|
-
const cliVersion = true ? "2.39.
|
|
26360
|
-
const
|
|
26797
|
+
const cliVersion = true ? "2.39.26" : "0.0.0-dev";
|
|
26798
|
+
const apiBase2 = resolveApiBaseUrl();
|
|
26361
26799
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
26362
26800
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
26363
26801
|
const [dns2, health] = await Promise.all([
|
|
26364
|
-
checkDns(
|
|
26365
|
-
checkHealth(
|
|
26802
|
+
checkDns(apiBase2),
|
|
26803
|
+
checkHealth(apiBase2)
|
|
26366
26804
|
]);
|
|
26367
26805
|
const checks = [
|
|
26368
26806
|
dns2,
|
|
@@ -26379,7 +26817,7 @@ async function doctor(args2 = []) {
|
|
|
26379
26817
|
node: process.version,
|
|
26380
26818
|
platform: process.platform,
|
|
26381
26819
|
arch: process.arch,
|
|
26382
|
-
apiBase,
|
|
26820
|
+
apiBase: apiBase2,
|
|
26383
26821
|
checks,
|
|
26384
26822
|
// Optional checks (e.g. agent-binary probes) report status but
|
|
26385
26823
|
// don't gate exit code — see CheckResult.optional.
|
|
@@ -26555,7 +26993,7 @@ async function completion(args2) {
|
|
|
26555
26993
|
// src/commands/version.ts
|
|
26556
26994
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
26557
26995
|
function version2() {
|
|
26558
|
-
const v = true ? "2.39.
|
|
26996
|
+
const v = true ? "2.39.26" : "unknown";
|
|
26559
26997
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
26560
26998
|
}
|
|
26561
26999
|
|
|
@@ -26683,23 +27121,23 @@ function tryShowSubcommandHelp(cmd, args2) {
|
|
|
26683
27121
|
var _subcommandHelpKeys = Object.keys(HELPS);
|
|
26684
27122
|
|
|
26685
27123
|
// src/lib/updateNotifier.ts
|
|
26686
|
-
var
|
|
26687
|
-
var
|
|
26688
|
-
var
|
|
27124
|
+
var fs45 = __toESM(require("fs"));
|
|
27125
|
+
var os35 = __toESM(require("os"));
|
|
27126
|
+
var path57 = __toESM(require("path"));
|
|
26689
27127
|
var https8 = __toESM(require("https"));
|
|
26690
|
-
var
|
|
27128
|
+
var import_node_child_process14 = require("child_process");
|
|
26691
27129
|
var import_picocolors16 = __toESM(require("picocolors"));
|
|
26692
27130
|
var PKG_NAME = "codeam-cli";
|
|
26693
27131
|
var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
26694
27132
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
26695
27133
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
26696
27134
|
function cachePath() {
|
|
26697
|
-
const dir =
|
|
26698
|
-
return
|
|
27135
|
+
const dir = path57.join(os35.homedir(), ".codeam");
|
|
27136
|
+
return path57.join(dir, "update-check.json");
|
|
26699
27137
|
}
|
|
26700
27138
|
function readCache() {
|
|
26701
27139
|
try {
|
|
26702
|
-
const raw =
|
|
27140
|
+
const raw = fs45.readFileSync(cachePath(), "utf8");
|
|
26703
27141
|
const parsed = JSON.parse(raw);
|
|
26704
27142
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
26705
27143
|
return parsed;
|
|
@@ -26710,10 +27148,10 @@ function readCache() {
|
|
|
26710
27148
|
function writeCache(cache) {
|
|
26711
27149
|
try {
|
|
26712
27150
|
const file = cachePath();
|
|
26713
|
-
|
|
27151
|
+
fs45.mkdirSync(path57.dirname(file), { recursive: true });
|
|
26714
27152
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
26715
|
-
|
|
26716
|
-
|
|
27153
|
+
fs45.writeFileSync(tmp, JSON.stringify(cache));
|
|
27154
|
+
fs45.renameSync(tmp, file);
|
|
26717
27155
|
} catch {
|
|
26718
27156
|
}
|
|
26719
27157
|
}
|
|
@@ -26781,14 +27219,14 @@ function notifyIfStale(currentVersion, latest) {
|
|
|
26781
27219
|
}
|
|
26782
27220
|
function isLinkedInstall() {
|
|
26783
27221
|
try {
|
|
26784
|
-
const root = (0,
|
|
27222
|
+
const root = (0, import_node_child_process14.execSync)("npm root -g", {
|
|
26785
27223
|
encoding: "utf8",
|
|
26786
27224
|
stdio: ["ignore", "pipe", "ignore"],
|
|
26787
27225
|
timeout: 2e3
|
|
26788
27226
|
}).trim();
|
|
26789
27227
|
if (!root) return false;
|
|
26790
|
-
const pkgPath =
|
|
26791
|
-
return
|
|
27228
|
+
const pkgPath = path57.join(root, PKG_NAME);
|
|
27229
|
+
return fs45.lstatSync(pkgPath).isSymbolicLink();
|
|
26792
27230
|
} catch {
|
|
26793
27231
|
return false;
|
|
26794
27232
|
}
|
|
@@ -26809,7 +27247,7 @@ function maybeAutoUpdate(currentVersion, latest) {
|
|
|
26809
27247
|
|
|
26810
27248
|
`
|
|
26811
27249
|
);
|
|
26812
|
-
const install = (0,
|
|
27250
|
+
const install = (0, import_node_child_process14.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
|
|
26813
27251
|
stdio: "inherit",
|
|
26814
27252
|
env: process.env
|
|
26815
27253
|
});
|
|
@@ -26824,13 +27262,13 @@ function maybeAutoUpdate(currentVersion, latest) {
|
|
|
26824
27262
|
return;
|
|
26825
27263
|
}
|
|
26826
27264
|
try {
|
|
26827
|
-
|
|
27265
|
+
fs45.unlinkSync(cachePath());
|
|
26828
27266
|
} catch {
|
|
26829
27267
|
}
|
|
26830
27268
|
process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
|
|
26831
27269
|
|
|
26832
27270
|
`);
|
|
26833
|
-
const child = (0,
|
|
27271
|
+
const child = (0, import_node_child_process14.spawnSync)("codeam", process.argv.slice(2), {
|
|
26834
27272
|
stdio: "inherit",
|
|
26835
27273
|
env: process.env
|
|
26836
27274
|
});
|
|
@@ -26841,7 +27279,7 @@ function checkForUpdates() {
|
|
|
26841
27279
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
26842
27280
|
if (process.env.CI) return;
|
|
26843
27281
|
if (!process.stdout.isTTY) return;
|
|
26844
|
-
const current = true ? "2.39.
|
|
27282
|
+
const current = true ? "2.39.26" : null;
|
|
26845
27283
|
if (!current) return;
|
|
26846
27284
|
const cache = readCache();
|
|
26847
27285
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -26886,6 +27324,8 @@ async function main() {
|
|
|
26886
27324
|
const commands = {
|
|
26887
27325
|
"pair": () => pair(args),
|
|
26888
27326
|
"pair-auto": () => pairAuto(args),
|
|
27327
|
+
"host-agent": () => hostAgent(args),
|
|
27328
|
+
"host": () => host(args),
|
|
26889
27329
|
"sessions": () => sessions2(args),
|
|
26890
27330
|
"status": () => status(),
|
|
26891
27331
|
"logout": () => logout(),
|