spine-framework 0.3.124 → 0.3.126

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/.framework/cli/commands/agents.ts +35 -37
  2. package/.framework/cli/commands/auth.ts +35 -34
  3. package/.framework/cli/commands/create-app.ts +104 -40
  4. package/.framework/cli/commands/dev.ts +104 -69
  5. package/.framework/cli/commands/doctor.ts +179 -69
  6. package/.framework/cli/commands/generate.ts +83 -143
  7. package/.framework/cli/commands/init.ts +72 -34
  8. package/.framework/cli/commands/install-app.ts +260 -125
  9. package/.framework/cli/commands/items.ts +33 -44
  10. package/.framework/cli/commands/migrate.ts +122 -40
  11. package/.framework/cli/commands/migrations.ts +33 -40
  12. package/.framework/cli/commands/pipelines.ts +31 -39
  13. package/.framework/cli/commands/status.ts +47 -23
  14. package/.framework/cli/commands/system.ts +47 -37
  15. package/.framework/cli/commands/test.ts +112 -68
  16. package/.framework/cli/commands/validate-app.ts +215 -121
  17. package/.framework/cli/context.ts +112 -130
  18. package/.framework/cli/env-loader.ts +47 -18
  19. package/.framework/cli/index.ts +81 -42
  20. package/.framework/docs/runtime-types.md +1024 -0
  21. package/.framework/functions/_shared/agent-runner.ts +1296 -961
  22. package/.framework/functions/_shared/app-manifest.ts +82 -68
  23. package/.framework/functions/_shared/audit.ts +135 -83
  24. package/.framework/functions/_shared/{cil-state.ts → cil.ts} +158 -56
  25. package/.framework/functions/_shared/db.ts +80 -126
  26. package/.framework/functions/_shared/hash-api-key.ts +63 -0
  27. package/.framework/functions/_shared/index.ts +224 -335
  28. package/.framework/functions/_shared/kb.ts +319 -0
  29. package/.framework/functions/_shared/llm.ts +92 -0
  30. package/.framework/functions/_shared/logging.ts +288 -0
  31. package/.framework/functions/_shared/middleware.ts +329 -365
  32. package/.framework/functions/_shared/outcomes.ts +36 -0
  33. package/.framework/functions/_shared/permissions.ts +359 -643
  34. package/.framework/functions/_shared/pipeline-runner.ts +243 -316
  35. package/.framework/functions/_shared/principal.ts +376 -468
  36. package/.framework/functions/_shared/resolve-credentials.ts +102 -0
  37. package/.framework/functions/_shared/resolve-ids.ts +188 -16
  38. package/.framework/functions/_shared/retry-deliveries.ts +104 -0
  39. package/.framework/functions/_shared/schema-utils.ts +611 -373
  40. package/.framework/functions/_shared/testing.ts +207 -137
  41. package/.framework/functions/_shared/tracing.ts +276 -0
  42. package/.framework/functions/_shared/trigger-engine.ts +159 -211
  43. package/.framework/functions/_shared/webhook-registration.ts +95 -81
  44. package/.framework/functions/_shared/webhook-registry.ts +153 -75
  45. package/.framework/functions/account-nodes.ts +31 -53
  46. package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
  47. package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
  48. package/.framework/functions/adapters/openai-outbound.ts +40 -0
  49. package/.framework/functions/admin-data.ts +685 -537
  50. package/.framework/functions/admin-funnel.ts +31 -20
  51. package/.framework/functions/admin-install-funnel.ts +47 -28
  52. package/.framework/functions/admin-signals.ts +47 -29
  53. package/.framework/functions/ai-agents.ts +122 -147
  54. package/.framework/functions/ai-interactions.ts +180 -90
  55. package/.framework/functions/api-keys.ts +250 -192
  56. package/.framework/functions/apps.ts +203 -197
  57. package/.framework/functions/auth.ts +98 -91
  58. package/.framework/functions/cil-agent-ingest.ts +773 -0
  59. package/.framework/functions/cil-agent.ts +592 -0
  60. package/.framework/functions/cil-callmap.ts +1227 -0
  61. package/.framework/functions/cil-config.ts +583 -0
  62. package/.framework/functions/cil-context.ts +445 -0
  63. package/.framework/functions/cil-doc.ts +1752 -0
  64. package/.framework/functions/cil-embeddings.ts +1202 -0
  65. package/.framework/functions/cil-graph.ts +585 -0
  66. package/.framework/functions/cil-ingest.ts +2416 -0
  67. package/.framework/functions/cil-pipeline.ts +318 -0
  68. package/.framework/functions/cil-project.ts +499 -0
  69. package/.framework/functions/cil-validate.ts +469 -0
  70. package/.framework/functions/debug-auth.ts +73 -53
  71. package/.framework/functions/deliveries.ts +117 -0
  72. package/.framework/functions/embeddings.ts +528 -516
  73. package/.framework/functions/eval-harness.ts +158 -106
  74. package/.framework/functions/integration-outbound.ts +311 -0
  75. package/.framework/functions/integration-routes.ts +240 -466
  76. package/.framework/functions/integrations.ts +132 -140
  77. package/.framework/functions/invites.ts +401 -201
  78. package/.framework/functions/item-progress.ts +113 -53
  79. package/.framework/functions/kb.ts +28 -0
  80. package/.framework/functions/logs.ts +239 -222
  81. package/.framework/functions/observability.ts +308 -259
  82. package/.framework/functions/pipeline-executions.ts +179 -235
  83. package/.framework/functions/pipelines.ts +163 -205
  84. package/.framework/functions/prompt-configs.ts +109 -156
  85. package/.framework/functions/roles.ts +97 -147
  86. package/.framework/functions/system-cron.ts +132 -218
  87. package/.framework/functions/system.ts +112 -52
  88. package/.framework/functions/tests.ts +32 -28
  89. package/.framework/functions/timers.ts +162 -210
  90. package/.framework/functions/triggers.ts +282 -346
  91. package/.framework/functions/types.ts +283 -400
  92. package/.framework/migrations/001_core_schema.sql +630 -0
  93. package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
  94. package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
  95. package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
  96. package/.framework/migrations/005_core_observability.sql +598 -0
  97. package/.framework/migrations/006_security_hardening_rls.sql +97 -0
  98. package/.framework/migrations/007_kb_article_list.sql +237 -0
  99. package/.framework/migrations/008_items_target.sql +8 -0
  100. package/.framework/migrations/009_roles_slug_unique.sql +11 -0
  101. package/.framework/public/spine.config.json +91 -0
  102. package/.framework/scripts/app-install-cli.ts +112 -98
  103. package/.framework/src/App.tsx +67 -20
  104. package/.framework/src/apps/admin/index.tsx +97 -27
  105. package/.framework/src/components/AppWrapper.tsx +50 -11
  106. package/.framework/src/components/CustomAppLoader.tsx +131 -22
  107. package/.framework/src/components/admin/AdminListPage.tsx +75 -8
  108. package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
  109. package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
  110. package/.framework/src/components/admin/PageInstructions.tsx +49 -0
  111. package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
  112. package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
  113. package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
  114. package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
  115. package/.framework/src/components/app-sidebar.tsx +50 -3
  116. package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
  117. package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
  118. package/.framework/src/components/kb/KBArticleList.tsx +557 -0
  119. package/.framework/src/components/layout/AppShell.tsx +54 -16
  120. package/.framework/src/components/layout/Header.tsx +50 -38
  121. package/.framework/src/components/layout/Layout.tsx +48 -32
  122. package/.framework/src/components/layout/Sidebar.tsx +167 -16
  123. package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
  124. package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
  125. package/.framework/src/components/runtime/DataFilters.tsx +78 -1
  126. package/.framework/src/components/runtime/DataHeader.tsx +32 -29
  127. package/.framework/src/components/runtime/DataListPage.tsx +161 -2
  128. package/.framework/src/components/runtime/DataStats.tsx +48 -1
  129. package/.framework/src/components/runtime/DataTable.tsx +153 -1
  130. package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
  131. package/.framework/src/components/runtime/index.ts +16 -9
  132. package/.framework/src/components/search-form.tsx +33 -1
  133. package/.framework/src/components/shared/AgentView.tsx +48 -51
  134. package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
  135. package/.framework/src/components/shared/InviteManager.tsx +113 -52
  136. package/.framework/src/components/shared/MemberList.tsx +182 -0
  137. package/.framework/src/components/shared/SchemaFields.tsx +96 -78
  138. package/.framework/src/components/ui/DataTable.tsx +86 -56
  139. package/.framework/src/components/ui/Form.tsx +188 -109
  140. package/.framework/src/components/ui/ItemCard.tsx +86 -58
  141. package/.framework/src/components/ui/ItemListView.tsx +88 -61
  142. package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
  143. package/.framework/src/components/ui/Modal.tsx +81 -4
  144. package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
  145. package/.framework/src/components/ui/accordion.tsx +97 -5
  146. package/.framework/src/components/ui/alert-dialog.tsx +225 -13
  147. package/.framework/src/components/ui/alert.tsx +113 -6
  148. package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
  149. package/.framework/src/components/ui/avatar.tsx +129 -7
  150. package/.framework/src/components/ui/badge.tsx +65 -3
  151. package/.framework/src/components/ui/breadcrumb.tsx +145 -8
  152. package/.framework/src/components/ui/button-group.tsx +81 -4
  153. package/.framework/src/components/ui/button.tsx +49 -2
  154. package/.framework/src/components/ui/calendar.tsx +65 -3
  155. package/.framework/src/components/ui/card.tsx +145 -8
  156. package/.framework/src/components/ui/carousel.tsx +129 -7
  157. package/.framework/src/components/ui/chart.tsx +161 -10
  158. package/.framework/src/components/ui/checkbox.tsx +49 -2
  159. package/.framework/src/components/ui/collapsible.tsx +81 -5
  160. package/.framework/src/components/ui/combobox.tsx +305 -20
  161. package/.framework/src/components/ui/command.tsx +177 -11
  162. package/.framework/src/components/ui/context-menu.tsx +273 -17
  163. package/.framework/src/components/ui/dialog.tsx +209 -27
  164. package/.framework/src/components/ui/direction.tsx +64 -4
  165. package/.framework/src/components/ui/drawer.tsx +193 -12
  166. package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
  167. package/.framework/src/components/ui/empty.tsx +145 -9
  168. package/.framework/src/components/ui/field.tsx +209 -14
  169. package/.framework/src/components/ui/hover-card.tsx +81 -4
  170. package/.framework/src/components/ui/input-group.tsx +162 -10
  171. package/.framework/src/components/ui/input-otp.tsx +98 -5
  172. package/.framework/src/components/ui/input.tsx +49 -2
  173. package/.framework/src/components/ui/item.tsx +225 -13
  174. package/.framework/src/components/ui/kbd.tsx +65 -3
  175. package/.framework/src/components/ui/label.tsx +49 -2
  176. package/.framework/src/components/ui/menubar.tsx +289 -17
  177. package/.framework/src/components/ui/native-select.tsx +97 -5
  178. package/.framework/src/components/ui/navigation-menu.tsx +177 -10
  179. package/.framework/src/components/ui/pagination.tsx +161 -9
  180. package/.framework/src/components/ui/popover.tsx +145 -8
  181. package/.framework/src/components/ui/progress.tsx +49 -2
  182. package/.framework/src/components/ui/radio-group.tsx +65 -3
  183. package/.framework/src/components/ui/resizable.tsx +82 -4
  184. package/.framework/src/components/ui/scroll-area.tsx +65 -3
  185. package/.framework/src/components/ui/select.tsx +193 -11
  186. package/.framework/src/components/ui/separator.tsx +49 -2
  187. package/.framework/src/components/ui/sheet.tsx +193 -11
  188. package/.framework/src/components/ui/sidebar.tsx +481 -38
  189. package/.framework/src/components/ui/skeleton.tsx +49 -2
  190. package/.framework/src/components/ui/slider.tsx +49 -2
  191. package/.framework/src/components/ui/sonner.tsx +49 -2
  192. package/.framework/src/components/ui/spinner.tsx +49 -2
  193. package/.framework/src/components/ui/switch.tsx +49 -2
  194. package/.framework/src/components/ui/table-primitives.tsx +160 -33
  195. package/.framework/src/components/ui/table.tsx +161 -9
  196. package/.framework/src/components/ui/tabs.tsx +113 -6
  197. package/.framework/src/components/ui/textarea.tsx +49 -2
  198. package/.framework/src/components/ui/toggle-group.tsx +81 -4
  199. package/.framework/src/components/ui/toggle.tsx +65 -3
  200. package/.framework/src/components/ui/tooltip.tsx +97 -5
  201. package/.framework/src/contexts/AppContext.tsx +129 -45
  202. package/.framework/src/contexts/AuthContext.tsx +187 -144
  203. package/.framework/src/hooks/use-mobile.ts +48 -2
  204. package/.framework/src/hooks/useApi.ts +208 -159
  205. package/.framework/src/hooks/useAppPath.ts +32 -23
  206. package/.framework/src/hooks/useApps.ts +51 -20
  207. package/.framework/src/hooks/useEntityList.ts +32 -78
  208. package/.framework/src/hooks/useEntityRecord.ts +35 -96
  209. package/.framework/src/hooks/useForm.ts +32 -92
  210. package/.framework/src/hooks/useListSchema.ts +49 -78
  211. package/.framework/src/hooks/useSchemaRecord.ts +114 -105
  212. package/.framework/src/lib/api.ts +195 -116
  213. package/.framework/src/lib/supabase.ts +98 -64
  214. package/.framework/src/lib/utils.ts +287 -151
  215. package/.framework/src/main.tsx +49 -3
  216. package/.framework/src/pages/DashboardPage.tsx +52 -29
  217. package/.framework/src/pages/NotFoundPage.tsx +32 -10
  218. package/.framework/src/pages/SetupPage.tsx +32 -12
  219. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
  220. package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
  221. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
  222. package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
  223. package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
  224. package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
  225. package/.framework/src/pages/admin/AppsPage.tsx +49 -2
  226. package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
  227. package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
  228. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
  229. package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
  230. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
  231. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
  232. package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
  233. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
  234. package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
  235. package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
  236. package/.framework/src/pages/admin/LogsPage.tsx +422 -75
  237. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
  238. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
  239. package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
  240. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
  241. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
  242. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
  243. package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
  244. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
  245. package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
  246. package/.framework/src/pages/admin/RolesPage.tsx +171 -18
  247. package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
  248. package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
  249. package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
  250. package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
  251. package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
  252. package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
  253. package/.framework/src/pages/admin/TimersPage.tsx +48 -20
  254. package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
  255. package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
  256. package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
  257. package/.framework/src/pages/admin/TypesPage.tsx +48 -20
  258. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
  259. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
  260. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
  261. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
  262. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
  263. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
  264. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
  265. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
  266. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
  267. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
  268. package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
  269. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
  270. package/.framework/src/pages/auth/LoginPage.tsx +50 -23
  271. package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
  272. package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
  273. package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
  274. package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
  275. package/.framework/src/types/auth.ts +128 -71
  276. package/.framework/src/types/types.ts +373 -157
  277. package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
  278. package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
  279. package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
  280. package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
  281. package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
  282. package/docs/README.md +9 -130
  283. package/netlify.toml +5 -2
  284. package/package.json +13 -25
  285. package/scripts/kb-ingest-docs.ts +203 -0
  286. package/spine.config.json +65 -4
  287. package/.framework/migrations/001_schema.sql +0 -425
  288. package/.framework/migrations/002_rls_and_functions.sql +0 -763
  289. package/.framework/migrations/004_enhancements.sql +0 -43
  290. package/.framework/migrations/005_auth_user_trigger.sql +0 -105
  291. package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
  292. package/.framework/migrations/016_invites.sql +0 -27
  293. package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
  294. package/.framework/migrations/018_apps_required_roles.sql +0 -17
  295. package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
  296. package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
  297. package/.framework/migrations/021_app_domains.sql +0 -112
  298. package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
  299. package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
  300. package/.framework/migrations/024_messages_account_id.sql +0 -9
  301. package/.framework/migrations/025_retype_threads_messages.sql +0 -240
  302. package/.framework/migrations/026_fix_rls_policies.sql +0 -47
  303. package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
  304. package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
  305. package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
  306. package/.framework/migrations/030_messages_updated_by.sql +0 -6
  307. package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
  308. package/docs/APPS.md +0 -232
  309. package/docs/ARCHITECTURE.md +0 -246
  310. package/docs/INSTALL.md +0 -155
  311. package/docs/design-schema-spec.md +0 -1837
  312. package/docs/dev-guides/01-create-an-app.md +0 -183
  313. package/docs/dev-guides/02-create-a-function.md +0 -178
  314. package/docs/dev-guides/03-create-a-component.md +0 -178
  315. package/docs/dev-guides/04-webhook-handlers.md +0 -129
  316. package/docs/dev-guides/05-testing.md +0 -168
  317. package/docs/dev-guides/README.md +0 -40
  318. package/docs/npm-packages-plan.md +0 -288
  319. package/docs/spine-core--api-reference.md +0 -822
