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,69 +1,33 @@
1
1
  #!/usr/bin/env bash
2
- #
3
- # Core Integrity Verifier - Verify core files against the build manifest.
4
- # SPINE_INTEGRITY=warn → log warnings (default, dev-friendly)
5
- # SPINE_INTEGRITY=enforce → fail build on mismatch
2
+ # CIL[BEGIN stable_id="~/.framework/scripts/verify-integrity.sh:module:script" type="script" identity="verify-integrity" parent="~/.framework/scripts/verify-integrity.sh"]
3
+ # CIL[DOC-MACRO purpose="Thin wrapper that verifies protected trees against .spine-manifest.json via scripts/verify-manifest.mts"]
4
+ # CIL[DOC-RESPONSIBILITY responsibility="Map SPINE_INTEGRITY to verifier flags and invoke the Node verifier; fail closed by default"]
5
+ # CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/verify-manifest.mts,scripts/build-manifest.sh,scripts/check-core-integrity.sh,package.json"]
6
+ # CIL[DOC-CONTRACT inputs="SPINE_INTEGRITY=warn|enforce (default enforce); passthrough args" outputs="exit 0 pass / exit 1 integrity failure" errors="exit 1 on missing tsx or verifier failure" side_effects="stdout/stderr report"]
7
+ # CIL[DOC-MICRO logic_summary="SPINE_INTEGRITY=warn passes --warn; the verifier itself ignores --warn when the manifest is frozen" notable_decisions="default is enforce — fail-closed — unlike the legacy warn-by-default script"]
8
+ # CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
9
+ # CIL[DOC-STABILITY stability="stable"]
10
+ # CIL[DOC-AUDIENCE audience="system-admin"]
11
+ # CIL[DOC-VECTOR type="context" content="Invoked by npm run verify and the retired check-core-integrity.sh shim"]
12
+ # CIL[DOC-VECTOR type="implementation_pattern" content="Sibling thin wrapper of build-manifest.sh; real logic in scripts/verify-manifest.mts" status="ready"]
13
+ # CIL[END stable_id="~/.framework/scripts/verify-integrity.sh:module:script"]
6
14
 
7
15
  set -euo pipefail
8
16
 
9
17
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
18
  PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
11
- MANIFEST_FILE="$PROJECT_ROOT/.spine-manifest.json"
12
19
 
13
- INTEGRITY_MODE="${SPINE_INTEGRITY:-warn}"
20
+ INTEGRITY_MODE="${SPINE_INTEGRITY:-enforce}"
21
+ echo "🔒 Verifying spine integrity (mode: $INTEGRITY_MODE)"
14
22
 
