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,791 @@
|
|
|
1
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/project.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/mcp/tools/cil/project.ts"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="Module header for CIL project MCP tools, importing dependencies used for project lifecycle and version management"]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Import MCP server SDK, Zod, CIL pipeline utilities, and shared database helpers required by this tool module"]
|
|
4
|
+
// CIL[DOC-CONTEXT module="mcp/tools/cil/project" layer="mcp" related_files=".framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="" outputs="" errors="" side_effects=""]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Sets up the module imports and makes the register function available for MCP server wiring" notable_decisions="[]"]
|
|
7
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
8
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
9
|
+
// CIL[DOC-AUDIENCE audience="ai"]
|
|
10
|
+
|
|
11
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
12
|
+
import { z } from 'zod'
|
|
13
|
+
import { PIPELINE_STATUS_RANK, pipelineRank } from '../../../functions/_shared/cil.js'
|
|
14
|
+
import { adminDb, fetchFunction } from '../../shared/db.js'
|
|
15
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Module header for CIL project MCP tools, importing dependencies used for project lifecycle and version management'; No verified external callers; imports: .framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts"]
|
|
16
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
17
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
18
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
19
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
20
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
21
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/project.ts:module_header:module_header"]
|
|
22
|
+
|
|
23
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/project.ts:getCompletedSteps:function" type="function" identity="getCompletedSteps" parent="~/.framework/mcp/tools/cil/project.ts"]
|
|
24
|
+
// CIL[DOC-MACRO purpose="Compute the list of completed pipeline step indices for a file based on its current status"]
|
|
25
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Convert a file's pipeline status rank into the set of completed step numbers"]
|
|
26
|
+
// CIL[DOC-CONTEXT module="mcp/tools/cil/project" layer="mcp" related_files=".framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts,.framework/mcp/tools/cil/project.ts"]
|
|
27
|
+
// CIL[DOC-CONTRACT inputs="file_path: string, fileStatuses: Record<string, string>" outputs="number[]" errors="none" side_effects="none"]
|
|
28
|
+
// CIL[DOC-MICRO logic_summary="Looks up the file status rank, caps it to the maximum rank, and returns a range of completed step numbers" notable_decisions="[]"]
|
|
29
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
30
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
31
|
+
function getCompletedSteps(file_path: string, fileStatuses: Record<string, string>): number[] {
|
|
32
|
+
const rank = pipelineRank(fileStatuses[file_path])
|
|
33
|
+
const maxRank = Math.max(...Object.values(PIPELINE_STATUS_RANK))
|
|
34
|
+
const capped = Math.min(rank, maxRank)
|
|
35
|
+
const completed: number[] = []
|
|
36
|
+
for (let i = 0; i <= capped; i++) completed.push(i)
|
|
37
|
+
return completed
|
|
38
|
+
}
|
|
39
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Compute the list of completed pipeline step indices for a file based on its current status'; No verified external callers; imports: .framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts"]
|
|
40
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
41
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
42
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
43
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
44
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
45
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/project.ts:getCompletedSteps:function"]
|
|
46
|
+
|
|
47
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/project.ts:getReadySteps:function" type="function" identity="getReadySteps" parent="~/.framework/mcp/tools/cil/project.ts"]
|
|
48
|
+
// CIL[DOC-MACRO purpose="Determine which pipeline steps are ready to be executed next"]
|
|
49
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Return step numbers whose prerequisites are all completed but which are not yet completed"]
|
|
50
|
+
// CIL[DOC-CONTEXT module="mcp/tools/cil/project" layer="mcp" related_files=".framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts,.framework/mcp/tools/cil/project.ts"]
|
|
51
|
+
// CIL[DOC-CONTRACT inputs="file_path: string, fileStatuses: Record<string, string>" outputs="number[]" errors="none" side_effects="none"]
|
|
52
|
+
// CIL[DOC-MICRO logic_summary="Iterates steps 0-8 and collects those not completed with all prerequisites fulfilled" notable_decisions="[]"]
|
|
53
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
54
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
55
|
+
function getReadySteps(file_path: string, fileStatuses: Record<string, string>): number[] {
|
|
56
|
+
const completed = getCompletedSteps(file_path, fileStatuses)
|
|
57
|
+
const ready: number[] = []
|
|
58
|
+
for (let step = 0; step <= 8; step++) {
|
|
59
|
+
const prerequisites = Array.from({ length: step }, (_, i) => i)
|
|
60
|
+
if (!completed.includes(step) && prerequisites.every(p => completed.includes(p))) {
|
|
61
|
+
ready.push(step)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return ready
|
|
65
|
+
}
|
|
66
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Determine which pipeline steps are ready to be executed next'; No verified external callers; imports: .framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts"]
|
|
67
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
68
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
69
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
70
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
71
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
72
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/project.ts:getReadySteps:function"]
|
|
73
|
+
|
|
74
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/project.ts:getBlockedSteps:function" type="function" identity="getBlockedSteps" parent="~/.framework/mcp/tools/cil/project.ts"]
|
|
75
|
+
// CIL[DOC-MACRO purpose="Identify pipeline steps that are neither completed nor ready to execute"]
|
|
76
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Return step numbers that cannot yet be executed because prerequisites are missing"]
|
|
77
|
+
// CIL[DOC-STABILITY stability="internal"]
|
|
78
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
79
|
+
// CIL[DOC-CONTEXT module="mcp/tools/cil/project" layer="mcp" related_files=".framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts,.framework/mcp/tools/cil/project.ts"]
|
|
80
|
+
// CIL[DOC-CONTRACT inputs="file_path: string, fileStatuses: Record<string, string>" outputs="number[]" errors="none" side_effects="none"]
|
|
81
|
+
// CIL[DOC-MICRO logic_summary="Compares all steps 0-8 against completed and ready sets and returns the remainder" notable_decisions="[]"]
|
|
82
|
+
function getBlockedSteps(file_path: string, fileStatuses: Record<string, string>): number[] {
|
|
83
|
+
const completed = getCompletedSteps(file_path, fileStatuses)
|
|
84
|
+
const ready = getReadySteps(file_path, fileStatuses)
|
|
85
|
+
const blocked: number[] = []
|
|
86
|
+
for (let step = 0; step <= 8; step++) {
|
|
87
|
+
if (!completed.includes(step) && !ready.includes(step)) blocked.push(step)
|
|
88
|
+
}
|
|
89
|
+
return blocked
|
|
90
|
+
}
|
|
91
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/project.ts:getBlockedSteps:function"]
|
|
92
|
+
|
|
93
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Identify pipeline steps that are neither completed nor ready to execute'; No verified external callers; imports: .framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts"]
|
|
94
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
95
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
96
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
97
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
98
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
99
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/project.ts:calculateProgress:function" type="function" identity="calculateProgress" parent="~/.framework/mcp/tools/cil/project.ts"]
|
|
100
|
+
// CIL[DOC-MACRO purpose="Calculate a percentage progress value for a file based on its pipeline status rank"]
|
|
101
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Convert a file's pipeline status rank into a 0-100 progress percentage"]
|
|
102
|
+
// CIL[DOC-CONTEXT module="mcp/tools/cil/project" layer="mcp" related_files=".framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts,.framework/mcp/tools/cil/project.ts"]
|
|
103
|
+
// CIL[DOC-CONTRACT inputs="file_path: string, fileStatuses: Record<string, string>" outputs="number" errors="none" side_effects="none"]
|
|
104
|
+
// CIL[DOC-MICRO logic_summary="Divides the capped status rank by the maximum rank and rounds to the nearest integer" notable_decisions="[]"]
|
|
105
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
106
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
107
|
+
function calculateProgress(file_path: string, fileStatuses: Record<string, string>): number {
|
|
108
|
+
const rank = pipelineRank(fileStatuses[file_path])
|
|
109
|
+
const maxRank = Math.max(...Object.values(PIPELINE_STATUS_RANK))
|
|
110
|
+
return Math.round((Math.min(rank, maxRank) / maxRank) * 100)
|
|
111
|
+
}
|
|
112
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Calculate a percentage progress value for a file based on its pipeline status rank'; No verified external callers; imports: .framework/functions/_shared/cil.ts,.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/tools/cil/project.ts:calculateProgress:function"]
|
|
119
|
+
|
|
120
|
+
// CIL[BEGIN stable_id="~/.framework/mcp/tools/cil/project.ts:register:function" type="function" identity="register" parent="~/.framework/mcp/tools/cil/project.ts"]
|
|
121
|
+
// CIL[DOC-MACRO purpose="Register CIL project management and version lifecycle tools on an MCP server"]
|
|
122
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Bind MCP tool handlers for listing projects, reporting status, managing versions, and updating pipeline status"]
|
|
123
|
+
// CIL[DOC-CONTEXT module="mcp/tools/cil/project" layer="mcp" related_files=".framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts,.framework/mcp/tools/cil/project.ts"]
|
|
124
|
+
// CIL[DOC-CONTRACT inputs="server: McpServer" outputs="void" errors="Throws if fetchFunction or database calls fail" side_effects="Registers tools on the provided MCP server and may read or update database records"]
|
|
125
|
+
// CIL[DOC-MICRO logic_summary="Registers a suite of CIL project tools including status reporting, version lifecycle, file selection, and pipeline publishing" notable_decisions="[]"]
|
|
126
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
127
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
128
|
+
export function register(server: McpServer) {
|
|
129
|
+
|
|
130
|
+
server.registerTool(
|
|
131
|
+
'spine_cil_list_projects',
|
|
132
|
+
{
|
|
133
|
+
description: 'List all CIL projects registered in the database. Returns project names, repo paths, and basic file/chunk counts.',
|
|
134
|
+
inputSchema: z.object({}),
|
|
135
|
+
},
|
|
136
|
+
async () => {
|
|
137
|
+
const { data } = await adminDb.from('items').select('id, title, data')
|
|
138
|
+
.filter('data->>kb_type', 'eq', 'cil_project')
|
|
139
|
+
.eq('is_active', true)
|
|
140
|
+
.order('created_at', { ascending: true })
|
|
141
|
+
|
|
142
|
+
const projects = (data || []).map((p: any) => ({
|
|
143
|
+
id: p.id,
|
|
144
|
+
name: p.title,
|
|
145
|
+
repo_path: p.data?.repo_path || '',
|
|
146
|
+
language_mix: p.data?.language_mix || '',
|
|
147
|
+
file_count: p.data?.file_count || 0,
|
|
148
|
+
chunk_count: p.data?.chunk_count || 0,
|
|
149
|
+
ingestion_status: p.data?.ingestion_status || 'not_started',
|
|
150
|
+
last_ingested_at: p.data?.last_ingested_at || null,
|
|
151
|
+
selected_paths: p.data?.selected_paths || [],
|
|
152
|
+
}))
|
|
153
|
+
|
|
154
|
+
return { content: [{ type: 'text', text: JSON.stringify({ project_count: projects.length, projects }, null, 2) }] }
|
|
155
|
+
}
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
server.registerTool(
|
|
159
|
+
'spine_cil_project_status',
|
|
160
|
+
{
|
|
161
|
+
description: 'Get the full pipeline status for a CIL project: unique file count (from chunks), chunk count, embedding coverage, documentation coverage, and link counts.',
|
|
162
|
+
inputSchema: z.object({
|
|
163
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
164
|
+
}),
|
|
165
|
+
},
|
|
166
|
+
async ({ project_id }) => {
|
|
167
|
+
const PAGE_SIZE = 1000
|
|
168
|
+
|
|
169
|
+
const [projectRes, totalChunksRes] = await Promise.allSettled([
|
|
170
|
+
adminDb.from('items').select('id, title, data').eq('id', project_id).maybeSingle(),
|
|
171
|
+
adminDb.from('items').select('*', { count: 'exact', head: true })
|
|
172
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
173
|
+
.filter('data->>project_id', 'eq', project_id)
|
|
174
|
+
.eq('is_active', true),
|
|
175
|
+
])
|
|
176
|
+
|
|
177
|
+
const project = projectRes.status === 'fulfilled' ? projectRes.value.data : null
|
|
178
|
+
const totalChunks = totalChunksRes.status === 'fulfilled' ? (totalChunksRes.value.count || 0) : 0
|
|
179
|
+
|
|
180
|
+
const chunks: any[] = []
|
|
181
|
+
let from = 0
|
|
182
|
+
while (true) {
|
|
183
|
+
const { data, error } = await adminDb.from('items').select('id, data')
|
|
184
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
185
|
+
.filter('data->>project_id', 'eq', project_id)
|
|
186
|
+
.eq('is_active', true)
|
|
187
|
+
.order('id')
|
|
188
|
+
.range(from, from + PAGE_SIZE - 1)
|
|
189
|
+
if (error) break
|
|
190
|
+
if (!data || data.length === 0) break
|
|
191
|
+
chunks.push(...data)
|
|
192
|
+
if (data.length < PAGE_SIZE) break
|
|
193
|
+
from += PAGE_SIZE
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const chunkIds = new Set(chunks.map((c: any) => c.id))
|
|
197
|
+
const embeddedIds = new Set<string>()
|
|
198
|
+
if (chunkIds.size > 0) {
|
|
199
|
+
let embFrom = 0
|
|
200
|
+
while (true) {
|
|
201
|
+
const { data: embeddings, error: embErr } = await adminDb.from('embeddings').select('document_id')
|
|
202
|
+
.order('id')
|
|
203
|
+
.range(embFrom, embFrom + PAGE_SIZE - 1)
|
|
204
|
+
if (embErr) break
|
|
205
|
+
if (!embeddings || embeddings.length === 0) break
|
|
206
|
+
for (const row of embeddings) {
|
|
207
|
+
if (chunkIds.has(row.document_id)) embeddedIds.add(row.document_id)
|
|
208
|
+
}
|
|
209
|
+
if (embeddings.length < PAGE_SIZE) break
|
|
210
|
+
embFrom += PAGE_SIZE
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const embeddedChunks = chunks.filter((c: any) => embeddedIds.has(c.id)).length
|
|
215
|
+
const documentedChunks = chunks.filter((c: any) => c.data?.macro && c.data?.doc_confidence !== 'unverified_legacy').length
|
|
216
|
+
const verifiedChunks = chunks.filter((c: any) => c.data?.doc_confidence === 'human_verified').length
|
|
217
|
+
const aiChunks = chunks.filter((c: any) => c.data?.doc_confidence === 'ai_generated').length
|
|
218
|
+
const pendingReview = chunks.filter((c: any) => c.data?.review_status === 'pending_review').length
|
|
219
|
+
const deadCode = chunks.filter((c: any) => c.data?.is_dead_code).length
|
|
220
|
+
|
|
221
|
+
const uniqueFilePaths = new Set(chunks.map((c: any) => c.data?.file_path).filter(Boolean))
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
content: [{
|
|
225
|
+
type: 'text',
|
|
226
|
+
text: JSON.stringify({
|
|
227
|
+
project_id,
|
|
228
|
+
project_name: project?.title || '',
|
|
229
|
+
repo_path: project?.data?.repo_path || '',
|
|
230
|
+
selected_paths: project?.data?.selected_paths || [],
|
|
231
|
+
pipeline: {
|
|
232
|
+
files: { total: uniqueFilePaths.size },
|
|
233
|
+
chunks: {
|
|
234
|
+
total: totalChunks,
|
|
235
|
+
dead_code: deadCode,
|
|
236
|
+
pending_review: pendingReview,
|
|
237
|
+
embedded: embeddedChunks,
|
|
238
|
+
embedding_coverage_pct: totalChunks > 0 ? Math.round((embeddedChunks / totalChunks) * 100) : 0,
|
|
239
|
+
documented: documentedChunks,
|
|
240
|
+
human_verified: verifiedChunks,
|
|
241
|
+
ai_generated: aiChunks,
|
|
242
|
+
doc_coverage_pct: totalChunks > 0 ? Math.round((documentedChunks / totalChunks) * 100) : 0,
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
}, null, 2),
|
|
246
|
+
}],
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
server.registerTool(
|
|
252
|
+
'spine_cil_doc_gap_report',
|
|
253
|
+
{
|
|
254
|
+
description: 'List chunks that have no AI-generated or human-verified documentation. Use this to find chunks that need to be documented before they can be safely edited.',
|
|
255
|
+
inputSchema: z.object({
|
|
256
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
257
|
+
limit: z.number().int().min(1).max(100).default(20).optional(),
|
|
258
|
+
}),
|
|
259
|
+
},
|
|
260
|
+
async ({ project_id, limit = 20 }) => {
|
|
261
|
+
const { data: chunks } = await adminDb.from('items').select('id, title, data')
|
|
262
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
263
|
+
.filter('data->>project_id', 'eq', project_id)
|
|
264
|
+
.filter('data->>doc_confidence', 'eq', 'unverified_legacy')
|
|
265
|
+
.eq('is_active', true)
|
|
266
|
+
.limit(limit)
|
|
267
|
+
|
|
268
|
+
const undocumented = (chunks || []).map((c: any) => ({
|
|
269
|
+
chunk_id: c.id,
|
|
270
|
+
chunk_name: c.data?.chunk_name || '',
|
|
271
|
+
file_path: c.data?.file_path || '',
|
|
272
|
+
chunk_type: c.data?.chunk_type || '',
|
|
273
|
+
line_start: c.data?.line_start || 0,
|
|
274
|
+
line_end: c.data?.line_end || 0,
|
|
275
|
+
}))
|
|
276
|
+
|
|
277
|
+
const { data: allChunks } = await adminDb.from('items').select('id')
|
|
278
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
279
|
+
.filter('data->>project_id', 'eq', project_id)
|
|
280
|
+
.eq('is_active', true)
|
|
281
|
+
|
|
282
|
+
const total = allChunks?.length || 0
|
|
283
|
+
const undocCount = undocumented.length
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
content: [{
|
|
287
|
+
type: 'text',
|
|
288
|
+
text: JSON.stringify({
|
|
289
|
+
project_id,
|
|
290
|
+
summary: {
|
|
291
|
+
total_chunks: total,
|
|
292
|
+
undocumented_shown: undocCount,
|
|
293
|
+
coverage_pct: total > 0 ? Math.round(((total - undocCount) / total) * 100) : 100,
|
|
294
|
+
},
|
|
295
|
+
undocumented,
|
|
296
|
+
}, null, 2),
|
|
297
|
+
}],
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
server.registerTool(
|
|
303
|
+
'spine_cil_get_files_by_status',
|
|
304
|
+
{
|
|
305
|
+
description: `Get the ordered work queue for a pipeline step — all files in a project at a given pipeline status.
|
|
306
|
+
Use this at the start of each pipeline step to get the list of files to process.
|
|
307
|
+
Valid statuses: "0-discovered", "1-selected", "2-chunked", "3-documented", "4-chunk-validated", "5-doc-validated", "6-enriched", "7-embedded-mapped", "8-published".
|
|
308
|
+
Returns file_path, chunk_count, and last_updated for each file. Process files in the order returned — complete all steps for one file before moving to the next.`,
|
|
309
|
+
inputSchema: z.object({
|
|
310
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
311
|
+
status: z.string().describe('Pipeline status to filter by, e.g. "0-discovered", "2-chunked"'),
|
|
312
|
+
include_progress_info: z.boolean().default(false).describe('Include pipeline progress and dependency information'),
|
|
313
|
+
}),
|
|
314
|
+
},
|
|
315
|
+
async ({ project_id, status, include_progress_info }) => {
|
|
316
|
+
const { data: project } = await adminDb.from('items').select('data')
|
|
317
|
+
.eq('id', project_id).maybeSingle()
|
|
318
|
+
if (!project) {
|
|
319
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: `Project not found: ${project_id}` }) }] }
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const fileStatuses: Record<string, string> = project.data?.file_statuses || {}
|
|
323
|
+
|
|
324
|
+
const matchingPaths = Object.entries(fileStatuses)
|
|
325
|
+
.filter(([, v]) => v === status)
|
|
326
|
+
.map(([file_path]) => file_path)
|
|
327
|
+
|
|
328
|
+
if (matchingPaths.length === 0) {
|
|
329
|
+
return {
|
|
330
|
+
content: [{
|
|
331
|
+
type: 'text',
|
|
332
|
+
text: JSON.stringify({ ok: true, project_id, status, file_count: 0, files: [], message: `No files found with status "${status}"` }, null, 2),
|
|
333
|
+
}],
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const { data: chunks } = await adminDb.from('items').select('data')
|
|
338
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
339
|
+
.filter('data->>project_id', 'eq', project_id)
|
|
340
|
+
.eq('is_active', true)
|
|
341
|
+
.in('data->>file_path' as any, matchingPaths)
|
|
342
|
+
|
|
343
|
+
const chunkCountByFile: Record<string, number> = {}
|
|
344
|
+
for (const c of chunks || []) {
|
|
345
|
+
const fp = c.data?.file_path
|
|
346
|
+
if (fp) chunkCountByFile[fp] = (chunkCountByFile[fp] || 0) + 1
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const files = matchingPaths.map(file_path => {
|
|
350
|
+
const baseFile = {
|
|
351
|
+
file_path,
|
|
352
|
+
status,
|
|
353
|
+
chunk_count: chunkCountByFile[file_path] || 0,
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (include_progress_info) {
|
|
357
|
+
const completedSteps = getCompletedSteps(file_path, fileStatuses)
|
|
358
|
+
const readySteps = getReadySteps(file_path, fileStatuses)
|
|
359
|
+
const blockedSteps = getBlockedSteps(file_path, fileStatuses)
|
|
360
|
+
|
|
361
|
+
return {
|
|
362
|
+
...baseFile,
|
|
363
|
+
completed_steps: completedSteps,
|
|
364
|
+
ready_for: readySteps,
|
|
365
|
+
blocked_by: blockedSteps,
|
|
366
|
+
progress_percentage: calculateProgress(file_path, fileStatuses),
|
|
367
|
+
can_proceed_to: readySteps
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return baseFile
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
return {
|
|
375
|
+
content: [{
|
|
376
|
+
type: 'text',
|
|
377
|
+
text: JSON.stringify({ ok: true, project_id, status, file_count: files.length, files }, null, 2),
|
|
378
|
+
}],
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
server.registerTool(
|
|
384
|
+
'spine_cil_update_pipeline_status_flexible',
|
|
385
|
+
{
|
|
386
|
+
description: 'Update pipeline status with dependency tracking and progress monitoring for flexible processing.',
|
|
387
|
+
inputSchema: z.object({
|
|
388
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
389
|
+
file_path: z.string().describe('File path relative to repo root'),
|
|
390
|
+
status: z.string().describe('New pipeline status'),
|
|
391
|
+
step_completed: z.number().optional().describe('Step number that was just completed'),
|
|
392
|
+
force: z.boolean().default(false).describe('Force update even if dependencies not met'),
|
|
393
|
+
}),
|
|
394
|
+
},
|
|
395
|
+
async ({ project_id, file_path, status, step_completed, force }) => {
|
|
396
|
+
|
|
397
|
+
const { data: project } = await adminDb.from('items').select('data')
|
|
398
|
+
.eq('id', project_id).maybeSingle()
|
|
399
|
+
|
|
400
|
+
if (!project) {
|
|
401
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: `Project not found: ${project_id}` }) }] }
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (!force) {
|
|
405
|
+
const fileStatuses = project.data?.file_statuses || {}
|
|
406
|
+
const completedSteps = getCompletedSteps(file_path, fileStatuses)
|
|
407
|
+
|
|
408
|
+
const statusRequirements: Record<string, number[]> = {
|
|
409
|
+
'0-discovered': [],
|
|
410
|
+
'1-selected': [0],
|
|
411
|
+
'2-chunked': [1],
|
|
412
|
+
'3-documented': [2],
|
|
413
|
+
'4-chunk-validated': [3],
|
|
414
|
+
'5-doc-validated': [4],
|
|
415
|
+
'6-enriched': [5],
|
|
416
|
+
'7-embedded-mapped': [6],
|
|
417
|
+
'8-published': [7],
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const requiredSteps = statusRequirements[status] || []
|
|
421
|
+
const missingSteps = requiredSteps.filter(step => !completedSteps.includes(step))
|
|
422
|
+
|
|
423
|
+
if (missingSteps.length > 0) {
|
|
424
|
+
return {
|
|
425
|
+
content: [{
|
|
426
|
+
type: 'text',
|
|
427
|
+
text: JSON.stringify({
|
|
428
|
+
ok: false,
|
|
429
|
+
error: `Cannot update to ${status}. Missing prerequisite steps: ${missingSteps.join(', ')}`,
|
|
430
|
+
current_completed: completedSteps,
|
|
431
|
+
required: requiredSteps
|
|
432
|
+
})
|
|
433
|
+
}]
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const fileStatuses = project.data?.file_statuses || {}
|
|
439
|
+
const previousStatus = fileStatuses[file_path]
|
|
440
|
+
fileStatuses[file_path] = status
|
|
441
|
+
|
|
442
|
+
const { error } = await adminDb.from('items')
|
|
443
|
+
.update({
|
|
444
|
+
data: {
|
|
445
|
+
...project.data,
|
|
446
|
+
file_statuses: fileStatuses,
|
|
447
|
+
last_ingested_at: new Date().toISOString()
|
|
448
|
+
}
|
|
449
|
+
})
|
|
450
|
+
.eq('id', project_id)
|
|
451
|
+
|
|
452
|
+
if (error) {
|
|
453
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: error.message }) }] }
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const updatedState = {
|
|
457
|
+
file_path,
|
|
458
|
+
previous_status: previousStatus,
|
|
459
|
+
new_status: status,
|
|
460
|
+
step_completed,
|
|
461
|
+
completed_steps: getCompletedSteps(file_path, fileStatuses),
|
|
462
|
+
ready_for: getReadySteps(file_path, fileStatuses),
|
|
463
|
+
blocked_by: getBlockedSteps(file_path, fileStatuses),
|
|
464
|
+
progress_percentage: calculateProgress(file_path, fileStatuses)
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
return {
|
|
468
|
+
content: [{
|
|
469
|
+
type: 'text',
|
|
470
|
+
text: JSON.stringify({ ok: true, ...updatedState }, null, 2)
|
|
471
|
+
}],
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
server.registerTool(
|
|
477
|
+
'spine_cil_list_files',
|
|
478
|
+
{
|
|
479
|
+
description: 'List indexed files for a CIL project with their status and chunk counts.',
|
|
480
|
+
inputSchema: z.object({
|
|
481
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
482
|
+
limit: z.number().int().min(1).max(1000).default(100).optional(),
|
|
483
|
+
}),
|
|
484
|
+
},
|
|
485
|
+
async ({ project_id, limit = 100 }) => {
|
|
486
|
+
const { data: project } = await adminDb.from('items').select('data')
|
|
487
|
+
.eq('id', project_id).maybeSingle()
|
|
488
|
+
if (!project) {
|
|
489
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: `Project not found: ${project_id}` }) }] }
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const { data: chunks, error } = await adminDb.from('items').select('id, data')
|
|
493
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
494
|
+
.filter('data->>project_id', 'eq', project_id)
|
|
495
|
+
.eq('is_active', true)
|
|
496
|
+
.limit(limit)
|
|
497
|
+
|
|
498
|
+
if (error) {
|
|
499
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: error.message }) }] }
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const fileMap: Record<string, { chunk_count: number; statuses: Set<string> }> = {}
|
|
503
|
+
for (const c of chunks || []) {
|
|
504
|
+
const fp = c.data?.file_path || ''
|
|
505
|
+
if (!fp) continue
|
|
506
|
+
if (!fileMap[fp]) fileMap[fp] = { chunk_count: 0, statuses: new Set() }
|
|
507
|
+
fileMap[fp].chunk_count += 1
|
|
508
|
+
if (c.data?.status) fileMap[fp].statuses.add(c.data.status)
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const fileStatuses: Record<string, string> = project.data?.file_statuses || {}
|
|
512
|
+
const files = Object.entries(fileMap).map(([file_path, info]) => ({
|
|
513
|
+
file_path,
|
|
514
|
+
status: fileStatuses[file_path] || null,
|
|
515
|
+
chunk_count: info.chunk_count,
|
|
516
|
+
chunk_statuses: Array.from(info.statuses),
|
|
517
|
+
})).sort((a, b) => a.file_path.localeCompare(b.file_path))
|
|
518
|
+
|
|
519
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, project_id, file_count: files.length, files }, null, 2) }] }
|
|
520
|
+
}
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
server.registerTool(
|
|
524
|
+
'spine_cil_list_versions',
|
|
525
|
+
{
|
|
526
|
+
description: 'List all versions for a CIL project.',
|
|
527
|
+
inputSchema: z.object({
|
|
528
|
+
project_id: z.string().describe('The cil_project UUID'),
|
|
529
|
+
}),
|
|
530
|
+
},
|
|
531
|
+
async ({ project_id }) => {
|
|
532
|
+
try {
|
|
533
|
+
const { data, error } = await adminDb.from('items')
|
|
534
|
+
.select('id, title, data')
|
|
535
|
+
.filter('data->>kb_type', 'eq', 'cil_version')
|
|
536
|
+
.filter('data->>project_id', 'eq', project_id)
|
|
537
|
+
.order('created_at', { ascending: false })
|
|
538
|
+
if (error) return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: error.message }) }] }
|
|
539
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, versions: data || [] }) }] }
|
|
540
|
+
} catch (err: any) {
|
|
541
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message || String(err) }) }] }
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
server.registerTool(
|
|
547
|
+
'spine_cil_create_version',
|
|
548
|
+
{
|
|
549
|
+
description: 'Create a new CIL version for a project. The version must be valid semver; prerelease versions are automatically marked as iterations.',
|
|
550
|
+
inputSchema: z.object({
|
|
551
|
+
project_id: z.string().describe('The cil_project UUID'),
|
|
552
|
+
version: z.string().describe('Version string, e.g. "0.1.0" or "0.1.6-dev.467.1"'),
|
|
553
|
+
base_version: z.string().optional().describe('Optional base version string to copy from'),
|
|
554
|
+
}),
|
|
555
|
+
},
|
|
556
|
+
async ({ project_id, version, base_version }) => {
|
|
557
|
+
try {
|
|
558
|
+
const result = await fetchFunction('cil-project', 'create_version', {}, {
|
|
559
|
+
project_id,
|
|
560
|
+
version,
|
|
561
|
+
base_version,
|
|
562
|
+
})
|
|
563
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, version: result.version }) }] }
|
|
564
|
+
} catch (err: any) {
|
|
565
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message || String(err) }) }] }
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
server.registerTool(
|
|
571
|
+
'spine_cil_set_active_version',
|
|
572
|
+
{
|
|
573
|
+
description: 'Set the active version for a CIL project.',
|
|
574
|
+
inputSchema: z.object({
|
|
575
|
+
project_id: z.string().describe('The cil_project UUID'),
|
|
576
|
+
version_id: z.string().describe('The cil_version UUID to make active'),
|
|
577
|
+
}),
|
|
578
|
+
},
|
|
579
|
+
async ({ project_id, version_id }) => {
|
|
580
|
+
try {
|
|
581
|
+
const result = await fetchFunction('cil-project', 'set_active_version', {}, {
|
|
582
|
+
project_id,
|
|
583
|
+
version_id,
|
|
584
|
+
})
|
|
585
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, project: result.project, version_id: result.version_id }) }] }
|
|
586
|
+
} catch (err: any) {
|
|
587
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message || String(err) }) }] }
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
server.registerTool(
|
|
593
|
+
'spine_cil_publish_version',
|
|
594
|
+
{
|
|
595
|
+
description: 'Publish a new CIL version. Marks all other versions as inactive and sets it as the active and default version.',
|
|
596
|
+
inputSchema: z.object({
|
|
597
|
+
project_id: z.string().describe('The cil_project UUID'),
|
|
598
|
+
version: z.string().describe('Version string to publish, e.g. "0.2.0"'),
|
|
599
|
+
base_version: z.string().optional().describe('Optional base version whose prerelease iteration should be linked'),
|
|
600
|
+
}),
|
|
601
|
+
},
|
|
602
|
+
async ({ project_id, version, base_version }) => {
|
|
603
|
+
try {
|
|
604
|
+
const result = await fetchFunction('cil-project', 'publish_version', {}, {
|
|
605
|
+
project_id,
|
|
606
|
+
version,
|
|
607
|
+
base_version,
|
|
608
|
+
})
|
|
609
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, version: result.version, project: result.project }) }] }
|
|
610
|
+
} catch (err: any) {
|
|
611
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message || String(err) }) }] }
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
server.registerTool(
|
|
617
|
+
'spine_cil_mark_versions_inactive',
|
|
618
|
+
{
|
|
619
|
+
description: 'Mark all CIL versions whose version string matches a pattern as inactive.',
|
|
620
|
+
inputSchema: z.object({
|
|
621
|
+
project_id: z.string().describe('The cil_project UUID'),
|
|
622
|
+
version_pattern: z.string().describe('Substring to match in version strings'),
|
|
623
|
+
}),
|
|
624
|
+
},
|
|
625
|
+
async ({ project_id, version_pattern }) => {
|
|
626
|
+
try {
|
|
627
|
+
const result = await fetchFunction('cil-project', 'mark_versions_inactive', {}, {
|
|
628
|
+
project_id,
|
|
629
|
+
version_pattern,
|
|
630
|
+
})
|
|
631
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, ...result }) }] }
|
|
632
|
+
} catch (err: any) {
|
|
633
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message || String(err) }) }] }
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
server.registerTool(
|
|
639
|
+
'spine_cil_archive_versions',
|
|
640
|
+
{
|
|
641
|
+
description: 'Archive the oldest inactive CIL versions, keeping only the most recent N inactive versions.',
|
|
642
|
+
inputSchema: z.object({
|
|
643
|
+
project_id: z.string().describe('The cil_project UUID'),
|
|
644
|
+
keep_last_n: z.number().int().min(0).describe('Number of most recent inactive versions to keep'),
|
|
645
|
+
}),
|
|
646
|
+
},
|
|
647
|
+
async ({ project_id, keep_last_n }) => {
|
|
648
|
+
try {
|
|
649
|
+
const result = await fetchFunction('cil-project', 'archive_versions', {}, {
|
|
650
|
+
project_id,
|
|
651
|
+
keep_last_n,
|
|
652
|
+
})
|
|
653
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, ...result }) }] }
|
|
654
|
+
} catch (err: any) {
|
|
655
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message || String(err) }) }] }
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
server.registerTool(
|
|
661
|
+
'spine_cil_create_project',
|
|
662
|
+
{
|
|
663
|
+
description: 'Create a new CIL project for a repository. The project will be created with discovery not yet run.',
|
|
664
|
+
inputSchema: z.object({
|
|
665
|
+
title: z.string().describe('Project title'),
|
|
666
|
+
repo_path: z.string().describe('Absolute path to the repository root'),
|
|
667
|
+
npm_name: z.string().describe('NPM package name'),
|
|
668
|
+
canonical_root: z.string().describe('Canonical root prefix for stable IDs'),
|
|
669
|
+
kind: z.enum(['core', 'custom']).default('custom').describe('Project kind: core (framework) or custom app'),
|
|
670
|
+
globs: z.array(z.string()).default(['**/*.{ts,tsx,js,jsx}']).optional().describe('Globs for source discovery'),
|
|
671
|
+
exclude_globs: z.array(z.string()).default(['**/node_modules/**', '**/dist/**', '**/*.d.ts']).optional().describe('Globs to exclude'),
|
|
672
|
+
}),
|
|
673
|
+
},
|
|
674
|
+
async ({ title, repo_path, npm_name, canonical_root, kind, globs, exclude_globs }) => {
|
|
675
|
+
try {
|
|
676
|
+
const result = await fetchFunction('cil-project', 'create', {}, {
|
|
677
|
+
title,
|
|
678
|
+
repo_path,
|
|
679
|
+
npm_name,
|
|
680
|
+
canonical_root,
|
|
681
|
+
kind,
|
|
682
|
+
globs,
|
|
683
|
+
exclude_globs,
|
|
684
|
+
})
|
|
685
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, ...result }) }] }
|
|
686
|
+
} catch (err: any) {
|
|
687
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message || String(err) }) }] }
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
server.registerTool(
|
|
693
|
+
'spine_cil_delete_project',
|
|
694
|
+
{
|
|
695
|
+
description: 'Delete a CIL project and all attached records: files, chunks, proposals, versions, suggestions, embeddings, and links.',
|
|
696
|
+
inputSchema: z.object({
|
|
697
|
+
project_id: z.string().uuid().describe('The cil_project UUID to delete'),
|
|
698
|
+
}),
|
|
699
|
+
},
|
|
700
|
+
async ({ project_id }) => {
|
|
701
|
+
try {
|
|
702
|
+
const result = await fetchFunction('cil-project', 'delete', { id: project_id })
|
|
703
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, ...result }) }] }
|
|
704
|
+
} catch (err: any) {
|
|
705
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message || String(err) }) }] }
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
server.registerTool(
|
|
711
|
+
'spine_cil_select_files',
|
|
712
|
+
{
|
|
713
|
+
description: 'Set the selected file paths for a CIL project and advance matching discovered files to 1-selected. Files must already have been discovered (step 0). Only selected files are processed by steps 2-8.',
|
|
714
|
+
inputSchema: z.object({
|
|
715
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
716
|
+
selected_paths: z.array(z.string()).describe('List of relative file paths or directories to include in ingestion'),
|
|
717
|
+
}),
|
|
718
|
+
},
|
|
719
|
+
async ({ project_id, selected_paths }) => {
|
|
720
|
+
try {
|
|
721
|
+
const result = await fetchFunction('cil-ingest', 'select', {}, { project_id, selected_paths })
|
|
722
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true, ...result }) }] }
|
|
723
|
+
} catch (err: any) {
|
|
724
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message || String(err) }) }] }
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
)
|
|
728
|
+
|
|
729
|
+
server.registerTool(
|
|
730
|
+
'spine_cil_publish',
|
|
731
|
+
{
|
|
732
|
+
description: 'Publish a CIL project version and mark all files at 7-embedded-mapped as 8-published. If file_path is provided, only that file is published.',
|
|
733
|
+
inputSchema: z.object({
|
|
734
|
+
project_id: z.string().uuid().describe('The cil_project UUID'),
|
|
735
|
+
version: z.string().describe('Version string to publish, e.g. "0.2.0"'),
|
|
736
|
+
file_path: z.string().optional().describe('Optional single file to publish'),
|
|
737
|
+
}),
|
|
738
|
+
},
|
|
739
|
+
async ({ project_id, version, file_path }) => {
|
|
740
|
+
try {
|
|
741
|
+
const pubResult = await fetchFunction('cil-project', 'publish_version', {}, {
|
|
742
|
+
project_id,
|
|
743
|
+
version,
|
|
744
|
+
})
|
|
745
|
+
|
|
746
|
+
const { data: project } = await adminDb.from('items').select('data').eq('id', project_id).maybeSingle()
|
|
747
|
+
const fileStatuses: Record<string, string> = project?.data?.file_statuses || {}
|
|
748
|
+
const now = new Date().toISOString()
|
|
749
|
+
const updated: Record<string, string> = {}
|
|
750
|
+
for (const [fp, status] of Object.entries(fileStatuses)) {
|
|
751
|
+
if (file_path && fp !== file_path) continue
|
|
752
|
+
if (status === '7-embedded-mapped') {
|
|
753
|
+
updated[fp] = '8-published'
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
if (Object.keys(updated).length > 0) {
|
|
758
|
+
const newStatuses = { ...fileStatuses, ...updated }
|
|
759
|
+
await adminDb.from('items').update({
|
|
760
|
+
data: { ...project.data, file_statuses: newStatuses, published_at: now },
|
|
761
|
+
updated_at: now,
|
|
762
|
+
}).eq('id', project_id)
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return {
|
|
766
|
+
content: [{
|
|
767
|
+
type: 'text',
|
|
768
|
+
text: JSON.stringify({
|
|
769
|
+
ok: true,
|
|
770
|
+
project_id,
|
|
771
|
+
version,
|
|
772
|
+
version_id: pubResult.version?.id,
|
|
773
|
+
published_files: Object.keys(updated).length,
|
|
774
|
+
file_path: file_path || null,
|
|
775
|
+
}, null, 2),
|
|
776
|
+
}],
|
|
777
|
+
}
|
|
778
|
+
} catch (err: any) {
|
|
779
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: err?.message || String(err) }) }] }
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
}
|
|
785
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Register CIL project management and version lifecycle tools on an MCP server'; No verified external callers; imports: .framework/functions/_shared/cil.ts,.framework/mcp/shared/db.ts"]
|
|
786
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
787
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
788
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
789
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
790
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
791
|
+
// CIL[END stable_id="~/.framework/mcp/tools/cil/project.ts:register:function"]
|