spine-framework 0.3.145 → 0.4.1

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 +5067 -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 +15 -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,14 +1,71 @@
1
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/kb/KBAdminPage.tsx:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/src/pages/admin/kb/KBAdminPage.tsx"]
2
+ // CIL[DOC-MACRO purpose="Renders the admin knowledge base page with article list and editor."]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide the top-level React component for managing KB articles and categories."]
4
+ // CIL[DOC-CONTEXT module="admin/kb" layer="page" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/kb/KBArticleEditor.tsx,.framework/src/components/kb/KBArticleList.tsx"]
5
+ // CIL[DOC-CONTRACT inputs="URL parameters (typeSlug, id) and mode prop" outputs="JSX for list or editor view" errors="None" side_effects="Programmatic navigation via react-router"]
6
+ // CIL[DOC-MICRO logic_summary="Imports subcomponents and conditionally renders the list or editor based on mode and id." notable_decisions="[]"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
8
+ // CIL[DOC-STABILITY stability="stable"]
9
+ // CIL[DOC-AUDIENCE audience="admin-ui"]
10
+
1
11
  import { useParams, useNavigate } from 'react-router-dom'
2
12
  import { KBArticleList } from '../../../components/kb/KBArticleList'
3
13
  import { KBArticleEditor } from '../../../components/kb/KBArticleEditor'
4
14
  import { PageInstructions } from '../../../components/admin/PageInstructions'
15
+ // CIL[DOC-VECTOR type="context" content="purpose='Renders the admin knowledge base page with article list and editor.'; No verified external callers; imports: .framework/src/components/kb/KBArticleList.tsx,.framework/src/components/kb/KBArticleEditor.tsx,.framework/src/components/admin/PageInstructions.tsx"]
16
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
17
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
18
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
19
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
20
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
21
+ // CIL[END stable_id="~/.framework/src/pages/admin/kb/KBAdminPage.tsx:module_header:module_header"]
22
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/kb/KBAdminPage.tsx:kb_type_slugs:constant" type="constant" identity="KB_TYPE_SLUGS" parent="~/.framework/src/pages/admin/kb/KBAdminPage.tsx"]
23
+ // CIL[DOC-MACRO purpose="Defines the allowed knowledge base type slugs."]
24
+ // CIL[DOC-RESPONSIBILITY responsibility="Enumerate valid KB categories used by the admin page and article list."]
25
+ // CIL[DOC-CONTEXT module="admin/kb" layer="data" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/kb/KBArticleEditor.tsx,.framework/src/components/kb/KBArticleList.tsx,.framework/src/pages/admin/kb/KBAdminPage.tsx"]
26
+ // CIL[DOC-CONTRACT inputs="None" outputs="Array of type slug strings" errors="None" side_effects="None"]
27
+ // CIL[DOC-MICRO logic_summary="Static string array enumerating valid knowledge base categories." notable_decisions="[]"]
28
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
29
+ // CIL[DOC-STABILITY stability="stable"]
5
30
 
6
31
  const KB_TYPE_SLUGS = ['kb-spine-admin', 'kb-spine-internal', 'kb-spine-public', 'kb-account']
32
+ // CIL[DOC-VECTOR type="context" content="purpose='Defines the allowed knowledge base type slugs.'; No verified external callers; imports: .framework/src/components/kb/KBArticleList.tsx,.framework/src/components/kb/KBArticleEditor.tsx,.framework/src/components/admin/PageInstructions.tsx"]
33
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
34
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
35
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
36
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
37
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
38
+ // CIL[END stable_id="~/.framework/src/pages/admin/kb/KBAdminPage.tsx:kb_type_slugs:constant"]
39
+
7
40
 
41
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/kb/KBAdminPage.tsx:KBAdminPageProps:interface" type="interface" identity="KBAdminPageProps" parent="~/.framework/src/pages/admin/kb/KBAdminPage.tsx"]
42
+ // CIL[DOC-MACRO purpose="Defines the props accepted by the KBAdminPage component."]
43
+ // CIL[DOC-RESPONSIBILITY responsibility="Declare the optional mode prop for view/edit/new state."]
44
+ // CIL[DOC-CONTEXT module="admin/kb" layer="interface" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/kb/KBArticleEditor.tsx,.framework/src/components/kb/KBArticleList.tsx,.framework/src/pages/admin/kb/KBAdminPage.tsx"]
45
+ // CIL[DOC-CONTRACT inputs="None" outputs="Type definition for KBAdminPageProps" errors="None" side_effects="None"]
46
+ // CIL[DOC-MICRO logic_summary="Optional mode union type supporting view, edit, and new modes." notable_decisions="[]"]
47
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
48
+ // CIL[DOC-STABILITY stability="stable"]
8
49
  interface KBAdminPageProps {
9
50
  mode?: 'view' | 'edit' | 'new'
10
51
  }
