aiden-runtime 4.0.1 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -7
- package/config/hardware.json +2 -2
- package/dist/api/server.js +50 -52
- package/dist/cli/v4/aidenCLI.js +513 -14
- package/dist/cli/v4/aidenPrompt.js +317 -0
- package/dist/cli/v4/box.js +105 -39
- package/dist/cli/v4/callbacks.js +39 -6
- package/dist/cli/v4/chatSession.js +269 -52
- package/dist/cli/v4/citationFooter.js +97 -0
- package/dist/cli/v4/commands/channel.js +656 -0
- package/dist/cli/v4/commands/clear.js +1 -1
- package/dist/cli/v4/commands/compress.js +1 -1
- package/dist/cli/v4/commands/cron.js +44 -16
- package/dist/cli/v4/commands/fanout.js +236 -0
- package/dist/cli/v4/commands/help.js +15 -4
- package/dist/cli/v4/commands/history.js +84 -0
- package/dist/cli/v4/commands/index.js +19 -1
- package/dist/cli/v4/commands/mcp.js +358 -0
- package/dist/cli/v4/commands/setup.js +34 -0
- package/dist/cli/v4/commands/show.js +43 -0
- package/dist/cli/v4/commands/skills.js +169 -4
- package/dist/cli/v4/commands/status.js +84 -0
- package/dist/cli/v4/commands/subagent.js +78 -0
- package/dist/cli/v4/commands/verbose.js +1 -1
- package/dist/cli/v4/commands/voice.js +218 -0
- package/dist/cli/v4/cronCli.js +103 -0
- package/dist/cli/v4/display.js +300 -14
- package/dist/cli/v4/doctor.js +41 -0
- package/dist/cli/v4/envSources.js +105 -0
- package/dist/cli/v4/ghostMatch.js +74 -0
- package/dist/cli/v4/historyStore.js +163 -0
- package/dist/cli/v4/pasteCompression.js +124 -0
- package/dist/cli/v4/pasteIntercept.js +203 -0
- package/dist/cli/v4/replyRenderer.js +209 -0
- package/dist/cli/v4/resizeGuard.js +92 -0
- package/dist/cli/v4/setupWizard.js +466 -232
- package/dist/cli/v4/shellInterpolation.js +139 -0
- package/dist/cli/v4/skinEngine.js +21 -1
- package/dist/cli/v4/streamingPrefix.js +121 -0
- package/dist/cli/v4/syntaxHighlight.js +345 -0
- package/dist/cli/v4/table.js +216 -0
- package/dist/cli/v4/themeDetect.js +81 -0
- package/dist/cli/v4/uiBuild.js +74 -0
- package/dist/cli/v4/voiceCli.js +113 -0
- package/dist/cli/v4/voicePromptApi.js +196 -0
- package/dist/core/channels/discord.js +16 -10
- package/dist/core/channels/email.js +13 -9
- package/dist/core/channels/imessage.js +13 -9
- package/dist/core/channels/manager.js +25 -7
- package/dist/core/channels/pdf-extract.js +180 -0
- package/dist/core/channels/photo-vision.js +157 -0
- package/dist/core/channels/signal.js +11 -7
- package/dist/core/channels/slack.js +13 -10
- package/dist/core/channels/telegram-commands.js +154 -0
- package/dist/core/channels/telegram-groups.js +198 -0
- package/dist/core/channels/telegram-rate-limit.js +124 -0
- package/dist/core/channels/telegram.js +1980 -0
- package/dist/core/channels/twilio.js +11 -7
- package/dist/core/channels/webhook.js +9 -5
- package/dist/core/channels/whatsapp.js +15 -11
- package/dist/core/channels/whisper-transcribe.js +163 -0
- package/dist/core/cronManager.js +33 -294
- package/dist/core/gateway.js +29 -8
- package/dist/core/playwrightBridge.js +90 -0
- package/dist/core/v4/aidenAgent.js +35 -0
- package/dist/core/v4/auxiliaryClient.js +2 -2
- package/dist/core/v4/cron/atomicWrite.js +18 -4
- package/dist/core/v4/cron/cronExecute.js +300 -0
- package/dist/core/v4/cron/cronManager.js +502 -0
- package/dist/core/v4/cron/cronState.js +314 -0
- package/dist/core/v4/cron/cronTick.js +90 -0
- package/dist/core/v4/cron/diagnostics.js +104 -0
- package/dist/core/v4/cron/graceWindow.js +79 -0
- package/dist/core/v4/firstRun/providerDetection.js +287 -0
- package/dist/core/v4/logger/factory.js +110 -0
- package/dist/core/v4/logger/index.js +22 -0
- package/dist/core/v4/logger/logger.js +101 -0
- package/dist/core/v4/logger/sinks/fileSink.js +110 -0
- package/dist/core/v4/logger/sinks/multiSink.js +43 -0
- package/dist/core/v4/logger/sinks/nullSink.js +53 -0
- package/dist/core/v4/logger/sinks/stdSink.js +81 -0
- package/dist/core/v4/mcp/server/diagnostics.js +40 -0
- package/dist/core/v4/mcp/server/skillBridge.js +94 -0
- package/dist/core/v4/mcp/server/stdioServer.js +119 -0
- package/dist/core/v4/mcp/server/toolBridge.js +168 -0
- package/dist/core/v4/platformPaths.js +105 -0
- package/dist/core/v4/providerFallback.js +25 -0
- package/dist/core/v4/skillLoader.js +21 -5
- package/dist/core/v4/skillMining/candidateStore.js +164 -0
- package/dist/core/v4/skillMining/extractorPrompt.js +111 -0
- package/dist/core/v4/skillMining/proposalBuilder.js +139 -0
- package/dist/core/v4/skillMining/skillMiner.js +191 -0
- package/dist/core/v4/skillMining/traceFingerprint.js +51 -0
- package/dist/core/v4/subagent/budget.js +76 -0
- package/dist/core/v4/subagent/diagnostics.js +22 -0
- package/dist/core/v4/subagent/fanout.js +216 -0
- package/dist/core/v4/subagent/merger.js +148 -0
- package/dist/core/v4/subagent/providerRotation.js +54 -0
- package/dist/core/v4/voice/audioStream.js +373 -0
- package/dist/core/v4/voice/cliVoice.js +393 -0
- package/dist/core/v4/voice/diagnostics.js +66 -0
- package/dist/core/v4/voice/ttsStream.js +193 -0
- package/dist/core/version.js +1 -1
- package/dist/core/visionAnalyze.js +291 -90
- package/dist/core/voice/audio.js +61 -5
- package/dist/core/voice/audioBackend.js +134 -0
- package/dist/core/voice/stt.js +61 -6
- package/dist/core/voice/tts.js +19 -3
- package/dist/providers/v4/nullAdapter.js +58 -0
- package/dist/tools/v4/index.js +32 -1
- package/dist/tools/v4/subagent/subagentFanout.js +166 -0
- package/package.json +11 -2
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 Shiva Deore (Taracod). Licensed under AGPL-3.0.
|
|
4
|
+
*
|
|
5
|
+
* Aiden — local-first agent.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* cli/v4/replyRenderer.ts — Phase v4.1-reply-formatting
|
|
9
|
+
*
|
|
10
|
+
* Configures marked-terminal with skin-aware renderers so Aiden's
|
|
11
|
+
* agent replies render as structured markdown instead of raw walls
|
|
12
|
+
* of text. Headers, lists, code blocks, blockquotes, inline emphasis,
|
|
13
|
+
* and links all get terminal-friendly painting.
|
|
14
|
+
*
|
|
15
|
+
* The renderer is an instance — `getReplyRenderer().render(text)`
|
|
16
|
+
* returns the painted string. Used by:
|
|
17
|
+
* - `display.markdown(text)` (non-streaming agent reply)
|
|
18
|
+
* - `display.streamComplete()` (post-stream re-render, optional)
|
|
19
|
+
* - the citation footer composer
|
|
20
|
+
*
|
|
21
|
+
* Stable-prefix split for streaming lives in `streamingPrefix.ts`
|
|
22
|
+
* (pure function over the buffered text); this module is only the
|
|
23
|
+
* static renderer.
|
|
24
|
+
*
|
|
25
|
+
* NO_COLOR honour: the skin engine already returns plain text when
|
|
26
|
+
* `NO_COLOR` is set, so every paint call gracefully degrades.
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.getReplyRenderer = getReplyRenderer;
|
|
30
|
+
exports._resetForTests = _resetForTests;
|
|
31
|
+
const marked_1 = require("marked");
|
|
32
|
+
const skinEngine_1 = require("./skinEngine");
|
|
33
|
+
const syntaxHighlight_1 = require("./syntaxHighlight");
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
35
|
+
const TerminalRenderer = require('marked-terminal').default ?? require('marked-terminal');
|
|
36
|
+
function paint(kind) {
|
|
37
|
+
return (text) => (0, skinEngine_1.getSkinEngine)().applyColors(text, kind);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Render a fenced code block: top divider with language label, body
|
|
41
|
+
* with optional syntax highlighting, bottom divider.
|
|
42
|
+
*
|
|
43
|
+
* ── typescript ─────────────
|
|
44
|
+
* const x = 1;
|
|
45
|
+
* ──────────────────────────
|
|
46
|
+
*
|
|
47
|
+
* Used by the prototype-override path below — marked-terminal's
|
|
48
|
+
* internal `Renderer.prototype.code` ignores user `opts.code` and
|
|
49
|
+
* runs its own highlighter, so we override the prototype method
|
|
50
|
+
* directly. The token-object signature is what marked v15 calls
|
|
51
|
+
* the renderer with; the older positional path is kept for
|
|
52
|
+
* compatibility.
|
|
53
|
+
*/
|
|
54
|
+
function renderCodeBlock(code, lang) {
|
|
55
|
+
const sk = (0, skinEngine_1.getSkinEngine)();
|
|
56
|
+
const width = Math.min(process.stdout.columns ?? 80, 100) - 4;
|
|
57
|
+
const langLabel = (lang ?? '').trim();
|
|
58
|
+
const top = langLabel
|
|
59
|
+
? `── ${langLabel} ${'─'.repeat(Math.max(0, width - langLabel.length - 4))}`
|
|
60
|
+
: '─'.repeat(width);
|
|
61
|
+
const bot = '─'.repeat(width);
|
|
62
|
+
const body = (0, syntaxHighlight_1.isSupportedLang)(langLabel)
|
|
63
|
+
? (0, syntaxHighlight_1.highlightCode)(code, langLabel)
|
|
64
|
+
: code;
|
|
65
|
+
const indented = body.split('\n').map((ln) => ` ${ln}`).join('\n');
|
|
66
|
+
return [
|
|
67
|
+
sk.applyColors(top, 'muted'),
|
|
68
|
+
indented,
|
|
69
|
+
sk.applyColors(bot, 'muted'),
|
|
70
|
+
'',
|
|
71
|
+
].join('\n') + '\n';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Render a block quote with a `┃` left rail in muted colour.
|
|
75
|
+
* Multi-line quotes get the rail on every line.
|
|
76
|
+
*/
|
|
77
|
+
function renderBlockquote(quote) {
|
|
78
|
+
const rail = paint('muted')('┃ ');
|
|
79
|
+
return quote
|
|
80
|
+
.split('\n')
|
|
81
|
+
.map((ln) => (ln.length === 0 ? rail.trimEnd() : `${rail}${ln}`))
|
|
82
|
+
.join('\n') + '\n';
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Marked-terminal heading callback gets the rendered heading text +
|
|
86
|
+
* level. We paint h1 in brand-bold, h2 in brand, h3+ in heading.
|
|
87
|
+
*/
|
|
88
|
+
function renderHeading(text, level, _raw) {
|
|
89
|
+
if (level <= 1)
|
|
90
|
+
return paint('brand')(text.toUpperCase()) + '\n\n';
|
|
91
|
+
if (level === 2)
|
|
92
|
+
return paint('brand')(text) + '\n\n';
|
|
93
|
+
return paint('heading')(text) + '\n\n';
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* List items get a `▸ ` glyph in muted; numbered lists keep their
|
|
97
|
+
* numeric prefix (marked-terminal already prepends `N.` for ordered
|
|
98
|
+
* lists, so we just paint the body).
|
|
99
|
+
*/
|
|
100
|
+
function renderListItem(text) {
|
|
101
|
+
// marked-terminal feeds us the rendered child text. Strip its
|
|
102
|
+
// default tab prefix so our two-space indent stays consistent.
|
|
103
|
+
const body = text.replace(/^\s+/, '');
|
|
104
|
+
return ` ${paint('muted')('▸')} ${body}\n`;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Singleton — caching is fine since options bind to the active skin
|
|
108
|
+
* via paint callbacks (which read getSkinEngine() each call).
|
|
109
|
+
*/
|
|
110
|
+
let cachedRenderer = null;
|
|
111
|
+
function getReplyRenderer() {
|
|
112
|
+
if (cachedRenderer)
|
|
113
|
+
return cachedRenderer;
|
|
114
|
+
// marked-terminal's `opts.<X>` callbacks are invoked with ALREADY-
|
|
115
|
+
// assembled strings, not raw token data — they're meant for ANSI
|
|
116
|
+
// wrapping, not structural override. So `opts.code` for example is
|
|
117
|
+
// never actually called for fenced blocks: marked-terminal's
|
|
118
|
+
// prototype.code runs its own internal highlighter and skips opts.
|
|
119
|
+
// To emit our structured code blocks (top divider + lang label +
|
|
120
|
+
// syntax highlight + bottom divider) we override the prototype
|
|
121
|
+
// method directly below.
|
|
122
|
+
const opts = {
|
|
123
|
+
blockquote: renderBlockquote,
|
|
124
|
+
heading: renderHeading,
|
|
125
|
+
firstHeading: (text, _level, _raw) => paint('brand')(text.toUpperCase()) + '\n\n',
|
|
126
|
+
hr: () => paint('muted')('─'.repeat(Math.min(process.stdout.columns ?? 80, 100) - 4)) + '\n',
|
|
127
|
+
listitem: renderListItem,
|
|
128
|
+
paragraph: (text) => `${text}\n\n`,
|
|
129
|
+
strong: paint('brand'),
|
|
130
|
+
em: paint('muted'),
|
|
131
|
+
codespan: (text) => paint('accent')(`\`${text}\``),
|
|
132
|
+
del: paint('muted'),
|
|
133
|
+
// marked-terminal calls opts.link with the ASSEMBLED visual
|
|
134
|
+
// (already OSC8-wrapped when the host terminal supports it),
|
|
135
|
+
// so we just paint it.
|
|
136
|
+
link: (assembled) => paint('accent')(assembled),
|
|
137
|
+
href: paint('accent'),
|
|
138
|
+
text: (text) => text,
|
|
139
|
+
width: Math.min(process.stdout.columns ?? 80, 100),
|
|
140
|
+
showSectionPrefix: false,
|
|
141
|
+
reflowText: false,
|
|
142
|
+
tab: 2,
|
|
143
|
+
};
|
|
144
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
145
|
+
const renderer = new TerminalRenderer(opts);
|
|
146
|
+
// Override the prototype `code` method on this instance so we get
|
|
147
|
+
// structured code blocks (divider + lang label + syntax highlight
|
|
148
|
+
// + divider) instead of marked-terminal's plain yellow-highlighted
|
|
149
|
+
// output. Token-object signature handles marked v15.
|
|
150
|
+
renderer.code = function (code, lang, _escaped) {
|
|
151
|
+
let text;
|
|
152
|
+
let langOut;
|
|
153
|
+
if (typeof code === 'object' && code !== null) {
|
|
154
|
+
// marked v15 passes a token object: { text, lang, escaped }.
|
|
155
|
+
const tok = code;
|
|
156
|
+
text = tok.text ?? '';
|
|
157
|
+
langOut = tok.lang;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
text = String(code ?? '');
|
|
161
|
+
langOut = lang;
|
|
162
|
+
}
|
|
163
|
+
return renderCodeBlock(text, langOut);
|
|
164
|
+
};
|
|
165
|
+
// Override `link` to ALWAYS emit OSC8 hyperlinks (marked-terminal's
|
|
166
|
+
// default uses `supports-hyperlinks` which returns false on piped
|
|
167
|
+
// stdout — but Aiden's REPL targets modern terminals that support
|
|
168
|
+
// OSC8 universally). Visible label gets accent paint; href is the
|
|
169
|
+
// OSC8 target. Token-object signature handles marked v15.
|
|
170
|
+
renderer.link = function (href, _title, text) {
|
|
171
|
+
let url;
|
|
172
|
+
let label;
|
|
173
|
+
if (typeof href === 'object' && href !== null) {
|
|
174
|
+
const tok = href;
|
|
175
|
+
url = tok.href ?? '';
|
|
176
|
+
label = this
|
|
177
|
+
.parser?.parseInline?.(tok.tokens ?? []) ?? '';
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
url = String(href ?? '');
|
|
181
|
+
label = String(text ?? url);
|
|
182
|
+
}
|
|
183
|
+
if (!label)
|
|
184
|
+
label = url;
|
|
185
|
+
const painted = paint('accent')(label);
|
|
186
|
+
return `\x1b]8;;${url}\x1b\\${painted}\x1b]8;;\x1b\\`;
|
|
187
|
+
};
|
|
188
|
+
cachedRenderer = {
|
|
189
|
+
render(text) {
|
|
190
|
+
try {
|
|
191
|
+
// Bind the renderer globally before each parse — marked v15
|
|
192
|
+
// applies the renderer at parse time, so re-setting before
|
|
193
|
+
// each call is safe and ensures our custom options win even
|
|
194
|
+
// if other code transiently swaps the renderer.
|
|
195
|
+
marked_1.marked.setOptions({ renderer: renderer });
|
|
196
|
+
const out = marked_1.marked.parse(text);
|
|
197
|
+
return typeof out === 'string' ? out : String(out);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return text;
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
return cachedRenderer;
|
|
205
|
+
}
|
|
206
|
+
/** Test reset — drops the cached renderer so a skin change picks up. */
|
|
207
|
+
function _resetForTests() {
|
|
208
|
+
cachedRenderer = null;
|
|
209
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
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/resizeGuard.ts — Phase v4.1-tier3-essentials
|
|
10
|
+
*
|
|
11
|
+
* Hard-clear the terminal on `process.stdout` resize so dropdown
|
|
12
|
+
* re-renders, prompt frames, and dirty escape state from before the
|
|
13
|
+
* resize don't ghost into the new viewport.
|
|
14
|
+
*
|
|
15
|
+
* The clear is a single `\x1b[2J\x1b[H` (erase display + cursor home);
|
|
16
|
+
* every mainstream emulator honours it. A virtualised transcript could
|
|
17
|
+
* do this more surgically via React state, but we don't have one yet,
|
|
18
|
+
* so the brute-force clear is the right minimum for v4.1.
|
|
19
|
+
*
|
|
20
|
+
* Skipped in non-TTY (`process.stdout.isTTY` falsy) and in MCP serve
|
|
21
|
+
* mode (`isMcpServeMode()` true). 100ms debounce so a continuous
|
|
22
|
+
* resize drag doesn't issue dozens of clears.
|
|
23
|
+
*
|
|
24
|
+
* `installResizeGuard()` returns a teardown function. Idempotent.
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.HARD_CLEAR_SEQUENCE = void 0;
|
|
28
|
+
exports.installResizeGuard = installResizeGuard;
|
|
29
|
+
exports._resetForTests = _resetForTests;
|
|
30
|
+
const uiBuild_1 = require("./uiBuild");
|
|
31
|
+
/** Single ANSI sequence: `ED 2` (erase display) + `CUP` (cursor home). */
|
|
32
|
+
const HARD_CLEAR = '\x1b[2J\x1b[H';
|
|
33
|
+
const DEFAULT_DEBOUNCE_MS = 100;
|
|
34
|
+
let installed = null;
|
|
35
|
+
/**
|
|
36
|
+
* Install a 'resize' listener on `process.stdout`. No-op when stdout
|
|
37
|
+
* is non-TTY or MCP serve mode is active. Idempotent — calling twice
|
|
38
|
+
* returns the same teardown.
|
|
39
|
+
*/
|
|
40
|
+
function installResizeGuard(opts = {}) {
|
|
41
|
+
if (installed)
|
|
42
|
+
return installed.uninstall;
|
|
43
|
+
const out = opts.out ?? process.stdout;
|
|
44
|
+
if (!out || !out.isTTY) {
|
|
45
|
+
const noop = () => { };
|
|
46
|
+
installed = { uninstall: noop };
|
|
47
|
+
return noop;
|
|
48
|
+
}
|
|
49
|
+
if ((0, uiBuild_1.isMcpServeMode)()) {
|
|
50
|
+
const noop = () => { };
|
|
51
|
+
installed = { uninstall: noop };
|
|
52
|
+
return noop;
|
|
53
|
+
}
|
|
54
|
+
const debounceMs = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
55
|
+
let pending = null;
|
|
56
|
+
const onResize = () => {
|
|
57
|
+
if (pending)
|
|
58
|
+
clearTimeout(pending);
|
|
59
|
+
pending = setTimeout(() => {
|
|
60
|
+
pending = null;
|
|
61
|
+
try {
|
|
62
|
+
out.write(HARD_CLEAR);
|
|
63
|
+
}
|
|
64
|
+
catch { /* defensive */ }
|
|
65
|
+
try {
|
|
66
|
+
opts.onCleared?.();
|
|
67
|
+
}
|
|
68
|
+
catch { /* re-render must not crash the listener */ }
|
|
69
|
+
}, debounceMs);
|
|
70
|
+
};
|
|
71
|
+
out.on('resize', onResize);
|
|
72
|
+
const uninstall = () => {
|
|
73
|
+
if (!installed)
|
|
74
|
+
return;
|
|
75
|
+
out.removeListener('resize', onResize);
|
|
76
|
+
if (pending) {
|
|
77
|
+
clearTimeout(pending);
|
|
78
|
+
pending = null;
|
|
79
|
+
}
|
|
80
|
+
installed = null;
|
|
81
|
+
};
|
|
82
|
+
installed = { uninstall };
|
|
83
|
+
return uninstall;
|
|
84
|
+
}
|
|
85
|
+
/** Test helper: drop install state. */
|
|
86
|
+
function _resetForTests() {
|
|
87
|
+
if (installed)
|
|
88
|
+
installed.uninstall();
|
|
89
|
+
installed = null;
|
|
90
|
+
}
|
|
91
|
+
/** Constant exposed for smokes — they assert we emit this exact bytes. */
|
|
92
|
+
exports.HARD_CLEAR_SEQUENCE = HARD_CLEAR;
|