@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.
- package/bin/ac-core-darwin-arm64 +0 -0
- package/bin/ac-core-darwin-x64 +0 -0
- package/bin/ac-core-win32-arm64.exe +0 -0
- package/bin/ac-core-win32-x64.exe +0 -0
- package/dist/src/platform/resolve.d.ts.map +1 -1
- package/dist/src/platform/resolve.js +5 -3
- package/dist/src/platform/resolve.js.map +1 -1
- package/dist-cjs/bin/ac.js +127 -0
- package/dist-cjs/package.json +1 -0
- package/dist-cjs/src/bridge.js +693 -0
- package/dist-cjs/src/cdp/ax-tree.js +162 -0
- package/dist-cjs/src/cdp/bounds.js +66 -0
- package/dist-cjs/src/cdp/client.js +272 -0
- package/dist-cjs/src/cdp/connection.js +285 -0
- package/dist-cjs/src/cdp/diff.js +55 -0
- package/dist-cjs/src/cdp/discovery.js +91 -0
- package/dist-cjs/src/cdp/index.js +27 -0
- package/dist-cjs/src/cdp/interactions.js +301 -0
- package/dist-cjs/src/cdp/port-manager.js +68 -0
- package/dist-cjs/src/cdp/role-map.js +102 -0
- package/dist-cjs/src/cdp/types.js +2 -0
- package/dist-cjs/src/cli/commands/apps.js +63 -0
- package/dist-cjs/src/cli/commands/batch.js +37 -0
- package/dist-cjs/src/cli/commands/click.js +61 -0
- package/dist-cjs/src/cli/commands/clipboard.js +31 -0
- package/dist-cjs/src/cli/commands/dialog.js +45 -0
- package/dist-cjs/src/cli/commands/drag.js +26 -0
- package/dist-cjs/src/cli/commands/find.js +99 -0
- package/dist-cjs/src/cli/commands/menu.js +36 -0
- package/dist-cjs/src/cli/commands/screenshot.js +27 -0
- package/dist-cjs/src/cli/commands/scroll.js +77 -0
- package/dist-cjs/src/cli/commands/session.js +27 -0
- package/dist-cjs/src/cli/commands/snapshot.js +24 -0
- package/dist-cjs/src/cli/commands/type.js +69 -0
- package/dist-cjs/src/cli/commands/windowmgmt.js +62 -0
- package/dist-cjs/src/cli/commands/windows.js +10 -0
- package/dist-cjs/src/cli/commands.js +215 -0
- package/dist-cjs/src/cli/output.js +253 -0
- package/dist-cjs/src/cli/parser.js +128 -0
- package/dist-cjs/src/config.js +79 -0
- package/dist-cjs/src/daemon.js +183 -0
- package/dist-cjs/src/errors.js +118 -0
- package/dist-cjs/src/index.js +24 -0
- package/dist-cjs/src/platform/index.js +16 -0
- package/dist-cjs/src/platform/resolve.js +71 -0
- package/dist-cjs/src/refs.js +91 -0
- package/dist-cjs/src/sdk.js +288 -0
- package/dist-cjs/src/types.js +11 -0
- package/package.json +4 -2
- package/scripts/fix-cjs-resolve.js +27 -0
|
@@ -0,0 +1,215 @@
|
|
|
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.registerCommand = registerCommand;
|
|
37
|
+
exports.getCommand = getCommand;
|
|
38
|
+
exports.getCommandAsync = getCommandAsync;
|
|
39
|
+
exports.getAllCommands = getAllCommands;
|
|
40
|
+
const daemon_js_1 = require("../daemon.js");
|
|
41
|
+
const config_js_1 = require("../config.js");
|
|
42
|
+
const commands = {};
|
|
43
|
+
let commandModulesLoaded = false;
|
|
44
|
+
function registerCommand(name, handler) {
|
|
45
|
+
commands[name] = handler;
|
|
46
|
+
}
|
|
47
|
+
async function ensureCommandModulesLoaded() {
|
|
48
|
+
if (commandModulesLoaded)
|
|
49
|
+
return;
|
|
50
|
+
commandModulesLoaded = true;
|
|
51
|
+
await Promise.resolve().then(() => __importStar(require('./commands/apps.js')));
|
|
52
|
+
await Promise.resolve().then(() => __importStar(require('./commands/windows.js')));
|
|
53
|
+
await Promise.resolve().then(() => __importStar(require('./commands/session.js')));
|
|
54
|
+
await Promise.resolve().then(() => __importStar(require('./commands/snapshot.js')));
|
|
55
|
+
await Promise.resolve().then(() => __importStar(require('./commands/click.js')));
|
|
56
|
+
await Promise.resolve().then(() => __importStar(require('./commands/type.js')));
|
|
57
|
+
await Promise.resolve().then(() => __importStar(require('./commands/clipboard.js')));
|
|
58
|
+
await Promise.resolve().then(() => __importStar(require('./commands/windowmgmt.js')));
|
|
59
|
+
await Promise.resolve().then(() => __importStar(require('./commands/screenshot.js')));
|
|
60
|
+
await Promise.resolve().then(() => __importStar(require('./commands/scroll.js')));
|
|
61
|
+
await Promise.resolve().then(() => __importStar(require('./commands/find.js')));
|
|
62
|
+
await Promise.resolve().then(() => __importStar(require('./commands/menu.js')));
|
|
63
|
+
await Promise.resolve().then(() => __importStar(require('./commands/dialog.js')));
|
|
64
|
+
await Promise.resolve().then(() => __importStar(require('./commands/drag.js')));
|
|
65
|
+
await Promise.resolve().then(() => __importStar(require('./commands/batch.js')));
|
|
66
|
+
}
|
|
67
|
+
function getCommand(name) {
|
|
68
|
+
return commands[name];
|
|
69
|
+
}
|
|
70
|
+
async function getCommandAsync(name) {
|
|
71
|
+
await ensureCommandModulesLoaded();
|
|
72
|
+
return commands[name];
|
|
73
|
+
}
|
|
74
|
+
function getAllCommands() {
|
|
75
|
+
return Object.keys(commands).sort();
|
|
76
|
+
}
|
|
77
|
+
// Register built-in commands
|
|
78
|
+
registerCommand('version', async () => {
|
|
79
|
+
return { data: { version: '0.1.0' }, exitCode: 0 };
|
|
80
|
+
});
|
|
81
|
+
registerCommand('help', async () => {
|
|
82
|
+
const help = `agent-computer — Agent Computer CLI for macOS
|
|
83
|
+
|
|
84
|
+
Usage: agent-computer <command> [options]
|
|
85
|
+
|
|
86
|
+
Commands:
|
|
87
|
+
snapshot Snapshot the accessibility tree
|
|
88
|
+
screenshot [path] Take a screenshot
|
|
89
|
+
click <sel> Click an element
|
|
90
|
+
type <text> Type text
|
|
91
|
+
fill <sel> <text> Focus, clear, and type into an element
|
|
92
|
+
key <combo> Press a key combination
|
|
93
|
+
find <text> Find elements by text
|
|
94
|
+
read <sel> Read element value
|
|
95
|
+
scroll <dir> [amount] Scroll in a direction
|
|
96
|
+
menu <path> Click a menu item by path
|
|
97
|
+
|
|
98
|
+
apps List applications
|
|
99
|
+
launch <name> Launch an application
|
|
100
|
+
quit <name> Quit an application
|
|
101
|
+
windows List windows
|
|
102
|
+
grab <sel> Set active window context
|
|
103
|
+
ungrab Clear active window context
|
|
104
|
+
status Show session state
|
|
105
|
+
|
|
106
|
+
wait <sel|ms> Wait for condition
|
|
107
|
+
clipboard [set <text>] Clipboard operations
|
|
108
|
+
alert Handle alerts
|
|
109
|
+
dialog Handle dialogs
|
|
110
|
+
|
|
111
|
+
daemon <start|stop|status|restart> Manage daemon
|
|
112
|
+
config [set <key> <val> | reset] Configuration
|
|
113
|
+
permissions [grant] Permission status
|
|
114
|
+
doctor Run diagnostics
|
|
115
|
+
version Print version
|
|
116
|
+
|
|
117
|
+
Global options:
|
|
118
|
+
--json JSON output (default: human-readable text)
|
|
119
|
+
--timeout <ms> Override timeout (default: 10000)
|
|
120
|
+
--verbose Debug logging to stderr
|
|
121
|
+
--content-boundary Wrap output in delimiters
|
|
122
|
+
--max-output <n> Truncate output to N characters
|
|
123
|
+
|
|
124
|
+
See: https://github.com/datawizz/agent-computer`;
|
|
125
|
+
return { data: help, exitCode: 0 };
|
|
126
|
+
});
|
|
127
|
+
registerCommand('daemon', async (args) => {
|
|
128
|
+
const manager = new daemon_js_1.DaemonManager();
|
|
129
|
+
const sub = args.subcommand;
|
|
130
|
+
switch (sub) {
|
|
131
|
+
case 'start': {
|
|
132
|
+
const status = await manager.start();
|
|
133
|
+
return { data: status, exitCode: 0 };
|
|
134
|
+
}
|
|
135
|
+
case 'stop': {
|
|
136
|
+
await manager.stop();
|
|
137
|
+
return { data: { ok: true }, exitCode: 0 };
|
|
138
|
+
}
|
|
139
|
+
case 'status': {
|
|
140
|
+
const status = await manager.status();
|
|
141
|
+
return { data: status, exitCode: 0 };
|
|
142
|
+
}
|
|
143
|
+
case 'restart': {
|
|
144
|
+
const status = await manager.restart();
|
|
145
|
+
return { data: status, exitCode: 0 };
|
|
146
|
+
}
|
|
147
|
+
default:
|
|
148
|
+
return { data: { error: `Unknown daemon subcommand: ${sub}. Use: start, stop, status, restart` }, exitCode: 1 };
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
registerCommand('config', async (args) => {
|
|
152
|
+
const sub = args.subcommand;
|
|
153
|
+
switch (sub) {
|
|
154
|
+
case 'set': {
|
|
155
|
+
const key = args.positional[0];
|
|
156
|
+
const value = args.positional[1];
|
|
157
|
+
if (!key || value === undefined) {
|
|
158
|
+
return { data: { error: 'Usage: agent-computer config set <key> <value>' }, exitCode: 1 };
|
|
159
|
+
}
|
|
160
|
+
const defaults = (0, config_js_1.getDefaults)();
|
|
161
|
+
if (!(key in defaults)) {
|
|
162
|
+
return { data: { error: `Unknown config key: ${key}` }, exitCode: 1 };
|
|
163
|
+
}
|
|
164
|
+
// Coerce value to correct type
|
|
165
|
+
const defaultVal = defaults[key];
|
|
166
|
+
let coerced = value;
|
|
167
|
+
if (typeof defaultVal === 'number')
|
|
168
|
+
coerced = parseInt(value, 10);
|
|
169
|
+
if (typeof defaultVal === 'boolean')
|
|
170
|
+
coerced = value === 'true' || value === '1';
|
|
171
|
+
(0, config_js_1.setConfigValue)(key, coerced);
|
|
172
|
+
return { data: { ok: true, key, value: coerced }, exitCode: 0 };
|
|
173
|
+
}
|
|
174
|
+
case 'reset': {
|
|
175
|
+
(0, config_js_1.resetConfig)();
|
|
176
|
+
return { data: { ok: true }, exitCode: 0 };
|
|
177
|
+
}
|
|
178
|
+
default: {
|
|
179
|
+
// Show current config
|
|
180
|
+
const config = (0, config_js_1.resolveConfig)();
|
|
181
|
+
return { data: config, exitCode: 0 };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
registerCommand('ping', async (_args, bridge) => {
|
|
186
|
+
const result = await bridge.send('ping');
|
|
187
|
+
return { data: result, exitCode: 0 };
|
|
188
|
+
});
|
|
189
|
+
registerCommand('status', async (_args, bridge) => {
|
|
190
|
+
const result = await bridge.send('status');
|
|
191
|
+
return { data: result, exitCode: 0 };
|
|
192
|
+
});
|
|
193
|
+
registerCommand('permissions', async (args, bridge) => {
|
|
194
|
+
if (args.subcommand === 'grant') {
|
|
195
|
+
const result = await bridge.send('permissions_grant');
|
|
196
|
+
return { data: result, exitCode: 0 };
|
|
197
|
+
}
|
|
198
|
+
const result = await bridge.send('permissions');
|
|
199
|
+
return { data: result, exitCode: 0 };
|
|
200
|
+
});
|
|
201
|
+
registerCommand('doctor', async (_args, bridge) => {
|
|
202
|
+
const [permissions, version, daemonStatus] = await Promise.all([
|
|
203
|
+
bridge.send('permissions'),
|
|
204
|
+
bridge.send('version'),
|
|
205
|
+
new daemon_js_1.DaemonManager().status(),
|
|
206
|
+
]);
|
|
207
|
+
const result = {
|
|
208
|
+
version: version.version,
|
|
209
|
+
permissions,
|
|
210
|
+
daemon: daemonStatus,
|
|
211
|
+
platform: process.platform,
|
|
212
|
+
arch: process.arch,
|
|
213
|
+
};
|
|
214
|
+
return { data: result, exitCode: 0 };
|
|
215
|
+
});
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatOutput = formatOutput;
|
|
4
|
+
exports.wrapBoundary = wrapBoundary;
|
|
5
|
+
exports.truncateOutput = truncateOutput;
|
|
6
|
+
const crypto_1 = require("crypto");
|
|
7
|
+
// Format output — text mode is default, --json for JSON
|
|
8
|
+
function formatOutput(data, textMode) {
|
|
9
|
+
if (textMode) {
|
|
10
|
+
return formatText(data);
|
|
11
|
+
}
|
|
12
|
+
return JSON.stringify(data, null, 2);
|
|
13
|
+
}
|
|
14
|
+
// Human-readable text formatting
|
|
15
|
+
function formatText(data) {
|
|
16
|
+
if (data === null || data === undefined) {
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
19
|
+
if (typeof data === 'string') {
|
|
20
|
+
return data;
|
|
21
|
+
}
|
|
22
|
+
if (typeof data === 'boolean' || typeof data === 'number') {
|
|
23
|
+
return String(data);
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(data)) {
|
|
26
|
+
return data.map(item => formatText(item)).join('\n');
|
|
27
|
+
}
|
|
28
|
+
if (typeof data === 'object') {
|
|
29
|
+
const obj = data;
|
|
30
|
+
// Snapshot result — format as tree
|
|
31
|
+
if ('snapshot_id' in obj && 'elements' in obj) {
|
|
32
|
+
return formatSnapshotText(obj);
|
|
33
|
+
}
|
|
34
|
+
// Windows list
|
|
35
|
+
if ('windows' in obj && Array.isArray(obj.windows)) {
|
|
36
|
+
return formatWindowsList(obj.windows);
|
|
37
|
+
}
|
|
38
|
+
// Apps list
|
|
39
|
+
if ('apps' in obj && Array.isArray(obj.apps)) {
|
|
40
|
+
return formatAppsList(obj.apps);
|
|
41
|
+
}
|
|
42
|
+
// Find results
|
|
43
|
+
if ('elements' in obj && Array.isArray(obj.elements) && !('snapshot_id' in obj)) {
|
|
44
|
+
return formatFindResults(obj.elements);
|
|
45
|
+
}
|
|
46
|
+
// Dialog detection
|
|
47
|
+
if ('found' in obj && 'dialog' in obj) {
|
|
48
|
+
return formatDialogResult(obj);
|
|
49
|
+
}
|
|
50
|
+
// Batch results
|
|
51
|
+
if ('results' in obj && Array.isArray(obj.results) && 'total' in obj) {
|
|
52
|
+
return formatBatchResults(obj);
|
|
53
|
+
}
|
|
54
|
+
// Diff/changed
|
|
55
|
+
if ('changed' in obj && typeof obj.changed === 'boolean') {
|
|
56
|
+
return formatDiffResult(obj);
|
|
57
|
+
}
|
|
58
|
+
// Menu list
|
|
59
|
+
if ('items' in obj && Array.isArray(obj.items)) {
|
|
60
|
+
return formatMenuItems(obj.items, obj.menu);
|
|
61
|
+
}
|
|
62
|
+
// Screenshot
|
|
63
|
+
if ('path' in obj && typeof obj.path === 'string' && ('width' in obj || 'ok' in obj)) {
|
|
64
|
+
return formatScreenshot(obj);
|
|
65
|
+
}
|
|
66
|
+
// Displays
|
|
67
|
+
if ('displays' in obj && Array.isArray(obj.displays)) {
|
|
68
|
+
return formatDisplays(obj.displays);
|
|
69
|
+
}
|
|
70
|
+
// Permissions
|
|
71
|
+
if ('accessibility' in obj && 'screen_recording' in obj) {
|
|
72
|
+
return formatPermissions(obj);
|
|
73
|
+
}
|
|
74
|
+
// Simple ok result
|
|
75
|
+
if ('ok' in obj && Object.keys(obj).length <= 3) {
|
|
76
|
+
const extra = Object.entries(obj)
|
|
77
|
+
.filter(([k]) => k !== 'ok')
|
|
78
|
+
.map(([k, v]) => {
|
|
79
|
+
if (typeof v !== 'object' || v === null)
|
|
80
|
+
return `${k}: ${v}`;
|
|
81
|
+
// Format nested objects as key=value pairs
|
|
82
|
+
const inner = Object.entries(v)
|
|
83
|
+
.map(([ik, iv]) => `${ik}=${Array.isArray(iv) ? iv.join(',') : iv}`)
|
|
84
|
+
.join(', ');
|
|
85
|
+
return `${k}: ${inner}`;
|
|
86
|
+
})
|
|
87
|
+
.join(', ');
|
|
88
|
+
return extra ? `OK (${extra})` : 'OK';
|
|
89
|
+
}
|
|
90
|
+
// Clipboard
|
|
91
|
+
if ('text' in obj && typeof obj.text === 'string' && Object.keys(obj).length <= 2) {
|
|
92
|
+
return obj.text;
|
|
93
|
+
}
|
|
94
|
+
// Generic key-value
|
|
95
|
+
return Object.entries(obj)
|
|
96
|
+
.map(([key, val]) => `${key}: ${typeof val === 'object' ? JSON.stringify(val) : val}`)
|
|
97
|
+
.join('\n');
|
|
98
|
+
}
|
|
99
|
+
return JSON.stringify(data);
|
|
100
|
+
}
|
|
101
|
+
// Format snapshot as hierarchical tree
|
|
102
|
+
function formatSnapshotText(snap) {
|
|
103
|
+
const elements = snap.elements;
|
|
104
|
+
const lines = [];
|
|
105
|
+
for (const el of elements) {
|
|
106
|
+
formatElementTree(el, 0, lines);
|
|
107
|
+
}
|
|
108
|
+
return lines.join('\n');
|
|
109
|
+
}
|
|
110
|
+
function formatElementTree(el, indent, lines) {
|
|
111
|
+
const prefix = ' '.repeat(indent);
|
|
112
|
+
const focusMarker = el.focused ? '*' : '';
|
|
113
|
+
const parts = [];
|
|
114
|
+
parts.push(`${focusMarker}[${el.ref}] ${capitalize(el.role)}`);
|
|
115
|
+
if (el.label)
|
|
116
|
+
parts.push(`"${el.label}"`);
|
|
117
|
+
if (el.value !== null && el.value !== undefined)
|
|
118
|
+
parts.push(`value="${truncate(String(el.value), 50)}"`);
|
|
119
|
+
const attrs = [];
|
|
120
|
+
if (el.enabled)
|
|
121
|
+
attrs.push('enabled');
|
|
122
|
+
if (!el.enabled)
|
|
123
|
+
attrs.push('disabled');
|
|
124
|
+
if (el.focused)
|
|
125
|
+
attrs.push('focused');
|
|
126
|
+
if (el.bounds) {
|
|
127
|
+
const [x, y, w, h] = el.bounds;
|
|
128
|
+
attrs.push(`${x},${y} ${w}x${h}`);
|
|
129
|
+
}
|
|
130
|
+
lines.push(`${prefix}${parts.join(' ')} (${attrs.join(', ')})`);
|
|
131
|
+
if (el.children) {
|
|
132
|
+
for (const child of el.children) {
|
|
133
|
+
formatElementTree(child, indent + 1, lines);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function formatWindowsList(windows) {
|
|
138
|
+
if (windows.length === 0)
|
|
139
|
+
return 'No windows';
|
|
140
|
+
return windows.map(w => `${w.ref || '-'} ${w.app}: "${w.title}"${w.minimized ? ' (minimized)' : ''}${w.hidden ? ' (hidden)' : ''}`).join('\n');
|
|
141
|
+
}
|
|
142
|
+
function formatAppsList(apps) {
|
|
143
|
+
if (apps.length === 0)
|
|
144
|
+
return 'No running apps';
|
|
145
|
+
return apps.map(a => `${a.name}${a.is_active ? ' *' : ''}${a.is_hidden ? ' (hidden)' : ''}${a.bundle_id ? ` [${a.bundle_id}]` : ''}`).join('\n');
|
|
146
|
+
}
|
|
147
|
+
function formatFindResults(elements) {
|
|
148
|
+
if (elements.length === 0)
|
|
149
|
+
return 'No elements found';
|
|
150
|
+
return elements.map(e => {
|
|
151
|
+
const parts = [`[${e.ref}] ${e.role}`];
|
|
152
|
+
if (e.label)
|
|
153
|
+
parts.push(`"${e.label}"`);
|
|
154
|
+
if (e.value)
|
|
155
|
+
parts.push(`value="${truncate(String(e.value), 40)}"`);
|
|
156
|
+
return parts.join(' ');
|
|
157
|
+
}).join('\n');
|
|
158
|
+
}
|
|
159
|
+
function formatDialogResult(obj) {
|
|
160
|
+
if (!obj.found)
|
|
161
|
+
return 'No dialog found';
|
|
162
|
+
const dialog = obj.dialog;
|
|
163
|
+
const lines = [`Dialog: ${dialog.type}`];
|
|
164
|
+
if (dialog.title)
|
|
165
|
+
lines.push(` Title: ${dialog.title}`);
|
|
166
|
+
if (dialog.message)
|
|
167
|
+
lines.push(` Message: ${dialog.message}`);
|
|
168
|
+
if (dialog.buttons && Array.isArray(dialog.buttons)) {
|
|
169
|
+
const btns = dialog.buttons.map(b => b.title).join(', ');
|
|
170
|
+
lines.push(` Buttons: ${btns}`);
|
|
171
|
+
}
|
|
172
|
+
return lines.join('\n');
|
|
173
|
+
}
|
|
174
|
+
function formatBatchResults(obj) {
|
|
175
|
+
const results = obj.results;
|
|
176
|
+
const lines = [`Batch: ${obj.count}/${obj.total} completed${obj.ok ? '' : ' (stopped on error)'}`];
|
|
177
|
+
for (const r of results) {
|
|
178
|
+
if (r.error) {
|
|
179
|
+
lines.push(` [${r.index}] ${r.method}: ERROR - ${r.error}`);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
lines.push(` [${r.index}] ${r.method}: OK`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return lines.join('\n');
|
|
186
|
+
}
|
|
187
|
+
function formatDiffResult(obj) {
|
|
188
|
+
if (!obj.changed)
|
|
189
|
+
return 'No changes detected';
|
|
190
|
+
const lines = ['Changes detected'];
|
|
191
|
+
if (obj.added_count)
|
|
192
|
+
lines.push(` Added: ${obj.added_count}`);
|
|
193
|
+
if (obj.removed_count)
|
|
194
|
+
lines.push(` Removed: ${obj.removed_count}`);
|
|
195
|
+
if (Array.isArray(obj.added) && obj.added.length > 0) {
|
|
196
|
+
lines.push(` Added elements: ${obj.added.length}`);
|
|
197
|
+
}
|
|
198
|
+
if (Array.isArray(obj.removed) && obj.removed.length > 0) {
|
|
199
|
+
lines.push(` Removed elements: ${obj.removed.length}`);
|
|
200
|
+
}
|
|
201
|
+
return lines.join('\n');
|
|
202
|
+
}
|
|
203
|
+
function formatMenuItems(items, menuName) {
|
|
204
|
+
if (items.length === 0)
|
|
205
|
+
return menuName ? `No items in menu "${menuName}"` : 'No menus';
|
|
206
|
+
const header = menuName ? `Menu: ${menuName}` : 'Menus';
|
|
207
|
+
const lines = [header];
|
|
208
|
+
for (const item of items) {
|
|
209
|
+
const enabled = item.enabled !== false ? '' : ' (disabled)';
|
|
210
|
+
lines.push(` ${item.title}${enabled}`);
|
|
211
|
+
if (Array.isArray(item.children)) {
|
|
212
|
+
for (const child of item.children) {
|
|
213
|
+
const cEnabled = child.enabled !== false ? '' : ' (disabled)';
|
|
214
|
+
lines.push(` ${child.title}${cEnabled}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return lines.join('\n');
|
|
219
|
+
}
|
|
220
|
+
function formatScreenshot(obj) {
|
|
221
|
+
const parts = [`Screenshot: ${obj.path}`];
|
|
222
|
+
if (obj.width && obj.height)
|
|
223
|
+
parts.push(`(${obj.width}x${obj.height})`);
|
|
224
|
+
return parts.join(' ');
|
|
225
|
+
}
|
|
226
|
+
function formatDisplays(displays) {
|
|
227
|
+
return displays.map(d => `Display ${d.id}${d.is_main ? ' (main)' : ''}: ${d.width}x${d.height} @ ${d.x},${d.y} scale=${d.scale_factor}`).join('\n');
|
|
228
|
+
}
|
|
229
|
+
function formatPermissions(obj) {
|
|
230
|
+
const lines = ['Permissions:'];
|
|
231
|
+
lines.push(` Accessibility: ${obj.accessibility ? 'granted' : 'NOT GRANTED'}`);
|
|
232
|
+
lines.push(` Screen Recording: ${obj.screen_recording ? 'granted' : 'NOT GRANTED'}`);
|
|
233
|
+
return lines.join('\n');
|
|
234
|
+
}
|
|
235
|
+
function capitalize(s) {
|
|
236
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
237
|
+
}
|
|
238
|
+
function truncate(s, maxLen) {
|
|
239
|
+
if (s.length <= maxLen)
|
|
240
|
+
return s;
|
|
241
|
+
return s.slice(0, maxLen - 3) + '...';
|
|
242
|
+
}
|
|
243
|
+
// Content boundary wrapping
|
|
244
|
+
function wrapBoundary(content) {
|
|
245
|
+
const boundary = `AC_BOUNDARY_${(0, crypto_1.randomBytes)(4).toString('hex')}`;
|
|
246
|
+
return `<<<${boundary}\n${content}\n${boundary}>>>`;
|
|
247
|
+
}
|
|
248
|
+
// Max-output truncation
|
|
249
|
+
function truncateOutput(content, maxChars) {
|
|
250
|
+
if (content.length <= maxChars)
|
|
251
|
+
return content;
|
|
252
|
+
return content.slice(0, maxChars) + `\n... (truncated at ${maxChars} chars)`;
|
|
253
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// CLI argument parser — verb-first pattern
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.parseArgs = parseArgs;
|
|
5
|
+
exports.parseSelector = parseSelector;
|
|
6
|
+
// Commands that have subcommands
|
|
7
|
+
const SUBCOMMAND_COMMANDS = new Set([
|
|
8
|
+
'daemon', 'menu', 'menubar', 'clipboard', 'mouse',
|
|
9
|
+
'record', 'config', 'permissions', 'dock', 'diff',
|
|
10
|
+
'dialog', 'alert', 'is',
|
|
11
|
+
]);
|
|
12
|
+
// Commands where the first positional arg looks like a subcommand
|
|
13
|
+
const DIRECTION_COMMANDS = new Set(['scroll']);
|
|
14
|
+
// Flag aliases
|
|
15
|
+
const FLAG_ALIASES = {
|
|
16
|
+
'-i': '--interactive',
|
|
17
|
+
'-c': '--compact',
|
|
18
|
+
'-d': '--depth',
|
|
19
|
+
'-o': '--output',
|
|
20
|
+
'-t': '--threshold',
|
|
21
|
+
};
|
|
22
|
+
// Flags that take a value (next arg)
|
|
23
|
+
const VALUE_FLAGS = new Set([
|
|
24
|
+
'--timeout', '--depth', '--app', '--pid', '--window', '--subtree',
|
|
25
|
+
'--on', '--modifiers', '--count', '--delay', '--repeat',
|
|
26
|
+
'--format', '--quality', '--output', '--threshold',
|
|
27
|
+
'--preset', '--text-match', '--role', '--attr',
|
|
28
|
+
'--max-output', '--duration', '--steps', '--to-coords',
|
|
29
|
+
'--from-coords', '--to-app', '--pixels', '--open',
|
|
30
|
+
]);
|
|
31
|
+
function parseArgs(argv) {
|
|
32
|
+
// Strip node and script path if present
|
|
33
|
+
const args = argv[0]?.includes('node') || argv[0]?.includes('tsx')
|
|
34
|
+
? argv.slice(2)
|
|
35
|
+
: argv;
|
|
36
|
+
const result = {
|
|
37
|
+
command: '',
|
|
38
|
+
subcommand: null,
|
|
39
|
+
positional: [],
|
|
40
|
+
flags: {},
|
|
41
|
+
};
|
|
42
|
+
if (args.length === 0) {
|
|
43
|
+
result.command = 'help';
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
let i = 0;
|
|
47
|
+
// Check for global flags before command
|
|
48
|
+
while (i < args.length && args[i].startsWith('-')) {
|
|
49
|
+
const flag = args[i];
|
|
50
|
+
if (flag === '--version') {
|
|
51
|
+
result.command = 'version';
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
if (flag === '--help' || flag === '-h') {
|
|
55
|
+
result.command = 'help';
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
// Global flags
|
|
59
|
+
const resolved = FLAG_ALIASES[flag] || flag;
|
|
60
|
+
const flagName = resolved.replace(/^--/, '');
|
|
61
|
+
if (VALUE_FLAGS.has(resolved) && i + 1 < args.length) {
|
|
62
|
+
result.flags[flagName] = args[i + 1];
|
|
63
|
+
i += 2;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
result.flags[flagName] = true;
|
|
67
|
+
i += 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Command
|
|
71
|
+
if (i >= args.length) {
|
|
72
|
+
result.command = 'help';
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
result.command = args[i];
|
|
76
|
+
i++;
|
|
77
|
+
// Subcommand (for commands that have them)
|
|
78
|
+
if (SUBCOMMAND_COMMANDS.has(result.command) && i < args.length && !args[i].startsWith('-') && !args[i].startsWith('@')) {
|
|
79
|
+
result.subcommand = args[i];
|
|
80
|
+
i++;
|
|
81
|
+
}
|
|
82
|
+
// Direction for scroll
|
|
83
|
+
if (DIRECTION_COMMANDS.has(result.command) && i < args.length && !args[i].startsWith('-') && !args[i].startsWith('@')) {
|
|
84
|
+
result.subcommand = args[i];
|
|
85
|
+
i++;
|
|
86
|
+
}
|
|
87
|
+
// Remaining args
|
|
88
|
+
while (i < args.length) {
|
|
89
|
+
const arg = args[i];
|
|
90
|
+
if (arg.startsWith('-')) {
|
|
91
|
+
const resolved = FLAG_ALIASES[arg] || arg;
|
|
92
|
+
const flagName = resolved.replace(/^--/, '');
|
|
93
|
+
if (VALUE_FLAGS.has(resolved) && i + 1 < args.length) {
|
|
94
|
+
result.flags[flagName] = args[i + 1];
|
|
95
|
+
i += 2;
|
|
96
|
+
}
|
|
97
|
+
else if (resolved === '--interactive' || resolved === '-i') {
|
|
98
|
+
result.flags['interactive'] = true;
|
|
99
|
+
i++;
|
|
100
|
+
}
|
|
101
|
+
else if (resolved === '--compact' || resolved === '-c') {
|
|
102
|
+
result.flags['compact'] = true;
|
|
103
|
+
i++;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Boolean flag
|
|
107
|
+
result.flags[flagName] = true;
|
|
108
|
+
i++;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
result.positional.push(arg);
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
// Parse a selector: could be a ref (@b1), coordinates (100,200), or a label string
|
|
119
|
+
function parseSelector(sel) {
|
|
120
|
+
if (sel.startsWith('@')) {
|
|
121
|
+
return { type: 'ref', ref: sel };
|
|
122
|
+
}
|
|
123
|
+
const coordMatch = /^(\d+),(\d+)$/.exec(sel);
|
|
124
|
+
if (coordMatch) {
|
|
125
|
+
return { type: 'coords', x: parseInt(coordMatch[1], 10), y: parseInt(coordMatch[2], 10) };
|
|
126
|
+
}
|
|
127
|
+
return { type: 'label', label: sel };
|
|
128
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveConfig = resolveConfig;
|
|
4
|
+
exports.getConfigValue = getConfigValue;
|
|
5
|
+
exports.setConfigValue = setConfigValue;
|
|
6
|
+
exports.resetConfig = resetConfig;
|
|
7
|
+
exports.getDefaults = getDefaults;
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
const os_1 = require("os");
|
|
11
|
+
const DEFAULTS = {
|
|
12
|
+
'default-timeout': 10000,
|
|
13
|
+
'screenshot-dir': '/tmp/agent-computer',
|
|
14
|
+
'screenshot-format': 'png',
|
|
15
|
+
retina: false,
|
|
16
|
+
'content-boundary': false,
|
|
17
|
+
'daemon-idle-timeout': 300000,
|
|
18
|
+
};
|
|
19
|
+
const CONFIG_DIR = (0, path_1.join)((0, os_1.homedir)(), '.config', 'agent-computer');
|
|
20
|
+
const CONFIG_FILE = (0, path_1.join)(CONFIG_DIR, 'config.json');
|
|
21
|
+
// Environment variable overrides
|
|
22
|
+
const ENV_MAP = {
|
|
23
|
+
AC_TIMEOUT: 'default-timeout',
|
|
24
|
+
AC_SCREENSHOT_DIR: 'screenshot-dir',
|
|
25
|
+
};
|
|
26
|
+
function loadConfigFile() {
|
|
27
|
+
try {
|
|
28
|
+
const raw = (0, fs_1.readFileSync)(CONFIG_FILE, 'utf-8');
|
|
29
|
+
return JSON.parse(raw);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function loadEnvOverrides() {
|
|
36
|
+
const overrides = {};
|
|
37
|
+
for (const [envVar, configKey] of Object.entries(ENV_MAP)) {
|
|
38
|
+
const val = process.env[envVar];
|
|
39
|
+
if (val !== undefined) {
|
|
40
|
+
if (configKey) {
|
|
41
|
+
if (configKey === 'default-timeout' || configKey === 'daemon-idle-timeout') {
|
|
42
|
+
overrides[configKey] = parseInt(val, 10);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
overrides[configKey] = val;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Boolean env vars
|
|
51
|
+
if (process.env.AC_JSON === '1') {
|
|
52
|
+
// This is handled at the CLI level, not config
|
|
53
|
+
}
|
|
54
|
+
if (process.env.AC_VERBOSE === '1') {
|
|
55
|
+
// This is handled at the CLI level, not config
|
|
56
|
+
}
|
|
57
|
+
return overrides;
|
|
58
|
+
}
|
|
59
|
+
function resolveConfig() {
|
|
60
|
+
const fileConfig = loadConfigFile();
|
|
61
|
+
const envConfig = loadEnvOverrides();
|
|
62
|
+
return { ...DEFAULTS, ...fileConfig, ...envConfig };
|
|
63
|
+
}
|
|
64
|
+
function getConfigValue(key) {
|
|
65
|
+
return resolveConfig()[key];
|
|
66
|
+
}
|
|
67
|
+
function setConfigValue(key, value) {
|
|
68
|
+
const existing = loadConfigFile();
|
|
69
|
+
existing[key] = value;
|
|
70
|
+
(0, fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
|
|
71
|
+
(0, fs_1.writeFileSync)(CONFIG_FILE, JSON.stringify(existing, null, 2) + '\n');
|
|
72
|
+
}
|
|
73
|
+
function resetConfig() {
|
|
74
|
+
(0, fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
|
|
75
|
+
(0, fs_1.writeFileSync)(CONFIG_FILE, JSON.stringify({}, null, 2) + '\n');
|
|
76
|
+
}
|
|
77
|
+
function getDefaults() {
|
|
78
|
+
return { ...DEFAULTS };
|
|
79
|
+
}
|