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,3 +1,13 @@
1
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/cli/commands/migrate.ts"]
2
+ // CIL[DOC-MACRO purpose="Provides the migrate command for applying database migrations to a Supabase project."]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Bootstraps imports and module context for the migrate CLI command."]
4
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
5
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
6
+ // CIL[DOC-MICRO logic_summary="Imports Commander type, fs, path, and url helpers and defines package and project root constants." notable_decisions="Package root is resolved relative to the installed package; project root is the current working directory."]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
8
+ // CIL[DOC-STABILITY stability="stable"]
9
+ // CIL[DOC-AUDIENCE audience="engineers"]
10
+
1
11
 
2
12
 
3
13
 
@@ -8,51 +18,120 @@
8
18
 
9
19
 
10
20
 
11
- // CIL[BEGIN chunk_id="migrate_moduleheader_1784069813" type="module_header" identity="module_header" parent="none"]
12
- // CIL[DOC-MACRO purpose="Module imports and types for migration CLI"]
13
- // CIL[DOC-RESPONSIBILITY responsibility="Provide filesystem utilities and migration interfaces"]
14
- // CIL[DOC-CONTEXT module="cli.commands.migrate" layer="cli" related_files="[\".framework/migrations/015_simplify_apps_table.sql\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\"\\\"]"]
15
- // CIL[DOC-CONTRACT inputs="none" outputs="imports and types" errors="none" side_effects="none"]
16
- // CIL[DOC-MICRO logic_summary="Imports Node.js modules and defines MigrateOptions interface" notable_decisions="[]"]
17
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
18
- // CIL[DOC-STABILITY stability="stable"]
19
- // CIL[DOC-AUDIENCE audience="developer"]
20
- // CIL[DOC-VECTOR type="context" content="Layer: cli. 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/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, \."]
21
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
22
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
23
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
24
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
25
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
26
21
  import type { Command } from 'commander'
27
22
  import { existsSync, readdirSync, readFileSync } from 'fs'
28
23
  import { resolve, dirname, join } from 'path'
29
24
  import { fileURLToPath } from 'url'
30
-
25
+ // CIL[DOC-VECTOR type="context" content="purpose='Provides the migrate command for applying database migrations to a Supabase project.'; No verified external callers; imports: none"]
26
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
27
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
28
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
29
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
30
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
31
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:module_header:module_header"]
32
+
33
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:__filename:constant" type="constant" identity="__filename" parent="~/.framework/cli/commands/migrate.ts"]
34
+ // CIL[DOC-MACRO purpose="Defines the current module file path."]
35
+ // CIL[DOC-RESPONSIBILITY responsibility="Derives __filename from the module import meta URL."]
36
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
37
+ // CIL[DOC-STABILITY stability="internal"]
38
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
39
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
40
+ // CIL[DOC-MICRO logic_summary="Converts import.meta.url to a file path and assigns to __filename." notable_decisions="none"]
41
+ // CIL[DOC-AUDIENCE audience="engineers"]
31
42
  const __filename = fileURLToPath(import.meta.url)
43
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:__filename:constant"]
44
+ // CIL[DOC-CONTEXT module="unknown" layer="unknown" related_files=".framework/cli/commands/migrate.ts"]
45
+ // CIL[DOC-VECTOR type="context" content="purpose='Defines the current module file path.'; No verified external callers; imports: none"]
46
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
47
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
48
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
49
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
50
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
51
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:__dirname:constant" type="constant" identity="__dirname" parent="~/.framework/cli/commands/migrate.ts"]
52
+ // CIL[DOC-MACRO purpose="Defines the current module directory."]
53
+ // CIL[DOC-RESPONSIBILITY responsibility="Derives __dirname from __filename."]
54
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
55
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
56
+ // CIL[DOC-STABILITY stability="internal"]
57
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
58
+ // CIL[DOC-MICRO logic_summary="Computes the directory of the current file and assigns to __dirname." notable_decisions="none"]
59
+ // CIL[DOC-AUDIENCE audience="engineers"]
32
60
  const __dirname = dirname(__filename)
