@agent-native/core 0.169.0 → 0.170.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/agent-native.eject.json +4 -1
- package/bin/agent-native.js +23 -5
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/analytics/actions/bigquery-table-info.ts +3 -2
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/actions/search-bigquery-schema.ts +130 -4
- package/corpus/templates/analytics/agent-native.config.ts +1 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +36 -23
- package/corpus/templates/analytics/app/i18n-data.ts +28 -0
- package/corpus/templates/analytics/app/lib/dashboard-visibility.ts +41 -0
- package/corpus/templates/analytics/app/pages/Agents.tsx +25 -1
- package/corpus/templates/analytics/app/pages/DashboardOverview.tsx +34 -9
- package/corpus/templates/analytics/app/routes/$.tsx +10 -0
- package/corpus/templates/analytics/app/routes.ts +3 -1
- package/corpus/templates/analytics/changelog/2026-08-21-dashboard-filters-keep-other-users-dashboards-out-of-mine.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-22-fixed-the-agent-native-templates-first-party-dashboard-panel.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-22-org-admin-panels-no-longer-report-a-database-error-as-a-per.md +9 -0
- package/corpus/templates/analytics/changelog/2026-08-22-slack-requests-report-invalid-inputs.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-22-unknown-analytics-links-now-return-a-real-not-found-status.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +2 -1
- package/corpus/templates/analytics/docs/schemas/tracked-events.md +2 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +29 -7
- package/corpus/templates/analytics/server/handlers/slack.ts +59 -5
- package/corpus/templates/analytics/server/lib/db-admin-connections.ts +11 -6
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +132 -2
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +14 -3
- package/corpus/templates/analytics/server/lib/slack.ts +4 -2
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +33 -3
- package/corpus/templates/analytics/vitest.config.ts +6 -1
- package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/assets/app/routes/library.tsx +5 -3
- package/corpus/templates/assets/app/routes.ts +3 -1
- package/corpus/templates/assets/changelog/2026-08-22-library-page-loads-again-instead-of-crashing-on-open.md +6 -0
- package/corpus/templates/assets/vitest.config.ts +6 -1
- package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/brain/app/components/ui/pointer-lock.ts +1 -0
- package/corpus/templates/brain/app/routes/sources.tsx +8 -3
- package/corpus/templates/brain/changelog/2026-08-22-tuning-or-adding-a-source-no-longer-leaves-the-sources-page.md +6 -0
- package/corpus/templates/brain/server/lib/brain.ts +27 -2
- package/corpus/templates/brain/vitest.config.ts +1 -0
- package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/calendar/actions/list-booking-links.ts +83 -4
- package/corpus/templates/calendar/actions/update-booking-link.ts +4 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +11 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +1 -1
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +103 -44
- package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +28 -24
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +9 -2
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +47 -58
- package/corpus/templates/calendar/app/hooks/use-booking-links.ts +5 -1
- package/corpus/templates/calendar/app/lib/event-layout.ts +52 -26
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +126 -98
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +1 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +88 -81
- package/corpus/templates/calendar/app/routes.ts +3 -1
- package/corpus/templates/calendar/changelog/2026-08-22-booking-link-visibility-respects-shared-access.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-clicking-an-out-of-office-event-s-marker-no-longer-creates-a.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-event-detail-views-now-show-your-calendar-timezone.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-google-calendar-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-overlapping-events-now-show-each-others-boundaries.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-public-booking-pages-now-offer-time-slots-from-the-host-s-we.md +6 -0
- package/corpus/templates/calendar/server/handlers/bookings.ts +5 -7
- package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
- package/corpus/templates/calendar/server/lib/google-calendar.ts +139 -14
- package/corpus/templates/calendar/server/onboarding.ts +85 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/calendar/shared/api.ts +9 -1
- package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/chat/app/routes.ts +3 -1
- package/corpus/templates/chat/vitest.config.ts +8 -0
- package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/clips/actions/get-meeting.ts +9 -4
- package/corpus/templates/clips/actions/list-recordings.ts +16 -3
- package/corpus/templates/clips/actions/search-meetings.ts +1 -0
- package/corpus/templates/clips/actions/stop-meeting-recording.ts +87 -6
- package/corpus/templates/clips/actions/view-screen.ts +8 -1
- package/corpus/templates/clips/app/components/library/search-bar.tsx +1 -1
- package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +32 -1
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +29 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +5 -0
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +33 -4
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -0
- package/corpus/templates/clips/app/routes/access-request.approve.tsx +16 -9
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +17 -7
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +17 -7
- package/corpus/templates/clips/changelog/2026-08-21-camera-bubble-black-circle.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-22-screen-recordings-respect-the-microphone-toggle.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-22-the-recordings-library-no-longer-fails-right-after-server-start.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-23-the-agent-can-see-your-library-right-after-server-start.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +1 -2
- package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +39 -7
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +21 -25
- package/corpus/templates/clips/desktop/src/app.tsx +53 -24
- package/corpus/templates/clips/desktop/src/lib/bubble-playback.ts +68 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +3 -0
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +72 -14
- package/corpus/templates/clips/desktop/src/lib/updater.ts +8 -3
- package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +162 -20
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +43 -6
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +150 -13
- package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +28 -3
- package/corpus/templates/clips/server/lib/emails.ts +17 -33
- package/corpus/templates/content/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +140 -15
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +12 -14
- package/corpus/templates/content/app/components/ui/pointer-lock.ts +1 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +18 -2
- package/corpus/templates/content/app/hooks/use-local-storage.ts +38 -22
- package/corpus/templates/content/app/i18n-data.ts +25 -0
- package/corpus/templates/content/app/routes.ts +3 -1
- package/corpus/templates/content/changelog/2026-08-22-code-blocks-inserted-from-the-slash-menu-no-longer-get-stuck.md +6 -0
- package/corpus/templates/content/changelog/2026-08-22-the-sidebar-page-tree-no-longer-flashes-empty-after-creating-a-page.md +6 -0
- package/corpus/templates/content/docs/solutions/2026-08-21-content-mermaid-rendering-shape.md +233 -0
- package/corpus/templates/content/server/plugins/agent-chat.ts +9 -2
- package/corpus/templates/content/vitest.config.ts +7 -1
- package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/design/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1386 -92
- package/corpus/templates/design/actions/generate-design.ts +98 -47
- package/corpus/templates/design/actions/get-design-system.ts +6 -1
- package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +146 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +70 -26
- package/corpus/templates/design/app/components/design/EditPanel.tsx +15 -47
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +284 -136
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2060 -144
- package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +6 -2
- package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +4 -4
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +10 -8
- package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +19 -2
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -2
- package/corpus/templates/design/app/components/layout/Header.tsx +15 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +7 -2
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +13 -8
- package/corpus/templates/design/app/i18n-data.ts +11 -10
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +12 -0
- package/corpus/templates/design/app/lib/design-system-data.ts +68 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +99 -57
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +39 -8
- package/corpus/templates/design/app/pages/DesignSystems.tsx +137 -43
- package/corpus/templates/design/app/pages/Index.tsx +3 -1
- package/corpus/templates/design/app/pages/Templates.tsx +0 -10
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +10 -0
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +50 -0
- package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +10 -8
- package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +6 -6
- package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +18 -7
- package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +4 -90
- package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +2 -1
- package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +4 -3
- package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +12 -2
- package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +9 -2
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +11 -1
- package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +11 -19
- package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +6 -6
- package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +12 -15
- package/corpus/templates/design/app/pages/design-editor/preview-navigation.ts +25 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -59
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +8 -0
- package/corpus/templates/design/app/pages/design-editor/types.ts +3 -3
- package/corpus/templates/design/app/routes.ts +3 -1
- package/corpus/templates/design/changelog/2026-08-20-canvas-edits-patch-the-frame-instead-of-rebuilding-it.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-draw-mode-needs-shift-y.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-eyedropper-shortcut.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-figma-style-alignment-guides-and-snapping.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-group-transforms-keep-the-selection.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-inspector-fields-keep-focus-on-enter.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-pen-alt-keeps-the-incoming-handle.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-pen-on-the-board-creates-one-vector.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-scale-a-multi-selection-from-the-group-handles.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-scale-resizes-text-with-the-object.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-selecting-another-object-keeps-the-scale-tool-armed.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-the-shape-tool-remembers-the-shape-you-picked.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-vectors-drawn-in-a-frame-land-where-you-drew-them.md +6 -0
- package/corpus/templates/design/changelog/2026-08-22-multi-screen-generation-no-longer-loses-a-saved-screens-layo.md +6 -0
- package/corpus/templates/design/changelog/2026-08-22-rename-and-search-fields-are-labeled-for-screen-readers.md +6 -0
- package/corpus/templates/design/package.json +2 -0
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +311 -0
- package/corpus/templates/design/shared/canvas-math.ts +612 -206
- package/corpus/templates/design/shared/pen-path.ts +37 -0
- package/corpus/templates/design/vitest.config.ts +7 -1
- package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/dispatch/actions/list-workspace-connections.ts +34 -3
- package/corpus/templates/dispatch/app/routes/integrations.tsx +55 -21
- package/corpus/templates/dispatch/app/routes.ts +3 -1
- package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/factory/.env.example +2 -7
- package/corpus/templates/factory/AGENTS.md +3 -0
- package/corpus/templates/factory/README.md +5 -3
- package/corpus/templates/factory/actions/create-factory.ts +16 -3
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +2 -0
- package/corpus/templates/factory/actions/get-triage-item.ts +2 -0
- package/corpus/templates/factory/actions/list-factory-audit.ts +116 -36
- package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
- package/corpus/templates/factory/actions/list-triage-items.ts +22 -19
- package/corpus/templates/factory/actions/run-factory-automation.ts +7 -3
- package/corpus/templates/factory/actions/save-factory-automation.ts +5 -2
- package/corpus/templates/factory/actions/save-triage-config.ts +2 -8
- package/corpus/templates/factory/actions/start-builder-for-item.ts +21 -0
- package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +229 -297
- package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +397 -247
- package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +33 -0
- package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +202 -162
- package/corpus/templates/factory/app/i18n/en-US.ts +32 -4
- package/corpus/templates/factory/app/routes/factory.tsx +84 -11
- package/corpus/templates/factory/app/routes.ts +3 -1
- package/corpus/templates/factory/changelog/2026-08-21-activity-runs-use-automation-display-names.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-create-and-settings-source-cards.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-keep-automations-visible-while-running.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-nested-factory-automations-can-poll.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-settings-sticky-unsaved-bar.md +6 -0
- package/corpus/templates/factory/server/connectors/credentials.ts +10 -5
- package/corpus/templates/factory/server/lib/factory-audit-report.ts +412 -0
- package/corpus/templates/factory/server/lib/factory-config-reconcile.ts +321 -0
- package/corpus/templates/factory/server/lib/factory-scope.ts +25 -2
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +13 -4
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +148 -4
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +4 -6
- package/corpus/templates/factory/vitest.config.ts +17 -2
- package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/forms/app/routes/_app.settings.tsx +4 -1
- package/corpus/templates/forms/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/forms/server/lib/public-form-ssr.ts +11 -1
- package/corpus/templates/forms/vitest.config.ts +1 -0
- package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/macros/app/routes.ts +3 -1
- package/corpus/templates/macros/vitest.config.ts +6 -1
- package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/mail/actions/manage-gmail-filters.ts +10 -2
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -37
- package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +14 -2
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +66 -36
- package/corpus/templates/mail/app/hooks/use-emails.ts +13 -3
- package/corpus/templates/mail/app/hooks/use-google-auth.ts +2 -0
- package/corpus/templates/mail/app/lib/google-oauth-setup.ts +17 -0
- package/corpus/templates/mail/app/pages/InboxPage.tsx +69 -9
- package/corpus/templates/mail/app/routes/$.tsx +9 -0
- package/corpus/templates/mail/app/routes/$view.$threadId.tsx +23 -1
- package/corpus/templates/mail/app/routes/$view.tsx +47 -1
- package/corpus/templates/mail/app/routes.ts +3 -1
- package/corpus/templates/mail/changelog/2026-08-22-gmail-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/mail/changelog/2026-08-22-gmail-filters-now-shows-the-real-error.md +6 -0
- package/corpus/templates/mail/changelog/2026-08-22-unknown-mail-urls-now-show-the-404-page.md +6 -0
- package/corpus/templates/mail/server/handlers/google-auth.ts +11 -2
- package/corpus/templates/mail/server/lib/google-auth.ts +92 -12
- package/corpus/templates/mail/server/onboarding.ts +66 -18
- package/corpus/templates/mail/vitest.config.ts +6 -1
- package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/plan/app/routes/settings.tsx +4 -1
- package/corpus/templates/plan/app/routes.ts +3 -1
- package/corpus/templates/plan/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/plan/netlify.toml +1 -1
- package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/slides/actions/patch-deck.ts +79 -10
- package/corpus/templates/slides/actions/update-slide.ts +11 -1
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +14 -4
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +10 -52
- package/corpus/templates/slides/app/components/editor/GoogleDocImportHint.tsx +8 -53
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +9 -75
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +8 -60
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +10 -2
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +19 -7
- package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +49 -36
- package/corpus/templates/slides/app/routes/access-request.approve.tsx +16 -9
- package/corpus/templates/slides/app/routes.ts +3 -1
- package/corpus/templates/slides/changelog/2026-08-22-already-uploaded-chat-images-are-no-longer-dropped.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-google-drive-and-slides-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-multi-slide-repairs-now-report-slides-that-still-overflow.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-update-slide-now-reports-which-batched-edit-was-skipped.md +6 -0
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +52 -1
- package/corpus/templates/slides/server/lib/chat-attachments.ts +29 -3
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +66 -16
- package/corpus/templates/slides/server/lib/slide-content-patch.ts +13 -2
- package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -2
- package/corpus/templates/slides/tsconfig.json +5 -0
- package/corpus/templates/slides/vitest.config.ts +6 -1
- package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/tasks/app/routes/settings.tsx +4 -1
- package/corpus/templates/tasks/app/routes.ts +3 -1
- package/corpus/templates/tasks/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/tasks/vitest.config.ts +7 -1
- package/dist/action.d.ts +91 -0
- package/dist/action.js +50 -0
- package/dist/agent/abort-reasons.d.ts +38 -0
- package/dist/agent/abort-reasons.js +49 -0
- package/dist/agent/engine/ai-sdk-engine.js +8 -5
- package/dist/agent/engine/anthropic-engine.js +7 -5
- package/dist/agent/engine/credential-errors.d.ts +1 -1
- package/dist/agent/engine/credential-errors.js +2 -2
- package/dist/agent/engine/first-event-timeout.d.ts +42 -17
- package/dist/agent/engine/first-event-timeout.js +67 -25
- package/dist/agent/production-agent.d.ts +23 -0
- package/dist/agent/production-agent.js +107 -102
- package/dist/agent/run-loop-with-resume.d.ts +2 -28
- package/dist/agent/run-loop-with-resume.js +25 -40
- package/dist/agent/run-manager.js +5 -4
- package/dist/agent/run-store.d.ts +55 -0
- package/dist/agent/run-store.js +124 -1
- package/dist/agent/tool-search.js +2 -1
- package/dist/agent/types.d.ts +9 -4
- package/dist/app-config/configuration-error.d.ts +11 -0
- package/dist/app-config/configuration-error.js +14 -0
- package/dist/app-config/index.d.ts +1 -0
- package/dist/app-config/index.js +1 -0
- package/dist/app-config/integrations.d.ts +1 -0
- package/dist/app-config/integrations.js +10 -0
- package/dist/app-config/plugins.d.ts +34 -0
- package/dist/app-config/plugins.js +39 -0
- package/dist/app-config/run-lifecycle-invariants.d.ts +18 -9
- package/dist/app-config/run-lifecycle-invariants.js +18 -25
- package/dist/app-config/schema.d.ts +16 -0
- package/dist/app-config/schema.js +2 -0
- package/dist/chat-threads/schema-migrations.js +20 -0
- package/dist/chat-threads/store.js +21 -4
- package/dist/cli/native-dependencies.d.ts +4 -0
- package/dist/cli/native-dependencies.js +15 -0
- package/dist/client/AssistantChat.js +47 -15
- package/dist/client/ConnectBuilderCard.d.ts +3 -1
- package/dist/client/ConnectBuilderCard.js +6 -3
- package/dist/client/EnvironmentBadge.d.ts +1 -1
- package/dist/client/EnvironmentBadge.js +40 -5
- package/dist/client/MultiTabAssistantChat.d.ts +1 -1
- package/dist/client/MultiTabAssistantChat.js +35 -14
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat/index.js +1 -1
- package/dist/client/agent-page/use-jobs.d.ts +2 -1
- package/dist/client/agent-page/use-jobs.js +3 -5
- package/dist/client/agent-sidebar-state.js +3 -1
- package/dist/client/blocks/library/code-tabs.js +5 -0
- package/dist/client/blocks/library/code.js +1 -0
- package/dist/client/chat/message-components.d.ts +7 -0
- package/dist/client/chat/message-components.js +1 -1
- package/dist/client/chat/run-recovery.js +5 -2
- package/dist/client/chat/tool-call-display.js +9 -3
- package/dist/client/chat-first/apps-rail.js +2 -2
- package/dist/client/chat-model-groups.d.ts +12 -0
- package/dist/client/chat-model-groups.js +3 -2
- package/dist/client/error-format.js +12 -0
- package/dist/client/integrations/GoogleProductLogo.d.ts +5 -0
- package/dist/client/integrations/GoogleProductLogo.js +45 -0
- package/dist/client/integrations/index.d.ts +2 -0
- package/dist/client/integrations/index.js +2 -0
- package/dist/client/integrations/workspace-provider-oauth.d.ts +8 -0
- package/dist/client/integrations/workspace-provider-oauth.js +13 -0
- package/dist/client/navigation/index.d.ts +1 -0
- package/dist/client/navigation/index.js +1 -0
- package/dist/client/resources/mcp-integration-catalog.js +0 -29
- package/dist/client/route-state.js +6 -0
- package/dist/client/settings/SettingsTabsPage.js +10 -6
- package/dist/client/sharing/ShareButton.js +11 -2
- package/dist/client/use-chat-models.d.ts +6 -0
- package/dist/client/use-chat-models.js +10 -0
- package/dist/client/use-db-sync.js +27 -9
- package/dist/client/workspace-app-navigation.d.ts +10 -0
- package/dist/client/workspace-app-navigation.js +38 -0
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +111 -9
- package/dist/connections/catalog.js +86 -30
- package/dist/db/create-get-db.js +18 -0
- package/dist/db/ddl-guard.d.ts +0 -4
- package/dist/db/ddl-guard.js +46 -0
- package/dist/deploy/build.d.ts +32 -0
- package/dist/deploy/build.js +241 -16
- package/dist/deploy/function-bundle.d.ts +45 -0
- package/dist/deploy/function-bundle.js +337 -0
- package/dist/deploy/workspace-deploy.js +19 -1
- package/dist/eject/workspace-connections.js +4 -0
- package/dist/email-catalog/registry.d.ts +4 -0
- package/dist/email-catalog/registry.js +79 -14
- package/dist/extensions/content-patch.js +14 -2
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/integrations/plugin.d.ts +10 -0
- package/dist/integrations/plugin.js +40 -6
- package/dist/jobs/actions/run-automation-now.d.ts +2 -1
- package/dist/jobs/actions/run-automation-now.js +11 -5
- package/dist/jobs/frontmatter.js +53 -2
- package/dist/jobs/run-now.d.ts +11 -1
- package/dist/jobs/run-now.js +42 -7
- package/dist/jobs/scheduler.d.ts +1 -0
- package/dist/jobs/scheduler.js +2 -1
- package/dist/localization/core-messages/ar-SA.js +4 -1
- package/dist/localization/core-messages/de-DE.js +4 -1
- package/dist/localization/core-messages/en-US.d.ts +4 -1
- package/dist/localization/core-messages/en-US.js +4 -1
- package/dist/localization/core-messages/es-ES.js +4 -1
- package/dist/localization/core-messages/fr-FR.js +4 -1
- package/dist/localization/core-messages/hi-IN.js +4 -1
- package/dist/localization/core-messages/ja-JP.js +4 -1
- package/dist/localization/core-messages/ko-KR.js +4 -1
- package/dist/localization/core-messages/pt-BR.js +4 -1
- package/dist/localization/core-messages/zh-CN.js +4 -1
- package/dist/localization/core-messages/zh-TW.js +4 -1
- package/dist/localization/core-messages.d.ts +4 -1
- package/dist/localization/default-messages.d.ts +2 -5
- package/dist/localization/default-messages.js +2 -5
- package/dist/mcp/build-server.d.ts +9 -0
- package/dist/mcp/build-server.js +37 -8
- package/dist/mcp-client/oauth-client.d.ts +7 -0
- package/dist/mcp-client/oauth-client.js +12 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/oauth-tokens/index.d.ts +1 -1
- package/dist/oauth-tokens/index.js +1 -1
- package/dist/oauth-tokens/lifecycle.d.ts +11 -0
- package/dist/oauth-tokens/lifecycle.js +17 -0
- package/dist/oauth-tokens/store.js +7 -0
- package/dist/observability/posthog-ai.d.ts +15 -1
- package/dist/observability/posthog-ai.js +24 -12
- package/dist/observability/traces.js +158 -28
- package/dist/onboarding/app-profile.js +2 -2
- package/dist/onboarding/plugin.js +10 -2
- package/dist/onboarding/types.d.ts +2 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.js +2 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/resources/store.js +13 -4
- package/dist/scripts/agent-engines/list-agent-engines.js +29 -3
- package/dist/scripts/db/check-scoping.js +9 -6
- package/dist/secrets/register-framework-secrets.js +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/action-discovery.js +5 -0
- package/dist/server/agent-chat/action-filters-a2a.d.ts +27 -3
- package/dist/server/agent-chat/action-filters-a2a.js +48 -9
- package/dist/server/agent-chat-plugin.js +36 -9
- package/dist/server/agent-discovery.js +43 -20
- package/dist/server/auth.js +18 -16
- package/dist/server/beta-opt-out-html.js +45 -4
- package/dist/server/better-auth-instance.d.ts +2 -1
- package/dist/server/better-auth-instance.js +23 -7
- package/dist/server/builder-browser.d.ts +4 -0
- package/dist/server/builder-browser.js +23 -1
- package/dist/server/builder-design-systems.d.ts +4 -1
- package/dist/server/builder-design-systems.js +87 -6
- package/dist/server/builder-oauth.d.ts +1 -7
- package/dist/server/builder-oauth.js +80 -163
- package/dist/server/core-routes-plugin.d.ts +29 -0
- package/dist/server/core-routes-plugin.js +113 -21
- package/dist/server/default-plugins.d.ts +18 -0
- package/dist/server/default-plugins.js +22 -0
- package/dist/server/edge.d.ts +1 -0
- package/dist/server/edge.js +1 -0
- package/dist/server/framework-request-handler.js +31 -3
- package/dist/server/google-oauth.d.ts +3 -0
- package/dist/server/google-oauth.js +3 -0
- package/dist/server/index.d.ts +4 -4
- package/dist/server/index.js +3 -3
- package/dist/server/onboarding-html.js +37 -3
- package/dist/server/workspace-provider-oauth.d.ts +6 -1
- package/dist/server/workspace-provider-oauth.js +72 -20
- package/dist/shared/agent-sidebar-url.d.ts +1 -0
- package/dist/shared/agent-sidebar-url.js +1 -0
- package/dist/shared/environment-lanes.d.ts +2 -0
- package/dist/shared/environment-lanes.js +3 -1
- package/dist/shared/index.d.ts +3 -1
- package/dist/shared/index.js +3 -1
- package/dist/shared/surface-visibility.d.ts +31 -0
- package/dist/shared/surface-visibility.js +57 -0
- package/dist/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/chat/app/routes.ts +3 -1
- package/dist/templates/chat/vitest.config.ts +8 -0
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/default/app/routes.ts +3 -1
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/tracking/registry.d.ts +11 -0
- package/dist/tracking/registry.js +5 -2
- package/dist/triggers/actions.js +10 -3
- package/dist/usage/store.js +23 -3
- package/dist/user-profile/actions/get-auth-methods.js +18 -5
- package/dist/vite/client.js +24 -5
- package/docs/content/actions-access-control.mdx +43 -4
- package/docs/content/actions-defining.mdx +16 -0
- package/docs/content/template-clips-capture-everywhere.mdx +29 -30
- package/docs/content/template-clips-developers.mdx +4 -4
- package/docs/content/template-clips.mdx +3 -1
- package/package.json +3 -3
- package/src/eject/workspace-connections.ts +4 -0
- package/src/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/chat/app/routes.ts +3 -1
- package/src/templates/chat/vitest.config.ts +8 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/default/app/routes.ts +3 -1
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
- /package/corpus/templates/dispatch/app/routes/{apps.$appId.tsx → apps.$appId.$.tsx} +0 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { DEFAULT_FACTORY_ID } from "../factory-graph/store.js";
|
|
2
|
+
import { factoryConfigRowId } from "./factory-scope.js";
|
|
3
|
+
|
|
4
|
+
export type FactoryConfigSqlRow = {
|
|
5
|
+
id: string;
|
|
6
|
+
org_id: string | null;
|
|
7
|
+
factory_id: string | null;
|
|
8
|
+
slack_workspace: string | null;
|
|
9
|
+
slack_channel_id: string | null;
|
|
10
|
+
slack_channel_name: string | null;
|
|
11
|
+
builder_slack_user_id: string | null;
|
|
12
|
+
polling_enabled: number | null;
|
|
13
|
+
last_slack_ts: string | null;
|
|
14
|
+
slack_history_cursor: string | null;
|
|
15
|
+
repository: string | null;
|
|
16
|
+
github_polling_enabled: number | null;
|
|
17
|
+
sentry_polling_enabled: number | null;
|
|
18
|
+
sentry_org_slug: string | null;
|
|
19
|
+
sentry_project_slug: string | null;
|
|
20
|
+
sentry_environment: string | null;
|
|
21
|
+
last_sentry_seen_at: string | null;
|
|
22
|
+
automation_failure_alerts_enabled: number | null;
|
|
23
|
+
automation_failure_alert_email: string | null;
|
|
24
|
+
last_automation_failure_alert_key: string | null;
|
|
25
|
+
last_automation_failure_alert_at: string | null;
|
|
26
|
+
owner_email: string | null;
|
|
27
|
+
created_at: string | null;
|
|
28
|
+
updated_at: string | null;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type FactoryConfigReconcilePlan = {
|
|
32
|
+
fromId: string;
|
|
33
|
+
row: FactoryConfigSqlRow;
|
|
34
|
+
deleteIds: string[];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function rowText(row: Record<string, unknown>, key: string): string | null {
|
|
38
|
+
return asText(row[key]);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function rowFlag(row: Record<string, unknown>, key: string): number | null {
|
|
42
|
+
const value = row[key];
|
|
43
|
+
if (value === null || value === undefined || value === "") return null;
|
|
44
|
+
return Number(value) === 1 ? 1 : 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function factoryConfigSqlRowFromQuery(
|
|
48
|
+
row: Record<string, unknown>,
|
|
49
|
+
): FactoryConfigSqlRow | null {
|
|
50
|
+
const id = rowText(row, "id");
|
|
51
|
+
if (!id) return null;
|
|
52
|
+
return {
|
|
53
|
+
id,
|
|
54
|
+
org_id: rowText(row, "org_id"),
|
|
55
|
+
factory_id: rowText(row, "factory_id"),
|
|
56
|
+
slack_workspace: rowText(row, "slack_workspace"),
|
|
57
|
+
slack_channel_id: rowText(row, "slack_channel_id"),
|
|
58
|
+
slack_channel_name: rowText(row, "slack_channel_name"),
|
|
59
|
+
builder_slack_user_id: rowText(row, "builder_slack_user_id"),
|
|
60
|
+
polling_enabled: rowFlag(row, "polling_enabled"),
|
|
61
|
+
last_slack_ts: rowText(row, "last_slack_ts"),
|
|
62
|
+
slack_history_cursor: rowText(row, "slack_history_cursor"),
|
|
63
|
+
repository: rowText(row, "repository"),
|
|
64
|
+
github_polling_enabled: rowFlag(row, "github_polling_enabled"),
|
|
65
|
+
sentry_polling_enabled: rowFlag(row, "sentry_polling_enabled"),
|
|
66
|
+
sentry_org_slug: rowText(row, "sentry_org_slug"),
|
|
67
|
+
sentry_project_slug: rowText(row, "sentry_project_slug"),
|
|
68
|
+
sentry_environment: rowText(row, "sentry_environment"),
|
|
69
|
+
last_sentry_seen_at: rowText(row, "last_sentry_seen_at"),
|
|
70
|
+
automation_failure_alerts_enabled: rowFlag(
|
|
71
|
+
row,
|
|
72
|
+
"automation_failure_alerts_enabled",
|
|
73
|
+
),
|
|
74
|
+
automation_failure_alert_email: rowText(
|
|
75
|
+
row,
|
|
76
|
+
"automation_failure_alert_email",
|
|
77
|
+
),
|
|
78
|
+
last_automation_failure_alert_key: rowText(
|
|
79
|
+
row,
|
|
80
|
+
"last_automation_failure_alert_key",
|
|
81
|
+
),
|
|
82
|
+
last_automation_failure_alert_at: rowText(
|
|
83
|
+
row,
|
|
84
|
+
"last_automation_failure_alert_at",
|
|
85
|
+
),
|
|
86
|
+
owner_email: rowText(row, "owner_email"),
|
|
87
|
+
created_at: rowText(row, "created_at"),
|
|
88
|
+
updated_at: rowText(row, "updated_at"),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function asText(value: unknown): string | null {
|
|
93
|
+
if (typeof value === "string") {
|
|
94
|
+
const text = value.trim();
|
|
95
|
+
return text.length > 0 ? text : null;
|
|
96
|
+
}
|
|
97
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function asFlag(value: unknown): number {
|
|
102
|
+
return Number(value) === 1 ? 1 : 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function pickText(
|
|
106
|
+
keep: string | null | undefined,
|
|
107
|
+
other: string | null | undefined,
|
|
108
|
+
): string | null {
|
|
109
|
+
return asText(keep) ?? asText(other);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function pickLater(
|
|
113
|
+
keep: string | null | undefined,
|
|
114
|
+
other: string | null | undefined,
|
|
115
|
+
): string | null {
|
|
116
|
+
const left = asText(keep);
|
|
117
|
+
const right = asText(other);
|
|
118
|
+
if (!left) return right;
|
|
119
|
+
if (!right) return left;
|
|
120
|
+
const leftNum = Number(left);
|
|
121
|
+
const rightNum = Number(right);
|
|
122
|
+
if (Number.isFinite(leftNum) && Number.isFinite(rightNum)) {
|
|
123
|
+
return leftNum >= rightNum ? left : right;
|
|
124
|
+
}
|
|
125
|
+
return left >= right ? left : right;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function isUniqueConstraintError(error: unknown): boolean {
|
|
129
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
130
|
+
return /unique constraint failed|duplicate key|primary key/i.test(message);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function mergeFactoryConfigRows(
|
|
134
|
+
keep: FactoryConfigSqlRow,
|
|
135
|
+
other: FactoryConfigSqlRow,
|
|
136
|
+
): FactoryConfigSqlRow {
|
|
137
|
+
const slackIdentity = mergeSlackIdentity(keep, other);
|
|
138
|
+
return {
|
|
139
|
+
...keep,
|
|
140
|
+
slack_workspace: slackIdentity.slack_workspace,
|
|
141
|
+
slack_channel_id: slackIdentity.slack_channel_id,
|
|
142
|
+
slack_channel_name: slackIdentity.slack_channel_name,
|
|
143
|
+
builder_slack_user_id: pickText(
|
|
144
|
+
keep.builder_slack_user_id,
|
|
145
|
+
other.builder_slack_user_id,
|
|
146
|
+
),
|
|
147
|
+
polling_enabled: Math.max(
|
|
148
|
+
asFlag(keep.polling_enabled),
|
|
149
|
+
asFlag(other.polling_enabled),
|
|
150
|
+
),
|
|
151
|
+
last_slack_ts: slackIdentity.last_slack_ts,
|
|
152
|
+
slack_history_cursor: slackIdentity.slack_history_cursor,
|
|
153
|
+
repository: pickText(keep.repository, other.repository),
|
|
154
|
+
github_polling_enabled: Math.max(
|
|
155
|
+
asFlag(keep.github_polling_enabled),
|
|
156
|
+
asFlag(other.github_polling_enabled),
|
|
157
|
+
),
|
|
158
|
+
sentry_polling_enabled: Math.max(
|
|
159
|
+
asFlag(keep.sentry_polling_enabled),
|
|
160
|
+
asFlag(other.sentry_polling_enabled),
|
|
161
|
+
),
|
|
162
|
+
sentry_org_slug: pickText(keep.sentry_org_slug, other.sentry_org_slug),
|
|
163
|
+
sentry_project_slug: pickText(
|
|
164
|
+
keep.sentry_project_slug,
|
|
165
|
+
other.sentry_project_slug,
|
|
166
|
+
),
|
|
167
|
+
sentry_environment: pickText(
|
|
168
|
+
keep.sentry_environment,
|
|
169
|
+
other.sentry_environment,
|
|
170
|
+
),
|
|
171
|
+
last_sentry_seen_at: pickLater(
|
|
172
|
+
keep.last_sentry_seen_at,
|
|
173
|
+
other.last_sentry_seen_at,
|
|
174
|
+
),
|
|
175
|
+
automation_failure_alerts_enabled: Math.max(
|
|
176
|
+
asFlag(keep.automation_failure_alerts_enabled),
|
|
177
|
+
asFlag(other.automation_failure_alerts_enabled),
|
|
178
|
+
),
|
|
179
|
+
automation_failure_alert_email: pickText(
|
|
180
|
+
keep.automation_failure_alert_email,
|
|
181
|
+
other.automation_failure_alert_email,
|
|
182
|
+
),
|
|
183
|
+
last_automation_failure_alert_key: pickText(
|
|
184
|
+
keep.last_automation_failure_alert_key,
|
|
185
|
+
other.last_automation_failure_alert_key,
|
|
186
|
+
),
|
|
187
|
+
last_automation_failure_alert_at: pickLater(
|
|
188
|
+
keep.last_automation_failure_alert_at,
|
|
189
|
+
other.last_automation_failure_alert_at,
|
|
190
|
+
),
|
|
191
|
+
owner_email: pickText(keep.owner_email, other.owner_email),
|
|
192
|
+
created_at: pickText(keep.created_at, other.created_at) ?? keep.created_at,
|
|
193
|
+
updated_at: pickLater(keep.updated_at, other.updated_at),
|
|
194
|
+
org_id: keep.org_id || other.org_id,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function planDefaultFactoryConfigReconciliation(
|
|
199
|
+
rows: FactoryConfigSqlRow[],
|
|
200
|
+
defaultFactoryId = DEFAULT_FACTORY_ID,
|
|
201
|
+
): FactoryConfigReconcilePlan[] {
|
|
202
|
+
const byOrg = new Map<string, FactoryConfigSqlRow[]>();
|
|
203
|
+
for (const row of rows) {
|
|
204
|
+
const orgId = asText(row.org_id);
|
|
205
|
+
const id = asText(row.id);
|
|
206
|
+
if (!orgId || !id) continue;
|
|
207
|
+
const group = byOrg.get(orgId) ?? [];
|
|
208
|
+
group.push({ ...row, id, org_id: orgId });
|
|
209
|
+
byOrg.set(orgId, group);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const plans: FactoryConfigReconcilePlan[] = [];
|
|
213
|
+
for (const [orgId, group] of byOrg) {
|
|
214
|
+
const canonicalId = factoryConfigRowId(orgId, defaultFactoryId);
|
|
215
|
+
const keepSource = group.find((row) => row.id === canonicalId) ?? group[0]!;
|
|
216
|
+
let merged: FactoryConfigSqlRow = {
|
|
217
|
+
...keepSource,
|
|
218
|
+
id: canonicalId,
|
|
219
|
+
org_id: orgId,
|
|
220
|
+
factory_id: defaultFactoryId,
|
|
221
|
+
};
|
|
222
|
+
const deleteIds: string[] = [];
|
|
223
|
+
for (const row of group) {
|
|
224
|
+
if (row.id === keepSource.id) continue;
|
|
225
|
+
merged = mergeFactoryConfigRows(merged, row);
|
|
226
|
+
deleteIds.push(row.id);
|
|
227
|
+
}
|
|
228
|
+
plans.push({
|
|
229
|
+
fromId: keepSource.id,
|
|
230
|
+
row: merged,
|
|
231
|
+
deleteIds,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
return plans;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export type SlackChannelConflictClear = {
|
|
238
|
+
id: string;
|
|
239
|
+
org_id: string;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
function mergeSlackIdentity(
|
|
243
|
+
keep: FactoryConfigSqlRow,
|
|
244
|
+
other: FactoryConfigSqlRow,
|
|
245
|
+
): Pick<
|
|
246
|
+
FactoryConfigSqlRow,
|
|
247
|
+
| "slack_workspace"
|
|
248
|
+
| "slack_channel_id"
|
|
249
|
+
| "slack_channel_name"
|
|
250
|
+
| "last_slack_ts"
|
|
251
|
+
| "slack_history_cursor"
|
|
252
|
+
> {
|
|
253
|
+
const keepChannel = asText(keep.slack_channel_id);
|
|
254
|
+
const otherChannel = asText(other.slack_channel_id);
|
|
255
|
+
if (!otherChannel || keepChannel === otherChannel) {
|
|
256
|
+
return {
|
|
257
|
+
slack_workspace: pickText(keep.slack_workspace, other.slack_workspace),
|
|
258
|
+
slack_channel_id: keepChannel ?? otherChannel,
|
|
259
|
+
slack_channel_name: pickText(
|
|
260
|
+
keep.slack_channel_name,
|
|
261
|
+
other.slack_channel_name,
|
|
262
|
+
),
|
|
263
|
+
last_slack_ts: pickLater(keep.last_slack_ts, other.last_slack_ts),
|
|
264
|
+
slack_history_cursor: pickText(
|
|
265
|
+
keep.slack_history_cursor,
|
|
266
|
+
other.slack_history_cursor,
|
|
267
|
+
),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
if (!keepChannel) {
|
|
271
|
+
return {
|
|
272
|
+
slack_workspace: other.slack_workspace,
|
|
273
|
+
slack_channel_id: other.slack_channel_id,
|
|
274
|
+
slack_channel_name: other.slack_channel_name,
|
|
275
|
+
last_slack_ts: other.last_slack_ts,
|
|
276
|
+
slack_history_cursor: other.slack_history_cursor,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
slack_workspace: keep.slack_workspace,
|
|
281
|
+
slack_channel_id: keep.slack_channel_id,
|
|
282
|
+
slack_channel_name: keep.slack_channel_name,
|
|
283
|
+
last_slack_ts: keep.last_slack_ts,
|
|
284
|
+
slack_history_cursor: keep.slack_history_cursor,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export function planSlackChannelConflictClears(
|
|
289
|
+
rows: FactoryConfigSqlRow[],
|
|
290
|
+
): SlackChannelConflictClear[] {
|
|
291
|
+
const groups = new Map<string, FactoryConfigSqlRow[]>();
|
|
292
|
+
for (const row of rows) {
|
|
293
|
+
const orgId = asText(row.org_id);
|
|
294
|
+
const channelId = asText(row.slack_channel_id);
|
|
295
|
+
const id = asText(row.id);
|
|
296
|
+
if (!orgId || !channelId || !id) continue;
|
|
297
|
+
const key = `${orgId}\0${channelId}`;
|
|
298
|
+
const group = groups.get(key) ?? [];
|
|
299
|
+
group.push({ ...row, id, org_id: orgId });
|
|
300
|
+
groups.set(key, group);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const clears: SlackChannelConflictClear[] = [];
|
|
304
|
+
for (const group of groups.values()) {
|
|
305
|
+
if (group.length < 2) continue;
|
|
306
|
+
const ranked = [...group].sort((left, right) => {
|
|
307
|
+
const polling =
|
|
308
|
+
asFlag(right.polling_enabled) - asFlag(left.polling_enabled);
|
|
309
|
+
if (polling !== 0) return polling;
|
|
310
|
+
const updated = (right.updated_at ?? "").localeCompare(
|
|
311
|
+
left.updated_at ?? "",
|
|
312
|
+
);
|
|
313
|
+
if (updated !== 0) return updated;
|
|
314
|
+
return left.id.localeCompare(right.id);
|
|
315
|
+
});
|
|
316
|
+
for (const row of ranked.slice(1)) {
|
|
317
|
+
clears.push({ id: row.id, org_id: row.org_id! });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return clears;
|
|
321
|
+
}
|
|
@@ -23,6 +23,14 @@ export const factoryIdSchema = z
|
|
|
23
23
|
.max(120)
|
|
24
24
|
.regex(/^[a-z0-9][a-z0-9-]*$/);
|
|
25
25
|
|
|
26
|
+
export const builderSlackUserIdSchema = z
|
|
27
|
+
.string()
|
|
28
|
+
.trim()
|
|
29
|
+
.max(32)
|
|
30
|
+
.refine((value) => value === "" || /^[UW][A-Z0-9]+$/i.test(value), {
|
|
31
|
+
message: "Builder Slack member id must look like U01234567.",
|
|
32
|
+
});
|
|
33
|
+
|
|
26
34
|
export function factoryConfigRowId(orgId: string, factoryId: string): string {
|
|
27
35
|
return `${orgId}:${factoryId}`;
|
|
28
36
|
}
|
|
@@ -222,7 +230,13 @@ function readFrontmatterFactoryId(content: string): string | undefined {
|
|
|
222
230
|
return value.replace(/^(\"|')|((\"|')$)/g, "");
|
|
223
231
|
}
|
|
224
232
|
|
|
225
|
-
export function readAutomationFactoryId(
|
|
233
|
+
export function readAutomationFactoryId(
|
|
234
|
+
meta: object,
|
|
235
|
+
content: string,
|
|
236
|
+
path: string,
|
|
237
|
+
): string {
|
|
238
|
+
const fromPath = readFactoryIdFromAutomationPath(path);
|
|
239
|
+
if (fromPath) return fromPath;
|
|
226
240
|
const fromContent = readFrontmatterFactoryId(content);
|
|
227
241
|
return resolveAutomationFactoryId(
|
|
228
242
|
fromContent ? { ...meta, factoryId: fromContent } : meta,
|
|
@@ -247,6 +261,15 @@ export function isLegacyFactoryAutomationPath(path: string): boolean {
|
|
|
247
261
|
return /^jobs\/factory-[^/]+\.md$/.test(path);
|
|
248
262
|
}
|
|
249
263
|
|
|
264
|
+
/** Scheduler trigger names keep the nested path; role allowlists use the leaf. */
|
|
265
|
+
export function factoryAutomationLeafName(nameOrPath: string): string {
|
|
266
|
+
const withoutJobsPrefix = nameOrPath
|
|
267
|
+
.replace(/^jobs\//, "")
|
|
268
|
+
.replace(/\.md$/, "");
|
|
269
|
+
const slash = withoutJobsPrefix.lastIndexOf("/");
|
|
270
|
+
return slash === -1 ? withoutJobsPrefix : withoutJobsPrefix.slice(slash + 1);
|
|
271
|
+
}
|
|
272
|
+
|
|
250
273
|
export function readFactoryIdFromAutomationPath(path: string): string | null {
|
|
251
274
|
const match = path.match(/^jobs\/factories\/([^/]+)\/factory-[^/]+\.md$/);
|
|
252
275
|
return match?.[1] ?? null;
|
|
@@ -294,7 +317,7 @@ export async function assertUniqueSlackChannelForFactory(
|
|
|
294
317
|
eq(triageConfig.slackChannelId, normalized),
|
|
295
318
|
),
|
|
296
319
|
)
|
|
297
|
-
).find((row) => row.factoryId
|
|
320
|
+
).find((row) => row.factoryId !== factoryId);
|
|
298
321
|
if (conflict) {
|
|
299
322
|
throw new Error(
|
|
300
323
|
"That Slack channel is already used by another Factory in this workspace.",
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ActionRunContext } from "@agent-native/core/action";
|
|
2
2
|
import { listAutomationDefinitions } from "@agent-native/core/triggers";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
factoryAutomationLeafName,
|
|
6
|
+
readAutomationFactoryId,
|
|
7
|
+
} from "./factory-scope.js";
|
|
5
8
|
import type { WorkspaceMemberIdentity } from "./require-workspace-member.js";
|
|
6
9
|
|
|
7
10
|
const FACTORY_AUTOMATION_NAMES = {
|
|
@@ -39,7 +42,10 @@ export async function requireFactoryAutomation(
|
|
|
39
42
|
}
|
|
40
43
|
const lineage = context.automation;
|
|
41
44
|
const expectedNames = FACTORY_AUTOMATION_NAMES[role];
|
|
42
|
-
if (
|
|
45
|
+
if (
|
|
46
|
+
!lineage ||
|
|
47
|
+
!expectedNames.has(factoryAutomationLeafName(lineage.triggerName))
|
|
48
|
+
) {
|
|
43
49
|
throw new Error(
|
|
44
50
|
"The action was not invoked by a governed Factory automation.",
|
|
45
51
|
);
|
|
@@ -71,8 +77,11 @@ export async function requireFactoryAutomation(
|
|
|
71
77
|
}
|
|
72
78
|
if (
|
|
73
79
|
expectedFactoryId &&
|
|
74
|
-
readAutomationFactoryId(
|
|
75
|
-
|
|
80
|
+
readAutomationFactoryId(
|
|
81
|
+
definition.meta,
|
|
82
|
+
definition.resource.content,
|
|
83
|
+
definition.resource.path,
|
|
84
|
+
) !== expectedFactoryId
|
|
76
85
|
) {
|
|
77
86
|
throw new Error(
|
|
78
87
|
"The action was not invoked by a governed Factory automation.",
|
|
@@ -1,6 +1,128 @@
|
|
|
1
|
-
import { runMigrations } from "@agent-native/core/db";
|
|
1
|
+
import { runMigrations, type DbExec } from "@agent-native/core/db";
|
|
2
2
|
import { defineNitroPlugin } from "@agent-native/core/server";
|
|
3
3
|
|
|
4
|
+
import {
|
|
5
|
+
factoryConfigSqlRowFromQuery,
|
|
6
|
+
isUniqueConstraintError,
|
|
7
|
+
planDefaultFactoryConfigReconciliation,
|
|
8
|
+
planSlackChannelConflictClears,
|
|
9
|
+
type FactoryConfigSqlRow,
|
|
10
|
+
} from "../lib/factory-config-reconcile.js";
|
|
11
|
+
|
|
12
|
+
async function writeReconciledFactoryConfig(
|
|
13
|
+
exec: DbExec,
|
|
14
|
+
plan: {
|
|
15
|
+
fromId: string;
|
|
16
|
+
row: FactoryConfigSqlRow;
|
|
17
|
+
deleteIds: string[];
|
|
18
|
+
},
|
|
19
|
+
): Promise<void> {
|
|
20
|
+
const { row } = plan;
|
|
21
|
+
await exec.execute({
|
|
22
|
+
sql: `UPDATE factory_config SET
|
|
23
|
+
id = ?,
|
|
24
|
+
factory_id = ?,
|
|
25
|
+
slack_workspace = ?,
|
|
26
|
+
slack_channel_id = ?,
|
|
27
|
+
slack_channel_name = ?,
|
|
28
|
+
builder_slack_user_id = ?,
|
|
29
|
+
polling_enabled = ?,
|
|
30
|
+
last_slack_ts = ?,
|
|
31
|
+
slack_history_cursor = ?,
|
|
32
|
+
repository = ?,
|
|
33
|
+
github_polling_enabled = ?,
|
|
34
|
+
sentry_polling_enabled = ?,
|
|
35
|
+
sentry_org_slug = ?,
|
|
36
|
+
sentry_project_slug = ?,
|
|
37
|
+
sentry_environment = ?,
|
|
38
|
+
last_sentry_seen_at = ?,
|
|
39
|
+
automation_failure_alerts_enabled = ?,
|
|
40
|
+
automation_failure_alert_email = ?,
|
|
41
|
+
last_automation_failure_alert_key = ?,
|
|
42
|
+
last_automation_failure_alert_at = ?,
|
|
43
|
+
owner_email = ?,
|
|
44
|
+
created_at = ?,
|
|
45
|
+
updated_at = ?
|
|
46
|
+
WHERE id = ? AND org_id = ?`,
|
|
47
|
+
args: [
|
|
48
|
+
row.id,
|
|
49
|
+
row.factory_id,
|
|
50
|
+
row.slack_workspace ?? "primary",
|
|
51
|
+
row.slack_channel_id,
|
|
52
|
+
row.slack_channel_name,
|
|
53
|
+
row.builder_slack_user_id,
|
|
54
|
+
row.polling_enabled ?? 0,
|
|
55
|
+
row.last_slack_ts,
|
|
56
|
+
row.slack_history_cursor,
|
|
57
|
+
row.repository,
|
|
58
|
+
row.github_polling_enabled ?? 0,
|
|
59
|
+
row.sentry_polling_enabled ?? 0,
|
|
60
|
+
row.sentry_org_slug,
|
|
61
|
+
row.sentry_project_slug,
|
|
62
|
+
row.sentry_environment,
|
|
63
|
+
row.last_sentry_seen_at,
|
|
64
|
+
row.automation_failure_alerts_enabled ?? 1,
|
|
65
|
+
row.automation_failure_alert_email,
|
|
66
|
+
row.last_automation_failure_alert_key,
|
|
67
|
+
row.last_automation_failure_alert_at,
|
|
68
|
+
row.owner_email ?? "",
|
|
69
|
+
row.created_at ?? new Date().toISOString(),
|
|
70
|
+
row.updated_at ?? new Date().toISOString(),
|
|
71
|
+
plan.fromId,
|
|
72
|
+
row.org_id,
|
|
73
|
+
],
|
|
74
|
+
});
|
|
75
|
+
for (const deleteId of plan.deleteIds) {
|
|
76
|
+
await exec.execute({
|
|
77
|
+
sql: `DELETE FROM factory_config WHERE id = ? AND org_id = ?`,
|
|
78
|
+
args: [deleteId, row.org_id],
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function reconcileDefaultFactoryConfigRows(): Promise<void> {
|
|
84
|
+
const { getDbExec } = await import("@agent-native/core/db");
|
|
85
|
+
const exec = getDbExec();
|
|
86
|
+
const defaultFactoryId = "product-feedback";
|
|
87
|
+
const configRows = await exec.execute({
|
|
88
|
+
sql: `SELECT * FROM factory_config
|
|
89
|
+
WHERE factory_id IS NULL OR factory_id = '' OR factory_id = ?`,
|
|
90
|
+
args: [defaultFactoryId],
|
|
91
|
+
});
|
|
92
|
+
const rows = (configRows.rows ?? [])
|
|
93
|
+
.map((row) => factoryConfigSqlRowFromQuery(row as Record<string, unknown>))
|
|
94
|
+
.filter((row): row is FactoryConfigSqlRow => row !== null);
|
|
95
|
+
for (const plan of planDefaultFactoryConfigReconciliation(
|
|
96
|
+
rows,
|
|
97
|
+
defaultFactoryId,
|
|
98
|
+
)) {
|
|
99
|
+
await writeReconciledFactoryConfig(exec, plan);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function clearDuplicateSlackChannelAssignments(): Promise<void> {
|
|
104
|
+
const { getDbExec } = await import("@agent-native/core/db");
|
|
105
|
+
const exec = getDbExec();
|
|
106
|
+
const configRows = await exec.execute({
|
|
107
|
+
sql: `SELECT * FROM factory_config`,
|
|
108
|
+
args: [],
|
|
109
|
+
});
|
|
110
|
+
const rows = (configRows.rows ?? [])
|
|
111
|
+
.map((row) => factoryConfigSqlRowFromQuery(row as Record<string, unknown>))
|
|
112
|
+
.filter((row): row is FactoryConfigSqlRow => row !== null);
|
|
113
|
+
for (const clear of planSlackChannelConflictClears(rows)) {
|
|
114
|
+
await exec.execute({
|
|
115
|
+
sql: `UPDATE factory_config SET
|
|
116
|
+
slack_channel_id = NULL,
|
|
117
|
+
slack_channel_name = NULL,
|
|
118
|
+
last_slack_ts = NULL,
|
|
119
|
+
slack_history_cursor = NULL
|
|
120
|
+
WHERE id = ? AND org_id = ?`,
|
|
121
|
+
args: [clear.id, clear.org_id],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
4
126
|
const migrations = [
|
|
5
127
|
{
|
|
6
128
|
version: 1,
|
|
@@ -339,10 +461,20 @@ const migrations = [
|
|
|
339
461
|
const id = String(row.id ?? "");
|
|
340
462
|
if (!orgId || id.includes(":")) continue;
|
|
341
463
|
const nextId = `${orgId}:${defaultFactoryId}`;
|
|
342
|
-
await exec.execute({
|
|
343
|
-
sql: `
|
|
344
|
-
args: [nextId,
|
|
464
|
+
const existing = await exec.execute({
|
|
465
|
+
sql: `SELECT id FROM factory_config WHERE id = ? AND org_id = ?`,
|
|
466
|
+
args: [nextId, orgId],
|
|
345
467
|
});
|
|
468
|
+
if ((existing.rows?.length ?? 0) > 0) continue;
|
|
469
|
+
try {
|
|
470
|
+
await exec.execute({
|
|
471
|
+
sql: `UPDATE factory_config SET id = ? WHERE id = ? AND org_id = ?`,
|
|
472
|
+
args: [nextId, id, orgId],
|
|
473
|
+
});
|
|
474
|
+
} catch (error) {
|
|
475
|
+
if (isUniqueConstraintError(error)) continue;
|
|
476
|
+
throw error;
|
|
477
|
+
}
|
|
346
478
|
}
|
|
347
479
|
},
|
|
348
480
|
},
|
|
@@ -368,12 +500,24 @@ const migrations = [
|
|
|
368
500
|
{
|
|
369
501
|
version: 24,
|
|
370
502
|
name: "factory-config-org-slack-channel-unique",
|
|
503
|
+
run: async () => {
|
|
504
|
+
await reconcileDefaultFactoryConfigRows();
|
|
505
|
+
await clearDuplicateSlackChannelAssignments();
|
|
506
|
+
},
|
|
371
507
|
sql: `
|
|
372
508
|
CREATE UNIQUE INDEX IF NOT EXISTS factory_config_org_slack_channel_idx
|
|
373
509
|
ON factory_config (org_id, slack_channel_id)
|
|
374
510
|
WHERE slack_channel_id IS NOT NULL AND slack_channel_id != '';
|
|
375
511
|
`,
|
|
376
512
|
},
|
|
513
|
+
{
|
|
514
|
+
version: 25,
|
|
515
|
+
name: "factory-config-reconcile-legacy-rows",
|
|
516
|
+
sql: {},
|
|
517
|
+
run: async () => {
|
|
518
|
+
await reconcileDefaultFactoryConfigRows();
|
|
519
|
+
},
|
|
520
|
+
},
|
|
377
521
|
];
|
|
378
522
|
|
|
379
523
|
export const runFactoryMigrations = runMigrations(migrations, {
|
|
@@ -39,8 +39,6 @@ import {
|
|
|
39
39
|
} from "../triage/review-skill-alignment.js";
|
|
40
40
|
|
|
41
41
|
const LEGACY_JOB_PATH = "jobs/factory-observation-scheduler.md";
|
|
42
|
-
const DEFAULT_SLACK_CHANNEL_ID = "C0ATH3CCZT4";
|
|
43
|
-
const DEFAULT_SLACK_CHANNEL_NAME = "product-agent-native-feedback";
|
|
44
42
|
const FAILURE_ALERT_COOLDOWN_MS = 15 * 60_000;
|
|
45
43
|
|
|
46
44
|
type AutomationRunFinishedEvent = {
|
|
@@ -627,6 +625,7 @@ export async function syncFactoryAutomationEnabledStates(
|
|
|
627
625
|
readAutomationFactoryId(
|
|
628
626
|
definition.meta,
|
|
629
627
|
definition.resource.content,
|
|
628
|
+
definition.resource.path,
|
|
630
629
|
) === factoryId,
|
|
631
630
|
)
|
|
632
631
|
.map(async (definition) => {
|
|
@@ -687,16 +686,15 @@ async function ensureDefaultTriageConfig(
|
|
|
687
686
|
}
|
|
688
687
|
const now = new Date().toISOString();
|
|
689
688
|
const repository = defaultRepository();
|
|
690
|
-
const pollingEnabled = 1;
|
|
691
689
|
const githubPollingEnabled = defaultGithubPollingEnabled() ? 1 : 0;
|
|
692
690
|
await db.insert(triageConfig).values({
|
|
693
691
|
id: factoryConfigRowId(orgId, factoryId),
|
|
694
692
|
factoryId,
|
|
695
693
|
slackWorkspace: "primary",
|
|
696
|
-
slackChannelId:
|
|
697
|
-
slackChannelName:
|
|
694
|
+
slackChannelId: null,
|
|
695
|
+
slackChannelName: null,
|
|
698
696
|
builderSlackUserId: null,
|
|
699
|
-
pollingEnabled,
|
|
697
|
+
pollingEnabled: 0,
|
|
700
698
|
githubPollingEnabled,
|
|
701
699
|
sentryPollingEnabled: 0,
|
|
702
700
|
lastSlackTs: null,
|
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
import baseConfig from "@agent-native/core/vitest-config";
|
|
2
|
-
import { mergeConfig } from "vitest/config";
|
|
2
|
+
import { defineConfig, mergeConfig } from "vitest/config";
|
|
3
3
|
|
|
4
4
|
import viteConfig from "./vite.config";
|
|
5
5
|
|
|
6
6
|
// Kept separate from vite.config.ts so the production config never imports
|
|
7
7
|
// vitest: `agent-native build` loads vite.config.ts in installs where vitest
|
|
8
8
|
// is absent.
|
|
9
|
-
export default mergeConfig(
|
|
9
|
+
export default mergeConfig(
|
|
10
|
+
viteConfig,
|
|
11
|
+
mergeConfig(
|
|
12
|
+
baseConfig,
|
|
13
|
+
defineConfig({
|
|
14
|
+
test: {
|
|
15
|
+
exclude: [
|
|
16
|
+
"**/node_modules/**",
|
|
17
|
+
"**/.git/**",
|
|
18
|
+
"**/dist/**",
|
|
19
|
+
"**/.react-router/**",
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
}),
|
|
23
|
+
),
|
|
24
|
+
);
|
|
@@ -19,10 +19,17 @@ data, and generated extension/app content may mention credential **names** such
|
|
|
19
19
|
as `OPENAI_API_KEY`, but must not contain real API keys, tokens, webhook URLs,
|
|
20
20
|
signing secrets, OAuth refresh tokens, or private Builder/customer data.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
`${keys.NAME}` substitution.
|
|
25
|
-
|
|
22
|
+
Provider secret values are supplied at runtime through the encrypted
|
|
23
|
+
`app_secrets` vault, `saveCredential` / `resolveCredential`, OAuth, or
|
|
24
|
+
`${keys.NAME}` substitution. Deployment configuration is reserved for
|
|
25
|
+
deploy-level secrets and non-provider configuration. Examples must use obvious
|
|
26
|
+
placeholders such as `<OPENAI_API_KEY>` or `${keys.SLACK_WEBHOOK}`, not
|
|
27
|
+
real-looking copied values.
|
|
28
|
+
|
|
29
|
+
Provider credentials and provider account identifiers are workspace data. Use
|
|
30
|
+
standard workspace connections and org/workspace vault scopes; never put them
|
|
31
|
+
in `.env` or deployment environment variables, and never add a provider-specific
|
|
32
|
+
action or startup bootstrap just to write a credential for one organization.
|
|
26
33
|
|
|
27
34
|
## Credential Modeling Preflight
|
|
28
35
|
|
|
@@ -22,7 +22,10 @@ export function meta() {
|
|
|
22
22
|
|
|
23
23
|
export default function SettingsRoute() {
|
|
24
24
|
const t = useT();
|
|
25
|
-
|
|
25
|
+
// /extensions redirects here and the agent's own navigate instructions list
|
|
26
|
+
// "extensions" as a workspace view, so the settings tab must exist too —
|
|
27
|
+
// otherwise /settings/extensions silently falls back to General.
|
|
28
|
+
const agentSettingsTabs = useAgentSettingsTabs({ extensionTools: true });
|
|
26
29
|
useSetPageTitle(t("settings.title"));
|
|
27
30
|
|
|
28
31
|
const generalSearchEntries = useMemo<SettingsSearchEntry[]>(
|