@nudge-ui/mcp 0.2.5 → 0.2.6

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.
@@ -3,7 +3,6 @@ export interface ProjectTarget {
3
3
  readonly workspaceRoot?: string;
4
4
  readonly sessionId?: string;
5
5
  }
6
- /** Keeps each explicit project selection independent for the lifetime of an MCP connection. */
7
6
  export declare class AdapterRouting {
8
7
  readonly registryRoot: string;
9
8
  private closing;
@@ -4,7 +4,6 @@ import { DiscoveredProjectRouter } from "./discovery.js";
4
4
  import { defaultSessionRegistryRoot, resolveWorkspaceRoot } from "./project.js";
5
5
  import { readLiveProjectSessions } from "./sessionRegistry.js";
6
6
  import { selectProjectSession } from "./sessionSelection.js";
7
- /** Keeps each explicit project selection independent for the lifetime of an MCP connection. */
8
7
  export class AdapterRouting {
9
8
  registryRoot;
10
9
  closing = false;
package/dist/bridge.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import { type BridgeClock, type BridgeSessionControls } from "./bridgeSession.js";
2
2
  export interface BrowserBridgeOptions {
3
- /** Stable project identity used to scope every browser message. */
4
3
  readonly projectId: string;
5
4
  /** Canonical app origin that pairing and Canvas routes must use. */
6
5
  readonly origin: string;
7
- /** Other explicit browser origins accepted by the loopback HTTP server. */
6
+ /** Other explicit browser origins, such as loopback aliases on the same port. */
8
7
  readonly allowedOrigins?: readonly string[];
9
8
  readonly host?: "127.0.0.1" | "::1" | "localhost";
10
9
  /** Use port 0 in tests or when several projects run concurrently. */
@@ -23,15 +22,11 @@ export interface BridgeAddress {
23
22
  readonly port: number;
24
23
  readonly url: string;
25
24
  }
26
- /** A loopback HTTP server exposing one project session to its browser and MCP adapter. */
27
25
  export interface BrowserBridge extends BridgeSessionControls {
28
26
  readonly projectId: string;
29
27
  readonly address: BridgeAddress | null;
30
28
  start(): Promise<BridgeAddress>;
31
29
  close(): Promise<void>;
32
30
  }
33
- /**
34
- * Creates the local browser bridge. It binds only to loopback and keeps every
35
- * pairing, prompt, command, and acknowledgement in process memory.
36
- */
31
+ /** Binds only to loopback and keeps every pairing, prompt, command, and acknowledgement in process memory. */
37
32
  export declare function createLoopbackBridge(options: BrowserBridgeOptions): BrowserBridge;
package/dist/bridge.js CHANGED
@@ -187,10 +187,7 @@ function writeSse(response, envelope) {
187
187
  return false;
188
188
  }
189
189
  }
190
- /**
191
- * Creates the local browser bridge. It binds only to loopback and keeps every
192
- * pairing, prompt, command, and acknowledgement in process memory.
193
- */
190
+ /** Binds only to loopback and keeps every pairing, prompt, command, and acknowledgement in process memory. */
194
191
  export function createLoopbackBridge(options) {
195
192
  const host = options.host ?? "127.0.0.1";
196
193
  if (!LOOPBACK_HOSTS.has(host))
@@ -1,11 +1,13 @@
1
1
  import type { AgentActivity, AgentDeliveredPrompt, AgentRequestOutcome, AgentSketchAttachment, AgentStatusSnapshot, AgentStatusUpdate, BridgeEnvelope, CanvasCommand, CanvasCommandResult, FitCanvasCommand, FocusCanvasGroupCommand, PairingResponse, PresentRoutesCommand, PromptDispatchResponse, ReadCanvasStateCommand, RemoveCanvasGroupCommand } from "./internal/agent-protocol.js";
2
2
  export declare const AGENT_CLAIM_TIMEOUT_MS = 30000;
3
3
  export declare const AGENT_ACKNOWLEDGMENT_TIMEOUT_MS = 60000;
4
+ /** Timer handle: Node returns Timeout objects and test clocks use numeric IDs; only the creating clock interprets it. */
5
+ export type BridgeTimeoutHandle = NodeJS.Timeout | number;
4
6
  /** A clock port keeps command timeout and claim expiry tests deterministic. */
5
7
  export interface BridgeClock {
6
8
  now(): number;
7
- setTimeout(callback: () => void, delayMs: number): unknown;
8
- clearTimeout(handle: unknown): void;
9
+ setTimeout(callback: () => void, delayMs: number): BridgeTimeoutHandle;
10
+ clearTimeout(handle: BridgeTimeoutHandle): void;
9
11
  }
10
12
  type WithOptionalCommandId<T extends CanvasCommand> = Omit<T, "commandId"> & {
11
13
  readonly commandId?: string;
@@ -22,7 +24,6 @@ export interface BrowserStream {
22
24
  send(envelope: BridgeEnvelope): boolean;
23
25
  end(): void;
24
26
  }
25
- /** Proof that a request came from the paired browser. */
26
27
  export interface BrowserGrant {
27
28
  readonly origin: string;
28
29
  readonly sessionToken: string;
@@ -35,31 +36,23 @@ export interface PromptDispatchInput {
35
36
  }
36
37
  export interface ListenOptions {
37
38
  readonly signal?: AbortSignal;
38
- /** MCP client name shown in the browser while this listener is active. */
39
+ /** Shown in the browser while this listener is active. */
39
40
  readonly agentClientName?: string;
40
41
  }
41
- /** In-process controls a host or an embedded agent uses on one project session. */
42
42
  export interface BridgeSessionControls {
43
43
  getStatus(): AgentStatusSnapshot;
44
- /** Host-side approval of a browser origin from the allow-list. */
45
44
  pairBrowser(origin: string, pageUrl?: string): PairingResponse;
46
45
  /** Revokes the pairing and interrupts any working request. */
47
46
  disconnectBrowser(sessionToken: string): void;
48
- /** Blocks until the paired browser dispatches a prompt. */
49
47
  waitForPrompt(options?: ListenOptions): Promise<AgentDeliveredPrompt>;
50
48
  /** Retrieves an unacknowledged request, including its sketch attachments. */
51
49
  getRequest(requestId: string): AgentDeliveredPrompt;
52
- /** Reports the status of the request currently in flight. */
53
50
  updateRequestStatus(update: AgentStatusUpdate | AgentRequestOutcome): void;
54
- /** Emits temporary source attribution for the working request. */
55
51
  reportActivity(activity: AgentActivity): void;
56
52
  /** Sends a Canvas command to the browser and waits for one bounded acknowledgement. */
57
53
  dispatchCanvasCommand(input: CanvasCommandInput): Promise<CanvasCommandResult>;
58
54
  }
59
- /**
60
- * The transport-free state of one project bridge. Browser-facing transitions
61
- * trust their caller to have authorized the request first.
62
- */
55
+ /** Browser-facing transitions trust their caller to have authorized the request first. */
63
56
  export interface BridgeSession extends BridgeSessionControls {
64
57
  readonly projectId: string;
65
58
  readonly agentClaimed: boolean;
@@ -83,9 +76,7 @@ export interface BridgeSession extends BridgeSessionControls {
83
76
  }
84
77
  export interface BridgeSessionOptions {
85
78
  readonly projectId: string;
86
- /** Canonical app origin that pairing and Canvas routes must use. */
87
79
  readonly origin: string;
88
- /** Other explicit browser origins, such as loopback aliases on the same port. */
89
80
  readonly allowedOrigins?: readonly string[];
90
81
  readonly commandTimeoutMs?: number;
91
82
  readonly clock?: BridgeClock;
@@ -20,10 +20,11 @@ function canonicalOrigins(options) {
20
20
  const origins = [options.origin, ...(options.allowedOrigins ?? [])].map((candidate) => canonicalOrigin(candidate));
21
21
  if (origins[0] === null)
22
22
  throw new TypeError("origin must be a canonical HTTP(S) origin");
23
- if (origins.some((candidate) => candidate === null)) {
23
+ const canonical = origins.filter((candidate) => candidate !== null);
24
+ if (canonical.length !== origins.length) {
24
25
  throw new TypeError("allowedOrigins must contain canonical HTTP(S) origins");
25
26
  }
26
- return origins;
27
+ return canonical;
27
28
  }
28
29
  export function createBridgeSession(options) {
29
30
  const { projectId } = options;
@@ -79,8 +80,7 @@ export function createBridgeSession(options) {
79
80
  };
80
81
  const publishStatus = () => publish({ type: "status", status: getStatus() });
81
82
  const authorizeOrigin = (candidate) => {
82
- // Before pairing only a configured origin is eligible; an empty allow-list
83
- // stays closed rather than trusting the first caller.
83
+ // An empty allow-list stays closed rather than trusting the first caller.
84
84
  if (candidate && (candidate === pairing?.origin || isAllowedOrigin(candidate, allowedOrigins)))
85
85
  return candidate;
86
86
  throw new BridgeSessionError("origin_not_allowed", "The browser origin is not allowed for this project.");
package/dist/cli.d.ts CHANGED
@@ -7,5 +7,4 @@ export type CliEnvironment = Readonly<Record<string, string | undefined>>;
7
7
  /** Serving takes no options; `doctor` accepts a diagnostic scope. */
8
8
  export declare function parseCliArguments(argv?: readonly string[], environment?: CliEnvironment): CliOptions;
9
9
  export declare const CLI_USAGE = "Usage: nudge-mcp [doctor] [options]\n\nStarts a standard MCP stdio adapter that discovers the bridges owned by running\nprojects. Every tool call names the checkout or application it targets.\n\nOptions:\n --workspace-root <path> doctor only: limit diagnostics to one checkout or application\n --help Show this message\n";
10
- /** Runs the CLI until the stdio MCP connection closes or the process stops. */
11
10
  export declare function runCli(argv?: readonly string[], environment?: CliEnvironment): Promise<void>;
package/dist/cli.js CHANGED
@@ -57,7 +57,6 @@ Options:
57
57
  --workspace-root <path> doctor only: limit diagnostics to one checkout or application
58
58
  --help Show this message
59
59
  `;
60
- /** Runs the CLI until the stdio MCP connection closes or the process stops. */
61
60
  export async function runCli(argv = process.argv.slice(2), environment = process.env) {
62
61
  const options = parseCliArguments(argv, environment);
63
62
  if (options.help) {
@@ -106,8 +105,8 @@ export async function runCli(argv = process.argv.slice(2), environment = process
106
105
  await adapter.start();
107
106
  await new Promise((resolveAdapter) => {
108
107
  const finish = () => resolveAdapter();
109
- // Keep a direct resolver so signal handlers terminate even though
110
- // installing a signal handler suppresses Node's default process exit.
108
+ // Installing a signal handler suppresses Node's default exit, so the
109
+ // handler needs this direct resolver to terminate.
111
110
  resolveAdapterWait = finish;
112
111
  process.stdin.once("end", finish);
113
112
  process.once("exit", finish);
@@ -9,7 +9,7 @@ export interface DiscoveredProjectSession extends ProjectSession {
9
9
  readonly status: Pick<AgentStatusSnapshot, "connection" | "listenerActive" | "paired">;
10
10
  }
11
11
  export declare function discoverProjectSessions(applicationRoot: string | undefined, registryRoot?: string): Promise<DiscoveredProjectSession[]>;
12
- /** Routes MCP tools to one selected live project, following it across bridge restarts. */
12
+ /** Follows one selected live project across bridge restarts. */
13
13
  export declare class DiscoveredProjectRouter {
14
14
  readonly workspaceRoot: string;
15
15
  readonly applicationRoot: string;
package/dist/discovery.js CHANGED
@@ -33,7 +33,7 @@ export async function discoverProjectSessions(applicationRoot, registryRoot = de
33
33
  };
34
34
  }).sort((left, right) => right.startedAt.localeCompare(left.startedAt));
35
35
  }
36
- /** Routes MCP tools to one selected live project, following it across bridge restarts. */
36
+ /** Follows one selected live project across bridge restarts. */
37
37
  export class DiscoveredProjectRouter {
38
38
  workspaceRoot;
39
39
  applicationRoot;
@@ -1,11 +1,4 @@
1
- /**
2
- * Public, host-neutral contracts shared by the Nudge browser inspector and
3
- * its local MCP companion.
4
- *
5
- * This module deliberately has no Node, browser, MCP SDK, or framework
6
- * imports. Hosts can use the same validation and message shapes without
7
- * pulling the companion into a browser bundle.
8
- */
1
+ /** Host-neutral contracts shared by the browser inspector and the local MCP companion; no Node, browser, MCP SDK, or framework imports. */
9
2
  export declare const AGENT_PROTOCOL_VERSION: 3;
10
3
  export declare const AGENT_PROTOCOL_LIMITS: {
11
4
  readonly projectId: 256;
@@ -38,6 +31,18 @@ export declare const AGENT_PROTOCOL_LIMITS: {
38
31
  readonly agentClientName: 120;
39
32
  };
40
33
  export type AgentProtocolVersion = typeof AGENT_PROTOCOL_VERSION;
34
+ /** Stable loopback endpoint names shared by the browser client and the MCP bridge. */
35
+ export declare const BRIDGE_ENDPOINTS: {
36
+ readonly health: "/health";
37
+ readonly pair: "/pair";
38
+ readonly takeover: "/takeover";
39
+ readonly events: "/events";
40
+ readonly prompt: "/prompt";
41
+ readonly status: "/status";
42
+ readonly canvasAcknowledgement: "/canvas/ack";
43
+ readonly disconnect: "/disconnect";
44
+ };
45
+ export type BridgeEndpoint = (typeof BRIDGE_ENDPOINTS)[keyof typeof BRIDGE_ENDPOINTS];
41
46
  /** A project identity is the pairing boundary for one companion process. */
42
47
  export interface AgentProjectIdentity {
43
48
  readonly projectId: string;
@@ -54,14 +59,12 @@ export interface AgentRoute {
54
59
  }
55
60
  /** The owner marker lets the browser remove only groups created by the agent. */
56
61
  export type CanvasGroupOwner = "agent" | "user";
57
- /** A browser-reported comparison group. */
58
62
  export interface CanvasGroup {
59
63
  readonly id: string;
60
64
  readonly label: string;
61
65
  readonly owner: CanvasGroupOwner;
62
66
  readonly routes: readonly AgentRoute[];
63
67
  }
64
- /** A compact, serialisable Canvas snapshot returned by the browser. */
65
68
  export interface CanvasState {
66
69
  readonly mode: "inspect" | "canvas";
67
70
  readonly groups: readonly CanvasGroup[];
@@ -287,32 +290,16 @@ export interface ProjectBridgeHandle {
287
290
  };
288
291
  close(): Promise<void>;
289
292
  }
290
- /**
291
- * The `startProjectBridge` export of `@nudge-ui/mcp/project`. Hosts load it
292
- * dynamically from the application's own dependencies, so this type is the
293
- * only compile-time link between the two packages.
294
- */
293
+ /** The `@nudge-ui/mcp/project` export; hosts load it dynamically, so this is the only compile-time link between the packages. */
295
294
  export type StartProjectBridge = (options: ProjectBridgeStartOptions) => Promise<ProjectBridgeHandle>;
296
- /**
297
- * Returns a canonical origin or null. Credentials, paths, and fragments are
298
- * rejected so the browser cannot broaden the pairing boundary accidentally.
299
- */
295
+ /** Canonical origin or null; credentials, paths, and fragments are rejected so pairing cannot broaden accidentally. */
300
296
  export declare function canonicalOrigin(value: unknown): string | null;
301
- /** Returns true only for exact, canonical HTTP(S) origins. */
302
297
  export declare function isCanonicalOrigin(value: unknown): value is string;
303
- /**
304
- * Checks an origin against an explicit allow-list. An empty allow-list does
305
- * not mean wildcard access; callers must choose an origin before pairing.
306
- */
298
+ /** An empty allow-list is not wildcard access; callers must choose an origin before pairing. */
307
299
  export declare function isAllowedOrigin(value: unknown, allowedOrigins: readonly string[]): value is string;
308
- /**
309
- * Validates an agent route and ensures it belongs to the paired origin.
310
- * Fragments are retained because they are useful initial Canvas locations.
311
- */
300
+ /** Fragments are retained because they are useful initial Canvas locations. */
312
301
  export declare function isSameOriginRoute(value: unknown, origin: string): value is AgentRoute;
313
- /** Validates and normalises route values for a presentation command. */
314
302
  export declare function validateRoutes(value: unknown, origin: string): AgentRoute[];
315
- /** Validates the fields shared by every companion message. */
316
303
  export declare function isProtocolVersion(value: unknown): value is AgentProtocolVersion;
317
304
  export declare function isProjectIdentity(value: unknown): value is AgentProjectIdentity;
318
305
  export declare function isAgentSketchCaptureMetadata(value: unknown): value is AgentSketchCaptureMetadata;
@@ -326,21 +313,12 @@ export declare function isCanvasState(value: unknown): value is CanvasState;
326
313
  export declare function isCanvasGroup(value: unknown): value is CanvasGroup;
327
314
  export declare function isCanvasCommand(value: unknown): value is CanvasCommand;
328
315
  export declare function isAgentDeliveredPrompt(value: unknown): value is AgentDeliveredPrompt;
329
- /** A Canvas acknowledgement or result; a successful one never carries an error. */
316
+ /** A successful result never carries an error. */
330
317
  export declare function isCanvasCommandResult(value: unknown): value is CanvasCommandResult;
331
- /** The connection state shown for a pairing, a listener, and the current request. */
332
318
  export declare function deriveConnectionState(status: Pick<AgentStatusSnapshot, "listenerActive" | "paired" | "request">): AgentConnectionState;
333
- /**
334
- * Decodes a status snapshot from any peer. Unknown fields are dropped and the
335
- * connection state is recomputed, so a snapshot can never claim a state its
336
- * own fields contradict.
337
- */
319
+ /** Unknown fields are dropped and the connection state is recomputed, so a snapshot cannot claim a state its own fields contradict. */
338
320
  export declare function decodeAgentStatusSnapshot(value: unknown): AgentStatusSnapshot | null;
339
- /**
340
- * Decodes the event inside a bridge envelope. A Canvas command is passed
341
- * through as received: the Canvas controller validates it so a malformed
342
- * command still receives an error acknowledgement instead of a timeout.
343
- */
321
+ /** A Canvas command is passed through as received: the Canvas controller validates it so a malformed command still receives an error acknowledgement. */
344
322
  export declare function decodeBridgeEvent(value: unknown): BridgeEvent | null;
345
323
  /** Decodes a pairing or takeover response for the exact project and origin requested. */
346
324
  export declare function decodePairingResponse(value: unknown, expected: Pick<PairingRequest, "projectId" | "origin">): PairingResponse | null;
@@ -1,11 +1,4 @@
1
- /**
2
- * Public, host-neutral contracts shared by the Nudge browser inspector and
3
- * its local MCP companion.
4
- *
5
- * This module deliberately has no Node, browser, MCP SDK, or framework
6
- * imports. Hosts can use the same validation and message shapes without
7
- * pulling the companion into a browser bundle.
8
- */
1
+ /** Host-neutral contracts shared by the browser inspector and the local MCP companion; no Node, browser, MCP SDK, or framework imports. */
9
2
  export const AGENT_PROTOCOL_VERSION = 3;
10
3
  export const AGENT_PROTOCOL_LIMITS = {
11
4
  projectId: 256,
@@ -37,6 +30,17 @@ export const AGENT_PROTOCOL_LIMITS = {
37
30
  canvasCardCount: 128,
38
31
  agentClientName: 120,
39
32
  };
33
+ /** Stable loopback endpoint names shared by the browser client and the MCP bridge. */
34
+ export const BRIDGE_ENDPOINTS = {
35
+ health: "/health",
36
+ pair: "/pair",
37
+ takeover: "/takeover",
38
+ events: "/events",
39
+ prompt: "/prompt",
40
+ status: "/status",
41
+ canvasAcknowledgement: "/canvas/ack",
42
+ disconnect: "/disconnect",
43
+ };
40
44
  export const CANVAS_COMMAND_TYPES = [
41
45
  "read-state",
42
46
  "present-routes",
@@ -93,10 +97,7 @@ function encodedByteLength(value) {
93
97
  const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
94
98
  return Math.max(0, Math.floor(value.length * 3 / 4) - padding);
95
99
  }
96
- /**
97
- * Returns a canonical origin or null. Credentials, paths, and fragments are
98
- * rejected so the browser cannot broaden the pairing boundary accidentally.
99
- */
100
+ /** Canonical origin or null; credentials, paths, and fragments are rejected so pairing cannot broaden accidentally. */
100
101
  export function canonicalOrigin(value) {
101
102
  if (!nonEmptyString(value, AGENT_PROTOCOL_LIMITS.origin))
102
103
  return null;
@@ -113,24 +114,17 @@ export function canonicalOrigin(value) {
113
114
  return null;
114
115
  return parsed.origin;
115
116
  }
116
- /** Returns true only for exact, canonical HTTP(S) origins. */
117
117
  export function isCanonicalOrigin(value) {
118
118
  return canonicalOrigin(value) === value;
119
119
  }
120
- /**
121
- * Checks an origin against an explicit allow-list. An empty allow-list does
122
- * not mean wildcard access; callers must choose an origin before pairing.
123
- */
120
+ /** An empty allow-list is not wildcard access; callers must choose an origin before pairing. */
124
121
  export function isAllowedOrigin(value, allowedOrigins) {
125
122
  const origin = canonicalOrigin(value);
126
123
  if (!origin || allowedOrigins.length === 0)
127
124
  return false;
128
125
  return allowedOrigins.some((candidate) => canonicalOrigin(candidate) === origin);
129
126
  }
130
- /**
131
- * Validates an agent route and ensures it belongs to the paired origin.
132
- * Fragments are retained because they are useful initial Canvas locations.
133
- */
127
+ /** Fragments are retained because they are useful initial Canvas locations. */
134
128
  export function isSameOriginRoute(value, origin) {
135
129
  if (!isRecord(value) || !hasOnlyKeys(value, ["url", "title", "label"]))
136
130
  return false;
@@ -154,7 +148,6 @@ export function isSameOriginRoute(value, origin) {
154
148
  return false;
155
149
  return true;
156
150
  }
157
- /** Validates and normalises route values for a presentation command. */
158
151
  export function validateRoutes(value, origin) {
159
152
  if (!Array.isArray(value) || value.length === 0 || value.length > AGENT_PROTOCOL_LIMITS.routeCount) {
160
153
  throw new TypeError(`routes must contain between 1 and ${AGENT_PROTOCOL_LIMITS.routeCount} items`);
@@ -175,7 +168,6 @@ export function validateRoutes(value, origin) {
175
168
  };
176
169
  });
177
170
  }
178
- /** Validates the fields shared by every companion message. */
179
171
  export function isProtocolVersion(value) {
180
172
  return value === AGENT_PROTOCOL_VERSION;
181
173
  }
@@ -418,7 +410,7 @@ function isCanvasCommandError(value) {
418
410
  && nonEmptyString(value.code, 128)
419
411
  && typeof value.message === "string" && value.message.length <= AGENT_PROTOCOL_LIMITS.prompt;
420
412
  }
421
- /** A Canvas acknowledgement or result; a successful one never carries an error. */
413
+ /** A successful result never carries an error. */
422
414
  export function isCanvasCommandResult(value) {
423
415
  if (!isRecord(value) || !hasOnlyKeys(value, ["commandId", "ok", "state", "group", "error"]))
424
416
  return false;
@@ -428,7 +420,6 @@ export function isCanvasCommandResult(value) {
428
420
  && (value.group === undefined || isCanvasGroup(value.group))
429
421
  && (value.error === undefined || (!value.ok && isCanvasCommandError(value.error)));
430
422
  }
431
- /** The connection state shown for a pairing, a listener, and the current request. */
432
423
  export function deriveConnectionState(status) {
433
424
  if (status.request?.status === "delivered")
434
425
  return "delivered";
@@ -460,11 +451,7 @@ function decodeStatusRequest(value) {
460
451
  ...(error === undefined ? {} : { error }),
461
452
  };
462
453
  }
463
- /**
464
- * Decodes a status snapshot from any peer. Unknown fields are dropped and the
465
- * connection state is recomputed, so a snapshot can never claim a state its
466
- * own fields contradict.
467
- */
454
+ /** Unknown fields are dropped and the connection state is recomputed, so a snapshot cannot claim a state its own fields contradict. */
468
455
  export function decodeAgentStatusSnapshot(value) {
469
456
  if (!isRecord(value)
470
457
  || value.protocolVersion !== AGENT_PROTOCOL_VERSION
@@ -491,11 +478,7 @@ export function decodeAgentStatusSnapshot(value) {
491
478
  : {}),
492
479
  };
493
480
  }
494
- /**
495
- * Decodes the event inside a bridge envelope. A Canvas command is passed
496
- * through as received: the Canvas controller validates it so a malformed
497
- * command still receives an error acknowledgement instead of a timeout.
498
- */
481
+ /** A Canvas command is passed through as received: the Canvas controller validates it so a malformed command still receives an error acknowledgement. */
499
482
  export function decodeBridgeEvent(value) {
500
483
  if (!isRecord(value))
501
484
  return null;
package/dist/project.d.ts CHANGED
@@ -19,7 +19,6 @@ export interface ProjectBridgeOptions {
19
19
  readonly workspaceRoot?: string;
20
20
  readonly projectId?: string;
21
21
  readonly origin: string;
22
- /** Other explicit browser origins, such as loopback aliases on the same port. */
23
22
  readonly allowedOrigins?: readonly string[];
24
23
  readonly host?: "127.0.0.1" | "::1" | "localhost";
25
24
  readonly port?: number;
@@ -45,10 +44,6 @@ export interface StoredProjectSession extends ProjectSession {
45
44
  export declare function defaultSessionRegistryRoot(): string;
46
45
  /** Resolves a checkout or worktree without conflating related worktrees. */
47
46
  export declare function resolveWorkspaceRoot(input: string): Promise<string>;
48
- /**
49
- * Starts the project-owned browser bridge and registers it for local MCP
50
- * adapters. The descriptor contains a private control credential and is never
51
- * suitable for browser bundles or user-facing tool results.
52
- */
47
+ /** The descriptor carries a private control credential; never expose it to browser bundles or tool results. */
53
48
  export declare const startProjectBridge: (options: ProjectBridgeOptions) => Promise<ProjectBridgeRuntime>;
54
49
  export {};
package/dist/project.js CHANGED
@@ -9,9 +9,8 @@ import { createLoopbackBridge } from "./bridge.js";
9
9
  const execFileAsync = promisify(execFile);
10
10
  const REGISTRY_SCHEMA_VERSION = 1;
11
11
  export function defaultSessionRegistryRoot() {
12
- // MCP hosts commonly sanitize TMPDIR and XDG_RUNTIME_DIR for stdio child
13
- // processes. The OS account home is stable across the development server
14
- // and agent adapter, so both processes discover the same private registry.
12
+ // MCP hosts sanitize TMPDIR and XDG_RUNTIME_DIR for stdio child processes;
13
+ // the OS account home is stable across the development server and adapter.
15
14
  return join(userInfo().homedir, ".cache", "nudge-ui", "sessions");
16
15
  }
17
16
  async function gitValue(cwd, args) {
@@ -92,11 +91,7 @@ async function closeProjectBridge(descriptorPath, bridge) {
92
91
  await bridge.close();
93
92
  }
94
93
  }
95
- /**
96
- * Starts the project-owned browser bridge and registers it for local MCP
97
- * adapters. The descriptor contains a private control credential and is never
98
- * suitable for browser bundles or user-facing tool results.
99
- */
94
+ /** The descriptor carries a private control credential; never expose it to browser bundles or tool results. */
100
95
  export const startProjectBridge = (async (options) => {
101
96
  const origin = canonicalOrigin(options.origin);
102
97
  if (!origin)
@@ -7,14 +7,11 @@ export interface SessionHealth {
7
7
  readonly claimed: boolean;
8
8
  readonly status: AgentStatusSnapshot;
9
9
  }
10
- /** Represents an HTTP response from a project bridge that could be classified. */
11
10
  export declare class ProjectSessionResponseError extends Error {
12
11
  readonly status: number;
13
12
  constructor(status: number, message: string);
14
13
  }
15
- /** Reads and validates a bridge's health; an invalid body is a classified response error. */
16
14
  export declare function readSessionHealth(session: StoredProjectSession, timeoutMs?: number): Promise<SessionHealth>;
17
- /** Owns one project's claim, heartbeat, and authenticated control requests. */
18
15
  export declare class ProjectSessionClient {
19
16
  readonly descriptor: StoredProjectSession;
20
17
  readonly agentId: string;
@@ -3,7 +3,6 @@ import { decodeAgentStatusSnapshot, isAgentDeliveredPrompt, isCanvasCommandResul
3
3
  import { AGENT_CONTROL_ENDPOINTS } from "./protocol.js";
4
4
  const CONTROL_TIMEOUT_MS = 5_000;
5
5
  const CANVAS_TIMEOUT_MS = 65_000;
6
- /** Represents an HTTP response from a project bridge that could be classified. */
7
6
  export class ProjectSessionResponseError extends Error {
8
7
  status;
9
8
  constructor(status, message) {
@@ -48,11 +47,9 @@ async function requestJson(session, path, decode, init = {}, { signal, timeoutMs
48
47
  }
49
48
  return decoded;
50
49
  }
51
- /** Reads and validates a bridge's health; an invalid body is a classified response error. */
52
50
  export async function readSessionHealth(session, timeoutMs = CONTROL_TIMEOUT_MS) {
53
51
  return await requestJson(session, AGENT_CONTROL_ENDPOINTS.health, decodeSessionHealth, {}, { timeoutMs });
54
52
  }
55
- /** Owns one project's claim, heartbeat, and authenticated control requests. */
56
53
  export class ProjectSessionClient {
57
54
  descriptor;
58
55
  agentId;
@@ -1,23 +1,8 @@
1
- /**
2
- * Companion-facing aliases and transport envelopes.
3
- *
4
- * The domain contracts live in the private shared protocol module. This public
5
- * subpath keeps transport names discoverable for Node consumers while
6
- * preserving one protocol vocabulary for browser and agent adapters.
7
- */
8
1
  export { AGENT_PROTOCOL_LIMITS, AGENT_PROTOCOL_VERSION, CANVAS_COMMAND_TYPES, canonicalOrigin, isAgentPromptRequest, isAgentSketchAttachment, isAgentSketchCaptureMetadata, isAgentSketchMetadata, isAgentStatusUpdate, isAgentActivity, isAllowedOrigin, isCanvasCommand, isCanvasGroup, isCanvasState, isCanonicalOrigin, isProjectIdentity, isSameOriginRoute, protocolError, validateSketchAttachments, validateRoutes, } from "./internal/agent-protocol.js";
9
2
  export type { AgentActivity, BridgeActivityEvent, AgentConnectionState, AgentProjectIdentity, AgentPromptRequest, AgentDeliveredPrompt, AgentSketchAttachment, AgentSketchCaptureMetadata, AgentSketchMetadata, AgentRequestOutcome, AgentRequestStatus, AgentRoute, AgentStatusSnapshot, AgentStatusUpdate, BridgeCanvasCommandEvent, BridgeConnectedEvent, BridgeDisconnectedEvent, BridgeEnvelope, BridgeEvent, BridgeEventType, BridgeStatusEvent, CanvasCommand, CanvasCommandAcknowledgement, CanvasCommandError, CanvasCommandResult, CanvasGroup, CanvasGroupOwner, CanvasState, FitCanvasCommand, FocusCanvasGroupCommand, PairingRequest, PairingResponse, PresentRoutesCommand, PromptDispatchRequest, PromptDispatchResponse, ReadCanvasStateCommand, RemoveCanvasGroupCommand, StatusEventRequest, } from "./internal/agent-protocol.js";
10
3
  /** Stable endpoint names used by the loopback browser bridge. */
11
- export declare const BRIDGE_ENDPOINTS: {
12
- readonly health: "/health";
13
- readonly pair: "/pair";
14
- readonly takeover: "/takeover";
15
- readonly events: "/events";
16
- readonly prompt: "/prompt";
17
- readonly status: "/status";
18
- readonly canvasAcknowledgement: "/canvas/ack";
19
- readonly disconnect: "/disconnect";
20
- };
4
+ export { BRIDGE_ENDPOINTS } from "./internal/agent-protocol.js";
5
+ export type { BridgeEndpoint } from "./internal/agent-protocol.js";
21
6
  /** Private, loopback-only endpoints used by an MCP adapter process. */
22
7
  export declare const AGENT_CONTROL_ENDPOINTS: {
23
8
  readonly health: "/__nudge/agent/health";
@@ -31,8 +16,6 @@ export declare const AGENT_CONTROL_ENDPOINTS: {
31
16
  readonly activity: "/__nudge/agent/activity";
32
17
  readonly canvas: "/__nudge/agent/canvas";
33
18
  };
34
- export type BridgeEndpoint = (typeof BRIDGE_ENDPOINTS)[keyof typeof BRIDGE_ENDPOINTS];
35
- /** Error body returned by every rejected bridge request. */
36
19
  export interface BridgeHttpError {
37
20
  readonly error: {
38
21
  readonly code: string;
package/dist/protocol.js CHANGED
@@ -1,22 +1,6 @@
1
- /**
2
- * Companion-facing aliases and transport envelopes.
3
- *
4
- * The domain contracts live in the private shared protocol module. This public
5
- * subpath keeps transport names discoverable for Node consumers while
6
- * preserving one protocol vocabulary for browser and agent adapters.
7
- */
8
1
  export { AGENT_PROTOCOL_LIMITS, AGENT_PROTOCOL_VERSION, CANVAS_COMMAND_TYPES, canonicalOrigin, isAgentPromptRequest, isAgentSketchAttachment, isAgentSketchCaptureMetadata, isAgentSketchMetadata, isAgentStatusUpdate, isAgentActivity, isAllowedOrigin, isCanvasCommand, isCanvasGroup, isCanvasState, isCanonicalOrigin, isProjectIdentity, isSameOriginRoute, protocolError, validateSketchAttachments, validateRoutes, } from "./internal/agent-protocol.js";
9
2
  /** Stable endpoint names used by the loopback browser bridge. */
10
- export const BRIDGE_ENDPOINTS = {
11
- health: "/health",
12
- pair: "/pair",
13
- takeover: "/takeover",
14
- events: "/events",
15
- prompt: "/prompt",
16
- status: "/status",
17
- canvasAcknowledgement: "/canvas/ack",
18
- disconnect: "/disconnect",
19
- };
3
+ export { BRIDGE_ENDPOINTS } from "./internal/agent-protocol.js";
20
4
  /** Private, loopback-only endpoints used by an MCP adapter process. */
21
5
  export const AGENT_CONTROL_ENDPOINTS = {
22
6
  health: "/__nudge/agent/health",
package/dist/server.d.ts CHANGED
@@ -11,7 +11,6 @@ export interface DiscoveredAgentAdapter {
11
11
  start(transport?: Transport): Promise<void>;
12
12
  close(): Promise<void>;
13
13
  }
14
- /** Creates a stdio MCP adapter that discovers project-owned bridges. */
15
14
  export declare function createDiscoveredAgentAdapter(options?: {
16
15
  readonly registryRoot?: string;
17
16
  readonly serverName?: string;
package/dist/server.js CHANGED
@@ -278,7 +278,6 @@ function installTools(mcpServer, routing) {
278
278
  }
279
279
  });
280
280
  }
281
- /** Creates a stdio MCP adapter that discovers project-owned bridges. */
282
281
  export function createDiscoveredAgentAdapter(options = {}) {
283
282
  const router = new AdapterRouting(options.registryRoot);
284
283
  const mcpServer = new McpServer({
@@ -11,7 +11,5 @@ export interface SessionInspection {
11
11
  readonly unreachable: readonly Pick<StoredProjectSession, "workspaceRoot" | "appRoot" | "sessionId">[];
12
12
  readonly live: LiveProjectSession[];
13
13
  }
14
- /** Separates absent, invalid, incompatible, and unreachable registrations. */
15
14
  export declare function inspectProjectSessions(registryRoot: string): Promise<SessionInspection>;
16
- /** Keeps only compatible bridges that answer authenticated probes. */
17
15
  export declare function readLiveProjectSessions(registryRoot: string): Promise<LiveProjectSession[]>;
@@ -4,7 +4,6 @@ import { AGENT_PROTOCOL_VERSION } from "./internal/agent-protocol.js";
4
4
  import { ProjectSessionResponseError, readSessionHealth } from "./projectSessionClient.js";
5
5
  const PROBE_TIMEOUT_MS = 750;
6
6
  const MAX_DESCRIPTOR_BYTES = 32 * 1024;
7
- /** Separates absent, invalid, incompatible, and unreachable registrations. */
8
7
  export async function inspectProjectSessions(registryRoot) {
9
8
  const names = (await readRegistryDirectory(registryRoot)).filter((name) => name.endsWith(".json"));
10
9
  const records = await Promise.all(names.map((name) => readDescriptor(resolve(registryRoot, name))));
@@ -20,7 +19,6 @@ export async function inspectProjectSessions(registryRoot) {
20
19
  live: probes.flatMap((probe) => probe.kind === "live" ? [probe.session] : []),
21
20
  };
22
21
  }
23
- /** Keeps only compatible bridges that answer authenticated probes. */
24
22
  export async function readLiveProjectSessions(registryRoot) {
25
23
  return (await inspectProjectSessions(registryRoot)).live;
26
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nudge-ui/mcp",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Optional local MCP companion for pairing Nudge UI with coding agents.",
5
5
  "license": "MIT",
6
6
  "repository": {