15
- if [ ! -f "$MANIFEST_FILE" ]; then
16
- echo "⚠️ No manifest found at $MANIFEST_FILE — run build-manifest.sh first"
17
- if [ "$INTEGRITY_MODE" = "enforce" ]; then exit 1; fi
18
- exit 0
19
- fi
20
-
21
- echo "🔒 Verifying core integrity (mode: $INTEGRITY_MODE)"
22
-
23
- MISMATCHES=0
24
- MISSING=0
25
-
26
- # Parse each file:hash pair from manifest
27
- while IFS=: read -r file_path expected_hash; do
28
- # Strip quotes and whitespace
29
- file_path=$(echo "$file_path" | tr -d '"' | xargs)
30
- expected_hash=$(echo "$expected_hash" | tr -d '"' | xargs)
31
-
32
- FULL_PATH="$PROJECT_ROOT/$file_path"
33
-
34
- if [ ! -f "$FULL_PATH" ]; then
35
- echo " ✗ MISSING: $file_path"
36
- MISSING=$((MISSING + 1))
37
- continue
38
- fi
39
-
40
- ACTUAL_HASH=$(shasum -a 256 "$FULL_PATH" | cut -d' ' -f1)
41
-
42
- if [ "$ACTUAL_HASH" != "$expected_hash" ]; then
43
- echo " ✗ MODIFIED: $file_path"
44
- MISMATCHES=$((MISMATCHES + 1))
45
- fi
46
- done < <(cat "$MANIFEST_FILE" | python3 -c "
47
- import json, sys
48
- data = json.load(sys.stdin)
49
- for k, v in data.get('hashes', {}).items():
50
- print(f'{k}:{v}')
51
- " 2>/dev/null || echo "")
52
-
53
- TOTAL=$((MISMATCHES + MISSING))
54
-
55
- if [ "$TOTAL" -eq 0 ]; then
56
- echo "✅ All core files match manifest"
57
- exit 0
23
+ TSX="$PROJECT_ROOT/node_modules/.bin/tsx"
24
+ if [ ! -x "$TSX" ]; then
25
+ echo "❌ tsx not found at $TSX — run 'npm install' first" >&2
26
+ exit 1
58
27
  fi
59
28
 
60
- echo ""
61
- echo "⚠️ $MISMATCHES modified, $MISSING missing ($TOTAL total issues)"
62
-
63
- if [ "$INTEGRITY_MODE" = "enforce" ]; then
64
- echo "❌ Build failed: core integrity check failed (SPINE_INTEGRITY=enforce)"
65
- exit 1
29
+ if [ "$INTEGRITY_MODE" = "warn" ]; then
30
+ "$TSX" "$SCRIPT_DIR/verify-manifest.mts" "$PROJECT_ROOT" --warn "$@"
66
31
  else
67
- echo "⚠️ Continuing with warnings (SPINE_INTEGRITY=warn)"
68
- exit 0
32
+ "$TSX" "$SCRIPT_DIR/verify-manifest.mts" "$PROJECT_ROOT" "$@"
69
33
  fi
@@ -0,0 +1,305 @@
1
+ // CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/scripts/verify-manifest.mts"]
2
+ // CIL[DOC-MACRO purpose="Fail-closed verifier for .spine-manifest.json — detects missing, modified, and extra files in protected trees"]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Parse the manifest, re-hash every listed path, confine symlinks to the root, and flag unlisted additions; exit 1 with an itemized failure list"]
4
+ // CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/checksum-manifest.mts,scripts/verify-integrity.sh,scripts/check-core-integrity.sh"]
5
+ // CIL[DOC-CONTRACT inputs="argv: <root> [--warn]" outputs="exit 0 pass / exit 1 with itemized failures (or 0 when --warn and manifest is not frozen)" errors="exit 1 on missing/malformed/empty manifest" side_effects="stdout/stderr report"]
6
+ // CIL[DOC-MICRO logic_summary="Shares enumeration and hashing with checksum-manifest.mts so generated and verified views can never drift" notable_decisions="frozen manifests ignore --warn entirely — warn mode is for dev regeneration only, never for frozen exports"]
7
+ // CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
8
+ // CIL[DOC-STABILITY stability="stable"]
9
+ // CIL[DOC-AUDIENCE audience="system-admin"]
10
+ // CIL[DOC-NOTE type="design" content="Extra-file check unions PROTECTED_DIRS with the top-level dirs actually present in the manifest so manifests generated with --include-dir still verify correctly"]
11
+ // CIL[DOC-VECTOR type="context" content="Invoked by npm run verify (scripts/verify-integrity.sh) and the retired scripts/check-core-integrity.sh shim"]
12
+ // CIL[DOC-VECTOR type="implementation_pattern" content="Imports collectProtectedFiles/hashEntry/topLevelDir from ./checksum-manifest.mts" status="ready"]
13
+ // CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:module_header:module_header"]
14
+
15
+ import * as fs from 'node:fs'
16
+ import * as path from 'node:path'
17
+ import {
18
+ PROTECTED_DIRS,
19
+ collectProtectedFiles,
20
+ computeTreeDigest,
21
+ hashEntry,
22
+ topLevelDir,
23
+ } from './checksum-manifest.mts'
24
+
25
+ // CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:Failure:interface" type="interface" identity="Failure" parent="~/.framework/scripts/verify-manifest.mts"]
26
+ // CIL[DOC-MACRO purpose="One itemized integrity failure"]
27
+ // CIL[DOC-RESPONSIBILITY responsibility="Carry a failure kind plus the manifest-relative path it concerns"]
28
+ // CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/verify-manifest.mts"]
29
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
30
+ // CIL[DOC-MICRO logic_summary="kind is one of MISSING, MODIFIED, EXTRA, UNSAFE_SYMLINK, TYPE_CHANGED, MALFORMED_ENTRY, MANIFEST_DIGEST_MISMATCH" notable_decisions="kept as a tagged union string so printing stays trivially itemizable"]
31
+ // CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
32
+ // CIL[DOC-STABILITY stability="stable"]
33
+ interface Failure {
34
+ kind:
35
+ | 'MISSING'
36
+ | 'MODIFIED'
37
+ | 'EXTRA'
38
+ | 'UNSAFE_SYMLINK'
39
+ | 'TYPE_CHANGED'
40
+ | 'MALFORMED_ENTRY'
41
+ | 'MANIFEST_DIGEST_MISMATCH'
42
+ rel: string
43
+ }
44
+ // CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:Failure:interface"]
45
+
46
+ // CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:HASH_RE:constant" type="constant" identity="HASH_RE" parent="~/.framework/scripts/verify-manifest.mts"]
47
+ // CIL[DOC-MACRO purpose="Strict shape for manifest hash values"]
48
+ // CIL[DOC-RESPONSIBILITY responsibility="Reject malformed 'sha256:<64 hex>' entries before comparing"]
49
+ // CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/checksum-manifest.mts"]
50
+ // CIL[DOC-CONTRACT inputs="none" outputs="RegExp" errors="none" side_effects="none"]
51
+ // CIL[DOC-MICRO logic_summary="Lowercase hex only — matches what node:crypto sha256 digest produces" notable_decisions="manifest is machine-generated; strictness catches hand edits"]
52
+ // CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
53
+ // CIL[DOC-STABILITY stability="stable"]
54
+ const HASH_RE = /^sha256:[0-9a-f]{64}$/
55
+ // CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:HASH_RE:constant"]
56
+
57
+ // CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:isInsideRoot:function" type="function" identity="isInsideRoot" parent="~/.framework/scripts/verify-manifest.mts"]
58
+ // CIL[DOC-MACRO purpose="Confinement check — is a resolved path still inside the root?"]
59
+ // CIL[DOC-RESPONSIBILITY responsibility="Return true when the resolved real path equals the root or sits beneath it"]
60
+ // CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/verify-manifest.mts"]
61
+ // CIL[DOC-CONTRACT inputs="rootAbs, resolved absolute path" outputs="boolean" errors="none" side_effects="none"]
62
+ // CIL[DOC-MICRO logic_summary="path.relative trick: outside paths yield '..' prefixes or absolute results" notable_decisions="boundary-safe — a sibling dir sharing a prefix like /root-evil does not pass"]
63
+ // CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
64
+ // CIL[DOC-STABILITY stability="stable"]
65
+ function isInsideRoot(rootAbs: string, resolved: string): boolean {
66
+ const rel = path.relative(rootAbs, resolved)
67
+ return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel))
68
+ }
69
+ // CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:isInsideRoot:function"]
70
+
71
+ // CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:loadManifest:function" type="function" identity="loadManifest" parent="~/.framework/scripts/verify-manifest.mts"]
72
+ // CIL[DOC-MACRO purpose="Read and structurally validate .spine-manifest.json"]
73
+ // CIL[DOC-RESPONSIBILITY responsibility="Fail closed on missing, unreadable, non-JSON, empty, or wrong-format manifest; return the parsed files map"]
74
+ // CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/checksum-manifest.mts"]
75
+ // CIL[DOC-CONTRACT inputs="manifestPath: absolute path" outputs="{ manifest, files } — parsed manifest plus its files record" errors="prints reason and exits 1 on any defect" side_effects="reads manifest file"]
76
+ // CIL[DOC-MICRO logic_summary="Structural checks: object root, format_version === 1, files is a non-empty object" notable_decisions="an empty files map is treated as malformed — a manifest that protects nothing is not a manifest"]
77
+ // CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
78
+ // CIL[DOC-STABILITY stability="stable"]
79
+ function loadManifest(manifestPath: string): { manifest: Record<string, unknown>; files: Record<string, string> } {
80
+ if (!fs.existsSync(manifestPath)) {
81
+ console.error(`❌ manifest not found: ${manifestPath}`)
82
+ console.error(' run npm run manifest to generate it')
83
+ process.exit(1)
84
+ }
85
+
86
+ let raw: string
87
+ try {
88
+ raw = fs.readFileSync(manifestPath, 'utf8')
89
+ } catch (err) {
90
+ console.error(`❌ manifest unreadable: ${(err as Error).message}`)
91
+ process.exit(1)
92
+ }
93
+
94
+ if (raw.trim() === '') {
95
+ console.error(`❌ manifest is empty: ${manifestPath}`)
96
+ process.exit(1)
97
+ }
98
+
99
+ let manifest: Record<string, unknown>
100
+ try {
101
+ manifest = JSON.parse(raw)
102
+ } catch (err) {
103
+ console.error(`❌ manifest is not valid JSON: ${(err as Error).message}`)
104
+ process.exit(1)
105
+ }
106
+
107
+ if (manifest === null || typeof manifest !== 'object' || Array.isArray(manifest)) {
108
+ console.error('❌ manifest root is not an object')
109
+ process.exit(1)
110
+ }
111
+
112
+ if (manifest.format_version !== 1) {
113
+ console.error(`❌ unknown manifest format_version: ${JSON.stringify(manifest.format_version)} (expected 1)`)
114
+ process.exit(1)
115
+ }
116
+
117
+ const files = manifest.files
118
+ if (files === null || typeof files !== 'object' || Array.isArray(files) || Object.keys(files).length === 0) {
119
+ console.error('❌ manifest declares no files — nothing to verify')
120
+ process.exit(1)
121
+ }
122
+
123
+ return { manifest, files: files as Record<string, string> }
124
+ }
125
+ // CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:loadManifest:function"]
126
+
127
+ // CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:verifyListedFiles:function" type="function" identity="verifyListedFiles" parent="~/.framework/scripts/verify-manifest.mts"]
128
+ // CIL[DOC-MACRO purpose="Re-hash every manifest-listed path and classify failures"]
129
+ // CIL[DOC-RESPONSIBILITY responsibility="Check each listed path exists, is confined to the root when a symlink, and still matches its stored sha256"]
130
+ // CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/checksum-manifest.mts"]
131
+ // CIL[DOC-CONTRACT inputs="rootAbs, files map" outputs="Failure[]" errors="none — failures collected, not thrown" side_effects="reads every listed file"]
132
+ // CIL[DOC-MICRO logic_summary="lstat distinguishes symlink/file/dir; symlink targets are realpath'd and confined; type changes count as failures" notable_decisions="hash order follows byte-sorted keys for a stable, greppable report"]
133
+ // CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
134
+ // CIL[DOC-STABILITY stability="stable"]
135
+ function verifyListedFiles(rootAbs: string, files: Record<string, string>): Failure[] {
136
+ const failures: Failure[] = []
137
+ const rels = Object.keys(files).sort((a, b) =>
138
+ Buffer.compare(Buffer.from(a, 'utf8'), Buffer.from(b, 'utf8')),
139
+ )
140
+
141
+ for (const rel of rels) {
142
+ const expected = files[rel]
143
+ const abs = path.join(rootAbs, rel)
144
+
145
+ if (!HASH_RE.test(expected)) {
146
+ failures.push({ kind: 'MALFORMED_ENTRY', rel })
147
+ continue
148
+ }
149
+
150
+ let st: fs.Stats
151
+ try {
152
+ st = fs.lstatSync(abs)
153
+ } catch {
154
+ failures.push({ kind: 'MISSING', rel })
155
+ continue
156
+ }
157
+
158
+ if (st.isSymbolicLink()) {
159
+ let resolved: string
160
+ try {
161
+ resolved = fs.realpathSync(abs)
162
+ } catch {
163
+ failures.push({ kind: 'UNSAFE_SYMLINK', rel })
164
+ continue
165
+ }
166
+ if (!isInsideRoot(rootAbs, resolved)) {
167
+ failures.push({ kind: 'UNSAFE_SYMLINK', rel })
168
+ continue
169
+ }
170
+ if (hashEntry({ rel, abs, symlink: true }) !== expected) {
171
+ failures.push({ kind: 'MODIFIED', rel })
172
+ }
173
+ continue
174
+ }
175
+
176
+ if (!st.isFile()) {
177
+ failures.push({ kind: 'TYPE_CHANGED', rel })
178
+ continue
179
+ }
180
+
181
+ if (hashEntry({ rel, abs, symlink: false }) !== expected) {
182
+ failures.push({ kind: 'MODIFIED', rel })
183
+ }
184
+ }
185
+
186
+ return failures
187
+ }
188
+ // CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:verifyListedFiles:function"]
189
+
190
+ // CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:findExtraFiles:function" type="function" identity="findExtraFiles" parent="~/.framework/scripts/verify-manifest.mts"]
191
+ // CIL[DOC-MACRO purpose="Reject unlisted additions inside protected trees"]
192
+ // CIL[DOC-RESPONSIBILITY responsibility="Enumerate the same trees the generator covered (defaults plus any top-level dirs present in the manifest) and flag anything not in the files map"]
193
+ // CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/checksum-manifest.mts"]
194
+ // CIL[DOC-CONTRACT inputs="rootAbs, manifestRel, files map" outputs="Failure[]" errors="none" side_effects="reads filesystem"]
195
+ // CIL[DOC-MICRO logic_summary="Shared collectProtectedFiles keeps exclusion rules identical between generate and verify; the manifest's own path is excluded" notable_decisions="manifest top-level dirs are unioned in so --include-dir manifests verify without extra flags"]
196
+ // CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
197
+ // CIL[DOC-STABILITY stability="stable"]
198
+ function findExtraFiles(rootAbs: string, manifestRel: string, files: Record<string, string>): Failure[] {
199
+ const trees = new Set<string>(PROTECTED_DIRS)
200
+ for (const rel of Object.keys(files)) {
201
+ const top = topLevelDir(rel)
202
+ if (top) trees.add(top)
203
+ }
204
+
205
+ const extraDirs = [...trees].filter((d) => !PROTECTED_DIRS.includes(d))
206
+ const present = collectProtectedFiles(rootAbs, extraDirs, new Set([manifestRel]))
207
+
208
+ const failures: Failure[] = []
209
+ for (const entry of present) {
210
+ if (!(entry.rel in files)) failures.push({ kind: 'EXTRA', rel: entry.rel })
211
+ }
212
+ return failures
213
+ }
214
+ // CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:findExtraFiles:function"]
215
+
216
+ // CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:main:function" type="function" identity="main" parent="~/.framework/scripts/verify-manifest.mts"]
217
+ // CIL[DOC-MACRO purpose="CLI entry — load manifest, run all checks, print itemized report"]
218
+ // CIL[DOC-RESPONSIBILITY responsibility="Wire parsing, digest consistency, listed-file verification, and extra-file detection; map --warn vs frozen to exit codes"]
219
+ // CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/verify-integrity.sh,package.json"]
220
+ // CIL[DOC-CONTRACT inputs="argv: <root> [--warn]" outputs="exit 0 pass; exit 1 on failures (exit 0 with warnings only when --warn AND frozen !== true)" errors="exit 1 hard on manifest defects" side_effects="stdout report"]
221
+ // CIL[DOC-MICRO logic_summary="frozen:true ignores --warn entirely per plan G15 — frozen exports may never downgrade a failure to a warning" notable_decisions="tree_digest is recomputed for self-consistency; mismatch means the files map was edited after generation"]
222
+ // CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
223
+ // CIL[DOC-STABILITY stability="stable"]
224
+ function main(): void {
225
+ const args = process.argv.slice(2)
226
+ const positional: string[] = []
227
+ let warnRequested = false
228
+
229
+ for (const arg of args) {
230
+ if (arg === '--warn') {
231
+ warnRequested = true
232
+ } else if (arg.startsWith('--')) {
233
+ console.error(`verify-manifest: unknown flag ${arg}`)
234
+ process.exit(2)
235
+ } else {
236
+ positional.push(arg)
237
+ }
238
+ }
239
+
240
+ if (positional.length !== 1) {
241
+ console.error('usage: verify-manifest.mts <root> [--warn]')
242
+ process.exit(2)
243
+ }
244
+
245
+ const root = path.resolve(positional[0])
246
+ const manifestRel = '.spine-manifest.json'
247
+ const { manifest, files } = loadManifest(path.join(root, manifestRel))
248
+ const frozen = manifest.frozen === true
249
+ const warnEffective = warnRequested && !frozen
250
+
251
+ console.log(`🔒 Verifying spine integrity (frozen: ${frozen}, warn: ${warnEffective})`)
252
+
253
+ const failures: Failure[] = []
254
+
255
+ // Self-consistency: tree_digest must match a recompute over the files map.
256
+ if (typeof manifest.tree_digest === 'string') {
257
+ const pairs = Object.keys(files)
258
+ .sort((a, b) => Buffer.compare(Buffer.from(a, 'utf8'), Buffer.from(b, 'utf8')))
259
+ .map((rel) => [rel, files[rel]] as const)
260
+ if (computeTreeDigest(pairs) !== manifest.tree_digest) {
261
+ failures.push({ kind: 'MANIFEST_DIGEST_MISMATCH', rel: manifestRel })
262
+ }
263
+ }
264
+
265
+ const rootAbs = path.resolve(root)
266
+ failures.push(...verifyListedFiles(rootAbs, files))
267
+ failures.push(...findExtraFiles(rootAbs, manifestRel, files))
268
+
269
+ if (failures.length === 0) {
270
+ console.log(`✅ All ${Object.keys(files).length} protected files match manifest`)
271
+ process.exit(0)
272
+ }
273
+
274
+ for (const f of failures) {
275
+ const detail =
276
+ f.kind === 'MISSING'
277
+ ? 'listed in manifest but not on disk'
278
+ : f.kind === 'MODIFIED'
279
+ ? 'hash mismatch — file changed since manifest was generated'
280
+ : f.kind === 'EXTRA'
281
+ ? 'present in protected tree but not listed in manifest'
282
+ : f.kind === 'UNSAFE_SYMLINK'
283
+ ? 'symlink target escapes the project root'
284
+ : f.kind === 'TYPE_CHANGED'
285
+ ? 'path exists but is no longer a regular file'
286
+ : f.kind === 'MALFORMED_ENTRY'
287
+ ? 'manifest hash value is not sha256:<64 hex>'
288
+ : 'tree_digest does not match the files map'
289
+ console.error(` ✗ ${f.kind}: ${f.rel} — ${detail}`)
290
+ }
291
+
292
+ console.error(`\n❌ ${failures.length} integrity failure(s)`)
293
+
294
+ if (warnEffective) {
295
+ console.error('⚠️ continuing with warnings (SPINE_INTEGRITY=warn, manifest not frozen)')
296
+ process.exit(0)
297
+ }
298
+ if (warnRequested && frozen) {
299
+ console.error(' (frozen manifest — --warn ignored)')
300
+ }
301
+ process.exit(1)
302
+ }
303
+ // CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:main:function"]
304
+
305
+ main()
@@ -15,13 +15,19 @@
15
15
  "data_type": "select",