61
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:__dirname:constant"]
62
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:PACKAGE_ROOT:constant" type="constant" identity="PACKAGE_ROOT" parent="~/.framework/cli/commands/migrate.ts"]
63
+ // CIL[DOC-VECTOR type="context" content="purpose='Defines the current module directory.'; No verified external callers; imports: none"]
64
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
65
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
66
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
67
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
68
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
69
+ // CIL[DOC-CONTEXT module="migrate" layer="cli" related_files=".framework/cli/commands/migrate.ts"]
70
+ // CIL[DOC-MACRO purpose="Defines the package root path."]
71
+ // CIL[DOC-RESPONSIBILITY responsibility="Resolves the package root by walking up from the CLI directory."]
72
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
73
+ // CIL[DOC-MICRO logic_summary="Resolves the package root three levels above the current module." notable_decisions="none"]
74
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
75
+ // CIL[DOC-STABILITY stability="stable"]
76
+ // CIL[DOC-AUDIENCE audience="engineers"]
33
77
  const PACKAGE_ROOT = resolve(__dirname, '../../../')
78
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:PACKAGE_ROOT:constant"]
79
+ // CIL[DOC-VECTOR type="context" content="purpose='Defines the package root path.'; No verified external callers; imports: none"]
80
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
81
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
82
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
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
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:PROJECT_ROOT:constant" type="constant" identity="PROJECT_ROOT" parent="~/.framework/cli/commands/migrate.ts"]
86
+ // CIL[DOC-MACRO purpose="Defines the project root path."]
87
+ // CIL[DOC-RESPONSIBILITY responsibility="Uses the current working directory as the project root."]
88
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
89
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
90
+ // CIL[DOC-MICRO logic_summary="Sets PROJECT_ROOT to process.cwd()." notable_decisions="none"]
91
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
92
+ // CIL[DOC-STABILITY stability="stable"]
93
+ // CIL[DOC-AUDIENCE audience="engineers"]
34
94
  const PROJECT_ROOT = process.cwd()
95
+ // CIL[DOC-VECTOR type="context" content="purpose='Defines the project root path.'; No verified external callers; imports: none"]
96
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
97
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
98
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
99
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
100
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
101
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:PROJECT_ROOT:constant"]
102
+
35
103
 
104
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:MigrateOptions:interface" type="interface" identity="MigrateOptions" parent="~/.framework/cli/commands/migrate.ts"]
105
+ // CIL[DOC-MACRO purpose="Declares the migrate command options."]
106
+ // CIL[DOC-RESPONSIBILITY responsibility="Types the CLI flags and optional db password."]
107
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
108
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
109
+ // CIL[DOC-MICRO logic_summary="Defines dbPassword, dryRun, and frameworkOnly fields." notable_decisions="none"]
110
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
111
+ // CIL[DOC-STABILITY stability="stable"]
112
+ // CIL[DOC-AUDIENCE audience="engineers"]
36
113
  interface MigrateOptions {
37
114
  dbPassword?: string
38
115
  dryRun: boolean
39
116
  frameworkOnly: boolean
40
117
  }
