spine-framework 0.3.145 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/.env.example +76 -0
  2. package/.framework/.spine-manifest.json +19 -0
  3. package/.framework/cli/commands/agents.ts +61 -33
  4. package/.framework/cli/commands/auth.ts +60 -28
  5. package/.framework/cli/commands/create-app.ts +212 -80
  6. package/.framework/cli/commands/dev.ts +184 -68
  7. package/.framework/cli/commands/doctor.ts +324 -152
  8. package/.framework/cli/commands/generate.ts +119 -68
  9. package/.framework/cli/commands/init.ts +141 -242
  10. package/.framework/cli/commands/install-app.ts +1336 -314
  11. package/.framework/cli/commands/items.ts +31 -29
  12. package/.framework/cli/commands/migrate.ts +299 -156
  13. package/.framework/cli/commands/migrations.ts +62 -30
  14. package/.framework/cli/commands/pipelines.ts +31 -29
  15. package/.framework/cli/commands/status.ts +105 -45
  16. package/.framework/cli/commands/system.ts +47 -42
  17. package/.framework/cli/commands/test.ts +161 -102
  18. package/.framework/cli/commands/upgrade.ts +260 -0
  19. package/.framework/cli/commands/validate-app.ts +517 -161
  20. package/.framework/cli/context.ts +117 -85
  21. package/.framework/cli/env-loader.ts +74 -43
  22. package/.framework/cli/index.ts +70 -46
  23. package/.framework/cli/lib/project-files.ts +404 -0
  24. package/.framework/docs/guides/testing-guide.md +1 -1
  25. package/.framework/docs/runtime-types.md +72 -72
  26. package/.framework/functions/_shared/access.ts +84 -0
  27. package/.framework/functions/_shared/agent-runner.ts +5067 -1026
  28. package/.framework/functions/_shared/app-manifest.ts +214 -94
  29. package/.framework/functions/_shared/ast.ts +214 -0
  30. package/.framework/functions/_shared/audit.ts +91 -55
  31. package/.framework/functions/_shared/cil.ts +368 -127
  32. package/.framework/functions/_shared/db.ts +337 -68
  33. package/.framework/functions/_shared/funnel.ts +228 -0
  34. package/.framework/functions/_shared/geo.ts +105 -0
  35. package/.framework/functions/_shared/hash-api-key.ts +94 -17
  36. package/.framework/functions/_shared/index.ts +22 -224
  37. package/.framework/functions/_shared/kb.ts +832 -58
  38. package/.framework/functions/_shared/llm.ts +118 -18
  39. package/.framework/functions/_shared/logging.ts +317 -19
  40. package/.framework/functions/_shared/middleware.ts +701 -131
  41. package/.framework/functions/_shared/notify.ts +70 -0
  42. package/.framework/functions/_shared/outcomes.ts +34 -19
  43. package/.framework/functions/_shared/permissions.ts +501 -315
  44. package/.framework/functions/_shared/pipeline-runner.ts +704 -155
  45. package/.framework/functions/_shared/principal.ts +436 -263
  46. package/.framework/functions/_shared/rate-limit.ts +233 -0
  47. package/.framework/functions/_shared/resolve-credentials.ts +86 -19
  48. package/.framework/functions/_shared/resolve-ids.ts +203 -139
  49. package/.framework/functions/_shared/retry-deliveries.ts +51 -16
  50. package/.framework/functions/_shared/schema-utils.ts +602 -521
  51. package/.framework/functions/_shared/security.ts +345 -0
  52. package/.framework/functions/_shared/testing.ts +197 -172
  53. package/.framework/functions/_shared/tracing.ts +351 -21
  54. package/.framework/functions/_shared/trigger-engine.ts +425 -136
  55. package/.framework/functions/_shared/webhook-registration.ts +71 -70
  56. package/.framework/functions/_shared/webhook-registry.ts +126 -83
  57. package/.framework/functions/account-nodes.ts +30 -30
  58. package/.framework/functions/adapters/generic-webhook-inbound.ts +49 -16
  59. package/.framework/functions/adapters/generic-webhook-outbound.ts +17 -17
  60. package/.framework/functions/adapters/openai-outbound.ts +15 -16
  61. package/.framework/functions/admin-data.ts +596 -173
  62. package/.framework/functions/admin-funnel.ts +64 -60
  63. package/.framework/functions/admin-install-funnel.ts +84 -66
  64. package/.framework/functions/admin-signals.ts +69 -51
  65. package/.framework/functions/ai-agents.ts +431 -106
  66. package/.framework/functions/ai-interactions.ts +186 -112
  67. package/.framework/functions/api-keys.ts +107 -107
  68. package/.framework/functions/apps.ts +154 -136
  69. package/.framework/functions/auth.ts +83 -65
  70. package/.framework/functions/cil-agent-ingest.ts +189 -232
  71. package/.framework/functions/cil-agent.ts +433 -177
  72. package/.framework/functions/cil-callmap.ts +642 -430
  73. package/.framework/functions/cil-config.ts +139 -135
  74. package/.framework/functions/cil-context.ts +214 -127
  75. package/.framework/functions/cil-doc.ts +587 -458
  76. package/.framework/functions/cil-embeddings.ts +453 -364
  77. package/.framework/functions/cil-graph.ts +427 -142
  78. package/.framework/functions/cil-ingest.ts +1418 -1154
  79. package/.framework/functions/cil-pipeline.ts +276 -21
  80. package/.framework/functions/cil-project.ts +659 -132
  81. package/.framework/functions/cil-validate.ts +198 -164
  82. package/.framework/functions/debug-auth.ts +57 -55
  83. package/.framework/functions/deliveries.ts +80 -21
  84. package/.framework/functions/embeddings.ts +1023 -318
  85. package/.framework/functions/eval-harness.ts +146 -108
  86. package/.framework/functions/integration-outbound.ts +205 -75
  87. package/.framework/functions/integration-routes.ts +128 -23
  88. package/.framework/functions/integrations.ts +125 -100
  89. package/.framework/functions/invites.ts +1095 -460
  90. package/.framework/functions/item-progress.ts +158 -102
  91. package/.framework/functions/kb.ts +34 -10
  92. package/.framework/functions/logs.ts +133 -133
  93. package/.framework/functions/observability.ts +152 -122
  94. package/.framework/functions/pipeline-executions.ts +147 -132
  95. package/.framework/functions/pipelines.ts +134 -119
  96. package/.framework/functions/prompt-configs.ts +96 -80
  97. package/.framework/functions/roles.ts +112 -82
  98. package/.framework/functions/security.ts +450 -0
  99. package/.framework/functions/system-cron.ts +117 -80
  100. package/.framework/functions/system.ts +158 -98
  101. package/.framework/functions/tests.ts +29 -29
  102. package/.framework/functions/timers.ts +94 -95
  103. package/.framework/functions/trigger-scheduler.ts +10 -0
  104. package/.framework/functions/triggers.ts +179 -149
  105. package/.framework/functions/types.ts +137 -125
  106. package/.framework/mcp/index.ts +133 -0
  107. package/.framework/mcp/load-env.ts +60 -0
  108. package/.framework/mcp/shared/app-manifest.ts +275 -0
  109. package/.framework/mcp/shared/db.ts +477 -0
  110. package/.framework/mcp/shared/kb.ts +118 -0
  111. package/.framework/mcp/tools/architect.ts +431 -0
  112. package/.framework/mcp/tools/cil/context.ts +345 -0
  113. package/.framework/mcp/tools/cil/graph.ts +242 -0
  114. package/.framework/mcp/tools/cil/ingest.ts +1217 -0
  115. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +693 -0
  116. package/.framework/mcp/tools/cil/pipeline.ts +767 -0
  117. package/.framework/mcp/tools/cil/project.ts +791 -0
  118. package/.framework/mcp/tools/cil/retrieval.ts +336 -0
  119. package/.framework/mcp/tools/cil/search-core.ts +454 -0
  120. package/.framework/mcp/tools/cil/search.ts +97 -0
  121. package/.framework/mcp/tools/cil/suggest.ts +186 -0
  122. package/.framework/mcp/tools/cil/validate.ts +1369 -0
  123. package/.framework/mcp/tools/kb/delete.ts +139 -0
  124. package/.framework/mcp/tools/kb/index.ts +52 -0
  125. package/.framework/mcp/tools/kb/ingest.ts +84 -0
  126. package/.framework/mcp/tools/kb/list-types.ts +102 -0
  127. package/.framework/mcp/tools/kb/publish.ts +100 -0
  128. package/.framework/mcp/tools/kb/reindex.ts +86 -0
  129. package/.framework/mcp/tools/kb/revoke.ts +85 -0
  130. package/.framework/mcp/tools/kb/search.ts +101 -0
  131. package/.framework/mcp/tools/kb/upsert.ts +125 -0
  132. package/.framework/mcp/tools/observability.ts +510 -0
  133. package/.framework/migrations/001_core_schema.sql +15 -0
  134. package/.framework/migrations/002_core_rls_and_functions.sql +15 -0
  135. package/.framework/migrations/003_core_system_data.sql +16 -1
  136. package/.framework/migrations/004_core_rpc_and_broker.sql +17 -1
  137. package/.framework/migrations/005_core_observability.sql +17 -1
  138. package/.framework/migrations/006_security_hardening_rls.sql +15 -0
  139. package/.framework/migrations/007_kb_article_list.sql +17 -1
  140. package/.framework/migrations/008_items_target.sql +15 -0
  141. package/.framework/migrations/009_roles_slug_unique.sql +15 -0
  142. package/.framework/migrations/010_auth_user_trigger.sql +15 -0
  143. package/.framework/migrations/011_spine_system_account.sql +16 -0
  144. package/.framework/migrations/012_service_role_grants.sql +16 -0
  145. package/.framework/migrations/013_get_account_apps_role_filter.sql +15 -0
  146. package/.framework/migrations/014_apps_required_roles.sql +16 -0
  147. package/.framework/migrations/015_types_kind_slug_unique.sql +15 -0
  148. package/.framework/migrations/016_cil_types.sql +281 -0
  149. package/.framework/migrations/017_cil_stable_ids.sql +37 -0
  150. package/.framework/migrations/018_runtime_tables.sql +129 -0
  151. package/.framework/migrations/019_agent_prompt_columns.sql +56 -0
  152. package/.framework/migrations/020_schema_reconciliation.sql +67 -0
  153. package/.framework/migrations/021_kb_embedding_lifecycle.sql +31 -0
  154. package/.framework/migrations/032_cil_status_migration.sql +73 -0
  155. package/.framework/migrations/033_cil_versioning.sql +73 -0
  156. package/.framework/migrations/034_match_embeddings_knn.sql +115 -0
  157. package/.framework/migrations/035_rate_limits.sql +55 -0
  158. package/.framework/migrations/036_demo_record_flags.sql +72 -0
  159. package/.framework/migrations/037_kb_types_canonical.sql +244 -0
  160. package/.framework/migrations/038_drop_demo_record_flags.sql +38 -0
  161. package/.framework/migrations/042_registration_hierarchy.sql +309 -0
  162. package/.framework/migrations/043_policy_actor_cleanup.sql +39 -0
  163. package/.framework/migrations/044_match_embeddings_filtered_knn.sql +151 -0
  164. package/.framework/migrations/045_security_critical_rls.sql +139 -0
  165. package/.framework/migrations/046_security_missing_rls.sql +79 -0
  166. package/.framework/migrations/047_people_updated_by.sql +27 -0
  167. package/.framework/migrations/048_watcher_last_seen_at.sql +24 -0
  168. package/.framework/migrations/049_security_blocklist.sql +148 -0
  169. package/.framework/migrations/050_notifications.sql +49 -0
  170. package/.framework/migrations/051_message_agent_fields.sql +74 -0
  171. package/.framework/migrations/052_registration_security.sql +421 -0
  172. package/.framework/migrations/053_builtin_action_seeds.sql +66 -0
  173. package/.framework/migrations/054_kb_ingest_lease.sql +157 -0
  174. package/.framework/migrations/055_type_id_drift_reconciliation.sql +33 -0
  175. package/.framework/migrations/056_slug_column_reconciliation.sql +38 -0
  176. package/.framework/migrations/057_pipelines_slug_identity.sql +14 -0
  177. package/.framework/migrations/058_account_data_field_declarations.sql +53 -0
  178. package/.framework/migrations/059_registration_placement_fixes.sql +269 -0
  179. package/.framework/migrations/060_account_person_record_permissions.sql +38 -0
  180. package/.framework/migrations/061_fk_dedup.sql +32 -0
  181. package/.framework/public/spine-logo.svg +10 -3
  182. package/.framework/scripts/app-install-cli.ts +190 -93
  183. package/.framework/scripts/assemble-frontend.sh +127 -44
  184. package/.framework/scripts/assemble-functions.sh +128 -30
  185. package/.framework/scripts/boundary-check.sh +6 -2
  186. package/.framework/scripts/build-manifest.sh +24 -68
  187. package/.framework/scripts/check-core-integrity.sh +15 -76
  188. package/.framework/scripts/checksum-manifest.mts +343 -0
  189. package/.framework/scripts/cil-migrate-markers.ts +403 -0
  190. package/.framework/scripts/fix-cil-markers.mjs +176 -0
  191. package/.framework/scripts/verify-integrity.sh +21 -57
  192. package/.framework/scripts/verify-manifest.mts +305 -0
  193. package/.framework/seeds/types/funnel_signal_use.json +74 -21
  194. package/.framework/seeds/types/spine_instance.json +73 -21
  195. package/.framework/src/App.tsx +118 -72
  196. package/.framework/src/apps/admin/index.tsx +855 -58
  197. package/.framework/src/components/AppWrapper.tsx +43 -45
  198. package/.framework/src/components/CustomAppLoader.tsx +160 -116
  199. package/.framework/src/components/admin/AdminListPage.tsx +46 -44
  200. package/.framework/src/components/admin/AdminSidebar.tsx +57 -47
  201. package/.framework/src/components/admin/AdminStatsCard.tsx +46 -44
  202. package/.framework/src/components/admin/PageInstructions.tsx +98 -2
  203. package/.framework/src/components/admin/SortableTableHeader.tsx +44 -45
  204. package/.framework/src/components/app-shell/GenericAppShell.tsx +64 -65
  205. package/.framework/src/components/app-shell/GenericDetailPage.tsx +44 -47
  206. package/.framework/src/components/app-shell/GenericListPage.tsx +45 -49
  207. package/.framework/src/components/app-sidebar.tsx +42 -45
  208. package/.framework/src/components/auth/ProtectedRoute.tsx +48 -41
  209. package/.framework/src/components/auth/TurnstileWidget.tsx +27 -0
  210. package/.framework/src/components/kb/KBArticleEditor.tsx +231 -22
  211. package/.framework/src/components/kb/KBArticleList.tsx +251 -10
  212. package/.framework/src/components/layout/AppShell.tsx +51 -45
  213. package/.framework/src/components/layout/Header.tsx +42 -43
  214. package/.framework/src/components/layout/Layout.tsx +46 -46
  215. package/.framework/src/components/layout/Sidebar.tsx +196 -96
  216. package/.framework/src/components/runtime/DataDetailHeader.tsx +55 -30
  217. package/.framework/src/components/runtime/DataDetailPage.tsx +31 -269
  218. package/.framework/src/components/runtime/DataFilters.tsx +49 -74
  219. package/.framework/src/components/runtime/DataHeader.tsx +53 -32
  220. package/.framework/src/components/runtime/DataListPage.tsx +51 -155
  221. package/.framework/src/components/runtime/DataStats.tsx +66 -44
  222. package/.framework/src/components/runtime/DataTable.tsx +49 -149
  223. package/.framework/src/components/runtime/SchemaDetailForm.tsx +45 -75
  224. package/.framework/src/components/runtime/index.ts +119 -16
  225. package/.framework/src/components/search-form.tsx +46 -29
  226. package/.framework/src/components/shared/AgentView.tsx +65 -48
  227. package/.framework/src/components/shared/FieldRenderer.tsx +144 -50
  228. package/.framework/src/components/shared/InviteManager.tsx +207 -97
  229. package/.framework/src/components/shared/MemberList.tsx +97 -0
  230. package/.framework/src/components/shared/SchemaFields.tsx +107 -86
  231. package/.framework/src/components/ui/DataTable.tsx +80 -68
  232. package/.framework/src/components/ui/Form.tsx +157 -146
  233. package/.framework/src/components/ui/ItemCard.tsx +74 -67
  234. package/.framework/src/components/ui/ItemListView.tsx +73 -68
  235. package/.framework/src/components/ui/LoadingSpinner.tsx +43 -48
  236. package/.framework/src/components/ui/Modal.tsx +78 -68
  237. package/.framework/src/components/ui/RichTextEditor.tsx +89 -69
  238. package/.framework/src/components/ui/accordion.tsx +85 -86
  239. package/.framework/src/components/ui/alert-dialog.tsx +197 -184
  240. package/.framework/src/components/ui/alert.tsx +105 -94
  241. package/.framework/src/components/ui/aspect-ratio.tsx +57 -43
  242. package/.framework/src/components/ui/avatar.tsx +122 -107
  243. package/.framework/src/components/ui/badge.tsx +60 -55
  244. package/.framework/src/components/ui/breadcrumb.tsx +127 -128
  245. package/.framework/src/components/ui/button-group.tsx +86 -72
  246. package/.framework/src/components/ui/button.tsx +71 -50
  247. package/.framework/src/components/ui/calendar.tsx +72 -57
  248. package/.framework/src/components/ui/card.tsx +136 -129
  249. package/.framework/src/components/ui/carousel.tsx +226 -107
  250. package/.framework/src/components/ui/chart.tsx +252 -147
  251. package/.framework/src/components/ui/checkbox.tsx +43 -44
  252. package/.framework/src/components/ui/collapsible.tsx +86 -71
  253. package/.framework/src/components/ui/combobox.tsx +282 -249
  254. package/.framework/src/components/ui/command.tsx +158 -146
  255. package/.framework/src/components/ui/context-menu.tsx +239 -240
  256. package/.framework/src/components/ui/dialog.tsx +174 -157
  257. package/.framework/src/components/ui/direction.tsx +72 -56
  258. package/.framework/src/components/ui/drawer.tsx +168 -169
  259. package/.framework/src/components/ui/dropdown-menu.tsx +254 -223
  260. package/.framework/src/components/ui/empty.tsx +131 -120
  261. package/.framework/src/components/ui/field.tsx +205 -173
  262. package/.framework/src/components/ui/hover-card.tsx +71 -72
  263. package/.framework/src/components/ui/input-group.tsx +148 -133
  264. package/.framework/src/components/ui/input-otp.tsx +99 -86
  265. package/.framework/src/components/ui/input.tsx +43 -41
  266. package/.framework/src/components/ui/item.tsx +207 -185
  267. package/.framework/src/components/ui/kbd.tsx +57 -56
  268. package/.framework/src/components/ui/label.tsx +45 -41
  269. package/.framework/src/components/ui/menubar.tsx +268 -236
  270. package/.framework/src/components/ui/native-select.tsx +85 -86
  271. package/.framework/src/components/ui/navigation-menu.tsx +166 -156
  272. package/.framework/src/components/ui/pagination.tsx +131 -141
  273. package/.framework/src/components/ui/popover.tsx +125 -128
  274. package/.framework/src/components/ui/progress.tsx +47 -44
  275. package/.framework/src/components/ui/radio-group.tsx +60 -55
  276. package/.framework/src/components/ui/resizable.tsx +85 -72
  277. package/.framework/src/components/ui/scroll-area.tsx +57 -58
  278. package/.framework/src/components/ui/select.tsx +182 -169
  279. package/.framework/src/components/ui/separator.tsx +42 -43
  280. package/.framework/src/components/ui/sheet.tsx +170 -159
  281. package/.framework/src/components/ui/sidebar.tsx +395 -398
  282. package/.framework/src/components/ui/skeleton.tsx +42 -43
  283. package/.framework/src/components/ui/slider.tsx +61 -44
  284. package/.framework/src/components/ui/sonner.tsx +44 -44
  285. package/.framework/src/components/ui/spinner.tsx +47 -42
  286. package/.framework/src/components/ui/switch.tsx +56 -42
  287. package/.framework/src/components/ui/table-primitives.tsx +272 -132
  288. package/.framework/src/components/ui/table.tsx +140 -142
  289. package/.framework/src/components/ui/tabs.tsx +110 -93
  290. package/.framework/src/components/ui/textarea.tsx +43 -44
  291. package/.framework/src/components/ui/toggle-group.tsx +87 -71
  292. package/.framework/src/components/ui/toggle.tsx +56 -56
  293. package/.framework/src/components/ui/tooltip.tsx +99 -85
  294. package/.framework/src/contexts/AppContext.tsx +166 -114
  295. package/.framework/src/contexts/AuthContext.tsx +232 -137
  296. package/.framework/src/hooks/use-mobile.ts +43 -44
  297. package/.framework/src/hooks/useApi.ts +185 -172
  298. package/.framework/src/hooks/useAppPath.ts +31 -29
  299. package/.framework/src/hooks/useApps.ts +77 -42
  300. package/.framework/src/hooks/useEntityList.ts +66 -29
  301. package/.framework/src/hooks/useEntityRecord.ts +76 -32
  302. package/.framework/src/hooks/useForm.ts +62 -30
  303. package/.framework/src/hooks/useListSchema.ts +60 -43
  304. package/.framework/src/hooks/useSchemaRecord.ts +115 -95
  305. package/.framework/src/lib/api.ts +258 -134
  306. package/.framework/src/lib/registration.ts +181 -0
  307. package/.framework/src/lib/supabase.ts +118 -81
  308. package/.framework/src/lib/utils.ts +266 -266
  309. package/.framework/src/main.tsx +43 -44
  310. package/.framework/src/pages/DashboardPage.tsx +44 -43
  311. package/.framework/src/pages/NoAppPage.tsx +50 -0
  312. package/.framework/src/pages/NotFoundPage.tsx +32 -29
  313. package/.framework/src/pages/SetupPage.tsx +34 -33
  314. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +69 -58
  315. package/.framework/src/pages/admin/AIAgentsPage.tsx +43 -40
  316. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +63 -55
  317. package/.framework/src/pages/admin/APIKeysPage.tsx +44 -42
  318. package/.framework/src/pages/admin/AlertsConfigPage.tsx +117 -94
  319. package/.framework/src/pages/admin/AppDetailPage.tsx +48 -42
  320. package/.framework/src/pages/admin/AppsPage.tsx +45 -42
  321. package/.framework/src/pages/admin/DeliveriesPage.tsx +49 -17
  322. package/.framework/src/pages/admin/DesignedPage.tsx +31 -30
  323. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +58 -0
  324. package/.framework/src/pages/admin/EmbeddingsPage.tsx +49 -0
  325. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +31 -29
  326. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +46 -29
  327. package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -29
  328. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +68 -55
  329. package/.framework/src/pages/admin/IntegrationsPage.tsx +45 -42
  330. package/.framework/src/pages/admin/InvitesPage.tsx +60 -44
  331. package/.framework/src/pages/admin/LogsPage.tsx +87 -137
  332. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +31 -29
  333. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +150 -89
  334. package/.framework/src/pages/admin/PipelineDetailPage.tsx +77 -104
  335. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +44 -43
  336. package/.framework/src/pages/admin/PipelinesPage.tsx +59 -145
  337. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +53 -42
  338. package/.framework/src/pages/admin/PromptConfigsPage.tsx +47 -117
  339. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +31 -44
  340. package/.framework/src/pages/admin/RoleDetailPage.tsx +49 -92
  341. package/.framework/src/pages/admin/RolesPage.tsx +47 -164
  342. package/.framework/src/pages/admin/SecurityPage.tsx +310 -0
  343. package/.framework/src/pages/admin/SelectTestPage.tsx +30 -32
  344. package/.framework/src/pages/admin/ShadcnTestPage.tsx +37 -44
  345. package/.framework/src/pages/admin/SimpleDashboard.tsx +32 -44
  346. package/.framework/src/pages/admin/TestRunDetailPage.tsx +97 -44
  347. package/.framework/src/pages/admin/TestingDashboard.tsx +126 -71
  348. package/.framework/src/pages/admin/TimerDetailPage.tsx +67 -55
  349. package/.framework/src/pages/admin/TimersPage.tsx +44 -42
  350. package/.framework/src/pages/admin/TriggerDetailPage.tsx +47 -42
  351. package/.framework/src/pages/admin/TriggersPage.tsx +58 -57
  352. package/.framework/src/pages/admin/TypeDetailPage.tsx +91 -55
  353. package/.framework/src/pages/admin/TypesPage.tsx +45 -42
  354. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +258 -128
  355. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +127 -123
  356. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +308 -235
  357. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +159 -110
  358. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +432 -0
  359. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +200 -178
  360. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +286 -239
  361. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +211 -90
  362. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +156 -143
  363. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +379 -0
  364. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +337 -0
  365. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +219 -214
  366. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
  367. package/.framework/src/pages/auth/AuthConfirmPage.tsx +135 -65
  368. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +39 -31
  369. package/.framework/src/pages/auth/LoginPage.tsx +38 -32
  370. package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -28
  371. package/.framework/src/pages/auth/RegisterPage.tsx +429 -155
  372. package/.framework/src/pages/spine-framework/APIPage.tsx +33 -30
  373. package/.framework/src/pages/spine-framework/CLIPage.tsx +32 -30
  374. package/.framework/src/types/auth.ts +101 -93
  375. package/.framework/src/types/types.ts +283 -262
  376. package/.framework/templates/project.json +87 -0
  377. package/.framework/templates/spine.config.neutral.json +7 -0
  378. package/.framework/tests/api/api-surface.test.ts +381 -0
  379. package/.framework/tests/fixtures/seed.ts +427 -0
  380. package/.framework/tests/fixtures/teardown.ts +228 -0
  381. package/.framework/tests/reporter.ts +351 -0
  382. package/.framework/tests/setup.ts +135 -0
  383. package/.framework/tests/ui/ui-sweep.ts +278 -0
  384. package/.framework/tests/unit/admin-data-logger.test.ts +310 -0
  385. package/.framework/tests/unit/agent-runner.test.ts +2389 -0
  386. package/.framework/tests/unit/ai-interactions.test.ts +81 -0
  387. package/.framework/tests/unit/app-manifest.test.ts +359 -0
  388. package/.framework/tests/unit/assembly-scripts.test.ts +172 -0
  389. package/.framework/tests/unit/cil-determinism.test.ts +85 -0
  390. package/.framework/tests/unit/core-isolation.test.ts +153 -0
  391. package/.framework/tests/unit/funnel-signals.test.ts +135 -0
  392. package/.framework/tests/unit/install-app.test.ts +1759 -0
  393. package/.framework/tests/unit/invites-security.test.ts +572 -0
  394. package/.framework/tests/unit/kb-ingest-lease.test.ts +287 -0
  395. package/.framework/tests/unit/kb-search.test.ts +119 -0
  396. package/.framework/tests/unit/migrate.test.ts +509 -0
  397. package/.framework/tests/unit/notify.test.ts +136 -0
  398. package/.framework/tests/unit/permissions.test.ts +269 -0
  399. package/.framework/tests/unit/pipeline-runner.test.ts +755 -0
  400. package/.framework/tests/unit/principal-cache.test.ts +138 -0
  401. package/.framework/tests/unit/retrieval-golden.test.ts +520 -0
  402. package/.framework/tests/unit/runtime-isolation.test.ts +642 -0
  403. package/.framework/tests/unit/schema-utils.test.ts +225 -0
  404. package/.framework/tests/unit/trigger-engine.test.ts +513 -0
  405. package/.framework/tests/unit/validate-app.test.ts +527 -0
  406. package/README.md +34 -3
  407. package/bin/spine-framework.cjs +1 -0
  408. package/config/tailwind.config.cjs +7 -0
  409. package/config/tsconfig.functions.json +42 -0
  410. package/config/tsconfig.json +37 -9
  411. package/config/vite.config.ts +31 -2
  412. package/netlify.toml +31 -3
  413. package/package.json +46 -29
  414. package/scripts/assemble-frontend.sh +127 -44
  415. package/scripts/assemble-functions.sh +127 -29
  416. package/scripts/boundary-check.sh +6 -2
  417. package/scripts/build-manifest.sh +24 -68
  418. package/scripts/checksum-manifest.mts +345 -0
  419. package/scripts/dev-clean.sh +86 -0
  420. package/scripts/dev-netlify.sh +49 -0
  421. package/scripts/netlify-dev-wrapper.sh +2 -0
  422. package/scripts/verify-install.ts +358 -0
  423. package/scripts/verify-integrity.sh +21 -57
  424. package/scripts/verify-manifest.mts +305 -0
  425. package/templates/project/gitignore +45 -0
  426. package/{config → templates/project}/package-lock.json +22335 -9366
  427. package/vitest.config.ts +46 -0
  428. package/.framework/public/spine.config.json +0 -91
  429. package/config/deno.lock +0 -108
  430. package/config/tsconfig.node.tsbuildinfo +0 -1
  431. package/config/tsconfig.tsbuildinfo +0 -1
  432. package/config/vite.config.d.ts +0 -2
  433. package/custom/.devin/AGENT.md +0 -357
  434. package/custom/.devin/skills/install-app/SKILL.md +0 -39
  435. package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +0 -39
  436. package/custom/.devin/skills/spine-workbench-idea/SKILL.md +0 -36
  437. package/custom/.devin/skills/spine-workbench-implement/SKILL.md +0 -46
  438. package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +0 -28
  439. package/custom/.devin/skills/spine-workbench-plan/SKILL.md +0 -38
  440. package/custom/.devin/workflows/app-install.yaml +0 -83
  441. package/custom/README.md +0 -79
  442. package/docs/README.md +0 -15
  443. package/scripts/app-install-cli.ts +0 -286
  444. package/scripts/check-core-integrity.sh +0 -82
  445. package/scripts/ingest-chunks.cjs +0 -202
  446. package/scripts/kb-chunk-parser.cjs +0 -312
  447. package/scripts/kb-chunk-parser.ts +0 -330
  448. package/scripts/kb-ingest-docs.ts +0 -203
  449. package/scripts/load-test-app-install.ts +0 -484
  450. package/scripts/test-login.js +0 -33
  451. package/spine.config.json +0 -91
