aiden-runtime 4.1.2 → 4.1.4
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/dist/cli/v4/aidenCLI.js +10 -0
- package/dist/cli/v4/callbacks.js +85 -13
- package/dist/cli/v4/chatSession.js +250 -24
- package/dist/cli/v4/commands/doctor.js +23 -27
- package/dist/cli/v4/commands/model.js +30 -1
- package/dist/cli/v4/defaultSoul.js +69 -2
- package/dist/cli/v4/display/capabilityCard.js +135 -0
- package/dist/cli/v4/display/frame.js +234 -0
- package/dist/cli/v4/display/progressBar.js +137 -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 +891 -153
- package/dist/cli/v4/doctor.js +377 -75
- package/dist/cli/v4/promotionPrompt.js +135 -5
- package/dist/cli/v4/replyRenderer.js +487 -26
- package/dist/cli/v4/skinEngine.js +26 -4
- package/dist/cli/v4/toolPreview.js +82 -19
- package/dist/core/tools/nowPlaying.js +7 -15
- package/dist/core/v4/aidenAgent.js +9 -0
- package/dist/core/v4/promptBuilder.js +2 -1
- package/dist/core/v4/sessionDistiller.js +48 -1
- package/dist/core/v4/toolRegistry.js +16 -1
- package/dist/core/version.js +1 -1
- package/dist/moat/plannerGuard.js +19 -0
- package/dist/providers/v4/anthropicAdapter.js +25 -2
- package/dist/providers/v4/errors.js +92 -0
- package/dist/tools/v4/index.js +24 -1
- package/dist/tools/v4/sessions/recallSession.js +14 -0
- package/dist/tools/v4/system/_psHelpers.js +70 -2
- package/dist/tools/v4/system/appInput.js +154 -0
- package/dist/tools/v4/system/appLaunch.js +136 -10
- package/dist/tools/v4/system/mediaKey.js +35 -4
- package/dist/tools/v4/system/mediaSessions.js +163 -0
- package/dist/tools/v4/system/mediaTransport.js +211 -0
- package/package.json +2 -1
- package/skills/system_control.md +56 -6
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
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/toolTrail.ts — Aiden v4.1.3-repl-polish
|
|
10
|
+
*
|
|
11
|
+
* Icon + verb lookup for the compact tool-trail rows.
|
|
12
|
+
*
|
|
13
|
+
* Format rendered by Display.toolRow():
|
|
14
|
+
*
|
|
15
|
+
* ┊ {icon} {verb:12} {detail:40}
|
|
16
|
+
*
|
|
17
|
+
* Rules:
|
|
18
|
+
* - Exact tool-name match tried first (lowercased), then substring,
|
|
19
|
+
* then the '·' / 'calling' fallback.
|
|
20
|
+
* - Success outcomes are SILENT — the running row is erased and nothing
|
|
21
|
+
* persists. Only failed/degraded/blocked rows leave a trace.
|
|
22
|
+
* - This module is pure (no I/O, no side effects) so it can be tested
|
|
23
|
+
* in full isolation.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.TRAIL_PIPE = exports.TRAIL_DETAIL_CAP = exports.TRAIL_VERB_PAD = void 0;
|
|
27
|
+
exports.iconForTool = iconForTool;
|
|
28
|
+
exports.padVerb = padVerb;
|
|
29
|
+
exports.truncDetail = truncDetail;
|
|
30
|
+
/** Width the verb field is padded / trimmed to. */
|
|
31
|
+
exports.TRAIL_VERB_PAD = 12;
|
|
32
|
+
/** Hard cap on the detail (arg-preview) field. */
|
|
33
|
+
exports.TRAIL_DETAIL_CAP = 40;
|
|
34
|
+
/** Row-prefix glyph that replaces the old indent dots. */
|
|
35
|
+
exports.TRAIL_PIPE = '┊';
|
|
36
|
+
/**
|
|
37
|
+
* Ordered lookup table: tool name patterns → { icon, verb }.
|
|
38
|
+
*
|
|
39
|
+
* Exact match (lowercased tool name present in `keys`) is tried before
|
|
40
|
+
* substring match. Entries are ordered from most-specific to most-generic
|
|
41
|
+
* so that e.g. `recall_session` matches 'recalling' before the generic
|
|
42
|
+
* `memory` → 'recalling' entry would.
|
|
43
|
+
*
|
|
44
|
+
* Keep entries grouped by semantic category to make auditing easy.
|
|
45
|
+
*/
|
|
46
|
+
const TRAIL_MAP = [
|
|
47
|
+
// ── Observe / read / list ────────────────────────────────────────────
|
|
48
|
+
{ keys: ['file_read', 'read_file', 'read_text_file', 'read_multiple_files',
|
|
49
|
+
'file_list', 'list_directory', 'list_directory_with_sizes',
|
|
50
|
+
'directory_tree', 'file_info', 'get_file_info',
|
|
51
|
+
'observe', 'read', 'list'],
|
|
52
|
+
icon: '👁', verb: 'reading' },
|
|
53
|
+
// ── Write / edit / create ────────────────────────────────────────────
|
|
54
|
+
{ keys: ['file_write', 'write_file', 'edit_file', 'move_file',
|
|
55
|
+
'notebook_edit', 'create_directory',
|
|
56
|
+
'write', 'edit', 'create', 'save'],
|
|
57
|
+
icon: '✏', verb: 'writing' },
|
|
58
|
+
// ── Execute / run / shell ────────────────────────────────────────────
|
|
59
|
+
{ keys: ['bash', 'powershell', 'execute_code', 'skill_view',
|
|
60
|
+
'shortcuts_execute', 'javascript_tool',
|
|
61
|
+
'shell_exec', 'process_spawn', 'process_kill',
|
|
62
|
+
'run', 'execute', 'exec'],
|
|
63
|
+
icon: '⚡', verb: 'running' },
|
|
64
|
+
// ── Clipboard ────────────────────────────────────────────────────────
|
|
65
|
+
{ keys: ['clipboard_read', 'clipboard_write', 'clipboard'],
|
|
66
|
+
icon: '📋', verb: 'copying' },
|
|
67
|
+
// ── Web / fetch / browse ─────────────────────────────────────────────
|
|
68
|
+
{ keys: ['web_search', 'web_fetch', 'fetch_url', 'fetch_page',
|
|
69
|
+
'open_url', 'navigate', 'get_page_text', 'read_page',
|
|
70
|
+
'browser_extract', 'browser_get_url',
|
|
71
|
+
'search_cloudflare_documentation', 'search_vercel_documentation',
|
|
72
|
+
'search_mcp_registry',
|
|
73
|
+
'browser', 'fetch', 'search'],
|
|
74
|
+
icon: '🌐', verb: 'fetching' },
|
|
75
|
+
// ── Memory / recall ──────────────────────────────────────────────────
|
|
76
|
+
{ keys: ['recall_session', 'session_search', 'session_list',
|
|
77
|
+
'memory_add', 'memory_search',
|
|
78
|
+
'recall', 'memory'],
|
|
79
|
+
icon: '🧠', verb: 'recalling' },
|
|
80
|
+
// ── Think / analyse / summarise ──────────────────────────────────────
|
|
81
|
+
{ keys: ['session_summary', 'deep_research', 'analyze', 'think', 'plan'],
|
|
82
|
+
icon: '🧠', verb: 'thinking' },
|
|
83
|
+
// ── Skills / tools / catalog ─────────────────────────────────────────
|
|
84
|
+
{ keys: ['skills_list', 'list_connectors', 'suggest_connectors',
|
|
85
|
+
'skill'],
|
|
86
|
+
icon: '📋', verb: 'listing' },
|
|
87
|
+
// ── Screen / capture / inspect ───────────────────────────────────────
|
|
88
|
+
{ keys: ['screenshot', 'browser_screenshot', 'aiden__screenshot',
|
|
89
|
+
'preview_screenshot', 'preview_snapshot', 'preview_inspect',
|
|
90
|
+
'computer', 'upload_image', 'read_media_file'],
|
|
91
|
+
icon: '🖥', verb: 'capturing' },
|
|
92
|
+
// ── Media control ────────────────────────────────────────────────────
|
|
93
|
+
// v4.1.4-media: the new three-layer media-control bundle.
|
|
94
|
+
// Listed BEFORE the launch category so substring matching on `media_*`
|
|
95
|
+
// tool names hits this category first — without this split, every
|
|
96
|
+
// media_* name's substring would collide with the 'media' key in the
|
|
97
|
+
// launch bucket and render as verb "launching".
|
|
98
|
+
{ keys: ['media_key', 'media_sessions', 'media_transport',
|
|
99
|
+
'now_playing', 'youtube_search'],
|
|
100
|
+
icon: '▶', verb: 'media' },
|
|
101
|
+
// ── Media launch / open ──────────────────────────────────────────────
|
|
102
|
+
// Note: `'media'` as a substring key was removed in v4.1.4 because it
|
|
103
|
+
// false-matched the new media_* control tools above. Launch tools
|
|
104
|
+
// (`app_launch`, `open_url`, etc.) are explicit-keyed.
|
|
105
|
+
{ keys: ['app_launch', 'open_url', 'open', 'launch'],
|
|
106
|
+
icon: '▶', verb: 'launching' },
|
|
107
|
+
// ── Deploy / build / publish ─────────────────────────────────────────
|
|
108
|
+
{ keys: ['deploy_to_vercel', 'deploy_edge_function', 'apply_migration',
|
|
109
|
+
'push_notification',
|
|
110
|
+
'deploy', 'build', 'package', 'push'],
|
|
111
|
+
icon: '📦', verb: 'deploying' },
|
|
112
|
+
// ── Message / notify / send ──────────────────────────────────────────
|
|
113
|
+
{ keys: ['create_draft', 'reply_to_toolbar_thread',
|
|
114
|
+
'send', 'message', 'notify', 'email', 'reply'],
|
|
115
|
+
icon: '💬', verb: 'sending' },
|
|
116
|
+
// ── Verify / test / health ───────────────────────────────────────────
|
|
117
|
+
{ keys: ['get_advisors', 'confirm_cost', 'subsystem_health',
|
|
118
|
+
'verify', 'test', 'doctor', 'health'],
|
|
119
|
+
icon: '🛡', verb: 'verifying' },
|
|
120
|
+
// ── Database / query ─────────────────────────────────────────────────
|
|
121
|
+
{ keys: ['execute_sql', 'd1_database_query',
|
|
122
|
+
'query', 'sql'],
|
|
123
|
+
icon: '🗄', verb: 'querying' },
|
|
124
|
+
];
|
|
125
|
+
/**
|
|
126
|
+
* Return the trail icon and verb for `name`.
|
|
127
|
+
*
|
|
128
|
+
* 1. Exact match — lowercased tool name is in `entry.keys`
|
|
129
|
+
* 2. Substring match — any key appears in the lowercased name
|
|
130
|
+
* 3. Default fallback: `{ icon: '⚡', verb: 'calling' }` — generic
|
|
131
|
+
* energy glyph for unmapped tools so the row still visually parses
|
|
132
|
+
* as a tool event even when the category is unknown.
|
|
133
|
+
*
|
|
134
|
+
* Pure — no side effects. Safe to call in hot paths.
|
|
135
|
+
*/
|
|
136
|
+
function iconForTool(name) {
|
|
137
|
+
const lc = name.toLowerCase();
|
|
138
|
+
// Pass 1 — exact match
|
|
139
|
+
for (const entry of TRAIL_MAP) {
|
|
140
|
+
if (entry.keys.includes(lc)) {
|
|
141
|
+
return { icon: entry.icon, verb: entry.verb };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Pass 2 — substring match (insertion order = priority)
|
|
145
|
+
for (const entry of TRAIL_MAP) {
|
|
146
|
+
for (const key of entry.keys) {
|
|
147
|
+
if (lc.includes(key)) {
|
|
148
|
+
return { icon: entry.icon, verb: entry.verb };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { icon: '⚡', verb: 'calling' };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Pad or trim `verb` to exactly TRAIL_VERB_PAD characters.
|
|
156
|
+
* Pure helper used by Display.toolRow() to keep columns aligned.
|
|
157
|
+
*/
|
|
158
|
+
function padVerb(verb) {
|
|
159
|
+
if (verb.length > exports.TRAIL_VERB_PAD)
|
|
160
|
+
return verb.slice(0, exports.TRAIL_VERB_PAD);
|
|
161
|
+
return verb.padEnd(exports.TRAIL_VERB_PAD);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Truncate `s` to TRAIL_DETAIL_CAP chars, appending '…' when cut.
|
|
165
|
+
* Collapses internal whitespace first so multi-line args stay on one line.
|
|
166
|
+
*/
|
|
167
|
+
function truncDetail(s) {
|
|
168
|
+
const flat = s.replace(/\s+/g, ' ').trim();
|
|
169
|
+
if (flat.length <= exports.TRAIL_DETAIL_CAP)
|
|
170
|
+
return flat;
|
|
171
|
+
return flat.slice(0, exports.TRAIL_DETAIL_CAP - 1) + '…';
|
|
172
|
+
}
|