@peekdev/mcp 0.1.0-alpha.12 → 0.1.0-alpha.13

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/README.md CHANGED
@@ -30,7 +30,7 @@ Read on if you're configuring the MCP server manually, building tooling against
30
30
  ## What this is NOT
31
31
 
32
32
  - Not a remote MCP server. Peek is **local-only**: stdio transport over a child-process pipe. There is no HTTP listener, no SSE endpoint, no remote auth. The MCP transport spec's Streamable HTTP variant is out of scope by design.
33
- - Not a write-by-default tool. Read tools are unauthenticated. The write tools (`execute_action`, `request_authorization`) are defined on the MCP surface and gated by the permission model + destructive blocklist + audit-log writer but the cross-process IPC that delivers them to the browser native host is **in development**. Calling `execute_action` against `peek-mcp@0.1.0-alpha.10` returns `bridge not wired in this MCP process`; peek is effectively read-only until that bridge lands.
33
+ - Not a write-by-default tool. Read tools are unauthenticated. The write tools (`execute_action`, `request_authorization`) are gated by the per-origin permission model (off by default) + the destructive blocklist + the audit-log writer. The cross-process IPC that delivers them to the browser native host (`LocalSocketHostBridge` ↔ `HostSocketServer` over `~/.peek/host.sock`) is now wired: at **Level 3** every action prompts the side-panel confirm banner before it runs. The real-browser MAIN-world dispatch + banner UX are covered by the Playwright E2E (`e2e/smoke.spec.ts`); the bridge, relay, dispatcher, and confirm logic are unit-tested.
34
34
  - Not a wrapper around Chrome DevTools Protocol. The server reads recorded events from SQLite; the extension owns capture. No live `chrome.debugger` access from the MCP server.
35
35
 
36
36
  ## Manual MCP-client config
@@ -95,7 +95,7 @@ At **Level 3** every `execute_action` call prompts the user via the side-panel b
95
95
 
96
96
  Every `execute_action` and `request_authorization` call is appended to `~/.peek/audit.log` (JSONL, mode 0600 — `peek audit log --json` prints it), including denied ones.
97
97
 
98
- **Shipped today (alpha.10) vs queued for a follow-up alpha:** the five-level model, the destructive blocklist, and the audit-log writer all ship — they're enforced inside `peek-mcp` and observable via `~/.peek/audit.log`. The cross-process IPC that lets `execute_action` actually fire a click in the browser (`LocalSocketHostBridge`) is **not yet wired**; calling `execute_action` against alpha.10 returns the `bridge not wired in this MCP process` error. Track the bridge work via [issues on the rrweb-stack repo](https://github.com/Cubenest/rrweb-stack/issues).
98
+ **The write-path is wired end to end:** the five-level model, the destructive blocklist, and the audit-log writer are enforced inside `peek-mcp` (observable via `~/.peek/audit.log`), and the cross-process IPC that lets `execute_action` fire a click in the browser now lands — a `LocalSocketHostBridge` (MCP process) `HostSocketServer` (native host) over `~/.peek/host.sock`, a MAIN-world action dispatcher (click/type/navigate/scroll), and a side-panel confirm banner. Both write levels are implemented: **Level 3** (act-with-confirm — every action prompts the banner) and **Level 4** (YOLO non-destructive actions auto-allow, destructive ones still prompt via the blocklist override). Both are opt-in per origin; the default stays Level 1 (read-only). Level 2 highlight and the remaining action types are queued. The real-browser dispatch + banner are covered by the Playwright E2E (`e2e/smoke.spec.ts`).
99
99
 
100
100
  ## Database
101
101
 
@@ -77,4 +77,53 @@ export declare class RegistryBackedHostBridge implements HostBridge {
77
77
  /** Test helper: reject the first pending request. */
78
78
  rejectNext(reason: unknown): boolean;
79
79
  }
80
+ /** The minimal duplex surface the bridge needs — injectable for tests. */
81
+ interface SocketLike {
82
+ write(data: string): void;
83
+ on(ev: string, h: (...a: unknown[]) => void): void;
84
+ end(): void;
85
+ /** Optional: decode inbound bytes as UTF-8 (real net.Socket has it). */
86
+ setEncoding?(encoding: string): void;
87
+ /**
88
+ * Optional: forcibly close the underlying socket (item G). Real net.Socket
89
+ * has it. `#reset` calls this so the orphaned socket doesn't stay open.
90
+ */
91
+ destroy?(): void;
92
+ /**
93
+ * Optional: detach the data/error/close listeners (item G) so a dropped
94
+ * socket doesn't leak its handlers. Real net.Socket (EventEmitter) has it.
95
+ */
96
+ removeAllListeners?(): void;
97
+ }
98
+ export interface LocalSocketHostBridgeDeps {
99
+ /** Override the socket / named-pipe path (tests + alternate PEEK_HOME). */
100
+ socketPath?: string;
101
+ /** Injectable connection factory; defaults to `net.connect(path)`. */
102
+ connect?: (path: string) => SocketLike;
103
+ /** Injectable correlation registry (tests). */
104
+ registry?: RequestRegistry;
105
+ /** Max bytes for a single inbound line before the connection is dropped. */
106
+ maxLineBytes?: number;
107
+ }
108
+ /**
109
+ * The production bridge: a newline-delimited-JSON client over the local
110
+ * `~/.peek/host.sock` (Unix domain socket) / `\\.\pipe\peek-host` (Windows).
111
+ *
112
+ * Wire frame (both directions): one JSON object per line, `\n`-terminated.
113
+ * client → host: { kind: 'act.request', id, payload: HostActionRequest }
114
+ * host → client: { kind: 'act.response', id, payload: HostActionResponse }
115
+ *
116
+ * Correlation reuses {@link RequestRegistry} (id ↔ pending promise) exactly like
117
+ * {@link RegistryBackedHostBridge}; only the transport differs. The connection
118
+ * is opened lazily on the first request and reused. A connect throw, a socket
119
+ * `error`, or a timeout all resolve to a structured `deny`/`error` response —
120
+ * fail-closed — so the MCP tool handler never sees a raw throw and the audit
121
+ * log still records the attempt.
122
+ */
123
+ export declare class LocalSocketHostBridge implements HostBridge {
124
+ #private;
125
+ constructor(deps?: LocalSocketHostBridgeDeps);
126
+ request(req: HostActionRequest): Promise<HostActionResponse>;
127
+ }
128
+ export {};
80
129
  //# sourceMappingURL=host-bridge.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"host-bridge.d.ts","sourceRoot":"","sources":["../../src/mcp/host-bridge.ts"],"names":[],"mappings":"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"}
