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
@@ -1,59 +1,51 @@
1
- /**
2
- * @module pipeline-runner
3
- * @audience both
4
- * @layer shared-core
5
- * @stability stable
6
- *
7
- * Sequential pipeline execution engine. A pipeline is a named list of stages
8
- * (`PipelineStage[]`) stored in `pipelines.stages`. Each stage references an
9
- * `action` record by `stage_type` slug. Stages run sequentially; a failed stage
10
- * halts execution unless `stage.continue_on_error` is set.
11
- *
12
- * Every execution creates a `pipeline_executions` row (status: running →
13
- * completed | failed) and emits an audit log on completion or failure.
14
- *
15
- * Built-in stage handlers (no external config required):
16
- * - `update_item` — update a record by ID
17
- * - `create_record` — insert a new record
18
- * - `http_request` — fetch any HTTP endpoint
19
- * - `send_notification`— insert watchers notification rows
20
- * - `run_pipeline` — trigger a nested pipeline (self-recursion blocked)
21
- * - `search_knowledge` — full-text + fallback search on embeddings table
22
- * - `query_items` — filtered query on any table
23
- * - `agent_inference` — call an external LLM webhook or return a mock
24
- *
25
- * INVARIANT: `adminDb` (service role) is used for all DB writes — stage
26
- * execution runs as the pipeline's machine principal, not the end user.
27
- * INVARIANT: `run_pipeline` handler blocks self-referential execution
28
- * (`config._pipelineId === pipeline_id`) to prevent infinite loops.
29
- * INVARIANT: `runPipeline` never throws — failures are captured in the
30
- * returned `ExecutionResult` with `status: 'failed'`.
31
- *
32
- * @seeAlso trigger-engine.ts (calls runPipeline when a trigger fires)
33
- * @seeAlso agent-runner.ts (calls runPipeline for agentic tool calls)
34
- * @seeAlso audit.ts (emitAudit called on pipeline.completed / pipeline.failed)
35
- * @seeAlso index.ts (runPipeline re-exported for v2-custom/ and CLI)
36
- */
37
1
 
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+ // CIL[BEGIN chunk_id="pipelinerunner_imports_1784020784" type="module_header" identity="imports" parent="none"]
11
+ // CIL[DOC-MACRO purpose="Import dependencies for pipeline execution"]
12
+ // CIL[DOC-RESPONSIBILITY responsibility="Import context, database, and audit modules"]
13
+ // CIL[DOC-CONTEXT module="pipeline-runner" layer="shared" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\"custom/apps/portal/pages/ContentPage.tsx\",\"\\\"]"]
14
+ // CIL[DOC-CONTRACT inputs="v" outputs="CoreContext, adminDb, emitAudit, UUID utilities" errors="none" side_effects="none"]
15
+ // CIL[DOC-MICRO logic_summary="Import required modules and UUID validation utilities" notable_decisions="[]"]
16
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
17
+ // CIL[DOC-STABILITY stability="stable"]
18
+ // CIL[DOC-AUDIENCE audience="developer"]
19
+ // CIL[DOC-VECTOR type="context" content="Layer: shared. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, custom/apps/portal/pages/ContentPage.tsx, \."]
20
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
21
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
22
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
23
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
24
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
38
25
  import { CoreContext } from './middleware'
39
26
  import { adminDb } from './db'
40
- import { emitAudit } from './audit'
27
+ import { emitAudit, emitSpan } from './audit'
28
+ import { emitOutcome } from './outcomes'
29
+ import { withSpan } from './tracing'
30
+ import { execute as executeOutbound } from '../integration-outbound'
41
31
 
42
32
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
43
33
  function isUuid(v: string | undefined | null): v is string { return !!v && UUID_RE.test(v) }
