spine-framework 0.3.145 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/.env.example +76 -0
  2. package/.framework/.spine-manifest.json +19 -0
  3. package/.framework/cli/commands/agents.ts +61 -33
  4. package/.framework/cli/commands/auth.ts +60 -28
  5. package/.framework/cli/commands/create-app.ts +212 -80
  6. package/.framework/cli/commands/dev.ts +184 -68
  7. package/.framework/cli/commands/doctor.ts +324 -152
  8. package/.framework/cli/commands/generate.ts +119 -68
  9. package/.framework/cli/commands/init.ts +141 -242
  10. package/.framework/cli/commands/install-app.ts +1336 -314
  11. package/.framework/cli/commands/items.ts +31 -29
  12. package/.framework/cli/commands/migrate.ts +299 -156
  13. package/.framework/cli/commands/migrations.ts +62 -30
  14. package/.framework/cli/commands/pipelines.ts +31 -29
  15. package/.framework/cli/commands/status.ts +105 -45
  16. package/.framework/cli/commands/system.ts +47 -42
  17. package/.framework/cli/commands/test.ts +161 -102
  18. package/.framework/cli/commands/upgrade.ts +260 -0
  19. package/.framework/cli/commands/validate-app.ts +517 -161
  20. package/.framework/cli/context.ts +117 -85
  21. package/.framework/cli/env-loader.ts +74 -43
  22. package/.framework/cli/index.ts +70 -46
  23. package/.framework/cli/lib/project-files.ts +404 -0
  24. package/.framework/docs/guides/testing-guide.md +1 -1
  25. package/.framework/docs/runtime-types.md +72 -72
  26. package/.framework/functions/_shared/access.ts +84 -0
  27. package/.framework/functions/_shared/agent-runner.ts +5051 -1026
  28. package/.framework/functions/_shared/app-manifest.ts +214 -94
  29. package/.framework/functions/_shared/ast.ts +214 -0
  30. package/.framework/functions/_shared/audit.ts +91 -55
  31. package/.framework/functions/_shared/cil.ts +368 -127
  32. package/.framework/functions/_shared/db.ts +337 -68
  33. package/.framework/functions/_shared/funnel.ts +228 -0
  34. package/.framework/functions/_shared/geo.ts +105 -0
  35. package/.framework/functions/_shared/hash-api-key.ts +94 -17
  36. package/.framework/functions/_shared/index.ts +22 -224
  37. package/.framework/functions/_shared/kb.ts +832 -58
  38. package/.framework/functions/_shared/llm.ts +118 -18
  39. package/.framework/functions/_shared/logging.ts +317 -19
  40. package/.framework/functions/_shared/middleware.ts +701 -131
  41. package/.framework/functions/_shared/notify.ts +70 -0
  42. package/.framework/functions/_shared/outcomes.ts +34 -19
  43. package/.framework/functions/_shared/permissions.ts +501 -315
  44. package/.framework/functions/_shared/pipeline-runner.ts +704 -155
  45. package/.framework/functions/_shared/principal.ts +436 -263
  46. package/.framework/functions/_shared/rate-limit.ts +233 -0
  47. package/.framework/functions/_shared/resolve-credentials.ts +86 -19
  48. package/.framework/functions/_shared/resolve-ids.ts +203 -139
  49. package/.framework/functions/_shared/retry-deliveries.ts +51 -16
  50. package/.framework/functions/_shared/schema-utils.ts +602 -521
  51. package/.framework/functions/_shared/security.ts +345 -0
  52. package/.framework/functions/_shared/testing.ts +197 -172
  53. package/.framework/functions/_shared/tracing.ts +351 -21
  54. package/.framework/functions/_shared/trigger-engine.ts +425 -136
  55. package/.framework/functions/_shared/webhook-registration.ts +71 -70
  56. package/.framework/functions/_shared/webhook-registry.ts +126 -83
  57. package/.framework/functions/account-nodes.ts +30 -30
  58. package/.framework/functions/adapters/generic-webhook-inbound.ts +49 -16
  59. package/.framework/functions/adapters/generic-webhook-outbound.ts +17 -17
  60. package/.framework/functions/adapters/openai-outbound.ts +15 -16
  61. package/.framework/functions/admin-data.ts +596 -173
  62. package/.framework/functions/admin-funnel.ts +64 -60
  63. package/.framework/functions/admin-install-funnel.ts +84 -66
  64. package/.framework/functions/admin-signals.ts +69 -51
  65. package/.framework/functions/ai-agents.ts +431 -106
  66. package/.framework/functions/ai-interactions.ts +186 -112
  67. package/.framework/functions/api-keys.ts +107 -107
  68. package/.framework/functions/apps.ts +154 -136
  69. package/.framework/functions/auth.ts +83 -65
  70. package/.framework/functions/cil-agent-ingest.ts +189 -232
  71. package/.framework/functions/cil-agent.ts +433 -177
  72. package/.framework/functions/cil-callmap.ts +642 -430
  73. package/.framework/functions/cil-config.ts +139 -135
  74. package/.framework/functions/cil-context.ts +214 -127
  75. package/.framework/functions/cil-doc.ts +587 -458
  76. package/.framework/functions/cil-embeddings.ts +453 -364
  77. package/.framework/functions/cil-graph.ts +427 -142
  78. package/.framework/functions/cil-ingest.ts +1418 -1154
  79. package/.framework/functions/cil-pipeline.ts +276 -21
  80. package/.framework/functions/cil-project.ts +659 -132
  81. package/.framework/functions/cil-validate.ts +198 -164
  82. package/.framework/functions/debug-auth.ts +57 -55
  83. package/.framework/functions/deliveries.ts +80 -21
  84. package/.framework/functions/embeddings.ts +1023 -318
  85. package/.framework/functions/eval-harness.ts +146 -108
  86. package/.framework/functions/integration-outbound.ts +205 -75
  87. package/.framework/functions/integration-routes.ts +128 -23
  88. package/.framework/functions/integrations.ts +125 -100
  89. package/.framework/functions/invites.ts +1095 -460
  90. package/.framework/functions/item-progress.ts +158 -102
  91. package/.framework/functions/kb.ts +34 -10
  92. package/.framework/functions/logs.ts +133 -133
  93. package/.framework/functions/observability.ts +152 -122
  94. package/.framework/functions/pipeline-executions.ts +147 -132
  95. package/.framework/functions/pipelines.ts +134 -119
  96. package/.framework/functions/prompt-configs.ts +96 -80
  97. package/.framework/functions/roles.ts +112 -82
  98. package/.framework/functions/security.ts +450 -0
  99. package/.framework/functions/system-cron.ts +117 -80
  100. package/.framework/functions/system.ts +158 -98
  101. package/.framework/functions/tests.ts +29 -29
  102. package/.framework/functions/timers.ts +94 -95
  103. package/.framework/functions/trigger-scheduler.ts +10 -0
  104. package/.framework/functions/triggers.ts +179 -149
  105. package/.framework/functions/types.ts +137 -125
  106. package/.framework/mcp/index.ts +133 -0
  107. package/.framework/mcp/load-env.ts +60 -0
  108. package/.framework/mcp/shared/app-manifest.ts +275 -0
  109. package/.framework/mcp/shared/db.ts +477 -0
  110. package/.framework/mcp/shared/kb.ts +118 -0
  111. package/.framework/mcp/tools/architect.ts +431 -0
  112. package/.framework/mcp/tools/cil/context.ts +345 -0
  113. package/.framework/mcp/tools/cil/graph.ts +242 -0
  114. package/.framework/mcp/tools/cil/ingest.ts +1217 -0
  115. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +693 -0
  116. package/.framework/mcp/tools/cil/pipeline.ts +767 -0
  117. package/.framework/mcp/tools/cil/project.ts +791 -0
  118. package/.framework/mcp/tools/cil/retrieval.ts +336 -0
  119. package/.framework/mcp/tools/cil/search-core.ts +454 -0
  120. package/.framework/mcp/tools/cil/search.ts +97 -0
  121. package/.framework/mcp/tools/cil/suggest.ts +186 -0
  122. package/.framework/mcp/tools/cil/validate.ts +1369 -0
  123. package/.framework/mcp/tools/kb/delete.ts +139 -0
  124. package/.framework/mcp/tools/kb/index.ts +52 -0
  125. package/.framework/mcp/tools/kb/ingest.ts +84 -0
  126. package/.framework/mcp/tools/kb/list-types.ts +102 -0
  127. package/.framework/mcp/tools/kb/publish.ts +100 -0
  128. package/.framework/mcp/tools/kb/reindex.ts +86 -0
  129. package/.framework/mcp/tools/kb/revoke.ts +85 -0
  130. package/.framework/mcp/tools/kb/search.ts +101 -0
  131. package/.framework/mcp/tools/kb/upsert.ts +125 -0
  132. package/.framework/mcp/tools/observability.ts +510 -0
  133. package/.framework/migrations/001_core_schema.sql +15 -0
  134. package/.framework/migrations/002_core_rls_and_functions.sql +15 -0
  135. package/.framework/migrations/003_core_system_data.sql +16 -1
  136. package/.framework/migrations/004_core_rpc_and_broker.sql +17 -1
  137. package/.framework/migrations/005_core_observability.sql +17 -1
  138. package/.framework/migrations/006_security_hardening_rls.sql +15 -0
  139. package/.framework/migrations/007_kb_article_list.sql +17 -1
  140. package/.framework/migrations/008_items_target.sql +15 -0
  141. package/.framework/migrations/009_roles_slug_unique.sql +15 -0
  142. package/.framework/migrations/010_auth_user_trigger.sql +15 -0
  143. package/.framework/migrations/011_spine_system_account.sql +16 -0
  144. package/.framework/migrations/012_service_role_grants.sql +16 -0
  145. package/.framework/migrations/013_get_account_apps_role_filter.sql +15 -0
  146. package/.framework/migrations/014_apps_required_roles.sql +16 -0
  147. package/.framework/migrations/015_types_kind_slug_unique.sql +15 -0
  148. package/.framework/migrations/016_cil_types.sql +281 -0
  149. package/.framework/migrations/017_cil_stable_ids.sql +37 -0
  150. package/.framework/migrations/018_runtime_tables.sql +129 -0
  151. package/.framework/migrations/019_agent_prompt_columns.sql +56 -0
  152. package/.framework/migrations/020_schema_reconciliation.sql +67 -0
  153. package/.framework/migrations/021_kb_embedding_lifecycle.sql +31 -0
  154. package/.framework/migrations/032_cil_status_migration.sql +73 -0
  155. package/.framework/migrations/033_cil_versioning.sql +73 -0
  156. package/.framework/migrations/034_match_embeddings_knn.sql +115 -0
  157. package/.framework/migrations/035_rate_limits.sql +55 -0
  158. package/.framework/migrations/036_demo_record_flags.sql +72 -0
  159. package/.framework/migrations/037_kb_types_canonical.sql +244 -0
  160. package/.framework/migrations/038_drop_demo_record_flags.sql +38 -0
  161. package/.framework/migrations/042_registration_hierarchy.sql +309 -0
  162. package/.framework/migrations/043_policy_actor_cleanup.sql +39 -0
  163. package/.framework/migrations/044_match_embeddings_filtered_knn.sql +151 -0
  164. package/.framework/migrations/045_security_critical_rls.sql +139 -0
  165. package/.framework/migrations/046_security_missing_rls.sql +79 -0
  166. package/.framework/migrations/047_people_updated_by.sql +27 -0
  167. package/.framework/migrations/048_watcher_last_seen_at.sql +24 -0
  168. package/.framework/migrations/049_security_blocklist.sql +148 -0
  169. package/.framework/migrations/050_notifications.sql +49 -0
  170. package/.framework/migrations/051_message_agent_fields.sql +74 -0
  171. package/.framework/migrations/052_registration_security.sql +421 -0
  172. package/.framework/migrations/053_builtin_action_seeds.sql +66 -0
  173. package/.framework/migrations/054_kb_ingest_lease.sql +157 -0
  174. package/.framework/migrations/055_type_id_drift_reconciliation.sql +33 -0
  175. package/.framework/migrations/056_slug_column_reconciliation.sql +38 -0
  176. package/.framework/migrations/057_pipelines_slug_identity.sql +14 -0
  177. package/.framework/migrations/058_account_data_field_declarations.sql +53 -0
  178. package/.framework/migrations/059_registration_placement_fixes.sql +269 -0
  179. package/.framework/migrations/060_account_person_record_permissions.sql +38 -0
  180. package/.framework/migrations/061_fk_dedup.sql +32 -0
  181. package/.framework/public/spine-logo.svg +10 -3
  182. package/.framework/scripts/app-install-cli.ts +190 -93
  183. package/.framework/scripts/assemble-frontend.sh +127 -44
  184. package/.framework/scripts/assemble-functions.sh +128 -30
  185. package/.framework/scripts/boundary-check.sh +6 -2
  186. package/.framework/scripts/build-manifest.sh +24 -68
  187. package/.framework/scripts/check-core-integrity.sh +15 -76
  188. package/.framework/scripts/checksum-manifest.mts +343 -0
  189. package/.framework/scripts/cil-migrate-markers.ts +403 -0
  190. package/.framework/scripts/fix-cil-markers.mjs +176 -0
  191. package/.framework/scripts/verify-integrity.sh +21 -57
  192. package/.framework/scripts/verify-manifest.mts +305 -0
  193. package/.framework/seeds/types/funnel_signal_use.json +74 -21
  194. package/.framework/seeds/types/spine_instance.json +73 -21
  195. package/.framework/src/App.tsx +118 -72
  196. package/.framework/src/apps/admin/index.tsx +855 -58
  197. package/.framework/src/components/AppWrapper.tsx +43 -45
  198. package/.framework/src/components/CustomAppLoader.tsx +160 -116
  199. package/.framework/src/components/admin/AdminListPage.tsx +46 -44
  200. package/.framework/src/components/admin/AdminSidebar.tsx +57 -47
  201. package/.framework/src/components/admin/AdminStatsCard.tsx +46 -44
  202. package/.framework/src/components/admin/PageInstructions.tsx +98 -2
  203. package/.framework/src/components/admin/SortableTableHeader.tsx +44 -45
  204. package/.framework/src/components/app-shell/GenericAppShell.tsx +64 -65
  205. package/.framework/src/components/app-shell/GenericDetailPage.tsx +44 -47
  206. package/.framework/src/components/app-shell/GenericListPage.tsx +45 -49
  207. package/.framework/src/components/app-sidebar.tsx +42 -45
  208. package/.framework/src/components/auth/ProtectedRoute.tsx +48 -41
  209. package/.framework/src/components/auth/TurnstileWidget.tsx +27 -0
  210. package/.framework/src/components/kb/KBArticleEditor.tsx +231 -22
  211. package/.framework/src/components/kb/KBArticleList.tsx +251 -10
  212. package/.framework/src/components/layout/AppShell.tsx +51 -45
  213. package/.framework/src/components/layout/Header.tsx +42 -43
  214. package/.framework/src/components/layout/Layout.tsx +46 -46
  215. package/.framework/src/components/layout/Sidebar.tsx +196 -96
  216. package/.framework/src/components/runtime/DataDetailHeader.tsx +55 -30
  217. package/.framework/src/components/runtime/DataDetailPage.tsx +31 -269
  218. package/.framework/src/components/runtime/DataFilters.tsx +49 -74
  219. package/.framework/src/components/runtime/DataHeader.tsx +53 -32
  220. package/.framework/src/components/runtime/DataListPage.tsx +51 -155
  221. package/.framework/src/components/runtime/DataStats.tsx +66 -44
  222. package/.framework/src/components/runtime/DataTable.tsx +49 -149
  223. package/.framework/src/components/runtime/SchemaDetailForm.tsx +45 -75
  224. package/.framework/src/components/runtime/index.ts +119 -16
  225. package/.framework/src/components/search-form.tsx +46 -29
  226. package/.framework/src/components/shared/AgentView.tsx +65 -48
  227. package/.framework/src/components/shared/FieldRenderer.tsx +144 -50
  228. package/.framework/src/components/shared/InviteManager.tsx +207 -97
  229. package/.framework/src/components/shared/MemberList.tsx +97 -0
  230. package/.framework/src/components/shared/SchemaFields.tsx +107 -86
  231. package/.framework/src/components/ui/DataTable.tsx +80 -68
  232. package/.framework/src/components/ui/Form.tsx +157 -146
  233. package/.framework/src/components/ui/ItemCard.tsx +74 -67
  234. package/.framework/src/components/ui/ItemListView.tsx +73 -68
  235. package/.framework/src/components/ui/LoadingSpinner.tsx +43 -48
  236. package/.framework/src/components/ui/Modal.tsx +78 -68
  237. package/.framework/src/components/ui/RichTextEditor.tsx +89 -69
  238. package/.framework/src/components/ui/accordion.tsx +85 -86
  239. package/.framework/src/components/ui/alert-dialog.tsx +197 -184
  240. package/.framework/src/components/ui/alert.tsx +105 -94
  241. package/.framework/src/components/ui/aspect-ratio.tsx +57 -43
  242. package/.framework/src/components/ui/avatar.tsx +122 -107
  243. package/.framework/src/components/ui/badge.tsx +60 -55
  244. package/.framework/src/components/ui/breadcrumb.tsx +127 -128
  245. package/.framework/src/components/ui/button-group.tsx +86 -72
  246. package/.framework/src/components/ui/button.tsx +71 -50
  247. package/.framework/src/components/ui/calendar.tsx +72 -57
  248. package/.framework/src/components/ui/card.tsx +136 -129
  249. package/.framework/src/components/ui/carousel.tsx +226 -107
  250. package/.framework/src/components/ui/chart.tsx +252 -147
  251. package/.framework/src/components/ui/checkbox.tsx +43 -44
  252. package/.framework/src/components/ui/collapsible.tsx +86 -71
  253. package/.framework/src/components/ui/combobox.tsx +282 -249
  254. package/.framework/src/components/ui/command.tsx +158 -146
  255. package/.framework/src/components/ui/context-menu.tsx +239 -240
  256. package/.framework/src/components/ui/dialog.tsx +174 -157
  257. package/.framework/src/components/ui/direction.tsx +72 -56
  258. package/.framework/src/components/ui/drawer.tsx +168 -169
  259. package/.framework/src/components/ui/dropdown-menu.tsx +254 -223
  260. package/.framework/src/components/ui/empty.tsx +131 -120
  261. package/.framework/src/components/ui/field.tsx +205 -173
  262. package/.framework/src/components/ui/hover-card.tsx +71 -72
  263. package/.framework/src/components/ui/input-group.tsx +148 -133
  264. package/.framework/src/components/ui/input-otp.tsx +99 -86
  265. package/.framework/src/components/ui/input.tsx +43 -41
  266. package/.framework/src/components/ui/item.tsx +207 -185
  267. package/.framework/src/components/ui/kbd.tsx +57 -56
  268. package/.framework/src/components/ui/label.tsx +45 -41
  269. package/.framework/src/components/ui/menubar.tsx +268 -236
  270. package/.framework/src/components/ui/native-select.tsx +85 -86
  271. package/.framework/src/components/ui/navigation-menu.tsx +166 -156
  272. package/.framework/src/components/ui/pagination.tsx +131 -141
  273. package/.framework/src/components/ui/popover.tsx +125 -128
  274. package/.framework/src/components/ui/progress.tsx +47 -44
  275. package/.framework/src/components/ui/radio-group.tsx +60 -55
  276. package/.framework/src/components/ui/resizable.tsx +85 -72
  277. package/.framework/src/components/ui/scroll-area.tsx +57 -58
  278. package/.framework/src/components/ui/select.tsx +182 -169
  279. package/.framework/src/components/ui/separator.tsx +42 -43
  280. package/.framework/src/components/ui/sheet.tsx +170 -159
  281. package/.framework/src/components/ui/sidebar.tsx +395 -398
  282. package/.framework/src/components/ui/skeleton.tsx +42 -43
  283. package/.framework/src/components/ui/slider.tsx +61 -44
  284. package/.framework/src/components/ui/sonner.tsx +44 -44
  285. package/.framework/src/components/ui/spinner.tsx +47 -42
  286. package/.framework/src/components/ui/switch.tsx +56 -42
  287. package/.framework/src/components/ui/table-primitives.tsx +272 -132
  288. package/.framework/src/components/ui/table.tsx +140 -142
  289. package/.framework/src/components/ui/tabs.tsx +110 -93
  290. package/.framework/src/components/ui/textarea.tsx +43 -44
  291. package/.framework/src/components/ui/toggle-group.tsx +87 -71
  292. package/.framework/src/components/ui/toggle.tsx +56 -56
  293. package/.framework/src/components/ui/tooltip.tsx +99 -85
  294. package/.framework/src/contexts/AppContext.tsx +166 -114
  295. package/.framework/src/contexts/AuthContext.tsx +232 -137
  296. package/.framework/src/hooks/use-mobile.ts +43 -44
  297. package/.framework/src/hooks/useApi.ts +185 -172
  298. package/.framework/src/hooks/useAppPath.ts +31 -29
  299. package/.framework/src/hooks/useApps.ts +77 -42
  300. package/.framework/src/hooks/useEntityList.ts +66 -29
  301. package/.framework/src/hooks/useEntityRecord.ts +76 -32
  302. package/.framework/src/hooks/useForm.ts +62 -30
  303. package/.framework/src/hooks/useListSchema.ts +60 -43
  304. package/.framework/src/hooks/useSchemaRecord.ts +115 -95
  305. package/.framework/src/lib/api.ts +258 -134
  306. package/.framework/src/lib/registration.ts +181 -0
  307. package/.framework/src/lib/supabase.ts +118 -81
  308. package/.framework/src/lib/utils.ts +266 -266
  309. package/.framework/src/main.tsx +43 -44
  310. package/.framework/src/pages/DashboardPage.tsx +44 -43
  311. package/.framework/src/pages/NoAppPage.tsx +50 -0
  312. package/.framework/src/pages/NotFoundPage.tsx +32 -29
  313. package/.framework/src/pages/SetupPage.tsx +34 -33
  314. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +69 -58
  315. package/.framework/src/pages/admin/AIAgentsPage.tsx +43 -40
  316. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +63 -55
  317. package/.framework/src/pages/admin/APIKeysPage.tsx +44 -42
  318. package/.framework/src/pages/admin/AlertsConfigPage.tsx +117 -94
  319. package/.framework/src/pages/admin/AppDetailPage.tsx +48 -42
  320. package/.framework/src/pages/admin/AppsPage.tsx +45 -42
  321. package/.framework/src/pages/admin/DeliveriesPage.tsx +49 -17
  322. package/.framework/src/pages/admin/DesignedPage.tsx +31 -30
  323. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +58 -0
  324. package/.framework/src/pages/admin/EmbeddingsPage.tsx +49 -0
  325. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +31 -29
  326. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +46 -29
  327. package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -29
  328. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +68 -55
  329. package/.framework/src/pages/admin/IntegrationsPage.tsx +45 -42
  330. package/.framework/src/pages/admin/InvitesPage.tsx +60 -44
  331. package/.framework/src/pages/admin/LogsPage.tsx +87 -137
  332. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +31 -29
  333. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +150 -89
  334. package/.framework/src/pages/admin/PipelineDetailPage.tsx +77 -104
  335. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +44 -43
  336. package/.framework/src/pages/admin/PipelinesPage.tsx +59 -145
  337. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +53 -42
  338. package/.framework/src/pages/admin/PromptConfigsPage.tsx +47 -117
  339. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +31 -44
  340. package/.framework/src/pages/admin/RoleDetailPage.tsx +49 -92
  341. package/.framework/src/pages/admin/RolesPage.tsx +47 -164
  342. package/.framework/src/pages/admin/SecurityPage.tsx +310 -0
  343. package/.framework/src/pages/admin/SelectTestPage.tsx +30 -32
  344. package/.framework/src/pages/admin/ShadcnTestPage.tsx +37 -44
  345. package/.framework/src/pages/admin/SimpleDashboard.tsx +32 -44
  346. package/.framework/src/pages/admin/TestRunDetailPage.tsx +97 -44
  347. package/.framework/src/pages/admin/TestingDashboard.tsx +126 -71
  348. package/.framework/src/pages/admin/TimerDetailPage.tsx +67 -55
  349. package/.framework/src/pages/admin/TimersPage.tsx +44 -42
  350. package/.framework/src/pages/admin/TriggerDetailPage.tsx +47 -42
  351. package/.framework/src/pages/admin/TriggersPage.tsx +58 -57
  352. package/.framework/src/pages/admin/TypeDetailPage.tsx +91 -55
  353. package/.framework/src/pages/admin/TypesPage.tsx +45 -42
  354. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +258 -128
  355. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +127 -123
  356. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +308 -235
  357. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +159 -110
  358. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +432 -0
  359. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +200 -178
  360. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +286 -239
  361. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +211 -90
  362. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +156 -143
  363. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +379 -0
  364. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +337 -0
  365. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +219 -214
  366. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
  367. package/.framework/src/pages/auth/AuthConfirmPage.tsx +135 -65
  368. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +39 -31
  369. package/.framework/src/pages/auth/LoginPage.tsx +38 -32
  370. package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -28
  371. package/.framework/src/pages/auth/RegisterPage.tsx +429 -155
  372. package/.framework/src/pages/spine-framework/APIPage.tsx +33 -30
  373. package/.framework/src/pages/spine-framework/CLIPage.tsx +32 -30
  374. package/.framework/src/types/auth.ts +101 -93
  375. package/.framework/src/types/types.ts +283 -262
  376. package/.framework/templates/project.json +87 -0
  377. package/.framework/templates/spine.config.neutral.json +7 -0
  378. package/.framework/tests/api/api-surface.test.ts +381 -0
  379. package/.framework/tests/fixtures/seed.ts +427 -0
  380. package/.framework/tests/fixtures/teardown.ts +228 -0
  381. package/.framework/tests/reporter.ts +351 -0
  382. package/.framework/tests/setup.ts +135 -0
  383. package/.framework/tests/ui/ui-sweep.ts +278 -0
  384. package/.framework/tests/unit/admin-data-logger.test.ts +310 -0
  385. package/.framework/tests/unit/agent-runner.test.ts +2389 -0
  386. package/.framework/tests/unit/ai-interactions.test.ts +81 -0
  387. package/.framework/tests/unit/app-manifest.test.ts +359 -0
  388. package/.framework/tests/unit/assembly-scripts.test.ts +172 -0
  389. package/.framework/tests/unit/cil-determinism.test.ts +85 -0
  390. package/.framework/tests/unit/core-isolation.test.ts +153 -0
  391. package/.framework/tests/unit/funnel-signals.test.ts +135 -0
  392. package/.framework/tests/unit/install-app.test.ts +1759 -0
  393. package/.framework/tests/unit/invites-security.test.ts +572 -0
  394. package/.framework/tests/unit/kb-ingest-lease.test.ts +287 -0
  395. package/.framework/tests/unit/kb-search.test.ts +119 -0
  396. package/.framework/tests/unit/migrate.test.ts +509 -0
  397. package/.framework/tests/unit/notify.test.ts +136 -0
  398. package/.framework/tests/unit/permissions.test.ts +269 -0
  399. package/.framework/tests/unit/pipeline-runner.test.ts +755 -0
  400. package/.framework/tests/unit/principal-cache.test.ts +138 -0
  401. package/.framework/tests/unit/retrieval-golden.test.ts +520 -0
  402. package/.framework/tests/unit/runtime-isolation.test.ts +642 -0
  403. package/.framework/tests/unit/schema-utils.test.ts +225 -0
  404. package/.framework/tests/unit/trigger-engine.test.ts +513 -0
  405. package/.framework/tests/unit/validate-app.test.ts +527 -0
  406. package/README.md +34 -3
  407. package/bin/spine-framework.cjs +1 -0
  408. package/config/tailwind.config.cjs +7 -0
  409. package/config/tsconfig.functions.json +42 -0
  410. package/config/tsconfig.json +37 -9
  411. package/config/vite.config.ts +31 -2
  412. package/netlify.toml +31 -3
  413. package/package.json +46 -29
  414. package/scripts/assemble-frontend.sh +127 -44
  415. package/scripts/assemble-functions.sh +127 -29
  416. package/scripts/boundary-check.sh +6 -2
  417. package/scripts/build-manifest.sh +24 -68
  418. package/scripts/checksum-manifest.mts +345 -0
  419. package/scripts/dev-clean.sh +86 -0
  420. package/scripts/dev-netlify.sh +49 -0
  421. package/scripts/netlify-dev-wrapper.sh +2 -0
  422. package/scripts/verify-install.ts +358 -0
  423. package/scripts/verify-integrity.sh +21 -57
  424. package/scripts/verify-manifest.mts +305 -0
  425. package/templates/project/gitignore +45 -0
  426. package/{config → templates/project}/package-lock.json +22335 -9366
  427. package/vitest.config.ts +46 -0
  428. package/.framework/public/spine.config.json +0 -91
  429. package/config/deno.lock +0 -108
  430. package/config/tsconfig.node.tsbuildinfo +0 -1
  431. package/config/tsconfig.tsbuildinfo +0 -1
  432. package/config/vite.config.d.ts +0 -2
  433. package/custom/.devin/AGENT.md +0 -357
  434. package/custom/.devin/skills/install-app/SKILL.md +0 -39
  435. package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +0 -39
  436. package/custom/.devin/skills/spine-workbench-idea/SKILL.md +0 -36
  437. package/custom/.devin/skills/spine-workbench-implement/SKILL.md +0 -46
  438. package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +0 -28
  439. package/custom/.devin/skills/spine-workbench-plan/SKILL.md +0 -38
  440. package/custom/.devin/workflows/app-install.yaml +0 -83
  441. package/custom/README.md +0 -79
  442. package/docs/README.md +0 -15
  443. package/scripts/app-install-cli.ts +0 -286
  444. package/scripts/check-core-integrity.sh +0 -82
  445. package/scripts/ingest-chunks.cjs +0 -202
  446. package/scripts/kb-chunk-parser.cjs +0 -312
  447. package/scripts/kb-chunk-parser.ts +0 -330
  448. package/scripts/kb-ingest-docs.ts +0 -203
  449. package/scripts/load-test-app-install.ts +0 -484
  450. package/scripts/test-login.js +0 -33
  451. package/spine.config.json +0 -91
