@peekdev/mcp 0.1.0-alpha.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/NOTICE +10 -0
- package/dist/db/index.d.ts +3 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +7 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrate.d.ts +37 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +86 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/migrations/0001_initial.sql +102 -0
- package/dist/db/migrations/0002_network_bodies.sql +15 -0
- package/dist/db/open.d.ts +57 -0
- package/dist/db/open.d.ts.map +1 -0
- package/dist/db/open.js +74 -0
- package/dist/db/open.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/action-schema.d.ts +223 -0
- package/dist/mcp/action-schema.d.ts.map +1 -0
- package/dist/mcp/action-schema.js +97 -0
- package/dist/mcp/action-schema.js.map +1 -0
- package/dist/mcp/event-blobs.d.ts +32 -0
- package/dist/mcp/event-blobs.d.ts.map +1 -0
- package/dist/mcp/event-blobs.js +65 -0
- package/dist/mcp/event-blobs.js.map +1 -0
- package/dist/mcp/event-walker.d.ts +86 -0
- package/dist/mcp/event-walker.d.ts.map +1 -0
- package/dist/mcp/event-walker.js +398 -0
- package/dist/mcp/event-walker.js.map +1 -0
- package/dist/mcp/host-bridge.d.ts +80 -0
- package/dist/mcp/host-bridge.d.ts.map +1 -0
- package/dist/mcp/host-bridge.js +88 -0
- package/dist/mcp/host-bridge.js.map +1 -0
- package/dist/mcp/index.d.ts +8 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +32 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/playwright-repro.d.ts +19 -0
- package/dist/mcp/playwright-repro.d.ts.map +1 -0
- package/dist/mcp/playwright-repro.js +78 -0
- package/dist/mcp/playwright-repro.js.map +1 -0
- package/dist/mcp/queries.d.ts +73 -0
- package/dist/mcp/queries.d.ts.map +1 -0
- package/dist/mcp/queries.js +139 -0
- package/dist/mcp/queries.js.map +1 -0
- package/dist/mcp/roots.d.ts +50 -0
- package/dist/mcp/roots.d.ts.map +1 -0
- package/dist/mcp/roots.js +97 -0
- package/dist/mcp/roots.js.map +1 -0
- package/dist/mcp/rrweb-types.d.ts +3 -0
- package/dist/mcp/rrweb-types.d.ts.map +1 -0
- package/dist/mcp/rrweb-types.js +7 -0
- package/dist/mcp/rrweb-types.js.map +1 -0
- package/dist/mcp/selector.d.ts +54 -0
- package/dist/mcp/selector.d.ts.map +1 -0
- package/dist/mcp/selector.js +209 -0
- package/dist/mcp/selector.js.map +1 -0
- package/dist/mcp/server.d.ts +49 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +469 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/summary.d.ts +26 -0
- package/dist/mcp/summary.d.ts.map +1 -0
- package/dist/mcp/summary.js +74 -0
- package/dist/mcp/summary.js.map +1 -0
- package/dist/native-host/action-protocol.d.ts +49 -0
- package/dist/native-host/action-protocol.d.ts.map +1 -0
- package/dist/native-host/action-protocol.js +36 -0
- package/dist/native-host/action-protocol.js.map +1 -0
- package/dist/native-host/audit.d.ts +69 -0
- package/dist/native-host/audit.d.ts.map +1 -0
- package/dist/native-host/audit.js +85 -0
- package/dist/native-host/audit.js.map +1 -0
- package/dist/native-host/config.d.ts +18 -0
- package/dist/native-host/config.d.ts.map +1 -0
- package/dist/native-host/config.js +56 -0
- package/dist/native-host/config.js.map +1 -0
- package/dist/native-host/extension-ids.json +6 -0
- package/dist/native-host/host.d.ts +30 -0
- package/dist/native-host/host.d.ts.map +1 -0
- package/dist/native-host/host.js +96 -0
- package/dist/native-host/host.js.map +1 -0
- package/dist/native-host/index.d.ts +4 -0
- package/dist/native-host/index.d.ts.map +1 -0
- package/dist/native-host/index.js +8 -0
- package/dist/native-host/index.js.map +1 -0
- package/dist/native-host/ingest.d.ts +83 -0
- package/dist/native-host/ingest.d.ts.map +1 -0
- package/dist/native-host/ingest.js +283 -0
- package/dist/native-host/ingest.js.map +1 -0
- package/dist/native-host/installer.d.ts +64 -0
- package/dist/native-host/installer.d.ts.map +1 -0
- package/dist/native-host/installer.js +110 -0
- package/dist/native-host/installer.js.map +1 -0
- package/dist/native-host/manifest.d.ts +64 -0
- package/dist/native-host/manifest.d.ts.map +1 -0
- package/dist/native-host/manifest.js +117 -0
- package/dist/native-host/manifest.js.map +1 -0
- package/dist/native-host/policy.d.ts +60 -0
- package/dist/native-host/policy.d.ts.map +1 -0
- package/dist/native-host/policy.js +116 -0
- package/dist/native-host/policy.js.map +1 -0
- package/dist/native-host/request-registry.d.ts +55 -0
- package/dist/native-host/request-registry.d.ts.map +1 -0
- package/dist/native-host/request-registry.js +111 -0
- package/dist/native-host/request-registry.js.map +1 -0
- package/dist/native-host/transport.d.ts +54 -0
- package/dist/native-host/transport.d.ts.map +1 -0
- package/dist/native-host/transport.js +113 -0
- package/dist/native-host/transport.js.map +1 -0
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +72 -0
- package/dist/postinstall.js.map +1 -0
- package/package.json +59 -0
- package/src/db/migrations/0001_initial.sql +102 -0
- package/src/db/migrations/0002_network_bodies.sql +15 -0
- package/src/native-host/extension-ids.json +6 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { eventWithTime } from './rrweb-types.js';
|
|
2
|
+
export interface GenerateReproOptions {
|
|
3
|
+
/** Only include actions at/after this epoch-millis. */
|
|
4
|
+
readonly startTs?: number;
|
|
5
|
+
/** Only include actions at/before this epoch-millis. */
|
|
6
|
+
readonly endTs?: number;
|
|
7
|
+
/** Test title (defaults to a session-derived label). */
|
|
8
|
+
readonly title?: string;
|
|
9
|
+
/** Max actions to emit (default 200); keeps the latest N, the rest noted. */
|
|
10
|
+
readonly maxActions?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Build a Playwright `test(...)` script from the user actions within
|
|
14
|
+
* `[startTs, endTs]`. Actions whose target selector couldn't be resolved are
|
|
15
|
+
* emitted as a `// TODO` comment (so the script stays runnable and the gap is
|
|
16
|
+
* visible) rather than silently dropped.
|
|
17
|
+
*/
|
|
18
|
+
export declare function generatePlaywrightRepro(events: eventWithTime[], options?: GenerateReproOptions): string;
|
|
19
|
+
//# sourceMappingURL=playwright-repro.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-repro.d.ts","sourceRoot":"","sources":["../../src/mcp/playwright-repro.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAgCD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,GAAE,oBAAyB,GACjC,MAAM,CAqCR"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// generate_playwright_repro (Task 3.13): turn a window of extracted user
|
|
2
|
+
// actions into a runnable Playwright test string. Each action maps to the
|
|
3
|
+
// idiomatic Playwright call:
|
|
4
|
+
// navigate -> await page.goto('url')
|
|
5
|
+
// click -> await page.click('selector')
|
|
6
|
+
// input -> await page.fill('selector', 'value')
|
|
7
|
+
// The first navigation seeds the opening goto; subsequent navigations are
|
|
8
|
+
// emitted inline (e.g. an in-app route change that triggered a full load).
|
|
9
|
+
import { extractUserActions } from './event-walker.js';
|
|
10
|
+
/** Default ceiling on emitted actions — caps the output size (PRD §B token budget). */
|
|
11
|
+
const DEFAULT_MAX_ACTIONS = 200;
|
|
12
|
+
/** Single-quote-escape a value for embedding in a generated JS string literal. */
|
|
13
|
+
function jsString(value) {
|
|
14
|
+
// Order matters: backslash first, then quote, then the line terminators —
|
|
15
|
+
// a bare \r or \n in a single-quoted literal is a strict-mode syntax error.
|
|
16
|
+
return `'${value
|
|
17
|
+
.replace(/\\/g, '\\\\')
|
|
18
|
+
.replace(/'/g, "\\'")
|
|
19
|
+
.replace(/\n/g, '\\n')
|
|
20
|
+
.replace(/\r/g, '\\r')}'`;
|
|
21
|
+
}
|
|
22
|
+
/** Map one user action to a Playwright statement, or undefined to skip it. */
|
|
23
|
+
function actionToStatement(action) {
|
|
24
|
+
switch (action.type) {
|
|
25
|
+
case 'navigate':
|
|
26
|
+
return action.url ? ` await page.goto(${jsString(action.url)});` : undefined;
|
|
27
|
+
case 'click':
|
|
28
|
+
return action.selector ? ` await page.click(${jsString(action.selector)});` : undefined;
|
|
29
|
+
case 'input':
|
|
30
|
+
return action.selector
|
|
31
|
+
? ` await page.fill(${jsString(action.selector)}, ${jsString(action.value ?? '')});`
|
|
32
|
+
: undefined;
|
|
33
|
+
default:
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build a Playwright `test(...)` script from the user actions within
|
|
39
|
+
* `[startTs, endTs]`. Actions whose target selector couldn't be resolved are
|
|
40
|
+
* emitted as a `// TODO` comment (so the script stays runnable and the gap is
|
|
41
|
+
* visible) rather than silently dropped.
|
|
42
|
+
*/
|
|
43
|
+
export function generatePlaywrightRepro(events, options = {}) {
|
|
44
|
+
const startTs = options.startTs ?? Number.NEGATIVE_INFINITY;
|
|
45
|
+
const endTs = options.endTs ?? Number.POSITIVE_INFINITY;
|
|
46
|
+
const title = options.title ?? 'peek recorded session';
|
|
47
|
+
const maxActions = options.maxActions ?? DEFAULT_MAX_ACTIONS;
|
|
48
|
+
const allInWindow = extractUserActions(events).filter((a) => a.ts >= startTs && a.ts <= endTs);
|
|
49
|
+
// Cap output: keep the LATEST N actions (most relevant to reproduce recent
|
|
50
|
+
// behavior), noting the truncation so the agent knows the repro is partial.
|
|
51
|
+
const truncated = allInWindow.length > maxActions;
|
|
52
|
+
const actions = truncated ? allInWindow.slice(allInWindow.length - maxActions) : allInWindow;
|
|
53
|
+
const lines = [];
|
|
54
|
+
lines.push(`import { test, expect } from '@playwright/test';`);
|
|
55
|
+
lines.push('');
|
|
56
|
+
lines.push(`test(${jsString(title)}, async ({ page }) => {`);
|
|
57
|
+
if (actions.length === 0) {
|
|
58
|
+
lines.push(' // No user actions were recorded in this window.');
|
|
59
|
+
}
|
|
60
|
+
else if (truncated) {
|
|
61
|
+
lines.push(` // truncated: showing last ${maxActions} of ${allInWindow.length} actions (narrow startTs/endTs for the rest)`);
|
|
62
|
+
}
|
|
63
|
+
for (const action of actions) {
|
|
64
|
+
const stmt = actionToStatement(action);
|
|
65
|
+
if (stmt !== undefined) {
|
|
66
|
+
lines.push(stmt);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
lines.push(` // TODO: ${action.summary} (target selector unresolved)`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
lines.push('});');
|
|
73
|
+
lines.push('');
|
|
74
|
+
return lines.join('\n');
|
|
75
|
+
}
|
|
76
|
+
// `expect` is imported in the generated script for the author to add assertions;
|
|
77
|
+
// we don't synthesize assertions in v1 (we have no oracle for "correct" state).
|
|
78
|
+
//# sourceMappingURL=playwright-repro.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-repro.js","sourceRoot":"","sources":["../../src/mcp/playwright-repro.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
/** A row of `sessions` as the MCP tools present it (camelCase, PRD §B3 ids). */
|
|
3
|
+
export interface SessionSummaryRow {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly origin: string | null;
|
|
6
|
+
readonly url: string | null;
|
|
7
|
+
readonly title: string | null;
|
|
8
|
+
readonly startedAt: number;
|
|
9
|
+
readonly durationMs: number;
|
|
10
|
+
readonly errorCount: number;
|
|
11
|
+
readonly eventCount: number;
|
|
12
|
+
}
|
|
13
|
+
/** Accurate `COUNT(*)` of error-level console rows for a session. */
|
|
14
|
+
export declare function countConsoleErrors(db: Database, sessionId: string): number;
|
|
15
|
+
/** Accurate `COUNT(*)` of failed/notable network rows (status >= 400 or net error). */
|
|
16
|
+
export declare function countNetworkErrors(db: Database, sessionId: string): number;
|
|
17
|
+
export interface ListSessionsOptions {
|
|
18
|
+
readonly limit?: number;
|
|
19
|
+
readonly origin?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* List the most-recently-updated sessions, newest first (PRD §B3
|
|
23
|
+
* `list_recent_sessions`). Default limit 10; capped to the schema's
|
|
24
|
+
* `origin`-filtered subset when `origin` is given.
|
|
25
|
+
*/
|
|
26
|
+
export declare function listRecentSessions(db: Database, options?: ListSessionsOptions): SessionSummaryRow[];
|
|
27
|
+
/** One session's summary row, or undefined if no such id. */
|
|
28
|
+
export declare function getSessionSummaryRow(db: Database, id: string): SessionSummaryRow | undefined;
|
|
29
|
+
export interface ConsoleErrorRow {
|
|
30
|
+
readonly id: number;
|
|
31
|
+
readonly ts: number;
|
|
32
|
+
readonly level: string;
|
|
33
|
+
readonly message: string;
|
|
34
|
+
readonly stack: string | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Console error rows for a session, oldest first (PRD §B3
|
|
38
|
+
* `get_session_console_errors`). `since` filters to ts >= it; default level
|
|
39
|
+
* filter is `error` only (the tool name says "errors").
|
|
40
|
+
*/
|
|
41
|
+
export declare function getConsoleErrors(db: Database, id: string, options?: {
|
|
42
|
+
since?: number;
|
|
43
|
+
limit?: number;
|
|
44
|
+
level?: string;
|
|
45
|
+
}): ConsoleErrorRow[];
|
|
46
|
+
export interface NetworkErrorRow {
|
|
47
|
+
readonly id: number;
|
|
48
|
+
readonly ts: number;
|
|
49
|
+
readonly method: string;
|
|
50
|
+
readonly url: string;
|
|
51
|
+
readonly status: number | null;
|
|
52
|
+
readonly statusText: string | null;
|
|
53
|
+
readonly resourceType: string | null;
|
|
54
|
+
readonly durationMs: number | null;
|
|
55
|
+
readonly errorText: string | null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Failed/notable network rows for a session, oldest first (PRD §B3
|
|
59
|
+
* `get_session_network_errors`). `statusGte` defaults to 400; rows with a
|
|
60
|
+
* net-error string are always included.
|
|
61
|
+
*/
|
|
62
|
+
export declare function getNetworkErrors(db: Database, id: string, options?: {
|
|
63
|
+
statusGte?: number;
|
|
64
|
+
limit?: number;
|
|
65
|
+
}): NetworkErrorRow[];
|
|
66
|
+
/** Look up the events blob path + first-event ts for a session (for the walker tools). */
|
|
67
|
+
export declare function getSessionBlobRef(db: Database, id: string): {
|
|
68
|
+
blobPath: string | null;
|
|
69
|
+
startedAt: number;
|
|
70
|
+
} | undefined;
|
|
71
|
+
/** The ts of a single console event id (used by get_user_action_before_error). */
|
|
72
|
+
export declare function getConsoleEventTs(db: Database, id: string, errorId: number): number | undefined;
|
|
73
|
+
//# sourceMappingURL=queries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/mcp/queries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// SQL read helpers for the MCP tools that hit structured tables directly
|
|
2
|
+
// (sessions, console_events, network_events). These mirror @peekdev/cli's
|
|
3
|
+
// db.ts shapes so a `peek sessions export --format json` and the MCP
|
|
4
|
+
// `get_session_*` tools return interchangeable data (P2 PRD §B3). The console /
|
|
5
|
+
// network rows are pre-extracted by the native host, so these are fast indexed
|
|
6
|
+
// reads — only the event-level tools fall back to the gzipped blob walker.
|
|
7
|
+
/** Epoch-millis of an ISO-8601 timestamp; 0 if unparseable. */
|
|
8
|
+
function isoToMs(iso) {
|
|
9
|
+
if (!iso)
|
|
10
|
+
return 0;
|
|
11
|
+
const ms = Date.parse(iso);
|
|
12
|
+
return Number.isNaN(ms) ? 0 : ms;
|
|
13
|
+
}
|
|
14
|
+
/** Accurate `COUNT(*)` of error-level console rows for a session. */
|
|
15
|
+
export function countConsoleErrors(db, sessionId) {
|
|
16
|
+
return db
|
|
17
|
+
.prepare("SELECT COUNT(*) AS c FROM console_events WHERE session_id = ? AND level = 'error'")
|
|
18
|
+
.get(sessionId).c;
|
|
19
|
+
}
|
|
20
|
+
/** Accurate `COUNT(*)` of failed/notable network rows (status >= 400 or net error). */
|
|
21
|
+
export function countNetworkErrors(db, sessionId) {
|
|
22
|
+
return db
|
|
23
|
+
.prepare('SELECT COUNT(*) AS c FROM network_events WHERE session_id = ? AND (status >= 400 OR error_text IS NOT NULL)')
|
|
24
|
+
.get(sessionId).c;
|
|
25
|
+
}
|
|
26
|
+
function errorCountFor(db, sessionId) {
|
|
27
|
+
return countConsoleErrors(db, sessionId) + countNetworkErrors(db, sessionId);
|
|
28
|
+
}
|
|
29
|
+
function toSummaryRow(db, r) {
|
|
30
|
+
const startedAt = isoToMs(r.created_at);
|
|
31
|
+
const endedAt = isoToMs(r.updated_at);
|
|
32
|
+
return {
|
|
33
|
+
id: r.id,
|
|
34
|
+
origin: r.origin,
|
|
35
|
+
url: r.url,
|
|
36
|
+
title: r.title,
|
|
37
|
+
startedAt,
|
|
38
|
+
durationMs: Math.max(0, endedAt - startedAt),
|
|
39
|
+
errorCount: errorCountFor(db, r.id),
|
|
40
|
+
eventCount: r.event_count,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* List the most-recently-updated sessions, newest first (PRD §B3
|
|
45
|
+
* `list_recent_sessions`). Default limit 10; capped to the schema's
|
|
46
|
+
* `origin`-filtered subset when `origin` is given.
|
|
47
|
+
*/
|
|
48
|
+
export function listRecentSessions(db, options = {}) {
|
|
49
|
+
const limit = options.limit ?? 10;
|
|
50
|
+
const params = [];
|
|
51
|
+
let sql = 'SELECT * FROM sessions';
|
|
52
|
+
if (options.origin !== undefined) {
|
|
53
|
+
sql += ' WHERE origin = ?';
|
|
54
|
+
params.push(options.origin);
|
|
55
|
+
}
|
|
56
|
+
sql += ' ORDER BY updated_at DESC, created_at DESC LIMIT ?';
|
|
57
|
+
params.push(limit);
|
|
58
|
+
const rows = db.prepare(sql).all(...params);
|
|
59
|
+
return rows.map((r) => toSummaryRow(db, r));
|
|
60
|
+
}
|
|
61
|
+
/** One session's summary row, or undefined if no such id. */
|
|
62
|
+
export function getSessionSummaryRow(db, id) {
|
|
63
|
+
const row = db.prepare('SELECT * FROM sessions WHERE id = ?').get(id);
|
|
64
|
+
return row ? toSummaryRow(db, row) : undefined;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Console error rows for a session, oldest first (PRD §B3
|
|
68
|
+
* `get_session_console_errors`). `since` filters to ts >= it; default level
|
|
69
|
+
* filter is `error` only (the tool name says "errors").
|
|
70
|
+
*/
|
|
71
|
+
export function getConsoleErrors(db, id, options = {}) {
|
|
72
|
+
const limit = options.limit ?? 50;
|
|
73
|
+
const params = [id];
|
|
74
|
+
let sql = 'SELECT id, ts_ms, level, message, stack FROM console_events WHERE session_id = ?';
|
|
75
|
+
if (options.level !== undefined) {
|
|
76
|
+
sql += ' AND level = ?';
|
|
77
|
+
params.push(options.level);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
sql += " AND level = 'error'";
|
|
81
|
+
}
|
|
82
|
+
if (options.since !== undefined) {
|
|
83
|
+
sql += ' AND ts_ms >= ?';
|
|
84
|
+
params.push(options.since);
|
|
85
|
+
}
|
|
86
|
+
sql += ' ORDER BY ts_ms ASC LIMIT ?';
|
|
87
|
+
params.push(limit);
|
|
88
|
+
const rows = db.prepare(sql).all(...params);
|
|
89
|
+
return rows.map((r) => ({
|
|
90
|
+
id: r.id,
|
|
91
|
+
ts: r.ts_ms,
|
|
92
|
+
level: r.level,
|
|
93
|
+
message: r.message,
|
|
94
|
+
stack: r.stack,
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Failed/notable network rows for a session, oldest first (PRD §B3
|
|
99
|
+
* `get_session_network_errors`). `statusGte` defaults to 400; rows with a
|
|
100
|
+
* net-error string are always included.
|
|
101
|
+
*/
|
|
102
|
+
export function getNetworkErrors(db, id, options = {}) {
|
|
103
|
+
const statusGte = options.statusGte ?? 400;
|
|
104
|
+
const limit = options.limit ?? 50;
|
|
105
|
+
const rows = db
|
|
106
|
+
.prepare(`SELECT id, ts_ms, method, url, status, status_text, resource_type, duration_ms, error_text
|
|
107
|
+
FROM network_events
|
|
108
|
+
WHERE session_id = ? AND (status >= ? OR error_text IS NOT NULL)
|
|
109
|
+
ORDER BY ts_ms ASC LIMIT ?`)
|
|
110
|
+
.all(id, statusGte, limit);
|
|
111
|
+
return rows.map((r) => ({
|
|
112
|
+
id: r.id,
|
|
113
|
+
ts: r.ts_ms,
|
|
114
|
+
method: r.method,
|
|
115
|
+
url: r.url,
|
|
116
|
+
status: r.status,
|
|
117
|
+
statusText: r.status_text,
|
|
118
|
+
resourceType: r.resource_type,
|
|
119
|
+
durationMs: r.duration_ms,
|
|
120
|
+
errorText: r.error_text,
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
/** Look up the events blob path + first-event ts for a session (for the walker tools). */
|
|
124
|
+
export function getSessionBlobRef(db, id) {
|
|
125
|
+
const row = db
|
|
126
|
+
.prepare('SELECT events_blob_path, created_at FROM sessions WHERE id = ?')
|
|
127
|
+
.get(id);
|
|
128
|
+
if (!row)
|
|
129
|
+
return undefined;
|
|
130
|
+
return { blobPath: row.events_blob_path, startedAt: isoToMs(row.created_at) };
|
|
131
|
+
}
|
|
132
|
+
/** The ts of a single console event id (used by get_user_action_before_error). */
|
|
133
|
+
export function getConsoleEventTs(db, id, errorId) {
|
|
134
|
+
const row = db
|
|
135
|
+
.prepare('SELECT ts_ms FROM console_events WHERE id = ? AND session_id = ?')
|
|
136
|
+
.get(errorId, id);
|
|
137
|
+
return row?.ts_ms;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/mcp/queries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The subset of `McpServer.server` this module depends on. Kept structurally
|
|
3
|
+
* loose (only the fields we read) so the SDK's richer `listRoots` return type
|
|
4
|
+
* (extra `_meta`, index signature) assigns cleanly under exactOptionalPropertyTypes.
|
|
5
|
+
*/
|
|
6
|
+
export interface RootsCapableServer {
|
|
7
|
+
getClientCapabilities(): {
|
|
8
|
+
roots?: unknown;
|
|
9
|
+
} | undefined;
|
|
10
|
+
listRoots(): Promise<{
|
|
11
|
+
roots: ReadonlyArray<{
|
|
12
|
+
uri: string;
|
|
13
|
+
}>;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
/** Resolved scope after consulting (or failing to consult) the client's roots. */
|
|
17
|
+
export interface RootsScope {
|
|
18
|
+
/**
|
|
19
|
+
* Origins (`scheme://host[:port]`) the session queries should be limited to,
|
|
20
|
+
* or `undefined` to mean "no scoping — all sessions" (the safe fallback when
|
|
21
|
+
* the client doesn't support roots, doesn't answer, or supplies roots from
|
|
22
|
+
* which no origin can be derived).
|
|
23
|
+
*/
|
|
24
|
+
readonly allowedOrigins: string[] | undefined;
|
|
25
|
+
/** Why we ended up with this scope — surfaced in logs / tests. */
|
|
26
|
+
readonly reason: 'no-roots-capability' | 'roots-timeout' | 'roots-error' | 'no-origins-derived' | 'scoped';
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Derive the origins peek should scope to from a set of client roots. Roots are
|
|
30
|
+
* usually `file://` project directories (e.g. `file:///Users/x/repo`), not web
|
|
31
|
+
* origins — so v1 derives origins only from roots that ARE http(s) URIs (a
|
|
32
|
+
* client that surfaces a dev-server URL as a root). `file://` roots yield no
|
|
33
|
+
* origin here (deriving localhost ports from package.json/vite config is a
|
|
34
|
+
* documented future enhancement, PRD §B5), so a file-only root set falls back
|
|
35
|
+
* to unscoped rather than scoping to nothing.
|
|
36
|
+
*/
|
|
37
|
+
export declare function deriveAllowedOrigins(roots: ReadonlyArray<{
|
|
38
|
+
uri: string;
|
|
39
|
+
}>): string[];
|
|
40
|
+
export interface ResolveRootsScopeOptions {
|
|
41
|
+
/** Timeout for `roots/list` before falling back (default 1000ms, Issue #3315). */
|
|
42
|
+
readonly timeoutMs?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Consult the client's roots (if advertised) and resolve the session scope,
|
|
46
|
+
* defensively timing out per claude-code Issue #3315. Never throws — every
|
|
47
|
+
* failure mode degrades to {@link UNSCOPED}.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveRootsScope(server: RootsCapableServer, options?: ResolveRootsScopeOptions): Promise<RootsScope>;
|
|
50
|
+
//# sourceMappingURL=roots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roots.d.ts","sourceRoot":"","sources":["../../src/mcp/roots.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,qBAAqB,IAAI;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;IACzD,SAAS,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,aAAa,CAAC;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CACjE;AAED,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9C,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EACX,qBAAqB,GACrB,eAAe,GACf,aAAa,GACb,oBAAoB,GACpB,QAAQ,CAAC;CACd;AAkCD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,MAAM,EAAE,CAapF;AAED,MAAM,WAAW,wBAAwB;IACvC,kFAAkF;IAClF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,UAAU,CAAC,CAyBrB"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// MCP Roots scoping (Task 3.14 / P2 PRD §B5). On `oninitialized` the server
|
|
2
|
+
// asks whether the client advertised the `roots` capability; if so it fetches
|
|
3
|
+
// the client's roots (project directories) and derives the origins peek should
|
|
4
|
+
// scope session queries to. Two defensive realities drive the design:
|
|
5
|
+
//
|
|
6
|
+
// 1. Anthropic claude-code Issue #3315 (Apr 2026): Claude Code advertises the
|
|
7
|
+
// `roots` capability but historically did NOT implement `roots/list` — a
|
|
8
|
+
// naive `await listRoots()` hangs forever. So we race it against a 1s
|
|
9
|
+
// timeout and fall back to "all sessions" (no scoping).
|
|
10
|
+
// 2. modelcontextprotocol/servers Issue #3602: the filesystem server
|
|
11
|
+
// *replaces* its allowed dirs with the client roots. peek instead treats
|
|
12
|
+
// roots as a SOFT filter over origins (v1) — see deriveAllowedOrigins.
|
|
13
|
+
//
|
|
14
|
+
// This module is transport-agnostic and side-effect-free: it takes the two
|
|
15
|
+
// Server methods it needs as inputs so it's trivially unit-testable.
|
|
16
|
+
/** The unscoped fallback. */
|
|
17
|
+
const UNSCOPED = (reason) => ({
|
|
18
|
+
allowedOrigins: undefined,
|
|
19
|
+
reason,
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Race a promise against a timeout. Resolves to the promise's value, or
|
|
23
|
+
* `{ timedOut: true }` after `ms`. The losing promise is left to settle
|
|
24
|
+
* (its result is ignored) — we never reject from the timeout path.
|
|
25
|
+
*/
|
|
26
|
+
async function withTimeout(promise, ms) {
|
|
27
|
+
let timer;
|
|
28
|
+
const timeout = new Promise((resolve) => {
|
|
29
|
+
timer = setTimeout(() => resolve({ timedOut: true }), ms);
|
|
30
|
+
// Don't keep the event loop alive solely for this timer.
|
|
31
|
+
timer.unref?.();
|
|
32
|
+
});
|
|
33
|
+
try {
|
|
34
|
+
const value = await Promise.race([
|
|
35
|
+
promise.then((v) => ({ timedOut: false, value: v })),
|
|
36
|
+
timeout,
|
|
37
|
+
]);
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
if (timer)
|
|
42
|
+
clearTimeout(timer);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Derive the origins peek should scope to from a set of client roots. Roots are
|
|
47
|
+
* usually `file://` project directories (e.g. `file:///Users/x/repo`), not web
|
|
48
|
+
* origins — so v1 derives origins only from roots that ARE http(s) URIs (a
|
|
49
|
+
* client that surfaces a dev-server URL as a root). `file://` roots yield no
|
|
50
|
+
* origin here (deriving localhost ports from package.json/vite config is a
|
|
51
|
+
* documented future enhancement, PRD §B5), so a file-only root set falls back
|
|
52
|
+
* to unscoped rather than scoping to nothing.
|
|
53
|
+
*/
|
|
54
|
+
export function deriveAllowedOrigins(roots) {
|
|
55
|
+
const origins = new Set();
|
|
56
|
+
for (const root of roots) {
|
|
57
|
+
try {
|
|
58
|
+
const url = new URL(root.uri);
|
|
59
|
+
if (url.protocol === 'http:' || url.protocol === 'https:') {
|
|
60
|
+
origins.add(url.origin);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Non-URL root — skip.
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return [...origins];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Consult the client's roots (if advertised) and resolve the session scope,
|
|
71
|
+
* defensively timing out per claude-code Issue #3315. Never throws — every
|
|
72
|
+
* failure mode degrades to {@link UNSCOPED}.
|
|
73
|
+
*/
|
|
74
|
+
export async function resolveRootsScope(server, options = {}) {
|
|
75
|
+
const timeoutMs = options.timeoutMs ?? 1000;
|
|
76
|
+
const caps = server.getClientCapabilities();
|
|
77
|
+
if (!caps?.roots) {
|
|
78
|
+
return UNSCOPED('no-roots-capability');
|
|
79
|
+
}
|
|
80
|
+
const raced = await withTimeout(server.listRoots(), timeoutMs).catch(() => ({
|
|
81
|
+
timedOut: false,
|
|
82
|
+
value: undefined,
|
|
83
|
+
}));
|
|
84
|
+
if (raced.timedOut) {
|
|
85
|
+
return UNSCOPED('roots-timeout');
|
|
86
|
+
}
|
|
87
|
+
const result = raced.value;
|
|
88
|
+
if (!result || !Array.isArray(result.roots)) {
|
|
89
|
+
return UNSCOPED('roots-error');
|
|
90
|
+
}
|
|
91
|
+
const allowedOrigins = deriveAllowedOrigins(result.roots);
|
|
92
|
+
if (allowedOrigins.length === 0) {
|
|
93
|
+
return UNSCOPED('no-origins-derived');
|
|
94
|
+
}
|
|
95
|
+
return { allowedOrigins, reason: 'scoped' };
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=roots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roots.js","sourceRoot":"","sources":["../../src/mcp/roots.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAC/E,sEAAsE;AACtE,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E,2EAA2E;AAC3E,6DAA6D;AAC7D,uEAAuE;AACvE,8EAA8E;AAC9E,4EAA4E;AAC5E,EAAE;AACF,2EAA2E;AAC3E,qEAAqE;AA8BrE,6BAA6B;AAC7B,MAAM,QAAQ,GAAG,CAAC,MAA4B,EAAc,EAAE,CAAC,CAAC;IAC9D,cAAc,EAAE,SAAS;IACzB,MAAM;CACP,CAAC,CAAC;AAEH;;;;GAIG;AACH,KAAK,UAAU,WAAW,CACxB,OAAmB,EACnB,EAAU;IAEV,IAAI,KAAgD,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAqB,CAAC,OAAO,EAAE,EAAE;QAC1D,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1D,yDAAyD;QACzD,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAc,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YAC7D,OAAO;SACR,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACf,CAAC;YAAS,CAAC;QACT,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAqC;IACxE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC1D,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AACtB,CAAC;AAOD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAA0B,EAC1B,UAAoC,EAAE;IAEtC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;IAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAC;IAC5C,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;QACjB,OAAO,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QAC1E,QAAQ,EAAE,KAAc;QACxB,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC,CAAC;IAEJ,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnB,OAAO,QAAQ,CAAC,eAAe,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC;IAC3B,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5C,OAAO,QAAQ,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,cAAc,GAAG,oBAAoB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1D,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { EventType, IncrementalSource, MouseInteractions, NodeType, } from '@cubenest/rrweb-core';
|
|
2
|
+
export type { eventWithTime, serializedNodeWithId, incrementalData, incrementalSnapshotEvent, fullSnapshotEvent, metaEvent, mouseInteractionData, inputData, mutationData, addedNodeMutation, attributeMutation, textMutation, } from '@cubenest/rrweb-core';
|
|
3
|
+
//# sourceMappingURL=rrweb-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rrweb-types.d.ts","sourceRoot":"","sources":["../../src/mcp/rrweb-types.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,QAAQ,GACT,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,wBAAwB,EACxB,iBAAiB,EACjB,SAAS,EACT,oBAAoB,EACpB,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,GACb,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// One local re-export point for the rrweb wire-format types + enums the event
|
|
2
|
+
// walker needs. Everything funnels through @cubenest/rrweb-core (the package
|
|
3
|
+
// that owns the vendored rrweb surface) so peek-mcp never depends on the
|
|
4
|
+
// PostHog rrweb-types package directly — if upstream shifts, rrweb-core is the
|
|
5
|
+
// single place that breaks (ADR-0002).
|
|
6
|
+
export { EventType, IncrementalSource, MouseInteractions, NodeType, } from '@cubenest/rrweb-core';
|
|
7
|
+
//# sourceMappingURL=rrweb-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rrweb-types.js","sourceRoot":"","sources":["../../src/mcp/rrweb-types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,6EAA6E;AAC7E,yEAAyE;AACzE,+EAA+E;AAC/E,uCAAuC;AAEvC,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,QAAQ,GACT,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type serializedNodeWithId } from './rrweb-types.js';
|
|
2
|
+
/** A serialized node plus its resolved parent, for ancestor walks. */
|
|
3
|
+
interface IndexedNode {
|
|
4
|
+
readonly node: serializedNodeWithId;
|
|
5
|
+
readonly parentId: number | null;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A flat index of a serialized snapshot tree: node id -> { node, parentId }.
|
|
9
|
+
* Built once per snapshot so selector derivation and DOM lookups are O(1) per
|
|
10
|
+
* id instead of re-walking the tree.
|
|
11
|
+
*/
|
|
12
|
+
export type NodeIndex = ReadonlyMap<number, IndexedNode>;
|
|
13
|
+
/**
|
|
14
|
+
* Max DOM nesting depth the offline walkers descend before stopping. Real
|
|
15
|
+
* browser DOMs are nowhere near this deep; the bound exists because this code
|
|
16
|
+
* ingests UNTRUSTED recordings — a crafted ~10k-deep tree would otherwise blow
|
|
17
|
+
* the call stack. Shared so the index builders and the serializer agree.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MAX_DOM_DEPTH = 1000;
|
|
20
|
+
/**
|
|
21
|
+
* Build a {@link NodeIndex} from a FullSnapshot's root serialized node. Nodes
|
|
22
|
+
* deeper than {@link MAX_DOM_DEPTH} are skipped (not indexed) rather than
|
|
23
|
+
* overflowing the stack on an adversarial blob.
|
|
24
|
+
*/
|
|
25
|
+
export declare function indexNodes(root: serializedNodeWithId): NodeIndex;
|
|
26
|
+
/** The serialized child nodes of a node, or `[]` for leaf/text/comment nodes. */
|
|
27
|
+
export declare function nodeChildren(node: serializedNodeWithId): serializedNodeWithId[];
|
|
28
|
+
/**
|
|
29
|
+
* Derive the most stable selector for a single node, ignoring ancestors:
|
|
30
|
+
* 1. `#id` (when the id looks static, not an obvious nonce)
|
|
31
|
+
* 2. `[data-testid="…"]` (or data-test / data-cy — test hooks)
|
|
32
|
+
* 3. `tag[name="…"]` (form controls)
|
|
33
|
+
* 4. `tag.class.class` (first two classes)
|
|
34
|
+
* 5. `tag`
|
|
35
|
+
* Returns `undefined` for non-element nodes.
|
|
36
|
+
*/
|
|
37
|
+
export declare function localSelector(node: serializedNodeWithId): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Heuristic: does a token look like a stable hook rather than a generated
|
|
40
|
+
* nonce? Rejects hashed/utility tokens (long hex-ish runs, CSS-module suffixes
|
|
41
|
+
* like `Button_x8Hk2`, emotion `css-1q2w3e`). Keeps short, word-y identifiers.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isStableToken(token: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Derive a full selector path for `id` within `index`, climbing ancestors until
|
|
46
|
+
* an id/test-hook anchor is hit (or the document root). Joins with `>` to keep
|
|
47
|
+
* the path specific and short. Returns `undefined` if `id` is missing or not an
|
|
48
|
+
* element. The result is a best-effort selector for human/agent consumption and
|
|
49
|
+
* Playwright scripts — not guaranteed unique on a live page, but stable enough
|
|
50
|
+
* for the recorded snapshot.
|
|
51
|
+
*/
|
|
52
|
+
export declare function selectorFor(index: NodeIndex, id: number): string | undefined;
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../src/mcp/selector.ts"],"names":[],"mappings":"AAUA,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAEvE,sEAAsE;AACtE,UAAU,WAAW;IACnB,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAEzD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,OAAO,CAAC;AAElC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,oBAAoB,GAAG,SAAS,CAWhE;AAED,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,IAAI,EAAE,oBAAoB,GAAG,oBAAoB,EAAE,CAM/E;AA8BD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAiC5E;AAOD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAWpD;AAwBD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAyC5E"}
|