@agent-native/core 0.127.3 → 0.128.1
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 +101 -0
- package/corpus/core/README.md +5 -26
- package/corpus/core/docs/content/actions.mdx +47 -4
- package/corpus/core/docs/content/native-chat-ui.mdx +7 -0
- package/corpus/core/docs/content/organizations-teams-permissions.mdx +109 -3
- package/corpus/core/docs/content/template-design-collaboration-and-full-apps.mdx +15 -0
- package/corpus/core/docs/content/toolkit-org-team.mdx +72 -12
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/a2a/artifact-response.ts +36 -29
- package/corpus/core/src/action.ts +83 -2
- package/corpus/core/src/chat-threads/store.ts +48 -43
- package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +46 -3
- package/corpus/core/src/client/AgentPanel.tsx +26 -6
- package/corpus/core/src/client/AssistantChat.tsx +63 -7
- package/corpus/core/src/client/DefaultSpinner.tsx +29 -0
- package/corpus/core/src/client/org/TeamPage.tsx +161 -6
- package/corpus/core/src/client/org/hooks.ts +67 -0
- package/corpus/core/src/client/org/index.ts +9 -0
- package/corpus/core/src/client/transcription/use-live-transcription.ts +62 -10
- package/corpus/core/src/db/client.ts +42 -3
- package/corpus/core/src/db/ensure-additive-columns.ts +60 -33
- package/corpus/core/src/deploy/build.ts +31 -2
- package/corpus/core/src/mcp-client/routes.ts +10 -1
- package/corpus/core/src/org/app-roles-handlers.ts +152 -0
- package/corpus/core/src/org/app-roles.ts +355 -0
- package/corpus/core/src/org/index.ts +27 -1
- package/corpus/core/src/org/migrations.ts +22 -0
- package/corpus/core/src/org/plugin.ts +27 -0
- package/corpus/core/src/org/schema.ts +15 -0
- package/corpus/core/src/scripts/docs/search.ts +17 -0
- package/corpus/core/src/scripts/docs/source-search.ts +10 -0
- package/corpus/core/src/server/agent-chat/script-entries.ts +3 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +53 -52
- package/corpus/core/src/server/builder-design-systems.ts +299 -82
- package/corpus/core/src/server/core-routes-plugin.ts +6 -1
- package/corpus/core/src/server/framework-request-handler.ts +44 -6
- package/corpus/core/src/server/index.ts +8 -0
- package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +31 -0
- package/corpus/core/src/templates/headless/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/analytics/_gitignore +2 -0
- package/corpus/templates/analytics/actions/data-source-status.ts +21 -12
- package/corpus/templates/analytics/app/global.css +7 -7
- package/corpus/templates/analytics/app/i18n-data.ts +30 -0
- package/corpus/templates/analytics/app/lib/data-source-status.ts +2 -1
- package/corpus/templates/analytics/app/pages/DataSources.tsx +54 -10
- package/corpus/templates/analytics/changelog/2026-07-28-analytics-pages-load-reliably-with-large-dashboard-workspaces.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-28-dashboard-loading-shimmer-now-flows-smoothly-in-one-directi.md +6 -0
- package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +5 -4
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +54 -42
- package/corpus/templates/analytics/server/plugins/db.ts +1 -18
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/assets/_gitignore +2 -0
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/calendar/_gitignore +2 -0
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/clips/_gitignore +2 -0
- package/corpus/templates/clips/actions/request-transcript.ts +77 -11
- package/corpus/templates/clips/actions/save-browser-transcript.ts +28 -7
- package/corpus/templates/clips/app/routes/record.tsx +11 -3
- package/corpus/templates/clips/changelog/2026-07-28-browser-recordings-no-longer-save-a-truncated-transcript-as-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-browser-recordings-no-longer-stop-transcribing-partway-throu.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-desktop-full-screen-clips-now-get-an-instant-local-transcrip.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-long-transcriptions-no-longer-show-a-false-transcription-sto.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-restarting-for-an-update-now-installs-the-newest-release-ins.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-the-meeting-recording-pill-now-anchors-to-the-right-edge-of-.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +31 -2
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +114 -13
- package/corpus/templates/clips/desktop/src/lib/updater.ts +12 -4
- package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +40 -15
- package/corpus/templates/clips/desktop/src/styles.css +10 -7
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +21 -14
- package/corpus/templates/clips/shared/transcript-status.ts +10 -0
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/content/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/content/_gitignore +2 -0
- package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/design/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +46 -3
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +7 -5
- package/corpus/templates/design/_gitignore +2 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -4
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +1 -1
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +10 -4
- package/corpus/templates/design/app/i18n-data.ts +10 -0
- package/corpus/templates/design/app/lib/builder-design-system-upload.ts +280 -0
- package/corpus/templates/design/app/lib/design-ui-events.ts +5 -0
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +90 -54
- package/corpus/templates/design/app/root.tsx +18 -1
- package/corpus/templates/design/changelog/2026-07-28-figma-fig-uploads-now-show-indexing-progress-and-an-open-in-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-28-show-or-hide-design-editing-chrome-with-cmd-on-apple-devices.md +6 -0
- package/corpus/templates/design/server/handlers/design-system-decode-job-status.ts +49 -0
- package/corpus/templates/design/server/handlers/design-system-upload-start.ts +87 -0
- package/corpus/templates/design/server/handlers/index-design-system-sources.ts +82 -0
- package/corpus/templates/design/server/routes/api/design-system-decode-job-status.get.ts +1 -0
- package/corpus/templates/design/server/routes/api/design-system-upload-start.post.ts +1 -0
- package/corpus/templates/design/server/routes/api/index-design-system-sources.post.ts +1 -0
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/dispatch/_gitignore +2 -0
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/forms/_gitignore +2 -0
- package/corpus/templates/macros/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/macros/_gitignore +2 -0
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/mail/_gitignore +2 -0
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/plan/_gitignore +2 -0
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/slides/_gitignore +2 -0
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +126 -53
- package/corpus/templates/slides/app/components/design-system/builder-design-system-upload.ts +271 -0
- package/corpus/templates/slides/app/components/design-system/builder-index-response.ts +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/server/handlers/design-system-decode-job-status.ts +49 -0
- package/corpus/templates/slides/server/handlers/design-system-upload-start.ts +87 -0
- package/corpus/templates/slides/server/handlers/index-design-system-sources.ts +79 -0
- package/corpus/templates/slides/server/routes/api/design-system-decode-job-status.get.ts +1 -0
- package/corpus/templates/slides/server/routes/api/design-system-upload-start.post.ts +1 -0
- package/corpus/templates/slides/server/routes/api/index-design-system-sources.post.ts +1 -0
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/tasks/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/tasks/_gitignore +2 -0
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +30 -29
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/action.d.ts +36 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +37 -2
- package/dist/action.js.map +1 -1
- package/dist/chat-threads/store.d.ts +12 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +48 -42
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.js +46 -3
- package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +3 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +11 -9
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +57 -6
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/DefaultSpinner.d.ts +7 -0
- package/dist/client/DefaultSpinner.d.ts.map +1 -1
- package/dist/client/DefaultSpinner.js +25 -1
- package/dist/client/DefaultSpinner.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts +13 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +41 -11
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/org/hooks.d.ts +37 -0
- package/dist/client/org/hooks.d.ts.map +1 -1
- package/dist/client/org/hooks.js +37 -0
- package/dist/client/org/hooks.js.map +1 -1
- package/dist/client/org/index.d.ts +3 -2
- package/dist/client/org/index.d.ts.map +1 -1
- package/dist/client/org/index.js +1 -1
- package/dist/client/org/index.js.map +1 -1
- package/dist/client/transcription/use-live-transcription.d.ts +8 -0
- package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
- package/dist/client/transcription/use-live-transcription.js +38 -11
- package/dist/client/transcription/use-live-transcription.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db/client.d.ts +12 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +40 -3
- package/dist/db/client.js.map +1 -1
- package/dist/db/ensure-additive-columns.d.ts.map +1 -1
- package/dist/db/ensure-additive-columns.js +54 -32
- package/dist/db/ensure-additive-columns.js.map +1 -1
- package/dist/deploy/build.d.ts +1 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +23 -2
- package/dist/deploy/build.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp-client/routes.d.ts +3 -1
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +8 -2
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/org/app-roles-handlers.d.ts +27 -0
- package/dist/org/app-roles-handlers.d.ts.map +1 -0
- package/dist/org/app-roles-handlers.js +125 -0
- package/dist/org/app-roles-handlers.js.map +1 -0
- package/dist/org/app-roles.d.ts +136 -0
- package/dist/org/app-roles.d.ts.map +1 -0
- package/dist/org/app-roles.js +216 -0
- package/dist/org/app-roles.js.map +1 -0
- package/dist/org/index.d.ts +4 -1
- package/dist/org/index.d.ts.map +1 -1
- package/dist/org/index.js +3 -1
- package/dist/org/index.js.map +1 -1
- package/dist/org/migrations.d.ts.map +1 -1
- package/dist/org/migrations.js +22 -0
- package/dist/org/migrations.js.map +1 -1
- package/dist/org/plugin.d.ts +2 -0
- package/dist/org/plugin.d.ts.map +1 -1
- package/dist/org/plugin.js +20 -0
- package/dist/org/plugin.js.map +1 -1
- package/dist/org/schema.d.ts +143 -0
- package/dist/org/schema.d.ts.map +1 -1
- package/dist/org/schema.js +14 -0
- package/dist/org/schema.js.map +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/scripts/docs/search.d.ts.map +1 -1
- package/dist/scripts/docs/search.js +15 -0
- package/dist/scripts/docs/search.js.map +1 -1
- package/dist/scripts/docs/source-search.d.ts +7 -0
- package/dist/scripts/docs/source-search.d.ts.map +1 -1
- package/dist/scripts/docs/source-search.js +9 -0
- package/dist/scripts/docs/source-search.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/script-entries.d.ts.map +1 -1
- package/dist/server/agent-chat/script-entries.js +3 -0
- package/dist/server/agent-chat/script-entries.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +46 -48
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts +49 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +221 -69
- package/dist/server/builder-design-systems.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +6 -1
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +42 -6
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/dist/templates/chat/.agents/skills/security/SKILL.md +31 -0
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
- package/dist/templates/default/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/dist/templates/default/.agents/skills/security/SKILL.md +31 -0
- package/dist/templates/headless/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
- package/docs/content/actions.mdx +47 -4
- package/docs/content/native-chat-ui.mdx +7 -0
- package/docs/content/organizations-teams-permissions.mdx +109 -3
- package/docs/content/template-design-collaboration-and-full-apps.mdx +15 -0
- package/docs/content/toolkit-org-team.mdx +72 -12
- package/package.json +2 -1
- package/src/a2a/artifact-response.ts +36 -29
- package/src/action.ts +83 -2
- package/src/chat-threads/store.ts +48 -43
- package/src/cli/skills-content/design-visual-edit-skill.ts +46 -3
- package/src/client/AgentPanel.tsx +26 -6
- package/src/client/AssistantChat.tsx +63 -7
- package/src/client/DefaultSpinner.tsx +29 -0
- package/src/client/org/TeamPage.tsx +161 -6
- package/src/client/org/hooks.ts +67 -0
- package/src/client/org/index.ts +9 -0
- package/src/client/transcription/use-live-transcription.ts +62 -10
- package/src/db/client.ts +42 -3
- package/src/db/ensure-additive-columns.ts +60 -33
- package/src/deploy/build.ts +31 -2
- package/src/mcp-client/routes.ts +10 -1
- package/src/org/app-roles-handlers.ts +152 -0
- package/src/org/app-roles.ts +355 -0
- package/src/org/index.ts +27 -1
- package/src/org/migrations.ts +22 -0
- package/src/org/plugin.ts +27 -0
- package/src/org/schema.ts +15 -0
- package/src/scripts/docs/search.ts +17 -0
- package/src/scripts/docs/source-search.ts +10 -0
- package/src/server/agent-chat/script-entries.ts +3 -0
- package/src/server/agent-chat-plugin.ts +53 -52
- package/src/server/builder-design-systems.ts +299 -82
- package/src/server/core-routes-plugin.ts +6 -1
- package/src/server/framework-request-handler.ts +44 -6
- package/src/server/index.ts +8 -0
- package/src/templates/chat/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/src/templates/chat/.agents/skills/security/SKILL.md +31 -0
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
- package/src/templates/default/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/src/templates/default/.agents/skills/security/SKILL.md +31 -0
- package/src/templates/headless/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/core/src/templates/chat/.agents/skills/actions/SKILL.md +0 -530
- package/corpus/core/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +0 -191
- package/corpus/core/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +0 -115
- package/corpus/core/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +0 -177
- package/corpus/core/src/templates/chat/.agents/skills/capture-learnings/SKILL.md +0 -89
- package/corpus/core/src/templates/chat/.agents/skills/create-skill/SKILL.md +0 -221
- package/corpus/core/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +0 -220
- package/corpus/core/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +0 -263
- package/corpus/core/src/templates/chat/.agents/skills/feature-flags/SKILL.md +0 -169
- package/corpus/core/src/templates/chat/.agents/skills/frontend-design/SKILL.md +0 -174
- package/corpus/core/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +0 -232
- package/corpus/core/src/templates/chat/.agents/skills/security/SKILL.md +0 -282
- package/corpus/core/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +0 -119
- package/corpus/core/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +0 -123
- package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +0 -122
- package/corpus/core/src/templates/chat/.env.example +0 -5
- package/corpus/core/src/templates/chat/.ignore +0 -0
- package/corpus/core/src/templates/chat/.oxfmtrc.json +0 -8
- package/corpus/core/src/templates/chat/AGENTS.md +0 -77
- package/corpus/core/src/templates/chat/CHANGELOG.md +0 -10
- package/corpus/core/src/templates/chat/DEVELOPING.md +0 -185
- package/corpus/core/src/templates/chat/README.md +0 -32
- package/corpus/core/src/templates/chat/_gitignore +0 -46
- package/corpus/core/src/templates/chat/actions/hello.ts +0 -13
- package/corpus/core/src/templates/chat/actions/navigate.ts +0 -41
- package/corpus/core/src/templates/chat/actions/run.ts +0 -2
- package/corpus/core/src/templates/chat/actions/view-screen.ts +0 -31
- package/corpus/core/src/templates/chat/app/components/layout/Header.tsx +0 -60
- package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +0 -188
- package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +0 -505
- package/corpus/core/src/templates/chat/app/components/ui/button.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/card.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/dropdown-menu.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/input.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/label.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/sheet.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/toolkit-provider.tsx +0 -17
- package/corpus/core/src/templates/chat/app/components/ui/tooltip.tsx +0 -1
- package/corpus/core/src/templates/chat/app/design-system.ts +0 -3
- package/corpus/core/src/templates/chat/app/entry.client.tsx +0 -22
- package/corpus/core/src/templates/chat/app/entry.server.tsx +0 -10
- package/corpus/core/src/templates/chat/app/global.css +0 -93
- package/corpus/core/src/templates/chat/app/hooks/use-navigation-state.ts +0 -93
- package/corpus/core/src/templates/chat/app/i18n/ar-SA.ts +0 -68
- package/corpus/core/src/templates/chat/app/i18n/de-DE.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/en-US.ts +0 -70
- package/corpus/core/src/templates/chat/app/i18n/es-ES.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/fr-FR.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/hi-IN.ts +0 -69
- package/corpus/core/src/templates/chat/app/i18n/index.ts +0 -34
- package/corpus/core/src/templates/chat/app/i18n/ja-JP.ts +0 -70
- package/corpus/core/src/templates/chat/app/i18n/ko-KR.ts +0 -70
- package/corpus/core/src/templates/chat/app/i18n/pt-BR.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/zh-CN.ts +0 -66
- package/corpus/core/src/templates/chat/app/i18n/zh-TW.ts +0 -66
- package/corpus/core/src/templates/chat/app/i18n-data.ts +0 -556
- package/corpus/core/src/templates/chat/app/lib/agent-page.tsx +0 -49
- package/corpus/core/src/templates/chat/app/lib/app-config.ts +0 -11
- package/corpus/core/src/templates/chat/app/lib/tab-id.ts +0 -1
- package/corpus/core/src/templates/chat/app/lib/utils.ts +0 -1
- package/corpus/core/src/templates/chat/app/root.tsx +0 -173
- package/corpus/core/src/templates/chat/app/routes/_index.tsx +0 -94
- package/corpus/core/src/templates/chat/app/routes/agent.tsx +0 -24
- package/corpus/core/src/templates/chat/app/routes/chat.$threadId.tsx +0 -1
- package/corpus/core/src/templates/chat/app/routes/database.tsx +0 -17
- package/corpus/core/src/templates/chat/app/routes/extensions.$id.$slug.tsx +0 -2
- package/corpus/core/src/templates/chat/app/routes/extensions.$id.tsx +0 -11
- package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +0 -11
- package/corpus/core/src/templates/chat/app/routes/extensions.tsx +0 -5
- package/corpus/core/src/templates/chat/app/routes/observability.tsx +0 -19
- package/corpus/core/src/templates/chat/app/routes/settings.tsx +0 -89
- package/corpus/core/src/templates/chat/app/routes/team.tsx +0 -11
- package/corpus/core/src/templates/chat/app/routes.ts +0 -4
- package/corpus/core/src/templates/chat/app/vite-env.d.ts +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +0 -5
- package/corpus/core/src/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-23-full-page-chat-is-better-centered-with-quieter-chat-history-.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +0 -6
- package/corpus/core/src/templates/chat/components.json +0 -20
- package/corpus/core/src/templates/chat/learnings.defaults.md +0 -5
- package/corpus/core/src/templates/chat/netlify.toml +0 -11
- package/corpus/core/src/templates/chat/package.json +0 -92
- package/corpus/core/src/templates/chat/public/agent-native-icon-dark.svg +0 -10
- package/corpus/core/src/templates/chat/public/agent-native-icon-light.svg +0 -10
- package/corpus/core/src/templates/chat/public/agent-native-logo-dark.svg +0 -21
- package/corpus/core/src/templates/chat/public/agent-native-logo-light.svg +0 -21
- package/corpus/core/src/templates/chat/public/favicon.svg +0 -1
- package/corpus/core/src/templates/chat/public/icon-180.svg +0 -1
- package/corpus/core/src/templates/chat/public/icon-192.svg +0 -1
- package/corpus/core/src/templates/chat/public/icon-512.svg +0 -1
- package/corpus/core/src/templates/chat/public/manifest.json +0 -21
- package/corpus/core/src/templates/chat/react-router.config.ts +0 -7
- package/corpus/core/src/templates/chat/server/middleware/auth.ts +0 -15
- package/corpus/core/src/templates/chat/server/plugins/agent-chat.ts +0 -21
- package/corpus/core/src/templates/chat/server/plugins/auth.ts +0 -17
- package/corpus/core/src/templates/chat/server/routes/[...page].get.ts +0 -5
- package/corpus/core/src/templates/chat/ssr-entry.ts +0 -15
- package/corpus/core/src/templates/chat/tsconfig.json +0 -21
- package/corpus/core/src/templates/chat/vite.config.ts +0 -19
- package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +0 -151
- package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +0 -1
- package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +0 -119
- package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +0 -1
|
@@ -34,6 +34,8 @@ Visibility is coarse. Explicit share grants are fine-grained (per user or per or
|
|
|
34
34
|
- **`editor`** — read + write.
|
|
35
35
|
- **`admin`** — read + write + manage shares. Does NOT replace the single `owner_email` on the resource.
|
|
36
36
|
|
|
37
|
+
There are three role systems and they never imply one another. A share role answers "what may this person do to **one row**". An org role (`org_members.role`) answers "what may this person do to the **team**". An app role (`defineAppRoles`, see the `authentication` skill) answers "what may this person do inside **one app**". A share `admin` is not an app admin and neither is an org admin.
|
|
38
|
+
|
|
37
39
|
### Anonymous public URLs stay separate
|
|
38
40
|
|
|
39
41
|
Form "publish" slugs, booking-link slugs, any feature that exposes a URL to unauthenticated users — these are a different axis and are NOT controlled by the sharing system. Keep them alongside it.
|
|
@@ -137,6 +139,8 @@ export default defineAction({
|
|
|
137
139
|
|
|
138
140
|
For delete actions use `"admin"` (or fold in `"owner"` to require the real owner).
|
|
139
141
|
|
|
142
|
+
`authorize` is a different axis, not an alternative: it gates whether the caller may run the operation at all, while `assertAccess` scopes which row they may touch. A write action restricted to some teammates needs both — `authorize: appAccess.requireAny(...)` on the action, `assertAccess` inside `run`.
|
|
143
|
+
|
|
140
144
|
## Create actions must set owner
|
|
141
145
|
|
|
142
146
|
When inserting a new row, fill `ownerEmail` and `orgId` from the request context:
|
|
@@ -305,6 +305,38 @@ export default defineAction({
|
|
|
305
305
|
|
|
306
306
|
On success the validated value is returned, so coercion/defaults on `outputSchema` apply. Omit `outputSchema` and behavior is byte-for-byte unchanged (no wrapping).
|
|
307
307
|
|
|
308
|
+
### Authorization (`authorize`)
|
|
309
|
+
|
|
310
|
+
`authorize` decides whether the caller may run the action at all. It wraps
|
|
311
|
+
`run`, so it holds at **all six dispatch sites** — agent tool, HTTP, frontend
|
|
312
|
+
hook, MCP, A2A, CLI — unlike `needsApproval`, which is honoured only in the
|
|
313
|
+
agent loop. Use `authorize` for "not everyone may do this"; use `needsApproval`
|
|
314
|
+
to ask a human to bless one call a permitted caller is already allowed to make.
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
|
|
318
|
+
|
|
319
|
+
export default defineAction({
|
|
320
|
+
description: "Archive a client roster.",
|
|
321
|
+
schema: z.object({ id: z.string() }),
|
|
322
|
+
authorize: coachAccess.requireAny("coach-admin"),
|
|
323
|
+
run: async (args) => {
|
|
324
|
+
/* ... */
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
The wrappers compose as `validate input -> authorize -> run -> validate output
|
|
330
|
+
-> audit`: the gate sits inside input validation, so a guard reading `args` gets
|
|
331
|
+
the parsed, coerced value, and auditing is outermost, so denials are recorded.
|
|
332
|
+
|
|
333
|
+
A guard that throws denies with its own message; returning `false` denies
|
|
334
|
+
generically; anything else (including `undefined`) allows. A guarded action
|
|
335
|
+
needs a user identity, so an unattended CLI/cron caller with no user email is
|
|
336
|
+
denied. `authorize` gates the operation; `accessFilter` / `assertAccess` still
|
|
337
|
+
scope which rows a permitted caller may touch. See the `authentication` skill
|
|
338
|
+
for `defineAppRoles` and the `sharing` skill for row scoping.
|
|
339
|
+
|
|
308
340
|
### Human-in-the-Loop Approval (`needsApproval`)
|
|
309
341
|
|
|
310
342
|
For high-consequence, outward-facing, hard-to-undo actions (sending an email, charging a card, deleting an account), set `needsApproval` so the agent **cannot** run the action without a human approving the specific call:
|
|
@@ -159,6 +159,35 @@ whole site. Data scoping lives in actions and API routes; the client gates
|
|
|
159
159
|
private UI after the shell loads. See the `authentication` skill and
|
|
160
160
|
`guard:ssr-cache-shell` / `ssr-handler.spec.ts`.
|
|
161
161
|
|
|
162
|
+
**Authorization beyond "is there a session" — `authorize`.** The auth guard only
|
|
163
|
+
proves *someone* is signed in. To restrict an operation to some teammates, set
|
|
164
|
+
`authorize` on the `defineAction`. It wraps `run`, so it applies at every
|
|
165
|
+
dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
|
|
166
|
+
`needsApproval`, which is honoured only in the agent loop.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
|
|
170
|
+
|
|
171
|
+
export default defineAction({
|
|
172
|
+
description: "Archive a client roster.",
|
|
173
|
+
schema: z.object({ id: z.string() }),
|
|
174
|
+
authorize: coachAccess.requireAny("coach-admin"),
|
|
175
|
+
run: async (args) => {
|
|
176
|
+
/* ... */
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
A guard that throws denies with its own message; returning `false` denies
|
|
182
|
+
generically; anything else (including `undefined`) allows. Guarded actions need
|
|
183
|
+
a user identity — an unattended CLI/cron caller with no user email is denied.
|
|
184
|
+
|
|
185
|
+
`authorize` is **not** a substitute for `accessFilter` / `assertAccess`. It
|
|
186
|
+
decides whether this caller may perform the operation at all; `accessFilter` /
|
|
187
|
+
`assertAccess` scope which rows a permitted caller may see or touch. A
|
|
188
|
+
restricted write action needs both. See the `authentication` skill for
|
|
189
|
+
`defineAppRoles` and the `actions` skill for the full surface.
|
|
190
|
+
|
|
162
191
|
## Human-in-the-Loop Approval for High-Consequence Actions
|
|
163
192
|
|
|
164
193
|
For a small set of outward-facing, hard-to-undo operations — sending an email, charging a card, deleting an account, posting publicly — auth and access control are necessary but not sufficient: you also do not want the **agent** to perform them autonomously. Set `needsApproval` on the `defineAction` so the agent cannot run the action without a human approving the specific call.
|
|
@@ -274,6 +303,8 @@ Run `pnpm action db-check-scoping` to verify. Use `--require-org` for multi-org
|
|
|
274
303
|
- [ ] New env vars in `.env` only, not committed
|
|
275
304
|
- [ ] New user-data tables have `owner_email` column
|
|
276
305
|
- [ ] Custom routes call `getSession` and reject unauthenticated requests
|
|
306
|
+
- [ ] Actions only some teammates may run set `authorize` (in addition to any
|
|
307
|
+
`accessFilter` / `assertAccess` row scoping)
|
|
277
308
|
|
|
278
309
|
## Related Skills
|
|
279
310
|
|
|
@@ -34,6 +34,8 @@ Visibility is coarse. Explicit share grants are fine-grained (per user or per or
|
|
|
34
34
|
- **`editor`** — read + write.
|
|
35
35
|
- **`admin`** — read + write + manage shares. Does NOT replace the single `owner_email` on the resource.
|
|
36
36
|
|
|
37
|
+
There are three role systems and they never imply one another. A share role answers "what may this person do to **one row**". An org role (`org_members.role`) answers "what may this person do to the **team**". An app role (`defineAppRoles`, see the `authentication` skill) answers "what may this person do inside **one app**". A share `admin` is not an app admin and neither is an org admin.
|
|
38
|
+
|
|
37
39
|
### Anonymous public URLs stay separate
|
|
38
40
|
|
|
39
41
|
Form "publish" slugs, booking-link slugs, any feature that exposes a URL to unauthenticated users — these are a different axis and are NOT controlled by the sharing system. Keep them alongside it.
|
|
@@ -137,6 +139,8 @@ export default defineAction({
|
|
|
137
139
|
|
|
138
140
|
For delete actions use `"admin"` (or fold in `"owner"` to require the real owner).
|
|
139
141
|
|
|
142
|
+
`authorize` is a different axis, not an alternative: it gates whether the caller may run the operation at all, while `assertAccess` scopes which row they may touch. A write action restricted to some teammates needs both — `authorize: appAccess.requireAny(...)` on the action, `assertAccess` inside `run`.
|
|
143
|
+
|
|
140
144
|
## Create actions must set owner
|
|
141
145
|
|
|
142
146
|
When inserting a new row, fill `ownerEmail` and `orgId` from the request context:
|
|
@@ -305,6 +305,38 @@ export default defineAction({
|
|
|
305
305
|
|
|
306
306
|
On success the validated value is returned, so coercion/defaults on `outputSchema` apply. Omit `outputSchema` and behavior is byte-for-byte unchanged (no wrapping).
|
|
307
307
|
|
|
308
|
+
### Authorization (`authorize`)
|
|
309
|
+
|
|
310
|
+
`authorize` decides whether the caller may run the action at all. It wraps
|
|
311
|
+
`run`, so it holds at **all six dispatch sites** — agent tool, HTTP, frontend
|
|
312
|
+
hook, MCP, A2A, CLI — unlike `needsApproval`, which is honoured only in the
|
|
313
|
+
agent loop. Use `authorize` for "not everyone may do this"; use `needsApproval`
|
|
314
|
+
to ask a human to bless one call a permitted caller is already allowed to make.
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
|
|
318
|
+
|
|
319
|
+
export default defineAction({
|
|
320
|
+
description: "Archive a client roster.",
|
|
321
|
+
schema: z.object({ id: z.string() }),
|
|
322
|
+
authorize: coachAccess.requireAny("coach-admin"),
|
|
323
|
+
run: async (args) => {
|
|
324
|
+
/* ... */
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
The wrappers compose as `validate input -> authorize -> run -> validate output
|
|
330
|
+
-> audit`: the gate sits inside input validation, so a guard reading `args` gets
|
|
331
|
+
the parsed, coerced value, and auditing is outermost, so denials are recorded.
|
|
332
|
+
|
|
333
|
+
A guard that throws denies with its own message; returning `false` denies
|
|
334
|
+
generically; anything else (including `undefined`) allows. A guarded action
|
|
335
|
+
needs a user identity, so an unattended CLI/cron caller with no user email is
|
|
336
|
+
denied. `authorize` gates the operation; `accessFilter` / `assertAccess` still
|
|
337
|
+
scope which rows a permitted caller may touch. See the `authentication` skill
|
|
338
|
+
for `defineAppRoles` and the `sharing` skill for row scoping.
|
|
339
|
+
|
|
308
340
|
### Human-in-the-Loop Approval (`needsApproval`)
|
|
309
341
|
|
|
310
342
|
For high-consequence, outward-facing, hard-to-undo actions (sending an email, charging a card, deleting an account), set `needsApproval` so the agent **cannot** run the action without a human approving the specific call:
|
|
@@ -179,8 +179,15 @@ If the feature stores **user-authored resources** (documents, dashboards, forms,
|
|
|
179
179
|
|
|
180
180
|
TL;DR: spread `ownableColumns()` into the resource table, pair it with `createSharesTable(...)`, call `registerShareableResource(...)`, wrap list/read queries with `accessFilter`, guard writes with `assertAccess`, and drop `<ShareButton>` in the resource header. The `share-resource`, `unshare-resource`, `list-resource-shares`, and `set-resource-visibility` actions are auto-mounted framework-wide.
|
|
181
181
|
|
|
182
|
+
## One more area — who inside the app may do it
|
|
183
|
+
|
|
184
|
+
If the feature is one **only some teammates should be able to perform inside this app** (an admin-only import, a settings reset), that is a per-app role — not a new organization, and not a share grant. See the `authentication` skill.
|
|
185
|
+
|
|
186
|
+
TL;DR: declare the vocabulary once with `defineAppRoles({ appId, roles, defaultRole })`, guard the action with `authorize: appAccess.requireAny("...")`, and render the picker with `<TeamPage appRoles={descriptor} />`. `defaultRole` is display only — it never satisfies a guard — and `authorize` gates the operation while `accessFilter` / `assertAccess` still scope the rows.
|
|
187
|
+
|
|
182
188
|
## Related Skills
|
|
183
189
|
|
|
190
|
+
- **authentication** — Per-app member roles (`defineAppRoles`) when only some teammates may use a feature
|
|
184
191
|
- **sharing** — How to make a new resource ownable (private by default, share with users/orgs/public)
|
|
185
192
|
- **context-awareness** — How to expose UI state to the agent (area 4 in detail)
|
|
186
193
|
- **actions** — How to create actions with `defineAction` and the `http` option (area 2 in detail)
|
|
@@ -159,6 +159,35 @@ whole site. Data scoping lives in actions and API routes; the client gates
|
|
|
159
159
|
private UI after the shell loads. See the `authentication` skill and
|
|
160
160
|
`guard:ssr-cache-shell` / `ssr-handler.spec.ts`.
|
|
161
161
|
|
|
162
|
+
**Authorization beyond "is there a session" — `authorize`.** The auth guard only
|
|
163
|
+
proves *someone* is signed in. To restrict an operation to some teammates, set
|
|
164
|
+
`authorize` on the `defineAction`. It wraps `run`, so it applies at every
|
|
165
|
+
dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
|
|
166
|
+
`needsApproval`, which is honoured only in the agent loop.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
|
|
170
|
+
|
|
171
|
+
export default defineAction({
|
|
172
|
+
description: "Archive a client roster.",
|
|
173
|
+
schema: z.object({ id: z.string() }),
|
|
174
|
+
authorize: coachAccess.requireAny("coach-admin"),
|
|
175
|
+
run: async (args) => {
|
|
176
|
+
/* ... */
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
A guard that throws denies with its own message; returning `false` denies
|
|
182
|
+
generically; anything else (including `undefined`) allows. Guarded actions need
|
|
183
|
+
a user identity — an unattended CLI/cron caller with no user email is denied.
|
|
184
|
+
|
|
185
|
+
`authorize` is **not** a substitute for `accessFilter` / `assertAccess`. It
|
|
186
|
+
decides whether this caller may perform the operation at all; `accessFilter` /
|
|
187
|
+
`assertAccess` scope which rows a permitted caller may see or touch. A
|
|
188
|
+
restricted write action needs both. See the `authentication` skill for
|
|
189
|
+
`defineAppRoles` and the `actions` skill for the full surface.
|
|
190
|
+
|
|
162
191
|
## Human-in-the-Loop Approval for High-Consequence Actions
|
|
163
192
|
|
|
164
193
|
For a small set of outward-facing, hard-to-undo operations — sending an email, charging a card, deleting an account, posting publicly — auth and access control are necessary but not sufficient: you also do not want the **agent** to perform them autonomously. Set `needsApproval` on the `defineAction` so the agent cannot run the action without a human approving the specific call.
|
|
@@ -274,6 +303,8 @@ Run `pnpm action db-check-scoping` to verify. Use `--require-org` for multi-org
|
|
|
274
303
|
- [ ] New env vars in `.env` only, not committed
|
|
275
304
|
- [ ] New user-data tables have `owner_email` column
|
|
276
305
|
- [ ] Custom routes call `getSession` and reject unauthenticated requests
|
|
306
|
+
- [ ] Actions only some teammates may run set `authorize` (in addition to any
|
|
307
|
+
`accessFilter` / `assertAccess` row scoping)
|
|
277
308
|
|
|
278
309
|
## Related Skills
|
|
279
310
|
|
|
@@ -34,6 +34,8 @@ Visibility is coarse. Explicit share grants are fine-grained (per user or per or
|
|
|
34
34
|
- **`editor`** — read + write.
|
|
35
35
|
- **`admin`** — read + write + manage shares. Does NOT replace the single `owner_email` on the resource.
|
|
36
36
|
|
|
37
|
+
There are three role systems and they never imply one another. A share role answers "what may this person do to **one row**". An org role (`org_members.role`) answers "what may this person do to the **team**". An app role (`defineAppRoles`, see the `authentication` skill) answers "what may this person do inside **one app**". A share `admin` is not an app admin and neither is an org admin.
|
|
38
|
+
|
|
37
39
|
### Anonymous public URLs stay separate
|
|
38
40
|
|
|
39
41
|
Form "publish" slugs, booking-link slugs, any feature that exposes a URL to unauthenticated users — these are a different axis and are NOT controlled by the sharing system. Keep them alongside it.
|
|
@@ -137,6 +139,8 @@ export default defineAction({
|
|
|
137
139
|
|
|
138
140
|
For delete actions use `"admin"` (or fold in `"owner"` to require the real owner).
|
|
139
141
|
|
|
142
|
+
`authorize` is a different axis, not an alternative: it gates whether the caller may run the operation at all, while `assertAccess` scopes which row they may touch. A write action restricted to some teammates needs both — `authorize: appAccess.requireAny(...)` on the action, `assertAccess` inside `run`.
|
|
143
|
+
|
|
140
144
|
## Create actions must set owner
|
|
141
145
|
|
|
142
146
|
When inserting a new row, fill `ownerEmail` and `orgId` from the request context:
|
|
@@ -305,6 +305,38 @@ export default defineAction({
|
|
|
305
305
|
|
|
306
306
|
On success the validated value is returned, so coercion/defaults on `outputSchema` apply. Omit `outputSchema` and behavior is byte-for-byte unchanged (no wrapping).
|
|
307
307
|
|
|
308
|
+
### Authorization (`authorize`)
|
|
309
|
+
|
|
310
|
+
`authorize` decides whether the caller may run the action at all. It wraps
|
|
311
|
+
`run`, so it holds at **all six dispatch sites** — agent tool, HTTP, frontend
|
|
312
|
+
hook, MCP, A2A, CLI — unlike `needsApproval`, which is honoured only in the
|
|
313
|
+
agent loop. Use `authorize` for "not everyone may do this"; use `needsApproval`
|
|
314
|
+
to ask a human to bless one call a permitted caller is already allowed to make.
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
|
|
318
|
+
|
|
319
|
+
export default defineAction({
|
|
320
|
+
description: "Archive a client roster.",
|
|
321
|
+
schema: z.object({ id: z.string() }),
|
|
322
|
+
authorize: coachAccess.requireAny("coach-admin"),
|
|
323
|
+
run: async (args) => {
|
|
324
|
+
/* ... */
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
The wrappers compose as `validate input -> authorize -> run -> validate output
|
|
330
|
+
-> audit`: the gate sits inside input validation, so a guard reading `args` gets
|
|
331
|
+
the parsed, coerced value, and auditing is outermost, so denials are recorded.
|
|
332
|
+
|
|
333
|
+
A guard that throws denies with its own message; returning `false` denies
|
|
334
|
+
generically; anything else (including `undefined`) allows. A guarded action
|
|
335
|
+
needs a user identity, so an unattended CLI/cron caller with no user email is
|
|
336
|
+
denied. `authorize` gates the operation; `accessFilter` / `assertAccess` still
|
|
337
|
+
scope which rows a permitted caller may touch. See the `authentication` skill
|
|
338
|
+
for `defineAppRoles` and the `sharing` skill for row scoping.
|
|
339
|
+
|
|
308
340
|
### Human-in-the-Loop Approval (`needsApproval`)
|
|
309
341
|
|
|
310
342
|
For high-consequence, outward-facing, hard-to-undo actions (sending an email, charging a card, deleting an account), set `needsApproval` so the agent **cannot** run the action without a human approving the specific call:
|
|
@@ -159,6 +159,35 @@ whole site. Data scoping lives in actions and API routes; the client gates
|
|
|
159
159
|
private UI after the shell loads. See the `authentication` skill and
|
|
160
160
|
`guard:ssr-cache-shell` / `ssr-handler.spec.ts`.
|
|
161
161
|
|
|
162
|
+
**Authorization beyond "is there a session" — `authorize`.** The auth guard only
|
|
163
|
+
proves *someone* is signed in. To restrict an operation to some teammates, set
|
|
164
|
+
`authorize` on the `defineAction`. It wraps `run`, so it applies at every
|
|
165
|
+
dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
|
|
166
|
+
`needsApproval`, which is honoured only in the agent loop.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
|
|
170
|
+
|
|
171
|
+
export default defineAction({
|
|
172
|
+
description: "Archive a client roster.",
|
|
173
|
+
schema: z.object({ id: z.string() }),
|
|
174
|
+
authorize: coachAccess.requireAny("coach-admin"),
|
|
175
|
+
run: async (args) => {
|
|
176
|
+
/* ... */
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
A guard that throws denies with its own message; returning `false` denies
|
|
182
|
+
generically; anything else (including `undefined`) allows. Guarded actions need
|
|
183
|
+
a user identity — an unattended CLI/cron caller with no user email is denied.
|
|
184
|
+
|
|
185
|
+
`authorize` is **not** a substitute for `accessFilter` / `assertAccess`. It
|
|
186
|
+
decides whether this caller may perform the operation at all; `accessFilter` /
|
|
187
|
+
`assertAccess` scope which rows a permitted caller may see or touch. A
|
|
188
|
+
restricted write action needs both. See the `authentication` skill for
|
|
189
|
+
`defineAppRoles` and the `actions` skill for the full surface.
|
|
190
|
+
|
|
162
191
|
## Human-in-the-Loop Approval for High-Consequence Actions
|
|
163
192
|
|
|
164
193
|
For a small set of outward-facing, hard-to-undo operations — sending an email, charging a card, deleting an account, posting publicly — auth and access control are necessary but not sufficient: you also do not want the **agent** to perform them autonomously. Set `needsApproval` on the `defineAction` so the agent cannot run the action without a human approving the specific call.
|
|
@@ -274,6 +303,8 @@ Run `pnpm action db-check-scoping` to verify. Use `--require-org` for multi-org
|
|
|
274
303
|
- [ ] New env vars in `.env` only, not committed
|
|
275
304
|
- [ ] New user-data tables have `owner_email` column
|
|
276
305
|
- [ ] Custom routes call `getSession` and reject unauthenticated requests
|
|
306
|
+
- [ ] Actions only some teammates may run set `authorize` (in addition to any
|
|
307
|
+
`accessFilter` / `assertAccess` row scoping)
|
|
277
308
|
|
|
278
309
|
## Related Skills
|
|
279
310
|
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
normalizeTranscriptSegments,
|
|
60
60
|
parseTranscriptSegments,
|
|
61
61
|
} from "../shared/transcript-segments.js";
|
|
62
|
+
import { PENDING_TRANSCRIPT_HEARTBEAT_MS } from "../shared/transcript-status.js";
|
|
62
63
|
import cleanupTranscript from "./cleanup-transcript.js";
|
|
63
64
|
import { loadAgentsMdContext } from "./lib/agents-md-context.js";
|
|
64
65
|
import {
|
|
@@ -419,6 +420,54 @@ function isRecentlyPendingTranscript(transcript: {
|
|
|
419
420
|
);
|
|
420
421
|
}
|
|
421
422
|
|
|
423
|
+
/**
|
|
424
|
+
* Run `work` while keeping this recording's pending transcript row marked live.
|
|
425
|
+
*
|
|
426
|
+
* `resolveTranscriptPresentation` infers "the worker is gone" from a pending
|
|
427
|
+
* row nothing has written for STALE_PENDING_TRANSCRIPT_MS, because the row
|
|
428
|
+
* carries no other liveness signal. Media fetch, ffmpeg extraction and the
|
|
429
|
+
* provider call legitimately add up past that window on a long recording, so
|
|
430
|
+
* without this ping the UI publishes a terminal "stopped before it finished"
|
|
431
|
+
* failure over a run that is still working — and the player's self-heal then
|
|
432
|
+
* forces a second concurrent transcription of the same clip.
|
|
433
|
+
*
|
|
434
|
+
* The update is scoped to `status = 'pending'` so it can never touch a row a
|
|
435
|
+
* concurrent run has already finished, and the interval is unref'd and cleared
|
|
436
|
+
* so it cannot hold a serverless invocation open.
|
|
437
|
+
*/
|
|
438
|
+
async function withPendingTranscriptHeartbeat<T>(
|
|
439
|
+
db: ReturnType<typeof getDb>,
|
|
440
|
+
recordingId: string,
|
|
441
|
+
work: () => Promise<T>,
|
|
442
|
+
): Promise<T> {
|
|
443
|
+
const timer = setInterval(() => {
|
|
444
|
+
void (async () => {
|
|
445
|
+
try {
|
|
446
|
+
await db
|
|
447
|
+
.update(schema.recordingTranscripts)
|
|
448
|
+
.set({ updatedAt: new Date().toISOString() })
|
|
449
|
+
.where(
|
|
450
|
+
and(
|
|
451
|
+
eq(schema.recordingTranscripts.recordingId, recordingId),
|
|
452
|
+
eq(schema.recordingTranscripts.status, "pending"),
|
|
453
|
+
),
|
|
454
|
+
);
|
|
455
|
+
} catch (err) {
|
|
456
|
+
console.warn(
|
|
457
|
+
`[clips] transcript heartbeat failed for ${recordingId}:`,
|
|
458
|
+
(err as Error)?.message ?? String(err),
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
})();
|
|
462
|
+
}, PENDING_TRANSCRIPT_HEARTBEAT_MS);
|
|
463
|
+
(timer as { unref?: () => void }).unref?.();
|
|
464
|
+
try {
|
|
465
|
+
return await work();
|
|
466
|
+
} finally {
|
|
467
|
+
clearInterval(timer);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
422
471
|
async function writeTranscriptCleanupState(
|
|
423
472
|
recordingId: string,
|
|
424
473
|
value: Record<string, unknown>,
|
|
@@ -1251,8 +1300,15 @@ const requestTranscriptAction = defineAction({
|
|
|
1251
1300
|
|
|
1252
1301
|
let audioMedia: AudioOnlyTranscriptionMedia;
|
|
1253
1302
|
try {
|
|
1254
|
-
audioMedia = await
|
|
1255
|
-
|
|
1303
|
+
audioMedia = await withPendingTranscriptHeartbeat(
|
|
1304
|
+
db,
|
|
1305
|
+
args.recordingId,
|
|
1306
|
+
async () => {
|
|
1307
|
+
const media = await getAudioMedia(rec);
|
|
1308
|
+
await ensureAudioHasSignal(media);
|
|
1309
|
+
return media;
|
|
1310
|
+
},
|
|
1311
|
+
);
|
|
1256
1312
|
} catch (err) {
|
|
1257
1313
|
return failAudioOnlyPreparation({
|
|
1258
1314
|
db,
|
|
@@ -1266,13 +1322,18 @@ const requestTranscriptAction = defineAction({
|
|
|
1266
1322
|
|
|
1267
1323
|
try {
|
|
1268
1324
|
const startedAt = Date.now();
|
|
1269
|
-
const builderResult = await
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1325
|
+
const builderResult = await withPendingTranscriptHeartbeat(
|
|
1326
|
+
db,
|
|
1327
|
+
args.recordingId,
|
|
1328
|
+
() =>
|
|
1329
|
+
transcribeWithBuilderModelFallback({
|
|
1330
|
+
audioBytes: audioMedia.audioBytes,
|
|
1331
|
+
mimeType: audioMedia.mimeType,
|
|
1332
|
+
diarize: false,
|
|
1333
|
+
instructions: SPEECH_ONLY_TRANSCRIPTION_INSTRUCTIONS,
|
|
1334
|
+
timeoutMs: builderTranscriptionTimeoutMs(rec.durationMs),
|
|
1335
|
+
}),
|
|
1336
|
+
);
|
|
1276
1337
|
|
|
1277
1338
|
const segments = (builderResult.segments ?? [])
|
|
1278
1339
|
.map((s) => ({
|
|
@@ -1449,6 +1510,11 @@ async function upsertTranscriptRow(
|
|
|
1449
1510
|
.limit(1);
|
|
1450
1511
|
|
|
1451
1512
|
const retryCount = row.status === "ready" ? 0 : (row.retryCount ?? undefined);
|
|
1513
|
+
// `row.now` is captured once at the top of a run that can last minutes, so it
|
|
1514
|
+
// is a creation timestamp, never a "last written" one. Stamping it as
|
|
1515
|
+
// `updatedAt` would walk the pending heartbeat backwards and re-arm the stale
|
|
1516
|
+
// check over a run that just finished.
|
|
1517
|
+
const updatedAt = new Date().toISOString();
|
|
1452
1518
|
|
|
1453
1519
|
if (existing) {
|
|
1454
1520
|
await db
|
|
@@ -1461,7 +1527,7 @@ async function upsertTranscriptRow(
|
|
|
1461
1527
|
...(row.segmentsJson ? { segmentsJson: row.segmentsJson } : {}),
|
|
1462
1528
|
...(row.fullText !== undefined ? { fullText: row.fullText } : {}),
|
|
1463
1529
|
...(retryCount !== undefined ? { retryCount } : {}),
|
|
1464
|
-
updatedAt
|
|
1530
|
+
updatedAt,
|
|
1465
1531
|
})
|
|
1466
1532
|
.where(eq(schema.recordingTranscripts.recordingId, row.recordingId));
|
|
1467
1533
|
} else {
|
|
@@ -1475,7 +1541,7 @@ async function upsertTranscriptRow(
|
|
|
1475
1541
|
failureReason: row.failureReason,
|
|
1476
1542
|
retryCount: retryCount ?? 0,
|
|
1477
1543
|
createdAt: row.now,
|
|
1478
|
-
updatedAt
|
|
1544
|
+
updatedAt,
|
|
1479
1545
|
});
|
|
1480
1546
|
}
|
|
1481
1547
|
}
|
|
@@ -153,6 +153,18 @@ export default defineAction({
|
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
// Text plus a failure reason means capture died partway (a Web Speech
|
|
157
|
+
// session that could not restart, a revoked mic). Keep the partial text,
|
|
158
|
+
// but never mark it `ready`: that is the terminal state every preserve
|
|
159
|
+
// guard checks, so a three-line partial would permanently suppress the
|
|
160
|
+
// Builder fallback that can still transcribe the whole recording.
|
|
161
|
+
// `failed` rather than `pending`/`streaming` — a fresh pending row makes
|
|
162
|
+
// finalization's own transcript job skip itself as already-pending, and a
|
|
163
|
+
// perpetual streaming row reads as normal progress that never resolves.
|
|
164
|
+
const truncated = Boolean(failureReason);
|
|
165
|
+
const savedStatus = truncated ? ("failed" as const) : ("ready" as const);
|
|
166
|
+
const savedFailureReason = truncated ? failureReason : null;
|
|
167
|
+
|
|
156
168
|
if (current) {
|
|
157
169
|
// Don't overwrite an already-segmented cloud/native transcript with a
|
|
158
170
|
// later lower-confidence native pass — UNLESS the caller owns this
|
|
@@ -172,8 +184,8 @@ export default defineAction({
|
|
|
172
184
|
ownerEmail,
|
|
173
185
|
fullText,
|
|
174
186
|
segmentsJson,
|
|
175
|
-
status:
|
|
176
|
-
failureReason:
|
|
187
|
+
status: savedStatus,
|
|
188
|
+
failureReason: savedFailureReason,
|
|
177
189
|
updatedAt: now,
|
|
178
190
|
})
|
|
179
191
|
.where(eq(schema.recordingTranscripts.recordingId, args.recordingId));
|
|
@@ -184,15 +196,17 @@ export default defineAction({
|
|
|
184
196
|
language: "en",
|
|
185
197
|
segmentsJson,
|
|
186
198
|
fullText,
|
|
187
|
-
status:
|
|
188
|
-
failureReason:
|
|
199
|
+
status: savedStatus,
|
|
200
|
+
failureReason: savedFailureReason,
|
|
189
201
|
createdAt: now,
|
|
190
202
|
updatedAt: now,
|
|
191
203
|
});
|
|
192
204
|
}
|
|
193
205
|
|
|
194
206
|
console.log(
|
|
195
|
-
|
|
207
|
+
truncated
|
|
208
|
+
? `[clips] Partial native transcript saved for ${args.recordingId} via ${args.source ?? "web-speech"} (${fullText.length} chars); Builder fallback will retranscribe: ${failureReason}`
|
|
209
|
+
: `[clips] Native transcript saved for ${args.recordingId} via ${args.source ?? "web-speech"} (${fullText.length} chars)`,
|
|
196
210
|
);
|
|
197
211
|
|
|
198
212
|
await writeAppState("refresh-signal", { ts: Date.now() });
|
|
@@ -212,7 +226,13 @@ export default defineAction({
|
|
|
212
226
|
rec && isAutoTitleReplaceable(rec.title, rec.titleSource)
|
|
213
227
|
);
|
|
214
228
|
const summaryQueued = Boolean(rec && !rec.description?.trim());
|
|
215
|
-
|
|
229
|
+
// A truncated capture dispatches too: the transcript job is what runs the
|
|
230
|
+
// Builder fallback, and it must not be skipped just because this clip
|
|
231
|
+
// already has a title and summary.
|
|
232
|
+
if (
|
|
233
|
+
rec?.status === "ready" &&
|
|
234
|
+
(truncated || titleQueued || summaryQueued)
|
|
235
|
+
) {
|
|
216
236
|
await dispatchPostFinalizeJob({
|
|
217
237
|
recordingId: args.recordingId,
|
|
218
238
|
kind: "transcript",
|
|
@@ -226,9 +246,10 @@ export default defineAction({
|
|
|
226
246
|
|
|
227
247
|
return {
|
|
228
248
|
recordingId: args.recordingId,
|
|
229
|
-
status:
|
|
249
|
+
status: savedStatus,
|
|
230
250
|
provider: args.source ?? "web-speech",
|
|
231
251
|
chars: fullText.length,
|
|
252
|
+
truncated,
|
|
232
253
|
titleQueued,
|
|
233
254
|
summaryQueued,
|
|
234
255
|
};
|
|
@@ -2054,6 +2054,11 @@ export default function RecordRoute() {
|
|
|
2054
2054
|
// (from Web Speech API) with no API key required.
|
|
2055
2055
|
const browserTranscript = await liveTranscription.stopAndWait();
|
|
2056
2056
|
const trimmedTranscript = browserTranscript.trim();
|
|
2057
|
+
// Non-null when Web Speech died before we asked it to stop, so whatever
|
|
2058
|
+
// it captured covers only part of the recording. Send it with the text:
|
|
2059
|
+
// a partial transcript must never be stored as the finished one, or the
|
|
2060
|
+
// cloud fallback is suppressed and the user keeps the first few lines.
|
|
2061
|
+
const incompleteReason = liveTranscription.getIncompleteReason();
|
|
2057
2062
|
if (trimmedTranscript) {
|
|
2058
2063
|
const transcriptRes = await fetch(
|
|
2059
2064
|
agentNativePath("/_agent-native/actions/save-browser-transcript"),
|
|
@@ -2064,6 +2069,7 @@ export default function RecordRoute() {
|
|
|
2064
2069
|
recordingId: pending.id,
|
|
2065
2070
|
fullText: trimmedTranscript,
|
|
2066
2071
|
source: "web-speech",
|
|
2072
|
+
failureReason: incompleteReason ?? undefined,
|
|
2067
2073
|
}),
|
|
2068
2074
|
},
|
|
2069
2075
|
).catch((err) => {
|
|
@@ -2086,9 +2092,11 @@ export default function RecordRoute() {
|
|
|
2086
2092
|
recordingId: pending.id,
|
|
2087
2093
|
fullText: "",
|
|
2088
2094
|
source: "web-speech",
|
|
2089
|
-
failureReason:
|
|
2090
|
-
|
|
2091
|
-
|
|
2095
|
+
failureReason:
|
|
2096
|
+
incompleteReason ??
|
|
2097
|
+
(liveTranscription.supported
|
|
2098
|
+
? "Browser native transcription returned no speech before recording stopped."
|
|
2099
|
+
: "Browser Web Speech recognition is unavailable in this browser."),
|
|
2092
2100
|
}),
|
|
2093
2101
|
},
|
|
2094
2102
|
).catch((err) => {
|