52
+ // CIL[DOC-VECTOR type="context" content="purpose='Defines the props accepted by the KBAdminPage component.'; No verified external callers; imports: .framework/src/components/kb/KBArticleList.tsx,.framework/src/components/kb/KBArticleEditor.tsx,.framework/src/components/admin/PageInstructions.tsx"]
53
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
54
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
55
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
56
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
57
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
58
+ // CIL[END stable_id="~/.framework/src/pages/admin/kb/KBAdminPage.tsx:KBAdminPageProps:interface"]
59
+
11
60
 
61
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/kb/KBAdminPage.tsx:kbadminpage:function" type="function" identity="KBAdminPage" parent="~/.framework/src/pages/admin/kb/KBAdminPage.tsx"]
62
+ // CIL[DOC-MACRO purpose="Displays the knowledge base article list or editor based on route mode and id."]
63
+ // CIL[DOC-RESPONSIBILITY responsibility="Render the admin KB page and route user actions to the appropriate editor/list views."]
64
+ // CIL[DOC-CONTEXT module="admin/kb" layer="page" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/kb/KBArticleEditor.tsx,.framework/src/components/kb/KBArticleList.tsx,.framework/src/pages/admin/kb/KBAdminPage.tsx"]
65
+ // CIL[DOC-CONTRACT inputs="mode prop and URL params typeSlug/id" outputs="JSX with KBArticleList or KBArticleEditor" errors="None" side_effects="Navigates using useNavigate"]
66
+ // CIL[DOC-MICRO logic_summary="Determines list mode from the mode prop and absence of id, then renders list or editor with navigation callbacks." notable_decisions="[]"]
67
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
68
+ // CIL[DOC-STABILITY stability="stable"]
12
69
  export function KBAdminPage({ mode = 'view' }: KBAdminPageProps) {
13
70
  const { typeSlug, id } = useParams<{ typeSlug: string; id: string }>()
14
71
  const navigate = useNavigate()
@@ -62,3 +119,10 @@ export function KBAdminPage({ mode = 'view' }: KBAdminPageProps) {
62
119
  </>
63
120
  )
64
121
  }
122
+ // CIL[DOC-VECTOR type="context" content="purpose='Displays the knowledge base article list or editor based on route mode and id.'; No verified external callers; imports: .framework/src/components/kb/KBArticleList.tsx,.framework/src/components/kb/KBArticleEditor.tsx,.framework/src/components/admin/PageInstructions.tsx"]
123
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
124
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
125
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
126
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
127
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
128
+ // CIL[END stable_id="~/.framework/src/pages/admin/kb/KBAdminPage.tsx:kbadminpage:function"]
@@ -1,61 +1,64 @@
1
- // CIL[BEGIN chunk_id="AuthConfirmPage_module_header_1783662155" type="module_header" identity="module_header" parent="none"]
2
- // CIL[DOC-MACRO purpose="Import React hooks, routing, Supabase, and UI components for auth confirmation"]
3
- // CIL[DOC-RESPONSIBILITY responsibility="Provide necessary imports for token verification and password reset functionality"]
4
- // CIL[DOC-CONTEXT module="src/pages/auth/AuthConfirmPage" layer="frontend-page" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/components/ui/dialog.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"\\\"]"]
5
- // CIL[DOC-CONTRACT inputs="none" outputs="React hooks, routing, Supabase client, LoadingSpinner" errors="none" side_effects="none"]
6
- // CIL[DOC-MICRO logic_summary="Standard imports for auth callback page with token handling" notable_decisions="[]"]
7
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1
+ // CIL[BEGIN stable_id="~/.framework/src/pages/auth/AuthConfirmPage.tsx:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/src/pages/auth/AuthConfirmPage.tsx"]
2
+ // CIL[DOC-MACRO purpose="Defines the AuthConfirmPage React component for confirming email signup and password reset tokens."]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Import dependencies, the Supabase client, and shared UI components."]
4
+ // CIL[DOC-CONTEXT module="AuthConfirmPage" layer="pages/auth" related_files=".framework/src/components/ui/LoadingSpinner.tsx,.framework/src/lib/supabase.ts"]
5
+ // CIL[DOC-CONTRACT inputs="N/A" outputs="N/A" errors="N/A" side_effects="N/A"]
6
+ // CIL[DOC-MICRO logic_summary="Top-level module imports for the auth confirmation page." notable_decisions="[]"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
8
8
  // CIL[DOC-STABILITY stability="stable"]
9
- // CIL[DOC-AUDIENCE audience="developer"]
10
- // CIL[DOC-VECTOR type="context" content="Layer: frontend-page. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/components/ui/dialog.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/TypeDetailPage.tsx, \."]
11
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
12
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
13
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
14
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
15
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
9
+ // CIL[DOC-AUDIENCE audience="developers maintaining auth flows"]
16
10
  import React, { useState, useEffect } from 'react'
17
11
  import { Link, useNavigate, useSearchParams } from 'react-router-dom'
18
12
  import { supabase } from '../../lib/supabase'
