spine-framework 0.3.125 → 0.3.127

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/.framework/cli/commands/agents.ts +35 -37
  2. package/.framework/cli/commands/auth.ts +35 -34
  3. package/.framework/cli/commands/create-app.ts +104 -40
  4. package/.framework/cli/commands/dev.ts +104 -69
  5. package/.framework/cli/commands/doctor.ts +169 -97
  6. package/.framework/cli/commands/generate.ts +82 -161
  7. package/.framework/cli/commands/init.ts +72 -34
  8. package/.framework/cli/commands/install-app.ts +260 -125
  9. package/.framework/cli/commands/items.ts +33 -44
  10. package/.framework/cli/commands/migrate.ts +122 -40
  11. package/.framework/cli/commands/migrations.ts +33 -40
  12. package/.framework/cli/commands/pipelines.ts +31 -39
  13. package/.framework/cli/commands/status.ts +47 -23
  14. package/.framework/cli/commands/system.ts +47 -37
  15. package/.framework/cli/commands/test.ts +112 -68
  16. package/.framework/cli/commands/validate-app.ts +215 -121
  17. package/.framework/cli/context.ts +112 -130
  18. package/.framework/cli/env-loader.ts +47 -18
  19. package/.framework/cli/index.ts +81 -42
  20. package/.framework/docs/runtime-types.md +1024 -0
  21. package/.framework/functions/_shared/agent-runner.ts +1296 -961
  22. package/.framework/functions/_shared/app-manifest.ts +82 -68
  23. package/.framework/functions/_shared/audit.ts +135 -83
  24. package/.framework/functions/_shared/{cil-state.ts → cil.ts} +147 -54
  25. package/.framework/functions/_shared/db.ts +80 -126
  26. package/.framework/functions/_shared/hash-api-key.ts +63 -0
  27. package/.framework/functions/_shared/index.ts +222 -347
  28. package/.framework/functions/_shared/kb.ts +319 -0
  29. package/.framework/functions/_shared/llm.ts +92 -0
  30. package/.framework/functions/_shared/logging.ts +288 -0
  31. package/.framework/functions/_shared/middleware.ts +329 -365
  32. package/.framework/functions/_shared/outcomes.ts +36 -0
  33. package/.framework/functions/_shared/permissions.ts +359 -643
  34. package/.framework/functions/_shared/pipeline-runner.ts +243 -316
  35. package/.framework/functions/_shared/principal.ts +376 -468
  36. package/.framework/functions/_shared/resolve-credentials.ts +102 -0
  37. package/.framework/functions/_shared/resolve-ids.ts +162 -14
  38. package/.framework/functions/_shared/retry-deliveries.ts +104 -0
  39. package/.framework/functions/_shared/schema-utils.ts +611 -373
  40. package/.framework/functions/_shared/testing.ts +207 -137
  41. package/.framework/functions/_shared/tracing.ts +276 -0
  42. package/.framework/functions/_shared/trigger-engine.ts +159 -211
  43. package/.framework/functions/_shared/webhook-registration.ts +95 -81
  44. package/.framework/functions/_shared/webhook-registry.ts +153 -75
  45. package/.framework/functions/account-nodes.ts +31 -53
  46. package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
  47. package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
  48. package/.framework/functions/adapters/openai-outbound.ts +40 -0
  49. package/.framework/functions/admin-data.ts +687 -533
  50. package/.framework/functions/admin-funnel.ts +31 -20
  51. package/.framework/functions/admin-install-funnel.ts +47 -28
  52. package/.framework/functions/admin-signals.ts +47 -29
  53. package/.framework/functions/ai-agents.ts +122 -147
  54. package/.framework/functions/ai-interactions.ts +180 -90
  55. package/.framework/functions/api-keys.ts +250 -192
  56. package/.framework/functions/apps.ts +203 -197
  57. package/.framework/functions/auth.ts +98 -91
  58. package/.framework/functions/cil-agent-ingest.ts +773 -0
  59. package/.framework/functions/cil-agent.ts +592 -0
  60. package/.framework/functions/cil-callmap.ts +1227 -0
  61. package/.framework/functions/cil-config.ts +583 -0
  62. package/.framework/functions/cil-context.ts +445 -0
  63. package/.framework/functions/cil-doc.ts +1752 -0
  64. package/.framework/functions/cil-embeddings.ts +1202 -0
  65. package/.framework/functions/cil-graph.ts +585 -0
  66. package/.framework/functions/cil-ingest.ts +2416 -0
  67. package/.framework/functions/cil-pipeline.ts +318 -0
  68. package/.framework/functions/cil-project.ts +499 -0
  69. package/.framework/functions/cil-validate.ts +469 -0
  70. package/.framework/functions/debug-auth.ts +73 -53
  71. package/.framework/functions/deliveries.ts +117 -0
  72. package/.framework/functions/embeddings.ts +528 -516
  73. package/.framework/functions/eval-harness.ts +158 -106
  74. package/.framework/functions/integration-outbound.ts +311 -0
  75. package/.framework/functions/integration-routes.ts +240 -466
  76. package/.framework/functions/integrations.ts +132 -140
  77. package/.framework/functions/invites.ts +401 -201
  78. package/.framework/functions/item-progress.ts +113 -53
  79. package/.framework/functions/kb.ts +28 -0
  80. package/.framework/functions/logs.ts +239 -222
  81. package/.framework/functions/observability.ts +308 -259
  82. package/.framework/functions/pipeline-executions.ts +179 -235
  83. package/.framework/functions/pipelines.ts +163 -205
  84. package/.framework/functions/prompt-configs.ts +109 -156
  85. package/.framework/functions/roles.ts +97 -147
  86. package/.framework/functions/system-cron.ts +132 -218
  87. package/.framework/functions/system.ts +112 -52
  88. package/.framework/functions/tests.ts +32 -28
  89. package/.framework/functions/timers.ts +162 -210
  90. package/.framework/functions/triggers.ts +282 -346
  91. package/.framework/functions/types.ts +283 -400
  92. package/.framework/migrations/001_core_schema.sql +630 -0
  93. package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
  94. package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
  95. package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
  96. package/.framework/migrations/005_core_observability.sql +598 -0
  97. package/.framework/migrations/006_security_hardening_rls.sql +97 -0
  98. package/.framework/migrations/007_kb_article_list.sql +237 -0
  99. package/.framework/migrations/008_items_target.sql +8 -0
  100. package/.framework/migrations/009_roles_slug_unique.sql +11 -0
  101. package/.framework/public/spine.config.json +91 -0
  102. package/.framework/scripts/app-install-cli.ts +112 -98
  103. package/.framework/src/App.tsx +67 -20
  104. package/.framework/src/apps/admin/index.tsx +97 -27
  105. package/.framework/src/components/AppWrapper.tsx +50 -11
  106. package/.framework/src/components/CustomAppLoader.tsx +131 -22
  107. package/.framework/src/components/admin/AdminListPage.tsx +75 -8
  108. package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
  109. package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
  110. package/.framework/src/components/admin/PageInstructions.tsx +49 -0
  111. package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
  112. package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
  113. package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
  114. package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
  115. package/.framework/src/components/app-sidebar.tsx +50 -3
  116. package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
  117. package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
  118. package/.framework/src/components/kb/KBArticleList.tsx +557 -0
  119. package/.framework/src/components/layout/AppShell.tsx +54 -16
  120. package/.framework/src/components/layout/Header.tsx +50 -38
  121. package/.framework/src/components/layout/Layout.tsx +48 -32
  122. package/.framework/src/components/layout/Sidebar.tsx +167 -16
  123. package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
  124. package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
  125. package/.framework/src/components/runtime/DataFilters.tsx +78 -1
  126. package/.framework/src/components/runtime/DataHeader.tsx +32 -29
  127. package/.framework/src/components/runtime/DataListPage.tsx +161 -2
  128. package/.framework/src/components/runtime/DataStats.tsx +48 -1
  129. package/.framework/src/components/runtime/DataTable.tsx +153 -1
  130. package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
  131. package/.framework/src/components/runtime/index.ts +16 -9
  132. package/.framework/src/components/search-form.tsx +33 -1
  133. package/.framework/src/components/shared/AgentView.tsx +48 -51
  134. package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
  135. package/.framework/src/components/shared/InviteManager.tsx +113 -52
  136. package/.framework/src/components/shared/MemberList.tsx +182 -0
  137. package/.framework/src/components/shared/SchemaFields.tsx +96 -78
  138. package/.framework/src/components/ui/DataTable.tsx +86 -56
  139. package/.framework/src/components/ui/Form.tsx +188 -109
  140. package/.framework/src/components/ui/ItemCard.tsx +86 -58
  141. package/.framework/src/components/ui/ItemListView.tsx +88 -61
  142. package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
  143. package/.framework/src/components/ui/Modal.tsx +81 -4
  144. package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
  145. package/.framework/src/components/ui/accordion.tsx +97 -5
  146. package/.framework/src/components/ui/alert-dialog.tsx +225 -13
  147. package/.framework/src/components/ui/alert.tsx +113 -6
  148. package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
  149. package/.framework/src/components/ui/avatar.tsx +129 -7
  150. package/.framework/src/components/ui/badge.tsx +65 -3
  151. package/.framework/src/components/ui/breadcrumb.tsx +145 -8
  152. package/.framework/src/components/ui/button-group.tsx +81 -4
  153. package/.framework/src/components/ui/button.tsx +49 -2
  154. package/.framework/src/components/ui/calendar.tsx +65 -3
  155. package/.framework/src/components/ui/card.tsx +145 -8
  156. package/.framework/src/components/ui/carousel.tsx +129 -7
  157. package/.framework/src/components/ui/chart.tsx +161 -10
  158. package/.framework/src/components/ui/checkbox.tsx +49 -2
  159. package/.framework/src/components/ui/collapsible.tsx +81 -5
  160. package/.framework/src/components/ui/combobox.tsx +305 -20
  161. package/.framework/src/components/ui/command.tsx +177 -11
  162. package/.framework/src/components/ui/context-menu.tsx +273 -17
  163. package/.framework/src/components/ui/dialog.tsx +209 -27
  164. package/.framework/src/components/ui/direction.tsx +64 -4
  165. package/.framework/src/components/ui/drawer.tsx +193 -12
  166. package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
  167. package/.framework/src/components/ui/empty.tsx +145 -9
  168. package/.framework/src/components/ui/field.tsx +209 -14
  169. package/.framework/src/components/ui/hover-card.tsx +81 -4
  170. package/.framework/src/components/ui/input-group.tsx +162 -10
  171. package/.framework/src/components/ui/input-otp.tsx +98 -5
  172. package/.framework/src/components/ui/input.tsx +49 -2
  173. package/.framework/src/components/ui/item.tsx +225 -13
  174. package/.framework/src/components/ui/kbd.tsx +65 -3
  175. package/.framework/src/components/ui/label.tsx +49 -2
  176. package/.framework/src/components/ui/menubar.tsx +289 -17
  177. package/.framework/src/components/ui/native-select.tsx +97 -5
  178. package/.framework/src/components/ui/navigation-menu.tsx +177 -10
  179. package/.framework/src/components/ui/pagination.tsx +161 -9
  180. package/.framework/src/components/ui/popover.tsx +145 -8
  181. package/.framework/src/components/ui/progress.tsx +49 -2
  182. package/.framework/src/components/ui/radio-group.tsx +65 -3
  183. package/.framework/src/components/ui/resizable.tsx +82 -4
  184. package/.framework/src/components/ui/scroll-area.tsx +65 -3
  185. package/.framework/src/components/ui/select.tsx +193 -11
  186. package/.framework/src/components/ui/separator.tsx +49 -2
  187. package/.framework/src/components/ui/sheet.tsx +193 -11
  188. package/.framework/src/components/ui/sidebar.tsx +481 -38
  189. package/.framework/src/components/ui/skeleton.tsx +49 -2
  190. package/.framework/src/components/ui/slider.tsx +49 -2
  191. package/.framework/src/components/ui/sonner.tsx +49 -2
  192. package/.framework/src/components/ui/spinner.tsx +49 -2
  193. package/.framework/src/components/ui/switch.tsx +49 -2
  194. package/.framework/src/components/ui/table-primitives.tsx +160 -33
  195. package/.framework/src/components/ui/table.tsx +161 -9
  196. package/.framework/src/components/ui/tabs.tsx +113 -6
  197. package/.framework/src/components/ui/textarea.tsx +49 -2
  198. package/.framework/src/components/ui/toggle-group.tsx +81 -4
  199. package/.framework/src/components/ui/toggle.tsx +65 -3
  200. package/.framework/src/components/ui/tooltip.tsx +97 -5
  201. package/.framework/src/contexts/AppContext.tsx +129 -45
  202. package/.framework/src/contexts/AuthContext.tsx +173 -145
  203. package/.framework/src/hooks/use-mobile.ts +48 -2
  204. package/.framework/src/hooks/useApi.ts +208 -159
  205. package/.framework/src/hooks/useAppPath.ts +32 -23
  206. package/.framework/src/hooks/useApps.ts +51 -20
  207. package/.framework/src/hooks/useEntityList.ts +32 -78
  208. package/.framework/src/hooks/useEntityRecord.ts +35 -96
  209. package/.framework/src/hooks/useForm.ts +32 -92
  210. package/.framework/src/hooks/useListSchema.ts +49 -78
  211. package/.framework/src/hooks/useSchemaRecord.ts +114 -105
  212. package/.framework/src/lib/api.ts +192 -115
  213. package/.framework/src/lib/supabase.ts +98 -64
  214. package/.framework/src/lib/utils.ts +287 -151
  215. package/.framework/src/main.tsx +49 -3
  216. package/.framework/src/pages/DashboardPage.tsx +52 -29
  217. package/.framework/src/pages/NotFoundPage.tsx +32 -10
  218. package/.framework/src/pages/SetupPage.tsx +32 -12
  219. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
  220. package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
  221. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
  222. package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
  223. package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
  224. package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
  225. package/.framework/src/pages/admin/AppsPage.tsx +49 -2
  226. package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
  227. package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
  228. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
  229. package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
  230. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
  231. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
  232. package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
  233. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
  234. package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
  235. package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
  236. package/.framework/src/pages/admin/LogsPage.tsx +422 -75
  237. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
  238. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
  239. package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
  240. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
  241. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
  242. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
  243. package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
  244. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
  245. package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
  246. package/.framework/src/pages/admin/RolesPage.tsx +171 -18
  247. package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
  248. package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
  249. package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
  250. package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
  251. package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
  252. package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
  253. package/.framework/src/pages/admin/TimersPage.tsx +48 -20
  254. package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
  255. package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
  256. package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
  257. package/.framework/src/pages/admin/TypesPage.tsx +48 -20
  258. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
  259. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
  260. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
  261. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
  262. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
  263. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
  264. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
  265. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
  266. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
  267. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
  268. package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
  269. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
  270. package/.framework/src/pages/auth/LoginPage.tsx +50 -23
  271. package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
  272. package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
  273. package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
  274. package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
  275. package/.framework/src/types/auth.ts +128 -71
  276. package/.framework/src/types/types.ts +373 -157
  277. package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
  278. package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
  279. package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
  280. package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
  281. package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
  282. package/docs/README.md +9 -130
  283. package/netlify.toml +3 -3
  284. package/package.json +13 -25
  285. package/scripts/kb-ingest-docs.ts +203 -0
  286. package/spine.config.json +65 -4
  287. package/.framework/migrations/001_schema.sql +0 -425
  288. package/.framework/migrations/002_rls_and_functions.sql +0 -763
  289. package/.framework/migrations/004_enhancements.sql +0 -43
  290. package/.framework/migrations/005_auth_user_trigger.sql +0 -105
  291. package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
  292. package/.framework/migrations/016_invites.sql +0 -27
  293. package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
  294. package/.framework/migrations/018_apps_required_roles.sql +0 -17
  295. package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
  296. package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
  297. package/.framework/migrations/021_app_domains.sql +0 -112
  298. package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
  299. package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
  300. package/.framework/migrations/024_messages_account_id.sql +0 -9
  301. package/.framework/migrations/025_retype_threads_messages.sql +0 -240
  302. package/.framework/migrations/026_fix_rls_policies.sql +0 -47
  303. package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
  304. package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
  305. package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
  306. package/.framework/migrations/030_messages_updated_by.sql +0 -6
  307. package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
  308. package/docs/APPS.md +0 -232
  309. package/docs/ARCHITECTURE.md +0 -246
  310. package/docs/INSTALL.md +0 -155
  311. package/docs/design-schema-spec.md +0 -1837
  312. package/docs/dev-guides/01-create-an-app.md +0 -183
  313. package/docs/dev-guides/02-create-a-function.md +0 -178
  314. package/docs/dev-guides/03-create-a-component.md +0 -178
  315. package/docs/dev-guides/04-webhook-handlers.md +0 -129
  316. package/docs/dev-guides/05-testing.md +0 -168
  317. package/docs/dev-guides/README.md +0 -40
  318. package/docs/npm-packages-plan.md +0 -288
  319. package/docs/spine-core--api-reference.md +0 -822
