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.
Files changed (451) hide show
  1. package/.env.example +76 -0
  2. package/.framework/.spine-manifest.json +19 -0
  3. package/.framework/cli/commands/agents.ts +61 -33
  4. package/.framework/cli/commands/auth.ts +60 -28
  5. package/.framework/cli/commands/create-app.ts +212 -80
  6. package/.framework/cli/commands/dev.ts +184 -68
  7. package/.framework/cli/commands/doctor.ts +324 -152
  8. package/.framework/cli/commands/generate.ts +119 -68
  9. package/.framework/cli/commands/init.ts +141 -242
  10. package/.framework/cli/commands/install-app.ts +1336 -314
  11. package/.framework/cli/commands/items.ts +31 -29
  12. package/.framework/cli/commands/migrate.ts +299 -156
  13. package/.framework/cli/commands/migrations.ts +62 -30
  14. package/.framework/cli/commands/pipelines.ts +31 -29
  15. package/.framework/cli/commands/status.ts +105 -45
  16. package/.framework/cli/commands/system.ts +47 -42
  17. package/.framework/cli/commands/test.ts +161 -102
  18. package/.framework/cli/commands/upgrade.ts +260 -0
  19. package/.framework/cli/commands/validate-app.ts +517 -161
  20. package/.framework/cli/context.ts +117 -85
  21. package/.framework/cli/env-loader.ts +74 -43
  22. package/.framework/cli/index.ts +70 -46
  23. package/.framework/cli/lib/project-files.ts +404 -0
  24. package/.framework/docs/guides/testing-guide.md +1 -1
  25. package/.framework/docs/runtime-types.md +72 -72
  26. package/.framework/functions/_shared/access.ts +84 -0
  27. package/.framework/functions/_shared/agent-runner.ts +5051 -1026
  28. package/.framework/functions/_shared/app-manifest.ts +214 -94
  29. package/.framework/functions/_shared/ast.ts +214 -0
  30. package/.framework/functions/_shared/audit.ts +91 -55
  31. package/.framework/functions/_shared/cil.ts +368 -127
  32. package/.framework/functions/_shared/db.ts +337 -68
  33. package/.framework/functions/_shared/funnel.ts +228 -0
  34. package/.framework/functions/_shared/geo.ts +105 -0
  35. package/.framework/functions/_shared/hash-api-key.ts +94 -17
  36. package/.framework/functions/_shared/index.ts +22 -224
  37. package/.framework/functions/_shared/kb.ts +832 -58
  38. package/.framework/functions/_shared/llm.ts +118 -18
  39. package/.framework/functions/_shared/logging.ts +317 -19
  40. package/.framework/functions/_shared/middleware.ts +701 -131
  41. package/.framework/functions/_shared/notify.ts +70 -0
  42. package/.framework/functions/_shared/outcomes.ts +34 -19
  43. package/.framework/functions/_shared/permissions.ts +501 -315
  44. package/.framework/functions/_shared/pipeline-runner.ts +704 -155
  45. package/.framework/functions/_shared/principal.ts +436 -263
  46. package/.framework/functions/_shared/rate-limit.ts +233 -0
  47. package/.framework/functions/_shared/resolve-credentials.ts +86 -19
  48. package/.framework/functions/_shared/resolve-ids.ts +203 -139
  49. package/.framework/functions/_shared/retry-deliveries.ts +51 -16
  50. package/.framework/functions/_shared/schema-utils.ts +602 -521
  51. package/.framework/functions/_shared/security.ts +345 -0
  52. package/.framework/functions/_shared/testing.ts +197 -172
  53. package/.framework/functions/_shared/tracing.ts +351 -21
  54. package/.framework/functions/_shared/trigger-engine.ts +425 -136
  55. package/.framework/functions/_shared/webhook-registration.ts +71 -70
  56. package/.framework/functions/_shared/webhook-registry.ts +126 -83
  57. package/.framework/functions/account-nodes.ts +30 -30
  58. package/.framework/functions/adapters/generic-webhook-inbound.ts +49 -16
  59. package/.framework/functions/adapters/generic-webhook-outbound.ts +17 -17
  60. package/.framework/functions/adapters/openai-outbound.ts +15 -16
  61. package/.framework/functions/admin-data.ts +596 -173
  62. package/.framework/functions/admin-funnel.ts +64 -60
  63. package/.framework/functions/admin-install-funnel.ts +84 -66
  64. package/.framework/functions/admin-signals.ts +69 -51
  65. package/.framework/functions/ai-agents.ts +431 -106
  66. package/.framework/functions/ai-interactions.ts +186 -112
  67. package/.framework/functions/api-keys.ts +107 -107
  68. package/.framework/functions/apps.ts +154 -136
  69. package/.framework/functions/auth.ts +83 -65
  70. package/.framework/functions/cil-agent-ingest.ts +189 -232
  71. package/.framework/functions/cil-agent.ts +433 -177
  72. package/.framework/functions/cil-callmap.ts +642 -430
  73. package/.framework/functions/cil-config.ts +139 -135
  74. package/.framework/functions/cil-context.ts +214 -127
  75. package/.framework/functions/cil-doc.ts +587 -458
  76. package/.framework/functions/cil-embeddings.ts +453 -364
  77. package/.framework/functions/cil-graph.ts +427 -142
  78. package/.framework/functions/cil-ingest.ts +1418 -1154
  79. package/.framework/functions/cil-pipeline.ts +276 -21
  80. package/.framework/functions/cil-project.ts +659 -132
  81. package/.framework/functions/cil-validate.ts +198 -164
  82. package/.framework/functions/debug-auth.ts +57 -55
  83. package/.framework/functions/deliveries.ts +80 -21
  84. package/.framework/functions/embeddings.ts +1023 -318
  85. package/.framework/functions/eval-harness.ts +146 -108
  86. package/.framework/functions/integration-outbound.ts +205 -75
  87. package/.framework/functions/integration-routes.ts +128 -23
  88. package/.framework/functions/integrations.ts +125 -100
  89. package/.framework/functions/invites.ts +1095 -460
  90. package/.framework/functions/item-progress.ts +158 -102
  91. package/.framework/functions/kb.ts +34 -10
  92. package/.framework/functions/logs.ts +133 -133
  93. package/.framework/functions/observability.ts +152 -122
  94. package/.framework/functions/pipeline-executions.ts +147 -132
  95. package/.framework/functions/pipelines.ts +134 -119
  96. package/.framework/functions/prompt-configs.ts +96 -80
  97. package/.framework/functions/roles.ts +112 -82
  98. package/.framework/functions/security.ts +450 -0
  99. package/.framework/functions/system-cron.ts +117 -80
  100. package/.framework/functions/system.ts +158 -98
  101. package/.framework/functions/tests.ts +29 -29
  102. package/.framework/functions/timers.ts +94 -95
  103. package/.framework/functions/trigger-scheduler.ts +10 -0
  104. package/.framework/functions/triggers.ts +179 -149
  105. package/.framework/functions/types.ts +137 -125
  106. package/.framework/mcp/index.ts +133 -0
  107. package/.framework/mcp/load-env.ts +60 -0
  108. package/.framework/mcp/shared/app-manifest.ts +275 -0
  109. package/.framework/mcp/shared/db.ts +477 -0
  110. package/.framework/mcp/shared/kb.ts +118 -0
  111. package/.framework/mcp/tools/architect.ts +431 -0
  112. package/.framework/mcp/tools/cil/context.ts +345 -0
  113. package/.framework/mcp/tools/cil/graph.ts +242 -0
  114. package/.framework/mcp/tools/cil/ingest.ts +1217 -0
  115. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +693 -0
  116. package/.framework/mcp/tools/cil/pipeline.ts +767 -0
  117. package/.framework/mcp/tools/cil/project.ts +791 -0
  118. package/.framework/mcp/tools/cil/retrieval.ts +336 -0
  119. package/.framework/mcp/tools/cil/search-core.ts +454 -0
  120. package/.framework/mcp/tools/cil/search.ts +97 -0
  121. package/.framework/mcp/tools/cil/suggest.ts +186 -0
  122. package/.framework/mcp/tools/cil/validate.ts +1369 -0
  123. package/.framework/mcp/tools/kb/delete.ts +139 -0
  124. package/.framework/mcp/tools/kb/index.ts +52 -0
  125. package/.framework/mcp/tools/kb/ingest.ts +84 -0
  126. package/.framework/mcp/tools/kb/list-types.ts +102 -0
  127. package/.framework/mcp/tools/kb/publish.ts +100 -0
  128. package/.framework/mcp/tools/kb/reindex.ts +86 -0
  129. package/.framework/mcp/tools/kb/revoke.ts +85 -0
  130. package/.framework/mcp/tools/kb/search.ts +101 -0
  131. package/.framework/mcp/tools/kb/upsert.ts +125 -0
  132. package/.framework/mcp/tools/observability.ts +510 -0
  133. package/.framework/migrations/001_core_schema.sql +15 -0
  134. package/.framework/migrations/002_core_rls_and_functions.sql +15 -0
  135. package/.framework/migrations/003_core_system_data.sql +16 -1
  136. package/.framework/migrations/004_core_rpc_and_broker.sql +17 -1
  137. package/.framework/migrations/005_core_observability.sql +17 -1
  138. package/.framework/migrations/006_security_hardening_rls.sql +15 -0
  139. package/.framework/migrations/007_kb_article_list.sql +17 -1
  140. package/.framework/migrations/008_items_target.sql +15 -0
  141. package/.framework/migrations/009_roles_slug_unique.sql +15 -0
  142. package/.framework/migrations/010_auth_user_trigger.sql +15 -0
  143. package/.framework/migrations/011_spine_system_account.sql +16 -0
  144. package/.framework/migrations/012_service_role_grants.sql +16 -0
  145. package/.framework/migrations/013_get_account_apps_role_filter.sql +15 -0
  146. package/.framework/migrations/014_apps_required_roles.sql +16 -0
  147. package/.framework/migrations/015_types_kind_slug_unique.sql +20 -0
  148. package/.framework/migrations/016_cil_types.sql +281 -0
  149. package/.framework/migrations/017_cil_stable_ids.sql +37 -0
  150. package/.framework/migrations/018_runtime_tables.sql +129 -0
  151. package/.framework/migrations/019_agent_prompt_columns.sql +56 -0
  152. package/.framework/migrations/020_schema_reconciliation.sql +67 -0
  153. package/.framework/migrations/021_kb_embedding_lifecycle.sql +31 -0
  154. package/.framework/migrations/032_cil_status_migration.sql +73 -0
  155. package/.framework/migrations/033_cil_versioning.sql +73 -0
  156. package/.framework/migrations/034_match_embeddings_knn.sql +115 -0
  157. package/.framework/migrations/035_rate_limits.sql +55 -0
  158. package/.framework/migrations/036_demo_record_flags.sql +72 -0
  159. package/.framework/migrations/037_kb_types_canonical.sql +244 -0
  160. package/.framework/migrations/038_drop_demo_record_flags.sql +38 -0
  161. package/.framework/migrations/042_registration_hierarchy.sql +309 -0
  162. package/.framework/migrations/043_policy_actor_cleanup.sql +39 -0
  163. package/.framework/migrations/044_match_embeddings_filtered_knn.sql +151 -0
  164. package/.framework/migrations/045_security_critical_rls.sql +139 -0
  165. package/.framework/migrations/046_security_missing_rls.sql +79 -0
  166. package/.framework/migrations/047_people_updated_by.sql +27 -0
  167. package/.framework/migrations/048_watcher_last_seen_at.sql +24 -0
  168. package/.framework/migrations/049_security_blocklist.sql +148 -0
  169. package/.framework/migrations/050_notifications.sql +49 -0
  170. package/.framework/migrations/051_message_agent_fields.sql +74 -0
  171. package/.framework/migrations/052_registration_security.sql +421 -0
  172. package/.framework/migrations/053_builtin_action_seeds.sql +66 -0
  173. package/.framework/migrations/054_kb_ingest_lease.sql +157 -0
  174. package/.framework/migrations/055_type_id_drift_reconciliation.sql +33 -0
  175. package/.framework/migrations/056_slug_column_reconciliation.sql +38 -0
  176. package/.framework/migrations/057_pipelines_slug_identity.sql +14 -0
  177. package/.framework/migrations/058_account_data_field_declarations.sql +53 -0
  178. package/.framework/migrations/059_registration_placement_fixes.sql +269 -0
  179. package/.framework/migrations/060_account_person_record_permissions.sql +38 -0
  180. package/.framework/migrations/061_fk_dedup.sql +32 -0
  181. package/.framework/public/spine-logo.svg +10 -3
  182. package/.framework/scripts/app-install-cli.ts +190 -93
  183. package/.framework/scripts/assemble-frontend.sh +127 -44
  184. package/.framework/scripts/assemble-functions.sh +128 -30
  185. package/.framework/scripts/boundary-check.sh +6 -2
  186. package/.framework/scripts/build-manifest.sh +24 -68
  187. package/.framework/scripts/check-core-integrity.sh +15 -76
  188. package/.framework/scripts/checksum-manifest.mts +343 -0
  189. package/.framework/scripts/cil-migrate-markers.ts +403 -0
  190. package/.framework/scripts/fix-cil-markers.mjs +176 -0
  191. package/.framework/scripts/verify-integrity.sh +21 -57
  192. package/.framework/scripts/verify-manifest.mts +305 -0
  193. package/.framework/seeds/types/funnel_signal_use.json +74 -21
  194. package/.framework/seeds/types/spine_instance.json +73 -21
  195. package/.framework/src/App.tsx +118 -72
  196. package/.framework/src/apps/admin/index.tsx +855 -58
  197. package/.framework/src/components/AppWrapper.tsx +43 -45
  198. package/.framework/src/components/CustomAppLoader.tsx +160 -116
  199. package/.framework/src/components/admin/AdminListPage.tsx +46 -44
  200. package/.framework/src/components/admin/AdminSidebar.tsx +57 -47
  201. package/.framework/src/components/admin/AdminStatsCard.tsx +46 -44
  202. package/.framework/src/components/admin/PageInstructions.tsx +98 -2
  203. package/.framework/src/components/admin/SortableTableHeader.tsx +44 -45
  204. package/.framework/src/components/app-shell/GenericAppShell.tsx +64 -65
  205. package/.framework/src/components/app-shell/GenericDetailPage.tsx +44 -47
  206. package/.framework/src/components/app-shell/GenericListPage.tsx +45 -49
  207. package/.framework/src/components/app-sidebar.tsx +42 -45
  208. package/.framework/src/components/auth/ProtectedRoute.tsx +48 -41
  209. package/.framework/src/components/auth/TurnstileWidget.tsx +27 -0
  210. package/.framework/src/components/kb/KBArticleEditor.tsx +231 -22
  211. package/.framework/src/components/kb/KBArticleList.tsx +251 -10
  212. package/.framework/src/components/layout/AppShell.tsx +51 -45
  213. package/.framework/src/components/layout/Header.tsx +42 -43
  214. package/.framework/src/components/layout/Layout.tsx +46 -46
  215. package/.framework/src/components/layout/Sidebar.tsx +196 -96
  216. package/.framework/src/components/runtime/DataDetailHeader.tsx +55 -30
  217. package/.framework/src/components/runtime/DataDetailPage.tsx +31 -269
  218. package/.framework/src/components/runtime/DataFilters.tsx +49 -74
  219. package/.framework/src/components/runtime/DataHeader.tsx +53 -32
  220. package/.framework/src/components/runtime/DataListPage.tsx +51 -155
  221. package/.framework/src/components/runtime/DataStats.tsx +66 -44
  222. package/.framework/src/components/runtime/DataTable.tsx +49 -149
  223. package/.framework/src/components/runtime/SchemaDetailForm.tsx +45 -75
  224. package/.framework/src/components/runtime/index.ts +119 -16
  225. package/.framework/src/components/search-form.tsx +46 -29
  226. package/.framework/src/components/shared/AgentView.tsx +65 -48
  227. package/.framework/src/components/shared/FieldRenderer.tsx +144 -50
  228. package/.framework/src/components/shared/InviteManager.tsx +207 -97
  229. package/.framework/src/components/shared/MemberList.tsx +97 -0
  230. package/.framework/src/components/shared/SchemaFields.tsx +107 -86
  231. package/.framework/src/components/ui/DataTable.tsx +80 -68
  232. package/.framework/src/components/ui/Form.tsx +157 -146
  233. package/.framework/src/components/ui/ItemCard.tsx +74 -67
  234. package/.framework/src/components/ui/ItemListView.tsx +73 -68
  235. package/.framework/src/components/ui/LoadingSpinner.tsx +43 -48
  236. package/.framework/src/components/ui/Modal.tsx +78 -68
  237. package/.framework/src/components/ui/RichTextEditor.tsx +89 -69
  238. package/.framework/src/components/ui/accordion.tsx +85 -86
  239. package/.framework/src/components/ui/alert-dialog.tsx +197 -184
  240. package/.framework/src/components/ui/alert.tsx +105 -94
  241. package/.framework/src/components/ui/aspect-ratio.tsx +57 -43
  242. package/.framework/src/components/ui/avatar.tsx +122 -107
  243. package/.framework/src/components/ui/badge.tsx +60 -55
  244. package/.framework/src/components/ui/breadcrumb.tsx +127 -128
  245. package/.framework/src/components/ui/button-group.tsx +86 -72
  246. package/.framework/src/components/ui/button.tsx +71 -50
  247. package/.framework/src/components/ui/calendar.tsx +72 -57
  248. package/.framework/src/components/ui/card.tsx +136 -129
  249. package/.framework/src/components/ui/carousel.tsx +226 -107
  250. package/.framework/src/components/ui/chart.tsx +252 -147
  251. package/.framework/src/components/ui/checkbox.tsx +43 -44
  252. package/.framework/src/components/ui/collapsible.tsx +86 -71
  253. package/.framework/src/components/ui/combobox.tsx +282 -249
  254. package/.framework/src/components/ui/command.tsx +158 -146
  255. package/.framework/src/components/ui/context-menu.tsx +239 -240
  256. package/.framework/src/components/ui/dialog.tsx +174 -157
  257. package/.framework/src/components/ui/direction.tsx +72 -56
  258. package/.framework/src/components/ui/drawer.tsx +168 -169
  259. package/.framework/src/components/ui/dropdown-menu.tsx +254 -223
  260. package/.framework/src/components/ui/empty.tsx +131 -120
  261. package/.framework/src/components/ui/field.tsx +205 -173
  262. package/.framework/src/components/ui/hover-card.tsx +71 -72
  263. package/.framework/src/components/ui/input-group.tsx +148 -133
  264. package/.framework/src/components/ui/input-otp.tsx +99 -86
  265. package/.framework/src/components/ui/input.tsx +43 -41
  266. package/.framework/src/components/ui/item.tsx +207 -185
  267. package/.framework/src/components/ui/kbd.tsx +57 -56
  268. package/.framework/src/components/ui/label.tsx +45 -41
  269. package/.framework/src/components/ui/menubar.tsx +268 -236
  270. package/.framework/src/components/ui/native-select.tsx +85 -86
  271. package/.framework/src/components/ui/navigation-menu.tsx +166 -156
  272. package/.framework/src/components/ui/pagination.tsx +131 -141
  273. package/.framework/src/components/ui/popover.tsx +125 -128
  274. package/.framework/src/components/ui/progress.tsx +47 -44
  275. package/.framework/src/components/ui/radio-group.tsx +60 -55
  276. package/.framework/src/components/ui/resizable.tsx +85 -72
  277. package/.framework/src/components/ui/scroll-area.tsx +57 -58
  278. package/.framework/src/components/ui/select.tsx +182 -169
  279. package/.framework/src/components/ui/separator.tsx +42 -43
  280. package/.framework/src/components/ui/sheet.tsx +170 -159
  281. package/.framework/src/components/ui/sidebar.tsx +395 -398
  282. package/.framework/src/components/ui/skeleton.tsx +42 -43
  283. package/.framework/src/components/ui/slider.tsx +61 -44
  284. package/.framework/src/components/ui/sonner.tsx +44 -44
  285. package/.framework/src/components/ui/spinner.tsx +47 -42
  286. package/.framework/src/components/ui/switch.tsx +56 -42
  287. package/.framework/src/components/ui/table-primitives.tsx +272 -132
  288. package/.framework/src/components/ui/table.tsx +140 -142
  289. package/.framework/src/components/ui/tabs.tsx +110 -93
  290. package/.framework/src/components/ui/textarea.tsx +43 -44
  291. package/.framework/src/components/ui/toggle-group.tsx +87 -71
  292. package/.framework/src/components/ui/toggle.tsx +56 -56
  293. package/.framework/src/components/ui/tooltip.tsx +99 -85
  294. package/.framework/src/contexts/AppContext.tsx +166 -114
  295. package/.framework/src/contexts/AuthContext.tsx +232 -137
  296. package/.framework/src/hooks/use-mobile.ts +43 -44
  297. package/.framework/src/hooks/useApi.ts +185 -172
  298. package/.framework/src/hooks/useAppPath.ts +31 -29
  299. package/.framework/src/hooks/useApps.ts +77 -42
  300. package/.framework/src/hooks/useEntityList.ts +66 -29
  301. package/.framework/src/hooks/useEntityRecord.ts +76 -32
  302. package/.framework/src/hooks/useForm.ts +62 -30
  303. package/.framework/src/hooks/useListSchema.ts +60 -43
  304. package/.framework/src/hooks/useSchemaRecord.ts +115 -95
  305. package/.framework/src/lib/api.ts +258 -134
  306. package/.framework/src/lib/registration.ts +181 -0
  307. package/.framework/src/lib/supabase.ts +118 -81
  308. package/.framework/src/lib/utils.ts +266 -266
  309. package/.framework/src/main.tsx +43 -44
  310. package/.framework/src/pages/DashboardPage.tsx +44 -43
  311. package/.framework/src/pages/NoAppPage.tsx +50 -0
  312. package/.framework/src/pages/NotFoundPage.tsx +32 -29
  313. package/.framework/src/pages/SetupPage.tsx +34 -33
  314. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +69 -58
  315. package/.framework/src/pages/admin/AIAgentsPage.tsx +43 -40
  316. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +63 -55
  317. package/.framework/src/pages/admin/APIKeysPage.tsx +44 -42
  318. package/.framework/src/pages/admin/AlertsConfigPage.tsx +117 -94
  319. package/.framework/src/pages/admin/AppDetailPage.tsx +48 -42
  320. package/.framework/src/pages/admin/AppsPage.tsx +45 -42
  321. package/.framework/src/pages/admin/DeliveriesPage.tsx +49 -17
  322. package/.framework/src/pages/admin/DesignedPage.tsx +31 -30
  323. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +58 -0
  324. package/.framework/src/pages/admin/EmbeddingsPage.tsx +49 -0
  325. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +31 -29
  326. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +46 -29
  327. package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -29
  328. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +68 -55
  329. package/.framework/src/pages/admin/IntegrationsPage.tsx +45 -42
  330. package/.framework/src/pages/admin/InvitesPage.tsx +60 -44
  331. package/.framework/src/pages/admin/LogsPage.tsx +87 -137
  332. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +31 -29
  333. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +150 -89
  334. package/.framework/src/pages/admin/PipelineDetailPage.tsx +77 -104
  335. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +44 -43
  336. package/.framework/src/pages/admin/PipelinesPage.tsx +59 -145
  337. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +53 -42
  338. package/.framework/src/pages/admin/PromptConfigsPage.tsx +47 -117
  339. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +31 -44
  340. package/.framework/src/pages/admin/RoleDetailPage.tsx +49 -92
  341. package/.framework/src/pages/admin/RolesPage.tsx +47 -164
  342. package/.framework/src/pages/admin/SecurityPage.tsx +310 -0
  343. package/.framework/src/pages/admin/SelectTestPage.tsx +30 -32
  344. package/.framework/src/pages/admin/ShadcnTestPage.tsx +37 -44
  345. package/.framework/src/pages/admin/SimpleDashboard.tsx +32 -44
  346. package/.framework/src/pages/admin/TestRunDetailPage.tsx +97 -44
  347. package/.framework/src/pages/admin/TestingDashboard.tsx +126 -71
  348. package/.framework/src/pages/admin/TimerDetailPage.tsx +67 -55
  349. package/.framework/src/pages/admin/TimersPage.tsx +44 -42
  350. package/.framework/src/pages/admin/TriggerDetailPage.tsx +47 -42
  351. package/.framework/src/pages/admin/TriggersPage.tsx +58 -57
  352. package/.framework/src/pages/admin/TypeDetailPage.tsx +91 -55
  353. package/.framework/src/pages/admin/TypesPage.tsx +45 -42
  354. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +258 -128
  355. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +127 -123
  356. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +308 -235
  357. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +159 -110
  358. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +432 -0
  359. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +200 -178
  360. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +286 -239
  361. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +211 -90
  362. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +156 -143
  363. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +379 -0
  364. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +337 -0
  365. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +219 -214
  366. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
  367. package/.framework/src/pages/auth/AuthConfirmPage.tsx +135 -65
  368. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +39 -31
  369. package/.framework/src/pages/auth/LoginPage.tsx +38 -32
  370. package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -28
  371. package/.framework/src/pages/auth/RegisterPage.tsx +429 -155
  372. package/.framework/src/pages/spine-framework/APIPage.tsx +33 -30
  373. package/.framework/src/pages/spine-framework/CLIPage.tsx +32 -30
  374. package/.framework/src/types/auth.ts +101 -93
  375. package/.framework/src/types/types.ts +283 -262
  376. package/.framework/templates/project.json +87 -0
  377. package/.framework/templates/spine.config.neutral.json +7 -0
  378. package/.framework/tests/api/api-surface.test.ts +381 -0
  379. package/.framework/tests/fixtures/seed.ts +427 -0
  380. package/.framework/tests/fixtures/teardown.ts +228 -0
  381. package/.framework/tests/reporter.ts +351 -0
  382. package/.framework/tests/setup.ts +135 -0
  383. package/.framework/tests/ui/ui-sweep.ts +278 -0
  384. package/.framework/tests/unit/admin-data-logger.test.ts +310 -0
  385. package/.framework/tests/unit/agent-runner.test.ts +2389 -0
  386. package/.framework/tests/unit/ai-interactions.test.ts +81 -0
  387. package/.framework/tests/unit/app-manifest.test.ts +359 -0
  388. package/.framework/tests/unit/assembly-scripts.test.ts +172 -0
  389. package/.framework/tests/unit/cil-determinism.test.ts +85 -0
  390. package/.framework/tests/unit/core-isolation.test.ts +153 -0
  391. package/.framework/tests/unit/funnel-signals.test.ts +135 -0
  392. package/.framework/tests/unit/install-app.test.ts +1759 -0
  393. package/.framework/tests/unit/invites-security.test.ts +572 -0
  394. package/.framework/tests/unit/kb-ingest-lease.test.ts +287 -0
  395. package/.framework/tests/unit/kb-search.test.ts +119 -0
  396. package/.framework/tests/unit/migrate.test.ts +509 -0
  397. package/.framework/tests/unit/notify.test.ts +136 -0
  398. package/.framework/tests/unit/permissions.test.ts +269 -0
  399. package/.framework/tests/unit/pipeline-runner.test.ts +755 -0
  400. package/.framework/tests/unit/principal-cache.test.ts +138 -0
  401. package/.framework/tests/unit/retrieval-golden.test.ts +520 -0
  402. package/.framework/tests/unit/runtime-isolation.test.ts +642 -0
  403. package/.framework/tests/unit/schema-utils.test.ts +225 -0
  404. package/.framework/tests/unit/trigger-engine.test.ts +513 -0
  405. package/.framework/tests/unit/validate-app.test.ts +527 -0
  406. package/README.md +34 -3
  407. package/bin/spine-framework.cjs +1 -0
  408. package/config/tailwind.config.cjs +7 -0
  409. package/config/tsconfig.functions.json +42 -0
  410. package/config/tsconfig.json +37 -9
  411. package/config/vite.config.ts +31 -2
  412. package/netlify.toml +31 -3
  413. package/package.json +46 -29
  414. package/scripts/assemble-frontend.sh +127 -44
  415. package/scripts/assemble-functions.sh +127 -29
  416. package/scripts/boundary-check.sh +6 -2
  417. package/scripts/build-manifest.sh +24 -68
  418. package/scripts/checksum-manifest.mts +345 -0
  419. package/scripts/dev-clean.sh +86 -0
  420. package/scripts/dev-netlify.sh +49 -0
  421. package/scripts/netlify-dev-wrapper.sh +2 -0
  422. package/scripts/verify-install.ts +358 -0
  423. package/scripts/verify-integrity.sh +21 -57
  424. package/scripts/verify-manifest.mts +305 -0
  425. package/templates/project/gitignore +45 -0
  426. package/{config → templates/project}/package-lock.json +22335 -9366
  427. package/vitest.config.ts +46 -0
  428. package/.framework/public/spine.config.json +0 -91
  429. package/config/deno.lock +0 -108
  430. package/config/tsconfig.node.tsbuildinfo +0 -1
  431. package/config/tsconfig.tsbuildinfo +0 -1
  432. package/config/vite.config.d.ts +0 -2
  433. package/custom/.devin/AGENT.md +0 -357
  434. package/custom/.devin/skills/install-app/SKILL.md +0 -39
  435. package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +0 -39
  436. package/custom/.devin/skills/spine-workbench-idea/SKILL.md +0 -36
  437. package/custom/.devin/skills/spine-workbench-implement/SKILL.md +0 -46
  438. package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +0 -28
  439. package/custom/.devin/skills/spine-workbench-plan/SKILL.md +0 -38
  440. package/custom/.devin/workflows/app-install.yaml +0 -83
  441. package/custom/README.md +0 -79
  442. package/docs/README.md +0 -15
  443. package/scripts/app-install-cli.ts +0 -286
  444. package/scripts/check-core-integrity.sh +0 -82
  445. package/scripts/ingest-chunks.cjs +0 -202
  446. package/scripts/kb-chunk-parser.cjs +0 -312
  447. package/scripts/kb-chunk-parser.ts +0 -330
  448. package/scripts/kb-ingest-docs.ts +0 -203
  449. package/scripts/load-test-app-install.ts +0 -484
  450. package/scripts/test-login.js +0 -33
  451. package/spine.config.json +0 -91