@@ -1,24 +1,26 @@
1
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_graph_module_header_1784235266" type="module_header" identity="module_header" parent="none"]
2
- // CIL[DOC-MACRO purpose="Module header and top-level exports for cortex.functions.custom_cil-graph"]
3
- // CIL[DOC-RESPONSIBILITY responsibility="Own module-level imports, exports, and configuration for cortex.functions.custom_cil-graph"]
4
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-graph" layer="function" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
5
- // CIL[DOC-CONTRACT inputs="none" outputs="module exports and side effects" errors="none" side_effects="none"]
6
- // CIL[DOC-MICRO logic_summary="Declares module scope, imports dependencies, and exports public surface of cortex.functions.custom_cil-graph" notable_decisions="[]"]
7
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/functions/cil-graph.ts"]
2
+ // CIL[DOC-MACRO purpose="Netlify function that exposes CIL chunk graph queries and search over the spine CIL index"]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Serve callers, blast radius, file chunks, project graph, search, and graph diff for CIL"]
4
+ // CIL[DOC-CONTEXT module=".framework/functions" layer="functions" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts"]
5
+ // CIL[DOC-CONTRACT inputs="HTTP action query parameter" outputs="JSON contract, graph, search results, or diff" errors="Unknown action or missing parameters" side_effects="Queries adminDb and link tables"]
6
+ // CIL[DOC-MICRO logic_summary="Creates a handler that dispatches to graph and search actions" notable_decisions="Uses Supabase RPC for vector search and link tables for edges"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
8
8
  // CIL[DOC-STABILITY stability="stable"]
