@aexol/spectral 0.8.7 → 0.8.9
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/dist/auth-helper.d.ts +49 -0
- package/dist/auth-helper.d.ts.map +1 -0
- package/dist/auth-helper.js +191 -0
- package/dist/commands/login-oauth.d.ts +2 -9
- package/dist/commands/login-oauth.d.ts.map +1 -1
- package/dist/commands/login-oauth.js +10 -105
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +68 -1
- package/dist/designer/systems.d.ts.map +1 -1
- package/dist/designer/systems.js +5 -0
- package/dist/extensions/aexol-mcp.d.ts.map +1 -1
- package/dist/extensions/aexol-mcp.js +33 -2
- package/dist/extensions/browser/browser-service.d.ts +104 -0
- package/dist/extensions/browser/browser-service.d.ts.map +1 -0
- package/dist/extensions/browser/browser-service.js +333 -0
- package/dist/extensions/browser/config.d.ts +24 -0
- package/dist/extensions/browser/config.d.ts.map +1 -0
- package/dist/extensions/browser/config.js +17 -0
- package/dist/extensions/browser/index.d.ts +35 -0
- package/dist/extensions/browser/index.d.ts.map +1 -0
- package/dist/extensions/browser/index.js +126 -0
- package/dist/extensions/browser/stream/signaling-client.d.ts +28 -0
- package/dist/extensions/browser/stream/signaling-client.d.ts.map +1 -0
- package/dist/extensions/browser/stream/signaling-client.js +69 -0
- package/dist/extensions/browser/stream/stream-injector.d.ts +30 -0
- package/dist/extensions/browser/stream/stream-injector.d.ts.map +1 -0
- package/dist/extensions/browser/stream/stream-injector.js +161 -0
- package/dist/extensions/browser/stream/stream-tool.d.ts +10 -0
- package/dist/extensions/browser/stream/stream-tool.d.ts.map +1 -0
- package/dist/extensions/browser/stream/stream-tool.js +182 -0
- package/dist/extensions/browser/tools/console.d.ts +7 -0
- package/dist/extensions/browser/tools/console.d.ts.map +1 -0
- package/dist/extensions/browser/tools/console.js +54 -0
- package/dist/extensions/browser/tools/core.d.ts +7 -0
- package/dist/extensions/browser/tools/core.d.ts.map +1 -0
- package/dist/extensions/browser/tools/core.js +115 -0
- package/dist/extensions/browser/tools/dialog.d.ts +11 -0
- package/dist/extensions/browser/tools/dialog.d.ts.map +1 -0
- package/dist/extensions/browser/tools/dialog.js +54 -0
- package/dist/extensions/browser/tools/drop.d.ts +7 -0
- package/dist/extensions/browser/tools/drop.d.ts.map +1 -0
- package/dist/extensions/browser/tools/drop.js +93 -0
- package/dist/extensions/browser/tools/evaluate.d.ts +7 -0
- package/dist/extensions/browser/tools/evaluate.d.ts.map +1 -0
- package/dist/extensions/browser/tools/evaluate.js +105 -0
- package/dist/extensions/browser/tools/input.d.ts +7 -0
- package/dist/extensions/browser/tools/input.d.ts.map +1 -0
- package/dist/extensions/browser/tools/input.js +290 -0
- package/dist/extensions/browser/tools/network.d.ts +7 -0
- package/dist/extensions/browser/tools/network.d.ts.map +1 -0
- package/dist/extensions/browser/tools/network.js +116 -0
- package/dist/extensions/browser/tools/screenshot.d.ts +7 -0
- package/dist/extensions/browser/tools/screenshot.d.ts.map +1 -0
- package/dist/extensions/browser/tools/screenshot.js +153 -0
- package/dist/extensions/browser/tools/tabs.d.ts +7 -0
- package/dist/extensions/browser/tools/tabs.d.ts.map +1 -0
- package/dist/extensions/browser/tools/tabs.js +72 -0
- package/dist/extensions/browser/tools/wait.d.ts +7 -0
- package/dist/extensions/browser/tools/wait.d.ts.map +1 -0
- package/dist/extensions/browser/tools/wait.js +64 -0
- package/dist/extensions/kanban-bridge.d.ts.map +1 -1
- package/dist/extensions/kanban-bridge.js +70 -3
- package/dist/mcp/ui-server.d.ts.map +1 -1
- package/dist/mcp/ui-server.js +23 -10
- package/dist/sdk/coding-agent/core/extensions/native-extensions.d.ts +60 -0
- package/dist/sdk/coding-agent/core/extensions/native-extensions.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/extensions/native-extensions.js +108 -0
- package/dist/sdk/coding-agent/core/resource-loader.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/resource-loader.js +23 -1
- package/dist/sdk/coding-agent/core/settings-manager.d.ts +5 -0
- package/dist/sdk/coding-agent/core/settings-manager.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/settings-manager.js +12 -0
- package/dist/server/sqlite-adapter.d.ts +41 -0
- package/dist/server/sqlite-adapter.d.ts.map +1 -0
- package/dist/server/sqlite-adapter.js +128 -0
- package/dist/server/storage.d.ts.map +1 -1
- package/dist/server/storage.js +2 -2
- package/package.json +5 -2
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dialog tool: browser_handle_dialog.
|
|
3
|
+
*
|
|
4
|
+
* NOTE: BrowserService intercepts all dialogs globally and holds them
|
|
5
|
+
* until the agent handles them via this tool. This avoids Playwright's
|
|
6
|
+
* default auto-dismiss behavior.
|
|
7
|
+
*/
|
|
8
|
+
export function registerDialogTools(ext, bs) {
|
|
9
|
+
const dialogTool = {
|
|
10
|
+
name: "browser_handle_dialog",
|
|
11
|
+
label: "Browser Handle Dialog",
|
|
12
|
+
description: "Handle a JavaScript dialog (alert, confirm, prompt) that appeared on the page. " +
|
|
13
|
+
"Call this AFTER performing an action that triggers a dialog.",
|
|
14
|
+
promptSnippet: "`browser_handle_dialog { accept, promptText }` — accept or dismiss a browser dialog",
|
|
15
|
+
parameters: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
accept: {
|
|
19
|
+
type: "boolean",
|
|
20
|
+
description: "Whether to accept (true) or dismiss (false) the dialog.",
|
|
21
|
+
},
|
|
22
|
+
promptText: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "Text to enter for prompt dialogs (only when accept is true).",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
required: ["accept"],
|
|
28
|
+
},
|
|
29
|
+
async execute(_toolCallId, params) {
|
|
30
|
+
const p = params;
|
|
31
|
+
try {
|
|
32
|
+
const message = await bs.handleDialog(p.accept, p.promptText);
|
|
33
|
+
const action = p.accept
|
|
34
|
+
? (p.promptText ? `accepted with "${p.promptText}"` : "accepted")
|
|
35
|
+
: "dismissed";
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: "text", text: `✓ Dialog ${action}: "${message}"` }],
|
|
38
|
+
details: {},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
43
|
+
return { content: [{ type: "text", text: `Dialog handling failed: ${msg}` }], details: { isError: true } };
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
try {
|
|
48
|
+
ext.registerTool(dialogTool);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
52
|
+
process.stderr.write(`[browser] Failed to register browser_handle_dialog: ${msg}\n`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drop tool: browser_drop.
|
|
3
|
+
*/
|
|
4
|
+
import type { ExtensionAPI } from "../../../sdk/coding-agent/index.js";
|
|
5
|
+
import { BrowserService } from "../browser-service.js";
|
|
6
|
+
export declare function registerDropTools(ext: ExtensionAPI, bs: BrowserService): void;
|
|
7
|
+
//# sourceMappingURL=drop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drop.d.ts","sourceRoot":"","sources":["../../../../src/extensions/browser/tools/drop.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,oCAAoC,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,cAAc,GAAG,IAAI,CAuG7E"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drop tool: browser_drop.
|
|
3
|
+
*/
|
|
4
|
+
export function registerDropTools(ext, bs) {
|
|
5
|
+
const dropTool = {
|
|
6
|
+
name: "browser_drop",
|
|
7
|
+
label: "Browser Drop",
|
|
8
|
+
description: "Drop files or MIME-typed data onto an element, as if dragged from outside the page. " +
|
|
9
|
+
"At least one of 'paths' or 'data' must be provided.",
|
|
10
|
+
promptSnippet: "`browser_drop { element, paths, data }` — drop files or data onto an element",
|
|
11
|
+
parameters: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
element: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: "CSS selector of the drop target element.",
|
|
17
|
+
},
|
|
18
|
+
paths: {
|
|
19
|
+
type: "array",
|
|
20
|
+
items: { type: "string" },
|
|
21
|
+
description: "File paths to drop onto the element.",
|
|
22
|
+
},
|
|
23
|
+
data: {
|
|
24
|
+
type: "array",
|
|
25
|
+
items: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
mimeType: { type: "string", description: "MIME type of the data (e.g. 'text/plain')." },
|
|
29
|
+
content: { type: "string", description: "The data content." },
|
|
30
|
+
},
|
|
31
|
+
required: ["mimeType", "content"],
|
|
32
|
+
},
|
|
33
|
+
description: "MIME-typed data items to drop.",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
required: ["element"],
|
|
37
|
+
},
|
|
38
|
+
async execute(_toolCallId, params) {
|
|
39
|
+
const p = params;
|
|
40
|
+
try {
|
|
41
|
+
const page = bs.getActivePage();
|
|
42
|
+
if (!p.paths && !p.data) {
|
|
43
|
+
return {
|
|
44
|
+
content: [{ type: "text", text: "Error: At least one of 'paths' or 'data' must be provided." }],
|
|
45
|
+
details: { isError: true },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Dispatch the drag-and-drop via dataTransfer
|
|
49
|
+
await page.evaluate(({ element, paths, data }) => {
|
|
50
|
+
const target = document.querySelector(element);
|
|
51
|
+
if (!target)
|
|
52
|
+
throw new Error(`Element not found: ${element}`);
|
|
53
|
+
const dt = new DataTransfer();
|
|
54
|
+
if (paths) {
|
|
55
|
+
// Note: DataTransfer files from paths won't actually contain file data
|
|
56
|
+
// in most browser contexts — use data for inline content instead
|
|
57
|
+
for (const path of paths) {
|
|
58
|
+
dt.items.add(path, "application/octet-stream");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (data) {
|
|
62
|
+
for (const item of data) {
|
|
63
|
+
dt.setData(item.mimeType, item.content);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
target.dispatchEvent(new DragEvent("drop", { dataTransfer: dt, bubbles: true }));
|
|
67
|
+
}, { element: p.element, paths: p.paths, data: p.data });
|
|
68
|
+
const droppedItems = [
|
|
69
|
+
...(p.paths ?? []).map((path) => `file: ${path}`),
|
|
70
|
+
...(p.data ?? []).map((d) => `${d.mimeType}: ${d.content.slice(0, 50)}`),
|
|
71
|
+
];
|
|
72
|
+
return {
|
|
73
|
+
content: [{
|
|
74
|
+
type: "text",
|
|
75
|
+
text: `✓ Dropped onto ${p.element}:\n${droppedItems.map((i) => ` - ${i}`).join("\n")}`,
|
|
76
|
+
}],
|
|
77
|
+
details: {},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
82
|
+
return { content: [{ type: "text", text: `Drop failed: ${msg}` }], details: { isError: true } };
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
try {
|
|
87
|
+
ext.registerTool(dropTool);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
91
|
+
process.stderr.write(`[browser] Failed to register browser_drop: ${msg}\n`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evaluate tools: browser_evaluate, browser_run_code_unsafe.
|
|
3
|
+
*/
|
|
4
|
+
import type { ExtensionAPI } from "../../../sdk/coding-agent/index.js";
|
|
5
|
+
import { BrowserService } from "../browser-service.js";
|
|
6
|
+
export declare function registerEvaluateTools(ext: ExtensionAPI, bs: BrowserService): void;
|
|
7
|
+
//# sourceMappingURL=evaluate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../../../src/extensions/browser/tools/evaluate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,oCAAoC,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,cAAc,GAAG,IAAI,CA0GjF"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evaluate tools: browser_evaluate, browser_run_code_unsafe.
|
|
3
|
+
*/
|
|
4
|
+
export function registerEvaluateTools(ext, bs) {
|
|
5
|
+
const evaluateTool = {
|
|
6
|
+
name: "browser_evaluate",
|
|
7
|
+
label: "Browser Evaluate",
|
|
8
|
+
description: "Evaluate a JavaScript expression on the page or on a specific element. " +
|
|
9
|
+
"Returns the result as JSON. Use this to read page state or interact with the DOM.",
|
|
10
|
+
promptSnippet: "`browser_evaluate { expression }` — run JS and get the result",
|
|
11
|
+
parameters: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
expression: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: "JavaScript expression to evaluate. Use 'return' for complex logic. " +
|
|
17
|
+
"Example: 'document.title' or 'Array.from(document.querySelectorAll(\"a\")).map(a => a.href)'",
|
|
18
|
+
},
|
|
19
|
+
ref: {
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "Snapshot reference to evaluate on. If provided, expression runs on the element identified by this ref.",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
required: ["expression"],
|
|
25
|
+
},
|
|
26
|
+
async execute(_toolCallId, params) {
|
|
27
|
+
const { expression } = params;
|
|
28
|
+
try {
|
|
29
|
+
const page = bs.getActivePage();
|
|
30
|
+
const result = await page.evaluate(expression);
|
|
31
|
+
if (result === undefined) {
|
|
32
|
+
return { content: [{ type: "text", text: "undefined" }], details: {} };
|
|
33
|
+
}
|
|
34
|
+
const text = typeof result === "string"
|
|
35
|
+
? result
|
|
36
|
+
: JSON.stringify(result, null, 2);
|
|
37
|
+
return {
|
|
38
|
+
content: [{
|
|
39
|
+
type: "text",
|
|
40
|
+
text: text.length > 50000 ? text.slice(0, 50000) + "\n\n[truncated]" : text,
|
|
41
|
+
}],
|
|
42
|
+
details: {},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
47
|
+
return { content: [{ type: "text", text: `Evaluate failed: ${msg}` }], details: { isError: true } };
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
const runCodeTool = {
|
|
52
|
+
name: "browser_run_code_unsafe",
|
|
53
|
+
label: "Browser Run Code (Unsafe)",
|
|
54
|
+
description: "Run a Playwright code snippet in the Node.js server process. " +
|
|
55
|
+
"WARNING: This executes arbitrary JavaScript and is RCE-equivalent. " +
|
|
56
|
+
"Use only when browser_evaluate is insufficient.",
|
|
57
|
+
promptSnippet: "`browser_run_code_unsafe { code }` — run arbitrary Node.js+Playwright code",
|
|
58
|
+
parameters: {
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
code: {
|
|
62
|
+
type: "string",
|
|
63
|
+
description: "A JavaScript function body that receives (page) as argument. " +
|
|
64
|
+
"Example: 'await page.goto(\"https://example.com\"); return await page.title();'",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
required: ["code"],
|
|
68
|
+
},
|
|
69
|
+
async execute(_toolCallId, params) {
|
|
70
|
+
const { code } = params;
|
|
71
|
+
try {
|
|
72
|
+
const page = bs.getActivePage();
|
|
73
|
+
// Create an async function from the code string with page in scope
|
|
74
|
+
const fn = new Function("page", `return (async () => { ${code} })()`);
|
|
75
|
+
const result = await fn(page);
|
|
76
|
+
if (result === undefined) {
|
|
77
|
+
return { content: [{ type: "text", text: "undefined" }], details: {} };
|
|
78
|
+
}
|
|
79
|
+
const text = typeof result === "string"
|
|
80
|
+
? result
|
|
81
|
+
: JSON.stringify(result, null, 2);
|
|
82
|
+
return {
|
|
83
|
+
content: [{
|
|
84
|
+
type: "text",
|
|
85
|
+
text: text.length > 50000 ? text.slice(0, 50000) + "\n\n[truncated]" : text,
|
|
86
|
+
}],
|
|
87
|
+
details: {},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
92
|
+
return { content: [{ type: "text", text: `Run code failed: ${msg}` }], details: { isError: true } };
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
for (const tool of [evaluateTool, runCodeTool]) {
|
|
97
|
+
try {
|
|
98
|
+
ext.registerTool(tool);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
102
|
+
process.stderr.write(`[browser] Failed to register ${tool.name}: ${msg}\n`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input tools: click, type, press_key, hover, drag, select_option, fill_form, file_upload.
|
|
3
|
+
*/
|
|
4
|
+
import type { ExtensionAPI } from "../../../sdk/coding-agent/index.js";
|
|
5
|
+
import { BrowserService } from "../browser-service.js";
|
|
6
|
+
export declare function registerInputTools(ext: ExtensionAPI, bs: BrowserService): void;
|
|
7
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../../src/extensions/browser/tools/input.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,oCAAoC,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,cAAc,GAAG,IAAI,CA8R9E"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input tools: click, type, press_key, hover, drag, select_option, fill_form, file_upload.
|
|
3
|
+
*/
|
|
4
|
+
export function registerInputTools(ext, bs) {
|
|
5
|
+
// ── browser_click ─────────────────────────────────────────────────
|
|
6
|
+
const clickTool = {
|
|
7
|
+
name: "browser_click",
|
|
8
|
+
label: "Browser Click",
|
|
9
|
+
description: "Click on an element identified by CSS selector or text match.",
|
|
10
|
+
promptSnippet: "`browser_click { element }` — click an element",
|
|
11
|
+
parameters: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
element: { type: "string", description: "CSS selector or text to click." },
|
|
15
|
+
ref: { type: "string", description: "Snapshot reference (from browser_snapshot), ignored for CSS selectors." },
|
|
16
|
+
button: { type: "string", enum: ["left", "right", "middle"], description: "Mouse button. Default: left." },
|
|
17
|
+
modifiers: {
|
|
18
|
+
type: "array",
|
|
19
|
+
items: { type: "string" },
|
|
20
|
+
description: "Modifier keys: Alt, Control, Meta, Shift.",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
required: ["element"],
|
|
24
|
+
},
|
|
25
|
+
async execute(_toolCallId, params) {
|
|
26
|
+
const p = params;
|
|
27
|
+
try {
|
|
28
|
+
const page = bs.getActivePage();
|
|
29
|
+
await page.click(p.element, {
|
|
30
|
+
button: p.button ?? "left",
|
|
31
|
+
modifiers: p.modifiers,
|
|
32
|
+
timeout: 5000,
|
|
33
|
+
});
|
|
34
|
+
return { content: [{ type: "text", text: `✓ Clicked: ${p.element}` }], details: {} };
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
38
|
+
return { content: [{ type: "text", text: `Click failed: ${msg}` }], details: { isError: true } };
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
// ── browser_type ──────────────────────────────────────────────────
|
|
43
|
+
const typeTool = {
|
|
44
|
+
name: "browser_type",
|
|
45
|
+
label: "Browser Type",
|
|
46
|
+
description: "Type text into an editable element.",
|
|
47
|
+
promptSnippet: "`browser_type { element, text }` — type text into an element",
|
|
48
|
+
parameters: {
|
|
49
|
+
type: "object",
|
|
50
|
+
properties: {
|
|
51
|
+
element: { type: "string", description: "CSS selector of the input element." },
|
|
52
|
+
text: { type: "string", description: "Text to type." },
|
|
53
|
+
ref: { type: "string", description: "Snapshot reference (from browser_snapshot)." },
|
|
54
|
+
slowly: { type: "boolean", description: "Type one character at a time (human-like). Default: false." },
|
|
55
|
+
},
|
|
56
|
+
required: ["element", "text"],
|
|
57
|
+
},
|
|
58
|
+
async execute(_toolCallId, params) {
|
|
59
|
+
const p = params;
|
|
60
|
+
try {
|
|
61
|
+
const page = bs.getActivePage();
|
|
62
|
+
await page.click(p.element);
|
|
63
|
+
await page.fill(p.element, "", { timeout: 5000 });
|
|
64
|
+
await page.type(p.element, p.text, { delay: p.slowly ? 50 : 0 });
|
|
65
|
+
return { content: [{ type: "text", text: `✓ Typed into ${p.element}: "${p.text.slice(0, 100)}"` }], details: {} };
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
69
|
+
return { content: [{ type: "text", text: `Type failed: ${msg}` }], details: { isError: true } };
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
// ── browser_press_key ─────────────────────────────────────────────
|
|
74
|
+
const pressKeyTool = {
|
|
75
|
+
name: "browser_press_key",
|
|
76
|
+
label: "Browser Press Key",
|
|
77
|
+
description: "Press a keyboard key. Use single keys like 'Enter', 'Escape', 'Tab', 'ArrowDown', etc.",
|
|
78
|
+
promptSnippet: "`browser_press_key { key }` — press a keyboard key",
|
|
79
|
+
parameters: {
|
|
80
|
+
type: "object",
|
|
81
|
+
properties: {
|
|
82
|
+
key: { type: "string", description: "Key to press, e.g. Enter, Escape, Tab, ArrowDown, Backspace." },
|
|
83
|
+
},
|
|
84
|
+
required: ["key"],
|
|
85
|
+
},
|
|
86
|
+
async execute(_toolCallId, params) {
|
|
87
|
+
const { key } = params;
|
|
88
|
+
try {
|
|
89
|
+
const page = bs.getActivePage();
|
|
90
|
+
await page.keyboard.press(key);
|
|
91
|
+
return { content: [{ type: "text", text: `✓ Pressed key: ${key}` }], details: {} };
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
95
|
+
return { content: [{ type: "text", text: `Press key failed: ${msg}` }], details: { isError: true } };
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
// ── browser_hover ─────────────────────────────────────────────────
|
|
100
|
+
const hoverTool = {
|
|
101
|
+
name: "browser_hover",
|
|
102
|
+
label: "Browser Hover",
|
|
103
|
+
description: "Hover the mouse over an element.",
|
|
104
|
+
promptSnippet: "`browser_hover { element }` — hover over an element",
|
|
105
|
+
parameters: {
|
|
106
|
+
type: "object",
|
|
107
|
+
properties: {
|
|
108
|
+
element: { type: "string", description: "CSS selector of the element to hover." },
|
|
109
|
+
ref: { type: "string", description: "Snapshot reference (from browser_snapshot)." },
|
|
110
|
+
},
|
|
111
|
+
required: ["element"],
|
|
112
|
+
},
|
|
113
|
+
async execute(_toolCallId, params) {
|
|
114
|
+
const { element } = params;
|
|
115
|
+
try {
|
|
116
|
+
const page = bs.getActivePage();
|
|
117
|
+
await page.hover(element, { timeout: 5000 });
|
|
118
|
+
return { content: [{ type: "text", text: `✓ Hovered: ${element}` }], details: {} };
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
122
|
+
return { content: [{ type: "text", text: `Hover failed: ${msg}` }], details: { isError: true } };
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
// ── browser_drag ──────────────────────────────────────────────────
|
|
127
|
+
const dragTool = {
|
|
128
|
+
name: "browser_drag",
|
|
129
|
+
label: "Browser Drag",
|
|
130
|
+
description: "Drag an element from one location to another.",
|
|
131
|
+
promptSnippet: "`browser_drag { startElement, endElement }` — drag and drop",
|
|
132
|
+
parameters: {
|
|
133
|
+
type: "object",
|
|
134
|
+
properties: {
|
|
135
|
+
startElement: { type: "string", description: "CSS selector of the element to drag." },
|
|
136
|
+
endElement: { type: "string", description: "CSS selector of the drop target." },
|
|
137
|
+
},
|
|
138
|
+
required: ["startElement", "endElement"],
|
|
139
|
+
},
|
|
140
|
+
async execute(_toolCallId, params) {
|
|
141
|
+
const { startElement, endElement } = params;
|
|
142
|
+
try {
|
|
143
|
+
const page = bs.getActivePage();
|
|
144
|
+
await page.dragAndDrop(startElement, endElement, { timeout: 5000 });
|
|
145
|
+
return { content: [{ type: "text", text: `✓ Dragged ${startElement} → ${endElement}` }], details: {} };
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
149
|
+
return { content: [{ type: "text", text: `Drag failed: ${msg}` }], details: { isError: true } };
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
// ── browser_select_option ─────────────────────────────────────────
|
|
154
|
+
const selectTool = {
|
|
155
|
+
name: "browser_select_option",
|
|
156
|
+
label: "Browser Select Option",
|
|
157
|
+
description: "Select option(s) in a <select> dropdown element.",
|
|
158
|
+
promptSnippet: "`browser_select_option { element, values }` — select dropdown options",
|
|
159
|
+
parameters: {
|
|
160
|
+
type: "object",
|
|
161
|
+
properties: {
|
|
162
|
+
element: { type: "string", description: "CSS selector of the <select> element." },
|
|
163
|
+
values: {
|
|
164
|
+
type: "array",
|
|
165
|
+
items: { type: "string" },
|
|
166
|
+
description: "Option values or labels to select.",
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
required: ["element", "values"],
|
|
170
|
+
},
|
|
171
|
+
async execute(_toolCallId, params) {
|
|
172
|
+
const { element, values } = params;
|
|
173
|
+
try {
|
|
174
|
+
const page = bs.getActivePage();
|
|
175
|
+
await page.selectOption(element, values, { timeout: 5000 });
|
|
176
|
+
return { content: [{ type: "text", text: `✓ Selected [${values.join(", ")}] in ${element}` }], details: {} };
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
180
|
+
return { content: [{ type: "text", text: `Select option failed: ${msg}` }], details: { isError: true } };
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
// ── browser_fill_form ─────────────────────────────────────────────
|
|
185
|
+
const fillFormTool = {
|
|
186
|
+
name: "browser_fill_form",
|
|
187
|
+
label: "Browser Fill Form",
|
|
188
|
+
description: "Fill multiple form fields at once.",
|
|
189
|
+
promptSnippet: "`browser_fill_form { fields }` — fill multiple form fields",
|
|
190
|
+
parameters: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: {
|
|
193
|
+
fields: {
|
|
194
|
+
type: "array",
|
|
195
|
+
items: {
|
|
196
|
+
type: "object",
|
|
197
|
+
properties: {
|
|
198
|
+
name: { type: "string", description: "CSS selector, name, or label of the form field." },
|
|
199
|
+
type: { type: "string", enum: ["text", "select", "checkbox", "radio"], description: "Input type." },
|
|
200
|
+
value: { type: "string", description: "Value to fill. For checkbox/radio use 'true' or 'false'." },
|
|
201
|
+
},
|
|
202
|
+
required: ["name", "type", "value"],
|
|
203
|
+
},
|
|
204
|
+
description: "Array of form fields to fill.",
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
required: ["fields"],
|
|
208
|
+
},
|
|
209
|
+
async execute(_toolCallId, params) {
|
|
210
|
+
const { fields } = params;
|
|
211
|
+
try {
|
|
212
|
+
const page = bs.getActivePage();
|
|
213
|
+
const results = [];
|
|
214
|
+
for (const f of fields) {
|
|
215
|
+
switch (f.type) {
|
|
216
|
+
case "select":
|
|
217
|
+
await page.selectOption(f.name, f.value, { timeout: 5000 });
|
|
218
|
+
results.push(`✓ [select] ${f.name} = ${f.value}`);
|
|
219
|
+
break;
|
|
220
|
+
case "checkbox":
|
|
221
|
+
case "radio":
|
|
222
|
+
if (f.value === "true") {
|
|
223
|
+
await page.check(f.name, { timeout: 5000 });
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
await page.uncheck(f.name, { timeout: 5000 });
|
|
227
|
+
}
|
|
228
|
+
results.push(`✓ [${f.type}] ${f.name} = ${f.value}`);
|
|
229
|
+
break;
|
|
230
|
+
default:
|
|
231
|
+
await page.click(f.name, { timeout: 5000 });
|
|
232
|
+
await page.fill(f.name, "", { timeout: 5000 });
|
|
233
|
+
await page.type(f.name, f.value);
|
|
234
|
+
results.push(`✓ [text] ${f.name} = "${f.value}"`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return { content: [{ type: "text", text: results.join("\n") }], details: {} };
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
241
|
+
return { content: [{ type: "text", text: `Fill form failed: ${msg}` }], details: { isError: true } };
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
// ── browser_file_upload ───────────────────────────────────────────
|
|
246
|
+
const fileUploadTool = {
|
|
247
|
+
name: "browser_file_upload",
|
|
248
|
+
label: "Browser File Upload",
|
|
249
|
+
description: "Upload one or more files through a file input element.",
|
|
250
|
+
promptSnippet: "`browser_file_upload { paths }` — upload files",
|
|
251
|
+
parameters: {
|
|
252
|
+
type: "object",
|
|
253
|
+
properties: {
|
|
254
|
+
element: { type: "string", description: "CSS selector of the file input element. Default: input[type=file]." },
|
|
255
|
+
paths: {
|
|
256
|
+
type: "array",
|
|
257
|
+
items: { type: "string" },
|
|
258
|
+
description: "Absolute or relative paths to files to upload.",
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
required: ["paths"],
|
|
262
|
+
},
|
|
263
|
+
async execute(_toolCallId, params) {
|
|
264
|
+
const p = params;
|
|
265
|
+
try {
|
|
266
|
+
const page = bs.getActivePage();
|
|
267
|
+
const selector = p.element ?? "input[type=file]";
|
|
268
|
+
const fileChooserPromise = page.waitForEvent("filechooser");
|
|
269
|
+
await page.click(selector, { timeout: 5000 });
|
|
270
|
+
const fileChooser = await fileChooserPromise;
|
|
271
|
+
await fileChooser.setFiles(p.paths);
|
|
272
|
+
return { content: [{ type: "text", text: `✓ Uploaded: ${p.paths.join(", ")}` }], details: {} };
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
276
|
+
return { content: [{ type: "text", text: `File upload failed: ${msg}` }], details: { isError: true } };
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
const tools = [clickTool, typeTool, pressKeyTool, hoverTool, dragTool, selectTool, fillFormTool, fileUploadTool];
|
|
281
|
+
for (const tool of tools) {
|
|
282
|
+
try {
|
|
283
|
+
ext.registerTool(tool);
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
287
|
+
process.stderr.write(`[browser] Failed to register ${tool.name}: ${msg}\n`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network tools: browser_network_requests, browser_network_request.
|
|
3
|
+
*/
|
|
4
|
+
import type { ExtensionAPI } from "../../../sdk/coding-agent/index.js";
|
|
5
|
+
import { BrowserService } from "../browser-service.js";
|
|
6
|
+
export declare function registerNetworkTools(ext: ExtensionAPI, bs: BrowserService): void;
|
|
7
|
+
//# sourceMappingURL=network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../../src/extensions/browser/tools/network.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,oCAAoC,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,cAAc,GAAG,IAAI,CAwHhF"}
|