@@ -1,24 +1,27 @@
1
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_project_module_header_1784235266" type="module_header" identity="module_header" parent="none"]
2
- // CIL[DOC-MACRO purpose="Module header and top-level exports for cortex.functions.custom_cil-project"]
3
- // CIL[DOC-RESPONSIBILITY responsibility="Own module-level imports, exports, and configuration for cortex.functions.custom_cil-project"]
4
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-project" layer="function" related_files="[\".framework/migrations/015_simplify_apps_table.sql\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/components/ui/table-primitives.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"\\\"]"]
5
- // CIL[DOC-CONTRACT inputs="none" outputs="module exports and side effects" errors="none" side_effects="none"]
6
- // CIL[DOC-MICRO logic_summary="Declares module scope, imports dependencies, and exports public surface of cortex.functions.custom_cil-project" notable_decisions="[]"]
7
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/functions/cil-project.ts"]
2
+ // CIL[DOC-MACRO purpose="Import dependencies and set module context for the cil-project Netlify function"]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Load shared middleware, database, id resolution, admin-data helpers, CIL hashing and semver for the project handler"]
4
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="function" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts"]
5
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
6
+ // CIL[DOC-MICRO logic_summary="Imports createHandler, adminDb, resolveTypeId, admin-data CRUD, computeContentHash and semver to support the exported handler" notable_decisions="[]"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
8
8
  // CIL[DOC-STABILITY stability="stable"]
