aiden-runtime 4.1.0 → 4.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +89 -33
  2. package/dist/cli/v4/aidenCLI.js +162 -11
  3. package/dist/cli/v4/callbacks.js +5 -2
  4. package/dist/cli/v4/chatSession.js +525 -15
  5. package/dist/cli/v4/commands/auth.js +6 -3
  6. package/dist/cli/v4/commands/help.js +4 -0
  7. package/dist/cli/v4/commands/index.js +10 -1
  8. package/dist/cli/v4/commands/reloadSoul.js +37 -0
  9. package/dist/cli/v4/commands/update.js +102 -0
  10. package/dist/cli/v4/defaultSoul.js +68 -2
  11. package/dist/cli/v4/display.js +28 -10
  12. package/dist/cli/v4/doctor.js +173 -1
  13. package/dist/cli/v4/doctorLiveness.js +384 -0
  14. package/dist/cli/v4/promotionPrompt.js +202 -0
  15. package/dist/cli/v4/providerBootSelector.js +144 -0
  16. package/dist/cli/v4/sessionSummaryGate.js +66 -0
  17. package/dist/cli/v4/toolPreview.js +139 -0
  18. package/dist/core/v4/aidenAgent.js +91 -29
  19. package/dist/core/v4/capabilities.js +89 -0
  20. package/dist/core/v4/contextCompressor.js +25 -8
  21. package/dist/core/v4/distillationIndex.js +167 -0
  22. package/dist/core/v4/distillationStore.js +98 -0
  23. package/dist/core/v4/logger/logger.js +40 -9
  24. package/dist/core/v4/promotionCandidates.js +234 -0
  25. package/dist/core/v4/promptBuilder.js +145 -1
  26. package/dist/core/v4/sessionDistiller.js +405 -0
  27. package/dist/core/v4/skillMining/extractorPrompt.js +28 -21
  28. package/dist/core/v4/skillMining/proposalBuilder.js +3 -2
  29. package/dist/core/v4/skillMining/skillMiner.js +43 -6
  30. package/dist/core/v4/skillOutcomeTracker.js +323 -0
  31. package/dist/core/v4/subsystemHealth.js +143 -0
  32. package/dist/core/v4/update/executeInstall.js +233 -0
  33. package/dist/core/version.js +1 -1
  34. package/dist/moat/dangerousPatterns.js +1 -1
  35. package/dist/moat/memoryGuard.js +111 -0
  36. package/dist/moat/skillTeacher.js +14 -5
  37. package/dist/providers/v4/chatCompletionsAdapter.js +9 -0
  38. package/dist/providers/v4/codexResponsesAdapter.js +7 -2
  39. package/dist/providers/v4/errors.js +67 -1
  40. package/dist/providers/v4/modelDefaults.js +65 -0
  41. package/dist/providers/v4/ollamaPromptToolsAdapter.js +9 -2
  42. package/dist/providers/v4/registry.js +9 -2
  43. package/dist/providers/v4/runtimeResolver.js +6 -0
  44. package/dist/tools/v4/index.js +57 -1
  45. package/dist/tools/v4/memory/memoryRemove.js +57 -2
  46. package/dist/tools/v4/memory/sessionSummary.js +151 -0
  47. package/dist/tools/v4/sessions/recallSession.js +163 -0
  48. package/dist/tools/v4/sessions/sessionSearch.js +5 -1
  49. package/dist/tools/v4/subagent/subagentFanout.js +24 -0
  50. package/dist/tools/v4/system/_psHelpers.js +55 -0
  51. package/dist/tools/v4/system/aidenSelfUpdate.js +162 -0
  52. package/dist/tools/v4/system/appClose.js +79 -0
  53. package/dist/tools/v4/system/appLaunch.js +92 -0
  54. package/dist/tools/v4/system/clipboardRead.js +54 -0
  55. package/dist/tools/v4/system/clipboardWrite.js +84 -0
  56. package/dist/tools/v4/system/mediaKey.js +78 -0
  57. package/dist/tools/v4/system/osProcessList.js +99 -0
  58. package/dist/tools/v4/system/screenshot.js +106 -0
  59. package/dist/tools/v4/system/volumeSet.js +157 -0
  60. package/package.json +4 -1
  61. package/skills/system_control.md +135 -69
