cssprobe-cli 0.2.26 → 0.3.1
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/AGENTS.md +29 -4
- package/CHANGELOG.md +11 -0
- package/README.md +84 -1
- package/dist/browser/interactions.d.ts +48 -0
- package/dist/browser/interactions.js +88 -0
- package/dist/cli/commands.js +97 -0
- package/dist/cli/program.js +78 -152
- package/dist/cli/session-ops.d.ts +44 -0
- package/dist/cli/session-ops.js +111 -0
- package/dist/daemon/daemon.js +102 -6
- package/dist/daemon/flowRunner.d.ts +62 -0
- package/dist/daemon/flowRunner.js +155 -0
- package/dist/engine/evalSerializer.d.ts +1 -0
- package/dist/engine/evalSerializer.js +43 -0
- package/dist/help.json +84 -1
- package/dist/installer/index.d.ts +2 -0
- package/dist/installer/index.js +6 -1
- package/dist/installer/mcp.d.ts +14 -0
- package/dist/installer/mcp.js +274 -0
- package/dist/installer/skill-template.js +43 -0
- package/dist/installer/toml.d.ts +20 -0
- package/dist/installer/toml.js +98 -0
- package/dist/mcp/index.d.ts +15 -0
- package/dist/mcp/index.js +174 -0
- package/dist/mcp/server-instructions.d.ts +1 -0
- package/dist/mcp/server-instructions.js +27 -0
- package/dist/mcp/tools.d.ts +261 -0
- package/dist/mcp/tools.js +238 -0
- package/dist/utils/screenshot.d.ts +1 -0
- package/dist/utils/screenshot.js +58 -0
- package/llms.txt +2 -1
- package/package.json +2 -1
|
@@ -127,6 +127,49 @@ function buildSkillMd() {
|
|
|
127
127
|
'cssprobe-cli close # stop browser + daemon',
|
|
128
128
|
BT3,
|
|
129
129
|
'',
|
|
130
|
+
'## Multi-step UI Flows',
|
|
131
|
+
'',
|
|
132
|
+
'Beyond inspection, cssprobe-cli drives the page: click, hover, type, wait, and',
|
|
133
|
+
'run scripted flows -- all in the same session.',
|
|
134
|
+
'',
|
|
135
|
+
BT3 + 'bash',
|
|
136
|
+
'cssprobe-cli click ".layout-switch" # real mouse click (auto-scroll + actionability wait)',
|
|
137
|
+
'cssprobe-cli click ".item" --nth 2 # 1-based match index; multi-match without --nth fails (strict)',
|
|
138
|
+
'cssprobe-cli hover ".menu-item"',
|
|
139
|
+
'cssprobe-cli type ".block-title input" "Hi" --press Enter # fill by default',
|
|
140
|
+
'cssprobe-cli type ".editor" "text" --sequential --clear # real key events for custom editors',
|
|
141
|
+
'cssprobe-cli wait-for ".modal" --state visible --timeout 5000',
|
|
142
|
+
'cssprobe-cli wait-for --js "() => ready === true"',
|
|
143
|
+
'cssprobe-cli wait-for --network-idle',
|
|
144
|
+
BT3,
|
|
145
|
+
'',
|
|
146
|
+
'### Scripted flows: ' + BT + 'run <file>' + BT,
|
|
147
|
+
'',
|
|
148
|
+
'A flow script default-exports an async function receiving the API object and',
|
|
149
|
+
'runs inside the daemon session:',
|
|
150
|
+
'',
|
|
151
|
+
BT3 + 'js',
|
|
152
|
+
'export default async ({ page, click, hover, type, waitFor, inspect, screenshot, log }) => {',
|
|
153
|
+
' await waitFor(".editor-canvas");',
|
|
154
|
+
' await click(".layout-switch", { nth: 1 });',
|
|
155
|
+
' await type(".block-title input", "Hello", { press: "Enter", sequential: true, clear: true });',
|
|
156
|
+
' await waitFor({ networkIdle: true });',
|
|
157
|
+
' const { findings } = await inspect(".block-grid", { format: "json" });',
|
|
158
|
+
' await screenshot({ path: "./after.png" });',
|
|
159
|
+
' return { findings: findings.length };',
|
|
160
|
+
'};',
|
|
161
|
+
BT3,
|
|
162
|
+
'',
|
|
163
|
+
BT3 + 'bash',
|
|
164
|
+
'cssprobe-cli run ./flow.js # --timeout ms (default 300000, 0 = unlimited)',
|
|
165
|
+
BT3,
|
|
166
|
+
'',
|
|
167
|
+
'Notes:',
|
|
168
|
+
'',
|
|
169
|
+
'- Scripts run on your machine with full Node privileges -- only run trusted scripts.',
|
|
170
|
+
'- ' + BT + 'screenshot' + BT + ' relative paths resolve against the script directory.',
|
|
171
|
+
'- On failure the command exits 1, prints collected logs, and keeps the session alive.',
|
|
172
|
+
'',
|
|
130
173
|
'## Output Modes',
|
|
131
174
|
'',
|
|
132
175
|
'Pass ' + BT + '--json' + BT + ' when consuming output programmatically:',
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny TOML helpers — just enough to inject / replace / remove a single
|
|
3
|
+
* dotted-key table block (`[mcp_servers.cssprobe-cli]`) inside an existing
|
|
4
|
+
* `~/.codex/config.toml`. We deliberately do NOT try to be a general TOML
|
|
5
|
+
* parser/serializer.
|
|
6
|
+
*
|
|
7
|
+
* Strategy: treat the file as text. Find the header line, splice it (and the
|
|
8
|
+
* lines that follow it until the next `[...]` header or EOF) in or out.
|
|
9
|
+
* Everything outside that block is preserved verbatim.
|
|
10
|
+
*/
|
|
11
|
+
export declare function serializeTomlTableBody(values: Record<string, string | string[]>): string;
|
|
12
|
+
export declare function buildTomlTable(header: string, values: Record<string, string | string[]>): string;
|
|
13
|
+
export declare function upsertTomlTable(fileContent: string, header: string, block: string): {
|
|
14
|
+
content: string;
|
|
15
|
+
action: 'inserted' | 'replaced' | 'unchanged';
|
|
16
|
+
};
|
|
17
|
+
export declare function removeTomlTable(fileContent: string, header: string): {
|
|
18
|
+
content: string;
|
|
19
|
+
action: 'removed' | 'not-found';
|
|
20
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tiny TOML helpers — just enough to inject / replace / remove a single
|
|
4
|
+
* dotted-key table block (`[mcp_servers.cssprobe-cli]`) inside an existing
|
|
5
|
+
* `~/.codex/config.toml`. We deliberately do NOT try to be a general TOML
|
|
6
|
+
* parser/serializer.
|
|
7
|
+
*
|
|
8
|
+
* Strategy: treat the file as text. Find the header line, splice it (and the
|
|
9
|
+
* lines that follow it until the next `[...]` header or EOF) in or out.
|
|
10
|
+
* Everything outside that block is preserved verbatim.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.serializeTomlTableBody = serializeTomlTableBody;
|
|
14
|
+
exports.buildTomlTable = buildTomlTable;
|
|
15
|
+
exports.upsertTomlTable = upsertTomlTable;
|
|
16
|
+
exports.removeTomlTable = removeTomlTable;
|
|
17
|
+
function serializeTomlTableBody(values) {
|
|
18
|
+
const lines = [];
|
|
19
|
+
for (const [key, value] of Object.entries(values)) {
|
|
20
|
+
if (typeof value === 'string') {
|
|
21
|
+
lines.push(`${key} = ${quoteString(value)}`);
|
|
22
|
+
}
|
|
23
|
+
else if (Array.isArray(value) && value.every((v) => typeof v === 'string')) {
|
|
24
|
+
const parts = value.map(quoteString).join(', ');
|
|
25
|
+
lines.push(`${key} = [${parts}]`);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
throw new Error(`Unsupported TOML value type for key "${key}"`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return lines.join('\n');
|
|
32
|
+
}
|
|
33
|
+
function quoteString(s) {
|
|
34
|
+
return '"' + s.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
|
|
35
|
+
}
|
|
36
|
+
function buildTomlTable(header, values) {
|
|
37
|
+
return `[${header}]\n${serializeTomlTableBody(values)}`;
|
|
38
|
+
}
|
|
39
|
+
function upsertTomlTable(fileContent, header, block) {
|
|
40
|
+
const headerLine = `[${header}]`;
|
|
41
|
+
const headerIdx = findHeaderIndex(fileContent, headerLine);
|
|
42
|
+
if (headerIdx === -1) {
|
|
43
|
+
const trimmed = fileContent.trimEnd();
|
|
44
|
+
const sep = trimmed.length > 0 ? '\n\n' : '';
|
|
45
|
+
return {
|
|
46
|
+
content: trimmed + sep + block + '\n',
|
|
47
|
+
action: 'inserted',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const blockEnd = findNextTableHeader(fileContent, headerIdx + headerLine.length);
|
|
51
|
+
const existingBlock = fileContent.substring(headerIdx, blockEnd).replace(/\n+$/, '');
|
|
52
|
+
if (existingBlock === block) {
|
|
53
|
+
return { content: fileContent, action: 'unchanged' };
|
|
54
|
+
}
|
|
55
|
+
const before = fileContent.substring(0, headerIdx);
|
|
56
|
+
const after = fileContent.substring(blockEnd);
|
|
57
|
+
const beforeClean = before.replace(/\n+$/, '');
|
|
58
|
+
const afterClean = after.replace(/^\n+/, '');
|
|
59
|
+
const sepBefore = beforeClean.length > 0 ? '\n\n' : '';
|
|
60
|
+
const sepAfter = afterClean.length > 0 ? '\n\n' : '\n';
|
|
61
|
+
return {
|
|
62
|
+
content: beforeClean + sepBefore + block + sepAfter + afterClean,
|
|
63
|
+
action: 'replaced',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function removeTomlTable(fileContent, header) {
|
|
67
|
+
const headerLine = `[${header}]`;
|
|
68
|
+
const headerIdx = findHeaderIndex(fileContent, headerLine);
|
|
69
|
+
if (headerIdx === -1)
|
|
70
|
+
return { content: fileContent, action: 'not-found' };
|
|
71
|
+
const blockEnd = findNextTableHeader(fileContent, headerIdx + headerLine.length);
|
|
72
|
+
const before = fileContent.substring(0, headerIdx).replace(/\n+$/, '');
|
|
73
|
+
const after = fileContent.substring(blockEnd).replace(/^\n+/, '');
|
|
74
|
+
const joined = before + (before && after ? '\n\n' : '') + after;
|
|
75
|
+
return { content: joined, action: 'removed' };
|
|
76
|
+
}
|
|
77
|
+
function findHeaderIndex(content, headerLine) {
|
|
78
|
+
if (content.startsWith(headerLine))
|
|
79
|
+
return 0;
|
|
80
|
+
const needle = '\n' + headerLine;
|
|
81
|
+
const idx = content.indexOf(needle);
|
|
82
|
+
return idx === -1 ? -1 : idx + 1;
|
|
83
|
+
}
|
|
84
|
+
function findNextTableHeader(content, from) {
|
|
85
|
+
let i = from;
|
|
86
|
+
while (i < content.length) {
|
|
87
|
+
const nlIdx = content.indexOf('\n[', i);
|
|
88
|
+
if (nlIdx === -1)
|
|
89
|
+
return content.length;
|
|
90
|
+
if (content[nlIdx + 2] === '[') {
|
|
91
|
+
i = nlIdx + 2;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
return nlIdx + 1;
|
|
95
|
+
}
|
|
96
|
+
return content.length;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=toml.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class MCPServer {
|
|
2
|
+
private rl;
|
|
3
|
+
private handler;
|
|
4
|
+
private version;
|
|
5
|
+
private pending;
|
|
6
|
+
private closing;
|
|
7
|
+
private queue;
|
|
8
|
+
constructor();
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
handleMessage(message: Record<string, unknown>): Promise<Record<string, unknown> | undefined>;
|
|
11
|
+
private handleToolCall;
|
|
12
|
+
private executeTool;
|
|
13
|
+
private send;
|
|
14
|
+
}
|
|
15
|
+
export declare function runMcpServer(): Promise<void>;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.MCPServer = void 0;
|
|
37
|
+
exports.runMcpServer = runMcpServer;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const readline = __importStar(require("readline"));
|
|
41
|
+
const server_instructions_1 = require("./server-instructions");
|
|
42
|
+
const tools_1 = require("./tools");
|
|
43
|
+
const PROTOCOL_VERSION = '2024-11-05';
|
|
44
|
+
class MCPServer {
|
|
45
|
+
rl = null;
|
|
46
|
+
handler = new tools_1.MCPToolHandler();
|
|
47
|
+
version;
|
|
48
|
+
pending = 0;
|
|
49
|
+
closing = false;
|
|
50
|
+
queue = Promise.resolve();
|
|
51
|
+
constructor() {
|
|
52
|
+
try {
|
|
53
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf-8'));
|
|
54
|
+
this.version = pkg.version || '0.0.0';
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
this.version = '0.0.0';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async run() {
|
|
61
|
+
this.rl = readline.createInterface({
|
|
62
|
+
input: process.stdin,
|
|
63
|
+
output: process.stdout,
|
|
64
|
+
terminal: false,
|
|
65
|
+
});
|
|
66
|
+
process.stderr.write('cssprobe-cli MCP server started\n');
|
|
67
|
+
// Requests are serialized: tool calls share one browser session, so an
|
|
68
|
+
// inspect racing an in-flight open must be queued, not run concurrently.
|
|
69
|
+
this.rl.on('line', (line) => {
|
|
70
|
+
this.pending++;
|
|
71
|
+
this.queue = this.queue.then(async () => {
|
|
72
|
+
try {
|
|
73
|
+
const message = JSON.parse(line);
|
|
74
|
+
const response = await this.handleMessage(message);
|
|
75
|
+
if (response)
|
|
76
|
+
this.send(response);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// ignore malformed lines
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
this.pending--;
|
|
83
|
+
if (this.closing && this.pending === 0)
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
// Exit only after in-flight requests drain, so a client that closes
|
|
89
|
+
// stdin immediately after sending still receives its responses.
|
|
90
|
+
this.rl.on('close', () => {
|
|
91
|
+
this.closing = true;
|
|
92
|
+
if (this.pending === 0)
|
|
93
|
+
process.exit(0);
|
|
94
|
+
});
|
|
95
|
+
process.on('SIGTERM', () => process.exit(0));
|
|
96
|
+
process.on('SIGINT', () => process.exit(0));
|
|
97
|
+
}
|
|
98
|
+
async handleMessage(message) {
|
|
99
|
+
const method = message['method'];
|
|
100
|
+
const id = message['id'];
|
|
101
|
+
if (!method)
|
|
102
|
+
return undefined;
|
|
103
|
+
// Notifications (no id) never receive a response.
|
|
104
|
+
if (id === undefined)
|
|
105
|
+
return undefined;
|
|
106
|
+
switch (method) {
|
|
107
|
+
case 'initialize':
|
|
108
|
+
return {
|
|
109
|
+
jsonrpc: '2.0',
|
|
110
|
+
id,
|
|
111
|
+
result: {
|
|
112
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
113
|
+
capabilities: { tools: {} },
|
|
114
|
+
serverInfo: { name: 'cssprobe-cli', version: this.version },
|
|
115
|
+
instructions: server_instructions_1.SERVER_INSTRUCTIONS,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
case 'ping':
|
|
119
|
+
return { jsonrpc: '2.0', id, result: {} };
|
|
120
|
+
case 'tools/list':
|
|
121
|
+
return { jsonrpc: '2.0', id, result: { tools: (0, tools_1.getToolDefinitions)() } };
|
|
122
|
+
case 'tools/call':
|
|
123
|
+
return this.handleToolCall(message, id);
|
|
124
|
+
default:
|
|
125
|
+
return { jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async handleToolCall(message, id) {
|
|
129
|
+
const params = message['params'];
|
|
130
|
+
const toolName = params?.['name'];
|
|
131
|
+
const args = params?.['arguments'] ?? {};
|
|
132
|
+
if (!toolName) {
|
|
133
|
+
return { jsonrpc: '2.0', id, error: { code: -32602, message: 'Missing tool name' } };
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const text = await this.executeTool(toolName, args);
|
|
137
|
+
return { jsonrpc: '2.0', id, result: { content: [{ type: 'text', text }] } };
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
141
|
+
return {
|
|
142
|
+
jsonrpc: '2.0',
|
|
143
|
+
id,
|
|
144
|
+
result: {
|
|
145
|
+
content: [{ type: 'text', text: `cssprobe-cli internal error: ${msg}\n\nThis is an unexpected error — please report it.` }],
|
|
146
|
+
isError: true,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
executeTool(name, args) {
|
|
152
|
+
switch (name) {
|
|
153
|
+
case 'cssprobe_open': return this.handler.open(args);
|
|
154
|
+
case 'cssprobe_inspect': return this.handler.inspect(args);
|
|
155
|
+
case 'cssprobe_tree': return this.handler.tree(args);
|
|
156
|
+
case 'cssprobe_layout': return this.handler.layout(args);
|
|
157
|
+
case 'cssprobe_findings': return this.handler.findings(args);
|
|
158
|
+
case 'cssprobe_eval': return this.handler.evalExpression(args);
|
|
159
|
+
case 'cssprobe_screenshot': return this.handler.screenshot(args);
|
|
160
|
+
case 'cssprobe_inject_css': return this.handler.injectCss(args);
|
|
161
|
+
case 'cssprobe_close': return this.handler.close(args);
|
|
162
|
+
case 'cssprobe_status': return this.handler.status();
|
|
163
|
+
default: return Promise.resolve(`Unknown tool: ${name}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
send(message) {
|
|
167
|
+
process.stdout.write(JSON.stringify(message) + '\n');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
exports.MCPServer = MCPServer;
|
|
171
|
+
async function runMcpServer() {
|
|
172
|
+
await new MCPServer().run();
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SERVER_INSTRUCTIONS = "cssprobe-cli \u2014 runtime CSS probe for AI agents.\n\nIt opens a real browser session and answers questions that static code cannot:\nwhy an element overflows, where its scroll chain goes, what it actually renders\nas. Findings carry a confidence level (DEFINITE / INDEFINITE / UNVERIFIABLE) \u2014\nreport UNVERIFIABLE items as \"needs verification\", never as conclusions.\n\nTypical workflow:\n1. cssprobe_open \u2014 start a session (optionally with a URL; headed: true when a\n login is needed, then ask the user to sign in manually).\n2. cssprobe_inspect / cssprobe_layout / cssprobe_findings \u2014 query a selector.\n inspect returns DOM tree + layout + findings; layout is the ASCII diagram;\n findings lists only issues/warnings/errors.\n3. cssprobe_eval / cssprobe_inject_css \u2014 probe or patch the live page.\n4. cssprobe_screenshot \u2014 capture the current page to a PNG file.\n5. cssprobe_close \u2014 stop the session when done.\n\nNotes:\n- One shared \"default\" session: open once, run many queries, close at the end.\n- Any command without an open session returns guidance instead of failing.\n- Pair with cssgraph (static CSS knowledge graph MCP) for the full picture:\n cssgraph finds where styles come from, cssprobe shows what they render as.\n- Prefer narrow selectors (\".card > .title\") to keep output small.";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SERVER_INSTRUCTIONS = void 0;
|
|
4
|
+
exports.SERVER_INSTRUCTIONS = `cssprobe-cli — runtime CSS probe for AI agents.
|
|
5
|
+
|
|
6
|
+
It opens a real browser session and answers questions that static code cannot:
|
|
7
|
+
why an element overflows, where its scroll chain goes, what it actually renders
|
|
8
|
+
as. Findings carry a confidence level (DEFINITE / INDEFINITE / UNVERIFIABLE) —
|
|
9
|
+
report UNVERIFIABLE items as "needs verification", never as conclusions.
|
|
10
|
+
|
|
11
|
+
Typical workflow:
|
|
12
|
+
1. cssprobe_open — start a session (optionally with a URL; headed: true when a
|
|
13
|
+
login is needed, then ask the user to sign in manually).
|
|
14
|
+
2. cssprobe_inspect / cssprobe_layout / cssprobe_findings — query a selector.
|
|
15
|
+
inspect returns DOM tree + layout + findings; layout is the ASCII diagram;
|
|
16
|
+
findings lists only issues/warnings/errors.
|
|
17
|
+
3. cssprobe_eval / cssprobe_inject_css — probe or patch the live page.
|
|
18
|
+
4. cssprobe_screenshot — capture the current page to a PNG file.
|
|
19
|
+
5. cssprobe_close — stop the session when done.
|
|
20
|
+
|
|
21
|
+
Notes:
|
|
22
|
+
- One shared "default" session: open once, run many queries, close at the end.
|
|
23
|
+
- Any command without an open session returns guidance instead of failing.
|
|
24
|
+
- Pair with cssgraph (static CSS knowledge graph MCP) for the full picture:
|
|
25
|
+
cssgraph finds where styles come from, cssprobe shows what they render as.
|
|
26
|
+
- Prefer narrow selectors (".card > .title") to keep output small.`;
|
|
27
|
+
//# sourceMappingURL=server-instructions.js.map
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
export declare function getToolDefinitions(): ({
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object";
|
|
6
|
+
properties: {
|
|
7
|
+
url: {
|
|
8
|
+
type: "string";
|
|
9
|
+
description: string;
|
|
10
|
+
};
|
|
11
|
+
headed: {
|
|
12
|
+
type: "boolean";
|
|
13
|
+
description: string;
|
|
14
|
+
};
|
|
15
|
+
viewport: {
|
|
16
|
+
type: "string";
|
|
17
|
+
description: string;
|
|
18
|
+
};
|
|
19
|
+
browser: {
|
|
20
|
+
type: "string";
|
|
21
|
+
enum: string[];
|
|
22
|
+
description: string;
|
|
23
|
+
};
|
|
24
|
+
state: {
|
|
25
|
+
type: "string";
|
|
26
|
+
description: string;
|
|
27
|
+
};
|
|
28
|
+
selector?: undefined;
|
|
29
|
+
depth?: undefined;
|
|
30
|
+
brief?: undefined;
|
|
31
|
+
expression?: undefined;
|
|
32
|
+
full_page?: undefined;
|
|
33
|
+
out?: undefined;
|
|
34
|
+
css?: undefined;
|
|
35
|
+
all?: undefined;
|
|
36
|
+
};
|
|
37
|
+
required: never[];
|
|
38
|
+
};
|
|
39
|
+
} | {
|
|
40
|
+
name: string;
|
|
41
|
+
description: string;
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: "object";
|
|
44
|
+
properties: {
|
|
45
|
+
selector: {
|
|
46
|
+
type: "string";
|
|
47
|
+
description: string;
|
|
48
|
+
};
|
|
49
|
+
depth: {
|
|
50
|
+
type: "number";
|
|
51
|
+
description: string;
|
|
52
|
+
};
|
|
53
|
+
brief: {
|
|
54
|
+
type: "boolean";
|
|
55
|
+
description: string;
|
|
56
|
+
};
|
|
57
|
+
url?: undefined;
|
|
58
|
+
headed?: undefined;
|
|
59
|
+
viewport?: undefined;
|
|
60
|
+
browser?: undefined;
|
|
61
|
+
state?: undefined;
|
|
62
|
+
expression?: undefined;
|
|
63
|
+
full_page?: undefined;
|
|
64
|
+
out?: undefined;
|
|
65
|
+
css?: undefined;
|
|
66
|
+
all?: undefined;
|
|
67
|
+
};
|
|
68
|
+
required: string[];
|
|
69
|
+
};
|
|
70
|
+
} | {
|
|
71
|
+
name: string;
|
|
72
|
+
description: string;
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: "object";
|
|
75
|
+
properties: {
|
|
76
|
+
selector: {
|
|
77
|
+
type: "string";
|
|
78
|
+
description: string;
|
|
79
|
+
};
|
|
80
|
+
depth: {
|
|
81
|
+
type: "number";
|
|
82
|
+
description: string;
|
|
83
|
+
};
|
|
84
|
+
url?: undefined;
|
|
85
|
+
headed?: undefined;
|
|
86
|
+
viewport?: undefined;
|
|
87
|
+
browser?: undefined;
|
|
88
|
+
state?: undefined;
|
|
89
|
+
brief?: undefined;
|
|
90
|
+
expression?: undefined;
|
|
91
|
+
full_page?: undefined;
|
|
92
|
+
out?: undefined;
|
|
93
|
+
css?: undefined;
|
|
94
|
+
all?: undefined;
|
|
95
|
+
};
|
|
96
|
+
required: string[];
|
|
97
|
+
};
|
|
98
|
+
} | {
|
|
99
|
+
name: string;
|
|
100
|
+
description: string;
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: "object";
|
|
103
|
+
properties: {
|
|
104
|
+
selector: {
|
|
105
|
+
type: "string";
|
|
106
|
+
description: string;
|
|
107
|
+
};
|
|
108
|
+
url?: undefined;
|
|
109
|
+
headed?: undefined;
|
|
110
|
+
viewport?: undefined;
|
|
111
|
+
browser?: undefined;
|
|
112
|
+
state?: undefined;
|
|
113
|
+
depth?: undefined;
|
|
114
|
+
brief?: undefined;
|
|
115
|
+
expression?: undefined;
|
|
116
|
+
full_page?: undefined;
|
|
117
|
+
out?: undefined;
|
|
118
|
+
css?: undefined;
|
|
119
|
+
all?: undefined;
|
|
120
|
+
};
|
|
121
|
+
required: string[];
|
|
122
|
+
};
|
|
123
|
+
} | {
|
|
124
|
+
name: string;
|
|
125
|
+
description: string;
|
|
126
|
+
inputSchema: {
|
|
127
|
+
type: "object";
|
|
128
|
+
properties: {
|
|
129
|
+
expression: {
|
|
130
|
+
type: "string";
|
|
131
|
+
description: string;
|
|
132
|
+
};
|
|
133
|
+
url?: undefined;
|
|
134
|
+
headed?: undefined;
|
|
135
|
+
viewport?: undefined;
|
|
136
|
+
browser?: undefined;
|
|
137
|
+
state?: undefined;
|
|
138
|
+
selector?: undefined;
|
|
139
|
+
depth?: undefined;
|
|
140
|
+
brief?: undefined;
|
|
141
|
+
full_page?: undefined;
|
|
142
|
+
out?: undefined;
|
|
143
|
+
css?: undefined;
|
|
144
|
+
all?: undefined;
|
|
145
|
+
};
|
|
146
|
+
required: string[];
|
|
147
|
+
};
|
|
148
|
+
} | {
|
|
149
|
+
name: string;
|
|
150
|
+
description: string;
|
|
151
|
+
inputSchema: {
|
|
152
|
+
type: "object";
|
|
153
|
+
properties: {
|
|
154
|
+
full_page: {
|
|
155
|
+
type: "boolean";
|
|
156
|
+
description: string;
|
|
157
|
+
};
|
|
158
|
+
out: {
|
|
159
|
+
type: "string";
|
|
160
|
+
description: string;
|
|
161
|
+
};
|
|
162
|
+
url?: undefined;
|
|
163
|
+
headed?: undefined;
|
|
164
|
+
viewport?: undefined;
|
|
165
|
+
browser?: undefined;
|
|
166
|
+
state?: undefined;
|
|
167
|
+
selector?: undefined;
|
|
168
|
+
depth?: undefined;
|
|
169
|
+
brief?: undefined;
|
|
170
|
+
expression?: undefined;
|
|
171
|
+
css?: undefined;
|
|
172
|
+
all?: undefined;
|
|
173
|
+
};
|
|
174
|
+
required: never[];
|
|
175
|
+
};
|
|
176
|
+
} | {
|
|
177
|
+
name: string;
|
|
178
|
+
description: string;
|
|
179
|
+
inputSchema: {
|
|
180
|
+
type: "object";
|
|
181
|
+
properties: {
|
|
182
|
+
css: {
|
|
183
|
+
type: "string";
|
|
184
|
+
description: string;
|
|
185
|
+
};
|
|
186
|
+
url?: undefined;
|
|
187
|
+
headed?: undefined;
|
|
188
|
+
viewport?: undefined;
|
|
189
|
+
browser?: undefined;
|
|
190
|
+
state?: undefined;
|
|
191
|
+
selector?: undefined;
|
|
192
|
+
depth?: undefined;
|
|
193
|
+
brief?: undefined;
|
|
194
|
+
expression?: undefined;
|
|
195
|
+
full_page?: undefined;
|
|
196
|
+
out?: undefined;
|
|
197
|
+
all?: undefined;
|
|
198
|
+
};
|
|
199
|
+
required: string[];
|
|
200
|
+
};
|
|
201
|
+
} | {
|
|
202
|
+
name: string;
|
|
203
|
+
description: string;
|
|
204
|
+
inputSchema: {
|
|
205
|
+
type: "object";
|
|
206
|
+
properties: {
|
|
207
|
+
all: {
|
|
208
|
+
type: "boolean";
|
|
209
|
+
description: string;
|
|
210
|
+
};
|
|
211
|
+
url?: undefined;
|
|
212
|
+
headed?: undefined;
|
|
213
|
+
viewport?: undefined;
|
|
214
|
+
browser?: undefined;
|
|
215
|
+
state?: undefined;
|
|
216
|
+
selector?: undefined;
|
|
217
|
+
depth?: undefined;
|
|
218
|
+
brief?: undefined;
|
|
219
|
+
expression?: undefined;
|
|
220
|
+
full_page?: undefined;
|
|
221
|
+
out?: undefined;
|
|
222
|
+
css?: undefined;
|
|
223
|
+
};
|
|
224
|
+
required: never[];
|
|
225
|
+
};
|
|
226
|
+
} | {
|
|
227
|
+
name: string;
|
|
228
|
+
description: string;
|
|
229
|
+
inputSchema: {
|
|
230
|
+
type: "object";
|
|
231
|
+
properties: {
|
|
232
|
+
url?: undefined;
|
|
233
|
+
headed?: undefined;
|
|
234
|
+
viewport?: undefined;
|
|
235
|
+
browser?: undefined;
|
|
236
|
+
state?: undefined;
|
|
237
|
+
selector?: undefined;
|
|
238
|
+
depth?: undefined;
|
|
239
|
+
brief?: undefined;
|
|
240
|
+
expression?: undefined;
|
|
241
|
+
full_page?: undefined;
|
|
242
|
+
out?: undefined;
|
|
243
|
+
css?: undefined;
|
|
244
|
+
all?: undefined;
|
|
245
|
+
};
|
|
246
|
+
required: never[];
|
|
247
|
+
};
|
|
248
|
+
})[];
|
|
249
|
+
export declare class MCPToolHandler {
|
|
250
|
+
private runSession;
|
|
251
|
+
open(args: Record<string, unknown>): Promise<string>;
|
|
252
|
+
inspect(args: Record<string, unknown>): Promise<string>;
|
|
253
|
+
tree(args: Record<string, unknown>): Promise<string>;
|
|
254
|
+
layout(args: Record<string, unknown>): Promise<string>;
|
|
255
|
+
findings(args: Record<string, unknown>): Promise<string>;
|
|
256
|
+
evalExpression(args: Record<string, unknown>): Promise<string>;
|
|
257
|
+
screenshot(args: Record<string, unknown>): Promise<string>;
|
|
258
|
+
injectCss(args: Record<string, unknown>): Promise<string>;
|
|
259
|
+
close(args: Record<string, unknown>): Promise<string>;
|
|
260
|
+
status(): Promise<string>;
|
|
261
|
+
}
|