zilmate 1.9.3 → 1.9.9

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 (66) hide show
  1. package/dist/agents/coding.agent.d.ts +82 -0
  2. package/dist/agents/coding.agent.d.ts.map +1 -1
  3. package/dist/agents/coding.agent.js +3 -3
  4. package/dist/agents/coding.agent.js.map +1 -1
  5. package/dist/agents/manager.d.ts +180 -2
  6. package/dist/agents/manager.d.ts.map +1 -1
  7. package/dist/agents/manager.js +8 -5
  8. package/dist/agents/manager.js.map +1 -1
  9. package/dist/cli/chat.d.ts +1 -1
  10. package/dist/cli/chat.d.ts.map +1 -1
  11. package/dist/cli/chat.js +32 -10
  12. package/dist/cli/chat.js.map +1 -1
  13. package/dist/cli/format.d.ts +1 -0
  14. package/dist/cli/format.d.ts.map +1 -1
  15. package/dist/cli/format.js +68 -14
  16. package/dist/cli/format.js.map +1 -1
  17. package/dist/cli/setup.d.ts.map +1 -1
  18. package/dist/cli/setup.js +9 -3
  19. package/dist/cli/setup.js.map +1 -1
  20. package/dist/cli/update.d.ts +2 -0
  21. package/dist/cli/update.d.ts.map +1 -1
  22. package/dist/cli/update.js +89 -1
  23. package/dist/cli/update.js.map +1 -1
  24. package/dist/config/env.d.ts +2 -0
  25. package/dist/config/env.d.ts.map +1 -1
  26. package/dist/config/env.js +9 -5
  27. package/dist/config/env.js.map +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +49 -5
  31. package/dist/index.js.map +1 -1
  32. package/dist/pre-init.d.ts +2 -0
  33. package/dist/pre-init.d.ts.map +1 -0
  34. package/dist/pre-init.js +3 -0
  35. package/dist/pre-init.js.map +1 -0
  36. package/dist/runtime/chat-bridge.d.ts.map +1 -1
  37. package/dist/runtime/chat-bridge.js +33 -2
  38. package/dist/runtime/chat-bridge.js.map +1 -1
  39. package/dist/server.d.ts +1 -0
  40. package/dist/server.d.ts.map +1 -1
  41. package/dist/server.js +1 -0
  42. package/dist/server.js.map +1 -1
  43. package/dist/tools/computer-use.tool.d.ts +4 -4
  44. package/dist/tools/desktop.tool.d.ts +96 -0
  45. package/dist/tools/desktop.tool.d.ts.map +1 -1
  46. package/dist/tools/desktop.tool.js +439 -0
  47. package/dist/tools/desktop.tool.js.map +1 -1
  48. package/dist/tools/shell.tool.d.ts +82 -0
  49. package/dist/tools/shell.tool.d.ts.map +1 -1
  50. package/dist/tools/shell.tool.js +192 -1
  51. package/dist/tools/shell.tool.js.map +1 -1
  52. package/dist/voice/cascade.d.ts +1 -0
  53. package/dist/voice/cascade.d.ts.map +1 -1
  54. package/dist/voice/cascade.js +16 -1
  55. package/dist/voice/cascade.js.map +1 -1
  56. package/dist/voice/deepgram.d.ts.map +1 -1
  57. package/dist/voice/deepgram.js +4 -0
  58. package/dist/voice/deepgram.js.map +1 -1
  59. package/dist/voice/terminal.d.ts +1 -0
  60. package/dist/voice/terminal.d.ts.map +1 -1
  61. package/dist/voice/terminal.js +28 -0
  62. package/dist/voice/terminal.js.map +1 -1
  63. package/dist/voice/types.d.ts +2 -0
  64. package/dist/voice/types.d.ts.map +1 -1
  65. package/package.json +2 -1
  66. package/scripts/release-github.mjs +8 -10
@@ -124,5 +124,101 @@ export declare const desktopTools: {
124
124
  error: any;
125
125
  input?: never;
126
126
  }>;
