@agimon-ai/po-computer-use 0.0.0-alpha.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/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/apiContracts.cjs +242 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +53 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +237 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/extensionService-Bp0q295i.cjs +504 -0
- package/dist/extensionService-Bp0q295i.cjs.map +1 -0
- package/dist/extensionService-DXvF7esO.mjs +434 -0
- package/dist/extensionService-DXvF7esO.mjs.map +1 -0
- package/dist/extensions/mcp-ui.mjs +47 -0
- package/dist/extensions/mcp-ui.mjs.map +1 -0
- package/dist/extensions/mcp.cjs +66 -0
- package/dist/extensions/mcp.cjs.map +1 -0
- package/dist/extensions/mcp.d.mts +5 -0
- package/dist/extensions/mcp.d.mts.map +1 -0
- package/dist/extensions/mcp.mjs +61 -0
- package/dist/extensions/mcp.mjs.map +1 -0
- package/dist/extensions/server.cjs +1394 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +1388 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +771 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/index.cjs +140 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +325 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +129 -0
- package/dist/index.mjs.map +1 -0
- package/docs/computer-scripts.md +72 -0
- package/llms.txt +12 -0
- package/package.json +147 -0
- package/src/prompts/po-use-computer-use/SKILL.md +34 -0
- package/src/types/computerUse.ts +132 -0
- package/src/types/computerUseApi.ts +83 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { realpath } from "node:fs/promises";
|
|
5
|
+
//#region src/constants/computerUse.ts
|
|
6
|
+
const COMPUTER_USE_GUIDANCE = `[COMPUTER USE ACTIVE]
|
|
7
|
+
Use computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Use computer_action for one semantic press, focus, set_value, or scroll at a time. Use computer_exec only for a trusted, explicitly allowed local TypeScript script. Never infer coordinates, inspect another application, bypass secure elements, or retry an uncertain outcome. Stop computer use when the task is complete.`;
|
|
8
|
+
const COMMAND_NAME = "computer-use";
|
|
9
|
+
const COMMAND_DESCRIPTION = "Inspect or manage the session computer use mode";
|
|
10
|
+
const COMPUTER_USE_TOOL_NAMES = [
|
|
11
|
+
"computer_state",
|
|
12
|
+
"computer_action",
|
|
13
|
+
"computer_exec"
|
|
14
|
+
];
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/services/computerScriptWorker/index.ts
|
|
17
|
+
/** Source for an isolated child process. Restricted modules execute in QuickJS, not in Node's realm. */
|
|
18
|
+
const COMPUTER_SCRIPT_WORKER_SOURCE = String.raw`
|
|
19
|
+
import { readFileSync, realpathSync, statSync } from 'node:fs';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
import { stripTypeScriptTypes } from 'node:module';
|
|
22
|
+
import { pathToFileURL } from 'node:url';
|
|
23
|
+
|
|
24
|
+
let nextRequestId = 0;
|
|
25
|
+
let started = false;
|
|
26
|
+
const pending = new Map();
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
process.once('SIGTERM', () => controller.abort());
|
|
29
|
+
const send = (message) => {
|
|
30
|
+
if (process.connected) process.send(message, () => {});
|
|
31
|
+
};
|
|
32
|
+
const call = (operation, payload) => new Promise((resolve, reject) => {
|
|
33
|
+
if (controller.signal.aborted) return reject(new Error('Computer script was cancelled.'));
|
|
34
|
+
if (pending.size >= 64) return reject(new Error('Too many outstanding program operations.'));
|
|
35
|
+
const id = String(++nextRequestId);
|
|
36
|
+
pending.set(id, { resolve, reject });
|
|
37
|
+
send({ type: 'program', id, operation, payload });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
async function restricted(message) {
|
|
41
|
+
const { getQuickJS } = await import(pathToFileURL(message.quickjsPath).href);
|
|
42
|
+
const QuickJS = await getQuickJS();
|
|
43
|
+
const runtime = QuickJS.newRuntime();
|
|
44
|
+
runtime.setMemoryLimit(32 * 1024 * 1024);
|
|
45
|
+
runtime.setMaxStackSize(512 * 1024);
|
|
46
|
+
const deadline = Date.now() + message.timeoutMs;
|
|
47
|
+
runtime.setInterruptHandler(() => controller.signal.aborted || Date.now() >= deadline);
|
|
48
|
+
const root = realpathSync(message.scriptRoot);
|
|
49
|
+
const sources = new Map();
|
|
50
|
+
let sourceBytes = 0;
|
|
51
|
+
let moduleFailure;
|
|
52
|
+
const modulePath = (candidate) => {
|
|
53
|
+
const filename = realpathSync(candidate);
|
|
54
|
+
const relative = path.relative(root, filename);
|
|
55
|
+
if (relative === '..' || relative.startsWith('..' + path.sep) || path.isAbsolute(relative)) {
|
|
56
|
+
throw new Error('Computer helper escapes the admitted script root.');
|
|
57
|
+
}
|
|
58
|
+
if (!/\.(ts|js|mjs)$/.test(filename)) throw new Error('Computer helpers must be JavaScript or erasable TypeScript.');
|
|
59
|
+
return filename;
|
|
60
|
+
};
|
|
61
|
+
const entry = modulePath(message.scriptPath);
|
|
62
|
+
runtime.setModuleLoader((filename) => {
|
|
63
|
+
// Preserve a rejected normalization even if the engine subsequently asks to load an empty name.
|
|
64
|
+
if (moduleFailure) throw moduleFailure;
|
|
65
|
+
if (sources.has(filename)) return sources.get(filename);
|
|
66
|
+
if (sources.size >= 32 || statSync(filename).size > 256 * 1024) throw new Error('Computer script module limit exceeded.');
|
|
67
|
+
const source = readFileSync(filename, 'utf8');
|
|
68
|
+
sourceBytes += Buffer.byteLength(source);
|
|
69
|
+
if (sourceBytes > 512 * 1024) throw new Error('Computer script source limit exceeded.');
|
|
70
|
+
const compiled = filename.endsWith('.ts') ? stripTypeScriptTypes(source, { mode: 'strip' }) : source;
|
|
71
|
+
sources.set(filename, compiled);
|
|
72
|
+
return compiled;
|
|
73
|
+
}, (base, name) => {
|
|
74
|
+
try {
|
|
75
|
+
if (name === '__entry__') return entry;
|
|
76
|
+
if (!name.startsWith('./') && !name.startsWith('../')) {
|
|
77
|
+
throw new Error('Restricted computer functions cannot import host or package modules.');
|
|
78
|
+
}
|
|
79
|
+
return modulePath(path.resolve(path.dirname(base), name));
|
|
80
|
+
} catch (error) {
|
|
81
|
+
moduleFailure = error;
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
const vm = runtime.newContext();
|
|
86
|
+
let disposed = false;
|
|
87
|
+
const deferreds = new Set();
|
|
88
|
+
const pump = () => {
|
|
89
|
+
if (disposed) return;
|
|
90
|
+
const jobs = runtime.executePendingJobs();
|
|
91
|
+
if (jobs.error) {
|
|
92
|
+
const detail = vm.dump(jobs.error);
|
|
93
|
+
jobs.error.dispose();
|
|
94
|
+
throw new Error(detail?.message ?? String(detail));
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const set = (name, value) => {
|
|
98
|
+
vm.setProp(vm.global, name, value);
|
|
99
|
+
value.dispose();
|
|
100
|
+
};
|
|
101
|
+
set('__input', vm.newString(JSON.stringify(message.input)));
|
|
102
|
+
set('__aborted', vm.newFunction('__aborted', () => controller.signal.aborted ? vm.true : vm.false));
|
|
103
|
+
set('__log', vm.newFunction('__log', (level, text) => {
|
|
104
|
+
send({ type: 'log', level: vm.getString(level), message: vm.getString(text) });
|
|
105
|
+
}));
|
|
106
|
+
set('__call', vm.newFunction('__call', (operationHandle, payloadHandle) => {
|
|
107
|
+
const operation = vm.getString(operationHandle);
|
|
108
|
+
const serialized = vm.getString(payloadHandle);
|
|
109
|
+
if (serialized.length > message.maxOutputBytes) throw new Error('Computer action exceeds the size limit.');
|
|
110
|
+
if (operation !== 'observe' && operation !== 'act') throw new Error('Unsupported program operation.');
|
|
111
|
+
const deferred = vm.newPromise();
|
|
112
|
+
deferreds.add(deferred);
|
|
113
|
+
call(operation, JSON.parse(serialized)).then((value) => {
|
|
114
|
+
if (disposed) return;
|
|
115
|
+
const handle = vm.newString(JSON.stringify(value));
|
|
116
|
+
deferred.resolve(handle);
|
|
117
|
+
handle.dispose();
|
|
118
|
+
}, (error) => {
|
|
119
|
+
if (disposed) return;
|
|
120
|
+
const handle = vm.newError(error.message);
|
|
121
|
+
deferred.reject(handle);
|
|
122
|
+
handle.dispose();
|
|
123
|
+
}).then(() => {
|
|
124
|
+
if (disposed) return;
|
|
125
|
+
deferred.dispose();
|
|
126
|
+
deferreds.delete(deferred);
|
|
127
|
+
pump();
|
|
128
|
+
}).catch((error) => send({ type: 'failed', error: error.message }));
|
|
129
|
+
return deferred.handle.dup();
|
|
130
|
+
}));
|
|
131
|
+
let evaluation;
|
|
132
|
+
try {
|
|
133
|
+
evaluation = vm.unwrapResult(vm.evalCode(
|
|
134
|
+
'import { run } from "__entry__";\n' +
|
|
135
|
+
'const invoke = __call; const log = __log; const isAborted = __aborted;\n' +
|
|
136
|
+
'const program = Object.freeze({\n' +
|
|
137
|
+
' observe: async (options = {}) => JSON.parse(await invoke("observe", JSON.stringify(options))),\n' +
|
|
138
|
+
' act: async (action) => JSON.parse(await invoke("act", JSON.stringify(action)))\n' +
|
|
139
|
+
'});\n' +
|
|
140
|
+
'const logger = Object.freeze(Object.fromEntries(["debug","info","warn","error"].map(level => [level, value => log(level, String(value))])));\n' +
|
|
141
|
+
'const signal = Object.freeze({ get aborted() { return isAborted(); }, throwIfAborted() { if (isAborted()) throw new Error("Computer script was cancelled."); } });\n' +
|
|
142
|
+
'const result = await run({ context: { program }, input: JSON.parse(__input), logger, signal });\n' +
|
|
143
|
+
'globalThis.__result = result === undefined ? undefined : JSON.stringify(result);',
|
|
144
|
+
path.join(root, '__computer_entry__.mjs'), { type: 'module' },
|
|
145
|
+
));
|
|
146
|
+
const completion = vm.resolvePromise(evaluation);
|
|
147
|
+
pump();
|
|
148
|
+
const completed = vm.unwrapResult(await completion);
|
|
149
|
+
completed.dispose();
|
|
150
|
+
const result = vm.getProp(vm.global, '__result');
|
|
151
|
+
const resultJson = vm.dump(result);
|
|
152
|
+
result.dispose();
|
|
153
|
+
return resultJson;
|
|
154
|
+
} finally {
|
|
155
|
+
disposed = true;
|
|
156
|
+
for (const deferred of deferreds) deferred.dispose();
|
|
157
|
+
evaluation?.dispose();
|
|
158
|
+
vm.dispose();
|
|
159
|
+
runtime.dispose();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
process.on('message', async (message) => {
|
|
164
|
+
if (message?.type === 'response') {
|
|
165
|
+
const request = pending.get(message.id);
|
|
166
|
+
if (!request) return;
|
|
167
|
+
pending.delete(message.id);
|
|
168
|
+
if (message.error) request.reject(new Error(message.error));
|
|
169
|
+
else request.resolve(message.value);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (message?.type !== 'start' || started) return;
|
|
173
|
+
started = true;
|
|
174
|
+
try {
|
|
175
|
+
let resultJson;
|
|
176
|
+
if (message.trusted) {
|
|
177
|
+
const loaded = await import(pathToFileURL(message.scriptPath).href);
|
|
178
|
+
if (typeof loaded.run !== 'function') throw new Error('Computer script must export a named run function.');
|
|
179
|
+
const program = {
|
|
180
|
+
observe: (options = {}) => call('observe', options),
|
|
181
|
+
act: (action) => call('act', action),
|
|
182
|
+
};
|
|
183
|
+
const logger = Object.fromEntries(['debug','info','warn','error'].map(level => [level, value => {
|
|
184
|
+
send({ type: 'log', level, message: String(value) });
|
|
185
|
+
}]));
|
|
186
|
+
const result = await loaded.run({ context: { program }, input: message.input, logger, signal: controller.signal });
|
|
187
|
+
resultJson = result === undefined ? undefined : JSON.stringify(result);
|
|
188
|
+
} else {
|
|
189
|
+
resultJson = await restricted(message);
|
|
190
|
+
}
|
|
191
|
+
if (typeof resultJson === 'string' && Buffer.byteLength(resultJson) > message.maxOutputBytes) {
|
|
192
|
+
throw new Error('Computer script result exceeded the size limit.');
|
|
193
|
+
}
|
|
194
|
+
send({ type: 'complete', resultJson });
|
|
195
|
+
} catch (error) {
|
|
196
|
+
send({ type: 'failed', error: String(error?.message ?? error).slice(0, 1024) });
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
`;
|
|
200
|
+
//#endregion
|
|
201
|
+
//#region src/services/computerScriptRunner/index.ts
|
|
202
|
+
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
203
|
+
const DEFAULT_MAX_OUTPUT_BYTES = 262144;
|
|
204
|
+
const MAX_IMAGE_BYTES = 6291456;
|
|
205
|
+
const MAX_PENDING_OPERATIONS = 64;
|
|
206
|
+
var ComputerScriptExecutionError = class extends Error {
|
|
207
|
+
completedActions;
|
|
208
|
+
outcomeUncertain;
|
|
209
|
+
constructor(message, completedActions, outcomeUncertain) {
|
|
210
|
+
super(message);
|
|
211
|
+
this.completedActions = completedActions;
|
|
212
|
+
this.outcomeUncertain = outcomeUncertain;
|
|
213
|
+
this.name = "ComputerScriptExecutionError";
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
var ComputerScriptRunner = class {
|
|
217
|
+
client;
|
|
218
|
+
allowedScriptPaths;
|
|
219
|
+
scriptRoot;
|
|
220
|
+
timeoutMs;
|
|
221
|
+
maxOutputBytes;
|
|
222
|
+
constructor(options) {
|
|
223
|
+
this.client = options.client;
|
|
224
|
+
this.allowedScriptPaths = options.allowedScriptPaths;
|
|
225
|
+
this.scriptRoot = options.scriptRoot;
|
|
226
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
227
|
+
this.maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
|
|
228
|
+
}
|
|
229
|
+
async execute(scriptPath, input, signal, options = {}, cwd) {
|
|
230
|
+
signal?.throwIfAborted();
|
|
231
|
+
const resolvedPath = await realpath(path.resolve(this.scriptRoot ?? cwd ?? process.cwd(), scriptPath));
|
|
232
|
+
const allowedPaths = await Promise.all(this.allowedScriptPaths.map(async (candidate) => realpath(candidate).catch(() => "")));
|
|
233
|
+
const trusted = options.trusted === true;
|
|
234
|
+
if ((trusted || this.scriptRoot === void 0) && !allowedPaths.includes(resolvedPath)) throw new Error("Computer script path is not explicitly allowed.");
|
|
235
|
+
if (!/\.(ts|js|mjs)$/u.test(resolvedPath)) throw new Error("Computer scripts must be JavaScript or erasable TypeScript files.");
|
|
236
|
+
const root = await realpath(this.scriptRoot ?? path.dirname(resolvedPath));
|
|
237
|
+
const relative = path.relative(root, resolvedPath);
|
|
238
|
+
if (!trusted && (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))) throw new Error("Computer script escapes the admitted script root.");
|
|
239
|
+
const serializedInput = JSON.stringify(input);
|
|
240
|
+
if (serializedInput === void 0) throw new Error("Computer script input must be JSON serializable.");
|
|
241
|
+
if (Buffer.byteLength(serializedInput) > this.maxOutputBytes) throw new Error("Computer script input exceeds the size limit.");
|
|
242
|
+
const quickjsPath = trusted ? void 0 : createRequire(import.meta.url).resolve("quickjs-emscripten");
|
|
243
|
+
signal?.throwIfAborted();
|
|
244
|
+
const started = performance.now();
|
|
245
|
+
return new Promise((resolve, reject) => {
|
|
246
|
+
const child = spawn(process.execPath, [
|
|
247
|
+
"--input-type=module",
|
|
248
|
+
"--eval",
|
|
249
|
+
COMPUTER_SCRIPT_WORKER_SOURCE
|
|
250
|
+
], {
|
|
251
|
+
stdio: [
|
|
252
|
+
"ignore",
|
|
253
|
+
"pipe",
|
|
254
|
+
"pipe",
|
|
255
|
+
"ipc"
|
|
256
|
+
],
|
|
257
|
+
env: trusted ? process.env : { ELECTRON_RUN_AS_NODE: "1" }
|
|
258
|
+
});
|
|
259
|
+
const controller = new AbortController();
|
|
260
|
+
const logs = [];
|
|
261
|
+
let outputBytes = 0;
|
|
262
|
+
let completedActions = 0;
|
|
263
|
+
let observations = 0;
|
|
264
|
+
let actionInFlight = false;
|
|
265
|
+
let settled = false;
|
|
266
|
+
let completing = false;
|
|
267
|
+
let outstanding = 0;
|
|
268
|
+
let operation = Promise.resolve();
|
|
269
|
+
const finish = (error, value) => {
|
|
270
|
+
if (settled) return;
|
|
271
|
+
settled = true;
|
|
272
|
+
clearTimeout(timeout);
|
|
273
|
+
signal?.removeEventListener("abort", onAbort);
|
|
274
|
+
controller.abort();
|
|
275
|
+
child.kill("SIGTERM");
|
|
276
|
+
setTimeout(() => child.kill("SIGKILL"), 250).unref();
|
|
277
|
+
if (error) reject(new ComputerScriptExecutionError(error.message, completedActions, actionInFlight));
|
|
278
|
+
else resolve(value);
|
|
279
|
+
};
|
|
280
|
+
const addOutput = (value) => {
|
|
281
|
+
outputBytes += Buffer.byteLength(value);
|
|
282
|
+
if (outputBytes <= this.maxOutputBytes) return true;
|
|
283
|
+
finish(/* @__PURE__ */ new Error("Computer script output exceeded the size limit."));
|
|
284
|
+
return false;
|
|
285
|
+
};
|
|
286
|
+
const send = (value) => {
|
|
287
|
+
if (settled || !child.connected) return;
|
|
288
|
+
child.send(value, (error) => {
|
|
289
|
+
if (error && !settled) finish(error);
|
|
290
|
+
});
|
|
291
|
+
};
|
|
292
|
+
const onAbort = () => finish(/* @__PURE__ */ new Error("Computer script execution was cancelled."));
|
|
293
|
+
const timeout = setTimeout(() => finish(/* @__PURE__ */ new Error("Computer script execution timed out.")), this.timeoutMs);
|
|
294
|
+
timeout.unref();
|
|
295
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
296
|
+
if (signal?.aborted) return onAbort();
|
|
297
|
+
child.stdout?.on("data", (chunk) => addOutput(chunk.toString("utf8")));
|
|
298
|
+
child.stderr?.on("data", (chunk) => addOutput(chunk.toString("utf8")));
|
|
299
|
+
child.on("error", (error) => finish(error));
|
|
300
|
+
child.on("exit", (code, exitSignal) => {
|
|
301
|
+
if (!settled) finish(/* @__PURE__ */ new Error(`Computer script worker exited before completion (${exitSignal ?? code ?? "unknown"}).`));
|
|
302
|
+
});
|
|
303
|
+
const observe = async (includeScreenshot) => {
|
|
304
|
+
const value = await this.client.observe(controller.signal, { includeScreenshot });
|
|
305
|
+
observations += 1;
|
|
306
|
+
const { screenshot, ...semantic } = value;
|
|
307
|
+
if (Buffer.byteLength(JSON.stringify(semantic)) > this.maxOutputBytes) throw new Error("Computer observation exceeds the size limit.");
|
|
308
|
+
if (includeScreenshot && screenshot) {
|
|
309
|
+
if (screenshot.mimeType !== "image/png" || screenshot.data.length > Math.ceil(MAX_IMAGE_BYTES / 3) * 4) throw new Error("Computer screenshot exceeds the image limit.");
|
|
310
|
+
return {
|
|
311
|
+
...semantic,
|
|
312
|
+
screenshot
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
return semantic;
|
|
316
|
+
};
|
|
317
|
+
child.on("message", (raw) => {
|
|
318
|
+
if (settled) return;
|
|
319
|
+
if (!raw || typeof raw !== "object" || Buffer.byteLength(JSON.stringify(raw)) > this.maxOutputBytes + 4096) {
|
|
320
|
+
finish(/* @__PURE__ */ new Error("Computer worker message exceeds the size limit."));
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (raw.type === "log" && typeof raw.message === "string") {
|
|
324
|
+
const line = `[${String(raw.level)}] ${raw.message}`;
|
|
325
|
+
if (addOutput(line)) logs.push(line);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (raw.type === "program") {
|
|
329
|
+
if (completing || typeof raw.id !== "string" || raw.id.length > 128 || raw.operation !== "observe" && raw.operation !== "act" || outstanding >= MAX_PENDING_OPERATIONS) {
|
|
330
|
+
finish(/* @__PURE__ */ new Error("Invalid or excessive computer program operations."));
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
outstanding += 1;
|
|
334
|
+
operation = operation.then(async () => {
|
|
335
|
+
if (settled || controller.signal.aborted) return;
|
|
336
|
+
try {
|
|
337
|
+
let value;
|
|
338
|
+
if (raw.operation === "observe") {
|
|
339
|
+
const settings = raw.payload;
|
|
340
|
+
if (!settings || typeof settings !== "object" || Array.isArray(settings) || Object.keys(settings).some((key) => key !== "includeScreenshot") || "includeScreenshot" in settings && typeof settings.includeScreenshot !== "boolean") throw new Error("Invalid observation options.");
|
|
341
|
+
value = await observe("includeScreenshot" in settings && settings.includeScreenshot === true);
|
|
342
|
+
} else {
|
|
343
|
+
actionInFlight = true;
|
|
344
|
+
value = await this.client.act(raw.payload, controller.signal);
|
|
345
|
+
completedActions += 1;
|
|
346
|
+
actionInFlight = false;
|
|
347
|
+
}
|
|
348
|
+
send({
|
|
349
|
+
type: "response",
|
|
350
|
+
id: raw.id,
|
|
351
|
+
value
|
|
352
|
+
});
|
|
353
|
+
} catch (error) {
|
|
354
|
+
if (actionInFlight) finish(error instanceof Error ? error : new Error(String(error)));
|
|
355
|
+
else send({
|
|
356
|
+
type: "response",
|
|
357
|
+
id: raw.id,
|
|
358
|
+
error: error instanceof Error ? error.message : String(error)
|
|
359
|
+
});
|
|
360
|
+
} finally {
|
|
361
|
+
outstanding -= 1;
|
|
362
|
+
}
|
|
363
|
+
}).catch((error) => finish(error instanceof Error ? error : new Error(String(error))));
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (raw.type === "failed" && typeof raw.error === "string") {
|
|
367
|
+
finish(new Error(raw.error));
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
if (raw.type === "complete") {
|
|
371
|
+
if (completing) {
|
|
372
|
+
finish(/* @__PURE__ */ new Error("Computer worker completed twice."));
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
completing = true;
|
|
376
|
+
operation = operation.then(async () => {
|
|
377
|
+
if (settled) return;
|
|
378
|
+
const resultJson = raw.resultJson;
|
|
379
|
+
if (resultJson !== void 0 && typeof resultJson !== "string") throw new Error("Computer script returned an invalid result.");
|
|
380
|
+
if (typeof resultJson === "string" && !addOutput(resultJson)) return;
|
|
381
|
+
const observation = await observe(options.includeScreenshot === true);
|
|
382
|
+
if (settled || !addOutput(JSON.stringify({
|
|
383
|
+
...observation,
|
|
384
|
+
screenshot: void 0
|
|
385
|
+
}))) return;
|
|
386
|
+
finish(void 0, {
|
|
387
|
+
...typeof resultJson === "string" ? { result: JSON.parse(resultJson) } : {},
|
|
388
|
+
observation,
|
|
389
|
+
logs,
|
|
390
|
+
metrics: {
|
|
391
|
+
actions: completedActions,
|
|
392
|
+
observations,
|
|
393
|
+
durationMs: Math.round(performance.now() - started),
|
|
394
|
+
outputBytes
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
}).catch((error) => finish(error instanceof Error ? error : new Error(String(error))));
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
send({
|
|
401
|
+
type: "start",
|
|
402
|
+
scriptPath: resolvedPath,
|
|
403
|
+
scriptRoot: root,
|
|
404
|
+
input: JSON.parse(serializedInput),
|
|
405
|
+
trusted,
|
|
406
|
+
quickjsPath,
|
|
407
|
+
timeoutMs: this.timeoutMs,
|
|
408
|
+
maxOutputBytes: this.maxOutputBytes
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
//#endregion
|
|
414
|
+
//#region src/services/extensionService/index.ts
|
|
415
|
+
var DefaultComputerUseExtensionService = class {
|
|
416
|
+
client;
|
|
417
|
+
constructor(client) {
|
|
418
|
+
this.client = client;
|
|
419
|
+
}
|
|
420
|
+
async execute() {
|
|
421
|
+
if (this.client === void 0) return {
|
|
422
|
+
message: "Computer use requires a Po Desktop session.",
|
|
423
|
+
level: "error"
|
|
424
|
+
};
|
|
425
|
+
return {
|
|
426
|
+
message: `Computer use is ${(await this.client.state()).phase.replaceAll("_", " ")}.`,
|
|
427
|
+
level: "info"
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
//#endregion
|
|
432
|
+
export { COMMAND_NAME as a, COMMAND_DESCRIPTION as i, ComputerScriptExecutionError as n, COMPUTER_USE_GUIDANCE as o, ComputerScriptRunner as r, COMPUTER_USE_TOOL_NAMES as s, DefaultComputerUseExtensionService as t };
|
|
433
|
+
|
|
434
|
+
//# sourceMappingURL=extensionService-DXvF7esO.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensionService-DXvF7esO.mjs","names":[],"sources":["../src/constants/computerUse.ts","../src/services/computerScriptWorker/index.ts","../src/services/computerScriptRunner/index.ts","../src/services/extensionService/index.ts"],"sourcesContent":["export const COMPUTER_USE_GUIDANCE = `[COMPUTER USE ACTIVE]\nUse computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Use computer_action for one semantic press, focus, set_value, or scroll at a time. Use computer_exec only for a trusted, explicitly allowed local TypeScript script. Never infer coordinates, inspect another application, bypass secure elements, or retry an uncertain outcome. Stop computer use when the task is complete.`;\nexport const COMMAND_NAME = 'computer-use';\nexport const COMMAND_DESCRIPTION = 'Inspect or manage the session computer use mode';\n\nexport const COMPUTER_USE_TOOL_NAMES = ['computer_state', 'computer_action', 'computer_exec'] as const;\n","/** Source for an isolated child process. Restricted modules execute in QuickJS, not in Node's realm. */\nexport const COMPUTER_SCRIPT_WORKER_SOURCE = String.raw`\nimport { readFileSync, realpathSync, statSync } from 'node:fs';\nimport path from 'node:path';\nimport { stripTypeScriptTypes } from 'node:module';\nimport { pathToFileURL } from 'node:url';\n\nlet nextRequestId = 0;\nlet started = false;\nconst pending = new Map();\nconst controller = new AbortController();\nprocess.once('SIGTERM', () => controller.abort());\nconst send = (message) => {\n if (process.connected) process.send(message, () => {});\n};\nconst call = (operation, payload) => new Promise((resolve, reject) => {\n if (controller.signal.aborted) return reject(new Error('Computer script was cancelled.'));\n if (pending.size >= 64) return reject(new Error('Too many outstanding program operations.'));\n const id = String(++nextRequestId);\n pending.set(id, { resolve, reject });\n send({ type: 'program', id, operation, payload });\n});\n\nasync function restricted(message) {\n const { getQuickJS } = await import(pathToFileURL(message.quickjsPath).href);\n const QuickJS = await getQuickJS();\n const runtime = QuickJS.newRuntime();\n runtime.setMemoryLimit(32 * 1024 * 1024);\n runtime.setMaxStackSize(512 * 1024);\n const deadline = Date.now() + message.timeoutMs;\n runtime.setInterruptHandler(() => controller.signal.aborted || Date.now() >= deadline);\n const root = realpathSync(message.scriptRoot);\n const sources = new Map();\n let sourceBytes = 0;\n let moduleFailure;\n const modulePath = (candidate) => {\n const filename = realpathSync(candidate);\n const relative = path.relative(root, filename);\n if (relative === '..' || relative.startsWith('..' + path.sep) || path.isAbsolute(relative)) {\n throw new Error('Computer helper escapes the admitted script root.');\n }\n if (!/\\.(ts|js|mjs)$/.test(filename)) throw new Error('Computer helpers must be JavaScript or erasable TypeScript.');\n return filename;\n };\n const entry = modulePath(message.scriptPath);\n runtime.setModuleLoader((filename) => {\n // Preserve a rejected normalization even if the engine subsequently asks to load an empty name.\n if (moduleFailure) throw moduleFailure;\n if (sources.has(filename)) return sources.get(filename);\n if (sources.size >= 32 || statSync(filename).size > 256 * 1024) throw new Error('Computer script module limit exceeded.');\n const source = readFileSync(filename, 'utf8');\n sourceBytes += Buffer.byteLength(source);\n if (sourceBytes > 512 * 1024) throw new Error('Computer script source limit exceeded.');\n const compiled = filename.endsWith('.ts') ? stripTypeScriptTypes(source, { mode: 'strip' }) : source;\n sources.set(filename, compiled);\n return compiled;\n }, (base, name) => {\n try {\n if (name === '__entry__') return entry;\n if (!name.startsWith('./') && !name.startsWith('../')) {\n throw new Error('Restricted computer functions cannot import host or package modules.');\n }\n return modulePath(path.resolve(path.dirname(base), name));\n } catch (error) {\n moduleFailure = error;\n throw error;\n }\n });\n const vm = runtime.newContext();\n let disposed = false;\n const deferreds = new Set();\n const pump = () => {\n if (disposed) return;\n const jobs = runtime.executePendingJobs();\n if (jobs.error) {\n const detail = vm.dump(jobs.error);\n jobs.error.dispose();\n throw new Error(detail?.message ?? String(detail));\n }\n };\n const set = (name, value) => {\n vm.setProp(vm.global, name, value);\n value.dispose();\n };\n set('__input', vm.newString(JSON.stringify(message.input)));\n set('__aborted', vm.newFunction('__aborted', () => controller.signal.aborted ? vm.true : vm.false));\n set('__log', vm.newFunction('__log', (level, text) => {\n send({ type: 'log', level: vm.getString(level), message: vm.getString(text) });\n }));\n set('__call', vm.newFunction('__call', (operationHandle, payloadHandle) => {\n const operation = vm.getString(operationHandle);\n const serialized = vm.getString(payloadHandle);\n if (serialized.length > message.maxOutputBytes) throw new Error('Computer action exceeds the size limit.');\n if (operation !== 'observe' && operation !== 'act') throw new Error('Unsupported program operation.');\n const deferred = vm.newPromise();\n deferreds.add(deferred);\n call(operation, JSON.parse(serialized)).then((value) => {\n if (disposed) return;\n const handle = vm.newString(JSON.stringify(value));\n deferred.resolve(handle);\n handle.dispose();\n }, (error) => {\n if (disposed) return;\n const handle = vm.newError(error.message);\n deferred.reject(handle);\n handle.dispose();\n }).then(() => {\n if (disposed) return;\n deferred.dispose();\n deferreds.delete(deferred);\n pump();\n }).catch((error) => send({ type: 'failed', error: error.message }));\n return deferred.handle.dup();\n }));\n let evaluation;\n try {\n evaluation = vm.unwrapResult(vm.evalCode(\n 'import { run } from \"__entry__\";\\n' +\n 'const invoke = __call; const log = __log; const isAborted = __aborted;\\n' +\n 'const program = Object.freeze({\\n' +\n ' observe: async (options = {}) => JSON.parse(await invoke(\"observe\", JSON.stringify(options))),\\n' +\n ' act: async (action) => JSON.parse(await invoke(\"act\", JSON.stringify(action)))\\n' +\n '});\\n' +\n 'const logger = Object.freeze(Object.fromEntries([\"debug\",\"info\",\"warn\",\"error\"].map(level => [level, value => log(level, String(value))])));\\n' +\n 'const signal = Object.freeze({ get aborted() { return isAborted(); }, throwIfAborted() { if (isAborted()) throw new Error(\"Computer script was cancelled.\"); } });\\n' +\n 'const result = await run({ context: { program }, input: JSON.parse(__input), logger, signal });\\n' +\n 'globalThis.__result = result === undefined ? undefined : JSON.stringify(result);',\n path.join(root, '__computer_entry__.mjs'), { type: 'module' },\n ));\n const completion = vm.resolvePromise(evaluation);\n pump();\n const completed = vm.unwrapResult(await completion);\n completed.dispose();\n const result = vm.getProp(vm.global, '__result');\n const resultJson = vm.dump(result);\n result.dispose();\n return resultJson;\n } finally {\n disposed = true;\n for (const deferred of deferreds) deferred.dispose();\n evaluation?.dispose();\n vm.dispose();\n runtime.dispose();\n }\n}\n\nprocess.on('message', async (message) => {\n if (message?.type === 'response') {\n const request = pending.get(message.id);\n if (!request) return;\n pending.delete(message.id);\n if (message.error) request.reject(new Error(message.error));\n else request.resolve(message.value);\n return;\n }\n if (message?.type !== 'start' || started) return;\n started = true;\n try {\n let resultJson;\n if (message.trusted) {\n const loaded = await import(pathToFileURL(message.scriptPath).href);\n if (typeof loaded.run !== 'function') throw new Error('Computer script must export a named run function.');\n const program = {\n observe: (options = {}) => call('observe', options),\n act: (action) => call('act', action),\n };\n const logger = Object.fromEntries(['debug','info','warn','error'].map(level => [level, value => {\n send({ type: 'log', level, message: String(value) });\n }]));\n const result = await loaded.run({ context: { program }, input: message.input, logger, signal: controller.signal });\n resultJson = result === undefined ? undefined : JSON.stringify(result);\n } else {\n resultJson = await restricted(message);\n }\n if (typeof resultJson === 'string' && Buffer.byteLength(resultJson) > message.maxOutputBytes) {\n throw new Error('Computer script result exceeded the size limit.');\n }\n send({ type: 'complete', resultJson });\n } catch (error) {\n send({ type: 'failed', error: String(error?.message ?? error).slice(0, 1024) });\n }\n});\n`;\n","import { spawn } from 'node:child_process';\nimport { realpath } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nimport type {\n ComputerScriptExecutionOptions,\n ComputerScriptExecutionResult,\n ComputerScriptRunnerOptions,\n} from '../../types/computerScript';\nimport type { ComputerUseAction, ComputerUseObservation, ComputerUseSessionClient } from '../../types/computerUse';\nimport { COMPUTER_SCRIPT_WORKER_SOURCE } from '../computerScriptWorker';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_OUTPUT_BYTES = 256 * 1024;\nconst MAX_IMAGE_BYTES = 6 * 1024 * 1024;\nconst MAX_PENDING_OPERATIONS = 64;\n\nexport class ComputerScriptExecutionError extends Error {\n constructor(\n message: string,\n readonly completedActions: number,\n readonly outcomeUncertain: boolean,\n ) {\n super(message);\n this.name = 'ComputerScriptExecutionError';\n }\n}\n\ninterface WorkerMessage {\n readonly type?: unknown;\n readonly id?: unknown;\n readonly operation?: unknown;\n readonly payload?: unknown;\n readonly level?: unknown;\n readonly message?: unknown;\n readonly resultJson?: unknown;\n readonly error?: unknown;\n}\n\nexport class ComputerScriptRunner {\n private readonly client: ComputerUseSessionClient;\n private readonly allowedScriptPaths: readonly string[];\n private readonly scriptRoot?: string;\n private readonly timeoutMs: number;\n private readonly maxOutputBytes: number;\n\n constructor(options: ComputerScriptRunnerOptions) {\n this.client = options.client;\n this.allowedScriptPaths = options.allowedScriptPaths;\n this.scriptRoot = options.scriptRoot;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;\n }\n\n async execute(\n scriptPath: string,\n input: unknown,\n signal?: AbortSignal,\n options: ComputerScriptExecutionOptions = {},\n cwd?: string,\n ): Promise<ComputerScriptExecutionResult> {\n signal?.throwIfAborted();\n const resolvedPath = await realpath(path.resolve(this.scriptRoot ?? cwd ?? process.cwd(), scriptPath));\n const allowedPaths = await Promise.all(\n this.allowedScriptPaths.map(async (candidate) => realpath(candidate).catch(() => '')),\n );\n const trusted = options.trusted === true;\n if ((trusted || this.scriptRoot === undefined) && !allowedPaths.includes(resolvedPath)) {\n throw new Error('Computer script path is not explicitly allowed.');\n }\n if (!/\\.(ts|js|mjs)$/u.test(resolvedPath))\n throw new Error('Computer scripts must be JavaScript or erasable TypeScript files.');\n const root = await realpath(this.scriptRoot ?? path.dirname(resolvedPath));\n const relative = path.relative(root, resolvedPath);\n if (!trusted && (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))) {\n throw new Error('Computer script escapes the admitted script root.');\n }\n const serializedInput = JSON.stringify(input);\n if (serializedInput === undefined) throw new Error('Computer script input must be JSON serializable.');\n if (Buffer.byteLength(serializedInput) > this.maxOutputBytes)\n throw new Error('Computer script input exceeds the size limit.');\n const quickjsPath = trusted ? undefined : createRequire(import.meta.url).resolve('quickjs-emscripten');\n signal?.throwIfAborted();\n const started = performance.now();\n\n return new Promise((resolve, reject) => {\n const child = spawn(process.execPath, ['--input-type=module', '--eval', COMPUTER_SCRIPT_WORKER_SOURCE], {\n stdio: ['ignore', 'pipe', 'pipe', 'ipc'],\n // Preserve Electron's Node mode, but no host credentials, for restricted workers.\n env: trusted ? process.env : { ELECTRON_RUN_AS_NODE: '1' },\n });\n const controller = new AbortController();\n const logs: string[] = [];\n let outputBytes = 0;\n let completedActions = 0;\n let observations = 0;\n let actionInFlight = false;\n let settled = false;\n let completing = false;\n let outstanding = 0;\n let operation: Promise<void> = Promise.resolve();\n const finish = (error?: Error, value?: ComputerScriptExecutionResult): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n signal?.removeEventListener('abort', onAbort);\n controller.abort();\n child.kill('SIGTERM');\n const killTimer = setTimeout(() => child.kill('SIGKILL'), 250);\n killTimer.unref();\n if (error) reject(new ComputerScriptExecutionError(error.message, completedActions, actionInFlight));\n else resolve(value!);\n };\n const addOutput = (value: string): boolean => {\n outputBytes += Buffer.byteLength(value);\n if (outputBytes <= this.maxOutputBytes) return true;\n finish(new Error('Computer script output exceeded the size limit.'));\n return false;\n };\n const send = (value: object): void => {\n if (settled || !child.connected) return;\n child.send(value, (error) => {\n if (error && !settled) finish(error);\n });\n };\n const onAbort = (): void => finish(new Error('Computer script execution was cancelled.'));\n const timeout = setTimeout(() => finish(new Error('Computer script execution timed out.')), this.timeoutMs);\n timeout.unref();\n signal?.addEventListener('abort', onAbort, { once: true });\n if (signal?.aborted) return onAbort();\n child.stdout?.on('data', (chunk: Buffer) => addOutput(chunk.toString('utf8')));\n child.stderr?.on('data', (chunk: Buffer) => addOutput(chunk.toString('utf8')));\n child.on('error', (error) => finish(error));\n child.on('exit', (code, exitSignal) => {\n if (!settled)\n finish(new Error(`Computer script worker exited before completion (${exitSignal ?? code ?? 'unknown'}).`));\n });\n\n const observe = async (includeScreenshot: boolean): Promise<ComputerUseObservation> => {\n const value = await this.client.observe(controller.signal, { includeScreenshot });\n observations += 1;\n const { screenshot, ...semantic } = value;\n if (Buffer.byteLength(JSON.stringify(semantic)) > this.maxOutputBytes)\n throw new Error('Computer observation exceeds the size limit.');\n if (includeScreenshot && screenshot) {\n if (screenshot.mimeType !== 'image/png' || screenshot.data.length > Math.ceil(MAX_IMAGE_BYTES / 3) * 4) {\n throw new Error('Computer screenshot exceeds the image limit.');\n }\n return { ...semantic, screenshot };\n }\n return semantic;\n };\n\n child.on('message', (raw: WorkerMessage) => {\n if (settled) return;\n if (!raw || typeof raw !== 'object' || Buffer.byteLength(JSON.stringify(raw)) > this.maxOutputBytes + 4096) {\n finish(new Error('Computer worker message exceeds the size limit.'));\n return;\n }\n if (raw.type === 'log' && typeof raw.message === 'string') {\n const line = `[${String(raw.level)}] ${raw.message}`;\n if (addOutput(line)) logs.push(line);\n return;\n }\n if (raw.type === 'program') {\n if (\n completing ||\n typeof raw.id !== 'string' ||\n raw.id.length > 128 ||\n (raw.operation !== 'observe' && raw.operation !== 'act') ||\n outstanding >= MAX_PENDING_OPERATIONS\n ) {\n finish(new Error('Invalid or excessive computer program operations.'));\n return;\n }\n outstanding += 1;\n operation = operation\n .then(async () => {\n if (settled || controller.signal.aborted) return;\n try {\n let value: unknown;\n if (raw.operation === 'observe') {\n const settings = raw.payload;\n if (\n !settings ||\n typeof settings !== 'object' ||\n Array.isArray(settings) ||\n Object.keys(settings).some((key) => key !== 'includeScreenshot') ||\n ('includeScreenshot' in settings && typeof settings.includeScreenshot !== 'boolean')\n ) {\n throw new Error('Invalid observation options.');\n }\n value = await observe('includeScreenshot' in settings && settings.includeScreenshot === true);\n } else {\n actionInFlight = true;\n value = await this.client.act(raw.payload as ComputerUseAction, controller.signal);\n completedActions += 1;\n actionInFlight = false;\n }\n send({ type: 'response', id: raw.id, value });\n } catch (error) {\n // An action can have taken effect before its transport failed. Never run the remaining chain.\n if (actionInFlight) finish(error instanceof Error ? error : new Error(String(error)));\n else\n send({ type: 'response', id: raw.id, error: error instanceof Error ? error.message : String(error) });\n } finally {\n outstanding -= 1;\n }\n })\n .catch((error: unknown) => finish(error instanceof Error ? error : new Error(String(error))));\n return;\n }\n if (raw.type === 'failed' && typeof raw.error === 'string') {\n finish(new Error(raw.error));\n return;\n }\n if (raw.type === 'complete') {\n if (completing) {\n finish(new Error('Computer worker completed twice.'));\n return;\n }\n completing = true;\n operation = operation\n .then(async () => {\n if (settled) return;\n const resultJson = raw.resultJson;\n if (resultJson !== undefined && typeof resultJson !== 'string')\n throw new Error('Computer script returned an invalid result.');\n if (typeof resultJson === 'string' && !addOutput(resultJson)) return;\n const observation = await observe(options.includeScreenshot === true);\n if (settled || !addOutput(JSON.stringify({ ...observation, screenshot: undefined }))) return;\n finish(undefined, {\n ...(typeof resultJson === 'string' ? { result: JSON.parse(resultJson) as unknown } : {}),\n observation,\n logs,\n metrics: {\n actions: completedActions,\n observations,\n durationMs: Math.round(performance.now() - started),\n outputBytes,\n },\n });\n })\n .catch((error: unknown) => finish(error instanceof Error ? error : new Error(String(error))));\n }\n });\n send({\n type: 'start',\n scriptPath: resolvedPath,\n scriptRoot: root,\n input: JSON.parse(serializedInput) as unknown,\n trusted,\n quickjsPath,\n timeoutMs: this.timeoutMs,\n maxOutputBytes: this.maxOutputBytes,\n });\n });\n }\n}\n","import type { ComputerUseExtensionResult, ComputerUseExtensionService } from '../../types/extension';\nimport type { ComputerUseSessionClient } from '../sessionApiClient';\n\nexport class DefaultComputerUseExtensionService implements ComputerUseExtensionService {\n public constructor(private readonly client?: ComputerUseSessionClient) {}\n\n public async execute(): Promise<ComputerUseExtensionResult> {\n if (this.client === undefined) return { message: 'Computer use requires a Po Desktop session.', level: 'error' };\n const state = await this.client.state();\n return { message: `Computer use is ${state.phase.replaceAll('_', ' ')}.`, level: 'info' };\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { defineMcpWidget } from "@agimon-ai/po-core/web";
|
|
2
|
+
import { McpToolFields, McpToolFrame, McpToolOutput } from "@agimon-ai/po-web-components";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
//#region src/extensions/workspaces/sessions/(frontend)/tool/computer_action.mcp.tsx
|
|
5
|
+
function ComputerActionMcpWidget(props) {
|
|
6
|
+
return /* @__PURE__ */ jsxs(McpToolFrame, {
|
|
7
|
+
...props,
|
|
8
|
+
title: "Interact with application",
|
|
9
|
+
children: [/* @__PURE__ */ jsx(McpToolFields, { fields: [
|
|
10
|
+
["Action", props.args.kind],
|
|
11
|
+
["Element", props.args.elementRef],
|
|
12
|
+
["Direction", props.args.direction],
|
|
13
|
+
["Amount", props.args.amount]
|
|
14
|
+
] }), /* @__PURE__ */ jsx(McpToolOutput, { result: props.result })]
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
var computer_action_mcp_default = defineMcpWidget(ComputerActionMcpWidget);
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/extensions/workspaces/sessions/(frontend)/tool/computer_exec.mcp.tsx
|
|
20
|
+
function ComputerExecMcpWidget(props) {
|
|
21
|
+
return /* @__PURE__ */ jsxs(McpToolFrame, {
|
|
22
|
+
...props,
|
|
23
|
+
title: "Run application script",
|
|
24
|
+
children: [/* @__PURE__ */ jsx(McpToolFields, { fields: [["Script", props.args.scriptPath]] }), /* @__PURE__ */ jsx(McpToolOutput, { result: props.result })]
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
var computer_exec_mcp_default = defineMcpWidget(ComputerExecMcpWidget);
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/extensions/workspaces/sessions/(frontend)/tool/computer_state.mcp.tsx
|
|
30
|
+
function ComputerStateMcpWidget(props) {
|
|
31
|
+
return /* @__PURE__ */ jsx(McpToolFrame, {
|
|
32
|
+
...props,
|
|
33
|
+
title: "Observe application",
|
|
34
|
+
children: /* @__PURE__ */ jsx(McpToolOutput, { result: props.result })
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region generated/mcp-ui.ts
|
|
39
|
+
const widgets = {
|
|
40
|
+
"@agimon-ai/po-computer-use/computer_action": computer_action_mcp_default,
|
|
41
|
+
"@agimon-ai/po-computer-use/computer_exec": computer_exec_mcp_default,
|
|
42
|
+
"@agimon-ai/po-computer-use/computer_state": defineMcpWidget(ComputerStateMcpWidget)
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { widgets };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=mcp-ui.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-ui.mjs","names":["Widget0","Widget1","Widget2"],"sources":["../../src/extensions/workspaces/sessions/(frontend)/tool/computer_action.mcp.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/computer_exec.mcp.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/computer_state.mcp.tsx","../../generated/mcp-ui.ts"],"sourcesContent":["import { defineMcpWidget, type DoomMcpWidgetProps } from '@agimon-ai/po-core/web';\nimport { McpToolFrame, McpToolFields, McpToolOutput } from '@agimon-ai/po-web-components';\n\nfunction ComputerActionMcpWidget(props: DoomMcpWidgetProps) {\n return (\n <McpToolFrame {...props} title=\"Interact with application\">\n <McpToolFields\n fields={[\n ['Action', props.args.kind],\n ['Element', props.args.elementRef],\n ['Direction', props.args.direction],\n ['Amount', props.args.amount],\n ]}\n />\n <McpToolOutput result={props.result} />\n </McpToolFrame>\n );\n}\n\nexport default defineMcpWidget(ComputerActionMcpWidget);\n","import { defineMcpWidget, type DoomMcpWidgetProps } from '@agimon-ai/po-core/web';\nimport { McpToolFrame, McpToolFields, McpToolOutput } from '@agimon-ai/po-web-components';\n\nfunction ComputerExecMcpWidget(props: DoomMcpWidgetProps) {\n return (\n <McpToolFrame {...props} title=\"Run application script\">\n <McpToolFields fields={[['Script', props.args.scriptPath]]} />\n <McpToolOutput result={props.result} />\n </McpToolFrame>\n );\n}\n\nexport default defineMcpWidget(ComputerExecMcpWidget);\n","import { defineMcpWidget, type DoomMcpWidgetProps } from '@agimon-ai/po-core/web';\nimport { McpToolFrame, McpToolOutput } from '@agimon-ai/po-web-components';\n\nfunction ComputerStateMcpWidget(props: DoomMcpWidgetProps) {\n return (\n <McpToolFrame {...props} title=\"Observe application\">\n <McpToolOutput result={props.result} />\n </McpToolFrame>\n );\n}\n\nexport default defineMcpWidget(ComputerStateMcpWidget);\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport type { ComponentType } from 'react';\nimport type { DoomMcpWidgetProps } from '@agimon-ai/po-core/mcpWidget';\nimport Widget0 from \"../src/extensions/workspaces/sessions/(frontend)/tool/computer_action.mcp\";\nimport Widget1 from \"../src/extensions/workspaces/sessions/(frontend)/tool/computer_exec.mcp\";\nimport Widget2 from \"../src/extensions/workspaces/sessions/(frontend)/tool/computer_state.mcp\";\n\nexport const widgets: Readonly<Record<string, ComponentType<DoomMcpWidgetProps>>> = {\n \"@agimon-ai/po-computer-use/computer_action\": Widget0,\n \"@agimon-ai/po-computer-use/computer_exec\": Widget1,\n \"@agimon-ai/po-computer-use/computer_state\": Widget2,\n};\n"],"mappings":";;;;AAGA,SAAS,wBAAwB,OAA2B;CAC1D,OACE,qBAAC,cAAD;EAAc,GAAI;EAAO,OAAM;EAA/B,UAAA,CACE,oBAAC,eAAD,EACE,QAAQ;GACN,CAAC,UAAU,MAAM,KAAK,IAAI;GAC1B,CAAC,WAAW,MAAM,KAAK,UAAU;GACjC,CAAC,aAAa,MAAM,KAAK,SAAS;GAClC,CAAC,UAAU,MAAM,KAAK,MAAM;EAC9B,EACD,CAAA,GACD,oBAAC,eAAD,EAAe,QAAQ,MAAM,OAAS,CAAA,CAC1B;;AAElB;AAEA,IAAA,8BAAe,gBAAgB,uBAAuB;;;AChBtD,SAAS,sBAAsB,OAA2B;CACxD,OACE,qBAAC,cAAD;EAAc,GAAI;EAAO,OAAM;EAA/B,UAAA,CACE,oBAAC,eAAD,EAAe,QAAQ,CAAC,CAAC,UAAU,MAAM,KAAK,UAAU,CAAC,EAAI,CAAA,GAC7D,oBAAC,eAAD,EAAe,QAAQ,MAAM,OAAS,CAAA,CAC1B;;AAElB;AAEA,IAAA,4BAAe,gBAAgB,qBAAqB;;;ACTpD,SAAS,uBAAuB,OAA2B;CACzD,OACE,oBAAC,cAAD;EAAc,GAAI;EAAO,OAAM;EAC7B,UAAA,oBAAC,eAAD,EAAe,QAAQ,MAAM,OAAS,CAAA;CAC1B,CAAA;AAElB;;;ACFA,MAAa,UAAuE;CAClF,8CAA8CA;CAC9C,4CAA4CC;CAC5C,6CDCa,gBAAgB,sBCDgBC;AAC/C"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
Object.defineProperties(exports, {
|
|
2
|
+
__esModule: { value: true },
|
|
3
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
+
});
|
|
5
|
+
let _agimon_ai_po_core_mcpFacet = require("@agimon-ai/po-core/mcpFacet");
|
|
6
|
+
let _agimon_ai_po_core_extensionFile = require("@agimon-ai/po-core/extensionFile");
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/services/mcpTools/index.ts
|
|
9
|
+
const COMPUTER_USE_MCP_TOOLS_SERVICE = "doom/computer-use-mcp-tools";
|
|
10
|
+
const MODE_LABEL = "Computer Use";
|
|
11
|
+
function bindMcpTool(context, name) {
|
|
12
|
+
const catalog = context.services.get(COMPUTER_USE_MCP_TOOLS_SERVICE);
|
|
13
|
+
const tool = catalog?.get(name);
|
|
14
|
+
if (!tool || !catalog) return void 0;
|
|
15
|
+
return {
|
|
16
|
+
...tool,
|
|
17
|
+
execute(toolCallId, parameters, signal, onUpdate) {
|
|
18
|
+
if (!(context.selection.read().state?.["minor-mode"] ?? []).includes("computer-use")) {
|
|
19
|
+
const inactiveTools = [...catalog.names()].sort().join(", ");
|
|
20
|
+
throw new Error(`${MODE_LABEL} minor mode is inactive. Inactive ${MODE_LABEL} tools: ${inactiveTools}.`);
|
|
21
|
+
}
|
|
22
|
+
const executionSignal = AbortSignal.any([context.signal, signal ?? context.signal]);
|
|
23
|
+
return tool.execute(toolCallId, parameters, executionSignal, onUpdate, context.execution);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/extensions/workspaces/sessions/(backend)/tool/computer_action.mcp.ts
|
|
29
|
+
var computer_action_mcp_default = (0, _agimon_ai_po_core_extensionFile.defineRoutedContribution)((context) => bindMcpTool(context, "computer_action"), { cardinality: "optional" });
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/extensions/workspaces/sessions/(backend)/tool/computer_exec.mcp.ts
|
|
32
|
+
var computer_exec_mcp_default = (0, _agimon_ai_po_core_extensionFile.defineRoutedContribution)((context) => bindMcpTool(context, "computer_exec"), { cardinality: "optional" });
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/extensions/workspaces/sessions/(backend)/tool/computer_state.mcp.ts
|
|
35
|
+
var computer_state_mcp_default = (0, _agimon_ai_po_core_extensionFile.defineRoutedContribution)((context) => bindMcpTool(context, "computer_state"), { cardinality: "optional" });
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region generated/mcp.ts
|
|
38
|
+
const at = (value, context) => typeof value === "function" ? value(context) : value;
|
|
39
|
+
/* v8 ignore next -- generated normalization branch */
|
|
40
|
+
const defined = (values) => values.filter((value) => value !== void 0);
|
|
41
|
+
const via = (identity, value) => value === void 0 ? void 0 : {
|
|
42
|
+
...identity,
|
|
43
|
+
...value
|
|
44
|
+
};
|
|
45
|
+
const withWidget = (key, value) => value === void 0 ? value : {
|
|
46
|
+
...value,
|
|
47
|
+
_meta: {
|
|
48
|
+
...value._meta,
|
|
49
|
+
["po/widget"]: key
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const mcp = (0, _agimon_ai_po_core_mcpFacet.defineMcpPlugin)({
|
|
53
|
+
name: "@agimon-ai/po-computer-use",
|
|
54
|
+
session: (context) => ({ get tools() {
|
|
55
|
+
return defined([
|
|
56
|
+
withWidget("@agimon-ai/po-computer-use/computer_action", via({ name: "computer_action" }, at(computer_action_mcp_default, context))),
|
|
57
|
+
withWidget("@agimon-ai/po-computer-use/computer_exec", via({ name: "computer_exec" }, at(computer_exec_mcp_default, context))),
|
|
58
|
+
withWidget("@agimon-ai/po-computer-use/computer_state", via({ name: "computer_state" }, at(computer_state_mcp_default, context)))
|
|
59
|
+
]);
|
|
60
|
+
} })
|
|
61
|
+
});
|
|
62
|
+
//#endregion
|
|
63
|
+
exports.default = mcp;
|
|
64
|
+
exports.mcp = mcp;
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=mcp.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.cjs","names":["defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineMcpPlugin","toolComputerAction","toolComputerExec","toolComputerState"],"sources":["../../src/types/computerUseApi.ts","../../src/services/mcpTools/index.ts","../../src/extensions/workspaces/sessions/(backend)/tool/computer_action.mcp.ts","../../src/extensions/workspaces/sessions/(backend)/tool/computer_exec.mcp.ts","../../src/extensions/workspaces/sessions/(backend)/tool/computer_state.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import type { DoomApiCaller } from '@agimon-ai/po-core/packageApi';\n\nexport const API_BASE_PATH = 'computer-use';\nexport const computerUseChannelType = 'computer_use_state';\nexport const COMPUTER_USE_MODE_ID = 'computer-use';\nexport const COMPUTER_USE_STATUS_KEY = 'doom-computer-use';\nexport const COMPUTER_USE_MODE_STATUS_KEY = 'doom-computer-use-mode';\nexport const COMPUTER_USE_MAX_DURATION_MS = 1_800 * 1_000;\nexport const COMPUTER_USE_DEFAULT_DURATION_MS = 300 * 1_000;\nexport const COMPUTER_USE_CONFIRMATION_WINDOW_MS = 2 * 60 * 1_000;\n\n/**\n * Every path this API answers on, below its mount.\n *\n * The typed route table in `./apiRoutes` is built from this, the dispatcher\n * reads that table, and the hub channel addresses the broker with these same\n * strings, so a route cannot move on one side alone.\n */\nexport const COMPUTER_USE_ROUTES = {\n activate: '/activate',\n artifact: '/artifact',\n agentState: '/agent/state',\n agentObserve: '/agent/observe',\n agentAction: '/agent/action',\n agentStop: '/agent/stop',\n hubState: '/hub/state',\n hubActivation: '/hub/activation',\n hubAuthorization: '/hub/authorization',\n hubNext: '/hub/next',\n hubComplete: '/hub/complete',\n hubStop: '/hub/stop',\n} as const;\n\nexport const COMPUTER_USE_WAKE_LIMIT = 1_000_000;\n\nexport interface ComputerUseArtifactView {\n readonly artifactId: string;\n readonly status: 'ready' | 'failed';\n readonly sizeBytes?: number;\n readonly downloadUrl?: string;\n readonly previewUrl?: string;\n readonly actionCount?: number;\n readonly completedAt?: string;\n readonly failure?: { readonly code: string; readonly message: string };\n}\n\nexport interface ComputerUseSessionView {\n readonly sessionId: string;\n readonly revision: number;\n readonly wake: number;\n readonly phase: 'inactive' | 'awaiting_confirmation' | 'activating' | 'active' | 'stopping' | 'failed';\n readonly requestId?: string;\n readonly target?: Record<string, unknown>;\n readonly durationMs?: number;\n readonly expiresAt?: number;\n readonly failure?: { readonly code: string; readonly message: string };\n readonly artifact?: ComputerUseArtifactView;\n}\n\nexport interface ComputerUseActivationRequest {\n readonly requestId: string;\n readonly target?: Record<string, unknown>;\n readonly durationSeconds: number;\n readonly createdAt: number;\n readonly confirmationExpiresAt: number;\n readonly caller: DoomApiCaller;\n}\n\nexport interface ComputerUseBrokerRequest {\n readonly id: string;\n readonly operation: 'observe' | 'act';\n readonly payload?: unknown;\n readonly grantId: string;\n readonly sequence?: number;\n}\n\nexport interface ComputerUseChannelPayload {\n readonly state: ComputerUseSessionView;\n readonly targets: readonly Record<string, unknown>[];\n readonly busy?: true;\n}\n\nexport type ComputerUseBrowserCommand = { readonly action: 'status' | 'targets' | 'stop' | 'artifacts' };\n","import type { DoomHeadlessTool } from '@agimon-ai/po-core/headless';\nimport type { DoomMcpPluginContext } from '@agimon-ai/po-core/mcpFacet';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { COMPUTER_USE_MODE_ID } from '../../types/computerUseApi';\n\nexport const COMPUTER_USE_MCP_TOOLS_SERVICE = 'doom/computer-use-mcp-tools';\n\nconst MODE_LABEL = 'Computer Use';\n\nexport interface McpToolCatalog {\n get(name: string): DoomHeadlessTool | undefined;\n names(): readonly string[];\n}\n\nexport function mountMcpTools(tools: readonly DoomHeadlessTool[]) {\n return (context: Context): void => {\n context.plugin((providerContext) => {\n providerContext.provide(COMPUTER_USE_MCP_TOOLS_SERVICE, {\n get: (name) => tools.find((tool) => tool.name === name),\n names: () => tools.map((tool) => tool.name),\n } satisfies McpToolCatalog);\n });\n };\n}\n\nexport function bindMcpTool(context: DoomMcpPluginContext, name: string): DoomHeadlessTool | undefined {\n const catalog = context.services.get<McpToolCatalog>(COMPUTER_USE_MCP_TOOLS_SERVICE);\n const tool = catalog?.get(name);\n if (!tool || !catalog) return undefined;\n return {\n ...tool,\n execute(toolCallId, parameters, signal, onUpdate) {\n const activeModes = context.selection.read().state?.['minor-mode'] ?? [];\n if (!activeModes.includes(COMPUTER_USE_MODE_ID)) {\n const inactiveTools = [...catalog.names()].sort().join(', ');\n throw new Error(`${MODE_LABEL} minor mode is inactive. Inactive ${MODE_LABEL} tools: ${inactiveTools}.`);\n }\n const executionSignal = AbortSignal.any([context.signal, signal ?? context.signal]);\n return tool.execute(toolCallId, parameters, executionSignal, onUpdate, context.execution);\n },\n };\n}\n","import { defineRoutedContribution } from '@agimon-ai/po-core/extensionFile';\nimport type { DoomMcpPluginContext } from '@agimon-ai/po-core/mcpFacet';\n\nimport { bindMcpTool } from '../../../../../services/mcpTools';\n\nexport default defineRoutedContribution((context: DoomMcpPluginContext) => bindMcpTool(context, 'computer_action'), {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution } from '@agimon-ai/po-core/extensionFile';\nimport type { DoomMcpPluginContext } from '@agimon-ai/po-core/mcpFacet';\n\nimport { bindMcpTool } from '../../../../../services/mcpTools';\n\nexport default defineRoutedContribution((context: DoomMcpPluginContext) => bindMcpTool(context, 'computer_exec'), {\n cardinality: 'optional',\n});\n","import { defineRoutedContribution } from '@agimon-ai/po-core/extensionFile';\nimport type { DoomMcpPluginContext } from '@agimon-ai/po-core/mcpFacet';\n\nimport { bindMcpTool } from '../../../../../services/mcpTools';\n\nexport default defineRoutedContribution((context: DoomMcpPluginContext) => bindMcpTool(context, 'computer_state'), {\n cardinality: 'optional',\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineMcpPlugin, type DoomMcpSessionPlugin } from '@agimon-ai/po-core/mcpFacet';\n\nimport toolComputerAction from '../src/extensions/workspaces/sessions/(backend)/tool/computer_action.mcp';\nimport toolComputerExec from '../src/extensions/workspaces/sessions/(backend)/tool/computer_exec.mcp';\nimport toolComputerState from '../src/extensions/workspaces/sessions/(backend)/tool/computer_state.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nconst withWidget = <T>(key: string, value: T): T => value === undefined ? value : ({\n ...value, _meta: { ...(value as { _meta?: object })._meta, [\"po/widget\"]: key },\n});\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/po-computer-use',\n session: (context) => ({\n get tools(): DoomMcpSessionPlugin['tools'] { return defined([withWidget(\"@agimon-ai/po-computer-use/computer_action\", via({ name: 'computer_action' }, at(toolComputerAction, context))), withWidget(\"@agimon-ai/po-computer-use/computer_exec\", via({ name: 'computer_exec' }, at(toolComputerExec, context))), withWidget(\"@agimon-ai/po-computer-use/computer_state\", via({ name: 'computer_state' }, at(toolComputerState, context)))]); },\n }) satisfies DoomMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":";;;;;;;;ACMA,MAAa,iCAAiC;AAE9C,MAAM,aAAa;AAkBnB,SAAgB,YAAY,SAA+B,MAA4C;CACrG,MAAM,UAAU,QAAQ,SAAS,IAAoB,8BAA8B;CACnF,MAAM,OAAO,SAAS,IAAI,IAAI;CAC9B,IAAI,CAAC,QAAQ,CAAC,SAAS,OAAO,KAAA;CAC9B,OAAO;EACL,GAAG;EACH,QAAQ,YAAY,YAAY,QAAQ,UAAU;GAEhD,IAAI,EADgB,QAAQ,UAAU,KAAK,CAAC,CAAC,QAAQ,iBAAiB,CAAC,EAAA,CACtD,SAAA,cAA6B,GAAG;IAC/C,MAAM,gBAAgB,CAAC,GAAG,QAAQ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI;IAC3D,MAAM,IAAI,MAAM,GAAG,WAAW,oCAAoC,WAAW,UAAU,cAAc,EAAE;GACzG;GACA,MAAM,kBAAkB,YAAY,IAAI,CAAC,QAAQ,QAAQ,UAAU,QAAQ,MAAM,CAAC;GAClF,OAAO,KAAK,QAAQ,YAAY,YAAY,iBAAiB,UAAU,QAAQ,SAAS;EAC1F;CACF;AACF;;;ACrCA,IAAA,+BAAA,GAAeA,iCAAAA,yBAAAA,EAA0B,YAAkC,YAAY,SAAS,iBAAiB,GAAG,EAClH,aAAa,WACf,CAAC;;;ACFD,IAAA,6BAAA,GAAeC,iCAAAA,yBAAAA,EAA0B,YAAkC,YAAY,SAAS,eAAe,GAAG,EAChH,aAAa,WACf,CAAC;;;ACFD,IAAA,8BAAA,GAAeC,iCAAAA,yBAAAA,EAA0B,YAAkC,YAAY,SAAS,gBAAgB,GAAG,EACjH,aAAa,WACf,CAAC;;;ACCD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;;AAEpE,MAAM,WAAc,WAClB,OAAO,QAAQ,UAAsB,UAAU,KAAA,CAAS;AAC1D,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAM,cAAiB,KAAa,UAAgB,UAAU,KAAA,IAAY,QAAS;CACjF,GAAG;CAAO,OAAO;EAAE,GAAI,MAA6B;GAAQ,cAAc;CAAI;AAChF;AAEA,MAAa,OAAA,GAAMC,4BAAAA,gBAAAA,CAAgB;CACjC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,QAAuC;EAAE,OAAO,QAAQ;GAAC,WAAW,8CAA8C,IAAI,EAAE,MAAM,kBAAkB,GAAG,GAAGC,6BAAoB,OAAO,CAAC,CAAC;GAAG,WAAW,4CAA4C,IAAI,EAAE,MAAM,gBAAgB,GAAG,GAAGC,2BAAkB,OAAO,CAAC,CAAC;GAAG,WAAW,6CAA6C,IAAI,EAAE,MAAM,iBAAiB,GAAG,GAAGC,4BAAmB,OAAO,CAAC,CAAC;EAAC,CAAC;CAAG,EAC/a;AACF,CAAC"}
|