9
- // CIL[DOC-AUDIENCE audience="developer"]
10
- // CIL[DOC-VECTOR type="context" content="Layer: function. 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/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, \."]
11
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
12
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
13
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
14
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
15
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
9
+ // CIL[DOC-AUDIENCE audience="spine-ia CIL pipeline and web UI"]
16
10
 
17
11
 
18
12
  import { createHandler } from './_shared/middleware'
19
13
  import { adminDb } from './_shared/db'
20
14
  import { resolveLinkTypeId } from './_shared/resolve-ids'
21
15
  import { callOpenAIEmbeddings } from './_shared/llm'
16
+ import { parseStableId } from './_shared/cil'
17
+ // CIL[DOC-VECTOR type="context" content="purpose='Netlify function that exposes CIL chunk graph queries and search over the spine CIL index'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
18
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
19
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
20
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
21
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
22
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
23
+ // CIL[END stable_id="~/.framework/functions/cil-graph.ts:module_header:module_header"]
22
24
 
23
25
 
24
26
 
@@ -26,21 +28,70 @@ import { callOpenAIEmbeddings } from './_shared/llm'
26
28
 
27
29
 
28
30
 
29
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_graph_module_header_1784235266"]
30
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_graph_chunkcontract_1784235266" type="interface" identity="chunkcontract" parent="none"]
31
- // CIL[DOC-MACRO purpose="Defines the chunkcontract type contract in cortex.functions.custom_cil-graph"]
32
- // CIL[DOC-RESPONSIBILITY responsibility="Describe the shape and allowed fields for chunkcontract"]
33
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-graph" layer="function" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
34
- // CIL[DOC-CONTRACT inputs="none" outputs="type definition for chunkcontract" errors="none" side_effects="none"]
35
- // CIL[DOC-MICRO logic_summary="Declares TypeScript type/interface chunkcontract with member definitions" notable_decisions="[]"]
36
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
31
+
32
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:resolveChunkByStableId:function" type="function" identity="resolveChunkByStableId" parent="~/.framework/functions/cil-graph.ts"]
33
+ // CIL[DOC-MACRO purpose="Resolve a CIL chunk record from the database by its stable_id and optional version"]
34
+ // CIL[DOC-RESPONSIBILITY responsibility="Lookup chunk by stable_id, fallback to project active version when version_id omitted"]
35
+ // CIL[DOC-CONTEXT module=".framework/functions" layer="functions" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/cil-graph.ts"]
36
+ // CIL[DOC-CONTRACT inputs="stableId: string, versionId?: string" outputs="chunk data or null" errors="Returns null when not found" side_effects="Reads items table via adminDb"]
37
+ // CIL[DOC-MICRO logic_summary="Parse stable_id, query any matching chunk, derive active version from project if needed, then query exact version" notable_decisions="Returns first match when no version supplied"]
38
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
37
39
  // CIL[DOC-STABILITY stability="stable"]
