aiden-runtime 4.1.4 → 4.5.0

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 (169) hide show
  1. package/README.md +250 -847
  2. package/dist/api/server.js +32 -5
  3. package/dist/cli/v4/aidenCLI.js +379 -53
  4. package/dist/cli/v4/callbacks.js +248 -0
  5. package/dist/cli/v4/chatSession.js +292 -4
  6. package/dist/cli/v4/commands/_runtimeToggleHelpers.js +92 -0
  7. package/dist/cli/v4/commands/browserDepth.js +45 -0
  8. package/dist/cli/v4/commands/cron.js +264 -0
  9. package/dist/cli/v4/commands/daemon.js +541 -0
  10. package/dist/cli/v4/commands/daemonStatus.js +253 -0
  11. package/dist/cli/v4/commands/help.js +7 -0
  12. package/dist/cli/v4/commands/index.js +20 -1
  13. package/dist/cli/v4/commands/runs.js +203 -0
  14. package/dist/cli/v4/commands/sandbox.js +48 -0
  15. package/dist/cli/v4/commands/suggestions.js +68 -0
  16. package/dist/cli/v4/commands/tce.js +41 -0
  17. package/dist/cli/v4/commands/trigger.js +378 -0
  18. package/dist/cli/v4/commands/update.js +95 -3
  19. package/dist/cli/v4/daemonAgentBuilder.js +142 -0
  20. package/dist/cli/v4/defaultSoul.js +75 -3
  21. package/dist/cli/v4/display/capabilityCard.js +26 -0
  22. package/dist/cli/v4/display/progressBar.js +41 -8
  23. package/dist/cli/v4/display.js +258 -15
  24. package/dist/cli/v4/replyRenderer.js +31 -23
  25. package/dist/cli/v4/toolPreview.js +10 -0
  26. package/dist/cli/v4/updateBootPrompt.js +170 -0
  27. package/dist/core/playwrightBridge.js +129 -0
  28. package/dist/core/toolRegistry.js +7 -1
  29. package/dist/core/v4/aidenAgent.js +371 -4
  30. package/dist/core/v4/browserState.js +436 -0
  31. package/dist/core/v4/checkpoint.js +79 -0
  32. package/dist/core/v4/daemon/bootstrap.js +604 -0
  33. package/dist/core/v4/daemon/cleanShutdown.js +154 -0
  34. package/dist/core/v4/daemon/cron/cronBridge.js +126 -0
  35. package/dist/core/v4/daemon/cron/cronEmitter.js +173 -0
  36. package/dist/core/v4/daemon/cron/migration.js +199 -0
  37. package/dist/core/v4/daemon/cron/misfirePolicy.js +115 -0
  38. package/dist/core/v4/daemon/daemonConfig.js +90 -0
  39. package/dist/core/v4/daemon/db/connection.js +106 -0
  40. package/dist/core/v4/daemon/db/migrations.js +296 -0
  41. package/dist/core/v4/daemon/db/schema/v1.spec.js +18 -0
  42. package/dist/core/v4/daemon/dispatcher/agentRunner.js +98 -0
  43. package/dist/core/v4/daemon/dispatcher/budgetGate.js +127 -0
  44. package/dist/core/v4/daemon/dispatcher/daemonApproval.js +113 -0
  45. package/dist/core/v4/daemon/dispatcher/dailyBudgetTracker.js +120 -0
  46. package/dist/core/v4/daemon/dispatcher/dispatcher.js +389 -0
  47. package/dist/core/v4/daemon/dispatcher/fireRateLimiter.js +113 -0
  48. package/dist/core/v4/daemon/dispatcher/index.js +53 -0
  49. package/dist/core/v4/daemon/dispatcher/promptTemplate.js +95 -0
  50. package/dist/core/v4/daemon/dispatcher/realAgentRunner.js +356 -0
  51. package/dist/core/v4/daemon/dispatcher/resolveModel.js +93 -0
  52. package/dist/core/v4/daemon/dispatcher/sessionId.js +93 -0
  53. package/dist/core/v4/daemon/drain.js +156 -0
  54. package/dist/core/v4/daemon/eventLoopLag.js +73 -0
  55. package/dist/core/v4/daemon/health.js +159 -0
  56. package/dist/core/v4/daemon/idempotencyStore.js +204 -0
  57. package/dist/core/v4/daemon/index.js +179 -0
  58. package/dist/core/v4/daemon/instanceTracker.js +99 -0
  59. package/dist/core/v4/daemon/resourceRegistry.js +150 -0
  60. package/dist/core/v4/daemon/restartCode.js +32 -0
  61. package/dist/core/v4/daemon/restartFailureCounter.js +77 -0
  62. package/dist/core/v4/daemon/runStore.js +114 -0
  63. package/dist/core/v4/daemon/runtimeLock.js +167 -0
  64. package/dist/core/v4/daemon/signals.js +50 -0
  65. package/dist/core/v4/daemon/supervisor.js +272 -0
  66. package/dist/core/v4/daemon/triggerBus.js +279 -0
  67. package/dist/core/v4/daemon/triggers/email/allowlist.js +70 -0
  68. package/dist/core/v4/daemon/triggers/email/automatedSender.js +78 -0
  69. package/dist/core/v4/daemon/triggers/email/bodyExtractor.js +0 -0
  70. package/dist/core/v4/daemon/triggers/email/emailSeenStore.js +99 -0
  71. package/dist/core/v4/daemon/triggers/email/emailSpec.js +107 -0
  72. package/dist/core/v4/daemon/triggers/email/imapConnection.js +211 -0
  73. package/dist/core/v4/daemon/triggers/email/index.js +332 -0
  74. package/dist/core/v4/daemon/triggers/email/seenUids.js +60 -0
  75. package/dist/core/v4/daemon/triggers/fileObservationsStore.js +93 -0
  76. package/dist/core/v4/daemon/triggers/fileWatcher.js +253 -0
  77. package/dist/core/v4/daemon/triggers/fileWatcherSpec.js +88 -0
  78. package/dist/core/v4/daemon/triggers/fsIdentity.js +42 -0
  79. package/dist/core/v4/daemon/triggers/globMatcher.js +100 -0
  80. package/dist/core/v4/daemon/triggers/reconcile.js +206 -0
  81. package/dist/core/v4/daemon/triggers/settleStat.js +81 -0
  82. package/dist/core/v4/daemon/triggers/webhook.js +376 -0
  83. package/dist/core/v4/daemon/triggers/webhookDeliveriesStore.js +109 -0
  84. package/dist/core/v4/daemon/triggers/webhookIdempotency.js +72 -0
  85. package/dist/core/v4/daemon/triggers/webhookRateLimit.js +56 -0
  86. package/dist/core/v4/daemon/triggers/webhookSpec.js +76 -0
  87. package/dist/core/v4/daemon/triggers/webhookVerifier.js +128 -0
  88. package/dist/core/v4/daemon/types.js +15 -0
  89. package/dist/core/v4/dockerSession.js +461 -0
  90. package/dist/core/v4/dryRun.js +117 -0
  91. package/dist/core/v4/failureClassifier.js +779 -0
  92. package/dist/core/v4/loopTrace.js +257 -0
  93. package/dist/core/v4/recoveryReport.js +449 -0
  94. package/dist/core/v4/runtimeToggles.js +187 -0
  95. package/dist/core/v4/sandboxConfig.js +285 -0
  96. package/dist/core/v4/sandboxFs.js +316 -0
  97. package/dist/core/v4/suggestionCatalog.js +41 -0
  98. package/dist/core/v4/suggestionEngine.js +210 -0
  99. package/dist/core/v4/toolRegistry.js +18 -0
  100. package/dist/core/v4/turnState.js +587 -0
  101. package/dist/core/v4/update/checkUpdate.js +63 -3
  102. package/dist/core/v4/update/installMethodDetect.js +115 -0
  103. package/dist/core/v4/update/registryClient.js +121 -0
  104. package/dist/core/v4/update/skipState.js +75 -0
  105. package/dist/core/v4/verifier.js +448 -0
  106. package/dist/core/version.js +1 -1
  107. package/dist/core/webSearch.js +64 -24
  108. package/dist/tools/v4/browser/_observer.js +224 -0
  109. package/dist/tools/v4/browser/browserBlocker.js +396 -0
  110. package/dist/tools/v4/browser/browserClick.js +18 -1
  111. package/dist/tools/v4/browser/browserClose.js +18 -1
  112. package/dist/tools/v4/browser/browserExtract.js +5 -1
  113. package/dist/tools/v4/browser/browserFill.js +17 -1
  114. package/dist/tools/v4/browser/browserGetUrl.js +5 -1
  115. package/dist/tools/v4/browser/browserNavigate.js +16 -1
  116. package/dist/tools/v4/browser/browserScreenshot.js +5 -1
  117. package/dist/tools/v4/browser/browserScroll.js +18 -1
  118. package/dist/tools/v4/browser/browserType.js +17 -1
  119. package/dist/tools/v4/browser/captchaCheck.js +5 -1
  120. package/dist/tools/v4/executeCode.js +1 -0
  121. package/dist/tools/v4/files/fileCopy.js +56 -2
  122. package/dist/tools/v4/files/fileDelete.js +38 -1
  123. package/dist/tools/v4/files/fileList.js +12 -1
  124. package/dist/tools/v4/files/fileMove.js +59 -2
  125. package/dist/tools/v4/files/filePatch.js +43 -1
  126. package/dist/tools/v4/files/fileRead.js +12 -1
  127. package/dist/tools/v4/files/fileWrite.js +41 -1
  128. package/dist/tools/v4/index.js +71 -58
  129. package/dist/tools/v4/memory/memoryAdd.js +14 -0
  130. package/dist/tools/v4/memory/memoryRemove.js +14 -0
  131. package/dist/tools/v4/memory/memoryReplace.js +15 -0
  132. package/dist/tools/v4/memory/sessionSummary.js +12 -0
  133. package/dist/tools/v4/process/processKill.js +19 -0
  134. package/dist/tools/v4/process/processList.js +1 -0
  135. package/dist/tools/v4/process/processLogRead.js +1 -0
  136. package/dist/tools/v4/process/processSpawn.js +13 -0
  137. package/dist/tools/v4/process/processWait.js +1 -0
  138. package/dist/tools/v4/sessions/recallSession.js +1 -0
  139. package/dist/tools/v4/sessions/sessionList.js +1 -0
  140. package/dist/tools/v4/sessions/sessionSearch.js +1 -0
  141. package/dist/tools/v4/skills/lookupToolSchema.js +2 -0
  142. package/dist/tools/v4/skills/skillManage.js +13 -0
  143. package/dist/tools/v4/skills/skillView.js +1 -0
  144. package/dist/tools/v4/skills/skillsList.js +1 -0
  145. package/dist/tools/v4/subagent/subagentFanout.js +1 -0
  146. package/dist/tools/v4/system/aidenSelfUpdate.js +16 -0
  147. package/dist/tools/v4/system/appClose.js +13 -0
  148. package/dist/tools/v4/system/appInput.js +13 -0
  149. package/dist/tools/v4/system/appLaunch.js +13 -0
  150. package/dist/tools/v4/system/clipboardRead.js +1 -0
  151. package/dist/tools/v4/system/clipboardWrite.js +14 -0
  152. package/dist/tools/v4/system/mediaKey.js +12 -0
  153. package/dist/tools/v4/system/mediaSessions.js +1 -0
  154. package/dist/tools/v4/system/mediaTransport.js +13 -0
  155. package/dist/tools/v4/system/naturalEvents.js +1 -0
  156. package/dist/tools/v4/system/nowPlaying.js +1 -0
  157. package/dist/tools/v4/system/osProcessList.js +1 -0
  158. package/dist/tools/v4/system/screenshot.js +1 -0
  159. package/dist/tools/v4/system/systemInfo.js +1 -0
  160. package/dist/tools/v4/system/volumeSet.js +17 -0
  161. package/dist/tools/v4/terminal/shellExec.js +81 -9
  162. package/dist/tools/v4/web/deepResearch.js +1 -0
  163. package/dist/tools/v4/web/openUrl.js +1 -0
  164. package/dist/tools/v4/web/webFetch.js +1 -0
  165. package/dist/tools/v4/web/webPage.js +1 -0
  166. package/dist/tools/v4/web/webSearch.js +1 -0
  167. package/dist/tools/v4/web/youtubeSearch.js +1 -0
  168. package/package.json +7 -1
  169. package/plugins/aiden-plugin-cdp-browser/.granted-permissions.json +8 -0
