@hybridlabor-api/aos 4.0.2 → 4.1.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/.claude/agents/database-reviewer.md +109 -0
- package/.claude/agents/go-build-resolver.md +112 -0
- package/.claude/agents/opensource-forker.md +216 -0
- package/.claude/agents/opensource-sanitizer.md +206 -0
- package/.claude/agents/security-reviewer.md +126 -0
- package/.claude/agents/silent-failure-hunter.md +68 -0
- package/CLAUDE.md +15 -0
- package/README.md +0 -13
- package/THIRD_PARTY_NOTICES.md +133 -0
- package/package.json +4 -2
- package/skills/basic/bdbmediastorm/SKILL.md +7 -1
- package/skills/basic/startcycle/SKILL.md +2 -0
- package/skills/bdbrainstorm/SKILL.md +1 -0
- package/skills/global_config/plan-canvas/SKILL.md +233 -0
- package/skills/global_config/plan-canvas/scripts/lib/loopback-guard.js +59 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/markdown.js +301 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/sdk.js +239 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/server.js +636 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/sessions.js +271 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/ui.js +630 -0
- package/skills/global_config/plan-canvas/scripts/plan-canvas.js +419 -0
- package/.agents/skills/firecrawl/SKILL.md +0 -149
- package/.agents/skills/firecrawl/rules/install.md +0 -82
- package/.agents/skills/firecrawl/rules/security.md +0 -26
- package/.agents/skills/firecrawl-agent/SKILL.md +0 -58
- package/.agents/skills/firecrawl-build/SKILL.md +0 -39
- package/.agents/skills/firecrawl-build-interact/SKILL.md +0 -68
- package/.agents/skills/firecrawl-build-onboarding/SKILL.md +0 -103
- package/.agents/skills/firecrawl-build-onboarding/references/auth-flow.md +0 -39
- package/.agents/skills/firecrawl-build-onboarding/references/project-setup.md +0 -20
- package/.agents/skills/firecrawl-build-onboarding/references/sdk-installation.md +0 -17
- package/.agents/skills/firecrawl-build-scrape/SKILL.md +0 -69
- package/.agents/skills/firecrawl-build-search/SKILL.md +0 -69
- package/.agents/skills/firecrawl-crawl/SKILL.md +0 -59
- package/.agents/skills/firecrawl-download/SKILL.md +0 -70
- package/.agents/skills/firecrawl-interact/SKILL.md +0 -84
- package/.agents/skills/firecrawl-map/SKILL.md +0 -51
- package/.agents/skills/firecrawl-scrape/SKILL.md +0 -69
- package/.agents/skills/firecrawl-search/SKILL.md +0 -60
- package/docs/sessions/AUDIT-HANDOVER-2026-08-28.md +0 -169
- package/docs/sessions/BDB_REMOTEOS_MCP_HANDOVER.md +0 -130
- package/docs/sessions/SESSION-HANDOVER-v3.13.md +0 -249
- package/mcps/RhinoMCP/cc-plugin/.claude/settings.json +0 -10
- package/mcps/after-effects-mcp/build/index.js +0 -840
- package/mcps/after-effects-mcp/build/scripts/applyEffect.jsx +0 -153
- package/mcps/after-effects-mcp/build/scripts/applyEffectTemplate.jsx +0 -218
- package/mcps/after-effects-mcp/build/scripts/createComposition.jsx +0 -71
- package/mcps/after-effects-mcp/build/scripts/createShapeLayer.jsx +0 -147
- package/mcps/after-effects-mcp/build/scripts/createSolidLayer.jsx +0 -114
- package/mcps/after-effects-mcp/build/scripts/createTextLayer.jsx +0 -115
- package/mcps/after-effects-mcp/build/scripts/getLayerInfo.jsx +0 -192
- package/mcps/after-effects-mcp/build/scripts/getProjectInfo.jsx +0 -90
- package/mcps/after-effects-mcp/build/scripts/listCompositions.jsx +0 -50
- package/mcps/after-effects-mcp/build/scripts/mcp-bridge-auto.jsx +0 -1773
- package/mcps/after-effects-mcp/build/scripts/setLayerProperties.jsx +0 -160
- package/mcps/bdb-remoteos-mcp/queue.db +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/__init__.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/incus_client.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/main.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/queue.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/schemas.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/server.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/src/bdb_remoteos_mcp/__pycache__/webhook.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/tests/__pycache__/mock_incus.cpython-312.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/tests/__pycache__/test_mcp_server.cpython-312-pytest-9.1.1.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/tests/__pycache__/test_security_redteam.cpython-312-pytest-9.1.1.pyc +0 -0
- package/mcps/bdb-remoteos-mcp/tests/__pycache__/test_webhook.cpython-312-pytest-9.1.1.pyc +0 -0
- package/mcps/computer-use-mcp/dist/client.d.ts +0 -150
- package/mcps/computer-use-mcp/dist/client.js +0 -136
- package/mcps/computer-use-mcp/dist/entrypoint.d.ts +0 -16
- package/mcps/computer-use-mcp/dist/entrypoint.js +0 -26
- package/mcps/computer-use-mcp/dist/native.d.ts +0 -212
- package/mcps/computer-use-mcp/dist/native.js +0 -50
- package/mcps/computer-use-mcp/dist/server.d.ts +0 -32
- package/mcps/computer-use-mcp/dist/server.js +0 -342
- package/mcps/computer-use-mcp/dist/session.d.ts +0 -101
- package/mcps/computer-use-mcp/dist/session.js +0 -2372
- package/skills/bdbsaastraining/scripts/__pycache__/build_profile.cpython-314.pyc +0 -0
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Native NAPI module loader — loads the compiled .node addon.
|
|
3
|
-
* Supports macOS (darwin) and Windows (win32) with platform-specific binaries.
|
|
4
|
-
*/
|
|
5
|
-
export interface AXBounds {
|
|
6
|
-
x: number;
|
|
7
|
-
y: number;
|
|
8
|
-
width: number;
|
|
9
|
-
height: number;
|
|
10
|
-
}
|
|
11
|
-
export interface AXElement {
|
|
12
|
-
role: string;
|
|
13
|
-
label: string | null;
|
|
14
|
-
value: string | null;
|
|
15
|
-
bounds: AXBounds;
|
|
16
|
-
actions: string[];
|
|
17
|
-
/** Present on full tree nodes; omitted by flat find_element results. */
|
|
18
|
-
children?: AXElement[];
|
|
19
|
-
/** Present on find_element results — indices from the walk root. */
|
|
20
|
-
path?: number[];
|
|
21
|
-
/** Set when a subtree or the whole tree hit the depth / node cap. */
|
|
22
|
-
truncated?: boolean;
|
|
23
|
-
}
|
|
24
|
-
export interface MenuItem {
|
|
25
|
-
title: string;
|
|
26
|
-
enabled: boolean;
|
|
27
|
-
shortcut?: string;
|
|
28
|
-
submenu?: MenuItem[];
|
|
29
|
-
}
|
|
30
|
-
export interface MenuBarEntry {
|
|
31
|
-
title: string;
|
|
32
|
-
enabled: boolean;
|
|
33
|
-
items: MenuItem[];
|
|
34
|
-
}
|
|
35
|
-
export interface WindowRecord {
|
|
36
|
-
windowId: number;
|
|
37
|
-
bundleId: string | null;
|
|
38
|
-
displayName: string;
|
|
39
|
-
pid: number;
|
|
40
|
-
title: string | null;
|
|
41
|
-
bounds: AXBounds;
|
|
42
|
-
isOnScreen: boolean;
|
|
43
|
-
isFocused: boolean;
|
|
44
|
-
displayId: number;
|
|
45
|
-
}
|
|
46
|
-
export interface NativeModule {
|
|
47
|
-
mouseMove(x: number, y: number): void;
|
|
48
|
-
mouseClick(x: number, y: number, button: string, count: number): void;
|
|
49
|
-
mouseButton(action: string, x: number, y: number): void;
|
|
50
|
-
mouseScroll(dy: number, dx: number): void;
|
|
51
|
-
mouseDrag(x: number, y: number): void;
|
|
52
|
-
cursorPosition(): {
|
|
53
|
-
x: number;
|
|
54
|
-
y: number;
|
|
55
|
-
};
|
|
56
|
-
keyPress(combo: string, repeat?: number): void;
|
|
57
|
-
typeText(text: string): void;
|
|
58
|
-
holdKey(keys: string[], durationMs: number): void;
|
|
59
|
-
activateApp(bundleId: string, timeoutMs?: number): {
|
|
60
|
-
bundleId: string;
|
|
61
|
-
activated: boolean;
|
|
62
|
-
displayName?: string;
|
|
63
|
-
};
|
|
64
|
-
getFrontmostApp(): {
|
|
65
|
-
bundleId: string;
|
|
66
|
-
displayName: string;
|
|
67
|
-
pid: number;
|
|
68
|
-
} | null;
|
|
69
|
-
getWindow(windowId: number): WindowRecord | null;
|
|
70
|
-
getCursorWindow(): WindowRecord | null;
|
|
71
|
-
activateWindow(windowId: number, timeoutMs?: number): {
|
|
72
|
-
windowId: number;
|
|
73
|
-
activated: boolean;
|
|
74
|
-
reason: string | null;
|
|
75
|
-
};
|
|
76
|
-
listWindows(bundleId?: string): Array<WindowRecord>;
|
|
77
|
-
listRunningApps(): Array<{
|
|
78
|
-
bundleId: string;
|
|
79
|
-
displayName: string;
|
|
80
|
-
pid: number;
|
|
81
|
-
isHidden: boolean;
|
|
82
|
-
}>;
|
|
83
|
-
hideApp(bundleId: string): boolean;
|
|
84
|
-
unhideApp(bundleId: string): boolean;
|
|
85
|
-
getDisplaySize(displayId?: number): {
|
|
86
|
-
width: number;
|
|
87
|
-
height: number;
|
|
88
|
-
pixelWidth: number;
|
|
89
|
-
pixelHeight: number;
|
|
90
|
-
scaleFactor: number;
|
|
91
|
-
displayId: number;
|
|
92
|
-
};
|
|
93
|
-
listDisplays(): Array<{
|
|
94
|
-
width: number;
|
|
95
|
-
height: number;
|
|
96
|
-
scaleFactor: number;
|
|
97
|
-
displayId: number;
|
|
98
|
-
}>;
|
|
99
|
-
takeScreenshot(width?: number, targetApp?: string, quality?: number, previousHash?: string, windowId?: number): {
|
|
100
|
-
base64?: string;
|
|
101
|
-
width: number;
|
|
102
|
-
height: number;
|
|
103
|
-
mimeType: string;
|
|
104
|
-
hash: string;
|
|
105
|
-
unchanged: boolean;
|
|
106
|
-
};
|
|
107
|
-
/** Depth-limited AX tree rooted at the window; caps at 500 nodes. */
|
|
108
|
-
getUiTree(windowId: number, maxDepth?: number): AXElement;
|
|
109
|
-
/** Currently focused AX element (or null). */
|
|
110
|
-
getFocusedElement(): AXElement | null;
|
|
111
|
-
/** Depth-first search within the window's AX tree. */
|
|
112
|
-
findElement(windowId: number, role?: string, label?: string, value?: string, maxResults?: number): AXElement[];
|
|
113
|
-
/** Perform an AX action (e.g. AXPress) on the first (role, label) match. */
|
|
114
|
-
performAction(windowId: number, role: string, label: string, action: string): {
|
|
115
|
-
performed: boolean;
|
|
116
|
-
reason?: string;
|
|
117
|
-
bounds?: AXBounds;
|
|
118
|
-
};
|
|
119
|
-
/** Set AXValue on the first (role, label) match. */
|
|
120
|
-
setElementValue(windowId: number, role: string, label: string, value: string): {
|
|
121
|
-
set: boolean;
|
|
122
|
-
reason?: string;
|
|
123
|
-
};
|
|
124
|
-
/** Walk the app's menu bar and return nested menu structure. */
|
|
125
|
-
getMenuBar(bundleId: string): MenuBarEntry[];
|
|
126
|
-
/** Press a named menu item, optionally nested under a submenu. */
|
|
127
|
-
pressMenuItem(bundleId: string, menu: string, item: string, submenu?: string): {
|
|
128
|
-
pressed: boolean;
|
|
129
|
-
reason?: string;
|
|
130
|
-
};
|
|
131
|
-
/** List user Spaces grouped by display, with the active Space ID. */
|
|
132
|
-
listSpaces(): {
|
|
133
|
-
supported: boolean;
|
|
134
|
-
reason?: string;
|
|
135
|
-
active_space_id: number | null;
|
|
136
|
-
displays: Array<{
|
|
137
|
-
display_id: string;
|
|
138
|
-
spaces: Array<{
|
|
139
|
-
id: number;
|
|
140
|
-
type: number;
|
|
141
|
-
uuid: string;
|
|
142
|
-
}>;
|
|
143
|
-
}>;
|
|
144
|
-
};
|
|
145
|
-
/** Active Space ID or null if CGS is unreachable. */
|
|
146
|
-
getActiveSpace(): number | null;
|
|
147
|
-
/** Create a new Space. Reports `attached: false` when the created Space is
|
|
148
|
-
* orphaned (not visible in Mission Control). */
|
|
149
|
-
createAgentSpace(): {
|
|
150
|
-
supported: boolean;
|
|
151
|
-
spaceId?: number;
|
|
152
|
-
attached?: boolean;
|
|
153
|
-
reason?: string;
|
|
154
|
-
note?: string;
|
|
155
|
-
};
|
|
156
|
-
/** Move a window into a Space. `verified: true` only when the window
|
|
157
|
-
* visibly disappears from the on-screen window list. */
|
|
158
|
-
moveWindowToSpace(windowId: number, spaceId: number): {
|
|
159
|
-
moved: boolean;
|
|
160
|
-
verified?: boolean;
|
|
161
|
-
reason?: string;
|
|
162
|
-
note?: string;
|
|
163
|
-
window_on_screen_before?: boolean;
|
|
164
|
-
window_on_screen_after?: boolean;
|
|
165
|
-
};
|
|
166
|
-
/** Remove a window from a Space (restores visibility). */
|
|
167
|
-
removeWindowFromSpace(windowId: number, spaceId: number): {
|
|
168
|
-
removed: boolean;
|
|
169
|
-
reason?: string;
|
|
170
|
-
};
|
|
171
|
-
/** Destroy a Space created via createAgentSpace. */
|
|
172
|
-
destroySpace(spaceId: number): {
|
|
173
|
-
destroyed: boolean;
|
|
174
|
-
reason?: string;
|
|
175
|
-
};
|
|
176
|
-
/**
|
|
177
|
-
* Pump the main CFRunLoop once. Used by the session layer during a CU
|
|
178
|
-
* session to keep NSWorkspace / AX state fresh. Cheap when idle.
|
|
179
|
-
*/
|
|
180
|
-
drainRunloop(): void;
|
|
181
|
-
/** Read clipboard text (Windows native). Undefined on macOS. */
|
|
182
|
-
readClipboard?(): string;
|
|
183
|
-
/** Write text to clipboard (Windows native). Undefined on macOS. */
|
|
184
|
-
writeClipboard?(text: string): void;
|
|
185
|
-
/** Draw annotations and grid lines on an image. Cross-platform. */
|
|
186
|
-
annotateImage(base64Jpeg: string, annotations: string | null, gridCols: number | null, gridRows: number | null, quality: number | null): {
|
|
187
|
-
base64: string;
|
|
188
|
-
width: number;
|
|
189
|
-
height: number;
|
|
190
|
-
mimeType: string;
|
|
191
|
-
};
|
|
192
|
-
/** Crop a region from a base64 image at full resolution. Cross-platform. */
|
|
193
|
-
cropImage(base64Image: string, x1: number, y1: number, x2: number, y2: number, quality: number | null): {
|
|
194
|
-
base64: string;
|
|
195
|
-
width: number;
|
|
196
|
-
height: number;
|
|
197
|
-
mimeType: string;
|
|
198
|
-
};
|
|
199
|
-
/**
|
|
200
|
-
* Hide every regular running app except the target and the keep-visible
|
|
201
|
-
* set. Defends against focus-stealing background apps (screenshot
|
|
202
|
-
* watchers, notification panels) before input dispatch.
|
|
203
|
-
*
|
|
204
|
-
* Returns the bundle IDs we actually hid — apps already hidden are NOT
|
|
205
|
-
* included, so callers can restore exactly the state they changed.
|
|
206
|
-
*/
|
|
207
|
-
prepareDisplay(targetBundleId: string, keepVisible: string[]): {
|
|
208
|
-
targetBundleId: string;
|
|
209
|
-
hiddenBundleIds: string[];
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
export declare function loadNative(): NativeModule;
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Native NAPI module loader — loads the compiled .node addon.
|
|
3
|
-
* Supports macOS (darwin) and Windows (win32) with platform-specific binaries.
|
|
4
|
-
*/
|
|
5
|
-
import { createRequire } from 'module';
|
|
6
|
-
import { existsSync } from 'fs';
|
|
7
|
-
import { join } from 'path';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
9
|
-
/**
|
|
10
|
-
* Supported platform + architecture combinations.
|
|
11
|
-
* Each entry maps to a binary named `computer-use-napi.${platform}-${arch}.node`.
|
|
12
|
-
*/
|
|
13
|
-
const SUPPORTED_TARGETS = [
|
|
14
|
-
{ platform: 'darwin', arch: 'arm64' },
|
|
15
|
-
{ platform: 'darwin', arch: 'x64' },
|
|
16
|
-
{ platform: 'win32', arch: 'x64' },
|
|
17
|
-
{ platform: 'linux', arch: 'x64' },
|
|
18
|
-
{ platform: 'linux', arch: 'arm64' },
|
|
19
|
-
];
|
|
20
|
-
/**
|
|
21
|
-
* Resolve the path to the platform-specific native binary.
|
|
22
|
-
* Throws a descriptive error on unsupported platforms or missing binaries.
|
|
23
|
-
*/
|
|
24
|
-
function resolveAddonPath() {
|
|
25
|
-
const platform = process.platform;
|
|
26
|
-
const arch = process.arch;
|
|
27
|
-
const isSupported = SUPPORTED_TARGETS.some((t) => t.platform === platform && t.arch === arch);
|
|
28
|
-
if (!isSupported) {
|
|
29
|
-
const supported = SUPPORTED_TARGETS.map((t) => `${t.platform}-${t.arch}`).join(', ');
|
|
30
|
-
throw new Error(`Unsupported platform: ${platform}-${arch}. ` +
|
|
31
|
-
`Supported platforms: ${supported}.`);
|
|
32
|
-
}
|
|
33
|
-
const binaryName = `computer-use-napi.${platform}-${arch}.node`;
|
|
34
|
-
const binaryPath = join(fileURLToPath(import.meta.url), '..', '..', binaryName);
|
|
35
|
-
if (!existsSync(binaryPath)) {
|
|
36
|
-
throw new Error(`Native binary not found: ${binaryName}. ` +
|
|
37
|
-
`Expected at ${binaryPath}. ` +
|
|
38
|
-
`Run the appropriate build script to compile the native module for ${platform}-${arch}.`);
|
|
39
|
-
}
|
|
40
|
-
return binaryPath;
|
|
41
|
-
}
|
|
42
|
-
const require = createRequire(import.meta.url);
|
|
43
|
-
const ADDON_PATH = resolveAddonPath();
|
|
44
|
-
let cached;
|
|
45
|
-
export function loadNative() {
|
|
46
|
-
if (cached)
|
|
47
|
-
return cached;
|
|
48
|
-
cached = require(ADDON_PATH);
|
|
49
|
-
return cached;
|
|
50
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Computer Use MCP Server — exposes tools over MCP protocol.
|
|
4
|
-
* Backed by in-process Rust NAPI module via session.
|
|
5
|
-
*/
|
|
6
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
-
import { type Session, type SessionOptions } from './session.js';
|
|
8
|
-
/**
|
|
9
|
-
* v5.2 — How each tool reaches the target app.
|
|
10
|
-
*
|
|
11
|
-
* - `scripting`: executes via AppleScript / JXA (`osascript`). Works even when
|
|
12
|
-
* the target app is backgrounded or hidden. Cheapest path for scriptable
|
|
13
|
-
* apps (Mail, Safari, Finder, Numbers, Music, Messages, Notes, Calendar).
|
|
14
|
-
* - `ax`: reads or mutates via the AXUIElement (Accessibility) API. Needs
|
|
15
|
-
* Accessibility permission. Reads are always safe; mutations typically
|
|
16
|
-
* require the target frontmost but some apps allow background AXPress.
|
|
17
|
-
* - `cgevent`: synthesizes keyboard / mouse events via CGEvent. **Requires
|
|
18
|
-
* the target app to be frontmost** — events route to whatever has focus.
|
|
19
|
-
* - `none`: pure observation of system state (clipboard, display size,
|
|
20
|
-
* cursor position). No target needed.
|
|
21
|
-
*/
|
|
22
|
-
export type FocusRequired = 'scripting' | 'ax' | 'cgevent' | 'none';
|
|
23
|
-
export interface ToolMeta {
|
|
24
|
-
focusRequired: FocusRequired;
|
|
25
|
-
/** Whether this tool is classified as mutating by the session layer. */
|
|
26
|
-
mutates: boolean;
|
|
27
|
-
}
|
|
28
|
-
export interface ServerOptions extends SessionOptions {
|
|
29
|
-
/** Override session instance for tests */
|
|
30
|
-
session?: Session;
|
|
31
|
-
}
|
|
32
|
-
export declare function createComputerUseServer(opts?: ServerOptions): McpServer;
|
|
@@ -1,342 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Computer Use MCP Server — exposes tools over MCP protocol.
|
|
4
|
-
* Backed by in-process Rust NAPI module via session.
|
|
5
|
-
*/
|
|
6
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
8
|
-
import { z } from 'zod';
|
|
9
|
-
import { createSession } from './session.js';
|
|
10
|
-
import { isStdioEntrypoint } from './entrypoint.js';
|
|
11
|
-
const targetAppParam = z.string().optional().describe('Bundle ID of target app (auto-focuses before action)');
|
|
12
|
-
const targetWindowIdParam = z.number().int().optional().describe('CGWindowID to target. Takes precedence over target_app.');
|
|
13
|
-
const focusStrategyParam = z.enum(['strict', 'best_effort', 'none', 'prepare_display']).optional().describe('Focus strategy: strict (fail if unconfirmed), best_effort (try and proceed), none (skip activation), prepare_display (hide every non-target app before acting — v5.2, defeats focus-stealing background apps)');
|
|
14
|
-
const coord = { coordinate: z.tuple([z.number(), z.number()]).describe('[x, y] pixels') };
|
|
15
|
-
const withTargeting = (schema) => ({
|
|
16
|
-
...schema,
|
|
17
|
-
target_app: targetAppParam,
|
|
18
|
-
target_window_id: targetWindowIdParam,
|
|
19
|
-
focus_strategy: focusStrategyParam,
|
|
20
|
-
});
|
|
21
|
-
const PROVIDERS = ['anthropic', 'openai', 'openai-low', 'gemini', 'llama', 'grok', 'mistral', 'qwen', 'nova', 'deepseek-vl', 'phi', 'auto'];
|
|
22
|
-
export function createComputerUseServer(opts = {}) {
|
|
23
|
-
const server = new McpServer({ name: 'computer-use', version: '6.1.0' });
|
|
24
|
-
const session = opts.session ?? createSession({
|
|
25
|
-
vision: opts.vision ?? (process.env.COMPUTER_USE_VISION !== 'false'),
|
|
26
|
-
provider: opts.provider ?? process.env.COMPUTER_USE_PROVIDER,
|
|
27
|
-
native: opts.native,
|
|
28
|
-
});
|
|
29
|
-
// v5.2: Per-tool metadata registry. Populated as each `tool()` call runs.
|
|
30
|
-
// Exposed to clients via the new `get_tool_metadata` tool and appended to
|
|
31
|
-
// each tool's description as `[focusRequired: X]` so agents that read
|
|
32
|
-
// descriptions can filter without a separate call.
|
|
33
|
-
const toolMeta = new Map();
|
|
34
|
-
// Shorthand for common metadata combos, so each tool() call stays readable.
|
|
35
|
-
const CG_MUT = { focusRequired: 'cgevent', mutates: true };
|
|
36
|
-
const AX_MUT = { focusRequired: 'ax', mutates: true };
|
|
37
|
-
const AX_READ = { focusRequired: 'ax', mutates: false };
|
|
38
|
-
const SCRIPTING = { focusRequired: 'scripting', mutates: true };
|
|
39
|
-
const SCRIPT_READ = { focusRequired: 'scripting', mutates: false };
|
|
40
|
-
const NONE_READ = { focusRequired: 'none', mutates: false };
|
|
41
|
-
const NONE_MUT = { focusRequired: 'none', mutates: true };
|
|
42
|
-
const tool = (name, desc, schema, meta) => {
|
|
43
|
-
toolMeta.set(name, meta);
|
|
44
|
-
const tagged = `${desc} [focusRequired: ${meta.focusRequired}]`;
|
|
45
|
-
server.tool(name, tagged, schema, async (args) => {
|
|
46
|
-
const result = await session.dispatch(name, args);
|
|
47
|
-
return {
|
|
48
|
-
content: result.content.map(c => c.type === 'image'
|
|
49
|
-
? { type: 'image', data: c.data, mimeType: c.mimeType }
|
|
50
|
-
: { type: 'text', text: c.text }),
|
|
51
|
-
isError: result.isError,
|
|
52
|
-
};
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
tool('screenshot', 'Capture the screen or a specific window. BEFORE using this, consider get_ui_tree or find_element to discover UI by role/label — structured queries are cheaper than visual parsing. Auto-targets the active session window when no explicit target is given.', {
|
|
56
|
-
width: z.number().int().positive().optional()
|
|
57
|
-
.describe('Override width in pixels. Omit to use provider-optimal default.'),
|
|
58
|
-
quality: z.number().int().min(0).max(100).optional()
|
|
59
|
-
.describe('Image quality. 1-100 = JPEG quality. 0 = PNG (lossless). Default: 80 (JPEG).'),
|
|
60
|
-
target_app: z.string().optional()
|
|
61
|
-
.describe('Bundle ID of app to capture (window only). Omit for full screen.'),
|
|
62
|
-
target_window_id: targetWindowIdParam,
|
|
63
|
-
provider: z.enum(PROVIDERS).optional()
|
|
64
|
-
.describe('AI provider — sets optimal default width. anthropic=1024px, openai=1024px, gemini=768px, qwen/deepseek-vl/phi=896px. Default: auto (1024px).'),
|
|
65
|
-
}, NONE_READ);
|
|
66
|
-
tool('zoom', 'View a specific region of the screen at full resolution. Useful for reading small text, inspecting UI details, or verifying pixel-level content. Returns the cropped region without downscaling.', {
|
|
67
|
-
region: z.tuple([z.number().int(), z.number().int(), z.number().int(), z.number().int()])
|
|
68
|
-
.describe('[x1, y1, x2, y2] — top-left and bottom-right corners of the region to inspect'),
|
|
69
|
-
quality: z.number().int().min(0).max(100).optional()
|
|
70
|
-
.describe('Image quality. 0 = PNG (lossless, best for text). 1-100 = JPEG. Default: 0 (PNG).'),
|
|
71
|
-
}, NONE_READ);
|
|
72
|
-
// Pointer / keyboard — CGEvent, target must be frontmost.
|
|
73
|
-
tool('left_click', 'Left-click at coordinates', withTargeting(coord), CG_MUT);
|
|
74
|
-
tool('right_click', 'Right-click at coordinates', withTargeting(coord), CG_MUT);
|
|
75
|
-
tool('middle_click', 'Middle-click at coordinates', withTargeting(coord), CG_MUT);
|
|
76
|
-
tool('double_click', 'Double-click at coordinates', withTargeting(coord), CG_MUT);
|
|
77
|
-
tool('triple_click', 'Triple-click at coordinates', withTargeting(coord), CG_MUT);
|
|
78
|
-
tool('mouse_move', 'Move cursor to coordinates', withTargeting(coord), CG_MUT);
|
|
79
|
-
tool('left_click_drag', 'Click and drag', withTargeting({
|
|
80
|
-
coordinate: z.tuple([z.number(), z.number()]),
|
|
81
|
-
start_coordinate: z.tuple([z.number(), z.number()]).optional(),
|
|
82
|
-
}), CG_MUT);
|
|
83
|
-
tool('cursor_position', 'Get current cursor position', {}, NONE_READ);
|
|
84
|
-
tool('left_mouse_down', 'Press left mouse button', withTargeting(coord), CG_MUT);
|
|
85
|
-
tool('left_mouse_up', 'Release left mouse button', withTargeting(coord), CG_MUT);
|
|
86
|
-
tool('scroll', 'Scroll at position', {
|
|
87
|
-
...coord,
|
|
88
|
-
direction: z.enum(['up', 'down', 'left', 'right']),
|
|
89
|
-
amount: z.number().int().positive().default(3),
|
|
90
|
-
target_app: targetAppParam,
|
|
91
|
-
target_window_id: targetWindowIdParam,
|
|
92
|
-
focus_strategy: focusStrategyParam,
|
|
93
|
-
}, CG_MUT);
|
|
94
|
-
tool('type', 'Type text into the focused app. For form fields, prefer set_value or fill_form — accessibility-based writes are more reliable and need no click-to-focus.', {
|
|
95
|
-
text: z.string(),
|
|
96
|
-
clear: z.boolean().optional().describe('Clear existing text before typing (Ctrl+A, Delete)'),
|
|
97
|
-
press_enter: z.boolean().optional().describe('Press Enter/Return after typing to submit'),
|
|
98
|
-
caret_position: z.enum(['start', 'end', 'idle']).optional().describe('Move caret before typing: start (Home), end (End), idle (leave as-is)'),
|
|
99
|
-
target_app: targetAppParam,
|
|
100
|
-
target_window_id: targetWindowIdParam,
|
|
101
|
-
focus_strategy: focusStrategyParam,
|
|
102
|
-
}, CG_MUT);
|
|
103
|
-
tool('key', 'Press a key combination (e.g. "command+c", "return"). Tab and Shift+Tab navigate between form fields; keyboard shortcuts are usually faster than coordinate-based clicks.', {
|
|
104
|
-
text: z.string().describe('Key combo like "command+c" or "return"'),
|
|
105
|
-
repeat: z.number().int().positive().optional(),
|
|
106
|
-
target_app: targetAppParam,
|
|
107
|
-
target_window_id: targetWindowIdParam,
|
|
108
|
-
focus_strategy: focusStrategyParam,
|
|
109
|
-
}, CG_MUT);
|
|
110
|
-
tool('hold_key', 'Hold keys for a duration', {
|
|
111
|
-
keys: z.array(z.string()),
|
|
112
|
-
duration: z.number().positive().describe('Seconds'),
|
|
113
|
-
target_app: targetAppParam,
|
|
114
|
-
target_window_id: targetWindowIdParam,
|
|
115
|
-
focus_strategy: focusStrategyParam,
|
|
116
|
-
}, CG_MUT);
|
|
117
|
-
// Clipboard — touches pasteboard only, no focus dependency.
|
|
118
|
-
tool('read_clipboard', 'Read clipboard contents', {}, NONE_READ);
|
|
119
|
-
tool('write_clipboard', 'Write text to clipboard', { text: z.string() }, NONE_MUT);
|
|
120
|
-
// App / window lifecycle — NSWorkspace/AX mutations.
|
|
121
|
-
tool('open_application', 'Open and focus an app by bundle ID', {
|
|
122
|
-
bundle_id: z.string().describe('macOS bundle ID e.g. "com.apple.Safari"'),
|
|
123
|
-
}, AX_MUT);
|
|
124
|
-
tool('get_frontmost_app', 'Get the currently frontmost app', {}, AX_READ);
|
|
125
|
-
tool('list_windows', 'List visible on-screen windows, optionally filtered by bundle ID', {
|
|
126
|
-
bundle_id: z.string().optional().describe('Bundle ID to filter windows by'),
|
|
127
|
-
}, AX_READ);
|
|
128
|
-
tool('list_running_apps', 'List all running regular applications', {}, AX_READ);
|
|
129
|
-
tool('hide_app', 'Hide an app by bundle ID', { bundle_id: z.string() }, AX_MUT);
|
|
130
|
-
tool('unhide_app', 'Unhide an app by bundle ID', { bundle_id: z.string() }, AX_MUT);
|
|
131
|
-
tool('get_display_size', 'Get display dimensions and scale factor', {
|
|
132
|
-
display_id: z.number().optional().describe('Display ID (omit for main display)'),
|
|
133
|
-
}, NONE_READ);
|
|
134
|
-
tool('list_displays', 'List all connected displays', {}, NONE_READ);
|
|
135
|
-
tool('get_window', 'Look up a window by its CGWindowID', {
|
|
136
|
-
window_id: z.number().int().describe('CGWindowID of the window to look up'),
|
|
137
|
-
}, AX_READ);
|
|
138
|
-
tool('get_cursor_window', 'Get the window currently under the mouse cursor', {}, AX_READ);
|
|
139
|
-
tool('activate_app', 'Activate an app and return structured before/after diagnostics', {
|
|
140
|
-
bundle_id: z.string().describe('macOS bundle ID'),
|
|
141
|
-
timeout_ms: z.number().int().positive().optional().describe('Activation polling timeout in ms'),
|
|
142
|
-
}, AX_MUT);
|
|
143
|
-
tool('activate_window', 'Raise a specific window by CGWindowID', {
|
|
144
|
-
window_id: z.number().int().describe('CGWindowID of the window to raise'),
|
|
145
|
-
timeout_ms: z.number().int().positive().optional().describe('Activation polling timeout in ms'),
|
|
146
|
-
}, AX_MUT);
|
|
147
|
-
tool('resize_window', 'Resize and/or move a window. Omit window_name to target the foreground window.', {
|
|
148
|
-
window_name: z.string().optional().describe('Window title or process name to target (omit for foreground)'),
|
|
149
|
-
window_id: z.number().int().optional().describe('Window ID to target (takes precedence over window_name)'),
|
|
150
|
-
window_size: z.tuple([z.number().int(), z.number().int()]).optional().describe('[width, height] in pixels'),
|
|
151
|
-
window_loc: z.tuple([z.number().int(), z.number().int()]).optional().describe('[x, y] top-left position'),
|
|
152
|
-
}, AX_MUT);
|
|
153
|
-
tool('wait', 'Wait for N seconds', { duration: z.number().positive().max(300) }, NONE_READ);
|
|
154
|
-
tool('snapshot', 'Combined screenshot + UI tree + window list + desktop info in one call. Returns structured text with all desktop state. Set use_vision=true to include screenshot image. Set use_annotation=true to draw bounding boxes on UI elements. Set grid_lines=[cols,rows] to overlay reference grid.', {
|
|
155
|
-
use_vision: z.boolean().optional().default(false).describe('Include screenshot image in response'),
|
|
156
|
-
use_annotation: z.boolean().optional().default(false).describe('Draw bounding boxes on detected UI elements'),
|
|
157
|
-
grid_lines: z.tuple([z.number().int(), z.number().int()]).optional().describe('[columns, rows] for reference grid overlay'),
|
|
158
|
-
display: z.array(z.number().int()).optional().describe('Monitor indices to capture (omit for all)'),
|
|
159
|
-
width: z.number().int().positive().optional().describe('Resize screenshot width'),
|
|
160
|
-
target_app: targetAppParam,
|
|
161
|
-
target_window_id: targetWindowIdParam,
|
|
162
|
-
}, NONE_READ);
|
|
163
|
-
// ── v5: Accessibility observation ───────────────────────────────────────
|
|
164
|
-
tool('get_ui_tree', 'Get the accessibility tree for a window — discover UI elements by role/label instead of parsing pixels. Returns role, label, value, bounds, actions, children per node. Capped at 500 nodes.', {
|
|
165
|
-
window_id: z.number().int().describe('CGWindowID to introspect'),
|
|
166
|
-
max_depth: z.number().int().positive().max(20).optional().describe('Maximum tree depth (default 10, max 20)'),
|
|
167
|
-
}, AX_READ);
|
|
168
|
-
tool('get_focused_element', 'Get the currently focused UI element — where typed text will go. Returns null if no element has focus.', {}, AX_READ);
|
|
169
|
-
tool('find_element', 'Search for UI elements in a window by role, label, or value (AND of the provided criteria). Faster than walking the full tree.', {
|
|
170
|
-
window_id: z.number().int().describe('CGWindowID to search within'),
|
|
171
|
-
role: z.string().optional().describe('AX role — e.g. AXButton, AXTextField, AXStaticText, AXMenuItem'),
|
|
172
|
-
label: z.string().optional().describe('Element label (AXTitle or AXDescription); case-insensitive substring match'),
|
|
173
|
-
value: z.string().optional().describe('Element value (AXValue); case-insensitive substring match'),
|
|
174
|
-
max_results: z.number().int().positive().max(100).optional().describe('Max matches to return (default 25)'),
|
|
175
|
-
}, AX_READ);
|
|
176
|
-
// ── v5: Semantic actions ────────────────────────────────────────────────
|
|
177
|
-
tool('click_element', 'Click a UI element by role and label — more reliable than pixel clicks (survives window moves and resolution changes). Falls back to coordinate click if AXPress is unsupported.', {
|
|
178
|
-
window_id: z.number().int().describe('CGWindowID of the window containing the element'),
|
|
179
|
-
role: z.string().describe('AX role of the element to click (e.g. AXButton)'),
|
|
180
|
-
label: z.string().describe('Element label — matched against AXTitle/AXDescription'),
|
|
181
|
-
focus_strategy: focusStrategyParam,
|
|
182
|
-
}, AX_MUT);
|
|
183
|
-
tool('set_value', 'Set a UI element\'s value directly (e.g. text field content). Avoids the click → type dance. Defaults to strict focus since it writes text.', {
|
|
184
|
-
window_id: z.number().int().describe('CGWindowID of the window containing the element'),
|
|
185
|
-
role: z.string().describe('AX role (usually AXTextField or AXTextArea)'),
|
|
186
|
-
label: z.string().describe('Element label'),
|
|
187
|
-
value: z.string().describe('New value to set'),
|
|
188
|
-
focus_strategy: focusStrategyParam,
|
|
189
|
-
}, AX_MUT);
|
|
190
|
-
tool('press_button', 'Press a button by its label. Shortcut over click_element for role=AXButton.', {
|
|
191
|
-
window_id: z.number().int().describe('CGWindowID of the window containing the button'),
|
|
192
|
-
label: z.string().describe('Button label'),
|
|
193
|
-
focus_strategy: focusStrategyParam,
|
|
194
|
-
}, AX_MUT);
|
|
195
|
-
tool('select_menu_item', 'Select an app menu item programmatically — walks AXMenuBar. Returns list of available menus on miss.', {
|
|
196
|
-
bundle_id: z.string().describe('Bundle ID of the app'),
|
|
197
|
-
menu: z.string().describe('Top-level menu title (e.g. "File")'),
|
|
198
|
-
item: z.string().describe('Menu item title (e.g. "New")'),
|
|
199
|
-
submenu: z.string().optional().describe('Submenu title when the item is nested'),
|
|
200
|
-
}, AX_MUT);
|
|
201
|
-
tool('fill_form', 'Set multiple UI element values in a single call — collapses click+type loops into one tool call. Partial failures are reported per field without aborting the batch.', {
|
|
202
|
-
window_id: z.number().int().describe('CGWindowID of the form window'),
|
|
203
|
-
fields: z.array(z.object({
|
|
204
|
-
role: z.string(),
|
|
205
|
-
label: z.string(),
|
|
206
|
-
value: z.string(),
|
|
207
|
-
})).describe('Ordered list of fields to fill'),
|
|
208
|
-
focus_strategy: focusStrategyParam,
|
|
209
|
-
}, AX_MUT);
|
|
210
|
-
// ── v5: Scripting bridge ────────────────────────────────────────────────
|
|
211
|
-
tool('run_script', 'Execute a script and return the output. On macOS: AppleScript or JXA for scriptable apps. On Windows: PowerShell. Bounded by timeout_ms.', {
|
|
212
|
-
language: z.enum(['applescript', 'javascript', 'powershell']).describe('Scripting language (applescript/javascript on macOS, powershell on Windows)'),
|
|
213
|
-
script: z.string().describe('Script body to execute'),
|
|
214
|
-
timeout_ms: z.number().int().positive().max(120_000).optional().describe('Hard timeout in ms (default 30000, max 120000)'),
|
|
215
|
-
}, SCRIPTING);
|
|
216
|
-
tool('get_app_dictionary', 'Get a scriptable app\'s dictionary (suites, commands, classes). Returns summarized names by default; pass `suite` for full details of one suite.', {
|
|
217
|
-
bundle_id: z.string().describe('Bundle ID of the scriptable app'),
|
|
218
|
-
suite: z.string().optional().describe('Limit to a specific suite; omit for a summary'),
|
|
219
|
-
}, SCRIPT_READ);
|
|
220
|
-
// ── v5.1: Menu bar introspection ────────────────────────────────────────
|
|
221
|
-
tool('list_menu_bar', 'List an app\'s full menu bar structure with keyboard shortcuts. Use this BEFORE select_menu_item to see what menus / items / shortcuts exist — agents can then press the shortcut directly (faster than walking the menu) or pass the exact item title to select_menu_item.', {
|
|
222
|
-
bundle_id: z.string().describe('Bundle ID of the app whose menu bar to read'),
|
|
223
|
-
}, AX_READ);
|
|
224
|
-
// ── v5: Strategy advisor ────────────────────────────────────────────────
|
|
225
|
-
tool('get_tool_guide', 'Recommend the best automation approach for a task. Call this BEFORE committing to screenshot-and-click — it suggests scripting or accessibility paths when they exist.', {
|
|
226
|
-
task_description: z.string().describe('Natural-language description of the task to automate'),
|
|
227
|
-
}, NONE_READ);
|
|
228
|
-
tool('get_app_capabilities', 'Discover what automation approaches work for an app: scriptable? accessible? running? hidden?', {
|
|
229
|
-
bundle_id: z.string().describe('Bundle ID to probe'),
|
|
230
|
-
}, AX_READ);
|
|
231
|
-
// ── v5: Agent Spaces ────────────────────────────────────────────────────
|
|
232
|
-
// macOS Space mutation uses best-effort backends selected by
|
|
233
|
-
// COMPUTER_USE_SPACES_BACKEND: yabai, Mission Control gestures, then CGS.
|
|
234
|
-
// CGS-created Spaces can be orphaned on SIP-enabled Macs.
|
|
235
|
-
tool('list_spaces', 'List user Spaces grouped by display. Always works — pure read via CGS.', {}, NONE_READ);
|
|
236
|
-
tool('get_active_space', 'Get the currently active Space ID.', {}, NONE_READ);
|
|
237
|
-
tool('create_agent_space', 'Create a new virtual desktop/Space. On macOS, auto-selects yabai, Mission Control gesture automation, or CGS fallback. On Windows uses Ctrl+Win+D keyboard shortcut.', {}, AX_MUT);
|
|
238
|
-
tool('move_window_to_space', 'Move a window to a virtual desktop/Space. On macOS, prefers yabai and falls back to private CGS APIs.', {
|
|
239
|
-
window_id: z.number().int().describe('Window ID to move'),
|
|
240
|
-
space_id: z.number().int().describe('Target Space/desktop ID'),
|
|
241
|
-
}, AX_MUT);
|
|
242
|
-
tool('remove_window_from_space', 'Remove a window from a virtual desktop/Space. Best effort on macOS because private CGS APIs may no-op without elevated entitlements.', {
|
|
243
|
-
window_id: z.number().int().describe('Window ID to remove'),
|
|
244
|
-
space_id: z.number().int().describe('Space/desktop ID to remove the window from'),
|
|
245
|
-
}, AX_MUT);
|
|
246
|
-
tool('destroy_space', 'Close a virtual desktop/Space. On macOS, prefers yabai and falls back to private CGS APIs. On Windows uses Ctrl+Win+F4.', {
|
|
247
|
-
space_id: z.number().int().optional().describe('Space ID to destroy (ignored on Windows — always closes current)'),
|
|
248
|
-
}, AX_MUT);
|
|
249
|
-
// ── v5.2: Tool metadata introspection ───────────────────────────────────
|
|
250
|
-
//
|
|
251
|
-
// This is the only tool that doesn't go through session.dispatch —
|
|
252
|
-
// it reads directly from the toolMeta registry populated by each
|
|
253
|
-
// tool() registration above. Pure read; no side effects.
|
|
254
|
-
server.tool('get_tool_metadata', 'Get structured metadata for a tool: focusRequired (scripting|ax|cgevent|none) and mutates (bool). Useful for agents that want to filter tools by their focus requirements — e.g. "show me only tools I can use while Safari is backgrounded". [focusRequired: none]', { tool_name: z.string().describe('Name of the tool to inspect') }, async (args) => {
|
|
255
|
-
const name = typeof args.tool_name === 'string' ? args.tool_name : '';
|
|
256
|
-
const meta = toolMeta.get(name);
|
|
257
|
-
if (!meta) {
|
|
258
|
-
return {
|
|
259
|
-
content: [{
|
|
260
|
-
type: 'text',
|
|
261
|
-
text: JSON.stringify({ error: 'unknown_tool', tool_name: name }),
|
|
262
|
-
}],
|
|
263
|
-
isError: true,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
return {
|
|
267
|
-
content: [{ type: 'text', text: JSON.stringify({ tool_name: name, ...meta }) }],
|
|
268
|
-
};
|
|
269
|
-
});
|
|
270
|
-
toolMeta.set('get_tool_metadata', { focusRequired: 'none', mutates: false });
|
|
271
|
-
// ── Windows-parity tools (cross-platform where possible) ────────────────
|
|
272
|
-
// FileSystem tool — Node.js fs, cross-platform
|
|
273
|
-
tool('filesystem', 'File and directory operations: read, write, copy, move, delete, list, search, info. Relative paths resolve from Desktop.', {
|
|
274
|
-
mode: z.enum(['read', 'write', 'copy', 'move', 'delete', 'list', 'search', 'info']).describe('Operation mode'),
|
|
275
|
-
path: z.string().describe('File or directory path'),
|
|
276
|
-
destination: z.string().optional().describe('Destination path for copy/move'),
|
|
277
|
-
content: z.string().optional().describe('Content for write mode'),
|
|
278
|
-
pattern: z.string().optional().describe('Glob pattern for list/search'),
|
|
279
|
-
recursive: z.boolean().optional().default(false).describe('Recursive delete/list/search'),
|
|
280
|
-
append: z.boolean().optional().default(false).describe('Append instead of overwrite'),
|
|
281
|
-
overwrite: z.boolean().optional().default(false).describe('Overwrite existing for copy/move'),
|
|
282
|
-
offset: z.number().int().optional().describe('Line offset for read'),
|
|
283
|
-
limit: z.number().int().optional().describe('Line limit for read'),
|
|
284
|
-
encoding: z.string().optional().default('utf-8').describe('File encoding'),
|
|
285
|
-
show_hidden: z.boolean().optional().default(false).describe('Show hidden files in list'),
|
|
286
|
-
}, NONE_MUT);
|
|
287
|
-
// Process tool — list and kill processes
|
|
288
|
-
tool('process_kill', 'List and kill running processes. mode=list for process listing, mode=kill to terminate by name or PID.', {
|
|
289
|
-
mode: z.enum(['list', 'kill']).describe('Operation mode'),
|
|
290
|
-
name: z.string().optional().describe('Process name to filter/kill'),
|
|
291
|
-
pid: z.number().int().optional().describe('Process ID to kill'),
|
|
292
|
-
force: z.boolean().optional().default(false).describe('Force kill without graceful close'),
|
|
293
|
-
sort_by: z.enum(['memory', 'cpu', 'name']).optional().default('memory').describe('Sort field for list'),
|
|
294
|
-
limit: z.number().int().optional().default(20).describe('Max processes to list'),
|
|
295
|
-
}, NONE_MUT);
|
|
296
|
-
// Registry tool — Windows only
|
|
297
|
-
tool('registry', 'Windows Registry operations: get, set, delete, list. Paths use PowerShell format (HKCU:\\Software\\...). Windows only.', {
|
|
298
|
-
mode: z.enum(['get', 'set', 'delete', 'list']).describe('Operation mode'),
|
|
299
|
-
path: z.string().describe('Registry path in PowerShell format'),
|
|
300
|
-
name: z.string().optional().describe('Value name'),
|
|
301
|
-
value: z.string().optional().describe('Value data for set mode'),
|
|
302
|
-
type: z.enum(['String', 'DWord', 'QWord', 'Binary', 'MultiString', 'ExpandString']).optional().default('String').describe('Value type for set'),
|
|
303
|
-
}, NONE_MUT);
|
|
304
|
-
// Notification tool — Windows only
|
|
305
|
-
tool('notification', 'Send a Windows toast notification. Windows only.', {
|
|
306
|
-
title: z.string().describe('Notification title'),
|
|
307
|
-
message: z.string().describe('Notification body text'),
|
|
308
|
-
app_id: z.string().optional().describe('Application User Model ID'),
|
|
309
|
-
}, NONE_MUT);
|
|
310
|
-
// MultiSelect tool — batch click with optional Ctrl hold
|
|
311
|
-
tool('multi_select', 'Select multiple items by clicking coordinates or UI element labels. Set press_ctrl=true for additive selection.', {
|
|
312
|
-
locs: z.array(z.tuple([z.number(), z.number()])).optional().describe('List of [x,y] coordinates'),
|
|
313
|
-
labels: z.array(z.string()).optional().describe('List of UI element labels'),
|
|
314
|
-
press_ctrl: z.boolean().optional().default(true).describe('Hold Ctrl for additive selection'),
|
|
315
|
-
target_app: targetAppParam,
|
|
316
|
-
target_window_id: targetWindowIdParam,
|
|
317
|
-
focus_strategy: focusStrategyParam,
|
|
318
|
-
}, CG_MUT);
|
|
319
|
-
// MultiEdit tool — batch click+type
|
|
320
|
-
tool('multi_edit', 'Enter text into multiple fields. Provide locs as [[x,y,text],...] or labels as [[label,text],...].', {
|
|
321
|
-
locs: z.array(z.tuple([z.number(), z.number(), z.string()])).optional().describe('List of [x,y,text] tuples'),
|
|
322
|
-
labels: z.array(z.tuple([z.string(), z.string()])).optional().describe('List of [label,text] tuples'),
|
|
323
|
-
target_app: targetAppParam,
|
|
324
|
-
target_window_id: targetWindowIdParam,
|
|
325
|
-
focus_strategy: focusStrategyParam,
|
|
326
|
-
}, CG_MUT);
|
|
327
|
-
// Scrape tool — fetch web page content
|
|
328
|
-
tool('scrape', 'Fetch and extract content from a URL. Returns clean text from web pages. Set use_dom=true to extract from active browser tab DOM instead of HTTP fetch.', {
|
|
329
|
-
url: z.string().describe('URL to fetch'),
|
|
330
|
-
query: z.string().optional().describe('Focus extraction on specific information'),
|
|
331
|
-
use_dom: z.boolean().optional().default(false).describe('Extract from active browser tab DOM instead of HTTP'),
|
|
332
|
-
}, NONE_READ);
|
|
333
|
-
return server;
|
|
334
|
-
}
|
|
335
|
-
// Standalone stdio entrypoint. Detection lives in ./entrypoint.ts so it is
|
|
336
|
-
// unit-testable without loading the native NAPI binary.
|
|
337
|
-
if (isStdioEntrypoint(process.argv[1])) {
|
|
338
|
-
const server = createComputerUseServer();
|
|
339
|
-
const transport = new StdioServerTransport();
|
|
340
|
-
server.connect(transport).then(() => console.error('[computer-use-mcp] Server running'))
|
|
341
|
-
.catch(err => { console.error('Fatal:', err); process.exit(1); });
|
|
342
|
-
}
|