41
- // CIL[END chunk_id="migrate_moduleheader_1784069813"]
42
- // CIL[BEGIN chunk_id="migrate_runmigrations_1784069813" type="function" identity="runMigrations" parent="none"]
43
- // CIL[DOC-MACRO purpose="Execute database migrations via direct PostgreSQL connection"]
44
- // CIL[DOC-RESPONSIBILITY responsibility="Apply pending SQL migrations to database"]
45
- // CIL[DOC-CONTEXT module="cli.commands.migrate" layer="cli" related_files="[\".framework/migrations/015_simplify_apps_table.sql\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
46
- // CIL[DOC-CONTRACT inputs="none" outputs="migration results" errors="database errors" side_effects="database writes"]
47
- // CIL[DOC-MICRO logic_summary="Connects to PostgreSQL, creates migration tracking table, applies SQL files" notable_decisions="[]"]
48
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
49
- // CIL[DOC-STABILITY stability="stable"]
50
- // CIL[DOC-VECTOR type="context" content="Layer: cli. Direct callers: 0. Direct calls: 0. Related files: .framework/migrations/015_simplify_apps_table.sql, .framework/src/pages/admin/RolesPage.tsx, \."]
51
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
52
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
53
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
118
+ // CIL[DOC-VECTOR type="context" content="purpose='Declares the migrate command options.'; No verified external callers; imports: none"]
119
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
120
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
121
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
54
122
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
55
123
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
124
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:MigrateOptions:interface"]
125
+
126
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:runMigrations:function" type="function" identity="runMigrations" parent="~/.framework/cli/commands/migrate.ts"]
127
+ // CIL[DOC-MACRO purpose="Applies pending SQL migration files to the Supabase database and tracks which have been applied."]
128
+ // CIL[DOC-RESPONSIBILITY responsibility="Executes migrations safely in transactions and records them in the tracking table."]
129
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
130
+ // CIL[DOC-CONTRACT inputs="opts: { frameworkOnly?: boolean }" outputs="Promise<{ applied: number; skipped: number; failed: number } | null>" errors="Returns null if credentials missing; throws on invalid SUPABASE_URL, tracking-table failures, and file read errors; logs per migration statement errors to stderr, rolls back, increments failed once, and stops." side_effects="Connects to Postgres, creates _spine_migrations table, executes SQL, inserts migration records, writes to stdout/stderr."]
131
+ // CIL[DOC-MICRO logic_summary="Reads env, validates SUPABASE_URL is a credential-free hosted https://<project-ref>.supabase.co URL, derives the db host, builds a pg.Client config object, collects migration files, filters already applied, splits and runs SQL statements, updates _spine_migrations, and returns counts." notable_decisions="Skips missing or placeholder credentials; non-HTTPS, credential-bearing, non-supabase.co, ported, pathed, or query/hash URLs are rejected before any client exists; uses a SET to track applied files; runs each migration in a transaction; tracking CREATE and SELECT propagate so migrations never run against unknown tracking state; first file error rolls back and breaks; the connected client always ends via finally."]
132
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
133
+ // CIL[DOC-STABILITY stability="stable"]
134
+ // CIL[DOC-AUDIENCE audience="engineers"]
56
135
  export async function runMigrations(opts: { frameworkOnly?: boolean } = {}): Promise<{ applied: number; skipped: number; failed: number } | null> {
57
136
  const supabaseUrl = process.env.SUPABASE_URL
58
137
  if (!supabaseUrl || supabaseUrl.includes('placeholder') || supabaseUrl.includes('your-project')) {
@@ -64,16 +143,41 @@ export async function runMigrations(opts: { frameworkOnly?: boolean } = {}): Pro
64
143
  return null
65
144
  }
66
145
 
67
- const projectRef = supabaseUrl.replace('https://', '').split('.')[0]
68
- const connectionString = `postgresql://postgres:${dbPassword}@db.${projectRef}.supabase.co:5432/postgres`
146
+ let projectRef: string
147
+ try {
148
+ const parsed = new URL(supabaseUrl)
149
+ if (
150
+ parsed.protocol !== 'https:' ||
151
+ parsed.username !== '' ||
152
+ parsed.password !== '' ||
153
+ parsed.port !== '' ||
154
+ parsed.search !== '' ||
155
+ parsed.hash !== '' ||
156
+ (parsed.pathname !== '/' && parsed.pathname !== '') ||
157
+ !/^[a-z0-9-]+\.supabase\.co$/.test(parsed.hostname)
158
+ ) {
159
+ throw new Error('not a hosted Supabase URL')
160
+ }
161
+ projectRef = parsed.hostname.split('.')[0]
162
+ } catch {
163
+ throw new Error('Invalid SUPABASE_URL — expected a URL like https://<project-ref>.supabase.co')
164
+ }
69
165
 
70
166
  const migrationFiles = collectMigrations(opts.frameworkOnly ?? false)
71
167
  if (migrationFiles.length === 0) return { applied: 0, skipped: 0, failed: 0 }
72
168
 
73
169
  const { default: pg } = await import('pg')
74
- const client = new pg.Client({ connectionString })
170
+ const client = new pg.Client({
171
+ user: 'postgres',
172
+ password: dbPassword,
173
+ host: `db.${projectRef}.supabase.co`,
174
+ port: 5432,
175
+ database: 'postgres',
176
+ })
75
177
  await client.connect()
76
178
 
179
+ let applied = 0, skipped = 0, failed = 0
180
+
77
181
  try {
78
182
  await client.query(`
79
183
  CREATE TABLE IF NOT EXISTS _spine_migrations (
@@ -82,62 +186,61 @@ export async function runMigrations(opts: { frameworkOnly?: boolean } = {}): Pro
82
186
  applied_at TIMESTAMPTZ DEFAULT NOW()
83
187
  )
84
188
  `)
85
- } catch { /* non-fatal */ }
86
189
 
87
- let appliedMigrations = new Set<string>()
88
- try {
89
190
  const { rows } = await client.query('SELECT filename FROM _spine_migrations')
90
- appliedMigrations = new Set(rows.map((r: { filename: string }) => r.filename))
91
- } catch { /* non-fatal */ }
191
+ const appliedMigrations = new Set<string>(rows.map((r: { filename: string }) => r.filename))
92
192
 
93
- let applied = 0, skipped = 0, failed = 0
94
-
95
- for (const { name, path } of migrationFiles) {
96
- if (appliedMigrations.has(name)) {
97
- skipped++
98
- continue
99
- }
193
+ for (const { name, path } of migrationFiles) {
194
+ if (appliedMigrations.has(name)) {
195
+ skipped++
196
+ continue
197
+ }
100
198
 
101
- const sql = readFileSync(path, 'utf8')
102
- process.stdout.write(` Applying ${name}... `)
103
- const statements = splitSqlStatements(sql)
199
+ const sql = readFileSync(path, 'utf8')
200
+ process.stdout.write(` Applying ${name}... `)
201
+ const statements = splitSqlStatements(sql)
104
202
 
105
- try {
106
- await client.query('BEGIN')
107
- for (const stmt of statements) await client.query(stmt)
108
- await client.query(
109
- `INSERT INTO _spine_migrations (filename) VALUES ($1) ON CONFLICT (filename) DO NOTHING`,
110
- [name]
111
- )
112
- await client.query('COMMIT')
113
- console.log('✓')
114
- applied++
115
- } catch (err: any) {
116
- await client.query('ROLLBACK').catch(() => {})
117
- console.log('✗')
118
- console.error(` ${err.message}`)
119
- failed++
203
+ try {
204
+ await client.query('BEGIN')
205
+ for (const stmt of statements) await client.query(stmt)
206
+ await client.query(
207
+ `INSERT INTO _spine_migrations (filename) VALUES ($1) ON CONFLICT (filename) DO NOTHING`,
208
+ [name]
209
+ )
210
+ await client.query('COMMIT')
211
+ console.log('✓')
212
+ applied++
213
+ } catch (err: any) {
214
+ await client.query('ROLLBACK').catch(() => { /* non-fatal */ })
215
+ console.log('✗')
216
+ console.error(` ${err.message}`)
217
+ failed++
218
+ break
219
+ }
120
220
  }
221
+ } finally {
222
+ await client.end().catch(() => { /* non-fatal */ })
121
223
  }
122
224
 
123
- await client.end()
124
225
  return { applied, skipped, failed }
125
226
  }
126
- // CIL[END chunk_id="migrate_runmigrations_1784069813"]
127
- // CIL[BEGIN chunk_id="migrate_migratecommand_1784069813" type="function" identity="migrateCommand" parent="none"]
128
- // CIL[DOC-MACRO purpose="Handle migration command execution with validation"]
129
- // CIL[DOC-RESPONSIBILITY responsibility="Validate environment and orchestrate migration process"]
130
- // CIL[DOC-CONTEXT module="cli.commands.migrate" layer="cli" related_files="[\".framework/functions/_shared/schema-utils.ts\",\".framework/migrations/015_simplify_apps_table.sql\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"\\\"]"]
131
- // CIL[DOC-CONTRACT inputs="none" outputs="migration execution" errors="validation errors" side_effects="process exit"]
132
- // CIL[DOC-MICRO logic_summary="Validates env vars, loads migrations, handles dry-run and execution" notable_decisions="[]"]
133
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
134
- // CIL[DOC-STABILITY stability="stable"]
135
- // CIL[DOC-VECTOR type="context" content="Layer: cli. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/schema-utils.ts, .framework/migrations/015_simplify_apps_table.sql, .framework/src/pages/admin/TypeDetailPage.tsx, \."]
136
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
137
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
138
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
227
+ // CIL[DOC-VECTOR type="context" content="purpose='Applies pending SQL migration files to the Supabase database and tracks which have been applied.'; No verified external callers; imports: none"]
228
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
229
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
230
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
139
231
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
140
232
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
233
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:runMigrations:function"]
234
+
235
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:migrateCommand:function" type="function" identity="migrateCommand" parent="~/.framework/cli/commands/migrate.ts"]
236
+ // CIL[DOC-MACRO purpose="CLI action that collects, optionally dry-runs, and applies framework migrations."]
237
+ // CIL[DOC-RESPONSIBILITY responsibility="Validates environment, loads .env, handles dry run, and prints result."]
238
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
239
+ // CIL[DOC-CONTRACT inputs="options: MigrateOptions" outputs="Promise<void>" errors="Exits process with status 1 on missing credentials or failed migrations." side_effects="Reads .env, writes to stdout/stderr, may set process.env, calls process.exit."]
240
+ // CIL[DOC-MICRO logic_summary="Loads .env, verifies SUPABASE_URL and password, collects migration files, dry-run lists them or calls runMigrations, reports counts, and exits." notable_decisions="Supports --db-password, --dry-run, and --framework-only; sets process.env.SUPABASE_DB_PASSWORD if passed; hard exits on missing env or failed migrations."]
241
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
242
+ // CIL[DOC-STABILITY stability="stable"]
243
+ // CIL[DOC-AUDIENCE audience="engineers"]
141
244
  async function migrateCommand(options: MigrateOptions): Promise<void> {
142
245
  console.log('\nRunning Spine Framework migrations...\n')
143
246
 
@@ -210,24 +313,26 @@ async function migrateCommand(options: MigrateOptions): Promise<void> {
210
313
 
211
314
  console.log('\n✅ All migrations applied successfully!\n')
212
315
  console.log('Next steps:')
213
- console.log(' npx spine-framework install-app spine-framework-portal@latest')
316
+ console.log(' npx spine-framework install-app <app-package>')
214
317
  console.log(' npm install && npm run assemble && netlify dev\n')
215
318
  }
216
- // CIL[END chunk_id="migrate_migratecommand_1784069813"]
217
- // CIL[BEGIN chunk_id="migrate_registermigratecommands_1784069813" type="function" identity="registerMigrateCommands" parent="none"]
218
- // CIL[DOC-MACRO purpose="Register migrate command with CLI program"]
219
- // CIL[DOC-RESPONSIBILITY responsibility="Provide CLI interface for database migrations"]
220
- // CIL[DOC-CONTEXT module="cli.commands.migrate" layer="cli" related_files="[\".framework/functions/_shared/schema-utils.ts\",\".framework/src/components/ui/dialog.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/components/ui/table-primitives.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"\\\"]"]
221
- // CIL[DOC-CONTRACT inputs="none" outputs="CLI command registration" errors="command errors" side_effects="none"]
222
- // CIL[DOC-MICRO logic_summary="Registers migrate command with db-password, dry-run, and framework-only options" notable_decisions="[]"]
223
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
224
- // CIL[DOC-STABILITY stability="stable"]
225
- // CIL[DOC-VECTOR type="context" content="Layer: cli. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/schema-utils.ts, .framework/src/components/ui/dialog.tsx, .framework/functions/_shared/principal.ts, .framework/src/components/ui/table-primitives.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, \."]
226
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
227
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
228
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
319
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:migrateCommand:function"]
320
+
321
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:registerMigrateCommands:function" type="function" identity="registerMigrateCommands" parent="~/.framework/cli/commands/migrate.ts"]
322
+ // CIL[DOC-VECTOR type="context" content="purpose='CLI action that collects, optionally dry-runs, and applies framework migrations.'; No verified external callers; imports: none"]
323
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
324
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
325
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
229
326
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
230
327
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
328
+ // CIL[DOC-MACRO purpose="Registers the migrate command with the Commander program."]
329
+ // CIL[DOC-RESPONSIBILITY responsibility="Defines CLI command options and delegates to migrateCommand."]
330
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
331
+ // CIL[DOC-CONTRACT inputs="program: Command" outputs="void" errors="Logs error and exits on action failure." side_effects="Mutates the Commander program with a new command."]
332
+ // CIL[DOC-MICRO logic_summary="Adds the migrate command with --db-password, --dry-run, and --framework-only options and an async action." notable_decisions="Catches action errors, prints messages, and exits on failure; logs stack if SPINE_CLI_DEBUG."]
333
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
334
+ // CIL[DOC-STABILITY stability="stable"]
335
+ // CIL[DOC-AUDIENCE audience="engineers"]
231
336
  export function registerMigrateCommands(program: Command) {
232
337
  program
233
338
  .command('migrate')
@@ -245,21 +350,23 @@ export function registerMigrateCommands(program: Command) {
245
350
  }
246
351
  })
247
352
  }
