@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/index.js
CHANGED
|
@@ -23962,7 +23962,7 @@ function installBridgeProcessResilience() {
|
|
|
23962
23962
|
}
|
|
23963
23963
|
|
|
23964
23964
|
// src/cli-version.ts
|
|
23965
|
-
var CLI_VERSION = "0.1.
|
|
23965
|
+
var CLI_VERSION = "0.1.33".length > 0 ? "0.1.33" : "0.0.0-dev";
|
|
23966
23966
|
|
|
23967
23967
|
// src/connection/heartbeat/constants.ts
|
|
23968
23968
|
var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
@@ -25022,6 +25022,30 @@ function runPendingAuth(options) {
|
|
|
25022
25022
|
};
|
|
25023
25023
|
}
|
|
25024
25024
|
|
|
25025
|
+
// src/dev-servers/manager/dev-server-constants.ts
|
|
25026
|
+
var BRIDGE_CLOSE_DEV_SERVER_GRACE_MS = 0;
|
|
25027
|
+
var BRIDGE_SHUTDOWN_GRACE_MS = 8e3;
|
|
25028
|
+
|
|
25029
|
+
// src/runtime/cli-process-interrupt.ts
|
|
25030
|
+
var cliImmediateShutdownRequested = false;
|
|
25031
|
+
function requestCliImmediateShutdown() {
|
|
25032
|
+
cliImmediateShutdownRequested = true;
|
|
25033
|
+
}
|
|
25034
|
+
function isCliImmediateShutdownRequested() {
|
|
25035
|
+
return cliImmediateShutdownRequested;
|
|
25036
|
+
}
|
|
25037
|
+
async function delayMsUnlessShutdownRequested(ms) {
|
|
25038
|
+
if (ms <= 0) return true;
|
|
25039
|
+
const end = Date.now() + ms;
|
|
25040
|
+
while (Date.now() < end) {
|
|
25041
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
25042
|
+
const chunk = Math.min(50, end - Date.now());
|
|
25043
|
+
if (chunk <= 0) break;
|
|
25044
|
+
await new Promise((r) => setTimeout(r, chunk));
|
|
25045
|
+
}
|
|
25046
|
+
return !isCliImmediateShutdownRequested();
|
|
25047
|
+
}
|
|
25048
|
+
|
|
25025
25049
|
// src/sqlite/cli-database.ts
|
|
25026
25050
|
import sqliteWasm from "node-sqlite3-wasm";
|
|
25027
25051
|
|
|
@@ -25325,6 +25349,12 @@ var { Database: SqliteDatabase } = sqliteWasm;
|
|
|
25325
25349
|
var CLI_SQLITE_SYNC_RETRY_MAX = 40;
|
|
25326
25350
|
var CLI_SQLITE_ASYNC_RETRY_MAX = 60;
|
|
25327
25351
|
var CLI_SQLITE_ASYNC_BASE_DELAY_MS = 20;
|
|
25352
|
+
var CliSqliteInterrupted = class extends Error {
|
|
25353
|
+
name = "CliSqliteInterrupted";
|
|
25354
|
+
constructor() {
|
|
25355
|
+
super("CLI SQLite interrupted (shutdown)");
|
|
25356
|
+
}
|
|
25357
|
+
};
|
|
25328
25358
|
function applyCliSqliteConcurrencyPragmas(db) {
|
|
25329
25359
|
try {
|
|
25330
25360
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -25335,7 +25365,7 @@ function applyCliSqliteConcurrencyPragmas(db) {
|
|
|
25335
25365
|
} catch {
|
|
25336
25366
|
}
|
|
25337
25367
|
try {
|
|
25338
|
-
db.run("PRAGMA busy_timeout =
|
|
25368
|
+
db.run("PRAGMA busy_timeout = 500");
|
|
25339
25369
|
} catch {
|
|
25340
25370
|
}
|
|
25341
25371
|
}
|
|
@@ -25356,26 +25386,42 @@ function safeCloseCliSqliteDatabase(db) {
|
|
|
25356
25386
|
function closeAllCliSqliteConnections() {
|
|
25357
25387
|
}
|
|
25358
25388
|
function isCliSqliteLockError(e) {
|
|
25389
|
+
if (e instanceof CliSqliteInterrupted) return false;
|
|
25359
25390
|
const msg = e instanceof Error ? e.message : String(e);
|
|
25360
25391
|
const lower = msg.toLowerCase();
|
|
25361
25392
|
return lower.includes("database is locked") || lower.includes("sqlite_busy") || lower.includes("sqlite3_busy") || lower.includes("database") && lower.includes("locked");
|
|
25362
25393
|
}
|
|
25363
25394
|
function syncSleepMs(ms) {
|
|
25364
25395
|
if (ms <= 0) return;
|
|
25365
|
-
|
|
25366
|
-
|
|
25367
|
-
|
|
25368
|
-
|
|
25369
|
-
|
|
25370
|
-
|
|
25371
|
-
|
|
25396
|
+
const deadline = Date.now() + ms;
|
|
25397
|
+
while (Date.now() < deadline) {
|
|
25398
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
25399
|
+
const chunk = Math.min(80, deadline - Date.now());
|
|
25400
|
+
if (chunk <= 0) break;
|
|
25401
|
+
try {
|
|
25402
|
+
const sab = new SharedArrayBuffer(4);
|
|
25403
|
+
const ia = new Int32Array(sab);
|
|
25404
|
+
Atomics.wait(ia, 0, 0, chunk);
|
|
25405
|
+
} catch {
|
|
25406
|
+
const end = Date.now() + chunk;
|
|
25407
|
+
while (Date.now() < end) {
|
|
25408
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
25409
|
+
}
|
|
25372
25410
|
}
|
|
25373
25411
|
}
|
|
25374
25412
|
}
|
|
25375
|
-
function
|
|
25376
|
-
|
|
25413
|
+
async function asyncDelayMsInterruptible(ms) {
|
|
25414
|
+
const end = Date.now() + ms;
|
|
25415
|
+
while (Date.now() < end) {
|
|
25416
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
25417
|
+
const chunk = Math.min(50, end - Date.now());
|
|
25418
|
+
if (chunk <= 0) break;
|
|
25419
|
+
await new Promise((r) => setTimeout(r, chunk));
|
|
25420
|
+
await yieldToEventLoop();
|
|
25421
|
+
}
|
|
25377
25422
|
}
|
|
25378
25423
|
function openCliSqliteConnection(options) {
|
|
25424
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
25379
25425
|
const sqlitePath = getCliSqlitePath();
|
|
25380
25426
|
ensureCliSqliteParentDir(sqlitePath);
|
|
25381
25427
|
const db = new SqliteDatabase(sqlitePath);
|
|
@@ -25392,6 +25438,7 @@ function openCliSqliteConnection(options) {
|
|
|
25392
25438
|
}
|
|
25393
25439
|
function withCliSqliteSync(fn, options) {
|
|
25394
25440
|
for (let attempt = 1; attempt <= CLI_SQLITE_SYNC_RETRY_MAX; attempt++) {
|
|
25441
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
25395
25442
|
let db;
|
|
25396
25443
|
try {
|
|
25397
25444
|
db = openCliSqliteConnection(options);
|
|
@@ -25402,6 +25449,7 @@ function withCliSqliteSync(fn, options) {
|
|
|
25402
25449
|
}
|
|
25403
25450
|
} catch (e) {
|
|
25404
25451
|
safeCloseCliSqliteDatabase(db);
|
|
25452
|
+
if (e instanceof CliSqliteInterrupted) throw e;
|
|
25405
25453
|
if (!isCliSqliteLockError(e) || attempt === CLI_SQLITE_SYNC_RETRY_MAX) throw e;
|
|
25406
25454
|
syncSleepMs(Math.min(500, 12 * attempt));
|
|
25407
25455
|
}
|
|
@@ -25411,6 +25459,7 @@ function withCliSqliteSync(fn, options) {
|
|
|
25411
25459
|
async function withCliSqlite(fn, options) {
|
|
25412
25460
|
let lastError;
|
|
25413
25461
|
for (let attempt = 1; attempt <= CLI_SQLITE_ASYNC_RETRY_MAX; attempt++) {
|
|
25462
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
25414
25463
|
let db;
|
|
25415
25464
|
try {
|
|
25416
25465
|
db = openCliSqliteConnection(options);
|
|
@@ -25422,9 +25471,10 @@ async function withCliSqlite(fn, options) {
|
|
|
25422
25471
|
} catch (e) {
|
|
25423
25472
|
lastError = e;
|
|
25424
25473
|
safeCloseCliSqliteDatabase(db);
|
|
25474
|
+
if (e instanceof CliSqliteInterrupted) throw e;
|
|
25425
25475
|
if (!isCliSqliteLockError(e) || attempt === CLI_SQLITE_ASYNC_RETRY_MAX) throw e;
|
|
25426
25476
|
const delayMs = Math.min(600, CLI_SQLITE_ASYNC_BASE_DELAY_MS * attempt);
|
|
25427
|
-
await
|
|
25477
|
+
await asyncDelayMsInterruptible(delayMs);
|
|
25428
25478
|
await yieldToEventLoop();
|
|
25429
25479
|
}
|
|
25430
25480
|
}
|
|
@@ -25437,9 +25487,9 @@ async function ensureCliSqliteInitialized(options) {
|
|
|
25437
25487
|
|
|
25438
25488
|
// src/connection/close-bridge-connection.ts
|
|
25439
25489
|
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
25490
|
+
requestCliImmediateShutdown();
|
|
25440
25491
|
const say = log2 ?? logImmediate;
|
|
25441
25492
|
say("Cleaning up connections\u2026");
|
|
25442
|
-
await new Promise((resolve18) => setImmediate(resolve18));
|
|
25443
25493
|
state.closedByUser = true;
|
|
25444
25494
|
clearReconnectQuietTimer(state.mainQuiet);
|
|
25445
25495
|
clearReconnectQuietTimer(state.firehoseQuiet);
|
|
@@ -25476,7 +25526,7 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
|
|
|
25476
25526
|
}
|
|
25477
25527
|
if (devServerManager) {
|
|
25478
25528
|
say("Stopping local dev server processes\u2026");
|
|
25479
|
-
await devServerManager.shutdownAllGraceful();
|
|
25529
|
+
await devServerManager.shutdownAllGraceful({ graceMs: BRIDGE_CLOSE_DEV_SERVER_GRACE_MS });
|
|
25480
25530
|
}
|
|
25481
25531
|
try {
|
|
25482
25532
|
closeAllCliSqliteConnections();
|
|
@@ -30722,34 +30772,50 @@ __export(claude_code_acp_client_exports, {
|
|
|
30722
30772
|
createClaudeCodeAcpClient: () => createClaudeCodeAcpClient,
|
|
30723
30773
|
detectLocalAgentPresence: () => detectLocalAgentPresence
|
|
30724
30774
|
});
|
|
30725
|
-
import { execFile as execFile9 } from "node:child_process";
|
|
30726
|
-
import { promisify as promisify9 } from "node:util";
|
|
30727
30775
|
|
|
30728
30776
|
// src/agents/acp/clients/detect-command-on-path.ts
|
|
30729
30777
|
import { execFile as execFile8 } from "node:child_process";
|
|
30730
30778
|
import { promisify as promisify8 } from "node:util";
|
|
30731
30779
|
var execFileAsync7 = promisify8(execFile8);
|
|
30732
|
-
|
|
30780
|
+
var COMMAND_ON_PATH_PROBE_TIMEOUT_MS = 750;
|
|
30781
|
+
async function execFileShutdownAware(file2, args, timeoutMs) {
|
|
30782
|
+
if (isCliImmediateShutdownRequested()) throw new Error("shutdown");
|
|
30783
|
+
const ac = new AbortController();
|
|
30784
|
+
const shutdownPoll = setInterval(() => {
|
|
30785
|
+
if (isCliImmediateShutdownRequested()) ac.abort();
|
|
30786
|
+
}, 50);
|
|
30787
|
+
shutdownPoll.unref?.();
|
|
30733
30788
|
try {
|
|
30734
|
-
await execFileAsync7(
|
|
30789
|
+
await execFileAsync7(file2, args, { timeout: timeoutMs, signal: ac.signal });
|
|
30790
|
+
} finally {
|
|
30791
|
+
clearInterval(shutdownPoll);
|
|
30792
|
+
}
|
|
30793
|
+
}
|
|
30794
|
+
async function isCommandOnPath(command, timeoutMs = COMMAND_ON_PATH_PROBE_TIMEOUT_MS) {
|
|
30795
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
30796
|
+
try {
|
|
30797
|
+
await execFileShutdownAware("which", [command], timeoutMs);
|
|
30735
30798
|
return true;
|
|
30736
30799
|
} catch {
|
|
30737
30800
|
return false;
|
|
30738
30801
|
}
|
|
30739
30802
|
}
|
|
30740
|
-
|
|
30741
|
-
|
|
30742
|
-
var execFileAsync8 = promisify9(execFile9);
|
|
30743
|
-
var BACKEND_LOCAL_AGENT_TYPE = "claude-code";
|
|
30744
|
-
async function detectLocalAgentPresence() {
|
|
30745
|
-
if (await isCommandOnPath("claude")) return true;
|
|
30803
|
+
async function execProbeShutdownAware(file2, args, timeoutMs) {
|
|
30804
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
30746
30805
|
try {
|
|
30747
|
-
await
|
|
30806
|
+
await execFileShutdownAware(file2, args, timeoutMs);
|
|
30748
30807
|
return true;
|
|
30749
30808
|
} catch {
|
|
30750
30809
|
return false;
|
|
30751
30810
|
}
|
|
30752
30811
|
}
|
|
30812
|
+
|
|
30813
|
+
// src/agents/acp/clients/claude-code-acp-client.ts
|
|
30814
|
+
var BACKEND_LOCAL_AGENT_TYPE = "claude-code";
|
|
30815
|
+
async function detectLocalAgentPresence() {
|
|
30816
|
+
if (await isCommandOnPath("claude")) return true;
|
|
30817
|
+
return execProbeShutdownAware("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], 3e3);
|
|
30818
|
+
}
|
|
30753
30819
|
function buildClaudeCodeAcpSpawnCommand(base, _sessionMode) {
|
|
30754
30820
|
return [...base];
|
|
30755
30821
|
}
|
|
@@ -33577,30 +33643,39 @@ import path27 from "node:path";
|
|
|
33577
33643
|
function shouldSkipWorkspaceWalkEntry(name) {
|
|
33578
33644
|
return name.startsWith(".");
|
|
33579
33645
|
}
|
|
33580
|
-
function
|
|
33646
|
+
async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
33581
33647
|
let names;
|
|
33582
33648
|
try {
|
|
33583
|
-
names = fs24.
|
|
33649
|
+
names = await fs24.promises.readdir(dir);
|
|
33584
33650
|
} catch {
|
|
33585
33651
|
return;
|
|
33586
33652
|
}
|
|
33587
33653
|
for (const name of names) {
|
|
33588
33654
|
if (shouldSkipWorkspaceWalkEntry(name)) continue;
|
|
33655
|
+
if (state.n > 0 && state.n % INDEX_WORK_YIELD_EVERY === 0) {
|
|
33656
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
33657
|
+
await yieldToEventLoop();
|
|
33658
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
33659
|
+
}
|
|
33660
|
+
state.n++;
|
|
33589
33661
|
const full = path27.join(dir, name);
|
|
33590
33662
|
let stat2;
|
|
33591
33663
|
try {
|
|
33592
|
-
stat2 = fs24.
|
|
33664
|
+
stat2 = await fs24.promises.stat(full);
|
|
33593
33665
|
} catch {
|
|
33594
33666
|
continue;
|
|
33595
33667
|
}
|
|
33596
33668
|
const relative5 = path27.relative(baseDir, full).replace(/\\/g, "/");
|
|
33597
33669
|
if (stat2.isDirectory()) {
|
|
33598
|
-
|
|
33670
|
+
await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
|
|
33599
33671
|
} else if (stat2.isFile()) {
|
|
33600
33672
|
onFile(relative5);
|
|
33601
33673
|
}
|
|
33602
33674
|
}
|
|
33603
33675
|
}
|
|
33676
|
+
function createWalkYieldState() {
|
|
33677
|
+
return { n: 0 };
|
|
33678
|
+
}
|
|
33604
33679
|
|
|
33605
33680
|
// src/files/index/file-index-sqlite-lock.ts
|
|
33606
33681
|
import fs25 from "node:fs";
|
|
@@ -33633,29 +33708,28 @@ function withFileIndexSqliteLock(fn) {
|
|
|
33633
33708
|
}
|
|
33634
33709
|
|
|
33635
33710
|
// src/files/index/build-file-index.ts
|
|
33636
|
-
var
|
|
33637
|
-
function
|
|
33711
|
+
var FILE_INDEX_INTERRUPT_CHECK_EVERY = 256;
|
|
33712
|
+
function assertNotShutdown() {
|
|
33713
|
+
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
33714
|
+
}
|
|
33715
|
+
function persistFileIndexPaths(resolved, paths) {
|
|
33638
33716
|
return withCliSqliteSync((db) => {
|
|
33639
33717
|
const h = getCwdHashForFileIndex(resolved);
|
|
33640
|
-
const buf = [];
|
|
33641
33718
|
let pathCount = 0;
|
|
33642
33719
|
db.run("BEGIN IMMEDIATE");
|
|
33643
33720
|
try {
|
|
33644
33721
|
db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
|
|
33645
33722
|
const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
|
|
33646
33723
|
try {
|
|
33647
|
-
|
|
33648
|
-
|
|
33649
|
-
|
|
33724
|
+
let batch = 0;
|
|
33725
|
+
for (const rel of paths) {
|
|
33726
|
+
if (++batch >= FILE_INDEX_INTERRUPT_CHECK_EVERY) {
|
|
33727
|
+
batch = 0;
|
|
33728
|
+
assertNotShutdown();
|
|
33650
33729
|
}
|
|
33651
|
-
|
|
33652
|
-
|
|
33653
|
-
}
|
|
33654
|
-
walkWorkspaceTreeSync(resolved, resolved, (rel) => {
|
|
33655
|
-
buf.push(rel);
|
|
33656
|
-
if (buf.length >= FILE_INDEX_INSERT_BUFFER) flushBuf();
|
|
33657
|
-
});
|
|
33658
|
-
flushBuf();
|
|
33730
|
+
ins.run([h, rel]);
|
|
33731
|
+
pathCount += 1;
|
|
33732
|
+
}
|
|
33659
33733
|
} finally {
|
|
33660
33734
|
ins.finalize();
|
|
33661
33735
|
}
|
|
@@ -33670,12 +33744,24 @@ function persistFileIndexForResolvedCwd(resolved) {
|
|
|
33670
33744
|
return pathCount;
|
|
33671
33745
|
});
|
|
33672
33746
|
}
|
|
33747
|
+
async function collectWorkspacePathsAsync(resolved) {
|
|
33748
|
+
const paths = [];
|
|
33749
|
+
const state = createWalkYieldState();
|
|
33750
|
+
await walkWorkspaceTreeAsync(resolved, resolved, (rel) => {
|
|
33751
|
+
assertNotShutdown();
|
|
33752
|
+
paths.push(rel);
|
|
33753
|
+
}, state);
|
|
33754
|
+
return paths;
|
|
33755
|
+
}
|
|
33673
33756
|
async function buildFileIndexAsync(cwd) {
|
|
33674
33757
|
return withFileIndexSqliteLock(async () => {
|
|
33675
33758
|
const resolved = path28.resolve(cwd);
|
|
33676
33759
|
await yieldToEventLoop();
|
|
33677
|
-
|
|
33760
|
+
assertNotShutdown();
|
|
33761
|
+
const paths = await collectWorkspacePathsAsync(resolved);
|
|
33678
33762
|
await yieldToEventLoop();
|
|
33763
|
+
assertNotShutdown();
|
|
33764
|
+
const pathCount = persistFileIndexPaths(resolved, paths);
|
|
33679
33765
|
return { pathCount };
|
|
33680
33766
|
});
|
|
33681
33767
|
}
|
|
@@ -33779,11 +33865,13 @@ function createFsWatcher(resolved, schedule) {
|
|
|
33779
33865
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
33780
33866
|
const resolved = path30.resolve(cwd);
|
|
33781
33867
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
33868
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
33782
33869
|
console.error("[file-index] Initial index build failed:", e);
|
|
33783
33870
|
});
|
|
33784
33871
|
let timer = null;
|
|
33785
33872
|
const runRebuild = () => {
|
|
33786
33873
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
33874
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
33787
33875
|
console.error("[file-index] Watch rebuild failed:", e);
|
|
33788
33876
|
});
|
|
33789
33877
|
};
|
|
@@ -34317,9 +34405,6 @@ var StreamTail = class {
|
|
|
34317
34405
|
}
|
|
34318
34406
|
};
|
|
34319
34407
|
|
|
34320
|
-
// src/dev-servers/manager/dev-server-constants.ts
|
|
34321
|
-
var BRIDGE_SHUTDOWN_GRACE_MS = 8e3;
|
|
34322
|
-
|
|
34323
34408
|
// src/dev-servers/manager/dev-server-firehose-messages.ts
|
|
34324
34409
|
function buildFirehoseSnapshotMessage(params) {
|
|
34325
34410
|
const payload = {
|
|
@@ -34605,22 +34690,23 @@ var DevServerManager = class {
|
|
|
34605
34690
|
}
|
|
34606
34691
|
this.start(serverId);
|
|
34607
34692
|
}
|
|
34608
|
-
async shutdownAllGraceful() {
|
|
34693
|
+
async shutdownAllGraceful(opts) {
|
|
34694
|
+
const graceMs = opts?.graceMs ?? BRIDGE_SHUTDOWN_GRACE_MS;
|
|
34609
34695
|
const pairs = [...this.processes.entries()];
|
|
34610
34696
|
if (pairs.length === 0) return;
|
|
34611
34697
|
this.log(
|
|
34612
34698
|
`[dev-server] Stopping ${pairs.length} local dev server process${pairs.length === 1 ? "" : "es"}\u2026`
|
|
34613
34699
|
);
|
|
34614
|
-
await Promise.all(pairs.map(([serverId, proc]) => this.gracefulTerminateOrUnknown(serverId, proc)));
|
|
34700
|
+
await Promise.all(pairs.map(([serverId, proc]) => this.gracefulTerminateOrUnknown(serverId, proc, graceMs)));
|
|
34615
34701
|
}
|
|
34616
|
-
async gracefulTerminateOrUnknown(serverId, proc) {
|
|
34702
|
+
async gracefulTerminateOrUnknown(serverId, proc, graceMs) {
|
|
34617
34703
|
const shortId = `${serverId.slice(0, 8)}\u2026`;
|
|
34618
|
-
await sigtermAndWaitForExit(proc,
|
|
34704
|
+
await sigtermAndWaitForExit(proc, graceMs, this.log, shortId);
|
|
34619
34705
|
if (!this.processes.has(serverId) || this.processes.get(serverId) !== proc) {
|
|
34620
34706
|
return;
|
|
34621
34707
|
}
|
|
34622
34708
|
this.bumpGeneration(serverId);
|
|
34623
|
-
forceKillChild(proc, this.log, shortId,
|
|
34709
|
+
forceKillChild(proc, this.log, shortId, graceMs);
|
|
34624
34710
|
this.processes.delete(serverId);
|
|
34625
34711
|
this.clearPoll(serverId);
|
|
34626
34712
|
this.pipedCaptureByServerId.delete(serverId);
|
|
@@ -35047,10 +35133,13 @@ var LOCAL_AGENT_ACP_MODULES = [
|
|
|
35047
35133
|
];
|
|
35048
35134
|
async function detectLocalAgentTypes() {
|
|
35049
35135
|
try {
|
|
35136
|
+
if (isCliImmediateShutdownRequested()) return [];
|
|
35050
35137
|
const out = [];
|
|
35051
35138
|
for (let i = 0; i < LOCAL_AGENT_ACP_MODULES.length; i++) {
|
|
35139
|
+
if (isCliImmediateShutdownRequested()) return out;
|
|
35052
35140
|
if (i > 0) {
|
|
35053
35141
|
await yieldToEventLoop();
|
|
35142
|
+
if (isCliImmediateShutdownRequested()) return out;
|
|
35054
35143
|
}
|
|
35055
35144
|
const mod = LOCAL_AGENT_ACP_MODULES[i];
|
|
35056
35145
|
try {
|
|
@@ -35083,6 +35172,7 @@ function createSendLocalSkillsReport(getWs, logFn) {
|
|
|
35083
35172
|
}
|
|
35084
35173
|
function createReportAutoDetectedAgents(getWs, logFn) {
|
|
35085
35174
|
return async () => {
|
|
35175
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
35086
35176
|
try {
|
|
35087
35177
|
const types = await detectLocalAgentTypes();
|
|
35088
35178
|
const socket = getWs();
|
|
@@ -35182,6 +35272,7 @@ var handleBridgeIdentified = (msg, deps) => {
|
|
|
35182
35272
|
});
|
|
35183
35273
|
setImmediate(() => {
|
|
35184
35274
|
void (async () => {
|
|
35275
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
35185
35276
|
try {
|
|
35186
35277
|
await deps.reportAutoDetectedAgents?.();
|
|
35187
35278
|
} catch (e) {
|
|
@@ -35189,6 +35280,7 @@ var handleBridgeIdentified = (msg, deps) => {
|
|
|
35189
35280
|
`[Bridge service] Auto-detect agents failed: ${e instanceof Error ? e.message : String(e)}`
|
|
35190
35281
|
);
|
|
35191
35282
|
}
|
|
35283
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
35192
35284
|
try {
|
|
35193
35285
|
await deps.warmupAgentCapabilitiesOnConnect?.();
|
|
35194
35286
|
} catch (e) {
|
|
@@ -35199,6 +35291,7 @@ var handleBridgeIdentified = (msg, deps) => {
|
|
|
35199
35291
|
})();
|
|
35200
35292
|
});
|
|
35201
35293
|
setImmediate(() => {
|
|
35294
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
35202
35295
|
try {
|
|
35203
35296
|
deps.sendLocalSkillsReport?.();
|
|
35204
35297
|
} catch (e) {
|
|
@@ -35500,12 +35593,12 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
35500
35593
|
}
|
|
35501
35594
|
|
|
35502
35595
|
// src/agents/acp/from-bridge/bridge-prompt-preamble.ts
|
|
35503
|
-
import { execFile as
|
|
35504
|
-
import { promisify as
|
|
35505
|
-
var
|
|
35596
|
+
import { execFile as execFile9 } from "node:child_process";
|
|
35597
|
+
import { promisify as promisify9 } from "node:util";
|
|
35598
|
+
var execFileAsync8 = promisify9(execFile9);
|
|
35506
35599
|
async function readGitBranch(cwd) {
|
|
35507
35600
|
try {
|
|
35508
|
-
const { stdout } = await
|
|
35601
|
+
const { stdout } = await execFileAsync8("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
|
|
35509
35602
|
const b = stdout.trim();
|
|
35510
35603
|
return b || null;
|
|
35511
35604
|
} catch {
|
|
@@ -36876,6 +36969,7 @@ import * as path39 from "node:path";
|
|
|
36876
36969
|
import * as path38 from "node:path";
|
|
36877
36970
|
async function probeOneAgentTypeForCapabilities(params) {
|
|
36878
36971
|
const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true } = params;
|
|
36972
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
36879
36973
|
const resolved = resolveAgentCommand(agentType);
|
|
36880
36974
|
if (!resolved) return false;
|
|
36881
36975
|
let sqliteChanged = false;
|
|
@@ -36909,6 +37003,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
36909
37003
|
}, 28e3);
|
|
36910
37004
|
killTimer.unref?.();
|
|
36911
37005
|
try {
|
|
37006
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
36912
37007
|
handle = await resolved.createClient({
|
|
36913
37008
|
command: resolved.command,
|
|
36914
37009
|
cwd: path38.resolve(cwd),
|
|
@@ -36928,7 +37023,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
36928
37023
|
onSessionUpdate: () => {
|
|
36929
37024
|
}
|
|
36930
37025
|
});
|
|
36931
|
-
|
|
37026
|
+
if (!await delayMsUnlessShutdownRequested(1200)) return false;
|
|
36932
37027
|
} catch (e) {
|
|
36933
37028
|
log2(
|
|
36934
37029
|
`[Bridge service] Agent capability probe (${agentType}): ${e instanceof Error ? e.message : String(e)}`
|
|
@@ -36956,6 +37051,7 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
|
|
|
36956
37051
|
} = params;
|
|
36957
37052
|
let changedCount = 0;
|
|
36958
37053
|
for (let i = 0; i < agentTypes.length; i++) {
|
|
37054
|
+
if (isCliImmediateShutdownRequested()) return changedCount;
|
|
36959
37055
|
if (i > 0) await yieldToEventLoop();
|
|
36960
37056
|
const agentType = agentTypes[i];
|
|
36961
37057
|
if (!agentType.trim()) continue;
|
|
@@ -36983,6 +37079,7 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
|
|
|
36983
37079
|
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
36984
37080
|
async function warmupAgentCapabilitiesOnConnect(params) {
|
|
36985
37081
|
const { workspaceId, log: log2, getWs } = params;
|
|
37082
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
36986
37083
|
const cwd = path39.resolve(getBridgeRoot());
|
|
36987
37084
|
async function sendBatchFromCache() {
|
|
36988
37085
|
const socket = getWs();
|
|
@@ -36995,18 +37092,21 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
36995
37092
|
items: rows.map((r) => ({ agentType: r.agentType, configOptions: r.configOptions }))
|
|
36996
37093
|
});
|
|
36997
37094
|
} catch (e) {
|
|
37095
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
36998
37096
|
log2(
|
|
36999
37097
|
`[Bridge service] Agent capability batch to bridge failed: ${e instanceof Error ? e.message : String(e)}`
|
|
37000
37098
|
);
|
|
37001
37099
|
}
|
|
37002
37100
|
}
|
|
37003
37101
|
await sendBatchFromCache();
|
|
37102
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
37004
37103
|
let types = [];
|
|
37005
37104
|
try {
|
|
37006
37105
|
types = [...await detectLocalAgentTypes()];
|
|
37007
37106
|
} catch (e) {
|
|
37008
37107
|
log2(`[Bridge service] detectLocalAgentTypes failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
37009
37108
|
}
|
|
37109
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
37010
37110
|
try {
|
|
37011
37111
|
const n = await probeAgentCapabilitiesForDetectedTypes({
|
|
37012
37112
|
agentTypes: types,
|
|
@@ -37018,11 +37118,13 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
37018
37118
|
});
|
|
37019
37119
|
if (n > 0) await sendBatchFromCache();
|
|
37020
37120
|
} catch (e) {
|
|
37121
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
37021
37122
|
log2(`[Bridge service] Agent capability probe (missing cache) failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
37022
37123
|
}
|
|
37023
37124
|
void (async () => {
|
|
37024
37125
|
try {
|
|
37025
37126
|
await yieldToEventLoop();
|
|
37127
|
+
if (isCliImmediateShutdownRequested()) return;
|
|
37026
37128
|
const n = await probeAgentCapabilitiesForDetectedTypes({
|
|
37027
37129
|
agentTypes: types,
|
|
37028
37130
|
cwd,
|
|
@@ -37033,6 +37135,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
37033
37135
|
});
|
|
37034
37136
|
if (n > 0) await sendBatchFromCache();
|
|
37035
37137
|
} catch (e) {
|
|
37138
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
37036
37139
|
log2(`[Bridge service] Agent capability lazy refresh failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
37037
37140
|
}
|
|
37038
37141
|
})();
|
|
@@ -37080,7 +37183,8 @@ async function createBridgeConnection(options) {
|
|
|
37080
37183
|
configOptions: info.configOptions
|
|
37081
37184
|
})
|
|
37082
37185
|
);
|
|
37083
|
-
} catch {
|
|
37186
|
+
} catch (e) {
|
|
37187
|
+
if (e instanceof CliSqliteInterrupted) return;
|
|
37084
37188
|
}
|
|
37085
37189
|
if (!changed) return;
|
|
37086
37190
|
const socket = getWs();
|
|
@@ -37163,6 +37267,7 @@ async function createBridgeConnection(options) {
|
|
|
37163
37267
|
const stopFileIndexWatcher = startFileIndexWatcher(getBridgeRoot());
|
|
37164
37268
|
return {
|
|
37165
37269
|
close: async () => {
|
|
37270
|
+
requestCliImmediateShutdown();
|
|
37166
37271
|
stopFileIndexWatcher();
|
|
37167
37272
|
bridgeHeartbeat.stop();
|
|
37168
37273
|
await closeBridgeConnection(state, acpManager, devServerManager, logFn);
|
|
@@ -37236,47 +37341,60 @@ async function runConnectedBridge(options, restartWithoutAuth) {
|
|
|
37236
37341
|
} = options;
|
|
37237
37342
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
37238
37343
|
let cleanupKeyCommand;
|
|
37239
|
-
|
|
37240
|
-
apiUrl,
|
|
37241
|
-
workspaceId,
|
|
37242
|
-
authToken,
|
|
37243
|
-
refreshToken,
|
|
37244
|
-
firehoseServerUrl,
|
|
37245
|
-
justAuthenticated,
|
|
37246
|
-
worktreesRootPath,
|
|
37247
|
-
e2eCertificate,
|
|
37248
|
-
log,
|
|
37249
|
-
persistTokens: (t) => {
|
|
37250
|
-
writeConfigForApi(apiUrl, {
|
|
37251
|
-
workspaceId,
|
|
37252
|
-
token: t.token,
|
|
37253
|
-
refreshToken: t.refreshToken
|
|
37254
|
-
});
|
|
37255
|
-
},
|
|
37256
|
-
onAuthInvalid: () => {
|
|
37257
|
-
cleanupKeyCommand?.();
|
|
37258
|
-
log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
|
|
37259
|
-
clearConfigForApi(apiUrl);
|
|
37260
|
-
void handle.close().then(() => {
|
|
37261
|
-
void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
|
|
37262
|
-
});
|
|
37263
|
-
}
|
|
37264
|
-
});
|
|
37344
|
+
let bridgeClose = null;
|
|
37265
37345
|
const onSignal = (kind) => {
|
|
37346
|
+
requestCliImmediateShutdown();
|
|
37266
37347
|
cleanupKeyCommand?.();
|
|
37267
37348
|
logImmediate(
|
|
37268
37349
|
kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
|
|
37269
37350
|
);
|
|
37270
|
-
|
|
37271
|
-
void
|
|
37272
|
-
|
|
37273
|
-
|
|
37274
|
-
|
|
37351
|
+
if (bridgeClose) {
|
|
37352
|
+
void bridgeClose().then(() => process.exit(0));
|
|
37353
|
+
return;
|
|
37354
|
+
}
|
|
37355
|
+
process.exit(0);
|
|
37275
37356
|
};
|
|
37276
37357
|
const onSigInt = () => onSignal("interrupt");
|
|
37277
37358
|
const onSigTerm = () => onSignal("stop");
|
|
37278
37359
|
process.on("SIGINT", onSigInt);
|
|
37279
37360
|
process.on("SIGTERM", onSigTerm);
|
|
37361
|
+
let handle;
|
|
37362
|
+
try {
|
|
37363
|
+
handle = await createBridgeConnection({
|
|
37364
|
+
apiUrl,
|
|
37365
|
+
workspaceId,
|
|
37366
|
+
authToken,
|
|
37367
|
+
refreshToken,
|
|
37368
|
+
firehoseServerUrl,
|
|
37369
|
+
justAuthenticated,
|
|
37370
|
+
worktreesRootPath,
|
|
37371
|
+
e2eCertificate,
|
|
37372
|
+
log,
|
|
37373
|
+
persistTokens: (t) => {
|
|
37374
|
+
writeConfigForApi(apiUrl, {
|
|
37375
|
+
workspaceId,
|
|
37376
|
+
token: t.token,
|
|
37377
|
+
refreshToken: t.refreshToken
|
|
37378
|
+
});
|
|
37379
|
+
},
|
|
37380
|
+
onAuthInvalid: () => {
|
|
37381
|
+
cleanupKeyCommand?.();
|
|
37382
|
+
log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
|
|
37383
|
+
clearConfigForApi(apiUrl);
|
|
37384
|
+
void handle.close().then(() => {
|
|
37385
|
+
void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
|
|
37386
|
+
});
|
|
37387
|
+
}
|
|
37388
|
+
});
|
|
37389
|
+
} catch (e) {
|
|
37390
|
+
process.off("SIGINT", onSigInt);
|
|
37391
|
+
process.off("SIGTERM", onSigTerm);
|
|
37392
|
+
if (e instanceof CliSqliteInterrupted) {
|
|
37393
|
+
process.exit(0);
|
|
37394
|
+
}
|
|
37395
|
+
throw e;
|
|
37396
|
+
}
|
|
37397
|
+
bridgeClose = () => handle.close();
|
|
37280
37398
|
if (e2eCertificate) {
|
|
37281
37399
|
let openingCertificate = false;
|
|
37282
37400
|
cleanupKeyCommand = installE2eCertificateKeyCommand({
|
|
@@ -37321,6 +37439,7 @@ async function runBridge(options) {
|
|
|
37321
37439
|
}
|
|
37322
37440
|
});
|
|
37323
37441
|
const onSignal = (kind) => {
|
|
37442
|
+
requestCliImmediateShutdown();
|
|
37324
37443
|
logImmediate(
|
|
37325
37444
|
kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
|
|
37326
37445
|
);
|