127
+ simulateMouse: import("ai").Tool<{
128
+ action: "move" | "click" | "double-click" | "right-click" | "drag" | "scroll";
129
+ x?: number | undefined;
130
+ y?: number | undefined;
131
+ endX?: number | undefined;
132
+ endY?: number | undefined;
133
+ scrollAmount?: number | undefined;
134
+ }, {
135
+ success: boolean;
136
+ action: "move" | "click" | "double-click" | "right-click" | "drag" | "scroll";
137
+ error?: never;
138
+ } | {
139
+ success: boolean;
140
+ error: any;
141
+ action?: never;
142
+ }>;
143
+ displaySystemNotification: import("ai").Tool<{
144
+ title: string;
145
+ message: string;
146
+ }, {
147
+ success: boolean;
148
+ error?: never;
149
+ } | {
150
+ success: boolean;
151
+ error: any;
152
+ }>;
153
+ recordAudioSnippet: import("ai").Tool<{
154
+ durationSeconds: number;
155
+ }, {
156
+ success: boolean;
157
+ file: string;
158
+ durationSeconds: number;
159
+ error?: never;
160
+ } | {
161
+ success: boolean;
162
+ error: any;
163
+ file?: never;
164
+ durationSeconds?: never;
165
+ }>;
166
+ getActiveWindowContext: import("ai").Tool<Record<string, never>, {
167
+ title?: string;
168
+ process?: string;
169
+ pid?: number;
170
+ success: boolean;
171
+ error?: never;
172
+ } | {
173
+ success: boolean;
174
+ error: any;
175
+ }>;
176
+ controlSystemVolume: import("ai").Tool<{
177
+ action: "set" | "get" | "mute" | "unmute" | "media-play-pause" | "media-next" | "media-prev";
178
+ level?: number | undefined;
179
+ }, {
180
+ success: boolean;
181
+ action: "media-play-pause";
182
+ level?: never;
183
+ error?: never;
184
+ } | {
185
+ success: boolean;
186
+ action: "media-next";
187
+ level?: never;
188
+ error?: never;
189
+ } | {
190
+ success: boolean;
191
+ action: "media-prev";
192
+ level?: never;
193
+ error?: never;
194
+ } | {
195
+ success: boolean;
196
+ action: "mute";
197
+ level?: never;
198
+ error?: never;
199
+ } | {
200
+ success: boolean;
201
+ action: "unmute";
202
+ level?: never;
203
+ error?: never;
204
+ } | {
205
+ success: boolean;
206
+ action: "set";
207
+ level: number;
208
+ error?: never;
209
+ } | {
210
+ success: boolean;
211
+ error: string;
212
+ action?: never;
213
+ level?: never;
214
+ } | {
215
+ success: boolean;
216
+ level: number;
217
+ action?: never;
218
+ error?: never;
219
+ } | {
220
+ success: boolean;
221
+ error: any;
222
+ }>;
127
223
  };
128
224
  //# sourceMappingURL=desktop.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"desktop.tool.d.ts","sourceRoot":"","sources":["../../src/tools/desktop.tool.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAgLF,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAgCrE;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAwBpE;AAED,wBAAsB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,mBAsBvD;AAgDD,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwTxB,CAAC"}
1
+ {"version":3,"file":"desktop.tool.d.ts","sourceRoot":"","sources":["../../src/tools/desktop.tool.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAsfF,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAgCrE;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAwBpE;AAED,wBAAsB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,mBAsBvD;AAgDD,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBA/Y2B,MAAM;kBAAY,MAAM;cAAQ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsyBzF,CAAC"}
@@ -38,6 +38,350 @@ async function commandExists(command) {
38
38
  return false;
39
39
  }
40
40
  }
