@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,14 +1,31 @@
|
|
|
1
|
+
import { Avatar, AvatarFallback } from "@agent-native/toolkit/ui/avatar";
|
|
2
|
+
import { Button } from "@agent-native/toolkit/ui/button";
|
|
1
3
|
import {
|
|
4
|
+
DropdownMenu,
|
|
5
|
+
DropdownMenuContent,
|
|
6
|
+
DropdownMenuItem,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
} from "@agent-native/toolkit/ui/dropdown-menu";
|
|
9
|
+
import { Input } from "@agent-native/toolkit/ui/input";
|
|
10
|
+
import { Skeleton } from "@agent-native/toolkit/ui/skeleton";
|
|
11
|
+
import { Spinner } from "@agent-native/toolkit/ui/spinner";
|
|
12
|
+
import {
|
|
13
|
+
IconCircleCheck,
|
|
14
|
+
IconDots,
|
|
2
15
|
IconMessageCircle,
|
|
3
|
-
IconPlus,
|
|
4
16
|
IconSend,
|
|
5
17
|
IconTrash,
|
|
6
|
-
|
|
18
|
+
IconX,
|
|
7
19
|
} from "@tabler/icons-react";
|
|
8
|
-
import { useMemo, useState } from "react";
|
|
20
|
+
import { useMemo, useState, type ReactNode } from "react";
|
|
9
21
|
|
|
10
|
-
import type {
|
|
22
|
+
import type {
|
|
23
|
+
ReviewComment,
|
|
24
|
+
ReviewResolutionTarget,
|
|
25
|
+
} from "../../review/types.js";
|
|
26
|
+
import { useFormatters } from "../i18n.js";
|
|
11
27
|
import { cn } from "../utils.js";
|
|
28
|
+
import { ReviewCommentComposer } from "./ReviewCommentComposer.js";
|
|
12
29
|
import { ReviewStatusBadge } from "./ReviewStatusBadge.js";
|
|
13
30
|
import {
|
|
14
31
|
useCreateReviewComment,
|
|
@@ -23,6 +40,14 @@ export interface ReviewThread {
|
|
|
23
40
|
replies: ReviewComment[];
|
|
24
41
|
}
|
|
25
42
|
|
|
43
|
+
export type ReviewThreadCapability =
|
|
44
|
+
| boolean
|
|
45
|
+
| ((thread: ReviewThread) => boolean);
|
|
46
|
+
|
|
47
|
+
export type ReviewCommentCapability =
|
|
48
|
+
| boolean
|
|
49
|
+
| ((comment: ReviewComment, thread: ReviewThread) => boolean);
|
|
50
|
+
|
|
26
51
|
export interface ReviewThreadPanelProps {
|
|
27
52
|
resourceType: string;
|
|
28
53
|
resourceId: string;
|
|
@@ -31,9 +56,33 @@ export interface ReviewThreadPanelProps {
|
|
|
31
56
|
className?: string;
|
|
32
57
|
includeResolved?: boolean;
|
|
33
58
|
showComposer?: boolean;
|
|
59
|
+
showHeader?: boolean;
|
|
60
|
+
variant?: "card" | "plain";
|
|
34
61
|
placeholder?: string;
|
|
35
62
|
emptyState?: string;
|
|
63
|
+
loadingLabel?: string;
|
|
64
|
+
replyLabel?: string;
|
|
65
|
+
replyPlaceholder?: string;
|
|
66
|
+
cancelReplyLabel?: string;
|
|
67
|
+
resolveLabel?: string;
|
|
68
|
+
deleteLabel?: string;
|
|
69
|
+
moreActionsLabel?: string;
|
|
70
|
+
resolvedLabel?: string;
|
|
71
|
+
reviewerLabel?: string;
|
|
36
72
|
onSelectThread?: (thread: ReviewThread) => void;
|
|
73
|
+
onCommentCreated?: (comment: ReviewComment) => void;
|
|
74
|
+
/** Allow signed-in commenters to reply. Omitted capabilities fail closed. */
|
|
75
|
+
canReply?: ReviewThreadCapability;
|
|
76
|
+
/** Allow editors to resolve a thread. Omitted capabilities fail closed. */
|
|
77
|
+
canResolve?: ReviewThreadCapability;
|
|
78
|
+
/** Allow deletion only for comments the caller has authorized. */
|
|
79
|
+
canDeleteComment?: ReviewCommentCapability;
|
|
80
|
+
/** Extra per-thread controls rendered next to reply/resolve/delete. */
|
|
81
|
+
renderThreadActions?: (thread: ReviewThread) => ReactNode;
|
|
82
|
+
/** Show a separate agent-submit action when the host supports agent routing. */
|
|
83
|
+
showComposerTargetPicker?: boolean;
|
|
84
|
+
composerCommentLabel?: string;
|
|
85
|
+
composerAgentLabel?: string;
|
|
37
86
|
}
|
|
38
87
|
|
|
39
88
|
export function ReviewThreadPanel({
|
|
@@ -44,12 +93,35 @@ export function ReviewThreadPanel({
|
|
|
44
93
|
className,
|
|
45
94
|
includeResolved = true,
|
|
46
95
|
showComposer = true,
|
|
96
|
+
showHeader = true,
|
|
97
|
+
variant = "card",
|
|
47
98
|
placeholder = "Add a comment...",
|
|
48
99
|
emptyState = "No review comments yet.",
|
|
100
|
+
loadingLabel = "Loading comments",
|
|
101
|
+
replyLabel = "Reply",
|
|
102
|
+
replyPlaceholder = "Reply...",
|
|
103
|
+
cancelReplyLabel = "Cancel reply",
|
|
104
|
+
resolveLabel = "Resolve",
|
|
105
|
+
deleteLabel = "Delete comment",
|
|
106
|
+
moreActionsLabel = "More actions",
|
|
107
|
+
resolvedLabel = "Resolved",
|
|
108
|
+
reviewerLabel = "Reviewer",
|
|
49
109
|
onSelectThread,
|
|
110
|
+
onCommentCreated,
|
|
111
|
+
canReply = false,
|
|
112
|
+
canResolve = false,
|
|
113
|
+
canDeleteComment = false,
|
|
114
|
+
renderThreadActions,
|
|
115
|
+
showComposerTargetPicker = false,
|
|
116
|
+
composerCommentLabel = "Comment",
|
|
117
|
+
composerAgentLabel = "Send to agent",
|
|
50
118
|
}: ReviewThreadPanelProps) {
|
|
51
119
|
const [draft, setDraft] = useState("");
|
|
120
|
+
const [submittingTarget, setSubmittingTarget] =
|
|
121
|
+
useState<ReviewResolutionTarget | null>(null);
|
|
122
|
+
const [replyingThreadId, setReplyingThreadId] = useState<string | null>(null);
|
|
52
123
|
const [replyDrafts, setReplyDrafts] = useState<Record<string, string>>({});
|
|
124
|
+
const { formatDate } = useFormatters();
|
|
53
125
|
const comments = useReviewComments({
|
|
54
126
|
resourceType,
|
|
55
127
|
resourceId,
|
|
@@ -65,153 +137,291 @@ export function ReviewThreadPanel({
|
|
|
65
137
|
[comments.data?.comments],
|
|
66
138
|
);
|
|
67
139
|
|
|
140
|
+
const submitDraft = (resolutionTarget: ReviewResolutionTarget) => {
|
|
141
|
+
const body = draft.trim();
|
|
142
|
+
if (!body || createComment.isPending) return;
|
|
143
|
+
setSubmittingTarget(resolutionTarget);
|
|
144
|
+
createComment.mutate(
|
|
145
|
+
{
|
|
146
|
+
resourceType,
|
|
147
|
+
resourceId,
|
|
148
|
+
targetId,
|
|
149
|
+
body,
|
|
150
|
+
...(showComposerTargetPicker ? { resolutionTarget } : {}),
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
onSuccess: (comment) => {
|
|
154
|
+
setDraft("");
|
|
155
|
+
onCommentCreated?.(comment);
|
|
156
|
+
},
|
|
157
|
+
onSettled: () => setSubmittingTarget(null),
|
|
158
|
+
},
|
|
159
|
+
);
|
|
160
|
+
};
|
|
161
|
+
|
|
68
162
|
return (
|
|
69
163
|
<section
|
|
70
164
|
className={cn(
|
|
71
|
-
"
|
|
165
|
+
"@container/review overflow-hidden text-card-foreground",
|
|
166
|
+
variant === "card"
|
|
167
|
+
? "rounded-lg border border-border bg-card"
|
|
168
|
+
: "bg-transparent",
|
|
72
169
|
className,
|
|
73
170
|
)}
|
|
74
171
|
>
|
|
75
|
-
|
|
76
|
-
<div className="flex items-center gap-2">
|
|
77
|
-
<
|
|
78
|
-
|
|
172
|
+
{showHeader ? (
|
|
173
|
+
<div className="flex items-center justify-between gap-3 border-b border-border px-3 py-2.5">
|
|
174
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
175
|
+
<IconMessageCircle className="size-4 shrink-0 text-muted-foreground" />
|
|
176
|
+
<h2 className="truncate text-sm font-medium">{title}</h2>
|
|
177
|
+
</div>
|
|
178
|
+
<ReviewStatusBadge
|
|
179
|
+
status={comments.data?.reviewStatus?.status}
|
|
180
|
+
className="shrink-0"
|
|
181
|
+
/>
|
|
79
182
|
</div>
|
|
80
|
-
|
|
81
|
-
</div>
|
|
183
|
+
) : null}
|
|
82
184
|
|
|
83
185
|
{showComposer ? (
|
|
84
|
-
<
|
|
85
|
-
className="border-b border-border
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
<textarea
|
|
97
|
-
value={draft}
|
|
98
|
-
onChange={(event) => setDraft(event.currentTarget.value)}
|
|
99
|
-
placeholder={placeholder}
|
|
100
|
-
className="min-h-20 w-full resize-y rounded-md border border-input bg-background px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-ring"
|
|
101
|
-
/>
|
|
102
|
-
<div className="mt-2 flex justify-end">
|
|
103
|
-
<button
|
|
104
|
-
type="submit"
|
|
105
|
-
disabled={!draft.trim() || createComment.isPending}
|
|
106
|
-
className="inline-flex h-8 items-center gap-1.5 rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50"
|
|
107
|
-
>
|
|
108
|
-
<IconPlus className="h-3.5 w-3.5" />
|
|
109
|
-
Comment
|
|
110
|
-
</button>
|
|
111
|
-
</div>
|
|
112
|
-
</form>
|
|
186
|
+
<ReviewCommentComposer
|
|
187
|
+
className="border-b border-border px-3 py-3"
|
|
188
|
+
value={draft}
|
|
189
|
+
onChange={setDraft}
|
|
190
|
+
onSubmit={submitDraft}
|
|
191
|
+
submittingTarget={submittingTarget}
|
|
192
|
+
disabled={createComment.isPending}
|
|
193
|
+
showAgentAction={showComposerTargetPicker}
|
|
194
|
+
placeholder={placeholder}
|
|
195
|
+
commentLabel={composerCommentLabel}
|
|
196
|
+
agentLabel={composerAgentLabel}
|
|
197
|
+
/>
|
|
113
198
|
) : null}
|
|
114
199
|
|
|
115
200
|
<div className="divide-y divide-border">
|
|
116
201
|
{comments.isLoading ? (
|
|
117
|
-
<div
|
|
118
|
-
|
|
202
|
+
<div
|
|
203
|
+
className="flex flex-col gap-3 px-3 py-4"
|
|
204
|
+
aria-label={loadingLabel}
|
|
205
|
+
>
|
|
206
|
+
<div className="flex items-center gap-2.5">
|
|
207
|
+
<Skeleton className="size-7 rounded-full" />
|
|
208
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1.5">
|
|
209
|
+
<Skeleton className="h-3 w-2/5" />
|
|
210
|
+
<Skeleton className="h-3 w-4/5" />
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
<Skeleton className="h-8 w-full" />
|
|
119
214
|
</div>
|
|
120
215
|
) : threads.length ? (
|
|
121
|
-
threads.map((thread) =>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
{
|
|
149
|
-
onSuccess: () =>
|
|
150
|
-
setReplyDrafts((current) => ({
|
|
151
|
-
...current,
|
|
152
|
-
[thread.root.id]: "",
|
|
153
|
-
})),
|
|
154
|
-
},
|
|
155
|
-
);
|
|
156
|
-
}}
|
|
216
|
+
threads.map((thread) => {
|
|
217
|
+
const replyDraft = replyDrafts[thread.root.id] ?? "";
|
|
218
|
+
const replying = replyingThreadId === thread.root.threadId;
|
|
219
|
+
const threadIsOpen = thread.root.status === "open";
|
|
220
|
+
const replyAllowed =
|
|
221
|
+
threadIsOpen && capabilityAllowsThread(canReply, thread);
|
|
222
|
+
const resolveAllowed =
|
|
223
|
+
threadIsOpen && capabilityAllowsThread(canResolve, thread);
|
|
224
|
+
const deleteAllowed = capabilityAllowsComment(
|
|
225
|
+
canDeleteComment,
|
|
226
|
+
thread.root,
|
|
227
|
+
thread,
|
|
228
|
+
);
|
|
229
|
+
const threadActions = renderThreadActions?.(thread);
|
|
230
|
+
const hasActions =
|
|
231
|
+
replyAllowed ||
|
|
232
|
+
resolveAllowed ||
|
|
233
|
+
deleteAllowed ||
|
|
234
|
+
Boolean(threadActions);
|
|
235
|
+
return (
|
|
236
|
+
<article
|
|
237
|
+
key={thread.root.threadId}
|
|
238
|
+
className={cn(
|
|
239
|
+
"group/thread px-3 py-3 transition-colors",
|
|
240
|
+
onSelectThread && "cursor-pointer hover:bg-muted/30",
|
|
241
|
+
)}
|
|
242
|
+
onClick={() => onSelectThread?.(thread)}
|
|
157
243
|
>
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
[thread.root.id]: event.currentTarget.value,
|
|
164
|
-
}))
|
|
165
|
-
}
|
|
166
|
-
placeholder="Reply..."
|
|
167
|
-
className="h-8 min-w-0 flex-1 rounded-md border border-input bg-background px-3 text-sm outline-none focus:ring-2 focus:ring-ring"
|
|
244
|
+
<CommentBubble
|
|
245
|
+
comment={thread.root}
|
|
246
|
+
resolvedLabel={resolvedLabel}
|
|
247
|
+
reviewerLabel={reviewerLabel}
|
|
248
|
+
formatDate={formatDate}
|
|
168
249
|
/>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
250
|
+
{thread.replies.length ? (
|
|
251
|
+
<div className="ms-3 mt-3 flex flex-col gap-3 border-s border-border ps-3">
|
|
252
|
+
{thread.replies.map((reply) => (
|
|
253
|
+
<CommentBubble
|
|
254
|
+
key={reply.id}
|
|
255
|
+
comment={reply}
|
|
256
|
+
compact
|
|
257
|
+
resolvedLabel={resolvedLabel}
|
|
258
|
+
reviewerLabel={reviewerLabel}
|
|
259
|
+
formatDate={formatDate}
|
|
260
|
+
/>
|
|
261
|
+
))}
|
|
262
|
+
</div>
|
|
263
|
+
) : null}
|
|
264
|
+
|
|
265
|
+
{replying && replyAllowed ? (
|
|
266
|
+
<form
|
|
267
|
+
className="mt-3 flex min-w-0 items-center gap-1.5"
|
|
268
|
+
onClick={(event) => event.stopPropagation()}
|
|
269
|
+
onSubmit={(event) => {
|
|
270
|
+
event.preventDefault();
|
|
271
|
+
const body = replyDraft.trim();
|
|
272
|
+
if (!body || replyComment.isPending) return;
|
|
273
|
+
replyComment.mutate(
|
|
274
|
+
{
|
|
275
|
+
resourceType,
|
|
276
|
+
resourceId,
|
|
277
|
+
commentId: thread.root.id,
|
|
278
|
+
body,
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
onSuccess: () => {
|
|
282
|
+
setReplyDrafts((current) => ({
|
|
283
|
+
...current,
|
|
284
|
+
[thread.root.id]: "",
|
|
285
|
+
}));
|
|
286
|
+
setReplyingThreadId(null);
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
);
|
|
290
|
+
}}
|
|
291
|
+
>
|
|
292
|
+
<Input
|
|
293
|
+
autoFocus
|
|
294
|
+
value={replyDraft}
|
|
295
|
+
onChange={(event) =>
|
|
296
|
+
setReplyDrafts((current) => ({
|
|
297
|
+
...current,
|
|
298
|
+
[thread.root.id]: event.currentTarget.value,
|
|
299
|
+
}))
|
|
300
|
+
}
|
|
301
|
+
onKeyDown={(event) => {
|
|
302
|
+
if (event.key === "Escape") {
|
|
303
|
+
event.preventDefault();
|
|
304
|
+
event.stopPropagation();
|
|
305
|
+
setReplyingThreadId(null);
|
|
306
|
+
}
|
|
307
|
+
}}
|
|
308
|
+
placeholder={replyPlaceholder}
|
|
309
|
+
className="h-8 min-w-0 flex-1 text-sm"
|
|
310
|
+
/>
|
|
311
|
+
<Button
|
|
312
|
+
type="submit"
|
|
313
|
+
size="icon"
|
|
314
|
+
variant="outline"
|
|
315
|
+
className="size-8 shrink-0"
|
|
316
|
+
disabled={!replyDraft.trim() || replyComment.isPending}
|
|
317
|
+
aria-label={replyLabel}
|
|
318
|
+
>
|
|
319
|
+
{replyComment.isPending ? (
|
|
320
|
+
<Spinner className="size-3.5" />
|
|
321
|
+
) : (
|
|
322
|
+
<IconSend className="size-3.5" />
|
|
323
|
+
)}
|
|
324
|
+
</Button>
|
|
325
|
+
<Button
|
|
326
|
+
type="button"
|
|
327
|
+
size="icon"
|
|
328
|
+
variant="ghost"
|
|
329
|
+
className="size-8 shrink-0"
|
|
330
|
+
aria-label={cancelReplyLabel}
|
|
331
|
+
onClick={() => setReplyingThreadId(null)}
|
|
332
|
+
>
|
|
333
|
+
<IconX className="size-3.5" />
|
|
334
|
+
</Button>
|
|
335
|
+
</form>
|
|
336
|
+
) : hasActions ? (
|
|
337
|
+
<div
|
|
338
|
+
className="mt-2.5 flex min-w-0 items-center gap-0.5"
|
|
339
|
+
onClick={(event) => event.stopPropagation()}
|
|
192
340
|
>
|
|
193
|
-
|
|
194
|
-
|
|
341
|
+
{replyAllowed ? (
|
|
342
|
+
<Button
|
|
343
|
+
type="button"
|
|
344
|
+
variant="ghost"
|
|
345
|
+
size="sm"
|
|
346
|
+
className="h-7 min-w-0 gap-1.5 px-1.5 text-xs @xs/review:px-2"
|
|
347
|
+
aria-label={replyLabel}
|
|
348
|
+
onClick={() =>
|
|
349
|
+
setReplyingThreadId(thread.root.threadId)
|
|
350
|
+
}
|
|
351
|
+
>
|
|
352
|
+
<IconMessageCircle className="size-3.5" />
|
|
353
|
+
<span className="hidden @2xs/review:inline">
|
|
354
|
+
{replyLabel}
|
|
355
|
+
</span>
|
|
356
|
+
</Button>
|
|
357
|
+
) : null}
|
|
358
|
+
<div className="ms-auto flex min-w-0 items-center gap-0.5">
|
|
359
|
+
{threadActions}
|
|
360
|
+
{resolveAllowed ? (
|
|
361
|
+
<Button
|
|
362
|
+
type="button"
|
|
363
|
+
variant="ghost"
|
|
364
|
+
size="sm"
|
|
365
|
+
className="h-7 min-w-0 gap-1.5 px-1.5 text-xs @xs/review:px-2"
|
|
366
|
+
disabled={resolveThread.isPending}
|
|
367
|
+
aria-label={resolveLabel}
|
|
368
|
+
onClick={() =>
|
|
369
|
+
resolveThread.mutate({
|
|
370
|
+
resourceType,
|
|
371
|
+
resourceId,
|
|
372
|
+
threadId: thread.root.threadId,
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
>
|
|
376
|
+
{resolveThread.isPending ? (
|
|
377
|
+
<Spinner className="size-3.5" />
|
|
378
|
+
) : (
|
|
379
|
+
<IconCircleCheck className="size-3.5" />
|
|
380
|
+
)}
|
|
381
|
+
<span className="hidden @xs/review:inline">
|
|
382
|
+
{resolveLabel}
|
|
383
|
+
</span>
|
|
384
|
+
</Button>
|
|
385
|
+
) : null}
|
|
386
|
+
{deleteAllowed ? (
|
|
387
|
+
<DropdownMenu>
|
|
388
|
+
<DropdownMenuTrigger asChild>
|
|
389
|
+
<Button
|
|
390
|
+
type="button"
|
|
391
|
+
variant="ghost"
|
|
392
|
+
size="icon"
|
|
393
|
+
className="size-7 shrink-0"
|
|
394
|
+
aria-label={moreActionsLabel}
|
|
395
|
+
>
|
|
396
|
+
<IconDots className="size-4" />
|
|
397
|
+
</Button>
|
|
398
|
+
</DropdownMenuTrigger>
|
|
399
|
+
<DropdownMenuContent align="end" className="w-44">
|
|
400
|
+
<DropdownMenuItem
|
|
401
|
+
disabled={deleteComment.isPending}
|
|
402
|
+
className="text-destructive focus:text-destructive"
|
|
403
|
+
onSelect={() =>
|
|
404
|
+
deleteComment.mutate({
|
|
405
|
+
resourceType,
|
|
406
|
+
resourceId,
|
|
407
|
+
commentId: thread.root.id,
|
|
408
|
+
})
|
|
409
|
+
}
|
|
410
|
+
>
|
|
411
|
+
<IconTrash className="size-4" />
|
|
412
|
+
{deleteLabel}
|
|
413
|
+
</DropdownMenuItem>
|
|
414
|
+
</DropdownMenuContent>
|
|
415
|
+
</DropdownMenu>
|
|
416
|
+
) : null}
|
|
417
|
+
</div>
|
|
418
|
+
</div>
|
|
195
419
|
) : null}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
aria-label="Delete comment"
|
|
200
|
-
onClick={() =>
|
|
201
|
-
deleteComment.mutate({
|
|
202
|
-
resourceType,
|
|
203
|
-
resourceId,
|
|
204
|
-
commentId: thread.root.id,
|
|
205
|
-
})
|
|
206
|
-
}
|
|
207
|
-
>
|
|
208
|
-
<IconTrash className="h-3.5 w-3.5" />
|
|
209
|
-
</button>
|
|
210
|
-
</form>
|
|
211
|
-
</article>
|
|
212
|
-
))
|
|
420
|
+
</article>
|
|
421
|
+
);
|
|
422
|
+
})
|
|
213
423
|
) : (
|
|
214
|
-
<div className="px-4 py-
|
|
424
|
+
<div className="px-4 py-8 text-center text-sm text-muted-foreground">
|
|
215
425
|
{emptyState}
|
|
216
426
|
</div>
|
|
217
427
|
)}
|
|
@@ -243,36 +453,158 @@ export function buildReviewThreads(comments: ReviewComment[]): ReviewThread[] {
|
|
|
243
453
|
function CommentBubble({
|
|
244
454
|
comment,
|
|
245
455
|
compact = false,
|
|
456
|
+
resolvedLabel,
|
|
457
|
+
reviewerLabel,
|
|
458
|
+
formatDate,
|
|
246
459
|
}: {
|
|
247
460
|
comment: ReviewComment;
|
|
248
461
|
compact?: boolean;
|
|
462
|
+
resolvedLabel: string;
|
|
463
|
+
reviewerLabel: string;
|
|
464
|
+
formatDate: ReturnType<typeof useFormatters>["formatDate"];
|
|
249
465
|
}) {
|
|
466
|
+
const author = comment.authorName ?? comment.authorEmail ?? reviewerLabel;
|
|
467
|
+
const resolutionNote =
|
|
468
|
+
comment.status === "resolved" ? getReviewResolutionNote(comment) : null;
|
|
469
|
+
const bodyIsResolutionNote =
|
|
470
|
+
resolutionNote !== null &&
|
|
471
|
+
resolutionNote === comment.body.trim() &&
|
|
472
|
+
isResolutionNoteMetadata(comment.metadata);
|
|
250
473
|
return (
|
|
251
|
-
<div className=
|
|
252
|
-
<
|
|
253
|
-
<
|
|
254
|
-
{
|
|
255
|
-
</
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
<
|
|
261
|
-
|
|
262
|
-
|
|
474
|
+
<div className="flex min-w-0 items-start gap-2.5">
|
|
475
|
+
<Avatar className={compact ? "size-5" : "size-7"}>
|
|
476
|
+
<AvatarFallback className="text-[10px] font-semibold text-muted-foreground">
|
|
477
|
+
{authorInitials(author)}
|
|
478
|
+
</AvatarFallback>
|
|
479
|
+
</Avatar>
|
|
480
|
+
<div className="min-w-0 flex-1">
|
|
481
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
482
|
+
<span className="truncate text-sm font-medium">{author}</span>
|
|
483
|
+
<time
|
|
484
|
+
className="shrink-0 text-[11px] text-muted-foreground"
|
|
485
|
+
dateTime={comment.createdAt}
|
|
486
|
+
>
|
|
487
|
+
{formatCommentDate(comment.createdAt, formatDate)}
|
|
488
|
+
</time>
|
|
489
|
+
{comment.status === "resolved" ? (
|
|
490
|
+
<span className="hidden shrink-0 rounded-full bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground @xs/review:inline-flex">
|
|
491
|
+
{resolvedLabel}
|
|
492
|
+
</span>
|
|
493
|
+
) : null}
|
|
494
|
+
</div>
|
|
495
|
+
{!bodyIsResolutionNote ? (
|
|
496
|
+
<p
|
|
497
|
+
className={cn(
|
|
498
|
+
"mt-1 whitespace-pre-wrap break-words text-foreground",
|
|
499
|
+
compact ? "text-xs leading-5" : "text-sm leading-5",
|
|
500
|
+
)}
|
|
501
|
+
>
|
|
502
|
+
{comment.body}
|
|
503
|
+
</p>
|
|
504
|
+
) : null}
|
|
505
|
+
{resolutionNote ? (
|
|
506
|
+
<div
|
|
507
|
+
className="mt-1.5 flex min-w-0 items-start gap-1.5 rounded-md bg-muted/60 px-2 py-1.5 text-muted-foreground"
|
|
508
|
+
aria-label={resolvedLabel}
|
|
509
|
+
>
|
|
510
|
+
<IconCircleCheck className="mt-0.5 size-3.5 shrink-0" />
|
|
511
|
+
<p className="min-w-0 whitespace-pre-wrap break-words text-xs leading-4">
|
|
512
|
+
{resolutionNote}
|
|
513
|
+
</p>
|
|
514
|
+
</div>
|
|
263
515
|
) : null}
|
|
264
516
|
</div>
|
|
265
|
-
<p className="mt-1 whitespace-pre-wrap text-sm text-foreground">
|
|
266
|
-
{comment.body}
|
|
267
|
-
</p>
|
|
268
517
|
</div>
|
|
269
518
|
);
|
|
270
519
|
}
|
|
271
520
|
|
|
272
|
-
function
|
|
521
|
+
function capabilityAllowsThread(
|
|
522
|
+
capability: ReviewThreadCapability,
|
|
523
|
+
thread: ReviewThread,
|
|
524
|
+
): boolean {
|
|
525
|
+
return typeof capability === "function" ? capability(thread) : capability;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function capabilityAllowsComment(
|
|
529
|
+
capability: ReviewCommentCapability,
|
|
530
|
+
comment: ReviewComment,
|
|
531
|
+
thread: ReviewThread,
|
|
532
|
+
): boolean {
|
|
533
|
+
return typeof capability === "function"
|
|
534
|
+
? capability(comment, thread)
|
|
535
|
+
: capability;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function getReviewResolutionNote(comment: ReviewComment): string | null {
|
|
539
|
+
const direct = comment.resolutionNote;
|
|
540
|
+
const metadata = comment.metadata;
|
|
541
|
+
const nestedResolution = metadata?.resolution;
|
|
542
|
+
const nestedNote =
|
|
543
|
+
isRecord(nestedResolution) && typeof nestedResolution.note === "string"
|
|
544
|
+
? nestedResolution.note
|
|
545
|
+
: null;
|
|
546
|
+
const metadataNote =
|
|
547
|
+
typeof metadata?.resolutionNote === "string"
|
|
548
|
+
? metadata.resolutionNote
|
|
549
|
+
: typeof metadata?.resolvedNote === "string"
|
|
550
|
+
? metadata.resolvedNote
|
|
551
|
+
: isResolutionNoteMetadata(metadata) &&
|
|
552
|
+
typeof metadata?.note === "string"
|
|
553
|
+
? metadata.note
|
|
554
|
+
: isResolutionNoteMetadata(metadata)
|
|
555
|
+
? comment.body
|
|
556
|
+
: null;
|
|
557
|
+
const candidate =
|
|
558
|
+
typeof direct === "string" ? direct : (metadataNote ?? nestedNote);
|
|
559
|
+
const normalized = candidate?.trim();
|
|
560
|
+
return normalized || null;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function isResolutionNoteMetadata(
|
|
564
|
+
metadata: Record<string, unknown> | null,
|
|
565
|
+
): boolean {
|
|
566
|
+
const marker = metadata?.type ?? metadata?.kind;
|
|
567
|
+
return (
|
|
568
|
+
marker === "resolution" ||
|
|
569
|
+
marker === "resolution_note" ||
|
|
570
|
+
marker === "resolution-note"
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
575
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
function authorInitials(value: string): string {
|
|
579
|
+
const normalized = value.split("@")[0]?.trim() ?? "";
|
|
580
|
+
const parts = normalized.split(/[\s._+-]+/).filter(Boolean);
|
|
581
|
+
const initials = parts
|
|
582
|
+
.slice(0, 2)
|
|
583
|
+
.map((part) => part[0]?.toUpperCase())
|
|
584
|
+
.join("");
|
|
585
|
+
return initials || "R";
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function formatCommentDate(
|
|
589
|
+
value: string,
|
|
590
|
+
formatDate: ReturnType<typeof useFormatters>["formatDate"],
|
|
591
|
+
): string {
|
|
273
592
|
const date = new Date(value);
|
|
274
|
-
if (Number.isNaN(date.getTime()))
|
|
275
|
-
|
|
593
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
594
|
+
const now = new Date();
|
|
595
|
+
const sameDay =
|
|
596
|
+
date.getFullYear() === now.getFullYear() &&
|
|
597
|
+
date.getMonth() === now.getMonth() &&
|
|
598
|
+
date.getDate() === now.getDate();
|
|
599
|
+
if (sameDay) {
|
|
600
|
+
return formatDate(date, { hour: "numeric", minute: "2-digit" });
|
|
276
601
|
}
|
|
277
|
-
|
|
602
|
+
if (date.getFullYear() === now.getFullYear()) {
|
|
603
|
+
return formatDate(date, { month: "short", day: "numeric" });
|
|
604
|
+
}
|
|
605
|
+
return formatDate(date, {
|
|
606
|
+
month: "short",
|
|
607
|
+
day: "numeric",
|
|
608
|
+
year: "numeric",
|
|
609
|
+
});
|
|
278
610
|
}
|