aiden-runtime 4.1.5 → 4.6.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 +265 -847
- package/dist/api/server.js +32 -5
- package/dist/cli/v4/aidenCLI.js +536 -152
- package/dist/cli/v4/callbacks.js +170 -0
- package/dist/cli/v4/chatSession.js +245 -3
- package/dist/cli/v4/commands/_runtimeToggleHelpers.js +94 -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/fanout.js +42 -59
- package/dist/cli/v4/commands/help.js +13 -0
- package/dist/cli/v4/commands/index.js +35 -1
- package/dist/cli/v4/commands/mcp.js +80 -54
- package/dist/cli/v4/commands/plannerGuard.js +53 -0
- package/dist/cli/v4/commands/recovery.js +122 -0
- package/dist/cli/v4/commands/runs.js +223 -0
- package/dist/cli/v4/commands/sandbox.js +48 -0
- package/dist/cli/v4/commands/spawnPause.js +93 -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 +145 -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 +527 -5
- package/dist/core/v4/browserState.js +436 -0
- package/dist/core/v4/checkpoint.js +79 -0
- package/dist/core/v4/daemon/bootstrap.js +651 -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 +362 -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 +144 -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/providerFallback.js +35 -2
- package/dist/core/v4/recoveryReport.js +449 -0
- package/dist/core/v4/runtimeToggles.js +214 -0
- package/dist/core/v4/sandboxConfig.js +285 -0
- package/dist/core/v4/sandboxFs.js +316 -0
- package/dist/core/v4/selfimprovement/recoveryStore.js +307 -0
- package/dist/core/v4/selfimprovement/signatureBuilder.js +158 -0
- package/dist/core/v4/subagent/childBuilder.js +391 -0
- package/dist/core/v4/subagent/fanout.js +75 -51
- package/dist/core/v4/subagent/spawnPause.js +191 -0
- package/dist/core/v4/subagent/spawnSubAgent.js +310 -0
- package/dist/core/v4/suggestionCatalog.js +41 -0
- package/dist/core/v4/suggestionEngine.js +210 -0
- package/dist/core/v4/toolRegistry.js +37 -3
- 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/moat/plannerGuard.js +29 -0
- package/dist/providers/v4/anthropicAdapter.js +31 -3
- package/dist/providers/v4/chatCompletionsAdapter.js +26 -3
- package/dist/providers/v4/codexResponsesAdapter.js +25 -2
- package/dist/providers/v4/ollamaPromptToolsAdapter.js +57 -2
- 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 +88 -61
- 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 +7 -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/spawnSubAgentTool.js +334 -0
- package/dist/tools/v4/subagent/subagentFanout.js +54 -1
- 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 +13 -3
|
@@ -0,0 +1,378 @@
|
|
|
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
|
+
* cli/v4/commands/trigger.ts — v4.5 Phase 2: `aiden trigger` command set.
|
|
10
|
+
*
|
|
11
|
+
* Subcommands:
|
|
12
|
+
* aiden trigger add file --path <p> --name <n> [opts]
|
|
13
|
+
* Writes a `triggers` row with source='file' and a normalized
|
|
14
|
+
* spec_json. Daemon restart picks it up on next boot. Phase 5
|
|
15
|
+
* will add hot-reload.
|
|
16
|
+
*
|
|
17
|
+
* aiden trigger list — show all triggers + status
|
|
18
|
+
* aiden trigger show <id> — full spec + stats
|
|
19
|
+
* aiden trigger remove <id> — delete from triggers + cascade
|
|
20
|
+
* aiden trigger enable <id> — set triggers.enabled = 1
|
|
21
|
+
* aiden trigger disable <id> — set triggers.enabled = 0
|
|
22
|
+
* aiden trigger test <id> — fire a synthetic event
|
|
23
|
+
*/
|
|
24
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
25
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
26
|
+
};
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.runTriggerSubcommand = runTriggerSubcommand;
|
|
29
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
30
|
+
const node_crypto_1 = require("node:crypto");
|
|
31
|
+
const daemon_1 = require("../../../core/v4/daemon");
|
|
32
|
+
const paths_1 = require("../../../core/v4/paths");
|
|
33
|
+
const noopOut = (s) => { process.stdout.write(s); };
|
|
34
|
+
const noopErr = (s) => { process.stderr.write(s); };
|
|
35
|
+
/**
|
|
36
|
+
* Run an `aiden trigger <action>` invocation. Returns the desired
|
|
37
|
+
* process exit code so the CLI top-level can propagate.
|
|
38
|
+
*/
|
|
39
|
+
async function runTriggerSubcommand(action, args, argv, opts = {}) {
|
|
40
|
+
const out = opts.writeOut ?? noopOut;
|
|
41
|
+
const err = opts.writeErr ?? noopErr;
|
|
42
|
+
const aidenRoot = (0, paths_1.resolveAidenRoot)();
|
|
43
|
+
const db = (0, daemon_1.openDaemonDb)((0, daemon_1.daemonDbPath)(aidenRoot));
|
|
44
|
+
switch (action) {
|
|
45
|
+
case 'add': {
|
|
46
|
+
const kind = args[0];
|
|
47
|
+
if (kind === 'webhook') {
|
|
48
|
+
return runAddWebhook(db, argv, out, err);
|
|
49
|
+
}
|
|
50
|
+
if (kind === 'email') {
|
|
51
|
+
return runAddEmail(db, argv, out, err);
|
|
52
|
+
}
|
|
53
|
+
if (kind !== 'file') {
|
|
54
|
+
err(`trigger add: 'file', 'webhook', or 'email' kind required (got: ${kind ?? '<none>'})\n`);
|
|
55
|
+
return 2;
|
|
56
|
+
}
|
|
57
|
+
const a = argv;
|
|
58
|
+
if (!a.name || !a.paths || a.paths.length === 0) {
|
|
59
|
+
err('trigger add file: --name and at least one --path required\n');
|
|
60
|
+
return 2;
|
|
61
|
+
}
|
|
62
|
+
const spec = (0, daemon_1.parseFileWatcherSpec)({
|
|
63
|
+
paths: a.paths,
|
|
64
|
+
recursive: daemon_1.DEFAULT_FILE_WATCHER_SPEC.recursive,
|
|
65
|
+
includeGlobs: a.include,
|
|
66
|
+
excludeGlobs: a.exclude,
|
|
67
|
+
eventTypes: a.events,
|
|
68
|
+
debounceMs: a.debounceMs ?? daemon_1.DEFAULT_FILE_WATCHER_SPEC.debounceMs,
|
|
69
|
+
settleMs: a.settleMs ?? daemon_1.DEFAULT_FILE_WATCHER_SPEC.settleMs,
|
|
70
|
+
maxSettleMs: a.maxSettleMs ?? daemon_1.DEFAULT_FILE_WATCHER_SPEC.maxSettleMs,
|
|
71
|
+
maxQueueDepth: a.maxQueueDepth ?? daemon_1.DEFAULT_FILE_WATCHER_SPEC.maxQueueDepth,
|
|
72
|
+
ignoreTemp: a.noIgnoreTemp ? false : daemon_1.DEFAULT_FILE_WATCHER_SPEC.ignoreTemp,
|
|
73
|
+
contentHash: a.contentHash === true,
|
|
74
|
+
reconcile: a.reconcile ?? daemon_1.DEFAULT_FILE_WATCHER_SPEC.reconcile,
|
|
75
|
+
polling: a.polling === true ? { enabled: true } : undefined,
|
|
76
|
+
promptTemplate: a.promptTemplate,
|
|
77
|
+
});
|
|
78
|
+
// Resolve paths to absolute upfront so the watcher sees stable inputs.
|
|
79
|
+
spec.paths = spec.paths.map((p) => node_path_1.default.resolve(p));
|
|
80
|
+
const id = (0, node_crypto_1.randomUUID)();
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
db.prepare(`INSERT INTO triggers
|
|
83
|
+
(id, source, name, spec_json, enabled, prompt_template, deliver_only,
|
|
84
|
+
created_at, updated_at)
|
|
85
|
+
VALUES (?, 'file', ?, ?, ?, ?, 0, ?, ?)`).run(id, a.name, JSON.stringify(spec), a.disabled ? 0 : 1, spec.promptTemplate ?? null, now, now);
|
|
86
|
+
out(`trigger added: ${id} (${a.name})\n`);
|
|
87
|
+
out('Restart the daemon to activate the watcher.\n');
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
case 'list': {
|
|
91
|
+
const rows = db.prepare(`SELECT id, source, name, enabled, created_at FROM triggers ORDER BY created_at DESC`).all();
|
|
92
|
+
if (rows.length === 0) {
|
|
93
|
+
out('No triggers registered.\n');
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
for (const r of rows) {
|
|
97
|
+
const status = r.enabled ? 'enabled' : 'disabled';
|
|
98
|
+
out(`${r.id} ${r.source.padEnd(8)} ${status.padEnd(9)} ${r.name}\n`);
|
|
99
|
+
}
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
case 'show': {
|
|
103
|
+
const id = args[0];
|
|
104
|
+
if (!id) {
|
|
105
|
+
err('trigger show: id required\n');
|
|
106
|
+
return 2;
|
|
107
|
+
}
|
|
108
|
+
const row = db.prepare('SELECT * FROM triggers WHERE id = ?').get(id);
|
|
109
|
+
if (!row) {
|
|
110
|
+
err(`trigger show: not found: ${id}\n`);
|
|
111
|
+
return 1;
|
|
112
|
+
}
|
|
113
|
+
out(JSON.stringify({
|
|
114
|
+
id: row.id, source: row.source, name: row.name,
|
|
115
|
+
enabled: row.enabled === 1, created_at: row.created_at,
|
|
116
|
+
spec: JSON.parse(row.spec_json),
|
|
117
|
+
}, null, 2) + '\n');
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
case 'remove': {
|
|
121
|
+
const id = args[0];
|
|
122
|
+
if (!id) {
|
|
123
|
+
err('trigger remove: id required\n');
|
|
124
|
+
return 2;
|
|
125
|
+
}
|
|
126
|
+
const r = db.prepare('DELETE FROM triggers WHERE id = ?').run(id);
|
|
127
|
+
if (r.changes === 0) {
|
|
128
|
+
err(`trigger remove: not found: ${id}\n`);
|
|
129
|
+
return 1;
|
|
130
|
+
}
|
|
131
|
+
out(`trigger removed: ${id}\n`);
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
case 'enable':
|
|
135
|
+
case 'disable': {
|
|
136
|
+
const id = args[0];
|
|
137
|
+
if (!id) {
|
|
138
|
+
err(`trigger ${action}: id required\n`);
|
|
139
|
+
return 2;
|
|
140
|
+
}
|
|
141
|
+
const r = db.prepare('UPDATE triggers SET enabled = ?, updated_at = ? WHERE id = ?')
|
|
142
|
+
.run(action === 'enable' ? 1 : 0, Date.now(), id);
|
|
143
|
+
if (r.changes === 0) {
|
|
144
|
+
err(`trigger ${action}: not found: ${id}\n`);
|
|
145
|
+
return 1;
|
|
146
|
+
}
|
|
147
|
+
out(`trigger ${action}d: ${id}\n`);
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
case 'test': {
|
|
151
|
+
const id = args[0];
|
|
152
|
+
if (!id) {
|
|
153
|
+
err('trigger test: id required\n');
|
|
154
|
+
return 2;
|
|
155
|
+
}
|
|
156
|
+
const row = db.prepare('SELECT source FROM triggers WHERE id = ?').get(id);
|
|
157
|
+
if (!row) {
|
|
158
|
+
err(`trigger test: not found: ${id}\n`);
|
|
159
|
+
return 1;
|
|
160
|
+
}
|
|
161
|
+
const bus = (0, daemon_1.createTriggerBus)({ db });
|
|
162
|
+
const result = bus.insert({
|
|
163
|
+
source: row.source,
|
|
164
|
+
sourceKey: id,
|
|
165
|
+
payload: { synthetic: true, test: true, source: row.source },
|
|
166
|
+
});
|
|
167
|
+
out(`trigger test event inserted: id=${result.id} inserted=${result.inserted}\n`);
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
case 'logs': {
|
|
171
|
+
// v4.5 Phase 6 — tail recent run_events for runs whose sessionId
|
|
172
|
+
// starts with `trigger:<source>:<id>:`. Surfaces what the agent
|
|
173
|
+
// did on each fire (or what the deliverOnly stub logged).
|
|
174
|
+
const id = args[0];
|
|
175
|
+
if (!id) {
|
|
176
|
+
err('trigger logs: id required\n');
|
|
177
|
+
return 2;
|
|
178
|
+
}
|
|
179
|
+
const trig = db.prepare('SELECT id, source, name FROM triggers WHERE id = ?').get(id);
|
|
180
|
+
if (!trig) {
|
|
181
|
+
err(`trigger logs: not found: ${id}\n`);
|
|
182
|
+
return 1;
|
|
183
|
+
}
|
|
184
|
+
const prefix = `trigger:${trig.source}:${id}:`;
|
|
185
|
+
const rows = db.prepare(`SELECT re.ts, re.kind, re.payload, r.id AS run_id
|
|
186
|
+
FROM run_events re
|
|
187
|
+
JOIN runs r ON re.run_id = r.id
|
|
188
|
+
WHERE r.session_id LIKE ?
|
|
189
|
+
ORDER BY re.ts DESC
|
|
190
|
+
LIMIT 50`).all(`${prefix}%`);
|
|
191
|
+
if (rows.length === 0) {
|
|
192
|
+
out(`No run events recorded for trigger ${id} (${trig.name}).\n`);
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
195
|
+
out(`Last ${rows.length} event(s) for trigger ${id} (${trig.name}):\n`);
|
|
196
|
+
for (const r of rows.reverse()) { // chronological order for tail-like output
|
|
197
|
+
const ts = new Date(r.ts).toISOString().slice(0, 19) + 'Z';
|
|
198
|
+
const payloadStr = r.payload.length > 120 ? r.payload.slice(0, 120) + '…' : r.payload;
|
|
199
|
+
out(` [${ts}] run=${r.run_id} ${r.kind.padEnd(20)} ${payloadStr}\n`);
|
|
200
|
+
}
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
203
|
+
case 'runs': {
|
|
204
|
+
// v4.5 Phase 6 — list runs that originated from this trigger.
|
|
205
|
+
const id = args[0];
|
|
206
|
+
if (!id) {
|
|
207
|
+
err('trigger runs: id required\n');
|
|
208
|
+
return 2;
|
|
209
|
+
}
|
|
210
|
+
const trig = db.prepare('SELECT id, source, name FROM triggers WHERE id = ?').get(id);
|
|
211
|
+
if (!trig) {
|
|
212
|
+
err(`trigger runs: not found: ${id}\n`);
|
|
213
|
+
return 1;
|
|
214
|
+
}
|
|
215
|
+
const prefix = `trigger:${trig.source}:${id}:`;
|
|
216
|
+
const rows = db.prepare(`SELECT id, status, finish_reason, started_at, completed_at
|
|
217
|
+
FROM runs
|
|
218
|
+
WHERE session_id LIKE ?
|
|
219
|
+
ORDER BY started_at DESC
|
|
220
|
+
LIMIT 50`).all(`${prefix}%`);
|
|
221
|
+
if (rows.length === 0) {
|
|
222
|
+
out(`No runs recorded for trigger ${id} (${trig.name}).\n`);
|
|
223
|
+
return 0;
|
|
224
|
+
}
|
|
225
|
+
out(`${'runId'.padEnd(6)} ${'status'.padEnd(11)} ${'finish'.padEnd(11)} started\n`);
|
|
226
|
+
for (const r of rows) {
|
|
227
|
+
const started = new Date(r.started_at).toISOString().slice(0, 19) + 'Z';
|
|
228
|
+
out(`${String(r.id).padEnd(6)} ${r.status.padEnd(11)} ${(r.finish_reason ?? '-').padEnd(11)} ${started}\n`);
|
|
229
|
+
}
|
|
230
|
+
out(`\n${rows.length} run${rows.length === 1 ? '' : 's'} for trigger ${id}\n`);
|
|
231
|
+
return 0;
|
|
232
|
+
}
|
|
233
|
+
default:
|
|
234
|
+
err(`Unknown trigger action: ${action}\n`);
|
|
235
|
+
err('Actions: add, list, show <id>, remove <id>, enable <id>, disable <id>, test <id>, logs <id>, runs <id>\n');
|
|
236
|
+
return 2;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function runAddWebhook(db, argv, out, err) {
|
|
240
|
+
const a = argv;
|
|
241
|
+
if (!a.name) {
|
|
242
|
+
err('trigger add webhook: --name required\n');
|
|
243
|
+
return 2;
|
|
244
|
+
}
|
|
245
|
+
// Generate the secret if the user didn't supply one — 32 bytes
|
|
246
|
+
// base64url-encoded (43-character URL-safe string).
|
|
247
|
+
const secret = a.secret && a.secret.length > 0
|
|
248
|
+
? a.secret
|
|
249
|
+
: (0, node_crypto_1.randomBytes)(32).toString('base64url');
|
|
250
|
+
const spec = (0, daemon_1.parseWebhookSpec)({
|
|
251
|
+
name: a.name,
|
|
252
|
+
secret,
|
|
253
|
+
hmacFormat: a.hmac ?? daemon_1.DEFAULT_WEBHOOK_SPEC.hmacFormat,
|
|
254
|
+
allowedEvents: a.events,
|
|
255
|
+
rateLimit: { perMinute: a.rateLimit ?? daemon_1.DEFAULT_WEBHOOK_SPEC.rateLimit.perMinute },
|
|
256
|
+
maxBodyBytes: a.maxBodyBytes ?? daemon_1.DEFAULT_WEBHOOK_SPEC.maxBodyBytes,
|
|
257
|
+
idempotencyTtlMs: a.idempotencyTtlMs ?? daemon_1.DEFAULT_WEBHOOK_SPEC.idempotencyTtlMs,
|
|
258
|
+
deliverOnly: a.deliverOnly === true,
|
|
259
|
+
promptTemplate: a.promptTemplate,
|
|
260
|
+
publicBound: false,
|
|
261
|
+
});
|
|
262
|
+
const id = (0, node_crypto_1.randomUUID)();
|
|
263
|
+
const now = Date.now();
|
|
264
|
+
db.prepare(`INSERT INTO triggers
|
|
265
|
+
(id, source, name, spec_json, enabled, prompt_template, deliver_only,
|
|
266
|
+
created_at, updated_at)
|
|
267
|
+
VALUES (?, 'webhook', ?, ?, ?, ?, ?, ?, ?)`).run(id, a.name, JSON.stringify(spec), a.disabled ? 0 : 1, spec.promptTemplate ?? null, spec.deliverOnly ? 1 : 0, now, now);
|
|
268
|
+
const cfg = (0, daemon_1.getDaemonConfig)();
|
|
269
|
+
const host = process.env.AIDEN_DAEMON_BIND ?? '127.0.0.1';
|
|
270
|
+
out(`trigger added: ${id} (${a.name})\n`);
|
|
271
|
+
out(`webhook url: http://${host}:${cfg.port}/api/triggers/webhook/${id}\n`);
|
|
272
|
+
out(`hmac format: ${spec.hmacFormat}\n`);
|
|
273
|
+
out(`rate limit: ${spec.rateLimit.perMinute}/min\n`);
|
|
274
|
+
out(`secret: ${secret}\n`);
|
|
275
|
+
out(`⚠ Save this secret now — it cannot be retrieved later.\n`);
|
|
276
|
+
out(`Restart the daemon to activate the route.\n`);
|
|
277
|
+
return 0;
|
|
278
|
+
}
|
|
279
|
+
async function runAddEmail(db, argv, out, err) {
|
|
280
|
+
const a = argv;
|
|
281
|
+
if (!a.name) {
|
|
282
|
+
err('trigger add email: --label required\n');
|
|
283
|
+
return 2;
|
|
284
|
+
}
|
|
285
|
+
if (!a.host) {
|
|
286
|
+
err('trigger add email: --host required\n');
|
|
287
|
+
return 2;
|
|
288
|
+
}
|
|
289
|
+
if (!a.user) {
|
|
290
|
+
err('trigger add email: --user required\n');
|
|
291
|
+
return 2;
|
|
292
|
+
}
|
|
293
|
+
if (!a.password) {
|
|
294
|
+
err('trigger add email: --password required\n');
|
|
295
|
+
return 2;
|
|
296
|
+
}
|
|
297
|
+
if (!a.allowSenders || a.allowSenders.length === 0) {
|
|
298
|
+
err('trigger add email: at least one --allow-sender required.\n' +
|
|
299
|
+
' Examples: --allow-sender "user@example.com"\n' +
|
|
300
|
+
' --allow-sender "*@taracod.com"\n');
|
|
301
|
+
return 2;
|
|
302
|
+
}
|
|
303
|
+
// Build + validate the spec (this also compile-checks subject regexes).
|
|
304
|
+
let spec;
|
|
305
|
+
try {
|
|
306
|
+
spec = (0, daemon_1.parseEmailSpec)({
|
|
307
|
+
name: a.name,
|
|
308
|
+
imap: {
|
|
309
|
+
host: a.host,
|
|
310
|
+
port: a.port ?? daemon_1.DEFAULT_IMAP.port,
|
|
311
|
+
user: a.user,
|
|
312
|
+
password: a.password,
|
|
313
|
+
tls: a.noTls ? false : daemon_1.DEFAULT_IMAP.tls,
|
|
314
|
+
authTimeoutMs: daemon_1.DEFAULT_IMAP.authTimeoutMs,
|
|
315
|
+
},
|
|
316
|
+
mailbox: a.mailbox ?? daemon_1.DEFAULT_EMAIL_SPEC.mailbox,
|
|
317
|
+
pollIntervalMs: a.pollMs ?? daemon_1.DEFAULT_EMAIL_SPEC.pollIntervalMs,
|
|
318
|
+
allowedSenders: a.allowSenders,
|
|
319
|
+
allowedSubjectPatterns: a.allowSubjects,
|
|
320
|
+
maxBodyBytes: a.maxBodyBytes ?? daemon_1.DEFAULT_EMAIL_SPEC.maxBodyBytes,
|
|
321
|
+
promptTemplate: a.promptTemplate,
|
|
322
|
+
deliverOnly: a.deliverOnly === true,
|
|
323
|
+
attachmentPolicy: a.attachmentPolicy ?? daemon_1.DEFAULT_EMAIL_SPEC.attachmentPolicy,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
catch (e) {
|
|
327
|
+
err(`trigger add email: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
328
|
+
return 2;
|
|
329
|
+
}
|
|
330
|
+
// Q-P4-5 default: validate at add-time. Opt out with --no-validate.
|
|
331
|
+
if (!a.noValidate) {
|
|
332
|
+
out('Validating IMAP connectivity ...\n');
|
|
333
|
+
const conn = (0, daemon_1.createImapConnection)({
|
|
334
|
+
config: spec.imap,
|
|
335
|
+
log: (level, msg) => { if (level === 'error')
|
|
336
|
+
err(msg + '\n'); },
|
|
337
|
+
});
|
|
338
|
+
try {
|
|
339
|
+
await conn.connect();
|
|
340
|
+
try {
|
|
341
|
+
await conn.openMailbox(spec.mailbox);
|
|
342
|
+
}
|
|
343
|
+
catch (e) {
|
|
344
|
+
err(`IMAP connectivity validated, but mailbox open failed: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
345
|
+
await conn.disconnect();
|
|
346
|
+
return 1;
|
|
347
|
+
}
|
|
348
|
+
await conn.disconnect();
|
|
349
|
+
out(' ✓ connected, authenticated, mailbox opened\n');
|
|
350
|
+
}
|
|
351
|
+
catch (e) {
|
|
352
|
+
err(`IMAP connection failed: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
353
|
+
err('Use --no-validate to skip the pre-flight check and add the trigger anyway.\n');
|
|
354
|
+
return 1;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
out('Skipping IMAP connectivity validation (--no-validate).\n');
|
|
359
|
+
}
|
|
360
|
+
const id = (0, node_crypto_1.randomUUID)();
|
|
361
|
+
const now = Date.now();
|
|
362
|
+
db.prepare(`INSERT INTO triggers
|
|
363
|
+
(id, source, name, spec_json, enabled, prompt_template, deliver_only,
|
|
364
|
+
created_at, updated_at)
|
|
365
|
+
VALUES (?, 'email', ?, ?, ?, ?, ?, ?, ?)`).run(id, a.name, JSON.stringify(spec), a.disabled ? 0 : 1, spec.promptTemplate ?? null, spec.deliverOnly ? 1 : 0, now, now);
|
|
366
|
+
out(`trigger added: ${id} (${a.name})\n`);
|
|
367
|
+
out(`imap host: ${spec.imap.host}:${spec.imap.port}${spec.imap.tls ? ' (TLS)' : ''}\n`);
|
|
368
|
+
out(`mailbox: ${spec.mailbox}\n`);
|
|
369
|
+
out(`poll interval: ${spec.pollIntervalMs}ms\n`);
|
|
370
|
+
out(`allow-senders: ${spec.allowedSenders.join(', ')}\n`);
|
|
371
|
+
out(`⚠ Password stored in plaintext in daemon.db (chmod 600 on POSIX,\n`);
|
|
372
|
+
out(` user-private on Windows). Encryption-at-rest is deferred to v4.6+.\n`);
|
|
373
|
+
out(`Restart the daemon to activate the trigger.\n`);
|
|
374
|
+
// Note: runAddEmail returns a Promise<number>, so the outer switch must
|
|
375
|
+
// await it. (Already handled — runTriggerSubcommand is async.)
|
|
376
|
+
void node_crypto_1.randomBytes; // imported but only used by webhook helper
|
|
377
|
+
return 0;
|
|
378
|
+
}
|
|
@@ -26,6 +26,8 @@ exports.update = void 0;
|
|
|
26
26
|
const version_1 = require("../../../core/version");
|
|
27
27
|
const checkUpdate_1 = require("../../../core/v4/update/checkUpdate");
|
|
28
28
|
const executeInstall_1 = require("../../../core/v4/update/executeInstall");
|
|
29
|
+
const installMethodDetect_1 = require("../../../core/v4/update/installMethodDetect");
|
|
30
|
+
const skipState_1 = require("../../../core/v4/update/skipState");
|
|
29
31
|
async function printStatus(ctx) {
|
|
30
32
|
if (!ctx.paths) {
|
|
31
33
|
ctx.display.warn('/update needs Aiden user-data paths — try in a real session.');
|
|
@@ -85,18 +87,108 @@ async function runInstall(ctx) {
|
|
|
85
87
|
}
|
|
86
88
|
ctx.display.warn(result.error ?? 'Install failed (no error message).');
|
|
87
89
|
}
|
|
90
|
+
// ── v4.5 update system — skip + auto subcommands ───────────────────────────
|
|
91
|
+
async function runSkip(ctx) {
|
|
92
|
+
if (!ctx.paths) {
|
|
93
|
+
ctx.display.warn('/update skip needs Aiden user-data paths — try in a real session.');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const version = ctx.args[1];
|
|
97
|
+
if (!version || version.trim().length === 0) {
|
|
98
|
+
ctx.display.printError('Usage: /update skip <version>\n' +
|
|
99
|
+
'Example: /update skip 4.5.1\n' +
|
|
100
|
+
'Suppresses the boot prompt for that version + any older. Newer versions still prompt.');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Reject obviously-bad inputs early so users get a clear error.
|
|
104
|
+
try {
|
|
105
|
+
(0, checkUpdate_1.compareVersions)(version, version);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
ctx.display.printError(`/update skip: "${version}" is not a recognised version (expected MAJOR.MINOR.PATCH).`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
await (0, checkUpdate_1.updateCacheFile)(ctx.paths, (current) => (0, skipState_1.applySkip)(current, version));
|
|
113
|
+
ctx.display.write(`Skipping ${version}. Boot prompt will resume when a newer version ships.\n`);
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
ctx.display.warn(`/update skip: failed to persist (${e instanceof Error ? e.message : String(e)}).`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function runAuto(ctx) {
|
|
120
|
+
const sub = (ctx.args[1] ?? 'status').toLowerCase();
|
|
121
|
+
if (sub === 'status') {
|
|
122
|
+
const off = process.env.AIDEN_NO_UPDATE_CHECK === '1';
|
|
123
|
+
ctx.display.write(`Update auto-check: ${off ? 'OFF' : 'ON'} (source: ${off ? 'env' : 'default'})\n`);
|
|
124
|
+
if (off) {
|
|
125
|
+
ctx.display.dim(' unset AIDEN_NO_UPDATE_CHECK or run `/update auto on` to re-enable.');
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (sub === 'on' || sub === 'off') {
|
|
130
|
+
// The env var is the authoritative gate (matches existing Phase 20
|
|
131
|
+
// contract). `/update auto on` clears it for the current process;
|
|
132
|
+
// permanent off needs the user's shell to keep it set, since we
|
|
133
|
+
// shouldn't quietly write env vars to user shells. Document this
|
|
134
|
+
// clearly so users aren't confused.
|
|
135
|
+
if (sub === 'on') {
|
|
136
|
+
delete process.env.AIDEN_NO_UPDATE_CHECK;
|
|
137
|
+
ctx.display.write('Update auto-check: ON for this session.\n');
|
|
138
|
+
ctx.display.dim(' To persist: ensure AIDEN_NO_UPDATE_CHECK is unset in your shell init.');
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
process.env.AIDEN_NO_UPDATE_CHECK = '1';
|
|
142
|
+
ctx.display.write('Update auto-check: OFF for this session.\n');
|
|
143
|
+
ctx.display.dim(' To persist: set AIDEN_NO_UPDATE_CHECK=1 in your shell init.');
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
ctx.display.printError('Usage: /update auto on|off|status');
|
|
148
|
+
}
|
|
149
|
+
async function runClearSkip(ctx) {
|
|
150
|
+
if (!ctx.paths) {
|
|
151
|
+
ctx.display.warn('/update unskip needs Aiden user-data paths — try in a real session.');
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
await (0, checkUpdate_1.updateCacheFile)(ctx.paths, (current) => (0, skipState_1.clearSkip)(current));
|
|
156
|
+
ctx.display.write('Cleared skipped-version state. The boot prompt will re-fire next session.\n');
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
ctx.display.warn(`/update unskip: failed to persist (${e instanceof Error ? e.message : String(e)}).`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
88
162
|
exports.update = {
|
|
89
163
|
name: 'update',
|
|
90
|
-
description: 'Check
|
|
164
|
+
description: 'Check, install, or skip aiden-runtime updates.',
|
|
91
165
|
category: 'system',
|
|
92
166
|
icon: '⬆',
|
|
93
167
|
handler: async (ctx) => {
|
|
94
168
|
const sub = (ctx.args[0] ?? '').toLowerCase();
|
|
169
|
+
// Display install method on `/update` default so users see how
|
|
170
|
+
// their install will be updated before they trigger one.
|
|
95
171
|
if (sub === 'install') {
|
|
96
172
|
await runInstall(ctx);
|
|
173
|
+
return;
|
|
97
174
|
}
|
|
98
|
-
|
|
99
|
-
await
|
|
175
|
+
if (sub === 'skip') {
|
|
176
|
+
await runSkip(ctx);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (sub === 'unskip') {
|
|
180
|
+
await runClearSkip(ctx);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (sub === 'auto') {
|
|
184
|
+
await runAuto(ctx);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
// Default ('' / 'check') → status probe.
|
|
188
|
+
await printStatus(ctx);
|
|
189
|
+
if (ctx.paths) {
|
|
190
|
+
const method = (0, installMethodDetect_1.detectInstallMethod)();
|
|
191
|
+
ctx.display.dim(` install method: ${method.description}`);
|
|
100
192
|
}
|
|
101
193
|
},
|
|
102
194
|
};
|
|
@@ -0,0 +1,145 @@
|
|
|
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
|
+
* cli/v4/daemonAgentBuilder.ts — v4.5 Phase 7b.
|
|
10
|
+
*
|
|
11
|
+
* Builds the `AgentBuilder` closure the daemon dispatcher uses to
|
|
12
|
+
* construct a fresh AidenAgent per claimed trigger event. Captures
|
|
13
|
+
* the REPL's already-initialized provider resolver, tool registry,
|
|
14
|
+
* auxiliary client, prompt builder, and memory manager — REPL and
|
|
15
|
+
* daemon turns share these instances per Q-P7b-2(a). State that
|
|
16
|
+
* MUST stay isolated (memoryDirty Set, cachedSystemPrompt) lives
|
|
17
|
+
* on AidenAgent instances, and the closure creates a fresh agent
|
|
18
|
+
* every time the dispatcher invokes it.
|
|
19
|
+
*
|
|
20
|
+
* Scope cuts deliberately deferred (per Phase 7b audit greenlight):
|
|
21
|
+
* - plannerGuard / honestyEnforcement / skillTeacher / skillMiner
|
|
22
|
+
* are NOT wired into daemon-mode agents. They add ~3 LLM calls
|
|
23
|
+
* per turn and the daemon's job is "act on the trigger," not
|
|
24
|
+
* "improve the agent." Opt-in per-trigger lands in v4.6 if
|
|
25
|
+
* real-world use surfaces a need.
|
|
26
|
+
* - REPL-only spinner hooks (onMemoryRefreshStart/onPromptBuilt/
|
|
27
|
+
* onProviderRequestStart) are omitted; daemon has no display
|
|
28
|
+
* surface.
|
|
29
|
+
* - skillTeacherCallbacks.promptUser is omitted; daemon has no
|
|
30
|
+
* operator to ask.
|
|
31
|
+
*
|
|
32
|
+
* Strategy B (closure capture) — chosen over Strategy A (full
|
|
33
|
+
* factory refactor) to keep the REPL's existing agent construction
|
|
34
|
+
* untouched. The risk of regression in the REPL path is minimised
|
|
35
|
+
* because we don't rewrite ANY of the REPL's setup — the daemon
|
|
36
|
+
* closure just constructs a SECOND lightweight agent on demand
|
|
37
|
+
* from the same building blocks.
|
|
38
|
+
*/
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.buildDaemonAgentBuilder = buildDaemonAgentBuilder;
|
|
41
|
+
const aidenAgent_1 = require("../../core/v4/aidenAgent");
|
|
42
|
+
const approvalEngine_1 = require("../../moat/approvalEngine");
|
|
43
|
+
// ── Implementation ─────────────────────────────────────────────────────────
|
|
44
|
+
const DEFAULT_MAX_TURNS = 90;
|
|
45
|
+
/**
|
|
46
|
+
* Returns the AgentBuilder the daemon dispatcher consumes. The
|
|
47
|
+
* returned closure is invoked once per trigger event the
|
|
48
|
+
* dispatcher claims; each call constructs a fresh AidenAgent with
|
|
49
|
+
* daemon-flavored options.
|
|
50
|
+
*/
|
|
51
|
+
function buildDaemonAgentBuilder(deps) {
|
|
52
|
+
const log = deps.log ?? ((msg) => process.stderr.write(msg + '\n'));
|
|
53
|
+
const maxTurns = deps.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
54
|
+
return async (input) => {
|
|
55
|
+
const turnStartMs = Date.now();
|
|
56
|
+
// Resolve a provider adapter for the chosen (provider, model)
|
|
57
|
+
// pair. The resolver's resolve() returns an adapter wrapper;
|
|
58
|
+
// the underlying connection pool is shared per Q-P7b-2(a).
|
|
59
|
+
// If resolution fails (model not configured, OAuth expired),
|
|
60
|
+
// fall back to the REPL's existing adapter so the daemon turn
|
|
61
|
+
// still runs against SOMETHING usable.
|
|
62
|
+
let adapter;
|
|
63
|
+
try {
|
|
64
|
+
adapter = await deps.resolver.resolve({
|
|
65
|
+
providerId: input.resolvedModel.provider,
|
|
66
|
+
modelId: input.resolvedModel.model,
|
|
67
|
+
paths: deps.paths,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
adapter = deps.fallbackAdapter;
|
|
72
|
+
}
|
|
73
|
+
// Approval engine — fresh per turn so the session-scoped
|
|
74
|
+
// allowlist doesn't bleed across daemon turns.
|
|
75
|
+
const approvalEngine = new approvalEngine_1.ApprovalEngine('smart');
|
|
76
|
+
approvalEngine['callbacks'] = input.approvalCallbacks;
|
|
77
|
+
// Per-turn promptBuilderOptions — same snapshot the REPL uses,
|
|
78
|
+
// only the providerId/modelId fields overridden to reflect the
|
|
79
|
+
// daemon's resolved model. The MemoryManager is shared (read-
|
|
80
|
+
// only access via loadSnapshot()), so memory-dirty propagation
|
|
81
|
+
// is the REPL agent's concern; daemon agent reads a fresh
|
|
82
|
+
// snapshot on each `runConversation` call and discards.
|
|
83
|
+
const pbOpts = {
|
|
84
|
+
...deps.promptBuilderOptions,
|
|
85
|
+
providerId: input.resolvedModel.provider,
|
|
86
|
+
modelId: input.resolvedModel.model,
|
|
87
|
+
};
|
|
88
|
+
const agent = new aidenAgent_1.AidenAgent({
|
|
89
|
+
provider: adapter,
|
|
90
|
+
// v4.6 Phase 1 — 'daemon' context filter excludes REPL-only
|
|
91
|
+
// tools (`spawn_sub_agent` per Q6). Tools without an explicit
|
|
92
|
+
// `contexts` field stay visible to both REPL and daemon.
|
|
93
|
+
tools: deps.toolRegistry.getSchemas(undefined, 'daemon'),
|
|
94
|
+
toolExecutor: deps.toolExecutor,
|
|
95
|
+
maxTurns,
|
|
96
|
+
auxiliaryClient: deps.auxiliaryClient,
|
|
97
|
+
// v4.5 Phase 7 — explicit sessionId option threads per-trigger
|
|
98
|
+
// keying through to v4.4 docker session reuse + v4.3 browser
|
|
99
|
+
// observer + v4.2 TurnState.
|
|
100
|
+
sessionId: input.sessionId,
|
|
101
|
+
// Daemon mode wires the dispatcher's run_events hooks here.
|
|
102
|
+
// No display-side onToolCall wrapping — the dispatcher's
|
|
103
|
+
// emission is the only consumer.
|
|
104
|
+
onToolCall: input.hooks.onToolCall,
|
|
105
|
+
onBudgetWarning: input.hooks.onBudgetWarning,
|
|
106
|
+
promptBuilder: deps.promptBuilder,
|
|
107
|
+
promptBuilderOptions: pbOpts,
|
|
108
|
+
providerId: input.resolvedModel.provider,
|
|
109
|
+
modelId: input.resolvedModel.model,
|
|
110
|
+
resolveVerifiedFlag: deps.resolveVerifiedFlag,
|
|
111
|
+
resolveToolset: deps.resolveToolset,
|
|
112
|
+
resolveMutates: deps.resolveMutates,
|
|
113
|
+
// Memory snapshot refresh — daemon agent doesn't track dirty
|
|
114
|
+
// bits because each instance is short-lived; we provide the
|
|
115
|
+
// refresh callback so honestyEnforcement-style consumers (when
|
|
116
|
+
// we add them) can still rebuild.
|
|
117
|
+
refreshMemorySnapshot: () => deps.memoryManager.loadSnapshot(),
|
|
118
|
+
// Scope cuts (Phase 7b): no plannerGuard, no honestyEnforcement,
|
|
119
|
+
// no skillTeacher, no skillMiner. These add LLM calls + state
|
|
120
|
+
// that don't fit the daemon's "fire and act" pattern.
|
|
121
|
+
});
|
|
122
|
+
// Q-P7b-4(b) — minimal per-turn stdout line for tail-friendly
|
|
123
|
+
// operator debugging. Fires on builder exit; the dispatcher's
|
|
124
|
+
// `dispatcher:completed` run_event carries the same data in
|
|
125
|
+
// structured form for sqlite queries.
|
|
126
|
+
//
|
|
127
|
+
// We attach this as a post-construct log via the abort signal's
|
|
128
|
+
// 'abort' event; if the runner aborts the turn (budget watcher
|
|
129
|
+
// tripped), the line still surfaces. The dispatcher emits its
|
|
130
|
+
// own log; the goal here is a one-liner the operator can grep.
|
|
131
|
+
//
|
|
132
|
+
// Note: the actual finishReason + duration is the dispatcher's
|
|
133
|
+
// job to log after runConversation returns — we don't have
|
|
134
|
+
// that info here in the builder closure. Phase 7b ships the
|
|
135
|
+
// "starting turn" line; "completed turn" is handled inside
|
|
136
|
+
// realAgentRunner.ts.
|
|
137
|
+
// Q-P7b-4(b) stdout one-liner. sessionId follows
|
|
138
|
+
// `trigger:<source>:<sourceKey>:<hash>` so operators can grep by
|
|
139
|
+
// source. Per-turn duration + finishReason are logged separately
|
|
140
|
+
// by the dispatcher's realAgentRunner.ts when the turn completes.
|
|
141
|
+
log(`[daemon-turn] starting sessionId=${input.sessionId} model=${input.resolvedModel.provider}/${input.resolvedModel.model} policy=${input.approvalPolicy}`);
|
|
142
|
+
void turnStartMs; // kept for symmetry; the dispatcher computes its own duration
|
|
143
|
+
return agent;
|
|
144
|
+
};
|
|
145
|
+
}
|
|
@@ -30,7 +30,7 @@ exports.PREVIOUS_BUNDLED_SOULS = exports.DEFAULT_SOUL_MD = exports.BUNDLED_SOUL_
|
|
|
30
30
|
// <act_dont_ask>. ensureSoulMdSeeded compares this against the user's
|
|
31
31
|
// on-disk SOUL.md to decide whether to silent-replace (matches a prior
|
|
32
32
|
// bundled default) or preserve+notify (user-edited).
|
|
33
|
-
exports.BUNDLED_SOUL_VERSION = 'v4.
|
|
33
|
+
exports.BUNDLED_SOUL_VERSION = 'v4.6.0';
|
|
34
34
|
exports.DEFAULT_SOUL_MD = `You are Aiden — a local-first AI agent built by Shiva Deore at Taracod.
|
|
35
35
|
|
|
36
36
|
Identity:
|