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
@@ -0,0 +1,42 @@
1
+ {
2
+ // Typecheck for the ASSEMBLED functions layout.
3
+ //
4
+ // Function sources (.framework/functions, custom/functions,
5
+ // custom/apps/<app>/functions) are merged flat into
6
+ // .assembled/netlify/functions by scripts/assemble-functions.sh. Their
7
+ // imports only resolve in that layout:
8
+ // - './_shared/*' resolves to the assembled _shared/ sibling dir
9
+ // - './<other-function>' resolves to other flat-assembled files
10
+ // - '@shared/*' is a runtime/bundler alias → assembled _shared/
11
+ // So this config checks the assembled output, not the source trees. Run:
12
+ // npx tsc --noEmit -p config/tsconfig.functions.json
13
+ // (Intentionally NOT in tsconfig.json's references — `tsc -b` would require
14
+ // composite+emit and fail the vite build on unrelated functions errors.)
15
+ "compilerOptions": {
16
+ "target": "ES2020",
17
+ "lib": ["ES2020"],
18
+ "types": ["node"],
19
+ "module": "ESNext",
20
+ "skipLibCheck": true,
21
+ "moduleResolution": "bundler",
22
+ "allowImportingTsExtensions": true,
23
+ "isolatedModules": true,
24
+ "moduleDetection": "force",
25
+ "noEmit": true,
26
+ "strict": false,
27
+ "noUnusedLocals": false,
28
+ "noUnusedParameters": false,
29
+ "resolveJsonModule": true,
30
+ "forceConsistentCasingInFileNames": true,
31
+ "baseUrl": ".",
32
+ "paths": {
33
+ "@shared/*": ["../.assembled/netlify/functions/_shared/*"],
34
+ "@/*": ["../.assembled/netlify/functions/*"]
35
+ }
36
+ },
37
+ "include": ["../.assembled/netlify/functions"],
38
+ "exclude": [
39
+ "../node_modules",
40
+ "../.assembled/netlify/functions/_quarantine"
41
+ ]
42
+ }
@@ -21,21 +21,49 @@
21
21
  "baseUrl": ".",
22
22
  "paths": {
23
23
  "@/*": ["../.assembled/src/*"], // Assembled frontend
24
- "@core/*": ["../.framework/src/*"], // Core source
25
- "@custom/*": ["../custom/*"], // Custom source
24
+ "@core/*": ["../.framework/src/*"], // Core source (same tree as .assembled/src base layer)
25
+ "@custom/*": ["../custom/*"], // Custom source
26
26
  "@shared/*": ["../.framework/functions/_shared/*"] // Shared functions (resolved at runtime via assembly)
27
27
  }
28
28
  },
29
- "include": [".assembled/src", ".framework/functions"],
29
+ // NOTE: include/exclude paths are relative to THIS directory (config/), so
30
+ // everything real needs a "../" prefix — the previous values silently
31
+ // matched nothing and typecheck covered zero files.
32
+ //
33
+ // Coverage: assembled frontend, framework source, and every custom app's
34
+ // index.tsx + source tree (components/pages/hooks/lib/utils/views).
35
+ // Function code is deliberately EXCLUDED here — both .framework/functions
36
+ // and custom/apps/​*/functions assume the assembled flat layout
37
+ // (./_shared/* sibling imports only resolve post-assembly). Typecheck them
38
+ // separately against the assembled output:
39
+ // npx tsc --noEmit -p config/tsconfig.functions.json
40
+ "include": [
41
+ "../.assembled/src",
42
+ "../.framework/src",
43
+ "../custom/apps",
44
+ "../custom/components",
45
+ "../custom/hooks"
46
+ ],
30
47
  "exclude": [
31
48
  "node_modules",
32
49
  "dist",
33
- "netlify/functions",
34
- "supabase",
35
- "scripts",
36
- ".netlify",
37
- ".assembled/src",
38
- "custom/functions"
50
+ "../node_modules",
51
+ "../dist",
52
+ "../netlify",
53
+ "../supabase",
54
+ "../scripts",
55
+ "../.netlify",
56
+ "../.framework/functions",
57
+ "../.assembled/netlify",
58
+ "../custom/functions",
59
+ "../custom/apps/*/functions",
60
+ "../custom/apps/*/seed",
61
+ "../custom/apps/*/public",
62
+ "../custom/apps/*/docs",
63
+ "../custom/apps/*/mcp",
64
+ "../custom/apps/*/migrations-archive",
65
+ "../custom/apps/*/node_modules",
66
+ "../custom/apps/*/dist"
39
67
  ],
