@agent-native/core 0.100.1 → 0.101.2
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 +73 -0
- package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +48 -30
- package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +7 -0
- package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +48 -30
- package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +7 -0
- package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +48 -30
- package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +14 -0
- package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +48 -30
- package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +7 -0
- package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +48 -30
- package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +7 -0
- package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +48 -30
- package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +7 -0
- package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +48 -30
- package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +7 -0
- package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +48 -30
- package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +14 -0
- package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +48 -30
- package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +7 -0
- package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +48 -30
- package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +7 -0
- package/corpus/core/docs/content/pr-visual-recap.mdx +50 -32
- package/corpus/core/docs/content/template-plan.mdx +14 -0
- package/corpus/core/docs/content/toolkit-comments-review.mdx +16 -2
- package/corpus/core/package.json +4 -1
- package/corpus/core/src/a2a/index.ts +2 -1
- package/corpus/core/src/a2a/server.ts +34 -9
- package/corpus/core/src/agent/production-agent.ts +56 -10
- package/corpus/core/src/cli/create.ts +47 -19
- package/corpus/core/src/cli/pr-visual-recap-workflow.ts +2 -3
- package/corpus/core/src/cli/recap.ts +3 -4932
- package/corpus/core/src/cli/skills-content/visual-plan-skill.ts +6 -4
- package/corpus/core/src/cli/skills-content/visual-recap-skill.ts +7 -1
- package/corpus/core/src/client/AgentPanel.tsx +19 -17
- package/corpus/core/src/client/AssistantChat.tsx +4 -0
- package/corpus/core/src/client/analytics.ts +8 -1
- package/corpus/core/src/client/chat/markdown-renderer.tsx +54 -8
- package/corpus/core/src/client/chat/message-components.tsx +8 -2
- package/corpus/core/src/client/clipboard.ts +28 -1
- package/corpus/core/src/client/composer/PromptComposer.tsx +4 -0
- package/corpus/core/src/client/composer/TiptapComposer.tsx +30 -3
- package/corpus/core/src/client/guided-questions.tsx +4 -0
- package/corpus/core/src/client/i18n.tsx +2 -1
- package/corpus/core/src/client/index.ts +4 -0
- package/corpus/core/src/client/review/ReviewCommentComposer.tsx +108 -0
- package/corpus/core/src/client/review/ReviewThreadPanel.tsx +482 -150
- package/corpus/core/src/client/review/index.ts +8 -0
- package/corpus/core/src/client/review/use-review.ts +35 -1
- package/corpus/core/src/client/use-agent-chat-context.ts +3 -2
- package/corpus/core/src/integrations/webhook-handler.ts +4 -2
- package/corpus/core/src/review/actions/create-review-comment.ts +2 -1
- package/corpus/core/src/review/actions/get-review-feedback.ts +6 -11
- package/corpus/core/src/review/actions/list-review-comments.ts +38 -4
- package/corpus/core/src/review/actions/reply-review-comment.ts +33 -22
- package/corpus/core/src/review/actions/resolve-review-thread.ts +29 -2
- package/corpus/core/src/review/actions/send-review-thread-to-agent.ts +62 -0
- package/corpus/core/src/review/identity.ts +101 -0
- package/corpus/core/src/review/index.ts +14 -0
- package/corpus/core/src/review/store.ts +315 -8
- package/corpus/core/src/review/types.ts +4 -0
- package/corpus/core/src/secrets/crypto.ts +98 -47
- package/corpus/core/src/secrets/index.ts +2 -1
- package/corpus/core/src/secrets/schema.ts +3 -0
- package/corpus/core/src/secrets/storage.ts +164 -31
- package/corpus/core/src/server/action-discovery.ts +4 -0
- package/corpus/core/src/server/action-routes.ts +125 -4
- package/corpus/core/src/server/agent-chat/plugin-options.ts +16 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +1 -0
- package/corpus/core/src/server/index.ts +8 -0
- package/corpus/core/src/vite/action-types-plugin.ts +4 -0
- package/corpus/templates/analytics/changelog/2026-07-14-daily-dashboard-email-captures-authenticate-with-a-sessi.md +6 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +156 -3
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +402 -142
- package/corpus/templates/assets/app/components/layout/Layout.tsx +4 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +3 -1
- package/corpus/templates/assets/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/assets/app/i18n-data.ts +1 -0
- package/corpus/templates/assets/app/routes/library.tsx +187 -48
- package/corpus/templates/assets/changelog/2026-07-13-assets-keeps-the-right-chat-sidebar-closed-when-the-full-pag.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-13-merged-the-candidates-panel-into-the-library-as-a-drafts-tab.md +6 -0
- package/corpus/templates/chat/app/lib/agent-page.tsx +40 -0
- package/corpus/templates/chat/app/routes/agent.tsx +5 -3
- package/corpus/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +5 -0
- package/corpus/templates/clips/AGENTS.md +4 -0
- package/corpus/templates/clips/actions/get-feature-flags.ts +30 -0
- package/corpus/templates/clips/actions/lib/transcript-preview.ts +48 -0
- package/corpus/templates/clips/actions/request-transcript.ts +41 -1
- package/corpus/templates/clips/actions/view-screen.ts +5 -9
- package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
- package/corpus/templates/clips/app/components/player/video-player.tsx +39 -1
- package/corpus/templates/clips/app/hooks/use-desktop-promo.ts +6 -12
- package/corpus/templates/clips/app/hooks/use-mse-video-source.ts +146 -0
- package/corpus/templates/clips/app/lib/capture-install-options.ts +21 -0
- package/corpus/templates/clips/app/lib/fmp4.ts +271 -0
- package/corpus/templates/clips/app/lib/mse-video-loader.ts +585 -0
- package/corpus/templates/clips/app/routes/_app.dictate.tsx +0 -4
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +5 -13
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +2 -37
- package/corpus/templates/clips/app/routes/download.tsx +3 -2
- package/corpus/templates/clips/changelog/2026-07-10-shared-clips-now-start-playing-instantly-instead-of-showing-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-14-clips-now-distinguishes-transcript-previews-from-incomplete-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-14-desktop-app-prompts-stay-hidden-after-you-download-the-insta.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +5 -0
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +10 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +2518 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +353 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +558 -67
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +11 -1
- package/corpus/templates/clips/desktop/src-tauri/src/remote_flags.rs +188 -0
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +1 -1
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +1 -0
- package/corpus/templates/clips/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +5 -1
- package/corpus/templates/clips/shared/feature-flags.ts +41 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +3 -0
- package/corpus/templates/design/.agents/skills/design-review-feedback/SKILL.md +42 -0
- package/corpus/templates/design/AGENTS.md +6 -0
- package/corpus/templates/design/README.md +1 -0
- package/corpus/templates/design/actions/navigate.ts +4 -4
- package/corpus/templates/design/actions/view-screen.ts +116 -2
- package/corpus/templates/design/agent-native.app-skill.json +5 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +52 -59
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +13 -9
- package/corpus/templates/design/app/components/design/EditPanel.tsx +79 -11
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +78 -65
- package/corpus/templates/design/app/components/design/ReviewCommentsPanel.tsx +161 -0
- package/corpus/templates/design/app/components/design/ReviewStatusControl.tsx +96 -0
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +166 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +1 -0
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +1077 -0
- package/corpus/templates/design/app/components/visual-editor/index.ts +1 -0
- package/corpus/templates/design/app/components/visual-editor/review-canvas-state.ts +42 -0
- package/corpus/templates/design/app/hooks/use-design-systems.ts +2 -2
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +9 -6
- package/corpus/templates/design/app/hooks/use-question-flow.ts +7 -1
- package/corpus/templates/design/app/i18n/ar-SA.ts +56 -1
- package/corpus/templates/design/app/i18n/de-DE.ts +57 -1
- package/corpus/templates/design/app/i18n/en-US.ts +56 -1
- package/corpus/templates/design/app/i18n/es-ES.ts +56 -1
- package/corpus/templates/design/app/i18n/fr-FR.ts +57 -1
- package/corpus/templates/design/app/i18n/hi-IN.ts +56 -1
- package/corpus/templates/design/app/i18n/ja-JP.ts +56 -1
- package/corpus/templates/design/app/i18n/ko-KR.ts +56 -1
- package/corpus/templates/design/app/i18n/pt-BR.ts +57 -1
- package/corpus/templates/design/app/i18n/zh-CN.ts +56 -1
- package/corpus/templates/design/app/i18n/zh-TW.ts +51 -0
- package/corpus/templates/design/app/pages/Present.tsx +172 -14
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +23 -0
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +10 -0
- package/corpus/templates/design/app/pages/present-review-state.ts +18 -0
- package/corpus/templates/design/app/public-routes.ts +8 -0
- package/corpus/templates/design/app/root.tsx +7 -6
- package/corpus/templates/design/changelog/2026-07-13-dragged-design-assets-now-appear-at-the-visible-drop-locatio.md +6 -0
- package/corpus/templates/design/changelog/2026-07-13-reviewers-can-pin-comments-on-shared-designs-and-apply-verif.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +10 -0
- package/corpus/templates/design/server/plugins/auth.ts +7 -5
- package/corpus/templates/design/server/plugins/review.ts +9 -0
- package/corpus/templates/design/shared/review-anchor.ts +83 -0
- package/corpus/templates/design/shared/review-summary.ts +25 -0
- package/corpus/templates/forms/.agents/skills/form-publishing/SKILL.md +2 -0
- package/corpus/templates/forms/AGENTS.md +4 -0
- package/corpus/templates/forms/actions/create-form.ts +2 -1
- package/corpus/templates/forms/actions/update-form.ts +5 -2
- package/corpus/templates/forms/app/i18n/ar-SA.ts +3 -0
- package/corpus/templates/forms/app/i18n/de-DE.ts +3 -0
- package/corpus/templates/forms/app/i18n/en-US.ts +3 -0
- package/corpus/templates/forms/app/i18n/es-ES.ts +3 -0
- package/corpus/templates/forms/app/i18n/fr-FR.ts +3 -0
- package/corpus/templates/forms/app/i18n/hi-IN.ts +3 -0
- package/corpus/templates/forms/app/i18n/ja-JP.ts +3 -0
- package/corpus/templates/forms/app/i18n/ko-KR.ts +3 -0
- package/corpus/templates/forms/app/i18n/pt-BR.ts +3 -0
- package/corpus/templates/forms/app/i18n/zh-CN.ts +3 -0
- package/corpus/templates/forms/app/i18n/zh-TW.ts +3 -0
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +19 -0
- package/corpus/templates/forms/changelog/2026-07-14-fixed-the-ask-forms-loading-input-appearing-above-the-welcom.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-14-form-social-previews-now-show-the-form-title-description-and.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-14-forms-can-email-the-form-owner-when-new-responses-arrive.md +6 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +17 -0
- package/corpus/templates/forms/server/lib/form-og-image.ts +64 -6
- package/corpus/templates/forms/server/lib/public-form-ssr.ts +6 -2
- package/corpus/templates/forms/server/lib/response-email.ts +65 -0
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/forms/server/routes/api/forms/og/[...slug]/og.png.get.ts +184 -0
- package/corpus/templates/forms/shared/types.ts +2 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +6 -4
- package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +7 -1
- package/dist/a2a/index.d.ts +2 -1
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +1 -1
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/server.d.ts +25 -0
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +30 -6
- package/dist/a2a/server.js.map +1 -1
- package/dist/agent/production-agent.d.ts +2 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +37 -12
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/create.d.ts +5 -3
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +44 -19
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +2 -2
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +2 -2
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts +3 -562
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +3 -3875
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
- package/dist/cli/skills-content/visual-plan-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/visual-plan-skill.js +6 -4
- package/dist/cli/skills-content/visual-plan-skill.js.map +1 -1
- package/dist/cli/skills-content/visual-recap-skill.d.ts +1 -1
- package/dist/cli/skills-content/visual-recap-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/visual-recap-skill.js +7 -1
- package/dist/cli/skills-content/visual-recap-skill.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +3 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +2 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/analytics.d.ts +5 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +3 -1
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/markdown-renderer.d.ts +1 -0
- package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
- package/dist/client/chat/markdown-renderer.js +36 -1
- package/dist/client/chat/markdown-renderer.js.map +1 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +5 -2
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/clipboard.d.ts +3 -1
- package/dist/client/clipboard.d.ts.map +1 -1
- package/dist/client/clipboard.js +24 -1
- package/dist/client/clipboard.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts +2 -0
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +2 -2
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +3 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +20 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/guided-questions.d.ts +3 -1
- package/dist/client/guided-questions.d.ts.map +1 -1
- package/dist/client/guided-questions.js +2 -1
- package/dist/client/guided-questions.js.map +1 -1
- package/dist/client/i18n.d.ts.map +1 -1
- package/dist/client/i18n.js +3 -1
- package/dist/client/i18n.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/review/ReviewCommentComposer.d.ts +18 -0
- package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -0
- package/dist/client/review/ReviewCommentComposer.js +30 -0
- package/dist/client/review/ReviewCommentComposer.js.map +1 -0
- package/dist/client/review/ReviewThreadPanel.d.ts +28 -1
- package/dist/client/review/ReviewThreadPanel.d.ts.map +1 -1
- package/dist/client/review/ReviewThreadPanel.js +151 -39
- package/dist/client/review/ReviewThreadPanel.js.map +1 -1
- package/dist/client/review/index.d.ts +3 -2
- package/dist/client/review/index.d.ts.map +1 -1
- package/dist/client/review/index.js +2 -1
- package/dist/client/review/index.js.map +1 -1
- package/dist/client/review/use-review.d.ts +23 -0
- package/dist/client/review/use-review.d.ts.map +1 -1
- package/dist/client/review/use-review.js +3 -0
- package/dist/client/review/use-review.js.map +1 -1
- package/dist/client/use-agent-chat-context.d.ts +1 -1
- package/dist/client/use-agent-chat-context.d.ts.map +1 -1
- package/dist/client/use-agent-chat-context.js +4 -2
- package/dist/client/use-agent-chat-context.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +3 -2
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/review/actions/create-review-comment.js +2 -1
- package/dist/review/actions/create-review-comment.js.map +1 -1
- package/dist/review/actions/get-review-feedback.js +6 -11
- package/dist/review/actions/get-review-feedback.js.map +1 -1
- package/dist/review/actions/list-review-comments.d.ts +1 -0
- package/dist/review/actions/list-review-comments.js +25 -4
- package/dist/review/actions/list-review-comments.js.map +1 -1
- package/dist/review/actions/reply-review-comment.js +12 -5
- package/dist/review/actions/reply-review-comment.js.map +1 -1
- package/dist/review/actions/resolve-review-thread.d.ts +3 -0
- package/dist/review/actions/resolve-review-thread.js +20 -3
- package/dist/review/actions/resolve-review-thread.js.map +1 -1
- package/dist/review/actions/send-review-thread-to-agent.d.ts +17 -0
- package/dist/review/actions/send-review-thread-to-agent.d.ts.map +1 -0
- package/dist/review/actions/send-review-thread-to-agent.js +49 -0
- package/dist/review/actions/send-review-thread-to-agent.js.map +1 -0
- package/dist/review/identity.d.ts +6 -0
- package/dist/review/identity.d.ts.map +1 -0
- package/dist/review/identity.js +68 -0
- package/dist/review/identity.js.map +1 -0
- package/dist/review/index.d.ts +3 -1
- package/dist/review/index.d.ts.map +1 -1
- package/dist/review/index.js +2 -1
- package/dist/review/index.js.map +1 -1
- package/dist/review/store.d.ts +36 -0
- package/dist/review/store.d.ts.map +1 -1
- package/dist/review/store.js +223 -8
- package/dist/review/store.js.map +1 -1
- package/dist/review/types.d.ts +4 -0
- package/dist/review/types.d.ts.map +1 -1
- package/dist/review/types.js.map +1 -1
- package/dist/secrets/crypto.d.ts +35 -13
- package/dist/secrets/crypto.d.ts.map +1 -1
- package/dist/secrets/crypto.js +78 -41
- package/dist/secrets/crypto.js.map +1 -1
- package/dist/secrets/index.d.ts.map +1 -1
- package/dist/secrets/index.js +2 -1
- package/dist/secrets/index.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/secrets/schema.d.ts +20 -1
- package/dist/secrets/schema.d.ts.map +1 -1
- package/dist/secrets/schema.js +3 -0
- package/dist/secrets/schema.js.map +1 -1
- package/dist/secrets/storage.d.ts +7 -7
- package/dist/secrets/storage.d.ts.map +1 -1
- package/dist/secrets/storage.js +121 -30
- package/dist/secrets/storage.js.map +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +4 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/action-routes.d.ts +45 -0
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +71 -5
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-chat/plugin-options.d.ts +16 -0
- package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
- package/dist/server/agent-chat/plugin-options.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +1 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -1
- package/dist/vite/action-types-plugin.d.ts.map +1 -1
- package/dist/vite/action-types-plugin.js +4 -0
- package/dist/vite/action-types-plugin.js.map +1 -1
- package/docs/content/locales/ar-SA/pr-visual-recap.mdx +48 -30
- package/docs/content/locales/ar-SA/template-plan.mdx +7 -0
- package/docs/content/locales/de-DE/pr-visual-recap.mdx +48 -30
- package/docs/content/locales/de-DE/template-plan.mdx +7 -0
- package/docs/content/locales/es-ES/pr-visual-recap.mdx +48 -30
- package/docs/content/locales/es-ES/template-plan.mdx +14 -0
- package/docs/content/locales/fr-FR/pr-visual-recap.mdx +48 -30
- package/docs/content/locales/fr-FR/template-plan.mdx +7 -0
- package/docs/content/locales/hi-IN/pr-visual-recap.mdx +48 -30
- package/docs/content/locales/hi-IN/template-plan.mdx +7 -0
- package/docs/content/locales/ja-JP/pr-visual-recap.mdx +48 -30
- package/docs/content/locales/ja-JP/template-plan.mdx +7 -0
- package/docs/content/locales/ko-KR/pr-visual-recap.mdx +48 -30
- package/docs/content/locales/ko-KR/template-plan.mdx +7 -0
- package/docs/content/locales/pt-BR/pr-visual-recap.mdx +48 -30
- package/docs/content/locales/pt-BR/template-plan.mdx +14 -0
- package/docs/content/locales/zh-CN/pr-visual-recap.mdx +48 -30
- package/docs/content/locales/zh-CN/template-plan.mdx +7 -0
- package/docs/content/locales/zh-TW/pr-visual-recap.mdx +48 -30
- package/docs/content/locales/zh-TW/template-plan.mdx +7 -0
- package/docs/content/pr-visual-recap.mdx +50 -32
- package/docs/content/template-plan.mdx +14 -0
- package/docs/content/toolkit-comments-review.mdx +16 -2
- package/package.json +4 -1
- package/corpus/templates/forms/server/routes/api/forms/og/[slug]/og.png.get.ts +0 -45
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Storage layer for the framework secrets registry.
|
|
3
3
|
*
|
|
4
|
-
* Values are encrypted at rest with AES-256-GCM. The
|
|
5
|
-
* derived from `SECRETS_ENCRYPTION_KEY` (preferred) or the
|
|
6
|
-
* `BETTER_AUTH_SECRET` env var (fallback so templates don't need a
|
|
7
|
-
* secret during development).
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* for
|
|
4
|
+
* Values are encrypted at rest with AES-256-GCM. The workspace-shared
|
|
5
|
+
* encryption key is derived from `SECRETS_ENCRYPTION_KEY` (preferred) or the
|
|
6
|
+
* existing `BETTER_AUTH_SECRET` env var (fallback so templates don't need a
|
|
7
|
+
* second secret during development). Deployments that only have the legacy
|
|
8
|
+
* app-scoped key continue to work until shared key material is configured;
|
|
9
|
+
* once configured, new rows use the shared key and reads retain a legacy-key
|
|
10
|
+
* fallback for existing rows.
|
|
11
11
|
*
|
|
12
12
|
* Secret values are NEVER logged and NEVER returned from any route handler.
|
|
13
13
|
*/
|
|
@@ -17,8 +17,11 @@ import { randomUUID } from "node:crypto";
|
|
|
17
17
|
import { getDbExec, isPostgres } from "../db/client.js";
|
|
18
18
|
import { ensureColumnExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
19
19
|
import {
|
|
20
|
-
encryptSecretValue as
|
|
21
|
-
|
|
20
|
+
encryptSecretValue as encryptLegacyValue,
|
|
21
|
+
encryptSharedSecretValue as encryptValue,
|
|
22
|
+
decryptSharedSecretValue as decryptValue,
|
|
23
|
+
decryptSecretValue as decryptLegacyValue,
|
|
24
|
+
hasSharedSecretEncryptionKeyMaterial,
|
|
22
25
|
} from "./crypto.js";
|
|
23
26
|
import type { SecretScope } from "./register.js";
|
|
24
27
|
import { APP_SECRETS_CREATE_SQL } from "./schema.js";
|
|
@@ -61,6 +64,11 @@ async function ensureTable(): Promise<void> {
|
|
|
61
64
|
"url_allowlist",
|
|
62
65
|
`ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS url_allowlist TEXT`,
|
|
63
66
|
);
|
|
67
|
+
await ensureColumnExists(
|
|
68
|
+
"app_secrets",
|
|
69
|
+
"shared_encrypted_value",
|
|
70
|
+
`ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS shared_encrypted_value TEXT`,
|
|
71
|
+
);
|
|
64
72
|
return;
|
|
65
73
|
}
|
|
66
74
|
|
|
@@ -86,6 +94,16 @@ async function ensureTable(): Promise<void> {
|
|
|
86
94
|
} catch {
|
|
87
95
|
// Column already exists — expected
|
|
88
96
|
}
|
|
97
|
+
|
|
98
|
+
// Additive migration: workspace-shared ciphertext. Keep the legacy
|
|
99
|
+
// encrypted_value column so older app versions remain readable.
|
|
100
|
+
try {
|
|
101
|
+
await client.execute(
|
|
102
|
+
`ALTER TABLE app_secrets ADD COLUMN shared_encrypted_value TEXT`,
|
|
103
|
+
);
|
|
104
|
+
} catch {
|
|
105
|
+
// Column already exists — expected
|
|
106
|
+
}
|
|
89
107
|
})().catch((err) => {
|
|
90
108
|
_initPromise = undefined;
|
|
91
109
|
throw err;
|
|
@@ -95,7 +113,9 @@ async function ensureTable(): Promise<void> {
|
|
|
95
113
|
}
|
|
96
114
|
|
|
97
115
|
// ---------------------------------------------------------------------------
|
|
98
|
-
// Encryption — see ./crypto.ts
|
|
116
|
+
// Encryption — see ./crypto.ts. Keep encrypted_value on the legacy app-key
|
|
117
|
+
// format for mixed-version deployments, and add shared_encrypted_value when a
|
|
118
|
+
// stable workspace key is configured so sibling apps can read the same row.
|
|
99
119
|
// ---------------------------------------------------------------------------
|
|
100
120
|
|
|
101
121
|
/**
|
|
@@ -141,7 +161,14 @@ export async function writeAppSecret(args: WriteSecretArgs): Promise<string> {
|
|
|
141
161
|
}
|
|
142
162
|
const client = getDbExec();
|
|
143
163
|
const now = Date.now();
|
|
144
|
-
|
|
164
|
+
// Dual-write during rollout: old readers continue using encrypted_value,
|
|
165
|
+
// while new readers prefer the nullable shared ciphertext. An app-only
|
|
166
|
+
// deployment leaves the shared column null; on an update, an existing
|
|
167
|
+
// shared ciphertext is preserved by the upsert below.
|
|
168
|
+
const encrypted = encryptLegacyValue(value);
|
|
169
|
+
const sharedEncrypted = hasSharedSecretEncryptionKeyMaterial()
|
|
170
|
+
? encryptValue(value)
|
|
171
|
+
: null;
|
|
145
172
|
const id = randomUUID();
|
|
146
173
|
|
|
147
174
|
// Atomic upsert by (scope, scope_id, key). Previously this was a
|
|
@@ -155,10 +182,11 @@ export async function writeAppSecret(args: WriteSecretArgs): Promise<string> {
|
|
|
155
182
|
// keeps its original id (any stored references stay stable); only a
|
|
156
183
|
// genuinely new row gets the freshly generated `id`. This syntax is
|
|
157
184
|
// portable across SQLite (UPSERT since 3.24) and Postgres.
|
|
158
|
-
const upsertSql = `INSERT INTO app_secrets (id, scope, scope_id, key, encrypted_value, description, url_allowlist, created_at, updated_at)
|
|
159
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
185
|
+
const upsertSql = `INSERT INTO app_secrets (id, scope, scope_id, key, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at)
|
|
186
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
160
187
|
ON CONFLICT (scope, scope_id, key) DO UPDATE SET
|
|
161
188
|
encrypted_value = excluded.encrypted_value,
|
|
189
|
+
shared_encrypted_value = COALESCE(excluded.shared_encrypted_value, app_secrets.shared_encrypted_value),
|
|
162
190
|
description = excluded.description,
|
|
163
191
|
url_allowlist = excluded.url_allowlist,
|
|
164
192
|
updated_at = excluded.updated_at`;
|
|
@@ -168,6 +196,7 @@ export async function writeAppSecret(args: WriteSecretArgs): Promise<string> {
|
|
|
168
196
|
scopeId,
|
|
169
197
|
key,
|
|
170
198
|
encrypted,
|
|
199
|
+
sharedEncrypted,
|
|
171
200
|
description ?? null,
|
|
172
201
|
urlAllowlist ?? null,
|
|
173
202
|
now,
|
|
@@ -201,6 +230,80 @@ export interface ReadSecretResult {
|
|
|
201
230
|
updatedAt: number;
|
|
202
231
|
}
|
|
203
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Read the shared-key format and retain compatibility with rows written before
|
|
235
|
+
* app_secrets moved to its workspace-shared encryption boundary. The legacy
|
|
236
|
+
* fallback is only useful when the current app owns the old row; sibling apps
|
|
237
|
+
* will receive shared-key ciphertext after the next vault sync or update.
|
|
238
|
+
*/
|
|
239
|
+
interface DecryptedAppSecretValue {
|
|
240
|
+
value: string;
|
|
241
|
+
/** True when the app-scoped fallback decrypted encrypted_value. */
|
|
242
|
+
usedLegacyKey: boolean;
|
|
243
|
+
/** True when shared_encrypted_value was not the source of the plaintext. */
|
|
244
|
+
needsSharedCiphertext: boolean;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function decryptAppSecretValue(
|
|
248
|
+
encrypted: string,
|
|
249
|
+
sharedEncrypted?: string | null,
|
|
250
|
+
): DecryptedAppSecretValue {
|
|
251
|
+
if (sharedEncrypted) {
|
|
252
|
+
try {
|
|
253
|
+
return {
|
|
254
|
+
value: decryptValue(sharedEncrypted),
|
|
255
|
+
usedLegacyKey: false,
|
|
256
|
+
needsSharedCiphertext: false,
|
|
257
|
+
};
|
|
258
|
+
} catch {
|
|
259
|
+
// Fall through to the legacy column. A partially migrated row may have
|
|
260
|
+
// a stale shared ciphertext while the old app-key value is valid.
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
return {
|
|
265
|
+
value: decryptValue(encrypted),
|
|
266
|
+
usedLegacyKey: false,
|
|
267
|
+
needsSharedCiphertext: true,
|
|
268
|
+
};
|
|
269
|
+
} catch {
|
|
270
|
+
return {
|
|
271
|
+
value: decryptLegacyValue(encrypted),
|
|
272
|
+
usedLegacyKey: true,
|
|
273
|
+
needsSharedCiphertext: true,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Populate the shared column without touching encrypted_value. This is
|
|
280
|
+
* intentionally best-effort: a read must still succeed if a deployment's DB
|
|
281
|
+
* role cannot update the row. The NULL predicate prevents a concurrent writer
|
|
282
|
+
* from overwriting newly-populated shared ciphertext, and leaving updated_at
|
|
283
|
+
* untouched preserves the row's user-visible ordering/metadata.
|
|
284
|
+
*/
|
|
285
|
+
async function populateSharedAppSecret(
|
|
286
|
+
id: unknown,
|
|
287
|
+
value: string,
|
|
288
|
+
): Promise<void> {
|
|
289
|
+
if (
|
|
290
|
+
id === undefined ||
|
|
291
|
+
id === null ||
|
|
292
|
+
!hasSharedSecretEncryptionKeyMaterial()
|
|
293
|
+
) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
await getDbExec().execute({
|
|
298
|
+
sql: `UPDATE app_secrets SET shared_encrypted_value = ? WHERE id = ? AND shared_encrypted_value IS NULL`,
|
|
299
|
+
args: [encryptValue(value), id],
|
|
300
|
+
});
|
|
301
|
+
} catch {
|
|
302
|
+
// Migration is opportunistic. Preserve the successful read if the update
|
|
303
|
+
// is unavailable due to a read-only role, transient DB failure, or race.
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
204
307
|
type AppSecretsReadQuery = { sql: string; args: unknown[] };
|
|
205
308
|
|
|
206
309
|
/**
|
|
@@ -244,15 +347,22 @@ export async function readAppSecret(
|
|
|
244
347
|
): Promise<ReadSecretResult | null> {
|
|
245
348
|
const { key, scope, scopeId } = ref;
|
|
246
349
|
const { rows } = await executeAppSecretsRead({
|
|
247
|
-
sql: `SELECT encrypted_value, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,
|
|
350
|
+
sql: `SELECT encrypted_value, shared_encrypted_value, updated_at, id FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,
|
|
248
351
|
args: [scope, scopeId, key],
|
|
249
352
|
});
|
|
250
353
|
if (rows.length === 0) return null;
|
|
251
354
|
try {
|
|
252
|
-
const
|
|
355
|
+
const encrypted = rows[0].encrypted_value as string;
|
|
356
|
+
const decrypted = decryptAppSecretValue(
|
|
357
|
+
encrypted,
|
|
358
|
+
rows[0].shared_encrypted_value as string | null,
|
|
359
|
+
);
|
|
360
|
+
if (decrypted.needsSharedCiphertext) {
|
|
361
|
+
await populateSharedAppSecret(rows[0].id, decrypted.value);
|
|
362
|
+
}
|
|
253
363
|
return {
|
|
254
|
-
value,
|
|
255
|
-
last4: last4(value),
|
|
364
|
+
value: decrypted.value,
|
|
365
|
+
last4: last4(decrypted.value),
|
|
256
366
|
updatedAt: Number(rows[0].updated_at ?? 0),
|
|
257
367
|
};
|
|
258
368
|
} catch {
|
|
@@ -273,7 +383,7 @@ export async function readAppSecrets(args: {
|
|
|
273
383
|
|
|
274
384
|
const placeholders = keys.map(() => "?").join(", ");
|
|
275
385
|
const { rows } = await executeAppSecretsRead({
|
|
276
|
-
sql: `SELECT key, encrypted_value, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? AND key IN (${placeholders})`,
|
|
386
|
+
sql: `SELECT key, encrypted_value, shared_encrypted_value, updated_at, id FROM app_secrets WHERE scope = ? AND scope_id = ? AND key IN (${placeholders})`,
|
|
277
387
|
args: [args.scope, args.scopeId, ...keys],
|
|
278
388
|
});
|
|
279
389
|
const results = new Map<string, ReadSecretResult>();
|
|
@@ -281,10 +391,17 @@ export async function readAppSecrets(args: {
|
|
|
281
391
|
const key = String(row.key ?? "");
|
|
282
392
|
if (!key) continue;
|
|
283
393
|
try {
|
|
284
|
-
const
|
|
394
|
+
const encrypted = row.encrypted_value as string;
|
|
395
|
+
const decrypted = decryptAppSecretValue(
|
|
396
|
+
encrypted,
|
|
397
|
+
row.shared_encrypted_value as string | null,
|
|
398
|
+
);
|
|
399
|
+
if (decrypted.needsSharedCiphertext) {
|
|
400
|
+
await populateSharedAppSecret(row.id, decrypted.value);
|
|
401
|
+
}
|
|
285
402
|
results.set(key, {
|
|
286
|
-
value,
|
|
287
|
-
last4: last4(value),
|
|
403
|
+
value: decrypted.value,
|
|
404
|
+
last4: last4(decrypted.value),
|
|
288
405
|
updatedAt: Number(row.updated_at ?? 0),
|
|
289
406
|
});
|
|
290
407
|
} catch {
|
|
@@ -330,15 +447,22 @@ export async function readAppSecretMeta(
|
|
|
330
447
|
const { key, scope, scopeId } = ref;
|
|
331
448
|
const client = getDbExec();
|
|
332
449
|
const { rows } = await client.execute({
|
|
333
|
-
sql: `SELECT encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,
|
|
450
|
+
sql: `SELECT id, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? AND key = ? LIMIT 1`,
|
|
334
451
|
args: [scope, scopeId, key],
|
|
335
452
|
});
|
|
336
453
|
if (rows.length === 0) return null;
|
|
337
454
|
const row = rows[0];
|
|
338
455
|
let last4Value = "";
|
|
339
456
|
try {
|
|
340
|
-
const
|
|
341
|
-
|
|
457
|
+
const encrypted = row.encrypted_value as string;
|
|
458
|
+
const decrypted = decryptAppSecretValue(
|
|
459
|
+
encrypted,
|
|
460
|
+
row.shared_encrypted_value as string | null,
|
|
461
|
+
);
|
|
462
|
+
if (decrypted.needsSharedCiphertext) {
|
|
463
|
+
await populateSharedAppSecret(row.id, decrypted.value);
|
|
464
|
+
}
|
|
465
|
+
last4Value = last4(decrypted.value);
|
|
342
466
|
} catch {
|
|
343
467
|
last4Value = "";
|
|
344
468
|
}
|
|
@@ -366,18 +490,26 @@ export async function listAppSecretsForScope(
|
|
|
366
490
|
await ensureTable();
|
|
367
491
|
const client = getDbExec();
|
|
368
492
|
const { rows } = await client.execute({
|
|
369
|
-
sql: `SELECT key, encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? ORDER BY updated_at DESC`,
|
|
493
|
+
sql: `SELECT id, key, encrypted_value, shared_encrypted_value, description, url_allowlist, created_at, updated_at FROM app_secrets WHERE scope = ? AND scope_id = ? ORDER BY updated_at DESC`,
|
|
370
494
|
args: [scope, scopeId],
|
|
371
495
|
});
|
|
372
|
-
|
|
496
|
+
const results: SecretMeta[] = [];
|
|
497
|
+
for (const row of rows) {
|
|
373
498
|
let last4Value = "";
|
|
374
499
|
try {
|
|
375
|
-
const
|
|
376
|
-
|
|
500
|
+
const encrypted = row.encrypted_value as string;
|
|
501
|
+
const decrypted = decryptAppSecretValue(
|
|
502
|
+
encrypted,
|
|
503
|
+
row.shared_encrypted_value as string | null,
|
|
504
|
+
);
|
|
505
|
+
if (decrypted.needsSharedCiphertext) {
|
|
506
|
+
await populateSharedAppSecret(row.id, decrypted.value);
|
|
507
|
+
}
|
|
508
|
+
last4Value = last4(decrypted.value);
|
|
377
509
|
} catch {
|
|
378
510
|
last4Value = "";
|
|
379
511
|
}
|
|
380
|
-
|
|
512
|
+
results.push({
|
|
381
513
|
key: row.key as string,
|
|
382
514
|
scope,
|
|
383
515
|
scopeId,
|
|
@@ -386,8 +518,9 @@ export async function listAppSecretsForScope(
|
|
|
386
518
|
urlAllowlist: parseAllowlist(row.url_allowlist as string | null),
|
|
387
519
|
createdAt: Number(row.created_at ?? 0),
|
|
388
520
|
updatedAt: Number(row.updated_at ?? 0),
|
|
389
|
-
};
|
|
390
|
-
}
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
return results;
|
|
391
524
|
}
|
|
392
525
|
|
|
393
526
|
function parseAllowlist(raw: string | null): string[] | null {
|
|
@@ -686,6 +686,10 @@ export async function mergeCoreSharingActions(
|
|
|
686
686
|
"set-review-status",
|
|
687
687
|
() => import("../review/actions/set-review-status.js"),
|
|
688
688
|
],
|
|
689
|
+
[
|
|
690
|
+
"send-review-thread-to-agent",
|
|
691
|
+
() => import("../review/actions/send-review-thread-to-agent.js"),
|
|
692
|
+
],
|
|
689
693
|
// Org service tokens (CI credentials, e.g. PLAN_RECAP_TOKEN). Mint/revoke
|
|
690
694
|
// are toolCallable:false — preserved via preserveActionFlags below.
|
|
691
695
|
[
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
createError,
|
|
2
3
|
defineEventHandler,
|
|
3
4
|
setResponseStatus,
|
|
4
5
|
setResponseHeader,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
|
|
11
12
|
import { isAgentActionStopError } from "../action.js";
|
|
12
13
|
import type { ActionEntry } from "../agent/production-agent.js";
|
|
14
|
+
import { resolveOrgIdForEmail } from "../org/context.js";
|
|
13
15
|
import { readBody } from "../server/h3-helpers.js";
|
|
14
16
|
import { EMBED_TARGET_HEADER } from "../shared/embed-auth.js";
|
|
15
17
|
import {
|
|
@@ -18,6 +20,10 @@ import {
|
|
|
18
20
|
shouldAllowMcpEmbedCredentials,
|
|
19
21
|
} from "../shared/mcp-embed-headers.js";
|
|
20
22
|
import { notifyActionChange } from "./action-change.js";
|
|
23
|
+
import {
|
|
24
|
+
seedAgentRunOwnerContext,
|
|
25
|
+
type AgentRunOwnerContext,
|
|
26
|
+
} from "./agent-run-context.js";
|
|
21
27
|
import {
|
|
22
28
|
getAllowedCorsOrigin as resolveAllowedCorsOrigin,
|
|
23
29
|
readCorsAllowedOrigins,
|
|
@@ -164,6 +170,51 @@ function handleOptionsRequest(event: any): string {
|
|
|
164
170
|
return "";
|
|
165
171
|
}
|
|
166
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Declarative auth adapter for the HTTP action route. Its `resolveCaller` runs
|
|
175
|
+
* BEFORE the framework's `getOwnerFromEvent` / `getSession` chain, letting an
|
|
176
|
+
* app accept caller identities `getSession` doesn't understand (e.g. an A2A
|
|
177
|
+
* JWT) without reaching into request context from a Nitro `request` hook.
|
|
178
|
+
*
|
|
179
|
+
* Scoped to `/_agent-native/actions/*` only — it does not affect other routes.
|
|
180
|
+
*/
|
|
181
|
+
export type ActionRouteResolvedCaller = AgentRunOwnerContext & {
|
|
182
|
+
/**
|
|
183
|
+
* Org to scope the request to, verified from the same credential as the
|
|
184
|
+
* caller identity (e.g. the A2A token's org claim). When omitted, the org
|
|
185
|
+
* is derived from the verified owner email via the framework's owner→org
|
|
186
|
+
* membership lookup. The ambient session/org state on the request is never
|
|
187
|
+
* consulted for adapter-resolved callers: a request can carry both a valid
|
|
188
|
+
* A2A bearer and an unrelated browser cookie, and the cookie user's org
|
|
189
|
+
* must not leak into the token caller's request context.
|
|
190
|
+
*/
|
|
191
|
+
orgId?: string;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export interface ActionRouteAuthAdapter {
|
|
195
|
+
/**
|
|
196
|
+
* Resolve a caller from the raw event before the cookie/bearer chain.
|
|
197
|
+
*
|
|
198
|
+
* - Return the resolved caller to run the action scoped to that identity.
|
|
199
|
+
* Org scoping comes exclusively from the caller: the returned `orgId` if
|
|
200
|
+
* set, otherwise the owner-email membership lookup — never from the
|
|
201
|
+
* request's session cookie or org context.
|
|
202
|
+
* - Return `null` when the credential isn't yours to judge — the request
|
|
203
|
+
* defers to `getOwnerFromEvent` / `getSession`.
|
|
204
|
+
* - THROW to hard-reject: the credential is present but invalid (e.g. an
|
|
205
|
+
* expired or forged A2A bearer). The action route responds 401 and does
|
|
206
|
+
* NOT fall through to the cookie/session chain, so a valid same-origin
|
|
207
|
+
* session cookie can't be used to execute the request as the logged-in
|
|
208
|
+
* user. Do not throw merely to signal "not mine" — return `null` for that.
|
|
209
|
+
*/
|
|
210
|
+
resolveCaller?: (
|
|
211
|
+
event: any,
|
|
212
|
+
) =>
|
|
213
|
+
| ActionRouteResolvedCaller
|
|
214
|
+
| null
|
|
215
|
+
| Promise<ActionRouteResolvedCaller | null>;
|
|
216
|
+
}
|
|
217
|
+
|
|
167
218
|
export interface MountActionRoutesOptions {
|
|
168
219
|
/** Resolve owner email from the H3 event (for data scoping). */
|
|
169
220
|
getOwnerFromEvent?: (event: any) => string | Promise<string>;
|
|
@@ -173,6 +224,18 @@ export interface MountActionRoutesOptions {
|
|
|
173
224
|
) => string | undefined | Promise<string | undefined>;
|
|
174
225
|
/** Resolve org ID from the H3 event (for org scoping). */
|
|
175
226
|
resolveOrgId?: (event: any) => string | null | Promise<string | null>;
|
|
227
|
+
/**
|
|
228
|
+
* Optional caller resolver that runs before the `getOwnerFromEvent` /
|
|
229
|
+
* `getSession` chain. Lets apps accept A2A JWTs (or other bearer schemes) on
|
|
230
|
+
* the action route declaratively. See {@link ActionRouteAuthAdapter}.
|
|
231
|
+
*/
|
|
232
|
+
actionRouteAuth?: ActionRouteAuthAdapter;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function normalizeOrgId(value: string | null | undefined): string | undefined {
|
|
236
|
+
return typeof value === "string" && value.trim().length > 0
|
|
237
|
+
? value.trim()
|
|
238
|
+
: undefined;
|
|
176
239
|
}
|
|
177
240
|
|
|
178
241
|
function isAuthResolutionFailure(error: unknown): boolean {
|
|
@@ -259,7 +322,42 @@ export function mountActionRoutes(
|
|
|
259
322
|
// Resolve auth context for per-request scoping
|
|
260
323
|
let userEmail: string | undefined;
|
|
261
324
|
let userName: string | undefined;
|
|
262
|
-
|
|
325
|
+
// An app-supplied auth adapter runs first: it can accept caller
|
|
326
|
+
// identities the framework's getSession chain doesn't understand (e.g.
|
|
327
|
+
// an A2A JWT). A resolved caller is seeded onto the event context so any
|
|
328
|
+
// downstream resolveAgentRunOwnerContext (nested agent runs) sees the
|
|
329
|
+
// same identity. The adapter is only consulted for the action route, so
|
|
330
|
+
// it can't affect other surfaces.
|
|
331
|
+
//
|
|
332
|
+
// Contract: `resolveCaller` returning `null` means "this credential
|
|
333
|
+
// isn't mine — defer to the cookie/session chain below". THROWING means
|
|
334
|
+
// "the credential is mine but invalid" (e.g. an expired/forged A2A
|
|
335
|
+
// bearer) and is a hard rejection: we surface a 401 instead of falling
|
|
336
|
+
// through, so a live same-origin session cookie can't silently execute
|
|
337
|
+
// the request as the logged-in user.
|
|
338
|
+
let resolvedCaller: ActionRouteResolvedCaller | null = null;
|
|
339
|
+
if (options?.actionRouteAuth?.resolveCaller) {
|
|
340
|
+
let caller: ActionRouteResolvedCaller | null;
|
|
341
|
+
try {
|
|
342
|
+
caller = await options.actionRouteAuth.resolveCaller(event);
|
|
343
|
+
} catch {
|
|
344
|
+
throw createError({
|
|
345
|
+
statusCode: 401,
|
|
346
|
+
statusMessage: "Unauthorized",
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
if (caller) {
|
|
350
|
+
seedAgentRunOwnerContext(event, {
|
|
351
|
+
owner: caller.owner,
|
|
352
|
+
anonymous: caller.anonymous,
|
|
353
|
+
name: caller.name,
|
|
354
|
+
});
|
|
355
|
+
userEmail = caller.owner;
|
|
356
|
+
userName = caller.name;
|
|
357
|
+
resolvedCaller = caller;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (!resolvedCaller && options?.getOwnerFromEvent) {
|
|
263
361
|
try {
|
|
264
362
|
userEmail = await options.getOwnerFromEvent(event);
|
|
265
363
|
userName = options?.getUserNameFromEvent
|
|
@@ -277,9 +375,32 @@ export function mountActionRoutes(
|
|
|
277
375
|
}
|
|
278
376
|
}
|
|
279
377
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
378
|
+
// Org scoping. For adapter-resolved callers the org must come
|
|
379
|
+
// exclusively from the verified credential: the adapter-asserted
|
|
380
|
+
// orgId when present, otherwise the owner-email membership lookup.
|
|
381
|
+
// The request's ambient session/org state (`resolveOrgId`, usually
|
|
382
|
+
// getSession-backed) is deliberately NOT consulted — a request can
|
|
383
|
+
// carry both a valid A2A bearer and an unrelated same-origin browser
|
|
384
|
+
// cookie, and the cookie user's org must not become the org the
|
|
385
|
+
// token caller's actions execute under. Non-adapter callers keep the
|
|
386
|
+
// original resolveOrgId-only behavior.
|
|
387
|
+
let orgId: string | undefined;
|
|
388
|
+
if (resolvedCaller) {
|
|
389
|
+
orgId = normalizeOrgId(resolvedCaller.orgId);
|
|
390
|
+
if (!orgId && resolvedCaller.owner && !resolvedCaller.anonymous) {
|
|
391
|
+
try {
|
|
392
|
+
orgId = normalizeOrgId(
|
|
393
|
+
await resolveOrgIdForEmail(resolvedCaller.owner),
|
|
394
|
+
);
|
|
395
|
+
} catch {
|
|
396
|
+
// Org tables may not exist yet on first boot.
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
} else {
|
|
400
|
+
orgId = options?.resolveOrgId
|
|
401
|
+
? ((await options.resolveOrgId(event)) ?? undefined)
|
|
402
|
+
: undefined;
|
|
403
|
+
}
|
|
283
404
|
const timezone = readTimezoneHeader(event);
|
|
284
405
|
|
|
285
406
|
return runWithRequestContext(
|
|
@@ -109,6 +109,22 @@ export interface AgentChatPluginOptions {
|
|
|
109
109
|
* agent mutations.
|
|
110
110
|
*/
|
|
111
111
|
anonymousReadOnly?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Optional auth adapter for the HTTP action route
|
|
114
|
+
* (`/_agent-native/actions/*`). Its `resolveCaller` runs before the
|
|
115
|
+
* cookie/bearer `getSession` chain, letting an app accept caller identities
|
|
116
|
+
* `getSession` doesn't understand (e.g. an A2A JWT verified with
|
|
117
|
+
* `verifyA2AToken`) declaratively, instead of pre-seeding request context
|
|
118
|
+
* from a Nitro `request` hook.
|
|
119
|
+
*
|
|
120
|
+
* Returning `null` defers to the normal chain; THROWING hard-rejects with a
|
|
121
|
+
* 401 (an invalid/forged credential must not fall through to a same-origin
|
|
122
|
+
* session cookie). A resolved caller's org comes exclusively from the
|
|
123
|
+
* verified credential — the returned `orgId` or the owner-email membership
|
|
124
|
+
* lookup — never from the request's session cookie.
|
|
125
|
+
* See {@link import("../action-routes.js").ActionRouteAuthAdapter}.
|
|
126
|
+
*/
|
|
127
|
+
actionRouteAuth?: import("../action-routes.js").ActionRouteAuthAdapter;
|
|
112
128
|
/**
|
|
113
129
|
* Optional callback to append template-specific context to the system
|
|
114
130
|
* prompt on each request. Runs after AGENTS.md / skills / memory are
|
|
@@ -241,6 +241,7 @@ export {
|
|
|
241
241
|
renderAgentNativeOgImageSvg,
|
|
242
242
|
type AgentNativeOgImageInput,
|
|
243
243
|
} from "./social-og-image.js";
|
|
244
|
+
export { resolveOgFontFiles } from "./og-fonts.js";
|
|
244
245
|
export {
|
|
245
246
|
createBrowserSessionActionEntries,
|
|
246
247
|
type CreateBrowserSessionActionEntriesOptions,
|
|
@@ -320,7 +321,14 @@ export {
|
|
|
320
321
|
export {
|
|
321
322
|
mountActionRoutes,
|
|
322
323
|
type MountActionRoutesOptions,
|
|
324
|
+
type ActionRouteAuthAdapter,
|
|
325
|
+
type ActionRouteResolvedCaller,
|
|
323
326
|
} from "./action-routes.js";
|
|
327
|
+
export {
|
|
328
|
+
AGENT_RUN_OWNER_CONTEXT_KEY,
|
|
329
|
+
seedAgentRunOwnerContext,
|
|
330
|
+
type AgentRunOwnerContext,
|
|
331
|
+
} from "./agent-run-context.js";
|
|
324
332
|
export {
|
|
325
333
|
runWithRequestContext,
|
|
326
334
|
hasRequestContext,
|
|
@@ -141,6 +141,10 @@ const CORE_SHARING_ACTIONS: Array<{ name: string; specifier: string }> = [
|
|
|
141
141
|
name: "set-review-status",
|
|
142
142
|
specifier: "@agent-native/core/review/actions/set-review-status",
|
|
143
143
|
},
|
|
144
|
+
{
|
|
145
|
+
name: "send-review-thread-to-agent",
|
|
146
|
+
specifier: "@agent-native/core/review/actions/send-review-thread-to-agent",
|
|
147
|
+
},
|
|
144
148
|
];
|
|
145
149
|
|
|
146
150
|
function isRuntimeSourceFile(filename: string): boolean {
|