@buildautomaton/cli 0.1.32 → 0.1.33
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/dist/cli.js +208 -89
- package/dist/cli.js.map +4 -4
- package/dist/index.js +208 -89
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -25064,7 +25064,7 @@ var {
|
|
|
25064
25064
|
} = import_index.default;
|
|
25065
25065
|
|
|
25066
25066
|
// src/cli-version.ts
|
|
25067
|
-
var CLI_VERSION = "0.1.
|
|
25067
|
+
var CLI_VERSION = "0.1.33".length > 0 ? "0.1.33" : "0.0.0-dev";
|
|
25068
25068
|
|
|
25069
25069
|
// src/cli/defaults.ts
|
|
25070
25070
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
@@ -26696,6 +26696,30 @@ function runPendingAuth(options) {
|
|
|
26696
26696
|
};
|
|
26697
26697
|
}
|
|
26698
26698
|
|
|
26699
|
+
// src/dev-servers/manager/dev-server-constants.ts
|
|
26700
|
+
var BRIDGE_CLOSE_DEV_SERVER_GRACE_MS = 0;
|
|
26701
|
+
var BRIDGE_SHUTDOWN_GRACE_MS = 8e3;
|
|
26702
|
+
|
|
26703
|
+
// src/runtime/cli-process-interrupt.ts
|
|
26704
|
+
var cliImmediateShutdownRequested = false;
|
|
26705
|
+
function requestCliImmediateShutdown() {
|
|
26706
|
+
cliImmediateShutdownRequested = true;
|
|
26707
|
+
}
|
|
26708
|
+
function isCliImmediateShutdownRequested() {
|
|
26709
|
+
return cliImmediateShutdownRequested;
|
|
26710
|
+
}
|
|
26711
|
+
async function delayMsUnlessShutdownRequested(ms) {
|
|
26712
|
+
if (ms <= 0) return true;
|
|
26713
|
+
const end = Date.now() + ms;
|
|
26714
|
+
while (Date.now() < end) {
|
|
26715
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
26716
|
+
const chunk = Math.min(50, end - Date.now());
|
|
26717
|
+
if (chunk <= 0) break;
|
|
26718
|
+
await new Promise((r) => setTimeout(r, chunk));
|
|
26719
|
+
}
|
|
26720
|
+
return !isCliImmediateShutdownRequested();
|
|
26721
|
+
}
|
|
26722
|
+
|
|
26699
26723
|
// src/sqlite/cli-database.ts
|
|
26700
26724
|
import sqliteWasm from "node-sqlite3-wasm";
|
|
26701
26725
|
|
|
@@ -26999,6 +27023,12 @@ var { Database: SqliteDatabase } = sqliteWasm;
|
|
|
26999
27023
|
var CLI_SQLITE_SYNC_RETRY_MAX = 40;
|
|
27000
27024
|
var CLI_SQLITE_ASYNC_RETRY_MAX = 60;
|
|
27001
27025
|
var CLI_SQLITE_ASYNC_BASE_DELAY_MS = 20;
|
|
27026
|
+
var CliSqliteInterrupted = class extends Error {
|
|
27027
|
+
name = "CliSqliteInterrupted";
|
|
27028
|
+
constructor() {
|
|
27029
|
+
super("CLI SQLite interrupted (shutdown)");
|
|
27030
|
+
}
|
|
27031
|
+
};
|
|
27002
27032
|
function applyCliSqliteConcurrencyPragmas(db) {
|
|
27003
27033
|
try {
|
|
27004
27034
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -27009,7 +27039,7 @@ function applyCliSqliteConcurrencyPragmas(db) {
|
|
|
27009
27039
|
} catch {
|
|
27010
27040
|
}
|
|
27011
27041
|
try {
|
|
27012
|
-
db.run("PRAGMA busy_timeout =
|
|
27042
|
+
db.run("PRAGMA busy_timeout = 500");
|
|
27013
27043
|
} catch {
|
|
27014
27044
|
}
|
|
27015
27045
|
}
|
|
@@ -27030,26 +27060,42 @@ function safeCloseCliSqliteDatabase(db) {
|
|
|
27030
27060
|
function closeAllCliSqliteConnections() {
|
|
27031
27061
|
}
|
|
27032
27062
|
function isCliSqliteLockError(e) {
|
|
27063
|
+
if (e instanceof CliSqliteInterrupted) return false;
|
|
27033
27064
|
const msg = e instanceof Error ? e.message : String(e);
|
|
27034
27065
|
const lower = msg.toLowerCase();
|
|
27035
27066
|
return lower.includes("database is locked") || lower.includes("sqlite_busy") || lower.includes("sqlite3_busy") || lower.includes("database") && lower.includes("locked");
|
|
27036
27067
|
}
|
|
27037
27068
|
function syncSleepMs(ms) {
|
|
27038
27069
|
if (ms <= 0) return;
|
|
27039
|
-
|
|
27040
|
-
|
|
27041
|
-
|
|
27042
|
-
|
|
27043
|
-
|
|
27044
|
-
|
|
27045
|
-
|
|
27070
|
+
const deadline = Date.now() + ms;
|
|
27071
|
+
while (Date.now() < deadline) {
|
|
27072
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
27073
|
+
const chunk = Math.min(80, deadline - Date.now());
|
|
27074
|
+
if (chunk <= 0) break;
|
|
27075
|
+
try {
|
|
27076
|
+
const sab = new SharedArrayBuffer(4);
|
|
27077
|
+
const ia = new Int32Array(sab);
|
|
27078
|
+
Atomics.wait(ia, 0, 0, chunk);
|
|
27079
|
+
} catch {
|
|
27080
|
+
const end = Date.now() + chunk;
|
|
27081
|
+
while (Date.now() < end) {
|
|
27082
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
27083
|
+
}
|
|
27046
27084
|
}
|
|
27047
27085
|
}
|
|
27048
27086
|
}
|
|
27049
|
-
function
|
|
27050
|
-
|
|
27087
|
+
async function asyncDelayMsInterruptible(ms) {
|
|
27088
|
+
const end = Date.now() + ms;
|
|
27089
|
+
while (Date.now() < end) {
|
|
27090
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
27091
|
+
const chunk = Math.min(50, end - Date.now());
|
|
27092
|
+
if (chunk <= 0) break;
|
|
27093
|
+
await new Promise((r) => setTimeout(r, chunk));
|
|
27094
|
+
await yieldToEventLoop();
|
|
27095
|
+
}
|
|
27051
27096
|
}
|
|
27052
27097
|
function openCliSqliteConnection(options) {
|
|
27098
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
27053
27099
|
const sqlitePath = getCliSqlitePath();
|
|
27054
27100
|
ensureCliSqliteParentDir(sqlitePath);
|
|
27055
27101
|
const db = new SqliteDatabase(sqlitePath);
|
|
@@ -27066,6 +27112,7 @@ function openCliSqliteConnection(options) {
|
|
|
27066
27112
|
}
|
|
27067
27113
|
function withCliSqliteSync(fn, options) {
|
|
27068
27114
|
for (let attempt = 1; attempt <= CLI_SQLITE_SYNC_RETRY_MAX; attempt++) {
|
|
27115
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
27069
27116
|
let db;
|
|
27070
27117
|
try {
|
|
27071
27118
|
db = openCliSqliteConnection(options);
|
|
@@ -27076,6 +27123,7 @@ function withCliSqliteSync(fn, options) {
|
|
|
27076
27123
|
}
|
|
27077
27124
|
} catch (e) {
|
|
27078
27125
|
safeCloseCliSqliteDatabase(db);
|
|
27126
|
+
if (e instanceof CliSqliteInterrupted) throw e;
|
|
27079
27127
|
if (!isCliSqliteLockError(e) || attempt === CLI_SQLITE_SYNC_RETRY_MAX) throw e;
|
|
27080
27128
|
syncSleepMs(Math.min(500, 12 * attempt));
|
|
27081
27129
|
}
|
|
@@ -27085,6 +27133,7 @@ function withCliSqliteSync(fn, options) {
|
|
|
27085
27133
|
async function withCliSqlite(fn, options) {
|
|
27086
27134
|
let lastError;
|
|
27087
27135
|
for (let attempt = 1; attempt <= CLI_SQLITE_ASYNC_RETRY_MAX; attempt++) {
|
|
27136
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
27088
27137
|
let db;
|
|
27089
27138
|
try {
|
|
27090
27139
|
db = openCliSqliteConnection(options);
|
|
@@ -27096,9 +27145,10 @@ async function withCliSqlite(fn, options) {
|
|
|
27096
27145
|
} catch (e) {
|
|
27097
27146
|
lastError = e;
|
|
27098
27147
|
safeCloseCliSqliteDatabase(db);
|
|
27148
|
+
if (e instanceof CliSqliteInterrupted) throw e;
|
|
27099
27149
|
if (!isCliSqliteLockError(e) || attempt === CLI_SQLITE_ASYNC_RETRY_MAX) throw e;
|
|
27100
27150
|
const delayMs = Math.min(600, CLI_SQLITE_ASYNC_BASE_DELAY_MS * attempt);
|
|
27101
|
-
await
|
|
27151
|
+
await asyncDelayMsInterruptible(delayMs);
|
|
27102
27152
|
await yieldToEventLoop();
|
|
27103
27153
|
}
|
|
27104
27154
|
}
|
|
@@ -27111,9 +27161,9 @@ async function ensureCliSqliteInitialized(options) {
|
|
|
27111
27161
|
|
|
27112
27162
|
// src/connection/close-bridge-connection.ts
|
|
27113
27163
|
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
27164
|
+
requestCliImmediateShutdown();
|
|
27114
27165
|
const say = log2 ?? logImmediate;
|
|
27115
27166
|
say("Cleaning up connections\u2026");
|
|
27116
|
-
await new Promise((resolve20) => setImmediate(resolve20));
|
|
27117
27167
|
state.closedByUser = true;
|
|
27118
27168
|
clearReconnectQuietTimer(state.mainQuiet);
|
|
27119
27169
|
clearReconnectQuietTimer(state.firehoseQuiet);
|
|
@@ -27150,7 +27200,7 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
|
|
|
27150
27200
|
}
|
|
27151
27201
|
if (devServerManager) {
|
|
27152
27202
|
say("Stopping local dev server processes\u2026");
|
|
27153
|
-
await devServerManager.shutdownAllGraceful();
|
|
27203
|
+
await devServerManager.shutdownAllGraceful({ graceMs: BRIDGE_CLOSE_DEV_SERVER_GRACE_MS });
|
|
27154
27204
|
}
|
|
27155
27205
|
try {
|
|
27156
27206
|
closeAllCliSqliteConnections();
|
|
@@ -32929,16 +32979,38 @@ __export(claude_code_acp_client_exports, {
|
|
|
32929
32979
|
createClaudeCodeAcpClient: () => createClaudeCodeAcpClient,
|
|
32930
32980
|
detectLocalAgentPresence: () => detectLocalAgentPresence
|
|
32931
32981
|
});
|
|
32932
|
-
import { execFile as execFile9 } from "node:child_process";
|
|
32933
|
-
import { promisify as promisify9 } from "node:util";
|
|
32934
32982
|
|
|
32935
32983
|
// src/agents/acp/clients/detect-command-on-path.ts
|
|
32936
32984
|
import { execFile as execFile8 } from "node:child_process";
|
|
32937
32985
|
import { promisify as promisify8 } from "node:util";
|
|
32938
32986
|
var execFileAsync7 = promisify8(execFile8);
|
|
32939
|
-
|
|
32987
|
+
var COMMAND_ON_PATH_PROBE_TIMEOUT_MS = 750;
|
|
32988
|
+
async function execFileShutdownAware(file2, args, timeoutMs) {
|
|
32989
|
+
if (isCliImmediateShutdownRequested()) throw new Error("shutdown");
|
|
32990
|
+
const ac = new AbortController();
|
|
32991
|
+
const shutdownPoll = setInterval(() => {
|
|
32992
|
+
if (isCliImmediateShutdownRequested()) ac.abort();
|
|
32993
|
+
}, 50);
|
|
32994
|
+
shutdownPoll.unref?.();
|
|
32940
32995
|
try {
|
|
32941
|
-
await execFileAsync7(
|
|
32996
|
+
await execFileAsync7(file2, args, { timeout: timeoutMs, signal: ac.signal });
|
|
32997
|
+
} finally {
|
|
32998
|
+
clearInterval(shutdownPoll);
|
|
32999
|
+
}
|
|
33000
|
+
}
|
|
33001
|
+
async function isCommandOnPath(command, timeoutMs = COMMAND_ON_PATH_PROBE_TIMEOUT_MS) {
|
|
33002
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
33003
|
+
try {
|
|
33004
|
+
await execFileShutdownAware("which", [command], timeoutMs);
|
|
33005
|
+
return true;
|
|
33006
|
+
} catch {
|
|
33007
|
+
return false;
|
|
33008
|
+
}
|
|
33009
|
+
}
|
|
33010
|
+
async function execProbeShutdownAware(file2, args, timeoutMs) {
|
|
33011
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
33012
|
+
try {
|
|
33013
|
+
await execFileShutdownAware(file2, args, timeoutMs);
|
|
32942
33014
|
return true;
|
|
32943
33015
|
} catch {
|
|
32944
33016
|
return false;
|
|
@@ -33699,16 +33771,10 @@ async function createSdkStdioAcpClient(options) {
|
|
|
33699
33771
|
}
|
|
33700
33772
|
|
|
33701
33773
|
// src/agents/acp/clients/claude-code-acp-client.ts
|
|
33702
|
-
var execFileAsync8 = promisify9(execFile9);
|
|
33703
33774
|
var BACKEND_LOCAL_AGENT_TYPE = "claude-code";
|
|
33704
33775
|
async function detectLocalAgentPresence() {
|
|
33705
33776
|
if (await isCommandOnPath("claude")) return true;
|
|
33706
|
-
|
|
33707
|
-
await execFileAsync8("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], { timeout: 25e3 });
|
|
33708
|
-
return true;
|
|
33709
|
-
} catch {
|
|
33710
|
-
return false;
|
|
33711
|
-
}
|
|
33777
|
+
return execProbeShutdownAware("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], 3e3);
|
|
33712
33778
|
}
|
|
33713
33779
|
function buildClaudeCodeAcpSpawnCommand(base, _sessionMode) {
|
|
33714
33780
|
return [...base];
|
|
@@ -36537,30 +36603,39 @@ import path28 from "node:path";
|
|
|
36537
36603
|
function shouldSkipWorkspaceWalkEntry(name) {
|
|
36538
36604
|
return name.startsWith(".");
|
|
36539
36605
|
}
|
|
36540
|
-
function
|
|
36606
|
+
async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
36541
36607
|
let names;
|
|
36542
36608
|
try {
|
|
36543
|
-
names = fs25.
|
|
36609
|
+
names = await fs25.promises.readdir(dir);
|
|
36544
36610
|
} catch {
|
|
36545
36611
|
return;
|
|
36546
36612
|
}
|
|
36547
36613
|
for (const name of names) {
|
|
36548
36614
|
if (shouldSkipWorkspaceWalkEntry(name)) continue;
|
|
36615
|
+
if (state.n > 0 && state.n % INDEX_WORK_YIELD_EVERY === 0) {
|
|
36616
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
36617
|
+
await yieldToEventLoop();
|
|
36618
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
36619
|
+
}
|
|
36620
|
+
state.n++;
|
|
36549
36621
|
const full = path28.join(dir, name);
|
|
36550
36622
|
let stat3;
|
|
36551
36623
|
try {
|
|
36552
|
-
stat3 = fs25.
|
|
36624
|
+
stat3 = await fs25.promises.stat(full);
|
|
36553
36625
|
} catch {
|
|
36554
36626
|
continue;
|
|
36555
36627
|
}
|
|
36556
36628
|
const relative5 = path28.relative(baseDir, full).replace(/\\/g, "/");
|
|
36557
36629
|
if (stat3.isDirectory()) {
|
|
36558
|
-
|
|
36630
|
+
await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
|
|
36559
36631
|
} else if (stat3.isFile()) {
|
|
36560
36632
|
onFile(relative5);
|
|
36561
36633
|
}
|
|
36562
36634
|
}
|
|
36563
36635
|
}
|
|
36636
|
+
function createWalkYieldState() {
|
|
36637
|
+
return { n: 0 };
|
|
36638
|
+
}
|
|
36564
36639
|
|
|
36565
36640
|
// src/files/index/file-index-sqlite-lock.ts
|
|
36566
36641
|
import fs26 from "node:fs";
|
|
@@ -36593,29 +36668,28 @@ function withFileIndexSqliteLock(fn) {
|
|
|
36593
36668
|
}
|
|
36594
36669
|
|
|
36595
36670
|
// src/files/index/build-file-index.ts
|
|
36596
|
-
var
|
|
36597
|
-
function
|
|
36671
|
+
var FILE_INDEX_INTERRUPT_CHECK_EVERY = 256;
|
|
36672
|
+
function assertNotShutdown() {
|
|
36673
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
36674
|
+
}
|
|
36675
|
+
function persistFileIndexPaths(resolved, paths) {
|
|
36598
36676
|
return withCliSqliteSync((db) => {
|
|
36599
36677
|
const h = getCwdHashForFileIndex(resolved);
|
|
36600
|
-
const buf = [];
|
|
36601
36678
|
let pathCount = 0;
|
|
36602
36679
|
db.run("BEGIN IMMEDIATE");
|
|
36603
36680
|
try {
|
|
36604
36681
|
db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
|
|
36605
36682
|
const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
|
|
36606
36683
|
try {
|
|
36607
|
-
|
|
36608
|
-
|
|
36609
|
-
|
|
36684
|
+
let batch = 0;
|
|
36685
|
+
for (const rel of paths) {
|
|
36686
|
+
if (++batch >= FILE_INDEX_INTERRUPT_CHECK_EVERY) {
|
|
36687
|
+
batch = 0;
|
|
36688
|
+
assertNotShutdown();
|
|
36610
36689
|
}
|
|
36611
|
-
|
|
36612
|
-
|
|
36613
|
-
}
|
|
36614
|
-
walkWorkspaceTreeSync(resolved, resolved, (rel) => {
|
|
36615
|
-
buf.push(rel);
|
|
36616
|
-
if (buf.length >= FILE_INDEX_INSERT_BUFFER) flushBuf();
|
|
36617
|
-
});
|
|
36618
|
-
flushBuf();
|
|
36690
|
+
ins.run([h, rel]);
|
|
36691
|
+
pathCount += 1;
|
|
36692
|
+
}
|
|
36619
36693
|
} finally {
|
|
36620
36694
|
ins.finalize();
|
|
36621
36695
|
}
|
|
@@ -36630,12 +36704,24 @@ function persistFileIndexForResolvedCwd(resolved) {
|
|
|
36630
36704
|
return pathCount;
|
|
36631
36705
|
});
|
|
36632
36706
|
}
|
|
36707
|
+
async function collectWorkspacePathsAsync(resolved) {
|
|
36708
|
+
const paths = [];
|
|
36709
|
+
const state = createWalkYieldState();
|
|
36710
|
+
await walkWorkspaceTreeAsync(resolved, resolved, (rel) => {
|
|
36711
|
+
assertNotShutdown();
|
|
36712
|
+
paths.push(rel);
|
|
36713
|
+
}, state);
|
|
36714
|
+
return paths;
|
|
36715
|
+
}
|
|
36633
36716
|
async function buildFileIndexAsync(cwd) {
|
|
36634
36717
|
return withFileIndexSqliteLock(async () => {
|
|
36635
36718
|
const resolved = path29.resolve(cwd);
|
|
36636
36719
|
await yieldToEventLoop();
|
|
36637
|
-
|
|
36720
|
+
assertNotShutdown();
|
|
36721
|
+
const paths = await collectWorkspacePathsAsync(resolved);
|
|
36638
36722
|
await yieldToEventLoop();
|
|
36723
|
+
assertNotShutdown();
|
|
36724
|
+
const pathCount = persistFileIndexPaths(resolved, paths);
|
|
36639
36725
|
return { pathCount };
|
|
36640
36726
|
});
|
|
36641
36727
|
}
|
|
@@ -36739,11 +36825,13 @@ function createFsWatcher(resolved, schedule) {
|
|
|
36739
36825
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
36740
36826
|
const resolved = path31.resolve(cwd);
|
|
36741
36827
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
36828
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
36742
36829
|
console.error("[file-index] Initial index build failed:", e);
|
|
36743
36830
|
});
|
|
36744
36831
|
let timer = null;
|
|
36745
36832
|
const runRebuild = () => {
|
|
36746
36833
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
36834
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
36747
36835
|
console.error("[file-index] Watch rebuild failed:", e);
|
|
36748
36836
|
});
|
|
36749
36837
|
};
|
|
@@ -37277,9 +37365,6 @@ var StreamTail = class {
|
|
|
37277
37365
|
}
|
|
37278
37366
|
};
|
|
37279
37367
|
|
|
37280
|
-
// src/dev-servers/manager/dev-server-constants.ts
|
|
37281
|
-
var BRIDGE_SHUTDOWN_GRACE_MS = 8e3;
|
|
37282
|
-
|
|
37283
37368
|
// src/dev-servers/manager/dev-server-firehose-messages.ts
|
|
37284
37369
|
function buildFirehoseSnapshotMessage(params) {
|
|
37285
37370
|
const payload = {
|
|
@@ -37565,22 +37650,23 @@ var DevServerManager = class {
|
|
|
37565
37650
|
}
|
|
37566
37651
|
this.start(serverId);
|
|
37567
37652
|
}
|
|
37568
|
-
async shutdownAllGraceful() {
|
|
37653
|
+
async shutdownAllGraceful(opts) {
|
|
37654
|
+
const graceMs = opts?.graceMs ?? BRIDGE_SHUTDOWN_GRACE_MS;
|
|
37569
37655
|
const pairs = [...this.processes.entries()];
|
|
37570
37656
|
if (pairs.length === 0) return;
|
|
37571
37657
|
this.log(
|
|
37572
37658
|
`[dev-server] Stopping ${pairs.length} local dev server process${pairs.length === 1 ? "" : "es"}\u2026`
|
|
37573
37659
|
);
|
|
37574
|
-
await Promise.all(pairs.map(([serverId, proc]) => this.gracefulTerminateOrUnknown(serverId, proc)));
|
|
37660
|
+
await Promise.all(pairs.map(([serverId, proc]) => this.gracefulTerminateOrUnknown(serverId, proc, graceMs)));
|
|
37575
37661
|
}
|
|
37576
|
-
async gracefulTerminateOrUnknown(serverId, proc) {
|
|
37662
|
+
async gracefulTerminateOrUnknown(serverId, proc, graceMs) {
|
|
37577
37663
|
const shortId = `${serverId.slice(0, 8)}\u2026`;
|
|
37578
|
-
await sigtermAndWaitForExit(proc,
|
|
37664
|
+
await sigtermAndWaitForExit(proc, graceMs, this.log, shortId);
|
|
37579
37665
|
if (!this.processes.has(serverId) || this.processes.get(serverId) !== proc) {
|
|
37580
37666
|
return;
|
|
37581
37667
|
}
|
|
37582
37668
|
this.bumpGeneration(serverId);
|
|
37583
|
-
forceKillChild(proc, this.log, shortId,
|
|
37669
|
+
forceKillChild(proc, this.log, shortId, graceMs);
|
|
37584
37670
|
this.processes.delete(serverId);
|
|
37585
37671
|
this.clearPoll(serverId);
|
|
37586
37672
|
this.pipedCaptureByServerId.delete(serverId);
|
|
@@ -38175,10 +38261,13 @@ var LOCAL_AGENT_ACP_MODULES = [
|
|
|
38175
38261
|
];
|
|
38176
38262
|
async function detectLocalAgentTypes() {
|
|
38177
38263
|
try {
|
|
38264
|
+
if (isCliImmediateShutdownRequested()) return [];
|
|
38178
38265
|
const out = [];
|
|
38179
38266
|
for (let i = 0; i < LOCAL_AGENT_ACP_MODULES.length; i++) {
|
|
38267
|
+
if (isCliImmediateShutdownRequested()) return out;
|
|
38180
38268
|
if (i > 0) {
|
|
38181
38269
|
await yieldToEventLoop();
|
|
38270
|
+
if (isCliImmediateShutdownRequested()) return out;
|
|
38182
38271
|
}
|
|
38183
38272
|
const mod = LOCAL_AGENT_ACP_MODULES[i];
|
|
38184
38273
|
try {
|
|
@@ -38211,6 +38300,7 @@ function createSendLocalSkillsReport(getWs, logFn) {
|
|
|
38211
38300
|
}
|
|
38212
38301
|
function createReportAutoDetectedAgents(getWs, logFn) {
|
|
38213
38302
|
return async () => {
|
|
38303
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
38214
38304
|
try {
|
|
38215
38305
|
const types = await detectLocalAgentTypes();
|
|
38216
38306
|
const socket = getWs();
|
|
@@ -38310,6 +38400,7 @@ var handleBridgeIdentified = (msg, deps) => {
|
|
|
38310
38400
|
});
|
|
38311
38401
|
setImmediate(() => {
|
|
38312
38402
|
void (async () => {
|
|
38403
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
38313
38404
|
try {
|
|
38314
38405
|
await deps.reportAutoDetectedAgents?.();
|
|
38315
38406
|
} catch (e) {
|
|
@@ -38317,6 +38408,7 @@ var handleBridgeIdentified = (msg, deps) => {
|
|
|
38317
38408
|
`[Bridge service] Auto-detect agents failed: ${e instanceof Error ? e.message : String(e)}`
|
|
38318
38409
|
);
|
|
38319
38410
|
}
|
|
38411
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
38320
38412
|
try {
|
|
38321
38413
|
await deps.warmupAgentCapabilitiesOnConnect?.();
|
|
38322
38414
|
} catch (e) {
|
|
@@ -38327,6 +38419,7 @@ var handleBridgeIdentified = (msg, deps) => {
|
|
|
38327
38419
|
})();
|
|
38328
38420
|
});
|
|
38329
38421
|
setImmediate(() => {
|
|
38422
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
38330
38423
|
try {
|
|
38331
38424
|
deps.sendLocalSkillsReport?.();
|
|
38332
38425
|
} catch (e) {
|
|
@@ -38628,12 +38721,12 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
38628
38721
|
}
|
|
38629
38722
|
|
|
38630
38723
|
// src/agents/acp/from-bridge/bridge-prompt-preamble.ts
|
|
38631
|
-
import { execFile as
|
|
38632
|
-
import { promisify as
|
|
38633
|
-
var
|
|
38724
|
+
import { execFile as execFile9 } from "node:child_process";
|
|
38725
|
+
import { promisify as promisify9 } from "node:util";
|
|
38726
|
+
var execFileAsync8 = promisify9(execFile9);
|
|
38634
38727
|
async function readGitBranch(cwd) {
|
|
38635
38728
|
try {
|
|
38636
|
-
const { stdout } = await
|
|
38729
|
+
const { stdout } = await execFileAsync8("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
|
|
38637
38730
|
const b = stdout.trim();
|
|
38638
38731
|
return b || null;
|
|
38639
38732
|
} catch {
|
|
@@ -40099,6 +40192,7 @@ import * as path40 from "node:path";
|
|
|
40099
40192
|
import * as path39 from "node:path";
|
|
40100
40193
|
async function probeOneAgentTypeForCapabilities(params) {
|
|
40101
40194
|
const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true } = params;
|
|
40195
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
40102
40196
|
const resolved = resolveAgentCommand(agentType);
|
|
40103
40197
|
if (!resolved) return false;
|
|
40104
40198
|
let sqliteChanged = false;
|
|
@@ -40132,6 +40226,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
40132
40226
|
}, 28e3);
|
|
40133
40227
|
killTimer.unref?.();
|
|
40134
40228
|
try {
|
|
40229
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
40135
40230
|
handle = await resolved.createClient({
|
|
40136
40231
|
command: resolved.command,
|
|
40137
40232
|
cwd: path39.resolve(cwd),
|
|
@@ -40151,7 +40246,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
40151
40246
|
onSessionUpdate: () => {
|
|
40152
40247
|
}
|
|
40153
40248
|
});
|
|
40154
|
-
|
|
40249
|
+
if (!await delayMsUnlessShutdownRequested(1200)) return false;
|
|
40155
40250
|
} catch (e) {
|
|
40156
40251
|
log2(
|
|
40157
40252
|
`[Bridge service] Agent capability probe (${agentType}): ${e instanceof Error ? e.message : String(e)}`
|
|
@@ -40179,6 +40274,7 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
|
|
|
40179
40274
|
} = params;
|
|
40180
40275
|
let changedCount = 0;
|
|
40181
40276
|
for (let i = 0; i < agentTypes.length; i++) {
|
|
40277
|
+
if (isCliImmediateShutdownRequested()) return changedCount;
|
|
40182
40278
|
if (i > 0) await yieldToEventLoop();
|
|
40183
40279
|
const agentType = agentTypes[i];
|
|
40184
40280
|
if (!agentType.trim()) continue;
|
|
@@ -40206,6 +40302,7 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
|
|
|
40206
40302
|
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
40207
40303
|
async function warmupAgentCapabilitiesOnConnect(params) {
|
|
40208
40304
|
const { workspaceId, log: log2, getWs } = params;
|
|
40305
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
40209
40306
|
const cwd = path40.resolve(getBridgeRoot());
|
|
40210
40307
|
async function sendBatchFromCache() {
|
|
40211
40308
|
const socket = getWs();
|
|
@@ -40218,18 +40315,21 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
40218
40315
|
items: rows.map((r) => ({ agentType: r.agentType, configOptions: r.configOptions }))
|
|
40219
40316
|
});
|
|
40220
40317
|
} catch (e) {
|
|
40318
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
40221
40319
|
log2(
|
|
40222
40320
|
`[Bridge service] Agent capability batch to bridge failed: ${e instanceof Error ? e.message : String(e)}`
|
|
40223
40321
|
);
|
|
40224
40322
|
}
|
|
40225
40323
|
}
|
|
40226
40324
|
await sendBatchFromCache();
|
|
40325
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
40227
40326
|
let types = [];
|
|
40228
40327
|
try {
|
|
40229
40328
|
types = [...await detectLocalAgentTypes()];
|
|
40230
40329
|
} catch (e) {
|
|
40231
40330
|
log2(`[Bridge service] detectLocalAgentTypes failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
40232
40331
|
}
|
|
40332
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
40233
40333
|
try {
|
|
40234
40334
|
const n = await probeAgentCapabilitiesForDetectedTypes({
|
|
40235
40335
|
agentTypes: types,
|
|
@@ -40241,11 +40341,13 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
40241
40341
|
});
|
|
40242
40342
|
if (n > 0) await sendBatchFromCache();
|
|
40243
40343
|
} catch (e) {
|
|
40344
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
40244
40345
|
log2(`[Bridge service] Agent capability probe (missing cache) failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
40245
40346
|
}
|
|
40246
40347
|
void (async () => {
|
|
40247
40348
|
try {
|
|
40248
40349
|
await yieldToEventLoop();
|
|
40350
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
40249
40351
|
const n = await probeAgentCapabilitiesForDetectedTypes({
|
|
40250
40352
|
agentTypes: types,
|
|
40251
40353
|
cwd,
|
|
@@ -40256,6 +40358,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
40256
40358
|
});
|
|
40257
40359
|
if (n > 0) await sendBatchFromCache();
|
|
40258
40360
|
} catch (e) {
|
|
40361
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
40259
40362
|
log2(`[Bridge service] Agent capability lazy refresh failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
40260
40363
|
}
|
|
40261
40364
|
})();
|
|
@@ -40303,7 +40406,8 @@ async function createBridgeConnection(options) {
|
|
|
40303
40406
|
configOptions: info.configOptions
|
|
40304
40407
|
})
|
|
40305
40408
|
);
|
|
40306
|
-
} catch {
|
|
40409
|
+
} catch (e) {
|
|
40410
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
40307
40411
|
}
|
|
40308
40412
|
if (!changed) return;
|
|
40309
40413
|
const socket = getWs();
|
|
@@ -40386,6 +40490,7 @@ async function createBridgeConnection(options) {
|
|
|
40386
40490
|
const stopFileIndexWatcher = startFileIndexWatcher(getBridgeRoot());
|
|
40387
40491
|
return {
|
|
40388
40492
|
close: async () => {
|
|
40493
|
+
requestCliImmediateShutdown();
|
|
40389
40494
|
stopFileIndexWatcher();
|
|
40390
40495
|
bridgeHeartbeat.stop();
|
|
40391
40496
|
await closeBridgeConnection(state, acpManager, devServerManager, logFn);
|
|
@@ -40459,47 +40564,60 @@ async function runConnectedBridge(options, restartWithoutAuth) {
|
|
|
40459
40564
|
} = options;
|
|
40460
40565
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
40461
40566
|
let cleanupKeyCommand;
|
|
40462
|
-
|
|
40463
|
-
apiUrl,
|
|
40464
|
-
workspaceId,
|
|
40465
|
-
authToken,
|
|
40466
|
-
refreshToken,
|
|
40467
|
-
firehoseServerUrl,
|
|
40468
|
-
justAuthenticated,
|
|
40469
|
-
worktreesRootPath,
|
|
40470
|
-
e2eCertificate,
|
|
40471
|
-
log,
|
|
40472
|
-
persistTokens: (t) => {
|
|
40473
|
-
writeConfigForApi(apiUrl, {
|
|
40474
|
-
workspaceId,
|
|
40475
|
-
token: t.token,
|
|
40476
|
-
refreshToken: t.refreshToken
|
|
40477
|
-
});
|
|
40478
|
-
},
|
|
40479
|
-
onAuthInvalid: () => {
|
|
40480
|
-
cleanupKeyCommand?.();
|
|
40481
|
-
log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
|
|
40482
|
-
clearConfigForApi(apiUrl);
|
|
40483
|
-
void handle.close().then(() => {
|
|
40484
|
-
void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
|
|
40485
|
-
});
|
|
40486
|
-
}
|
|
40487
|
-
});
|
|
40567
|
+
let bridgeClose = null;
|
|
40488
40568
|
const onSignal = (kind) => {
|
|
40569
|
+
requestCliImmediateShutdown();
|
|
40489
40570
|
cleanupKeyCommand?.();
|
|
40490
40571
|
logImmediate(
|
|
40491
40572
|
kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
|
|
40492
40573
|
);
|
|
40493
|
-
|
|
40494
|
-
void
|
|
40495
|
-
|
|
40496
|
-
|
|
40497
|
-
|
|
40574
|
+
if (bridgeClose) {
|
|
40575
|
+
void bridgeClose().then(() => process.exit(0));
|
|
40576
|
+
return;
|
|
40577
|
+
}
|
|
40578
|
+
process.exit(0);
|
|
40498
40579
|
};
|
|
40499
40580
|
const onSigInt = () => onSignal("interrupt");
|
|
40500
40581
|
const onSigTerm = () => onSignal("stop");
|
|
40501
40582
|
process.on("SIGINT", onSigInt);
|
|
40502
40583
|
process.on("SIGTERM", onSigTerm);
|
|
40584
|
+
let handle;
|
|
40585
|
+
try {
|
|
40586
|
+
handle = await createBridgeConnection({
|
|
40587
|
+
apiUrl,
|
|
40588
|
+
workspaceId,
|
|
40589
|
+
authToken,
|
|
40590
|
+
refreshToken,
|
|
40591
|
+
firehoseServerUrl,
|
|
40592
|
+
justAuthenticated,
|
|
40593
|
+
worktreesRootPath,
|
|
40594
|
+
e2eCertificate,
|
|
40595
|
+
log,
|
|
40596
|
+
persistTokens: (t) => {
|
|
40597
|
+
writeConfigForApi(apiUrl, {
|
|
40598
|
+
workspaceId,
|
|
40599
|
+
token: t.token,
|
|
40600
|
+
refreshToken: t.refreshToken
|
|
40601
|
+
});
|
|
40602
|
+
},
|
|
40603
|
+
onAuthInvalid: () => {
|
|
40604
|
+
cleanupKeyCommand?.();
|
|
40605
|
+
log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
|
|
40606
|
+
clearConfigForApi(apiUrl);
|
|
40607
|
+
void handle.close().then(() => {
|
|
40608
|
+
void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
|
|
40609
|
+
});
|
|
40610
|
+
}
|
|
40611
|
+
});
|
|
40612
|
+
} catch (e) {
|
|
40613
|
+
process.off("SIGINT", onSigInt);
|
|
40614
|
+
process.off("SIGTERM", onSigTerm);
|
|
40615
|
+
if (e instanceof CliSqliteInterrupted) {
|
|
40616
|
+
process.exit(0);
|
|
40617
|
+
}
|
|
40618
|
+
throw e;
|
|
40619
|
+
}
|
|
40620
|
+
bridgeClose = () => handle.close();
|
|
40503
40621
|
if (e2eCertificate) {
|
|
40504
40622
|
let openingCertificate = false;
|
|
40505
40623
|
cleanupKeyCommand = installE2eCertificateKeyCommand({
|
|
@@ -40544,6 +40662,7 @@ async function runBridge(options) {
|
|
|
40544
40662
|
}
|
|
40545
40663
|
});
|
|
40546
40664
|
const onSignal = (kind) => {
|
|
40665
|
+
requestCliImmediateShutdown();
|
|
40547
40666
|
logImmediate(
|
|
40548
40667
|
kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
|
|
40549
40668
|
);
|