41
+ async function simulateMouseAction(action, x, y, endX, endY, scrollAmount) {
42
+ if (process.platform === 'win32') {
43
+ let script = '';
44
+ if (action === 'move' && x !== undefined && y !== undefined) {
45
+ script = `[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${x}, ${y})`;
46
+ }
47
+ else if (action === 'click') {
48
+ script = `
49
+ Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern void mouse_event(int flags, int dx, int dy, int data, int extra);' -Name Mouse -Namespace Win32
50
+ if ($null -ne ${x} -and $null -ne ${y}) { [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${x}, ${y}) }
51
+ [Win32.Mouse]::mouse_event(0x0002, 0, 0, 0, 0) # LEFTDOWN
52
+ [Win32.Mouse]::mouse_event(0x0004, 0, 0, 0, 0) # LEFTUP
53
+ `;
54
+ }
55
+ else if (action === 'double-click') {
56
+ script = `
57
+ Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern void mouse_event(int flags, int dx, int dy, int data, int extra);' -Name Mouse -Namespace Win32
58
+ if ($null -ne ${x} -and $null -ne ${y}) { [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${x}, ${y}) }
59
+ [Win32.Mouse]::mouse_event(0x0002, 0, 0, 0, 0)
60
+ [Win32.Mouse]::mouse_event(0x0004, 0, 0, 0, 0)
61
+ Start-Sleep -Milliseconds 100
62
+ [Win32.Mouse]::mouse_event(0x0002, 0, 0, 0, 0)
63
+ [Win32.Mouse]::mouse_event(0x0004, 0, 0, 0, 0)
64
+ `;
65
+ }
66
+ else if (action === 'right-click') {
67
+ script = `
68
+ Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern void mouse_event(int flags, int dx, int dy, int data, int extra);' -Name Mouse -Namespace Win32
69
+ if ($null -ne ${x} -and $null -ne ${y}) { [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${x}, ${y}) }
70
+ [Win32.Mouse]::mouse_event(0x0008, 0, 0, 0, 0) # RIGHTDOWN
71
+ [Win32.Mouse]::mouse_event(0x0010, 0, 0, 0, 0) # RIGHTUP
72
+ `;
73
+ }
74
+ else if (action === 'drag' && x !== undefined && y !== undefined && endX !== undefined && endY !== undefined) {
75
+ script = `
76
+ Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern void mouse_event(int flags, int dx, int dy, int data, int extra);' -Name Mouse -Namespace Win32
77
+ [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${x}, ${y})
78
+ [Win32.Mouse]::mouse_event(0x0002, 0, 0, 0, 0)
79
+ Start-Sleep -Milliseconds 100
80
+ [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${endX}, ${endY})
81
+ Start-Sleep -Milliseconds 100
82
+ [Win32.Mouse]::mouse_event(0x0004, 0, 0, 0, 0)
83
+ `;
84
+ }
85
+ else if (action === 'scroll') {
86
+ const amount = scrollAmount ?? 120;
87
+ script = `
88
+ Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern void mouse_event(int flags, int dx, int dy, int data, int extra);' -Name Mouse -Namespace Win32
89
+ [Win32.Mouse]::mouse_event(0x0800, 0, 0, ${amount}, 0) # WHEEL
90
+ `;
91
+ }
92
+ if (script) {
93
+ await execFileAsync('powershell.exe', ['-NoProfile', '-Command', `Add-Type -AssemblyName System.Windows.Forms; ${script}`], { windowsHide: true, timeout: 10000 });
94
+ }
95
+ }
96
+ else if (process.platform === 'darwin') {
97
+ if (x !== undefined && y !== undefined) {
98
+ await execFileAsync('osascript', ['-e', `tell application "System Events" to click at {${x}, ${y}}`], { timeout: 10000 });
99
+ }
100
+ }
101
+ else {
102
+ if (await commandExists('xdotool')) {
103
+ let args = [];
104
+ if (action === 'move' && x !== undefined && y !== undefined) {
105
+ args = ['mousemove', String(x), String(y)];
106
+ }
107
+ else if (action === 'click') {
108
+ if (x !== undefined && y !== undefined) {
109
+ args = ['mousemove', String(x), String(y), 'click', '1'];
110
+ }
111
+ else {
112
+ args = ['click', '1'];
113
+ }
114
+ }
115
+ else if (action === 'double-click') {
116
+ if (x !== undefined && y !== undefined) {
117
+ args = ['mousemove', String(x), String(y), 'click', '--repeat', '2', '1'];
118
+ }
119
+ else {
120
+ args = ['click', '--repeat', '2', '1'];
121
+ }
122
+ }
123
+ else if (action === 'right-click') {
124
+ if (x !== undefined && y !== undefined) {
125
+ args = ['mousemove', String(x), String(y), 'click', '3'];
126
+ }
127
+ else {
128
+ args = ['click', '3'];
129
+ }
130
+ }
131
+ else if (action === 'drag' && x !== undefined && y !== undefined && endX !== undefined && endY !== undefined) {
132
+ args = ['mousemove', String(x), String(y), 'mousedown', '1', 'mousemove', String(endX), String(endY), 'mouseup', '1'];
133
+ }
134
+ else if (action === 'scroll') {
135
+ const btn = (scrollAmount ?? 120) > 0 ? '4' : '5';
136
+ args = ['click', btn];
137
+ }
138
+ if (args.length > 0) {
139
+ await execFileAsync('xdotool', args, { timeout: 10000 });
140
+ }
141
+ }
142
+ else {
143
+ throw new Error('xdotool is required for mouse simulation on Linux.');
144
+ }
145
+ }
146
+ }
147
+ async function showNotification(title, message) {
148
+ if (process.platform === 'win32') {
149
+ const cleanTitle = safeShellText(title);
150
+ const cleanMsg = safeShellText(message);
151
+ const script = `
152
+ [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
153
+ [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
154
+ $xml = New-Object Windows.Data.Xml.Dom.XmlDocument
155
+ $template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)
156
+ $textNodes = $template.GetElementsByTagName("text")
157
+ $textNodes.Item(0).AppendChild($template.CreateTextNode("${cleanTitle}")) | Out-Null
158
+ $textNodes.Item(1).AppendChild($template.CreateTextNode("${cleanMsg}")) | Out-Null
159
+ $toast = New-Object Windows.UI.Notifications.ToastNotification $template
160
+ $notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("ZilMate")
161
+ $notifier.Show($toast)
162
+ `;
163
+ await execFileAsync('powershell.exe', ['-NoProfile', '-Command', script], { windowsHide: true, timeout: 5000 });
164
+ }
165
+ else if (process.platform === 'darwin') {
166
+ const script = `display notification "${safeShellText(message)}" with title "${safeShellText(title)}"`;
167
+ await execFileAsync('osascript', ['-e', script], { timeout: 5000 });
168
+ }
169
+ else {
170
+ if (await commandExists('notify-send')) {
171
+ await execFileAsync('notify-send', [title, message], { timeout: 5000 });
172
+ }
173
+ }
174
+ }
175
+ async function listAudioDevices() {
176
+ try {
177
+ if (process.platform === 'win32') {
178
+ const result = await execFileAsync('ffmpeg', ['-hide_banner', '-list_devices', 'true', '-f', 'dshow', '-i', 'dummy'], { timeout: 5000 });
179
+ const output = `${result.stdout}\n${result.stderr}`;
180
+ const names = [...output.matchAll(/"([^"]+)"\s+\(audio\)/gi)].map((match) => match[1]).filter(Boolean);
181
+ return names;
182
+ }
183
+ if (process.platform === 'darwin') {
184
+ const result = await execFileAsync('ffmpeg', ['-hide_banner', '-f', 'avfoundation', '-list_devices', 'true', '-i', ''], { timeout: 5000 });
185
+ const output = `${result.stdout}\n${result.stderr}`;
186
+ const names = [...output.matchAll(/\[(\d+)\]\s+(.+)/g)].map((match) => match[2].trim());
187
+ return names;
188
+ }
189
+ return [];
190
+ }
191
+ catch (error) {
192
+ const output = error && typeof error === 'object' && 'stderr' in error ? String(error.stderr || '') : '';
193
+ if (process.platform === 'win32') {
194
+ return [...output.matchAll(/"([^"]+)"\s+\(audio\)/gi)].map((match) => match[1]).filter(Boolean);
195
+ }
196
+ if (process.platform === 'darwin') {
197
+ return [...output.matchAll(/\[(\d+)\]\s+(.+)/g)].map((match) => match[2].trim());
198
+ }
199
+ return [];
200
+ }
201
+ }
202
+ async function recordAudio(durationSeconds) {
203
+ const outputDir = path.join(path.dirname(screenshotDir), 'audio');
204
+ await mkdir(outputDir, { recursive: true });
205
+ const target = path.join(outputDir, `zilmate-audio-${Date.now()}.wav`);
206
+ if (!(await commandExists('ffmpeg'))) {
207
+ throw new Error('Audio recording requires ffmpeg on PATH.');
208
+ }
209
+ let inputDevice = '';
210
+ let format = '';
211
+ if (process.platform === 'win32') {
212
+ format = 'dshow';
213
+ const audios = await listAudioDevices();
214
+ if (audios.length > 0) {
215
+ inputDevice = `audio=${audios[0]}`;
216
+ }
217
+ else {
218
+ inputDevice = 'audio=default';
219
+ }
220
+ }
221
+ else if (process.platform === 'darwin') {
222
+ format = 'avfoundation';
223
+ inputDevice = 'none:0';
224
+ }
225
+ else {
226
+ format = 'alsa';
227
+ inputDevice = 'default';
228
+ }
229
+ const args = ['-y', '-f', format, '-i', inputDevice, '-t', String(durationSeconds), target];
230
+ await execFileAsync('ffmpeg', args, { timeout: (durationSeconds + 15) * 1000, maxBuffer: 2_000_000 });
231
+ return target;
232
+ }
233
+ async function getActiveWindow() {
234
+ if (process.platform === 'win32') {
235
+ const script = `
236
+ $sig = @'
237
+ [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
238
+ [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count);
239
+ [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
240
+ '@
241
+ Add-Type -MemberDefinition $sig -Name Window -Namespace Win32
242
+ $hwnd = [Win32.Window]::GetForegroundWindow()
243
+ if ($hwnd -ne [IntPtr]::Zero) {
244
+ $title = New-Object System.Text.StringBuilder 256
245
+ [Win32.Window]::GetWindowText($hwnd, $title, 256) | Out-Null
246
+ $pid = 0
247
+ [Win32.Window]::GetWindowThreadProcessId($hwnd, [ref]$pid) | Out-Null
248
+ $process = Get-Process -Id $pid -ErrorAction SilentlyContinue
249
+ @{
250
+ title = $title.ToString()
251
+ process = $process.ProcessName
252
+ pid = $pid
253
+ } | ConvertTo-Json
254
+ } else {
255
+ "{}"
256
+ }
257
+ `;
258
+ const { stdout } = await execFileAsync('powershell.exe', ['-NoProfile', '-Command', script], { windowsHide: true, timeout: 5000 });
259
+ try {
260
+ return JSON.parse(stdout.trim());
261
+ }
262
+ catch {
263
+ return {};
264
+ }
265
+ }
266
+ else if (process.platform === 'darwin') {
267
+ const script = `
268
+ tell application "System Events"
269
+ set frontApp to first application process whose frontmost is true
270
+ set appName to name of frontApp
271
+ tell frontApp
272
+ try
273
+ set windowTitle to name of first window
274
+ on error
275
+ set windowTitle to ""
276
+ end try
277
+ end tell
278
+ return appName & "|||" & windowTitle
279
+ end tell
280
+ `;
281
+ const { stdout } = await execFileAsync('osascript', ['-e', script], { timeout: 5000 });
282
+ const parts = stdout.trim().split('|||');
283
+ return {
284
+ process: parts[0] || 'Unknown',
285
+ title: parts[1] || 'Unknown',
286
+ };
287
+ }
288
+ else {
289
+ if (await commandExists('xdotool')) {
290
+ try {
291
+ const { stdout: windowId } = await execFileAsync('xdotool', ['getactivewindow'], { timeout: 5000 });
292
+ const { stdout: windowName } = await execFileAsync('xdotool', ['getwindowname', windowId.trim()], { timeout: 5000 });
293
+ return {
294
+ title: windowName.trim(),
295
+ process: 'Unknown',
296
+ };
297
+ }
298
+ catch {
299
+ return {};
300
+ }
301
+ }
302
+ return {};
303
+ }
304
+ }
305
+ async function controlVolume(action, level) {
306
+ if (process.platform === 'win32') {
307
+ if (action === 'media-play-pause') {
308
+ const ps = `Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait([char]179)`;
309
+ await execFileAsync('powershell.exe', ['-NoProfile', '-Command', ps], { windowsHide: true, timeout: 5000 });
310
+ return { success: true, action };
311
+ }
312
+ if (action === 'media-next') {
313
+ const ps = `Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait([char]176)`;
314
+ await execFileAsync('powershell.exe', ['-NoProfile', '-Command', ps], { windowsHide: true, timeout: 5000 });
315
+ return { success: true, action };
316
+ }
317
+ if (action === 'media-prev') {
318
+ const ps = `Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait([char]177)`;
319
+ await execFileAsync('powershell.exe', ['-NoProfile', '-Command', ps], { windowsHide: true, timeout: 5000 });
320
+ return { success: true, action };
321
+ }
322
+ if (action === 'mute') {
323
+ const ps = `Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait([char]173)`;
324
+ await execFileAsync('powershell.exe', ['-NoProfile', '-Command', ps], { windowsHide: true, timeout: 5000 });
325
+ return { success: true, action };
326
+ }
327
+ if (action === 'unmute') {
328
+ const ps = `Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait([char]173)`;
329
+ await execFileAsync('powershell.exe', ['-NoProfile', '-Command', ps], { windowsHide: true, timeout: 5000 });
330
+ return { success: true, action };
331
+ }
332
+ if (action === 'set' && level !== undefined) {
333
+ const script = `
334
+ $wsh = New-Object -ComObject WScript.Shell
335
+ for ($i = 0; $i -lt 50; $i++) { $wsh.SendKeys([char]174) }
336
+ $steps = [Math]::Floor(${level} / 2)
337
+ for ($i = 0; $i -lt $steps; $i++) { $wsh.SendKeys([char]175) }
338
+ `;
339
+ await execFileAsync('powershell.exe', ['-NoProfile', '-Command', script], { windowsHide: true, timeout: 10000 });
340
+ return { success: true, action, level };
341
+ }
342
+ return { success: false, error: 'Action not supported or requires arguments' };
343
+ }
344
+ else if (process.platform === 'darwin') {
345
+ if (action === 'set' && level !== undefined) {
346
+ await execFileAsync('osascript', ['-e', `set volume output volume ${level}`], { timeout: 5000 });
347
+ return { success: true, action, level };
348
+ }
349
+ if (action === 'mute') {
350
+ await execFileAsync('osascript', ['-e', 'set volume with output muted'], { timeout: 5000 });
351
+ return { success: true, action };
352
+ }
353
+ if (action === 'unmute') {
354
+ await execFileAsync('osascript', ['-e', 'set volume without output muted'], { timeout: 5000 });
355
+ return { success: true, action };
356
+ }
357
+ if (action === 'get') {
358
+ const { stdout } = await execFileAsync('osascript', ['-e', 'output volume of (get volume settings)'], { timeout: 5000 });
359
+ return { success: true, level: parseInt(stdout.trim(), 10) };
360
+ }
361
+ if (action === 'media-play-pause') {
362
+ await execFileAsync('osascript', ['-e', 'tell application "System Events" to key code 16'], { timeout: 5000 });
363
+ return { success: true, action };
364
+ }
365
+ return { success: false, error: 'Action not supported or requires arguments' };
366
+ }
367
+ else {
368
+ if (await commandExists('amixer')) {
369
+ if (action === 'set' && level !== undefined) {
370
+ await execFileAsync('amixer', ['set', 'Master', `${level}%`], { timeout: 5000 });
371
+ return { success: true, action, level };
372
+ }
373
+ if (action === 'mute') {
374
+ await execFileAsync('amixer', ['set', 'Master', 'mute'], { timeout: 5000 });
375
+ return { success: true, action };
376
+ }
377
+ if (action === 'unmute') {
378
+ await execFileAsync('amixer', ['set', 'Master', 'unmute'], { timeout: 5000 });
379
+ return { success: true, action };
380
+ }
381
+ }
382
+ return { success: false, error: 'amixer is not available on Linux' };
383
+ }
384
+ }
41
385
  function cameraInstallHint() {
42
386
  if (process.platform === 'win32')
43
387
  return 'Install ffmpeg: winget install Gyan.FFmpeg';
@@ -606,5 +950,100 @@ export const desktopTools = {
606
950
  }
607
951
  },