@@ -0,0 +1,1202 @@
1
+
2
+ const EMBED_SOURCE_STATUS: Record<'first' | 'second', { prior: string; target: string }> = {
3
+ first: { prior: '5-documented', target: '6-embedded' },
4
+ second: { prior: '8-enriched', target: '9-embedded' },
5
+ }
6
+
7
+ function getEmbedSourceFilePaths(projectItem: any, secondPass: boolean): string[] {
8
+ const fileStatuses: Record<string, string> = projectItem?.data?.file_statuses || {}
9
+ const { prior, target } = secondPass ? EMBED_SOURCE_STATUS.second : EMBED_SOURCE_STATUS.first
10
+ return Object.entries(fileStatuses)
11
+ .filter(([, status]) => status === prior || status === target)
12
+ .map(([filePath]) => filePath)
13
+ }
14
+
15
+ async function loadSourceChunks(
16
+ projectId: string,
17
+ sourceFilePaths: string[],
18
+ offset: number,
19
+ limit: number
20
+ ): Promise<{ chunks: any[]; total: number }> {
21
+ if (sourceFilePaths.length === 0) return { chunks: [], total: 0 }
22
+
23
+ // Keep the REST URL under the ~8k character limit while still using the
24
+ // indexed file_path filter instead of scanning every project chunk page.
25
+ const FILE_PATH_IN_BATCH = 50
26
+ const allIds: string[] = []
27
+ let total = 0
28
+
29
+ for (let i = 0; i < sourceFilePaths.length; i += FILE_PATH_IN_BATCH) {
30
+ const batch = sourceFilePaths.slice(i, i + FILE_PATH_IN_BATCH)
31
+ const [{ count }, { data, error }] = await Promise.all([
32
+ adminDb
33
+ .from('items')
34
+ .select('*', { count: 'exact', head: true })
35
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
36
+ .filter('data->>project_id', 'eq', projectId)
37
+ .eq('is_active', true)
38
+ .in('data->>file_path' as any, batch),
39
+ adminDb
40
+ .from('items')
41
+ .select('id, data->>file_path')
42
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
43
+ .filter('data->>project_id', 'eq', projectId)
44
+ .eq('is_active', true)
45
+ .in('data->>file_path' as any, batch)
46
+ .order('id'),
47
+ ])
48
+
49
+ if (error) throw new Error(`Failed to load source chunk ids: ${error.message}`)
50
+ total += count || 0
51
+ for (const row of data || []) allIds.push(row.id)
52
+ }
53
+
54
+ allIds.sort()
55
+ const pageIds = allIds.slice(offset, offset + limit)
56
+ if (pageIds.length === 0) return { chunks: [], total }
57
+
58
+ const { data: chunks, error } = await adminDb
59
+ .from('items')
60
+ .select('id, title, data')
61
+ .in('id', pageIds)
62
+
63
+ if (error) throw new Error(`Failed to load source chunks: ${error.message}`)
64
+
65
+ const chunkMap = new Map((chunks || []).map((c: any) => [c.id, c]))
66
+ const ordered = pageIds.map(id => chunkMap.get(id)).filter(Boolean) as any[]
67
+ return { chunks: ordered, total }
68
+ }
69
+
70
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_module_header_1784235266" type="module_header" identity="module_header" parent="none"]
71
+ // CIL[DOC-MACRO purpose="Module header and top-level exports for cortex.functions.custom_cil-embeddings"]
72
+ // CIL[DOC-RESPONSIBILITY responsibility="Own module-level imports, exports, and configuration for cortex.functions.custom_cil-embeddings"]
73
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[\".framework/migrations/015_simplify_apps_table.sql\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/components/ui/table-primitives.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"\\\"]"]
74
+ // CIL[DOC-CONTRACT inputs="none" outputs="module exports and side effects" errors="none" side_effects="none"]
75
+ // CIL[DOC-MICRO logic_summary="Declares module scope, imports dependencies, and exports public surface of cortex.functions.custom_cil-embeddings" notable_decisions="[]"]
76
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
77
+ // CIL[DOC-STABILITY stability="stable"]
78
+ // CIL[DOC-AUDIENCE audience="developer"]
79
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: .framework/migrations/015_simplify_apps_table.sql, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/components/ui/table-primitives.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, \."]
80
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
81
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
82
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
83
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
84
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
85
+
86
+
87
+
88
+
89
+ import { createHandler } from './_shared/middleware'
90
+ import { adminDb } from './_shared/db'
91
+ import { generate } from './embeddings'
92
+ import { callOpenAIEmbeddings, callEmbeddingApi } from './_shared/llm'
93
+ import { FileStatus, FileTreeNode, isSelectedPath, getFileStatus, updateTreeNodeStatus, saveProjectTree } from './_shared/cil'
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_module_header_1784235266"]
102
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_status_rank_1784235266" type="variable" identity="status_rank" parent="none"]
103
+ // CIL[DOC-MACRO purpose="Defines status_rank configuration or state in cortex.functions.custom_cil-embeddings"]
104
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for status_rank"]
105
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
106
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of status_rank" errors="none" side_effects="none"]
107
+ // CIL[DOC-MICRO logic_summary="Declares status_rank with initial value or constant binding used by cortex.functions.custom_cil-embeddings" notable_decisions="[]"]
108
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
109
+ // CIL[DOC-STABILITY stability="stable"]
110
+ // 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, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/src/pages/admin/RolesPage.tsx, \."]
111
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
112
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
113
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
114
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
115
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
116
+ const STATUS_RANK: Record<string, number> = {
117
+ '2-discovered': 2,
118
+ '3-selected': 3,
119
+ '4-chunked': 4,
120
+ '5-documented': 5,
121
+ '6-embedded': 6,
122
+ '7-mapped': 7,
123
+ '8-enriched': 8,
124
+ '9-embedded': 9,
125
+ '10-mapped': 10,
126
+
127
+ 'pass2_complete': 4,
128
+ 'pass3_complete': 5,
129
+ 'pass4_complete': 6,
130
+ 'pass4b_complete': 7,
131
+ 'pass6_complete': 8,
132
+ 'pass7_complete': 9,
133
+ 'pass8_complete': 10,
134
+ }
135
+
136
+
137
+
138
+
139
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_status_rank_1784235266"]
140
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_rank_1784235266" type="function" identity="rank" parent="none"]
141
+ // CIL[DOC-MACRO purpose="Implements rank logic in cortex.functions.custom_cil-embeddings"]
142
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute rank and return its computed result"]
143
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/migrations/015_simplify_apps_table.sql\",\"\\\"]"]
144
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
145
+ // CIL[DOC-MICRO logic_summary="Provides rank with rank(status: string | undefined inputs, handling internal flow and returning a result" notable_decisions="[]"]
146
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
147
+ // CIL[DOC-STABILITY stability="stable"]
148
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 1. Direct calls: 0. Related files: .framework/functions/_shared/principal.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/migrations/015_simplify_apps_table.sql, \."]
149
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
150
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
151
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
152
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
153
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
154
+ function rank(status: string | undefined): number {
155
+ return status ? STATUS_RANK[status] || 0 : 0
156
+ }
157
+
158
+
159
+
160
+
161
+
162
+
163
+
164
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_rank_1784235266"]
165
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_embedding_model_1784235266" type="variable" identity="embedding_model" parent="none"]
166
+ // CIL[DOC-MACRO purpose="Defines embedding_model configuration or state in cortex.functions.custom_cil-embeddings"]
167
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for embedding_model"]
168
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
169
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of embedding_model" errors="none" side_effects="none"]
170
+ // CIL[DOC-MICRO logic_summary="Declares embedding_model with initial value or constant binding used by cortex.functions.custom_cil-embeddings" notable_decisions="[]"]
171
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
172
+ // CIL[DOC-STABILITY stability="stable"]
173
+ // 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, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/src/pages/admin/RolesPage.tsx, \."]
174
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
175
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
176
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
177
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
178
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
179
+ const EMBEDDING_MODEL = 'text-embedding-3-small'
180
+
181
+
182
+
183
+
184
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_embedding_model_1784235266"]
185
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_default_batch_size_1784235266" type="variable" identity="default_batch_size" parent="none"]
186
+ // CIL[DOC-MACRO purpose="Defines default_batch_size configuration or state in cortex.functions.custom_cil-embeddings"]
187
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for default_batch_size"]
188
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
189
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of default_batch_size" errors="none" side_effects="none"]
190
+ // CIL[DOC-MICRO logic_summary="Declares default_batch_size with initial value or constant binding used by cortex.functions.custom_cil-embeddings" notable_decisions="[]"]
191
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
192
+ // CIL[DOC-STABILITY stability="stable"]
193
+ // 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, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/src/pages/admin/RolesPage.tsx, \."]
194
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
195
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
196
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
197
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
198
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
199
+ const DEFAULT_BATCH_SIZE = 20
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+
208
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_default_batch_size_1784235266"]
209
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_vector_type_index_1784235266" type="variable" identity="vector_type_index" parent="none"]
210
+ // CIL[DOC-MACRO purpose="Defines vector_type_index configuration or state in cortex.functions.custom_cil-embeddings"]
211
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for vector_type_index"]
212
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
213
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of vector_type_index" errors="none" side_effects="none"]
214
+ // CIL[DOC-MICRO logic_summary="Declares vector_type_index with initial value or constant binding used by cortex.functions.custom_cil-embeddings" notable_decisions="[]"]
215
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
216
+ // CIL[DOC-STABILITY stability="stable"]
217
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
218
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
219
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
220
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
221
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
222
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
223
+ const VECTOR_TYPE_INDEX: Record<string, number> = {
224
+ semantic: 0,
225
+ structural: 1,
226
+ contract: 2,
227
+ code: 3,
228
+ }
229
+
230
+
231
+
232
+
233
+
234
+
235
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_vector_type_index_1784235266"]
236
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_embedding_prices_1784235266" type="variable" identity="embedding_prices" parent="none"]
237
+ // CIL[DOC-MACRO purpose="Defines embedding_prices configuration or state in cortex.functions.custom_cil-embeddings"]
238
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for embedding_prices"]
239
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
240
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of embedding_prices" errors="none" side_effects="none"]
241
+ // CIL[DOC-MICRO logic_summary="Declares embedding_prices with initial value or constant binding used by cortex.functions.custom_cil-embeddings" notable_decisions="[]"]
242
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
243
+ // CIL[DOC-STABILITY stability="stable"]
244
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
245
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
246
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
247
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
248
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
249
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
250
+ const EMBEDDING_PRICES: Record<string, number> = {
251
+ 'text-embedding-3-small': 0.02,
252
+ 'text-embedding-3-large': 0.13,
253
+ 'text-embedding-ada-002': 0.10,
254
+ }
255
+
256
+
257
+
258
+
259
+
260
+
261
+
262
+
263
+
264
+
265
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_embedding_prices_1784235266"]
266
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_buildsemantictext_1784235266" type="function" identity="buildsemantictext" parent="none"]
267
+ // CIL[DOC-MACRO purpose="Implements buildsemantictext logic in cortex.functions.custom_cil-embeddings"]
268
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute buildsemantictext and return its computed result"]
269
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
270
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
271
+ // CIL[DOC-MICRO logic_summary="Provides buildsemantictext with buildSemanticText(chunk: any inputs, handling internal flow and returning a result" notable_decisions="[]"]
272
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
273
+ // CIL[DOC-STABILITY stability="stable"]
274
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
275
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
276
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
277
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
278
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
279
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
280
+ export function buildSemanticText(chunk: any): string {
281
+ const d = chunk.data || {}
282
+ const parts: string[] = []
283
+ if (d.chunk_name) parts.push(d.chunk_name)
284
+ if (d.chunk_type) parts.push(`[${d.chunk_type}]`)
285
+ if (d.file_path) parts.push(`in ${d.file_path}`)
286
+
287
+ const vc = d.vector_content || {}
288
+ if (vc.context?.status === 'ready' && vc.context.content) {
289
+ parts.push(`Context: ${vc.context.content}`)
290
+ }
291
+ if (vc.blast_radius?.status === 'ready' && vc.blast_radius.content) {
292
+ parts.push(`Blast radius: ${vc.blast_radius.content}`)
293
+ }
294
+
295
+ if (d.macro) parts.push(d.macro)
296
+ if (d.micro) parts.push(d.micro)
297
+ if (d.input_spec) parts.push(`Inputs: ${d.input_spec}`)
298
+ if (d.output_spec) parts.push(`Returns: ${d.output_spec}`)
299
+ if (Array.isArray(d.notes)) {
300
+ for (const note of d.notes) {
301
+ if (note.content) parts.push(`Note (${note.type || 'general'}): ${note.content}`)
302
+ }
303
+ }
304
+ if (Array.isArray(d.learnings)) {
305
+ for (const learning of d.learnings) {
306
+ if (learning.content) parts.push(`Learning (${learning.topic || 'general'}): ${learning.content}`)
307
+ }
308
+ }
309
+ return parts.join('. ')
310
+ }
311
+
312
+
313
+
314
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_buildsemantictext_1784235266"]
315
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_buildstructuraltext_1784235266" type="function" identity="buildstructuraltext" parent="none"]
316
+ // CIL[DOC-MACRO purpose="Implements buildstructuraltext logic in cortex.functions.custom_cil-embeddings"]
317
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute buildstructuraltext and return its computed result"]
318
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
319
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
320
+ // CIL[DOC-MICRO logic_summary="Provides buildstructuraltext with buildStructuralText(chunk: any inputs, handling internal flow and returning a result" notable_decisions="[]"]
321
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
322
+ // CIL[DOC-STABILITY stability="stable"]
323
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
324
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
325
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
326
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
327
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
328
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
329
+ export function buildStructuralText(chunk: any): string {
330
+ const d = chunk.data || {}
331
+ return JSON.stringify({
332
+ chunk_name: d.chunk_name || '',
333
+ chunk_type: d.chunk_type || '',
334
+ file_path: d.file_path || '',
335
+ stability: d.stability || '',
336
+ is_dead_code: d.is_dead_code || false,
337
+ boundary_confidence: d.boundary_confidence || '',
338
+ doc_confidence: d.doc_confidence || '',
339
+ review_status: d.review_status || '',
340
+ })
341
+ }
342
+
343
+
344
+
345
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_buildstructuraltext_1784235266"]
346
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_buildcontracttext_1784235266" type="function" identity="buildcontracttext" parent="none"]
347
+ // CIL[DOC-MACRO purpose="Implements buildcontracttext logic in cortex.functions.custom_cil-embeddings"]
348
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute buildcontracttext and return its computed result"]
349
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
350
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
351
+ // CIL[DOC-MICRO logic_summary="Provides buildcontracttext with buildContractText(chunk: any inputs, handling internal flow and returning a result" notable_decisions="[]"]
352
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
353
+ // CIL[DOC-STABILITY stability="stable"]
354
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
355
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
356
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
357
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
358
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
359
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
360
+ export function buildContractText(chunk: any): string {
361
+ const d = chunk.data || {}
362
+ const parts: string[] = []
363
+ if (d.input_spec) parts.push(`INPUTS: ${d.input_spec}`)
364
+ if (d.output_spec) parts.push(`OUTPUTS: ${d.output_spec}`)
365
+ if (d.side_effects) parts.push(`SIDE_EFFECTS: ${d.side_effects}`)
366
+ if (d.macro) parts.push(`PURPOSE: ${d.macro}`)
367
+ return parts.join('\n') || `${d.chunk_name || 'unknown'} — no contract yet`
368
+ }
369
+
370
+
371
+
372
+
373
+ function buildCodeText(chunk: any): string {
374
+ const d = chunk.data || {}
375
+ const parts: string[] = []
376
+ if (d.chunk_name) parts.push(d.chunk_name)
377
+ if (d.file_path) parts.push(`in ${d.file_path}`)
378
+ if (d.chunk_type) parts.push(`[${d.chunk_type}]`)
379
+ if (d.macro) parts.push(d.macro)
380
+ if (d.micro) parts.push(d.micro)
381
+ if (d.code_content) {
382
+ parts.push('CODE:')
383
+ parts.push(String(d.code_content))
384
+ }
385
+ return parts.join('\n') || `${d.chunk_name || 'unknown'} — no code content`
386
+ }
387
+
388
+
389
+
390
+
391
+
392
+
393
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_buildcontracttext_1784235266"]
394
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_loadpendingchunks_1784235266" type="function" identity="loadpendingchunks" parent="none"]
395
+ // CIL[DOC-MACRO purpose="Implements loadpendingchunks logic in cortex.functions.custom_cil-embeddings"]
396
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute loadpendingchunks and return its computed result"]
397
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
398
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
399
+ // CIL[DOC-MICRO logic_summary="Provides loadpendingchunks with loadPendingChunks(projectId: string, selectedPaths: string[], requiredStatus: FileStatus inputs, handling internal flow and returning a result" notable_decisions="[]"]
400
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
401
+ // CIL[DOC-STABILITY stability="stable"]
402
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
403
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
404
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
405
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
406
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
407
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
408
+ async function loadPendingChunks(projectId: string, selectedPaths: string[], requiredStatus: FileStatus): Promise<any[]> {
409
+ const { data: fileItems } = await adminDb
410
+ .from('items')
411
+ .select('id, data')
412
+ .filter('data->>kb_type', 'eq', 'cil_file')
413
+ .filter('data->>project_id', 'eq', projectId)
414
+ .eq('is_active', true)
415
+
416
+ const selectedFileIds = (fileItems || [])
417
+ .filter((f: any) => getFileStatus(f) === requiredStatus && isSelectedPath(f.data?.file_path || f.title, selectedPaths))
418
+ .map((f: any) => f.id)
419
+
420
+ if (selectedFileIds.length === 0) return []
421
+
422
+ const { data: allChunks } = await adminDb
423
+ .from('items')
424
+ .select('id, title, data')
425
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
426
+ .filter('data->>project_id', 'eq', projectId)
427
+ .eq('is_active', true)
428
+
429
+ return (allChunks || []).filter((c: any) => selectedFileIds.includes(c.data?.file_id))
430
+ }
431
+
432
+
433
+
434
+
435
+
436
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_loadpendingchunks_1784235266"]
437
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_maybeadvancefiletopass4_1784235266" type="function" identity="maybeadvancefiletopass4" parent="none"]
438
+ // CIL[DOC-MACRO purpose="Implements maybeadvancefiletopass4 logic in cortex.functions.custom_cil-embeddings"]
439
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute maybeadvancefiletopass4 and return its computed result"]
440
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
441
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
442
+ // CIL[DOC-MICRO logic_summary="Provides maybeadvancefiletopass4 with maybeAdvanceFileToPass4( inputs, handling internal flow and returning a result" notable_decisions="[]"]
443
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
444
+ // CIL[DOC-STABILITY stability="stable"]
445
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
446
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
447
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
448
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
449
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
450
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
451
+ async function maybeAdvanceFileToPass4(
452
+ ctx: any,
453
+ fileId: string,
454
+ tree: FileTreeNode | null,
455
+ secondPass = false,
456
+ projectItem?: any
457
+ ): Promise<void> {
458
+ const { data: fileChunks } = await adminDb
459
+ .from('items')
460
+ .select('id, title, data')
461
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
462
+ .filter('data->>file_id', 'eq', fileId)
463
+ .eq('is_active', true)
464
+
465
+ if (!fileChunks || fileChunks.length === 0) return
466
+
467
+ const chunkIds = fileChunks.map((c: any) => c.id)
468
+ const { data: embeddedDocs } = await adminDb
469
+ .from('embeddings')
470
+ .select('document_id')
471
+ .in('document_id', chunkIds)
472
+ .is('revoked_at', null)
473
+
474
+ const embeddedChunkIds = new Set((embeddedDocs || []).map((e: any) => e.document_id))
475
+ const allEmbedded = chunkIds.every(id => embeddedChunkIds.has(id))
476
+ if (!allEmbedded) return
477
+
478
+ const { data: fileItem } = await adminDb
479
+ .from('items')
480
+ .select('id, data')
481
+ .eq('id', fileId)
482
+ .maybeSingle()
483
+
484
+ if (!fileItem) return
485
+
486
+ const cil_file_status = secondPass ? 'pass7_complete' : 'pass4_complete'
487
+ const pipeline_status = secondPass ? '9-embedded' : '6-embedded'
488
+ const currentFileStatus = getFileStatus(fileItem)
489
+ const filePath: string = fileItem.data?.file_path
490
+
491
+
492
+ if (rank(currentFileStatus) < rank(cil_file_status)) {
493
+ const { update } = await import('./admin-data')
494
+ const updateCtx = { ...ctx, query: { ...(ctx.query || {}), entity: 'items', id: fileId } }
495
+ await update(updateCtx, {
496
+ data: {
497
+ ...fileItem.data,
498
+ status: cil_file_status,
499
+ last_status_at: new Date().toISOString(),
500
+ },
501
+ }).catch((e: any) => console.error(`advance to ${cil_file_status} failed:`, e.message))
502
+ }
503
+
504
+ if (tree) updateTreeNodeStatus(tree, fileId, cil_file_status)
505
+
506
+
507
+ const projectId: string = fileItem.data?.project_id
508
+ if (!filePath || !projectId) return
509
+
510
+ let projItem = projectItem
511
+ if (!projItem) {
512
+ const { data } = await adminDb.from('items').select('id, data').eq('id', projectId).maybeSingle()
513
+ projItem = data
514
+ }
515
+ if (!projItem) return
516
+
517
+ const currentPipelineStatus = projItem.data?.file_statuses?.[filePath]
518
+ if (rank(currentPipelineStatus) >= rank(pipeline_status)) return
519
+
520
+ const fileStatuses = { ...(projItem.data?.file_statuses || {}) }
521
+ fileStatuses[filePath] = pipeline_status
522
+ fileStatuses[`${filePath}_updated`] = new Date().toISOString()
523
+ const { error: fsErr } = await adminDb.from('items')
524
+ .update({ data: { ...projItem.data, file_statuses: fileStatuses } })
525
+ .eq('id', projectId)
526
+ .select('id')
527
+ if (fsErr) {
528
+ console.error(`pipeline status advance to ${pipeline_status} failed:`, fsErr.message)
529
+ return
530
+ }
531
+
532
+
533
+ if (projectItem) {
534
+ if (!projectItem.data) projectItem.data = {}
535
+ projectItem.data.file_statuses = fileStatuses
536
+ }
537
+ }
538
+
539
+
540
+
541
+
542
+
543
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_maybeadvancefiletopass4_1784235266"]
544
+
545
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_contenthash_1784235266" type="function" identity="contenthash" parent="none"]
546
+ // CIL[DOC-MACRO purpose="Implements contenthash logic in cortex.functions.custom_cil-embeddings"]
547
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute contenthash and return its computed result"]
548
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
549
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
550
+ // CIL[DOC-MICRO logic_summary="Provides contenthash with contentHash(text: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
551
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
552
+ // CIL[DOC-STABILITY stability="stable"]
553
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
554
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
555
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
556
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
557
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
558
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
559
+ export function contentHash(text: string): string {
560
+
561
+ let h = 2166136261
562
+ for (let i = 0; i < text.length; i++) {
563
+ h ^= text.charCodeAt(i)
564
+ h = Math.imul(h, 16777619)
565
+ }
566
+ return (h >>> 0).toString(16).padStart(8, '0')
567
+ }
568
+
569
+
570
+
571
+
572
+
573
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_contenthash_1784235266"]
574
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_embedchunk_1784235266" type="function" identity="embedchunk" parent="none"]
575
+ // CIL[DOC-MACRO purpose="Implements embedchunk logic in cortex.functions.custom_cil-embeddings"]
576
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute embedchunk and return its computed result"]
577
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
578
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
579
+ // CIL[DOC-MICRO logic_summary="Provides embedchunk with embedChunk( inputs, handling internal flow and returning a result" notable_decisions="[]"]
580
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
581
+ // CIL[DOC-STABILITY stability="stable"]
582
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
583
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
584
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
585
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
586
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
587
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
588
+ export async function embedChunk(
589
+ chunkItem: any,
590
+ accountId: string,
591
+ forceRegenerate: boolean
592
+ ): Promise<{ created: string[]; skipped: string[]; error?: string }> {
593
+ const chunkId = chunkItem.id
594
+ const created: string[] = []
595
+ const skipped: string[] = []
596
+
597
+
598
+ const vectors: { type: string; text: string }[] = [
599
+ { type: 'semantic', text: buildSemanticText(chunkItem) },
600
+ { type: 'structural', text: buildStructuralText(chunkItem) },
601
+ { type: 'contract', text: buildContractText(chunkItem) },
602
+ { type: 'code', text: buildCodeText(chunkItem) },
603
+ ].filter(v => v.text.trim().length > 0)
604
+
605
+ if (!vectors.length) return { created, skipped: ['all:empty'] }
606
+
607
+
608
+ const { data: existing } = await adminDb
609
+ .from('embeddings')
610
+ .select('id, content_hash, metadata')
611
+ .eq('document_id', chunkId)
612
+
613
+ const existingMap = new Map<string, any>()
614
+ for (const row of existing || []) {
615
+ existingMap.set(row.metadata?.vector_type || '', row)
616
+ }
617
+
618
+ if (forceRegenerate && (existing || []).length > 0) {
619
+ await adminDb.from('embeddings').delete().eq('document_id', chunkId)
620
+ existingMap.clear()
621
+ }
622
+
623
+
624
+ const toEmbed = vectors.filter(v => {
625
+ const hash = contentHash(v.text)
626
+ const row = existingMap.get(v.type)
627
+ if (row && row.content_hash === hash) { skipped.push(v.type); return false }
628
+ return true
629
+ })
630
+
631
+ if (!toEmbed.length) return { created, skipped }
632
+
633
+ try {
634
+ const embeddings = await callEmbeddingApi(toEmbed.map(v => v.text))
635
+ const now = new Date().toISOString()
636
+
637
+ for (let i = 0; i < toEmbed.length; i++) {
638
+ const { type, text } = toEmbed[i]
639
+ const hash = contentHash(text)
640
+ const existingRow = existingMap.get(type)
641
+
642
+
643
+ const vectorLiteral = `[${embeddings[i].join(',')}]`
644
+
645
+ const row = {
646
+ account_id: accountId,
647
+ model_id: EMBEDDING_MODEL,
648
+ document_id: chunkId,
649
+ chunk_index: VECTOR_TYPE_INDEX[type] ?? 0,
650
+ content: text,
651
+ embedding: vectorLiteral,
652
+ content_hash: hash,
653
+ approved_at: now, // CIL chunks are always "approved" — they're internal, not published content
654
+ revoked_at: null,
655
+ metadata: {
656
+ vector_type: type,
657
+ item_type: 'cil_chunk',
658
+ kb_type: 'cil_chunk',
659
+ security_level: 'internal',
660
+ source_item_id: chunkId,
661
+ chunk_name: chunkItem.data?.chunk_name || '',
662
+ file_path: chunkItem.data?.file_path || '',
663
+ project_id: chunkItem.data?.project_id || '',
664
+ },
665
+ }
666
+
667
+ if (existingRow) {
668
+ await adminDb.from('embeddings').update(row).eq('id', existingRow.id)
669
+ } else {
670
+ await adminDb.from('embeddings').insert(row)
671
+ }
672
+ created.push(type)
673
+ }
674
+ } catch (err) {
675
+ return { created, skipped, error: err instanceof Error ? err.message : String(err) }
676
+ }
677
+
678
+ return { created, skipped }
679
+ }
680
+
681
+
682
+
683
+
684
+
685
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_embedchunk_1784235266"]
686
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_semanticsearch_1784235266" type="function" identity="semanticsearch" parent="none"]
687
+ // CIL[DOC-MACRO purpose="Implements semanticsearch logic in cortex.functions.custom_cil-embeddings"]
688
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute semanticsearch and return its computed result"]
689
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
690
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
691
+ // CIL[DOC-MICRO logic_summary="Provides semanticsearch with semanticSearch( inputs, handling internal flow and returning a result" notable_decisions="[]"]
692
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
693
+ // CIL[DOC-STABILITY stability="stable"]
694
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
695
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
696
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
697
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
698
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
699
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
700
+ async function semanticSearch(
701
+ query: string,
702
+ projectId: string | null,
703
+ limit: number,
704
+ accountId: string
705
+ ): Promise<any[]> {
706
+ const j = await callOpenAIEmbeddings(undefined, [query], EMBEDDING_MODEL)
707
+ const queryVector = j.data?.[0]?.embedding
708
+ if (!queryVector) throw new Error('Failed to embed query')
709
+
710
+ const vectorLiteral = `[${queryVector.join(',')}]`
711
+
712
+
713
+ const rpcParams: any = {
714
+ query_embedding: vectorLiteral,
715
+ match_count: limit * 3,
716
+ filter_account_ids: [accountId],
717
+ filter_vector_type: null,
718
+ similarity_threshold: 0.15,
719
+ filter_item_types: ['cil_chunk'],
720
+ }
721
+
722
+ const { data: matches, error } = await adminDb.rpc('match_embeddings', rpcParams)
723
+ if (error) throw new Error(`match_embeddings RPC error: ${error.message}`)
724
+
725
+
726
+ const chunkIds = [...new Set((matches || []).map((m: any) => m.document_id))]
727
+ if (!chunkIds.length) return []
728
+
729
+ const { data: chunks } = await adminDb
730
+ .from('items')
731
+ .select('id, title, data')
732
+ .in('id', chunkIds)
733
+
734
+ const chunkMap = new Map((chunks || []).map((c: any) => [c.id, c]))
735
+
736
+ return (matches || [])
737
+ .filter((m: any) => {
738
+ const chunk = chunkMap.get(m.document_id)
739
+ if (!chunk || chunk.data?.kb_type !== 'cil_chunk') return false
740
+ if (!projectId) return true
741
+ return chunk.data?.project_id === projectId
742
+ })
743
+ .map((m: any) => {
744
+ const chunk = chunkMap.get(m.document_id)
745
+ return {
746
+ chunk_id: m.document_id,
747
+ chunk_name: chunk?.data?.chunk_name || chunk?.title || '',
748
+ file_path: chunk?.data?.file_path || '',
749
+ macro: chunk?.data?.macro || '',
750
+ micro: chunk?.data?.micro || '',
751
+ chunk_type: chunk?.data?.chunk_type || '',
752
+ doc_confidence: chunk?.data?.doc_confidence || '',
753
+ similarity: m.similarity,
754
+ content_snippet: (m.content || '').slice(0, 200),
755
+ vector_content: chunk?.data?.vector_content || null,
756
+ }
757
+ })
758
+ .slice(0, limit)
759
+ }
760
+
761
+
762
+
763
+
764
+
765
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_semanticsearch_1784235266"]
766
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_getplatformaccountid_1784235266" type="function" identity="getplatformaccountid" parent="none"]
767
+ // CIL[DOC-MACRO purpose="Implements getplatformaccountid logic in cortex.functions.custom_cil-embeddings"]
768
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute getplatformaccountid and return its computed result"]
769
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
770
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
771
+ // CIL[DOC-MICRO logic_summary="Provides getplatformaccountid with getPlatformAccountId( inputs, handling internal flow and returning a result" notable_decisions="[]"]
772
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
773
+ // CIL[DOC-STABILITY stability="stable"]
774
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
775
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
776
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
777
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
778
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
779
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
780
+ async function getPlatformAccountId(): Promise<string> {
781
+ const { data } = await adminDb.from('accounts').select('id').eq('slug', 'spine-system').maybeSingle()
782
+ return data?.id || ''
783
+ }
784
+
785
+
786
+
787
+
788
+
789
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_getplatformaccountid_1784235266"]
790
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_handler_1784235266" type="variable" identity="handler" parent="none"]
791
+ // CIL[DOC-MACRO purpose="Defines handler configuration or state in cortex.functions.custom_cil-embeddings"]
792
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for handler"]
793
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-embeddings" layer="function" related_files="[]"]
794
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of handler" errors="none" side_effects="none"]
795
+ // CIL[DOC-MICRO logic_summary="Declares handler with initial value or constant binding used by cortex.functions.custom_cil-embeddings" notable_decisions="[]"]
796
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
797
+ // CIL[DOC-STABILITY stability="stable"]
798
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
799
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
800
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
801
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
802
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
803
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
804
+ export const handler = createHandler(async (ctx, body) => {
805
+ const action = ctx.query?.action
806
+ const accountId = ctx.accountId || await getPlatformAccountId()
807
+
808
+
809
+ if (action === 'estimate') {
810
+ const projectId = body?.project_id || ctx.query?.project_id
811
+ if (!projectId) throw new Error('project_id is required')
812
+ const model = body?.model || ctx.query?.model || EMBEDDING_MODEL
813
+ const pricePerMillion = EMBEDDING_PRICES[model] ?? EMBEDDING_PRICES[EMBEDDING_MODEL]
814
+ const filePath = body?.file_path || ctx.query?.file_path
815
+
816
+
817
+ const PAGE_SIZE = 1000
818
+ let offset = 0
819
+ const chunks: any[] = []
820
+ while (true) {
821
+ let q = adminDb
822
+ .from('items')
823
+ .select('id, data')
824
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
825
+ .filter('data->>project_id', 'eq', projectId)
826
+ .filter('data->>review_status', 'eq', 'approved')
827
+ .eq('is_active', true)
828
+ .range(offset, offset + PAGE_SIZE - 1)
829
+ if (filePath) q = q.filter('data->>file_path', 'eq', filePath)
830
+ const { data: page, error } = await q
831
+ if (error) throw new Error(`Failed to load chunks: ${error.message}`)
832
+ chunks.push(...(page || []))
833
+ if ((page || []).length < PAGE_SIZE) break
834
+ offset += PAGE_SIZE
835
+ }
836
+
837
+
838
+ const chunkIds = (chunks || []).map((c: any) => c.id)
839
+ const existingDocIds = new Set<string>()
840
+ const SUPABASE_IN_LIMIT = 500
841
+ for (let i = 0; i < chunkIds.length; i += SUPABASE_IN_LIMIT) {
842
+ const { data: emb } = await adminDb
843
+ .from('embeddings')
844
+ .select('document_id')
845
+ .in('document_id', chunkIds.slice(i, i + SUPABASE_IN_LIMIT))
846
+ for (const row of emb || []) existingDocIds.add(row.document_id)
847
+ }
848
+
849
+ const toEmbed = (chunks || []).filter((c: any) => !existingDocIds.has(c.id))
850
+ const alreadyEmbedded = (chunks || []).length - toEmbed.length
851
+
852
+
853
+
854
+ let totalTokens = 0
855
+ for (const chunk of toEmbed) {
856
+ const baseTokens = chunk.data?.token_count || Math.ceil((chunk.data?.code_content?.length || 200) / 4)
857
+ totalTokens += baseTokens * 4
858
+ }
859
+
860
+ const estimatedCostUsd = (totalTokens / 1_000_000) * pricePerMillion
861
+
862
+ return {
863
+ project_id: projectId,
864
+ model,
865
+ file_path: filePath || null,
866
+ price_per_1m_tokens: pricePerMillion,
867
+ total_approved_chunks: (chunks || []).length,
868
+ chunks_to_embed: toEmbed.length,
869
+ already_embedded: alreadyEmbedded,
870
+ vectors_per_chunk: 4,
871
+ estimated_tokens: totalTokens,
872
+ estimated_cost_usd: parseFloat(estimatedCostUsd.toFixed(4)),
873
+ }
874
+ }
875
+
876
+
877
+ if (action === 'embed_chunk') {
878
+ const chunkId = body?.chunk_id || ctx.query?.chunk_id
879
+ if (!chunkId) throw new Error('chunk_id is required')
880
+
881
+ const { data: chunk, error } = await adminDb
882
+ .from('items')
883
+ .select('id, title, data')
884
+ .eq('id', chunkId)
885
+ .maybeSingle()
886
+
887
+ if (error || !chunk) throw new Error(`Chunk not found: ${chunkId}`)
888
+
889
+ const result = await embedChunk(chunk, accountId, body?.force_regenerate ?? false)
890
+ return {
891
+ chunk_id: chunkId,
892
+ chunk_name: chunk.data?.chunk_name || '',
893
+ ...result,
894
+ }
895
+ }
896
+
897
+
898
+
899
+
900
+
901
+
902
+
903
+
904
+
905
+
906
+
907
+ if (action === 'embed_project' || action === 'embed_approved') {
908
+ const projectId = body?.project_id || ctx.query?.project_id
909
+ if (!projectId) throw new Error('project_id is required')
910
+
911
+ const forceRegenerate = body?.force_regenerate ?? false
912
+ const secondPass = body?.second_pass ?? false
913
+ const filePath = body?.file_path || ctx.query?.file_path
914
+ const pageLimit = Math.min(parseInt(body?.limit || '10', 10), 25)
915
+ const pageOffset = parseInt(body?.offset || '0', 10)
916
+
917
+
918
+ const { data: projectItem } = await adminDb.from('items').select('id, data').eq('id', projectId).maybeSingle()
919
+
920
+ const selectedPaths: string[] = projectItem?.data?.selected_paths || []
921
+ const fileTree = (projectItem?.data?.file_tree as FileTreeNode) || null
922
+
923
+
924
+ let totalChunks = 0
925
+ let pageChunks: any[] = []
926
+ let error: any = null
927
+
928
+ if (action === 'embed_approved' && selectedPaths.length > 0 && !filePath) {
929
+
930
+ const pending = await loadPendingChunks(projectId, selectedPaths, 'pass3_complete')
931
+ const sorted = pending.sort((a: any, b: any) => a.id.localeCompare(b.id))
932
+ totalChunks = sorted.length
933
+ pageChunks = sorted.slice(pageOffset, pageOffset + pageLimit)
934
+ } else {
935
+ const sourceFilePaths = filePath ? [filePath] : getEmbedSourceFilePaths(projectItem, secondPass)
936
+ const sourceChunks = await loadSourceChunks(projectId, sourceFilePaths, pageOffset, pageLimit)
937
+ totalChunks = sourceChunks.total
938
+ pageChunks = sourceChunks.chunks
939
+ error = null
940
+ }
941
+
942
+ if (error) throw new Error(`Failed to load chunks: ${error.message}`)
943
+ if (error) throw new Error(`Failed to load chunks: ${error.message}`)
944
+ if (!pageChunks || pageChunks.length === 0) {
945
+ return { project_id: projectId, total: totalChunks, embeddings_created: 0, embeddings_skipped: 0, errors: [], has_more: false, next_offset: null, done_total: totalChunks }
946
+ }
947
+
948
+
949
+ const pageChunkIds = pageChunks.map((c: any) => c.id)
950
+ const SUPABASE_IN_LIMIT = 500
951
+ const existingRows: any[] = []
952
+ for (let i = 0; i < pageChunkIds.length; i += SUPABASE_IN_LIMIT) {
953
+ const { data } = await adminDb
954
+ .from('embeddings')
955
+ .select('id, document_id, content_hash, metadata')
956
+ .in('document_id', pageChunkIds.slice(i, i + SUPABASE_IN_LIMIT))
957
+ existingRows.push(...(data || []))
958
+ }
959
+
960
+ const existingMap = new Map<string, Map<string, any>>()
961
+ for (const row of existingRows) {
962
+ const docId = row.document_id
963
+ if (!existingMap.has(docId)) existingMap.set(docId, new Map())
964
+ existingMap.get(docId)!.set(row.metadata?.vector_type || '', row)
965
+ }
966
+
967
+
968
+ const toEmbed: { chunkId: string; type: string; text: string; existingRowId?: string }[] = []
969
+ let totalSkipped = 0
970
+
971
+ for (const chunk of pageChunks) {
972
+ const vectors = [
973
+ { type: 'semantic', text: buildSemanticText(chunk) },
974
+ { type: 'structural', text: buildStructuralText(chunk) },
975
+ { type: 'contract', text: buildContractText(chunk) },
976
+ { type: 'code', text: buildCodeText(chunk) },
977
+ ].filter(v => v.text.trim().length > 0)
978
+
979
+ for (const v of vectors) {
980
+ const hash = contentHash(v.text)
981
+ const existing = existingMap.get(chunk.id)?.get(v.type)
982
+ if (!forceRegenerate && existing && existing.content_hash === hash) {
983
+ totalSkipped++
984
+ continue
985
+ }
986
+ toEmbed.push({ chunkId: chunk.id, type: v.type, text: v.text, existingRowId: existing?.id })
987
+ }
988
+ }
989
+
990
+
991
+
992
+
993
+ const targetPipelineStatus = secondPass ? '9-embedded' : '6-embedded'
994
+
995
+ const advanceFiles = async () => {
996
+ const affectedFileIds = [...new Set(pageChunks.map(c => c.data?.file_id).filter(Boolean))]
997
+ for (const fileId of affectedFileIds) {
998
+ const chunk = pageChunks.find((c: any) => c.data?.file_id === fileId)
999
+ const filePath = chunk?.data?.file_path
1000
+ const fileStatus = projectItem?.data?.file_statuses?.[filePath]
1001
+ if (fileStatus === targetPipelineStatus) continue
1002
+ await maybeAdvanceFileToPass4(ctx, fileId, fileTree, secondPass, projectItem)
1003
+ }
1004
+ if (fileTree) {
1005
+ await saveProjectTree(ctx, projectId, fileTree, { last_ingested_at: new Date().toISOString() }, projectItem)
1006
+ }
1007
+ }
1008
+
1009
+ if (toEmbed.length === 0) {
1010
+ await advanceFiles()
1011
+ const nextOffset = pageOffset + pageLimit
1012
+ return {
1013
+ project_id: projectId, total: totalChunks,
1014
+ embeddings_created: 0, embeddings_skipped: totalSkipped, errors: [],
1015
+ has_more: nextOffset < totalChunks, next_offset: nextOffset < totalChunks ? nextOffset : null,
1016
+ done_total: pageOffset + pageChunks.length,
1017
+ }
1018
+ }
1019
+
1020
+
1021
+ if (forceRegenerate && pageChunkIds.length > 0) {
1022
+ for (let i = 0; i < pageChunkIds.length; i += SUPABASE_IN_LIMIT) {
1023
+ await adminDb.from('embeddings').delete().in('document_id', pageChunkIds.slice(i, i + SUPABASE_IN_LIMIT))
1024
+ }
1025
+ for (const item of toEmbed) { item.existingRowId = undefined }
1026
+ }
1027
+
1028
+
1029
+ const OPENAI_BATCH = 100
1030
+ const errors: string[] = []
1031
+
1032
+
1033
+ const batchPromises: Promise<{ startIdx: number; vecs: number[][] }>[] = []
1034
+ for (let i = 0; i < toEmbed.length; i += OPENAI_BATCH) {
1035
+ const startIdx = i
1036
+ const batchTexts = toEmbed.slice(i, i + OPENAI_BATCH).map(e => e.text)
1037
+ batchPromises.push(
1038
+ callEmbeddingApi(batchTexts)
1039
+ .then(vecs => ({ startIdx, vecs }))
1040
+ .catch(err => {
1041
+ errors.push(`OpenAI batch ${startIdx}-${startIdx + OPENAI_BATCH}: ${err instanceof Error ? err.message : String(err)}`)
1042
+ return { startIdx, vecs: batchTexts.map(() => []) }
1043
+ })
1044
+ )
1045
+ }
1046
+ const batchResults = await Promise.all(batchPromises)
1047
+
1048
+
1049
+ const allVectors: number[][] = new Array(toEmbed.length)
1050
+ for (const { startIdx, vecs } of batchResults) {
1051
+ for (let k = 0; k < vecs.length; k++) allVectors[startIdx + k] = vecs[k]
1052
+ }
1053
+
1054
+
1055
+ const now = new Date().toISOString()
1056
+ const chunkMap = new Map(pageChunks.map((c: any) => [c.id, c]))
1057
+
1058
+ const rowsToInsert: object[] = []
1059
+ const rowsToUpdate: { id: string; row: object }[] = []
1060
+
1061
+ for (let i = 0; i < toEmbed.length; i++) {
1062
+ const { chunkId, type, text, existingRowId } = toEmbed[i]
1063
+ const vec = allVectors[i]
1064
+ if (!vec || vec.length === 0) continue
1065
+
1066
+ const chunk = chunkMap.get(chunkId)
1067
+ const row = {
1068
+ account_id: accountId,
1069
+ model_id: EMBEDDING_MODEL,
1070
+ document_id: chunkId,
1071
+ chunk_index: VECTOR_TYPE_INDEX[type] ?? 0,
1072
+ content: text,
1073
+ embedding: `[${vec.join(',')}]`,
1074
+ content_hash: contentHash(text),
1075
+ approved_at: now,
1076
+ revoked_at: null,
1077
+ metadata: {
1078
+ vector_type: type,
1079
+ item_type: 'cil_chunk',
1080
+ kb_type: 'cil_chunk',
1081
+ security_level: 'internal',
1082
+ source_item_id: chunkId,
1083
+ chunk_name: chunk?.data?.chunk_name || '',
1084
+ file_path: chunk?.data?.file_path || '',
1085
+ project_id: projectId,
1086
+ },
1087
+ }
1088
+
1089
+ if (existingRowId) rowsToUpdate.push({ id: existingRowId, row })
1090
+ else rowsToInsert.push(row)
1091
+ }
1092
+
1093
+
1094
+ const INSERT_BATCH = 10
1095
+ for (let i = 0; i < rowsToInsert.length; i += INSERT_BATCH) {
1096
+ const { error: e } = await adminDb.from('embeddings').insert(rowsToInsert.slice(i, i + INSERT_BATCH))
1097
+ if (e) errors.push(`embedding insert batch failed: ${e.message}`)
1098
+ }
1099
+
1100
+
1101
+ const PARALLEL_UPDATE = 5
1102
+ const updatePromises: Promise<void>[] = []
1103
+ for (let i = 0; i < rowsToUpdate.length; i += PARALLEL_UPDATE) {
1104
+ for (const { id, row } of rowsToUpdate.slice(i, i + PARALLEL_UPDATE)) {
1105
+ updatePromises.push(
1106
+ adminDb.from('embeddings').update(row).eq('id', id)
1107
+ .then(({ error: e }) => { if (e) errors.push(`embedding update ${id}: ${e.message}`) })
1108
+ )
1109
+ }
1110
+ }
1111
+
1112
+ await Promise.all(updatePromises)
1113
+
1114
+ await advanceFiles()
1115
+
1116
+ const nextOffset = pageOffset + pageLimit
1117
+ return {
1118
+ project_id: projectId,
1119
+ file_path: filePath || null,
1120
+ total: totalChunks,
1121
+ embeddings_created: rowsToInsert.length + rowsToUpdate.length,
1122
+ embeddings_skipped: totalSkipped,
1123
+ errors,
1124
+ has_more: nextOffset < totalChunks,
1125
+ next_offset: nextOffset < totalChunks ? nextOffset : null,
1126
+ done_total: pageOffset + pageChunks.length,
1127
+ }
1128
+ }
1129
+
1130
+
1131
+ if (action === 'status') {
1132
+ const projectId = body?.project_id || ctx.query?.project_id
1133
+ if (!projectId) throw new Error('project_id is required')
1134
+
1135
+ const { count: totalChunks } = await adminDb
1136
+ .from('items')
1137
+ .select('id', { count: 'exact' })
1138
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
1139
+ .filter('data->>project_id', 'eq', projectId)
1140
+ .eq('is_active', true)
1141
+
1142
+
1143
+ const { data: chunkItems } = await adminDb
1144
+ .from('items')
1145
+ .select('id')
1146
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
1147
+ .filter('data->>project_id', 'eq', projectId)
1148
+ .eq('is_active', true)
1149
+
1150
+ const chunkIds = (chunkItems || []).map((c: any) => c.id)
1151
+ let embeddedCount = 0
1152
+
1153
+ if (chunkIds.length > 0) {
1154
+ const { data: embeddedDocs } = await adminDb
1155
+ .from('embeddings')
1156
+ .select('document_id')
1157
+ .in('document_id', chunkIds)
1158
+ .is('revoked_at', null)
1159
+
1160
+ embeddedCount = new Set((embeddedDocs || []).map((e: any) => e.document_id)).size
1161
+ }
1162
+
1163
+ return {
1164
+ project_id: projectId,
1165
+ total_chunks: totalChunks || 0,
1166
+ embedded_chunks: embeddedCount,
1167
+ unembedded_chunks: (totalChunks || 0) - embeddedCount,
1168
+ coverage_pct: totalChunks ? Math.round((embeddedCount / totalChunks) * 100) : 0,
1169
+ }
1170
+ }
1171
+
1172
+
1173
+ if (action === 'search') {
1174
+ const query = body?.q || ctx.query?.q
1175
+ const projectId = body?.project_id || ctx.query?.project_id || null
1176
+ const limit = parseInt(body?.limit || ctx.query?.limit || '10')
1177
+ if (!query) throw new Error('q is required')
1178
+
1179
+ const results = await semanticSearch(query, projectId, limit, accountId)
1180
+ return { query, results, count: results.length }
1181
+ }
1182
+
1183
+
1184
+ if (action === 'delete') {
1185
+ const chunkId = body?.chunk_id || ctx.query?.chunk_id
1186
+ if (!chunkId) throw new Error('chunk_id is required')
1187
+
1188
+ const { error } = await adminDb
1189
+ .from('embeddings')
1190
+ .delete()
1191
+ .eq('document_id', chunkId)
1192
+
1193
+ if (error) throw new Error(`Failed to delete embeddings: ${error.message}`)
1194
+ return { chunk_id: chunkId, deleted: true }
1195
+ }
1196
+
1197
+ throw new Error(`Unknown action: ${action}. Valid: embed_chunk, embed_project, embed_approved, status, search, delete`)
1198
+ })
1199
+
1200
+
1201
+
1202
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_embeddings_handler_1784235266"]