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,571 @@
1
+ // CIL[BEGIN chunk_id="cilsearchpage_module_header_1784193942" type="module_header" identity="module_header" parent="none"]
2
+ // CIL[DOC-MACRO purpose="Import dependencies and icons for the CIL search page"]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Provides React hooks, apiFetch, app path hook, UI components, and icons used by the page"]
4
+ // CIL[DOC-CONTEXT module="cortex:cil-search" 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="Sets up React hooks, apiFetch, useAppPath, UI card/button/input/select/label/badge 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 { useState, useRef, useMemo } from 'react'
17
+ import { apiFetch } from '@core/lib/api'
18
+ import { Card, CardContent } from '@core/components/ui/card'
19
+ import { Button } from '@core/components/ui/button'
20
+ import { Badge } from '@core/components/ui/badge'
21
+ import { Input } from '@core/components/ui/input'
22
+ import { Label } from '@core/components/ui/label'
23
+ import {
24
+ Select,
25
+ SelectContent,
26
+ SelectItem,
27
+ SelectTrigger,
28
+ SelectValue,
29
+ } from '@core/components/ui/select'
30
+ import {
31
+ Search,
32
+ Zap,
33
+ FileCode2,
34
+ ChevronRight,
35
+ Code2,
36
+ RefreshCw,
37
+ AlertTriangle,
38
+ } from 'lucide-react'
39
+
40
+
41
+
42
+ import { PageInstructions } from '../../../components/admin/PageInstructions'
43
+ // CIL[END chunk_id="cilsearchpage_module_header_1784193942"]
44
+ // CIL[BEGIN chunk_id="cilsearchpage_searchresult_1784193942" type="interface" identity="SearchResult" parent="none"]
45
+ // CIL[DOC-MACRO purpose="Define the shape of a search result chunk"]
46
+ // CIL[DOC-RESPONSIBILITY responsibility="Declares the TypeScript interface for chunk data returned by the CIL search API"]
47
+ // CIL[DOC-CONTEXT module="cortex:cil-search" layer="presentation" related_files="[\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"\\\"]"]
48
+ // CIL[DOC-CONTRACT inputs="none" outputs="SearchResult type contract" errors="none" side_effects="none"]
49
+ // CIL[DOC-MICRO logic_summary="Describes id, chunk_name, file_path, macro, micro, chunk_type, doc_confidence, similarity, and match_type fields" notable_decisions="[]"]
50
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
51
+ // CIL[DOC-STABILITY stability="stable"]
52
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/principal.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/schema-utils.ts, custom/apps/cortex/functions/custom_cil-embeddings.ts, \."]
53
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
54
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
55
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
56
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
57
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
58
+ interface SearchResult {
59
+ id: string
60
+ chunk_name: string
61
+ file_path: string
62
+ macro: string
63
+ micro?: string
64
+ chunk_type: string
65
+ doc_confidence: string
66
+ similarity: number | null
67
+ match_type: 'semantic' | 'text'
68
+ }
69
+
70
+
71
+
72
+ // CIL[END chunk_id="cilsearchpage_searchresult_1784193942"]
73
+ // CIL[BEGIN chunk_id="cilsearchpage_chunk_type_colors_1784193942" type="constant" identity="CHUNK_TYPE_COLORS" parent="none"]
74
+ // CIL[DOC-MACRO purpose="Map chunk types to Tailwind badge color classes"]
75
+ // CIL[DOC-RESPONSIBILITY responsibility="Supplies a color palette used by result cards to style chunk-type badges"]
76
+ // CIL[DOC-CONTEXT module="cortex:cil-search" layer="presentation" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
77
+ // CIL[DOC-CONTRACT inputs="none" outputs="Record<string, string> color classes" errors="none" side_effects="none"]
78
+ // CIL[DOC-MICRO logic_summary="Maps each chunk type to background, text, and border utility classes for badge rendering" notable_decisions="[]"]
79
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
80
+ // CIL[DOC-STABILITY stability="stable"]
81
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, custom/apps/cortex/functions/custom_cil-embeddings.ts, custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
82
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
83
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
84
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
85
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
86
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
87
+ const CHUNK_TYPE_COLORS: Record<string, string> = {
88
+ function: 'bg-indigo-100 text-indigo-700 border-indigo-200',
89
+ class: 'bg-violet-100 text-violet-700 border-violet-200',
90
+ interface: 'bg-emerald-100 text-emerald-700 border-emerald-200',
91
+ type: 'bg-cyan-100 text-cyan-700 border-cyan-200',
92
+ component: 'bg-amber-100 text-amber-700 border-amber-200',
93
+ hook: 'bg-pink-100 text-pink-700 border-pink-200',
94
+ route: 'bg-red-100 text-red-700 border-red-200',
95
+ config: 'bg-slate-100 text-slate-700 border-slate-200',
96
+ }
97
+
98
+ // CIL[END chunk_id="cilsearchpage_chunk_type_colors_1784193942"]
99
+ // CIL[BEGIN chunk_id="cilsearchpage_doc_confidence_label_1784193942" type="constant" identity="DOC_CONFIDENCE_LABEL" parent="none"]
100
+ // CIL[DOC-MACRO purpose="Map documentation confidence keys to human labels and badge classes"]
101
+ // CIL[DOC-RESPONSIBILITY responsibility="Supplies badge label and color config for documentation confidence states"]
102
+ // CIL[DOC-CONTEXT module="cortex:cil-search" layer="presentation" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"\\\"]"]
103
+ // CIL[DOC-CONTRACT inputs="none" outputs="Record of label and className objects" errors="none" side_effects="none"]
104
+ // CIL[DOC-MICRO logic_summary="Maps human_verified, ai_generated, and unverified_legacy to display label and Tailwind className" 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: custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/RolesPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/cortex/functions/custom_cil-embeddings.ts, \."]
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 DOC_CONFIDENCE_LABEL: Record<string, { label: string; className: string }> = {
114
+ human_verified: { label: 'Verified', className: 'bg-green-100 text-green-700 border-green-200' },
115
+ ai_generated: { label: 'AI Docs', className: 'bg-blue-100 text-blue-700 border-blue-200' },
116
+ unverified_legacy: { label: 'No Docs', className: 'bg-slate-100 text-slate-500 border-slate-200' },
117
+ }
118
+
119
+ // CIL[END chunk_id="cilsearchpage_doc_confidence_label_1784193942"]
120
+ // CIL[BEGIN chunk_id="cilsearchpage_similaritybar_1784193942" type="function" identity="SimilarityBar" parent="none"]
121
+ // CIL[DOC-MACRO purpose="Render a percentage bar for a similarity score"]
122
+ // CIL[DOC-RESPONSIBILITY responsibility="Display numeric similarity as a small indigo progress bar and percentage text"]
123
+ // CIL[DOC-CONTEXT module="cortex:cil-search" layer="presentation" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
124
+ // CIL[DOC-CONTRACT inputs="none" outputs="JSX.Element | null" errors="none" side_effects="none"]
125
+ // CIL[DOC-MICRO logic_summary="Renders null for null scores, otherwise a rounded percentage with an indigo progress bar" notable_decisions="[]"]
126
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
127
+ // CIL[DOC-STABILITY stability="stable"]
128
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/functions/_shared/schema-utils.ts, \."]
129
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
130
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
131
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
132
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
133
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
134
+ function SimilarityBar({ score }: { score: number | null }) {
135
+ if (score === null) return null
136
+ const pct = Math.round(score * 100)
137
+ return (
138
+ <div className="flex items-center gap-1.5 shrink-0">
139
+ <div className="w-16 h-1.5 bg-muted rounded-full overflow-hidden">
140
+ <div
141
+ className="h-full bg-indigo-500 rounded-full"
142
+ style={{ width: `${pct}%` }}
143
+ />
144
+ </div>
145
+ <span className="text-xs text-muted-foreground tabular-nums">{pct}%</span>
146
+ </div>
147
+ )
148
+ }
149
+
150
+ // CIL[END chunk_id="cilsearchpage_similaritybar_1784193942"]
151
+ // CIL[BEGIN chunk_id="cilsearchpage_resultcard_1784193942" type="function" identity="ResultCard" parent="none"]
152
+ // CIL[DOC-MACRO purpose="Render a single search result as a link card"]
153
+ // CIL[DOC-RESPONSIBILITY responsibility="Display chunk name, type badge, doc confidence badge, file path, macro snippet, and similarity bar"]
154
+ // CIL[DOC-CONTEXT module="cortex:cil-search" layer="presentation" related_files="[]"]
155
+ // CIL[DOC-CONTRACT inputs="none" outputs="JSX.Element" errors="none" side_effects="none"]
156
+ // CIL[DOC-MICRO logic_summary="Uses CHUNK_TYPE_COLORS and DOC_CONFIDENCE_LABEL to style badges, links to chunk detail via appPath, and renders SimilarityBar" notable_decisions="[]"]
157
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
158
+ // CIL[DOC-STABILITY stability="stable"]
159
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
160
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
161
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
162
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
163
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
164
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
165
+ function ResultCard({ result, projectId }: { result: SearchResult; projectId: string }) {
166
+ const appPath = (path: string) => '/spine-framework/admin' + (path.startsWith('/') ? path : '/' + path)
167
+ const typeClass = CHUNK_TYPE_COLORS[result.chunk_type] || CHUNK_TYPE_COLORS.config
168
+ const docCfg = DOC_CONFIDENCE_LABEL[result.doc_confidence] || DOC_CONFIDENCE_LABEL.unverified_legacy
169
+
170
+ return (
171
+ <a
172
+ href={appPath(`/cil/${projectId}/chunks/${result.id}`)}
173
+ className="block group"
174
+ >
175
+ <Card className="hover:shadow-md transition-shadow cursor-pointer group-hover:border-indigo-200">
176
+ <CardContent className="py-3 px-4">
177
+ <div className="flex items-start gap-3">
178
+ <Code2 className="h-4 w-4 mt-0.5 text-muted-foreground shrink-0" />
179
+ <div className="flex-1 min-w-0 space-y-1">
180
+ <div className="flex items-center gap-2 flex-wrap">
181
+ <span className="font-mono font-semibold text-sm group-hover:text-indigo-600 transition-colors">
182
+ {result.chunk_name}
183
+ </span>
184
+ <span className={`text-xs px-1.5 py-0.5 rounded border ${typeClass}`}>
185
+ {result.chunk_type}
186
+ </span>
187
+ <span className={`text-xs px-1.5 py-0.5 rounded border ${docCfg.className}`}>
188
+ {docCfg.label}
189
+ </span>
190
+ {result.match_type === 'semantic' && (
191
+ <span className="flex items-center gap-0.5 text-xs text-indigo-500">
192
+ <Zap className="h-3 w-3" /> semantic
193
+ </span>
194
+ )}
195
+ </div>
196
+ <div className="flex items-center gap-1 text-xs text-muted-foreground font-mono">
197
+ <FileCode2 className="h-3 w-3 shrink-0" />
198
+ <span className="truncate">{result.file_path}</span>
199
+ </div>
200
+ {result.macro && (
201
+ <p className="text-xs text-muted-foreground line-clamp-2">{result.macro}</p>
202
+ )}
203
+ </div>
204
+ <SimilarityBar score={result.similarity} />
205
+ </div>
206
+ </CardContent>
207
+ </Card>
208
+ </a>
209
+ )
210
+ }
211
+
212
+
213
+
214
+ // CIL[END chunk_id="cilsearchpage_resultcard_1784193942"]
215
+ // CIL[BEGIN chunk_id="cilsearchpage_sortby_1784193942" type="type" identity="SortBy" parent="none"]
216
+ // CIL[DOC-MACRO purpose="Union type for result sort keys"]
217
+ // CIL[DOC-RESPONSIBILITY responsibility="Defines the allowed sort column identifiers for the search results"]
218
+ // CIL[DOC-CONTEXT module="cortex:cil-search" layer="presentation" related_files="[]"]
219
+ // CIL[DOC-CONTRACT inputs="none" outputs="'relevance' | 'name' | 'file' | 'doc_confidence'" errors="none" side_effects="none"]
220
+ // CIL[DOC-MICRO logic_summary="Constrains sortBy state to four predefined string literals" notable_decisions="[]"]
221
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
222
+ // CIL[DOC-STABILITY stability="stable"]
223
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
224
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
225
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
226
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
227
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
228
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
229
+ type SortBy = 'relevance' | 'name' | 'file' | 'doc_confidence'
230
+ // CIL[END chunk_id="cilsearchpage_sortby_1784193942"]
231
+ // CIL[BEGIN chunk_id="cilsearchpage_chunktypefilter_1784193942" type="type" identity="ChunkTypeFilter" parent="none"]
232
+ // CIL[DOC-MACRO purpose="Union type for chunk type filter values"]
233
+ // CIL[DOC-RESPONSIBILITY responsibility="Defines the allowed chunk type filter options including 'all'"]
234
+ // CIL[DOC-CONTEXT module="cortex:cil-search" layer="presentation" related_files="[]"]
235
+ // CIL[DOC-CONTRACT inputs="none" outputs="'all' | chunk type literals" errors="none" side_effects="none"]
236
+ // CIL[DOC-MICRO logic_summary="Constrains chunkTypeFilter state to 'all' or one of the supported chunk type strings" notable_decisions="[]"]
237
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
238
+ // CIL[DOC-STABILITY stability="stable"]
239
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
240
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
241
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
242
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
243
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
244
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
245
+ type ChunkTypeFilter = 'all' | 'function' | 'class' | 'interface' | 'type' | 'component' | 'hook' | 'route' | 'config'
246
+ // CIL[END chunk_id="cilsearchpage_chunktypefilter_1784193942"]
247
+ // CIL[BEGIN chunk_id="cilsearchpage_docconfidencefilter_1784193942" type="type" identity="DocConfidenceFilter" parent="none"]
248
+ // CIL[DOC-MACRO purpose="Union type for documentation confidence filter values"]
249
+ // CIL[DOC-RESPONSIBILITY responsibility="Defines the allowed doc confidence filter options"]
250
+ // CIL[DOC-CONTEXT module="cortex:cil-search" layer="presentation" related_files="[]"]
251
+ // CIL[DOC-CONTRACT inputs="none" outputs="'all' | 'human_verified' | 'ai_generated' | 'unverified_legacy'" errors="none" side_effects="none"]
252
+ // CIL[DOC-MICRO logic_summary="Constrains docConfidenceFilter state to 'all' or one of the confidence level strings" notable_decisions="[]"]
253
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
254
+ // CIL[DOC-STABILITY stability="stable"]
255
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
256
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
257
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
258
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
259
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
260
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
261
+ type DocConfidenceFilter = 'all' | 'human_verified' | 'ai_generated' | 'unverified_legacy'
262
+
263
+ // CIL[END chunk_id="cilsearchpage_docconfidencefilter_1784193942"]
264
+ // CIL[BEGIN chunk_id="cilsearchpage_cilsearchpage_1784193942" type="component" identity="CILSearchPage" parent="none"]
265
+ // CIL[DOC-MACRO purpose="Main page component for searching CIL chunks"]
266
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide a UI for query input, search mode/limit/project filters, result filtering/sorting, and rendering results"]
267
+ // CIL[DOC-CONTEXT module="cortex:cil-search" layer="presentation" related_files="[]"]
268
+ // CIL[DOC-CONTRACT inputs="none" outputs="JSX.Element" errors="Displays error message string" side_effects="Calls apiFetch on search, sets React state"]
269
+ // CIL[DOC-MICRO logic_summary="Manages query, projectId, mode, limit, chunkTypeFilter, docConfidenceFilter, and sortBy state; calls /api/cil-graph search endpoint; filters and sorts displayResults; renders controls, error, empty state, and ResultCard list" notable_decisions="[]"]
270
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
271
+ // CIL[DOC-STABILITY stability="stable"]
272
+ // CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
273
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
274
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
275
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
276
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
277
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
278
+ export default function CILSearchPage() {
279
+ const appPath = (path: string) => '/spine-framework/admin' + (path.startsWith('/') ? path : '/' + path)
280
+ const [query, setQuery] = useState('')
281
+ const [projectId, setProjectId] = useState('')
282
+ const [mode, setMode] = useState<'hybrid' | 'semantic' | 'text'>('hybrid')
283
+ const [limit, setLimit] = useState('20')
284
+ const [chunkTypeFilter, setChunkTypeFilter] = useState<ChunkTypeFilter>('all')
285
+ const [docConfidenceFilter, setDocConfidenceFilter] = useState<DocConfidenceFilter>('all')
286
+ const [sortBy, setSortBy] = useState<SortBy>('relevance')
287
+ const [results, setResults] = useState<SearchResult[]>([])
288
+ const [loading, setLoading] = useState(false)
289
+ const [searched, setSearched] = useState(false)
290
+ const [error, setError] = useState<string | null>(null)
291
+ const inputRef = useRef<HTMLInputElement>(null)
292
+
293
+ const handleSearch = async () => {
294
+ if (!query.trim()) return
295
+ setLoading(true)
296
+ setError(null)
297
+ setSearched(true)
298
+
299
+ try {
300
+ const params = new URLSearchParams({
301
+ action: 'search',
302
+ q: query.trim(),
303
+ mode,
304
+ limit,
305
+ })
306
+ if (projectId) params.set('project_id', projectId)
307
+
308
+ const res = await apiFetch(`/api/cil-graph?${params.toString()}`)
309
+ const data = await res.json()
310
+ setResults(data?.results || data?.data?.results || [])
311
+ } catch (err) {
312
+ setError(String(err))
313
+ setResults([])
314
+ } finally {
315
+ setLoading(false)
316
+ }
317
+ }
318
+
319
+
320
+ const displayResults = useMemo(() => {
321
+ let r = [...results]
322
+ if (chunkTypeFilter !== 'all') r = r.filter(x => x.chunk_type === chunkTypeFilter)
323
+ if (docConfidenceFilter !== 'all') r = r.filter(x => x.doc_confidence === docConfidenceFilter)
324
+ if (sortBy === 'name') r.sort((a, b) => a.chunk_name.localeCompare(b.chunk_name))
325
+ else if (sortBy === 'file') r.sort((a, b) => a.file_path.localeCompare(b.file_path))
326
+ else if (sortBy === 'doc_confidence') {
327
+ const order: Record<string, number> = { human_verified: 0, ai_generated: 1, unverified_legacy: 2 }
328
+ r.sort((a, b) => (order[a.doc_confidence] ?? 3) - (order[b.doc_confidence] ?? 3))
329
+ }
330
+
331
+ return r
332
+ }, [results, chunkTypeFilter, docConfidenceFilter, sortBy])
333
+
334
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
335
+ if (e.key === 'Enter') handleSearch()
336
+ }
337
+
338
+ return (
339
+ <div className="p-6 space-y-6 max-w-4xl">
340
+ {}
341
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
342
+ <a href={appPath('/cil')} className="hover:underline">Code Intelligence</a>
343
+ <ChevronRight className="h-3 w-3" />
344
+ <span>Search</span>
345
+ </div>
346
+
347
+ <div>
348
+ <h1 className="text-2xl font-bold flex items-center gap-2">
349
+ <Search className="h-6 w-6 text-indigo-500" />
350
+ Chunk Search
351
+ </h1>
352
+ <p className="text-sm text-muted-foreground mt-1">
353
+ Semantic + text search across all indexed code chunks
354
+ </p>
355
+ </div>
356
+
357
+ <PageInstructions
358
+ description="Search the Code Intelligence Layer index by meaning or text."
359
+ sections={[
360
+ { title: 'What this page is for', content: 'This page lets you find indexed code chunks across projects using hybrid, semantic, or text search.' },
361
+ { title: 'How to use this page', content: 'Enter a query, choose a mode, and click the search button or press Enter. Use the Project ID, Type, Docs, and Sort filters to narrow results.' },
362
+ { title: 'How to read the results', content: 'Each result shows the chunk name, file, type, documentation confidence, and a relevance score. Semantic mode ranks by vector similarity; text mode matches literal terms.' },
363
+ { title: 'Important notes', content: 'Hybrid mode combines vector and text ranking. Filters can exclude results, and the count line indicates how many of the total results are displayed after filtering.' },
364
+ ]}
365
+ />
366
+
367
+ {}
368
+ <div className="space-y-3">
369
+ <div className="flex gap-2">
370
+ <Input
371
+ ref={inputRef}
372
+ placeholder="Describe what you're looking for, e.g. 'authenticate user and check roles'"
373
+ value={query}
374
+ onChange={e => setQuery(e.target.value)}
375
+ onKeyDown={handleKeyDown}
376
+ className="flex-1"
377
+ autoFocus
378
+ />
379
+ <Button onClick={handleSearch} disabled={loading || !query.trim()}>
380
+ {loading ? (
381
+ <RefreshCw className="h-4 w-4 animate-spin" />
382
+ ) : (
383
+ <Search className="h-4 w-4" />
384
+ )}
385
+ </Button>
386
+ </div>
387
+
388
+ {}
389
+ <div className="flex items-center gap-4 flex-wrap">
390
+ <div className="flex items-center gap-2">
391
+ <Label className="text-xs text-muted-foreground">Mode</Label>
392
+ <Select value={mode} onValueChange={v => setMode(v as typeof mode)}>
393
+ <SelectTrigger className="h-7 w-28 text-xs">
394
+ <SelectValue />
395
+ </SelectTrigger>
396
+ <SelectContent>
397
+ <SelectItem value="hybrid">Hybrid</SelectItem>
398
+ <SelectItem value="semantic">Semantic</SelectItem>
399
+ <SelectItem value="text">Text</SelectItem>
400
+ </SelectContent>
401
+ </Select>
402
+ </div>
403
+
404
+ <div className="flex items-center gap-2">
405
+ <Label className="text-xs text-muted-foreground">Project ID</Label>
406
+ <Input
407
+ placeholder="(all projects)"
408
+ value={projectId}
409
+ onChange={e => setProjectId(e.target.value)}
410
+ className="h-7 w-48 text-xs font-mono"
411
+ />
412
+ </div>
413
+
414
+ <div className="flex items-center gap-2">
415
+ <Label className="text-xs text-muted-foreground">Limit</Label>
416
+ <Select value={limit} onValueChange={setLimit}>
417
+ <SelectTrigger className="h-7 w-16 text-xs">
418
+ <SelectValue />
419
+ </SelectTrigger>
420
+ <SelectContent>
421
+ <SelectItem value="10">10</SelectItem>
422
+ <SelectItem value="20">20</SelectItem>
423
+ <SelectItem value="50">50</SelectItem>
424
+ </SelectContent>
425
+ </Select>
426
+ </div>
427
+ </div>
428
+
429
+ {}
430
+ <div className="flex items-center gap-4 flex-wrap">
431
+ <div className="flex items-center gap-2">
432
+ <Label className="text-xs text-muted-foreground">Type</Label>
433
+ <Select value={chunkTypeFilter} onValueChange={v => setChunkTypeFilter(v as ChunkTypeFilter)}>
434
+ <SelectTrigger className="h-7 w-32 text-xs">
435
+ <SelectValue />
436
+ </SelectTrigger>
437
+ <SelectContent>
438
+ <SelectItem value="all">All types</SelectItem>
439
+ <SelectItem value="function">Function</SelectItem>
440
+ <SelectItem value="class">Class</SelectItem>
441
+ <SelectItem value="interface">Interface</SelectItem>
442
+ <SelectItem value="type">Type</SelectItem>
443
+ <SelectItem value="component">Component</SelectItem>
444
+ <SelectItem value="hook">Hook</SelectItem>
445
+ <SelectItem value="route">Route</SelectItem>
446
+ <SelectItem value="config">Config</SelectItem>
447
+ </SelectContent>
448
+ </Select>
449
+ </div>
450
+
451
+ <div className="flex items-center gap-2">
452
+ <Label className="text-xs text-muted-foreground">Docs</Label>
453
+ <Select value={docConfidenceFilter} onValueChange={v => setDocConfidenceFilter(v as DocConfidenceFilter)}>
454
+ <SelectTrigger className="h-7 w-32 text-xs">
455
+ <SelectValue />
456
+ </SelectTrigger>
457
+ <SelectContent>
458
+ <SelectItem value="all">All docs</SelectItem>
459
+ <SelectItem value="human_verified">Verified</SelectItem>
460
+ <SelectItem value="ai_generated">AI Docs</SelectItem>
461
+ <SelectItem value="unverified_legacy">No Docs</SelectItem>
462
+ </SelectContent>
463
+ </Select>
464
+ </div>
465
+
466
+ <div className="flex items-center gap-2">
467
+ <Label className="text-xs text-muted-foreground">Sort</Label>
468
+ <Select value={sortBy} onValueChange={v => setSortBy(v as SortBy)}>
469
+ <SelectTrigger className="h-7 w-32 text-xs">
470
+ <SelectValue />
471
+ </SelectTrigger>
472
+ <SelectContent>
473
+ <SelectItem value="relevance">Relevance</SelectItem>
474
+ <SelectItem value="name">Name A–Z</SelectItem>
475
+ <SelectItem value="file">File A–Z</SelectItem>
476
+ <SelectItem value="doc_confidence">Doc quality</SelectItem>
477
+ </SelectContent>
478
+ </Select>
479
+ </div>
480
+
481
+ {(chunkTypeFilter !== 'all' || docConfidenceFilter !== 'all' || sortBy !== 'relevance') && (
482
+ <button
483
+ className="text-xs text-muted-foreground hover:text-foreground underline underline-offset-2"
484
+ onClick={() => { setChunkTypeFilter('all'); setDocConfidenceFilter('all'); setSortBy('relevance') }}
485
+ >
486
+ Reset filters
487
+ </button>
488
+ )}
489
+ </div>
490
+ </div>
491
+
492
+ {}
493
+ {error && (
494
+ <div className="flex items-center gap-2 text-sm text-red-600 bg-red-50 p-3 rounded-lg border border-red-200">
495
+ <AlertTriangle className="h-4 w-4 shrink-0" />
496
+ {error}
497
+ </div>
498
+ )}
499
+
500
+ {searched && !loading && !error && (
501
+ <div className="space-y-3">
502
+ <div className="flex items-center justify-between">
503
+ <p className="text-sm text-muted-foreground">
504
+ {displayResults.length === 0
505
+ ? (results.length > 0 ? `0 of ${results.length} results match filters` : 'No results found')
506
+ : `${displayResults.length}${displayResults.length !== results.length ? ` of ${results.length}` : ''} result${displayResults.length !== 1 ? 's' : ''}`}
507
+ {results.length > 0 && mode !== 'text' && (
508
+ <span className="ml-2 text-xs text-indigo-500 inline-flex items-center gap-0.5">
509
+ <Zap className="h-3 w-3" /> semantic ranking active
510
+ </span>
511
+ )}
512
+ </p>
513
+ {results.length > 0 && (
514
+ <Button
515
+ size="sm"
516
+ variant="ghost"
517
+ className="h-6 text-xs"
518
+ onClick={() => { setResults([]); setSearched(false); setQuery(''); inputRef.current?.focus() }}
519
+ >
520
+ Clear
521
+ </Button>
522
+ )}
523
+ </div>
524
+
525
+ {displayResults.length === 0 && (
526
+ <div className="text-center py-12 text-muted-foreground space-y-2">
527
+ <Search className="h-10 w-10 mx-auto opacity-20" />
528
+ <p className="text-sm">No chunks match your query.</p>
529
+ {mode === 'semantic' && (
530
+ <p className="text-xs">Try switching to Hybrid mode to also search chunk names.</p>
531
+ )}
532
+ {mode !== 'semantic' && (
533
+ <p className="text-xs">Try a different query or run Pass 3 to generate embeddings first.</p>
534
+ )}
535
+ </div>
536
+ )}
537
+
538
+ {displayResults.map(result => (
539
+ <ResultCard key={result.id} result={result} projectId={projectId || result.id} />
540
+ ))}
541
+ </div>
542
+ )}
543
+
544
+ {!searched && (
545
+ <div className="text-center py-16 text-muted-foreground space-y-3">
546
+ <Search className="h-12 w-12 mx-auto opacity-15" />
547
+ <p className="text-sm">Search across all code chunks by purpose, inputs, or behaviour</p>
548
+ <div className="flex flex-wrap gap-2 justify-center">
549
+ {[
550
+ 'handle authentication middleware',
551
+ 'send email notification',
552
+ 'validate JWT token',
553
+ 'write embeddings to database',
554
+ 'resolve type ID by slug',
555
+ ].map(suggestion => (
556
+ <button
557
+ key={suggestion}
558
+ className="text-xs px-3 py-1.5 rounded-full border hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
559
+ onClick={() => { setQuery(suggestion); setTimeout(handleSearch, 10) }}
560
+ >
561
+ {suggestion}
562
+ </button>
563
+ ))}
564
+ </div>
565
+ </div>
566
+ )}
567
+ </div>
568
+ )
569
+ }
570
+
571
+ // CIL[END chunk_id="cilsearchpage_cilsearchpage_1784193942"]