608
952
  }),
953
+ simulateMouse: tool({
954
+ description: 'Simulate mouse movements, clicks, drags, or scrolls. Use for automating GUI interactions, clicking buttons, scrollable areas, etc.',
955
+ inputSchema: z.object({
956
+ action: z.enum(['click', 'double-click', 'right-click', 'move', 'drag', 'scroll']).describe('Mouse action to simulate'),
957
+ x: z.number().int().optional().describe('X coordinate (pixels) from the top-left of the primary screen'),
958
+ y: z.number().int().optional().describe('Y coordinate (pixels) from the top-left of the primary screen'),
959
+ endX: z.number().int().optional().describe('Ending X coordinate for drag action'),
960
+ endY: z.number().int().optional().describe('Ending Y coordinate for drag action'),
961
+ scrollAmount: z.number().int().optional().describe('Amount to scroll (default 120. Positive for scroll up, negative for scroll down)'),
962
+ }),
963
+ execute: async ({ action, x, y, endX, endY, scrollAmount }) => {
964
+ emitProgress({ type: 'tool:start', label: 'Simulating mouse action', detail: `${action} at (${x ?? 'current'}, ${y ?? 'current'})` });
965
+ try {
966
+ await simulateMouseAction(action, x, y, endX, endY, scrollAmount);
967
+ emitProgress({ type: 'tool:end', label: 'Mouse action simulated' });
968
+ return { success: true, action };
969
+ }
970
+ catch (error) {
971
+ emitProgress({ type: 'tool:error', label: 'Mouse action failed', detail: error.message });
972
+ return { success: false, error: error.message };
973
+ }
974
+ },
975
+ }),
976
+ displaySystemNotification: tool({
977
+ description: 'Display a native OS toast, banner, or alert notification with a custom title and message.',
978
+ inputSchema: z.object({
979
+ title: z.string().min(1).describe('The title of the notification'),
980
+ message: z.string().min(1).describe('The main body message of the notification'),
981
+ }),
982
+ execute: async ({ title, message }) => {
983
+ emitProgress({ type: 'tool:start', label: 'Displaying system notification', detail: title });
984
+ try {
985
+ await showNotification(title, message);
986
+ emitProgress({ type: 'tool:end', label: 'System notification displayed' });
987
+ return { success: true };
988
+ }
989
+ catch (error) {
990
+ emitProgress({ type: 'tool:error', label: 'Failed to display notification', detail: error.message });
991
+ return { success: false, error: error.message };
992
+ }
993
+ },
994
+ }),
995
+ recordAudioSnippet: tool({
996
+ description: 'Record an audio snippet from the microphone/audio input device as a WAV file. Requires ffmpeg.',
997
+ inputSchema: z.object({
998
+ durationSeconds: z.number().int().min(1).max(60).describe('Duration of the audio recording in seconds (max 60)'),
999
+ }),
1000
+ execute: async ({ durationSeconds }) => {
1001
+ emitProgress({ type: 'tool:start', label: 'Recording audio snippet', detail: `${durationSeconds}s` });
1002
+ try {
1003
+ const file = await recordAudio(durationSeconds);
1004
+ emitProgress({ type: 'tool:end', label: 'Audio snippet recorded', detail: file });
1005
+ return { success: true, file, durationSeconds };
1006
+ }
1007
+ catch (error) {
1008
+ emitProgress({ type: 'tool:error', label: 'Failed to record audio', detail: error.message });
1009
+ return { success: false, error: error.message };
1010
+ }
1011
+ },
1012
+ }),
1013
+ getActiveWindowContext: tool({
1014
+ description: 'Retrieve context of the active, foreground window, including application process name, window title, and process ID (PID) if available.',
1015
+ inputSchema: z.object({}),
1016
+ execute: async () => {
1017
+ emitProgress({ type: 'tool:start', label: 'Retrieving active window context' });
1018
+ try {
1019
+ const context = await getActiveWindow();
1020
+ emitProgress({ type: 'tool:end', label: 'Active window context retrieved', detail: context.title || context.process || 'Unknown' });
1021
+ return { success: true, ...context };
1022
+ }
1023
+ catch (error) {
1024
+ emitProgress({ type: 'tool:error', label: 'Failed to retrieve active window context', detail: error.message });
1025
+ return { success: false, error: error.message };
1026
+ }
1027
+ },
1028
+ }),
1029
+ controlSystemVolume: tool({
1030
+ description: 'Control system audio volume, mute status, or simulate media playback keys (play/pause, next, previous track).',
1031
+ inputSchema: z.object({
1032
+ action: z.enum(['set', 'mute', 'unmute', 'get', 'media-play-pause', 'media-next', 'media-prev']).describe('Volume or media key action to perform'),
1033
+ level: z.number().int().min(0).max(100).optional().describe('Volume percentage level (0 to 100), required only when action is "set"'),
1034
+ }),
1035
+ execute: async ({ action, level }) => {
1036
+ emitProgress({ type: 'tool:start', label: 'Controlling system volume/media', detail: action });
1037
+ try {
1038
+ const result = await controlVolume(action, level);
1039
+ emitProgress({ type: 'tool:end', label: 'System volume/media controlled' });
1040
+ return result;
1041
+ }
1042
+ catch (error) {
1043
+ emitProgress({ type: 'tool:error', label: 'Failed to control system volume/media', detail: error.message });
1044
+ return { success: false, error: error.message };
1045
+ }
1046
+ },
1047
+ }),
609
1048
  };
610
1049
  //# sourceMappingURL=desktop.tool.js.map