13
+ import { useAuth } from '../../contexts/AuthContext'
19
14
  import { LoadingSpinner } from '../../components/ui/LoadingSpinner'
20
- // CIL[END chunk_id="AuthConfirmPage_module_header_1783662155"]
21
- // CIL[BEGIN chunk_id="AuthConfirmPage_stage_1783662155" type="type" identity="stage" parent="none"]
22
- // CIL[DOC-MACRO purpose="Define authentication confirmation page states for token verification flow"]
23
- // CIL[DOC-RESPONSIBILITY responsibility="Provide type definition for all possible page states during auth confirmation"]
24
- // CIL[DOC-CONTEXT module="src/pages/auth/AuthConfirmPage" layer="frontend-page" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
25
- // CIL[DOC-CONTRACT inputs="none" outputs="Stage union type" errors="none" side_effects="none"]
26
- // CIL[DOC-MICRO logic_summary="Type definition for auth confirmation flow states" notable_decisions="[]"]
27
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
28
- // CIL[DOC-STABILITY stability="stable"]
29
- // CIL[DOC-VECTOR type="context" content="Layer: frontend-page. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/src/pages/admin/RolesPage.tsx, \."]
30
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
31
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
32
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
15
+ import {
16
+ clearPendingRegistration,
17
+ finalizeRegistration,
18
+ readPendingRegistration,
19
+ } from '../../lib/registration'
20
+ // CIL[DOC-VECTOR type="context" content="purpose='Defines the AuthConfirmPage React component for confirming email signup and password reset tokens.'; No verified external callers; imports: .framework/src/lib/supabase.ts,.framework/src/components/ui/LoadingSpinner.tsx"]
21
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
22
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
23
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
33
24
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
34
25
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
26
+ // CIL[END stable_id="~/.framework/src/pages/auth/AuthConfirmPage.tsx:module_header:module_header"]
27
+ // CIL[BEGIN stable_id="~/.framework/src/pages/auth/AuthConfirmPage.tsx:stage:type" type="type" identity="Stage" parent="~/.framework/src/pages/auth/AuthConfirmPage.tsx"]
28
+ // CIL[DOC-MACRO purpose="Union type describing the possible stages of the email and password confirmation flow."]
29
+ // CIL[DOC-RESPONSIBILITY responsibility="Define the string literal stage values used by the AuthConfirmPage state machine."]
30
+ // CIL[DOC-CONTEXT module="AuthConfirmPage" layer="pages/auth" related_files=".framework/src/components/ui/LoadingSpinner.tsx,.framework/src/lib/supabase.ts,.framework/src/pages/auth/AuthConfirmPage.tsx"]
31
+ // CIL[DOC-CONTRACT inputs="N/A" outputs="Stage union string literal" errors="N/A" side_effects="N/A"]
32
+ // CIL[DOC-MICRO logic_summary="Literal union type for the component's UI and verification state." notable_decisions="[]"]
33
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
34
+ // CIL[DOC-STABILITY stability="stable"]
35
35
  type Stage =
36
36
  | 'verifying'
37
37
  | 'signup_success'
38
38
  | 'set_password'
39
39
  | 'password_saved'
40
40
  | 'error'
