spine-framework 0.3.144 → 0.4.0

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 +5051 -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 +20 -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,79 @@
1
+ -- CIL[BEGIN stable_id="~/.framework/migrations/046_security_missing_rls.sql:security_missing_rls:file" type="file" identity="security_missing_rls" parent="~/.framework/migrations/046_security_missing_rls.sql"]
2
+ -- CIL[DOC-MACRO purpose="Enable RLS on the nine tables that currently expose all rows to any PostgREST caller"]
3
+ -- CIL[DOC-RESPONSIBILITY responsibility="Enable row level security on account_paths, invites, alerts, observability, integration_routes, test_runs, test_cases, test_results, and _spine_migrations with policies matching each table's intended consumer"]
4
+ -- CIL[DOC-CONTEXT module="migrations" layer="database" related_files=".framework/migrations/006_security_hardening_rls.sql,.framework/migrations/045_security_critical_rls.sql,.framework/migrations/035_rate_limits.sql"]
5
+ -- CIL[DOC-CONTRACT inputs="none" outputs="RLS enabled + policies created" errors="SQL errors if referenced objects are missing" side_effects="Blocks direct PostgREST reads/writes previously allowed by missing RLS"]
6
+ -- CIL[DOC-MICRO logic_summary="account_paths is system-admin read (get_accessible_accounts SECURITY DEFINER still serves all lookups); invites/alerts/observability get account-scoped access on account_id; integration_routes/test_*/_spine_migrations are service_role-only infrastructure with no tenant use case" notable_decisions="all existing consumers use adminDb which bypasses RLS entirely — these policies only gate direct PostgREST access via the anon/user keys; service_role policies are declared explicitly for documentation even though service_role holds BYPASSRLS"]
7
+ -- CIL[DOC-CONFIDENCE pass="first" score="0.85" flags="none"]
8
+ -- CIL[DOC-STABILITY stability="stable"]
9
+
10
+ -- account_paths: the tenant-hierarchy closure table. Reading it directly
11
+ -- reveals every parent/child relationship without going through
12
+ -- get_accessible_accounts(). That SECURITY DEFINER function continues to serve
13
+ -- all legitimate lookups; direct reads are system-admin only.
14
+ ALTER TABLE public.account_paths ENABLE ROW LEVEL SECURITY;
15
+
16
+ CREATE POLICY account_paths_read ON public.account_paths FOR SELECT
17
+ USING (public.person_is_system_admin(public.current_actor_id()));
18
+
19
+ CREATE POLICY account_paths_service_role ON public.account_paths FOR ALL
20
+ TO service_role USING (true) WITH CHECK (true);
21
+
22
+ -- invites: invitation metadata is scoped to the issuing account. Invite tokens
23
+ -- themselves live on people.data (validated server-side via adminDb), so
24
+ -- account-scoped access covers admin list/revoke without exposing tokens.
25
+ ALTER TABLE public.invites ENABLE ROW LEVEL SECURITY;
26
+
27
+ CREATE POLICY invites_access ON public.invites FOR ALL
28
+ USING (account_id IN (SELECT public.get_accessible_accounts(public.current_actor_id())))
29
+ WITH CHECK (account_id IN (SELECT public.get_accessible_accounts(public.current_actor_id())));
30
+
31
+ CREATE POLICY invites_service_role ON public.invites FOR ALL
32
+ TO service_role USING (true) WITH CHECK (true);
33
+
34
+ -- alerts: account-scoped operational alerts.
35
+ ALTER TABLE public.alerts ENABLE ROW LEVEL SECURITY;
36
+
37
+ CREATE POLICY alerts_access ON public.alerts FOR ALL
38
+ USING (account_id IN (SELECT public.get_accessible_accounts(public.current_actor_id())))
39
+ WITH CHECK (account_id IN (SELECT public.get_accessible_accounts(public.current_actor_id())));
40
+
41
+ CREATE POLICY alerts_service_role ON public.alerts FOR ALL
42
+ TO service_role USING (true) WITH CHECK (true);
43
+
44
+ -- observability: account-scoped telemetry (agent runs, traces). Written only
45
+ -- via adminDb; account members can read their own telemetry.
46
+ ALTER TABLE public.observability ENABLE ROW LEVEL SECURITY;
47
+
48
+ CREATE POLICY observability_access ON public.observability FOR ALL
49
+ USING (account_id IN (SELECT public.get_accessible_accounts(public.current_actor_id())))
50
+ WITH CHECK (account_id IN (SELECT public.get_accessible_accounts(public.current_actor_id())));
51
+
52
+ CREATE POLICY observability_service_role ON public.observability FOR ALL
53
+ TO service_role USING (true) WITH CHECK (true);
54
+
55
+ -- test_runs / test_cases / test_results / _spine_migrations:
56
+ -- internal infrastructure consumed exclusively by adminDb in system-cron.ts,
57
+ -- tests.ts, system.ts, and cli. No tenant-facing use case — service_role only
58
+ -- (matching the rate_limits precedent in 035). integration_routes is not
59
+ -- covered — 004 drops it as dead schema.
60
+ ALTER TABLE public.test_runs ENABLE ROW LEVEL SECURITY;
61
+ CREATE POLICY test_runs_service_role ON public.test_runs FOR ALL
62
+ TO service_role USING (true) WITH CHECK (true);
63
+
64
+ ALTER TABLE public.test_cases ENABLE ROW LEVEL SECURITY;
65
+ CREATE POLICY test_cases_service_role ON public.test_cases FOR ALL
66
+ TO service_role USING (true) WITH CHECK (true);
67
+
68
+ ALTER TABLE public.test_results ENABLE ROW LEVEL SECURITY;
69
+ CREATE POLICY test_results_service_role ON public.test_results FOR ALL
70
+ TO service_role USING (true) WITH CHECK (true);
71
+
72
+ ALTER TABLE public._spine_migrations ENABLE ROW LEVEL SECURITY;
73
+ CREATE POLICY spine_migrations_service_role ON public._spine_migrations FOR ALL
74
+ TO service_role USING (true) WITH CHECK (true);
75
+ -- CIL[DOC-VECTOR type="context" content="purpose='Enable RLS on nine tables that were fully exposed to PostgREST.'; No verified external callers; imports: none"]
76
+ -- CIL[DOC-VECTOR type="blast_radius" content="Direct PostgREST access to account_paths/invites/alerts/observability/integration_routes/test_*/_spine_migrations is now gated; adminDb consumers unaffected (service_role bypasses RLS)" status="ready"]
77
+ -- CIL[DOC-VECTOR type="configuration" content="Depends on public.current_actor_id, public.person_is_system_admin, public.get_accessible_accounts; requires account_id column on invites/alerts/observability" status="ready"]
78
+ -- CIL[DOC-VECTOR type="constraint" content="Any client that read these tables via anon/user keys must move to a function path or accept denial" status="ready"]
79
+ -- CIL[END stable_id="~/.framework/migrations/046_security_missing_rls.sql:security_missing_rls:file"]
@@ -0,0 +1,27 @@
1
+ -- CIL[BEGIN stable_id="~/.framework/migrations/047_people_updated_by.sql:people_updated_by:file" type="file" identity="people_updated_by" parent="~/.framework/migrations/047_people_updated_by.sql"]
2
+ -- CIL[DOC-MACRO purpose="Add updated_by to entity tables missing it so admin-data PATCH stops failing for human callers"]
3
+ -- CIL[DOC-RESPONSIBILITY responsibility="Add nullable uuid updated_by columns to people, watchers, and attachments — the three entity tables that follow the created_by/updated_by audit convention but lacked the column"]
4
+ -- CIL[DOC-CONTEXT module="migrations" layer="database" related_files=".framework/functions/admin-data.ts,.framework/migrations/045_security_critical_rls.sql,.framework/migrations/046_security_missing_rls.sql"]
5
+ -- CIL[DOC-CONTRACT inputs="none" outputs="Three new nullable uuid columns" errors="none — add column if not exists is idempotent" side_effects="Enables admin-data to stamp updated_by on PATCH for people/watchers/attachments"]
6
+ -- CIL[DOC-MICRO logic_summary="admin-data's update handler unconditionally writes updated_by for every non-raw entity; PATCH on these three tables failed with a schema-cache error for human callers. Column shape matches sibling tables (items/accounts/threads/messages/links): nullable uuid, no FK — created_by/updated_by across the schema are plain uuid markers, not enforced references" notable_decisions="nullable and unindexed because no read path queries by updated_by today; kept people/watchers/attachments together since they share the identical gap"]
7
+ -- CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
8
+ -- CIL[DOC-STABILITY stability="stable"]
9
+
10
+ -- Migration 047: add updated_by to entity tables that follow the created_by/
11
+ -- updated_by audit convention but are missing the column. admin-data's update
12
+ -- handler unconditionally writes updated_by for every non-raw entity, so PATCH
13
+ -- on people/watchers/attachments currently fails for human callers with
14
+ -- "Could not find the 'updated_by' column ... in the schema cache".
15
+
16
+ alter table public.people add column if not exists updated_by uuid;
17
+ alter table public.watchers add column if not exists updated_by uuid;
18
+ alter table public.attachments add column if not exists updated_by uuid;
19
+
20
+ comment on column public.people.updated_by is 'Person id of the last updater; written by admin-data update handler';
21
+ comment on column public.watchers.updated_by is 'Person id of the last updater; written by admin-data update handler';
22
+ comment on column public.attachments.updated_by is 'Person id of the last updater; written by admin-data update handler';
23
+ -- CIL[DOC-VECTOR type="context" content="purpose='Fix admin-data PATCH failures on people/watchers/attachments by adding the missing updated_by column.'; No verified external callers; imports: none"]
24
+ -- CIL[DOC-VECTOR type="blast_radius" content="Human-caller updates via admin-data to people (user settings modal), watchers, and attachments now succeed instead of failing with a schema-cache error" status="ready"]
25
+ -- CIL[DOC-VECTOR type="configuration" content="None — plain ALTER TABLE; admin-data update handler consumes the column automatically" status="ready"]
26
+ -- CIL[DOC-VECTOR type="constraint" content="Column is a plain uuid marker with no FK, matching the created_by convention across the schema" status="ready"]
27
+ -- CIL[END stable_id="~/.framework/migrations/047_people_updated_by.sql:people_updated_by:file"]
@@ -0,0 +1,24 @@
1
+ -- CIL[BEGIN stable_id="~/.framework/migrations/048_watcher_last_seen_at.sql:watcher_last_seen_at:file" type="file" identity="watcher_last_seen_at" parent="~/.framework/migrations/048_watcher_last_seen_at.sql"]
2
+ -- CIL[DOC-MACRO purpose="Declare last_seen_at in the watcher type design_schema so read sanitize and update validation accept it"]
3
+ -- CIL[DOC-RESPONSIBILITY responsibility="Merge the last_seen_at field definition into the watcher type's design_schema.fields and validation_schema.fields"]
4
+ -- CIL[DOC-CONTEXT module="migrations" layer="database" related_files=".framework/functions/_shared/permissions.ts,custom/apps/*/hooks/useWatchers.ts"]
5
+ -- CIL[DOC-CONTRACT inputs="none" outputs="watcher type accepts data.last_seen_at on read/write" errors="none — jsonb_set with create_missing is idempotent" side_effects="Unread tracking (markSeen/hasUnreadActivity) works for watcher rows"]
6
+ -- CIL[DOC-MICRO logic_summary="sanitizeRecordData strips data keys not declared in design_schema.fields on read, and validateUpdatePermissions rejects them on PATCH — so watcher.data.last_seen_at (written by downstream markSeen hooks) was dropped both ways. Declaring the field makes it readable and writable for roles with record update (member, support). Non-system field: system fields are record columns, last_seen_at lives in data." notable_decisions="type rows are global (kind+slug unique) so updating the single watcher row covers every account"]
7
+ -- CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
8
+ -- CIL[DOC-STABILITY stability="stable"]
9
+
10
+ update public.types
11
+ set design_schema = jsonb_set(
12
+ design_schema,
13
+ '{fields,last_seen_at}',
14
+ '{"data_type":"datetime","label":"Last Seen","required":false,"validation":null}'::jsonb,
15
+ true
16
+ ),
17
+ validation_schema = jsonb_set(
18
+ coalesce(validation_schema, '{"fields":{}}'::jsonb),
19
+ '{fields,last_seen_at}',
20
+ '{"data_type":"datetime","required":false}'::jsonb,
21
+ true
22
+ )
23
+ where kind = 'watcher' and slug = 'watcher';
24
+ -- CIL[END stable_id="~/.framework/migrations/048_watcher_last_seen_at.sql:watcher_last_seen_at:file"]
@@ -0,0 +1,148 @@
1
+ -- CIL[BEGIN stable_id="~/.framework/migrations/049_security_blocklist.sql:security_blocklist:file" type="file" identity="security_blocklist" parent="~/.framework/migrations/049_security_blocklist.sql"]
2
+ -- CIL[DOC-MACRO purpose="Platform security layer: security_blocklist table, person geo RPCs, and schema declarations for security fields"]
3
+ -- CIL[DOC-RESPONSIBILITY responsibility="Create public.security_blocklist (platform-wide denylist for person/account/email/email_domain/ip), person_touch_geo + person_record_registration_geo RPCs for IP capture, and declare registration/last-seen geo fields plus AO injection flags in the affected type design_schemas"]
4
+ -- CIL[DOC-CONTEXT module="migrations" layer="database" related_files=".framework/functions/_shared/security.ts,.framework/functions/_shared/middleware.ts,.framework/functions/invites.ts,.framework/functions/security.ts"]
5
+ -- CIL[DOC-CONTRACT inputs="none" outputs="security_blocklist table, person_touch_geo + person_record_registration_geo functions, declared type fields" errors="none — CREATE IF NOT EXISTS / jsonb_set are idempotent" side_effects="Middleware geo stamping + blocklist enforcement + security admin report work"]
6
+ -- CIL[DOC-MICRO logic_summary="Blocklist rows are (type, value) unique with severity/expiry; geo fields live in people.data so no schema change; jsonb_set declares them on the person/ao types so admin-data sanitize doesn't strip them on read" notable_decisions="RLS service_role-only: blocklist reads/writes happen exclusively through _shared/security.ts and functions/security.ts; starter disposable-domain rows seed the email_domain check"]
7
+ -- CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
8
+ -- CIL[DOC-STABILITY stability="stable"]
9
+
10
+ -- ── security_blocklist ─────────────────────────────────────────────
11
+ -- Platform-wide denylist. Enforced at three chokepoints:
12
+ -- registration (invites.completeRegistration), authenticated request
13
+ -- (middleware.createHandler), public request IP (createPublicHandler).
14
+ CREATE TABLE IF NOT EXISTS public.security_blocklist (
15
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
16
+ type text NOT NULL CHECK (type IN ('ip', 'email', 'email_domain', 'person_id', 'account_id')),
17
+ value text NOT NULL,
18
+ severity text NOT NULL DEFAULT 'hard' CHECK (severity IN ('soft', 'hard')),
19
+ reason text,
20
+ banned_by uuid,
21
+ expires_at timestamptz,
22
+ revoked_at timestamptz,
23
+ created_at timestamptz NOT NULL DEFAULT now(),
24
+ UNIQUE (type, value)
25
+ );
26
+
27
+ CREATE INDEX IF NOT EXISTS idx_security_blocklist_lookup
28
+ ON public.security_blocklist (type, value)
29
+ WHERE revoked_at IS NULL;
30
+
31
+ ALTER TABLE public.security_blocklist ENABLE ROW LEVEL SECURITY;
32
+
33
+ -- Service-role only: all reads/writes flow through _shared/security.ts
34
+ -- (adminDb) and functions/security.ts (system-admin gated).
35
+ DROP POLICY IF EXISTS security_blocklist_service_role ON public.security_blocklist;
36
+ CREATE POLICY security_blocklist_service_role ON public.security_blocklist
37
+ FOR ALL TO service_role USING (true) WITH CHECK (true);
38
+
39
+ -- ── person_touch_geo ───────────────────────────────────────────────
40
+ -- Fire-and-forget last-seen geo stamp, called from middleware on every
41
+ -- authenticated request. Single-statement merge; does not touch
42
+ -- updated_at (record content did not change).
43
+ CREATE OR REPLACE FUNCTION public.person_touch_geo(p_person_id uuid, p_ip text, p_country text)
44
+ RETURNS void
45
+ LANGUAGE sql
46
+ SECURITY DEFINER
47
+ SET search_path = public
48
+ AS $$
49
+ UPDATE public.people
50
+ SET data = data || jsonb_build_object(
51
+ 'last_ip', p_ip,
52
+ 'last_country', p_country,
53
+ 'last_seen_at', now()
54
+ )
55
+ WHERE id = p_person_id;
56
+ $$;
57
+
58
+ REVOKE ALL ON FUNCTION public.person_touch_geo(uuid, text, text) FROM PUBLIC;
59
+ REVOKE ALL ON FUNCTION public.person_touch_geo(uuid, text, text) FROM anon;
60
+ REVOKE ALL ON FUNCTION public.person_touch_geo(uuid, text, text) FROM authenticated;
61
+ GRANT EXECUTE ON FUNCTION public.person_touch_geo(uuid, text, text) TO service_role;
62
+
63
+ -- ── person_record_registration_geo ─────────────────────────────────
64
+ -- First-seen geo stamp, called from invites.completeRegistration.
65
+ -- COALESCE keeps the FIRST recorded values (a later registration attempt
66
+ -- must not overwrite the original signup IP).
67
+ CREATE OR REPLACE FUNCTION public.person_record_registration_geo(p_person_id uuid, p_ip text, p_country text)
68
+ RETURNS void
69
+ LANGUAGE sql
70
+ SECURITY DEFINER
71
+ SET search_path = public
72
+ AS $$
73
+ UPDATE public.people
74
+ SET data = data || jsonb_build_object(
75
+ 'registration_ip', coalesce(data->>'registration_ip', p_ip),
76
+ 'registration_country', coalesce(data->>'registration_country', p_country)
77
+ )
78
+ WHERE id = p_person_id;
79
+ $$;
80
+
81
+ REVOKE ALL ON FUNCTION public.person_record_registration_geo(uuid, text, text) FROM PUBLIC;
82
+ REVOKE ALL ON FUNCTION public.person_record_registration_geo(uuid, text, text) FROM anon;
83
+ REVOKE ALL ON FUNCTION public.person_record_registration_geo(uuid, text, text) FROM authenticated;
84
+ GRANT EXECUTE ON FUNCTION public.person_record_registration_geo(uuid, text, text) TO service_role;
85
+
86
+ -- ── Declare geo/security fields on the person type ─────────────────
87
+ -- Without declaration, admin-data sanitizeRecordData strips these data
88
+ -- keys on read (same failure mode as watcher.last_seen_at, migration 048).
89
+ update public.types
90
+ set design_schema = jsonb_set(
91
+ design_schema,
92
+ '{fields}',
93
+ (design_schema->'fields') || '{
94
+ "registration_ip": {"data_type":"text","label":"Registration IP","required":false,"validation":null},
95
+ "registration_country": {"data_type":"text","label":"Registration Country","required":false,"validation":null},
96
+ "last_ip": {"data_type":"text","label":"Last IP","required":false,"validation":null},
97
+ "last_country": {"data_type":"text","label":"Last Country","required":false,"validation":null},
98
+ "last_seen_at": {"data_type":"datetime","label":"Last Seen","required":false,"validation":null}
99
+ }'::jsonb,
100
+ true
101
+ ),
102
+ validation_schema = jsonb_set(
103
+ coalesce(validation_schema, '{"fields":{}}'::jsonb),
104
+ '{fields}',
105
+ (coalesce(validation_schema, '{"fields":{}}'::jsonb)->'fields') || '{
106
+ "registration_ip": {"data_type":"text","required":false},
107
+ "registration_country": {"data_type":"text","required":false},
108
+ "last_ip": {"data_type":"text","required":false},
109
+ "last_country": {"data_type":"text","required":false},
110
+ "last_seen_at": {"data_type":"datetime","required":false}
111
+ }'::jsonb,
112
+ true
113
+ )
114
+ where kind = 'person' and slug = 'person';
115
+
116
+ -- ── Declare injection flags on Answer Once types ───────────────────
117
+ update public.types
118
+ set design_schema = jsonb_set(
119
+ design_schema,
120
+ '{fields}',
121
+ (design_schema->'fields') || '{
122
+ "injection_detected": {"data_type":"boolean","label":"Injection Detected","required":false,"validation":null},
123
+ "injection_pattern": {"data_type":"text","label":"Injection Pattern","required":false,"validation":null}
124
+ }'::jsonb,
125
+ true
126
+ ),
127
+ validation_schema = jsonb_set(
128
+ coalesce(validation_schema, '{"fields":{}}'::jsonb),
129
+ '{fields}',
130
+ (coalesce(validation_schema, '{"fields":{}}'::jsonb)->'fields') || '{
131
+ "injection_detected": {"data_type":"boolean","required":false},
132
+ "injection_pattern": {"data_type":"text","required":false}
133
+ }'::jsonb,
134
+ true
135
+ )
136
+ where slug in ('ao_ticket_message', 'ao_support_ticket');
137
+
138
+ -- ── Starter disposable-email domain denylist ───────────────────────
139
+ INSERT INTO public.security_blocklist (type, value, severity, reason)
140
+ SELECT 'email_domain', d, 'hard', 'Disposable email provider'
141
+ FROM (VALUES
142
+ ('mailinator.com'), ('tempmail.com'), ('temp-mail.org'),
143
+ ('guerrillamail.com'), ('10minutemail.com'), ('yopmail.com'),
144
+ ('maildrop.cc'), ('sharklasers.com'), ('dispostable.com'),
145
+ ('trashmail.com'), ('getnada.com'), ('mailnesia.com')
146
+ ) AS v(d)
147
+ ON CONFLICT (type, value) DO NOTHING;
148
+ -- CIL[END stable_id="~/.framework/migrations/049_security_blocklist.sql:security_blocklist:file"]
@@ -0,0 +1,49 @@
1
+ -- ── notifications: durable notification-delivery records ─────────────────────
2
+ -- send_notification previously wrote into watchers, which is a SUBSCRIPTION
3
+ -- table (target_type/target_id/person_id, unique per target+person) — not a
4
+ -- delivery log. This table holds actual deliveries: one row per recipient per
5
+ -- notification. watchers stays the "who is subscribed" record; notifications is
6
+ -- "what was sent".
7
+
8
+ CREATE TABLE IF NOT EXISTS public.notifications (
9
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
10
+ account_id uuid NOT NULL REFERENCES public.accounts(id),
11
+ person_id uuid NOT NULL, -- recipient
12
+ source_type text NOT NULL DEFAULT 'pipeline_execution',
13
+ source_id text, -- pipeline execution / request id (not always a uuid)
14
+ target_type text, -- entity the notification concerns
15
+ target_id uuid,
16
+ message text NOT NULL,
17
+ data jsonb NOT NULL DEFAULT '{}',
18
+ is_read boolean NOT NULL DEFAULT false,
19
+ read_at timestamptz,
20
+ created_at timestamptz NOT NULL DEFAULT now()
21
+ );
22
+
23
+ CREATE INDEX IF NOT EXISTS idx_notifications_inbox
24
+ ON public.notifications (account_id, person_id, is_read, created_at DESC);
25
+
26
+ CREATE INDEX IF NOT EXISTS idx_notifications_target
27
+ ON public.notifications (target_type, target_id);
28
+
29
+ ALTER TABLE public.notifications ENABLE ROW LEVEL SECURITY;
30
+
31
+ -- Recipients read and mark-read their own notifications. Delivery inserts go
32
+ -- through adminDb (service_role) from pipeline-runner / agent-runner.
33
+ DROP POLICY IF EXISTS notifications_recipient_read ON public.notifications;
34
+ CREATE POLICY notifications_recipient_read ON public.notifications FOR SELECT
35
+ USING (person_id = public.current_actor_id());
36
+
37
+ DROP POLICY IF EXISTS notifications_recipient_update ON public.notifications;
38
+ CREATE POLICY notifications_recipient_update ON public.notifications FOR UPDATE
39
+ USING (person_id = public.current_actor_id())
40
+ WITH CHECK (person_id = public.current_actor_id());
41
+
42
+ -- Account members can see deliveries into their workspace (admin/audit views).
43
+ DROP POLICY IF EXISTS notifications_account_read ON public.notifications;
44
+ CREATE POLICY notifications_account_read ON public.notifications FOR SELECT
45
+ USING (account_id IN (SELECT public.get_accessible_accounts(public.current_actor_id())));
46
+
47
+ DROP POLICY IF EXISTS notifications_service_role ON public.notifications;
48
+ CREATE POLICY notifications_service_role ON public.notifications
49
+ FOR ALL TO service_role USING (true) WITH CHECK (true);
@@ -0,0 +1,74 @@
1
+ -- CIL[BEGIN stable_id="~/.framework/migrations/051_message_agent_fields.sql:message_agent_fields:file" type="file" identity="message_agent_fields" parent="~/.framework/migrations/051_message_agent_fields.sql"]
2
+ -- CIL[DOC-MACRO purpose="Declare agent-written data keys on support_reply/community_reply so read sanitize stops stripping citations and evidence metadata"]
3
+ -- CIL[DOC-RESPONSIBILITY responsibility="Merge the full set of agent-runner-written data fields into the support_reply and community_reply message types' design_schema.fields and validation_schema.fields"]
4
+ -- CIL[DOC-CONTEXT module="migrations" layer="database" related_files=".framework/functions/_shared/permissions.ts,.framework/functions/_shared/agent-runner.ts,custom/apps/demo/views/CustomerView.tsx,custom/apps/portal/pages/TicketsPage.tsx"]
5
+ -- CIL[DOC-CONTRACT inputs="none" outputs="support_reply/community_reply message rows (existing and new) expose cited_sources, evidence_state and tool-step keys on admin-data reads" errors="none — jsonb concat merge and restamp are idempotent" side_effects="customer transcripts render cited-source chips, the grounded badge, and step narration identically on the feed and self-poll paths"]
6
+ -- CIL[DOC-MICRO logic_summary="agent-runner persists cited_sources/evidence_state/tools_used/tool-step keys into message.data, but sanitizeRecordData drops undeclared data.* keys for non-system-admin readers — so fetchThreadMessages silently returned retrieved_sources-only rows and CustomerView fell back to rendering all retrieved candidates as cited chips (8 chips for 1 citation). Same failure mode as watcher.last_seen_at (048) and person geo fields (049). Field shape mirrors sibling retrieved_sources: system-stamped, read-only for every record role." notable_decisions="types are global (kind+slug unique) so updating support_reply/community_reply covers demo and portal installs; ao_ticket_message already declares the full set and is skipped"]
7
+ -- CIL[DOC-LEARNING topic="stamped_schema" content="Types gain fields on two levels: updating public.types.design_schema only helps NEW records — runtime records snapshot design_schema/validation_schema at creation and must be restamped (see scripts/restamp-ao-record-schemas.ts pattern). Separately, once a field has a validation_schema entry, admin-data display-formats it on read (formatFieldData stringifies json, booleans become 'Yes'/'No') — consumers must parse defensively"]
8
+ -- CIL[DOC-CONFIDENCE pass="first" score="0.95" flags="none"]
9
+ -- CIL[DOC-STABILITY stability="stable"]
10
+
11
+ update public.types
12
+ set design_schema = jsonb_set(
13
+ design_schema,
14
+ '{fields}',
15
+ (design_schema->'fields') || '{
16
+ "cited_sources": {"data_type":"json","label":"Cited Sources","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
17
+ "evidence_state": {"data_type":"text","label":"Evidence State","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
18
+ "evidence_found": {"data_type":"boolean","label":"Evidence Found","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
19
+ "mean_similarity": {"data_type":"number","label":"Mean Similarity","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
20
+ "tools_used": {"data_type":"json","label":"Tools Used","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
21
+ "human_reply": {"data_type":"boolean","label":"Human Reply","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
22
+ "tool": {"data_type":"text","label":"Tool","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
23
+ "params": {"data_type":"json","label":"Tool Params","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
24
+ "tool_call_id": {"data_type":"text","label":"Tool Call ID","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
25
+ "result": {"data_type":"json","label":"Tool Result","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
26
+ "details_truncated": {"data_type":"boolean","label":"Details Truncated","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
27
+ "error": {"data_type":"text","label":"Error","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
28
+ "max_turns": {"data_type":"number","label":"Max Turns","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
29
+ "turn_count": {"data_type":"number","label":"Turn Count","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
30
+ "phase": {"data_type":"text","label":"Phase","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
31
+ "analysis_summary": {"data_type":"textarea","label":"Analysis Summary","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
32
+ "case_analysis_id": {"data_type":"text","label":"Case Analysis ID","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}},
33
+ "confidence_score": {"data_type":"number","label":"Confidence Score","system":true,"permissions":{"member":["read"],"support":["read"],"member_admin":["read"],"support_admin":["read"],"system_admin":["read"]}}
34
+ }'::jsonb,
35
+ true
36
+ ),
37
+ validation_schema = jsonb_set(
38
+ coalesce(validation_schema, '{"fields":{}}'::jsonb),
39
+ '{fields}',
40
+ (coalesce(validation_schema, '{"fields":{}}'::jsonb)->'fields') || '{
41
+ "cited_sources": {"data_type":"json","required":false},
42
+ "evidence_state": {"data_type":"text","required":false},
43
+ "evidence_found": {"data_type":"boolean","required":false},
44
+ "mean_similarity": {"data_type":"number","required":false},
45
+ "tools_used": {"data_type":"json","required":false},
46
+ "human_reply": {"data_type":"boolean","required":false},
47
+ "tool": {"data_type":"text","required":false},
48
+ "params": {"data_type":"json","required":false},
49
+ "tool_call_id": {"data_type":"text","required":false},
50
+ "result": {"data_type":"json","required":false},
51
+ "details_truncated": {"data_type":"boolean","required":false},
52
+ "error": {"data_type":"text","required":false},
53
+ "max_turns": {"data_type":"number","required":false},
54
+ "turn_count": {"data_type":"number","required":false},
55
+ "phase": {"data_type":"text","required":false},
56
+ "analysis_summary": {"data_type":"textarea","required":false},
57
+ "case_analysis_id": {"data_type":"text","required":false},
58
+ "confidence_score": {"data_type":"number","required":false}
59
+ }'::jsonb,
60
+ true
61
+ )
62
+ where kind = 'message' and slug in ('support_reply', 'community_reply');
63
+
64
+ -- Restamp existing message records — design_schema/validation_schema are
65
+ -- snapshotted onto each record at creation, so the type-level update alone
66
+ -- leaves historical rows still stripping the new fields on read.
67
+ update public.messages m
68
+ set design_schema = t.design_schema,
69
+ validation_schema = t.validation_schema
70
+ from public.types t
71
+ where m.type_id = t.id
72
+ and t.kind = 'message'
73
+ and t.slug in ('support_reply', 'community_reply');
74
+ -- CIL[END stable_id="~/.framework/migrations/051_message_agent_fields.sql:message_agent_fields:file"]