@moxxy/plugin-computer-control 0.41.2 → 0.42.0
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/win32-x64/moxxy-computer.exe +0 -0
- package/bin/win32-x64/moxxy-computer.exe.json +1 -1
- package/dist/backend/access.d.ts +129 -0
- package/dist/backend/access.d.ts.map +1 -0
- package/dist/backend/access.js +158 -0
- package/dist/backend/access.js.map +1 -0
- package/dist/backend/app-hints.d.ts +14 -0
- package/dist/backend/app-hints.d.ts.map +1 -0
- package/dist/backend/app-hints.js +30 -0
- package/dist/backend/app-hints.js.map +1 -0
- package/dist/backend/backend.d.ts +70 -0
- package/dist/backend/backend.d.ts.map +1 -0
- package/dist/backend/backend.js +466 -0
- package/dist/backend/backend.js.map +1 -0
- package/dist/backend/rpc.d.ts +1438 -0
- package/dist/backend/rpc.d.ts.map +1 -0
- package/dist/backend/rpc.js +75 -0
- package/dist/backend/rpc.js.map +1 -0
- package/dist/backend/turn-controls.d.ts +20 -0
- package/dist/backend/turn-controls.d.ts.map +1 -0
- package/dist/backend/turn-controls.js +115 -0
- package/dist/backend/turn-controls.js.map +1 -0
- package/dist/contract/guidance.d.ts +12 -0
- package/dist/contract/guidance.d.ts.map +1 -0
- package/dist/contract/guidance.js +42 -0
- package/dist/contract/guidance.js.map +1 -0
- package/dist/contract/image.d.ts +29 -0
- package/dist/contract/image.d.ts.map +1 -0
- package/dist/contract/image.js +46 -0
- package/dist/contract/image.js.map +1 -0
- package/dist/contract/keys.d.ts +15 -0
- package/dist/contract/keys.d.ts.map +1 -0
- package/dist/contract/keys.js +118 -0
- package/dist/contract/keys.js.map +1 -0
- package/dist/contract/outcome.d.ts +61 -0
- package/dist/contract/outcome.d.ts.map +1 -0
- package/dist/contract/outcome.js +63 -0
- package/dist/contract/outcome.js.map +1 -0
- package/dist/contract/progress.d.ts +27 -0
- package/dist/contract/progress.d.ts.map +1 -0
- package/dist/contract/progress.js +36 -0
- package/dist/contract/progress.js.map +1 -0
- package/dist/contract/tools.d.ts +338 -0
- package/dist/contract/tools.d.ts.map +1 -0
- package/dist/contract/tools.js +195 -0
- package/dist/contract/tools.js.map +1 -0
- package/dist/contract/untrusted.d.ts +3 -0
- package/dist/contract/untrusted.d.ts.map +1 -0
- package/dist/contract/untrusted.js +8 -0
- package/dist/contract/untrusted.js.map +1 -0
- package/dist/helper/artifact.d.ts +41 -0
- package/dist/helper/artifact.d.ts.map +1 -0
- package/dist/helper/artifact.js +189 -0
- package/dist/helper/artifact.js.map +1 -0
- package/dist/helper/protocol.d.ts +80 -0
- package/dist/helper/protocol.d.ts.map +1 -0
- package/dist/helper/protocol.js +49 -0
- package/dist/helper/protocol.js.map +1 -0
- package/dist/helper/transport.d.ts +43 -0
- package/dist/helper/transport.d.ts.map +1 -0
- package/dist/{windows → helper}/transport.js +45 -19
- package/dist/helper/transport.js.map +1 -0
- package/dist/index.d.ts +9 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -42
- package/dist/index.js.map +1 -1
- package/dist/jev/ladder.d.ts +32 -0
- package/dist/jev/ladder.d.ts.map +1 -0
- package/dist/jev/ladder.js +66 -0
- package/dist/jev/ladder.js.map +1 -0
- package/dist/jev/memory.d.ts +11 -0
- package/dist/jev/memory.d.ts.map +1 -0
- package/dist/jev/memory.js +16 -0
- package/dist/jev/memory.js.map +1 -0
- package/dist/jev/run.d.ts +93 -0
- package/dist/jev/run.d.ts.map +1 -0
- package/dist/jev/run.js +403 -0
- package/dist/jev/run.js.map +1 -0
- package/dist/jev/train.d.ts +97 -0
- package/dist/jev/train.d.ts.map +1 -0
- package/dist/jev/train.js +28 -0
- package/dist/jev/train.js.map +1 -0
- package/dist/linux/profile.d.ts +6 -0
- package/dist/linux/profile.d.ts.map +1 -0
- package/dist/linux/profile.js +21 -0
- package/dist/linux/profile.js.map +1 -0
- package/dist/macos/profile.d.ts +5 -0
- package/dist/macos/profile.d.ts.map +1 -0
- package/dist/macos/profile.js +17 -0
- package/dist/macos/profile.js.map +1 -0
- package/dist/preview/controller.d.ts +127 -0
- package/dist/preview/controller.d.ts.map +1 -0
- package/dist/preview/controller.js +203 -0
- package/dist/preview/controller.js.map +1 -0
- package/dist/preview/surface.d.ts +9 -0
- package/dist/preview/surface.d.ts.map +1 -0
- package/dist/preview/surface.js +50 -0
- package/dist/preview/surface.js.map +1 -0
- package/dist/windows/maintenance.d.ts +1 -1
- package/dist/windows/maintenance.d.ts.map +1 -1
- package/dist/windows/maintenance.js +6 -5
- package/dist/windows/maintenance.js.map +1 -1
- package/dist/windows/profile.d.ts +5 -0
- package/dist/windows/profile.d.ts.map +1 -0
- package/dist/windows/profile.js +17 -0
- package/dist/windows/profile.js.map +1 -0
- package/learned/README.md +26 -0
- package/learned/cases/com.apple.calculator.json +395 -0
- package/learned/cases/com.apple.finder.json +115 -0
- package/learned/cases/com.apple.safari.json +112 -0
- package/learned/cases/com.apple.systempreferences.json +255 -0
- package/learned/com.apple.calculator-eace95fc.json +334 -0
- package/learned/com.apple.finder-27cf6ce8.json +260 -0
- package/learned/com.apple.safari-7cd9df4f.json +143 -0
- package/learned/com.apple.systempreferences-02cf0b8b.json +535 -0
- package/package.json +13 -7
- package/scripts/promote-learned.mjs +8 -0
- package/scripts/summarize-trial.mjs +68 -0
- package/scripts/train-learned.mjs +64 -0
- package/skills/computer-apps/blender.md +29 -0
- package/skills/computer-apps/browsers.md +50 -0
- package/skills/computer-apps/design-tools.md +37 -0
- package/skills/computer-apps/finder.md +23 -0
- package/skills/computer-apps/office.md +46 -0
- package/skills/computer-apps/video-editors.md +44 -0
- package/skills/computer-control.md +154 -191
- package/src/backend/access.test.ts +158 -0
- package/src/backend/access.ts +168 -0
- package/src/backend/app-hints.test.ts +59 -0
- package/src/backend/app-hints.ts +39 -0
- package/src/backend/backend.test.ts +725 -0
- package/src/backend/backend.ts +482 -0
- package/src/backend/contract-helper.fixture.mjs +138 -0
- package/src/backend/helper.fixture.ts +38 -0
- package/src/backend/rpc.ts +90 -0
- package/src/backend/turn-controls.test.ts +178 -0
- package/src/backend/turn-controls.ts +120 -0
- package/src/contract/guidance.test.ts +75 -0
- package/src/contract/guidance.ts +48 -0
- package/src/contract/image.test.ts +74 -0
- package/src/contract/image.ts +54 -0
- package/src/contract/keys.test.ts +103 -0
- package/src/contract/keys.ts +117 -0
- package/src/contract/outcome.test.ts +71 -0
- package/src/contract/outcome.ts +72 -0
- package/src/contract/progress.test.ts +56 -0
- package/src/contract/progress.ts +43 -0
- package/src/contract/tools.test.ts +210 -0
- package/src/contract/tools.ts +212 -0
- package/src/contract/untrusted.test.ts +20 -0
- package/src/contract/untrusted.ts +8 -0
- package/src/helper/artifact.test.ts +131 -0
- package/src/helper/artifact.ts +182 -0
- package/src/helper/protocol.test.ts +29 -0
- package/src/helper/protocol.ts +50 -0
- package/src/{windows → helper}/transport.test.ts +76 -19
- package/src/{windows → helper}/transport.ts +54 -16
- package/src/index.test.ts +112 -0
- package/src/index.ts +36 -53
- package/src/jev/ladder.test.ts +113 -0
- package/src/jev/ladder.ts +88 -0
- package/src/jev/memory.ts +20 -0
- package/src/jev/run.test.ts +700 -0
- package/src/jev/run.ts +443 -0
- package/src/jev/train.test.ts +40 -0
- package/src/jev/train.ts +41 -0
- package/src/linux/helper.test.ts +481 -0
- package/src/linux/profile.ts +25 -0
- package/src/macos/helper.test.ts +988 -0
- package/src/macos/profile.ts +19 -0
- package/src/preview/controller.test.ts +308 -0
- package/src/preview/controller.ts +262 -0
- package/src/preview/surface.test.ts +68 -0
- package/src/preview/surface.ts +45 -0
- package/src/skill.test.ts +34 -0
- package/src/windows/maintenance.ts +8 -7
- package/src/windows/profile.ts +19 -0
- package/dist/shell.d.ts +0 -56
- package/dist/shell.d.ts.map +0 -1
- package/dist/shell.js +0 -189
- package/dist/shell.js.map +0 -1
- package/dist/temporary-files.d.ts +0 -2
- package/dist/temporary-files.d.ts.map +0 -1
- package/dist/temporary-files.js +0 -10
- package/dist/temporary-files.js.map +0 -1
- package/dist/tools/applescript.d.ts +0 -2
- package/dist/tools/applescript.d.ts.map +0 -1
- package/dist/tools/applescript.js +0 -50
- package/dist/tools/applescript.js.map +0 -1
- package/dist/tools/click.d.ts +0 -2
- package/dist/tools/click.d.ts.map +0 -1
- package/dist/tools/click.js +0 -58
- package/dist/tools/click.js.map +0 -1
- package/dist/tools/clipboard.d.ts +0 -2
- package/dist/tools/clipboard.d.ts.map +0 -1
- package/dist/tools/clipboard.js +0 -71
- package/dist/tools/clipboard.js.map +0 -1
- package/dist/tools/key.d.ts +0 -11
- package/dist/tools/key.d.ts.map +0 -1
- package/dist/tools/key.js +0 -143
- package/dist/tools/key.js.map +0 -1
- package/dist/tools/open.d.ts +0 -2
- package/dist/tools/open.d.ts.map +0 -1
- package/dist/tools/open.js +0 -91
- package/dist/tools/open.js.map +0 -1
- package/dist/tools/screenshot.d.ts +0 -2
- package/dist/tools/screenshot.d.ts.map +0 -1
- package/dist/tools/screenshot.js +0 -162
- package/dist/tools/screenshot.js.map +0 -1
- package/dist/tools/type.d.ts +0 -8
- package/dist/tools/type.d.ts.map +0 -1
- package/dist/tools/type.js +0 -65
- package/dist/tools/type.js.map +0 -1
- package/dist/windows/artifact.d.ts +0 -3
- package/dist/windows/artifact.d.ts.map +0 -1
- package/dist/windows/artifact.js +0 -57
- package/dist/windows/artifact.js.map +0 -1
- package/dist/windows/backend.d.ts +0 -11
- package/dist/windows/backend.d.ts.map +0 -1
- package/dist/windows/backend.js +0 -122
- package/dist/windows/backend.js.map +0 -1
- package/dist/windows/contracts.d.ts +0 -1627
- package/dist/windows/contracts.d.ts.map +0 -1
- package/dist/windows/contracts.js +0 -137
- package/dist/windows/contracts.js.map +0 -1
- package/dist/windows/control-service.d.ts +0 -12
- package/dist/windows/control-service.d.ts.map +0 -1
- package/dist/windows/control-service.js +0 -65
- package/dist/windows/control-service.js.map +0 -1
- package/dist/windows/guidance.d.ts +0 -3
- package/dist/windows/guidance.d.ts.map +0 -1
- package/dist/windows/guidance.js +0 -20
- package/dist/windows/guidance.js.map +0 -1
- package/dist/windows/protocol.d.ts +0 -9
- package/dist/windows/protocol.d.ts.map +0 -1
- package/dist/windows/protocol.js +0 -32
- package/dist/windows/protocol.js.map +0 -1
- package/dist/windows/transport.d.ts +0 -23
- package/dist/windows/transport.d.ts.map +0 -1
- package/dist/windows/transport.js.map +0 -1
- package/src/shell.test.ts +0 -186
- package/src/shell.ts +0 -213
- package/src/temporary-files.test.ts +0 -18
- package/src/temporary-files.ts +0 -9
- package/src/tools/applescript-serialize.test.ts +0 -74
- package/src/tools/applescript.ts +0 -53
- package/src/tools/click.ts +0 -60
- package/src/tools/clipboard.ts +0 -72
- package/src/tools/key.ts +0 -155
- package/src/tools/open.ts +0 -96
- package/src/tools/screenshot.test.ts +0 -137
- package/src/tools/screenshot.ts +0 -180
- package/src/tools/type.ts +0 -68
- package/src/tools.test.ts +0 -94
- package/src/windows/action-contracts.test.ts +0 -13
- package/src/windows/artifact.test.ts +0 -16
- package/src/windows/artifact.ts +0 -57
- package/src/windows/backend.test.ts +0 -41
- package/src/windows/backend.ts +0 -122
- package/src/windows/contracts.test.ts +0 -81
- package/src/windows/contracts.ts +0 -143
- package/src/windows/control-service.test.ts +0 -58
- package/src/windows/control-service.ts +0 -68
- package/src/windows/guidance.test.ts +0 -29
- package/src/windows/guidance.ts +0 -21
- package/src/windows/model-contract.test.ts +0 -37
- package/src/windows/protocol.ts +0 -27
- package/src/windows/text-contracts.test.ts +0 -14
- package/src/windows/window-typing.test.ts +0 -14
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { OF_THE_FOCUS, pointsAtFocus, wordsIn } from '@moxxy/jev';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { parseKeyCombo } from './keys.js';
|
|
4
|
+
const coordinate = z.number().finite().nonnegative();
|
|
5
|
+
/** A chord string checked by the xdotool parser, plus an optional rule on the parsed chord. */
|
|
6
|
+
const chord = (rule = () => undefined) => z.string().max(64).superRefine((value, ctx) => {
|
|
7
|
+
let problem;
|
|
8
|
+
try {
|
|
9
|
+
problem = rule(parseKeyCombo(value));
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
problem = error.message;
|
|
13
|
+
}
|
|
14
|
+
if (problem)
|
|
15
|
+
ctx.addIssue({ code: 'custom', message: problem });
|
|
16
|
+
});
|
|
17
|
+
/** Field schemas without defaults; each action decides what is required, optional or defaulted. */
|
|
18
|
+
const fields = {
|
|
19
|
+
element_index: z.number().int().nonnegative()
|
|
20
|
+
.describe('Index of an element ([N]) in the latest computer_get_app_state of this app. Prefer it over coordinates.'),
|
|
21
|
+
x: coordinate.describe('Horizontal pixel in the latest screenshot of this app, from its left edge. Give together with y.'),
|
|
22
|
+
y: coordinate.describe('Vertical pixel in the latest screenshot of this app, from its top edge. Give together with x.'),
|
|
23
|
+
mouse_button: z.enum(['left', 'right', 'middle']),
|
|
24
|
+
click_count: z.number().int().min(1).max(3),
|
|
25
|
+
modifiers: chord((combo) => combo.key === null ? undefined : 'modifiers only, e.g. "shift" or "cmd+shift"')
|
|
26
|
+
.describe('Modifier keys held during the click, e.g. "shift" or "cmd+alt".'),
|
|
27
|
+
text: z.string().min(1).max(20_000),
|
|
28
|
+
key: chord().describe('One chord in xdotool syntax: "Return", "Tab", "Escape", "BackSpace", "Delete" (forward delete), "Up", "Page_Down", "F5", "KP_0", "super+c" (super = Command on macOS, Windows key on Windows, Super on Linux), "ctrl+shift+Tab".'),
|
|
29
|
+
repeat: z.number().int().min(1).max(100),
|
|
30
|
+
direction: z.enum(['up', 'down', 'left', 'right']),
|
|
31
|
+
pages: z.number().min(0.1).max(50).describe('How far to scroll, in visible pages.'),
|
|
32
|
+
value: z.string().max(100_000),
|
|
33
|
+
secondary_action: z.string().min(1).max(64).describe('An action listed for this element in the app state, e.g. "AXShowMenu". Never guess one.'),
|
|
34
|
+
};
|
|
35
|
+
const app = z.string().min(1).max(512)
|
|
36
|
+
.describe('App display name or bundle identifier (macOS), or app id from computer_list_apps (Windows, Linux).');
|
|
37
|
+
export function resolveTarget(input) {
|
|
38
|
+
if (input.element_index !== undefined)
|
|
39
|
+
return { kind: 'element', index: input.element_index };
|
|
40
|
+
if (input.x !== undefined && input.y !== undefined)
|
|
41
|
+
return { kind: 'point', x: input.x, y: input.y };
|
|
42
|
+
return { kind: 'focused' };
|
|
43
|
+
}
|
|
44
|
+
function checkTarget(required) {
|
|
45
|
+
return (input, ctx) => {
|
|
46
|
+
if ((input.x === undefined) !== (input.y === undefined)) {
|
|
47
|
+
ctx.addIssue({ code: 'custom', path: [input.x === undefined ? 'x' : 'y'], message: 'x and y go together' });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (required && input.element_index === undefined && input.x === undefined) {
|
|
51
|
+
ctx.addIssue({ code: 'custom', message: `Give exactly one target: element_index, or x and y${required ? '' : ' (or neither for the focused element)'}` });
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const target = { element_index: fields.element_index.optional(), x: fields.x.optional(), y: fields.y.optional() };
|
|
56
|
+
const define = (shape, rule) => ({ shape, target: rule });
|
|
57
|
+
const targeted = (shape, rule) => define({ ...target, ...shape }, rule);
|
|
58
|
+
/**
|
|
59
|
+
* Models fill every field of a tool. null, "" and a 0,0 point are filler; a real point sent next to an element is
|
|
60
|
+
* where the model looked, so the point is the target (a control under it is still pressed through accessibility).
|
|
61
|
+
*/
|
|
62
|
+
function dropFiller(input, optionalTarget = false) {
|
|
63
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input))
|
|
64
|
+
return input;
|
|
65
|
+
const kept = Object.fromEntries(Object.entries(input).filter(([, value]) => value !== null));
|
|
66
|
+
for (const name of ['modifiers', 'window_id'])
|
|
67
|
+
if (kept[name] === '')
|
|
68
|
+
delete kept[name];
|
|
69
|
+
const zeroPoint = kept.x === 0 && kept.y === 0;
|
|
70
|
+
const realPoint = kept.x !== undefined && kept.y !== undefined && !zeroPoint;
|
|
71
|
+
// The window itself (index 0) is no target for typing or keys, so all zeros there mean the focused element.
|
|
72
|
+
if (realPoint || (optionalTarget && kept.element_index === 0))
|
|
73
|
+
delete kept.element_index;
|
|
74
|
+
if (zeroPoint && (kept.element_index !== undefined || optionalTarget)) {
|
|
75
|
+
delete kept.x;
|
|
76
|
+
delete kept.y;
|
|
77
|
+
}
|
|
78
|
+
return kept;
|
|
79
|
+
}
|
|
80
|
+
function build(shape, rule) {
|
|
81
|
+
const object = z.object(shape).strict();
|
|
82
|
+
return z.preprocess((input) => dropFiller(input, rule === 'optional'), rule ? object.superRefine(checkTarget(rule === 'required')) : object);
|
|
83
|
+
}
|
|
84
|
+
/** Actions on one app, without the `app` field. */
|
|
85
|
+
const actions = {
|
|
86
|
+
click: targeted({ mouse_button: fields.mouse_button.default('left'), click_count: fields.click_count.default(1), modifiers: fields.modifiers.optional() }, 'required'),
|
|
87
|
+
type_text: define({ element_index: fields.element_index.optional(), text: fields.text }, 'optional'),
|
|
88
|
+
press_key: define({ key: fields.key, repeat: fields.repeat.default(1) }),
|
|
89
|
+
scroll: targeted({ direction: fields.direction, pages: fields.pages.default(1) }, 'required'),
|
|
90
|
+
drag: define({
|
|
91
|
+
from_x: coordinate.describe('Where the button goes down: horizontal pixel in the latest screenshot of this app.'), from_y: coordinate,
|
|
92
|
+
to_x: coordinate.describe('Where the button comes up.'), to_y: coordinate,
|
|
93
|
+
}),
|
|
94
|
+
set_value: define({ element_index: fields.element_index, value: fields.value }),
|
|
95
|
+
perform_secondary_action: define({ element_index: fields.element_index, secondary_action: fields.secondary_action }),
|
|
96
|
+
};
|
|
97
|
+
export const actionNames = Object.keys(actions);
|
|
98
|
+
/** The single tool for an action: the same fields with the target `app` first. */
|
|
99
|
+
const onApp = (name) => build({ app, ...actions[name].shape }, actions[name].target);
|
|
100
|
+
/** One step of computer_run: what to do, the element in words, and what must show afterwards. */
|
|
101
|
+
export const runStepShape = z.object({
|
|
102
|
+
do: z.enum(['click', 'type', 'set_value', 'key', 'scroll']),
|
|
103
|
+
target: z.string().min(1).max(300).optional()
|
|
104
|
+
.describe('The element in words, the way it reads on screen: its label and kind, and where it is when that matters ("the Export button", "the file name field of the dialog"). Needed for click, set_value and scroll; leave it out of type to type into the focus. A key goes to the focus and takes none.'),
|
|
105
|
+
text: z.string().max(20_000).optional().describe('The exact text for type and set_value.'),
|
|
106
|
+
key: chord().optional().describe('The chord for key, in xdotool syntax.'),
|
|
107
|
+
direction: fields.direction.optional().describe('For scroll.'),
|
|
108
|
+
expect: z.string().min(1).max(300).optional()
|
|
109
|
+
.describe('What the window shows once this step worked ("an export dialog is open"). The step is checked against it and tried another way when it does not hold.'),
|
|
110
|
+
}).strict();
|
|
111
|
+
const needs = {
|
|
112
|
+
click: ['target'], type: ['text'], set_value: ['target', 'text'], key: ['key'], scroll: ['target', 'direction'],
|
|
113
|
+
};
|
|
114
|
+
/** A key goes to the focus, so it has no target: one found for it would only be another way to press the key again. */
|
|
115
|
+
const uses = {
|
|
116
|
+
click: ['target'], type: ['target', 'text'], set_value: ['target', 'text'], key: ['key'], scroll: ['target', 'direction'],
|
|
117
|
+
};
|
|
118
|
+
export { pointsAtFocus, wordsIn };
|
|
119
|
+
/**
|
|
120
|
+
* A strict provider fills every field of every step: null and "" are filler, and so is any field the step's kind
|
|
121
|
+
* does not use, and a target of typing that names nothing but the focus, where typing without a target goes.
|
|
122
|
+
* An empty text for set_value is kept; it clears the field.
|
|
123
|
+
*/
|
|
124
|
+
function dropStepFiller(input) {
|
|
125
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input))
|
|
126
|
+
return input;
|
|
127
|
+
const step = input;
|
|
128
|
+
const used = uses[step.do];
|
|
129
|
+
const focusOnly = step.do === 'type' && typeof step.target === 'string' && pointsAtFocus(step.target)
|
|
130
|
+
&& wordsIn(step.target).every((word) => OF_THE_FOCUS.has(word));
|
|
131
|
+
return Object.fromEntries(Object.entries(step).filter(([name, value]) => value !== null && (value !== '' || (name === 'text' && step.do === 'set_value'))
|
|
132
|
+
&& (used === undefined || name === 'do' || name === 'expect' || used.includes(name))
|
|
133
|
+
&& !(name === 'target' && focusOnly)));
|
|
134
|
+
}
|
|
135
|
+
const runStep = z.preprocess(dropStepFiller, runStepShape.superRefine((step, ctx) => {
|
|
136
|
+
for (const field of needs[step.do]) {
|
|
137
|
+
if (step[field] === undefined || (field === 'text' && step.do === 'type' && step.text === ''))
|
|
138
|
+
ctx.addIssue({ code: 'custom', path: [field], message: `${step.do} needs ${field}` });
|
|
139
|
+
}
|
|
140
|
+
}));
|
|
141
|
+
const region = z.array(z.number().int().nonnegative()).length(4).refine(([x0 = 0, y0 = 0, x1 = 0, y1 = 0]) => x1 > x0 && y1 > y0, 'region must be [x0, y0, x1, y1] with x1 > x0 and y1 > y0')
|
|
142
|
+
.describe('[x0, y0, x1, y1] in the coordinate frame of the latest screenshot.');
|
|
143
|
+
const AFTER = ' Returns the technical outcome and the fresh app state; check that the intended change happened.';
|
|
144
|
+
export const computerTools = {
|
|
145
|
+
computer_status: {
|
|
146
|
+
description: 'Report whether Computer Use can work on this computer and which system permission is missing. Call it when a tool reports missing permissions; open_settings shows the user the settings pane to allow one.',
|
|
147
|
+
input: z.object({ open_settings: z.enum(['accessibility', 'screen_recording']).optional().describe('Open the system settings pane where the user allows this permission.') }).strict(),
|
|
148
|
+
},
|
|
149
|
+
computer_list_apps: {
|
|
150
|
+
description: 'List installed and running applications (and their windows on Windows) with the identifier to pass as `app`. No side effects.',
|
|
151
|
+
input: z.object({ query: z.string().max(256).optional().describe('Case-insensitive filter on name and identifier.'), limit: z.number().int().min(1).max(200).default(50) }).strict(),
|
|
152
|
+
},
|
|
153
|
+
computer_request_access: {
|
|
154
|
+
description: 'Ask the user, in one dialog, to let you control a set of applications for this conversation. Required before the single tools act on an app; computer_run asks for its own app. Browsers default to read-only and terminals to click-only; ask here for full control of them, for the clipboard and for system chords.',
|
|
155
|
+
input: z.object({
|
|
156
|
+
apps: z.array(app).min(1).max(32),
|
|
157
|
+
reason: z.string().min(1).max(500).describe('One sentence for the dialog: the task, not the mechanism.'),
|
|
158
|
+
clipboard_read: z.boolean().optional(),
|
|
159
|
+
clipboard_write: z.boolean().optional(),
|
|
160
|
+
system_key_combos: z.boolean().optional().describe('Also allow system chords such as quit, switch app or lock screen.'),
|
|
161
|
+
full_access: z.array(app).max(32).optional()
|
|
162
|
+
.describe('Apps from `apps` that need full control although their kind is restricted by default (browsers read-only, terminals click-only). The user sees this list before approving.'),
|
|
163
|
+
}).strict().refine((input) => (input.full_access ?? []).every((name) => input.apps.includes(name)), {
|
|
164
|
+
message: 'full_access may only name apps listed in apps', path: ['full_access'],
|
|
165
|
+
}),
|
|
166
|
+
},
|
|
167
|
+
computer_get_app_state: {
|
|
168
|
+
description: 'Observe one app: its focused window as indexed accessibility elements plus a screenshot. Launches the app in the background if needed and waits for it to settle. Returns only what changed since your last look unless disable_diff is true. Call it before the first action; every action returns the fresh state itself, so look again only when that is not enough.',
|
|
169
|
+
input: z.preprocess((input) => dropFiller(input), z.object({
|
|
170
|
+
app,
|
|
171
|
+
window_id: z.string().min(1).max(160).optional().describe('Windows only: a window from computer_list_apps. Leave it out for the app\'s main window.'),
|
|
172
|
+
disable_diff: z.boolean().default(false),
|
|
173
|
+
}).strict()),
|
|
174
|
+
},
|
|
175
|
+
computer_click: { description: `Click an element by element_index (preferred) or a point in the latest screenshot.${AFTER}`, input: onApp('click') },
|
|
176
|
+
computer_type_text: { description: `Type text into the focused element of the app, or into element_index. On a canvas or a spreadsheet cell, click the place first, then type with no element_index.${AFTER}`, input: onApp('type_text') },
|
|
177
|
+
computer_press_key: { description: `Press one key or chord in the app, in xdotool syntax.${AFTER}`, input: onApp('press_key') },
|
|
178
|
+
computer_scroll: { description: `Scroll an element or the content under a point.${AFTER}`, input: onApp('scroll') },
|
|
179
|
+
computer_drag: { description: `Drag with the left button from one screenshot point to another: moving or trimming clips on a timeline, sliders, selections. The grab point decides what happens (a clip's edge trims, its body moves), so aim it exactly.${AFTER}`, input: onApp('drag') },
|
|
180
|
+
computer_set_value: { description: `Set the value of an editable element directly (text fields, sliders, steppers).${AFTER}`, input: onApp('set_value') },
|
|
181
|
+
computer_perform_secondary_action: { description: `Run an accessibility action an element lists besides a click (show menu, expand, increment, cancel).${AFTER}`, input: onApp('perform_secondary_action') },
|
|
182
|
+
computer_run: {
|
|
183
|
+
description: 'Run several steps on one app in a row, without a round trip per step. Describe each element in words; the element is found on the live window, also on a screen you have not seen yet, each `expect` is checked, and a step that does not work is tried another way. Stops at the first step that cannot be done and returns what was done plus the fresh app state. Use it whenever the next steps are known; use the single tools for work by x and y. On an app not granted yet, approving this call grants the app for the conversation at its default level (browsers read-only, terminals click-only). Steps that send keys or text into a browser or terminal are refused at that level: call computer_request_access with full_access for it first, in the same response.',
|
|
184
|
+
input: z.object({
|
|
185
|
+
app,
|
|
186
|
+
goal: z.string().min(1).max(500).describe('What these steps achieve, in one sentence. It tells similar elements apart.'),
|
|
187
|
+
steps: z.array(runStep).min(1).max(30),
|
|
188
|
+
}).strict(),
|
|
189
|
+
},
|
|
190
|
+
computer_zoom: {
|
|
191
|
+
description: 'Look closer at a region of the latest screenshot of an app, to read small text or find an exact edge. Reading aid only: coordinates keep referring to the screenshot, never to the zoomed image.',
|
|
192
|
+
input: z.object({ app, region }).strict(),
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/contract/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"untrusted.d.ts","sourceRoot":"","sources":["../../src/contract/untrusted.ts"],"names":[],"mappings":"AAEA,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAI/D"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const CLOSING_TAG = /<\/(app_content)(\s*)>/gi;
|
|
2
|
+
/** Fence text read from an application so the model treats it as data, never as instructions. */
|
|
3
|
+
export function wrapUntrusted(text, app) {
|
|
4
|
+
const attribute = app.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<');
|
|
5
|
+
const body = text.replace(CLOSING_TAG, '<\\/$1$2>');
|
|
6
|
+
return `<app_content app="${attribute}" trust="untrusted">\n${body}\n</app_content>`;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=untrusted.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"untrusted.js","sourceRoot":"","sources":["../../src/contract/untrusted.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG,0BAA0B,CAAC;AAE/C,iGAAiG;AACjG,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,GAAW;IACrD,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3F,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACpD,OAAO,qBAAqB,SAAS,yBAAyB,IAAI,kBAAkB,CAAC;AACvF,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const manifestSchema: (protocolVersion: number) => z.ZodObject<{
|
|
3
|
+
protocolVersion: z.ZodLiteral<number>;
|
|
4
|
+
/** Absent for Windows and macOS, which the architecture alone tells apart. */
|
|
5
|
+
os: z.ZodOptional<z.ZodLiteral<"linux">>;
|
|
6
|
+
architecture: z.ZodEnum<["x64", "arm64", "x86_64", "universal"]>;
|
|
7
|
+
sha256: z.ZodString;
|
|
8
|
+
}, "strict", z.ZodTypeAny, {
|
|
9
|
+
sha256: string;
|
|
10
|
+
protocolVersion: number;
|
|
11
|
+
architecture: "x64" | "arm64" | "x86_64" | "universal";
|
|
12
|
+
os?: "linux" | undefined;
|
|
13
|
+
}, {
|
|
14
|
+
sha256: string;
|
|
15
|
+
protocolVersion: number;
|
|
16
|
+
architecture: "x64" | "arm64" | "x86_64" | "universal";
|
|
17
|
+
os?: "linux" | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
type Architecture = z.infer<ReturnType<typeof manifestSchema>>['architecture'];
|
|
20
|
+
/**
|
|
21
|
+
* The digest a manifest records. A Windows or Linux executable is hashed whole. A Mach-O
|
|
22
|
+
* is hashed without its code signatures, because packaging the desktop app signs
|
|
23
|
+
* every executable again after the manifest was written; macOS itself refuses to
|
|
24
|
+
* run code whose signature does not match.
|
|
25
|
+
*/
|
|
26
|
+
export declare function helperDigest(bytes: Buffer): string;
|
|
27
|
+
export declare function validateHelperArtifact(bytes: Buffer, manifest: unknown, protocolVersion: number): void;
|
|
28
|
+
export declare function verifyHelperArtifact(executable: string, protocolVersion: number): Promise<void>;
|
|
29
|
+
/** Written by the native build next to the executable it just produced. */
|
|
30
|
+
export declare function writeHelperManifest(executable: string, manifest: {
|
|
31
|
+
protocolVersion: number;
|
|
32
|
+
architecture: Architecture;
|
|
33
|
+
os?: 'linux';
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Why a helper cannot be used, known without reading the executable: decides
|
|
37
|
+
* which tools a plugin offers. The full check runs before every launch.
|
|
38
|
+
*/
|
|
39
|
+
export declare function helperProblem(executable: string, protocolVersion: number): string | undefined;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=artifact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../src/helper/artifact.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,QAAA,MAAM,cAAc,GAAI,iBAAiB,MAAM;;IAE7C,8EAA8E;;;;;;;;;;;;;;EAIrE,CAAC;AACZ,KAAK,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;AA4E/E;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWlD;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,CAMtG;AAgCD,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOrG;AAED,2EAA2E;AAC3E,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,YAAY,CAAC;IAAC,EAAE,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5J;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAc7F"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { constants, existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { lstat, open, rename, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
const manifestSchema = (protocolVersion) => z.object({
|
|
6
|
+
protocolVersion: z.literal(protocolVersion),
|
|
7
|
+
/** Absent for Windows and macOS, which the architecture alone tells apart. */
|
|
8
|
+
os: z.literal('linux').optional(),
|
|
9
|
+
architecture: z.enum(['x64', 'arm64', 'x86_64', 'universal']),
|
|
10
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
11
|
+
}).strict();
|
|
12
|
+
const MACH_O_64 = 0xfeedfacf;
|
|
13
|
+
const MACH_O_FAT = 0xcafebabe;
|
|
14
|
+
const CPU = { arm64: 0x0100000c, x86_64: 0x01000007 };
|
|
15
|
+
function assertWindowsX64(bytes) {
|
|
16
|
+
if (bytes.length < 64 || bytes.toString('ascii', 0, 2) !== 'MZ')
|
|
17
|
+
throw new Error('Invalid Computer Use executable');
|
|
18
|
+
const offset = bytes.readUInt32LE(60);
|
|
19
|
+
if (offset > bytes.length - 6 || bytes.toString('ascii', offset, offset + 4) !== 'PE\0\0' || bytes.readUInt16LE(offset + 4) !== 0x8664) {
|
|
20
|
+
throw new Error('Computer Use requires a Windows x64 executable');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const ELF_MACHINE = { x64: 62, arm64: 183 };
|
|
24
|
+
function assertLinux(bytes, architecture) {
|
|
25
|
+
const machine = ELF_MACHINE[architecture];
|
|
26
|
+
// 64-bit, little-endian ELF for the named machine.
|
|
27
|
+
const matches = machine !== undefined && bytes.length >= 20 && bytes.toString('latin1', 0, 4) === '\x7fELF'
|
|
28
|
+
&& bytes[4] === 2 && bytes[5] === 1 && bytes.readUInt16LE(18) === machine;
|
|
29
|
+
if (!matches)
|
|
30
|
+
throw new Error(`Computer Use requires a Linux ${architecture} executable`);
|
|
31
|
+
}
|
|
32
|
+
function assertMacOS(bytes, architecture) {
|
|
33
|
+
const cpus = (machOSlices(bytes) ?? []).map(({ cpu }) => cpu);
|
|
34
|
+
const required = architecture === 'universal' ? [CPU.arm64, CPU.x86_64] : [CPU[architecture]];
|
|
35
|
+
if (!required.every((cpu) => cpus.includes(cpu)))
|
|
36
|
+
throw new Error(`Computer Use requires a macOS ${architecture} executable`);
|
|
37
|
+
}
|
|
38
|
+
const LC_SEGMENT_64 = 0x19;
|
|
39
|
+
const LC_CODE_SIGNATURE = 0x1d;
|
|
40
|
+
const invalid = () => new Error('Invalid Computer Use executable');
|
|
41
|
+
/** One Mach-O slice without its code signature, with the fields signing rewrites set to zero. */
|
|
42
|
+
function unsignedSlice(slice) {
|
|
43
|
+
if (slice.length < 32 || slice.readUInt32LE(0) !== MACH_O_64)
|
|
44
|
+
throw invalid();
|
|
45
|
+
const copy = Buffer.from(slice);
|
|
46
|
+
const commands = copy.readUInt32LE(16);
|
|
47
|
+
if (32 + copy.readUInt32LE(20) > copy.length)
|
|
48
|
+
throw invalid();
|
|
49
|
+
let end = copy.length;
|
|
50
|
+
let offset = 32;
|
|
51
|
+
for (let index = 0; index < commands; index++) {
|
|
52
|
+
if (offset + 8 > copy.length)
|
|
53
|
+
throw invalid();
|
|
54
|
+
const command = copy.readUInt32LE(offset);
|
|
55
|
+
const size = copy.readUInt32LE(offset + 4);
|
|
56
|
+
if (size < 8 || offset + size > copy.length)
|
|
57
|
+
throw invalid();
|
|
58
|
+
if (command === LC_CODE_SIGNATURE && size >= 16) {
|
|
59
|
+
end = Math.min(end, copy.readUInt32LE(offset + 8));
|
|
60
|
+
copy.fill(0, offset + 8, offset + 16);
|
|
61
|
+
}
|
|
62
|
+
else if (command === LC_SEGMENT_64 && size >= 72 && copy.toString('latin1', offset + 8, offset + 24).replace(/\0+$/, '') === '__LINKEDIT') {
|
|
63
|
+
// The signature is the tail of __LINKEDIT, so its sizes move with it.
|
|
64
|
+
copy.fill(0, offset + 32, offset + 40);
|
|
65
|
+
copy.fill(0, offset + 48, offset + 56);
|
|
66
|
+
}
|
|
67
|
+
offset += size;
|
|
68
|
+
}
|
|
69
|
+
return copy.subarray(0, end);
|
|
70
|
+
}
|
|
71
|
+
/** The slices of a thin or fat Mach-O with their CPU type; `undefined` when the bytes are not Mach-O. */
|
|
72
|
+
function machOSlices(bytes) {
|
|
73
|
+
if (bytes.length < 8)
|
|
74
|
+
return undefined;
|
|
75
|
+
if (bytes.readUInt32LE(0) === MACH_O_64)
|
|
76
|
+
return [{ cpu: bytes.readUInt32LE(4), slice: bytes }];
|
|
77
|
+
if (bytes.readUInt32BE(0) !== MACH_O_FAT)
|
|
78
|
+
return undefined;
|
|
79
|
+
const count = bytes.readUInt32BE(4);
|
|
80
|
+
if (count > 16 || 8 + count * 20 > bytes.length)
|
|
81
|
+
throw invalid();
|
|
82
|
+
return Array.from({ length: count }, (_, index) => {
|
|
83
|
+
const entry = 8 + index * 20;
|
|
84
|
+
const start = bytes.readUInt32BE(entry + 8);
|
|
85
|
+
const size = bytes.readUInt32BE(entry + 12);
|
|
86
|
+
if (start + size > bytes.length)
|
|
87
|
+
throw invalid();
|
|
88
|
+
return { cpu: bytes.readUInt32BE(entry), slice: bytes.subarray(start, start + size) };
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The digest a manifest records. A Windows or Linux executable is hashed whole. A Mach-O
|
|
93
|
+
* is hashed without its code signatures, because packaging the desktop app signs
|
|
94
|
+
* every executable again after the manifest was written; macOS itself refuses to
|
|
95
|
+
* run code whose signature does not match.
|
|
96
|
+
*/
|
|
97
|
+
export function helperDigest(bytes) {
|
|
98
|
+
const hash = createHash('sha256');
|
|
99
|
+
const slices = machOSlices(bytes);
|
|
100
|
+
if (!slices)
|
|
101
|
+
return hash.update(bytes).digest('hex');
|
|
102
|
+
for (const { cpu, slice } of slices) {
|
|
103
|
+
const header = Buffer.alloc(4);
|
|
104
|
+
header.writeUInt32BE(cpu);
|
|
105
|
+
// An empty fat entry (synthetic headers in tests) has no code to hash.
|
|
106
|
+
hash.update(header).update(slice.length === 0 ? slice : unsignedSlice(slice));
|
|
107
|
+
}
|
|
108
|
+
return hash.digest('hex');
|
|
109
|
+
}
|
|
110
|
+
export function validateHelperArtifact(bytes, manifest, protocolVersion) {
|
|
111
|
+
const expected = manifestSchema(protocolVersion).parse(manifest);
|
|
112
|
+
if (expected.os === 'linux')
|
|
113
|
+
assertLinux(bytes, expected.architecture);
|
|
114
|
+
else if (expected.architecture === 'x64')
|
|
115
|
+
assertWindowsX64(bytes);
|
|
116
|
+
else
|
|
117
|
+
assertMacOS(bytes, expected.architecture);
|
|
118
|
+
if (helperDigest(bytes) !== expected.sha256)
|
|
119
|
+
throw new Error('Computer Use executable checksum mismatch');
|
|
120
|
+
}
|
|
121
|
+
// POSIX-only; Node leaves it undefined on Windows.
|
|
122
|
+
const O_NOFOLLOW = constants.O_NOFOLLOW ?? 0;
|
|
123
|
+
/**
|
|
124
|
+
* Read a regular file no larger than `limit`, checking the open handle rather
|
|
125
|
+
* than the path so the bytes that are validated are the bytes that were
|
|
126
|
+
* measured. A `stat` followed by `readFile` can be repointed in between, which
|
|
127
|
+
* would let an oversized file through the size guard.
|
|
128
|
+
*/
|
|
129
|
+
async function readBounded(file, limit) {
|
|
130
|
+
if (O_NOFOLLOW === 0 && (await lstat(file)).isSymbolicLink()) {
|
|
131
|
+
throw new Error('Computer Use artifact exceeds size limit');
|
|
132
|
+
}
|
|
133
|
+
let handle;
|
|
134
|
+
try {
|
|
135
|
+
handle = await open(file, constants.O_RDONLY | O_NOFOLLOW);
|
|
136
|
+
const info = await handle.stat();
|
|
137
|
+
if (!info.isFile() || info.size > limit)
|
|
138
|
+
throw new Error('Computer Use artifact exceeds size limit');
|
|
139
|
+
return await handle.readFile();
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
// O_NOFOLLOW reports a symlink as ELOOP.
|
|
143
|
+
if (error.code === 'ELOOP') {
|
|
144
|
+
throw new Error('Computer Use artifact exceeds size limit');
|
|
145
|
+
}
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
await handle?.close();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export async function verifyHelperArtifact(executable, protocolVersion) {
|
|
153
|
+
const manifestPath = executable + '.json';
|
|
154
|
+
const [bytes, manifest] = await Promise.all([
|
|
155
|
+
readBounded(executable, 32_000_000),
|
|
156
|
+
readBounded(manifestPath, 4096),
|
|
157
|
+
]);
|
|
158
|
+
validateHelperArtifact(bytes, JSON.parse(manifest.toString('utf8')), protocolVersion);
|
|
159
|
+
}
|
|
160
|
+
/** Written by the native build next to the executable it just produced. */
|
|
161
|
+
export async function writeHelperManifest(executable, manifest) {
|
|
162
|
+
const sha256 = helperDigest(await readBounded(executable, 32_000_000));
|
|
163
|
+
const temporary = `${executable}.json.tmp`;
|
|
164
|
+
await writeFile(temporary, JSON.stringify({ ...manifest, sha256 }));
|
|
165
|
+
await rename(temporary, `${executable}.json`);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Why a helper cannot be used, known without reading the executable: decides
|
|
169
|
+
* which tools a plugin offers. The full check runs before every launch.
|
|
170
|
+
*/
|
|
171
|
+
export function helperProblem(executable, protocolVersion) {
|
|
172
|
+
if (!existsSync(executable))
|
|
173
|
+
return 'The Computer Use helper is missing.';
|
|
174
|
+
let manifest;
|
|
175
|
+
try {
|
|
176
|
+
manifest = JSON.parse(readFileSync(`${executable}.json`, 'utf8'));
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return 'The Computer Use helper has no readable manifest.';
|
|
180
|
+
}
|
|
181
|
+
const found = z.object({ protocolVersion: z.number().int() }).safeParse(manifest);
|
|
182
|
+
if (!found.success)
|
|
183
|
+
return 'The Computer Use helper has no readable manifest.';
|
|
184
|
+
if (found.data.protocolVersion !== protocolVersion) {
|
|
185
|
+
return `The Computer Use helper speaks protocol ${found.data.protocolVersion}; this version needs ${protocolVersion}.`;
|
|
186
|
+
}
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact.js","sourceRoot":"","sources":["../../src/helper/artifact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Per-frame byte ceiling shared by every native helper. */
|
|
3
|
+
export declare const MAX_FRAME_BYTES = 3000000;
|
|
4
|
+
export declare const controlCommandSchema: z.ZodEnum<["pause", "resume", "stop", "takeover"]>;
|
|
5
|
+
/** The first helper protocol that understands `takeover`; older helpers are paused instead. */
|
|
6
|
+
export declare const TAKEOVER_PROTOCOL_VERSION = 5;
|
|
7
|
+
export declare const controlStates: readonly ["idle", "background", "foreground", "waiting_for_focus", "paused_by_user", "recovering", "stopped", "failed"];
|
|
8
|
+
/** A request-correlated state change; the transport suspends the request deadline while waiting. */
|
|
9
|
+
export declare const controlStateSchemaFor: (version: number) => z.ZodObject<{
|
|
10
|
+
version: z.ZodLiteral<number>;
|
|
11
|
+
event: z.ZodLiteral<"control_state">;
|
|
12
|
+
id: z.ZodString;
|
|
13
|
+
state: z.ZodEnum<["idle", "background", "foreground", "waiting_for_focus", "paused_by_user", "recovering", "stopped", "failed"]>;
|
|
14
|
+
}, "strict", z.ZodTypeAny, {
|
|
15
|
+
id: string;
|
|
16
|
+
state: "background" | "failed" | "idle" | "foreground" | "waiting_for_focus" | "paused_by_user" | "recovering" | "stopped";
|
|
17
|
+
version: number;
|
|
18
|
+
event: "control_state";
|
|
19
|
+
}, {
|
|
20
|
+
id: string;
|
|
21
|
+
state: "background" | "failed" | "idle" | "foreground" | "waiting_for_focus" | "paused_by_user" | "recovering" | "stopped";
|
|
22
|
+
version: number;
|
|
23
|
+
event: "control_state";
|
|
24
|
+
}>;
|
|
25
|
+
export type ControlState = z.infer<ReturnType<typeof controlStateSchemaFor>>;
|
|
26
|
+
export declare const responseSchemaFor: (version: number) => z.ZodDiscriminatedUnion<"ok", [z.ZodObject<{
|
|
27
|
+
version: z.ZodLiteral<number>;
|
|
28
|
+
id: z.ZodString;
|
|
29
|
+
ok: z.ZodLiteral<true>;
|
|
30
|
+
result: z.ZodUnknown;
|
|
31
|
+
}, "strict", z.ZodTypeAny, {
|
|
32
|
+
id: string;
|
|
33
|
+
version: number;
|
|
34
|
+
ok: true;
|
|
35
|
+
result?: unknown;
|
|
36
|
+
}, {
|
|
37
|
+
id: string;
|
|
38
|
+
version: number;
|
|
39
|
+
ok: true;
|
|
40
|
+
result?: unknown;
|
|
41
|
+
}>, z.ZodObject<{
|
|
42
|
+
version: z.ZodLiteral<number>;
|
|
43
|
+
id: z.ZodString;
|
|
44
|
+
ok: z.ZodLiteral<false>;
|
|
45
|
+
error: z.ZodObject<{
|
|
46
|
+
code: z.ZodString;
|
|
47
|
+
message: z.ZodString;
|
|
48
|
+
}, "strict", z.ZodTypeAny, {
|
|
49
|
+
code: string;
|
|
50
|
+
message: string;
|
|
51
|
+
}, {
|
|
52
|
+
code: string;
|
|
53
|
+
message: string;
|
|
54
|
+
}>;
|
|
55
|
+
}, "strict", z.ZodTypeAny, {
|
|
56
|
+
id: string;
|
|
57
|
+
version: number;
|
|
58
|
+
error: {
|
|
59
|
+
code: string;
|
|
60
|
+
message: string;
|
|
61
|
+
};
|
|
62
|
+
ok: false;
|
|
63
|
+
}, {
|
|
64
|
+
id: string;
|
|
65
|
+
version: number;
|
|
66
|
+
error: {
|
|
67
|
+
code: string;
|
|
68
|
+
message: string;
|
|
69
|
+
};
|
|
70
|
+
ok: false;
|
|
71
|
+
}>]>;
|
|
72
|
+
/** A byte-bounded decoder; UTF-8 is decoded only after a complete frame arrives. */
|
|
73
|
+
export declare class JsonLineDecoder {
|
|
74
|
+
private readonly limit;
|
|
75
|
+
private pending;
|
|
76
|
+
constructor(limit: number);
|
|
77
|
+
push(bytes: Buffer): unknown[];
|
|
78
|
+
finish(): void;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/helper/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,4DAA4D;AAC5D,eAAO,MAAM,eAAe,UAAY,CAAC;AAGzC,eAAO,MAAM,oBAAoB,oDAAkD,CAAC;AACpF,+FAA+F;AAC/F,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAC3C,eAAO,MAAM,aAAa,yHAA0H,CAAC;AAErJ,oGAAoG;AACpG,eAAO,MAAM,qBAAqB,GAAI,SAAS,MAAM;;;;;;;;;;;;;;;EAE1C,CAAC;AACZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC;AAE7E,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAI/C,CAAC;AAEH,oFAAoF;AACpF,qBAAa,eAAe;IAEd,OAAO,CAAC,QAAQ,CAAC,KAAK;IADlC,OAAO,CAAC,OAAO,CAAmB;gBACL,KAAK,EAAE,MAAM;IAE1C,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE;IAkB9B,MAAM,IAAI,IAAI;CAGf"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Per-frame byte ceiling shared by every native helper. */
|
|
3
|
+
export const MAX_FRAME_BYTES = 3_000_000;
|
|
4
|
+
const idSchema = z.string().min(1).max(160);
|
|
5
|
+
export const controlCommandSchema = z.enum(['pause', 'resume', 'stop', 'takeover']);
|
|
6
|
+
/** The first helper protocol that understands `takeover`; older helpers are paused instead. */
|
|
7
|
+
export const TAKEOVER_PROTOCOL_VERSION = 5;
|
|
8
|
+
export const controlStates = ['idle', 'background', 'foreground', 'waiting_for_focus', 'paused_by_user', 'recovering', 'stopped', 'failed'];
|
|
9
|
+
/** A request-correlated state change; the transport suspends the request deadline while waiting. */
|
|
10
|
+
export const controlStateSchemaFor = (version) => z.object({
|
|
11
|
+
version: z.literal(version), event: z.literal('control_state'), id: idSchema, state: z.enum(controlStates),
|
|
12
|
+
}).strict();
|
|
13
|
+
export const responseSchemaFor = (version) => z.discriminatedUnion('ok', [
|
|
14
|
+
z.object({ version: z.literal(version), id: idSchema, ok: z.literal(true), result: z.unknown() }).strict(),
|
|
15
|
+
z.object({ version: z.literal(version), id: idSchema, ok: z.literal(false),
|
|
16
|
+
error: z.object({ code: z.string().max(80), message: z.string().max(2048) }).strict() }).strict(),
|
|
17
|
+
]);
|
|
18
|
+
/** A byte-bounded decoder; UTF-8 is decoded only after a complete frame arrives. */
|
|
19
|
+
export class JsonLineDecoder {
|
|
20
|
+
limit;
|
|
21
|
+
pending = Buffer.alloc(0);
|
|
22
|
+
constructor(limit) {
|
|
23
|
+
this.limit = limit;
|
|
24
|
+
}
|
|
25
|
+
push(bytes) {
|
|
26
|
+
const frames = [];
|
|
27
|
+
let offset = 0;
|
|
28
|
+
while (offset < bytes.length) {
|
|
29
|
+
const newline = bytes.indexOf(10, offset);
|
|
30
|
+
const end = newline < 0 ? bytes.length : newline;
|
|
31
|
+
const part = bytes.subarray(offset, end);
|
|
32
|
+
if (this.pending.length + part.length > this.limit)
|
|
33
|
+
throw new Error('Computer Use protocol frame limit exceeded');
|
|
34
|
+
this.pending = Buffer.concat([this.pending, part]);
|
|
35
|
+
if (newline < 0)
|
|
36
|
+
break;
|
|
37
|
+
const text = new TextDecoder('utf-8', { fatal: true }).decode(this.pending);
|
|
38
|
+
frames.push(JSON.parse(text));
|
|
39
|
+
this.pending = Buffer.alloc(0);
|
|
40
|
+
offset = newline + 1;
|
|
41
|
+
}
|
|
42
|
+
return frames;
|
|
43
|
+
}
|
|
44
|
+
finish() {
|
|
45
|
+
if (this.pending.length)
|
|
46
|
+
throw new Error('Computer Use protocol incomplete frame');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=protocol.js.map
|