@particle-academy/agent-integrations 0.28.1 → 0.29.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.
Files changed (161) hide show
  1. package/README.md +9 -0
  2. package/dist/bridges/artboard.d.cts +3 -3
  3. package/dist/bridges/artboard.d.ts +3 -3
  4. package/dist/bridges/catalog.d.cts +3 -3
  5. package/dist/bridges/catalog.d.ts +3 -3
  6. package/dist/bridges/charts.d.cts +3 -3
  7. package/dist/bridges/charts.d.ts +3 -3
  8. package/dist/bridges/cms.d.cts +3 -3
  9. package/dist/bridges/cms.d.ts +3 -3
  10. package/dist/bridges/code.d.cts +3 -3
  11. package/dist/bridges/code.d.ts +3 -3
  12. package/dist/bridges/doc.d.cts +3 -3
  13. package/dist/bridges/doc.d.ts +3 -3
  14. package/dist/bridges/features.d.cts +3 -3
  15. package/dist/bridges/features.d.ts +3 -3
  16. package/dist/bridges/files.d.cts +3 -3
  17. package/dist/bridges/files.d.ts +3 -3
  18. package/dist/bridges/flow.d.cts +3 -3
  19. package/dist/bridges/flow.d.ts +3 -3
  20. package/dist/bridges/forms.d.cts +3 -3
  21. package/dist/bridges/forms.d.ts +3 -3
  22. package/dist/bridges/map.d.cts +3 -3
  23. package/dist/bridges/map.d.ts +3 -3
  24. package/dist/bridges/scene.d.cts +3 -3
  25. package/dist/bridges/scene.d.ts +3 -3
  26. package/dist/bridges/screens.d.cts +3 -3
  27. package/dist/bridges/screens.d.ts +3 -3
  28. package/dist/bridges/sheets.d.cts +3 -3
  29. package/dist/bridges/sheets.d.ts +3 -3
  30. package/dist/bridges/slides.d.cts +3 -3
  31. package/dist/bridges/slides.d.ts +3 -3
  32. package/dist/bridges/terminal.d.cts +3 -3
  33. package/dist/bridges/terminal.d.ts +3 -3
  34. package/dist/bridges/tui.d.cts +45 -0
  35. package/dist/bridges/tui.d.ts +45 -0
  36. package/dist/bridges/whiteboard.d.cts +3 -3
  37. package/dist/bridges/whiteboard.d.ts +3 -3
  38. package/dist/bridges-artboard.cjs.map +1 -1
  39. package/dist/bridges-artboard.js +2 -2
  40. package/dist/bridges-catalog.cjs.map +1 -1
  41. package/dist/bridges-catalog.js +3 -3
  42. package/dist/bridges-charts.cjs.map +1 -1
  43. package/dist/bridges-charts.js +3 -3
  44. package/dist/bridges-cms.cjs.map +1 -1
  45. package/dist/bridges-cms.js +4 -4
  46. package/dist/bridges-code.cjs.map +1 -1
  47. package/dist/bridges-code.js +3 -3
  48. package/dist/bridges-doc.cjs.map +1 -1
  49. package/dist/bridges-doc.js +3 -3
  50. package/dist/bridges-features.cjs.map +1 -1
  51. package/dist/bridges-features.js +3 -3
  52. package/dist/bridges-files.cjs.map +1 -1
  53. package/dist/bridges-files.js +3 -3
  54. package/dist/bridges-flow.cjs.map +1 -1
  55. package/dist/bridges-flow.js +2 -2
  56. package/dist/bridges-forms.cjs.map +1 -1
  57. package/dist/bridges-forms.js +3 -3
  58. package/dist/bridges-map.cjs.map +1 -1
  59. package/dist/bridges-map.js +3 -3
  60. package/dist/bridges-scene.cjs.map +1 -1
  61. package/dist/bridges-scene.js +3 -3
  62. package/dist/bridges-screens.cjs.map +1 -1
  63. package/dist/bridges-screens.js +3 -3
  64. package/dist/bridges-sheets.cjs.map +1 -1
  65. package/dist/bridges-sheets.js +3 -3
  66. package/dist/bridges-slides.cjs.map +1 -1
  67. package/dist/bridges-slides.js +3 -3
  68. package/dist/bridges-terminal.cjs.map +1 -1
  69. package/dist/bridges-terminal.js +3 -3
  70. package/dist/bridges-tui.cjs +114 -0
  71. package/dist/bridges-tui.cjs.map +1 -0
  72. package/dist/bridges-tui.js +7 -0
  73. package/dist/bridges-tui.js.map +1 -0
  74. package/dist/bridges-whiteboard.cjs.map +1 -1
  75. package/dist/bridges-whiteboard.js +3 -3
  76. package/dist/{chunk-AROVENCE.js → chunk-2Y7Y5PTR.js} +4 -4
  77. package/dist/{chunk-AROVENCE.js.map → chunk-2Y7Y5PTR.js.map} +1 -1
  78. package/dist/{chunk-QDD4WHIV.js → chunk-3PKHJ4IV.js} +4 -4
  79. package/dist/{chunk-QDD4WHIV.js.map → chunk-3PKHJ4IV.js.map} +1 -1
  80. package/dist/{chunk-A57CRGEK.js → chunk-7VBB2FJB.js} +3 -3
  81. package/dist/{chunk-A57CRGEK.js.map → chunk-7VBB2FJB.js.map} +1 -1
  82. package/dist/{chunk-FF5F526J.js → chunk-AF454WRD.js} +4 -4
  83. package/dist/{chunk-FF5F526J.js.map → chunk-AF454WRD.js.map} +1 -1
  84. package/dist/{chunk-66WOHZZJ.js → chunk-BE2XS577.js} +4 -4
  85. package/dist/{chunk-66WOHZZJ.js.map → chunk-BE2XS577.js.map} +1 -1
  86. package/dist/{chunk-GHY3PBPN.js → chunk-BT7HM5I6.js} +3 -3
  87. package/dist/{chunk-GHY3PBPN.js.map → chunk-BT7HM5I6.js.map} +1 -1
  88. package/dist/{chunk-KJ5AOOV7.js → chunk-CT3LRNH7.js} +3 -3
  89. package/dist/{chunk-KJ5AOOV7.js.map → chunk-CT3LRNH7.js.map} +1 -1
  90. package/dist/{chunk-4KAIV6OD.js → chunk-DF3PLL2E.js} +10 -5
  91. package/dist/chunk-DF3PLL2E.js.map +1 -0
  92. package/dist/{chunk-AAD3Z5E7.js → chunk-HFLHLS2N.js} +4 -4
  93. package/dist/{chunk-AAD3Z5E7.js.map → chunk-HFLHLS2N.js.map} +1 -1
  94. package/dist/{chunk-HWVVS6HE.js → chunk-KKGC4ERF.js} +4 -4
  95. package/dist/{chunk-HWVVS6HE.js.map → chunk-KKGC4ERF.js.map} +1 -1
  96. package/dist/{chunk-NN3ELTVO.js → chunk-KYMEDV6E.js} +4 -4
  97. package/dist/{chunk-NN3ELTVO.js.map → chunk-KYMEDV6E.js.map} +1 -1
  98. package/dist/{chunk-YGD2VTUM.js → chunk-LZJI7EKQ.js} +4 -4
  99. package/dist/{chunk-YGD2VTUM.js.map → chunk-LZJI7EKQ.js.map} +1 -1
  100. package/dist/chunk-MFMBR6LN.js +100 -0
  101. package/dist/chunk-MFMBR6LN.js.map +1 -0
  102. package/dist/{chunk-VFKO2VUR.js → chunk-NSPL5TVF.js} +4 -4
  103. package/dist/{chunk-VFKO2VUR.js.map → chunk-NSPL5TVF.js.map} +1 -1
  104. package/dist/{chunk-AAMQOXZC.js → chunk-OFCR6JY3.js} +4 -4
  105. package/dist/{chunk-AAMQOXZC.js.map → chunk-OFCR6JY3.js.map} +1 -1
  106. package/dist/{chunk-ZX6UQURN.js → chunk-OHUDEA6R.js} +4 -4
  107. package/dist/{chunk-ZX6UQURN.js.map → chunk-OHUDEA6R.js.map} +1 -1
  108. package/dist/chunk-PMI4C5S4.js +44 -0
  109. package/dist/chunk-PMI4C5S4.js.map +1 -0
  110. package/dist/{chunk-PCW2EK5G.js → chunk-TNU6AWUO.js} +4 -4
  111. package/dist/{chunk-PCW2EK5G.js.map → chunk-TNU6AWUO.js.map} +1 -1
  112. package/dist/{chunk-QRDVJW6Q.js → chunk-UTUVN6HQ.js} +4 -4
  113. package/dist/{chunk-QRDVJW6Q.js.map → chunk-UTUVN6HQ.js.map} +1 -1
  114. package/dist/{chunk-XMMCSQ4I.js → chunk-VMCG3PJD.js} +4 -4
  115. package/dist/{chunk-XMMCSQ4I.js.map → chunk-VMCG3PJD.js.map} +1 -1
  116. package/dist/components-shared-whiteboard.cjs +8 -3
  117. package/dist/components-shared-whiteboard.cjs.map +1 -1
  118. package/dist/components-shared-whiteboard.js +3 -3
  119. package/dist/human-plus/file-store.d.cts +17 -0
  120. package/dist/human-plus/file-store.d.ts +17 -0
  121. package/dist/human-plus/index.d.cts +61 -0
  122. package/dist/human-plus/index.d.ts +61 -0
  123. package/dist/human-plus-node.cjs +121 -0
  124. package/dist/human-plus-node.cjs.map +1 -0
  125. package/dist/human-plus-node.js +76 -0
  126. package/dist/human-plus-node.js.map +1 -0
  127. package/dist/human-plus.cjs +46 -0
  128. package/dist/human-plus.cjs.map +1 -0
  129. package/dist/human-plus.js +3 -0
  130. package/dist/human-plus.js.map +1 -0
  131. package/dist/index.cjs +212 -43
  132. package/dist/index.cjs.map +1 -1
  133. package/dist/index.d.cts +9 -7
  134. package/dist/index.d.ts +9 -7
  135. package/dist/index.js +58 -29
  136. package/dist/index.js.map +1 -1
  137. package/dist/mcp/index.d.cts +5 -5
  138. package/dist/mcp/index.d.ts +5 -5
  139. package/dist/mcp.cjs +8 -3
  140. package/dist/mcp.cjs.map +1 -1
  141. package/dist/mcp.js +1 -1
  142. package/dist/presence/index.d.cts +1 -1
  143. package/dist/presence/index.d.ts +1 -1
  144. package/dist/{server-FFZpYPyM.d.ts → server-CDX643Kz.d.ts} +4 -2
  145. package/dist/{server-Dr3j48CU.d.cts → server-DDD3IZ56.d.cts} +4 -2
  146. package/dist/sharing/index.d.cts +3 -3
  147. package/dist/sharing/index.d.ts +3 -3
  148. package/dist/sheets-adapter.d.cts +3 -3
  149. package/dist/sheets-adapter.d.ts +3 -3
  150. package/dist/{tool-host-C_Vh17J_.d.ts → tool-host-CWTOJEm2.d.ts} +1 -1
  151. package/dist/{tool-host-IDecPrF1.d.cts → tool-host-EuYHYSSH.d.cts} +1 -1
  152. package/dist/{types-CBoQhR8L.d.ts → types-BKD6uf86.d.ts} +1 -1
  153. package/dist/{types-BDI_g5UG.d.ts → types-C58ZXs4K.d.cts} +6 -2
  154. package/dist/{types-BDI_g5UG.d.cts → types-C58ZXs4K.d.ts} +6 -2
  155. package/dist/{types-B0rmWyoR.d.cts → types-NFGP769G.d.cts} +1 -1
  156. package/dist/undo/index.d.cts +2 -2
  157. package/dist/undo/index.d.ts +2 -2
  158. package/dist/undo.cjs.map +1 -1
  159. package/dist/undo.js +3 -3
  160. package/package.json +13 -1
  161. package/dist/chunk-4KAIV6OD.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -112,7 +112,7 @@ var MicroMcpServer = class extends ToolRegistry {
112
112
  }
