aiden-runtime 4.1.5 → 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.
- package/README.md +250 -847
- package/dist/api/server.js +32 -5
- package/dist/cli/v4/aidenCLI.js +351 -53
- package/dist/cli/v4/callbacks.js +170 -0
- package/dist/cli/v4/chatSession.js +138 -3
- package/dist/cli/v4/commands/_runtimeToggleHelpers.js +92 -0
- package/dist/cli/v4/commands/browserDepth.js +45 -0
- package/dist/cli/v4/commands/cron.js +264 -0
- package/dist/cli/v4/commands/daemon.js +541 -0
- package/dist/cli/v4/commands/daemonStatus.js +253 -0
- package/dist/cli/v4/commands/help.js +7 -0
- package/dist/cli/v4/commands/index.js +20 -1
- package/dist/cli/v4/commands/runs.js +203 -0
- package/dist/cli/v4/commands/sandbox.js +48 -0
- package/dist/cli/v4/commands/suggestions.js +68 -0
- package/dist/cli/v4/commands/tce.js +41 -0
- package/dist/cli/v4/commands/trigger.js +378 -0
- package/dist/cli/v4/commands/update.js +95 -3
- package/dist/cli/v4/daemonAgentBuilder.js +142 -0
- package/dist/cli/v4/defaultSoul.js +1 -1
- package/dist/cli/v4/display/capabilityCard.js +26 -0
- package/dist/cli/v4/display.js +18 -8
- package/dist/cli/v4/replyRenderer.js +31 -23
- package/dist/cli/v4/updateBootPrompt.js +170 -0
- package/dist/core/playwrightBridge.js +129 -0
- package/dist/core/v4/aidenAgent.js +308 -4
- package/dist/core/v4/browserState.js +436 -0
- package/dist/core/v4/checkpoint.js +79 -0
- package/dist/core/v4/daemon/bootstrap.js +604 -0
- package/dist/core/v4/daemon/cleanShutdown.js +154 -0
- package/dist/core/v4/daemon/cron/cronBridge.js +126 -0
- package/dist/core/v4/daemon/cron/cronEmitter.js +173 -0
- package/dist/core/v4/daemon/cron/migration.js +199 -0
- package/dist/core/v4/daemon/cron/misfirePolicy.js +115 -0
- package/dist/core/v4/daemon/daemonConfig.js +90 -0
- package/dist/core/v4/daemon/db/connection.js +106 -0
- package/dist/core/v4/daemon/db/migrations.js +296 -0
- package/dist/core/v4/daemon/db/schema/v1.spec.js +18 -0
- package/dist/core/v4/daemon/dispatcher/agentRunner.js +98 -0
- package/dist/core/v4/daemon/dispatcher/budgetGate.js +127 -0
- package/dist/core/v4/daemon/dispatcher/daemonApproval.js +113 -0
- package/dist/core/v4/daemon/dispatcher/dailyBudgetTracker.js +120 -0
- package/dist/core/v4/daemon/dispatcher/dispatcher.js +389 -0
- package/dist/core/v4/daemon/dispatcher/fireRateLimiter.js +113 -0
- package/dist/core/v4/daemon/dispatcher/index.js +53 -0
- package/dist/core/v4/daemon/dispatcher/promptTemplate.js +95 -0
- package/dist/core/v4/daemon/dispatcher/realAgentRunner.js +356 -0
- package/dist/core/v4/daemon/dispatcher/resolveModel.js +93 -0
- package/dist/core/v4/daemon/dispatcher/sessionId.js +93 -0
- package/dist/core/v4/daemon/drain.js +156 -0
- package/dist/core/v4/daemon/eventLoopLag.js +73 -0
- package/dist/core/v4/daemon/health.js +159 -0
- package/dist/core/v4/daemon/idempotencyStore.js +204 -0
- package/dist/core/v4/daemon/index.js +179 -0
- package/dist/core/v4/daemon/instanceTracker.js +99 -0
- package/dist/core/v4/daemon/resourceRegistry.js +150 -0
- package/dist/core/v4/daemon/restartCode.js +32 -0
- package/dist/core/v4/daemon/restartFailureCounter.js +77 -0
- package/dist/core/v4/daemon/runStore.js +114 -0
- package/dist/core/v4/daemon/runtimeLock.js +167 -0
- package/dist/core/v4/daemon/signals.js +50 -0
- package/dist/core/v4/daemon/supervisor.js +272 -0
- package/dist/core/v4/daemon/triggerBus.js +279 -0
- package/dist/core/v4/daemon/triggers/email/allowlist.js +70 -0
- package/dist/core/v4/daemon/triggers/email/automatedSender.js +78 -0
- package/dist/core/v4/daemon/triggers/email/bodyExtractor.js +0 -0
- package/dist/core/v4/daemon/triggers/email/emailSeenStore.js +99 -0
- package/dist/core/v4/daemon/triggers/email/emailSpec.js +107 -0
- package/dist/core/v4/daemon/triggers/email/imapConnection.js +211 -0
- package/dist/core/v4/daemon/triggers/email/index.js +332 -0
- package/dist/core/v4/daemon/triggers/email/seenUids.js +60 -0
- package/dist/core/v4/daemon/triggers/fileObservationsStore.js +93 -0
- package/dist/core/v4/daemon/triggers/fileWatcher.js +253 -0
- package/dist/core/v4/daemon/triggers/fileWatcherSpec.js +88 -0
- package/dist/core/v4/daemon/triggers/fsIdentity.js +42 -0
- package/dist/core/v4/daemon/triggers/globMatcher.js +100 -0
- package/dist/core/v4/daemon/triggers/reconcile.js +206 -0
- package/dist/core/v4/daemon/triggers/settleStat.js +81 -0
- package/dist/core/v4/daemon/triggers/webhook.js +376 -0
- package/dist/core/v4/daemon/triggers/webhookDeliveriesStore.js +109 -0
- package/dist/core/v4/daemon/triggers/webhookIdempotency.js +72 -0
- package/dist/core/v4/daemon/triggers/webhookRateLimit.js +56 -0
- package/dist/core/v4/daemon/triggers/webhookSpec.js +76 -0
- package/dist/core/v4/daemon/triggers/webhookVerifier.js +128 -0
- package/dist/core/v4/daemon/types.js +15 -0
- package/dist/core/v4/dockerSession.js +461 -0
- package/dist/core/v4/dryRun.js +117 -0
- package/dist/core/v4/failureClassifier.js +779 -0
- package/dist/core/v4/recoveryReport.js +449 -0
- package/dist/core/v4/runtimeToggles.js +187 -0
- package/dist/core/v4/sandboxConfig.js +285 -0
- package/dist/core/v4/sandboxFs.js +316 -0
- package/dist/core/v4/suggestionCatalog.js +41 -0
- package/dist/core/v4/suggestionEngine.js +210 -0
- package/dist/core/v4/toolRegistry.js +18 -0
- package/dist/core/v4/turnState.js +587 -0
- package/dist/core/v4/update/checkUpdate.js +63 -3
- package/dist/core/v4/update/installMethodDetect.js +115 -0
- package/dist/core/v4/update/registryClient.js +121 -0
- package/dist/core/v4/update/skipState.js +75 -0
- package/dist/core/v4/verifier.js +448 -0
- package/dist/core/version.js +1 -1
- package/dist/tools/v4/browser/_observer.js +224 -0
- package/dist/tools/v4/browser/browserBlocker.js +396 -0
- package/dist/tools/v4/browser/browserClick.js +18 -1
- package/dist/tools/v4/browser/browserClose.js +18 -1
- package/dist/tools/v4/browser/browserExtract.js +5 -1
- package/dist/tools/v4/browser/browserFill.js +17 -1
- package/dist/tools/v4/browser/browserGetUrl.js +5 -1
- package/dist/tools/v4/browser/browserNavigate.js +16 -1
- package/dist/tools/v4/browser/browserScreenshot.js +5 -1
- package/dist/tools/v4/browser/browserScroll.js +18 -1
- package/dist/tools/v4/browser/browserType.js +17 -1
- package/dist/tools/v4/browser/captchaCheck.js +5 -1
- package/dist/tools/v4/executeCode.js +1 -0
- package/dist/tools/v4/files/fileCopy.js +56 -2
- package/dist/tools/v4/files/fileDelete.js +38 -1
- package/dist/tools/v4/files/fileList.js +12 -1
- package/dist/tools/v4/files/fileMove.js +59 -2
- package/dist/tools/v4/files/filePatch.js +43 -1
- package/dist/tools/v4/files/fileRead.js +12 -1
- package/dist/tools/v4/files/fileWrite.js +41 -1
- package/dist/tools/v4/index.js +71 -58
- package/dist/tools/v4/memory/memoryAdd.js +14 -0
- package/dist/tools/v4/memory/memoryRemove.js +14 -0
- package/dist/tools/v4/memory/memoryReplace.js +15 -0
- package/dist/tools/v4/memory/sessionSummary.js +12 -0
- package/dist/tools/v4/process/processKill.js +19 -0
- package/dist/tools/v4/process/processList.js +1 -0
- package/dist/tools/v4/process/processLogRead.js +1 -0
- package/dist/tools/v4/process/processSpawn.js +13 -0
- package/dist/tools/v4/process/processWait.js +1 -0
- package/dist/tools/v4/sessions/recallSession.js +1 -0
- package/dist/tools/v4/sessions/sessionList.js +1 -0
- package/dist/tools/v4/sessions/sessionSearch.js +1 -0
- package/dist/tools/v4/skills/lookupToolSchema.js +2 -0
- package/dist/tools/v4/skills/skillManage.js +13 -0
- package/dist/tools/v4/skills/skillView.js +1 -0
- package/dist/tools/v4/skills/skillsList.js +1 -0
- package/dist/tools/v4/subagent/subagentFanout.js +1 -0
- package/dist/tools/v4/system/aidenSelfUpdate.js +16 -0
- package/dist/tools/v4/system/appClose.js +13 -0
- package/dist/tools/v4/system/appInput.js +13 -0
- package/dist/tools/v4/system/appLaunch.js +13 -0
- package/dist/tools/v4/system/clipboardRead.js +1 -0
- package/dist/tools/v4/system/clipboardWrite.js +14 -0
- package/dist/tools/v4/system/mediaKey.js +12 -0
- package/dist/tools/v4/system/mediaSessions.js +1 -0
- package/dist/tools/v4/system/mediaTransport.js +13 -0
- package/dist/tools/v4/system/naturalEvents.js +1 -0
- package/dist/tools/v4/system/nowPlaying.js +1 -0
- package/dist/tools/v4/system/osProcessList.js +1 -0
- package/dist/tools/v4/system/screenshot.js +1 -0
- package/dist/tools/v4/system/systemInfo.js +1 -0
- package/dist/tools/v4/system/volumeSet.js +17 -0
- package/dist/tools/v4/terminal/shellExec.js +81 -9
- package/dist/tools/v4/web/deepResearch.js +1 -0
- package/dist/tools/v4/web/openUrl.js +1 -0
- package/dist/tools/v4/web/webFetch.js +1 -0
- package/dist/tools/v4/web/webPage.js +1 -0
- package/dist/tools/v4/web/webSearch.js +1 -0
- package/dist/tools/v4/web/youtubeSearch.js +1 -0
- package/package.json +7 -1
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 Shiva Deore (Taracod).
|
|
4
|
+
* Licensed under AGPL-3.0. See LICENSE for details.
|
|
5
|
+
*
|
|
6
|
+
* Aiden — local-first agent.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* core/v4/suggestionEngine.ts — v4.5 Phase 8b.
|
|
10
|
+
*
|
|
11
|
+
* Contextual one-time suggestions for the v4.4/v4.5 subsystems the
|
|
12
|
+
* user hasn't enabled yet. Fires when their CURRENT task would
|
|
13
|
+
* genuinely benefit:
|
|
14
|
+
*
|
|
15
|
+
* - sandbox → destructive shell pattern + sandbox is OFF
|
|
16
|
+
* - browser_depth → browser_* tool call + browser_depth is OFF
|
|
17
|
+
* - daemon_scheduling → user said "every day", "watch this folder",
|
|
18
|
+
* "when an email arrives", etc.
|
|
19
|
+
* - tce_recovery → recovery situation reached + TCE is OFF
|
|
20
|
+
* (lower priority; most users keep TCE on)
|
|
21
|
+
*
|
|
22
|
+
* Budget Q-P8b-1(a): 2 suggestions per session global. Each slot
|
|
23
|
+
* fires AT MOST ONCE per session. Resets on REPL restart.
|
|
24
|
+
*
|
|
25
|
+
* Dismissal Q-P8b-4(c) + Q-P8b-6(a):
|
|
26
|
+
* - Per-session: `dismissAll()` silences for the rest of the session.
|
|
27
|
+
* - Permanent: `runtime_toggles.suggestions = false` in config.yaml
|
|
28
|
+
* (slash command persists). Engine reads via runtimeToggles
|
|
29
|
+
* singleton — when the toggle reports OFF the engine treats every
|
|
30
|
+
* classification as "no tip".
|
|
31
|
+
*
|
|
32
|
+
* Pure module — no I/O. Display happens at the call site
|
|
33
|
+
* (`display.dim()` per audit Q-P8b-3). Engine only classifies +
|
|
34
|
+
* tracks state.
|
|
35
|
+
*/
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.buildSuggestionEngine = buildSuggestionEngine;
|
|
38
|
+
exports.getSuggestionEngine = getSuggestionEngine;
|
|
39
|
+
exports._resetSuggestionEngineForTests = _resetSuggestionEngineForTests;
|
|
40
|
+
const dangerousPatterns_1 = require("../../moat/dangerousPatterns");
|
|
41
|
+
const runtimeToggles_1 = require("./runtimeToggles");
|
|
42
|
+
const suggestionCatalog_1 = require("./suggestionCatalog");
|
|
43
|
+
// ── Daemon-scheduling regex (Q-P8b-2a — simple keyword) ────────────────────
|
|
44
|
+
const SCHEDULING_PATTERNS = [
|
|
45
|
+
/\b(every|each)\s+(day|hour|minute|week|morning|evening|monday|tuesday|wednesday|thursday|friday|saturday|sunday)\b/i,
|
|
46
|
+
/\b(daily|hourly|weekly|nightly)\b/i,
|
|
47
|
+
/\bat\s+\d{1,2}(:\d{2})?\s*(am|pm)?\s+(every|each)\b/i,
|
|
48
|
+
/\bwatch\s+(this|the)?\s*(folder|directory|path)\b/i,
|
|
49
|
+
/\bmonitor\s+(changes|files?|directory|folder)\b/i,
|
|
50
|
+
/\bwhen\s+(an?\s+)?(email|webhook|file|message)\s+(arrives|comes|is\s+received|drops)\b/i,
|
|
51
|
+
/\b(remind|alert|notify)\s+me\s+(when|to|every)\b/i,
|
|
52
|
+
/\bset\s+up\s+(a\s+)?(cron|schedule|trigger|watcher|webhook)\b/i,
|
|
53
|
+
];
|
|
54
|
+
// ── System-path heuristic for file_* tool sandbox tips ─────────────────────
|
|
55
|
+
const SYSTEM_PATH_PATTERNS = [
|
|
56
|
+
/^\/etc\b/i,
|
|
57
|
+
/^\/System\b/i,
|
|
58
|
+
/^\/Library\/System\b/i,
|
|
59
|
+
/^\/usr\/(s)?bin\b/i,
|
|
60
|
+
/^[A-Z]:\\Windows\b/i,
|
|
61
|
+
/^[A-Z]:\\Program\s+Files\b/i,
|
|
62
|
+
/\\System32\\/i,
|
|
63
|
+
];
|
|
64
|
+
function isSystemPath(p) {
|
|
65
|
+
if (typeof p !== 'string' || p.length === 0)
|
|
66
|
+
return false;
|
|
67
|
+
return SYSTEM_PATH_PATTERNS.some((r) => r.test(p));
|
|
68
|
+
}
|
|
69
|
+
// ── Classifiers (pure) ─────────────────────────────────────────────────────
|
|
70
|
+
/** sandbox slot — destructive shell or system-path write. */
|
|
71
|
+
function classifySandbox(call) {
|
|
72
|
+
const args = (call.arguments ?? {});
|
|
73
|
+
if (call.name === 'shell_exec') {
|
|
74
|
+
const cmd = typeof args.command === 'string' ? args.command : '';
|
|
75
|
+
if (cmd.length === 0)
|
|
76
|
+
return false;
|
|
77
|
+
const cls = (0, dangerousPatterns_1.classifyCommand)(cmd);
|
|
78
|
+
return cls.tier === 'caution' || cls.tier === 'dangerous';
|
|
79
|
+
}
|
|
80
|
+
if (call.name === 'file_write' || call.name === 'file_delete'
|
|
81
|
+
|| call.name === 'file_move' || call.name === 'file_patch') {
|
|
82
|
+
const target = typeof args.path === 'string' ? args.path
|
|
83
|
+
: typeof args.target === 'string' ? args.target
|
|
84
|
+
: '';
|
|
85
|
+
return isSystemPath(target);
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
/** browser_depth slot — any browser_* tool fires the suggestion when off. */
|
|
90
|
+
function classifyBrowserDepth(call) {
|
|
91
|
+
return call.name.startsWith('browser_');
|
|
92
|
+
}
|
|
93
|
+
/** daemon_scheduling slot — keyword regex on initial message. */
|
|
94
|
+
function classifySchedulingIntent(message) {
|
|
95
|
+
if (typeof message !== 'string' || message.length < 6)
|
|
96
|
+
return false;
|
|
97
|
+
return SCHEDULING_PATTERNS.some((r) => r.test(message));
|
|
98
|
+
}
|
|
99
|
+
// ── Singleton ──────────────────────────────────────────────────────────────
|
|
100
|
+
const DEFAULT_BUDGET_PER_SESSION = 2;
|
|
101
|
+
function buildSuggestionEngine(opts = {}) {
|
|
102
|
+
const budget = opts.budgetPerSession ?? DEFAULT_BUDGET_PER_SESSION;
|
|
103
|
+
const getRT = opts.runtimeTogglesGetter ?? (() => (0, runtimeToggles_1.getRuntimeToggles)());
|
|
104
|
+
const firedSlots = new Set();
|
|
105
|
+
let dismissedSession = false;
|
|
106
|
+
function permanentlyOff() {
|
|
107
|
+
try {
|
|
108
|
+
// 'suggestions' is wired as a runtime toggle key via Phase 8b
|
|
109
|
+
// schema extension. When the user has typed `/suggestions off`
|
|
110
|
+
// (persisted to config.yaml runtime_toggles.suggestions=false),
|
|
111
|
+
// the toggle reports off and we skip every classification.
|
|
112
|
+
return !getRT().isEnabled('suggestions');
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// Defensive — if the toggle key isn't registered yet we treat
|
|
116
|
+
// suggestions as on (the default).
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function canFire(slot) {
|
|
121
|
+
if (dismissedSession)
|
|
122
|
+
return false;
|
|
123
|
+
if (permanentlyOff())
|
|
124
|
+
return false;
|
|
125
|
+
if (firedSlots.has(slot))
|
|
126
|
+
return false;
|
|
127
|
+
if (firedSlots.size >= budget)
|
|
128
|
+
return false;
|
|
129
|
+
// Only suggest when the relevant subsystem is OFF — otherwise the
|
|
130
|
+
// tip is noise. Mapping: slot → underlying runtimeToggles key.
|
|
131
|
+
try {
|
|
132
|
+
switch (slot) {
|
|
133
|
+
case 'sandbox':
|
|
134
|
+
if (getRT().isEnabled('sandbox'))
|
|
135
|
+
return false;
|
|
136
|
+
break;
|
|
137
|
+
case 'browser_depth':
|
|
138
|
+
if (getRT().isEnabled('browser_depth'))
|
|
139
|
+
return false;
|
|
140
|
+
break;
|
|
141
|
+
case 'tce_recovery':
|
|
142
|
+
if (getRT().isEnabled('tce'))
|
|
143
|
+
return false;
|
|
144
|
+
break;
|
|
145
|
+
case 'daemon_scheduling':
|
|
146
|
+
// No matching toggle — daemon mode is a process-level
|
|
147
|
+
// boolean (AIDEN_DAEMON). Suggest only when daemon is off,
|
|
148
|
+
// which we detect by reading the env var (the daemon
|
|
149
|
+
// toggle isn't part of runtime_toggles by design).
|
|
150
|
+
if (process.env.AIDEN_DAEMON === '1')
|
|
151
|
+
return false;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch { /* defensive */ }
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
function build(slot) {
|
|
159
|
+
return { slot, message: (0, suggestionCatalog_1.suggestionMessageFor)(slot) };
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
checkToolCall(call) {
|
|
163
|
+
if (!call || typeof call.name !== 'string')
|
|
164
|
+
return null;
|
|
165
|
+
if (classifyBrowserDepth(call) && canFire('browser_depth')) {
|
|
166
|
+
return build('browser_depth');
|
|
167
|
+
}
|
|
168
|
+
if (classifySandbox(call) && canFire('sandbox')) {
|
|
169
|
+
return build('sandbox');
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
},
|
|
173
|
+
checkInitialMessage(message) {
|
|
174
|
+
if (classifySchedulingIntent(message) && canFire('daemon_scheduling')) {
|
|
175
|
+
return build('daemon_scheduling');
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
},
|
|
179
|
+
recordFired(slot) {
|
|
180
|
+
firedSlots.add(slot);
|
|
181
|
+
},
|
|
182
|
+
dismissAll() {
|
|
183
|
+
dismissedSession = true;
|
|
184
|
+
},
|
|
185
|
+
snapshot() {
|
|
186
|
+
return {
|
|
187
|
+
firedSlots: [...firedSlots],
|
|
188
|
+
dismissedSession,
|
|
189
|
+
permanentlyOff: permanentlyOff(),
|
|
190
|
+
budgetRemaining: Math.max(0, budget - firedSlots.size),
|
|
191
|
+
};
|
|
192
|
+
},
|
|
193
|
+
_resetForTests() {
|
|
194
|
+
firedSlots.clear();
|
|
195
|
+
dismissedSession = false;
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
// ── Process-wide singleton ─────────────────────────────────────────────────
|
|
200
|
+
let _singleton = null;
|
|
201
|
+
function getSuggestionEngine() {
|
|
202
|
+
if (!_singleton)
|
|
203
|
+
_singleton = buildSuggestionEngine();
|
|
204
|
+
return _singleton;
|
|
205
|
+
}
|
|
206
|
+
function _resetSuggestionEngineForTests() {
|
|
207
|
+
if (_singleton)
|
|
208
|
+
_singleton._resetForTests();
|
|
209
|
+
_singleton = null;
|
|
210
|
+
}
|
|
@@ -136,12 +136,30 @@ class ToolRegistry {
|
|
|
136
136
|
riskTier = c.tier;
|
|
137
137
|
reason = c.reason;
|
|
138
138
|
}
|
|
139
|
+
// v4.4 Phase 4 — dangerous-tier auto-preview. Surface
|
|
140
|
+
// "what would happen if you say yes" to the approval prompt.
|
|
141
|
+
// Effective tier is the handler annotation (Phase 1 floor)
|
|
142
|
+
// OR the classifier escalation above (whichever is higher).
|
|
143
|
+
let preview;
|
|
144
|
+
const effectiveTier = (riskTier === 'dangerous' || handler.riskTier === 'dangerous')
|
|
145
|
+
? 'dangerous' : (riskTier ?? handler.riskTier);
|
|
146
|
+
if (effectiveTier === 'dangerous' && typeof handler.buildPreview === 'function') {
|
|
147
|
+
try {
|
|
148
|
+
preview = await handler.buildPreview(args, context);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Preview is best-effort. A bad preview never blocks
|
|
152
|
+
// the underlying approval decision.
|
|
153
|
+
preview = undefined;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
139
156
|
const allowed = await context.approvalEngine.checkApproval({
|
|
140
157
|
toolName: call.name,
|
|
141
158
|
category: handler.category,
|
|
142
159
|
args,
|
|
143
160
|
riskTier,
|
|
144
161
|
reason,
|
|
162
|
+
preview,
|
|
145
163
|
});
|
|
146
164
|
if (!allowed) {
|
|
147
165
|
return {
|