248
- // CIL[END chunk_id="migrate_registermigratecommands_1784069813"]
249
- // CIL[BEGIN chunk_id="migrate_loadenv_1784069813" type="function" identity="loadEnv" parent="none"]
250
- // CIL[DOC-MACRO purpose="Load environment variables from .env file"]
251
- // CIL[DOC-RESPONSIBILITY responsibility="Parse and set environment variables"]
252
- // CIL[DOC-CONTEXT module="cli.commands.migrate" layer="cli" related_files="[\"\\\"]"]
253
- // CIL[DOC-CONTRACT inputs="none" outputs="process.env updates" errors="file read errors" side_effects="process.env mutation"]
254
- // CIL[DOC-MICRO logic_summary="Reads .env file, parses key=value pairs, sets process.env" notable_decisions="[]"]
255
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
256
- // CIL[DOC-STABILITY stability="stable"]
257
- // CIL[DOC-VECTOR type="context" content="Layer: cli. Direct callers: 0. Direct calls: 0. Related files: \."]
258
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
259
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
260
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
353
+ // CIL[DOC-VECTOR type="context" content="purpose='Registers the migrate command with the Commander program.'; No verified external callers; imports: none"]
354
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
355
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
356
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
261
357
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
262
358
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
359
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:registerMigrateCommands:function"]
360
+
361
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:loadEnv:function" type="function" identity="loadEnv" parent="~/.framework/cli/commands/migrate.ts"]
362
+ // CIL[DOC-MACRO purpose="Loads key=value pairs from the project .env file into process.env."]
363
+ // CIL[DOC-RESPONSIBILITY responsibility="Reads .env without overwriting existing environment variables."]
364
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
365
+ // CIL[DOC-CONTRACT inputs="none (reads PROJECT_ROOT/.env)" outputs="void" errors="silently returns if .env is missing" side_effects="Mutates process.env."]
366
+ // CIL[DOC-MICRO logic_summary="Reads .env lines, skips comments and blank lines, parses the first = into key and value, and sets process.env if absent." notable_decisions="Ignores malformed lines; does not overwrite existing environment variables."]
367
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
368
+ // CIL[DOC-STABILITY stability="stable"]
369
+ // CIL[DOC-AUDIENCE audience="engineers"]
263
370
  function loadEnv() {
264
371
  const envPath = join(PROJECT_ROOT, '.env')
265
372
  if (!existsSync(envPath)) return
@@ -274,22 +381,24 @@ function loadEnv() {
274
381
  if (key && !(key in process.env)) process.env[key] = val
275
382
  }
276
383
  }
