spine-framework 0.3.124 → 0.3.126

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 (319) hide show
  1. package/.framework/cli/commands/agents.ts +35 -37
  2. package/.framework/cli/commands/auth.ts +35 -34
  3. package/.framework/cli/commands/create-app.ts +104 -40
  4. package/.framework/cli/commands/dev.ts +104 -69
  5. package/.framework/cli/commands/doctor.ts +179 -69
  6. package/.framework/cli/commands/generate.ts +83 -143
  7. package/.framework/cli/commands/init.ts +72 -34
  8. package/.framework/cli/commands/install-app.ts +260 -125
  9. package/.framework/cli/commands/items.ts +33 -44
  10. package/.framework/cli/commands/migrate.ts +122 -40
  11. package/.framework/cli/commands/migrations.ts +33 -40
  12. package/.framework/cli/commands/pipelines.ts +31 -39
  13. package/.framework/cli/commands/status.ts +47 -23
  14. package/.framework/cli/commands/system.ts +47 -37
  15. package/.framework/cli/commands/test.ts +112 -68
  16. package/.framework/cli/commands/validate-app.ts +215 -121
  17. package/.framework/cli/context.ts +112 -130
  18. package/.framework/cli/env-loader.ts +47 -18
  19. package/.framework/cli/index.ts +81 -42
  20. package/.framework/docs/runtime-types.md +1024 -0
  21. package/.framework/functions/_shared/agent-runner.ts +1296 -961
  22. package/.framework/functions/_shared/app-manifest.ts +82 -68
  23. package/.framework/functions/_shared/audit.ts +135 -83
  24. package/.framework/functions/_shared/{cil-state.ts → cil.ts} +158 -56
  25. package/.framework/functions/_shared/db.ts +80 -126
  26. package/.framework/functions/_shared/hash-api-key.ts +63 -0
  27. package/.framework/functions/_shared/index.ts +224 -335
  28. package/.framework/functions/_shared/kb.ts +319 -0
  29. package/.framework/functions/_shared/llm.ts +92 -0
  30. package/.framework/functions/_shared/logging.ts +288 -0
  31. package/.framework/functions/_shared/middleware.ts +329 -365
  32. package/.framework/functions/_shared/outcomes.ts +36 -0
  33. package/.framework/functions/_shared/permissions.ts +359 -643
  34. package/.framework/functions/_shared/pipeline-runner.ts +243 -316
  35. package/.framework/functions/_shared/principal.ts +376 -468
  36. package/.framework/functions/_shared/resolve-credentials.ts +102 -0
  37. package/.framework/functions/_shared/resolve-ids.ts +188 -16
  38. package/.framework/functions/_shared/retry-deliveries.ts +104 -0
  39. package/.framework/functions/_shared/schema-utils.ts +611 -373
  40. package/.framework/functions/_shared/testing.ts +207 -137
  41. package/.framework/functions/_shared/tracing.ts +276 -0
  42. package/.framework/functions/_shared/trigger-engine.ts +159 -211
  43. package/.framework/functions/_shared/webhook-registration.ts +95 -81
  44. package/.framework/functions/_shared/webhook-registry.ts +153 -75
  45. package/.framework/functions/account-nodes.ts +31 -53
  46. package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
  47. package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
  48. package/.framework/functions/adapters/openai-outbound.ts +40 -0
  49. package/.framework/functions/admin-data.ts +685 -537
  50. package/.framework/functions/admin-funnel.ts +31 -20
  51. package/.framework/functions/admin-install-funnel.ts +47 -28
  52. package/.framework/functions/admin-signals.ts +47 -29
  53. package/.framework/functions/ai-agents.ts +122 -147
  54. package/.framework/functions/ai-interactions.ts +180 -90
  55. package/.framework/functions/api-keys.ts +250 -192
  56. package/.framework/functions/apps.ts +203 -197
  57. package/.framework/functions/auth.ts +98 -91
  58. package/.framework/functions/cil-agent-ingest.ts +773 -0
  59. package/.framework/functions/cil-agent.ts +592 -0
  60. package/.framework/functions/cil-callmap.ts +1227 -0
  61. package/.framework/functions/cil-config.ts +583 -0
  62. package/.framework/functions/cil-context.ts +445 -0
  63. package/.framework/functions/cil-doc.ts +1752 -0
  64. package/.framework/functions/cil-embeddings.ts +1202 -0
  65. package/.framework/functions/cil-graph.ts +585 -0
  66. package/.framework/functions/cil-ingest.ts +2416 -0
  67. package/.framework/functions/cil-pipeline.ts +318 -0
  68. package/.framework/functions/cil-project.ts +499 -0
  69. package/.framework/functions/cil-validate.ts +469 -0
  70. package/.framework/functions/debug-auth.ts +73 -53
  71. package/.framework/functions/deliveries.ts +117 -0
  72. package/.framework/functions/embeddings.ts +528 -516
  73. package/.framework/functions/eval-harness.ts +158 -106
  74. package/.framework/functions/integration-outbound.ts +311 -0
  75. package/.framework/functions/integration-routes.ts +240 -466
  76. package/.framework/functions/integrations.ts +132 -140
  77. package/.framework/functions/invites.ts +401 -201
  78. package/.framework/functions/item-progress.ts +113 -53
  79. package/.framework/functions/kb.ts +28 -0
  80. package/.framework/functions/logs.ts +239 -222
  81. package/.framework/functions/observability.ts +308 -259
  82. package/.framework/functions/pipeline-executions.ts +179 -235
  83. package/.framework/functions/pipelines.ts +163 -205
  84. package/.framework/functions/prompt-configs.ts +109 -156
  85. package/.framework/functions/roles.ts +97 -147
  86. package/.framework/functions/system-cron.ts +132 -218
  87. package/.framework/functions/system.ts +112 -52
  88. package/.framework/functions/tests.ts +32 -28
  89. package/.framework/functions/timers.ts +162 -210
  90. package/.framework/functions/triggers.ts +282 -346
  91. package/.framework/functions/types.ts +283 -400
  92. package/.framework/migrations/001_core_schema.sql +630 -0
  93. package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
  94. package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
  95. package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
  96. package/.framework/migrations/005_core_observability.sql +598 -0
  97. package/.framework/migrations/006_security_hardening_rls.sql +97 -0
  98. package/.framework/migrations/007_kb_article_list.sql +237 -0
  99. package/.framework/migrations/008_items_target.sql +8 -0
  100. package/.framework/migrations/009_roles_slug_unique.sql +11 -0
  101. package/.framework/public/spine.config.json +91 -0
  102. package/.framework/scripts/app-install-cli.ts +112 -98
  103. package/.framework/src/App.tsx +67 -20
  104. package/.framework/src/apps/admin/index.tsx +97 -27
  105. package/.framework/src/components/AppWrapper.tsx +50 -11
  106. package/.framework/src/components/CustomAppLoader.tsx +131 -22
  107. package/.framework/src/components/admin/AdminListPage.tsx +75 -8
  108. package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
  109. package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
  110. package/.framework/src/components/admin/PageInstructions.tsx +49 -0
  111. package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
  112. package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
  113. package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
  114. package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
  115. package/.framework/src/components/app-sidebar.tsx +50 -3
  116. package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
  117. package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
  118. package/.framework/src/components/kb/KBArticleList.tsx +557 -0
  119. package/.framework/src/components/layout/AppShell.tsx +54 -16
  120. package/.framework/src/components/layout/Header.tsx +50 -38
  121. package/.framework/src/components/layout/Layout.tsx +48 -32
  122. package/.framework/src/components/layout/Sidebar.tsx +167 -16
  123. package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
  124. package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
  125. package/.framework/src/components/runtime/DataFilters.tsx +78 -1
  126. package/.framework/src/components/runtime/DataHeader.tsx +32 -29
  127. package/.framework/src/components/runtime/DataListPage.tsx +161 -2
  128. package/.framework/src/components/runtime/DataStats.tsx +48 -1
  129. package/.framework/src/components/runtime/DataTable.tsx +153 -1
  130. package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
  131. package/.framework/src/components/runtime/index.ts +16 -9
  132. package/.framework/src/components/search-form.tsx +33 -1
  133. package/.framework/src/components/shared/AgentView.tsx +48 -51
  134. package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
  135. package/.framework/src/components/shared/InviteManager.tsx +113 -52
  136. package/.framework/src/components/shared/MemberList.tsx +182 -0
  137. package/.framework/src/components/shared/SchemaFields.tsx +96 -78
  138. package/.framework/src/components/ui/DataTable.tsx +86 -56
  139. package/.framework/src/components/ui/Form.tsx +188 -109
  140. package/.framework/src/components/ui/ItemCard.tsx +86 -58
  141. package/.framework/src/components/ui/ItemListView.tsx +88 -61
  142. package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
  143. package/.framework/src/components/ui/Modal.tsx +81 -4
  144. package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
  145. package/.framework/src/components/ui/accordion.tsx +97 -5
  146. package/.framework/src/components/ui/alert-dialog.tsx +225 -13
  147. package/.framework/src/components/ui/alert.tsx +113 -6
  148. package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
  149. package/.framework/src/components/ui/avatar.tsx +129 -7
  150. package/.framework/src/components/ui/badge.tsx +65 -3
  151. package/.framework/src/components/ui/breadcrumb.tsx +145 -8
  152. package/.framework/src/components/ui/button-group.tsx +81 -4
  153. package/.framework/src/components/ui/button.tsx +49 -2
  154. package/.framework/src/components/ui/calendar.tsx +65 -3
  155. package/.framework/src/components/ui/card.tsx +145 -8
  156. package/.framework/src/components/ui/carousel.tsx +129 -7
  157. package/.framework/src/components/ui/chart.tsx +161 -10
  158. package/.framework/src/components/ui/checkbox.tsx +49 -2
  159. package/.framework/src/components/ui/collapsible.tsx +81 -5
  160. package/.framework/src/components/ui/combobox.tsx +305 -20
  161. package/.framework/src/components/ui/command.tsx +177 -11
  162. package/.framework/src/components/ui/context-menu.tsx +273 -17
  163. package/.framework/src/components/ui/dialog.tsx +209 -27
  164. package/.framework/src/components/ui/direction.tsx +64 -4
  165. package/.framework/src/components/ui/drawer.tsx +193 -12
  166. package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
  167. package/.framework/src/components/ui/empty.tsx +145 -9
  168. package/.framework/src/components/ui/field.tsx +209 -14
  169. package/.framework/src/components/ui/hover-card.tsx +81 -4
  170. package/.framework/src/components/ui/input-group.tsx +162 -10
  171. package/.framework/src/components/ui/input-otp.tsx +98 -5
  172. package/.framework/src/components/ui/input.tsx +49 -2
  173. package/.framework/src/components/ui/item.tsx +225 -13
  174. package/.framework/src/components/ui/kbd.tsx +65 -3
  175. package/.framework/src/components/ui/label.tsx +49 -2
  176. package/.framework/src/components/ui/menubar.tsx +289 -17
  177. package/.framework/src/components/ui/native-select.tsx +97 -5
  178. package/.framework/src/components/ui/navigation-menu.tsx +177 -10
  179. package/.framework/src/components/ui/pagination.tsx +161 -9
  180. package/.framework/src/components/ui/popover.tsx +145 -8
  181. package/.framework/src/components/ui/progress.tsx +49 -2
  182. package/.framework/src/components/ui/radio-group.tsx +65 -3
  183. package/.framework/src/components/ui/resizable.tsx +82 -4
  184. package/.framework/src/components/ui/scroll-area.tsx +65 -3
  185. package/.framework/src/components/ui/select.tsx +193 -11
  186. package/.framework/src/components/ui/separator.tsx +49 -2
  187. package/.framework/src/components/ui/sheet.tsx +193 -11
  188. package/.framework/src/components/ui/sidebar.tsx +481 -38
  189. package/.framework/src/components/ui/skeleton.tsx +49 -2
  190. package/.framework/src/components/ui/slider.tsx +49 -2
  191. package/.framework/src/components/ui/sonner.tsx +49 -2
  192. package/.framework/src/components/ui/spinner.tsx +49 -2
  193. package/.framework/src/components/ui/switch.tsx +49 -2
  194. package/.framework/src/components/ui/table-primitives.tsx +160 -33
  195. package/.framework/src/components/ui/table.tsx +161 -9
  196. package/.framework/src/components/ui/tabs.tsx +113 -6
  197. package/.framework/src/components/ui/textarea.tsx +49 -2
  198. package/.framework/src/components/ui/toggle-group.tsx +81 -4
  199. package/.framework/src/components/ui/toggle.tsx +65 -3
  200. package/.framework/src/components/ui/tooltip.tsx +97 -5
  201. package/.framework/src/contexts/AppContext.tsx +129 -45
  202. package/.framework/src/contexts/AuthContext.tsx +187 -144
  203. package/.framework/src/hooks/use-mobile.ts +48 -2
  204. package/.framework/src/hooks/useApi.ts +208 -159
  205. package/.framework/src/hooks/useAppPath.ts +32 -23
  206. package/.framework/src/hooks/useApps.ts +51 -20
  207. package/.framework/src/hooks/useEntityList.ts +32 -78
  208. package/.framework/src/hooks/useEntityRecord.ts +35 -96
  209. package/.framework/src/hooks/useForm.ts +32 -92
  210. package/.framework/src/hooks/useListSchema.ts +49 -78
  211. package/.framework/src/hooks/useSchemaRecord.ts +114 -105
  212. package/.framework/src/lib/api.ts +195 -116
  213. package/.framework/src/lib/supabase.ts +98 -64
  214. package/.framework/src/lib/utils.ts +287 -151
  215. package/.framework/src/main.tsx +49 -3
  216. package/.framework/src/pages/DashboardPage.tsx +52 -29
  217. package/.framework/src/pages/NotFoundPage.tsx +32 -10
  218. package/.framework/src/pages/SetupPage.tsx +32 -12
  219. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
  220. package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
  221. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
  222. package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
  223. package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
  224. package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
  225. package/.framework/src/pages/admin/AppsPage.tsx +49 -2
  226. package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
  227. package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
  228. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
  229. package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
  230. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
  231. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
  232. package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
  233. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
  234. package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
  235. package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
  236. package/.framework/src/pages/admin/LogsPage.tsx +422 -75
  237. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
  238. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
  239. package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
  240. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
  241. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
  242. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
  243. package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
  244. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
  245. package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
  246. package/.framework/src/pages/admin/RolesPage.tsx +171 -18
  247. package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
  248. package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
  249. package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
  250. package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
  251. package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
  252. package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
  253. package/.framework/src/pages/admin/TimersPage.tsx +48 -20
  254. package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
  255. package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
  256. package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
  257. package/.framework/src/pages/admin/TypesPage.tsx +48 -20
  258. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
  259. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
  260. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
  261. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
  262. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
  263. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
  264. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
  265. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
  266. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
  267. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
  268. package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
  269. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
  270. package/.framework/src/pages/auth/LoginPage.tsx +50 -23
  271. package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
  272. package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
  273. package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
  274. package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
  275. package/.framework/src/types/auth.ts +128 -71
  276. package/.framework/src/types/types.ts +373 -157
  277. package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
  278. package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
  279. package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
  280. package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
  281. package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
  282. package/docs/README.md +9 -130
  283. package/netlify.toml +5 -2
  284. package/package.json +13 -25
  285. package/scripts/kb-ingest-docs.ts +203 -0
  286. package/spine.config.json +65 -4
  287. package/.framework/migrations/001_schema.sql +0 -425
  288. package/.framework/migrations/002_rls_and_functions.sql +0 -763
  289. package/.framework/migrations/004_enhancements.sql +0 -43
  290. package/.framework/migrations/005_auth_user_trigger.sql +0 -105
  291. package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
  292. package/.framework/migrations/016_invites.sql +0 -27
  293. package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
  294. package/.framework/migrations/018_apps_required_roles.sql +0 -17
  295. package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
  296. package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
  297. package/.framework/migrations/021_app_domains.sql +0 -112
  298. package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
  299. package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
  300. package/.framework/migrations/024_messages_account_id.sql +0 -9
  301. package/.framework/migrations/025_retype_threads_messages.sql +0 -240
  302. package/.framework/migrations/026_fix_rls_policies.sql +0 -47
  303. package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
  304. package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
  305. package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
  306. package/.framework/migrations/030_messages_updated_by.sql +0 -6
  307. package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
  308. package/docs/APPS.md +0 -232
  309. package/docs/ARCHITECTURE.md +0 -246
  310. package/docs/INSTALL.md +0 -155
  311. package/docs/design-schema-spec.md +0 -1837
  312. package/docs/dev-guides/01-create-an-app.md +0 -183
  313. package/docs/dev-guides/02-create-a-function.md +0 -178
  314. package/docs/dev-guides/03-create-a-component.md +0 -178
  315. package/docs/dev-guides/04-webhook-handlers.md +0 -129
  316. package/docs/dev-guides/05-testing.md +0 -168
  317. package/docs/dev-guides/README.md +0 -40
  318. package/docs/npm-packages-plan.md +0 -288
  319. package/docs/spine-core--api-reference.md +0 -822
