@skillful-agents/agent-computer 0.0.4 → 0.0.6

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 (50) hide show
  1. package/bin/ac-core-darwin-arm64 +0 -0
  2. package/bin/ac-core-darwin-x64 +0 -0
  3. package/bin/ac-core-win32-arm64.exe +0 -0
  4. package/bin/ac-core-win32-x64.exe +0 -0
  5. package/dist/src/platform/resolve.d.ts.map +1 -1
  6. package/dist/src/platform/resolve.js +5 -3
  7. package/dist/src/platform/resolve.js.map +1 -1
  8. package/dist-cjs/bin/ac.js +127 -0
  9. package/dist-cjs/package.json +1 -0
  10. package/dist-cjs/src/bridge.js +693 -0
  11. package/dist-cjs/src/cdp/ax-tree.js +162 -0
  12. package/dist-cjs/src/cdp/bounds.js +66 -0
  13. package/dist-cjs/src/cdp/client.js +272 -0
  14. package/dist-cjs/src/cdp/connection.js +285 -0
  15. package/dist-cjs/src/cdp/diff.js +55 -0
  16. package/dist-cjs/src/cdp/discovery.js +91 -0
  17. package/dist-cjs/src/cdp/index.js +27 -0
  18. package/dist-cjs/src/cdp/interactions.js +301 -0
  19. package/dist-cjs/src/cdp/port-manager.js +68 -0
  20. package/dist-cjs/src/cdp/role-map.js +102 -0
  21. package/dist-cjs/src/cdp/types.js +2 -0
  22. package/dist-cjs/src/cli/commands/apps.js +63 -0
  23. package/dist-cjs/src/cli/commands/batch.js +37 -0
  24. package/dist-cjs/src/cli/commands/click.js +61 -0
  25. package/dist-cjs/src/cli/commands/clipboard.js +31 -0
  26. package/dist-cjs/src/cli/commands/dialog.js +45 -0
  27. package/dist-cjs/src/cli/commands/drag.js +26 -0
  28. package/dist-cjs/src/cli/commands/find.js +99 -0
  29. package/dist-cjs/src/cli/commands/menu.js +36 -0
  30. package/dist-cjs/src/cli/commands/screenshot.js +27 -0
  31. package/dist-cjs/src/cli/commands/scroll.js +77 -0
  32. package/dist-cjs/src/cli/commands/session.js +27 -0
  33. package/dist-cjs/src/cli/commands/snapshot.js +24 -0
  34. package/dist-cjs/src/cli/commands/type.js +69 -0
  35. package/dist-cjs/src/cli/commands/windowmgmt.js +62 -0
  36. package/dist-cjs/src/cli/commands/windows.js +10 -0
  37. package/dist-cjs/src/cli/commands.js +215 -0
  38. package/dist-cjs/src/cli/output.js +253 -0
  39. package/dist-cjs/src/cli/parser.js +128 -0
  40. package/dist-cjs/src/config.js +79 -0
  41. package/dist-cjs/src/daemon.js +183 -0
  42. package/dist-cjs/src/errors.js +118 -0
  43. package/dist-cjs/src/index.js +24 -0
  44. package/dist-cjs/src/platform/index.js +16 -0
  45. package/dist-cjs/src/platform/resolve.js +71 -0
  46. package/dist-cjs/src/refs.js +91 -0
  47. package/dist-cjs/src/sdk.js +288 -0
  48. package/dist-cjs/src/types.js +11 -0
  49. package/package.json +4 -2
  50. package/scripts/fix-cjs-resolve.js +27 -0
