@particle-academy/agent-integrations 0.32.0 → 0.33.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.
@@ -170,11 +170,21 @@ function ShareControls({
170
170
  onStart,
171
171
  onStop,
172
172
  status,
173
+ agentConnected = false,
174
+ activity,
173
175
  shareBaseUrl,
174
176
  className,
175
177
  style
176
178
  }) {
177
179
  const [tab, setTab] = useState("prompt");
180
+ const wasConnected = useRef(false);
181
+ useEffect(() => {
182
+ if (agentConnected && !wasConnected.current) {
183
+ wasConnected.current = true;
184
+ setTab("activity");
185
+ }
186
+ if (!agentConnected) wasConnected.current = false;
187
+ }, [agentConnected]);
178
188
  if (!session) {
179
189
  return /* @__PURE__ */ jsxs("div", { className: ["fai-share fai-share--idle", className ?? ""].filter(Boolean).join(" "), style, children: [
180
190
  /* @__PURE__ */ jsx("button", { type: "button", className: "fai-share__start", onClick: onStart, children: "Start shared session" }),
@@ -209,12 +219,14 @@ function ShareControls({
209
219
  ] })
210
220
  ] }),
211
221
  /* @__PURE__ */ jsxs("div", { className: "fai-share__tabs", role: "tablist", children: [
222
+ agentConnected && /* @__PURE__ */ jsx(TabButton, { tab: "activity", active: tab, setTab, children: "Activity" }),
212
223
  /* @__PURE__ */ jsx(TabButton, { tab: "prompt", active: tab, setTab, children: "Agent prompt" }),
213
224
  /* @__PURE__ */ jsx(TabButton, { tab: "url", active: tab, setTab, children: "URL" }),
214
225
  /* @__PURE__ */ jsx(TabButton, { tab: "json", active: tab, setTab, children: "JSON" }),
215
226
  /* @__PURE__ */ jsx(TabButton, { tab: "curl", active: tab, setTab, children: "cURL recipe" })
216
227
  ] }),
217
228
  /* @__PURE__ */ jsxs("div", { className: "fai-share__panel", children: [
229
+ tab === "activity" && /* @__PURE__ */ jsx(ActivityLog, { activity }),
218
230
  tab === "prompt" && /* @__PURE__ */ jsx(
219
231
  CopyBox,
220
232
  {
@@ -242,6 +254,21 @@ function ShareControls({
242
254
  ] })
243
255
  ] });
244
256
  }
257
+ function ActivityLog({ activity }) {
258
+ const entries = (activity ?? []).slice().reverse();
259
+ if (entries.length === 0) {
260
+ return /* @__PURE__ */ jsx("p", { className: "fai-share__empty", children: "Connected. Nothing yet \u2014 actions appear here as the agent takes them." });
261
+ }
262
+ return /* @__PURE__ */ jsx("ol", { className: "fai-share__activity", "aria-live": "polite", children: entries.map((entry) => /* @__PURE__ */ jsxs("li", { className: "fai-share__activity-row", "data-kind": entry.kind, children: [
263
+ /* @__PURE__ */ jsx("time", { className: "fai-share__activity-time", dateTime: new Date(entry.at).toISOString(), children: new Date(entry.at).toLocaleTimeString(void 0, {
264
+ hour: "2-digit",
265
+ minute: "2-digit",
266
+ second: "2-digit"
267
+ }) }),
268
+ /* @__PURE__ */ jsx("span", { className: "fai-share__activity-source", children: entry.source }),
269
+ /* @__PURE__ */ jsx("span", { className: "fai-share__activity-text", children: entry.text })
270
+ ] }, entry.id)) });
271
+ }
245
272
  function TabButton({ tab, active, setTab, children }) {
246
273
  return /* @__PURE__ */ jsx(
247
274
  "button",
@@ -326,5 +353,5 @@ function buildCurlRecipe(session) {
326
353
  }
327
354
 
328
355
  export { AgentActivityHighlight, AgentCursor, AgentPanel, ShareControls, buildAgentPrompt };
329
- //# sourceMappingURL=chunk-HSI5RVF4.js.map
330
- //# sourceMappingURL=chunk-HSI5RVF4.js.map
356
+ //# sourceMappingURL=chunk-SJTLTITO.js.map
357
+ //# sourceMappingURL=chunk-SJTLTITO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/AgentPanel/AgentPanel.tsx","../src/components/AgentCursor/AgentCursor.tsx","../src/components/AgentActivityHighlight/AgentActivityHighlight.tsx","../src/components/ShareControls/ShareControls.tsx"],"names":["jsxs","jsx","useEffect","useState","useRef"],"mappings":"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","file":"chunk-SJTLTITO.js","sourcesContent":["import { type CSSProperties, type ReactNode, useEffect, useRef } from \"react\";\n\nexport type AgentActivity = {\n id: string;\n /** Wall-clock timestamp; component formats it. */\n at: number;\n /** \"tool\" for MCP tool invocations, \"message\" for chat, \"info\" for status. */\n kind: \"tool\" | \"message\" | \"info\" | \"error\";\n /** Short label, e.g. \"whiteboard_add_sticky\" or \"Agent\". */\n source: string;\n /** Body text. */\n text: string;\n /** Optional structured payload, rendered as collapsed JSON. */\n detail?: unknown;\n};\n\nexport type AgentPanelProps = {\n /** The agent's identity (name + color appears in the header). */\n agent?: { name?: string; color?: string };\n /** Activity stream. Most recent at the end. */\n activity: AgentActivity[];\n /** Optional chat composer — pass an onSubmit to enable. */\n onSubmit?: (message: string) => void;\n /** Disabled while a request is in flight. */\n busy?: boolean;\n /** Right-rail header actions. */\n actions?: ReactNode;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * AgentPanel — sidebar showing the agent's identity, a tool-and-chat log,\n * and an optional input composer. Pure presentational: hosts feed it the\n * activity stream from their own state (typically the MCP transport log).\n */\nexport function AgentPanel({ agent, activity, onSubmit, busy, actions, className, style }: AgentPanelProps) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n el.scrollTop = el.scrollHeight;\n }, [activity.length]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n const value = inputRef.current?.value.trim();\n if (!value || !onSubmit) return;\n onSubmit(value);\n if (inputRef.current) inputRef.current.value = \"\";\n };\n\n const color = agent?.color ?? \"#a855f7\";\n const name = agent?.name ?? \"Agent\";\n\n return (\n <div className={[\"fai-panel\", className ?? \"\"].filter(Boolean).join(\" \")} style={style}>\n <header className=\"fai-panel__header\">\n <div\n className=\"fai-panel__avatar\"\n style={{ background: color }}\n aria-hidden\n >\n {name.slice(0, 1)}\n </div>\n <div className=\"fai-panel__title\">\n <strong>{name}</strong>\n <span className=\"fai-panel__subtitle\">\n {busy ? \"Working…\" : `${activity.length} event${activity.length === 1 ? \"\" : \"s\"}`}\n </span>\n </div>\n {actions && <div className=\"fai-panel__actions\">{actions}</div>}\n </header>\n\n <div ref={scrollRef} className=\"fai-panel__stream\">\n {activity.length === 0 ? (\n <p className=\"fai-panel__empty\">No activity yet.</p>\n ) : (\n activity.map((a) => <ActivityRow key={a.id} item={a} />)\n )}\n </div>\n\n {onSubmit && (\n <form className=\"fai-panel__composer\" onSubmit={handleSubmit}>\n <textarea\n ref={inputRef}\n className=\"fai-panel__input\"\n placeholder={busy ? \"Working…\" : \"Ask the agent…\"}\n disabled={busy}\n rows={2}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit(e as unknown as React.FormEvent);\n }\n }}\n />\n <button type=\"submit\" className=\"fai-panel__send\" disabled={busy}>\n Send\n </button>\n </form>\n )}\n </div>\n );\n}\n\nfunction ActivityRow({ item }: { item: AgentActivity }) {\n const time = formatTime(item.at);\n return (\n <div className={`fai-row fai-row--${item.kind}`}>\n <div className=\"fai-row__meta\">\n <span className=\"fai-row__source\">{item.source}</span>\n <span className=\"fai-row__time\">{time}</span>\n </div>\n <div className=\"fai-row__text\">{item.text}</div>\n {item.detail !== undefined && (\n <details className=\"fai-row__detail\">\n <summary>details</summary>\n <pre>{safeJson(item.detail)}</pre>\n </details>\n )}\n </div>\n );\n}\n\nfunction formatTime(at: number): string {\n const d = new Date(at);\n const hh = d.getHours().toString().padStart(2, \"0\");\n const mm = d.getMinutes().toString().padStart(2, \"0\");\n const ss = d.getSeconds().toString().padStart(2, \"0\");\n return `${hh}:${mm}:${ss}`;\n}\n\nfunction safeJson(v: unknown): string {\n try {\n return JSON.stringify(v, null, 2);\n } catch {\n return String(v);\n }\n}\n","import type { CSSProperties } from \"react\";\n\nexport type AgentCursorProps = {\n x: number;\n y: number;\n name?: string;\n color?: string;\n /** Optional caption shown under the name (e.g. current tool). */\n status?: string;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * AgentCursor — on-canvas presence marker for the agent. Drop it inside\n * (or alongside) a fancy-whiteboard <Board> at screen coords matching\n * the agent's reported position.\n */\nexport function AgentCursor({ x, y, name, color = \"#a855f7\", status, className, style }: AgentCursorProps) {\n return (\n <div\n className={[\"fai-cursor\", className ?? \"\"].filter(Boolean).join(\" \")}\n style={{\n position: \"absolute\",\n left: x,\n top: y,\n pointerEvents: \"none\",\n transform: \"translate(-2px, -2px)\",\n ...style,\n }}\n >\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" aria-hidden>\n <path\n d=\"M2 2 L2 17 L7 13 L10 19 L12 18 L9 12 L15 12 Z\"\n fill={color}\n stroke=\"white\"\n strokeWidth=\"1.2\"\n />\n </svg>\n {name && (\n <span\n className=\"fai-cursor__tag\"\n style={{ background: color }}\n >\n {name}\n {status ? <em className=\"fai-cursor__status\"> · {status}</em> : null}\n </span>\n )}\n </div>\n );\n}\n","import { type CSSProperties, useEffect, useState } from \"react\";\n\nexport type AgentActivityHighlightProps = {\n /** Bounds of the highlighted item in the parent's coord system. */\n x: number;\n y: number;\n width: number;\n height: number;\n /** Trigger token — change it (e.g. set to Date.now()) to re-fire the pulse. */\n pulseKey?: string | number;\n /** Highlight tint. */\n color?: string;\n /** Pulse duration in ms. Defaults 1200. */\n duration?: number;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * AgentActivityHighlight — short pulsing outline that flashes around an\n * item the agent just touched. Position the parent so this can be placed\n * absolutely matching the item's bounds.\n */\nexport function AgentActivityHighlight({\n x,\n y,\n width,\n height,\n pulseKey,\n color = \"#a855f7\",\n duration = 1200,\n className,\n style,\n}: AgentActivityHighlightProps) {\n const [visible, setVisible] = useState(false);\n\n useEffect(() => {\n if (pulseKey === undefined) return;\n setVisible(true);\n const t = setTimeout(() => setVisible(false), duration);\n return () => clearTimeout(t);\n }, [pulseKey, duration]);\n\n if (!visible) return null;\n\n return (\n <div\n className={[\"fai-highlight\", className ?? \"\"].filter(Boolean).join(\" \")}\n style={{\n position: \"absolute\",\n left: x - 4,\n top: y - 4,\n width: width + 8,\n height: height + 8,\n borderRadius: 8,\n boxShadow: `0 0 0 2px ${color}, 0 0 16px ${color}66`,\n pointerEvents: \"none\",\n animation: `fai-pulse ${duration}ms ease-out forwards`,\n ...style,\n }}\n />\n );\n}\n","import { type CSSProperties, useEffect, useRef, useState } from \"react\";\nimport type { SessionDescriptor } from \"../../sharing/token\";\nimport type { AgentActivity } from \"../AgentPanel\";\nimport { buildShareConfig, buildShareUrl } from \"../../sharing/token\";\n\nexport type ShareControlsProps = {\n /** The active session, or null when not sharing yet. */\n session: SessionDescriptor | null;\n onStart: () => void;\n onStop: () => void;\n /** Optional connection-state badge text. */\n status?: string;\n /**\n * True once an agent has actually connected to the session.\n *\n * Flips the panel from \"here is how to connect\" to \"here is what the agent is\n * doing\" — the paste-this-prompt UI is dead weight the moment it has been\n * pasted, and what the human needs then is visibility.\n */\n agentConnected?: boolean;\n /**\n * What the agent has done, newest last. Reuses `AgentActivity` from\n * `AgentPanel` rather than a second shape, so a host already collecting\n * presence events can pass the same array to both.\n */\n activity?: AgentActivity[];\n /** Override the URL base used in the share URL. */\n shareBaseUrl?: string;\n className?: string;\n style?: CSSProperties;\n};\n\ntype Tab = \"activity\" | \"prompt\" | \"url\" | \"json\" | \"curl\";\n\n/**\n * ShareControls — the host-facing UI for turning sharing on/off and\n * surfacing the resulting connection details (URL / JSON / cURL).\n */\nexport function ShareControls({\n session,\n onStart,\n onStop,\n status,\n agentConnected = false,\n activity,\n shareBaseUrl,\n className,\n style,\n}: ShareControlsProps) {\n const [tab, setTab] = useState<Tab>(\"prompt\");\n\n // Switch to the log the FIRST time an agent connects, then leave the tab\n // alone. Forcing it on every render would fight a human who deliberately went\n // back to copy the URL again — the panel should follow the session, not\n // overrule the person reading it.\n const wasConnected = useRef(false);\n useEffect(() => {\n if (agentConnected && !wasConnected.current) {\n wasConnected.current = true;\n setTab(\"activity\");\n }\n if (!agentConnected) wasConnected.current = false;\n }, [agentConnected]);\n\n if (!session) {\n return (\n <div className={[\"fai-share fai-share--idle\", className ?? \"\"].filter(Boolean).join(\" \")} style={style}>\n <button type=\"button\" className=\"fai-share__start\" onClick={onStart}>\n Start shared session\n </button>\n <p className=\"fai-share__hint\">\n Generates a session id + secret token. Hand the <strong>Agent prompt</strong> to an AI agent, share the URL with humans, or give the JSON config to an MCP-capable client.\n </p>\n </div>\n );\n }\n\n const url = buildShareUrl(session, shareBaseUrl);\n const config = buildShareConfig(session);\n const curl = buildCurlRecipe(session);\n const prompt = buildAgentPrompt(url);\n\n return (\n <div className={[\"fai-share fai-share--active\", className ?? \"\"].filter(Boolean).join(\" \")} style={style}>\n <div className=\"fai-share__header\">\n <div>\n <strong>Sharing</strong>\n <span className=\"fai-share__id\">\n session <code>{session.id}</code> · token <code>{session.display}…</code>\n </span>\n </div>\n <div className=\"fai-share__header-actions\">\n {status && <span className=\"fai-share__status\">{status}</span>}\n <button type=\"button\" className=\"fai-share__stop\" onClick={onStop}>\n Stop\n </button>\n </div>\n </div>\n\n <div className=\"fai-share__tabs\" role=\"tablist\">\n {agentConnected && (\n <TabButton tab=\"activity\" active={tab} setTab={setTab}>\n Activity\n </TabButton>\n )}\n <TabButton tab=\"prompt\" active={tab} setTab={setTab}>Agent prompt</TabButton>\n <TabButton tab=\"url\" active={tab} setTab={setTab}>URL</TabButton>\n <TabButton tab=\"json\" active={tab} setTab={setTab}>JSON</TabButton>\n <TabButton tab=\"curl\" active={tab} setTab={setTab}>cURL recipe</TabButton>\n </div>\n\n <div className=\"fai-share__panel\">\n {tab === \"activity\" && <ActivityLog activity={activity} />}\n {tab === \"prompt\" && (\n <CopyBox\n label=\"Paste this straight into an AI agent — it connects over MCP, no browser\"\n value={prompt}\n multiline\n />\n )}\n {tab === \"url\" && <CopyBox label=\"Open this URL in another tab to join the session\" value={url} />}\n {tab === \"json\" && (\n <CopyBox\n label=\"Paste into Claude Desktop / Cline MCP server config\"\n value={JSON.stringify(config, null, 2)}\n />\n )}\n {tab === \"curl\" && (\n <CopyBox\n label=\"Connect from a terminal (verifies the relay is reachable)\"\n value={curl}\n multiline\n />\n )}\n </div>\n </div>\n );\n}\n\n/**\n * What the agent has actually done, newest first.\n *\n * The panel used to keep showing the paste-this-prompt UI after the agent was\n * already connected and driving — dead weight at exactly the moment the human\n * needs the opposite: visibility. A connected agent with no visible activity is\n * indistinguishable from a broken one, which is precisely how a stalled session\n * goes unnoticed.\n */\nfunction ActivityLog({ activity }: { activity?: AgentActivity[] }) {\n const entries = (activity ?? []).slice().reverse();\n\n if (entries.length === 0) {\n return (\n <p className=\"fai-share__empty\">\n Connected. Nothing yet — actions appear here as the agent takes them.\n </p>\n );\n }\n\n return (\n <ol className=\"fai-share__activity\" aria-live=\"polite\">\n {entries.map((entry) => (\n <li key={entry.id} className=\"fai-share__activity-row\" data-kind={entry.kind}>\n <time className=\"fai-share__activity-time\" dateTime={new Date(entry.at).toISOString()}>\n {new Date(entry.at).toLocaleTimeString(undefined, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n })}\n </time>\n <span className=\"fai-share__activity-source\">{entry.source}</span>\n <span className=\"fai-share__activity-text\">{entry.text}</span>\n </li>\n ))}\n </ol>\n );\n}\n\nfunction TabButton({ tab, active, setTab, children }: { tab: Tab; active: Tab; setTab: (t: Tab) => void; children: React.ReactNode }) {\n return (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={tab === active}\n className={`fai-share__tab${tab === active ? \" is-active\" : \"\"}`}\n onClick={() => setTab(tab)}\n >\n {children}\n </button>\n );\n}\n\nfunction CopyBox({ label, value, multiline }: { label: string; value: string; multiline?: boolean }) {\n const [copied, setCopied] = useState(false);\n const copy = async () => {\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n } catch {\n // ignore\n }\n };\n return (\n <div>\n <div className=\"fai-share__panel-label\">{label}</div>\n <div className=\"fai-share__copy\">\n <pre className={`fai-share__pre${multiline ? \" is-multi\" : \"\"}`}>{value}</pre>\n <button type=\"button\" className=\"fai-share__copy-btn\" onClick={copy}>\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </div>\n </div>\n );\n}\n\n/**\n * Build a copy-paste natural-language prompt to hand directly to an AI agent.\n * Agents handed a bare URL tend to try to *open it in a browser* — this spells\n * out that the link is a live MCP co-browsing session it should drive over MCP\n * tools (via the zero-install relay client), never visit.\n */\nexport function buildAgentPrompt(url: string): string {\n return [\n `You're joining a live Human+ co-browsing session on a web app. This is an MCP`,\n `(Model Context Protocol) session — NOT a website to visit. Do NOT open the URL`,\n `in a browser and do NOT use any browser/Playwright tool. You drive the real,`,\n `running app through MCP tools while a human watches and can take over.`,\n ``,\n `Session link (carries the session id + token — treat it as a secret):`,\n ` ${url}`,\n ``,\n `Connect by running the relay client as an MCP server (zero install):`,\n ` npx -y mcp-relay-client \"${url}\"`,\n ``,\n `That exposes the app's own tools (e.g. page_describe, page_read, nav_visit,`,\n `page_click, page_set_field, page_submit, plus surface tools like whiteboard_*).`,\n `Then:`,\n ` 1. Call page_describe first to see the current page and its interactive handles.`,\n ` 2. Act only on the STABLE HANDLES the tools return — never guess DOM selectors.`,\n ` 3. Navigate with nav_visit, type with page_set_field, click with page_click.`,\n ` Submits and destructive clicks are staged for the human to confirm.`,\n ``,\n `If you can't register an MCP server but can run a shell, drive it directly:`,\n ` curl -O https://raw.githubusercontent.com/Particle-Academy/mcp-relay-client/main/connect.sh`,\n ` bash connect.sh \"${url}\" tools`,\n ` bash connect.sh \"${url}\" call page_describe '{}'`,\n ].join(\"\\n\");\n}\n\n/** Build a copy-paste cURL recipe for connecting an external MCP client. */\nfunction buildCurlRecipe(session: SessionDescriptor): string {\n const base =\n typeof window !== \"undefined\"\n ? `${window.location.protocol}//${window.location.host}`\n : \"http://localhost\";\n const inbox = `${base}/agent-relay/${session.id}/inbox?token=${session.token}`;\n const events = `${base}/agent-relay/${session.id}/events?token=${session.token}`;\n return [\n `# 1) In one terminal, subscribe to server-pushed frames (SSE)`,\n `curl -N \"${events}\"`,\n ``,\n `# 2) In another terminal, send an initialize handshake`,\n `curl -X POST \"${inbox}\" \\\\`,\n ` -H 'content-type: application/json' \\\\`,\n ` -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{}}'`,\n ``,\n `# 3) List the tools the bridge exposes`,\n `curl -X POST \"${inbox}\" \\\\`,\n ` -H 'content-type: application/json' \\\\`,\n ` -d '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\"}'`,\n ``,\n `# 4) Add a sticky note`,\n `curl -X POST \"${inbox}\" \\\\`,\n ` -H 'content-type: application/json' \\\\`,\n ` -d '{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"whiteboard_add_sticky\",\"arguments\":{\"x\":300,\"y\":300,\"text\":\"hello from curl\"}}}'`,\n ].join(\"\\n\");\n}\n"]}
@@ -980,11 +980,21 @@ function ShareControls({
980
980
  onStart,
981
981
  onStop,
982
982
  status,
983
+ agentConnected = false,
984
+ activity,
983
985
  shareBaseUrl,
984
986
  className,
985
987
  style
986
988
  }) {
987
989
  const [tab, setTab] = react.useState("prompt");
990
+ const wasConnected = react.useRef(false);
991
+ react.useEffect(() => {
992
+ if (agentConnected && !wasConnected.current) {
993
+ wasConnected.current = true;
994
+ setTab("activity");
995
+ }
996
+ if (!agentConnected) wasConnected.current = false;
997
+ }, [agentConnected]);
988
998
  if (!session) {
989
999
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ["fai-share fai-share--idle", className ?? ""].filter(Boolean).join(" "), style, children: [
990
1000
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "fai-share__start", onClick: onStart, children: "Start shared session" }),
@@ -1019,12 +1029,14 @@ function ShareControls({
1019
1029
  ] })
1020
1030
  ] }),
