@agent-native/core 0.95.1 → 0.97.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +64 -0
- package/corpus/core/docs/content/audit-log.mdx +2 -1
- package/corpus/core/docs/content/automations.mdx +7 -7
- package/corpus/core/docs/content/creating-templates.mdx +1 -1
- package/corpus/core/docs/content/internationalization.mdx +2 -1
- package/corpus/core/docs/content/locales/ar-SA/audit-log.mdx +2 -1
- package/corpus/core/docs/content/locales/ar-SA/automations.mdx +7 -7
- package/corpus/core/docs/content/locales/ar-SA/getting-started.mdx +7 -1
- package/corpus/core/docs/content/locales/ar-SA/internationalization.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/package-lifecycle.mdx +19 -0
- package/corpus/core/docs/content/locales/ar-SA/sandbox-adapters.mdx +18 -7
- package/corpus/core/docs/content/locales/ar-SA/security.mdx +8 -0
- package/corpus/core/docs/content/locales/de-DE/audit-log.mdx +2 -1
- package/corpus/core/docs/content/locales/de-DE/automations.mdx +7 -7
- package/corpus/core/docs/content/locales/de-DE/getting-started.mdx +7 -1
- package/corpus/core/docs/content/locales/de-DE/internationalization.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/package-lifecycle.mdx +22 -0
- package/corpus/core/docs/content/locales/de-DE/sandbox-adapters.mdx +18 -7
- package/corpus/core/docs/content/locales/de-DE/security.mdx +8 -0
- package/corpus/core/docs/content/locales/es-ES/audit-log.mdx +2 -1
- package/corpus/core/docs/content/locales/es-ES/automations.mdx +7 -7
- package/corpus/core/docs/content/locales/es-ES/getting-started.mdx +7 -1
- package/corpus/core/docs/content/locales/es-ES/internationalization.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/package-lifecycle.mdx +22 -0
- package/corpus/core/docs/content/locales/es-ES/sandbox-adapters.mdx +18 -7
- package/corpus/core/docs/content/locales/es-ES/security.mdx +8 -0
- package/corpus/core/docs/content/locales/fr-FR/audit-log.mdx +2 -1
- package/corpus/core/docs/content/locales/fr-FR/automations.mdx +7 -7
- package/corpus/core/docs/content/locales/fr-FR/getting-started.mdx +7 -1
- package/corpus/core/docs/content/locales/fr-FR/internationalization.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/package-lifecycle.mdx +21 -0
- package/corpus/core/docs/content/locales/fr-FR/sandbox-adapters.mdx +19 -8
- package/corpus/core/docs/content/locales/fr-FR/security.mdx +8 -0
- package/corpus/core/docs/content/locales/hi-IN/audit-log.mdx +2 -1
- package/corpus/core/docs/content/locales/hi-IN/automations.mdx +7 -7
- package/corpus/core/docs/content/locales/hi-IN/getting-started.mdx +7 -1
- package/corpus/core/docs/content/locales/hi-IN/internationalization.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/package-lifecycle.mdx +20 -0
- package/corpus/core/docs/content/locales/hi-IN/sandbox-adapters.mdx +18 -7
- package/corpus/core/docs/content/locales/hi-IN/security.mdx +8 -0
- package/corpus/core/docs/content/locales/ja-JP/audit-log.mdx +2 -1
- package/corpus/core/docs/content/locales/ja-JP/automations.mdx +7 -7
- package/corpus/core/docs/content/locales/ja-JP/getting-started.mdx +7 -1
- package/corpus/core/docs/content/locales/ja-JP/internationalization.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/package-lifecycle.mdx +21 -0
- package/corpus/core/docs/content/locales/ja-JP/sandbox-adapters.mdx +17 -6
- package/corpus/core/docs/content/locales/ja-JP/security.mdx +8 -0
- package/corpus/core/docs/content/locales/ko-KR/audit-log.mdx +2 -1
- package/corpus/core/docs/content/locales/ko-KR/automations.mdx +7 -7
- package/corpus/core/docs/content/locales/ko-KR/getting-started.mdx +7 -1
- package/corpus/core/docs/content/locales/ko-KR/internationalization.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/package-lifecycle.mdx +20 -0
- package/corpus/core/docs/content/locales/ko-KR/sandbox-adapters.mdx +17 -6
- package/corpus/core/docs/content/locales/ko-KR/security.mdx +8 -0
- package/corpus/core/docs/content/locales/pt-BR/audit-log.mdx +2 -1
- package/corpus/core/docs/content/locales/pt-BR/automations.mdx +7 -7
- package/corpus/core/docs/content/locales/pt-BR/getting-started.mdx +7 -1
- package/corpus/core/docs/content/locales/pt-BR/internationalization.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/package-lifecycle.mdx +21 -0
- package/corpus/core/docs/content/locales/pt-BR/sandbox-adapters.mdx +18 -7
- package/corpus/core/docs/content/locales/pt-BR/security.mdx +8 -0
- package/corpus/core/docs/content/locales/zh-CN/audit-log.mdx +2 -1
- package/corpus/core/docs/content/locales/zh-CN/automations.mdx +7 -7
- package/corpus/core/docs/content/locales/zh-CN/getting-started.mdx +6 -4
- package/corpus/core/docs/content/locales/zh-CN/internationalization.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/package-lifecycle.mdx +19 -0
- package/corpus/core/docs/content/locales/zh-CN/sandbox-adapters.mdx +17 -6
- package/corpus/core/docs/content/locales/zh-CN/security.mdx +8 -0
- package/corpus/core/docs/content/locales/zh-TW/audit-log.mdx +2 -1
- package/corpus/core/docs/content/locales/zh-TW/automations.mdx +7 -7
- package/corpus/core/docs/content/locales/zh-TW/getting-started.mdx +6 -4
- package/corpus/core/docs/content/locales/zh-TW/internationalization.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/package-lifecycle.mdx +19 -0
- package/corpus/core/docs/content/locales/zh-TW/sandbox-adapters.mdx +18 -7
- package/corpus/core/docs/content/locales/zh-TW/security.mdx +8 -0
- package/corpus/core/docs/content/package-lifecycle.mdx +51 -0
- package/corpus/core/docs/content/sandbox-adapters.mdx +16 -5
- package/corpus/core/package.json +11 -2
- package/corpus/core/src/a2a/auth-policy.ts +33 -0
- package/corpus/core/src/a2a/client.ts +11 -1
- package/corpus/core/src/agent/durable-background.ts +15 -7
- package/corpus/core/src/agent/production-agent.ts +87 -27
- package/corpus/core/src/agent/run-store.ts +13 -4
- package/corpus/core/src/agent/thread-data-builder.ts +7 -5
- package/corpus/core/src/audit/actions/export-audit-events.ts +162 -0
- package/corpus/core/src/audit/store.ts +8 -3
- package/corpus/core/src/audit/types.ts +3 -0
- package/corpus/core/src/chat-threads/store.ts +20 -1
- package/corpus/core/src/cli/code-agent-executor.ts +1 -0
- package/corpus/core/src/cli/code-agent-runs.ts +14 -0
- package/corpus/core/src/cli/doctor.ts +396 -0
- package/corpus/core/src/cli/index.ts +56 -0
- package/corpus/core/src/cli/info.ts +3 -3
- package/corpus/core/src/cli/package-lifecycle.ts +821 -0
- package/corpus/core/src/client/AgentPanel.tsx +32 -25
- package/corpus/core/src/client/AssistantChat.tsx +36 -20
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +141 -90
- package/corpus/core/src/client/agent-chat-adapter.ts +9 -9
- package/corpus/core/src/client/chat/ChatHistoryList.tsx +404 -0
- package/corpus/core/src/client/chat/index.ts +6 -0
- package/corpus/core/src/client/chat/tool-call-display.tsx +37 -3
- package/corpus/core/src/client/code-agent-chat-adapter.ts +72 -4
- package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +52 -11
- package/corpus/core/src/client/composer/TiptapComposer.tsx +157 -20
- package/corpus/core/src/client/composer/VoiceButton.tsx +28 -0
- package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +5 -0
- package/corpus/core/src/client/conversation/code-agent-transcript.ts +4 -5
- package/corpus/core/src/client/guided-questions.tsx +2 -1
- package/corpus/core/src/client/index.ts +11 -0
- package/corpus/core/src/client/use-chat-threads.ts +10 -1
- package/corpus/core/src/client/voice-provider-status.ts +44 -0
- package/corpus/core/src/code-agents/transcript-normalizer.ts +76 -0
- package/corpus/core/src/deploy/build.ts +12 -11
- package/corpus/core/src/guards/db-tool-scoping.ts +129 -0
- package/corpus/core/src/guards/index.ts +23 -0
- package/corpus/core/src/guards/no-drizzle-push.ts +116 -0
- package/corpus/core/src/guards/no-env-credentials.ts +229 -0
- package/corpus/core/src/guards/no-env-mutation.ts +114 -0
- package/corpus/core/src/guards/no-localhost-fallback.ts +124 -0
- package/corpus/core/src/guards/no-unscoped-credentials.ts +227 -0
- package/corpus/core/src/guards/no-unscoped-queries.ts +834 -0
- package/corpus/core/src/guards/scan-utils.ts +105 -0
- package/corpus/core/src/guards/types.ts +30 -0
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +35 -5
- package/corpus/core/src/integrations/adapters/slack.ts +74 -21
- package/corpus/core/src/integrations/webhook-handler.ts +14 -0
- package/corpus/core/src/localization/default-messages.ts +6 -0
- package/corpus/core/src/observability/hosted-model-experiment.ts +118 -0
- package/corpus/core/src/observability/routes.ts +17 -0
- package/corpus/core/src/observability/store.ts +4 -1
- package/corpus/core/src/observability/traces.ts +41 -2
- package/corpus/core/src/org/accept-pending.ts +9 -1
- package/corpus/core/src/org/migrations.ts +41 -0
- package/corpus/core/src/package-lifecycle/index.ts +1 -0
- package/corpus/core/src/package-lifecycle/manifest.ts +120 -0
- package/corpus/core/src/provider-api/custom-registry.ts +56 -0
- package/corpus/core/src/provider-api/index.ts +2 -0
- package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +19 -1
- package/corpus/core/src/scripts/call-agent.ts +53 -3
- package/corpus/core/src/scripts/chat/search-chats.ts +11 -8
- package/corpus/core/src/secrets/register-framework-secrets.ts +1 -1
- package/corpus/core/src/secrets/storage.ts +47 -27
- package/corpus/core/src/server/action-discovery.ts +4 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +95 -18
- package/corpus/core/src/server/core-routes-plugin.ts +45 -14
- package/corpus/core/src/server/csrf.ts +24 -5
- package/corpus/core/src/server/framework-request-handler.ts +34 -0
- package/corpus/core/src/server/google-realtime-session.ts +1 -36
- package/corpus/core/src/server/poll.ts +24 -2
- package/corpus/core/src/server/realtime-voice.ts +80 -24
- package/corpus/core/src/server/request-origin.ts +63 -0
- package/corpus/core/src/server/transcribe-voice.ts +1 -50
- package/corpus/core/src/server/voice-providers-status.ts +4 -3
- package/corpus/core/src/shared/cache-control.ts +2 -8
- package/corpus/core/src/styles/agent-native.css +1 -0
- package/corpus/core/src/styles/chat-history-list.css +313 -0
- package/corpus/core/src/templates/default/package.json +2 -2
- package/corpus/core/src/templates/headless/package.json +0 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +3 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
- package/corpus/core/src/templates/workspace-core/package.json +0 -1
- package/corpus/core/src/templates/workspace-root/package.json +0 -1
- package/corpus/core/src/triggers/actions.ts +11 -3
- package/corpus/core/src/triggers/types.ts +7 -1
- package/corpus/core/src/vite/client.ts +1 -0
- package/corpus/templates/analytics/AGENTS.md +7 -0
- package/corpus/templates/analytics/actions/bigquery.ts +26 -2
- package/corpus/templates/analytics/actions/compose-dashboard.ts +65 -37
- package/corpus/templates/analytics/actions/data-source-status.ts +18 -0
- package/corpus/templates/analytics/actions/mutate-dashboard.ts +73 -24
- package/corpus/templates/analytics/actions/reorder-dashboard-panels.ts +16 -13
- package/corpus/templates/analytics/actions/update-dashboard.ts +53 -42
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +5 -4
- package/corpus/templates/analytics/app/global.css +10 -0
- package/corpus/templates/analytics/app/pages/Ask.tsx +25 -2
- package/corpus/templates/analytics/changelog/2026-07-10-analytics-answers-simple-time-bounded-metrics-without-unnece.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-analytics-chat-reliably-uses-connected-data-sources-across-s.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-chat-threads-now-stay-clear-of-top-actions-and-fade-smoothly.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-context-chips-can-now-be-selected-and-removed-one-at-a-time-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-dashboard-edits-from-the-agent-and-the-ui-at-the-same-time-n.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-the-ask-composer-no-longer-carries-dashboard-or-panel-contex.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-the-ask-section-stays-highlighted-while-its-chat-history-is-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-timed-out-bigquery-jobs-are-now-cancelled-so-they-stop-consu.md +6 -0
- package/corpus/templates/analytics/package.json +1 -2
- package/corpus/templates/analytics/server/lib/bigquery.ts +91 -14
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +154 -11
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +82 -7
- package/corpus/templates/assets/package.json +1 -2
- package/corpus/templates/brain/package.json +1 -2
- package/corpus/templates/calendar/package.json +1 -2
- package/corpus/templates/chat/package.json +1 -2
- package/corpus/templates/clips/changelog/2026-07-10-atomic-view-tracking.md +6 -0
- package/corpus/templates/clips/chrome-extension/package.json +3 -2
- package/corpus/templates/clips/desktop/package.json +6 -4
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +26 -13
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +4 -1
- package/corpus/templates/clips/package.json +1 -2
- package/corpus/templates/clips/server/db/schema.ts +29 -17
- package/corpus/templates/clips/server/plugins/db.ts +8 -0
- package/corpus/templates/clips/server/routes/api/view-event.post.ts +260 -105
- package/corpus/templates/content/.agents/skills/notion-integration/SKILL.md +16 -0
- package/corpus/templates/content/AGENTS.md +72 -62
- package/corpus/templates/content/actions/_content-database-source-adapters.ts +84 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +206 -96
- package/corpus/templates/content/actions/_notion-database-source-adapter.ts +216 -0
- package/corpus/templates/content/actions/_position-utils.ts +76 -0
- package/corpus/templates/content/actions/_property-utils.ts +31 -20
- package/corpus/templates/content/actions/add-database-item.ts +52 -39
- package/corpus/templates/content/actions/attach-content-database-source.ts +95 -11
- package/corpus/templates/content/actions/change-content-database-source-role.ts +24 -1
- package/corpus/templates/content/actions/configure-document-property.ts +36 -27
- package/corpus/templates/content/actions/create-content-database.ts +40 -30
- package/corpus/templates/content/actions/create-document.ts +39 -32
- package/corpus/templates/content/actions/duplicate-document-property.ts +37 -28
- package/corpus/templates/content/actions/list-notion-database-sources.ts +80 -0
- package/corpus/templates/content/actions/move-document.ts +64 -48
- package/corpus/templates/content/actions/refresh-content-database-source.ts +42 -3
- package/corpus/templates/content/actions/share-local-file-document.ts +36 -27
- package/corpus/templates/content/actions/suggest-source-join-key.ts +39 -16
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +89 -23
- package/corpus/templates/content/app/components/editor/database/settings.tsx +1 -1
- package/corpus/templates/content/app/hooks/use-content-database.ts +18 -1
- package/corpus/templates/content/app/i18n/zh-TW.ts +4 -0
- package/corpus/templates/content/app/i18n-data.ts +40 -0
- package/corpus/templates/content/changelog/2026-07-10-failed-row-creation-and-source-attach-now-show-an-error-inst.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-items-added-at-the-same-time-no-longer-end-up-with-identical.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-notion-databases-can-add-read-only-details-to-content-tables.md +6 -0
- package/corpus/templates/content/package.json +1 -2
- package/corpus/templates/content/parity/matrix.md +25 -25
- package/corpus/templates/content/parity/matrix.ts +1 -0
- package/corpus/templates/content/server/routes/api/documents/[id]/move.patch.ts +43 -26
- package/corpus/templates/content/shared/api.ts +16 -1
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +8 -4
- package/corpus/templates/design/AGENTS.md +12 -2
- package/corpus/templates/design/DEVELOPING.md +10 -6
- package/corpus/templates/design/actions/apply-visual-edit.ts +191 -6
- package/corpus/templates/design/actions/duplicate-design.ts +31 -25
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +5 -1
- package/corpus/templates/design/changelog/2026-07-10-duplicating-a-design-can-no-longer-produce-a-copy-with-missi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-local-visual-edits-can-now-save-safe-leaf-text-class-and.md +6 -0
- package/corpus/templates/design/package.json +1 -1
- package/corpus/templates/design/shared/local-jsx-visual-edit.ts +388 -0
- package/corpus/templates/dispatch/package.json +1 -2
- package/corpus/templates/forms/actions/patch-form-fields.ts +82 -44
- package/corpus/templates/forms/changelog/2026-07-10-simultaneous-edits-to-different-form-fields-no-longer-overwr.md +6 -0
- package/corpus/templates/forms/package.json +1 -2
- package/corpus/templates/macros/package.json +1 -2
- package/corpus/templates/mail/app/components/email/EmailThread.tsx +3 -1
- package/corpus/templates/mail/changelog/2026-07-10-fixed-calendar-rsvp-buttons-in-emails-firing-duplicate-respo.md +6 -0
- package/corpus/templates/mail/package.json +1 -2
- package/corpus/templates/plan/actions/restore-plan-version.ts +126 -96
- package/corpus/templates/plan/changelog/2026-07-10-restoring-a-plan-version-can-no-longer-leave-a-plan-half-res.md +6 -0
- package/corpus/templates/plan/package.json +1 -2
- package/corpus/templates/plan/server/plans.ts +9 -2
- package/corpus/templates/slides/actions/list-decks.ts +28 -0
- package/corpus/templates/slides/app/components/deck/MermaidRenderer.tsx +41 -26
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +4 -8
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +2 -4
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +4 -8
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +5 -12
- package/corpus/templates/slides/app/components/editor/HistoryPanel.tsx +3 -6
- package/corpus/templates/slides/app/components/editor/ImageDropPromptPopover.tsx +3 -6
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +2 -5
- package/corpus/templates/slides/app/context/DeckContext.tsx +47 -4
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +11 -30
- package/corpus/templates/slides/app/pages/Index.tsx +2 -3
- package/corpus/templates/slides/app/root.tsx +0 -5
- package/corpus/templates/slides/changelog/2026-07-10-deck-lists-load-much-faster-and-no-longer-re-download-slide-.md +6 -0
- package/corpus/templates/slides/package.json +1 -2
- package/dist/a2a/auth-policy.d.ts +19 -0
- package/dist/a2a/auth-policy.d.ts.map +1 -1
- package/dist/a2a/auth-policy.js +32 -0
- package/dist/a2a/auth-policy.js.map +1 -1
- package/dist/a2a/client.d.ts +7 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +2 -1
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/durable-background.d.ts +8 -5
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +15 -8
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/production-agent.d.ts +6 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +63 -26
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +9 -4
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +1 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +6 -5
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/audit/actions/export-audit-events.d.ts +27 -0
- package/dist/audit/actions/export-audit-events.d.ts.map +1 -0
- package/dist/audit/actions/export-audit-events.js +144 -0
- package/dist/audit/actions/export-audit-events.js.map +1 -0
- package/dist/audit/store.d.ts +1 -0
- package/dist/audit/store.d.ts.map +1 -1
- package/dist/audit/store.js +8 -3
- package/dist/audit/store.js.map +1 -1
- package/dist/audit/types.d.ts +3 -0
- package/dist/audit/types.d.ts.map +1 -1
- package/dist/audit/types.js.map +1 -1
- package/dist/chat-threads/store.d.ts +10 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +6 -0
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +1 -0
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/code-agent-runs.d.ts +12 -0
- package/dist/cli/code-agent-runs.d.ts.map +1 -1
- package/dist/cli/code-agent-runs.js +1 -0
- package/dist/cli/code-agent-runs.js.map +1 -1
- package/dist/cli/doctor.d.ts +83 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +277 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/index.js +50 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/info.js +3 -3
- package/dist/cli/info.js.map +1 -1
- package/dist/cli/package-lifecycle.d.ts +50 -0
- package/dist/cli/package-lifecycle.d.ts.map +1 -0
- package/dist/cli/package-lifecycle.js +560 -0
- package/dist/cli/package-lifecycle.js.map +1 -0
- 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 +11 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +7 -4
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +83 -10
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.js +7 -3
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/ChatHistoryList.d.ts +88 -0
- package/dist/client/chat/ChatHistoryList.d.ts.map +1 -0
- package/dist/client/chat/ChatHistoryList.js +83 -0
- package/dist/client/chat/ChatHistoryList.js.map +1 -0
- package/dist/client/chat/index.d.ts +1 -0
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -0
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +13 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +10 -2
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/code-agent-chat-adapter.d.ts +17 -1
- package/dist/client/code-agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/code-agent-chat-adapter.js +47 -3
- package/dist/client/code-agent-chat-adapter.js.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.d.ts +11 -1
- package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.js +5 -3
- package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +25 -2
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +96 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/VoiceButton.d.ts.map +1 -1
- package/dist/client/composer/VoiceButton.js +21 -1
- package/dist/client/composer/VoiceButton.js.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.js +5 -0
- package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
- package/dist/client/conversation/code-agent-transcript.d.ts +2 -0
- package/dist/client/conversation/code-agent-transcript.d.ts.map +1 -1
- package/dist/client/conversation/code-agent-transcript.js +3 -5
- package/dist/client/conversation/code-agent-transcript.js.map +1 -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/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +9 -1
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/client/voice-provider-status.d.ts +10 -0
- package/dist/client/voice-provider-status.d.ts.map +1 -0
- package/dist/client/voice-provider-status.js +32 -0
- package/dist/client/voice-provider-status.js.map +1 -0
- package/dist/code-agents/transcript-normalizer.d.ts +29 -0
- package/dist/code-agents/transcript-normalizer.d.ts.map +1 -1
- package/dist/code-agents/transcript-normalizer.js +55 -0
- package/dist/code-agents/transcript-normalizer.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +13 -11
- package/dist/deploy/build.js.map +1 -1
- package/dist/guards/db-tool-scoping.d.ts +38 -0
- package/dist/guards/db-tool-scoping.d.ts.map +1 -0
- package/dist/guards/db-tool-scoping.js +114 -0
- package/dist/guards/db-tool-scoping.js.map +1 -0
- package/dist/guards/index.d.ts +23 -0
- package/dist/guards/index.d.ts.map +1 -0
- package/dist/guards/index.js +19 -0
- package/dist/guards/index.js.map +1 -0
- package/dist/guards/no-drizzle-push.d.ts +14 -0
- package/dist/guards/no-drizzle-push.d.ts.map +1 -0
- package/dist/guards/no-drizzle-push.js +97 -0
- package/dist/guards/no-drizzle-push.js.map +1 -0
- package/dist/guards/no-env-credentials.d.ts +36 -0
- package/dist/guards/no-env-credentials.d.ts.map +1 -0
- package/dist/guards/no-env-credentials.js +204 -0
- package/dist/guards/no-env-credentials.js.map +1 -0
- package/dist/guards/no-env-mutation.d.ts +23 -0
- package/dist/guards/no-env-mutation.d.ts.map +1 -0
- package/dist/guards/no-env-mutation.js +90 -0
- package/dist/guards/no-env-mutation.js.map +1 -0
- package/dist/guards/no-localhost-fallback.d.ts +30 -0
- package/dist/guards/no-localhost-fallback.d.ts.map +1 -0
- package/dist/guards/no-localhost-fallback.js +105 -0
- package/dist/guards/no-localhost-fallback.js.map +1 -0
- package/dist/guards/no-unscoped-credentials.d.ts +28 -0
- package/dist/guards/no-unscoped-credentials.d.ts.map +1 -0
- package/dist/guards/no-unscoped-credentials.js +199 -0
- package/dist/guards/no-unscoped-credentials.js.map +1 -0
- package/dist/guards/no-unscoped-queries.d.ts +32 -0
- package/dist/guards/no-unscoped-queries.d.ts.map +1 -0
- package/dist/guards/no-unscoped-queries.js +720 -0
- package/dist/guards/no-unscoped-queries.js.map +1 -0
- package/dist/guards/scan-utils.d.ts +28 -0
- package/dist/guards/scan-utils.d.ts.map +1 -0
- package/dist/guards/scan-utils.js +92 -0
- package/dist/guards/scan-utils.js.map +1 -0
- package/dist/guards/types.d.ts +28 -0
- package/dist/guards/types.d.ts.map +1 -0
- package/dist/guards/types.js +11 -0
- package/dist/guards/types.js.map +1 -0
- package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
- package/dist/integrations/a2a-continuation-processor.js +25 -5
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +55 -21
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +11 -0
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/localization/default-messages.d.ts +5 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +5 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/hosted-model-experiment.d.ts +39 -0
- package/dist/observability/hosted-model-experiment.d.ts.map +1 -0
- package/dist/observability/hosted-model-experiment.js +90 -0
- package/dist/observability/hosted-model-experiment.js.map +1 -0
- package/dist/observability/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts.map +1 -1
- package/dist/observability/routes.js +16 -0
- package/dist/observability/routes.js.map +1 -1
- package/dist/observability/store.d.ts.map +1 -1
- package/dist/observability/store.js +4 -1
- package/dist/observability/store.js.map +1 -1
- package/dist/observability/traces.d.ts +6 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +28 -2
- package/dist/observability/traces.js.map +1 -1
- package/dist/org/accept-pending.d.ts.map +1 -1
- package/dist/org/accept-pending.js +9 -1
- package/dist/org/accept-pending.js.map +1 -1
- package/dist/org/migrations.d.ts +7 -2
- package/dist/org/migrations.d.ts.map +1 -1
- package/dist/org/migrations.js +41 -0
- package/dist/org/migrations.js.map +1 -1
- package/dist/package-lifecycle/index.d.ts +2 -0
- package/dist/package-lifecycle/index.d.ts.map +1 -0
- package/dist/package-lifecycle/index.js +2 -0
- package/dist/package-lifecycle/index.js.map +1 -0
- package/dist/package-lifecycle/manifest.d.ts +24 -0
- package/dist/package-lifecycle/manifest.d.ts.map +1 -0
- package/dist/package-lifecycle/manifest.js +81 -0
- package/dist/package-lifecycle/manifest.js.map +1 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/custom-registry.d.ts +32 -1
- package/dist/provider-api/custom-registry.d.ts.map +1 -1
- package/dist/provider-api/custom-registry.js +41 -1
- package/dist/provider-api/custom-registry.js.map +1 -1
- package/dist/provider-api/index.d.ts +1 -1
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +1 -1
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +19 -1
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +43 -3
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/scripts/chat/search-chats.d.ts +1 -1
- package/dist/scripts/chat/search-chats.d.ts.map +1 -1
- package/dist/scripts/chat/search-chats.js +11 -8
- package/dist/scripts/chat/search-chats.js.map +1 -1
- package/dist/secrets/register-framework-secrets.js +1 -1
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/secrets/storage.d.ts.map +1 -1
- package/dist/secrets/storage.js +45 -27
- 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/agent-chat-plugin.d.ts +11 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +74 -19
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts +3 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +36 -12
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/csrf.js +18 -5
- package/dist/server/csrf.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +34 -0
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/google-realtime-session.d.ts.map +1 -1
- package/dist/server/google-realtime-session.js +2 -34
- package/dist/server/google-realtime-session.js.map +1 -1
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +24 -2
- package/dist/server/poll.js.map +1 -1
- package/dist/server/realtime-voice.d.ts.map +1 -1
- package/dist/server/realtime-voice.js +64 -21
- package/dist/server/realtime-voice.js.map +1 -1
- package/dist/server/request-origin.d.ts +10 -0
- package/dist/server/request-origin.d.ts.map +1 -0
- package/dist/server/request-origin.js +60 -0
- package/dist/server/request-origin.js.map +1 -0
- package/dist/server/transcribe-voice.d.ts.map +1 -1
- package/dist/server/transcribe-voice.js +2 -48
- package/dist/server/transcribe-voice.js.map +1 -1
- package/dist/server/voice-providers-status.d.ts.map +1 -1
- package/dist/server/voice-providers-status.js +2 -3
- package/dist/server/voice-providers-status.js.map +1 -1
- package/dist/shared/cache-control.d.ts +4 -6
- package/dist/shared/cache-control.d.ts.map +1 -1
- package/dist/shared/cache-control.js +2 -7
- package/dist/shared/cache-control.js.map +1 -1
- package/dist/styles/agent-native.css +1 -0
- package/dist/styles/chat-history-list.css +313 -0
- package/dist/templates/default/package.json +2 -2
- package/dist/templates/headless/package.json +0 -1
- package/dist/templates/workspace-core/.agents/skills/audit-log/SKILL.md +3 -0
- package/dist/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
- package/dist/templates/workspace-core/package.json +0 -1
- package/dist/templates/workspace-root/package.json +0 -1
- package/dist/triggers/actions.d.ts.map +1 -1
- package/dist/triggers/actions.js +8 -3
- package/dist/triggers/actions.js.map +1 -1
- package/dist/triggers/types.d.ts +7 -1
- package/dist/triggers/types.d.ts.map +1 -1
- package/dist/triggers/types.js.map +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +1 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/audit-log.mdx +2 -1
- package/docs/content/automations.mdx +7 -7
- package/docs/content/creating-templates.mdx +1 -1
- package/docs/content/internationalization.mdx +2 -1
- package/docs/content/locales/ar-SA/audit-log.mdx +2 -1
- package/docs/content/locales/ar-SA/automations.mdx +7 -7
- package/docs/content/locales/ar-SA/getting-started.mdx +7 -1
- package/docs/content/locales/ar-SA/internationalization.mdx +1 -1
- package/docs/content/locales/ar-SA/package-lifecycle.mdx +19 -0
- package/docs/content/locales/ar-SA/sandbox-adapters.mdx +18 -7
- package/docs/content/locales/ar-SA/security.mdx +8 -0
- package/docs/content/locales/de-DE/audit-log.mdx +2 -1
- package/docs/content/locales/de-DE/automations.mdx +7 -7
- package/docs/content/locales/de-DE/getting-started.mdx +7 -1
- package/docs/content/locales/de-DE/internationalization.mdx +1 -1
- package/docs/content/locales/de-DE/package-lifecycle.mdx +22 -0
- package/docs/content/locales/de-DE/sandbox-adapters.mdx +18 -7
- package/docs/content/locales/de-DE/security.mdx +8 -0
- package/docs/content/locales/es-ES/audit-log.mdx +2 -1
- package/docs/content/locales/es-ES/automations.mdx +7 -7
- package/docs/content/locales/es-ES/getting-started.mdx +7 -1
- package/docs/content/locales/es-ES/internationalization.mdx +1 -1
- package/docs/content/locales/es-ES/package-lifecycle.mdx +22 -0
- package/docs/content/locales/es-ES/sandbox-adapters.mdx +18 -7
- package/docs/content/locales/es-ES/security.mdx +8 -0
- package/docs/content/locales/fr-FR/audit-log.mdx +2 -1
- package/docs/content/locales/fr-FR/automations.mdx +7 -7
- package/docs/content/locales/fr-FR/getting-started.mdx +7 -1
- package/docs/content/locales/fr-FR/internationalization.mdx +1 -1
- package/docs/content/locales/fr-FR/package-lifecycle.mdx +21 -0
- package/docs/content/locales/fr-FR/sandbox-adapters.mdx +19 -8
- package/docs/content/locales/fr-FR/security.mdx +8 -0
- package/docs/content/locales/hi-IN/audit-log.mdx +2 -1
- package/docs/content/locales/hi-IN/automations.mdx +7 -7
- package/docs/content/locales/hi-IN/getting-started.mdx +7 -1
- package/docs/content/locales/hi-IN/internationalization.mdx +1 -1
- package/docs/content/locales/hi-IN/package-lifecycle.mdx +20 -0
- package/docs/content/locales/hi-IN/sandbox-adapters.mdx +18 -7
- package/docs/content/locales/hi-IN/security.mdx +8 -0
- package/docs/content/locales/ja-JP/audit-log.mdx +2 -1
- package/docs/content/locales/ja-JP/automations.mdx +7 -7
- package/docs/content/locales/ja-JP/getting-started.mdx +7 -1
- package/docs/content/locales/ja-JP/internationalization.mdx +1 -1
- package/docs/content/locales/ja-JP/package-lifecycle.mdx +21 -0
- package/docs/content/locales/ja-JP/sandbox-adapters.mdx +17 -6
- package/docs/content/locales/ja-JP/security.mdx +8 -0
- package/docs/content/locales/ko-KR/audit-log.mdx +2 -1
- package/docs/content/locales/ko-KR/automations.mdx +7 -7
- package/docs/content/locales/ko-KR/getting-started.mdx +7 -1
- package/docs/content/locales/ko-KR/internationalization.mdx +1 -1
- package/docs/content/locales/ko-KR/package-lifecycle.mdx +20 -0
- package/docs/content/locales/ko-KR/sandbox-adapters.mdx +17 -6
- package/docs/content/locales/ko-KR/security.mdx +8 -0
- package/docs/content/locales/pt-BR/audit-log.mdx +2 -1
- package/docs/content/locales/pt-BR/automations.mdx +7 -7
- package/docs/content/locales/pt-BR/getting-started.mdx +7 -1
- package/docs/content/locales/pt-BR/internationalization.mdx +1 -1
- package/docs/content/locales/pt-BR/package-lifecycle.mdx +21 -0
- package/docs/content/locales/pt-BR/sandbox-adapters.mdx +18 -7
- package/docs/content/locales/pt-BR/security.mdx +8 -0
- package/docs/content/locales/zh-CN/audit-log.mdx +2 -1
- package/docs/content/locales/zh-CN/automations.mdx +7 -7
- package/docs/content/locales/zh-CN/getting-started.mdx +6 -4
- package/docs/content/locales/zh-CN/internationalization.mdx +1 -1
- package/docs/content/locales/zh-CN/package-lifecycle.mdx +19 -0
- package/docs/content/locales/zh-CN/sandbox-adapters.mdx +17 -6
- package/docs/content/locales/zh-CN/security.mdx +8 -0
- package/docs/content/locales/zh-TW/audit-log.mdx +2 -1
- package/docs/content/locales/zh-TW/automations.mdx +7 -7
- package/docs/content/locales/zh-TW/getting-started.mdx +6 -4
- package/docs/content/locales/zh-TW/internationalization.mdx +1 -1
- package/docs/content/locales/zh-TW/package-lifecycle.mdx +19 -0
- package/docs/content/locales/zh-TW/sandbox-adapters.mdx +18 -7
- package/docs/content/locales/zh-TW/security.mdx +8 -0
- package/docs/content/package-lifecycle.mdx +51 -0
- package/docs/content/sandbox-adapters.mdx +16 -5
- package/package.json +12 -3
- package/src/templates/default/package.json +2 -2
- package/src/templates/headless/package.json +0 -1
- package/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +3 -0
- package/src/templates/workspace-core/.agents/skills/automations/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
- package/src/templates/workspace-core/package.json +0 -1
- package/src/templates/workspace-root/package.json +0 -1
- package/corpus/templates/slides/app/components/ui/toast.tsx +0 -1
- package/corpus/templates/slides/app/components/ui/toaster.tsx +0 -1
- package/corpus/templates/slides/app/hooks/use-toast.ts +0 -1
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { defineAction } from "../../action.js";
|
|
4
|
+
import { MAX_LIMIT, queryAuditEvents } from "../store.js";
|
|
5
|
+
import type { AuditEvent } from "../types.js";
|
|
6
|
+
|
|
7
|
+
const DEFAULT_MAX_ROWS = 5000;
|
|
8
|
+
const HARD_CAP_ROWS = 10000;
|
|
9
|
+
|
|
10
|
+
// Deterministic column order for CSV — mirrors the store's list projection
|
|
11
|
+
// (`LIST_COLUMNS`), which deliberately excludes `input` so a bulk export
|
|
12
|
+
// never streams every event's (redacted) request body at once. Future
|
|
13
|
+
// columns added to the audit store must be reflected here too.
|
|
14
|
+
const CSV_COLUMNS: Array<[key: keyof AuditEvent, header: string]> = [
|
|
15
|
+
["id", "id"],
|
|
16
|
+
["createdAt", "created_at"],
|
|
17
|
+
["action", "action"],
|
|
18
|
+
["caller", "caller"],
|
|
19
|
+
["actorKind", "actor_kind"],
|
|
20
|
+
["actorEmail", "actor_email"],
|
|
21
|
+
["orgId", "org_id"],
|
|
22
|
+
["threadId", "thread_id"],
|
|
23
|
+
["turnId", "turn_id"],
|
|
24
|
+
["targetType", "target_type"],
|
|
25
|
+
["targetId", "target_id"],
|
|
26
|
+
["status", "status"],
|
|
27
|
+
["summary", "summary"],
|
|
28
|
+
["errorCode", "error_code"],
|
|
29
|
+
["ownerEmail", "owner_email"],
|
|
30
|
+
["visibility", "visibility"],
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/** Hand-rolled CSV field escaper — quotes a field when it contains a comma,
|
|
34
|
+
* quote, or newline, doubling any embedded quotes. No dependency needed for
|
|
35
|
+
* ~10 lines of RFC 4180 escaping. */
|
|
36
|
+
function csvField(value: unknown): string {
|
|
37
|
+
if (value === null || value === undefined) return "";
|
|
38
|
+
const raw = String(value);
|
|
39
|
+
if (/[",\n\r]/.test(raw)) {
|
|
40
|
+
return `"${raw.replace(/"/g, '""')}"`;
|
|
41
|
+
}
|
|
42
|
+
return raw;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function toCsv(events: AuditEvent[]): string {
|
|
46
|
+
const header = CSV_COLUMNS.map(([, label]) => label).join(",");
|
|
47
|
+
const rows = events.map((event) =>
|
|
48
|
+
CSV_COLUMNS.map(([key]) => csvField(event[key])).join(","),
|
|
49
|
+
);
|
|
50
|
+
return [header, ...rows].join("\n");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function toNdjson(events: AuditEvent[]): string {
|
|
54
|
+
return events.map((event) => JSON.stringify(event)).join("\n");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Bulk-export audit-log events as CSV or NDJSON — the "bulk export" sensitive
|
|
59
|
+
* read the audit doc itself names. Pages past the per-call row clamp
|
|
60
|
+
* (`queryAuditEvents`'s `MAX_LIMIT`) up to `maxRows`, scoped in SQL to the
|
|
61
|
+
* caller's identity exactly like `list-audit-events`. Read-only; never
|
|
62
|
+
* exposes other tenants' rows.
|
|
63
|
+
*/
|
|
64
|
+
export default defineAction({
|
|
65
|
+
description:
|
|
66
|
+
"Export audit-log events as a CSV or NDJSON document for offline/compliance pulls (up to maxRows, default 5000, hard cap 10000). Use this instead of hand-paging list-audit-events when you need a bulk download of the trail; use list-audit-events instead for browsing recent activity or answering 'what changed'.",
|
|
67
|
+
schema: z.object({
|
|
68
|
+
targetType: z
|
|
69
|
+
.string()
|
|
70
|
+
.optional()
|
|
71
|
+
.describe("Filter to one resource type, e.g. 'recording'."),
|
|
72
|
+
targetId: z
|
|
73
|
+
.string()
|
|
74
|
+
.optional()
|
|
75
|
+
.describe("Filter to one resource id (pair with targetType)."),
|
|
76
|
+
actorKind: z
|
|
77
|
+
.enum(["agent", "human", "system"])
|
|
78
|
+
.optional()
|
|
79
|
+
.describe("Filter to changes made by the agent, a human, or the system."),
|
|
80
|
+
actorEmail: z.string().optional().describe("Filter to one actor's email."),
|
|
81
|
+
status: z
|
|
82
|
+
.enum(["success", "error", "denied"])
|
|
83
|
+
.optional()
|
|
84
|
+
.describe("Filter by outcome."),
|
|
85
|
+
threadId: z.string().optional().describe("Filter to one agent thread."),
|
|
86
|
+
turnId: z
|
|
87
|
+
.string()
|
|
88
|
+
.optional()
|
|
89
|
+
.describe("Filter to one agent turn (a single agent response)."),
|
|
90
|
+
action: z.string().optional().describe("Filter to one action name."),
|
|
91
|
+
sinceMs: z
|
|
92
|
+
.number()
|
|
93
|
+
.optional()
|
|
94
|
+
.describe("Only events at or after this Unix epoch (ms)."),
|
|
95
|
+
format: z
|
|
96
|
+
.enum(["csv", "ndjson"])
|
|
97
|
+
.default("csv")
|
|
98
|
+
.describe(
|
|
99
|
+
"Export format — CSV with a header row, or one JSON event per line.",
|
|
100
|
+
),
|
|
101
|
+
maxRows: z
|
|
102
|
+
.number()
|
|
103
|
+
.optional()
|
|
104
|
+
.describe("Max rows to export (default 5000, hard cap 10000)."),
|
|
105
|
+
}),
|
|
106
|
+
http: { method: "GET" },
|
|
107
|
+
audit: {
|
|
108
|
+
// Read-only actions are skipped by default — this is exactly the
|
|
109
|
+
// "bulk export" sensitive read the framework's own audit doc calls out.
|
|
110
|
+
onRead: true,
|
|
111
|
+
summary: (args) =>
|
|
112
|
+
`Bulk export of audit events (${(args as { format?: string }).format ?? "csv"})`,
|
|
113
|
+
},
|
|
114
|
+
run: async (args, ctx) => {
|
|
115
|
+
const scope = { userEmail: ctx?.userEmail, orgId: ctx?.orgId ?? null };
|
|
116
|
+
const cap = Math.min(
|
|
117
|
+
Math.max(1, Math.floor(args.maxRows ?? DEFAULT_MAX_ROWS)),
|
|
118
|
+
HARD_CAP_ROWS,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const filters = {
|
|
122
|
+
...(args.targetType ? { targetType: args.targetType } : {}),
|
|
123
|
+
...(args.targetId ? { targetId: args.targetId } : {}),
|
|
124
|
+
...(args.actorKind ? { actorKind: args.actorKind } : {}),
|
|
125
|
+
...(args.actorEmail ? { actorEmail: args.actorEmail } : {}),
|
|
126
|
+
...(args.status ? { status: args.status } : {}),
|
|
127
|
+
...(args.threadId ? { threadId: args.threadId } : {}),
|
|
128
|
+
...(args.turnId ? { turnId: args.turnId } : {}),
|
|
129
|
+
...(args.action ? { action: args.action } : {}),
|
|
130
|
+
...(typeof args.sinceMs === "number" ? { sinceMs: args.sinceMs } : {}),
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const events: AuditEvent[] = [];
|
|
134
|
+
let offset = 0;
|
|
135
|
+
while (events.length < cap) {
|
|
136
|
+
const pageLimit = Math.min(MAX_LIMIT, cap - events.length);
|
|
137
|
+
const page = await queryAuditEvents(scope, {
|
|
138
|
+
...filters,
|
|
139
|
+
limit: pageLimit,
|
|
140
|
+
offset,
|
|
141
|
+
});
|
|
142
|
+
events.push(...page);
|
|
143
|
+
offset += page.length;
|
|
144
|
+
if (page.length < pageLimit) break; // exhausted — no more matching rows
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// We stopped because we hit the cap, not because we ran out of rows —
|
|
148
|
+
// probe one more row to know whether the export was actually truncated.
|
|
149
|
+
let truncated = false;
|
|
150
|
+
if (events.length >= cap) {
|
|
151
|
+
const probe = await queryAuditEvents(scope, {
|
|
152
|
+
...filters,
|
|
153
|
+
limit: 1,
|
|
154
|
+
offset,
|
|
155
|
+
});
|
|
156
|
+
truncated = probe.length > 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const content = args.format === "ndjson" ? toNdjson(events) : toCsv(events);
|
|
160
|
+
return { content, rowCount: events.length, truncated, format: args.format };
|
|
161
|
+
},
|
|
162
|
+
});
|
|
@@ -250,7 +250,9 @@ function scopeClause(scope: AuditReadScope): { sql: string; args: any[] } {
|
|
|
250
250
|
return { sql: `(${clauses.join(" OR ")})`, args };
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
|
|
253
|
+
// Exported so callers that must page past a single call (e.g.
|
|
254
|
+
// `export-audit-events`) can mirror the clamp instead of guessing it.
|
|
255
|
+
export const MAX_LIMIT = 500;
|
|
254
256
|
const DEFAULT_LIMIT = 100;
|
|
255
257
|
|
|
256
258
|
// Columns returned by the list surface — deliberately EXCLUDES `input` so a
|
|
@@ -297,13 +299,16 @@ export async function queryAuditEvents(
|
|
|
297
299
|
Math.max(1, Math.floor(filters.limit ?? DEFAULT_LIMIT)),
|
|
298
300
|
MAX_LIMIT,
|
|
299
301
|
);
|
|
302
|
+
// 0-based, default-compatible: existing callers that never pass `offset`
|
|
303
|
+
// keep selecting from the top of the ordered result set.
|
|
304
|
+
const offset = Math.max(0, Math.floor(filters.offset ?? 0));
|
|
300
305
|
|
|
301
306
|
const result = await client.execute({
|
|
302
307
|
sql: `SELECT ${LIST_COLUMNS} FROM agent_audit_log
|
|
303
308
|
WHERE ${where.join(" AND ")}
|
|
304
309
|
ORDER BY created_at DESC
|
|
305
|
-
LIMIT ?`,
|
|
306
|
-
args: [...args, limit],
|
|
310
|
+
LIMIT ? OFFSET ?`,
|
|
311
|
+
args: [...args, limit, offset],
|
|
307
312
|
});
|
|
308
313
|
return (result.rows ?? []).map(mapRow);
|
|
309
314
|
}
|
|
@@ -135,4 +135,7 @@ export interface AuditQueryFilters {
|
|
|
135
135
|
sourcePlatform?: string;
|
|
136
136
|
sinceMs?: number;
|
|
137
137
|
limit?: number;
|
|
138
|
+
/** Skip this many matching rows before applying `limit` (0-based). Used by
|
|
139
|
+
* `export-audit-events` to page past the per-call `MAX_LIMIT` clamp. */
|
|
140
|
+
offset?: number;
|
|
138
141
|
}
|
|
@@ -639,6 +639,14 @@ export interface ListThreadsOptions {
|
|
|
639
639
|
/** When true, returns only threads with no scope (general chats). */
|
|
640
640
|
unscopedOnly?: boolean;
|
|
641
641
|
orgId?: string | null;
|
|
642
|
+
/**
|
|
643
|
+
* Include archived threads in the results. Defaults to false: archived
|
|
644
|
+
* threads (`archived_at` set via `setThreadArchived`) are hidden from the
|
|
645
|
+
* ordinary chat list/search so archiving actually removes a thread from
|
|
646
|
+
* view. Pass true for surfaces that explicitly need to see archived chats
|
|
647
|
+
* (e.g. an "Archived" filter or restoring one via `setThreadArchived`).
|
|
648
|
+
*/
|
|
649
|
+
includeArchived?: boolean;
|
|
642
650
|
}
|
|
643
651
|
|
|
644
652
|
function chatThreadAccessSql(
|
|
@@ -686,6 +694,9 @@ export async function listThreads(
|
|
|
686
694
|
);
|
|
687
695
|
const filters: string[] = [access.sql, `message_count > 0`];
|
|
688
696
|
const args: (string | number)[] = [...access.args];
|
|
697
|
+
if (!opts.includeArchived) {
|
|
698
|
+
filters.push(`archived_at IS NULL`);
|
|
699
|
+
}
|
|
689
700
|
if (opts.scope) {
|
|
690
701
|
filters.push(`scope_type = ? AND scope_id = ?`);
|
|
691
702
|
args.push(opts.scope.type, opts.scope.id);
|
|
@@ -710,7 +721,12 @@ export async function searchThreads(
|
|
|
710
721
|
ownerEmail: string,
|
|
711
722
|
query: string,
|
|
712
723
|
limit = 50,
|
|
713
|
-
options: {
|
|
724
|
+
options: {
|
|
725
|
+
scope?: { type: string; id: string };
|
|
726
|
+
orgId?: string | null;
|
|
727
|
+
/** See `ListThreadsOptions.includeArchived` — defaults to false. */
|
|
728
|
+
includeArchived?: boolean;
|
|
729
|
+
} = {},
|
|
714
730
|
): Promise<ChatThreadSummary[]> {
|
|
715
731
|
await ensureTable();
|
|
716
732
|
const client = getDbExec();
|
|
@@ -728,6 +744,9 @@ export async function searchThreads(
|
|
|
728
744
|
`(title LIKE ? ESCAPE '!' OR preview LIKE ? ESCAPE '!' OR thread_data LIKE ? ESCAPE '!')`,
|
|
729
745
|
];
|
|
730
746
|
const args: (string | number)[] = [...access.args, pattern, pattern, pattern];
|
|
747
|
+
if (!options.includeArchived) {
|
|
748
|
+
filters.push(`archived_at IS NULL`);
|
|
749
|
+
}
|
|
731
750
|
if (options.scope) {
|
|
732
751
|
filters.push(`scope_type = ? AND scope_id = ?`);
|
|
733
752
|
args.push(options.scope.type, options.scope.id);
|
|
@@ -215,6 +215,7 @@ export async function executeCodeAgentRun(
|
|
|
215
215
|
runId: existing.id,
|
|
216
216
|
kind: "status",
|
|
217
217
|
message,
|
|
218
|
+
signal: "credential-gap",
|
|
218
219
|
metadata: { status: "paused", phase: "missing-credentials" },
|
|
219
220
|
});
|
|
220
221
|
return updateCodeAgentRunRecord(existing.id, {
|
|
@@ -77,6 +77,17 @@ export type CodeAgentTranscriptEventKind =
|
|
|
77
77
|
| "artifact"
|
|
78
78
|
| "status";
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Structured, machine-checkable marker for transcript events that need
|
|
82
|
+
* special handling in the UI beyond free-text matching. `"credential-gap"`
|
|
83
|
+
* marks the status event the executor appends when no LLM provider key (or
|
|
84
|
+
* Codex CLI login) is available; consumers should prefer this field over
|
|
85
|
+
* regex-matching `message` (see `isCredentialGapCodeAgentEvent` in
|
|
86
|
+
* `../code-agents/transcript-normalizer.js`). Optional so older, already
|
|
87
|
+
* persisted JSONL transcripts without the field keep parsing unchanged.
|
|
88
|
+
*/
|
|
89
|
+
export type CodeAgentTranscriptEventSignal = "credential-gap";
|
|
90
|
+
|
|
80
91
|
export interface CodeAgentTranscriptEvent {
|
|
81
92
|
schemaVersion: 1;
|
|
82
93
|
id: string;
|
|
@@ -85,6 +96,7 @@ export interface CodeAgentTranscriptEvent {
|
|
|
85
96
|
message: string;
|
|
86
97
|
createdAt: string;
|
|
87
98
|
metadata?: Record<string, unknown>;
|
|
99
|
+
signal?: CodeAgentTranscriptEventSignal;
|
|
88
100
|
}
|
|
89
101
|
|
|
90
102
|
export interface CreateCodeAgentRunInput {
|
|
@@ -109,6 +121,7 @@ export interface AppendCodeAgentTranscriptEventInput {
|
|
|
109
121
|
message: string;
|
|
110
122
|
createdAt?: string;
|
|
111
123
|
metadata?: Record<string, unknown>;
|
|
124
|
+
signal?: CodeAgentTranscriptEventSignal;
|
|
112
125
|
}
|
|
113
126
|
|
|
114
127
|
export interface QueueCodeAgentFollowUpInput {
|
|
@@ -294,6 +307,7 @@ export function appendCodeAgentTranscriptEvent(
|
|
|
294
307
|
message: input.message,
|
|
295
308
|
createdAt,
|
|
296
309
|
metadata: input.metadata,
|
|
310
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
297
311
|
};
|
|
298
312
|
|
|
299
313
|
fs.mkdirSync(codeAgentTranscriptsDir(), { recursive: true });
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agent-native doctor` — scan an app's source tree for the security-
|
|
3
|
+
* critical code-safety invariants this monorepo already enforces on
|
|
4
|
+
* itself via `scripts/guard-*.mjs` (see
|
|
5
|
+
* `advisor-plans/reports/005-doctor-design.md` for the full design and
|
|
6
|
+
* `advisor-plans/015-doctor-v1-implementation.md` for the implementation
|
|
7
|
+
* plan). v1 ships 7 of those guards, ported to work against a single
|
|
8
|
+
* generated app root instead of this monorepo's multi-template layout —
|
|
9
|
+
* see `../guards/index.ts`.
|
|
10
|
+
*
|
|
11
|
+
* This is a NEW top-level command, deliberately kept separate from the two
|
|
12
|
+
* existing "doctor" precedents in this CLI:
|
|
13
|
+
* - `agent-native upgrade check` (`upgrade.ts`) — dependency-pin health.
|
|
14
|
+
* - `agent-native recap doctor` (`recap.ts`) — PR Visual Recap config health.
|
|
15
|
+
* Each diagnoses a different domain; none are folded into a shared
|
|
16
|
+
* mega-doctor (see report 005, "Relationship to upgrade doctor and recap
|
|
17
|
+
* doctor").
|
|
18
|
+
*
|
|
19
|
+
* `--fix` is reserved, not implemented in v1 — it prints a message and
|
|
20
|
+
* exits 2 rather than silently no-op, so a future implementation doesn't
|
|
21
|
+
* collide with a script already passing the flag.
|
|
22
|
+
*/
|
|
23
|
+
import fs from "node:fs";
|
|
24
|
+
import path from "node:path";
|
|
25
|
+
|
|
26
|
+
import {
|
|
27
|
+
scanDbToolScoping,
|
|
28
|
+
scanDrizzlePush,
|
|
29
|
+
scanEnvCredentials,
|
|
30
|
+
scanEnvMutation,
|
|
31
|
+
scanLocalhostFallback,
|
|
32
|
+
scanUnscopedCredentials,
|
|
33
|
+
scanUnscopedQueries,
|
|
34
|
+
} from "../guards/index.js";
|
|
35
|
+
import type { GuardResult } from "../guards/index.js";
|
|
36
|
+
|
|
37
|
+
export type GuardName =
|
|
38
|
+
| "no-drizzle-push"
|
|
39
|
+
| "no-unscoped-credentials"
|
|
40
|
+
| "no-unscoped-queries"
|
|
41
|
+
| "no-env-credentials"
|
|
42
|
+
| "db-tool-scoping"
|
|
43
|
+
| "no-env-mutation"
|
|
44
|
+
| "no-localhost-fallback";
|
|
45
|
+
|
|
46
|
+
export const ALL_GUARD_NAMES: GuardName[] = [
|
|
47
|
+
"no-drizzle-push",
|
|
48
|
+
"no-unscoped-credentials",
|
|
49
|
+
"no-unscoped-queries",
|
|
50
|
+
"no-env-credentials",
|
|
51
|
+
"db-tool-scoping",
|
|
52
|
+
"no-env-mutation",
|
|
53
|
+
"no-localhost-fallback",
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
export interface DoctorConfig {
|
|
57
|
+
disabledGuards: string[];
|
|
58
|
+
dbToolScopingDenylist: Record<string, string>;
|
|
59
|
+
failOnBuild: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const DEFAULT_DOCTOR_CONFIG: DoctorConfig = {
|
|
63
|
+
disabledGuards: [],
|
|
64
|
+
dbToolScopingDenylist: {},
|
|
65
|
+
failOnBuild: false,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export interface DoctorFinding {
|
|
69
|
+
guard: string;
|
|
70
|
+
file: string;
|
|
71
|
+
line: number;
|
|
72
|
+
message: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface DoctorReport {
|
|
76
|
+
ok: boolean;
|
|
77
|
+
findings: DoctorFinding[];
|
|
78
|
+
guardsRun: string[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Reads the optional `"doctor"` key from `<root>/agent-native.json`. All
|
|
83
|
+
* fields are optional with sane empty defaults — an app needs zero config
|
|
84
|
+
* to run `agent-native doctor` with every v1 guard enabled.
|
|
85
|
+
*/
|
|
86
|
+
export function readDoctorConfig(root: string): DoctorConfig {
|
|
87
|
+
const manifestPath = path.join(root, "agent-native.json");
|
|
88
|
+
if (!fs.existsSync(manifestPath)) {
|
|
89
|
+
return { ...DEFAULT_DOCTOR_CONFIG, dbToolScopingDenylist: {} };
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const raw = fs.readFileSync(manifestPath, "utf-8");
|
|
93
|
+
const parsed = JSON.parse(raw) as { doctor?: Record<string, unknown> };
|
|
94
|
+
const doctor = parsed.doctor ?? {};
|
|
95
|
+
const disabledGuards = Array.isArray(doctor.disabledGuards)
|
|
96
|
+
? doctor.disabledGuards.filter((v): v is string => typeof v === "string")
|
|
97
|
+
: [];
|
|
98
|
+
const dbToolScopingDenylist =
|
|
99
|
+
doctor.dbToolScopingDenylist &&
|
|
100
|
+
typeof doctor.dbToolScopingDenylist === "object"
|
|
101
|
+
? (Object.fromEntries(
|
|
102
|
+
Object.entries(
|
|
103
|
+
doctor.dbToolScopingDenylist as Record<string, unknown>,
|
|
104
|
+
).filter(
|
|
105
|
+
(entry): entry is [string, string] =>
|
|
106
|
+
typeof entry[1] === "string",
|
|
107
|
+
),
|
|
108
|
+
) as Record<string, string>)
|
|
109
|
+
: {};
|
|
110
|
+
const failOnBuild = doctor.failOnBuild === true;
|
|
111
|
+
return { disabledGuards, dbToolScopingDenylist, failOnBuild };
|
|
112
|
+
} catch {
|
|
113
|
+
return { ...DEFAULT_DOCTOR_CONFIG, dbToolScopingDenylist: {} };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function runGuard(
|
|
118
|
+
name: GuardName,
|
|
119
|
+
root: string,
|
|
120
|
+
config: DoctorConfig,
|
|
121
|
+
): GuardResult {
|
|
122
|
+
switch (name) {
|
|
123
|
+
case "no-drizzle-push":
|
|
124
|
+
return scanDrizzlePush({ root });
|
|
125
|
+
case "no-unscoped-credentials":
|
|
126
|
+
return scanUnscopedCredentials({ root });
|
|
127
|
+
case "no-unscoped-queries":
|
|
128
|
+
return scanUnscopedQueries({ root, extraExemptPaths: [] });
|
|
129
|
+
case "no-env-credentials":
|
|
130
|
+
return scanEnvCredentials({ root });
|
|
131
|
+
case "db-tool-scoping":
|
|
132
|
+
return scanDbToolScoping({
|
|
133
|
+
root,
|
|
134
|
+
denylist: config.dbToolScopingDenylist,
|
|
135
|
+
});
|
|
136
|
+
case "no-env-mutation":
|
|
137
|
+
return scanEnvMutation({ root });
|
|
138
|
+
case "no-localhost-fallback":
|
|
139
|
+
return scanLocalhostFallback({ root, extraExemptPaths: [] });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface RunDoctorScanOptions {
|
|
144
|
+
root: string;
|
|
145
|
+
/** Restrict to these guard names. When omitted, runs every guard not
|
|
146
|
+
* listed in `agent-native.json`'s `doctor.disabledGuards`. Unknown names
|
|
147
|
+
* are silently ignored here — the CLI layer (`runDoctor`) validates
|
|
148
|
+
* `--only` and reports a usage error before calling this. */
|
|
149
|
+
only?: string[];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Pure scan orchestrator: runs the selected guards against `root` and
|
|
153
|
+
* returns a flat report. No I/O beyond reading `agent-native.json` and the
|
|
154
|
+
* app source tree — no printing, no process.exit. */
|
|
155
|
+
export function runDoctorScan(options: RunDoctorScanOptions): DoctorReport {
|
|
156
|
+
const root = options.root;
|
|
157
|
+
const config = readDoctorConfig(root);
|
|
158
|
+
|
|
159
|
+
let names: GuardName[];
|
|
160
|
+
if (options.only && options.only.length > 0) {
|
|
161
|
+
const knownOnly = options.only.filter((n): n is GuardName =>
|
|
162
|
+
(ALL_GUARD_NAMES as string[]).includes(n),
|
|
163
|
+
);
|
|
164
|
+
names = knownOnly;
|
|
165
|
+
} else {
|
|
166
|
+
names = ALL_GUARD_NAMES.filter((n) => !config.disabledGuards.includes(n));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const findings: DoctorFinding[] = [];
|
|
170
|
+
for (const name of names) {
|
|
171
|
+
const result = runGuard(name, root, config);
|
|
172
|
+
for (const f of result.findings) {
|
|
173
|
+
findings.push({
|
|
174
|
+
guard: name,
|
|
175
|
+
file: f.file,
|
|
176
|
+
line: f.line,
|
|
177
|
+
message: f.message,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return { ok: findings.length === 0, findings, guardsRun: names };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Pure escalation rule shared by the CLI (`--strict`) and the `build`
|
|
186
|
+
* pre-step (`--strict` / `agent-native.json` `doctor.failOnBuild`). Doctor
|
|
187
|
+
* findings never fail anything on their own — only `strict` or
|
|
188
|
+
* `failOnBuild` turn findings into a hard failure. */
|
|
189
|
+
export function shouldFailBuild(
|
|
190
|
+
hasFindings: boolean,
|
|
191
|
+
opts: { strict?: boolean; failOnBuild?: boolean },
|
|
192
|
+
): boolean {
|
|
193
|
+
return hasFindings && Boolean(opts.strict || opts.failOnBuild);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export interface DoctorIo {
|
|
197
|
+
log: (message: string) => void;
|
|
198
|
+
err: (message: string) => void;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const defaultIo: DoctorIo = {
|
|
202
|
+
log: (message) => console.log(message),
|
|
203
|
+
err: (message) => console.error(message),
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
function formatDoctorHuman(report: DoctorReport, root: string): string {
|
|
207
|
+
const lines: string[] = [];
|
|
208
|
+
lines.push(`agent-native doctor: ${root}`);
|
|
209
|
+
lines.push(`Guards run: ${report.guardsRun.join(", ") || "(none)"}`);
|
|
210
|
+
if (report.findings.length === 0) {
|
|
211
|
+
lines.push("Clean — no findings.");
|
|
212
|
+
} else {
|
|
213
|
+
lines.push(`${report.findings.length} finding(s):`);
|
|
214
|
+
for (const f of report.findings) {
|
|
215
|
+
lines.push(` [${f.guard}] ${f.file}:${f.line} — ${f.message}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return lines.join("\n");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface DoctorCliOptions {
|
|
222
|
+
json?: boolean;
|
|
223
|
+
cwd?: string;
|
|
224
|
+
only?: string[];
|
|
225
|
+
strict?: boolean;
|
|
226
|
+
help?: boolean;
|
|
227
|
+
fix?: boolean;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function parseDoctorArgs(argv: string[]): DoctorCliOptions {
|
|
231
|
+
const opts: DoctorCliOptions = {};
|
|
232
|
+
for (let i = 0; i < argv.length; i++) {
|
|
233
|
+
const arg = argv[i];
|
|
234
|
+
if (arg === "--help" || arg === "-h") {
|
|
235
|
+
opts.help = true;
|
|
236
|
+
} else if (arg === "--json") {
|
|
237
|
+
opts.json = true;
|
|
238
|
+
} else if (arg === "--strict") {
|
|
239
|
+
opts.strict = true;
|
|
240
|
+
} else if (arg === "--fix") {
|
|
241
|
+
opts.fix = true;
|
|
242
|
+
} else if (arg === "--cwd" && argv[i + 1] !== undefined) {
|
|
243
|
+
opts.cwd = argv[++i];
|
|
244
|
+
} else if (arg.startsWith("--cwd=")) {
|
|
245
|
+
opts.cwd = arg.slice("--cwd=".length);
|
|
246
|
+
} else if (arg === "--only" && argv[i + 1] !== undefined) {
|
|
247
|
+
opts.only = splitGuardList(argv[++i]);
|
|
248
|
+
} else if (arg.startsWith("--only=")) {
|
|
249
|
+
opts.only = splitGuardList(arg.slice("--only=".length));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return opts;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function splitGuardList(value: string): string[] {
|
|
256
|
+
return value
|
|
257
|
+
.split(",")
|
|
258
|
+
.map((s) => s.trim())
|
|
259
|
+
.filter((s) => s.length > 0);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function printDoctorHelp(io: Pick<DoctorIo, "log"> = defaultIo): void {
|
|
263
|
+
io.log(
|
|
264
|
+
[
|
|
265
|
+
"Usage:",
|
|
266
|
+
" agent-native doctor Scan app source for security-critical guard violations",
|
|
267
|
+
" agent-native doctor --json Machine-readable report: { ok, findings, guardsRun }",
|
|
268
|
+
" agent-native doctor --only <guard,guard> Run only the named guard(s)",
|
|
269
|
+
" agent-native doctor --strict Escalate findings to a hard failure when used by `agent-native build --strict`",
|
|
270
|
+
" agent-native doctor --cwd <dir> Run against a project root other than the current directory",
|
|
271
|
+
" agent-native doctor --fix Not implemented in this version",
|
|
272
|
+
" agent-native doctor --help Show this help",
|
|
273
|
+
"",
|
|
274
|
+
`Guards: ${ALL_GUARD_NAMES.join(", ")}`,
|
|
275
|
+
"",
|
|
276
|
+
"Exit codes: 0 clean, 1 findings present, 2 usage/execution error.",
|
|
277
|
+
"",
|
|
278
|
+
"`agent-native build` runs doctor as a warn-only pre-step by default — it",
|
|
279
|
+
"never fails the build unless `agent-native build --strict` is passed or",
|
|
280
|
+
'agent-native.json sets { "doctor": { "failOnBuild": true } }.',
|
|
281
|
+
"",
|
|
282
|
+
"For dependency-pin health (framework overrides/patches, stale",
|
|
283
|
+
"@agent-native/* pins), run `agent-native upgrade check` instead.",
|
|
284
|
+
].join("\n"),
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** `agent-native doctor` CLI entrypoint. Returns the process exit code —
|
|
289
|
+
* callers are responsible for calling `process.exit(code)`. */
|
|
290
|
+
export async function runDoctor(
|
|
291
|
+
argv: string[],
|
|
292
|
+
io: DoctorIo = defaultIo,
|
|
293
|
+
): Promise<number> {
|
|
294
|
+
const opts = parseDoctorArgs(argv);
|
|
295
|
+
|
|
296
|
+
if (opts.help) {
|
|
297
|
+
printDoctorHelp(io);
|
|
298
|
+
return 0;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (opts.fix) {
|
|
302
|
+
io.err(
|
|
303
|
+
"agent-native doctor --fix is not implemented in this version. Fix findings manually and re-run `agent-native doctor`.",
|
|
304
|
+
);
|
|
305
|
+
return 2;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const root = path.resolve(opts.cwd ?? process.cwd());
|
|
309
|
+
if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) {
|
|
310
|
+
const message = `--cwd path does not exist or is not a directory: ${root}`;
|
|
311
|
+
if (opts.json) io.err(JSON.stringify({ ok: false, message }, null, 2));
|
|
312
|
+
else io.err(message);
|
|
313
|
+
return 2;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (opts.only) {
|
|
317
|
+
const unknown = opts.only.filter(
|
|
318
|
+
(n) => !(ALL_GUARD_NAMES as string[]).includes(n),
|
|
319
|
+
);
|
|
320
|
+
if (unknown.length > 0) {
|
|
321
|
+
const message = `Unknown guard name(s) in --only: ${unknown.join(", ")}. Known guards: ${ALL_GUARD_NAMES.join(", ")}`;
|
|
322
|
+
if (opts.json) io.err(JSON.stringify({ ok: false, message }, null, 2));
|
|
323
|
+
else io.err(message);
|
|
324
|
+
return 2;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const report = runDoctorScan({ root, only: opts.only });
|
|
329
|
+
|
|
330
|
+
if (opts.json) {
|
|
331
|
+
const sink = report.ok ? io.log : io.err;
|
|
332
|
+
sink(JSON.stringify({ ...report, strict: Boolean(opts.strict) }, null, 2));
|
|
333
|
+
} else {
|
|
334
|
+
io.log(formatDoctorHuman(report, root));
|
|
335
|
+
if (!report.ok) {
|
|
336
|
+
io.err("");
|
|
337
|
+
io.err(
|
|
338
|
+
"agent-native doctor found issues above. Fix them, or add a `// guard:allow-<check> — reason` opt-out with reviewer approval.",
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return report.ok ? 0 : 1;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export interface DoctorBuildHookOptions {
|
|
347
|
+
cwd: string;
|
|
348
|
+
/** Set when the caller passed `agent-native build --strict`. */
|
|
349
|
+
strict?: boolean;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export interface DoctorBuildHookResult {
|
|
353
|
+
/** False only when findings are present AND (`strict` was requested OR
|
|
354
|
+
* `agent-native.json`'s `doctor.failOnBuild` is true). */
|
|
355
|
+
ok: boolean;
|
|
356
|
+
report: DoctorReport;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* `agent-native build`'s doctor pre-step. Always runs every enabled guard
|
|
361
|
+
* and always prints findings (as warnings) to `io.err` — never silent.
|
|
362
|
+
* Never causes the build to fail unless `strict` was passed or
|
|
363
|
+
* `agent-native.json` sets `doctor.failOnBuild: true` (see report 005,
|
|
364
|
+
* "Where it runs" — the v1 doctor has zero field mileage against arbitrary
|
|
365
|
+
* app layouts, so shipping fail-by-default would risk breaking a first
|
|
366
|
+
* deploy on a false positive).
|
|
367
|
+
*/
|
|
368
|
+
export async function runDoctorBuildHook(
|
|
369
|
+
options: DoctorBuildHookOptions,
|
|
370
|
+
io: DoctorIo = defaultIo,
|
|
371
|
+
): Promise<DoctorBuildHookResult> {
|
|
372
|
+
const root = path.resolve(options.cwd);
|
|
373
|
+
const config = readDoctorConfig(root);
|
|
374
|
+
const report = runDoctorScan({ root });
|
|
375
|
+
|
|
376
|
+
if (report.findings.length > 0) {
|
|
377
|
+
io.err(
|
|
378
|
+
`\n[doctor] ${report.findings.length} finding(s) from \`agent-native doctor\` — run it directly for details. This does not fail the build unless --strict was passed or agent-native.json's doctor.failOnBuild is true.`,
|
|
379
|
+
);
|
|
380
|
+
for (const f of report.findings) {
|
|
381
|
+
io.err(` [${f.guard}] ${f.file}:${f.line} — ${f.message}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const fail = shouldFailBuild(report.findings.length > 0, {
|
|
386
|
+
strict: options.strict,
|
|
387
|
+
failOnBuild: config.failOnBuild,
|
|
388
|
+
});
|
|
389
|
+
if (fail) {
|
|
390
|
+
io.err(
|
|
391
|
+
`\n[doctor] Failing build: ${options.strict ? "--strict was passed" : "agent-native.json's doctor.failOnBuild is true"}.`,
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return { ok: !fail, report };
|
|
396
|
+
}
|