@@ -0,0 +1,301 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CDPInteractions = void 0;
4
+ // Modifier flag values for CDP Input events
5
+ const MODIFIER_FLAGS = {
6
+ alt: 1,
7
+ ctrl: 2,
8
+ meta: 4, // Cmd on Mac
9
+ shift: 8,
10
+ };
11
+ // Key name mapping for special keys
12
+ const KEY_MAP = {
13
+ enter: { key: 'Enter', code: 'Enter', keyCode: 13 },
14
+ return: { key: 'Enter', code: 'Enter', keyCode: 13 },
15
+ tab: { key: 'Tab', code: 'Tab', keyCode: 9 },
16
+ escape: { key: 'Escape', code: 'Escape', keyCode: 27 },
17
+ esc: { key: 'Escape', code: 'Escape', keyCode: 27 },
18
+ backspace: { key: 'Backspace', code: 'Backspace', keyCode: 8 },
19
+ delete: { key: 'Delete', code: 'Delete', keyCode: 46 },
20
+ space: { key: ' ', code: 'Space', keyCode: 32 },
21
+ up: { key: 'ArrowUp', code: 'ArrowUp', keyCode: 38 },
22
+ down: { key: 'ArrowDown', code: 'ArrowDown', keyCode: 40 },
23
+ left: { key: 'ArrowLeft', code: 'ArrowLeft', keyCode: 37 },
24
+ right: { key: 'ArrowRight', code: 'ArrowRight', keyCode: 39 },
25
+ home: { key: 'Home', code: 'Home', keyCode: 36 },
26
+ end: { key: 'End', code: 'End', keyCode: 35 },
27
+ pageup: { key: 'PageUp', code: 'PageUp', keyCode: 33 },
28
+ pagedown: { key: 'PageDown', code: 'PageDown', keyCode: 34 },
29
+ // Letters a-z will be handled dynamically
30
+ };
31
+ class CDPInteractions {
32
+ connection;
33
+ constructor(connection) {
34
+ this.connection = connection;
35
+ }
36
+ /** Click at element center (CSS viewport coords). Options: right, double, modifiers */
37
+ async click(backendDOMNodeId, cssBounds, options = {}) {
38
+ const x = cssBounds[0] + cssBounds[2] / 2;
39
+ const y = cssBounds[1] + cssBounds[3] / 2;
40
+ await this.clickAt(x, y, options);
41
+ }
42
+ /** Click at specific CSS viewport coords */
43
+ async clickAt(x, y, options = {}) {
44
+ const button = options.right ? 'right' : 'left';
45
+ const clickCount = options.double ? 2 : (options.count ?? 1);
46
+ const modifiers = this.computeModifiers(options.modifiers);
47
+ // Move mouse first
48
+ await this.connection.send('Input.dispatchMouseEvent', {
49
+ type: 'mouseMoved',
50
+ x, y,
51
+ modifiers,
52
+ });
53
+ // For double click, send two full click sequences
54
+ for (let i = 0; i < clickCount; i++) {
55
+ await this.connection.send('Input.dispatchMouseEvent', {
56
+ type: 'mousePressed',
57
+ x, y,
58
+ button,
59
+ clickCount: i + 1,
60
+ modifiers,
61
+ });
62
+ await this.connection.send('Input.dispatchMouseEvent', {
63
+ type: 'mouseReleased',
64
+ x, y,
65
+ button,
66
+ clickCount: i + 1,
67
+ modifiers,
68
+ });
69
+ }
70
+ }
71
+ /** Hover over element (move mouse to center) */
72
+ async hover(cssBounds) {
73
+ const x = cssBounds[0] + cssBounds[2] / 2;
74
+ const y = cssBounds[1] + cssBounds[3] / 2;
75
+ await this.connection.send('Input.dispatchMouseEvent', {
76
+ type: 'mouseMoved',
77
+ x, y,
78
+ });
79
+ }
80
+ /** Focus an element by backendNodeId */
81
+ async focus(backendDOMNodeId) {
82
+ await this.connection.send('DOM.focus', { backendNodeId: backendDOMNodeId });
83
+ }
84
+ /** Insert text at current focus (fast, no key events) */
85
+ async type(text) {
86
+ await this.connection.send('Input.insertText', { text });
87
+ }
88
+ /** Type with per-character key events and optional delay */
89
+ async typeWithDelay(text, delay) {
90
+ for (const char of text) {
91
+ await this.connection.send('Input.dispatchKeyEvent', {
92
+ type: 'keyDown',
93
+ key: char,
94
+ text: char,
95
+ });
96
+ await this.connection.send('Input.dispatchKeyEvent', {
97
+ type: 'keyUp',
98
+ key: char,
99
+ });
100
+ if (delay > 0) {
101
+ await sleep(delay);
102
+ }
103
+ }
104
+ }
105
+ /** Fill: focus element, select all, insert text. Fallback: set .value via Runtime */
106
+ async fill(backendDOMNodeId, text) {
107
+ // Focus the element
108
+ await this.focus(backendDOMNodeId);
109
+ await sleep(50);
110
+ // Select all (Cmd+A on Mac)
111
+ await this.key('cmd+a');
112
+ await sleep(50);
113
+ // Insert text (replaces selection)
114
+ await this.type(text);
115
+ }
116
+ /** Press a key combination (e.g., "cmd+a", "shift+enter", "ctrl+c") */
117
+ async key(combo, repeat) {
118
+ const times = repeat ?? 1;
119
+ const { modifiers, keyInfo } = this.parseCombo(combo);
120
+ for (let i = 0; i < times; i++) {
121
+ // Press modifier keys
122
+ for (const mod of modifiers) {
123
+ await this.connection.send('Input.dispatchKeyEvent', {
124
+ type: 'rawKeyDown',
125
+ key: this.modifierKeyName(mod),
126
+ modifiers: this.computeModifiers(modifiers),
127
+ });
128
+ }
129
+ // Press the main key
130
+ const modifierFlags = this.computeModifiers(modifiers);
131
+ await this.connection.send('Input.dispatchKeyEvent', {
132
+ type: 'rawKeyDown',
133
+ key: keyInfo.key,
134
+ code: keyInfo.code,
135
+ windowsVirtualKeyCode: keyInfo.keyCode,
136
+ modifiers: modifierFlags,
137
+ });
138
+ // If it's a printable character with no modifiers (or just shift), send char event
139
+ if (keyInfo.key.length === 1 && modifiers.every(m => m === 'shift')) {
140
+ await this.connection.send('Input.dispatchKeyEvent', {
141
+ type: 'char',
142
+ key: keyInfo.key,
143
+ text: keyInfo.key,
144
+ modifiers: modifierFlags,
145
+ });
146
+ }
147
+ await this.connection.send('Input.dispatchKeyEvent', {
148
+ type: 'keyUp',
149
+ key: keyInfo.key,
150
+ code: keyInfo.code,
151
+ windowsVirtualKeyCode: keyInfo.keyCode,
152
+ modifiers: modifierFlags,
153
+ });
154
+ // Release modifier keys (reverse order)
155
+ for (const mod of [...modifiers].reverse()) {
156
+ await this.connection.send('Input.dispatchKeyEvent', {
157
+ type: 'keyUp',
158
+ key: this.modifierKeyName(mod),
159
+ modifiers: 0,
160
+ });
161
+ }
162
+ if (i < times - 1)
163
+ await sleep(50);
164
+ }
165
+ }
166
+ /** Scroll using mouseWheel events */
167
+ async scroll(direction, amount = 3, atX, atY) {
168
+ const x = atX ?? 300; // center of typical window
169
+ const y = atY ?? 250;
170
+ const pixelAmount = amount * 100; // Each "amount" unit = 100px
171
+ let deltaX = 0;
172
+ let deltaY = 0;
173
+ switch (direction) {
174
+ case 'up':
175
+ deltaY = -pixelAmount;
176
+ break;
177
+ case 'down':
178
+ deltaY = pixelAmount;
179
+ break;
180
+ case 'left':
181
+ deltaX = -pixelAmount;
182
+ break;
183
+ case 'right':
184
+ deltaX = pixelAmount;
185
+ break;
186
+ }
187
+ await this.connection.send('Input.dispatchMouseEvent', {
188
+ type: 'mouseWheel',
189
+ x, y,
190
+ deltaX,
191
+ deltaY,
192
+ });
193
+ }
194
+ /** Select a value in a <select> element */
195
+ async select(backendDOMNodeId, value) {
196
+ // Resolve to a remote object first
197
+ const { object } = await this.connection.send('DOM.resolveNode', {
198
+ backendNodeId: backendDOMNodeId,
199
+ });
200
+ await this.connection.send('Runtime.callFunctionOn', {
201
+ objectId: object.objectId,
202
+ functionDeclaration: `function(val) {
203
+ for (let i = 0; i < this.options.length; i++) {
204
+ if (this.options[i].value === val || this.options[i].text === val) {
205
+ this.selectedIndex = i;
206
+ this.dispatchEvent(new Event('change', { bubbles: true }));
207
+ return true;
208
+ }
209
+ }
210
+ return false;
211
+ }`,
212
+ arguments: [{ value }],
213
+ });
214
+ }
215
+ /** Check a checkbox (click if not already checked) */
216
+ async check(backendDOMNodeId, cssBounds) {
217
+ const checked = await this.getCheckedState(backendDOMNodeId);
218
+ if (!checked) {
219
+ await this.click(backendDOMNodeId, cssBounds);
220
+ }
221
+ }
222
+ /** Uncheck a checkbox (click if currently checked) */
223
+ async uncheck(backendDOMNodeId, cssBounds) {
224
+ const checked = await this.getCheckedState(backendDOMNodeId);
225
+ if (checked) {
226
+ await this.click(backendDOMNodeId, cssBounds);
227
+ }
228
+ }
229
+ /** Get .checked state of an element via Runtime */
230
+ async getCheckedState(backendDOMNodeId) {
231
+ const { object } = await this.connection.send('DOM.resolveNode', {
232
+ backendNodeId: backendDOMNodeId,
233
+ });
234
+ const result = await this.connection.send('Runtime.callFunctionOn', {
235
+ objectId: object.objectId,
236
+ functionDeclaration: 'function() { return this.checked; }',
237
+ returnByValue: true,
238
+ });
239
+ return result.result.value === true;
240
+ }
241
+ /** Parse key combo string like "cmd+shift+a" */
242
+ parseCombo(combo) {
243
+ const parts = combo.toLowerCase().split('+');
244
+ const modifiers = [];
245
+ let mainKey = '';
246
+ for (const part of parts) {
247
+ const p = part.trim();
248
+ if (p === 'cmd' || p === 'command' || p === 'meta') {
249
+ modifiers.push('meta');
250
+ }
251
+ else if (p === 'ctrl' || p === 'control') {
252
+ modifiers.push('ctrl');
253
+ }
254
+ else if (p === 'alt' || p === 'option' || p === 'opt') {
255
+ modifiers.push('alt');
256
+ }
257
+ else if (p === 'shift') {
258
+ modifiers.push('shift');
259
+ }
260
+ else {
261
+ mainKey = p;
262
+ }
263
+ }
264
+ const keyInfo = KEY_MAP[mainKey] ?? this.letterKeyInfo(mainKey);
265
+ return { modifiers, keyInfo };
266
+ }
267
+ letterKeyInfo(key) {
268
+ if (key.length === 1) {
269
+ const upper = key.toUpperCase();
270
+ return {
271
+ key: key,
272
+ code: `Key${upper}`,
273
+ keyCode: upper.charCodeAt(0),
274
+ };
275
+ }
276
+ // Unknown key - pass through
277
+ return { key, code: key, keyCode: 0 };
278
+ }
279
+ modifierKeyName(mod) {
280
+ switch (mod) {
281
+ case 'meta': return 'Meta';
282
+ case 'ctrl': return 'Control';
283
+ case 'alt': return 'Alt';
284
+ case 'shift': return 'Shift';
285
+ default: return mod;
286
+ }
287
+ }
288
+ computeModifiers(mods) {
289
+ if (!mods)
290
+ return 0;
291
+ let flags = 0;
292
+ for (const mod of mods) {
293
+ flags |= MODIFIER_FLAGS[mod] ?? 0;
294
+ }
295
+ return flags;
296
+ }
297
+ }
298
+ exports.CDPInteractions = CDPInteractions;
299
+ function sleep(ms) {
300
+ return new Promise(resolve => setTimeout(resolve, ms));
301
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.findFreePort = findFreePort;
37
+ const net = __importStar(require("net"));
38
+ const PORT_RANGE_START = 19200;
39
+ const PORT_RANGE_END = 19299;
40
+ /** Find a free port in the CDP range by probing for one not in use. */
41
+ async function findFreePort() {
42
+ for (let port = PORT_RANGE_START; port <= PORT_RANGE_END; port++) {
43
+ if (await isPortAvailable(port)) {
44
+ return port;
45
+ }
46
+ }
47
+ throw new Error(`No available CDP ports in range ${PORT_RANGE_START}-${PORT_RANGE_END}`);
48
+ }
49
+ /** Check if a port is available by attempting a TCP connection */
50
+ function isPortAvailable(port) {
51
+ return new Promise((resolve) => {
52
+ const socket = new net.Socket();
53
+ socket.setTimeout(500);
54
+ socket.on('connect', () => {
55
+ socket.destroy();
56
+ resolve(false); // Port is in use
57
+ });
58
+ socket.on('timeout', () => {
59
+ socket.destroy();
60
+ resolve(true); // Timeout = nothing listening = available
61
+ });
62
+ socket.on('error', () => {
63
+ socket.destroy();
64
+ resolve(true); // Connection refused = available
65
+ });
66
+ socket.connect(port, '127.0.0.1');
67
+ });
68
+ }
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ // Maps CDP ARIA roles to normalized roles used by the agent-computer Element format.
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.INTERACTIVE_ROLES = void 0;
5
+ exports.mapCDPRole = mapCDPRole;
6
+ const CDP_ROLE_MAP = {
7
+ // Interactive controls
8
+ button: 'button',
9
+ textbox: 'textfield',
10
+ searchbox: 'textfield',
11
+ textfield: 'textfield',
12
+ link: 'link',
13
+ checkbox: 'checkbox',
14
+ radio: 'radio',
15
+ slider: 'slider',
16
+ spinbutton: 'slider',
17
+ combobox: 'dropdown',
18
+ listbox: 'dropdown',
19
+ popupbutton: 'dropdown',
20
+ // Media
21
+ img: 'image',
22
+ image: 'image',
23
+ // Text content
24
+ heading: 'text',
25
+ StaticText: 'text',
26
+ LabelText: 'text',
27
+ paragraph: 'text',
28
+ status: 'text',
29
+ // Tabs
30
+ tab: 'tab',
31
+ tablist: 'tabgroup',
32
+ tabpanel: 'group',
33
+ // Menus
34
+ menuitem: 'menuitem',
35
+ menu: 'group',
36
+ menubar: 'group',
37
+ // Tables
38
+ table: 'table',
39
+ grid: 'table',
40
+ row: 'row',
41
+ cell: 'row',
42
+ gridcell: 'row',
43
+ columnheader: 'row',
44
+ rowheader: 'row',
45
+ // Trees
46
+ tree: 'treeview',
47
+ treeitem: 'menuitem',
48
+ // Misc widgets
49
+ scrollbar: 'scrollarea',
50
+ progressbar: 'progress',
51
+ // Generic / presentational
52
+ generic: 'generic',
53
+ none: 'generic',
54
+ presentation: 'generic',
55
+ separator: 'generic',
56
+ // Document / web areas
57
+ WebArea: 'webarea',
58
+ RootWebArea: 'webarea',
59
+ document: 'webarea',
60
+ // Landmark & structural → group
61
+ navigation: 'group',
62
+ region: 'group',
63
+ main: 'group',
64
+ form: 'group',
65
+ section: 'group',
66
+ article: 'group',
67
+ banner: 'group',
68
+ complementary: 'group',
69
+ contentinfo: 'group',
70
+ list: 'group',
71
+ listitem: 'group',
72
+ group: 'group',
73
+ toolbar: 'group',
74
+ dialog: 'group',
75
+ alertdialog: 'group',
76
+ alert: 'group',
77
+ };
78
+ /** Map a CDP ARIA role string to a normalized role. Unknown roles become 'generic'. */
79
+ function mapCDPRole(cdpRole) {
80
+ return CDP_ROLE_MAP[cdpRole] ?? 'generic';
81
+ }
82
+ /**
83
+ * CDP roles considered interactive — used to filter the AX tree in interactive mode.
84
+ * These are CDP/ARIA role strings (keys in CDP_ROLE_MAP), not normalized roles.
85
+ */
86
+ exports.INTERACTIVE_ROLES = new Set([
87
+ 'button',
88
+ 'textbox',
89
+ 'searchbox',
90
+ 'textfield',
91
+ 'link',
92
+ 'checkbox',
93
+ 'radio',
94
+ 'slider',
95
+ 'spinbutton',
96
+ 'combobox',
97
+ 'listbox',
98
+ 'popupbutton',
99
+ 'tab',
100
+ 'menuitem',
101
+ 'treeitem',
102
+ ]);
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const commands_js_1 = require("../commands.js");
4
+ (0, commands_js_1.registerCommand)('apps', async (args, bridge) => {
5
+ const params = {};
6
+ if (args.flags['running'])
7
+ params.running = true;
8
+ const result = await bridge.send('apps', params);
9
+ return { data: result, exitCode: 0 };
10
+ });
11
+ (0, commands_js_1.registerCommand)('launch', async (args, bridge) => {
12
+ const name = args.positional[0];
13
+ if (!name) {
14
+ return { data: { error: 'Usage: agent-computer launch <name> [--wait] [--background]' }, exitCode: 1 };
15
+ }
16
+ const params = {
17
+ name,
18
+ wait: args.flags['wait'] === true,
19
+ background: args.flags['background'] === true,
20
+ };
21
+ if (args.flags['open']) {
22
+ params.open = args.flags['open'];
23
+ }
24
+ const result = await bridge.send('launch', params);
25
+ return { data: result, exitCode: 0 };
26
+ });
27
+ (0, commands_js_1.registerCommand)('relaunch', async (args, bridge) => {
28
+ const name = args.positional[0];
29
+ if (!name) {
30
+ return { data: { error: 'Usage: agent-computer relaunch <name>' }, exitCode: 1 };
31
+ }
32
+ const result = await bridge.send('relaunch', { name });
33
+ return { data: result, exitCode: 0 };
34
+ });
35
+ (0, commands_js_1.registerCommand)('quit', async (args, bridge) => {
36
+ const name = args.positional[0];
37
+ if (!name) {
38
+ return { data: { error: 'Usage: agent-computer quit <name> [--force]' }, exitCode: 1 };
39
+ }
40
+ const result = await bridge.send('quit', { name, force: args.flags['force'] === true });
41
+ return { data: result, exitCode: 0 };
42
+ });
43
+ (0, commands_js_1.registerCommand)('hide', async (args, bridge) => {
44
+ const name = args.positional[0];
45
+ if (!name)
46
+ return { data: { error: 'Usage: agent-computer hide <name>' }, exitCode: 1 };
47
+ const result = await bridge.send('hide', { name });
48
+ return { data: result, exitCode: 0 };
49
+ });
50
+ (0, commands_js_1.registerCommand)('unhide', async (args, bridge) => {
51
+ const name = args.positional[0];
52
+ if (!name)
53
+ return { data: { error: 'Usage: agent-computer unhide <name>' }, exitCode: 1 };
54
+ const result = await bridge.send('unhide', { name });
55
+ return { data: result, exitCode: 0 };
56
+ });
57
+ (0, commands_js_1.registerCommand)('switch', async (args, bridge) => {
58
+ const name = args.positional[0];
59
+ if (!name)
60
+ return { data: { error: 'Usage: agent-computer switch <name>' }, exitCode: 1 };
61
+ const result = await bridge.send('switch', { name });
62
+ return { data: result, exitCode: 0 };
63
+ });
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const commands_js_1 = require("../commands.js");
4
+ (0, commands_js_1.registerCommand)('batch', async (args, bridge) => {
5
+ const jsonStr = args.positional[0] || args.subcommand;
6
+ if (!jsonStr) {
7
+ return { data: { error: 'Usage: agent-computer batch \'[["method", ...args], ...]\'' }, exitCode: 1 };
8
+ }
9
+ let commands;
10
+ try {
11
+ commands = JSON.parse(jsonStr);
12
+ if (!Array.isArray(commands))
13
+ throw new Error('not array');
14
+ }
15
+ catch {
16
+ return { data: { error: 'Invalid JSON. Expected array of command arrays.' }, exitCode: 1 };
17
+ }
18
+ const params = { commands };
19
+ if (args.flags['no-stop-on-error'])
20
+ params.stop_on_error = false;
21
+ const result = await bridge.send('batch', params);
22
+ return { data: result, exitCode: 0 };
23
+ });
24
+ (0, commands_js_1.registerCommand)('changed', async (args, bridge) => {
25
+ const params = {};
26
+ if (args.flags['app'])
27
+ params.app = args.flags['app'];
28
+ const result = await bridge.send('changed', params);
29
+ return { data: result, exitCode: 0 };
30
+ });
31
+ (0, commands_js_1.registerCommand)('diff', async (args, bridge) => {
32
+ const params = {};
33
+ if (args.flags['app'])
34
+ params.app = args.flags['app'];
35
+ const result = await bridge.send('diff', params);
36
+ return { data: result, exitCode: 0 };
37
+ });
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const commands_js_1 = require("../commands.js");
4
+ const parser_js_1 = require("../parser.js");
5
+ (0, commands_js_1.registerCommand)('click', async (args, bridge) => {
6
+ const sel = args.positional[0];
7
+ if (!sel) {
8
+ return { data: { error: 'Usage: agent-computer click <ref|x,y|label> [--right] [--double] [--count N] [--modifiers keys]' }, exitCode: 1 };
9
+ }
10
+ const params = {};
11
+ const parsed = (0, parser_js_1.parseSelector)(sel);
12
+ if (parsed.type === 'ref') {
13
+ params.ref = parsed.ref;
14
+ }
15
+ else if (parsed.type === 'coords') {
16
+ params.x = parsed.x;
17
+ params.y = parsed.y;
18
+ }
19
+ else {
20
+ // Label-based click — not yet implemented, pass as ref for now
21
+ params.ref = parsed.label;
22
+ }
23
+ if (args.flags['right'])
24
+ params.right = true;
25
+ if (args.flags['double'])
26
+ params.double = true;
27
+ if (args.flags['count'])
28
+ params.count = parseInt(args.flags['count'], 10);
29
+ if (args.flags['modifiers']) {
30
+ const mods = args.flags['modifiers'];
31
+ params.modifiers = mods.split(',').map(m => m.trim());
32
+ }
33
+ if (args.flags['wait'])
34
+ params.wait = true;
35
+ if (args.flags['human'])
36
+ params.human = true;
37
+ const result = await bridge.send('click', params);
38
+ return { data: result, exitCode: 0 };
39
+ });
40
+ (0, commands_js_1.registerCommand)('hover', async (args, bridge) => {
41
+ const sel = args.positional[0];
42
+ if (!sel) {
43
+ return { data: { error: 'Usage: agent-computer hover <ref|x,y>' }, exitCode: 1 };
44
+ }
45
+ const params = {};
46
+ const parsed = (0, parser_js_1.parseSelector)(sel);
47
+ if (parsed.type === 'ref') {
48
+ params.ref = parsed.ref;
49
+ }
50
+ else if (parsed.type === 'coords') {
51
+ params.x = parsed.x;
52
+ params.y = parsed.y;
53
+ }
54
+ else {
55
+ params.ref = parsed.label;
56
+ }
57
+ if (args.flags['human'])
58
+ params.human = true;
59
+ const result = await bridge.send('hover', params);
60
+ return { data: result, exitCode: 0 };
61
+ });
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const commands_js_1 = require("../commands.js");
4
+ (0, commands_js_1.registerCommand)('clipboard', async (args, bridge) => {
5
+ const sub = args.subcommand;
6
+ switch (sub) {
7
+ case 'set': {
8
+ const text = args.positional[0];
9
+ if (!text) {
10
+ return { data: { error: 'Usage: agent-computer clipboard set <text>' }, exitCode: 1 };
11
+ }
12
+ const result = await bridge.send('clipboard_set', { text });
13
+ return { data: result, exitCode: 0 };
14
+ }
15
+ case 'copy': {
16
+ const result = await bridge.send('clipboard_copy');
17
+ return { data: result, exitCode: 0 };
18
+ }
19
+ case 'paste': {
20
+ const result = await bridge.send('paste', { text: '' });
21
+ // Actually clipboard paste is just Cmd+V
22
+ const pasteResult = await bridge.send('key', { combo: 'cmd+v' });
23
+ return { data: pasteResult, exitCode: 0 };
24
+ }
25
+ default: {
26
+ // Read clipboard
27
+ const result = await bridge.send('clipboard_read');
28
+ return { data: result, exitCode: 0 };
29
+ }
30
+ }
31
+ });