@agent-native/core 0.30.6 → 0.31.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 (255) hide show
  1. package/dist/a2a/client.d.ts +2 -0
  2. package/dist/a2a/client.d.ts.map +1 -1
  3. package/dist/a2a/client.js +6 -4
  4. package/dist/a2a/client.js.map +1 -1
  5. package/dist/a2a/handlers.d.ts.map +1 -1
  6. package/dist/a2a/handlers.js +3 -0
  7. package/dist/a2a/handlers.js.map +1 -1
  8. package/dist/a2a/server.d.ts.map +1 -1
  9. package/dist/a2a/server.js.map +1 -1
  10. package/dist/a2a/task-store.js.map +1 -1
  11. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  12. package/dist/agent/engine/anthropic-engine.js +0 -7
  13. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  14. package/dist/agent/engine/registry.d.ts.map +1 -1
  15. package/dist/agent/engine/registry.js.map +1 -1
  16. package/dist/agent/engine/translate-ai-sdk.d.ts.map +1 -1
  17. package/dist/agent/engine/translate-ai-sdk.js +5 -3
  18. package/dist/agent/engine/translate-ai-sdk.js.map +1 -1
  19. package/dist/agent/production-agent.js +7 -3
  20. package/dist/agent/production-agent.js.map +1 -1
  21. package/dist/agent/run-manager.d.ts.map +1 -1
  22. package/dist/agent/run-manager.js +14 -6
  23. package/dist/agent/run-manager.js.map +1 -1
  24. package/dist/application-state/store.d.ts.map +1 -1
  25. package/dist/application-state/store.js.map +1 -1
  26. package/dist/brand-kit/brand-signals.d.ts +31 -0
  27. package/dist/brand-kit/brand-signals.d.ts.map +1 -0
  28. package/dist/brand-kit/brand-signals.js +101 -0
  29. package/dist/brand-kit/brand-signals.js.map +1 -0
  30. package/dist/brand-kit/index.d.ts +21 -0
  31. package/dist/brand-kit/index.d.ts.map +1 -0
  32. package/dist/brand-kit/index.js +34 -0
  33. package/dist/brand-kit/index.js.map +1 -0
  34. package/dist/brand-kit/types.d.ts +103 -0
  35. package/dist/brand-kit/types.d.ts.map +1 -0
  36. package/dist/brand-kit/types.js +17 -0
  37. package/dist/brand-kit/types.js.map +1 -0
  38. package/dist/cli/code-agent-executor.d.ts.map +1 -1
  39. package/dist/cli/code-agent-executor.js.map +1 -1
  40. package/dist/cli/create.d.ts.map +1 -1
  41. package/dist/cli/create.js +0 -1
  42. package/dist/cli/create.js.map +1 -1
  43. package/dist/client/AgentNative.js.map +1 -1
  44. package/dist/client/AgentPanel.d.ts.map +1 -1
  45. package/dist/client/AgentPanel.js +0 -2
  46. package/dist/client/AgentPanel.js.map +1 -1
  47. package/dist/client/AssistantChat.d.ts.map +1 -1
  48. package/dist/client/AssistantChat.js +69 -17
  49. package/dist/client/AssistantChat.js.map +1 -1
  50. package/dist/client/IframeEmbed.d.ts.map +1 -1
  51. package/dist/client/IframeEmbed.js.map +1 -1
  52. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  53. package/dist/client/MultiTabAssistantChat.js +1 -1
  54. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  55. package/dist/client/RunStuckBanner.js.map +1 -1
  56. package/dist/client/agent-chat.d.ts.map +1 -1
  57. package/dist/client/agent-chat.js.map +1 -1
  58. package/dist/client/builder-mark.d.ts.map +1 -1
  59. package/dist/client/builder-mark.js.map +1 -1
  60. package/dist/client/components/MissingKeyCard.d.ts.map +1 -1
  61. package/dist/client/components/MissingKeyCard.js.map +1 -1
  62. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  63. package/dist/client/composer/PromptComposer.js +6 -3
  64. package/dist/client/composer/PromptComposer.js.map +1 -1
  65. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  66. package/dist/client/composer/TiptapComposer.js +5 -0
  67. package/dist/client/composer/TiptapComposer.js.map +1 -1
  68. package/dist/client/composer/VoiceButton.d.ts.map +1 -1
  69. package/dist/client/composer/VoiceButton.js +9 -0
  70. package/dist/client/composer/VoiceButton.js.map +1 -1
  71. package/dist/client/composer/extensions/FileReference.d.ts.map +1 -1
  72. package/dist/client/composer/extensions/FileReference.js.map +1 -1
  73. package/dist/client/composer/extensions/MentionReference.d.ts.map +1 -1
  74. package/dist/client/composer/extensions/MentionReference.js.map +1 -1
  75. package/dist/client/composer/extensions/SkillReference.d.ts.map +1 -1
  76. package/dist/client/composer/extensions/SkillReference.js.map +1 -1
  77. package/dist/client/conversation/AgentConversation.js +8 -6
  78. package/dist/client/conversation/AgentConversation.js.map +1 -1
  79. package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -1
  80. package/dist/client/conversation/use-near-bottom-autoscroll.js +133 -35
  81. package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -1
  82. package/dist/client/db-admin/DbAdminPage.js.map +1 -1
  83. package/dist/client/dev-overlay/DevOverlay.d.ts.map +1 -1
  84. package/dist/client/dev-overlay/DevOverlay.js +0 -1
  85. package/dist/client/dev-overlay/DevOverlay.js.map +1 -1
  86. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  87. package/dist/client/extensions/EmbeddedExtension.js +19 -0
  88. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  89. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  90. package/dist/client/extensions/ExtensionViewer.js +11 -3
  91. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  92. package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
  93. package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
  94. package/dist/client/mcp-app-host.d.ts.map +1 -1
  95. package/dist/client/mcp-app-host.js +6 -1
  96. package/dist/client/mcp-app-host.js.map +1 -1
  97. package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  98. package/dist/client/mcp-apps/McpAppRenderer.js +1 -1
  99. package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
  100. package/dist/client/notifications/NotificationsBell.js.map +1 -1
  101. package/dist/client/onboarding/SetupButton.d.ts.map +1 -1
  102. package/dist/client/onboarding/SetupButton.js +6 -0
  103. package/dist/client/onboarding/SetupButton.js.map +1 -1
  104. package/dist/client/progress/RunsTray.js.map +1 -1
  105. package/dist/client/resources/McpServerDetail.d.ts.map +1 -1
  106. package/dist/client/resources/McpServerDetail.js.map +1 -1
  107. package/dist/client/settings/AgentsSection.d.ts.map +1 -1
  108. package/dist/client/settings/AgentsSection.js +1 -1
  109. package/dist/client/settings/AgentsSection.js.map +1 -1
  110. package/dist/client/settings/AutomationsSection.js.map +1 -1
  111. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  112. package/dist/client/sharing/ShareButton.js +0 -4
  113. package/dist/client/sharing/ShareButton.js.map +1 -1
  114. package/dist/client/terminal/AgentTerminal.d.ts.map +1 -1
  115. package/dist/client/terminal/AgentTerminal.js +1 -1
  116. package/dist/client/terminal/AgentTerminal.js.map +1 -1
  117. package/dist/client/use-agent-chat.d.ts.map +1 -1
  118. package/dist/client/use-agent-chat.js +20 -4
  119. package/dist/client/use-agent-chat.js.map +1 -1
  120. package/dist/client/use-chat-threads.d.ts.map +1 -1
  121. package/dist/client/use-chat-threads.js +39 -25
  122. package/dist/client/use-chat-threads.js.map +1 -1
  123. package/dist/client/use-db-sync.d.ts.map +1 -1
  124. package/dist/client/use-db-sync.js +8 -0
  125. package/dist/client/use-db-sync.js.map +1 -1
  126. package/dist/client/use-dev-mode.d.ts.map +1 -1
  127. package/dist/client/use-dev-mode.js +25 -9
  128. package/dist/client/use-dev-mode.js.map +1 -1
  129. package/dist/client/useProductionAgent.d.ts.map +1 -1
  130. package/dist/client/useProductionAgent.js +6 -2
  131. package/dist/client/useProductionAgent.js.map +1 -1
  132. package/dist/collab/agent-presence.d.ts.map +1 -1
  133. package/dist/collab/agent-presence.js +1 -1
  134. package/dist/collab/agent-presence.js.map +1 -1
  135. package/dist/collab/awareness.d.ts.map +1 -1
  136. package/dist/collab/awareness.js +8 -0
  137. package/dist/collab/awareness.js.map +1 -1
  138. package/dist/collab/client-struct.js.map +1 -1
  139. package/dist/deploy/build.js +0 -5
  140. package/dist/deploy/build.js.map +1 -1
  141. package/dist/extensions/fetch-tool.d.ts.map +1 -1
  142. package/dist/extensions/fetch-tool.js +4 -1
  143. package/dist/extensions/fetch-tool.js.map +1 -1
  144. package/dist/file-upload/actions/upload-image.d.ts.map +1 -1
  145. package/dist/file-upload/actions/upload-image.js +39 -4
  146. package/dist/file-upload/actions/upload-image.js.map +1 -1
  147. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  148. package/dist/integrations/adapters/slack.js.map +1 -1
  149. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  150. package/dist/integrations/google-docs-poller.js +14 -1
  151. package/dist/integrations/google-docs-poller.js.map +1 -1
  152. package/dist/integrations/plugin.d.ts.map +1 -1
  153. package/dist/integrations/plugin.js.map +1 -1
  154. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  155. package/dist/integrations/webhook-handler.js +10 -1
  156. package/dist/integrations/webhook-handler.js.map +1 -1
  157. package/dist/jobs/scheduler.d.ts.map +1 -1
  158. package/dist/jobs/scheduler.js.map +1 -1
  159. package/dist/mcp/build-server.d.ts.map +1 -1
  160. package/dist/mcp/build-server.js +20 -8
  161. package/dist/mcp/build-server.js.map +1 -1
  162. package/dist/mcp/connect-store.d.ts.map +1 -1
  163. package/dist/mcp/connect-store.js +1 -1
  164. package/dist/mcp/connect-store.js.map +1 -1
  165. package/dist/notifications/channels.d.ts.map +1 -1
  166. package/dist/notifications/channels.js +3 -2
  167. package/dist/notifications/channels.js.map +1 -1
  168. package/dist/oauth-tokens/store.js.map +1 -1
  169. package/dist/observability/evals.d.ts.map +1 -1
  170. package/dist/observability/evals.js +7 -7
  171. package/dist/observability/evals.js.map +1 -1
  172. package/dist/observability/traces.d.ts.map +1 -1
  173. package/dist/observability/traces.js +15 -5
  174. package/dist/observability/traces.js.map +1 -1
  175. package/dist/org/handlers.d.ts.map +1 -1
  176. package/dist/org/handlers.js +3 -2
  177. package/dist/org/handlers.js.map +1 -1
  178. package/dist/resources/handlers.d.ts +5 -5
  179. package/dist/resources/handlers.d.ts.map +1 -1
  180. package/dist/resources/handlers.js.map +1 -1
  181. package/dist/scripts/db/schema.js.map +1 -1
  182. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  183. package/dist/server/agent-chat-plugin.js +0 -6
  184. package/dist/server/agent-chat-plugin.js.map +1 -1
  185. package/dist/server/auth.d.ts.map +1 -1
  186. package/dist/server/auth.js.map +1 -1
  187. package/dist/server/better-auth-instance.d.ts.map +1 -1
  188. package/dist/server/better-auth-instance.js +0 -3
  189. package/dist/server/better-auth-instance.js.map +1 -1
  190. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  191. package/dist/server/core-routes-plugin.js +1 -2
  192. package/dist/server/core-routes-plugin.js.map +1 -1
  193. package/dist/server/create-server.d.ts.map +1 -1
  194. package/dist/server/create-server.js +0 -23
  195. package/dist/server/create-server.js.map +1 -1
  196. package/dist/server/google-oauth.d.ts.map +1 -1
  197. package/dist/server/google-oauth.js +0 -3
  198. package/dist/server/google-oauth.js.map +1 -1
  199. package/dist/server/poll.d.ts.map +1 -1
  200. package/dist/server/poll.js +49 -18
  201. package/dist/server/poll.js.map +1 -1
  202. package/dist/settings/store.js.map +1 -1
  203. package/dist/sharing/access.d.ts.map +1 -1
  204. package/dist/sharing/access.js +25 -4
  205. package/dist/sharing/access.js.map +1 -1
  206. package/dist/triggers/dispatcher.d.ts.map +1 -1
  207. package/dist/triggers/dispatcher.js.map +1 -1
  208. package/dist/vite/client.d.ts.map +1 -1
  209. package/dist/vite/client.js +2 -0
  210. package/dist/vite/client.js.map +1 -1
  211. package/package.json +3 -2
  212. package/dist/client/conversation/AgentConversation.spec.d.ts +0 -2
  213. package/dist/client/conversation/AgentConversation.spec.d.ts.map +0 -1
  214. package/dist/client/conversation/AgentConversation.spec.js +0 -69
  215. package/dist/client/conversation/AgentConversation.spec.js.map +0 -1
  216. package/dist/client/extensions/AgentNativeExtensionFrame.e2e-host.d.ts +0 -2
  217. package/dist/client/extensions/AgentNativeExtensionFrame.e2e-host.d.ts.map +0 -1
  218. package/dist/client/extensions/AgentNativeExtensionFrame.e2e-host.js +0 -110
  219. package/dist/client/extensions/AgentNativeExtensionFrame.e2e-host.js.map +0 -1
  220. package/dist/client/extensions/AgentNativeExtensionFrame.spec.d.ts +0 -2
  221. package/dist/client/extensions/AgentNativeExtensionFrame.spec.d.ts.map +0 -1
  222. package/dist/client/extensions/AgentNativeExtensionFrame.spec.js +0 -68
  223. package/dist/client/extensions/AgentNativeExtensionFrame.spec.js.map +0 -1
  224. package/dist/client/extensions/ExtensionViewer.spec.d.ts +0 -2
  225. package/dist/client/extensions/ExtensionViewer.spec.d.ts.map +0 -1
  226. package/dist/client/extensions/ExtensionViewer.spec.js +0 -94
  227. package/dist/client/extensions/ExtensionViewer.spec.js.map +0 -1
  228. package/dist/client/guided-questions.flow.spec.d.ts +0 -2
  229. package/dist/client/guided-questions.flow.spec.d.ts.map +0 -1
  230. package/dist/client/guided-questions.flow.spec.js +0 -147
  231. package/dist/client/guided-questions.flow.spec.js.map +0 -1
  232. package/dist/client/settings/useBuilderStatus.spec.d.ts +0 -2
  233. package/dist/client/settings/useBuilderStatus.spec.d.ts.map +0 -1
  234. package/dist/client/settings/useBuilderStatus.spec.js +0 -487
  235. package/dist/client/settings/useBuilderStatus.spec.js.map +0 -1
  236. package/dist/client/sharing/ShareButton.spec.d.ts +0 -2
  237. package/dist/client/sharing/ShareButton.spec.d.ts.map +0 -1
  238. package/dist/client/sharing/ShareButton.spec.js +0 -196
  239. package/dist/client/sharing/ShareButton.spec.js.map +0 -1
  240. package/dist/client/use-chat-models.spec.d.ts +0 -2
  241. package/dist/client/use-chat-models.spec.d.ts.map +0 -1
  242. package/dist/client/use-chat-models.spec.js +0 -39
  243. package/dist/client/use-chat-models.spec.js.map +0 -1
  244. package/dist/client/use-chat-threads.spec.d.ts +0 -2
  245. package/dist/client/use-chat-threads.spec.d.ts.map +0 -1
  246. package/dist/client/use-chat-threads.spec.js +0 -760
  247. package/dist/client/use-chat-threads.spec.js.map +0 -1
  248. package/dist/client/use-db-sync.spec.d.ts +0 -2
  249. package/dist/client/use-db-sync.spec.d.ts.map +0 -1
  250. package/dist/client/use-db-sync.spec.js +0 -107
  251. package/dist/client/use-db-sync.spec.js.map +0 -1
  252. package/dist/server/script-discovery.d.ts +0 -6
  253. package/dist/server/script-discovery.d.ts.map +0 -1
  254. package/dist/server/script-discovery.js +0 -6
  255. package/dist/server/script-discovery.js.map +0 -1
