@particle-academy/agent-integrations 0.2.4 → 0.3.4

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.
Files changed (107) hide show
  1. package/dist/bridges/charts.d.cts +39 -0
  2. package/dist/bridges/charts.d.ts +39 -0
  3. package/dist/bridges/code.d.cts +47 -0
  4. package/dist/bridges/code.d.ts +47 -0
  5. package/dist/bridges/flow.d.cts +3 -2
  6. package/dist/bridges/flow.d.ts +3 -2
  7. package/dist/bridges/forms.d.cts +76 -0
  8. package/dist/bridges/forms.d.ts +76 -0
  9. package/dist/bridges/scene.d.cts +54 -0
  10. package/dist/bridges/scene.d.ts +54 -0
  11. package/dist/bridges/sheets.d.cts +62 -0
  12. package/dist/bridges/sheets.d.ts +62 -0
  13. package/dist/bridges/whiteboard.d.cts +3 -2
  14. package/dist/bridges/whiteboard.d.ts +3 -2
  15. package/dist/bridges-charts.cjs +167 -0
  16. package/dist/bridges-charts.cjs.map +1 -0
  17. package/dist/bridges-charts.js +6 -0
  18. package/dist/bridges-charts.js.map +1 -0
  19. package/dist/bridges-code.cjs +219 -0
  20. package/dist/bridges-code.cjs.map +1 -0
  21. package/dist/bridges-code.js +6 -0
  22. package/dist/bridges-code.js.map +1 -0
  23. package/dist/bridges-flow.cjs +76 -17
  24. package/dist/bridges-flow.cjs.map +1 -1
  25. package/dist/bridges-flow.js +3 -1
  26. package/dist/bridges-forms.cjs +205 -0
  27. package/dist/bridges-forms.cjs.map +1 -0
  28. package/dist/bridges-forms.js +6 -0
  29. package/dist/bridges-forms.js.map +1 -0
  30. package/dist/bridges-scene.cjs +250 -0
  31. package/dist/bridges-scene.cjs.map +1 -0
  32. package/dist/bridges-scene.js +6 -0
  33. package/dist/bridges-scene.js.map +1 -0
  34. package/dist/bridges-sheets.cjs +327 -0
  35. package/dist/bridges-sheets.cjs.map +1 -0
  36. package/dist/bridges-sheets.js +6 -0
  37. package/dist/bridges-sheets.js.map +1 -0
  38. package/dist/bridges-whiteboard.cjs +224 -38
  39. package/dist/bridges-whiteboard.cjs.map +1 -1
  40. package/dist/bridges-whiteboard.js +4 -1
  41. package/dist/{chunk-2VOQJKSU.js → chunk-4IAVAFUV.js} +41 -19
  42. package/dist/chunk-4IAVAFUV.js.map +1 -0
  43. package/dist/chunk-52S7XYZK.js +38 -0
  44. package/dist/chunk-52S7XYZK.js.map +1 -0
  45. package/dist/chunk-ACBENYYO.js +124 -0
  46. package/dist/chunk-ACBENYYO.js.map +1 -0
  47. package/dist/chunk-DJOWMF6Q.js +25 -0
  48. package/dist/chunk-DJOWMF6Q.js.map +1 -0
  49. package/dist/{chunk-FLEOQUKF.js → chunk-JMYPUAFH.js} +17 -2
  50. package/dist/chunk-JMYPUAFH.js.map +1 -0
  51. package/dist/chunk-JU2N4KK6.js +34 -0
  52. package/dist/chunk-JU2N4KK6.js.map +1 -0
  53. package/dist/chunk-OEIULP2L.js +158 -0
  54. package/dist/chunk-OEIULP2L.js.map +1 -0
  55. package/dist/chunk-PDBF4W7E.js +280 -0
  56. package/dist/chunk-PDBF4W7E.js.map +1 -0
  57. package/dist/chunk-PHPXKSWI.js +120 -0
  58. package/dist/chunk-PHPXKSWI.js.map +1 -0
  59. package/dist/chunk-QJUTISFC.js +203 -0
  60. package/dist/chunk-QJUTISFC.js.map +1 -0
  61. package/dist/{chunk-5ZUHNNLR.js → chunk-TBEITXF4.js} +79 -41
  62. package/dist/chunk-TBEITXF4.js.map +1 -0
  63. package/dist/chunk-X66JWQBB.js +37 -0
  64. package/dist/chunk-X66JWQBB.js.map +1 -0
  65. package/dist/chunk-XYYSTJHW.js +172 -0
  66. package/dist/chunk-XYYSTJHW.js.map +1 -0
  67. package/dist/index.cjs +1411 -57
  68. package/dist/index.cjs.map +1 -1
  69. package/dist/index.d.cts +96 -3
  70. package/dist/index.d.ts +96 -3
  71. package/dist/index.js +111 -7
  72. package/dist/index.js.map +1 -1
  73. package/dist/mcp/index.d.cts +4 -2
  74. package/dist/mcp/index.d.ts +4 -2
  75. package/dist/presence/index.d.cts +136 -0
  76. package/dist/presence/index.d.ts +136 -0
  77. package/dist/presence.cjs +107 -0
  78. package/dist/presence.cjs.map +1 -0
  79. package/dist/presence.js +5 -0
  80. package/dist/presence.js.map +1 -0
  81. package/dist/registry-2DRURS6U.js +3 -0
  82. package/dist/registry-2DRURS6U.js.map +1 -0
  83. package/dist/server-BJu_AMH3.d.ts +64 -0
  84. package/dist/server-si-VvFxI.d.cts +64 -0
  85. package/dist/sharing/index.d.cts +2 -1
  86. package/dist/sharing/index.d.ts +2 -1
  87. package/dist/sharing.cjs +68 -0
  88. package/dist/sharing.cjs.map +1 -1
  89. package/dist/sharing.js +1 -1
  90. package/dist/styles.css +57 -0
  91. package/dist/styles.css.map +1 -1
  92. package/dist/{types-DR5AS6Rd.d.cts → types-Bf1ZoGmI.d.cts} +1 -1
  93. package/dist/{types-CRPA_D0z.d.ts → types-DXKpLuia.d.ts} +1 -1
  94. package/dist/types-DksGd5Y7.d.cts +112 -0
  95. package/dist/types-DksGd5Y7.d.ts +112 -0
  96. package/dist/undo/index.d.cts +69 -0
  97. package/dist/undo/index.d.ts +69 -0
  98. package/dist/undo.cjs +163 -0
  99. package/dist/undo.cjs.map +1 -0
  100. package/dist/undo.js +5 -0
  101. package/dist/undo.js.map +1 -0
  102. package/package.json +1 -1
  103. package/dist/chunk-2VOQJKSU.js.map +0 -1
  104. package/dist/chunk-5ZUHNNLR.js.map +0 -1
  105. package/dist/chunk-FLEOQUKF.js.map +0 -1
  106. package/dist/server-Bv985us3.d.cts +0 -173
  107. package/dist/server-Bv985us3.d.ts +0 -173