40
68
  "references": [{ "path": "./tsconfig.node.json" }]
41
69
  }
@@ -2,10 +2,39 @@ import { defineConfig } from 'vite'
2
2
  import react from '@vitejs/plugin-react'
3
3
  import path from 'path'
4
4
 
5
+ // CIL[BEGIN stable_id="~/config/vite.config.ts:module:config" type="config" identity="vite-config" parent="~/config/vite.config.ts"]
6
+ // CIL[DOC-MACRO purpose="Vite build/dev config for Spine: assembled src root, /api proxy to Netlify dev, manual vendor chunks, @/ @core @custom @shared aliases."]
7
+ // CIL[DOC-RESPONSIBILITY responsibility="Point Vite at .assembled/src, wire SPA fallback middleware, public dir, PostCSS (config/postcss.config.cjs), and dev-server fs/proxy settings."]
8
+ // CIL[DOC-CONTEXT module="build-config" layer="build" related_files="scripts/assemble-frontend.sh,config/postcss.config.cjs,netlify.toml"]
9
+ // CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
10
+ // CIL[DOC-STABILITY stability="stable"]
11
+ // CIL[DOC-NOTE type="gotcha" content="css.postcss must reference postcss.config.cjs — the .js filename does not exist on disk."]
12
+ // CIL[END stable_id="~/config/vite.config.ts:module:config"]
13
+
5
14
  // Vite config for Spine - assembled src as working root
