aiden-runtime 4.7.0 → 4.8.1
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 +12 -1
- package/dist/cli/v4/aidenCLI.js +40 -5
- package/dist/cli/v4/callbacks.js +52 -31
- package/dist/cli/v4/chatSession.js +55 -8
- package/dist/cli/v4/commands/help.js +22 -11
- package/dist/cli/v4/commands/runs.js +42 -24
- package/dist/cli/v4/commands/skills.js +15 -17
- package/dist/cli/v4/commands/update.js +14 -2
- package/dist/cli/v4/commands/usage.js +17 -5
- package/dist/cli/v4/daemonAgentBuilder.js +1 -0
- package/dist/cli/v4/design/tokens.js +265 -0
- package/dist/cli/v4/display/framedPanel.js +116 -0
- package/dist/cli/v4/display/toolTrail.js +2 -2
- package/dist/cli/v4/display.js +489 -164
- package/dist/cli/v4/onboarding/disclaimer.js +42 -10
- package/dist/cli/v4/onboarding/loading.js +24 -1
- package/dist/cli/v4/onboarding/successScreen.js +17 -8
- package/dist/cli/v4/pasteIntercept.js +214 -70
- package/dist/cli/v4/replyRenderer.js +213 -58
- package/dist/cli/v4/setupWizard.js +19 -2
- package/dist/cli/v4/skinEngine.js +13 -0
- package/dist/cli/v4/table.js +65 -8
- package/dist/core/v4/aidenAgent.js +23 -0
- package/dist/core/v4/auxiliaryClient.js +46 -13
- package/dist/core/v4/daemon/dispatcher/realAgentRunner.js +13 -8
- package/dist/core/v4/promptBuilder.js +51 -0
- package/dist/core/v4/subagent/childBuilder.js +1 -0
- package/dist/core/v4/subagent/spawnSubAgent.js +7 -1
- package/dist/core/v4/ui/banner.js +16 -16
- package/dist/core/v4/update/executeInstall.js +10 -6
- package/dist/core/v4/update/installMethodDetect.js +7 -0
- package/dist/core/version.js +67 -2
- package/dist/moat/approvalEngine.js +14 -0
- package/dist/tools/v4/index.js +54 -0
- package/dist/tools/v4/subagent/spawnSubAgentTool.js +23 -0
- package/package.json +1 -3
|
@@ -177,14 +177,19 @@ function createRealAgentRunner(opts) {
|
|
|
177
177
|
let invocationError = null;
|
|
178
178
|
try {
|
|
179
179
|
result = await agent.runConversation(history, {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
180
|
+
// The agent honours its own abort signal via per-tool aborts;
|
|
181
|
+
// tools that respect AbortSignal (shell_exec, fetch_*) will
|
|
182
|
+
// bail when perTurnWatcher trips.
|
|
183
|
+
//
|
|
184
|
+
// Note: runConversation doesn't currently take an abort
|
|
185
|
+
// signal in its options — the budget watcher is best-effort
|
|
186
|
+
// observability via tally(). Future enhancement: thread the
|
|
187
|
+
// signal into the loop body via options.
|
|
188
|
+
//
|
|
189
|
+
// v4.8.0 Phase 2.2 — uiOnly events on the daemon side are
|
|
190
|
+
// dropped here. Phase 2.4 will serialize them into the
|
|
191
|
+
// dispatcher's run_events stream.
|
|
192
|
+
onUiEvent: () => { },
|
|
188
193
|
});
|
|
189
194
|
// Stamp the actual token usage onto the watcher for the
|
|
190
195
|
// post-turn snapshot below.
|
|
@@ -131,6 +131,48 @@ const EXECUTION_DISCIPLINE_PROSE = [
|
|
|
131
131
|
'result. When the user requests an action, take it. When the user requests',
|
|
132
132
|
'discussion, discuss.',
|
|
133
133
|
].join('\n');
|
|
134
|
+
/**
|
|
135
|
+
* v4.8.0 Phase 2.6 — UI events nudge. Without this, the model only
|
|
136
|
+
* emits ui_* tools when explicitly told to (e.g. "call ui_task_update
|
|
137
|
+
* with ..."). With it, events fire during normal multi-step work —
|
|
138
|
+
* research, file creation, test runs, command execution. Always-on:
|
|
139
|
+
* every model that sees the ui_* tools benefits.
|
|
140
|
+
*/
|
|
141
|
+
const UI_EVENTS_GUIDANCE = [
|
|
142
|
+
'## UI events',
|
|
143
|
+
'',
|
|
144
|
+
'When doing multi-step work, emit structured progress signals INSTEAD OF',
|
|
145
|
+
'writing them as text. The user sees these as inline rows separate from',
|
|
146
|
+
'your prose reply.',
|
|
147
|
+
'',
|
|
148
|
+
'WRONG (do NOT do this):',
|
|
149
|
+
' "✓ Done — found 3 results"',
|
|
150
|
+
' "⟳ Searching the web..."',
|
|
151
|
+
' "Created hello.py"',
|
|
152
|
+
'',
|
|
153
|
+
'RIGHT:',
|
|
154
|
+
' ui_task_update {task_id, label, status: "running"}',
|
|
155
|
+
' ui_task_done {task_id, status: "success", summary}',
|
|
156
|
+
' ui_artifact_created {path, kind: "file", preview}',
|
|
157
|
+
'',
|
|
158
|
+
'When to fire each:',
|
|
159
|
+
'- ui_task_update + ui_task_done for any multi-step task (pair them by task_id)',
|
|
160
|
+
'- ui_command_result after shell_exec when the output is interesting',
|
|
161
|
+
'- ui_test_result after running tests',
|
|
162
|
+
'- ui_toast for transient notices (e.g. "switched to dark mode")',
|
|
163
|
+
'- ui_artifact_created when you create or modify a file/skill',
|
|
164
|
+
'- ui_approval_request fires automatically for risky tools — NEVER emit it manually',
|
|
165
|
+
'',
|
|
166
|
+
'Markdown text in your reply is for explanation, not status. Status goes',
|
|
167
|
+
'through events. Skip events entirely on single-shot queries that aren\'t',
|
|
168
|
+
'multi-step work.',
|
|
169
|
+
'',
|
|
170
|
+
'## Comparison formatting',
|
|
171
|
+
'',
|
|
172
|
+
'For comparison requests, prefer sectioned lists or narrow tables (3 cols max).',
|
|
173
|
+
'Wide tables (4+ columns or cells over ~30 chars) render imperfectly in the',
|
|
174
|
+
'CLI grid — break long content into sections with headers + bullets instead.',
|
|
175
|
+
].join('\n');
|
|
134
176
|
/**
|
|
135
177
|
* Llama-3.3-specific tool-call format guard. Adapter-side recovery picks
|
|
136
178
|
* up failures, but we'd rather avoid the 400 round-trip.
|
|
@@ -358,6 +400,15 @@ class PromptBuilder {
|
|
|
358
400
|
optional: true,
|
|
359
401
|
});
|
|
360
402
|
}
|
|
403
|
+
// ── 6.6. UI events nudge (v4.8.0 Phase 2.6) ───────────────────────
|
|
404
|
+
// Unconditional like execution discipline — every model that sees
|
|
405
|
+
// the ui_* tools benefits. Teaches structured-event emission for
|
|
406
|
+
// multi-step work instead of relying on text status formatting.
|
|
407
|
+
slots.push({
|
|
408
|
+
name: 'uiEvents',
|
|
409
|
+
content: UI_EVENTS_GUIDANCE,
|
|
410
|
+
optional: true,
|
|
411
|
+
});
|
|
361
412
|
// ── 7. Iteration budget ───────────────────────────────────────────
|
|
362
413
|
if (opts.initialBudget) {
|
|
363
414
|
const { used, max } = opts.initialBudget;
|
|
@@ -199,6 +199,7 @@ function buildChildAgent(deps, input) {
|
|
|
199
199
|
resolveVerifiedFlag: deps.resolveVerifiedFlag,
|
|
200
200
|
resolveToolset: deps.resolveToolset,
|
|
201
201
|
resolveMutates: deps.resolveMutates,
|
|
202
|
+
resolveUiOnly: deps.resolveUiOnly,
|
|
202
203
|
honestyEnforcement: childHonestyEnforcement,
|
|
203
204
|
onToolCall,
|
|
204
205
|
// iterationBudgetInjection inherits the default (true) — child
|
|
@@ -190,7 +190,13 @@ async function spawnSubAgent(spec, deps, ctx) {
|
|
|
190
190
|
let tokensIn = 0;
|
|
191
191
|
let tokensOut = 0;
|
|
192
192
|
try {
|
|
193
|
-
const result = await agentBundle.agent.runConversation(agentBundle.history, {
|
|
193
|
+
const result = await agentBundle.agent.runConversation(agentBundle.history, {
|
|
194
|
+
signal: childCtrl.signal,
|
|
195
|
+
// v4.8.0 Phase 2.2 — uiOnly events from a subagent are
|
|
196
|
+
// dropped. Subagents have no chat surface; the parent
|
|
197
|
+
// assembles their summary. Stub stays a no-op forever.
|
|
198
|
+
onUiEvent: () => { },
|
|
199
|
+
});
|
|
194
200
|
apiCalls = result.turnCount; // one provider call per turn
|
|
195
201
|
tokensIn = result.totalUsage.inputTokens;
|
|
196
202
|
tokensOut = result.totalUsage.outputTokens;
|
|
@@ -90,29 +90,29 @@ function renderBanner(opts) {
|
|
|
90
90
|
out.push('');
|
|
91
91
|
return out.join('\n') + '\n';
|
|
92
92
|
}
|
|
93
|
-
//
|
|
93
|
+
// v4.8.0 Slice 10b — wide layout flows the AIDEN art without the
|
|
94
|
+
// heavy `╔══╗` frame (legacy chrome). The art carries its own
|
|
95
|
+
// visual weight as the boot-card identity anchor; framing it
|
|
96
|
+
// inside a closed box collides with the asymmetric orange-bar
|
|
97
|
+
// language used by every other v4.8.0 surface.
|
|
98
|
+
//
|
|
99
|
+
// v4.8.0 Slice 10c — emit raw 24-bit truecolor for the AIDEN art
|
|
100
|
+
// instead of routing through `c.primary` (which depth-detects via
|
|
101
|
+
// theme.ts and degrades to 256-color or 16-color when COLORTERM is
|
|
102
|
+
// unset — common on Windows ConPTY). Result on those terminals was
|
|
103
|
+
// a washed-out / grey AIDEN that didn't match the boot card's
|
|
104
|
+
// skinEngine-painted brand orange. Forcing truecolor here brings
|
|
105
|
+
// disclaimer + setupWizard banner in line with the boot card.
|
|
106
|
+
const ORANGE_ON = '\x1b[38;2;255;107;53m';
|
|
107
|
+
const COLOR_OFF = '\x1b[39m';
|
|
94
108
|
const inner = w - 2;
|
|
95
109
|
const artPad = Math.max(0, Math.floor((inner - ART_WIDTH) / 2));
|
|
96
|
-
const framed = opts.framed !== false;
|
|
97
|
-
const horiz = '═'.repeat(inner);
|
|
98
|
-
const top = framed ? theme_1.c.rule(`╔${horiz}╗`) : '';
|
|
99
|
-
const bottom = framed ? theme_1.c.rule(`╚${horiz}╝`) : '';
|
|
100
|
-
const blank = framed
|
|
101
|
-
? `${theme_1.c.rule('║')}${' '.repeat(inner)}${theme_1.c.rule('║')}`
|
|
102
|
-
: ' '.repeat(w);
|
|
103
110
|
const lines = [];
|
|
104
111
|
lines.push('');
|
|
105
|
-
if (framed)
|
|
106
|
-
lines.push(top);
|
|
107
|
-
lines.push(blank);
|
|
108
112
|
for (const row of AIDEN_ART) {
|
|
109
113
|
const padded = rpad(' '.repeat(artPad) + row, inner);
|
|
110
|
-
|
|
111
|
-
lines.push(framed ? `${theme_1.c.rule('║')}${coloured}${theme_1.c.rule('║')}` : ` ${coloured}`);
|
|
114
|
+
lines.push(` ${ORANGE_ON}${padded}${COLOR_OFF}`);
|
|
112
115
|
}
|
|
113
|
-
lines.push(blank);
|
|
114
|
-
if (framed)
|
|
115
|
-
lines.push(bottom);
|
|
116
116
|
lines.push('');
|
|
117
117
|
lines.push(' ' + (0, theme_1.dim)(theme_1.c.muted(versionLine)));
|
|
118
118
|
lines.push('');
|
|
@@ -66,17 +66,21 @@ async function executeInstall(opts = {}) {
|
|
|
66
66
|
const platform = opts.platform ?? process.platform;
|
|
67
67
|
return new Promise((resolve) => {
|
|
68
68
|
const args = ['install', '-g', packageSpec];
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
69
|
+
// v4.8.1 Slice 2 — drop `shell: true`. Node 20+ emits
|
|
70
|
+
// `DeprecationWarning: Passing args to a child process with shell
|
|
71
|
+
// option true can lead to security vulnerabilities` whenever
|
|
72
|
+
// shell:true is paired with an args array. We don't need the
|
|
73
|
+
// shell either — on Windows we spawn `npm.cmd` explicitly (the
|
|
74
|
+
// shim that PATHEXT would otherwise resolve to); on POSIX we
|
|
75
|
+
// spawn `npm` directly. No user input flows into argv on either
|
|
76
|
+
// path so the prior shell-resolution wasn't load-bearing.
|
|
77
|
+
const cmd = platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
73
78
|
const spawnOpts = {
|
|
74
|
-
shell: platform === 'win32',
|
|
75
79
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
76
80
|
};
|
|
77
81
|
let child;
|
|
78
82
|
try {
|
|
79
|
-
child = spawn(
|
|
83
|
+
child = spawn(cmd, args, spawnOpts);
|
|
80
84
|
}
|
|
81
85
|
catch (err) {
|
|
82
86
|
resolve({
|
|
@@ -37,6 +37,13 @@ const NPM_GLOBAL_HINTS = [
|
|
|
37
37
|
/[/\\]npm-global[/\\]/,
|
|
38
38
|
/[/\\]\.nvm[/\\]versions[/\\]node[/\\][^/\\]+[/\\]lib[/\\]node_modules\b/,
|
|
39
39
|
/Program Files[/\\]nodejs[/\\]node_modules[/\\]aiden-runtime\b/i,
|
|
40
|
+
// v4.8.1 Slice 2 — Windows user-mode `npm install -g` lands in
|
|
41
|
+
// `C:\Users\<u>\AppData\Roaming\npm\node_modules\aiden-runtime\`.
|
|
42
|
+
// The leading `[/\\]npm[/\\]node_modules` hint above usually catches
|
|
43
|
+
// it, but tests on a non-default `npm config prefix` setup
|
|
44
|
+
// (Cmder, Scoop, etc.) can land outside the canonical path. The
|
|
45
|
+
// extra hint here is a belt-and-suspenders explicit AppData match.
|
|
46
|
+
/[/\\]AppData[/\\]Roaming[/\\]npm[/\\]/i,
|
|
40
47
|
];
|
|
41
48
|
function inferDirs(input) {
|
|
42
49
|
return {
|
package/dist/core/version.js
CHANGED
|
@@ -1,5 +1,70 @@
|
|
|
1
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/version.ts — runtime version reader.
|
|
10
|
+
*
|
|
11
|
+
* v4.8.1 Slice 2 — switched from build-time injection to a runtime
|
|
12
|
+
* `package.json` walk. The previous design relied on
|
|
13
|
+
* `scripts/inject-version.js` (a `prebuild:cli` / `prebuild:api` hook)
|
|
14
|
+
* to write a hardcoded VERSION constant into this file. That design
|
|
15
|
+
* had a subtle ordering bug:
|
|
16
|
+
*
|
|
17
|
+
* `npm run build` ran `tsc --outDir dist` BEFORE `inject-version.js`.
|
|
18
|
+
* tsc compiled `core/version.ts` (still at the previously-committed
|
|
19
|
+
* value) into `dist/core/version.js`. Inject then mutated the
|
|
20
|
+
* source, but only the esbuild bundle (`dist-bundle/cli.js`) picked
|
|
21
|
+
* up the fresh value. The `bin` entry uses the tsc tree
|
|
22
|
+
* (`dist/cli/v4/aidenCLI.js`), so the globally-installed CLI
|
|
23
|
+
* reported the stale version.
|
|
24
|
+
*
|
|
25
|
+
* Fix: read the version at module-load time by walking up from
|
|
26
|
+
* `__dirname` and parsing the first `package.json` we find whose
|
|
27
|
+
* `name` is `aiden-runtime`. This works for:
|
|
28
|
+
*
|
|
29
|
+
* - the tsc tree (`dist/core/version.js` → walk to `<install>/package.json`)
|
|
30
|
+
* - the esbuild bundle (`dist-bundle/cli.js` → walk to root)
|
|
31
|
+
* - source / tsx dev runs (`core/version.ts` → walk to repo root)
|
|
32
|
+
* - tests (any `__dirname` inside the repo lands on the right pkg)
|
|
33
|
+
*
|
|
34
|
+
* Failure mode: returns `'0.0.0-unknown'` if no aiden-runtime
|
|
35
|
+
* package.json is found within 6 parent directories. End-user
|
|
36
|
+
* deployments always have one within 3 levels; the 6-level budget
|
|
37
|
+
* keeps the function defensive without scanning the whole filesystem.
|
|
38
|
+
*/
|
|
2
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
40
|
exports.VERSION = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
41
|
+
const node_fs_1 = require("node:fs");
|
|
42
|
+
const node_path_1 = require("node:path");
|
|
43
|
+
function readVersion() {
|
|
44
|
+
let dir = __dirname;
|
|
45
|
+
for (let i = 0; i < 6; i += 1) {
|
|
46
|
+
const candidate = (0, node_path_1.join)(dir, 'package.json');
|
|
47
|
+
if ((0, node_fs_1.existsSync)(candidate)) {
|
|
48
|
+
try {
|
|
49
|
+
const pkg = JSON.parse((0, node_fs_1.readFileSync)(candidate, 'utf8'));
|
|
50
|
+
if (pkg.name === 'aiden-runtime' && typeof pkg.version === 'string') {
|
|
51
|
+
return pkg.version;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
/* unreadable / non-JSON → keep walking */
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const parent = (0, node_path_1.dirname)(dir);
|
|
59
|
+
if (parent === dir)
|
|
60
|
+
break;
|
|
61
|
+
dir = parent;
|
|
62
|
+
}
|
|
63
|
+
return '0.0.0-unknown';
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Resolved at module-load time. Idempotent — multiple imports share
|
|
67
|
+
* the cached value. Re-reading on every access would be wasteful;
|
|
68
|
+
* the package.json version doesn't change during a process lifetime.
|
|
69
|
+
*/
|
|
70
|
+
exports.VERSION = readVersion();
|
|
@@ -237,6 +237,20 @@ class ApprovalEngine {
|
|
|
237
237
|
this.callbacks.onDecision?.(req, 'deny');
|
|
238
238
|
return false;
|
|
239
239
|
}
|
|
240
|
+
// v4.8.0 Phase 2.5 — emit a structured ui_approval_request event
|
|
241
|
+
// BEFORE the y/n prompt fires. Additive: the display layer paints
|
|
242
|
+
// the gutter-integrated row, then the existing promptUser flow
|
|
243
|
+
// runs unchanged. Moat-tier (safe/caution/dangerous) maps to the
|
|
244
|
+
// ui schema's 4-tier scale; 'critical' is reserved for future
|
|
245
|
+
// wiring and unreachable from this path.
|
|
246
|
+
const uiTier = req.riskTier === 'safe' ? 'low' :
|
|
247
|
+
req.riskTier === 'dangerous' ? 'high' : 'medium';
|
|
248
|
+
const argsPreview = JSON.stringify(req.args).slice(0, 80);
|
|
249
|
+
this.callbacks.onUiEvent?.('ui_approval_request', {
|
|
250
|
+
prompt: `${req.toolName} ${argsPreview}`,
|
|
251
|
+
risk_tier: uiTier,
|
|
252
|
+
reason: req.reason,
|
|
253
|
+
});
|
|
240
254
|
const decision = await this.callbacks.promptUser(req);
|
|
241
255
|
this.callbacks.onDecision?.(req, decision);
|
|
242
256
|
if (decision === 'deny')
|
package/dist/tools/v4/index.js
CHANGED
|
@@ -246,6 +246,60 @@ function registerWriteTools(registry) {
|
|
|
246
246
|
function registerAllTools(registry) {
|
|
247
247
|
registerReadOnlyTools(registry);
|
|
248
248
|
registerWriteTools(registry);
|
|
249
|
+
// v4.8.0 Phase 2.2 — register the 7 semantic ui_* event tools.
|
|
250
|
+
// All uiOnly: true → the dispatch loop in core/v4/aidenAgent.ts
|
|
251
|
+
// bypasses execute and fires onUiEvent on the caller. execute()
|
|
252
|
+
// throws as a safety guard: if the uiOnly branch ever misfires
|
|
253
|
+
// and an executor is reached, that's a wiring bug, not a render.
|
|
254
|
+
// Renderer is a no-op stub in this phase; Phase 2.3 lands chrome.
|
|
255
|
+
const ui = (name, description, properties, required) => ({
|
|
256
|
+
schema: { name, description, inputSchema: { type: 'object', properties, required } },
|
|
257
|
+
execute: async () => { throw new Error(`${name} is uiOnly — dispatch branch should bypass execute`); },
|
|
258
|
+
category: 'read', mutates: false, uiOnly: true,
|
|
259
|
+
});
|
|
260
|
+
const str = { type: 'string' };
|
|
261
|
+
const num = { type: 'number' };
|
|
262
|
+
registry.register(ui('ui_task_update', 'Signal current task state for the live task panel. Append-only stream.', { task_id: str, label: { type: 'string', description: '≤80 chars' },
|
|
263
|
+
status: { type: 'string', enum: ['running', 'blocked', 'paused'] },
|
|
264
|
+
kind: { type: 'string', enum: ['task', 'subagent'] }, depth: num, parent_id: str }, ['task_id', 'label', 'status']));
|
|
265
|
+
registry.register(ui('ui_task_done', 'Signal a task is complete. Pairs with a prior ui_task_update.', { task_id: str, status: { type: 'string', enum: ['success', 'failure', 'blocked'] },
|
|
266
|
+
summary: { type: 'string', description: 'Optional, ≤120 chars' } }, ['task_id', 'status']));
|
|
267
|
+
registry.register(ui('ui_command_result', 'Surface shell output as a formatted block.', { command: str, stdout: str, stderr: str, exit_code: num }, ['command']));
|
|
268
|
+
registry.register(ui('ui_test_result', 'Pass/fail count after a test run.', { framework: { type: 'string', description: 'e.g. "vitest", "pytest"' },
|
|
269
|
+
passed: num, failed: num, skipped: num, duration_ms: num }, ['framework', 'passed', 'failed']));
|
|
270
|
+
registry.register(ui('ui_approval_request', 'Structured approval prompt before a privileged action.', { prompt: { type: 'string', description: '≤160 chars' },
|
|
271
|
+
risk_tier: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
|
|
272
|
+
reason: { type: 'string', description: 'Optional, ≤200 chars' } }, ['prompt', 'risk_tier']));
|
|
273
|
+
registry.register(ui('ui_toast', 'Transient notice to surface without interrupting flow.', { message: { type: 'string', description: '≤120 chars' },
|
|
274
|
+
kind: { type: 'string', enum: ['info', 'success', 'warning', 'error'] } }, ['message', 'kind']));
|
|
275
|
+
registry.register(ui('ui_artifact_created', 'Surface a file or skill created/modified this turn.', { path: str, kind: { type: 'string', enum: ['file', 'skill', 'directory'] },
|
|
276
|
+
preview: { type: 'string', description: 'Optional, ≤200 chars' } }, ['path', 'kind']));
|
|
277
|
+
// v4.8.0 Phase 2.1 — env-gated uiOnly smoke stub. Never registers
|
|
278
|
+
// in production. Set AIDEN_TEST_UI_STUB=1 to enable for the
|
|
279
|
+
// dispatch-branch smoke harness. The execute() throws on purpose:
|
|
280
|
+
// if the uiOnly branch is wired correctly the model can never
|
|
281
|
+
// reach the executor.
|
|
282
|
+
if (process.env.AIDEN_TEST_UI_STUB === '1') {
|
|
283
|
+
registry.register({
|
|
284
|
+
schema: {
|
|
285
|
+
name: '_test_ui_stub',
|
|
286
|
+
description: 'Test-only uiOnly stub for v4.8.0 Phase 2.1 smoke. Set AIDEN_TEST_UI_STUB=1 to enable.',
|
|
287
|
+
inputSchema: {
|
|
288
|
+
type: 'object',
|
|
289
|
+
properties: {
|
|
290
|
+
message: { type: 'string', description: 'Arbitrary message to echo via onUiEvent' },
|
|
291
|
+
},
|
|
292
|
+
required: ['message'],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
execute: async () => {
|
|
296
|
+
throw new Error('_test_ui_stub should never execute — uiOnly branch should bypass it');
|
|
297
|
+
},
|
|
298
|
+
category: 'read',
|
|
299
|
+
mutates: false,
|
|
300
|
+
uiOnly: true,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
249
303
|
}
|
|
250
304
|
var subagentFanout_2 = require("./subagent/subagentFanout");
|
|
251
305
|
Object.defineProperty(exports, "makeSubagentFanoutTool", { enumerable: true, get: function () { return subagentFanout_2.makeSubagentFanoutTool; } });
|
|
@@ -289,6 +289,19 @@ function makeSpawnSubAgentTool(factory) {
|
|
|
289
289
|
// ── 3. Resolve optional parent run / session identifiers ─────────────
|
|
290
290
|
const parentRunId = factory.resolveParentRunId?.();
|
|
291
291
|
const parentSessionId = factory.resolveParentSessionId?.();
|
|
292
|
+
// v4.8.0 Phase 2.5 — emit ui_task_update for the subagent start.
|
|
293
|
+
// Stable task_id correlates with the matching ui_task_done emit
|
|
294
|
+
// after the spawnSubAgent call returns. depth:1 hardcoded today
|
|
295
|
+
// — childBuilder caps recursion at 1 (see SUBAGENT_BLOCKED_TOOL_NAMES
|
|
296
|
+
// 'spawn_sub_agent'). TODO: thread real depth when nested spawns ship.
|
|
297
|
+
const subTaskId = `subagent-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
298
|
+
factory.onUiEvent?.('ui_task_update', {
|
|
299
|
+
task_id: subTaskId,
|
|
300
|
+
label: goalPreview,
|
|
301
|
+
status: 'running',
|
|
302
|
+
kind: 'subagent',
|
|
303
|
+
depth: 1,
|
|
304
|
+
});
|
|
292
305
|
// ── 4. Invoke the primitive. NEVER throws — always envelope. ─────────
|
|
293
306
|
const result = await (0, spawnSubAgent_1.spawnSubAgent)(spec, {
|
|
294
307
|
// ChildBuilderDeps fields:
|
|
@@ -310,6 +323,16 @@ function makeSpawnSubAgentTool(factory) {
|
|
|
310
323
|
parentRunId,
|
|
311
324
|
parentSessionId,
|
|
312
325
|
});
|
|
326
|
+
// v4.8.0 Phase 2.5 — emit ui_task_done with the same subTaskId
|
|
327
|
+
// so the display layer can finalize the in-flight row.
|
|
328
|
+
const doneStatus = result.ok ? 'success' :
|
|
329
|
+
result.status === 'interrupted' ? 'blocked' :
|
|
330
|
+
result.status === 'timeout' ? 'blocked' : 'failure';
|
|
331
|
+
factory.onUiEvent?.('ui_task_done', {
|
|
332
|
+
task_id: subTaskId,
|
|
333
|
+
status: doneStatus,
|
|
334
|
+
summary: `${result.metrics.apiCalls} calls · ${result.exitReason}`,
|
|
335
|
+
});
|
|
313
336
|
// Completion log — pairs with "spawn_sub_agent invoked" so a
|
|
314
337
|
// grep on parentSessionId surfaces invoke → complete in order.
|
|
315
338
|
logger.info('spawn_sub_agent completed', {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiden-runtime",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -60,9 +60,7 @@
|
|
|
60
60
|
"scripts": {
|
|
61
61
|
"dev": "electron electron/main.js",
|
|
62
62
|
"build": "tsc --outDir dist && npm run build:cli && npm run build:api",
|
|
63
|
-
"prebuild:cli": "node scripts/inject-version.js",
|
|
64
63
|
"build:cli": "esbuild cli/aiden.ts --bundle --platform=node --target=node18 --outfile=dist-bundle/cli.js --external:electron --external:cpu-features --external:ssh2 --external:bcrypt --external:playwright --external:playwright-core --external:@aws-sdk/client-s3",
|
|
65
|
-
"prebuild:api": "node scripts/inject-version.js",
|
|
66
64
|
"build:api": "esbuild api/entry.ts --bundle --platform=node --target=node18 --outfile=dist-bundle/index.js --external:electron --external:cpu-features --external:ssh2 --external:bcrypt --external:playwright --external:playwright-core --external:@aws-sdk/client-s3",
|
|
67
65
|
"prepublishOnly": "npm run typecheck && npm run build",
|
|
68
66
|
"typecheck": "tsc --noEmit",
|