41
- // CIL[END chunk_id="AuthConfirmPage_stage_1783662155"]
42
- // CIL[BEGIN chunk_id="AuthConfirmPage_authconfirmpage_1783662155" type="function" identity="AuthConfirmPage" parent="none"]
43
- // CIL[DOC-MACRO purpose="Handle email confirmation and password reset flows with token verification"]
44
- // CIL[DOC-RESPONSIBILITY responsibility="Verify auth tokens, handle signup confirmation, and manage password reset flow"]
45
- // CIL[DOC-CONTEXT module="src/pages/auth/AuthConfirmPage" layer="frontend-page" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/components/ui/dialog.tsx\",\".framework/functions/_shared/principal.ts\",\"\\\"]"]
46
- // CIL[DOC-CONTRACT inputs="none" outputs="authenticated session or password reset form" errors="token errors, validation errors" side_effects="updates auth state, creates user session"]
47
- // CIL[DOC-MICRO logic_summary="Token verification with multiple flow handling and error states" notable_decisions="[]"]
48
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
49
- // CIL[DOC-STABILITY stability="stable"]
50
- // CIL[DOC-VECTOR type="context" content="Layer: frontend-page. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/RolesPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/components/ui/dialog.tsx, .framework/functions/_shared/principal.ts, \."]
51
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
52
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
53
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
41
+
42
+ // CIL[DOC-VECTOR type="context" content="purpose='Union type describing the possible stages of the email and password confirmation flow.'; No verified external callers; imports: .framework/src/lib/supabase.ts,.framework/src/components/ui/LoadingSpinner.tsx"]
43
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
44
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
45
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
54
46
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
55
47
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
48
+ // CIL[END stable_id="~/.framework/src/pages/auth/AuthConfirmPage.tsx:stage:type"]
49
+ // CIL[BEGIN stable_id="~/.framework/src/pages/auth/AuthConfirmPage.tsx:authconfirmpage:function" type="function" identity="AuthConfirmPage" parent="~/.framework/src/pages/auth/AuthConfirmPage.tsx"]
50
+ // CIL[DOC-MACRO purpose="Render the authentication confirmation page and allow users to set a new password after a recovery flow."]
51
+ // CIL[DOC-RESPONSIBILITY responsibility="Verify the OTP token hash, display success or error UI, and handle the new password form submission."]
52
+ // CIL[DOC-CONTEXT module="AuthConfirmPage" layer="pages/auth" related_files=".framework/src/components/ui/LoadingSpinner.tsx,.framework/src/lib/supabase.ts,.framework/src/pages/auth/AuthConfirmPage.tsx"]
53
+ // CIL[DOC-CONTRACT inputs="token_hash and type URL query parameters" outputs="JSX for the verifying, error, signup success, set password, or password saved states" errors="Invalid or missing confirmation link, expired or invalid OTP, failed password update, mismatched or short passwords" side_effects="Calls supabase.auth.verifyOtp and supabase.auth.updateUser; navigates to / on success after a timeout"]
54
+ // CIL[DOC-MICRO logic_summary="Reads token_hash and type from the query string, verifies the OTP with Supabase, then renders a stage-based UI and processes password form submission with client-side validation." notable_decisions="['hash/implicit session fallback via getSession + PASSWORD_RECOVERY listener','resumes spine.pending_registration intent after signup confirm via finalizeRegistration + refreshUser']"]
55
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
56
+ // CIL[DOC-STABILITY stability="stable"]
57
+ // CIL[DOC-NOTE type="change" content="Batch4b: links with no token_hash fall back to supabase.auth.getSession (implicit/hash flow); successful signup confirms resume pending registration intent — non-invite runs authenticated complete-registration, invite just rebinds context"]
56
58
  export function AuthConfirmPage() {
57
59
  const [searchParams] = useSearchParams()
58
60
  const navigate = useNavigate()
61
+ const { refreshUser } = useAuth()
59
62
 
60
63
  const tokenHash = searchParams.get('token_hash')
61
64
  const type = searchParams.get('type') as 'signup' | 'recovery' | string | null
@@ -69,37 +72,98 @@ export function AuthConfirmPage() {
69
72
  const [isSaving, setIsSaving] = useState(false)
70
73
 
71
74
  useEffect(() => {
72
- if (!tokenHash || !type) {
73
- setErrorMessage('Invalid or missing confirmation link. Please request a new one.')
74
- setStage('error')
75
- return
75
+ let cancelled = false
76
+
77
+ // After a confirmed signup, resume the pending registration intent saved
78
+ // in sessionStorage before the email round-trip (spine.pending_registration).
79
+ // Invite intents need no server call — the stub was claimed by the
80
+ // auth.users trigger when signUp ran.
81
+ const finishSignup = async () => {
82
+ const intent = readPendingRegistration()
83
+ try {
84
+ if (intent && !intent.invite && intent.path) {
85
+ const result = await finalizeRegistration(intent)
86
+ clearPendingRegistration()
87
+ await refreshUser()
88
+ if (cancelled) return
89
+ setStage('signup_success')
90
+ setTimeout(() => navigate(
91
+ result.status === 'pending' ? '/auth/pending-approval' : '/',
92
+ { replace: true }
93
+ ), 1500)
94
+ return
95
+ }
96
+ if (intent) clearPendingRegistration()
97
+ await refreshUser()
98
+ if (cancelled) return
99
+ setStage('signup_success')
100
+ setTimeout(() => navigate('/', { replace: true }), 1500)
101
+ } catch {
102
+ // Keep the intent — /register?resume=1 retries it and surfaces the
103
+ // error. The signup itself is still confirmed.
104
+ if (cancelled) return
105
+ setStage('signup_success')
106
+ setTimeout(() => navigate('/register?resume=1', { replace: true }), 1500)
107
+ }
76
108
  }
77
109
 
78
- ;(async () => {
79
- const { error } = await supabase.auth.verifyOtp({
80
- token_hash: tokenHash,
81
- type: type as any,
82
- })
110
+ if (tokenHash && type) {
111
+ ;(async () => {
112
+ const { error } = await supabase.auth.verifyOtp({
113
+ token_hash: tokenHash,
114
+ type: type as any,
115
+ })
83
116
 
84
- if (error) {
85
- if (error.message.includes('expired') || error.message.includes('otp_expired')) {
86
- setErrorMessage('This link has expired. Links are valid for 1 hour.')
87
- } else if (error.message.includes('invalid')) {
88
- setErrorMessage('This link is invalid or has already been used.')
117
+ if (error) {
118
+ if (error.message.includes('expired') || error.message.includes('otp_expired')) {
119
+ setErrorMessage('This link has expired. Links are valid for 1 hour.')
120
+ } else if (error.message.includes('invalid')) {
121
+ setErrorMessage('This link is invalid or has already been used.')
122
+ } else {
123
+ setErrorMessage(error.message)
124
+ }
125
+ setStage('error')
126
+ return
127
+ }
128
+
129
+ if (type === 'recovery') {
130
+ setStage('set_password')
89
131
  } else {
90
- setErrorMessage(error.message)
132
+ void finishSignup()
91
133
  }
92
- setStage('error')
93
- return
94
- }
134
+ })()
135
+ return () => { cancelled = true }
136
+ }
95
137
 
96
- if (type === 'recovery') {
138
+ // Hash/implicit callback: detectSessionInUrl consumes #access_token before
139
+ // this page reads params, so a live session means the link verified.
140
+ const hashType = new URLSearchParams(window.location.hash.replace(/^#/, '')).get('type')
141
+ if (hashType === 'recovery') {
142
+ setStage('set_password')
143
+ return () => { cancelled = true }
144
+ }
145
+
146
+ const { data: { subscription } } = supabase.auth.onAuthStateChange((event) => {
147
+ if (event === 'PASSWORD_RECOVERY' && !cancelled) {
97
148
  setStage('set_password')
98
- } else {
99
- setStage('signup_success')
100
- setTimeout(() => navigate('/', { replace: true }), 1500)
101
149
  }
150
+ })
151
+
152
+ ;(async () => {
153
+ const { data: { session } } = await supabase.auth.getSession()
154
+ if (cancelled) return
155
+ if (session) {
156
+ await finishSignup()
157
+ return
158
+ }
159
+ setErrorMessage('Invalid or missing confirmation link. Please request a new one.')
160
+ setStage('error')
102
161
  })()
162
+
163
+ return () => {
164
+ cancelled = true
165
+ subscription.unsubscribe()
166
+ }
103
167
  }, [])
104
168
 
105
169
  const handleSetPassword = async (e: React.FormEvent) => {
@@ -210,8 +274,8 @@ export function AuthConfirmPage() {
210
274
  <div className="min-h-screen flex items-center justify-center bg-slate-50 py-12 px-4 sm:px-6 lg:px-8">
211
275
  <div className="max-w-md w-full space-y-8">
212
276
  <div>
213
- <div className="mx-auto h-12 w-12 flex items-center justify-center rounded-full bg-slate-900">
214
- <span className="text-white font-bold text-xl">S</span>
277
+ <div className="mx-auto flex items-center justify-center">
278
+ <img src="/spine-logo.svg" alt="Spine Framework" className="h-14 w-auto" />
215
279
  </div>
216
280
  <h2 className="mt-6 text-center text-3xl font-extrabold text-slate-900">
217
281
  Set a new password
@@ -286,4 +350,10 @@ export function AuthConfirmPage() {
286
350
  </div>
287
351
  )
288
352
  }
289
- // CIL[END chunk_id="AuthConfirmPage_authconfirmpage_1783662155"]
353
+ // CIL[DOC-VECTOR type="context" content="purpose='Render the authentication confirmation page and allow users to set a new password after a recovery flow.'; No verified external callers; imports: .framework/src/lib/supabase.ts,.framework/src/components/ui/LoadingSpinner.tsx"]
354
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
355
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
356
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
357
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
358
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
359
+ // CIL[END stable_id="~/.framework/src/pages/auth/AuthConfirmPage.tsx:authconfirmpage:function"]
@@ -1,39 +1,38 @@
1
- // CIL[BEGIN chunk_id="ForgotPasswordPage_module_header_1783662155" type="module_header" identity="module_header" parent="none"]
2
- // CIL[DOC-MACRO purpose="Import React hooks, routing, Supabase, and UI components for password reset"]
3
- // CIL[DOC-RESPONSIBILITY responsibility="Provide necessary imports for password reset functionality"]
4
- // CIL[DOC-CONTEXT module="src/pages/auth/ForgotPasswordPage" layer="frontend-page" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/components/ui/dialog.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\"\\\"]"]
5
- // CIL[DOC-CONTRACT inputs="none" outputs="React hooks, routing, Supabase client, LoadingSpinner" errors="none" side_effects="none"]
6
- // CIL[DOC-MICRO logic_summary="Standard imports for password reset page with email handling" notable_decisions="[]"]
7
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1
+ // CIL[BEGIN stable_id="~/.framework/src/pages/auth/ForgotPasswordPage.tsx:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/src/pages/auth/ForgotPasswordPage.tsx"]
2
+ // CIL[DOC-MACRO purpose="Provides imports and entry-point metadata for the ForgotPasswordPage component."]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Declare module dependencies and export the ForgotPasswordPage component."]
4
+ // CIL[DOC-CONTEXT module="auth" layer="presentation" related_files=".framework/src/components/ui/LoadingSpinner.tsx,.framework/src/lib/supabase.ts"]
5
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
6
+ // CIL[DOC-MICRO logic_summary="Imports React, routing, Supabase client, and a loading spinner; contains no runtime logic." notable_decisions="[]"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
8
8
  // CIL[DOC-STABILITY stability="stable"]
9
- // CIL[DOC-AUDIENCE audience="developer"]
10
- // CIL[DOC-VECTOR type="context" content="Layer: frontend-page. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/components/ui/dialog.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, \."]
11
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
12
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
13
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
14
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
15
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
9
+ // CIL[DOC-AUDIENCE audience="developers,ui-maintainers"]
10
+
16
11
  import React, { useState } from 'react'
17
12
  import { Link } from 'react-router-dom'
18
13
  import { supabase } from '../../lib/supabase'
19
14
  import { LoadingSpinner } from '../../components/ui/LoadingSpinner'
20
- // CIL[END chunk_id="ForgotPasswordPage_module_header_1783662155"]
21
- // CIL[BEGIN chunk_id="ForgotPasswordPage_forgotpasswordpage_1783662155" type="function" identity="ForgotPasswordPage" parent="none"]
22
- // CIL[DOC-MACRO purpose="Handle password reset request form with email submission and success states"]
23
- // CIL[DOC-RESPONSIBILITY responsibility="Manage password reset flow, form submission, and user feedback states"]
24
- // CIL[DOC-CONTEXT module="src/pages/auth/ForgotPasswordPage" layer="frontend-page" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/components/ui/dialog.tsx\",\"\\\"]"]
25
- // CIL[DOC-CONTRACT inputs="none" outputs="password reset email or error message" errors="validation errors, API errors" side_effects="sends password reset email via Supabase"]
26
- // CIL[DOC-MICRO logic_summary="Form with email validation, async submission, and success confirmation" notable_decisions="[]"]
27
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
28
- // CIL[DOC-STABILITY stability="stable"]
29
- // CIL[DOC-VECTOR type="context" content="Layer: frontend-page. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/RolesPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/components/ui/dialog.tsx, \."]
30
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
31
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
32
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
15
+ import { TurnstileWidget, turnstileEnabled } from '../../components/auth/TurnstileWidget'
16
+
17
+ // CIL[DOC-VECTOR type="context" content="purpose='Provides imports and entry-point metadata for the ForgotPasswordPage component.'; No verified external callers; imports: .framework/src/lib/supabase.ts,.framework/src/components/ui/LoadingSpinner.tsx"]
18
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
19
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
20
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
33
21
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
34
22
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
23
+ // CIL[END stable_id="~/.framework/src/pages/auth/ForgotPasswordPage.tsx:module_header:module_header"]
24
+ // CIL[BEGIN stable_id="~/.framework/src/pages/auth/ForgotPasswordPage.tsx:ForgotPasswordPage:component" type="component" identity="ForgotPasswordPage" parent="~/.framework/src/pages/auth/ForgotPasswordPage.tsx"]
25
+ // CIL[DOC-MACRO purpose="Render a password-reset request page and submit the email to Supabase."]
26
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide a UI for users to enter their email and trigger a password reset email."]
27
+ // CIL[DOC-CONTEXT module="auth" layer="presentation" related_files=".framework/src/components/ui/LoadingSpinner.tsx,.framework/src/lib/supabase.ts,.framework/src/pages/auth/ForgotPasswordPage.tsx"]
28
+ // CIL[DOC-CONTRACT inputs="email (string from user input)" outputs="Rendered JSX form or success confirmation; local state updates for loading/submitted/error." errors="Supabase resetPasswordForEmail errors surfaced to the UI." side_effects="Calls supabase.auth.resetPasswordForEmail with a redirectTo URL; updates component state."]
29
+ // CIL[DOC-MICRO logic_summary="Manages email, loading, submitted and error state. On submit it prevents default, clears errors, sets loading, calls Supabase reset, and on success shows a confirmation with a back-to-login link." notable_decisions="[]"]
30
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
31
+ // CIL[DOC-STABILITY stability="stable"]
32
+
35
33
  export function ForgotPasswordPage() {
36
34
  const [email, setEmail] = useState('')
35
+ const [captchaToken, setCaptchaToken] = useState<string | null>(null)
37
36
  const [isLoading, setIsLoading] = useState(false)
38
37
  const [submitted, setSubmitted] = useState(false)
39
38
  const [error, setError] = useState('')
@@ -46,6 +45,7 @@ export function ForgotPasswordPage() {
46
45
  try {
47
46
  const { error: resetError } = await supabase.auth.resetPasswordForEmail(email, {
48
47
  redirectTo: `${window.location.origin}/auth/confirm`,
48
+ captchaToken: captchaToken ?? undefined,
49
49
  })
50
50
 
51
51
  if (resetError) {
@@ -90,8 +90,8 @@ export function ForgotPasswordPage() {
90
90
  <div className="min-h-screen flex items-center justify-center bg-slate-50 py-12 px-4 sm:px-6 lg:px-8">
91
91
  <div className="max-w-md w-full space-y-8">
92
92
  <div>
93
- <div className="mx-auto h-12 w-12 flex items-center justify-center rounded-full bg-slate-900">
94
- <span className="text-white font-bold text-xl">S</span>
93
+ <div className="mx-auto flex items-center justify-center">
94
+ <img src="/spine-logo.svg" alt="Spine Framework" className="h-14 w-auto" />
95
95
  </div>
96
96
  <h2 className="mt-6 text-center text-3xl font-extrabold text-slate-900">
97
97
  Reset your password
@@ -125,10 +125,12 @@ export function ForgotPasswordPage() {
125
125
  />
126
126
  </div>
127
127
 
128
+ <TurnstileWidget onToken={setCaptchaToken} />
129
+
128
130
  <div>
129
131
  <button
130
132
  type="submit"
131
- disabled={isLoading}
133
+ disabled={isLoading || (turnstileEnabled && !captchaToken)}
132
134
  className="group relative w-full flex justify-center py-2 px-4 border border-transparent rounded-[5px] shadow-sm text-sm font-medium text-white bg-slate-900 hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-accent-blue disabled:opacity-50 disabled:cursor-not-allowed"
133
135
  >
134
136
  {isLoading ? (
@@ -152,4 +154,10 @@ export function ForgotPasswordPage() {
152
154
  </div>
153
155
  )
154
156
  }
155
- // CIL[END chunk_id="ForgotPasswordPage_forgotpasswordpage_1783662155"]
157
+ // CIL[DOC-VECTOR type="context" content="purpose='Render a password-reset request page and submit the email to Supabase.'; No verified external callers; imports: .framework/src/lib/supabase.ts,.framework/src/components/ui/LoadingSpinner.tsx"]
158
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
159
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
160
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
161
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
162
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
163
+ // CIL[END stable_id="~/.framework/src/pages/auth/ForgotPasswordPage.tsx:ForgotPasswordPage:component"]
@@ -1,40 +1,38 @@
1
- // CIL[BEGIN chunk_id="LoginPage_module_header_1783662155" type="module_header" identity="module_header" parent="none"]
2
- // CIL[DOC-MACRO purpose="Import React hooks and components for login page functionality"]
3
- // CIL[DOC-RESPONSIBILITY responsibility="Provide necessary imports for React component, routing, auth context, and UI elements"]
4
- // CIL[DOC-CONTEXT module="src/pages/auth/LoginPage" layer="frontend-page" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/CoursesPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
5
- // CIL[DOC-CONTRACT inputs="none" outputs="React, useState, Link, useAuth, LoadingSpinner" errors="none" side_effects="none"]
6
- // CIL[DOC-MICRO logic_summary="Standard React component imports for authentication page" notable_decisions="[]"]
7
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1
+ // CIL[BEGIN stable_id="~/.framework/src/pages/auth/LoginPage.tsx:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/src/pages/auth/LoginPage.tsx"]
2
+ // CIL[DOC-MACRO purpose="Module header for the LoginPage component: imports, dependencies, and module-level context."]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Declare module-level imports and setup for the authentication login page."]
4
+ // CIL[DOC-CONTEXT module="auth" layer="presentation" related_files=".framework/src/components/ui/LoadingSpinner.tsx,.framework/src/contexts/AuthContext.tsx"]
5
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
6
+ // CIL[DOC-MICRO logic_summary="Imports React, routing, auth context, and the LoadingSpinner UI component." notable_decisions="[]"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.85" flags="none"]
8
8
  // CIL[DOC-STABILITY stability="stable"]
9
- // CIL[DOC-AUDIENCE audience="developer"]
10
- // CIL[DOC-VECTOR type="context" content="Layer: frontend-page. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/CoursesPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/RolesPage.tsx, \."]
11
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
12
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
13
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
14
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
15
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
9
+ // CIL[DOC-AUDIENCE audience="developers"]
10
+
16
11
  import React, { useState } from 'react'
17
12
  import { Link, useNavigate } from 'react-router-dom'
18
13
  import { useAuth } from '../../contexts/AuthContext'
19
14
  import { LoadingSpinner } from '../../components/ui/LoadingSpinner'
20
- // CIL[END chunk_id="LoginPage_module_header_1783662155"]
21
- // CIL[BEGIN chunk_id="LoginPage_loginpage_1783662155" type="function" identity="LoginPage" parent="none"]
22
- // CIL[DOC-MACRO purpose="Render login form with email/password inputs and authentication handling"]
23
- // CIL[DOC-RESPONSIBILITY responsibility="Manage login state, form submission, error display, and user authentication flow"]
24
- // CIL[DOC-CONTEXT module="src/pages/auth/LoginPage" layer="frontend-page" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
25
- // CIL[DOC-CONTRACT inputs="none" outputs="authenticated user session or error message" errors="login failure, network errors" side_effects="updates auth context state"]
26
- // CIL[DOC-MICRO logic_summary="Form with controlled state, async login call, loading states, and error handling" notable_decisions="[]"]
27
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
28
- // CIL[DOC-STABILITY stability="stable"]
29
- // CIL[DOC-VECTOR type="context" content="Layer: frontend-page. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/RolesPage.tsx, custom/apps/cortex/functions/custom_cil-embeddings.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
30
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
31
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
32
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
15
+ import { TurnstileWidget, turnstileEnabled } from '../../components/auth/TurnstileWidget'
16
+
17
+ // CIL[DOC-VECTOR type="context" content="purpose='Module header for the LoginPage component: imports, dependencies, and module-level context.'; No verified external callers; imports: .framework/src/contexts/AuthContext.tsx,.framework/src/components/ui/LoadingSpinner.tsx"]
18
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
19
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
20
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
33
21
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
34
22
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
23
+ // CIL[END stable_id="~/.framework/src/pages/auth/LoginPage.tsx:module_header:module_header"]
24
+ // CIL[BEGIN stable_id="~/.framework/src/pages/auth/LoginPage.tsx:LoginPage:component" type="component" identity="LoginPage" parent="~/.framework/src/pages/auth/LoginPage.tsx"]
25
+ // CIL[DOC-MACRO purpose="Render the login form and handle user authentication."]
26
+ // CIL[DOC-RESPONSIBILITY responsibility="Collect email and password, call auth login, and navigate to the appropriate post-login route."]
27
+ // CIL[DOC-CONTEXT module="auth" layer="presentation" related_files=".framework/src/components/ui/LoadingSpinner.tsx,.framework/src/contexts/AuthContext.tsx,.framework/src/pages/auth/LoginPage.tsx"]
28
+ // CIL[DOC-CONTRACT inputs="none (reads from local form state and AuthContext)" outputs="JSX login page" errors="displays authentication error message" side_effects="calls login API and navigates with react-router"]
29
+ // CIL[DOC-MICRO logic_summary="Manages email/password/isLoading state; on submit prevents default, calls login, fetches spine.config.json, resolves default app by role, and navigates." notable_decisions="[]"]
30
+ // CIL[DOC-CONFIDENCE pass="second" score="0.85" flags="none"]
31
+ // CIL[DOC-STABILITY stability="stable"]
35
32
  export function LoginPage() {
36
33
  const [email, setEmail] = useState('')
37
34
  const [password, setPassword] = useState('')
35
+ const [captchaToken, setCaptchaToken] = useState<string | null>(null)
38
36
  const [error, setError] = useState('')
39
37
  const [isLoading, setIsLoading] = useState(false)
40
38
 
@@ -47,7 +45,7 @@ export function LoginPage() {
47
45
  setIsLoading(true)
48
46
 
49
47
  try {
50
- const user = await login(email, password)
48
+ const user = await login(email, password, captchaToken ?? undefined)
51
49
  const role = user?.roles?.[0]
52
50
  if (!role) {
53
51
  navigate('/')
@@ -75,8 +73,8 @@ export function LoginPage() {
75
73
  <div className="min-h-screen flex items-center justify-center bg-slate-50 py-12 px-4 sm:px-6 lg:px-8">
76
74
  <div className="max-w-md w-full space-y-8">
77
75
  <div>
78
- <div className="mx-auto h-12 w-12 flex items-center justify-center rounded-full bg-slate-900">
79
- <span className="text-white font-bold text-xl">S</span>
76
+ <div className="mx-auto flex items-center justify-center">
77
+ <img src="/spine-logo.svg" alt="Spine Framework" className="h-14 w-auto" />
80
78
  </div>
81
79
  <h2 className="mt-6 text-center text-3xl font-extrabold text-slate-900">
82
80
  Sign in to Spine
@@ -152,10 +150,12 @@ export function LoginPage() {
152
150
  </div>
153
151
  </div>
154
152
 
153
+ <TurnstileWidget onToken={setCaptchaToken} />
154
+
155
155
  <div>
156
156
  <button
157
157
  type="submit"
158
- disabled={isLoading}
158
+ disabled={isLoading || (turnstileEnabled && !captchaToken)}
159
159
  className="group relative w-full flex justify-center py-2 px-4 border border-transparent rounded-[5px] shadow-sm text-sm font-medium text-white bg-slate-900 hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-accent-blue disabled:opacity-50 disabled:cursor-not-allowed"
160
160
  >
161
161
  {isLoading ? (
@@ -173,4 +173,10 @@ export function LoginPage() {
173
173
  </div>
174
174
  )
175
175
  }
176
- // CIL[END chunk_id="LoginPage_loginpage_1783662155"]
176
+ // CIL[DOC-VECTOR type="context" content="purpose='Render the login form and handle user authentication.'; No verified external callers; imports: .framework/src/contexts/AuthContext.tsx,.framework/src/components/ui/LoadingSpinner.tsx"]
177
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
178
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
179
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
180
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
181
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
182
+ // CIL[END stable_id="~/.framework/src/pages/auth/LoginPage.tsx:LoginPage:component"]