6
15
  export default defineConfig({
7
16
  plugins: [
8
17
  react(),
18
+ {
19
+ name: 'spa-fallback-first',
20
+ configureServer(server) {
21
+ // Runs before Vite's transform middleware. Browser navigation to an
22
+ // app route like /demo would otherwise resolve to demo/index.tsx
23
+ // (directory index) and be served as a JS module instead of the SPA.
24
+ server.middlewares.use((req, _res, next) => {
25
+ const accept = req.headers.accept || ''
26
+ const pathname = (req.url || '').split('?')[0]
27
+ if (
28
+ req.method === 'GET' &&
29
+ accept.includes('text/html') &&
30
+ !/\.[a-zA-Z0-9]+$/.test(pathname)
31
+ ) {
32
+ req.url = '/index.html'
33
+ }
34
+ next()
35
+ })
36
+ },
37
+ },
9
38
  ],
10
39
 
11
40
  // Root directory for the assembled app
@@ -70,8 +99,8 @@ export default defineConfig({
70
99
  // Environment directory (project root for .env files)
71
100
  envDir: path.resolve(__dirname, '..'),
72
101
 
73
- // PostCSS configuration
102
+ // PostCSS configuration (file on disk is postcss.config.cjs — must match exactly)
74
103
  css: {
75
- postcss: path.resolve(__dirname, 'postcss.config.js'),
104
+ postcss: path.resolve(__dirname, 'postcss.config.cjs'),
76
105
  },
77
106
  })
package/netlify.toml CHANGED
@@ -1,11 +1,11 @@
1
1
  [build]
2
- command = "npm run build"
2
+ command = "npm run assemble && npm run build"
3
3
  publish = "dist"
4
4
  functions = ".assembled/netlify/functions"
5
5
 
6
6
  [build.environment]
7
7
  # Supabase VITE variables are meant to be public in the browser
8
- SECRETS_SCAN_OMIT_KEYS = "VITE_SUPABASE_URL,VITE_SUPABASE_ANON_KEY,VITE_DB_SCHEMA,VITE_APP_NAME,VITE_ENVIRONMENT,SUPABASE_URL,DB_SCHEMA"
8
+ SECRETS_SCAN_OMIT_KEYS = "VITE_SUPABASE_URL,VITE_SUPABASE_ANON_KEY,VITE_DB_SCHEMA,VITE_APP_NAME,VITE_ENVIRONMENT,SUPABASE_URL,DB_SCHEMA,APP_BASE_URL,SITE_URL"
9
9
  SECRETS_SCAN_OMIT_PATHS = ".framework/.xenv,.framework/.xenv.test"
10
10
 
11
11
  # Spine functions configuration - assembled from .framework + custom
@@ -13,6 +13,10 @@
13
13
  directory = ".assembled/netlify/functions"
14
14
  included_files = [".assembled/netlify/functions/_shared/**"]
15
15
  node_bundler = "esbuild"
16
+ # typescript.js trips a flaky esbuild printer panic under parallel function
17
+ # bundling (cil-*, ai-agents, custom_case_analysis). Ship it unbundled —
18
+ # it's a real dependency loaded lazily at runtime.
19
+ external_node_modules = ["typescript"]
16
20
 
17
21
  [dev]
18
22
  command = "bash scripts/netlify-dev-wrapper.sh"
@@ -20,11 +24,15 @@
20
24
  port = 8888
21
25
  targetPort = 3001
22
26
  autoLaunch = false
23
- startTimeout = 60
27
+ startTimeout = 300
24
28
 
25
29
  [functions."trigger-scheduler"]
26
30
  schedule = "* * * * *"
27
31
 
32
+ # NOTE: app-specific schedules were removed — the root netlify.toml serves the
33
+ # monorepo and must stay generic. Scheduled functions belong to each app's own
34
+ # deployed Netlify config; app installers declare their own custom_* sections.
35
+
28
36
  # CIL ingestion passes are long-running — extend timeout for local dev
29
37
  # TODO: migrate to background functions for production
30
38
  [functions."cil-ingest"]
@@ -33,6 +41,21 @@
33
41
  [functions."cil-embeddings"]
34
42
  timeout = 300
35
43
 
44
+ [functions."cil-callmap"]
45
+ timeout = 60
46
+
47
+ # CIL agent can need multiple LLM tool-call rounds for broad questions
48
+ [functions."cil-agent"]
49
+ timeout = 120
50
+
51
+ # ai-agents run action drives multi-turn research steps (retrieval + tools + LLM)
52
+ [functions."ai-agents"]
53
+ timeout = 120
54
+
55
+ # kb reindex ingests an entire published corpus (batched, ~10 items in flight)
56
+ [functions."kb"]
57
+ timeout = 120
58
+
36
59
  [[redirects]]
37
60
  from = "/*"
38
61
  to = "/index.html"
@@ -47,3 +70,8 @@
47
70
  Referrer-Policy = "strict-origin-when-cross-origin"
48
71
  Permissions-Policy = "camera=(), microphone=(), geolocation=()"
49
72
  X-XSS-Protection = "1; mode=block"
73
+ # CSP: 'unsafe-inline' in script-src is required by the Vite dev
74
+ # preamble and module-preload; challenges.cloudflare.com covers
75
+ # Turnstile. Supabase needs https + wss for realtime. No
76
+ # upgrade-insecure-requests — local dev runs over plain HTTP.
77
+ Content-Security-Policy = "default-src 'self'; script-src 'self' 'unsafe-inline' https://challenges.cloudflare.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' data: https://fonts.gstatic.com; img-src 'self' data: https: blob:; connect-src 'self' https://*.supabase.co wss://*.supabase.co https://api.netlify.com https://challenges.cloudflare.com; frame-src https://challenges.cloudflare.com; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework",
3
- "version": "0.3.144",
3
+ "version": "0.4.0",
4
4
  "description": "Multi-tenant, modular application platform for modern SaaS systems",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,31 +8,40 @@
8
8
  },
9
9
  "files": [
10
10
  "bin/",
11
- "scripts/",
11
+ "scripts/assemble.sh",
12
+ "scripts/assemble-frontend.sh",
13
+ "scripts/assemble-functions.sh",
14
+ "scripts/dev-netlify.sh",
15
+ "scripts/dev-clean.sh",
16
+ "scripts/netlify-dev-wrapper.sh",
17
+ "scripts/verify-integrity.sh",
18
+ "scripts/build-manifest.sh",
19
+ "scripts/checksum-manifest.mts",
20
+ "scripts/verify-manifest.mts",
21
+ "scripts/boundary-check.sh",
22
+ "scripts/verify-install.ts",
12
23
  "config/",
24
+ "!config/*.tsbuildinfo",
25
+ "!config/deno.lock",
26
+ "!config/package-lock.json",
27
+ "templates/project/",
28
+ "vitest.config.ts",
13
29
  "netlify.toml",
14
- "spine.config.json",
15
- ".framework/cli/bin.js",
16
- ".framework/cli/",
17
- ".framework/docs/",
18
- ".framework/functions/",
19
- ".framework/migrations/*.sql",
20
- ".framework/public/",
21
- ".framework/scripts/",
22
- ".framework/seeds/",
23
- ".framework/src/",
24
- ".framework/index.html",
25
- ".framework/README.md",
26
- "custom/.devin/",
27
- "custom/README.md",
28
- "docs/APPS.md",
29
- "docs/ARCHITECTURE.md",
30
- "docs/INSTALL.md",
31
- "docs/README.md",
32
- "docs/spine-core--api-reference.md",
33
- "docs/design-schema-spec.md",
34
- "docs/dev-guides/",
35
- "docs/npm-packages-plan.md",
30
+ ".env.example",
31
+ ".framework/",
32
+ "!.framework/migrations/archive/",
33
+ "!.framework/functions/_quarantine/",
34
+ "!.framework/tests/integration/",
35
+ "!.framework/public/spine.config.json",
36
+ "!**/*.tsbuildinfo",
37
+ "!**/.DS_Store",
38
+ "!**/.env",
39
+ "!**/.env.local",
40
+ "!**/.env.production",
41
+ "!**/.env.development",
42
+ "!**/.env.test",
43
+ "!**/.xenv",
44
+ "!**/.xenv.*",
36
45
  "README.md",
37
46
  "LICENSE.md"
38
47
  ],
@@ -57,13 +66,15 @@
57
66
  "scripts": {
58
67
  "spine-framework": "tsx .framework/cli/index.ts",
59
68
  "dev": "vite --config config/vite.config.ts",
69
+ "dev:netlify": "bash scripts/dev-netlify.sh",
70
+ "dev:stop": "bash scripts/dev-clean.sh",
60
71
  "assemble": "bash scripts/assemble.sh",
61
72
  "assemble:frontend": "bash scripts/assemble-frontend.sh",
62
73
  "assemble:functions": "bash scripts/assemble-functions.sh",
63
74
  "manifest": "bash scripts/build-manifest.sh",
64
75
  "verify": "bash scripts/verify-integrity.sh",
65
76
  "prebuild": "npm run assemble && npm run verify",
66
- "build": "tsc -b config/tsconfig.json && vite build --config config/vite.config.ts",
77
+ "build": "vite build --config config/vite.config.ts",
67
78
  "preview": "vite preview --config config/vite.config.ts",
68
79
  "lint": "eslint .",
69
80
  "app-install": "tsx scripts/app-install-cli.ts",
@@ -75,12 +86,18 @@
75
86
  "test:boundary": "bash scripts/boundary-check.sh",
76
87
  "docs": "typedoc --entryPoints .framework/functions/_shared/index.ts --out docs/generated",
77
88
  "mcp": "tsx --env-file=.env .framework/mcp/index.ts",
78
- "mcp:spine-framework": "tsx --env-file=.env .framework/mcp/index.ts"
89
+ "mcp:spine-framework": "tsx --env-file=.env .framework/mcp/index.ts",
90
+ "prepack": "node custom/npm/scripts/prepack-framework.mjs stage",
91
+ "postpack": "node custom/npm/scripts/prepack-framework.mjs clean",
92
+ "cil:migrate-markers": "tsx .framework/scripts/cil-migrate-markers.ts",
93
+ "typecheck": "tsc -b config/tsconfig.json",
94
+ "typecheck:functions": "tsc --noEmit -p config/tsconfig.functions.json"
79
95
  },
80
96
  "dependencies": {
81
97
  "@base-ui/react": "^1.4.1",
82
98
  "@fontsource-variable/inter": "^5.2.8",
83
99
  "@heroicons/react": "^2.2.0",
100
+ "@marsidev/react-turnstile": "^1.1.0",
84
101
  "@radix-ui/react-accordion": "^1.2.12",
85
102
  "@radix-ui/react-avatar": "^1.1.3",
86
103
  "@radix-ui/react-dialog": "^1.1.6",
@@ -115,6 +132,7 @@
115
132
  "class-variance-authority": "^0.7.1",
116
133
  "clsx": "^2.1.1",
117
134
  "cmdk": "^1.1.1",
135
+ "commander": "^12.0.0",
118
136
  "dagre": "^0.8.5",
119
137
  "date-fns": "^4.1.0",
120
138
  "dompurify": "^3.4.13",
@@ -153,6 +171,7 @@
153
171
  "tiptap-markdown": "^0.9.0",
154
172
  "tsx": "^4.21.0",
155
173
  "tw-animate-css": "^1.4.0",
174
+ "typescript": "~5.6.2",
156
175
  "vaul": "^1.1.2",
157
176
  "ws": "^8.18.0"
158
177
  },
@@ -168,14 +187,12 @@
168
187
  "@vitejs/plugin-react": "^4.3.4",
169
188
  "ajv": "^8.12.0",
170
189
  "autoprefixer": "^10.4.20",
171
- "commander": "^12.0.0",
172
190
  "js-yaml": "^4.1.0",
191
+ "netlify-cli": "27.8.0",
173
192
  "postcss": "^8.5.1",
174
193
  "react-refresh": "^0.14.0",
175
194
  "tailwindcss": "^3.4.17",
176
- "tsx": "^4.21.0",
177
195
  "typedoc": "^0.27.0",
178
- "typescript": "~5.6.2",
179
196
  "vite": "^6.0.11",
180
197
  "vitest": "^2.1.9"
181
198
  },