@@ -1,110 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { createRoot } from "react-dom/client";
3
- import { defineClientAction } from "../client-action.js";
4
- import { AgentNativeExtensionSlot } from "./AgentNativeExtensionFrame.js";
5
- const extensionContent = `
6
- <div id="status">pending</div>
7
- <pre id="results"></pre>
8
- <script>
9
- (async function() {
10
- const result = {};
11
- async function capture(name, fn) {
12
- try {
13
- result[name] = { ok: true, value: await fn() };
14
- } catch (error) {
15
- result[name] = {
16
- ok: false,
17
- error: error && error.message ? error.message : String(error),
18
- };
19
- }
20
- }
21
-
22
- await capture('context', () => agentNative.context());
23
- await capture('actions', () => agentNative.listActions());
24
- await capture('allowedAction', () => appAction('allowed-action', { value: 3 }));
25
- await capture('blockedAction', () => appAction('blocked-action', {}));
26
- await capture('allowedCommand', () =>
27
- agentNative.command('refreshData', { customerId: slotContext.customerId })
28
- );
29
- await capture('blockedCommand', () => agentNative.command('hardReload', {}));
30
- await capture('storageSet', () =>
31
- extensionData.set('notes', 'note-1', { text: 'Saved note' }, { scope: 'user' })
32
- );
33
- await capture('storageGet', () =>
34
- extensionData.get('notes', 'note-1', { scope: 'user' })
35
- );
36
- await capture('blockedStorageScope', () =>
37
- extensionData.set('notes', 'note-2', { text: 'Org note' }, { scope: 'org' })
38
- );
39
-
40
- result.done = true;
41
- document.getElementById('status').textContent = 'done';
42
- document.getElementById('results').textContent = JSON.stringify(result);
43
- window.parent.postMessage({ type: 'extension-e2e.done', result }, '*');
44
- })();
45
- </script>
46
- `;
47
- const hostWindow = window;
48
- const extension = {
49
- id: "allowed-extension",
50
- name: "Allowed extension",
51
- content: extensionContent,
52
- manifest: {
53
- slots: ["crm.customer.sidebar"],
54
- requestedActions: ["allowed-action"],
55
- requestedCommands: ["refreshData"],
56
- storageScopes: ["user"],
57
- },
58
- };
59
- const wrongSlotExtension = {
60
- id: "wrong-slot-extension",
61
- name: "Wrong slot extension",
62
- content: "<div>should not render</div>",
63
- manifest: { slots: ["crm.billing.sidebar"] },
64
- };
65
- hostWindow.__extensionE2ECommands = [];
66
- window.addEventListener("message", (event) => {
67
- if (event.data?.type !== "extension-e2e.done")
68
- return;
69
- hostWindow.__extensionE2EResult = event.data.result;
70
- const results = document.getElementById("host-results");
71
- if (results)
72
- results.textContent = JSON.stringify(event.data.result);
73
- });
74
- const actions = [
75
- defineClientAction({
76
- name: "allowed-action",
77
- description: "Allowed test action",
78
- schema: {
79
- type: "object",
80
- properties: { value: { type: "number" } },
81
- required: ["value"],
82
- },
83
- run: async (args) => ({ doubled: args.value * 2 }),
84
- }),
85
- defineClientAction({
86
- name: "blocked-action",
87
- description: "Blocked test action",
88
- schema: { type: "object", properties: {} },
89
- run: async () => ({ shouldNotRun: true }),
90
- }),
91
- ];
92
- function Host() {
93
- return (_jsxs("main", { children: [_jsx("div", { id: "command-count", children: hostWindow.__extensionE2ECommands?.length }), _jsx("div", { id: "host-results" }), _jsx(AgentNativeExtensionSlot, { id: "crm.customer.sidebar", extensions: [extension, wrongSlotExtension], context: { customerId: "customer-1" }, actions: actions, getContext: () => ({
94
- resource: { type: "customer", id: "customer-1", name: "Ada Co" },
95
- }), commands: {
96
- refreshData: async ({ payload }) => {
97
- hostWindow.__extensionE2ECommands?.push({
98
- command: "refreshData",
99
- payload,
100
- });
101
- const count = document.getElementById("command-count");
102
- if (count) {
103
- count.textContent = String(hostWindow.__extensionE2ECommands?.length ?? 0);
104
- }
105
- return { refreshed: true, payload };
106
- },
107
- } })] }));
108
- }
109
- createRoot(document.getElementById("root")).render(_jsx(Host, {}));
110
- //# sourceMappingURL=AgentNativeExtensionFrame.e2e-host.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AgentNativeExtensionFrame.e2e-host.js","sourceRoot":"","sources":["../../../src/client/extensions/AgentNativeExtensionFrame.e2e-host.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { defineClientAction } from \"../client-action.js\";\nimport { AgentNativeExtensionSlot } from \"./AgentNativeExtensionFrame.js\";\n\nconst extensionContent = `\n<div id=\"status\">pending</div>\n<pre id=\"results\"></pre>\n<script>\n (async function() {\n const result = {};\n async function capture(name, fn) {\n try {\n result[name] = { ok: true, value: await fn() };\n } catch (error) {\n result[name] = {\n ok: false,\n error: error && error.message ? error.message : String(error),\n };\n }\n }\n\n await capture('context', () => agentNative.context());\n await capture('actions', () => agentNative.listActions());\n await capture('allowedAction', () => appAction('allowed-action', { value: 3 }));\n await capture('blockedAction', () => appAction('blocked-action', {}));\n await capture('allowedCommand', () =>\n agentNative.command('refreshData', { customerId: slotContext.customerId })\n );\n await capture('blockedCommand', () => agentNative.command('hardReload', {}));\n await capture('storageSet', () =>\n extensionData.set('notes', 'note-1', { text: 'Saved note' }, { scope: 'user' })\n );\n await capture('storageGet', () =>\n extensionData.get('notes', 'note-1', { scope: 'user' })\n );\n await capture('blockedStorageScope', () =>\n extensionData.set('notes', 'note-2', { text: 'Org note' }, { scope: 'org' })\n );\n\n result.done = true;\n document.getElementById('status').textContent = 'done';\n document.getElementById('results').textContent = JSON.stringify(result);\n window.parent.postMessage({ type: 'extension-e2e.done', result }, '*');\n })();\n</script>\n`;\n\ninterface ExtensionE2EWindow {\n __extensionE2EResult?: unknown;\n __extensionE2ECommands?: Array<{ command: string; payload: unknown }>;\n}\n\nconst hostWindow = window as Window & ExtensionE2EWindow;\n\nconst extension = {\n id: \"allowed-extension\",\n name: \"Allowed extension\",\n content: extensionContent,\n manifest: {\n slots: [\"crm.customer.sidebar\"],\n requestedActions: [\"allowed-action\"],\n requestedCommands: [\"refreshData\"],\n storageScopes: [\"user\"],\n },\n};\n\nconst wrongSlotExtension = {\n id: \"wrong-slot-extension\",\n name: \"Wrong slot extension\",\n content: \"<div>should not render</div>\",\n manifest: { slots: [\"crm.billing.sidebar\"] },\n};\n\nhostWindow.__extensionE2ECommands = [];\nwindow.addEventListener(\"message\", (event) => {\n if (event.data?.type !== \"extension-e2e.done\") return;\n hostWindow.__extensionE2EResult = event.data.result;\n const results = document.getElementById(\"host-results\");\n if (results) results.textContent = JSON.stringify(event.data.result);\n});\n\nconst actions = [\n defineClientAction<{ value: number }, { doubled: number }>({\n name: \"allowed-action\",\n description: \"Allowed test action\",\n schema: {\n type: \"object\",\n properties: { value: { type: \"number\" } },\n required: [\"value\"],\n },\n run: async (args) => ({ doubled: args.value * 2 }),\n }),\n defineClientAction<Record<string, never>, { shouldNotRun: true }>({\n name: \"blocked-action\",\n description: \"Blocked test action\",\n schema: { type: \"object\", properties: {} },\n run: async () => ({ shouldNotRun: true }),\n }),\n];\n\nfunction Host() {\n return (\n <main>\n <div id=\"command-count\">{hostWindow.__extensionE2ECommands?.length}</div>\n <div id=\"host-results\"></div>\n <AgentNativeExtensionSlot\n id=\"crm.customer.sidebar\"\n extensions={[extension, wrongSlotExtension]}\n context={{ customerId: \"customer-1\" }}\n actions={actions}\n getContext={() => ({\n resource: { type: \"customer\", id: \"customer-1\", name: \"Ada Co\" },\n })}\n commands={{\n refreshData: async ({ payload }) => {\n hostWindow.__extensionE2ECommands?.push({\n command: \"refreshData\",\n payload,\n });\n const count = document.getElementById(\"command-count\");\n if (count) {\n count.textContent = String(\n hostWindow.__extensionE2ECommands?.length ?? 0,\n );\n }\n return { refreshed: true, payload };\n },\n }}\n />\n </main>\n );\n}\n\ncreateRoot(document.getElementById(\"root\") as HTMLElement).render(<Host />);\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=AgentNativeExtensionFrame.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AgentNativeExtensionFrame.spec.d.ts","sourceRoot":"","sources":["../../../src/client/extensions/AgentNativeExtensionFrame.spec.tsx"],"names":[],"mappings":""}
@@ -1,68 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- // @vitest-environment happy-dom
3
- import { act } from "react";
4
- import { createRoot } from "react-dom/client";
5
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
- import { AgentNativeExtensionFrame, AgentNativeExtensionSlot, } from "./AgentNativeExtensionFrame.js";
7
- describe("AgentNativeExtensionFrame", () => {
8
- let container;
9
- let root;
10
- beforeEach(() => {
11
- vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
12
- container = document.createElement("div");
13
- root = createRoot(container);
14
- });
15
- afterEach(() => {
16
- act(() => root.unmount());
17
- container.remove();
18
- vi.unstubAllGlobals();
19
- });
20
- it("renders extension content into a sandboxed srcdoc iframe", async () => {
21
- await act(async () => {
22
- root.render(_jsx(AgentNativeExtensionFrame, { extension: {
23
- id: "ext-1",
24
- name: "Customer panel",
25
- content: "<section>Customer health</section>",
26
- }, sandbox: "allow-scripts allow-same-origin allow-popups" }));
27
- });
28
- const iframe = container.querySelector("iframe");
29
- expect(iframe).toBeTruthy();
30
- expect(iframe?.getAttribute("sandbox")).toBe("allow-scripts allow-popups");
31
- expect(iframe?.getAttribute("srcdoc")).toContain("<section>Customer health</section>");
32
- });
33
- it("renders one iframe per extension in a portable slot", async () => {
34
- await act(async () => {
35
- root.render(_jsx(AgentNativeExtensionSlot, { id: "crm.sidebar", extensions: [
36
- { id: "ext-1", name: "One", content: "<p>One</p>" },
37
- { id: "ext-2", name: "Two", content: "<p>Two</p>" },
38
- ], context: { customerId: "cus_123" } }));
39
- });
40
- const frames = Array.from(container.querySelectorAll("iframe"));
41
- expect(frames).toHaveLength(2);
42
- expect(frames[0].getAttribute("srcdoc")).toContain("cus_123");
43
- expect(frames[1].getAttribute("srcdoc")).toContain("<p>Two</p>");
44
- });
45
- it("does not render extensions into slots outside their manifest", async () => {
46
- await act(async () => {
47
- root.render(_jsx(AgentNativeExtensionSlot, { id: "crm.sidebar", extensions: [
48
- {
49
- id: "ext-1",
50
- name: "Allowed",
51
- content: "<p>Allowed</p>",
52
- manifest: { slots: ["crm.sidebar"] },
53
- },
54
- {
55
- id: "ext-2",
56
- name: "Blocked",
57
- content: "<p>Blocked</p>",
58
- manifest: { slots: ["billing.sidebar"] },
59
- },
60
- ] }));
61
- });
62
- const frames = Array.from(container.querySelectorAll("iframe"));
63
- expect(frames).toHaveLength(1);
64
- expect(frames[0].getAttribute("srcdoc")).toContain("<p>Allowed</p>");
65
- expect(frames[0].getAttribute("srcdoc")).not.toContain("<p>Blocked</p>");
66
- });
67
- });
68
- //# sourceMappingURL=AgentNativeExtensionFrame.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AgentNativeExtensionFrame.spec.js","sourceRoot":"","sources":["../../../src/client/extensions/AgentNativeExtensionFrame.spec.tsx"],"names":[],"mappings":";AAAA,gCAAgC;AAChC,OAAc,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,UAAU,EAAa,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EACL,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,gCAAgC,CAAC;AAExC,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,IAAI,SAAyB,CAAC;IAC9B,IAAI,IAAU,CAAC;IAEf,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,UAAU,CAAC,0BAA0B,EAAE,IAAI,CAAC,CAAC;QAChD,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1B,SAAS,CAAC,MAAM,EAAE,CAAC;QACnB,EAAE,CAAC,gBAAgB,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,IAAI,CAAC,MAAM,CACT,KAAC,yBAAyB,IACxB,SAAS,EAAE;oBACT,EAAE,EAAE,OAAO;oBACX,IAAI,EAAE,gBAAgB;oBACtB,OAAO,EAAE,oCAAoC;iBAC9C,EACD,OAAO,EAAC,8CAA8C,GACtD,CACH,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,CAAC;QAC5B,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC3E,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAC9C,oCAAoC,CACrC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,IAAI,CAAC,MAAM,CACT,KAAC,wBAAwB,IACvB,EAAE,EAAC,aAAa,EAChB,UAAU,EAAE;oBACV,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE;oBACnD,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE;iBACpD,EACD,OAAO,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,GAClC,CACH,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,IAAI,CAAC,MAAM,CACT,KAAC,wBAAwB,IACvB,EAAE,EAAC,aAAa,EAChB,UAAU,EAAE;oBACV;wBACE,EAAE,EAAE,OAAO;wBACX,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,gBAAgB;wBACzB,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,aAAa,CAAC,EAAE;qBACrC;oBACD;wBACE,EAAE,EAAE,OAAO;wBACX,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,gBAAgB;wBACzB,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,iBAAiB,CAAC,EAAE;qBACzC;iBACF,GACD,CACH,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QACrE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["// @vitest-environment happy-dom\nimport React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n AgentNativeExtensionFrame,\n AgentNativeExtensionSlot,\n} from \"./AgentNativeExtensionFrame.js\";\n\ndescribe(\"AgentNativeExtensionFrame\", () => {\n let container: HTMLDivElement;\n let root: Root;\n\n beforeEach(() => {\n vi.stubGlobal(\"IS_REACT_ACT_ENVIRONMENT\", true);\n container = document.createElement(\"div\");\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.unstubAllGlobals();\n });\n\n it(\"renders extension content into a sandboxed srcdoc iframe\", async () => {\n await act(async () => {\n root.render(\n <AgentNativeExtensionFrame\n extension={{\n id: \"ext-1\",\n name: \"Customer panel\",\n content: \"<section>Customer health</section>\",\n }}\n sandbox=\"allow-scripts allow-same-origin allow-popups\"\n />,\n );\n });\n\n const iframe = container.querySelector(\"iframe\");\n expect(iframe).toBeTruthy();\n expect(iframe?.getAttribute(\"sandbox\")).toBe(\"allow-scripts allow-popups\");\n expect(iframe?.getAttribute(\"srcdoc\")).toContain(\n \"<section>Customer health</section>\",\n );\n });\n\n it(\"renders one iframe per extension in a portable slot\", async () => {\n await act(async () => {\n root.render(\n <AgentNativeExtensionSlot\n id=\"crm.sidebar\"\n extensions={[\n { id: \"ext-1\", name: \"One\", content: \"<p>One</p>\" },\n { id: \"ext-2\", name: \"Two\", content: \"<p>Two</p>\" },\n ]}\n context={{ customerId: \"cus_123\" }}\n />,\n );\n });\n\n const frames = Array.from(container.querySelectorAll(\"iframe\"));\n expect(frames).toHaveLength(2);\n expect(frames[0].getAttribute(\"srcdoc\")).toContain(\"cus_123\");\n expect(frames[1].getAttribute(\"srcdoc\")).toContain(\"<p>Two</p>\");\n });\n\n it(\"does not render extensions into slots outside their manifest\", async () => {\n await act(async () => {\n root.render(\n <AgentNativeExtensionSlot\n id=\"crm.sidebar\"\n extensions={[\n {\n id: \"ext-1\",\n name: \"Allowed\",\n content: \"<p>Allowed</p>\",\n manifest: { slots: [\"crm.sidebar\"] },\n },\n {\n id: \"ext-2\",\n name: \"Blocked\",\n content: \"<p>Blocked</p>\",\n manifest: { slots: [\"billing.sidebar\"] },\n },\n ]}\n />,\n );\n });\n\n const frames = Array.from(container.querySelectorAll(\"iframe\"));\n expect(frames).toHaveLength(1);\n expect(frames[0].getAttribute(\"srcdoc\")).toContain(\"<p>Allowed</p>\");\n expect(frames[0].getAttribute(\"srcdoc\")).not.toContain(\"<p>Blocked</p>\");\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=ExtensionViewer.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ExtensionViewer.spec.d.ts","sourceRoot":"","sources":["../../../src/client/extensions/ExtensionViewer.spec.tsx"],"names":[],"mappings":""}
@@ -1,94 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- // @vitest-environment happy-dom
3
- import { act } from "react";
4
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
5
- import { createRoot } from "react-dom/client";
6
- import { MemoryRouter } from "react-router";
7
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
8
- import { ExtensionViewer } from "./ExtensionViewer.js";
9
- const embedState = vi.hoisted(() => ({ active: false }));
10
- vi.mock("../embed-auth.js", () => ({
11
- ensureEmbedAuthFetchInterceptor: vi.fn(),
12
- isEmbedMcpChatBridgeActive: () => embedState.active,
13
- }));
14
- vi.mock("../sharing/ShareButton.js", () => ({
15
- ShareButton: () => _jsx("button", { type: "button", children: "Share" }),
16
- }));
17
- vi.mock("../AgentPanel.js", () => ({
18
- AgentToggleButton: () => _jsx("button", { type: "button", children: "Agent" }),
19
- }));
20
- vi.mock("../notifications/NotificationsBell.js", () => ({
21
- NotificationsBell: () => _jsx("button", { type: "button", children: "Notifications" }),
22
- }));
23
- vi.mock("../composer/PromptComposer.js", () => ({
24
- PromptComposer: () => _jsx("div", {}),
25
- }));
26
- vi.mock("../components/ui/popover.js", () => ({
27
- Popover: ({ children }) => (_jsx("div", { children: children })),
28
- PopoverContent: ({ children }) => (_jsx("div", { children: children })),
29
- PopoverTrigger: ({ children }) => (_jsx(_Fragment, { children: children })),
30
- }));
31
- vi.mock("../components/ui/tooltip.js", () => ({
32
- Tooltip: ({ children }) => _jsx(_Fragment, { children: children }),
33
- TooltipContent: ({ children }) => (_jsx("div", { children: children })),
34
- TooltipProvider: ({ children }) => (_jsx(_Fragment, { children: children })),
35
- TooltipTrigger: ({ children }) => (_jsx(_Fragment, { children: children })),
36
- }));
37
- const extensionResponse = {
38
- id: "ext-1",
39
- name: "GitHub Stars Over Time",
40
- description: "Tracks stars",
41
- content: "<section>Star history chart</section>",
42
- updatedAt: "2026-05-22T00:00:00.000Z",
43
- ownerEmail: "owner@example.test",
44
- role: "owner",
45
- canDelete: true,
46
- };
47
- describe("ExtensionViewer MCP embeds", () => {
48
- let container;
49
- let root;
50
- let queryClient;
51
- beforeEach(() => {
52
- vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
53
- vi.stubGlobal("fetch", vi.fn(async () => Response.json(extensionResponse)));
54
- embedState.active = false;
55
- queryClient = new QueryClient({
56
- defaultOptions: {
57
- queries: { retry: false },
58
- mutations: { retry: false },
59
- },
60
- });
61
- container = document.createElement("div");
62
- root = createRoot(container);
63
- });
64
- afterEach(() => {
65
- act(() => root.unmount());
66
- queryClient.clear();
67
- container.remove();
68
- vi.unstubAllGlobals();
69
- });
70
- async function renderViewer() {
71
- await act(async () => {
72
- root.render(_jsx(QueryClientProvider, { client: queryClient, children: _jsx(MemoryRouter, { initialEntries: ["/extensions/ext-1/github-stars"], children: _jsx(ExtensionViewer, { extensionId: "ext-1" }) }) }));
73
- });
74
- await vi.waitFor(() => {
75
- expect(container.querySelector("iframe")).toBeTruthy();
76
- });
77
- return container.querySelector("iframe");
78
- }
79
- it("uses the extension render route in the normal app", async () => {
80
- const iframe = await renderViewer();
81
- expect(iframe.getAttribute("src")).toContain("/_agent-native/extensions/ext-1/render");
82
- expect(iframe.getAttribute("srcdoc")).toBeNull();
83
- expect(iframe.getAttribute("sandbox")).toBe("allow-scripts allow-forms");
84
- });
85
- it("uses sandboxed srcdoc inside MCP chat embeds to avoid a blocked nested route frame", async () => {
86
- embedState.active = true;
87
- const iframe = await renderViewer();
88
- expect(iframe.getAttribute("src")).toBeNull();
89
- expect(iframe.getAttribute("srcdoc")).toContain("Star history chart");
90
- expect(iframe.getAttribute("srcdoc")).toContain("agent-native-extension-binding");
91
- expect(iframe.getAttribute("sandbox")).toBe("allow-scripts allow-forms");
92
- });
93
- });
94
- //# sourceMappingURL=ExtensionViewer.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ExtensionViewer.spec.js","sourceRoot":"","sources":["../../../src/client/extensions/ExtensionViewer.spec.tsx"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment happy-dom\nimport React, { act } from \"react\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { MemoryRouter } from \"react-router\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { ExtensionViewer } from \"./ExtensionViewer.js\";\n\nconst embedState = vi.hoisted(() => ({ active: false }));\n\nvi.mock(\"../embed-auth.js\", () => ({\n ensureEmbedAuthFetchInterceptor: vi.fn(),\n isEmbedMcpChatBridgeActive: () => embedState.active,\n}));\n\nvi.mock(\"../sharing/ShareButton.js\", () => ({\n ShareButton: () => <button type=\"button\">Share</button>,\n}));\n\nvi.mock(\"../AgentPanel.js\", () => ({\n AgentToggleButton: () => <button type=\"button\">Agent</button>,\n}));\n\nvi.mock(\"../notifications/NotificationsBell.js\", () => ({\n NotificationsBell: () => <button type=\"button\">Notifications</button>,\n}));\n\nvi.mock(\"../composer/PromptComposer.js\", () => ({\n PromptComposer: () => <div />,\n}));\n\nvi.mock(\"../components/ui/popover.js\", () => ({\n Popover: ({ children }: { children: React.ReactNode }) => (\n <div>{children}</div>\n ),\n PopoverContent: ({ children }: { children: React.ReactNode }) => (\n <div>{children}</div>\n ),\n PopoverTrigger: ({ children }: { children: React.ReactNode }) => (\n <>{children}</>\n ),\n}));\n\nvi.mock(\"../components/ui/tooltip.js\", () => ({\n Tooltip: ({ children }: { children: React.ReactNode }) => <>{children}</>,\n TooltipContent: ({ children }: { children: React.ReactNode }) => (\n <div>{children}</div>\n ),\n TooltipProvider: ({ children }: { children: React.ReactNode }) => (\n <>{children}</>\n ),\n TooltipTrigger: ({ children }: { children: React.ReactNode }) => (\n <>{children}</>\n ),\n}));\n\nconst extensionResponse = {\n id: \"ext-1\",\n name: \"GitHub Stars Over Time\",\n description: \"Tracks stars\",\n content: \"<section>Star history chart</section>\",\n updatedAt: \"2026-05-22T00:00:00.000Z\",\n ownerEmail: \"owner@example.test\",\n role: \"owner\",\n canDelete: true,\n};\n\ndescribe(\"ExtensionViewer MCP embeds\", () => {\n let container: HTMLDivElement;\n let root: Root;\n let queryClient: QueryClient;\n\n beforeEach(() => {\n vi.stubGlobal(\"IS_REACT_ACT_ENVIRONMENT\", true);\n vi.stubGlobal(\n \"fetch\",\n vi.fn(async () => Response.json(extensionResponse)),\n );\n embedState.active = false;\n queryClient = new QueryClient({\n defaultOptions: {\n queries: { retry: false },\n mutations: { retry: false },\n },\n });\n container = document.createElement(\"div\");\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n queryClient.clear();\n container.remove();\n vi.unstubAllGlobals();\n });\n\n async function renderViewer() {\n await act(async () => {\n root.render(\n <QueryClientProvider client={queryClient}>\n <MemoryRouter initialEntries={[\"/extensions/ext-1/github-stars\"]}>\n <ExtensionViewer extensionId=\"ext-1\" />\n </MemoryRouter>\n </QueryClientProvider>,\n );\n });\n await vi.waitFor(() => {\n expect(container.querySelector(\"iframe\")).toBeTruthy();\n });\n return container.querySelector(\"iframe\") as HTMLIFrameElement;\n }\n\n it(\"uses the extension render route in the normal app\", async () => {\n const iframe = await renderViewer();\n\n expect(iframe.getAttribute(\"src\")).toContain(\n \"/_agent-native/extensions/ext-1/render\",\n );\n expect(iframe.getAttribute(\"srcdoc\")).toBeNull();\n expect(iframe.getAttribute(\"sandbox\")).toBe(\"allow-scripts allow-forms\");\n });\n\n it(\"uses sandboxed srcdoc inside MCP chat embeds to avoid a blocked nested route frame\", async () => {\n embedState.active = true;\n const iframe = await renderViewer();\n\n expect(iframe.getAttribute(\"src\")).toBeNull();\n expect(iframe.getAttribute(\"srcdoc\")).toContain(\"Star history chart\");\n expect(iframe.getAttribute(\"srcdoc\")).toContain(\n \"agent-native-extension-binding\",\n );\n expect(iframe.getAttribute(\"sandbox\")).toBe(\"allow-scripts allow-forms\");\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=guided-questions.flow.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"guided-questions.flow.spec.d.ts","sourceRoot":"","sources":["../../src/client/guided-questions.flow.spec.tsx"],"names":[],"mappings":""}
@@ -1,147 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- // @vitest-environment happy-dom
3
- import { act } from "react";
4
- import { createRoot } from "react-dom/client";
5
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
6
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
7
- import { useGuidedQuestionFlow } from "./guided-questions.js";
8
- // The agent's `ask-question` action writes the guided-questions payload to a
9
- // per-tab application-state key (`guided-questions:<tabId>`) whenever the run
10
- // carries a browser tab id, which it almost always does. The client hook must
11
- // therefore read the scoped key first (falling back to the bare key) and clear
12
- // whichever key actually held the payload. These tests lock that contract so
13
- // the clarifying-question card cannot silently stop rendering again.
14
- vi.mock("./agent-chat.js", () => ({
15
- sendToAgentChat: vi.fn(),
16
- }));
17
- const STATE_PREFIX = "/_agent-native/application-state/";
18
- function keyFromUrl(url) {
19
- const idx = url.indexOf(STATE_PREFIX);
20
- return idx >= 0 ? url.slice(idx + STATE_PREFIX.length) : url;
21
- }
22
- const payload = {
23
- questions: [
24
- {
25
- id: "q1",
26
- type: "text-options",
27
- question: "Which range?",
28
- options: [{ label: "7d", value: "7d" }],
29
- },
30
- ],
31
- };
32
- describe("useGuidedQuestionFlow scoped reads", () => {
33
- let container;
34
- let root;
35
- beforeEach(() => {
36
- vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
37
- container = document.createElement("div");
38
- document.body.appendChild(container);
39
- root = createRoot(container);
40
- });
41
- afterEach(() => {
42
- act(() => {
43
- root.unmount();
44
- });
45
- container.remove();
46
- vi.unstubAllGlobals();
47
- vi.restoreAllMocks();
48
- });
49
- async function flush() {
50
- await act(async () => {
51
- await Promise.resolve();
52
- await new Promise((resolve) => setTimeout(resolve, 0));
53
- await Promise.resolve();
54
- });
55
- }
56
- async function renderFlow(options) {
57
- const client = new QueryClient({
58
- defaultOptions: { queries: { retry: false } },
59
- });
60
- let latest = null;
61
- function Harness() {
62
- latest = useGuidedQuestionFlow(options);
63
- return null;
64
- }
65
- await act(async () => {
66
- root.render(_jsx(QueryClientProvider, { client: client, children: _jsx(Harness, {}) }));
67
- });
68
- // The query resolves asynchronously and then `setPayload` triggers a
69
- // re-render; pump microtasks/timers until the hook reports its questions.
70
- for (let i = 0; i < 20 && !latest?.questions; i += 1) {
71
- await flush();
72
- }
73
- return { current: () => latest };
74
- }
75
- it("reads the tab-scoped key first when a browserTabId is provided", async () => {
76
- const seen = [];
77
- vi.stubGlobal("fetch", vi.fn(async (input) => {
78
- const key = keyFromUrl(String(input));
79
- seen.push(key);
80
- // Only the scoped key holds the payload; the bare key is empty.
81
- if (key === "guided-questions:tab123") {
82
- return new Response(JSON.stringify(payload), { status: 200 });
83
- }
84
- return new Response("", { status: 200 });
85
- }));
86
- const result = await renderFlow({
87
- stateKey: "guided-questions",
88
- queryKey: ["guided-questions"],
89
- browserTabId: "tab123",
90
- refetchInterval: false,
91
- });
92
- expect(result.current().questions?.length).toBe(1);
93
- expect(seen).toContain("guided-questions:tab123");
94
- });
95
- it("reads the bare key (no `:undefined` suffix) when no tab id is provided", async () => {
96
- const seen = [];
97
- const fetchMock = vi.fn(async (input) => {
98
- const key = keyFromUrl(String(input));
99
- seen.push(key);
100
- if (key === "guided-questions") {
101
- return new Response(JSON.stringify(payload), { status: 200 });
102
- }
103
- return new Response("", { status: 200 });
104
- });
105
- vi.stubGlobal("fetch", fetchMock);
106
- const result = await renderFlow({
107
- stateKey: "guided-questions",
108
- queryKey: ["guided-questions"],
109
- refetchInterval: false,
110
- });
111
- // The question renders from the bare key, and the hook must never probe a
112
- // malformed `guided-questions:undefined` key when there is no tab id.
113
- expect(result.current().questions?.length).toBe(1);
114
- expect(fetchMock).toHaveBeenCalled();
115
- const requestedKeys = fetchMock.mock.calls.map((call) => keyFromUrl(String(call[0])));
116
- expect(requestedKeys).toContain("guided-questions");
117
- expect(requestedKeys).not.toContain("guided-questions:undefined");
118
- });
119
- it("DELETEs the scoped key on clear so the card does not reappear", async () => {
120
- const deleted = [];
121
- vi.stubGlobal("fetch", vi.fn(async (input, init) => {
122
- const key = keyFromUrl(String(input));
123
- if (init?.method === "DELETE") {
124
- deleted.push(key);
125
- return new Response("", { status: 200 });
126
- }
127
- if (key === "guided-questions:tab123") {
128
- return new Response(JSON.stringify(payload), { status: 200 });
129
- }
130
- return new Response("", { status: 200 });
131
- }));
132
- const result = await renderFlow({
133
- stateKey: "guided-questions",
134
- queryKey: ["guided-questions"],
135
- browserTabId: "tab123",
136
- refetchInterval: false,
137
- });
138
- expect(result.current().questions?.length).toBe(1);
139
- await act(async () => {
140
- result.current().clear();
141
- await Promise.resolve();
142
- });
143
- await flush();
144
- expect(deleted).toContain("guided-questions:tab123");
145
- });
146
- });
147
- //# sourceMappingURL=guided-questions.flow.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"guided-questions.flow.spec.js","sourceRoot":"","sources":["../../src/client/guided-questions.flow.spec.tsx"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment happy-dom\n\nimport React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { useGuidedQuestionFlow } from \"./guided-questions.js\";\n\n// The agent's `ask-question` action writes the guided-questions payload to a\n// per-tab application-state key (`guided-questions:<tabId>`) whenever the run\n// carries a browser tab id, which it almost always does. The client hook must\n// therefore read the scoped key first (falling back to the bare key) and clear\n// whichever key actually held the payload. These tests lock that contract so\n// the clarifying-question card cannot silently stop rendering again.\n\nvi.mock(\"./agent-chat.js\", () => ({\n sendToAgentChat: vi.fn(),\n}));\n\nconst STATE_PREFIX = \"/_agent-native/application-state/\";\n\nfunction keyFromUrl(url: string): string {\n const idx = url.indexOf(STATE_PREFIX);\n return idx >= 0 ? url.slice(idx + STATE_PREFIX.length) : url;\n}\n\nconst payload = {\n questions: [\n {\n id: \"q1\",\n type: \"text-options\" as const,\n question: \"Which range?\",\n options: [{ label: \"7d\", value: \"7d\" }],\n },\n ],\n};\n\ntype HookResult = ReturnType<typeof useGuidedQuestionFlow>;\n\ndescribe(\"useGuidedQuestionFlow scoped reads\", () => {\n let container: HTMLDivElement;\n let root: Root;\n\n beforeEach(() => {\n vi.stubGlobal(\"IS_REACT_ACT_ENVIRONMENT\", true);\n container = document.createElement(\"div\");\n document.body.appendChild(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => {\n root.unmount();\n });\n container.remove();\n vi.unstubAllGlobals();\n vi.restoreAllMocks();\n });\n\n async function flush() {\n await act(async () => {\n await Promise.resolve();\n await new Promise((resolve) => setTimeout(resolve, 0));\n await Promise.resolve();\n });\n }\n\n async function renderFlow(\n options: Parameters<typeof useGuidedQuestionFlow>[0],\n ): Promise<{ current: () => HookResult }> {\n const client = new QueryClient({\n defaultOptions: { queries: { retry: false } },\n });\n let latest: HookResult | null = null;\n function Harness() {\n latest = useGuidedQuestionFlow(options);\n return null;\n }\n await act(async () => {\n root.render(\n <QueryClientProvider client={client}>\n <Harness />\n </QueryClientProvider>,\n );\n });\n // The query resolves asynchronously and then `setPayload` triggers a\n // re-render; pump microtasks/timers until the hook reports its questions.\n for (let i = 0; i < 20 && !latest?.questions; i += 1) {\n await flush();\n }\n return { current: () => latest as HookResult };\n }\n\n it(\"reads the tab-scoped key first when a browserTabId is provided\", async () => {\n const seen: string[] = [];\n vi.stubGlobal(\n \"fetch\",\n vi.fn(async (input: RequestInfo | URL) => {\n const key = keyFromUrl(String(input));\n seen.push(key);\n // Only the scoped key holds the payload; the bare key is empty.\n if (key === \"guided-questions:tab123\") {\n return new Response(JSON.stringify(payload), { status: 200 });\n }\n return new Response(\"\", { status: 200 });\n }),\n );\n\n const result = await renderFlow({\n stateKey: \"guided-questions\",\n queryKey: [\"guided-questions\"],\n browserTabId: \"tab123\",\n refetchInterval: false,\n });\n\n expect(result.current().questions?.length).toBe(1);\n expect(seen).toContain(\"guided-questions:tab123\");\n });\n\n it(\"reads the bare key (no `:undefined` suffix) when no tab id is provided\", async () => {\n const seen: string[] = [];\n const fetchMock = vi.fn(async (input: RequestInfo | URL) => {\n const key = keyFromUrl(String(input));\n seen.push(key);\n if (key === \"guided-questions\") {\n return new Response(JSON.stringify(payload), { status: 200 });\n }\n return new Response(\"\", { status: 200 });\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n const result = await renderFlow({\n stateKey: \"guided-questions\",\n queryKey: [\"guided-questions\"],\n refetchInterval: false,\n });\n\n // The question renders from the bare key, and the hook must never probe a\n // malformed `guided-questions:undefined` key when there is no tab id.\n expect(result.current().questions?.length).toBe(1);\n expect(fetchMock).toHaveBeenCalled();\n const requestedKeys = fetchMock.mock.calls.map((call) =>\n keyFromUrl(String(call[0])),\n );\n expect(requestedKeys).toContain(\"guided-questions\");\n expect(requestedKeys).not.toContain(\"guided-questions:undefined\");\n });\n\n it(\"DELETEs the scoped key on clear so the card does not reappear\", async () => {\n const deleted: string[] = [];\n vi.stubGlobal(\n \"fetch\",\n vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {\n const key = keyFromUrl(String(input));\n if (init?.method === \"DELETE\") {\n deleted.push(key);\n return new Response(\"\", { status: 200 });\n }\n if (key === \"guided-questions:tab123\") {\n return new Response(JSON.stringify(payload), { status: 200 });\n }\n return new Response(\"\", { status: 200 });\n }),\n );\n\n const result = await renderFlow({\n stateKey: \"guided-questions\",\n queryKey: [\"guided-questions\"],\n browserTabId: \"tab123\",\n refetchInterval: false,\n });\n\n expect(result.current().questions?.length).toBe(1);\n\n await act(async () => {\n result.current().clear();\n await Promise.resolve();\n });\n await flush();\n\n expect(deleted).toContain(\"guided-questions:tab123\");\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=useBuilderStatus.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useBuilderStatus.spec.d.ts","sourceRoot":"","sources":["../../../src/client/settings/useBuilderStatus.spec.tsx"],"names":[],"mappings":""}