16
16
  "label": "Source",
17
17
  "required": true,
18
- "options": ["use"]
18
+ "options": [
19
+ "use"
20
+ ]
19
21
  },
20
22
  "stage": {
21
23
  "data_type": "select",
22
24
  "label": "Stage",
23
25
  "required": true,
24
- "options": ["installed", "claimed", "active"]
26
+ "options": [
27
+ "installed",
28
+ "claimed",
29
+ "active"
30
+ ]
25
31
  },
26
32
  "action_type": {
27
33
  "data_type": "text",
@@ -39,10 +45,9 @@
39
45
  "required": true
40
46
  },
41
47
  "app_slug": {
42
- "data_type": "select",
48
+ "data_type": "text",
43
49
  "label": "App",
44
- "required": false,
45
- "options": ["framework", "cortex", "portal"]
50
+ "required": false
46
51
  },
47
52
  "app_version": {
48
53
  "data_type": "text",
@@ -56,11 +61,26 @@
56
61
  "display": "table",
57
62
  "label": "Usage Signals",
58
63
  "fields": {
59
- "title": { "sortable": true, "display_type": "text" },
60
- "action_type": { "sortable": true, "display_type": "badge" },
61
- "stage": { "sortable": true, "display_type": "badge" },
62
- "serial": { "sortable": true, "display_type": "text" },
63
- "created_at": { "sortable": true, "display_type": "timestamp" }
64
+ "title": {
65
+ "sortable": true,
66
+ "display_type": "text"
67
+ },
68
+ "action_type": {
69
+ "sortable": true,
70
+ "display_type": "badge"
71
+ },
72
+ "stage": {
73
+ "sortable": true,
74
+ "display_type": "badge"
75
+ },
76
+ "serial": {
77
+ "sortable": true,
78
+ "display_type": "text"
79
+ },
80
+ "created_at": {
81
+ "sortable": true,
82
+ "display_type": "timestamp"
83
+ }
64
84
  }
65
85
  },