@@ -1,89 +1,172 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
- # Frontend Assembly - Merge .framework/src + custom/apps/*/src → .assembled/src
3
+ # CIL[BEGIN stable_id="~/scripts/assemble-frontend.sh:module:script" type="script" identity="assemble-frontend" parent="~/scripts/assemble-frontend.sh"]
4
+ # CIL[DOC-MACRO purpose="Assemble .framework/src base layer + each custom app under .assembled/src/<app-slug>/ and merge public assets with collision detection, for the Vite build."]
5
+ # CIL[DOC-RESPONSIBILITY responsibility="Stage core src, per-app dirs (verbatim, no basename flattening), index.html path fix, _redirects, and public assets; then mtime-preserving rsync into .assembled/src and public/."]
6
+ # CIL[DOC-CONTEXT module="assembly" layer="build" related_files="scripts/assemble-functions.sh,scripts/assemble.sh,config/vite.config.ts,.framework/src/components/CustomAppLoader.tsx"]
7
+ # CIL[DOC-CONTRACT inputs=".framework/src,.framework/public,custom/apps/*,spine.config.json; env SPINE_PROJECT_ROOT (fixture override for tests)" outputs=".assembled/src + merged public/; exit 1 on public-path collision" errors="hard error naming both sources when two public assets share a relative path with different content" side_effects="rewrites .assembled/src and public/"]
8
+ # CIL[DOC-MICRO logic_summary="Temp-dir staging → core copy → per-app rsync with excludes (functions/seed/public/node_modules/dist/dotfiles) → public manifest-tracked collision check → rsync -rlc (no -t) publish." notable_decisions="identical duplicate public assets skip silently; root spine.config.json wins over framework template; no .gitkeep rsync exclude so --delete can remove stale dirs"]
9
+ # CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
10
+ # CIL[DOC-STABILITY stability="stable"]
11
+ # CIL[DOC-NOTE type="invariant" content="import.meta.glob('../../../custom/apps/*/index.tsx') in CustomAppLoader must keep resolving — app dirs are copied verbatim under src/<slug>/, never flattened by basename."]
12
+ # CIL[END stable_id="~/scripts/assemble-frontend.sh:module:script"]
13
+
14
+ # Frontend Assembly - Merge .framework/src + custom/apps/* → .assembled/src
4
15
  #