@@ -0,0 +1,107 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/presence/registry.ts
6
+ var HISTORY_CAP = 200;
7
+ var listeners = /* @__PURE__ */ new Set();
8
+ var history = [];
9
+ function emitActivity(event) {
10
+ history.push(event);
11
+ if (history.length > HISTORY_CAP) history.splice(0, history.length - HISTORY_CAP);
12
+ for (const l of listeners) l(event);
13
+ }
14
+ function onActivity(listener, filter) {
15
+ const wrapped = filter ? (e) => {
16
+ if (matches(e, filter)) listener(e);
17
+ } : listener;
18
+ listeners.add(wrapped);
19
+ return () => listeners.delete(wrapped);
20
+ }
21
+ function readActivityHistory(filter) {
22
+ if (!filter) return history.slice();
23
+ return history.filter((e) => matches(e, filter));
24
+ }
25
+ function resetActivityRegistry() {
26
+ listeners.clear();
27
+ history.length = 0;
28
+ }
29
+ function matches(e, f) {
30
+ if (f.agentId !== void 0 && e.agentId !== f.agentId) return false;
31
+ if (f.screenId !== void 0 && e.target.screenId !== f.screenId) return false;
32
+ if (f.kind !== void 0 && e.target.kind !== f.kind) return false;
33
+ return true;
34
+ }
35
+
36
+ // src/presence/wrap-tool-with-activity.ts
37
+ function wrapToolWithActivity(handler, options) {
38
+ return async (args) => {
39
+ const result = await handler(args);
40
+ if (result.isError) return result;
41
+ let target;
42
+ if (options.resolveTarget) {
43
+ target = options.resolveTarget({ toolName: options.toolName, args, result });
44
+ } else {
45
+ target = { kind: options.kind, screenId: options.screenId };
46
+ }
47
+ if (!target) return result;
48
+ emitActivity({
49
+ agentId: options.agent.id,
50
+ agentName: options.agent.name,
51
+ agentColor: options.agent.color,
52
+ target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },
53
+ action: options.toolName,
54
+ timestamp: Date.now(),
55
+ meta: extractMeta(result),
56
+ ttlMs: options.ttlMs
57
+ });
58
+ return result;
59
+ };
60
+ }
61
+ function extractMeta(result) {
62
+ const sc = result.structuredContent;
63
+ if (sc && typeof sc === "object" && !Array.isArray(sc)) {
64
+ return sc;
65
+ }
66
+ return void 0;
67
+ }
68
+ function useAgentActivity(filter, options = {}) {
69
+ const cap = options.capacity ?? 50;
70
+ const [events, setEvents] = react.useState(() => readActivityHistory(filter).slice(-cap));
71
+ react.useEffect(() => {
72
+ setEvents(readActivityHistory(filter).slice(-cap));
73
+ return onActivity((event) => {
74
+ setEvents((prev) => {
75
+ const next = prev.length >= cap ? prev.slice(prev.length - cap + 1) : prev.slice();
76
+ next.push(event);
77
+ return next;
78
+ });
79
+ }, filter);
80
+ }, [filter?.agentId, filter?.screenId, filter?.kind, cap]);
81
+ return { events, latest: events.length > 0 ? events[events.length - 1] : null };
82
+ }
83
+ function useAgentActivityForScreen(screenId, options = {}) {
84
+ const { events, latest } = useAgentActivity({ screenId }, options);
85
+ const fadeAfter = latest?.ttlMs ?? 1500;
86
+ const [isAgentActive, setActive] = react.useState(false);
87
+ react.useEffect(() => {
88
+ if (!latest) {
89
+ setActive(false);
90
+ return;
91
+ }
92
+ setActive(true);
93
+ const timer = setTimeout(() => setActive(false), fadeAfter);
94
+ return () => clearTimeout(timer);
95
+ }, [latest, fadeAfter]);
96
+ return { events, latest, isAgentActive };
97
+ }
98
+
99
+ exports.emitActivity = emitActivity;
100
+ exports.onActivity = onActivity;
101
+ exports.readActivityHistory = readActivityHistory;
102
+ exports.resetActivityRegistry = resetActivityRegistry;
103
+ exports.useAgentActivity = useAgentActivity;
104
+ exports.useAgentActivityForScreen = useAgentActivityForScreen;
105
+ exports.wrapToolWithActivity = wrapToolWithActivity;
106
+ //# sourceMappingURL=presence.cjs.map
107
+ //# sourceMappingURL=presence.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presence/registry.ts","../src/presence/wrap-tool-with-activity.ts","../src/presence/use-agent-activity.ts"],"names":["useState","useEffect"],"mappings":"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","file":"presence.cjs","sourcesContent":["import type { ActivityFilter, AgentActivityEvent, AgentActivityListener } from \"./types\";\n\n/**\n * In-process registry of agent activity events. Bridges call `emitActivity`\n * after a tool runs; React hooks + the SSE relay subscribe via\n * `onActivity()`.\n *\n * Holds a short scrollback of recent events (default 200) so newly-mounted\n * subscribers can render the recent past — useful for activity-log UIs\n * that rejoin a session mid-stream.\n */\n\nconst HISTORY_CAP = 200;\n\nconst listeners = new Set<AgentActivityListener>();\nconst history: AgentActivityEvent[] = [];\n\n/** Emit an activity event. All current listeners receive it synchronously. */\nexport function emitActivity(event: AgentActivityEvent): void {\n history.push(event);\n if (history.length > HISTORY_CAP) history.splice(0, history.length - HISTORY_CAP);\n for (const l of listeners) l(event);\n}\n\n/**\n * Subscribe to all events (or a filtered subset). Returns an unsubscribe\n * function. Filter checks all provided keys with strict equality; omit a\n * key to ignore it.\n */\nexport function onActivity(listener: AgentActivityListener, filter?: ActivityFilter): () => void {\n const wrapped: AgentActivityListener = filter\n ? (e) => { if (matches(e, filter)) listener(e); }\n : listener;\n listeners.add(wrapped);\n return () => listeners.delete(wrapped);\n}\n\n/** Read the recent history (newest last). Optional filter. */\nexport function readActivityHistory(filter?: ActivityFilter): AgentActivityEvent[] {\n if (!filter) return history.slice();\n return history.filter((e) => matches(e, filter));\n}\n\n/** Wipe history + clear listeners. Test/teardown helper. */\nexport function resetActivityRegistry(): void {\n listeners.clear();\n history.length = 0;\n}\n\nfunction matches(e: AgentActivityEvent, f: ActivityFilter): boolean {\n if (f.agentId !== undefined && e.agentId !== f.agentId) return false;\n if (f.screenId !== undefined && e.target.screenId !== f.screenId) return false;\n if (f.kind !== undefined && e.target.kind !== f.kind) return false;\n return true;\n}\n","import type { CallToolResult } from \"../mcp/types\";\nimport { emitActivity } from \"./registry\";\nimport type { AgentTarget } from \"./types\";\n\nexport type ActivityAgent = { id: string; name?: string; color?: string };\n\nexport type ActivityResolverContext<TArgs = Record<string, unknown>> = {\n /** Tool name as registered. */\n toolName: string;\n /** Arguments the tool was called with. */\n args: TArgs;\n /** The CallToolResult the underlying handler produced. */\n result: CallToolResult;\n};\n\n/**\n * Resolves an `AgentTarget` for an executed tool. Bridges declare one of\n * these per registration so the wrapper knows which surface / element /\n * screen the activity belongs to.\n *\n * The resolver runs AFTER the tool handler so it can inspect the result\n * (e.g. read a newly-created item id from `structuredContent`).\n */\nexport type ActivityTargetResolver<TArgs = Record<string, unknown>> = (\n ctx: ActivityResolverContext<TArgs>,\n) => AgentTarget | null;\n\nexport type ToolHandler<TArgs = Record<string, unknown>> = (\n args: TArgs,\n) => Promise<CallToolResult> | CallToolResult;\n\n/**\n * wrapToolWithActivity — decorate a bridge tool handler so every successful\n * call emits an `AgentActivityEvent`. Returns a new handler with the same shape.\n *\n * Usage in a bridge:\n *\n * server.registerTool(\n * definition,\n * wrapToolWithActivity(\n * handler,\n * { agent, kind: \"whiteboard\", resolveTarget: ({ args }) => ({\n * kind: \"whiteboard\", elementId: args.id as string,\n * }) },\n * ),\n * );\n */\nexport function wrapToolWithActivity<TArgs = Record<string, unknown>>(\n handler: ToolHandler<TArgs>,\n options: {\n toolName: string;\n agent: ActivityAgent;\n /** Optional fancy-screens screen id this bridge is scoped to. */\n screenId?: string;\n /** Default target kind if the resolver returns one without `kind`. */\n kind: AgentTarget[\"kind\"];\n /** Per-call resolver. Return `null` to skip emitting (e.g. for read-only tools). */\n resolveTarget?: ActivityTargetResolver<TArgs>;\n /** Optional ttl override. */\n ttlMs?: number;\n },\n): ToolHandler<TArgs> {\n return async (args) => {\n const result = await handler(args);\n if (result.isError) return result;\n\n let target: AgentTarget | null;\n if (options.resolveTarget) {\n target = options.resolveTarget({ toolName: options.toolName, args, result });\n } else {\n target = { kind: options.kind, screenId: options.screenId };\n }\n if (!target) return result;\n\n emitActivity({\n agentId: options.agent.id,\n agentName: options.agent.name,\n agentColor: options.agent.color,\n target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },\n action: options.toolName,\n timestamp: Date.now(),\n meta: extractMeta(result),\n ttlMs: options.ttlMs,\n });\n return result;\n };\n}\n\nfunction extractMeta(result: CallToolResult): Record<string, unknown> | undefined {\n const sc = result.structuredContent;\n if (sc && typeof sc === \"object\" && !Array.isArray(sc)) {\n return sc as Record<string, unknown>;\n }\n return undefined;\n}\n","import { useEffect, useState } from \"react\";\nimport { onActivity, readActivityHistory } from \"./registry\";\nimport type { ActivityFilter, AgentActivityEvent } from \"./types\";\n\n/**\n * useAgentActivity — React subscription to the in-process activity stream.\n *\n * Returns:\n * - `events`: capped scrollback of recent events matching the filter\n * - `latest`: the most recent event (handy for transient highlights)\n */\nexport function useAgentActivity(\n filter?: ActivityFilter,\n options: { capacity?: number } = {},\n): { events: AgentActivityEvent[]; latest: AgentActivityEvent | null } {\n const cap = options.capacity ?? 50;\n const [events, setEvents] = useState<AgentActivityEvent[]>(() => readActivityHistory(filter).slice(-cap));\n\n useEffect(() => {\n setEvents(readActivityHistory(filter).slice(-cap));\n return onActivity((event) => {\n setEvents((prev) => {\n const next = prev.length >= cap ? prev.slice(prev.length - cap + 1) : prev.slice();\n next.push(event);\n return next;\n });\n }, filter);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [filter?.agentId, filter?.screenId, filter?.kind, cap]);\n\n return { events, latest: events.length > 0 ? events[events.length - 1] : null };\n}\n\n/**\n * useAgentActivityForScreen — convenience wrapper that filters by screen id.\n * Drives \"agent is here\" badges in fancy-screens-based shells.\n */\nexport function useAgentActivityForScreen(\n screenId: string,\n options: { capacity?: number } = {},\n): { events: AgentActivityEvent[]; latest: AgentActivityEvent | null; isAgentActive: boolean } {\n const { events, latest } = useAgentActivity({ screenId }, options);\n const fadeAfter = latest?.ttlMs ?? 1500;\n const [isAgentActive, setActive] = useState(false);\n\n useEffect(() => {\n if (!latest) {\n setActive(false);\n return;\n }\n setActive(true);\n const timer = setTimeout(() => setActive(false), fadeAfter);\n return () => clearTimeout(timer);\n }, [latest, fadeAfter]);\n\n return { events, latest, isAgentActive };\n}\n"]}
@@ -0,0 +1,5 @@
1
+ export { useAgentActivity, useAgentActivityForScreen } from './chunk-X66JWQBB.js';
2
+ export { wrapToolWithActivity } from './chunk-52S7XYZK.js';
3
+ export { emitActivity, onActivity, readActivityHistory, resetActivityRegistry } from './chunk-JU2N4KK6.js';
4
+ //# sourceMappingURL=presence.js.map
5
+ //# sourceMappingURL=presence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"presence.js"}
@@ -0,0 +1,3 @@
1
+ export { emitActivity, onActivity, readActivityHistory, resetActivityRegistry } from './chunk-JU2N4KK6.js';
2
+ //# sourceMappingURL=registry-2DRURS6U.js.map
3
+ //# sourceMappingURL=registry-2DRURS6U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"registry-2DRURS6U.js"}
@@ -0,0 +1,64 @@
1
+ import { S as ServerInfo, a as ServerCapabilities, J as JsonRpcMessage, T as ToolDefinition, b as ToolHandler, C as CallToolResult } from './types-DksGd5Y7.js';
2
+
3
+ type McpServerOptions = {
4
+ info: ServerInfo;
5
+ /** Defaults to { tools: { listChanged: true } } */
6
+ capabilities?: ServerCapabilities;
7
+ /** Free-text instructions surfaced to clients during initialize. */
8
+ instructions?: string;
9
+ };
10
+ type Transport = {
11
+ /** Called by the server when it has a message to deliver to the client. */
12
+ send: (message: JsonRpcMessage) => void;
13
+ /** Called by the server when it's torn down so the transport can clean up. */
14
+ close?: () => void;
15
+ };
16
+ /**
17
+ * MicroMcpServer — protocol-level MCP server, transport-agnostic.
18
+ *
19
+ * Use it like:
20
+ *
21
+ * const server = new MicroMcpServer({ info: { name: "session", version: "0.1" } });
22
+ * server.registerTool({ name: "...", inputSchema: { type: "object" } }, async (args) => ({...}));
23
+ * const transport = new InProcessTransport();
24
+ * server.attach(transport);
25
+ * transport.deliver({ ... }); // client → server frames
26
+ *
27
+ * The same server can serve multiple transports (e.g. an in-process agent
28
+ * AND a relayed external client) by attaching each one.
29
+ */
30
+ declare class MicroMcpServer {
31
+ private tools;
32
+ private transports;
33
+ private notifyListChangedScheduled;
34
+ readonly info: ServerInfo;
35
+ readonly capabilities: ServerCapabilities;
36
+ readonly instructions?: string;
37
+ constructor(options: McpServerOptions);
38
+ attach(transport: Transport): () => void;
39
+ detach(transport: Transport): void;
40
+ registerTool(definition: ToolDefinition, handler: ToolHandler): () => void;
41
+ unregisterTool(name: string): void;
42
+ listTools(): ToolDefinition[];
43
+ /**
44
+ * Receive a JSON-RPC frame from a client (called by the transport).
45
+ * The transport is responsible for sending the response back.
46
+ */
47
+ receive(transport: Transport, message: JsonRpcMessage): Promise<void>;
48
+ private handle;
49
+ private scheduleListChangedNotification;
50
+ private broadcast;
51
+ private toRpcError;
52
+ }
53
+ declare function rpcError(code: number, message: string, data?: any): {
54
+ data?: any;
55
+ code: number;
56
+ message: string;
57
+ };
58
+ /**
59
+ * Helper to build a CallToolResult from a string or structured value.
60
+ */
61
+ declare function textResult(text: string, structured?: any): CallToolResult;
62
+ declare function errorResult(text: string): CallToolResult;
63
+
64
+ export { MicroMcpServer as M, type Transport as T, type McpServerOptions as a, errorResult as e, rpcError as r, textResult as t };
@@ -0,0 +1,64 @@
1
+ import { S as ServerInfo, a as ServerCapabilities, J as JsonRpcMessage, T as ToolDefinition, b as ToolHandler, C as CallToolResult } from './types-DksGd5Y7.cjs';
2
+
3
+ type McpServerOptions = {
4
+ info: ServerInfo;
5
+ /** Defaults to { tools: { listChanged: true } } */
6
+ capabilities?: ServerCapabilities;
7
+ /** Free-text instructions surfaced to clients during initialize. */
8
+ instructions?: string;
9
+ };
10
+ type Transport = {
11
+ /** Called by the server when it has a message to deliver to the client. */
12
+ send: (message: JsonRpcMessage) => void;
13
+ /** Called by the server when it's torn down so the transport can clean up. */
14
+ close?: () => void;
15
+ };
16
+ /**
17
+ * MicroMcpServer — protocol-level MCP server, transport-agnostic.
18
+ *
19
+ * Use it like:
20
+ *
21
+ * const server = new MicroMcpServer({ info: { name: "session", version: "0.1" } });
22
+ * server.registerTool({ name: "...", inputSchema: { type: "object" } }, async (args) => ({...}));
23
+ * const transport = new InProcessTransport();
24
+ * server.attach(transport);
25
+ * transport.deliver({ ... }); // client → server frames
26
+ *
27
+ * The same server can serve multiple transports (e.g. an in-process agent
28
+ * AND a relayed external client) by attaching each one.
29
+ */
30
+ declare class MicroMcpServer {
31
+ private tools;
32
+ private transports;
33
+ private notifyListChangedScheduled;
34
+ readonly info: ServerInfo;
35
+ readonly capabilities: ServerCapabilities;
36
+ readonly instructions?: string;
37
+ constructor(options: McpServerOptions);
38
+ attach(transport: Transport): () => void;
39
+ detach(transport: Transport): void;
40
+ registerTool(definition: ToolDefinition, handler: ToolHandler): () => void;
41
+ unregisterTool(name: string): void;
42
+ listTools(): ToolDefinition[];
43
+ /**
44
+ * Receive a JSON-RPC frame from a client (called by the transport).
45
+ * The transport is responsible for sending the response back.
46
+ */
47
+ receive(transport: Transport, message: JsonRpcMessage): Promise<void>;
48
+ private handle;
49
+ private scheduleListChangedNotification;
50
+ private broadcast;
51
+ private toRpcError;
52
+ }
53
+ declare function rpcError(code: number, message: string, data?: any): {
54
+ data?: any;
55
+ code: number;
56
+ message: string;
57
+ };
58
+ /**
59
+ * Helper to build a CallToolResult from a string or structured value.
60
+ */
61
+ declare function textResult(text: string, structured?: any): CallToolResult;
62
+ declare function errorResult(text: string): CallToolResult;
63
+
64
+ export { MicroMcpServer as M, type Transport as T, type McpServerOptions as a, errorResult as e, rpcError as r, textResult as t };
@@ -1,4 +1,5 @@
1
- import { j as Transport, M as MicroMcpServer, b as JsonRpcMessage } from '../server-Bv985us3.cjs';
1
+ import { J as JsonRpcMessage } from '../types-DksGd5Y7.cjs';
2
+ import { T as Transport, M as MicroMcpServer } from '../server-si-VvFxI.cjs';
2
3
 
