spine-framework 0.3.144 → 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 +20 -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,477 @@
|
|
|
1
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/shared/db.ts:mcp_db:file" type="file" identity="mcp_db" parent="~/.framework/mcp/shared/db.ts"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="MCP admin-data proxy query builder and type resolver for the Spine framework."]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provides a fluent Query class that proxies Supabase-style requests to the admin-data Netlify function, plus helpers to resolve type and link type IDs."]
|
|
4
|
+
// CIL[DOC-CONTEXT module="mcp" layer="shared" related_files=".framework/mcp/shared/db.ts"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="table names, filters, sort/limit options, insert/update/delete payloads" outputs="records or {data,error} shaped results" errors="Environment missing, network/HTTP errors, record not found" side_effects="Makes fetch calls to the Spine admin-data and function endpoints."]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Builds URL query parameters, applies client-side filters/sorting, handles single/maybeSingle semantics, and routes apps/embeddings tables to dedicated function endpoints." notable_decisions="admin-data does not support upsert; apps/embeddings writes are rejected; RPC only supports match_embeddings."]
|
|
7
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
8
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
9
|
+
|
|
10
|
+
import { randomUUID } from 'node:crypto'
|
|
11
|
+
|
|
12
|
+
const SPINE_URL = process.env.SPINE_URL || process.env.URL || ''
|
|
13
|
+
|
|
14
|
+
const API_KEY = process.env.SPINE_API_KEY || process.env.SPINE_FRAMEWORK_API_KEY || ''
|
|
15
|
+
|
|
16
|
+
function baseUrl(): string {
|
|
17
|
+
if (!SPINE_URL) throw new Error('SPINE_URL environment variable is required')
|
|
18
|
+
return SPINE_URL.replace(/\/$/, '')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function headers(): Record<string, string> {
|
|
22
|
+
if (!API_KEY) throw new Error('SPINE_API_KEY environment variable is required')
|
|
23
|
+
return {
|
|
24
|
+
'Content-Type': 'application/json',
|
|
25
|
+
'X-Api-Key': API_KEY,
|
|
26
|
+
'X-Request-ID': randomUUID(),
|
|
27
|
+
'X-Source': 'spine-framework-mcp',
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function handleResponse<T>(res: Response): Promise<T> {
|
|
32
|
+
const body = await res.json().catch(() => ({}))
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
throw new Error(body?.error || body?.message || `request failed: ${res.status}`)
|
|
35
|
+
}
|
|
36
|
+
if (body && 'data' in body) {
|
|
37
|
+
return body.data as T
|
|
38
|
+
}
|
|
39
|
+
return body as T
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function fetchAdminData(
|
|
43
|
+
entity: string,
|
|
44
|
+
action: 'list' | 'get' | 'create' | 'update' | 'remove' | 'stats',
|
|
45
|
+
query: Record<string, any> = {},
|
|
46
|
+
body?: Record<string, any>
|
|
47
|
+
): Promise<any> {
|
|
48
|
+
const methodMap: Record<string, string> = {
|
|
49
|
+
list: 'GET',
|
|
50
|
+
get: 'GET',
|
|
51
|
+
stats: 'GET',
|
|
52
|
+
create: 'POST',
|
|
53
|
+
update: 'PATCH',
|
|
54
|
+
remove: 'DELETE',
|
|
55
|
+
}
|
|
56
|
+
const method = methodMap[action]
|
|
57
|
+
const params: Record<string, any> = { ...query, action, entity, method }
|
|
58
|
+
const qs = new URLSearchParams(params as Record<string, string>).toString()
|
|
59
|
+
const init: RequestInit = { method, headers: headers() }
|
|
60
|
+
if (body && (action === 'create' || action === 'update')) {
|
|
61
|
+
init.body = JSON.stringify(body)
|
|
62
|
+
}
|
|
63
|
+
const res = await fetch(`${baseUrl()}/.netlify/functions/admin-data?${qs}`, init)
|
|
64
|
+
const data = await handleResponse<any>(res)
|
|
65
|
+
if (Array.isArray(data)) return data
|
|
66
|
+
return data
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function fetchFunction(functionName: string, action: string, query: Record<string, any> = {}, body?: Record<string, any>): Promise<any> {
|
|
70
|
+
const method = body ? 'POST' : 'GET'
|
|
71
|
+
const params: Record<string, any> = { ...query, action, method }
|
|
72
|
+
const qs = new URLSearchParams(params as Record<string, string>).toString()
|
|
73
|
+
const init: RequestInit = { method, headers: headers() }
|
|
74
|
+
if (body) init.body = JSON.stringify(body)
|
|
75
|
+
const res = await fetch(`${baseUrl()}/.netlify/functions/${functionName}?${qs}`, init)
|
|
76
|
+
return handleResponse<any>(res)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
type Filter = { key: string; op: string; value: any }
|
|
80
|
+
|
|
81
|
+
type Sort = { field: string; ascending: boolean }
|
|
82
|
+
|
|
83
|
+
class Query {
|
|
84
|
+
private table: string
|
|
85
|
+
private columns = '*'
|
|
86
|
+
private count = false
|
|
87
|
+
private head = false
|
|
88
|
+
private _single = false
|
|
89
|
+
private _maybeSingle = false
|
|
90
|
+
private filters: Filter[] = []
|
|
91
|
+
private sorts: Sort[] = []
|
|
92
|
+
private limitN?: number
|
|
93
|
+
private rangeFrom?: number
|
|
94
|
+
private rangeTo?: number
|
|
95
|
+
private insertData?: any
|
|
96
|
+
private updateData?: any
|
|
97
|
+
private deleteFlag = false
|
|
98
|
+
private selectAfterInsert = false
|
|
99
|
+
|
|
100
|
+
constructor(table: string) {
|
|
101
|
+
this.table = table
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
select(columns?: string, opts?: { count?: 'exact'; head?: boolean }) {
|
|
105
|
+
if (columns) this.columns = columns
|
|
106
|
+
if (opts) {
|
|
107
|
+
this.count = opts.count === 'exact'
|
|
108
|
+
this.head = !!opts.head
|
|
109
|
+
}
|
|
110
|
+
return this
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
eq(key: string, value: any) {
|
|
114
|
+
this.filters.push({ key, op: 'eq', value })
|
|
115
|
+
return this
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
filter(key: string, op: string, value: any) {
|
|
119
|
+
this.filters.push({ key, op, value })
|
|
120
|
+
return this
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
in(key: string, values: any[]) {
|
|
124
|
+
this.filters.push({ key, op: 'in', value: values })
|
|
125
|
+
return this
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
order(field: string, opts?: { ascending?: boolean }) {
|
|
129
|
+
this.sorts.push({ field, ascending: opts?.ascending !== false })
|
|
130
|
+
return this
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
limit(n: number) {
|
|
134
|
+
this.limitN = n
|
|
135
|
+
return this
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
range(from: number, to: number) {
|
|
139
|
+
this.rangeFrom = from
|
|
140
|
+
this.rangeTo = to
|
|
141
|
+
return this
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
ilike(key: string, value: any) {
|
|
145
|
+
this.filters.push({ key, op: 'ilike', value })
|
|
146
|
+
return this
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
lte(key: string, value: any) {
|
|
150
|
+
this.filters.push({ key, op: 'lte', value })
|
|
151
|
+
return this
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
gte(key: string, value: any) {
|
|
155
|
+
this.filters.push({ key, op: 'gte', value })
|
|
156
|
+
return this
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
neq(key: string, value: any) {
|
|
160
|
+
this.filters.push({ key, op: 'neq', value })
|
|
161
|
+
return this
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
maybeSingle() {
|
|
165
|
+
this._maybeSingle = true
|
|
166
|
+
return this
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
single() {
|
|
170
|
+
this._single = true
|
|
171
|
+
return this
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
insert(data: any) {
|
|
175
|
+
this.insertData = data
|
|
176
|
+
return this
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
update(data: any) {
|
|
180
|
+
this.updateData = data
|
|
181
|
+
return this
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
upsert(data: any) {
|
|
185
|
+
// admin-data does not support upsert; treat as create
|
|
186
|
+
this.insertData = data
|
|
187
|
+
return this
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
delete() {
|
|
191
|
+
this.deleteFlag = true
|
|
192
|
+
return this
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
contains(key: string, value: any) {
|
|
196
|
+
this.filters.push({ key, op: 'contains', value })
|
|
197
|
+
return this
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
then<TResult1 = any, TResult2 = never>(
|
|
201
|
+
onfulfilled?: ((value: any) => TResult1 | PromiseLike<TResult1>) | undefined | null,
|
|
202
|
+
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
|
|
203
|
+
): Promise<TResult1 | TResult2> {
|
|
204
|
+
return this.execute().then(onfulfilled, onrejected)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
private async execute(): Promise<any> {
|
|
208
|
+
if (this.table === 'apps') return this.executeApps()
|
|
209
|
+
if (this.table === 'embeddings') return this.executeEmbeddings()
|
|
210
|
+
return this.executeAdminData()
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private async executeApps(): Promise<any> {
|
|
214
|
+
if (this.insertData || this.updateData || this.deleteFlag) {
|
|
215
|
+
throw new Error('apps write not supported through MCP proxy')
|
|
216
|
+
}
|
|
217
|
+
const idFilter = this.filters.find(f => f.key === 'id')
|
|
218
|
+
const slugFilter = this.filters.find(f => f.key === 'slug')
|
|
219
|
+
if (this._single || this._maybeSingle || idFilter || slugFilter) {
|
|
220
|
+
const q: Record<string, any> = {}
|
|
221
|
+
if (idFilter) q.id = idFilter.value
|
|
222
|
+
else if (slugFilter) q.slug = slugFilter.value
|
|
223
|
+
try {
|
|
224
|
+
const record = await fetchFunction('apps', 'get', q)
|
|
225
|
+
if (this._single && !record) throw new Error('App not found')
|
|
226
|
+
return { data: record || null, error: null }
|
|
227
|
+
} catch (err: any) {
|
|
228
|
+
if (this._maybeSingle && (err?.message?.includes('not found') || err?.message?.includes('Not found') || err?.message?.includes('not_found'))) {
|
|
229
|
+
return { data: null, error: null }
|
|
230
|
+
}
|
|
231
|
+
return { data: null, error: err }
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const records = await fetchFunction('apps', 'list', { include_system: 'true', include_inactive: 'true' })
|
|
235
|
+
const filtered = this.applyClientFilters(records || [])
|
|
236
|
+
const sorted = this.applyClientSort(filtered)
|
|
237
|
+
return { data: sorted, error: null }
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private async executeEmbeddings(): Promise<any> {
|
|
241
|
+
if (this.insertData || this.updateData || this.deleteFlag) {
|
|
242
|
+
throw new Error('embeddings write not supported through MCP proxy')
|
|
243
|
+
}
|
|
244
|
+
const q: Record<string, any> = {}
|
|
245
|
+
const modelFilter = this.filters.find(f => f.key === 'model_id')
|
|
246
|
+
const docFilter = this.filters.find(f => f.key === 'document_id')
|
|
247
|
+
if (modelFilter) q.model_id = modelFilter.value
|
|
248
|
+
if (docFilter) q.document_id = docFilter.value
|
|
249
|
+
if (this.limitN) q.limit = this.limitN
|
|
250
|
+
if (this.rangeFrom !== undefined) q.offset = this.rangeFrom
|
|
251
|
+
const records = await fetchFunction('embeddings', 'list', q)
|
|
252
|
+
return { data: records || [], error: null }
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private async executeAdminData(): Promise<any> {
|
|
256
|
+
const entity = this.table
|
|
257
|
+
const idFilter = this.filters.find(f => f.key === 'id')
|
|
258
|
+
const hasIdFilter = !!idFilter
|
|
259
|
+
|
|
260
|
+
if (this.count && this.head) {
|
|
261
|
+
try {
|
|
262
|
+
const result = await fetchAdminData(entity, 'stats', {})
|
|
263
|
+
return { data: [], count: result?.count ?? 0, error: null }
|
|
264
|
+
} catch (err: any) {
|
|
265
|
+
return { data: [], count: 0, error: err }
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (this.insertData) {
|
|
270
|
+
const record = await fetchAdminData(entity, 'create', {}, this.insertData)
|
|
271
|
+
if (this.selectAfterInsert && this.columns === 'id') {
|
|
272
|
+
return { data: record ? { id: record.id } : record, error: null }
|
|
273
|
+
}
|
|
274
|
+
return { data: record, error: null }
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (this.updateData) {
|
|
278
|
+
if (!hasIdFilter) throw new Error('update requires id filter')
|
|
279
|
+
const record = await fetchAdminData(entity, 'update', { id: idFilter.value }, this.updateData)
|
|
280
|
+
return { data: record, error: null }
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (this.deleteFlag) {
|
|
284
|
+
if (hasIdFilter) {
|
|
285
|
+
const record = await fetchAdminData(entity, 'remove', { id: idFilter.value })
|
|
286
|
+
return { data: record, error: null }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// list with any eq filters we can push, then client-filter the rest
|
|
290
|
+
const params: Record<string, any> = {}
|
|
291
|
+
for (const f of this.filters) {
|
|
292
|
+
if (f.op === 'eq') params[f.key] = f.value
|
|
293
|
+
}
|
|
294
|
+
const records = await fetchAdminData(entity, 'list', { ...params, limit: 5000 })
|
|
295
|
+
const toDelete = this.applyClientFilters(records || [], this.filters)
|
|
296
|
+
for (const record of toDelete) {
|
|
297
|
+
await fetchAdminData(entity, 'remove', { id: record.id })
|
|
298
|
+
}
|
|
299
|
+
return { data: null, error: null }
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if ((this._single || this._maybeSingle) && hasIdFilter) {
|
|
303
|
+
try {
|
|
304
|
+
const record = await fetchAdminData(entity, 'get', { id: idFilter.value })
|
|
305
|
+
if (this._single && !record) throw new Error('Record not found')
|
|
306
|
+
return { data: record || null, error: null }
|
|
307
|
+
} catch (err: any) {
|
|
308
|
+
if (this._maybeSingle) return { data: null, error: null }
|
|
309
|
+
return { data: null, error: err }
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const inIdFilter = this.filters.find(f => f.key === 'id' && f.op === 'in')
|
|
314
|
+
if (inIdFilter) {
|
|
315
|
+
const records: any[] = []
|
|
316
|
+
for (const id of inIdFilter.value) {
|
|
317
|
+
try {
|
|
318
|
+
const record = await fetchAdminData(entity, 'get', { id })
|
|
319
|
+
if (record) records.push(record)
|
|
320
|
+
} catch {
|
|
321
|
+
// ignore missing
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
const otherFilters = this.filters.filter(f => !(f.key === 'id' && f.op === 'in'))
|
|
325
|
+
const filtered = this.applyClientFilters(records, otherFilters)
|
|
326
|
+
return { data: filtered, error: null }
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const params: Record<string, any> = {}
|
|
330
|
+
for (const f of this.filters) {
|
|
331
|
+
if (f.op === 'eq') {
|
|
332
|
+
params[f.key] = f.value
|
|
333
|
+
} else if (f.op === 'ilike') {
|
|
334
|
+
params.search = f.value.replace(/%/g, '')
|
|
335
|
+
} else {
|
|
336
|
+
// other ops are not supported by admin-data list; will client-filter later
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (this.rangeFrom !== undefined && this.rangeTo !== undefined) {
|
|
340
|
+
params.offset = this.rangeFrom
|
|
341
|
+
params.limit = Math.max(0, this.rangeTo - this.rangeFrom)
|
|
342
|
+
}
|
|
343
|
+
if (this.limitN !== undefined) {
|
|
344
|
+
params.limit = this.limitN
|
|
345
|
+
}
|
|
346
|
+
if (this.sorts.length > 0) {
|
|
347
|
+
params.sort_field = this.sorts[0].field
|
|
348
|
+
params.sort_direction = this.sorts[0].ascending ? 'asc' : 'desc'
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const records = await fetchAdminData(entity, 'list', params)
|
|
352
|
+
const filtered = this.applyClientFilters(records || [])
|
|
353
|
+
|
|
354
|
+
if (this._single) {
|
|
355
|
+
if (filtered.length === 0) throw new Error('Record not found')
|
|
356
|
+
if (filtered.length > 1) throw new Error('Multiple records found')
|
|
357
|
+
return { data: filtered[0], error: null }
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (this._maybeSingle) {
|
|
361
|
+
return { data: filtered[0] || null, error: null }
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return { data: filtered, error: null }
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
private applyClientFilters(records: any[], filters = this.filters): any[] {
|
|
368
|
+
return records.filter(record => {
|
|
369
|
+
for (const f of filters) {
|
|
370
|
+
const value = this.getValue(record, f.key)
|
|
371
|
+
if (f.op === 'eq' && value !== f.value) return false
|
|
372
|
+
if (f.op === 'in' && !f.value.includes(value)) return false
|
|
373
|
+
if (f.op === 'ilike' && typeof value === 'string' && !value.toLowerCase().includes(String(f.value).toLowerCase().replace(/%/g, ''))) return false
|
|
374
|
+
if (f.op === 'lte' && value > f.value) return false
|
|
375
|
+
if (f.op === 'gte' && value < f.value) return false
|
|
376
|
+
if (f.op === 'neq' && value === f.value) return false
|
|
377
|
+
if (f.op === 'contains') {
|
|
378
|
+
if (Array.isArray(value) && !value.includes(f.value)) return false
|
|
379
|
+
if (typeof value === 'string' && !value.includes(f.value)) return false
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return true
|
|
383
|
+
})
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private applyClientSort(records: any[]): any[] {
|
|
387
|
+
if (this.sorts.length === 0) return records
|
|
388
|
+
const s = this.sorts[0]
|
|
389
|
+
return [...records].sort((a, b) => {
|
|
390
|
+
const av = this.getValue(a, s.field)
|
|
391
|
+
const bv = this.getValue(b, s.field)
|
|
392
|
+
if (av < bv) return s.ascending ? -1 : 1
|
|
393
|
+
if (av > bv) return s.ascending ? 1 : -1
|
|
394
|
+
return 0
|
|
395
|
+
})
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private getValue(record: any, key: string): any {
|
|
399
|
+
if (key === 'id') return record.id
|
|
400
|
+
if (key in record) return record[key]
|
|
401
|
+
if (key.startsWith('data->>')) {
|
|
402
|
+
const field = key.slice(7)
|
|
403
|
+
return record.data?.[field]
|
|
404
|
+
}
|
|
405
|
+
if (key.startsWith('data->')) {
|
|
406
|
+
const path = key.slice(6)
|
|
407
|
+
return record.data?.[path]
|
|
408
|
+
}
|
|
409
|
+
return undefined
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export const adminDb = {
|
|
414
|
+
from(table: string) {
|
|
415
|
+
return new Query(table)
|
|
416
|
+
},
|
|
417
|
+
async rpc(name: string, params: Record<string, any> = {}): Promise<any> {
|
|
418
|
+
if (name === 'match_embeddings') {
|
|
419
|
+
const result = await fetchFunction('embeddings', 'search-similar', {}, {
|
|
420
|
+
query_embedding: params.query_embedding,
|
|
421
|
+
model_id: params.model_id || 'text-embedding-3-small',
|
|
422
|
+
limit: params.match_count || params.limit || 10,
|
|
423
|
+
threshold: params.similarity_threshold || 0.15,
|
|
424
|
+
filter_account_ids: params.filter_account_ids ?? null,
|
|
425
|
+
filter_vector_type: params.filter_vector_type ?? null,
|
|
426
|
+
filter_item_types: params.filter_item_types ?? null,
|
|
427
|
+
filter_document_ids: params.filter_document_ids ?? null,
|
|
428
|
+
})
|
|
429
|
+
const rows = Array.isArray(result) ? result : (result?.results || [])
|
|
430
|
+
return { data: rows, error: null }
|
|
431
|
+
}
|
|
432
|
+
throw new Error(`RPC not supported through MCP proxy: ${name}`)
|
|
433
|
+
},
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export async function resolveTypeRecord(kind: string, slug: string): Promise<any> {
|
|
437
|
+
const rows = await fetchAdminData('types', 'list', { kind, slug, limit: 1 })
|
|
438
|
+
const row = rows?.[0]
|
|
439
|
+
if (!row) throw new Error(`Type not found: ${kind}/${slug}`)
|
|
440
|
+
return {
|
|
441
|
+
id: row.id,
|
|
442
|
+
slug: row.slug,
|
|
443
|
+
kind: row.kind,
|
|
444
|
+
design_schema: row.design_schema || {},
|
|
445
|
+
validation_schema: row.validation_schema || {},
|
|
446
|
+
is_active: row.is_active ?? true,
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
export async function resolveTypeId(kind: string, slug: string): Promise<string> {
|
|
451
|
+
const record = await resolveTypeRecord(kind, slug)
|
|
452
|
+
return record.id
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
export async function resolveLinkTypeId(slug: string): Promise<string> {
|
|
456
|
+
const rows = await fetchAdminData('link_types', 'list', { slug, limit: 1 })
|
|
457
|
+
const row = rows?.[0]
|
|
458
|
+
if (!row) throw new Error(`Link type not found: ${slug}`)
|
|
459
|
+
return row.id
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export async function resolveLinkTypeIds(slugs: string[]): Promise<Record<string, string>> {
|
|
463
|
+
const ids = await Promise.all(slugs.map(resolveLinkTypeId))
|
|
464
|
+
const result: Record<string, string> = {}
|
|
465
|
+
for (let i = 0; i < slugs.length; i++) {
|
|
466
|
+
result[slugs[i]] = ids[i]
|
|
467
|
+
}
|
|
468
|
+
return result
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// CIL[DOC-VECTOR type="context" content="purpose='MCP admin-data proxy query builder and type resolver for the Spine framework.'; No verified external callers; imports: none"]
|
|
472
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
473
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
474
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
475
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
476
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
477
|
+
// CIL[END stable_id="~/.framework/mcp/shared/db.ts:mcp_db:file"]
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/shared/kb.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/mcp/shared/kb.ts"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="Shared MCP KB operation wrappers"]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provide thin async wrappers that route KB search/ingest/reindex/revoke/publish operations to the database fetch function"]
|
|
4
|
+
// CIL[DOC-CONTEXT module=".framework/mcp/shared/kb.ts" layer="mcp" related_files=".framework/mcp/shared/db.ts"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="none at module level" outputs="named KB operation exports" errors="none at module level" side_effects="none at module level"]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Re-exports fetchFunction-bound helpers for the kb namespace" notable_decisions="[]"]
|
|
7
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
8
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
9
|
+
// CIL[DOC-AUDIENCE audience="mcp"]
|
|
10
|
+
|
|
11
|
+
import { fetchFunction } from './db.js'
|
|
12
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Shared MCP KB operation wrappers'; No verified external callers; imports: .framework/mcp/shared/db.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/mcp/shared/kb.ts:module_header:module_header"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/shared/kb.ts:kbsearch:function" type="function" identity="kbSearch" parent="~/.framework/mcp/shared/kb.ts"]
|
|
22
|
+
// CIL[DOC-MACRO purpose="Search the knowledge base"]
|
|
23
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Delegate a KB search call to the database fetchFunction"]
|
|
24
|
+
// CIL[DOC-CONTEXT module=".framework/mcp/shared/kb.ts" layer="mcp" related_files=".framework/mcp/shared/db.ts,.framework/mcp/shared/kb.ts"]
|
|
25
|
+
// CIL[DOC-CONTRACT inputs="_ctx: any, body: Record<string, any>" outputs="Promise<any>" errors="propagates fetchFunction errors" side_effects="queries the KB search index"]
|
|
26
|
+
// CIL[DOC-MICRO logic_summary="Calls fetchFunction with the kb namespace, search action, empty static context, and the provided body" notable_decisions="[]"]
|
|
27
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
28
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
29
|
+
export async function kbSearch(_ctx: any, body: Record<string, any>): Promise<any> {
|
|
30
|
+
return fetchFunction('kb', 'search', {}, body)
|
|
31
|
+
}
|
|
32
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Search the knowledge base'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
33
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
34
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
35
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
36
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
37
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
38
|
+
// CIL[END stable_id="~/.framework/mcp/shared/kb.ts:kbsearch:function"]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/shared/kb.ts:kbingest:function" type="function" identity="kbIngest" parent="~/.framework/mcp/shared/kb.ts"]
|
|
42
|
+
// CIL[DOC-MACRO purpose="Ingest content into the knowledge base"]
|
|
43
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Delegate a KB ingest call to the database fetchFunction"]
|
|
44
|
+
// CIL[DOC-CONTEXT module=".framework/mcp/shared/kb.ts" layer="mcp" related_files=".framework/mcp/shared/db.ts,.framework/mcp/shared/kb.ts"]
|
|
45
|
+
// CIL[DOC-CONTRACT inputs="_ctx: any, body: Record<string, any>" outputs="Promise<any>" errors="propagates fetchFunction errors" side_effects="adds or updates KB records"]
|
|
46
|
+
// CIL[DOC-MICRO logic_summary="Calls fetchFunction with the kb namespace, ingest action, empty static context, and the provided body" notable_decisions="[]"]
|
|
47
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
48
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
49
|
+
export async function kbIngest(_ctx: any, body: Record<string, any>): Promise<any> {
|
|
50
|
+
return fetchFunction('kb', 'ingest', {}, body)
|
|
51
|
+
}
|
|
52
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Ingest content into the knowledge base'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
53
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
54
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
55
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
56
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
57
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
58
|
+
// CIL[END stable_id="~/.framework/mcp/shared/kb.ts:kbingest:function"]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/shared/kb.ts:kbreindex:function" type="function" identity="kbReindex" parent="~/.framework/mcp/shared/kb.ts"]
|
|
62
|
+
// CIL[DOC-MACRO purpose="Reindex the knowledge base"]
|
|
63
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Delegate a KB reindex call to the database fetchFunction"]
|
|
64
|
+
// CIL[DOC-CONTEXT module=".framework/mcp/shared/kb.ts" layer="mcp" related_files=".framework/mcp/shared/db.ts,.framework/mcp/shared/kb.ts"]
|
|
65
|
+
// CIL[DOC-CONTRACT inputs="_ctx: any, body: Record<string, any>" outputs="Promise<any>" errors="propagates fetchFunction errors" side_effects="rebuilds the KB index"]
|
|
66
|
+
// CIL[DOC-MICRO logic_summary="Calls fetchFunction with the kb namespace, reindex action, empty static context, and the provided body" notable_decisions="[]"]
|
|
67
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
68
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
69
|
+
export async function kbReindex(_ctx: any, body: Record<string, any>): Promise<any> {
|
|
70
|
+
return fetchFunction('kb', 'reindex', {}, body)
|
|
71
|
+
}
|
|
72
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Reindex the knowledge base'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
73
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
74
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
75
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
76
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
77
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
78
|
+
// CIL[END stable_id="~/.framework/mcp/shared/kb.ts:kbreindex:function"]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/shared/kb.ts:kbrevoke:function" type="function" identity="kbRevoke" parent="~/.framework/mcp/shared/kb.ts"]
|
|
82
|
+
// CIL[DOC-MACRO purpose="Revoke a knowledge base record"]
|
|
83
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Delegate a KB revoke call to the database fetchFunction"]
|
|
84
|
+
// CIL[DOC-CONTEXT module=".framework/mcp/shared/kb.ts" layer="mcp" related_files=".framework/mcp/shared/db.ts,.framework/mcp/shared/kb.ts"]
|
|
85
|
+
// CIL[DOC-CONTRACT inputs="_ctx: any, body: Record<string, any>" outputs="Promise<any>" errors="propagates fetchFunction errors" side_effects="removes or invalidates the specified KB record"]
|
|
86
|
+
// CIL[DOC-MICRO logic_summary="Calls fetchFunction with the kb namespace, revoke action, empty static context, and the provided body" notable_decisions="[]"]
|
|
87
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
88
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
89
|
+
export async function kbRevoke(_ctx: any, body: Record<string, any>): Promise<any> {
|
|
90
|
+
return fetchFunction('kb', 'revoke', {}, body)
|
|
91
|
+
}
|
|
92
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Revoke a knowledge base record'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
93
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
94
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
95
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
96
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
97
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
98
|
+
// CIL[END stable_id="~/.framework/mcp/shared/kb.ts:kbrevoke:function"]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/shared/kb.ts:kbpublish:function" type="function" identity="kbPublish" parent="~/.framework/mcp/shared/kb.ts"]
|
|
102
|
+
// CIL[DOC-MACRO purpose="Publish a knowledge base record"]
|
|
103
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Delegate a KB publish call to the database fetchFunction"]
|
|
104
|
+
// CIL[DOC-CONTEXT module=".framework/mcp/shared/kb.ts" layer="mcp" related_files=".framework/mcp/shared/db.ts,.framework/mcp/shared/kb.ts"]
|
|
105
|
+
// CIL[DOC-CONTRACT inputs="_ctx: any, body: Record<string, any>" outputs="Promise<any>" errors="propagates fetchFunction errors" side_effects="publishes the specified KB record"]
|
|
106
|
+
// CIL[DOC-MICRO logic_summary="Calls fetchFunction with the kb namespace, publish action, empty static context, and the provided body" notable_decisions="[]"]
|
|
107
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
108
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
109
|
+
export async function kbPublish(_ctx: any, body: Record<string, any>): Promise<any> {
|
|
110
|
+
return fetchFunction('kb', 'publish', {}, body)
|
|
111
|
+
}
|
|
112
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Publish a knowledge base record'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
113
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
114
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
115
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
116
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
117
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
118
|
+
// CIL[END stable_id="~/.framework/mcp/shared/kb.ts:kbpublish:function"]
|