spine-framework 0.4.4 → 0.5.0-rc.5

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.
Files changed (305) hide show
  1. package/.env.example +13 -3
  2. package/.framework/cli/commands/bootstrap.ts +392 -0
  3. package/.framework/cli/commands/dev.ts +91 -218
  4. package/.framework/cli/commands/doctor.ts +132 -26
  5. package/.framework/cli/commands/generate.ts +38 -298
  6. package/.framework/cli/commands/init.ts +20 -1
  7. package/.framework/cli/commands/install-app.ts +183 -13
  8. package/.framework/cli/commands/migrate.ts +36 -30
  9. package/.framework/cli/commands/migrations.ts +16 -56
  10. package/.framework/cli/commands/upgrade.ts +35 -0
  11. package/.framework/cli/commands/validate-app.ts +127 -1
  12. package/.framework/cli/commands/validate-schema.ts +147 -0
  13. package/.framework/cli/context.ts +223 -110
  14. package/.framework/cli/index.ts +6 -0
  15. package/.framework/cli/lib/project-files.ts +241 -1
  16. package/.framework/functions/_shared/app-manifest.ts +2 -0
  17. package/.framework/functions/_shared/hash-api-key.ts +183 -79
  18. package/.framework/functions/_shared/logging.ts +562 -224
  19. package/.framework/functions/_shared/middleware.ts +47 -44
  20. package/.framework/functions/_shared/permissions.ts +4 -0
  21. package/.framework/functions/admin-data.ts +51 -28
  22. package/.framework/functions/ai-agents.ts +10 -6
  23. package/.framework/functions/api-keys.ts +301 -122
  24. package/.framework/functions/apps.ts +63 -29
  25. package/.framework/functions/cil-ingest.ts +48 -15
  26. package/.framework/functions/debug-auth.ts +14 -8
  27. package/.framework/functions/deliveries.ts +39 -12
  28. package/.framework/functions/embeddings.ts +149 -78
  29. package/.framework/functions/integration-outbound.ts +67 -27
  30. package/.framework/functions/integrations.ts +254 -127
  31. package/.framework/functions/logs.ts +273 -133
  32. package/.framework/functions/observability.ts +278 -148
  33. package/.framework/functions/pipeline-executions.ts +1 -1
  34. package/.framework/functions/pipelines.ts +14 -9
  35. package/.framework/functions/prompt-configs.ts +7 -4
  36. package/.framework/functions/roles.ts +8 -5
  37. package/.framework/functions/security.ts +30 -17
  38. package/.framework/functions/system-cron.ts +240 -127
  39. package/.framework/functions/tests.ts +7 -6
  40. package/.framework/functions/timers.ts +310 -107
  41. package/.framework/functions/triggers.ts +28 -13
  42. package/.framework/functions/types.ts +13 -10
  43. package/.framework/migrations/069_log_stats_window.sql +54 -0
  44. package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
  45. package/.framework/migrations/071_timer_interval_keys.sql +96 -0
  46. package/.framework/migrations/072_slug_autofill.sql +77 -0
  47. package/.framework/migrations/073_seed_member_roles.sql +26 -0
  48. package/.framework/migrations/074_app_route_prefix_domains.sql +168 -0
  49. package/.framework/migrations/075_security_definer_grants.sql +157 -0
  50. package/.framework/src/apps/admin/index.tsx +1141 -775
  51. package/.framework/src/components/ErrorBoundary.tsx +136 -0
  52. package/.framework/src/components/admin/AdminListPage.tsx +81 -73
  53. package/.framework/src/components/admin/AdminSidebar.tsx +88 -79
  54. package/.framework/src/components/admin/EntitySelect.tsx +181 -0
  55. package/.framework/src/components/admin/PageInstructions.tsx +86 -127
  56. package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
  57. package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
  58. package/.framework/src/components/layout/Sidebar.tsx +300 -177
  59. package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
  60. package/.framework/src/components/runtime/DataHeader.tsx +96 -48
  61. package/.framework/src/components/runtime/DataListPage.tsx +3 -26
  62. package/.framework/src/components/runtime/DataStats.tsx +10 -10
  63. package/.framework/src/components/runtime/DataTable.tsx +12 -10
  64. package/.framework/src/components/ui/sheet.tsx +24 -26
  65. package/.framework/src/components/ui/textarea.tsx +74 -48
  66. package/.framework/src/contexts/AppContext.tsx +5 -12
  67. package/.framework/src/contexts/AuthContext.tsx +17 -9
  68. package/.framework/src/hooks/useApps.ts +18 -22
  69. package/.framework/src/hooks/useEntityList.ts +12 -9
  70. package/.framework/src/hooks/useListSchema.ts +108 -58
  71. package/.framework/src/instructions/README.md +74 -0
  72. package/.framework/src/instructions/accounts.md +97 -0
  73. package/.framework/src/instructions/ai-agents.md +69 -0
  74. package/.framework/src/instructions/alerts.md +80 -0
  75. package/.framework/src/instructions/api-keys.md +87 -0
  76. package/.framework/src/instructions/apps.md +77 -0
  77. package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
  78. package/.framework/src/instructions/concepts/apps-and-renderers.md +228 -0
  79. package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
  80. package/.framework/src/instructions/concepts/automation.md +186 -0
  81. package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
  82. package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
  83. package/.framework/src/instructions/concepts/design-schema.md +152 -0
  84. package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
  85. package/.framework/src/instructions/concepts/observability.md +116 -0
  86. package/.framework/src/instructions/concepts/permissions.md +150 -0
  87. package/.framework/src/instructions/concepts/runtime-records.md +111 -0
  88. package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
  89. package/.framework/src/instructions/concepts/spine-way.md +172 -0
  90. package/.framework/src/instructions/deliveries.md +59 -0
  91. package/.framework/src/instructions/guide/00-orientation.md +106 -0
  92. package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
  93. package/.framework/src/instructions/guide/02-project-map.md +147 -0
  94. package/.framework/src/instructions/guide/03-domain-model.md +223 -0
  95. package/.framework/src/instructions/guide/04-first-app.md +227 -0
  96. package/.framework/src/instructions/guide/05-glossary.md +183 -0
  97. package/.framework/src/instructions/integrations.md +96 -0
  98. package/.framework/src/instructions/internal/cil-markers.md +83 -0
  99. package/.framework/src/instructions/internal/docs-contract.md +158 -0
  100. package/.framework/src/instructions/invites.md +60 -0
  101. package/.framework/src/instructions/kb.md +80 -0
  102. package/.framework/src/instructions/logs.md +77 -0
  103. package/.framework/src/instructions/notifications.md +77 -0
  104. package/.framework/src/instructions/observability.md +61 -0
  105. package/.framework/src/instructions/operations/deployment.md +115 -0
  106. package/.framework/src/instructions/operations/migrations.md +125 -0
  107. package/.framework/src/instructions/operations/security-checklist.md +170 -0
  108. package/.framework/src/instructions/operations/troubleshooting.md +170 -0
  109. package/.framework/src/instructions/operations/upgrade.md +116 -0
  110. package/.framework/src/instructions/people.md +91 -0
  111. package/.framework/src/instructions/pipeline-executions.md +62 -0
  112. package/.framework/src/instructions/pipelines.md +78 -0
  113. package/.framework/src/instructions/prompts.md +95 -0
  114. package/.framework/src/instructions/reference/api/admin-data.md +162 -0
  115. package/.framework/src/instructions/reference/api/auth.md +113 -0
  116. package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
  117. package/.framework/src/instructions/reference/app-manifest.md +184 -0
  118. package/.framework/src/instructions/reference/cli.md +124 -0
  119. package/.framework/src/instructions/reference/database.md +132 -0
  120. package/.framework/src/instructions/reference/design-schema.md +280 -0
  121. package/.framework/src/instructions/reference/env-vars.md +133 -0
  122. package/.framework/src/instructions/reference/frontend-sdk.md +207 -0
  123. package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
  124. package/.framework/src/instructions/reference/functions/admin-data.md +197 -0
  125. package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
  126. package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
  127. package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
  128. package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
  129. package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
  130. package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
  131. package/.framework/src/instructions/reference/functions/apps.md +140 -0
  132. package/.framework/src/instructions/reference/functions/auth.md +99 -0
  133. package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
  134. package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
  135. package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
  136. package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
  137. package/.framework/src/instructions/reference/functions/index.md +103 -0
  138. package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
  139. package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
  140. package/.framework/src/instructions/reference/functions/integrations.md +130 -0
  141. package/.framework/src/instructions/reference/functions/invites.md +182 -0
  142. package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
  143. package/.framework/src/instructions/reference/functions/kb.md +166 -0
  144. package/.framework/src/instructions/reference/functions/logs.md +141 -0
  145. package/.framework/src/instructions/reference/functions/observability.md +105 -0
  146. package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
  147. package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
  148. package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
  149. package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
  150. package/.framework/src/instructions/reference/functions/roles.md +121 -0
  151. package/.framework/src/instructions/reference/functions/security.md +140 -0
  152. package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
  153. package/.framework/src/instructions/reference/functions/system.md +106 -0
  154. package/.framework/src/instructions/reference/functions/tests.md +97 -0
  155. package/.framework/src/instructions/reference/functions/timers.md +117 -0
  156. package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
  157. package/.framework/src/instructions/reference/functions/triggers.md +140 -0
  158. package/.framework/src/instructions/reference/functions/types.md +146 -0
  159. package/.framework/src/instructions/reference/seeds.md +126 -0
  160. package/.framework/src/instructions/reference/shared-modules.md +127 -0
  161. package/.framework/src/instructions/reference/spine-config.md +114 -0
  162. package/.framework/src/instructions/roles.md +80 -0
  163. package/.framework/src/instructions/runtime-collaboration.md +106 -0
  164. package/.framework/src/instructions/runtime-detail.md +70 -0
  165. package/.framework/src/instructions/runtime-list.md +77 -0
  166. package/.framework/src/instructions/security.md +67 -0
  167. package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
  168. package/.framework/src/instructions/tasks/add-a-role.md +96 -0
  169. package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
  170. package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
  171. package/.framework/src/instructions/tasks/add-a-type.md +151 -0
  172. package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
  173. package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
  174. package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
  175. package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
  176. package/.framework/src/instructions/tasks/document-your-app.md +117 -0
  177. package/.framework/src/instructions/tasks/package-and-install-an-app.md +136 -0
  178. package/.framework/src/instructions/tasks/register-an-app.md +137 -0
  179. package/.framework/src/instructions/tasks/test-your-code.md +108 -0
  180. package/.framework/src/instructions/tasks/write-a-function.md +132 -0
  181. package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
  182. package/.framework/src/instructions/testing.md +59 -0
  183. package/.framework/src/instructions/timers.md +84 -0
  184. package/.framework/src/instructions/triggers.md +69 -0
  185. package/.framework/src/instructions/types.md +93 -0
  186. package/.framework/src/lib/app-mount.ts +88 -0
  187. package/.framework/src/pages/NotFoundPage.tsx +62 -31
  188. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
  189. package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
  190. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
  191. package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
  192. package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
  193. package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
  194. package/.framework/src/pages/admin/AppsPage.tsx +104 -66
  195. package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
  196. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
  197. package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
  198. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
  199. package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
  200. package/.framework/src/pages/admin/LogsPage.tsx +144 -76
  201. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
  202. package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
  203. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
  204. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
  205. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
  206. package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
  207. package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
  208. package/.framework/src/pages/admin/RolesPage.tsx +86 -43
  209. package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
  210. package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
  211. package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
  212. package/.framework/src/pages/admin/TimersPage.tsx +90 -62
  213. package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
  214. package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
  215. package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
  216. package/.framework/src/pages/admin/TypesPage.tsx +90 -48
  217. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
  218. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
  219. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
  220. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
  221. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
  222. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
  223. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
  224. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
  225. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
  226. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
  227. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
  228. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
  229. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
  230. package/.framework/src/pages/auth/LoginPage.tsx +3 -2
  231. package/.framework/src/pages/auth/RegisterPage.tsx +16 -8
  232. package/.framework/templates/agent/AGENTS.md +167 -0
  233. package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
  234. package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
  235. package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
  236. package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
  237. package/.framework/templates/agent/skills/spine-install-app/SKILL.md +79 -0
  238. package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
  239. package/.framework/templates/agent/skills/spine-new-app/SKILL.md +79 -0
  240. package/.framework/templates/agent/skills/spine-new-function/SKILL.md +71 -0
  241. package/.framework/templates/agent/skills/spine-new-type/SKILL.md +72 -0
  242. package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
  243. package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
  244. package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
  245. package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
  246. package/.framework/templates/project.json +4 -1
  247. package/.framework/tests/unit/account-scoping-gates.test.ts +394 -0
  248. package/.framework/tests/unit/agent-files.test.ts +355 -0
  249. package/.framework/tests/unit/agent-runner.test.ts +479 -44
  250. package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
  251. package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
  252. package/.framework/tests/unit/app-mount.test.ts +80 -0
  253. package/.framework/tests/unit/bootstrap.test.ts +242 -0
  254. package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
  255. package/.framework/tests/unit/debug-auth.test.ts +38 -0
  256. package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
  257. package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
  258. package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
  259. package/.framework/tests/unit/logging-app-id.test.ts +75 -0
  260. package/.framework/tests/unit/security-definer-grants.test.ts +154 -0
  261. package/.framework/tests/unit/system-context-denial.test.ts +145 -0
  262. package/.framework/tests/unit/system-cron.test.ts +240 -0
  263. package/.framework/tests/unit/timers.test.ts +159 -0
  264. package/README.md +125 -166
  265. package/config/tsconfig.cli.json +2 -2
  266. package/package.json +15 -4
  267. package/templates/project/package-lock.json +2 -2
  268. package/.framework/docs/admin-routes.md +0 -76
  269. package/.framework/docs/api-docs-progress.md +0 -38
  270. package/.framework/docs/api-governance.md +0 -146
  271. package/.framework/docs/api-testing-results.md +0 -212
  272. package/.framework/docs/assembly-launch-guide.md +0 -138
  273. package/.framework/docs/audit-results.md +0 -590
  274. package/.framework/docs/db-api-inventory.md +0 -95
  275. package/.framework/docs/gap-remediation-backlog.md +0 -103
  276. package/.framework/docs/ui-adoption-verification.md +0 -111
  277. package/.framework/docs/ui-api-coverage.md +0 -84
  278. package/.framework/docs/v2-compatibility-audit.md +0 -228
  279. package/.framework/mcp/index.ts +0 -133
  280. package/.framework/mcp/load-env.ts +0 -60
  281. package/.framework/mcp/shared/app-manifest.ts +0 -275
  282. package/.framework/mcp/shared/db.ts +0 -477
  283. package/.framework/mcp/shared/kb.ts +0 -118
  284. package/.framework/mcp/tools/architect.ts +0 -431
  285. package/.framework/mcp/tools/cil/context.ts +0 -345
  286. package/.framework/mcp/tools/cil/graph.ts +0 -242
  287. package/.framework/mcp/tools/cil/ingest.ts +0 -1217
  288. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
  289. package/.framework/mcp/tools/cil/pipeline.ts +0 -767
  290. package/.framework/mcp/tools/cil/project.ts +0 -791
  291. package/.framework/mcp/tools/cil/retrieval.ts +0 -336
  292. package/.framework/mcp/tools/cil/search-core.ts +0 -454
  293. package/.framework/mcp/tools/cil/search.ts +0 -97
  294. package/.framework/mcp/tools/cil/suggest.ts +0 -186
  295. package/.framework/mcp/tools/cil/validate.ts +0 -1369
  296. package/.framework/mcp/tools/kb/delete.ts +0 -139
  297. package/.framework/mcp/tools/kb/index.ts +0 -52
  298. package/.framework/mcp/tools/kb/ingest.ts +0 -84
  299. package/.framework/mcp/tools/kb/list-types.ts +0 -102
  300. package/.framework/mcp/tools/kb/publish.ts +0 -100
  301. package/.framework/mcp/tools/kb/reindex.ts +0 -86
  302. package/.framework/mcp/tools/kb/revoke.ts +0 -85
  303. package/.framework/mcp/tools/kb/search.ts +0 -101
  304. package/.framework/mcp/tools/kb/upsert.ts +0 -125
  305. package/.framework/mcp/tools/observability.ts +0 -510
@@ -1,791 +0,0 @@
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"]