aiden-runtime 4.1.1 → 4.1.3
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 +78 -26
- package/dist/cli/v4/aidenCLI.js +169 -9
- package/dist/cli/v4/callbacks.js +20 -2
- package/dist/cli/v4/chatSession.js +644 -16
- package/dist/cli/v4/commands/auth.js +6 -3
- package/dist/cli/v4/commands/doctor.js +23 -27
- package/dist/cli/v4/commands/help.js +4 -0
- package/dist/cli/v4/commands/index.js +10 -1
- package/dist/cli/v4/commands/model.js +30 -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/capabilityCard.js +135 -0
- package/dist/cli/v4/display/sessionEndCard.js +127 -0
- package/dist/cli/v4/display/toolTrail.js +172 -0
- package/dist/cli/v4/display.js +492 -142
- package/dist/cli/v4/doctor.js +472 -58
- package/dist/cli/v4/doctorLiveness.js +65 -10
- package/dist/cli/v4/promotionPrompt.js +332 -0
- package/dist/cli/v4/providerBootSelector.js +144 -0
- package/dist/cli/v4/replyRenderer.js +311 -20
- package/dist/cli/v4/sessionSummaryGate.js +66 -0
- package/dist/cli/v4/skinEngine.js +14 -3
- package/dist/cli/v4/toolPreview.js +153 -0
- package/dist/core/tools/nowPlaying.js +7 -15
- 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 +452 -0
- 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/toolRegistry.js +16 -1
- package/dist/core/v4/update/executeInstall.js +233 -0
- package/dist/core/version.js +1 -1
- package/dist/moat/memoryGuard.js +111 -0
- package/dist/moat/plannerGuard.js +19 -0
- package/dist/moat/skillTeacher.js +14 -5
- package/dist/providers/v4/chatCompletionsAdapter.js +9 -0
- package/dist/providers/v4/errors.js +112 -4
- package/dist/providers/v4/modelDefaults.js +65 -0
- package/dist/providers/v4/registry.js +9 -2
- package/dist/providers/v4/runtimeResolver.js +6 -0
- package/dist/tools/v4/index.js +80 -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 +177 -0
- package/dist/tools/v4/sessions/sessionSearch.js +5 -1
- package/dist/tools/v4/system/_psHelpers.js +123 -0
- package/dist/tools/v4/system/aidenSelfUpdate.js +162 -0
- package/dist/tools/v4/system/appClose.js +79 -0
- package/dist/tools/v4/system/appInput.js +154 -0
- package/dist/tools/v4/system/appLaunch.js +218 -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 +109 -0
- package/dist/tools/v4/system/mediaSessions.js +163 -0
- package/dist/tools/v4/system/mediaTransport.js +211 -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 +185 -69
|
@@ -86,9 +86,12 @@ function renderStatus(ctx, providerId, tokens) {
|
|
|
86
86
|
if (tokens.account)
|
|
87
87
|
ctx.display.write(` account: ${tokens.account}\n`);
|
|
88
88
|
ctx.display.write(` ${formatRelativeExpiry(tokens.expiresAtMs)}\n`);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
// Post-v4.1.1 cleanup: don't render `models:` — the stored list is
|
|
90
|
+
// captured at OAuth mint time and never refreshed, so it goes stale
|
|
91
|
+
// when the provider rotates its model catalog (e.g. OpenAI retired
|
|
92
|
+
// gpt-5 / gpt-5-mini in Feb 2026). The live model list lives in
|
|
93
|
+
// /model picker → providerCatalog.ts. /auth status is for AUTH
|
|
94
|
+
// state, not catalog state.
|
|
92
95
|
if (ctx.paths) {
|
|
93
96
|
ctx.display.dim(` file: ${node_path_1.default.join(ctx.paths.root, 'auth', `${providerId}.json`)}`);
|
|
94
97
|
}
|
|
@@ -32,35 +32,31 @@ exports.doctor = {
|
|
|
32
32
|
}
|
|
33
33
|
ctx.display.info('Running diagnostic checks...');
|
|
34
34
|
const report = await (0, doctor_1.runDoctor)({ paths: ctx.paths });
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
// `aiden doctor` CLI subcommand correctly omits this — the
|
|
43
|
-
// counters would always be zero there.
|
|
35
|
+
// v4.1.3-essentials doctor-polish: pull in-process subsystem
|
|
36
|
+
// health + skill-outcome data into the same report so they
|
|
37
|
+
// render as additional grouped sections inside the health box,
|
|
38
|
+
// not as disconnected blocks below it. `subsystemHealthResults`
|
|
39
|
+
// / `skillOutcomeResults` return empty arrays when their
|
|
40
|
+
// sources are unavailable so the grouped-renderer simply drops
|
|
41
|
+
// those sections.
|
|
44
42
|
if (ctx.agent) {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
ctx.display.write(`[url-provenance] blocked=${u.blocked} recovered=${u.recovered} failed=${u.failed} (session)\n`);
|
|
57
|
-
// Phase 23.4a-fix2: empty-response counters. detected =
|
|
58
|
-
// Codex backend completed a turn with no content and no tool
|
|
59
|
-
// calls; retried = corrective system message injected (cap
|
|
60
|
-
// 1/turn); recovered = retry yielded a non-empty reply.
|
|
61
|
-
const e = ctx.agent.getEmptyResponseMetrics();
|
|
62
|
-
ctx.display.write(`[empty-response] detected=${e.detected} retried=${e.retried} recovered=${e.recovered} (session)\n`);
|
|
43
|
+
const a = ctx.agent;
|
|
44
|
+
report.results.push(...(0, doctor_1.subsystemHealthResults)(a.subsystemHealthRegistry));
|
|
45
|
+
report.results.push(...(0, doctor_1.skillOutcomeResults)(a.skillOutcomeTracker));
|
|
46
|
+
// v4.1.3-essentials doctor-polish: session-scoped counters
|
|
47
|
+
// (skill enforcement / URL provenance / empty response) now
|
|
48
|
+
// fold into the same report so they render as a "Session
|
|
49
|
+
// counters" group INSIDE the box instead of as orphan
|
|
50
|
+
// `display.write` lines below it. Previous code emitted them
|
|
51
|
+
// as 3 separate `[bracket-prefix] key=N ...` lines after
|
|
52
|
+
// renderHealthBox closed — visually disconnected.
|
|
53
|
+
report.results.push(...(0, doctor_1.sessionCounterResults)(ctx.agent));
|
|
63
54
|
}
|
|
55
|
+
// v4.1.3-essentials doctor-polish: renderHealthBox now groups
|
|
56
|
+
// results by section header with a top summary. Same renderer
|
|
57
|
+
// is used by `aiden doctor` CLI path so both surfaces stay in
|
|
58
|
+
// visual sync (Path-A unification).
|
|
59
|
+
ctx.display.write((0, doctor_1.renderHealthBox)(report, ctx.display) + '\n');
|
|
64
60
|
return {};
|
|
65
61
|
},
|
|
66
62
|
};
|
|
@@ -36,6 +36,8 @@ exports.SUBSECTION_MAP = {
|
|
|
36
36
|
'debug-prompt': 'Configuration',
|
|
37
37
|
// ── Identity ── SOUL.md introspection
|
|
38
38
|
identity: 'Identity',
|
|
39
|
+
// Phase v4.1.2 alive-core: manual SOUL.md cache invalidation.
|
|
40
|
+
'reload-soul': 'Identity',
|
|
39
41
|
// ── System ── housekeeping & process control (default fallback)
|
|
40
42
|
doctor: 'System',
|
|
41
43
|
license: 'System',
|
|
@@ -54,6 +56,8 @@ exports.SUBSECTION_MAP = {
|
|
|
54
56
|
status: 'System',
|
|
55
57
|
show: 'System',
|
|
56
58
|
history: 'System',
|
|
59
|
+
// Phase v4.1.2-update — npm self-update for the running install.
|
|
60
|
+
update: 'System',
|
|
57
61
|
// ── Authentication ──
|
|
58
62
|
auth: 'Authentication',
|
|
59
63
|
// ── Help ──
|
|
@@ -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
|
];
|
|
@@ -106,7 +106,36 @@ exports.model = {
|
|
|
106
106
|
return {};
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
// v4.1.3-prebump: persist the selection to config.yaml so the NEXT
|
|
110
|
+
// boot honours the user's choice. Without this, `/model` only
|
|
111
|
+
// updated the live session — and the persisted `model.provider /
|
|
112
|
+
// model.modelId` keys (which Case 3 in providerBootSelector
|
|
113
|
+
// consults first) silently kept their stale values from the
|
|
114
|
+
// previous wizard run. Result: every reboot snapped the user back
|
|
115
|
+
// to the wizard's original pick (typically groq + llama-3.3-70b),
|
|
116
|
+
// confusing /model into looking like a "session-only" switch.
|
|
117
|
+
//
|
|
118
|
+
// The `aiden model` CLI subcommand (aidenCLI.ts:1773-1777) has
|
|
119
|
+
// always persisted; this brings the REPL `/model` path in line.
|
|
120
|
+
// Best-effort: if `ctx.config` isn't plumbed (test harness, etc.)
|
|
121
|
+
// we still succeeded for the live session — emit a subtle warning
|
|
122
|
+
// instead of failing the whole switch.
|
|
123
|
+
let persisted = false;
|
|
124
|
+
if (ctx.config) {
|
|
125
|
+
try {
|
|
126
|
+
ctx.config.set('model.provider', providerId);
|
|
127
|
+
ctx.config.set('model.modelId', modelId);
|
|
128
|
+
await ctx.config.save();
|
|
129
|
+
persisted = true;
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
ctx.display.warn(`Switched the live session but could not persist to config.yaml: ` +
|
|
133
|
+
`${err.message}. Next boot may revert.`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
ctx.display.success(persisted
|
|
137
|
+
? `Now using ${providerId}:${modelId} (saved to config.yaml)`
|
|
138
|
+
: `Now using ${providerId}:${modelId} (session only — not persisted)`);
|
|
110
139
|
return {};
|
|
111
140
|
},
|
|
112
141
|
};
|
|
@@ -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.
|
|
@@ -0,0 +1,135 @@
|
|
|
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/display/capabilityCard.ts — Aiden v4.1.3-essentials.
|
|
10
|
+
*
|
|
11
|
+
* Renders the structured "capability card" tools return on certain
|
|
12
|
+
* failure classes:
|
|
13
|
+
* 1. Platform unsupported (e.g. media_transport called on Linux)
|
|
14
|
+
* 2. Auth missing (provider 401/403, or a tool that needs a specific
|
|
15
|
+
* OAuth/API key)
|
|
16
|
+
*
|
|
17
|
+
* Distinct from the one-line tool-trail row (`display.toolRow`) because
|
|
18
|
+
* it's a different category of information — a state assessment of
|
|
19
|
+
* what the user CAN still do versus what they CANNOT, with a one-line
|
|
20
|
+
* fix hint. Rendered as a box-bordered multi-line block.
|
|
21
|
+
*
|
|
22
|
+
* Pure module — takes the data + a colorize callback, returns lines.
|
|
23
|
+
* No I/O, no SkinEngine reach-through. Caller writes the result.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.renderCapabilityCard = renderCapabilityCard;
|
|
27
|
+
exports.truncToContent = truncToContent;
|
|
28
|
+
const box_1 = require("../box");
|
|
29
|
+
/** Total card width (chars). Wide enough for typical action labels;
|
|
30
|
+
* short enough to stay readable on narrow terminals. */
|
|
31
|
+
const CARD_WIDTH = 64;
|
|
32
|
+
/** Box-content width = CARD_WIDTH minus 2 border chars and 2 padding. */
|
|
33
|
+
const CONTENT_WIDTH = CARD_WIDTH - 4;
|
|
34
|
+
/**
|
|
35
|
+
* Render a capability card from `data`. Returns an array of lines
|
|
36
|
+
* (no trailing newlines). Caller writes them with appended `\n`:
|
|
37
|
+
*
|
|
38
|
+
* for (const line of renderCapabilityCard(data, colorize)) {
|
|
39
|
+
* display.write(line + '\n');
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* Layout:
|
|
43
|
+
*
|
|
44
|
+
* ┌── ⚠ <title> ──────────────────────────────┐
|
|
45
|
+
* │ │
|
|
46
|
+
* │ Can still: │
|
|
47
|
+
* │ ✓ <action 1> │
|
|
48
|
+
* │ ✓ <action 2> │
|
|
49
|
+
* │ │
|
|
50
|
+
* │ Cannot reliably: │
|
|
51
|
+
* │ ✗ <action 1> │
|
|
52
|
+
* │ ✗ <action 2> │
|
|
53
|
+
* │ │
|
|
54
|
+
* │ Fix: <one-line guidance> │
|
|
55
|
+
* └───────────────────────────────────────────┘
|
|
56
|
+
*
|
|
57
|
+
* Empty `canStill` or `cannotReliably` arrays cause the corresponding
|
|
58
|
+
* section to be omitted (no empty heading). Always renders at least
|
|
59
|
+
* the title + fix line so the user has actionable signal.
|
|
60
|
+
*/
|
|
61
|
+
function renderCapabilityCard(data, colorize) {
|
|
62
|
+
// Pre-color the section headings + bullet markers.
|
|
63
|
+
const heading = (s) => colorize(s, 'warn');
|
|
64
|
+
const okMark = colorize('✓', 'success');
|
|
65
|
+
const noMark = colorize('✗', 'error');
|
|
66
|
+
const fixLbl = colorize('Fix:', 'tool');
|
|
67
|
+
// Compose the inner rows that boxSharp will wrap. Each row is the
|
|
68
|
+
// CONTENT (no border) — boxSharp adds the side borders + padding.
|
|
69
|
+
const rows = [];
|
|
70
|
+
if (data.canStill.length > 0) {
|
|
71
|
+
rows.push('');
|
|
72
|
+
rows.push(heading('Can still:'));
|
|
73
|
+
for (const action of data.canStill) {
|
|
74
|
+
rows.push(` ${okMark} ${truncToContent(action)}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (data.cannotReliably.length > 0) {
|
|
78
|
+
rows.push('');
|
|
79
|
+
rows.push(heading('Cannot reliably:'));
|
|
80
|
+
for (const action of data.cannotReliably) {
|
|
81
|
+
rows.push(` ${noMark} ${truncToContent(action)}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
rows.push('');
|
|
85
|
+
// Fix line — split-wrap to two lines if needed so long guidance
|
|
86
|
+
// doesn't get cut off mid-sentence by boxSharp's clipper.
|
|
87
|
+
const fixText = data.fix;
|
|
88
|
+
const fixPrefix = 'Fix: ';
|
|
89
|
+
const fixPrefixVis = (0, box_1.visibleLength)(fixPrefix);
|
|
90
|
+
if ((0, box_1.visibleLength)(fixText) + fixPrefixVis <= CONTENT_WIDTH) {
|
|
91
|
+
rows.push(`${fixLbl} ${fixText}`);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
rows.push(fixLbl);
|
|
95
|
+
// Wrap the fix text across content-width lines.
|
|
96
|
+
let remaining = fixText;
|
|
97
|
+
const wrapLimit = CONTENT_WIDTH - 2; // 2-space indent
|
|
98
|
+
while (remaining.length > 0) {
|
|
99
|
+
const chunk = remaining.length <= wrapLimit
|
|
100
|
+
? remaining
|
|
101
|
+
: breakAtWord(remaining, wrapLimit);
|
|
102
|
+
rows.push(` ${chunk}`);
|
|
103
|
+
remaining = remaining.slice(chunk.length).trimStart();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
rows.push('');
|
|
107
|
+
// Title is rendered into the top border by boxSharp. Prefix with
|
|
108
|
+
// a warning glyph (yellow) so the user reads it as an attention card.
|
|
109
|
+
const title = `${colorize('⚠', 'warn')} ${data.title}`;
|
|
110
|
+
return (0, box_1.boxSharp)(rows, CARD_WIDTH, title).split('\n');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Shorten an action label so it fits the bullet column with room for
|
|
114
|
+
* the marker (" ✓ ") and the border padding. Appends an ellipsis when
|
|
115
|
+
* truncated. Pure — exported for unit tests.
|
|
116
|
+
*/
|
|
117
|
+
function truncToContent(s) {
|
|
118
|
+
// Reserve 6 chars for " ✓ " prefix + 2 for border padding margin.
|
|
119
|
+
const cap = CONTENT_WIDTH - 6;
|
|
120
|
+
if ((0, box_1.visibleLength)(s) <= cap)
|
|
121
|
+
return s;
|
|
122
|
+
return s.slice(0, cap - 1) + '…';
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Break `s` at the last word boundary at-or-before `limit`. Falls back
|
|
126
|
+
* to a hard cut at `limit` when no whitespace appears in the prefix.
|
|
127
|
+
* Pure helper used by the Fix-line wrapper.
|
|
128
|
+
*/
|
|
129
|
+
function breakAtWord(s, limit) {
|
|
130
|
+
if (s.length <= limit)
|
|
131
|
+
return s;
|
|
132
|
+
const slice = s.slice(0, limit);
|
|
133
|
+
const lastSpace = slice.lastIndexOf(' ');
|
|
134
|
+
return lastSpace > 0 ? slice.slice(0, lastSpace) : slice;
|
|
135
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
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/display/sessionEndCard.ts — Aiden v4.1.3-repl-polish
|
|
10
|
+
*
|
|
11
|
+
* Renders a compact session-end summary card from a SessionDistillation.
|
|
12
|
+
*
|
|
13
|
+
* Returned as an array of plain lines (WITHOUT trailing '\n'). The caller
|
|
14
|
+
* writes them with a newline appended, e.g.:
|
|
15
|
+
*
|
|
16
|
+
* for (const line of renderSessionEndCard(dist, colorize)) {
|
|
17
|
+
* display.write(line + '\n');
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* Design rules (from spec):
|
|
21
|
+
* - Skip entirely when user_turns === 0 (silent/internal sessions).
|
|
22
|
+
* - Label column is colon-aligned to column LABEL_COL (14).
|
|
23
|
+
* - Session ID rendered in 'session' color (soft cyan).
|
|
24
|
+
* - Bullets / decisions / open_items shown only when non-empty.
|
|
25
|
+
* - Takes a `colorize` callback instead of a SkinEngine directly, so
|
|
26
|
+
* the function is fully unit-testable without a Display stack.
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.renderSessionEndCard = renderSessionEndCard;
|
|
30
|
+
/** Width of the "Label:" prefix, colon included, padded to this column. */
|
|
31
|
+
const LABEL_COL = 14;
|
|
32
|
+
/** Horizontal rule width (chars). */
|
|
33
|
+
const HR_WIDTH = 48;
|
|
34
|
+
// ── Internal helpers ──────────────────────────────────────────────────────────
|
|
35
|
+
function labelRow(label, value) {
|
|
36
|
+
return `${`${label}:`.padEnd(LABEL_COL)}${value}`;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Format a wall-clock duration from two ISO timestamps.
|
|
40
|
+
* Returns '—' when the delta is ≤0 or non-finite (e.g. partial distillation).
|
|
41
|
+
*/
|
|
42
|
+
function fmtDuration(startIso, endIso) {
|
|
43
|
+
const ms = new Date(endIso).getTime() - new Date(startIso).getTime();
|
|
44
|
+
if (!Number.isFinite(ms) || ms <= 0)
|
|
45
|
+
return '—';
|
|
46
|
+
const sec = ms / 1000;
|
|
47
|
+
if (sec < 60)
|
|
48
|
+
return `${Math.round(sec)}s`;
|
|
49
|
+
const mins = Math.floor(sec / 60);
|
|
50
|
+
const remSec = Math.round(sec - mins * 60);
|
|
51
|
+
return remSec > 0 ? `${mins}m ${remSec}s` : `${mins}m`;
|
|
52
|
+
}
|
|
53
|
+
// ── Public API ────────────────────────────────────────────────────────────────
|
|
54
|
+
/**
|
|
55
|
+
* Render a session-end card from `dist`.
|
|
56
|
+
*
|
|
57
|
+
* @param dist Completed SessionDistillation (may be partial).
|
|
58
|
+
* @param colorize Skin-aware colorizer — `(text, kind) => coloredText`.
|
|
59
|
+
* @param distillationPath Absolute path the distillation JSON was written to,
|
|
60
|
+
* if any. Rendered as a `Distillation:` row so the
|
|
61
|
+
* user has something concrete to inspect / pass to
|
|
62
|
+
* recall_session. Omitted from the card when null /
|
|
63
|
+
* undefined (e.g. write failed earlier).
|
|
64
|
+
* @returns Array of lines (no trailing newlines). Empty when
|
|
65
|
+
* `user_turns === 0`.
|
|
66
|
+
*/
|
|
67
|
+
function renderSessionEndCard(dist, colorize, distillationPath) {
|
|
68
|
+
if (dist.user_turns === 0)
|
|
69
|
+
return [];
|
|
70
|
+
const lines = [];
|
|
71
|
+
const hr = colorize('─'.repeat(HR_WIDTH), 'muted');
|
|
72
|
+
const bullet = colorize('•', 'muted');
|
|
73
|
+
// ── Header block ───────────────────────────────────────────────────────
|
|
74
|
+
lines.push(hr);
|
|
75
|
+
lines.push(labelRow('Session', colorize(dist.session_id, 'session')));
|
|
76
|
+
lines.push(labelRow('Duration', fmtDuration(dist.started_at, dist.ended_at)));
|
|
77
|
+
lines.push(labelRow('Turns', String(dist.user_turns)));
|
|
78
|
+
lines.push(labelRow('Exit', dist.exit_path));
|
|
79
|
+
if (dist.files_touched.length > 0) {
|
|
80
|
+
// Show at most 6 files; truncate list with '…' if longer.
|
|
81
|
+
const shown = dist.files_touched.slice(0, 6);
|
|
82
|
+
const suffix = dist.files_touched.length > 6
|
|
83
|
+
? ` … +${dist.files_touched.length - 6} more`
|
|
84
|
+
: '';
|
|
85
|
+
lines.push(labelRow('Files', shown.join(', ') + suffix));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
lines.push(labelRow('Files', colorize('(none)', 'muted')));
|
|
89
|
+
}
|
|
90
|
+
if (dist.tools_used.length > 0) {
|
|
91
|
+
const top = [...dist.tools_used]
|
|
92
|
+
.sort((a, b) => b.count - a.count)
|
|
93
|
+
.slice(0, 5)
|
|
94
|
+
.map(t => `${t.name}(${t.count})`)
|
|
95
|
+
.join(', ');
|
|
96
|
+
lines.push(labelRow('Tools', top));
|
|
97
|
+
}
|
|
98
|
+
if (distillationPath) {
|
|
99
|
+
lines.push(labelRow('Distillation', colorize(distillationPath, 'muted')));
|
|
100
|
+
}
|
|
101
|
+
lines.push(hr);
|
|
102
|
+
// ── Semantic sections (LLM-generated, may be empty on partial) ─────────
|
|
103
|
+
if (dist.bullets.length > 0) {
|
|
104
|
+
lines.push('');
|
|
105
|
+
lines.push(colorize('What happened:', 'heading'));
|
|
106
|
+
for (const b of dist.bullets) {
|
|
107
|
+
lines.push(` ${bullet} ${b}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (dist.decisions.length > 0) {
|
|
111
|
+
lines.push('');
|
|
112
|
+
lines.push(colorize('Decisions:', 'heading'));
|
|
113
|
+
for (const d of dist.decisions) {
|
|
114
|
+
lines.push(` ${bullet} ${d}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (dist.open_items.length > 0) {
|
|
118
|
+
lines.push('');
|
|
119
|
+
lines.push(colorize('Open items:', 'heading'));
|
|
120
|
+
for (const o of dist.open_items) {
|
|
121
|
+
lines.push(` ${bullet} ${o}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Blank line so "Goodbye." has breathing room.
|
|
125
|
+
lines.push('');
|
|
126
|
+
return lines;
|
|
127
|
+
}
|