@@ -0,0 +1,162 @@
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
+ * tools/v4/system/aidenSelfUpdate.ts — Phase v4.1.2-update.
10
+ *
11
+ * Natural-language entry point for self-update. When the user asks
12
+ * Aiden to update / install latest / upgrade itself, the model calls
13
+ * this tool. Routes to the same shared executor (`executeInstall`)
14
+ * that `/update install` uses — single source of truth for install
15
+ * behavior.
16
+ *
17
+ * Two-step confirmation contract (consent gate):
18
+ * 1. First call with `confirm: false` — returns status + a prompt
19
+ * asking the user to confirm. NEVER spawns.
20
+ * 2. Model surfaces the prompt to the user; waits for explicit
21
+ * agreement ("yes update", "go ahead", "do it").
22
+ * 3. Second call with `confirm: true` — only after explicit user
23
+ * agreement; spawns the install.
24
+ *
25
+ * The contract is enforced via tool DESCRIPTION (model-facing rule).
26
+ * Tool-side, we don't track "did the user actually consent" — that
27
+ * needs a runtime approval object (request_id + fresh-confirmation
28
+ * verification) which is a v4.2+ design. For v4.1.2 the description
29
+ * carries the rule and the tool trusts the model to follow it.
30
+ *
31
+ * Acceptable risk: failure mode of a misbehaving model is "user gets
32
+ * an unwanted install they have to /quit to apply" — not data loss.
33
+ * Phase D's promotion path is the more sensitive consent surface and
34
+ * is user-driven UI.
35
+ */
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.aidenSelfUpdateTool = void 0;
38
+ const version_1 = require("../../../core/version");
39
+ const checkUpdate_1 = require("../../../core/v4/update/checkUpdate");
40
+ const executeInstall_1 = require("../../../core/v4/update/executeInstall");
41
+ exports.aidenSelfUpdateTool = {
42
+ schema: {
43
+ name: 'aiden_self_update',
44
+ description: 'Update Aiden to the latest version via npm install -g aiden-runtime@latest. ' +
45
+ 'TWO-STEP CONFIRMATION REQUIRED: first call with confirm:false to check status ' +
46
+ 'and surface to the user; only call with confirm:true AFTER the user explicitly ' +
47
+ 'agrees in their next message ("yes update", "go ahead", "do it"). NEVER call ' +
48
+ 'with confirm:true autonomously. ' +
49
+ 'Call this tool ONLY when the user explicitly asks Aiden to update / install ' +
50
+ 'latest / upgrade itself. Example user phrases that warrant a call: ' +
51
+ '"update yourself", "can you install the latest version?", "upgrade to the latest", ' +
52
+ '"self-update". DO NOT call when: user asks about update status without requesting ' +
53
+ 'action ("are there updates?") — for status queries, just answer from your context; ' +
54
+ 'user mentions updates of OTHER software ("update VSCode"); user has not explicitly ' +
55
+ 'asked Aiden to update itself.',
56
+ inputSchema: {
57
+ type: 'object',
58
+ properties: {
59
+ confirm: {
60
+ type: 'boolean',
61
+ description: 'False on first call (status check, no install). True on second call AFTER ' +
62
+ 'the user explicitly agreed to proceed in their last message.',
63
+ },
64
+ },
65
+ required: ['confirm'],
66
+ },
67
+ },
68
+ category: 'write',
69
+ mutates: true,
70
+ toolset: 'system',
71
+ async execute(args, ctx) {
72
+ if (!ctx.paths) {
73
+ return {
74
+ success: false,
75
+ error: 'aiden_self_update needs Aiden user-data paths — not configured in this context.',
76
+ };
77
+ }
78
+ const confirm = args.confirm === true;
79
+ // Status probe — bypass the 6h boot cache for user-initiated checks.
80
+ const status = await (0, checkUpdate_1.checkForUpdate)({
81
+ paths: ctx.paths,
82
+ installedVersion: version_1.VERSION,
83
+ cacheTtlMs: 0,
84
+ });
85
+ // ── First call: confirm:false → status + prompt. NEVER spawn. ─────
86
+ if (!confirm) {
87
+ if (status.latest === null) {
88
+ return {
89
+ success: true,
90
+ stage: 'status',
91
+ message: "Couldn't check for updates (registry unreachable). " +
92
+ 'Try again in a moment, or run `npm install -g aiden-runtime@latest` manually.',
93
+ installed: status.installed,
94
+ latest: null,
95
+ updateAvailable: false,
96
+ };
97
+ }
98
+ if (!status.updateAvailable) {
99
+ return {
100
+ success: true,
101
+ stage: 'status',
102
+ message: `You're on the latest version (v${status.installed}). Nothing to update.`,
103
+ installed: status.installed,
104
+ latest: status.latest,
105
+ updateAvailable: false,
106
+ };
107
+ }
108
+ return {
109
+ success: true,
110
+ stage: 'status',
111
+ message: `Update available: v${status.installed} → v${status.latest}. ` +
112
+ `Confirm by saying "yes update" or "go ahead". This runs ` +
113
+ `\`npm install -g aiden-runtime@latest\` and you'll need to ` +
114
+ `restart Aiden after.`,
115
+ installed: status.installed,
116
+ latest: status.latest,
117
+ updateAvailable: true,
118
+ };
119
+ }
120
+ // ── Second call: confirm:true → install. ────────────────────────
121
+ if (status.latest === null) {
122
+ return {
123
+ success: false,
124
+ stage: 'install',
125
+ error: "Can't install — registry unreachable. " +
126
+ 'Try again or run `npm install -g aiden-runtime@latest` manually.',
127
+ installed: status.installed,
128
+ };
129
+ }
130
+ if (!status.updateAvailable) {
131
+ return {
132
+ success: true,
133
+ stage: 'install',
134
+ message: `Already on v${status.installed}. Nothing to install.`,
135
+ installed: status.installed,
136
+ latest: status.latest,
137
+ updateAvailable: false,
138
+ };
139
+ }
140
+ const result = await (0, executeInstall_1.executeInstall)();
141
+ if (result.success) {
142
+ const v = result.installedVersion ?? status.latest;
143
+ return {
144
+ success: true,
145
+ stage: 'install',
146
+ message: `✓ aiden-runtime v${v} installed. Restart Aiden to apply: ` +
147
+ `type /quit then re-run \`aiden\`.`,
148
+ installed: status.installed,
149
+ installedVersion: v,
150
+ };
151
+ }
152
+ return {
153
+ success: false,
154
+ stage: 'install',
155
+ error: result.error ?? 'Install failed (no error message).',
156
+ installed: status.installed,
157
+ latestSeen: status.latest,
158
+ // Keep stdout/stderr off the model-visible response to avoid
159
+ // prompt bloat; user-actionable copy-paste is already in error.
160
+ };
161
+ },
162
+ };
@@ -0,0 +1,79 @@
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
+ * tools/v4/system/appClose.ts — `app_close` tool.
10
+ *
11
+ * Close one or more Windows processes by process name. Accepts the
12
+ * bare name without `.exe` (matches `Stop-Process -Name` semantics).
13
+ * Returns the count of processes successfully terminated.
14
+ *
15
+ * The .exe stripper handles user input like "close notepad.exe" /
16
+ * "close notepad" identically — both resolve to the same call.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.appCloseTool = void 0;
20
+ const _psHelpers_1 = require("./_psHelpers");
21
+ function normalise(name) {
22
+ return name.trim().replace(/\.exe$/i, '');
23
+ }
24
+ function buildPs(processName, force) {
25
+ const safe = processName.replace(/'/g, "''");
26
+ const forceFlag = force ? '-Force' : '';
27
+ return [
28
+ `$procs = Get-Process -Name '${safe}' -ErrorAction SilentlyContinue;`,
29
+ `$count = ($procs | Measure-Object).Count;`,
30
+ `if ($count -gt 0) { $procs | Stop-Process ${forceFlag} -ErrorAction SilentlyContinue; }`,
31
+ `Write-Output ('closed:' + $count);`,
32
+ ].join(' ');
33
+ }
34
+ exports.appCloseTool = {
35
+ schema: {
36
+ name: 'app_close',
37
+ description: 'Close one or more Windows processes by name (with or without the .exe suffix). Matches all running instances of that name. Set `force: true` to skip the app\'s graceful-shutdown prompt. Windows-only in v4.1.2.',
38
+ inputSchema: {
39
+ type: 'object',
40
+ properties: {
41
+ app: {
42
+ type: 'string',
43
+ description: 'Process name (e.g. "notepad", "spotify"). The .exe suffix is stripped automatically. Matches ALL running instances of that name.',
44
+ },
45
+ force: {
46
+ type: 'boolean',
47
+ description: 'If true, terminate without giving the app a chance to save unsaved work. Default false (graceful close).',
48
+ },
49
+ },
50
+ required: ['app'],
51
+ },
52
+ },
53
+ category: 'execute',
54
+ mutates: true,
55
+ toolset: 'system',
56
+ async execute(args, _ctx) {
57
+ if (!(0, _psHelpers_1.isWindows)())
58
+ return (0, _psHelpers_1.windowsOnlyError)('app_close');
59
+ const app = typeof args.app === 'string' ? normalise(args.app) : '';
60
+ if (!app) {
61
+ return { success: false, error: '`app` is required and must be non-empty.' };
62
+ }
63
+ const force = args.force === true;
64
+ try {
65
+ const { stdout } = await (0, _psHelpers_1.runPowerShell)(buildPs(app, force), {
66
+ timeoutMs: 10000,
67
+ });
68
+ const m = stdout.trim().match(/closed:(\d+)/);
69
+ const closed = m ? Number(m[1]) : 0;
70
+ return { success: true, app, closed, force };
71
+ }
72
+ catch (e) {
73
+ return {
74
+ success: false,
75
+ error: e instanceof Error ? e.message : String(e),
76
+ };
77
+ }
78
+ },
79
+ };
@@ -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
+ * tools/v4/system/appLaunch.ts — `app_launch` tool.
10
+ *
11
+ * Start a Windows application by executable name or absolute path via
12
+ * PowerShell `Start-Process`. Resolves bare names through PATH and
13
+ * `App Paths` registry (so `spotify`, `notepad`, `chrome` all work
14
+ * without the user supplying the full path).
15
+ *
16
+ * Returns the PID of the launched process when available — useful for
17
+ * a subsequent `app_close` invocation or for confirming "did the
18
+ * launch succeed?" without a `window_list` round-trip.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.appLaunchTool = void 0;
22
+ const _psHelpers_1 = require("./_psHelpers");
23
+ function buildPs(appName, args) {
24
+ // Single-quote escape the app name for PowerShell.
25
+ const safeApp = appName.replace(/'/g, "''");
26
+ const argString = args && args.length > 0
27
+ ? `-ArgumentList @(${args.map((a) => `'${a.replace(/'/g, "''")}'`).join(',')})`
28
+ : '';
29
+ return [
30
+ `try {`,
31
+ ` $p = Start-Process '${safeApp}' ${argString} -PassThru -ErrorAction Stop;`,
32
+ ` Write-Output ('PID=' + $p.Id);`,
33
+ `} catch {`,
34
+ // App Paths registry resolution fallback: Start-Process sometimes
35
+ // fails on bare names that Windows would otherwise resolve via
36
+ // App Paths (Spotify, Chrome). Fall back to `start <name>` which
37
+ // honours App Paths.
38
+ ` cmd /c "start '' '${safeApp}'";`,
39
+ ` Write-Output 'PID=unknown (launched via cmd start fallback)';`,
40
+ `}`,
41
+ ].join(' ');
42
+ }
43
+ exports.appLaunchTool = {
44
+ schema: {
45
+ name: 'app_launch',
46
+ description: 'Launch a Windows application by exe name, friendly name (resolved via App Paths registry), or absolute path. Returns the launched PID when available. Use for "open Spotify" / "start Chrome" / etc. Windows-only in v4.1.2.',
47
+ inputSchema: {
48
+ type: 'object',
49
+ properties: {
50
+ app: {
51
+ type: 'string',
52
+ description: 'Application identifier. Accepts: bare name (e.g. "spotify", "notepad", "chrome"), exe basename ("notepad.exe"), or absolute path ("C:\\\\Program Files\\\\App\\\\app.exe").',
53
+ },
54
+ args: {
55
+ type: 'array',
56
+ description: 'Optional command-line arguments to pass to the app.',
57
+ items: { type: 'string', description: 'A single CLI argument string.' },
58
+ },
59
+ },
60
+ required: ['app'],
61
+ },
62
+ },
63
+ category: 'execute',
64
+ mutates: true,
65
+ toolset: 'system',
66
+ async execute(args, _ctx) {
67
+ if (!(0, _psHelpers_1.isWindows)())
68
+ return (0, _psHelpers_1.windowsOnlyError)('app_launch');
69
+ const app = typeof args.app === 'string' ? args.app.trim() : '';
70
+ if (!app) {
71
+ return { success: false, error: '`app` is required and must be non-empty.' };
72
+ }
73
+ const rawArgs = Array.isArray(args.args) ? args.args : undefined;
74
+ const cliArgs = rawArgs?.filter((a) => typeof a === 'string');
75
+ try {
76
+ const { stdout } = await (0, _psHelpers_1.runPowerShell)(buildPs(app, cliArgs), {
77
+ timeoutMs: 20000,
78
+ });
79
+ const out = stdout.trim();
80
+ // Extract PID when Start-Process succeeded; null for cmd-fallback path.
81
+ const pidMatch = out.match(/PID=(\d+)/);
82
+ const pid = pidMatch ? Number(pidMatch[1]) : null;
83
+ return { success: true, app, pid, raw: out };
84
+ }
85
+ catch (e) {
86
+ return {
87
+ success: false,
88
+ error: e instanceof Error ? e.message : String(e),
89
+ };
90
+ }
91
+ },
92
+ };
@@ -0,0 +1,54 @@
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
+ * tools/v4/system/clipboardRead.ts — `clipboard_read` tool.
10
+ *
11
+ * Read the current Windows clipboard contents as text via PowerShell
12
+ * `Get-Clipboard`. Non-text clipboard contents (image, file list, RTF)
13
+ * return an empty string — text-only by design; binary surfaces would
14
+ * need a different rendering contract.
15
+ *
16
+ * Privacy note: clipboard contents can include passwords, OTPs, and
17
+ * personal text. Tool description flags this so the model can warn
18
+ * the user before reading sensitive contexts.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.clipboardReadTool = void 0;
22
+ const _psHelpers_1 = require("./_psHelpers");
23
+ exports.clipboardReadTool = {
24
+ schema: {
25
+ name: 'clipboard_read',
26
+ description: 'Read the current Windows clipboard contents as text. Non-text clipboard data returns an empty string. Privacy-sensitive: clipboard may contain passwords, OTPs, or personal text — only invoke when the user has clearly asked. Windows-only in v4.1.2.',
27
+ inputSchema: {
28
+ type: 'object',
29
+ properties: {},
30
+ },
31
+ },
32
+ category: 'read',
33
+ mutates: false,
34
+ toolset: 'system',
35
+ async execute(_args, _ctx) {
36
+ if (!(0, _psHelpers_1.isWindows)())
37
+ return (0, _psHelpers_1.windowsOnlyError)('clipboard_read');
38
+ try {
39
+ // -Raw returns the whole buffer as one string (including newlines)
40
+ // rather than splitting on line breaks.
41
+ const { stdout } = await (0, _psHelpers_1.runPowerShell)('Get-Clipboard -Raw', { timeoutMs: 5000 });
42
+ // PowerShell appends a trailing CRLF — strip ONE trailing newline
43
+ // so the model sees what the user actually copied.
44
+ const text = stdout.replace(/\r?\n$/, '');
45
+ return { success: true, text, length: text.length };
46
+ }
47
+ catch (e) {
48
+ return {
49
+ success: false,
50
+ error: e instanceof Error ? e.message : String(e),
51
+ };
52
+ }
53
+ },
54
+ };
@@ -0,0 +1,84 @@
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
+ * tools/v4/system/clipboardWrite.ts — `clipboard_write` tool.
10
+ *
11
+ * Write text to the Windows clipboard via PowerShell `Set-Clipboard`.
12
+ * Caller passes the text as a string arg; we route it through stdin to
13
+ * the PowerShell process to side-step shell-argument quoting issues
14
+ * with newlines / special chars (Aiden's existing `shellInterpolation`
15
+ * pattern doesn't apply to tool args, but stdin is still the safest
16
+ * conduit for arbitrary text).
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.clipboardWriteTool = void 0;
20
+ const node_child_process_1 = require("node:child_process");
21
+ const _psHelpers_1 = require("./_psHelpers");
22
+ /**
23
+ * Spawn `powershell.exe Set-Clipboard` with the text piped on stdin.
24
+ * Wrapper Promise so the tool's `execute` can `await` it.
25
+ */
26
+ function setClipboardViaStdin(text, timeoutMs) {
27
+ return new Promise((resolve, reject) => {
28
+ const ps = (0, node_child_process_1.exec)(
29
+ // -Command - reads the script from stdin; but we want to PIPE the
30
+ // *value* not the script. Cleanest cross-version PowerShell path:
31
+ // read stdin in PowerShell and pass to Set-Clipboard.
32
+ 'powershell.exe -NoProfile -Command "$input | Set-Clipboard"', { timeout: timeoutMs, windowsHide: true }, (err) => {
33
+ if (err)
34
+ reject(err);
35
+ else
36
+ resolve();
37
+ });
38
+ if (!ps.stdin) {
39
+ reject(new Error('PowerShell child has no stdin'));
40
+ return;
41
+ }
42
+ ps.stdin.write(text);
43
+ ps.stdin.end();
44
+ });
45
+ }
46
+ exports.clipboardWriteTool = {
47
+ schema: {
48
+ name: 'clipboard_write',
49
+ description: 'Write text to the Windows clipboard. Replaces existing clipboard contents. Handles multi-line strings and special characters safely (text routed via stdin). Windows-only in v4.1.2.',
50
+ inputSchema: {
51
+ type: 'object',
52
+ properties: {
53
+ text: {
54
+ type: 'string',
55
+ description: 'Text to place on the clipboard. Replaces whatever is currently there.',
56
+ },
57
+ },
58
+ required: ['text'],
59
+ },
60
+ },
61
+ category: 'execute',
62
+ mutates: true,
63
+ toolset: 'system',
64
+ async execute(args, _ctx) {
65
+ if (!(0, _psHelpers_1.isWindows)())
66
+ return (0, _psHelpers_1.windowsOnlyError)('clipboard_write');
67
+ const text = typeof args.text === 'string' ? args.text : '';
68
+ // Empty string IS valid — it clears the clipboard. Distinguished
69
+ // from "no arg supplied" by the explicit type check.
70
+ if (typeof args.text !== 'string') {
71
+ return { success: false, error: '`text` is required and must be a string.' };
72
+ }
73
+ try {
74
+ await setClipboardViaStdin(text, 5000);
75
+ return { success: true, length: text.length };
76
+ }
77
+ catch (e) {
78
+ return {
79
+ success: false,
80
+ error: e instanceof Error ? e.message : String(e),
81
+ };
82
+ }
83
+ },
84
+ };
@@ -0,0 +1,78 @@
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
+ * tools/v4/system/mediaKey.ts — `media_key` tool.
10
+ *
11
+ * Send Windows media-control keys (play/pause, next, previous, stop)
12
+ * via PowerShell `System.Windows.Forms.SendKeys`. Works against any
13
+ * app that registers with SMTC (Spotify, YouTube in browser, Windows
14
+ * Media Player, Apple Music for Windows, VLC with MediaKey plugin,
15
+ * etc.) — the OS routes the keypress to the currently-active media
16
+ * session, so no per-app integration is required.
17
+ *
18
+ * Pairs with `now_playing` (read-only probe): the model reads what's
19
+ * playing, then issues the right media_key to control it.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.mediaKeyTool = void 0;
23
+ const _psHelpers_1 = require("./_psHelpers");
24
+ const ACTION_KEYS = {
25
+ play_pause: '{MEDIA_PLAY_PAUSE}',
26
+ next: '{MEDIA_NEXT_TRACK}',
27
+ previous: '{MEDIA_PREV_TRACK}',
28
+ stop: '{MEDIA_STOP}',
29
+ };
30
+ exports.mediaKeyTool = {
31
+ schema: {
32
+ name: 'media_key',
33
+ description: 'Send a media-control key to the active media session (Spotify, YouTube, etc.). Pair with `now_playing` to inspect current state. Windows-only in v4.1.2.',
34
+ inputSchema: {
35
+ type: 'object',
36
+ properties: {
37
+ action: {
38
+ type: 'string',
39
+ enum: ['play_pause', 'next', 'previous', 'stop'],
40
+ description: "'play_pause' toggles play/pause on the active media session. " +
41
+ "'next' / 'previous' skip tracks. 'stop' halts playback.",
42
+ },
43
+ },
44
+ required: ['action'],
45
+ },
46
+ },
47
+ category: 'execute',
48
+ mutates: true,
49
+ toolset: 'system',
50
+ async execute(args, _ctx) {
51
+ if (!(0, _psHelpers_1.isWindows)())
52
+ return (0, _psHelpers_1.windowsOnlyError)('media_key');
53
+ const action = args.action;
54
+ if (!ACTION_KEYS[action]) {
55
+ return {
56
+ success: false,
57
+ error: `Unknown media action: ${String(args.action)}. ` +
58
+ `Valid: ${Object.keys(ACTION_KEYS).join(', ')}`,
59
+ };
60
+ }
61
+ const sendkey = ACTION_KEYS[action];
62
+ const script = [
63
+ 'Add-Type -AssemblyName System.Windows.Forms;',
64
+ `[System.Windows.Forms.SendKeys]::SendWait('${sendkey}');`,
65
+ `Write-Output 'sent:${action}';`,
66
+ ].join(' ');
67
+ try {
68
+ await (0, _psHelpers_1.runPowerShell)(script, { timeoutMs: 5000 });
69
+ return { success: true, action };
70
+ }
71
+ catch (e) {
72
+ return {
73
+ success: false,
74
+ error: e instanceof Error ? e.message : String(e),
75
+ };
76
+ }
77
+ },
78
+ };
@@ -0,0 +1,99 @@
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
+ * tools/v4/system/osProcessList.ts — `os_process_list` tool.
10
+ *
11
+ * Lists OS-wide running processes via `Get-Process`. Distinct from the
12
+ * existing `process_list` tool which only enumerates child processes
13
+ * Aiden itself spawned via `process_spawn` — that's the wrong shape
14
+ * for questions like "is claude code running?" (the answer's process
15
+ * was started by the user, not Aiden).
16
+ *
17
+ * Filtering is supported via a substring on the process name. Default
18
+ * (no filter) lists the top-CPU processes capped at 30 so the model
19
+ * doesn't drown in a 200-row dump.
20
+ *
21
+ * Read-only. Cross-platform fallback returns a structured error
22
+ * pointing at the issue tracker.
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.osProcessListTool = void 0;
26
+ const _psHelpers_1 = require("./_psHelpers");
27
+ const DEFAULT_LIMIT = 30;
28
+ const MAX_LIMIT = 200;
29
+ function buildPs(nameFilter, limit) {
30
+ // Escape single quotes for the PowerShell -Name argument.
31
+ const filter = (nameFilter ?? '').trim();
32
+ // Get-Process picks `Name` (short), `Id` (pid), `CPU` (seconds), and
33
+ // `WorkingSet` (memory). ConvertTo-Json emits an array we parse.
34
+ const base = filter.length > 0
35
+ ? `Get-Process -Name '*${filter.replace(/'/g, "''")}*' -ErrorAction SilentlyContinue`
36
+ : 'Get-Process';
37
+ return [
38
+ base,
39
+ `| Sort-Object CPU -Descending`,
40
+ `| Select-Object -First ${limit} Name, Id, @{N='CPU';E={[math]::Round($_.CPU,2)}}, @{N='MemoryMB';E={[math]::Round($_.WorkingSet64/1MB,1)}}`,
41
+ `| ConvertTo-Json -Compress -Depth 2`,
42
+ ].join(' ');
43
+ }
44
+ exports.osProcessListTool = {
45
+ schema: {
46
+ name: 'os_process_list',
47
+ description: 'List OS-wide running processes (top by CPU). Use this to answer questions like "is X running?" or "what apps are using CPU?". Supports an optional name substring filter. Distinct from `process_list` which only shows processes Aiden itself spawned. Windows-only in v4.1.2.',
48
+ inputSchema: {
49
+ type: 'object',
50
+ properties: {
51
+ name: {
52
+ type: 'string',
53
+ description: 'Optional process-name substring filter, e.g. "claude" to find "claude.exe" / "claude_code.exe" / "claude-helper.exe". Omit to list top-CPU processes.',
54
+ },
55
+ limit: {
56
+ type: 'number',
57
+ description: 'Max rows to return (default 30, max 200). Use a higher value when answering "list everything running" style questions.',
58
+ },
59
+ },
60
+ },
61
+ },
62
+ category: 'read',
63
+ mutates: false,
64
+ toolset: 'system',
65
+ async execute(args, _ctx) {
66
+ if (!(0, _psHelpers_1.isWindows)())
67
+ return (0, _psHelpers_1.windowsOnlyError)('os_process_list');
68
+ const nameArg = typeof args.name === 'string' ? args.name : undefined;
69
+ const rawLimit = typeof args.limit === 'number' ? args.limit : DEFAULT_LIMIT;
70
+ const limit = Math.min(Math.max(1, Math.floor(rawLimit)), MAX_LIMIT);
71
+ try {
72
+ const { stdout } = await (0, _psHelpers_1.runPowerShell)(buildPs(nameArg, limit), {
73
+ timeoutMs: 15000,
74
+ });
75
+ const trimmed = stdout.trim();
76
+ // Get-Process returns nothing when the filter matches zero processes;
77
+ // PowerShell pipeline prints empty. Treat as "no matches" success.
78
+ if (trimmed.length === 0) {
79
+ return { success: true, processes: [], count: 0, filter: nameArg };
80
+ }
81
+ // ConvertTo-Json emits an object (single result) or array (multiple).
82
+ // Normalise to array.
83
+ const parsed = JSON.parse(trimmed);
84
+ const processes = Array.isArray(parsed) ? parsed : [parsed];
85
+ return {
86
+ success: true,
87
+ count: processes.length,
88
+ filter: nameArg,
89
+ processes,
90
+ };
91
+ }
92
+ catch (e) {
93
+ return {
94
+ success: false,
95
+ error: e instanceof Error ? e.message : String(e),
96
+ };
97
+ }
98
+ },
99
+ };