38
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/src/pages/admin/IntegrationsPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
39
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
40
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
41
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
40
+ async function resolveChunkByStableId(stableId: string, versionId?: string): Promise<any | null> {
41
+ const parsed = parseStableId(stableId)
42
+ if (!parsed) return null
43
+
44
+ let effectiveVersionId = versionId
45
+ if (!effectiveVersionId) {
46
+ const { data: anyChunk } = await adminDb
47
+ .from('items')
48
+ .select('id, data')
49
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
50
+ .filter('data->>stable_id', 'eq', stableId)
51
+ .maybeSingle()
52
+
53
+ if (!anyChunk) return null
54
+ const projectId = anyChunk.data?.project_id
55
+ if (projectId) {
56
+ const { data: project } = await adminDb
57
+ .from('items')
58
+ .select('id, data')
59
+ .eq('id', projectId)
60
+ .filter('data->>kb_type', 'eq', 'cil_project')
61
+ .maybeSingle()
62
+
63
+ effectiveVersionId = project?.data?.active_version_id
64
+ }
65
+ }
66
+
67
+ let q = adminDb
68
+ .from('items')
69
+ .select('id, title, data')
70
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
71
+ .filter('data->>stable_id', 'eq', stableId)
72
+
73
+ if (effectiveVersionId) {
74
+ q = q.filter('data->>version_id', 'eq', effectiveVersionId)
75
+ }
76
+
77
+ const { data } = await q.maybeSingle()
78
+ return data
79
+ }
80
+ // CIL[DOC-VECTOR type="context" content="purpose='Resolve a CIL chunk record from the database by its stable_id and optional version'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
81
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
82
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
83
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
42
84
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
43
85
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
86
+ // CIL[END stable_id="~/.framework/functions/cil-graph.ts:resolveChunkByStableId:function"]
87
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:ChunkContract:interface" type="interface" identity="ChunkContract" parent="~/.framework/functions/cil-graph.ts"]
88
+ // CIL[DOC-MACRO purpose="TypeScript contract describing a CIL chunk record for the graph API"]
89
+ // CIL[DOC-RESPONSIBILITY responsibility="Define the shape and field set returned by get_chunk_contract"]
90
+ // CIL[DOC-CONTEXT module=".framework/functions" layer="types" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/cil-graph.ts"]
91
+ // CIL[DOC-CONTRACT inputs="N/A" outputs="Interface fields for chunk metadata and edges" errors="N/A" side_effects="N/A"]
92
+ // CIL[DOC-MICRO logic_summary="Declares all scalar and edge fields for a CIL chunk" notable_decisions="Uses string or null types for optional paths and version"]
93
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
94
+ // CIL[DOC-STABILITY stability="stable"]
44
95
  interface ChunkContract {
45
96
  id: string
46
97
  chunk_name: string
@@ -60,10 +111,19 @@ interface ChunkContract {
60
111
  boundary_confidence: string
61
112
  stored_hash: string | null
62
113
  hash_status: 'current' | 'drift_detected' | 'unknown'
114
+ content_hash: string | null
115
+ version_id: string | null
63
116
  callers: { chunk_id: string; chunk_name: string; file_path: string }[]
64
117
  callees: { chunk_id: string; chunk_name: string; file_path: string }[]
65
118
  is_dead_code: boolean
66
119
  }
120
+ // CIL[DOC-VECTOR type="context" content="purpose='TypeScript contract describing a CIL chunk record for the graph API'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
121
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
122
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
123
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
124
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
125
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
126
+ // CIL[END stable_id="~/.framework/functions/cil-graph.ts:ChunkContract:interface"]
67
127
 
68
128
 
69
129
 
@@ -71,22 +131,21 @@ interface ChunkContract {
71
131
 
72
132
 
73
133
 
74
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_graph_chunkcontract_1784235266"]
75
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_graph_getchunkbyid_1784235266" type="function" identity="getchunkbyid" parent="none"]
76
- // CIL[DOC-MACRO purpose="Implements getchunkbyid logic in cortex.functions.custom_cil-graph"]
77
- // CIL[DOC-RESPONSIBILITY responsibility="Execute getchunkbyid and return its computed result"]
78
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-graph" layer="function" related_files="[\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\"\\\"]"]
79
- // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
80
- // CIL[DOC-MICRO logic_summary="Provides getchunkbyid with getChunkById(chunkId: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
81
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
134
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:getChunkById:function" type="function" identity="getChunkById" parent="~/.framework/functions/cil-graph.ts"]
135
+ // CIL[DOC-MACRO purpose="Fetch a single chunk by id, title, or chunk_name, with optional stable_id and version fallback"]
136
+ // CIL[DOC-RESPONSIBILITY responsibility="Resolve chunk identifier to record using multiple lookup strategies"]
137
+ // CIL[DOC-CONTEXT module=".framework/functions" layer="functions" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/cil-graph.ts"]
138
+ // CIL[DOC-CONTRACT inputs="chunkId: string, stableId?: string, versionId?: string" outputs="chunk data or null" errors="Returns null when not found" side_effects="Reads active items table"]
139
+ // CIL[DOC-MICRO logic_summary="Try stable_id resolution, then id, title, and chunk_name lookups" notable_decisions="Short-circuits on stable_id before trying other keys"]
140
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
82
141
  // CIL[DOC-STABILITY stability="stable"]
83
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, \."]
84
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
85
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
86
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
87
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
88
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
89
- async function getChunkById(chunkId: string): Promise<any | null> {
142
+ async function getChunkById(chunkId: string, stableId?: string, versionId?: string): Promise<any | null> {
143
+ if (stableId) {
144
+ const chunk = await resolveChunkByStableId(stableId, versionId)
145
+ if (chunk) return chunk
146
+ return null
147
+ }
148
+
90
149
  const { data: byId } = await adminDb
91
150
  .from('items')
92
151
  .select('id, title, data')
@@ -112,37 +171,42 @@ async function getChunkById(chunkId: string): Promise<any | null> {
112
171
  .maybeSingle()
113
172
  return byChunkName
114
173
  }
174
+ // CIL[DOC-VECTOR type="context" content="purpose='Fetch a single chunk by id, title, or chunk_name, with optional stable_id and version fallback'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
175
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
176
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
177
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
178
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
179
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
180
+ // CIL[END stable_id="~/.framework/functions/cil-graph.ts:getChunkById:function"]
115
181
 
116
182
 
117
183
 
118
184
 
119
185
 
120
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_graph_getchunkbyid_1784235266"]
121
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_graph_getlinkedchunks_1784235266" type="function" identity="getlinkedchunks" parent="none"]
122
- // CIL[DOC-MACRO purpose="Implements getlinkedchunks logic in cortex.functions.custom_cil-graph"]
123
- // CIL[DOC-RESPONSIBILITY responsibility="Execute getlinkedchunks and return its computed result"]
124
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-graph" layer="function" related_files="[\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\"\\\"]"]
125
- // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
126
- // CIL[DOC-MICRO logic_summary="Provides getlinkedchunks with getLinkedChunks( inputs, handling internal flow and returning a result" notable_decisions="[]"]
127
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
186
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:getLinkedChunks:function" type="function" identity="getLinkedChunks" parent="~/.framework/functions/cil-graph.ts"]
187
+ // CIL[DOC-MACRO purpose="Retrieve caller or callee chunks for a given chunk via the cil_calls link type"]
188
+ // CIL[DOC-RESPONSIBILITY responsibility="Resolve link type, query links, then map target/source ids to chunk metadata"]
189
+ // CIL[DOC-CONTEXT module=".framework/functions" layer="functions" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/cil-graph.ts"]
190
+ // CIL[DOC-CONTRACT inputs="chunkId: string, linkTypeSlug: string, direction: callers|callees, versionId?: string" outputs="Array of chunk_id, chunk_name, file_path" errors="Returns empty array on link-type resolution failure" side_effects="Reads links and items tables"]
191
+ // CIL[DOC-MICRO logic_summary="Resolve link type, filter by version, collect ids, then map linked chunks" notable_decisions="Swallows exceptions and returns empty list on errors"]
192
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
128
193
  // CIL[DOC-STABILITY stability="stable"]
129
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, \."]
130
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
131
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
132
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
133
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
134
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
135
194
  async function getLinkedChunks(
136
195
  chunkId: string,
137
196
  linkTypeSlug: string,
138
- direction: 'callers' | 'callees'
197
+ direction: 'callers' | 'callees',
198
+ versionId?: string
139
199
  ): Promise<{ chunk_id: string; chunk_name: string; file_path: string }[]> {
140
200
  try {
141
201
  const linkTypeId = await resolveLinkTypeId(linkTypeSlug)
142
202
 
143
- const query = direction === 'callees'
144
- ? adminDb.from('links').select('target_id').eq('source_id', chunkId).eq('link_type_id', linkTypeId)
145
- : adminDb.from('links').select('source_id').eq('target_id', chunkId).eq('link_type_id', linkTypeId)
203
+ let query = direction === 'callees'
204
+ ? adminDb.from('links').select('target_id, metadata').eq('source_id', chunkId).eq('link_type_id', linkTypeId)
205
+ : adminDb.from('links').select('source_id, metadata').eq('target_id', chunkId).eq('link_type_id', linkTypeId)
206
+
207
+ if (versionId) {
208
+ query = query.filter('metadata->>version_id', 'eq', versionId)
209
+ }
146
210
 
147
211
  const { data: links } = await query
148
212
  if (!links || links.length === 0) return []
@@ -165,6 +229,13 @@ async function getLinkedChunks(
165
229
  return []
166
230
  }
167
231
  }
232
+ // CIL[DOC-VECTOR type="context" content="purpose='Retrieve caller or callee chunks for a given chunk via the cil_calls link type'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
233
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
234
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
235
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
236
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
237
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
238
+ // CIL[END stable_id="~/.framework/functions/cil-graph.ts:getLinkedChunks:function"]
168
239
 
169
240
 
170
241
 
@@ -172,36 +243,34 @@ async function getLinkedChunks(
172
243
 
173
244
 
174
245
 
175
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_graph_getlinkedchunks_1784235266"]
176
- // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_graph_handler_1784235266" type="variable" identity="handler" parent="none"]
177
- // CIL[DOC-MACRO purpose="Defines handler configuration or state in cortex.functions.custom_cil-graph"]
178
- // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for handler"]
179
- // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-graph" layer="function" related_files="[\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\"\\\"]"]
180
- // CIL[DOC-CONTRACT inputs="none" outputs="value of handler" errors="none" side_effects="none"]
181
- // CIL[DOC-MICRO logic_summary="Declares handler with initial value or constant binding used by cortex.functions.custom_cil-graph" notable_decisions="[]"]
182
- // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
246
+ // CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/cil-graph.ts"]
247
+ // CIL[DOC-MACRO purpose="Main request handler for the cil-graph function dispatching graph and search actions"]
248
+ // CIL[DOC-RESPONSIBILITY responsibility="Validate query parameters, route to the correct action, and return JSON results"]
249
+ // CIL[DOC-CONTEXT module=".framework/functions" layer="functions" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/cil-graph.ts"]
250
+ // CIL[DOC-CONTRACT inputs="ctx, body, action via ctx.query.action, versionId via ctx.query.version_id or body" outputs="JSON response per action" errors="Throws Error for missing/invalid action or parameters" side_effects="Queries adminDb and calls embeddings"]
251
+ // CIL[DOC-MICRO logic_summary="Create handler that branches on action, runs db queries and vector search, then serializes results" notable_decisions="Vector search falls through to text search on failure; graph diff loads two versions and compares edge sets"]
252
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
183
253
  // CIL[DOC-STABILITY stability="stable"]
184
- // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/IntegrationsPage.tsx, \."]
185
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
186
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
187
- // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
188
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
189
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
190
254
  export const handler = createHandler(async (ctx, body) => {
191
255
  const action = ctx.query?.action
192
256
 
193
257
 
194
258
  if (action === 'get_chunk_contract') {
195
259
  const chunkId = ctx.query?.chunk_id
196
- if (!chunkId) throw new Error('chunk_id is required')
260
+ const stableId = ctx.query?.stable_id
261
+ const versionId = ctx.query?.version_id
262
+ if (!chunkId && !stableId) throw new Error('chunk_id or stable_id is required')
197
263
 
198
- const chunk = await getChunkById(chunkId)
199
- if (!chunk) throw new Error(`Chunk not found: ${chunkId}`)
264
+ const chunk = await getChunkById(chunkId || '', stableId, versionId)
265
+ if (!chunk) {
266
+ throw new Error(stableId ? `Chunk not found for stable_id: ${stableId}` : `Chunk not found: ${chunkId}`)
267
+ }
200
268
  const resolvedChunkId = chunk.id
269
+ const effectiveVersionId = versionId || chunk.data?.version_id
201
270
 
202
271
  const [callers, callees] = await Promise.all([
203
- getLinkedChunks(resolvedChunkId, 'cil_calls', 'callers'),
204
- getLinkedChunks(resolvedChunkId, 'cil_calls', 'callees'),
272
+ getLinkedChunks(resolvedChunkId, 'cil_calls', 'callers', effectiveVersionId),
273
+ getLinkedChunks(resolvedChunkId, 'cil_calls', 'callees', effectiveVersionId),
205
274
  ])
206
275
 
207
276
  const d = chunk.data || {}
@@ -224,6 +293,8 @@ export const handler = createHandler(async (ctx, body) => {
224
293
  boundary_confidence: d.boundary_confidence || 'unknown',
225
294
  stored_hash: d.stored_hash || null,
226
295
  hash_status: 'unknown', // validated on demand via custom_cil-validate
296
+ content_hash: d.content_hash || null,
297
+ version_id: d.version_id || null,
227
298
  callers,
228
299
  callees,
229
300
  is_dead_code: d.is_dead_code || false,
@@ -235,22 +306,32 @@ export const handler = createHandler(async (ctx, body) => {
235
306
 
236
307
  if (action === 'get_callers') {
237
308
  const chunkId = ctx.query?.chunk_id
238
- if (!chunkId) throw new Error('chunk_id is required')
239
- const chunk = await getChunkById(chunkId)
240
- if (!chunk) throw new Error(`Chunk not found: ${chunkId}`)
241
- const callers = await getLinkedChunks(chunk.id, 'cil_calls', 'callers')
309
+ const stableId = ctx.query?.stable_id
310
+ const versionId = ctx.query?.version_id
311
+ if (!chunkId && !stableId) throw new Error('chunk_id or stable_id is required')
312
+ const chunk = await getChunkById(chunkId || '', stableId, versionId)
313
+ if (!chunk) {
314
+ throw new Error(stableId ? `Chunk not found for stable_id: ${stableId}` : `Chunk not found: ${chunkId}`)
315
+ }
316
+ const effectiveVersionId = versionId || chunk.data?.version_id
317
+ const callers = await getLinkedChunks(chunk.id, 'cil_calls', 'callers', effectiveVersionId)
242
318
  return { chunk_id: chunk.id, callers }
243
319
  }
244
320
 
245
321
 
246
322
  if (action === 'get_blast_radius') {
247
323
  const chunkId = ctx.query?.chunk_id
324
+ const stableId = ctx.query?.stable_id
325
+ const versionId = ctx.query?.version_id
248
326
  const maxDepth = parseInt(ctx.query?.max_depth || '3')
249
- if (!chunkId) throw new Error('chunk_id is required')
327
+ if (!chunkId && !stableId) throw new Error('chunk_id or stable_id is required')
250
328
 
251
- const rootChunk = await getChunkById(chunkId)
252
- if (!rootChunk) throw new Error(`Chunk not found: ${chunkId}`)
329
+ const rootChunk = await getChunkById(chunkId || '', stableId, versionId)
330
+ if (!rootChunk) {
331
+ throw new Error(stableId ? `Chunk not found for stable_id: ${stableId}` : `Chunk not found: ${chunkId}`)
332
+ }
253
333
  const resolvedChunkId = rootChunk.id
334
+ const effectiveVersionId = versionId || rootChunk.data?.version_id
254
335
 
255
336
  const visited = new Set<string>()
256
337
  const queue: { id: string; depth: number }[] = [{ id: resolvedChunkId, depth: 0 }]
@@ -274,7 +355,7 @@ export const handler = createHandler(async (ctx, body) => {
274
355
  }
275
356
 
276
357
  if (depth < maxDepth) {
277
- const callers = await getLinkedChunks(id, 'cil_calls', 'callers')
358
+ const callers = await getLinkedChunks(id, 'cil_calls', 'callers', effectiveVersionId)
278
359
  for (const caller of callers) {
279
360
  if (!visited.has(caller.chunk_id)) {
280
361
  queue.push({ id: caller.chunk_id, depth: depth + 1 })
@@ -370,6 +451,7 @@ export const handler = createHandler(async (ctx, body) => {
370
451
  if (action === 'search') {
371
452
  const query = ctx.query?.q || body?.q
372
453
  const projectId = ctx.query?.project_id || body?.project_id
454
+ const versionId = ctx.query?.version_id || body?.version_id
373
455
  const limit = parseInt(ctx.query?.limit || '20')
374
456
  const mode = ctx.query?.mode || body?.mode || 'hybrid'
375
457
  if (!query) throw new Error('q is required')
@@ -386,9 +468,9 @@ export const handler = createHandler(async (ctx, body) => {
386
468
  const vectorLiteral = `[${vec.join(',')}]`
387
469
  const { data: matches } = await adminDb.rpc('match_embeddings', {
388
470
  query_embedding: vectorLiteral,
389
- match_count: limit,
390
- filter_vector_type: 'semantic',
391
- similarity_threshold: 0.2,
471
+ match_count: limit * 3,
472
+ filter_vector_type: null,
473
+ similarity_threshold: 0.15,
392
474
  filter_item_types: ['cil_chunk'],
393
475
  })
394
476
 
@@ -397,27 +479,42 @@ export const handler = createHandler(async (ctx, body) => {
397
479
  let chunkQuery = adminDb
398
480
  .from('items')
399
481
  .select('id, title, data')
400
- .in('id', matchIds)
482
+ .in('data->>stable_id', matchIds)
401
483
  .eq('is_active', true)
402
484
 
403
485
  if (projectId) {
404
486
  chunkQuery = chunkQuery.filter('data->>project_id', 'eq', projectId)
405
487
  }
488
+ if (versionId) {
489
+ chunkQuery = chunkQuery.filter('data->>version_id', 'eq', versionId)
490
+ }
406
491
 
407
492
  const { data: chunks } = await chunkQuery
408
- const chunkMap = new Map((chunks || []).map((c: any) => [c.id, c]))
493
+ const chunkMap = new Map((chunks || []).map((c: any) => [c.data?.stable_id, c]))
409
494
 
410
495
  for (const m of (matches || [])) {
411
496
  const chunk = chunkMap.get(m.document_id)
412
497
  if (!chunk || seenIds.has(chunk.id)) continue
413
498
  seenIds.add(chunk.id)
499
+ const d = chunk.data || {}
414
500
  results.push({
415
501
  id: chunk.id,
416
- chunk_name: chunk.data?.chunk_name || chunk.title,
417
- file_path: chunk.data?.file_path || '',
418
- macro: chunk.data?.macro || '',
419
- chunk_type: chunk.data?.chunk_type || '',
420
- doc_confidence: chunk.data?.doc_confidence || '',
502
+ stable_id: d.stable_id || '',
503
+ version_id: d.version_id || null,
504
+ chunk_name: d.chunk_name || chunk.title,
505
+ file_path: d.file_path || '',
506
+ chunk_type: d.chunk_type || '',
507
+ source_set_id: d.source_set_id || null,
508
+ layer: d.layer || null,
509
+ macro: d.macro || '',
510
+ micro: d.micro || '',
511
+ input_spec: d.input_spec || '',
512
+ output_spec: d.output_spec || '',
513
+ side_effects: d.side_effects || '',
514
+ stability: d.stability || 'unknown',
515
+ tags: d.tags || '',
516
+ complexity: d.complexity || '',
517
+ doc_confidence: d.doc_confidence || 'unverified_legacy',
421
518
  similarity: m.similarity,
422
519
  match_type: 'semantic',
423
520
  })
@@ -434,23 +531,68 @@ export const handler = createHandler(async (ctx, body) => {
434
531
  .select('id, title, data')
435
532
  .filter('data->>kb_type', 'eq', 'cil_chunk')
436
533
  .eq('is_active', true)
437
- .limit(limit - results.length)
534
+ .limit(5000)
438
535
 
439
536
  if (projectId) dbQuery = dbQuery.filter('data->>project_id', 'eq', projectId)
440
- const { data: textResults } = await dbQuery.ilike('title', `%${query}%`)
441
-
442
- for (const r of textResults || []) {
537
+ if (versionId) dbQuery = dbQuery.filter('data->>version_id', 'eq', versionId)
538
+ const { data: textResults } = await dbQuery
539
+
540
+ const normalizedQuery = query.toLowerCase().replace(/[^a-z0-9]/g, '')
541
+ const terms = query.toLowerCase().split(/[^a-z0-9]+/).filter((t: string) => t.length >= 2)
542
+ const phrase = query.toLowerCase()
543
+
544
+ const scored = (textResults || []).map((r: any) => {
545
+ const d = r.data || {}
546
+ const title = (r.title || '').toLowerCase()
547
+ const macro = (d.macro || '').toLowerCase()
548
+ const micro = (d.micro || '').toLowerCase()
549
+ const tags = (d.tags || '').toLowerCase()
550
+ const codeContent = (d.code_content || '').toLowerCase()
551
+ const normTitle = title.replace(/[^a-z0-9]/g, '')
552
+ const normMacro = macro.replace(/[^a-z0-9]/g, '')
553
+ const normMicro = micro.replace(/[^a-z0-9]/g, '')
554
+ const normTags = tags.replace(/[^a-z0-9]/g, '')
555
+ const normCode = codeContent.replace(/[^a-z0-9]/g, '')
556
+ let score = 0
557
+ for (const term of terms) {
558
+ if (normTitle.includes(term)) score += 3
559
+ if (normMacro.includes(term)) score += 2
560
+ if (normMicro.includes(term)) score += 1
561
+ if (normTags.includes(term)) score += 1
562
+ const codeCount = normCode.split(term).length - 1
563
+ score += Math.min(codeCount, 3)
564
+ }
565
+ if (codeContent.includes(phrase) || normCode.includes(normalizedQuery)) score += 5
566
+ return { chunk: r, score }
567
+ })
568
+ .filter(({ score }: any) => score > 0)
569
+ .sort((a: any, b: any) => b.score - a.score)
570
+ .slice(0, limit - results.length)
571
+
572
+ for (const { chunk: r, score } of scored) {
443
573
  if (seenIds.has(r.id)) continue
444
574
  seenIds.add(r.id)
575
+ const d = r.data || {}
445
576
  results.push({
446
577
  id: r.id,
447
- chunk_name: r.data?.chunk_name || r.title,
448
- file_path: r.data?.file_path || '',
449
- macro: r.data?.macro || '',
450
- chunk_type: r.data?.chunk_type || '',
451
- doc_confidence: r.data?.doc_confidence || '',
452
- similarity: null,
453
- match_type: 'text',
578
+ stable_id: d.stable_id || '',
579
+ version_id: d.version_id || null,
580
+ chunk_name: d.chunk_name || r.title,
581
+ file_path: d.file_path || '',
582
+ chunk_type: d.chunk_type || '',
583
+ source_set_id: d.source_set_id || null,
584
+ layer: d.layer || null,
585
+ macro: d.macro || '',
586
+ micro: d.micro || '',
587
+ input_spec: d.input_spec || '',
588
+ output_spec: d.output_spec || '',
589
+ side_effects: d.side_effects || '',
590
+ stability: d.stability || 'unknown',
591
+ tags: d.tags || '',
592
+ complexity: d.complexity || '',
593
+ doc_confidence: d.doc_confidence || 'unverified_legacy',
594
+ similarity: score / maxScore,
595
+ match_type: 'content',
454
596
  })
455
597
  }
456
598
  }
@@ -467,14 +609,33 @@ export const handler = createHandler(async (ctx, body) => {
467
609
  .eq('id', fileId).maybeSingle()
468
610
  if (!fileItem) throw new Error(`File not found: ${fileId}`)
469
611
 
470
- const { data: chunks } = await adminDb.from('items').select('id, title, data')
612
+ let versionId = ctx.query?.version_id
613
+ if (!versionId) {
614
+ const projectId = fileItem.data?.project_id
615
+ if (projectId) {
616
+ const { data: project } = await adminDb
617
+ .from('items')
618
+ .select('id, data')
619
+ .eq('id', projectId)
620
+ .filter('data->>kb_type', 'eq', 'cil_project')
621
+ .maybeSingle()
622
+ versionId = project?.data?.active_version_id
623
+ }
624
+ }
625
+
626
+ let chunksQuery = adminDb.from('items').select('id, title, data')
471
627
  .filter('data->>kb_type', 'eq', 'cil_chunk')
472
628
  .filter('data->>file_id', 'eq', fileId)
473
629
  .eq('is_active', true)
474
630
 
631
+ if (versionId) chunksQuery = chunksQuery.filter('data->>version_id', 'eq', versionId)
632
+
633
+ const { data: chunks } = await chunksQuery
634
+
475
635
  const sorted = (chunks || [])
476
636
  .map((c: any) => ({
477
637
  id: c.id,
638
+ stable_id: c.data?.stable_id || '',
478
639
  chunk_name: c.data?.chunk_name || '',
479
640
  chunk_type: c.data?.chunk_type || '',
480
641
  line_start: c.data?.line_start || 0,
@@ -503,54 +664,79 @@ export const handler = createHandler(async (ctx, body) => {
503
664
 
504
665
  if (action === 'get_project_graph') {
505
666
  const projectId = ctx.query?.project_id
667
+ const versionId = ctx.query?.version_id
506
668
  if (!projectId) throw new Error('project_id is required')
507
669
 
508
- const [filesResult, chunksResult] = await Promise.all([
509
- adminDb.from('items').select('id, title, data')
510
- .filter('data->>kb_type', 'eq', 'cil_file')
511
- .filter('data->>project_id', 'eq', projectId)
512
- .eq('is_active', true),
513
- adminDb.from('items').select('id, title, data')
514
- .filter('data->>kb_type', 'eq', 'cil_chunk')
515
- .filter('data->>project_id', 'eq', projectId)
516
- .eq('is_active', true)
517
- .limit(500),
670
+ const PAGE_SIZE = 1000
671
+
672
+ async function fetchAllItems(kbType: string) {
673
+ const out: any[] = []
674
+ let offset = 0
675
+ while (true) {
676
+ let q = adminDb.from('items').select('id, title, data')
677
+ .filter('data->>kb_type', 'eq', kbType)
678
+ .filter('data->>project_id', 'eq', projectId)
679
+ .eq('is_active', true)
680
+ .range(offset, offset + PAGE_SIZE - 1)
681
+ if (versionId) q = q.filter('data->>version_id', 'eq', versionId)
682
+ const { data } = await q
683
+ const rows = data || []
684
+ out.push(...rows)
685
+ if (rows.length < PAGE_SIZE) break
686
+ offset += PAGE_SIZE
687
+ }
688
+ return out
689
+ }
690
+
691
+ async function fetchAllLinks(linkTypeId: string) {
692
+ const out: any[] = []
693
+ let offset = 0
694
+ while (true) {
695
+ let q = adminDb.from('links')
696
+ .select('source_id, target_id, source_type, target_type, metadata')
697
+ .eq('link_type_id', linkTypeId)
698
+ .range(offset, offset + PAGE_SIZE - 1)
699
+ if (versionId) q = q.filter('metadata->>version_id', 'eq', versionId)
700
+ const { data } = await q
701
+ const rows = data || []
702
+ out.push(...rows)
703
+ if (rows.length < PAGE_SIZE) break
704
+ offset += PAGE_SIZE
705
+ }
706
+ return out
707
+ }
708
+
709
+ const [fileItems, chunkItems] = await Promise.all([
710
+ fetchAllItems('cil_file'),
711
+ fetchAllItems('cil_chunk'),
518
712
  ])
519
713
 
520
-
714
+ const fileIdSet = new Set(fileItems.map((f: any) => f.id))
715
+ const chunkIdSet = new Set(chunkItems.map((c: any) => c.id))
716
+
521
717
  let importEdges: any[] = []
522
718
  try {
523
719
  const importLinkTypeId = await resolveLinkTypeId('cil_imports')
524
- const fileIds = (filesResult.data || []).map((f: any) => f.id)
525
- if (fileIds.length > 0) {
526
- const { data: edges } = await adminDb
527
- .from('links')
528
- .select('source_id, target_id, metadata')
529
- .eq('link_type_id', importLinkTypeId)
530
- .in('source_id', fileIds)
531
- importEdges = edges || []
532
- }
720
+ const edges = await fetchAllLinks(importLinkTypeId)
721
+ importEdges = edges.filter((e: any) =>
722
+ chunkIdSet.has(e.source_id) &&
723
+ (fileIdSet.has(e.target_id) || chunkIdSet.has(e.target_id))
724
+ )
533
725
  } catch { /* link type may not exist yet */ }
534
726
 
535
-
536
727
  let callEdges: any[] = []
537
728
  try {
538
729
  const callLinkTypeId = await resolveLinkTypeId('cil_calls')
539
- const chunkIds = (chunksResult.data || []).map((c: any) => c.id)
540
- if (chunkIds.length > 0) {
541
- const { data: edges } = await adminDb
542
- .from('links')
543
- .select('source_id, target_id, metadata')
544
- .eq('link_type_id', callLinkTypeId)
545
- .in('source_id', chunkIds)
546
- callEdges = edges || []
547
- }
730
+ const edges = await fetchAllLinks(callLinkTypeId)
731
+ callEdges = edges.filter((e: any) =>
732
+ chunkIdSet.has(e.source_id) && chunkIdSet.has(e.target_id)
733
+ )
548
734
  } catch { /* link type may not exist yet */ }
549
735
 
550
736
  return {
551
737
  project_id: projectId,
552
738
  nodes: {
553
- files: (filesResult.data || []).map((f: any) => ({
739
+ files: fileItems.map((f: any) => ({
554
740
  id: f.id,
555
741
  file_path: f.data?.file_path || '',
556
742
  language: f.data?.language || '',
@@ -558,7 +744,7 @@ export const handler = createHandler(async (ctx, body) => {
558
744
  is_dead_code: f.data?.is_dead_code || false,
559
745
  chunk_count: f.data?.chunk_count || 0,
560
746
  })),
561
- chunks: (chunksResult.data || []).map((c: any) => ({
747
+ chunks: chunkItems.map((c: any) => ({
562
748
  id: c.id,
563
749
  chunk_name: c.data?.chunk_name || '',
564
750
  file_id: c.data?.file_id || '',
@@ -577,9 +763,108 @@ export const handler = createHandler(async (ctx, body) => {
577
763
  }
578
764
  }
579
765
 
766
+ if (action === 'graph_diff') {
767
+ const projectId = ctx.query?.project_id
768
+ const fromVersionId = ctx.query?.from_version_id
769
+ const toVersionId = ctx.query?.to_version_id
770
+ if (!projectId) throw new Error('project_id is required')
771
+ if (!fromVersionId) throw new Error('from_version_id is required')
772
+ if (!toVersionId) throw new Error('to_version_id is required')
773
+
774
+ const items: any[] = []
775
+ for (const versionId of [fromVersionId, toVersionId]) {
776
+ for (const kbType of ['cil_chunk', 'cil_file']) {
777
+ const { data: rows } = await adminDb
778
+ .from('items')
779
+ .select('id, data')
780
+ .filter('data->>kb_type', 'eq', kbType)
781
+ .filter('data->>project_id', 'eq', projectId)
782
+ .filter('data->>version_id', 'eq', versionId)
783
+ .eq('is_active', true)
784
+ if (rows) items.push(...rows)
785
+ }
786
+ }
787
+
788
+ const stableMap = new Map<string, string>()
789
+ const pathMap = new Map<string, string>()
790
+ for (const item of items) {
791
+ stableMap.set(item.id, item.data?.stable_id || item.id)
792
+ pathMap.set(item.id, item.data?.file_path || '')
793
+ }
794
+
795
+ const [callsId, importsId] = await Promise.all([
796
+ resolveLinkTypeId('cil_calls'),
797
+ resolveLinkTypeId('cil_imports'),
798
+ ])
799
+ const edgeTypeById: Record<string, string> = {
800
+ [callsId]: 'cil_calls',
801
+ [importsId]: 'cil_imports',
802
+ }
803
+
804
+ async function getEdgesForVersion(versionId: string) {
805
+ const { data: edges } = await adminDb
806
+ .from('links')
807
+ .select('source_id, target_id, link_type_id, metadata')
808
+ .in('link_type_id', [callsId, importsId])
809
+ .filter('metadata->>version_id', 'eq', versionId)
810
+
811
+ const seen = new Map<string, { edge_type: string; from_stable_id: string; to_stable_id: string; from_file_path: string; to_file_path: string }>()
812
+ for (const edge of edges || []) {
813
+ const edgeType = edgeTypeById[edge.link_type_id]
814
+ if (!edgeType) continue
815
+ if (!stableMap.has(edge.source_id) || !stableMap.has(edge.target_id)) continue
816
+
817
+ const fromStable = stableMap.get(edge.source_id)!
818
+ const toStable = stableMap.get(edge.target_id)!
819
+ const key = `${edgeType}|${fromStable}|${toStable}`
820
+ if (seen.has(key)) continue
821
+
822
+ seen.set(key, {
823
+ edge_type: edgeType,
824
+ from_stable_id: fromStable,
825
+ to_stable_id: toStable,
826
+ from_file_path: pathMap.get(edge.source_id) || '',
827
+ to_file_path: pathMap.get(edge.target_id) || '',
828
+ })
829
+ }
830
+ return seen
831
+ }
832
+
833
+ const [fromEdges, toEdges] = await Promise.all([
834
+ getEdgesForVersion(fromVersionId),
835
+ getEdgesForVersion(toVersionId),
836
+ ])
837
+
838
+ const added: any[] = []
839
+ const removed: any[] = []
840
+ const unchanged: any[] = []
841
+
842
+ for (const [key, entry] of toEdges) {
843
+ if (fromEdges.has(key)) unchanged.push(entry)
844
+ else added.push(entry)
845
+ }
846
+ for (const [key, entry] of fromEdges) {
847
+ if (!toEdges.has(key)) removed.push(entry)
848
+ }
849
+
850
+ return {
851
+ project_id: projectId,
852
+ from_version_id: fromVersionId,
853
+ to_version_id: toVersionId,
854
+ added,
855
+ removed,
856
+ unchanged,
857
+ }
858
+ }
859
+
580
860
  throw new Error(`Unknown action: ${action}. Valid: get_chunk_contract, get_callers, get_blast_radius, get_test_paths, get_file_graph, get_file_chunks, search, get_project_graph`)
581
861
  })
862
+ // CIL[DOC-VECTOR type="context" content="purpose='Main request handler for the cil-graph function dispatching graph and search actions'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
863
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
864
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
865
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
866
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
867
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
868
+ // CIL[END stable_id="~/.framework/functions/cil-graph.ts:handler:constant"]
582
869
 
583
870
 
584
-
585
- // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_graph_handler_1784235266"]