codeam-cli 2.20.0 → 2.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/index.js +288 -179
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -441,7 +441,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
441
441
|
// package.json
|
|
442
442
|
var package_default = {
|
|
443
443
|
name: "codeam-cli",
|
|
444
|
-
version: "2.20.
|
|
444
|
+
version: "2.20.2",
|
|
445
445
|
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
446
|
type: "commonjs",
|
|
447
447
|
main: "dist/index.js",
|
|
@@ -735,7 +735,7 @@ async function postLinkCredential(input) {
|
|
|
735
735
|
}
|
|
736
736
|
}
|
|
737
737
|
async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
738
|
-
return new Promise((
|
|
738
|
+
return new Promise((resolve4, reject) => {
|
|
739
739
|
const data = JSON.stringify(body);
|
|
740
740
|
const u2 = new URL(url);
|
|
741
741
|
const transport = u2.protocol === "https:" ? https : http;
|
|
@@ -767,9 +767,9 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
|
767
767
|
return;
|
|
768
768
|
}
|
|
769
769
|
try {
|
|
770
|
-
|
|
770
|
+
resolve4(JSON.parse(responseBody));
|
|
771
771
|
} catch {
|
|
772
|
-
|
|
772
|
+
resolve4(null);
|
|
773
773
|
}
|
|
774
774
|
});
|
|
775
775
|
}
|
|
@@ -784,7 +784,7 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
|
784
784
|
});
|
|
785
785
|
}
|
|
786
786
|
async function _postJson(url, body) {
|
|
787
|
-
return new Promise((
|
|
787
|
+
return new Promise((resolve4, reject) => {
|
|
788
788
|
const data = JSON.stringify(body);
|
|
789
789
|
const u2 = new URL(url);
|
|
790
790
|
const transport = u2.protocol === "https:" ? https : http;
|
|
@@ -813,9 +813,9 @@ async function _postJson(url, body) {
|
|
|
813
813
|
return;
|
|
814
814
|
}
|
|
815
815
|
try {
|
|
816
|
-
|
|
816
|
+
resolve4(JSON.parse(body2));
|
|
817
817
|
} catch {
|
|
818
|
-
|
|
818
|
+
resolve4(null);
|
|
819
819
|
}
|
|
820
820
|
});
|
|
821
821
|
}
|
|
@@ -830,7 +830,7 @@ async function _postJson(url, body) {
|
|
|
830
830
|
});
|
|
831
831
|
}
|
|
832
832
|
async function _getJson(url) {
|
|
833
|
-
return new Promise((
|
|
833
|
+
return new Promise((resolve4, reject) => {
|
|
834
834
|
const u2 = new URL(url);
|
|
835
835
|
const transport = u2.protocol === "https:" ? https : http;
|
|
836
836
|
const req = transport.request(
|
|
@@ -854,9 +854,9 @@ async function _getJson(url) {
|
|
|
854
854
|
return;
|
|
855
855
|
}
|
|
856
856
|
try {
|
|
857
|
-
|
|
857
|
+
resolve4(JSON.parse(body));
|
|
858
858
|
} catch {
|
|
859
|
-
|
|
859
|
+
resolve4(null);
|
|
860
860
|
}
|
|
861
861
|
});
|
|
862
862
|
}
|
|
@@ -3508,14 +3508,14 @@ async function addSourceContext(frames) {
|
|
|
3508
3508
|
return frames;
|
|
3509
3509
|
}
|
|
3510
3510
|
function getContextLinesFromFile(path37, ranges, output) {
|
|
3511
|
-
return new Promise((
|
|
3511
|
+
return new Promise((resolve4) => {
|
|
3512
3512
|
const stream = (0, import_node_fs.createReadStream)(path37);
|
|
3513
3513
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
3514
3514
|
input: stream
|
|
3515
3515
|
});
|
|
3516
3516
|
function destroyStreamAndResolve() {
|
|
3517
3517
|
stream.destroy();
|
|
3518
|
-
|
|
3518
|
+
resolve4();
|
|
3519
3519
|
}
|
|
3520
3520
|
let lineNumber = 0;
|
|
3521
3521
|
let currentRangeIndex = 0;
|
|
@@ -4802,9 +4802,9 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4802
4802
|
if (!waitUntil) return;
|
|
4803
4803
|
if (this.disabled || this.optedOut) return;
|
|
4804
4804
|
if (!this._waitUntilCycle) {
|
|
4805
|
-
let
|
|
4805
|
+
let resolve4;
|
|
4806
4806
|
const promise = new Promise((r) => {
|
|
4807
|
-
|
|
4807
|
+
resolve4 = r;
|
|
4808
4808
|
});
|
|
4809
4809
|
try {
|
|
4810
4810
|
waitUntil(promise);
|
|
@@ -4812,7 +4812,7 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4812
4812
|
return;
|
|
4813
4813
|
}
|
|
4814
4814
|
this._waitUntilCycle = {
|
|
4815
|
-
resolve:
|
|
4815
|
+
resolve: resolve4,
|
|
4816
4816
|
startedAt: Date.now(),
|
|
4817
4817
|
timer: void 0
|
|
4818
4818
|
};
|
|
@@ -4836,12 +4836,12 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4836
4836
|
return cycle?.resolve;
|
|
4837
4837
|
}
|
|
4838
4838
|
async resolveWaitUntilFlush() {
|
|
4839
|
-
const
|
|
4839
|
+
const resolve4 = this._consumeWaitUntilCycle();
|
|
4840
4840
|
try {
|
|
4841
4841
|
await super.flush();
|
|
4842
4842
|
} catch {
|
|
4843
4843
|
} finally {
|
|
4844
|
-
|
|
4844
|
+
resolve4?.();
|
|
4845
4845
|
}
|
|
4846
4846
|
}
|
|
4847
4847
|
getPersistedProperty(key) {
|
|
@@ -4933,15 +4933,15 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
4933
4933
|
async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
|
|
4934
4934
|
if (this.isLocalEvaluationReady()) return true;
|
|
4935
4935
|
if (void 0 === this.featureFlagsPoller) return false;
|
|
4936
|
-
return new Promise((
|
|
4936
|
+
return new Promise((resolve4) => {
|
|
4937
4937
|
const timeout = setTimeout(() => {
|
|
4938
4938
|
cleanup();
|
|
4939
|
-
|
|
4939
|
+
resolve4(false);
|
|
4940
4940
|
}, timeoutMs);
|
|
4941
4941
|
const cleanup = this._events.on("localEvaluationFlagsLoaded", (count) => {
|
|
4942
4942
|
clearTimeout(timeout);
|
|
4943
4943
|
cleanup();
|
|
4944
|
-
|
|
4944
|
+
resolve4(count > 0);
|
|
4945
4945
|
});
|
|
4946
4946
|
});
|
|
4947
4947
|
}
|
|
@@ -5378,13 +5378,13 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
|
|
|
5378
5378
|
this.context?.enter(data, options);
|
|
5379
5379
|
}
|
|
5380
5380
|
async _shutdown(shutdownTimeoutMs) {
|
|
5381
|
-
const
|
|
5381
|
+
const resolve4 = this._consumeWaitUntilCycle();
|
|
5382
5382
|
await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
|
|
5383
5383
|
this.errorTracking.shutdown();
|
|
5384
5384
|
try {
|
|
5385
5385
|
return await super._shutdown(shutdownTimeoutMs);
|
|
5386
5386
|
} finally {
|
|
5387
|
-
|
|
5387
|
+
resolve4?.();
|
|
5388
5388
|
}
|
|
5389
5389
|
}
|
|
5390
5390
|
async _requestRemoteConfigPayload(flagKey) {
|
|
@@ -5740,7 +5740,7 @@ function readAnonId() {
|
|
|
5740
5740
|
}
|
|
5741
5741
|
function superProperties() {
|
|
5742
5742
|
return {
|
|
5743
|
-
cliVersion: true ? "2.20.
|
|
5743
|
+
cliVersion: true ? "2.20.2" : "0.0.0-dev",
|
|
5744
5744
|
nodeVersion: process.version,
|
|
5745
5745
|
platform: process.platform,
|
|
5746
5746
|
arch: process.arch,
|
|
@@ -8874,15 +8874,15 @@ function runInstaller() {
|
|
|
8874
8874
|
"-Command",
|
|
8875
8875
|
"irm https://claude.ai/install.ps1 | iex"
|
|
8876
8876
|
] : ["-c", "curl -fsSL https://claude.ai/install.sh | bash"];
|
|
8877
|
-
return new Promise((
|
|
8877
|
+
return new Promise((resolve4) => {
|
|
8878
8878
|
const proc = (0, import_child_process4.spawn)(cmd, args2, { stdio: "inherit" });
|
|
8879
8879
|
proc.on("error", (err) => {
|
|
8880
8880
|
console.error(`
|
|
8881
8881
|
\u2717 Installer failed to launch: ${err.message}`);
|
|
8882
|
-
|
|
8882
|
+
resolve4(false);
|
|
8883
8883
|
});
|
|
8884
8884
|
proc.on("exit", (code) => {
|
|
8885
|
-
|
|
8885
|
+
resolve4(code === 0);
|
|
8886
8886
|
});
|
|
8887
8887
|
});
|
|
8888
8888
|
}
|
|
@@ -9045,17 +9045,17 @@ function parseUsageOutput(raw) {
|
|
|
9045
9045
|
return { percent, resetAt };
|
|
9046
9046
|
}
|
|
9047
9047
|
async function fetchClaudeQuota() {
|
|
9048
|
-
return new Promise((
|
|
9048
|
+
return new Promise((resolve4) => {
|
|
9049
9049
|
const claudeCmd = findInPath("claude") ? "claude" : "claude-code";
|
|
9050
9050
|
if (!claudeCmd) {
|
|
9051
|
-
|
|
9051
|
+
resolve4(null);
|
|
9052
9052
|
return;
|
|
9053
9053
|
}
|
|
9054
9054
|
const helperPath = path11.join(os10.tmpdir(), "codeam-quota-helper.py");
|
|
9055
9055
|
fs8.writeFileSync(helperPath, HELPER_SCRIPT, { mode: 420 });
|
|
9056
9056
|
const python = findInPath("python3") ?? findInPath("python");
|
|
9057
9057
|
if (!python) {
|
|
9058
|
-
|
|
9058
|
+
resolve4(null);
|
|
9059
9059
|
return;
|
|
9060
9060
|
}
|
|
9061
9061
|
const proc = (0, import_child_process5.spawn)(python, [helperPath, claudeCmd, "--tools", ""], {
|
|
@@ -9082,13 +9082,13 @@ async function fetchClaudeQuota() {
|
|
|
9082
9082
|
fs8.unlinkSync(helperPath);
|
|
9083
9083
|
} catch {
|
|
9084
9084
|
}
|
|
9085
|
-
|
|
9085
|
+
resolve4(result);
|
|
9086
9086
|
}, 5e3);
|
|
9087
9087
|
}, 8e3);
|
|
9088
9088
|
setTimeout(() => {
|
|
9089
9089
|
if (!resolved) {
|
|
9090
9090
|
resolved = true;
|
|
9091
|
-
|
|
9091
|
+
resolve4(null);
|
|
9092
9092
|
}
|
|
9093
9093
|
try {
|
|
9094
9094
|
proc.kill();
|
|
@@ -9531,6 +9531,9 @@ var ClaudeRuntimeStrategy = class {
|
|
|
9531
9531
|
detectInteractivePrompt(lines) {
|
|
9532
9532
|
return detectSelector(lines) ?? detectListSelector(lines);
|
|
9533
9533
|
}
|
|
9534
|
+
detectReadyPrompt(lines) {
|
|
9535
|
+
return lines.some((l) => /^\?\s.*shortcut/i.test(l.trim()));
|
|
9536
|
+
}
|
|
9534
9537
|
credentialLocator() {
|
|
9535
9538
|
return claudeCredentialLocator();
|
|
9536
9539
|
}
|
|
@@ -10411,6 +10414,9 @@ var CodexRuntimeStrategy = class {
|
|
|
10411
10414
|
detectInteractivePrompt(lines) {
|
|
10412
10415
|
return detectCodexSelector(lines);
|
|
10413
10416
|
}
|
|
10417
|
+
detectReadyPrompt(lines) {
|
|
10418
|
+
return lines.some((l) => /[│┃]\s*›/u.test(l));
|
|
10419
|
+
}
|
|
10414
10420
|
credentialLocator() {
|
|
10415
10421
|
return codexCredentialLocator();
|
|
10416
10422
|
}
|
|
@@ -10422,12 +10428,12 @@ function resolveNpm(os26) {
|
|
|
10422
10428
|
return os26.id === "win32" ? "npm.cmd" : "npm";
|
|
10423
10429
|
}
|
|
10424
10430
|
async function installCodexViaNpm(os26) {
|
|
10425
|
-
return new Promise((
|
|
10431
|
+
return new Promise((resolve4, reject) => {
|
|
10426
10432
|
const proc = (0, import_node_child_process4.spawn)(resolveNpm(os26), ["install", "-g", "@openai/codex"], {
|
|
10427
10433
|
stdio: "inherit"
|
|
10428
10434
|
});
|
|
10429
10435
|
proc.on("close", (code) => {
|
|
10430
|
-
if (code === 0)
|
|
10436
|
+
if (code === 0) resolve4();
|
|
10431
10437
|
else reject(new Error(`npm install -g @openai/codex exited ${code}`));
|
|
10432
10438
|
});
|
|
10433
10439
|
proc.on("error", (err) => {
|
|
@@ -10542,12 +10548,12 @@ async function ensureCoderabbitInstalled(os26) {
|
|
|
10542
10548
|
return false;
|
|
10543
10549
|
}
|
|
10544
10550
|
console.log("\n CodeRabbit CLI not found \u2014 installing via the official script\u2026\n");
|
|
10545
|
-
const ok = await new Promise((
|
|
10551
|
+
const ok = await new Promise((resolve4) => {
|
|
10546
10552
|
const proc = (0, import_node_child_process5.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL} | sh`], {
|
|
10547
10553
|
stdio: "inherit"
|
|
10548
10554
|
});
|
|
10549
|
-
proc.on("close", (code) =>
|
|
10550
|
-
proc.on("error", () =>
|
|
10555
|
+
proc.on("close", (code) => resolve4(code === 0));
|
|
10556
|
+
proc.on("error", () => resolve4(false));
|
|
10551
10557
|
});
|
|
10552
10558
|
if (!ok) return false;
|
|
10553
10559
|
os26.augmentPath([`${os26.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
@@ -10666,7 +10672,7 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
10666
10672
|
}
|
|
10667
10673
|
async runOneShot(input) {
|
|
10668
10674
|
const launch = await this.prepareInvocation(input);
|
|
10669
|
-
return new Promise((
|
|
10675
|
+
return new Promise((resolve4, reject) => {
|
|
10670
10676
|
const stdoutBuf = [];
|
|
10671
10677
|
const stderrBuf = [];
|
|
10672
10678
|
const proc = (0, import_node_child_process7.spawn)(launch.cmd, launch.args, {
|
|
@@ -10677,7 +10683,7 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
10677
10683
|
proc.stderr?.on("data", (b) => stderrBuf.push(b));
|
|
10678
10684
|
proc.on("error", (err) => reject(err));
|
|
10679
10685
|
proc.on("close", (code) => {
|
|
10680
|
-
|
|
10686
|
+
resolve4(
|
|
10681
10687
|
this.parseOutput({
|
|
10682
10688
|
exitCode: code ?? 0,
|
|
10683
10689
|
stdout: Buffer.concat(stdoutBuf).toString("utf8"),
|
|
@@ -10858,6 +10864,9 @@ var CursorRuntimeStrategy = class {
|
|
|
10858
10864
|
detectInteractivePrompt(lines) {
|
|
10859
10865
|
return detectCursorSelector(lines);
|
|
10860
10866
|
}
|
|
10867
|
+
detectReadyPrompt(lines) {
|
|
10868
|
+
return lines.some((l) => /[│┃]\s*[›>]\s/u.test(l));
|
|
10869
|
+
}
|
|
10861
10870
|
credentialLocator() {
|
|
10862
10871
|
return cursorCredentialLocator();
|
|
10863
10872
|
}
|
|
@@ -11065,6 +11074,12 @@ var AiderRuntimeStrategy = class {
|
|
|
11065
11074
|
detectInteractivePrompt(lines) {
|
|
11066
11075
|
return detectAiderSelector(lines);
|
|
11067
11076
|
}
|
|
11077
|
+
detectReadyPrompt(lines) {
|
|
11078
|
+
return lines.some((l) => {
|
|
11079
|
+
const t2 = l.replace(/\x1B\[[^@-~]*[@-~]/g, "").trim();
|
|
11080
|
+
return t2 === ">" || /^>\s*$/.test(t2) || /^\.\.\.\s*>\s*$/.test(t2);
|
|
11081
|
+
});
|
|
11082
|
+
}
|
|
11068
11083
|
credentialLocator() {
|
|
11069
11084
|
return aiderCredentialLocator();
|
|
11070
11085
|
}
|
|
@@ -11201,14 +11216,14 @@ var ChunkEmitter = class {
|
|
|
11201
11216
|
"chunkEmitter",
|
|
11202
11217
|
`send type=${body.type ?? "(clear)"} bytes=${payload.length} done=${body.done === true}`
|
|
11203
11218
|
);
|
|
11204
|
-
return new Promise((
|
|
11219
|
+
return new Promise((resolve4) => {
|
|
11205
11220
|
const attempt = (attemptsLeft) => {
|
|
11206
11221
|
_transport2.post(this.url, this.headers, payload).then(({ statusCode, body: resBody }) => {
|
|
11207
11222
|
const tookMs = Date.now() - t0;
|
|
11208
11223
|
if (statusCode === 410 || statusCode === 404 && /SESSION_NOT_FOUND|SESSION_GONE/.test(resBody)) {
|
|
11209
11224
|
process.stderr.write("[codeam] session was deleted/disconnected \u2014 stopping output stream.\n");
|
|
11210
11225
|
log.info("chunkEmitter", `dead status=${statusCode} took=${tookMs}ms`);
|
|
11211
|
-
|
|
11226
|
+
resolve4({ dead: true });
|
|
11212
11227
|
return;
|
|
11213
11228
|
}
|
|
11214
11229
|
if (statusCode >= 400) {
|
|
@@ -11218,7 +11233,7 @@ var ChunkEmitter = class {
|
|
|
11218
11233
|
} else {
|
|
11219
11234
|
log.info("chunkEmitter", `ok status=${statusCode} took=${tookMs}ms`);
|
|
11220
11235
|
}
|
|
11221
|
-
|
|
11236
|
+
resolve4({ dead: false });
|
|
11222
11237
|
}).catch((err) => {
|
|
11223
11238
|
log.warn(
|
|
11224
11239
|
"chunkEmitter",
|
|
@@ -11229,7 +11244,7 @@ var ChunkEmitter = class {
|
|
|
11229
11244
|
const delay = 200 * (maxRetries - attemptsLeft + 1);
|
|
11230
11245
|
setTimeout(() => attempt(attemptsLeft - 1), delay);
|
|
11231
11246
|
} else {
|
|
11232
|
-
|
|
11247
|
+
resolve4({ dead: false });
|
|
11233
11248
|
}
|
|
11234
11249
|
});
|
|
11235
11250
|
};
|
|
@@ -11241,7 +11256,7 @@ var _transport2 = {
|
|
|
11241
11256
|
post: _post
|
|
11242
11257
|
};
|
|
11243
11258
|
function _post(url, headers, payload) {
|
|
11244
|
-
return new Promise((
|
|
11259
|
+
return new Promise((resolve4, reject) => {
|
|
11245
11260
|
let settled = false;
|
|
11246
11261
|
const u2 = new URL(url);
|
|
11247
11262
|
const transport = u2.protocol === "https:" ? https3 : http3;
|
|
@@ -11265,7 +11280,7 @@ function _post(url, headers, payload) {
|
|
|
11265
11280
|
res.on("end", () => {
|
|
11266
11281
|
if (settled) return;
|
|
11267
11282
|
settled = true;
|
|
11268
|
-
|
|
11283
|
+
resolve4({ statusCode: res.statusCode ?? 0, body: resData });
|
|
11269
11284
|
});
|
|
11270
11285
|
}
|
|
11271
11286
|
);
|
|
@@ -11362,6 +11377,20 @@ var OutputService = class _OutputService {
|
|
|
11362
11377
|
emitter;
|
|
11363
11378
|
runtime;
|
|
11364
11379
|
lastSentContent = "";
|
|
11380
|
+
/**
|
|
11381
|
+
* Wall-clock of the most recent tick where the rendered + filtered
|
|
11382
|
+
* content actually changed. Most agent TUIs keep redrawing a
|
|
11383
|
+
* spinner + input prompt after the response is settled (Claude:
|
|
11384
|
+
* `? for shortcuts`; Codex: ratatui input bar), which keeps
|
|
11385
|
+
* `pty.lastPushTime` moving and prevents the PTY-idle heuristic
|
|
11386
|
+
* from ever crossing the IDLE_MS threshold — so the turn never
|
|
11387
|
+
* finalises and `done: true` never reaches the webapp's
|
|
11388
|
+
* canonical-refresh path. Tracking content-stability separately
|
|
11389
|
+
* closes that hole: PTY can churn all it wants, but once the
|
|
11390
|
+
* filtered TUI output stops changing for a beat we know the
|
|
11391
|
+
* agent is done.
|
|
11392
|
+
*/
|
|
11393
|
+
lastContentChangeAt = 0;
|
|
11365
11394
|
pollTimer = null;
|
|
11366
11395
|
startTime = 0;
|
|
11367
11396
|
terminalTurnPending = false;
|
|
@@ -11375,6 +11404,22 @@ var OutputService = class _OutputService {
|
|
|
11375
11404
|
static IDLE_MS = 3e3;
|
|
11376
11405
|
/** Same threshold but tighter for selectors (UI is ready to interact immediately). */
|
|
11377
11406
|
static SELECTOR_IDLE_MS = 1500;
|
|
11407
|
+
/**
|
|
11408
|
+
* Content-stable threshold. When the rendered + filtered content
|
|
11409
|
+
* hasn't changed for this long AND we can see Claude's "? for
|
|
11410
|
+
* shortcuts" prompt re-drawn at the bottom (= back to input
|
|
11411
|
+
* state), we know the response is settled even though the PTY
|
|
11412
|
+
* itself is still pushing spinner / status redraws. Tighter than
|
|
11413
|
+
* IDLE_MS because the ready-prompt is a strong signal on its own.
|
|
11414
|
+
*/
|
|
11415
|
+
static READY_STABLE_MS = 800;
|
|
11416
|
+
/**
|
|
11417
|
+
* Hard content-stable fallback. If the filtered content has been
|
|
11418
|
+
* unchanged for this long, finalize regardless of the ready
|
|
11419
|
+
* prompt — covers cases where Claude's TUI doesn't redraw the
|
|
11420
|
+
* shortcuts line (older versions, headless runs).
|
|
11421
|
+
*/
|
|
11422
|
+
static CONTENT_STABLE_MS = 8e3;
|
|
11378
11423
|
/**
|
|
11379
11424
|
* Grace period before tick processes anything — Claude needs ~100-
|
|
11380
11425
|
* 200 ms after `\r` to clear the input echo and re-render the TUI.
|
|
@@ -11496,6 +11541,7 @@ var OutputService = class _OutputService {
|
|
|
11496
11541
|
this.pty.activate();
|
|
11497
11542
|
this.steps.reset();
|
|
11498
11543
|
this.lastSentContent = "";
|
|
11544
|
+
this.lastContentChangeAt = 0;
|
|
11499
11545
|
this.startTime = Date.now();
|
|
11500
11546
|
this.pollTimer = setInterval(() => this.tick(), _OutputService.POLL_MS);
|
|
11501
11547
|
}
|
|
@@ -11588,18 +11634,32 @@ var OutputService = class _OutputService {
|
|
|
11588
11634
|
return;
|
|
11589
11635
|
}
|
|
11590
11636
|
const idleMs = this.pty.lastPushTime > 0 ? now - this.pty.lastPushTime : elapsed;
|
|
11637
|
+
if (content !== this.lastSentContent) {
|
|
11638
|
+
this.lastContentChangeAt = now;
|
|
11639
|
+
this.lastSentContent = content;
|
|
11640
|
+
this.send({ type: "text", content, done: false }).catch(() => {
|
|
11641
|
+
});
|
|
11642
|
+
}
|
|
11643
|
+
const contentStableMs = this.lastContentChangeAt > 0 ? now - this.lastContentChangeAt : 0;
|
|
11644
|
+
const readyPrompt = this.runtime.detectReadyPrompt?.(lines) ?? false;
|
|
11591
11645
|
log.trace(
|
|
11592
11646
|
"outputSvc",
|
|
11593
|
-
`tick content (raw=${this.pty.size}B lines=${lines.length} content=${content.length} idleMs=${idleMs})`
|
|
11647
|
+
`tick content (raw=${this.pty.size}B lines=${lines.length} content=${content.length} idleMs=${idleMs} stableMs=${contentStableMs} ready=${readyPrompt})`
|
|
11594
11648
|
);
|
|
11595
11649
|
if (idleMs >= _OutputService.IDLE_MS) {
|
|
11650
|
+
log.trace("outputSvc", `finalize: idleMs=${idleMs}`);
|
|
11596
11651
|
this.finalize();
|
|
11597
11652
|
return;
|
|
11598
11653
|
}
|
|
11599
|
-
if (
|
|
11600
|
-
|
|
11601
|
-
this.
|
|
11602
|
-
|
|
11654
|
+
if (readyPrompt && contentStableMs >= _OutputService.READY_STABLE_MS) {
|
|
11655
|
+
log.trace("outputSvc", `finalize: readyPrompt + stableMs=${contentStableMs}`);
|
|
11656
|
+
this.finalize();
|
|
11657
|
+
return;
|
|
11658
|
+
}
|
|
11659
|
+
if (contentStableMs >= _OutputService.CONTENT_STABLE_MS) {
|
|
11660
|
+
log.trace("outputSvc", `finalize: stableMs=${contentStableMs} (fallback)`);
|
|
11661
|
+
this.finalize();
|
|
11662
|
+
return;
|
|
11603
11663
|
}
|
|
11604
11664
|
}
|
|
11605
11665
|
finalize() {
|
|
@@ -11721,7 +11781,7 @@ function parseJsonl(filePath) {
|
|
|
11721
11781
|
return messages;
|
|
11722
11782
|
}
|
|
11723
11783
|
function post(endpoint, body) {
|
|
11724
|
-
return new Promise((
|
|
11784
|
+
return new Promise((resolve4) => {
|
|
11725
11785
|
const payload = JSON.stringify(body);
|
|
11726
11786
|
const u2 = new URL(`${API_BASE4}${endpoint}`);
|
|
11727
11787
|
const transport = u2.protocol === "https:" ? https4 : http4;
|
|
@@ -11742,17 +11802,17 @@ function post(endpoint, body) {
|
|
|
11742
11802
|
res.resume();
|
|
11743
11803
|
const ok = res.statusCode !== void 0 && res.statusCode >= 200 && res.statusCode < 300;
|
|
11744
11804
|
if (!ok) log.warn("history:post", `${endpoint} \u2192 HTTP ${res.statusCode}`);
|
|
11745
|
-
|
|
11805
|
+
resolve4(ok);
|
|
11746
11806
|
}
|
|
11747
11807
|
);
|
|
11748
11808
|
req.on("error", (err) => {
|
|
11749
11809
|
log.warn("history:post", `${endpoint} network error`, err);
|
|
11750
|
-
|
|
11810
|
+
resolve4(false);
|
|
11751
11811
|
});
|
|
11752
11812
|
req.on("timeout", () => {
|
|
11753
11813
|
log.warn("history:post", `${endpoint} timeout after 15s`);
|
|
11754
11814
|
req.destroy();
|
|
11755
|
-
|
|
11815
|
+
resolve4(false);
|
|
11756
11816
|
});
|
|
11757
11817
|
req.write(payload);
|
|
11758
11818
|
req.end();
|
|
@@ -12146,6 +12206,7 @@ var HistoryService = class _HistoryService {
|
|
|
12146
12206
|
|
|
12147
12207
|
// src/services/file-watcher.service.ts
|
|
12148
12208
|
var import_child_process7 = require("child_process");
|
|
12209
|
+
var fs21 = __toESM(require("fs"));
|
|
12149
12210
|
var os22 = __toESM(require("os"));
|
|
12150
12211
|
var path25 = __toESM(require("path"));
|
|
12151
12212
|
|
|
@@ -12235,7 +12296,7 @@ var _transport3 = {
|
|
|
12235
12296
|
post: _post2
|
|
12236
12297
|
};
|
|
12237
12298
|
function _post2(url, headers, payload) {
|
|
12238
|
-
return new Promise((
|
|
12299
|
+
return new Promise((resolve4, reject) => {
|
|
12239
12300
|
let settled = false;
|
|
12240
12301
|
const u2 = new URL(url);
|
|
12241
12302
|
const lib = u2.protocol === "https:" ? https5 : http5;
|
|
@@ -12260,7 +12321,7 @@ function _post2(url, headers, payload) {
|
|
|
12260
12321
|
res.on("end", () => {
|
|
12261
12322
|
if (settled) return;
|
|
12262
12323
|
settled = true;
|
|
12263
|
-
|
|
12324
|
+
resolve4({ statusCode: res.statusCode ?? 0, body });
|
|
12264
12325
|
});
|
|
12265
12326
|
}
|
|
12266
12327
|
);
|
|
@@ -12320,6 +12381,30 @@ var _chokidarSeam = {
|
|
|
12320
12381
|
}
|
|
12321
12382
|
}
|
|
12322
12383
|
};
|
|
12384
|
+
function findGitRoot(startDir) {
|
|
12385
|
+
return _findGitRootSeam.resolve(startDir);
|
|
12386
|
+
}
|
|
12387
|
+
var _findGitRootSeam = {
|
|
12388
|
+
resolve: _defaultFindGitRoot
|
|
12389
|
+
};
|
|
12390
|
+
function _defaultFindGitRoot(startDir) {
|
|
12391
|
+
let dir = path25.resolve(startDir);
|
|
12392
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12393
|
+
for (let i = 0; i < 256; i++) {
|
|
12394
|
+
if (seen.has(dir)) return null;
|
|
12395
|
+
seen.add(dir);
|
|
12396
|
+
try {
|
|
12397
|
+
const gitPath = path25.join(dir, ".git");
|
|
12398
|
+
const stat3 = fs21.statSync(gitPath, { throwIfNoEntry: false });
|
|
12399
|
+
if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
|
|
12400
|
+
} catch {
|
|
12401
|
+
}
|
|
12402
|
+
const parent = path25.dirname(dir);
|
|
12403
|
+
if (parent === dir) return null;
|
|
12404
|
+
dir = parent;
|
|
12405
|
+
}
|
|
12406
|
+
return null;
|
|
12407
|
+
}
|
|
12323
12408
|
var FileWatcherService = class {
|
|
12324
12409
|
constructor(opts) {
|
|
12325
12410
|
this.opts = opts;
|
|
@@ -12329,6 +12414,13 @@ var FileWatcherService = class {
|
|
|
12329
12414
|
watcher = null;
|
|
12330
12415
|
pending = /* @__PURE__ */ new Map();
|
|
12331
12416
|
apiBase;
|
|
12417
|
+
/**
|
|
12418
|
+
* Cache of (file directory → git root). Resolved lazily on each
|
|
12419
|
+
* file event so brand-new sub-repos under the workingDir light up
|
|
12420
|
+
* automatically; cached so a hot session with thousands of writes
|
|
12421
|
+
* doesn't hammer `fs.statSync` for every event.
|
|
12422
|
+
*/
|
|
12423
|
+
gitRootByDir = /* @__PURE__ */ new Map();
|
|
12332
12424
|
stopped = false;
|
|
12333
12425
|
/**
|
|
12334
12426
|
* Start watching `opts.workingDir`. Idempotent (second call is a
|
|
@@ -12471,67 +12563,82 @@ var FileWatcherService = class {
|
|
|
12471
12563
|
}
|
|
12472
12564
|
async emitForFile(absPath, changeType) {
|
|
12473
12565
|
if (this.stopped) return;
|
|
12474
|
-
const
|
|
12475
|
-
|
|
12566
|
+
const fileDir = path25.dirname(absPath);
|
|
12567
|
+
let gitRoot = this.gitRootByDir.get(fileDir);
|
|
12568
|
+
if (gitRoot === void 0) {
|
|
12569
|
+
gitRoot = findGitRoot(fileDir);
|
|
12570
|
+
this.gitRootByDir.set(fileDir, gitRoot);
|
|
12571
|
+
}
|
|
12572
|
+
if (!gitRoot) {
|
|
12573
|
+
log.trace(
|
|
12574
|
+
"fileWatcher",
|
|
12575
|
+
`no enclosing git repo for ${absPath} \u2014 suppressing emit`
|
|
12576
|
+
);
|
|
12476
12577
|
return;
|
|
12477
12578
|
}
|
|
12579
|
+
const relPathInRepo = path25.relative(gitRoot, absPath);
|
|
12580
|
+
if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
|
|
12581
|
+
const repoPath = path25.relative(this.opts.workingDir, gitRoot);
|
|
12582
|
+
const repoName = path25.basename(gitRoot);
|
|
12478
12583
|
let diffText = "";
|
|
12479
12584
|
let fileStatus = "modified";
|
|
12480
12585
|
if (changeType === "unlink") {
|
|
12481
|
-
const diff = await this.gitDiff(
|
|
12586
|
+
const diff = await this.gitDiff(gitRoot, relPathInRepo);
|
|
12482
12587
|
if (diff !== null && diff.trim().length > 0) {
|
|
12483
12588
|
diffText = diff;
|
|
12484
12589
|
} else {
|
|
12485
12590
|
await this.postFileChanged({
|
|
12486
12591
|
sessionId: this.opts.sessionId,
|
|
12487
12592
|
pluginId: this.opts.pluginId,
|
|
12488
|
-
filePath:
|
|
12593
|
+
filePath: relPathInRepo,
|
|
12489
12594
|
fileStatus: "deleted",
|
|
12490
12595
|
linesAdded: 0,
|
|
12491
12596
|
linesRemoved: 0,
|
|
12492
|
-
hunkCount: 0
|
|
12597
|
+
hunkCount: 0,
|
|
12598
|
+
repoPath,
|
|
12599
|
+
repoName
|
|
12493
12600
|
});
|
|
12494
12601
|
return;
|
|
12495
12602
|
}
|
|
12496
12603
|
fileStatus = "deleted";
|
|
12497
12604
|
} else {
|
|
12498
|
-
const diff = await this.gitDiff(
|
|
12605
|
+
const diff = await this.gitDiff(gitRoot, relPathInRepo);
|
|
12499
12606
|
if (diff === null) {
|
|
12500
12607
|
log.warn(
|
|
12501
12608
|
"fileWatcher",
|
|
12502
|
-
`git diff failed for ${
|
|
12609
|
+
`git diff failed for ${relPathInRepo} in ${gitRoot} \u2014 suppressing emit`
|
|
12503
12610
|
);
|
|
12504
|
-
await this.postFileChanged({
|
|
12505
|
-
sessionId: this.opts.sessionId,
|
|
12506
|
-
pluginId: this.opts.pluginId,
|
|
12507
|
-
filePath: relPath,
|
|
12508
|
-
fileStatus: changeType === "add" ? "added" : "modified",
|
|
12509
|
-
linesAdded: 0,
|
|
12510
|
-
linesRemoved: 0,
|
|
12511
|
-
hunkCount: 0
|
|
12512
|
-
});
|
|
12513
12611
|
return;
|
|
12514
12612
|
}
|
|
12515
12613
|
diffText = diff;
|
|
12516
12614
|
}
|
|
12517
12615
|
const parsed = parseUnifiedDiff(diffText);
|
|
12616
|
+
if (changeType !== "unlink" && parsed.totalLinesAdded === 0 && parsed.totalLinesRemoved === 0 && parsed.hunks.length === 0) {
|
|
12617
|
+
log.trace(
|
|
12618
|
+
"fileWatcher",
|
|
12619
|
+
`no content delta for ${relPathInRepo} in ${repoName} \u2014 suppressing emit`
|
|
12620
|
+
);
|
|
12621
|
+
return;
|
|
12622
|
+
}
|
|
12518
12623
|
const finalStatus = parsed.fileStatus !== "modified" ? parsed.fileStatus : changeType === "add" ? "added" : changeType === "unlink" ? "deleted" : fileStatus;
|
|
12519
12624
|
const reviewStatus = parsed.hunks.length > 0 ? "awaiting_review" : void 0;
|
|
12520
12625
|
await this.postFileChanged({
|
|
12521
12626
|
sessionId: this.opts.sessionId,
|
|
12522
12627
|
pluginId: this.opts.pluginId,
|
|
12523
|
-
filePath:
|
|
12628
|
+
filePath: relPathInRepo,
|
|
12524
12629
|
fileStatus: finalStatus,
|
|
12525
12630
|
linesAdded: parsed.totalLinesAdded,
|
|
12526
12631
|
linesRemoved: parsed.totalLinesRemoved,
|
|
12527
12632
|
hunkCount: parsed.hunks.length,
|
|
12528
|
-
reviewStatus
|
|
12633
|
+
reviewStatus,
|
|
12634
|
+
repoPath,
|
|
12635
|
+
repoName
|
|
12529
12636
|
});
|
|
12530
12637
|
for (const hunk of parsed.hunks) {
|
|
12531
12638
|
await this.postReviewHunk({
|
|
12532
12639
|
sessionId: this.opts.sessionId,
|
|
12533
12640
|
pluginId: this.opts.pluginId,
|
|
12534
|
-
filePath:
|
|
12641
|
+
filePath: relPathInRepo,
|
|
12535
12642
|
fileStatus: finalStatus,
|
|
12536
12643
|
hunkHeader: hunk.header,
|
|
12537
12644
|
lines: hunk.lines,
|
|
@@ -12542,9 +12649,11 @@ var FileWatcherService = class {
|
|
|
12542
12649
|
}
|
|
12543
12650
|
/**
|
|
12544
12651
|
* Compute the unified diff for a single path relative to the
|
|
12545
|
-
*
|
|
12546
|
-
*
|
|
12547
|
-
*
|
|
12652
|
+
* enclosing git repo (NOT the CLI's workingDir — see
|
|
12653
|
+
* `emitForFile`'s walk-up). Returns `null` when git is unavailable
|
|
12654
|
+
* or the discovered repo root is no longer a repo (race with
|
|
12655
|
+
* external removal). Returns `''` when there's no diff (a touch
|
|
12656
|
+
* that didn't change content).
|
|
12548
12657
|
*
|
|
12549
12658
|
* For tracked files we use `git diff --no-color -- <path>` which
|
|
12550
12659
|
* compares the worktree against HEAD's blob.
|
|
@@ -12552,16 +12661,16 @@ var FileWatcherService = class {
|
|
|
12552
12661
|
* zero) we use `git diff --no-color --no-index /dev/null <path>`,
|
|
12553
12662
|
* which produces an "added"-shaped diff against an empty source.
|
|
12554
12663
|
*/
|
|
12555
|
-
async gitDiff(relPath) {
|
|
12664
|
+
async gitDiff(repoRoot, relPath) {
|
|
12556
12665
|
const tracked = await runGit(
|
|
12557
|
-
|
|
12666
|
+
repoRoot,
|
|
12558
12667
|
["diff", "--no-color", "--", relPath]
|
|
12559
12668
|
);
|
|
12560
12669
|
if (tracked === null) return null;
|
|
12561
12670
|
if (tracked.trim().length > 0) return tracked;
|
|
12562
12671
|
const devNull = process.platform === "win32" ? "NUL" : "/dev/null";
|
|
12563
12672
|
const untracked = await runGit(
|
|
12564
|
-
|
|
12673
|
+
repoRoot,
|
|
12565
12674
|
["diff", "--no-color", "--no-index", "--", devNull, relPath],
|
|
12566
12675
|
{ allowNonZeroExit: true }
|
|
12567
12676
|
);
|
|
@@ -12629,12 +12738,12 @@ var _gitSeam = {
|
|
|
12629
12738
|
run: _runGitImpl
|
|
12630
12739
|
};
|
|
12631
12740
|
async function _runGitImpl(cwd, args2, opts = {}) {
|
|
12632
|
-
return new Promise((
|
|
12741
|
+
return new Promise((resolve4) => {
|
|
12633
12742
|
let proc;
|
|
12634
12743
|
try {
|
|
12635
12744
|
proc = (0, import_child_process7.spawn)("git", args2, { cwd, env: process.env });
|
|
12636
12745
|
} catch {
|
|
12637
|
-
|
|
12746
|
+
resolve4(null);
|
|
12638
12747
|
return;
|
|
12639
12748
|
}
|
|
12640
12749
|
let stdout = "";
|
|
@@ -12645,13 +12754,13 @@ async function _runGitImpl(cwd, args2, opts = {}) {
|
|
|
12645
12754
|
proc.stderr?.on("data", (c2) => {
|
|
12646
12755
|
stderr += c2.toString();
|
|
12647
12756
|
});
|
|
12648
|
-
proc.on("error", () =>
|
|
12757
|
+
proc.on("error", () => resolve4(null));
|
|
12649
12758
|
proc.on("close", (code) => {
|
|
12650
12759
|
if (code === 0 || opts.allowNonZeroExit) {
|
|
12651
|
-
|
|
12760
|
+
resolve4(stdout);
|
|
12652
12761
|
} else {
|
|
12653
12762
|
log.trace("fileWatcher", `git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`);
|
|
12654
|
-
|
|
12763
|
+
resolve4(null);
|
|
12655
12764
|
}
|
|
12656
12765
|
});
|
|
12657
12766
|
});
|
|
@@ -12671,7 +12780,7 @@ var _transport4 = {
|
|
|
12671
12780
|
get: _get
|
|
12672
12781
|
};
|
|
12673
12782
|
function _post3(url, headers, payload) {
|
|
12674
|
-
return new Promise((
|
|
12783
|
+
return new Promise((resolve4, reject) => {
|
|
12675
12784
|
let settled = false;
|
|
12676
12785
|
const u2 = new URL(url);
|
|
12677
12786
|
const lib = u2.protocol === "https:" ? https6 : http6;
|
|
@@ -12696,7 +12805,7 @@ function _post3(url, headers, payload) {
|
|
|
12696
12805
|
res.on("end", () => {
|
|
12697
12806
|
if (settled) return;
|
|
12698
12807
|
settled = true;
|
|
12699
|
-
|
|
12808
|
+
resolve4({ statusCode: res.statusCode ?? 0, body });
|
|
12700
12809
|
});
|
|
12701
12810
|
}
|
|
12702
12811
|
);
|
|
@@ -12713,7 +12822,7 @@ function _post3(url, headers, payload) {
|
|
|
12713
12822
|
});
|
|
12714
12823
|
}
|
|
12715
12824
|
function _get(url, headers) {
|
|
12716
|
-
return new Promise((
|
|
12825
|
+
return new Promise((resolve4, reject) => {
|
|
12717
12826
|
let settled = false;
|
|
12718
12827
|
const u2 = new URL(url);
|
|
12719
12828
|
const lib = u2.protocol === "https:" ? https6 : http6;
|
|
@@ -12737,7 +12846,7 @@ function _get(url, headers) {
|
|
|
12737
12846
|
res.on("end", () => {
|
|
12738
12847
|
if (settled) return;
|
|
12739
12848
|
settled = true;
|
|
12740
|
-
|
|
12849
|
+
resolve4({ statusCode: res.statusCode ?? 0, body });
|
|
12741
12850
|
});
|
|
12742
12851
|
}
|
|
12743
12852
|
);
|
|
@@ -13120,7 +13229,7 @@ function buildKeepAlive(ctx) {
|
|
|
13120
13229
|
let timer = null;
|
|
13121
13230
|
async function setIdleTimeout(minutes) {
|
|
13122
13231
|
if (!ctx.inCodespace || !ctx.codespaceName) return;
|
|
13123
|
-
await new Promise((
|
|
13232
|
+
await new Promise((resolve4) => {
|
|
13124
13233
|
const proc = (0, import_child_process8.spawn)(
|
|
13125
13234
|
"gh",
|
|
13126
13235
|
[
|
|
@@ -13134,8 +13243,8 @@ function buildKeepAlive(ctx) {
|
|
|
13134
13243
|
{ stdio: "ignore", detached: true }
|
|
13135
13244
|
);
|
|
13136
13245
|
proc.unref();
|
|
13137
|
-
proc.on("exit", () =>
|
|
13138
|
-
proc.on("error", () =>
|
|
13246
|
+
proc.on("exit", () => resolve4());
|
|
13247
|
+
proc.on("error", () => resolve4());
|
|
13139
13248
|
});
|
|
13140
13249
|
}
|
|
13141
13250
|
return {
|
|
@@ -13158,7 +13267,7 @@ function buildKeepAlive(ctx) {
|
|
|
13158
13267
|
}
|
|
13159
13268
|
|
|
13160
13269
|
// src/commands/start/handlers.ts
|
|
13161
|
-
var
|
|
13270
|
+
var fs24 = __toESM(require("fs"));
|
|
13162
13271
|
var os23 = __toESM(require("os"));
|
|
13163
13272
|
var path29 = __toESM(require("path"));
|
|
13164
13273
|
var import_crypto4 = require("crypto");
|
|
@@ -13218,7 +13327,7 @@ function parsePayload2(schema, raw) {
|
|
|
13218
13327
|
}
|
|
13219
13328
|
|
|
13220
13329
|
// src/services/file-ops.service.ts
|
|
13221
|
-
var
|
|
13330
|
+
var fs22 = __toESM(require("fs/promises"));
|
|
13222
13331
|
var path26 = __toESM(require("path"));
|
|
13223
13332
|
var MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
13224
13333
|
var MAX_WALK_DEPTH = 6;
|
|
@@ -13259,7 +13368,7 @@ function isUnder(parent, candidate) {
|
|
|
13259
13368
|
}
|
|
13260
13369
|
async function isExistingFile(absPath) {
|
|
13261
13370
|
try {
|
|
13262
|
-
const stat3 = await
|
|
13371
|
+
const stat3 = await fs22.stat(absPath);
|
|
13263
13372
|
return stat3.isFile();
|
|
13264
13373
|
} catch {
|
|
13265
13374
|
return false;
|
|
@@ -13272,7 +13381,7 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
|
|
|
13272
13381
|
ctx.visited++;
|
|
13273
13382
|
let entries = [];
|
|
13274
13383
|
try {
|
|
13275
|
-
entries = await
|
|
13384
|
+
entries = await fs22.readdir(dir, { withFileTypes: true });
|
|
13276
13385
|
} catch {
|
|
13277
13386
|
return;
|
|
13278
13387
|
}
|
|
@@ -13333,11 +13442,11 @@ async function readProjectFile(rawPath) {
|
|
|
13333
13442
|
if (!abs) {
|
|
13334
13443
|
return { error: `File not found in the project tree: ${rawPath}` };
|
|
13335
13444
|
}
|
|
13336
|
-
const stat3 = await
|
|
13445
|
+
const stat3 = await fs22.stat(abs);
|
|
13337
13446
|
if (stat3.size > MAX_FILE_BYTES) {
|
|
13338
13447
|
return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
|
|
13339
13448
|
}
|
|
13340
|
-
const buf = await
|
|
13449
|
+
const buf = await fs22.readFile(abs);
|
|
13341
13450
|
if (looksBinary(buf)) {
|
|
13342
13451
|
return { error: "Binary file \u2014 refusing to open in a code editor." };
|
|
13343
13452
|
}
|
|
@@ -13356,8 +13465,8 @@ async function writeProjectFile(rawPath, content) {
|
|
|
13356
13465
|
if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
|
|
13357
13466
|
return { error: "Content too large." };
|
|
13358
13467
|
}
|
|
13359
|
-
await
|
|
13360
|
-
await
|
|
13468
|
+
await fs22.mkdir(path26.dirname(abs), { recursive: true });
|
|
13469
|
+
await fs22.writeFile(abs, content, "utf-8");
|
|
13361
13470
|
return { ok: true };
|
|
13362
13471
|
} catch (e) {
|
|
13363
13472
|
const msg = e instanceof Error ? e.message : "Write failed";
|
|
@@ -13368,7 +13477,7 @@ async function writeProjectFile(rawPath, content) {
|
|
|
13368
13477
|
// src/services/project-ops.service.ts
|
|
13369
13478
|
var import_child_process9 = require("child_process");
|
|
13370
13479
|
var import_util2 = require("util");
|
|
13371
|
-
var
|
|
13480
|
+
var fs23 = __toESM(require("fs/promises"));
|
|
13372
13481
|
var path27 = __toESM(require("path"));
|
|
13373
13482
|
var execFileP3 = (0, import_util2.promisify)(import_child_process9.execFile);
|
|
13374
13483
|
var PROJECT_IGNORE = /* @__PURE__ */ new Set([
|
|
@@ -13417,7 +13526,7 @@ async function listProjectFiles(opts = {}) {
|
|
|
13417
13526
|
}
|
|
13418
13527
|
let entries = [];
|
|
13419
13528
|
try {
|
|
13420
|
-
entries = await
|
|
13529
|
+
entries = await fs23.readdir(dir, { withFileTypes: true });
|
|
13421
13530
|
} catch {
|
|
13422
13531
|
return;
|
|
13423
13532
|
}
|
|
@@ -13438,7 +13547,7 @@ async function listProjectFiles(opts = {}) {
|
|
|
13438
13547
|
}
|
|
13439
13548
|
let size = 0;
|
|
13440
13549
|
try {
|
|
13441
|
-
const st3 = await
|
|
13550
|
+
const st3 = await fs23.stat(full);
|
|
13442
13551
|
size = st3.size;
|
|
13443
13552
|
} catch {
|
|
13444
13553
|
}
|
|
@@ -13541,7 +13650,7 @@ async function gitStatus(cwd) {
|
|
|
13541
13650
|
try {
|
|
13542
13651
|
const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
|
|
13543
13652
|
const mergeHead = path27.isAbsolute(gitDir) ? path27.join(gitDir, "MERGE_HEAD") : path27.join(root, gitDir, "MERGE_HEAD");
|
|
13544
|
-
await
|
|
13653
|
+
await fs23.access(mergeHead);
|
|
13545
13654
|
hasMergeInProgress = true;
|
|
13546
13655
|
} catch {
|
|
13547
13656
|
}
|
|
@@ -13687,7 +13796,7 @@ async function jsSearchFiles(opts, cwd, cap) {
|
|
|
13687
13796
|
}
|
|
13688
13797
|
let content = "";
|
|
13689
13798
|
try {
|
|
13690
|
-
content = await
|
|
13799
|
+
content = await fs23.readFile(path27.join(cwd, f.path), "utf8");
|
|
13691
13800
|
} catch {
|
|
13692
13801
|
continue;
|
|
13693
13802
|
}
|
|
@@ -13971,7 +14080,7 @@ var pendingAttachmentFiles = /* @__PURE__ */ new Set();
|
|
|
13971
14080
|
function cleanupAttachmentTempFiles() {
|
|
13972
14081
|
for (const p2 of pendingAttachmentFiles) {
|
|
13973
14082
|
try {
|
|
13974
|
-
|
|
14083
|
+
fs24.unlinkSync(p2);
|
|
13975
14084
|
} catch {
|
|
13976
14085
|
}
|
|
13977
14086
|
}
|
|
@@ -13981,7 +14090,7 @@ function saveFilesTemp(files) {
|
|
|
13981
14090
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
13982
14091
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
13983
14092
|
const tmpPath = path29.join(os23.tmpdir(), `codeam-${(0, import_crypto4.randomUUID)()}-${safeName}`);
|
|
13984
|
-
|
|
14093
|
+
fs24.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
13985
14094
|
pendingAttachmentFiles.add(tmpPath);
|
|
13986
14095
|
return tmpPath;
|
|
13987
14096
|
});
|
|
@@ -14001,7 +14110,7 @@ var startTask = (ctx, _cmd, parsed) => {
|
|
|
14001
14110
|
setTimeout(() => {
|
|
14002
14111
|
for (const p2 of paths) {
|
|
14003
14112
|
try {
|
|
14004
|
-
|
|
14113
|
+
fs24.unlinkSync(p2);
|
|
14005
14114
|
} catch {
|
|
14006
14115
|
}
|
|
14007
14116
|
pendingAttachmentFiles.delete(p2);
|
|
@@ -14567,7 +14676,7 @@ async function pair(args2 = []) {
|
|
|
14567
14676
|
waitSpin.message(waitMessage());
|
|
14568
14677
|
}, 1e3);
|
|
14569
14678
|
countdownInterval.unref?.();
|
|
14570
|
-
await new Promise((
|
|
14679
|
+
await new Promise((resolve4) => {
|
|
14571
14680
|
let stopPolling = null;
|
|
14572
14681
|
function sigintHandler() {
|
|
14573
14682
|
clearInterval(countdownInterval);
|
|
@@ -14607,7 +14716,7 @@ async function pair(args2 = []) {
|
|
|
14607
14716
|
});
|
|
14608
14717
|
showSuccess(`Paired with ${info.userName} (${info.plan})`);
|
|
14609
14718
|
console.log("");
|
|
14610
|
-
|
|
14719
|
+
resolve4();
|
|
14611
14720
|
},
|
|
14612
14721
|
() => {
|
|
14613
14722
|
clearInterval(countdownInterval);
|
|
@@ -14623,7 +14732,7 @@ async function pair(args2 = []) {
|
|
|
14623
14732
|
}
|
|
14624
14733
|
|
|
14625
14734
|
// src/commands/pair-auto.ts
|
|
14626
|
-
var
|
|
14735
|
+
var fs25 = __toESM(require("fs"));
|
|
14627
14736
|
var os24 = __toESM(require("os"));
|
|
14628
14737
|
var import_crypto6 = require("crypto");
|
|
14629
14738
|
var API_BASE7 = resolveApiBaseUrl();
|
|
@@ -14643,10 +14752,10 @@ function readTokenFromArgs(args2) {
|
|
|
14643
14752
|
if (fileFlag) {
|
|
14644
14753
|
const path37 = fileFlag.slice("--token-file=".length);
|
|
14645
14754
|
try {
|
|
14646
|
-
const content =
|
|
14755
|
+
const content = fs25.readFileSync(path37, "utf8").trim();
|
|
14647
14756
|
if (content.length === 0) fail(`--token-file ${path37} is empty`);
|
|
14648
14757
|
try {
|
|
14649
|
-
|
|
14758
|
+
fs25.unlinkSync(path37);
|
|
14650
14759
|
} catch {
|
|
14651
14760
|
}
|
|
14652
14761
|
return content;
|
|
@@ -14943,12 +15052,12 @@ var GitHubCodespacesProvider = class {
|
|
|
14943
15052
|
}
|
|
14944
15053
|
if (!isAuthed) {
|
|
14945
15054
|
resetStdinForChild();
|
|
14946
|
-
await new Promise((
|
|
15055
|
+
await new Promise((resolve4, reject) => {
|
|
14947
15056
|
const proc = (0, import_child_process12.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
|
|
14948
15057
|
stdio: "inherit"
|
|
14949
15058
|
});
|
|
14950
15059
|
proc.on("exit", (code) => {
|
|
14951
|
-
if (code === 0)
|
|
15060
|
+
if (code === 0) resolve4();
|
|
14952
15061
|
else reject(new Error("gh auth login failed."));
|
|
14953
15062
|
});
|
|
14954
15063
|
proc.on("error", reject);
|
|
@@ -14977,13 +15086,13 @@ var GitHubCodespacesProvider = class {
|
|
|
14977
15086
|
}
|
|
14978
15087
|
wt(noteLines.join("\n"), "One more permission needed");
|
|
14979
15088
|
resetStdinForChild();
|
|
14980
|
-
const refreshCode = await new Promise((
|
|
15089
|
+
const refreshCode = await new Promise((resolve4, reject) => {
|
|
14981
15090
|
const proc = (0, import_child_process12.spawn)(
|
|
14982
15091
|
"gh",
|
|
14983
15092
|
["auth", "refresh", "-h", "github.com", "-s", "codespace"],
|
|
14984
15093
|
{ stdio: "inherit" }
|
|
14985
15094
|
);
|
|
14986
|
-
proc.on("exit", (code) =>
|
|
15095
|
+
proc.on("exit", (code) => resolve4(code ?? 1));
|
|
14987
15096
|
proc.on("error", reject);
|
|
14988
15097
|
});
|
|
14989
15098
|
if (refreshCode !== 0) {
|
|
@@ -15127,10 +15236,10 @@ var GitHubCodespacesProvider = class {
|
|
|
15127
15236
|
if (q(proceed) || !proceed) return;
|
|
15128
15237
|
O2.step(`Installing gh via ${installCmd.describe}\u2026`);
|
|
15129
15238
|
resetStdinForChild();
|
|
15130
|
-
const ok = await new Promise((
|
|
15239
|
+
const ok = await new Promise((resolve4) => {
|
|
15131
15240
|
const proc = (0, import_child_process12.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
|
|
15132
|
-
proc.on("exit", (code) =>
|
|
15133
|
-
proc.on("error", () =>
|
|
15241
|
+
proc.on("exit", (code) => resolve4(code === 0));
|
|
15242
|
+
proc.on("error", () => resolve4(false));
|
|
15134
15243
|
});
|
|
15135
15244
|
if (ok) O2.success("gh installed");
|
|
15136
15245
|
else O2.error("gh install failed");
|
|
@@ -15154,14 +15263,14 @@ var GitHubCodespacesProvider = class {
|
|
|
15154
15263
|
"Expanding GitHub scopes"
|
|
15155
15264
|
);
|
|
15156
15265
|
resetStdinForChild();
|
|
15157
|
-
await new Promise((
|
|
15266
|
+
await new Promise((resolve4, reject) => {
|
|
15158
15267
|
const proc = (0, import_child_process12.spawn)(
|
|
15159
15268
|
"gh",
|
|
15160
15269
|
["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
|
|
15161
15270
|
{ stdio: "inherit" }
|
|
15162
15271
|
);
|
|
15163
15272
|
proc.on("exit", (code) => {
|
|
15164
|
-
if (code === 0)
|
|
15273
|
+
if (code === 0) resolve4();
|
|
15165
15274
|
else reject(new Error(
|
|
15166
15275
|
"gh auth refresh failed. Re-run `gh auth refresh -h github.com -s repo,read:org` manually."
|
|
15167
15276
|
));
|
|
@@ -15332,13 +15441,13 @@ var GitHubCodespacesProvider = class {
|
|
|
15332
15441
|
}
|
|
15333
15442
|
async streamCommand(workspaceId, command2) {
|
|
15334
15443
|
resetStdinForChild();
|
|
15335
|
-
return new Promise((
|
|
15444
|
+
return new Promise((resolve4, reject) => {
|
|
15336
15445
|
const proc = (0, import_child_process12.spawn)(
|
|
15337
15446
|
"gh",
|
|
15338
15447
|
["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
|
|
15339
15448
|
{ stdio: "inherit" }
|
|
15340
15449
|
);
|
|
15341
|
-
proc.on("exit", (code) =>
|
|
15450
|
+
proc.on("exit", (code) => resolve4({ code: code ?? 0 }));
|
|
15342
15451
|
proc.on("error", reject);
|
|
15343
15452
|
});
|
|
15344
15453
|
}
|
|
@@ -15359,7 +15468,7 @@ var GitHubCodespacesProvider = class {
|
|
|
15359
15468
|
"--",
|
|
15360
15469
|
`mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
|
|
15361
15470
|
];
|
|
15362
|
-
await new Promise((
|
|
15471
|
+
await new Promise((resolve4, reject) => {
|
|
15363
15472
|
const tar = (0, import_child_process12.spawn)("tar", tarArgs, {
|
|
15364
15473
|
stdio: ["ignore", "pipe", "pipe"],
|
|
15365
15474
|
env: tarEnv
|
|
@@ -15379,7 +15488,7 @@ var GitHubCodespacesProvider = class {
|
|
|
15379
15488
|
ssh.on("error", reject);
|
|
15380
15489
|
ssh.on("exit", (code) => {
|
|
15381
15490
|
if (code === 0) {
|
|
15382
|
-
|
|
15491
|
+
resolve4();
|
|
15383
15492
|
} else {
|
|
15384
15493
|
const reason = (sshErr || tarErr || `exit ${code}`).trim().slice(0, 500);
|
|
15385
15494
|
reject(new Error(`Remote tar failed: ${reason}`));
|
|
@@ -15397,7 +15506,7 @@ var GitHubCodespacesProvider = class {
|
|
|
15397
15506
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote(remotePath)}`);
|
|
15398
15507
|
}
|
|
15399
15508
|
const cmd = parts.join(" && ");
|
|
15400
|
-
await new Promise((
|
|
15509
|
+
await new Promise((resolve4, reject) => {
|
|
15401
15510
|
const proc = (0, import_child_process12.spawn)(
|
|
15402
15511
|
"gh",
|
|
15403
15512
|
["codespace", "ssh", "-c", workspaceId, "--", cmd],
|
|
@@ -15409,7 +15518,7 @@ var GitHubCodespacesProvider = class {
|
|
|
15409
15518
|
});
|
|
15410
15519
|
proc.on("error", reject);
|
|
15411
15520
|
proc.on("exit", (code) => {
|
|
15412
|
-
if (code === 0)
|
|
15521
|
+
if (code === 0) resolve4();
|
|
15413
15522
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
15414
15523
|
});
|
|
15415
15524
|
proc.stdin?.write(contents);
|
|
@@ -15499,10 +15608,10 @@ var GitpodProvider = class {
|
|
|
15499
15608
|
"Authenticating Gitpod"
|
|
15500
15609
|
);
|
|
15501
15610
|
resetStdinForChild2();
|
|
15502
|
-
await new Promise((
|
|
15611
|
+
await new Promise((resolve4, reject) => {
|
|
15503
15612
|
const proc = (0, import_child_process13.spawn)("gitpod", ["login"], { stdio: "inherit" });
|
|
15504
15613
|
proc.on("exit", (code) => {
|
|
15505
|
-
if (code === 0)
|
|
15614
|
+
if (code === 0) resolve4();
|
|
15506
15615
|
else reject(new Error("gitpod login failed."));
|
|
15507
15616
|
});
|
|
15508
15617
|
proc.on("error", reject);
|
|
@@ -15651,13 +15760,13 @@ var GitpodProvider = class {
|
|
|
15651
15760
|
}
|
|
15652
15761
|
async streamCommand(workspaceId, command2) {
|
|
15653
15762
|
resetStdinForChild2();
|
|
15654
|
-
return new Promise((
|
|
15763
|
+
return new Promise((resolve4, reject) => {
|
|
15655
15764
|
const proc = (0, import_child_process13.spawn)(
|
|
15656
15765
|
"gitpod",
|
|
15657
15766
|
["workspace", "ssh", workspaceId, "--", "-tt", command2],
|
|
15658
15767
|
{ stdio: "inherit" }
|
|
15659
15768
|
);
|
|
15660
|
-
proc.on("exit", (code) =>
|
|
15769
|
+
proc.on("exit", (code) => resolve4({ code: code ?? 0 }));
|
|
15661
15770
|
proc.on("error", reject);
|
|
15662
15771
|
});
|
|
15663
15772
|
}
|
|
@@ -15671,7 +15780,7 @@ var GitpodProvider = class {
|
|
|
15671
15780
|
tarArgs.push(".");
|
|
15672
15781
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
15673
15782
|
const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
|
|
15674
|
-
await new Promise((
|
|
15783
|
+
await new Promise((resolve4, reject) => {
|
|
15675
15784
|
const tar = (0, import_child_process13.spawn)("tar", tarArgs, {
|
|
15676
15785
|
stdio: ["ignore", "pipe", "pipe"],
|
|
15677
15786
|
env: tarEnv
|
|
@@ -15692,7 +15801,7 @@ var GitpodProvider = class {
|
|
|
15692
15801
|
tar.on("error", reject);
|
|
15693
15802
|
ssh.on("error", reject);
|
|
15694
15803
|
ssh.on("exit", (code) => {
|
|
15695
|
-
if (code === 0)
|
|
15804
|
+
if (code === 0) resolve4();
|
|
15696
15805
|
else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
15697
15806
|
});
|
|
15698
15807
|
});
|
|
@@ -15707,7 +15816,7 @@ var GitpodProvider = class {
|
|
|
15707
15816
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote2(remotePath)}`);
|
|
15708
15817
|
}
|
|
15709
15818
|
const cmd = parts.join(" && ");
|
|
15710
|
-
await new Promise((
|
|
15819
|
+
await new Promise((resolve4, reject) => {
|
|
15711
15820
|
const proc = (0, import_child_process13.spawn)(
|
|
15712
15821
|
"gitpod",
|
|
15713
15822
|
["workspace", "ssh", workspaceId, "--", cmd],
|
|
@@ -15719,7 +15828,7 @@ var GitpodProvider = class {
|
|
|
15719
15828
|
});
|
|
15720
15829
|
proc.on("error", reject);
|
|
15721
15830
|
proc.on("exit", (code) => {
|
|
15722
|
-
if (code === 0)
|
|
15831
|
+
if (code === 0) resolve4();
|
|
15723
15832
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
15724
15833
|
});
|
|
15725
15834
|
proc.stdin?.write(contents);
|
|
@@ -15776,14 +15885,14 @@ var GitLabWorkspacesProvider = class {
|
|
|
15776
15885
|
"Authenticating GitLab"
|
|
15777
15886
|
);
|
|
15778
15887
|
resetStdinForChild3();
|
|
15779
|
-
await new Promise((
|
|
15888
|
+
await new Promise((resolve4, reject) => {
|
|
15780
15889
|
const proc = (0, import_child_process14.spawn)(
|
|
15781
15890
|
"glab",
|
|
15782
15891
|
["auth", "login", "--scopes", "api,read_user,read_repository"],
|
|
15783
15892
|
{ stdio: "inherit" }
|
|
15784
15893
|
);
|
|
15785
15894
|
proc.on("exit", (code) => {
|
|
15786
|
-
if (code === 0)
|
|
15895
|
+
if (code === 0) resolve4();
|
|
15787
15896
|
else reject(new Error("glab auth login failed."));
|
|
15788
15897
|
});
|
|
15789
15898
|
proc.on("error", reject);
|
|
@@ -15948,13 +16057,13 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
15948
16057
|
async streamCommand(workspaceId, command2) {
|
|
15949
16058
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
15950
16059
|
resetStdinForChild3();
|
|
15951
|
-
return new Promise((
|
|
16060
|
+
return new Promise((resolve4, reject) => {
|
|
15952
16061
|
const proc = (0, import_child_process14.spawn)(
|
|
15953
16062
|
"ssh",
|
|
15954
16063
|
["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
|
|
15955
16064
|
{ stdio: "inherit" }
|
|
15956
16065
|
);
|
|
15957
|
-
proc.on("exit", (code) =>
|
|
16066
|
+
proc.on("exit", (code) => resolve4({ code: code ?? 0 }));
|
|
15958
16067
|
proc.on("error", reject);
|
|
15959
16068
|
});
|
|
15960
16069
|
}
|
|
@@ -15969,7 +16078,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
15969
16078
|
tarArgs.push(".");
|
|
15970
16079
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
15971
16080
|
const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
|
|
15972
|
-
await new Promise((
|
|
16081
|
+
await new Promise((resolve4, reject) => {
|
|
15973
16082
|
const tar = (0, import_child_process14.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
15974
16083
|
const ssh = (0, import_child_process14.spawn)(
|
|
15975
16084
|
"ssh",
|
|
@@ -15987,7 +16096,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
15987
16096
|
tar.on("error", reject);
|
|
15988
16097
|
ssh.on("error", reject);
|
|
15989
16098
|
ssh.on("exit", (code) => {
|
|
15990
|
-
if (code === 0)
|
|
16099
|
+
if (code === 0) resolve4();
|
|
15991
16100
|
else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
15992
16101
|
});
|
|
15993
16102
|
});
|
|
@@ -16000,7 +16109,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
16000
16109
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
16001
16110
|
}
|
|
16002
16111
|
const cmd = parts.join(" && ");
|
|
16003
|
-
await new Promise((
|
|
16112
|
+
await new Promise((resolve4, reject) => {
|
|
16004
16113
|
const proc = (0, import_child_process14.spawn)(
|
|
16005
16114
|
"ssh",
|
|
16006
16115
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
|
|
@@ -16012,7 +16121,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
16012
16121
|
});
|
|
16013
16122
|
proc.on("error", reject);
|
|
16014
16123
|
proc.on("exit", (code) => {
|
|
16015
|
-
if (code === 0)
|
|
16124
|
+
if (code === 0) resolve4();
|
|
16016
16125
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
16017
16126
|
});
|
|
16018
16127
|
proc.stdin?.write(contents);
|
|
@@ -16103,10 +16212,10 @@ var RailwayProvider = class {
|
|
|
16103
16212
|
"Authenticating Railway"
|
|
16104
16213
|
);
|
|
16105
16214
|
resetStdinForChild4();
|
|
16106
|
-
await new Promise((
|
|
16215
|
+
await new Promise((resolve4, reject) => {
|
|
16107
16216
|
const proc = (0, import_child_process15.spawn)("railway", ["login"], { stdio: "inherit" });
|
|
16108
16217
|
proc.on("exit", (code) => {
|
|
16109
|
-
if (code === 0)
|
|
16218
|
+
if (code === 0) resolve4();
|
|
16110
16219
|
else reject(new Error("railway login failed."));
|
|
16111
16220
|
});
|
|
16112
16221
|
proc.on("error", reject);
|
|
@@ -16246,13 +16355,13 @@ var RailwayProvider = class {
|
|
|
16246
16355
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
16247
16356
|
}
|
|
16248
16357
|
resetStdinForChild4();
|
|
16249
|
-
return new Promise((
|
|
16358
|
+
return new Promise((resolve4, reject) => {
|
|
16250
16359
|
const proc = (0, import_child_process15.spawn)(
|
|
16251
16360
|
"railway",
|
|
16252
16361
|
["shell", "--project", projectId, "--service", serviceId, "--command", command2],
|
|
16253
16362
|
{ stdio: "inherit" }
|
|
16254
16363
|
);
|
|
16255
|
-
proc.on("exit", (code) =>
|
|
16364
|
+
proc.on("exit", (code) => resolve4({ code: code ?? 0 }));
|
|
16256
16365
|
proc.on("error", reject);
|
|
16257
16366
|
});
|
|
16258
16367
|
}
|
|
@@ -16270,7 +16379,7 @@ var RailwayProvider = class {
|
|
|
16270
16379
|
tarArgs.push(".");
|
|
16271
16380
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
16272
16381
|
const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
|
|
16273
|
-
await new Promise((
|
|
16382
|
+
await new Promise((resolve4, reject) => {
|
|
16274
16383
|
const tar = (0, import_child_process15.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
16275
16384
|
const sh = (0, import_child_process15.spawn)(
|
|
16276
16385
|
"railway",
|
|
@@ -16288,7 +16397,7 @@ var RailwayProvider = class {
|
|
|
16288
16397
|
tar.on("error", reject);
|
|
16289
16398
|
sh.on("error", reject);
|
|
16290
16399
|
sh.on("exit", (code) => {
|
|
16291
|
-
if (code === 0)
|
|
16400
|
+
if (code === 0) resolve4();
|
|
16292
16401
|
else reject(new Error(`Remote tar failed: ${(shErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
16293
16402
|
});
|
|
16294
16403
|
});
|
|
@@ -16304,7 +16413,7 @@ var RailwayProvider = class {
|
|
|
16304
16413
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
16305
16414
|
}
|
|
16306
16415
|
const cmd = parts.join(" && ");
|
|
16307
|
-
await new Promise((
|
|
16416
|
+
await new Promise((resolve4, reject) => {
|
|
16308
16417
|
const proc = (0, import_child_process15.spawn)(
|
|
16309
16418
|
"railway",
|
|
16310
16419
|
["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
|
|
@@ -16316,7 +16425,7 @@ var RailwayProvider = class {
|
|
|
16316
16425
|
});
|
|
16317
16426
|
proc.on("error", reject);
|
|
16318
16427
|
proc.on("exit", (code) => {
|
|
16319
|
-
if (code === 0)
|
|
16428
|
+
if (code === 0) resolve4();
|
|
16320
16429
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
16321
16430
|
});
|
|
16322
16431
|
proc.stdin?.write(contents);
|
|
@@ -16839,7 +16948,7 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
16839
16948
|
|
|
16840
16949
|
// src/commands/link.ts
|
|
16841
16950
|
var import_node_crypto4 = require("crypto");
|
|
16842
|
-
var
|
|
16951
|
+
var fs26 = __toESM(require("fs"));
|
|
16843
16952
|
var path34 = __toESM(require("path"));
|
|
16844
16953
|
var import_chokidar = __toESM(require("chokidar"));
|
|
16845
16954
|
var import_picocolors11 = __toESM(require("picocolors"));
|
|
@@ -16878,7 +16987,7 @@ function parseLinkArgs(args2) {
|
|
|
16878
16987
|
if (apiKeyFileArg) {
|
|
16879
16988
|
const filePath = apiKeyFileArg.slice("--api-key-file=".length);
|
|
16880
16989
|
try {
|
|
16881
|
-
apiKey =
|
|
16990
|
+
apiKey = fs26.readFileSync(path34.resolve(filePath), "utf8").trim();
|
|
16882
16991
|
} catch (err) {
|
|
16883
16992
|
throw new Error(`Could not read --api-key-file ${filePath}: ${err.message}`);
|
|
16884
16993
|
}
|
|
@@ -16923,7 +17032,7 @@ async function link(args2 = []) {
|
|
|
16923
17032
|
waitSpin.start(waitMsg());
|
|
16924
17033
|
const countdown = setInterval(() => waitSpin.message(waitMsg()), 1e3);
|
|
16925
17034
|
countdown.unref?.();
|
|
16926
|
-
const paired = await new Promise((
|
|
17035
|
+
const paired = await new Promise((resolve4, reject) => {
|
|
16927
17036
|
let stopPoll = null;
|
|
16928
17037
|
const sigint = () => {
|
|
16929
17038
|
clearInterval(countdown);
|
|
@@ -16936,7 +17045,7 @@ async function link(args2 = []) {
|
|
|
16936
17045
|
process.removeListener("SIGINT", sigint);
|
|
16937
17046
|
clearInterval(countdown);
|
|
16938
17047
|
waitSpin.stop("Paired");
|
|
16939
|
-
|
|
17048
|
+
resolve4(info);
|
|
16940
17049
|
},
|
|
16941
17050
|
() => {
|
|
16942
17051
|
clearInterval(countdown);
|
|
@@ -16972,7 +17081,7 @@ async function link(args2 = []) {
|
|
|
16972
17081
|
return;
|
|
16973
17082
|
}
|
|
16974
17083
|
if (parsed.tokenFile) {
|
|
16975
|
-
const credential =
|
|
17084
|
+
const credential = fs26.readFileSync(path34.resolve(parsed.tokenFile), "utf8").trim();
|
|
16976
17085
|
if (!credential) {
|
|
16977
17086
|
showError(`--token-file ${parsed.tokenFile} is empty.`);
|
|
16978
17087
|
process.exit(1);
|
|
@@ -17042,14 +17151,14 @@ async function captureFreshCredentials(ctx) {
|
|
|
17042
17151
|
}
|
|
17043
17152
|
};
|
|
17044
17153
|
try {
|
|
17045
|
-
const token = await new Promise((
|
|
17154
|
+
const token = await new Promise((resolve4, reject) => {
|
|
17046
17155
|
let settled = false;
|
|
17047
17156
|
const tryExtract = async () => {
|
|
17048
17157
|
if (settled) return;
|
|
17049
17158
|
const t2 = await ctx.locator.extract();
|
|
17050
17159
|
if (t2 && !settled) {
|
|
17051
17160
|
settled = true;
|
|
17052
|
-
|
|
17161
|
+
resolve4(t2);
|
|
17053
17162
|
}
|
|
17054
17163
|
};
|
|
17055
17164
|
watcher.on("add", () => void tryExtract());
|
|
@@ -17161,7 +17270,7 @@ async function linkDryRunPreflight(ctx) {
|
|
|
17161
17270
|
var import_node_dns = require("dns");
|
|
17162
17271
|
var import_node_util4 = require("util");
|
|
17163
17272
|
var import_node_crypto5 = require("crypto");
|
|
17164
|
-
var
|
|
17273
|
+
var fs27 = __toESM(require("fs"));
|
|
17165
17274
|
var path35 = __toESM(require("path"));
|
|
17166
17275
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
17167
17276
|
var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
|
|
@@ -17220,11 +17329,11 @@ async function checkHealth(apiBase) {
|
|
|
17220
17329
|
function checkConfigDir() {
|
|
17221
17330
|
const dir = path35.join(require("os").homedir(), ".codeam");
|
|
17222
17331
|
try {
|
|
17223
|
-
|
|
17332
|
+
fs27.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
17224
17333
|
const probe = path35.join(dir, ".doctor-probe");
|
|
17225
|
-
|
|
17226
|
-
const read =
|
|
17227
|
-
|
|
17334
|
+
fs27.writeFileSync(probe, "ok", { mode: 384 });
|
|
17335
|
+
const read = fs27.readFileSync(probe, "utf8");
|
|
17336
|
+
fs27.unlinkSync(probe);
|
|
17228
17337
|
if (read !== "ok") throw new Error("write/read round-trip mismatch");
|
|
17229
17338
|
return {
|
|
17230
17339
|
id: "config-dir",
|
|
@@ -17330,7 +17439,7 @@ function checkChokidar() {
|
|
|
17330
17439
|
}
|
|
17331
17440
|
async function doctor(args2 = []) {
|
|
17332
17441
|
const json = args2.includes("--json");
|
|
17333
|
-
const cliVersion = true ? "2.20.
|
|
17442
|
+
const cliVersion = true ? "2.20.2" : "0.0.0-dev";
|
|
17334
17443
|
const apiBase = resolveApiBaseUrl();
|
|
17335
17444
|
const diagnosticId = (0, import_node_crypto5.randomUUID)();
|
|
17336
17445
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -17529,7 +17638,7 @@ async function completion(args2) {
|
|
|
17529
17638
|
// src/commands/version.ts
|
|
17530
17639
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
17531
17640
|
function version2() {
|
|
17532
|
-
const v = true ? "2.20.
|
|
17641
|
+
const v = true ? "2.20.2" : "unknown";
|
|
17533
17642
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
17534
17643
|
}
|
|
17535
17644
|
|
|
@@ -17657,7 +17766,7 @@ function tryShowSubcommandHelp(cmd, args2) {
|
|
|
17657
17766
|
var _subcommandHelpKeys = Object.keys(HELPS);
|
|
17658
17767
|
|
|
17659
17768
|
// src/lib/updateNotifier.ts
|
|
17660
|
-
var
|
|
17769
|
+
var fs28 = __toESM(require("fs"));
|
|
17661
17770
|
var os25 = __toESM(require("os"));
|
|
17662
17771
|
var path36 = __toESM(require("path"));
|
|
17663
17772
|
var https7 = __toESM(require("https"));
|
|
@@ -17672,7 +17781,7 @@ function cachePath() {
|
|
|
17672
17781
|
}
|
|
17673
17782
|
function readCache() {
|
|
17674
17783
|
try {
|
|
17675
|
-
const raw =
|
|
17784
|
+
const raw = fs28.readFileSync(cachePath(), "utf8");
|
|
17676
17785
|
const parsed = JSON.parse(raw);
|
|
17677
17786
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
17678
17787
|
return parsed;
|
|
@@ -17683,10 +17792,10 @@ function readCache() {
|
|
|
17683
17792
|
function writeCache(cache) {
|
|
17684
17793
|
try {
|
|
17685
17794
|
const file = cachePath();
|
|
17686
|
-
|
|
17795
|
+
fs28.mkdirSync(path36.dirname(file), { recursive: true });
|
|
17687
17796
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
17688
|
-
|
|
17689
|
-
|
|
17797
|
+
fs28.writeFileSync(tmp, JSON.stringify(cache));
|
|
17798
|
+
fs28.renameSync(tmp, file);
|
|
17690
17799
|
} catch {
|
|
17691
17800
|
}
|
|
17692
17801
|
}
|
|
@@ -17704,14 +17813,14 @@ function compareSemver(a, b) {
|
|
|
17704
17813
|
return 0;
|
|
17705
17814
|
}
|
|
17706
17815
|
function fetchLatest() {
|
|
17707
|
-
return new Promise((
|
|
17816
|
+
return new Promise((resolve4) => {
|
|
17708
17817
|
const req = https7.get(
|
|
17709
17818
|
REGISTRY_URL,
|
|
17710
17819
|
{ headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
|
|
17711
17820
|
(res) => {
|
|
17712
17821
|
if (res.statusCode !== 200) {
|
|
17713
17822
|
res.resume();
|
|
17714
|
-
|
|
17823
|
+
resolve4(null);
|
|
17715
17824
|
return;
|
|
17716
17825
|
}
|
|
17717
17826
|
let buf = "";
|
|
@@ -17723,21 +17832,21 @@ function fetchLatest() {
|
|
|
17723
17832
|
try {
|
|
17724
17833
|
const json = JSON.parse(buf);
|
|
17725
17834
|
if (typeof json.version === "string") {
|
|
17726
|
-
|
|
17835
|
+
resolve4(json.version);
|
|
17727
17836
|
} else {
|
|
17728
|
-
|
|
17837
|
+
resolve4(null);
|
|
17729
17838
|
}
|
|
17730
17839
|
} catch {
|
|
17731
|
-
|
|
17840
|
+
resolve4(null);
|
|
17732
17841
|
}
|
|
17733
17842
|
});
|
|
17734
17843
|
}
|
|
17735
17844
|
);
|
|
17736
17845
|
req.on("timeout", () => {
|
|
17737
17846
|
req.destroy();
|
|
17738
|
-
|
|
17847
|
+
resolve4(null);
|
|
17739
17848
|
});
|
|
17740
|
-
req.on("error", () =>
|
|
17849
|
+
req.on("error", () => resolve4(null));
|
|
17741
17850
|
});
|
|
17742
17851
|
}
|
|
17743
17852
|
function notifyIfStale(currentVersion, latest) {
|
|
@@ -17757,7 +17866,7 @@ function checkForUpdates() {
|
|
|
17757
17866
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17758
17867
|
if (process.env.CI) return;
|
|
17759
17868
|
if (!process.stdout.isTTY) return;
|
|
17760
|
-
const current = true ? "2.20.
|
|
17869
|
+
const current = true ? "2.20.2" : null;
|
|
17761
17870
|
if (!current) return;
|
|
17762
17871
|
const cache = readCache();
|
|
17763
17872
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|