9
- // CIL[DOC-AUDIENCE audience="developer"]
10
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: .framework/migrations/015_simplify_apps_table.sql, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/components/ui/table-primitives.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, \."]
11
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
12
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
13
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
14
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
15
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
9
+ // CIL[DOC-AUDIENCE audience="maintainer"]
16
10
 
17
11
 
18
12
  import { createHandler } from './_shared/middleware'
19
13
  import { adminDb } from './_shared/db'
20
14
  import { resolveTypeId } from './_shared/resolve-ids'
21
15
  import { create as adminCreate, update as adminUpdate, remove as adminRemove } from './admin-data'
16
+ import { computeContentHash } from './_shared/cil'
17
+ import * as semver from 'semver'
18
+ // CIL[DOC-VECTOR type="context" content="purpose='Import dependencies and set module context for the cil-project Netlify function'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
19
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
20
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
21
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
22
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
23
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
24
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:module_header:module_header"]
22
25
 
23
26
 
24
27
 
@@ -26,62 +29,55 @@ import { create as adminCreate, update as adminUpdate, remove as adminRemove } f
26
29
 
27
30
 
28
31
 
29
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_project_module_header_1784235266"]
30
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_project_default_globs_1784235266" type="variable" identity="default_globs" parent="none"]
31
- // CIL[DOC-MACRO purpose="Defines default_globs configuration or state in cortex.functions.custom_cil-project"]
32
- // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for default_globs"]
33
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-project" layer="function" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\"\\\"]"]
34
- // CIL[DOC-CONTRACT inputs="none" outputs="value of default_globs" errors="none" side_effects="none"]
35
- // CIL[DOC-MICRO logic_summary="Declares default_globs with initial value or constant binding used by cortex.functions.custom_cil-project" notable_decisions="[]"]
36
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
37
- // CIL[DOC-STABILITY stability="stable"]
38
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/src/pages/admin/IntegrationsPage.tsx, custom/apps/portal/pages/ContentPage.tsx, \."]
39
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
40
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
41
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
42
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
43
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
32
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:DEFAULT_GLOBS:constant" type="constant" identity="DEFAULT_GLOBS" parent="~/.framework/functions/cil-project.ts"]
33
+ // CIL[DOC-MACRO purpose="Define default source glob patterns for CIL project discovery"]
34
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide the default list of file extensions to include during CIL discovery"]
35
+ // CIL[DOC-STABILITY stability="internal"]
36
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
37
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="constant" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts,.framework/functions/cil-project.ts"]
38
+ // CIL[DOC-CONTRACT inputs="none" outputs="string[] of glob patterns" errors="none" side_effects="none"]
39
+ // CIL[DOC-MICRO logic_summary="Declares a constant array of glob strings for TypeScript and TSX source discovery" notable_decisions="[]"]
44
40
  const DEFAULT_GLOBS = ['**/*.ts', '**/*.tsx', '**/*.sql']
