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.
- package/README.md +89 -33
- package/dist/cli/v4/aidenCLI.js +162 -11
- package/dist/cli/v4/callbacks.js +5 -2
- package/dist/cli/v4/chatSession.js +525 -15
- package/dist/cli/v4/commands/auth.js +6 -3
- package/dist/cli/v4/commands/help.js +4 -0
- package/dist/cli/v4/commands/index.js +10 -1
- package/dist/cli/v4/commands/reloadSoul.js +37 -0
- package/dist/cli/v4/commands/update.js +102 -0
- package/dist/cli/v4/defaultSoul.js +68 -2
- package/dist/cli/v4/display.js +28 -10
- package/dist/cli/v4/doctor.js +173 -1
- package/dist/cli/v4/doctorLiveness.js +384 -0
- package/dist/cli/v4/promotionPrompt.js +202 -0
- package/dist/cli/v4/providerBootSelector.js +144 -0
- package/dist/cli/v4/sessionSummaryGate.js +66 -0
- package/dist/cli/v4/toolPreview.js +139 -0
- package/dist/core/v4/aidenAgent.js +91 -29
- package/dist/core/v4/capabilities.js +89 -0
- package/dist/core/v4/contextCompressor.js +25 -8
- package/dist/core/v4/distillationIndex.js +167 -0
- package/dist/core/v4/distillationStore.js +98 -0
- package/dist/core/v4/logger/logger.js +40 -9
- package/dist/core/v4/promotionCandidates.js +234 -0
- package/dist/core/v4/promptBuilder.js +145 -1
- package/dist/core/v4/sessionDistiller.js +405 -0
- package/dist/core/v4/skillMining/extractorPrompt.js +28 -21
- package/dist/core/v4/skillMining/proposalBuilder.js +3 -2
- package/dist/core/v4/skillMining/skillMiner.js +43 -6
- package/dist/core/v4/skillOutcomeTracker.js +323 -0
- package/dist/core/v4/subsystemHealth.js +143 -0
- package/dist/core/v4/update/executeInstall.js +233 -0
- package/dist/core/version.js +1 -1
- package/dist/moat/dangerousPatterns.js +1 -1
- package/dist/moat/memoryGuard.js +111 -0
- package/dist/moat/skillTeacher.js +14 -5
- package/dist/providers/v4/chatCompletionsAdapter.js +9 -0
- package/dist/providers/v4/codexResponsesAdapter.js +7 -2
- package/dist/providers/v4/errors.js +67 -1
- package/dist/providers/v4/modelDefaults.js +65 -0
- package/dist/providers/v4/ollamaPromptToolsAdapter.js +9 -2
- package/dist/providers/v4/registry.js +9 -2
- package/dist/providers/v4/runtimeResolver.js +6 -0
- package/dist/tools/v4/index.js +57 -1
- package/dist/tools/v4/memory/memoryRemove.js +57 -2
- package/dist/tools/v4/memory/sessionSummary.js +151 -0
- package/dist/tools/v4/sessions/recallSession.js +163 -0
- package/dist/tools/v4/sessions/sessionSearch.js +5 -1
- package/dist/tools/v4/subagent/subagentFanout.js +24 -0
- package/dist/tools/v4/system/_psHelpers.js +55 -0
- package/dist/tools/v4/system/aidenSelfUpdate.js +162 -0
- package/dist/tools/v4/system/appClose.js +79 -0
- package/dist/tools/v4/system/appLaunch.js +92 -0
- package/dist/tools/v4/system/clipboardRead.js +54 -0
- package/dist/tools/v4/system/clipboardWrite.js +84 -0
- package/dist/tools/v4/system/mediaKey.js +78 -0
- package/dist/tools/v4/system/osProcessList.js +99 -0
- package/dist/tools/v4/system/screenshot.js +106 -0
- package/dist/tools/v4/system/volumeSet.js +157 -0
- package/package.json +4 -1
- package/skills/system_control.md +135 -69
|
@@ -0,0 +1,106 @@
|
|
|
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/screenshot.ts — `screenshot` tool.
|
|
10
|
+
*
|
|
11
|
+
* Captures the full desktop and writes it as a PNG to
|
|
12
|
+
* `<aidenHome>/screenshots/<timestamp>.png`. Returns the absolute path
|
|
13
|
+
* in `path` so a Telegram / Discord channel adapter can attach the
|
|
14
|
+
* file directly without a separate file_read round-trip.
|
|
15
|
+
*
|
|
16
|
+
* Privacy note (Phase v4.1.2-followup-3): this tool reads what is
|
|
17
|
+
* currently visible on the screen — anything in front of the user.
|
|
18
|
+
* The tool description says so explicitly so users know what they're
|
|
19
|
+
* approving when the model invokes it.
|
|
20
|
+
*
|
|
21
|
+
* Implementation: PowerShell-only, no native dependency. Uses
|
|
22
|
+
* `System.Windows.Forms.Screen` + `System.Drawing.Bitmap` /
|
|
23
|
+
* `Graphics.CopyFromScreen()` — both ship with .NET on every modern
|
|
24
|
+
* Windows install. Cross-platform fallback returns a structured error.
|
|
25
|
+
*/
|
|
26
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
27
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
28
|
+
};
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.screenshotTool = void 0;
|
|
31
|
+
const node_fs_1 = require("node:fs");
|
|
32
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
33
|
+
const _psHelpers_1 = require("./_psHelpers");
|
|
34
|
+
/**
|
|
35
|
+
* Build the PowerShell capture script. The bitmap dimensions come from
|
|
36
|
+
* `Screen::PrimaryScreen.Bounds` so we get the actual primary-monitor
|
|
37
|
+
* resolution, not a hardcoded value. SaveAs PNG to keep losslessness
|
|
38
|
+
* — file size on a 4K screen is ~4-8 MB which is fine for chat.
|
|
39
|
+
*/
|
|
40
|
+
function buildScreenshotPs(outPath) {
|
|
41
|
+
const psQuoted = outPath.replace(/'/g, "''"); // PowerShell single-quote escape
|
|
42
|
+
return [
|
|
43
|
+
'Add-Type -AssemblyName System.Windows.Forms;',
|
|
44
|
+
'Add-Type -AssemblyName System.Drawing;',
|
|
45
|
+
'$bounds = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds;',
|
|
46
|
+
'$bitmap = New-Object System.Drawing.Bitmap $bounds.Width, $bounds.Height;',
|
|
47
|
+
'$gfx = [System.Drawing.Graphics]::FromImage($bitmap);',
|
|
48
|
+
'$gfx.CopyFromScreen($bounds.Location, [System.Drawing.Point]::Empty, $bounds.Size);',
|
|
49
|
+
`$bitmap.Save('${psQuoted}', [System.Drawing.Imaging.ImageFormat]::Png);`,
|
|
50
|
+
'$gfx.Dispose(); $bitmap.Dispose();',
|
|
51
|
+
`Write-Output '${psQuoted}';`,
|
|
52
|
+
].join(' ');
|
|
53
|
+
}
|
|
54
|
+
exports.screenshotTool = {
|
|
55
|
+
schema: {
|
|
56
|
+
name: 'screenshot',
|
|
57
|
+
description: 'Capture the current primary-monitor desktop as a PNG. Returns the absolute path of the saved file. Reads whatever is currently visible on screen — privacy-sensitive; only invoke when the user explicitly asks for a screenshot or screen share. Windows-only in v4.1.2.',
|
|
58
|
+
inputSchema: {
|
|
59
|
+
type: 'object',
|
|
60
|
+
properties: {},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
category: 'read',
|
|
64
|
+
mutates: false,
|
|
65
|
+
toolset: 'system',
|
|
66
|
+
async execute(_args, ctx) {
|
|
67
|
+
if (!(0, _psHelpers_1.isWindows)())
|
|
68
|
+
return (0, _psHelpers_1.windowsOnlyError)('screenshot');
|
|
69
|
+
if (!ctx.paths) {
|
|
70
|
+
return { success: false, error: 'aiden paths not wired (test mode?)' };
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const dir = node_path_1.default.join(ctx.paths.root, 'screenshots');
|
|
74
|
+
await node_fs_1.promises.mkdir(dir, { recursive: true });
|
|
75
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
76
|
+
const outPath = node_path_1.default.join(dir, `${stamp}.png`);
|
|
77
|
+
const { stdout } = await (0, _psHelpers_1.runPowerShell)(buildScreenshotPs(outPath), {
|
|
78
|
+
timeoutMs: 30000,
|
|
79
|
+
});
|
|
80
|
+
// Verify the file actually landed on disk — PowerShell can exit 0
|
|
81
|
+
// and have written nothing on an exotic display configuration.
|
|
82
|
+
try {
|
|
83
|
+
const stat = await node_fs_1.promises.stat(outPath);
|
|
84
|
+
return {
|
|
85
|
+
success: true,
|
|
86
|
+
path: outPath,
|
|
87
|
+
size: stat.size,
|
|
88
|
+
// For Telegram / Discord adapters — they can attach via path.
|
|
89
|
+
attachAs: 'image/png',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return {
|
|
94
|
+
success: false,
|
|
95
|
+
error: `screenshot script ran but file not found at ${outPath} (stdout=${stdout.trim().slice(0, 120)})`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
error: e instanceof Error ? e.message : String(e),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
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/volumeSet.ts — `volume_set` tool.
|
|
10
|
+
*
|
|
11
|
+
* Set the Windows master-volume level to a percentage (0-100), or
|
|
12
|
+
* toggle mute. Uses the Shell.Application COM object's appCommand
|
|
13
|
+
* SendKeys for up/down nudges; for absolute level setting, talks to
|
|
14
|
+
* `IAudioEndpointVolume` via PowerShell inline C# (Add-Type) — no
|
|
15
|
+
* external binary (no nircmd, no soundvolumeview).
|
|
16
|
+
*
|
|
17
|
+
* The inline-C# approach is well-trodden Windows lore: the
|
|
18
|
+
* IAudioEndpointVolume COM interface is part of the Core Audio APIs
|
|
19
|
+
* available since Vista. We declare the interop types in PowerShell,
|
|
20
|
+
* invoke `SetMasterVolumeLevelScalar`, and clean up. Adds ~1-2s
|
|
21
|
+
* cold-start (PowerShell Add-Type compilation) — fine for an
|
|
22
|
+
* occasionally-invoked control.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.volumeSetTool = void 0;
|
|
26
|
+
const _psHelpers_1 = require("./_psHelpers");
|
|
27
|
+
const ADD_TYPE_AUDIO = `
|
|
28
|
+
Add-Type -TypeDefinition @'
|
|
29
|
+
using System;
|
|
30
|
+
using System.Runtime.InteropServices;
|
|
31
|
+
[Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
32
|
+
interface IAudioEndpointVolume {
|
|
33
|
+
int RegisterControlChangeNotify(IntPtr cb);
|
|
34
|
+
int UnregisterControlChangeNotify(IntPtr cb);
|
|
35
|
+
int GetChannelCount(out uint count);
|
|
36
|
+
int SetMasterVolumeLevel(float level, Guid ctx);
|
|
37
|
+
int SetMasterVolumeLevelScalar(float level, Guid ctx);
|
|
38
|
+
int GetMasterVolumeLevel(out float level);
|
|
39
|
+
int GetMasterVolumeLevelScalar(out float level);
|
|
40
|
+
int SetChannelVolumeLevel(uint ch, float level, Guid ctx);
|
|
41
|
+
int SetChannelVolumeLevelScalar(uint ch, float level, Guid ctx);
|
|
42
|
+
int GetChannelVolumeLevel(uint ch, out float level);
|
|
43
|
+
int GetChannelVolumeLevelScalar(uint ch, out float level);
|
|
44
|
+
int SetMute(bool mute, Guid ctx);
|
|
45
|
+
int GetMute(out bool mute);
|
|
46
|
+
int GetVolumeStepInfo(out uint step, out uint count);
|
|
47
|
+
int VolumeStepUp(Guid ctx);
|
|
48
|
+
int VolumeStepDown(Guid ctx);
|
|
49
|
+
int QueryHardwareSupport(out uint mask);
|
|
50
|
+
int GetVolumeRange(out float min, out float max, out float inc);
|
|
51
|
+
}
|
|
52
|
+
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
53
|
+
interface IMMDeviceEnumerator {
|
|
54
|
+
int NotImpl0();
|
|
55
|
+
int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice ep);
|
|
56
|
+
}
|
|
57
|
+
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
58
|
+
interface IMMDevice {
|
|
59
|
+
int Activate(ref Guid id, int clsCtx, IntPtr pa, [MarshalAs(UnmanagedType.IUnknown)] out object o);
|
|
60
|
+
}
|
|
61
|
+
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
|
|
62
|
+
class MMDeviceEnumeratorComObject { }
|
|
63
|
+
public static class Audio {
|
|
64
|
+
static IAudioEndpointVolume Vol() {
|
|
65
|
+
var enumerator = new MMDeviceEnumeratorComObject() as IMMDeviceEnumerator;
|
|
66
|
+
IMMDevice dev = null;
|
|
67
|
+
Marshal.ThrowExceptionForHR(enumerator.GetDefaultAudioEndpoint(0, 1, out dev));
|
|
68
|
+
Guid epvid = typeof(IAudioEndpointVolume).GUID;
|
|
69
|
+
object o;
|
|
70
|
+
Marshal.ThrowExceptionForHR(dev.Activate(ref epvid, 7, IntPtr.Zero, out o));
|
|
71
|
+
return o as IAudioEndpointVolume;
|
|
72
|
+
}
|
|
73
|
+
public static float GetLevel() { float l; Marshal.ThrowExceptionForHR(Vol().GetMasterVolumeLevelScalar(out l)); return l; }
|
|
74
|
+
public static void SetLevel(float level) { Marshal.ThrowExceptionForHR(Vol().SetMasterVolumeLevelScalar(level, Guid.Empty)); }
|
|
75
|
+
public static bool GetMute() { bool m; Marshal.ThrowExceptionForHR(Vol().GetMute(out m)); return m; }
|
|
76
|
+
public static void SetMute(bool mute) { Marshal.ThrowExceptionForHR(Vol().SetMute(mute, Guid.Empty)); }
|
|
77
|
+
}
|
|
78
|
+
'@;
|
|
79
|
+
`;
|
|
80
|
+
function buildPs(action, percent) {
|
|
81
|
+
if (action === 'set' && typeof percent === 'number') {
|
|
82
|
+
const scalar = (Math.max(0, Math.min(100, percent)) / 100).toFixed(4);
|
|
83
|
+
return [
|
|
84
|
+
ADD_TYPE_AUDIO,
|
|
85
|
+
`[Audio]::SetLevel([float]${scalar});`,
|
|
86
|
+
`$level = [Audio]::GetLevel();`,
|
|
87
|
+
`Write-Output ([math]::Round($level * 100, 0));`,
|
|
88
|
+
].join('\n');
|
|
89
|
+
}
|
|
90
|
+
if (action === 'mute') {
|
|
91
|
+
return [ADD_TYPE_AUDIO, `[Audio]::SetMute($true); Write-Output 'muted';`].join('\n');
|
|
92
|
+
}
|
|
93
|
+
if (action === 'unmute') {
|
|
94
|
+
return [ADD_TYPE_AUDIO, `[Audio]::SetMute($false); Write-Output 'unmuted';`].join('\n');
|
|
95
|
+
}
|
|
96
|
+
// toggle_mute
|
|
97
|
+
return [
|
|
98
|
+
ADD_TYPE_AUDIO,
|
|
99
|
+
`$cur = [Audio]::GetMute(); [Audio]::SetMute(-not $cur);`,
|
|
100
|
+
`Write-Output (if (-not $cur) {'muted'} else {'unmuted'});`,
|
|
101
|
+
].join('\n');
|
|
102
|
+
}
|
|
103
|
+
exports.volumeSetTool = {
|
|
104
|
+
schema: {
|
|
105
|
+
name: 'volume_set',
|
|
106
|
+
description: 'Set Windows master volume to a percentage (0-100), or mute / unmute / toggle mute. Operates on the default audio endpoint. Windows-only in v4.1.2.',
|
|
107
|
+
inputSchema: {
|
|
108
|
+
type: 'object',
|
|
109
|
+
properties: {
|
|
110
|
+
action: {
|
|
111
|
+
type: 'string',
|
|
112
|
+
enum: ['set', 'mute', 'unmute', 'toggle_mute'],
|
|
113
|
+
description: "'set' requires `percent`. 'mute' / 'unmute' force the state. 'toggle_mute' flips it.",
|
|
114
|
+
},
|
|
115
|
+
percent: {
|
|
116
|
+
type: 'number',
|
|
117
|
+
description: 'Target volume 0-100 (only used when action="set"). Values outside the range are clamped.',
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
required: ['action'],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
category: 'execute',
|
|
124
|
+
mutates: true,
|
|
125
|
+
toolset: 'system',
|
|
126
|
+
async execute(args, _ctx) {
|
|
127
|
+
if (!(0, _psHelpers_1.isWindows)())
|
|
128
|
+
return (0, _psHelpers_1.windowsOnlyError)('volume_set');
|
|
129
|
+
const action = args.action;
|
|
130
|
+
if (!['set', 'mute', 'unmute', 'toggle_mute'].includes(action)) {
|
|
131
|
+
return {
|
|
132
|
+
success: false,
|
|
133
|
+
error: `Unknown volume action: ${String(args.action)}. ` +
|
|
134
|
+
`Valid: set, mute, unmute, toggle_mute`,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const percent = typeof args.percent === 'number' ? args.percent : undefined;
|
|
138
|
+
if (action === 'set' && percent === undefined) {
|
|
139
|
+
return {
|
|
140
|
+
success: false,
|
|
141
|
+
error: "action='set' requires a numeric `percent` (0-100).",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const { stdout } = await (0, _psHelpers_1.runPowerShell)(buildPs(action, percent), {
|
|
146
|
+
timeoutMs: 10000,
|
|
147
|
+
});
|
|
148
|
+
return { success: true, action, result: stdout.trim() };
|
|
149
|
+
}
|
|
150
|
+
catch (e) {
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
error: e instanceof Error ? e.message : String(e),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiden-runtime",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -77,6 +77,9 @@
|
|
|
77
77
|
"dist:linux": "node scripts/prepare-electron.js && electron-builder --linux --x64 --publish never && node -e \"const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json','utf8'));p.main='./dist/index.js';fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\\n');console.log(' main restored')\"",
|
|
78
78
|
"test": "vitest run",
|
|
79
79
|
"test:ui": "vitest --ui",
|
|
80
|
+
"eval": "ts-node evals/cli.ts",
|
|
81
|
+
"eval:honesty": "ts-node evals/cli.ts --suite honesty",
|
|
82
|
+
"eval:scenario": "ts-node evals/cli.ts --scenario",
|
|
80
83
|
"stress-test": "npx ts-node tests/stressTest.ts",
|
|
81
84
|
"test:all": "npx ts-node tests/e2e/masterTestSuite.ts",
|
|
82
85
|
"test:unit": "npx ts-node tests/e2e/masterTestSuite.ts --part1",
|
package/skills/system_control.md
CHANGED
|
@@ -1,69 +1,135 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: system_control
|
|
3
|
-
description: Windows desktop control — clipboard,
|
|
4
|
-
version:
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Skill: System Control
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
1
|
+
---
|
|
2
|
+
name: system_control
|
|
3
|
+
description: Windows desktop control — clipboard, screenshots, media, volume, apps
|
|
4
|
+
version: 2.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: System Control
|
|
8
|
+
|
|
9
|
+
Interact with the Windows desktop: clipboard, screenshots, media playback,
|
|
10
|
+
volume, app launch/close, OS-wide process listing. All eight verbs below
|
|
11
|
+
are real registered tools — call them directly. The two verbs in the
|
|
12
|
+
"Not a tool yet" section route through `shell_exec` with the PowerShell
|
|
13
|
+
snippet shown.
|
|
14
|
+
|
|
15
|
+
Windows-only in v4.1.2. macOS/Linux callers get a structured error
|
|
16
|
+
pointing at the issue tracker; route to the user's clarifying-question
|
|
17
|
+
path if they need cross-platform coverage.
|
|
18
|
+
|
|
19
|
+
## Read-only verbs
|
|
20
|
+
|
|
21
|
+
### clipboard_read
|
|
22
|
+
Read the current clipboard contents as text. Empty string for non-text
|
|
23
|
+
clipboard data (image, RTF, file list). Privacy-sensitive — the
|
|
24
|
+
clipboard often holds passwords, OTPs, or personal text. Only call when
|
|
25
|
+
the user has clearly asked.
|
|
26
|
+
```json
|
|
27
|
+
{ "tool": "clipboard_read", "input": {} }
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### screenshot
|
|
31
|
+
Capture the primary monitor as a PNG. Saves to
|
|
32
|
+
`<aidenHome>/screenshots/<timestamp>.png` and returns the absolute path.
|
|
33
|
+
Telegram / Discord channel adapters can attach the file directly via
|
|
34
|
+
the returned path. Privacy-sensitive — captures everything visible.
|
|
35
|
+
```json
|
|
36
|
+
{ "tool": "screenshot", "input": {} }
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### os_process_list
|
|
40
|
+
List OS-wide running processes (top by CPU). Use this to answer
|
|
41
|
+
"is X running?" or "what's hogging my CPU?". Distinct from `process_list`
|
|
42
|
+
which only shows processes Aiden itself spawned via `process_spawn`.
|
|
43
|
+
```json
|
|
44
|
+
{ "tool": "os_process_list", "input": { "name": "claude" } }
|
|
45
|
+
{ "tool": "os_process_list", "input": { "limit": 50 } }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Mutating verbs (approval-gated)
|
|
49
|
+
|
|
50
|
+
### clipboard_write
|
|
51
|
+
Replace the clipboard with new text. Handles multi-line strings safely
|
|
52
|
+
(text routed via stdin to PowerShell, no shell-quoting issues).
|
|
53
|
+
```json
|
|
54
|
+
{ "tool": "clipboard_write", "input": { "text": "Hello, world!" } }
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### media_key
|
|
58
|
+
Send a media-control key to the active media session (Spotify, YouTube
|
|
59
|
+
in browser, Windows Media Player, etc.). Pair with `now_playing` to
|
|
60
|
+
inspect state first.
|
|
61
|
+
```json
|
|
62
|
+
{ "tool": "media_key", "input": { "action": "play_pause" } }
|
|
63
|
+
{ "tool": "media_key", "input": { "action": "next" } }
|
|
64
|
+
{ "tool": "media_key", "input": { "action": "previous" } }
|
|
65
|
+
{ "tool": "media_key", "input": { "action": "stop" } }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### volume_set
|
|
69
|
+
Set Windows master volume to a percentage, or mute / unmute / toggle.
|
|
70
|
+
```json
|
|
71
|
+
{ "tool": "volume_set", "input": { "action": "set", "percent": 30 } }
|
|
72
|
+
{ "tool": "volume_set", "input": { "action": "mute" } }
|
|
73
|
+
{ "tool": "volume_set", "input": { "action": "toggle_mute" } }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### app_launch
|
|
77
|
+
Launch a Windows application by exe name, friendly name (resolved via
|
|
78
|
+
App Paths registry), or absolute path. Returns the PID when available.
|
|
79
|
+
```json
|
|
80
|
+
{ "tool": "app_launch", "input": { "app": "spotify" } }
|
|
81
|
+
{ "tool": "app_launch", "input": { "app": "notepad", "args": ["C:\\temp\\note.txt"] } }
|
|
82
|
+
{ "tool": "app_launch", "input": { "app": "C:\\Program Files\\App\\app.exe" } }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### app_close
|
|
86
|
+
Close one or more processes by name (with or without the `.exe`
|
|
87
|
+
suffix). Matches all running instances. Set `force: true` to skip the
|
|
88
|
+
app's graceful-shutdown prompt.
|
|
89
|
+
```json
|
|
90
|
+
{ "tool": "app_close", "input": { "app": "notepad" } }
|
|
91
|
+
{ "tool": "app_close", "input": { "app": "chrome.exe", "force": true } }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Not a tool yet — route via `shell_exec`
|
|
95
|
+
|
|
96
|
+
### Focus a window by title
|
|
97
|
+
v4.1.2 does not ship a `window_focus` tool — Win32 P/Invoke complexity
|
|
98
|
+
isn't worth a dedicated tool when shell_exec covers the same ground.
|
|
99
|
+
```powershell
|
|
100
|
+
(New-Object -ComObject WScript.Shell).AppActivate('Notepad')
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### List visible windows
|
|
104
|
+
Same reasoning. The MainWindowTitle filter excludes background services.
|
|
105
|
+
```powershell
|
|
106
|
+
Get-Process | Where-Object { $_.MainWindowTitle } |
|
|
107
|
+
Select-Object Id, ProcessName, MainWindowTitle |
|
|
108
|
+
ConvertTo-Json -Compress
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Wrap either snippet in `shell_exec` when the user explicitly asks for
|
|
112
|
+
window manipulation. Track v4.1.3+ for native tool wrappers if these
|
|
113
|
+
turn into common requests.
|
|
114
|
+
|
|
115
|
+
## Usage Patterns
|
|
116
|
+
|
|
117
|
+
**Copy file content to clipboard after writing it:**
|
|
118
|
+
1. `file_write` → write the content
|
|
119
|
+
2. `clipboard_write` → copy the file path or content
|
|
120
|
+
|
|
121
|
+
**Confirm an app launched:**
|
|
122
|
+
1. `app_launch` → returns PID
|
|
123
|
+
2. `os_process_list` with the app's name → verify it's still running
|
|
124
|
+
|
|
125
|
+
**"Is X running?" workflow:**
|
|
126
|
+
1. `os_process_list` with `name: "<substring>"` → returns matching processes
|
|
127
|
+
2. If `count === 0` → tell the user honestly, suggest `app_launch`
|
|
128
|
+
|
|
129
|
+
**Media control workflow:**
|
|
130
|
+
1. `now_playing` → see what's currently playing
|
|
131
|
+
2. `media_key` → control it (play_pause / next / previous / stop)
|
|
132
|
+
|
|
133
|
+
**Volume change with feedback:**
|
|
134
|
+
1. `volume_set` → returns the resulting volume percent in `result`
|
|
135
|
+
2. Surface it to the user so they know the change landed.
|