5
16
  # Purpose: Create unified frontend source directory for Vite build process.
6
- # - .framework/src is the canonical Spine frontend
7
- # - custom/apps/*/src are your application sources
8
- # - Vite expects a single src directory, so we assemble at build time
17
+ # - .framework/src is the canonical Spine frontend (base layer at root)
18
+ # - each custom/apps/<app> is copied to .assembled/src/<app-slug>/ VERBATIM —
19
+ # no basename flattening (two apps' components/ must never merge silently)
20
+ # - custom app index resolution uses import.meta.glob('../../../custom/apps/*/index.tsx')
21
+ # in .framework/src/components/CustomAppLoader.tsx — assembled app dirs exist
22
+ # for @/(@core)-style imports and layout consistency, not for the glob
9
23
  #
10
24
  # Process:
11
- # 1. Clean target directory
12
- # 2. Copy core src files
13
- # 3. Overlay custom src files (overwrites existing)
25
+ # 1. Assemble into temp directory first
26
+ # 2. Copy core src files (base layer)
27
+ # 3. Copy each app to <app-slug>/, excluding functions/, seed/, public/,
28
+ # node_modules, dist, and dotfiles
29
+ # 4. Merge public assets with same-relative-path collision detection
30
+ # 5. rsync -c into target so unchanged files keep their mtimes — Vite then only
31
+ # reloads modules that actually changed instead of every file
32
+ #
33
+ # SPINE_PROJECT_ROOT (optional): override the project root — used by the
34
+ # fixture-based unit tests; production use leaves it unset.
14
35
  #
