@particle-academy/agent-integrations 0.27.0 → 0.28.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.
@@ -1,5 +1,5 @@
1
- import { ShareControls, AgentCursor, AgentActivityHighlight, AgentPanel } from './chunk-HKQBG2HZ.js';
2
- import { createSessionDescriptor, attachSseRelay } from './chunk-FUI7KXE7.js';
1
+ import { ShareControls, AgentCursor, AgentActivityHighlight, AgentPanel } from './chunk-5KLUYF4D.js';
2
+ import { createSessionDescriptor, attachSseRelay } from './chunk-KMSRG5KH.js';
3
3
  import { attachInProcess } from './chunk-AFUULW5E.js';
4
4
  import { registerWhiteboardBridge } from './chunk-AAMQOXZC.js';
5
5
  import './chunk-ULJL53DL.js';
package/dist/index.cjs CHANGED
@@ -2820,7 +2820,7 @@ function registerNavigationBridge(host, options) {
2820
2820
  ].join("\n");
2821
2821
  return textResult(text, snap);
2822
2822
  },
2823
- false
2823
+ () => target("Inspect page")
2824
2824
  );
2825
2825
  reg(
2826
2826
  "page_read",
@@ -2828,7 +2828,23 @@ function registerNavigationBridge(host, options) {
2828
2828
  {},
2829
2829
  [],
2830
2830
  () => textResult(adapter.read ? adapter.read() : "(host did not provide page text)"),
2831
- false
2831
+ () => target("Read page")
2832
+ );
2833
+ reg(
2834
+ "page_focus",
2835
+ "Move the agent's visible focus to an interactive element by stable handle without activating it.",
2836
+ { handle: { type: "string" } },
2837
+ ["handle"],
2838
+ (args) => {
2839
+ const handle = String(args.handle ?? "");
2840
+ const action = adapter.describe().actions.find((candidate) => candidate.handle === handle);
2841
+ if (!action) return errorResult(`No element for handle "${handle}"`);
2842
+ return textResult(`Focused ${handle}`, {
2843
+ handle,
2844
+ rect: adapter.rectFor?.(handle) ?? void 0
2845
+ });
2846
+ },
2847
+ (args) => target(`Focus ${String(args.handle ?? "")}`, String(args.handle ?? ""))
2832
2848
  );
2833
2849
  reg(
2834
2850
  "nav_visit",
@@ -3853,6 +3869,7 @@ function constantTimeEqual(a, b) {
3853
3869
  }
3854
3870
 
3855
3871
  // src/sharing/sse-relay.ts
3872
+ init_registry();
3856
3873
  var SseRelayTransport = class {
3857
3874
  constructor(options) {
3858
3875
  this.disposed = false;
@@ -3860,6 +3877,7 @@ var SseRelayTransport = class {
3860
3877
  this.connected = false;
3861
3878
  this.listeners = /* @__PURE__ */ new Set();
3862
3879
  this.state = "idle";
3880
+ this.peers = /* @__PURE__ */ new Set();
3863
3881
  this.opts = options;
3864
3882
  this.expectedToken = options.token;
3865
3883
  }
@@ -3958,6 +3976,36 @@ var SseRelayTransport = class {
3958
3976
  } catch {
3959
3977
  return;
3960
3978
  }
3979
+ if ("method" in message && message.method === "notifications/peer_joined") {
3980
+ const subscriberId = String(message.params?.subscriberId ?? "peer");
3981
+ this.peers.add(subscriberId);
3982
+ fancyAutoCommon.emitActivity({
3983
+ agentId: "agent",
3984
+ agentName: "Agent",
3985
+ agentColor: "#a855f7",
3986
+ action: "agent_connected",
3987
+ timestamp: Date.now(),
3988
+ target: { kind: "navigation", label: "Agent connected" },
3989
+ meta: { subscriberId }
3990
+ });
3991
+ return;
3992
+ }
3993
+ if ("method" in message && message.method === "notifications/peer_left") {
3994
+ const subscriberId = String(message.params?.subscriberId ?? "peer");
3995
+ this.peers.delete(subscriberId);
3996
+ if (this.peers.size === 0) {
3997
+ fancyAutoCommon.emitActivity({
3998
+ agentId: "agent",
3999
+ agentName: "Agent",
4000
+ agentColor: "#a855f7",
4001
+ action: "agent_disconnected",
4002
+ timestamp: Date.now(),
4003
+ target: { kind: "navigation", label: "Agent disconnected" },
4004
+ meta: { subscriberId }
4005
+ });
4006
+ }
4007
+ return;
4008
+ }
3961
4009
  await this.server.receive(this, message);
3962
4010
  }
3963
4011
  setState(state) {
@@ -4026,11 +4074,14 @@ function useCoBrowseSession(options) {
4026
4074
  if (!server || relayRef.current) return;
4027
4075
  const descriptor = createSessionDescriptor();
4028
4076
  const csrf = options.csrfToken?.() ?? "";
4029
- await fetch(`${relayBaseUrl}/register`, {
4077
+ const response = await fetch(`${relayBaseUrl}/register`, {
4030
4078
  method: "POST",
4031
4079
  headers: { "content-type": "application/json", "x-csrf-token": csrf },
4032
4080
  body: JSON.stringify({ session: descriptor.id, token: descriptor.token })
4033
4081
  });
4082
+ if (!response.ok) {
4083
+ throw new Error(`Relay registration failed (${response.status})`);
4084
+ }
4034
4085
  const relay = attachSseRelay(server, { baseUrl: relayBaseUrl, sessionId: descriptor.id, token: descriptor.token });
4035
4086
  relay.onStateChange(setRelayState);
4036
4087
  relayRef.current = relay;
@@ -4044,16 +4095,15 @@ function useCoBrowseSession(options) {
4044
4095
  setSession(null);
4045
4096
  if (current) {
4046
4097
  const csrf = options.csrfToken?.() ?? "";
4047
- void fetch(`${relayBaseUrl}/${current.id}/unregister`, {
4098
+ void fetch(`${relayBaseUrl}/${current.id}/unregister?token=${encodeURIComponent(current.token)}`, {
4048
4099
  method: "POST",
4049
- headers: { "content-type": "application/json", "x-csrf-token": csrf },
4050
- body: JSON.stringify({ token: current.token })
4100
+ headers: { "content-type": "application/json", "x-csrf-token": csrf }
4051
4101
  }).catch(() => {
4052
4102
  });
4053
4103
  }
4054
4104
  }, [relayBaseUrl, options, session]);
4055
4105
  const observeUser = react.useCallback((event) => {
4056
- const label = event.kind === "navigation" ? `You navigated to ${event.url}` : event.kind === "scroll" ? "You scrolled" : `You edited ${event.handle}${event.masked ? " (hidden)" : ""}`;
4106
+ const label = event.kind === "navigation" ? `You navigated to ${event.url}` : event.kind === "scroll" ? "You scrolled" : event.kind === "click" ? `You clicked ${event.label ?? event.handle}` : `You edited ${event.handle}${event.masked ? " (hidden)" : ""}`;
4057
4107
  fancyAutoCommon.emitActivity({
4058
4108
  agentId: USER.id,
4059
4109
  agentName: USER.name,
@@ -4829,6 +4879,11 @@ function CoBrowseCursorLayer({ active = true, zIndex = 2147483e3 }) {
4829
4879
  const [pulse, setPulse] = react.useState(null);
4830
4880
  react.useEffect(() => {
4831
4881
  if (!latest || (latest.source ?? "agent") === "user") return;
4882
+ if (latest.action === "agent_disconnected") {
4883
+ setCursor(null);
4884
+ setPulse(null);
4885
+ return;
4886
+ }
4832
4887
  const color = latest.agentColor ?? "#a855f7";
4833
4888
  const name = latest.agentName ?? "Agent";
4834
4889
  const status = latest.target?.label ?? latest.action;