@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,398 @@
|
|
|
1
|
+
// The shared rrweb stream walker — the heart of the event-level read tools.
|
|
2
|
+
//
|
|
3
|
+
// rrweb records a session as a FullSnapshot (the serialized DOM at capture
|
|
4
|
+
// start) followed by IncrementalSnapshot events (mutations, mouse interactions,
|
|
5
|
+
// input edits) and Meta events (navigations). To answer the MCP read tools we
|
|
6
|
+
// decode that stream once and offer three views over it:
|
|
7
|
+
//
|
|
8
|
+
// • user actions — clicks / inputs / navigations with timestamps +
|
|
9
|
+
// derived selectors (get_user_action_before_error,
|
|
10
|
+
// generate_playwright_repro).
|
|
11
|
+
// • DOM at a timestamp — the FullSnapshot's serialized tree with structural +
|
|
12
|
+
// attribute + text mutations applied up to T, rendered
|
|
13
|
+
// to an HTML-ish string (get_dom_snapshot). v1 scope:
|
|
14
|
+
// see reconstructDomAt's doc.
|
|
15
|
+
// • selector history — the timeline of attribute / text changes for a node
|
|
16
|
+
// matched by selector (query_dom_history).
|
|
17
|
+
//
|
|
18
|
+
// Everything works on the decoded `eventWithTime[]` with no live DOM, so it
|
|
19
|
+
// runs in plain Node (no jsdom) — matching ADR-0011's "thin local client".
|
|
20
|
+
import { EventType, IncrementalSource, MouseInteractions, NodeType, } from './rrweb-types.js';
|
|
21
|
+
import { MAX_DOM_DEPTH, indexNodes, nodeChildren, selectorFor, } from './selector.js';
|
|
22
|
+
function isFullSnapshot(e) {
|
|
23
|
+
return e.type === EventType.FullSnapshot;
|
|
24
|
+
}
|
|
25
|
+
function isIncremental(e) {
|
|
26
|
+
return e.type === EventType.IncrementalSnapshot;
|
|
27
|
+
}
|
|
28
|
+
function isMeta(e) {
|
|
29
|
+
return e.type === EventType.Meta;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Walk the stream and pull out user actions (clicks, input commits, page
|
|
33
|
+
* navigations) in chronological order. The selector for a click/input is
|
|
34
|
+
* derived from whichever FullSnapshot is in effect at that point (rebuilt as
|
|
35
|
+
* new FullSnapshots arrive), with added nodes folded into the index so
|
|
36
|
+
* interactions on dynamically-inserted elements still resolve.
|
|
37
|
+
*
|
|
38
|
+
* Mouse *moves*, scrolls, and non-Click interactions are intentionally dropped
|
|
39
|
+
* — they're noise for repro/explanation and blow the token budget.
|
|
40
|
+
*/
|
|
41
|
+
export function extractUserActions(events) {
|
|
42
|
+
const actions = [];
|
|
43
|
+
// The live node index, seeded by the latest FullSnapshot and grown by adds.
|
|
44
|
+
let index;
|
|
45
|
+
const resolveSelector = (id) => index ? selectorFor(index, id) : undefined;
|
|
46
|
+
for (const e of events) {
|
|
47
|
+
if (isFullSnapshot(e)) {
|
|
48
|
+
index = new Map(indexNodes(e.data.node));
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (isMeta(e)) {
|
|
52
|
+
const href = e.data.href;
|
|
53
|
+
if (typeof href === 'string' && href.length > 0) {
|
|
54
|
+
actions.push({ type: 'navigate', ts: e.timestamp, url: href, summary: `navigate ${href}` });
|
|
55
|
+
}
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (!isIncremental(e))
|
|
59
|
+
continue;
|
|
60
|
+
const data = e.data;
|
|
61
|
+
if (data.source === IncrementalSource.Mutation) {
|
|
62
|
+
// Keep the index current so interactions on inserted nodes resolve.
|
|
63
|
+
foldAddsIntoIndex(index, data.adds);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (data.source === IncrementalSource.MouseInteraction) {
|
|
67
|
+
const mi = data;
|
|
68
|
+
if (mi.type === MouseInteractions.Click || mi.type === MouseInteractions.DblClick) {
|
|
69
|
+
const selector = resolveSelector(mi.id);
|
|
70
|
+
actions.push({
|
|
71
|
+
type: 'click',
|
|
72
|
+
ts: e.timestamp,
|
|
73
|
+
...(selector !== undefined ? { selector } : {}),
|
|
74
|
+
summary: selector !== undefined ? `click ${selector}` : `click node#${mi.id}`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (data.source === IncrementalSource.Input) {
|
|
80
|
+
const input = data;
|
|
81
|
+
const selector = resolveSelector(input.id);
|
|
82
|
+
// rrweb already masks values per the recorder config; we surface as-is.
|
|
83
|
+
const value = typeof input.text === 'string' ? input.text : '';
|
|
84
|
+
actions.push({
|
|
85
|
+
type: 'input',
|
|
86
|
+
ts: e.timestamp,
|
|
87
|
+
...(selector !== undefined ? { selector } : {}),
|
|
88
|
+
value,
|
|
89
|
+
summary: selector !== undefined
|
|
90
|
+
? `input ${selector} = ${truncate(value, 40)}`
|
|
91
|
+
: `input node#${input.id} = ${truncate(value, 40)}`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return actions;
|
|
96
|
+
}
|
|
97
|
+
/** Fold a mutation's added nodes into the live index (best-effort, recursive). */
|
|
98
|
+
function foldAddsIntoIndex(index, adds) {
|
|
99
|
+
if (!index || !adds)
|
|
100
|
+
return;
|
|
101
|
+
for (const add of adds) {
|
|
102
|
+
const register = (node, parentId, depth) => {
|
|
103
|
+
index.set(node.id, { node, parentId });
|
|
104
|
+
if (depth >= MAX_DOM_DEPTH)
|
|
105
|
+
return;
|
|
106
|
+
for (const child of nodeChildren(node))
|
|
107
|
+
register(child, node.id, depth + 1);
|
|
108
|
+
};
|
|
109
|
+
register(add.node, add.parentId, 0);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** The user actions strictly before `errorTs`, most-recent-last, capped to `window`. */
|
|
113
|
+
export function userActionsBeforeError(events, errorTs, window = 10) {
|
|
114
|
+
const all = extractUserActions(events).filter((a) => a.ts <= errorTs);
|
|
115
|
+
return all.slice(Math.max(0, all.length - window));
|
|
116
|
+
}
|
|
117
|
+
export function reconstructDomAt(events, ts, selector) {
|
|
118
|
+
// Find the base FullSnapshot (latest at or before ts).
|
|
119
|
+
let baseIdx = -1;
|
|
120
|
+
for (let i = 0; i < events.length; i += 1) {
|
|
121
|
+
const e = events[i];
|
|
122
|
+
if (e && isFullSnapshot(e) && e.timestamp <= ts)
|
|
123
|
+
baseIdx = i;
|
|
124
|
+
}
|
|
125
|
+
if (baseIdx < 0)
|
|
126
|
+
return undefined;
|
|
127
|
+
const baseEvent = events[baseIdx];
|
|
128
|
+
// Deep clone so we can mutate without touching the caller's events. Use a
|
|
129
|
+
// depth-bounded clone (not structuredClone, which recurses and overflows the
|
|
130
|
+
// stack on an adversarial deeply-nested tree before any of our guards run).
|
|
131
|
+
const root = cloneNodeBounded(baseEvent.data.node, 0);
|
|
132
|
+
const byId = new Map();
|
|
133
|
+
const parentOf = new Map();
|
|
134
|
+
(function indexMutable(node, parentId, depth) {
|
|
135
|
+
byId.set(node.id, node);
|
|
136
|
+
if (parentId !== null)
|
|
137
|
+
parentOf.set(node.id, parentId);
|
|
138
|
+
if (depth >= MAX_DOM_DEPTH)
|
|
139
|
+
return;
|
|
140
|
+
for (const child of nodeChildren(node))
|
|
141
|
+
indexMutable(child, node.id, depth + 1);
|
|
142
|
+
})(root, null, 0);
|
|
143
|
+
let mutationsApplied = 0;
|
|
144
|
+
for (let i = baseIdx + 1; i < events.length; i += 1) {
|
|
145
|
+
const e = events[i];
|
|
146
|
+
if (!e || e.timestamp > ts)
|
|
147
|
+
break;
|
|
148
|
+
if (!isIncremental(e))
|
|
149
|
+
continue;
|
|
150
|
+
const data = e.data;
|
|
151
|
+
if (data.source !== IncrementalSource.Mutation)
|
|
152
|
+
continue;
|
|
153
|
+
applyMutation(data, byId, parentOf);
|
|
154
|
+
mutationsApplied += 1;
|
|
155
|
+
}
|
|
156
|
+
// Optionally scope to the first node matching `selector`.
|
|
157
|
+
let renderRoot = root;
|
|
158
|
+
if (selector !== undefined) {
|
|
159
|
+
const match = findBySelector(root, byId, selector);
|
|
160
|
+
if (match)
|
|
161
|
+
renderRoot = match;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
baseSnapshotTs: baseEvent.timestamp,
|
|
165
|
+
mutationsApplied,
|
|
166
|
+
root: renderRoot,
|
|
167
|
+
html: serializeNode(renderRoot),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Depth-bounded deep clone of a serialized node. Stops cloning children past
|
|
172
|
+
* {@link MAX_DOM_DEPTH} (the truncated node keeps its own scalar fields but
|
|
173
|
+
* loses descendants), so it never overflows the stack on an adversarial
|
|
174
|
+
* deeply-nested subtree — unlike `structuredClone`, which recurses internally.
|
|
175
|
+
* Attribute objects are shallow-copied (flat string maps, never nested).
|
|
176
|
+
*/
|
|
177
|
+
function cloneNodeBounded(node, depth) {
|
|
178
|
+
const src = node;
|
|
179
|
+
const clone = { ...src };
|
|
180
|
+
if (src.attributes)
|
|
181
|
+
clone.attributes = { ...src.attributes };
|
|
182
|
+
const children = nodeChildren(node);
|
|
183
|
+
if (children.length > 0) {
|
|
184
|
+
clone.childNodes =
|
|
185
|
+
depth >= MAX_DOM_DEPTH ? [] : children.map((c) => cloneNodeBounded(c, depth + 1));
|
|
186
|
+
}
|
|
187
|
+
return clone;
|
|
188
|
+
}
|
|
189
|
+
/** Apply a single mutation event to the in-memory serialized tree. */
|
|
190
|
+
function applyMutation(m, byId, parentOf) {
|
|
191
|
+
// Removes first (rrweb applies removes, then adds, then attrs/texts).
|
|
192
|
+
for (const r of m.removes ?? []) {
|
|
193
|
+
const parent = byId.get(r.parentId);
|
|
194
|
+
if (parent && Array.isArray(parent.childNodes)) {
|
|
195
|
+
parent.childNodes = parent.childNodes.filter((c) => c.id !== r.id);
|
|
196
|
+
}
|
|
197
|
+
byId.delete(r.id);
|
|
198
|
+
parentOf.delete(r.id);
|
|
199
|
+
}
|
|
200
|
+
for (const a of m.adds ?? []) {
|
|
201
|
+
const parent = byId.get(a.parentId);
|
|
202
|
+
if (!parent)
|
|
203
|
+
continue;
|
|
204
|
+
if (!Array.isArray(parent.childNodes))
|
|
205
|
+
parent.childNodes = [];
|
|
206
|
+
const clone = cloneNodeBounded(a.node, 0);
|
|
207
|
+
// Insert before `nextId` when present, else append.
|
|
208
|
+
if (a.nextId !== null && a.nextId !== undefined) {
|
|
209
|
+
const at = parent.childNodes.findIndex((c) => c.id === a.nextId);
|
|
210
|
+
if (at >= 0)
|
|
211
|
+
parent.childNodes.splice(at, 0, clone);
|
|
212
|
+
else
|
|
213
|
+
parent.childNodes.push(clone);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
parent.childNodes.push(clone);
|
|
217
|
+
}
|
|
218
|
+
// Register the added subtree (depth-bounded against adversarial nesting).
|
|
219
|
+
(function register(node, parentId, depth) {
|
|
220
|
+
byId.set(node.id, node);
|
|
221
|
+
parentOf.set(node.id, parentId);
|
|
222
|
+
if (depth >= MAX_DOM_DEPTH)
|
|
223
|
+
return;
|
|
224
|
+
for (const child of nodeChildren(node))
|
|
225
|
+
register(child, node.id, depth + 1);
|
|
226
|
+
})(clone, parent.id, 0);
|
|
227
|
+
}
|
|
228
|
+
for (const at of m.attributes ?? []) {
|
|
229
|
+
const node = byId.get(at.id);
|
|
230
|
+
if (!node)
|
|
231
|
+
continue;
|
|
232
|
+
if (!node.attributes)
|
|
233
|
+
node.attributes = {};
|
|
234
|
+
for (const [key, value] of Object.entries(at.attributes)) {
|
|
235
|
+
if (value === null)
|
|
236
|
+
delete node.attributes[key];
|
|
237
|
+
else
|
|
238
|
+
node.attributes[key] = value;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
for (const t of m.texts ?? []) {
|
|
242
|
+
const node = byId.get(t.id);
|
|
243
|
+
if (node)
|
|
244
|
+
node.textContent = t.value ?? '';
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/** Find the first node matching `selector` by re-deriving selectors from the tree. */
|
|
248
|
+
function findBySelector(root, byId, selector) {
|
|
249
|
+
// Rebuild a NodeIndex over the (mutated) tree and compare derived selectors.
|
|
250
|
+
const index = indexNodes(root);
|
|
251
|
+
for (const [id, node] of byId) {
|
|
252
|
+
const derived = selectorFor(index, id);
|
|
253
|
+
if (derived === selector)
|
|
254
|
+
return node;
|
|
255
|
+
}
|
|
256
|
+
// Fallback: match the trailing segment (e.g. "#submit") loosely.
|
|
257
|
+
const tail = selector.split('>').pop()?.trim();
|
|
258
|
+
if (tail) {
|
|
259
|
+
for (const [id, node] of byId) {
|
|
260
|
+
const derived = selectorFor(index, id);
|
|
261
|
+
if (derived?.endsWith(tail))
|
|
262
|
+
return node;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Render a serialized node tree to an HTML-ish string (lightweight, not
|
|
269
|
+
* spec-perfect). Stops descending past {@link MAX_DOM_DEPTH} — emitting a
|
|
270
|
+
* truncation marker instead of recursing — so an adversarial deeply-nested
|
|
271
|
+
* recording can't overflow the stack (this code ingests untrusted blobs).
|
|
272
|
+
*/
|
|
273
|
+
export function serializeNode(node, depth = 0) {
|
|
274
|
+
const n = node;
|
|
275
|
+
switch (node.type) {
|
|
276
|
+
case NodeType.Document: {
|
|
277
|
+
if (depth >= MAX_DOM_DEPTH)
|
|
278
|
+
return '<!-- [truncated: max depth] -->';
|
|
279
|
+
return nodeChildren(node)
|
|
280
|
+
.map((c) => serializeNode(c, depth + 1))
|
|
281
|
+
.join('');
|
|
282
|
+
}
|
|
283
|
+
case NodeType.DocumentType: {
|
|
284
|
+
const dt = node;
|
|
285
|
+
return `<!DOCTYPE ${dt.name}>`;
|
|
286
|
+
}
|
|
287
|
+
case NodeType.Text: {
|
|
288
|
+
return n.textContent ?? '';
|
|
289
|
+
}
|
|
290
|
+
case NodeType.CDATA:
|
|
291
|
+
return '';
|
|
292
|
+
case NodeType.Comment:
|
|
293
|
+
return `<!--${n.textContent ?? ''}-->`;
|
|
294
|
+
case NodeType.Element: {
|
|
295
|
+
const el = node;
|
|
296
|
+
const tag = el.tagName.toLowerCase();
|
|
297
|
+
const attrs = renderAttributes(n.attributes ?? {});
|
|
298
|
+
if (VOID_ELEMENTS.has(tag))
|
|
299
|
+
return `<${tag}${attrs}>`;
|
|
300
|
+
if (depth >= MAX_DOM_DEPTH) {
|
|
301
|
+
return `<${tag}${attrs}><!-- [truncated: max depth] --></${tag}>`;
|
|
302
|
+
}
|
|
303
|
+
const children = nodeChildren(node)
|
|
304
|
+
.map((c) => serializeNode(c, depth + 1))
|
|
305
|
+
.join('');
|
|
306
|
+
return `<${tag}${attrs}>${children}</${tag}>`;
|
|
307
|
+
}
|
|
308
|
+
default:
|
|
309
|
+
return '';
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const VOID_ELEMENTS = new Set([
|
|
313
|
+
'area',
|
|
314
|
+
'base',
|
|
315
|
+
'br',
|
|
316
|
+
'col',
|
|
317
|
+
'embed',
|
|
318
|
+
'hr',
|
|
319
|
+
'img',
|
|
320
|
+
'input',
|
|
321
|
+
'link',
|
|
322
|
+
'meta',
|
|
323
|
+
'param',
|
|
324
|
+
'source',
|
|
325
|
+
'track',
|
|
326
|
+
'wbr',
|
|
327
|
+
]);
|
|
328
|
+
function renderAttributes(attrs) {
|
|
329
|
+
const parts = [];
|
|
330
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
331
|
+
if (value === false || value === null || value === undefined)
|
|
332
|
+
continue;
|
|
333
|
+
if (value === true) {
|
|
334
|
+
parts.push(` ${key}`);
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
const str = String(value).replace(/"/g, '"');
|
|
338
|
+
parts.push(` ${key}="${str}"`);
|
|
339
|
+
}
|
|
340
|
+
return parts.join('');
|
|
341
|
+
}
|
|
342
|
+
export function queryDomHistory(events, selector, options = {}) {
|
|
343
|
+
const limit = options.limit ?? 100;
|
|
344
|
+
// Resolve the target id from the first FullSnapshot.
|
|
345
|
+
const fullSnapshot = events.find(isFullSnapshot);
|
|
346
|
+
if (!fullSnapshot)
|
|
347
|
+
return [];
|
|
348
|
+
const index = indexNodes(fullSnapshot.data.node);
|
|
349
|
+
let targetId;
|
|
350
|
+
for (const [id] of index) {
|
|
351
|
+
if (selectorFor(index, id) === selector) {
|
|
352
|
+
targetId = id;
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (targetId === undefined)
|
|
357
|
+
return [];
|
|
358
|
+
const wantAttr = options.op !== 'innerText';
|
|
359
|
+
const wantText = options.op !== 'attributeChanges';
|
|
360
|
+
const changes = [];
|
|
361
|
+
for (const e of events) {
|
|
362
|
+
if (!isIncremental(e))
|
|
363
|
+
continue;
|
|
364
|
+
const data = e.data;
|
|
365
|
+
if (data.source !== IncrementalSource.Mutation)
|
|
366
|
+
continue;
|
|
367
|
+
const m = data;
|
|
368
|
+
if (wantAttr) {
|
|
369
|
+
for (const at of m.attributes ?? []) {
|
|
370
|
+
if (at.id !== targetId)
|
|
371
|
+
continue;
|
|
372
|
+
for (const [key, value] of Object.entries(at.attributes)) {
|
|
373
|
+
changes.push({
|
|
374
|
+
ts: e.timestamp,
|
|
375
|
+
op: 'attribute',
|
|
376
|
+
attribute: key,
|
|
377
|
+
value: value === null ? null : String(value),
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (wantText) {
|
|
383
|
+
for (const t of m.texts ?? []) {
|
|
384
|
+
// Text mutations target the text node; also surface direct text-child
|
|
385
|
+
// edits whose parent is the target (common for innerText changes).
|
|
386
|
+
const parentId = index.get(t.id)?.parentId;
|
|
387
|
+
if (t.id === targetId || parentId === targetId) {
|
|
388
|
+
changes.push({ ts: e.timestamp, op: 'text', value: t.value ?? null });
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return changes.slice(0, limit);
|
|
394
|
+
}
|
|
395
|
+
function truncate(s, max) {
|
|
396
|
+
return s.length <= max ? s : `${s.slice(0, max)}…`;
|
|
397
|
+
}
|
|
398
|
+
//# sourceMappingURL=event-walker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-walker.js","sourceRoot":"","sources":["../../src/mcp/event-walker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { RequestRegistry, type RequestRegistryDeps } from '../native-host/request-registry.js';
|
|
2
|
+
import type { Action } from './action-schema.js';
|
|
3
|
+
/** Input the MCP tool handler hands the bridge. */
|
|
4
|
+
export interface HostActionRequest {
|
|
5
|
+
/** 'execute_action' | 'request_authorization' — picks audit shape + UX. */
|
|
6
|
+
readonly tool: 'execute_action' | 'request_authorization';
|
|
7
|
+
readonly sessionId: string;
|
|
8
|
+
readonly action: Action;
|
|
9
|
+
/** MCP client name (from clientInfo). */
|
|
10
|
+
readonly client: string;
|
|
11
|
+
/**
|
|
12
|
+
* Time the bridge waits before failing the await (5min default — longer
|
|
13
|
+
* than any plausible Level-3 banner decision). Defaults applied at the
|
|
14
|
+
* call site, not here, so different tools can use different budgets.
|
|
15
|
+
*/
|
|
16
|
+
readonly timeoutMs?: number;
|
|
17
|
+
/**
|
|
18
|
+
* A pre-existing confirmation token from a prior `request_authorization`
|
|
19
|
+
* call. Only meaningful for `tool === 'execute_action'`: the host can use
|
|
20
|
+
* it to skip the banner step. NULL/undefined → no token (auth still happens).
|
|
21
|
+
*/
|
|
22
|
+
readonly confirmToken?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Reply the bridge yields to the MCP tool handler. */
|
|
25
|
+
export interface HostActionResponse {
|
|
26
|
+
/** verdict + result from the SW (see action-protocol.ts ActionResultMessage). */
|
|
27
|
+
readonly verdict: 'allow' | 'deny';
|
|
28
|
+
readonly result: 'ok' | 'denied' | 'error';
|
|
29
|
+
readonly approver: 'user' | 'allow-list-match' | 'level-4-auto';
|
|
30
|
+
readonly approvalMs?: number;
|
|
31
|
+
readonly destructiveTerm?: string;
|
|
32
|
+
readonly details?: unknown;
|
|
33
|
+
readonly error?: string;
|
|
34
|
+
/**
|
|
35
|
+
* For `request_authorization`: a one-shot token the AI then passes to
|
|
36
|
+
* `execute_action`. Opaque; the host validates.
|
|
37
|
+
*/
|
|
38
|
+
readonly confirmToken?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The bridge contract. The MCP tool handler awaits this; an implementation
|
|
42
|
+
* relays the request to the SW + waits for the verdict.
|
|
43
|
+
*/
|
|
44
|
+
export interface HostBridge {
|
|
45
|
+
request(req: HostActionRequest): Promise<HostActionResponse>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Default placeholder used when the IPC layer hasn't been wired in this
|
|
49
|
+
* process (e.g. an MCP server started without a co-running native host).
|
|
50
|
+
*
|
|
51
|
+
* Every act-tool call resolves with `denied` + a clear error message so the
|
|
52
|
+
* AI sees a structured failure rather than the tool throwing. The audit log
|
|
53
|
+
* still records the attempt at the tool-handler layer.
|
|
54
|
+
*/
|
|
55
|
+
export declare class MissingHostBridge implements HostBridge {
|
|
56
|
+
#private;
|
|
57
|
+
constructor(reason?: string);
|
|
58
|
+
request(_req: HostActionRequest): Promise<HostActionResponse>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A bridge backed by a {@link RequestRegistry}. The MCP tool handler's call
|
|
62
|
+
* registers a pending request; tests (or a future IPC implementation) call
|
|
63
|
+
* `resolveRequest` / `rejectRequest` to drive the reply. Used directly in
|
|
64
|
+
* `server.test.ts` to exercise the act-tool handlers without real IPC.
|
|
65
|
+
*/
|
|
66
|
+
export declare class RegistryBackedHostBridge implements HostBridge {
|
|
67
|
+
#private;
|
|
68
|
+
/** FIFO queue of {id, req} pairs awaiting resolution — exposed for tests. */
|
|
69
|
+
readonly pending: Array<{
|
|
70
|
+
id: string;
|
|
71
|
+
req: HostActionRequest;
|
|
72
|
+
}>;
|
|
73
|
+
constructor(registry?: RequestRegistry, deps?: RequestRegistryDeps);
|
|
74
|
+
request(req: HostActionRequest): Promise<HostActionResponse>;
|
|
75
|
+
/** Test helper: resolve the first pending request. */
|
|
76
|
+
resolveNext(payload: HostActionResponse): boolean;
|
|
77
|
+
/** Test helper: reject the first pending request. */
|
|
78
|
+
rejectNext(reason: unknown): boolean;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=host-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-bridge.d.ts","sourceRoot":"","sources":["../../src/mcp/host-bridge.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAE,eAAe,EAAE,KAAK,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC/F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAKjD,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,uBAAuB,CAAC;IAC1D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,uDAAuD;AACvD,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,cAAc,CAAC;IAChE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC9D;AAED;;;;;;;GAOG;AACH,qBAAa,iBAAkB,YAAW,UAAU;;gBAEtC,MAAM,SAAqD;IAGjE,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAQpE;AAED;;;;;GAKG;AACH,qBAAa,wBAAyB,YAAW,UAAU;;IAEzD,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,iBAAiB,CAAA;KAAE,CAAC,CAAM;gBAEzD,QAAQ,CAAC,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,mBAAmB;IAI5D,OAAO,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAQlE,sDAAsD;IACtD,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO;IAMjD,qDAAqD;IACrD,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;CAKrC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// MCP-process ↔ native-host-process bridge (Task 3.24).
|
|
2
|
+
//
|
|
3
|
+
// Architecture note (and an HONEST design boundary):
|
|
4
|
+
//
|
|
5
|
+
// • The `peek-mcp` binary serves TWO roles via argv dispatch (see
|
|
6
|
+
// src/index.ts): the **native host** process (owns ~/.peek/sessions.db
|
|
7
|
+
// and the chrome.runtime.connectNative port), and the **MCP server**
|
|
8
|
+
// process (an AI client like Cursor spawns it over stdio).
|
|
9
|
+
// • For act-tool execution, the MCP server has to TELL the native host
|
|
10
|
+
// "ask the SW to do X". Two processes — they need IPC.
|
|
11
|
+
// • The two processes share ~/.peek/. The simplest cross-platform IPC for
|
|
12
|
+
// a local-only design is a Unix domain socket on macOS/Linux (`~/.peek/
|
|
13
|
+
// host.sock`) and a named pipe on Windows. That bridge lives outside
|
|
14
|
+
// this chunk's scope — it's part of the action-execution E2E that the
|
|
15
|
+
// brief explicitly marks as E2E-deferred.
|
|
16
|
+
//
|
|
17
|
+
// This module defines:
|
|
18
|
+
// 1. The `HostBridge` interface every layer above calls — the seam
|
|
19
|
+
// action-tool handlers depend on. PURE: in/out promises.
|
|
20
|
+
// 2. A {@link MissingHostBridge} default that throws a clear "bridge not
|
|
21
|
+
// wired in this process" error. Used until the IPC implementation
|
|
22
|
+
// lands; lets the MCP server CONSTRUCT cleanly + lets tests inject
|
|
23
|
+
// a fake.
|
|
24
|
+
// 3. A {@link RegistryBackedHostBridge} test/integration helper that
|
|
25
|
+
// wraps a {@link RequestRegistry} so tests can simulate the host
|
|
26
|
+
// side without real IPC.
|
|
27
|
+
//
|
|
28
|
+
// When the IPC layer lands (3d-4 or 3e) we add a concrete
|
|
29
|
+
// `LocalSocketHostBridge` here; nothing else changes.
|
|
30
|
+
import { RequestRegistry } from '../native-host/request-registry.js';
|
|
31
|
+
// 5 minutes — longer than any plausible Level-3 banner-decision window.
|
|
32
|
+
const DEFAULT_BRIDGE_TIMEOUT_MS = 5 * 60_000;
|
|
33
|
+
/**
|
|
34
|
+
* Default placeholder used when the IPC layer hasn't been wired in this
|
|
35
|
+
* process (e.g. an MCP server started without a co-running native host).
|
|
36
|
+
*
|
|
37
|
+
* Every act-tool call resolves with `denied` + a clear error message so the
|
|
38
|
+
* AI sees a structured failure rather than the tool throwing. The audit log
|
|
39
|
+
* still records the attempt at the tool-handler layer.
|
|
40
|
+
*/
|
|
41
|
+
export class MissingHostBridge {
|
|
42
|
+
#reason;
|
|
43
|
+
constructor(reason = 'native-host bridge not wired in this MCP process') {
|
|
44
|
+
this.#reason = reason;
|
|
45
|
+
}
|
|
46
|
+
async request(_req) {
|
|
47
|
+
return {
|
|
48
|
+
verdict: 'deny',
|
|
49
|
+
result: 'denied',
|
|
50
|
+
approver: 'user',
|
|
51
|
+
error: this.#reason,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A bridge backed by a {@link RequestRegistry}. The MCP tool handler's call
|
|
57
|
+
* registers a pending request; tests (or a future IPC implementation) call
|
|
58
|
+
* `resolveRequest` / `rejectRequest` to drive the reply. Used directly in
|
|
59
|
+
* `server.test.ts` to exercise the act-tool handlers without real IPC.
|
|
60
|
+
*/
|
|
61
|
+
export class RegistryBackedHostBridge {
|
|
62
|
+
#registry;
|
|
63
|
+
/** FIFO queue of {id, req} pairs awaiting resolution — exposed for tests. */
|
|
64
|
+
pending = [];
|
|
65
|
+
constructor(registry, deps) {
|
|
66
|
+
this.#registry = registry ?? new RequestRegistry(deps);
|
|
67
|
+
}
|
|
68
|
+
async request(req) {
|
|
69
|
+
const { id, response } = this.#registry.create(req.timeoutMs ?? DEFAULT_BRIDGE_TIMEOUT_MS);
|
|
70
|
+
this.pending.push({ id, req });
|
|
71
|
+
return response;
|
|
72
|
+
}
|
|
73
|
+
/** Test helper: resolve the first pending request. */
|
|
74
|
+
resolveNext(payload) {
|
|
75
|
+
const entry = this.pending.shift();
|
|
76
|
+
if (!entry)
|
|
77
|
+
return false;
|
|
78
|
+
return this.#registry.resolve(entry.id, payload);
|
|
79
|
+
}
|
|
80
|
+
/** Test helper: reject the first pending request. */
|
|
81
|
+
rejectNext(reason) {
|
|
82
|
+
const entry = this.pending.shift();
|
|
83
|
+
if (!entry)
|
|
84
|
+
return false;
|
|
85
|
+
return this.#registry.reject(entry.id, reason);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=host-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-bridge.js","sourceRoot":"","sources":["../../src/mcp/host-bridge.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,EAAE;AACF,qDAAqD;AACrD,EAAE;AACF,oEAAoE;AACpE,2EAA2E;AAC3E,yEAAyE;AACzE,+DAA+D;AAC/D,yEAAyE;AACzE,2DAA2D;AAC3D,4EAA4E;AAC5E,4EAA4E;AAC5E,yEAAyE;AACzE,0EAA0E;AAC1E,8CAA8C;AAC9C,EAAE;AACF,yBAAyB;AACzB,uEAAuE;AACvE,gEAAgE;AAChE,6EAA6E;AAC7E,yEAAyE;AACzE,0EAA0E;AAC1E,iBAAiB;AACjB,yEAAyE;AACzE,wEAAwE;AACxE,gCAAgC;AAChC,EAAE;AACF,4DAA4D;AAC5D,wDAAwD;AAExD,OAAO,EAAE,eAAe,EAA4B,MAAM,oCAAoC,CAAC;AAG/F,wEAAwE;AACxE,MAAM,yBAAyB,GAAG,CAAC,GAAG,MAAM,CAAC;AAiD7C;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAiB;IACnB,OAAO,CAAS;IACzB,YAAY,MAAM,GAAG,kDAAkD;QACrE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,IAAuB;QACnC,OAAO;YACL,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,IAAI,CAAC,OAAO;SACpB,CAAC;IACJ,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,wBAAwB;IAC1B,SAAS,CAAkB;IACpC,6EAA6E;IACpE,OAAO,GAAkD,EAAE,CAAC;IAErE,YAAY,QAA0B,EAAE,IAA0B;QAChE,IAAI,CAAC,SAAS,GAAG,QAAQ,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAsB;QAClC,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAC5C,GAAG,CAAC,SAAS,IAAI,yBAAyB,CAC3C,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,sDAAsD;IACtD,WAAW,CAAC,OAA2B;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QACzB,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAED,qDAAqD;IACrD,UAAU,CAAC,MAAe;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QACzB,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type CreatePeekMcpServerOptions } from './server.js';
|
|
2
|
+
/**
|
|
3
|
+
* Start the peek MCP stdio server and resolve when the transport closes (the
|
|
4
|
+
* client disconnected — stdin EOF). The DB handle is released on close.
|
|
5
|
+
*/
|
|
6
|
+
export declare function runMcpServer(options?: CreatePeekMcpServerOptions): Promise<void>;
|
|
7
|
+
export { createPeekMcpServer, PEEK_MCP_TOOLS, SERVER_NAME, type CreatePeekMcpServerOptions, type PeekMcpServer, } from './server.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,0BAA0B,EAAuB,MAAM,aAAa,CAAC;AAEnF;;;GAGG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,0BAA+B,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB1F;AAED,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,KAAK,0BAA0B,EAC/B,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// MCP-mode entry (Task 3.11, ADR-0011): construct the peek MCP server and
|
|
2
|
+
// connect it over a single StdioServerTransport — the only transport peek
|
|
3
|
+
// exposes in v1. Invoked from src/index.ts when `peek-mcp` runs without
|
|
4
|
+
// --native-host and without a chrome-extension:// origin arg.
|
|
5
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
6
|
+
import { createPeekMcpServer } from './server.js';
|
|
7
|
+
/**
|
|
8
|
+
* Start the peek MCP stdio server and resolve when the transport closes (the
|
|
9
|
+
* client disconnected — stdin EOF). The DB handle is released on close.
|
|
10
|
+
*/
|
|
11
|
+
export async function runMcpServer(options = {}) {
|
|
12
|
+
const peek = createPeekMcpServer(options);
|
|
13
|
+
const transport = new StdioServerTransport();
|
|
14
|
+
// Resolve when the client disconnects (stdin EOF). McpServer.connect
|
|
15
|
+
// (Protocol.connect) PRESERVES and chains a pre-existing transport.onclose:
|
|
16
|
+
// it captures the current handler and invokes it before its own internal
|
|
17
|
+
// teardown. So we set it ONCE here, before connect — setting it again after
|
|
18
|
+
// connect would clobber the SDK's chained cleanup. The read-only DB handle is
|
|
19
|
+
// released in the same callback.
|
|
20
|
+
const closed = new Promise((resolve) => {
|
|
21
|
+
transport.onclose = () => {
|
|
22
|
+
peek.close();
|
|
23
|
+
resolve();
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
await peek.server.connect(transport);
|
|
27
|
+
// `connect` returns once the transport is started; the process stays alive on
|
|
28
|
+
// the open stdio streams until the client closes them. Block for that.
|
|
29
|
+
await closed;
|
|
30
|
+
}
|
|
31
|
+
export { createPeekMcpServer, PEEK_MCP_TOOLS, SERVER_NAME, } from './server.js';
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,0EAA0E;AAC1E,wEAAwE;AACxE,8DAA8D;AAE9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAmC,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEnF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAsC,EAAE;IACzE,MAAM,IAAI,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,qEAAqE;IACrE,4EAA4E;IAC5E,yEAAyE;IACzE,4EAA4E;IAC5E,8EAA8E;IAC9E,iCAAiC;IACjC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC3C,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;YACvB,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAErC,8EAA8E;IAC9E,uEAAuE;IACvE,MAAM,MAAM,CAAC;AACf,CAAC;AAED,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,WAAW,GAGZ,MAAM,aAAa,CAAC"}
|