aiden-runtime 4.9.0 → 4.9.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.
Files changed (44) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/v4/aidenCLI.js +2 -2
  3. package/dist/cli/v4/aidenPrompt.js +12 -0
  4. package/dist/cli/v4/chatSession.js +43 -17
  5. package/dist/cli/v4/commands/channel.js +4 -6
  6. package/dist/cli/v4/commands/cron.js +6 -1
  7. package/dist/cli/v4/commands/daemon.js +6 -1
  8. package/dist/cli/v4/commands/daemonDoctor.js +6 -6
  9. package/dist/cli/v4/commands/daemonStatus.js +46 -27
  10. package/dist/cli/v4/commands/help.js +3 -0
  11. package/dist/cli/v4/commands/hooks.js +39 -1
  12. package/dist/cli/v4/commands/hooksSlash.js +33 -0
  13. package/dist/cli/v4/commands/index.js +9 -1
  14. package/dist/cli/v4/commands/mcp.js +2 -2
  15. package/dist/cli/v4/commands/memory.js +6 -1
  16. package/dist/cli/v4/commands/memorySlash.js +38 -0
  17. package/dist/cli/v4/commands/plugins.js +4 -6
  18. package/dist/cli/v4/commands/trigger.js +18 -18
  19. package/dist/cli/v4/confirmPrompt.js +67 -0
  20. package/dist/cli/v4/ui/progressBar.js +179 -0
  21. package/dist/cli/v4/util/closestAction.js +48 -0
  22. package/dist/core/v4/daemon/db/migrations.js +398 -398
  23. package/dist/core/v4/daemon/idempotency/runIdempotencyStore.js +10 -10
  24. package/dist/core/v4/daemon/incarnationStore.js +9 -9
  25. package/dist/core/v4/daemon/runs/attemptStore.js +8 -8
  26. package/dist/core/v4/daemon/runs/reclaim.js +12 -12
  27. package/dist/core/v4/daemon/runs/stuckAttemptWatchdog.js +19 -19
  28. package/dist/core/v4/daemon/spans/spanStore.js +14 -14
  29. package/dist/core/v4/daemon/triggerBus.js +61 -61
  30. package/dist/core/v4/hooks/auditQuery.js +11 -11
  31. package/dist/core/v4/hooks/dispatcher.js +13 -13
  32. package/dist/core/v4/hooks/registry.js +8 -8
  33. package/dist/core/v4/mcp/transport.js +9 -9
  34. package/dist/core/v4/update/depWarningFilter.js +76 -0
  35. package/dist/core/v4/update/executeInstall.js +70 -53
  36. package/dist/core/v4/update/platformInstructions.js +128 -0
  37. package/dist/core/v4/update/recoveryScript.js +70 -0
  38. package/dist/core/v4/util/spawnCommand.js +151 -0
  39. package/package.json +1 -1
  40. package/themes/default.yaml +52 -52
  41. package/themes/dracula.yaml +32 -32
  42. package/themes/light.yaml +32 -32
  43. package/themes/monochrome.yaml +31 -31
  44. package/themes/tokyo-night.yaml +32 -32
