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,318 @@
1
+ import { createHandler } from './_shared/middleware'
2
+ import { adminDb } from './_shared/db'
3
+
4
+ const PIPELINE_STEPS = {
5
+ 4: { name: 'chunk', prerequisites: [], target_status: '4-chunked' },
6
+ 5: { name: 'document', prerequisites: [4], target_status: '5-documented' },
7
+ 6: { name: 'embed-1st-pass', prerequisites: [5], target_status: '6-embedded' },
8
+ 7: { name: 'map-1st-pass', prerequisites: [6], target_status: '7-mapped' },
9
+ 8: { name: 'enrich', prerequisites: [7], target_status: '8-enriched' },
10
+ 9: { name: 'embed-2nd-pass', prerequisites: [8], target_status: '9-embedded' },
11
+ 10: { name: 'map-2nd-pass', prerequisites: [9], target_status: '10-mapped' },
12
+ } as const
13
+
14
+ type PipelineStep = keyof typeof PIPELINE_STEPS
15
+
16
+ async function getProject(project_id: string) {
17
+ const { data: project } = await adminDb.from('items').select('data')
18
+ .eq('id', project_id).maybeSingle()
19
+ if (!project) throw new Error(`Project not found: ${project_id}`)
20
+ return project
21
+ }
22
+
23
+ function getCompletedSteps(status: string): PipelineStep[] {
24
+ const stepMap: Record<string, PipelineStep> = {
25
+ '4-chunked': 4,
26
+ '5-documented': 5,
27
+ '6-embedded': 6,
28
+ '7-mapped': 7,
29
+ '7.5-selected': 7,
30
+ '8-enriched': 8,
31
+ '9-embedded': 9,
32
+ '10-mapped': 10,
33
+ }
34
+ const completed: PipelineStep[] = []
35
+ for (const [statusName, stepNum] of Object.entries(stepMap)) {
36
+ if (status === statusName) {
37
+ completed.push(stepNum)
38
+ }
39
+ }
40
+ return completed
41
+ }
42
+
43
+ function getReadySteps(status: string): PipelineStep[] {
44
+ const completed = getCompletedSteps(status)
45
+ const ready: PipelineStep[] = []
46
+ for (const [stepNum, stepDef] of Object.entries(PIPELINE_STEPS)) {
47
+ const num = parseInt(stepNum) as PipelineStep
48
+ if (stepDef.prerequisites.every(prereq => completed.includes(prereq))) {
49
+ ready.push(num)
50
+ }
51
+ }
52
+ return ready
53
+ }
54
+
55
+ function getBlockedSteps(status: string): PipelineStep[] {
56
+ const completed = getCompletedSteps(status)
57
+ const blocked: PipelineStep[] = []
58
+ for (const [stepNum, stepDef] of Object.entries(PIPELINE_STEPS)) {
59
+ const num = parseInt(stepNum) as PipelineStep
60
+ if (!stepDef.prerequisites.every(prereq => completed.includes(prereq))) {
61
+ blocked.push(num)
62
+ }
63
+ }
64
+ return blocked
65
+ }
66
+
67
+ function calculateProgress(status: string): number {
68
+ const completed = getCompletedSteps(status)
69
+ const totalSteps = Object.keys(PIPELINE_STEPS).length
70
+ return (completed.length / totalSteps) * 100
71
+ }
72
+
73
+ function getBlockingReasons(status: string, step: PipelineStep): string[] {
74
+ const completed = getCompletedSteps(status)
75
+ const reasons: string[] = []
76
+ for (const prereq of PIPELINE_STEPS[step].prerequisites) {
77
+ if (!completed.includes(prereq)) {
78
+ reasons.push(`Missing prerequisite step ${prereq} (${PIPELINE_STEPS[prereq].name})`)
79
+ }
80
+ }
81
+ return reasons
82
+ }
83
+
84
+ function getStepBlockingReasons(files: Array<[string, string]>, step: PipelineStep): string[] {
85
+ const blockingReasons: string[] = []
86
+ for (const [file_path, status] of files) {
87
+ const completed = getCompletedSteps(status)
88
+ if (!PIPELINE_STEPS[step].prerequisites.every(prereq => completed.includes(prereq))) {
89
+ for (const prereq of PIPELINE_STEPS[step].prerequisites) {
90
+ if (!completed.includes(prereq)) {
91
+ blockingReasons.push(`${file_path}: missing step ${prereq}`)
92
+ }
93
+ }
94
+ }
95
+ }
96
+ return [...new Set(blockingReasons)]
97
+ }
98
+
99
+ function getOptimalProcessingOrder(files: Array<[string, string]>): Array<{file_path: string, suggested_next_step: PipelineStep | null}> {
100
+ const fileStates = files.map(([file_path, status]) => ({
101
+ file_path,
102
+ status,
103
+ completed_steps: getCompletedSteps(status),
104
+ ready_for: getReadySteps(status)
105
+ }))
106
+ return fileStates
107
+ .sort((a, b) => {
108
+ if (a.ready_for.length !== b.ready_for.length) {
109
+ return b.ready_for.length - a.ready_for.length
110
+ }
111
+ return a.completed_steps.length - b.completed_steps.length
112
+ })
113
+ .map(({ file_path, ready_for }) => ({
114
+ file_path,
115
+ suggested_next_step: ready_for[0] || null
116
+ }))
117
+ }
118
+
119
+ async function getPipelineStatus(project_id: string) {
120
+ const project = await getProject(project_id)
121
+ const fileStatuses: Record<string, string> = project.data?.file_statuses || {}
122
+ const files = Object.entries(fileStatuses).map(([file_path, status]) => ({
123
+ file_path,
124
+ current_status: status,
125
+ completed_steps: getCompletedSteps(status),
126
+ ready_for: getReadySteps(status),
127
+ blocked_by: getBlockedSteps(status),
128
+ progress_percentage: calculateProgress(status)
129
+ }))
130
+ const stepSummary: Record<PipelineStep, { completed: number; pending: number; in_progress: number }> = {} as any
131
+ for (const step of Object.keys(PIPELINE_STEPS) as PipelineStep[]) {
132
+ const stepNum = step as unknown as number
133
+ stepSummary[step] = {
134
+ completed: files.filter(f => f.completed_steps.includes(stepNum)).length,
135
+ pending: files.filter(f => f.ready_for.includes(stepNum)).length,
136
+ in_progress: files.filter(f => f.current_status === PIPELINE_STEPS[step].target_status).length
137
+ }
138
+ }
139
+ const overallProgress = files.reduce((sum, file) => sum + file.progress_percentage, 0) / files.length
140
+ return {
141
+ project_id,
142
+ files,
143
+ step_summary: stepSummary,
144
+ overall_progress: Math.round(overallProgress)
145
+ }
146
+ }
147
+
148
+ async function getFilesReadyForStep(project_id: string, step: number, include_blocking_info: boolean) {
149
+ const stepKey = step as PipelineStep
150
+ if (!PIPELINE_STEPS[stepKey]) {
151
+ throw new Error(`Invalid step: ${step}`)
152
+ }
153
+ const project = await getProject(project_id)
154
+ const fileStatuses: Record<string, string> = project.data?.file_statuses || {}
155
+ const allFiles = Object.entries(fileStatuses)
156
+ const readyFiles = allFiles.filter(([file_path, status]) => {
157
+ const completedSteps = getCompletedSteps(status)
158
+ return PIPELINE_STEPS[stepKey].prerequisites.every(prereq => completedSteps.includes(prereq))
159
+ })
160
+ const filePaths = readyFiles.map(([file_path]) => file_path)
161
+ const { data: chunks } = await adminDb.from('items').select('data')
162
+ .filter('data->>kb_type', 'eq', 'cil_chunk')
163
+ .filter('data->>project_id', 'eq', project_id)
164
+ .eq('is_active', true)
165
+ .in('data->>file_path' as any, filePaths)
166
+ const chunkCountByFile: Record<string, number> = {}
167
+ for (const c of chunks || []) {
168
+ const fp = c.data?.file_path
169
+ if (fp) chunkCountByFile[fp] = (chunkCountByFile[fp] || 0) + 1
170
+ }
171
+ const files = readyFiles.map(([file_path, status]) => {
172
+ const fileInfo: any = {
173
+ file_path,
174
+ status,
175
+ chunk_count: chunkCountByFile[file_path] || 0,
176
+ completed_steps: getCompletedSteps(status),
177
+ ready_for: getReadySteps(status),
178
+ blocked_by: getBlockedSteps(status)
179
+ }
180
+ if (include_blocking_info) {
181
+ fileInfo.blocking_reasons = getBlockingReasons(status, stepKey)
182
+ fileInfo.can_proceed = fileInfo.ready_for.includes(stepKey)
183
+ }
184
+ return fileInfo
185
+ })
186
+ return {
187
+ ok: true,
188
+ project_id,
189
+ step: stepKey,
190
+ step_name: PIPELINE_STEPS[stepKey].name,
191
+ prerequisites: PIPELINE_STEPS[stepKey].prerequisites,
192
+ target_status: PIPELINE_STEPS[stepKey].target_status,
193
+ file_count: files.length,
194
+ files
195
+ }
196
+ }
197
+
198
+ async function updateFilePipelineState(
199
+ project_id: string,
200
+ file_path: string,
201
+ step_completed: number,
202
+ new_status: string
203
+ ) {
204
+ const project = await getProject(project_id)
205
+ const fileStatuses = project.data?.file_statuses || {}
206
+ const previous_status = fileStatuses[file_path]
207
+ fileStatuses[file_path] = new_status
208
+ const { error } = await adminDb.from('items')
209
+ .update({
210
+ data: {
211
+ ...project.data,
212
+ file_statuses: fileStatuses,
213
+ last_ingested_at: new Date().toISOString()
214
+ }
215
+ })
216
+ .eq('id', project_id)
217
+ if (error) throw new Error(error.message)
218
+ return {
219
+ ok: true,
220
+ file_path,
221
+ previous_status,
222
+ new_status,
223
+ step_completed,
224
+ completed_steps: getCompletedSteps(new_status),
225
+ ready_for: getReadySteps(new_status),
226
+ progress_percentage: calculateProgress(new_status)
227
+ }
228
+ }
229
+
230
+ async function getPipelineBottlenecks(project_id: string) {
231
+ const project = await getProject(project_id)
232
+ const fileStatuses: Record<string, string> = project.data?.file_statuses || {}
233
+ const files = Object.entries(fileStatuses)
234
+ const bottlenecks = []
235
+ const recommendations = []
236
+ for (const step of Object.keys(PIPELINE_STEPS) as PipelineStep[]) {
237
+ const stepNum = step as unknown as number
238
+ const readyCount = files.filter(([_, status]) => {
239
+ const completedSteps = getCompletedSteps(status)
240
+ return PIPELINE_STEPS[step].prerequisites.every(prereq => completedSteps.includes(prereq))
241
+ }).length
242
+ const totalCount = files.length
243
+ const blockedCount = totalCount - readyCount
244
+ if (blockedCount > 0) {
245
+ bottlenecks.push({
246
+ step: stepNum,
247
+ step_name: PIPELINE_STEPS[step].name,
248
+ ready: readyCount,
249
+ blocked: blockedCount,
250
+ blocking_reasons: getStepBlockingReasons(files, step)
251
+ })
252
+ recommendations.push({
253
+ step: stepNum,
254
+ action: `Process ${blockedCount} files through prerequisite steps first`,
255
+ priority: step === 8 ? 'high' : 'medium'
256
+ })
257
+ }
258
+ }
259
+ const optimalOrder = getOptimalProcessingOrder(files)
260
+ return {
261
+ project_id,
262
+ bottlenecks,
263
+ recommendations: recommendations.sort((a, b) => {
264
+ const priorityOrder = { high: 3, medium: 2, low: 1 }
265
+ return priorityOrder[b.priority as keyof typeof priorityOrder] - priorityOrder[a.priority as keyof typeof priorityOrder]
266
+ }),
267
+ optimal_processing_order: optimalOrder,
268
+ summary: {
269
+ total_files: files.length,
270
+ bottleneck_count: bottlenecks.length,
271
+ ready_for_processing: files.filter(([_, status]) =>
272
+ getCompletedSteps(status).length >= 3
273
+ ).length
274
+ }
275
+ }
276
+ }
277
+
278
+ export const handler = createHandler(async (ctx, body) => {
279
+ const action = ctx.query?.action
280
+ if (!action) throw new Error('action is required')
281
+
282
+ if (action === 'get_pipeline_status') {
283
+ const { project_id } = body as { project_id: string }
284
+ if (!project_id) throw new Error('project_id is required')
285
+ return await getPipelineStatus(project_id)
286
+ }
287
+
288
+ if (action === 'get_files_ready_for_step') {
289
+ const { project_id, step, include_blocking_info } = body as {
290
+ project_id: string
291
+ step: number
292
+ include_blocking_info?: boolean
293
+ }
294
+ if (!project_id || step === undefined) throw new Error('project_id and step are required')
295
+ return await getFilesReadyForStep(project_id, step, include_blocking_info ?? false)
296
+ }
297
+
298
+ if (action === 'update_file_pipeline_state') {
299
+ const { project_id, file_path, step_completed, new_status } = body as {
300
+ project_id: string
301
+ file_path: string
302
+ step_completed: number
303
+ new_status: string
304
+ }
305
+ if (!project_id || !file_path || step_completed === undefined || !new_status) {
306
+ throw new Error('project_id, file_path, step_completed, and new_status are required')
307
+ }
308
+ return await updateFilePipelineState(project_id, file_path, step_completed, new_status)
309
+ }
310
+
311
+ if (action === 'get_pipeline_bottlenecks') {
312
+ const { project_id } = body as { project_id: string }
313
+ if (!project_id) throw new Error('project_id is required')
314
+ return await getPipelineBottlenecks(project_id)
315
+ }
316
+
317
+ throw new Error(`Unknown action: ${action}`)
318
+ })