aiden-runtime 4.1.0 → 4.1.2
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 +89 -33
- package/dist/cli/v4/aidenCLI.js +162 -11
- package/dist/cli/v4/callbacks.js +5 -2
- package/dist/cli/v4/chatSession.js +525 -15
- package/dist/cli/v4/commands/auth.js +6 -3
- package/dist/cli/v4/commands/help.js +4 -0
- package/dist/cli/v4/commands/index.js +10 -1
- package/dist/cli/v4/commands/reloadSoul.js +37 -0
- package/dist/cli/v4/commands/update.js +102 -0
- package/dist/cli/v4/defaultSoul.js +68 -2
- package/dist/cli/v4/display.js +28 -10
- package/dist/cli/v4/doctor.js +173 -1
- package/dist/cli/v4/doctorLiveness.js +384 -0
- package/dist/cli/v4/promotionPrompt.js +202 -0
- package/dist/cli/v4/providerBootSelector.js +144 -0
- package/dist/cli/v4/sessionSummaryGate.js +66 -0
- package/dist/cli/v4/toolPreview.js +139 -0
- package/dist/core/v4/aidenAgent.js +91 -29
- package/dist/core/v4/capabilities.js +89 -0
- package/dist/core/v4/contextCompressor.js +25 -8
- package/dist/core/v4/distillationIndex.js +167 -0
- package/dist/core/v4/distillationStore.js +98 -0
- package/dist/core/v4/logger/logger.js +40 -9
- package/dist/core/v4/promotionCandidates.js +234 -0
- package/dist/core/v4/promptBuilder.js +145 -1
- package/dist/core/v4/sessionDistiller.js +405 -0
- package/dist/core/v4/skillMining/extractorPrompt.js +28 -21
- package/dist/core/v4/skillMining/proposalBuilder.js +3 -2
- package/dist/core/v4/skillMining/skillMiner.js +43 -6
- package/dist/core/v4/skillOutcomeTracker.js +323 -0
- package/dist/core/v4/subsystemHealth.js +143 -0
- package/dist/core/v4/update/executeInstall.js +233 -0
- package/dist/core/version.js +1 -1
- package/dist/moat/dangerousPatterns.js +1 -1
- package/dist/moat/memoryGuard.js +111 -0
- package/dist/moat/skillTeacher.js +14 -5
- package/dist/providers/v4/chatCompletionsAdapter.js +9 -0
- package/dist/providers/v4/codexResponsesAdapter.js +7 -2
- package/dist/providers/v4/errors.js +67 -1
- package/dist/providers/v4/modelDefaults.js +65 -0
- package/dist/providers/v4/ollamaPromptToolsAdapter.js +9 -2
- package/dist/providers/v4/registry.js +9 -2
- package/dist/providers/v4/runtimeResolver.js +6 -0
- package/dist/tools/v4/index.js +57 -1
- package/dist/tools/v4/memory/memoryRemove.js +57 -2
- package/dist/tools/v4/memory/sessionSummary.js +151 -0
- package/dist/tools/v4/sessions/recallSession.js +163 -0
- package/dist/tools/v4/sessions/sessionSearch.js +5 -1
- package/dist/tools/v4/subagent/subagentFanout.js +24 -0
- package/dist/tools/v4/system/_psHelpers.js +55 -0
- package/dist/tools/v4/system/aidenSelfUpdate.js +162 -0
- package/dist/tools/v4/system/appClose.js +79 -0
- package/dist/tools/v4/system/appLaunch.js +92 -0
- package/dist/tools/v4/system/clipboardRead.js +54 -0
- package/dist/tools/v4/system/clipboardWrite.js +84 -0
- package/dist/tools/v4/system/mediaKey.js +78 -0
- package/dist/tools/v4/system/osProcessList.js +99 -0
- package/dist/tools/v4/system/screenshot.js +106 -0
- package/dist/tools/v4/system/volumeSet.js +157 -0
- package/package.json +4 -1
- package/skills/system_control.md +135 -69
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* and registers each on the global CommandRegistry at boot.
|
|
13
13
|
*/
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.allCommands = exports.history = exports.show = exports.status = exports.voice = exports.channel = exports.setup = exports.cron = exports.doctor = exports.license = exports.auth = exports.plugins = exports.streaming = exports.debugPrompt = exports.identity = exports.providers = exports.quit = exports.clear = exports.verbose = exports.reasoning = exports.reloadMcp = exports.skills = exports.skin = exports.yolo = exports.usage = exports.compress = exports.title = exports.save = exports.personality = exports.model = exports.tools = exports.help = void 0;
|
|
15
|
+
exports.allCommands = exports.update = exports.reloadSoul = exports.history = exports.show = exports.status = exports.voice = exports.channel = exports.setup = exports.cron = exports.doctor = exports.license = exports.auth = exports.plugins = exports.streaming = exports.debugPrompt = exports.identity = exports.providers = exports.quit = exports.clear = exports.verbose = exports.reasoning = exports.reloadMcp = exports.skills = exports.skin = exports.yolo = exports.usage = exports.compress = exports.title = exports.save = exports.personality = exports.model = exports.tools = exports.help = void 0;
|
|
16
16
|
const help_1 = require("./help");
|
|
17
17
|
Object.defineProperty(exports, "help", { enumerable: true, get: function () { return help_1.help; } });
|
|
18
18
|
const tools_1 = require("./tools");
|
|
@@ -75,6 +75,10 @@ const show_1 = require("./show");
|
|
|
75
75
|
Object.defineProperty(exports, "show", { enumerable: true, get: function () { return show_1.show; } });
|
|
76
76
|
const history_1 = require("./history");
|
|
77
77
|
Object.defineProperty(exports, "history", { enumerable: true, get: function () { return history_1.history; } });
|
|
78
|
+
const reloadSoul_1 = require("./reloadSoul");
|
|
79
|
+
Object.defineProperty(exports, "reloadSoul", { enumerable: true, get: function () { return reloadSoul_1.reloadSoul; } });
|
|
80
|
+
const update_1 = require("./update");
|
|
81
|
+
Object.defineProperty(exports, "update", { enumerable: true, get: function () { return update_1.update; } });
|
|
78
82
|
/** All built-in system commands, in canonical order. */
|
|
79
83
|
exports.allCommands = [
|
|
80
84
|
help_1.help,
|
|
@@ -103,9 +107,14 @@ exports.allCommands = [
|
|
|
103
107
|
status_1.status,
|
|
104
108
|
show_1.show,
|
|
105
109
|
history_1.history,
|
|
110
|
+
reloadSoul_1.reloadSoul,
|
|
106
111
|
reloadMcp_1.reloadMcp,
|
|
107
112
|
reasoning_1.reasoning,
|
|
108
113
|
verbose_1.verbose,
|
|
114
|
+
// Phase v4.1.2-update: /update + /update install — fresh registry
|
|
115
|
+
// probe + shared executeInstall executor (also wired into
|
|
116
|
+
// aiden_self_update tool for natural-language requests).
|
|
117
|
+
update_1.update,
|
|
109
118
|
clear_1.clear,
|
|
110
119
|
quit_1.quit,
|
|
111
120
|
];
|
|
@@ -0,0 +1,37 @@
|
|
|
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/reload-soul.ts — Phase v4.1.2 alive-core.
|
|
10
|
+
*
|
|
11
|
+
* `/reload-soul` — explicit fallback for the SOUL.md file-watcher path.
|
|
12
|
+
* Some filesystems (network mounts, certain WSL configs) don't support
|
|
13
|
+
* `fs.watch` reliably; this command lets users force a system-prompt
|
|
14
|
+
* rebuild after editing SOUL.md without restarting `aiden`.
|
|
15
|
+
*
|
|
16
|
+
* Mechanism: marks the agent's 'soul' dirty bit; the next turn calls
|
|
17
|
+
* `refreshSystemPromptIfDirty()` which invalidates the cached prompt.
|
|
18
|
+
* `PromptBuilder.build()` then re-reads SOUL.md from disk.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.reloadSoul = void 0;
|
|
22
|
+
exports.reloadSoul = {
|
|
23
|
+
name: 'reload-soul',
|
|
24
|
+
description: 'Re-read SOUL.md from disk on the next turn (manual cache invalidation).',
|
|
25
|
+
category: 'system',
|
|
26
|
+
icon: '🔁',
|
|
27
|
+
aliases: ['soul-reload'],
|
|
28
|
+
handler: async (ctx) => {
|
|
29
|
+
if (!ctx.agent) {
|
|
30
|
+
ctx.display.warn('Reload-soul cannot run before the agent boots.');
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
ctx.agent.markMemoryDirty('soul');
|
|
34
|
+
ctx.display.success('SOUL.md flagged for reload — the next turn will pick up your edits.');
|
|
35
|
+
return {};
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
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/update.ts — Phase v4.1.2-update.
|
|
10
|
+
*
|
|
11
|
+
* /update — bypass the boot-time 6h cache, probe npm registry
|
|
12
|
+
* fresh, print current vs latest with hint.
|
|
13
|
+
* /update install — spawn `npm install -g aiden-runtime@latest`
|
|
14
|
+
* via the shared executeInstall executor; print
|
|
15
|
+
* restart hint on success or platform-specific
|
|
16
|
+
* remediation on permission failure.
|
|
17
|
+
*
|
|
18
|
+
* No auto-restart on success — the user keeps control by typing
|
|
19
|
+
* /quit and re-launching aiden. Honest UX: never claim the current
|
|
20
|
+
* process is upgraded after a successful install. Auto-restart of
|
|
21
|
+
* a node REPL via re-exec is also fragile across Windows/macOS/
|
|
22
|
+
* Linux, so the explicit /quit path is both honest and reliable.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.update = void 0;
|
|
26
|
+
const version_1 = require("../../../core/version");
|
|
27
|
+
const checkUpdate_1 = require("../../../core/v4/update/checkUpdate");
|
|
28
|
+
const executeInstall_1 = require("../../../core/v4/update/executeInstall");
|
|
29
|
+
async function printStatus(ctx) {
|
|
30
|
+
if (!ctx.paths) {
|
|
31
|
+
ctx.display.warn('/update needs Aiden user-data paths — try in a real session.');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
ctx.display.dim('Checking for updates…');
|
|
35
|
+
// cacheTtlMs: 0 — user explicitly asked, so bypass the 6h boot cache.
|
|
36
|
+
const status = await (0, checkUpdate_1.checkForUpdate)({
|
|
37
|
+
paths: ctx.paths,
|
|
38
|
+
installedVersion: version_1.VERSION,
|
|
39
|
+
cacheTtlMs: 0,
|
|
40
|
+
});
|
|
41
|
+
ctx.display.write(` installed: v${status.installed}\n`);
|
|
42
|
+
if (status.latest === null) {
|
|
43
|
+
ctx.display.write(' latest: unknown (registry unreachable)\n');
|
|
44
|
+
ctx.display.dim('Could not reach the npm registry. Check your network and try again.');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
ctx.display.write(` latest: v${status.latest}\n`);
|
|
48
|
+
if (status.updateAvailable) {
|
|
49
|
+
ctx.display.write(`\n update available: v${status.installed} → v${status.latest}\n` +
|
|
50
|
+
` run \`/update install\` to install, or \`npm install -g aiden-runtime@latest\` manually.\n`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
ctx.display.dim("You're on the latest version.");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function runInstall(ctx) {
|
|
57
|
+
if (!ctx.paths) {
|
|
58
|
+
ctx.display.warn('/update install needs Aiden user-data paths — try in a real session.');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Status probe first so we don't run a no-op install. Also bypasses
|
|
62
|
+
// cache — same rationale as the bare /update path.
|
|
63
|
+
ctx.display.dim('Checking for updates…');
|
|
64
|
+
const status = await (0, checkUpdate_1.checkForUpdate)({
|
|
65
|
+
paths: ctx.paths,
|
|
66
|
+
installedVersion: version_1.VERSION,
|
|
67
|
+
cacheTtlMs: 0,
|
|
68
|
+
});
|
|
69
|
+
if (status.latest === null) {
|
|
70
|
+
ctx.display.warn("Couldn't check for updates (registry unreachable). " +
|
|
71
|
+
'Try `/update` first, or run `npm install -g aiden-runtime@latest` manually.');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!status.updateAvailable) {
|
|
75
|
+
ctx.display.dim(`You're already on the latest version (v${status.installed}).`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
ctx.display.write(`Installing aiden-runtime v${status.latest} (current: v${status.installed})…\n`);
|
|
79
|
+
const result = await (0, executeInstall_1.executeInstall)();
|
|
80
|
+
if (result.success) {
|
|
81
|
+
const v = result.installedVersion ?? status.latest;
|
|
82
|
+
ctx.display.write(`\n ✓ aiden-runtime v${v} installed.\n`);
|
|
83
|
+
ctx.display.dim('Restart Aiden to apply: type /quit then re-run `aiden`.');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
ctx.display.warn(result.error ?? 'Install failed (no error message).');
|
|
87
|
+
}
|
|
88
|
+
exports.update = {
|
|
89
|
+
name: 'update',
|
|
90
|
+
description: 'Check for / install the latest aiden-runtime. Use "install" subcommand to apply.',
|
|
91
|
+
category: 'system',
|
|
92
|
+
icon: '⬆',
|
|
93
|
+
handler: async (ctx) => {
|
|
94
|
+
const sub = (ctx.args[0] ?? '').toLowerCase();
|
|
95
|
+
if (sub === 'install') {
|
|
96
|
+
await runInstall(ctx);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
await printStatus(ctx);
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
};
|
|
@@ -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 = '
|
|
33
|
+
exports.BUNDLED_SOUL_VERSION = 'v4.1.2';
|
|
34
34
|
exports.DEFAULT_SOUL_MD = `You are Aiden — a local-first AI agent built by Taracod.
|
|
35
35
|
|
|
36
36
|
Identity:
|
|
@@ -88,7 +88,6 @@ asking the user what to do next.
|
|
|
88
88
|
</keep_going>
|
|
89
89
|
|
|
90
90
|
Limits:
|
|
91
|
-
- You're a CLI agent in v4.0.0. No voice, no scheduled jobs, no messaging gateway yet — those are v4.1.
|
|
92
91
|
- You can't bypass approval prompts for dangerous commands.
|
|
93
92
|
- You don't lie to look smart. If you don't know, you say so.
|
|
94
93
|
`;
|
|
@@ -184,6 +183,73 @@ the tool calls within a single turn instead of returning halfway and
|
|
|
184
183
|
asking the user what to do next.
|
|
185
184
|
</keep_going>
|
|
186
185
|
|
|
186
|
+
Limits:
|
|
187
|
+
- You're a CLI agent in v4.0.0. No voice, no scheduled jobs, no messaging gateway yet — those are v4.1.
|
|
188
|
+
- You can't bypass approval prompts for dangerous commands.
|
|
189
|
+
- You don't lie to look smart. If you don't know, you say so.
|
|
190
|
+
`,
|
|
191
|
+
// 16h default — media-search anti-pattern + skill_view reference,
|
|
192
|
+
// but still carried the stale 'v4.0.0 / planned for v4.1' limits line
|
|
193
|
+
// claiming voice, cron, and messaging were not yet shipped. Phase
|
|
194
|
+
// v4.1.2-followup strips that line because cron / Telegram / 9 channels
|
|
195
|
+
// ALL shipped in v4.1.0. Users on the v4.1.0 / v4.1.1 install have this
|
|
196
|
+
// verbatim text on disk; silent-upgrade picks them up here.
|
|
197
|
+
`You are Aiden — a local-first AI agent built by Taracod.
|
|
198
|
+
|
|
199
|
+
Identity:
|
|
200
|
+
- You run on the user's machine, native Windows/Linux/macOS (not WSL2).
|
|
201
|
+
- You have 72 bundled skills + access to install more via skills.sh.
|
|
202
|
+
- You remember past sessions via persistent storage.
|
|
203
|
+
- You have 40 tools spanning files, browser, terminal, web, memory.
|
|
204
|
+
|
|
205
|
+
Voice:
|
|
206
|
+
- Direct. No fluff. Match the user's energy.
|
|
207
|
+
- Honest above all — if you didn't do something, say so. If you're not sure, say so.
|
|
208
|
+
- You never claim to "have run" a tool unless the trace shows it.
|
|
209
|
+
|
|
210
|
+
Behavior:
|
|
211
|
+
- Default to action over discussion. The user wants results.
|
|
212
|
+
- When asked who you are, identify as Aiden. Not "a large language model."
|
|
213
|
+
- When asked what you can do, mention specific skills/tools, not generic capabilities.
|
|
214
|
+
- If user mentions trading/NSE/markets, you have specialized skills for that.
|
|
215
|
+
|
|
216
|
+
<act_dont_ask>
|
|
217
|
+
When a request has an obvious default interpretation, act on it
|
|
218
|
+
immediately instead of asking for clarification. Examples:
|
|
219
|
+
- "play me a popular song" / "play X on youtube" → load skill_view(media-search)
|
|
220
|
+
and follow it. Substitute fuzzy phrases ("popular song") with a specific
|
|
221
|
+
chart-topper BEFORE searching, then open_url a /watch?v= URL once.
|
|
222
|
+
NEVER search verbatim "popular song" — that returns articles, not music.
|
|
223
|
+
- "what files are in my Downloads?" → file_list on Downloads. Don't ask
|
|
224
|
+
"which user?" — it's the current user.
|
|
225
|
+
- "is port 443 open?" → check this machine. Don't ask "open where?"
|
|
226
|
+
Only ask for clarification when the ambiguity genuinely changes which
|
|
227
|
+
tool you would call.
|
|
228
|
+
</act_dont_ask>
|
|
229
|
+
|
|
230
|
+
<prerequisite_checks>
|
|
231
|
+
Before acting, check whether prerequisite discovery, lookup, or
|
|
232
|
+
context-gathering steps are needed. If a step depends on output from a
|
|
233
|
+
prior step, resolve that dependency first. Don't skip prerequisite
|
|
234
|
+
steps just because the final action seems obvious.
|
|
235
|
+
</prerequisite_checks>
|
|
236
|
+
|
|
237
|
+
<missing_context>
|
|
238
|
+
If required context is missing, do NOT guess or hallucinate. Use the
|
|
239
|
+
appropriate lookup tool when missing information is retrievable
|
|
240
|
+
(file_read, file_list, web_search, fetch_url, session_search,
|
|
241
|
+
system_info). Ask a clarifying question ONLY when no tool can resolve
|
|
242
|
+
the ambiguity.
|
|
243
|
+
</missing_context>
|
|
244
|
+
|
|
245
|
+
<keep_going>
|
|
246
|
+
Work autonomously until the task is fully resolved. Don't stop with a
|
|
247
|
+
plan — execute it. Multi-step tasks (open browser → search → click
|
|
248
|
+
result; or list files → read each → summarise) are expected; chain
|
|
249
|
+
the tool calls within a single turn instead of returning halfway and
|
|
250
|
+
asking the user what to do next.
|
|
251
|
+
</keep_going>
|
|
252
|
+
|
|
187
253
|
Limits:
|
|
188
254
|
- You're a CLI agent in v4.0.0. No voice, no scheduled jobs, no messaging gateway yet — those are v4.1.
|
|
189
255
|
- You can't bypass approval prompts for dangerous commands.
|
package/dist/cli/v4/display.js
CHANGED
|
@@ -42,6 +42,7 @@ const box_1 = require("./box");
|
|
|
42
42
|
const replyRenderer_1 = require("./replyRenderer");
|
|
43
43
|
// Optional "Sources" footer when AIDEN_CITATIONS=1 (default off).
|
|
44
44
|
const citationFooter_1 = require("./citationFooter");
|
|
45
|
+
const toolPreview_1 = require("./toolPreview");
|
|
45
46
|
/**
|
|
46
47
|
* Phase 26.2.7 — category emoji icons for the tool-row prefix when
|
|
47
48
|
* `AIDEN_UI_ICONS=1` is set in the environment. Default OFF (the
|
|
@@ -393,13 +394,18 @@ class Display {
|
|
|
393
394
|
const pill = (on, label, value) => `${dot(on)} ${lab(label)} ${val(value)}`;
|
|
394
395
|
const providerOk = args.providerOk !== false;
|
|
395
396
|
const modelValue = providerOk ? args.model : 'not configured';
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
397
|
+
const pills = [
|
|
398
|
+
pill(args.coreOnline, 'core', args.coreOnline ? 'online' : 'starting'),
|
|
399
|
+
pill(true, 'mode', args.mode),
|
|
400
|
+
pill(providerOk, 'model', modelValue),
|
|
401
|
+
pill(args.memoryActive, 'memory', args.memoryActive ? 'active' : 'off'),
|
|
402
|
+
];
|
|
403
|
+
if (args.version) {
|
|
404
|
+
// Version pill: dot + value, no label (the `v` prefix is the label).
|
|
405
|
+
// Always-on dot — informational, not a health indicator.
|
|
406
|
+
pills.push(`${dot(true)} ${val(`v${args.version}`)}`);
|
|
407
|
+
}
|
|
408
|
+
return ' ' + pills.join(' ');
|
|
403
409
|
}
|
|
404
410
|
/**
|
|
405
411
|
* Two-column block (Environment + Capabilities). Side-by-side when
|
|
@@ -794,11 +800,24 @@ class Display {
|
|
|
794
800
|
};
|
|
795
801
|
}
|
|
796
802
|
/**
|
|
797
|
-
* Pretty-print a tool call before it executes.
|
|
798
|
-
*
|
|
803
|
+
* Pretty-print a tool call before it executes. Phase v4.1.2 first
|
|
804
|
+
* consults the `TOOL_PRIMARY_ARG` map in `toolPreview.ts` to render
|
|
805
|
+
* just the meaningful argument (e.g. `terminal: npm test`); falls
|
|
806
|
+
* back to the legacy full-JSON stringification (200-char hard cap)
|
|
807
|
+
* for tools that aren't in the map.
|
|
799
808
|
*/
|
|
800
809
|
toolPreview(name, args) {
|
|
801
810
|
const sk = this.skin;
|
|
811
|
+
const arrow = sk.getActive().glyphs?.arrow ?? '>';
|
|
812
|
+
// Phase v4.1.2: per-tool primary-arg preview.
|
|
813
|
+
const preview = (0, toolPreview_1.buildToolPreview)(name, args);
|
|
814
|
+
if (preview !== null) {
|
|
815
|
+
if (preview === '') {
|
|
816
|
+
return `${sk.applyColors(arrow, 'tool')} ${sk.applyColors(name, 'tool')}`;
|
|
817
|
+
}
|
|
818
|
+
return `${sk.applyColors(arrow, 'tool')} ${sk.applyColors(name, 'tool')} ${sk.applyColors(preview, 'muted')}`;
|
|
819
|
+
}
|
|
820
|
+
// Unknown tool — original behaviour (full JSON, 200-char cap).
|
|
802
821
|
let serialized;
|
|
803
822
|
try {
|
|
804
823
|
serialized = JSON.stringify(args);
|
|
@@ -808,7 +827,6 @@ class Display {
|
|
|
808
827
|
}
|
|
809
828
|
if (serialized.length > 200)
|
|
810
829
|
serialized = `${serialized.slice(0, 197)}...`;
|
|
811
|
-
const arrow = sk.getActive().glyphs?.arrow ?? '>';
|
|
812
830
|
return `${sk.applyColors(arrow, 'tool')} ${sk.applyColors(name, 'tool')} ${sk.applyColors(serialized, 'muted')}`;
|
|
813
831
|
}
|
|
814
832
|
/**
|
package/dist/cli/v4/doctor.js
CHANGED
|
@@ -18,10 +18,45 @@
|
|
|
18
18
|
* will normally be sub-second.
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
24
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
25
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
26
|
+
}
|
|
27
|
+
Object.defineProperty(o, k2, desc);
|
|
28
|
+
}) : (function(o, m, k, k2) {
|
|
29
|
+
if (k2 === undefined) k2 = k;
|
|
30
|
+
o[k2] = m[k];
|
|
31
|
+
}));
|
|
32
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
33
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
34
|
+
}) : function(o, v) {
|
|
35
|
+
o["default"] = v;
|
|
36
|
+
});
|
|
37
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
38
|
+
var ownKeys = function(o) {
|
|
39
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
40
|
+
var ar = [];
|
|
41
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
42
|
+
return ar;
|
|
43
|
+
};
|
|
44
|
+
return ownKeys(o);
|
|
45
|
+
};
|
|
46
|
+
return function (mod) {
|
|
47
|
+
if (mod && mod.__esModule) return mod;
|
|
48
|
+
var result = {};
|
|
49
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
50
|
+
__setModuleDefault(result, mod);
|
|
51
|
+
return result;
|
|
52
|
+
};
|
|
53
|
+
})();
|
|
21
54
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
55
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
56
|
};
|
|
24
57
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
|
+
exports.renderSubsystemHealthSection = renderSubsystemHealthSection;
|
|
59
|
+
exports.renderSkillOutcomesSection = renderSkillOutcomesSection;
|
|
25
60
|
exports.resolveBinaryPath = resolveBinaryPath;
|
|
26
61
|
exports._resetBinaryResolutionCacheForTests = _resetBinaryResolutionCacheForTests;
|
|
27
62
|
exports.buildProbeInvocation = buildProbeInvocation;
|
|
@@ -50,6 +85,104 @@ const license_1 = require("../../core/v4/license");
|
|
|
50
85
|
const checkUpdate_1 = require("../../core/v4/update/checkUpdate");
|
|
51
86
|
const box_1 = require("./box");
|
|
52
87
|
const audioBackend_1 = require("../../core/voice/audioBackend");
|
|
88
|
+
/**
|
|
89
|
+
* Phase v4.1.2-slice3: render the Subsystem health section. Decision
|
|
90
|
+
* tree (per slice3 Phase 3 Q4):
|
|
91
|
+
* - registry undefined → render nothing (no live state to report)
|
|
92
|
+
* - all subsystems healthy → one-line green summary
|
|
93
|
+
* - any degradation → expand block with last-error per failed sub
|
|
94
|
+
*
|
|
95
|
+
* The Honesty layer is intentionally listed as "(not instrumented yet)"
|
|
96
|
+
* when the expanded block fires, because the audit determined the
|
|
97
|
+
* pure-pattern path has no I/O failure surface today.
|
|
98
|
+
*/
|
|
99
|
+
function renderSubsystemHealthSection(registry) {
|
|
100
|
+
if (!registry)
|
|
101
|
+
return '';
|
|
102
|
+
const snaps = registry.snapshot();
|
|
103
|
+
if (snaps.length === 0)
|
|
104
|
+
return '';
|
|
105
|
+
const degraded = snaps.filter((s) => s.totalErrors > 0);
|
|
106
|
+
if (degraded.length === 0) {
|
|
107
|
+
return `\nSubsystem health: all green (${snaps.length} subsystems instrumented)\n`;
|
|
108
|
+
}
|
|
109
|
+
// Expanded form. Per-subsystem rows:
|
|
110
|
+
// ✓ name N calls, 0 errors
|
|
111
|
+
// ✗ name N calls, E errors (last <duration> ago: "message")
|
|
112
|
+
// - honesty (not instrumented yet)
|
|
113
|
+
const lines = ['\nSubsystem health'];
|
|
114
|
+
for (const s of snaps) {
|
|
115
|
+
const mark = s.totalErrors > 0 ? 'x' : 'ok';
|
|
116
|
+
const stats = `${s.totalCalls} call${s.totalCalls === 1 ? '' : 's'}, ${s.totalErrors} error${s.totalErrors === 1 ? '' : 's'}`;
|
|
117
|
+
if (s.lastError) {
|
|
118
|
+
const ago = humanAge(Date.now() - s.lastError.at.getTime());
|
|
119
|
+
const streak = s.lastError.consecutive > 1
|
|
120
|
+
? ` (${s.lastError.consecutive} consecutive)`
|
|
121
|
+
: '';
|
|
122
|
+
lines.push(` [${mark}] ${s.subsystem.padEnd(16)} ${stats}${streak} (last ${ago} ago: "${s.lastError.message}")`);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
lines.push(` [${mark}] ${s.subsystem.padEnd(16)} ${stats}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Slice3 audit decision: HonestyEnforcement was deliberately not
|
|
129
|
+
// instrumented (pure-pattern path has no failure surface). Surface
|
|
130
|
+
// that explicitly so users know the gap is known, not forgotten.
|
|
131
|
+
lines.push(` [-] honesty (not instrumented yet)`);
|
|
132
|
+
lines.push('');
|
|
133
|
+
return lines.join('\n');
|
|
134
|
+
}
|
|
135
|
+
function humanAge(ms) {
|
|
136
|
+
if (ms < 1000)
|
|
137
|
+
return `${ms}ms`;
|
|
138
|
+
if (ms < 60000)
|
|
139
|
+
return `${(ms / 1000).toFixed(0)}s`;
|
|
140
|
+
if (ms < 3600000)
|
|
141
|
+
return `${Math.floor(ms / 60000)}m`;
|
|
142
|
+
if (ms < 86400000)
|
|
143
|
+
return `${Math.floor(ms / 3600000)}h`;
|
|
144
|
+
return `${Math.floor(ms / 86400000)}d`;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Phase v4.1.2-slice4: render the Skill outcomes section. Per Q3
|
|
148
|
+
* decision: silent on empty state (no tracker, or no skills tracked
|
|
149
|
+
* yet) — doctor output for healthy systems stays short.
|
|
150
|
+
*
|
|
151
|
+
* Output (when not empty): top N skills sorted by load count, with
|
|
152
|
+
* total observations and success percentage. Last-error message
|
|
153
|
+
* shown for the one most-recently failing skill (cap one row of
|
|
154
|
+
* detail so the block stays compact).
|
|
155
|
+
*/
|
|
156
|
+
function renderSkillOutcomesSection(tracker, topN = 5) {
|
|
157
|
+
if (!tracker)
|
|
158
|
+
return '';
|
|
159
|
+
const snaps = tracker.snapshot();
|
|
160
|
+
if (snaps.length === 0)
|
|
161
|
+
return '';
|
|
162
|
+
const lines = ['\nSkill outcomes (top ' + Math.min(topN, snaps.length) + ' by load count)'];
|
|
163
|
+
for (const s of snaps.slice(0, topN)) {
|
|
164
|
+
const attributed = s.toolSuccesses + s.toolFailures;
|
|
165
|
+
const rate = attributed === 0
|
|
166
|
+
? '—'
|
|
167
|
+
: `${Math.round((s.toolSuccesses / attributed) * 100)}% success`;
|
|
168
|
+
const stats = `loaded ${s.loaded}, ${s.toolSuccesses} ok, ${s.toolFailures} err (${rate})`;
|
|
169
|
+
const last = s.lastUsed
|
|
170
|
+
? ` last ${humanAge(Date.now() - new Date(s.lastUsed).getTime())} ago`
|
|
171
|
+
: '';
|
|
172
|
+
lines.push(` ${s.skillName.padEnd(32)} ${stats}${last}`);
|
|
173
|
+
}
|
|
174
|
+
// Spotlight the most-recent failure across all tracked skills so a
|
|
175
|
+
// single broken skill is visible without scanning every row.
|
|
176
|
+
const recentFailures = snaps
|
|
177
|
+
.filter((s) => s.lastError)
|
|
178
|
+
.sort((a, b) => new Date(b.lastError.at).getTime() - new Date(a.lastError.at).getTime());
|
|
179
|
+
if (recentFailures.length > 0) {
|
|
180
|
+
const f = recentFailures[0];
|
|
181
|
+
lines.push(` ↳ last failure: ${f.skillName} — "${f.lastError.message}"`);
|
|
182
|
+
}
|
|
183
|
+
lines.push('');
|
|
184
|
+
return lines.join('\n');
|
|
185
|
+
}
|
|
53
186
|
const DEFAULT_TIMEOUT_MS = 3000;
|
|
54
187
|
/** Wrap a promise with a timeout. The timed-out path resolves to the fallback result. */
|
|
55
188
|
async function withTimeout(p, ms, fallback) {
|
|
@@ -760,6 +893,45 @@ async function runDoctorCli(opts) {
|
|
|
760
893
|
}
|
|
761
894
|
}
|
|
762
895
|
process.stdout.write(`\n${report.passed ? 'all checks passed' : 'some checks failed'} in ${report.totalMs} ms\n`);
|
|
763
|
-
|
|
896
|
+
// Phase v4.1.1-oauth-fix Phase 5: discoverability hint for the deep
|
|
897
|
+
// mode. Only emitted in standard mode — if the user already passed
|
|
898
|
+
// `--providers`, the section right below this is the answer to the hint.
|
|
899
|
+
if (!opts?.liveness) {
|
|
900
|
+
process.stdout.write(' hint: Run `aiden doctor --providers` for live provider checks\n');
|
|
901
|
+
}
|
|
902
|
+
// Phase v4.1.1-oauth-fix Phase 4: opt-in provider liveness.
|
|
903
|
+
// Runs after the standard report so a failed config check is visible
|
|
904
|
+
// before the network probes start. Section header + summary line are
|
|
905
|
+
// rendered by doctorLiveness.renderProviderLivenessSection so the
|
|
906
|
+
// formatting stays alongside its consumer.
|
|
907
|
+
let livenessFailed = false;
|
|
908
|
+
if (opts?.liveness) {
|
|
909
|
+
process.stdout.write('\n Running provider liveness checks...\n');
|
|
910
|
+
const { runProviderLiveness, renderProviderLivenessSection } = await Promise.resolve().then(() => __importStar(require('./doctorLiveness')));
|
|
911
|
+
const paths = opts.paths ?? (0, paths_1.resolveAidenPaths)();
|
|
912
|
+
const { results, summary } = await runProviderLiveness({
|
|
913
|
+
paths,
|
|
914
|
+
env: opts.env,
|
|
915
|
+
fetchImpl: opts.fetchImpl,
|
|
916
|
+
timeoutMs: opts.livenessTimeoutMs,
|
|
917
|
+
});
|
|
918
|
+
process.stdout.write(renderProviderLivenessSection(results, summary));
|
|
919
|
+
livenessFailed = summary.red > 0;
|
|
920
|
+
}
|
|
921
|
+
// Phase v4.1.2-slice3: subsystem-health surface. Renders only when
|
|
922
|
+
// a registry was passed (in-REPL doctor); standalone CLI doctor has
|
|
923
|
+
// no live agent so the section is omitted.
|
|
924
|
+
const subsystemBlock = renderSubsystemHealthSection(opts?.subsystemHealthRegistry);
|
|
925
|
+
if (subsystemBlock)
|
|
926
|
+
process.stdout.write(subsystemBlock);
|
|
927
|
+
// Phase v4.1.2-slice4: skill-outcome surface. Same gating — only
|
|
928
|
+
// renders when a tracker was passed and has at least one observed
|
|
929
|
+
// skill. Standalone CLI invocations skip it.
|
|
930
|
+
const outcomesBlock = renderSkillOutcomesSection(opts?.skillOutcomeTracker);
|
|
931
|
+
if (outcomesBlock)
|
|
932
|
+
process.stdout.write(outcomesBlock);
|
|
933
|
+
// Liveness reds count toward the overall exit code so CI / scripts
|
|
934
|
+
// can `aiden doctor --providers && deploy`.
|
|
935
|
+
process.exitCode = (report.passed && !livenessFailed) ? 0 : 1;
|
|
764
936
|
return report;
|
|
765
937
|
}
|