@@ -19,6 +19,7 @@
19
19
  */
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.CliCallbacks = void 0;
22
+ exports.mapBlockerToCard = mapBlockerToCard;
22
23
  exports.renderApprovalBox = renderApprovalBox;
23
24
  const box_1 = require("./box");
24
25
  async function defaultPrompts() {
@@ -45,6 +46,68 @@ const DECISION_CHOICES = [
45
46
  { name: 'Deny', value: 'deny' },
46
47
  ];
47
48
  const KNOWN_TIERS = new Set(['safe', 'caution', 'dangerous']);
49
+ // ── v4.3 Phase 3 — manual-blocker card mapping ────────────────────────────
50
+ /** Best-effort hostname extraction; falls back to the raw URL. */
51
+ function blockerHostname(url) {
52
+ try {
53
+ return new URL(url).hostname || url;
54
+ }
55
+ catch {
56
+ return url;
57
+ }
58
+ }
59
+ /**
60
+ * Map a BlockerSurface to the existing CapabilityCardData chrome.
61
+ * Pure helper — same shape per `BlockerKind`, parameterised by the
62
+ * blocker's URL + optional subtype for the body text. The renderer
63
+ * (`display.capabilityCard`) handles all rendering chrome; this
64
+ * function only fills the slots semantically.
65
+ *
66
+ * Public for unit tests; chatSession + callbacks consume via the
67
+ * `renderBlockerCardIfPresent` method below.
68
+ */
69
+ function mapBlockerToCard(blocker) {
70
+ const host = blockerHostname(blocker.url);
71
+ const labels = {
72
+ captcha: {
73
+ title: `CAPTCHA challenge at ${host}`,
74
+ canStill: ['Solve the challenge in the browser tab', 'Cancel this task'],
75
+ cannot: ['Continue automatically without your action'],
76
+ fix: `I'll wait — solve the ${blocker.subtype ?? 'CAPTCHA'} challenge and tell me when ready.`,
77
+ },
78
+ login: {
79
+ title: `Sign-in required at ${host}`,
80
+ canStill: ['Sign in via the browser tab', 'Cancel this task'],
81
+ cannot: ['Continue without authentication'],
82
+ fix: `I'll wait — sign in and let me know when done.`,
83
+ },
84
+ '2fa': {
85
+ title: `Two-factor code required at ${host}`,
86
+ canStill: ['Enter the 2FA code in the browser tab', 'Cancel this task'],
87
+ cannot: ['Continue without the verification code'],
88
+ fix: `I'll wait — enter your code and tell me when complete.`,
89
+ },
90
+ verification: {
91
+ title: `Identity verification at ${host}`,
92
+ canStill: ['Complete the verification in the browser', 'Cancel this task'],
93
+ cannot: ['Continue without verification'],
94
+ fix: `I'll wait — finish the verification and tell me when done.`,
95
+ },
96
+ consent: {
97
+ title: `Consent banner at ${host}`,
98
+ canStill: ['Dismiss the banner in the browser', 'Continue if banner is dismissable'],
99
+ cannot: ['Reliably interact with content while the banner blocks it'],
100
+ fix: `Dismiss the cookie or privacy banner and I'll retry.`,
101
+ },
102
+ };
103
+ const t = labels[blocker.kind];
104
+ return {
105
+ title: `🛑 ${t.title}`,
106
+ canStill: t.canStill,
107
+ cannotReliably: t.cannot,
108
+ fix: t.fix,
109
+ };
110
+ }
48
111
  function parseRiskTier(content) {
49
112
  const head = content.trim().toLowerCase().split(/\s+/)[0] ?? '';
50
113
  // Strip punctuation that might bleed in from JSON: "safe.", "caution,"...
@@ -63,6 +126,29 @@ class CliCallbacks {
63
126
  this.toolRows = new Map();
64
127
  this.toolStartTimes = new Map();
65
128
  this.firstToolFiredThisTurn = false;
129
+ // v4.1.5 Issue K — `firePhaseVerb` is the public entry point for the
130
+ // AidenCLI bridge. AidenAgent fires `onMemoryRefreshStart` etc.,
131
+ // aidenCLI's adapter calls into one of these `onPhase…` shims, each
132
+ // mapping a lifecycle event to a verb string. Defensive try/catch so
133
+ // a misbehaving display sink can't unwind the agent loop.
134
+ this.onMemoryRefreshStart = () => {
135
+ try {
136
+ this.phaseVerbHook?.('refreshing memory');
137
+ }
138
+ catch { /* defensive */ }
139
+ };
140
+ this.onPromptBuilt = (_info) => {
141
+ try {
142
+ this.phaseVerbHook?.('preparing prompt');
143
+ }
144
+ catch { /* defensive */ }
145
+ };
146
+ this.onProviderRequestStart = (_providerId) => {
147
+ try {
148
+ this.phaseVerbHook?.('calling provider');
149
+ }
150
+ catch { /* defensive */ }
151
+ };
66
152
  /**
67
153
  * Phase 23.5 — bound to AidenAgent.onToolCall. Emits one event row
68
154
  * per tool call: prints `[running]` on `before`, mutates the bracket
@@ -91,6 +177,14 @@ class CliCallbacks {
91
177
  this.beforeToolHook?.();
92
178
  }
93
179
  catch { /* defensive */ }
180
+ // v4.1.5+ Path A — fire the loop-trace sink BEFORE row writes.
181
+ // Captures every tool's call.id + name (including hidden ones
182
+ // suppressed from the visible trail) so the trace covers the
183
+ // full agent loop, not just user-visible work.
184
+ try {
185
+ this.toolTraceBeforeHook?.(call.id, call.name);
186
+ }
187
+ catch { /* defensive */ }
94
188
  const handle = this.display.toolRow(call.name, call.arguments);
95
189
  this.toolRows.set(call.id, handle);
96
190
  this.toolStartTimes.set(call.id, Date.now());
@@ -109,14 +203,38 @@ class CliCallbacks {
109
203
  this.afterEachToolHook?.(call.name);
110
204
  }
111
205
  catch { /* defensive */ }
206
+ // v4.1.5+ Path A — loop-trace sink fires even when handle was
207
+ // lost (rare; happens if before/after pairing slipped) so the
208
+ // trace never under-counts tool calls.
209
+ try {
210
+ this.toolTraceAfterHook?.(call.id, call.name, call.arguments);
211
+ }
212
+ catch { /* defensive */ }
112
213
  return;
113
214
  }
114
215
  const ms = Date.now() - startedAt;
115
216
  const err = result?.error;
116
217
  if (typeof err === 'string' && err.includes('URL provenance gate')) {
117
218
  handle.blocked();
219
+ // v4.1.5+ Path A — blocked path still needs the trace sink so
220
+ // the URL-provenance failure mode shows up in loop diagnostics.
221
+ try {
222
+ this.toolTraceAfterHook?.(call.id, call.name, call.arguments);
223
+ }
224
+ catch { /* defensive */ }
118
225
  return;
119
226
  }
227
+ // v4.3 Phase 3 — render a structured "agent needs human help"
228
+ // card when the browser observer detected a manual blocker
229
+ // (CAPTCHA / login / 2FA / verification / consent). Renders for
230
+ // ALL trail-row outcomes below — the blocker is independent of
231
+ // the tool's own success/fail signal. Inline placement gives
232
+ // the user immediate awareness; the model's next reply will
233
+ // explain in prose. Defensive: missing fields silently skip.
234
+ try {
235
+ this.renderBlockerCardIfPresent(result);
236
+ }
237
+ catch { /* defensive */ }
120
238
  // v4.1.4 reply-quality polish — Part 1.6. Helper used by ALL
121
239
  // outcome branches below so the activity indicator gets re-armed
122
240
  // for the gap that follows this tool (next tool, or final reply).
@@ -127,6 +245,14 @@ class CliCallbacks {
127
245
  this.afterEachToolHook?.(call.name);
128
246
  }
129
247
  catch { /* defensive */ }
248
+ // v4.1.5+ Path A — also fire the loop-trace `after` sink so the
249
+ // tracer can compute duration + capture args (hidden-from-trail
250
+ // tools still flow through here, by design — the trace must see
251
+ // them to detect lookup_tool_schema / skill_view loops).
252
+ try {
253
+ this.toolTraceAfterHook?.(call.id, call.name, call.arguments);
254
+ }
255
+ catch { /* defensive */ }
130
256
  };