66
86
  "default_detail": {
@@ -70,28 +90,61 @@
70
90
  {
71
91
  "title": "Signal",
72
92
  "fields": {
73
- "action_type": { "display_type": "input" },
74
- "action_value": { "display_type": "input" },
75
- "stage": { "display_type": "select" }
93
+ "action_type": {
94
+ "display_type": "input"
95
+ },
96
+ "action_value": {
97
+ "display_type": "input"
98
+ },
99
+ "stage": {
100
+ "display_type": "select"
101
+ }
76
102
  }
77
103
  },
78
104
  {
79
105
  "title": "Instance",
80
106
  "fields": {
81
- "serial": { "display_type": "input" },
82
- "app_slug": { "display_type": "select" },
83
- "app_version": { "display_type": "input" }
107
+ "serial": {
108
+ "display_type": "input"
109
+ },
110
+ "app_slug": {
111
+ "display_type": "select"
112
+ },
113
+ "app_version": {
114
+ "display_type": "input"
115
+ }
84
116
  }
85
117
  }
86
118
  ]
87
119
  }
88
120
  },
89
121
  "record_permissions": {
90
- "system_admin": ["create", "read", "update", "delete"],
91
- "support_admin": ["create", "read", "update"],
92
- "support": ["create", "read", "update"],
93
- "member_admin": ["create", "read", "update"],
94
- "member": ["create", "read", "update"]
122
+ "system_admin": [
123
+ "create",
124
+ "read",
125
+ "update",
126
+ "delete"
127
+ ],
128
+ "support_admin": [
129
+ "create",
130
+ "read",
131
+ "update"
132
+ ],
133
+ "support": [
134
+ "create",
135
+ "read",
136
+ "update"
137
+ ],
138
+ "member_admin": [
139
+ "create",
140
+ "read",
141
+ "update"
142
+ ],
143
+ "member": [
144
+ "create",
145
+ "read",
146
+ "update"
147
+ ]
95
148
  }
96
149
  },
97
150
  "validation_schema": {},