spine-framework 0.3.145 → 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 +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
@@ -0,0 +1,432 @@
1
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:module_header:module_header" type="module_header" identity="module_header" parent="none"]
2
+ // CIL[DOC-MACRO purpose="Pass 2 file/folder selection UI for CIL projects"]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Let users visually select discovered files and folders for a CIL project"]
4
+ // CIL[DOC-CONTEXT module=".framework/src/pages/admin/cil" layer="admin-ui" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/ui/button.tsx,.framework/src/components/ui/card.tsx,.framework/src/components/ui/checkbox.tsx,.framework/src/components/ui/skeleton.tsx,.framework/src/lib/api.ts"]
5
+ // CIL[DOC-CONTRACT inputs="project_id from URL" outputs="Updated selected_paths for the project" errors="Project not found, selection save failed" side_effects="Calls /api/cil-ingest?action=select"]
6
+ // CIL[DOC-MICRO logic_summary="Fetch discovered files from the project file_statuses map, render a tri-state tree with checkboxes, and submit the selected file set." notable_decisions=["Folders recursively select/deselect all descendant files.","Status is inferred from project.data.file_statuses."]"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
8
+ // CIL[DOC-STABILITY stability="experimental"]
9
+ // CIL[DOC-AUDIENCE audience="developer"]
10
+
11
+ import { useEffect, useState, useCallback, useMemo } from 'react'
12
+ import { useParams, useNavigate } from 'react-router-dom'
13
+ import { apiFetch } from '@core/lib/api'
14
+ import { Card, CardContent, CardHeader, CardTitle } from '@core/components/ui/card'
15
+ import { Button } from '@core/components/ui/button'
16
+ import { Checkbox } from '@core/components/ui/checkbox'
17
+ import { Skeleton } from '@core/components/ui/skeleton'
18
+ import { ChevronRight, ChevronDown, Folder, FileCode2, Save } from 'lucide-react'
19
+
20
+ import { PageInstructions } from '../../../components/admin/PageInstructions'
21
+
22
+ // CIL[DOC-VECTOR type="context" content="purpose='Pass 2 file/folder selection UI for CIL projects'; No verified external callers; imports: .framework/src/lib/api.ts,.framework/src/components/ui/card.tsx,.framework/src/components/ui/button.tsx"]
23
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
24
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
25
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
26
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
27
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
28
+ // CIL[END stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:module_header:module_header"]
29
+
30
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:project:interface" type="interface" identity="CILProject" parent="none"]
31
+ // CIL[DOC-MACRO purpose="TypeScript interface describing the CIL project record shape"]
32
+ // CIL[DOC-RESPONSIBILITY responsibility="Define the typed contract for CIL project data used by the file selection page"]
33
+ // CIL[DOC-CONTEXT module=".framework/src/pages/admin/cil" layer="admin-ui" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/ui/button.tsx,.framework/src/components/ui/card.tsx,.framework/src/components/ui/checkbox.tsx,.framework/src/components/ui/skeleton.tsx,.framework/src/lib/api.ts,.framework/src/pages/admin/cil/CILFileSelectPage.tsx"]
34
+ // CIL[DOC-CONTRACT inputs="none" outputs="CILProject type definition" errors="none" side_effects="none"]
35
+ // CIL[DOC-MICRO logic_summary="Declares CILProject with id, title, description, and a data object containing repo_path and file_statuses." notable_decisions="[]"]
36
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
37
+ // CIL[DOC-STABILITY stability="stable"]
38
+ interface CILProject {
39
+ id: string
40
+ title: string
41
+ description: string
42
+ data: {
43
+ repo_path: string
44
+ file_statuses: Record<string, string>
45
+ [key: string]: any
46
+ }
47
+ }
48
+ // CIL[DOC-VECTOR type="context" content="purpose='TypeScript interface describing the CIL project record shape'; No verified external callers; imports: .framework/src/lib/api.ts,.framework/src/components/ui/card.tsx,.framework/src/components/ui/button.tsx"]
49
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
50
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
51
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
52
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
53
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
54
+ // CIL[END stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:project:interface"]
55
+
56
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:treenode:interface" type="interface" identity="TreeNode" parent="none"]
57
+ // CIL[DOC-MACRO purpose="Recursive tree node type for file and folder paths"]
58
+ // CIL[DOC-RESPONSIBILITY responsibility="Define the shape of tree nodes used to render the selectable file tree"]
59
+ // CIL[DOC-CONTEXT module=".framework/src/pages/admin/cil" layer="admin-ui" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/ui/button.tsx,.framework/src/components/ui/card.tsx,.framework/src/components/ui/checkbox.tsx,.framework/src/components/ui/skeleton.tsx,.framework/src/lib/api.ts,.framework/src/pages/admin/cil/CILFileSelectPage.tsx"]
60
+ // CIL[DOC-CONTRACT inputs="none" outputs="TreeNode type definition" errors="none" side_effects="none"]
61
+ // CIL[DOC-MICRO logic_summary="Declares a TreeNode with name, path, type, and a recursive children array." notable_decisions="[]"]
62
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
63
+ // CIL[DOC-STABILITY stability="stable"]
64
+ interface TreeNode {
65
+ name: string
66
+ path: string
67
+ type: 'file' | 'folder'
68
+ children: TreeNode[]
69
+ }
70
+ // CIL[DOC-VECTOR type="context" content="purpose='Recursive tree node type for file and folder paths'; No verified external callers; imports: .framework/src/lib/api.ts,.framework/src/components/ui/card.tsx,.framework/src/components/ui/button.tsx"]
71
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
72
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
73
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
74
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
75
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
76
+ // CIL[END stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:treenode:interface"]
77
+
78
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:buildtree:function" type="function" identity="buildTree" parent="none"]
79
+ // CIL[DOC-MACRO purpose="Build a sorted nested tree from a flat list of file paths"]
80
+ // CIL[DOC-RESPONSIBILITY responsibility="Transform an array of file paths into a hierarchical TreeNode structure grouped by path segments"]
81
+ // CIL[DOC-CONTEXT module=".framework/src/pages/admin/cil" layer="admin-ui" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/ui/button.tsx,.framework/src/components/ui/card.tsx,.framework/src/components/ui/checkbox.tsx,.framework/src/components/ui/skeleton.tsx,.framework/src/lib/api.ts,.framework/src/pages/admin/cil/CILFileSelectPage.tsx"]
82
+ // CIL[DOC-CONTRACT inputs="filePaths: string[], rootName: string" outputs="TreeNode root containing nested files and folders" errors="none" side_effects="none"]
83
+ // CIL[DOC-MICRO logic_summary="Sorts paths, splits each by '/', and creates nested children on demand, sorting folders before files." notable_decisions="["Sorts children by type (folders first) and then by name"]"]
84
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
85
+ // CIL[DOC-STABILITY stability="stable"]
86
+ function buildTree(filePaths: string[], rootName: string): TreeNode {
87
+ const root: TreeNode = { name: rootName, path: '', type: 'folder', children: [] }
88
+
89
+ const sortedPaths = [...filePaths].sort()
90
+ for (const fullPath of sortedPaths) {
91
+ const parts = fullPath.split('/')
92
+ let current = root
93
+ let built = ''
94
+ for (let i = 0; i < parts.length; i++) {
95
+ const part = parts[i]
96
+ built = built ? `${built}/${part}` : part
97
+ const isFile = i === parts.length - 1
98
+ const existing = current.children.find(c => c.name === part)
99
+ if (existing) {
100
+ current = existing
101
+ } else {
102
+ const child: TreeNode = {
103
+ name: part,
104
+ path: built,
105
+ type: isFile ? 'file' : 'folder',
106
+ children: [],
107
+ }
108
+ current.children.push(child)
109
+ current.children.sort((a, b) => (a.type === b.type ? a.name.localeCompare(b.name) : a.type === 'folder' ? -1 : 1))
110
+ current = child
111
+ }
112
+ }
113
+ }
114
+
115
+ return root
116
+ }
117
+ // CIL[DOC-VECTOR type="context" content="purpose='Build a sorted nested tree from a flat list of file paths'; No verified external callers; imports: .framework/src/lib/api.ts,.framework/src/components/ui/card.tsx,.framework/src/components/ui/button.tsx"]
118
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
119
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
120
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
121
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
122
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
123
+ // CIL[END stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:buildtree:function"]
124
+
125
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:filepaths:function" type="function" identity="allFilePaths" parent="none"]
126
+ // CIL[DOC-MACRO purpose="Collect all file paths under a tree node"]
127
+ // CIL[DOC-RESPONSIBILITY responsibility="Recursively flatten a node and its children into a list of file paths"]
128
+ // CIL[DOC-CONTEXT module=".framework/src/pages/admin/cil" layer="admin-ui" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/ui/button.tsx,.framework/src/components/ui/card.tsx,.framework/src/components/ui/checkbox.tsx,.framework/src/components/ui/skeleton.tsx,.framework/src/lib/api.ts,.framework/src/pages/admin/cil/CILFileSelectPage.tsx"]
129
+ // CIL[DOC-CONTRACT inputs="node: TreeNode" outputs="string[] of all descendant file paths" errors="none" side_effects="none"]
130
+ // CIL[DOC-MICRO logic_summary="If the node is a file, returns its path; otherwise returns flatMap of child paths." notable_decisions="[]"]
131
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
132
+ // CIL[DOC-STABILITY stability="stable"]
133
+ function allFilePaths(node: TreeNode): string[] {
134
+ if (node.type === 'file') return [node.path]
135
+ return node.children.flatMap(allFilePaths)
136
+ }
137
+ // CIL[DOC-VECTOR type="context" content="purpose='Collect all file paths under a tree node'; No verified external callers; imports: .framework/src/lib/api.ts,.framework/src/components/ui/card.tsx,.framework/src/components/ui/button.tsx"]
138
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
139
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
140
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
141
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
142
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
143
+ // CIL[END stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:filepaths:function"]
144
+
145
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:nodecheck:function" type="function" identity="nodeCheckState" parent="none"]
146
+ // CIL[DOC-MACRO purpose="Determine the checked state of a tree node against a selection set"]
147
+ // CIL[DOC-RESPONSIBILITY responsibility="Compute whether a node is checked, indeterminate, or unchecked based on descendant file selection"]
148
+ // CIL[DOC-CONTEXT module=".framework/src/pages/admin/cil" layer="admin-ui" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/ui/button.tsx,.framework/src/components/ui/card.tsx,.framework/src/components/ui/checkbox.tsx,.framework/src/components/ui/skeleton.tsx,.framework/src/lib/api.ts,.framework/src/pages/admin/cil/CILFileSelectPage.tsx"]
149
+ // CIL[DOC-CONTRACT inputs="node: TreeNode, selected: Set<string>" outputs="'checked' | 'indeterminate' | 'unchecked'" errors="none" side_effects="none"]
150
+ // CIL[DOC-MICRO logic_summary="For files, checks membership in selected. For folders, compares selected descendant count to total descendants." notable_decisions="[]"]
151
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
152
+ // CIL[DOC-STABILITY stability="stable"]
153
+ function nodeCheckState(node: TreeNode, selected: Set<string>): 'checked' | 'indeterminate' | 'unchecked' {
154
+ if (node.type === 'file') {
155
+ return selected.has(node.path) ? 'checked' : 'unchecked'
156
+ }
157
+ const paths = allFilePaths(node)
158
+ if (paths.length === 0) return 'unchecked'
159
+ const selectedCount = paths.filter(p => selected.has(p)).length
160
+ if (selectedCount === 0) return 'unchecked'
161
+ if (selectedCount === paths.length) return 'checked'
162
+ return 'indeterminate'
163
+ }
164
+ // CIL[DOC-VECTOR type="context" content="purpose='Determine the checked state of a tree node against a selection set'; No verified external callers; imports: .framework/src/lib/api.ts,.framework/src/components/ui/card.tsx,.framework/src/components/ui/button.tsx"]
165
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
166
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
167
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
168
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
169
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
170
+ // CIL[END stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:nodecheck:function"]
171
+
172
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:filenamenode:function" type="function" identity="FileNameNode" parent="none"]
173
+ // CIL[DOC-MACRO purpose="Render a file or folder label with icon and expand chevron"]
174
+ // CIL[DOC-RESPONSIBILITY responsibility="Display a node name with an appropriate icon and folder expand/collapse chevron"]
175
+ // CIL[DOC-CONTEXT module=".framework/src/pages/admin/cil" layer="admin-ui" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/ui/button.tsx,.framework/src/components/ui/card.tsx,.framework/src/components/ui/checkbox.tsx,.framework/src/components/ui/skeleton.tsx,.framework/src/lib/api.ts,.framework/src/pages/admin/cil/CILFileSelectPage.tsx"]
176
+ // CIL[DOC-CONTRACT inputs="name: string, isFolder: boolean, expanded: boolean" outputs="JSX.Element label" errors="none" side_effects="none"]
177
+ // CIL[DOC-MICRO logic_summary="Renders a folder with chevron and folder icon when isFolder is true, otherwise a file icon followed by the name." notable_decisions="[]"]
178
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
179
+ // CIL[DOC-STABILITY stability="stable"]
180
+ function FileNameNode({ name, isFolder, expanded }: { name: string; isFolder: boolean; expanded: boolean }) {
181
+ return (
182
+ <span className="flex items-center gap-2">
183
+ {isFolder ? (
184
+ <>
185
+ {expanded ? <ChevronDown className="h-3.5 w-3.5 text-muted-foreground" /> : <ChevronRight className="h-3.5 w-3.5 text-muted-foreground" />}
186
+ <Folder className="h-4 w-4 text-indigo-500" />
187
+ </>
188
+ ) : (
189
+ <FileCode2 className="h-4 w-4 text-muted-foreground" />
190
+ )}
191
+ <span className="text-sm">{name}</span>
192
+ </span>
193
+ )
194
+ }
195
+ // CIL[DOC-VECTOR type="context" content="purpose='Render a file or folder label with icon and expand chevron'; No verified external callers; imports: .framework/src/lib/api.ts,.framework/src/components/ui/card.tsx,.framework/src/components/ui/button.tsx"]
196
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
197
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
198
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
199
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
200
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
201
+ // CIL[END stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:filenamenode:function"]
202
+
203
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:treenode:component" type="component" identity="TreeNodeRow" parent="none"]
204
+ // CIL[DOC-MACRO purpose="Render a selectable, recursively expandable tree row"]
205
+ // CIL[DOC-RESPONSIBILITY responsibility="Display a tree node with a tri-state checkbox, expand/collapse behavior, and recursive child rendering"]
206
+ // CIL[DOC-CONTEXT module=".framework/src/pages/admin/cil" layer="admin-ui" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/ui/button.tsx,.framework/src/components/ui/card.tsx,.framework/src/components/ui/checkbox.tsx,.framework/src/components/ui/skeleton.tsx,.framework/src/lib/api.ts,.framework/src/pages/admin/cil/CILFileSelectPage.tsx"]
207
+ // CIL[DOC-CONTRACT inputs="node: TreeNode, selected: Set<string>, expanded: Set<string>, onToggle: (node: TreeNode) => void, onToggleExpand: (path: string) => void, depth?: number" outputs="JSX.Element" errors="none" side_effects="none"]
208
+ // CIL[DOC-MICRO logic_summary="Computes the checkbox state, renders the label with indentation, and conditionally renders children." notable_decisions="[]"]
209
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
210
+ // CIL[DOC-STABILITY stability="stable"]
211
+ function TreeNodeRow({
212
+ node,
213
+ selected,
214
+ expanded,
215
+ onToggle,
216
+ onToggleExpand,
217
+ depth = 0,
218
+ }: {
219
+ node: TreeNode
220
+ selected: Set<string>
221
+ expanded: Set<string>
222
+ onToggle: (node: TreeNode) => void
223
+ onToggleExpand: (path: string) => void
224
+ depth?: number
225
+ }) {
226
+ const checkState = nodeCheckState(node, selected)
227
+ const isFolder = node.type === 'folder'
228
+ const hasChildren = isFolder && node.children.length > 0
229
+ const isExpanded = expanded.has(node.path) || depth === 0
230
+
231
+ return (
232
+ <div className="select-none">
233
+ <div
234
+ className="flex items-center gap-2 py-1 hover:bg-muted/40 rounded px-1"
235
+ style={{ paddingLeft: `${depth * 12}px` }}
236
+ >
237
+ <Checkbox
238
+ checked={checkState === 'checked' ? true : checkState === 'indeterminate' ? 'indeterminate' : false}
239
+ onCheckedChange={() => onToggle(node)}
240
+ />
241
+ <div
242
+ className="flex-1 cursor-pointer"
243
+ onClick={() => isFolder && hasChildren ? onToggleExpand(node.path) : undefined}
244
+ >
245
+ <FileNameNode name={node.name} isFolder={isFolder} expanded={isExpanded} />
246
+ </div>
247
+ </div>
248
+ {isFolder && isExpanded && hasChildren && (
249
+ <div>
250
+ {node.children.map(child => (
251
+ <TreeNodeRow
252
+ key={child.path}
253
+ node={child}
254
+ selected={selected}
255
+ expanded={expanded}
256
+ onToggle={onToggle}
257
+ onToggleExpand={onToggleExpand}
258
+ depth={depth + 1}
259
+ />
260
+ ))}
261
+ </div>
262
+ )}
263
+ </div>
264
+ )
265
+ }
266
+ // CIL[DOC-VECTOR type="context" content="purpose='Render a selectable, recursively expandable tree row'; No verified external callers; imports: .framework/src/lib/api.ts,.framework/src/components/ui/card.tsx,.framework/src/components/ui/button.tsx"]
267
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
268
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
269
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
270
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
271
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
272
+ // CIL[END stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:treenode:component"]
273
+
274
+ // CIL[BEGIN stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:CILFileSelectPage:component" type="component" identity="CILFileSelectPage" parent="none"]
275
+ // CIL[DOC-MACRO purpose="Main page component for CIL file and folder selection"]
276
+ // CIL[DOC-RESPONSIBILITY responsibility="Load the CIL project, render a tri-state file tree, and submit the selected file set"]
277
+ // CIL[DOC-CONTEXT module=".framework/src/pages/admin/cil" layer="admin-ui" related_files=".framework/src/components/admin/PageInstructions.tsx,.framework/src/components/ui/button.tsx,.framework/src/components/ui/card.tsx,.framework/src/components/ui/checkbox.tsx,.framework/src/components/ui/skeleton.tsx,.framework/src/lib/api.ts,.framework/src/pages/admin/cil/CILFileSelectPage.tsx"]
278
+ // CIL[DOC-CONTRACT inputs="project_id from URL" outputs="Updated selected_paths for the project" errors="Project not found, selection save failed" side_effects="Calls /api/cil-ingest?action=select and navigates to the dashboard"]
279
+ // CIL[DOC-MICRO logic_summary="Fetches the project, builds the tree, manages selected and expanded sets, renders the tree and instructions, and saves the selection." notable_decisions="["Tree root is derived from repo_path basename","All files under a folder are selected/deselected together"]"]
280
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
281
+ // CIL[DOC-STABILITY stability="stable"]
282
+ export default function CILFileSelectPage() {
283
+ const { id: projectId } = useParams<{ id: string }>()
284
+ const navigate = useNavigate()
285
+ const appPath = (path: string) => '/spine-framework/admin' + (path.startsWith('/') ? path : '/' + path)
286
+
287
+ const [project, setProject] = useState<CILProject | null>(null)
288
+ const [loading, setLoading] = useState(true)
289
+ const [saving, setSaving] = useState(false)
290
+ const [selected, setSelected] = useState<Set<string>>(new Set())
291
+ const [expanded, setExpanded] = useState<Set<string>>(new Set())
292
+
293
+ const load = useCallback(async () => {
294
+ if (!projectId) return
295
+ setLoading(true)
296
+ try {
297
+ const res = await apiFetch(`/api/cil-project?action=get&id=${projectId}`)
298
+ const result = await res.json()
299
+ const projectData = result?.project || result?.data?.project
300
+ setProject(projectData)
301
+ const statuses: Record<string, string> = projectData?.data?.file_statuses || {}
302
+ const initialSelected = new Set<string>(
303
+ Object.entries(statuses).filter(([_, status]) => status === '1-selected').map(([path]) => path)
304
+ )
305
+ setSelected(initialSelected)
306
+ setExpanded(new Set())
307
+ } finally {
308
+ setLoading(false)
309
+ }
310
+ }, [projectId])
311
+
312
+ useEffect(() => { load() }, [load])
313
+
314
+ const filePaths = useMemo(() => {
315
+ if (!project) return []
316
+ return Object.keys(project.data.file_statuses || {})
317
+ }, [project])
318
+
319
+ const tree = useMemo(() => {
320
+ const rootName = project?.data?.repo_path ? project.data.repo_path.split('/').pop() || 'root' : 'root'
321
+ return buildTree(filePaths, rootName)
322
+ }, [filePaths, project])
323
+
324
+ const handleToggle = useCallback((node: TreeNode) => {
325
+ const paths = allFilePaths(node)
326
+ setSelected(prev => {
327
+ const next = new Set(prev)
328
+ const allSelected = paths.every(p => next.has(p))
329
+ if (allSelected) {
330
+ paths.forEach(p => next.delete(p))
331
+ } else {
332
+ paths.forEach(p => next.add(p))
333
+ }
334
+ return next
335
+ })
336
+ }, [])
337
+
338
+ const handleToggleExpand = useCallback((path: string) => {
339
+ setExpanded(prev => {
340
+ const next = new Set(prev)
341
+ if (next.has(path)) next.delete(path)
342
+ else next.add(path)
343
+ return next
344
+ })
345
+ }, [])
346
+
347
+ const handleSave = useCallback(async () => {
348
+ if (!projectId) return
349
+ setSaving(true)
350
+ try {
351
+ await apiFetch('/api/cil-ingest?action=select', {
352
+ method: 'POST',
353
+ headers: { 'Content-Type': 'application/json' },
354
+ body: JSON.stringify({
355
+ project_id: projectId,
356
+ selected_paths: Array.from(selected),
357
+ }),
358
+ })
359
+ navigate(appPath(`/cil/${projectId}/dashboard`))
360
+ } finally {
361
+ setSaving(false)
362
+ }
363
+ }, [projectId, selected, navigate, appPath])
364
+
365
+ if (loading) {
366
+ return (
367
+ <div className="p-6 space-y-4">
368
+ <Skeleton className="h-8 w-48" />
369
+ <Skeleton className="h-96 w-full" />
370
+ </div>
371
+ )
372
+ }
373
+
374
+ if (!project) {
375
+ return (
376
+ <div className="p-6">
377
+ <p className="text-muted-foreground">Project not found.</p>
378
+ </div>
379
+ )
380
+ }
381
+
382
+ return (
383
+ <div className="p-6 space-y-4 max-w-5xl">
384
+ <div className="flex items-start justify-between flex-wrap gap-4">
385
+ <div>
386
+ <h1 className="text-2xl font-bold">Select Files</h1>
387
+ <p className="text-sm text-muted-foreground">{project.title} — choose files and folders for CIL processing</p>
388
+ </div>
389
+ <div className="flex items-center gap-2">
390
+ <Button size="sm" variant="outline" onClick={() => navigate(appPath(`/cil/${projectId}/dashboard`))}>
391
+ Cancel
392
+ </Button>
393
+ <Button size="sm" onClick={handleSave} disabled={saving}>
394
+ {saving ? <span className="animate-pulse">Saving…</span> : <><Save className="h-4 w-4 mr-1" /> Save Selection</>}
395
+ </Button>
396
+ </div>
397
+ </div>
398
+
399
+ <PageInstructions
400
+ description="Select which discovered files should move forward through the CIL pipeline."
401
+ sections={[
402
+ { title: 'What this page is for', content: 'Pass 2 — selection. Check files or folders to mark them as selected for chunking, documentation, and enrichment.' },
403
+ { title: 'How to select', content: 'Click a file checkbox to toggle it. Click a folder to select or deselect all files inside that folder.' },
404
+ { title: 'What happens next', content: 'Saving writes the selected paths to the project and updates each cil_file status to 1-selected. Passes 3-8 are then run by Devin through the CIL MCP tools.' },
405
+ ]}
406
+ />
407
+
408
+ <Card>
409
+ <CardHeader className="pb-2">
410
+ <CardTitle className="text-sm">Discovered Files</CardTitle>
411
+ <p className="text-xs text-muted-foreground">{filePaths.length} discovered • {selected.size} selected</p>
412
+ </CardHeader>
413
+ <CardContent className="max-h-[60vh] overflow-y-auto border-t pt-3">
414
+ <TreeNodeRow
415
+ node={tree}
416
+ selected={selected}
417
+ expanded={expanded}
418
+ onToggle={handleToggle}
419
+ onToggleExpand={handleToggleExpand}
420
+ />
421
+ </CardContent>
422
+ </Card>
423
+ </div>
424
+ )
425
+ }
426
+ // CIL[DOC-VECTOR type="context" content="purpose='Main page component for CIL file and folder selection'; No verified external callers; imports: .framework/src/lib/api.ts,.framework/src/components/ui/card.tsx,.framework/src/components/ui/button.tsx"]
427
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
428
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
429
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
430
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
431
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
432
+ // CIL[END stable_id="~/.framework/src/pages/admin/cil/CILFileSelectPage.tsx:CILFileSelectPage:component"]