@buildautomaton/cli 0.1.77 → 0.1.79

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 CHANGED
@@ -7262,31 +7262,31 @@ function handleWorkerOutMessage(message) {
7262
7262
  return;
7263
7263
  }
7264
7264
  if (message.type === "error") {
7265
- const pending2 = message.requestId != null ? pendingRequests.get(message.requestId) : void 0;
7265
+ const pending3 = message.requestId != null ? pendingRequests.get(message.requestId) : void 0;
7266
7266
  maybeLogCodeNavCacheWorkerError(message.message);
7267
- if (pending2 != null) {
7267
+ if (pending3 != null) {
7268
7268
  pendingRequests.delete(message.requestId);
7269
7269
  if (isCliImmediateShutdownRequested()) {
7270
- pending2.reject(new CliSqliteInterrupted());
7270
+ pending3.reject(new CliSqliteInterrupted());
7271
7271
  } else {
7272
- pending2.reject(new Error(message.message));
7272
+ pending3.reject(new Error(message.message));
7273
7273
  }
7274
7274
  }
7275
7275
  return;
7276
7276
  }
7277
7277
  if (!("requestId" in message)) return;
7278
- const pending = pendingRequests.get(message.requestId);
7279
- if (pending == null) return;
7278
+ const pending2 = pendingRequests.get(message.requestId);
7279
+ if (pending2 == null) return;
7280
7280
  pendingRequests.delete(message.requestId);
7281
- pending.resolve(message);
7281
+ pending2.resolve(message);
7282
7282
  }
7283
7283
  function resetWorkerReadyState() {
7284
7284
  workerReady = false;
7285
7285
  workerReadyWaiters = [];
7286
7286
  }