113
113
  const request = message;
114
114
  try {
115
- const result = await this.handle(request);
115
+ const result = await this.handle(request, transport);
116
116
  transport.send({ jsonrpc: "2.0", id: request.id, result });
117
117
  } catch (err) {
118
118
  transport.send({
@@ -122,7 +122,7 @@ var MicroMcpServer = class extends ToolRegistry {
122
122
  });
123
123
  }
124
124
  }
125
- async handle(request) {
125
+ async handle(request, transport) {
126
126
  const { method, params } = request;
127
127
  switch (method) {
128
128
  case "initialize":
@@ -144,7 +144,7 @@ var MicroMcpServer = class extends ToolRegistry {
144
144
  if (!tool) {
145
145
  throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unknown tool: ${name}`);
146
146
  }
147
- const result = await tool.handler(args);
147
+ const result = await tool.handler(args, { transport });
148
148
  return result;
149
149
  }
150
150
  case "ping":
@@ -161,6 +161,11 @@ var MicroMcpServer = class extends ToolRegistry {
161
161
  this.broadcast({ jsonrpc: "2.0", method: "notifications/tools/list_changed" });
162
162
  });
163
163
  }
164
+ /** Send an application notification to every client, or one attached transport. */
165
+ notify(message, transport) {
166
+ if (transport) transport.send(message);
167
+ else this.broadcast(message);
168
+ }
164
169
  broadcast(message) {
165
170
  for (const t of this.transports) t.send(message);
166
171
  }
@@ -252,6 +257,50 @@ function attachRelay(server, channel) {
252
257
  return transport;
253
258
  }
254
259
 
260
+ // src/human-plus/events.ts
261
+ var MemoryHumanPlusEventStore = class {
262
+ constructor() {
263
+ this.events = [];
264
+ this.acknowledgements = /* @__PURE__ */ new Map();
265
+ this.listeners = /* @__PURE__ */ new Set();
266
+ this.nextSequence = 1;
267
+ }
268
+ async append(input) {
269
+ const event = { ...input, id: input.id ?? globalThis.crypto.randomUUID(), timestamp: input.timestamp ?? Date.now(), sequence: this.nextSequence++ };
270
+ this.events.push(event);
271
+ this.listeners.forEach((listener) => listener(event));
272
+ return event;
273
+ }
274
+ async list(query) {
275
+ const acknowledged = this.acknowledgements.get(query.consumerId);
276
+ const events = this.events.filter((event) => event.sequence > (query.after ?? 0) && (!query.unacknowledgedOnly || !acknowledged?.has(event.id)) && (!query.types?.length || query.types.includes(event.type)) && (!query.surfaces?.length || query.surfaces.includes(event.surfaceId))).slice(0, Math.max(1, Math.min(500, query.limit ?? 50)));
277
+ return { events, nextCursor: events.at(-1)?.sequence ?? query.after ?? 0 };
278
+ }
279
+ async acknowledge(consumerId, eventIds, disposition) {
280
+ let values = this.acknowledgements.get(consumerId);
281
+ if (!values) {
282
+ values = /* @__PURE__ */ new Map();
283
+ this.acknowledgements.set(consumerId, values);
284
+ }
285
+ eventIds.forEach((id) => values.set(id, disposition));
286
+ }
287
+ subscribe(listener) {
288
+ this.listeners.add(listener);
289
+ return () => this.listeners.delete(listener);
290
+ }
291
+ async compact(options = {}) {
292
+ const cutoff = options.before ?? Number.POSITIVE_INFINITY;
293
+ const keep = options.keepLast ?? 1e3;
294
+ const removable = Math.max(0, this.events.length - keep);
295
+ this.events = this.events.filter((event, index) => index >= removable || event.timestamp >= cutoff);
296
+ const ids = new Set(this.events.map((event) => event.id));
297
+ for (const values of this.acknowledgements.values()) for (const id of values.keys()) if (!ids.has(id)) values.delete(id);
298
+ }
299
+ };
300
+
301
+ // src/presence/index.ts
302
+ init_registry();
303
+
255
304
  // src/presence/wrap-tool-with-activity.ts
256
305
  init_registry();
257
306
  function wrapToolWithActivity(handler, options) {
@@ -286,6 +335,133 @@ function extractMeta(result) {
286
335
  return void 0;
287
336
  }
288
337
 
338
+ // src/presence/use-agent-activity.ts
339
+ init_registry();
340
+ function useAgentActivity(filter, options = {}) {
341
+ const cap = options.capacity ?? 50;
342
+ const [events, setEvents] = react.useState(() => fancyAutoCommon.readActivityHistory(filter).slice(-cap));
343
+ react.useEffect(() => {
344
+ setEvents(fancyAutoCommon.readActivityHistory(filter).slice(-cap));
345
+ return fancyAutoCommon.onActivity((event) => {
346
+ setEvents((prev) => {
347
+ const next = prev.length >= cap ? prev.slice(prev.length - cap + 1) : prev.slice();
348
+ next.push(event);
349
+ return next;
350
+ });
351
+ }, filter);
352
+ }, [filter?.agentId, filter?.screenId, filter?.kind, cap]);
353
+ return { events, latest: events.length > 0 ? events[events.length - 1] : null };
354
+ }
355
+ function useAgentActivityForScreen(screenId, options = {}) {
356
+ const { events, latest } = useAgentActivity({ screenId }, options);
357
+ const fadeAfter = latest?.ttlMs ?? 1500;
358
+ const [isAgentActive, setActive] = react.useState(false);
359
+ react.useEffect(() => {
360
+ if (!latest) {
361
+ setActive(false);
362
+ return;
363
+ }
364
+ setActive(true);
365
+ const timer = setTimeout(() => setActive(false), fadeAfter);
366
+ return () => clearTimeout(timer);
367
+ }, [latest, fadeAfter]);
368
+ return { events, latest, isAgentActive };
369
+ }
370
+
371
+ // src/bridges/tui.ts
372
+ function registerTuiBridge(host, options) {
373
+ const disposers = [];
374
+ const subscriptions = /* @__PURE__ */ new Map();
375
+ const pending = /* @__PURE__ */ new Map();
376
+ const defaultActor = options.actor ?? { kind: "agent", id: "agent", name: "Agent" };
377
+ const serverCapabilities = host.capabilities;
378
+ if (serverCapabilities) serverCapabilities.experimental = { ...serverCapabilities.experimental, "io.particle-academy/human-plus": { version: "1", push: true, durableCursor: true, stagedActions: true, wakesAgent: false } };
379
+ const register = (name, description, properties, required, handler) => {
380
+ disposers.push(host.registerTool({ name, description, inputSchema: { type: "object", properties, required } }, async (args, context) => {
381
+ try {
382
+ const result = await handler(args, context);
383
+ return textResult(typeof result === "string" ? result : JSON.stringify(result), result);
384
+ } catch (error) {
385
+ return errorResult(error instanceof Error ? error.message : String(error));
386
+ }
387
+ }));
388
+ };
389
+ const publish = async (surfaceId, type, payload, actor = defaultActor, priority = "normal") => options.eventStore.append({ appId: options.appId, sessionId: options.sessionId, surfaceId, type, payload, actor, priority });
390
+ register("tui_surfaces_list", "List addressable Fancy TUI surfaces and commands.", {}, [], () => options.registry.list().map((surface) => ({ id: surface.id, kind: surface.kind, label: surface.label, commands: surface.commands?.map((command) => ({ name: command.name, description: command.description, policy: command.policy ?? "execute", inputSchema: command.inputSchema })) ?? [] })));
391
+ register("tui_surface_read", "Read a Fancy TUI surface by stable id.", { id: { type: "string" } }, ["id"], (args) => {
392
+ const surface = options.registry.get(String(args.id));
393
+ if (!surface) throw new Error(`Unknown TUI surface: ${String(args.id)}`);
394
+ return { id: surface.id, kind: surface.kind, state: surface.read() };
395
+ });
396
+ register("tui_action_invoke", "Invoke or propose an action on a Fancy TUI surface.", { surfaceId: { type: "string" }, command: { type: "string" }, input: { type: "object" } }, ["surfaceId", "command"], async (args) => {
397
+ const surfaceId = String(args.surfaceId);
398
+ const commandName = String(args.command);
399
+ const surface = options.registry.get(surfaceId);
400
+ if (!surface) throw new Error(`Unknown TUI surface: ${surfaceId}`);
401
+ const command = surface.commands?.find((value) => value.name === commandName);
402
+ if (!command) throw new Error(`Unknown command '${commandName}' on ${surfaceId}`);
403
+ const policy = command.policy ?? "execute";
404
+ if (policy === "observe" || policy === "human-only") throw new Error(`Action ${surfaceId}.${commandName} is ${policy}`);
405
+ const input = args.input && typeof args.input === "object" && !Array.isArray(args.input) ? args.input : {};
406
+ if (policy === "propose" || policy === "confirm") {
407
+ const id = globalThis.crypto.randomUUID();
408
+ pending.set(id, { id, surfaceId, command: commandName, input, actor: defaultActor });
409
+ await publish(surfaceId, "action.proposed", { id, command: commandName, input }, defaultActor, "attention");
410
+ return { pending: true, id };
411
+ }
412
+ const result = await command.invoke(input);
413
+ await publish(surfaceId, "action.executed", { command: commandName, input, result });
414
+ fancyAutoCommon.emitActivity({ agentId: defaultActor.id, agentName: defaultActor.name, target: { kind: "custom", elementId: surfaceId }, action: `tui_${commandName}`, timestamp: Date.now(), meta: { surfaceId } });
415
+ return { executed: true, result };
416
+ });
417
+ register("tui_action_confirm", "Confirm and execute a pending TUI action.", { id: { type: "string" } }, ["id"], async (args) => {
418
+ const id = String(args.id);
419
+ const value = pending.get(id);
420
+ if (!value) throw new Error(`Unknown pending action: ${id}`);
421
+ const surface = options.registry.get(value.surfaceId);
422
+ const command = surface?.commands?.find((x) => x.name === value.command);
423
+ if (!command) throw new Error("Pending action target is no longer available");
424
+ pending.delete(id);
425
+ const result = await command.invoke(value.input);
426
+ await publish(value.surfaceId, "action.confirmed", { id, command: value.command, result }, { kind: "human", id: "human" });
427
+ return { executed: true, result };
428
+ });
429
+ register("tui_action_reject", "Reject a pending TUI action.", { id: { type: "string" } }, ["id"], async (args) => {
430
+ const id = String(args.id);
431
+ const value = pending.get(id);
432
+ if (!value) throw new Error(`Unknown pending action: ${id}`);
433
+ pending.delete(id);
434
+ await publish(value.surfaceId, "action.rejected", { id, command: value.command }, { kind: "human", id: "human" });
435
+ return { rejected: true };
436
+ });
437
+ register("human_plus_events_list", "Pull durable Human+ events for a consumer.", { consumerId: { type: "string" }, after: { type: "number" }, limit: { type: "number" }, unacknowledgedOnly: { type: "boolean" } }, ["consumerId"], (args) => options.eventStore.list({ consumerId: String(args.consumerId), after: typeof args.after === "number" ? args.after : void 0, limit: typeof args.limit === "number" ? args.limit : void 0, unacknowledgedOnly: args.unacknowledgedOnly === true }));
438
+ register("human_plus_events_ack", "Acknowledge durable Human+ events.", { consumerId: { type: "string" }, eventIds: { type: "array", items: { type: "string" } }, disposition: { type: "string" } }, ["consumerId", "eventIds"], async (args) => {
439
+ const ids = Array.isArray(args.eventIds) ? args.eventIds.map(String) : [];
440
+ await options.eventStore.acknowledge(String(args.consumerId), ids, ["seen", "handled", "rejected", "ignored"].includes(String(args.disposition)) ? String(args.disposition) : "handled");
441
+ return { acknowledged: ids.length };
442
+ });
443
+ register("human_plus_events_subscribe", "Push matching Human+ events on this MCP transport while retaining them in the inbox.", { consumerId: { type: "string" }, types: { type: "array" }, surfaces: { type: "array" } }, ["consumerId"], (args, context) => {
444
+ if (!context?.transport) throw new Error("Subscriptions require an attached MCP transport");
445
+ subscriptions.set(context.transport, { consumerId: String(args.consumerId), types: Array.isArray(args.types) ? args.types.map(String) : void 0, surfaces: Array.isArray(args.surfaces) ? args.surfaces.map(String) : void 0 });
446
+ return { subscribed: true, delivery: "at-least-once", wakesAgent: false };
447
+ });
448
+ const unsubscribeStore = options.eventStore.subscribe((event) => {
449
+ const server = host;
450
+ if (typeof server.notify !== "function") return;
451
+ for (const [transport, subscription] of subscriptions) {
452
+ if (subscription.types?.length && !subscription.types.includes(event.type)) continue;
453
+ if (subscription.surfaces?.length && !subscription.surfaces.includes(event.surfaceId)) continue;
454
+ server.notify({ jsonrpc: "2.0", method: "notifications/human_plus/event", params: event }, transport);
455
+ }
456
+ });
457
+ return { id: "tui", title: "Fancy TUI", pending: () => [...pending.values()], dispose: () => {
458
+ disposers.forEach((dispose) => dispose());
459
+ unsubscribeStore();
460
+ subscriptions.clear();
461
+ pending.clear();
462
+ } };
463
+ }
464
+
289
465
  // src/undo/undo-tools.ts
290
466
  var installedHosts = /* @__PURE__ */ new WeakSet();
291
467
  function ensureUndoToolsRegistered(host, options = {}) {
@@ -4568,39 +4744,6 @@ function buildCurlRecipe(session) {
4568
4744
  ].join("\n");
4569
4745
  }
4570
4746
 
4571
- // src/presence/use-agent-activity.ts
4572
- init_registry();
4573
- function useAgentActivity(filter, options = {}) {
4574
- const cap = options.capacity ?? 50;
4575
- const [events, setEvents] = react.useState(() => fancyAutoCommon.readActivityHistory(filter).slice(-cap));
4576
- react.useEffect(() => {
4577
- setEvents(fancyAutoCommon.readActivityHistory(filter).slice(-cap));
4578
- return fancyAutoCommon.onActivity((event) => {
4579
- setEvents((prev) => {
4580
- const next = prev.length >= cap ? prev.slice(prev.length - cap + 1) : prev.slice();
4581
- next.push(event);
4582
- return next;
4583
- });
4584
- }, filter);
4585
- }, [filter?.agentId, filter?.screenId, filter?.kind, cap]);
4586
- return { events, latest: events.length > 0 ? events[events.length - 1] : null };
4587
- }
4588
- function useAgentActivityForScreen(screenId, options = {}) {
4589
- const { events, latest } = useAgentActivity({ screenId }, options);
4590
- const fadeAfter = latest?.ttlMs ?? 1500;
4591
- const [isAgentActive, setActive] = react.useState(false);
4592
- react.useEffect(() => {
4593
- if (!latest) {
4594
- setActive(false);
4595
- return;
4596
- }
4597
- setActive(true);
4598
- const timer = setTimeout(() => setActive(false), fadeAfter);
4599
- return () => clearTimeout(timer);
4600
- }, [latest, fadeAfter]);
4601
- return { events, latest, isAgentActive };
4602
- }
4603
-
4604
4747
  // src/connectors/targets.ts
4605
4748
  var CLAUDE_CONNECTORS_URL = "https://claude.ai/settings/connectors";
4606
4749
  function encodeBase64Json(value) {
@@ -4905,6 +5048,23 @@ function CoBrowsePresence({ session, connectUrl, shareBaseUrl, className }) {
4905
5048
  ] });
4906
5049
  }
4907
5050
  CoBrowsePresence.displayName = "CoBrowsePresence";
5051
+ var CURSOR_EDGE_INSET = 24;
5052
+ var FLUID_CURSOR_SPEED_PX_PER_SECOND = 1050;
5053
+ var MIN_GLIDE_MS = 240;
5054
+ var MAX_GLIDE_MS = 1200;
5055
+ function visibleCursorPoint(rect, viewport) {
5056
+ const x = rect.x + rect.width / 2;
5057
+ const y = rect.y + rect.height / 2;
5058
+ return {
5059
+ x: Math.min(Math.max(x, CURSOR_EDGE_INSET), Math.max(CURSOR_EDGE_INSET, viewport.width - CURSOR_EDGE_INSET)),
5060
+ y: Math.min(Math.max(y, CURSOR_EDGE_INSET), Math.max(CURSOR_EDGE_INSET, viewport.height - CURSOR_EDGE_INSET))
5061
+ };
5062
+ }
5063
+ function fluidGlideDuration(from, to) {
5064
+ if (!from) return 0;
5065
+ const distance = Math.hypot(to.x - from.x, to.y - from.y);
5066
+ return Math.round(Math.min(MAX_GLIDE_MS, Math.max(MIN_GLIDE_MS, distance / FLUID_CURSOR_SPEED_PX_PER_SECOND * 1e3)));
5067
+ }
4908
5068
  function CoBrowseCursorLayer({ active = true, zIndex = 2147483e3 }) {
4909
5069
  const { latest } = useAgentActivity(void 0, { capacity: 12 });
4910
5070
  const [cursor, setCursor] = react.useState(
@@ -4914,7 +5074,7 @@ function CoBrowseCursorLayer({ active = true, zIndex = 2147483e3 }) {
4914
5074
  react.useEffect(() => {
4915
5075
  if (!latest || (latest.source ?? "agent") === "user") return;
4916
5076
  if (latest.action === "agent_disconnected") {
4917
- setCursor(null);
5077
+ setCursor((prev) => prev ? { ...prev, status: "Standing by", glideMs: 0 } : prev);
4918
5078
  setPulse(null);
4919
5079
  return;
4920
5080
  }
@@ -4923,11 +5083,19 @@ function CoBrowseCursorLayer({ active = true, zIndex = 2147483e3 }) {
4923
5083
  const status = latest.target?.label ?? latest.action;
4924
5084
  const rect = latest.meta?.rect;
4925
5085
  if (rect) {
4926
- setCursor({ x: rect.x + rect.width / 2, y: rect.y + rect.height / 2, name, color, status });
5086
+ const target = visibleCursorPoint(rect, { width: window.innerWidth, height: window.innerHeight });
5087
+ const reduceMotion = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
5088
+ setCursor((prev) => ({
5089
+ ...target,
5090
+ name,
5091
+ color,
5092
+ status,
5093
+ glideMs: reduceMotion ? 0 : fluidGlideDuration(prev, target)
5094
+ }));
4927
5095
  setPulse({ rect, color, key: latest.timestamp });
4928
5096
  } else {
4929
5097
  setCursor(
4930
- (prev) => prev ? { ...prev, status, name, color } : { x: window.innerWidth / 2, y: window.innerHeight / 2, name, color, status }
5098
+ (prev) => prev ? { ...prev, status, name, color } : { x: window.innerWidth / 2, y: window.innerHeight / 2, name, color, status, glideMs: 0 }
4931
5099
  );
4932
5100
  }
4933
5101
  }, [latest?.timestamp]);
@@ -4953,7 +5121,9 @@ function CoBrowseCursorLayer({ active = true, zIndex = 2147483e3 }) {
4953
5121
  name: cursor.name,
4954
5122
  color: cursor.color,
4955
5123
  status: cursor.status,
4956
- style: { transition: "left .35s cubic-bezier(.22,.61,.36,1), top .35s cubic-bezier(.22,.61,.36,1)" }
5124
+ style: {
5125
+ transition: cursor.glideMs ? `left ${cursor.glideMs}ms cubic-bezier(.22,.61,.36,1), top ${cursor.glideMs}ms cubic-bezier(.22,.61,.36,1)` : "none"
5126
+ }
4957
5127
  }
4958
5128
  )
4959
5129
  ] }),
@@ -5032,9 +5202,6 @@ function SimulateUsersButton({
5032
5202
  );
5033
5203
  }
5034
5204
 
5035
- // src/presence/index.ts
5036
- init_registry();
5037
-
5038
5205
  // src/heuristics/sink.ts
5039
5206
  function numericMeta(meta, key) {
5040
5207
  const v = meta?.[key];
@@ -5275,6 +5442,7 @@ exports.InProcessTransport = InProcessTransport;
5275
5442
  exports.MCPB_MANIFEST_VERSION = MCPB_MANIFEST_VERSION;
5276
5443
  exports.MCPB_MIN_NODE = MCPB_MIN_NODE;
5277
5444
  exports.MCP_PROTOCOL_VERSION = MCP_PROTOCOL_VERSION;
5445
+ exports.MemoryHumanPlusEventStore = MemoryHumanPlusEventStore;
5278
5446
  exports.MicroMcpServer = MicroMcpServer;
5279
5447
  exports.RelayTransport = RelayTransport;
5280
5448
  exports.ScreensActivityBridge = ScreensActivityBridge;
@@ -5321,6 +5489,7 @@ exports.registerScreensBridge = registerScreensBridge;
5321
5489
  exports.registerSheetsBridge = registerSheetsBridge;
5322
5490
  exports.registerSlidesBridge = registerSlidesBridge;
5323
5491
  exports.registerTerminalBridge = registerTerminalBridge;
5492
+ exports.registerTuiBridge = registerTuiBridge;
5324
5493
  exports.registerUndoTools = registerUndoTools;
5325
5494
  exports.rpcError = rpcError;
5326
5495
  exports.slugifyServerName = slugifyServerName;