131
257
  if (typeof err === 'string' && err.includes('URL provenance gate')) {
132
258
  handle.blocked();
@@ -301,12 +427,84 @@ Reply with ONE word: safe, caution, or dangerous.`;
301
427
  const label = files.length > 0 ? files.join(', ') : 'none';
302
428
  this.display.dim(`[memory] refreshed system prompt (${label})`);
303
429
  };
430
+ /**
431
+ * v4.1.6 Polish 2 — post-turn skill-proposal handler.
432
+ *
433
+ * chatSession calls this AFTER `agentTurn` has rendered the agent's
434
+ * reply on screen. Internally:
435
+ * 1. Reuses `promptSkillProposal` (the existing inquirer modal)
436
+ * to ask the user "Save this as a reusable skill? Yes/No".
437
+ * 2. If accepted AND a SkillTeacher reference is wired, calls
438
+ * `skillTeacher.handleProposal({...skipPrompt})` to build
439
+ * the markdown + persist via skillManager.
440
+ * 3. Returns the result so chatSession can surface a confirmation
441
+ * line if needed.
442
+ *
443
+ * Decoupled from the agent's `runConversation` so the inquirer no
444
+ * longer fires mid-turn (the v4.1.5 visual-smoke regression).
445
+ *
446
+ * Defensive — exceptions in any step return `{created: false,
447
+ * reason: 'error'}` so a misbehaving prompt or save can't break
448
+ * the chat loop. The inquirer modal itself catches input-stream
449
+ * exceptions via the existing try/catch in promptSkillProposal.
450
+ */
451
+ this.handleSkillProposal = async (proposal) => {
452
+ // Step 1: ask the user (reuses existing modal).
453
+ let accept;
454
+ try {
455
+ accept = await this.promptSkillProposal(proposal);
456
+ }
457
+ catch {
458
+ return { created: false, reason: 'prompt_error' };
459
+ }
460
+ if (!accept) {
461
+ return { created: false, reason: 'declined' };
462
+ }
463
+ // Step 2: persist via SkillTeacher when available. Test harnesses
464
+ // that don't wire a teacher just get the prompt without the save.
465
+ if (!this.skillTeacher) {
466
+ return { created: false, reason: 'no_skill_teacher_wired' };
467
+ }
468
+ try {
469
+ // Pass `promptUser: undefined` to bypass the modal in
470
+ // `handleProposal` (we already showed it above). The teacher
471
+ // sees tier === 'tier_3_propose' WITHOUT a prompt callback,
472
+ // which it interprets as `no_prompt_callback` and skips the
473
+ // save — so we need to call the create branch directly.
474
+ //
475
+ // SkillTeacher's tier-4 (auto) branch creates without
476
+ // prompting; we reuse that path by passing a stub that always
477
+ // returns true (user already accepted above).
478
+ const result = await this.skillTeacher.handleProposal(proposal, {
479
+ promptUser: async () => true,
480
+ });
481
+ return result;
482
+ }
483
+ catch (err) {
484
+ return {
485
+ created: false,
486
+ reason: `create_failed: ${err instanceof Error ? err.message : String(err)}`,
487
+ };
488
+ }
489
+ };
304
490
  this.display = opts.display;
305
491
  this.auxiliaryClient = opts.auxiliaryClient;
306
492
  this.verboseMode = opts.verboseMode ?? 'normal';
307
493
  this.promptsPromise = opts.promptModule
308
494
  ? Promise.resolve(opts.promptModule)
309
495
  : defaultPrompts();
496
+ this.skillTeacher = opts.skillTeacher;
497
+ }
498
+ /**
499
+ * v4.1.6 Polish 2 — late-wire the SkillTeacher reference. aidenCLI
500
+ * constructs CliCallbacks early (the approval engine needs it
501
+ * stitched in), but SkillTeacher is built later in the boot
502
+ * sequence after skillLoader / skillManager are ready. Call this
503
+ * once after both exist so `handleSkillProposal` can persist
504
+ * accepted proposals.
505
+ */
506
+ setSkillTeacher(teacher) {
507
+ this.skillTeacher = teacher;
310
508
  }
311
509
  /** Update verbose mode at runtime (wired to /verbose). */
312
510
  setVerboseMode(mode) {
@@ -337,6 +535,56 @@ Reply with ONE word: safe, caution, or dangerous.`;
337
535
  this.beforeToolHook = opts.beforeTool;
338
536
  this.afterEachToolHook = opts.afterEachTool;
339
537
  }
