codeam-cli 2.25.0 → 2.26.1
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 +27 -0
- package/dist/index.js +801 -186
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -326,6 +326,37 @@ function resolveApiBaseUrl() {
|
|
|
326
326
|
return DEFAULT_API_BASE_URL;
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
+
// ../../packages/shared/src/preview-prompts.ts
|
|
330
|
+
var PREVIEW_DETECT_PROMPT = `
|
|
331
|
+
Analyze the project in the current working directory and return how to start
|
|
332
|
+
its development server for in-app preview.
|
|
333
|
+
|
|
334
|
+
Read package.json, Procfile, Dockerfile, docker-compose.yml, manage.py, app.json,
|
|
335
|
+
mix.exs, Cargo.toml, go.mod, requirements.txt, Gemfile, and any other framework
|
|
336
|
+
markers you find at depth <= 2.
|
|
337
|
+
|
|
338
|
+
Return ONLY a JSON object on stdout (no prose, no markdown fences):
|
|
339
|
+
|
|
340
|
+
{
|
|
341
|
+
"framework": "<name, or 'unsupported'>",
|
|
342
|
+
"command": "<executable>",
|
|
343
|
+
"args": ["..."],
|
|
344
|
+
"port": <number>,
|
|
345
|
+
"ready_pattern": "<regex matching the server-ready stdout line>",
|
|
346
|
+
"env": { "HOST": "0.0.0.0" },
|
|
347
|
+
"setup_commands": [{"cmd":"npm","args":["install"]}],
|
|
348
|
+
"notes": "<one-line caveat or null>"
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
Rules:
|
|
352
|
+
- Pick the script the developer would run locally to see the app (typically "dev", "start", "serve").
|
|
353
|
+
- Prefer binding to 0.0.0.0 \u2014 most frameworks default to localhost which the tunnel cannot reach.
|
|
354
|
+
- For Expo: framework="Expo", command="npx", args=["expo","start","--tunnel"], port=8081, notes="Scan QR with Expo Go".
|
|
355
|
+
- If no dev server applies (CLI library, lambda, batch script): {"framework":"unsupported","notes":"<reason>"}.
|
|
356
|
+
|
|
357
|
+
OUTPUT JSON ONLY. NO MARKDOWN. NO COMMENTARY.
|
|
358
|
+
`.trim();
|
|
359
|
+
|
|
329
360
|
// src/config.ts
|
|
330
361
|
var fs = __toESM(require("fs"));
|
|
331
362
|
var os = __toESM(require("os"));
|
|
@@ -441,7 +472,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
441
472
|
// package.json
|
|
442
473
|
var package_default = {
|
|
443
474
|
name: "codeam-cli",
|
|
444
|
-
version: "2.
|
|
475
|
+
version: "2.26.1",
|
|
445
476
|
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.",
|
|
446
477
|
type: "commonjs",
|
|
447
478
|
main: "dist/index.js",
|
|
@@ -515,6 +546,7 @@ var package_default = {
|
|
|
515
546
|
chokidar: "^3.6.0",
|
|
516
547
|
picocolors: "^1.1.0",
|
|
517
548
|
"qrcode-terminal": "^0.12.0",
|
|
549
|
+
which: "^2.0.2",
|
|
518
550
|
ws: "^8.18.0",
|
|
519
551
|
zod: "^4.3.6"
|
|
520
552
|
},
|
|
@@ -522,6 +554,7 @@ var package_default = {
|
|
|
522
554
|
"@codeagent/shared": "*",
|
|
523
555
|
"@types/node": "^22.0.0",
|
|
524
556
|
"@types/qrcode-terminal": "^0.12.0",
|
|
557
|
+
"@types/which": "^3.0.4",
|
|
525
558
|
"@types/ws": "^8.5.0",
|
|
526
559
|
"@vitest/coverage-v8": "^4.1.7",
|
|
527
560
|
"node-pty": "^1.1.0",
|
|
@@ -768,6 +801,28 @@ async function postAiResult(input) {
|
|
|
768
801
|
};
|
|
769
802
|
}
|
|
770
803
|
}
|
|
804
|
+
async function postPreviewEvent(input) {
|
|
805
|
+
try {
|
|
806
|
+
await _transport.postJsonAuthed(
|
|
807
|
+
`${API_BASE}/api/preview/events`,
|
|
808
|
+
{
|
|
809
|
+
sessionId: input.sessionId,
|
|
810
|
+
pluginId: input.pluginId,
|
|
811
|
+
type: input.type,
|
|
812
|
+
payload: input.payload ?? {}
|
|
813
|
+
},
|
|
814
|
+
input.pluginAuthToken
|
|
815
|
+
);
|
|
816
|
+
return { ok: true };
|
|
817
|
+
} catch (err) {
|
|
818
|
+
const e = err;
|
|
819
|
+
return {
|
|
820
|
+
ok: false,
|
|
821
|
+
status: typeof e.statusCode === "number" ? e.statusCode : 0,
|
|
822
|
+
message: e.message || "unknown"
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
}
|
|
771
826
|
async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
772
827
|
return new Promise((resolve5, reject) => {
|
|
773
828
|
const data = JSON.stringify(body);
|
|
@@ -1060,8 +1115,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
1060
1115
|
return decodedFile;
|
|
1061
1116
|
};
|
|
1062
1117
|
}
|
|
1063
|
-
function normalizeWindowsPath(
|
|
1064
|
-
return
|
|
1118
|
+
function normalizeWindowsPath(path42) {
|
|
1119
|
+
return path42.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
1065
1120
|
}
|
|
1066
1121
|
|
|
1067
1122
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -3541,9 +3596,9 @@ async function addSourceContext(frames) {
|
|
|
3541
3596
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
3542
3597
|
return frames;
|
|
3543
3598
|
}
|
|
3544
|
-
function getContextLinesFromFile(
|
|
3599
|
+
function getContextLinesFromFile(path42, ranges, output) {
|
|
3545
3600
|
return new Promise((resolve5) => {
|
|
3546
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
3601
|
+
const stream = (0, import_node_fs.createReadStream)(path42);
|
|
3547
3602
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
3548
3603
|
input: stream
|
|
3549
3604
|
});
|
|
@@ -3558,7 +3613,7 @@ function getContextLinesFromFile(path40, ranges, output) {
|
|
|
3558
3613
|
let rangeStart = range[0];
|
|
3559
3614
|
let rangeEnd = range[1];
|
|
3560
3615
|
function onStreamError() {
|
|
3561
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
3616
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path42, 1);
|
|
3562
3617
|
lineReaded.close();
|
|
3563
3618
|
lineReaded.removeAllListeners();
|
|
3564
3619
|
destroyStreamAndResolve();
|
|
@@ -3619,8 +3674,8 @@ function clearLineContext(frame) {
|
|
|
3619
3674
|
delete frame.context_line;
|
|
3620
3675
|
delete frame.post_context;
|
|
3621
3676
|
}
|
|
3622
|
-
function shouldSkipContextLinesForFile(
|
|
3623
|
-
return
|
|
3677
|
+
function shouldSkipContextLinesForFile(path42) {
|
|
3678
|
+
return path42.startsWith("node:") || path42.endsWith(".min.js") || path42.endsWith(".min.cjs") || path42.endsWith(".min.mjs") || path42.startsWith("data:");
|
|
3624
3679
|
}
|
|
3625
3680
|
function shouldSkipContextLinesForFrame(frame) {
|
|
3626
3681
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -5774,7 +5829,7 @@ function readAnonId() {
|
|
|
5774
5829
|
}
|
|
5775
5830
|
function superProperties() {
|
|
5776
5831
|
return {
|
|
5777
|
-
cliVersion: true ? "2.
|
|
5832
|
+
cliVersion: true ? "2.26.1" : "0.0.0-dev",
|
|
5778
5833
|
nodeVersion: process.version,
|
|
5779
5834
|
platform: process.platform,
|
|
5780
5835
|
arch: process.arch,
|
|
@@ -7116,10 +7171,10 @@ function buildForPlatform(platform2) {
|
|
|
7116
7171
|
var import_node_crypto4 = require("crypto");
|
|
7117
7172
|
|
|
7118
7173
|
// src/agents/claude/resolver.ts
|
|
7119
|
-
function buildClaudeLaunch(extraArgs = [],
|
|
7120
|
-
const found =
|
|
7174
|
+
function buildClaudeLaunch(extraArgs = [], os27 = createOsStrategy()) {
|
|
7175
|
+
const found = os27.findInPath("claude") ?? os27.findInPath("claude-code");
|
|
7121
7176
|
if (!found) return null;
|
|
7122
|
-
return
|
|
7177
|
+
return os27.buildLaunch(found, extraArgs);
|
|
7123
7178
|
}
|
|
7124
7179
|
|
|
7125
7180
|
// src/agents/claude/installer.ts
|
|
@@ -9802,13 +9857,13 @@ function detectStartupBanner(lines) {
|
|
|
9802
9857
|
while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
|
|
9803
9858
|
if (metaIdx - artStart < 2) return null;
|
|
9804
9859
|
const pathLine = (lines[metaIdx + 1] ?? "").trim();
|
|
9805
|
-
const
|
|
9860
|
+
const path42 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
|
|
9806
9861
|
return {
|
|
9807
9862
|
title: "",
|
|
9808
9863
|
subtitle: lines[metaIdx].trim(),
|
|
9809
|
-
path:
|
|
9864
|
+
path: path42,
|
|
9810
9865
|
startIdx: artStart,
|
|
9811
|
-
endIdx: metaIdx + (
|
|
9866
|
+
endIdx: metaIdx + (path42 ? 1 : 0)
|
|
9812
9867
|
};
|
|
9813
9868
|
}
|
|
9814
9869
|
|
|
@@ -9818,8 +9873,8 @@ var ClaudeRuntimeStrategy = class {
|
|
|
9818
9873
|
meta = getAgent("claude");
|
|
9819
9874
|
mode = "interactive";
|
|
9820
9875
|
os;
|
|
9821
|
-
constructor(
|
|
9822
|
-
this.os =
|
|
9876
|
+
constructor(os27) {
|
|
9877
|
+
this.os = os27;
|
|
9823
9878
|
}
|
|
9824
9879
|
/**
|
|
9825
9880
|
* Claude Code's react-ink TUI enables bracketed-paste mode at
|
|
@@ -10708,8 +10763,8 @@ function codexCredentialLocator() {
|
|
|
10708
10763
|
function codexLoginLauncher() {
|
|
10709
10764
|
return {
|
|
10710
10765
|
async ensureInstalled() {
|
|
10711
|
-
const
|
|
10712
|
-
return
|
|
10766
|
+
const os27 = createOsStrategy();
|
|
10767
|
+
return os27.findInPath("codex") !== null;
|
|
10713
10768
|
},
|
|
10714
10769
|
launch() {
|
|
10715
10770
|
return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
@@ -10732,8 +10787,8 @@ var CodexRuntimeStrategy = class {
|
|
|
10732
10787
|
meta = getAgent("codex");
|
|
10733
10788
|
mode = "interactive";
|
|
10734
10789
|
os;
|
|
10735
|
-
constructor(
|
|
10736
|
-
this.os =
|
|
10790
|
+
constructor(os27) {
|
|
10791
|
+
this.os = os27;
|
|
10737
10792
|
}
|
|
10738
10793
|
async prepareLaunch() {
|
|
10739
10794
|
let binary = this.os.findInPath("codex");
|
|
@@ -10836,12 +10891,12 @@ var CodexRuntimeStrategy = class {
|
|
|
10836
10891
|
});
|
|
10837
10892
|
}
|
|
10838
10893
|
};
|
|
10839
|
-
function resolveNpm(
|
|
10840
|
-
return
|
|
10894
|
+
function resolveNpm(os27) {
|
|
10895
|
+
return os27.id === "win32" ? "npm.cmd" : "npm";
|
|
10841
10896
|
}
|
|
10842
|
-
async function installCodexViaNpm(
|
|
10897
|
+
async function installCodexViaNpm(os27) {
|
|
10843
10898
|
return new Promise((resolve5, reject) => {
|
|
10844
|
-
const proc = (0, import_node_child_process4.spawn)(resolveNpm(
|
|
10899
|
+
const proc = (0, import_node_child_process4.spawn)(resolveNpm(os27), ["install", "-g", "@openai/codex"], {
|
|
10845
10900
|
stdio: "inherit"
|
|
10846
10901
|
});
|
|
10847
10902
|
proc.on("close", (code) => {
|
|
@@ -10858,16 +10913,16 @@ async function installCodexViaNpm(os26) {
|
|
|
10858
10913
|
});
|
|
10859
10914
|
});
|
|
10860
10915
|
}
|
|
10861
|
-
function augmentNpmGlobalBin(
|
|
10916
|
+
function augmentNpmGlobalBin(os27) {
|
|
10862
10917
|
try {
|
|
10863
|
-
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(
|
|
10918
|
+
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os27), ["prefix", "-g"], {
|
|
10864
10919
|
stdio: ["ignore", "pipe", "ignore"]
|
|
10865
10920
|
});
|
|
10866
10921
|
if (result.status !== 0) return;
|
|
10867
10922
|
const prefix = result.stdout.toString().trim();
|
|
10868
10923
|
if (!prefix) return;
|
|
10869
|
-
const binDir =
|
|
10870
|
-
|
|
10924
|
+
const binDir = os27.id === "win32" ? prefix : path17.join(prefix, "bin");
|
|
10925
|
+
os27.augmentPath([binDir]);
|
|
10871
10926
|
} catch {
|
|
10872
10927
|
}
|
|
10873
10928
|
}
|
|
@@ -10951,9 +11006,9 @@ var import_node_child_process7 = require("child_process");
|
|
|
10951
11006
|
// src/agents/coderabbit/installer.ts
|
|
10952
11007
|
var import_node_child_process5 = require("child_process");
|
|
10953
11008
|
var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
|
|
10954
|
-
async function ensureCoderabbitInstalled(
|
|
10955
|
-
if (
|
|
10956
|
-
if (
|
|
11009
|
+
async function ensureCoderabbitInstalled(os27) {
|
|
11010
|
+
if (os27.findInPath("coderabbit")) return true;
|
|
11011
|
+
if (os27.id === "win32") {
|
|
10957
11012
|
console.error(
|
|
10958
11013
|
"\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"
|
|
10959
11014
|
);
|
|
@@ -10968,8 +11023,8 @@ async function ensureCoderabbitInstalled(os26) {
|
|
|
10968
11023
|
proc.on("error", () => resolve5(false));
|
|
10969
11024
|
});
|
|
10970
11025
|
if (!ok) return false;
|
|
10971
|
-
|
|
10972
|
-
return
|
|
11026
|
+
os27.augmentPath([`${os27.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
11027
|
+
return os27.findInPath("coderabbit") !== null;
|
|
10973
11028
|
}
|
|
10974
11029
|
|
|
10975
11030
|
// src/agents/coderabbit/link.ts
|
|
@@ -10996,10 +11051,10 @@ function coderabbitCredentialLocator() {
|
|
|
10996
11051
|
extract: extractLocalCoderabbitToken
|
|
10997
11052
|
};
|
|
10998
11053
|
}
|
|
10999
|
-
function coderabbitLoginLauncher(
|
|
11054
|
+
function coderabbitLoginLauncher(os27) {
|
|
11000
11055
|
return {
|
|
11001
11056
|
async ensureInstalled() {
|
|
11002
|
-
return ensureCoderabbitInstalled(
|
|
11057
|
+
return ensureCoderabbitInstalled(os27);
|
|
11003
11058
|
},
|
|
11004
11059
|
launch() {
|
|
11005
11060
|
return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
|
|
@@ -11022,11 +11077,11 @@ function parseReview(stdout) {
|
|
|
11022
11077
|
for (const line of lines) {
|
|
11023
11078
|
const m = line.match(HUNK_LINE_RE);
|
|
11024
11079
|
if (!m) continue;
|
|
11025
|
-
const [,
|
|
11026
|
-
if (!
|
|
11080
|
+
const [, path42, lineNo, sevToken, message] = m;
|
|
11081
|
+
if (!path42 || !lineNo || !message) continue;
|
|
11027
11082
|
const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
|
|
11028
11083
|
hunks.push({
|
|
11029
|
-
path:
|
|
11084
|
+
path: path42.trim(),
|
|
11030
11085
|
line: Number(lineNo),
|
|
11031
11086
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
11032
11087
|
message: cleanedMessage
|
|
@@ -11045,8 +11100,8 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11045
11100
|
meta = getAgent("coderabbit");
|
|
11046
11101
|
mode = "batch";
|
|
11047
11102
|
os;
|
|
11048
|
-
constructor(
|
|
11049
|
-
this.os =
|
|
11103
|
+
constructor(os27) {
|
|
11104
|
+
this.os = os27;
|
|
11050
11105
|
}
|
|
11051
11106
|
getDefaultArgs() {
|
|
11052
11107
|
return ["review"];
|
|
@@ -11161,10 +11216,10 @@ function cursorCredentialLocator() {
|
|
|
11161
11216
|
extract: extractLocalCursorToken
|
|
11162
11217
|
};
|
|
11163
11218
|
}
|
|
11164
|
-
function cursorLoginLauncher(
|
|
11219
|
+
function cursorLoginLauncher(os27) {
|
|
11165
11220
|
return {
|
|
11166
11221
|
async ensureInstalled() {
|
|
11167
|
-
if (
|
|
11222
|
+
if (os27.findInPath("cursor-agent")) return true;
|
|
11168
11223
|
console.error(
|
|
11169
11224
|
"\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"
|
|
11170
11225
|
);
|
|
@@ -11226,8 +11281,8 @@ var CursorRuntimeStrategy = class {
|
|
|
11226
11281
|
meta = getAgent("cursor");
|
|
11227
11282
|
mode = "interactive";
|
|
11228
11283
|
os;
|
|
11229
|
-
constructor(
|
|
11230
|
-
this.os =
|
|
11284
|
+
constructor(os27) {
|
|
11285
|
+
this.os = os27;
|
|
11231
11286
|
}
|
|
11232
11287
|
async prepareLaunch() {
|
|
11233
11288
|
const binary = this.os.findInPath("cursor-agent");
|
|
@@ -11347,10 +11402,10 @@ function aiderCredentialLocator() {
|
|
|
11347
11402
|
extract: extractLocalAiderToken
|
|
11348
11403
|
};
|
|
11349
11404
|
}
|
|
11350
|
-
function aiderLoginLauncher(
|
|
11405
|
+
function aiderLoginLauncher(os27) {
|
|
11351
11406
|
return {
|
|
11352
11407
|
async ensureInstalled() {
|
|
11353
|
-
if (
|
|
11408
|
+
if (os27.findInPath("aider")) return true;
|
|
11354
11409
|
console.error(
|
|
11355
11410
|
"\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
|
|
11356
11411
|
);
|
|
@@ -11360,7 +11415,7 @@ function aiderLoginLauncher(os26) {
|
|
|
11360
11415
|
console.error(
|
|
11361
11416
|
"\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"
|
|
11362
11417
|
);
|
|
11363
|
-
return (0, import_node_child_process9.spawn)(
|
|
11418
|
+
return (0, import_node_child_process9.spawn)(os27.id === "win32" ? "cmd.exe" : "sh", os27.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
|
|
11364
11419
|
stdio: "ignore"
|
|
11365
11420
|
});
|
|
11366
11421
|
}
|
|
@@ -11432,8 +11487,8 @@ var AiderRuntimeStrategy = class {
|
|
|
11432
11487
|
meta = getAgent("aider");
|
|
11433
11488
|
mode = "interactive";
|
|
11434
11489
|
os;
|
|
11435
|
-
constructor(
|
|
11436
|
-
this.os =
|
|
11490
|
+
constructor(os27) {
|
|
11491
|
+
this.os = os27;
|
|
11437
11492
|
}
|
|
11438
11493
|
async prepareLaunch() {
|
|
11439
11494
|
const binary = this.os.findInPath("aider");
|
|
@@ -11502,17 +11557,17 @@ var AiderRuntimeStrategy = class {
|
|
|
11502
11557
|
|
|
11503
11558
|
// src/agents/registry.ts
|
|
11504
11559
|
var runtimeBuilders = {
|
|
11505
|
-
claude: (
|
|
11506
|
-
codex: (
|
|
11507
|
-
coderabbit: (
|
|
11508
|
-
cursor: (
|
|
11509
|
-
aider: (
|
|
11560
|
+
claude: (os27) => new ClaudeRuntimeStrategy(os27),
|
|
11561
|
+
codex: (os27) => new CodexRuntimeStrategy(os27),
|
|
11562
|
+
coderabbit: (os27) => new CoderabbitRuntimeStrategy(os27),
|
|
11563
|
+
cursor: (os27) => new CursorRuntimeStrategy(os27),
|
|
11564
|
+
aider: (os27) => new AiderRuntimeStrategy(os27)
|
|
11510
11565
|
};
|
|
11511
11566
|
var deployBuilders = {
|
|
11512
11567
|
claude: () => new ClaudeDeployStrategy(),
|
|
11513
11568
|
codex: () => new CodexDeployStrategy()
|
|
11514
11569
|
};
|
|
11515
|
-
function createAgentStrategy(agent,
|
|
11570
|
+
function createAgentStrategy(agent, os27 = createOsStrategy()) {
|
|
11516
11571
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
11517
11572
|
throw new Error(
|
|
11518
11573
|
`Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
|
|
@@ -11522,10 +11577,10 @@ function createAgentStrategy(agent, os26 = createOsStrategy()) {
|
|
|
11522
11577
|
if (!build) {
|
|
11523
11578
|
throw new Error(`No runtime strategy registered for agent "${agent}"`);
|
|
11524
11579
|
}
|
|
11525
|
-
return build(
|
|
11580
|
+
return build(os27);
|
|
11526
11581
|
}
|
|
11527
|
-
function createInteractiveAgentStrategy(agent,
|
|
11528
|
-
const s = createAgentStrategy(agent,
|
|
11582
|
+
function createInteractiveAgentStrategy(agent, os27 = createOsStrategy()) {
|
|
11583
|
+
const s = createAgentStrategy(agent, os27);
|
|
11529
11584
|
if (s.mode !== "interactive") {
|
|
11530
11585
|
throw new Error(
|
|
11531
11586
|
`Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
|
|
@@ -13622,7 +13677,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
13622
13677
|
});
|
|
13623
13678
|
}
|
|
13624
13679
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
13625
|
-
const
|
|
13680
|
+
const fs33 = await import("fs/promises");
|
|
13626
13681
|
const out2 = [];
|
|
13627
13682
|
await walk(workingDir, 0);
|
|
13628
13683
|
return out2;
|
|
@@ -13630,7 +13685,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
13630
13685
|
if (depth > maxDepth) return;
|
|
13631
13686
|
let entries = [];
|
|
13632
13687
|
try {
|
|
13633
|
-
const dirents = await
|
|
13688
|
+
const dirents = await fs33.readdir(dir, { withFileTypes: true });
|
|
13634
13689
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
13635
13690
|
} catch {
|
|
13636
13691
|
return;
|
|
@@ -14532,11 +14587,11 @@ function buildKeepAlive(ctx) {
|
|
|
14532
14587
|
}
|
|
14533
14588
|
|
|
14534
14589
|
// src/commands/start/handlers.ts
|
|
14535
|
-
var
|
|
14536
|
-
var
|
|
14537
|
-
var
|
|
14590
|
+
var fs29 = __toESM(require("fs"));
|
|
14591
|
+
var os24 = __toESM(require("os"));
|
|
14592
|
+
var path35 = __toESM(require("path"));
|
|
14538
14593
|
var import_crypto5 = require("crypto");
|
|
14539
|
-
var
|
|
14594
|
+
var import_child_process15 = require("child_process");
|
|
14540
14595
|
|
|
14541
14596
|
// src/lib/payload.ts
|
|
14542
14597
|
var import_zod2 = require("zod");
|
|
@@ -14628,6 +14683,28 @@ var startCommandSchema = import_zod2.z.object({
|
|
|
14628
14683
|
added: import_zod2.z.number().int(),
|
|
14629
14684
|
removed: import_zod2.z.number().int(),
|
|
14630
14685
|
complexityShift: import_zod2.z.number().int()
|
|
14686
|
+
}).optional(),
|
|
14687
|
+
// `preview_start` carries the agent-detected `PreviewDetection`
|
|
14688
|
+
// shape from the mobile / web confirmation sheet. Mirrors
|
|
14689
|
+
// `@codeagent/shared`'s `PreviewDetection` byte-for-byte. Kept
|
|
14690
|
+
// loose (`unknown` for env / setup_commands) so a CLI version
|
|
14691
|
+
// running against a newer backend that adds optional fields still
|
|
14692
|
+
// accepts the payload; the handler validates the shape it needs
|
|
14693
|
+
// before spawning.
|
|
14694
|
+
detection: import_zod2.z.object({
|
|
14695
|
+
framework: import_zod2.z.string().max(64),
|
|
14696
|
+
command: import_zod2.z.string().min(1).max(256),
|
|
14697
|
+
args: import_zod2.z.array(import_zod2.z.string().max(1024)).max(64),
|
|
14698
|
+
port: import_zod2.z.number().int().min(1).max(65535),
|
|
14699
|
+
ready_pattern: import_zod2.z.string().min(1).max(4096),
|
|
14700
|
+
env: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string().max(8192)).optional(),
|
|
14701
|
+
setup_commands: import_zod2.z.array(
|
|
14702
|
+
import_zod2.z.object({
|
|
14703
|
+
cmd: import_zod2.z.string().min(1).max(256),
|
|
14704
|
+
args: import_zod2.z.array(import_zod2.z.string().max(1024)).max(64)
|
|
14705
|
+
})
|
|
14706
|
+
).max(32).optional(),
|
|
14707
|
+
notes: import_zod2.z.string().max(4096).nullable().optional()
|
|
14631
14708
|
}).optional()
|
|
14632
14709
|
});
|
|
14633
14710
|
function parsePayload2(schema, raw) {
|
|
@@ -15811,12 +15888,212 @@ async function linkDryRunPreflight(ctx) {
|
|
|
15811
15888
|
process.exit(1);
|
|
15812
15889
|
}
|
|
15813
15890
|
|
|
15891
|
+
// src/services/preview/cloudflared.ts
|
|
15892
|
+
var import_fs = require("fs");
|
|
15893
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
15894
|
+
var import_os7 = __toESM(require("os"));
|
|
15895
|
+
var import_path4 = __toESM(require("path"));
|
|
15896
|
+
var import_promises2 = require("stream/promises");
|
|
15897
|
+
var import_which = __toESM(require("which"));
|
|
15898
|
+
var CACHED_BINARY = import_path4.default.join(import_os7.default.homedir(), ".codeam", "bin", "cloudflared");
|
|
15899
|
+
async function resolveCloudflared(opts = {}) {
|
|
15900
|
+
try {
|
|
15901
|
+
return await (0, import_which.default)("cloudflared");
|
|
15902
|
+
} catch {
|
|
15903
|
+
}
|
|
15904
|
+
try {
|
|
15905
|
+
await import_promises.default.access(CACHED_BINARY);
|
|
15906
|
+
return CACHED_BINARY;
|
|
15907
|
+
} catch {
|
|
15908
|
+
}
|
|
15909
|
+
if (opts.skipDownload) {
|
|
15910
|
+
throw new Error(
|
|
15911
|
+
"cloudflared not installed. Install via `brew install cloudflared` (macOS) or download from https://github.com/cloudflare/cloudflared/releases."
|
|
15912
|
+
);
|
|
15913
|
+
}
|
|
15914
|
+
await downloadCloudflared(CACHED_BINARY);
|
|
15915
|
+
return CACHED_BINARY;
|
|
15916
|
+
}
|
|
15917
|
+
async function downloadCloudflared(target) {
|
|
15918
|
+
const url = downloadUrlForPlatform();
|
|
15919
|
+
await import_promises.default.mkdir(import_path4.default.dirname(target), { recursive: true });
|
|
15920
|
+
const response = await fetch(url);
|
|
15921
|
+
if (!response.ok || !response.body) {
|
|
15922
|
+
throw new Error(
|
|
15923
|
+
`Failed to download cloudflared from ${url}: HTTP ${response.status}. Install manually from https://github.com/cloudflare/cloudflared/releases.`
|
|
15924
|
+
);
|
|
15925
|
+
}
|
|
15926
|
+
await (0, import_promises2.pipeline)(
|
|
15927
|
+
response.body,
|
|
15928
|
+
(0, import_fs.createWriteStream)(target, { mode: 493 })
|
|
15929
|
+
);
|
|
15930
|
+
}
|
|
15931
|
+
function downloadUrlForPlatform() {
|
|
15932
|
+
const platform2 = process.platform;
|
|
15933
|
+
const arch = process.arch;
|
|
15934
|
+
const base = "https://github.com/cloudflare/cloudflared/releases/latest/download";
|
|
15935
|
+
if (platform2 === "darwin" && arch === "arm64") return `${base}/cloudflared-darwin-arm64.tgz`;
|
|
15936
|
+
if (platform2 === "darwin" && arch === "x64") return `${base}/cloudflared-darwin-amd64.tgz`;
|
|
15937
|
+
if (platform2 === "linux" && arch === "x64") return `${base}/cloudflared-linux-amd64`;
|
|
15938
|
+
if (platform2 === "linux" && arch === "arm64") return `${base}/cloudflared-linux-arm64`;
|
|
15939
|
+
if (platform2 === "win32") return `${base}/cloudflared-windows-amd64.exe`;
|
|
15940
|
+
throw new Error(
|
|
15941
|
+
`cloudflared auto-install not supported on ${platform2}/${arch}. Install manually from https://github.com/cloudflare/cloudflared/releases.`
|
|
15942
|
+
);
|
|
15943
|
+
}
|
|
15944
|
+
|
|
15945
|
+
// src/services/preview/codespace.ts
|
|
15946
|
+
var import_child_process14 = require("child_process");
|
|
15947
|
+
var import_util3 = require("util");
|
|
15948
|
+
var execFileP4 = (0, import_util3.promisify)(import_child_process14.execFile);
|
|
15949
|
+
function isCodespaceSession(env = process.env) {
|
|
15950
|
+
return Boolean(env.CODESPACE_NAME);
|
|
15951
|
+
}
|
|
15952
|
+
function buildCodespaceUrl(codespaceName, port) {
|
|
15953
|
+
return `https://${codespaceName}-${port}.app.github.dev`;
|
|
15954
|
+
}
|
|
15955
|
+
async function setPortPublic(codespaceName, port) {
|
|
15956
|
+
await execFileP4("gh", [
|
|
15957
|
+
"codespace",
|
|
15958
|
+
"ports",
|
|
15959
|
+
"visibility",
|
|
15960
|
+
`${port}:public`,
|
|
15961
|
+
"-c",
|
|
15962
|
+
codespaceName
|
|
15963
|
+
]);
|
|
15964
|
+
}
|
|
15965
|
+
async function waitForCodespacePortReady(url, timeoutMs = 15e3) {
|
|
15966
|
+
const start2 = Date.now();
|
|
15967
|
+
while (Date.now() - start2 < timeoutMs) {
|
|
15968
|
+
try {
|
|
15969
|
+
const res = await fetch(url, { method: "HEAD" });
|
|
15970
|
+
if (res.status < 500) return;
|
|
15971
|
+
} catch {
|
|
15972
|
+
}
|
|
15973
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
15974
|
+
}
|
|
15975
|
+
throw new Error(`Codespace forwarded URL ${url} not reachable after ${timeoutMs}ms.`);
|
|
15976
|
+
}
|
|
15977
|
+
|
|
15978
|
+
// src/services/preview/config-file.ts
|
|
15979
|
+
var import_promises3 = __toESM(require("fs/promises"));
|
|
15980
|
+
var import_path5 = __toESM(require("path"));
|
|
15981
|
+
var CONFIG_DIR = ".codeam";
|
|
15982
|
+
var CONFIG_FILE = "preview.json";
|
|
15983
|
+
function configPath(cwd) {
|
|
15984
|
+
return import_path5.default.join(cwd, CONFIG_DIR, CONFIG_FILE);
|
|
15985
|
+
}
|
|
15986
|
+
var REQUIRED_FIELDS = [
|
|
15987
|
+
"framework",
|
|
15988
|
+
"command",
|
|
15989
|
+
"args",
|
|
15990
|
+
"port",
|
|
15991
|
+
"ready_pattern"
|
|
15992
|
+
];
|
|
15993
|
+
async function readPreviewConfig(cwd) {
|
|
15994
|
+
let raw;
|
|
15995
|
+
try {
|
|
15996
|
+
raw = await import_promises3.default.readFile(configPath(cwd), "utf-8");
|
|
15997
|
+
} catch {
|
|
15998
|
+
return null;
|
|
15999
|
+
}
|
|
16000
|
+
let parsed;
|
|
16001
|
+
try {
|
|
16002
|
+
parsed = JSON.parse(raw);
|
|
16003
|
+
} catch {
|
|
16004
|
+
return null;
|
|
16005
|
+
}
|
|
16006
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
16007
|
+
const obj = parsed;
|
|
16008
|
+
for (const field of REQUIRED_FIELDS) {
|
|
16009
|
+
if (!(field in obj)) return null;
|
|
16010
|
+
}
|
|
16011
|
+
return obj;
|
|
16012
|
+
}
|
|
16013
|
+
async function writePreviewConfig(cwd, detection) {
|
|
16014
|
+
const filePath = configPath(cwd);
|
|
16015
|
+
await import_promises3.default.mkdir(import_path5.default.dirname(filePath), { recursive: true });
|
|
16016
|
+
await import_promises3.default.writeFile(filePath, JSON.stringify(detection, null, 2) + "\n", "utf-8");
|
|
16017
|
+
}
|
|
16018
|
+
|
|
16019
|
+
// src/services/preview/parser.ts
|
|
16020
|
+
var REQUIRED_FIELDS2 = [
|
|
16021
|
+
"framework",
|
|
16022
|
+
"command",
|
|
16023
|
+
"args",
|
|
16024
|
+
"port",
|
|
16025
|
+
"ready_pattern"
|
|
16026
|
+
];
|
|
16027
|
+
function safeParseDetection(raw) {
|
|
16028
|
+
if (!raw) return null;
|
|
16029
|
+
const stripped = raw.replace(/^```(?:json)?\s*/m, "").replace(/\s*```\s*$/m, "").trim();
|
|
16030
|
+
let parsed;
|
|
16031
|
+
try {
|
|
16032
|
+
parsed = JSON.parse(stripped);
|
|
16033
|
+
} catch {
|
|
16034
|
+
return null;
|
|
16035
|
+
}
|
|
16036
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
16037
|
+
const obj = parsed;
|
|
16038
|
+
for (const field of REQUIRED_FIELDS2) {
|
|
16039
|
+
if (!(field in obj)) return null;
|
|
16040
|
+
}
|
|
16041
|
+
return obj;
|
|
16042
|
+
}
|
|
16043
|
+
var CLOUDFLARED_URL_RE = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/i;
|
|
16044
|
+
function parseCloudflaredUrl(stderr) {
|
|
16045
|
+
const match = stderr.match(CLOUDFLARED_URL_RE);
|
|
16046
|
+
return match ? match[0] : null;
|
|
16047
|
+
}
|
|
16048
|
+
var EXPO_URL_RE = /exp:\/\/[^\s]+\.exp\.host/;
|
|
16049
|
+
function parseExpoUrl(stdout) {
|
|
16050
|
+
const match = stdout.match(EXPO_URL_RE);
|
|
16051
|
+
return match ? match[0] : null;
|
|
16052
|
+
}
|
|
16053
|
+
|
|
16054
|
+
// src/services/preview/index.ts
|
|
16055
|
+
var activePreviews = /* @__PURE__ */ new Map();
|
|
16056
|
+
function registerPreview(sessionId, preview) {
|
|
16057
|
+
activePreviews.set(sessionId, preview);
|
|
16058
|
+
}
|
|
16059
|
+
async function killPreview(sessionId) {
|
|
16060
|
+
const preview = activePreviews.get(sessionId);
|
|
16061
|
+
if (!preview) return;
|
|
16062
|
+
if (preview.tunnel) {
|
|
16063
|
+
try {
|
|
16064
|
+
preview.tunnel.kill("SIGTERM");
|
|
16065
|
+
} catch {
|
|
16066
|
+
}
|
|
16067
|
+
}
|
|
16068
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
16069
|
+
try {
|
|
16070
|
+
preview.devServer.kill("SIGTERM");
|
|
16071
|
+
} catch {
|
|
16072
|
+
}
|
|
16073
|
+
const sigkillTimer = setTimeout(() => {
|
|
16074
|
+
try {
|
|
16075
|
+
preview.devServer.kill("SIGKILL");
|
|
16076
|
+
} catch {
|
|
16077
|
+
}
|
|
16078
|
+
try {
|
|
16079
|
+
preview.tunnel?.kill("SIGKILL");
|
|
16080
|
+
} catch {
|
|
16081
|
+
}
|
|
16082
|
+
}, 250);
|
|
16083
|
+
sigkillTimer.unref?.();
|
|
16084
|
+
activePreviews.delete(sessionId);
|
|
16085
|
+
}
|
|
16086
|
+
async function killAllPreviews() {
|
|
16087
|
+
const ids = Array.from(activePreviews.keys());
|
|
16088
|
+
await Promise.all(ids.map((id) => killPreview(id)));
|
|
16089
|
+
}
|
|
16090
|
+
|
|
15814
16091
|
// src/commands/start/handlers.ts
|
|
15815
16092
|
var pendingAttachmentFiles = /* @__PURE__ */ new Set();
|
|
15816
16093
|
function cleanupAttachmentTempFiles() {
|
|
15817
16094
|
for (const p2 of pendingAttachmentFiles) {
|
|
15818
16095
|
try {
|
|
15819
|
-
|
|
16096
|
+
fs29.unlinkSync(p2);
|
|
15820
16097
|
} catch {
|
|
15821
16098
|
}
|
|
15822
16099
|
}
|
|
@@ -15825,8 +16102,8 @@ function cleanupAttachmentTempFiles() {
|
|
|
15825
16102
|
function saveFilesTemp(files) {
|
|
15826
16103
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
15827
16104
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
15828
|
-
const tmpPath =
|
|
15829
|
-
|
|
16105
|
+
const tmpPath = path35.join(os24.tmpdir(), `codeam-${(0, import_crypto5.randomUUID)()}-${safeName}`);
|
|
16106
|
+
fs29.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
15830
16107
|
pendingAttachmentFiles.add(tmpPath);
|
|
15831
16108
|
return tmpPath;
|
|
15832
16109
|
});
|
|
@@ -15846,7 +16123,7 @@ var startTask = (ctx, _cmd, parsed) => {
|
|
|
15846
16123
|
setTimeout(() => {
|
|
15847
16124
|
for (const p2 of paths) {
|
|
15848
16125
|
try {
|
|
15849
|
-
|
|
16126
|
+
fs29.unlinkSync(p2);
|
|
15850
16127
|
} catch {
|
|
15851
16128
|
}
|
|
15852
16129
|
pendingAttachmentFiles.delete(p2);
|
|
@@ -15971,7 +16248,7 @@ var sessionTerminated = async (ctx, cmd) => {
|
|
|
15971
16248
|
} catch {
|
|
15972
16249
|
}
|
|
15973
16250
|
try {
|
|
15974
|
-
const proc = (0,
|
|
16251
|
+
const proc = (0, import_child_process15.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
15975
16252
|
detached: true,
|
|
15976
16253
|
stdio: "ignore"
|
|
15977
16254
|
});
|
|
@@ -15993,7 +16270,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
15993
16270
|
}
|
|
15994
16271
|
if (ctx.keepAliveCtx.inCodespace && ctx.keepAliveCtx.codespaceName) {
|
|
15995
16272
|
try {
|
|
15996
|
-
const stopProc = (0,
|
|
16273
|
+
const stopProc = (0, import_child_process15.spawn)(
|
|
15997
16274
|
"bash",
|
|
15998
16275
|
["-lc", `sleep 1; gh codespace stop -c ${JSON.stringify(ctx.keepAliveCtx.codespaceName)} >/dev/null 2>&1 || true`],
|
|
15999
16276
|
{ detached: true, stdio: "ignore" }
|
|
@@ -16003,7 +16280,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
16003
16280
|
}
|
|
16004
16281
|
}
|
|
16005
16282
|
try {
|
|
16006
|
-
const proc = (0,
|
|
16283
|
+
const proc = (0, import_child_process15.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
16007
16284
|
detached: true,
|
|
16008
16285
|
stdio: "ignore"
|
|
16009
16286
|
});
|
|
@@ -16297,6 +16574,339 @@ function parseInsightText(text) {
|
|
|
16297
16574
|
securityNote: securityMatch?.[1]?.trim() || void 0
|
|
16298
16575
|
};
|
|
16299
16576
|
}
|
|
16577
|
+
var requestPreviewDetectH = (ctx) => {
|
|
16578
|
+
if (!ctx.pluginAuthToken) {
|
|
16579
|
+
log.info("preview", "no pluginAuthToken \u2014 skipping detect");
|
|
16580
|
+
return;
|
|
16581
|
+
}
|
|
16582
|
+
if (typeof ctx.runtime.generateOneShot !== "function") {
|
|
16583
|
+
log.info("preview", `runtime ${ctx.runtime.id} has no generateOneShot \u2014 emitting unsupported`);
|
|
16584
|
+
void postPreviewEvent({
|
|
16585
|
+
sessionId: ctx.sessionId,
|
|
16586
|
+
pluginId: ctx.pluginId,
|
|
16587
|
+
pluginAuthToken: ctx.pluginAuthToken,
|
|
16588
|
+
type: "preview_error",
|
|
16589
|
+
payload: {
|
|
16590
|
+
stage: "detection",
|
|
16591
|
+
message: `Preview detection isn't available on ${ctx.runtime.id} sessions yet \u2014 link a Claude or Codex agent.`
|
|
16592
|
+
}
|
|
16593
|
+
});
|
|
16594
|
+
return;
|
|
16595
|
+
}
|
|
16596
|
+
const pluginAuthToken = ctx.pluginAuthToken;
|
|
16597
|
+
void (async () => {
|
|
16598
|
+
const fromFile = await readPreviewConfig(process.cwd());
|
|
16599
|
+
if (fromFile) {
|
|
16600
|
+
log.info("preview", `detect: using .codeam/preview.json (${fromFile.framework})`);
|
|
16601
|
+
void postPreviewEvent({
|
|
16602
|
+
sessionId: ctx.sessionId,
|
|
16603
|
+
pluginId: ctx.pluginId,
|
|
16604
|
+
pluginAuthToken,
|
|
16605
|
+
type: "preview_detection_ready",
|
|
16606
|
+
payload: { detection: fromFile }
|
|
16607
|
+
});
|
|
16608
|
+
return;
|
|
16609
|
+
}
|
|
16610
|
+
void postPreviewEvent({
|
|
16611
|
+
sessionId: ctx.sessionId,
|
|
16612
|
+
pluginId: ctx.pluginId,
|
|
16613
|
+
pluginAuthToken,
|
|
16614
|
+
type: "preview_detection_pending"
|
|
16615
|
+
});
|
|
16616
|
+
log.info("preview", "detect: invoking generateOneShot");
|
|
16617
|
+
const startedAt = Date.now();
|
|
16618
|
+
const raw = await ctx.runtime.generateOneShot(PREVIEW_DETECT_PROMPT).catch((err) => {
|
|
16619
|
+
log.info("preview", `detect: generateOneShot threw: ${String(err)}`);
|
|
16620
|
+
return null;
|
|
16621
|
+
});
|
|
16622
|
+
const tookMs = Date.now() - startedAt;
|
|
16623
|
+
const detection = safeParseDetection(raw);
|
|
16624
|
+
if (!detection) {
|
|
16625
|
+
log.info("preview", `detect: invalid agent output after ${tookMs}ms`);
|
|
16626
|
+
void postPreviewEvent({
|
|
16627
|
+
sessionId: ctx.sessionId,
|
|
16628
|
+
pluginId: ctx.pluginId,
|
|
16629
|
+
pluginAuthToken,
|
|
16630
|
+
type: "preview_error",
|
|
16631
|
+
payload: {
|
|
16632
|
+
stage: "detection",
|
|
16633
|
+
message: "Agent returned invalid JSON. Try again, or add a .codeam/preview.json override."
|
|
16634
|
+
}
|
|
16635
|
+
});
|
|
16636
|
+
return;
|
|
16637
|
+
}
|
|
16638
|
+
if (detection.framework === "unsupported") {
|
|
16639
|
+
log.info("preview", "detect: framework=unsupported");
|
|
16640
|
+
void postPreviewEvent({
|
|
16641
|
+
sessionId: ctx.sessionId,
|
|
16642
|
+
pluginId: ctx.pluginId,
|
|
16643
|
+
pluginAuthToken,
|
|
16644
|
+
type: "preview_error",
|
|
16645
|
+
payload: {
|
|
16646
|
+
stage: "unsupported",
|
|
16647
|
+
message: detection.notes ?? "No dev server applies to this project."
|
|
16648
|
+
}
|
|
16649
|
+
});
|
|
16650
|
+
return;
|
|
16651
|
+
}
|
|
16652
|
+
log.info("preview", `detect: ${detection.framework} on :${detection.port} (took ${tookMs}ms)`);
|
|
16653
|
+
void postPreviewEvent({
|
|
16654
|
+
sessionId: ctx.sessionId,
|
|
16655
|
+
pluginId: ctx.pluginId,
|
|
16656
|
+
pluginAuthToken,
|
|
16657
|
+
type: "preview_detection_ready",
|
|
16658
|
+
payload: { detection }
|
|
16659
|
+
});
|
|
16660
|
+
})();
|
|
16661
|
+
};
|
|
16662
|
+
var previewStartH = (ctx, _cmd, parsed) => {
|
|
16663
|
+
if (!ctx.pluginAuthToken) {
|
|
16664
|
+
log.info("preview", "no pluginAuthToken \u2014 skipping start");
|
|
16665
|
+
return;
|
|
16666
|
+
}
|
|
16667
|
+
const detection = parsed.detection;
|
|
16668
|
+
if (!detection) {
|
|
16669
|
+
log.info("preview", "start: no detection in payload");
|
|
16670
|
+
return;
|
|
16671
|
+
}
|
|
16672
|
+
const pluginAuthToken = ctx.pluginAuthToken;
|
|
16673
|
+
void (async () => {
|
|
16674
|
+
void postPreviewEvent({
|
|
16675
|
+
sessionId: ctx.sessionId,
|
|
16676
|
+
pluginId: ctx.pluginId,
|
|
16677
|
+
pluginAuthToken,
|
|
16678
|
+
type: "preview_starting",
|
|
16679
|
+
payload: { framework: detection.framework, port: detection.port }
|
|
16680
|
+
});
|
|
16681
|
+
for (const setup of detection.setup_commands ?? []) {
|
|
16682
|
+
const exitCode = await runOnce(setup.cmd, setup.args, process.cwd(), detection.env);
|
|
16683
|
+
if (exitCode !== 0) {
|
|
16684
|
+
void postPreviewEvent({
|
|
16685
|
+
sessionId: ctx.sessionId,
|
|
16686
|
+
pluginId: ctx.pluginId,
|
|
16687
|
+
pluginAuthToken,
|
|
16688
|
+
type: "preview_error",
|
|
16689
|
+
payload: {
|
|
16690
|
+
stage: "spawn",
|
|
16691
|
+
message: `Setup failed (${setup.cmd} ${setup.args.join(" ")}, exit ${exitCode}).`
|
|
16692
|
+
}
|
|
16693
|
+
});
|
|
16694
|
+
return;
|
|
16695
|
+
}
|
|
16696
|
+
}
|
|
16697
|
+
const devServer = (0, import_child_process15.spawn)(detection.command, detection.args, {
|
|
16698
|
+
cwd: process.cwd(),
|
|
16699
|
+
env: { ...process.env, ...detection.env ?? {} },
|
|
16700
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
16701
|
+
});
|
|
16702
|
+
let readyMatched = false;
|
|
16703
|
+
let expoUrl = null;
|
|
16704
|
+
const readyRe = new RegExp(detection.ready_pattern);
|
|
16705
|
+
const onChunk = (chunk) => {
|
|
16706
|
+
const s = chunk.toString();
|
|
16707
|
+
if (!readyMatched && readyRe.test(s)) readyMatched = true;
|
|
16708
|
+
if (!expoUrl && detection.framework === "Expo") expoUrl = parseExpoUrl(s);
|
|
16709
|
+
};
|
|
16710
|
+
devServer.stdout.on("data", onChunk);
|
|
16711
|
+
devServer.stderr.on("data", onChunk);
|
|
16712
|
+
const readyDeadline = Date.now() + 12e4;
|
|
16713
|
+
while (!readyMatched && Date.now() < readyDeadline) {
|
|
16714
|
+
if (devServer.exitCode !== null) {
|
|
16715
|
+
void postPreviewEvent({
|
|
16716
|
+
sessionId: ctx.sessionId,
|
|
16717
|
+
pluginId: ctx.pluginId,
|
|
16718
|
+
pluginAuthToken,
|
|
16719
|
+
type: "preview_error",
|
|
16720
|
+
payload: {
|
|
16721
|
+
stage: "spawn",
|
|
16722
|
+
message: `Dev server exited (code ${devServer.exitCode}).`
|
|
16723
|
+
}
|
|
16724
|
+
});
|
|
16725
|
+
return;
|
|
16726
|
+
}
|
|
16727
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
16728
|
+
}
|
|
16729
|
+
if (!readyMatched) {
|
|
16730
|
+
try {
|
|
16731
|
+
devServer.kill("SIGTERM");
|
|
16732
|
+
} catch {
|
|
16733
|
+
}
|
|
16734
|
+
void postPreviewEvent({
|
|
16735
|
+
sessionId: ctx.sessionId,
|
|
16736
|
+
pluginId: ctx.pluginId,
|
|
16737
|
+
pluginAuthToken,
|
|
16738
|
+
type: "preview_error",
|
|
16739
|
+
payload: { stage: "ready_timeout", message: "Server didn't signal ready in 120s." }
|
|
16740
|
+
});
|
|
16741
|
+
return;
|
|
16742
|
+
}
|
|
16743
|
+
let tunnel = null;
|
|
16744
|
+
let url;
|
|
16745
|
+
if (detection.framework === "Expo") {
|
|
16746
|
+
if (!expoUrl) {
|
|
16747
|
+
const expoDeadline = Date.now() + 15e3;
|
|
16748
|
+
while (!expoUrl && Date.now() < expoDeadline) {
|
|
16749
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
16750
|
+
}
|
|
16751
|
+
}
|
|
16752
|
+
if (!expoUrl) {
|
|
16753
|
+
try {
|
|
16754
|
+
devServer.kill("SIGTERM");
|
|
16755
|
+
} catch {
|
|
16756
|
+
}
|
|
16757
|
+
void postPreviewEvent({
|
|
16758
|
+
sessionId: ctx.sessionId,
|
|
16759
|
+
pluginId: ctx.pluginId,
|
|
16760
|
+
pluginAuthToken,
|
|
16761
|
+
type: "preview_error",
|
|
16762
|
+
payload: { stage: "tunnel", message: "Expo did not report a tunnel URL." }
|
|
16763
|
+
});
|
|
16764
|
+
return;
|
|
16765
|
+
}
|
|
16766
|
+
url = expoUrl;
|
|
16767
|
+
} else if (isCodespaceSession()) {
|
|
16768
|
+
const codespaceName = process.env.CODESPACE_NAME;
|
|
16769
|
+
try {
|
|
16770
|
+
await setPortPublic(codespaceName, detection.port);
|
|
16771
|
+
} catch (e) {
|
|
16772
|
+
try {
|
|
16773
|
+
devServer.kill("SIGTERM");
|
|
16774
|
+
} catch {
|
|
16775
|
+
}
|
|
16776
|
+
void postPreviewEvent({
|
|
16777
|
+
sessionId: ctx.sessionId,
|
|
16778
|
+
pluginId: ctx.pluginId,
|
|
16779
|
+
pluginAuthToken,
|
|
16780
|
+
type: "preview_error",
|
|
16781
|
+
payload: { stage: "tunnel", message: `Failed to flip port public: ${e.message}` }
|
|
16782
|
+
});
|
|
16783
|
+
return;
|
|
16784
|
+
}
|
|
16785
|
+
url = buildCodespaceUrl(codespaceName, detection.port);
|
|
16786
|
+
try {
|
|
16787
|
+
await waitForCodespacePortReady(url, 15e3);
|
|
16788
|
+
} catch (e) {
|
|
16789
|
+
try {
|
|
16790
|
+
devServer.kill("SIGTERM");
|
|
16791
|
+
} catch {
|
|
16792
|
+
}
|
|
16793
|
+
void postPreviewEvent({
|
|
16794
|
+
sessionId: ctx.sessionId,
|
|
16795
|
+
pluginId: ctx.pluginId,
|
|
16796
|
+
pluginAuthToken,
|
|
16797
|
+
type: "preview_error",
|
|
16798
|
+
payload: { stage: "tunnel", message: e.message }
|
|
16799
|
+
});
|
|
16800
|
+
return;
|
|
16801
|
+
}
|
|
16802
|
+
} else {
|
|
16803
|
+
let bin;
|
|
16804
|
+
try {
|
|
16805
|
+
bin = await resolveCloudflared();
|
|
16806
|
+
} catch (e) {
|
|
16807
|
+
try {
|
|
16808
|
+
devServer.kill("SIGTERM");
|
|
16809
|
+
} catch {
|
|
16810
|
+
}
|
|
16811
|
+
void postPreviewEvent({
|
|
16812
|
+
sessionId: ctx.sessionId,
|
|
16813
|
+
pluginId: ctx.pluginId,
|
|
16814
|
+
pluginAuthToken,
|
|
16815
|
+
type: "preview_error",
|
|
16816
|
+
payload: { stage: "tunnel", message: e.message }
|
|
16817
|
+
});
|
|
16818
|
+
return;
|
|
16819
|
+
}
|
|
16820
|
+
tunnel = (0, import_child_process15.spawn)(bin, ["tunnel", "--url", `http://localhost:${detection.port}`], {
|
|
16821
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
16822
|
+
});
|
|
16823
|
+
let parsedUrl = null;
|
|
16824
|
+
const onTunnelChunk = (chunk) => {
|
|
16825
|
+
const s = chunk.toString();
|
|
16826
|
+
if (!parsedUrl) parsedUrl = parseCloudflaredUrl(s);
|
|
16827
|
+
};
|
|
16828
|
+
tunnel.stderr.on("data", onTunnelChunk);
|
|
16829
|
+
tunnel.stdout.on("data", onTunnelChunk);
|
|
16830
|
+
const tunnelDeadline = Date.now() + 15e3;
|
|
16831
|
+
while (!parsedUrl && Date.now() < tunnelDeadline) {
|
|
16832
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
16833
|
+
}
|
|
16834
|
+
if (!parsedUrl) {
|
|
16835
|
+
try {
|
|
16836
|
+
tunnel.kill("SIGTERM");
|
|
16837
|
+
} catch {
|
|
16838
|
+
}
|
|
16839
|
+
try {
|
|
16840
|
+
devServer.kill("SIGTERM");
|
|
16841
|
+
} catch {
|
|
16842
|
+
}
|
|
16843
|
+
void postPreviewEvent({
|
|
16844
|
+
sessionId: ctx.sessionId,
|
|
16845
|
+
pluginId: ctx.pluginId,
|
|
16846
|
+
pluginAuthToken,
|
|
16847
|
+
type: "preview_error",
|
|
16848
|
+
payload: { stage: "tunnel", message: "cloudflared did not emit a URL within 15s." }
|
|
16849
|
+
});
|
|
16850
|
+
return;
|
|
16851
|
+
}
|
|
16852
|
+
url = parsedUrl;
|
|
16853
|
+
}
|
|
16854
|
+
registerPreview(ctx.sessionId, {
|
|
16855
|
+
sessionId: ctx.sessionId,
|
|
16856
|
+
devServer,
|
|
16857
|
+
tunnel,
|
|
16858
|
+
url,
|
|
16859
|
+
framework: detection.framework
|
|
16860
|
+
});
|
|
16861
|
+
log.info("preview", `ready: ${detection.framework} at ${url}`);
|
|
16862
|
+
void postPreviewEvent({
|
|
16863
|
+
sessionId: ctx.sessionId,
|
|
16864
|
+
pluginId: ctx.pluginId,
|
|
16865
|
+
pluginAuthToken,
|
|
16866
|
+
type: "preview_ready",
|
|
16867
|
+
payload: { url, framework: detection.framework, port: detection.port }
|
|
16868
|
+
});
|
|
16869
|
+
})();
|
|
16870
|
+
};
|
|
16871
|
+
var previewStopH = (ctx) => {
|
|
16872
|
+
if (!ctx.pluginAuthToken) {
|
|
16873
|
+
log.info("preview", "no pluginAuthToken \u2014 skipping stop");
|
|
16874
|
+
return;
|
|
16875
|
+
}
|
|
16876
|
+
const pluginAuthToken = ctx.pluginAuthToken;
|
|
16877
|
+
void (async () => {
|
|
16878
|
+
await killPreview(ctx.sessionId);
|
|
16879
|
+
log.info("preview", `stopped session=${ctx.sessionId}`);
|
|
16880
|
+
void postPreviewEvent({
|
|
16881
|
+
sessionId: ctx.sessionId,
|
|
16882
|
+
pluginId: ctx.pluginId,
|
|
16883
|
+
pluginAuthToken,
|
|
16884
|
+
type: "preview_stopped",
|
|
16885
|
+
payload: { reason: "user" }
|
|
16886
|
+
});
|
|
16887
|
+
})();
|
|
16888
|
+
};
|
|
16889
|
+
function runOnce(cmd, args2, cwd, env) {
|
|
16890
|
+
return new Promise((resolve5) => {
|
|
16891
|
+
const child = (0, import_child_process15.spawn)(cmd, args2, {
|
|
16892
|
+
cwd,
|
|
16893
|
+
env: { ...process.env, ...env ?? {} },
|
|
16894
|
+
stdio: "inherit"
|
|
16895
|
+
});
|
|
16896
|
+
child.once("exit", (code) => resolve5(code));
|
|
16897
|
+
child.once("error", () => resolve5(-1));
|
|
16898
|
+
});
|
|
16899
|
+
}
|
|
16900
|
+
var savePreviewConfigH = (_ctx, _cmd, parsed) => {
|
|
16901
|
+
const detection = parsed.detection;
|
|
16902
|
+
if (!detection) {
|
|
16903
|
+
log.info("preview", "save_preview_config: no detection in payload");
|
|
16904
|
+
return;
|
|
16905
|
+
}
|
|
16906
|
+
void writePreviewConfig(process.cwd(), detection).catch((err) => {
|
|
16907
|
+
log.info("preview", `save_preview_config failed: ${String(err)}`);
|
|
16908
|
+
});
|
|
16909
|
+
};
|
|
16300
16910
|
var handlers = {
|
|
16301
16911
|
start_task: startTask,
|
|
16302
16912
|
provide_input: provideInput,
|
|
@@ -16331,7 +16941,11 @@ var handlers = {
|
|
|
16331
16941
|
apply_file_review: applyFileReviewH,
|
|
16332
16942
|
request_link_credentials: requestLinkCredentialsH,
|
|
16333
16943
|
request_ai_summary: requestAiSummaryH,
|
|
16334
|
-
request_ai_insight: requestAiInsightH
|
|
16944
|
+
request_ai_insight: requestAiInsightH,
|
|
16945
|
+
request_preview_detect: requestPreviewDetectH,
|
|
16946
|
+
preview_start: previewStartH,
|
|
16947
|
+
preview_stop: previewStopH,
|
|
16948
|
+
save_preview_config: savePreviewConfigH
|
|
16335
16949
|
};
|
|
16336
16950
|
async function dispatchCommand(ctx, cmd) {
|
|
16337
16951
|
const parsed = parsePayload2(startCommandSchema, cmd.payload);
|
|
@@ -16505,6 +17119,7 @@ async function start(requestedAgent) {
|
|
|
16505
17119
|
closeAllTerminals();
|
|
16506
17120
|
cleanupAttachmentTempFiles();
|
|
16507
17121
|
killActiveSpawnAndCaptureChildren();
|
|
17122
|
+
void killAllPreviews();
|
|
16508
17123
|
void shutdownTelemetry();
|
|
16509
17124
|
process.exit(0);
|
|
16510
17125
|
}
|
|
@@ -16710,8 +17325,8 @@ async function autoLinkAfterPair(opts) {
|
|
|
16710
17325
|
}
|
|
16711
17326
|
|
|
16712
17327
|
// src/commands/pair-auto.ts
|
|
16713
|
-
var
|
|
16714
|
-
var
|
|
17328
|
+
var fs30 = __toESM(require("fs"));
|
|
17329
|
+
var os25 = __toESM(require("os"));
|
|
16715
17330
|
var import_crypto7 = require("crypto");
|
|
16716
17331
|
|
|
16717
17332
|
// src/commands/start-infra-only.ts
|
|
@@ -16879,12 +17494,12 @@ function readTokenFromArgs(args2) {
|
|
|
16879
17494
|
}
|
|
16880
17495
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
16881
17496
|
if (fileFlag) {
|
|
16882
|
-
const
|
|
17497
|
+
const path42 = fileFlag.slice("--token-file=".length);
|
|
16883
17498
|
try {
|
|
16884
|
-
const content =
|
|
16885
|
-
if (content.length === 0) fail(`--token-file ${
|
|
17499
|
+
const content = fs30.readFileSync(path42, "utf8").trim();
|
|
17500
|
+
if (content.length === 0) fail(`--token-file ${path42} is empty`);
|
|
16886
17501
|
try {
|
|
16887
|
-
|
|
17502
|
+
fs30.unlinkSync(path42);
|
|
16888
17503
|
} catch {
|
|
16889
17504
|
}
|
|
16890
17505
|
return content;
|
|
@@ -16910,7 +17525,7 @@ async function claimOnce(token, pluginId) {
|
|
|
16910
17525
|
pluginId,
|
|
16911
17526
|
ideName: "codeam-cli (codespace)",
|
|
16912
17527
|
ideVersion: process.env.npm_package_version ?? "unknown",
|
|
16913
|
-
hostname:
|
|
17528
|
+
hostname: os25.hostname(),
|
|
16914
17529
|
codespaceName: process.env.CODESPACE_NAME ?? "",
|
|
16915
17530
|
// Current git branch of the codespace's working directory, so the
|
|
16916
17531
|
// backend can populate `PairedSession.branch` for the codespace pair.
|
|
@@ -17147,11 +17762,11 @@ async function logout() {
|
|
|
17147
17762
|
var import_picocolors10 = __toESM(require("picocolors"));
|
|
17148
17763
|
|
|
17149
17764
|
// src/services/providers/github-codespaces.ts
|
|
17150
|
-
var
|
|
17151
|
-
var
|
|
17765
|
+
var import_child_process16 = require("child_process");
|
|
17766
|
+
var import_util4 = require("util");
|
|
17152
17767
|
var import_picocolors8 = __toESM(require("picocolors"));
|
|
17153
|
-
var
|
|
17154
|
-
var
|
|
17768
|
+
var path36 = __toESM(require("path"));
|
|
17769
|
+
var execFileP5 = (0, import_util4.promisify)(import_child_process16.execFile);
|
|
17155
17770
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
17156
17771
|
function resetStdinForChild() {
|
|
17157
17772
|
if (process.stdin.isTTY) {
|
|
@@ -17168,11 +17783,11 @@ var GitHubCodespacesProvider = class {
|
|
|
17168
17783
|
available = true;
|
|
17169
17784
|
async authorize() {
|
|
17170
17785
|
try {
|
|
17171
|
-
await
|
|
17786
|
+
await execFileP5("gh", ["--version"], { maxBuffer: MAX_BUFFER });
|
|
17172
17787
|
} catch {
|
|
17173
17788
|
await this.tryInstallGh();
|
|
17174
17789
|
try {
|
|
17175
|
-
await
|
|
17790
|
+
await execFileP5("gh", ["--version"], { maxBuffer: MAX_BUFFER });
|
|
17176
17791
|
} catch {
|
|
17177
17792
|
throw new Error(
|
|
17178
17793
|
[
|
|
@@ -17188,14 +17803,14 @@ var GitHubCodespacesProvider = class {
|
|
|
17188
17803
|
}
|
|
17189
17804
|
let isAuthed = false;
|
|
17190
17805
|
try {
|
|
17191
|
-
await
|
|
17806
|
+
await execFileP5("gh", ["auth", "status"], { maxBuffer: MAX_BUFFER });
|
|
17192
17807
|
isAuthed = true;
|
|
17193
17808
|
} catch {
|
|
17194
17809
|
}
|
|
17195
17810
|
if (!isAuthed) {
|
|
17196
17811
|
resetStdinForChild();
|
|
17197
17812
|
await new Promise((resolve5, reject) => {
|
|
17198
|
-
const proc = (0,
|
|
17813
|
+
const proc = (0, import_child_process16.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
|
|
17199
17814
|
stdio: "inherit"
|
|
17200
17815
|
});
|
|
17201
17816
|
proc.on("exit", (code) => {
|
|
@@ -17229,7 +17844,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17229
17844
|
wt(noteLines.join("\n"), "One more permission needed");
|
|
17230
17845
|
resetStdinForChild();
|
|
17231
17846
|
const refreshCode = await new Promise((resolve5, reject) => {
|
|
17232
|
-
const proc = (0,
|
|
17847
|
+
const proc = (0, import_child_process16.spawn)(
|
|
17233
17848
|
"gh",
|
|
17234
17849
|
["auth", "refresh", "-h", "github.com", "-s", "codespace"],
|
|
17235
17850
|
{ stdio: "inherit" }
|
|
@@ -17264,7 +17879,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17264
17879
|
*/
|
|
17265
17880
|
async getActiveGhUser() {
|
|
17266
17881
|
try {
|
|
17267
|
-
const { stdout } = await
|
|
17882
|
+
const { stdout } = await execFileP5(
|
|
17268
17883
|
"gh",
|
|
17269
17884
|
["api", "user", "--jq", ".login"],
|
|
17270
17885
|
{ maxBuffer: MAX_BUFFER }
|
|
@@ -17284,7 +17899,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17284
17899
|
*/
|
|
17285
17900
|
async hasCodespaceScope() {
|
|
17286
17901
|
try {
|
|
17287
|
-
const { stdout } = await
|
|
17902
|
+
const { stdout } = await execFileP5(
|
|
17288
17903
|
"gh",
|
|
17289
17904
|
["api", "-i", "user"],
|
|
17290
17905
|
{ maxBuffer: MAX_BUFFER }
|
|
@@ -17333,7 +17948,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17333
17948
|
let installCmd = null;
|
|
17334
17949
|
if (platform2 === "darwin") {
|
|
17335
17950
|
try {
|
|
17336
|
-
await
|
|
17951
|
+
await execFileP5("brew", ["--version"], { maxBuffer: MAX_BUFFER });
|
|
17337
17952
|
} catch {
|
|
17338
17953
|
wt(
|
|
17339
17954
|
[
|
|
@@ -17352,7 +17967,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17352
17967
|
};
|
|
17353
17968
|
} else if (platform2 === "win32") {
|
|
17354
17969
|
try {
|
|
17355
|
-
await
|
|
17970
|
+
await execFileP5("winget", ["--version"], { maxBuffer: MAX_BUFFER });
|
|
17356
17971
|
} catch {
|
|
17357
17972
|
wt(
|
|
17358
17973
|
[
|
|
@@ -17379,7 +17994,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17379
17994
|
O2.step(`Installing gh via ${installCmd.describe}\u2026`);
|
|
17380
17995
|
resetStdinForChild();
|
|
17381
17996
|
const ok = await new Promise((resolve5) => {
|
|
17382
|
-
const proc = (0,
|
|
17997
|
+
const proc = (0, import_child_process16.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
|
|
17383
17998
|
proc.on("exit", (code) => resolve5(code === 0));
|
|
17384
17999
|
proc.on("error", () => resolve5(false));
|
|
17385
18000
|
});
|
|
@@ -17406,7 +18021,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17406
18021
|
);
|
|
17407
18022
|
resetStdinForChild();
|
|
17408
18023
|
await new Promise((resolve5, reject) => {
|
|
17409
|
-
const proc = (0,
|
|
18024
|
+
const proc = (0, import_child_process16.spawn)(
|
|
17410
18025
|
"gh",
|
|
17411
18026
|
["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
|
|
17412
18027
|
{ stdio: "inherit" }
|
|
@@ -17431,7 +18046,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17431
18046
|
"200"
|
|
17432
18047
|
);
|
|
17433
18048
|
try {
|
|
17434
|
-
const { stdout } = await
|
|
18049
|
+
const { stdout } = await execFileP5("gh", args2, { maxBuffer: MAX_BUFFER });
|
|
17435
18050
|
return JSON.parse(stdout);
|
|
17436
18051
|
} catch {
|
|
17437
18052
|
return [];
|
|
@@ -17440,7 +18055,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17440
18055
|
const own = await fetchRepos();
|
|
17441
18056
|
let orgRepos = [];
|
|
17442
18057
|
try {
|
|
17443
|
-
const { stdout } = await
|
|
18058
|
+
const { stdout } = await execFileP5(
|
|
17444
18059
|
"gh",
|
|
17445
18060
|
["api", "--paginate", "user/orgs", "--jq", ".[].login"],
|
|
17446
18061
|
{ maxBuffer: MAX_BUFFER }
|
|
@@ -17477,7 +18092,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17477
18092
|
*/
|
|
17478
18093
|
async listMachineTypes(projectId) {
|
|
17479
18094
|
try {
|
|
17480
|
-
const { stdout } = await
|
|
18095
|
+
const { stdout } = await execFileP5(
|
|
17481
18096
|
"gh",
|
|
17482
18097
|
["api", `/repos/${projectId}/codespaces/machines`],
|
|
17483
18098
|
{ maxBuffer: MAX_BUFFER }
|
|
@@ -17508,7 +18123,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17508
18123
|
const machine = machineTypeId ?? await this.pickDefaultMachine(projectId);
|
|
17509
18124
|
const args2 = ["codespace", "create", "-R", projectId, "--default-permissions"];
|
|
17510
18125
|
if (machine) args2.push("-m", machine);
|
|
17511
|
-
const { stdout } = await
|
|
18126
|
+
const { stdout } = await execFileP5(
|
|
17512
18127
|
"gh",
|
|
17513
18128
|
args2,
|
|
17514
18129
|
{ maxBuffer: MAX_BUFFER, timeout: 12e4 }
|
|
@@ -17548,7 +18163,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17548
18163
|
async waitUntilAvailable(name) {
|
|
17549
18164
|
const deadline = Date.now() + 5 * 60 * 1e3;
|
|
17550
18165
|
while (Date.now() < deadline) {
|
|
17551
|
-
const { stdout } = await
|
|
18166
|
+
const { stdout } = await execFileP5(
|
|
17552
18167
|
"gh",
|
|
17553
18168
|
["codespace", "list", "--json", "name,state"],
|
|
17554
18169
|
{ maxBuffer: MAX_BUFFER }
|
|
@@ -17566,7 +18181,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17566
18181
|
}
|
|
17567
18182
|
async exec(workspaceId, command2) {
|
|
17568
18183
|
try {
|
|
17569
|
-
const { stdout, stderr } = await
|
|
18184
|
+
const { stdout, stderr } = await execFileP5(
|
|
17570
18185
|
"gh",
|
|
17571
18186
|
["codespace", "ssh", "-c", workspaceId, "--", command2],
|
|
17572
18187
|
{ maxBuffer: MAX_BUFFER, timeout: 6e5 }
|
|
@@ -17584,7 +18199,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17584
18199
|
async streamCommand(workspaceId, command2) {
|
|
17585
18200
|
resetStdinForChild();
|
|
17586
18201
|
return new Promise((resolve5, reject) => {
|
|
17587
|
-
const proc = (0,
|
|
18202
|
+
const proc = (0, import_child_process16.spawn)(
|
|
17588
18203
|
"gh",
|
|
17589
18204
|
["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
|
|
17590
18205
|
{ stdio: "inherit" }
|
|
@@ -17611,11 +18226,11 @@ var GitHubCodespacesProvider = class {
|
|
|
17611
18226
|
`mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
|
|
17612
18227
|
];
|
|
17613
18228
|
await new Promise((resolve5, reject) => {
|
|
17614
|
-
const tar = (0,
|
|
18229
|
+
const tar = (0, import_child_process16.spawn)("tar", tarArgs, {
|
|
17615
18230
|
stdio: ["ignore", "pipe", "pipe"],
|
|
17616
18231
|
env: tarEnv
|
|
17617
18232
|
});
|
|
17618
|
-
const ssh = (0,
|
|
18233
|
+
const ssh = (0, import_child_process16.spawn)("gh", sshArgs, {
|
|
17619
18234
|
stdio: [tar.stdout, "pipe", "pipe"]
|
|
17620
18235
|
});
|
|
17621
18236
|
let tarErr = "";
|
|
@@ -17639,7 +18254,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17639
18254
|
});
|
|
17640
18255
|
}
|
|
17641
18256
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
17642
|
-
const remoteDir =
|
|
18257
|
+
const remoteDir = path36.posix.dirname(remotePath);
|
|
17643
18258
|
const parts = [
|
|
17644
18259
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
17645
18260
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -17649,7 +18264,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17649
18264
|
}
|
|
17650
18265
|
const cmd = parts.join(" && ");
|
|
17651
18266
|
await new Promise((resolve5, reject) => {
|
|
17652
|
-
const proc = (0,
|
|
18267
|
+
const proc = (0, import_child_process16.spawn)(
|
|
17653
18268
|
"gh",
|
|
17654
18269
|
["codespace", "ssh", "-c", workspaceId, "--", cmd],
|
|
17655
18270
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -17671,7 +18286,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17671
18286
|
try {
|
|
17672
18287
|
const args2 = ["codespace", "list", "--json", "name,displayName,state,lastUsedAt"];
|
|
17673
18288
|
if (projectId) args2.push("--repo", projectId);
|
|
17674
|
-
const { stdout } = await
|
|
18289
|
+
const { stdout } = await execFileP5("gh", args2, { maxBuffer: MAX_BUFFER });
|
|
17675
18290
|
const list = JSON.parse(stdout);
|
|
17676
18291
|
return list.map((c2) => ({
|
|
17677
18292
|
id: c2.name,
|
|
@@ -17686,7 +18301,7 @@ var GitHubCodespacesProvider = class {
|
|
|
17686
18301
|
}
|
|
17687
18302
|
async startWorkspace(workspaceId) {
|
|
17688
18303
|
try {
|
|
17689
|
-
await
|
|
18304
|
+
await execFileP5(
|
|
17690
18305
|
"gh",
|
|
17691
18306
|
["api", "-X", "POST", `/user/codespaces/${workspaceId}/start`],
|
|
17692
18307
|
{ maxBuffer: MAX_BUFFER, timeout: 6e4 }
|
|
@@ -17707,11 +18322,11 @@ function shellQuote(s) {
|
|
|
17707
18322
|
}
|
|
17708
18323
|
|
|
17709
18324
|
// src/services/providers/gitpod.ts
|
|
17710
|
-
var
|
|
17711
|
-
var
|
|
17712
|
-
var
|
|
18325
|
+
var import_child_process17 = require("child_process");
|
|
18326
|
+
var import_util5 = require("util");
|
|
18327
|
+
var path37 = __toESM(require("path"));
|
|
17713
18328
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
17714
|
-
var
|
|
18329
|
+
var execFileP6 = (0, import_util5.promisify)(import_child_process17.execFile);
|
|
17715
18330
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
17716
18331
|
function resetStdinForChild2() {
|
|
17717
18332
|
if (process.stdin.isTTY) {
|
|
@@ -17728,7 +18343,7 @@ var GitpodProvider = class {
|
|
|
17728
18343
|
available = true;
|
|
17729
18344
|
async authorize() {
|
|
17730
18345
|
try {
|
|
17731
|
-
await
|
|
18346
|
+
await execFileP6("gitpod", ["--version"], { maxBuffer: MAX_BUFFER2 });
|
|
17732
18347
|
} catch {
|
|
17733
18348
|
throw new Error(
|
|
17734
18349
|
[
|
|
@@ -17741,7 +18356,7 @@ var GitpodProvider = class {
|
|
|
17741
18356
|
);
|
|
17742
18357
|
}
|
|
17743
18358
|
try {
|
|
17744
|
-
await
|
|
18359
|
+
await execFileP6("gitpod", ["whoami"], { maxBuffer: MAX_BUFFER2 });
|
|
17745
18360
|
return;
|
|
17746
18361
|
} catch {
|
|
17747
18362
|
}
|
|
@@ -17751,7 +18366,7 @@ var GitpodProvider = class {
|
|
|
17751
18366
|
);
|
|
17752
18367
|
resetStdinForChild2();
|
|
17753
18368
|
await new Promise((resolve5, reject) => {
|
|
17754
|
-
const proc = (0,
|
|
18369
|
+
const proc = (0, import_child_process17.spawn)("gitpod", ["login"], { stdio: "inherit" });
|
|
17755
18370
|
proc.on("exit", (code) => {
|
|
17756
18371
|
if (code === 0) resolve5();
|
|
17757
18372
|
else reject(new Error("gitpod login failed."));
|
|
@@ -17761,7 +18376,7 @@ var GitpodProvider = class {
|
|
|
17761
18376
|
}
|
|
17762
18377
|
async listProjects() {
|
|
17763
18378
|
try {
|
|
17764
|
-
const { stdout } = await
|
|
18379
|
+
const { stdout } = await execFileP6(
|
|
17765
18380
|
"gitpod",
|
|
17766
18381
|
["workspace", "list", "--output", "json", "--limit", "200"],
|
|
17767
18382
|
{ maxBuffer: MAX_BUFFER2 }
|
|
@@ -17794,7 +18409,7 @@ var GitpodProvider = class {
|
|
|
17794
18409
|
async createWorkspace(projectId, machineTypeId) {
|
|
17795
18410
|
const args2 = ["workspace", "create", projectId, "--start", "--output", "json"];
|
|
17796
18411
|
if (machineTypeId) args2.push("--class", machineTypeId);
|
|
17797
|
-
const { stdout } = await
|
|
18412
|
+
const { stdout } = await execFileP6("gitpod", args2, {
|
|
17798
18413
|
maxBuffer: MAX_BUFFER2,
|
|
17799
18414
|
timeout: 3e5
|
|
17800
18415
|
});
|
|
@@ -17818,7 +18433,7 @@ var GitpodProvider = class {
|
|
|
17818
18433
|
const deadline = Date.now() + 5 * 60 * 1e3;
|
|
17819
18434
|
while (Date.now() < deadline) {
|
|
17820
18435
|
try {
|
|
17821
|
-
const { stdout } = await
|
|
18436
|
+
const { stdout } = await execFileP6(
|
|
17822
18437
|
"gitpod",
|
|
17823
18438
|
["workspace", "get", workspaceId, "--output", "json"],
|
|
17824
18439
|
{ maxBuffer: MAX_BUFFER2 }
|
|
@@ -17836,7 +18451,7 @@ var GitpodProvider = class {
|
|
|
17836
18451
|
}
|
|
17837
18452
|
async listMachineTypes(_projectId) {
|
|
17838
18453
|
try {
|
|
17839
|
-
const { stdout } = await
|
|
18454
|
+
const { stdout } = await execFileP6(
|
|
17840
18455
|
"gitpod",
|
|
17841
18456
|
["organization", "list-classes", "--output", "json"],
|
|
17842
18457
|
{ maxBuffer: MAX_BUFFER2 }
|
|
@@ -17854,7 +18469,7 @@ var GitpodProvider = class {
|
|
|
17854
18469
|
async listExistingWorkspaces(projectId) {
|
|
17855
18470
|
try {
|
|
17856
18471
|
const args2 = ["workspace", "list", "--output", "json", "--limit", "200"];
|
|
17857
|
-
const { stdout } = await
|
|
18472
|
+
const { stdout } = await execFileP6("gitpod", args2, { maxBuffer: MAX_BUFFER2 });
|
|
17858
18473
|
const list = JSON.parse(stdout);
|
|
17859
18474
|
return list.filter((w3) => !projectId || w3.contextUrl === projectId).map((w3) => ({
|
|
17860
18475
|
id: w3.id,
|
|
@@ -17869,7 +18484,7 @@ var GitpodProvider = class {
|
|
|
17869
18484
|
}
|
|
17870
18485
|
async startWorkspace(workspaceId) {
|
|
17871
18486
|
try {
|
|
17872
|
-
await
|
|
18487
|
+
await execFileP6(
|
|
17873
18488
|
"gitpod",
|
|
17874
18489
|
["workspace", "start", workspaceId],
|
|
17875
18490
|
{ maxBuffer: MAX_BUFFER2, timeout: 6e4 }
|
|
@@ -17885,7 +18500,7 @@ var GitpodProvider = class {
|
|
|
17885
18500
|
}
|
|
17886
18501
|
async exec(workspaceId, command2) {
|
|
17887
18502
|
try {
|
|
17888
|
-
const { stdout, stderr } = await
|
|
18503
|
+
const { stdout, stderr } = await execFileP6(
|
|
17889
18504
|
"gitpod",
|
|
17890
18505
|
["workspace", "ssh", workspaceId, "--", command2],
|
|
17891
18506
|
{ maxBuffer: MAX_BUFFER2, timeout: 6e5 }
|
|
@@ -17903,7 +18518,7 @@ var GitpodProvider = class {
|
|
|
17903
18518
|
async streamCommand(workspaceId, command2) {
|
|
17904
18519
|
resetStdinForChild2();
|
|
17905
18520
|
return new Promise((resolve5, reject) => {
|
|
17906
|
-
const proc = (0,
|
|
18521
|
+
const proc = (0, import_child_process17.spawn)(
|
|
17907
18522
|
"gitpod",
|
|
17908
18523
|
["workspace", "ssh", workspaceId, "--", "-tt", command2],
|
|
17909
18524
|
{ stdio: "inherit" }
|
|
@@ -17923,11 +18538,11 @@ var GitpodProvider = class {
|
|
|
17923
18538
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
17924
18539
|
const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
|
|
17925
18540
|
await new Promise((resolve5, reject) => {
|
|
17926
|
-
const tar = (0,
|
|
18541
|
+
const tar = (0, import_child_process17.spawn)("tar", tarArgs, {
|
|
17927
18542
|
stdio: ["ignore", "pipe", "pipe"],
|
|
17928
18543
|
env: tarEnv
|
|
17929
18544
|
});
|
|
17930
|
-
const ssh = (0,
|
|
18545
|
+
const ssh = (0, import_child_process17.spawn)(
|
|
17931
18546
|
"gitpod",
|
|
17932
18547
|
["workspace", "ssh", workspaceId, "--", remoteCmd],
|
|
17933
18548
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -17949,7 +18564,7 @@ var GitpodProvider = class {
|
|
|
17949
18564
|
});
|
|
17950
18565
|
}
|
|
17951
18566
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
17952
|
-
const remoteDir =
|
|
18567
|
+
const remoteDir = path37.posix.dirname(remotePath);
|
|
17953
18568
|
const parts = [
|
|
17954
18569
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
17955
18570
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -17959,7 +18574,7 @@ var GitpodProvider = class {
|
|
|
17959
18574
|
}
|
|
17960
18575
|
const cmd = parts.join(" && ");
|
|
17961
18576
|
await new Promise((resolve5, reject) => {
|
|
17962
|
-
const proc = (0,
|
|
18577
|
+
const proc = (0, import_child_process17.spawn)(
|
|
17963
18578
|
"gitpod",
|
|
17964
18579
|
["workspace", "ssh", workspaceId, "--", cmd],
|
|
17965
18580
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -17983,10 +18598,10 @@ function shellQuote2(s) {
|
|
|
17983
18598
|
}
|
|
17984
18599
|
|
|
17985
18600
|
// src/services/providers/gitlab-workspaces.ts
|
|
17986
|
-
var
|
|
17987
|
-
var
|
|
17988
|
-
var
|
|
17989
|
-
var
|
|
18601
|
+
var import_child_process18 = require("child_process");
|
|
18602
|
+
var import_util6 = require("util");
|
|
18603
|
+
var path38 = __toESM(require("path"));
|
|
18604
|
+
var execFileP7 = (0, import_util6.promisify)(import_child_process18.execFile);
|
|
17990
18605
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
17991
18606
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
17992
18607
|
function resetStdinForChild3() {
|
|
@@ -18004,7 +18619,7 @@ var GitLabWorkspacesProvider = class {
|
|
|
18004
18619
|
available = true;
|
|
18005
18620
|
async authorize() {
|
|
18006
18621
|
try {
|
|
18007
|
-
await
|
|
18622
|
+
await execFileP7("glab", ["--version"], { maxBuffer: MAX_BUFFER3 });
|
|
18008
18623
|
} catch {
|
|
18009
18624
|
throw new Error(
|
|
18010
18625
|
[
|
|
@@ -18018,7 +18633,7 @@ var GitLabWorkspacesProvider = class {
|
|
|
18018
18633
|
);
|
|
18019
18634
|
}
|
|
18020
18635
|
try {
|
|
18021
|
-
await
|
|
18636
|
+
await execFileP7("glab", ["auth", "status"], { maxBuffer: MAX_BUFFER3 });
|
|
18022
18637
|
return;
|
|
18023
18638
|
} catch {
|
|
18024
18639
|
}
|
|
@@ -18028,7 +18643,7 @@ var GitLabWorkspacesProvider = class {
|
|
|
18028
18643
|
);
|
|
18029
18644
|
resetStdinForChild3();
|
|
18030
18645
|
await new Promise((resolve5, reject) => {
|
|
18031
|
-
const proc = (0,
|
|
18646
|
+
const proc = (0, import_child_process18.spawn)(
|
|
18032
18647
|
"glab",
|
|
18033
18648
|
["auth", "login", "--scopes", "api,read_user,read_repository"],
|
|
18034
18649
|
{ stdio: "inherit" }
|
|
@@ -18042,7 +18657,7 @@ var GitLabWorkspacesProvider = class {
|
|
|
18042
18657
|
}
|
|
18043
18658
|
async listProjects() {
|
|
18044
18659
|
try {
|
|
18045
|
-
const { stdout } = await
|
|
18660
|
+
const { stdout } = await execFileP7(
|
|
18046
18661
|
"glab",
|
|
18047
18662
|
["repo", "list", "--per-page", "200", "--output", "json"],
|
|
18048
18663
|
{ maxBuffer: MAX_BUFFER3 }
|
|
@@ -18174,7 +18789,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
18174
18789
|
async exec(workspaceId, command2) {
|
|
18175
18790
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
18176
18791
|
try {
|
|
18177
|
-
const { stdout, stderr } = await
|
|
18792
|
+
const { stdout, stderr } = await execFileP7(
|
|
18178
18793
|
"ssh",
|
|
18179
18794
|
[
|
|
18180
18795
|
"-o",
|
|
@@ -18200,7 +18815,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
18200
18815
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
18201
18816
|
resetStdinForChild3();
|
|
18202
18817
|
return new Promise((resolve5, reject) => {
|
|
18203
|
-
const proc = (0,
|
|
18818
|
+
const proc = (0, import_child_process18.spawn)(
|
|
18204
18819
|
"ssh",
|
|
18205
18820
|
["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
|
|
18206
18821
|
{ stdio: "inherit" }
|
|
@@ -18221,8 +18836,8 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
18221
18836
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
18222
18837
|
const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
|
|
18223
18838
|
await new Promise((resolve5, reject) => {
|
|
18224
|
-
const tar = (0,
|
|
18225
|
-
const ssh = (0,
|
|
18839
|
+
const tar = (0, import_child_process18.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
18840
|
+
const ssh = (0, import_child_process18.spawn)(
|
|
18226
18841
|
"ssh",
|
|
18227
18842
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, remoteCmd],
|
|
18228
18843
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -18245,14 +18860,14 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
18245
18860
|
}
|
|
18246
18861
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
18247
18862
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
18248
|
-
const remoteDir =
|
|
18863
|
+
const remoteDir = path38.posix.dirname(remotePath);
|
|
18249
18864
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
18250
18865
|
if (options.mode != null) {
|
|
18251
18866
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
18252
18867
|
}
|
|
18253
18868
|
const cmd = parts.join(" && ");
|
|
18254
18869
|
await new Promise((resolve5, reject) => {
|
|
18255
|
-
const proc = (0,
|
|
18870
|
+
const proc = (0, import_child_process18.spawn)(
|
|
18256
18871
|
"ssh",
|
|
18257
18872
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
|
|
18258
18873
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -18277,7 +18892,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
18277
18892
|
*/
|
|
18278
18893
|
async getGlabToken() {
|
|
18279
18894
|
try {
|
|
18280
|
-
const { stdout, stderr } = await
|
|
18895
|
+
const { stdout, stderr } = await execFileP7(
|
|
18281
18896
|
"glab",
|
|
18282
18897
|
["auth", "status", "--show-token"],
|
|
18283
18898
|
{ maxBuffer: MAX_BUFFER3 }
|
|
@@ -18311,10 +18926,10 @@ function shellQuote3(s) {
|
|
|
18311
18926
|
}
|
|
18312
18927
|
|
|
18313
18928
|
// src/services/providers/railway.ts
|
|
18314
|
-
var
|
|
18315
|
-
var
|
|
18316
|
-
var
|
|
18317
|
-
var
|
|
18929
|
+
var import_child_process19 = require("child_process");
|
|
18930
|
+
var import_util7 = require("util");
|
|
18931
|
+
var path39 = __toESM(require("path"));
|
|
18932
|
+
var execFileP8 = (0, import_util7.promisify)(import_child_process19.execFile);
|
|
18318
18933
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
18319
18934
|
function resetStdinForChild4() {
|
|
18320
18935
|
if (process.stdin.isTTY) {
|
|
@@ -18331,7 +18946,7 @@ var RailwayProvider = class {
|
|
|
18331
18946
|
available = true;
|
|
18332
18947
|
async authorize() {
|
|
18333
18948
|
try {
|
|
18334
|
-
await
|
|
18949
|
+
await execFileP8("railway", ["--version"], { maxBuffer: MAX_BUFFER4 });
|
|
18335
18950
|
} catch {
|
|
18336
18951
|
throw new Error(
|
|
18337
18952
|
[
|
|
@@ -18345,7 +18960,7 @@ var RailwayProvider = class {
|
|
|
18345
18960
|
);
|
|
18346
18961
|
}
|
|
18347
18962
|
try {
|
|
18348
|
-
await
|
|
18963
|
+
await execFileP8("railway", ["whoami"], { maxBuffer: MAX_BUFFER4 });
|
|
18349
18964
|
return;
|
|
18350
18965
|
} catch {
|
|
18351
18966
|
}
|
|
@@ -18355,7 +18970,7 @@ var RailwayProvider = class {
|
|
|
18355
18970
|
);
|
|
18356
18971
|
resetStdinForChild4();
|
|
18357
18972
|
await new Promise((resolve5, reject) => {
|
|
18358
|
-
const proc = (0,
|
|
18973
|
+
const proc = (0, import_child_process19.spawn)("railway", ["login"], { stdio: "inherit" });
|
|
18359
18974
|
proc.on("exit", (code) => {
|
|
18360
18975
|
if (code === 0) resolve5();
|
|
18361
18976
|
else reject(new Error("railway login failed."));
|
|
@@ -18365,7 +18980,7 @@ var RailwayProvider = class {
|
|
|
18365
18980
|
}
|
|
18366
18981
|
async listProjects() {
|
|
18367
18982
|
try {
|
|
18368
|
-
const { stdout } = await
|
|
18983
|
+
const { stdout } = await execFileP8(
|
|
18369
18984
|
"railway",
|
|
18370
18985
|
["list", "--json"],
|
|
18371
18986
|
{ maxBuffer: MAX_BUFFER4 }
|
|
@@ -18381,7 +18996,7 @@ var RailwayProvider = class {
|
|
|
18381
18996
|
}));
|
|
18382
18997
|
} catch {
|
|
18383
18998
|
try {
|
|
18384
|
-
const { stdout } = await
|
|
18999
|
+
const { stdout } = await execFileP8("railway", ["list"], { maxBuffer: MAX_BUFFER4 });
|
|
18385
19000
|
const projects = [];
|
|
18386
19001
|
for (const line of stdout.split("\n")) {
|
|
18387
19002
|
const trimmed = line.trim();
|
|
@@ -18432,7 +19047,7 @@ var RailwayProvider = class {
|
|
|
18432
19047
|
async listExistingWorkspaces(projectId) {
|
|
18433
19048
|
if (!projectId) return [];
|
|
18434
19049
|
try {
|
|
18435
|
-
const { stdout } = await
|
|
19050
|
+
const { stdout } = await execFileP8(
|
|
18436
19051
|
"railway",
|
|
18437
19052
|
["service", "list", "--project", projectId, "--json"],
|
|
18438
19053
|
{ maxBuffer: MAX_BUFFER4 }
|
|
@@ -18457,7 +19072,7 @@ var RailwayProvider = class {
|
|
|
18457
19072
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
18458
19073
|
}
|
|
18459
19074
|
try {
|
|
18460
|
-
await
|
|
19075
|
+
await execFileP8(
|
|
18461
19076
|
"railway",
|
|
18462
19077
|
["service", "restart", "--service", serviceId, "--project", projectId],
|
|
18463
19078
|
{ maxBuffer: MAX_BUFFER4, timeout: 6e4 }
|
|
@@ -18476,7 +19091,7 @@ var RailwayProvider = class {
|
|
|
18476
19091
|
};
|
|
18477
19092
|
}
|
|
18478
19093
|
try {
|
|
18479
|
-
const { stdout, stderr } = await
|
|
19094
|
+
const { stdout, stderr } = await execFileP8(
|
|
18480
19095
|
"railway",
|
|
18481
19096
|
["run", "--project", projectId, "--service", serviceId, "--", "bash", "-lc", command2],
|
|
18482
19097
|
{ maxBuffer: MAX_BUFFER4, timeout: 6e5 }
|
|
@@ -18498,7 +19113,7 @@ var RailwayProvider = class {
|
|
|
18498
19113
|
}
|
|
18499
19114
|
resetStdinForChild4();
|
|
18500
19115
|
return new Promise((resolve5, reject) => {
|
|
18501
|
-
const proc = (0,
|
|
19116
|
+
const proc = (0, import_child_process19.spawn)(
|
|
18502
19117
|
"railway",
|
|
18503
19118
|
["shell", "--project", projectId, "--service", serviceId, "--command", command2],
|
|
18504
19119
|
{ stdio: "inherit" }
|
|
@@ -18522,8 +19137,8 @@ var RailwayProvider = class {
|
|
|
18522
19137
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
18523
19138
|
const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
|
|
18524
19139
|
await new Promise((resolve5, reject) => {
|
|
18525
|
-
const tar = (0,
|
|
18526
|
-
const sh = (0,
|
|
19140
|
+
const tar = (0, import_child_process19.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
19141
|
+
const sh = (0, import_child_process19.spawn)(
|
|
18527
19142
|
"railway",
|
|
18528
19143
|
["shell", "--project", projectId, "--service", serviceId, "--command", remoteCmd],
|
|
18529
19144
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -18549,14 +19164,14 @@ var RailwayProvider = class {
|
|
|
18549
19164
|
if (!projectId || !serviceId) {
|
|
18550
19165
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
18551
19166
|
}
|
|
18552
|
-
const remoteDir =
|
|
19167
|
+
const remoteDir = path39.posix.dirname(remotePath);
|
|
18553
19168
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
18554
19169
|
if (options.mode != null) {
|
|
18555
19170
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
18556
19171
|
}
|
|
18557
19172
|
const cmd = parts.join(" && ");
|
|
18558
19173
|
await new Promise((resolve5, reject) => {
|
|
18559
|
-
const proc = (0,
|
|
19174
|
+
const proc = (0, import_child_process19.spawn)(
|
|
18560
19175
|
"railway",
|
|
18561
19176
|
["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
|
|
18562
19177
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -19080,10 +19695,10 @@ async function probeCodeamPair(provider, workspace) {
|
|
|
19080
19695
|
}
|
|
19081
19696
|
async function stopWorkspaceFromLocal(target) {
|
|
19082
19697
|
if (target.provider.id === "github-codespaces") {
|
|
19083
|
-
const { execFile:
|
|
19084
|
-
const { promisify:
|
|
19085
|
-
const
|
|
19086
|
-
await
|
|
19698
|
+
const { execFile: execFile9 } = await import("child_process");
|
|
19699
|
+
const { promisify: promisify10 } = await import("util");
|
|
19700
|
+
const execFileP9 = promisify10(execFile9);
|
|
19701
|
+
await execFileP9("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
|
|
19087
19702
|
return;
|
|
19088
19703
|
}
|
|
19089
19704
|
}
|
|
@@ -19092,8 +19707,8 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
19092
19707
|
var import_node_dns = require("dns");
|
|
19093
19708
|
var import_node_util4 = require("util");
|
|
19094
19709
|
var import_node_crypto6 = require("crypto");
|
|
19095
|
-
var
|
|
19096
|
-
var
|
|
19710
|
+
var fs31 = __toESM(require("fs"));
|
|
19711
|
+
var path40 = __toESM(require("path"));
|
|
19097
19712
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
19098
19713
|
var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
|
|
19099
19714
|
async function checkDns(apiBase) {
|
|
@@ -19149,13 +19764,13 @@ async function checkHealth(apiBase) {
|
|
|
19149
19764
|
}
|
|
19150
19765
|
}
|
|
19151
19766
|
function checkConfigDir() {
|
|
19152
|
-
const dir =
|
|
19767
|
+
const dir = path40.join(require("os").homedir(), ".codeam");
|
|
19153
19768
|
try {
|
|
19154
|
-
|
|
19155
|
-
const probe =
|
|
19156
|
-
|
|
19157
|
-
const read =
|
|
19158
|
-
|
|
19769
|
+
fs31.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
19770
|
+
const probe = path40.join(dir, ".doctor-probe");
|
|
19771
|
+
fs31.writeFileSync(probe, "ok", { mode: 384 });
|
|
19772
|
+
const read = fs31.readFileSync(probe, "utf8");
|
|
19773
|
+
fs31.unlinkSync(probe);
|
|
19159
19774
|
if (read !== "ok") throw new Error("write/read round-trip mismatch");
|
|
19160
19775
|
return {
|
|
19161
19776
|
id: "config-dir",
|
|
@@ -19195,9 +19810,9 @@ function checkSessions() {
|
|
|
19195
19810
|
}
|
|
19196
19811
|
}
|
|
19197
19812
|
function checkAgentBinaries() {
|
|
19198
|
-
const
|
|
19813
|
+
const os27 = createOsStrategy();
|
|
19199
19814
|
return getEnabledAgents().map((meta) => {
|
|
19200
|
-
const found =
|
|
19815
|
+
const found = os27.findInPath(meta.binaryName);
|
|
19201
19816
|
return {
|
|
19202
19817
|
id: `agent-${meta.id}`,
|
|
19203
19818
|
label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
|
|
@@ -19219,7 +19834,7 @@ function checkNodePty() {
|
|
|
19219
19834
|
detail: "not required on this platform"
|
|
19220
19835
|
};
|
|
19221
19836
|
}
|
|
19222
|
-
const vendoredPath =
|
|
19837
|
+
const vendoredPath = path40.join(__dirname, "vendor", "node-pty");
|
|
19223
19838
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
19224
19839
|
try {
|
|
19225
19840
|
require(target);
|
|
@@ -19261,7 +19876,7 @@ function checkChokidar() {
|
|
|
19261
19876
|
}
|
|
19262
19877
|
async function doctor(args2 = []) {
|
|
19263
19878
|
const json = args2.includes("--json");
|
|
19264
|
-
const cliVersion = true ? "2.
|
|
19879
|
+
const cliVersion = true ? "2.26.1" : "0.0.0-dev";
|
|
19265
19880
|
const apiBase = resolveApiBaseUrl();
|
|
19266
19881
|
const diagnosticId = (0, import_node_crypto6.randomUUID)();
|
|
19267
19882
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -19460,7 +20075,7 @@ async function completion(args2) {
|
|
|
19460
20075
|
// src/commands/version.ts
|
|
19461
20076
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
19462
20077
|
function version2() {
|
|
19463
|
-
const v = true ? "2.
|
|
20078
|
+
const v = true ? "2.26.1" : "unknown";
|
|
19464
20079
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
19465
20080
|
}
|
|
19466
20081
|
|
|
@@ -19588,9 +20203,9 @@ function tryShowSubcommandHelp(cmd, args2) {
|
|
|
19588
20203
|
var _subcommandHelpKeys = Object.keys(HELPS);
|
|
19589
20204
|
|
|
19590
20205
|
// src/lib/updateNotifier.ts
|
|
19591
|
-
var
|
|
19592
|
-
var
|
|
19593
|
-
var
|
|
20206
|
+
var fs32 = __toESM(require("fs"));
|
|
20207
|
+
var os26 = __toESM(require("os"));
|
|
20208
|
+
var path41 = __toESM(require("path"));
|
|
19594
20209
|
var https7 = __toESM(require("https"));
|
|
19595
20210
|
var import_picocolors16 = __toESM(require("picocolors"));
|
|
19596
20211
|
var PKG_NAME = "codeam-cli";
|
|
@@ -19598,12 +20213,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
|
19598
20213
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
19599
20214
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
19600
20215
|
function cachePath() {
|
|
19601
|
-
const dir =
|
|
19602
|
-
return
|
|
20216
|
+
const dir = path41.join(os26.homedir(), ".codeam");
|
|
20217
|
+
return path41.join(dir, "update-check.json");
|
|
19603
20218
|
}
|
|
19604
20219
|
function readCache() {
|
|
19605
20220
|
try {
|
|
19606
|
-
const raw =
|
|
20221
|
+
const raw = fs32.readFileSync(cachePath(), "utf8");
|
|
19607
20222
|
const parsed = JSON.parse(raw);
|
|
19608
20223
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
19609
20224
|
return parsed;
|
|
@@ -19614,10 +20229,10 @@ function readCache() {
|
|
|
19614
20229
|
function writeCache(cache) {
|
|
19615
20230
|
try {
|
|
19616
20231
|
const file = cachePath();
|
|
19617
|
-
|
|
20232
|
+
fs32.mkdirSync(path41.dirname(file), { recursive: true });
|
|
19618
20233
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
19619
|
-
|
|
19620
|
-
|
|
20234
|
+
fs32.writeFileSync(tmp, JSON.stringify(cache));
|
|
20235
|
+
fs32.renameSync(tmp, file);
|
|
19621
20236
|
} catch {
|
|
19622
20237
|
}
|
|
19623
20238
|
}
|
|
@@ -19688,7 +20303,7 @@ function checkForUpdates() {
|
|
|
19688
20303
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
19689
20304
|
if (process.env.CI) return;
|
|
19690
20305
|
if (!process.stdout.isTTY) return;
|
|
19691
|
-
const current = true ? "2.
|
|
20306
|
+
const current = true ? "2.26.1" : null;
|
|
19692
20307
|
if (!current) return;
|
|
19693
20308
|
const cache = readCache();
|
|
19694
20309
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|