@buildautomaton/cli 0.1.29 → 0.1.31

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
@@ -973,7 +973,7 @@ var require_command = __commonJS({
973
973
  "../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
974
974
  var EventEmitter2 = __require("node:events").EventEmitter;
975
975
  var childProcess2 = __require("node:child_process");
976
- var path41 = __require("node:path");
976
+ var path43 = __require("node:path");
977
977
  var fs38 = __require("node:fs");
978
978
  var process8 = __require("node:process");
979
979
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -1906,9 +1906,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
1906
1906
  let launchWithNode = false;
1907
1907
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1908
1908
  function findFile(baseDir, baseName) {
1909
- const localBin = path41.resolve(baseDir, baseName);
1909
+ const localBin = path43.resolve(baseDir, baseName);
1910
1910
  if (fs38.existsSync(localBin)) return localBin;
1911
- if (sourceExt.includes(path41.extname(baseName))) return void 0;
1911
+ if (sourceExt.includes(path43.extname(baseName))) return void 0;
1912
1912
  const foundExt = sourceExt.find(
1913
1913
  (ext) => fs38.existsSync(`${localBin}${ext}`)
1914
1914
  );
@@ -1926,17 +1926,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
1926
1926
  } catch (err) {
1927
1927
  resolvedScriptPath = this._scriptPath;
1928
1928
  }
1929
- executableDir = path41.resolve(
1930
- path41.dirname(resolvedScriptPath),
1929
+ executableDir = path43.resolve(
1930
+ path43.dirname(resolvedScriptPath),
1931
1931
  executableDir
1932
1932
  );
1933
1933
  }
1934
1934
  if (executableDir) {
1935
1935
  let localFile = findFile(executableDir, executableFile);
1936
1936
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1937
- const legacyName = path41.basename(
1937
+ const legacyName = path43.basename(
1938
1938
  this._scriptPath,
1939
- path41.extname(this._scriptPath)
1939
+ path43.extname(this._scriptPath)
1940
1940
  );
1941
1941
  if (legacyName !== this._name) {
1942
1942
  localFile = findFile(
@@ -1947,7 +1947,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1947
1947
  }
1948
1948
  executableFile = localFile || executableFile;
1949
1949
  }
1950
- launchWithNode = sourceExt.includes(path41.extname(executableFile));
1950
+ launchWithNode = sourceExt.includes(path43.extname(executableFile));
1951
1951
  let proc;
1952
1952
  if (process8.platform !== "win32") {
1953
1953
  if (launchWithNode) {
@@ -2787,7 +2787,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2787
2787
  * @return {Command}
2788
2788
  */
2789
2789
  nameFromFilename(filename) {
2790
- this._name = path41.basename(filename, path41.extname(filename));
2790
+ this._name = path43.basename(filename, path43.extname(filename));
2791
2791
  return this;
2792
2792
  }
2793
2793
  /**
@@ -2801,9 +2801,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2801
2801
  * @param {string} [path]
2802
2802
  * @return {(string|null|Command)}
2803
2803
  */
2804
- executableDir(path42) {
2805
- if (path42 === void 0) return this._executableDir;
2806
- this._executableDir = path42;
2804
+ executableDir(path44) {
2805
+ if (path44 === void 0) return this._executableDir;
2806
+ this._executableDir = path44;
2807
2807
  return this;
2808
2808
  }
2809
2809
  /**
@@ -5236,7 +5236,7 @@ var require_websocket = __commonJS({
5236
5236
  var http = __require("http");
5237
5237
  var net = __require("net");
5238
5238
  var tls = __require("tls");
5239
- var { randomBytes: randomBytes3, createHash: createHash2 } = __require("crypto");
5239
+ var { randomBytes: randomBytes3, createHash: createHash3 } = __require("crypto");
5240
5240
  var { Duplex, Readable: Readable2 } = __require("stream");
5241
5241
  var { URL: URL2 } = __require("url");
5242
5242
  var PerMessageDeflate = require_permessage_deflate();
@@ -5896,7 +5896,7 @@ var require_websocket = __commonJS({
5896
5896
  abortHandshake(websocket, socket, "Invalid Upgrade header");
5897
5897
  return;
5898
5898
  }
5899
- const digest = createHash2("sha1").update(key + GUID).digest("base64");
5899
+ const digest = createHash3("sha1").update(key + GUID).digest("base64");
5900
5900
  if (res.headers["sec-websocket-accept"] !== digest) {
5901
5901
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
5902
5902
  return;
@@ -6263,7 +6263,7 @@ var require_websocket_server = __commonJS({
6263
6263
  var EventEmitter2 = __require("events");
6264
6264
  var http = __require("http");
6265
6265
  var { Duplex } = __require("stream");
6266
- var { createHash: createHash2 } = __require("crypto");
6266
+ var { createHash: createHash3 } = __require("crypto");
6267
6267
  var extension = require_extension();
6268
6268
  var PerMessageDeflate = require_permessage_deflate();
6269
6269
  var subprotocol = require_subprotocol();
@@ -6564,7 +6564,7 @@ var require_websocket_server = __commonJS({
6564
6564
  );
6565
6565
  }
6566
6566
  if (this._state > RUNNING) return abortHandshake(socket, 503);
6567
- const digest = createHash2("sha1").update(key + GUID).digest("base64");
6567
+ const digest = createHash3("sha1").update(key + GUID).digest("base64");
6568
6568
  const headers = [
6569
6569
  "HTTP/1.1 101 Switching Protocols",
6570
6570
  "Upgrade: websocket",
@@ -7061,8 +7061,8 @@ var init_parseUtil = __esm({
7061
7061
  init_errors();
7062
7062
  init_en();
7063
7063
  makeIssue = (params) => {
7064
- const { data, path: path41, errorMaps, issueData } = params;
7065
- const fullPath = [...path41, ...issueData.path || []];
7064
+ const { data, path: path43, errorMaps, issueData } = params;
7065
+ const fullPath = [...path43, ...issueData.path || []];
7066
7066
  const fullIssue = {
7067
7067
  ...issueData,
7068
7068
  path: fullPath
@@ -7370,11 +7370,11 @@ var init_types = __esm({
7370
7370
  init_parseUtil();
7371
7371
  init_util();
7372
7372
  ParseInputLazyPath = class {
7373
- constructor(parent, value, path41, key) {
7373
+ constructor(parent, value, path43, key) {
7374
7374
  this._cachedPath = [];
7375
7375
  this.parent = parent;
7376
7376
  this.data = value;
7377
- this._path = path41;
7377
+ this._path = path43;
7378
7378
  this._key = key;
7379
7379
  }
7380
7380
  get path() {
@@ -11529,10 +11529,10 @@ var require_src2 = __commonJS({
11529
11529
  var fs_1 = __require("fs");
11530
11530
  var debug_1 = __importDefault(require_src());
11531
11531
  var log2 = debug_1.default("@kwsites/file-exists");
11532
- function check2(path41, isFile, isDirectory) {
11533
- log2(`checking %s`, path41);
11532
+ function check2(path43, isFile, isDirectory) {
11533
+ log2(`checking %s`, path43);
11534
11534
  try {
11535
- const stat3 = fs_1.statSync(path41);
11535
+ const stat3 = fs_1.statSync(path43);
11536
11536
  if (stat3.isFile() && isFile) {
11537
11537
  log2(`[OK] path represents a file`);
11538
11538
  return true;
@@ -11552,8 +11552,8 @@ var require_src2 = __commonJS({
11552
11552
  throw e;
11553
11553
  }
11554
11554
  }
11555
- function exists2(path41, type = exports.READABLE) {
11556
- return check2(path41, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
11555
+ function exists2(path43, type = exports.READABLE) {
11556
+ return check2(path43, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
11557
11557
  }
11558
11558
  exports.exists = exists2;
11559
11559
  exports.FILE = 1;
@@ -11850,10 +11850,10 @@ function assignProp(target, prop, value) {
11850
11850
  configurable: true
11851
11851
  });
11852
11852
  }
11853
- function getElementAtPath(obj, path41) {
11854
- if (!path41)
11853
+ function getElementAtPath(obj, path43) {
11854
+ if (!path43)
11855
11855
  return obj;
11856
- return path41.reduce((acc, key) => acc?.[key], obj);
11856
+ return path43.reduce((acc, key) => acc?.[key], obj);
11857
11857
  }
11858
11858
  function promiseAllObject(promisesObj) {
11859
11859
  const keys = Object.keys(promisesObj);
@@ -12102,11 +12102,11 @@ function aborted(x, startIndex = 0) {
12102
12102
  }
12103
12103
  return false;
12104
12104
  }
12105
- function prefixIssues(path41, issues) {
12105
+ function prefixIssues(path43, issues) {
12106
12106
  return issues.map((iss) => {
12107
12107
  var _a2;
12108
12108
  (_a2 = iss).path ?? (_a2.path = []);
12109
- iss.path.unshift(path41);
12109
+ iss.path.unshift(path43);
12110
12110
  return iss;
12111
12111
  });
12112
12112
  }
@@ -12295,7 +12295,7 @@ function treeifyError(error40, _mapper) {
12295
12295
  return issue2.message;
12296
12296
  };
12297
12297
  const result = { errors: [] };
12298
- const processError = (error41, path41 = []) => {
12298
+ const processError = (error41, path43 = []) => {
12299
12299
  var _a2, _b;
12300
12300
  for (const issue2 of error41.issues) {
12301
12301
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -12305,7 +12305,7 @@ function treeifyError(error40, _mapper) {
12305
12305
  } else if (issue2.code === "invalid_element") {
12306
12306
  processError({ issues: issue2.issues }, issue2.path);
12307
12307
  } else {
12308
- const fullpath = [...path41, ...issue2.path];
12308
+ const fullpath = [...path43, ...issue2.path];
12309
12309
  if (fullpath.length === 0) {
12310
12310
  result.errors.push(mapper(issue2));
12311
12311
  continue;
@@ -12335,9 +12335,9 @@ function treeifyError(error40, _mapper) {
12335
12335
  processError(error40);
12336
12336
  return result;
12337
12337
  }
12338
- function toDotPath(path41) {
12338
+ function toDotPath(path43) {
12339
12339
  const segs = [];
12340
- for (const seg of path41) {
12340
+ for (const seg of path43) {
12341
12341
  if (typeof seg === "number")
12342
12342
  segs.push(`[${seg}]`);
12343
12343
  else if (typeof seg === "symbol")
@@ -24800,8 +24800,8 @@ var init_acp = __esm({
24800
24800
  this.#requestHandler = requestHandler;
24801
24801
  this.#notificationHandler = notificationHandler;
24802
24802
  this.#stream = stream;
24803
- this.#closedPromise = new Promise((resolve18) => {
24804
- this.#abortController.signal.addEventListener("abort", () => resolve18());
24803
+ this.#closedPromise = new Promise((resolve20) => {
24804
+ this.#abortController.signal.addEventListener("abort", () => resolve20());
24805
24805
  });
24806
24806
  this.#receive();
24807
24807
  }
@@ -24950,8 +24950,8 @@ var init_acp = __esm({
24950
24950
  }
24951
24951
  async sendRequest(method, params) {
24952
24952
  const id = this.#nextRequestId++;
24953
- const responsePromise = new Promise((resolve18, reject) => {
24954
- this.#pendingResponses.set(id, { resolve: resolve18, reject });
24953
+ const responsePromise = new Promise((resolve20, reject) => {
24954
+ this.#pendingResponses.set(id, { resolve: resolve20, reject });
24955
24955
  });
24956
24956
  await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
24957
24957
  return responsePromise;
@@ -25064,7 +25064,7 @@ var {
25064
25064
  } = import_index.default;
25065
25065
 
25066
25066
  // src/cli-version.ts
25067
- var CLI_VERSION = "0.1.29".length > 0 ? "0.1.29" : "0.0.0-dev";
25067
+ var CLI_VERSION = "0.1.31".length > 0 ? "0.1.31" : "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";
@@ -25072,7 +25072,7 @@ var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
25072
25072
 
25073
25073
  // src/cli/run-cli-action.ts
25074
25074
  import * as fs37 from "node:fs";
25075
- import * as path40 from "node:path";
25075
+ import * as path42 from "node:path";
25076
25076
 
25077
25077
  // src/cli-log-level.ts
25078
25078
  var verbosity = "info";
@@ -26077,14 +26077,14 @@ var baseOpen = async (options) => {
26077
26077
  }
26078
26078
  const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
26079
26079
  if (options.wait) {
26080
- return new Promise((resolve18, reject) => {
26080
+ return new Promise((resolve20, reject) => {
26081
26081
  subprocess.once("error", reject);
26082
26082
  subprocess.once("close", (exitCode) => {
26083
26083
  if (!options.allowNonzeroExitCode && exitCode > 0) {
26084
26084
  reject(new Error(`Exited with code ${exitCode}`));
26085
26085
  return;
26086
26086
  }
26087
- resolve18(subprocess);
26087
+ resolve20(subprocess);
26088
26088
  });
26089
26089
  });
26090
26090
  }
@@ -26573,8 +26573,8 @@ function runPendingAuth(options) {
26573
26573
  let hasOpenedBrowser = false;
26574
26574
  let resolved = false;
26575
26575
  let resolveAuth;
26576
- const authPromise = new Promise((resolve18) => {
26577
- resolveAuth = resolve18;
26576
+ const authPromise = new Promise((resolve20) => {
26577
+ resolveAuth = resolve20;
26578
26578
  });
26579
26579
  let reconnectAttempt = 0;
26580
26580
  const signInQuiet = createEmptyReconnectQuietSlot();
@@ -26929,6 +26929,16 @@ function recordMigrationAndPruneCheckpointLegacy(db, migration, applied2) {
26929
26929
  }
26930
26930
  var CHECKPOINT_V1 = "001_cli_sqlite_checkpoint_v1";
26931
26931
  var CHECKPOINT_V1_SQL = readCliSqliteMigrationSql("001_cli_sqlite_checkpoint_v1.sql");
26932
+ var AGENT_CAPABILITIES_SQL = readCliSqliteMigrationSql("002_agent_capabilities.sql");
26933
+ function agentCapabilitiesTableState(db) {
26934
+ const rows = db.all(
26935
+ `SELECT name FROM sqlite_master WHERE type='table' AND name IN ('agent_capabilities', 'agent_capability_cache')`
26936
+ );
26937
+ const names = new Set(rows.map((r) => r.name));
26938
+ if (names.has("agent_capabilities")) return "current";
26939
+ if (names.has("agent_capability_cache")) return "legacy";
26940
+ return "new";
26941
+ }
26932
26942
  var CLI_SQLITE_MIGRATIONS = [
26933
26943
  {
26934
26944
  name: CHECKPOINT_V1,
@@ -26936,6 +26946,23 @@ var CLI_SQLITE_MIGRATIONS = [
26936
26946
  migrate: (db) => {
26937
26947
  db.exec(CHECKPOINT_V1_SQL);
26938
26948
  }
26949
+ },
26950
+ {
26951
+ name: "002_agent_capabilities",
26952
+ migrate: (db) => {
26953
+ const state = agentCapabilitiesTableState(db);
26954
+ if (state === "current") return;
26955
+ if (state === "legacy") {
26956
+ db.exec(`
26957
+ ALTER TABLE agent_capability_cache RENAME TO agent_capabilities;
26958
+ DROP INDEX IF EXISTS idx_agent_capability_cache_workspace;
26959
+ CREATE INDEX IF NOT EXISTS idx_agent_capabilities_workspace ON agent_capabilities(workspace_id);
26960
+ `);
26961
+ return;
26962
+ }
26963
+ db.exec(AGENT_CAPABILITIES_SQL);
26964
+ },
26965
+ alreadyApplied: (db) => agentCapabilitiesTableState(db) === "current"
26939
26966
  }
26940
26967
  ];
26941
26968
  function migrateCliSqlite(db) {
@@ -26964,6 +26991,13 @@ function migrateCliSqlite(db) {
26964
26991
 
26965
26992
  // src/sqlite/cli-database.ts
26966
26993
  var { Database: SqliteDatabase } = sqliteWasm;
26994
+ function applyCliSqliteMemoryPragmas(db) {
26995
+ try {
26996
+ db.run("PRAGMA cache_size = -8192");
26997
+ db.run("PRAGMA temp_store = FILE");
26998
+ } catch {
26999
+ }
27000
+ }
26967
27001
  var openDatabases = /* @__PURE__ */ new Map();
26968
27002
  var processExitCloseRegistered = false;
26969
27003
  function registerProcessExitSqliteClose() {
@@ -27000,6 +27034,7 @@ function getCliDatabase(options) {
27000
27034
  ensureCliSqliteParentDir(sqlitePath);
27001
27035
  const db = new SqliteDatabase(sqlitePath);
27002
27036
  try {
27037
+ applyCliSqliteMemoryPragmas(db);
27003
27038
  migrateCliSqlite(db);
27004
27039
  importCliSqliteLegacyDiskData(db, options?.logLegacyMigration);
27005
27040
  } catch (e) {
@@ -27015,7 +27050,7 @@ function getCliDatabase(options) {
27015
27050
  async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
27016
27051
  const say = log2 ?? logImmediate;
27017
27052
  say("Cleaning up connections\u2026");
27018
- await new Promise((resolve18) => setImmediate(resolve18));
27053
+ await new Promise((resolve20) => setImmediate(resolve20));
27019
27054
  state.closedByUser = true;
27020
27055
  clearReconnectQuietTimer(state.mainQuiet);
27021
27056
  clearReconnectQuietTimer(state.firehoseQuiet);
@@ -27403,9 +27438,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
27403
27438
  const rawPath = typeof o.path === "string" ? o.path.trim() : "";
27404
27439
  const summary = typeof o.summary === "string" ? o.summary.trim() : "";
27405
27440
  if (!rawPath || !summary) continue;
27406
- const path41 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
27407
- if (!path41) continue;
27408
- rows.push({ path: path41, summary: clampSummaryToAtMostTwoLines(summary) });
27441
+ const path43 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
27442
+ if (!path43) continue;
27443
+ rows.push({ path: path43, summary: clampSummaryToAtMostTwoLines(summary) });
27409
27444
  }
27410
27445
  return rows;
27411
27446
  }
@@ -27615,6 +27650,7 @@ function buildCliAutoApprovedPermissionRpcResult(requestParams) {
27615
27650
  // ../types/src/agent-config.ts
27616
27651
  var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
27617
27652
  var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
27653
+ var AGENT_CONFIG_AGENT_MODEL_KEY = "agent_model";
27618
27654
  function getClaudePermissionModeFromAgentConfig(config2) {
27619
27655
  if (!config2) return null;
27620
27656
  const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
@@ -27626,6 +27662,13 @@ function getCliPermissionModeFromAgentConfig(config2) {
27626
27662
  if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
27627
27663
  return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
27628
27664
  }
27665
+ function getAgentModelFromAgentConfig(config2) {
27666
+ if (!config2) return null;
27667
+ const cur = config2[AGENT_CONFIG_AGENT_MODEL_KEY];
27668
+ if (typeof cur !== "string") return null;
27669
+ const t = cur.trim();
27670
+ return t !== "" ? t : null;
27671
+ }
27629
27672
 
27630
27673
  // src/git/session-git-queue.ts
27631
27674
  import { execFile as execFile7 } from "node:child_process";
@@ -27680,8 +27723,8 @@ function pathspec(...paths) {
27680
27723
  cache.set(key, paths);
27681
27724
  return key;
27682
27725
  }
27683
- function isPathSpec(path41) {
27684
- return path41 instanceof String && cache.has(path41);
27726
+ function isPathSpec(path43) {
27727
+ return path43 instanceof String && cache.has(path43);
27685
27728
  }
27686
27729
  function toPaths(pathSpec) {
27687
27730
  return cache.get(pathSpec) || [];
@@ -27770,8 +27813,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
27770
27813
  function forEachLineWithContent(input, callback) {
27771
27814
  return toLinesWithContent(input, true).map((line) => callback(line));
27772
27815
  }
27773
- function folderExists(path41) {
27774
- return (0, import_file_exists.exists)(path41, import_file_exists.FOLDER);
27816
+ function folderExists(path43) {
27817
+ return (0, import_file_exists.exists)(path43, import_file_exists.FOLDER);
27775
27818
  }
27776
27819
  function append(target, item) {
27777
27820
  if (Array.isArray(target)) {
@@ -28175,8 +28218,8 @@ function checkIsRepoRootTask() {
28175
28218
  commands,
28176
28219
  format: "utf-8",
28177
28220
  onError,
28178
- parser(path41) {
28179
- return /^\.(git)?$/.test(path41.trim());
28221
+ parser(path43) {
28222
+ return /^\.(git)?$/.test(path43.trim());
28180
28223
  }
28181
28224
  };
28182
28225
  }
@@ -28610,11 +28653,11 @@ function parseGrep(grep) {
28610
28653
  const paths = /* @__PURE__ */ new Set();
28611
28654
  const results = {};
28612
28655
  forEachLineWithContent(grep, (input) => {
28613
- const [path41, line, preview] = input.split(NULL);
28614
- paths.add(path41);
28615
- (results[path41] = results[path41] || []).push({
28656
+ const [path43, line, preview] = input.split(NULL);
28657
+ paths.add(path43);
28658
+ (results[path43] = results[path43] || []).push({
28616
28659
  line: asNumber(line),
28617
- path: path41,
28660
+ path: path43,
28618
28661
  preview
28619
28662
  });
28620
28663
  });
@@ -29379,14 +29422,14 @@ var init_hash_object = __esm2({
29379
29422
  init_task();
29380
29423
  }
29381
29424
  });
29382
- function parseInit(bare, path41, text) {
29425
+ function parseInit(bare, path43, text) {
29383
29426
  const response = String(text).trim();
29384
29427
  let result;
29385
29428
  if (result = initResponseRegex.exec(response)) {
29386
- return new InitSummary(bare, path41, false, result[1]);
29429
+ return new InitSummary(bare, path43, false, result[1]);
29387
29430
  }
29388
29431
  if (result = reInitResponseRegex.exec(response)) {
29389
- return new InitSummary(bare, path41, true, result[1]);
29432
+ return new InitSummary(bare, path43, true, result[1]);
29390
29433
  }
29391
29434
  let gitDir = "";
29392
29435
  const tokens = response.split(" ");
@@ -29397,7 +29440,7 @@ function parseInit(bare, path41, text) {
29397
29440
  break;
29398
29441
  }
29399
29442
  }
29400
- return new InitSummary(bare, path41, /^re/i.test(response), gitDir);
29443
+ return new InitSummary(bare, path43, /^re/i.test(response), gitDir);
29401
29444
  }
29402
29445
  var InitSummary;
29403
29446
  var initResponseRegex;
@@ -29406,9 +29449,9 @@ var init_InitSummary = __esm2({
29406
29449
  "src/lib/responses/InitSummary.ts"() {
29407
29450
  "use strict";
29408
29451
  InitSummary = class {
29409
- constructor(bare, path41, existing, gitDir) {
29452
+ constructor(bare, path43, existing, gitDir) {
29410
29453
  this.bare = bare;
29411
- this.path = path41;
29454
+ this.path = path43;
29412
29455
  this.existing = existing;
29413
29456
  this.gitDir = gitDir;
29414
29457
  }
@@ -29420,7 +29463,7 @@ var init_InitSummary = __esm2({
29420
29463
  function hasBareCommand(command) {
29421
29464
  return command.includes(bareCommand);
29422
29465
  }
29423
- function initTask(bare = false, path41, customArgs) {
29466
+ function initTask(bare = false, path43, customArgs) {
29424
29467
  const commands = ["init", ...customArgs];
29425
29468
  if (bare && !hasBareCommand(commands)) {
29426
29469
  commands.splice(1, 0, bareCommand);
@@ -29429,7 +29472,7 @@ function initTask(bare = false, path41, customArgs) {
29429
29472
  commands,
29430
29473
  format: "utf-8",
29431
29474
  parser(text) {
29432
- return parseInit(commands.includes("--bare"), path41, text);
29475
+ return parseInit(commands.includes("--bare"), path43, text);
29433
29476
  }
29434
29477
  };
29435
29478
  }
@@ -30245,12 +30288,12 @@ var init_FileStatusSummary = __esm2({
30245
30288
  "use strict";
30246
30289
  fromPathRegex = /^(.+)\0(.+)$/;
30247
30290
  FileStatusSummary = class {
30248
- constructor(path41, index, working_dir) {
30249
- this.path = path41;
30291
+ constructor(path43, index, working_dir) {
30292
+ this.path = path43;
30250
30293
  this.index = index;
30251
30294
  this.working_dir = working_dir;
30252
30295
  if (index === "R" || working_dir === "R") {
30253
- const detail = fromPathRegex.exec(path41) || [null, path41, path41];
30296
+ const detail = fromPathRegex.exec(path43) || [null, path43, path43];
30254
30297
  this.from = detail[2] || "";
30255
30298
  this.path = detail[1] || "";
30256
30299
  }
@@ -30281,14 +30324,14 @@ function splitLine(result, lineStr) {
30281
30324
  default:
30282
30325
  return;
30283
30326
  }
30284
- function data(index, workingDir, path41) {
30327
+ function data(index, workingDir, path43) {
30285
30328
  const raw = `${index}${workingDir}`;
30286
30329
  const handler = parsers6.get(raw);
30287
30330
  if (handler) {
30288
- handler(result, path41);
30331
+ handler(result, path43);
30289
30332
  }
30290
30333
  if (raw !== "##" && raw !== "!!") {
30291
- result.files.push(new FileStatusSummary(path41, index, workingDir));
30334
+ result.files.push(new FileStatusSummary(path43, index, workingDir));
30292
30335
  }
30293
30336
  }
30294
30337
  }
@@ -30597,9 +30640,9 @@ var init_simple_git_api = __esm2({
30597
30640
  next
30598
30641
  );
30599
30642
  }
30600
- hashObject(path41, write) {
30643
+ hashObject(path43, write) {
30601
30644
  return this._runTask(
30602
- hashObjectTask(path41, write === true),
30645
+ hashObjectTask(path43, write === true),
30603
30646
  trailingFunctionArgument(arguments)
30604
30647
  );
30605
30648
  }
@@ -30952,8 +30995,8 @@ var init_branch = __esm2({
30952
30995
  }
30953
30996
  });
30954
30997
  function toPath(input) {
30955
- const path41 = input.trim().replace(/^["']|["']$/g, "");
30956
- return path41 && normalize(path41);
30998
+ const path43 = input.trim().replace(/^["']|["']$/g, "");
30999
+ return path43 && normalize(path43);
30957
31000
  }
30958
31001
  var parseCheckIgnore;
30959
31002
  var init_CheckIgnore = __esm2({
@@ -31267,8 +31310,8 @@ __export2(sub_module_exports, {
31267
31310
  subModuleTask: () => subModuleTask,
31268
31311
  updateSubModuleTask: () => updateSubModuleTask
31269
31312
  });
31270
- function addSubModuleTask(repo, path41) {
31271
- return subModuleTask(["add", repo, path41]);
31313
+ function addSubModuleTask(repo, path43) {
31314
+ return subModuleTask(["add", repo, path43]);
31272
31315
  }
31273
31316
  function initSubModuleTask(customArgs) {
31274
31317
  return subModuleTask(["init", ...customArgs]);
@@ -31601,8 +31644,8 @@ var require_git = __commonJS2({
31601
31644
  }
31602
31645
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
31603
31646
  };
31604
- Git2.prototype.submoduleAdd = function(repo, path41, then) {
31605
- return this._runTask(addSubModuleTask2(repo, path41), trailingFunctionArgument2(arguments));
31647
+ Git2.prototype.submoduleAdd = function(repo, path43, then) {
31648
+ return this._runTask(addSubModuleTask2(repo, path43), trailingFunctionArgument2(arguments));
31606
31649
  };
31607
31650
  Git2.prototype.submoduleUpdate = function(args, then) {
31608
31651
  return this._runTask(
@@ -32489,9 +32532,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
32489
32532
  // src/agents/acp/put-summarize-change-summaries.ts
32490
32533
  async function putEncryptedChangeSummaryRows(params) {
32491
32534
  const base = params.apiBaseUrl.replace(/\/+$/, "");
32492
- const entries = params.rows.map(({ path: path41, summary }) => {
32535
+ const entries = params.rows.map(({ path: path43, summary }) => {
32493
32536
  const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
32494
- return { path: path41, summary: JSON.stringify(enc) };
32537
+ return { path: path43, summary: JSON.stringify(enc) };
32495
32538
  });
32496
32539
  const res = await fetch(
32497
32540
  `${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
@@ -33125,6 +33168,48 @@ async function applyClaudePermissionFromAcpSession(params) {
33125
33168
  }
33126
33169
  }
33127
33170
 
33171
+ // src/agents/acp/apply-acp-model-from-agent-session.ts
33172
+ function flattenSelectOptions2(options) {
33173
+ if (options == null || options.length === 0) return [];
33174
+ const first2 = options[0];
33175
+ if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
33176
+ return options.flatMap((g) => Array.isArray(g.options) ? g.options : []);
33177
+ }
33178
+ return options;
33179
+ }
33180
+ function looksLikeModelOption(o) {
33181
+ if (o.category === "model" || o.category === "models") return true;
33182
+ const id = typeof o.id === "string" ? o.id.toLowerCase() : "";
33183
+ if (id === "model" || id.endsWith("_model") || id.includes("model")) return true;
33184
+ const name = typeof o.name === "string" ? o.name.toLowerCase() : "";
33185
+ return name.includes("model") && !name.includes("mode");
33186
+ }
33187
+ function pickModelConfigOption(configOptions) {
33188
+ if (configOptions == null || configOptions.length === 0) return null;
33189
+ return configOptions.find(looksLikeModelOption) ?? null;
33190
+ }
33191
+ async function applyAcpModelFromAcpSession(params) {
33192
+ const { sessionId, agentConfig, configOptions, setSessionConfigOption, logDebug: logDebug2 } = params;
33193
+ const desired = getAgentModelFromAgentConfig(agentConfig);
33194
+ if (desired == null) return;
33195
+ const modelOpt = pickModelConfigOption(configOptions ?? null);
33196
+ if (modelOpt == null) return;
33197
+ const flat = flattenSelectOptions2(modelOpt.options);
33198
+ const allowed = flat.some((o) => o.value === desired);
33199
+ if (!allowed) return;
33200
+ if (modelOpt.currentValue === desired) return;
33201
+ try {
33202
+ logDebug2(
33203
+ `[Agent] ACP session/set_config_option (model) configId=${JSON.stringify(modelOpt.id)} value=${JSON.stringify(desired)} was=${JSON.stringify(modelOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
33204
+ );
33205
+ await setSessionConfigOption({ sessionId, configId: modelOpt.id, value: desired });
33206
+ } catch (e) {
33207
+ logDebug2(
33208
+ `[Agent] ACP session/set_config_option (model) failed: ${e instanceof Error ? e.message : String(e)}`
33209
+ );
33210
+ }
33211
+ }
33212
+
33128
33213
  // src/agents/acp/clients/shared/config-options-for-permission.ts
33129
33214
  function configOptionsForPermission(getActive, established) {
33130
33215
  const mem = getActive?.();
@@ -33217,6 +33302,17 @@ async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
33217
33302
  logDebug: ctx.logDebug
33218
33303
  });
33219
33304
  }
33305
+ const cfgAll = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
33306
+ const configOptionsForModel = established.configOptions;
33307
+ if (transport.setSessionConfigOption) {
33308
+ await applyAcpModelFromAcpSession({
33309
+ sessionId,
33310
+ agentConfig: cfgAll,
33311
+ configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsForModel),
33312
+ setSessionConfigOption: (p) => transport.setSessionConfigOption(p),
33313
+ logDebug: ctx.logDebug
33314
+ });
33315
+ }
33220
33316
  return established;
33221
33317
  }
33222
33318
 
@@ -33322,10 +33418,15 @@ async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText,
33322
33418
  // src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
33323
33419
  function awaitSdkStdioPermissionRequestHandshake(params) {
33324
33420
  const { requestId, paramsRecord, pending, onRequest } = params;
33325
- return new Promise((resolve18) => {
33326
- pending.set(requestId, { resolve: resolve18, params: paramsRecord });
33421
+ return new Promise((resolve20) => {
33422
+ pending.set(requestId, { resolve: resolve20, params: paramsRecord });
33423
+ if (onRequest == null) {
33424
+ pending.delete(requestId);
33425
+ resolve20({ outcome: { outcome: "denied" } });
33426
+ return;
33427
+ }
33327
33428
  try {
33328
- onRequest?.({
33429
+ onRequest({
33329
33430
  requestId,
33330
33431
  method: "session/request_permission",
33331
33432
  params: paramsRecord
@@ -33387,7 +33488,7 @@ async function createSdkStdioAcpClient(options) {
33387
33488
  child.once("close", (code, signal) => {
33388
33489
  onAgentSubprocessExit?.({ code, signal });
33389
33490
  });
33390
- return new Promise((resolve18, reject) => {
33491
+ return new Promise((resolve20, reject) => {
33391
33492
  let initSettled = false;
33392
33493
  const settleReject = (err) => {
33393
33494
  if (initSettled) return;
@@ -33401,7 +33502,7 @@ async function createSdkStdioAcpClient(options) {
33401
33502
  const settleResolve = (handle) => {
33402
33503
  if (initSettled) return;
33403
33504
  initSettled = true;
33404
- resolve18(handle);
33505
+ resolve20(handle);
33405
33506
  };
33406
33507
  child.on("error", (err) => {
33407
33508
  settleReject(new Error(formatSpawnError(err, command[0])));
@@ -33693,7 +33794,7 @@ async function createCursorAcpClient(options) {
33693
33794
  logDebug,
33694
33795
  getStderrText: () => stderrCapture.getText()
33695
33796
  };
33696
- return new Promise((resolve18, reject) => {
33797
+ return new Promise((resolve20, reject) => {
33697
33798
  child.on("error", (err) => {
33698
33799
  child.kill();
33699
33800
  reject(new Error(formatSpawnError2(err, command[0])));
@@ -33772,12 +33873,16 @@ async function createCursorAcpClient(options) {
33772
33873
  }
33773
33874
  if (method === "session/request_permission" && typeof id === "number") {
33774
33875
  const params = msg.params ?? {};
33775
- pendingRequests.set(id, { method, params });
33776
- onRequest?.({
33777
- requestId: String(id),
33778
- method,
33779
- params
33780
- });
33876
+ if (onRequest) {
33877
+ pendingRequests.set(id, { method, params });
33878
+ onRequest({
33879
+ requestId: String(id),
33880
+ method,
33881
+ params
33882
+ });
33883
+ } else {
33884
+ respond(id, { outcome: { outcome: "denied" } });
33885
+ }
33781
33886
  return;
33782
33887
  }
33783
33888
  if (typeof id === "number" && method) {
@@ -33865,7 +33970,7 @@ async function createCursorAcpClient(options) {
33865
33970
  clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
33866
33971
  });
33867
33972
  const sessionId = established.sessionId;
33868
- resolve18({
33973
+ resolve20({
33869
33974
  sessionId,
33870
33975
  async sendPrompt(prompt, options2) {
33871
33976
  const imgs = options2?.images?.map((im) => ({ type: "image", mimeType: im.mimeType, data: im.dataBase64 }));
@@ -34573,6 +34678,28 @@ function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, sessio
34573
34678
  }
34574
34679
  }
34575
34680
 
34681
+ // src/agents/acp/hooks/bridge-on-session-update/send-session-info-title-update.ts
34682
+ function extractSessionInfoTitle(params) {
34683
+ if (!params || typeof params !== "object") return null;
34684
+ const p = params;
34685
+ const title = typeof p.title === "string" ? p.title.trim() : "";
34686
+ return title ? title : null;
34687
+ }
34688
+ function sendSessionInfoTitleUpdate(params) {
34689
+ const title = extractSessionInfoTitle(params.payload);
34690
+ if (!title || !params.runId || !params.send) return;
34691
+ try {
34692
+ params.send({
34693
+ type: "session_title_update",
34694
+ ...params.sessionId ? { sessionId: params.sessionId } : {},
34695
+ runId: params.runId,
34696
+ title
34697
+ });
34698
+ } catch (err) {
34699
+ params.log(`[Bridge service] Session title update send failed: ${errorMessage(err)}`);
34700
+ }
34701
+ }
34702
+
34576
34703
  // src/agents/acp/hooks/bridge-on-session-update/create-bridge-on-session-update.ts
34577
34704
  function createBridgeOnSessionUpdate(opts) {
34578
34705
  const { routing, getSendSessionUpdate, log: log2, sessionParentPath } = opts;
@@ -34588,6 +34715,10 @@ function createBridgeOnSessionUpdate(opts) {
34588
34715
  if (updateKind === "config_option_update") {
34589
34716
  return;
34590
34717
  }
34718
+ if (updateKind === "session_info_update") {
34719
+ sendSessionInfoTitleUpdate({ payload: params, runId, sessionId, send, log: log2 });
34720
+ return;
34721
+ }
34591
34722
  const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
34592
34723
  const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
34593
34724
  const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
@@ -34745,6 +34876,7 @@ async function ensureAcpClient(options) {
34745
34876
  sessionParentPath,
34746
34877
  routing,
34747
34878
  cloudSessionId,
34879
+ reportAgentCapabilities,
34748
34880
  sendSessionUpdate,
34749
34881
  sendRequest,
34750
34882
  log: log2
@@ -34832,6 +34964,12 @@ async function ensureAcpClient(options) {
34832
34964
  backendAgentType: preferredAgentType
34833
34965
  });
34834
34966
  }
34967
+ if (reportAgentCapabilities && preferredAgentType && Array.isArray(info.configOptions) && info.configOptions.length > 0) {
34968
+ reportAgentCapabilities({
34969
+ agentType: preferredAgentType,
34970
+ configOptions: info.configOptions
34971
+ });
34972
+ }
34835
34973
  },
34836
34974
  onAcpConfigOptionsUpdated: (configOptions) => {
34837
34975
  state.activeSessionConfigOptions = configOptions;
@@ -34841,6 +34979,12 @@ async function ensureAcpClient(options) {
34841
34979
  backendAgentType: preferredAgentType
34842
34980
  });
34843
34981
  }
34982
+ if (reportAgentCapabilities && preferredAgentType && Array.isArray(configOptions) && configOptions.length > 0) {
34983
+ reportAgentCapabilities({
34984
+ agentType: preferredAgentType,
34985
+ configOptions
34986
+ });
34987
+ }
34844
34988
  },
34845
34989
  onAgentSubprocessExit: () => {
34846
34990
  state.acpHandle = null;
@@ -34871,7 +35015,7 @@ async function ensureAcpClient(options) {
34871
35015
 
34872
35016
  // src/agents/acp/create-acp-manager.ts
34873
35017
  async function createAcpManager(options) {
34874
- const { log: log2 } = options;
35018
+ const { log: log2, reportAgentCapabilities } = options;
34875
35019
  const state = {
34876
35020
  acpHandle: null,
34877
35021
  acpStartPromise: null,
@@ -34915,7 +35059,8 @@ async function createAcpManager(options) {
34915
35059
  cloudApiBaseUrl,
34916
35060
  getCloudAccessToken,
34917
35061
  e2ee,
34918
- attachments
35062
+ attachments,
35063
+ agentId
34919
35064
  } = opts;
34920
35065
  const preferredForPrompt = agentType ?? backendFallbackAgentType ?? null;
34921
35066
  pendingCancelRunId = void 0;
@@ -34933,7 +35078,8 @@ async function createAcpManager(options) {
34933
35078
  cloudSessionId: sessionId,
34934
35079
  sendSessionUpdate,
34935
35080
  sendRequest: sendSessionUpdate,
34936
- log: log2
35081
+ log: log2,
35082
+ reportAgentCapabilities
34937
35083
  });
34938
35084
  if (!handle) {
34939
35085
  const errMsg = state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app.";
@@ -36300,43 +36446,39 @@ import path29 from "node:path";
36300
36446
 
36301
36447
  // src/runtime/yield-to-event-loop.ts
36302
36448
  function yieldToEventLoop() {
36303
- return new Promise((resolve18) => setImmediate(resolve18));
36449
+ return new Promise((resolve20) => setImmediate(resolve20));
36304
36450
  }
36305
36451
 
36306
36452
  // src/files/index/walk-workspace-tree.ts
36307
36453
  import fs25 from "node:fs";
36308
36454
  import path28 from "node:path";
36309
- async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
36455
+ function shouldSkipWorkspaceWalkEntry(name) {
36456
+ return name.startsWith(".");
36457
+ }
36458
+ function walkWorkspaceTreeSync(dir, baseDir, onFile) {
36310
36459
  let names;
36311
36460
  try {
36312
- names = await fs25.promises.readdir(dir);
36461
+ names = fs25.readdirSync(dir);
36313
36462
  } catch {
36314
36463
  return;
36315
36464
  }
36316
36465
  for (const name of names) {
36317
- if (name.startsWith(".")) continue;
36318
- if (state.n > 0 && state.n % INDEX_WORK_YIELD_EVERY === 0) {
36319
- await yieldToEventLoop();
36320
- }
36321
- state.n++;
36466
+ if (shouldSkipWorkspaceWalkEntry(name)) continue;
36322
36467
  const full = path28.join(dir, name);
36323
36468
  let stat3;
36324
36469
  try {
36325
- stat3 = await fs25.promises.stat(full);
36470
+ stat3 = fs25.statSync(full);
36326
36471
  } catch {
36327
36472
  continue;
36328
36473
  }
36329
36474
  const relative5 = path28.relative(baseDir, full).replace(/\\/g, "/");
36330
36475
  if (stat3.isDirectory()) {
36331
- await walkWorkspaceTreeAsync(full, baseDir, out, state);
36476
+ walkWorkspaceTreeSync(full, baseDir, onFile);
36332
36477
  } else if (stat3.isFile()) {
36333
- out.push(relative5);
36478
+ onFile(relative5);
36334
36479
  }
36335
36480
  }
36336
36481
  }
36337
- function createWalkYieldState() {
36338
- return { n: 0 };
36339
- }
36340
36482
 
36341
36483
  // src/files/index/file-index-sqlite-lock.ts
36342
36484
  import fs26 from "node:fs";
@@ -36369,20 +36511,29 @@ function withFileIndexSqliteLock(fn) {
36369
36511
  }
36370
36512
 
36371
36513
  // src/files/index/build-file-index.ts
36372
- function sortPaths(paths) {
36373
- paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
36374
- }
36375
- function persistPathsToSqlite(resolved, paths) {
36514
+ var FILE_INDEX_INSERT_BUFFER = 2048;
36515
+ function persistFileIndexForResolvedCwd(resolved) {
36376
36516
  const db = getCliDatabase();
36377
36517
  const h = getCwdHashForFileIndex(resolved);
36518
+ const buf = [];
36519
+ let pathCount = 0;
36378
36520
  db.run("BEGIN IMMEDIATE");
36379
36521
  try {
36380
36522
  db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
36381
36523
  const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
36382
36524
  try {
36383
- for (const rel of paths) {
36384
- ins.run([h, rel]);
36385
- }
36525
+ const flushBuf = () => {
36526
+ for (const rel of buf) {
36527
+ ins.run([h, rel]);
36528
+ }
36529
+ pathCount += buf.length;
36530
+ buf.length = 0;
36531
+ };
36532
+ walkWorkspaceTreeSync(resolved, resolved, (rel) => {
36533
+ buf.push(rel);
36534
+ if (buf.length >= FILE_INDEX_INSERT_BUFFER) flushBuf();
36535
+ });
36536
+ flushBuf();
36386
36537
  } finally {
36387
36538
  ins.finalize();
36388
36539
  }
@@ -36394,22 +36545,26 @@ function persistPathsToSqlite(resolved, paths) {
36394
36545
  }
36395
36546
  throw e;
36396
36547
  }
36548
+ return pathCount;
36397
36549
  }
36398
36550
  async function buildFileIndexAsync(cwd) {
36399
36551
  return withFileIndexSqliteLock(async () => {
36400
36552
  const resolved = path29.resolve(cwd);
36401
- const paths = [];
36402
- await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
36403
36553
  await yieldToEventLoop();
36404
- sortPaths(paths);
36405
- persistPathsToSqlite(resolved, paths);
36406
- return { pathCount: paths.length };
36554
+ const pathCount = persistFileIndexForResolvedCwd(resolved);
36555
+ await yieldToEventLoop();
36556
+ return { pathCount };
36407
36557
  });
36408
36558
  }
36409
36559
 
36410
36560
  // src/files/index/ensure-file-index.ts
36411
36561
  import path30 from "node:path";
36412
36562
 
36563
+ // src/files/index/file-index-dependency-path.ts
36564
+ function sqliteExprBridgeFileIndexDependencyRank() {
36565
+ return `CASE WHEN lower(path) = 'node_modules' OR lower(path) LIKE 'node_modules/%' OR lower(path) LIKE '%/node_modules/%' OR lower(path) = 'bower_components' OR lower(path) LIKE 'bower_components/%' OR lower(path) LIKE '%/bower_components/%' THEN 1 ELSE 0 END`;
36566
+ }
36567
+
36413
36568
  // src/files/index/search-file-index.ts
36414
36569
  function escapeLikePattern(fragment) {
36415
36570
  return fragment.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
@@ -36434,8 +36589,9 @@ function searchBridgeFilePaths(resolvedCwd, query, limit = 100) {
36434
36589
  const h = getCwdHashForFileIndex(resolvedCwd);
36435
36590
  const pattern = `%${escapeLikePattern(q)}%`;
36436
36591
  const lim = Math.max(0, Math.min(1e4, Math.floor(limit)));
36592
+ const depRank = sqliteExprBridgeFileIndexDependencyRank();
36437
36593
  const rows = db.all(
36438
- `SELECT path FROM file_index_path WHERE cwd_hash = ? AND lower(path) LIKE ? ESCAPE '\\' LIMIT ?`,
36594
+ `SELECT path FROM file_index_path WHERE cwd_hash = ? AND lower(path) LIKE ? ESCAPE '\\' ORDER BY ${depRank}, path LIMIT ?`,
36439
36595
  [h, pattern, lim]
36440
36596
  );
36441
36597
  return rows.map((r) => String(r.path));
@@ -36460,7 +36616,6 @@ async function ensureFileIndexAsync(cwd) {
36460
36616
  var DEBOUNCE_MS = 900;
36461
36617
  function shouldIgnoreRelative(rel) {
36462
36618
  const n = rel.replace(/\\/g, "/");
36463
- if (n.includes("/node_modules/") || n.startsWith("node_modules/")) return true;
36464
36619
  if (n.includes("/.git/") || n === ".git" || n.startsWith(".git/")) return true;
36465
36620
  if (n.includes("/.buildautomaton/") || n.startsWith(".buildautomaton/")) return true;
36466
36621
  return false;
@@ -36524,7 +36679,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
36524
36679
  }
36525
36680
 
36526
36681
  // src/connection/create-bridge-connection.ts
36527
- import * as path39 from "node:path";
36682
+ import * as path41 from "node:path";
36528
36683
 
36529
36684
  // src/dev-servers/manager/dev-server-manager.ts
36530
36685
  import { rm as rm2 } from "node:fs/promises";
@@ -36546,15 +36701,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
36546
36701
 
36547
36702
  // src/dev-servers/process/terminate-child-process.ts
36548
36703
  async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
36549
- const exited = new Promise((resolve18) => {
36550
- proc.once("exit", () => resolve18());
36704
+ const exited = new Promise((resolve20) => {
36705
+ proc.once("exit", () => resolve20());
36551
36706
  });
36552
36707
  log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
36553
36708
  try {
36554
36709
  proc.kill("SIGTERM");
36555
36710
  } catch {
36556
36711
  }
36557
- await Promise.race([exited, new Promise((resolve18) => setTimeout(resolve18, graceMs))]);
36712
+ await Promise.race([exited, new Promise((resolve20) => setTimeout(resolve20, graceMs))]);
36558
36713
  }
36559
36714
  function forceKillChild(proc, log2, shortId, graceMs) {
36560
36715
  log2(
@@ -37437,7 +37592,7 @@ async function proxyToLocal(request) {
37437
37592
  };
37438
37593
  const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
37439
37594
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
37440
- const once = await new Promise((resolve18) => {
37595
+ const once = await new Promise((resolve20) => {
37441
37596
  const req = mod.request(opts, (res) => {
37442
37597
  const chunks = [];
37443
37598
  res.on("data", (c) => chunks.push(c));
@@ -37448,7 +37603,7 @@ async function proxyToLocal(request) {
37448
37603
  if (typeof v === "string") headers[k] = v;
37449
37604
  else if (Array.isArray(v) && v[0]) headers[k] = v[0];
37450
37605
  }
37451
- resolve18({
37606
+ resolve20({
37452
37607
  id: request.id,
37453
37608
  statusCode: res.statusCode ?? 0,
37454
37609
  headers,
@@ -37457,7 +37612,7 @@ async function proxyToLocal(request) {
37457
37612
  });
37458
37613
  });
37459
37614
  req.on("error", (err) => {
37460
- resolve18({
37615
+ resolve20({
37461
37616
  id: request.id,
37462
37617
  statusCode: 0,
37463
37618
  headers: {},
@@ -38076,6 +38231,13 @@ var handleBridgeIdentified = (msg, deps) => {
38076
38231
  `[Bridge service] Auto-detect agents failed: ${e instanceof Error ? e.message : String(e)}`
38077
38232
  );
38078
38233
  }
38234
+ try {
38235
+ await deps.warmupAgentCapabilitiesOnConnect?.();
38236
+ } catch (e) {
38237
+ deps.log(
38238
+ `[Bridge service] Agent capability warmup failed: ${e instanceof Error ? e.message : String(e)}`
38239
+ );
38240
+ }
38079
38241
  })();
38080
38242
  });
38081
38243
  setImmediate(() => {
@@ -38428,9 +38590,9 @@ function parseChangeSummarySnapshots(raw) {
38428
38590
  for (const item of raw) {
38429
38591
  if (!item || typeof item !== "object") continue;
38430
38592
  const o = item;
38431
- const path41 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
38432
- if (!path41) continue;
38433
- const row = { path: path41 };
38593
+ const path43 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
38594
+ if (!path43) continue;
38595
+ const row = { path: path43 };
38434
38596
  if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
38435
38597
  if (typeof o.oldText === "string") row.oldText = o.oldText;
38436
38598
  if (typeof o.newText === "string") row.newText = o.newText;
@@ -38548,6 +38710,8 @@ function handleBridgePrompt(msg, deps) {
38548
38710
  const sessionParent = rawParent === "bridge_root" || rawParent === "worktrees_root" ? rawParent : rawParent === "session_worktrees_root" ? "worktrees_root" : null;
38549
38711
  const sessionParentPath = typeof msg.sessionParentPath === "string" && msg.sessionParentPath.trim() ? msg.sessionParentPath.trim() : null;
38550
38712
  const agentType = typeof msg.agentType === "string" && msg.agentType.trim() ? msg.agentType.trim() : void 0;
38713
+ const rawAgentId = msg.agentId;
38714
+ const agentId = typeof rawAgentId === "string" && rawAgentId.trim() !== "" ? rawAgentId.trim() : null;
38551
38715
  const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
38552
38716
  const agentConfig = msg.agentConfig != null && typeof msg.agentConfig === "object" && !Array.isArray(msg.agentConfig) ? msg.agentConfig : void 0;
38553
38717
  acpManager.logPromptReceivedFromBridge({ agentType, mode });
@@ -38585,6 +38749,7 @@ function handleBridgePrompt(msg, deps) {
38585
38749
  runId,
38586
38750
  mode,
38587
38751
  agentType,
38752
+ agentId,
38588
38753
  agentConfig,
38589
38754
  sessionParentPath: effectiveCwd,
38590
38755
  sendResult: sendResult2,
@@ -38647,8 +38812,8 @@ function randomSecret() {
38647
38812
  }
38648
38813
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
38649
38814
  }
38650
- async function requestPreviewApi(port, secret, method, path41, body) {
38651
- const url2 = `http://127.0.0.1:${port}${path41}`;
38815
+ async function requestPreviewApi(port, secret, method, path43, body) {
38816
+ const url2 = `http://127.0.0.1:${port}${path43}`;
38652
38817
  const headers = {
38653
38818
  [PREVIEW_SECRET_HEADER]: secret,
38654
38819
  "Content-Type": "application/json"
@@ -38660,7 +38825,7 @@ async function requestPreviewApi(port, secret, method, path41, body) {
38660
38825
  });
38661
38826
  const data = await res.json().catch(() => ({}));
38662
38827
  if (!res.ok) {
38663
- throw new Error(data?.error ?? `Preview API ${method} ${path41}: ${res.status}`);
38828
+ throw new Error(data?.error ?? `Preview API ${method} ${path43}: ${res.status}`);
38664
38829
  }
38665
38830
  return data;
38666
38831
  }
@@ -39774,6 +39939,242 @@ function createBridgeHeartbeatController(params) {
39774
39939
  };
39775
39940
  }
39776
39941
 
39942
+ // src/sqlite/hash-json-sha256.ts
39943
+ import { createHash as createHash2 } from "node:crypto";
39944
+ function hashJsonUtf8Sha256(value) {
39945
+ return createHash2("sha256").update(JSON.stringify(value), "utf8").digest("hex");
39946
+ }
39947
+
39948
+ // src/sqlite/agent-capability-cache.ts
39949
+ function hasNonEmptyAgentCapabilityCache(db, workspaceId, agentType) {
39950
+ const t = agentType.trim();
39951
+ if (!t) return false;
39952
+ try {
39953
+ const row = db.get(
39954
+ `SELECT config_options_json FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
39955
+ [workspaceId, t]
39956
+ );
39957
+ if (row?.config_options_json == null || row.config_options_json === "") return false;
39958
+ const parsed = JSON.parse(row.config_options_json);
39959
+ return Array.isArray(parsed) && parsed.length > 0;
39960
+ } catch {
39961
+ return false;
39962
+ }
39963
+ }
39964
+ function upsertCliAgentCapabilityCache(db, row) {
39965
+ const t = row.agentType.trim();
39966
+ if (!t) return false;
39967
+ const hash = hashJsonUtf8Sha256(row.configOptions);
39968
+ try {
39969
+ const prev = db.get(
39970
+ `SELECT content_hash FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
39971
+ [row.workspaceId, t]
39972
+ );
39973
+ if (prev?.content_hash === hash) return false;
39974
+ } catch {
39975
+ }
39976
+ const json2 = JSON.stringify(row.configOptions);
39977
+ const now = (/* @__PURE__ */ new Date()).toISOString();
39978
+ db.run(
39979
+ `INSERT INTO agent_capabilities (workspace_id, agent_type, config_options_json, content_hash, updated_at)
39980
+ VALUES (?, ?, ?, ?, ?)
39981
+ ON CONFLICT(workspace_id, agent_type) DO UPDATE SET
39982
+ config_options_json = excluded.config_options_json,
39983
+ content_hash = excluded.content_hash,
39984
+ updated_at = excluded.updated_at`,
39985
+ [row.workspaceId, t, json2, hash, now]
39986
+ );
39987
+ return true;
39988
+ }
39989
+ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
39990
+ const rows = db.all(
39991
+ `SELECT agent_type, config_options_json FROM agent_capabilities WHERE workspace_id = ?`,
39992
+ [workspaceId]
39993
+ );
39994
+ const out = [];
39995
+ for (const r of rows) {
39996
+ try {
39997
+ const parsed = JSON.parse(r.config_options_json);
39998
+ if (!Array.isArray(parsed) || parsed.length === 0) continue;
39999
+ out.push({ agentType: r.agent_type, configOptions: parsed });
40000
+ } catch {
40001
+ }
40002
+ }
40003
+ return out;
40004
+ }
40005
+
40006
+ // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
40007
+ import * as path40 from "node:path";
40008
+
40009
+ // src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
40010
+ import * as path39 from "node:path";
40011
+ async function probeOneAgentTypeForCapabilities(params) {
40012
+ const { agentType, cwd, workspaceId, log: log2, getDb, reportAgentCapabilities, bridgeReport = true } = params;
40013
+ const resolved = resolveAgentCommand(agentType);
40014
+ if (!resolved) return false;
40015
+ let sqliteChanged = false;
40016
+ const reportedRef = { done: false };
40017
+ const tryReport = (co) => {
40018
+ if (reportedRef.done) return;
40019
+ if (!Array.isArray(co) || co.length === 0) return;
40020
+ reportedRef.done = true;
40021
+ let changed = false;
40022
+ try {
40023
+ changed = upsertCliAgentCapabilityCache(getDb(), {
40024
+ workspaceId,
40025
+ agentType,
40026
+ configOptions: co
40027
+ });
40028
+ } catch {
40029
+ }
40030
+ sqliteChanged ||= changed;
40031
+ if (bridgeReport && changed) {
40032
+ reportAgentCapabilities?.({ agentType, configOptions: co });
40033
+ }
40034
+ };
40035
+ let handle = null;
40036
+ const killTimer = setTimeout(() => {
40037
+ try {
40038
+ handle?.disconnect();
40039
+ } catch {
40040
+ }
40041
+ }, 28e3);
40042
+ killTimer.unref?.();
40043
+ try {
40044
+ handle = await resolved.createClient({
40045
+ command: resolved.command,
40046
+ cwd: path39.resolve(cwd),
40047
+ backendAgentType: agentType,
40048
+ sessionMode: "agent",
40049
+ persistedAcpSessionId: null,
40050
+ agentConfig: null,
40051
+ getActiveConfigOptions: () => null,
40052
+ onAcpSessionEstablished: (info) => {
40053
+ tryReport(info.configOptions ?? null);
40054
+ },
40055
+ onAcpConfigOptionsUpdated: (co) => {
40056
+ tryReport(co);
40057
+ },
40058
+ onAgentSubprocessExit: () => {
40059
+ },
40060
+ onSessionUpdate: () => {
40061
+ }
40062
+ });
40063
+ await new Promise((r) => setTimeout(r, 1200));
40064
+ } catch (e) {
40065
+ log2(
40066
+ `[Bridge service] Agent capability probe (${agentType}): ${e instanceof Error ? e.message : String(e)}`
40067
+ );
40068
+ } finally {
40069
+ clearTimeout(killTimer);
40070
+ try {
40071
+ handle?.disconnect();
40072
+ } catch {
40073
+ }
40074
+ }
40075
+ return sqliteChanged;
40076
+ }
40077
+
40078
+ // src/agents/capabilities/probe-agent-capabilities-for-types.ts
40079
+ async function probeAgentCapabilitiesForDetectedTypes(params) {
40080
+ const {
40081
+ agentTypes,
40082
+ cwd,
40083
+ workspaceId,
40084
+ log: log2,
40085
+ getDb,
40086
+ reportAgentCapabilities,
40087
+ bridgeReport = true,
40088
+ forceAllTypes = false
40089
+ } = params;
40090
+ let changedCount = 0;
40091
+ for (let i = 0; i < agentTypes.length; i++) {
40092
+ if (i > 0) await yieldToEventLoop();
40093
+ const agentType = agentTypes[i];
40094
+ if (!agentType.trim()) continue;
40095
+ if (!forceAllTypes) {
40096
+ try {
40097
+ if (process.env.BUILDAUTOMATON_FORCE_PROBE_ACP_CAPABILITIES !== "1" && hasNonEmptyAgentCapabilityCache(getDb(), workspaceId, agentType)) {
40098
+ continue;
40099
+ }
40100
+ } catch {
40101
+ }
40102
+ }
40103
+ const changed = await probeOneAgentTypeForCapabilities({
40104
+ agentType,
40105
+ cwd,
40106
+ workspaceId,
40107
+ log: log2,
40108
+ getDb,
40109
+ reportAgentCapabilities,
40110
+ bridgeReport
40111
+ });
40112
+ if (changed) changedCount += 1;
40113
+ }
40114
+ return changedCount;
40115
+ }
40116
+
40117
+ // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
40118
+ async function warmupAgentCapabilitiesOnConnect(params) {
40119
+ const { workspaceId, log: log2, getDb, getWs } = params;
40120
+ const cwd = path40.resolve(getBridgeRoot());
40121
+ const db = getDb();
40122
+ function sendBatchFromCache() {
40123
+ const socket = getWs();
40124
+ if (!socket || socket.readyState !== wrapper_default.OPEN) return;
40125
+ try {
40126
+ const rows = listCliAgentCapabilityCacheForWorkspace(db, workspaceId);
40127
+ if (rows.length === 0) return;
40128
+ sendWsMessage(socket, {
40129
+ type: "agent_capabilities_batch",
40130
+ items: rows.map((r) => ({ agentType: r.agentType, configOptions: r.configOptions }))
40131
+ });
40132
+ } catch (e) {
40133
+ log2(
40134
+ `[Bridge service] Agent capability batch to bridge failed: ${e instanceof Error ? e.message : String(e)}`
40135
+ );
40136
+ }
40137
+ }
40138
+ sendBatchFromCache();
40139
+ let types = [];
40140
+ try {
40141
+ types = [...await detectLocalAgentTypes()];
40142
+ } catch (e) {
40143
+ log2(`[Bridge service] detectLocalAgentTypes failed: ${e instanceof Error ? e.message : String(e)}`);
40144
+ }
40145
+ try {
40146
+ const n = await probeAgentCapabilitiesForDetectedTypes({
40147
+ agentTypes: types,
40148
+ cwd,
40149
+ workspaceId,
40150
+ log: log2,
40151
+ getDb,
40152
+ bridgeReport: false,
40153
+ forceAllTypes: false
40154
+ });
40155
+ if (n > 0) sendBatchFromCache();
40156
+ } catch (e) {
40157
+ log2(`[Bridge service] Agent capability probe (missing cache) failed: ${e instanceof Error ? e.message : String(e)}`);
40158
+ }
40159
+ void (async () => {
40160
+ try {
40161
+ await yieldToEventLoop();
40162
+ const n = await probeAgentCapabilitiesForDetectedTypes({
40163
+ agentTypes: types,
40164
+ cwd,
40165
+ workspaceId,
40166
+ log: log2,
40167
+ getDb,
40168
+ bridgeReport: false,
40169
+ forceAllTypes: true
40170
+ });
40171
+ if (n > 0) sendBatchFromCache();
40172
+ } catch (e) {
40173
+ log2(`[Bridge service] Agent capability lazy refresh failed: ${e instanceof Error ? e.message : String(e)}`);
40174
+ }
40175
+ })();
40176
+ }
40177
+
39777
40178
  // src/connection/create-bridge-connection.ts
39778
40179
  async function createBridgeConnection(options) {
39779
40180
  const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
@@ -39802,16 +40203,39 @@ async function createBridgeConnection(options) {
39802
40203
  firehoseOutage: createEmptyReconnectOutageTracker(),
39803
40204
  lastFirehoseReconnectCloseMeta: null
39804
40205
  };
40206
+ function getWs() {
40207
+ return state.currentWs;
40208
+ }
40209
+ function sendAgentCapabilitiesToBridge(info) {
40210
+ if (!Array.isArray(info.configOptions) || info.configOptions.length === 0) return;
40211
+ let changed = false;
40212
+ try {
40213
+ changed = upsertCliAgentCapabilityCache(getCliDatabase(), {
40214
+ workspaceId,
40215
+ agentType: info.agentType,
40216
+ configOptions: info.configOptions
40217
+ });
40218
+ } catch {
40219
+ }
40220
+ if (!changed) return;
40221
+ const socket = getWs();
40222
+ if (!socket || socket.readyState !== wrapper_default.OPEN) return;
40223
+ sendWsMessage(socket, {
40224
+ type: "agent_capabilities",
40225
+ agentType: info.agentType,
40226
+ configOptions: info.configOptions
40227
+ });
40228
+ }
39805
40229
  const worktreesRootPath = options.worktreesRootPath ?? defaultWorktreesRootPath();
39806
40230
  const sessionWorktreeManager = new SessionWorktreeManager({
39807
40231
  worktreesRootPath,
39808
40232
  log: logFn
39809
40233
  });
39810
- const acpManager = await createAcpManager({ log: logFn });
40234
+ const acpManager = await createAcpManager({
40235
+ log: logFn,
40236
+ reportAgentCapabilities: sendAgentCapabilitiesToBridge
40237
+ });
39811
40238
  logFn("CLI running. Press Ctrl+C to exit.");
39812
- function getWs() {
39813
- return state.currentWs;
39814
- }
39815
40239
  const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
39816
40240
  const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
39817
40241
  const bridgeHeartbeat = createBridgeHeartbeatController({ getWs, log: logFn });
@@ -39839,14 +40263,22 @@ async function createBridgeConnection(options) {
39839
40263
  },
39840
40264
  sendLocalSkillsReport,
39841
40265
  reportAutoDetectedAgents,
40266
+ warmupAgentCapabilitiesOnConnect: async () => {
40267
+ await warmupAgentCapabilitiesOnConnect({
40268
+ workspaceId,
40269
+ log: logFn,
40270
+ getDb: getCliDatabase,
40271
+ getWs
40272
+ });
40273
+ },
39842
40274
  devServerManager,
39843
40275
  e2ee,
39844
40276
  cloudApiBaseUrl: apiUrl,
39845
40277
  getCloudAccessToken: () => tokens.accessToken
39846
40278
  };
39847
40279
  const identifyReportedPaths = {
39848
- bridgeRootPath: path39.resolve(getBridgeRoot()),
39849
- worktreesRootPath: path39.resolve(worktreesRootPath)
40280
+ bridgeRootPath: path41.resolve(getBridgeRoot()),
40281
+ worktreesRootPath: path41.resolve(worktreesRootPath)
39850
40282
  };
39851
40283
  const { connect } = createMainBridgeWebSocketLifecycle({
39852
40284
  state,
@@ -40084,7 +40516,7 @@ async function runCliAction(program2, opts) {
40084
40516
  const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
40085
40517
  const bridgeRootOpt = (opts.bridgeRoot && typeof opts.bridgeRoot === "string" && opts.bridgeRoot.trim() ? opts.bridgeRoot.trim() : null) ?? (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim() ? opts.cwd.trim() : null);
40086
40518
  if (bridgeRootOpt) {
40087
- const resolvedBridgeRoot = path40.resolve(process.cwd(), bridgeRootOpt);
40519
+ const resolvedBridgeRoot = path42.resolve(process.cwd(), bridgeRootOpt);
40088
40520
  try {
40089
40521
  const st = fs37.statSync(resolvedBridgeRoot);
40090
40522
  if (!st.isDirectory()) {
@@ -40106,7 +40538,7 @@ async function runCliAction(program2, opts) {
40106
40538
  );
40107
40539
  let worktreesRootPath;
40108
40540
  if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
40109
- worktreesRootPath = path40.resolve(opts.worktreesRoot.trim());
40541
+ worktreesRootPath = path42.resolve(opts.worktreesRoot.trim());
40110
40542
  }
40111
40543
  const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
40112
40544
  if (e2eCertificates) {