15
- # Dependencies: standard bash utilities, find, cp, rsync
36
+ # Dependencies: standard bash utilities, find, cp, rsync, cmp
16
37
 
17
38
  set -euo pipefail
18
39
 
19
40
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
20
- PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
41
+ # Canonicalize (-P resolves symlinks) — consistent with assemble-functions.sh
42
+ # and safe when the repo itself is reached through a symlinked path.
43
+ PROJECT_ROOT="$(cd "${SPINE_PROJECT_ROOT:-$(dirname "$SCRIPT_DIR")}" && pwd -P)"
21
44
 
22
45
  CORE_SRC_DIR="$PROJECT_ROOT/.framework/src"
23
46
  CUSTOM_SRC_DIR="$PROJECT_ROOT/custom/apps"
24
47
  TARGET_SRC_DIR="$PROJECT_ROOT/.assembled/src"
48
+ VITE_PUBLIC_DIR="$PROJECT_ROOT/public"
49
+ TMP_ROOT="$PROJECT_ROOT/.frontend-assemble-tmp"
50
+ TMP_SRC_DIR="$TMP_ROOT/src"
51
+ TMP_PUBLIC_DIR="$TMP_ROOT/public"
52
+ # rel-path → source-file map for public-asset collision errors
53
+ PUBLIC_MANIFEST="$TMP_ROOT/public-manifest.tsv"
25
54
 
26
55
  echo "🔧 Assembling frontend → $TARGET_SRC_DIR"
27
56
 
28
- # 1. Clean target (except .gitkeep if exists)
29
- if [ -d "$TARGET_SRC_DIR" ]; then
30
- find "$TARGET_SRC_DIR" -mindepth 1 -not -name '.gitkeep' -delete 2>/dev/null || true
31
- else
32
- mkdir -p "$TARGET_SRC_DIR"
33
- fi
57
+ # 1. Stage into temp dir
58
+ rm -rf "$TMP_ROOT"
59
+ mkdir -p "$TMP_SRC_DIR" "$TMP_PUBLIC_DIR"
60
+ : > "$PUBLIC_MANIFEST"
34
61
 
35
62
  # 2. Copy core src (base layer)
36
63
  if [ -d "$CORE_SRC_DIR" ]; then