package/README.md CHANGED
@@ -94,7 +94,7 @@ Windows · Linux · WSL · macOS (API Mode)
94
94
  ![Built solo](https://img.shields.io/badge/Built-solo-B8A893?style=flat-square)
95
95
  ![By Taracod](https://img.shields.io/badge/By-Taracod-FF6B35?style=flat-square)
96
96
  ![White Lotus](https://img.shields.io/badge/Brand-White_Lotus-FFB088?style=flat-square)
97
- ![v4.9.0](https://img.shields.io/badge/Latest-v4.9.0-4ADE80?style=flat-square)
97
+ ![v4.9.1](https://img.shields.io/badge/Latest-v4.9.1-4ADE80?style=flat-square)
98
98
 
99
99
  </div>
100
100
 
@@ -568,7 +568,7 @@ async function main(argv, opts = {}) {
568
568
  });
569
569
  program
570
570
  .command('voice [args...]')
571
- .description('Voice diagnostics + one-shot TTS / transcribe (Phase v4.1-voice-cli). ' +
571
+ .description('Voice diagnostics + one-shot TTS / transcribe. ' +
572
572
  'Usage: aiden voice doctor | tts "<text>" | transcribe <file>')
573
573
  .allowUnknownOption()
574
574
  .action(async (args) => {
@@ -611,7 +611,7 @@ async function main(argv, opts = {}) {
611
611
  // v4.1 placeholders. (`tui` graduated to a real flag in Phase 15.)
612
612
  program
613
613
  .command('cron [args...]')
614
- .description('Cron diagnostics + one-shot list / run (Phase v4.1 hardened cron). ' +
614
+ .description('Cron diagnostics + one-shot list / run. ' +
615
615
  'Usage: aiden cron status | list | run <id>')
616
616
  .allowUnknownOption()
617
617
  .action(async (args) => {
@@ -291,6 +291,18 @@ exports.default = (0, core_1.createPrompt)((config, done) => {
291
291
  line = `${message} ${theme.style.answer(value)}`;
292
292
  }
293
293
  else {
294
+ // v4.9.2 Slice 2 (commit 0d0668f1) attempted to fix cursor
295
+ // misalignment by post-pending cursorBackward(ghost.length).
296
+ // Live-REPL diagnostic proved the fix is structurally inert:
297
+ // @inquirer/core's screen-manager.js:56 appends an ABSOLUTE
298
+ // cursorTo(this.cursorPos.cols) AFTER our content, overriding
299
+ // any cursor-positioning escape we emit inline. The real fix
300
+ // requires either rendering the ghost via a side-channel post-
301
+ // render write or moving it out of the inline line entirely —
302
+ // both need the proper save/restore refactor scheduled for v4.10
303
+ // once the prompt has a real screen-manager-aware test harness.
304
+ // Reverted here so the shipped v4.9.2 doesn't carry a "fix" that
305
+ // doesn't fix anything. Bug D status: known, deferred.
294
306
  const ghostStr = ghost ? dim(ghost) : '';
295
307
  line = `${prefix} ${message}${value}${ghostStr}`;
296
308
  }
@@ -82,6 +82,7 @@ const progressBar_1 = require("./display/progressBar");
82
82
  const uiBuild_1 = require("./uiBuild");
83
83
  const sessionSummaryGate_1 = require("./sessionSummaryGate");
84
84
  const aidenPrompt_1 = __importDefault(require("./aidenPrompt"));
85
+ const confirmPrompt_1 = require("./confirmPrompt");
85
86
  const historyStore_1 = require("./historyStore");
86
87
  const modelMetadata_1 = require("../../core/v4/modelMetadata");
87
88
  // v4.1.3-prebump: classify provider errors so the catch path can show
@@ -496,17 +497,21 @@ class ChatSession {
496
497
  agent: this.opts.agent,
497
498
  pluginLoader: this.opts.pluginLoader,
498
499
  channelManager: this.opts.channelManager,
499
- confirm: async (msg) => {
500
- // Phase 17.1: bug was reading `this.opts.promptApi?` which is
501
- // undefined when no override is passed; the chain silently
502
- // resolved to undefined returned false → "Grant cancelled"
503
- // before the user could type anything. Use the resolved local
504
- // promptApi (which falls back to readline-default) instead.
505
- const r = await promptApi.readLine(msg);
506
- if (typeof r !== 'string')
507
- return false;
508
- return /^(y|yes)$/i.test(r.trim());
509
- },
500
+ // v4.9.2 Slice 3 — UX-rebuilt confirmation primitive.
501
+ // The stdin/keypress mechanics worked correctly all along;
502
+ // users simply couldn't see the prompt was open. The
503
+ // extracted `runConfirm` helper now owns the canonical
504
+ // y/N hint, the warn-tinted '?' glyph, the
505
+ // suggestionsDisabled flag (so confirmations skip ghost-
506
+ // match against outer chat history), and the per-input
507
+ // honest cancellation message.
508
+ //
509
+ // Phase 17.1 anchor: the previous primitive read
510
+ // `this.opts.promptApi?` (undefined → silently returned
511
+ // false → "Grant cancelled" before user could type) —
512
+ // fixed by routing through the resolved local `promptApi`.
513
+ // That fix stands; Slice 3 adds the UX layer on top.
514
+ confirm: (msg) => (0, confirmPrompt_1.runConfirm)(msg, promptApi, this.opts.display),
510
515
  // Phase 18: raw text prompt for /auth login OAuth code paste.
511
516
  prompt: (msg) => promptApi.readLine(msg),
512
517
  });
@@ -1656,6 +1661,10 @@ class ChatSession {
1656
1661
  // .update_check.json cache so subsequent boots stay quiet until
1657
1662
  // a newer release ships.
1658
1663
  try {
1664
+ // v4.9.1 — modal sits BELOW the welcome banner with a blank
1665
+ // separator. Prevents the box from visually overlapping the
1666
+ // boot card on first-paint (smoke-reported regression).
1667
+ display.write('\n');
1659
1668
  await this.maybeShowBootUpdatePrompt();
1660
1669
  }
1661
1670
  catch { /* never let the update prompt crash boot */ }
@@ -1713,13 +1722,24 @@ class ChatSession {
1713
1722
  });
1714
1723
  if (choice === 'install') {
1715
1724
  if (method.inProcessInstallSupported) {
1716
- this.opts.display.write(`Installing aiden-runtime ${status.latest}…\n`);
1717
- const result = await ei.executeInstall({ packageSpec: `aiden-runtime@${status.latest}` });
1725
+ // v4.9.1 drive a live progress bar off the executor's
1726
+ // phase callback. The bar degrades cleanly on non-TTY, NO_COLOR,
1727
+ // and dumb terminals — see cli/v4/ui/progressBar.ts.
1728
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
1729
+ const pb = require('./ui/progressBar');
1730
+ const bar = pb.startProgressBar({
1731
+ label: `Installing aiden-runtime ${status.latest}...`,
1732
+ phases: ['spawning', 'resolving', 'downloading', 'extracting', 'verifying', 'installed'],
1733
+ });
1734
+ const result = await ei.executeInstall({
1735
+ packageSpec: `aiden-runtime@${status.latest}`,
1736
+ onPhase: (p) => { bar.setPhase(p); bar.setPercent(pb.npmInstallPhasePercent(p)); },
1737
+ });
1718
1738
  if (result.success) {
1719
- this.opts.display.write(`aiden-runtime ${result.installedVersion ?? status.latest} installed.\n`);
1720
- this.opts.display.dim('Restart Aiden to apply: type /quit then re-run `aiden`.');
1739
+ bar.complete(`aiden-runtime ${result.installedVersion ?? status.latest} installed. Restart Aiden to apply: type /quit then re-run \`aiden\`.`);
1721
1740
  }
1722
1741
  else {
1742
+ bar.fail('Install failed.');
1723
1743
  this.opts.display.warn(result.error ?? 'Install failed (no error message).');
1724
1744
  }
1725
1745
  }
@@ -2070,9 +2090,15 @@ function createDefaultPromptApi(opts = {}) {
2070
2090
  // aidenPrompt component (ghost text + slash dropdown + history nav).
2071
2091
  const useLegacyPrompt = (0, uiBuild_1.isNoUiMode)() || !opts.commands;
2072
2092
  return {
2073
- async readLine(prompt) {
2093
+ async readLine(prompt, readOpts) {
2074
2094
  try {
2075
- if (useLegacyPrompt) {
2095
+ // v4.9.2 Slice 3 — confirmation prompts (suggestionsDisabled)
2096
+ // always route through the legacy inquirer input path. No
2097
+ // ghost-text (would autocomplete from outer chat history —
2098
+ // wrong context for a y/n question), no slash dropdown
2099
+ // (irrelevant for confirmations). Inquirer's plain input is
2100
+ // the well-tested baseline for single-shot questions.
2101
+ if (readOpts?.suggestionsDisabled || useLegacyPrompt) {
2076
2102
  return (await inq.input({ message: prompt, theme: promptTheme })) ?? '';
2077
2103
  }
2078
2104
  // Fetch history just-in-time so each read sees the latest
@@ -255,10 +255,9 @@ async function telegramRemove(ctx) {
255
255
  return;
256
256
  }
257
257
  const proceed = await confirm('Remove the Telegram bot token? This stops polling.');
258
- if (!proceed) {
259
- display.dim(' Cancelled.');
258
+ // v4.9.2 Slice 3 — confirm() now owns the rejection message.
259
+ if (!proceed)
260
260
  return;
261
- }
262
261
  // Stop the live adapter first so polling actually halts even if the
263
262
  // .env write fails for some reason.
264
263
  const manager = ctx.channelManager;
@@ -297,10 +296,9 @@ async function telegramTakeover(ctx) {
297
296
  const proceed = confirm
298
297
  ? await confirm('Take over Telegram polling? This will boot any other Aiden instance off the bot.')
299
298
  : true;
300
- if (!proceed) {
301
- display.dim(' Cancelled.');
299
+ // v4.9.2 Slice 3 — confirm() now owns the rejection message.
300
+ if (!proceed)
302
301
  return;
303
- }
304
302
  const spinner = display.startSpinner('Reclaiming Telegram polling…');
305
303
  let result;
306
304
  try {
@@ -327,8 +327,13 @@ async function cmdRemove(ctx, args) {
327
327
  else if (ctx.confirm) {
328
328
  ok = await ctx.confirm(question);
329
329
  }
330
+ // v4.9.2 Slice 3 — when ctx.confirm was the source, the primitive
331
+ // already printed a per-input rejection message. The ctx.prompt
332
+ // branch above does its own y/N parsing, so it still owns its own
333
+ // "Cancelled." line.
330
334
  if (!ok) {
331
- ctx.display.dim('Cancelled.');
335
+ if (ctx.prompt)
336
+ ctx.display.dim('Cancelled.');
332
337
  return;
333
338
  }
334
339
  if ((0, cronManager_1.deleteJob)(job.id)) {
@@ -104,10 +104,15 @@ async function runDaemonSubcommand(action, args, opts = {}) {
104
104
  writeErr: err,
105
105
  });
106
106
  }
107
- default:
107
+ default: {
108
108
  err(`Unknown daemon action: ${action}\n`);
109
+ const { closestAction } = await Promise.resolve().then(() => __importStar(require('../util/closestAction')));
110
+ const m = closestAction(action, ['install', 'uninstall', 'start', 'stop', 'restart', 'status', 'logs', 'doctor']);
111
+ if (m)
112
+ err(`Did you mean: ${m}?\n\n`);
109
113
  err('Actions: install, uninstall, start, stop, restart, status, logs, doctor\n');
110
114
  return 2;
115
+ }
111
116
  }
112
117
  }
113
118
  const SYSTEMD_UNIT_NAME = 'aiden.service';
@@ -85,11 +85,11 @@ function collectDoctorChecks(rootDir) {
85
85
  detail: `current=${ver} latest=${migrations_1.LATEST_SCHEMA_VERSION}`,
86
86
  fixable: false });
87
87
  // 3. Recent incarnation
88
- const inc = db.prepare(`SELECT incarnation_id, started_at, ended_at, exit_reason FROM daemon_incarnations
88
+ const inc = db.prepare(`SELECT incarnation_id, started_at, ended_at, exit_reason FROM daemon_incarnations
89
89
  ORDER BY started_at DESC LIMIT 1`).get();
90
90
  if (!inc) {
91
91
  checks.push({ name: 'recent incarnation', status: 'warn',
92
- detail: 'no daemon_incarnations rows (daemon never booted post-Slice-4)',
92
+ detail: 'no daemon_incarnations rows (daemon never started in this root)',
93
93
  fixable: false });
94
94
  }
95
95
  else {
@@ -100,7 +100,7 @@ function collectDoctorChecks(rootDir) {
100
100
  }
101
101
  // 4. Recent crashes (24h)
102
102
  const sinceIso = new Date(Date.now() - TWENTY_FOUR_HOURS_MS).toISOString();
103
- const crashes = db.prepare(`SELECT COUNT(*) AS c FROM daemon_incarnations
103
+ const crashes = db.prepare(`SELECT COUNT(*) AS c FROM daemon_incarnations
104
104
  WHERE exit_reason = 'crash' AND started_at > ?`).get(sinceIso);
105
105
  checks.push({ name: 'recent crashes (24h)',
106
106
  status: crashes.c === 0 ? 'ok' : crashes.c > 3 ? 'warn' : 'ok',
@@ -111,7 +111,7 @@ function collectDoctorChecks(rootDir) {
111
111
  if (tableExists(db, 'run_attempts')) {
112
112
  const currentInc = inc?.incarnation_id ?? '';
113
113
  const cutoffIso = new Date(Date.now() - 30 * 60 * 1000).toISOString();
114
- stuckAttempts = db.prepare(`SELECT COUNT(*) AS c FROM run_attempts
114
+ stuckAttempts = db.prepare(`SELECT COUNT(*) AS c FROM run_attempts
115
115
  WHERE status='running' AND incarnation_id != ? AND started_at < ?`).get(currentInc, cutoffIso).c;
116
116
  }
117
117
  checks.push({ name: 'stuck attempts',
@@ -125,7 +125,7 @@ function collectDoctorChecks(rootDir) {
125
125
  let orphanSpans = 0;
126
126
  if (tableExists(db, 'spans')) {
127
127
  const currentInc = inc?.incarnation_id ?? '';
128
- orphanSpans = db.prepare(`SELECT COUNT(*) AS c FROM spans
128
+ orphanSpans = db.prepare(`SELECT COUNT(*) AS c FROM spans
129
129
  WHERE status IS NULL AND ended_at IS NULL AND incarnation_id != ?`).get(currentInc).c;
130
130
  }
131
131
  checks.push({ name: 'orphan spans',
@@ -147,7 +147,7 @@ function collectDoctorChecks(rootDir) {
147
147
  // 8. Stale-claimed trigger events
148
148
  let staleClaimed = 0;
149
149
  if (tableExists(db, 'trigger_events')) {
150
- staleClaimed = db.prepare(`SELECT COUNT(*) AS c FROM trigger_events
150
+ staleClaimed = db.prepare(`SELECT COUNT(*) AS c FROM trigger_events
151
151
  WHERE status='claimed' AND claim_expires_at IS NOT NULL AND claim_expires_at < ?`).get(Date.now()).c;
152
152
  }
153
153
  checks.push({ name: 'stale-claimed trigger events',
@@ -22,44 +22,63 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
22
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
23
23
  };
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.daemonStatus = void 0;
25
+ exports.daemonStatus = exports.DAEMON_SHELL_ONLY = void 0;
26
+ exports.dispatchDaemonSlash = dispatchDaemonSlash;
26
27
  const node_fs_1 = __importDefault(require("node:fs"));
27
28
  const node_os_1 = __importDefault(require("node:os"));
28
29
  const node_path_1 = __importDefault(require("node:path"));
29
- const daemon_1 = require("../../../core/v4/daemon");
30
+ const daemon_1 = require("./daemon");
31
+ const daemon_2 = require("../../../core/v4/daemon");
30
32
  const paths_1 = require("../../../core/v4/paths");
33
+ /**
34
+ * v4.9.1 amendment — `/daemon` defaults to `doctor` and routes
35
+ * `doctor` / `logs` to the existing `runDaemonSubcommand`. The pure-
36
+ * REPL `/daemon status` (in-process snapshot) stays inline. Lifecycle
37
+ * ops shell-hint — they need terminal control we can't grant inside chat.
38
+ */
39
+ exports.DAEMON_SHELL_ONLY = new Set(['install', 'uninstall', 'start', 'stop', 'restart']);
40
+ async function dispatchDaemonSlash(opts) {
41
+ const a = (opts.action || 'doctor').toLowerCase();
42
+ if (exports.DAEMON_SHELL_ONLY.has(a)) {
43
+ opts.write(`⚠ /daemon ${a} not available inside chat (requires terminal control)\n`);
44
+ opts.write(' Quit (/quit) and run from shell:\n\n');
45
+ const tail = opts.args.length > 0 ? ' ' + opts.args.join(' ') : '';
46
+ opts.write(` aiden daemon ${a}${tail}\n`);
47
+ return;
48
+ }
49
+ if (a === 'status' && opts.paintStatus) {
50
+ try {
51
+ opts.paintStatus();
52
+ }
53
+ catch (e) {
54
+ opts.warn(`/daemon status: failed to read state (${e instanceof Error ? e.message : String(e)})`);
55
+ }
56
+ return;
57
+ }
58
+ await opts.runDaemon(a, opts.args, { writeOut: opts.write, writeErr: opts.write });
59
+ }
31
60
  exports.daemonStatus = {
32
61
  name: 'daemon',
33
- description: 'Show daemon status (read-only). Use `aiden daemon` for lifecycle.',
62
+ description: 'Daemon diagnostics (doctor / status / logs).',
34
63
  category: 'system',
35
64
  icon: '⚙',
36
65
  handler: async (ctx) => {
37
- const sub = (ctx.args[0] ?? 'status').toLowerCase();
38
- if (sub !== 'status') {
39
- ctx.display.printError('Usage: /daemon status\n' +
40
- 'For lifecycle commands (install / start / stop / restart / logs), use the top-level CLI:\n' +
41
- ' aiden daemon install\n' +
42
- ' aiden daemon start\n' +
43
- ' aiden daemon stop\n' +
44
- ' aiden daemon status\n' +
45
- ' aiden daemon logs');
46
- return {};
47
- }
48
- try {
49
- const snapshot = readSnapshot();
50
- printSnapshot(snapshot, ctx);
51
- }
52
- catch (e) {
53
- ctx.display.warn(`/daemon status: failed to read state (${e instanceof Error ? e.message : String(e)})`);
54
- }
66
+ await dispatchDaemonSlash({
67
+ action: ctx.args[0] ?? 'doctor',
68
+ args: ctx.args.slice(1),
69
+ write: (s) => ctx.display.write(s),
70
+ warn: (s) => ctx.display.warn(s),
71
+ runDaemon: daemon_1.runDaemonSubcommand,
72
+ paintStatus: () => printSnapshot(readSnapshot(), ctx),
73
+ });
55
74
  return {};
56
75
  },
57
76
  };
58
77
  // ── Snapshot collector ─────────────────────────────────────────────────────
59
78
  function readSnapshot() {
60
79
  const aidenRoot = (0, paths_1.resolveAidenRoot)();
61
- const dbPath = (0, daemon_1.daemonDbPath)(aidenRoot);
62
- const lockPath = (0, daemon_1.daemonRuntimeLockPath)(aidenRoot);
80
+ const dbPath = (0, daemon_2.daemonDbPath)(aidenRoot);
81
+ const lockPath = (0, daemon_2.daemonRuntimeLockPath)(aidenRoot);
63
82
  // ── Liveness via the in-process bootstrap handle first, then fall
64
83
  // back to the runtime.lock PID check (covers the case where the
65
84
  // daemon is another process and we're a REPL inspecting its db).
@@ -67,11 +86,11 @@ function readSnapshot() {
67
86
  let instanceId = null;
68
87
  let port = null;
69
88
  let uptimeMs = null;
70
- const handle = (0, daemon_1.getDaemonHandle)();
89
+ const handle = (0, daemon_2.getDaemonHandle)();
71
90
  if (handle?.active && handle.instanceId) {
72
91
  running = true;
73
92
  instanceId = handle.instanceId;
74
- port = (0, daemon_1.getDaemonConfig)().port;
93
+ port = (0, daemon_2.getDaemonConfig)().port;
75
94
  if (handle.instanceTracker) {
76
95
  // instanceTracker has a `getStartedAt` if exposed; otherwise
77
96
  // derive from daemon_instances row below.
@@ -105,7 +124,7 @@ function readSnapshot() {
105
124
  dailyBudget: null,
106
125
  };
107
126
  }
108
- const db = (0, daemon_1.openDaemonDb)(dbPath);
127
+ const db = (0, daemon_2.openDaemonDb)(dbPath);
109
128
  // Uptime from the instance row when we have an instanceId.
110
129
  if (running && instanceId) {
111
130
  try {
@@ -131,7 +150,7 @@ function readSnapshot() {
131
150
  // Recent runs (last 3).
132
151
  const recentRuns = (() => {
133
152
  try {
134
- const rows = db.prepare(`SELECT id, status, finish_reason, started_at, completed_at FROM runs
153
+ const rows = db.prepare(`SELECT id, status, finish_reason, started_at, completed_at FROM runs
135
154
  ORDER BY id DESC LIMIT 3`).all();
136
155
  return rows.map((r) => ({
137
156
  id: r.id,
@@ -76,6 +76,9 @@ exports.SUBSECTION_MAP = {
76
76
  recovery: 'System',
77
77
  // v4.6 ONB1 slice 10 — new-user guided tour.
78
78
  walkthrough: 'System',
79
+ // v4.9.1 amendment — REPL surfaces for memory + hooks (daemon already mapped).
80
+ memory: 'System',
81
+ hooks: 'System',
79
82
  // ── Authentication ──
80
83
  auth: 'Authentication',
81
84
  // ── Help ──
@@ -23,6 +23,39 @@
23
23
  * directory and runs a rescan, but NEVER auto-trusts anything (trust
24
24
  * remains an explicit, deliberate user action).
25
25
  */
26
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ var desc = Object.getOwnPropertyDescriptor(m, k);
29
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
30
+ desc = { enumerable: true, get: function() { return m[k]; } };
31
+ }
32
+ Object.defineProperty(o, k2, desc);
33
+ }) : (function(o, m, k, k2) {
34
+ if (k2 === undefined) k2 = k;
35
+ o[k2] = m[k];
36
+ }));
37
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
38
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
39
+ }) : function(o, v) {
40
+ o["default"] = v;
41
+ });
42
+ var __importStar = (this && this.__importStar) || (function () {
43
+ var ownKeys = function(o) {
44
+ ownKeys = Object.getOwnPropertyNames || function (o) {
45
+ var ar = [];
46
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
47
+ return ar;
48
+ };
49
+ return ownKeys(o);
50
+ };
51
+ return function (mod) {
52
+ if (mod && mod.__esModule) return mod;
53
+ var result = {};
54
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
55
+ __setModuleDefault(result, mod);
56
+ return result;
57
+ };
58
+ })();
26
59
  var __importDefault = (this && this.__importDefault) || function (mod) {
27
60
  return (mod && mod.__esModule) ? mod : { "default": mod };
28
61
  };
@@ -78,10 +111,15 @@ async function runHooksSubcommand(action, args, opts = {}) {
78
111
  case 'audit': return await cmdAudit(ctx);
79
112
  case '--help':
80
113
  case 'help': return cmdHelp(out);
81
- default:
114
+ default: {
82
115
  err(`Unknown hooks action: ${effective}\n`);
116
+ const { closestAction } = await Promise.resolve().then(() => __importStar(require('../util/closestAction')));
117
+ const m = closestAction(effective, ['list', 'show', 'trust', 'revoke', 'rescan', 'test', 'doctor', 'audit']);
118
+ if (m)
119
+ err(`Did you mean: ${m}?\n\n`);
83
120
  cmdHelp(err);
84
121
  return 2;
122
+ }
85
123
  }
86
124
  }
87
125
  finally {
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hooks = exports.HOOKS_SHELL_ONLY = void 0;
4
+ exports.dispatchHooksSlash = dispatchHooksSlash;
5
+ const hooks_1 = require("./hooks");
6
+ /** Actions that need an interactive confirmation prompt. */
7
+ exports.HOOKS_SHELL_ONLY = new Set(['trust', 'revoke']);
8
+ async function dispatchHooksSlash(opts) {
9
+ const a = (opts.action || 'list').toLowerCase();
10
+ if (exports.HOOKS_SHELL_ONLY.has(a)) {
11
+ opts.write(`⚠ /hooks ${a} not available inside chat (needs confirmation prompt)\n`);
12
+ opts.write(' Quit (/quit) and run from shell:\n\n');
13
+ const tail = opts.args.length > 0 ? ' ' + opts.args.join(' ') : '';
14
+ opts.write(` aiden hooks ${a}${tail}\n`);
15
+ return;
16
+ }
17
+ await opts.runHooks(a, opts.args, { writeOut: opts.write, writeErr: opts.write });
18
+ }
19
+ exports.hooks = {
20
+ name: 'hooks',
21
+ description: 'Manage hooks (list / show / rescan / test / doctor / audit).',
22
+ category: 'system',
23
+ icon: '🪝',
24
+ handler: async (ctx) => {
25
+ await dispatchHooksSlash({
26
+ action: ctx.args[0] ?? 'list',
27
+ args: ctx.args.slice(1),
28
+ write: (s) => ctx.display.write(s),
29
+ runHooks: hooks_1.runHooksSubcommand,
30
+ });
31
+ return {};
32
+ },
33
+ };
@@ -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.walkthrough = exports.recovery = exports.spawnPause = exports.plannerGuard = exports.suggestions = exports.daemonStatus = exports.browserDepth = exports.tce = exports.sandbox = 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.theme = 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.hooks = exports.memory = exports.walkthrough = exports.recovery = exports.spawnPause = exports.plannerGuard = exports.suggestions = exports.daemonStatus = exports.browserDepth = exports.tce = exports.sandbox = 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.theme = 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");
@@ -106,6 +106,11 @@ Object.defineProperty(exports, "recovery", { enumerable: true, get: function ()
106
106
  // ONB1 slice 10 — new-user guided tour.
107
107
  const walkthrough_1 = require("./walkthrough");
108
108
  Object.defineProperty(exports, "walkthrough", { enumerable: true, get: function () { return walkthrough_1.walkthrough; } });
109
+ // v4.9.1 amendment — REPL slash surfaces for memory + hooks (mirrors CLI).
110
+ const memorySlash_1 = require("./memorySlash");
111
+ Object.defineProperty(exports, "memory", { enumerable: true, get: function () { return memorySlash_1.memory; } });
112
+ const hooksSlash_1 = require("./hooksSlash");
113
+ Object.defineProperty(exports, "hooks", { enumerable: true, get: function () { return hooksSlash_1.hooks; } });
109
114
  /** All built-in system commands, in canonical order. */
110
115
  exports.allCommands = [
111
116
  help_1.help,
@@ -158,6 +163,9 @@ exports.allCommands = [
158
163
  recovery_1.recovery,
159
164
  // ONB1 slice 10 — new-user guided tour.
160
165
  walkthrough_1.walkthrough,
166
+ // v4.9.1 amendment — REPL slash surfaces mirroring CLI subcommands.
167
+ memorySlash_1.memory,
168
+ hooksSlash_1.hooks,
161
169
  clear_1.clear,
162
170
  quit_1.quit,
163
171
  ];
@@ -266,8 +266,8 @@ async function wireSubagentFanout(opts) {
266
266
  // WAL-coexistence model as REPL — connection.ts caches per-path.
267
267
  const mcpInstanceId = `mcp-${(0, node_crypto_1.randomUUID)().slice(0, 8)}`;
268
268
  const mcpDb = (0, daemon_1.openDaemonDb)((0, daemon_1.daemonDbPath)(opts.paths.root));
269
- mcpDb.prepare(`INSERT OR IGNORE INTO daemon_instances
270
- (instance_id, pid, hostname, started_at, last_heartbeat, version)
269
+ mcpDb.prepare(`INSERT OR IGNORE INTO daemon_instances
270
+ (instance_id, pid, hostname, started_at, last_heartbeat, version)
271
271
  VALUES (?, ?, ?, ?, ?, ?)`).run(mcpInstanceId, process.pid, node_os_1.default.hostname(), Date.now(), Date.now(), version_1.VERSION);
272
272
  const mcpRunStore = (0, daemon_1.createRunStore)({ db: mcpDb });
273
273
  // v4.6 Phase 3b — self-improvement loop singleton against the
@@ -155,10 +155,15 @@ async function runMemorySubcommand(action, args, opts = {}) {
155
155
  case 'review': return cmdReview(args, paths, opts, out, err, json);
156
156
  case '--help':
157
157
  case 'help': return cmdHelp(out);
158
- default:
158
+ default: {
159
159
  err(`Unknown memory action: ${effective}\n`);
160
+ const { closestAction } = await Promise.resolve().then(() => __importStar(require('../util/closestAction')));
161
+ const m = closestAction(effective, ['list', 'show', 'add', 'remove', 'edit', 'backup', 'restore', 'diff', 'namespaces', 'pending', 'approve', 'reject', 'review']);
162
+ if (m)
163
+ err(`Did you mean: ${m}?\n\n`);
160
164
  cmdHelp(err);
161
165
  return 2;
166
+ }
162
167
  }
163
168
  }
164
169
  function cmdHelp(write) {
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.memory = exports.MEMORY_SHELL_ONLY = void 0;
4
+ exports.dispatchMemorySlash = dispatchMemorySlash;
5
+ const memory_1 = require("./memory");
6
+ /** Actions that need the full CLI surface (confirmation / destructive). */
7
+ exports.MEMORY_SHELL_ONLY = new Set(['remove', 'restore']);
8
+ /**
9
+ * Pure dispatch — exported for tests + reuse. Either prints a shell
10
+ * hint OR delegates to the provided `runMemory` runner. Side effects
11
+ * confined to the supplied `write` sink.
12
+ */
13
+ async function dispatchMemorySlash(opts) {
14
+ const a = (opts.action || 'list').toLowerCase();
15
+ if (exports.MEMORY_SHELL_ONLY.has(a)) {
16
+ opts.write(`⚠ /memory ${a} not available inside chat (destructive operation)\n`);
17
+ opts.write(' Quit (/quit) and run from shell:\n\n');
18
+ const tail = opts.args.length > 0 ? ' ' + opts.args.join(' ') : '';
19
+ opts.write(` aiden memory ${a}${tail}\n`);
20
+ return;
21
+ }
22
+ await opts.runMemory(a, opts.args, { writeOut: opts.write, writeErr: opts.write });
23
+ }
24
+ exports.memory = {
25
+ name: 'memory',
26
+ description: 'Manage memory (list / show / add / namespaces / pending / approve / review).',
27
+ category: 'system',
28
+ icon: '🧠',
29
+ handler: async (ctx) => {
30
+ await dispatchMemorySlash({
31
+ action: ctx.args[0] ?? 'list',
32
+ args: ctx.args.slice(1),
33
+ write: (s) => ctx.display.write(s),
34
+ runMemory: memory_1.runMemorySubcommand,
35
+ });
36
+ return {};
37
+ },
38
+ };
@@ -161,10 +161,9 @@ exports.plugins = {
161
161
  ctx.display.write('\n');
162
162
  const confirmFn = ctx.confirm ?? (async () => false);
163
163
  const allow = await confirmFn(`Install ${manifest.name} with the listed permissions? [y/N] `);
164
- if (!allow) {
165
- ctx.display.dim('Install cancelled.');
164
+ // v4.9.2 Slice 3 — confirm() now owns the rejection message.
165
+ if (!allow)
166
166
  return {};
167
- }
168
167
  // Copy into the user plugins dir.
169
168
  const dst = node_path_1.default.join(ctx.paths.pluginsDir, manifest.name);
170
169
  try {
@@ -258,10 +257,9 @@ exports.plugins = {
258
257
  const allow = await confirmFn(isUpgrade
259
258
  ? `Grant the listed permissions (including ${newPerms.length} new)? [y/N] `
260
259
  : `Grant the listed permissions? [y/N] `);
261
- if (!allow) {
262
- ctx.display.dim('Grant cancelled.');
260
+ // v4.9.2 Slice 3 — confirm() now owns the rejection message.
261
+ if (!allow)
263
262
  return {};
264
- }
265
263
  await (0, plugins_1.saveGrantedPermissions)(dir, entry.manifest.permissions);
266
264
  // Reload so the new state takes effect.
267
265
  await ctx.pluginLoader.teardown();