perchai-cli 2.4.15 → 2.4.17

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.
Files changed (2) hide show
  1. package/dist/perch.mjs +582 -345
  2. package/package.json +1 -1
package/dist/perch.mjs CHANGED
@@ -75566,6 +75566,7 @@ var init_payroll = __esm({
75566
75566
  // lib/perchBusinessTools/index.ts
75567
75567
  var init_perchBusinessTools = __esm({
75568
75568
  "lib/perchBusinessTools/index.ts"() {
75569
+ "use strict";
75569
75570
  init_generateAPAuditPacket();
75570
75571
  init_inventoryFolder();
75571
75572
  init_loadBusinessTables();
@@ -76004,7 +76005,188 @@ var init_userFacingErrors = __esm({
76004
76005
  }
76005
76006
  });
76006
76007
 
76007
- // lib/perchTerminal/toolDisplayNames.ts
76008
+ // features/perchTerminal/runtime/toolNames.ts
76009
+ var TOOL_NAMES, BROWSER_OPERATOR_TOOL_NAMES, BROWSER_RESEARCH_TOOL_NAMES, VERIFIED_SURFACE_SKILL_NAMES, DELIVERY_OPERATOR_TOOL_NAMES;
76010
+ var init_toolNames = __esm({
76011
+ "features/perchTerminal/runtime/toolNames.ts"() {
76012
+ "use strict";
76013
+ TOOL_NAMES = {
76014
+ // Desktop tools (require Perch AI Desktop; filesystem policy validates paths per call)
76015
+ validateWorkspaceRoot: "validateWorkspaceRoot",
76016
+ bash: "bash",
76017
+ runBashTerminalCommand: "runBashTerminalCommand",
76018
+ glob: "glob",
76019
+ grep: "grep",
76020
+ readLocalFile: "readLocalFile",
76021
+ writeLocalFile: "writeLocalFile",
76022
+ moveLocalFile: "moveLocalFile",
76023
+ copyLocalFile: "copyLocalFile",
76024
+ createDirectory: "createDirectory",
76025
+ deleteLocalFile: "deleteLocalFile",
76026
+ printFile: "printFile",
76027
+ editLocalFile: "editLocalFile",
76028
+ statPath: "statPath",
76029
+ prepareSandboxInputs: "prepareSandboxInputs",
76030
+ readProjectMemory: "readProjectMemory",
76031
+ saveToMemory: "saveToMemory",
76032
+ addProjectRule: "addProjectRule",
76033
+ writePerchManual: "writePerchManual",
76034
+ getProjectRules: "getProjectRules",
76035
+ listLocalSources: "listLocalSources",
76036
+ readLocalSourceFile: "readLocalSourceFile",
76037
+ generateAPAuditPacket: "generateAPAuditPacket",
76038
+ prepareAPEvidence: "prepare_ap_evidence",
76039
+ queryAPCases: "query_ap_cases",
76040
+ renderAPControlGraph: "render_ap_control_graph",
76041
+ runManagedPlaybook: "runManagedPlaybook",
76042
+ runSuite: "run_suite",
76043
+ listSuiteCatalog: "list_suite_catalog",
76044
+ proposeSuitePlan: "propose_suite_plan",
76045
+ executeSuitePlan: "execute_suite_plan",
76046
+ proposeWork: "propose_work",
76047
+ executeWork: "execute_work",
76048
+ sendWorkerMessage: "send_worker_message",
76049
+ taskStop: "task_stop",
76050
+ spawnWorker: "spawn_worker",
76051
+ dispatchAgent: "dispatch_agent",
76052
+ runSandboxAnalysis: "runSandboxAnalysis",
76053
+ runSandboxCode: "run_sandbox_code",
76054
+ safeBrowserAction: "safeBrowserAction",
76055
+ // Operator primitives — drive the browser turn-by-turn (observe→act). Each
76056
+ // result embeds a fresh accessibility snapshot + URL so the model re-observes
76057
+ // after every action. Clipboard-free: typing uses direct key events.
76058
+ browserNavigate: "browser_navigate",
76059
+ browserExecuteTask: "browser_execute_task",
76060
+ browserObserve: "browser_observe",
76061
+ browserClick: "browser_click",
76062
+ browserType: "browser_type",
76063
+ browserVisualClick: "browser_visual_click",
76064
+ browserFocusType: "browser_focus_type",
76065
+ browserPressKey: "browser_press_key",
76066
+ browserRead: "browser_read",
76067
+ browserWait: "browser_wait",
76068
+ browserHandleDialog: "browser_handle_dialog",
76069
+ // Browser research tools — higher-level web research through the browser operator
76070
+ browserSearchWeb: "browser_search_web",
76071
+ browserReadPage: "browser_read_page",
76072
+ browserCollectSources: "browser_collect_sources",
76073
+ gmailSendEmail: "gmail_send_email",
76074
+ gmailSaveDraft: "gmail_save_draft",
76075
+ googleDocsCreate: "google_docs_create",
76076
+ googleDocsAppend: "google_docs_append",
76077
+ googleCalendarCreateEvent: "google_calendar_create_event",
76078
+ googleSheetsCreate: "google_sheets_create",
76079
+ googleSheetsAppendRows: "google_sheets_append_rows",
76080
+ // Verified surface skills — optional shortcuts for Google Workspace delivery.
76081
+ // Operator-first workers default to browser primitives and may use these
76082
+ // adapter wrappers once when they can return proof-based receipt verification.
76083
+ gmailSendEmailVerified: "gmail_send_email_verified",
76084
+ gmailSaveDraftVerified: "gmail_save_draft_verified",
76085
+ googleDocsCreateVerified: "google_docs_create_verified",
76086
+ googleCalendarCreateEventVerified: "google_calendar_create_event_verified",
76087
+ // Market desk tools (flag-gated: PERCH_MARKET_DESK=1)
76088
+ getMarketSignal: "get_market_signal",
76089
+ queryMarketSignalLog: "query_market_signal_log",
76090
+ explainMarketSignal: "explain_market_signal",
76091
+ listMarketStrategies: "list_market_strategies",
76092
+ runMarketBacktest: "run_market_backtest",
76093
+ getMarketTrackRecord: "get_market_track_record",
76094
+ // Native tools (always available; executed locally without Desktop bridge)
76095
+ ctxInspect: "ctxInspect",
76096
+ toolSearch: "toolSearch",
76097
+ configInspect: "configInspect",
76098
+ syntheticOutput: "syntheticOutput",
76099
+ todoWrite: "todoWrite",
76100
+ askUserQuestion: "askUserQuestion",
76101
+ proposePlan: "propose_plan",
76102
+ enterPlanMode: "enterPlanMode",
76103
+ exitPlanMode: "exitPlanMode",
76104
+ brief: "brief",
76105
+ listMcpServers: "listMcpServers",
76106
+ searchKnowledge: "searchKnowledge",
76107
+ // Unavailable tools (not executable in Perch Terminal Desktop; Supabase/web/sandbox)
76108
+ listSources: "listSources",
76109
+ readSource: "readSource",
76110
+ analyzeWorkbook: "analyzeWorkbook",
76111
+ extractDocument: "extractDocument",
76112
+ searchSources: "searchSources",
76113
+ semanticSearch: "semanticSearch",
76114
+ retrieveContext: "retrieveContext",
76115
+ diagnoseWorkspaceAccess: "diagnoseWorkspaceAccess",
76116
+ listIndexedSources: "listIndexedSources",
76117
+ searchWorkspaceSources: "searchWorkspaceSources",
76118
+ resolveSourceCandidates: "resolveSourceCandidates",
76119
+ inspectDocument: "inspectDocument",
76120
+ visionInspect: "visionInspect",
76121
+ extractDocumentSection: "extractDocumentSection",
76122
+ inspectWorkbookSheets: "inspectWorkbookSheets",
76123
+ compareEvidenceAcrossSources: "compareEvidenceAcrossSources",
76124
+ listArtifacts: "listArtifacts",
76125
+ webSearch: "webSearch",
76126
+ webFetch: "webFetch",
76127
+ scholarSearch: "scholarSearch",
76128
+ runLocalCommand: "runLocalCommand",
76129
+ createTextArtifact: "createTextArtifact",
76130
+ createDocumentArtifact: "createDocumentArtifact",
76131
+ artifactCapabilityReport: "artifactCapabilityReport",
76132
+ writingEnvironmentCheck: "writingEnvironmentCheck"
76133
+ };
76134
+ BROWSER_OPERATOR_TOOL_NAMES = [
76135
+ TOOL_NAMES.browserNavigate,
76136
+ TOOL_NAMES.browserExecuteTask,
76137
+ TOOL_NAMES.browserObserve,
76138
+ TOOL_NAMES.browserClick,
76139
+ TOOL_NAMES.browserType,
76140
+ TOOL_NAMES.browserVisualClick,
76141
+ TOOL_NAMES.browserFocusType,
76142
+ TOOL_NAMES.browserPressKey,
76143
+ TOOL_NAMES.browserRead,
76144
+ TOOL_NAMES.browserWait,
76145
+ TOOL_NAMES.browserHandleDialog
76146
+ ];
76147
+ BROWSER_RESEARCH_TOOL_NAMES = [
76148
+ TOOL_NAMES.browserSearchWeb,
76149
+ TOOL_NAMES.browserReadPage,
76150
+ TOOL_NAMES.browserCollectSources
76151
+ ];
76152
+ VERIFIED_SURFACE_SKILL_NAMES = [
76153
+ TOOL_NAMES.gmailSendEmailVerified,
76154
+ TOOL_NAMES.gmailSaveDraftVerified,
76155
+ TOOL_NAMES.googleDocsCreateVerified,
76156
+ TOOL_NAMES.googleCalendarCreateEventVerified
76157
+ ];
76158
+ DELIVERY_OPERATOR_TOOL_NAMES = [
76159
+ ...BROWSER_OPERATOR_TOOL_NAMES,
76160
+ ...VERIFIED_SURFACE_SKILL_NAMES
76161
+ ];
76162
+ }
76163
+ });
76164
+
76165
+ // features/perchTerminal/runtime/toolSystem/catalog.ts
76166
+ function isEnabledToolName(name) {
76167
+ return Object.values(TOOL_NAMES).includes(name);
76168
+ }
76169
+ function getToolRiskLevel(name) {
76170
+ if (!isEnabledToolName(name)) return null;
76171
+ return TOOL_RISK[name];
76172
+ }
76173
+ function getCatalogToolOwner(name) {
76174
+ if (!isEnabledToolName(name)) return null;
76175
+ return NON_MODULE_TOOL_OWNERS[name] ?? "module";
76176
+ }
76177
+ function getToolCatalogEntry(name) {
76178
+ if (!isEnabledToolName(name)) return null;
76179
+ const owner = getCatalogToolOwner(name);
76180
+ if (!owner) return null;
76181
+ const riskLevel = getToolRiskLevel(name);
76182
+ if (!riskLevel) return null;
76183
+ return {
76184
+ name,
76185
+ owner,
76186
+ riskLevel,
76187
+ displayName: getToolDisplayName(name)
76188
+ };
76189
+ }
76008
76190
  function humanizeToolSlug(toolName) {
76009
76191
  const stripped = toolName.replace(/^mcp__[^_]+__/, "");
76010
76192
  if (stripped !== toolName) {
@@ -76012,14 +76194,150 @@ function humanizeToolSlug(toolName) {
76012
76194
  }
76013
76195
  return toolName.replace(/_/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
76014
76196
  }
76015
- function displayToolName(toolName) {
76197
+ function getToolDisplayName(toolName) {
76016
76198
  return TOOL_DISPLAY_NAMES[toolName] ?? humanizeToolSlug(toolName);
76017
76199
  }
76018
- var TOOL_DISPLAY_NAMES;
76019
- var init_toolDisplayNames = __esm({
76020
- "lib/perchTerminal/toolDisplayNames.ts"() {
76200
+ var NON_MODULE_TOOL_OWNERS, TOOL_RISK, TOOL_DISPLAY_NAMES;
76201
+ var init_catalog = __esm({
76202
+ "features/perchTerminal/runtime/toolSystem/catalog.ts"() {
76203
+ init_toolNames();
76204
+ NON_MODULE_TOOL_OWNERS = {
76205
+ [TOOL_NAMES.listSources]: "lane",
76206
+ [TOOL_NAMES.readSource]: "lane",
76207
+ [TOOL_NAMES.searchSources]: "lane",
76208
+ [TOOL_NAMES.semanticSearch]: "lane",
76209
+ [TOOL_NAMES.retrieveContext]: "lane",
76210
+ [TOOL_NAMES.diagnoseWorkspaceAccess]: "lane",
76211
+ [TOOL_NAMES.listIndexedSources]: "lane",
76212
+ [TOOL_NAMES.searchWorkspaceSources]: "lane",
76213
+ [TOOL_NAMES.resolveSourceCandidates]: "lane",
76214
+ [TOOL_NAMES.webSearch]: "lane",
76215
+ [TOOL_NAMES.webFetch]: "lane",
76216
+ [TOOL_NAMES.scholarSearch]: "lane",
76217
+ [TOOL_NAMES.analyzeWorkbook]: "external",
76218
+ [TOOL_NAMES.extractDocument]: "external",
76219
+ [TOOL_NAMES.inspectDocument]: "external",
76220
+ [TOOL_NAMES.extractDocumentSection]: "external",
76221
+ [TOOL_NAMES.inspectWorkbookSheets]: "external",
76222
+ [TOOL_NAMES.compareEvidenceAcrossSources]: "external",
76223
+ [TOOL_NAMES.listArtifacts]: "external",
76224
+ [TOOL_NAMES.runLocalCommand]: "external",
76225
+ [TOOL_NAMES.createTextArtifact]: "external",
76226
+ [TOOL_NAMES.createDocumentArtifact]: "external",
76227
+ [TOOL_NAMES.artifactCapabilityReport]: "external",
76228
+ [TOOL_NAMES.writingEnvironmentCheck]: "external"
76229
+ };
76230
+ TOOL_RISK = {
76231
+ [TOOL_NAMES.validateWorkspaceRoot]: "read",
76232
+ [TOOL_NAMES.bash]: "command",
76233
+ [TOOL_NAMES.runBashTerminalCommand]: "command",
76234
+ [TOOL_NAMES.glob]: "read",
76235
+ [TOOL_NAMES.grep]: "read",
76236
+ [TOOL_NAMES.readLocalFile]: "read",
76237
+ [TOOL_NAMES.writeLocalFile]: "write",
76238
+ [TOOL_NAMES.moveLocalFile]: "write",
76239
+ [TOOL_NAMES.copyLocalFile]: "write",
76240
+ [TOOL_NAMES.createDirectory]: "write",
76241
+ [TOOL_NAMES.deleteLocalFile]: "write",
76242
+ [TOOL_NAMES.printFile]: "write",
76243
+ [TOOL_NAMES.editLocalFile]: "write",
76244
+ [TOOL_NAMES.statPath]: "read",
76245
+ [TOOL_NAMES.prepareSandboxInputs]: "read",
76246
+ [TOOL_NAMES.readProjectMemory]: "read",
76247
+ [TOOL_NAMES.saveToMemory]: "write",
76248
+ [TOOL_NAMES.addProjectRule]: "write",
76249
+ [TOOL_NAMES.writePerchManual]: "write",
76250
+ [TOOL_NAMES.getProjectRules]: "read",
76251
+ [TOOL_NAMES.listLocalSources]: "read",
76252
+ [TOOL_NAMES.readLocalSourceFile]: "read",
76253
+ [TOOL_NAMES.generateAPAuditPacket]: "command",
76254
+ [TOOL_NAMES.prepareAPEvidence]: "command",
76255
+ [TOOL_NAMES.queryAPCases]: "read",
76256
+ [TOOL_NAMES.renderAPControlGraph]: "read",
76257
+ [TOOL_NAMES.runManagedPlaybook]: "command",
76258
+ [TOOL_NAMES.runSuite]: "command",
76259
+ [TOOL_NAMES.listSuiteCatalog]: "read",
76260
+ [TOOL_NAMES.proposeSuitePlan]: "command",
76261
+ [TOOL_NAMES.executeSuitePlan]: "command",
76262
+ [TOOL_NAMES.proposeWork]: "command",
76263
+ [TOOL_NAMES.executeWork]: "command",
76264
+ [TOOL_NAMES.sendWorkerMessage]: "command",
76265
+ [TOOL_NAMES.taskStop]: "command",
76266
+ [TOOL_NAMES.spawnWorker]: "command",
76267
+ [TOOL_NAMES.dispatchAgent]: "command",
76268
+ [TOOL_NAMES.runSandboxAnalysis]: "command",
76269
+ [TOOL_NAMES.runSandboxCode]: "command",
76270
+ [TOOL_NAMES.safeBrowserAction]: "write",
76271
+ [TOOL_NAMES.browserNavigate]: "write",
76272
+ [TOOL_NAMES.browserExecuteTask]: "write",
76273
+ [TOOL_NAMES.browserObserve]: "read",
76274
+ [TOOL_NAMES.browserClick]: "write",
76275
+ [TOOL_NAMES.browserType]: "write",
76276
+ [TOOL_NAMES.browserVisualClick]: "write",
76277
+ [TOOL_NAMES.browserFocusType]: "write",
76278
+ [TOOL_NAMES.browserPressKey]: "write",
76279
+ [TOOL_NAMES.browserRead]: "read",
76280
+ [TOOL_NAMES.browserWait]: "read",
76281
+ [TOOL_NAMES.browserHandleDialog]: "write",
76282
+ [TOOL_NAMES.browserSearchWeb]: "read",
76283
+ [TOOL_NAMES.browserReadPage]: "read",
76284
+ [TOOL_NAMES.browserCollectSources]: "read",
76285
+ [TOOL_NAMES.gmailSendEmail]: "write",
76286
+ [TOOL_NAMES.gmailSaveDraft]: "write",
76287
+ [TOOL_NAMES.googleDocsCreate]: "write",
76288
+ [TOOL_NAMES.googleDocsAppend]: "write",
76289
+ [TOOL_NAMES.googleCalendarCreateEvent]: "write",
76290
+ [TOOL_NAMES.googleSheetsCreate]: "write",
76291
+ [TOOL_NAMES.googleSheetsAppendRows]: "write",
76292
+ [TOOL_NAMES.gmailSendEmailVerified]: "write",
76293
+ [TOOL_NAMES.gmailSaveDraftVerified]: "write",
76294
+ [TOOL_NAMES.googleDocsCreateVerified]: "write",
76295
+ [TOOL_NAMES.googleCalendarCreateEventVerified]: "write",
76296
+ [TOOL_NAMES.getMarketSignal]: "read",
76297
+ [TOOL_NAMES.queryMarketSignalLog]: "read",
76298
+ [TOOL_NAMES.explainMarketSignal]: "read",
76299
+ [TOOL_NAMES.listMarketStrategies]: "read",
76300
+ [TOOL_NAMES.runMarketBacktest]: "command",
76301
+ [TOOL_NAMES.getMarketTrackRecord]: "read",
76302
+ [TOOL_NAMES.ctxInspect]: "read",
76303
+ [TOOL_NAMES.toolSearch]: "read",
76304
+ [TOOL_NAMES.configInspect]: "read",
76305
+ [TOOL_NAMES.syntheticOutput]: "read",
76306
+ [TOOL_NAMES.todoWrite]: "read",
76307
+ [TOOL_NAMES.askUserQuestion]: "read",
76308
+ [TOOL_NAMES.proposePlan]: "read",
76309
+ [TOOL_NAMES.enterPlanMode]: "read",
76310
+ [TOOL_NAMES.exitPlanMode]: "read",
76311
+ [TOOL_NAMES.brief]: "read",
76312
+ [TOOL_NAMES.listMcpServers]: "read",
76313
+ [TOOL_NAMES.searchKnowledge]: "read",
76314
+ [TOOL_NAMES.listSources]: "read",
76315
+ [TOOL_NAMES.readSource]: "read",
76316
+ [TOOL_NAMES.analyzeWorkbook]: "read",
76317
+ [TOOL_NAMES.extractDocument]: "read",
76318
+ [TOOL_NAMES.searchSources]: "read",
76319
+ [TOOL_NAMES.semanticSearch]: "read",
76320
+ [TOOL_NAMES.retrieveContext]: "read",
76321
+ [TOOL_NAMES.diagnoseWorkspaceAccess]: "read",
76322
+ [TOOL_NAMES.listIndexedSources]: "read",
76323
+ [TOOL_NAMES.searchWorkspaceSources]: "read",
76324
+ [TOOL_NAMES.resolveSourceCandidates]: "read",
76325
+ [TOOL_NAMES.inspectDocument]: "read",
76326
+ [TOOL_NAMES.visionInspect]: "read",
76327
+ [TOOL_NAMES.extractDocumentSection]: "read",
76328
+ [TOOL_NAMES.inspectWorkbookSheets]: "read",
76329
+ [TOOL_NAMES.compareEvidenceAcrossSources]: "read",
76330
+ [TOOL_NAMES.listArtifacts]: "read",
76331
+ [TOOL_NAMES.webSearch]: "read",
76332
+ [TOOL_NAMES.webFetch]: "read",
76333
+ [TOOL_NAMES.scholarSearch]: "read",
76334
+ [TOOL_NAMES.runLocalCommand]: "command",
76335
+ [TOOL_NAMES.createTextArtifact]: "write",
76336
+ [TOOL_NAMES.createDocumentArtifact]: "write",
76337
+ [TOOL_NAMES.artifactCapabilityReport]: "read",
76338
+ [TOOL_NAMES.writingEnvironmentCheck]: "read"
76339
+ };
76021
76340
  TOOL_DISPLAY_NAMES = {
76022
- // ── Desktop / workspace ─────────────────────────────────────────────────────
76023
76341
  validateWorkspaceRoot: "Local folder access",
76024
76342
  bash: "Shell command",
76025
76343
  runBashTerminalCommand: "Terminal command",
@@ -76049,7 +76367,6 @@ var init_toolDisplayNames = __esm({
76049
76367
  query_ap_cases: "Query AP cases",
76050
76368
  render_ap_control_graph: "Render AP graph",
76051
76369
  runSandboxAnalysis: "Sandbox analysis",
76052
- // ── Workflows & specialists ───────────────────────────────────────────────
76053
76370
  run_suite: "Run workflow suite",
76054
76371
  list_suite_catalog: "Browse workflows",
76055
76372
  propose_suite_plan: "Propose workflow plan",
@@ -76061,7 +76378,6 @@ var init_toolDisplayNames = __esm({
76061
76378
  spawn_worker: "Run specialist",
76062
76379
  send_worker_message: "Message specialist",
76063
76380
  task_stop: "Stop specialist",
76064
- // ── Native / meta ─────────────────────────────────────────────────────────
76065
76381
  ctxInspect: "Inspect context",
76066
76382
  toolSearch: "Search tools",
76067
76383
  configInspect: "Inspect config",
@@ -76073,7 +76389,6 @@ var init_toolDisplayNames = __esm({
76073
76389
  exitPlanMode: "Exit plan mode",
76074
76390
  brief: "Brief",
76075
76391
  listMcpServers: "List integrations",
76076
- // ── Sources & retrieval (web / indexed) ───────────────────────────────────
76077
76392
  listSources: "List sources",
76078
76393
  readSource: "Read source",
76079
76394
  analyzeWorkbook: "Analyze workbook",
@@ -76099,7 +76414,6 @@ var init_toolDisplayNames = __esm({
76099
76414
  createDocumentArtifact: "Create document",
76100
76415
  artifactCapabilityReport: "Artifact capabilities",
76101
76416
  writingEnvironmentCheck: "Writing environment",
76102
- // ── Playwright Google Workspace adapters ─────────────────────────────────
76103
76417
  safeBrowserAction: "Browser action",
76104
76418
  browser_navigate: "Open page",
76105
76419
  browser_execute_task: "Browser task",
@@ -76126,7 +76440,12 @@ var init_toolDisplayNames = __esm({
76126
76440
  google_calendar_create_event: "Create calendar event",
76127
76441
  google_sheets_create: "Create Google Sheet",
76128
76442
  google_sheets_append_rows: "Append to Google Sheet",
76129
- // ── Playwright MCP ────────────────────────────────────────────────────────
76443
+ get_market_signal: "Reading market signal",
76444
+ query_market_signal_log: "Querying signal log",
76445
+ explain_market_signal: "Explaining signal",
76446
+ list_market_strategies: "Listing strategies",
76447
+ run_market_backtest: "Running backtest",
76448
+ get_market_track_record: "Computing track record",
76130
76449
  "mcp__playwright__browser_navigate": "Open page",
76131
76450
  "mcp__playwright__browser_snapshot": "Read page",
76132
76451
  "mcp__playwright__browser_click": "Click",
@@ -76145,7 +76464,6 @@ var init_toolDisplayNames = __esm({
76145
76464
  "mcp__playwright__browser_fill_form": "Fill form",
76146
76465
  "mcp__playwright__browser_press_key": "Keyboard",
76147
76466
  "mcp__playwright__browser_resize": "Resize window",
76148
- // ── CourtListener MCP ─────────────────────────────────────────────────────
76149
76467
  "mcp__courtlistener__search_cases_by_problem": "Searching case law",
76150
76468
  "mcp__courtlistener__search_cases": "Searching case law",
76151
76469
  "mcp__courtlistener__search_opinions": "Searching case law",
@@ -76160,19 +76478,18 @@ var init_toolDisplayNames = __esm({
76160
76478
  "mcp__courtlistener__lookup_citation": "Looking up citation",
76161
76479
  "mcp__courtlistener__validate_citations": "Verifying legal citations",
76162
76480
  "mcp__courtlistener__courtlistener_verify_citation": "Verifying legal citations",
76163
- // ── Market desk ──────────────────────────────────────────────────────────
76164
- get_market_signal: "Reading market signal",
76165
- query_market_signal_log: "Querying signal log",
76166
- explain_market_signal: "Explaining signal",
76167
- list_market_strategies: "Listing strategies",
76168
- run_market_backtest: "Running backtest",
76169
- get_market_track_record: "Computing track record",
76170
- // ── Future MCP slots (route to GenericCard until dedicated cards ship) ───
76171
76481
  "mcp__slack__post_message": "Post Slack message"
76172
76482
  };
76173
76483
  }
76174
76484
  });
76175
76485
 
76486
+ // lib/perchTerminal/toolDisplayNames.ts
76487
+ var init_toolDisplayNames = __esm({
76488
+ "lib/perchTerminal/toolDisplayNames.ts"() {
76489
+ init_catalog();
76490
+ }
76491
+ });
76492
+
76176
76493
  // features/perchTerminal/runtime/toolCallNormalizer.ts
76177
76494
  function normalizeToolCalls(modelResponse) {
76178
76495
  const calls = [];
@@ -77231,7 +77548,7 @@ function buildTranscriptSegments(state) {
77231
77548
  segments.push({
77232
77549
  kind: "executor_event",
77233
77550
  label: ev.title,
77234
- detail: ev.toolName ? `Started ${displayToolName(ev.toolName)}` : "Started",
77551
+ detail: ev.toolName ? `Started ${getToolDisplayName(ev.toolName)}` : "Started",
77235
77552
  status: "running",
77236
77553
  seq: seq++,
77237
77554
  timestamp: ev.ts
@@ -77243,7 +77560,7 @@ function buildTranscriptSegments(state) {
77243
77560
  segments.push({
77244
77561
  kind: "executor_event",
77245
77562
  label: ev.title,
77246
- detail: ev.resultSummary ?? (ev.toolName ? `Completed ${displayToolName(ev.toolName)}` : "Completed"),
77563
+ detail: ev.resultSummary ?? (ev.toolName ? `Completed ${getToolDisplayName(ev.toolName)}` : "Completed"),
77247
77564
  status: "completed",
77248
77565
  seq: seq++,
77249
77566
  timestamp: ev.ts
@@ -81350,163 +81667,6 @@ Tool strengths:
81350
81667
  }
81351
81668
  });
81352
81669
 
81353
- // features/perchTerminal/runtime/toolNames.ts
81354
- var TOOL_NAMES, BROWSER_OPERATOR_TOOL_NAMES, BROWSER_RESEARCH_TOOL_NAMES, VERIFIED_SURFACE_SKILL_NAMES, DELIVERY_OPERATOR_TOOL_NAMES;
81355
- var init_toolNames = __esm({
81356
- "features/perchTerminal/runtime/toolNames.ts"() {
81357
- "use strict";
81358
- TOOL_NAMES = {
81359
- // Desktop tools (require Perch AI Desktop; filesystem policy validates paths per call)
81360
- validateWorkspaceRoot: "validateWorkspaceRoot",
81361
- bash: "bash",
81362
- runBashTerminalCommand: "runBashTerminalCommand",
81363
- glob: "glob",
81364
- grep: "grep",
81365
- readLocalFile: "readLocalFile",
81366
- writeLocalFile: "writeLocalFile",
81367
- moveLocalFile: "moveLocalFile",
81368
- copyLocalFile: "copyLocalFile",
81369
- createDirectory: "createDirectory",
81370
- deleteLocalFile: "deleteLocalFile",
81371
- printFile: "printFile",
81372
- editLocalFile: "editLocalFile",
81373
- statPath: "statPath",
81374
- prepareSandboxInputs: "prepareSandboxInputs",
81375
- readProjectMemory: "readProjectMemory",
81376
- saveToMemory: "saveToMemory",
81377
- addProjectRule: "addProjectRule",
81378
- writePerchManual: "writePerchManual",
81379
- getProjectRules: "getProjectRules",
81380
- listLocalSources: "listLocalSources",
81381
- readLocalSourceFile: "readLocalSourceFile",
81382
- generateAPAuditPacket: "generateAPAuditPacket",
81383
- prepareAPEvidence: "prepare_ap_evidence",
81384
- queryAPCases: "query_ap_cases",
81385
- renderAPControlGraph: "render_ap_control_graph",
81386
- runManagedPlaybook: "runManagedPlaybook",
81387
- runSuite: "run_suite",
81388
- listSuiteCatalog: "list_suite_catalog",
81389
- proposeSuitePlan: "propose_suite_plan",
81390
- executeSuitePlan: "execute_suite_plan",
81391
- proposeWork: "propose_work",
81392
- executeWork: "execute_work",
81393
- sendWorkerMessage: "send_worker_message",
81394
- taskStop: "task_stop",
81395
- spawnWorker: "spawn_worker",
81396
- dispatchAgent: "dispatch_agent",
81397
- runSandboxAnalysis: "runSandboxAnalysis",
81398
- runSandboxCode: "run_sandbox_code",
81399
- safeBrowserAction: "safeBrowserAction",
81400
- // Operator primitives — drive the browser turn-by-turn (observe→act). Each
81401
- // result embeds a fresh accessibility snapshot + URL so the model re-observes
81402
- // after every action. Clipboard-free: typing uses direct key events.
81403
- browserNavigate: "browser_navigate",
81404
- browserExecuteTask: "browser_execute_task",
81405
- browserObserve: "browser_observe",
81406
- browserClick: "browser_click",
81407
- browserType: "browser_type",
81408
- browserVisualClick: "browser_visual_click",
81409
- browserFocusType: "browser_focus_type",
81410
- browserPressKey: "browser_press_key",
81411
- browserRead: "browser_read",
81412
- browserWait: "browser_wait",
81413
- browserHandleDialog: "browser_handle_dialog",
81414
- // Browser research tools — higher-level web research through the browser operator
81415
- browserSearchWeb: "browser_search_web",
81416
- browserReadPage: "browser_read_page",
81417
- browserCollectSources: "browser_collect_sources",
81418
- gmailSendEmail: "gmail_send_email",
81419
- gmailSaveDraft: "gmail_save_draft",
81420
- googleDocsCreate: "google_docs_create",
81421
- googleDocsAppend: "google_docs_append",
81422
- googleCalendarCreateEvent: "google_calendar_create_event",
81423
- googleSheetsCreate: "google_sheets_create",
81424
- googleSheetsAppendRows: "google_sheets_append_rows",
81425
- // Verified surface skills — optional shortcuts for Google Workspace delivery.
81426
- // Operator-first workers default to browser primitives and may use these
81427
- // adapter wrappers once when they can return proof-based receipt verification.
81428
- gmailSendEmailVerified: "gmail_send_email_verified",
81429
- gmailSaveDraftVerified: "gmail_save_draft_verified",
81430
- googleDocsCreateVerified: "google_docs_create_verified",
81431
- googleCalendarCreateEventVerified: "google_calendar_create_event_verified",
81432
- // Market desk tools (flag-gated: PERCH_MARKET_DESK=1)
81433
- getMarketSignal: "get_market_signal",
81434
- queryMarketSignalLog: "query_market_signal_log",
81435
- explainMarketSignal: "explain_market_signal",
81436
- listMarketStrategies: "list_market_strategies",
81437
- runMarketBacktest: "run_market_backtest",
81438
- getMarketTrackRecord: "get_market_track_record",
81439
- // Native tools (always available; executed locally without Desktop bridge)
81440
- ctxInspect: "ctxInspect",
81441
- toolSearch: "toolSearch",
81442
- configInspect: "configInspect",
81443
- syntheticOutput: "syntheticOutput",
81444
- todoWrite: "todoWrite",
81445
- askUserQuestion: "askUserQuestion",
81446
- proposePlan: "propose_plan",
81447
- enterPlanMode: "enterPlanMode",
81448
- exitPlanMode: "exitPlanMode",
81449
- brief: "brief",
81450
- listMcpServers: "listMcpServers",
81451
- searchKnowledge: "searchKnowledge",
81452
- // Unavailable tools (not executable in Perch Terminal Desktop; Supabase/web/sandbox)
81453
- listSources: "listSources",
81454
- readSource: "readSource",
81455
- analyzeWorkbook: "analyzeWorkbook",
81456
- extractDocument: "extractDocument",
81457
- searchSources: "searchSources",
81458
- semanticSearch: "semanticSearch",
81459
- retrieveContext: "retrieveContext",
81460
- diagnoseWorkspaceAccess: "diagnoseWorkspaceAccess",
81461
- listIndexedSources: "listIndexedSources",
81462
- searchWorkspaceSources: "searchWorkspaceSources",
81463
- resolveSourceCandidates: "resolveSourceCandidates",
81464
- inspectDocument: "inspectDocument",
81465
- visionInspect: "visionInspect",
81466
- extractDocumentSection: "extractDocumentSection",
81467
- inspectWorkbookSheets: "inspectWorkbookSheets",
81468
- compareEvidenceAcrossSources: "compareEvidenceAcrossSources",
81469
- listArtifacts: "listArtifacts",
81470
- webSearch: "webSearch",
81471
- webFetch: "webFetch",
81472
- scholarSearch: "scholarSearch",
81473
- runLocalCommand: "runLocalCommand",
81474
- createTextArtifact: "createTextArtifact",
81475
- createDocumentArtifact: "createDocumentArtifact",
81476
- artifactCapabilityReport: "artifactCapabilityReport",
81477
- writingEnvironmentCheck: "writingEnvironmentCheck"
81478
- };
81479
- BROWSER_OPERATOR_TOOL_NAMES = [
81480
- TOOL_NAMES.browserNavigate,
81481
- TOOL_NAMES.browserExecuteTask,
81482
- TOOL_NAMES.browserObserve,
81483
- TOOL_NAMES.browserClick,
81484
- TOOL_NAMES.browserType,
81485
- TOOL_NAMES.browserVisualClick,
81486
- TOOL_NAMES.browserFocusType,
81487
- TOOL_NAMES.browserPressKey,
81488
- TOOL_NAMES.browserRead,
81489
- TOOL_NAMES.browserWait,
81490
- TOOL_NAMES.browserHandleDialog
81491
- ];
81492
- BROWSER_RESEARCH_TOOL_NAMES = [
81493
- TOOL_NAMES.browserSearchWeb,
81494
- TOOL_NAMES.browserReadPage,
81495
- TOOL_NAMES.browserCollectSources
81496
- ];
81497
- VERIFIED_SURFACE_SKILL_NAMES = [
81498
- TOOL_NAMES.gmailSendEmailVerified,
81499
- TOOL_NAMES.gmailSaveDraftVerified,
81500
- TOOL_NAMES.googleDocsCreateVerified,
81501
- TOOL_NAMES.googleCalendarCreateEventVerified
81502
- ];
81503
- DELIVERY_OPERATOR_TOOL_NAMES = [
81504
- ...BROWSER_OPERATOR_TOOL_NAMES,
81505
- ...VERIFIED_SURFACE_SKILL_NAMES
81506
- ];
81507
- }
81508
- });
81509
-
81510
81670
  // features/perchTerminal/runtime/marketDesk/marketDeskAccess.ts
81511
81671
  function isMarketDeskEnabled() {
81512
81672
  return process.env.PERCH_MARKET_DESK === "1";
@@ -130788,24 +130948,36 @@ async function callModelRouterViaServer(request, opts, endpoint = "/api/perch-te
130788
130948
  signal: _signal,
130789
130949
  ...serializableRequest
130790
130950
  } = request;
130791
- const response = await fetch(endpoint, {
130951
+ const body = JSON.stringify({
130952
+ request: serializableRequest,
130953
+ runId: opts?.runId,
130954
+ lane: opts?.lane ?? "chat",
130955
+ strictManual: opts?.strictManual ?? false,
130956
+ raceMode: opts?.raceMode,
130957
+ preferredModelId: opts?.preferredModelId ?? null,
130958
+ avoidModelIds: opts?.avoidModelIds ?? [],
130959
+ attribution: opts?.attribution ?? null
130960
+ });
130961
+ const response = await fetchModelProxyWithRetry(endpoint, {
130792
130962
  method: "POST",
130793
130963
  headers: {
130794
130964
  "Content-Type": "application/json",
130795
130965
  ...hasStreamingHandler ? { Accept: "text/event-stream" } : {},
130796
130966
  ...nodeModelProxyAuthHeader()
130797
130967
  },
130798
- body: JSON.stringify({
130799
- request: serializableRequest,
130800
- runId: opts?.runId,
130801
- lane: opts?.lane ?? "chat",
130802
- strictManual: opts?.strictManual ?? false,
130803
- raceMode: opts?.raceMode,
130804
- preferredModelId: opts?.preferredModelId ?? null,
130805
- avoidModelIds: opts?.avoidModelIds ?? [],
130806
- attribution: opts?.attribution ?? null
130807
- }),
130968
+ body,
130808
130969
  signal: _signal
130970
+ }, {
130971
+ onRetry: (attempt, statusOrError) => {
130972
+ onStreamEvent?.({
130973
+ type: "model_call_failed",
130974
+ provider: "model_proxy",
130975
+ modelId: "app-proxy",
130976
+ lane: opts?.lane ?? "chat",
130977
+ error: `Model proxy retry ${attempt + 1}/${MODEL_PROXY_MAX_ATTEMPTS}: ${statusOrError}`,
130978
+ errorCategory: "proxy_transient"
130979
+ });
130980
+ }
130809
130981
  });
130810
130982
  if (!hasStreamingHandler) {
130811
130983
  return await response.json();
@@ -130913,6 +131085,46 @@ async function callModelRouterViaServer(request, opts, endpoint = "/api/perch-te
130913
131085
  durationMs: 0
130914
131086
  };
130915
131087
  }
131088
+ async function fetchModelProxyWithRetry(endpoint, init, options) {
131089
+ const maxAttempts = Math.max(1, options?.maxAttempts ?? MODEL_PROXY_MAX_ATTEMPTS);
131090
+ let lastError = null;
131091
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
131092
+ try {
131093
+ const response = await fetch(endpoint, init);
131094
+ if (!isRetriableModelProxyStatus(response.status) || attempt === maxAttempts - 1) {
131095
+ return response;
131096
+ }
131097
+ options?.onRetry?.(attempt, `HTTP ${response.status}`);
131098
+ await response.body?.cancel().catch(() => void 0);
131099
+ await waitForModelProxyRetry(attempt, init.signal);
131100
+ } catch (error) {
131101
+ if (isAbortLikeError(error) || attempt === maxAttempts - 1) throw error;
131102
+ lastError = error;
131103
+ options?.onRetry?.(attempt, error instanceof Error ? error.message : String(error));
131104
+ await waitForModelProxyRetry(attempt, init.signal);
131105
+ }
131106
+ }
131107
+ throw lastError instanceof Error ? lastError : new Error(String(lastError ?? "Model proxy request failed"));
131108
+ }
131109
+ function isRetriableModelProxyStatus(status) {
131110
+ return status === 408 || status === 425 || status >= 500 && status <= 599;
131111
+ }
131112
+ function isAbortLikeError(error) {
131113
+ if (!(error instanceof Error)) return false;
131114
+ return error.name === "AbortError" || error.message.toLowerCase().includes("abort");
131115
+ }
131116
+ function waitForModelProxyRetry(attempt, signal) {
131117
+ const delayMs = MODEL_PROXY_RETRY_BASE_MS * 2 ** attempt;
131118
+ if (signal?.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
131119
+ return new Promise((resolve5, reject2) => {
131120
+ const timer = setTimeout(resolve5, delayMs);
131121
+ const onAbort = () => {
131122
+ clearTimeout(timer);
131123
+ reject2(new DOMException("Aborted", "AbortError"));
131124
+ };
131125
+ signal?.addEventListener("abort", onAbort, { once: true });
131126
+ });
131127
+ }
130916
131128
  function resolveNodeModelCallProxyUrl() {
130917
131129
  if (typeof process === "undefined") return null;
130918
131130
  const raw = process.env[MODEL_CALL_PROXY_ENV]?.trim();
@@ -131002,7 +131214,7 @@ function safeParseObject2(text) {
131002
131214
  function objectRecord(value) {
131003
131215
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
131004
131216
  }
131005
- var MODEL_CALL_PROXY_ENV, MODEL_CALL_PROXY_TOKEN_ENV;
131217
+ var MODEL_CALL_PROXY_ENV, MODEL_CALL_PROXY_TOKEN_ENV, MODEL_PROXY_MAX_ATTEMPTS, MODEL_PROXY_RETRY_BASE_MS;
131006
131218
  var init_modelRouter = __esm({
131007
131219
  "features/perchTerminal/runtime/modelRouter.ts"() {
131008
131220
  "use strict";
@@ -131014,6 +131226,8 @@ var init_modelRouter = __esm({
131014
131226
  init_toolCallNormalizer();
131015
131227
  MODEL_CALL_PROXY_ENV = "PERCH_MODEL_CALL_PROXY_URL";
131016
131228
  MODEL_CALL_PROXY_TOKEN_ENV = "PERCH_MODEL_CALL_PROXY_TOKEN";
131229
+ MODEL_PROXY_MAX_ATTEMPTS = 3;
131230
+ MODEL_PROXY_RETRY_BASE_MS = 350;
131017
131231
  }
131018
131232
  });
131019
131233
 
@@ -133606,10 +133820,18 @@ function classifyTool(name) {
133606
133820
  message: `Unknown tool: ${name}`
133607
133821
  };
133608
133822
  }
133823
+ const riskLevel = getToolRiskLevel(name);
133824
+ if (!riskLevel) {
133825
+ return {
133826
+ ok: false,
133827
+ code: "tool_unknown",
133828
+ message: `Tool is not cataloged: ${name}`
133829
+ };
133830
+ }
133609
133831
  return {
133610
133832
  ok: true,
133611
133833
  toolName: name,
133612
- riskLevel: TOOL_RISK[name]
133834
+ riskLevel
133613
133835
  };
133614
133836
  }
133615
133837
  function validateToolCallPolicy(input) {
@@ -133860,9 +134082,6 @@ function classifyIrreversibleOrOutboundAction(toolName, args) {
133860
134082
  return null;
133861
134083
  }
133862
134084
  }
133863
- function isEnabledToolName(name) {
133864
- return Object.values(TOOL_NAMES).includes(name);
133865
- }
133866
134085
  function countEmailRecipients(args) {
133867
134086
  const countValue = (value) => {
133868
134087
  if (Array.isArray(value)) return value.filter((item) => String(item).trim()).length;
@@ -134242,7 +134461,7 @@ function validateArgs(name, args) {
134242
134461
  return "run_sandbox_code.command must be a non-empty string when provided.";
134243
134462
  if (args.language !== void 0 && args.language !== "python" && args.language !== "node")
134244
134463
  return 'run_sandbox_code.language must be either "python" or "node" when provided.';
134245
- if (args.code !== void 0 && !hasCode)
134464
+ if (args.code !== void 0 && !hasCode && !hasCommand)
134246
134465
  return "run_sandbox_code.code must be a non-empty string when provided.";
134247
134466
  }
134248
134467
  if (args.label !== void 0 && typeof args.label !== "string")
@@ -134303,128 +134522,77 @@ function isSafeSandboxInputRef(value) {
134303
134522
  if (typeof value !== "string") return false;
134304
134523
  return isSafeLocalSourceId(value) || isSafeFilePath(value);
134305
134524
  }
134306
- var TOOL_RISK;
134307
134525
  var init_toolPolicy = __esm({
134308
134526
  "features/perchTerminal/runtime/toolPolicy.ts"() {
134309
134527
  "use strict";
134310
134528
  init_toolNames();
134529
+ init_catalog();
134311
134530
  init_toolPermissionPolicy();
134312
134531
  init_permissionModes();
134313
134532
  init_localCommandPolicy();
134314
- TOOL_RISK = {
134315
- // Desktop tools
134316
- [TOOL_NAMES.validateWorkspaceRoot]: "read",
134317
- [TOOL_NAMES.bash]: "command",
134318
- [TOOL_NAMES.runBashTerminalCommand]: "command",
134319
- [TOOL_NAMES.glob]: "read",
134320
- [TOOL_NAMES.grep]: "read",
134321
- [TOOL_NAMES.readLocalFile]: "read",
134322
- [TOOL_NAMES.writeLocalFile]: "write",
134323
- [TOOL_NAMES.moveLocalFile]: "write",
134324
- [TOOL_NAMES.copyLocalFile]: "write",
134325
- [TOOL_NAMES.createDirectory]: "write",
134326
- [TOOL_NAMES.deleteLocalFile]: "write",
134327
- [TOOL_NAMES.printFile]: "write",
134328
- [TOOL_NAMES.editLocalFile]: "write",
134329
- [TOOL_NAMES.statPath]: "read",
134330
- [TOOL_NAMES.prepareSandboxInputs]: "read",
134331
- [TOOL_NAMES.readProjectMemory]: "read",
134332
- [TOOL_NAMES.saveToMemory]: "write",
134333
- [TOOL_NAMES.addProjectRule]: "write",
134334
- [TOOL_NAMES.writePerchManual]: "write",
134335
- [TOOL_NAMES.getProjectRules]: "read",
134336
- [TOOL_NAMES.listLocalSources]: "read",
134337
- [TOOL_NAMES.readLocalSourceFile]: "read",
134338
- [TOOL_NAMES.generateAPAuditPacket]: "command",
134339
- [TOOL_NAMES.prepareAPEvidence]: "command",
134340
- [TOOL_NAMES.queryAPCases]: "read",
134341
- [TOOL_NAMES.renderAPControlGraph]: "read",
134342
- [TOOL_NAMES.runManagedPlaybook]: "command",
134343
- [TOOL_NAMES.runSuite]: "command",
134344
- [TOOL_NAMES.listSuiteCatalog]: "read",
134345
- [TOOL_NAMES.proposeSuitePlan]: "command",
134346
- [TOOL_NAMES.executeSuitePlan]: "command",
134347
- [TOOL_NAMES.proposeWork]: "command",
134348
- [TOOL_NAMES.executeWork]: "command",
134349
- [TOOL_NAMES.sendWorkerMessage]: "command",
134350
- [TOOL_NAMES.taskStop]: "command",
134351
- [TOOL_NAMES.spawnWorker]: "command",
134352
- [TOOL_NAMES.dispatchAgent]: "command",
134353
- [TOOL_NAMES.runSandboxAnalysis]: "command",
134354
- [TOOL_NAMES.runSandboxCode]: "command",
134355
- [TOOL_NAMES.safeBrowserAction]: "write",
134356
- [TOOL_NAMES.browserNavigate]: "write",
134357
- [TOOL_NAMES.browserExecuteTask]: "write",
134358
- [TOOL_NAMES.browserObserve]: "read",
134359
- [TOOL_NAMES.browserClick]: "write",
134360
- [TOOL_NAMES.browserType]: "write",
134361
- [TOOL_NAMES.browserVisualClick]: "write",
134362
- [TOOL_NAMES.browserFocusType]: "write",
134363
- [TOOL_NAMES.browserPressKey]: "write",
134364
- [TOOL_NAMES.browserRead]: "read",
134365
- [TOOL_NAMES.browserWait]: "read",
134366
- [TOOL_NAMES.browserHandleDialog]: "write",
134367
- [TOOL_NAMES.browserSearchWeb]: "read",
134368
- [TOOL_NAMES.browserReadPage]: "read",
134369
- [TOOL_NAMES.browserCollectSources]: "read",
134370
- [TOOL_NAMES.gmailSendEmail]: "write",
134371
- [TOOL_NAMES.gmailSaveDraft]: "write",
134372
- [TOOL_NAMES.googleDocsCreate]: "write",
134373
- [TOOL_NAMES.googleDocsAppend]: "write",
134374
- [TOOL_NAMES.googleCalendarCreateEvent]: "write",
134375
- [TOOL_NAMES.googleSheetsCreate]: "write",
134376
- [TOOL_NAMES.googleSheetsAppendRows]: "write",
134377
- [TOOL_NAMES.gmailSendEmailVerified]: "write",
134378
- [TOOL_NAMES.gmailSaveDraftVerified]: "write",
134379
- [TOOL_NAMES.googleDocsCreateVerified]: "write",
134380
- [TOOL_NAMES.googleCalendarCreateEventVerified]: "write",
134381
- // Market desk tools
134382
- [TOOL_NAMES.getMarketSignal]: "read",
134383
- [TOOL_NAMES.queryMarketSignalLog]: "read",
134384
- [TOOL_NAMES.explainMarketSignal]: "read",
134385
- [TOOL_NAMES.listMarketStrategies]: "read",
134386
- [TOOL_NAMES.runMarketBacktest]: "command",
134387
- [TOOL_NAMES.getMarketTrackRecord]: "read",
134388
- // Native tools
134389
- [TOOL_NAMES.ctxInspect]: "read",
134390
- [TOOL_NAMES.toolSearch]: "read",
134391
- [TOOL_NAMES.configInspect]: "read",
134392
- [TOOL_NAMES.syntheticOutput]: "read",
134393
- [TOOL_NAMES.todoWrite]: "read",
134394
- [TOOL_NAMES.askUserQuestion]: "read",
134395
- [TOOL_NAMES.proposePlan]: "read",
134396
- [TOOL_NAMES.enterPlanMode]: "read",
134397
- [TOOL_NAMES.exitPlanMode]: "read",
134398
- [TOOL_NAMES.brief]: "read",
134399
- [TOOL_NAMES.listMcpServers]: "read",
134400
- [TOOL_NAMES.searchKnowledge]: "read",
134401
- // Unavailable tools (handled in executor, mapped to read for policy purposes)
134402
- [TOOL_NAMES.listSources]: "read",
134403
- [TOOL_NAMES.readSource]: "read",
134404
- [TOOL_NAMES.analyzeWorkbook]: "read",
134405
- [TOOL_NAMES.extractDocument]: "read",
134406
- [TOOL_NAMES.searchSources]: "read",
134407
- [TOOL_NAMES.semanticSearch]: "read",
134408
- [TOOL_NAMES.retrieveContext]: "read",
134409
- [TOOL_NAMES.diagnoseWorkspaceAccess]: "read",
134410
- [TOOL_NAMES.listIndexedSources]: "read",
134411
- [TOOL_NAMES.searchWorkspaceSources]: "read",
134412
- [TOOL_NAMES.resolveSourceCandidates]: "read",
134413
- [TOOL_NAMES.inspectDocument]: "read",
134414
- [TOOL_NAMES.visionInspect]: "read",
134415
- [TOOL_NAMES.extractDocumentSection]: "read",
134416
- [TOOL_NAMES.inspectWorkbookSheets]: "read",
134417
- [TOOL_NAMES.compareEvidenceAcrossSources]: "read",
134418
- [TOOL_NAMES.listArtifacts]: "read",
134419
- [TOOL_NAMES.webSearch]: "read",
134420
- [TOOL_NAMES.webFetch]: "read",
134421
- [TOOL_NAMES.scholarSearch]: "read",
134422
- [TOOL_NAMES.runLocalCommand]: "command",
134423
- [TOOL_NAMES.createTextArtifact]: "write",
134424
- [TOOL_NAMES.createDocumentArtifact]: "write",
134425
- [TOOL_NAMES.artifactCapabilityReport]: "read",
134426
- [TOOL_NAMES.writingEnvironmentCheck]: "read"
134427
- };
134533
+ }
134534
+ });
134535
+
134536
+ // features/perchTerminal/runtime/toolSystem/schemaCatalog.ts
134537
+ function buildToolSchemaCatalog(sections) {
134538
+ const byName = /* @__PURE__ */ new Map();
134539
+ const definitions = [];
134540
+ for (const section of sections) {
134541
+ for (const definition of section.definitions) {
134542
+ const name = definition.function.name;
134543
+ const existing = byName.get(name);
134544
+ if (existing) {
134545
+ throw new Error(
134546
+ `Duplicate model tool schema "${name}" in schema section "${section.id}".`
134547
+ );
134548
+ }
134549
+ if (section.owner !== "mcp") {
134550
+ const entry = getToolCatalogEntry(name);
134551
+ if (!entry) {
134552
+ throw new Error(
134553
+ `Model tool schema "${name}" in schema section "${section.id}" is missing from the tool catalog.`
134554
+ );
134555
+ }
134556
+ if (entry.owner !== section.owner) {
134557
+ throw new Error(
134558
+ `Model tool schema "${name}" declares owner "${section.owner}" but catalog owner is "${entry.owner}".`
134559
+ );
134560
+ }
134561
+ }
134562
+ byName.set(name, definition);
134563
+ definitions.push(definition);
134564
+ }
134565
+ }
134566
+ return {
134567
+ definitions,
134568
+ byName,
134569
+ sections
134570
+ };
134571
+ }
134572
+ function groupSchemaDefinitionsByCatalogOwner(idPrefix, definitions) {
134573
+ const groups = /* @__PURE__ */ new Map();
134574
+ for (const definition of definitions) {
134575
+ const name = definition.function.name;
134576
+ const entry = getToolCatalogEntry(name);
134577
+ if (!entry) {
134578
+ throw new Error(
134579
+ `Model tool schema "${name}" in schema group "${idPrefix}" is missing from the tool catalog.`
134580
+ );
134581
+ }
134582
+ const defs = groups.get(entry.owner) ?? [];
134583
+ defs.push(definition);
134584
+ groups.set(entry.owner, defs);
134585
+ }
134586
+ return [...groups.entries()].map(([owner, groupedDefinitions]) => ({
134587
+ id: `${idPrefix}:${owner}`,
134588
+ owner,
134589
+ definitions: groupedDefinitions
134590
+ }));
134591
+ }
134592
+ var init_schemaCatalog = __esm({
134593
+ "features/perchTerminal/runtime/toolSystem/schemaCatalog.ts"() {
134594
+ "use strict";
134595
+ init_catalog();
134428
134596
  }
134429
134597
  });
134430
134598
 
@@ -136543,7 +136711,7 @@ function buildFullRegistry(desktopConnected, cliLocalTools, activeRootPath, supa
136543
136711
  const baseUnavailable = UNAVAILABLE_TOOLS.filter(
136544
136712
  (t) => !dynamicSupabaseNames.has(t.name)
136545
136713
  );
136546
- return [
136714
+ return dedupeFullRegistryEntries([
136547
136715
  ...desktopEntries,
136548
136716
  ...nativeEntries,
136549
136717
  ...knowledgeEntries,
@@ -136552,7 +136720,17 @@ function buildFullRegistry(desktopConnected, cliLocalTools, activeRootPath, supa
136552
136720
  ...docWorkbookEntries,
136553
136721
  ...artifactEntries,
136554
136722
  ...baseUnavailable
136555
- ];
136723
+ ]);
136724
+ }
136725
+ function dedupeFullRegistryEntries(entries) {
136726
+ const byName = /* @__PURE__ */ new Map();
136727
+ for (const entry of entries) {
136728
+ const existing = byName.get(entry.name);
136729
+ if (!existing || entry.available && !existing.available) {
136730
+ byName.set(entry.name, entry);
136731
+ }
136732
+ }
136733
+ return [...byName.values()];
136556
136734
  }
136557
136735
  function getFullToolRegistry(opts) {
136558
136736
  return buildFullRegistry(
@@ -136588,46 +136766,53 @@ function filterToolDefinitionsForNames(definitions, allowedToolNames) {
136588
136766
  (definition) => allowed.has(definition.function.name)
136589
136767
  );
136590
136768
  }
136591
- function getEnabledToolDefinitions(opts) {
136769
+ function getEnabledToolSchemaSections(opts) {
136592
136770
  const native = getNativeToolDefinitions();
136593
136771
  const knowledgeTools = getKnowledgeToolDefinitions();
136594
136772
  const webTools = getWebToolDefinitions();
136595
136773
  const marketDeskDefs = isMarketDeskEnabled() ? getMarketDeskToolDefinitions() : [];
136596
- const supabaseDefs = getSupabaseToolDefinitions(
136597
- opts.supabaseConfigured,
136598
- opts.workspaceId
136599
- );
136600
136774
  const mcpDefs = filterModelFacingMcpTools(opts.mcpTools ?? []);
136775
+ const supabaseSections = groupSchemaDefinitionsByCatalogOwner(
136776
+ "supabase",
136777
+ getSupabaseToolDefinitions(opts.supabaseConfigured, opts.workspaceId)
136778
+ );
136601
136779
  if (!opts.desktopConnected) {
136602
136780
  const cliLocalDesktop = opts.cliLocalTools === true ? getDesktopToolDefinitions().filter(
136603
136781
  (definition) => isCliLocalToolName(definition.function.name)
136604
136782
  ) : [];
136605
136783
  return [
136606
- ...cliLocalDesktop,
136607
- ...native,
136608
- ...knowledgeTools,
136609
- ...webTools,
136610
- ...marketDeskDefs,
136611
- ...supabaseDefs,
136612
- ...mcpDefs
136784
+ { id: "desktop:cli-local", owner: "module", definitions: cliLocalDesktop },
136785
+ { id: "native", owner: "module", definitions: native },
136786
+ { id: "knowledge", owner: "module", definitions: knowledgeTools },
136787
+ { id: "web", owner: "lane", definitions: webTools },
136788
+ { id: "market-desk", owner: "module", definitions: marketDeskDefs },
136789
+ ...supabaseSections,
136790
+ { id: "mcp", owner: "mcp", definitions: mcpDefs }
136613
136791
  ];
136614
136792
  }
136615
136793
  const desktop = getDesktopToolDefinitions();
136616
136794
  const desktopNames = new Set(desktop.map((d) => d.function.name));
136795
+ const supabaseDefs = getSupabaseToolDefinitions(
136796
+ opts.supabaseConfigured,
136797
+ opts.workspaceId
136798
+ );
136617
136799
  const supabaseFiltered = supabaseDefs.filter((d) => !desktopNames.has(d.function.name));
136618
136800
  const hasVisionInspect = desktopNames.has(TOOL_NAMES.visionInspect) || supabaseFiltered.some((d) => d.function.name === TOOL_NAMES.visionInspect);
136619
136801
  const desktopVisionInspect = hasVisionInspect ? [] : [getVisionInspectToolDefinition()];
136620
136802
  return [
136621
- ...desktop,
136622
- ...native,
136623
- ...knowledgeTools,
136624
- ...webTools,
136625
- ...marketDeskDefs,
136626
- ...desktopVisionInspect,
136627
- ...supabaseFiltered,
136628
- ...mcpDefs
136803
+ { id: "desktop", owner: "module", definitions: desktop },
136804
+ { id: "native", owner: "module", definitions: native },
136805
+ { id: "knowledge", owner: "module", definitions: knowledgeTools },
136806
+ { id: "web", owner: "lane", definitions: webTools },
136807
+ { id: "market-desk", owner: "module", definitions: marketDeskDefs },
136808
+ { id: "desktop:vision-fallback", owner: "module", definitions: desktopVisionInspect },
136809
+ ...groupSchemaDefinitionsByCatalogOwner("supabase", supabaseFiltered),
136810
+ { id: "mcp", owner: "mcp", definitions: mcpDefs }
136629
136811
  ];
136630
136812
  }
136813
+ function getEnabledToolDefinitions(opts) {
136814
+ return buildToolSchemaCatalog(getEnabledToolSchemaSections(opts)).definitions;
136815
+ }
136631
136816
  function filterModelFacingMcpTools(mcpTools) {
136632
136817
  return mcpTools.filter((tool) => !tool.function.name.startsWith("mcp__playwright__"));
136633
136818
  }
@@ -136779,6 +136964,7 @@ var init_toolDefinitions = __esm({
136779
136964
  init_toolAvailability();
136780
136965
  init_toolPolicy();
136781
136966
  init_marketDeskAccess();
136967
+ init_schemaCatalog();
136782
136968
  init_toolNames();
136783
136969
  init_toolPermissionPolicy();
136784
136970
  init_toolPermissionPolicy();
@@ -206575,6 +206761,8 @@ var init_operatorPrimitives = __esm({
206575
206761
  operatorPrimitive(TOOL_NAMES.browserObserve),
206576
206762
  operatorPrimitive(TOOL_NAMES.browserClick),
206577
206763
  operatorPrimitive(TOOL_NAMES.browserType),
206764
+ operatorPrimitive(TOOL_NAMES.browserVisualClick),
206765
+ operatorPrimitive(TOOL_NAMES.browserFocusType),
206578
206766
  operatorPrimitive(TOOL_NAMES.browserPressKey),
206579
206767
  operatorPrimitive(TOOL_NAMES.browserRead),
206580
206768
  operatorPrimitive(TOOL_NAMES.browserWait),
@@ -215147,9 +215335,21 @@ var init_marketDesk = __esm({
215147
215335
  });
215148
215336
 
215149
215337
  // features/perchTerminal/runtime/toolSystem/registry.ts
215338
+ var registry_exports = {};
215339
+ __export(registry_exports, {
215340
+ getRegisteredTool: () => getRegisteredTool,
215341
+ getRegisteredToolNames: () => getRegisteredToolNames,
215342
+ isRegisteredTool: () => isRegisteredTool
215343
+ });
215150
215344
  function getRegisteredTool(name) {
215151
215345
  return REGISTRY.get(name) ?? null;
215152
215346
  }
215347
+ function isRegisteredTool(name) {
215348
+ return REGISTRY.has(name);
215349
+ }
215350
+ function getRegisteredToolNames() {
215351
+ return [...REGISTRY.keys()];
215352
+ }
215153
215353
  var TOOL_MODULES, REGISTRY;
215154
215354
  var init_registry5 = __esm({
215155
215355
  "features/perchTerminal/runtime/toolSystem/registry.ts"() {
@@ -215207,8 +215407,16 @@ var init_registry5 = __esm({
215207
215407
  });
215208
215408
 
215209
215409
  // features/perchTerminal/runtime/toolSystem/executeTool.ts
215410
+ async function loadToolRegistry() {
215411
+ if (typeof window !== "undefined") return null;
215412
+ registryPromise ??= Promise.resolve().then(() => (init_registry5(), registry_exports));
215413
+ return registryPromise;
215414
+ }
215210
215415
  async function executeRegisteredTool(name, args, ctx) {
215211
- const mod = getRegisteredTool(name);
215416
+ const registry2 = await loadToolRegistry();
215417
+ if (!registry2) return { handled: false };
215418
+ const { getRegisteredTool: getRegisteredTool2 } = registry2;
215419
+ const mod = getRegisteredTool2(name);
215212
215420
  if (!mod) return { handled: false };
215213
215421
  if (MARKET_DESK_TOOL_NAMES.has(name) && !isMarketDeskEnabled()) {
215214
215422
  return {
@@ -215222,11 +215430,12 @@ async function executeRegisteredTool(name, args, ctx) {
215222
215430
  }
215223
215431
  return { handled: true, result: await mod.handler(args, ctx) };
215224
215432
  }
215433
+ var registryPromise;
215225
215434
  var init_executeTool = __esm({
215226
215435
  "features/perchTerminal/runtime/toolSystem/executeTool.ts"() {
215227
215436
  "use strict";
215228
215437
  init_marketDeskAccess();
215229
- init_registry5();
215438
+ registryPromise = null;
215230
215439
  }
215231
215440
  });
215232
215441
 
@@ -219705,17 +219914,18 @@ async function runLiveAgentsLoop(input) {
219705
219914
  }
219706
219915
  const mode = effectiveChatMode;
219707
219916
  const loopTools = tools;
219708
- const loopSystemPrompt = appendLiveTurnContract(context.systemPrompt, {
219917
+ const sandboxExecutionRequired = sandboxExecutionRequiredByUserText(turn.trimmedInput, loopTools);
219918
+ const loopSystemPromptBase = appendLiveTurnContract(context.systemPrompt, {
219709
219919
  chatMode: mode,
219710
219920
  toolsAvailable: loopTools.length > 0,
219711
219921
  userObjective: turn.trimmedInput,
219712
219922
  planGateRejected
219713
219923
  });
219924
+ const loopSystemPrompt = sandboxExecutionRequired ? appendSandboxExecutionRequiredContract(loopSystemPromptBase) : loopSystemPromptBase;
219714
219925
  const threadSession = turn.threadId ? getThreadSessionFromMemory(turn.threadId) : null;
219715
219926
  const contextCompaction = threadSession?.contextCompaction ?? null;
219716
219927
  const approvedToolCall = approvedToolCallFromState(workflowState);
219717
219928
  const runLoop = input.loopRunner ?? runModelToolLoop;
219718
- const sandboxExecutionRequired = sandboxExecutionRequiredByUserText(turn.trimmedInput, loopTools);
219719
219929
  const loopInput = {
219720
219930
  signal: deps.signal ?? void 0,
219721
219931
  lane: loopLane,
@@ -219746,7 +219956,7 @@ async function runLiveAgentsLoop(input) {
219746
219956
  forcedInitialToolCall: approvedToolCall ?? turn.forcedInitialToolCall ?? null,
219747
219957
  forcedInitialToolCallApproved: Boolean(approvedToolCall),
219748
219958
  stopAfterForcedInitialToolCall: Boolean(approvedToolCall),
219749
- forceToolUse: turn.forceToolUse === true || sandboxExecutionRequired,
219959
+ forceToolUse: turn.forceToolUse === true,
219750
219960
  mcpTools: turn.mcpTools ?? [],
219751
219961
  maxIterations: turnHasBrowserOperatorTools(loopTools) ? 24 : turn.coordinatorSessionActive ? 20 : void 0,
219752
219962
  attachOperatorScreenshots: turnHasBrowserOperatorTools(loopTools),
@@ -219843,10 +220053,11 @@ async function runLiveAgentsLoop(input) {
219843
220053
  if (sandboxExecutionRequired && loopResult.ok && !hasRunSandboxCodeToolCall(loopResult)) {
219844
220054
  loopResult = await runLoop({
219845
220055
  ...loopInput,
219846
- forceToolUse: true,
219847
- systemPrompt: `${loopInput.systemPrompt.trim()}
219848
-
219849
- Sandbox execution is explicitly required by the user. This turn is incomplete until you call run_sandbox_code. Use the command field when possible; pass source file paths in sources and read copied files from input/. The sandbox tool result already captures stdout/stderr and produced files; do not try to read output/report.json from the host filesystem after the run. Do not mention internal model, provider, or lane details in the user-facing answer. Do not finish with prose before a sandbox run.`
220056
+ forceToolUse: false,
220057
+ systemPrompt: appendSandboxExecutionRequiredContract(
220058
+ loopInput.systemPrompt,
220059
+ true
220060
+ )
219850
220061
  });
219851
220062
  }
219852
220063
  if (sandboxExecutionRequired && loopResult.ok && !hasRunSandboxCodeToolCall(loopResult)) {
@@ -219977,6 +220188,12 @@ function sandboxExecutionRequiredByUserText(userText, tools) {
219977
220188
  if (!mentionsSandbox) return false;
219978
220189
  return /\b(use|run|execute|call|primary|required|mandatory|must|final numbers|must come from|do not stop)\b/.test(normalized) || /sandbox.{0,80}(primary|required|mandatory|must|execute|run|numbers|code)/.test(normalized) || /(primary|required|mandatory|must|execute|run|numbers|code).{0,80}sandbox/.test(normalized);
219979
220190
  }
220191
+ function appendSandboxExecutionRequiredContract(systemPrompt, retry = false) {
220192
+ const prefix = retry ? "The previous attempt did not call run_sandbox_code." : "Sandbox execution is explicitly required by the user.";
220193
+ return `${systemPrompt.trim()}
220194
+
220195
+ ${prefix} This turn is incomplete until you call run_sandbox_code. Use the command field when possible; pass source file paths in sources and read copied files from input/. The sandbox tool result already captures stdout/stderr and produced files; do not try to read output/report.json from the host filesystem after the run. Do not mention internal model, provider, or lane details in the user-facing answer. Do not finish with prose before a sandbox run.`;
220196
+ }
219980
220197
  function hasRunSandboxCodeToolCall(loopResult) {
219981
220198
  return loopResult.toolCalls.some((call) => call.toolName === TOOL_NAMES.runSandboxCode);
219982
220199
  }
@@ -222813,7 +223030,9 @@ function maybeWarnCategoryDrift(input) {
222813
223030
  const drift = sum - input.headlineTokens;
222814
223031
  const allowed = Math.max(256, Math.ceil(input.wireOverheadTokens ?? 0) + 64);
222815
223032
  if (Math.abs(drift) <= allowed) return;
222816
- if (typeof process !== "undefined" && process.env.NODE_ENV === "production") return;
223033
+ if (typeof process === "undefined" || process.env.PERCH_CONTEXT_METER_DEBUG !== "1") {
223034
+ return;
223035
+ }
222817
223036
  console.warn(
222818
223037
  `[context-meter] Category total drift in ${input.source}: categories=${sum}, headline=${input.headlineTokens}, drift=${drift}`
222819
223038
  );
@@ -282005,12 +282224,27 @@ async function runInkInteractivePerchCli(writer, deps, options) {
282005
282224
  const [pulse, setPulse] = React11.useState(0);
282006
282225
  const [, refresh] = React11.useState(0);
282007
282226
  const liveTextRef = React11.useRef("");
282227
+ const liveTextFlushTimerRef = React11.useRef(null);
282008
282228
  const activeRunRef = React11.useRef(null);
282009
282229
  const toolInputsById = React11.useRef(/* @__PURE__ */ new Map());
282010
282230
  const richToolIds = React11.useRef(/* @__PURE__ */ new Set());
282011
282231
  const terminalCommandItems = React11.useRef(/* @__PURE__ */ new Map());
282012
282232
  const sandboxRunItems = React11.useRef(/* @__PURE__ */ new Map());
282013
282233
  const sandboxRunMeta = React11.useRef(/* @__PURE__ */ new Map());
282234
+ const clearLiveTextFlushTimer = React11.useCallback(() => {
282235
+ if (liveTextFlushTimerRef.current) {
282236
+ clearTimeout(liveTextFlushTimerRef.current);
282237
+ liveTextFlushTimerRef.current = null;
282238
+ }
282239
+ }, []);
282240
+ const scheduleLiveTextPaint = React11.useCallback(() => {
282241
+ if (liveTextFlushTimerRef.current) return;
282242
+ liveTextFlushTimerRef.current = setTimeout(() => {
282243
+ liveTextFlushTimerRef.current = null;
282244
+ setLiveText(liveTextRef.current);
282245
+ }, 33);
282246
+ }, []);
282247
+ React11.useEffect(() => clearLiveTextFlushTimer, [clearLiveTextFlushTimer]);
282014
282248
  React11.useEffect(() => {
282015
282249
  if (!working) return void 0;
282016
282250
  const timer = setInterval(() => setPulse((value) => value + 1), 120);
@@ -282109,6 +282343,7 @@ async function runInkInteractivePerchCli(writer, deps, options) {
282109
282343
  }
282110
282344
  setWorking(true);
282111
282345
  setWorkingText("thinking");
282346
+ clearLiveTextFlushTimer();
282112
282347
  setLiveText("");
282113
282348
  liveTextRef.current = "";
282114
282349
  const toolNamesById = /* @__PURE__ */ new Map();
@@ -282155,7 +282390,7 @@ async function runInkInteractivePerchCli(writer, deps, options) {
282155
282390
  case "content_delta":
282156
282391
  case "streaming_text":
282157
282392
  liveTextRef.current += event.text;
282158
- setLiveText(liveTextRef.current);
282393
+ scheduleLiveTextPaint();
282159
282394
  break;
282160
282395
  case "assistant_preamble":
282161
282396
  case "activity_delta":
@@ -282403,6 +282638,7 @@ async function runInkInteractivePerchCli(writer, deps, options) {
282403
282638
  }
282404
282639
  }
282405
282640
  });
282641
+ clearLiveTextFlushTimer();
282406
282642
  setLiveText("");
282407
282643
  const assistantText = result2.assistantText.trim() || liveTextRef.current.trim();
282408
282644
  if (assistantText) {
@@ -282439,12 +282675,13 @@ async function runInkInteractivePerchCli(writer, deps, options) {
282439
282675
  if (activeRunRef.current?.runId === clientRunId) {
282440
282676
  activeRunRef.current = null;
282441
282677
  }
282678
+ clearLiveTextFlushTimer();
282442
282679
  setWorking(false);
282443
282680
  setWorkingText("ready");
282444
282681
  setLiveText("");
282445
282682
  liveTextRef.current = "";
282446
282683
  }
282447
- }, [addItem, app, appendItemDetails, patchItem, reconnect, runTurn, updateToolItem, working]);
282684
+ }, [addItem, app, appendItemDetails, clearLiveTextFlushTimer, patchItem, reconnect, runTurn, scheduleLiveTextPaint, updateToolItem, working]);
282448
282685
  Ink2.useInput((input, key) => {
282449
282686
  if (working) {
282450
282687
  if (key.ctrl && input === "e") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perchai-cli",
3
- "version": "2.4.15",
3
+ "version": "2.4.17",
4
4
  "description": "Perch AI command-line interface",
5
5
  "bin": {
6
6
  "perch": "bin/perch"