@agent-native/core 0.7.18 → 0.7.20
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.
- package/README.md +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +60 -5
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/loop-settings.d.ts +37 -0
- package/dist/agent/loop-settings.d.ts.map +1 -0
- package/dist/agent/loop-settings.js +127 -0
- package/dist/agent/loop-settings.js.map +1 -0
- package/dist/agent/production-agent.d.ts +8 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +268 -29
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +76 -3
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +1 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +65 -2
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +3 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +52 -10
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/agent/tool-search.d.ts +37 -0
- package/dist/agent/tool-search.d.ts.map +1 -0
- package/dist/agent/tool-search.js +201 -0
- package/dist/agent/tool-search.js.map +1 -0
- package/dist/agent/types.d.ts +8 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +57 -11
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/workspacify.d.ts +2 -0
- package/dist/cli/workspacify.d.ts.map +1 -1
- package/dist/cli/workspacify.js +34 -1
- package/dist/cli/workspacify.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +303 -14
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
- package/dist/client/ConnectBuilderCard.js +1 -1
- package/dist/client/ConnectBuilderCard.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +16 -24
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.d.ts +14 -0
- package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -0
- package/dist/client/NewWorkspaceAppFlow.js +200 -0
- package/dist/client/NewWorkspaceAppFlow.js.map +1 -0
- package/dist/client/PoweredByBadge.d.ts +10 -1
- package/dist/client/PoweredByBadge.d.ts.map +1 -1
- package/dist/client/PoweredByBadge.js +120 -8
- package/dist/client/PoweredByBadge.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts +8 -0
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +32 -5
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +15 -3
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/analytics.d.ts +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +141 -1
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/builder-frame.d.ts +10 -0
- package/dist/client/builder-frame.d.ts.map +1 -0
- package/dist/client/builder-frame.js +94 -0
- package/dist/client/builder-frame.js.map +1 -0
- package/dist/client/composer/MentionPopover.d.ts.map +1 -1
- package/dist/client/composer/MentionPopover.js +5 -1
- package/dist/client/composer/MentionPopover.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +11 -6
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/error-format.d.ts +20 -1
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +53 -5
- package/dist/client/error-format.js.map +1 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.js +88 -6
- package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +14 -2
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +145 -9
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +13 -0
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +50 -9
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +9 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +95 -8
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/tools/ToolsListPage.d.ts.map +1 -1
- package/dist/client/tools/ToolsListPage.js +16 -1
- package/dist/client/tools/ToolsListPage.js.map +1 -1
- package/dist/client/tools/ToolsSidebarSection.d.ts.map +1 -1
- package/dist/client/tools/ToolsSidebarSection.js +63 -8
- package/dist/client/tools/ToolsSidebarSection.js.map +1 -1
- package/dist/client/tools/tool-order.d.ts +7 -0
- package/dist/client/tools/tool-order.d.ts.map +1 -0
- package/dist/client/tools/tool-order.js +47 -0
- package/dist/client/tools/tool-order.js.map +1 -0
- package/dist/client/transcription/BuilderTranscriptionCta.d.ts.map +1 -1
- package/dist/client/transcription/BuilderTranscriptionCta.js +71 -6
- package/dist/client/transcription/BuilderTranscriptionCta.js.map +1 -1
- package/dist/client/use-send-to-agent-chat.d.ts.map +1 -1
- package/dist/client/use-send-to-agent-chat.js +11 -3
- package/dist/client/use-send-to-agent-chat.js.map +1 -1
- package/dist/client/useProductionAgent.d.ts.map +1 -1
- package/dist/client/useProductionAgent.js +1 -1
- package/dist/client/useProductionAgent.js.map +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +5 -1
- package/dist/db/client.js.map +1 -1
- package/dist/deploy/build.d.ts +1 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +4 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-retry-job.js +1 -1
- package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
- package/dist/oauth-tokens/index.d.ts +1 -1
- package/dist/oauth-tokens/index.d.ts.map +1 -1
- package/dist/oauth-tokens/index.js +1 -1
- package/dist/oauth-tokens/index.js.map +1 -1
- package/dist/oauth-tokens/store.d.ts.map +1 -1
- package/dist/oauth-tokens/store.js +6 -0
- package/dist/oauth-tokens/store.js.map +1 -1
- package/dist/observability/store.d.ts.map +1 -1
- package/dist/observability/store.js +19 -19
- package/dist/observability/store.js.map +1 -1
- package/dist/onboarding/default-steps.d.ts.map +1 -1
- package/dist/onboarding/default-steps.js +95 -61
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/onboarding/plugin.d.ts.map +1 -1
- package/dist/onboarding/plugin.js +17 -8
- package/dist/onboarding/plugin.js.map +1 -1
- package/dist/org/migrations.js +2 -2
- package/dist/org/migrations.js.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +2 -3
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/scripts/db/exec.d.ts +2 -1
- package/dist/scripts/db/exec.d.ts.map +1 -1
- package/dist/scripts/db/exec.js +264 -61
- package/dist/scripts/db/exec.js.map +1 -1
- package/dist/scripts/db/schema.d.ts.map +1 -1
- package/dist/scripts/db/schema.js +16 -4
- package/dist/scripts/db/schema.js.map +1 -1
- package/dist/scripts/dev/index.d.ts.map +1 -1
- package/dist/scripts/dev/index.js +36 -11
- package/dist/scripts/dev/index.js.map +1 -1
- package/dist/scripts/manage-agent-loop-settings.d.ts +7 -0
- package/dist/scripts/manage-agent-loop-settings.d.ts.map +1 -0
- package/dist/scripts/manage-agent-loop-settings.js +63 -0
- package/dist/scripts/manage-agent-loop-settings.js.map +1 -0
- package/dist/scripts/runner.d.ts.map +1 -1
- package/dist/scripts/runner.js +11 -0
- package/dist/scripts/runner.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +60 -18
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/app-url.d.ts +5 -4
- package/dist/server/app-url.d.ts.map +1 -1
- package/dist/server/app-url.js +8 -4
- package/dist/server/app-url.js.map +1 -1
- package/dist/server/auth.d.ts +37 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +114 -35
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +15 -0
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +131 -5
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/builder-browser.d.ts +12 -0
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +36 -4
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +350 -53
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +21 -3
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +51 -21
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/google-oauth.d.ts +3 -0
- package/dist/server/google-oauth.d.ts.map +1 -1
- package/dist/server/google-oauth.js +35 -18
- package/dist/server/google-oauth.js.map +1 -1
- package/dist/server/index.d.ts +4 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4 -3
- package/dist/server/index.js.map +1 -1
- package/dist/server/schema-prompt.d.ts.map +1 -1
- package/dist/server/schema-prompt.js +2 -1
- package/dist/server/schema-prompt.js.map +1 -1
- package/dist/server/security-headers.d.ts +3 -0
- package/dist/server/security-headers.d.ts.map +1 -1
- package/dist/server/security-headers.js +7 -1
- package/dist/server/security-headers.js.map +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +24 -4
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/server/voice-providers-status.d.ts +7 -0
- package/dist/server/voice-providers-status.d.ts.map +1 -1
- package/dist/server/voice-providers-status.js +1 -0
- package/dist/server/voice-providers-status.js.map +1 -1
- package/dist/templates/default/_gitignore +5 -1
- package/dist/templates/default/app/root.tsx +1 -0
- package/dist/templates/default/public/favicon.svg +3 -3
- package/dist/templates/default/public/icon-180.svg +3 -3
- package/dist/templates/default/public/icon-192.svg +3 -3
- package/dist/templates/default/public/icon-512.svg +3 -3
- package/dist/templates/workspace-core/AGENTS.md +23 -7
- package/dist/templates/workspace-core/package.json +2 -1
- package/dist/templates/workspace-core/src/credentials.ts +22 -11
- package/dist/templates/workspace-root/.env.example +7 -0
- package/dist/templates/workspace-root/README.md +6 -3
- package/dist/templates/workspace-root/_gitignore +3 -0
- package/dist/templates/workspace-root/package.json +3 -1
- package/dist/templates/workspace-root/scripts/workspace-dev.ts +410 -0
- package/dist/tools/actions.d.ts.map +1 -1
- package/dist/tools/actions.js +2 -0
- package/dist/tools/actions.js.map +1 -1
- package/dist/tools/html-shell.d.ts.map +1 -1
- package/dist/tools/html-shell.js +13 -1
- package/dist/tools/html-shell.js.map +1 -1
- package/dist/tools/store.d.ts.map +1 -1
- package/dist/tools/store.js +16 -11
- package/dist/tools/store.js.map +1 -1
- package/dist/tracking/providers.d.ts +1 -0
- package/dist/tracking/providers.d.ts.map +1 -1
- package/dist/tracking/providers.js +72 -0
- package/dist/tracking/providers.js.map +1 -1
- package/dist/vite/action-types-plugin.d.ts.map +1 -1
- package/dist/vite/action-types-plugin.js +106 -9
- package/dist/vite/action-types-plugin.js.map +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +67 -2
- package/dist/vite/client.js.map +1 -1
- package/docs/content/authentication.md +17 -13
- package/docs/content/deployment.md +11 -11
- package/docs/content/mcp-clients.md +2 -2
- package/docs/content/onboarding.md +32 -30
- package/docs/content/security.md +1 -1
- package/docs/content/tools.md +4 -0
- package/package.json +2 -2
- package/src/templates/default/_gitignore +5 -1
- package/src/templates/default/app/root.tsx +1 -0
- package/src/templates/default/public/favicon.svg +3 -3
- package/src/templates/default/public/icon-180.svg +3 -3
- package/src/templates/default/public/icon-192.svg +3 -3
- package/src/templates/default/public/icon-512.svg +3 -3
- package/src/templates/workspace-core/AGENTS.md +23 -7
- package/src/templates/workspace-core/package.json +2 -1
- package/src/templates/workspace-core/src/credentials.ts +22 -11
- package/src/templates/workspace-root/.env.example +7 -0
- package/src/templates/workspace-root/README.md +6 -3
- package/src/templates/workspace-root/_gitignore +3 -0
- package/src/templates/workspace-root/package.json +3 -1
- package/src/templates/workspace-root/scripts/workspace-dev.ts +410 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/tools/actions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ActionEntry } from \"../agent/production-agent.js\";\nimport { createTool, getTool, updateTool, updateToolContent } from \"./store.js\";\nimport {\n addToolSlotTarget,\n installToolSlot,\n uninstallToolSlot,\n listToolsForSlot,\n listSlotsForTool,\n} from \"./slots/store.js\";\n\ntype ToolPatch = { find: string; replace: string };\n\nexport function createToolActionEntries(): Record<string, ActionEntry> {\n return {\n \"create-tool\": {\n tool: {\n description:\n \"Create a sandboxed Alpine.js mini-app tool. Use this when the user asks to create, build, or make a tool/widget/dashboard/calculator. The content must be a self-contained Alpine.js HTML body snippet that can use appAction(), appFetch(), dbQuery(), dbExec(), toolFetch(), and toolData.\",\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n 'Short display name for the tool. Do not include \"app\" — e.g. name a todo app \"Todos\", a weather app \"Weather\".',\n },\n description: {\n type: \"string\",\n description: \"One-sentence summary of what the tool does.\",\n },\n content: {\n type: \"string\",\n description:\n \"Self-contained Alpine.js HTML body snippet. The iframe body has no padding, so add p-4 or p-6 to the outermost element. Use semantic Tailwind colors (bg-background, text-foreground, bg-primary, etc.) for native theming. Do not include a full app build, React code, or source files.\",\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n },\n required: [\"name\", \"content\"],\n },\n },\n run: async (args) => {\n const name = String(args?.name ?? \"\").trim();\n const content = String(args?.content ?? \"\").trim();\n if (!name) return \"Error: name is required.\";\n if (!content) return \"Error: content is required.\";\n\n const tool = await createTool({\n name,\n description: String(args?.description ?? \"\").trim(),\n content,\n icon: args?.icon ? String(args.icon) : undefined,\n });\n\n return {\n ok: true,\n tool,\n next: `Navigate to /tools/${tool.id} or use the navigate action with --view=tools --toolId=${tool.id}.`,\n };\n },\n },\n\n \"update-tool\": {\n tool: {\n description:\n \"Update an existing sandboxed Alpine.js mini-app tool. Prefer patches for surgical edits; use full content replacement only when necessary.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description: \"Tool id to update.\",\n },\n name: {\n type: \"string\",\n description: \"Optional new display name.\",\n },\n description: {\n type: \"string\",\n description: \"Optional new description.\",\n },\n content: {\n type: \"string\",\n description:\n \"Optional full replacement Alpine.js HTML body snippet.\",\n },\n patches: {\n type: \"string\",\n description:\n 'Optional JSON array of { \"find\": \"...\", \"replace\": \"...\" } patches to apply to the current content.',\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n visibility: {\n type: \"string\",\n description: \"Optional sharing visibility.\",\n enum: [\"private\", \"org\", \"public\"],\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n\n let result = null;\n if (args?.content !== undefined || args?.patches !== undefined) {\n const patches = parsePatches((args as any).patches);\n if (args?.patches !== undefined && !patches) {\n return \"Error: patches must be a JSON array of { find, replace } objects.\";\n }\n result = await updateToolContent(id, {\n content:\n args?.content !== undefined ? String(args.content) : undefined,\n patches,\n });\n }\n\n const meta: Record<string, string> = {};\n if (args?.name !== undefined) meta.name = String(args.name).trim();\n if (args?.description !== undefined) {\n meta.description = String(args.description).trim();\n }\n if (args?.icon !== undefined) meta.icon = String(args.icon);\n if (args?.visibility !== undefined) {\n meta.visibility = String(args.visibility);\n }\n if (Object.keys(meta).length > 0) {\n result = await updateTool(id, meta as any);\n }\n\n if (!result) result = await getTool(id);\n if (!result) return `Error: tool not found: ${id}`;\n return { ok: true, tool: result };\n },\n },\n\n \"add-tool-slot-target\": {\n tool: {\n description:\n 'Declare that a tool can render in a UI extension-point slot of an app (e.g. \"mail.contact-sidebar.bottom\"). Apps drop ExtensionSlot components in their UI; this action registers a tool as installable into one of those slots. Slot IDs follow the convention <app>.<area>.<position>. Caller must have editor access to the tool.',\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with slot-specific config (defaults, hints, etc.).\",\n },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const row = await addToolSlotTarget(\n toolId,\n slotId,\n args?.config ? String(args.config) : undefined,\n );\n return { ok: true, slot: row };\n },\n },\n\n \"install-extension\": {\n tool: {\n description:\n \"Install a tool as a widget in an extension-point slot for the current user. The tool must already declare the slot via add-tool-slot-target. Per-user installation — only affects the calling user's view. Use after creating a tool that targets a slot, or when the user asks to add an existing widget to a slot.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id to install.\" },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n position: {\n type: \"number\",\n description:\n \"Optional integer position within the slot (lower = earlier). Defaults to end.\",\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with per-install config (overrides, settings).\",\n },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const position =\n args?.position !== undefined && args.position !== null\n ? Number(args.position)\n : undefined;\n const row = await installToolSlot(toolId, slotId, {\n position: Number.isFinite(position as number) ? position : undefined,\n config: args?.config ? String(args.config) : undefined,\n });\n return { ok: true, install: row };\n },\n },\n\n \"uninstall-extension\": {\n tool: {\n description:\n \"Remove a tool from an extension-point slot for the current user. Does not delete the tool itself.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n await uninstallToolSlot(toolId, slotId);\n return { ok: true };\n },\n },\n\n \"list-tools-for-slot\": {\n tool: {\n description:\n \"List tools the current user has access to that declare a given extension-point slot. Use to discover what's available to install into a slot the user mentioned.\",\n parameters: {\n type: \"object\",\n properties: {\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"slotId\"],\n },\n },\n run: async (args) => {\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!slotId) return \"Error: slotId is required.\";\n return { tools: await listToolsForSlot(slotId) };\n },\n },\n\n \"list-tool-slots\": {\n tool: {\n description:\n \"List the extension-point slots a specific tool declares it can render in. Caller must have viewer access to the tool.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n },\n required: [\"toolId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n return { slots: await listSlotsForTool(toolId) };\n },\n },\n };\n}\n\nfunction parsePatches(value: unknown): ToolPatch[] | undefined {\n if (value === undefined) return undefined;\n const parsed = typeof value === \"string\" ? JSON.parse(value) : value;\n if (!Array.isArray(parsed)) return undefined;\n if (\n parsed.some(\n (patch) =>\n !patch ||\n typeof patch.find !== \"string\" ||\n typeof patch.replace !== \"string\",\n )\n ) {\n return undefined;\n }\n return parsed;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/tools/actions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ActionEntry } from \"../agent/production-agent.js\";\nimport { createTool, getTool, updateTool, updateToolContent } from \"./store.js\";\nimport {\n addToolSlotTarget,\n installToolSlot,\n uninstallToolSlot,\n listToolsForSlot,\n listSlotsForTool,\n} from \"./slots/store.js\";\n\ntype ToolPatch = { find: string; replace: string };\n\nexport function createToolActionEntries(): Record<string, ActionEntry> {\n return {\n \"create-tool\": {\n tool: {\n description:\n \"Create a sandboxed Alpine.js mini-app tool. Use this when the user asks to create, build, or make a tool/widget/dashboard/calculator. The content must be a self-contained Alpine.js HTML body snippet that can use appAction(), appFetch(), dbQuery(), dbExec(), toolFetch(), and toolData.\",\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n 'Short display name for the tool. Do not include \"app\" — e.g. name a todo app \"Todos\", a weather app \"Weather\".',\n },\n description: {\n type: \"string\",\n description: \"One-sentence summary of what the tool does.\",\n },\n content: {\n type: \"string\",\n description:\n \"Self-contained Alpine.js HTML body snippet. The iframe body has no padding, so add p-4 or p-6 to the outermost element. Use semantic Tailwind colors (bg-background, text-foreground, bg-primary, etc.) for native theming. Do not include a full app build, React code, or source files.\",\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n },\n required: [\"name\", \"content\"],\n },\n },\n run: async (args) => {\n const name = String(args?.name ?? \"\").trim();\n const content = String(args?.content ?? \"\").trim();\n if (!name) return \"Error: name is required.\";\n if (!content) return \"Error: content is required.\";\n\n const tool = await createTool({\n name,\n description: String(args?.description ?? \"\").trim(),\n content,\n icon: args?.icon ? String(args.icon) : undefined,\n });\n\n return {\n ok: true,\n tool,\n next: `Navigate to /tools/${tool.id} or use the navigate action with --view=tools --toolId=${tool.id}.`,\n };\n },\n },\n\n \"update-tool\": {\n tool: {\n description:\n \"Update an existing sandboxed Alpine.js mini-app tool. Prefer patches for surgical edits; use full content replacement only when necessary.\",\n parameters: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description: \"Tool id to update.\",\n },\n name: {\n type: \"string\",\n description: \"Optional new display name.\",\n },\n description: {\n type: \"string\",\n description: \"Optional new description.\",\n },\n content: {\n type: \"string\",\n description:\n \"Optional full replacement Alpine.js HTML body snippet.\",\n },\n patches: {\n type: \"string\",\n description:\n 'Optional JSON array of { \"find\": \"...\", \"replace\": \"...\" } patches to apply to the current content.',\n },\n icon: {\n type: \"string\",\n description: \"Optional icon name or short label.\",\n },\n visibility: {\n type: \"string\",\n description: \"Optional sharing visibility.\",\n enum: [\"private\", \"org\", \"public\"],\n },\n },\n required: [\"id\"],\n },\n },\n run: async (args) => {\n const id = String(args?.id ?? \"\").trim();\n if (!id) return \"Error: id is required.\";\n\n let result = null;\n if (args?.content !== undefined || args?.patches !== undefined) {\n const patches = parsePatches((args as any).patches);\n if (args?.patches !== undefined && !patches) {\n return \"Error: patches must be a JSON array of { find, replace } objects.\";\n }\n result = await updateToolContent(id, {\n content:\n args?.content !== undefined ? String(args.content) : undefined,\n patches,\n });\n }\n\n const meta: Record<string, string> = {};\n if (args?.name !== undefined) meta.name = String(args.name).trim();\n if (args?.description !== undefined) {\n meta.description = String(args.description).trim();\n }\n if (args?.icon !== undefined) meta.icon = String(args.icon);\n if (args?.visibility !== undefined) {\n meta.visibility = String(args.visibility);\n }\n if (Object.keys(meta).length > 0) {\n result = await updateTool(id, meta as any);\n }\n\n if (!result) result = await getTool(id);\n if (!result) return `Error: tool not found: ${id}`;\n return { ok: true, tool: result };\n },\n },\n\n \"add-tool-slot-target\": {\n tool: {\n description:\n 'Declare that a tool can render in a UI extension-point slot of an app (e.g. \"mail.contact-sidebar.bottom\"). Apps drop ExtensionSlot components in their UI; this action registers a tool as installable into one of those slots. Slot IDs follow the convention <app>.<area>.<position>. Caller must have editor access to the tool.',\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with slot-specific config (defaults, hints, etc.).\",\n },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const row = await addToolSlotTarget(\n toolId,\n slotId,\n args?.config ? String(args.config) : undefined,\n );\n return { ok: true, slot: row };\n },\n },\n\n \"install-extension\": {\n tool: {\n description:\n \"Install a tool as a widget in an extension-point slot for the current user. The tool must already declare the slot via add-tool-slot-target. Per-user installation — only affects the calling user's view. Use after creating a tool that targets a slot, or when the user asks to add an existing widget to a slot.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id to install.\" },\n slotId: {\n type: \"string\",\n description:\n 'Slot identifier — e.g. \"mail.contact-sidebar.bottom\".',\n },\n position: {\n type: \"number\",\n description:\n \"Optional integer position within the slot (lower = earlier). Defaults to end.\",\n },\n config: {\n type: \"string\",\n description:\n \"Optional JSON string with per-install config (overrides, settings).\",\n },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n const position =\n args?.position !== undefined && args.position !== null\n ? Number(args.position)\n : undefined;\n const row = await installToolSlot(toolId, slotId, {\n position: Number.isFinite(position as number) ? position : undefined,\n config: args?.config ? String(args.config) : undefined,\n });\n return { ok: true, install: row };\n },\n },\n\n \"uninstall-extension\": {\n tool: {\n description:\n \"Remove a tool from an extension-point slot for the current user. Does not delete the tool itself.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"toolId\", \"slotId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n if (!slotId) return \"Error: slotId is required.\";\n await uninstallToolSlot(toolId, slotId);\n return { ok: true };\n },\n },\n\n \"list-tools-for-slot\": {\n tool: {\n description:\n \"List tools the current user has access to that declare a given extension-point slot. Use to discover what's available to install into a slot the user mentioned.\",\n parameters: {\n type: \"object\",\n properties: {\n slotId: { type: \"string\", description: \"Slot identifier.\" },\n },\n required: [\"slotId\"],\n },\n },\n run: async (args) => {\n const slotId = String(args?.slotId ?? \"\").trim();\n if (!slotId) return \"Error: slotId is required.\";\n return { tools: await listToolsForSlot(slotId) };\n },\n readOnly: true,\n },\n\n \"list-tool-slots\": {\n tool: {\n description:\n \"List the extension-point slots a specific tool declares it can render in. Caller must have viewer access to the tool.\",\n parameters: {\n type: \"object\",\n properties: {\n toolId: { type: \"string\", description: \"Tool id.\" },\n },\n required: [\"toolId\"],\n },\n },\n run: async (args) => {\n const toolId = String(args?.toolId ?? \"\").trim();\n if (!toolId) return \"Error: toolId is required.\";\n return { slots: await listSlotsForTool(toolId) };\n },\n readOnly: true,\n },\n };\n}\n\nfunction parsePatches(value: unknown): ToolPatch[] | undefined {\n if (value === undefined) return undefined;\n const parsed = typeof value === \"string\" ? JSON.parse(value) : value;\n if (!Array.isArray(parsed)) return undefined;\n if (\n parsed.some(\n (patch) =>\n !patch ||\n typeof patch.find !== \"string\" ||\n typeof patch.replace !== \"string\",\n )\n ) {\n return undefined;\n }\n return parsed;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-shell.d.ts","sourceRoot":"","sources":["../../src/tools/html-shell.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,8YACiX,CAAC;AAE9Y,eAAO,MAAM,oBAAoB,QAGhC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;;;;OASG;IACH,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;CAC/C;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,EACf,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,iBAAiB,GAC1B,MAAM,
|
|
1
|
+
{"version":3,"file":"html-shell.d.ts","sourceRoot":"","sources":["../../src/tools/html-shell.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,8YACiX,CAAC;AAE9Y,eAAO,MAAM,oBAAoB,QAGhC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;;;;OASG;IACH,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;CAC/C;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,EACf,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,iBAAiB,GAC1B,MAAM,CA0fR"}
|
package/dist/tools/html-shell.js
CHANGED
|
@@ -131,7 +131,19 @@ export function buildToolHtml(content, themeVars, isDark, toolId, binding) {
|
|
|
131
131
|
</style>
|
|
132
132
|
<style>
|
|
133
133
|
*, *::before, *::after { border-color: hsl(var(--border)); }
|
|
134
|
-
body {
|
|
134
|
+
body {
|
|
135
|
+
--agent-native-tool-padding: clamp(16px, 2vw, 24px);
|
|
136
|
+
box-sizing: border-box;
|
|
137
|
+
font-family: 'Inter', sans-serif;
|
|
138
|
+
margin: 0;
|
|
139
|
+
min-height: 100vh;
|
|
140
|
+
padding: var(--agent-native-tool-padding);
|
|
141
|
+
}
|
|
142
|
+
body:has(> [data-tool-layout="full-bleed"]),
|
|
143
|
+
body:has(> [data-tool-padding="none"]),
|
|
144
|
+
body:has(> .agent-native-tool-bleed) {
|
|
145
|
+
padding: 0;
|
|
146
|
+
}
|
|
135
147
|
</style>
|
|
136
148
|
<script>
|
|
137
149
|
var _toolRequestSeq = 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-shell.js","sourceRoot":"","sources":["../../src/tools/html-shell.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAC1B,2YAA2Y,CAAC;AAE9Y,MAAM,CAAC,MAAM,oBAAoB,GAAG,eAAe,CAAC,OAAO,CACzD,8BAA8B,EAC9B,EAAE,CACH,CAAC;AA6CF,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,SAAiB,EACjB,MAAe,EACf,MAAe,EACf,OAA2B;IAE3B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAChC,OAAO,IAAI;QACT,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,EAAE;QACf,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,OAAO;KACd,CACF,CAAC;IAEF,OAAO;iBACQ,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;;;;wDAIU,oBAAoB;IACxE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,kDAAkD,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA8E7H,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAgLA,UAAU;yBACL,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiN5B,MAAM,CAAC,CAAC,CAAC,kBAAkB,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE;GAClD,OAAO;;;;;;;;;;SAUD,CAAC;AACV,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC","sourcesContent":["export const TOOL_IFRAME_CSP =\n \"default-src 'none'; script-src 'self' https://cdn.jsdelivr.net 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; font-src https://fonts.gstatic.com; connect-src 'self'; img-src 'self' data: blob:; media-src 'self' data: blob:; frame-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'self';\";\n\nexport const TOOL_IFRAME_META_CSP = TOOL_IFRAME_CSP.replace(\n /\\s*frame-ancestors 'self';?$/,\n \"\",\n);\n\n/**\n * SECURITY — TOOL CONTENT IS UNTRUSTED.\n *\n * `${content}` (line ~Body) interpolates raw HTML/JS authored by a user. This\n * file is the boundary between framework-controlled HTML and user-controlled\n * HTML. Two non-negotiable invariants for every change here:\n *\n * 1. The iframe MUST be rendered with a `sandbox` attribute that does NOT\n * include `allow-same-origin`. The viewer (`ToolViewer.tsx`,\n * `EmbeddedTool.tsx`) sets `sandbox=\"allow-scripts allow-forms\"` — and\n * that is the only acceptable shape. Adding `allow-same-origin` would\n * give the tool full DOM access to the parent window via cross-frame\n * script.\n *\n * 2. Every reachable parent action must treat the postMessage payload as\n * hostile. The bridge in `iframe-bridge.ts` enforces a path allowlist,\n * header sanitization, and method allowlist; do not relax those gates\n * for \"convenience\" in this file or any caller.\n *\n * For the trust model rationale, see audit 05-tools-sandbox.md (C1) and the\n * `tools` skill. When in doubt, fail closed.\n */\n\nexport interface ToolRenderBinding {\n /** Email of the user who authored / owns the tool. */\n authorEmail: string;\n /** Email of the user currently viewing/running the tool. */\n viewerEmail: string;\n /** True when viewer === author. */\n isAuthor: boolean;\n /**\n * Resolved role for the viewer (\"owner\" | \"admin\" | \"editor\" | \"viewer\").\n *\n * TODO(security, audit H4): the host-side bridge does not yet gate any\n * helper based on this value — every viewer gets the same powers as the\n * author. The role is plumbed through so a follow-up PR can constrain\n * `appAction` / `dbExec` / `toolFetch` for non-author viewers (and\n * eventually require an explicit consent step before running a shared\n * tool, audit C1). For now this is metadata only.\n */\n role: \"owner\" | \"admin\" | \"editor\" | \"viewer\";\n}\n\nexport function buildToolHtml(\n content: string,\n themeVars: string,\n isDark: boolean,\n toolId?: string,\n binding?: ToolRenderBinding,\n): string {\n const toolIdJson = JSON.stringify(toolId ?? \"\");\n const toolIdAttr = escapeHtmlAttribute(toolId ?? \"\");\n const bindingJson = JSON.stringify(\n binding ?? {\n authorEmail: \"\",\n viewerEmail: \"\",\n isAuthor: true,\n role: \"owner\",\n },\n );\n\n return `<!DOCTYPE html>\n<html lang=\"en\"${isDark ? ' class=\"dark\"' : \"\"}>\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta http-equiv=\"Content-Security-Policy\" content=\"${TOOL_IFRAME_META_CSP}\" />\n ${binding && !binding.isAuthor ? `<meta name=\"agent-native-tool-author\" content=\"${escapeHtmlAttribute(binding.authorEmail)}\" />` : \"\"}\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300..700&display=swap\" rel=\"stylesheet\" />\n <script>\n var _toolErrors = [];\n var _toolErrorDetails = [];\n var _consoleLogs = [];\n var _networkLogs = [];\n\n var _origConsole = { log: console.log, warn: console.warn, error: console.error, info: console.info };\n function _wrapConsole(level, orig) {\n return function() {\n var args = Array.prototype.slice.call(arguments);\n var msg = args.map(function(a) {\n try { return typeof a === 'object' ? JSON.stringify(a) : String(a); }\n catch(e) { return String(a); }\n }).join(' ');\n if (_consoleLogs.length >= 50) _consoleLogs.shift();\n _consoleLogs.push({ level: level, message: msg });\n orig.apply(console, arguments);\n };\n }\n console.log = _wrapConsole('log', _origConsole.log);\n console.warn = _wrapConsole('warn', _origConsole.warn);\n console.error = _wrapConsole('error', _origConsole.error);\n console.info = _wrapConsole('info', _origConsole.info);\n\n function _collectError(message, stack) {\n if (!message) return;\n if (message === 'Script error.' || message === 'Script error') message = 'Runtime error';\n if (_toolErrors.indexOf(message) !== -1) return;\n _toolErrors.push(message);\n _toolErrorDetails.push({ message: message, stack: stack || '' });\n var toast = document.getElementById('__tool-error-toast');\n if (!toast) return;\n var msg = document.getElementById('__tool-error-msg');\n if (_toolErrors.length === 1) {\n msg.textContent = _toolErrors[0];\n } else {\n msg.textContent = _toolErrors.length + ' errors — ' + _toolErrors[_toolErrors.length - 1];\n }\n toast.style.display = 'block';\n }\n\n window.addEventListener('error', function(event) {\n var msg = event.message || '';\n if (msg.indexOf('Alpine Expression Error') === 0) return;\n var stack = event.error && event.error.stack ? event.error.stack : '';\n _collectError(msg, stack);\n });\n\n window.addEventListener('unhandledrejection', function(event) {\n var msg = event.reason && event.reason.message ? event.reason.message : String(event.reason);\n var stack = event.reason && event.reason.stack ? event.reason.stack : '';\n _collectError(msg, stack);\n });\n </script>\n <!--\n SECURITY: pinned to exact patch versions + SRI integrity hashes. A\n malicious republish of @tailwindcss/browser@4.x or alpinejs@3.x would\n otherwise inject code into every tool. To bump these versions:\n 1. npm view @tailwindcss/browser version (or alpinejs)\n 2. curl -sL https://cdn.jsdelivr.net/npm/@tailwindcss/browser@<v> \\\n | openssl dgst -sha384 -binary | openssl base64 -A\n 3. Update the URL + integrity hash below in lockstep.\n -->\n <script\n src=\"https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.2.4\"\n integrity=\"sha384-yNSZBFvuOWcmww494a9+1zNuvgUGEXoWkein7cxP8wHUTi3iXCU4vJ7hr3tzBCml\"\n crossorigin=\"anonymous\"\n ></script>\n <script\n defer\n src=\"https://cdn.jsdelivr.net/npm/alpinejs@3.15.11/dist/cdn.min.js\"\n integrity=\"sha384-WPtu0YHhJ3arcykfnv1JgUffWDSKRnqnDeTpJUbOc2os2moEmLkIdaeR0trPN4be\"\n crossorigin=\"anonymous\"\n ></script>\n <style>${themeVars}</style>\n <style type=\"text/tailwindcss\">\n @custom-variant dark (&:where(.dark, .dark *));\n @theme {\n --color-border: hsl(var(--border));\n --color-input: hsl(var(--input));\n --color-ring: hsl(var(--ring));\n --color-background: hsl(var(--background));\n --color-foreground: hsl(var(--foreground));\n --color-primary: hsl(var(--primary));\n --color-primary-foreground: hsl(var(--primary-foreground));\n --color-secondary: hsl(var(--secondary));\n --color-secondary-foreground: hsl(var(--secondary-foreground));\n --color-destructive: hsl(var(--destructive));\n --color-destructive-foreground: hsl(var(--destructive-foreground));\n --color-muted: hsl(var(--muted));\n --color-muted-foreground: hsl(var(--muted-foreground));\n --color-accent: hsl(var(--accent));\n --color-accent-foreground: hsl(var(--accent-foreground));\n --color-popover: hsl(var(--popover));\n --color-popover-foreground: hsl(var(--popover-foreground));\n --color-card: hsl(var(--card));\n --color-card-foreground: hsl(var(--card-foreground));\n --color-sidebar: hsl(var(--sidebar-background));\n --color-sidebar-foreground: hsl(var(--sidebar-foreground));\n --color-sidebar-primary: hsl(var(--sidebar-primary));\n --color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));\n --color-sidebar-accent: hsl(var(--sidebar-accent));\n --color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));\n --color-sidebar-border: hsl(var(--sidebar-border));\n --color-sidebar-ring: hsl(var(--sidebar-ring));\n --radius-lg: var(--radius);\n --radius-md: calc(var(--radius) - 2px);\n --radius-sm: calc(var(--radius) - 4px);\n }\n </style>\n\t <style>\n\t *, *::before, *::after { border-color: hsl(var(--border)); }\n\t body { font-family: 'Inter', sans-serif; margin: 0; padding: 0; min-height: 100vh; }\n\t </style>\n\t <script>\n\t var _toolRequestSeq = 0;\n\t var _toolPendingRequests = {};\n\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var message = event.data || {};\n\t if (message.type !== 'agent-native-tool-response') return;\n\t var pending = _toolPendingRequests[message.requestId];\n\t if (!pending) return;\n\t delete _toolPendingRequests[message.requestId];\n\t if (message.error) {\n\t pending.reject(new Error(message.error));\n\t } else {\n\t pending.resolve(message.response);\n\t }\n\t });\n\n\t function hostRequest(path, options) {\n\t options = options || {};\n\t return new Promise(function(resolve, reject) {\n\t var requestId = 'tool-req-' + (++_toolRequestSeq);\n\t _toolPendingRequests[requestId] = { resolve: resolve, reject: reject };\n\t window.parent.postMessage({\n\t type: 'agent-native-tool-request',\n\t requestId: requestId,\n\t path: path,\n\t options: {\n\t method: options.method || 'GET',\n\t headers: options.headers || {},\n\t body: options.body,\n\t },\n\t }, '*');\n\t setTimeout(function() {\n\t var pending = _toolPendingRequests[requestId];\n\t if (!pending) return;\n\t delete _toolPendingRequests[requestId];\n\t pending.reject(new Error('Tool host request timed out'));\n\t }, 30000);\n\t });\n\t }\n\n\t var _origHostRequest = hostRequest;\n\t hostRequest = function(path, options) {\n\t var entry = { path: path, method: (options && options.method) || 'GET' };\n\t return _origHostRequest(path, options).then(function(res) {\n\t entry.ok = res.ok;\n\t entry.status = res.status;\n\t if (!res.ok && res.body) {\n\t try { entry.error = typeof res.body === 'string' ? res.body.slice(0, 200) : JSON.stringify(res.body).slice(0, 200); } catch(e) {}\n\t }\n\t if (_networkLogs.length >= 20) _networkLogs.shift();\n\t _networkLogs.push(entry);\n\t return res;\n\t }, function(err) {\n\t entry.ok = false;\n\t entry.error = err.message;\n\t if (_networkLogs.length >= 20) _networkLogs.shift();\n\t _networkLogs.push(entry);\n\t throw err;\n\t });\n\t };\n\n\t function toolFetch(url, options) {\n\t var opts = options || {};\n\t return hostRequest('/_agent-native/tools/proxy', {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify({\n\t url: url,\n method: opts.method || 'GET',\n headers: opts.headers,\n body: opts.body,\n }),\n\t }).then(function(res) {\n\t var data = res.body;\n\t if (data.error && data.status === undefined) {\n\t throw new Error(data.error);\n\t }\n return {\n ok: data.status >= 200 && data.status < 300,\n status: data.status,\n\t json: function() { return Promise.resolve(data.body); },\n\t text: function() { return Promise.resolve(typeof data.body === 'string' ? data.body : JSON.stringify(data.body)); },\n\t };\n\t });\n\t }\n\n\t async function appAction(name, params) {\n\t params = params || {};\n\t var res = await hostRequest('/_agent-native/actions/' + encodeURIComponent(name), {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify(params),\n\t });\n\t if (!res.ok) {\n\t var err = res.body || { error: res.statusText };\n\t throw new Error(err.error || 'Action failed: ' + res.status);\n\t }\n\t return res.body;\n\t }\n\n\t async function appFetch(path, options) {\n\t options = options || {};\n\t var res = await hostRequest(path, {\n\t ...options,\n\t headers: {\n\t 'Content-Type': 'application/json',\n\t ...(options.headers || {}),\n\t },\n\t });\n\t if (!res.ok) {\n\t var err = typeof res.body === 'object' && res.body ? res.body : { error: res.statusText };\n\t throw new Error(err.error || 'Request failed: ' + res.status);\n\t }\n\t return res.body;\n\t }\n\n async function dbQuery(sql, args) {\n var body = { sql: sql };\n if (args) body.args = args;\n return appFetch('/_agent-native/tools/sql/query', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n }\n\n async function dbExec(sql, args) {\n var body = { sql: sql };\n if (args) body.args = args;\n return appFetch('/_agent-native/tools/sql/exec', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n }\n\n var _toolId = ${toolIdJson};\n var _toolBinding = ${bindingJson};\n window.toolBinding = _toolBinding;\n // SECURITY (audit H4): announce the resolved binding to the parent so the\n // host bridge can gate dangerous helpers based on viewer role. Sent\n // BEFORE the user-authored content has a chance to run, so a malicious\n // tool body cannot suppress or rewrite the announcement. The parent\n // ignores subsequent announcements for the same iframe; see\n // ToolViewer.tsx / EmbeddedTool.tsx.\n try {\n window.parent.postMessage(\n {\n type: 'agent-native-tool-binding',\n toolId: _toolId,\n binding: _toolBinding,\n },\n '*',\n );\n } catch (_) {}\n // SECURITY: when the viewer is not the author of this tool, emit a clear\n // console warning. The bridge currently runs every helper with the\n // viewer's session — a malicious shared tool can call any action, read\n // any owned table row in scope, and resolve any user-scope secret. A\n // full consent step is tracked as TODO C1 in audit 05-tools-sandbox.md.\n if (_toolBinding && !_toolBinding.isAuthor) {\n try {\n console.warn(\n '[agent-native] Shared tool — running with viewer\\\\'s session. ' +\n 'Author: ' + (_toolBinding.authorEmail || '<unknown>') + '. ' +\n 'Bridge calls (appAction, dbExec, toolFetch) execute under ' +\n 'your account; they are gated by your permissions, not the ' +\n 'author\\\\'s. Do not run untrusted shared tools.',\n );\n } catch (_) {}\n }\n\n var toolData = {\n\t async list(collection, opts) {\n\t var limit = (opts && opts.limit) || 100;\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/tools/data/' + _toolId + '/' + encodeURIComponent(collection) + '?limit=' + limit + '&scope=' + scope);\n\t if (!res.ok) throw new Error('Failed to list tool data');\n\t return res.body;\n\t },\n async get(collection, id, opts) {\n var scope = (opts && opts.scope) || 'user';\n var items = await this.list(collection, { scope: scope });\n return (items || []).find(function(item) { return item.id === id; }) || null;\n },\n async set(collection, id, data, opts) {\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/tools/data/' + _toolId + '/' + encodeURIComponent(collection), {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify({ id: id, data: data, scope: scope }),\n\t });\n\t if (!res.ok) throw new Error('Failed to save tool data');\n\t return res.body;\n\t },\n\t async remove(collection, id, opts) {\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/tools/data/' + _toolId + '/' + encodeURIComponent(collection) + '/' + encodeURIComponent(id) + '?scope=' + scope, {\n\t method: 'DELETE',\n\t });\n\t if (!res.ok) throw new Error('Failed to delete tool data');\n\t return res.body;\n\t },\n\t };\n\t </script>\n\t <style>\n\t #__tool-error-toast {\n\t display: none;\n\t position: fixed;\n\t bottom: 16px;\n\t right: 16px;\n\t max-width: 420px;\n\t background: hsl(var(--destructive));\n\t color: hsl(var(--destructive-foreground));\n\t border: 1px solid hsl(var(--destructive) / .6);\n\t border-radius: calc(var(--radius, .5rem) + 2px);\n\t padding: 12px 16px;\n\t font-size: 13px;\n\t line-height: 1.4;\n\t font-family: 'Inter', sans-serif;\n\t z-index: 9999;\n\t box-shadow: 0 4px 12px rgba(0,0,0,.15), 0 1px 3px rgba(0,0,0,.1);\n\t animation: __toast-in 0.2s ease-out;\n\t }\n\t @keyframes __toast-in {\n\t from { opacity: 0; transform: translateY(8px); }\n\t to { opacity: 1; transform: translateY(0); }\n\t }\n\t </style>\n\t <script>\n\t // Extension-point slot context: when a tool is rendered embedded inside an\n\t // ExtensionSlot, the host pushes a context object via postMessage. Tools\n\t // read it synchronously via window.slotContext or subscribe to changes\n\t // via window.onSlotContext(fn). When rendered full-page (no ?slot= param),\n\t // slotContext stays null and tools branch on that.\n\t window.slotContext = null;\n\t var _slotContextSubscribers = [];\n\t window.onSlotContext = function(fn) {\n\t _slotContextSubscribers.push(fn);\n\t if (window.slotContext !== null) {\n\t try { fn(window.slotContext); } catch(_) {}\n\t }\n\t return function() {\n\t _slotContextSubscribers = _slotContextSubscribers.filter(function(f) { return f !== fn; });\n\t };\n\t };\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var msg = event.data;\n\t if (!msg || msg.type !== 'agent-native-slot-context') return;\n\t window.slotContext = msg.context || {};\n\t _slotContextSubscribers.forEach(function(fn) {\n\t try { fn(window.slotContext); } catch(_) {}\n\t });\n\t });\n\n\t // Auto-resize the iframe to its content when running in slot mode. The\n\t // host listens for agent-native-tool-resize and adjusts the iframe height.\n\t if (new URLSearchParams(location.search).get('slot')) {\n\t var _lastH = 0;\n\t var _reportHeight = function() {\n\t var h = Math.max(\n\t document.documentElement.scrollHeight,\n\t document.body ? document.body.scrollHeight : 0,\n\t );\n\t if (h !== _lastH) {\n\t _lastH = h;\n\t window.parent.postMessage({ type: 'agent-native-tool-resize', height: h }, '*');\n\t }\n\t };\n\t if (typeof ResizeObserver !== 'undefined') {\n\t var _ro = new ResizeObserver(_reportHeight);\n\t document.addEventListener('DOMContentLoaded', function() {\n\t _ro.observe(document.documentElement);\n\t if (document.body) _ro.observe(document.body);\n\t });\n\t }\n\t // Initial reports — Alpine takes a tick to render after DOMContentLoaded.\n\t setTimeout(_reportHeight, 50);\n\t setTimeout(_reportHeight, 250);\n\t }\n\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var msg = event.data;\n\t if (!msg || msg.type !== 'agent-native-theme-update') return;\n\t var root = document.documentElement;\n\t if (msg.isDark !== undefined) {\n\t if (msg.isDark) root.classList.add('dark');\n\t else root.classList.remove('dark');\n\t }\n\t var vars = msg.vars || {};\n\t for (var key in vars) {\n\t if (vars.hasOwnProperty(key)) {\n\t root.style.setProperty(key, vars[key]);\n\t }\n\t }\n\t });\n\n\t document.addEventListener('keydown', function(e) {\n\t if ((e.metaKey || e.ctrlKey) && !e.altKey) {\n\t var key = e.key.toLowerCase();\n\t if (key === 'c' || key === 'v' || key === 'x' || key === 'a' || key === 'z' || key === 'y') return;\n\t e.preventDefault();\n\t e.stopPropagation();\n\t window.parent.postMessage({\n\t type: 'agent-native-tool-keydown',\n\t key: e.key, code: e.code,\n\t metaKey: e.metaKey, ctrlKey: e.ctrlKey,\n\t shiftKey: e.shiftKey, altKey: e.altKey,\n\t }, '*');\n\t return;\n\t }\n\t if (e.key === 'Escape') {\n\t window.parent.postMessage({\n\t type: 'agent-native-tool-keydown',\n\t key: e.key, code: e.code,\n\t metaKey: false, ctrlKey: false,\n\t shiftKey: false, altKey: false,\n\t }, '*');\n\t }\n\t });\n\n\t document.addEventListener('DOMContentLoaded', function() {\n\t var fixBtn = document.getElementById('__tool-error-fix');\n\t if (fixBtn) {\n\t fixBtn.addEventListener('click', function() {\n\t window.parent.postMessage({\n\t type: 'agent-native-tool-error-fix',\n\t errors: _toolErrors,\n\t errorDetails: _toolErrorDetails,\n\t consoleLogs: _consoleLogs.slice(-30),\n\t networkLogs: _networkLogs.slice(-15)\n\t }, '*');\n\t document.getElementById('__tool-error-toast').style.display = 'none';\n\t });\n\t }\n\t var dismissBtn = document.getElementById('__tool-error-dismiss');\n\t if (dismissBtn) {\n\t dismissBtn.addEventListener('click', function() {\n\t document.getElementById('__tool-error-toast').style.display = 'none';\n\t });\n\t }\n\t });\n\t </script>\n\t</head>\n\t<body${toolId ? ` data-tool-id=\"${toolIdAttr}\"` : \"\"} class=\"bg-background text-foreground\">\n\t${content}\n\t<div id=\"__tool-error-toast\">\n\t <div style=\"display:flex;align-items:flex-start;gap:8px;\">\n\t <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0;margin-top:1px;\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"/></svg>\n\t <span id=\"__tool-error-msg\" style=\"flex:1;overflow:hidden;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;\"></span>\n\t <button id=\"__tool-error-fix\" style=\"cursor:pointer;border:none;background:rgba(255,255,255,.9);color:hsl(0 84.2% 40%);font-size:12px;font-weight:500;padding:4px 12px;border-radius:4px;flex-shrink:0;\">Fix</button>\n\t <button id=\"__tool-error-dismiss\" style=\"cursor:pointer;border:none;background:transparent;color:inherit;font-size:16px;padding:2px 6px;opacity:0.7;flex-shrink:0;\">×</button>\n\t </div>\n\t</div>\n\t</body>\n\t</html>`;\n}\n\nfunction escapeHtmlAttribute(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"html-shell.js","sourceRoot":"","sources":["../../src/tools/html-shell.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAC1B,2YAA2Y,CAAC;AAE9Y,MAAM,CAAC,MAAM,oBAAoB,GAAG,eAAe,CAAC,OAAO,CACzD,8BAA8B,EAC9B,EAAE,CACH,CAAC;AA6CF,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,SAAiB,EACjB,MAAe,EACf,MAAe,EACf,OAA2B;IAE3B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAChC,OAAO,IAAI;QACT,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,EAAE;QACf,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,OAAO;KACd,CACF,CAAC;IAEF,OAAO;iBACQ,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;;;;wDAIU,oBAAoB;IACxE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,kDAAkD,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA8E7H,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBA4LA,UAAU;yBACL,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiN5B,MAAM,CAAC,CAAC,CAAC,kBAAkB,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE;GAClD,OAAO;;;;;;;;;;SAUD,CAAC;AACV,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC","sourcesContent":["export const TOOL_IFRAME_CSP =\n \"default-src 'none'; script-src 'self' https://cdn.jsdelivr.net 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; font-src https://fonts.gstatic.com; connect-src 'self'; img-src 'self' data: blob:; media-src 'self' data: blob:; frame-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'self';\";\n\nexport const TOOL_IFRAME_META_CSP = TOOL_IFRAME_CSP.replace(\n /\\s*frame-ancestors 'self';?$/,\n \"\",\n);\n\n/**\n * SECURITY — TOOL CONTENT IS UNTRUSTED.\n *\n * `${content}` (line ~Body) interpolates raw HTML/JS authored by a user. This\n * file is the boundary between framework-controlled HTML and user-controlled\n * HTML. Two non-negotiable invariants for every change here:\n *\n * 1. The iframe MUST be rendered with a `sandbox` attribute that does NOT\n * include `allow-same-origin`. The viewer (`ToolViewer.tsx`,\n * `EmbeddedTool.tsx`) sets `sandbox=\"allow-scripts allow-forms\"` — and\n * that is the only acceptable shape. Adding `allow-same-origin` would\n * give the tool full DOM access to the parent window via cross-frame\n * script.\n *\n * 2. Every reachable parent action must treat the postMessage payload as\n * hostile. The bridge in `iframe-bridge.ts` enforces a path allowlist,\n * header sanitization, and method allowlist; do not relax those gates\n * for \"convenience\" in this file or any caller.\n *\n * For the trust model rationale, see audit 05-tools-sandbox.md (C1) and the\n * `tools` skill. When in doubt, fail closed.\n */\n\nexport interface ToolRenderBinding {\n /** Email of the user who authored / owns the tool. */\n authorEmail: string;\n /** Email of the user currently viewing/running the tool. */\n viewerEmail: string;\n /** True when viewer === author. */\n isAuthor: boolean;\n /**\n * Resolved role for the viewer (\"owner\" | \"admin\" | \"editor\" | \"viewer\").\n *\n * TODO(security, audit H4): the host-side bridge does not yet gate any\n * helper based on this value — every viewer gets the same powers as the\n * author. The role is plumbed through so a follow-up PR can constrain\n * `appAction` / `dbExec` / `toolFetch` for non-author viewers (and\n * eventually require an explicit consent step before running a shared\n * tool, audit C1). For now this is metadata only.\n */\n role: \"owner\" | \"admin\" | \"editor\" | \"viewer\";\n}\n\nexport function buildToolHtml(\n content: string,\n themeVars: string,\n isDark: boolean,\n toolId?: string,\n binding?: ToolRenderBinding,\n): string {\n const toolIdJson = JSON.stringify(toolId ?? \"\");\n const toolIdAttr = escapeHtmlAttribute(toolId ?? \"\");\n const bindingJson = JSON.stringify(\n binding ?? {\n authorEmail: \"\",\n viewerEmail: \"\",\n isAuthor: true,\n role: \"owner\",\n },\n );\n\n return `<!DOCTYPE html>\n<html lang=\"en\"${isDark ? ' class=\"dark\"' : \"\"}>\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta http-equiv=\"Content-Security-Policy\" content=\"${TOOL_IFRAME_META_CSP}\" />\n ${binding && !binding.isAuthor ? `<meta name=\"agent-native-tool-author\" content=\"${escapeHtmlAttribute(binding.authorEmail)}\" />` : \"\"}\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300..700&display=swap\" rel=\"stylesheet\" />\n <script>\n var _toolErrors = [];\n var _toolErrorDetails = [];\n var _consoleLogs = [];\n var _networkLogs = [];\n\n var _origConsole = { log: console.log, warn: console.warn, error: console.error, info: console.info };\n function _wrapConsole(level, orig) {\n return function() {\n var args = Array.prototype.slice.call(arguments);\n var msg = args.map(function(a) {\n try { return typeof a === 'object' ? JSON.stringify(a) : String(a); }\n catch(e) { return String(a); }\n }).join(' ');\n if (_consoleLogs.length >= 50) _consoleLogs.shift();\n _consoleLogs.push({ level: level, message: msg });\n orig.apply(console, arguments);\n };\n }\n console.log = _wrapConsole('log', _origConsole.log);\n console.warn = _wrapConsole('warn', _origConsole.warn);\n console.error = _wrapConsole('error', _origConsole.error);\n console.info = _wrapConsole('info', _origConsole.info);\n\n function _collectError(message, stack) {\n if (!message) return;\n if (message === 'Script error.' || message === 'Script error') message = 'Runtime error';\n if (_toolErrors.indexOf(message) !== -1) return;\n _toolErrors.push(message);\n _toolErrorDetails.push({ message: message, stack: stack || '' });\n var toast = document.getElementById('__tool-error-toast');\n if (!toast) return;\n var msg = document.getElementById('__tool-error-msg');\n if (_toolErrors.length === 1) {\n msg.textContent = _toolErrors[0];\n } else {\n msg.textContent = _toolErrors.length + ' errors — ' + _toolErrors[_toolErrors.length - 1];\n }\n toast.style.display = 'block';\n }\n\n window.addEventListener('error', function(event) {\n var msg = event.message || '';\n if (msg.indexOf('Alpine Expression Error') === 0) return;\n var stack = event.error && event.error.stack ? event.error.stack : '';\n _collectError(msg, stack);\n });\n\n window.addEventListener('unhandledrejection', function(event) {\n var msg = event.reason && event.reason.message ? event.reason.message : String(event.reason);\n var stack = event.reason && event.reason.stack ? event.reason.stack : '';\n _collectError(msg, stack);\n });\n </script>\n <!--\n SECURITY: pinned to exact patch versions + SRI integrity hashes. A\n malicious republish of @tailwindcss/browser@4.x or alpinejs@3.x would\n otherwise inject code into every tool. To bump these versions:\n 1. npm view @tailwindcss/browser version (or alpinejs)\n 2. curl -sL https://cdn.jsdelivr.net/npm/@tailwindcss/browser@<v> \\\n | openssl dgst -sha384 -binary | openssl base64 -A\n 3. Update the URL + integrity hash below in lockstep.\n -->\n <script\n src=\"https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.2.4\"\n integrity=\"sha384-yNSZBFvuOWcmww494a9+1zNuvgUGEXoWkein7cxP8wHUTi3iXCU4vJ7hr3tzBCml\"\n crossorigin=\"anonymous\"\n ></script>\n <script\n defer\n src=\"https://cdn.jsdelivr.net/npm/alpinejs@3.15.11/dist/cdn.min.js\"\n integrity=\"sha384-WPtu0YHhJ3arcykfnv1JgUffWDSKRnqnDeTpJUbOc2os2moEmLkIdaeR0trPN4be\"\n crossorigin=\"anonymous\"\n ></script>\n <style>${themeVars}</style>\n <style type=\"text/tailwindcss\">\n @custom-variant dark (&:where(.dark, .dark *));\n @theme {\n --color-border: hsl(var(--border));\n --color-input: hsl(var(--input));\n --color-ring: hsl(var(--ring));\n --color-background: hsl(var(--background));\n --color-foreground: hsl(var(--foreground));\n --color-primary: hsl(var(--primary));\n --color-primary-foreground: hsl(var(--primary-foreground));\n --color-secondary: hsl(var(--secondary));\n --color-secondary-foreground: hsl(var(--secondary-foreground));\n --color-destructive: hsl(var(--destructive));\n --color-destructive-foreground: hsl(var(--destructive-foreground));\n --color-muted: hsl(var(--muted));\n --color-muted-foreground: hsl(var(--muted-foreground));\n --color-accent: hsl(var(--accent));\n --color-accent-foreground: hsl(var(--accent-foreground));\n --color-popover: hsl(var(--popover));\n --color-popover-foreground: hsl(var(--popover-foreground));\n --color-card: hsl(var(--card));\n --color-card-foreground: hsl(var(--card-foreground));\n --color-sidebar: hsl(var(--sidebar-background));\n --color-sidebar-foreground: hsl(var(--sidebar-foreground));\n --color-sidebar-primary: hsl(var(--sidebar-primary));\n --color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));\n --color-sidebar-accent: hsl(var(--sidebar-accent));\n --color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));\n --color-sidebar-border: hsl(var(--sidebar-border));\n --color-sidebar-ring: hsl(var(--sidebar-ring));\n --radius-lg: var(--radius);\n --radius-md: calc(var(--radius) - 2px);\n --radius-sm: calc(var(--radius) - 4px);\n }\n </style>\n\t <style>\n\t *, *::before, *::after { border-color: hsl(var(--border)); }\n\t body {\n\t --agent-native-tool-padding: clamp(16px, 2vw, 24px);\n\t box-sizing: border-box;\n\t font-family: 'Inter', sans-serif;\n\t margin: 0;\n\t min-height: 100vh;\n\t padding: var(--agent-native-tool-padding);\n\t }\n\t body:has(> [data-tool-layout=\"full-bleed\"]),\n\t body:has(> [data-tool-padding=\"none\"]),\n\t body:has(> .agent-native-tool-bleed) {\n\t padding: 0;\n\t }\n\t </style>\n\t <script>\n\t var _toolRequestSeq = 0;\n\t var _toolPendingRequests = {};\n\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var message = event.data || {};\n\t if (message.type !== 'agent-native-tool-response') return;\n\t var pending = _toolPendingRequests[message.requestId];\n\t if (!pending) return;\n\t delete _toolPendingRequests[message.requestId];\n\t if (message.error) {\n\t pending.reject(new Error(message.error));\n\t } else {\n\t pending.resolve(message.response);\n\t }\n\t });\n\n\t function hostRequest(path, options) {\n\t options = options || {};\n\t return new Promise(function(resolve, reject) {\n\t var requestId = 'tool-req-' + (++_toolRequestSeq);\n\t _toolPendingRequests[requestId] = { resolve: resolve, reject: reject };\n\t window.parent.postMessage({\n\t type: 'agent-native-tool-request',\n\t requestId: requestId,\n\t path: path,\n\t options: {\n\t method: options.method || 'GET',\n\t headers: options.headers || {},\n\t body: options.body,\n\t },\n\t }, '*');\n\t setTimeout(function() {\n\t var pending = _toolPendingRequests[requestId];\n\t if (!pending) return;\n\t delete _toolPendingRequests[requestId];\n\t pending.reject(new Error('Tool host request timed out'));\n\t }, 30000);\n\t });\n\t }\n\n\t var _origHostRequest = hostRequest;\n\t hostRequest = function(path, options) {\n\t var entry = { path: path, method: (options && options.method) || 'GET' };\n\t return _origHostRequest(path, options).then(function(res) {\n\t entry.ok = res.ok;\n\t entry.status = res.status;\n\t if (!res.ok && res.body) {\n\t try { entry.error = typeof res.body === 'string' ? res.body.slice(0, 200) : JSON.stringify(res.body).slice(0, 200); } catch(e) {}\n\t }\n\t if (_networkLogs.length >= 20) _networkLogs.shift();\n\t _networkLogs.push(entry);\n\t return res;\n\t }, function(err) {\n\t entry.ok = false;\n\t entry.error = err.message;\n\t if (_networkLogs.length >= 20) _networkLogs.shift();\n\t _networkLogs.push(entry);\n\t throw err;\n\t });\n\t };\n\n\t function toolFetch(url, options) {\n\t var opts = options || {};\n\t return hostRequest('/_agent-native/tools/proxy', {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify({\n\t url: url,\n method: opts.method || 'GET',\n headers: opts.headers,\n body: opts.body,\n }),\n\t }).then(function(res) {\n\t var data = res.body;\n\t if (data.error && data.status === undefined) {\n\t throw new Error(data.error);\n\t }\n return {\n ok: data.status >= 200 && data.status < 300,\n status: data.status,\n\t json: function() { return Promise.resolve(data.body); },\n\t text: function() { return Promise.resolve(typeof data.body === 'string' ? data.body : JSON.stringify(data.body)); },\n\t };\n\t });\n\t }\n\n\t async function appAction(name, params) {\n\t params = params || {};\n\t var res = await hostRequest('/_agent-native/actions/' + encodeURIComponent(name), {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify(params),\n\t });\n\t if (!res.ok) {\n\t var err = res.body || { error: res.statusText };\n\t throw new Error(err.error || 'Action failed: ' + res.status);\n\t }\n\t return res.body;\n\t }\n\n\t async function appFetch(path, options) {\n\t options = options || {};\n\t var res = await hostRequest(path, {\n\t ...options,\n\t headers: {\n\t 'Content-Type': 'application/json',\n\t ...(options.headers || {}),\n\t },\n\t });\n\t if (!res.ok) {\n\t var err = typeof res.body === 'object' && res.body ? res.body : { error: res.statusText };\n\t throw new Error(err.error || 'Request failed: ' + res.status);\n\t }\n\t return res.body;\n\t }\n\n async function dbQuery(sql, args) {\n var body = { sql: sql };\n if (args) body.args = args;\n return appFetch('/_agent-native/tools/sql/query', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n }\n\n async function dbExec(sql, args) {\n var body = { sql: sql };\n if (args) body.args = args;\n return appFetch('/_agent-native/tools/sql/exec', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n }\n\n var _toolId = ${toolIdJson};\n var _toolBinding = ${bindingJson};\n window.toolBinding = _toolBinding;\n // SECURITY (audit H4): announce the resolved binding to the parent so the\n // host bridge can gate dangerous helpers based on viewer role. Sent\n // BEFORE the user-authored content has a chance to run, so a malicious\n // tool body cannot suppress or rewrite the announcement. The parent\n // ignores subsequent announcements for the same iframe; see\n // ToolViewer.tsx / EmbeddedTool.tsx.\n try {\n window.parent.postMessage(\n {\n type: 'agent-native-tool-binding',\n toolId: _toolId,\n binding: _toolBinding,\n },\n '*',\n );\n } catch (_) {}\n // SECURITY: when the viewer is not the author of this tool, emit a clear\n // console warning. The bridge currently runs every helper with the\n // viewer's session — a malicious shared tool can call any action, read\n // any owned table row in scope, and resolve any user-scope secret. A\n // full consent step is tracked as TODO C1 in audit 05-tools-sandbox.md.\n if (_toolBinding && !_toolBinding.isAuthor) {\n try {\n console.warn(\n '[agent-native] Shared tool — running with viewer\\\\'s session. ' +\n 'Author: ' + (_toolBinding.authorEmail || '<unknown>') + '. ' +\n 'Bridge calls (appAction, dbExec, toolFetch) execute under ' +\n 'your account; they are gated by your permissions, not the ' +\n 'author\\\\'s. Do not run untrusted shared tools.',\n );\n } catch (_) {}\n }\n\n var toolData = {\n\t async list(collection, opts) {\n\t var limit = (opts && opts.limit) || 100;\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/tools/data/' + _toolId + '/' + encodeURIComponent(collection) + '?limit=' + limit + '&scope=' + scope);\n\t if (!res.ok) throw new Error('Failed to list tool data');\n\t return res.body;\n\t },\n async get(collection, id, opts) {\n var scope = (opts && opts.scope) || 'user';\n var items = await this.list(collection, { scope: scope });\n return (items || []).find(function(item) { return item.id === id; }) || null;\n },\n async set(collection, id, data, opts) {\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/tools/data/' + _toolId + '/' + encodeURIComponent(collection), {\n\t method: 'POST',\n\t headers: { 'Content-Type': 'application/json' },\n\t body: JSON.stringify({ id: id, data: data, scope: scope }),\n\t });\n\t if (!res.ok) throw new Error('Failed to save tool data');\n\t return res.body;\n\t },\n\t async remove(collection, id, opts) {\n\t var scope = (opts && opts.scope) || 'user';\n\t var res = await hostRequest('/_agent-native/tools/data/' + _toolId + '/' + encodeURIComponent(collection) + '/' + encodeURIComponent(id) + '?scope=' + scope, {\n\t method: 'DELETE',\n\t });\n\t if (!res.ok) throw new Error('Failed to delete tool data');\n\t return res.body;\n\t },\n\t };\n\t </script>\n\t <style>\n\t #__tool-error-toast {\n\t display: none;\n\t position: fixed;\n\t bottom: 16px;\n\t right: 16px;\n\t max-width: 420px;\n\t background: hsl(var(--destructive));\n\t color: hsl(var(--destructive-foreground));\n\t border: 1px solid hsl(var(--destructive) / .6);\n\t border-radius: calc(var(--radius, .5rem) + 2px);\n\t padding: 12px 16px;\n\t font-size: 13px;\n\t line-height: 1.4;\n\t font-family: 'Inter', sans-serif;\n\t z-index: 9999;\n\t box-shadow: 0 4px 12px rgba(0,0,0,.15), 0 1px 3px rgba(0,0,0,.1);\n\t animation: __toast-in 0.2s ease-out;\n\t }\n\t @keyframes __toast-in {\n\t from { opacity: 0; transform: translateY(8px); }\n\t to { opacity: 1; transform: translateY(0); }\n\t }\n\t </style>\n\t <script>\n\t // Extension-point slot context: when a tool is rendered embedded inside an\n\t // ExtensionSlot, the host pushes a context object via postMessage. Tools\n\t // read it synchronously via window.slotContext or subscribe to changes\n\t // via window.onSlotContext(fn). When rendered full-page (no ?slot= param),\n\t // slotContext stays null and tools branch on that.\n\t window.slotContext = null;\n\t var _slotContextSubscribers = [];\n\t window.onSlotContext = function(fn) {\n\t _slotContextSubscribers.push(fn);\n\t if (window.slotContext !== null) {\n\t try { fn(window.slotContext); } catch(_) {}\n\t }\n\t return function() {\n\t _slotContextSubscribers = _slotContextSubscribers.filter(function(f) { return f !== fn; });\n\t };\n\t };\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var msg = event.data;\n\t if (!msg || msg.type !== 'agent-native-slot-context') return;\n\t window.slotContext = msg.context || {};\n\t _slotContextSubscribers.forEach(function(fn) {\n\t try { fn(window.slotContext); } catch(_) {}\n\t });\n\t });\n\n\t // Auto-resize the iframe to its content when running in slot mode. The\n\t // host listens for agent-native-tool-resize and adjusts the iframe height.\n\t if (new URLSearchParams(location.search).get('slot')) {\n\t var _lastH = 0;\n\t var _reportHeight = function() {\n\t var h = Math.max(\n\t document.documentElement.scrollHeight,\n\t document.body ? document.body.scrollHeight : 0,\n\t );\n\t if (h !== _lastH) {\n\t _lastH = h;\n\t window.parent.postMessage({ type: 'agent-native-tool-resize', height: h }, '*');\n\t }\n\t };\n\t if (typeof ResizeObserver !== 'undefined') {\n\t var _ro = new ResizeObserver(_reportHeight);\n\t document.addEventListener('DOMContentLoaded', function() {\n\t _ro.observe(document.documentElement);\n\t if (document.body) _ro.observe(document.body);\n\t });\n\t }\n\t // Initial reports — Alpine takes a tick to render after DOMContentLoaded.\n\t setTimeout(_reportHeight, 50);\n\t setTimeout(_reportHeight, 250);\n\t }\n\n\t window.addEventListener('message', function(event) {\n\t if (event.source !== window.parent) return;\n\t var msg = event.data;\n\t if (!msg || msg.type !== 'agent-native-theme-update') return;\n\t var root = document.documentElement;\n\t if (msg.isDark !== undefined) {\n\t if (msg.isDark) root.classList.add('dark');\n\t else root.classList.remove('dark');\n\t }\n\t var vars = msg.vars || {};\n\t for (var key in vars) {\n\t if (vars.hasOwnProperty(key)) {\n\t root.style.setProperty(key, vars[key]);\n\t }\n\t }\n\t });\n\n\t document.addEventListener('keydown', function(e) {\n\t if ((e.metaKey || e.ctrlKey) && !e.altKey) {\n\t var key = e.key.toLowerCase();\n\t if (key === 'c' || key === 'v' || key === 'x' || key === 'a' || key === 'z' || key === 'y') return;\n\t e.preventDefault();\n\t e.stopPropagation();\n\t window.parent.postMessage({\n\t type: 'agent-native-tool-keydown',\n\t key: e.key, code: e.code,\n\t metaKey: e.metaKey, ctrlKey: e.ctrlKey,\n\t shiftKey: e.shiftKey, altKey: e.altKey,\n\t }, '*');\n\t return;\n\t }\n\t if (e.key === 'Escape') {\n\t window.parent.postMessage({\n\t type: 'agent-native-tool-keydown',\n\t key: e.key, code: e.code,\n\t metaKey: false, ctrlKey: false,\n\t shiftKey: false, altKey: false,\n\t }, '*');\n\t }\n\t });\n\n\t document.addEventListener('DOMContentLoaded', function() {\n\t var fixBtn = document.getElementById('__tool-error-fix');\n\t if (fixBtn) {\n\t fixBtn.addEventListener('click', function() {\n\t window.parent.postMessage({\n\t type: 'agent-native-tool-error-fix',\n\t errors: _toolErrors,\n\t errorDetails: _toolErrorDetails,\n\t consoleLogs: _consoleLogs.slice(-30),\n\t networkLogs: _networkLogs.slice(-15)\n\t }, '*');\n\t document.getElementById('__tool-error-toast').style.display = 'none';\n\t });\n\t }\n\t var dismissBtn = document.getElementById('__tool-error-dismiss');\n\t if (dismissBtn) {\n\t dismissBtn.addEventListener('click', function() {\n\t document.getElementById('__tool-error-toast').style.display = 'none';\n\t });\n\t }\n\t });\n\t </script>\n\t</head>\n\t<body${toolId ? ` data-tool-id=\"${toolIdAttr}\"` : \"\"} class=\"bg-background text-foreground\">\n\t${content}\n\t<div id=\"__tool-error-toast\">\n\t <div style=\"display:flex;align-items:flex-start;gap:8px;\">\n\t <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"flex-shrink:0;margin-top:1px;\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"/></svg>\n\t <span id=\"__tool-error-msg\" style=\"flex:1;overflow:hidden;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;\"></span>\n\t <button id=\"__tool-error-fix\" style=\"cursor:pointer;border:none;background:rgba(255,255,255,.9);color:hsl(0 84.2% 40%);font-size:12px;font-weight:500;padding:4px 12px;border-radius:4px;flex-shrink:0;\">Fix</button>\n\t <button id=\"__tool-error-dismiss\" style=\"cursor:pointer;border:none;background:transparent;color:inherit;font-size:16px;padding:2px 6px;opacity:0.7;flex-shrink:0;\">×</button>\n\t </div>\n\t</div>\n\t</body>\n\t</html>`;\n}\n\nfunction escapeHtmlAttribute(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/tools/store.ts"],"names":[],"mappings":"AAuCA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/tools/store.ts"],"names":[],"mappings":"AAuCA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA6CvD;AA4DD,wBAAgB,sBAAsB,SASrC;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,CAAC;CAC1C;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAOpD;AAED,wBAAsB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAIjE;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CA2BvE;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,CAAC;CAC3C;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAczB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAED,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAyBzB;AAED,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAe7D"}
|
package/dist/tools/store.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { eq } from "drizzle-orm";
|
|
3
|
-
import { getDbExec, isPostgres } from "../db/client.js";
|
|
3
|
+
import { getDbExec, isPostgres, retryOnDdlRace } from "../db/client.js";
|
|
4
4
|
import { createGetDb } from "../db/create-get-db.js";
|
|
5
5
|
import { accessFilter, assertAccess, resolveAccess, } from "../sharing/access.js";
|
|
6
6
|
import { getRequestUserEmail, getRequestOrgId, } from "../server/request-context.js";
|
|
@@ -13,23 +13,23 @@ export async function ensureToolsTables() {
|
|
|
13
13
|
_initPromise = (async () => {
|
|
14
14
|
const client = getDbExec();
|
|
15
15
|
const pg = isPostgres();
|
|
16
|
-
await client.execute(pg ? TOOLS_CREATE_SQL_PG : TOOLS_CREATE_SQL);
|
|
17
|
-
await client.execute(pg ? TOOL_SHARES_CREATE_SQL_PG : TOOL_SHARES_CREATE_SQL);
|
|
18
|
-
await client.execute(pg ? TOOL_DATA_CREATE_SQL_PG : TOOL_DATA_CREATE_SQL);
|
|
16
|
+
await retryOnDdlRace(() => client.execute(pg ? TOOLS_CREATE_SQL_PG : TOOLS_CREATE_SQL));
|
|
17
|
+
await retryOnDdlRace(() => client.execute(pg ? TOOL_SHARES_CREATE_SQL_PG : TOOL_SHARES_CREATE_SQL));
|
|
18
|
+
await retryOnDdlRace(() => client.execute(pg ? TOOL_DATA_CREATE_SQL_PG : TOOL_DATA_CREATE_SQL));
|
|
19
19
|
await ensureToolDataItemId(client, pg);
|
|
20
20
|
await ensureToolDataScope(client, pg);
|
|
21
21
|
await client.execute(pg ? TOOL_DATA_DROP_OLD_INDEX_SQL_PG : TOOL_DATA_DROP_OLD_INDEX_SQL);
|
|
22
|
-
await client.execute(pg ? TOOL_DATA_ITEM_INDEX_SQL_PG : TOOL_DATA_ITEM_INDEX_SQL);
|
|
23
|
-
await client.execute(TOOLS_OWNER_INDEX_SQL);
|
|
24
|
-
await client.execute(TOOLS_ORG_INDEX_SQL);
|
|
25
|
-
await client.execute(TOOL_SHARES_RESOURCE_INDEX_SQL);
|
|
22
|
+
await retryOnDdlRace(() => client.execute(pg ? TOOL_DATA_ITEM_INDEX_SQL_PG : TOOL_DATA_ITEM_INDEX_SQL));
|
|
23
|
+
await retryOnDdlRace(() => client.execute(TOOLS_OWNER_INDEX_SQL));
|
|
24
|
+
await retryOnDdlRace(() => client.execute(TOOLS_ORG_INDEX_SQL));
|
|
25
|
+
await retryOnDdlRace(() => client.execute(TOOL_SHARES_RESOURCE_INDEX_SQL));
|
|
26
26
|
// tool_consents was introduced for an audit-C1 per-viewer consent
|
|
27
27
|
// gate that we removed once we settled on intra-org trust as the
|
|
28
28
|
// baseline. The table is kept (additive — never drop) so deploys
|
|
29
29
|
// that already created it stay healthy; the runtime consent code
|
|
30
30
|
// is gone. Idempotent CREATE IF NOT EXISTS for fresh schemas.
|
|
31
|
-
await client.execute(pg ? TOOL_CONSENTS_CREATE_SQL_PG : TOOL_CONSENTS_CREATE_SQL);
|
|
32
|
-
await client.execute(TOOL_CONSENTS_VIEWER_INDEX_SQL);
|
|
31
|
+
await retryOnDdlRace(() => client.execute(pg ? TOOL_CONSENTS_CREATE_SQL_PG : TOOL_CONSENTS_CREATE_SQL));
|
|
32
|
+
await retryOnDdlRace(() => client.execute(TOOL_CONSENTS_VIEWER_INDEX_SQL));
|
|
33
33
|
})();
|
|
34
34
|
}
|
|
35
35
|
return _initPromise;
|
|
@@ -117,7 +117,12 @@ export async function createTool(data) {
|
|
|
117
117
|
updatedAt: now,
|
|
118
118
|
ownerEmail: userEmail,
|
|
119
119
|
orgId: orgId ?? null,
|
|
120
|
-
visibility
|
|
120
|
+
// Default to org-visibility when the user has an active organization so
|
|
121
|
+
// teammates see the tool in their sidebar — matching how analytics
|
|
122
|
+
// dashboards/analyses are scoped (`templates/analytics/server/lib/
|
|
123
|
+
// dashboards-store.ts:356`). Solo users (no org) get the private
|
|
124
|
+
// default. Owners can still flip back to private via update-tool.
|
|
125
|
+
visibility: orgId ? "org" : "private",
|
|
121
126
|
};
|
|
122
127
|
await db.insert(tools).values(row);
|
|
123
128
|
return row;
|
package/dist/tools/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/tools/store.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { eq } from \"drizzle-orm\";\nimport { getDbExec, isPostgres } from \"../db/client.js\";\nimport { createGetDb } from \"../db/create-get-db.js\";\nimport {\n accessFilter,\n assertAccess,\n resolveAccess,\n} from \"../sharing/access.js\";\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n} from \"../server/request-context.js\";\nimport { registerShareableResource } from \"../sharing/registry.js\";\nimport {\n tools,\n toolShares,\n TOOLS_CREATE_SQL,\n TOOLS_CREATE_SQL_PG,\n TOOL_SHARES_CREATE_SQL,\n TOOL_SHARES_CREATE_SQL_PG,\n TOOL_DATA_CREATE_SQL,\n TOOL_DATA_CREATE_SQL_PG,\n TOOL_DATA_ITEM_INDEX_SQL,\n TOOL_DATA_ITEM_INDEX_SQL_PG,\n TOOL_DATA_DROP_OLD_INDEX_SQL,\n TOOL_DATA_DROP_OLD_INDEX_SQL_PG,\n TOOLS_OWNER_INDEX_SQL,\n TOOLS_ORG_INDEX_SQL,\n TOOL_SHARES_RESOURCE_INDEX_SQL,\n TOOL_CONSENTS_CREATE_SQL,\n TOOL_CONSENTS_CREATE_SQL_PG,\n TOOL_CONSENTS_VIEWER_INDEX_SQL,\n} from \"./schema.js\";\n\nconst getDb = createGetDb({ tools, toolShares });\n\nlet _initPromise: Promise<void> | undefined;\n\nexport async function ensureToolsTables(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const pg = isPostgres();\n await client.execute(pg ? TOOLS_CREATE_SQL_PG : TOOLS_CREATE_SQL);\n await client.execute(\n pg ? TOOL_SHARES_CREATE_SQL_PG : TOOL_SHARES_CREATE_SQL,\n );\n await client.execute(pg ? TOOL_DATA_CREATE_SQL_PG : TOOL_DATA_CREATE_SQL);\n await ensureToolDataItemId(client, pg);\n await ensureToolDataScope(client, pg);\n await client.execute(\n pg ? TOOL_DATA_DROP_OLD_INDEX_SQL_PG : TOOL_DATA_DROP_OLD_INDEX_SQL,\n );\n await client.execute(\n pg ? TOOL_DATA_ITEM_INDEX_SQL_PG : TOOL_DATA_ITEM_INDEX_SQL,\n );\n await client.execute(TOOLS_OWNER_INDEX_SQL);\n await client.execute(TOOLS_ORG_INDEX_SQL);\n await client.execute(TOOL_SHARES_RESOURCE_INDEX_SQL);\n // tool_consents was introduced for an audit-C1 per-viewer consent\n // gate that we removed once we settled on intra-org trust as the\n // baseline. The table is kept (additive — never drop) so deploys\n // that already created it stay healthy; the runtime consent code\n // is gone. Idempotent CREATE IF NOT EXISTS for fresh schemas.\n await client.execute(\n pg ? TOOL_CONSENTS_CREATE_SQL_PG : TOOL_CONSENTS_CREATE_SQL,\n );\n await client.execute(TOOL_CONSENTS_VIEWER_INDEX_SQL);\n })();\n }\n return _initPromise;\n}\n\nasync function ensureToolDataItemId(\n client: ReturnType<typeof getDbExec>,\n pg: boolean,\n): Promise<void> {\n if (pg) {\n await client.execute(\n `ALTER TABLE tool_data ADD COLUMN IF NOT EXISTS item_id TEXT`,\n );\n return;\n }\n\n // Keep this additive: legacy rows with item_id=id are still read correctly\n // through COALESCE(item_id, id), so SQLite never needs a table rebuild here.\n try {\n await client.execute(`ALTER TABLE tool_data ADD COLUMN item_id TEXT`);\n } catch (err: any) {\n if (\n !String(err?.message ?? err)\n .toLowerCase()\n .includes(\"duplicate\")\n ) {\n throw err;\n }\n }\n}\n\nasync function ensureToolDataScope(\n client: ReturnType<typeof getDbExec>,\n pg: boolean,\n): Promise<void> {\n const addCol = (name: string, def: string) => {\n if (pg) {\n return client.execute(\n `ALTER TABLE tool_data ADD COLUMN IF NOT EXISTS ${name} ${def}`,\n );\n }\n return client\n .execute(`ALTER TABLE tool_data ADD COLUMN ${name} ${def}`)\n .catch((err: any) => {\n if (\n !String(err?.message ?? err)\n .toLowerCase()\n .includes(\"duplicate\")\n )\n throw err;\n });\n };\n await addCol(\"scope\", \"TEXT NOT NULL DEFAULT 'user'\");\n await addCol(\"org_id\", \"TEXT\");\n await addCol(\"scope_key\", \"TEXT NOT NULL DEFAULT 'local@localhost'\");\n // One-time backfill migration: replaces the dev-mode DEFAULT scope_key\n // with each row's real owner_email. Not a per-request fallback.\n await client.execute(\n // guard:allow-localhost-fallback — one-time backfill migration replacing dev-mode default scope_key with the row's real owner_email\n `UPDATE tool_data SET scope_key = owner_email WHERE scope_key = 'local@localhost' AND owner_email != 'local@localhost'`,\n );\n}\n\nexport function registerToolsShareable() {\n registerShareableResource({\n type: \"tool\",\n resourceTable: tools,\n sharesTable: toolShares,\n displayName: \"Tool\",\n titleColumn: \"name\",\n getDb: () => getDb(),\n });\n}\n\nexport interface ToolRow {\n id: string;\n name: string;\n description: string;\n content: string;\n icon: string | null;\n createdAt: string;\n updatedAt: string;\n ownerEmail: string;\n orgId: string | null;\n visibility: \"private\" | \"org\" | \"public\";\n}\n\nexport async function listTools(): Promise<ToolRow[]> {\n await ensureToolsTables();\n const db = getDb();\n return db\n .select()\n .from(tools)\n .where(accessFilter(tools, toolShares)) as Promise<ToolRow[]>;\n}\n\nexport async function getTool(id: string): Promise<ToolRow | null> {\n await ensureToolsTables();\n const access = await resolveAccess(\"tool\", id);\n return (access?.resource as ToolRow | undefined) ?? null;\n}\n\nexport interface CreateToolData {\n name: string;\n description?: string;\n content?: string;\n icon?: string;\n}\n\nexport async function createTool(data: CreateToolData): Promise<ToolRow> {\n await ensureToolsTables();\n const db = getDb();\n const userEmail = getRequestUserEmail();\n if (!userEmail) throw new Error(\"no authenticated user\");\n const orgId = getRequestOrgId();\n const id = randomUUID();\n const now = new Date().toISOString();\n const row: ToolRow = {\n id,\n name: data.name,\n description: data.description ?? \"\",\n content: data.content ?? \"\",\n icon: data.icon ?? null,\n createdAt: now,\n updatedAt: now,\n ownerEmail: userEmail,\n orgId: orgId ?? null,\n visibility: \"private\",\n };\n await db.insert(tools).values(row);\n return row;\n}\n\nexport interface UpdateToolData {\n name?: string;\n description?: string;\n icon?: string;\n visibility?: \"private\" | \"org\" | \"public\";\n}\n\nexport async function updateTool(\n id: string,\n data: UpdateToolData,\n): Promise<ToolRow | null> {\n await ensureToolsTables();\n await assertAccess(\"tool\", id, \"editor\");\n const db = getDb();\n const updates: Record<string, unknown> = {\n updatedAt: new Date().toISOString(),\n };\n if (data.name !== undefined) updates.name = data.name;\n if (data.description !== undefined) updates.description = data.description;\n if (data.icon !== undefined) updates.icon = data.icon;\n if (data.visibility !== undefined) updates.visibility = data.visibility;\n await db.update(tools).set(updates).where(eq(tools.id, id));\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n return (rows[0] as ToolRow) ?? null;\n}\n\nexport interface UpdateToolContentOpts {\n content?: string;\n patches?: Array<{ find: string; replace: string }>;\n}\n\nexport async function updateToolContent(\n id: string,\n opts: UpdateToolContentOpts,\n): Promise<ToolRow | null> {\n await ensureToolsTables();\n await assertAccess(\"tool\", id, \"editor\");\n const db = getDb();\n\n let newContent: string;\n if (opts.content !== undefined) {\n newContent = opts.content;\n } else if (opts.patches) {\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n if (!rows[0]) return null;\n newContent = (rows[0] as ToolRow).content;\n for (const patch of opts.patches) {\n newContent = newContent.replace(patch.find, patch.replace);\n }\n } else {\n return null;\n }\n\n await db\n .update(tools)\n .set({ content: newContent, updatedAt: new Date().toISOString() })\n .where(eq(tools.id, id));\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n return (rows[0] as ToolRow) ?? null;\n}\n\nexport async function deleteTool(id: string): Promise<boolean> {\n await ensureToolsTables();\n await assertAccess(\"tool\", id, \"admin\");\n const db = getDb();\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n if (!rows[0]) return false;\n await db.delete(toolShares).where(eq(toolShares.resourceId, id));\n await getDbExec().execute({\n sql: `DELETE FROM tool_data WHERE tool_id = ?`,\n args: [id],\n });\n const { cascadeDeleteToolSlots } = await import(\"./slots/store.js\");\n await cascadeDeleteToolSlots(id);\n await db.delete(tools).where(eq(tools.id, id));\n return true;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/tools/store.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { eq } from \"drizzle-orm\";\nimport { getDbExec, isPostgres, retryOnDdlRace } from \"../db/client.js\";\nimport { createGetDb } from \"../db/create-get-db.js\";\nimport {\n accessFilter,\n assertAccess,\n resolveAccess,\n} from \"../sharing/access.js\";\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n} from \"../server/request-context.js\";\nimport { registerShareableResource } from \"../sharing/registry.js\";\nimport {\n tools,\n toolShares,\n TOOLS_CREATE_SQL,\n TOOLS_CREATE_SQL_PG,\n TOOL_SHARES_CREATE_SQL,\n TOOL_SHARES_CREATE_SQL_PG,\n TOOL_DATA_CREATE_SQL,\n TOOL_DATA_CREATE_SQL_PG,\n TOOL_DATA_ITEM_INDEX_SQL,\n TOOL_DATA_ITEM_INDEX_SQL_PG,\n TOOL_DATA_DROP_OLD_INDEX_SQL,\n TOOL_DATA_DROP_OLD_INDEX_SQL_PG,\n TOOLS_OWNER_INDEX_SQL,\n TOOLS_ORG_INDEX_SQL,\n TOOL_SHARES_RESOURCE_INDEX_SQL,\n TOOL_CONSENTS_CREATE_SQL,\n TOOL_CONSENTS_CREATE_SQL_PG,\n TOOL_CONSENTS_VIEWER_INDEX_SQL,\n} from \"./schema.js\";\n\nconst getDb = createGetDb({ tools, toolShares });\n\nlet _initPromise: Promise<void> | undefined;\n\nexport async function ensureToolsTables(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const pg = isPostgres();\n await retryOnDdlRace(() =>\n client.execute(pg ? TOOLS_CREATE_SQL_PG : TOOLS_CREATE_SQL),\n );\n await retryOnDdlRace(() =>\n client.execute(pg ? TOOL_SHARES_CREATE_SQL_PG : TOOL_SHARES_CREATE_SQL),\n );\n await retryOnDdlRace(() =>\n client.execute(pg ? TOOL_DATA_CREATE_SQL_PG : TOOL_DATA_CREATE_SQL),\n );\n await ensureToolDataItemId(client, pg);\n await ensureToolDataScope(client, pg);\n await client.execute(\n pg ? TOOL_DATA_DROP_OLD_INDEX_SQL_PG : TOOL_DATA_DROP_OLD_INDEX_SQL,\n );\n await retryOnDdlRace(() =>\n client.execute(\n pg ? TOOL_DATA_ITEM_INDEX_SQL_PG : TOOL_DATA_ITEM_INDEX_SQL,\n ),\n );\n await retryOnDdlRace(() => client.execute(TOOLS_OWNER_INDEX_SQL));\n await retryOnDdlRace(() => client.execute(TOOLS_ORG_INDEX_SQL));\n await retryOnDdlRace(() =>\n client.execute(TOOL_SHARES_RESOURCE_INDEX_SQL),\n );\n // tool_consents was introduced for an audit-C1 per-viewer consent\n // gate that we removed once we settled on intra-org trust as the\n // baseline. The table is kept (additive — never drop) so deploys\n // that already created it stay healthy; the runtime consent code\n // is gone. Idempotent CREATE IF NOT EXISTS for fresh schemas.\n await retryOnDdlRace(() =>\n client.execute(\n pg ? TOOL_CONSENTS_CREATE_SQL_PG : TOOL_CONSENTS_CREATE_SQL,\n ),\n );\n await retryOnDdlRace(() =>\n client.execute(TOOL_CONSENTS_VIEWER_INDEX_SQL),\n );\n })();\n }\n return _initPromise;\n}\n\nasync function ensureToolDataItemId(\n client: ReturnType<typeof getDbExec>,\n pg: boolean,\n): Promise<void> {\n if (pg) {\n await client.execute(\n `ALTER TABLE tool_data ADD COLUMN IF NOT EXISTS item_id TEXT`,\n );\n return;\n }\n\n // Keep this additive: legacy rows with item_id=id are still read correctly\n // through COALESCE(item_id, id), so SQLite never needs a table rebuild here.\n try {\n await client.execute(`ALTER TABLE tool_data ADD COLUMN item_id TEXT`);\n } catch (err: any) {\n if (\n !String(err?.message ?? err)\n .toLowerCase()\n .includes(\"duplicate\")\n ) {\n throw err;\n }\n }\n}\n\nasync function ensureToolDataScope(\n client: ReturnType<typeof getDbExec>,\n pg: boolean,\n): Promise<void> {\n const addCol = (name: string, def: string) => {\n if (pg) {\n return client.execute(\n `ALTER TABLE tool_data ADD COLUMN IF NOT EXISTS ${name} ${def}`,\n );\n }\n return client\n .execute(`ALTER TABLE tool_data ADD COLUMN ${name} ${def}`)\n .catch((err: any) => {\n if (\n !String(err?.message ?? err)\n .toLowerCase()\n .includes(\"duplicate\")\n )\n throw err;\n });\n };\n await addCol(\"scope\", \"TEXT NOT NULL DEFAULT 'user'\");\n await addCol(\"org_id\", \"TEXT\");\n await addCol(\"scope_key\", \"TEXT NOT NULL DEFAULT 'local@localhost'\");\n // One-time backfill migration: replaces the dev-mode DEFAULT scope_key\n // with each row's real owner_email. Not a per-request fallback.\n await client.execute(\n // guard:allow-localhost-fallback — one-time backfill migration replacing dev-mode default scope_key with the row's real owner_email\n `UPDATE tool_data SET scope_key = owner_email WHERE scope_key = 'local@localhost' AND owner_email != 'local@localhost'`,\n );\n}\n\nexport function registerToolsShareable() {\n registerShareableResource({\n type: \"tool\",\n resourceTable: tools,\n sharesTable: toolShares,\n displayName: \"Tool\",\n titleColumn: \"name\",\n getDb: () => getDb(),\n });\n}\n\nexport interface ToolRow {\n id: string;\n name: string;\n description: string;\n content: string;\n icon: string | null;\n createdAt: string;\n updatedAt: string;\n ownerEmail: string;\n orgId: string | null;\n visibility: \"private\" | \"org\" | \"public\";\n}\n\nexport async function listTools(): Promise<ToolRow[]> {\n await ensureToolsTables();\n const db = getDb();\n return db\n .select()\n .from(tools)\n .where(accessFilter(tools, toolShares)) as Promise<ToolRow[]>;\n}\n\nexport async function getTool(id: string): Promise<ToolRow | null> {\n await ensureToolsTables();\n const access = await resolveAccess(\"tool\", id);\n return (access?.resource as ToolRow | undefined) ?? null;\n}\n\nexport interface CreateToolData {\n name: string;\n description?: string;\n content?: string;\n icon?: string;\n}\n\nexport async function createTool(data: CreateToolData): Promise<ToolRow> {\n await ensureToolsTables();\n const db = getDb();\n const userEmail = getRequestUserEmail();\n if (!userEmail) throw new Error(\"no authenticated user\");\n const orgId = getRequestOrgId();\n const id = randomUUID();\n const now = new Date().toISOString();\n const row: ToolRow = {\n id,\n name: data.name,\n description: data.description ?? \"\",\n content: data.content ?? \"\",\n icon: data.icon ?? null,\n createdAt: now,\n updatedAt: now,\n ownerEmail: userEmail,\n orgId: orgId ?? null,\n // Default to org-visibility when the user has an active organization so\n // teammates see the tool in their sidebar — matching how analytics\n // dashboards/analyses are scoped (`templates/analytics/server/lib/\n // dashboards-store.ts:356`). Solo users (no org) get the private\n // default. Owners can still flip back to private via update-tool.\n visibility: orgId ? \"org\" : \"private\",\n };\n await db.insert(tools).values(row);\n return row;\n}\n\nexport interface UpdateToolData {\n name?: string;\n description?: string;\n icon?: string;\n visibility?: \"private\" | \"org\" | \"public\";\n}\n\nexport async function updateTool(\n id: string,\n data: UpdateToolData,\n): Promise<ToolRow | null> {\n await ensureToolsTables();\n await assertAccess(\"tool\", id, \"editor\");\n const db = getDb();\n const updates: Record<string, unknown> = {\n updatedAt: new Date().toISOString(),\n };\n if (data.name !== undefined) updates.name = data.name;\n if (data.description !== undefined) updates.description = data.description;\n if (data.icon !== undefined) updates.icon = data.icon;\n if (data.visibility !== undefined) updates.visibility = data.visibility;\n await db.update(tools).set(updates).where(eq(tools.id, id));\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n return (rows[0] as ToolRow) ?? null;\n}\n\nexport interface UpdateToolContentOpts {\n content?: string;\n patches?: Array<{ find: string; replace: string }>;\n}\n\nexport async function updateToolContent(\n id: string,\n opts: UpdateToolContentOpts,\n): Promise<ToolRow | null> {\n await ensureToolsTables();\n await assertAccess(\"tool\", id, \"editor\");\n const db = getDb();\n\n let newContent: string;\n if (opts.content !== undefined) {\n newContent = opts.content;\n } else if (opts.patches) {\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n if (!rows[0]) return null;\n newContent = (rows[0] as ToolRow).content;\n for (const patch of opts.patches) {\n newContent = newContent.replace(patch.find, patch.replace);\n }\n } else {\n return null;\n }\n\n await db\n .update(tools)\n .set({ content: newContent, updatedAt: new Date().toISOString() })\n .where(eq(tools.id, id));\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n return (rows[0] as ToolRow) ?? null;\n}\n\nexport async function deleteTool(id: string): Promise<boolean> {\n await ensureToolsTables();\n await assertAccess(\"tool\", id, \"admin\");\n const db = getDb();\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n if (!rows[0]) return false;\n await db.delete(toolShares).where(eq(toolShares.resourceId, id));\n await getDbExec().execute({\n sql: `DELETE FROM tool_data WHERE tool_id = ?`,\n args: [id],\n });\n const { cascadeDeleteToolSlots } = await import(\"./slots/store.js\");\n await cascadeDeleteToolSlots(id);\n await db.delete(tools).where(eq(tools.id, id));\n return true;\n}\n"]}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* POSTHOG_API_KEY + POSTHOG_HOST → PostHog
|
|
8
8
|
* MIXPANEL_TOKEN → Mixpanel
|
|
9
9
|
* AMPLITUDE_API_KEY → Amplitude
|
|
10
|
+
* AGENT_NATIVE_ANALYTICS_PUBLIC_KEY → Agent Native Analytics
|
|
10
11
|
*
|
|
11
12
|
* Call `registerBuiltinProviders()` at server startup (done
|
|
12
13
|
* automatically by the core-routes plugin).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/tracking/providers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/tracking/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAmTH,wBAAgB,wBAAwB,IAAI,IAAI,CA6C/C"}
|
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
* POSTHOG_API_KEY + POSTHOG_HOST → PostHog
|
|
8
8
|
* MIXPANEL_TOKEN → Mixpanel
|
|
9
9
|
* AMPLITUDE_API_KEY → Amplitude
|
|
10
|
+
* AGENT_NATIVE_ANALYTICS_PUBLIC_KEY → Agent Native Analytics
|
|
10
11
|
*
|
|
11
12
|
* Call `registerBuiltinProviders()` at server startup (done
|
|
12
13
|
* automatically by the core-routes plugin).
|
|
13
14
|
*/
|
|
14
15
|
import { registerTrackingProvider } from "./registry.js";
|
|
15
16
|
const POSTHOG_DEFAULT_HOST = "https://us.i.posthog.com";
|
|
17
|
+
const AGENT_NATIVE_ANALYTICS_DEFAULT_ENDPOINT = "https://analytics.agent-native.com/track";
|
|
16
18
|
const BATCH_INTERVAL_MS = 10_000;
|
|
17
19
|
const MAX_BATCH_SIZE = 50;
|
|
18
20
|
// Use globalThis so multiple ESM graph instances (Vite dev + Nitro symlinks)
|
|
@@ -58,6 +60,42 @@ function drainQueue() {
|
|
|
58
60
|
}).catch(() => { });
|
|
59
61
|
}
|
|
60
62
|
}
|
|
63
|
+
function isLocalhostUrl(value) {
|
|
64
|
+
if (!value || !value.trim())
|
|
65
|
+
return false;
|
|
66
|
+
const raw = value.trim();
|
|
67
|
+
const withProtocol = /^[a-z][a-z0-9+.-]*:\/\//i.test(raw)
|
|
68
|
+
? raw
|
|
69
|
+
: `https://${raw}`;
|
|
70
|
+
try {
|
|
71
|
+
const { hostname } = new URL(withProtocol);
|
|
72
|
+
const h = hostname.toLowerCase();
|
|
73
|
+
return (h === "localhost" ||
|
|
74
|
+
h === "127.0.0.1" ||
|
|
75
|
+
h === "::1" ||
|
|
76
|
+
h === "[::1]" ||
|
|
77
|
+
h.endsWith(".localhost") ||
|
|
78
|
+
h.endsWith(".local"));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function shouldSkipAgentNativeAnalyticsForLocalhost() {
|
|
85
|
+
if (process.env.AGENT_NATIVE_ANALYTICS_ALLOW_LOCALHOST === "true") {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
if (process.env.NODE_ENV === "development")
|
|
89
|
+
return true;
|
|
90
|
+
return [
|
|
91
|
+
process.env.APP_URL,
|
|
92
|
+
process.env.BETTER_AUTH_URL,
|
|
93
|
+
process.env.URL,
|
|
94
|
+
process.env.DEPLOY_URL,
|
|
95
|
+
process.env.VERCEL_PROJECT_PRODUCTION_URL,
|
|
96
|
+
process.env.VERCEL_URL,
|
|
97
|
+
].some(isLocalhostUrl);
|
|
98
|
+
}
|
|
61
99
|
// ─── PostHog ───────────────────────────────────────────────────────────────
|
|
62
100
|
function createPostHogProvider(apiKey, host) {
|
|
63
101
|
return {
|
|
@@ -185,6 +223,34 @@ function createWebhookProvider(url, authHeader) {
|
|
|
185
223
|
},
|
|
186
224
|
};
|
|
187
225
|
}
|
|
226
|
+
// ─── Agent Native Analytics ───────────────────────────────────────────────
|
|
227
|
+
function createAgentNativeAnalyticsProvider(publicKey, endpoint) {
|
|
228
|
+
return {
|
|
229
|
+
name: "agent-native-analytics",
|
|
230
|
+
track(event) {
|
|
231
|
+
enqueue(endpoint, JSON.stringify({
|
|
232
|
+
publicKey,
|
|
233
|
+
event: event.name,
|
|
234
|
+
properties: event.properties ?? {},
|
|
235
|
+
userId: event.userId,
|
|
236
|
+
timestamp: event.timestamp,
|
|
237
|
+
}));
|
|
238
|
+
},
|
|
239
|
+
identify(userId, traits) {
|
|
240
|
+
enqueue(endpoint, JSON.stringify({
|
|
241
|
+
publicKey,
|
|
242
|
+
event: "$identify",
|
|
243
|
+
userId,
|
|
244
|
+
properties: traits ?? {},
|
|
245
|
+
timestamp: new Date().toISOString(),
|
|
246
|
+
}));
|
|
247
|
+
},
|
|
248
|
+
flush: () => {
|
|
249
|
+
drainQueue();
|
|
250
|
+
return Promise.resolve();
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
}
|
|
188
254
|
// ─── Auto-registration ────────────────────────────────────────────────────
|
|
189
255
|
let _registered = false;
|
|
190
256
|
export function registerBuiltinProviders() {
|
|
@@ -204,6 +270,12 @@ export function registerBuiltinProviders() {
|
|
|
204
270
|
if (amplitudeKey) {
|
|
205
271
|
registerTrackingProvider(createAmplitudeProvider(amplitudeKey));
|
|
206
272
|
}
|
|
273
|
+
const agentNativeAnalyticsKey = process.env.AGENT_NATIVE_ANALYTICS_PUBLIC_KEY;
|
|
274
|
+
if (agentNativeAnalyticsKey &&
|
|
275
|
+
!shouldSkipAgentNativeAnalyticsForLocalhost()) {
|
|
276
|
+
registerTrackingProvider(createAgentNativeAnalyticsProvider(agentNativeAnalyticsKey, (process.env.AGENT_NATIVE_ANALYTICS_ENDPOINT ||
|
|
277
|
+
AGENT_NATIVE_ANALYTICS_DEFAULT_ENDPOINT).replace(/\/+$/, "")));
|
|
278
|
+
}
|
|
207
279
|
const webhookUrl = process.env.TRACKING_WEBHOOK_URL;
|
|
208
280
|
if (webhookUrl) {
|
|
209
281
|
registerTrackingProvider(createWebhookProvider(webhookUrl, process.env.TRACKING_WEBHOOK_AUTH));
|