277
- // CIL[END chunk_id="migrate_loadenv_1784069813"]
278
- // CIL[BEGIN chunk_id="migrate_collectmigrations_1784069813" type="function" identity="collectMigrations" parent="none"]
279
- // CIL[DOC-MACRO purpose="Collect migration files from framework and custom directories"]
280
- // CIL[DOC-RESPONSIBILITY responsibility="Find and sort SQL migration files"]
281
- // CIL[DOC-CONTEXT module="cli.commands.migrate" layer="cli" related_files="[]"]
282
- // CIL[DOC-CONTRACT inputs="none" outputs="migration file list" errors="filesystem errors" side_effects="none"]
283
- // CIL[DOC-MICRO logic_summary="Scans .framework/migrations and custom/migrations for .sql files" notable_decisions="[]"]
284
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
285
- // CIL[DOC-STABILITY stability="stable"]
286
- // CIL[DOC-VECTOR type="context" content="Layer: cli. Direct callers: 0. Direct calls: 0. Related files: none."]
287
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
288
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
289
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
384
+ // CIL[DOC-VECTOR type="context" content="purpose='Loads key=value pairs from the project .env file into process.env.'; No verified external callers; imports: none"]
385
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
386
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
387
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
290
388
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
291
389
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
292
- function collectMigrations(frameworkOnly: boolean): { name: string; path: string }[] {
390
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:loadEnv:function"]
391
+
392
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:collectMigrations:function" type="function" identity="collectMigrations" parent="~/.framework/cli/commands/migrate.ts"]
393
+ // CIL[DOC-MACRO purpose="Collects SQL migration files from framework and custom directories."]
394
+ // CIL[DOC-RESPONSIBILITY responsibility="Sorts and returns file paths for pending migrations, optionally including custom migrations."]
395
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
396
+ // CIL[DOC-CONTRACT inputs="frameworkOnly: boolean" outputs="Array<{ name: string; path: string }>" errors="none" side_effects="Reads directories via readdirSync."]
397
+ // CIL[DOC-MICRO logic_summary="Resolves the framework migrations directory, optionally adds custom/migrations, and returns sorted .sql entries." notable_decisions="Prefers PROJECT_ROOT/.framework/migrations over PACKAGE_ROOT; filters dotfiles and non-.sql files."]
398
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
399
+ // CIL[DOC-STABILITY stability="stable"]
400
+ // CIL[DOC-AUDIENCE audience="engineers"]
401
+ export function collectMigrations(frameworkOnly: boolean): { name: string; path: string }[] {
293
402
  const files: { name: string; path: string }[] = []
294
403
 
295
404
 
@@ -317,47 +426,81 @@ function collectMigrations(frameworkOnly: boolean): { name: string; path: string
317
426
 
318
427
  return files
319
428
  }
320
- // CIL[END chunk_id="migrate_collectmigrations_1784069813"]
321
- // CIL[BEGIN chunk_id="migrate_splitsqlstatements_1784069813" type="function" identity="splitSqlStatements" parent="none"]
322
- // CIL[DOC-MACRO purpose="Split SQL string into individual statements"]
323
- // CIL[DOC-RESPONSIBILITY responsibility="Parse SQL migration files into executable statements"]
324
- // CIL[DOC-CONTEXT module="cli.commands.migrate" layer="cli" related_files="[]"]
325
- // CIL[DOC-CONTRACT inputs="none" outputs="statement array" errors="parsing errors" side_effects="none"]
326
- // CIL[DOC-MICRO logic_summary="Handles dollar-quoted blocks, removes comments, splits on semicolons" notable_decisions="[]"]
327
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="complex_sql_parsing"]
328
- // CIL[DOC-STABILITY stability="stable"]
329
- // CIL[DOC-VECTOR type="context" content="Layer: cli. Direct callers: 0. Direct calls: 0. Related files: none."]
330
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
331
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
332
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
429
+ // CIL[DOC-VECTOR type="context" content="purpose='Collects SQL migration files from framework and custom directories.'; No verified external callers; imports: none"]
430
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
431
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
432
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
333
433
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
334
434
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
335
- function splitSqlStatements(sql: string): string[] {
336
- const dollarBlocks: string[] = []
337
- let blockIndex = 0
338
-
339
-
340
- const protectedSql = sql.replace(/\$[A-Za-z_]*\$[\s\S]*?\$[A-Za-z_]*\$/g, (match) => {
341
- const placeholder = `__DOLLAR_BLOCK_${blockIndex}__`
342
- dollarBlocks[blockIndex] = match
343
- blockIndex++
344
- return placeholder
345
- })
435
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:collectMigrations:function"]
436
+
437
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/migrate.ts:splitSqlStatements:function" type="function" identity="splitSqlStatements" parent="~/.framework/cli/commands/migrate.ts"]
438
+ // CIL[DOC-MACRO purpose="Splits SQL into executable statements while preserving dollar-quoted blocks."]
439
+ // CIL[DOC-RESPONSIBILITY responsibility="Removes single-line comments, splits on semicolons, restores protected dollar-quoted blocks, and returns trimmed statements."]
440
+ // CIL[DOC-CONTEXT module="cli" layer="framework" related_files=".framework/cli/commands/migrate.ts"]
441
+ // CIL[DOC-CONTRACT inputs="sql: string" outputs="Array<string>" errors="none" side_effects="none"]
442
+ // CIL[DOC-MICRO logic_summary="Single-pass scanner tracking --, /* */, single-quote, double-quote, and dollar-tag state so ; only splits statements in normal state" notable_decisions="Regex layering was abandoned — apostrophes inside comments and semicolons inside literals broke both orderings; a state machine is the only correct approach."]
443
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
444
+ // CIL[DOC-STABILITY stability="stable"]
445
+ // CIL[DOC-AUDIENCE audience="engineers"]
446
+ export function splitSqlStatements(sql: string): string[] {
447
+ // Single-pass scanner: a ; only ends a statement in normal state. Comments
448
+ // are dropped; string literals, quoted identifiers, and dollar-quoted blocks
449
+ // are preserved verbatim.
450
+ const statements: string[] = []
451
+ let buf = ''
452
+ let i = 0
453
+ let inLine = false, inBlock = false, inSingle = false, inDouble = false
454
+ let dollarTag: string | null = null
455
+
456
+ while (i < sql.length) {
457
+ const ch = sql[i], next = sql[i + 1]
458
+
459
+ if (inLine) { if (ch === '\n') inLine = false; i++; continue }
460
+ if (inBlock) { if (ch === '*' && next === '/') { inBlock = false; i += 2 } else i++; continue }
461
+
462
+ if (dollarTag) {
463
+ if (sql.startsWith(dollarTag, i)) { buf += dollarTag; i += dollarTag.length; dollarTag = null }
464
+ else { buf += ch; i++ }
465
+ continue
466
+ }
467
+ if (inSingle) {
468
+ buf += ch
469
+ if (ch === "'") { if (next === "'") { buf += next; i++ } else inSingle = false }
470
+ i++; continue
471
+ }
472
+ if (inDouble) {
473
+ buf += ch
474
+ if (ch === '"') inDouble = false
475
+ i++; continue
476
+ }
346
477
 
347
-
348
- const noComments = protectedSql.replace(/--[^\n]*/g, '')
478
+ if (ch === '-' && next === '-') { inLine = true; i += 2; continue }
479
+ if (ch === '/' && next === '*') { inBlock = true; i += 2; continue }
480
+ if (ch === "'") { inSingle = true; buf += ch; i++; continue }
481
+ if (ch === '"') { inDouble = true; buf += ch; i++; continue }
482
+ if (ch === '$') {
483
+ const m = sql.slice(i).match(/^\$[A-Za-z_]*\$/)
484
+ if (m) { dollarTag = m[0]; buf += m[0]; i += m[0].length; continue }
485
+ }
486
+ if (ch === ';') {
487
+ const s = buf.trim()
488
+ if (s) statements.push(s + ';')
489
+ buf = ''
490
+ i++
491
+ continue
492
+ }
493
+ buf += ch; i++
494
+ }
349
495
 
350
-
351
- return noComments
352
- .split(';')
353
- .map(s => {
354
- let restored = s.trim()
355
- dollarBlocks.forEach((block, idx) => {
356
- restored = restored.replace(`__DOLLAR_BLOCK_${idx}__`, () => block)
357
- })
358
- return restored
359
- })
360
- .filter(s => s.length > 0)
361
- .map(s => s + ';')
496
+ const tail = buf.trim()
497
+ if (tail) statements.push(tail + ';')
498
+ return statements
362
499
  }
363
- // CIL[END chunk_id="migrate_splitsqlstatements_1784069813"]
500
+ // CIL[DOC-VECTOR type="context" content="purpose='Splits SQL into executable statements while preserving dollar-quoted blocks.'; No verified external callers; imports: none"]
501
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
502
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
503
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
504
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
505
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
506
+ // CIL[END stable_id="~/.framework/cli/commands/migrate.ts:splitSqlStatements:function"]