@@ -27,7 +27,9 @@
27
27
  //
28
28
  // When the IPC layer lands (3d-4 or 3e) we add a concrete
29
29
  // `LocalSocketHostBridge` here; nothing else changes.
30
+ import * as net from 'node:net';
30
31
  import { RequestRegistry } from '../native-host/request-registry.js';
32
+ import { hostSocketPath } from '../native-host/socket-path.js';
31
33
  // 5 minutes — longer than any plausible Level-3 banner-decision window.
32
34
  const DEFAULT_BRIDGE_TIMEOUT_MS = 5 * 60_000;
33
35
  /**
@@ -85,4 +87,135 @@ export class RegistryBackedHostBridge {
85
87
  return this.#registry.reject(entry.id, reason);
86
88
  }
87
89
  }
90
+ /**
91
+ * Cap for a single newline-delimited frame on the bridge's read side. A
92
+ * well-behaved native host never sends a frame near this; the cap is a
93
+ * local-DoS guard so a malformed / hostile peer can't make the bridge buffer
94
+ * unbounded. 1 MiB mirrors the native-messaging host→ext frame cap.
95
+ */
96
+ const DEFAULT_MAX_LINE_BYTES = 1024 * 1024;
97
+ /**
98
+ * The production bridge: a newline-delimited-JSON client over the local
99
+ * `~/.peek/host.sock` (Unix domain socket) / `\\.\pipe\peek-host` (Windows).
100
+ *
101
+ * Wire frame (both directions): one JSON object per line, `\n`-terminated.
102
+ * client → host: { kind: 'act.request', id, payload: HostActionRequest }
103
+ * host → client: { kind: 'act.response', id, payload: HostActionResponse }
104
+ *
105
+ * Correlation reuses {@link RequestRegistry} (id ↔ pending promise) exactly like
106
+ * {@link RegistryBackedHostBridge}; only the transport differs. The connection
107
+ * is opened lazily on the first request and reused. A connect throw, a socket
108
+ * `error`, or a timeout all resolve to a structured `deny`/`error` response —
109
+ * fail-closed — so the MCP tool handler never sees a raw throw and the audit
110
+ * log still records the attempt.
111
+ */
112
+ export class LocalSocketHostBridge {
113
+ #registry;
114
+ #path;
115
+ #connect;
116
+ #maxLineBytes;
117
+ #sock;
118
+ #buf = '';
119
+ constructor(deps = {}) {
120
+ this.#registry = deps.registry ?? new RequestRegistry();
121
+ this.#path = deps.socketPath ?? hostSocketPath();
122
+ this.#connect = deps.connect ?? ((p) => net.connect(p));
123
+ this.#maxLineBytes = deps.maxLineBytes ?? DEFAULT_MAX_LINE_BYTES;
124
+ }
125
+ /**
126
+ * Drop the cached socket + clear the read buffer (reconnect on next request).
127
+ *
128
+ * Item G: DESTROY the live socket + remove its listeners BEFORE nulling the
129
+ * reference — otherwise the orphaned socket stays open with its
130
+ * data/error/close listeners attached (a socket + listener leak on every
131
+ * reconnect, and a late event from the dead socket could still mutate state).
132
+ * Item H: fail every in-flight request with a structured error so a closed /
133
+ * errored transport rejects awaiting tool calls PROMPTLY rather than leaving
134
+ * them hanging until the 5-minute registry timeout.
135
+ */
136
+ #reset(reason) {
137
+ const sock = this.#sock;
138
+ this.#sock = undefined;
139
+ this.#buf = '';
140
+ if (sock) {
141
+ try {
142
+ sock.removeAllListeners?.();
143
+ sock.destroy?.();
144
+ }
145
+ catch {
146
+ // A destroy/removeListeners throw must not mask the reset.
147
+ }
148
+ }
149
+ // Item H: reject all pending requests now (fail-closed) instead of waiting
150
+ // out the per-request timeout.
151
+ this.#registry.rejectAll(new Error(reason ?? 'peek: host socket connection closed'));
152
+ }
153
+ /** Open (once) + wire the framing reader. Throws if the connect throws. */
154
+ #ensure() {
155
+ if (this.#sock)
156
+ return this.#sock;
157
+ const s = this.#connect(this.#path);
158
+ // Item F: decode inbound bytes as UTF-8 (matches the server side) so a
159
+ // multibyte char split across two reads can't corrupt a frame. Real
160
+ // net.Socket has setEncoding; injected fakes may not.
161
+ s.setEncoding?.('utf8');
162
+ s.on('data', (chunk) => {
163
+ this.#buf += String(chunk);
164
+ // Item F: local-DoS guard. If the buffer grows past the cap WITHOUT a
165
+ // frame delimiter, a hostile/malformed peer is trying to make us buffer
166
+ // unbounded — drop the connection + clear the buffer (in-flight requests
167
+ // time out via the registry → fail-closed).
168
+ if (this.#buf.length > this.#maxLineBytes && this.#buf.indexOf('\n') < 0) {
169
+ this.#reset('peek: host socket frame exceeded the line cap');
170
+ return;
171
+ }
172
+ let nl;
173
+ // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic frame-drain loop
174
+ while ((nl = this.#buf.indexOf('\n')) >= 0) {
175
+ const line = this.#buf.slice(0, nl);
176
+ this.#buf = this.#buf.slice(nl + 1);
177
+ if (!line.trim())
178
+ continue;
179
+ if (line.length > this.#maxLineBytes)
180
+ continue; // oversized frame — drop it
181
+ try {
182
+ const m = JSON.parse(line);
183
+ if (m.kind === 'act.response' && typeof m.id === 'string') {
184
+ this.#registry.resolve(m.id, m.payload);
185
+ }
186
+ }
187
+ catch {
188
+ // Drop a malformed frame; a single bad line must not wedge the bridge.
189
+ }
190
+ }
191
+ });
192
+ s.on('error', (err) => {
193
+ // Item H: drop the cached socket so the next request reconnects AND fail
194
+ // every in-flight request now (via #reset → registry.rejectAll), instead
195
+ // of letting them hang until the 5-minute per-request timeout.
196
+ this.#reset(`peek: host socket error — ${err instanceof Error ? err.message : 'connection error'}`);
197
+ });
198
+ s.on('close', () => {
199
+ this.#reset('peek: host socket closed');
200
+ });
201
+ this.#sock = s;
202
+ return s;
203
+ }
204
+ async request(req) {
205
+ try {
206
+ const sock = this.#ensure();
207
+ const { id, response } = this.#registry.create(req.timeoutMs ?? DEFAULT_BRIDGE_TIMEOUT_MS);
208
+ sock.write(`${JSON.stringify({ kind: 'act.request', id, payload: req })}\n`);
209
+ return await response;
210
+ }
211
+ catch (err) {
212
+ return {
213
+ verdict: 'deny',
214
+ result: 'error',
215
+ approver: 'user',
216
+ error: err instanceof Error ? err.message : String(err),
217
+ };
218
+ }
219
+ }
220
+ }
88
221
  //# sourceMappingURL=host-bridge.js.map
@@ -1 +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"}
1
+ {"version":3,"file":"host-bridge.js","sourceRoot":"","sources":["../../src/mcp/host-bridge.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,12 @@ import { type CreatePeekMcpServerOptions } from './server.js';
2
2
  /**
3
3
  * Start the peek MCP stdio server and resolve when the transport closes (the
4
4
  * client disconnected — stdin EOF). The DB handle is released on close.
5
+ *
6
+ * In MCP mode we wire the {@link LocalSocketHostBridge} so act-tool calls reach
7
+ * the co-running native host over ~/.peek/host.sock (replacing the
8
+ * MissingHostBridge default that returns "bridge not wired"). The bridge
9
+ * fail-closes when the socket is unavailable — every act-tool call still goes
10
+ * through the audit log. A caller-supplied `hostBridge` (tests) wins.
5
11
  */
6
12
  export declare function runMcpServer(options?: CreatePeekMcpServerOptions): Promise<void>;
7
13
  export { createPeekMcpServer, PEEK_MCP_TOOLS, SERVER_NAME, type CreatePeekMcpServerOptions, type PeekMcpServer, } from './server.js';
@@ -1 +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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,0BAA0B,EAAuB,MAAM,aAAa,CAAC;AAEnF;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,0BAA+B,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB1F;AAED,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,KAAK,0BAA0B,EAC/B,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC"}
package/dist/mcp/index.js CHANGED
@@ -3,13 +3,23 @@
3
3
  // exposes in v1. Invoked from src/index.ts when `peek-mcp` runs without
4
4
  // --native-host and without a chrome-extension:// origin arg.
5
5
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
6
+ import { LocalSocketHostBridge } from './host-bridge.js';
6
7
  import { createPeekMcpServer } from './server.js';
7
8
  /**
8
9
  * Start the peek MCP stdio server and resolve when the transport closes (the
9
10
  * client disconnected — stdin EOF). The DB handle is released on close.
11
+ *
12
+ * In MCP mode we wire the {@link LocalSocketHostBridge} so act-tool calls reach
13
+ * the co-running native host over ~/.peek/host.sock (replacing the
14
+ * MissingHostBridge default that returns "bridge not wired"). The bridge
15
+ * fail-closes when the socket is unavailable — every act-tool call still goes
16
+ * through the audit log. A caller-supplied `hostBridge` (tests) wins.
10
17
  */
11
18
  export async function runMcpServer(options = {}) {
12
- const peek = createPeekMcpServer(options);
19
+ const peek = createPeekMcpServer({
20
+ hostBridge: new LocalSocketHostBridge(),
21
+ ...options,
22
+ });
13
23
  const transport = new StdioServerTransport();
14
24
  // Resolve when the client disconnects (stdin EOF). McpServer.connect
15
25
  // (Protocol.connect) PRESERVES and chains a pre-existing transport.onclose:
@@ -1 +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"}
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,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAmC,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEnF;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAsC,EAAE;IACzE,MAAM,IAAI,GAAG,mBAAmB,CAAC;QAC/B,UAAU,EAAE,IAAI,qBAAqB,EAAE;QACvC,GAAG,OAAO;KACX,CAAC,CAAC;IACH,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"}
@@ -19,6 +19,12 @@ export interface ActionResultMessage {
19
19
  details?: unknown;
20
20
  /** Error message when `result === 'error'` or 'denied'. */
21
21
  error?: string;
22
+ /**
23
+ * A one-shot confirm token issued on a `request_authorization` reply. The
24
+ * relay carries it back to the MCP process so the AI can pass it to a later
25
+ * `execute_action` (mirrors the extension-side ActionResultMessage).
26
+ */
27
+ confirmToken?: string;
22
28
  }
23
29
  /** host → SW: please execute / authorize this action. */
24
30
  export interface ActionRequestMessage {
@@ -36,6 +42,13 @@ export interface ActionRequestMessage {
36
42
  };
37
43
  /** Optional pinning to a specific tab id (SW picks active when omitted). */
38
44
  tabId?: number;
45
+ /**
46
+ * Pre-issued one-shot token from a prior `request_authorization` call. When
47
+ * present and valid (matching this request's sessionId + action.type), the SW
48
+ * consumes it and skips the side-panel banner. NULL/undefined → no token; the
49
+ * banner runs.
50
+ */
51
+ confirmToken?: string;
39
52
  }
40
53
  /** SW → host: the banner is now visible to the user (timing signal). */
41
54
  export interface ActionConfirmShownMessage {
@@ -1 +1 @@
1
- {"version":3,"file":"action-protocol.d.ts","sourceRoot":"","sources":["../../src/native-host/action-protocol.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,6EAA6E;AAC7E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,IAAI,EAAE,gBAAgB,GAAG,uBAAuB,CAAC;IACjD,mEAAmE;IACnE,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,oEAAoE;IACpE,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC;IAClC,oDAAoD;IACpD,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,cAAc,CAAC;IACvD,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,gBAAgB,GAAG,uBAAuB,CAAC;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,MAAM,EAAE;QACN,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;QACvB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;KAC3B,CAAC;IACF,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wEAAwE;AACxE,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AACnD,MAAM,MAAM,eAAe,GAAG,mBAAmB,GAAG,yBAAyB,CAAC"}
1
+ {"version":3,"file":"action-protocol.d.ts","sourceRoot":"","sources":["../../src/native-host/action-protocol.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,6EAA6E;AAC7E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,IAAI,EAAE,gBAAgB,GAAG,uBAAuB,CAAC;IACjD,mEAAmE;IACnE,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,oEAAoE;IACpE,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC;IAClC,oDAAoD;IACpD,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,cAAc,CAAC;IACvD,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,gBAAgB,GAAG,uBAAuB,CAAC;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,MAAM,EAAE;QACN,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;QACvB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;KAC3B,CAAC;IACF,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wEAAwE;AACxE,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AACnD,MAAM,MAAM,eAAe,GAAG,mBAAmB,GAAG,yBAAyB,CAAC"}
@@ -0,0 +1,105 @@
1
+ import type { ActionConfirmShownMessage, ActionRequestMessage, ActionResultMessage } from './action-protocol.js';
2
+ import { type LoadedPolicy } from './policy.js';
3
+ /**
4
+ * Item E + I: unlink a Unix-domain-socket file ONLY when it's safe to do so —
5
+ * the path is a socket inode (never a regular file the user owns). This is the
6
+ * pure filesystem guard; the LIVE-vs-stale decision (item I) is made by the
7
+ * caller via {@link probeSocketAlive} BEFORE calling this, because the mere
8
+ * existence of a socket inode does NOT mean it's stale — a live host could be
9
+ * listening on it. Clobbering a live host's socket would silently break it.
10
+ *
11
+ * A missing path is a no-op. Windows named pipes aren't filesystem paths, so
12
+ * this is skipped there. Best-effort: any stat/unlink error is swallowed.
13
+ */
14
+ export declare function cleanupStaleSocket(path: string): void;
15
+ /**
16
+ * Item I: probe whether a LIVE server is listening at `path`. Connects with a
17
+ * short timeout: a successful connect → a live host owns the socket (do NOT
18
+ * unlink it); a refused/ENOENT/timeout → the inode is stale (safe to unlink and
19
+ * retry the bind). Windows named pipes are probed the same way (net.connect
20
+ * accepts the pipe path). Resolves false on any error so a probe failure can't
21
+ * wedge startup.
22
+ */
23
+ export declare function probeSocketAlive(path: string, timeoutMs?: number): Promise<boolean>;
24
+ /** Minimal duplex surface a connection must provide — injectable for tests. */
25
+ export interface ConnectionLike {
26
+ write(data: string): void;
27
+ on(ev: string, h: (...a: unknown[]) => void): void;
28
+ /** Optional: forcibly close the connection (item J — over-cap line drop). */
29
+ destroy?(): void;
30
+ /** Optional: gracefully end the connection (fallback when destroy is absent). */
31
+ end?(): void;
32
+ }
33
+ /** Minimal server surface — injectable for tests (real impl is net.Server). */
34
+ export interface NetServerLike {
35
+ listen(): void;
36
+ close(): void;
37
+ /**
38
+ * Item I: subscribe to the server's async 'error' event (EADDRINUSE/EACCES are
39
+ * emitted here, NOT thrown from listen()). Optional so existing fakes that
40
+ * never error don't need it.
41
+ */
42
+ on?(ev: 'error', handler: (err: Error & {
43
+ code?: string;
44
+ }) => void): void;
45
+ }
46
+ export interface HostSocketServerDeps {
47
+ /** Forward an `action.request` to the SW over the native port. */
48
+ postToSw(message: ActionRequestMessage): void;
49
+ /** Read ~/.peek/policy.json (per request — cheap). Defaults to {@link loadPolicy}. */
50
+ loadPolicy?: () => LoadedPolicy;
51
+ /** Generate a fresh native-port requestId. Defaults to crypto.randomUUID. */
52
+ generateRequestId?: () => string;
53
+ /** Override the socket / named-pipe path. */
54
+ socketPath?: string;
55
+ /**
56
+ * Build the underlying server given the per-connection handler. Defaults to
57
+ * `net.createServer`; tests inject a fake that drives connections directly.
58
+ */
59
+ createServer?: (onConnection: (conn: ConnectionLike) => void) => NetServerLike;
60
+ /**
61
+ * Item J: max bytes for a single inbound line before the connection is
62
+ * dropped. Defaults to 1 MiB (matches the bridge side).
63
+ */
64
+ maxLineBytes?: number;
65
+ /**
66
+ * Item I: probe whether a LIVE server owns the socket path. Defaults to
67
+ * {@link probeSocketAlive}; injectable so the bind-failure policy is testable.
68
+ */
69
+ probeSocketAlive?: (path: string) => Promise<boolean>;
70
+ /**
71
+ * Item I: unlink the (confirmed-stale) socket inode. Defaults to
72
+ * {@link cleanupStaleSocket}; injectable for tests.
73
+ */
74
+ unlinkSocket?: (path: string) => void;
75
+ /**
76
+ * Item I: called when the socket fails to bind even after the stale-unlink
77
+ * retry (e.g. a LIVE owner, or EACCES). The caller (startNativeHost) uses
78
+ * this to degrade — set `socketServer = undefined` — instead of crashing.
79
+ */
80
+ onListenError?: (err: Error) => void;
81
+ }
82
+ export declare class HostSocketServer {
83
+ #private;
84
+ constructor(deps: HostSocketServerDeps);
85
+ /**
86
+ * Start listening for MCP-process connections. Item I: bind failures
87
+ * (EADDRINUSE/EACCES) surface ASYNC via the server 'error' event, not a throw,
88
+ * so we attach an error handler and run the stale-vs-live policy:
89
+ * • EADDRINUSE + probe says LIVE → another host owns it: report + stay down.
90
+ * • EADDRINUSE + probe says stale → unlink + retry listen ONCE.
91
+ * • any other bind error (e.g. EACCES) or a second EADDRINUSE → report + down.
92
+ * "Report" calls onListenError so startNativeHost degrades gracefully.
93
+ */
94
+ listen(): void;
95
+ /** Stop the server (best-effort). */
96
+ close(): void;
97
+ /**
98
+ * Inbound from the SW over the native port. For a terminal `action.result`,
99
+ * find the originating connection by requestId and write back the mapped
100
+ * `act.response`. `action.confirm.shown` is a non-terminal timing signal —
101
+ * the verdict still arrives in a later `action.result` — so we drop it here.
102
+ */
103
+ onSwMessage(message: ActionResultMessage | ActionConfirmShownMessage): void;
104
+ }
105
+ //# sourceMappingURL=host-socket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-socket.d.ts","sourceRoot":"","sources":["../../src/native-host/host-socket.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EACV,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,YAAY,EAAc,MAAM,aAAa,CAAC;AAG5D;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAUrD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAmBhF;AAED,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IACnD,6EAA6E;IAC7E,OAAO,CAAC,IAAI,IAAI,CAAC;IACjB,iFAAiF;IACjF,GAAG,CAAC,IAAI,IAAI,CAAC;CACd;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,IAAI,IAAI,CAAC;IACd;;;;OAIG;IACH,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAC;CAC3E;AAKD,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC9C,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,YAAY,CAAC;IAChC,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAC;IACjC,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,KAAK,aAAa,CAAC;IAC/E;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CACtC;AA6BD,qBAAa,gBAAgB;;gBAUf,IAAI,EAAE,oBAAoB;IAiCtC;;;;;;;;OAQG;IACH,MAAM,IAAI,IAAI;IAoCd,qCAAqC;IACrC,KAAK,IAAI,IAAI;IAMb;;;;;OAKG;IACH,WAAW,CAAC,OAAO,EAAE,mBAAmB,GAAG,yBAAyB,GAAG,IAAI;CAkG5E"}
@@ -0,0 +1,300 @@
1
+ // Native-host-side IPC relay (Task 3.24 IPC layer).
2
+ //
3
+ // The MCP-server process talks to this server over the local socket
4
+ // (`~/.peek/host.sock`) using the {@link LocalSocketHostBridge}. This server
5
+ // runs INSIDE the native-host process — the one that owns the
6
+ // `chrome.runtime.connectNative` port to the service worker. It relays:
7
+ //
8
+ // socket act.request → native-port action.request (host → SW)
9
+ // native-port action.result / action.confirm.shown → socket act.response
10
+ //
11
+ // Correlation has TWO id spaces that must not be conflated:
12
+ // • the socket wire `id` (the LocalSocketHostBridge's RequestRegistry id) —
13
+ // the MCP process correlates `act.response` back to its awaiting tool call.
14
+ // • the native-port `requestId` (UUID) — the SW echoes it on its reply so we
15
+ // find the originating socket connection.
16
+ // We hold a `Map<requestId, { conn, wireId }>` so an `action.result` resolves
17
+ // to the right connection AND echoes the right wire id.
18
+ //
19
+ // Security / robustness: per-connection newline-JSON framing (reused shape from
20
+ // the bridge); a malformed frame is dropped, never crashes the loop; an
21
+ // `action.result` for an unknown requestId is dropped (a stale reply after a
22
+ // timeout must not throw). The policy deltas are loaded per request (the file
23
+ // is tiny) and forwarded so the SW's destructive matcher merges them.
24
+ import { statSync, unlinkSync } from 'node:fs';
25
+ import * as net from 'node:net';
26
+ import { platform } from 'node:os';
27
+ import { setTimeout as delay } from 'node:timers/promises';
28
+ import { loadPolicy } from './policy.js';
29
+ import { hostSocketPath } from './socket-path.js';
30
+ /**
31
+ * Item E + I: unlink a Unix-domain-socket file ONLY when it's safe to do so —
32
+ * the path is a socket inode (never a regular file the user owns). This is the
33
+ * pure filesystem guard; the LIVE-vs-stale decision (item I) is made by the
34
+ * caller via {@link probeSocketAlive} BEFORE calling this, because the mere
35
+ * existence of a socket inode does NOT mean it's stale — a live host could be
36
+ * listening on it. Clobbering a live host's socket would silently break it.
37
+ *
38
+ * A missing path is a no-op. Windows named pipes aren't filesystem paths, so
39
+ * this is skipped there. Best-effort: any stat/unlink error is swallowed.
40
+ */
41
+ export function cleanupStaleSocket(path) {
42
+ if (platform() === 'win32')
43
+ return; // named pipe — not a filesystem inode
44
+ try {
45
+ const st = statSync(path);
46
+ if (!st.isSocket())
47
+ return; // never clobber a regular file / dir
48
+ unlinkSync(path);
49
+ }
50
+ catch {
51
+ // ENOENT (nothing there) or any other stat/unlink error — leave it for the
52
+ // bind to report. Don't throw; cleanup is best-effort.
53
+ }
54
+ }
55
+ /**
56
+ * Item I: probe whether a LIVE server is listening at `path`. Connects with a
57
+ * short timeout: a successful connect → a live host owns the socket (do NOT
58
+ * unlink it); a refused/ENOENT/timeout → the inode is stale (safe to unlink and
59
+ * retry the bind). Windows named pipes are probed the same way (net.connect
60
+ * accepts the pipe path). Resolves false on any error so a probe failure can't
61
+ * wedge startup.
62
+ */
63
+ export function probeSocketAlive(path, timeoutMs = 500) {
64
+ return new Promise((resolve) => {
65
+ let settled = false;
66
+ const done = (alive) => {
67
+ if (settled)
68
+ return;
69
+ settled = true;
70
+ try {
71
+ client.destroy();
72
+ }
73
+ catch {
74
+ // ignore
75
+ }
76
+ resolve(alive);
77
+ };
78
+ const client = net.connect(path);
79
+ client.setTimeout?.(timeoutMs);
80
+ client.on('connect', () => done(true)); // a live server accepted us
81
+ client.on('error', () => done(false)); // ECONNREFUSED / ENOENT → stale
82
+ client.on('timeout', () => done(false));
83
+ });
84
+ }
85
+ /** Default cap for a single inbound newline-delimited frame (item J). 1 MiB. */
86
+ const DEFAULT_MAX_LINE_BYTES = 1024 * 1024;
87
+ /**
88
+ * Map a terminal {@link ActionResultMessage} to the wire `payload` the bridge
89
+ * expects (a {@link HostActionResponse}). Drops the wire-protocol envelope
90
+ * fields (`type`, `requestId`, `tool`) and keeps the verdict/result data —
91
+ * INCLUDING `confirmToken` when the SW issued one (request_authorization).
92
+ */
93
+ function toResponsePayload(result) {
94
+ const payload = {
95
+ verdict: result.verdict,
96
+ result: result.result,
97
+ approver: result.approver,
98
+ };
99
+ if (result.approvalMs !== undefined)
100
+ payload.approvalMs = result.approvalMs;
101
+ if (result.destructiveTerm !== undefined)
102
+ payload.destructiveTerm = result.destructiveTerm;
103
+ if (result.details !== undefined)
104
+ payload.details = result.details;
105
+ if (result.error !== undefined)
106
+ payload.error = result.error;
107
+ if (result.confirmToken !== undefined)
108
+ payload.confirmToken = result.confirmToken;
109
+ return payload;
110
+ }
111
+ export class HostSocketServer {
112
+ #deps;
113
+ #inFlight = new Map();
114
+ #server;
115
+ /** Whether we've already done the one stale-unlink retry (item I). */
116
+ #retriedAfterUnlink = false;
117
+ constructor(deps) {
118
+ this.#deps = {
119
+ postToSw: deps.postToSw,
120
+ loadPolicy: deps.loadPolicy ?? (() => loadPolicy()),
121
+ generateRequestId: deps.generateRequestId ?? (() => globalThis.crypto.randomUUID()),
122
+ socketPath: deps.socketPath ?? hostSocketPath(),
123
+ maxLineBytes: deps.maxLineBytes ?? DEFAULT_MAX_LINE_BYTES,
124
+ probeSocketAlive: deps.probeSocketAlive ?? ((p) => probeSocketAlive(p)),
125
+ unlinkSocket: deps.unlinkSocket ?? ((p) => cleanupStaleSocket(p)),
126
+ ...(deps.onListenError ? { onListenError: deps.onListenError } : {}),
127
+ createServer: deps.createServer ??
128
+ ((onConnection) => {
129
+ const server = net.createServer((socket) => {
130
+ socket.setEncoding('utf8');
131
+ onConnection(socket);
132
+ });
133
+ let errorHandler;
134
+ server.on('error', (err) => errorHandler?.(err));
135
+ return {
136
+ // Item I: do NOT blindly unlink before binding (that could clobber a
137
+ // LIVE host's socket). Bind directly; if it emits EADDRINUSE the
138
+ // listen() orchestration probes live-vs-stale and only then unlinks.
139
+ listen: () => server.listen(this.#deps.socketPath),
140
+ close: () => server.close(),
141
+ on: (_ev, handler) => {
142
+ errorHandler = handler;
143
+ },
144
+ };
145
+ }),
146
+ };
147
+ }
148
+ /**
149
+ * Start listening for MCP-process connections. Item I: bind failures
150
+ * (EADDRINUSE/EACCES) surface ASYNC via the server 'error' event, not a throw,
151
+ * so we attach an error handler and run the stale-vs-live policy:
152
+ * • EADDRINUSE + probe says LIVE → another host owns it: report + stay down.
153
+ * • EADDRINUSE + probe says stale → unlink + retry listen ONCE.
154
+ * • any other bind error (e.g. EACCES) or a second EADDRINUSE → report + down.
155
+ * "Report" calls onListenError so startNativeHost degrades gracefully.
156
+ */
157
+ listen() {
158
+ if (this.#server)
159
+ return;
160
+ const server = this.#deps.createServer((conn) => this.#onConnection(conn));
161
+ this.#server = server;
162
+ server.on?.('error', (err) => {
163
+ void this.#handleListenError(err);
164
+ });
165
+ server.listen();
166
+ }
167
+ async #handleListenError(err) {
168
+ // Only EADDRINUSE is recoverable via the stale-unlink dance; everything else
169
+ // (EACCES, etc.) is reported as-is.
170
+ if (err.code !== 'EADDRINUSE' || this.#retriedAfterUnlink) {
171
+ this.#reportListenFailure(err);
172
+ return;
173
+ }
174
+ const alive = await this.#deps.probeSocketAlive(this.#deps.socketPath).catch(() => false);
175
+ if (alive) {
176
+ // A live host already owns this socket — DO NOT clobber it. Degrade.
177
+ this.#reportListenFailure(err);
178
+ return;
179
+ }
180
+ // Stale inode: unlink it and retry the bind exactly once.
181
+ this.#retriedAfterUnlink = true;
182
+ this.#deps.unlinkSocket(this.#deps.socketPath);
183
+ // A short beat so the unlink settles before rebind (mostly belt-and-braces).
184
+ await delay(0);
185
+ this.#server?.listen();
186
+ }
187
+ #reportListenFailure(err) {
188
+ this.#server = undefined;
189
+ this.#deps.onListenError?.(err);
190
+ }
191
+ /** Stop the server (best-effort). */
192
+ close() {
193
+ this.#server?.close();
194
+ this.#server = undefined;
195
+ this.#inFlight.clear();
196
+ }
197
+ /**
198
+ * Inbound from the SW over the native port. For a terminal `action.result`,
199
+ * find the originating connection by requestId and write back the mapped
200
+ * `act.response`. `action.confirm.shown` is a non-terminal timing signal —
201
+ * the verdict still arrives in a later `action.result` — so we drop it here.
202
+ */
203
+ onSwMessage(message) {
204
+ if (message.type !== 'action.result')
205
+ return; // confirm.shown: timing only
206
+ const inFlight = this.#inFlight.get(message.requestId);
207
+ if (!inFlight)
208
+ return; // stale reply after a timeout — drop, don't throw
209
+ this.#inFlight.delete(message.requestId);
210
+ const frame = {
211
+ kind: 'act.response',
212
+ id: inFlight.wireId,
213
+ payload: toResponsePayload(message),
214
+ };
215
+ try {
216
+ inFlight.conn.write(`${JSON.stringify(frame)}\n`);
217
+ }
218
+ catch {
219
+ // The MCP process closed the socket mid-flight; its tool call will time
220
+ // out. Nothing else to do here.
221
+ }
222
+ }
223
+ #onConnection(conn) {
224
+ let buf = '';
225
+ let dropped = false;
226
+ conn.on('data', (chunk) => {
227
+ if (dropped)
228
+ return; // connection already torn down for an over-cap line
229
+ buf += String(chunk);
230
+ // Item J: local-DoS guard (mirrors the bridge). If the buffer grows past
231
+ // the cap WITHOUT a frame delimiter, a hostile/malformed peer is trying to
232
+ // make us buffer unbounded — drop the connection + clear the buffer.
233
+ if (buf.length > this.#deps.maxLineBytes && buf.indexOf('\n') < 0) {
234
+ dropped = true;
235
+ buf = '';
236
+ try {
237
+ conn.destroy?.();
238
+ conn.end?.();
239
+ }
240
+ catch {
241
+ // best-effort teardown
242
+ }
243
+ return;
244
+ }
245
+ let nl;
246
+ // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic frame-drain loop
247
+ while ((nl = buf.indexOf('\n')) >= 0) {
248
+ const line = buf.slice(0, nl);
249
+ buf = buf.slice(nl + 1);
250
+ if (!line.trim())
251
+ continue;
252
+ if (line.length > this.#deps.maxLineBytes)
253
+ continue; // oversized framed line — drop it
254
+ this.#handleFrame(conn, line);
255
+ }
256
+ });
257
+ // A connection error / close leaves any of its in-flight entries dangling;
258
+ // they'll never be resolved (the MCP tool call times out). Drop them so the
259
+ // map doesn't grow unbounded.
260
+ const drop = () => {
261
+ for (const [requestId, entry] of this.#inFlight.entries()) {
262
+ if (entry.conn === conn)
263
+ this.#inFlight.delete(requestId);
264
+ }
265
+ };
266
+ conn.on('error', drop);
267
+ conn.on('close', drop);
268
+ conn.on('end', drop);
269
+ }
270
+ #handleFrame(conn, line) {
271
+ let frame;
272
+ try {
273
+ frame = JSON.parse(line);
274
+ }
275
+ catch {
276
+ return; // malformed — drop, keep the loop alive
277
+ }
278
+ if (frame.kind !== 'act.request' || typeof frame.id !== 'string')
279
+ return;
280
+ const payload = frame.payload;
281
+ if (!payload || payload.tool === undefined || payload.action === undefined)
282
+ return;
283
+ const requestId = this.#deps.generateRequestId();
284
+ this.#inFlight.set(requestId, { conn, wireId: frame.id });
285
+ const policy = this.#deps.loadPolicy().destructiveTerms;
286
+ const request = {
287
+ type: 'action.request',
288
+ requestId,
289
+ tool: payload.tool,
290
+ sessionId: payload.sessionId ?? '',
291
+ action: payload.action,
292
+ client: payload.client ?? 'unknown',
293
+ policy: { add: policy.add, remove: policy.remove },
294
+ ...(payload.tabId !== undefined ? { tabId: payload.tabId } : {}),
295
+ ...(payload.confirmToken !== undefined ? { confirmToken: payload.confirmToken } : {}),
296
+ };
297
+ this.#deps.postToSw(request);
298
+ }
299
+ }
300
+ //# sourceMappingURL=host-socket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-socket.js","sourceRoot":"","sources":["../../src/native-host/host-socket.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,17 @@ export interface NativeHostOptions {
20
20
  readonly input?: Readable;
21
21
  /** Override the output stream (default: process.stdout). */
22
22
  readonly output?: Writable;
23
+ /**
24
+ * Override the IPC socket / named-pipe path the {@link HostSocketServer}
25
+ * listens on (tests + alternate PEEK_HOME). Defaults to ~/.peek/host.sock.
26
+ */
27
+ readonly socketPath?: string;
28
+ /**
29
+ * When false, skip starting the {@link HostSocketServer}. Defaults to true.
30
+ * Tests that only exercise the ingest/handshake path set this false to avoid
31
+ * binding a real socket.
32
+ */
33
+ readonly startSocketServer?: boolean;
23
34
  }
24
35
  /**
25
36
  * Start the native messaging host: open the DB (running migrations) and begin
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/native-host/host.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAKtD,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,mCAAmC;IACnC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAC1B,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;CAC5B;AAUD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CA4EjF"}
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/native-host/host.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQtD,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,mCAAmC;IACnC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAC1B,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CACtC;AAaD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAmIjF"}
@@ -9,8 +9,12 @@
9
9
  // network.append / shadow.report). The act-tool action-protocol dispatch
10
10
  // (request/result correlation through the SW) lands alongside the IPC bridge.
11
11
  import { openDb, peekHomeDir, schemaVersion } from '../db/open.js';
12
+ import { HostSocketServer } from './host-socket.js';
12
13
  import { ingest } from './ingest.js';
14
+ import { hostSocketPath } from './socket-path.js';
13
15
  import { readMessages, writeMessage } from './transport.js';
16
+ /** Message types the SW sends back on the action-request correlation channel. */
17
+ const ACTION_REPLY_TYPES = new Set(['action.result', 'action.confirm.shown']);
14
18
  /** Message-type strings the ingest handler claims. */
15
19
  const INGEST_TYPES = new Set([
16
20
  'session.append',
@@ -35,6 +39,47 @@ export function startNativeHost(options = {}) {
35
39
  };
36
40
  if (options.input !== undefined)
37
41
  readOptions.input = options.input;
42
+ // IPC relay to the MCP-server process (Task 3.24). The MCP process's
43
+ // LocalSocketHostBridge connects here; the server relays `act.request` →
44
+ // native-port `action.request` (via `write`, the host → SW direction) and
45
+ // `action.result` (inbound, see handleMessage) → `act.response`.
46
+ let socketServer;
47
+ if (options.startSocketServer !== false) {
48
+ // Resolve the socket path: explicit option wins; else derive from the
49
+ // (possibly test-overridden) peek data dir via hostSocketPath(home). This
50
+ // is the SAME function the MCP-process bridge dials, so both sides agree —
51
+ // including under a custom $PEEK_HOME (item D). On Windows it's the fixed
52
+ // named pipe; a test `home` binds its own socket and never collides.
53
+ const socketPath = options.socketPath ?? hostSocketPath(home);
54
+ socketServer = new HostSocketServer({
55
+ // postToSw writes the action.request out the native port (host → SW).
56
+ postToSw: (message) => {
57
+ void write(message).catch((err) => {
58
+ console.error(`native host: action.request post failed — ${err instanceof Error ? err.message : String(err)}`);
59
+ });
60
+ },
61
+ socketPath,
62
+ // Item I/J: bind failures (EADDRINUSE/EACCES) are emitted ASYNC via the
63
+ // server 'error' event, so a try/catch around listen() can't catch them.
64
+ // The server probes live-vs-stale + retries once on a stale socket; if it
65
+ // still can't bind it calls this. Degrade — the action write-path is down,
66
+ // but ingest/capture still flows — never crash the host.
67
+ onListenError: (err) => {
68
+ console.error(`native host: IPC socket failed to listen — ${err.message}`);
69
+ socketServer = undefined;
70
+ },
71
+ });
72
+ // listen() is async-internally (the bind-error/probe/retry path); it never
73
+ // throws synchronously, but keep the try/catch for a defensive construct-time
74
+ // failure.
75
+ try {
76
+ socketServer.listen();
77
+ }
78
+ catch (err) {
79
+ console.error(`native host: IPC socket listen threw — ${err instanceof Error ? err.message : String(err)}`);
80
+ socketServer = undefined;
81
+ }
82
+ }
38
83
  const done = readMessages((message) => {
39
84
  // A reply-write failure (e.g. the browser closed the port mid-reply) must
40
85
  // not become an unhandled rejection that tears down the host.
@@ -45,6 +90,7 @@ export function startNativeHost(options = {}) {
45
90
  return {
46
91
  done,
47
92
  close() {
93
+ socketServer?.close();
48
94
  db.close();
49
95
  },
50
96
  };
@@ -60,6 +106,14 @@ export function startNativeHost(options = {}) {
60
106
  });
61
107
  return;
62
108
  }
109
+ // Action-request correlation replies from the SW (Task 3.24). Forward to
110
+ // the IPC relay, which writes the mapped `act.response` back to the
111
+ // originating MCP-process socket connection. These are NOT acked over the
112
+ // native port (the MCP process is the one awaiting, over the socket).
113
+ if (type !== undefined && ACTION_REPLY_TYPES.has(type)) {
114
+ socketServer?.onSwMessage(message);
115
+ return;
116
+ }
63
117
  if (type !== undefined && INGEST_TYPES.has(type)) {
64
118
  // ingest() catches its own throws + returns a structured reply. The
65
119
  // try/catch here is defense in depth: if a future regression introduces
@@ -1 +1 @@
1
- {"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/native-host/host.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/native-host/host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The local socket / named-pipe path the {@link LocalSocketHostBridge} connects
3
+ * to and the {@link HostSocketServer} listens on.
4
+ *
5
+ * @param peekHome the peek data dir (defaults to {@link peekHomeDir}, which
6
+ * honors `$PEEK_HOME`). On win32 the named pipe is a fixed namespace path and
7
+ * this argument is ignored.
8
+ */
9
+ export declare function hostSocketPath(peekHome?: string): string;
10
+ //# sourceMappingURL=socket-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket-path.d.ts","sourceRoot":"","sources":["../../src/native-host/socket-path.ts"],"names":[],"mappings":"AAkBA;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAgB,GAAG,MAAM,CAI/D"}
@@ -0,0 +1,31 @@
1
+ // Local IPC endpoint path for the MCP-process ↔ native-host bridge (Task 3.24
2
+ // IPC layer). The two `peek-mcp` processes share the peek data dir; the
3
+ // simplest cross-platform local-only IPC is a Unix domain socket on
4
+ // macOS/Linux (`<peekHome>/host.sock`) and a named pipe on Windows.
5
+ //
6
+ // Item D: the socket lives DIRECTLY inside the peek data dir (peekHomeDir(),
7
+ // which honors $PEEK_HOME) as `host.sock`. The native host binds at the same
8
+ // `join(peekHomeDir(), 'host.sock')`, so a user who relocates the store via
9
+ // PEEK_HOME gets the bridge and the host on ONE path — not the bridge dialing
10
+ // ~/.peek/host.sock while the host listens elsewhere.
11
+ //
12
+ // Pure path derivation — no `node:net`, no filesystem — so it unit-tests
13
+ // cleanly. The peek-home dir is injectable for tests.
14
+ import { platform } from 'node:os';
15
+ import { join } from 'node:path';
16
+ import { peekHomeDir } from '../db/open.js';
17
+ /**
18
+ * The local socket / named-pipe path the {@link LocalSocketHostBridge} connects
19
+ * to and the {@link HostSocketServer} listens on.
20
+ *
21
+ * @param peekHome the peek data dir (defaults to {@link peekHomeDir}, which
22
+ * honors `$PEEK_HOME`). On win32 the named pipe is a fixed namespace path and
23
+ * this argument is ignored.
24
+ */
25
+ export function hostSocketPath(peekHome = peekHomeDir()) {
26
+ // Windows named pipes live in the `\\.\pipe\` namespace, not the filesystem.
27
+ if (platform() === 'win32')
28
+ return '\\\\.\\pipe\\peek-host';
29
+ return join(peekHome, 'host.sock');
30
+ }
31
+ //# sourceMappingURL=socket-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket-path.js","sourceRoot":"","sources":["../../src/native-host/socket-path.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wEAAwE;AACxE,oEAAoE;AACpE,oEAAoE;AACpE,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,sDAAsD;AACtD,EAAE;AACF,yEAAyE;AACzE,sDAAsD;AAEtD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,QAAQ,GAAG,WAAW,EAAE;IACrD,6EAA6E;IAC7E,IAAI,QAAQ,EAAE,KAAK,OAAO;QAAE,OAAO,wBAAwB,CAAC;IAC5D,OAAO,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACrC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@peekdev/mcp",
3
- "version": "0.1.0-alpha.12",
3
+ "version": "0.1.0-alpha.13",
4
+ "mcpName": "io.github.cubenest/peek-mcp",
4
5
  "description": "peek native messaging host + stdio MCP server. Owns ~/.peek/sessions.db (better-sqlite3) and bridges the browser extension, CLI, and AI tools to a single local source of truth.",
5
6
  "keywords": [
6
7
  "peek",