37
- # Ensure subdirectories are copied properly
38
- cp -r "$CORE_SRC_DIR"/* "$TARGET_SRC_DIR"/ 2>/dev/null || true
64
+ cp -r "$CORE_SRC_DIR"/* "$TMP_SRC_DIR"/ 2>/dev/null || true
39
65
  echo " ✓ Core: $(find "$CORE_SRC_DIR" -name '*.tsx' -o -name '*.ts' -o -name '*.css' | wc -l | tr -d ' ') files"
40
66
  else
41
67
  echo " ⚠ Core: $CORE_SRC_DIR not found"
42
68
  fi
43
69
 
44
- # 4. Copy public files from .framework
70
+ # 3. Copy index.html, fixing the script src path for assembled structure
45
71
  if [ -f "$PROJECT_ROOT/.framework/index.html" ]; then
46
- # Copy and fix the script src path for assembled structure
47
- sed 's|/src/main.tsx|./main.tsx|g' "$PROJECT_ROOT/.framework/index.html" > "$TARGET_SRC_DIR/index.html"
72
+ sed 's|/src/main.tsx|./main.tsx|g' "$PROJECT_ROOT/.framework/index.html" > "$TMP_SRC_DIR/index.html"
48
73
  echo " ✓ Core: index.html (paths fixed)"
49
74
  fi
50
75
 
51
- # 3. Copy public assets from .framework
52
- # Vite's publicDir is set to PROJECT_ROOT/public (i.e. ../public relative to .assembled/src)
53
- # so static files must go there to be served at the root URL
54
- VITE_PUBLIC_DIR="$PROJECT_ROOT/public"
76
+ # 4. Stage a public-asset source dir into TMP_PUBLIC_DIR with collision
77
+ # detection. The SAME relative path may never come from two different sources:
78
+ # - identical content → skip silently (duplicate copy is harmless)
79
+ # - differing content → hard error naming both source files
80
+ stage_public_dir() {
81
+ local src_dir="$1"
82
+ local f rel staged prev
83
+ while IFS= read -r -d '' f; do
84
+ rel="${f#"$src_dir"/}"
85
+ staged="$TMP_PUBLIC_DIR/$rel"
86
+ if [ -e "$staged" ]; then
87
+ if cmp -s "$f" "$staged"; then
88
+ continue
89
+ fi
90
+ prev="$(awk -F '\t' -v r="$rel" '$1 == r { print $2; exit }' "$PUBLIC_MANIFEST")"
91
+ echo " ✗ Public asset collision: '$rel' is provided by both" >&2
92
+ echo " - $prev" >&2
93
+ echo " - $f" >&2
94
+ echo " Rename one of them — public/ merges flat, last-wins is forbidden." >&2
95
+ exit 1
96
+ fi
97
+ mkdir -p "$(dirname "$staged")"
98
+ cp "$f" "$staged"
99
+ printf '%s\t%s\n' "$rel" "$f" >> "$PUBLIC_MANIFEST"
100
+ done < <(find "$src_dir" -type f ! -name '.*' -print0 | sort -z)
101
+ }
102
+
103
+ # 5. Framework public assets merge first — Vite's publicDir is
104
+ # PROJECT_ROOT/public, so static files must land there to be served at root URL
55
105
  if [ -d "$PROJECT_ROOT/.framework/public" ]; then
56
- mkdir -p "$VITE_PUBLIC_DIR"
57
- cp -r "$PROJECT_ROOT/.framework/public"/* "$VITE_PUBLIC_DIR/" 2>/dev/null || true
106
+ stage_public_dir "$PROJECT_ROOT/.framework/public"
58
107
  echo " ✓ Core: $(find "$PROJECT_ROOT/.framework/public" -type f | wc -l | tr -d ' ') public files"
59
108
  fi
60
109
 
61
- # 3.5. Copy _redirects to Vite-served root for Netlify dev (served from .assembled/src root)
110
+ # 6. Copy _redirects to Vite-served root for Netlify dev (served from .assembled/src root)
62
111
  if [ -f "$PROJECT_ROOT/.framework/public/_redirects" ]; then
63
- cp "$PROJECT_ROOT/.framework/public/_redirects" "$TARGET_SRC_DIR/_redirects"
112
+ cp "$PROJECT_ROOT/.framework/public/_redirects" "$TMP_SRC_DIR/_redirects"
64
113
  echo " ✓ Core: _redirects copied to Vite-served directory for Netlify dev"
65
114
  fi
66
115
 
67
- # 3.6. Copy spine.config.json to Vite publicDir so it's served at /spine.config.json
116
+ # 7. Per-app copy: custom/apps/<app> → .assembled/src/<app-slug>/ verbatim.
117
+ # Excluded: functions (goes to .assembled/netlify/functions), seed, public
118
+ # (merged into /public above), node_modules, dist, dotfiles.
119
+ CUSTOM_COUNT=0
120
+ if [ -d "$CUSTOM_SRC_DIR" ]; then
121
+ for app_dir in "$CUSTOM_SRC_DIR"/*/; do
122
+ [ -d "$app_dir" ] || continue
123
+ slug="$(basename "$app_dir")"
124
+
125
+ rsync -a \
126
+ --exclude='functions' \
127
+ --exclude='seed' \
128
+ --exclude='public' \
129
+ --exclude='node_modules' \
130
+ --exclude='dist' \
131
+ --exclude='.*' \
132
+ "$app_dir" "$TMP_SRC_DIR/$slug/"
133
+
134
+ # App public assets merge into /public AFTER framework public; a same
135
+ # relative path in two sources (or vs framework) is a hard error above.
136
+ if [ -d "$app_dir/public" ]; then
137
+ stage_public_dir "$app_dir/public"
138
+ fi
139
+
140
+ app_count=$(find "$TMP_SRC_DIR/$slug" -name '*.tsx' -o -name '*.ts' -o -name '*.css' 2>/dev/null | wc -l | tr -d ' ')
141
+ CUSTOM_COUNT=$((CUSTOM_COUNT + app_count))
142
+ echo " ✓ $slug: $app_count files → src/$slug/"
143
+ done
144
+ fi
145
+ if [ "$CUSTOM_COUNT" -eq 0 ]; then
146
+ echo " ○ Custom: (empty)"
147
+ fi
148
+
149
+ # 8. spine.config.json → staged public (root config, served at /spine.config.json).
150
+ # The ROOT copy is the instance config and intentionally wins over the
151
+ # framework template of the same name (framework/public/spine.config.json).
68
152
  if [ -f "$PROJECT_ROOT/spine.config.json" ]; then