7287
7287
  function rejectAllPendingRequests(error40) {
7288
- for (const [, pending] of pendingRequests) {
7289
- pending.reject(error40);
7288
+ for (const [, pending2] of pendingRequests) {
7289
+ pending2.reject(error40);
7290
7290
  }
7291
7291
  pendingRequests.clear();
7292
7292
  }
@@ -8319,14 +8319,14 @@ function legacyCliDiskMigrationIsPending() {
8319
8319
  return false;
8320
8320
  }
8321
8321
  function importCliSqliteLegacyDiskData(db, log2) {
8322
- const pending = legacyCliDiskMigrationIsPending();
8323
- if (pending && log2) {
8322
+ const pending2 = legacyCliDiskMigrationIsPending();
8323
+ if (pending2 && log2) {
8324
8324
  log2("Migrating legacy on-disk CLI data to SQLite\u2026");
8325
8325
  }
8326
8326
  archiveLegacyFileIndexJsonFiles();
8327
8327
  importLegacyAgentSessionsFromDisk(db);
8328
8328
  importLegacyPromptQueuesFromDisk(db);
8329
- if (pending && log2) {
8329
+ if (pending2 && log2) {
8330
8330
  log2("Legacy on-disk CLI data migration finished.");
8331
8331
  }
8332
8332
  }
@@ -8413,7 +8413,11 @@ var init_migrate_cli_sqlite = __esm({
8413
8413
  });
8414
8414
 
8415
8415
  // src/sqlite/cli-database.ts
8416
- var cliSqlite, safeCloseCliSqliteDatabase, closeAllCliSqliteConnections, openCliSqliteConnection, withCliSqliteSync, withCliSqlite, ensureCliSqliteInitialized;
8416
+ function closeAllCliSqliteConnections() {
8417
+ legacyImportDoneForPath = null;
8418
+ cliSqlite.closeAllConnections();
8419
+ }
8420
+ var legacyImportDoneForPath, cliSqlite, safeCloseCliSqliteDatabase, openCliSqliteConnection, withCliSqliteSync, withCliSqlite, ensureCliSqliteInitialized;
8417
8421
  var init_cli_database = __esm({
8418
8422
  "src/sqlite/cli-database.ts"() {
8419
8423
  "use strict";
@@ -8423,16 +8427,19 @@ var init_cli_database = __esm({
8423
8427
  init_import_cli_legacy_disk_data();
8424
8428
  init_migrate_cli_sqlite();
8425
8429
  init_sqlite_errors();
8430
+ legacyImportDoneForPath = null;
8426
8431
  cliSqlite = createSqliteDatabaseAccess({
8427
8432
  getPath: getCliSqlitePath,
8428
8433
  ensureParentDir: ensureCliSqliteParentDir,
8429
8434
  migrate: migrateCliSqlite,
8430
8435
  afterOpen: (db, options) => {
8436
+ const sqlitePath = getCliSqlitePath();
8437
+ if (legacyImportDoneForPath === sqlitePath) return;
8431
8438
  importCliSqliteLegacyDiskData(db, options?.logLegacyMigration);
8439
+ legacyImportDoneForPath = sqlitePath;
8432
8440
  }
8433
8441
  });
8434
8442
  safeCloseCliSqliteDatabase = cliSqlite.safeClose;
8435
- closeAllCliSqliteConnections = cliSqlite.closeAllConnections;
8436
8443
  openCliSqliteConnection = cliSqlite.openConnection;
8437
8444
  withCliSqliteSync = cliSqlite.withSync;
8438
8445
  withCliSqlite = cliSqlite.withAsync;
@@ -16650,7 +16657,7 @@ var require_tree_kill = __commonJS({
16650
16657
  "../../node_modules/.pnpm/tree-kill@1.2.2/node_modules/tree-kill/index.js"(exports, module) {
16651
16658
  "use strict";
16652
16659
  var childProcess2 = __require("child_process");
16653
- var spawn11 = childProcess2.spawn;
16660
+ var spawn12 = childProcess2.spawn;
16654
16661
  var exec = childProcess2.exec;
16655
16662
  module.exports = function(pid, signal, callback) {
16656
16663
  if (typeof signal === "function" && callback === void 0) {
@@ -16675,7 +16682,7 @@ var require_tree_kill = __commonJS({
16675
16682
  break;
16676
16683
  case "darwin":
16677
16684
  buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
16678
- return spawn11("pgrep", ["-P", parentPid]);
16685
+ return spawn12("pgrep", ["-P", parentPid]);
16679
16686
  }, function() {
16680
16687
  killAll(tree, signal, callback);
16681
16688
  });
@@ -16687,7 +16694,7 @@ var require_tree_kill = __commonJS({
16687
16694
  // break;
16688
16695
  default:
16689
16696
  buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
16690
- return spawn11("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
16697
+ return spawn12("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
16691
16698
  }, function() {
16692
16699
  killAll(tree, signal, callback);
16693
16700
  });
@@ -31064,7 +31071,7 @@ var {
31064
31071
  } = import_index.default;
31065
31072
 
31066
31073
  // src/cli-version.ts
31067
- var CLI_VERSION = "0.1.77".length > 0 ? "0.1.77" : "0.0.0-dev";
31074
+ var CLI_VERSION = "0.1.79".length > 0 ? "0.1.79" : "0.0.0-dev";
31068
31075
 
31069
31076
  // src/cli/defaults.ts
31070
31077
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
@@ -31691,9 +31698,9 @@ function createWsBridge(options) {
31691
31698
  return ws;
31692
31699
  }
31693
31700
  function sendWsMessage(ws, payload) {
31694
- if (ws.readyState === wrapper_default.OPEN) {
31695
- ws.send(JSON.stringify(payload));
31696
- }
31701
+ if (ws.readyState !== wrapper_default.OPEN) return false;
31702
+ ws.send(JSON.stringify(payload));
31703
+ return true;
31697
31704
  }
31698
31705
 
31699
31706
  // src/connection/heartbeat/constants.ts
@@ -34946,6 +34953,31 @@ function getAgentModelFromAgentConfig(config2) {
34946
34953
  var HOUR_MS = 36e5;
34947
34954
  var DAY_MS = 24 * HOUR_MS;
34948
34955
 
34956
+ // ../types/src/hosts/skus.ts
34957
+ function defineHostSku(params) {
34958
+ return structuredClone(params);
34959
+ }
34960
+ var FLY_LEGACY_HOST_SKU = defineHostSku({
34961
+ id: "fly-shared-1x512-1gb",
34962
+ provider: "fly",
34963
+ compute: { cpus: 1, cpuKind: "shared" },
34964
+ memory: { memoryMb: 512 },
34965
+ storage: { storageGb: 1 },
34966
+ monthlyPriceCents: 750
34967
+ });
34968
+ var FLY_DEFAULT_HOST_SKU = defineHostSku({
34969
+ id: "fly-shared-1x1024-1gb",
34970
+ provider: "fly",
34971
+ compute: { cpus: 1, cpuKind: "shared" },
34972
+ memory: { memoryMb: 1024 },
34973
+ storage: { storageGb: 1 },
34974
+ monthlyPriceCents: 1e3
34975
+ });
34976
+ var HOST_SKUS_BY_ID = {
34977
+ [FLY_LEGACY_HOST_SKU.id]: FLY_LEGACY_HOST_SKU,
34978
+ [FLY_DEFAULT_HOST_SKU.id]: FLY_DEFAULT_HOST_SKU
34979
+ };
34980
+
34949
34981
  // ../types/src/bridges/agents/types.ts
34950
34982
  var INSTALLABLE_BRIDGE_AGENTS = [
34951
34983
  { value: "claude-code", label: "Anthropic Claude Code", tokenLabel: "Anthropic API key", tokenEnvVar: "ANTHROPIC_API_KEY" },
@@ -35446,11 +35478,11 @@ function createSdkStdioExtNotificationHandler(options) {
35446
35478
 
35447
35479
  // src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
35448
35480
  function awaitSdkStdioPermissionRequestHandshake(params) {
35449
- const { requestId, paramsRecord, pending, onRequest } = params;
35481
+ const { requestId, paramsRecord, pending: pending2, onRequest } = params;
35450
35482
  return new Promise((resolve37) => {
35451
- pending.set(requestId, { resolve: resolve37, params: paramsRecord });
35483
+ pending2.set(requestId, { resolve: resolve37, params: paramsRecord });
35452
35484
  if (onRequest == null) {
35453
- pending.delete(requestId);
35485
+ pending2.delete(requestId);
35454
35486
  resolve37({ outcome: { outcome: "denied" } });
35455
35487
  return;
35456
35488
  }
@@ -35466,9 +35498,9 @@ function awaitSdkStdioPermissionRequestHandshake(params) {
35466
35498
  }
35467
35499
 
35468
35500
  // src/agents/acp/clients/sdk/sdk-stdio-permission-pending.ts
35469
- function resolvePendingSdkStdioPermissionCancellations(pending) {
35470
- for (const [id, entry] of [...pending.entries()]) {
35471
- pending.delete(id);
35501
+ function resolvePendingSdkStdioPermissionCancellations(pending2) {
35502
+ for (const [id, entry] of [...pending2.entries()]) {
35503
+ pending2.delete(id);
35472
35504
  entry.resolve({ outcome: { outcome: "cancelled" } });
35473
35505
  }
35474
35506
  }
@@ -36194,8 +36226,8 @@ function createCursorAcpSessionContext(options) {
36194
36226
 
36195
36227
  // src/agents/acp/clients/cursor/cancel-pending-cursor-permission-requests.ts
36196
36228
  function cancelPendingCursorPermissionRequests(pendingRequests2, respond) {
36197
- for (const [reqId, pending] of [...pendingRequests2.entries()]) {
36198
- if (pending.method === "session/request_permission") {
36229
+ for (const [reqId, pending2] of [...pendingRequests2.entries()]) {
36230
+ if (pending2.method === "session/request_permission") {
36199
36231
  respond(reqId, { outcome: { outcome: "cancelled" } });
36200
36232
  pendingRequests2.delete(reqId);
36201
36233
  }
@@ -36387,8 +36419,8 @@ function handleCursorIncomingPermissionRequest(id, method, msg, deps) {
36387
36419
 
36388
36420
  // src/agents/acp/clients/cursor/cursor-incoming-resolve-request.ts
36389
36421
  function resolveCursorIncomingRequest(pendingRequests2, respond, requestId, result) {
36390
- const pending = pendingRequests2.get(requestId);
36391
- const payload = pending?.method === "session/request_permission" ? enrichAcpPermissionRpcResultFromRequestParams(result, pending.params) : result;
36422
+ const pending2 = pendingRequests2.get(requestId);
36423
+ const payload = pending2?.method === "session/request_permission" ? enrichAcpPermissionRpcResultFromRequestParams(result, pending2.params) : result;
36392
36424
  respond(requestId, payload);
36393
36425
  pendingRequests2.delete(requestId);
36394
36426
  }
@@ -36526,25 +36558,25 @@ function createCursorJsonRpcInboundRespond(stdin) {
36526
36558
 
36527
36559
  // src/agents/acp/clients/cursor/cursor-json-rpc-outbound.ts
36528
36560
  function createCursorJsonRpcOutboundPending() {
36529
- const pending = /* @__PURE__ */ new Map();
36561
+ const pending2 = /* @__PURE__ */ new Map();
36530
36562
  let nextId = 1;
36531
36563
  function allocateId() {
36532
36564
  return nextId++;
36533
36565
  }
36534
36566
  function register(id, waiter) {
36535
- pending.set(id, waiter);
36567
+ pending2.set(id, waiter);
36536
36568
  }
36537
36569
  function settleResponse(id, msg) {
36538
- const waiter = pending.get(id);
36570
+ const waiter = pending2.get(id);
36539
36571
  if (!waiter) return false;
36540
- pending.delete(id);
36572
+ pending2.delete(id);
36541
36573
  if (msg.error) waiter.reject(msg.error);
36542
36574
  else waiter.resolve(msg.result);
36543
36575
  return true;
36544
36576
  }
36545
36577
  function rejectOnWriteError(id, err) {
36546
- const waiter = pending.get(id);
36547
- pending.delete(id);
36578
+ const waiter = pending2.get(id);
36579
+ pending2.delete(id);
36548
36580
  waiter?.reject(err);
36549
36581
  }
36550
36582
  return { allocateId, register, settleResponse, rejectOnWriteError };
@@ -36801,13 +36833,15 @@ import { existsSync as existsSync4, statSync } from "node:fs";
36801
36833
  // src/git/get-git-repo-root-sync.ts
36802
36834
  import { execFileSync as execFileSync3 } from "node:child_process";
36803
36835
  import * as path28 from "node:path";
36836
+ var GIT_LOOKUP_TIMEOUT_MS = 2e3;
36804
36837
  function getGitRepoRootSync(startDir) {
36805
36838
  try {
36806
36839
  const out = execFileSync3("git", ["rev-parse", "--show-toplevel"], {
36807
36840
  cwd: path28.resolve(startDir),
36808
36841
  encoding: "utf8",
36809
36842
  stdio: ["ignore", "pipe", "ignore"],
36810
- maxBuffer: 1024 * 1024
36843
+ maxBuffer: 1024 * 1024,
36844
+ timeout: GIT_LOOKUP_TIMEOUT_MS
36811
36845
  }).trim();
36812
36846
  return out ? path28.resolve(out) : null;
36813
36847
  } catch {
@@ -36819,6 +36853,7 @@ function getGitRepoRootSync(startDir) {
36819
36853
  import { execFileSync as execFileSync4 } from "node:child_process";
36820
36854
  import { readFileSync as readFileSync4 } from "node:fs";
36821
36855
  import * as path29 from "node:path";
36856
+ var GIT_FILE_READ_TIMEOUT_MS = 2e3;
36822
36857
  function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
36823
36858
  const trimmed2 = rawPath.trim();
36824
36859
  if (!trimmed2) return null;
@@ -36880,7 +36915,8 @@ function readGitHeadBlob(sessionParentPath, displayPath) {
36880
36915
  return execFileSync4("git", ["show", `HEAD:${displayPath}`], {
36881
36916
  cwd: execCwd,
36882
36917
  encoding: "utf8",
36883
- maxBuffer: 50 * 1024 * 1024
36918
+ maxBuffer: 50 * 1024 * 1024,
36919
+ timeout: GIT_FILE_READ_TIMEOUT_MS
36884
36920
  });
36885
36921
  } catch {
36886
36922
  return "";
@@ -36888,6 +36924,7 @@ function readGitHeadBlob(sessionParentPath, displayPath) {
36888
36924
  }
36889
36925
 
36890
36926
  // src/agents/acp/session-file-change-path-kind.ts
36927
+ var GIT_PATH_KIND_TIMEOUT_MS = 2e3;
36891
36928
  function gitHeadPathObjectType(sessionParentPath, displayPath) {
36892
36929
  if (!displayPath || displayPath.includes("..")) return null;
36893
36930
  const gitRoot = getGitRepoRootSync(sessionParentPath);
@@ -36895,7 +36932,8 @@ function gitHeadPathObjectType(sessionParentPath, displayPath) {
36895
36932
  try {
36896
36933
  return execFileSync5("git", ["cat-file", "-t", `HEAD:${displayPath}`], {
36897
36934
  cwd: gitRoot,
36898
- encoding: "utf8"
36935
+ encoding: "utf8",
36936
+ timeout: GIT_PATH_KIND_TIMEOUT_MS
36899
36937
  }).trim();
36900
36938
  } catch {
36901
36939
  return null;
@@ -38003,23 +38041,30 @@ function augmentPromptResultAuthFields(agentType, errorText) {
38003
38041
  }
38004
38042
 
38005
38043
  // src/agents/planning/submit-planning-todos-for-turn.ts
38044
+ var PLANNING_TODO_SUBMIT_TIMEOUT_MS = 3e3;
38006
38045
  async function submitPlanningTodosForTurn(params) {
38007
38046
  const token = params.getCloudAccessToken();
38008
38047
  if (!token.trim()) return { ok: false, error: "Missing cloud access token" };
38009
38048
  const base = params.cloudApiBaseUrl.replace(/\/$/, "");
38010
38049
  const url2 = `${base}/internal/sessions/todos/submit`;
38011
- const res = await fetch(url2, {
38012
- method: "POST",
38013
- headers: {
38014
- Authorization: `Bearer ${token}`,
38015
- "Content-Type": "application/json"
38016
- },
38017
- body: JSON.stringify({
38018
- sessionId: params.sessionId,
38019
- turnId: params.turnId,
38020
- items: params.items
38021
- })
38022
- });
38050
+ let res;
38051
+ try {
38052
+ res = await fetch(url2, {
38053
+ method: "POST",
38054
+ signal: AbortSignal.timeout(PLANNING_TODO_SUBMIT_TIMEOUT_MS),
38055
+ headers: {
38056
+ Authorization: `Bearer ${token}`,
38057
+ "Content-Type": "application/json"
38058
+ },
38059
+ body: JSON.stringify({
38060
+ sessionId: params.sessionId,
38061
+ turnId: params.turnId,
38062
+ items: params.items
38063
+ })
38064
+ });
38065
+ } catch (error40) {
38066
+ return { ok: false, error: error40 instanceof Error ? error40.message : String(error40) };
38067
+ }
38023
38068
  if (!res.ok) {
38024
38069
  const body = await res.json().catch(() => null);
38025
38070
  return { ok: false, error: body?.error ?? `Planning todo submit failed (${res.status})` };
@@ -38906,6 +38951,7 @@ async function resolveSendPromptImages(params) {
38906
38951
  }
38907
38952
 
38908
38953
  // src/agents/acp/prompts/send-prompt-to-agent.ts
38954
+ var SLOW_ACP_PROMPT_MS = 5e3;
38909
38955
  async function sendPromptToAgent(options) {
38910
38956
  const {
38911
38957
  handle,
@@ -38952,7 +38998,12 @@ async function sendPromptToAgent(options) {
38952
38998
  sendResult(imagesResolved.errorResult);
38953
38999
  return;
38954
39000
  }
39001
+ const promptStartedAt = Date.now();
38955
39002
  const result = await handle.sendPrompt(prepared.agentPromptText, imagesResolved.sendOpts);
39003
+ const promptDurationMs = Date.now() - promptStartedAt;
39004
+ if (promptDurationMs >= SLOW_ACP_PROMPT_MS) {
39005
+ log2(`[Agent] ACP session/prompt completed after ${promptDurationMs}ms.`);
39006
+ }
38956
39007
  await finalizeAndSendPromptResult({
38957
39008
  result,
38958
39009
  sessionId,
@@ -41478,11 +41529,11 @@ function tryConsumeBinaryProxyBody(raw, deps) {
41478
41529
  if (!PROXY_ID_RE.test(id)) return false;
41479
41530
  const body = raw.slice(PROXY_ID_BYTES);
41480
41531
  const bodyBytes = body.length > 0 ? new Uint8Array(body) : new Uint8Array(0);
41481
- const pending = deps.pendingProxyBody.get(id);
41482
- if (pending) {
41532
+ const pending2 = deps.pendingProxyBody.get(id);
41533
+ if (pending2) {
41483
41534
  deps.pendingProxyBody.delete(id);
41484
41535
  deps.startStreamingProxy({
41485
- ...pending.pr,
41536
+ ...pending2.pr,
41486
41537
  body: bodyBytes.length > 0 ? bodyBytes : void 0
41487
41538
  });
41488
41539
  return true;
@@ -41875,9 +41926,9 @@ function processHeartbeatAck(params) {
41875
41926
  if (awaitingSeq === null) return { awaitingSeq, missed: 0 };
41876
41927
  if (!Number.isFinite(seq)) return { awaitingSeq, missed: 0 };
41877
41928
  const ack = Math.trunc(seq);
41878
- const pending = awaitingSeq;
41879
- if (ack < pending) return { awaitingSeq, missed: 0 };
41880
- if (ack === pending) {
41929
+ const pending2 = awaitingSeq;
41930
+ if (ack < pending2) return { awaitingSeq, missed: 0 };
41931
+ if (ack === pending2) {
41881
41932
  recordRtt(Date.now() - sentAtMs);
41882
41933
  }
41883
41934
  return { awaitingSeq: null, missed: 0 };
@@ -49525,9 +49576,13 @@ import * as fs50 from "node:fs";
49525
49576
  import * as path71 from "node:path";
49526
49577
 
49527
49578
  // src/git/snapshot/git.ts
49579
+ var SNAPSHOT_GIT_TIMEOUT_MS = 5e3;
49528
49580
  async function gitStashCreate(repoRoot, log2) {
49529
49581
  try {
49530
- const { stdout } = await execGitFile(["stash", "create"], { cwd: repoRoot });
49582
+ const { stdout } = await execGitFile(["stash", "create"], {
49583
+ cwd: repoRoot,
49584
+ timeout: SNAPSHOT_GIT_TIMEOUT_MS
49585
+ });
49531
49586
  return stdout.trim();
49532
49587
  } catch (e) {
49533
49588
  log2(
@@ -49538,7 +49593,10 @@ async function gitStashCreate(repoRoot, log2) {
49538
49593
  }
49539
49594
  async function gitUntrackedPaths(repoRoot, log2) {
49540
49595
  try {
49541
- const { stdout } = await execGitFile(["ls-files", "--others", "--exclude-standard"], { cwd: repoRoot });
49596
+ const { stdout } = await execGitFile(["ls-files", "--others", "--exclude-standard"], {
49597
+ cwd: repoRoot,
49598
+ timeout: SNAPSHOT_GIT_TIMEOUT_MS
49599
+ });
49542
49600
  return stdout.split("\n").map((l) => l.trim()).filter(Boolean);
49543
49601
  } catch (e) {
49544
49602
  log2(
@@ -52223,28 +52281,78 @@ async function startPromptQueueRuns(entries, deps) {
52223
52281
  }
52224
52282
 
52225
52283
  // src/prompt-turn-queue/runner/apply-prompt-queue-state-from-server.ts
52284
+ var SLOW_QUEUE_SYNC_MS = 2e3;
52226
52285
  async function applyPromptQueueStateFromServer(msg, deps) {
52227
52286
  const raw = msg.queues;
52228
52287
  if (!raw || typeof raw !== "object") return;
52288
+ const startedAt = Date.now();
52229
52289
  const entries = promptQueueSnapshotEntries(raw);
52230
52290
  await persistPromptQueueSnapshot(entries);
52231
52291
  await handlePromptQueueCancellations(entries, deps);
52232
52292
  const started = await startPromptQueueRuns(entries, deps);
52233
52293
  await dispatchStartedPromptQueueRuns(entries, started, deps);
52294
+ const durationMs = Date.now() - startedAt;
52295
+ if (durationMs >= SLOW_QUEUE_SYNC_MS) {
52296
+ deps.log(`[Queue] Queue state sync and dispatch took ${durationMs}ms.`);
52297
+ }
52298
+ }
52299
+
52300
+ // src/agents/acp/from-bridge/pending-prompt-results.ts
52301
+ var pending = [];
52302
+ function enqueuePendingPromptResult(message) {
52303
+ const runId = typeof message.runId === "string" ? message.runId : "";
52304
+ if (runId) {
52305
+ const idx = pending.findIndex((m) => m.runId === runId);
52306
+ if (idx >= 0) pending.splice(idx, 1);
52307
+ }
52308
+ pending.push(message);
52309
+ }
52310
+ function flushPendingPromptResults(getWs, encrypt) {
52311
+ if (pending.length === 0) return;
52312
+ const ws = getWs();
52313
+ if (!ws || ws.readyState !== wrapper_default.OPEN) return;
52314
+ const still = [];
52315
+ for (const message of pending) {
52316
+ const wire = encrypt ? encrypt(message) : message;
52317
+ if (!sendWsMessage(ws, wire)) still.push(message);
52318
+ }
52319
+ pending.length = 0;
52320
+ pending.push(...still);
52321
+ }
52322
+
52323
+ // src/agents/acp/from-bridge/send-session-update-wire.ts
52324
+ function sendSessionUpdateWire(getWs, payload, opts) {
52325
+ const s = getWs();
52326
+ if (!s || s.readyState !== wrapper_default.OPEN) {
52327
+ opts.log("[Bridge service] Session update not sent: not connected to the bridge.");
52328
+ return;
52329
+ }
52330
+ const p = payload;
52331
+ const wire = p.type === "session_update" && opts.e2ee ? opts.e2ee.encryptFields(payload, ["payload"]) : p.type === "session_file_change" && opts.e2ee ? opts.e2ee.encryptFields(payload, [
52332
+ "path",
52333
+ "oldText",
52334
+ "newText",
52335
+ "patchContent",
52336
+ "isDirectory",
52337
+ "directoryRemoved"
52338
+ ]) : payload;
52339
+ sendWsMessage(s, wire);
52234
52340
  }
52235
52341
 
52236
52342
  // src/agents/acp/from-bridge/bridge-prompt-wiring.ts
52237
52343
  function createBridgePromptSenders(deps, getWs) {
52238
52344
  const sendBridgeMessage = (message, encryptedFields = []) => {
52239
52345
  const s = getWs();
52240
- if (!s) return false;
52346
+ if (!s || s.readyState !== wrapper_default.OPEN) return false;
52241
52347
  const wire = deps.e2ee && encryptedFields.length > 0 ? deps.e2ee.encryptFields(message, encryptedFields) : message;
52242
- sendWsMessage(s, wire);
52243
- return true;
52348
+ return sendWsMessage(s, wire);
52244
52349
  };
52245
52350
  const sendResult = (result) => {
52246
- const encryptedFields = result.type === "prompt_result" ? ["output", "error"] : [];
52247
- sendBridgeMessage(result, encryptedFields);
52351
+ const sent = sendBridgeMessage(result, result.type === "prompt_result" ? ["output", "error"] : []);
52352
+ if (!sent && result.type === "prompt_result") {
52353
+ enqueuePendingPromptResult(result);
52354
+ deps.log("[Bridge service] prompt_result deferred until bridge reconnect.");
52355
+ }
52248
52356
  if (result.type === "prompt_result") {
52249
52357
  const pr = result;
52250
52358
  const cancelled = pr.stopReason === "cancelled";
@@ -52257,24 +52365,11 @@ function createBridgePromptSenders(deps, getWs) {
52257
52365
  });
52258
52366
  }
52259
52367
  };
52260
- const sendSessionUpdate = (payload) => {
52261
- const s = getWs();
52262
- if (!s) {
52263
- deps.log("[Bridge service] Session update not sent: not connected to the bridge.");
52264
- return;
52265
- }
52266
- const p = payload;
52267
- const wire = p.type === "session_update" && deps.e2ee ? deps.e2ee.encryptFields(payload, ["payload"]) : p.type === "session_file_change" && deps.e2ee ? deps.e2ee.encryptFields(payload, [
52268
- "path",
52269
- "oldText",
52270
- "newText",
52271
- "patchContent",
52272
- "isDirectory",
52273
- "directoryRemoved"
52274
- ]) : payload;
52275
- sendWsMessage(s, wire);
52368
+ return {
52369
+ sendBridgeMessage,
52370
+ sendResult,
52371
+ sendSessionUpdate: (payload) => sendSessionUpdateWire(getWs, payload, { e2ee: deps.e2ee, log: deps.log })
52276
52372
  };
52277
- return { sendBridgeMessage, sendResult, sendSessionUpdate };
52278
52373
  }
52279
52374
 
52280
52375
  // src/agents/acp/from-bridge/handle-bridge-prompt/parse-bridge-attachments.ts
@@ -52307,59 +52402,93 @@ function parseWorktreeBaseBranches(msg) {
52307
52402
  return Object.keys(out).length > 0 ? out : void 0;
52308
52403
  }
52309
52404
 
52310
- // src/agents/acp/from-bridge/bridge-prompt-preamble.ts
52405
+ // src/agents/acp/from-bridge/parse-follow-up-prompt-fields.ts
52406
+ function parseFollowUpFieldsFromPromptMessage(msg) {
52407
+ const value = msg.followUpCatalogPromptId;
52408
+ return {
52409
+ followUpCatalogPromptId: typeof value === "string" && value.trim() !== "" ? value.trim() : null
52410
+ };
52411
+ }
52412
+
52413
+ // src/agents/acp/from-bridge/prepare-bridge-prompt-git-state.ts
52311
52414
  import { execFile as execFile8 } from "node:child_process";
52312
52415
  import { promisify as promisify9 } from "node:util";
52416
+
52417
+ // src/agents/acp/from-bridge/git-state-preparation-timeout.ts
52418
+ async function awaitGitStatePreparation(options) {
52419
+ const { label, timeoutMs, work, fallback, log: log2 } = options;
52420
+ let timer;
52421
+ try {
52422
+ return await Promise.race([
52423
+ work,
52424
+ new Promise((resolve37) => {
52425
+ timer = setTimeout(() => {
52426
+ log2(`[Agent] ${label} exceeded ${timeoutMs}ms; continuing without it.`);
52427
+ resolve37(fallback);
52428
+ }, timeoutMs);
52429
+ timer.unref?.();
52430
+ })
52431
+ ]);
52432
+ } finally {
52433
+ if (timer) clearTimeout(timer);
52434
+ }
52435
+ }
52436
+
52437
+ // src/agents/acp/from-bridge/prepare-bridge-prompt-git-state.ts
52313
52438
  var execFileAsync7 = promisify9(execFile8);
52439
+ var GIT_STATE_DISCOVERY_TIMEOUT_MS = 2e3;
52314
52440
  async function readGitBranch(cwd) {
52315
52441
  try {
52316
- const { stdout } = await execFileAsync7("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
52317
- const b = stdout.trim();
52318
- return b || null;
52442
+ const { stdout } = await execFileAsync7("git", ["branch", "--show-current"], {
52443
+ cwd,
52444
+ maxBuffer: 64 * 1024,
52445
+ timeout: GIT_STATE_DISCOVERY_TIMEOUT_MS
52446
+ });
52447
+ return stdout.trim() || null;
52319
52448
  } catch {
52320
52449
  return null;
52321
52450
  }
52322
52451
  }
52323
- async function runBridgePromptPreamble(params) {
52452
+ async function prepareBridgePromptGitState(params) {
52324
52453
  const { getWs, log: log2, sessionWorktreeManager, sessionId, runId, effectiveCwd } = params;
52325
- const s = getWs();
52326
- const repoCheckoutPaths = await sessionWorktreeManager.ensureRepoCheckoutPathsForSessionAsync(sessionId);
52454
+ const repoCheckoutPaths = await awaitGitStatePreparation({
52455
+ label: "Session worktree discovery",
52456
+ timeoutMs: GIT_STATE_DISCOVERY_TIMEOUT_MS,
52457
+ work: sessionWorktreeManager.ensureRepoCheckoutPathsForSessionAsync(sessionId),
52458
+ fallback: void 0,
52459
+ log: log2
52460
+ });
52327
52461
  const repoRoots = await resolveSnapshotRepoRoots({
52328
52462
  worktreePaths: repoCheckoutPaths,
52329
52463
  fallbackCwd: effectiveCwd,
52330
52464
  sessionId: sessionId?.trim() || void 0,
52331
52465
  log: log2
52332
52466
  });
52333
- if (s && sessionId) {
52334
- const usesWt = sessionWorktreeManager.usesWorktreeSession(sessionId);
52335
- const cliGitBranch = repoRoots.length > 0 ? await readGitBranch(effectiveCwd) : null;
52336
- const isolatedSessionParentPath = sessionWorktreeManager.getIsolatedSessionParentPathForSession(sessionId);
52337
- sendWsMessage(s, {
52467
+ const socket = getWs();
52468
+ if (socket && sessionId) {
52469
+ const usesWorktree = sessionWorktreeManager.usesWorktreeSession(sessionId);
52470
+ sendWsMessage(socket, {
52338
52471
  type: "session_git_context_report",
52339
52472
  sessionId,
52340
- cliGitBranch,
52341
- agentUsesWorktree: usesWt,
52342
- sessionParent: usesWt ? "worktrees_root" : "bridge_root",
52343
- sessionParentPath: usesWt ? isolatedSessionParentPath ?? effectiveCwd : getBridgeRoot()
52473
+ cliGitBranch: repoRoots.length > 0 ? await readGitBranch(effectiveCwd) : null,
52474
+ agentUsesWorktree: usesWorktree,
52475
+ sessionParent: usesWorktree ? "worktrees_root" : "bridge_root",
52476
+ sessionParentPath: usesWorktree ? sessionWorktreeManager.getIsolatedSessionParentPathForSession(sessionId) ?? effectiveCwd : getBridgeRoot()
52344
52477
  });
52345
52478
  }
52346
- if (s && sessionId && runId) {
52347
- const cap = repoRoots.length > 0 ? await capturePreTurnSnapshot({ runId, repoRoots, agentCwd: effectiveCwd, log: log2 }) : { ok: false, error: "No git repos" };
52348
- sendWsMessage(s, {
52479
+ if (socket && sessionId && runId) {
52480
+ const snapshot = repoRoots.length > 0 ? await capturePreTurnSnapshot({ runId, repoRoots, agentCwd: effectiveCwd, log: log2 }) : { ok: false };
52481
+ sendWsMessage(socket, {
52349
52482
  type: "pre_turn_snapshot_report",
52350
52483
  sessionId,
52351
52484
  turnId: runId,
52352
- captured: cap.ok
52485
+ captured: snapshot.ok
52353
52486
  });
52354
52487
  }
52355
52488
  }
52356
- function parseFollowUpFieldsFromPromptMessage(msg) {
52357
- const followUpCatalogPromptId = typeof msg.followUpCatalogPromptId === "string" && msg.followUpCatalogPromptId.trim() !== "" ? msg.followUpCatalogPromptId.trim() : null;
52358
- return { followUpCatalogPromptId };
52359
- }
52360
52489
 
52361
- // src/agents/acp/from-bridge/handle-bridge-prompt/run-preamble-and-prompt.ts
52362
- async function runPreambleAndPrompt(params) {
52490
+ // src/agents/acp/from-bridge/handle-bridge-prompt/prepare-git-state-and-run-prompt.ts
52491
+ async function prepareGitStateAndRunPrompt(params) {
52363
52492
  const {
52364
52493
  deps,
52365
52494
  msg,
@@ -52378,7 +52507,7 @@ async function runPreambleAndPrompt(params) {
52378
52507
  senders: { sendResult, sendSessionUpdate }
52379
52508
  } = params;
52380
52509
  const effectiveCwd = resolveSessionParentPathForAgentProcess(resolvedCwd);
52381
- await runBridgePromptPreamble({
52510
+ await prepareBridgePromptGitState({
52382
52511
  getWs,
52383
52512
  log: log2,
52384
52513
  sessionWorktreeManager,
@@ -52449,7 +52578,7 @@ function handleBridgePrompt(msg, deps) {
52449
52578
  sessionParentPath,
52450
52579
  ...worktreeBaseBranches ? { worktreeBaseBranches } : {}
52451
52580
  }).then(
52452
- (cwd) => runPreambleAndPrompt({
52581
+ (cwd) => prepareGitStateAndRunPrompt({
52453
52582
  deps,
52454
52583
  msg,
52455
52584
  getWs,
@@ -52468,7 +52597,7 @@ function handleBridgePrompt(msg, deps) {
52468
52597
  })
52469
52598
  ).catch((err) => {
52470
52599
  log2(`[Agent] Session parent path resolve failed: ${err instanceof Error ? err.message : String(err)}`);
52471
- void runPreambleAndPrompt({
52600
+ void prepareGitStateAndRunPrompt({
52472
52601
  deps,
52473
52602
  msg,
52474
52603
  getWs,
@@ -53124,25 +53253,59 @@ var handleInstallSkillsMessage = (msg, deps) => {
53124
53253
  })();
53125
53254
  };
53126
53255
 
53127
- // src/agents/install/commands/run-npm-global-install.ts
53128
- import { execFile as execFile9 } from "node:child_process";
53129
- import { promisify as promisify10 } from "node:util";
53130
-
53131
- // src/agents/install/format-command-output.ts
53132
- function formatCommandOutput(stdout, stderr) {
53133
- const parts = [String(stdout ?? "").trimEnd(), String(stderr ?? "").trimEnd()].filter(Boolean);
53134
- return parts.join("\n");
53256
+ // src/agents/install/run-streaming-command.ts
53257
+ import { spawn as spawn11 } from "node:child_process";
53258
+ import * as readline3 from "node:readline";
53259
+ function runStreamingCommand(command, args, options) {
53260
+ return new Promise((resolve37, reject) => {
53261
+ const child = spawn11(command, args, {
53262
+ env: options.env,
53263
+ stdio: ["ignore", "pipe", "pipe"]
53264
+ });
53265
+ let settled = false;
53266
+ const timer = options.timeoutMs != null ? setTimeout(() => {
53267
+ child.kill("SIGKILL");
53268
+ if (!settled) {
53269
+ settled = true;
53270
+ reject(new Error(`Command timed out after ${options.timeoutMs}ms`));
53271
+ }
53272
+ }, options.timeoutMs) : null;
53273
+ const onLine = (line) => {
53274
+ if (line.length > 0) options.onLine?.(line);
53275
+ };
53276
+ if (child.stdout) {
53277
+ readline3.createInterface({ input: child.stdout, crlfDelay: Infinity }).on("line", onLine);
53278
+ }
53279
+ if (child.stderr) {
53280
+ readline3.createInterface({ input: child.stderr, crlfDelay: Infinity }).on("line", onLine);
53281
+ }
53282
+ child.on("error", (err) => {
53283
+ if (timer) clearTimeout(timer);
53284
+ if (!settled) {
53285
+ settled = true;
53286
+ reject(err);
53287
+ }
53288
+ });
53289
+ child.on("close", (code, signal) => {
53290
+ if (timer) clearTimeout(timer);
53291
+ if (!settled) {
53292
+ settled = true;
53293
+ resolve37({ code, signal });
53294
+ }
53295
+ });
53296
+ });
53135
53297
  }
53136
53298
 
53137
53299
  // src/agents/install/commands/run-npm-global-install.ts
53138
- var execFileAsync8 = promisify10(execFile9);
53139
- async function runNpmGlobalInstall(packageName, env, timeoutMs = 3e5) {
53140
- const { stdout, stderr } = await execFileAsync8("npm", ["install", "-g", packageName], {
53141
- timeout: timeoutMs,
53300
+ async function runNpmGlobalInstall(packageName, env, options) {
53301
+ const result = await runStreamingCommand("npm", ["install", "-g", packageName], {
53142
53302
  env: bridgeAgentPathEnv(env),
53143
- maxBuffer: 10 * 1024 * 1024
53303
+ timeoutMs: options?.timeoutMs ?? 3e5,
53304
+ onLine: options?.onLine
53144
53305
  });
53145
- return formatCommandOutput(stdout, stderr);
53306
+ if (result.code !== 0) {
53307
+ throw new Error(`npm install -g ${packageName} failed (exit ${result.code ?? "signal"})`);
53308
+ }
53146
53309
  }
53147
53310
 
53148
53311
  // src/agents/install/commands/claude-code.ts
@@ -53150,11 +53313,12 @@ var claudeCodeInstallCommand = {
53150
53313
  agentType: "claude-code",
53151
53314
  detectCommand: "claude",
53152
53315
  async install(ctx) {
53153
- const logOutput = await runNpmGlobalInstall("@anthropic-ai/claude-code", {
53154
- ...ctx.env,
53155
- ANTHROPIC_API_KEY: ctx.authToken
53156
- });
53157
- ctx.onProgress?.("Installing Anthropic Claude Code", logOutput || void 0);
53316
+ ctx.onProgress?.("Installing Anthropic Claude Code");
53317
+ await runNpmGlobalInstall(
53318
+ "@anthropic-ai/claude-code",
53319
+ { ...ctx.env, ANTHROPIC_API_KEY: ctx.authToken },
53320
+ { onLine: (line) => ctx.onProgress?.("Installing Anthropic Claude Code", line) }
53321
+ );
53158
53322
  }
53159
53323
  };
53160
53324
 
@@ -53163,34 +53327,34 @@ var codexAcpInstallCommand = {
53163
53327
  agentType: "codex-acp",
53164
53328
  detectCommand: "codex",
53165
53329
  async install(ctx) {
53166
- const logOutput = await runNpmGlobalInstall("@openai/codex", {
53167
- ...ctx.env,
53168
- OPENAI_API_KEY: ctx.authToken
53169
- });
53170
- ctx.onProgress?.("Installing Codex", logOutput || void 0);
53330
+ ctx.onProgress?.("Installing Codex");
53331
+ await runNpmGlobalInstall(
53332
+ "@openai/codex",
53333
+ { ...ctx.env, OPENAI_API_KEY: ctx.authToken },
53334
+ { onLine: (line) => ctx.onProgress?.("Installing Codex", line) }
53335
+ );
53171
53336
  }
53172
53337
  };
53173
53338
 
53174
53339
  // src/agents/install/commands/cursor-cli.ts
53175
- import { execFile as execFile10 } from "node:child_process";
53176
- import { promisify as promisify11 } from "node:util";
53177
- var execFileAsync9 = promisify11(execFile10);
53178
53340
  var cursorCliInstallCommand = {
53179
53341
  agentType: "cursor-cli",
53180
53342
  detectCommand: "agent",
53181
53343
  alternateDetectCommands: ["cursor-agent"],
53182
53344
  async install(ctx) {
53183
- const { stdout, stderr } = await execFileAsync9(
53345
+ ctx.onProgress?.("Installing Cursor CLI");
53346
+ const result = await runStreamingCommand(
53184
53347
  "bash",
53185
53348
  ["-lc", "curl -fsSL https://cursor.com/install | bash"],
53186
53349
  {
53187
- timeout: 3e5,
53350
+ timeoutMs: 3e5,
53188
53351
  env: { ...bridgeAgentPathEnv(ctx.env), CURSOR_API_KEY: ctx.authToken },
53189
- maxBuffer: 10 * 1024 * 1024
53352
+ onLine: (line) => ctx.onProgress?.("Installing Cursor CLI", line)
53190
53353
  }
53191
53354
  );
53192
- const logOutput = formatCommandOutput(stdout, stderr);
53193
- ctx.onProgress?.("Installing Cursor CLI", logOutput || void 0);
53355
+ if (result.code !== 0) {
53356
+ throw new Error(`Cursor CLI install failed (exit ${result.code ?? "signal"})`);
53357
+ }
53194
53358
  }
53195
53359
  };
53196
53360
 
@@ -53199,11 +53363,12 @@ var opencodeInstallCommand = {
53199
53363
  agentType: "opencode",
53200
53364
  detectCommand: "opencode",
53201
53365
  async install(ctx) {
53202
- const logOutput = await runNpmGlobalInstall("opencode-ai", {
53203
- ...ctx.env,
53204
- OPENCODE_API_KEY: ctx.authToken
53205
- });
53206
- ctx.onProgress?.("Installing OpenCode", logOutput || void 0);
53366
+ ctx.onProgress?.("Installing OpenCode");
53367
+ await runNpmGlobalInstall(
53368
+ "opencode-ai",
53369
+ { ...ctx.env, OPENCODE_API_KEY: ctx.authToken },
53370
+ { onLine: (line) => ctx.onProgress?.("Installing OpenCode", line) }
53371
+ );
53207
53372
  }
53208
53373
  };
53209
53374
 
@@ -53264,25 +53429,47 @@ var handleInstallAgentMessage = (msg, deps) => {
53264
53429
  if (!processId || !agentId || !tokenId || !agentType || !authToken) return;
53265
53430
  void (async () => {
53266
53431
  const socket = deps.getWs();
53267
- const report = (step, message, logOutput) => {
53268
- if (socket) {
53269
- sendWsMessage(socket, {
53270
- type: "install_agent_progress",
53271
- processId,
53272
- agentId,
53273
- tokenId,
53274
- agentType,
53275
- step,
53276
- message,
53277
- ...logOutput ? { logOutput } : {}
53278
- });
53432
+ let pendingLines = [];
53433
+ let flushTimer = null;
53434
+ const sendProgress = (message, logOutput) => {
53435
+ if (!socket) return;
53436
+ sendWsMessage(socket, {
53437
+ type: "install_agent_progress",
53438
+ processId,
53439
+ agentId,
53440
+ tokenId,
53441
+ agentType,
53442
+ step: "agent_install_package",
53443
+ message,
53444
+ ...logOutput ? { logOutput } : {}
53445
+ });
53446
+ };
53447
+ const flushLines = (message) => {
53448
+ if (flushTimer) {
53449
+ clearTimeout(flushTimer);
53450
+ flushTimer = null;
53279
53451
  }
53452
+ if (pendingLines.length === 0) return;
53453
+ const logOutput = pendingLines.join("\n");
53454
+ pendingLines = [];
53455
+ sendProgress(message, logOutput);
53280
53456
  };
53281
53457
  const result = await installLocalAgentOnBridge({
53282
53458
  agentType,
53283
53459
  authToken,
53284
- onProgress: (message, logOutput) => report("agent_install_package", message, logOutput)
53460
+ onProgress: (message, logOutput) => {
53461
+ if (logOutput == null) {
53462
+ flushLines(message);
53463
+ sendProgress(message);
53464
+ return;
53465
+ }
53466
+ pendingLines.push(logOutput);
53467
+ if (!flushTimer) {
53468
+ flushTimer = setTimeout(() => flushLines(message), 100);
53469
+ }
53470
+ }
53285
53471
  });
53472
+ flushLines("Installing agent packages on the bridge machine.");
53286
53473
  if (socket) {
53287
53474
  sendWsMessage(socket, {
53288
53475
  type: "install_agent_result",
@@ -53294,9 +53481,7 @@ var handleInstallAgentMessage = (msg, deps) => {
53294
53481
  error: result.error
53295
53482
  });
53296
53483
  }
53297
- if (result.success) {
53298
- await deps.reportAutoDetectedAgents?.();
53299
- }
53484
+ if (result.success) await deps.reportAutoDetectedAgents?.();
53300
53485
  if (!result.success) {
53301
53486
  deps.log(`[Bridge service] Install agent failed: ${result.error ?? "unknown"}`);
53302
53487
  }
@@ -53881,6 +54066,10 @@ function createMainBridgeOpenHandler(params) {
53881
54066
  if (socket) {
53882
54067
  sendBridgeIdentify(socket, { identifyReportedPaths, e2ee });
53883
54068
  reportGitRepos(getWs, logFn);
54069
+ flushPendingPromptResults(
54070
+ getWs,
54071
+ (message) => e2ee ? e2ee.encryptFields(message, ["output", "error"]) : message
54072
+ );
53884
54073
  try {
53885
54074
  onBridgeSocketOpen?.();
53886
54075
  } catch {
@@ -54025,7 +54214,7 @@ async function createBridgeConnection(options) {
54025
54214
  }
54026
54215
 
54027
54216
  // src/e2e-certificates/key-command.ts
54028
- import * as readline3 from "node:readline";
54217
+ import * as readline4 from "node:readline";
54029
54218
  function installE2eCertificateKeyCommand({
54030
54219
  log: log2,
54031
54220
  onOpenCertificate,
@@ -54036,7 +54225,7 @@ function installE2eCertificateKeyCommand({
54036
54225
  return () => {
54037
54226
  };
54038
54227
  }
54039
- readline3.emitKeypressEvents(process.stdin);
54228
+ readline4.emitKeypressEvents(process.stdin);
54040
54229
  process.stdin.setRawMode(true);
54041
54230
  process.stdin.resume();
54042
54231
  const onKeypress = (str, key) => {