44
-
45
- // ─── TYPES ──────────────────────────────────────────────────────────────
46
-
47
- /**
48
- * Result of a single pipeline stage execution.
49
- *
50
- * @outputSpec stageIndex: number — 0-based position in the pipeline's stages array
51
- * @outputSpec stageType: string — action slug (e.g. 'update_item', 'http_request')
52
- * @outputSpec status: 'success' | 'failed' | 'skipped'
53
- * @outputSpec output: any | undefined — handler return value on success
54
- * @outputSpec error: string | undefined — error message on failure
55
- * @outputSpec durationMs: number — wall-clock time for this stage
56
- */
34
+ // CIL[END chunk_id="pipelinerunner_imports_1784020784"]
35
+ // CIL[BEGIN chunk_id="pipelinerunner_stageresult_1784020784" type="interface" identity="StageResult" parent="none"]
36
+ // CIL[DOC-MACRO purpose="Define stage execution result interface"]
37
+ // CIL[DOC-RESPONSIBILITY responsibility="Structure pipeline stage execution data"]
38
+ // CIL[DOC-CONTEXT module="pipeline-runner" layer="shared" related_files="[\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"\\\"]"]
39
+ // CIL[DOC-CONTRACT inputs="none" outputs="StageResult interface" errors="none" side_effects="none"]
40
+ // CIL[DOC-MICRO logic_summary="Interface for tracking individual pipeline stage execution status" notable_decisions="[]"]
41
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
42
+ // CIL[DOC-STABILITY stability="stable"]
43
+ // CIL[DOC-VECTOR type="context" content="Layer: shared. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/functions/custom_cil-embeddings.ts, \."]
44
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
45
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
46
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
47
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
48
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
57
49
  export interface StageResult {
58
50
  stageIndex: number
59
51
  stageType: string
@@ -62,17 +54,21 @@ export interface StageResult {
62
54
  error?: string
63
55
  durationMs: number
64
56
  }
65
-
66
- /**
67
- * Top-level result of a `runPipeline` call. Stored in `pipeline_executions.result`.
68
- *
69
- * @outputSpec executionId: string — UUID of the pipeline_executions row
70
- * @outputSpec pipelineId: string — UUID of the pipeline that was run
71
- * @outputSpec status: 'completed' | 'failed' | 'cancelled'
72
- * @outputSpec stages: StageResult[] — per-stage results in execution order
73
- * @outputSpec durationMs: number — total wall-clock time
74
- * @outputSpec error: string | undefined — top-level error message on failure
75
- */
57
+ // CIL[END chunk_id="pipelinerunner_stageresult_1784020784"]
58
+ // CIL[BEGIN chunk_id="pipelinerunner_executionresult_1784020784" type="interface" identity="ExecutionResult" parent="none"]
59
+ // CIL[DOC-MACRO purpose="Define pipeline execution result interface"]
60
+ // CIL[DOC-RESPONSIBILITY responsibility="Structure complete pipeline execution data"]
61
+ // CIL[DOC-CONTEXT module="pipeline-runner" layer="shared" related_files="[\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"\\\"]"]
62
+ // CIL[DOC-CONTRACT inputs="none" outputs="ExecutionResult interface" errors="none" side_effects="none"]
63
+ // CIL[DOC-MICRO logic_summary="Interface for tracking overall pipeline execution with all stages" notable_decisions="[]"]
64
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
65
+ // CIL[DOC-STABILITY stability="stable"]
66
+ // CIL[DOC-VECTOR type="context" content="Layer: shared. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/functions/custom_cil-embeddings.ts, \."]
67
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
68
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
69
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
70
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
71
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
76
72
  export interface ExecutionResult {
77
73
  executionId: string
78
74
  pipelineId: string
@@ -81,79 +77,49 @@ export interface ExecutionResult {
81
77
  durationMs: number
82
78
  error?: string
83
79
  }
84
-
85
- /**
86
- * Single stage definition as stored in `pipelines.stages` JSONB array.
87
- *
88
- * @inputSpec stage_type: string — action.slug to look up the handler
89
- * @inputSpec config: Record<string, any> | undefined — merged with action defaults
90
- * @inputSpec continue_on_error: boolean | undefined — if true, failure doesn’t halt
91
- */
80
+ // CIL[END chunk_id="pipelinerunner_executionresult_1784020784"]
81
+ // CIL[BEGIN chunk_id="pipelinerunner_pipelinestage_1784020784" type="interface" identity="PipelineStage" parent="none"]
82
+ // CIL[DOC-MACRO purpose="Define pipeline stage configuration interface"]
83
+ // CIL[DOC-RESPONSIBILITY responsibility="Structure individual pipeline stage definition"]
84
+ // CIL[DOC-CONTEXT module="pipeline-runner" layer="shared" related_files="[\".framework/functions/_shared/schema-utils.ts\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
85
+ // CIL[DOC-CONTRACT inputs="none" outputs="PipelineStage interface" errors="none" side_effects="none"]
86
+ // CIL[DOC-MICRO logic_summary="Interface for defining pipeline stage type and configuration" notable_decisions="[]"]
87
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
88
+ // CIL[DOC-STABILITY stability="stable"]
89
+ // CIL[DOC-VECTOR type="context" content="Layer: shared. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/schema-utils.ts, custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
90
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
91
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
92
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
93
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
94
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
92
95
  interface PipelineStage {
93
96
  stage_type: string
94
97
  config?: Record<string, any>
95
98
  continue_on_error?: boolean
96
99
  }
97
-
98
- // ─── PRIMARY EXPORT ────────────────────────────────────────────────────────────
99
-
100
- /**
101
- * Executes a pipeline by ID, running its stages sequentially.
102
- *
103
- * Execution lifecycle:
104
- * 1. Load pipeline record (`pipelines` table, `is_active = true`)
105
- * 2. Insert `pipeline_executions` row with `status: 'running'`
106
- * 3. For each stage: load action → merge config → call `executeStage`
107
- * 4. On stage failure: push failed StageResult; stop unless `continue_on_error`
108
- * 5. Update `pipeline_executions` to `completed` or `failed`
109
- * 6. Emit `pipeline.completed` or `pipeline.failed` audit log
110
- * 7. Return `ExecutionResult` (never throws; failures are in result.status)
111
- *
112
- * @param pipelineId - UUID of the pipeline to run (must be active)
113
- * @param triggerData - Arbitrary context passed to each stage as `_triggerData`
114
- * @param ctx - CoreContext with principal and accountId for audit and stage writes
115
- * @returns Promise<ExecutionResult> — always resolves; never throws
116
- * @throws Error('Pipeline not found or inactive') — only if pipeline lookup fails
117
- * before execution begins (throws before creating the execution row)
118
- * @throws Error('Failed to create execution') — if execution row insert fails
119
- * @inputSpec pipelineId: string — valid UUID of a pipeline in pipelines table
120
- * @inputSpec triggerData: any — JSON-serializable; stored in trigger_data column
121
- * @inputSpec ctx.accountId: string | null — stamped on execution row
122
- * @inputSpec ctx.principal.id: string — stamped as created_by on execution row
123
- * @outputSpec ExecutionResult with status, stages, durationMs
124
- * @sideEffects DB write: inserts pipeline_executions row; updates it on completion
125
- * @sideEffects DB write: emitAudit to logs table
126
- * @calledBy trigger-engine.ts (on trigger fire)
127
- * @calledBy agent-runner.ts (tool call dispatch)
128
- * @calledBy stageHandlers.run_pipeline (nested execution)
129
- * @calledBy v2-custom/ import callers and CLI
130
- * @calls executeStage, adminDb, emitAudit
131
- * @testUnit tests/unit/pipeline-runner.test.ts
132
- * @testIntegration tests/integration/pipeline-runner.test.ts
133
- *
134
- * @example API handler trigger
135
- * ```ts
136
- * import { runPipeline } from './_shared/index'
137
- * const result = await runPipeline(body.pipeline_id, body.data, ctx)
138
- * if (result.status === 'failed') return error(result.error!, 500)
139
- * return result
140
- * ```
141
- *
142
- * @example Import usage (v2-custom/)
143
- * ```ts
144
- * import { runPipeline, SYSTEM_PRINCIPAL, adminDb, CoreContext } from '../_shared/index'
145
- * const ctx: CoreContext = { principal: SYSTEM_PRINCIPAL, accountId: MY_ACCOUNT, db: adminDb, requestId: crypto.randomUUID() }
146
- * const result = await runPipeline('pipeline-uuid', { source: 'import' }, ctx)
147
- * ```
148
- */
100
+ // CIL[END chunk_id="pipelinerunner_pipelinestage_1784020784"]
101
+ // CIL[BEGIN chunk_id="pipelinerunner_runpipeline_1784020784" type="function" identity="runPipeline" parent="none"]
102
+ // CIL[DOC-MACRO purpose="Execute complete pipeline with all stages"]
103
+ // CIL[DOC-RESPONSIBILITY responsibility="Orchestrate pipeline execution and error handling"]
104
+ // CIL[DOC-CONTEXT module="pipeline-runner" layer="shared" related_files="[\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/RolesPage.tsx\",\".framework/src/components/ui/dialog.tsx\"]"]
105
+ // CIL[DOC-CONTRACT inputs="none" outputs="ExecutionResult" errors="Pipeline not found, execution failed" side_effects="Database updates, audit events"]
106
+ // CIL[DOC-MICRO logic_summary="Main pipeline executor handling stages, errors, and database tracking" notable_decisions="[]"]
107
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
108
+ // CIL[DOC-STABILITY stability="stable"]
109
+ // CIL[DOC-VECTOR type="context" content="Layer: shared. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/RolesPage.tsx, .framework/src/components/ui/dialog.tsx."]
110
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
111
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
112
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
113
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
114
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
149
115
  export async function runPipeline(
150
116
  pipelineId: string,
151
117
  triggerData: any,
152
118
  ctx: CoreContext
153
119
  ): Promise<ExecutionResult> {
120
+ return withSpan(ctx, 'pipeline.run', async (ctx) => {
154
121
  const startTime = Date.now()
155
122
 
156
- // Load pipeline definition
157
123
  const { data: pipeline, error: pipelineError } = await adminDb
158
124
  .from('pipelines')
159
125
  .select('*')
@@ -165,7 +131,6 @@ export async function runPipeline(
165
131
  throw new Error(`Pipeline not found or inactive: ${pipelineId}`)
166
132
  }
167
133
 
168
- // Create execution record
169
134
  const { data: execution, error: execError } = await adminDb
170
135
  .from('pipeline_executions')
171
136
  .insert({
@@ -188,13 +153,11 @@ export async function runPipeline(
188
153
  const stages: PipelineStage[] = pipeline.stages || []
189
154
 
190
155
  try {
191
- // Execute each stage sequentially
192
156
  for (let i = 0; i < stages.length; i++) {
193
157
  const stage = stages[i]
194
158
  const stageStartTime = Date.now()
195
159
 
196
160
  try {
197
- // Load action for this stage type
198
161
  const { data: action, error: actionError } = await adminDb
199
162
  .from('actions')
200
163
  .select('*')
@@ -206,7 +169,6 @@ export async function runPipeline(
206
169
  throw new Error(`Action not found for stage type: ${stage.stage_type}`)
207
170
  }
208
171
 
209
- // Merge stage config with action defaults
210
172
  const mergedConfig = {
211
173
  ...action.config,
212
174
  ...stage.config,
@@ -216,7 +178,6 @@ export async function runPipeline(
216
178
  _triggerData: triggerData
217
179
  }
218
180
 
219
- // Execute the stage
220
181
  const output = await executeStage(ctx, action, mergedConfig)
221
182
 
222
183
  stageResults.push({
@@ -238,14 +199,12 @@ export async function runPipeline(
238
199
  durationMs: Date.now() - stageStartTime
239
200
  })
240
201
 
241
- // Stop unless continue_on_error is set
242
202
  if (!stage.continue_on_error) {
243
203
  throw new Error(`Stage ${i} (${stage.stage_type}) failed: ${errorMessage}`)
244
204
  }
245
205
  }
246
206
  }
247
207
 
248
- // Complete successfully
249
208
  const durationMs = Date.now() - startTime
250
209
 
251
210
  await adminDb
@@ -267,6 +226,12 @@ export async function runPipeline(
267
226
  duration_ms: durationMs,
268
227
  stages_completed: stageResults.length
269
228
  })
229
+ await emitOutcome(ctx, 'pipeline.outcome', 'success', {
230
+ pipeline_id: pipelineId,
231
+ execution_id: executionId,
232
+ stages_completed: stageResults.length,
233
+ duration_ms: durationMs
234
+ })
270
235
 
271
236
  return {
272
237
  executionId,
@@ -277,7 +242,6 @@ export async function runPipeline(
277
242
  }
278
243
 
279
244
  } catch (error: any) {
280
- // Complete with failure
281
245
  const durationMs = Date.now() - startTime
282
246
 
283
247
  await adminDb
@@ -300,6 +264,12 @@ export async function runPipeline(
300
264
  error: error.message,
301
265
  stages_completed: stageResults.length
302
266
  })
267
+ await emitOutcome(ctx, 'pipeline.outcome', 'failure', {
268
+ pipeline_id: pipelineId,
269
+ execution_id: executionId,
270
+ error: error.message,
271
+ stages_completed: stageResults.length
272
+ })
303
273
 
304
274
  return {
305
275
  executionId,
@@ -310,76 +280,62 @@ export async function runPipeline(
310
280
  error: error.message
311
281
  }
312
282
  }
283
+ }, { onEnd: emitSpan })
313
284
  }
314
-
315
- // ─── STAGE DISPATCH ────────────────────────────────────────────────────────────
316
-
317
- /**
318
- * Dispatches a single stage to the correct handler module.
319
- *
320
- * Routes based on `action.handler_module`:
321
- * - `'functions'` → `executeFunctionHandler` (built-in stageHandlers)
322
- * - `'integrations'` → `executeIntegrationHandler` (loads integration by slug)
323
- * - `'webhook'` → `executeWebhookHandler` (calls action.config.url)
324
- *
325
- * @param ctx - CoreContext
326
- * @param action - Action record from the `actions` table
327
- * @param config - Merged stage + action config with `_pipelineId`, `_executionId`,
328
- * `_stageIndex`, `_triggerData` injected by runPipeline
329
- * @returns Promise<any> — handler output
330
- * @throws Error('Unknown handler module') on unrecognised module string
331
- * @inputSpec action.handler_module: 'functions' | 'integrations' | 'webhook'
332
- * @inputSpec action.handler: string — handler name or integration slug
333
- * @sideEffects depends on handler module (DB writes, HTTP calls)
334
- * @calledBy runPipeline (per-stage loop)
335
- * @calls executeFunctionHandler | executeIntegrationHandler | executeWebhookHandler
336
- */
285
+ // CIL[END chunk_id="pipelinerunner_runpipeline_1784020784"]
286
+ // CIL[BEGIN chunk_id="pipelinerunner_executestage_1784020784" type="function" identity="executeStage" parent="none"]
287
+ // CIL[DOC-MACRO purpose="Route stage execution to appropriate handler"]
288
+ // CIL[DOC-RESPONSIBILITY responsibility="Dispatch stage execution based on handler module"]
289
+ // CIL[DOC-CONTEXT module="pipeline-runner" layer="shared" related_files="[]"]
290
+ // CIL[DOC-CONTRACT inputs="none" outputs="stage execution result" errors="Unknown handler module" side_effects="Handler execution"]
291
+ // CIL[DOC-MICRO logic_summary="Stage dispatcher routing to functions, integrations, or webhooks" notable_decisions="[]"]
292
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
293
+ // CIL[DOC-STABILITY stability="stable"]
294
+ // CIL[DOC-VECTOR type="context" content="Layer: shared. Direct callers: 0. Direct calls: 0. Related files: none."]
295
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
296
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
297
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
298
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
299
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
337
300
  async function executeStage(
338
301
  ctx: CoreContext,
339
302
  action: any,
340
303
  config: any
341
304
  ): Promise<any> {
342
- const handlerModule = action.handler_module || 'functions'
343
- const handlerName = action.handler
344
-
345
- switch (handlerModule) {
346
- case 'functions':
347
- return await executeFunctionHandler(ctx, handlerName, config)
348
-
349
- case 'integrations':
350
- return await executeIntegrationHandler(ctx, handlerName, config)
351
-
352
- case 'webhook':
353
- return await executeWebhookHandler(ctx, action, config)
354
-
355
- default:
356
- throw new Error(`Unknown handler module: ${handlerModule}`)
357
- }
305
+ return withSpan(ctx, `pipeline.stage.${action.handler || action.stage_type || 'unknown'}`, async (ctx) => {
306
+ const handlerModule = action.handler_module || 'functions'
307
+ const handlerName = action.handler
308
+
309
+ switch (handlerModule) {
310
+ case 'functions':
311
+ return await executeFunctionHandler(ctx, handlerName, config)
312
+
313
+ case 'integrations':
314
+ return await executeIntegrationHandler(ctx, handlerName, config)
315
+
316
+ case 'webhook':
317
+ return await executeWebhookHandler(ctx, action, config)
318
+
319
+ default:
320
+ throw new Error(`Unknown handler module: ${handlerModule}`)
321
+ }
322
+ }, { onEnd: emitSpan })
358
323
  }
359
-
360
- // ─── BUILT-IN STAGE HANDLERS ─────────────────────────────────────────────────────────
361
-
362
- /**
363
- * Map of built-in stage handler functions keyed by action slug.
364
- *
365
- * Each handler receives `(ctx: CoreContext, config: any)` and returns a
366
- * JSON-serializable result or throws on failure. Registered handlers:
367
- *
368
- * | Slug | Required config keys | Returns |
369
- * |---------------------|-----------------------------------|--------------------------------|
370
- * | `update_item` | `entity`, `record_id`, `data` | `{ success, record }` |
371
- * | `create_record` | `entity`, `data` | `{ success, record }` |
372
- * | `http_request` | `url` | `{ success, status, body }` |
373
- * | `send_notification` | `message`, `recipients[]` | `{ success, notified_count }` |
374
- * | `run_pipeline` | `pipeline_id` | `{ success, nested_result }` |
375
- * | `search_knowledge` | `query` | `{ results[], count, method }` |
376
- * | `query_items` | `entity` | `{ items[], count }` |
377
- * | `agent_inference` | `context` | `{ content, confidence, ... }` |
378
- *
379
- * @sideEffects DB writes for update_item, create_record, send_notification
380
- * @sideEffects HTTP calls for http_request, agent_inference (webhook_url)
381
- * @calledBy executeFunctionHandler
382
- */
324
+ // CIL[END chunk_id="pipelinerunner_executestage_1784020784"]
325
+ // CIL[BEGIN chunk_id="pipelinerunner_stagehandlers_1784020784" type="variable" identity="stageHandlers" parent="none"]
326
+ // CIL[DOC-MACRO purpose="Define all available pipeline stage handlers"]
327
+ // CIL[DOC-RESPONSIBILITY responsibility="Implement core pipeline stage execution functions"]
328
+ // CIL[DOC-CONTEXT module="pipeline-runner" layer="shared" related_files="[]"]
329
+ // CIL[DOC-CONTRACT inputs="none" outputs="stageHandlers object" errors="none" side_effects="Database operations, HTTP requests"]
330
+ // CIL[DOC-MICRO logic_summary="Collection of handlers for database, HTTP, notification, and AI operations" notable_decisions="[]"]
331
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
332
+ // CIL[DOC-STABILITY stability="stable"]
333
+ // CIL[DOC-VECTOR type="context" content="Layer: shared. Direct callers: 0. Direct calls: 0. Related files: none."]
334
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
335
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
336
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
337
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
338
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
383
339
  const stageHandlers: Record<string, Function> = {
384
340
  'update_item': async (ctx: CoreContext, config: any) => {
385
341
  const { entity, record_id, data } = config
@@ -433,33 +389,21 @@ const stageHandlers: Record<string, Function> = {
433
389
  throw new Error('url is required for http_request')
434
390
  }
435
391
 
436
- const fetchOptions: RequestInit = {
437
- method,
438
- headers: {
439
- 'Content-Type': 'application/json',
440
- ...headers
441
- }
442
- }
443
-
444
- if (body && ['POST', 'PUT', 'PATCH'].includes(method)) {
445
- fetchOptions.body = JSON.stringify(body)
446
- }
447
-
448
- const response = await fetch(url, fetchOptions)
449
- const responseBody = await response.json().catch(() => null)
392
+ const result = await executeOutbound(ctx, {
393
+ integration_slug: 'generic-http',
394
+ action_config: { url, method, headers, body: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined }
395
+ })
450
396
 
451
397
  return {
452
- success: response.ok,
453
- status: response.status,
454
- statusText: response.statusText,
455
- body: responseBody
398
+ success: true,
399
+ status: result.response_status,
400
+ body: result.response_body
456
401
  }
457
402
  },
458
403
 
459
404
  'send_notification': async (ctx: CoreContext, config: any) => {
460
405
  const { message, entity_type, entity_id, recipients = [] } = config
461
406
 
462
- // Create watcher notifications
463
407
  const notifications = recipients.map((recipientId: string) => ({
464
408
  account_id: ctx.accountId,
465
409
  person_id: recipientId,
@@ -488,7 +432,6 @@ const stageHandlers: Record<string, Function> = {
488
432
  throw new Error('pipeline_id is required for run_pipeline')
489
433
  }
490
434
 
491
- // Prevent infinite recursion
492
435
  if (config._pipelineId === pipeline_id) {
493
436
  throw new Error('Recursive pipeline execution prevented')
494
437
  }
@@ -508,7 +451,6 @@ const stageHandlers: Record<string, Function> = {
508
451
  throw new Error('query is required for search_knowledge')
509
452
  }
510
453
 
511
- // Text search fallback (when no embedding provided)
512
454
  let dbQuery = adminDb
513
455
  .from('embeddings')
514
456
  .select('*')
@@ -523,7 +465,6 @@ const stageHandlers: Record<string, Function> = {
523
465
  dbQuery = dbQuery.eq('model_id', model_id)
524
466
  }
525
467
 
526
- // Try text search first
527
468
  const { data: textResults, error: textError } = await dbQuery
528
469
  .textSearch('content', query, { type: 'websearch', config: 'english' })
529
470
 
@@ -536,7 +477,6 @@ const stageHandlers: Record<string, Function> = {
536
477
  }
537
478
  }
538
479
 
539
- // Fallback to ilike search
540
480
  const { data: fallbackResults, error: fallbackError } = await dbQuery
541
481
  .ilike('content', `%${query}%`)
542
482
 
@@ -565,12 +505,10 @@ const stageHandlers: Record<string, Function> = {
565
505
  .eq('account_id', ctx.accountId)
566
506
  .limit(parseInt(limit.toString()))
567
507
 
568
- // Apply filters
569
508
  Object.entries(filters).forEach(([key, value]) => {
570
509
  dbQuery = dbQuery.eq(key, value)
571
510
  })
572
511
 
573
- // Add text search if query provided
574
512
  if (query) {
575
513
  dbQuery = dbQuery.textSearch('data', query, { type: 'websearch', config: 'english' })
576
514
  }
@@ -588,37 +526,36 @@ const stageHandlers: Record<string, Function> = {
588
526
  throw new Error('context is required for agent_inference')
589
527
  }
590
528
 
591
- // If webhook_url provided, call external LLM service
592
529
  if (webhook_url) {
593
- const response = await fetch(webhook_url, {
594
- method: 'POST',
595
- headers: {
596
- 'Content-Type': 'application/json',
597
- ...headers
598
- },
599
- body: JSON.stringify({
600
- context,
601
- model: model || 'gpt-4o',
602
- temperature: temperature ?? 0.7,
603
- max_tokens: max_tokens ?? 4000
604
- })
530
+ const result = await executeOutbound(ctx, {
531
+ integration_slug: 'generic-http',
532
+ action_config: {
533
+ url: webhook_url,
534
+ method: 'POST',
535
+ headers,
536
+ body: {
537
+ context,
538
+ model: model || 'gpt-4o',
539
+ temperature: temperature ?? 0.7,
540
+ max_tokens: max_tokens ?? 4000
541
+ }
542
+ }
605
543
  })
606
544
 
607
- if (!response.ok) {
608
- throw new Error(`Inference failed: ${response.status} ${response.statusText}`)
545
+ if (!result.success) {
546
+ throw new Error(`Inference failed: ${result.response_status} ${result.response_body}`)
609
547
  }
610
548
 
611
- const result: any = await response.json()
549
+ const response: any = result.response_body
612
550
  return {
613
- content: result.content || result.message || '',
614
- confidence: result.confidence || 0.8,
615
- tool_calls: result.tool_calls,
616
- metadata: result.metadata,
551
+ content: response.content || response.message || '',
552
+ confidence: response.confidence || 0.8,
553
+ tool_calls: response.tool_calls,
554
+ metadata: response.metadata,
617
555
  model: model || 'gpt-4o'
618
556
  }
619
557
  }
620
558
 
621
- // Fallback: return mock for development/testing
622
559
  return {
623
560
  content: `[Mock Response] Received ${context.length} chars of context. In production, configure webhook_url in action config.`,
624
561
  confidence: 0.9,
@@ -628,20 +565,11 @@ const stageHandlers: Record<string, Function> = {
628
565
  }
629
566
  },
630
567
 
631
- // ── generate_embeddings ─────────────────────────────────────────────────────
632
- // Generates embeddings for an item using the core embeddings.generate action.
633
- // Supports {{trigger.entity_id}} template interpolation in config.item_id.
634
- //
635
- // Config: item_id (required — supports {{trigger.entity_id}}),
636
- // force_regenerate (bool, default false)
637
- //
638
- // Called by the auto_embed_on_publish and auto_revoke_on_unpublish pipelines.
639
568
  'generate_embeddings': async (ctx: CoreContext, config: any) => {
640
569
  const triggerData = config._triggerData || {}
641
570
  let itemId = config.item_id
642
571
  if (!itemId) throw new Error('item_id is required for generate_embeddings')
643
572
 
644
- // Template interpolation: {{trigger.entity_id}} or {{entity_id}}
645
573
  if (typeof itemId === 'string' && itemId.includes('{{')) {
646
574
  itemId = itemId
647
575
  .replace(/\{\{trigger\.entity_id\}\}/g, triggerData?.entity_id || '')
@@ -651,23 +579,28 @@ const stageHandlers: Record<string, Function> = {
651
579
  if (!itemId) throw new Error('generate_embeddings: could not resolve item_id from trigger data')
652
580
 
653
581
  const { generate } = await import('../embeddings')
654
- const genCtx = { ...ctx, query: { ...(ctx.query || {}), action: 'generate' } }
582
+ const genCtx = { ...ctx, query: { ...((ctx as any).query || {}), action: 'generate' } } as any
655
583
  return await generate(genCtx, {
656
584
  item_id: itemId,
657
585
  force_regenerate: config.force_regenerate ?? false,
658
586
  })
659
587
  },
660
588
  }
661
-
662
- // ─── MODULE DISPATCHERS ────────────────────────────────────────────────────────────
663
-
664
- /**
665
- * Looks up a built-in handler by name and calls it.
666
- *
667
- * @throws Error('Unknown function handler: <name>') if not in stageHandlers map
668
- * @calledBy executeStage (functions module)
669
- * @calls stageHandlers[handlerName]
670
- */
589
+ // CIL[END chunk_id="pipelinerunner_stagehandlers_1784020784"]
590
+ // CIL[BEGIN chunk_id="pipelinerunner_executefunctionhandler_1784020784" type="function" identity="executeFunctionHandler" parent="none"]
591
+ // CIL[DOC-MACRO purpose="Execute built-in function stage handlers"]
592
+ // CIL[DOC-RESPONSIBILITY responsibility="Dispatch to internal stage handler functions"]
593
+ // CIL[DOC-CONTEXT module="pipeline-runner" layer="shared" related_files="[]"]
594
+ // CIL[DOC-CONTRACT inputs="none" outputs="handler execution result" errors="Unknown function handler" side_effects="Handler execution"]
595
+ // CIL[DOC-MICRO logic_summary="Lookup and execute built-in stage handler by name" notable_decisions="[]"]
596
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
597
+ // CIL[DOC-STABILITY stability="stable"]
598
+ // CIL[DOC-VECTOR type="context" content="Layer: shared. Direct callers: 0. Direct calls: 0. Related files: none."]
599
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
600
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
601
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
602
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
603
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
671
604
  async function executeFunctionHandler(
672
605
  ctx: CoreContext,
673
606
  handlerName: string,
@@ -681,55 +614,48 @@ async function executeFunctionHandler(
681
614
 
682
615
  return await handler(ctx, config)
683
616
  }
684
-
685
- /**
686
- * Loads an integration record by slug and executes it.
687
- *
688
- * Currently a stub — logs the call and returns the integration ID.
689
- * Future: delegate to integration-specific executor based on integration type.
690
- *
691
- * @throws Error('Integration not found') if no active integration matches slug
692
- * @sideEffects DB read: integrations table
693
- * @calledBy executeStage (integrations module)
694
- */
617
+ // CIL[END chunk_id="pipelinerunner_executefunctionhandler_1784020784"]
618
+ // CIL[BEGIN chunk_id="pipelinerunner_executeintegrationhandler_1784020784" type="function" identity="executeIntegrationHandler" parent="none"]
619
+ // CIL[DOC-MACRO purpose="Execute external integration stage handlers"]
620
+ // CIL[DOC-RESPONSIBILITY responsibility="Dispatch to configured integration handlers"]
621
+ // CIL[DOC-CONTEXT module="pipeline-runner" layer="shared" related_files="[]"]
622
+ // CIL[DOC-CONTRACT inputs="none" outputs="integration execution result" errors="Integration not found" side_effects="Integration execution"]
623
+ // CIL[DOC-MICRO logic_summary="Lookup integration config and execute external handler" notable_decisions="[]"]
624
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
625
+ // CIL[DOC-STABILITY stability="stable"]
626
+ // CIL[DOC-VECTOR type="context" content="Layer: shared. Direct callers: 0. Direct calls: 0. Related files: none."]
627
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
628
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
629
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
630
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
631
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
695
632
  async function executeIntegrationHandler(
696
633
  ctx: CoreContext,
697
634
  handlerName: string,
698
635
  config: any
699
636
  ): Promise<any> {
700
- // Load integration configuration
701
- const { data: integration, error } = await adminDb
702
- .from('integrations')
703
- .select('*')
704
- .eq('slug', handlerName)
705
- .eq('is_active', true)
706
- .single()
707
-
708
- if (error || !integration) {
709
- throw new Error(`Integration not found: ${handlerName}`)
710
- }
711
-
712
- // Execute based on integration type
713
- // This is a placeholder for actual integration logic
714
- console.log(`[${ctx.requestId}] Integration handler: ${handlerName}`, config)
715
-
716
- return {
717
- success: true,
718
- handler: handlerName,
719
- integration_id: integration.id
720
- }
637
+ const { execute } = await import('../integration-outbound')
638
+ return execute(ctx, {
639
+ integration_slug: handlerName,
640
+ record_id: config.record_id,
641
+ action_config: config
642
+ })
721
643
  }
722
-
723
- /**
724
- * POSTs the merged stage config as JSON to the webhook URL from action.config.url.
725
- *
726
- * Returns `{ success, status, body }` based on the HTTP response. Does not
727
- * throw on non-2xx responses — `success: false` is returned instead.
728
- *
729
- * @throws Error('Webhook URL not configured') if action.config.url is missing
730
- * @sideEffects HTTP call to action.config.url
731
- * @calledBy executeStage (webhook module)
732
- */
644
+ // CIL[END chunk_id="pipelinerunner_executeintegrationhandler_1784020784"]
645
+ // CIL[BEGIN chunk_id="pipelinerunner_executewebhookhandler_1784020784" type="function" identity="executeWebhookHandler" parent="none"]
646
+ // CIL[DOC-MACRO purpose="Execute webhook stage handlers via HTTP"]
647
+ // CIL[DOC-RESPONSIBILITY responsibility="Send stage execution data to webhook endpoints"]
648
+ // CIL[DOC-CONTEXT module="pipeline-runner" layer="shared" related_files="[]"]
649
+ // CIL[DOC-CONTRACT inputs="none" outputs="webhook response" errors="Webhook URL not configured" side_effects="HTTP requests"]
650
+ // CIL[DOC-MICRO logic_summary="Send configuration data to configured webhook endpoint" notable_decisions="[]"]
651
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
652
+ // CIL[DOC-STABILITY stability="stable"]
653
+ // CIL[DOC-VECTOR type="context" content="Layer: shared. Direct callers: 0. Direct calls: 0. Related files: none."]
654
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
655
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
656
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
657
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
658
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
733
659
  async function executeWebhookHandler(
734
660
  ctx: CoreContext,
735
661
  action: any,
@@ -741,21 +667,22 @@ async function executeWebhookHandler(
741
667
  throw new Error('Webhook URL not configured in action')
742
668
  }
743
669
 
744
- const fetchOptions: RequestInit = {
745
- method,
746
- headers: {
747
- 'Content-Type': 'application/json',
748
- ...headers
749
- },
750
- body: JSON.stringify(config)
751
- }
752
-
753
- const response = await fetch(url, fetchOptions)
754
- const body = await response.json().catch(() => null)
670
+ const { execute } = await import('../integration-outbound')
671
+ const result = await execute(ctx, {
672
+ integration_slug: 'generic-http',
673
+ action_config: {
674
+ url,
675
+ method,
676
+ headers,
677
+ body: config,
678
+ credential_field: 'api_token'
679
+ }
680
+ })
755
681
 
756
682
  return {
757
- success: response.ok,
758
- status: response.status,
759
- body
683
+ success: result.success,
684
+ status: result.response_status,
685
+ body: result.response_body
760
686
  }
761
687
  }
688
+ // CIL[END chunk_id="pipelinerunner_executewebhookhandler_1784020784"]