538
+ /**
539
+ * v4.1.5 Issue K — set/clear the phase-verb sink. chatSession
540
+ * registers a closure that captures the per-turn indicator handle
541
+ * and forwards calls to `indicator.setVerb(verb)`. Cleared between
542
+ * turns by passing `undefined`. Optional — non-indicator callers
543
+ * (test harnesses with stub displays) get no-op behaviour.
544
+ */
545
+ setPhaseVerbHook(fn) {
546
+ this.phaseVerbHook = fn;
547
+ }
548
+ /**
549
+ * v4.1.5+ Path A — register a per-turn tool-trace sink for the
550
+ * loop-trace logger. `before` fires with the call's id+name BEFORE
551
+ * the row writes; `after` fires post-execution with the same id +
552
+ * the call's args (for skill-name extraction in trace context).
553
+ * Cleared between turns by passing `undefined`.
554
+ *
555
+ * Separate from `setActivityIndicatorHooks` because the activity
556
+ * hook is name-only and fires for visible-trail purposes; this
557
+ * one captures FULL call data including hidden tools (which the
558
+ * trail suppresses via TRAIL_HIDE_TOOLS but the trace must see).
559
+ */
560
+ setToolTraceHook(opts) {
561
+ this.toolTraceBeforeHook = opts.before;
562
+ this.toolTraceAfterHook = opts.after;
563
+ }
564
+ /**
565
+ * v4.3 Phase 3 — render a manual-blocker card when the browser
566
+ * observer detected a CAPTCHA / login / 2FA / verification /
567
+ * consent surface on the page. Reuses the existing capabilityCard
568
+ * chrome via a `mapBlockerToCard` semantic mapping — no new layout
569
+ * code, no new dedicated card component.
570
+ *
571
+ * Defensive: silently skips when the field shape doesn't match
572
+ * (no browserState, no blocker, unrecognised kind). Never throws
573
+ * — caller wraps in try/catch defensively.
574
+ *
575
+ * The blocker info is structural data emitted by the observer
576
+ * HOC (`tools/v4/browser/_observer.ts`); the renderer reads it
577
+ * from `result.result.browserState.blocker` after every browser
578
+ * tool call. Inline placement gives users immediate awareness
579
+ * before the model's next reply lands.
580
+ */
581
+ renderBlockerCardIfPresent(result) {
582
+ const inner = (result?.result ?? null);
583
+ const blocker = inner?.browserState?.blocker;
584
+ if (!blocker)
585
+ return;
586
+ this.display.capabilityCard(mapBlockerToCard(blocker));
587
+ }
340
588
  }
341
589
  exports.CliCallbacks = CliCallbacks;
342
590
  // Tier-3.1 (v4.1-tier3.1): replaced 🟢/🟡/🔴 emoji badges with