@buildautomaton/cli 0.1.98 → 0.1.99

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/index.js CHANGED
@@ -3805,6 +3805,7 @@ function isCliSqliteLockError(e) {
3805
3805
  var CliSqliteInterrupted;
3806
3806
  var init_sqlite_errors = __esm({
3807
3807
  "../bridge/src/sqlite/sqlite-errors.ts"() {
3808
+ "use strict";
3808
3809
  CliSqliteInterrupted = class extends Error {
3809
3810
  name = "CliSqliteInterrupted";
3810
3811
  constructor() {
@@ -3959,6 +3960,7 @@ function maybeLogCodeNavCacheWorkerError(message) {
3959
3960
  var diagnosticSink, lastDiagnosticKey;
3960
3961
  var init_code_nav_cache_log = __esm({
3961
3962
  "../bridge/src/sqlite/code-nav-cache/code-nav-cache-log.ts"() {
3963
+ "use strict";
3962
3964
  init_log();
3963
3965
  init_sqlite_errors();
3964
3966
  init_sqlite_lock_path();
@@ -5122,6 +5124,7 @@ async function ensureCodeNavCacheSqliteInitialized() {
5122
5124
  var safeCloseCodeNavCacheSqliteDatabase, openCodeNavCacheSqliteConnection;
5123
5125
  var init_database = __esm({
5124
5126
  "../bridge/src/sqlite/code-nav-cache/database.ts"() {
5127
+ "use strict";
5125
5128
  init_code_nav_cache_availability();
5126
5129
  init_instance();
5127
5130
  init_sqlite_errors();
@@ -5366,7 +5369,7 @@ function migrateCliSqlite(db) {
5366
5369
  "cli-sqlite"
5367
5370
  );
5368
5371
  }
5369
- var CHECKPOINT_V12, CHECKPOINT_V1_SQL2, AGENT_CAPABILITIES_SQL, DROP_CACHE_TABLES_SQL, CLI_SQLITE_MIGRATIONS;
5372
+ var CHECKPOINT_V12, CHECKPOINT_V1_SQL2, AGENT_CAPABILITIES_SQL, AGENT_SESSION_AVAILABLE_COMMANDS_SQL, AGENT_CAPABILITIES_AVAILABLE_COMMANDS_SQL, DROP_CACHE_TABLES_SQL, CLI_SQLITE_MIGRATIONS;
5370
5373
  var init_migrate_cli_sqlite = __esm({
5371
5374
  "../bridge/src/sqlite/migrate-cli-sqlite.ts"() {
5372
5375
  "use strict";
@@ -5375,6 +5378,12 @@ var init_migrate_cli_sqlite = __esm({
5375
5378
  CHECKPOINT_V12 = "001_cli_sqlite_checkpoint_v1";
5376
5379
  CHECKPOINT_V1_SQL2 = readCliSqliteMigrationSql("001_cli_sqlite_checkpoint_v1.sql");
5377
5380
  AGENT_CAPABILITIES_SQL = readCliSqliteMigrationSql("002_agent_capabilities.sql");
5381
+ AGENT_SESSION_AVAILABLE_COMMANDS_SQL = readCliSqliteMigrationSql(
5382
+ "003_agent_session_available_commands.sql"
5383
+ );
5384
+ AGENT_CAPABILITIES_AVAILABLE_COMMANDS_SQL = readCliSqliteMigrationSql(
5385
+ "004_agent_capabilities_available_commands.sql"
5386
+ );
5378
5387
  DROP_CACHE_TABLES_SQL = readCliSqliteMigrationSql("006_drop_cache_tables.sql");
5379
5388
  CLI_SQLITE_MIGRATIONS = [
5380
5389
  {
@@ -5401,6 +5410,26 @@ var init_migrate_cli_sqlite = __esm({
5401
5410
  },
5402
5411
  alreadyApplied: (db) => agentCapabilitiesTableState(db) === "current"
5403
5412
  },
5413
+ {
5414
+ name: "003_agent_session_available_commands",
5415
+ migrate: (db) => {
5416
+ db.exec(AGENT_SESSION_AVAILABLE_COMMANDS_SQL);
5417
+ },
5418
+ alreadyApplied: (db) => {
5419
+ const rows = db.all(`PRAGMA table_info(agent_session)`);
5420
+ return rows.some((r) => r.name === "available_commands_json");
5421
+ }
5422
+ },
5423
+ {
5424
+ name: "004_agent_capabilities_available_commands",
5425
+ migrate: (db) => {
5426
+ db.exec(AGENT_CAPABILITIES_AVAILABLE_COMMANDS_SQL);
5427
+ },
5428
+ alreadyApplied: (db) => {
5429
+ const rows = db.all(`PRAGMA table_info(agent_capabilities)`);
5430
+ return rows.some((r) => r.name === "available_commands_json");
5431
+ }
5432
+ },
5404
5433
  {
5405
5434
  name: "006_drop_cache_tables",
5406
5435
  migrate: (db) => {
@@ -32824,6 +32853,12 @@ function liveEditSnippetToUnifiedDiff(filePath, oldText, newText) {
32824
32853
  // ../bridge/src/files/workspace/limits.ts
32825
32854
  var MAX_SYNC_WORKSPACE_FILE_BYTES = 512 * 1024;
32826
32855
 
32856
+ // ../bridge/src/files/workspace/path-has-dot-dot-segment.ts
32857
+ function pathHasDotDotSegment(path84) {
32858
+ if (!path84) return false;
32859
+ return path84.split(/[/\\]/).includes("..");
32860
+ }
32861
+
32827
32862
  // ../bridge/src/files/workspace/safe-path.ts
32828
32863
  import * as path2 from "node:path";
32829
32864
  function resolveSafePathUnderCwd(cwd, filePath) {
@@ -32832,7 +32867,7 @@ function resolveSafePathUnderCwd(cwd, filePath) {
32832
32867
  const normalizedCwd = path2.resolve(cwd);
32833
32868
  const resolved = path2.isAbsolute(trimmed2) ? path2.normalize(trimmed2) : path2.resolve(normalizedCwd, trimmed2);
32834
32869
  const rel = path2.relative(normalizedCwd, resolved);
32835
- if (rel.startsWith("..") || path2.isAbsolute(rel)) return null;
32870
+ if (rel === ".." || rel.startsWith(`..${path2.sep}`) || path2.isAbsolute(rel)) return null;
32836
32871
  return resolved;
32837
32872
  }
32838
32873
  function toDisplayPathRelativeToCwd(cwd, absolutePath) {
@@ -32994,6 +33029,9 @@ function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
32994
33029
  import { readFileSync as readFileSync3, statSync } from "node:fs";
32995
33030
  import * as path19 from "node:path";
32996
33031
  var GIT_FILE_READ_TIMEOUT_MS = 2e3;
33032
+ function isRelUnderRoot(rel) {
33033
+ return rel !== ".." && !rel.startsWith(`..${path19.sep}`) && !path19.isAbsolute(rel);
33034
+ }
32997
33035
  function readUtf8FileCapped(resolvedPath) {
32998
33036
  try {
32999
33037
  const st = statSync(resolvedPath);
@@ -33004,12 +33042,12 @@ function readUtf8FileCapped(resolvedPath) {
33004
33042
  }
33005
33043
  }
33006
33044
  function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
33007
- if (!displayPath || displayPath.includes("..")) return "";
33045
+ if (!displayPath || pathHasDotDotSegment(displayPath)) return "";
33008
33046
  const gitRoot = getGitRepoRootSync(sessionParentPath);
33009
33047
  if (gitRoot) {
33010
33048
  const resolvedPath2 = path19.resolve(gitRoot, displayPath);
33011
33049
  const rel = path19.relative(gitRoot, resolvedPath2);
33012
- if (!rel.startsWith("..") && !path19.isAbsolute(rel)) {
33050
+ if (isRelUnderRoot(rel)) {
33013
33051
  return readUtf8FileCapped(resolvedPath2);
33014
33052
  }
33015
33053
  }
@@ -33018,17 +33056,17 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
33018
33056
  return readUtf8FileCapped(resolvedPath);
33019
33057
  }
33020
33058
  function tryWorkspaceDisplayToPath(sessionParentPath, displayPath) {
33021
- if (!displayPath || displayPath.includes("..")) return null;
33059
+ if (!displayPath || pathHasDotDotSegment(displayPath)) return null;
33022
33060
  const gitRoot = getGitRepoRootSync(sessionParentPath);
33023
33061
  if (gitRoot) {
33024
33062
  const resolvedPath = path19.resolve(gitRoot, displayPath);
33025
33063
  const rel = path19.relative(gitRoot, resolvedPath);
33026
- if (!rel.startsWith("..") && !path19.isAbsolute(rel)) return resolvedPath;
33064
+ if (isRelUnderRoot(rel)) return resolvedPath;
33027
33065
  }
33028
33066
  return resolveSafePathUnderCwd(sessionParentPath, displayPath);
33029
33067
  }
33030
33068
  function readGitHeadBlob(sessionParentPath, displayPath) {
33031
- if (!displayPath || displayPath.includes("..")) return "";
33069
+ if (!displayPath || pathHasDotDotSegment(displayPath)) return "";
33032
33070
  const gitRoot = getGitRepoRootSync(sessionParentPath);
33033
33071
  if (!gitRoot) return "";
33034
33072
  try {
@@ -33080,15 +33118,35 @@ function acpWriteTextFileInProcess(ctx, filePath, newText) {
33080
33118
  return {};
33081
33119
  }
33082
33120
 
33121
+ // ../bridge/src/agents/acp/clients/shared/parse-available-commands.ts
33122
+ function parseAvailableCommandsList(raw) {
33123
+ if (!Array.isArray(raw)) return null;
33124
+ return raw;
33125
+ }
33126
+ function availableCommandsFromSessionUpdatePayload(flatPayload) {
33127
+ return parseAvailableCommandsList(flatPayload.availableCommands ?? flatPayload.available_commands);
33128
+ }
33129
+
33083
33130
  // ../bridge/src/agents/acp/clients/shared/dispatch-session-update.ts
33084
33131
  function dispatchAcpSessionUpdate(opts) {
33085
- const { flatPayload, onAcpConfigOptionsUpdated, onSessionUpdate, suppressLoadReplay } = opts;
33132
+ const {
33133
+ flatPayload,
33134
+ onAcpConfigOptionsUpdated,
33135
+ onAcpAvailableCommandsUpdated,
33136
+ onSessionUpdate,
33137
+ suppressLoadReplay
33138
+ } = opts;
33086
33139
  const su = flatPayload.sessionUpdate ?? flatPayload.session_update;
33087
33140
  if (su === "config_option_update") {
33088
33141
  const co = flatPayload.configOptions;
33089
33142
  if (Array.isArray(co)) onAcpConfigOptionsUpdated?.(co);
33090
33143
  return;
33091
33144
  }
33145
+ if (su === "available_commands_update") {
33146
+ const cmds = availableCommandsFromSessionUpdatePayload(flatPayload);
33147
+ if (cmds) onAcpAvailableCommandsUpdated?.(cmds);
33148
+ return;
33149
+ }
33092
33150
  if (suppressLoadReplay()) return;
33093
33151
  onSessionUpdate?.(flatPayload);
33094
33152
  }
@@ -33161,6 +33219,7 @@ function createSdkStdioConnectionClient(deps) {
33161
33219
  dispatchAcpSessionUpdate({
33162
33220
  flatPayload: bridged,
33163
33221
  onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
33222
+ onAcpAvailableCommandsUpdated: sessionCtx.onAcpAvailableCommandsUpdated,
33164
33223
  onSessionUpdate,
33165
33224
  suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
33166
33225
  });
@@ -33248,6 +33307,7 @@ function createSdkStdioSessionContext(options) {
33248
33307
  getActiveConfigOptions: options.getActiveConfigOptions,
33249
33308
  onAcpSessionEstablished: options.onAcpSessionEstablished,
33250
33309
  onAcpConfigOptionsUpdated: options.onAcpConfigOptionsUpdated,
33310
+ onAcpAvailableCommandsUpdated: options.onAcpAvailableCommandsUpdated,
33251
33311
  logDebug,
33252
33312
  getStderrText: () => options.stderrCapture.getText(),
33253
33313
  afterSessionEstablished: options.afterSessionEstablished
@@ -33606,6 +33666,7 @@ async function createSdkStdioAcpClient(options) {
33606
33666
  getActiveConfigOptions,
33607
33667
  onAcpSessionEstablished,
33608
33668
  onAcpConfigOptionsUpdated,
33669
+ onAcpAvailableCommandsUpdated: options.onAcpAvailableCommandsUpdated,
33609
33670
  onFileChange,
33610
33671
  afterSessionEstablished,
33611
33672
  stderrCapture
@@ -35742,6 +35803,7 @@ function createCursorAcpSessionContext(options) {
35742
35803
  getActiveConfigOptions: options.getActiveConfigOptions,
35743
35804
  onAcpSessionEstablished: options.onAcpSessionEstablished,
35744
35805
  onAcpConfigOptionsUpdated: options.onAcpConfigOptionsUpdated,
35806
+ onAcpAvailableCommandsUpdated: options.onAcpAvailableCommandsUpdated,
35745
35807
  logDebug,
35746
35808
  getStderrText: () => options.stderrCapture.getText(),
35747
35809
  pendingPlanExecute: { value: false },
@@ -36166,6 +36228,7 @@ function handleCursorIncomingSessionUpdate(msg, deps) {
36166
36228
  dispatchAcpSessionUpdate({
36167
36229
  flatPayload: update,
36168
36230
  onAcpConfigOptionsUpdated: deps.sessionCtx.onAcpConfigOptionsUpdated,
36231
+ onAcpAvailableCommandsUpdated: deps.sessionCtx.onAcpAvailableCommandsUpdated,
36169
36232
  onSessionUpdate: deps.onSessionUpdate,
36170
36233
  suppressLoadReplay: () => deps.sessionCtx.suppressLoadReplay.value
36171
36234
  });
@@ -36418,6 +36481,7 @@ async function createCursorAcpClient(options) {
36418
36481
  getActiveConfigOptions: options.getActiveConfigOptions,
36419
36482
  onAcpSessionEstablished,
36420
36483
  onAcpConfigOptionsUpdated,
36484
+ onAcpAvailableCommandsUpdated: options.onAcpAvailableCommandsUpdated,
36421
36485
  onFileChange,
36422
36486
  afterSessionEstablished,
36423
36487
  stderrCapture
@@ -36619,7 +36683,7 @@ function getAgentTypeDisplayName(agentType) {
36619
36683
  import { existsSync as existsSync4, statSync as statSync2 } from "node:fs";
36620
36684
  var GIT_PATH_KIND_TIMEOUT_MS = 2e3;
36621
36685
  function gitHeadPathObjectType(sessionParentPath, displayPath) {
36622
- if (!displayPath || displayPath.includes("..")) return null;
36686
+ if (!displayPath || pathHasDotDotSegment(displayPath)) return null;
36623
36687
  const gitRoot = getGitRepoRootSync(sessionParentPath);
36624
36688
  if (!gitRoot) return null;
36625
36689
  try {
@@ -37395,36 +37459,74 @@ function buildAcpSessionBridgeHooks(opts) {
37395
37459
 
37396
37460
  // ../bridge/src/agents/acp/local-agent-session-file.ts
37397
37461
  init_cli_database();
37462
+
37463
+ // ../bridge/src/agents/acp/local-agent-session-row.ts
37464
+ function parseJsonArray(raw) {
37465
+ if (raw == null || raw === "") return null;
37466
+ try {
37467
+ const parsed = JSON.parse(raw);
37468
+ return Array.isArray(parsed) ? parsed : null;
37469
+ } catch {
37470
+ return null;
37471
+ }
37472
+ }
37473
+ function rowToFile(row) {
37474
+ return {
37475
+ v: 1,
37476
+ acpSessionId: row.acp_session_id,
37477
+ backendAgentType: row.backend_agent_type,
37478
+ configOptions: parseJsonArray(row.config_options_json),
37479
+ availableCommands: parseJsonArray(row.available_commands_json),
37480
+ updatedAt: row.updated_at
37481
+ };
37482
+ }
37483
+ function readLocalAgentSessionRow(db, key) {
37484
+ const row = db.get(
37485
+ `SELECT acp_session_id, backend_agent_type, config_options_json, available_commands_json, updated_at
37486
+ FROM agent_session WHERE session_key = ?`,
37487
+ [key]
37488
+ );
37489
+ return row ? rowToFile(row) : null;
37490
+ }
37491
+ function writeLocalAgentSessionRow(db, key, patch) {
37492
+ const prev = readLocalAgentSessionRow(db, key);
37493
+ const next = {
37494
+ v: 1,
37495
+ acpSessionId: patch.acpSessionId !== void 0 ? patch.acpSessionId : prev?.acpSessionId ?? null,
37496
+ backendAgentType: patch.backendAgentType !== void 0 ? patch.backendAgentType : prev?.backendAgentType ?? null,
37497
+ configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
37498
+ availableCommands: patch.availableCommands !== void 0 ? patch.availableCommands : prev?.availableCommands ?? null,
37499
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
37500
+ };
37501
+ db.run(
37502
+ `INSERT INTO agent_session (
37503
+ session_key, acp_session_id, backend_agent_type, config_options_json, available_commands_json, updated_at
37504
+ ) VALUES (?, ?, ?, ?, ?, ?)
37505
+ ON CONFLICT(session_key) DO UPDATE SET
37506
+ acp_session_id = excluded.acp_session_id,
37507
+ backend_agent_type = excluded.backend_agent_type,
37508
+ config_options_json = excluded.config_options_json,
37509
+ available_commands_json = excluded.available_commands_json,
37510
+ updated_at = excluded.updated_at`,
37511
+ [
37512
+ key,
37513
+ next.acpSessionId,
37514
+ next.backendAgentType,
37515
+ next.configOptions != null ? JSON.stringify(next.configOptions) : null,
37516
+ next.availableCommands != null ? JSON.stringify(next.availableCommands) : null,
37517
+ next.updatedAt
37518
+ ]
37519
+ );
37520
+ }
37521
+
37522
+ // ../bridge/src/agents/acp/local-agent-session-file.ts
37398
37523
  function sessionKeyForCloudSessionId(cloudSessionId) {
37399
37524
  const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
37400
37525
  return t.length > 0 ? t : "session";
37401
37526
  }
37402
37527
  function readLocalAgentSessionFile(cloudSessionId) {
37403
37528
  try {
37404
- return withCliSqliteSync((db) => {
37405
- const key = sessionKeyForCloudSessionId(cloudSessionId);
37406
- const row = db.get(
37407
- "SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
37408
- [key]
37409
- );
37410
- if (!row) return null;
37411
- let configOptions = null;
37412
- if (row.config_options_json != null && row.config_options_json !== "") {
37413
- try {
37414
- const parsed = JSON.parse(row.config_options_json);
37415
- configOptions = Array.isArray(parsed) ? parsed : null;
37416
- } catch {
37417
- configOptions = null;
37418
- }
37419
- }
37420
- return {
37421
- v: 1,
37422
- acpSessionId: row.acp_session_id,
37423
- backendAgentType: row.backend_agent_type,
37424
- configOptions,
37425
- updatedAt: row.updated_at
37426
- };
37427
- });
37529
+ return withCliSqliteSync((db) => readLocalAgentSessionRow(db, sessionKeyForCloudSessionId(cloudSessionId)));
37428
37530
  } catch {
37429
37531
  return null;
37430
37532
  }
@@ -37432,53 +37534,28 @@ function readLocalAgentSessionFile(cloudSessionId) {
37432
37534
  function writeLocalAgentSessionFile(cloudSessionId, patch) {
37433
37535
  try {
37434
37536
  withCliSqliteSync((db) => {
37435
- const key = sessionKeyForCloudSessionId(cloudSessionId);
37436
- const prevRow = db.get(
37437
- "SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
37438
- [key]
37439
- );
37440
- let prev = null;
37441
- if (prevRow) {
37442
- let configOptions = null;
37443
- if (prevRow.config_options_json != null && prevRow.config_options_json !== "") {
37444
- try {
37445
- const parsed = JSON.parse(prevRow.config_options_json);
37446
- configOptions = Array.isArray(parsed) ? parsed : null;
37447
- } catch {
37448
- configOptions = null;
37449
- }
37450
- }
37451
- prev = {
37452
- v: 1,
37453
- acpSessionId: prevRow.acp_session_id,
37454
- backendAgentType: prevRow.backend_agent_type,
37455
- configOptions,
37456
- updatedAt: prevRow.updated_at
37457
- };
37458
- }
37459
- const next = {
37460
- v: 1,
37461
- acpSessionId: patch.acpSessionId !== void 0 ? patch.acpSessionId : prev?.acpSessionId ?? null,
37462
- backendAgentType: patch.backendAgentType !== void 0 ? patch.backendAgentType : prev?.backendAgentType ?? null,
37463
- configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
37464
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
37465
- };
37466
- const configJson = next.configOptions != null ? JSON.stringify(next.configOptions) : null;
37467
- db.run(
37468
- `INSERT INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
37469
- VALUES (?, ?, ?, ?, ?)
37470
- ON CONFLICT(session_key) DO UPDATE SET
37471
- acp_session_id = excluded.acp_session_id,
37472
- backend_agent_type = excluded.backend_agent_type,
37473
- config_options_json = excluded.config_options_json,
37474
- updated_at = excluded.updated_at`,
37475
- [key, next.acpSessionId, next.backendAgentType, configJson, next.updatedAt]
37476
- );
37537
+ writeLocalAgentSessionRow(db, sessionKeyForCloudSessionId(cloudSessionId), patch);
37477
37538
  });
37478
37539
  } catch {
37479
37540
  }
37480
37541
  }
37481
37542
 
37543
+ // ../bridge/src/agents/acp/persist-acp-available-commands.ts
37544
+ function persistAcpAvailableCommands(params) {
37545
+ const { availableCommands, setActive, cloudSessionId, preferredAgentType, reportAgentCapabilities } = params;
37546
+ if (!Array.isArray(availableCommands)) return;
37547
+ setActive(availableCommands);
37548
+ if (cloudSessionId != null && cloudSessionId !== "") {
37549
+ writeLocalAgentSessionFile(cloudSessionId, {
37550
+ availableCommands,
37551
+ ...preferredAgentType != null && preferredAgentType !== "" ? { backendAgentType: preferredAgentType } : {}
37552
+ });
37553
+ }
37554
+ if (reportAgentCapabilities && preferredAgentType != null && preferredAgentType !== "" && availableCommands.length > 0) {
37555
+ reportAgentCapabilities({ agentType: preferredAgentType, availableCommands });
37556
+ }
37557
+ }
37558
+
37482
37559
  // ../bridge/src/agents/acp/acp-agent.ts
37483
37560
  function computeAcpSessionAgentKey(cloudSessionId, acpAgentKey) {
37484
37561
  const sid = cloudSessionId?.trim();
@@ -37527,6 +37604,7 @@ function invalidateAcpClientState(state) {
37527
37604
  state.acpStartPromise = null;
37528
37605
  state.acpAgentKey = null;
37529
37606
  state.activeSessionConfigOptions = null;
37607
+ state.activeAvailableCommands = null;
37530
37608
  state.latestAgentConfigForBridgeHooks = null;
37531
37609
  }
37532
37610
  function createEmptyAcpClientState() {
@@ -37537,6 +37615,7 @@ function createEmptyAcpClientState() {
37537
37615
  lastAcpCwd: null,
37538
37616
  acpAgentKey: null,
37539
37617
  activeSessionConfigOptions: null,
37618
+ activeAvailableCommands: null,
37540
37619
  latestAgentConfigForBridgeHooks: null,
37541
37620
  clientEpoch: 0
37542
37621
  };
@@ -37622,6 +37701,7 @@ async function ensureAcpClient(options) {
37622
37701
  const persisted = cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "" ? readLocalAgentSessionFile(cloudSessionId) : null;
37623
37702
  const persistedAcpSessionId = persisted && persisted.backendAgentType === preferredAgentType && typeof persisted.acpSessionId === "string" && persisted.acpSessionId.trim() !== "" ? persisted.acpSessionId.trim() : null;
37624
37703
  state.activeSessionConfigOptions = Array.isArray(persisted?.configOptions) ? persisted.configOptions : null;
37704
+ state.activeAvailableCommands = Array.isArray(persisted?.availableCommands) ? persisted.availableCommands : null;
37625
37705
  const spawnEpoch = state.clientEpoch;
37626
37706
  state.acpStartPromise = resolved.createClient({
37627
37707
  command: resolved.command,
@@ -37661,6 +37741,17 @@ async function ensureAcpClient(options) {
37661
37741
  });
37662
37742
  }
37663
37743
  },
37744
+ onAcpAvailableCommandsUpdated: (availableCommands) => {
37745
+ persistAcpAvailableCommands({
37746
+ availableCommands,
37747
+ setActive: (cmds) => {
37748
+ state.activeAvailableCommands = cmds;
37749
+ },
37750
+ cloudSessionId,
37751
+ preferredAgentType,
37752
+ reportAgentCapabilities
37753
+ });
37754
+ },
37664
37755
  onAgentSubprocessExit: () => {
37665
37756
  if (state.acpHandle != null) {
37666
37757
  state.clientEpoch += 1;
@@ -37669,6 +37760,7 @@ async function ensureAcpClient(options) {
37669
37760
  state.acpStartPromise = null;
37670
37761
  state.acpAgentKey = null;
37671
37762
  state.activeSessionConfigOptions = null;
37763
+ state.activeAvailableCommands = null;
37672
37764
  state.latestAgentConfigForBridgeHooks = null;
37673
37765
  state.lastAcpStartError = "Agent subprocess exited";
37674
37766
  },
@@ -37878,7 +37970,7 @@ function repoDisplayPath(repoPath, multiRepo) {
37878
37970
  return (rel) => multiRepo ? `${slug}/${rel}` : rel;
37879
37971
  }
37880
37972
  function safeRelPath(rel) {
37881
- return typeof rel === "string" && rel.length > 0 && !rel.includes("..");
37973
+ return typeof rel === "string" && rel.length > 0 && !pathHasDotDotSegment(rel);
37882
37974
  }
37883
37975
  function newUntrackedPaths(raw, baselineUntracked, seen) {
37884
37976
  const baseline = new Set(baselineUntracked);
@@ -38208,6 +38300,19 @@ async function sendPromptToAgent(options) {
38208
38300
  attachments,
38209
38301
  isNewSession = false
38210
38302
  } = options;
38303
+ const finalize2 = (result) => finalizeAndSendPromptResult({
38304
+ result,
38305
+ sessionId,
38306
+ runId,
38307
+ promptId,
38308
+ agentType,
38309
+ agentCwd,
38310
+ followUpCatalogPromptId,
38311
+ plugin,
38312
+ sendResult,
38313
+ sendSessionUpdate,
38314
+ log: log2
38315
+ });
38211
38316
  try {
38212
38317
  const prepared = await prepareAgentPromptText({
38213
38318
  promptText,
@@ -38228,7 +38333,10 @@ async function sendPromptToAgent(options) {
38228
38333
  log: log2
38229
38334
  });
38230
38335
  if (!imagesResolved.ok) {
38231
- sendResult(imagesResolved.errorResult);
38336
+ await finalize2({
38337
+ success: false,
38338
+ error: imagesResolved.errorResult.error
38339
+ });
38232
38340
  return;
38233
38341
  }
38234
38342
  const promptStartedAt = Date.now();
@@ -38237,32 +38345,11 @@ async function sendPromptToAgent(options) {
38237
38345
  if (promptDurationMs >= SLOW_ACP_PROMPT_MS) {
38238
38346
  log2(`[Agent] ACP session/prompt completed after ${promptDurationMs}ms.`);
38239
38347
  }
38240
- await finalizeAndSendPromptResult({
38241
- result,
38242
- sessionId,
38243
- runId,
38244
- promptId,
38245
- agentType,
38246
- agentCwd,
38247
- followUpCatalogPromptId,
38248
- plugin,
38249
- sendResult,
38250
- sendSessionUpdate,
38251
- log: log2
38252
- });
38348
+ await finalize2(result);
38253
38349
  } catch (err) {
38254
38350
  const errMsg = err instanceof Error ? err.message : String(err);
38255
38351
  log2(`[Agent] Send failed: ${errMsg}`);
38256
- sendResult({
38257
- type: "prompt_result",
38258
- id: promptId,
38259
- ...sessionId ? { sessionId } : {},
38260
- ...runId ? { runId } : {},
38261
- success: false,
38262
- error: errMsg,
38263
- ...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
38264
- ...augmentPromptResultAuthFields(agentType, errMsg)
38265
- });
38352
+ await finalize2({ success: false, error: errMsg });
38266
38353
  }
38267
38354
  }
38268
38355
 
@@ -38382,8 +38469,13 @@ async function ensureAcpPromptClient(ctx, runCtx, opts) {
38382
38469
 
38383
38470
  // ../bridge/src/agents/acp/manager/run-acp-prompt.ts
38384
38471
  async function runAcpPrompt(ctx, runCtx, opts) {
38385
- const handle = await ensureAcpPromptClient(ctx, runCtx, opts);
38386
- if (handle) await dispatchAcpPrompt(ctx, runCtx, opts, handle);
38472
+ ctx.promptRouting.setStreamingRunId(runCtx.activeAcpSessionAgentKey, runCtx.activeRunId);
38473
+ try {
38474
+ const handle = await ensureAcpPromptClient(ctx, runCtx, opts);
38475
+ if (handle) await dispatchAcpPrompt(ctx, runCtx, opts, handle);
38476
+ } finally {
38477
+ ctx.promptRouting.clearStreamingRunId(runCtx.activeAcpSessionAgentKey, runCtx.activeRunId);
38478
+ }
38387
38479
  }
38388
38480
 
38389
38481
  // ../bridge/src/agents/acp/manager/handle-prompt.ts
@@ -38838,63 +38930,95 @@ function hashJsonUtf8Sha256(value) {
38838
38930
  return createHash("sha256").update(JSON.stringify(value), "utf8").digest("hex");
38839
38931
  }
38840
38932
 
38933
+ // ../bridge/src/sqlite/agent-capability-fields.ts
38934
+ function parseJsonArrayColumn(raw) {
38935
+ if (raw == null || raw === "") return null;
38936
+ try {
38937
+ const parsed = JSON.parse(raw);
38938
+ return Array.isArray(parsed) ? parsed : null;
38939
+ } catch {
38940
+ return null;
38941
+ }
38942
+ }
38943
+ function mergeAgentCapabilityFields(existing, patch) {
38944
+ return {
38945
+ configOptions: patch.configOptions !== void 0 ? patch.configOptions : existing.configOptions,
38946
+ availableCommands: patch.availableCommands !== void 0 ? patch.availableCommands : existing.availableCommands
38947
+ };
38948
+ }
38949
+
38950
+ // ../bridge/src/sqlite/list-cli-agent-capability-cache.ts
38951
+ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
38952
+ const rows = db.all(
38953
+ `SELECT agent_type, config_options_json, available_commands_json FROM agent_capabilities WHERE workspace_id = ?`,
38954
+ [workspaceId]
38955
+ );
38956
+ const out = [];
38957
+ for (const r of rows) {
38958
+ const configOptions = parseJsonArrayColumn(r.config_options_json) ?? [];
38959
+ const availableCommands = parseJsonArrayColumn(r.available_commands_json);
38960
+ if (configOptions.length === 0 && !(availableCommands && availableCommands.length > 0)) continue;
38961
+ out.push({ agentType: r.agent_type, configOptions, availableCommands });
38962
+ }
38963
+ return out;
38964
+ }
38965
+
38841
38966
  // ../bridge/src/sqlite/agent-capability-cache.ts
38842
- function hasNonEmptyAgentCapabilityCache(db, workspaceId, agentType) {
38843
- const t = agentType.trim();
38844
- if (!t) return false;
38967
+ function readExistingFields(db, workspaceId, agentType) {
38845
38968
  try {
38846
38969
  const row = db.get(
38847
- `SELECT config_options_json FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
38848
- [workspaceId, t]
38970
+ `SELECT config_options_json, available_commands_json, content_hash
38971
+ FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
38972
+ [workspaceId, agentType]
38849
38973
  );
38850
- if (row?.config_options_json == null || row.config_options_json === "") return false;
38851
- const parsed = JSON.parse(row.config_options_json);
38852
- return Array.isArray(parsed) && parsed.length > 0;
38974
+ if (!row) return { configOptions: null, availableCommands: null };
38975
+ return {
38976
+ configOptions: parseJsonArrayColumn(row.config_options_json),
38977
+ availableCommands: parseJsonArrayColumn(row.available_commands_json),
38978
+ contentHash: row.content_hash
38979
+ };
38853
38980
  } catch {
38854
- return false;
38981
+ return { configOptions: null, availableCommands: null };
38855
38982
  }
38856
38983
  }
38984
+ function hasNonEmptyAgentCapabilityCache(db, workspaceId, agentType) {
38985
+ const t = agentType.trim();
38986
+ if (!t) return false;
38987
+ const existing = readExistingFields(db, workspaceId, t);
38988
+ return Array.isArray(existing.configOptions) && existing.configOptions.length > 0;
38989
+ }
38857
38990
  function upsertCliAgentCapabilityCache(db, row) {
38858
38991
  const t = row.agentType.trim();
38859
38992
  if (!t) return false;
38860
- const hash2 = hashJsonUtf8Sha256(row.configOptions);
38861
- try {
38862
- const prev = db.get(
38863
- `SELECT content_hash FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
38864
- [row.workspaceId, t]
38865
- );
38866
- if (prev?.content_hash === hash2) return false;
38867
- } catch {
38868
- }
38869
- const json2 = JSON.stringify(row.configOptions);
38993
+ const existing = readExistingFields(db, row.workspaceId, t);
38994
+ const next = mergeAgentCapabilityFields(existing, row);
38995
+ if (!next.configOptions?.length && !next.availableCommands?.length) return false;
38996
+ const hash2 = hashJsonUtf8Sha256({
38997
+ configOptions: next.configOptions,
38998
+ availableCommands: next.availableCommands
38999
+ });
39000
+ if (existing.contentHash === hash2) return false;
38870
39001
  const now = (/* @__PURE__ */ new Date()).toISOString();
38871
39002
  db.run(
38872
- `INSERT INTO agent_capabilities (workspace_id, agent_type, config_options_json, content_hash, updated_at)
38873
- VALUES (?, ?, ?, ?, ?)
39003
+ `INSERT INTO agent_capabilities (
39004
+ workspace_id, agent_type, config_options_json, available_commands_json, content_hash, updated_at
39005
+ ) VALUES (?, ?, ?, ?, ?, ?)
38874
39006
  ON CONFLICT(workspace_id, agent_type) DO UPDATE SET
38875
39007
  config_options_json = excluded.config_options_json,
39008
+ available_commands_json = excluded.available_commands_json,
38876
39009
  content_hash = excluded.content_hash,
38877
39010
  updated_at = excluded.updated_at`,
38878
- [row.workspaceId, t, json2, hash2, now]
39011
+ [
39012
+ row.workspaceId,
39013
+ t,
39014
+ next.configOptions != null ? JSON.stringify(next.configOptions) : null,
39015
+ next.availableCommands != null ? JSON.stringify(next.availableCommands) : null,
39016
+ hash2,
39017
+ now
39018
+ ]
38879
39019
  );
38880
39020
  return true;
38881
39021
  }
38882
- function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
38883
- const rows = db.all(
38884
- `SELECT agent_type, config_options_json FROM agent_capabilities WHERE workspace_id = ?`,
38885
- [workspaceId]
38886
- );
38887
- const out = [];
38888
- for (const r of rows) {
38889
- try {
38890
- const parsed = JSON.parse(r.config_options_json);
38891
- if (!Array.isArray(parsed) || parsed.length === 0) continue;
38892
- out.push({ agentType: r.agent_type, configOptions: parsed });
38893
- } catch {
38894
- }
38895
- }
38896
- return out;
38897
- }
38898
39022
 
38899
39023
  // ../bridge/src/agents/capabilities/probe-agent-capabilities-for-types.ts
38900
39024
  init_cli_database();
@@ -39048,7 +39172,11 @@ async function warmupAgentCapabilitiesOnConnect(params) {
39048
39172
  if (!isCurrent() || rows.length === 0) return;
39049
39173
  sendWsMessage(socket, {
39050
39174
  type: "agent_capabilities_batch",
39051
- items: rows.map((r) => ({ agentType: r.agentType, configOptions: r.configOptions }))
39175
+ items: rows.map((r) => ({
39176
+ agentType: r.agentType,
39177
+ configOptions: r.configOptions,
39178
+ ...r.availableCommands != null ? { availableCommands: r.availableCommands } : {}
39179
+ }))
39052
39180
  });
39053
39181
  } catch (e) {
39054
39182
  if (e instanceof CliSqliteInterrupted) return;
@@ -39092,7 +39220,9 @@ init_cli_database();
39092
39220
  function createAgentCapabilitiesReporter(params) {
39093
39221
  const { workspaceId, getWs } = params;
39094
39222
  return (info) => {
39095
- if (!Array.isArray(info.configOptions) || info.configOptions.length === 0) return;
39223
+ const hasConfig = Array.isArray(info.configOptions) && info.configOptions.length > 0;
39224
+ const hasCommands = Array.isArray(info.availableCommands) && info.availableCommands.length > 0;
39225
+ if (!hasConfig && !hasCommands) return;
39096
39226
  setImmediate(() => {
39097
39227
  let changed = false;
39098
39228
  try {
@@ -39100,7 +39230,8 @@ function createAgentCapabilitiesReporter(params) {
39100
39230
  (db) => upsertCliAgentCapabilityCache(db, {
39101
39231
  workspaceId,
39102
39232
  agentType: info.agentType,
39103
- configOptions: info.configOptions
39233
+ ...hasConfig ? { configOptions: info.configOptions } : {},
39234
+ ...hasCommands ? { availableCommands: info.availableCommands } : {}
39104
39235
  })
39105
39236
  );
39106
39237
  } catch (e) {
@@ -39112,7 +39243,8 @@ function createAgentCapabilitiesReporter(params) {
39112
39243
  sendWsMessage(socket, {
39113
39244
  type: "agent_capabilities",
39114
39245
  agentType: info.agentType,
39115
- configOptions: info.configOptions
39246
+ ...hasConfig ? { configOptions: info.configOptions } : {},
39247
+ ...hasCommands ? { availableCommands: info.availableCommands } : {}
39116
39248
  });
39117
39249
  });
39118
39250
  };
@@ -40494,7 +40626,7 @@ function createBridgeHeartbeatController(params) {
40494
40626
  }
40495
40627
 
40496
40628
  // ../bridge/src/cli/cli-version.ts
40497
- var CLI_VERSION = "0.1.98".length > 0 ? "0.1.98" : "0.0.0-dev";
40629
+ var CLI_VERSION = "0.1.99".length > 0 ? "0.1.99" : "0.0.0-dev";
40498
40630
 
40499
40631
  // ../bridge/src/connection/identify/send-bridge-identify.ts
40500
40632
  function sendBridgeIdentify(ws, params) {
@@ -53572,7 +53704,7 @@ function createPendingAuthOnMessage(params) {
53572
53704
  }
53573
53705
 
53574
53706
  // src/cli-version.ts
53575
- var CLI_VERSION2 = "0.1.98".length > 0 ? "0.1.98" : "0.0.0-dev";
53707
+ var CLI_VERSION2 = "0.1.99".length > 0 ? "0.1.99" : "0.0.0-dev";
53576
53708
 
53577
53709
  // src/auth/pending/pending-auth-on-open.ts
53578
53710
  function createPendingAuthOnOpen(params) {