41
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:DEFAULT_GLOBS:constant"]
45
42
 
43
+ // CIL[DOC-VECTOR type="context" content="purpose='Define default source glob patterns for CIL project discovery'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
44
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
45
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
46
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
47
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
48
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
46
49
 
47
50
 
48
51
 
49
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_project_default_globs_1784235266"]
50
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_project_default_exclude_globs_1784235266" type="variable" identity="default_exclude_globs" parent="none"]
51
- // CIL[DOC-MACRO purpose="Defines default_exclude_globs configuration or state in cortex.functions.custom_cil-project"]
52
- // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for default_exclude_globs"]
53
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-project" layer="function" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\"\\\"]"]
54
- // CIL[DOC-CONTRACT inputs="none" outputs="value of default_exclude_globs" errors="none" side_effects="none"]
55
- // CIL[DOC-MICRO logic_summary="Declares default_exclude_globs with initial value or constant binding used by cortex.functions.custom_cil-project" notable_decisions="[]"]
56
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
52
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:DEFAULT_EXCLUDE_GLOBS:constant" type="constant" identity="DEFAULT_EXCLUDE_GLOBS" parent="~/.framework/functions/cil-project.ts"]
53
+ // CIL[DOC-MACRO purpose="Define default exclusion globs for CIL project discovery"]
54
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide default ignored paths during CIL discovery"]
55
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="constant" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts,.framework/functions/cil-project.ts"]
56
+ // CIL[DOC-CONTRACT inputs="none" outputs="string[] of exclusion globs" errors="none" side_effects="none"]
57
+ // CIL[DOC-MICRO logic_summary="Declares a constant array of exclusion globs covering dependencies, build output and generated files" notable_decisions="[]"]
58
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
57
59
  // CIL[DOC-STABILITY stability="stable"]
58
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/src/pages/admin/IntegrationsPage.tsx, custom/apps/portal/pages/ContentPage.tsx, \."]
59
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
60
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
61
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
60
+ const DEFAULT_EXCLUDE_GLOBS = ['node_modules/**', '.git/**', '.assembled/**', 'dist/**', 'build/**', '.netlify/**', '**/*.min.js', '**/*.d.ts']
61
+ // CIL[DOC-VECTOR type="context" content="purpose='Define default exclusion globs for CIL project discovery'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
62
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
63
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
64
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
62
65
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
63
66
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
64
- const DEFAULT_EXCLUDE_GLOBS = ['node_modules/**', '.git/**', 'dist/**', 'build/**', '.netlify/**', '**/*.min.js', '**/*.d.ts']
67
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:DEFAULT_EXCLUDE_GLOBS:constant"]
65
68
 
66
69
 
67
70
 
68
71
 
69
72
 
70
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_project_default_exclude_globs_1784235266"]
71
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_project_sourceset_1784235266" type="interface" identity="sourceset" parent="none"]
72
- // CIL[DOC-MACRO purpose="Defines the sourceset type contract in cortex.functions.custom_cil-project"]
73
- // CIL[DOC-RESPONSIBILITY responsibility="Describe the shape and allowed fields for sourceset"]
74
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-project" layer="function" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/migrations/015_simplify_apps_table.sql\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
75
- // CIL[DOC-CONTRACT inputs="none" outputs="type definition for sourceset" errors="none" side_effects="none"]
76
- // CIL[DOC-MICRO logic_summary="Declares TypeScript type/interface sourceset with member definitions" notable_decisions="[]"]
77
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
73
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:SourceSet:interface" type="interface" identity="SourceSet" parent="~/.framework/functions/cil-project.ts"]
74
+ // CIL[DOC-MACRO purpose="Define the typed shape of a CIL project source set"]
75
+ // CIL[DOC-RESPONSIBILITY responsibility="Describe the fields of a SourceSet configuration"]
76
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="interface" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts,.framework/functions/cil-project.ts"]
77
+ // CIL[DOC-CONTRACT inputs="none" outputs="SourceSet TypeScript interface" errors="none" side_effects="none"]
78
+ // CIL[DOC-MICRO logic_summary="Declares an interface with id, name, base_path, globs, exclude_globs and optional layer" notable_decisions="[]"]
79
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
78
80
  // CIL[DOC-STABILITY stability="stable"]