1021
1031
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fai-share__tabs", role: "tablist", children: [
1032
+ agentConnected && /* @__PURE__ */ jsxRuntime.jsx(TabButton, { tab: "activity", active: tab, setTab, children: "Activity" }),
1022
1033
  /* @__PURE__ */ jsxRuntime.jsx(TabButton, { tab: "prompt", active: tab, setTab, children: "Agent prompt" }),
1023
1034
  /* @__PURE__ */ jsxRuntime.jsx(TabButton, { tab: "url", active: tab, setTab, children: "URL" }),
1024
1035
  /* @__PURE__ */ jsxRuntime.jsx(TabButton, { tab: "json", active: tab, setTab, children: "JSON" }),
1025
1036
  /* @__PURE__ */ jsxRuntime.jsx(TabButton, { tab: "curl", active: tab, setTab, children: "cURL recipe" })
1026
1037
  ] }),
1027
1038
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fai-share__panel", children: [
1039
+ tab === "activity" && /* @__PURE__ */ jsxRuntime.jsx(ActivityLog, { activity }),
1028
1040
  tab === "prompt" && /* @__PURE__ */ jsxRuntime.jsx(
1029
1041
  CopyBox,
1030
1042
  {
@@ -1052,6 +1064,21 @@ function ShareControls({
1052
1064
  ] })
1053
1065
  ] });
1054
1066
  }
1067
+ function ActivityLog({ activity }) {
1068
+ const entries = (activity ?? []).slice().reverse();
1069
+ if (entries.length === 0) {
1070
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "fai-share__empty", children: "Connected. Nothing yet \u2014 actions appear here as the agent takes them." });
1071
+ }
1072
+ return /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "fai-share__activity", "aria-live": "polite", children: entries.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "fai-share__activity-row", "data-kind": entry.kind, children: [
1073
+ /* @__PURE__ */ jsxRuntime.jsx("time", { className: "fai-share__activity-time", dateTime: new Date(entry.at).toISOString(), children: new Date(entry.at).toLocaleTimeString(void 0, {
1074
+ hour: "2-digit",
1075
+ minute: "2-digit",
1076
+ second: "2-digit"
1077
+ }) }),
1078
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "fai-share__activity-source", children: entry.source }),
1079
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "fai-share__activity-text", children: entry.text })
1080
+ ] }, entry.id)) });
1081
+ }
1055
1082
  function TabButton({ tab, active, setTab, children }) {
1056
1083
  return /* @__PURE__ */ jsxRuntime.jsx(
1057
1084
  "button",