@particle-academy/agent-integrations 0.34.0 → 0.36.0

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bridges/navigation.ts","../src/sharing/use-co-browse-session.ts","../src/components/BridgedForm/BridgedForm.tsx","../src/components/ScreensActivityBridge/ScreensActivityBridge.tsx","../src/components/CoBrowsePresence/CoBrowsePresence.tsx","../src/components/CoBrowseCursorLayer/CoBrowseCursorLayer.tsx","../src/components/SimulateUsersButton/SimulateUsersButton.tsx"],"names":["DEFAULT_AGENT","useRef","useEffect","jsx","useState","jsxs"],"mappings":"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","file":"index.js","sourcesContent":["import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport type { AgentTarget } from \"../presence/types\";\nimport { pushUndoEntry } from \"../undo/undo-stack\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\n\n/**\n * One interactive element the agent can act on, addressed by a STABLE handle\n * (not a CSS selector) so the agent drives the page the Human+ way — never DOM\n * scraping. The host builds these in `describe()` (data-co-handle → name/id →\n * ARIA role + accessible name).\n */\nexport type PageAction = {\n /** Stable, opaque handle the agent passes back to act on this element. */\n handle: string;\n /** ARIA-ish role: \"link\" | \"button\" | \"textbox\" | \"checkbox\" | \"select\" | … */\n role: string;\n /** Accessible name / label. */\n label: string;\n /** Current value for inputs (omitted/masked for sensitive fields). */\n value?: unknown;\n /** True when activating this is destructive / submits (agent should stage). */\n destructive?: boolean;\n};\n\n/** The page as the agent sees it: where it is + what it can do. */\nexport type PageSnapshot = {\n url: string;\n title: string;\n actions: PageAction[];\n /** Monotonic host revision. Human input advances it and invalidates stale agent intent. */\n revision?: number;\n};\n\n/** A write the host may want the human to confirm (trust-but-verify). */\nexport type NavigationConfirmRequest = {\n action: \"submit\" | \"click\";\n handle: string;\n label: string;\n};\n\n/**\n * Host-provided adapter. In the sandbox this is backed by Inertia's `router` +\n * a DOM walker (see resources/js/agent/CoBrowseProvider.tsx). Every method\n * works on stable handles, never raw selectors.\n */\nexport type NavigationBridgeAdapter = {\n /** Optional fancy-screens screen id for presence targeting. */\n screenId?: string;\n /** Current location. */\n getLocation: () => { url: string; title: string };\n /** Current human-control revision. Omit to disable stale-intent protection. */\n getRevision?: () => number;\n /** Snapshot of the page's actionable elements (stable handles + labels). */\n describe: () => PageSnapshot;\n /** Visible text / heading outline for grounding (optional). */\n read?: () => string;\n /** Navigate to a URL (host wires to router.visit). */\n visit: (url: string) => void | Promise<void>;\n back?: () => void | Promise<void>;\n forward?: () => void | Promise<void>;\n /** Scroll to coords or to a handle's element. */\n scrollTo: (opts: { x?: number; y?: number; handle?: string }) => void;\n scrollBy: (dy: number) => void;\n /** Set a field's value by handle (host dispatches input/change for React). */\n setField: (handle: string, value: unknown) => { ok: boolean; error?: string };\n /** Activate an element by handle. */\n click: (handle: string) => { ok: boolean; error?: string };\n /** Submit a form by handle. */\n submit: (handle: string) => Promise<{ ok: boolean; error?: string }> | { ok: boolean; error?: string };\n /**\n * Viewport rect of a handle's element, for agent-presence rendering (cursor +\n * highlight). Returned in tool `meta.rect` so `<CoBrowseCursorLayer>` can show\n * the agent acting on the page. Optional — omit and there's just no cursor.\n */\n rectFor?: (handle: string) => { x: number; y: number; width: number; height: number } | null;\n /**\n * Trust-but-verify hook. When `pendingMode` is on, `page_submit` and\n * destructive `page_click` route through this; the host shows a prompt and\n * resolves true (proceed) / false (declined).\n */\n confirm?: (req: NavigationConfirmRequest) => Promise<boolean>;\n};\n\nexport type NavigationBridgeOptions = {\n adapter: NavigationBridgeAdapter;\n /** Identity tagged into activity events (so the human sees who's driving). */\n agent?: { id: string; name?: string; color?: string };\n /** Route submit + destructive clicks through `adapter.confirm`. Default true. */\n pendingMode?: boolean;\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/**\n * registerNavigationBridge — site-wide co-browsing. Lets a connected agent\n * navigate, scroll, and (with staged confirm) fill + click any page, addressed\n * by stable handles. Pairs with `useCoBrowseSession` (server + relay) and\n * `<CoBrowsePresence>` (the human's view of the agent). The 12th Fancy bridge.\n */\nexport function registerNavigationBridge(\n host: ToolHost,\n options: NavigationBridgeOptions,\n): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const pendingMode = options.pendingMode ?? true;\n const disposers: Array<() => void> = [];\n let groundedRevision: number | null = null;\n\n const staleIntent = () => {\n const current = adapter.getRevision?.();\n if (current === undefined) return null;\n if (groundedRevision === null || groundedRevision !== current) {\n return errorResult(\n `Human took control at page revision ${current}. This agent action was cancelled; call page_describe before acting again.`,\n );\n }\n return null;\n };\n\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const target = (label: string, elementId?: string): AgentTarget => ({\n kind: \"navigation\",\n screenId: adapter.screenId,\n elementId,\n label,\n });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n activity: false | ((args: JsonObject) => AgentTarget),\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = activity\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent: { id: agent.id, name: agent.name, color: agent.color },\n kind: \"navigation\",\n screenId: adapter.screenId,\n resolveTarget: ({ args }) => activity(args),\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n {\n name,\n description,\n inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false },\n },\n final as any,\n ),\n );\n };\n\n // ───────────── Read ─────────────\n\n reg(\n \"page_describe\",\n \"Describe the current page: its URL, title, and the interactive elements you can act on (each with a stable `handle`, role, and label). Call this first, and again after navigating.\",\n {},\n [],\n () => {\n const snap = adapter.describe();\n const revision = adapter.getRevision?.();\n if (revision !== undefined) {\n snap.revision = revision;\n groundedRevision = revision;\n }\n const text = [\n `URL: ${snap.url}`,\n `Title: ${snap.title}`,\n \"\",\n ...snap.actions.map((a) => `[${a.handle}] ${a.role}: ${a.label}${a.destructive ? \" (destructive)\" : \"\"}`),\n ].join(\"\\n\");\n return textResult(text, snap);\n },\n () => target(\"Inspect page\"),\n );\n\n reg(\n \"page_read\",\n \"Read the page's visible text / heading outline for grounding.\",\n {},\n [],\n () => textResult(adapter.read ? adapter.read() : \"(host did not provide page text)\"),\n () => target(\"Read page\"),\n );\n\n reg(\n \"page_focus\",\n \"Move the agent's visible focus to an interactive element by stable handle without activating it.\",\n { handle: { type: \"string\" } },\n [\"handle\"],\n (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const handle = String(args.handle ?? \"\");\n const action = adapter.describe().actions.find((candidate) => candidate.handle === handle);\n if (!action) return errorResult(`No element for handle \"${handle}\"`);\n return textResult(`Focused ${handle}`, {\n handle,\n rect: adapter.rectFor?.(handle) ?? undefined,\n });\n },\n (args) => target(`Focus ${String(args.handle ?? \"\")}`, String(args.handle ?? \"\")),\n );\n\n // ───────────── Navigate / scroll ─────────────\n\n reg(\n \"nav_visit\",\n \"Navigate to a URL (same-site path or absolute). The human watches the page change.\",\n { url: { type: \"string\", description: \"Path like /packages or an absolute URL.\" } },\n [\"url\"],\n async (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const url = String(args.url ?? \"\");\n if (!url) return errorResult(\"url is required\");\n // Scheme allow-list: permit only same-site/relative paths and http(s)\n // absolutes. A `javascript:` / `data:` / `file:` / `vbscript:` URL handed\n // to a host that wires visit() to window.location would execute as the\n // human — a semi-trusted agent (steerable via page_read prompt injection)\n // must not reach those.\n const scheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(url)?.[1]?.toLowerCase();\n if (scheme && scheme !== \"http\" && scheme !== \"https\") {\n return errorResult(\n `Refusing to navigate to a '${scheme}:' URL. Only http(s) URLs or same-site paths are allowed.`,\n );\n }\n const from = adapter.getLocation().url;\n await adapter.visit(url);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"navigation\",\n action: \"nav_visit\",\n label: `Navigate to ${url}`,\n undo: () => {\n adapter.visit(from);\n },\n redo: () => {\n adapter.visit(url);\n },\n });\n return textResult(`Navigated to ${url}`, { url });\n },\n (args) => target(`Navigate → ${String(args.url ?? \"\")}`),\n );\n\n reg(\n \"nav_back\",\n \"Go back to the previous page.\",\n {},\n [],\n async () => {\n const stale = staleIntent();\n if (stale) return stale;\n if (!adapter.back) return errorResult(\"Host did not provide back navigation.\");\n await adapter.back();\n return textResult(\"Went back\");\n },\n () => target(\"Back\"),\n );\n\n reg(\n \"nav_forward\",\n \"Go forward to the next page.\",\n {},\n [],\n async () => {\n const stale = staleIntent();\n if (stale) return stale;\n if (!adapter.forward) return errorResult(\"Host did not provide forward navigation.\");\n await adapter.forward();\n return textResult(\"Went forward\");\n },\n () => target(\"Forward\"),\n );\n\n reg(\n \"nav_scroll_to\",\n \"Scroll the page to absolute coordinates, or to a specific element by its handle.\",\n {\n handle: { type: \"string\", description: \"Scroll this element into view.\" },\n x: { type: \"number\" },\n y: { type: \"number\" },\n },\n [],\n (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const handle = typeof args.handle === \"string\" ? args.handle : undefined;\n adapter.scrollTo({\n handle,\n x: typeof args.x === \"number\" ? args.x : undefined,\n y: typeof args.y === \"number\" ? args.y : undefined,\n });\n return textResult(\"Scrolled\", handle ? { handle, rect: adapter.rectFor?.(handle) ?? undefined } : undefined);\n },\n () => target(\"Scroll\"),\n );\n\n reg(\n \"nav_scroll_by\",\n \"Scroll the page by a vertical delta in pixels (negative scrolls up).\",\n { dy: { type: \"number\" } },\n [\"dy\"],\n (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n adapter.scrollBy(Number(args.dy ?? 0));\n return textResult(`Scrolled by ${Number(args.dy ?? 0)}px`);\n },\n () => target(\"Scroll\"),\n );\n\n // ───────────── Co-drive (fill / click / submit) ─────────────\n\n reg(\n \"page_set_field\",\n \"Set a form field's value by handle. The host updates the controlled input and the human sees it change.\",\n {\n handle: { type: \"string\" },\n value: { description: \"Value to set; type matches the field.\" },\n },\n [\"handle\", \"value\"],\n (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const handle = String(args.handle ?? \"\");\n const res = adapter.setField(handle, args.value);\n if (!res.ok) return errorResult(res.error ?? `Could not set ${handle}`);\n return textResult(`${handle} ← ${JSON.stringify(args.value)}`, { handle, value: args.value, rect: adapter.rectFor?.(handle) ?? undefined });\n },\n (args) => target(`Set ${String(args.handle ?? \"\")}`, String(args.handle ?? \"\")),\n );\n\n reg(\n \"page_click\",\n \"Activate an element by handle (link, button, checkbox…). Destructive elements are staged for the human to confirm.\",\n { handle: { type: \"string\" } },\n [\"handle\"],\n async (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const handle = String(args.handle ?? \"\");\n const action = adapter.describe().actions.find((a) => a.handle === handle);\n const rect = adapter.rectFor?.(handle) ?? undefined; // capture before the click may navigate away\n if (pendingMode && action?.destructive && adapter.confirm) {\n const ok = await adapter.confirm({ action: \"click\", handle, label: action.label });\n if (!ok) return errorResult(\"Declined by user\");\n }\n const res = adapter.click(handle);\n if (!res.ok) return errorResult(res.error ?? `Could not click ${handle}`);\n return textResult(`Clicked ${handle}`, { handle, rect });\n },\n (args) => target(`Click ${String(args.handle ?? \"\")}`, String(args.handle ?? \"\")),\n );\n\n reg(\n \"page_submit\",\n \"Submit a form by handle. Always staged for the human to confirm when pendingMode is on.\",\n { handle: { type: \"string\" } },\n [\"handle\"],\n async (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const handle = String(args.handle ?? \"\");\n const rect = adapter.rectFor?.(handle) ?? undefined; // capture before the submit navigates\n if (pendingMode && adapter.confirm) {\n const ok = await adapter.confirm({ action: \"submit\", handle, label: handle });\n if (!ok) return errorResult(\"Declined by user\");\n }\n const res = await adapter.submit(handle);\n if (!res.ok) return errorResult(res.error ?? \"Submit failed\");\n return textResult(`Submitted ${handle}`, { handle, rect });\n },\n (args) => target(`Submit ${String(args.handle ?? \"\")}`, String(args.handle ?? \"\")),\n );\n\n return {\n id: \"navigation\",\n title: \"Co-browsing\",\n dispose: () => {\n for (const d of disposers) d();\n },\n };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { MicroMcpServer } from \"../mcp/server\";\nimport { attachInProcess } from \"../mcp/transports\";\nimport { attachSseRelay, type RelayState, type SseRelayTransport } from \"./sse-relay\";\nimport { createSessionDescriptor, type SessionDescriptor } from \"./token\";\nimport { emitActivity } from \"../presence/registry\";\nimport { registerNavigationBridge, type NavigationBridgeAdapter } from \"../bridges/navigation\";\n\n/** A thing the human did, surfaced so the connected agent stays aware. */\nexport type CoBrowseUserEvent =\n | { kind: \"navigation\"; url: string; title?: string; revision?: number }\n | { kind: \"scroll\"; y: number; revision?: number }\n | { kind: \"form\"; handle: string; value?: unknown; masked?: boolean; revision?: number }\n | { kind: \"click\"; handle: string; label?: string; revision?: number };\n\nexport type UseCoBrowseSessionOptions = {\n /**\n * The navigation adapter (Inertia + DOM in the sandbox). MUST be stable —\n * its methods should read live state via refs, since the bridge captures it\n * once on mount. Memoize it.\n */\n adapter: NavigationBridgeAdapter;\n /** Identity for the agent's presence (cursor/log color + name). */\n agent?: { id: string; name?: string; color?: string };\n /** Relay base path. Default \"/agent-relay\" (the generic frame broker). */\n relayBaseUrl?: string;\n /** MCP server info advertised to the agent. */\n info?: { name: string; version: string; instructions?: string };\n /** Register extra bridges (forms/screens/…) on the same server. */\n extraBridges?: (server: MicroMcpServer) => void;\n /** CSRF token for the relay register/unregister POSTs. */\n csrfToken?: () => string | null | undefined;\n /** Stage submit + destructive clicks for human confirm. Default true. */\n pendingMode?: boolean;\n};\n\nexport type CoBrowseSession = {\n server: MicroMcpServer | null;\n session: SessionDescriptor | null;\n relayState: RelayState;\n startShare: () => Promise<void>;\n stopShare: () => void;\n /**\n * Report a human action so the connected agent is notified. Emits a\n * `source:\"user\"` activity event, which the SSE relay forwards to the agent\n * as a `notifications/agent_activity` frame.\n */\n observeUser: (event: CoBrowseUserEvent) => void;\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\nconst USER = { id: \"human\", name: \"You\" };\n\n/**\n * Site-wide co-browsing session: one persistent in-page `MicroMcpServer` running\n * the navigation bridge, joinable by an external agent over the relay. Mount it\n * once at the app root; render `<CoBrowsePresence>` to show the agent + a Stop\n * control. The host wires `observeUser(...)` to navigation/scroll/form listeners\n * so the agent sees what the human does.\n */\nexport function useCoBrowseSession(options: UseCoBrowseSessionOptions): CoBrowseSession {\n const { adapter, extraBridges } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const relayBaseUrl = options.relayBaseUrl ?? \"/agent-relay\";\n\n const serverRef = useRef<MicroMcpServer | null>(null);\n const relayRef = useRef<SseRelayTransport | null>(null);\n const detachInProc = useRef<(() => void) | null>(null);\n const disposeBridge = useRef<(() => void) | null>(null);\n\n const [session, setSession] = useState<SessionDescriptor | null>(null);\n const [relayState, setRelayState] = useState<RelayState>(\"idle\");\n\n // Build the server + bridges once. The adapter is captured here, so it must\n // be stable (its methods read live state).\n useEffect(() => {\n const server = new MicroMcpServer({\n info: options.info ?? { name: \"fancy-co-browse\", version: \"0.1.0\" },\n instructions:\n options.info?.instructions ??\n \"Co-browse with a watching human. Call page_describe first; navigate, scroll, and (with confirm) fill/click via stable handles. You receive notifications/agent_activity for the human's actions (source:\\\"user\\\").\",\n });\n const bridge = registerNavigationBridge(server, { adapter, agent, pendingMode: options.pendingMode });\n extraBridges?.(server);\n const inProc = attachInProcess(server);\n detachInProc.current = () => inProc.close();\n disposeBridge.current = bridge.dispose;\n serverRef.current = server;\n\n return () => {\n relayRef.current?.close();\n relayRef.current = null;\n disposeBridge.current?.();\n detachInProc.current?.();\n serverRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const startShare = useCallback(async () => {\n const server = serverRef.current;\n if (!server || relayRef.current) return;\n const descriptor = createSessionDescriptor();\n const csrf = options.csrfToken?.() ?? \"\";\n const response = await fetch(`${relayBaseUrl}/register`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-csrf-token\": csrf },\n body: JSON.stringify({ session: descriptor.id, token: descriptor.token }),\n });\n if (!response.ok) {\n throw new Error(`Relay registration failed (${response.status})`);\n }\n const relay = attachSseRelay(server, { baseUrl: relayBaseUrl, sessionId: descriptor.id, token: descriptor.token });\n relay.onStateChange(setRelayState);\n relayRef.current = relay;\n setSession(descriptor);\n }, [relayBaseUrl, options]);\n\n const stopShare = useCallback(() => {\n const current = session;\n relayRef.current?.close();\n relayRef.current = null;\n setRelayState(\"idle\");\n setSession(null);\n if (current) {\n const csrf = options.csrfToken?.() ?? \"\";\n void fetch(`${relayBaseUrl}/${current.id}/unregister?token=${encodeURIComponent(current.token)}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-csrf-token\": csrf },\n }).catch(() => {});\n }\n }, [relayBaseUrl, options, session]);\n\n const observeUser = useCallback((event: CoBrowseUserEvent) => {\n const label =\n event.kind === \"navigation\"\n ? `You navigated to ${event.url}`\n : event.kind === \"scroll\"\n ? \"You scrolled\"\n : event.kind === \"click\"\n ? `You clicked ${event.label ?? event.handle}`\n : `You edited ${event.handle}${event.masked ? \" (hidden)\" : \"\"}`;\n emitActivity({\n agentId: USER.id,\n agentName: USER.name,\n source: \"user\",\n target: { kind: \"navigation\", label },\n action: `user_${event.kind}`,\n timestamp: Date.now(),\n meta: event as Record<string, unknown>,\n });\n }, []);\n\n return { server: serverRef.current, session, relayState, startShare, stopShare, observeUser };\n}\n","import { type ReactNode, useEffect, useMemo, useRef } from \"react\";\nimport type { MicroMcpServer } from \"../../mcp/server\";\nimport { registerFormBridge, type FormBridgeAdapter, type FormFieldDescriptor } from \"../../bridges/forms\";\n\nexport type BridgedFormProps = {\n /** Stable id for this form. Used by agents in `form_*` tool calls. */\n id: string;\n /** Human title (also surfaced as the bridge title). */\n title?: string;\n /** Optional fancy-screens screen id this form lives in. */\n screenId?: string;\n /** Field descriptors — drives the agent-facing schema. */\n fields: FormFieldDescriptor[];\n /** Controlled values. */\n values: Record<string, unknown>;\n /** Setter — hosts pass their setState. */\n onChange: (next: Record<string, unknown>) => void;\n /** Optional submit handler. */\n onSubmit?: () => Promise<{ ok: boolean; values?: Record<string, unknown>; error?: string }>;\n /** The MicroMcpServer the bridge registers against. Pass null/undefined\n * to render without a bridge (useful for stories / non-shared use). */\n server?: MicroMcpServer | null;\n /** Identity used in activity events. */\n agent?: { id: string; name?: string; color?: string };\n children: ReactNode;\n};\n\n/**\n * BridgedForm — wraps a react-fancy form (or any controlled inputs)\n * with a `registerFormBridge` lifecycle. Children render the actual form\n * using `values` + `onChange`; this component only manages the bridge.\n *\n * Hosts use it like:\n *\n * <BridgedForm id=\"signup\" fields={...} values={values} onChange={setValues} server={server}>\n * <Field><Input value={values.email} onValueChange={(v) => onChange({ ...values, email: v })} /></Field>\n * ...\n * </BridgedForm>\n *\n * Agents can then call form_describe, form_set_value, form_submit, etc.\n */\nexport function BridgedForm({\n id,\n title,\n screenId,\n fields,\n values,\n onChange,\n onSubmit,\n server,\n agent,\n children,\n}: BridgedFormProps) {\n // Refs so the adapter sees fresh values without re-installing the bridge.\n const valuesRef = useRef(values);\n const onChangeRef = useRef(onChange);\n const fieldsRef = useRef(fields);\n const submitRef = useRef(onSubmit);\n useEffect(() => { valuesRef.current = values; }, [values]);\n useEffect(() => { onChangeRef.current = onChange; }, [onChange]);\n useEffect(() => { fieldsRef.current = fields; }, [fields]);\n useEffect(() => { submitRef.current = onSubmit; }, [onSubmit]);\n\n const focusElement = (name: string) => {\n if (typeof document === \"undefined\") return;\n const el = document.querySelector(`[data-form-id=\"${id}\"] [name=\"${name}\"]`) as HTMLElement | null;\n el?.focus();\n };\n\n const adapter = useMemo<FormBridgeAdapter>(() => ({\n id,\n title,\n screenId,\n getFields: () => fieldsRef.current,\n getValue: (name) => valuesRef.current[name],\n getValues: () => ({ ...valuesRef.current }),\n setValue: (name, v) => onChangeRef.current({ ...valuesRef.current, [name]: v }),\n setValues: (next) => onChangeRef.current({ ...valuesRef.current, ...next }),\n focus: focusElement,\n submit: async () => {\n if (!submitRef.current) {\n return { ok: true, values: { ...valuesRef.current } };\n }\n return submitRef.current();\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }), [id, title, screenId]);\n\n useEffect(() => {\n if (!server) return;\n const bridge = registerFormBridge(server, { adapter, agent });\n return () => bridge.dispose();\n }, [server, adapter, agent]);\n\n return <div data-form-id={id}>{children}</div>;\n}\n","import { useEffect } from \"react\";\nimport { onActivity } from \"../../presence/registry\";\n\n/**\n * Loose shape of the fancy-screens system context — kept here so this\n * component doesn't hard-import `@particle-academy/fancy-screens`.\n */\ntype ScreenSystemLike = {\n registry: Map<string, { id: string; agentActivity?: unknown }>;\n updateScreen: (id: string, patch: { agentActivity?: unknown }) => void;\n};\n\nexport type ScreensActivityBridgeProps = {\n /** The value returned by `useScreenSystem()` from fancy-screens. */\n system: ScreenSystemLike;\n /** ms to wait after the last activity before clearing the screen's badge. Default 1500. */\n fadeMs?: number;\n};\n\n/**\n * ScreensActivityBridge — subscribe to the in-process activity registry\n * and patch each event into the matching screen's `agentActivity` field.\n * Fade-out clears the badge after `fadeMs`.\n *\n * Use it once near the root of your app, ABOVE every <Screen>:\n *\n * const system = useScreenSystem();\n * <>\n * <ScreensActivityBridge system={system} />\n * <Screen id=\"dashboard\">…</Screen>\n * <Screen id=\"form\">…</Screen>\n * </>\n *\n * Renders nothing; pure side-effect component.\n */\nexport function ScreensActivityBridge({ system, fadeMs = 1500 }: ScreensActivityBridgeProps) {\n useEffect(() => {\n const fadeTimers = new Map<string, ReturnType<typeof setTimeout>>();\n const off = onActivity((event) => {\n const screenId = event.target.screenId;\n if (!screenId) return;\n // Only patch screens that are currently registered.\n if (!system.registry.has(screenId)) return;\n const activity = {\n agentId: event.agentId,\n agentName: event.agentName,\n agentColor: event.agentColor,\n action: event.action,\n timestamp: event.timestamp,\n elementId: event.target.elementId,\n label: event.target.label,\n };\n system.updateScreen(screenId, { agentActivity: activity });\n const prev = fadeTimers.get(screenId);\n if (prev) clearTimeout(prev);\n fadeTimers.set(\n screenId,\n setTimeout(() => {\n system.updateScreen(screenId, { agentActivity: null });\n fadeTimers.delete(screenId);\n }, event.ttlMs ?? fadeMs),\n );\n });\n return () => {\n off();\n for (const t of fadeTimers.values()) clearTimeout(t);\n };\n }, [system, fadeMs]);\n return null;\n}\n","import { useAgentActivity } from \"../../presence/use-agent-activity\";\nimport { ShareControls } from \"../ShareControls/ShareControls\";\nimport { ConnectorButtons } from \"../../connectors/ConnectorButtons\";\nimport type { CoBrowseSession } from \"../../sharing/use-co-browse-session\";\n\nexport type CoBrowsePresenceProps = {\n /** The session from `useCoBrowseSession`. */\n session: CoBrowseSession;\n /** Public MCP/connect URL shown to the user (for ConnectorButtons), optional. */\n connectUrl?: string;\n /** Base URL used to build the shareable session link. */\n shareBaseUrl?: string;\n className?: string;\n};\n\n/**\n * The human's view of a site-wide co-browsing session: a \"Let an agent drive\"\n * starter, the share/connect surface once started, a live \"agent is driving\"\n * status with the latest action, and a Stop / take-back-control button.\n *\n * Staged-action confirms are rendered by the HOST (via the navigation adapter's\n * `confirm`), so this component stays presentation-only.\n */\nexport function CoBrowsePresence({ session, connectUrl, shareBaseUrl, className }: CoBrowsePresenceProps) {\n const { events } = useAgentActivity(undefined, { capacity: 40 });\n const lastAgentAction = [...events].reverse().find((e) => (e.source ?? \"agent\") !== \"user\");\n const connected = session.relayState === \"open\";\n\n if (!session.session) {\n return (\n <div className={className} data-co-browse-presence=\"idle\">\n <button type=\"button\" onClick={() => void session.startShare()} data-co-browse-start>\n Let an agent drive\n </button>\n </div>\n );\n }\n\n return (\n <div className={className} data-co-browse-presence={connected ? \"connected\" : \"waiting\"}>\n <div data-co-browse-bar>\n <span data-co-browse-dot data-state={session.relayState} />\n <span data-co-browse-status>\n {connected ? \"Agent is driving\" : `Waiting for an agent… (${session.relayState})`}\n </span>\n {lastAgentAction && <span data-co-browse-last>{lastAgentAction.target?.label ?? lastAgentAction.action}</span>}\n <button type=\"button\" onClick={session.stopShare} data-co-browse-stop>\n Stop\n </button>\n </div>\n\n <ShareControls\n session={session.session}\n onStart={() => void session.startShare()}\n onStop={session.stopShare}\n status={session.relayState}\n shareBaseUrl={shareBaseUrl}\n />\n\n {connectUrl && <ConnectorButtons serverName=\"Fancy UI co-browse\" mcpUrl={connectUrl} />}\n </div>\n );\n}\n\nCoBrowsePresence.displayName = \"CoBrowsePresence\";\n","import { useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useAgentActivity } from \"../../presence/use-agent-activity\";\nimport { AgentCursor } from \"../AgentCursor/AgentCursor\";\nimport { AgentActivityHighlight } from \"../AgentActivityHighlight/AgentActivityHighlight\";\n\ntype Rect = { x: number; y: number; width: number; height: number };\n\nconst CURSOR_EDGE_INSET = 24;\nconst FLUID_CURSOR_SPEED_PX_PER_SECOND = 1_050;\nconst MIN_GLIDE_MS = 240;\nconst MAX_GLIDE_MS = 1_200;\n\nexport function visibleCursorPoint(rect: Rect, viewport: { width: number; height: number }) {\n const x = rect.x + rect.width / 2;\n const y = rect.y + rect.height / 2;\n return {\n x: Math.min(Math.max(x, CURSOR_EDGE_INSET), Math.max(CURSOR_EDGE_INSET, viewport.width - CURSOR_EDGE_INSET)),\n y: Math.min(Math.max(y, CURSOR_EDGE_INSET), Math.max(CURSOR_EDGE_INSET, viewport.height - CURSOR_EDGE_INSET)),\n };\n}\n\nexport function fluidGlideDuration(from: { x: number; y: number } | null, to: { x: number; y: number }) {\n if (!from) return 0;\n const distance = Math.hypot(to.x - from.x, to.y - from.y);\n return Math.round(Math.min(MAX_GLIDE_MS, Math.max(MIN_GLIDE_MS, (distance / FLUID_CURSOR_SPEED_PX_PER_SECOND) * 1_000)));\n}\n\nexport type CoBrowseCursorLayerProps = {\n /** Render the overlay only while a session is live. Default true. */\n active?: boolean;\n /** Stacking order of the overlay. Default just under the max. */\n zIndex?: number;\n};\n\n/**\n * Page-wide agent presence for co-browsing — the missing \"all actors present\"\n * half of Human+ UX. A fixed, click-through overlay (portaled to <body>) that\n * shows the connected agent as a live cursor + pings/highlights the element it\n * just acted on, gliding between targets. Same visual language as the whiteboard\n * demo's agent cursor, but mapped from the navigation bridge's STABLE HANDLES\n * (the agent has no real mouse) — each tool reports the acted element's viewport\n * rect in `meta.rect` (see `NavigationBridgeAdapter.rectFor`).\n *\n * Mount it once near the app root (e.g. in your CoBrowseProvider), gated on an\n * active session. SSR-safe: renders null on the server / until the first action.\n */\nexport function CoBrowseCursorLayer({ active = true, zIndex = 2147483000 }: CoBrowseCursorLayerProps) {\n const { latest } = useAgentActivity(undefined, { capacity: 12 });\n const [cursor, setCursor] = useState<{ x: number; y: number; name: string; color: string; status?: string; glideMs: number } | null>(\n null,\n );\n const [pulse, setPulse] = useState<{ rect: Rect; color: string; key: number } | null>(null);\n\n useEffect(() => {\n if (!latest || (latest.source ?? \"agent\") === \"user\") return;\n if (latest.action === \"agent_disconnected\") {\n // Relay clients may be intentionally short-lived (one process per MCP\n // call). The shared session is the presence boundary, not an individual\n // transport connection, so leave the agent's cursor in place between\n // calls. `active=false` still removes it when sharing actually ends.\n setCursor((prev) => (prev ? { ...prev, status: \"Standing by\", glideMs: 0 } : prev));\n setPulse(null);\n return;\n }\n const color = latest.agentColor ?? \"#a855f7\";\n const name = latest.agentName ?? \"Agent\";\n const status = latest.target?.label ?? latest.action;\n const rect = (latest.meta as { rect?: Rect } | undefined)?.rect;\n if (rect) {\n // Keep off-screen targets represented at the nearest viewport edge, then\n // glide at a distance-aware pace that a watching human can comfortably\n // follow. This is presence, not a teleport animation.\n const target = visibleCursorPoint(rect, { width: window.innerWidth, height: window.innerHeight });\n const reduceMotion = window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches ?? false;\n setCursor((prev) => ({\n ...target,\n name,\n color,\n status,\n glideMs: reduceMotion ? 0 : fluidGlideDuration(prev, target),\n }));\n setPulse({ rect, color, key: latest.timestamp });\n } else {\n // nav / scroll — no element. Keep (or first-show, at viewport center) the\n // cursor so the agent stays visibly present; just refresh its caption.\n setCursor((prev) =>\n prev\n ? { ...prev, status, name, color }\n : { x: window.innerWidth / 2, y: window.innerHeight / 2, name, color, status, glideMs: 0 },\n );\n }\n }, [latest?.timestamp]);\n\n if (!active || !cursor || typeof document === \"undefined\") return null;\n\n return createPortal(\n <div data-co-browse-cursor-layer=\"\" style={{ position: \"fixed\", inset: 0, pointerEvents: \"none\", zIndex }}>\n {pulse && (\n <AgentActivityHighlight\n x={pulse.rect.x}\n y={pulse.rect.y}\n width={pulse.rect.width}\n height={pulse.rect.height}\n color={pulse.color}\n pulseKey={pulse.key}\n />\n )}\n <AgentCursor\n x={cursor.x}\n y={cursor.y}\n name={cursor.name}\n color={cursor.color}\n status={cursor.status}\n style={{\n transition: cursor.glideMs\n ? `left ${cursor.glideMs}ms cubic-bezier(.22,.61,.36,1), top ${cursor.glideMs}ms cubic-bezier(.22,.61,.36,1)`\n : \"none\",\n }}\n />\n </div>,\n document.body,\n );\n}\n\nCoBrowseCursorLayer.displayName = \"CoBrowseCursorLayer\";\n","import { type CSSProperties, useState } from \"react\";\n\nexport type SimulateUsersButtonProps = {\n /** Endpoint that injects the fake active users. Default `/active-users/simulate`. */\n endpoint?: string;\n /** How many fake users to simulate (sent as `count`). Default `10`. */\n count?: number;\n /** Button label. Default `Simulate {count} active users`. */\n label?: string;\n /**\n * CSRF token sent as `X-CSRF-TOKEN`. If omitted, falls back to a\n * `<meta name=\"csrf-token\">` on the page (the Laravel default).\n */\n csrfToken?: string;\n /** Called after a successful trigger. */\n onTriggered?: () => void;\n /** Called if the request fails. */\n onError?: (error: unknown) => void;\n className?: string;\n style?: CSSProperties;\n};\n\nfunction resolveCsrf(explicit?: string): string | undefined {\n if (explicit) return explicit;\n if (typeof document === \"undefined\") return undefined;\n return document.querySelector<HTMLMetaElement>('meta[name=\"csrf-token\"]')?.content;\n}\n\n/**\n * A button that asks the host to inject N **fake** active users (injected\n * dummies, not real accounts) so the live ActiveUser stream / presence overlay\n * has something to animate in a demo. POSTs `{ count }` to `endpoint`.\n *\n * Self-contained (inline styles, no react-fancy dependency) so it drops into any\n * host. The fakes + their staggered activity are produced server-side; this\n * button only triggers them.\n */\nexport function SimulateUsersButton({\n endpoint = \"/active-users/simulate\",\n count = 10,\n label,\n csrfToken,\n onTriggered,\n onError,\n className,\n style,\n}: SimulateUsersButtonProps) {\n const [busy, setBusy] = useState(false);\n\n async function trigger() {\n if (busy) return;\n setBusy(true);\n try {\n const token = resolveCsrf(csrfToken);\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n ...(token ? { \"X-CSRF-TOKEN\": token } : {}),\n },\n credentials: \"same-origin\",\n body: JSON.stringify({ count }),\n });\n if (!res.ok) throw new Error(`Simulate request failed: ${res.status}`);\n onTriggered?.();\n } catch (err) {\n onError?.(err);\n } finally {\n setBusy(false);\n }\n }\n\n return (\n <button\n type=\"button\"\n data-fai-simulate-users=\"\"\n className={[\"fai-simulate-users\", className ?? \"\"].filter(Boolean).join(\" \")}\n onClick={trigger}\n disabled={busy}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"8px 14px\",\n borderRadius: 8,\n border: \"1px solid rgba(139,92,246,0.4)\",\n background: busy ? \"rgba(139,92,246,0.15)\" : \"rgba(139,92,246,0.1)\",\n color: \"#7c3aed\",\n font: \"inherit\",\n fontSize: 13,\n fontWeight: 500,\n cursor: busy ? \"progress\" : \"pointer\",\n opacity: busy ? 0.7 : 1,\n ...style,\n }}\n >\n <span aria-hidden>{busy ? \"⏳\" : \"✨\"}</span>\n {label ?? `Simulate ${count} active users`}\n </button>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/bridges/navigation.ts","../src/bridges/screen-doc.ts","../src/sharing/use-co-browse-session.ts","../src/components/BridgedForm/BridgedForm.tsx","../src/components/ScreensActivityBridge/ScreensActivityBridge.tsx","../src/components/CoBrowsePresence/CoBrowsePresence.tsx","../src/components/CoBrowseCursorLayer/CoBrowseCursorLayer.tsx","../src/components/SimulateUsersButton/SimulateUsersButton.tsx"],"names":["DEFAULT_AGENT","useRef","useEffect","useMemo","jsx","LIFECYCLE_ACTIONS","useState","jsxs"],"mappings":"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","file":"index.js","sourcesContent":["import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport type { AgentTarget } from \"../presence/types\";\nimport { pushUndoEntry } from \"../undo/undo-stack\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\n\n/**\n * One interactive element the agent can act on, addressed by a STABLE handle\n * (not a CSS selector) so the agent drives the page the Human+ way — never DOM\n * scraping. The host builds these in `describe()` (data-co-handle → name/id →\n * ARIA role + accessible name).\n */\nexport type PageAction = {\n /** Stable, opaque handle the agent passes back to act on this element. */\n handle: string;\n /** ARIA-ish role: \"link\" | \"button\" | \"textbox\" | \"checkbox\" | \"select\" | … */\n role: string;\n /** Accessible name / label. */\n label: string;\n /** Current value for inputs (omitted/masked for sensitive fields). */\n value?: unknown;\n /** True when activating this is destructive / submits (agent should stage). */\n destructive?: boolean;\n};\n\n/** The page as the agent sees it: where it is + what it can do. */\nexport type PageSnapshot = {\n url: string;\n title: string;\n actions: PageAction[];\n /** Monotonic host revision. Human input advances it and invalidates stale agent intent. */\n revision?: number;\n};\n\n/** A write the host may want the human to confirm (trust-but-verify). */\nexport type NavigationConfirmRequest = {\n action: \"submit\" | \"click\";\n handle: string;\n label: string;\n};\n\n/**\n * Host-provided adapter. In the sandbox this is backed by Inertia's `router` +\n * a DOM walker (see resources/js/agent/CoBrowseProvider.tsx). Every method\n * works on stable handles, never raw selectors.\n */\nexport type NavigationBridgeAdapter = {\n /** Optional fancy-screens screen id for presence targeting. */\n screenId?: string;\n /** Current location. */\n getLocation: () => { url: string; title: string };\n /** Current human-control revision. Omit to disable stale-intent protection. */\n getRevision?: () => number;\n /** Snapshot of the page's actionable elements (stable handles + labels). */\n describe: () => PageSnapshot;\n /** Visible text / heading outline for grounding (optional). */\n read?: () => string;\n /** Navigate to a URL (host wires to router.visit). */\n visit: (url: string) => void | Promise<void>;\n back?: () => void | Promise<void>;\n forward?: () => void | Promise<void>;\n /** Scroll to coords or to a handle's element. */\n scrollTo: (opts: { x?: number; y?: number; handle?: string }) => void;\n scrollBy: (dy: number) => void;\n /** Set a field's value by handle (host dispatches input/change for React). */\n setField: (handle: string, value: unknown) => { ok: boolean; error?: string };\n /** Activate an element by handle. */\n click: (handle: string) => { ok: boolean; error?: string };\n /** Submit a form by handle. */\n submit: (handle: string) => Promise<{ ok: boolean; error?: string }> | { ok: boolean; error?: string };\n /**\n * Viewport rect of a handle's element, for agent-presence rendering (cursor +\n * highlight). Returned in tool `meta.rect` so `<CoBrowseCursorLayer>` can show\n * the agent acting on the page. Optional — omit and there's just no cursor.\n */\n rectFor?: (handle: string) => { x: number; y: number; width: number; height: number } | null;\n /**\n * Trust-but-verify hook. When `pendingMode` is on, `page_submit` and\n * destructive `page_click` route through this; the host shows a prompt and\n * resolves true (proceed) / false (declined).\n */\n confirm?: (req: NavigationConfirmRequest) => Promise<boolean>;\n};\n\nexport type NavigationBridgeOptions = {\n adapter: NavigationBridgeAdapter;\n /** Identity tagged into activity events (so the human sees who's driving). */\n agent?: { id: string; name?: string; color?: string };\n /** Route submit + destructive clicks through `adapter.confirm`. Default true. */\n pendingMode?: boolean;\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/**\n * registerNavigationBridge — site-wide co-browsing. Lets a connected agent\n * navigate, scroll, and (with staged confirm) fill + click any page, addressed\n * by stable handles. Pairs with `useCoBrowseSession` (server + relay) and\n * `<CoBrowsePresence>` (the human's view of the agent). The 12th Fancy bridge.\n */\nexport function registerNavigationBridge(\n host: ToolHost,\n options: NavigationBridgeOptions,\n): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const pendingMode = options.pendingMode ?? true;\n const disposers: Array<() => void> = [];\n let groundedRevision: number | null = null;\n\n const staleIntent = () => {\n const current = adapter.getRevision?.();\n if (current === undefined) return null;\n if (groundedRevision === null || groundedRevision !== current) {\n return errorResult(\n `Human took control at page revision ${current}. This agent action was cancelled; call page_describe before acting again.`,\n );\n }\n return null;\n };\n\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const target = (label: string, elementId?: string): AgentTarget => ({\n kind: \"navigation\",\n screenId: adapter.screenId,\n elementId,\n label,\n });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n activity: false | ((args: JsonObject) => AgentTarget),\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = activity\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent: { id: agent.id, name: agent.name, color: agent.color },\n kind: \"navigation\",\n screenId: adapter.screenId,\n resolveTarget: ({ args }) => activity(args),\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n {\n name,\n description,\n inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false },\n },\n final as any,\n ),\n );\n };\n\n // ───────────── Read ─────────────\n\n reg(\n \"page_describe\",\n \"Describe the current page: its URL, title, and the interactive elements you can act on (each with a stable `handle`, role, and label). Call this first, and again after navigating.\",\n {},\n [],\n () => {\n const snap = adapter.describe();\n const revision = adapter.getRevision?.();\n if (revision !== undefined) {\n snap.revision = revision;\n groundedRevision = revision;\n }\n const text = [\n `URL: ${snap.url}`,\n `Title: ${snap.title}`,\n \"\",\n ...snap.actions.map((a) => `[${a.handle}] ${a.role}: ${a.label}${a.destructive ? \" (destructive)\" : \"\"}`),\n ].join(\"\\n\");\n return textResult(text, snap);\n },\n () => target(\"Inspect page\"),\n );\n\n reg(\n \"page_read\",\n \"Read the page's visible text / heading outline for grounding.\",\n {},\n [],\n () => textResult(adapter.read ? adapter.read() : \"(host did not provide page text)\"),\n () => target(\"Read page\"),\n );\n\n reg(\n \"page_focus\",\n \"Move the agent's visible focus to an interactive element by stable handle without activating it.\",\n { handle: { type: \"string\" } },\n [\"handle\"],\n (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const handle = String(args.handle ?? \"\");\n const action = adapter.describe().actions.find((candidate) => candidate.handle === handle);\n if (!action) return errorResult(`No element for handle \"${handle}\"`);\n return textResult(`Focused ${handle}`, {\n handle,\n rect: adapter.rectFor?.(handle) ?? undefined,\n });\n },\n (args) => target(`Focus ${String(args.handle ?? \"\")}`, String(args.handle ?? \"\")),\n );\n\n // ───────────── Navigate / scroll ─────────────\n\n reg(\n \"nav_visit\",\n \"Navigate to a URL (same-site path or absolute). The human watches the page change.\",\n { url: { type: \"string\", description: \"Path like /packages or an absolute URL.\" } },\n [\"url\"],\n async (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const url = String(args.url ?? \"\");\n if (!url) return errorResult(\"url is required\");\n // Scheme allow-list: permit only same-site/relative paths and http(s)\n // absolutes. A `javascript:` / `data:` / `file:` / `vbscript:` URL handed\n // to a host that wires visit() to window.location would execute as the\n // human — a semi-trusted agent (steerable via page_read prompt injection)\n // must not reach those.\n const scheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(url)?.[1]?.toLowerCase();\n if (scheme && scheme !== \"http\" && scheme !== \"https\") {\n return errorResult(\n `Refusing to navigate to a '${scheme}:' URL. Only http(s) URLs or same-site paths are allowed.`,\n );\n }\n const from = adapter.getLocation().url;\n await adapter.visit(url);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"navigation\",\n action: \"nav_visit\",\n label: `Navigate to ${url}`,\n undo: () => {\n adapter.visit(from);\n },\n redo: () => {\n adapter.visit(url);\n },\n });\n return textResult(`Navigated to ${url}`, { url });\n },\n (args) => target(`Navigate → ${String(args.url ?? \"\")}`),\n );\n\n reg(\n \"nav_back\",\n \"Go back to the previous page.\",\n {},\n [],\n async () => {\n const stale = staleIntent();\n if (stale) return stale;\n if (!adapter.back) return errorResult(\"Host did not provide back navigation.\");\n await adapter.back();\n return textResult(\"Went back\");\n },\n () => target(\"Back\"),\n );\n\n reg(\n \"nav_forward\",\n \"Go forward to the next page.\",\n {},\n [],\n async () => {\n const stale = staleIntent();\n if (stale) return stale;\n if (!adapter.forward) return errorResult(\"Host did not provide forward navigation.\");\n await adapter.forward();\n return textResult(\"Went forward\");\n },\n () => target(\"Forward\"),\n );\n\n reg(\n \"nav_scroll_to\",\n \"Scroll the page to absolute coordinates, or to a specific element by its handle.\",\n {\n handle: { type: \"string\", description: \"Scroll this element into view.\" },\n x: { type: \"number\" },\n y: { type: \"number\" },\n },\n [],\n (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const handle = typeof args.handle === \"string\" ? args.handle : undefined;\n adapter.scrollTo({\n handle,\n x: typeof args.x === \"number\" ? args.x : undefined,\n y: typeof args.y === \"number\" ? args.y : undefined,\n });\n return textResult(\"Scrolled\", handle ? { handle, rect: adapter.rectFor?.(handle) ?? undefined } : undefined);\n },\n () => target(\"Scroll\"),\n );\n\n reg(\n \"nav_scroll_by\",\n \"Scroll the page by a vertical delta in pixels (negative scrolls up).\",\n { dy: { type: \"number\" } },\n [\"dy\"],\n (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n adapter.scrollBy(Number(args.dy ?? 0));\n return textResult(`Scrolled by ${Number(args.dy ?? 0)}px`);\n },\n () => target(\"Scroll\"),\n );\n\n // ───────────── Co-drive (fill / click / submit) ─────────────\n\n reg(\n \"page_set_field\",\n \"Set a form field's value by handle. The host updates the controlled input and the human sees it change.\",\n {\n handle: { type: \"string\" },\n value: { description: \"Value to set; type matches the field.\" },\n },\n [\"handle\", \"value\"],\n (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const handle = String(args.handle ?? \"\");\n const res = adapter.setField(handle, args.value);\n if (!res.ok) return errorResult(res.error ?? `Could not set ${handle}`);\n return textResult(`${handle} ← ${JSON.stringify(args.value)}`, { handle, value: args.value, rect: adapter.rectFor?.(handle) ?? undefined });\n },\n (args) => target(`Set ${String(args.handle ?? \"\")}`, String(args.handle ?? \"\")),\n );\n\n reg(\n \"page_click\",\n \"Activate an element by handle (link, button, checkbox…). Destructive elements are staged for the human to confirm.\",\n { handle: { type: \"string\" } },\n [\"handle\"],\n async (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const handle = String(args.handle ?? \"\");\n const action = adapter.describe().actions.find((a) => a.handle === handle);\n const rect = adapter.rectFor?.(handle) ?? undefined; // capture before the click may navigate away\n if (pendingMode && action?.destructive && adapter.confirm) {\n const ok = await adapter.confirm({ action: \"click\", handle, label: action.label });\n if (!ok) return errorResult(\"Declined by user\");\n }\n const res = adapter.click(handle);\n if (!res.ok) return errorResult(res.error ?? `Could not click ${handle}`);\n return textResult(`Clicked ${handle}`, { handle, rect });\n },\n (args) => target(`Click ${String(args.handle ?? \"\")}`, String(args.handle ?? \"\")),\n );\n\n reg(\n \"page_submit\",\n \"Submit a form by handle. Always staged for the human to confirm when pendingMode is on.\",\n { handle: { type: \"string\" } },\n [\"handle\"],\n async (args) => {\n const stale = staleIntent();\n if (stale) return stale;\n const handle = String(args.handle ?? \"\");\n const rect = adapter.rectFor?.(handle) ?? undefined; // capture before the submit navigates\n if (pendingMode && adapter.confirm) {\n const ok = await adapter.confirm({ action: \"submit\", handle, label: handle });\n if (!ok) return errorResult(\"Declined by user\");\n }\n const res = await adapter.submit(handle);\n if (!res.ok) return errorResult(res.error ?? \"Submit failed\");\n return textResult(`Submitted ${handle}`, { handle, rect });\n },\n (args) => target(`Submit ${String(args.handle ?? \"\")}`, String(args.handle ?? \"\")),\n );\n\n return {\n id: \"navigation\",\n title: \"Co-browsing\",\n dispose: () => {\n for (const d of disposers) d();\n },\n };\n}\n","/**\n * registerScreenDocBridge — an agent bridge over the CONTENT of one rendered\n * `<Screen doc={…}>` (fancy-screens ≥ 0.6), built on {@link registerDocBridge}.\n *\n * This is the other half of {@link registerScreensBridge}, and the halves are\n * not interchangeable. That one moves *between* screens and creates them from\n * host templates, treating a screen's contents as an opaque `config` blob. This\n * one addresses the nodes *inside* one screen: read them, patch a prop, retext a\n * label, reparent a card.\n *\n * Until fancy-screens 0.6 there was no way to do that at all — `ScreenSchema`\n * nodes had no `id`, so an agent could emit a whole surface and then not touch\n * anything in it. That was a standing violation of the component contract's\n * stable-handles requirement, on the one shipped \"agent emits a UI\" path.\n *\n * A screen document is a plain `DocTree`, so the generic bridge supplies\n * describe/get/list/get_node + add/update/remove/move + undo + agent activity +\n * staged writes for free. What this layer adds is everything that is specific to\n * a screen being a rendered React tree:\n *\n * - **Synthetic ids are reported as such.** fancy-screens mints a position-derived\n * id for any node the author left anonymous. It looks like a handle and is not\n * one: insert a sibling above it and it points at a different node, silently.\n * Every read here says which kind of id it handed back, and `screen_addressable`\n * lists only the durable ones.\n * - **Literal text is a node**, not a prop, so that a string and an element can be\n * siblings without losing their order. `screen_set_text` hides that from the\n * agent, which otherwise has to know the reserved `#text` type to change a label.\n *\n * No dependency on fancy-screens — the contract is the `DocTree`, mirroring how\n * `bridges/screens.ts` keeps its own snapshot types loose.\n */\nimport { textResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { Bridge } from \"./types\";\nimport { registerDocBridge, type DocAdapter, type DocOpTool } from \"./doc\";\nimport {\n childrenOf,\n appendOrder,\n type DocNode,\n type StagePolicy,\n type TreeOp,\n} from \"@particle-academy/fancy-doc-commons\";\n\n/**\n * Reserved node type for a literal string child. Must match fancy-screens'\n * `TEXT_NODE_TYPE`; duplicated rather than imported to keep this bridge free of\n * a fancy-screens dependency.\n */\nexport const SCREEN_TEXT_NODE_TYPE = \"#text\";\n\n/** A screen document node — a `DocNode` plus the minted-id flag. */\nexport interface ScreenDocNode extends DocNode {\n /**\n * True when fancy-screens minted this id because the author supplied none.\n * A synthetic id is derived from position, so it is not a durable handle.\n */\n synthetic?: boolean;\n}\n\nexport type ScreenDocOp = TreeOp<ScreenDocNode>;\n\nexport interface ScreenDocBridgeOptions {\n adapter: DocAdapter<ScreenDocNode>;\n /**\n * Tool-name prefix. Default `\"screen\"` → `screen_add`, `screen_set_text`, …\n *\n * Tool names are global, so a host wiring more than one doc-driven screen at\n * once must give each a distinct prefix (`\"screen_checkout\"`).\n */\n surface?: string;\n agent?: { id: string; name?: string; color?: string };\n /** Auto-apply vs. confirm per op (trust-but-verify). Default: auto. */\n stagePolicy?: StagePolicy<ScreenDocOp>;\n onPending?: (staged: { id: string; op: ScreenDocOp; label: string }) => void;\n}\n\n/** Register the screen-content bridge (prefix `screen_`) over a screen's `DocTree`. */\nexport function registerScreenDocBridge(host: ToolHost, options: ScreenDocBridgeOptions): Bridge {\n const { adapter } = options;\n const surface = options.surface ?? \"screen\";\n\n const setText: DocOpTool<ScreenDocNode, ScreenDocOp> = {\n verb: \"set_text\",\n description:\n \"Replace the literal text of an element node — the natural way to change a label, heading or paragraph. Pass the ELEMENT's id, not the text node's.\",\n properties: {\n id: { type: \"string\", description: \"Id of the element whose text to set.\" },\n text: { type: \"string\" },\n },\n required: [\"id\", \"text\"],\n build: (args, tree) => {\n const id = String(args.id);\n const node = tree.nodes[id];\n if (!node) return { error: `No node ${id}` };\n if (node.type === SCREEN_TEXT_NODE_TYPE) {\n return { t: \"set_props\", id, patch: { value: String(args.text) } };\n }\n\n const texts = childrenOf(tree, id).filter((c) => c.type === SCREEN_TEXT_NODE_TYPE);\n if (texts.length === 1) {\n return { t: \"set_props\", id: texts[0]!.id, patch: { value: String(args.text) } };\n }\n if (texts.length === 0) {\n // Nothing to retext, so give it text. The minted child is addressable in\n // its own right, which is what makes the follow-up edit possible.\n return {\n t: \"insert\",\n node: {\n id: `${id}-text`,\n type: SCREEN_TEXT_NODE_TYPE,\n parent: id,\n order: appendOrder(tree, id),\n props: { value: String(args.text) },\n },\n };\n }\n // Ambiguous on purpose: picking one would look like it worked.\n return {\n error: `Node ${id} has ${texts.length} text children (${texts.map((t) => t.id).join(\", \")}) — set_text on the one you mean`,\n };\n },\n targetId: (args) => String(args.id),\n };\n\n const bridge = registerDocBridge<ScreenDocNode, ScreenDocOp>(host, {\n adapter,\n surface,\n agent: options.agent,\n stagePolicy: options.stagePolicy,\n onPending: options.onPending,\n // Anything the AGENT adds is authored by definition — it chose or was given\n // the id — so it must not inherit the synthetic flag from its neighbours.\n makeNode: ({ id, type, parent, order }, props) => ({ id, type, parent, order, props }),\n describeNode: (n) => ({\n id: n.id,\n type: n.type,\n parent: n.parent,\n ...(n.synthetic ? { synthetic: true } : {}),\n ...(n.type === SCREEN_TEXT_NODE_TYPE ? { text: String(n.props?.value ?? \"\") } : { props: Object.keys(n.props ?? {}) }),\n }),\n opTools: [setText],\n });\n\n // A read tool, so it lives here rather than in `opTools` (which are mutations).\n const disposeAddressable = host.registerTool(\n {\n name: `${surface}_addressable`,\n description:\n \"List the node ids that are safe to remember and use later. Ids NOT listed here were minted from a node's position: they resolve today and silently point at a different node once a sibling is inserted above them. Address those in the same turn you read them, and never store one.\",\n inputSchema: { type: \"object\", properties: {} as never, required: [], additionalProperties: false },\n },\n (async () => {\n const nodes = Object.values(adapter.get().nodes);\n const authored = nodes.filter((n) => !n.synthetic).map((n) => ({ id: n.id, type: n.type }));\n const syntheticCount = nodes.length - authored.length;\n\n return textResult(\n authored.length\n ? `${authored.length} addressable, ${syntheticCount} positional`\n : `no addressable ids — all ${syntheticCount} nodes are positional`,\n { addressable: authored, syntheticCount },\n );\n }) as never,\n );\n\n return {\n id: surface,\n title: \"Screen content\",\n dispose: () => {\n disposeAddressable();\n bridge.dispose();\n },\n };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { MicroMcpServer } from \"../mcp/server\";\nimport { attachInProcess } from \"../mcp/transports\";\nimport { attachSseRelay, type RelayState, type SseRelayTransport } from \"./sse-relay\";\nimport { createSessionDescriptor, type SessionDescriptor } from \"./token\";\nimport { emitActivity } from \"../presence/registry\";\nimport { registerNavigationBridge, type NavigationBridgeAdapter } from \"../bridges/navigation\";\n\n/** A thing the human did, surfaced so the connected agent stays aware. */\nexport type CoBrowseUserEvent =\n | { kind: \"navigation\"; url: string; title?: string; revision?: number }\n | { kind: \"scroll\"; y: number; revision?: number }\n | { kind: \"form\"; handle: string; value?: unknown; masked?: boolean; revision?: number }\n | { kind: \"click\"; handle: string; label?: string; revision?: number };\n\nexport type UseCoBrowseSessionOptions = {\n /**\n * The navigation adapter (Inertia + DOM in the sandbox). MUST be stable —\n * its methods should read live state via refs, since the bridge captures it\n * once on mount. Memoize it.\n */\n adapter: NavigationBridgeAdapter;\n /** Identity for the agent's presence (cursor/log color + name). */\n agent?: { id: string; name?: string; color?: string };\n /** Relay base path. Default \"/agent-relay\" (the generic frame broker). */\n relayBaseUrl?: string;\n /** MCP server info advertised to the agent. */\n info?: { name: string; version: string; instructions?: string };\n /** Register extra bridges (forms/screens/…) on the same server. */\n extraBridges?: (server: MicroMcpServer) => void;\n /** CSRF token for the relay register/unregister POSTs. */\n csrfToken?: () => string | null | undefined;\n /** Stage submit + destructive clicks for human confirm. Default true. */\n pendingMode?: boolean;\n};\n\nexport type CoBrowseSession = {\n server: MicroMcpServer | null;\n session: SessionDescriptor | null;\n relayState: RelayState;\n /**\n * True once at least one remote agent is actually attached to the session.\n *\n * Distinct from `relayState === \"open\"`, which only says the BROWSER reached\n * the relay — true the moment sharing starts, before the link has been handed\n * to anyone. A UI that keys \"Agent is driving\" off the relay state therefore\n * announces a driver who does not exist, and stays silent when a real one\n * arrives.\n */\n agentConnected: boolean;\n /** How many remote agents are attached (0 when nobody has joined). */\n agentCount: number;\n startShare: () => Promise<void>;\n stopShare: () => void;\n /**\n * Report a human action so the connected agent is notified. Emits a\n * `source:\"user\"` activity event, which the SSE relay forwards to the agent\n * as a `notifications/agent_activity` frame.\n */\n observeUser: (event: CoBrowseUserEvent) => void;\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\nconst USER = { id: \"human\", name: \"You\" };\n\n/**\n * Site-wide co-browsing session: one persistent in-page `MicroMcpServer` running\n * the navigation bridge, joinable by an external agent over the relay. Mount it\n * once at the app root; render `<CoBrowsePresence>` to show the agent + a Stop\n * control. The host wires `observeUser(...)` to navigation/scroll/form listeners\n * so the agent sees what the human does.\n */\nexport function useCoBrowseSession(options: UseCoBrowseSessionOptions): CoBrowseSession {\n const { adapter, extraBridges } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const relayBaseUrl = options.relayBaseUrl ?? \"/agent-relay\";\n\n const serverRef = useRef<MicroMcpServer | null>(null);\n const relayRef = useRef<SseRelayTransport | null>(null);\n const detachInProc = useRef<(() => void) | null>(null);\n const disposeBridge = useRef<(() => void) | null>(null);\n\n const [session, setSession] = useState<SessionDescriptor | null>(null);\n const [relayState, setRelayState] = useState<RelayState>(\"idle\");\n const [agentCount, setAgentCount] = useState(0);\n\n // Build the server + bridges once. The adapter is captured here, so it must\n // be stable (its methods read live state).\n useEffect(() => {\n const server = new MicroMcpServer({\n info: options.info ?? { name: \"fancy-co-browse\", version: \"0.1.0\" },\n instructions:\n options.info?.instructions ??\n \"Co-browse with a watching human. Call page_describe first; navigate, scroll, and (with confirm) fill/click via stable handles. You receive notifications/agent_activity for the human's actions (source:\\\"user\\\").\",\n });\n const bridge = registerNavigationBridge(server, { adapter, agent, pendingMode: options.pendingMode });\n extraBridges?.(server);\n const inProc = attachInProcess(server);\n detachInProc.current = () => inProc.close();\n disposeBridge.current = bridge.dispose;\n serverRef.current = server;\n\n return () => {\n relayRef.current?.close();\n relayRef.current = null;\n disposeBridge.current?.();\n detachInProc.current?.();\n serverRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const startShare = useCallback(async () => {\n const server = serverRef.current;\n if (!server || relayRef.current) return;\n const descriptor = createSessionDescriptor();\n const csrf = options.csrfToken?.() ?? \"\";\n const response = await fetch(`${relayBaseUrl}/register`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-csrf-token\": csrf },\n body: JSON.stringify({ session: descriptor.id, token: descriptor.token }),\n });\n if (!response.ok) {\n throw new Error(`Relay registration failed (${response.status})`);\n }\n const relay = attachSseRelay(server, { baseUrl: relayBaseUrl, sessionId: descriptor.id, token: descriptor.token });\n relay.onStateChange(setRelayState);\n relay.onPeersChange(setAgentCount);\n relayRef.current = relay;\n setSession(descriptor);\n }, [relayBaseUrl, options]);\n\n const stopShare = useCallback(() => {\n const current = session;\n relayRef.current?.close();\n relayRef.current = null;\n setRelayState(\"idle\");\n setAgentCount(0);\n setSession(null);\n if (current) {\n const csrf = options.csrfToken?.() ?? \"\";\n void fetch(`${relayBaseUrl}/${current.id}/unregister?token=${encodeURIComponent(current.token)}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-csrf-token\": csrf },\n }).catch(() => {});\n }\n }, [relayBaseUrl, options, session]);\n\n const observeUser = useCallback((event: CoBrowseUserEvent) => {\n const label =\n event.kind === \"navigation\"\n ? `You navigated to ${event.url}`\n : event.kind === \"scroll\"\n ? \"You scrolled\"\n : event.kind === \"click\"\n ? `You clicked ${event.label ?? event.handle}`\n : `You edited ${event.handle}${event.masked ? \" (hidden)\" : \"\"}`;\n emitActivity({\n agentId: USER.id,\n agentName: USER.name,\n source: \"user\",\n target: { kind: \"navigation\", label },\n action: `user_${event.kind}`,\n timestamp: Date.now(),\n meta: event as Record<string, unknown>,\n });\n }, []);\n\n return {\n server: serverRef.current,\n session,\n relayState,\n agentConnected: agentCount > 0,\n agentCount,\n startShare,\n stopShare,\n observeUser,\n };\n}\n","import { type ReactNode, useEffect, useMemo, useRef } from \"react\";\nimport type { MicroMcpServer } from \"../../mcp/server\";\nimport { registerFormBridge, type FormBridgeAdapter, type FormFieldDescriptor } from \"../../bridges/forms\";\n\nexport type BridgedFormProps = {\n /** Stable id for this form. Used by agents in `form_*` tool calls. */\n id: string;\n /** Human title (also surfaced as the bridge title). */\n title?: string;\n /** Optional fancy-screens screen id this form lives in. */\n screenId?: string;\n /** Field descriptors — drives the agent-facing schema. */\n fields: FormFieldDescriptor[];\n /** Controlled values. */\n values: Record<string, unknown>;\n /** Setter — hosts pass their setState. */\n onChange: (next: Record<string, unknown>) => void;\n /** Optional submit handler. */\n onSubmit?: () => Promise<{ ok: boolean; values?: Record<string, unknown>; error?: string }>;\n /** The MicroMcpServer the bridge registers against. Pass null/undefined\n * to render without a bridge (useful for stories / non-shared use). */\n server?: MicroMcpServer | null;\n /** Identity used in activity events. */\n agent?: { id: string; name?: string; color?: string };\n children: ReactNode;\n};\n\n/**\n * BridgedForm — wraps a react-fancy form (or any controlled inputs)\n * with a `registerFormBridge` lifecycle. Children render the actual form\n * using `values` + `onChange`; this component only manages the bridge.\n *\n * Hosts use it like:\n *\n * <BridgedForm id=\"signup\" fields={...} values={values} onChange={setValues} server={server}>\n * <Field><Input value={values.email} onValueChange={(v) => onChange({ ...values, email: v })} /></Field>\n * ...\n * </BridgedForm>\n *\n * Agents can then call form_describe, form_set_value, form_submit, etc.\n */\nexport function BridgedForm({\n id,\n title,\n screenId,\n fields,\n values,\n onChange,\n onSubmit,\n server,\n agent,\n children,\n}: BridgedFormProps) {\n // Refs so the adapter sees fresh values without re-installing the bridge.\n const valuesRef = useRef(values);\n const onChangeRef = useRef(onChange);\n const fieldsRef = useRef(fields);\n const submitRef = useRef(onSubmit);\n useEffect(() => { valuesRef.current = values; }, [values]);\n useEffect(() => { onChangeRef.current = onChange; }, [onChange]);\n useEffect(() => { fieldsRef.current = fields; }, [fields]);\n useEffect(() => { submitRef.current = onSubmit; }, [onSubmit]);\n\n const focusElement = (name: string) => {\n if (typeof document === \"undefined\") return;\n const el = document.querySelector(`[data-form-id=\"${id}\"] [name=\"${name}\"]`) as HTMLElement | null;\n el?.focus();\n };\n\n const adapter = useMemo<FormBridgeAdapter>(() => ({\n id,\n title,\n screenId,\n getFields: () => fieldsRef.current,\n getValue: (name) => valuesRef.current[name],\n getValues: () => ({ ...valuesRef.current }),\n setValue: (name, v) => onChangeRef.current({ ...valuesRef.current, [name]: v }),\n setValues: (next) => onChangeRef.current({ ...valuesRef.current, ...next }),\n focus: focusElement,\n submit: async () => {\n if (!submitRef.current) {\n return { ok: true, values: { ...valuesRef.current } };\n }\n return submitRef.current();\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }), [id, title, screenId]);\n\n useEffect(() => {\n if (!server) return;\n const bridge = registerFormBridge(server, { adapter, agent });\n return () => bridge.dispose();\n }, [server, adapter, agent]);\n\n return <div data-form-id={id}>{children}</div>;\n}\n","import { useEffect } from \"react\";\nimport { onActivity } from \"../../presence/registry\";\n\n/**\n * Loose shape of the fancy-screens system context — kept here so this\n * component doesn't hard-import `@particle-academy/fancy-screens`.\n */\ntype ScreenSystemLike = {\n registry: Map<string, { id: string; agentActivity?: unknown }>;\n updateScreen: (id: string, patch: { agentActivity?: unknown }) => void;\n};\n\nexport type ScreensActivityBridgeProps = {\n /** The value returned by `useScreenSystem()` from fancy-screens. */\n system: ScreenSystemLike;\n /** ms to wait after the last activity before clearing the screen's badge. Default 1500. */\n fadeMs?: number;\n};\n\n/**\n * ScreensActivityBridge — subscribe to the in-process activity registry\n * and patch each event into the matching screen's `agentActivity` field.\n * Fade-out clears the badge after `fadeMs`.\n *\n * Use it once near the root of your app, ABOVE every <Screen>:\n *\n * const system = useScreenSystem();\n * <>\n * <ScreensActivityBridge system={system} />\n * <Screen id=\"dashboard\">…</Screen>\n * <Screen id=\"form\">…</Screen>\n * </>\n *\n * Renders nothing; pure side-effect component.\n */\nexport function ScreensActivityBridge({ system, fadeMs = 1500 }: ScreensActivityBridgeProps) {\n useEffect(() => {\n const fadeTimers = new Map<string, ReturnType<typeof setTimeout>>();\n const off = onActivity((event) => {\n const screenId = event.target.screenId;\n if (!screenId) return;\n // Only patch screens that are currently registered.\n if (!system.registry.has(screenId)) return;\n const activity = {\n agentId: event.agentId,\n agentName: event.agentName,\n agentColor: event.agentColor,\n action: event.action,\n timestamp: event.timestamp,\n elementId: event.target.elementId,\n label: event.target.label,\n };\n system.updateScreen(screenId, { agentActivity: activity });\n const prev = fadeTimers.get(screenId);\n if (prev) clearTimeout(prev);\n fadeTimers.set(\n screenId,\n setTimeout(() => {\n system.updateScreen(screenId, { agentActivity: null });\n fadeTimers.delete(screenId);\n }, event.ttlMs ?? fadeMs),\n );\n });\n return () => {\n off();\n for (const t of fadeTimers.values()) clearTimeout(t);\n };\n }, [system, fadeMs]);\n return null;\n}\n","import { useMemo } from \"react\";\nimport { useAgentActivity } from \"../../presence/use-agent-activity\";\nimport { ShareControls } from \"../ShareControls/ShareControls\";\nimport { ConnectorButtons } from \"../../connectors/ConnectorButtons\";\nimport type { AgentActivity } from \"../AgentPanel\";\nimport type { AgentActivityEvent } from \"../../presence/types\";\nimport type { CoBrowseSession } from \"../../sharing/use-co-browse-session\";\n\nexport type CoBrowsePresenceProps = {\n /** The session from `useCoBrowseSession`. */\n session: CoBrowseSession;\n /** Public MCP/connect URL shown to the user (for ConnectorButtons), optional. */\n connectUrl?: string;\n /** Base URL used to build the shareable session link. */\n shareBaseUrl?: string;\n className?: string;\n};\n\n/** Lifecycle chatter — real to the session, but not something the agent *did*. */\nconst LIFECYCLE_ACTIONS = new Set([\"agent_connected\", \"agent_disconnected\"]);\n\n/**\n * The human's view of a site-wide co-browsing session: a \"Let an agent drive\"\n * starter, the share/connect surface until an agent arrives, a live log of what\n * it is doing once one has, and a Stop / take-back-control button.\n *\n * Staged-action confirms are rendered by the HOST (via the navigation adapter's\n * `confirm`), so this component stays presentation-only.\n */\nexport function CoBrowsePresence({ session, connectUrl, shareBaseUrl, className }: CoBrowsePresenceProps) {\n const { events } = useAgentActivity(undefined, { capacity: 40 });\n const lastAgentAction = [...events]\n .reverse()\n .find((e) => (e.source ?? \"agent\") !== \"user\" && !LIFECYCLE_ACTIONS.has(e.action));\n\n // Whether an agent is HERE, not whether the browser reached the relay. The\n // latter is true the instant sharing starts, so keying the badge on it told\n // every human \"Agent is driving\" before they had handed the link to anyone.\n const connected = session.agentConnected;\n\n const activity = useMemo(() => events.map(toPanelActivity), [events]);\n\n if (!session.session) {\n return (\n <div className={className} data-co-browse-presence=\"idle\">\n <button type=\"button\" onClick={() => void session.startShare()} data-co-browse-start>\n Let an agent drive\n </button>\n </div>\n );\n }\n\n return (\n <div className={className} data-co-browse-presence={connected ? \"connected\" : \"waiting\"}>\n <div data-co-browse-bar>\n <span data-co-browse-dot data-state={session.relayState} />\n <span data-co-browse-status>\n {connected ? \"Agent is driving\" : `Waiting for an agent… (${session.relayState})`}\n </span>\n {lastAgentAction && <span data-co-browse-last>{lastAgentAction.target?.label ?? lastAgentAction.action}</span>}\n <button type=\"button\" onClick={session.stopShare} data-co-browse-stop>\n Stop\n </button>\n </div>\n\n <ShareControls\n session={session.session}\n onStart={() => void session.startShare()}\n onStop={session.stopShare}\n status={session.relayState}\n agentConnected={connected}\n activity={activity}\n shareBaseUrl={shareBaseUrl}\n />\n\n {connectUrl && <ConnectorButtons serverName=\"Fancy UI co-browse\" mcpUrl={connectUrl} />}\n </div>\n );\n}\n\n/**\n * Presence event → the `AgentActivity` row `<ShareControls>` / `<AgentPanel>`\n * render. One shape for both, so a host already collecting presence needs no\n * second stream.\n */\nfunction toPanelActivity(event: AgentActivityEvent): AgentActivity {\n const who = (event.source ?? \"agent\") === \"user\" ? \"You\" : (event.agentName ?? \"Agent\");\n return {\n id: `${event.timestamp}-${event.action}-${event.target?.elementId ?? event.target?.label ?? \"\"}`,\n at: event.timestamp,\n kind: LIFECYCLE_ACTIONS.has(event.action) ? \"info\" : \"tool\",\n source: who,\n text: event.target?.label ?? event.action,\n detail: event.meta,\n };\n}\n\nCoBrowsePresence.displayName = \"CoBrowsePresence\";\n","import { useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useAgentActivity } from \"../../presence/use-agent-activity\";\nimport { AgentCursor } from \"../AgentCursor/AgentCursor\";\nimport { AgentActivityHighlight } from \"../AgentActivityHighlight/AgentActivityHighlight\";\n\ntype Rect = { x: number; y: number; width: number; height: number };\n\nconst CURSOR_EDGE_INSET = 24;\nconst FLUID_CURSOR_SPEED_PX_PER_SECOND = 1_050;\nconst MIN_GLIDE_MS = 240;\nconst MAX_GLIDE_MS = 1_200;\n\nexport function visibleCursorPoint(rect: Rect, viewport: { width: number; height: number }) {\n const x = rect.x + rect.width / 2;\n const y = rect.y + rect.height / 2;\n return {\n x: Math.min(Math.max(x, CURSOR_EDGE_INSET), Math.max(CURSOR_EDGE_INSET, viewport.width - CURSOR_EDGE_INSET)),\n y: Math.min(Math.max(y, CURSOR_EDGE_INSET), Math.max(CURSOR_EDGE_INSET, viewport.height - CURSOR_EDGE_INSET)),\n };\n}\n\nexport function fluidGlideDuration(from: { x: number; y: number } | null, to: { x: number; y: number }) {\n if (!from) return 0;\n const distance = Math.hypot(to.x - from.x, to.y - from.y);\n return Math.round(Math.min(MAX_GLIDE_MS, Math.max(MIN_GLIDE_MS, (distance / FLUID_CURSOR_SPEED_PX_PER_SECOND) * 1_000)));\n}\n\nexport type CoBrowseCursorLayerProps = {\n /** Render the overlay only while a session is live. Default true. */\n active?: boolean;\n /** Stacking order of the overlay. Default just under the max. */\n zIndex?: number;\n /**\n * Retire the cursor after this long without a tool call. Default 15s;\n * `0` keeps it on screen indefinitely.\n *\n * A cursor that sits still is not neutral — it reads as \"the agent is\n * broken\", which is worse than showing nothing. Continuous presence belongs\n * in the activity log; the cursor is for *motion*.\n */\n idleAfterMs?: number;\n};\n\n/**\n * Session lifecycle chatter. Real events, but nothing the agent DID — so they\n * must never conjure a cursor. `agent_connected` used to, parking a motionless\n * pointer captioned \"Agent connected\" in the middle of the viewport for a\n * session in which the agent had not yet made a single tool call.\n */\nconst LIFECYCLE_ACTIONS = new Set([\"agent_connected\", \"agent_disconnected\"]);\n\n/**\n * Page-wide agent presence for co-browsing — the missing \"all actors present\"\n * half of Human+ UX. A fixed, click-through overlay (portaled to <body>) that\n * shows the connected agent as a live cursor + pings/highlights the element it\n * just acted on, gliding between targets. Same visual language as the whiteboard\n * demo's agent cursor, but mapped from the navigation bridge's STABLE HANDLES\n * (the agent has no real mouse) — each tool reports the acted element's viewport\n * rect in `meta.rect` (see `NavigationBridgeAdapter.rectFor`).\n *\n * Mount it once near the app root (e.g. in your CoBrowseProvider), gated on an\n * active session. SSR-safe: renders null on the server / until the first action.\n */\nexport function CoBrowseCursorLayer({\n active = true,\n zIndex = 2147483000,\n idleAfterMs = 15_000,\n}: CoBrowseCursorLayerProps) {\n const { latest } = useAgentActivity(undefined, { capacity: 12 });\n const [cursor, setCursor] = useState<{ x: number; y: number; name: string; color: string; status?: string; glideMs: number } | null>(\n null,\n );\n const [pulse, setPulse] = useState<{ rect: Rect; color: string; key: number } | null>(null);\n // Timestamp of the last real tool call — the only thing that keeps the cursor\n // alive. Deliberately NOT bumped by lifecycle events, so a relay client\n // reconnecting every call can't hold a stale pointer on screen forever.\n const [lastActionAt, setLastActionAt] = useState(0);\n\n useEffect(() => {\n if (!latest || (latest.source ?? \"agent\") === \"user\") return;\n if (LIFECYCLE_ACTIONS.has(latest.action)) {\n // Connecting is not acting. Relay clients may also be intentionally\n // short-lived (one process per MCP call), so a disconnect is not the end\n // of the session either — if a cursor is already on screen from real work,\n // leave it and just say so. What we must NOT do is create one: an agent\n // that has connected and done nothing has nowhere to point.\n setCursor((prev) => (prev ? { ...prev, status: \"Standing by\", glideMs: 0 } : null));\n setPulse(null);\n return;\n }\n setLastActionAt(latest.timestamp);\n const color = latest.agentColor ?? \"#a855f7\";\n const name = latest.agentName ?? \"Agent\";\n const status = latest.target?.label ?? latest.action;\n const rect = (latest.meta as { rect?: Rect } | undefined)?.rect;\n if (rect) {\n // Keep off-screen targets represented at the nearest viewport edge, then\n // glide at a distance-aware pace that a watching human can comfortably\n // follow. This is presence, not a teleport animation.\n const target = visibleCursorPoint(rect, { width: window.innerWidth, height: window.innerHeight });\n const reduceMotion = window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches ?? false;\n setCursor((prev) => ({\n ...target,\n name,\n color,\n status,\n glideMs: reduceMotion ? 0 : fluidGlideDuration(prev, target),\n }));\n setPulse({ rect, color, key: latest.timestamp });\n } else {\n // nav / scroll — no element. Keep (or first-show, at viewport center) the\n // cursor so the agent stays visibly present; just refresh its caption.\n setCursor((prev) =>\n prev\n ? { ...prev, status, name, color }\n : { x: window.innerWidth / 2, y: window.innerHeight / 2, name, color, status, glideMs: 0 },\n );\n }\n }, [latest?.timestamp]);\n\n // Retire the cursor once the agent goes quiet. Presence that never changes\n // stops being information — the human reads a frozen pointer as a hung agent,\n // and the activity log is where \"still connected\" is supposed to live.\n useEffect(() => {\n if (!idleAfterMs || !lastActionAt) return;\n const timer = setTimeout(() => {\n setCursor(null);\n setPulse(null);\n }, idleAfterMs);\n return () => clearTimeout(timer);\n }, [lastActionAt, idleAfterMs]);\n\n if (!active || !cursor || typeof document === \"undefined\") return null;\n\n return createPortal(\n <div data-co-browse-cursor-layer=\"\" style={{ position: \"fixed\", inset: 0, pointerEvents: \"none\", zIndex }}>\n {pulse && (\n <AgentActivityHighlight\n x={pulse.rect.x}\n y={pulse.rect.y}\n width={pulse.rect.width}\n height={pulse.rect.height}\n color={pulse.color}\n pulseKey={pulse.key}\n />\n )}\n <AgentCursor\n x={cursor.x}\n y={cursor.y}\n name={cursor.name}\n color={cursor.color}\n status={cursor.status}\n style={{\n transition: cursor.glideMs\n ? `left ${cursor.glideMs}ms cubic-bezier(.22,.61,.36,1), top ${cursor.glideMs}ms cubic-bezier(.22,.61,.36,1)`\n : \"none\",\n }}\n />\n </div>,\n document.body,\n );\n}\n\nCoBrowseCursorLayer.displayName = \"CoBrowseCursorLayer\";\n","import { type CSSProperties, useState } from \"react\";\n\nexport type SimulateUsersButtonProps = {\n /** Endpoint that injects the fake active users. Default `/active-users/simulate`. */\n endpoint?: string;\n /** How many fake users to simulate (sent as `count`). Default `10`. */\n count?: number;\n /** Button label. Default `Simulate {count} active users`. */\n label?: string;\n /**\n * CSRF token sent as `X-CSRF-TOKEN`. If omitted, falls back to a\n * `<meta name=\"csrf-token\">` on the page (the Laravel default).\n */\n csrfToken?: string;\n /** Called after a successful trigger. */\n onTriggered?: () => void;\n /** Called if the request fails. */\n onError?: (error: unknown) => void;\n className?: string;\n style?: CSSProperties;\n};\n\nfunction resolveCsrf(explicit?: string): string | undefined {\n if (explicit) return explicit;\n if (typeof document === \"undefined\") return undefined;\n return document.querySelector<HTMLMetaElement>('meta[name=\"csrf-token\"]')?.content;\n}\n\n/**\n * A button that asks the host to inject N **fake** active users (injected\n * dummies, not real accounts) so the live ActiveUser stream / presence overlay\n * has something to animate in a demo. POSTs `{ count }` to `endpoint`.\n *\n * Self-contained (inline styles, no react-fancy dependency) so it drops into any\n * host. The fakes + their staggered activity are produced server-side; this\n * button only triggers them.\n */\nexport function SimulateUsersButton({\n endpoint = \"/active-users/simulate\",\n count = 10,\n label,\n csrfToken,\n onTriggered,\n onError,\n className,\n style,\n}: SimulateUsersButtonProps) {\n const [busy, setBusy] = useState(false);\n\n async function trigger() {\n if (busy) return;\n setBusy(true);\n try {\n const token = resolveCsrf(csrfToken);\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n ...(token ? { \"X-CSRF-TOKEN\": token } : {}),\n },\n credentials: \"same-origin\",\n body: JSON.stringify({ count }),\n });\n if (!res.ok) throw new Error(`Simulate request failed: ${res.status}`);\n onTriggered?.();\n } catch (err) {\n onError?.(err);\n } finally {\n setBusy(false);\n }\n }\n\n return (\n <button\n type=\"button\"\n data-fai-simulate-users=\"\"\n className={[\"fai-simulate-users\", className ?? \"\"].filter(Boolean).join(\" \")}\n onClick={trigger}\n disabled={busy}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"8px 14px\",\n borderRadius: 8,\n border: \"1px solid rgba(139,92,246,0.4)\",\n background: busy ? \"rgba(139,92,246,0.15)\" : \"rgba(139,92,246,0.1)\",\n color: \"#7c3aed\",\n font: \"inherit\",\n fontSize: 13,\n fontWeight: 500,\n cursor: busy ? \"progress\" : \"pointer\",\n opacity: busy ? 0.7 : 1,\n ...style,\n }}\n >\n <span aria-hidden>{busy ? \"⏳\" : \"✨\"}</span>\n {label ?? `Simulate ${count} active users`}\n </button>\n );\n}\n"]}
@@ -39,6 +39,7 @@ declare class SseRelayTransport implements Transport {
39
39
  private state;
40
40
  private expectedToken;
41
41
  private peers;
42
+ private peerListeners;
42
43
  constructor(options: SseRelayOptions);
43
44
  bindServer(server: MicroMcpServer): void;
44
45
  /** Open the receive channel. Idempotent. */
@@ -50,6 +51,20 @@ declare class SseRelayTransport implements Transport {
50
51
  send(message: JsonRpcMessage): void;
51
52
  close(): void;
52
53
  onStateChange(listener: (state: RelayState) => void): () => void;
54
+ /** How many remote peers (agents) are currently attached to this session. */
55
+ peerCount(): number;
56
+ /**
57
+ * Subscribe to peer arrivals/departures. Fires immediately with the current
58
+ * count.
59
+ *
60
+ * This is the ONLY honest answer to "is an agent actually here?".
61
+ * `onStateChange` reports the BROWSER's own channel to the relay, which opens
62
+ * the instant sharing starts — so a UI keyed on it announces "Agent is
63
+ * driving" to a human who has not yet handed the link to anybody, and can
64
+ * never tell them when one really arrives.
65
+ */
66
+ onPeersChange(listener: (count: number) => void): () => void;
67
+ private notifyPeers;
53
68
  /**
54
69
  * For relays that wrap each frame with auth metadata: hosts can call this
55
70
  * directly when a frame arrives via a non-SSE path. The transport will
@@ -39,6 +39,7 @@ declare class SseRelayTransport implements Transport {
39
39
  private state;
40
40
  private expectedToken;
41
41
  private peers;
42
+ private peerListeners;
42
43
  constructor(options: SseRelayOptions);
43
44
  bindServer(server: MicroMcpServer): void;
44
45
  /** Open the receive channel. Idempotent. */
@@ -50,6 +51,20 @@ declare class SseRelayTransport implements Transport {
50
51
  send(message: JsonRpcMessage): void;
51
52
  close(): void;
52
53
  onStateChange(listener: (state: RelayState) => void): () => void;
54
+ /** How many remote peers (agents) are currently attached to this session. */
55
+ peerCount(): number;
56
+ /**
57
+ * Subscribe to peer arrivals/departures. Fires immediately with the current
58
+ * count.
59
+ *
60
+ * This is the ONLY honest answer to "is an agent actually here?".
61
+ * `onStateChange` reports the BROWSER's own channel to the relay, which opens
62
+ * the instant sharing starts — so a UI keyed on it announces "Agent is
63
+ * driving" to a human who has not yet handed the link to anybody, and can
64
+ * never tell them when one really arrives.
65
+ */
66
+ onPeersChange(listener: (count: number) => void): () => void;
67
+ private notifyPeers;
53
68
  /**
54
69
  * For relays that wrap each frame with auth metadata: hosts can call this
55
70
  * directly when a frame arrives via a non-SSE path. The transport will
package/dist/sharing.cjs CHANGED
@@ -96,6 +96,7 @@ var SseRelayTransport = class {
96
96
  this.listeners = /* @__PURE__ */ new Set();
97
97
  this.state = "idle";
98
98
  this.peers = /* @__PURE__ */ new Set();
99
+ this.peerListeners = /* @__PURE__ */ new Set();
99
100
  this.opts = options;
100
101
  this.expectedToken = options.token;
101
102
  }
@@ -156,6 +157,8 @@ var SseRelayTransport = class {
156
157
  this.es?.close();
157
158
  this.es = void 0;
158
159
  this.connected = false;
160
+ this.peers.clear();
161
+ this.notifyPeers();
159
162
  this.setState("closed");
160
163
  }
161
164
  onStateChange(listener) {
@@ -163,6 +166,28 @@ var SseRelayTransport = class {
163
166
  listener(this.state);
164
167
  return () => this.listeners.delete(listener);
165
168
  }
169
+ /** How many remote peers (agents) are currently attached to this session. */
170
+ peerCount() {
171
+ return this.peers.size;
172
+ }
173
+ /**
174
+ * Subscribe to peer arrivals/departures. Fires immediately with the current
175
+ * count.
176
+ *
177
+ * This is the ONLY honest answer to "is an agent actually here?".
178
+ * `onStateChange` reports the BROWSER's own channel to the relay, which opens
179
+ * the instant sharing starts — so a UI keyed on it announces "Agent is
180
+ * driving" to a human who has not yet handed the link to anybody, and can
181
+ * never tell them when one really arrives.
182
+ */
183
+ onPeersChange(listener) {
184
+ this.peerListeners.add(listener);
185
+ listener(this.peers.size);
186
+ return () => this.peerListeners.delete(listener);
187
+ }
188
+ notifyPeers() {
189
+ for (const l of this.peerListeners) l(this.peers.size);
190
+ }
166
191
  /**
167
192
  * For relays that wrap each frame with auth metadata: hosts can call this
168
193
  * directly when a frame arrives via a non-SSE path. The transport will
@@ -197,6 +222,7 @@ var SseRelayTransport = class {
197
222
  if ("method" in message && message.method === "notifications/peer_joined") {
198
223
  const subscriberId = String(message.params?.subscriberId ?? "peer");
199
224
  this.peers.add(subscriberId);
225
+ this.notifyPeers();
200
226
  fancyAutoCommon.emitActivity({
201
227
  agentId: "agent",
202
228
  agentName: "Agent",
@@ -211,6 +237,7 @@ var SseRelayTransport = class {
211
237
  if ("method" in message && message.method === "notifications/peer_left") {
212
238
  const subscriberId = String(message.params?.subscriberId ?? "peer");
213
239
  this.peers.delete(subscriberId);
240
+ this.notifyPeers();
214
241
  if (this.peers.size === 0) {
215
242
  fancyAutoCommon.emitActivity({
216
243
  agentId: "agent",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/presence/registry.ts","../src/sharing/token.ts","../src/sharing/sse-relay.ts"],"names":["emitActivity","onActivity","readActivityHistory","resetActivityRegistry"],"mappings":"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","file":"sharing.cjs","sourcesContent":["/**\n * In-process registry of activity events. Now backed by the shared bus in\n * `@particle-academy/fancy-auto-common`, so agent activity (here) and flow\n * activity (fancy-flow's FlowRunnerUx) land in ONE stream — presence layers\n * render both. Re-exported under the same names for back-compat.\n */\nexport {\n emitActivity,\n onActivity,\n readActivityHistory,\n resetActivityRegistry,\n} from \"@particle-academy/fancy-auto-common\";\n","/**\n * Session-token utilities. The token is a high-entropy secret; possession\n * grants read/write on the session. We don't HMAC frames — frames carry\n * the token directly (which is fine for in-process / same-origin / TLS\n * transports). For lower-trust transports, host apps can layer signing\n * on top of the BroadcastChannelTransport.\n */\n\nconst TOKEN_BYTES = 24; // 192 bits, base64url-encoded → 32 chars\n\nexport type SessionDescriptor = {\n /** Stable session identifier. Channel name = `fai:share:${id}`. */\n id: string;\n /** Secret token. Treat as a password — anyone with it can read/write. */\n token: string;\n /** Pretty hash for display (first 8 chars of token). */\n display: string;\n};\n\nexport function createSessionDescriptor(): SessionDescriptor {\n const id = randomId(8);\n const token = randomToken();\n return { id, token, display: token.slice(0, 8) };\n}\n\nexport function describeSession(id: string, token: string): SessionDescriptor {\n return { id, token, display: token.slice(0, 8) };\n}\n\n/**\n * Build the shareable URL for the current page (preserves path, adds\n * session+token in the URL FRAGMENT).\n *\n * The token goes in the `#fragment`, never the `?query`: a fragment is never\n * transmitted to the server, so it can't leak through access/proxy logs or the\n * `Referer` header sent to third-party assets on the page. The recipient reads\n * it back with {@link readSessionFromUrl}. (The on-wire relay leg still sends\n * `?token=` today — moving that off the query is the larger transport change.)\n */\nexport function buildShareUrl(\n descriptor: SessionDescriptor,\n baseUrl: string = typeof window !== \"undefined\" ? window.location.href.split(\"?\")[0] : \"\",\n): string {\n const u = new URL(baseUrl);\n u.hash = new URLSearchParams({ session: descriptor.id, token: descriptor.token }).toString();\n return u.toString();\n}\n\n/** Build the JSON config form (suitable for Claude Desktop / Cline / etc.). */\nexport function buildShareConfig(descriptor: SessionDescriptor, transport = \"broadcast-channel\") {\n return {\n name: `whiteboard-${descriptor.id}`,\n transport,\n session: descriptor.id,\n token: descriptor.token,\n channel: `fai:share:${descriptor.id}`,\n protocol_version: \"2025-06-18\",\n };\n}\n\n/**\n * Read session descriptor from the current URL, or null if not a shared link.\n * Prefers the fragment (the non-leaking form {@link buildShareUrl} now emits),\n * falling back to the query string for links minted before that change.\n */\nexport function readSessionFromUrl(): SessionDescriptor | null {\n if (typeof window === \"undefined\") return null;\n const url = new URL(window.location.href);\n const frag = new URLSearchParams(url.hash.replace(/^#/, \"\"));\n const id = frag.get(\"session\") ?? url.searchParams.get(\"session\");\n const token = frag.get(\"token\") ?? url.searchParams.get(\"token\");\n if (!id || !token) return null;\n return describeSession(id, token);\n}\n\nfunction randomToken(): string {\n const bytes = new Uint8Array(TOKEN_BYTES);\n crypto.getRandomValues(bytes);\n return base64Url(bytes);\n}\n\nfunction randomId(len: number): string {\n const bytes = new Uint8Array(Math.ceil((len * 3) / 4));\n crypto.getRandomValues(bytes);\n return base64Url(bytes).slice(0, len);\n}\n\nfunction base64Url(bytes: Uint8Array): string {\n let s = \"\";\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n/** Constant-time string compare so a mismatched token leaks no timing info. */\nexport function constantTimeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n return diff === 0;\n}\n","import type { JsonRpcMessage } from \"../mcp/types\";\nimport type { Transport } from \"../mcp/server\";\nimport type { MicroMcpServer } from \"../mcp/server\";\nimport type { RelayChannelHandle } from \"@particle-academy/fancy-cf-relay\";\nimport { constantTimeEqual } from \"./token\";\nimport { emitActivity } from \"../presence/registry\";\n\n/**\n * SseRelayTransport — bridges the in-page MicroMcpServer to a host-app\n * relay broker over Server-Sent Events (inbound) + POST (outbound).\n *\n * Wire model:\n * - Browser opens an EventSource at `${baseUrl}/${sessionId}/events?token=…`.\n * Each `event: mcp` carries one JSON-RPC frame from a remote client.\n * - Browser POSTs JSON-RPC frames to `${baseUrl}/${sessionId}/outbox?token=…`\n * when the local server has a response/notification to send.\n *\n * The host provides the relay endpoint (any HTTP server). See the demo\n * `WhiteboardShareController` for the reference implementation.\n *\n * Token authentication is the host's job — this transport just carries the\n * token in the query string. For lower-trust deployments, layer signing on\n * top by wrapping `send` / `deliverFromRemote`.\n */\nexport type SseRelayOptions = {\n baseUrl: string;\n sessionId: string;\n token: string;\n /** Override fetch (testing / non-browser). Defaults to global fetch. */\n fetch?: typeof fetch;\n};\n\nexport class SseRelayTransport implements Transport {\n private server?: MicroMcpServer;\n private es?: EventSource;\n private channel?: RelayChannelHandle;\n private disposed = false;\n private opts: SseRelayOptions;\n private sendQueue: JsonRpcMessage[] = [];\n private connected = false;\n private listeners = new Set<(state: RelayState) => void>();\n private state: RelayState = \"idle\";\n private expectedToken: string;\n private peers = new Set<string>();\n\n constructor(options: SseRelayOptions) {\n this.opts = options;\n this.expectedToken = options.token;\n }\n\n bindServer(server: MicroMcpServer): void {\n this.server = server;\n }\n\n /** Open the receive channel. Idempotent. */\n start(): void {\n if (this.connected || this.disposed || typeof window === \"undefined\") return;\n this.setState(\"connecting\");\n // Prefer @particle-academy/fancy-cf-relay's adaptive channel (auto SSE↔\n // long-poll with Cloudflare detection) so the receive leg survives a\n // Cloudflare HTTP/3 (QUIC) edge that resets long-lived SSE streams. It's an\n // OPTIONAL peer: if it isn't installed, fall back to a plain EventSource.\n void import(\"@particle-academy/fancy-cf-relay\")\n .then(({ createRelayChannel }) => {\n if (this.connected || this.disposed) return;\n this.channel = createRelayChannel({\n baseUrl: this.opts.baseUrl,\n session: this.opts.sessionId,\n token: this.opts.token,\n transport: \"auto\",\n receiveDirection: \"inbound\",\n sendPath: \"outbox\",\n onFrame: (raw) => this.handleInbound(raw),\n onOpen: () => this.markOpen(),\n onError: () => this.setState(\"error\"),\n fetchImpl: this.opts.fetch,\n });\n this.channel.start();\n })\n .catch(() => {\n if (!this.disposed) this.startSse();\n });\n }\n\n /** Fallback receive leg: a plain EventSource (no fancy-cf-relay installed). */\n private startSse(): void {\n if (this.connected || this.disposed) return;\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/events?token=${encodeURIComponent(this.opts.token)}`;\n const es = new EventSource(url, { withCredentials: false });\n this.es = es;\n es.addEventListener(\"open\", () => this.markOpen());\n es.addEventListener(\"mcp\", (ev: MessageEvent) => this.handleInbound(ev.data));\n es.addEventListener(\"error\", () => this.setState(\"error\")); // EventSource auto-reconnects\n }\n\n /** Mark the channel live + flush any queued outbound frames. */\n private markOpen(): void {\n this.connected = true;\n this.setState(\"open\");\n const queued = this.sendQueue.splice(0);\n for (const msg of queued) this.postOut(msg);\n }\n\n send(message: JsonRpcMessage): void {\n if (!this.connected) {\n this.sendQueue.push(message);\n return;\n }\n this.postOut(message);\n }\n\n close(): void {\n this.disposed = true;\n this.channel?.stop();\n this.channel = undefined;\n this.es?.close();\n this.es = undefined;\n this.connected = false;\n this.setState(\"closed\");\n }\n\n onStateChange(listener: (state: RelayState) => void): () => void {\n this.listeners.add(listener);\n listener(this.state);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * For relays that wrap each frame with auth metadata: hosts can call this\n * directly when a frame arrives via a non-SSE path. The transport will\n * dispatch it to the bound server.\n */\n async deliverFromRemote(payload: JsonRpcMessage | string, token?: string): Promise<void> {\n if (token !== undefined && !constantTimeEqual(token, this.expectedToken)) return;\n if (!this.server) throw new Error(\"SseRelayTransport has no bound server\");\n const message: JsonRpcMessage = typeof payload === \"string\" ? JSON.parse(payload) : payload;\n await this.server.receive(this, message);\n }\n\n private async postOut(message: JsonRpcMessage): Promise<void> {\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/outbox?token=${encodeURIComponent(this.opts.token)}`;\n const f = this.opts.fetch ?? fetch;\n try {\n await f(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"accept\": \"application/json\" },\n body: JSON.stringify(message),\n });\n } catch {\n // Drop — relay errors are surfaced via state change separately.\n }\n }\n\n private async handleInbound(raw: string): Promise<void> {\n if (!this.server) return;\n let message: JsonRpcMessage;\n try {\n message = JSON.parse(raw);\n } catch {\n return;\n }\n if (\"method\" in message && message.method === \"notifications/peer_joined\") {\n const subscriberId = String((message.params as { subscriberId?: unknown } | undefined)?.subscriberId ?? \"peer\");\n this.peers.add(subscriberId);\n emitActivity({\n agentId: \"agent\",\n agentName: \"Agent\",\n agentColor: \"#a855f7\",\n action: \"agent_connected\",\n timestamp: Date.now(),\n target: { kind: \"navigation\", label: \"Agent connected\" },\n meta: { subscriberId },\n });\n return;\n }\n if (\"method\" in message && message.method === \"notifications/peer_left\") {\n const subscriberId = String((message.params as { subscriberId?: unknown } | undefined)?.subscriberId ?? \"peer\");\n this.peers.delete(subscriberId);\n if (this.peers.size === 0) {\n emitActivity({\n agentId: \"agent\",\n agentName: \"Agent\",\n agentColor: \"#a855f7\",\n action: \"agent_disconnected\",\n timestamp: Date.now(),\n target: { kind: \"navigation\", label: \"Agent disconnected\" },\n meta: { subscriberId },\n });\n }\n return;\n }\n await this.server.receive(this, message);\n }\n\n private setState(state: RelayState): void {\n this.state = state;\n for (const l of this.listeners) l(state);\n }\n}\n\nexport type RelayState = \"idle\" | \"connecting\" | \"open\" | \"closed\" | \"error\";\n\nexport function attachSseRelay(server: MicroMcpServer, options: SseRelayOptions): SseRelayTransport {\n const transport = new SseRelayTransport(options);\n transport.bindServer(server);\n server.attach(transport);\n transport.start();\n\n // Forward in-process agent activity events out over the relay so external\n // subscribers can render presence indicators in real time. Uses a dynamic\n // import so the relay doesn't hard-depend on the presence module if it's\n // tree-shaken out.\n import(\"../presence/registry\").then(({ onActivity }) => {\n const off = onActivity((event) => {\n transport.send({\n jsonrpc: \"2.0\",\n method: \"notifications/agent_activity\",\n params: event as any,\n });\n });\n // Tear down the subscription when the transport closes.\n const origClose = transport.close.bind(transport);\n transport.close = () => {\n off();\n origClose();\n };\n }).catch(() => {\n // Presence module unavailable — silently no-op (relay still works).\n });\n\n return transport;\n}\n"]}
1
+ {"version":3,"sources":["../src/presence/registry.ts","../src/sharing/token.ts","../src/sharing/sse-relay.ts"],"names":["emitActivity","onActivity","readActivityHistory","resetActivityRegistry"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,IAAA,gBAAA,GAAA,EAAA;AAAA,QAAA,CAAA,gBAAA,EAAA;AAAA,EAAA,YAAA,EAAA,MAAAA,4BAAA;AAAA,EAAA,UAAA,EAAA,MAAAC,0BAAA;AAAA,EAAA,mBAAA,EAAA,MAAAC,mCAAA;AAAA,EAAA,qBAAA,EAAA,MAAAC;AAAA,CAAA,CAAA;AAAA,IAAA,aAAA,GAAA,KAAA,CAAA;AAAA,EAAA,0BAAA,GAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACQA,IAAM,WAAA,GAAc,EAAA;AAWb,SAAS,uBAAA,GAA6C;AAC3D,EAAA,MAAM,EAAA,GAAK,SAAS,CAAC,CAAA;AACrB,EAAA,MAAM,QAAQ,WAAA,EAAY;AAC1B,EAAA,OAAO,EAAE,IAAI,KAAA,EAAO,OAAA,EAAS,MAAM,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,EAAE;AACjD;AAEO,SAAS,eAAA,CAAgB,IAAY,KAAA,EAAkC;AAC5E,EAAA,OAAO,EAAE,IAAI,KAAA,EAAO,OAAA,EAAS,MAAM,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,EAAE;AACjD;AAYO,SAAS,aAAA,CACd,UAAA,EACA,OAAA,GAAkB,OAAO,WAAW,WAAA,GAAc,MAAA,CAAO,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,IAAI,EAAA,EAC/E;AACR,EAAA,MAAM,CAAA,GAAI,IAAI,GAAA,CAAI,OAAO,CAAA;AACzB,EAAA,CAAA,CAAE,IAAA,GAAO,IAAI,eAAA,CAAgB,EAAE,OAAA,EAAS,UAAA,CAAW,EAAA,EAAI,KAAA,EAAO,UAAA,CAAW,KAAA,EAAO,CAAA,CAAE,QAAA,EAAS;AAC3F,EAAA,OAAO,EAAE,QAAA,EAAS;AACpB;AAGO,SAAS,gBAAA,CAAiB,UAAA,EAA+B,SAAA,GAAY,mBAAA,EAAqB;AAC/F,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,CAAA,WAAA,EAAc,UAAA,CAAW,EAAE,CAAA,CAAA;AAAA,IACjC,SAAA;AAAA,IACA,SAAS,UAAA,CAAW,EAAA;AAAA,IACpB,OAAO,UAAA,CAAW,KAAA;AAAA,IAClB,OAAA,EAAS,CAAA,UAAA,EAAa,UAAA,CAAW,EAAE,CAAA,CAAA;AAAA,IACnC,gBAAA,EAAkB;AAAA,GACpB;AACF;AAOO,SAAS,kBAAA,GAA+C;AAC7D,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,IAAA;AAC1C,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,MAAA,CAAO,SAAS,IAAI,CAAA;AACxC,EAAA,MAAM,IAAA,GAAO,IAAI,eAAA,CAAgB,GAAA,CAAI,KAAK,OAAA,CAAQ,IAAA,EAAM,EAAE,CAAC,CAAA;AAC3D,EAAA,MAAM,EAAA,GAAK,KAAK,GAAA,CAAI,SAAS,KAAK,GAAA,CAAI,YAAA,CAAa,IAAI,SAAS,CAAA;AAChE,EAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,OAAO,KAAK,GAAA,CAAI,YAAA,CAAa,IAAI,OAAO,CAAA;AAC/D,EAAA,IAAI,CAAC,EAAA,IAAM,CAAC,KAAA,EAAO,OAAO,IAAA;AAC1B,EAAA,OAAO,eAAA,CAAgB,IAAI,KAAK,CAAA;AAClC;AAEA,SAAS,WAAA,GAAsB;AAC7B,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,WAAW,CAAA;AACxC,EAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC5B,EAAA,OAAO,UAAU,KAAK,CAAA;AACxB;AAEA,SAAS,SAAS,GAAA,EAAqB;AACrC,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,IAAA,CAAK,KAAM,GAAA,GAAM,CAAA,GAAK,CAAC,CAAC,CAAA;AACrD,EAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC5B,EAAA,OAAO,SAAA,CAAU,KAAK,CAAA,CAAE,KAAA,CAAM,GAAG,GAAG,CAAA;AACtC;AAEA,SAAS,UAAU,KAAA,EAA2B;AAC5C,EAAA,IAAI,CAAA,GAAI,EAAA;AACR,EAAA,KAAA,MAAW,CAAA,IAAK,KAAA,EAAO,CAAA,IAAK,MAAA,CAAO,aAAa,CAAC,CAAA;AACjD,EAAA,OAAO,IAAA,CAAK,CAAC,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC1E;AAGO,SAAS,iBAAA,CAAkB,GAAW,CAAA,EAAoB;AAC/D,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,CAAA,CAAE,MAAA,EAAQ,OAAO,KAAA;AAClC,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,MAAA,EAAQ,CAAA,EAAA,EAAK,IAAA,IAAQ,CAAA,CAAE,UAAA,CAAW,CAAC,CAAA,GAAI,CAAA,CAAE,WAAW,CAAC,CAAA;AAC3E,EAAA,OAAO,IAAA,KAAS,CAAA;AAClB;;;AC9FA,aAAA,EAAA;AA2BO,IAAM,oBAAN,MAA6C;AAAA,EAclD,YAAY,OAAA,EAA0B;AAVtC,IAAA,IAAA,CAAQ,QAAA,GAAW,KAAA;AAEnB,IAAA,IAAA,CAAQ,YAA8B,EAAC;AACvC,IAAA,IAAA,CAAQ,SAAA,GAAY,KAAA;AACpB,IAAA,IAAA,CAAQ,SAAA,uBAAgB,GAAA,EAAiC;AACzD,IAAA,IAAA,CAAQ,KAAA,GAAoB,MAAA;AAE5B,IAAA,IAAA,CAAQ,KAAA,uBAAY,GAAA,EAAY;AAChC,IAAA,IAAA,CAAQ,aAAA,uBAAoB,GAAA,EAA6B;AAGvD,IAAA,IAAA,CAAK,IAAA,GAAO,OAAA;AACZ,IAAA,IAAA,CAAK,gBAAgB,OAAA,CAAQ,KAAA;AAAA,EAC/B;AAAA,EAEA,WAAW,MAAA,EAA8B;AACvC,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA,EAGA,KAAA,GAAc;AACZ,IAAA,IAAI,KAAK,SAAA,IAAa,IAAA,CAAK,QAAA,IAAY,OAAO,WAAW,WAAA,EAAa;AACtE,IAAA,IAAA,CAAK,SAAS,YAAY,CAAA;AAK1B,IAAA,KAAK,OAAO,kCAAkC,CAAA,CAC3C,KAAK,CAAC,EAAE,oBAAmB,KAAM;AAChC,MAAA,IAAI,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,QAAA,EAAU;AACrC,MAAA,IAAA,CAAK,UAAU,kBAAA,CAAmB;AAAA,QAChC,OAAA,EAAS,KAAK,IAAA,CAAK,OAAA;AAAA,QACnB,OAAA,EAAS,KAAK,IAAA,CAAK,SAAA;AAAA,QACnB,KAAA,EAAO,KAAK,IAAA,CAAK,KAAA;AAAA,QACjB,SAAA,EAAW,MAAA;AAAA,QACX,gBAAA,EAAkB,SAAA;AAAA,QAClB,QAAA,EAAU,QAAA;AAAA,QACV,OAAA,EAAS,CAAC,GAAA,KAAQ,IAAA,CAAK,cAAc,GAAG,CAAA;AAAA,QACxC,MAAA,EAAQ,MAAM,IAAA,CAAK,QAAA,EAAS;AAAA,QAC5B,OAAA,EAAS,MAAM,IAAA,CAAK,QAAA,CAAS,OAAO,CAAA;AAAA,QACpC,SAAA,EAAW,KAAK,IAAA,CAAK;AAAA,OACtB,CAAA;AACD,MAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AAAA,IACrB,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,MAAA,IAAI,CAAC,IAAA,CAAK,QAAA,EAAU,IAAA,CAAK,QAAA,EAAS;AAAA,IACpC,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,QAAA,GAAiB;AACvB,IAAA,IAAI,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,QAAA,EAAU;AACrC,IAAA,MAAM,MAAM,CAAA,EAAG,IAAA,CAAK,IAAA,CAAK,OAAO,IAAI,kBAAA,CAAmB,IAAA,CAAK,IAAA,CAAK,SAAS,CAAC,CAAA,cAAA,EAAiB,kBAAA,CAAmB,IAAA,CAAK,IAAA,CAAK,KAAK,CAAC,CAAA,CAAA;AAC/H,IAAA,MAAM,KAAK,IAAI,WAAA,CAAY,KAAK,EAAE,eAAA,EAAiB,OAAO,CAAA;AAC1D,IAAA,IAAA,CAAK,EAAA,GAAK,EAAA;AACV,IAAA,EAAA,CAAG,gBAAA,CAAiB,MAAA,EAAQ,MAAM,IAAA,CAAK,UAAU,CAAA;AACjD,IAAA,EAAA,CAAG,gBAAA,CAAiB,OAAO,CAAC,EAAA,KAAqB,KAAK,aAAA,CAAc,EAAA,CAAG,IAAI,CAAC,CAAA;AAC5E,IAAA,EAAA,CAAG,iBAAiB,OAAA,EAAS,MAAM,IAAA,CAAK,QAAA,CAAS,OAAO,CAAC,CAAA;AAAA,EAC3D;AAAA;AAAA,EAGQ,QAAA,GAAiB;AACvB,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AACjB,IAAA,IAAA,CAAK,SAAS,MAAM,CAAA;AACpB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,CAAC,CAAA;AACtC,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,EAAQ,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAAA,EAC5C;AAAA,EAEA,KAAK,OAAA,EAA+B;AAClC,IAAA,IAAI,CAAC,KAAK,SAAA,EAAW;AACnB,MAAA,IAAA,CAAK,SAAA,CAAU,KAAK,OAAO,CAAA;AAC3B,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,QAAQ,OAAO,CAAA;AAAA,EACtB;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAChB,IAAA,IAAA,CAAK,SAAS,IAAA,EAAK;AACnB,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,IAAI,KAAA,EAAM;AACf,IAAA,IAAA,CAAK,EAAA,GAAK,MAAA;AACV,IAAA,IAAA,CAAK,SAAA,GAAY,KAAA;AACjB,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AACjB,IAAA,IAAA,CAAK,WAAA,EAAY;AACjB,IAAA,IAAA,CAAK,SAAS,QAAQ,CAAA;AAAA,EACxB;AAAA,EAEA,cAAc,QAAA,EAAmD;AAC/D,IAAA,IAAA,CAAK,SAAA,CAAU,IAAI,QAAQ,CAAA;AAC3B,IAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AACnB,IAAA,OAAO,MAAM,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,QAAQ,CAAA;AAAA,EAC7C;AAAA;AAAA,EAGA,SAAA,GAAoB;AAClB,IAAA,OAAO,KAAK,KAAA,CAAM,IAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,cAAc,QAAA,EAA+C;AAC3D,IAAA,IAAA,CAAK,aAAA,CAAc,IAAI,QAAQ,CAAA;AAC/B,IAAA,QAAA,CAAS,IAAA,CAAK,MAAM,IAAI,CAAA;AACxB,IAAA,OAAO,MAAM,IAAA,CAAK,aAAA,CAAc,MAAA,CAAO,QAAQ,CAAA;AAAA,EACjD;AAAA,EAEQ,WAAA,GAAoB;AAC1B,IAAA,KAAA,MAAW,KAAK,IAAA,CAAK,aAAA,EAAe,CAAA,CAAE,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBAAA,CAAkB,OAAA,EAAkC,KAAA,EAA+B;AACvF,IAAA,IAAI,UAAU,MAAA,IAAa,CAAC,kBAAkB,KAAA,EAAO,IAAA,CAAK,aAAa,CAAA,EAAG;AAC1E,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,MAAM,IAAI,MAAM,uCAAuC,CAAA;AACzE,IAAA,MAAM,UAA0B,OAAO,OAAA,KAAY,WAAW,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA,GAAI,OAAA;AACpF,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA;AAAA,EACzC;AAAA,EAEA,MAAc,QAAQ,OAAA,EAAwC;AAC5D,IAAA,MAAM,MAAM,CAAA,EAAG,IAAA,CAAK,IAAA,CAAK,OAAO,IAAI,kBAAA,CAAmB,IAAA,CAAK,IAAA,CAAK,SAAS,CAAC,CAAA,cAAA,EAAiB,kBAAA,CAAmB,IAAA,CAAK,IAAA,CAAK,KAAK,CAAC,CAAA,CAAA;AAC/H,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,IAAA,CAAK,KAAA,IAAS,KAAA;AAC7B,IAAA,IAAI;AACF,MAAA,MAAM,EAAE,GAAA,EAAK;AAAA,QACX,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,UAAU,kBAAA,EAAmB;AAAA,QAC5E,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,OAC7B,CAAA;AAAA,IACH,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,GAAA,EAA4B;AACtD,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAClB,IAAA,IAAI,OAAA;AACJ,IAAA,IAAI;AACF,MAAA,OAAA,GAAU,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,IAC1B,CAAA,CAAA,MAAQ;AACN,MAAA;AAAA,IACF;AACA,IAAA,IAAI,QAAA,IAAY,OAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,2BAAA,EAA6B;AACzE,MAAA,MAAM,YAAA,GAAe,MAAA,CAAQ,OAAA,CAAQ,MAAA,EAAmD,gBAAgB,MAAM,CAAA;AAC9G,MAAA,IAAA,CAAK,KAAA,CAAM,IAAI,YAAY,CAAA;AAC3B,MAAA,IAAA,CAAK,WAAA,EAAY;AACjB,MAAAH,4BAAA,CAAa;AAAA,QACX,OAAA,EAAS,OAAA;AAAA,QACT,SAAA,EAAW,OAAA;AAAA,QACX,UAAA,EAAY,SAAA;AAAA,QACZ,MAAA,EAAQ,iBAAA;AAAA,QACR,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,MAAA,EAAQ,EAAE,IAAA,EAAM,YAAA,EAAc,OAAO,iBAAA,EAAkB;AAAA,QACvD,IAAA,EAAM,EAAE,YAAA;AAAa,OACtB,CAAA;AACD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,QAAA,IAAY,OAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,yBAAA,EAA2B;AACvE,MAAA,MAAM,YAAA,GAAe,MAAA,CAAQ,OAAA,CAAQ,MAAA,EAAmD,gBAAgB,MAAM,CAAA;AAC9G,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,YAAY,CAAA;AAC9B,MAAA,IAAA,CAAK,WAAA,EAAY;AACjB,MAAA,IAAI,IAAA,CAAK,KAAA,CAAM,IAAA,KAAS,CAAA,EAAG;AACzB,QAAAA,4BAAA,CAAa;AAAA,UACX,OAAA,EAAS,OAAA;AAAA,UACT,SAAA,EAAW,OAAA;AAAA,UACX,UAAA,EAAY,SAAA;AAAA,UACZ,MAAA,EAAQ,oBAAA;AAAA,UACR,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,UACpB,MAAA,EAAQ,EAAE,IAAA,EAAM,YAAA,EAAc,OAAO,oBAAA,EAAqB;AAAA,UAC1D,IAAA,EAAM,EAAE,YAAA;AAAa,SACtB,CAAA;AAAA,MACH;AACA,MAAA;AAAA,IACF;AACA,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA;AAAA,EACzC;AAAA,EAEQ,SAAS,KAAA,EAAyB;AACxC,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,KAAA,MAAW,CAAA,IAAK,IAAA,CAAK,SAAA,EAAW,CAAA,CAAE,KAAK,CAAA;AAAA,EACzC;AACF;AAIO,SAAS,cAAA,CAAe,QAAwB,OAAA,EAA6C;AAClG,EAAA,MAAM,SAAA,GAAY,IAAI,iBAAA,CAAkB,OAAO,CAAA;AAC/C,EAAA,SAAA,CAAU,WAAW,MAAM,CAAA;AAC3B,EAAA,MAAA,CAAO,OAAO,SAAS,CAAA;AACvB,EAAA,SAAA,CAAU,KAAA,EAAM;AAMhB,EAAA,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,aAAA,EAAA,EAAA,gBAAA,CAAA,CAAA,CAA+B,IAAA,CAAK,CAAC,EAAE,UAAA,EAAAC,aAAW,KAAM;AACtD,IAAA,MAAM,GAAA,GAAMA,WAAAA,CAAW,CAAC,KAAA,KAAU;AAChC,MAAA,SAAA,CAAU,IAAA,CAAK;AAAA,QACb,OAAA,EAAS,KAAA;AAAA,QACT,MAAA,EAAQ,8BAAA;AAAA,QACR,MAAA,EAAQ;AAAA,OACT,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,MAAM,SAAA,GAAY,SAAA,CAAU,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA;AAChD,IAAA,SAAA,CAAU,QAAQ,MAAM;AACtB,MAAA,GAAA,EAAI;AACJ,MAAA,SAAA,EAAU;AAAA,IACZ,CAAA;AAAA,EACF,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,EAEf,CAAC,CAAA;AAED,EAAA,OAAO,SAAA;AACT","file":"sharing.cjs","sourcesContent":["/**\n * In-process registry of activity events. Now backed by the shared bus in\n * `@particle-academy/fancy-auto-common`, so agent activity (here) and flow\n * activity (fancy-flow's FlowRunnerUx) land in ONE stream — presence layers\n * render both. Re-exported under the same names for back-compat.\n */\nexport {\n emitActivity,\n onActivity,\n readActivityHistory,\n resetActivityRegistry,\n} from \"@particle-academy/fancy-auto-common\";\n","/**\n * Session-token utilities. The token is a high-entropy secret; possession\n * grants read/write on the session. We don't HMAC frames — frames carry\n * the token directly (which is fine for in-process / same-origin / TLS\n * transports). For lower-trust transports, host apps can layer signing\n * on top of the BroadcastChannelTransport.\n */\n\nconst TOKEN_BYTES = 24; // 192 bits, base64url-encoded → 32 chars\n\nexport type SessionDescriptor = {\n /** Stable session identifier. Channel name = `fai:share:${id}`. */\n id: string;\n /** Secret token. Treat as a password — anyone with it can read/write. */\n token: string;\n /** Pretty hash for display (first 8 chars of token). */\n display: string;\n};\n\nexport function createSessionDescriptor(): SessionDescriptor {\n const id = randomId(8);\n const token = randomToken();\n return { id, token, display: token.slice(0, 8) };\n}\n\nexport function describeSession(id: string, token: string): SessionDescriptor {\n return { id, token, display: token.slice(0, 8) };\n}\n\n/**\n * Build the shareable URL for the current page (preserves path, adds\n * session+token in the URL FRAGMENT).\n *\n * The token goes in the `#fragment`, never the `?query`: a fragment is never\n * transmitted to the server, so it can't leak through access/proxy logs or the\n * `Referer` header sent to third-party assets on the page. The recipient reads\n * it back with {@link readSessionFromUrl}. (The on-wire relay leg still sends\n * `?token=` today — moving that off the query is the larger transport change.)\n */\nexport function buildShareUrl(\n descriptor: SessionDescriptor,\n baseUrl: string = typeof window !== \"undefined\" ? window.location.href.split(\"?\")[0] : \"\",\n): string {\n const u = new URL(baseUrl);\n u.hash = new URLSearchParams({ session: descriptor.id, token: descriptor.token }).toString();\n return u.toString();\n}\n\n/** Build the JSON config form (suitable for Claude Desktop / Cline / etc.). */\nexport function buildShareConfig(descriptor: SessionDescriptor, transport = \"broadcast-channel\") {\n return {\n name: `whiteboard-${descriptor.id}`,\n transport,\n session: descriptor.id,\n token: descriptor.token,\n channel: `fai:share:${descriptor.id}`,\n protocol_version: \"2025-06-18\",\n };\n}\n\n/**\n * Read session descriptor from the current URL, or null if not a shared link.\n * Prefers the fragment (the non-leaking form {@link buildShareUrl} now emits),\n * falling back to the query string for links minted before that change.\n */\nexport function readSessionFromUrl(): SessionDescriptor | null {\n if (typeof window === \"undefined\") return null;\n const url = new URL(window.location.href);\n const frag = new URLSearchParams(url.hash.replace(/^#/, \"\"));\n const id = frag.get(\"session\") ?? url.searchParams.get(\"session\");\n const token = frag.get(\"token\") ?? url.searchParams.get(\"token\");\n if (!id || !token) return null;\n return describeSession(id, token);\n}\n\nfunction randomToken(): string {\n const bytes = new Uint8Array(TOKEN_BYTES);\n crypto.getRandomValues(bytes);\n return base64Url(bytes);\n}\n\nfunction randomId(len: number): string {\n const bytes = new Uint8Array(Math.ceil((len * 3) / 4));\n crypto.getRandomValues(bytes);\n return base64Url(bytes).slice(0, len);\n}\n\nfunction base64Url(bytes: Uint8Array): string {\n let s = \"\";\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n/** Constant-time string compare so a mismatched token leaks no timing info. */\nexport function constantTimeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n return diff === 0;\n}\n","import type { JsonRpcMessage } from \"../mcp/types\";\nimport type { Transport } from \"../mcp/server\";\nimport type { MicroMcpServer } from \"../mcp/server\";\nimport type { RelayChannelHandle } from \"@particle-academy/fancy-cf-relay\";\nimport { constantTimeEqual } from \"./token\";\nimport { emitActivity } from \"../presence/registry\";\n\n/**\n * SseRelayTransport — bridges the in-page MicroMcpServer to a host-app\n * relay broker over Server-Sent Events (inbound) + POST (outbound).\n *\n * Wire model:\n * - Browser opens an EventSource at `${baseUrl}/${sessionId}/events?token=…`.\n * Each `event: mcp` carries one JSON-RPC frame from a remote client.\n * - Browser POSTs JSON-RPC frames to `${baseUrl}/${sessionId}/outbox?token=…`\n * when the local server has a response/notification to send.\n *\n * The host provides the relay endpoint (any HTTP server). See the demo\n * `WhiteboardShareController` for the reference implementation.\n *\n * Token authentication is the host's job — this transport just carries the\n * token in the query string. For lower-trust deployments, layer signing on\n * top by wrapping `send` / `deliverFromRemote`.\n */\nexport type SseRelayOptions = {\n baseUrl: string;\n sessionId: string;\n token: string;\n /** Override fetch (testing / non-browser). Defaults to global fetch. */\n fetch?: typeof fetch;\n};\n\nexport class SseRelayTransport implements Transport {\n private server?: MicroMcpServer;\n private es?: EventSource;\n private channel?: RelayChannelHandle;\n private disposed = false;\n private opts: SseRelayOptions;\n private sendQueue: JsonRpcMessage[] = [];\n private connected = false;\n private listeners = new Set<(state: RelayState) => void>();\n private state: RelayState = \"idle\";\n private expectedToken: string;\n private peers = new Set<string>();\n private peerListeners = new Set<(count: number) => void>();\n\n constructor(options: SseRelayOptions) {\n this.opts = options;\n this.expectedToken = options.token;\n }\n\n bindServer(server: MicroMcpServer): void {\n this.server = server;\n }\n\n /** Open the receive channel. Idempotent. */\n start(): void {\n if (this.connected || this.disposed || typeof window === \"undefined\") return;\n this.setState(\"connecting\");\n // Prefer @particle-academy/fancy-cf-relay's adaptive channel (auto SSE↔\n // long-poll with Cloudflare detection) so the receive leg survives a\n // Cloudflare HTTP/3 (QUIC) edge that resets long-lived SSE streams. It's an\n // OPTIONAL peer: if it isn't installed, fall back to a plain EventSource.\n void import(\"@particle-academy/fancy-cf-relay\")\n .then(({ createRelayChannel }) => {\n if (this.connected || this.disposed) return;\n this.channel = createRelayChannel({\n baseUrl: this.opts.baseUrl,\n session: this.opts.sessionId,\n token: this.opts.token,\n transport: \"auto\",\n receiveDirection: \"inbound\",\n sendPath: \"outbox\",\n onFrame: (raw) => this.handleInbound(raw),\n onOpen: () => this.markOpen(),\n onError: () => this.setState(\"error\"),\n fetchImpl: this.opts.fetch,\n });\n this.channel.start();\n })\n .catch(() => {\n if (!this.disposed) this.startSse();\n });\n }\n\n /** Fallback receive leg: a plain EventSource (no fancy-cf-relay installed). */\n private startSse(): void {\n if (this.connected || this.disposed) return;\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/events?token=${encodeURIComponent(this.opts.token)}`;\n const es = new EventSource(url, { withCredentials: false });\n this.es = es;\n es.addEventListener(\"open\", () => this.markOpen());\n es.addEventListener(\"mcp\", (ev: MessageEvent) => this.handleInbound(ev.data));\n es.addEventListener(\"error\", () => this.setState(\"error\")); // EventSource auto-reconnects\n }\n\n /** Mark the channel live + flush any queued outbound frames. */\n private markOpen(): void {\n this.connected = true;\n this.setState(\"open\");\n const queued = this.sendQueue.splice(0);\n for (const msg of queued) this.postOut(msg);\n }\n\n send(message: JsonRpcMessage): void {\n if (!this.connected) {\n this.sendQueue.push(message);\n return;\n }\n this.postOut(message);\n }\n\n close(): void {\n this.disposed = true;\n this.channel?.stop();\n this.channel = undefined;\n this.es?.close();\n this.es = undefined;\n this.connected = false;\n this.peers.clear();\n this.notifyPeers();\n this.setState(\"closed\");\n }\n\n onStateChange(listener: (state: RelayState) => void): () => void {\n this.listeners.add(listener);\n listener(this.state);\n return () => this.listeners.delete(listener);\n }\n\n /** How many remote peers (agents) are currently attached to this session. */\n peerCount(): number {\n return this.peers.size;\n }\n\n /**\n * Subscribe to peer arrivals/departures. Fires immediately with the current\n * count.\n *\n * This is the ONLY honest answer to \"is an agent actually here?\".\n * `onStateChange` reports the BROWSER's own channel to the relay, which opens\n * the instant sharing starts — so a UI keyed on it announces \"Agent is\n * driving\" to a human who has not yet handed the link to anybody, and can\n * never tell them when one really arrives.\n */\n onPeersChange(listener: (count: number) => void): () => void {\n this.peerListeners.add(listener);\n listener(this.peers.size);\n return () => this.peerListeners.delete(listener);\n }\n\n private notifyPeers(): void {\n for (const l of this.peerListeners) l(this.peers.size);\n }\n\n /**\n * For relays that wrap each frame with auth metadata: hosts can call this\n * directly when a frame arrives via a non-SSE path. The transport will\n * dispatch it to the bound server.\n */\n async deliverFromRemote(payload: JsonRpcMessage | string, token?: string): Promise<void> {\n if (token !== undefined && !constantTimeEqual(token, this.expectedToken)) return;\n if (!this.server) throw new Error(\"SseRelayTransport has no bound server\");\n const message: JsonRpcMessage = typeof payload === \"string\" ? JSON.parse(payload) : payload;\n await this.server.receive(this, message);\n }\n\n private async postOut(message: JsonRpcMessage): Promise<void> {\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/outbox?token=${encodeURIComponent(this.opts.token)}`;\n const f = this.opts.fetch ?? fetch;\n try {\n await f(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"accept\": \"application/json\" },\n body: JSON.stringify(message),\n });\n } catch {\n // Drop — relay errors are surfaced via state change separately.\n }\n }\n\n private async handleInbound(raw: string): Promise<void> {\n if (!this.server) return;\n let message: JsonRpcMessage;\n try {\n message = JSON.parse(raw);\n } catch {\n return;\n }\n if (\"method\" in message && message.method === \"notifications/peer_joined\") {\n const subscriberId = String((message.params as { subscriberId?: unknown } | undefined)?.subscriberId ?? \"peer\");\n this.peers.add(subscriberId);\n this.notifyPeers();\n emitActivity({\n agentId: \"agent\",\n agentName: \"Agent\",\n agentColor: \"#a855f7\",\n action: \"agent_connected\",\n timestamp: Date.now(),\n target: { kind: \"navigation\", label: \"Agent connected\" },\n meta: { subscriberId },\n });\n return;\n }\n if (\"method\" in message && message.method === \"notifications/peer_left\") {\n const subscriberId = String((message.params as { subscriberId?: unknown } | undefined)?.subscriberId ?? \"peer\");\n this.peers.delete(subscriberId);\n this.notifyPeers();\n if (this.peers.size === 0) {\n emitActivity({\n agentId: \"agent\",\n agentName: \"Agent\",\n agentColor: \"#a855f7\",\n action: \"agent_disconnected\",\n timestamp: Date.now(),\n target: { kind: \"navigation\", label: \"Agent disconnected\" },\n meta: { subscriberId },\n });\n }\n return;\n }\n await this.server.receive(this, message);\n }\n\n private setState(state: RelayState): void {\n this.state = state;\n for (const l of this.listeners) l(state);\n }\n}\n\nexport type RelayState = \"idle\" | \"connecting\" | \"open\" | \"closed\" | \"error\";\n\nexport function attachSseRelay(server: MicroMcpServer, options: SseRelayOptions): SseRelayTransport {\n const transport = new SseRelayTransport(options);\n transport.bindServer(server);\n server.attach(transport);\n transport.start();\n\n // Forward in-process agent activity events out over the relay so external\n // subscribers can render presence indicators in real time. Uses a dynamic\n // import so the relay doesn't hard-depend on the presence module if it's\n // tree-shaken out.\n import(\"../presence/registry\").then(({ onActivity }) => {\n const off = onActivity((event) => {\n transport.send({\n jsonrpc: \"2.0\",\n method: \"notifications/agent_activity\",\n params: event as any,\n });\n });\n // Tear down the subscription when the transport closes.\n const origClose = transport.close.bind(transport);\n transport.close = () => {\n off();\n origClose();\n };\n }).catch(() => {\n // Presence module unavailable — silently no-op (relay still works).\n });\n\n return transport;\n}\n"]}
package/dist/sharing.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import './chunk-IJ6JX5VC.js';
2
- export { SseRelayTransport, attachSseRelay, buildShareConfig, buildShareUrl, constantTimeEqual, createSessionDescriptor, describeSession, readSessionFromUrl } from './chunk-N6RLSLOF.js';
2
+ export { SseRelayTransport, attachSseRelay, buildShareConfig, buildShareUrl, constantTimeEqual, createSessionDescriptor, describeSession, readSessionFromUrl } from './chunk-JDCB2NMM.js';
3
3
  import './chunk-C3TYI5TJ.js';
4
4
  //# sourceMappingURL=sharing.js.map
5
5
  //# sourceMappingURL=sharing.js.map