@agent-native/core 0.107.2 → 0.109.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +24 -0
- package/corpus/core/docs/content/actions.mdx +48 -0
- package/corpus/core/docs/content/locales/ar-SA/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/de-DE/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/es-ES/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/fr-FR/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/hi-IN/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/ja-JP/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/ko-KR/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/pt-BR/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/zh-CN/actions.mdx +38 -0
- package/corpus/core/docs/content/locales/zh-TW/actions.mdx +38 -0
- package/corpus/core/package.json +5 -1
- package/corpus/core/src/a2a/client.ts +140 -17
- package/corpus/core/src/a2a/handlers.ts +60 -0
- package/corpus/core/src/a2a/index.ts +6 -1
- package/corpus/core/src/a2a/invoke.ts +68 -1
- package/corpus/core/src/a2a/server.ts +13 -1
- package/corpus/core/src/a2a/types.ts +16 -0
- package/corpus/core/src/a2a-claims.ts +52 -0
- package/corpus/core/src/action.ts +7 -2
- package/corpus/core/src/agent/production-agent.ts +10 -4
- package/corpus/core/src/audit/record.ts +6 -0
- package/corpus/core/src/client/AssistantChat.tsx +648 -603
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
- package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
- package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
- package/corpus/core/src/client/analytics.ts +84 -0
- package/corpus/core/src/client/chat/message-components.tsx +94 -22
- package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
- package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
- package/corpus/core/src/client/chat-thread-url.ts +11 -0
- package/corpus/core/src/client/error-capture.ts +12 -0
- package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
- package/corpus/core/src/client/feature-flags/FeatureFlagsPanel.tsx +519 -0
- package/corpus/core/src/client/feature-flags/helpers.ts +77 -0
- package/corpus/core/src/client/feature-flags/index.ts +13 -0
- package/corpus/core/src/client/feature-flags/types.ts +29 -0
- package/corpus/core/src/client/feature-flags/use-feature-flag.ts +26 -0
- package/corpus/core/src/client/index.ts +13 -0
- package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
- package/corpus/core/src/client/session-replay.ts +31 -0
- package/corpus/core/src/extensions/actions.ts +2 -14
- package/corpus/core/src/extensions/routes.ts +1 -1
- package/corpus/core/src/extensions/store.ts +1 -1
- package/corpus/core/src/feature-flags/a2a-action-route.ts +56 -0
- package/corpus/core/src/feature-flags/actions/get-feature-flags.ts +24 -0
- package/corpus/core/src/feature-flags/actions/list-feature-flags.ts +69 -0
- package/corpus/core/src/feature-flags/actions/set-feature-flag.ts +89 -0
- package/corpus/core/src/feature-flags/index.ts +21 -0
- package/corpus/core/src/feature-flags/permissions.ts +53 -0
- package/corpus/core/src/feature-flags/plugin.ts +44 -0
- package/corpus/core/src/feature-flags/registry.ts +96 -0
- package/corpus/core/src/feature-flags/store.ts +176 -0
- package/corpus/core/src/index.ts +15 -0
- package/corpus/core/src/localization/default-messages.ts +50 -0
- package/corpus/core/src/mcp/build-server.ts +2 -2
- package/corpus/core/src/progress/actions.ts +4 -2
- package/corpus/core/src/provider-api/index.ts +205 -105
- package/corpus/core/src/scripts/call-agent.ts +137 -17
- package/corpus/core/src/server/action-discovery.ts +12 -0
- package/corpus/core/src/server/action-routes.ts +47 -5
- package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +40 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +31 -0
- package/corpus/core/src/server/index.ts +1 -0
- package/corpus/core/src/settings/org-settings.ts +13 -0
- package/corpus/core/src/settings/store.ts +57 -0
- package/corpus/core/src/styles/agent-conversation.css +7 -0
- package/corpus/core/src/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/core/src/templates/default/AGENTS.md +1 -0
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/corpus/core/src/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/corpus/core/src/templates/workspace-core/AGENTS.md +1 -1
- package/corpus/core/src/templates/workspace-root/AGENTS.md +1 -1
- package/corpus/core/src/vite/action-types-plugin.ts +12 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
- package/corpus/templates/analytics/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
- package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
- package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
- package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
- package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
- package/corpus/templates/analytics/AGENTS.md +37 -16
- package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
- package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
- package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
- package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
- package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
- package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
- package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
- package/corpus/templates/analytics/actions/list-workspace-feature-flags.ts +15 -0
- package/corpus/templates/analytics/actions/navigate.ts +2 -2
- package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
- package/corpus/templates/analytics/actions/set-workspace-feature-flag.ts +45 -0
- package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
- package/corpus/templates/analytics/actions/view-screen.ts +13 -0
- package/corpus/templates/analytics/app/components/agents/FeatureFlagsFleetPanel.tsx +243 -0
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +11 -3
- package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
- package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +3 -1
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +30 -0
- package/corpus/templates/analytics/app/i18n-data.ts +385 -0
- package/corpus/templates/analytics/app/pages/Agents.tsx +22 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
- package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-manage-feature-flag-rollouts-across-your-organization-s-apps.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
- package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
- package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
- package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
- package/corpus/templates/analytics/server/lib/db-admin-connections.ts +13 -5
- package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
- package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
- package/corpus/templates/analytics/server/lib/gong.ts +54 -66
- package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
- package/corpus/templates/analytics/server/lib/notion.ts +83 -8
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
- package/corpus/templates/analytics/server/lib/slack.ts +242 -90
- package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +347 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
- package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
- package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
- package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
- package/corpus/templates/assets/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/brain/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/calendar/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/clips/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
- package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
- package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
- package/corpus/templates/clips/app/entry.client.tsx +6 -1
- package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
- package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
- package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
- package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
- package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
- package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
- package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
- package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
- package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
- package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
- package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +1 -1
- package/corpus/templates/clips/server/plugins/feature-flags.ts +11 -0
- package/corpus/templates/clips/shared/feature-flags.ts +30 -37
- package/corpus/templates/content/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/content/app/entry.client.tsx +6 -1
- package/corpus/templates/design/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/design/AGENTS.md +5 -3
- package/corpus/templates/design/actions/add-fusion-screens.ts +4 -6
- package/corpus/templates/design/actions/apply-fusion-edits.ts +4 -6
- package/corpus/templates/design/actions/create-fusion-app.ts +5 -4
- package/corpus/templates/design/actions/deploy-fusion-app.ts +4 -3
- package/corpus/templates/design/actions/get-fusion-deploy-status.ts +4 -6
- package/corpus/templates/design/actions/list-fusion-edits.ts +4 -3
- package/corpus/templates/design/actions/push-fusion-app.ts +4 -6
- package/corpus/templates/design/actions/queue-fusion-edit.ts +4 -3
- package/corpus/templates/design/actions/send-fusion-message.ts +4 -6
- package/corpus/templates/design/actions/sync-fusion-app.ts +4 -3
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +1 -1
- package/corpus/templates/design/app/pages/Index.tsx +8 -6
- package/corpus/templates/design/server/plugins/feature-flags.ts +5 -0
- package/corpus/templates/design/shared/full-app.ts +10 -7
- package/corpus/templates/dispatch/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/dispatch/AGENTS.md +5 -0
- package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
- package/corpus/templates/forms/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/macros/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/mail/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/mail/app/entry.client.tsx +6 -1
- package/corpus/templates/plan/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/slides/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
- package/corpus/templates/slides/.env.example +0 -1
- package/corpus/templates/slides/AGENTS.md +4 -0
- package/corpus/templates/slides/DEVELOPING.md +2 -2
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
- package/corpus/templates/slides/actions/logo-config.ts +6 -7
- package/corpus/templates/slides/actions/search-images.ts +11 -39
- package/corpus/templates/slides/actions/search-logos.ts +5 -52
- package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
- package/corpus/templates/slides/app/entry.client.tsx +6 -1
- package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
- package/corpus/templates/slides/server/register-secrets.ts +30 -0
- package/corpus/templates/tasks/.agents/skills/feature-flags/SKILL.md +169 -0
- package/dist/a2a/client.d.ts +38 -1
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +81 -12
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +47 -0
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/index.d.ts +4 -4
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +2 -2
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/invoke.d.ts +26 -2
- package/dist/a2a/invoke.d.ts.map +1 -1
- package/dist/a2a/invoke.js +30 -1
- package/dist/a2a/invoke.js.map +1 -1
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +14 -1
- package/dist/a2a/server.js.map +1 -1
- package/dist/a2a/types.d.ts +12 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/a2a-claims.d.ts +10 -0
- package/dist/a2a-claims.d.ts.map +1 -0
- package/dist/a2a-claims.js +41 -0
- package/dist/a2a-claims.js.map +1 -0
- package/dist/action.d.ts +7 -2
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js.map +1 -1
- package/dist/agent/production-agent.d.ts +5 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +5 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/audit/record.d.ts +3 -0
- package/dist/audit/record.d.ts.map +1 -1
- package/dist/audit/record.js +3 -0
- package/dist/audit/record.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +14 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +158 -136
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +27 -4
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +21 -39
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-sidebar-state.d.ts +1 -0
- package/dist/client/agent-sidebar-state.d.ts.map +1 -1
- package/dist/client/agent-sidebar-state.js +4 -0
- package/dist/client/agent-sidebar-state.js.map +1 -1
- package/dist/client/analytics.d.ts +14 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +67 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +8 -0
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +62 -19
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +6 -0
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +83 -14
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
- package/dist/client/chat-thread-url.d.ts +2 -0
- package/dist/client/chat-thread-url.d.ts.map +1 -0
- package/dist/client/chat-thread-url.js +12 -0
- package/dist/client/chat-thread-url.js.map +1 -0
- package/dist/client/error-capture.d.ts.map +1 -1
- package/dist/client/error-capture.js +7 -0
- package/dist/client/error-capture.js.map +1 -1
- package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
- package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionSlot.js +28 -3
- package/dist/client/extensions/ExtensionSlot.js.map +1 -1
- package/dist/client/feature-flags/FeatureFlagsPanel.d.ts +10 -0
- package/dist/client/feature-flags/FeatureFlagsPanel.d.ts.map +1 -0
- package/dist/client/feature-flags/FeatureFlagsPanel.js +143 -0
- package/dist/client/feature-flags/FeatureFlagsPanel.js.map +1 -0
- package/dist/client/feature-flags/helpers.d.ts +16 -0
- package/dist/client/feature-flags/helpers.d.ts.map +1 -0
- package/dist/client/feature-flags/helpers.js +50 -0
- package/dist/client/feature-flags/helpers.js.map +1 -0
- package/dist/client/feature-flags/index.d.ts +5 -0
- package/dist/client/feature-flags/index.d.ts.map +1 -0
- package/dist/client/feature-flags/index.js +4 -0
- package/dist/client/feature-flags/index.js.map +1 -0
- package/dist/client/feature-flags/types.d.ts +27 -0
- package/dist/client/feature-flags/types.d.ts.map +1 -0
- package/dist/client/feature-flags/types.js +2 -0
- package/dist/client/feature-flags/types.js.map +1 -0
- package/dist/client/feature-flags/use-feature-flag.d.ts +8 -0
- package/dist/client/feature-flags/use-feature-flag.d.ts.map +1 -0
- package/dist/client/feature-flags/use-feature-flag.js +15 -0
- package/dist/client/feature-flags/use-feature-flag.js.map +1 -0
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/route-chunk-recovery.d.ts.map +1 -1
- package/dist/client/route-chunk-recovery.js +14 -9
- package/dist/client/route-chunk-recovery.js.map +1 -1
- package/dist/client/session-replay.d.ts +15 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +20 -0
- package/dist/client/session-replay.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/extensions/actions.d.ts.map +1 -1
- package/dist/extensions/actions.js +2 -10
- package/dist/extensions/actions.js.map +1 -1
- package/dist/extensions/routes.d.ts.map +1 -1
- package/dist/extensions/routes.js +1 -1
- package/dist/extensions/routes.js.map +1 -1
- package/dist/extensions/store.js +1 -1
- package/dist/extensions/store.js.map +1 -1
- package/dist/feature-flags/a2a-action-route.d.ts +14 -0
- package/dist/feature-flags/a2a-action-route.d.ts.map +1 -0
- package/dist/feature-flags/a2a-action-route.js +50 -0
- package/dist/feature-flags/a2a-action-route.js.map +1 -0
- package/dist/feature-flags/actions/get-feature-flags.d.ts +3 -0
- package/dist/feature-flags/actions/get-feature-flags.d.ts.map +1 -0
- package/dist/feature-flags/actions/get-feature-flags.js +18 -0
- package/dist/feature-flags/actions/get-feature-flags.js.map +1 -0
- package/dist/feature-flags/actions/list-feature-flags.d.ts +28 -0
- package/dist/feature-flags/actions/list-feature-flags.d.ts.map +1 -0
- package/dist/feature-flags/actions/list-feature-flags.js +60 -0
- package/dist/feature-flags/actions/list-feature-flags.js.map +1 -0
- package/dist/feature-flags/actions/set-feature-flag.d.ts +26 -0
- package/dist/feature-flags/actions/set-feature-flag.d.ts.map +1 -0
- package/dist/feature-flags/actions/set-feature-flag.js +78 -0
- package/dist/feature-flags/actions/set-feature-flag.js.map +1 -0
- package/dist/feature-flags/index.d.ts +5 -0
- package/dist/feature-flags/index.d.ts.map +1 -0
- package/dist/feature-flags/index.js +5 -0
- package/dist/feature-flags/index.js.map +1 -0
- package/dist/feature-flags/permissions.d.ts +13 -0
- package/dist/feature-flags/permissions.d.ts.map +1 -0
- package/dist/feature-flags/permissions.js +37 -0
- package/dist/feature-flags/permissions.js.map +1 -0
- package/dist/feature-flags/plugin.d.ts +17 -0
- package/dist/feature-flags/plugin.d.ts.map +1 -0
- package/dist/feature-flags/plugin.js +29 -0
- package/dist/feature-flags/plugin.js.map +1 -0
- package/dist/feature-flags/registry.d.ts +23 -0
- package/dist/feature-flags/registry.d.ts.map +1 -0
- package/dist/feature-flags/registry.js +59 -0
- package/dist/feature-flags/registry.js.map +1 -0
- package/dist/feature-flags/store.d.ts +31 -0
- package/dist/feature-flags/store.d.ts.map +1 -0
- package/dist/feature-flags/store.js +124 -0
- package/dist/feature-flags/store.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/localization/default-messages.d.ts +45 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +45 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/build-server.d.ts +2 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +2 -2
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/progress/actions.d.ts.map +1 -1
- package/dist/progress/actions.js +3 -2
- package/dist/progress/actions.js.map +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +91 -8
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +107 -16
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +12 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/action-routes.d.ts +3 -0
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +45 -5
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.d.ts +6 -0
- package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +27 -0
- package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +27 -1
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/settings/org-settings.d.ts +2 -0
- package/dist/settings/org-settings.d.ts.map +1 -1
- package/dist/settings/org-settings.js +5 -1
- package/dist/settings/org-settings.js.map +1 -1
- package/dist/settings/store.d.ts +8 -0
- package/dist/settings/store.d.ts.map +1 -1
- package/dist/settings/store.js +48 -0
- package/dist/settings/store.js.map +1 -1
- package/dist/styles/agent-conversation.css +7 -0
- package/dist/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
- package/dist/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
- package/dist/templates/default/AGENTS.md +1 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
- package/dist/templates/default/app/i18n/de-DE.ts +20 -0
- package/dist/templates/default/app/i18n/en-US.ts +20 -0
- package/dist/templates/default/app/i18n/es-ES.ts +20 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
- package/dist/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
- package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/dist/templates/workspace-core/AGENTS.md +1 -1
- package/dist/templates/workspace-root/AGENTS.md +1 -1
- package/dist/vite/action-types-plugin.d.ts.map +1 -1
- package/dist/vite/action-types-plugin.js +12 -0
- package/dist/vite/action-types-plugin.js.map +1 -1
- package/docs/content/actions.mdx +48 -0
- package/docs/content/locales/ar-SA/actions.mdx +38 -0
- package/docs/content/locales/de-DE/actions.mdx +38 -0
- package/docs/content/locales/es-ES/actions.mdx +38 -0
- package/docs/content/locales/fr-FR/actions.mdx +38 -0
- package/docs/content/locales/hi-IN/actions.mdx +38 -0
- package/docs/content/locales/ja-JP/actions.mdx +38 -0
- package/docs/content/locales/ko-KR/actions.mdx +38 -0
- package/docs/content/locales/pt-BR/actions.mdx +38 -0
- package/docs/content/locales/zh-CN/actions.mdx +38 -0
- package/docs/content/locales/zh-TW/actions.mdx +38 -0
- package/package.json +5 -1
- package/src/templates/chat/.agents/skills/feature-flags/SKILL.md +169 -0
- package/src/templates/default/.agents/skills/feature-flags/SKILL.md +169 -0
- package/src/templates/default/AGENTS.md +1 -0
- package/src/templates/default/app/i18n/ar-SA.ts +20 -0
- package/src/templates/default/app/i18n/de-DE.ts +20 -0
- package/src/templates/default/app/i18n/en-US.ts +20 -0
- package/src/templates/default/app/i18n/es-ES.ts +20 -0
- package/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/src/templates/default/app/i18n/hi-IN.ts +19 -0
- package/src/templates/default/app/i18n/ja-JP.ts +20 -0
- package/src/templates/default/app/i18n/ko-KR.ts +19 -0
- package/src/templates/default/app/i18n/pt-BR.ts +20 -0
- package/src/templates/default/app/i18n/zh-CN.ts +19 -0
- package/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/src/templates/headless/.agents/skills/feature-flags/SKILL.md +169 -0
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +28 -0
- package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/feature-flags/SKILL.md +169 -0
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/src/templates/workspace-core/AGENTS.md +1 -1
- package/src/templates/workspace-root/AGENTS.md +1 -1
- package/corpus/templates/analytics/server/handlers/github.ts +0 -200
- package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
- package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
- package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
- package/corpus/templates/analytics/server/lib/github.ts +0 -660
- package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
- package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
- package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
- package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
- package/corpus/templates/clips/actions/get-feature-flags.ts +0 -30
- package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
- package/corpus/templates/slides/actions/image-search.ts +0 -64
- package/corpus/templates/slides/actions/import-github.ts +0 -182
- package/corpus/templates/slides/actions/logo-lookup.ts +0 -113
|
@@ -201,6 +201,17 @@ function recoverToIntendedNavigation(
|
|
|
201
201
|
return true;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
function recoverFromDynamicImportFailure(
|
|
205
|
+
win: Window,
|
|
206
|
+
state: RouteChunkRecoveryState,
|
|
207
|
+
message: string,
|
|
208
|
+
): boolean {
|
|
209
|
+
if (!isDynamicImportFailureMessage(message)) return false;
|
|
210
|
+
state.routeModuleFailureAt = Date.now();
|
|
211
|
+
if (recoverToIntendedNavigation(win, state)) return true;
|
|
212
|
+
return reloadForStaleChunk(win);
|
|
213
|
+
}
|
|
214
|
+
|
|
204
215
|
function patchHistoryMethod(
|
|
205
216
|
win: Window,
|
|
206
217
|
state: RouteChunkRecoveryState,
|
|
@@ -290,16 +301,17 @@ export function installRouteChunkRecovery(
|
|
|
290
301
|
win.addEventListener("unhandledrejection", (event) => {
|
|
291
302
|
const reason = (event as PromiseRejectionEvent).reason;
|
|
292
303
|
const message = String(reason?.message || reason || "");
|
|
293
|
-
if (
|
|
294
|
-
state.routeModuleFailureAt = Date.now();
|
|
295
|
-
if (recoverToIntendedNavigation(win, state)) {
|
|
304
|
+
if (recoverFromDynamicImportFailure(win, state, message)) {
|
|
296
305
|
event.preventDefault();
|
|
297
|
-
return;
|
|
298
306
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
win.addEventListener("error", (event) => {
|
|
310
|
+
const errorEvent = event as ErrorEvent;
|
|
311
|
+
const message = String(
|
|
312
|
+
errorEvent.error?.message || errorEvent.message || "",
|
|
313
|
+
);
|
|
314
|
+
if (recoverFromDynamicImportFailure(win, state, message)) {
|
|
303
315
|
event.preventDefault();
|
|
304
316
|
}
|
|
305
317
|
});
|
|
@@ -390,6 +390,8 @@ const SESSION_REPLAY_CLAIM_TIMEOUT_MS = 150;
|
|
|
390
390
|
export const SESSION_REPLAY_CONSOLE_EVENT_TAG = "agent-native.console";
|
|
391
391
|
/** rrweb custom-event tag for captured fetch/XHR request summaries. */
|
|
392
392
|
export const SESSION_REPLAY_NETWORK_EVENT_TAG = "agent-native.network";
|
|
393
|
+
/** Content-free agent-chat lifecycle markers for replay incident forensics. */
|
|
394
|
+
export const SESSION_REPLAY_AGENT_CHAT_EVENT_TAG = "agent-native.chat";
|
|
393
395
|
|
|
394
396
|
const DEFAULT_MAX_CONSOLE_EVENTS = 1000;
|
|
395
397
|
const DEFAULT_MAX_NETWORK_EVENTS = 2000;
|
|
@@ -3384,3 +3386,32 @@ export function emitSessionReplayException(input: {
|
|
|
3384
3386
|
...(input.url ? { url: input.url } : {}),
|
|
3385
3387
|
});
|
|
3386
3388
|
}
|
|
3389
|
+
|
|
3390
|
+
export type SessionReplayAgentChatEvent = {
|
|
3391
|
+
phase: "surface-mounted" | "run-observed" | "run-stopped";
|
|
3392
|
+
surface: string;
|
|
3393
|
+
threadId?: string;
|
|
3394
|
+
runId?: string;
|
|
3395
|
+
tabId?: string;
|
|
3396
|
+
};
|
|
3397
|
+
|
|
3398
|
+
/**
|
|
3399
|
+
* Add a content-free chat lifecycle marker to the active replay. The payload
|
|
3400
|
+
* deliberately accepts only ids and low-cardinality state; prompt/response
|
|
3401
|
+
* content must never enter replay diagnostics through this path.
|
|
3402
|
+
*/
|
|
3403
|
+
export function emitSessionReplayAgentChatEvent(
|
|
3404
|
+
input: SessionReplayAgentChatEvent,
|
|
3405
|
+
): void {
|
|
3406
|
+
const state = getState();
|
|
3407
|
+
if (!state.active || !state.addCustomEvent) return;
|
|
3408
|
+
const bounded = (value: string | undefined, max = 160) =>
|
|
3409
|
+
value?.trim().slice(0, max) || undefined;
|
|
3410
|
+
emitReplayCustomEvent(state, SESSION_REPLAY_AGENT_CHAT_EVENT_TAG, {
|
|
3411
|
+
phase: input.phase,
|
|
3412
|
+
surface: bounded(input.surface, 80) ?? "app",
|
|
3413
|
+
...(bounded(input.threadId) ? { threadId: bounded(input.threadId) } : {}),
|
|
3414
|
+
...(bounded(input.runId) ? { runId: bounded(input.runId) } : {}),
|
|
3415
|
+
...(bounded(input.tabId) ? { tabId: bounded(input.tabId) } : {}),
|
|
3416
|
+
});
|
|
3417
|
+
}
|
|
@@ -727,20 +727,8 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
|
|
|
727
727
|
!coerceBoolean(args?.allowFullReplacement)
|
|
728
728
|
) {
|
|
729
729
|
const message =
|
|
730
|
-
"Full extension-body replacement
|
|
731
|
-
throw new
|
|
732
|
-
errorCode: "extension_full_replacement_requires_explicit_intent",
|
|
733
|
-
toolResult: JSON.stringify(
|
|
734
|
-
{
|
|
735
|
-
error: "extension_full_replacement_requires_explicit_intent",
|
|
736
|
-
message,
|
|
737
|
-
recoverable: false,
|
|
738
|
-
next: "Call get-extension once, then update-extension with patches or edits that change only the data-loading code. Use allowFullReplacement=true only for an explicitly requested visual rewrite.",
|
|
739
|
-
},
|
|
740
|
-
null,
|
|
741
|
-
2,
|
|
742
|
-
),
|
|
743
|
-
});
|
|
730
|
+
"Full extension-body replacement requires allowFullReplacement=true. No changes were applied. If the user's request includes a broad visual rewrite such as changing layout, compactness, visible sections, naming, or padding, retry once with allowFullReplacement=true; otherwise read the current extension and use focused patches/edits for a data-only repair. Do not retry unchanged arguments.";
|
|
731
|
+
throw new ExtensionContentEditError(message);
|
|
744
732
|
}
|
|
745
733
|
|
|
746
734
|
// Full-replacement content can come inline (`content`) or by reference
|
|
@@ -982,7 +982,7 @@ export const DESTRUCTIVE_SQL_RE =
|
|
|
982
982
|
// integrations, notifications, scheduling, sharing/orgs), and Postgres
|
|
983
983
|
// catalogs that would let a extension enumerate or read internals.
|
|
984
984
|
export const SENSITIVE_SQL_RE =
|
|
985
|
-
/\b(app_secrets|user|users|session|sessions|account|accounts|verification|oauth_tokens|tools|extensions|tool_shares|tool_slots|tool_slot_installs|tool_hidden_extensions|tool_history|member|organization|invitation|jwks|agent_trace_spans|agent_trace_summaries|agent_feedback|agent_satisfaction_scores|agent_evals|agent_runs|agent_run_events|notifications|progress_runs|integration_configs|integration_pending_tasks|integration_thread_mappings|resources|org_members|org_invitations|bigquery_cache|dashboard_views|pg_catalog|information_schema|pg_class|pg_proc|pg_namespace|pg_user|pg_roles|pg_authid|pg_shadow)\b/i;
|
|
985
|
+
/\b(app_secrets|settings|user|users|session|sessions|account|accounts|verification|oauth_tokens|tools|extensions|tool_shares|tool_slots|tool_slot_installs|tool_hidden_extensions|tool_history|member|organization|invitation|jwks|agent_trace_spans|agent_trace_summaries|agent_feedback|agent_satisfaction_scores|agent_evals|agent_runs|agent_run_events|notifications|progress_runs|integration_configs|integration_pending_tasks|integration_thread_mappings|resources|org_members|org_invitations|bigquery_cache|dashboard_views|pg_catalog|information_schema|pg_class|pg_proc|pg_namespace|pg_user|pg_roles|pg_authid|pg_shadow)\b/i;
|
|
986
986
|
|
|
987
987
|
// Refuses positional INSERTs (no column list). `INSERT INTO recordings VALUES
|
|
988
988
|
// (...)` would let a extension stuff arbitrary owner_email values into a row.
|
|
@@ -1192,7 +1192,7 @@ export async function updateExtensionContent(
|
|
|
1192
1192
|
|
|
1193
1193
|
if (opts.content !== undefined && opts.allowFullReplacement !== true) {
|
|
1194
1194
|
throw new ExtensionContentEditError(
|
|
1195
|
-
"Full extension-body replacement requires
|
|
1195
|
+
"Full extension-body replacement requires allowFullReplacement=true. No changes were applied. Use patches or edits for a targeted data-only repair, or set allowFullReplacement=true for a user-requested broad visual rewrite.",
|
|
1196
1196
|
);
|
|
1197
1197
|
}
|
|
1198
1198
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { getHeader } from "h3";
|
|
2
|
+
import * as jose from "jose";
|
|
3
|
+
|
|
4
|
+
import { verifyA2ATokenWithClaims } from "../a2a-claims.js";
|
|
5
|
+
import type { ActionRouteAuthAdapter } from "../server/action-routes.js";
|
|
6
|
+
|
|
7
|
+
const FLAG_ACTION_SCOPES = {
|
|
8
|
+
"list-feature-flags": "flags:read",
|
|
9
|
+
"set-feature-flag": "flags:write",
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
export function declaresFeatureFlagDelegation(token: string): boolean {
|
|
13
|
+
try {
|
|
14
|
+
const raw = jose.decodeJwt(token);
|
|
15
|
+
const scopes =
|
|
16
|
+
typeof raw.scope === "string"
|
|
17
|
+
? raw.scope.split(/\s+/)
|
|
18
|
+
: Array.isArray(raw.scope)
|
|
19
|
+
? raw.scope.filter(
|
|
20
|
+
(scope): scope is string => typeof scope === "string",
|
|
21
|
+
)
|
|
22
|
+
: [];
|
|
23
|
+
return scopes.some((scope) => scope.startsWith("flags:"));
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Narrow opt-in adapter for fleet flag control. It owns Bearer credentials only
|
|
31
|
+
* for these two actions; malformed owned bearers reject rather than falling
|
|
32
|
+
* back to a browser cookie.
|
|
33
|
+
*/
|
|
34
|
+
export function createFeatureFlagA2AActionRouteAuth(
|
|
35
|
+
actionName: keyof typeof FLAG_ACTION_SCOPES,
|
|
36
|
+
): ActionRouteAuthAdapter {
|
|
37
|
+
return {
|
|
38
|
+
async resolveCaller(event) {
|
|
39
|
+
const header = getHeader(event, "authorization");
|
|
40
|
+
if (!header?.startsWith("Bearer ")) return null;
|
|
41
|
+
const token = header.slice(7);
|
|
42
|
+
if (!declaresFeatureFlagDelegation(token)) return null;
|
|
43
|
+
const claims = await verifyA2ATokenWithClaims(token, event);
|
|
44
|
+
if (!claims || !claims.scope.includes(FLAG_ACTION_SCOPES[actionName])) {
|
|
45
|
+
throw new Error("Invalid feature flag delegation");
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
owner: claims.email,
|
|
49
|
+
orgId: claims.orgId,
|
|
50
|
+
anonymous: false,
|
|
51
|
+
delegationJti: claims.jti,
|
|
52
|
+
delegationIssuer: claims.issuer,
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { defineAction } from "../../action.js";
|
|
4
|
+
import { listFeatureFlags } from "../registry.js";
|
|
5
|
+
import { evaluateFeatureFlag } from "../store.js";
|
|
6
|
+
|
|
7
|
+
export default defineAction({
|
|
8
|
+
description:
|
|
9
|
+
"Return the boolean values of every feature flag registered by this app for the current caller. Unknown or unconfigured flags always evaluate to false.",
|
|
10
|
+
schema: z.object({}),
|
|
11
|
+
http: { method: "GET" },
|
|
12
|
+
run: async (_args, ctx) => {
|
|
13
|
+
const scope = { userEmail: ctx?.userEmail, orgId: ctx?.orgId };
|
|
14
|
+
const values = Object.fromEntries(
|
|
15
|
+
await Promise.all(
|
|
16
|
+
listFeatureFlags().map(async ({ key }) => [
|
|
17
|
+
key,
|
|
18
|
+
await evaluateFeatureFlag(key, scope).catch(() => false),
|
|
19
|
+
]),
|
|
20
|
+
),
|
|
21
|
+
);
|
|
22
|
+
return values;
|
|
23
|
+
},
|
|
24
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { defineAction } from "../../action.js";
|
|
4
|
+
import { requireFeatureFlagManager } from "../permissions.js";
|
|
5
|
+
import { listFeatureFlags } from "../registry.js";
|
|
6
|
+
import { evaluateFeatureFlagRules, getFeatureFlagRules } from "../store.js";
|
|
7
|
+
|
|
8
|
+
export default defineAction({
|
|
9
|
+
description:
|
|
10
|
+
"List this app's registered feature flags and their current rules. Organization owner/admin only (or the explicit no-org administrator).",
|
|
11
|
+
schema: z.object({}),
|
|
12
|
+
http: { method: "GET" },
|
|
13
|
+
toolCallable: false,
|
|
14
|
+
run: async (_args, ctx) => {
|
|
15
|
+
const definitions = listFeatureFlags();
|
|
16
|
+
let manager;
|
|
17
|
+
try {
|
|
18
|
+
manager = await requireFeatureFlagManager(ctx ?? {});
|
|
19
|
+
} catch (error) {
|
|
20
|
+
if (
|
|
21
|
+
error instanceof Error &&
|
|
22
|
+
"statusCode" in error &&
|
|
23
|
+
(error as { statusCode?: number }).statusCode === 403
|
|
24
|
+
) {
|
|
25
|
+
return {
|
|
26
|
+
contractVersion: 1,
|
|
27
|
+
status: "forbidden" as const,
|
|
28
|
+
reason: "forbidden" as const,
|
|
29
|
+
flags: [],
|
|
30
|
+
canManage: false,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
if (definitions.length === 0)
|
|
36
|
+
return {
|
|
37
|
+
contractVersion: 1,
|
|
38
|
+
status: "no-definitions" as const,
|
|
39
|
+
reason: "no-definitions" as const,
|
|
40
|
+
flags: [],
|
|
41
|
+
canManage: true,
|
|
42
|
+
};
|
|
43
|
+
const flags = await Promise.all(
|
|
44
|
+
definitions.map(async (definition) => {
|
|
45
|
+
const rules = await getFeatureFlagRules(definition.key, manager);
|
|
46
|
+
return {
|
|
47
|
+
...definition,
|
|
48
|
+
rules,
|
|
49
|
+
enabledForCurrentUser: evaluateFeatureFlagRules(
|
|
50
|
+
definition.key,
|
|
51
|
+
rules,
|
|
52
|
+
{
|
|
53
|
+
userEmail: manager.email,
|
|
54
|
+
userKey: manager.email,
|
|
55
|
+
orgId: manager.orgId,
|
|
56
|
+
},
|
|
57
|
+
),
|
|
58
|
+
};
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
return {
|
|
62
|
+
contractVersion: 1,
|
|
63
|
+
status: "ready" as const,
|
|
64
|
+
reason: "ready" as const,
|
|
65
|
+
flags,
|
|
66
|
+
canManage: true,
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { defineAction } from "../../action.js";
|
|
4
|
+
import { requireFeatureFlagManager } from "../permissions.js";
|
|
5
|
+
import { getFeatureFlagDefinition } from "../registry.js";
|
|
6
|
+
import {
|
|
7
|
+
defaultFeatureFlagRules,
|
|
8
|
+
mutateFeatureFlagRules,
|
|
9
|
+
normalizeFeatureFlagRules,
|
|
10
|
+
} from "../store.js";
|
|
11
|
+
|
|
12
|
+
const rulesSchema = z.object({
|
|
13
|
+
mode: z.enum(["off", "on", "rules"]),
|
|
14
|
+
emails: z.array(z.string().email()).max(500).optional(),
|
|
15
|
+
orgIds: z.array(z.string().min(1).max(200)).max(500).optional(),
|
|
16
|
+
percentage: z.number().int().min(0).max(100).optional(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const schema = z.discriminatedUnion("operation", [
|
|
20
|
+
z.object({
|
|
21
|
+
operation: z.literal("enable-for-current-user"),
|
|
22
|
+
key: z.string(),
|
|
23
|
+
}),
|
|
24
|
+
z.object({ operation: z.literal("off"), key: z.string() }),
|
|
25
|
+
z.object({
|
|
26
|
+
operation: z.literal("replace-rules"),
|
|
27
|
+
key: z.string(),
|
|
28
|
+
rules: rulesSchema,
|
|
29
|
+
}),
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
export default defineAction({
|
|
33
|
+
description:
|
|
34
|
+
"Atomically manage one registered feature flag: enable it for the current user, turn it off immediately for the active scope, or replace its full rules. Organization owner/admin only (or the explicit no-org administrator).",
|
|
35
|
+
schema,
|
|
36
|
+
// Keep the strict discriminated union for runtime validation, but advertise
|
|
37
|
+
// an object-shaped schema so agent tool registries can expose the action.
|
|
38
|
+
// Root-level JSON Schema unions are intentionally rejected by the agent.
|
|
39
|
+
agentInputSchema: z.object({
|
|
40
|
+
operation: z.enum(["enable-for-current-user", "off", "replace-rules"]),
|
|
41
|
+
key: z.string(),
|
|
42
|
+
rules: rulesSchema.optional(),
|
|
43
|
+
}),
|
|
44
|
+
toolCallable: false,
|
|
45
|
+
audit: {
|
|
46
|
+
target: (args, _result, meta) => ({
|
|
47
|
+
type: "feature-flag",
|
|
48
|
+
id: args.key,
|
|
49
|
+
ownerEmail: meta.userEmail,
|
|
50
|
+
visibility: meta.orgId ? "org" : "private",
|
|
51
|
+
}),
|
|
52
|
+
summary: (args) => `Feature flag ${args.key}: ${args.operation}`,
|
|
53
|
+
},
|
|
54
|
+
run: async (args, ctx) => {
|
|
55
|
+
const manager = await requireFeatureFlagManager(ctx ?? {});
|
|
56
|
+
if (!getFeatureFlagDefinition(args.key)) {
|
|
57
|
+
throw new Error(`Unknown feature flag: ${args.key}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const persistedRules = await mutateFeatureFlagRules(
|
|
61
|
+
args.key,
|
|
62
|
+
manager,
|
|
63
|
+
(current) => {
|
|
64
|
+
let rules;
|
|
65
|
+
if (args.operation === "off") {
|
|
66
|
+
rules = defaultFeatureFlagRules();
|
|
67
|
+
} else if (args.operation === "replace-rules") {
|
|
68
|
+
rules = normalizeFeatureFlagRules(args.rules);
|
|
69
|
+
} else {
|
|
70
|
+
rules = normalizeFeatureFlagRules({
|
|
71
|
+
...current,
|
|
72
|
+
// A globally-on flag already includes this user. Do not
|
|
73
|
+
// accidentally narrow it to a one-email rollout.
|
|
74
|
+
mode: current.mode === "on" ? "on" : "rules",
|
|
75
|
+
emails: [...current.emails, manager.email],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return { ...rules, updatedAt: Date.now(), updatedBy: manager.email };
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
return {
|
|
82
|
+
contractVersion: 1 as const,
|
|
83
|
+
status: "ready" as const,
|
|
84
|
+
key: args.key,
|
|
85
|
+
rules: persistedRules,
|
|
86
|
+
scope: { orgId: manager.orgId },
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export {
|
|
2
|
+
defineFeatureFlag,
|
|
3
|
+
defineFeatureFlags,
|
|
4
|
+
getFeatureFlagDefinition,
|
|
5
|
+
listFeatureFlags,
|
|
6
|
+
registerFeatureFlags,
|
|
7
|
+
type FeatureFlagDefinition,
|
|
8
|
+
} from "./registry.js";
|
|
9
|
+
export {
|
|
10
|
+
defaultFeatureFlagRules,
|
|
11
|
+
evaluateFeatureFlag,
|
|
12
|
+
evaluateFeatureFlagRules,
|
|
13
|
+
isFeatureFlagEnabled,
|
|
14
|
+
getFeatureFlagRules,
|
|
15
|
+
normalizeFeatureFlagRules,
|
|
16
|
+
type FeatureFlagMode,
|
|
17
|
+
type FeatureFlagRules,
|
|
18
|
+
type FeatureFlagScope,
|
|
19
|
+
} from "./store.js";
|
|
20
|
+
export { createFeatureFlagsPlugin } from "./plugin.js";
|
|
21
|
+
export { createFeatureFlagA2AActionRouteAuth } from "./a2a-action-route.js";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { getOrgRoleForEmail } from "../mcp/actions/service-token-access.js";
|
|
2
|
+
import { canManageOrg } from "../org/permissions.js";
|
|
3
|
+
|
|
4
|
+
export class FeatureFlagPermissionError extends Error {
|
|
5
|
+
statusCode: number;
|
|
6
|
+
|
|
7
|
+
constructor(message: string, statusCode: number) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function productionAdminAllowlist(): Set<string> {
|
|
14
|
+
return new Set(
|
|
15
|
+
(process.env.AGENT_NATIVE_FEATURE_FLAG_ADMIN_EMAILS ?? "")
|
|
16
|
+
.split(",")
|
|
17
|
+
.map((email) => email.trim().toLowerCase())
|
|
18
|
+
.filter(Boolean),
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Require an org admin/owner, or an explicit production no-org allowlist entry. */
|
|
23
|
+
export async function requireFeatureFlagManager(scope: {
|
|
24
|
+
userEmail?: string;
|
|
25
|
+
orgId?: string | null;
|
|
26
|
+
}): Promise<{ email: string; orgId: string | null }> {
|
|
27
|
+
const email = scope.userEmail?.trim().toLowerCase();
|
|
28
|
+
if (!email) {
|
|
29
|
+
throw new FeatureFlagPermissionError(
|
|
30
|
+
"Sign in to manage feature flags.",
|
|
31
|
+
401,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
const orgId = scope.orgId?.trim() || null;
|
|
35
|
+
if (orgId) {
|
|
36
|
+
const role = await getOrgRoleForEmail(orgId, email);
|
|
37
|
+
if (!canManageOrg(role)) {
|
|
38
|
+
throw new FeatureFlagPermissionError(
|
|
39
|
+
"Only organization owners or admins can manage feature flags.",
|
|
40
|
+
403,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return { email, orgId };
|
|
44
|
+
}
|
|
45
|
+
if (process.env.NODE_ENV !== "production") return { email, orgId: null };
|
|
46
|
+
if (!productionAdminAllowlist().has(email)) {
|
|
47
|
+
throw new FeatureFlagPermissionError(
|
|
48
|
+
"Feature flag management without an organization requires an explicit admin allowlist entry.",
|
|
49
|
+
403,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return { email, orgId: null };
|
|
53
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { getSetting } from "../settings/store.js";
|
|
2
|
+
import {
|
|
3
|
+
registerFeatureFlags,
|
|
4
|
+
type FeatureFlagDefinition,
|
|
5
|
+
} from "./registry.js";
|
|
6
|
+
import { mutateFeatureFlagRules } from "./store.js";
|
|
7
|
+
|
|
8
|
+
type NitroPluginDef = (nitroApp: any) => void | Promise<void>;
|
|
9
|
+
|
|
10
|
+
/** A tiny startup plugin for app-local, explicit feature-flag registration. */
|
|
11
|
+
export function createFeatureFlagsPlugin(options: {
|
|
12
|
+
flags: readonly FeatureFlagDefinition[];
|
|
13
|
+
/**
|
|
14
|
+
* One-time compatibility bridge for apps that previously stored global
|
|
15
|
+
* booleans together in a single settings object. Only legacy `true` values
|
|
16
|
+
* are copied, and an explicit rule in the new store always wins.
|
|
17
|
+
*/
|
|
18
|
+
legacyBooleanSetting?: {
|
|
19
|
+
settingKey: string;
|
|
20
|
+
flagKeys: readonly string[];
|
|
21
|
+
};
|
|
22
|
+
}): NitroPluginDef {
|
|
23
|
+
return async () => {
|
|
24
|
+
registerFeatureFlags(options.flags);
|
|
25
|
+
if (!options.legacyBooleanSetting) return;
|
|
26
|
+
|
|
27
|
+
const legacy = await getSetting(options.legacyBooleanSetting.settingKey);
|
|
28
|
+
if (!legacy) return;
|
|
29
|
+
await Promise.all(
|
|
30
|
+
options.legacyBooleanSetting.flagKeys.map(async (key) => {
|
|
31
|
+
if (legacy[key] !== true) return;
|
|
32
|
+
await mutateFeatureFlagRules(key, {}, (current) => {
|
|
33
|
+
if (current.updatedAt !== null) return current;
|
|
34
|
+
return {
|
|
35
|
+
...current,
|
|
36
|
+
mode: "on",
|
|
37
|
+
updatedAt: Date.now(),
|
|
38
|
+
updatedBy: "legacy-settings-migration",
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App-owned feature-flag definitions. Core intentionally starts with an empty
|
|
3
|
+
* registry: a flag key is part of an app's stable contract, not framework
|
|
4
|
+
* configuration that Core should guess at.
|
|
5
|
+
*/
|
|
6
|
+
export interface FeatureFlagDefinition {
|
|
7
|
+
key: string;
|
|
8
|
+
/** Boolean flags are always default-off; explicit in operator metadata. */
|
|
9
|
+
defaultValue?: false;
|
|
10
|
+
displayName?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const registry = new Map<string, FeatureFlagDefinition>();
|
|
15
|
+
|
|
16
|
+
function normalizeDefinition(
|
|
17
|
+
definition: FeatureFlagDefinition,
|
|
18
|
+
): FeatureFlagDefinition {
|
|
19
|
+
const key = definition.key.trim();
|
|
20
|
+
if (!/^[A-Za-z][A-Za-z0-9._-]{0,63}$/.test(key)) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
"Feature flag keys must be stable strings containing only letters, numbers, dots, underscores, or hyphens (1-64 characters).",
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
key,
|
|
27
|
+
defaultValue: false,
|
|
28
|
+
...(definition.displayName?.trim() && {
|
|
29
|
+
displayName: definition.displayName.trim(),
|
|
30
|
+
}),
|
|
31
|
+
...(definition.description?.trim() && {
|
|
32
|
+
description: definition.description.trim(),
|
|
33
|
+
}),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Define one app-local feature flag for registration at server startup. */
|
|
38
|
+
export function defineFeatureFlag(
|
|
39
|
+
definition: FeatureFlagDefinition,
|
|
40
|
+
): FeatureFlagDefinition {
|
|
41
|
+
return Object.freeze(normalizeDefinition(definition));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Define a small app-owned feature-flag registry. */
|
|
45
|
+
export function defineFeatureFlags(
|
|
46
|
+
definitions: readonly FeatureFlagDefinition[],
|
|
47
|
+
): readonly FeatureFlagDefinition[] {
|
|
48
|
+
const seen = new Set<string>();
|
|
49
|
+
return Object.freeze(
|
|
50
|
+
definitions.map((definition) => {
|
|
51
|
+
const normalized = defineFeatureFlag(definition);
|
|
52
|
+
if (seen.has(normalized.key)) {
|
|
53
|
+
throw new Error(`Duplicate feature flag key: ${normalized.key}`);
|
|
54
|
+
}
|
|
55
|
+
seen.add(normalized.key);
|
|
56
|
+
return normalized;
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Register definitions once at Nitro startup. Re-registering identical data is safe for HMR. */
|
|
62
|
+
export function registerFeatureFlags(
|
|
63
|
+
definitions: readonly FeatureFlagDefinition[],
|
|
64
|
+
): void {
|
|
65
|
+
for (const rawDefinition of definitions) {
|
|
66
|
+
const definition = defineFeatureFlag(rawDefinition);
|
|
67
|
+
const existing = registry.get(definition.key);
|
|
68
|
+
if (!existing) {
|
|
69
|
+
registry.set(definition.key, definition);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (
|
|
73
|
+
existing.displayName !== definition.displayName ||
|
|
74
|
+
existing.description !== definition.description
|
|
75
|
+
) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Feature flag ${definition.key} was registered with conflicting metadata.`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function listFeatureFlags(): readonly FeatureFlagDefinition[] {
|
|
84
|
+
return [...registry.values()].sort((a, b) => a.key.localeCompare(b.key));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function getFeatureFlagDefinition(
|
|
88
|
+
key: string,
|
|
89
|
+
): FeatureFlagDefinition | null {
|
|
90
|
+
return registry.get(key) ?? null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Test-only registry reset; not exported from package entrypoints. */
|
|
94
|
+
export function _resetFeatureFlagRegistryForTests(): void {
|
|
95
|
+
registry.clear();
|
|
96
|
+
}
|