spine-framework 0.3.125 → 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 +169 -97
  6. package/.framework/cli/commands/generate.ts +82 -160
  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} +147 -54
  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 +222 -347
  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 +162 -14
  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 +687 -533
  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 +173 -145
  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 +192 -115
  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 +3 -3
  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,616 @@
1
+ // CIL[BEGIN chunk_id="cilgraphpage_module_header_1784193942" type="module_header" identity="module_header" parent="none"]
2
+ // CIL[DOC-MACRO purpose="Imports and dependencies for the CIL graph visualization page"]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Declare external libraries, hooks, UI components, and icons used by CILGraphPage"]
4
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" 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="imported modules and types" errors="none" side_effects="none"]
6
+ // CIL[DOC-MICRO logic_summary="Aggregates React, react-router, XYFlow, dagre, internal api/hooks, UI primitives, 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, useCallback } from 'react'
17
+ import { useParams } from 'react-router-dom'
18
+ import {
19
+ ReactFlow,
20
+ Background,
21
+ Controls,
22
+ MiniMap,
23
+ useNodesState,
24
+ useEdgesState,
25
+ addEdge,
26
+ type Node,
27
+ type Edge,
28
+ type Connection,
29
+ MarkerType,
30
+ Panel,
31
+ } from '@xyflow/react'
32
+ import '@xyflow/react/dist/style.css'
33
+ import dagre from 'dagre'
34
+ import { apiFetch } from '@core/lib/api'
35
+ import { Button } from '@core/components/ui/button'
36
+ import { Badge } from '@core/components/ui/badge'
37
+ import { Skeleton } from '@core/components/ui/skeleton'
38
+ import {
39
+ Select,
40
+ SelectContent,
41
+ SelectItem,
42
+ SelectTrigger,
43
+ SelectValue,
44
+ } from '@core/components/ui/select'
45
+ import { RefreshCw, ChevronRight, ZoomIn, Layers } from 'lucide-react'
46
+
47
+
48
+
49
+ import { PageInstructions } from '../../../components/admin/PageInstructions'
50
+ // CIL[END chunk_id="cilgraphpage_module_header_1784193942"]
51
+ // CIL[BEGIN chunk_id="cilgraphpage_node_width_1784193942" type="constant" identity="NODE_WIDTH" parent="none"]
52
+ // CIL[DOC-MACRO purpose="Define default width for chunk graph nodes"]
53
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide constant node width used in layout and rendering"]
54
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
55
+ // CIL[DOC-CONTRACT inputs="none" outputs="NODE_WIDTH number" errors="none" side_effects="none"]
56
+ // CIL[DOC-MICRO logic_summary="Declares a fixed width of 180 pixels for chunk nodes." notable_decisions="[]"]
57
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
58
+ // CIL[DOC-STABILITY stability="stable"]
59
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
60
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
61
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
62
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
63
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
64
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
65
+ const NODE_WIDTH = 180
66
+ // CIL[END chunk_id="cilgraphpage_node_width_1784193942"]
67
+ // CIL[BEGIN chunk_id="cilgraphpage_node_height_1784193942" type="constant" identity="NODE_HEIGHT" parent="none"]
68
+ // CIL[DOC-MACRO purpose="Define default height for chunk graph nodes"]
69
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide constant node height used in layout and rendering"]
70
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
71
+ // CIL[DOC-CONTRACT inputs="none" outputs="NODE_HEIGHT number" errors="none" side_effects="none"]
72
+ // CIL[DOC-MICRO logic_summary="Declares a fixed height of 60 pixels for chunk nodes." notable_decisions="[]"]
73
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
74
+ // CIL[DOC-STABILITY stability="stable"]
75
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
76
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
77
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
78
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
79
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
80
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
81
+ const NODE_HEIGHT = 60
82
+ // CIL[END chunk_id="cilgraphpage_node_height_1784193942"]
83
+ // CIL[BEGIN chunk_id="cilgraphpage_file_width_1784193942" type="constant" identity="FILE_WIDTH" parent="none"]
84
+ // CIL[DOC-MACRO purpose="Define default width for file graph nodes"]
85
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide constant file node width used in layout and rendering"]
86
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
87
+ // CIL[DOC-CONTRACT inputs="none" outputs="FILE_WIDTH number" errors="none" side_effects="none"]
88
+ // CIL[DOC-MICRO logic_summary="Declares a fixed width of 200 pixels for file nodes." notable_decisions="[]"]
89
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
90
+ // CIL[DOC-STABILITY stability="stable"]
91
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
92
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
93
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
94
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
95
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
96
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
97
+ const FILE_WIDTH = 200
98
+ // CIL[END chunk_id="cilgraphpage_file_width_1784193942"]
99
+ // CIL[BEGIN chunk_id="cilgraphpage_file_height_1784193942" type="constant" identity="FILE_HEIGHT" parent="none"]
100
+ // CIL[DOC-MACRO purpose="Define default height for file graph nodes"]
101
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide constant file node height used in layout and rendering"]
102
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
103
+ // CIL[DOC-CONTRACT inputs="none" outputs="FILE_HEIGHT number" errors="none" side_effects="none"]
104
+ // CIL[DOC-MICRO logic_summary="Declares a fixed height of 40 pixels for file nodes." notable_decisions="[]"]
105
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
106
+ // CIL[DOC-STABILITY stability="stable"]
107
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
108
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
109
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
110
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
111
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
112
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
113
+ const FILE_HEIGHT = 40
114
+
115
+ // CIL[END chunk_id="cilgraphpage_file_height_1784193942"]
116
+ // CIL[BEGIN chunk_id="cilgraphpage_viewmode_1784193942" type="type" identity="ViewMode" parent="none"]
117
+ // CIL[DOC-MACRO purpose="Enumerate valid graph view modes"]
118
+ // CIL[DOC-RESPONSIBILITY responsibility="Type alias restricting view mode values"]
119
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[]"]
120
+ // CIL[DOC-CONTRACT inputs="none" outputs="ViewMode union type" errors="none" side_effects="none"]
121
+ // CIL[DOC-MICRO logic_summary="Defines allowed view modes for the graph: files, chunks, or mixed." notable_decisions="[]"]
122
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
123
+ // CIL[DOC-STABILITY stability="stable"]
124
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
125
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
126
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
127
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
128
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
129
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
130
+ type ViewMode = 'files' | 'chunks' | 'mixed'
131
+
132
+ // CIL[END chunk_id="cilgraphpage_viewmode_1784193942"]
133
+ // CIL[BEGIN chunk_id="cilgraphpage_layoutgraph_1784193942" type="function" identity="layoutGraph" parent="none"]
134
+ // CIL[DOC-MACRO purpose="Compute directed graph layout for React Flow nodes and edges"]
135
+ // CIL[DOC-RESPONSIBILITY responsibility="Arrange nodes using Dagre left-to-right layout and return positioned elements"]
136
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[]"]
137
+ // CIL[DOC-CONTRACT inputs="none" outputs="{nodes: Node[]; edges: Edge[]}" errors="none" side_effects="none"]
138
+ // CIL[DOC-MICRO logic_summary="Builds a dagre graph, sets LR options, adds nodes/edges with dynamic widths/heights, runs layout, then centers each node by subtracting half its size." notable_decisions="['Uses file dimensions for file nodes and chunk dimensions otherwise','Centers node positions by subtracting half width/height']"]
139
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
140
+ // CIL[DOC-STABILITY stability="stable"]
141
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
142
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
143
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
144
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
145
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
146
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
147
+ function layoutGraph(nodes: Node[], edges: Edge[]): { nodes: Node[]; edges: Edge[] } {
148
+ const g = new dagre.graphlib.Graph()
149
+ g.setDefaultEdgeLabel(() => ({}))
150
+ g.setGraph({ rankdir: 'LR', nodesep: 40, ranksep: 80 })
151
+
152
+ for (const node of nodes) {
153
+ g.setNode(node.id, { width: node.data?.isFile ? FILE_WIDTH : NODE_WIDTH, height: node.data?.isFile ? FILE_HEIGHT : NODE_HEIGHT })
154
+ }
155
+ for (const edge of edges) {
156
+ g.setEdge(edge.source, edge.target)
157
+ }
158
+
159
+ dagre.layout(g)
160
+
161
+ const positionedNodes = nodes.map(node => {
162
+ const pos = g.node(node.id)
163
+ const w = node.data?.isFile ? FILE_WIDTH : NODE_WIDTH
164
+ const h = node.data?.isFile ? FILE_HEIGHT : NODE_HEIGHT
165
+ return { ...node, position: { x: pos.x - w / 2, y: pos.y - h / 2 } }
166
+ })
167
+
168
+ return { nodes: positionedNodes, edges }
169
+ }
170
+
171
+
172
+
173
+ // CIL[END chunk_id="cilgraphpage_layoutgraph_1784193942"]
174
+ // CIL[BEGIN chunk_id="cilgraphpage_chunk_type_colors_1784193942" type="constant" identity="CHUNK_TYPE_COLORS" parent="none"]
175
+ // CIL[DOC-MACRO purpose="Map chunk types to display colors"]
176
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide color palette for graph legend and node styling"]
177
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[]"]
178
+ // CIL[DOC-CONTRACT inputs="none" outputs="Record<string,string> color map" errors="none" side_effects="none"]
179
+ // CIL[DOC-MICRO logic_summary="Color lookup table mapping chunk type strings to hex colors for nodes and legend." notable_decisions="[]"]
180
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
181
+ // CIL[DOC-STABILITY stability="stable"]
182
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
183
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
184
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
185
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
186
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
187
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
188
+ const CHUNK_TYPE_COLORS: Record<string, string> = {
189
+ function: '#6366F1',
190
+ class: '#8B5CF6',
191
+ interface: '#10B981',
192
+ type: '#06B6D4',
193
+ component: '#F59E0B',
194
+ hook: '#EC4899',
195
+ route: '#EF4444',
196
+ config: '#64748B',
197
+ }
198
+
199
+ // CIL[END chunk_id="cilgraphpage_chunk_type_colors_1784193942"]
200
+ // CIL[BEGIN chunk_id="cilgraphpage_nodecolor_1784193942" type="function" identity="nodeColor" parent="none"]
201
+ // CIL[DOC-MACRO purpose="Resolve a display color for a graph node"]
202
+ // CIL[DOC-RESPONSIBILITY responsibility="Return the appropriate color based on file, dead-code, or chunk type"]
203
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[]"]
204
+ // CIL[DOC-CONTRACT inputs="none" outputs="hex color string" errors="none" side_effects="none"]
205
+ // CIL[DOC-MICRO logic_summary="Returns slate for file nodes, gray for dead code, or CHUNK_TYPE_COLORS lookup with an indigo fallback." notable_decisions="['Falls back to indigo when chunk type has no mapped color']"]
206
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
207
+ // CIL[DOC-STABILITY stability="stable"]
208
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
209
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
210
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
211
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
212
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
213
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
214
+ function nodeColor(node: Node): string {
215
+ if (node.data?.isFile) return '#1E293B'
216
+ if (node.data?.is_dead_code) return '#94A3B8'
217
+ return CHUNK_TYPE_COLORS[node.data?.chunk_type as string] || '#6366F1'
218
+ }
219
+
220
+
221
+
222
+ // CIL[END chunk_id="cilgraphpage_nodecolor_1784193942"]
223
+ // CIL[BEGIN chunk_id="cilgraphpage_projectgraph_1784193942" type="interface" identity="ProjectGraph" parent="none"]
224
+ // CIL[DOC-MACRO purpose="Describe the shape of the project graph API response"]
225
+ // CIL[DOC-RESPONSIBILITY responsibility="Define the TypeScript contract for nodes and edges data"]
226
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[]"]
227
+ // CIL[DOC-CONTRACT inputs="none" outputs="ProjectGraph interface" errors="none" side_effects="none"]
228
+ // CIL[DOC-MICRO logic_summary="Declares nodes containing files and chunks arrays and edges containing imports and calls arrays, using any for metadata extensibility." notable_decisions="['Uses any types for flexible API schema']"]
229
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
230
+ // CIL[DOC-STABILITY stability="stable"]
231
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
232
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
233
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
234
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
235
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
236
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
237
+ interface ProjectGraph {
238
+ nodes: {
239
+ files: any[]
240
+ chunks: any[]
241
+ }
242
+ edges: {
243
+ imports: { source_id: string; target_id: string; metadata?: any }[]
244
+ calls: { source_id: string; target_id: string; metadata?: any }[]
245
+ }
246
+ }
247
+
248
+ // CIL[END chunk_id="cilgraphpage_projectgraph_1784193942"]
249
+ // CIL[BEGIN chunk_id="cilgraphpage_buildflowgraph_1784193942" type="function" identity="buildFlowGraph" parent="none"]
250
+ // CIL[DOC-MACRO purpose="Build React Flow nodes and edges from project graph data"]
251
+ // CIL[DOC-RESPONSIBILITY responsibility="Transform ProjectGraph into React Flow elements per view mode"]
252
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[]"]
253
+ // CIL[DOC-CONTRACT inputs="none" outputs="{nodes: Node[]; edges: Edge[]}" errors="none" side_effects="none"]
254
+ // CIL[DOC-MICRO logic_summary="Constructs file and chunk nodes with styling, adds import and call edges, and applies layoutGraph to position the flow graph." notable_decisions="['Dashed edges for imports','Separate branching for files/chunks/mixed views','Labels call edges with callee_name']"]
255
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
256
+ // CIL[DOC-STABILITY stability="stable"]
257
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
258
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
259
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
260
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
261
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
262
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
263
+ function buildFlowGraph(graph: ProjectGraph, viewMode: ViewMode): { nodes: Node[]; edges: Edge[] } {
264
+ const nodes: Node[] = []
265
+ const edges: Edge[] = []
266
+
267
+ if (viewMode === 'files' || viewMode === 'mixed') {
268
+ for (const file of graph.nodes.files) {
269
+ nodes.push({
270
+ id: file.id,
271
+ type: 'default',
272
+ position: { x: 0, y: 0 },
273
+ data: {
274
+ label: file.file_path.split('/').pop() || file.file_path,
275
+ isFile: true,
276
+ file_path: file.file_path,
277
+ language: file.language,
278
+ chunk_count: file.chunk_count,
279
+ is_dead_code: file.is_dead_code,
280
+ },
281
+ style: {
282
+ background: file.is_dead_code ? '#64748B' : '#0F172A',
283
+ color: '#F8FAFC',
284
+ border: `2px solid ${file.is_dead_code ? '#475569' : '#334155'}`,
285
+ borderRadius: '6px',
286
+ fontSize: '11px',
287
+ fontFamily: 'monospace',
288
+ padding: '6px 10px',
289
+ width: FILE_WIDTH,
290
+ },
291
+ })
292
+ }
293
+
294
+ for (const imp of graph.edges.imports) {
295
+ edges.push({
296
+ id: `imp-${imp.source_id}-${imp.target_id}`,
297
+ source: imp.source_id,
298
+ target: imp.target_id,
299
+ type: 'smoothstep',
300
+ style: { stroke: '#334155', strokeWidth: 1.5, strokeDasharray: '4,3' },
301
+ markerEnd: { type: MarkerType.ArrowClosed, width: 12, height: 12, color: '#334155' },
302
+ label: imp.metadata?.symbols?.slice(0, 2).join(', ') || '',
303
+ labelStyle: { fontSize: 9, fill: '#94A3B8' },
304
+ })
305
+ }
306
+ }
307
+
308
+ if (viewMode === 'chunks' || viewMode === 'mixed') {
309
+ for (const chunk of graph.nodes.chunks) {
310
+ const color = chunk.is_dead_code ? '#94A3B8' : (CHUNK_TYPE_COLORS[chunk.chunk_type] || '#6366F1')
311
+ nodes.push({
312
+ id: chunk.id,
313
+ type: 'default',
314
+ position: { x: 0, y: 0 },
315
+ data: {
316
+ label: chunk.chunk_name,
317
+ isFile: false,
318
+ chunk_type: chunk.chunk_type,
319
+ file_path: chunk.file_path,
320
+ doc_confidence: chunk.doc_confidence,
321
+ boundary_confidence: chunk.boundary_confidence,
322
+ is_dead_code: chunk.is_dead_code,
323
+ stored_hash: chunk.stored_hash,
324
+ },
325
+ style: {
326
+ background: color + '22',
327
+ color: '#1E293B',
328
+ border: `2px solid ${color}`,
329
+ borderRadius: '8px',
330
+ fontSize: '11px',
331
+ fontFamily: 'monospace',
332
+ padding: '8px 12px',
333
+ width: NODE_WIDTH,
334
+ opacity: chunk.is_dead_code ? 0.5 : 1,
335
+ },
336
+ })
337
+ }
338
+
339
+ for (const call of graph.edges.calls) {
340
+ edges.push({
341
+ id: `call-${call.source_id}-${call.target_id}`,
342
+ source: call.source_id,
343
+ target: call.target_id,
344
+ type: 'smoothstep',
345
+ style: { stroke: '#6366F1', strokeWidth: 1.5 },
346
+ markerEnd: { type: MarkerType.ArrowClosed, width: 12, height: 12, color: '#6366F1' },
347
+ label: call.metadata?.callee_name || '',
348
+ labelStyle: { fontSize: 9, fill: '#6366F1' },
349
+ })
350
+ }
351
+ }
352
+
353
+ return layoutGraph(nodes, edges)
354
+ }
355
+
356
+
357
+
358
+ // CIL[END chunk_id="cilgraphpage_buildflowgraph_1784193942"]
359
+ // CIL[BEGIN chunk_id="cilgraphpage_nodedetailpanel_1784193942" type="function" identity="NodeDetailPanel" parent="none"]
360
+ // CIL[DOC-MACRO purpose="Render metadata for a selected graph node"]
361
+ // CIL[DOC-RESPONSIBILITY responsibility="Display file or chunk details and a link to the chunk contract page"]
362
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[]"]
363
+ // CIL[DOC-CONTRACT inputs="none" outputs="JSX.Element" errors="none" side_effects="none"]
364
+ // CIL[DOC-MICRO logic_summary="Renders a placeholder or file/chunk metadata, including badges for dead code, doc confidence, and stored hash, plus a contract link." notable_decisions="['Casts node.data as any for flexible field access']"]
365
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
366
+ // CIL[DOC-STABILITY stability="stable"]
367
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
368
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
369
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
370
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
371
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
372
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
373
+ function NodeDetailPanel({
374
+ node,
375
+ projectId,
376
+ }: {
377
+ node: Node | null
378
+ projectId: string
379
+ }) {
380
+ const appPath = (path: string) => '/spine-framework/admin' + (path.startsWith('/') ? path : '/' + path)
381
+ if (!node) {
382
+ return (
383
+ <div className="p-3 text-xs text-muted-foreground">
384
+ Click a node to inspect it
385
+ </div>
386
+ )
387
+ }
388
+
389
+ const d = node.data as any
390
+
391
+ if (d.isFile) {
392
+ return (
393
+ <div className="p-3 space-y-2 text-xs">
394
+ <div className="font-mono font-bold truncate" title={d.file_path}>{d.file_path}</div>
395
+ <div className="text-muted-foreground">{d.language} · {d.chunk_count ?? '?'} chunks</div>
396
+ {d.is_dead_code && <Badge variant="destructive" className="text-xs">Dead Code</Badge>}
397
+ </div>
398
+ )
399
+ }
400
+
401
+ return (
402
+ <div className="p-3 space-y-2 text-xs">
403
+ <div className="font-mono font-bold">{d.label}</div>
404
+ <div className="text-muted-foreground truncate">{d.file_path}</div>
405
+ <div className="flex gap-1 flex-wrap">
406
+ <Badge variant="secondary" className="text-xs">{d.chunk_type}</Badge>
407
+ {d.is_dead_code && <Badge variant="destructive" className="text-xs">Dead</Badge>}
408
+ {d.doc_confidence === 'human_verified' && <Badge variant="default" className="text-xs bg-green-600">Verified</Badge>}
409
+ {d.doc_confidence === 'ai_generated' && <Badge variant="outline" className="text-xs">AI Docs</Badge>}
410
+ {!d.stored_hash && <Badge variant="outline" className="text-xs text-amber-600 border-amber-300">No Hash</Badge>}
411
+ </div>
412
+ <a
413
+ href={appPath(`/cil/${projectId}/chunks/${node.id}`)}
414
+ className="block text-indigo-600 hover:underline font-medium"
415
+ >
416
+ Open Contract →
417
+ </a>
418
+ </div>
419
+ )
420
+ }
421
+
422
+
423
+
424
+ // CIL[END chunk_id="cilgraphpage_nodedetailpanel_1784193942"]
425
+ // CIL[BEGIN chunk_id="cilgraphpage_cilgraphpage_1784193942" type="component" identity="CILGraphPage" parent="none"]
426
+ // CIL[DOC-MACRO purpose="Main interactive page for the CIL project graph"]
427
+ // CIL[DOC-RESPONSIBILITY responsibility="Fetch graph data, manage React Flow state, and render the graph with controls"]
428
+ // CIL[DOC-CONTEXT module="cortex:cil-graph" layer="presentation" related_files="[]"]
429
+ // CIL[DOC-CONTRACT inputs="none" outputs="JSX.Element" errors="swallows fetch errors silently" side_effects="calls apiFetch and updates React state"]
430
+ // CIL[DOC-MICRO logic_summary="Loads project graph and title, builds React Flow elements, handles view mode and selection, and renders the graph, legend, and inspector panel." notable_decisions="['Silently catches API errors','Hides React Flow attribution','Refreshes on button click']"]
431
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
432
+ // CIL[DOC-STABILITY stability="stable"]
433
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
434
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
435
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
436
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
437
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
438
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
439
+ export default function CILGraphPage() {
440
+ const { id: projectId } = useParams<{ id: string }>()
441
+ const appPath = (path: string) => '/spine-framework/admin' + (path.startsWith('/') ? path : '/' + path)
442
+ const [nodes, setNodes, onNodesChange] = useNodesState([])
443
+ const [edges, setEdges, onEdgesChange] = useEdgesState([])
444
+ const [loading, setLoading] = useState(true)
445
+ const [viewMode, setViewMode] = useState<ViewMode>('chunks')
446
+ const [selectedNode, setSelectedNode] = useState<Node | null>(null)
447
+ const [stats, setStats] = useState({ files: 0, chunks: 0, imports: 0, calls: 0 })
448
+ const [projectTitle, setProjectTitle] = useState('')
449
+
450
+ const loadGraph = useCallback(async () => {
451
+ if (!projectId) return
452
+ setLoading(true)
453
+ try {
454
+ const [graphRes, projectRes] = await Promise.all([
455
+ apiFetch(`/api/cil-graph?action=get_project_graph&project_id=${projectId}`),
456
+ apiFetch(`/api/cil-project?action=get&id=${projectId}`),
457
+ ])
458
+ const graphData = await graphRes.json()
459
+ const projectData = await projectRes.json()
460
+
461
+ const graph: ProjectGraph = graphData?.data || graphData
462
+ const project = projectData?.project || projectData?.data?.project
463
+
464
+ if (project?.title) setProjectTitle(project.title)
465
+
466
+ const { nodes: flowNodes, edges: flowEdges } = buildFlowGraph(graph, viewMode)
467
+ setNodes(flowNodes)
468
+ setEdges(flowEdges)
469
+ setStats({
470
+ files: graph.nodes.files.length,
471
+ chunks: graph.nodes.chunks.length,
472
+ imports: graph.edges.imports.length,
473
+ calls: graph.edges.calls.length,
474
+ })
475
+ } catch {
476
+ } finally {
477
+ setLoading(false)
478
+ }
479
+ }, [projectId, viewMode])
480
+
481
+ useEffect(() => { loadGraph() }, [loadGraph])
482
+
483
+ const onConnect = useCallback(
484
+ (params: Connection) => setEdges(eds => addEdge(params, eds)),
485
+ [setEdges]
486
+ )
487
+
488
+ if (loading) {
489
+ return (
490
+ <div className="p-6 space-y-4">
491
+ <Skeleton className="h-6 w-48" />
492
+ <Skeleton className="h-[600px] rounded-xl" />
493
+ </div>
494
+ )
495
+ }
496
+
497
+ return (
498
+ <div className="flex flex-col h-[calc(100vh-64px)]">
499
+ {}
500
+ <div className="flex items-center justify-between px-4 py-2 border-b bg-background shrink-0 gap-4 flex-wrap">
501
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
502
+ <a href={appPath('/cil')} className="hover:underline">Code Intelligence</a>
503
+ <ChevronRight className="h-3 w-3" />
504
+ <a href={appPath(`/cil/${projectId}/ingest`)} className="hover:underline">{projectTitle || 'Project'}</a>
505
+ <ChevronRight className="h-3 w-3" />
506
+ <span>Graph</span>
507
+ </div>
508
+
509
+ <div className="flex items-center gap-2">
510
+ <div className="flex items-center gap-1.5 text-xs text-muted-foreground">
511
+ <span className="font-mono">{stats.files} files</span>
512
+ <span>·</span>
513
+ <span className="font-mono">{stats.chunks} chunks</span>
514
+ <span>·</span>
515
+ <span className="font-mono">{stats.calls} calls</span>
516
+ <span>·</span>
517
+ <span className="font-mono">{stats.imports} imports</span>
518
+ </div>
519
+
520
+ <Select value={viewMode} onValueChange={v => setViewMode(v as ViewMode)}>
521
+ <SelectTrigger className="h-7 w-28 text-xs">
522
+ <Layers className="h-3 w-3 mr-1" />
523
+ <SelectValue />
524
+ </SelectTrigger>
525
+ <SelectContent>
526
+ <SelectItem value="chunks">Chunks</SelectItem>
527
+ <SelectItem value="files">Files</SelectItem>
528
+ <SelectItem value="mixed">Mixed</SelectItem>
529
+ </SelectContent>
530
+ </Select>
531
+
532
+ <Button size="sm" variant="outline" onClick={loadGraph} className="h-7 text-xs">
533
+ <RefreshCw className="h-3 w-3 mr-1" />
534
+ Refresh
535
+ </Button>
536
+ </div>
537
+ </div>
538
+
539
+ <PageInstructions
540
+ description="Explore the file and chunk call graph for a project."
541
+ sections={[
542
+ { title: 'What this page is for', content: 'This page visualizes import links between files and call links between chunks for the selected CIL project.' },
543
+ { title: 'How to read this page', content: 'The React Flow canvas shows nodes and edges. The legend explains colors by chunk type. The Inspector panel on the right displays details for the selected node.' },
544
+ { title: 'How to use this page', content: 'Switch the view mode to files or chunks. Click a node to see its details in the inspector. Pan, zoom, and use the minimap to navigate large graphs.' },
545
+ { title: 'Important notes', content: 'The graph is only available after Pass 1 and Pass 2 ingestion complete. Empty graphs mean no imports or calls were detected yet.' },
546
+ ]}
547
+ />
548
+
549
+ {}
550
+ <div className="flex flex-1 min-h-0">
551
+ <div className="flex-1">
552
+ {nodes.length === 0 ? (
553
+ <div className="flex items-center justify-center h-full text-muted-foreground text-sm">
554
+ <div className="text-center space-y-2">
555
+ <ZoomIn className="h-10 w-10 mx-auto opacity-20" />
556
+ <p>No {viewMode === 'files' ? 'files' : 'chunks'} found.</p>
557
+ <p className="text-xs">Run Pass 1 + Pass 2 ingestion first.</p>
558
+ </div>
559
+ </div>
560
+ ) : (
561
+ <ReactFlow
562
+ nodes={nodes}
563
+ edges={edges}
564
+ onNodesChange={onNodesChange}
565
+ onEdgesChange={onEdgesChange}
566
+ onConnect={onConnect}
567
+ onNodeClick={(_evt, node) => setSelectedNode(node)}
568
+ fitView
569
+ fitViewOptions={{ padding: 0.15 }}
570
+ minZoom={0.1}
571
+ maxZoom={2}
572
+ proOptions={{ hideAttribution: true }}
573
+ >
574
+ <Background color="#E2E8F0" gap={20} size={1} />
575
+ <Controls />
576
+ <MiniMap
577
+ nodeColor={nodeColor}
578
+ style={{ background: '#F8FAFC', border: '1px solid #E2E8F0' }}
579
+ pannable
580
+ zoomable
581
+ />
582
+
583
+ {}
584
+ <Panel position="bottom-left">
585
+ <div className="bg-background/90 backdrop-blur border rounded-lg p-2 text-xs space-y-1 shadow-sm">
586
+ {Object.entries(CHUNK_TYPE_COLORS).map(([type, color]) => (
587
+ <div key={type} className="flex items-center gap-1.5">
588
+ <div className="w-3 h-3 rounded-sm shrink-0" style={{ background: color + '44', border: `1.5px solid ${color}` }} />
589
+ <span className="text-muted-foreground">{type}</span>
590
+ </div>
591
+ ))}
592
+ {viewMode !== 'chunks' && (
593
+ <div className="flex items-center gap-1.5 pt-1 border-t">
594
+ <div className="w-3 h-3 rounded-sm shrink-0 bg-slate-900" />
595
+ <span className="text-muted-foreground">file</span>
596
+ </div>
597
+ )}
598
+ </div>
599
+ </Panel>
600
+ </ReactFlow>
601
+ )}
602
+ </div>
603
+
604
+ {}
605
+ <div className="w-56 border-l bg-muted/30 shrink-0 overflow-y-auto">
606
+ <div className="p-2 border-b bg-background">
607
+ <p className="text-xs font-medium text-muted-foreground uppercase tracking-wide">Inspector</p>
608
+ </div>
609
+ <NodeDetailPanel node={selectedNode} projectId={projectId!} />
610
+ </div>
611
+ </div>
612
+ </div>
613
+ )
614
+ }
615
+
616
+ // CIL[END chunk_id="cilgraphpage_cilgraphpage_1784193942"]