@@ -0,0 +1,614 @@
1
+ // CIL[BEGIN chunk_id="cilprojectspage_module_header_1784193942" type="module_header" identity="module_header" parent="none"]
2
+ // CIL[DOC-MACRO purpose="Import dependencies and icons for the CIL projects page"]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Provides module imports and icon references used by CILProjectsPage"]
4
+ // CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
5
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
6
+ // CIL[DOC-MICRO logic_summary="Imports React hooks, router, apiFetch, useAppPath, shadcn UI components, and lucide icons" notable_decisions="[]"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
8
+ // CIL[DOC-STABILITY stability="stable"]
9
+ // CIL[DOC-AUDIENCE audience="developer"]
10
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.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"]
16
+ import { useEffect, useState } from 'react'
17
+ import { useNavigate } from 'react-router-dom'
18
+ import { apiFetch } from '@core/lib/api'
19
+ import { Card, CardContent, CardHeader, CardTitle } from '@core/components/ui/card'
20
+ import { Button } from '@core/components/ui/button'
21
+ import { Badge } from '@core/components/ui/badge'
22
+ import { Skeleton } from '@core/components/ui/skeleton'
23
+ import {
24
+ Dialog,
25
+ DialogContent,
26
+ DialogHeader,
27
+ DialogTitle,
28
+ DialogFooter,
29
+ } from '@core/components/ui/dialog'
30
+ import { Input } from '@core/components/ui/input'
31
+ import { Label } from '@core/components/ui/label'
32
+ import { Textarea } from '@core/components/ui/textarea'
33
+ import { NativeSelect, NativeSelectOption } from '@core/components/ui/native-select'
34
+ import { FolderGit2, Plus, Play, CheckCircle2, Clock, AlertCircle, GitGraph, LayoutDashboard, Trash2, Layers, Pencil, X } from 'lucide-react'
35
+
36
+ import { PageInstructions } from '../../../components/admin/PageInstructions'
37
+ // CIL[END chunk_id="cilprojectspage_module_header_1784193942"]
38
+ // CIL[BEGIN chunk_id="cilprojectspage_sourceset_1784193942" type="interface" identity="SourceSet" parent="none"]
39
+ // CIL[DOC-MACRO purpose="Declare the SourceSet data shape for ingestion configuration"]
40
+ // CIL[DOC-RESPONSIBILITY responsibility="Provides the TypeScript contract for a named source set within a CIL project"]
41
+ // CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
42
+ // CIL[DOC-CONTRACT inputs="none" outputs="SourceSet type definition" errors="none" side_effects="none"]
43
+ // CIL[DOC-MICRO logic_summary="Defines id, name, base_path, and optional globs, exclude_globs, and layer fields" notable_decisions="[]"]
44
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
45
+ // CIL[DOC-STABILITY stability="stable"]
46
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/schema-utils.ts, \."]
47
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
48
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
49
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
50
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
51
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
52
+ interface SourceSet {
53
+ id: string
54
+ name: string
55
+ base_path: string
56
+ globs?: string
57
+ exclude_globs?: string
58
+ layer?: string
59
+ }
60
+
61
+ // CIL[END chunk_id="cilprojectspage_sourceset_1784193942"]
62
+ // CIL[BEGIN chunk_id="cilprojectspage_cilproject_1784193942" type="interface" identity="CILProject" parent="none"]
63
+ // CIL[DOC-MACRO purpose="Declare the CILProject data shape for project listing and management"]
64
+ // CIL[DOC-RESPONSIBILITY responsibility="Provides the TypeScript contract for CIL project records including ingestion metadata"]
65
+ // CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\"\\\"]"]
66
+ // CIL[DOC-CONTRACT inputs="none" outputs="CILProject type definition" errors="none" side_effects="none"]
67
+ // CIL[DOC-MICRO logic_summary="Defines id, title, description, status, and nested data with repo, language mix, status, counts, cost, timestamps, source sets, and dependencies" notable_decisions="[]"]
68
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
69
+ // CIL[DOC-STABILITY stability="stable"]
70
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, \."]
71
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
72
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
73
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
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
+ interface CILProject {
77
+ id: string
78
+ title: string
79
+ description: string
80
+ status: string
81
+ data: {
82
+ repo_path: string
83
+ language_mix: string
84
+ ingestion_status: 'not_started' | 'in_progress' | 'complete'
85
+ file_count: number
86
+ chunk_count: number
87
+ total_ingestion_cost_usd: number
88
+ last_ingested_at: string | null
89
+ source_sets?: SourceSet[]
90
+ dependencies?: string[]
91
+ }
92
+ created_at: string
93
+ }
94
+
95
+ // CIL[END chunk_id="cilprojectspage_cilproject_1784193942"]
96
+ // CIL[BEGIN chunk_id="cilprojectspage_status_badge_1784193942" type="constant" identity="STATUS_BADGE" parent="none"]
97
+ // CIL[DOC-MACRO purpose="Map ingestion status strings to badge labels and variants"]
98
+ // CIL[DOC-RESPONSIBILITY responsibility="Supplies visual badge configuration for project ingestion status"]
99
+ // CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
100
+ // CIL[DOC-CONTRACT inputs="none" outputs="STATUS_BADGE mapping" errors="none" side_effects="none"]
101
+ // CIL[DOC-MICRO logic_summary="Maps not_started, in_progress, and complete to label text and shadcn Badge variant values" notable_decisions="[]"]
102
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
103
+ // CIL[DOC-STABILITY stability="stable"]
104
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/functions/custom_cil-embeddings.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
105
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
106
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
107
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
108
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
109
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
110
+ const STATUS_BADGE: Record<string, { label: string; variant: 'default' | 'secondary' | 'outline' }> = {
111
+ not_started: { label: 'Not Started', variant: 'outline' },
112
+ in_progress: { label: 'In Progress', variant: 'secondary' },
113
+ complete: { label: 'Complete', variant: 'default' },
114
+ }
115
+
116
+ // CIL[END chunk_id="cilprojectspage_status_badge_1784193942"]
117
+ // CIL[BEGIN chunk_id="cilprojectspage_status_icon_1784193942" type="constant" identity="STATUS_ICON" parent="none"]
118
+ // CIL[DOC-MACRO purpose="Map ingestion status strings to icon components"]
119
+ // CIL[DOC-RESPONSIBILITY responsibility="Supplies the icon component used for each project ingestion status"]
120
+ // CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[]"]
121
+ // CIL[DOC-CONTRACT inputs="none" outputs="STATUS_ICON mapping of React.ElementType" errors="none" side_effects="none"]
122
+ // CIL[DOC-MICRO logic_summary="Maps not_started to Clock, in_progress to AlertCircle, and complete to CheckCircle2" notable_decisions="[]"]
123
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
124
+ // CIL[DOC-STABILITY stability="stable"]
125
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
126
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
127
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
128
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
129
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
130
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
131
+ const STATUS_ICON: Record<string, React.ElementType> = {
132
+ not_started: Clock,
133
+ in_progress: AlertCircle,
134
+ complete: CheckCircle2,
135
+ }
136
+
137
+ // CIL[END chunk_id="cilprojectspage_status_icon_1784193942"]
138
+ // CIL[BEGIN chunk_id="cilprojectspage_cilprojectspage_1784193942" type="component" identity="CILProjectsPage" parent="none"]
139
+ // CIL[DOC-MACRO purpose="Render the CIL projects list with creation, editing, and deletion workflows"]
140
+ // CIL[DOC-RESPONSIBILITY responsibility="Manage CIL project list state and render project cards, dialogs, and navigation"]
141
+ // CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[]"]
142
+ // CIL[DOC-CONTRACT inputs="none" outputs="JSX.Element" errors="API errors are silently caught; required fields block save" side_effects="Calls /api/cil-project actions and navigates to /cil/:id routes"]
143
+ // CIL[DOC-MICRO logic_summary="Fetches projects on mount, displays loading/empty/card states, manages create/edit form with source sets, and navigates to ingest, dashboard, files, and graph pages" notable_decisions="[]"]
144
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
145
+ // CIL[DOC-STABILITY stability="stable"]
146
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
147
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
148
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
149
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
150
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
151
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
152
+ export default function CILProjectsPage() {
153
+ const navigate = useNavigate()
154
+ const appPath = (path: string) => '/spine-framework/admin' + (path.startsWith('/') ? path : '/' + path)
155
+ const [projects, setProjects] = useState<CILProject[]>([])
156
+ const [loading, setLoading] = useState(true)
157
+ const [showCreate, setShowCreate] = useState(false)
158
+ const [creating, setCreating] = useState(false)
159
+ const [confirmDeleteId, setConfirmDeleteId] = useState<string | null>(null)
160
+ const [deleting, setDeleting] = useState(false)
161
+ const [form, setForm] = useState({ name: '', description: '', repo_path: '', language_mix: '', source_sets: [] as SourceSet[] })
162
+ const [editingProjectId, setEditingProjectId] = useState<string | null>(null)
163
+
164
+ const fetchProjects = () => {
165
+ setLoading(true)
166
+ apiFetch('/api/cil-project?action=list')
167
+ .then(r => r.json())
168
+ .then(data => setProjects(data?.projects || data?.data?.projects || []))
169
+ .catch(() => {})
170
+ .finally(() => setLoading(false))
171
+ }
172
+
173
+ useEffect(() => { fetchProjects() }, [])
174
+
175
+ const handleSave = async () => {
176
+ if (!form.name || !form.repo_path) return
177
+ setCreating(true)
178
+ try {
179
+ const payload: Record<string, any> = {
180
+ name: form.name,
181
+ description: form.description,
182
+ repo_path: form.repo_path,
183
+ language_mix: form.language_mix,
184
+ }
185
+ if (form.source_sets && form.source_sets.length > 0) {
186
+ payload.source_sets = form.source_sets.map(ss => ({
187
+ ...ss,
188
+ globs: ss.globs ? ss.globs.split(',').map(s => s.trim()).filter(Boolean) : undefined,
189
+ exclude_globs: ss.exclude_globs ? ss.exclude_globs.split(',').map(s => s.trim()).filter(Boolean) : undefined,
190
+ }))
191
+ }
192
+
193
+ let res: Response
194
+ if (editingProjectId) {
195
+ res = await apiFetch(`/api/cil-project?action=update&id=${editingProjectId}`, {
196
+ method: 'PATCH',
197
+ headers: { 'Content-Type': 'application/json' },
198
+ body: JSON.stringify({ data: payload }),
199
+ })
200
+ } else {
201
+ res = await apiFetch('/api/cil-project?action=create', {
202
+ method: 'POST',
203
+ headers: { 'Content-Type': 'application/json' },
204
+ body: JSON.stringify(payload),
205
+ })
206
+ }
207
+
208
+ const data = await res.json()
209
+ const newId = data?.project?.id || data?.data?.project?.id
210
+ setShowCreate(false)
211
+ setEditingProjectId(null)
212
+ setForm({ name: '', description: '', repo_path: '', language_mix: '', source_sets: [] })
213
+ if (newId && !editingProjectId) {
214
+ navigate(appPath(`/cil/${newId}/ingest`))
215
+ } else {
216
+ fetchProjects()
217
+ }
218
+ } catch {
219
+ } finally {
220
+ setCreating(false)
221
+ }
222
+ }
223
+
224
+ const openCreate = () => {
225
+ setEditingProjectId(null)
226
+ setForm({ name: '', description: '', repo_path: '', language_mix: '', source_sets: [] })
227
+ setShowCreate(true)
228
+ }
229
+
230
+ const openEdit = (project: CILProject) => {
231
+ setEditingProjectId(project.id)
232
+ setForm({
233
+ name: project.title,
234
+ description: project.description,
235
+ repo_path: project.data?.repo_path || '',
236
+ language_mix: project.data?.language_mix || '',
237
+ source_sets: (project.data?.source_sets || []).map(ss => ({
238
+ ...ss,
239
+ globs: Array.isArray(ss.globs) ? ss.globs.join(', ') : ss.globs || '',
240
+ exclude_globs: Array.isArray(ss.exclude_globs) ? ss.exclude_globs.join(', ') : ss.exclude_globs || '',
241
+ })),
242
+ })
243
+ openCreate()
244
+ }
245
+
246
+ const handleDeleteProject = async () => {
247
+ if (!confirmDeleteId) return
248
+ setDeleting(true)
249
+ try {
250
+ await apiFetch(`/api/cil-project?action=delete&id=${confirmDeleteId}`, {
251
+ method: 'DELETE',
252
+ })
253
+ setConfirmDeleteId(null)
254
+ fetchProjects()
255
+ } catch {
256
+ } finally {
257
+ setDeleting(false)
258
+ }
259
+ }
260
+
261
+ return (
262
+ <div className="p-6 space-y-6">
263
+ <div className="flex items-center justify-between">
264
+ <div>
265
+ <h1 className="text-2xl font-bold flex items-center gap-2">
266
+ <FolderGit2 className="h-6 w-6 text-indigo-500" />
267
+ Code Intelligence Layer
268
+ </h1>
269
+ <p className="text-muted-foreground text-sm mt-1">
270
+ Register codebases, run ingestion passes, and query the code graph
271
+ </p>
272
+ </div>
273
+ <Button onClick={() => openCreate()}>
274
+ <Plus className="h-4 w-4 mr-2" />
275
+ New Project
276
+ </Button>
277
+ </div>
278
+
279
+ <PageInstructions
280
+ description="Manage CIL projects and registered codebases."
281
+ sections={[
282
+ { title: 'What this page is for', content: 'Projects represent codebases that the CIL has indexed. This page lists all projects, their ingestion status, and quick stats.' },
283
+ { title: 'How to read this page', content: 'Each card shows the project title, repository path, status badge, and counts for files, chunks, and cumulative ingestion cost. Click a card to open the project.' },
284
+ { title: 'How to create / manage', content: 'Click New Project to register a codebase. Open a project to run ingestion, inspect the graph, or use the agent. Use the dashboard or ingestion tabs for detailed status.' },
285
+ { title: 'Important notes', content: 'The status badge reflects the latest ingestion pass. Costs are cumulative across all runs and include embedding and documentation generation.' },
286
+ ]}
287
+ />
288
+
289
+ {loading ? (
290
+ <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
291
+ {[1, 2, 3].map(i => <Skeleton key={i} className="h-44 rounded-xl" />)}
292
+ </div>
293
+ ) : projects.length === 0 ? (
294
+ <div className="flex flex-col items-center justify-center py-24 text-center space-y-3">
295
+ <FolderGit2 className="h-12 w-12 text-muted-foreground/40" />
296
+ <p className="text-muted-foreground">No projects yet. Register a codebase to get started.</p>
297
+ <Button variant="outline" onClick={() => openCreate()}>
298
+ <Plus className="h-4 w-4 mr-2" />
299
+ New Project
300
+ </Button>
301
+ </div>
302
+ ) : (
303
+ <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
304
+ {projects.map(project => {
305
+ const ingestionStatus = project.data?.ingestion_status || 'not_started'
306
+ const { label, variant } = STATUS_BADGE[ingestionStatus] || STATUS_BADGE.not_started
307
+ const StatusIcon = STATUS_ICON[ingestionStatus] || Clock
308
+
309
+ return (
310
+ <Card
311
+ key={project.id}
312
+ className="cursor-pointer hover:shadow-md transition-shadow"
313
+ onClick={() => navigate(appPath(`/cil/${project.id}/ingest`))}
314
+ >
315
+ <CardHeader className="pb-2">
316
+ <div className="flex items-start justify-between gap-2">
317
+ <CardTitle className="text-base">{project.title}</CardTitle>
318
+ <Badge variant={variant} className="shrink-0 flex items-center gap-1">
319
+ <StatusIcon className="h-3 w-3" />
320
+ {label}
321
+ </Badge>
322
+ </div>
323
+ <p className="text-xs text-muted-foreground font-mono truncate">
324
+ {project.data?.repo_path || '—'}
325
+ </p>
326
+ </CardHeader>
327
+ <CardContent className="space-y-3">
328
+ {project.description && (
329
+ <p className="text-sm text-muted-foreground line-clamp-2">{project.description}</p>
330
+ )}
331
+ <div className="grid grid-cols-3 gap-2 pt-1">
332
+ <div className="text-center">
333
+ <div className="text-xl font-bold">{project.data?.file_count ?? 0}</div>
334
+ <div className="text-xs text-muted-foreground">Files</div>
335
+ </div>
336
+ <div className="text-center">
337
+ <div className="text-xl font-bold">{project.data?.chunk_count ?? 0}</div>
338
+ <div className="text-xs text-muted-foreground">Chunks</div>
339
+ </div>
340
+ <div className="text-center">
341
+ <div className="text-xl font-bold">
342
+ ${(project.data?.total_ingestion_cost_usd ?? 0).toFixed(2)}
343
+ </div>
344
+ <div className="text-xs text-muted-foreground">Cost</div>
345
+ </div>
346
+ </div>
347
+ {project.data?.language_mix && (
348
+ <p className="text-xs text-muted-foreground">{project.data.language_mix}</p>
349
+ )}
350
+ <div className="flex gap-2">
351
+ <Button
352
+ size="sm"
353
+ variant="outline"
354
+ className="flex-1"
355
+ onClick={e => {
356
+ e.stopPropagation()
357
+ navigate(appPath(`/cil/${project.id}/ingest`))
358
+ }}
359
+ >
360
+ <Play className="h-3 w-3 mr-1" />
361
+ Run Pipeline
362
+ </Button>
363
+ <Button
364
+ size="sm"
365
+ variant="ghost"
366
+ className="px-2"
367
+ onClick={e => {
368
+ e.stopPropagation()
369
+ navigate(appPath(`/cil/${project.id}/dashboard`))
370
+ }}
371
+ title="Dashboard"
372
+ >
373
+ <LayoutDashboard className="h-3.5 w-3.5" />
374
+ </Button>
375
+ <Button
376
+ size="sm"
377
+ variant="ghost"
378
+ className="px-2"
379
+ onClick={e => {
380
+ e.stopPropagation()
381
+ navigate(appPath(`/cil/${project.id}/files`))
382
+ }}
383
+ title="Browse Files"
384
+ >
385
+ <Layers className="h-3.5 w-3.5" />
386
+ </Button>
387
+ <Button
388
+ size="sm"
389
+ variant="ghost"
390
+ className="px-2"
391
+ onClick={e => {
392
+ e.stopPropagation()
393
+ navigate(appPath(`/cil/${project.id}/graph`))
394
+ }}
395
+ title="View Graph"
396
+ >
397
+ <GitGraph className="h-3.5 w-3.5" />
398
+ </Button>
399
+ <Button
400
+ size="sm"
401
+ variant="ghost"
402
+ className="px-2"
403
+ onClick={e => {
404
+ e.stopPropagation()
405
+ openEdit(project)
406
+ }}
407
+ title="Edit project"
408
+ >
409
+ <Pencil className="h-3.5 w-3.5" />
410
+ </Button>
411
+ <Button
412
+ size="sm"
413
+ variant="ghost"
414
+ className="px-2 text-destructive hover:text-destructive hover:bg-destructive/10"
415
+ onClick={e => {
416
+ e.stopPropagation()
417
+ setConfirmDeleteId(project.id)
418
+ }}
419
+ title="Delete project"
420
+ >
421
+ <Trash2 className="h-3.5 w-3.5" />
422
+ </Button>
423
+ </div>
424
+ </CardContent>
425
+ </Card>
426
+ )
427
+ })}
428
+ </div>
429
+ )}
430
+
431
+ {}
432
+ <Dialog open={showCreate} onOpenChange={open => { if (!open) { setEditingProjectId(null); setForm({ name: '', description: '', repo_path: '', language_mix: '', source_sets: [] }) } setShowCreate(open) }}>
433
+ <DialogContent className="max-w-2xl max-h-[85vh] overflow-y-auto">
434
+ <DialogHeader>
435
+ <DialogTitle>{editingProjectId ? 'Edit CIL Project' : 'Register New CIL Project'}</DialogTitle>
436
+ </DialogHeader>
437
+ <div className="space-y-4 py-2">
438
+ <div className="space-y-1.5">
439
+ <Label htmlFor="name">Project Name *</Label>
440
+ <Input
441
+ id="name"
442
+ placeholder="spine-ia"
443
+ value={form.name}
444
+ onChange={e => setForm(f => ({ ...f, name: e.target.value }))}
445
+ />
446
+ </div>
447
+ <div className="space-y-1.5">
448
+ <Label htmlFor="repo_path">Repository Path *</Label>
449
+ <Input
450
+ id="repo_path"
451
+ placeholder="/Users/thistle/CascadeProjects/spine-ia"
452
+ value={form.repo_path}
453
+ onChange={e => setForm(f => ({ ...f, repo_path: e.target.value }))}
454
+ />
455
+ <p className="text-xs text-muted-foreground">Absolute path to the repository root on the agent's filesystem</p>
456
+ </div>
457
+ {editingProjectId && (
458
+ <>
459
+ <div className="space-y-1.5">
460
+ <Label htmlFor="language_mix">Languages</Label>
461
+ <Input
462
+ id="language_mix"
463
+ placeholder="TypeScript, SQL"
464
+ value={form.language_mix}
465
+ onChange={e => setForm(f => ({ ...f, language_mix: e.target.value }))}
466
+ />
467
+ </div>
468
+ <div className="space-y-1.5">
469
+ <Label htmlFor="description">Description</Label>
470
+ <Textarea
471
+ id="description"
472
+ placeholder="Spine framework — multi-tenant SaaS platform"
473
+ value={form.description}
474
+ onChange={e => setForm(f => ({ ...f, description: e.target.value }))}
475
+ rows={3}
476
+ />
477
+ </div>
478
+ </>
479
+ )}
480
+
481
+ {}
482
+ {editingProjectId && <div className="space-y-2 pt-2 border-t">
483
+ <div className="flex items-center justify-between">
484
+ <Label>Source Sets</Label>
485
+ <Button
486
+ type="button"
487
+ size="sm"
488
+ variant="outline"
489
+ onClick={() => setForm(f => ({
490
+ ...f,
491
+ source_sets: [...f.source_sets, { id: crypto.randomUUID(), name: '', base_path: '', globs: '', exclude_globs: '', layer: 'app-specific' }],
492
+ }))}
493
+ >
494
+ <Plus className="h-3 w-3 mr-1" /> Add Source Set
495
+ </Button>
496
+ </div>
497
+ <p className="text-xs text-muted-foreground">
498
+ Optional. Leave empty to use the default globs. Each source set defines a base path relative to the repo root, its own globs/excludes, and an architectural layer.
499
+ </p>
500
+ {form.source_sets.length === 0 && (
501
+ <p className="text-xs text-muted-foreground italic">No source sets — default globs will be used.</p>
502
+ )}
503
+ {form.source_sets.map((ss, idx) => (
504
+ <div key={ss.id} className="border rounded-md p-3 space-y-2 bg-muted/30">
505
+ <div className="flex items-center justify-between gap-2">
506
+ <Input
507
+ placeholder="Set name"
508
+ value={ss.name}
509
+ onChange={e => setForm(f => {
510
+ const next = [...f.source_sets]
511
+ next[idx] = { ...next[idx], name: e.target.value }
512
+ return { ...f, source_sets: next }
513
+ })}
514
+ className="text-sm"
515
+ />
516
+ <Button
517
+ type="button"
518
+ size="sm"
519
+ variant="ghost"
520
+ className="text-destructive hover:text-destructive hover:bg-destructive/10 shrink-0"
521
+ onClick={() => setForm(f => ({ ...f, source_sets: f.source_sets.filter((_, i) => i !== idx) }))}
522
+ >
523
+ <X className="h-3.5 w-3.5" />
524
+ </Button>
525
+ </div>
526
+ <div className="grid grid-cols-2 gap-2">
527
+ <Input
528
+ placeholder="Base path (relative to repo)"
529
+ value={ss.base_path}
530
+ onChange={e => setForm(f => {
531
+ const next = [...f.source_sets]
532
+ next[idx] = { ...next[idx], base_path: e.target.value }
533
+ return { ...f, source_sets: next }
534
+ })}
535
+ className="text-xs font-mono"
536
+ />
537
+ <NativeSelect
538
+ value={ss.layer || 'app-specific'}
539
+ onChange={e => setForm(f => {
540
+ const next = [...f.source_sets]
541
+ next[idx] = { ...next[idx], layer: e.target.value }
542
+ return { ...f, source_sets: next }
543
+ })}
544
+ className="text-xs"
545
+ >
546
+ <NativeSelectOption value="shared-core">shared-core</NativeSelectOption>
547
+ <NativeSelectOption value="app-specific">app-specific</NativeSelectOption>
548
+ <NativeSelectOption value="infrastructure">infrastructure</NativeSelectOption>
549
+ <NativeSelectOption value="test">test</NativeSelectOption>
550
+ </NativeSelect>
551
+ </div>
552
+ <Input
553
+ placeholder="Globs, comma-separated (e.g. **/*.ts, **/*.tsx)"
554
+ value={ss.globs || ''}
555
+ onChange={e => setForm(f => {
556
+ const next = [...f.source_sets]
557
+ next[idx] = { ...next[idx], globs: e.target.value }
558
+ return { ...f, source_sets: next }
559
+ })}
560
+ className="text-xs font-mono"
561
+ />
562
+ <Input
563
+ placeholder="Exclude globs, comma-separated (optional)"
564
+ value={ss.exclude_globs || ''}
565
+ onChange={e => setForm(f => {
566
+ const next = [...f.source_sets]
567
+ next[idx] = { ...next[idx], exclude_globs: e.target.value }
568
+ return { ...f, source_sets: next }
569
+ })}
570
+ className="text-xs font-mono"
571
+ />
572
+ </div>
573
+ ))}
574
+ </div>}
575
+ </div>
576
+ <DialogFooter>
577
+ <Button variant="outline" onClick={() => setShowCreate(false)}>Cancel</Button>
578
+ <Button
579
+ onClick={handleSave}
580
+ disabled={creating || !form.name || !form.repo_path}
581
+ >
582
+ {creating ? 'Saving…' : (editingProjectId ? 'Save Project' : 'Create Project')}
583
+ </Button>
584
+ </DialogFooter>
585
+ </DialogContent>
586
+ </Dialog>
587
+
588
+ {}
589
+ <Dialog open={!!confirmDeleteId} onOpenChange={open => { if (!open) setConfirmDeleteId(null) }}>
590
+ <DialogContent>
591
+ <DialogHeader>
592
+ <DialogTitle className="text-destructive flex items-center gap-2">
593
+ <Trash2 className="h-4 w-4" /> Delete Project
594
+ </DialogTitle>
595
+ </DialogHeader>
596
+ <p className="text-sm text-muted-foreground">
597
+ This will permanently delete the project and <strong>all associated files, chunks, proposals, embeddings, and graph links</strong>. This action cannot be undone.
598
+ </p>
599
+ <p className="text-sm font-medium">
600
+ Project: <span className="font-mono">{projects.find(p => p.id === confirmDeleteId)?.title || confirmDeleteId}</span>
601
+ </p>
602
+ <DialogFooter>
603
+ <Button variant="outline" onClick={() => setConfirmDeleteId(null)} disabled={deleting}>Cancel</Button>
604
+ <Button variant="destructive" onClick={handleDeleteProject} disabled={deleting}>
605
+ {deleting ? 'Deleting…' : 'Delete Project'}
606
+ </Button>
607
+ </DialogFooter>
608
+ </DialogContent>
609
+ </Dialog>
610
+ </div>
611
+ )
612
+ }
613
+
614
+ // CIL[END chunk_id="cilprojectspage_cilprojectspage_1784193942"]