3
4
  /**
4
5
  * Session-token utilities. The token is a high-entropy secret; possession
@@ -1,4 +1,5 @@
1
- import { j as Transport, M as MicroMcpServer, b as JsonRpcMessage } from '../server-Bv985us3.js';
1
+ import { J as JsonRpcMessage } from '../types-DksGd5Y7.js';
2
+ import { T as Transport, M as MicroMcpServer } from '../server-BJu_AMH3.js';
2
3
 
3
4
  /**
4
5
  * Session-token utilities. The token is a high-entropy secret; possession
package/dist/sharing.cjs CHANGED
@@ -1,5 +1,58 @@
1
1
  'use strict';
2
2
 
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __esm = (fn, res) => function __init() {
6
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
+ };
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+
13
+ // src/presence/registry.ts
14
+ var registry_exports = {};
15
+ __export(registry_exports, {
16
+ emitActivity: () => emitActivity,
17
+ onActivity: () => onActivity,
18
+ readActivityHistory: () => readActivityHistory,
19
+ resetActivityRegistry: () => resetActivityRegistry
20
+ });
21
+ function emitActivity(event) {
22
+ history.push(event);
23
+ if (history.length > HISTORY_CAP) history.splice(0, history.length - HISTORY_CAP);
24
+ for (const l of listeners) l(event);
25
+ }
26
+ function onActivity(listener, filter) {
27
+ const wrapped = filter ? (e) => {
28
+ if (matches(e, filter)) listener(e);
29
+ } : listener;
30
+ listeners.add(wrapped);
31
+ return () => listeners.delete(wrapped);
32
+ }
33
+ function readActivityHistory(filter) {
34
+ if (!filter) return history.slice();
35
+ return history.filter((e) => matches(e, filter));
36
+ }
37
+ function resetActivityRegistry() {
38
+ listeners.clear();
39
+ history.length = 0;
40
+ }
41
+ function matches(e, f) {
42
+ if (f.agentId !== void 0 && e.agentId !== f.agentId) return false;
43
+ if (f.screenId !== void 0 && e.target.screenId !== f.screenId) return false;
44
+ if (f.kind !== void 0 && e.target.kind !== f.kind) return false;
45
+ return true;
46
+ }
47
+ var HISTORY_CAP, listeners, history;
48
+ var init_registry = __esm({
49
+ "src/presence/registry.ts"() {
50
+ HISTORY_CAP = 200;
51
+ listeners = /* @__PURE__ */ new Set();
52
+ history = [];
53
+ }
54
+ });
55
+
3
56
  // src/sharing/token.ts