@@ -0,0 +1,1752 @@
1
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_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-doc"]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Own module-level imports, exports, and configuration for cortex.functions.custom_cil-doc"]
4
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" 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-doc" notable_decisions="[]"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
8
+ // CIL[DOC-STABILITY stability="stable"]
9
+ // CIL[DOC-AUDIENCE audience="developer"]
10
+ // CIL[DOC-VECTOR type="context" content="Layer: 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"]
16
+
17
+
18
+
19
+
20
+
21
+ import { createHandler } from './_shared/middleware'
22
+ import { adminDb } from './_shared/db'
23
+ import { update as adminUpdate } from './admin-data'
24
+ import { callOpenAIChat } from './_shared/llm'
25
+ import { FileStatus, FileTreeNode, isSelectedPath, getFileStatus, updateTreeNodeStatus, saveProjectTree } from './_shared/cil'
26
+ import * as fs from 'fs'
27
+ import * as path from 'path'
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_module_header_1784235266"]
38
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_default_model_1784235266" type="variable" identity="default_model" parent="none"]
39
+ // CIL[DOC-MACRO purpose="Defines default_model configuration or state in cortex.functions.custom_cil-doc"]
40
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for default_model"]
41
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" 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\",\"\\\"]"]
42
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of default_model" errors="none" side_effects="none"]
43
+ // CIL[DOC-MICRO logic_summary="Declares default_model with initial value or constant binding used by cortex.functions.custom_cil-doc" notable_decisions="[]"]
44
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
45
+ // CIL[DOC-STABILITY stability="stable"]
46
+ // CIL[DOC-VECTOR type="context" content="Layer: 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, \."]
47
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
48
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
49
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
50
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
51
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
52
+ const DEFAULT_MODEL = 'gpt-4o-mini'
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_default_model_1784235266"]
63
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_model_prices_1784235266" type="variable" identity="model_prices" parent="none"]
64
+ // CIL[DOC-MACRO purpose="Defines model_prices configuration or state in cortex.functions.custom_cil-doc"]
65
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for model_prices"]
66
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" 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\",\"\\\"]"]
67
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of model_prices" errors="none" side_effects="none"]
68
+ // CIL[DOC-MICRO logic_summary="Declares model_prices with initial value or constant binding used by cortex.functions.custom_cil-doc" notable_decisions="[]"]
69
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
70
+ // CIL[DOC-STABILITY stability="stable"]
71
+ // 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, \."]
72
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
73
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
74
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
75
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
76
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
77
+ const MODEL_PRICES: Record<string, { input_per_1m: number; output_per_1m: number }> = {
78
+ 'gpt-4o-mini': { input_per_1m: 0.15, output_per_1m: 0.60 },
79
+ 'gpt-4o': { input_per_1m: 2.50, output_per_1m: 10.00 },
80
+ 'gpt-4-turbo': { input_per_1m: 10.00, output_per_1m: 30.00 },
81
+ 'gpt-3.5-turbo': { input_per_1m: 0.50, output_per_1m: 1.50 },
82
+ }
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_model_prices_1784235266"]
92
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_estimated_output_tokens_per_chunk_1784235266" type="variable" identity="estimated_output_tokens_per_chunk" parent="none"]
93
+ // CIL[DOC-MACRO purpose="Defines estimated_output_tokens_per_chunk configuration or state in cortex.functions.custom_cil-doc"]
94
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for estimated_output_tokens_per_chunk"]
95
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" 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\",\"\\\"]"]
96
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of estimated_output_tokens_per_chunk" errors="none" side_effects="none"]
97
+ // CIL[DOC-MICRO logic_summary="Declares estimated_output_tokens_per_chunk with initial value or constant binding used by cortex.functions.custom_cil-doc" notable_decisions="[]"]
98
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
99
+ // CIL[DOC-STABILITY stability="stable"]
100
+ // 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, \."]
101
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
102
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
103
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
104
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
105
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
106
+ const ESTIMATED_OUTPUT_TOKENS_PER_CHUNK = 200
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_estimated_output_tokens_per_chunk_1784235266"]
115
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_system_prompt_overhead_tokens_1784235266" type="variable" identity="system_prompt_overhead_tokens" parent="none"]
116
+ // CIL[DOC-MACRO purpose="Defines system_prompt_overhead_tokens configuration or state in cortex.functions.custom_cil-doc"]
117
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for system_prompt_overhead_tokens"]
118
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" 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\",\"\\\"]"]
119
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of system_prompt_overhead_tokens" errors="none" side_effects="none"]
120
+ // CIL[DOC-MICRO logic_summary="Declares system_prompt_overhead_tokens with initial value or constant binding used by cortex.functions.custom_cil-doc" notable_decisions="[]"]
121
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
122
+ // CIL[DOC-STABILITY stability="stable"]
123
+ // 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, \."]
124
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
125
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
126
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
127
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
128
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
129
+ const SYSTEM_PROMPT_OVERHEAD_TOKENS = 350
130
+
131
+
132
+
133
+
134
+
135
+
136
+
137
+
138
+
139
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_system_prompt_overhead_tokens_1784235266"]
140
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_estimatetokens_1784235266" type="function" identity="estimatetokens" parent="none"]
141
+ // CIL[DOC-MACRO purpose="Implements estimatetokens logic in cortex.functions.custom_cil-doc"]
142
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute estimatetokens and return its computed result"]
143
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
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 estimatetokens with estimateTokens(text: string 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: 0. Direct calls: 0. Related files: none."]
149
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
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 estimateTokens(text: string): number {
155
+ return Math.ceil(text.length / 4)
156
+ }
157
+
158
+
159
+
160
+
161
+
162
+
163
+
164
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_estimatetokens_1784235266"]
165
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_needsdocumentation_1784235266" type="function" identity="needsdocumentation" parent="none"]
166
+ // CIL[DOC-MACRO purpose="Implements needsdocumentation logic in cortex.functions.custom_cil-doc"]
167
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute needsdocumentation and return its computed result"]
168
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
169
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
170
+ // CIL[DOC-MICRO logic_summary="Provides needsdocumentation with needsDocumentation(chunk: any inputs, handling internal flow and returning a result" 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: none."]
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
+ function needsDocumentation(chunk: any): boolean {
180
+ const d = chunk.data || {}
181
+
182
+ if (d.doc_validation_errors && d.doc_validation_errors.length > 0) return true
183
+
184
+
185
+
186
+ const required = d.chunk_type === 'module_header'
187
+ ? REQUIRED_MODULE_FIELDS
188
+ : REQUIRED_CHUNK_FIELDS
189
+ return required.some(f => !d[f] || String(d[f]).trim() === '')
190
+ }
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_needsdocumentation_1784235266"]
200
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_loadallchunks_1784235266" type="function" identity="loadallchunks" parent="none"]
201
+ // CIL[DOC-MACRO purpose="Implements loadallchunks logic in cortex.functions.custom_cil-doc"]
202
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute loadallchunks and return its computed result"]
203
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
204
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
205
+ // CIL[DOC-MICRO logic_summary="Provides loadallchunks with loadAllChunks(projectId: string, filePath?: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
206
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
207
+ // CIL[DOC-STABILITY stability="stable"]
208
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
209
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
210
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
211
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
212
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
213
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
214
+ async function loadAllChunks(projectId: string, filePath?: string): Promise<any[]> {
215
+ const PAGE = 1000
216
+ const all: any[] = []
217
+ for (let offset = 0; ; offset += PAGE) {
218
+ let q = adminDb
219
+ .from('items')
220
+ .select('id, title, data')
221
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
222
+ .filter('data->>project_id', 'eq', projectId)
223
+ .eq('is_active', true)
224
+ .order('id')
225
+ .range(offset, offset + PAGE - 1)
226
+ if (filePath) q = q.filter('data->>file_path', 'eq', filePath)
227
+ const { data, error } = await q
228
+ if (error) throw new Error(`Failed to load chunks: ${error.message}`)
229
+ if (!data || data.length === 0) break
230
+ all.push(...data)
231
+ if (data.length < PAGE) break
232
+ }
233
+ return all
234
+ }
235
+
236
+
237
+
238
+
239
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_loadallchunks_1784235266"]
240
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_loadpendingchunks_1784235266" type="function" identity="loadpendingchunks" parent="none"]
241
+ // CIL[DOC-MACRO purpose="Implements loadpendingchunks logic in cortex.functions.custom_cil-doc"]
242
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute loadpendingchunks and return its computed result"]
243
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
244
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
245
+ // 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="[]"]
246
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
247
+ // CIL[DOC-STABILITY stability="stable"]
248
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
249
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
250
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
251
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
252
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
253
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
254
+ async function loadPendingChunks(projectId: string, selectedPaths: string[], requiredStatus: FileStatus): Promise<any[]> {
255
+ const { data: fileItems } = await adminDb
256
+ .from('items')
257
+ .select('id, data')
258
+ .filter('data->>kb_type', 'eq', 'cil_file')
259
+ .filter('data->>project_id', 'eq', projectId)
260
+ .eq('is_active', true)
261
+
262
+ const selectedFileIds = (fileItems || [])
263
+ .filter((f: any) => getFileStatus(f) === requiredStatus && isSelectedPath(f.data?.file_path || f.title, selectedPaths))
264
+ .map((f: any) => f.id)
265
+
266
+ if (selectedFileIds.length === 0) return []
267
+
268
+ const { data: allChunks } = await adminDb
269
+ .from('items')
270
+ .select('id, title, data')
271
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
272
+ .filter('data->>project_id', 'eq', projectId)
273
+ .eq('is_active', true)
274
+
275
+ return (allChunks || []).filter((c: any) => selectedFileIds.includes(c.data?.file_id))
276
+ }
277
+
278
+
279
+
280
+
281
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_loadpendingchunks_1784235266"]
282
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_maybeadvancefiletopass3_1784235266" type="function" identity="maybeadvancefiletopass3" parent="none"]
283
+ // CIL[DOC-MACRO purpose="Implements maybeadvancefiletopass3 logic in cortex.functions.custom_cil-doc"]
284
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute maybeadvancefiletopass3 and return its computed result"]
285
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
286
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
287
+ // CIL[DOC-MICRO logic_summary="Provides maybeadvancefiletopass3 with maybeAdvanceFileToPass3(ctx: any, fileId: string, tree: FileTreeNode | null inputs, handling internal flow and returning a result" notable_decisions="[]"]
288
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
289
+ // CIL[DOC-STABILITY stability="stable"]
290
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
291
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
292
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
293
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
294
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
295
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
296
+ async function maybeAdvanceFileToPass3(ctx: any, fileId: string, tree: FileTreeNode | null): Promise<void> {
297
+ const { data: fileChunks } = await adminDb
298
+ .from('items')
299
+ .select('id, title, data')
300
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
301
+ .filter('data->>file_id', 'eq', fileId)
302
+ .eq('is_active', true)
303
+
304
+ const allDocumented = (fileChunks || []).every(c => !needsDocumentation(c))
305
+ if (!allDocumented) return
306
+
307
+ const { data: fileItem } = await adminDb
308
+ .from('items')
309
+ .select('id, data')
310
+ .eq('id', fileId)
311
+ .maybeSingle()
312
+
313
+ if (!fileItem) return
314
+
315
+ const updateCtx = { ...ctx, query: { ...(ctx.query || {}), entity: 'items', id: fileId } }
316
+ await adminUpdate(updateCtx, {
317
+ data: {
318
+ ...fileItem.data,
319
+ status: 'pass3_complete',
320
+ last_status_at: new Date().toISOString(),
321
+ },
322
+ }).catch((e: any) => console.error('advance to pass3 failed:', e.message))
323
+
324
+ if (tree) updateTreeNodeStatus(tree, fileId, 'pass3_complete')
325
+ }
326
+
327
+
328
+
329
+
330
+
331
+
332
+
333
+
334
+
335
+
336
+
337
+
338
+
339
+
340
+
341
+
342
+
343
+
344
+
345
+
346
+
347
+
348
+
349
+
350
+
351
+
352
+
353
+
354
+
355
+
356
+
357
+
358
+
359
+
360
+
361
+
362
+
363
+
364
+
365
+
366
+
367
+
368
+
369
+
370
+
371
+
372
+
373
+
374
+
375
+
376
+
377
+
378
+
379
+
380
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_maybeadvancefiletopass3_1784235266"]
381
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_required_module_fields_1784235266" type="variable" identity="required_module_fields" parent="none"]
382
+ // CIL[DOC-MACRO purpose="Defines required_module_fields configuration or state in cortex.functions.custom_cil-doc"]
383
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for required_module_fields"]
384
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
385
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of required_module_fields" errors="none" side_effects="none"]
386
+ // CIL[DOC-MICRO logic_summary="Declares required_module_fields with initial value or constant binding used by cortex.functions.custom_cil-doc" notable_decisions="[]"]
387
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
388
+ // CIL[DOC-STABILITY stability="stable"]
389
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
390
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
391
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
392
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
393
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
394
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
395
+ const REQUIRED_MODULE_FIELDS = ['module', 'audience', 'layer', 'stability', 'description']
396
+
397
+
398
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_required_module_fields_1784235266"]
399
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_required_chunk_fields_1784235266" type="variable" identity="required_chunk_fields" parent="none"]
400
+ // CIL[DOC-MACRO purpose="Defines required_chunk_fields configuration or state in cortex.functions.custom_cil-doc"]
401
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for required_chunk_fields"]
402
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
403
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of required_chunk_fields" errors="none" side_effects="none"]
404
+ // CIL[DOC-MICRO logic_summary="Declares required_chunk_fields with initial value or constant binding used by cortex.functions.custom_cil-doc" notable_decisions="[]"]
405
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
406
+ // CIL[DOC-STABILITY stability="stable"]
407
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
408
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
409
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
410
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
411
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
412
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
413
+ const REQUIRED_CHUNK_FIELDS = ['description', 'input_spec', 'output_spec', 'side_effects', 'stability']
414
+
415
+
416
+
417
+
418
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_required_chunk_fields_1784235266"]
419
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_modulenamefrompath_1784235266" type="function" identity="modulenamefrompath" parent="none"]
420
+ // CIL[DOC-MACRO purpose="Implements modulenamefrompath logic in cortex.functions.custom_cil-doc"]
421
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute modulenamefrompath and return its computed result"]
422
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
423
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
424
+ // CIL[DOC-MICRO logic_summary="Provides modulenamefrompath with moduleNameFromPath(relPath: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
425
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
426
+ // CIL[DOC-STABILITY stability="stable"]
427
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
428
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
429
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
430
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
431
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
432
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
433
+ function moduleNameFromPath(relPath: string): string {
434
+ return path.basename(relPath, path.extname(relPath))
435
+ }
436
+
437
+
438
+
439
+
440
+
441
+
442
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_modulenamefrompath_1784235266"]
443
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_buildjsdoc_1784235266" type="function" identity="buildjsdoc" parent="none"]
444
+ // CIL[DOC-MACRO purpose="Implements buildjsdoc logic in cortex.functions.custom_cil-doc"]
445
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute buildjsdoc and return its computed result"]
446
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
447
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
448
+ // CIL[DOC-MICRO logic_summary="Provides buildjsdoc with buildJsDoc(chunk: any inputs, handling internal flow and returning a result" notable_decisions="[]"]
449
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
450
+ // CIL[DOC-STABILITY stability="stable"]
451
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
452
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
453
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
454
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
455
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
456
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
457
+ function buildJsDoc(chunk: any): string {
458
+ const d = chunk.data || {}
459
+ const isModuleHeader = d.chunk_type === 'module_header'
460
+ const description = (d.description || d.macro || '').trim()
461
+ if (!description) return ''
462
+
463
+
464
+ if (isModuleHeader) {
465
+ const body: string[] = []
466
+ if (d.module) body.push(`@module ${d.module}`)
467
+ if (d.audience) body.push(`@audience ${d.audience}`)
468
+ if (d.layer) body.push(`@layer ${d.layer}`)
469
+ if (d.stability)body.push(`@stability ${d.stability}`)
470
+
471
+
472
+
473
+ const descLines = description.split('\n')
474
+
475
+
476
+ const seeAlsoRefs = d.see_also
477
+ ? d.see_also.split(/\n/).map((s: string) => s.trim()).filter(Boolean)
478
+ : []
479
+
480
+ const docLines = [
481
+ '/**',
482
+ ...body.map(l => ` * ${l}`),
483
+ ' *',
484
+ ...descLines.map(l => ` * ${l}`),
485
+ ...(seeAlsoRefs.length > 0 ? [' *'] : []),
486
+ ...seeAlsoRefs.map(ref => ` * @seeAlso ${ref}`),
487
+ ' *',
488
+ ' * @cil-generated',
489
+ ' */',
490
+ ]
491
+ return docLines.join('\n')
492
+ }
493
+
494
+
495
+ const body: string[] = []
496
+
497
+ const chunkKind = d.chunk_type || ''
498
+ const isTypeDecl = ['interface', 'type', 'enum'].includes(chunkKind)
499
+ const isConstant = chunkKind === 'constant'
500
+ const isCallableChunk = !isTypeDecl && !isConstant
501
+
502
+
503
+
504
+
505
+ const macro = (d.macro || '').trim()
506
+ const micro = (d.micro || '').trim()
507
+ if (!isTypeDecl && !isConstant) {
508
+ const descNorm = description.toLowerCase().replace(/\s+/g, ' ')
509
+ const macroNorm = macro.toLowerCase().replace(/\s+/g, ' ')
510
+ const macroDistinct = macro && macroNorm !== descNorm && !descNorm.includes(macroNorm.slice(0, 40))
511
+ const microDistinct = micro && micro !== description && micro !== macro
512
+ if (macroDistinct) body.push(`@macro ${macro}`)
513
+ if (macroDistinct && microDistinct) body.push(`@micro ${micro}`)
514
+ }
515
+
516
+
517
+ if (isCallableChunk && d.input_spec) {
518
+ const entries = d.input_spec.split(/\n/).map((s: string) => s.trim()).filter(Boolean)
519
+ if (entries.length === 1 && entries[0].toLowerCase() === 'none') {
520
+ } else {
521
+ body.push('@inputSpec')
522
+ for (const entry of entries) body.push(` ${entry}`)
523
+ }
524
+ }
525
+
526
+
527
+
528
+ if (isCallableChunk && d.output_spec) body.push(`@outputSpec ${d.output_spec}`)
529
+
530
+
531
+ const throwsVal = (d.throws || '').trim()
532
+ if (throwsVal && throwsVal.toLowerCase() !== 'none') body.push(`@throws ${throwsVal}`)
533
+
534
+
535
+ if (d.side_effects) body.push(`@sideEffects ${d.side_effects}`)
536
+
537
+
538
+ if (d.stability) body.push(`@stability ${d.stability}`)
539
+
540
+
541
+
542
+ const callsVal = (d.calls || '').trim()
543
+ if (callsVal && callsVal.toLowerCase() !== 'unknown' && callsVal.toLowerCase() !== 'none') {
544
+ body.push(`@calls ${callsVal}`)
545
+ }
546
+
547
+
548
+
549
+
550
+ const ehVal = (d.error_handling || '').trim()
551
+ const ehNoise = /^throws( on (unhandled|unexpected) errors?)?$/i.test(ehVal)
552
+ if (ehVal && !ehNoise) body.push(`@errorHandling ${ehVal}`)
553
+
554
+
555
+
556
+
557
+ body.push('@cil-generated')
558
+
559
+ const docLines = [
560
+ '/**',
561
+ ` * ${description}`,
562
+ ...(body.length > 0 ? [' *'] : []),
563
+ ...body.map(l => ` * ${l}`),
564
+ ' */',
565
+ ]
566
+ return docLines.join('\n')
567
+ }
568
+
569
+
570
+
571
+
572
+
573
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_buildjsdoc_1784235266"]
574
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_validatechunkdocs_1784235266" type="function" identity="validatechunkdocs" parent="none"]
575
+ // CIL[DOC-MACRO purpose="Implements validatechunkdocs logic in cortex.functions.custom_cil-doc"]
576
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute validatechunkdocs and return its computed result"]
577
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" 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 validatechunkdocs with validateChunkDocs(chunk: any 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
+ function validateChunkDocs(chunk: any): string[] {
589
+ const d = chunk.data || {}
590
+ const errors: string[] = []
591
+ const isModuleHeader = d.chunk_type === 'module_header'
592
+
593
+ const required = isModuleHeader ? REQUIRED_MODULE_FIELDS : REQUIRED_CHUNK_FIELDS
594
+ for (const field of required) {
595
+ if (!d[field] || String(d[field]).trim() === '') {
596
+ errors.push(`missing ${field}`)
597
+ }
598
+ }
599
+
600
+ if (!isModuleHeader && d.input_spec && d.input_spec !== 'none') {
601
+ const params = d.input_spec.split(/\n/).map((s: string) => s.trim()).filter(Boolean)
602
+ const paramNames = params.map(p => {
603
+ const m = p.match(/^[-\s]*([a-zA-Z0-9_]+)/)
604
+ return m ? m[1] : ''
605
+ }).filter(Boolean)
606
+
607
+ const code = d.code_content || ''
608
+ const signatureMatch = code.match(/(?:function|const|let|var)\s+\w+\s*\(([^)]*)\)/)
609
+ if (signatureMatch) {
610
+ const rawParams = signatureMatch[1]
611
+ const declaredNames = rawParams
612
+ .split(',')
613
+ .map(s => s.trim())
614
+ .filter(s => s)
615
+ .map(s => s.split(/[:=]/)[0].trim().replace(/\?/, ''))
616
+ .filter(Boolean)
617
+ for (const declared of declaredNames) {
618
+ if (!paramNames.includes(declared)) {
619
+ errors.push(`undocumented parameter: ${declared}`)
620
+ }
621
+ }
622
+ }
623
+ }
624
+
625
+ return errors
626
+ }
627
+
628
+
629
+
630
+
631
+
632
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_validatechunkdocs_1784235266"]
633
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_findexistingciljsdoc_1784235266" type="function" identity="findexistingciljsdoc" parent="none"]
634
+ // CIL[DOC-MACRO purpose="Implements findexistingciljsdoc logic in cortex.functions.custom_cil-doc"]
635
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute findexistingciljsdoc and return its computed result"]
636
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
637
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
638
+ // CIL[DOC-MICRO logic_summary="Provides findexistingciljsdoc with findExistingCilJsDoc(lines: string[], markerIdx: number inputs, handling internal flow and returning a result" notable_decisions="[]"]
639
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
640
+ // CIL[DOC-STABILITY stability="stable"]
641
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
642
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
643
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
644
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
645
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
646
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
647
+ function findExistingCilJsDoc(lines: string[], markerIdx: number): { start: number; end: number } | null {
648
+ let startIdx = -1
649
+ for (let i = markerIdx + 1; i < lines.length; i++) {
650
+ const trimmed = lines[i].trim()
651
+ if (trimmed === '') continue
652
+ if (trimmed.startsWith('/**')) { startIdx = i; break }
653
+ break
654
+ }
655
+ if (startIdx === -1) return null
656
+
657
+ let endIdx = -1
658
+ let hasCilTag = false
659
+ for (let i = startIdx; i < lines.length; i++) {
660
+ const trimmed = lines[i].trim()
661
+ if (trimmed.includes('@cil-generated')) hasCilTag = true
662
+ if (trimmed === '*/' || trimmed.endsWith('*/')) { endIdx = i; break }
663
+ }
664
+ if (endIdx === -1 || !hasCilTag) return null
665
+ return { start: startIdx, end: endIdx }
666
+ }
667
+
668
+
669
+
670
+
671
+
672
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_findexistingciljsdoc_1784235266"]
673
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_findlegacyciljsdocabove_1784235266" type="function" identity="findlegacyciljsdocabove" parent="none"]
674
+ // CIL[DOC-MACRO purpose="Implements findlegacyciljsdocabove logic in cortex.functions.custom_cil-doc"]
675
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute findlegacyciljsdocabove and return its computed result"]
676
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
677
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
678
+ // CIL[DOC-MICRO logic_summary="Provides findlegacyciljsdocabove with findLegacyCilJsDocAbove(lines: string[], markerIdx: number inputs, handling internal flow and returning a result" notable_decisions="[]"]
679
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
680
+ // CIL[DOC-STABILITY stability="stable"]
681
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
682
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
683
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
684
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
685
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
686
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
687
+ function findLegacyCilJsDocAbove(lines: string[], markerIdx: number): { start: number; end: number } | null {
688
+ let endIdx = -1
689
+ for (let i = markerIdx - 1; i >= 0; i--) {
690
+ const trimmed = lines[i].trim()
691
+ if (trimmed === '') continue
692
+ if (trimmed === '*/' || trimmed.endsWith('*/')) { endIdx = i; break }
693
+ break
694
+ }
695
+ if (endIdx === -1) return null
696
+
697
+ let startIdx = -1
698
+ let hasCilTag = false
699
+ for (let i = endIdx; i >= 0; i--) {
700
+ const trimmed = lines[i].trim()
701
+ if (trimmed.includes('@cil-generated')) hasCilTag = true
702
+ if (trimmed.startsWith('/**')) { startIdx = i; break }
703
+ }
704
+ if (startIdx === -1 || !hasCilTag) return null
705
+
706
+ return { start: startIdx, end: endIdx }
707
+ }
708
+
709
+
710
+
711
+
712
+
713
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_findlegacyciljsdocabove_1784235266"]
714
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_writejsdoctosource_1784235266" type="function" identity="writejsdoctosource" parent="none"]
715
+ // CIL[DOC-MACRO purpose="Implements writejsdoctosource logic in cortex.functions.custom_cil-doc"]
716
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute writejsdoctosource and return its computed result"]
717
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
718
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
719
+ // CIL[DOC-MICRO logic_summary="Provides writejsdoctosource with writeJsDocToSource(chunk: any, repoPath: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
720
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
721
+ // CIL[DOC-STABILITY stability="stable"]
722
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
723
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
724
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
725
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
726
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
727
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
728
+ function writeJsDocToSource(chunk: any, repoPath: string): void {
729
+ const d = chunk.data || {}
730
+ const relPath = d.file_path
731
+ if (!repoPath || !relPath) return
732
+
733
+ const ext = path.extname(relPath).toLowerCase()
734
+ if (!['.ts', '.tsx', '.js', '.jsx'].includes(ext)) return
735
+
736
+ const jsDoc = buildJsDoc(chunk)
737
+ if (!jsDoc) return
738
+
739
+ const absPath = path.join(repoPath, relPath)
740
+ if (!fs.existsSync(absPath)) return
741
+
742
+ const content = fs.readFileSync(absPath, 'utf-8')
743
+ const lines = content.split('\n')
744
+
745
+ const markerMap = findChunkStartMarkers(lines)
746
+ let markerIdx = markerMap.get((d.chunk_name || chunk.title).trim().toLowerCase())
747
+ if (markerIdx === undefined) return
748
+
749
+ const newLines = [...lines]
750
+
751
+
752
+ const legacyAbove = findLegacyCilJsDocAbove(newLines, markerIdx)
753
+ if (legacyAbove) {
754
+ newLines.splice(legacyAbove.start, legacyAbove.end - legacyAbove.start + 1)
755
+
756
+ markerIdx -= (legacyAbove.end - legacyAbove.start + 1)
757
+ }
758
+
759
+ const existing = findExistingCilJsDoc(newLines, markerIdx)
760
+ if (existing) {
761
+ newLines.splice(existing.start, existing.end - existing.start + 1, jsDoc)
762
+ } else {
763
+ newLines.splice(markerIdx + 1, 0, jsDoc)
764
+ }
765
+
766
+ fs.writeFileSync(absPath, newLines.join('\n'), 'utf-8')
767
+ }
768
+
769
+
770
+
771
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_writejsdoctosource_1784235266"]
772
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_escaperegexp_1784235266" type="function" identity="escaperegexp" parent="none"]
773
+ // CIL[DOC-MACRO purpose="Implements escaperegexp logic in cortex.functions.custom_cil-doc"]
774
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute escaperegexp and return its computed result"]
775
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
776
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
777
+ // CIL[DOC-MICRO logic_summary="Provides escaperegexp with escapeRegExp(s: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
778
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
779
+ // CIL[DOC-STABILITY stability="stable"]
780
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
781
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
782
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
783
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
784
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
785
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
786
+ function escapeRegExp(s: string): string {
787
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
788
+ }
789
+
790
+
791
+
792
+
793
+
794
+
795
+
796
+
797
+
798
+
799
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_escaperegexp_1784235266"]
800
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_chunk_start_marker_re_1784235266" type="variable" identity="chunk_start_marker_re" parent="none"]
801
+ // CIL[DOC-MACRO purpose="Defines chunk_start_marker_re configuration or state in cortex.functions.custom_cil-doc"]
802
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for chunk_start_marker_re"]
803
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
804
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of chunk_start_marker_re" errors="none" side_effects="none"]
805
+ // CIL[DOC-MICRO logic_summary="Declares chunk_start_marker_re with initial value or constant binding used by cortex.functions.custom_cil-doc" notable_decisions="[]"]
806
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
807
+ // CIL[DOC-STABILITY stability="stable"]
808
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
809
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
810
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
811
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
812
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
813
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
814
+ const CHUNK_START_MARKER_RE = /^\s*\/\*\*\s*[─\-]+\s*CHUNK_START:\s*(?:PROPOSAL\s+|REJECTED\s+)?(.+?)\s*[─\-]*\s*\*\/\s*$/
815
+
816
+
817
+
818
+
819
+
820
+
821
+
822
+
823
+
824
+
825
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_chunk_start_marker_re_1784235266"]
826
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_findchunkstartmarkers_1784235266" type="function" identity="findchunkstartmarkers" parent="none"]
827
+ // CIL[DOC-MACRO purpose="Implements findchunkstartmarkers logic in cortex.functions.custom_cil-doc"]
828
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute findchunkstartmarkers and return its computed result"]
829
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
830
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
831
+ // CIL[DOC-MICRO logic_summary="Provides findchunkstartmarkers with findChunkStartMarkers(lines: string[] inputs, handling internal flow and returning a result" notable_decisions="[]"]
832
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
833
+ // CIL[DOC-STABILITY stability="stable"]
834
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
835
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
836
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
837
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
838
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
839
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
840
+ function findChunkStartMarkers(lines: string[]): Map<string, number> {
841
+ const map = new Map<string, number>()
842
+ for (let i = 0; i < lines.length; i++) {
843
+ const m = lines[i].match(CHUNK_START_MARKER_RE)
844
+ if (m) {
845
+ const name = m[1].trim().toLowerCase()
846
+ if (!map.has(name)) map.set(name, i)
847
+ }
848
+ }
849
+ return map
850
+ }
851
+
852
+
853
+
854
+
855
+
856
+
857
+
858
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_findchunkstartmarkers_1784235266"]
859
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_builddocprompt_1784235266" type="function" identity="builddocprompt" parent="none"]
860
+ // CIL[DOC-MACRO purpose="Implements builddocprompt logic in cortex.functions.custom_cil-doc"]
861
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute builddocprompt and return its computed result"]
862
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
863
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
864
+ // CIL[DOC-MICRO logic_summary="Provides builddocprompt with buildDocPrompt(chunk: any inputs, handling internal flow and returning a result" notable_decisions="[]"]
865
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
866
+ // CIL[DOC-STABILITY stability="stable"]
867
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
868
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
869
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
870
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
871
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
872
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
873
+ function buildDocPrompt(chunk: any): string {
874
+ const d = chunk.data || {}
875
+ const code = (d.code_content || '').slice(0, 3000)
876
+ const isModuleHeader = d.chunk_type === 'module_header'
877
+ return isModuleHeader ? buildModuleHeaderPrompt(d, code) : buildChunkPrompt(d, code)
878
+ }
879
+
880
+
881
+
882
+
883
+
884
+
885
+
886
+
887
+
888
+
889
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_builddocprompt_1784235266"]
890
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_buildmoduleheaderprompt_1784235266" type="function" identity="buildmoduleheaderprompt" parent="none"]
891
+ // CIL[DOC-MACRO purpose="Implements buildmoduleheaderprompt logic in cortex.functions.custom_cil-doc"]
892
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute buildmoduleheaderprompt and return its computed result"]
893
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
894
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
895
+ // CIL[DOC-MICRO logic_summary="Provides buildmoduleheaderprompt with buildModuleHeaderPrompt(d: any, code: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
896
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
897
+ // CIL[DOC-STABILITY stability="stable"]
898
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
899
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
900
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
901
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
902
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
903
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
904
+ function buildModuleHeaderPrompt(d: any, code: string): string {
905
+ const filePath = d.file_path || 'unknown'
906
+ return `You are documenting the MODULE HEADER for file: ${filePath}
907
+
908
+ This is the top of the file — imports, constants, and module-level setup.
909
+
910
+ \`\`\`typescript
911
+ ${code}
912
+ \`\`\`
913
+
914
+ Generate a file-level JSDoc block. Your job is to orient a developer to this module
915
+ in 10 seconds — what it does, how it is entered, and what depends on it.
916
+
917
+ Rules:
918
+ - description: 2–4 sentences covering what the module does, its role in the system,
919
+ and any key architectural constraints. If this is an API handler, include the
920
+ route pattern(s). If it has a multi-step pipeline (auth → validate → execute),
921
+ number the steps. If there are non-obvious invariants (things that must always be
922
+ true for callers), prefix them with INVARIANT:.
923
+ - seeAlso: 2–4 direct dependencies a reader needs to understand this module.
924
+ Format each as: filename (reason it matters). Omit obvious/trivial imports.
925
+ - Do NOT list every import. Do NOT describe individual functions (those get their own docs).
926
+
927
+ Respond ONLY with a JSON object (no markdown, no commentary):
928
+ {
929
+ "description": "<2-4 sentences + optional route table + optional numbered flow + optional INVARIANT lines, all as a single string with \\n between paragraphs>",
930
+ "module": "<filename without extension>",
931
+ "audience": "<internal | external | both>",
932
+ "layer": "<shared-core | app-specific | infrastructure | test>",
933
+ "stability": "<stable | experimental | deprecated>",
934
+ "seeAlso": "<newline-separated list: filename (reason). 2-4 entries max. Empty string if no meaningful cross-references.>",
935
+ "tags": "<comma-separated relevant tags>"
936
+ }`
937
+ }
938
+
939
+
940
+
941
+
942
+
943
+
944
+
945
+
946
+
947
+
948
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_buildmoduleheaderprompt_1784235266"]
949
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_buildchunkprompt_1784235266" type="function" identity="buildchunkprompt" parent="none"]
950
+ // CIL[DOC-MACRO purpose="Implements buildchunkprompt logic in cortex.functions.custom_cil-doc"]
951
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute buildchunkprompt and return its computed result"]
952
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
953
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
954
+ // CIL[DOC-MICRO logic_summary="Provides buildchunkprompt with buildChunkPrompt(d: any, code: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
955
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
956
+ // CIL[DOC-STABILITY stability="stable"]
957
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
958
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
959
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
960
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
961
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
962
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
963
+ function buildChunkPrompt(d: any, code: string): string {
964
+ const chunkType = d.chunk_type || 'function'
965
+ const chunkName = d.chunk_name || 'unknown'
966
+ const location = `${d.file_path || 'unknown'}:${d.line_start || 0}-${d.line_end || 0}`
967
+
968
+ return `You are documenting a ${chunkType} named "${chunkName}" at ${location}.
969
+
970
+ \`\`\`typescript
971
+ ${code}
972
+ \`\`\`
973
+
974
+ Rules:
975
+ - description: 1–2 sentences — what it does and why it exists in this module.
976
+ Do NOT start with "It achieves this by". Write it as a direct statement.
977
+ - macro: one sentence classifying WHAT this chunk IS and its primary responsibility.
978
+ Only write this if it adds information that description does not already convey.
979
+ Example: "Async resolver that maps an HTTP request to a typed Principal object."
980
+ If it would be the same sentence as description, return "".
981
+ - micro: one sentence on the SPECIFIC implementation mechanism — the algorithm,
982
+ branching strategy, data structure, or key external call pattern used.
983
+ Must be distinct from macro. If not meaningfully distinct, return "".
984
+ Example: "Checks headers in priority order (API key → cron → trigger → JWT),
985
+ delegating to a type-specific sub-resolver for each."
986
+ - inputSpec: one line per parameter: - name: Type (required|optional[|nullable]) — description.
987
+ Be precise about types (string, UUID, timestamp, not just "string").
988
+ Note enums if the field has a fixed value set.
989
+ Write "none" if the function takes no parameters.
990
+ - outputSpec: exact return type including Promise<T> if async. Add a brief shape
991
+ description if the return value is non-obvious.
992
+ - throws: only list errors the function explicitly throws that callers must handle.
993
+ Write "none" if the function never throws.
994
+ - side_effects: concrete observable effects (DB writes, RPC calls, file I/O,
995
+ external API calls). Write "none" if the function is pure.
996
+ - stability: stable | experimental | deprecated
997
+ - calls: comma-separated list of KEY named functions or external services this chunk
998
+ calls. Write the function name or service name only — not method chains.
999
+ BAD: "adminDb.from, adminDb.select, adminDb.eq, adminDb.single" (these are chained
1000
+ builder methods on one call — write "adminDb.from('schedules')" instead)
1001
+ GOOD: "adminDb.rpc('validate_machine_principal'), getClientIp"
1002
+ GOOD: "supabase.auth.getUser, adminDb.from('people')"
1003
+ Omit: String methods, Array methods, standard library, trivial getters.
1004
+ Write "none" if no significant external callees.
1005
+ - errorHandling: only write this if the error handling strategy is non-obvious —
1006
+ e.g. "returns ANONYMOUS_PRINCIPAL on auth failure rather than throwing".
1007
+ Write "" if it simply throws or returns null on error.
1008
+ - calledBy: your best guess at likely callers or entry points. For RAG use only.
1009
+ - complexity: simple | moderate | complex
1010
+ - tags: comma-separated relevant tags
1011
+
1012
+ Respond ONLY with a JSON object (no markdown, no commentary):
1013
+ {
1014
+ "description": "<1-2 direct sentences>",
1015
+ "macro": "<classification sentence, or empty string>",
1016
+ "micro": "<mechanism sentence distinct from macro, or empty string>",
1017
+ "inputSpec": "<newline-separated param lines, or 'none'>",
1018
+ "outputSpec": "<return type and shape>",
1019
+ "throws": "<ErrorType — condition, or 'none'>",
1020
+ "side_effects": "<effects or 'none'>",
1021
+ "stability": "<stable | experimental | deprecated>",
1022
+ "calls": "<key callees or 'none'>",
1023
+ "errorHandling": "<non-obvious strategy or empty string>",
1024
+ "calledBy": "<likely callers or 'unknown'>",
1025
+ "complexity": "<simple | moderate | complex>",
1026
+ "tags": "<comma-separated tags>"
1027
+ }`
1028
+ }
1029
+
1030
+
1031
+
1032
+
1033
+
1034
+
1035
+
1036
+
1037
+
1038
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_buildchunkprompt_1784235266"]
1039
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_callllm_1784235266" type="function" identity="callllm" parent="none"]
1040
+ // CIL[DOC-MACRO purpose="Implements callllm logic in cortex.functions.custom_cil-doc"]
1041
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute callllm and return its computed result"]
1042
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
1043
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
1044
+ // CIL[DOC-MICRO logic_summary="Provides callllm with callLLM(prompt: string, model: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
1045
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1046
+ // CIL[DOC-STABILITY stability="stable"]
1047
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
1048
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
1049
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
1050
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
1051
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
1052
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
1053
+ async function callLLM(prompt: string, model: string): Promise<string> {
1054
+ const j = await callOpenAIChat(undefined, [
1055
+ {
1056
+ role: 'system',
1057
+ content: 'You are a code documentation assistant. You extract structured contracts from source code. Always respond with valid JSON only.',
1058
+ },
1059
+ { role: 'user', content: prompt },
1060
+ ], model, {
1061
+ temperature: 0.2,
1062
+ max_tokens: 800,
1063
+ response_format: { type: 'json_object' }
1064
+ })
1065
+ return j.choices?.[0]?.message?.content?.trim() || '{}'
1066
+ }
1067
+
1068
+
1069
+
1070
+
1071
+
1072
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_callllm_1784235266"]
1073
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_parsedocresponse_1784235266" type="function" identity="parsedocresponse" parent="none"]
1074
+ // CIL[DOC-MACRO purpose="Implements parsedocresponse logic in cortex.functions.custom_cil-doc"]
1075
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute parsedocresponse and return its computed result"]
1076
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
1077
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
1078
+ // CIL[DOC-MICRO logic_summary="Provides parsedocresponse with parseDocResponse(raw: string inputs, handling internal flow and returning a result" notable_decisions="[]"]
1079
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1080
+ // CIL[DOC-STABILITY stability="stable"]
1081
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
1082
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
1083
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
1084
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
1085
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
1086
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
1087
+ function parseDocResponse(raw: string): Record<string, string> {
1088
+ try {
1089
+
1090
+ let cleaned = raw.trim()
1091
+ if (cleaned.startsWith('```')) {
1092
+ cleaned = cleaned.replace(/^```[a-zA-Z0-9]*\n?/, '').replace(/\n?```$/, '').trim()
1093
+ }
1094
+ const parsed = JSON.parse(cleaned)
1095
+ return {
1096
+ description: String(parsed.description || parsed.macro || '').slice(0, 1000),
1097
+ macro: String(parsed.macro || '').slice(0, 500),
1098
+ micro: String(parsed.micro || '').slice(0, 500),
1099
+ input_spec: String(parsed.inputSpec || parsed.input_spec || '').slice(0, 2000),
1100
+ output_spec: String(parsed.outputSpec || parsed.output_spec || '').slice(0, 500),
1101
+ throws: String(parsed.throws || '').slice(0, 500),
1102
+ side_effects:String(parsed.sideEffects || parsed.side_effects|| '').slice(0, 500),
1103
+ stability: ['stable', 'internal', 'experimental', 'deprecated'].includes(parsed.stability)
1104
+ ? parsed.stability : 'internal',
1105
+ called_by: String(parsed.calledBy || parsed.called_by || '').slice(0, 500),
1106
+ calls: String(parsed.calls || '').slice(0, 500),
1107
+ tags: String(parsed.tags || '').slice(0, 500),
1108
+ complexity: ['simple', 'moderate', 'complex'].includes(parsed.complexity)
1109
+ ? parsed.complexity : 'moderate',
1110
+ error_handling: String(parsed.errorHandling || parsed.error_handling || '').slice(0, 500),
1111
+ module: String(parsed.module || '').slice(0, 100),
1112
+ audience: ['internal', 'external', 'both'].includes(parsed.audience)
1113
+ ? parsed.audience : 'both',
1114
+ layer: ['shared-core', 'app-specific', 'infrastructure', 'test'].includes(parsed.layer)
1115
+ ? parsed.layer : 'app-specific',
1116
+ see_also: String(parsed.seeAlso || parsed.see_also || '').slice(0, 1000),
1117
+ }
1118
+ } catch {
1119
+ return {}
1120
+ }
1121
+ }
1122
+
1123
+
1124
+
1125
+
1126
+
1127
+
1128
+
1129
+
1130
+
1131
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_parsedocresponse_1784235266"]
1132
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_hasmeaningfulllmfields_1784235266" type="function" identity="hasmeaningfulllmfields" parent="none"]
1133
+ // CIL[DOC-MACRO purpose="Implements hasmeaningfulllmfields logic in cortex.functions.custom_cil-doc"]
1134
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute hasmeaningfulllmfields and return its computed result"]
1135
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
1136
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
1137
+ // CIL[DOC-MICRO logic_summary="Provides hasmeaningfulllmfields with hasMeaningfulLlmFields(fields: Record<string, string> inputs, handling internal flow and returning a result" notable_decisions="[]"]
1138
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1139
+ // CIL[DOC-STABILITY stability="stable"]
1140
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
1141
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
1142
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
1143
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
1144
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
1145
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
1146
+ function hasMeaningfulLlmFields(fields: Record<string, string>): boolean {
1147
+ const meaningfulKeys = ['description', 'macro', 'micro', 'input_spec', 'output_spec']
1148
+ return meaningfulKeys.some(k => (fields[k] || '').trim() !== '')
1149
+ }
1150
+
1151
+
1152
+
1153
+
1154
+
1155
+
1156
+
1157
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_hasmeaningfulllmfields_1784235266"]
1158
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_normalizedocfields_1784235266" type="function" identity="normalizedocfields" parent="none"]
1159
+ // CIL[DOC-MACRO purpose="Implements normalizedocfields logic in cortex.functions.custom_cil-doc"]
1160
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute normalizedocfields and return its computed result"]
1161
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
1162
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
1163
+ // CIL[DOC-MICRO logic_summary="Provides normalizedocfields with normalizeDocFields(fields: Record<string, string>, chunk: any inputs, handling internal flow and returning a result" notable_decisions="[]"]
1164
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1165
+ // CIL[DOC-STABILITY stability="stable"]
1166
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
1167
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
1168
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
1169
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
1170
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
1171
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
1172
+ function normalizeDocFields(fields: Record<string, string>, chunk: any): Record<string, string> {
1173
+ const d = chunk.data || {}
1174
+ const isModuleHeader = d.chunk_type === 'module_header'
1175
+ const code = d.code_content || ''
1176
+ const chunkName = d.chunk_name || chunk.title || ''
1177
+ const layer = d.layer || (isModuleHeader ? 'shared-core' : 'app-specific')
1178
+
1179
+ const normalized = { ...fields }
1180
+
1181
+ if (isModuleHeader) {
1182
+ if (!normalized.module) normalized.module = moduleNameFromPath(d.file_path || chunkName)
1183
+ if (!normalized.audience) normalized.audience = 'both'
1184
+ if (!normalized.layer) normalized.layer = layer
1185
+ if (!normalized.description) normalized.description = normalized.macro || `${chunkName} module setup and imports.`
1186
+ if (!normalized.stability) normalized.stability = 'stable'
1187
+ if (!normalized.see_also) normalized.see_also = ''
1188
+ } else {
1189
+ const chunkType = d.chunk_type || 'symbol'
1190
+ const isCallable = !['interface', 'type', 'enum', 'constant'].includes(chunkType)
1191
+
1192
+ if (!normalized.description) normalized.description = normalized.macro || `${chunkName} ${chunkType}.`
1193
+
1194
+
1195
+
1196
+
1197
+ const macroFromLlm = fields.macro
1198
+ const microFromLlm = fields.micro
1199
+ if (macroFromLlm === undefined || macroFromLlm === null) {
1200
+ normalized.macro = normalized.description.split(/(?<=[.!?])\s+/)[0] || normalized.description
1201
+ }
1202
+ if (microFromLlm === undefined || microFromLlm === null) {
1203
+ normalized.micro = ''
1204
+ }
1205
+
1206
+
1207
+
1208
+ if (!normalized.input_spec) {
1209
+ if (isCallable) {
1210
+ const sigMatch = code.match(/(?:function|const|let|var)\s+\w+\s*\(([^)]*)\)|(?:async\s+)?function\s*\(([^)]*)\)/)
1211
+ const paramStr = sigMatch?.[1] || sigMatch?.[2] || ''
1212
+ const params = paramStr.split(',').map(s => s.trim()).filter(Boolean).map(p => {
1213
+ const [name, type] = p.split(/[:=]/).map(s => s.trim())
1214
+ const optional = p.includes('?')
1215
+ return `- ${name.replace(/\?$/, '')}: ${type || 'any'} (${optional ? 'optional' : 'required'})`
1216
+ })
1217
+ normalized.input_spec = params.length ? params.join('\n') : 'none'
1218
+ } else {
1219
+ normalized.input_spec = 'none'
1220
+ }
1221
+ }
1222
+
1223
+
1224
+ if (!normalized.output_spec) {
1225
+ if (!isCallable) {
1226
+ normalized.output_spec = chunkName
1227
+ } else {
1228
+
1229
+ const returnMatch = code.match(/\)\s*:\s*(Promise<[^>]+>|[A-Za-z0-9_<>|[\]{}?\s]+)\s*(?:\{|=>)/)
1230
+ normalized.output_spec = returnMatch ? returnMatch[1].trim() : 'void'
1231
+ }
1232
+ }
1233
+
1234
+ if (!normalized.side_effects) normalized.side_effects = 'none'
1235
+ if (!normalized.stability) normalized.stability = 'stable'
1236
+ if (!normalized.tags) normalized.tags = chunkType
1237
+ if (!normalized.complexity) normalized.complexity = 'moderate'
1238
+ if (!normalized.error_handling) normalized.error_handling = ''
1239
+ if (!normalized.called_by) normalized.called_by = 'unknown'
1240
+ if (!normalized.calls) normalized.calls = 'unknown'
1241
+ }
1242
+
1243
+ return normalized
1244
+ }
1245
+
1246
+
1247
+
1248
+
1249
+
1250
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_normalizedocfields_1784235266"]
1251
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_documentchunk_1784235266" type="function" identity="documentchunk" parent="none"]
1252
+ // CIL[DOC-MACRO purpose="Implements documentchunk logic in cortex.functions.custom_cil-doc"]
1253
+ // CIL[DOC-RESPONSIBILITY responsibility="Execute documentchunk and return its computed result"]
1254
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
1255
+ // CIL[DOC-CONTRACT inputs="none" outputs="return value from function execution" errors="throws on invalid input or runtime failure" side_effects="none"]
1256
+ // CIL[DOC-MICRO logic_summary="Provides documentchunk with documentChunk( inputs, handling internal flow and returning a result" notable_decisions="[]"]
1257
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1258
+ // CIL[DOC-STABILITY stability="stable"]
1259
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
1260
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
1261
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
1262
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
1263
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
1264
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
1265
+ async function documentChunk(
1266
+ ctx: any,
1267
+ chunk: any,
1268
+ model: string,
1269
+ force: boolean,
1270
+ repoPath?: string
1271
+ ): Promise<{ success: boolean; fields_set: string[]; error?: string; skipped?: boolean; updatedChunk?: any; validation_errors?: string[] }> {
1272
+ if (!force && !needsDocumentation(chunk)) {
1273
+ return { success: true, fields_set: [], skipped: true, updatedChunk: chunk }
1274
+ }
1275
+
1276
+ const d = chunk.data || {}
1277
+ if (!d.code_content && !d.chunk_name) {
1278
+ return { success: false, fields_set: [], error: 'No code content to document' }
1279
+ }
1280
+
1281
+ const prompt = buildDocPrompt(chunk)
1282
+
1283
+ let raw: string
1284
+ try {
1285
+ raw = await callLLM(prompt, model)
1286
+ } catch (err) {
1287
+ return { success: false, fields_set: [], error: err instanceof Error ? err.message : String(err) }
1288
+ }
1289
+
1290
+ const rawFields = parseDocResponse(raw)
1291
+ const hadLlmFields = hasMeaningfulLlmFields(rawFields)
1292
+
1293
+
1294
+
1295
+
1296
+ const fields = normalizeDocFields(rawFields, chunk)
1297
+
1298
+
1299
+ const toWrite: Record<string, string> = {}
1300
+ for (const [k, v] of Object.entries(fields)) {
1301
+ if (force || !d[k]) toWrite[k] = v
1302
+ }
1303
+
1304
+ if (!Object.keys(toWrite).length) {
1305
+ return { success: true, fields_set: [], skipped: true, updatedChunk: chunk }
1306
+ }
1307
+
1308
+ const updatedData = { ...d, ...toWrite, doc_confidence: 'ai_generated', doc_fallback: !hadLlmFields }
1309
+ const updatedChunk = { ...chunk, data: updatedData }
1310
+
1311
+
1312
+ const validationErrors = validateChunkDocs(updatedChunk)
1313
+ if (validationErrors.length > 0) {
1314
+ return { success: false, fields_set: [], error: `Validation failed: ${validationErrors.join(', ')}`, validation_errors: validationErrors, updatedChunk }
1315
+ }
1316
+
1317
+ const updateCtx = { ...ctx, query: { ...ctx.query, entity: 'items', id: chunk.id } }
1318
+ try {
1319
+ await adminUpdate(updateCtx, { data: updatedData })
1320
+ } catch (updateError: any) {
1321
+ return { success: false, fields_set: [], error: updateError.message }
1322
+ }
1323
+
1324
+
1325
+ if (repoPath) {
1326
+ writeJsDocToSource(updatedChunk, repoPath)
1327
+ }
1328
+
1329
+ return { success: true, fields_set: Object.keys(toWrite), updatedChunk }
1330
+ }
1331
+
1332
+
1333
+
1334
+
1335
+
1336
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_documentchunk_1784235266"]
1337
+ // CIL[BEGIN chunk_id="custom_apps_cortex_functions_custom_cil_doc_handler_1784235266" type="variable" identity="handler" parent="none"]
1338
+ // CIL[DOC-MACRO purpose="Defines handler configuration or state in cortex.functions.custom_cil-doc"]
1339
+ // CIL[DOC-RESPONSIBILITY responsibility="Hold the value and default configuration for handler"]
1340
+ // CIL[DOC-CONTEXT module="cortex.functions.custom_cil-doc" layer="function" related_files="[]"]
1341
+ // CIL[DOC-CONTRACT inputs="none" outputs="value of handler" errors="none" side_effects="none"]
1342
+ // CIL[DOC-MICRO logic_summary="Declares handler with initial value or constant binding used by cortex.functions.custom_cil-doc" notable_decisions="[]"]
1343
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
1344
+ // CIL[DOC-STABILITY stability="stable"]
1345
+ // CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: none."]
1346
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
1347
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
1348
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
1349
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
1350
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
1351
+ export const handler = createHandler(async (ctx, body) => {
1352
+ const action = ctx.query?.action
1353
+
1354
+
1355
+ if (action === 'gap_report') {
1356
+ const projectId = ctx.query?.project_id || body?.project_id
1357
+ if (!projectId) throw new Error('project_id is required')
1358
+
1359
+ const chunks = await loadAllChunks(projectId)
1360
+
1361
+ const undocumented = chunks.filter(needsDocumentation)
1362
+ const documented = chunks.filter(c => !needsDocumentation(c))
1363
+ const aiGenerated = documented.filter(c => c.data?.doc_confidence === 'ai_generated')
1364
+ const humanVerified= documented.filter(c => c.data?.doc_confidence === 'human_verified')
1365
+
1366
+ return {
1367
+ project_id: projectId,
1368
+ total_chunks: chunks.length,
1369
+ undocumented_count: undocumented.length,
1370
+ documented_count: documented.length,
1371
+ ai_generated_count: aiGenerated.length,
1372
+ human_verified_count: humanVerified.length,
1373
+ coverage_pct: chunks.length
1374
+ ? Math.round((documented.length / chunks.length) * 100) : 0,
1375
+ undocumented: undocumented.slice(0, 100).map(c => ({
1376
+ id: c.id,
1377
+ chunk_name: c.data?.chunk_name || c.title,
1378
+ file_path: c.data?.file_path || '',
1379
+ chunk_type: c.data?.chunk_type || '',
1380
+ line_count: (c.data?.line_end || 0) - (c.data?.line_start || 0) + 1,
1381
+ token_count: c.data?.token_count || 0,
1382
+ })),
1383
+ }
1384
+ }
1385
+
1386
+
1387
+ if (action === 'estimate') {
1388
+ const projectId = ctx.query?.project_id || body?.project_id
1389
+ const model = ctx.query?.model || body?.model || DEFAULT_MODEL
1390
+ const modelPrices = body?.model_prices || MODEL_PRICES[model] || MODEL_PRICES[DEFAULT_MODEL]
1391
+ const filePath = ctx.query?.file_path || body?.file_path
1392
+
1393
+ if (!projectId) throw new Error('project_id is required')
1394
+
1395
+ const chunks = await loadAllChunks(projectId, filePath)
1396
+ const toDocument = chunks.filter(needsDocumentation)
1397
+
1398
+ let totalInputTokens = 0
1399
+ const breakdown: any[] = []
1400
+
1401
+ for (const chunk of toDocument) {
1402
+ const prompt = buildDocPrompt(chunk)
1403
+ const inputTokens = estimateTokens(prompt) + SYSTEM_PROMPT_OVERHEAD_TOKENS
1404
+ totalInputTokens += inputTokens
1405
+ breakdown.push({
1406
+ chunk_name: chunk.data?.chunk_name || chunk.title,
1407
+ file_path: chunk.data?.file_path || '',
1408
+ input_tokens: inputTokens,
1409
+ })
1410
+ }
1411
+
1412
+ const totalOutputTokens = toDocument.length * ESTIMATED_OUTPUT_TOKENS_PER_CHUNK
1413
+ const totalTokens = totalInputTokens + totalOutputTokens
1414
+
1415
+ const inputCostUsd = (totalInputTokens / 1_000_000) * modelPrices.input_per_1m
1416
+ const outputCostUsd = (totalOutputTokens / 1_000_000) * modelPrices.output_per_1m
1417
+ const totalCostUsd = inputCostUsd + outputCostUsd
1418
+
1419
+ return {
1420
+ project_id: projectId,
1421
+ model,
1422
+ file_path: filePath || null,
1423
+ model_prices: modelPrices,
1424
+ chunks_to_document: toDocument.length,
1425
+ total_chunks: chunks.length,
1426
+ already_documented: chunks.length - toDocument.length,
1427
+ estimated_input_tokens: totalInputTokens,
1428
+ estimated_output_tokens: totalOutputTokens,
1429
+ estimated_total_tokens: totalTokens,
1430
+ estimated_cost_usd: parseFloat(totalCostUsd.toFixed(4)),
1431
+ estimated_cost_usd_breakdown: {
1432
+ input: parseFloat(inputCostUsd.toFixed(4)),
1433
+ output: parseFloat(outputCostUsd.toFixed(4)),
1434
+ },
1435
+
1436
+ top_chunks_by_cost: breakdown
1437
+ .sort((a, b) => b.input_tokens - a.input_tokens)
1438
+ .slice(0, 20),
1439
+ }
1440
+ }
1441
+
1442
+
1443
+ if (action === 'doc_chunk') {
1444
+ const chunkId = body?.chunk_id || ctx.query?.chunk_id
1445
+ const model = body?.model || ctx.query?.model || DEFAULT_MODEL
1446
+ const force = body?.force ?? false
1447
+ if (!chunkId) throw new Error('chunk_id is required')
1448
+
1449
+ const { data: chunk, error } = await adminDb
1450
+ .from('items')
1451
+ .select('id, title, data')
1452
+ .eq('id', chunkId)
1453
+ .maybeSingle()
1454
+
1455
+ if (error || !chunk) throw new Error(`Chunk not found: ${chunkId}`)
1456
+
1457
+ const projectId = chunk.data?.project_id
1458
+ let repoPath = ''
1459
+ if (projectId) {
1460
+ const { data: projectItem } = await adminDb.from('items').select('data').eq('id', projectId).maybeSingle()
1461
+ repoPath = projectItem?.data?.repo_path || ''
1462
+ }
1463
+
1464
+ const result = await documentChunk(ctx, chunk, model, force, repoPath)
1465
+ return { chunk_id: chunkId, chunk_name: chunk.data?.chunk_name || chunk.title, ...result }
1466
+ }
1467
+
1468
+
1469
+
1470
+
1471
+ if (action === 'validate') {
1472
+ const projectId = ctx.query?.project_id || body?.project_id
1473
+ const filePath = ctx.query?.file_path || body?.file_path
1474
+ if (!projectId) throw new Error('project_id is required')
1475
+
1476
+ const chunks = await loadAllChunks(projectId, filePath)
1477
+ const invalid: any[] = []
1478
+ for (const chunk of chunks) {
1479
+ const errors = validateChunkDocs(chunk)
1480
+ if (errors.length > 0) {
1481
+ invalid.push({
1482
+ chunk_id: chunk.id,
1483
+ chunk_name: chunk.data?.chunk_name || chunk.title,
1484
+ file_path: chunk.data?.file_path || '',
1485
+ chunk_type: chunk.data?.chunk_type || '',
1486
+ errors,
1487
+ })
1488
+ }
1489
+ }
1490
+
1491
+ return {
1492
+ project_id: projectId,
1493
+ file_path: filePath || null,
1494
+ total_chunks: chunks.length,
1495
+ valid_chunks: chunks.length - invalid.length,
1496
+ invalid_chunks: invalid.length,
1497
+ invalid,
1498
+ }
1499
+ }
1500
+
1501
+
1502
+
1503
+
1504
+
1505
+
1506
+
1507
+
1508
+
1509
+
1510
+
1511
+
1512
+
1513
+ if (action === 'document') {
1514
+ const projectId = body?.project_id
1515
+ if (!projectId) throw new Error('project_id is required')
1516
+
1517
+ const model = body?.model || DEFAULT_MODEL
1518
+ const dryRun = body?.dry_run ?? false
1519
+ const force = body?.force ?? false
1520
+ const chunkIds: string[] | undefined = body?.chunk_ids
1521
+ const filePath: string | undefined = body?.file_path
1522
+ const pageLimit = Math.min(parseInt(body?.limit || '5', 10), 100)
1523
+ const pageOffset= parseInt(body?.offset || '0', 10)
1524
+ const concurrency = Math.min(parseInt(body?.concurrency || '20', 10), 30)
1525
+
1526
+
1527
+ const { data: projectItem } = await adminDb.from('items').select('id, data').eq('id', projectId).maybeSingle()
1528
+ const selectedPaths: string[] = body?.selected_paths || projectItem?.data?.selected_paths || []
1529
+ const fileTree = (projectItem?.data?.file_tree as FileTreeNode) || null
1530
+
1531
+
1532
+
1533
+ let stableList: any[]
1534
+ if (chunkIds?.length) {
1535
+ let q = adminDb
1536
+ .from('items')
1537
+ .select('id, title, data')
1538
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
1539
+ .filter('data->>project_id', 'eq', projectId)
1540
+ .eq('is_active', true)
1541
+ .in('id', chunkIds)
1542
+ .order('id')
1543
+ if (filePath) q = q.filter('data->>file_path', 'eq', filePath)
1544
+ const { data, error } = await q
1545
+ if (error) throw new Error(`Failed to load chunks: ${error.message}`)
1546
+ stableList = data || []
1547
+ } else if (selectedPaths.length > 0 && !filePath) {
1548
+
1549
+ stableList = await loadPendingChunks(projectId, selectedPaths, 'pass2_complete')
1550
+ } else {
1551
+ stableList = await loadAllChunks(projectId, filePath)
1552
+ }
1553
+
1554
+ const totalChunks = stableList.length
1555
+ const pageChunks = stableList.slice(pageOffset, pageOffset + pageLimit)
1556
+
1557
+
1558
+ const allToDocument = force ? pageChunks : pageChunks.filter(needsDocumentation)
1559
+
1560
+ const totalToDocument = force
1561
+ ? stableList.length
1562
+ : stableList.filter(needsDocumentation).length
1563
+
1564
+ if (dryRun) {
1565
+ return {
1566
+ dry_run: true,
1567
+ project_id: projectId,
1568
+ model,
1569
+ total_to_document: totalToDocument,
1570
+ page_offset: pageOffset,
1571
+ page_limit: pageLimit,
1572
+ page_chunks: pageChunks.length,
1573
+ chunk_names: pageChunks.map(c => c.data?.chunk_name || c.title),
1574
+ }
1575
+ }
1576
+
1577
+
1578
+
1579
+ const results: Array<{ chunk: any; fields: Record<string, string> | null; is_fallback?: boolean; error?: string }> = []
1580
+
1581
+ for (let i = 0; i < allToDocument.length; i += concurrency) {
1582
+ const subBatch = allToDocument.slice(i, i + concurrency)
1583
+ const subResults = await Promise.all(subBatch.map(async chunk => {
1584
+ const d = chunk.data || {}
1585
+ if (!d.code_content && !d.chunk_name) {
1586
+ return { chunk, fields: null, error: 'No code content' }
1587
+ }
1588
+ const prompt = buildDocPrompt(chunk)
1589
+ try {
1590
+ const raw = await callLLM(prompt, model)
1591
+ const rawFields = parseDocResponse(raw)
1592
+ const hadLlmFields = hasMeaningfulLlmFields(rawFields)
1593
+
1594
+
1595
+ const fields = normalizeDocFields(rawFields, chunk)
1596
+ return { chunk, fields, is_fallback: !hadLlmFields, error: undefined }
1597
+ } catch (err) {
1598
+
1599
+ const fields = normalizeDocFields({}, chunk)
1600
+ return { chunk, fields, is_fallback: true, error: undefined }
1601
+ }
1602
+ }))
1603
+ results.push(...subResults)
1604
+ }
1605
+
1606
+
1607
+ let documented = 0, validated = 0, skipped = 0, failed = 0
1608
+ const errors: string[] = []
1609
+ const updatedChunks: any[] = []
1610
+
1611
+ await Promise.all(results.map(async ({ chunk, fields, is_fallback, error: llmError }) => {
1612
+ if (!fields) {
1613
+ if (llmError) { failed++; errors.push(`${chunk.data?.chunk_name || chunk.id}: ${llmError}`) }
1614
+ else skipped++
1615
+ return
1616
+ }
1617
+ const d = chunk.data || {}
1618
+ const toWrite: Record<string, string> = {}
1619
+ for (const [k, v] of Object.entries(fields)) {
1620
+ if (force || !d[k]) toWrite[k] = v
1621
+ }
1622
+ if (!Object.keys(toWrite).length) { skipped++; return }
1623
+
1624
+ const updatedData = { ...d, ...toWrite, doc_confidence: 'ai_generated', doc_fallback: !!is_fallback }
1625
+ const updatedChunk = { ...chunk, data: updatedData }
1626
+
1627
+
1628
+ const validationErrors = validateChunkDocs(updatedChunk)
1629
+ const chunkUpdateCtx = { ...ctx, query: { ...ctx.query, entity: 'items', id: chunk.id } }
1630
+ if (validationErrors.length > 0) {
1631
+ failed++
1632
+ errors.push(`${chunk.data?.chunk_name || chunk.id}: ${validationErrors.join(', ')}`)
1633
+ await adminUpdate(chunkUpdateCtx, { data: { ...updatedData, doc_validation_errors: validationErrors } })
1634
+ .catch(() => { /* non-fatal — don't mask original validation error */ })
1635
+ return
1636
+ }
1637
+
1638
+ try {
1639
+ await adminUpdate(chunkUpdateCtx, { data: updatedData })
1640
+ } catch (updateError: any) {
1641
+ failed++; errors.push(`${chunk.data?.chunk_name || chunk.id}: ${updateError.message}`)
1642
+ return
1643
+ }
1644
+ {
1645
+ documented++; validated++; updatedChunks.push(updatedChunk)
1646
+ }
1647
+ }))
1648
+
1649
+
1650
+
1651
+ if (updatedChunks.length > 0) {
1652
+ const { data: projectItem } = await adminDb.from('items').select('id, data').eq('id', projectId).maybeSingle()
1653
+ const repoPath = projectItem?.data?.repo_path || ''
1654
+ if (repoPath) {
1655
+ const byFile = new Map<string, any[]>()
1656
+ for (const chunk of updatedChunks) {
1657
+ const relPath = chunk.data?.file_path
1658
+ if (!relPath) continue
1659
+ if (!byFile.has(relPath)) byFile.set(relPath, [])
1660
+ byFile.get(relPath)!.push(chunk)
1661
+ }
1662
+ for (const [relPath, chunks] of byFile) {
1663
+ const absPath = path.join(repoPath, relPath)
1664
+ if (!fs.existsSync(absPath)) continue
1665
+ const content = fs.readFileSync(absPath, 'utf-8')
1666
+ const fileLines = content.split('\n')
1667
+ const newLines = [...fileLines]
1668
+
1669
+
1670
+
1671
+ const markerMap = findChunkStartMarkers(newLines)
1672
+
1673
+
1674
+ const sorted = [...chunks]
1675
+ .map(c => ({ chunk: c, markerIdx: markerMap.get((c.data?.chunk_name || c.title).trim().toLowerCase()) }))
1676
+ .filter((item): item is { chunk: any; markerIdx: number } => item.markerIdx !== undefined)
1677
+ .sort((a, b) => b.markerIdx - a.markerIdx)
1678
+ const missed = chunks
1679
+ .filter(c => markerMap.get((c.data?.chunk_name || c.title).trim().toLowerCase()) === undefined)
1680
+ .map(c => c.data?.chunk_name || c.title)
1681
+ if (missed.length > 0) {
1682
+ errors.push(`Write-back: could not find markers for ${missed.join(', ')} in ${relPath}`)
1683
+ }
1684
+ for (const { chunk, markerIdx } of sorted) {
1685
+ const jsDoc = buildJsDoc(chunk)
1686
+ if (!jsDoc) {
1687
+ errors.push(`Write-back: no JSDoc built for ${chunk.data?.chunk_name || chunk.title}`)
1688
+ continue
1689
+ }
1690
+ const existing = findExistingCilJsDoc(newLines, markerIdx)
1691
+ if (existing) {
1692
+ newLines.splice(existing.start, existing.end - existing.start + 1, jsDoc)
1693
+ } else {
1694
+
1695
+ newLines.splice(markerIdx + 1, 0, jsDoc)
1696
+ }
1697
+ }
1698
+ fs.writeFileSync(absPath, newLines.join('\n'), 'utf-8')
1699
+ }
1700
+ }
1701
+ }
1702
+
1703
+
1704
+ const affectedFileIds = [...new Set((force ? pageChunks : allToDocument).map(c => c.data?.file_id).filter(Boolean))]
1705
+ for (const fileId of affectedFileIds) {
1706
+ await maybeAdvanceFileToPass3(ctx, fileId, fileTree)
1707
+ }
1708
+ if (fileTree) {
1709
+ await saveProjectTree(ctx, projectId, fileTree, { last_ingested_at: new Date().toISOString() })
1710
+ }
1711
+
1712
+
1713
+ const nextOffset = pageOffset + pageLimit
1714
+ const isLastPage = nextOffset >= totalChunks
1715
+ if (isLastPage && documented > 0) {
1716
+ const { data: projectItem } = await adminDb.from('items').select('id, data').eq('id', projectId).maybeSingle()
1717
+ if (projectItem) {
1718
+ const prices = MODEL_PRICES[model] || MODEL_PRICES[DEFAULT_MODEL]
1719
+ const approxCost = (documented * (ESTIMATED_OUTPUT_TOKENS_PER_CHUNK + 800) / 1_000_000) * ((prices.input_per_1m + prices.output_per_1m) / 2)
1720
+ const projUpdateCtx = { ...ctx, query: { ...ctx.query, entity: 'items', id: projectId } }
1721
+ await adminUpdate(projUpdateCtx, {
1722
+ data: { ...projectItem.data, total_ingestion_cost_usd: (projectItem.data?.total_ingestion_cost_usd || 0) + approxCost, last_ingested_at: new Date().toISOString() },
1723
+ }).catch(() => { /* non-fatal */ })
1724
+ }
1725
+ }
1726
+
1727
+ return {
1728
+ project_id: projectId,
1729
+ model,
1730
+ total_to_document: totalToDocument,
1731
+ total_chunks: totalChunks,
1732
+ page_offset: pageOffset,
1733
+ page_limit: pageLimit,
1734
+ documented,
1735
+ validated,
1736
+ skipped,
1737
+ failed,
1738
+ errors: errors.slice(0, 20),
1739
+
1740
+ has_more: nextOffset < totalChunks,
1741
+ next_offset: nextOffset < totalChunks ? nextOffset : null,
1742
+ done_total: pageOffset + pageChunks.length,
1743
+ }
1744
+ }
1745
+
1746
+ throw new Error(`Unknown action: ${action}. Valid: estimate, gap_report, document, doc_chunk, validate`)
1747
+ })
1748
+
1749
+
1750
+
1751
+
1752
+ // CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_doc_handler_1784235266"]