@@ -0,0 +1,513 @@
1
+ // CIL[BEGIN stable_id="~/.framework/tests/unit/trigger-engine.test.ts:module_header:module_header" type="module_header" identity="module_header" parent="none"]
2
+ // CIL[DOC-MACRO purpose="Test setup and imports for trigger engine tests"]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Configure test environment and mock dependencies"]
4
+ // CIL[DOC-CONTEXT module="tests/unit/trigger-engine" layer="test-unit" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/pipeline-runner.ts,.framework/functions/_shared/trigger-engine.ts"]
5
+ // CIL[DOC-CONTRACT inputs="none" outputs="configured test mocks" errors="none" side_effects="Mocks database, audit, and pipeline runner"]
6
+ // CIL[DOC-MICRO logic_summary="Imports vitest, mocks db/audit/pipeline, imports trigger engine" notable_decisions="[]"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
8
+ // CIL[DOC-STABILITY stability="stable"]
9
+ // CIL[DOC-AUDIENCE audience="test"]
10
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
11
+ import type { CoreContext } from '../../functions/_shared/middleware.ts'
12
+
13
+ vi.mock('../../functions/_shared/db.ts', () => ({
14
+ adminDb: {
15
+ from: vi.fn(),
16
+ rpc: vi.fn()
17
+ }
18
+ }))
19
+
20
+ vi.mock('../../functions/_shared/audit.ts', () => ({
21
+ emitAudit: vi.fn().mockResolvedValue(undefined)
22
+ }))
23
+
24
+ vi.mock('../../functions/_shared/pipeline-runner.ts', () => ({
25
+ runPipeline: vi.fn().mockResolvedValue({
26
+ executionId: 'mock-exec-id',
27
+ pipelineId: 'mock-pipeline-id',
28
+ status: 'completed',
29
+ stages: [],
30
+ durationMs: 10
31
+ })
32
+ }))
33
+
34
+ import { checkAndFireTriggers, fireCreateTriggers, fireUpdateTriggers } from '../../functions/_shared/trigger-engine.ts'
35
+ import { runPipeline } from '../../functions/_shared/pipeline-runner.ts'
36
+ import { emitAudit } from '../../functions/_shared/audit.ts'
37
+ import { adminDb } from '../../functions/_shared/db.ts'
38
+ // CIL[DOC-VECTOR type="context" content="purpose='Test setup and imports for trigger engine tests'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/trigger-engine.ts,.framework/functions/_shared/pipeline-runner.ts"]
39
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
40
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
41
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
42
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
43
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
44
+ // CIL[END stable_id="~/.framework/tests/unit/trigger-engine.test.ts:module_header:module_header"]
45
+
46
+ // CIL[BEGIN stable_id="~/.framework/tests/unit/trigger-engine.test.ts:makeCtx:function" type="function" identity="makeCtx" parent="none"]
47
+ // CIL[DOC-MACRO purpose="Create test context with system principal"]
48
+ // CIL[DOC-RESPONSIBILITY responsibility="Generate test context objects"]
49
+ // CIL[DOC-CONTEXT module="tests/unit/trigger-engine" layer="test-unit" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/pipeline-runner.ts,.framework/functions/_shared/trigger-engine.ts,.framework/tests/unit/trigger-engine.test.ts"]
50
+ // CIL[DOC-CONTRACT inputs="none" outputs="CoreContext object" errors="none" side_effects="none"]
51
+ // CIL[DOC-MICRO logic_summary="Creates context with system machine principal and test data" notable_decisions="[]"]
52
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
53
+ // CIL[DOC-STABILITY stability="stable"]
54
+ function makeCtx(): CoreContext {
55
+ return {
56
+ principal: {
57
+ id: 'system', type: 'machine', accountId: null, scopes: ['*:*'],
58
+ provenance: { sourceType: 'manual', createdBy: null, invokedAt: new Date().toISOString() }
59
+ },
60
+ accountId: 'acct-1',
61
+ db: {},
62
+ requestId: 'req-test'
63
+ }
64
+ }
65
+ // CIL[DOC-VECTOR type="context" content="purpose='Create test context with system principal'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/trigger-engine.ts,.framework/functions/_shared/pipeline-runner.ts"]
66
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
67
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
68
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
69
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
70
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
71
+ // CIL[END stable_id="~/.framework/tests/unit/trigger-engine.test.ts:makeCtx:function"]
72
+
73
+ // CIL[BEGIN stable_id="~/.framework/tests/unit/trigger-engine.test.ts:makeTrigger:function" type="function" identity="makeTrigger" parent="none"]
74
+ // CIL[DOC-MACRO purpose="Create test trigger with default values"]
75
+ // CIL[DOC-RESPONSIBILITY responsibility="Generate test trigger objects"]
76
+ // CIL[DOC-CONTEXT module="tests/unit/trigger-engine" layer="test-unit" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/pipeline-runner.ts,.framework/functions/_shared/trigger-engine.ts,.framework/tests/unit/trigger-engine.test.ts"]
77
+ // CIL[DOC-CONTRACT inputs="overrides: Record<string, any>" outputs="trigger object" errors="none" side_effects="none"]
78
+ // CIL[DOC-MICRO logic_summary="Returns default trigger with overrides applied" notable_decisions="[]"]
79
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
80
+ // CIL[DOC-STABILITY stability="stable"]
81
+ function makeTrigger(overrides: Record<string, any> = {}) {
82
+ return {
83
+ id: 'trigger-1',
84
+ name: 'Test Trigger',
85
+ event_type: 'item_created',
86
+ pipeline_id: 'pipeline-1',
87
+ is_active: true,
88
+ config: {},
89
+ ...overrides
90
+ }
91
+ }
92
+ // CIL[DOC-VECTOR type="context" content="purpose='Create test trigger with default values'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/trigger-engine.ts,.framework/functions/_shared/pipeline-runner.ts"]
93
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
94
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
95
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
96
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
97
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
98
+ // CIL[END stable_id="~/.framework/tests/unit/trigger-engine.test.ts:makeTrigger:function"]
99
+
100
+ // CIL[BEGIN stable_id="~/.framework/tests/unit/trigger-engine.test.ts:mockDbTriggers:function" type="function" identity="mockDbTriggers" parent="none"]
101
+ // CIL[DOC-MACRO purpose="Mock database to return trigger list"]
102
+ // CIL[DOC-RESPONSIBILITY responsibility="Configure database mock for trigger queries"]
103
+ // CIL[DOC-CONTEXT module="tests/unit/trigger-engine" layer="test-unit" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/pipeline-runner.ts,.framework/functions/_shared/trigger-engine.ts,.framework/tests/unit/trigger-engine.test.ts"]
104
+ // CIL[DOC-CONTRACT inputs="triggers: any[]" outputs="mocked adminDb.from" errors="none" side_effects="Mocks adminDb.from"]
105
+ // CIL[DOC-MICRO logic_summary="Sets up adminDb.from mock to return provided triggers" notable_decisions="[]"]
106
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
107
+ // CIL[DOC-STABILITY stability="stable"]
108
+ function mockDbTriggers(triggers: any[]) {
109
+ const chain = {
110
+ select: vi.fn().mockReturnThis(),
111
+ eq: vi.fn().mockReturnThis(),
112
+ order: vi.fn().mockResolvedValue({ data: triggers, error: null })
113
+ }
114
+ vi.mocked(adminDb.from).mockReturnValue(chain as any)
115
+ }
116
+ // CIL[DOC-VECTOR type="context" content="purpose='Mock database to return trigger list'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/trigger-engine.ts,.framework/functions/_shared/pipeline-runner.ts"]
117
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
118
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
119
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
120
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
121
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
122
+ // CIL[END stable_id="~/.framework/tests/unit/trigger-engine.test.ts:mockDbTriggers:function"]
123
+
124
+ // CIL[BEGIN stable_id="~/.framework/tests/unit/trigger-engine.test.ts:mockDbTriggersWithUpdate:function" type="function" identity="mockDbTriggersWithUpdate" parent="none"]
125
+ // CIL[DOC-MACRO purpose="Mock database with trigger query and stat updates"]
126
+ // CIL[DOC-RESPONSIBILITY responsibility="Configure database mock for trigger operations"]
127
+ // CIL[DOC-CONTEXT module="tests/unit/trigger-engine" layer="test-unit" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/pipeline-runner.ts,.framework/functions/_shared/trigger-engine.ts,.framework/tests/unit/trigger-engine.test.ts"]
128
+ // CIL[DOC-CONTRACT inputs="triggers: any[]" outputs="mocked adminDb.from and adminDb.rpc" errors="none" side_effects="Mocks adminDb.from and adminDb.rpc"]
129
+ // CIL[DOC-MICRO logic_summary="Sets up mocks for trigger query and stat update operations" notable_decisions="[]"]
130
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
131
+ // CIL[DOC-STABILITY stability="stable"]
132
+ function mockDbTriggersWithUpdate(triggers: any[]) {
133
+ const updateChain = {
134
+ update: vi.fn().mockReturnThis(),
135
+ eq: vi.fn().mockResolvedValue({ data: null, error: null })
136
+ }
137
+ let callCount = 0
138
+ vi.mocked(adminDb.from).mockImplementation(() => {
139
+ callCount++
140
+ if (callCount === 1) {
141
+ return {
142
+ select: vi.fn().mockReturnThis(),
143
+ eq: vi.fn().mockReturnThis(),
144
+ order: vi.fn().mockResolvedValue({ data: triggers, error: null })
145
+ } as any
146
+ }
147
+ return updateChain as any
148
+ })
149
+ vi.mocked(adminDb.rpc).mockResolvedValue({ data: 1, error: null } as any)
150
+ }
151
+ // CIL[DOC-VECTOR type="context" content="purpose='Mock database with trigger query and stat updates'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/trigger-engine.ts,.framework/functions/_shared/pipeline-runner.ts"]
152
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
153
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
154
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
155
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
156
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
157
+ // CIL[END stable_id="~/.framework/tests/unit/trigger-engine.test.ts:mockDbTriggersWithUpdate:function"]
158
+
159
+ // CIL[BEGIN stable_id="~/.framework/tests/unit/trigger-engine.test.ts:describe_checkAndFireTriggers:block" type="block" identity="describe_checkAndFireTriggers" parent="none"]
160
+ // CIL[DOC-MACRO purpose="Test checkAndFireTriggers core functionality"]
161
+ // CIL[DOC-RESPONSIBILITY responsibility="Verify trigger execution and error handling"]
162
+ // CIL[DOC-CONTEXT module="tests/unit/trigger-engine" layer="test-unit" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/pipeline-runner.ts,.framework/functions/_shared/trigger-engine.ts,.framework/tests/unit/trigger-engine.test.ts"]
163
+ // CIL[DOC-CONTRACT inputs="none" outputs="test assertions" errors="none" side_effects="Tests trigger-engine.ts module"]
164
+ // CIL[DOC-MICRO logic_summary="Tests trigger matching, pipeline execution, audit emission, and error recovery" notable_decisions="[]"]
165
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
166
+ // CIL[DOC-STABILITY stability="stable"]
167
+ describe('checkAndFireTriggers', () => {
168
+ beforeEach(() => {
169
+ vi.clearAllMocks()
170
+ })
171
+
172
+ it('does nothing when no triggers match the event type', async () => {
173
+ mockDbTriggers([])
174
+ await checkAndFireTriggers('item_created', 'items', 'item-1', {}, makeCtx())
175
+ expect(runPipeline).not.toHaveBeenCalled()
176
+ })
177
+
178
+ it('does nothing when DB query errors', async () => {
179
+ const chain = {
180
+ select: vi.fn().mockReturnThis(),
181
+ eq: vi.fn().mockReturnThis(),
182
+ order: vi.fn().mockResolvedValue({ data: null, error: { message: 'DB error' } })
183
+ }
184
+ vi.mocked(adminDb.from).mockReturnValue(chain as any)
185
+ await checkAndFireTriggers('item_created', 'items', 'item-1', {}, makeCtx())
186
+ expect(runPipeline).not.toHaveBeenCalled()
187
+ })
188
+
189
+ it('fires pipeline for a matching trigger with no conditions', async () => {
190
+ mockDbTriggersWithUpdate([makeTrigger()])
191
+ await checkAndFireTriggers('item_created', 'items', 'item-1', {}, makeCtx())
192
+ expect(runPipeline).toHaveBeenCalledOnce()
193
+ expect(runPipeline).toHaveBeenCalledWith(
194
+ 'pipeline-1',
195
+ expect.objectContaining({
196
+ event: 'item_created',
197
+ entity: expect.objectContaining({ type: 'items', id: 'item-1' })
198
+ }),
199
+ expect.any(Object)
200
+ )
201
+ })
202
+
203
+ it('passes trigger metadata in the trigger data', async () => {
204
+ mockDbTriggersWithUpdate([makeTrigger({ id: 'trig-xyz', name: 'My Trigger' })])
205
+ await checkAndFireTriggers('item_created', 'items', 'item-1', {}, makeCtx())
206
+ expect(runPipeline).toHaveBeenCalledWith(
207
+ 'pipeline-1',
208
+ expect.objectContaining({
209
+ trigger: { id: 'trig-xyz', name: 'My Trigger' }
210
+ }),
211
+ expect.any(Object)
212
+ )
213
+ })
214
+
215
+ it('emits audit on successful trigger fire', async () => {
216
+ mockDbTriggersWithUpdate([makeTrigger()])
217
+ await checkAndFireTriggers('item_created', 'items', 'item-1', {}, makeCtx())
218
+ expect(emitAudit).toHaveBeenCalledWith(
219
+ expect.any(Object),
220
+ 'trigger.fired',
221
+ expect.objectContaining({ type: 'trigger', id: 'trigger-1' }),
222
+ expect.objectContaining({ execution_status: 'completed' })
223
+ )
224
+ })
225
+
226
+ it('emits audit.failed and continues when runPipeline throws', async () => {
227
+ mockDbTriggers([makeTrigger({ id: 'bad-trigger' })])
228
+ vi.mocked(runPipeline).mockRejectedValueOnce(new Error('Pipeline exploded'))
229
+ await checkAndFireTriggers('item_created', 'items', 'item-1', {}, makeCtx())
230
+ expect(emitAudit).toHaveBeenCalledWith(
231
+ expect.any(Object),
232
+ 'trigger.failed',
233
+ expect.objectContaining({ id: 'bad-trigger' }),
234
+ expect.objectContaining({ error: 'Pipeline exploded' })
235
+ )
236
+ })
237
+
238
+ it('fires all matching triggers, not just the first', async () => {
239
+ const t1 = makeTrigger({ id: 'trig-1', pipeline_id: 'pipe-1' })
240
+ const t2 = makeTrigger({ id: 'trig-2', pipeline_id: 'pipe-2' })
241
+ mockDbTriggersWithUpdate([t1, t2])
242
+ vi.mocked(runPipeline)
243
+ .mockResolvedValueOnce({ executionId: 'exec-1', pipelineId: 'pipe-1', status: 'completed', stages: [], durationMs: 5 })
244
+ .mockResolvedValueOnce({ executionId: 'exec-2', pipelineId: 'pipe-2', status: 'completed', stages: [], durationMs: 5 })
245
+
246
+ await checkAndFireTriggers('item_created', 'items', 'item-1', {}, makeCtx())
247
+ expect(runPipeline).toHaveBeenCalledTimes(2)
248
+ expect(runPipeline).toHaveBeenCalledWith('pipe-1', expect.any(Object), expect.any(Object))
249
+ expect(runPipeline).toHaveBeenCalledWith('pipe-2', expect.any(Object), expect.any(Object))
250
+ })
251
+
252
+ it('continues to fire remaining triggers after one fails', async () => {
253
+ const t1 = makeTrigger({ id: 'trig-fail', pipeline_id: 'pipe-1' })
254
+ const t2 = makeTrigger({ id: 'trig-ok', pipeline_id: 'pipe-2' })
255
+ mockDbTriggers([t1, t2])
256
+ vi.mocked(runPipeline)
257
+ .mockRejectedValueOnce(new Error('pipe-1 failed'))
258
+ .mockResolvedValueOnce({ executionId: 'exec-2', pipelineId: 'pipe-2', status: 'completed', stages: [], durationMs: 5 })
259
+
260
+ await checkAndFireTriggers('item_created', 'items', 'item-1', {}, makeCtx())
261
+ expect(runPipeline).toHaveBeenCalledTimes(2)
262
+ })
263
+ })
264
+ // CIL[DOC-VECTOR type="context" content="purpose='Test checkAndFireTriggers core functionality'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/trigger-engine.ts,.framework/functions/_shared/pipeline-runner.ts"]
265
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
266
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
267
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
268
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
269
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
270
+ // CIL[END stable_id="~/.framework/tests/unit/trigger-engine.test.ts:describe_checkAndFireTriggers:block"]
271
+
272
+ // CIL[BEGIN stable_id="~/.framework/tests/unit/trigger-engine.test.ts:describe_triggerConditionFiltering:block" type="block" identity="describe_triggerConditionFiltering" parent="none"]
273
+ // CIL[DOC-MACRO purpose="Test trigger condition filtering logic"]
274
+ // CIL[DOC-RESPONSIBILITY responsibility="Verify trigger condition evaluation"]
275
+ // CIL[DOC-CONTEXT module="tests/unit/trigger-engine" layer="test-unit" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/pipeline-runner.ts,.framework/functions/_shared/trigger-engine.ts,.framework/tests/unit/trigger-engine.test.ts"]
276
+ // CIL[DOC-CONTRACT inputs="none" outputs="test assertions" errors="none" side_effects="Tests trigger-engine.ts module"]
277
+ // CIL[DOC-MICRO logic_summary="Tests entity_type, type_slug, and filter condition matching" notable_decisions="[]"]
278
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
279
+ // CIL[DOC-STABILITY stability="stable"]
280
+ describe('trigger condition filtering', () => {
281
+ beforeEach(() => {
282
+ vi.clearAllMocks()
283
+ })
284
+
285
+ it('skips trigger when entity_type filter does not match', async () => {
286
+ const trigger = makeTrigger({ config: { entity_type: 'people' } })
287
+ mockDbTriggers([trigger])
288
+ await checkAndFireTriggers('item_created', 'items', 'item-1', {}, makeCtx())
289
+ expect(runPipeline).not.toHaveBeenCalled()
290
+ })
291
+
292
+ it('fires trigger when entity_type filter matches', async () => {
293
+ const trigger = makeTrigger({ config: { entity_type: 'items' } })
294
+ mockDbTriggersWithUpdate([trigger])
295
+ await checkAndFireTriggers('item_created', 'items', 'item-1', {}, makeCtx())
296
+ expect(runPipeline).toHaveBeenCalledOnce()
297
+ })
298
+
299
+ it('skips trigger when type_slug filter does not match', async () => {
300
+ const trigger = makeTrigger({ config: { type_slug: 'invoice' } })
301
+ mockDbTriggers([trigger])
302
+ await checkAndFireTriggers('item_created', 'items', 'item-1', { type_slug: 'support_ticket' }, makeCtx())
303
+ expect(runPipeline).not.toHaveBeenCalled()
304
+ })
305
+
306
+ it('fires trigger when type_slug filter matches', async () => {
307
+ const trigger = makeTrigger({ config: { type_slug: 'support_ticket' } })
308
+ mockDbTriggersWithUpdate([trigger])
309
+ await checkAndFireTriggers('item_created', 'items', 'item-1', { type_slug: 'support_ticket' }, makeCtx())
310
+ expect(runPipeline).toHaveBeenCalledOnce()
311
+ })
312
+
313
+ it('skips trigger when simple filter value does not match', async () => {
314
+ const trigger = makeTrigger({ config: { filters: { status: 'open' } } })
315
+ mockDbTriggers([trigger])
316
+ await checkAndFireTriggers('item_created', 'items', 'item-1', { status: 'closed' }, makeCtx())
317
+ expect(runPipeline).not.toHaveBeenCalled()
318
+ })
319
+
320
+ it('fires trigger when simple filter value matches', async () => {
321
+ const trigger = makeTrigger({ config: { filters: { status: 'open' } } })
322
+ mockDbTriggersWithUpdate([trigger])
323
+ await checkAndFireTriggers('item_created', 'items', 'item-1', { status: 'open' }, makeCtx())
324
+ expect(runPipeline).toHaveBeenCalledOnce()
325
+ })
326
+
327
+ it('fires trigger when array filter includes the value', async () => {
328
+ const trigger = makeTrigger({ config: { filters: { priority: ['high', 'critical'] } } })
329
+ mockDbTriggersWithUpdate([trigger])
330
+ await checkAndFireTriggers('item_created', 'items', 'item-1', { priority: 'high' }, makeCtx())
331
+ expect(runPipeline).toHaveBeenCalledOnce()
332
+ })
333
+
334
+ it('skips trigger when value not in array filter', async () => {
335
+ const trigger = makeTrigger({ config: { filters: { priority: ['high', 'critical'] } } })
336
+ mockDbTriggers([trigger])
337
+ await checkAndFireTriggers('item_created', 'items', 'item-1', { priority: 'low' }, makeCtx())
338
+ expect(runPipeline).not.toHaveBeenCalled()
339
+ })
340
+
341
+ it('resolves nested dot-notation filter paths', async () => {
342
+ const trigger = makeTrigger({ config: { filters: { 'data.region': 'us-west' } } })
343
+ mockDbTriggersWithUpdate([trigger])
344
+ await checkAndFireTriggers('item_created', 'items', 'item-1', { data: { region: 'us-west' } }, makeCtx())
345
+ expect(runPipeline).toHaveBeenCalledOnce()
346
+ })
347
+
348
+ it('resolves Postgres-style ->> filter paths against the data column', async () => {
349
+ const trigger = makeTrigger({ config: { filters: { "data->>'sender_type'": { $eq: 'agent' } } } })
350
+ mockDbTriggersWithUpdate([trigger])
351
+ await checkAndFireTriggers('message_created', 'messages', 'msg-1', { data: { sender_type: 'agent' } }, makeCtx())
352
+ expect(runPipeline).toHaveBeenCalledOnce()
353
+ })
354
+
355
+ it('maps plural table names to singular event types (fireCreateTriggers)', async () => {
356
+ const trigger = makeTrigger({ config: { entity_type: 'items' } })
357
+ mockDbTriggersWithUpdate([trigger])
358
+ // admin-data passes the table name 'items'; the seeded event is 'item_created'
359
+ await fireCreateTriggers('items', 'item-1', {}, makeCtx())
360
+ expect(runPipeline).toHaveBeenCalledOnce()
361
+ expect(runPipeline).toHaveBeenCalledWith(
362
+ 'pipeline-1',
363
+ expect.objectContaining({ event: 'item_created' }),
364
+ expect.any(Object)
365
+ )
366
+ })
367
+
368
+ it('maps plural table names to singular event types (fireUpdateTriggers)', async () => {
369
+ const trigger = makeTrigger({ config: { entity_type: 'items' } })
370
+ mockDbTriggersWithUpdate([trigger])
371
+ await fireUpdateTriggers('items', 'item-1', {}, makeCtx())
372
+ expect(runPipeline).toHaveBeenCalledWith(
373
+ 'pipeline-1',
374
+ expect.objectContaining({ event: 'item_updated' }),
375
+ expect.any(Object)
376
+ )
377
+ })
378
+
379
+ it('maps people → person for event types', async () => {
380
+ const trigger = makeTrigger({ config: { entity_type: 'people' } })
381
+ mockDbTriggersWithUpdate([trigger])
382
+ await fireCreateTriggers('people', 'person-1', {}, makeCtx())
383
+ expect(runPipeline).toHaveBeenCalledWith(
384
+ 'pipeline-1',
385
+ expect.objectContaining({ event: 'person_created' }),
386
+ expect.any(Object)
387
+ )
388
+ })
389
+
390
+ it('resolves type_slug from entityData.type_id when the slug is not inline', async () => {
391
+ const trigger = makeTrigger({ config: { entity_type: 'items', type_slug: 'kb_article' } })
392
+ const chain = {
393
+ select: vi.fn().mockReturnThis(),
394
+ eq: vi.fn().mockReturnThis(),
395
+ order: vi.fn().mockResolvedValue({ data: [trigger], error: null }),
396
+ maybeSingle: vi.fn().mockResolvedValue({ data: { slug: 'kb_article' }, error: null }),
397
+ update: vi.fn().mockReturnThis()
398
+ }
399
+ vi.mocked(adminDb.from).mockImplementation((table: string) => {
400
+ if (table === 'types') return chain as any
401
+ return chain as any
402
+ })
403
+ await checkAndFireTriggers('item_created', 'items', 'item-1', { type_id: 'type-uuid-1', status: 'published' }, makeCtx())
404
+ expect(runPipeline).toHaveBeenCalledOnce()
405
+ })
406
+
407
+ // CIL[DOC-NOTE type="behavior" content="The demo seed filter { data->>'ca_kb_candidate': { $eq: true } } relies on strict boolean equality — the jsonb value is a real boolean, so a string 'true' operand would never fire."]
408
+ it('matches a boolean $eq against a Postgres-style data->> filter path', async () => {
409
+ const trigger = makeTrigger({
410
+ config: {
411
+ type_slug: 'demo_support_ticket',
412
+ filters: { "data->>'ca_kb_candidate'": { $eq: true } }
413
+ }
414
+ })
415
+ mockDbTriggersWithUpdate([trigger])
416
+ await checkAndFireTriggers('item_updated', 'items', 'item-1', { type_slug: 'demo_support_ticket', data: { ca_kb_candidate: true } }, makeCtx())
417
+ expect(runPipeline).toHaveBeenCalledOnce()
418
+ })
419
+
420
+ it('does not fire a boolean data->> field when $eq uses the string "true"', async () => {
421
+ const trigger = makeTrigger({
422
+ config: { filters: { "data->>'ca_kb_candidate'": { $eq: 'true' } } }
423
+ })
424
+ mockDbTriggers([trigger])
425
+ await checkAndFireTriggers('item_updated', 'items', 'item-1', { data: { ca_kb_candidate: true } }, makeCtx())
426
+ expect(runPipeline).not.toHaveBeenCalled()
427
+ })
428
+
429
+ it('skips a boolean $eq filter when the data flag is false', async () => {
430
+ const trigger = makeTrigger({
431
+ config: { filters: { "data->>'ca_kb_candidate'": { $eq: true } } }
432
+ })
433
+ mockDbTriggers([trigger])
434
+ await checkAndFireTriggers('item_updated', 'items', 'item-1', { data: { ca_kb_candidate: false } }, makeCtx())
435
+ expect(runPipeline).not.toHaveBeenCalled()
436
+ })
437
+ })
438
+ // CIL[DOC-VECTOR type="context" content="purpose='Test trigger condition filtering logic'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/trigger-engine.ts,.framework/functions/_shared/pipeline-runner.ts"]
439
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
440
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
441
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
442
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
443
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
444
+ // CIL[END stable_id="~/.framework/tests/unit/trigger-engine.test.ts:describe_triggerConditionFiltering:block"]
445
+
446
+ // CIL[BEGIN stable_id="~/.framework/tests/unit/trigger-engine.test.ts:describe_filterOperators:block" type="block" identity="describe_filterOperators" parent="none"]
447
+ // CIL[DOC-MACRO purpose="Test filter operator evaluation logic"]
448
+ // CIL[DOC-RESPONSIBILITY responsibility="Verify filter operator implementations"]
449
+ // CIL[DOC-CONTEXT module="tests/unit/trigger-engine" layer="test-unit" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/pipeline-runner.ts,.framework/functions/_shared/trigger-engine.ts,.framework/tests/unit/trigger-engine.test.ts"]
450
+ // CIL[DOC-CONTRACT inputs="none" outputs="test assertions" errors="none" side_effects="Tests trigger-engine.ts module"]
451
+ // CIL[DOC-MICRO logic_summary="Tests all filter operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists" notable_decisions="[]"]
452
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
453
+ // CIL[DOC-STABILITY stability="stable"]
454
+ describe('filter operators', () => {
455
+ beforeEach(() => {
456
+ vi.clearAllMocks()
457
+ })
458
+
459
+ async function testOp(operator: Record<string, any>, entityData: any, shouldFire: boolean) {
460
+ const trigger = makeTrigger({ config: { filters: { score: operator } } })
461
+ if (shouldFire) {
462
+ mockDbTriggersWithUpdate([trigger])
463
+ } else {
464
+ mockDbTriggers([trigger])
465
+ }
466
+ await checkAndFireTriggers('item_created', 'items', 'item-1', entityData, makeCtx())
467
+ if (shouldFire) {
468
+ expect(runPipeline).toHaveBeenCalledOnce()
469
+ } else {
470
+ expect(runPipeline).not.toHaveBeenCalled()
471
+ }
472
+ vi.clearAllMocks()
473
+ }
474
+
475
+ it('$eq — fires when equal', () => testOp({ $eq: 10 }, { score: 10 }, true))
476
+ it('$eq — skips when not equal', () => testOp({ $eq: 10 }, { score: 5 }, false))
477
+
478
+ it('$ne — fires when not equal', () => testOp({ $ne: 10 }, { score: 5 }, true))
479
+ it('$ne — skips when equal', () => testOp({ $ne: 10 }, { score: 10 }, false))
480
+
481
+ it('$gt — fires when greater', () => testOp({ $gt: 5 }, { score: 10 }, true))
482
+ it('$gt — skips when equal', () => testOp({ $gt: 5 }, { score: 5 }, false))
483
+ it('$gt — skips when less', () => testOp({ $gt: 5 }, { score: 3 }, false))
484
+
485
+ it('$gte — fires when equal', () => testOp({ $gte: 5 }, { score: 5 }, true))
486
+ it('$gte — fires when greater', () => testOp({ $gte: 5 }, { score: 6 }, true))
487
+ it('$gte — skips when less', () => testOp({ $gte: 5 }, { score: 4 }, false))
488
+
489
+ it('$lt — fires when less', () => testOp({ $lt: 10 }, { score: 5 }, true))
490
+ it('$lt — skips when equal', () => testOp({ $lt: 10 }, { score: 10 }, false))
491
+
492
+ it('$lte — fires when equal', () => testOp({ $lte: 10 }, { score: 10 }, true))
493
+ it('$lte — fires when less', () => testOp({ $lte: 10 }, { score: 9 }, true))
494
+ it('$lte — skips when greater', () => testOp({ $lte: 10 }, { score: 11 }, false))
495
+
496
+ it('$in — fires when value in array', () => testOp({ $in: ['a', 'b', 'c'] }, { score: 'b' }, true))
497
+ it('$in — skips when value not in array', () => testOp({ $in: ['a', 'b'] }, { score: 'z' }, false))
498
+
499
+ it('$nin — fires when value not in array', () => testOp({ $nin: ['a', 'b'] }, { score: 'z' }, true))
500
+ it('$nin — skips when value in array', () => testOp({ $nin: ['a', 'b'] }, { score: 'a' }, false))
501
+
502
+ it('$exists:true — fires when field exists', () => testOp({ $exists: true }, { score: 0 }, true))
503
+ it('$exists:true — skips when field is null', () => testOp({ $exists: true }, { score: null }, false))
504
+ it('$exists:false — fires when field is null', () => testOp({ $exists: false }, { score: null }, true))
505
+ it('$exists:false — skips when field has value', () => testOp({ $exists: false }, { score: 1 }, false))
506
+ })
507
+ // CIL[DOC-VECTOR type="context" content="purpose='Test filter operator evaluation logic'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/trigger-engine.ts,.framework/functions/_shared/pipeline-runner.ts"]
508
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
509
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
510
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
511
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
512
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
513
+ // CIL[END stable_id="~/.framework/tests/unit/trigger-engine.test.ts:describe_filterOperators:block"]