@agent-native/core 0.146.8 → 0.148.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/analytics/DEVELOPING.md +50 -3
- package/corpus/templates/analytics/actions/purge-first-party-analytics-postgres.ts +190 -0
- package/corpus/templates/analytics/app/i18n/index.ts +14 -29
- package/corpus/templates/analytics/app/i18n-data.ts +10 -10
- package/corpus/templates/analytics/app/pages/Settings.tsx +5 -21
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -3
- package/corpus/templates/analytics/app/routes/status.$slug.tsx +4 -2
- package/corpus/templates/analytics/scripts/first-party-analytics-bigquery-backfill.ts +253 -24
- package/corpus/templates/analytics/server/db/schema.ts +23 -0
- package/corpus/templates/analytics/server/handlers/first-party-analytics.ts +3 -1
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +1 -1
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +113 -13
- package/corpus/templates/analytics/server/lib/first-party-analytics-purge.ts +140 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-volume.ts +207 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +40 -9
- package/corpus/templates/analytics/server/lib/gcloud.ts +148 -20
- package/corpus/templates/analytics/server/plugins/db.ts +42 -0
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/assets/app/i18n/index.ts +14 -29
- package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/brain/app/i18n/index.ts +14 -29
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/chat/app/i18n/index.ts +14 -29
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +2 -7
- package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +18 -13
- package/corpus/templates/clips/app/components/settings/ai-setup-section.tsx +87 -370
- package/corpus/templates/clips/app/components/settings/slack-section.tsx +59 -101
- package/corpus/templates/clips/app/components/settings/video-storage-section.tsx +136 -213
- package/corpus/templates/clips/app/i18n/en-US.ts +11 -8
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +16 -4
- package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +14 -5
- package/corpus/templates/clips/desktop/src/app.tsx +1 -1
- package/corpus/templates/clips/package.json +1 -0
- package/corpus/templates/clips/react-router.config.ts +7 -0
- package/corpus/templates/clips/server/plugins/auth.ts +6 -1
- package/corpus/templates/clips/shared/prerendered-public-paths.ts +21 -0
- package/corpus/templates/clips/shared/share-meta.ts +8 -3
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/content/app/i18n/index.ts +14 -29
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/crm/app/i18n/index.ts +14 -29
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/design/actions/analyze-brand-assets.ts +15 -15
- package/corpus/templates/design/actions/import-code.ts +2 -43
- package/corpus/templates/design/app/i18n/index.ts +14 -29
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/dispatch/app/chat-first-pages.ts +747 -0
- package/corpus/templates/dispatch/app/i18n-data.ts +182 -1
- package/corpus/templates/dispatch/app/routes/settings.tsx +62 -1
- package/corpus/templates/dispatch/changelog/2026-08-08-chat-first-navigation-keeps-conversations-central-while-open.md +6 -0
- package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/factory/AGENTS.md +40 -49
- package/corpus/templates/factory/actions/babysit-agent-native-pull-request.ts +66 -0
- package/corpus/templates/factory/actions/evaluate-triage-item.ts +37 -0
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +20 -0
- package/corpus/templates/factory/actions/get-triage-item.ts +25 -4
- package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +55 -0
- package/corpus/templates/factory/actions/ingest-github-observation.ts +21 -0
- package/corpus/templates/factory/actions/list-factory-audit.ts +118 -0
- package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
- package/corpus/templates/factory/actions/list-triage-items.ts +24 -2
- package/corpus/templates/factory/actions/poll-github-sources.ts +60 -0
- package/corpus/templates/factory/actions/poll-sentry-errors.ts +39 -0
- package/corpus/templates/factory/actions/poll-slack-channel.ts +45 -1
- package/corpus/templates/factory/actions/run-factory-automation.ts +1 -1
- package/corpus/templates/factory/actions/save-factory-automation.ts +2 -2
- package/corpus/templates/factory/actions/start-builder-for-item.ts +51 -0
- package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +685 -0
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +6 -0
- package/corpus/templates/factory/app/i18n/en-US.ts +25 -0
- package/corpus/templates/factory/app/routes/factory.tsx +203 -118
- package/corpus/templates/factory/changelog/2026-08-08-scheduler-health-moves-to-settings.md +6 -0
- package/corpus/templates/factory/server/db/schema.ts +37 -0
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +5 -1
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +29 -0
- package/corpus/templates/factory/server/triage/audit.ts +79 -0
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/forms/app/i18n/index.ts +14 -29
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/macros/app/i18n/index.ts +14 -29
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/mail/app/i18n/index.ts +14 -29
- package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +7 -7
- package/corpus/templates/plan/app/i18n/index.ts +14 -29
- package/corpus/templates/plan/app/lib/plan-document-title.ts +3 -1
- package/corpus/templates/plan/app/root.tsx +1 -0
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/slides/actions/analyze-brand-assets.ts +15 -15
- package/corpus/templates/slides/actions/import-code.ts +2 -43
- package/corpus/templates/slides/app/i18n/index.ts +14 -29
- package/corpus/templates/slides/server/routes/api/preview-images.get.ts +4 -1
- package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +115 -68
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/corpus/templates/tasks/app/components/layout/HeaderActions.tsx +1 -84
- package/corpus/templates/tasks/app/hooks/use-mobile.tsx +1 -21
- package/corpus/templates/tasks/app/i18n/index.ts +14 -29
- package/dist/agent/engine/ai-sdk-engine.js +2 -1
- package/dist/agent/engine/builder-engine.d.ts +11 -1
- package/dist/agent/engine/builder-engine.js +11 -4
- package/dist/agent/engine/openai-compatible-endpoint.d.ts +2 -0
- package/dist/agent/engine/openai-compatible-endpoint.js +5 -1
- package/dist/agent/engine/provider-endpoint-validation.d.ts +9 -0
- package/dist/agent/engine/provider-endpoint-validation.js +26 -0
- package/dist/agent/engine/provider-env-vars.d.ts +1 -1
- package/dist/agent/engine/provider-env-vars.js +1 -1
- package/dist/agent/engine/registry.d.ts +8 -6
- package/dist/agent/engine/registry.js +37 -24
- package/dist/agent/tool-search.d.ts +1 -0
- package/dist/agent/tool-search.js +17 -1
- package/dist/automations/service.js +4 -10
- package/dist/brand-kit/brand-signals.d.ts +13 -0
- package/dist/brand-kit/brand-signals.js +15 -0
- package/dist/brand-kit/index.d.ts +2 -2
- package/dist/brand-kit/index.js +1 -1
- package/dist/chat-threads/store.d.ts +2 -0
- package/dist/chat-threads/store.js +1 -1
- package/dist/cli/agent-plugin.d.ts +5 -2
- package/dist/cli/agent-plugin.js +17 -9
- package/dist/cli/code-agent-executor.js +25 -5
- package/dist/cli/code-agent-mcp-config.d.ts +21 -0
- package/dist/cli/code-agent-mcp-config.js +103 -0
- package/dist/cli/plan-blocks.d.ts +3 -18
- package/dist/cli/plan-blocks.js +2 -95
- package/dist/cli/plan-publish-store.d.ts +2 -61
- package/dist/cli/plan-publish-store.js +2 -127
- package/dist/cli/skills-content/connection.d.ts +1 -1
- package/dist/cli/skills-content/connection.js +1 -52
- package/dist/cli/skills-content/visual-recap-skill.d.ts +1 -1
- package/dist/cli/skills-content/visual-recap-skill.js +1 -553
- package/dist/client/NewWorkspaceAppFlow.js +4 -1
- package/dist/client/agent-chat/index.d.ts +4 -1
- package/dist/client/agent-chat/index.js +4 -1
- package/dist/client/agent-engine-key.d.ts +14 -4
- package/dist/client/agent-engine-key.js +51 -5
- package/dist/client/agent-page/AgentTabsPage.d.ts +1 -0
- package/dist/client/agent-page/AgentTabsPage.js +4 -3
- package/dist/client/agent-provider-catalog.d.ts +20 -0
- package/dist/client/agent-provider-catalog.js +100 -0
- package/dist/client/app-providers.d.ts +3 -1
- package/dist/client/app-providers.js +50 -5
- package/dist/client/blocks/index.d.ts +1 -0
- package/dist/client/blocks/index.js +1 -0
- package/dist/client/chat/run-recovery.js +4 -48
- package/dist/client/chat/runtime.js +63 -0
- package/dist/client/chat-first/agents-pane.d.ts +2 -0
- package/dist/client/chat-first/agents-pane.js +6 -0
- package/dist/client/chat-first/app-pane.d.ts +2 -0
- package/dist/client/chat-first/app-pane.js +6 -0
- package/dist/client/chat-first/apps-rail.d.ts +2 -0
- package/dist/client/chat-first/apps-rail.js +103 -0
- package/dist/client/chat-first/browser-pane.d.ts +2 -0
- package/dist/client/chat-first/browser-pane.js +64 -0
- package/dist/client/chat-first/chat-history.d.ts +12 -0
- package/dist/client/chat-first/chat-history.js +10 -0
- package/dist/client/chat-first/copy.d.ts +2 -0
- package/dist/client/chat-first/copy.js +117 -0
- package/dist/client/chat-first/index.d.ts +13 -0
- package/dist/client/chat-first/index.js +12 -0
- package/dist/client/chat-first/primary-nav.d.ts +8 -0
- package/dist/client/chat-first/primary-nav.js +6 -0
- package/dist/client/chat-first/session-watch-pane.d.ts +2 -0
- package/dist/client/chat-first/session-watch-pane.js +9 -0
- package/dist/client/chat-first/surface-panel.d.ts +9 -0
- package/dist/client/chat-first/surface-panel.js +9 -0
- package/dist/client/chat-first/surface-tabs.d.ts +9 -0
- package/dist/client/chat-first/surface-tabs.js +74 -0
- package/dist/client/chat-first/types.d.ts +74 -0
- package/dist/client/chat-first/types.js +1 -0
- package/dist/client/chat-first-agent-activity.d.ts +11 -0
- package/dist/client/chat-first-agent-activity.js +51 -0
- package/dist/client/chat-first-surface-panel-toggle.d.ts +5 -0
- package/dist/client/chat-first-surface-panel-toggle.js +6 -0
- package/dist/client/chat-first.d.ts +208 -0
- package/dist/client/chat-first.js +817 -0
- package/dist/client/extensions/ExtensionViewer.js +8 -1
- package/dist/client/i18n.d.ts +14 -0
- package/dist/client/i18n.js +18 -0
- package/dist/client/resources/McpIntegrationDialog.js +3 -2
- package/dist/client/resources/McpServerDetail.js +6 -11
- package/dist/client/resources/index.d.ts +1 -0
- package/dist/client/resources/index.js +1 -0
- package/dist/client/resources/use-mcp-servers.d.ts +20 -0
- package/dist/client/resources/use-mcp-servers.js +82 -46
- package/dist/client/settings/ProviderSetupForm.d.ts +21 -0
- package/dist/client/settings/ProviderSetupForm.js +145 -0
- package/dist/client/settings/SettingsPanel.js +52 -49
- package/dist/client/settings/index.d.ts +3 -0
- package/dist/client/settings/index.js +3 -0
- package/dist/coding-tools/run-code.d.ts +5 -0
- package/dist/coding-tools/run-code.js +196 -36
- package/dist/coding-tools/tool-orchestration.d.ts +10 -0
- package/dist/coding-tools/tool-orchestration.js +107 -0
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/jobs/background-automation-runner.js +19 -2
- package/dist/jobs/frontmatter.d.ts +9 -0
- package/dist/jobs/frontmatter.js +16 -0
- package/dist/jobs/scheduler-health.d.ts +20 -0
- package/dist/jobs/scheduler-health.js +86 -1
- package/dist/jobs/scheduler.js +46 -9
- package/dist/jobs/tools.d.ts +1 -1
- package/dist/jobs/tools.js +2 -7
- package/dist/localization/default-messages.d.ts +20 -0
- package/dist/localization/default-messages.js +25 -5
- package/dist/mcp-client/routes.d.ts +3 -0
- package/dist/mcp-client/routes.js +14 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/onboarding/app-profile.js +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/scripts/agent-engines/test-agent-engine.js +34 -10
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-chat/run-code-tools.d.ts +1 -1
- package/dist/server/agent-chat/run-code-tools.js +3 -1
- package/dist/server/agent-chat-plugin.js +6 -6
- package/dist/server/agent-engine-api-key-route.js +43 -12
- package/dist/server/agents-bundle.d.ts +2 -0
- package/dist/server/agents-bundle.js +32 -2
- package/dist/server/auth.js +21 -5
- package/dist/server/credential-provider.d.ts +8 -2
- package/dist/server/credential-provider.js +14 -9
- package/dist/server/design-token-utils.d.ts +18 -0
- package/dist/server/design-token-utils.js +31 -0
- package/dist/server/onboarding-html.js +22 -2
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/chat-first-app-creation.d.ts +19 -0
- package/dist/shared/chat-first-app-creation.js +75 -0
- package/dist/shared/document-title.d.ts +7 -0
- package/dist/shared/document-title.js +29 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/styles/chat-history-list.css +16 -0
- package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +115 -68
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/dist/templates/chat/app/i18n/index.ts +14 -29
- package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +115 -68
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/dist/templates/default/app/i18n/index.ts +14 -29
- package/dist/templates/default/react-router.config.ts +18 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +22 -9
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +115 -68
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -0
- package/dist/triggers/dispatcher.js +1 -8
- package/docs/content/environment-variables.mdx +39 -38
- package/package.json +5 -4
- package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +115 -68
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/src/templates/chat/app/i18n/index.ts +14 -29
- package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +115 -68
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/src/templates/default/app/i18n/index.ts +14 -29
- package/src/templates/default/react-router.config.ts +18 -0
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +9 -0
- package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +22 -9
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +115 -68
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -6
- package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
- package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -0
- package/corpus/templates/plan/app/components/plan/wireframe/sanitize-html.ts +0 -343
|
@@ -154,6 +154,31 @@ const messages = {
|
|
|
154
154
|
metricRuns: "Runs",
|
|
155
155
|
rulesTab: "Rules",
|
|
156
156
|
automationsTab: "Automations",
|
|
157
|
+
auditTab: "Audit",
|
|
158
|
+
auditTitle: "Run audit",
|
|
159
|
+
auditDescription:
|
|
160
|
+
"See exactly which sources the agent inspected, what it decided, and which actions it took.",
|
|
161
|
+
auditRefresh: "Refresh",
|
|
162
|
+
auditLoadError: "Could not load the run audit.",
|
|
163
|
+
auditEmpty: "No automation runs have been recorded yet.",
|
|
164
|
+
auditRuns: "Recent runs",
|
|
165
|
+
auditEventsShort: "events",
|
|
166
|
+
auditActionsShort: "actions",
|
|
167
|
+
auditRunDetail: "Evidence and decisions recorded for this run.",
|
|
168
|
+
auditStarted: "Started",
|
|
169
|
+
auditFinished: "Finished",
|
|
170
|
+
auditItems: "Items",
|
|
171
|
+
auditRunError: "Run error",
|
|
172
|
+
auditEvidence: "Evidence and decisions",
|
|
173
|
+
auditNoEvents:
|
|
174
|
+
"No item-level audit events were recorded. Open the agent thread for the full trace.",
|
|
175
|
+
auditOpenThread: "Open thread",
|
|
176
|
+
auditOpenItem: "Open item",
|
|
177
|
+
auditOpenSource: "Open source",
|
|
178
|
+
auditInternal: "Factory",
|
|
179
|
+
auditClearBug: "Clear bug",
|
|
180
|
+
auditUxImpact: "UX impact",
|
|
181
|
+
auditOwnerArea: "Owner area",
|
|
157
182
|
automationsTitle: "Automations",
|
|
158
183
|
automationsDescription: "Schedule and run Factory prompts.",
|
|
159
184
|
automationsLoading: "Loading automations...",
|
|
@@ -10,10 +10,12 @@ import {
|
|
|
10
10
|
IconLoader2,
|
|
11
11
|
IconPlayerPlay,
|
|
12
12
|
IconPlus,
|
|
13
|
+
IconRefresh,
|
|
13
14
|
} from "@tabler/icons-react";
|
|
14
15
|
import { useEffect, useMemo, useState } from "react";
|
|
15
16
|
import { useSearchParams } from "react-router";
|
|
16
17
|
|
|
18
|
+
import { FactoryAuditView } from "@/components/factory/FactoryAuditView";
|
|
17
19
|
import {
|
|
18
20
|
FactoryCanvas,
|
|
19
21
|
type FactoryCanvasEdge,
|
|
@@ -111,7 +113,13 @@ type TriageConfig = {
|
|
|
111
113
|
};
|
|
112
114
|
|
|
113
115
|
type Verdict = "correct" | "incorrect" | "uncertain";
|
|
114
|
-
type WorkspaceTab =
|
|
116
|
+
type WorkspaceTab =
|
|
117
|
+
| "map"
|
|
118
|
+
| "inbox"
|
|
119
|
+
| "rules"
|
|
120
|
+
| "automations"
|
|
121
|
+
| "audit"
|
|
122
|
+
| "settings";
|
|
115
123
|
|
|
116
124
|
type FactoryAutomationRun = {
|
|
117
125
|
id?: string;
|
|
@@ -164,6 +172,7 @@ export default function FactoryRoute() {
|
|
|
164
172
|
const [dirty, setDirty] = useState(false);
|
|
165
173
|
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null);
|
|
166
174
|
const [selectedEdgeId, setSelectedEdgeId] = useState<string | null>(null);
|
|
175
|
+
const [auditRefreshToken, setAuditRefreshToken] = useState(0);
|
|
167
176
|
|
|
168
177
|
function setActiveTab(tab: WorkspaceTab) {
|
|
169
178
|
setSearchParams(
|
|
@@ -418,41 +427,62 @@ export default function FactoryRoute() {
|
|
|
418
427
|
</Button>
|
|
419
428
|
</div>
|
|
420
429
|
</div>
|
|
421
|
-
<
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
<TabButton
|
|
426
|
-
active={activeTab === "map"}
|
|
427
|
-
onClick={() => setActiveTab("map")}
|
|
428
|
-
>
|
|
429
|
-
Map
|
|
430
|
-
</TabButton>
|
|
431
|
-
<TabButton
|
|
432
|
-
active={activeTab === "inbox"}
|
|
433
|
-
onClick={() => setActiveTab("inbox")}
|
|
434
|
-
>
|
|
435
|
-
Inbox
|
|
436
|
-
</TabButton>
|
|
437
|
-
<TabButton
|
|
438
|
-
active={activeTab === "rules"}
|
|
439
|
-
onClick={() => setActiveTab("rules")}
|
|
440
|
-
>
|
|
441
|
-
{t("factoryRoute.rulesTab")}
|
|
442
|
-
</TabButton>
|
|
443
|
-
<TabButton
|
|
444
|
-
active={activeTab === "automations"}
|
|
445
|
-
onClick={() => setActiveTab("automations")}
|
|
430
|
+
<div className="mt-4 flex items-center gap-2">
|
|
431
|
+
<nav
|
|
432
|
+
className="flex min-w-0 flex-1 items-center gap-1 overflow-x-auto"
|
|
433
|
+
aria-label={t("factoryRoute.factoryViews")}
|
|
446
434
|
>
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
435
|
+
<TabButton
|
|
436
|
+
active={activeTab === "map"}
|
|
437
|
+
onClick={() => setActiveTab("map")}
|
|
438
|
+
>
|
|
439
|
+
Map
|
|
440
|
+
</TabButton>
|
|
441
|
+
<TabButton
|
|
442
|
+
active={activeTab === "inbox"}
|
|
443
|
+
onClick={() => setActiveTab("inbox")}
|
|
444
|
+
>
|
|
445
|
+
Inbox
|
|
446
|
+
</TabButton>
|
|
447
|
+
<TabButton
|
|
448
|
+
active={activeTab === "rules"}
|
|
449
|
+
onClick={() => setActiveTab("rules")}
|
|
450
|
+
>
|
|
451
|
+
{t("factoryRoute.rulesTab")}
|
|
452
|
+
</TabButton>
|
|
453
|
+
<TabButton
|
|
454
|
+
active={activeTab === "automations"}
|
|
455
|
+
onClick={() => setActiveTab("automations")}
|
|
456
|
+
>
|
|
457
|
+
{t("factoryRoute.automationsTab")}
|
|
458
|
+
</TabButton>
|
|
459
|
+
<TabButton
|
|
460
|
+
active={activeTab === "audit"}
|
|
461
|
+
onClick={() => setActiveTab("audit")}
|
|
462
|
+
>
|
|
463
|
+
{t("factoryRoute.auditTab")}
|
|
464
|
+
</TabButton>
|
|
465
|
+
<TabButton
|
|
466
|
+
active={activeTab === "settings"}
|
|
467
|
+
onClick={() => setActiveTab("settings")}
|
|
468
|
+
>
|
|
469
|
+
Settings
|
|
470
|
+
</TabButton>
|
|
471
|
+
</nav>
|
|
472
|
+
{activeTab === "audit" && (
|
|
473
|
+
<Button
|
|
474
|
+
type="button"
|
|
475
|
+
variant="ghost"
|
|
476
|
+
size="icon"
|
|
477
|
+
className="size-8 shrink-0 text-muted-foreground hover:text-foreground"
|
|
478
|
+
aria-label={t("factoryRoute.auditRefresh")}
|
|
479
|
+
title={t("factoryRoute.auditRefresh")}
|
|
480
|
+
onClick={() => setAuditRefreshToken((current) => current + 1)}
|
|
481
|
+
>
|
|
482
|
+
<IconRefresh className="size-4" />
|
|
483
|
+
</Button>
|
|
484
|
+
)}
|
|
485
|
+
</div>
|
|
456
486
|
</header>
|
|
457
487
|
|
|
458
488
|
<main className="min-h-0 flex-1 overflow-y-auto">
|
|
@@ -526,6 +556,11 @@ export default function FactoryRoute() {
|
|
|
526
556
|
<RulesView t={t} />
|
|
527
557
|
) : activeTab === "automations" ? (
|
|
528
558
|
<AutomationsView factoryId={factoryId} t={t} />
|
|
559
|
+
) : activeTab === "audit" ? (
|
|
560
|
+
<FactoryAuditView
|
|
561
|
+
factoryId={factoryId}
|
|
562
|
+
refreshToken={auditRefreshToken}
|
|
563
|
+
/>
|
|
529
564
|
) : (
|
|
530
565
|
<SettingsView t={t} />
|
|
531
566
|
)}
|
|
@@ -559,6 +594,7 @@ function parseWorkspaceTab(value: string | null): WorkspaceTab {
|
|
|
559
594
|
return value === "inbox" ||
|
|
560
595
|
value === "rules" ||
|
|
561
596
|
value === "automations" ||
|
|
597
|
+
value === "audit" ||
|
|
562
598
|
value === "settings"
|
|
563
599
|
? value
|
|
564
600
|
: "map";
|
|
@@ -589,11 +625,6 @@ function AutomationsView({
|
|
|
589
625
|
"list-factory-automations",
|
|
590
626
|
{ factoryId },
|
|
591
627
|
);
|
|
592
|
-
const healthQuery = useActionQuery<FactoryAutomationHealth>(
|
|
593
|
-
"get-factory-automation-health",
|
|
594
|
-
{},
|
|
595
|
-
{ refetchInterval: 60_000 },
|
|
596
|
-
);
|
|
597
628
|
const saveMutation = useActionMutation("save-factory-automation");
|
|
598
629
|
const runMutation = useActionMutation("run-factory-automation");
|
|
599
630
|
const {
|
|
@@ -684,85 +715,17 @@ function AutomationsView({
|
|
|
684
715
|
schedule: draft.schedule ?? "",
|
|
685
716
|
enabled: draft.enabled,
|
|
686
717
|
});
|
|
687
|
-
await
|
|
718
|
+
await automationsQuery.refetch();
|
|
688
719
|
}
|
|
689
720
|
|
|
690
721
|
async function runAutomation() {
|
|
691
722
|
if (!draft) return;
|
|
692
723
|
await runMutation.mutateAsync({ factoryId, automationId: draft.id });
|
|
693
|
-
await
|
|
724
|
+
await automationsQuery.refetch();
|
|
694
725
|
}
|
|
695
726
|
|
|
696
|
-
const health = healthQuery.data;
|
|
697
|
-
const healthLabel = health
|
|
698
|
-
? {
|
|
699
|
-
healthy: t("factoryRoute.automationHealthHealthy"),
|
|
700
|
-
stale: t("factoryRoute.automationHealthStale"),
|
|
701
|
-
error: t("factoryRoute.automationHealthError"),
|
|
702
|
-
"no-data": t("factoryRoute.automationHealthNoData"),
|
|
703
|
-
}[health.status]
|
|
704
|
-
: t("factoryRoute.automationHealthNoData");
|
|
705
|
-
|
|
706
727
|
return (
|
|
707
728
|
<div className="space-y-4 p-4 lg:p-6">
|
|
708
|
-
<Card>
|
|
709
|
-
<CardHeader className="pb-3">
|
|
710
|
-
<CardTitle className="text-base">
|
|
711
|
-
{t("factoryRoute.automationHealthTitle")}
|
|
712
|
-
</CardTitle>
|
|
713
|
-
<p className="text-sm text-muted-foreground">
|
|
714
|
-
{t("factoryRoute.automationHealthDescription")}
|
|
715
|
-
</p>
|
|
716
|
-
</CardHeader>
|
|
717
|
-
<CardContent className="space-y-2 pt-0 text-sm">
|
|
718
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
719
|
-
<span className="rounded-full border px-2 py-1 font-medium">
|
|
720
|
-
{healthLabel}
|
|
721
|
-
</span>
|
|
722
|
-
{health?.lastCheckedAt && (
|
|
723
|
-
<span className="text-muted-foreground">
|
|
724
|
-
{t("factoryRoute.automationLastCheck")}:{" "}
|
|
725
|
-
{formatAutomationDate(health.lastCheckedAt)}
|
|
726
|
-
</span>
|
|
727
|
-
)}
|
|
728
|
-
{health?.lastDispatchedAt && (
|
|
729
|
-
<span className="text-muted-foreground">
|
|
730
|
-
{t("factoryRoute.automationLastDispatch")}:{" "}
|
|
731
|
-
{formatAutomationDate(health.lastDispatchedAt)}
|
|
732
|
-
</span>
|
|
733
|
-
)}
|
|
734
|
-
{health?.runtime && (
|
|
735
|
-
<span className="text-muted-foreground">
|
|
736
|
-
{t("factoryRoute.automationRuntime")}: {health.runtime}
|
|
737
|
-
</span>
|
|
738
|
-
)}
|
|
739
|
-
</div>
|
|
740
|
-
{!health?.lastCheckedAt && (
|
|
741
|
-
<p className="text-muted-foreground">
|
|
742
|
-
{t("factoryRoute.automationHealthNoDataHint")}
|
|
743
|
-
</p>
|
|
744
|
-
)}
|
|
745
|
-
{health?.status === "stale" && (
|
|
746
|
-
<p className="text-destructive">
|
|
747
|
-
{t("factoryRoute.automationHealthStaleHint")}
|
|
748
|
-
</p>
|
|
749
|
-
)}
|
|
750
|
-
{health?.lastError && (
|
|
751
|
-
<p className="text-destructive">
|
|
752
|
-
{t("factoryRoute.automationHealthErrorDetail")}:{" "}
|
|
753
|
-
{health.lastError}
|
|
754
|
-
</p>
|
|
755
|
-
)}
|
|
756
|
-
{healthQuery.isError && (
|
|
757
|
-
<p className="text-destructive">
|
|
758
|
-
{t("factoryRoute.automationDiagnosticsLoadError")}{" "}
|
|
759
|
-
{healthQuery.error instanceof Error
|
|
760
|
-
? healthQuery.error.message
|
|
761
|
-
: String(healthQuery.error)}
|
|
762
|
-
</p>
|
|
763
|
-
)}
|
|
764
|
-
</CardContent>
|
|
765
|
-
</Card>
|
|
766
729
|
<div className="grid gap-4 lg:grid-cols-[minmax(220px,.35fr)_minmax(0,1fr)]">
|
|
767
730
|
<Card>
|
|
768
731
|
<CardHeader>
|
|
@@ -802,7 +765,7 @@ function AutomationsView({
|
|
|
802
765
|
<span className="block truncate text-sm font-medium">
|
|
803
766
|
{automation.name}
|
|
804
767
|
</span>
|
|
805
|
-
<span className="mt-1 block text-xs text-muted-foreground">
|
|
768
|
+
<span className="mt-1 block truncate text-xs text-muted-foreground">
|
|
806
769
|
{automation.enabled
|
|
807
770
|
? t("factoryRoute.automationEnabled")
|
|
808
771
|
: t("factoryRoute.automationDisabled")}
|
|
@@ -1029,8 +992,11 @@ function formatModelName(model: string | null | undefined) {
|
|
|
1029
992
|
}
|
|
1030
993
|
|
|
1031
994
|
function InboxView({ t }: { t: ReturnType<typeof useT> }) {
|
|
995
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
1032
996
|
const [status, setStatus] = useState("");
|
|
1033
|
-
const [selectedId, setSelectedId] = useState<string | null>(
|
|
997
|
+
const [selectedId, setSelectedId] = useState<string | null>(
|
|
998
|
+
searchParams.get("itemId"),
|
|
999
|
+
);
|
|
1034
1000
|
const [feedbackNote, setFeedbackNote] = useState("");
|
|
1035
1001
|
const [verdict, setVerdict] = useState<Verdict | null>(null);
|
|
1036
1002
|
const listQuery = useActionQuery("list-triage-items", {
|
|
@@ -1062,6 +1028,24 @@ function InboxView({ t }: { t: ReturnType<typeof useT> }) {
|
|
|
1062
1028
|
const normalizedItems = Array.isArray(items) ? items : (items.items ?? []);
|
|
1063
1029
|
const selectedItem = detailQuery.data as TriageItem | undefined;
|
|
1064
1030
|
|
|
1031
|
+
useEffect(() => {
|
|
1032
|
+
setSelectedId(searchParams.get("itemId"));
|
|
1033
|
+
}, [searchParams]);
|
|
1034
|
+
|
|
1035
|
+
function selectItem(itemId: string) {
|
|
1036
|
+
setSelectedId(itemId);
|
|
1037
|
+
setVerdict(null);
|
|
1038
|
+
setFeedbackNote("");
|
|
1039
|
+
setSearchParams(
|
|
1040
|
+
(current) => {
|
|
1041
|
+
const next = new URLSearchParams(current);
|
|
1042
|
+
next.set("itemId", itemId);
|
|
1043
|
+
return next;
|
|
1044
|
+
},
|
|
1045
|
+
{ replace: true },
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1065
1049
|
return (
|
|
1066
1050
|
<div className="grid gap-4 p-4 lg:grid-cols-[minmax(0,1.3fr)_minmax(320px,.7fr)] lg:p-6">
|
|
1067
1051
|
<Card>
|
|
@@ -1119,11 +1103,7 @@ function InboxView({ t }: { t: ReturnType<typeof useT> }) {
|
|
|
1119
1103
|
key={id}
|
|
1120
1104
|
type="button"
|
|
1121
1105
|
className={`grid w-full gap-3 p-4 text-left transition-colors hover:bg-muted/50 sm:grid-cols-[1.1fr_.7fr_.9fr_1.6fr] ${selectedId === id ? "bg-muted/60" : ""}`}
|
|
1122
|
-
onClick={() =>
|
|
1123
|
-
setSelectedId(id);
|
|
1124
|
-
setVerdict(null);
|
|
1125
|
-
setFeedbackNote("");
|
|
1126
|
-
}}
|
|
1106
|
+
onClick={() => selectItem(id)}
|
|
1127
1107
|
>
|
|
1128
1108
|
<span className="min-w-0">
|
|
1129
1109
|
<span className="block truncate text-sm font-medium">
|
|
@@ -1407,6 +1387,11 @@ function SettingsView({ t }: { t: ReturnType<typeof useT> }) {
|
|
|
1407
1387
|
const [automationFailureAlertEmail, setAutomationFailureAlertEmail] =
|
|
1408
1388
|
useState("");
|
|
1409
1389
|
const query = useActionQuery("get-triage-config", {});
|
|
1390
|
+
const schedulerHealthQuery = useActionQuery<FactoryAutomationHealth>(
|
|
1391
|
+
"get-factory-automation-health",
|
|
1392
|
+
{},
|
|
1393
|
+
{ refetchInterval: 60_000 },
|
|
1394
|
+
);
|
|
1410
1395
|
const mutation = useActionMutation("save-triage-config");
|
|
1411
1396
|
useEffect(() => {
|
|
1412
1397
|
const data = query.data as TriageConfig | undefined;
|
|
@@ -1427,7 +1412,7 @@ function SettingsView({ t }: { t: ReturnType<typeof useT> }) {
|
|
|
1427
1412
|
setAutomationFailureAlertEmail(data.automationFailureAlertEmail ?? "");
|
|
1428
1413
|
}, [query.data]);
|
|
1429
1414
|
return (
|
|
1430
|
-
<div className="max-w-4xl p-4 lg:p-6">
|
|
1415
|
+
<div className="max-w-4xl space-y-4 p-4 lg:p-6">
|
|
1431
1416
|
<Card>
|
|
1432
1417
|
<CardHeader>
|
|
1433
1418
|
<CardTitle className="text-base">
|
|
@@ -1621,10 +1606,110 @@ function SettingsView({ t }: { t: ReturnType<typeof useT> }) {
|
|
|
1621
1606
|
</div>
|
|
1622
1607
|
</CardContent>
|
|
1623
1608
|
</Card>
|
|
1609
|
+
<SchedulerHealthStatus
|
|
1610
|
+
health={schedulerHealthQuery.data}
|
|
1611
|
+
isError={schedulerHealthQuery.isError}
|
|
1612
|
+
error={schedulerHealthQuery.error}
|
|
1613
|
+
t={t}
|
|
1614
|
+
/>
|
|
1624
1615
|
</div>
|
|
1625
1616
|
);
|
|
1626
1617
|
}
|
|
1627
1618
|
|
|
1619
|
+
function SchedulerHealthStatus({
|
|
1620
|
+
health,
|
|
1621
|
+
isError,
|
|
1622
|
+
error,
|
|
1623
|
+
t,
|
|
1624
|
+
}: {
|
|
1625
|
+
health?: FactoryAutomationHealth;
|
|
1626
|
+
isError: boolean;
|
|
1627
|
+
error: unknown;
|
|
1628
|
+
t: ReturnType<typeof useT>;
|
|
1629
|
+
}) {
|
|
1630
|
+
const healthLabel = isError
|
|
1631
|
+
? t("factoryRoute.automationHealthError")
|
|
1632
|
+
: health
|
|
1633
|
+
? {
|
|
1634
|
+
healthy: t("factoryRoute.automationHealthHealthy"),
|
|
1635
|
+
stale: t("factoryRoute.automationHealthStale"),
|
|
1636
|
+
error: t("factoryRoute.automationHealthError"),
|
|
1637
|
+
"no-data": t("factoryRoute.automationHealthNoData"),
|
|
1638
|
+
}[health.status]
|
|
1639
|
+
: t("factoryRoute.automationHealthNoData");
|
|
1640
|
+
const hasNoHeartbeat =
|
|
1641
|
+
!isError &&
|
|
1642
|
+
(!health || health.status === "no-data") &&
|
|
1643
|
+
!health?.lastCheckedAt;
|
|
1644
|
+
const hasDiagnostics =
|
|
1645
|
+
isError ||
|
|
1646
|
+
hasNoHeartbeat ||
|
|
1647
|
+
health?.status === "stale" ||
|
|
1648
|
+
health?.status === "error" ||
|
|
1649
|
+
Boolean(health?.lastError);
|
|
1650
|
+
|
|
1651
|
+
return (
|
|
1652
|
+
<section
|
|
1653
|
+
aria-labelledby="factory-scheduler-health"
|
|
1654
|
+
className="border-t px-1 pt-4"
|
|
1655
|
+
>
|
|
1656
|
+
<div className="flex flex-wrap items-center justify-between gap-x-4 gap-y-2">
|
|
1657
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1658
|
+
<h2
|
|
1659
|
+
id="factory-scheduler-health"
|
|
1660
|
+
className="text-sm font-medium text-muted-foreground"
|
|
1661
|
+
>
|
|
1662
|
+
{t("factoryRoute.automationHealthTitle")}
|
|
1663
|
+
</h2>
|
|
1664
|
+
<span className="rounded-full border px-2 py-0.5 text-xs font-medium">
|
|
1665
|
+
{healthLabel}
|
|
1666
|
+
</span>
|
|
1667
|
+
</div>
|
|
1668
|
+
<div className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground">
|
|
1669
|
+
{health?.lastCheckedAt && (
|
|
1670
|
+
<span>
|
|
1671
|
+
{t("factoryRoute.automationLastCheck")}:{" "}
|
|
1672
|
+
{formatAutomationDate(health.lastCheckedAt)}
|
|
1673
|
+
</span>
|
|
1674
|
+
)}
|
|
1675
|
+
{health?.lastDispatchedAt && (
|
|
1676
|
+
<span>
|
|
1677
|
+
{t("factoryRoute.automationLastDispatch")}:{" "}
|
|
1678
|
+
{formatAutomationDate(health.lastDispatchedAt)}
|
|
1679
|
+
</span>
|
|
1680
|
+
)}
|
|
1681
|
+
</div>
|
|
1682
|
+
</div>
|
|
1683
|
+
{hasDiagnostics && (
|
|
1684
|
+
<div className="mt-2 grid gap-1 text-xs">
|
|
1685
|
+
{hasNoHeartbeat && (
|
|
1686
|
+
<p className="text-muted-foreground">
|
|
1687
|
+
{t("factoryRoute.automationHealthNoDataHint")}
|
|
1688
|
+
</p>
|
|
1689
|
+
)}
|
|
1690
|
+
{health?.status === "stale" && (
|
|
1691
|
+
<p className="text-destructive">
|
|
1692
|
+
{t("factoryRoute.automationHealthStaleHint")}
|
|
1693
|
+
</p>
|
|
1694
|
+
)}
|
|
1695
|
+
{health?.lastError && (
|
|
1696
|
+
<p className="text-destructive">
|
|
1697
|
+
{t("factoryRoute.automationHealthErrorDetail")}:{" "}
|
|
1698
|
+
{health.lastError}
|
|
1699
|
+
</p>
|
|
1700
|
+
)}
|
|
1701
|
+
{isError && (
|
|
1702
|
+
<p className="text-destructive">
|
|
1703
|
+
{t("factoryRoute.automationDiagnosticsLoadError")}{" "}
|
|
1704
|
+
{error instanceof Error ? error.message : String(error)}
|
|
1705
|
+
</p>
|
|
1706
|
+
)}
|
|
1707
|
+
</div>
|
|
1708
|
+
)}
|
|
1709
|
+
</section>
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1628
1713
|
function ErrorState({
|
|
1629
1714
|
message,
|
|
1630
1715
|
onRetry,
|
|
@@ -132,6 +132,43 @@ export const triageConfig = table("factory_config", {
|
|
|
132
132
|
orgId: text("org_id"),
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
+
export const factoryAuditEvents = table(
|
|
136
|
+
"factory_audit_events",
|
|
137
|
+
{
|
|
138
|
+
id: text("id").primaryKey(),
|
|
139
|
+
automationRunId: text("automation_run_id"),
|
|
140
|
+
automationThreadId: text("automation_thread_id"),
|
|
141
|
+
automationName: text("automation_name"),
|
|
142
|
+
itemId: text("item_id"),
|
|
143
|
+
source: text("source"),
|
|
144
|
+
sourceUrl: text("source_url"),
|
|
145
|
+
action: text("action").notNull(),
|
|
146
|
+
kind: text("kind").notNull(),
|
|
147
|
+
status: text("status").notNull(),
|
|
148
|
+
summary: text("summary").notNull(),
|
|
149
|
+
detailsJson: text("details_json").notNull().default("{}"),
|
|
150
|
+
createdAt: text("created_at").notNull().default(now()),
|
|
151
|
+
ownerEmail: text("owner_email").notNull(),
|
|
152
|
+
orgId: text("org_id"),
|
|
153
|
+
},
|
|
154
|
+
(event) => ({
|
|
155
|
+
orgCreatedIdx: index("factory_audit_events_org_created_idx").on(
|
|
156
|
+
event.orgId,
|
|
157
|
+
event.createdAt,
|
|
158
|
+
),
|
|
159
|
+
runCreatedIdx: index("factory_audit_events_run_created_idx").on(
|
|
160
|
+
event.orgId,
|
|
161
|
+
event.automationRunId,
|
|
162
|
+
event.createdAt,
|
|
163
|
+
),
|
|
164
|
+
itemCreatedIdx: index("factory_audit_events_item_created_idx").on(
|
|
165
|
+
event.orgId,
|
|
166
|
+
event.itemId,
|
|
167
|
+
event.createdAt,
|
|
168
|
+
),
|
|
169
|
+
}),
|
|
170
|
+
);
|
|
171
|
+
|
|
135
172
|
export const factoryDefinitions = table(
|
|
136
173
|
"factory_definitions",
|
|
137
174
|
{
|
|
@@ -45,7 +45,11 @@ export async function requireFactoryAutomation(
|
|
|
45
45
|
|
|
46
46
|
const definition = (
|
|
47
47
|
await listAutomationDefinitions(
|
|
48
|
-
{
|
|
48
|
+
{
|
|
49
|
+
userEmail: identity.userEmail,
|
|
50
|
+
orgId: identity.orgId,
|
|
51
|
+
appId: "factory",
|
|
52
|
+
},
|
|
49
53
|
"organization",
|
|
50
54
|
)
|
|
51
55
|
).find((entry) => entry.resource.id === lineage.triggerId);
|
|
@@ -258,6 +258,35 @@ const migrations = [
|
|
|
258
258
|
ALTER TABLE factory_config ADD COLUMN last_automation_failure_alert_at TEXT;
|
|
259
259
|
`,
|
|
260
260
|
},
|
|
261
|
+
{
|
|
262
|
+
version: 18,
|
|
263
|
+
name: "factory-audit-events-table",
|
|
264
|
+
sql: `
|
|
265
|
+
CREATE TABLE IF NOT EXISTS factory_audit_events (
|
|
266
|
+
id TEXT PRIMARY KEY,
|
|
267
|
+
automation_run_id TEXT,
|
|
268
|
+
automation_thread_id TEXT,
|
|
269
|
+
automation_name TEXT,
|
|
270
|
+
item_id TEXT,
|
|
271
|
+
source TEXT,
|
|
272
|
+
source_url TEXT,
|
|
273
|
+
action TEXT NOT NULL,
|
|
274
|
+
kind TEXT NOT NULL,
|
|
275
|
+
status TEXT NOT NULL,
|
|
276
|
+
summary TEXT NOT NULL,
|
|
277
|
+
details_json TEXT NOT NULL DEFAULT '{}',
|
|
278
|
+
created_at TEXT NOT NULL,
|
|
279
|
+
owner_email TEXT NOT NULL,
|
|
280
|
+
org_id TEXT
|
|
281
|
+
);
|
|
282
|
+
CREATE INDEX IF NOT EXISTS factory_audit_events_org_created_idx
|
|
283
|
+
ON factory_audit_events (org_id, created_at);
|
|
284
|
+
CREATE INDEX IF NOT EXISTS factory_audit_events_run_created_idx
|
|
285
|
+
ON factory_audit_events (org_id, automation_run_id, created_at);
|
|
286
|
+
CREATE INDEX IF NOT EXISTS factory_audit_events_item_created_idx
|
|
287
|
+
ON factory_audit_events (org_id, item_id, created_at);
|
|
288
|
+
`,
|
|
289
|
+
},
|
|
261
290
|
];
|
|
262
291
|
|
|
263
292
|
export const runFactoryMigrations = runMigrations(migrations, {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import type { ActionRunContext } from "@agent-native/core/action";
|
|
4
|
+
|
|
5
|
+
import { getDb } from "../db/index.js";
|
|
6
|
+
import { factoryAuditEvents } from "../db/schema.js";
|
|
7
|
+
|
|
8
|
+
const MAX_SUMMARY_LENGTH = 500;
|
|
9
|
+
const MAX_DETAILS_LENGTH = 4_000;
|
|
10
|
+
|
|
11
|
+
export type FactoryAuditKind =
|
|
12
|
+
| "observed"
|
|
13
|
+
| "read"
|
|
14
|
+
| "decision"
|
|
15
|
+
| "external_action"
|
|
16
|
+
| "governance";
|
|
17
|
+
|
|
18
|
+
export type FactoryAuditStatus = "success" | "error" | "skipped";
|
|
19
|
+
|
|
20
|
+
export interface FactoryAuditInput {
|
|
21
|
+
action: string;
|
|
22
|
+
kind: FactoryAuditKind;
|
|
23
|
+
status?: FactoryAuditStatus;
|
|
24
|
+
itemId?: string | null;
|
|
25
|
+
source?: string | null;
|
|
26
|
+
sourceUrl?: string | null;
|
|
27
|
+
summary: string;
|
|
28
|
+
details?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function boundedText(value: string, max: number): string {
|
|
32
|
+
const compact = value.replace(/\s+/g, " ").trim();
|
|
33
|
+
return compact.length > max ? `${compact.slice(0, max - 1)}…` : compact;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function boundedDetails(value: Record<string, unknown> | undefined): string {
|
|
37
|
+
if (!value) return "{}";
|
|
38
|
+
let serialized: string;
|
|
39
|
+
try {
|
|
40
|
+
serialized = JSON.stringify(value);
|
|
41
|
+
} catch {
|
|
42
|
+
throw new Error("Factory audit details are not serializable.");
|
|
43
|
+
}
|
|
44
|
+
return serialized.length > MAX_DETAILS_LENGTH
|
|
45
|
+
? JSON.stringify({ truncated: true })
|
|
46
|
+
: serialized;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Persist a bounded, source-linked explanation of an automation action. The
|
|
51
|
+
* agent run id is the join key to core's automation history; no raw provider
|
|
52
|
+
* payload is copied into this table.
|
|
53
|
+
*/
|
|
54
|
+
export async function recordFactoryAudit(
|
|
55
|
+
context: ActionRunContext | undefined,
|
|
56
|
+
identity: { userEmail: string; orgId: string },
|
|
57
|
+
input: FactoryAuditInput,
|
|
58
|
+
): Promise<void> {
|
|
59
|
+
if (context?.caller !== "automation" || !context.runId) return;
|
|
60
|
+
await getDb()
|
|
61
|
+
.insert(factoryAuditEvents)
|
|
62
|
+
.values({
|
|
63
|
+
id: randomUUID(),
|
|
64
|
+
automationRunId: context.runId,
|
|
65
|
+
automationThreadId: context.threadId ?? null,
|
|
66
|
+
automationName: context.automation?.triggerName ?? null,
|
|
67
|
+
itemId: input.itemId ?? null,
|
|
68
|
+
source: input.source ?? null,
|
|
69
|
+
sourceUrl: input.sourceUrl ?? null,
|
|
70
|
+
action: boundedText(input.action, 120),
|
|
71
|
+
kind: input.kind,
|
|
72
|
+
status: input.status ?? "success",
|
|
73
|
+
summary: boundedText(input.summary, MAX_SUMMARY_LENGTH),
|
|
74
|
+
detailsJson: boundedDetails(input.details),
|
|
75
|
+
createdAt: new Date().toISOString(),
|
|
76
|
+
ownerEmail: identity.userEmail,
|
|
77
|
+
orgId: identity.orgId,
|
|
78
|
+
});
|
|
79
|
+
}
|