69
- mkdir -p "$VITE_PUBLIC_DIR"
70
- cp "$PROJECT_ROOT/spine.config.json" "$VITE_PUBLIC_DIR/spine.config.json"
153
+ cp -f "$PROJECT_ROOT/spine.config.json" "$TMP_PUBLIC_DIR/spine.config.json"
71
154
  echo " ✓ Config: spine.config.json copied to public/"
72
155
  fi
73
156
 
74
- # 6. Overlay custom src (overrides + additions)
75
- if [ -d "$CUSTOM_SRC_DIR" ]; then
76
- # Copy files and subdirectories
77
- cp -r "$CUSTOM_SRC_DIR"/* "$TARGET_SRC_DIR"/ 2>/dev/null || true
78
-
79
- # Handle subdirectories properly
80
- find "$CUSTOM_SRC_DIR" -mindepth 1 -type d -exec sh -c 'dir="$1"; base=$(basename "$dir"); mkdir -p "'"$TARGET_SRC_DIR"'/$base" && cp -r "$dir"/* "'"$TARGET_SRC_DIR"'/$base/"' _ {} \; 2>/dev/null || true
81
-
82
- CUSTOM_COUNT=$(find "$CUSTOM_SRC_DIR" -name '*.tsx' -o -name '*.ts' -o -name '*.css' 2>/dev/null | wc -l | tr -d ' ')
83
- echo " ✓ Custom: $CUSTOM_COUNT files"
84
- else
85
- echo " ○ Custom: (empty)"
86
- fi
157
+ # 9. Publish staged public assets. -c compares content checksums; deliberately
158
+ # NO -t so unchanged files keep mtimes (see final sync note below).
159
+ mkdir -p "$VITE_PUBLIC_DIR"
160
+ rsync -rlc "$TMP_PUBLIC_DIR"/ "$VITE_PUBLIC_DIR"/
161
+
162
+ # 10. Sync temp into place. -c compares content checksums; deliberately NO -t —
163
+ # otherwise rsync "corrects" mtimes of unchanged files to the fresh temp-copy
164
+ # time and Vite reloads the entire module graph on every assemble.
165
+ mkdir -p "$TARGET_SRC_DIR"
166
+ # No .gitkeep exclusion: .assembled/ is gitignored, and leftover .gitkeep
167
+ # files inside stale dirs would make --delete treat them as non-empty.
168
+ rsync -rlc --delete "$TMP_SRC_DIR"/ "$TARGET_SRC_DIR"/
169
+ rm -rf "$TMP_ROOT"
87
170
 
88
171
  echo " ✓ Assembled: $(find "$TARGET_SRC_DIR" -name '*.tsx' -o -name '*.ts' -o -name '*.css' | wc -l | tr -d ' ') total files"
89
172
  echo "✅ Done"