79
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/migrations/015_simplify_apps_table.sql, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
80
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
81
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
82
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
83
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
84
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
85
81
  interface SourceSet {
86
82
  id: string
87
83
  name: string
@@ -90,56 +86,57 @@ interface SourceSet {
90
86
  exclude_globs?: string[]
91
87
  layer?: string
92
88
  }
89
+ // CIL[DOC-VECTOR type="context" content="purpose='Define the typed shape of a CIL project source set'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
90
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
91
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
92
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
93
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
94
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
95
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:SourceSet:interface"]
93
96
 
94
97
 
95
98
 
96
99
 
97
100
 
98
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_project_sourceset_1784235266"]
99
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_project_createprojectrequest_1784235266" type="interface" identity="createprojectrequest" parent="none"]
100
- // CIL[DOC-MACRO purpose="Defines the createprojectrequest type contract in cortex.functions.custom_cil-project"]
101
- // CIL[DOC-RESPONSIBILITY responsibility="Describe the shape and allowed fields for createprojectrequest"]
102
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-project" layer="function" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/migrations/015_simplify_apps_table.sql\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
103
- // CIL[DOC-CONTRACT inputs="none" outputs="type definition for createprojectrequest" errors="none" side_effects="none"]
104
- // CIL[DOC-MICRO logic_summary="Declares TypeScript type/interface createprojectrequest with member definitions" notable_decisions="[]"]
105
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
101
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:CreateProjectRequest:interface" type="interface" identity="CreateProjectRequest" parent="~/.framework/functions/cil-project.ts"]
102
+ // CIL[DOC-MACRO purpose="Define the typed request shape for creating a CIL project"]
103
+ // CIL[DOC-RESPONSIBILITY responsibility="Declare the input fields accepted by the project create action"]
104
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="interface" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts,.framework/functions/cil-project.ts"]
105
+ // CIL[DOC-CONTRACT inputs="none" outputs="CreateProjectRequest TypeScript interface" errors="none" side_effects="none"]
106
+ // CIL[DOC-MICRO logic_summary="Declares an interface with name, description, repo_path, language_mix, kind, globs, exclude_globs, source_sets and dependencies" notable_decisions="[]"]
107
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
106
108
  // CIL[DOC-STABILITY stability="stable"]
107
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/migrations/015_simplify_apps_table.sql, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
108
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
109
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
110
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
111
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
112
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
113
109
  interface CreateProjectRequest {
114
110
  name: string
115
111
  description?: string
116
112
  repo_path: string
117
113
  language_mix?: string
114
+ kind?: 'core' | 'custom'
118
115
  globs?: string[]
119
116
  exclude_globs?: string[]
120
117
  source_sets?: SourceSet[]
121
118
  dependencies?: string[]
122
119
  }
120
+ // CIL[DOC-VECTOR type="context" content="purpose='Define the typed request shape for creating a CIL project'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
121
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
122
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
123
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
124
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
125
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
126
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:CreateProjectRequest:interface"]
123
127
 
124
128
 
125
129
 
126
130
 
127
131
 
128
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_project_createprojectrequest_1784235266"]
129
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_project_projectstats_1784235266" type="interface" identity="projectstats" parent="none"]
130
- // CIL[DOC-MACRO purpose="Defines the projectstats type contract in cortex.functions.custom_cil-project"]
131
- // CIL[DOC-RESPONSIBILITY responsibility="Describe the shape and allowed fields for projectstats"]
132
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-project" layer="function" related_files="[]"]
133
- // CIL[DOC-CONTRACT inputs="none" outputs="type definition for projectstats" errors="none" side_effects="none"]
134
- // CIL[DOC-MICRO logic_summary="Declares TypeScript type/interface projectstats with member definitions" notable_decisions="[]"]
135
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
132
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:ProjectStats:interface" type="interface" identity="ProjectStats" parent="~/.framework/functions/cil-project.ts"]
133
+ // CIL[DOC-MACRO purpose="Define the typed shape for CIL project statistics"]
134
+ // CIL[DOC-RESPONSIBILITY responsibility="Declare the aggregate counters returned by getProjectStats"]
135
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="interface" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts,.framework/functions/cil-project.ts"]
136
+ // CIL[DOC-CONTRACT inputs="none" outputs="ProjectStats TypeScript interface" errors="none" side_effects="none"]
137
+ // CIL[DOC-MICRO logic_summary="Declares an interface with file, chunk, proposal, approved, pending review, dead code and doc confidence counters" notable_decisions="[]"]
138
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
136
139
  // CIL[DOC-STABILITY stability="stable"]
137
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
138
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
139
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
140
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
141
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
142
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
143
140
  interface ProjectStats {
144
141
  file_count: number
145
142
  chunk_count: number
@@ -150,6 +147,13 @@ interface ProjectStats {
150
147
  doc_verified_count: number
151
148
  doc_ai_count: number
152
149
  }
150
+ // CIL[DOC-VECTOR type="context" content="purpose='Define the typed shape for CIL project statistics'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
151
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
152
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
153
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
154
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
155
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
156
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:ProjectStats:interface"]
153
157
 
154
158
 
155
159
 
@@ -157,21 +161,14 @@ interface ProjectStats {
157
161
 
158
162
 
159
163
 
160
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_project_projectstats_1784235266"]
161
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_project_getprojectstats_1784235266" type="function" identity="getprojectstats" parent="none"]
162
- // CIL[DOC-MACRO purpose="Implements getprojectstats logic in cortex.functions.custom_cil-project"]
163
- // CIL[DOC-RESPONSIBILITY responsibility="Execute getprojectstats and return its computed result"]
164
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-project" layer="function" related_files="[]"]
165
- // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
166
- // CIL[DOC-MICRO logic_summary="Provides getprojectstats with getProjectStats(projectId: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
167
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
164
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:getProjectStats:function" type="function" identity="getProjectStats" parent="~/.framework/functions/cil-project.ts"]
165
+ // CIL[DOC-MACRO purpose="Compute aggregate CIL project statistics from the database"]
166
+ // CIL[DOC-RESPONSIBILITY responsibility="Query files, chunks and proposals for a project and return summary counts"]
167
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="function" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts,.framework/functions/cil-project.ts"]
168
+ // CIL[DOC-CONTRACT inputs="projectId: string" outputs="ProjectStats object" errors="throws on database error" side_effects="none"]
169
+ // CIL[DOC-MICRO logic_summary="Runs three parallel adminDb queries, filters results by review_status, is_dead_code and doc_confidence to populate counters" notable_decisions="[]"]
170
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
168
171
  // CIL[DOC-STABILITY stability="stable"]
169
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
170
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
171
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
172
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
173
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
174
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
175
172
  async function getProjectStats(projectId: string): Promise<ProjectStats> {
176
173
  const [filesResult, chunksResult, proposalsResult] = await Promise.all([
177
174
  adminDb.from('items').select('id, data', { count: 'exact' })
@@ -202,27 +199,27 @@ async function getProjectStats(projectId: string): Promise<ProjectStats> {
202
199
  doc_ai_count: chunks.filter(c => c.data?.doc_confidence === 'ai_generated').length,
203
200
  }
204
201
  }
202
+ // CIL[DOC-VECTOR type="context" content="purpose='Compute aggregate CIL project statistics from the database'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
203
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
204
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
205
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
206
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
207
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
208
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:getProjectStats:function"]
205
209
 
206
210
 
207
211
 
208
212
 
209
213
 
210
214
 
211
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_project_getprojectstats_1784235266"]
212
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_project_bulkadminremove_1784235266" type="function" identity="bulkadminremove" parent="none"]
213
- // CIL[DOC-MACRO purpose="Implements bulkadminremove logic in cortex.functions.custom_cil-project"]
214
- // CIL[DOC-RESPONSIBILITY responsibility="Execute bulkadminremove and return its computed result"]
215
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-project" layer="function" related_files="[]"]
216
- // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
217
- // CIL[DOC-MICRO logic_summary="Provides bulkadminremove with bulkAdminRemove(ctx: any, entity: string, ids: string[] inputs, handling internal flow and returning a result" notable_decisions="[]"]
218
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
215
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:bulkAdminRemove:function" type="function" identity="bulkAdminRemove" parent="~/.framework/functions/cil-project.ts"]
216
+ // CIL[DOC-MACRO purpose="Bulk delete admin-data records while tolerating individual failures"]
217
+ // CIL[DOC-RESPONSIBILITY responsibility="Remove many records of a given entity and return the count of successful deletions"]
218
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="function" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts,.framework/functions/cil-project.ts"]
219
+ // CIL[DOC-CONTRACT inputs="ctx: any, entity: string, ids: string[]" outputs="number of successful deletions" errors="logs per-item failures and returns count" side_effects="calls adminRemove for each id"]
220
+ // CIL[DOC-MICRO logic_summary="Maps ids through adminRemove with soft false, catches errors per id, and counts non-null results" notable_decisions="[]"]
221
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
219
222
  // CIL[DOC-STABILITY stability="stable"]
220
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
221
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
222
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
223
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
224
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
225
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
226
223
  async function bulkAdminRemove(ctx: any, entity: string, ids: string[]): Promise<number> {
227
224
  const results = await Promise.all(ids.map(id =>
228
225
  adminRemove({ ...ctx, query: { ...(ctx.query || {}), entity, id, soft: 'false' } } as any).catch((e: any) => {
@@ -232,26 +229,233 @@ async function bulkAdminRemove(ctx: any, entity: string, ids: string[]): Promise
232
229
  ))
233
230
  return results.filter(r => r !== null).length
234
231
  }
232
+ // CIL[DOC-VECTOR type="context" content="purpose='Bulk delete admin-data records while tolerating individual failures'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
233
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
234
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
235
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
236
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
237
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
238
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:bulkAdminRemove:function"]
239
+
235
240
 
236
241
 
237
242
 
238
243
 
239
244
 
240
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_project_bulkadminremove_1784235266"]
241
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_project_handler_1784235266" type="variable" identity="handler" parent="none"]
242
- // CIL[DOC-MACRO purpose="Defines handler configuration or state in cortex.functions.custom_cil-project"]
243
- // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for handler"]
244
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-project" layer="function" related_files="[]"]
245
- // CIL[DOC-CONTRACT inputs="none" outputs="value of handler" errors="none" side_effects="none"]
246
- // CIL[DOC-MICRO logic_summary="Declares handler with initial value or constant binding used by cortex.functions.custom_cil-project" notable_decisions="[]"]
247
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
245
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:buildVersionManifest:function" type="function" identity="buildVersionManifest" parent="~/.framework/functions/cil-project.ts"]
246
+ // CIL[DOC-MACRO purpose="Build a version manifest from CIL project files, chunks, embeddings and links"]
247
+ // CIL[DOC-RESPONSIBILITY responsibility="Collect all versioned CIL items for a project into a manifest object"]
248
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="function" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts,.framework/functions/cil-project.ts"]
249
+ // CIL[DOC-CONTRACT inputs="projectId: string" outputs="Record with files, chunks, embeddings, links and metadata" errors="throws if manifest or embedding queries fail" side_effects="reads from items, embeddings and links tables"]
250
+ // CIL[DOC-MICRO logic_summary="Loads files and chunks, joins embeddings by chunk id, and batches link queries both directions to build a stable-id keyed manifest" notable_decisions="[]"]
251
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
248
252
  // CIL[DOC-STABILITY stability="stable"]
249
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
250
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
251
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
252
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
253
+ async function buildVersionManifest(projectId: string): Promise<Record<string, any>> {
254
+ const IN_LIMIT = 500
255
+
256
+ const { data: fileItems, error: fErr } = await adminDb
257
+ .from('items')
258
+ .select('id, data')
259
+ .filter('data->>kb_type', 'eq', 'cil_file')
260
+ .filter('data->>project_id', 'eq', projectId)
261
+ .eq('is_active', true)
262
+
263
+ const { data: chunkItems, error: cErr } = await adminDb
264
+ .from('items')
265
+ .select('id, data')
266
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
267
+ .filter('data->>project_id', 'eq', projectId)
268
+ .eq('is_active', true)
269
+
270
+ if (fErr) throw new Error(`Failed to load files for manifest: ${fErr.message}`)
271
+ if (cErr) throw new Error(`Failed to load chunks for manifest: ${cErr.message}`)
272
+
273
+ const files: Record<string, any> = {}
274
+ const chunks: Record<string, any> = {}
275
+ const itemIdToStable: Record<string, { stable_id: string; type: string }> = {}
276
+
277
+ for (const f of fileItems || []) {
278
+ const stable = f.data?.stable_id || f.data?.file_path || f.id
279
+ files[stable] = {
280
+ file_id: f.id,
281
+ stable_id: stable,
282
+ stored_hash: f.data?.stored_hash || f.data?.file_hash || '',
283
+ spine_version_id: f.data?.spine_version_id || '',
284
+ customer_version_id: f.data?.customer_version_id || '',
285
+ customized: f.data?.customized || false,
286
+ }
287
+ itemIdToStable[f.id] = { stable_id: stable, type: 'file' }
288
+ }
289
+
290
+ const chunkIds: string[] = []
291
+ for (const c of chunkItems || []) {
292
+ const stable = c.data?.stable_id || c.id
293
+ chunks[stable] = {
294
+ chunk_id: c.id,
295
+ file_id: c.data?.file_id || '',
296
+ file_path: c.data?.file_path || '',
297
+ stable_id: stable,
298
+ stored_hash: c.data?.stored_hash || c.data?.content_hash || '',
299
+ spine_version_id: c.data?.spine_version_id || '',
300
+ customer_version_id: c.data?.customer_version_id || '',
301
+ customized: c.data?.customized || false,
302
+ }
303
+ itemIdToStable[c.id] = { stable_id: stable, type: 'chunk' }
304
+ chunkIds.push(c.id)
305
+ }
306
+
307
+ const embeddings: Record<string, any> = {}
308
+ if (chunkIds.length > 0) {
309
+ const { data: embeddingRows, error: eErr } = await adminDb
310
+ .from('embeddings')
311
+ .select('id, source_item_id, data')
312
+ .in('source_item_id', chunkIds)
313
+ .eq('is_active', true)
314
+ if (eErr) throw new Error(`Failed to load embeddings for manifest: ${eErr.message}`)
315
+ for (const e of embeddingRows || []) {
316
+ const type = e.data?.type || 'semantic'
317
+ const contentHash = e.data?.input_hash || e.data?.content_hash || ''
318
+ const chunkStable = itemIdToStable[e.source_item_id]?.stable_id
319
+ if (!chunkStable) continue
320
+ if (!embeddings[chunkStable]) embeddings[chunkStable] = {}
321
+ embeddings[chunkStable][type] = {
322
+ embedding_id: e.id,
323
+ content_hash: contentHash,
324
+ }
325
+ }
326
+ }
327
+
328
+ const links: any[] = []
329
+ const seenLinks = new Set<string>()
330
+ const allIds = Object.keys(itemIdToStable)
331
+ for (let i = 0; i < allIds.length; i += IN_LIMIT) {
332
+ const batch = allIds.slice(i, i + IN_LIMIT)
333
+ const [{ data: sourceLinks }, { data: targetLinks }] = await Promise.all([
334
+ adminDb.from('links').select('id, source_id, target_id, link_type_id, data').in('source_id', batch),
335
+ adminDb.from('links').select('id, source_id, target_id, link_type_id, data').in('target_id', batch),
336
+ ])
337
+ for (const l of [...(sourceLinks || []), ...(targetLinks || [])]) {
338
+ if (seenLinks.has(l.id)) continue
339
+ seenLinks.add(l.id)
340
+ const sourceStable = itemIdToStable[l.source_id]?.stable_id || l.source_id
341
+ const targetStable = itemIdToStable[l.target_id]?.stable_id || l.target_id
342
+ links.push({
343
+ link_id: l.id,
344
+ source_id: l.source_id,
345
+ target_id: l.target_id,
346
+ source_stable_id: sourceStable,
347
+ target_stable_id: targetStable,
348
+ link_type_id: l.link_type_id,
349
+ metadata_hash: computeContentHash(JSON.stringify(l.data || {})),
350
+ })
351
+ }
352
+ }
353
+
354
+ return {
355
+ files,
356
+ chunks,
357
+ embeddings,
358
+ links,
359
+ project_id: projectId,
360
+ generated_at: new Date().toISOString(),
361
+ }
362
+ }
363
+ // CIL[DOC-VECTOR type="context" content="purpose='Build a version manifest from CIL project files, chunks, embeddings and links'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
364
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
365
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
366
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
253
367
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
254
368
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
369
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:buildVersionManifest:function"]
370
+
371
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:buildVersionDiff:function" type="function" identity="buildVersionDiff" parent="~/.framework/functions/cil-project.ts"]
372
+ // CIL[DOC-MACRO purpose="Compute a diff between two CIL version manifests"]
373
+ // CIL[DOC-RESPONSIBILITY responsibility="Compare from and to manifests to produce added, removed and modified lists"]
374
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="function" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts,.framework/functions/cil-project.ts"]
375
+ // CIL[DOC-CONTRACT inputs="fromManifest: Record<string, any>, toManifest: Record<string, any>" outputs="Record with added/removed/modified files, chunks, embeddings and links" errors="none" side_effects="none"]
376
+ // CIL[DOC-MICRO logic_summary="Iterates combined keys for files, chunks, embeddings and links, comparing stored_hash or metadata_hash to classify changes" notable_decisions="[]"]
377
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
378
+ // CIL[DOC-STABILITY stability="stable"]
379
+ function buildVersionDiff(fromManifest: Record<string, any> = {}, toManifest: Record<string, any> = {}): Record<string, any> {
380
+ const diff: Record<string, any> = {
381
+ added_files: [],
382
+ removed_files: [],
383
+ modified_files: [],
384
+ added_chunks: [],
385
+ removed_chunks: [],
386
+ modified_chunks: [],
387
+ added_embeddings: [],
388
+ removed_embeddings: [],
389
+ modified_embeddings: [],
390
+ added_links: [],
391
+ removed_links: [],
392
+ modified_links: [],
393
+ }
394
+
395
+ const fromFiles = fromManifest.files || {}
396
+ const toFiles = toManifest.files || {}
397
+ const fromChunks = fromManifest.chunks || {}
398
+ const toChunks = toManifest.chunks || {}
399
+
400
+ const allFileStables = new Set([...Object.keys(fromFiles), ...Object.keys(toFiles)])
401
+ for (const stable of allFileStables) {
402
+ if (!fromFiles[stable]) diff.added_files.push({ stable_id: stable, ...toFiles[stable] })
403
+ else if (!toFiles[stable]) diff.removed_files.push({ stable_id: stable, ...fromFiles[stable] })
404
+ else if (fromFiles[stable].stored_hash !== toFiles[stable].stored_hash) diff.modified_files.push({ stable_id: stable, from: fromFiles[stable], to: toFiles[stable] })
405
+ }
406
+
407
+ const allChunkStables = new Set([...Object.keys(fromChunks), ...Object.keys(toChunks)])
408
+ for (const stable of allChunkStables) {
409
+ if (!fromChunks[stable]) diff.added_chunks.push({ stable_id: stable, ...toChunks[stable] })
410
+ else if (!toChunks[stable]) diff.removed_chunks.push({ stable_id: stable, ...fromChunks[stable] })
411
+ else if (fromChunks[stable].stored_hash !== toChunks[stable].stored_hash) diff.modified_chunks.push({ stable_id: stable, from: fromChunks[stable], to: toChunks[stable] })
412
+ }
413
+
414
+ const fromEmbeddings = fromManifest.embeddings || {}
415
+ const toEmbeddings = toManifest.embeddings || {}
416
+ const allChunkEmbeds = new Set([...Object.keys(fromEmbeddings), ...Object.keys(toEmbeddings)])
417
+ for (const chunkStable of allChunkEmbeds) {
418
+ const fromTypes = fromEmbeddings[chunkStable] || {}
419
+ const toTypes = toEmbeddings[chunkStable] || {}
420
+ const allTypes = new Set([...Object.keys(fromTypes), ...Object.keys(toTypes)])
421
+ for (const type of allTypes) {
422
+ const fromE = fromTypes[type]
423
+ const toE = toTypes[type]
424
+ if (!fromE) diff.added_embeddings.push({ chunk_stable_id: chunkStable, vector_type: type, ...toE })
425
+ else if (!toE) diff.removed_embeddings.push({ chunk_stable_id: chunkStable, vector_type: type, ...fromE })
426
+ else if (fromE.content_hash !== toE.content_hash) diff.modified_embeddings.push({ chunk_stable_id: chunkStable, vector_type: type, from: fromE, to: toE })
427
+ }
428
+ }
429
+
430
+ const linkKey = (l: any) => `${l.source_stable_id}:${l.target_stable_id}:${l.link_type_id}`
431
+ const fromLinks = (fromManifest.links || []).reduce((acc: Record<string, any>, l: any) => { acc[linkKey(l)] = l; return acc }, {})
432
+ const toLinks = (toManifest.links || []).reduce((acc: Record<string, any>, l: any) => { acc[linkKey(l)] = l; return acc }, {})
433
+ const allLinkKeys = new Set([...Object.keys(fromLinks), ...Object.keys(toLinks)])
434
+ for (const key of allLinkKeys) {
435
+ const fromL = fromLinks[key]
436
+ const toL = toLinks[key]
437
+ if (!fromL) diff.added_links.push(toL)
438
+ else if (!toL) diff.removed_links.push(fromL)
439
+ else if (fromL.metadata_hash !== toL.metadata_hash) diff.modified_links.push({ from: fromL, to: toL })
440
+ }
441
+
442
+ return diff
443
+ }
444
+ // CIL[DOC-VECTOR type="context" content="purpose='Compute a diff between two CIL version manifests'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
445
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
446
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
447
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
448
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
449
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
450
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:buildVersionDiff:function"]
451
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-project.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/cil-project.ts"]
452
+ // CIL[DOC-MACRO purpose="Netlify function handler for CIL project CRUD and version lifecycle actions"]
453
+ // CIL[DOC-RESPONSIBILITY responsibility="Dispatch actions: list, get, create, update, delete, pipeline progress, create_version, set_active_version, publish_version, mark_versions_inactive, archive_versions"]
454
+ // CIL[DOC-CONTEXT module=".framework/functions/cil-project" layer="function" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/admin-data.ts,.framework/functions/cil-project.ts"]
455
+ // CIL[DOC-CONTRACT inputs="ctx: RequestContext, body: any" outputs="action-specific response object" errors="throws Error with action-specific message for missing/invalid inputs or DB failures" side_effects="reads and writes items, embeddings and links via adminDb and admin-data"]
456
+ // CIL[DOC-MICRO logic_summary="createHandler wrapper that branches on action and method to list, fetch, create, update, delete, version and publish CIL projects" notable_decisions="[]"]
457
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
458
+ // CIL[DOC-STABILITY stability="stable"]
255
459
  export const handler = createHandler(async (ctx, body) => {
256
460
  const action = ctx.query?.action
257
461
  const method = (ctx as any).method || (body ? 'POST' : 'GET')
@@ -311,20 +515,22 @@ export const handler = createHandler(async (ctx, body) => {
311
515
 
312
516
 
313
517
  if (action === 'create' || (!action && method === 'POST')) {
314
- const req = body as CreateProjectRequest
315
- if (!req?.name) throw new Error('name is required')
518
+ const req = body as any
519
+ const name = req?.name || req?.title
520
+ if (!name) throw new Error('name is required')
316
521
  if (!req?.repo_path) throw new Error('repo_path is required')
317
522
 
318
523
  const result = await adminCreate(ctx, {
319
524
  entity: 'items',
320
525
  type_slug: 'cil_project',
321
- title: req.name,
526
+ title: name,
322
527
  description: req.description || '',
323
528
  status: 'active',
324
529
  data: {
325
530
  kb_type: 'cil_project',
326
531
  repo_path: req.repo_path,
327
532
  language_mix: req.language_mix || '',
533
+ kind: req.kind || 'custom',
328
534
  ingestion_status: 'not_started',
329
535
  file_count: 0,
330
536
  chunk_count: 0,
@@ -337,7 +543,30 @@ export const handler = createHandler(async (ctx, body) => {
337
543
  }
338
544
  })
339
545
 
340
- return { project: result }
546
+ const defaultVersion = await adminCreate(ctx, {
547
+ entity: 'items',
548
+ type_slug: 'cil_version',
549
+ title: `${name} v0.0.0`,
550
+ status: 'active',
551
+ data: {
552
+ project_id: result.id,
553
+ version: 'v0.0.0',
554
+ base_version: '',
555
+ is_iteration: false,
556
+ status: 'active',
557
+ },
558
+ })
559
+
560
+ const updateCtx = { ...ctx, query: { ...ctx.query, entity: 'items', id: result.id } }
561
+ await adminUpdate(updateCtx, {
562
+ data: {
563
+ ...result.data,
564
+ active_version_id: defaultVersion.id,
565
+ default_version_id: defaultVersion.id,
566
+ },
567
+ })
568
+
569
+ return { project: { ...result, data: { ...result.data, active_version_id: defaultVersion.id, default_version_id: defaultVersion.id } } }
341
570
  }
342
571
 
343
572
 
@@ -357,6 +586,7 @@ export const handler = createHandler(async (ctx, body) => {
357
586
  data: mergedData,
358
587
  ...(body?.status ? { status: body.status } : {}),
359
588
  ...(body?.title ? { title: body.title } : {}),
589
+ ...(body?.description ? { description: body.description } : {}),
360
590
  })
361
591
 
362
592
  return { project: result }
@@ -430,7 +660,7 @@ export const handler = createHandler(async (ctx, body) => {
430
660
  }
431
661
 
432
662
 
433
- for (const kbType of ['cil_chunk', 'cil_chunk_proposal', 'cil_file', 'cil_config']) {
663
+ for (const kbType of ['cil_chunk', 'cil_chunk_proposal', 'cil_file', 'cil_config', 'cil_version', 'cil_suggestion', 'cil_learning_proposal']) {
434
664
  const { data: itemsToDelete } = await adminDb
435
665
  .from('items')
436
666
  .select('id')
@@ -471,6 +701,7 @@ export const handler = createHandler(async (ctx, body) => {
471
701
  const by_status: Record<string, number> = {}
472
702
  for (const [key, val] of Object.entries(fileStatuses)) {
473
703
  if (key.endsWith('_updated')) continue
704
+ if (typeof val !== 'string') continue
474
705
  by_status[val] = (by_status[val] || 0) + 1
475
706
  }
476
707
 
@@ -491,9 +722,305 @@ export const handler = createHandler(async (ctx, body) => {
491
722
  }
492
723
  }
493
724
 
494
- throw new Error(`Unknown action: ${action}. Valid: list, get, create, update, delete, pipeline_progress`)
495
- })
725
+
726
+ if (action === 'create_version') {
727
+ const projectId = body?.project_id
728
+ const version = body?.version
729
+ if (!projectId) throw new Error('project_id is required')
730
+ if (!version) throw new Error('version is required')
731
+ if (!semver.valid(version)) throw new Error(`Invalid semver version: ${version}`)
732
+
733
+ const versionTypeId = await resolveTypeId('item', 'cil_version')
734
+ const { count, error: countErr } = await adminDb
735
+ .from('items')
736
+ .select('*', { count: 'exact', head: true })
737
+ .eq('type_id', versionTypeId)
738
+ .filter('data->>project_id', 'eq', projectId)
739
+ if (countErr) throw new Error(`Failed to check existing versions: ${countErr.message}`)
740
+
741
+ const isFirst = (count || 0) === 0
742
+ const isIteration = semver.prerelease(version) !== null
743
+ const status = isFirst ? 'active' : 'inactive'
744
+
745
+ const versionRecord = await adminCreate(ctx, {
746
+ entity: 'items',
747
+ type_slug: 'cil_version',
748
+ title: version,
749
+ status,
750
+ data: {
751
+ project_id: projectId,
752
+ version,
753
+ base_version: body?.base_version || '',
754
+ is_iteration: isIteration,
755
+ status,
756
+ },
757
+ })
758
+
759
+ if (isFirst) {
760
+ const projectTypeId = await resolveTypeId('item', 'cil_project')
761
+ const { data: projects, error: pErr } = await adminDb
762
+ .from('items')
763
+ .select('id, data')
764
+ .eq('type_id', projectTypeId)
765
+ .eq('id', projectId)
766
+ .limit(1)
767
+ if (pErr || !projects || projects.length === 0) throw new Error(`Project not found: ${projectId}`)
768
+ const project = projects[0]
769
+ const updateCtx = { ...ctx, query: { ...ctx.query, entity: 'items', id: projectId } }
770
+ await adminUpdate(updateCtx, {
771
+ data: {
772
+ ...project.data,
773
+ active_version_id: versionRecord.id,
774
+ default_version_id: versionRecord.id,
775
+ },
776
+ })
777
+ }
778
+
779
+ return { version: versionRecord }
780
+ }
781
+
782
+
783
+ if (action === 'set_active_version') {
784
+ const projectId = body?.project_id || ctx.query?.id
785
+ const versionId = body?.version_id
786
+ if (!projectId) throw new Error('project_id is required')
787
+ if (!versionId) throw new Error('version_id is required')
788
+
789
+ const projectTypeId = await resolveTypeId('item', 'cil_project')
790
+ const versionTypeId = await resolveTypeId('item', 'cil_version')
791
+
792
+ const { data: projectRows, error: pErr } = await adminDb
793
+ .from('items')
794
+ .select('id, data')
795
+ .eq('type_id', projectTypeId)
796
+ .eq('id', projectId)
797
+ .limit(1)
798
+ if (pErr || !projectRows || projectRows.length === 0) throw new Error(`Project not found: ${projectId}`)
799
+ const project = projectRows[0]
800
+
801
+ const { data: targetRows, error: tErr } = await adminDb
802
+ .from('items')
803
+ .select('id, data, status, is_active')
804
+ .eq('type_id', versionTypeId)
805
+ .eq('id', versionId)
806
+ .filter('data->>project_id', 'eq', projectId)
807
+ .limit(1)
808
+ if (tErr || !targetRows || targetRows.length === 0) throw new Error(`Version not found: ${versionId}`)
809
+ const targetVersion = targetRows[0]
810
+
811
+ const { data: otherVersions, error: oErr } = await adminDb
812
+ .from('items')
813
+ .select('id, data, status, is_active')
814
+ .eq('type_id', versionTypeId)
815
+ .filter('data->>project_id', 'eq', projectId)
816
+ .neq('id', versionId)
817
+ if (oErr) throw new Error(`Failed to list versions: ${oErr.message}`)
818
+
819
+ for (const v of otherVersions || []) {
820
+ if (v.data?.status === 'active') {
821
+ await adminDb.from('items').update({
822
+ status: 'inactive',
823
+ data: { ...v.data, status: 'inactive' },
824
+ }).eq('id', v.id)
825
+ }
826
+ }
827
+
828
+ await adminDb.from('items').update({
829
+ status: 'active',
830
+ data: { ...targetVersion.data, status: 'active' },
831
+ }).eq('id', versionId)
832
+
833
+ const updateCtx = { ...ctx, query: { ...ctx.query, entity: 'items', id: projectId } }
834
+ const result = await adminUpdate(updateCtx, {
835
+ data: {
836
+ ...project.data,
837
+ active_version_id: versionId,
838
+ },
839
+ })
840
+
841
+ return { project: result, version_id: versionId }
842
+ }
843
+
844
+
845
+ if (action === 'publish_version') {
846
+ const projectId = body?.project_id
847
+ const version = body?.version
848
+ if (!projectId) throw new Error('project_id is required')
849
+ if (!version) throw new Error('version is required')
850
+ if (!semver.valid(version)) throw new Error(`Invalid semver version: ${version}`)
496
851
 
852
+ const projectTypeId = await resolveTypeId('item', 'cil_project')
853
+ const versionTypeId = await resolveTypeId('item', 'cil_version')
854
+
855
+ const { data: projectRows, error: pErr } = await adminDb
856
+ .from('items')
857
+ .select('id, data, title')
858
+ .eq('type_id', projectTypeId)
859
+ .eq('id', projectId)
860
+ .limit(1)
861
+ if (pErr || !projectRows || projectRows.length === 0) throw new Error(`Project not found: ${projectId}`)
862
+ const project = projectRows[0]
863
+
864
+ const versionRecord = await adminCreate(ctx, {
865
+ entity: 'items',
866
+ type_slug: 'cil_version',
867
+ title: version,
868
+ status: 'active',
869
+ data: {
870
+ project_id: projectId,
871
+ version,
872
+ base_version: body?.base_version || '',
873
+ parent_version_id: project.data?.active_version_id || '',
874
+ npm_name: project.data?.npm_name || '',
875
+ npm_version: version,
876
+ is_iteration: false,
877
+ is_customer: false,
878
+ status: 'active',
879
+ manifest: null,
880
+ diff: null,
881
+ },
882
+ })
883
+
884
+ const manifest = await buildVersionManifest(projectId)
885
+ const parentVersionId = versionRecord.data.parent_version_id
886
+ const { data: parentVersionRows } = parentVersionId
887
+ ? await adminDb.from('items').select('id, data').eq('id', parentVersionId).maybeSingle()
888
+ : { data: null }
889
+ const parentManifest = parentVersionRows?.data?.manifest || null
890
+ const diff = buildVersionDiff(parentManifest, manifest)
891
+ await adminDb.from('items').update({ data: { ...versionRecord.data, manifest, diff } }).eq('id', versionRecord.id)
892
+ versionRecord.data = { ...versionRecord.data, manifest, diff }
893
+
894
+ const { data: allVersions, error: vErr } = await adminDb
895
+ .from('items')
896
+ .select('id, data, status, is_active')
897
+ .eq('type_id', versionTypeId)
898
+ .filter('data->>project_id', 'eq', projectId)
899
+ .neq('id', versionRecord.id)
900
+ if (vErr) throw new Error(`Failed to list versions: ${vErr.message}`)
901
+
902
+ for (const v of allVersions || []) {
903
+ if (v.data?.status !== 'inactive') {
904
+ await adminDb.from('items').update({
905
+ status: 'inactive',
906
+ data: { ...v.data, status: 'inactive' },
907
+ }).eq('id', v.id)
908
+ }
909
+ }
910
+
911
+ if (body?.base_version) {
912
+ const baseVersion = body.base_version
913
+ const { data: iterations, error: iErr } = await adminDb
914
+ .from('items')
915
+ .select('id, data, status, is_active')
916
+ .eq('type_id', versionTypeId)
917
+ .filter('data->>project_id', 'eq', projectId)
918
+ .filter('data->>base_version', 'eq', baseVersion)
919
+ .filter('data->>is_iteration', 'eq', 'true')
920
+ if (iErr) throw new Error(`Failed to list iterations: ${iErr.message}`)
921
+
922
+ for (const iter of iterations || []) {
923
+ if (iter.data?.status !== 'inactive') {
924
+ await adminDb.from('items').update({
925
+ status: 'inactive',
926
+ data: { ...iter.data, status: 'inactive' },
927
+ }).eq('id', iter.id)
928
+ }
929
+ }
930
+
931
+ const activeIteration = (iterations || []).find((i: any) => i.data?.status === 'active' || !i.data?.published_version_id)
932
+ || (iterations || [])[0]
933
+ if (activeIteration) {
934
+ await adminDb.from('items').update({
935
+ data: { ...activeIteration.data, published_version_id: versionRecord.id },
936
+ }).eq('id', activeIteration.id)
937
+ }
938
+ }
939
+
940
+ const updateCtx = { ...ctx, query: { ...ctx.query, entity: 'items', id: projectId } }
941
+ const result = await adminUpdate(updateCtx, {
942
+ data: {
943
+ ...project.data,
944
+ active_version_id: versionRecord.id,
945
+ default_version_id: versionRecord.id,
946
+ },
947
+ })
948
+
949
+ return { version: versionRecord, project: result }
950
+ }
951
+
952
+
953
+ if (action === 'mark_versions_inactive') {
954
+ const projectId = body?.project_id
955
+ const versionPattern = body?.version_pattern
956
+ if (!projectId) throw new Error('project_id is required')
957
+ if (!versionPattern) throw new Error('version_pattern is required')
958
+
959
+ const versionTypeId = await resolveTypeId('item', 'cil_version')
960
+ const { data: matches, error } = await adminDb
961
+ .from('items')
962
+ .select('id, data, status, is_active')
963
+ .eq('type_id', versionTypeId)
964
+ .filter('data->>project_id', 'eq', projectId)
965
+ .ilike('data->>version', `%${versionPattern}%`)
966
+ if (error) throw new Error(`Failed to find versions: ${error.message}`)
967
+
968
+ const updatedIds: string[] = []
969
+ for (const v of matches || []) {
970
+ await adminDb.from('items').update({
971
+ status: 'inactive',
972
+ data: { ...v.data, status: 'inactive' },
973
+ }).eq('id', v.id)
974
+ updatedIds.push(v.id)
975
+ }
976
+
977
+ return { updated_ids: updatedIds, count: updatedIds.length }
978
+ }
979
+
980
+
981
+ if (action === 'archive_versions') {
982
+ const projectId = body?.project_id
983
+ const keepLastN = parseInt(body?.keep_last_n, 10)
984
+ if (!projectId) throw new Error('project_id is required')
985
+ if (Number.isNaN(keepLastN) || keepLastN < 0) throw new Error('keep_last_n is required and must be a number >= 0')
986
+
987
+ const versionTypeId = await resolveTypeId('item', 'cil_version')
988
+ const { data: allVersions, error } = await adminDb
989
+ .from('items')
990
+ .select('id, data, status, is_active, created_at')
991
+ .eq('type_id', versionTypeId)
992
+ .filter('data->>project_id', 'eq', projectId)
993
+ .order('created_at', { ascending: true })
994
+ if (error) throw new Error(`Failed to list versions: ${error.message}`)
995
+
996
+ const activeVersionId = (allVersions || []).find((v: any) => v.data?.status === 'active')?.id
997
+ const inactiveVersions = (allVersions || []).filter((v: any) =>
998
+ v.data?.status === 'inactive' && v.id !== activeVersionId
999
+ )
1000
+
1001
+ const toArchive = inactiveVersions.slice(0, Math.max(0, inactiveVersions.length - keepLastN))
1002
+ const archivedIds: string[] = []
1003
+
1004
+ for (const v of toArchive) {
1005
+ await adminDb.from('items').update({
1006
+ is_active: false,
1007
+ status: 'archived',
1008
+ data: { ...v.data, status: 'archived' },
1009
+ }).eq('id', v.id)
1010
+ archivedIds.push(v.id)
1011
+ }
1012
+
1013
+ return { archived_ids: archivedIds, count: archivedIds.length, kept: (allVersions || []).length - archivedIds.length }
1014
+ }
1015
+
1016
+ throw new Error(`Unknown action: ${action}. Valid: list, get, create, update, delete, pipeline_progress, create_version, set_active_version, publish_version, mark_versions_inactive, archive_versions`)
1017
+ })
1018
+ // CIL[DOC-VECTOR type="context" content="purpose='Netlify function handler for CIL project CRUD and version lifecycle actions'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
1019
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
1020
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
1021
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
1022
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
1023
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
1024
+ // CIL[END stable_id="~/.framework/functions/cil-project.ts:handler:constant"]
497
1025
 
498
1026
 
499
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_project_handler_1784235266"]