4
57
  var TOKEN_BYTES = 24;
5
58
  function createSessionDescriptor() {
@@ -151,6 +204,21 @@ function attachSseRelay(server, options) {
151
204
  transport.bindServer(server);
152
205
  server.attach(transport);
153
206
  transport.start();
207
+ Promise.resolve().then(() => (init_registry(), registry_exports)).then(({ onActivity: onActivity2 }) => {
208
+ const off = onActivity2((event) => {
209
+ transport.send({
210
+ jsonrpc: "2.0",
211
+ method: "notifications/agent_activity",
212
+ params: event
213
+ });
214
+ });
215
+ const origClose = transport.close.bind(transport);
216
+ transport.close = () => {
217
+ off();
218
+ origClose();
219
+ };
220
+ }).catch(() => {
221
+ });
154
222
  return transport;
155
223
  }
156
224
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sharing/token.ts","../src/sharing/sse-relay.ts"],"names":[],"mappings":"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","file":"sharing.cjs","sourcesContent":["/**\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/** Build the shareable URL for the current page (preserves path, adds session+token). */\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.searchParams.set(\"session\", descriptor.id);\n u.searchParams.set(\"token\", descriptor.token);\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/** Read session descriptor from current URL, or null if not a shared link. */\nexport function readSessionFromUrl(): SessionDescriptor | null {\n if (typeof window === \"undefined\") return null;\n const params = new URL(window.location.href).searchParams;\n const id = params.get(\"session\");\n const token = params.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 { constantTimeEqual } from \"./token\";\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 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\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 SSE channel. Idempotent. */\n start(): void {\n if (this.connected || typeof window === \"undefined\") return;\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/events?token=${encodeURIComponent(this.opts.token)}`;\n this.setState(\"connecting\");\n const es = new EventSource(url, { withCredentials: false });\n this.es = es;\n\n es.addEventListener(\"open\", () => {\n this.connected = true;\n this.setState(\"open\");\n // Flush queued outbound frames (tool list_changed notifications, etc.)\n const queued = this.sendQueue.splice(0);\n for (const msg of queued) this.postOut(msg);\n });\n\n es.addEventListener(\"mcp\", (ev: MessageEvent) => {\n const raw = ev.data;\n this.handleInbound(raw);\n });\n\n es.addEventListener(\"error\", () => {\n this.setState(\"error\");\n // EventSource auto-reconnects; no need to dispose.\n });\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.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 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 return transport;\n}\n"]}
1
+ {"version":3,"sources":["../src/presence/registry.ts","../src/sharing/token.ts","../src/sharing/sse-relay.ts"],"names":["onActivity"],"mappings":";;;;;;;;;;;;;AAAA,IAAA,gBAAA,GAAA,EAAA;AAAA,QAAA,CAAA,gBAAA,EAAA;AAAA,EAAA,YAAA,EAAA,MAAA,YAAA;AAAA,EAAA,UAAA,EAAA,MAAA,UAAA;AAAA,EAAA,mBAAA,EAAA,MAAA,mBAAA;AAAA,EAAA,qBAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AAkBO,SAAS,aAAa,KAAA,EAAiC;AAC5D,EAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAClB,EAAA,IAAI,OAAA,CAAQ,SAAS,WAAA,EAAa,OAAA,CAAQ,OAAO,CAAA,EAAG,OAAA,CAAQ,SAAS,WAAW,CAAA;AAChF,EAAA,KAAA,MAAW,CAAA,IAAK,SAAA,EAAW,CAAA,CAAE,KAAK,CAAA;AACpC;AAOO,SAAS,UAAA,CAAW,UAAiC,MAAA,EAAqC;AAC/F,EAAA,MAAM,OAAA,GAAiC,MAAA,GACnC,CAAC,CAAA,KAAM;AAAE,IAAA,IAAI,OAAA,CAAQ,CAAA,EAAG,MAAM,CAAA,WAAY,CAAC,CAAA;AAAA,EAAG,CAAA,GAC9C,QAAA;AACJ,EAAA,SAAA,CAAU,IAAI,OAAO,CAAA;AACrB,EAAA,OAAO,MAAM,SAAA,CAAU,MAAA,CAAO,OAAO,CAAA;AACvC;AAGO,SAAS,oBAAoB,MAAA,EAA+C;AACjF,EAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,OAAA,CAAQ,KAAA,EAAM;AAClC,EAAA,OAAO,QAAQ,MAAA,CAAO,CAAC,MAAM,OAAA,CAAQ,CAAA,EAAG,MAAM,CAAC,CAAA;AACjD;AAGO,SAAS,qBAAA,GAA8B;AAC5C,EAAA,SAAA,CAAU,KAAA,EAAM;AAChB,EAAA,OAAA,CAAQ,MAAA,GAAS,CAAA;AACnB;AAEA,SAAS,OAAA,CAAQ,GAAuB,CAAA,EAA4B;AAClE,EAAA,IAAI,EAAE,OAAA,KAAY,MAAA,IAAa,EAAE,OAAA,KAAY,CAAA,CAAE,SAAS,OAAO,KAAA;AAC/D,EAAA,IAAI,CAAA,CAAE,aAAa,MAAA,IAAa,CAAA,CAAE,OAAO,QAAA,KAAa,CAAA,CAAE,UAAU,OAAO,KAAA;AACzE,EAAA,IAAI,CAAA,CAAE,SAAS,MAAA,IAAa,CAAA,CAAE,OAAO,IAAA,KAAS,CAAA,CAAE,MAAM,OAAO,KAAA;AAC7D,EAAA,OAAO,IAAA;AACT;AAtDA,IAYM,aAEA,SAAA,EACA,OAAA;AAfN,IAAA,aAAA,GAAA,KAAA,CAAA;AAAA,EAAA,0BAAA,GAAA;AAYA,IAAM,WAAA,GAAc,GAAA;AAEpB,IAAM,SAAA,uBAAgB,GAAA,EAA2B;AACjD,IAAM,UAAgC,EAAC;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACPvC,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;AAGO,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,YAAA,CAAa,GAAA,CAAI,SAAA,EAAW,UAAA,CAAW,EAAE,CAAA;AAC3C,EAAA,CAAA,CAAE,YAAA,CAAa,GAAA,CAAI,OAAA,EAAS,UAAA,CAAW,KAAK,CAAA;AAC5C,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;AAGO,SAAS,kBAAA,GAA+C;AAC7D,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,IAAA;AAC1C,EAAA,MAAM,SAAS,IAAI,GAAA,CAAI,MAAA,CAAO,QAAA,CAAS,IAAI,CAAA,CAAE,YAAA;AAC7C,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,GAAA,CAAI,SAAS,CAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA;AAChC,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;;;ACxDO,IAAM,oBAAN,MAA6C;AAAA,EAUlD,YAAY,OAAA,EAA0B;AANtC,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;AAI1B,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,IAAA,CAAK,SAAA,IAAa,OAAO,MAAA,KAAW,WAAA,EAAa;AACrD,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,IAAA,CAAK,SAAS,YAAY,CAAA;AAC1B,IAAA,MAAM,KAAK,IAAI,WAAA,CAAY,KAAK,EAAE,eAAA,EAAiB,OAAO,CAAA;AAC1D,IAAA,IAAA,CAAK,EAAA,GAAK,EAAA;AAEV,IAAA,EAAA,CAAG,gBAAA,CAAiB,QAAQ,MAAM;AAChC,MAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AACjB,MAAA,IAAA,CAAK,SAAS,MAAM,CAAA;AAEpB,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,CAAC,CAAA;AACtC,MAAA,KAAA,MAAW,GAAA,IAAO,MAAA,EAAQ,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAAA,IAC5C,CAAC,CAAA;AAED,IAAA,EAAA,CAAG,gBAAA,CAAiB,KAAA,EAAO,CAAC,EAAA,KAAqB;AAC/C,MAAA,MAAM,MAAM,EAAA,CAAG,IAAA;AACf,MAAA,IAAA,CAAK,cAAc,GAAG,CAAA;AAAA,IACxB,CAAC,CAAA;AAED,IAAA,EAAA,CAAG,gBAAA,CAAiB,SAAS,MAAM;AACjC,MAAA,IAAA,CAAK,SAAS,OAAO,CAAA;AAAA,IAEvB,CAAC,CAAA;AAAA,EACH;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,IAAI,KAAA,EAAM;AACf,IAAA,IAAA,CAAK,EAAA,GAAK,MAAA;AACV,IAAA,IAAA,CAAK,SAAA,GAAY,KAAA;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;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,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,EAAAA,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":["import type { ActivityFilter, AgentActivityEvent, AgentActivityListener } from \"./types\";\n\n/**\n * In-process registry of agent activity events. Bridges call `emitActivity`\n * after a tool runs; React hooks + the SSE relay subscribe via\n * `onActivity()`.\n *\n * Holds a short scrollback of recent events (default 200) so newly-mounted\n * subscribers can render the recent past — useful for activity-log UIs\n * that rejoin a session mid-stream.\n */\n\nconst HISTORY_CAP = 200;\n\nconst listeners = new Set<AgentActivityListener>();\nconst history: AgentActivityEvent[] = [];\n\n/** Emit an activity event. All current listeners receive it synchronously. */\nexport function emitActivity(event: AgentActivityEvent): void {\n history.push(event);\n if (history.length > HISTORY_CAP) history.splice(0, history.length - HISTORY_CAP);\n for (const l of listeners) l(event);\n}\n\n/**\n * Subscribe to all events (or a filtered subset). Returns an unsubscribe\n * function. Filter checks all provided keys with strict equality; omit a\n * key to ignore it.\n */\nexport function onActivity(listener: AgentActivityListener, filter?: ActivityFilter): () => void {\n const wrapped: AgentActivityListener = filter\n ? (e) => { if (matches(e, filter)) listener(e); }\n : listener;\n listeners.add(wrapped);\n return () => listeners.delete(wrapped);\n}\n\n/** Read the recent history (newest last). Optional filter. */\nexport function readActivityHistory(filter?: ActivityFilter): AgentActivityEvent[] {\n if (!filter) return history.slice();\n return history.filter((e) => matches(e, filter));\n}\n\n/** Wipe history + clear listeners. Test/teardown helper. */\nexport function resetActivityRegistry(): void {\n listeners.clear();\n history.length = 0;\n}\n\nfunction matches(e: AgentActivityEvent, f: ActivityFilter): boolean {\n if (f.agentId !== undefined && e.agentId !== f.agentId) return false;\n if (f.screenId !== undefined && e.target.screenId !== f.screenId) return false;\n if (f.kind !== undefined && e.target.kind !== f.kind) return false;\n return true;\n}\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/** Build the shareable URL for the current page (preserves path, adds session+token). */\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.searchParams.set(\"session\", descriptor.id);\n u.searchParams.set(\"token\", descriptor.token);\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/** Read session descriptor from current URL, or null if not a shared link. */\nexport function readSessionFromUrl(): SessionDescriptor | null {\n if (typeof window === \"undefined\") return null;\n const params = new URL(window.location.href).searchParams;\n const id = params.get(\"session\");\n const token = params.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 { constantTimeEqual } from \"./token\";\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 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\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 SSE channel. Idempotent. */\n start(): void {\n if (this.connected || typeof window === \"undefined\") return;\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/events?token=${encodeURIComponent(this.opts.token)}`;\n this.setState(\"connecting\");\n const es = new EventSource(url, { withCredentials: false });\n this.es = es;\n\n es.addEventListener(\"open\", () => {\n this.connected = true;\n this.setState(\"open\");\n // Flush queued outbound frames (tool list_changed notifications, etc.)\n const queued = this.sendQueue.splice(0);\n for (const msg of queued) this.postOut(msg);\n });\n\n es.addEventListener(\"mcp\", (ev: MessageEvent) => {\n const raw = ev.data;\n this.handleInbound(raw);\n });\n\n es.addEventListener(\"error\", () => {\n this.setState(\"error\");\n // EventSource auto-reconnects; no need to dispose.\n });\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.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 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,3 +1,3 @@
1
- export { SseRelayTransport, attachSseRelay, buildShareConfig, buildShareUrl, constantTimeEqual, createSessionDescriptor, describeSession, readSessionFromUrl } from './chunk-FLEOQUKF.js';
1
+ export { SseRelayTransport, attachSseRelay, buildShareConfig, buildShareUrl, constantTimeEqual, createSessionDescriptor, describeSession, readSessionFromUrl } from './chunk-JMYPUAFH.js';
2
2
  //# sourceMappingURL=sharing.js.map
3
3
  //# sourceMappingURL=sharing.js.map
package/dist/styles.css CHANGED
@@ -328,4 +328,61 @@
328
328
  color: inherit;
329
329
  font-size: 12px;
330
330
  }
331
+ .agent-focused-element {
332
+ --agent-color: #a855f7;
333
+ position: relative;
334
+ outline: 2px solid var(--agent-color);
335
+ outline-offset: 2px;
336
+ border-radius: 4px;
337
+ animation: agent-focus-pulse 1500ms ease-out forwards;
338
+ }
339
+ @keyframes agent-focus-pulse {
340
+ 0% {
341
+ box-shadow: 0 0 0 0 var(--agent-color);
342
+ }
343
+ 40% {
344
+ box-shadow: 0 0 0 6px rgba(168, 85, 247, 0.18);
345
+ }
346
+ 100% {
347
+ box-shadow: 0 0 0 0 rgba(168, 85, 247, 0);
348
+ outline-color: transparent;
349
+ }
350
+ }
351
+ @media (prefers-reduced-motion: reduce) {
352
+ .agent-focused-element {
353
+ animation: none;
354
+ }
355
+ }
356
+ .agent-active-badge {
357
+ display: inline-flex;
358
+ align-items: center;
359
+ gap: 4px;
360
+ background: var(--agent-color, #a855f7);
361
+ color: white;
362
+ font-family:
363
+ ui-sans-serif,
364
+ system-ui,
365
+ sans-serif;
366
+ font-size: 11px;
367
+ font-weight: 500;
368
+ padding: 2px 6px;
369
+ border-radius: 999px;
370
+ vertical-align: middle;
371
+ }
372
+ .agent-active-badge::before {
373
+ content: "";
374
+ width: 6px;
375
+ height: 6px;
376
+ border-radius: 50%;
377
+ background: white;
378
+ animation: agent-active-blink 1.4s ease-in-out infinite;
379
+ }
380
+ @keyframes agent-active-blink {
381
+ 0%, 100% {
382
+ opacity: 0.4;
383
+ }
384
+ 50% {
385
+ opacity: 1;
386
+ }
387
+ }
331
388
  /*# sourceMappingURL=styles.css.map */
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/styles.css"],"sourcesContent":["/* @particle-academy/agent-integrations — minimal styles, host app provides tailwind/theme. */\n\n.fai-panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: white;\n color: #18181b;\n border-radius: 12px;\n border: 1px solid #e4e4e7;\n font-family: ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n overflow: hidden;\n}\n@media (prefers-color-scheme: dark) {\n .fai-panel { background: #18181b; color: #fafafa; border-color: #3f3f46; }\n}\n.fai-panel__header {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 12px; border-bottom: 1px solid #e4e4e7;\n}\n@media (prefers-color-scheme: dark) { .fai-panel__header { border-color: #3f3f46; } }\n.fai-panel__avatar {\n width: 32px; height: 32px; border-radius: 50%;\n display: inline-flex; align-items: center; justify-content: center;\n color: white; font-weight: 600; font-size: 14px;\n}\n.fai-panel__title { display: flex; flex-direction: column; line-height: 1.1; flex: 1; }\n.fai-panel__subtitle { font-size: 11px; opacity: 0.6; }\n.fai-panel__actions { display: flex; gap: 6px; }\n.fai-panel__stream {\n flex: 1; overflow: auto; padding: 8px 12px;\n display: flex; flex-direction: column; gap: 6px;\n}\n.fai-panel__empty { font-size: 12px; opacity: 0.5; margin: auto; }\n.fai-row {\n font-size: 12px;\n border-radius: 6px;\n padding: 6px 8px;\n background: rgba(244, 244, 245, 0.6);\n}\n@media (prefers-color-scheme: dark) { .fai-row { background: rgba(63, 63, 70, 0.4); } }\n.fai-row--tool { border-left: 3px solid #a855f7; }\n.fai-row--message { border-left: 3px solid #3b82f6; }\n.fai-row--info { border-left: 3px solid #71717a; }\n.fai-row--error { border-left: 3px solid #ef4444; background: rgba(254, 226, 226, 0.4); }\n.fai-row__meta { display: flex; justify-content: space-between; opacity: 0.6; font-size: 10px; }\n.fai-row__source { font-family: ui-monospace, monospace; }\n.fai-row__text { white-space: pre-wrap; }\n.fai-row__detail summary { cursor: pointer; opacity: 0.7; font-size: 11px; margin-top: 4px; }\n.fai-row__detail pre {\n font-size: 11px; margin: 4px 0 0; padding: 6px;\n background: rgba(0,0,0,0.06); border-radius: 4px; overflow: auto;\n max-height: 200px;\n}\n.fai-panel__composer {\n display: flex; gap: 6px; padding: 8px;\n border-top: 1px solid #e4e4e7;\n}\n@media (prefers-color-scheme: dark) { .fai-panel__composer { border-color: #3f3f46; } }\n.fai-panel__input {\n flex: 1;\n resize: none;\n border-radius: 6px;\n border: 1px solid #d4d4d8;\n padding: 6px 8px;\n font: inherit;\n background: transparent;\n color: inherit;\n}\n.fai-panel__input:focus { outline: 2px solid #a855f7; outline-offset: -1px; }\n.fai-panel__send {\n align-self: stretch;\n padding: 0 14px;\n border: 0; border-radius: 6px;\n background: #a855f7; color: white;\n cursor: pointer; font-weight: 500;\n}\n.fai-panel__send:disabled { opacity: 0.5; cursor: default; }\n\n/* Cursor */\n.fai-cursor {\n transition: left 500ms cubic-bezier(0.22, 1, 0.36, 1),\n top 500ms cubic-bezier(0.22, 1, 0.36, 1);\n}\n@media (prefers-reduced-motion: reduce) { .fai-cursor { transition: none; } }\n.fai-cursor__tag {\n position: absolute; left: 18px; top: 14px;\n color: white;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 11px; font-family: system-ui, sans-serif;\n white-space: nowrap;\n}\n.fai-cursor__status { font-style: normal; opacity: 0.85; }\n\n/* Highlight pulse */\n@keyframes fai-pulse {\n 0% { opacity: 0; transform: scale(0.96); }\n 20% { opacity: 1; transform: scale(1.03); }\n 100% { opacity: 0; transform: scale(1); }\n}\n\n/* ShareControls */\n.fai-share {\n border: 1px solid #e4e4e7; border-radius: 12px; padding: 12px;\n background: white; color: #18181b;\n font-family: ui-sans-serif, system-ui, sans-serif; font-size: 13px;\n}\n@media (prefers-color-scheme: dark) { .fai-share { background: #18181b; color: #fafafa; border-color: #3f3f46; } }\n.fai-share--idle { display: flex; flex-direction: column; gap: 6px; }\n.fai-share__start { align-self: flex-start; padding: 8px 14px; border: 0; border-radius: 6px; background: #a855f7; color: white; font-weight: 500; cursor: pointer; }\n.fai-share__hint { margin: 0; opacity: 0.7; font-size: 12px; }\n.fai-share__header { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 8px; }\n.fai-share__id { display: block; opacity: 0.7; font-size: 11px; margin-top: 2px; }\n.fai-share__id code { font-family: ui-monospace, monospace; }\n.fai-share__header-actions { display: flex; gap: 8px; align-items: center; }\n.fai-share__status { font-size: 11px; padding: 2px 8px; border-radius: 999px; background: rgba(34, 197, 94, 0.15); color: #16a34a; }\n.fai-share__stop { border: 1px solid #d4d4d8; background: transparent; border-radius: 6px; padding: 4px 10px; cursor: pointer; font-size: 12px; color: inherit; }\n.fai-share__tabs { display: flex; gap: 4px; margin-bottom: 8px; }\n.fai-share__tab { border: 0; background: transparent; cursor: pointer; padding: 4px 10px; border-radius: 4px; color: inherit; font-size: 12px; }\n.fai-share__tab.is-active { background: rgba(168, 85, 247, 0.12); color: #a855f7; }\n.fai-share__panel-label { font-size: 11px; opacity: 0.7; margin-bottom: 4px; }\n.fai-share__copy { display: flex; gap: 6px; align-items: stretch; }\n.fai-share__pre { flex: 1; margin: 0; padding: 8px 10px; background: rgba(0,0,0,0.05); border-radius: 6px; font-family: ui-monospace, monospace; font-size: 11px; white-space: nowrap; overflow: auto; }\n.fai-share__pre.is-multi { white-space: pre; max-height: 240px; }\n.fai-share__copy-btn { border: 1px solid #d4d4d8; background: transparent; cursor: pointer; border-radius: 6px; padding: 0 12px; color: inherit; font-size: 12px; }\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/styles.css"],"sourcesContent":["/* @particle-academy/agent-integrations — minimal styles, host app provides tailwind/theme. */\n\n.fai-panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: white;\n color: #18181b;\n border-radius: 12px;\n border: 1px solid #e4e4e7;\n font-family: ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n overflow: hidden;\n}\n@media (prefers-color-scheme: dark) {\n .fai-panel { background: #18181b; color: #fafafa; border-color: #3f3f46; }\n}\n.fai-panel__header {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 12px; border-bottom: 1px solid #e4e4e7;\n}\n@media (prefers-color-scheme: dark) { .fai-panel__header { border-color: #3f3f46; } }\n.fai-panel__avatar {\n width: 32px; height: 32px; border-radius: 50%;\n display: inline-flex; align-items: center; justify-content: center;\n color: white; font-weight: 600; font-size: 14px;\n}\n.fai-panel__title { display: flex; flex-direction: column; line-height: 1.1; flex: 1; }\n.fai-panel__subtitle { font-size: 11px; opacity: 0.6; }\n.fai-panel__actions { display: flex; gap: 6px; }\n.fai-panel__stream {\n flex: 1; overflow: auto; padding: 8px 12px;\n display: flex; flex-direction: column; gap: 6px;\n}\n.fai-panel__empty { font-size: 12px; opacity: 0.5; margin: auto; }\n.fai-row {\n font-size: 12px;\n border-radius: 6px;\n padding: 6px 8px;\n background: rgba(244, 244, 245, 0.6);\n}\n@media (prefers-color-scheme: dark) { .fai-row { background: rgba(63, 63, 70, 0.4); } }\n.fai-row--tool { border-left: 3px solid #a855f7; }\n.fai-row--message { border-left: 3px solid #3b82f6; }\n.fai-row--info { border-left: 3px solid #71717a; }\n.fai-row--error { border-left: 3px solid #ef4444; background: rgba(254, 226, 226, 0.4); }\n.fai-row__meta { display: flex; justify-content: space-between; opacity: 0.6; font-size: 10px; }\n.fai-row__source { font-family: ui-monospace, monospace; }\n.fai-row__text { white-space: pre-wrap; }\n.fai-row__detail summary { cursor: pointer; opacity: 0.7; font-size: 11px; margin-top: 4px; }\n.fai-row__detail pre {\n font-size: 11px; margin: 4px 0 0; padding: 6px;\n background: rgba(0,0,0,0.06); border-radius: 4px; overflow: auto;\n max-height: 200px;\n}\n.fai-panel__composer {\n display: flex; gap: 6px; padding: 8px;\n border-top: 1px solid #e4e4e7;\n}\n@media (prefers-color-scheme: dark) { .fai-panel__composer { border-color: #3f3f46; } }\n.fai-panel__input {\n flex: 1;\n resize: none;\n border-radius: 6px;\n border: 1px solid #d4d4d8;\n padding: 6px 8px;\n font: inherit;\n background: transparent;\n color: inherit;\n}\n.fai-panel__input:focus { outline: 2px solid #a855f7; outline-offset: -1px; }\n.fai-panel__send {\n align-self: stretch;\n padding: 0 14px;\n border: 0; border-radius: 6px;\n background: #a855f7; color: white;\n cursor: pointer; font-weight: 500;\n}\n.fai-panel__send:disabled { opacity: 0.5; cursor: default; }\n\n/* Cursor */\n.fai-cursor {\n transition: left 500ms cubic-bezier(0.22, 1, 0.36, 1),\n top 500ms cubic-bezier(0.22, 1, 0.36, 1);\n}\n@media (prefers-reduced-motion: reduce) { .fai-cursor { transition: none; } }\n.fai-cursor__tag {\n position: absolute; left: 18px; top: 14px;\n color: white;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 11px; font-family: system-ui, sans-serif;\n white-space: nowrap;\n}\n.fai-cursor__status { font-style: normal; opacity: 0.85; }\n\n/* Highlight pulse */\n@keyframes fai-pulse {\n 0% { opacity: 0; transform: scale(0.96); }\n 20% { opacity: 1; transform: scale(1.03); }\n 100% { opacity: 0; transform: scale(1); }\n}\n\n/* ShareControls */\n.fai-share {\n border: 1px solid #e4e4e7; border-radius: 12px; padding: 12px;\n background: white; color: #18181b;\n font-family: ui-sans-serif, system-ui, sans-serif; font-size: 13px;\n}\n@media (prefers-color-scheme: dark) { .fai-share { background: #18181b; color: #fafafa; border-color: #3f3f46; } }\n.fai-share--idle { display: flex; flex-direction: column; gap: 6px; }\n.fai-share__start { align-self: flex-start; padding: 8px 14px; border: 0; border-radius: 6px; background: #a855f7; color: white; font-weight: 500; cursor: pointer; }\n.fai-share__hint { margin: 0; opacity: 0.7; font-size: 12px; }\n.fai-share__header { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 8px; }\n.fai-share__id { display: block; opacity: 0.7; font-size: 11px; margin-top: 2px; }\n.fai-share__id code { font-family: ui-monospace, monospace; }\n.fai-share__header-actions { display: flex; gap: 8px; align-items: center; }\n.fai-share__status { font-size: 11px; padding: 2px 8px; border-radius: 999px; background: rgba(34, 197, 94, 0.15); color: #16a34a; }\n.fai-share__stop { border: 1px solid #d4d4d8; background: transparent; border-radius: 6px; padding: 4px 10px; cursor: pointer; font-size: 12px; color: inherit; }\n.fai-share__tabs { display: flex; gap: 4px; margin-bottom: 8px; }\n.fai-share__tab { border: 0; background: transparent; cursor: pointer; padding: 4px 10px; border-radius: 4px; color: inherit; font-size: 12px; }\n.fai-share__tab.is-active { background: rgba(168, 85, 247, 0.12); color: #a855f7; }\n.fai-share__panel-label { font-size: 11px; opacity: 0.7; margin-bottom: 4px; }\n.fai-share__copy { display: flex; gap: 6px; align-items: stretch; }\n.fai-share__pre { flex: 1; margin: 0; padding: 8px 10px; background: rgba(0,0,0,0.05); border-radius: 6px; font-family: ui-monospace, monospace; font-size: 11px; white-space: nowrap; overflow: auto; }\n.fai-share__pre.is-multi { white-space: pre; max-height: 240px; }\n.fai-share__copy-btn { border: 1px solid #d4d4d8; background: transparent; cursor: pointer; border-radius: 6px; padding: 0 12px; color: inherit; font-size: 12px; }\n\n/* === Cross-package agent presence === */\n/*\n * Apply `.agent-focused-element` to any DOM node that's currently being\n * touched by an agent. The CSS variables let hosts override the agent's\n * accent without touching the rule. Bridges typically apply this class\n * via a brief side-effect when their tools fire.\n */\n.agent-focused-element {\n --agent-color: #a855f7;\n position: relative;\n outline: 2px solid var(--agent-color);\n outline-offset: 2px;\n border-radius: 4px;\n animation: agent-focus-pulse 1500ms ease-out forwards;\n}\n@keyframes agent-focus-pulse {\n 0% { box-shadow: 0 0 0 0 var(--agent-color); }\n 40% { box-shadow: 0 0 0 6px rgba(168, 85, 247, 0.18); }\n 100% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0); outline-color: transparent; }\n}\n@media (prefers-reduced-motion: reduce) {\n .agent-focused-element { animation: none; }\n}\n\n/* Small badge hosts can drop next to an element to label \"Agent active\". */\n.agent-active-badge {\n display: inline-flex; align-items: center; gap: 4px;\n background: var(--agent-color, #a855f7);\n color: white;\n font-family: ui-sans-serif, system-ui, sans-serif;\n font-size: 11px; font-weight: 500;\n padding: 2px 6px; border-radius: 999px;\n vertical-align: middle;\n}\n.agent-active-badge::before {\n content: \"\";\n width: 6px; height: 6px;\n border-radius: 50%;\n background: white;\n animation: agent-active-blink 1.4s ease-in-out infinite;\n}\n@keyframes agent-active-blink {\n 0%, 100% { opacity: 0.4; }\n 50% { opacity: 1; }\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,4 @@
1
- import { M as MicroMcpServer } from './server-Bv985us3.cjs';
1
+ import { M as MicroMcpServer } from './server-si-VvFxI.cjs';
2
2
 
3
3
  /**
4
4
  * Bridge — registers a cohesive set of MCP tools/resources for a single
@@ -1,4 +1,4 @@
1
- import { M as MicroMcpServer } from './server-Bv985us3.js';
1
+ import { M as MicroMcpServer } from './server-BJu_AMH3.js';
2
2
 
3
3
  /**
4
4
  * Bridge — registers a cohesive set of MCP tools/resources for a single