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,345 @@
|
|
|
1
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/context.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/mcp/tools/cil/context.ts"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="MCP tool module that exposes CIL context and post-edit helpers for named chunks"]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Register MCP tools providing pre-edit context briefs and post-edit next steps"]
|
|
4
|
+
// CIL[DOC-CONTEXT module="mcp-cil-context" layer="tools" related_files=".framework/mcp/shared/db.ts"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="McpServer instance" outputs="registered tools" errors="none" side_effects="registers three tools on the server"]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Imports SDK, zod, and shared DB helpers; no runtime logic" notable_decisions="[]"]
|
|
7
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
8
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
9
|
+
// CIL[DOC-AUDIENCE audience="internal"]
|
|
10
|
+
|
|
11
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
12
|
+
import { z } from 'zod'
|
|
13
|
+
import { adminDb, resolveLinkTypeId } from '../../shared/db.js'
|
|
14
|
+
// CIL[DOC-VECTOR type="context" content="purpose='MCP tool module that exposes CIL context and post-edit helpers for named chunks'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
15
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
16
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
17
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
18
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
19
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
20
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/context.ts:module_header:module_header"]
|
|
21
|
+
|
|
22
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/context.ts:getChunkById:function" type="function" identity="getChunkById" parent="~/.framework/mcp/tools/cil/context.ts"]
|
|
23
|
+
// CIL[DOC-MACRO purpose="Fetch a CIL chunk row by its primary id"]
|
|
24
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Return raw chunk data for a given id"]
|
|
25
|
+
// CIL[DOC-CONTEXT module="mcp-cil-context" layer="data-access" related_files=".framework/mcp/shared/db.ts,.framework/mcp/tools/cil/context.ts"]
|
|
26
|
+
// CIL[DOC-CONTRACT inputs="id: string" outputs="chunk data or undefined" errors="none" side_effects="queries adminDb"]
|
|
27
|
+
// CIL[DOC-MICRO logic_summary="Selects from items table by id" notable_decisions="[]"]
|
|
28
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
29
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
30
|
+
async function getChunkById(id: string) {
|
|
31
|
+
const { data } = await adminDb.from('items').select('id, title, data')
|
|
32
|
+
.eq('id', id).maybeSingle()
|
|
33
|
+
return data
|
|
34
|
+
}
|
|
35
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Fetch a CIL chunk row by its primary id'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
36
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
37
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
38
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
39
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
40
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
41
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/context.ts:getChunkById:function"]
|
|
42
|
+
|
|
43
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/context.ts:getChunkByStableId:function" type="function" identity="getChunkByStableId" parent="~/.framework/mcp/tools/cil/context.ts"]
|
|
44
|
+
// CIL[DOC-MACRO purpose="Fetch an active CIL chunk by project and stable id"]
|
|
45
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Return the matching chunk or undefined"]
|
|
46
|
+
// CIL[DOC-CONTEXT module="mcp-cil-context" layer="data-access" related_files=".framework/mcp/shared/db.ts,.framework/mcp/tools/cil/context.ts"]
|
|
47
|
+
// CIL[DOC-CONTRACT inputs="projectId: string, stableId: string, versionId?: string" outputs="chunk data" errors="none" side_effects="queries adminDb with filters"]
|
|
48
|
+
// CIL[DOC-MICRO logic_summary="Builds a filtered Supabase query and returns maybeSingle result" notable_decisions="[]"]
|
|
49
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
50
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
51
|
+
async function getChunkByStableId(projectId: string, stableId: string, versionId?: string) {
|
|
52
|
+
let q = adminDb.from('items').select('id, title, data')
|
|
53
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
54
|
+
.filter('data->>project_id', 'eq', projectId)
|
|
55
|
+
.filter('data->>stable_id', 'eq', stableId)
|
|
56
|
+
.eq('is_active', true)
|
|
57
|
+
if (versionId) q = (q as any).filter('data->>version_id', 'eq', versionId)
|
|
58
|
+
const { data } = await (q as any).maybeSingle()
|
|
59
|
+
return data
|
|
60
|
+
}
|
|
61
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Fetch an active CIL chunk by project and stable id'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
62
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
63
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
64
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
65
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
66
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
67
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/context.ts:getChunkByStableId:function"]
|
|
68
|
+
|
|
69
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/context.ts:findChunkByName:function" type="function" identity="findChunkByName" parent="~/.framework/mcp/tools/cil/context.ts"]
|
|
70
|
+
// CIL[DOC-MACRO purpose="Find an active CIL chunk by chunk name"]
|
|
71
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Return the first matching chunk by name"]
|
|
72
|
+
// CIL[DOC-STABILITY stability="internal"]
|
|
73
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
74
|
+
// CIL[DOC-CONTEXT module="mcp-cil-context" layer="data-access" related_files=".framework/mcp/shared/db.ts,.framework/mcp/tools/cil/context.ts"]
|
|
75
|
+
// CIL[DOC-CONTRACT inputs="name: string, projectId?: string" outputs="chunk data" errors="none" side_effects="queries adminDb"]
|
|
76
|
+
// CIL[DOC-MICRO logic_summary="Filters by chunk_name and optional project, returns first result" notable_decisions="[]"]
|
|
77
|
+
async function findChunkByName(name: string, projectId?: string) {
|
|
78
|
+
let q = adminDb.from('items').select('id, title, data')
|
|
79
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
80
|
+
.filter('data->>chunk_name', 'eq', name)
|
|
81
|
+
.eq('is_active', true)
|
|
82
|
+
if (projectId) q = (q as any).filter('data->>project_id', 'eq', projectId)
|
|
83
|
+
const { data } = await (q as any).limit(1).maybeSingle()
|
|
84
|
+
return data
|
|
85
|
+
}
|
|
86
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/context.ts:findChunkByName:function"]
|
|
87
|
+
|
|
88
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Find an active CIL chunk by chunk name'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
89
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
90
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
91
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
92
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
93
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
94
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/context.ts:blastRadiusBFS:function" type="function" identity="blastRadiusBFS" parent="~/.framework/mcp/tools/cil/context.ts"]
|
|
95
|
+
// CIL[DOC-MACRO purpose="Compute transitive callers of a chunk up to a max depth"]
|
|
96
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Return a list of caller chunks with depth metadata"]
|
|
97
|
+
// CIL[DOC-CONTEXT module="mcp-cil-context" layer="analysis" related_files=".framework/mcp/shared/db.ts,.framework/mcp/tools/cil/context.ts"]
|
|
98
|
+
// CIL[DOC-CONTRACT inputs="chunkId, maxDepth, callsLinkTypeId" outputs="caller records" errors="none" side_effects="queries links and items tables"]
|
|
99
|
+
// CIL[DOC-MICRO logic_summary="Breadth-first search over cil_calls links in reverse direction" notable_decisions="[]"]
|
|
100
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
101
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
102
|
+
async function blastRadiusBFS(
|
|
103
|
+
chunkId: string, maxDepth: number, callsLinkTypeId: string
|
|
104
|
+
): Promise<{ chunk_id: string; chunk_name: string; file_path: string; depth: number }[]> {
|
|
105
|
+
const visited = new Set([chunkId])
|
|
106
|
+
const queue: { id: string; depth: number }[] = [{ id: chunkId, depth: 0 }]
|
|
107
|
+
const result: { chunk_id: string; chunk_name: string; file_path: string; depth: number }[] = []
|
|
108
|
+
|
|
109
|
+
while (queue.length > 0) {
|
|
110
|
+
const { id, depth } = queue.shift()!
|
|
111
|
+
if (depth >= maxDepth) continue
|
|
112
|
+
const { data: callerLinks } = await adminDb.from('links').select('source_id')
|
|
113
|
+
.eq('link_type_id', callsLinkTypeId).eq('target_id', id)
|
|
114
|
+
for (const link of callerLinks || []) {
|
|
115
|
+
if (visited.has(link.source_id)) continue
|
|
116
|
+
visited.add(link.source_id)
|
|
117
|
+
const c = await getChunkById(link.source_id)
|
|
118
|
+
if (!c) continue
|
|
119
|
+
result.push({ chunk_id: c.id, chunk_name: c.data?.chunk_name || '', file_path: c.data?.file_path || '', depth: depth + 1 })
|
|
120
|
+
queue.push({ id: c.id, depth: depth + 1 })
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return result
|
|
124
|
+
}
|
|
125
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/context.ts:blastRadiusBFS:function"]
|
|
126
|
+
|
|
127
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/context.ts:safetyVerdict:function" type="function" identity="safetyVerdict" parent="~/.framework/mcp/tools/cil/context.ts"]
|
|
128
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Compute transitive callers of a chunk up to a max depth'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
129
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
130
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
131
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
132
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
133
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
134
|
+
// CIL[DOC-MACRO purpose="Assess edit safety for a chunk based on stability, blast radius, docs, and config dependencies"]
|
|
135
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Return a safety level and list of risk flags"]
|
|
136
|
+
// CIL[DOC-CONTEXT module="mcp-cil-context" layer="analysis" related_files=".framework/mcp/shared/db.ts,.framework/mcp/tools/cil/context.ts"]
|
|
137
|
+
// CIL[DOC-CONTRACT inputs="chunk, blastRadius, configDeps" outputs="{level, flags, summary}" errors="none" side_effects="none"]
|
|
138
|
+
// CIL[DOC-MICRO logic_summary="Inspects chunk data and derived metrics to classify risk" notable_decisions="[]"]
|
|
139
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
140
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
141
|
+
function safetyVerdict(chunk: any, blastRadius: any[], configDeps: any[]) {
|
|
142
|
+
const d = chunk.data || {}
|
|
143
|
+
const flags: string[] = []
|
|
144
|
+
if (d.stability === 'stable') flags.push('stability=stable: downstream consumers may break on signature changes')
|
|
145
|
+
if (blastRadius.length >= 10) flags.push(`high blast radius: ${blastRadius.length} transitive callers`)
|
|
146
|
+
else if (blastRadius.length >= 3) flags.push(`moderate blast radius: ${blastRadius.length} callers`)
|
|
147
|
+
if (configDeps.length > 0) flags.push(`reads ${configDeps.length} config field(s)`)
|
|
148
|
+
if (!d.macro && !d.micro) flags.push('no contract documentation')
|
|
149
|
+
if (d.is_dead_code) flags.push('flagged as dead code')
|
|
150
|
+
const level = flags.length === 0 ? 'safe' : (d.stability === 'stable' || blastRadius.length >= 10) ? 'risky' : 'caution'
|
|
151
|
+
return { level, flags, summary: level === 'safe' ? 'Low risk.' : `${level === 'risky' ? 'High' : 'Moderate'} risk — review flags before editing.` }
|
|
152
|
+
}
|
|
153
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Assess edit safety for a chunk based on stability, blast radius, docs, and config dependencies'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
154
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
155
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
156
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
157
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
158
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
159
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/context.ts:safetyVerdict:function"]
|
|
160
|
+
|
|
161
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/context.ts:buildBrief:function" type="function" identity="buildBrief" parent="~/.framework/mcp/tools/cil/context.ts"]
|
|
162
|
+
// CIL[DOC-MACRO purpose="Assemble a full pre-edit context brief for a chunk"]
|
|
163
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Return contract, blast radius, callees, tests, config deps, and safety verdict"]
|
|
164
|
+
// CIL[DOC-CONTEXT module="mcp-cil-context" layer="analysis" related_files=".framework/mcp/shared/db.ts,.framework/mcp/tools/cil/context.ts"]
|
|
165
|
+
// CIL[DOC-CONTRACT inputs="chunk: any, maxDepth: number = 4" outputs="context brief object" errors="none" side_effects="queries multiple link and item tables"]
|
|
166
|
+
// CIL[DOC-MICRO logic_summary="Resolves link types, computes blast radius, gathers callees, tests, and config dependencies" notable_decisions="[]"]
|
|
167
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
168
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
169
|
+
async function buildBrief(chunk: any, maxDepth = 4) {
|
|
170
|
+
const d = chunk.data || {}
|
|
171
|
+
const [callsId, testedById, configuresId] = await Promise.all([
|
|
172
|
+
resolveLinkTypeId('cil_calls').catch(() => null),
|
|
173
|
+
resolveLinkTypeId('cil_tested_by').catch(() => null),
|
|
174
|
+
resolveLinkTypeId('cil_configures').catch(() => null),
|
|
175
|
+
])
|
|
176
|
+
|
|
177
|
+
const blastRadius = callsId ? await blastRadiusBFS(chunk.id, maxDepth, callsId) : []
|
|
178
|
+
|
|
179
|
+
const callees: any[] = []
|
|
180
|
+
if (callsId) {
|
|
181
|
+
const { data: ls } = await adminDb.from('links').select('target_id').eq('link_type_id', callsId).eq('source_id', chunk.id)
|
|
182
|
+
for (const l of ls || []) {
|
|
183
|
+
const c = await getChunkById(l.target_id)
|
|
184
|
+
if (c) callees.push({ chunk_id: c.id, chunk_name: c.data?.chunk_name || '', file_path: c.data?.file_path || '' })
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const testPaths: { path: string; is_e2e: boolean }[] = []
|
|
189
|
+
if (testedById) {
|
|
190
|
+
const { data: ls } = await adminDb.from('links').select('target_id, metadata').eq('link_type_id', testedById).eq('source_id', chunk.id)
|
|
191
|
+
for (const l of ls || []) testPaths.push({ path: l.metadata?.test_path || '', is_e2e: l.metadata?.is_e2e || false })
|
|
192
|
+
}
|
|
193
|
+
if (testPaths.length === 0) {
|
|
194
|
+
if (d.test_unit_path) testPaths.push({ path: d.test_unit_path, is_e2e: false })
|
|
195
|
+
if (d.test_e2e_path) testPaths.push({ path: d.test_e2e_path, is_e2e: true })
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const configDeps: { field_name: string; config_id: string }[] = []
|
|
199
|
+
if (configuresId) {
|
|
200
|
+
const { data: ls } = await adminDb.from('links').select('source_id, metadata').eq('link_type_id', configuresId).eq('target_id', chunk.id)
|
|
201
|
+
for (const l of ls || []) {
|
|
202
|
+
const ci = await getChunkById(l.source_id)
|
|
203
|
+
if (ci) configDeps.push({ field_name: ci.data?.field_name || '', config_id: l.source_id })
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
chunk_id: chunk.id,
|
|
209
|
+
chunk_name: d.chunk_name || '',
|
|
210
|
+
file_path: d.file_path || '',
|
|
211
|
+
line_start: d.line_start || null,
|
|
212
|
+
line_end: d.line_end || null,
|
|
213
|
+
chunk_type: d.chunk_type || '',
|
|
214
|
+
source_set_id: d.source_set_id || null,
|
|
215
|
+
layer: d.layer || null,
|
|
216
|
+
contract: {
|
|
217
|
+
description: d.description || '',
|
|
218
|
+
module: d.module || '',
|
|
219
|
+
audience: d.audience || '',
|
|
220
|
+
macro: d.macro || '',
|
|
221
|
+
micro: d.micro || '',
|
|
222
|
+
input_spec: d.input_spec || '',
|
|
223
|
+
output_spec: d.output_spec || '',
|
|
224
|
+
side_effects: d.side_effects || '',
|
|
225
|
+
throws: d.throws || '',
|
|
226
|
+
stability: d.stability || 'unknown',
|
|
227
|
+
called_by: d.called_by || '',
|
|
228
|
+
calls: d.calls || '',
|
|
229
|
+
tags: d.tags || '',
|
|
230
|
+
complexity: d.complexity || '',
|
|
231
|
+
error_handling: d.error_handling || '',
|
|
232
|
+
related_files: d.related_files || d.see_also || '',
|
|
233
|
+
depends_on: d.depends_on || [],
|
|
234
|
+
depended_by: d.depended_by || [],
|
|
235
|
+
doc_confidence: d.doc_confidence || 'unverified_legacy',
|
|
236
|
+
validation_errors: d.doc_validation_errors || [],
|
|
237
|
+
},
|
|
238
|
+
hash: { stored_hash: d.stored_hash || null, hash_updated_at: d.hash_updated_at || null },
|
|
239
|
+
blast_radius: { direct_caller_count: blastRadius.filter(r => r.depth === 1).length, total_affected: blastRadius.length, callers: blastRadius },
|
|
240
|
+
calls: callees,
|
|
241
|
+
test_paths: testPaths,
|
|
242
|
+
config_dependencies: configDeps,
|
|
243
|
+
edit_safety: safetyVerdict(chunk, blastRadius, configDeps),
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Assemble a full pre-edit context brief for a chunk'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
247
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
248
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
249
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
250
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
251
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
252
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/context.ts:buildBrief:function"]
|
|
253
|
+
|
|
254
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/context.ts:register:function" type="function" identity="register" parent="~/.framework/mcp/tools/cil/context.ts"]
|
|
255
|
+
// CIL[DOC-MACRO purpose="Register CIL context tools on an MCP server"]
|
|
256
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Expose spine_cil_find_context, spine_cil_get_context, and spine_cil_post_edit"]
|
|
257
|
+
// CIL[DOC-CONTEXT module="mcp-cil-context" layer="tools" related_files=".framework/mcp/shared/db.ts,.framework/mcp/tools/cil/context.ts"]
|
|
258
|
+
// CIL[DOC-CONTRACT inputs="server: McpServer" outputs="none" errors="none" side_effects="registers three tools"]
|
|
259
|
+
// CIL[DOC-MICRO logic_summary="Calls server.registerTool for find context, get context, and post edit handlers" notable_decisions="[]"]
|
|
260
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
261
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
262
|
+
export function register(server: McpServer) {
|
|
263
|
+
|
|
264
|
+
server.registerTool(
|
|
265
|
+
'spine_cil_find_context',
|
|
266
|
+
{
|
|
267
|
+
description: 'Get a full pre-edit context brief for a chunk by name. Call this BEFORE editing any named chunk. Returns contract, blast radius, test paths, config dependencies, and an edit_safety verdict (safe/caution/risky).',
|
|
268
|
+
inputSchema: z.object({
|
|
269
|
+
stable_id: z.string().describe('Exact stable_id of the chunk'),
|
|
270
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
271
|
+
version_id: z.string().optional().describe('Optional version UUID to scope the lookup'),
|
|
272
|
+
max_depth: z.number().int().min(1).max(6).default(4).optional().describe('BFS depth for blast radius traversal'),
|
|
273
|
+
}),
|
|
274
|
+
},
|
|
275
|
+
async ({ stable_id, project_id, version_id, max_depth }) => {
|
|
276
|
+
const chunk = await getChunkByStableId(project_id, stable_id, version_id)
|
|
277
|
+
if (!chunk) {
|
|
278
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: `No chunk with stable_id "${stable_id}" found`, hint: 'Use spine_cil_search_chunks to find chunks by description' }) }] }
|
|
279
|
+
}
|
|
280
|
+
const brief = await buildBrief(chunk, max_depth ?? 4)
|
|
281
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, brief }, null, 2) }] }
|
|
282
|
+
}
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
server.registerTool(
|
|
286
|
+
'spine_cil_get_context',
|
|
287
|
+
{
|
|
288
|
+
description: 'Get a full pre-edit context brief for a chunk by its stable_id. Returns contract, blast radius, test paths, config dependencies, and edit_safety verdict.',
|
|
289
|
+
inputSchema: z.object({
|
|
290
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
291
|
+
stable_id: z.string().describe('The chunk stable_id'),
|
|
292
|
+
version_id: z.string().optional().describe('Optional version UUID to scope the lookup'),
|
|
293
|
+
max_depth: z.number().int().min(1).max(6).default(4).optional(),
|
|
294
|
+
}),
|
|
295
|
+
},
|
|
296
|
+
async ({ project_id, stable_id, version_id, max_depth }) => {
|
|
297
|
+
const chunk = await getChunkByStableId(project_id, stable_id, version_id)
|
|
298
|
+
if (!chunk) return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: `Chunk not found: ${stable_id}` }) }] }
|
|
299
|
+
const brief = await buildBrief(chunk, max_depth ?? 4)
|
|
300
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, brief }, null, 2) }] }
|
|
301
|
+
}
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
server.registerTool(
|
|
305
|
+
'spine_cil_post_edit',
|
|
306
|
+
{
|
|
307
|
+
description: 'Call this AFTER editing a chunk. Returns its stored hash status and exact next_steps commands to reindex and validate the change.',
|
|
308
|
+
inputSchema: z.object({
|
|
309
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
310
|
+
stable_id: z.string().describe('The stable_id of the chunk you just edited'),
|
|
311
|
+
version_id: z.string().optional().describe('Optional version UUID to scope the lookup'),
|
|
312
|
+
}),
|
|
313
|
+
},
|
|
314
|
+
async ({ project_id, stable_id, version_id }) => {
|
|
315
|
+
const chunk = await getChunkByStableId(project_id, stable_id, version_id)
|
|
316
|
+
if (!chunk) return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: `Chunk not found: ${stable_id}` }) }] }
|
|
317
|
+
const d = chunk.data || {}
|
|
318
|
+
const result = {
|
|
319
|
+
ok: true,
|
|
320
|
+
stable_id,
|
|
321
|
+
project_id,
|
|
322
|
+
version_id: version_id || d.version_id || null,
|
|
323
|
+
chunk_name: d.chunk_name || '',
|
|
324
|
+
file_path: d.file_path || '',
|
|
325
|
+
stored_hash: d.stored_hash || null,
|
|
326
|
+
hash_updated_at: d.hash_updated_at || null,
|
|
327
|
+
action_required: d.stored_hash
|
|
328
|
+
? 'Run spine_cil_reindex_chunk to refresh the stored hash after your edit, then spine_cil_validate_file to confirm drift is resolved.'
|
|
329
|
+
: 'No stored hash yet — run spine_cil_reindex_chunk or Pass 2 ingestion.',
|
|
330
|
+
next_steps: [
|
|
331
|
+
`spine_cil_reindex_chunk({ project_id: "${d.project_id || project_id}", stable_id: "${stable_id}", version_id: "${version_id || d.version_id || ''}", also_embed: true })`,
|
|
332
|
+
`spine_cil_validate_file({ project_id: "${d.project_id || project_id}", file_path: "${d.file_path || ''}" })`,
|
|
333
|
+
],
|
|
334
|
+
}
|
|
335
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }
|
|
336
|
+
}
|
|
337
|
+
)
|
|
338
|
+
}
|
|
339
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Register CIL context tools on an MCP server'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
340
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
341
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
342
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
343
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
344
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
345
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/context.ts:register:function"]
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/graph.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/mcp/tools/cil/graph.ts"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="Import dependencies and set up the CIL graph MCP tool module"]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Declare module-level imports for the MCP CIL graph tool"]
|
|
4
|
+
// CIL[DOC-CONTEXT module="mcp-tools-cil" layer="tools" related_files=".framework/mcp/shared/db.ts"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Import McpServer SDK, zod, and shared database helpers" notable_decisions="none"]
|
|
7
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
8
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
9
|
+
// CIL[DOC-AUDIENCE audience="maintainer"]
|
|
10
|
+
|
|
11
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
12
|
+
import { z } from 'zod'
|
|
13
|
+
import { adminDb, resolveLinkTypeId, fetchFunction } from '../../shared/db.js'
|
|
14
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Import dependencies and set up the CIL graph MCP tool module'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
15
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
16
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
17
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
18
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
19
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
20
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/graph.ts:module_header:module_header"]
|
|
21
|
+
|
|
22
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/graph.ts:getChunkById:function" type="function" identity="getChunkById" parent="~/.framework/mcp/tools/cil/graph.ts"]
|
|
23
|
+
// CIL[DOC-MACRO purpose="Fetch a single CIL chunk by its primary item id"]
|
|
24
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Load a chunk record from the items table by id"]
|
|
25
|
+
// CIL[DOC-CONTEXT module="mcp-tools-cil" layer="tools" related_files=".framework/mcp/shared/db.ts,.framework/mcp/tools/cil/graph.ts"]
|
|
26
|
+
// CIL[DOC-CONTRACT inputs="id: string" outputs="chunk record or null" errors="none" side_effects="database read"]
|
|
27
|
+
// CIL[DOC-MICRO logic_summary="Query adminDb items table for id, title, data matching the given id and return the data" notable_decisions="Uses maybeSingle to return null when no match"]
|
|
28
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
29
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
30
|
+
async function getChunkById(id: string) {
|
|
31
|
+
const { data } = await adminDb.from('items').select('id, title, data')
|
|
32
|
+
.eq('id', id).maybeSingle()
|
|
33
|
+
return data
|
|
34
|
+
}
|
|
35
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Fetch a single CIL chunk by its primary item id'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
36
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
37
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
38
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
39
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
40
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
41
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/graph.ts:getChunkById:function"]
|
|
42
|
+
|
|
43
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/graph.ts:getChunkByStableId:function" type="function" identity="getChunkByStableId" parent="~/.framework/mcp/tools/cil/graph.ts"]
|
|
44
|
+
// CIL[DOC-MACRO purpose="Fetch a CIL chunk by its stable_id within a project and optional version"]
|
|
45
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Locate a unique active CIL chunk by stable_id"]
|
|
46
|
+
// CIL[DOC-CONTEXT module="mcp-tools-cil" layer="tools" related_files=".framework/mcp/shared/db.ts,.framework/mcp/tools/cil/graph.ts"]
|
|
47
|
+
// CIL[DOC-CONTRACT inputs="projectId: string, stableId: string, versionId?: string" outputs="chunk record or null" errors="none" side_effects="database read"]
|
|
48
|
+
// CIL[DOC-MICRO logic_summary="Filter items by kb_type, project_id, stable_id, is_active and optional version_id, then return data" notable_decisions="Casts query to any when adding the optional version filter"]
|
|
49
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
50
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
51
|
+
async function getChunkByStableId(projectId: string, stableId: string, versionId?: string) {
|
|
52
|
+
let q = adminDb.from('items').select('id, title, data')
|
|
53
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
54
|
+
.filter('data->>project_id', 'eq', projectId)
|
|
55
|
+
.filter('data->>stable_id', 'eq', stableId)
|
|
56
|
+
.eq('is_active', true)
|
|
57
|
+
if (versionId) q = (q as any).filter('data->>version_id', 'eq', versionId)
|
|
58
|
+
const { data } = await (q as any).maybeSingle()
|
|
59
|
+
return data
|
|
60
|
+
}
|
|
61
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Fetch a CIL chunk by its stable_id within a project and optional version'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
62
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
63
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
64
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
65
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
66
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
67
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/graph.ts:getChunkByStableId:function"]
|
|
68
|
+
|
|
69
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/graph.ts:register:function" type="function" identity="register" parent="~/.framework/mcp/tools/cil/graph.ts"]
|
|
70
|
+
// CIL[DOC-MACRO purpose="Register CIL graph query tools on an MCP server"]
|
|
71
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Wire up MCP tools for blast radius, callers, file chunks and graph diff"]
|
|
72
|
+
// CIL[DOC-CONTEXT module="mcp-tools-cil" layer="tools" related_files=".framework/mcp/shared/db.ts,.framework/mcp/tools/cil/graph.ts"]
|
|
73
|
+
// CIL[DOC-CONTRACT inputs="server: McpServer" outputs="registered tool handlers" errors="throws if cil_calls link type or chunk is not found" side_effects="registers tools on the server and queries the database and links table"]
|
|
74
|
+
// CIL[DOC-MICRO logic_summary="Use server.registerTool to expose four CIL graph introspection endpoints backed by Supabase items and links" notable_decisions="Returns JSON-stringified content; uses BFS for blast radius; filters symbol references for direct callers; delegates graph_diff to fetchFunction"]
|
|
75
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
76
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
77
|
+
export function register(server: McpServer) {
|
|
78
|
+
|
|
79
|
+
server.registerTool(
|
|
80
|
+
'spine_cil_blast_radius',
|
|
81
|
+
{
|
|
82
|
+
description: 'Find all chunks that transitively call a given chunk (BFS traversal). Use this before refactoring to understand how many callers will be affected.',
|
|
83
|
+
inputSchema: z.object({
|
|
84
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
85
|
+
stable_id: z.string().describe('The chunk stable_id to analyse'),
|
|
86
|
+
version_id: z.string().optional().describe('Optional version UUID to scope the lookup'),
|
|
87
|
+
max_depth: z.number().int().min(1).max(6).default(4).optional().describe('Maximum BFS hop depth'),
|
|
88
|
+
}),
|
|
89
|
+
},
|
|
90
|
+
async ({ project_id, stable_id, version_id, max_depth = 4 }) => {
|
|
91
|
+
let callsId: string
|
|
92
|
+
try { callsId = await resolveLinkTypeId('cil_calls') }
|
|
93
|
+
catch { return { content: [{ type: 'text', text: JSON.stringify({ error: 'cil_calls link type not found — run Pass 4b first' }) }] } }
|
|
94
|
+
|
|
95
|
+
const chunk = await getChunkByStableId(project_id, stable_id, version_id)
|
|
96
|
+
if (!chunk) return { content: [{ type: 'text', text: JSON.stringify({ error: `Chunk not found: ${stable_id}` }) }] }
|
|
97
|
+
|
|
98
|
+
const startId = chunk.id
|
|
99
|
+
const visited = new Set([startId])
|
|
100
|
+
const queue: { id: string; depth: number }[] = [{ id: startId, depth: 0 }]
|
|
101
|
+
const callers: { stable_id: string; chunk_name: string; file_path: string; depth: number }[] = []
|
|
102
|
+
|
|
103
|
+
while (queue.length > 0) {
|
|
104
|
+
const { id, depth } = queue.shift()!
|
|
105
|
+
if (depth >= max_depth) continue
|
|
106
|
+
const { data: links } = await adminDb.from('links').select('source_id')
|
|
107
|
+
.eq('link_type_id', callsId).eq('target_id', id)
|
|
108
|
+
for (const l of links || []) {
|
|
109
|
+
if (visited.has(l.source_id)) continue
|
|
110
|
+
visited.add(l.source_id)
|
|
111
|
+
const c = await getChunkById(l.source_id)
|
|
112
|
+
if (!c) continue
|
|
113
|
+
callers.push({ stable_id: c.data?.stable_id || c.id, chunk_name: c.data?.chunk_name || '', file_path: c.data?.file_path || '', depth: depth + 1 })
|
|
114
|
+
queue.push({ id: c.id, depth: depth + 1 })
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const result = {
|
|
119
|
+
stable_id,
|
|
120
|
+
chunk_name: chunk.data?.chunk_name || '',
|
|
121
|
+
file_path: chunk.data?.file_path || '',
|
|
122
|
+
max_depth,
|
|
123
|
+
direct_callers: callers.filter(c => c.depth === 1).length,
|
|
124
|
+
total_affected: callers.length,
|
|
125
|
+
callers,
|
|
126
|
+
}
|
|
127
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
server.registerTool(
|
|
132
|
+
'spine_cil_get_callers',
|
|
133
|
+
{
|
|
134
|
+
description: 'Get the direct callers and symbol references (imports/references) of a chunk (depth-1 only). Faster than spine_cil_blast_radius when you just need to know what directly uses a chunk.',
|
|
135
|
+
inputSchema: z.object({
|
|
136
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
137
|
+
stable_id: z.string().describe('The chunk stable_id'),
|
|
138
|
+
version_id: z.string().optional().describe('Optional version UUID to scope the lookup'),
|
|
139
|
+
}),
|
|
140
|
+
},
|
|
141
|
+
async ({ project_id, stable_id, version_id }) => {
|
|
142
|
+
let callsId: string
|
|
143
|
+
try { callsId = await resolveLinkTypeId('cil_calls') }
|
|
144
|
+
catch { return { content: [{ type: 'text', text: JSON.stringify({ error: 'cil_calls link type not found' }) }] } }
|
|
145
|
+
|
|
146
|
+
const chunk = await getChunkByStableId(project_id, stable_id, version_id)
|
|
147
|
+
if (!chunk) return { content: [{ type: 'text', text: JSON.stringify({ error: `Chunk not found: ${stable_id}` }) }] }
|
|
148
|
+
|
|
149
|
+
const { data: links } = await adminDb.from('links').select('source_id, data, metadata')
|
|
150
|
+
.eq('link_type_id', callsId).eq('target_id', chunk.id)
|
|
151
|
+
|
|
152
|
+
const callers = []
|
|
153
|
+
for (const l of links || []) {
|
|
154
|
+
const c = await getChunkById(l.source_id)
|
|
155
|
+
if (c) callers.push({ stable_id: c.data?.stable_id || c.id, chunk_name: c.data?.chunk_name || '', file_path: c.data?.file_path || '' })
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return { content: [{ type: 'text', text: JSON.stringify({ stable_id, caller_count: callers.length, callers }, null, 2) }] }
|
|
159
|
+
}
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
server.registerTool(
|
|
163
|
+
'spine_cil_get_file_chunks',
|
|
164
|
+
{
|
|
165
|
+
description: 'List all indexed chunks for a file, sorted by line number. Useful for understanding the structure of a file before editing.',
|
|
166
|
+
inputSchema: z.object({
|
|
167
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
168
|
+
file_path: z.string().describe('Relative file path from repo root, e.g. ".framework/cli/commands/auth.ts"'),
|
|
169
|
+
}),
|
|
170
|
+
},
|
|
171
|
+
async ({ project_id, file_path }) => {
|
|
172
|
+
const { data: chunks } = await adminDb.from('items').select('id, title, data')
|
|
173
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
174
|
+
.filter('data->>project_id', 'eq', project_id)
|
|
175
|
+
.filter('data->>file_path', 'eq', file_path)
|
|
176
|
+
.eq('is_active', true)
|
|
177
|
+
|
|
178
|
+
if (!chunks || chunks.length === 0) {
|
|
179
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: `No chunks found for file: ${file_path}` }) }] }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const sorted = chunks
|
|
183
|
+
.map((c: any) => ({
|
|
184
|
+
id: c.id,
|
|
185
|
+
stable_id: c.data?.stable_id || '',
|
|
186
|
+
version_id: c.data?.version_id || '',
|
|
187
|
+
chunk_name: c.data?.chunk_name || '',
|
|
188
|
+
chunk_type: c.data?.chunk_type || '',
|
|
189
|
+
line_start: c.data?.line_start || 0,
|
|
190
|
+
line_end: c.data?.line_end || 0,
|
|
191
|
+
macro: c.data?.macro || '',
|
|
192
|
+
doc_confidence: c.data?.doc_confidence || 'unverified_legacy',
|
|
193
|
+
is_dead_code: c.data?.is_dead_code || false,
|
|
194
|
+
stability: c.data?.stability || '',
|
|
195
|
+
}))
|
|
196
|
+
.sort((a: any, b: any) => a.line_start - b.line_start)
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
content: [{
|
|
200
|
+
type: 'text',
|
|
201
|
+
text: JSON.stringify({
|
|
202
|
+
project_id,
|
|
203
|
+
file_path,
|
|
204
|
+
chunk_count: sorted.length,
|
|
205
|
+
chunks: sorted,
|
|
206
|
+
}, null, 2),
|
|
207
|
+
}],
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
server.registerTool(
|
|
213
|
+
'spine_cil_graph_diff',
|
|
214
|
+
{
|
|
215
|
+
description: 'Compare the CIL call and import graph between two project versions. Returns added, removed, and unchanged edges keyed by stable IDs and file paths.',
|
|
216
|
+
inputSchema: z.object({
|
|
217
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
218
|
+
from_version_id: z.string().uuid().describe('The source version UUID to diff from'),
|
|
219
|
+
to_version_id: z.string().uuid().describe('The target version UUID to diff to'),
|
|
220
|
+
}),
|
|
221
|
+
},
|
|
222
|
+
async ({ project_id, from_version_id, to_version_id }) => {
|
|
223
|
+
try {
|
|
224
|
+
const result = await fetchFunction('cil-graph', 'graph_diff', {
|
|
225
|
+
project_id,
|
|
226
|
+
from_version_id,
|
|
227
|
+
to_version_id,
|
|
228
|
+
})
|
|
229
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }
|
|
230
|
+
} catch (err: any) {
|
|
231
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: err?.message || String(err) }) }] }
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Register CIL graph query tools on an MCP server'; No verified external callers; imports: .framework/mcp/shared/db.ts"]
|
|
237
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
238
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
239
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
240
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
241
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
242
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/graph.ts:register:function"]
|