spine-framework 0.3.145 → 0.4.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/.env.example +76 -0
- package/.framework/.spine-manifest.json +19 -0
- package/.framework/cli/commands/agents.ts +61 -33
- package/.framework/cli/commands/auth.ts +60 -28
- package/.framework/cli/commands/create-app.ts +212 -80
- package/.framework/cli/commands/dev.ts +184 -68
- package/.framework/cli/commands/doctor.ts +324 -152
- package/.framework/cli/commands/generate.ts +119 -68
- package/.framework/cli/commands/init.ts +141 -242
- package/.framework/cli/commands/install-app.ts +1336 -314
- package/.framework/cli/commands/items.ts +31 -29
- package/.framework/cli/commands/migrate.ts +299 -156
- package/.framework/cli/commands/migrations.ts +62 -30
- package/.framework/cli/commands/pipelines.ts +31 -29
- package/.framework/cli/commands/status.ts +105 -45
- package/.framework/cli/commands/system.ts +47 -42
- package/.framework/cli/commands/test.ts +161 -102
- package/.framework/cli/commands/upgrade.ts +260 -0
- package/.framework/cli/commands/validate-app.ts +517 -161
- package/.framework/cli/context.ts +117 -85
- package/.framework/cli/env-loader.ts +74 -43
- package/.framework/cli/index.ts +70 -46
- package/.framework/cli/lib/project-files.ts +404 -0
- package/.framework/docs/guides/testing-guide.md +1 -1
- package/.framework/docs/runtime-types.md +72 -72
- package/.framework/functions/_shared/access.ts +84 -0
- package/.framework/functions/_shared/agent-runner.ts +5051 -1026
- package/.framework/functions/_shared/app-manifest.ts +214 -94
- package/.framework/functions/_shared/ast.ts +214 -0
- package/.framework/functions/_shared/audit.ts +91 -55
- package/.framework/functions/_shared/cil.ts +368 -127
- package/.framework/functions/_shared/db.ts +337 -68
- package/.framework/functions/_shared/funnel.ts +228 -0
- package/.framework/functions/_shared/geo.ts +105 -0
- package/.framework/functions/_shared/hash-api-key.ts +94 -17
- package/.framework/functions/_shared/index.ts +22 -224
- package/.framework/functions/_shared/kb.ts +832 -58
- package/.framework/functions/_shared/llm.ts +118 -18
- package/.framework/functions/_shared/logging.ts +317 -19
- package/.framework/functions/_shared/middleware.ts +701 -131
- package/.framework/functions/_shared/notify.ts +70 -0
- package/.framework/functions/_shared/outcomes.ts +34 -19
- package/.framework/functions/_shared/permissions.ts +501 -315
- package/.framework/functions/_shared/pipeline-runner.ts +704 -155
- package/.framework/functions/_shared/principal.ts +436 -263
- package/.framework/functions/_shared/rate-limit.ts +233 -0
- package/.framework/functions/_shared/resolve-credentials.ts +86 -19
- package/.framework/functions/_shared/resolve-ids.ts +203 -139
- package/.framework/functions/_shared/retry-deliveries.ts +51 -16
- package/.framework/functions/_shared/schema-utils.ts +602 -521
- package/.framework/functions/_shared/security.ts +345 -0
- package/.framework/functions/_shared/testing.ts +197 -172
- package/.framework/functions/_shared/tracing.ts +351 -21
- package/.framework/functions/_shared/trigger-engine.ts +425 -136
- package/.framework/functions/_shared/webhook-registration.ts +71 -70
- package/.framework/functions/_shared/webhook-registry.ts +126 -83
- package/.framework/functions/account-nodes.ts +30 -30
- package/.framework/functions/adapters/generic-webhook-inbound.ts +49 -16
- package/.framework/functions/adapters/generic-webhook-outbound.ts +17 -17
- package/.framework/functions/adapters/openai-outbound.ts +15 -16
- package/.framework/functions/admin-data.ts +596 -173
- package/.framework/functions/admin-funnel.ts +64 -60
- package/.framework/functions/admin-install-funnel.ts +84 -66
- package/.framework/functions/admin-signals.ts +69 -51
- package/.framework/functions/ai-agents.ts +431 -106
- package/.framework/functions/ai-interactions.ts +186 -112
- package/.framework/functions/api-keys.ts +107 -107
- package/.framework/functions/apps.ts +154 -136
- package/.framework/functions/auth.ts +83 -65
- package/.framework/functions/cil-agent-ingest.ts +189 -232
- package/.framework/functions/cil-agent.ts +433 -177
- package/.framework/functions/cil-callmap.ts +642 -430
- package/.framework/functions/cil-config.ts +139 -135
- package/.framework/functions/cil-context.ts +214 -127
- package/.framework/functions/cil-doc.ts +587 -458
- package/.framework/functions/cil-embeddings.ts +453 -364
- package/.framework/functions/cil-graph.ts +427 -142
- package/.framework/functions/cil-ingest.ts +1418 -1154
- package/.framework/functions/cil-pipeline.ts +276 -21
- package/.framework/functions/cil-project.ts +659 -132
- package/.framework/functions/cil-validate.ts +198 -164
- package/.framework/functions/debug-auth.ts +57 -55
- package/.framework/functions/deliveries.ts +80 -21
- package/.framework/functions/embeddings.ts +1023 -318
- package/.framework/functions/eval-harness.ts +146 -108
- package/.framework/functions/integration-outbound.ts +205 -75
- package/.framework/functions/integration-routes.ts +128 -23
- package/.framework/functions/integrations.ts +125 -100
- package/.framework/functions/invites.ts +1095 -460
- package/.framework/functions/item-progress.ts +158 -102
- package/.framework/functions/kb.ts +34 -10
- package/.framework/functions/logs.ts +133 -133
- package/.framework/functions/observability.ts +152 -122
- package/.framework/functions/pipeline-executions.ts +147 -132
- package/.framework/functions/pipelines.ts +134 -119
- package/.framework/functions/prompt-configs.ts +96 -80
- package/.framework/functions/roles.ts +112 -82
- package/.framework/functions/security.ts +450 -0
- package/.framework/functions/system-cron.ts +117 -80
- package/.framework/functions/system.ts +158 -98
- package/.framework/functions/tests.ts +29 -29
- package/.framework/functions/timers.ts +94 -95
- package/.framework/functions/trigger-scheduler.ts +10 -0
- package/.framework/functions/triggers.ts +179 -149
- package/.framework/functions/types.ts +137 -125
- package/.framework/mcp/index.ts +133 -0
- package/.framework/mcp/load-env.ts +60 -0
- package/.framework/mcp/shared/app-manifest.ts +275 -0
- package/.framework/mcp/shared/db.ts +477 -0
- package/.framework/mcp/shared/kb.ts +118 -0
- package/.framework/mcp/tools/architect.ts +431 -0
- package/.framework/mcp/tools/cil/context.ts +345 -0
- package/.framework/mcp/tools/cil/graph.ts +242 -0
- package/.framework/mcp/tools/cil/ingest.ts +1217 -0
- package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +693 -0
- package/.framework/mcp/tools/cil/pipeline.ts +767 -0
- package/.framework/mcp/tools/cil/project.ts +791 -0
- package/.framework/mcp/tools/cil/retrieval.ts +336 -0
- package/.framework/mcp/tools/cil/search-core.ts +454 -0
- package/.framework/mcp/tools/cil/search.ts +97 -0
- package/.framework/mcp/tools/cil/suggest.ts +186 -0
- package/.framework/mcp/tools/cil/validate.ts +1369 -0
- package/.framework/mcp/tools/kb/delete.ts +139 -0
- package/.framework/mcp/tools/kb/index.ts +52 -0
- package/.framework/mcp/tools/kb/ingest.ts +84 -0
- package/.framework/mcp/tools/kb/list-types.ts +102 -0
- package/.framework/mcp/tools/kb/publish.ts +100 -0
- package/.framework/mcp/tools/kb/reindex.ts +86 -0
- package/.framework/mcp/tools/kb/revoke.ts +85 -0
- package/.framework/mcp/tools/kb/search.ts +101 -0
- package/.framework/mcp/tools/kb/upsert.ts +125 -0
- package/.framework/mcp/tools/observability.ts +510 -0
- package/.framework/migrations/001_core_schema.sql +15 -0
- package/.framework/migrations/002_core_rls_and_functions.sql +15 -0
- package/.framework/migrations/003_core_system_data.sql +16 -1
- package/.framework/migrations/004_core_rpc_and_broker.sql +17 -1
- package/.framework/migrations/005_core_observability.sql +17 -1
- package/.framework/migrations/006_security_hardening_rls.sql +15 -0
- package/.framework/migrations/007_kb_article_list.sql +17 -1
- package/.framework/migrations/008_items_target.sql +15 -0
- package/.framework/migrations/009_roles_slug_unique.sql +15 -0
- package/.framework/migrations/010_auth_user_trigger.sql +15 -0
- package/.framework/migrations/011_spine_system_account.sql +16 -0
- package/.framework/migrations/012_service_role_grants.sql +16 -0
- package/.framework/migrations/013_get_account_apps_role_filter.sql +15 -0
- package/.framework/migrations/014_apps_required_roles.sql +16 -0
- package/.framework/migrations/015_types_kind_slug_unique.sql +15 -0
- package/.framework/migrations/016_cil_types.sql +281 -0
- package/.framework/migrations/017_cil_stable_ids.sql +37 -0
- package/.framework/migrations/018_runtime_tables.sql +129 -0
- package/.framework/migrations/019_agent_prompt_columns.sql +56 -0
- package/.framework/migrations/020_schema_reconciliation.sql +67 -0
- package/.framework/migrations/021_kb_embedding_lifecycle.sql +31 -0
- package/.framework/migrations/032_cil_status_migration.sql +73 -0
- package/.framework/migrations/033_cil_versioning.sql +73 -0
- package/.framework/migrations/034_match_embeddings_knn.sql +115 -0
- package/.framework/migrations/035_rate_limits.sql +55 -0
- package/.framework/migrations/036_demo_record_flags.sql +72 -0
- package/.framework/migrations/037_kb_types_canonical.sql +244 -0
- package/.framework/migrations/038_drop_demo_record_flags.sql +38 -0
- package/.framework/migrations/042_registration_hierarchy.sql +309 -0
- package/.framework/migrations/043_policy_actor_cleanup.sql +39 -0
- package/.framework/migrations/044_match_embeddings_filtered_knn.sql +151 -0
- package/.framework/migrations/045_security_critical_rls.sql +139 -0
- package/.framework/migrations/046_security_missing_rls.sql +79 -0
- package/.framework/migrations/047_people_updated_by.sql +27 -0
- package/.framework/migrations/048_watcher_last_seen_at.sql +24 -0
- package/.framework/migrations/049_security_blocklist.sql +148 -0
- package/.framework/migrations/050_notifications.sql +49 -0
- package/.framework/migrations/051_message_agent_fields.sql +74 -0
- package/.framework/migrations/052_registration_security.sql +421 -0
- package/.framework/migrations/053_builtin_action_seeds.sql +66 -0
- package/.framework/migrations/054_kb_ingest_lease.sql +157 -0
- package/.framework/migrations/055_type_id_drift_reconciliation.sql +33 -0
- package/.framework/migrations/056_slug_column_reconciliation.sql +38 -0
- package/.framework/migrations/057_pipelines_slug_identity.sql +14 -0
- package/.framework/migrations/058_account_data_field_declarations.sql +53 -0
- package/.framework/migrations/059_registration_placement_fixes.sql +269 -0
- package/.framework/migrations/060_account_person_record_permissions.sql +38 -0
- package/.framework/migrations/061_fk_dedup.sql +32 -0
- package/.framework/public/spine-logo.svg +10 -3
- package/.framework/scripts/app-install-cli.ts +190 -93
- package/.framework/scripts/assemble-frontend.sh +127 -44
- package/.framework/scripts/assemble-functions.sh +128 -30
- package/.framework/scripts/boundary-check.sh +6 -2
- package/.framework/scripts/build-manifest.sh +24 -68
- package/.framework/scripts/check-core-integrity.sh +15 -76
- package/.framework/scripts/checksum-manifest.mts +343 -0
- package/.framework/scripts/cil-migrate-markers.ts +403 -0
- package/.framework/scripts/fix-cil-markers.mjs +176 -0
- package/.framework/scripts/verify-integrity.sh +21 -57
- package/.framework/scripts/verify-manifest.mts +305 -0
- package/.framework/seeds/types/funnel_signal_use.json +74 -21
- package/.framework/seeds/types/spine_instance.json +73 -21
- package/.framework/src/App.tsx +118 -72
- package/.framework/src/apps/admin/index.tsx +855 -58
- package/.framework/src/components/AppWrapper.tsx +43 -45
- package/.framework/src/components/CustomAppLoader.tsx +160 -116
- package/.framework/src/components/admin/AdminListPage.tsx +46 -44
- package/.framework/src/components/admin/AdminSidebar.tsx +57 -47
- package/.framework/src/components/admin/AdminStatsCard.tsx +46 -44
- package/.framework/src/components/admin/PageInstructions.tsx +98 -2
- package/.framework/src/components/admin/SortableTableHeader.tsx +44 -45
- package/.framework/src/components/app-shell/GenericAppShell.tsx +64 -65
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +44 -47
- package/.framework/src/components/app-shell/GenericListPage.tsx +45 -49
- package/.framework/src/components/app-sidebar.tsx +42 -45
- package/.framework/src/components/auth/ProtectedRoute.tsx +48 -41
- package/.framework/src/components/auth/TurnstileWidget.tsx +27 -0
- package/.framework/src/components/kb/KBArticleEditor.tsx +231 -22
- package/.framework/src/components/kb/KBArticleList.tsx +251 -10
- package/.framework/src/components/layout/AppShell.tsx +51 -45
- package/.framework/src/components/layout/Header.tsx +42 -43
- package/.framework/src/components/layout/Layout.tsx +46 -46
- package/.framework/src/components/layout/Sidebar.tsx +196 -96
- package/.framework/src/components/runtime/DataDetailHeader.tsx +55 -30
- package/.framework/src/components/runtime/DataDetailPage.tsx +31 -269
- package/.framework/src/components/runtime/DataFilters.tsx +49 -74
- package/.framework/src/components/runtime/DataHeader.tsx +53 -32
- package/.framework/src/components/runtime/DataListPage.tsx +51 -155
- package/.framework/src/components/runtime/DataStats.tsx +66 -44
- package/.framework/src/components/runtime/DataTable.tsx +49 -149
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +45 -75
- package/.framework/src/components/runtime/index.ts +119 -16
- package/.framework/src/components/search-form.tsx +46 -29
- package/.framework/src/components/shared/AgentView.tsx +65 -48
- package/.framework/src/components/shared/FieldRenderer.tsx +144 -50
- package/.framework/src/components/shared/InviteManager.tsx +207 -97
- package/.framework/src/components/shared/MemberList.tsx +97 -0
- package/.framework/src/components/shared/SchemaFields.tsx +107 -86
- package/.framework/src/components/ui/DataTable.tsx +80 -68
- package/.framework/src/components/ui/Form.tsx +157 -146
- package/.framework/src/components/ui/ItemCard.tsx +74 -67
- package/.framework/src/components/ui/ItemListView.tsx +73 -68
- package/.framework/src/components/ui/LoadingSpinner.tsx +43 -48
- package/.framework/src/components/ui/Modal.tsx +78 -68
- package/.framework/src/components/ui/RichTextEditor.tsx +89 -69
- package/.framework/src/components/ui/accordion.tsx +85 -86
- package/.framework/src/components/ui/alert-dialog.tsx +197 -184
- package/.framework/src/components/ui/alert.tsx +105 -94
- package/.framework/src/components/ui/aspect-ratio.tsx +57 -43
- package/.framework/src/components/ui/avatar.tsx +122 -107
- package/.framework/src/components/ui/badge.tsx +60 -55
- package/.framework/src/components/ui/breadcrumb.tsx +127 -128
- package/.framework/src/components/ui/button-group.tsx +86 -72
- package/.framework/src/components/ui/button.tsx +71 -50
- package/.framework/src/components/ui/calendar.tsx +72 -57
- package/.framework/src/components/ui/card.tsx +136 -129
- package/.framework/src/components/ui/carousel.tsx +226 -107
- package/.framework/src/components/ui/chart.tsx +252 -147
- package/.framework/src/components/ui/checkbox.tsx +43 -44
- package/.framework/src/components/ui/collapsible.tsx +86 -71
- package/.framework/src/components/ui/combobox.tsx +282 -249
- package/.framework/src/components/ui/command.tsx +158 -146
- package/.framework/src/components/ui/context-menu.tsx +239 -240
- package/.framework/src/components/ui/dialog.tsx +174 -157
- package/.framework/src/components/ui/direction.tsx +72 -56
- package/.framework/src/components/ui/drawer.tsx +168 -169
- package/.framework/src/components/ui/dropdown-menu.tsx +254 -223
- package/.framework/src/components/ui/empty.tsx +131 -120
- package/.framework/src/components/ui/field.tsx +205 -173
- package/.framework/src/components/ui/hover-card.tsx +71 -72
- package/.framework/src/components/ui/input-group.tsx +148 -133
- package/.framework/src/components/ui/input-otp.tsx +99 -86
- package/.framework/src/components/ui/input.tsx +43 -41
- package/.framework/src/components/ui/item.tsx +207 -185
- package/.framework/src/components/ui/kbd.tsx +57 -56
- package/.framework/src/components/ui/label.tsx +45 -41
- package/.framework/src/components/ui/menubar.tsx +268 -236
- package/.framework/src/components/ui/native-select.tsx +85 -86
- package/.framework/src/components/ui/navigation-menu.tsx +166 -156
- package/.framework/src/components/ui/pagination.tsx +131 -141
- package/.framework/src/components/ui/popover.tsx +125 -128
- package/.framework/src/components/ui/progress.tsx +47 -44
- package/.framework/src/components/ui/radio-group.tsx +60 -55
- package/.framework/src/components/ui/resizable.tsx +85 -72
- package/.framework/src/components/ui/scroll-area.tsx +57 -58
- package/.framework/src/components/ui/select.tsx +182 -169
- package/.framework/src/components/ui/separator.tsx +42 -43
- package/.framework/src/components/ui/sheet.tsx +170 -159
- package/.framework/src/components/ui/sidebar.tsx +395 -398
- package/.framework/src/components/ui/skeleton.tsx +42 -43
- package/.framework/src/components/ui/slider.tsx +61 -44
- package/.framework/src/components/ui/sonner.tsx +44 -44
- package/.framework/src/components/ui/spinner.tsx +47 -42
- package/.framework/src/components/ui/switch.tsx +56 -42
- package/.framework/src/components/ui/table-primitives.tsx +272 -132
- package/.framework/src/components/ui/table.tsx +140 -142
- package/.framework/src/components/ui/tabs.tsx +110 -93
- package/.framework/src/components/ui/textarea.tsx +43 -44
- package/.framework/src/components/ui/toggle-group.tsx +87 -71
- package/.framework/src/components/ui/toggle.tsx +56 -56
- package/.framework/src/components/ui/tooltip.tsx +99 -85
- package/.framework/src/contexts/AppContext.tsx +166 -114
- package/.framework/src/contexts/AuthContext.tsx +232 -137
- package/.framework/src/hooks/use-mobile.ts +43 -44
- package/.framework/src/hooks/useApi.ts +185 -172
- package/.framework/src/hooks/useAppPath.ts +31 -29
- package/.framework/src/hooks/useApps.ts +77 -42
- package/.framework/src/hooks/useEntityList.ts +66 -29
- package/.framework/src/hooks/useEntityRecord.ts +76 -32
- package/.framework/src/hooks/useForm.ts +62 -30
- package/.framework/src/hooks/useListSchema.ts +60 -43
- package/.framework/src/hooks/useSchemaRecord.ts +115 -95
- package/.framework/src/lib/api.ts +258 -134
- package/.framework/src/lib/registration.ts +181 -0
- package/.framework/src/lib/supabase.ts +118 -81
- package/.framework/src/lib/utils.ts +266 -266
- package/.framework/src/main.tsx +43 -44
- package/.framework/src/pages/DashboardPage.tsx +44 -43
- package/.framework/src/pages/NoAppPage.tsx +50 -0
- package/.framework/src/pages/NotFoundPage.tsx +32 -29
- package/.framework/src/pages/SetupPage.tsx +34 -33
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +69 -58
- package/.framework/src/pages/admin/AIAgentsPage.tsx +43 -40
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +63 -55
- package/.framework/src/pages/admin/APIKeysPage.tsx +44 -42
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +117 -94
- package/.framework/src/pages/admin/AppDetailPage.tsx +48 -42
- package/.framework/src/pages/admin/AppsPage.tsx +45 -42
- package/.framework/src/pages/admin/DeliveriesPage.tsx +49 -17
- package/.framework/src/pages/admin/DesignedPage.tsx +31 -30
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +58 -0
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +49 -0
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +31 -29
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +46 -29
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -29
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +68 -55
- package/.framework/src/pages/admin/IntegrationsPage.tsx +45 -42
- package/.framework/src/pages/admin/InvitesPage.tsx +60 -44
- package/.framework/src/pages/admin/LogsPage.tsx +87 -137
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +31 -29
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +150 -89
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +77 -104
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +44 -43
- package/.framework/src/pages/admin/PipelinesPage.tsx +59 -145
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +53 -42
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +47 -117
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +31 -44
- package/.framework/src/pages/admin/RoleDetailPage.tsx +49 -92
- package/.framework/src/pages/admin/RolesPage.tsx +47 -164
- package/.framework/src/pages/admin/SecurityPage.tsx +310 -0
- package/.framework/src/pages/admin/SelectTestPage.tsx +30 -32
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +37 -44
- package/.framework/src/pages/admin/SimpleDashboard.tsx +32 -44
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +97 -44
- package/.framework/src/pages/admin/TestingDashboard.tsx +126 -71
- package/.framework/src/pages/admin/TimerDetailPage.tsx +67 -55
- package/.framework/src/pages/admin/TimersPage.tsx +44 -42
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +47 -42
- package/.framework/src/pages/admin/TriggersPage.tsx +58 -57
- package/.framework/src/pages/admin/TypeDetailPage.tsx +91 -55
- package/.framework/src/pages/admin/TypesPage.tsx +45 -42
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +258 -128
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +127 -123
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +308 -235
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +159 -110
- package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +432 -0
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +200 -178
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +286 -239
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +211 -90
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +156 -143
- package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +379 -0
- package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +337 -0
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +219 -214
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
- package/.framework/src/pages/auth/AuthConfirmPage.tsx +135 -65
- package/.framework/src/pages/auth/ForgotPasswordPage.tsx +39 -31
- package/.framework/src/pages/auth/LoginPage.tsx +38 -32
- package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -28
- package/.framework/src/pages/auth/RegisterPage.tsx +429 -155
- package/.framework/src/pages/spine-framework/APIPage.tsx +33 -30
- package/.framework/src/pages/spine-framework/CLIPage.tsx +32 -30
- package/.framework/src/types/auth.ts +101 -93
- package/.framework/src/types/types.ts +283 -262
- package/.framework/templates/project.json +87 -0
- package/.framework/templates/spine.config.neutral.json +7 -0
- package/.framework/tests/api/api-surface.test.ts +381 -0
- package/.framework/tests/fixtures/seed.ts +427 -0
- package/.framework/tests/fixtures/teardown.ts +228 -0
- package/.framework/tests/reporter.ts +351 -0
- package/.framework/tests/setup.ts +135 -0
- package/.framework/tests/ui/ui-sweep.ts +278 -0
- package/.framework/tests/unit/admin-data-logger.test.ts +310 -0
- package/.framework/tests/unit/agent-runner.test.ts +2389 -0
- package/.framework/tests/unit/ai-interactions.test.ts +81 -0
- package/.framework/tests/unit/app-manifest.test.ts +359 -0
- package/.framework/tests/unit/assembly-scripts.test.ts +172 -0
- package/.framework/tests/unit/cil-determinism.test.ts +85 -0
- package/.framework/tests/unit/core-isolation.test.ts +153 -0
- package/.framework/tests/unit/funnel-signals.test.ts +135 -0
- package/.framework/tests/unit/install-app.test.ts +1759 -0
- package/.framework/tests/unit/invites-security.test.ts +572 -0
- package/.framework/tests/unit/kb-ingest-lease.test.ts +287 -0
- package/.framework/tests/unit/kb-search.test.ts +119 -0
- package/.framework/tests/unit/migrate.test.ts +509 -0
- package/.framework/tests/unit/notify.test.ts +136 -0
- package/.framework/tests/unit/permissions.test.ts +269 -0
- package/.framework/tests/unit/pipeline-runner.test.ts +755 -0
- package/.framework/tests/unit/principal-cache.test.ts +138 -0
- package/.framework/tests/unit/retrieval-golden.test.ts +520 -0
- package/.framework/tests/unit/runtime-isolation.test.ts +642 -0
- package/.framework/tests/unit/schema-utils.test.ts +225 -0
- package/.framework/tests/unit/trigger-engine.test.ts +513 -0
- package/.framework/tests/unit/validate-app.test.ts +527 -0
- package/README.md +34 -3
- package/bin/spine-framework.cjs +1 -0
- package/config/tailwind.config.cjs +7 -0
- package/config/tsconfig.functions.json +42 -0
- package/config/tsconfig.json +37 -9
- package/config/vite.config.ts +31 -2
- package/netlify.toml +31 -3
- package/package.json +46 -29
- package/scripts/assemble-frontend.sh +127 -44
- package/scripts/assemble-functions.sh +127 -29
- package/scripts/boundary-check.sh +6 -2
- package/scripts/build-manifest.sh +24 -68
- package/scripts/checksum-manifest.mts +345 -0
- package/scripts/dev-clean.sh +86 -0
- package/scripts/dev-netlify.sh +49 -0
- package/scripts/netlify-dev-wrapper.sh +2 -0
- package/scripts/verify-install.ts +358 -0
- package/scripts/verify-integrity.sh +21 -57
- package/scripts/verify-manifest.mts +305 -0
- package/templates/project/gitignore +45 -0
- package/{config → templates/project}/package-lock.json +22335 -9366
- package/vitest.config.ts +46 -0
- package/.framework/public/spine.config.json +0 -91
- package/config/deno.lock +0 -108
- package/config/tsconfig.node.tsbuildinfo +0 -1
- package/config/tsconfig.tsbuildinfo +0 -1
- package/config/vite.config.d.ts +0 -2
- package/custom/.devin/AGENT.md +0 -357
- package/custom/.devin/skills/install-app/SKILL.md +0 -39
- package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +0 -39
- package/custom/.devin/skills/spine-workbench-idea/SKILL.md +0 -36
- package/custom/.devin/skills/spine-workbench-implement/SKILL.md +0 -46
- package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +0 -28
- package/custom/.devin/skills/spine-workbench-plan/SKILL.md +0 -38
- package/custom/.devin/workflows/app-install.yaml +0 -83
- package/custom/README.md +0 -79
- package/docs/README.md +0 -15
- package/scripts/app-install-cli.ts +0 -286
- package/scripts/check-core-integrity.sh +0 -82
- package/scripts/ingest-chunks.cjs +0 -202
- package/scripts/kb-chunk-parser.cjs +0 -312
- package/scripts/kb-chunk-parser.ts +0 -330
- package/scripts/kb-ingest-docs.ts +0 -203
- package/scripts/load-test-app-install.ts +0 -484
- package/scripts/test-login.js +0 -33
- package/spine.config.json +0 -91
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// CIL[BEGIN stable_id="~/.framework/tests/unit/cil-determinism.test.ts:module_header:module_header" type="module_header" identity="module_header" parent="none"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="Unit tests for CIL deterministic identity and content hashing utilities"]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provide test coverage for CIL stable identity generation and content hash normalization"]
|
|
4
|
+
// CIL[DOC-CONTEXT module="cil-determinism.test.ts" layer="tests" related_files=".framework/functions/_shared/cil.ts"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="vitest describe/it/expect, cil.ts computeContentHash/generateStableId/parseStableId" outputs="Passing unit test assertions" errors="AssertionError on deterministic/round-trip/hash mismatch failures" side_effects="none"]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Imports utilities and sets up a Vitest test module" notable_decisions="[]"]
|
|
7
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
8
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
9
|
+
// CIL[DOC-AUDIENCE audience="test maintainers"]
|
|
10
|
+
import { describe, it, expect } from 'vitest'
|
|
11
|
+
import { computeContentHash, generateStableId, parseStableId } from '../../functions/_shared/cil.ts'
|
|
12
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Unit tests for CIL deterministic identity and content hashing utilities'; No verified external callers; imports: .framework/functions/_shared/cil.ts"]
|
|
13
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
14
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
15
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
16
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
17
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
18
|
+
// CIL[END stable_id="~/.framework/tests/unit/cil-determinism.test.ts:module_header:module_header"]
|
|
19
|
+
|
|
20
|
+
// CIL[BEGIN stable_id="~/.framework/tests/unit/cil-determinism.test.ts:describe_cil_stable_identity:block" type="block" identity="describe_cil_stable_identity" parent="none"]
|
|
21
|
+
// CIL[DOC-MACRO purpose="Verify stable id generation and parsing are deterministic"]
|
|
22
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Assert generateStableId and parseStableId behave predictably"]
|
|
23
|
+
// CIL[DOC-CONTEXT module="cil-determinism.test.ts" layer="tests" related_files=".framework/functions/_shared/cil.ts,.framework/tests/unit/cil-determinism.test.ts"]
|
|
24
|
+
// CIL[DOC-CONTRACT inputs="file path, identity, and type strings; stable id strings" outputs="Stable id string; parsed stable id object" errors="AssertionError if output does not match expected deterministic id or object" side_effects="none"]
|
|
25
|
+
// CIL[DOC-MICRO logic_summary="Tests deterministic stable id formatting and round-trip parsing" notable_decisions="[]"]
|
|
26
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
27
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
28
|
+
describe('CIL stable identity', () => {
|
|
29
|
+
it('generateStableId produces deterministic stable ids', () => {
|
|
30
|
+
expect(generateStableId('~/.framework/functions/auth.ts', 'getAccount', 'function'))
|
|
31
|
+
.toBe('~/.framework/functions/auth.ts:getAccount:function')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('parseStableId round-trips stable ids', () => {
|
|
35
|
+
const id = generateStableId('~/.framework/functions/auth.ts', 'getAccount', 'function')
|
|
36
|
+
expect(parseStableId(id)).toEqual({
|
|
37
|
+
canonicalPath: '~/.framework/functions/auth.ts',
|
|
38
|
+
identity: 'getAccount',
|
|
39
|
+
type: 'function',
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Verify stable id generation and parsing are deterministic'; No verified external callers; imports: .framework/functions/_shared/cil.ts"]
|
|
44
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
45
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
46
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
47
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
48
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
49
|
+
// CIL[END stable_id="~/.framework/tests/unit/cil-determinism.test.ts:describe_cil_stable_identity:block"]
|
|
50
|
+
|
|
51
|
+
// CIL[BEGIN stable_id="~/.framework/tests/unit/cil-determinism.test.ts:describe_cil_content_hash:block" type="block" identity="describe_cil_content_hash" parent="none"]
|
|
52
|
+
// CIL[DOC-MACRO purpose="Verify content hash is deterministic and normalizes CIL markers"]
|
|
53
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Assert computeContentHash produces consistent hashes and ignores CIL markers/blank lines"]
|
|
54
|
+
// CIL[DOC-CONTEXT module="cil-determinism.test.ts" layer="tests" related_files=".framework/functions/_shared/cil.ts,.framework/tests/unit/cil-determinism.test.ts"]
|
|
55
|
+
// CIL[DOC-CONTRACT inputs="JavaScript function source strings" outputs="32-character hexadecimal hash string" errors="AssertionError on hash mismatch or non-hex output" side_effects="none"]
|
|
56
|
+
// CIL[DOC-MICRO logic_summary="Tests hash determinism, CIL marker stripping, and sensitivity to code changes" notable_decisions="[]"]
|
|
57
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
58
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
59
|
+
describe('CIL content_hash', () => {
|
|
60
|
+
it('computeContentHash is deterministic for identical inputs', () => {
|
|
61
|
+
const h1 = computeContentHash('function foo() { return 1 }')
|
|
62
|
+
const h2 = computeContentHash('function foo() { return 1 }')
|
|
63
|
+
expect(h1).toBe(h2)
|
|
64
|
+
expect(h1).toMatch(/^[0-9a-f]{32}$/)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('computeContentHash normalizes away CIL markers and blank lines', () => {
|
|
68
|
+
const withCil = '// CIL[BEGIN]\nfunction foo() { return 1 }\n// CIL[END]\n\n'
|
|
69
|
+
const without = 'function foo() { return 1 }'
|
|
70
|
+
expect(computeContentHash(withCil)).toBe(computeContentHash(without))
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('computeContentHash changes when code changes', () => {
|
|
74
|
+
const h1 = computeContentHash('function foo() { return 1 }')
|
|
75
|
+
const h2 = computeContentHash('function foo() { return 2 }')
|
|
76
|
+
expect(h1).not.toBe(h2)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Verify content hash is deterministic and normalizes CIL markers'; No verified external callers; imports: .framework/functions/_shared/cil.ts"]
|
|
80
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
81
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
82
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
83
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
84
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
85
|
+
// CIL[END stable_id="~/.framework/tests/unit/cil-determinism.test.ts:describe_cil_content_hash:block"]
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// CIL[BEGIN stable_id="~/.framework/tests/unit/core-isolation.test.ts:module_header:module_header" type="module_header" identity="module_header" parent="none"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="Test setup and imports for core isolation tests"]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Configure test environment for core isolation"]
|
|
4
|
+
// CIL[DOC-CONTEXT module="tests/unit/core-isolation" layer="test-unit" related_files=".framework/functions/_shared/app-manifest.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/webhook-registry.ts"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="test imports" errors="none" side_effects="Imports vitest and core modules"]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Imports vitest, db, webhook-registry, app-manifest, and middleware" notable_decisions="[]"]
|
|
7
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
8
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
9
|
+
// CIL[DOC-AUDIENCE audience="developers"]
|
|
10
|
+
import { describe, it, expect, beforeAll } from 'vitest'
|
|
11
|
+
import { adminDb } from '../../functions/_shared/db'
|
|
12
|
+
import { resolveHandler, lookupHandler } from '../../functions/_shared/webhook-registry'
|
|
13
|
+
import { loadManifest, discoverManifests } from '../../functions/_shared/app-manifest'
|
|
14
|
+
import { createHandler } from '../../functions/_shared/middleware'
|
|
15
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Test setup and imports for core isolation tests'; No verified external callers; imports: .framework/functions/_shared/db.ts,.framework/functions/_shared/webhook-registry.ts,.framework/functions/_shared/app-manifest.ts"]
|
|
16
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
17
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
18
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
19
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
20
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
21
|
+
// CIL[END stable_id="~/.framework/tests/unit/core-isolation.test.ts:module_header:module_header"]
|
|
22
|
+
|
|
23
|
+
// CIL[BEGIN stable_id="~/.framework/tests/unit/core-isolation.test.ts:describe_CoreIsolation:block" type="block" identity="describe_CoreIsolation" parent="none"]
|
|
24
|
+
// CIL[DOC-MACRO purpose="Test core functionality works without custom code"]
|
|
25
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Verify core independence from custom code"]
|
|
26
|
+
// CIL[DOC-CONTEXT module="tests/unit/core-isolation" layer="test-unit" related_files=".framework/functions/_shared/app-manifest.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/webhook-registry.ts,.framework/tests/unit/core-isolation.test.ts"]
|
|
27
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="test assertions" errors="none" side_effects="Tests core modules"]
|
|
28
|
+
// CIL[DOC-MICRO logic_summary="Tests webhook registry, app manifests, DB access, handler creation, and permissions" notable_decisions="[]"]
|
|
29
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
30
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
31
|
+
describe('Core Isolation', () => {
|
|
32
|
+
describe('Webhook Registry', () => {
|
|
33
|
+
it('should have empty registry when no custom handlers registered', async () => {
|
|
34
|
+
const handlers = await lookupHandler('non-existent-handler')
|
|
35
|
+
expect(handlers).toBeNull()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should fail gracefully when resolving unknown handler', async () => {
|
|
39
|
+
const handler = await resolveHandler('unknown-handler')
|
|
40
|
+
expect(handler).toBeNull()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('should not depend on custom_webhook-handlers.ts', async () => {
|
|
44
|
+
const registry = await import('../../functions/_shared/webhook-registry')
|
|
45
|
+
expect(registry.resolveHandler).toBeDefined()
|
|
46
|
+
expect(registry.lookupHandler).toBeDefined()
|
|
47
|
+
expect(registry.loadHandler).toBeDefined()
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
describe('App Manifest System', () => {
|
|
52
|
+
it('should discover manifests without error', () => {
|
|
53
|
+
const manifests = discoverManifests()
|
|
54
|
+
expect(Array.isArray(manifests)).toBe(true)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('should handle missing manifest gracefully', () => {
|
|
58
|
+
const manifest = loadManifest('non/existent/manifest.json')
|
|
59
|
+
expect(manifest).toBeNull()
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('should load valid manifest if exists', () => {
|
|
63
|
+
const manifest = loadManifest('custom/apps/cortex/manifest.json')
|
|
64
|
+
if (manifest) {
|
|
65
|
+
expect(manifest.slug).toBeDefined()
|
|
66
|
+
expect(manifest.name).toBeDefined()
|
|
67
|
+
expect(Array.isArray(manifest.required_roles)).toBe(true)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// Live-DB probes — only meaningful when real credentials are configured
|
|
73
|
+
// (`.env.test` in the monorepo). The setup file stubs a placeholder URL for
|
|
74
|
+
// unit runs; hitting it would produce a fetch error, so gate on the stub.
|
|
75
|
+
const LIVE_DB =
|
|
76
|
+
!!process.env.SUPABASE_URL && !process.env.SUPABASE_URL.includes('test.supabase.co')
|
|
77
|
+
|
|
78
|
+
describe.runIf(LIVE_DB)('Database Access', () => {
|
|
79
|
+
it('should connect to database without custom code', async () => {
|
|
80
|
+
const { data, error } = await adminDb.from('accounts').select('id').limit(1)
|
|
81
|
+
expect(error).toBeNull()
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('should query apps without custom dependencies', async () => {
|
|
85
|
+
const { data, error } = await adminDb
|
|
86
|
+
.from('apps')
|
|
87
|
+
.select('slug, name, is_active')
|
|
88
|
+
.limit(1)
|
|
89
|
+
|
|
90
|
+
expect(error).toBeNull()
|
|
91
|
+
expect(Array.isArray(data) || data === null).toBe(true)
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
describe('Handler Creation', () => {
|
|
96
|
+
it('should create handler without custom imports', () => {
|
|
97
|
+
const handler = createHandler(async (event, ctx) => {
|
|
98
|
+
return { status: 'ok' }
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
expect(handler).toBeDefined()
|
|
102
|
+
expect(typeof handler).toBe('function')
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
describe('Permission System', () => {
|
|
107
|
+
it('should check permissions without custom code', async () => {
|
|
108
|
+
const { isSystemAdmin } = await import('../../functions/_shared/permissions')
|
|
109
|
+
|
|
110
|
+
const memberCtx = { principal: { id: 'test-user', account_id: 'test-account', roles: [] } }
|
|
111
|
+
const adminCtx = { principal: { id: 'admin-user', account_id: 'test-account', roles: [{ slug: 'system_admin' }] } }
|
|
112
|
+
|
|
113
|
+
expect(isSystemAdmin(memberCtx as any)).toBe(false)
|
|
114
|
+
expect(isSystemAdmin(adminCtx as any)).toBe(true)
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Test core functionality works without custom code'; No verified external callers; imports: .framework/functions/_shared/db.ts,.framework/functions/_shared/webhook-registry.ts,.framework/functions/_shared/app-manifest.ts"]
|
|
119
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
120
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
121
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
122
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
123
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
124
|
+
// CIL[END stable_id="~/.framework/tests/unit/core-isolation.test.ts:describe_CoreIsolation:block"]
|
|
125
|
+
|
|
126
|
+
// CIL[BEGIN stable_id="~/.framework/tests/unit/core-isolation.test.ts:describe_NoCoreCustomImports:block" type="block" identity="describe_NoCoreCustomImports" parent="none"]
|
|
127
|
+
// CIL[DOC-MACRO purpose="Test core files don't import custom code"]
|
|
128
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Verify static import boundaries"]
|
|
129
|
+
// CIL[DOC-CONTEXT module="tests/unit/core-isolation" layer="test-unit" related_files=".framework/functions/_shared/app-manifest.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/webhook-registry.ts,.framework/tests/unit/core-isolation.test.ts"]
|
|
130
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="test assertions" errors="none" side_effects="Conceptual test only"]
|
|
131
|
+
// CIL[DOC-MICRO logic_summary="Documents expected clean files without actual file reading" notable_decisions="[]"]
|
|
132
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
133
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
134
|
+
describe('No Core→Custom Imports', () => {
|
|
135
|
+
it('should verify no static imports from custom/', async () => {
|
|
136
|
+
const expectedCleanFiles = [
|
|
137
|
+
'.framework/functions/integration-routes.ts',
|
|
138
|
+
'.framework/functions/apps.ts',
|
|
139
|
+
'.framework/src/hooks/useApps.ts'
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
expectedCleanFiles.forEach(file => {
|
|
143
|
+
expect(file).toContain('.framework/')
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Test core files don't import custom code'; No verified external callers; imports: .framework/functions/_shared/db.ts,.framework/functions/_shared/webhook-registry.ts,.framework/functions/_shared/app-manifest.ts"]
|
|
148
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
149
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
150
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
151
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
152
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
153
|
+
// CIL[END stable_id="~/.framework/tests/unit/core-isolation.test.ts:describe_NoCoreCustomImports:block"]
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// CIL[DOC-MACRO purpose="Unit tests for emitSignal dedupe_scope behavior in _shared/funnel.ts"]
|
|
2
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Assert the optional dedupe_scope narrows the dedupe lookup to (account_id, action_type, dedupe_scope), is stamped into the inserted row data, and that omitting it preserves the once-per-account default"]
|
|
3
|
+
// CIL[DOC-CONTEXT module="funnel-signals.test" layer="test-unit" related_files=".framework/functions/_shared/funnel.ts"]
|
|
4
|
+
// CIL[DOC-CONTRACT inputs="mocked adminDb + fireCreateTriggers" outputs="expect assertions on query filters and inserted payloads" errors="none" side_effects="registers vi.mock factories"]
|
|
5
|
+
// CIL[DOC-AUDIENCE audience="test"]
|
|
6
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
7
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
8
|
+
|
|
9
|
+
vi.mock('../../functions/_shared/db.ts', () => ({
|
|
10
|
+
adminDb: { from: vi.fn(), rpc: vi.fn() },
|
|
11
|
+
}))
|
|
12
|
+
vi.mock('../../functions/_shared/trigger-engine.ts', () => ({
|
|
13
|
+
fireCreateTriggers: vi.fn().mockResolvedValue(undefined),
|
|
14
|
+
}))
|
|
15
|
+
|
|
16
|
+
import { adminDb } from '../../functions/_shared/db.ts'
|
|
17
|
+
import { emitSignal } from '../../functions/_shared/funnel.ts'
|
|
18
|
+
|
|
19
|
+
function ctx(): any {
|
|
20
|
+
return { accountId: 'acct-1', principal: { id: 'p-1', type: 'human' } }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Recording query builder — captures every chain call so tests can assert
|
|
25
|
+
* which filters were applied. `terminal` is the value single/maybeSingle/
|
|
26
|
+
* then resolve with.
|
|
27
|
+
*/
|
|
28
|
+
function chain(calls: any[][], terminal: any): any {
|
|
29
|
+
const b: any = {}
|
|
30
|
+
const rec = (name: string) => (...args: any[]) => {
|
|
31
|
+
calls.push([name, ...args])
|
|
32
|
+
return b
|
|
33
|
+
}
|
|
34
|
+
for (const m of [
|
|
35
|
+
'select', 'eq', 'in', 'or', 'is', 'not', 'order', 'insert', 'update',
|
|
36
|
+
'delete', 'upsert', 'lt', 'gt', 'lte', 'gte', 'neq', 'contains', 'limit',
|
|
37
|
+
]) b[m] = rec(m)
|
|
38
|
+
b.single = () => Promise.resolve(terminal)
|
|
39
|
+
b.maybeSingle = () => Promise.resolve(terminal)
|
|
40
|
+
b.then = (res: any, rej?: any) => Promise.resolve(terminal).then(res, rej)
|
|
41
|
+
return b
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Wire adminDb so `types` resolves the signal type and `items` answers the
|
|
46
|
+
* dedupe lookup (first call) and the insert (second call). Returns the
|
|
47
|
+
* recorded call lists.
|
|
48
|
+
*/
|
|
49
|
+
function mockDb(opts: { dedupeRows?: any[] } = {}) {
|
|
50
|
+
const itemsCalls: any[][] = []
|
|
51
|
+
let itemsCallIdx = 0
|
|
52
|
+
vi.mocked(adminDb.from).mockImplementation((table: string) => {
|
|
53
|
+
if (table === 'types') {
|
|
54
|
+
return chain([], { data: { id: 'type-demo-signal' }, error: null })
|
|
55
|
+
}
|
|
56
|
+
if (table === 'items') {
|
|
57
|
+
itemsCallIdx++
|
|
58
|
+
return chain(
|
|
59
|
+
itemsCalls,
|
|
60
|
+
itemsCallIdx === 1
|
|
61
|
+
? { data: opts.dedupeRows ?? [], error: null }
|
|
62
|
+
: { data: { id: 'sig-1', type_id: 'type-demo-signal' }, error: null }
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
return chain([], { data: null, error: null })
|
|
66
|
+
})
|
|
67
|
+
return { itemsCalls }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
describe('emitSignal — dedupe_scope', () => {
|
|
71
|
+
beforeEach(() => vi.clearAllMocks())
|
|
72
|
+
|
|
73
|
+
it('narrows the dedupe lookup by data.dedupe_scope and stamps it on the row', async () => {
|
|
74
|
+
const { itemsCalls } = mockDb()
|
|
75
|
+
const created = await emitSignal(ctx(), {
|
|
76
|
+
type_slug: 'demo_signal',
|
|
77
|
+
action: 'workflow_completed',
|
|
78
|
+
dedupe_scope: 'run-1',
|
|
79
|
+
data: { source: 'demo' },
|
|
80
|
+
})
|
|
81
|
+
expect(created?.id).toBe('sig-1')
|
|
82
|
+
// The dedupe query filters on the scope marker.
|
|
83
|
+
expect(itemsCalls).toContainEqual(['eq', 'data->>dedupe_scope', 'run-1'])
|
|
84
|
+
// The inserted row carries the scope so later lookups match.
|
|
85
|
+
const insert = itemsCalls.find((c) => c[0] === 'insert')
|
|
86
|
+
expect(insert?.[1]?.data?.dedupe_scope).toBe('run-1')
|
|
87
|
+
expect(insert?.[1]?.data?.action_type).toBe('workflow_completed')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('omits the scope filter entirely when dedupe_scope is not set', async () => {
|
|
91
|
+
const { itemsCalls } = mockDb()
|
|
92
|
+
const created = await emitSignal(ctx(), {
|
|
93
|
+
type_slug: 'demo_signal',
|
|
94
|
+
action: 'demo_started',
|
|
95
|
+
data: { source: 'demo' },
|
|
96
|
+
})
|
|
97
|
+
expect(created?.id).toBe('sig-1')
|
|
98
|
+
expect(itemsCalls.some((c) => c[0] === 'eq' && c[1] === 'data->>dedupe_scope')).toBe(false)
|
|
99
|
+
const insert = itemsCalls.find((c) => c[0] === 'insert')
|
|
100
|
+
expect(insert?.[1]?.data).not.toHaveProperty('dedupe_scope')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('skips the insert when a scoped signal already exists for the run', async () => {
|
|
104
|
+
const { itemsCalls } = mockDb({ dedupeRows: [{ id: 'existing' }] })
|
|
105
|
+
const created = await emitSignal(ctx(), {
|
|
106
|
+
type_slug: 'demo_signal',
|
|
107
|
+
action: 'workflow_completed',
|
|
108
|
+
dedupe_scope: 'run-1',
|
|
109
|
+
})
|
|
110
|
+
expect(created).toBeNull()
|
|
111
|
+
expect(itemsCalls.some((c) => c[0] === 'insert')).toBe(false)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('skips the dedupe lookup entirely when dedupe is false', async () => {
|
|
115
|
+
const { itemsCalls } = mockDb()
|
|
116
|
+
await emitSignal(ctx(), {
|
|
117
|
+
type_slug: 'demo_signal',
|
|
118
|
+
action: 'demo_started',
|
|
119
|
+
dedupe: false,
|
|
120
|
+
})
|
|
121
|
+
expect(itemsCalls.some((c) => c[0] === 'eq' && c[1] === 'data->>action_type')).toBe(false)
|
|
122
|
+
expect(itemsCalls.some((c) => c[0] === 'insert')).toBe(true)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('returns null when the signal type is not installed', async () => {
|
|
126
|
+
vi.mocked(adminDb.from).mockImplementation((table: string) =>
|
|
127
|
+
chain([], table === 'types' ? { data: null, error: null } : { data: [], error: null })
|
|
128
|
+
)
|
|
129
|
+
const created = await emitSignal(ctx(), {
|
|
130
|
+
type_slug: 'demo_signal',
|
|
131
|
+
action: 'demo_started',
|
|
132
|
+
})
|
|
133
|
+
expect(created).toBeNull()
|
|
134
|
+
})
|
|
135
|
+
})
|