frely-cli 0.9.5 → 0.9.7
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/README.md +30 -8
- package/README.zh-CN.md +18 -7
- package/dist/agent-help.d.ts +110 -14
- package/dist/agent-help.js +20 -9
- package/dist/agent-help.js.map +1 -1
- package/dist/auth.d.ts +14 -1
- package/dist/auth.js +14 -22
- package/dist/auth.js.map +1 -1
- package/dist/cloud.d.ts +11 -1
- package/dist/cloud.js +73 -1
- package/dist/cloud.js.map +1 -1
- package/dist/computer/command.d.ts +6 -0
- package/dist/computer/command.js +53 -0
- package/dist/computer/command.js.map +1 -0
- package/dist/computer/guard.d.ts +18 -0
- package/dist/computer/guard.js +82 -0
- package/dist/computer/guard.js.map +1 -0
- package/dist/computer/image.d.ts +22 -0
- package/dist/computer/image.js +183 -0
- package/dist/computer/image.js.map +1 -0
- package/dist/computer/ocu.d.ts +40 -0
- package/dist/computer/ocu.js +59 -0
- package/dist/computer/ocu.js.map +1 -0
- package/dist/computer/runtime.d.ts +22 -0
- package/dist/computer/runtime.js +85 -0
- package/dist/computer/runtime.js.map +1 -0
- package/dist/computer/server.d.ts +11 -0
- package/dist/computer/server.js +31 -0
- package/dist/computer/server.js.map +1 -0
- package/dist/computer/state.d.ts +11 -0
- package/dist/computer/state.js +17 -0
- package/dist/computer/state.js.map +1 -0
- package/dist/computer/toolset.d.ts +22 -0
- package/dist/computer/toolset.js +112 -0
- package/dist/computer/toolset.js.map +1 -0
- package/dist/device/protocol.d.ts +2 -0
- package/dist/device/protocol.js +7 -1
- package/dist/device/protocol.js.map +1 -1
- package/dist/device/relay-client.d.ts +3 -0
- package/dist/device/relay-client.js +7 -1
- package/dist/device/relay-client.js.map +1 -1
- package/dist/index.js +103 -40
- package/dist/index.js.map +1 -1
- package/dist/local-mcp-command.d.ts +10 -0
- package/dist/local-mcp-command.js +105 -0
- package/dist/local-mcp-command.js.map +1 -0
- package/dist/mcp-authorization.d.ts +11 -2
- package/dist/mcp-authorization.js +21 -6
- package/dist/mcp-authorization.js.map +1 -1
- package/dist/mcp-command.d.ts +2 -1
- package/dist/mcp-command.js +18 -2
- package/dist/mcp-command.js.map +1 -1
- package/dist/provider/control.d.ts +8 -2
- package/dist/provider/control.js.map +1 -1
- package/dist/runtime/local-mcp.d.ts +114 -0
- package/dist/runtime/local-mcp.js +448 -0
- package/dist/runtime/local-mcp.js.map +1 -0
- package/dist/runtime/mcp.d.ts +20 -0
- package/dist/runtime/mcp.js +29 -0
- package/dist/runtime/mcp.js.map +1 -1
- package/dist/runtime/relay-mcp.d.ts +3 -1
- package/dist/runtime/relay-mcp.js +5 -1
- package/dist/runtime/relay-mcp.js.map +1 -1
- package/dist/runtime/relay-session.d.ts +2 -2
- package/dist/runtime/relay-session.js +1 -1
- package/dist/runtime/relay-session.js.map +1 -1
- package/dist/runtime/sandbox.js +3 -0
- package/dist/runtime/sandbox.js.map +1 -1
- package/dist/skill/cloud-item.d.ts +38 -0
- package/dist/skill/cloud-item.js +151 -0
- package/dist/skill/cloud-item.js.map +1 -0
- package/dist/upgrade/maintenance.js +1 -1
- package/dist/upgrade/maintenance.js.map +1 -1
- package/dist/upgrade/service-refresh.js +1 -1
- package/dist/upgrade/service-refresh.js.map +1 -1
- package/dist/upgrade/update.js +2 -2
- package/dist/upgrade/update.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Long edge cap for screenshots sent to the model (plan computer-use D6); keeps a frame far below the 8 MiB relay limit. */
|
|
2
|
+
export declare const SCREENSHOT_MAX_EDGE = 1280;
|
|
3
|
+
export interface ScaledPng {
|
|
4
|
+
data: Buffer;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number; /** original / scaled; multiply model coordinates by this to get device pixels. */
|
|
7
|
+
scale: number;
|
|
8
|
+
}
|
|
9
|
+
/** Returns null when the PNG is not a plain 8-bit non-interlaced grey/RGB(A) image (caller then passes it through or rejects it by size). */
|
|
10
|
+
export declare function downscalePng(png: Buffer, maxEdge?: number): ScaledPng | null;
|
|
11
|
+
export declare function pngSize(png: Buffer): {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
} | null;
|
|
15
|
+
/** Encode raw 8-bit RGBA pixels as a PNG (used by tests and fixtures). */
|
|
16
|
+
export declare function encodeRgbaPng(width: number, height: number, rgba: Buffer): Buffer;
|
|
17
|
+
export declare function decodePngPixels(png: Buffer): {
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
channels: number;
|
|
21
|
+
data: Buffer;
|
|
22
|
+
} | null;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { deflateSync, inflateSync } from "node:zlib";
|
|
2
|
+
/** Long edge cap for screenshots sent to the model (plan computer-use D6); keeps a frame far below the 8 MiB relay limit. */
|
|
3
|
+
export const SCREENSHOT_MAX_EDGE = 1280;
|
|
4
|
+
const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
5
|
+
/** Returns null when the PNG is not a plain 8-bit non-interlaced grey/RGB(A) image (caller then passes it through or rejects it by size). */
|
|
6
|
+
export function downscalePng(png, maxEdge = SCREENSHOT_MAX_EDGE) {
|
|
7
|
+
const raster = decodePng(png);
|
|
8
|
+
if (!raster)
|
|
9
|
+
return null;
|
|
10
|
+
const longEdge = Math.max(raster.width, raster.height);
|
|
11
|
+
if (longEdge <= maxEdge)
|
|
12
|
+
return { data: png, width: raster.width, height: raster.height, scale: 1 };
|
|
13
|
+
const ratio = maxEdge / longEdge;
|
|
14
|
+
const width = Math.max(1, Math.round(raster.width * ratio));
|
|
15
|
+
const height = Math.max(1, Math.round(raster.height * ratio));
|
|
16
|
+
return { data: encodePng(resize(raster, width, height)), width, height, scale: raster.width / width };
|
|
17
|
+
}
|
|
18
|
+
export function pngSize(png) {
|
|
19
|
+
if (png.length < 24 || !png.subarray(0, 8).equals(PNG_SIGNATURE))
|
|
20
|
+
return null;
|
|
21
|
+
return { width: png.readUInt32BE(16), height: png.readUInt32BE(20) };
|
|
22
|
+
}
|
|
23
|
+
function decodePng(png) {
|
|
24
|
+
if (png.length < 33 || !png.subarray(0, 8).equals(PNG_SIGNATURE))
|
|
25
|
+
return null;
|
|
26
|
+
let offset = 8;
|
|
27
|
+
let width = 0;
|
|
28
|
+
let height = 0;
|
|
29
|
+
let bitDepth = 0;
|
|
30
|
+
let colorType = -1;
|
|
31
|
+
let interlace = 0;
|
|
32
|
+
const idat = [];
|
|
33
|
+
while (offset + 8 <= png.length) {
|
|
34
|
+
const length = png.readUInt32BE(offset);
|
|
35
|
+
const type = png.toString("latin1", offset + 4, offset + 8);
|
|
36
|
+
const body = png.subarray(offset + 8, offset + 8 + length);
|
|
37
|
+
if (body.length !== length)
|
|
38
|
+
return null;
|
|
39
|
+
if (type === "IHDR") {
|
|
40
|
+
width = body.readUInt32BE(0);
|
|
41
|
+
height = body.readUInt32BE(4);
|
|
42
|
+
bitDepth = body[8];
|
|
43
|
+
colorType = body[9];
|
|
44
|
+
interlace = body[12];
|
|
45
|
+
}
|
|
46
|
+
else if (type === "IDAT")
|
|
47
|
+
idat.push(body);
|
|
48
|
+
else if (type === "IEND")
|
|
49
|
+
break;
|
|
50
|
+
offset += 12 + length;
|
|
51
|
+
}
|
|
52
|
+
const channels = { 0: 1, 2: 3, 4: 2, 6: 4 }[colorType];
|
|
53
|
+
if (!channels || bitDepth !== 8 || interlace !== 0 || width === 0 || height === 0 || width * height > 64_000_000)
|
|
54
|
+
return null;
|
|
55
|
+
let raw;
|
|
56
|
+
try {
|
|
57
|
+
raw = inflateSync(Buffer.concat(idat));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const stride = width * channels;
|
|
63
|
+
if (raw.length !== (stride + 1) * height)
|
|
64
|
+
return null;
|
|
65
|
+
const out = Buffer.alloc(stride * height);
|
|
66
|
+
for (let y = 0; y < height; y += 1) {
|
|
67
|
+
const filter = raw[y * (stride + 1)];
|
|
68
|
+
const src = raw.subarray(y * (stride + 1) + 1, (y + 1) * (stride + 1));
|
|
69
|
+
const row = out.subarray(y * stride, (y + 1) * stride);
|
|
70
|
+
const prev = y > 0 ? out.subarray((y - 1) * stride, y * stride) : null;
|
|
71
|
+
for (let x = 0; x < stride; x += 1) {
|
|
72
|
+
const a = x >= channels ? row[x - channels] : 0;
|
|
73
|
+
const b = prev ? prev[x] : 0;
|
|
74
|
+
const c = prev && x >= channels ? prev[x - channels] : 0;
|
|
75
|
+
let value;
|
|
76
|
+
switch (filter) {
|
|
77
|
+
case 0:
|
|
78
|
+
value = src[x];
|
|
79
|
+
break;
|
|
80
|
+
case 1:
|
|
81
|
+
value = src[x] + a;
|
|
82
|
+
break;
|
|
83
|
+
case 2:
|
|
84
|
+
value = src[x] + b;
|
|
85
|
+
break;
|
|
86
|
+
case 3:
|
|
87
|
+
value = src[x] + ((a + b) >> 1);
|
|
88
|
+
break;
|
|
89
|
+
case 4:
|
|
90
|
+
value = src[x] + paeth(a, b, c);
|
|
91
|
+
break;
|
|
92
|
+
default: return null;
|
|
93
|
+
}
|
|
94
|
+
row[x] = value & 0xff;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return { width, height, channels, data: out };
|
|
98
|
+
}
|
|
99
|
+
function paeth(a, b, c) {
|
|
100
|
+
const p = a + b - c;
|
|
101
|
+
const pa = Math.abs(p - a);
|
|
102
|
+
const pb = Math.abs(p - b);
|
|
103
|
+
const pc = Math.abs(p - c);
|
|
104
|
+
return pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
|
|
105
|
+
}
|
|
106
|
+
/** Area-average resize: each target pixel averages the source box it covers. */
|
|
107
|
+
function resize(source, width, height) {
|
|
108
|
+
const { channels } = source;
|
|
109
|
+
const out = Buffer.alloc(width * height * channels);
|
|
110
|
+
const xRatio = source.width / width;
|
|
111
|
+
const yRatio = source.height / height;
|
|
112
|
+
for (let y = 0; y < height; y += 1) {
|
|
113
|
+
const y0 = Math.floor(y * yRatio);
|
|
114
|
+
const y1 = Math.min(source.height, Math.max(y0 + 1, Math.ceil((y + 1) * yRatio)));
|
|
115
|
+
for (let x = 0; x < width; x += 1) {
|
|
116
|
+
const x0 = Math.floor(x * xRatio);
|
|
117
|
+
const x1 = Math.min(source.width, Math.max(x0 + 1, Math.ceil((x + 1) * xRatio)));
|
|
118
|
+
const count = (y1 - y0) * (x1 - x0);
|
|
119
|
+
for (let channel = 0; channel < channels; channel += 1) {
|
|
120
|
+
let sum = 0;
|
|
121
|
+
for (let sy = y0; sy < y1; sy += 1) {
|
|
122
|
+
let index = (sy * source.width + x0) * channels + channel;
|
|
123
|
+
for (let sx = x0; sx < x1; sx += 1, index += channels)
|
|
124
|
+
sum += source.data[index];
|
|
125
|
+
}
|
|
126
|
+
out[(y * width + x) * channels + channel] = Math.round(sum / count);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return { width, height, channels, data: out };
|
|
131
|
+
}
|
|
132
|
+
function encodePng(raster) {
|
|
133
|
+
const { width, height, channels } = raster;
|
|
134
|
+
const stride = width * channels;
|
|
135
|
+
const raw = Buffer.alloc((stride + 1) * height);
|
|
136
|
+
for (let y = 0; y < height; y += 1) {
|
|
137
|
+
const base = y * (stride + 1);
|
|
138
|
+
raw[base] = 1; // Sub filter compresses UI screenshots noticeably better than None.
|
|
139
|
+
for (let x = 0; x < stride; x += 1) {
|
|
140
|
+
const left = x >= channels ? raster.data[y * stride + x - channels] : 0;
|
|
141
|
+
raw[base + 1 + x] = (raster.data[y * stride + x] - left) & 0xff;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const colorType = { 1: 0, 2: 4, 3: 2, 4: 6 }[channels];
|
|
145
|
+
const header = Buffer.alloc(13);
|
|
146
|
+
header.writeUInt32BE(width, 0);
|
|
147
|
+
header.writeUInt32BE(height, 4);
|
|
148
|
+
header[8] = 8;
|
|
149
|
+
header[9] = colorType;
|
|
150
|
+
return Buffer.concat([PNG_SIGNATURE, chunk("IHDR", header), chunk("IDAT", deflateSync(raw, { level: 6 })), chunk("IEND", Buffer.alloc(0))]);
|
|
151
|
+
}
|
|
152
|
+
function chunk(type, body) {
|
|
153
|
+
const head = Buffer.alloc(8);
|
|
154
|
+
head.writeUInt32BE(body.length, 0);
|
|
155
|
+
head.write(type, 4, "latin1");
|
|
156
|
+
const crc = Buffer.alloc(4);
|
|
157
|
+
crc.writeUInt32BE(crc32(Buffer.concat([head.subarray(4), body])), 0);
|
|
158
|
+
return Buffer.concat([head, body, crc]);
|
|
159
|
+
}
|
|
160
|
+
let crcTable;
|
|
161
|
+
function crc32(data) {
|
|
162
|
+
if (!crcTable) {
|
|
163
|
+
crcTable = new Uint32Array(256);
|
|
164
|
+
for (let n = 0; n < 256; n += 1) {
|
|
165
|
+
let c = n;
|
|
166
|
+
for (let k = 0; k < 8; k += 1)
|
|
167
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
168
|
+
crcTable[n] = c >>> 0;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
let crc = 0xffffffff;
|
|
172
|
+
for (const byte of data)
|
|
173
|
+
crc = crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8);
|
|
174
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
175
|
+
}
|
|
176
|
+
/** Encode raw 8-bit RGBA pixels as a PNG (used by tests and fixtures). */
|
|
177
|
+
export function encodeRgbaPng(width, height, rgba) {
|
|
178
|
+
return encodePng({ width, height, channels: 4, data: rgba });
|
|
179
|
+
}
|
|
180
|
+
export function decodePngPixels(png) {
|
|
181
|
+
return decodePng(png);
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/computer/image.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Pinned open-computer-use release the CLI is built and tested against (plan computer-use D1/D7). */
|
|
2
|
+
export declare const OCU_VERSION = "0.3.6";
|
|
3
|
+
export interface OcuTool {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
inputSchema: Record<string, unknown>;
|
|
7
|
+
annotations?: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export interface OcuContent {
|
|
10
|
+
type: string;
|
|
11
|
+
text?: string;
|
|
12
|
+
data?: string;
|
|
13
|
+
mimeType?: string;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface OcuResult {
|
|
17
|
+
content: OcuContent[];
|
|
18
|
+
isError?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** The part of the open-computer-use MCP server the toolset depends on; tests substitute a fake. */
|
|
21
|
+
export interface OcuBackend {
|
|
22
|
+
listTools(): Promise<OcuTool[]>;
|
|
23
|
+
callTool(name: string, args: Record<string, unknown>, signal?: AbortSignal): Promise<OcuResult>;
|
|
24
|
+
close(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export declare function ocuBinaryPath(): string;
|
|
27
|
+
export declare class OcuNotInstalledError extends Error {
|
|
28
|
+
constructor(path: string);
|
|
29
|
+
}
|
|
30
|
+
/** Lazily started stdio client for the open-computer-use binary; restarts on the next call after it dies. */
|
|
31
|
+
export declare class StdioOcuBackend implements OcuBackend {
|
|
32
|
+
private readonly binary;
|
|
33
|
+
private client;
|
|
34
|
+
private starting;
|
|
35
|
+
constructor(binary?: string);
|
|
36
|
+
private connect;
|
|
37
|
+
listTools(): Promise<OcuTool[]>;
|
|
38
|
+
callTool(name: string, args: Record<string, unknown>, signal?: AbortSignal): Promise<OcuResult>;
|
|
39
|
+
close(): Promise<void>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
5
|
+
import { computerDir } from "./state.js";
|
|
6
|
+
/** Pinned open-computer-use release the CLI is built and tested against (plan computer-use D1/D7). */
|
|
7
|
+
export const OCU_VERSION = "0.3.6";
|
|
8
|
+
export function ocuBinaryPath() {
|
|
9
|
+
if (process.env.FRELY_COMPUTER_BIN)
|
|
10
|
+
return process.env.FRELY_COMPUTER_BIN;
|
|
11
|
+
const dir = join(computerDir(), "bin", OCU_VERSION);
|
|
12
|
+
if (process.platform === "darwin")
|
|
13
|
+
return join(dir, "Open Computer Use.app", "Contents", "MacOS", "OpenComputerUse");
|
|
14
|
+
return join(dir, process.platform === "win32" ? "open-computer-use.exe" : "open-computer-use");
|
|
15
|
+
}
|
|
16
|
+
export class OcuNotInstalledError extends Error {
|
|
17
|
+
constructor(path) {
|
|
18
|
+
super(`The computer-use runtime is not installed (expected ${path}). Run \`frely computer enable\` on this device to install it.`);
|
|
19
|
+
this.name = "OcuNotInstalledError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Lazily started stdio client for the open-computer-use binary; restarts on the next call after it dies. */
|
|
23
|
+
export class StdioOcuBackend {
|
|
24
|
+
binary;
|
|
25
|
+
client;
|
|
26
|
+
starting;
|
|
27
|
+
constructor(binary = ocuBinaryPath()) {
|
|
28
|
+
this.binary = binary;
|
|
29
|
+
}
|
|
30
|
+
async connect() {
|
|
31
|
+
if (this.client)
|
|
32
|
+
return this.client;
|
|
33
|
+
this.starting ??= (async () => {
|
|
34
|
+
await access(this.binary).catch(() => { throw new OcuNotInstalledError(this.binary); });
|
|
35
|
+
const transport = new StdioClientTransport({ command: this.binary, args: ["mcp"], stderr: "ignore" });
|
|
36
|
+
const client = new Client({ name: "frely-cli-computer", version: "1" });
|
|
37
|
+
client.onclose = () => { if (this.client === client)
|
|
38
|
+
this.client = undefined; };
|
|
39
|
+
await client.connect(transport);
|
|
40
|
+
this.client = client;
|
|
41
|
+
return client;
|
|
42
|
+
})().finally(() => { this.starting = undefined; });
|
|
43
|
+
return this.starting;
|
|
44
|
+
}
|
|
45
|
+
async listTools() {
|
|
46
|
+
const result = await (await this.connect()).listTools();
|
|
47
|
+
return result.tools;
|
|
48
|
+
}
|
|
49
|
+
async callTool(name, args, signal) {
|
|
50
|
+
const result = await (await this.connect()).callTool({ name, arguments: args }, undefined, { ...(signal ? { signal } : {}), timeout: 60_000 });
|
|
51
|
+
return { content: (result.content ?? []), ...(result.isError ? { isError: true } : {}) };
|
|
52
|
+
}
|
|
53
|
+
async close() {
|
|
54
|
+
const client = this.client;
|
|
55
|
+
this.client = undefined;
|
|
56
|
+
await client?.close().catch(() => undefined);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=ocu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ocu.js","sourceRoot":"","sources":["../../src/computer/ocu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pinned open-computer-use release (plan computer-use D7): the npm tarball bundles every platform's
|
|
3
|
+
* binary, and its sha512 integrity is fixed here, so a changed or tampered download is refused.
|
|
4
|
+
* Bumping OCU_VERSION means updating both constants from `npm view open-computer-use@<version> dist`.
|
|
5
|
+
*/
|
|
6
|
+
export declare const OCU_TARBALL_URL = "https://registry.npmjs.org/open-computer-use/-/open-computer-use-0.3.6.tgz";
|
|
7
|
+
export declare const OCU_TARBALL_INTEGRITY = "sha512-pGNfWBBefl5qzQMo6rkC/e28sOfeczTQ0hEKkYn2sXwti38uz+fC4Y0oBdtnNACemsNVR06Dzp6SozJjkpkbSg==";
|
|
8
|
+
export declare class OcuRuntimeError extends Error {
|
|
9
|
+
readonly code: "unsupported_platform" | "download_failed" | "integrity_mismatch" | "extract_failed";
|
|
10
|
+
constructor(code: "unsupported_platform" | "download_failed" | "integrity_mismatch" | "extract_failed", message: string);
|
|
11
|
+
}
|
|
12
|
+
export interface OcuRuntimeOptions {
|
|
13
|
+
fetchImpl?: typeof fetch;
|
|
14
|
+
url?: string;
|
|
15
|
+
integrity?: string;
|
|
16
|
+
platform?: NodeJS.Platform;
|
|
17
|
+
arch?: string;
|
|
18
|
+
/** Install target; defaults to the directory the toolset launches the binary from. */
|
|
19
|
+
binaryPath?: string;
|
|
20
|
+
}
|
|
21
|
+
/** Download the pinned tarball, verify its integrity, and install this platform's runtime. Idempotent. */
|
|
22
|
+
export declare function installOcuRuntime(options?: OcuRuntimeOptions): Promise<string>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { execFile as execFileCallback } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { chmod, cp, mkdir, mkdtemp, rename, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { OCU_VERSION, ocuBinaryPath } from "./ocu.js";
|
|
7
|
+
const execFile = promisify(execFileCallback);
|
|
8
|
+
/**
|
|
9
|
+
* The pinned open-computer-use release (plan computer-use D7): the npm tarball bundles every platform's
|
|
10
|
+
* binary, and its sha512 integrity is fixed here, so a changed or tampered download is refused.
|
|
11
|
+
* Bumping OCU_VERSION means updating both constants from `npm view open-computer-use@<version> dist`.
|
|
12
|
+
*/
|
|
13
|
+
export const OCU_TARBALL_URL = `https://registry.npmjs.org/open-computer-use/-/open-computer-use-${OCU_VERSION}.tgz`;
|
|
14
|
+
export const OCU_TARBALL_INTEGRITY = "sha512-pGNfWBBefl5qzQMo6rkC/e28sOfeczTQ0hEKkYn2sXwti38uz+fC4Y0oBdtnNACemsNVR06Dzp6SozJjkpkbSg==";
|
|
15
|
+
const MAX_TARBALL_BYTES = 64 * 1024 * 1024;
|
|
16
|
+
export class OcuRuntimeError extends Error {
|
|
17
|
+
code;
|
|
18
|
+
constructor(code, message) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.code = code;
|
|
21
|
+
this.name = "OcuRuntimeError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Path of the part of the tarball to extract for this platform, and what it becomes in the install directory. */
|
|
25
|
+
function layout(platform, arch) {
|
|
26
|
+
const cpu = arch === "arm64" ? "arm64" : arch === "x64" ? "amd64" : undefined;
|
|
27
|
+
if (platform === "darwin" && (arch === "arm64" || arch === "x64"))
|
|
28
|
+
return { member: "package/dist/Open Computer Use.app", kind: "app", source: "Open Computer Use.app" };
|
|
29
|
+
if (platform === "linux" && cpu)
|
|
30
|
+
return { member: `package/dist/linux/${cpu}/open-computer-use`, kind: "binary", source: `dist/linux/${cpu}/open-computer-use` };
|
|
31
|
+
if (platform === "win32" && cpu)
|
|
32
|
+
return { member: `package/dist/windows/${cpu}/open-computer-use.exe`, kind: "binary", source: `dist/windows/${cpu}/open-computer-use.exe` };
|
|
33
|
+
throw new OcuRuntimeError("unsupported_platform", `Computer use is not available for ${platform}-${arch}.`);
|
|
34
|
+
}
|
|
35
|
+
/** Download the pinned tarball, verify its integrity, and install this platform's runtime. Idempotent. */
|
|
36
|
+
export async function installOcuRuntime(options = {}) {
|
|
37
|
+
const target = options.binaryPath ?? ocuBinaryPath();
|
|
38
|
+
const plan = layout(options.platform ?? process.platform, options.arch ?? process.arch);
|
|
39
|
+
const url = options.url ?? OCU_TARBALL_URL;
|
|
40
|
+
if (!url.startsWith("https://") && !(options.url && options.fetchImpl))
|
|
41
|
+
throw new OcuRuntimeError("download_failed", "The runtime must be downloaded over HTTPS.");
|
|
42
|
+
const response = await (options.fetchImpl ?? fetch)(url).catch((error) => {
|
|
43
|
+
throw new OcuRuntimeError("download_failed", `Could not download the computer-use runtime: ${error instanceof Error ? error.message : "network error"}`);
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok)
|
|
46
|
+
throw new OcuRuntimeError("download_failed", `Could not download the computer-use runtime (HTTP ${response.status}).`);
|
|
47
|
+
const bytes = Buffer.from(await response.arrayBuffer());
|
|
48
|
+
if (bytes.length > MAX_TARBALL_BYTES)
|
|
49
|
+
throw new OcuRuntimeError("download_failed", "The runtime download is larger than expected.");
|
|
50
|
+
const expected = options.integrity ?? OCU_TARBALL_INTEGRITY;
|
|
51
|
+
if (`sha512-${createHash("sha512").update(bytes).digest("base64")}` !== expected) {
|
|
52
|
+
throw new OcuRuntimeError("integrity_mismatch", "The downloaded runtime does not match the pinned checksum and was discarded.");
|
|
53
|
+
}
|
|
54
|
+
const installDir = plan.kind === "app" ? dirname(dirname(dirname(dirname(target)))) : dirname(target);
|
|
55
|
+
await mkdir(dirname(installDir), { recursive: true });
|
|
56
|
+
const stage = await mkdtemp(join(dirname(installDir), ".computer-install-"));
|
|
57
|
+
try {
|
|
58
|
+
const archive = join(stage, "runtime.tgz");
|
|
59
|
+
await writeFile(archive, bytes);
|
|
60
|
+
try {
|
|
61
|
+
await execFile("tar", ["-xzf", archive, "-C", stage, plan.member], { timeout: 120_000 });
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
throw new OcuRuntimeError("extract_failed", `Could not unpack the computer-use runtime: ${error instanceof Error ? error.message : "tar failed"}`);
|
|
65
|
+
}
|
|
66
|
+
const extracted = join(stage, "package", "dist", ...(plan.kind === "app" ? [plan.source] : plan.source.split("/").slice(1)));
|
|
67
|
+
const staged = join(stage, "ready");
|
|
68
|
+
await mkdir(staged, { recursive: true });
|
|
69
|
+
if (plan.kind === "app")
|
|
70
|
+
await cp(extracted, join(staged, plan.source), { recursive: true });
|
|
71
|
+
else {
|
|
72
|
+
await cp(extracted, join(staged, plan.source.split("/").pop()));
|
|
73
|
+
if (process.platform !== "win32")
|
|
74
|
+
await chmod(join(staged, plan.source.split("/").pop()), 0o755);
|
|
75
|
+
}
|
|
76
|
+
await rm(installDir, { recursive: true, force: true });
|
|
77
|
+
await mkdir(dirname(installDir), { recursive: true });
|
|
78
|
+
await rename(staged, installDir);
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
await rm(stage, { recursive: true, force: true });
|
|
82
|
+
}
|
|
83
|
+
return target;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/computer/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
3
|
+
import { ComputerToolset } from "./toolset.js";
|
|
4
|
+
/** Name `frely computer enable` registers in the local MCP list; the web page turns it on by this name. */
|
|
5
|
+
export declare const COMPUTER_MCP_NAME = "computer";
|
|
6
|
+
/** The local key of the two-key rule: computer use works only while its entry is in the local MCP list. */
|
|
7
|
+
export declare function computerEntryRegistered(): Promise<boolean>;
|
|
8
|
+
export declare function createComputerToolset(): ComputerToolset;
|
|
9
|
+
/** MCP server over the guarded toolset. Local MCP forwarding starts it as a stdio server (`frely computer mcp`). */
|
|
10
|
+
export declare function createComputerMcpServer(toolset: ComputerToolset): Server;
|
|
11
|
+
export declare function runComputerMcpServer(transport?: Transport, toolset?: ComputerToolset): Promise<void>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { VERSION } from "../version.js";
|
|
5
|
+
import { loadManualEntries } from "../runtime/local-mcp.js";
|
|
6
|
+
import { StdioOcuBackend } from "./ocu.js";
|
|
7
|
+
import { ComputerToolset } from "./toolset.js";
|
|
8
|
+
/** Name `frely computer enable` registers in the local MCP list; the web page turns it on by this name. */
|
|
9
|
+
export const COMPUTER_MCP_NAME = "computer";
|
|
10
|
+
/** The local key of the two-key rule: computer use works only while its entry is in the local MCP list. */
|
|
11
|
+
export async function computerEntryRegistered() {
|
|
12
|
+
return (await loadManualEntries().catch(() => [])).some((entry) => entry.name === COMPUTER_MCP_NAME && entry.transport === "stdio");
|
|
13
|
+
}
|
|
14
|
+
export function createComputerToolset() {
|
|
15
|
+
return new ComputerToolset({ backend: new StdioOcuBackend(), isLocallyEnabled: computerEntryRegistered });
|
|
16
|
+
}
|
|
17
|
+
/** MCP server over the guarded toolset. Local MCP forwarding starts it as a stdio server (`frely computer mcp`). */
|
|
18
|
+
export function createComputerMcpServer(toolset) {
|
|
19
|
+
const server = new Server({ name: "frely-computer", version: VERSION }, { capabilities: { tools: {} } });
|
|
20
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: await toolset.listTools() }));
|
|
21
|
+
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
22
|
+
const result = await toolset.call(request.params.name, (request.params.arguments ?? {}), extra.signal);
|
|
23
|
+
return { content: result.content, ...(result.isError ? { isError: true } : {}) };
|
|
24
|
+
});
|
|
25
|
+
server.onclose = () => { void toolset.close(); };
|
|
26
|
+
return server;
|
|
27
|
+
}
|
|
28
|
+
export async function runComputerMcpServer(transport = new StdioServerTransport(), toolset = createComputerToolset()) {
|
|
29
|
+
await createComputerMcpServer(toolset).connect(transport);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/computer/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AACnG,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,2GAA2G;AAC3G,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAE5C,2GAA2G;AAC3G,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAC3C,OAAO,CAAC,MAAM,iBAAiB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,iBAAiB,IAAI,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC;AACtI,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,eAAe,EAAE,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,CAAC,CAAC;AAC5G,CAAC;AAED,oHAAoH;AACpH,MAAM,UAAU,uBAAuB,CAAC,OAAwB;IAC9D,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACzG,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;IACrG,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAA4B,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAClI,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAsE,CAAC;IACvJ,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,YAAuB,IAAI,oBAAoB,EAAE,EAAE,UAA2B,qBAAqB,EAAE;IAC9I,MAAM,uBAAuB,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function computerDir(): string;
|
|
2
|
+
export interface ComputerAuditEntry {
|
|
3
|
+
ts: string;
|
|
4
|
+
tool: string;
|
|
5
|
+
app?: string;
|
|
6
|
+
ok: boolean;
|
|
7
|
+
ms: number;
|
|
8
|
+
reason?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Metadata only: never the screenshot, the typed text or any tool output. Failures here never affect the call. */
|
|
11
|
+
export declare function appendComputerAudit(entry: ComputerAuditEntry): Promise<void>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { appendFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
export function computerDir() {
|
|
5
|
+
return join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "frely", "computer");
|
|
6
|
+
}
|
|
7
|
+
const auditPath = () => join(computerDir(), "audit.jsonl");
|
|
8
|
+
/** Metadata only: never the screenshot, the typed text or any tool output. Failures here never affect the call. */
|
|
9
|
+
export async function appendComputerAudit(entry) {
|
|
10
|
+
try {
|
|
11
|
+
const path = auditPath();
|
|
12
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
13
|
+
await appendFile(path, `${JSON.stringify(entry)}\n`, { mode: 0o600 });
|
|
14
|
+
}
|
|
15
|
+
catch { /* best effort */ }
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/computer/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAC9F,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa,CAAC,CAAC;AAI3D,mHAAmH;AACnH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,KAAyB;IACjE,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;QACzB,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7D,MAAM,UAAU,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { OcuBackend, OcuResult, OcuTool } from "./ocu.js";
|
|
2
|
+
import { type ComputerAuditEntry } from "./state.js";
|
|
3
|
+
export interface ComputerToolsetOptions {
|
|
4
|
+
backend: OcuBackend;
|
|
5
|
+
/** Local key of the two-key rule (the registered local MCP entry); checked on every list and call so `frely computer disable` takes effect at once. */
|
|
6
|
+
isLocallyEnabled: () => Promise<boolean>;
|
|
7
|
+
audit?: (entry: ComputerAuditEntry) => Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare class ComputerToolset {
|
|
10
|
+
private readonly backend;
|
|
11
|
+
private readonly isLocallyEnabled;
|
|
12
|
+
private readonly audit;
|
|
13
|
+
/** original / sent size per app, from its latest screenshot, to map model coordinates back to device pixels. */
|
|
14
|
+
private readonly scales;
|
|
15
|
+
constructor(options: ComputerToolsetOptions);
|
|
16
|
+
available(): Promise<boolean>;
|
|
17
|
+
listTools(): Promise<OcuTool[]>;
|
|
18
|
+
call(name: string, args: Record<string, unknown>, signal?: AbortSignal): Promise<OcuResult>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
private scaleCoordinates;
|
|
21
|
+
private shapeScreenshots;
|
|
22
|
+
}
|