spine-framework 0.4.3 → 0.5.0-rc.4

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 (320) hide show
  1. package/.env.example +13 -3
  2. package/.framework/cli/commands/bootstrap.ts +392 -0
  3. package/.framework/cli/commands/dev.ts +91 -218
  4. package/.framework/cli/commands/doctor.ts +132 -26
  5. package/.framework/cli/commands/generate.ts +38 -298
  6. package/.framework/cli/commands/init.ts +20 -1
  7. package/.framework/cli/commands/migrate.ts +36 -30
  8. package/.framework/cli/commands/migrations.ts +16 -56
  9. package/.framework/cli/commands/upgrade.ts +35 -0
  10. package/.framework/cli/commands/validate-schema.ts +147 -0
  11. package/.framework/cli/context.ts +223 -110
  12. package/.framework/cli/index.ts +6 -0
  13. package/.framework/cli/lib/project-files.ts +241 -1
  14. package/.framework/functions/_shared/agent-runner.ts +1000 -81
  15. package/.framework/functions/_shared/cil.ts +2 -1
  16. package/.framework/functions/_shared/db.ts +3 -6
  17. package/.framework/functions/_shared/hash-api-key.ts +183 -79
  18. package/.framework/functions/_shared/kb.ts +61 -7
  19. package/.framework/functions/_shared/logging.ts +562 -224
  20. package/.framework/functions/_shared/message-sequence.ts +53 -0
  21. package/.framework/functions/_shared/middleware.ts +47 -44
  22. package/.framework/functions/_shared/pipeline-runner.ts +150 -37
  23. package/.framework/functions/_shared/principal.ts +9 -6
  24. package/.framework/functions/_shared/trigger-engine.ts +149 -40
  25. package/.framework/functions/admin-data.ts +48 -31
  26. package/.framework/functions/ai-agents.ts +103 -33
  27. package/.framework/functions/api-keys.ts +301 -122
  28. package/.framework/functions/apps.ts +43 -26
  29. package/.framework/functions/cil-ingest.ts +48 -15
  30. package/.framework/functions/debug-auth.ts +14 -8
  31. package/.framework/functions/deliveries.ts +39 -12
  32. package/.framework/functions/embeddings.ts +145 -76
  33. package/.framework/functions/integration-outbound.ts +67 -27
  34. package/.framework/functions/integrations.ts +254 -127
  35. package/.framework/functions/logs.ts +273 -133
  36. package/.framework/functions/observability.ts +277 -147
  37. package/.framework/functions/pipeline-executions.ts +1 -1
  38. package/.framework/functions/pipeline-runner-background.ts +120 -0
  39. package/.framework/functions/pipelines.ts +14 -9
  40. package/.framework/functions/prompt-configs.ts +7 -4
  41. package/.framework/functions/roles.ts +8 -5
  42. package/.framework/functions/security.ts +30 -17
  43. package/.framework/functions/system-cron.ts +250 -128
  44. package/.framework/functions/tests.ts +7 -6
  45. package/.framework/functions/timers.ts +310 -107
  46. package/.framework/functions/trigger-scheduler.ts +65 -5
  47. package/.framework/functions/triggers.ts +28 -13
  48. package/.framework/functions/types.ts +13 -10
  49. package/.framework/migrations/064_episode_leases.sql +196 -0
  50. package/.framework/migrations/065_execution_tables_updated_at.sql +20 -0
  51. package/.framework/migrations/066_episode_steal_thread_merge.sql +148 -0
  52. package/.framework/migrations/067_episode_lease_stale_steal.sql +93 -0
  53. package/.framework/migrations/068_cron_schedule_timer_rpcs.sql +251 -0
  54. package/.framework/migrations/069_log_stats_window.sql +54 -0
  55. package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
  56. package/.framework/migrations/071_timer_interval_keys.sql +96 -0
  57. package/.framework/migrations/072_slug_autofill.sql +77 -0
  58. package/.framework/migrations/073_seed_member_roles.sql +26 -0
  59. package/.framework/schemas/spine.config.schema.json +62 -0
  60. package/.framework/src/App.tsx +3 -1
  61. package/.framework/src/apps/admin/index.tsx +1141 -775
  62. package/.framework/src/components/ErrorBoundary.tsx +136 -0
  63. package/.framework/src/components/admin/AdminListPage.tsx +81 -73
  64. package/.framework/src/components/admin/AdminSidebar.tsx +92 -81
  65. package/.framework/src/components/admin/EntitySelect.tsx +181 -0
  66. package/.framework/src/components/admin/PageInstructions.tsx +86 -127
  67. package/.framework/src/components/app-shell/GenericAppShell.tsx +3 -1
  68. package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
  69. package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
  70. package/.framework/src/components/auth/TurnstileWidget.tsx +9 -6
  71. package/.framework/src/components/kb/KBArticleEditor.tsx +49 -6
  72. package/.framework/src/components/layout/Layout.tsx +4 -2
  73. package/.framework/src/components/layout/Sidebar.tsx +304 -179
  74. package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
  75. package/.framework/src/components/runtime/DataHeader.tsx +96 -48
  76. package/.framework/src/components/runtime/DataListPage.tsx +3 -26
  77. package/.framework/src/components/runtime/DataStats.tsx +10 -10
  78. package/.framework/src/components/runtime/DataTable.tsx +12 -10
  79. package/.framework/src/components/ui/sheet.tsx +24 -26
  80. package/.framework/src/components/ui/textarea.tsx +74 -48
  81. package/.framework/src/hooks/useBranding.ts +47 -0
  82. package/.framework/src/hooks/useEntityList.ts +12 -9
  83. package/.framework/src/hooks/useListSchema.ts +108 -58
  84. package/.framework/src/instructions/README.md +57 -0
  85. package/.framework/src/instructions/ai-agents.md +69 -0
  86. package/.framework/src/instructions/alerts.md +80 -0
  87. package/.framework/src/instructions/api-keys.md +87 -0
  88. package/.framework/src/instructions/apps.md +77 -0
  89. package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
  90. package/.framework/src/instructions/concepts/apps-and-renderers.md +162 -0
  91. package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
  92. package/.framework/src/instructions/concepts/automation.md +186 -0
  93. package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
  94. package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
  95. package/.framework/src/instructions/concepts/design-schema.md +152 -0
  96. package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
  97. package/.framework/src/instructions/concepts/observability.md +116 -0
  98. package/.framework/src/instructions/concepts/permissions.md +150 -0
  99. package/.framework/src/instructions/concepts/runtime-records.md +111 -0
  100. package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
  101. package/.framework/src/instructions/concepts/spine-way.md +172 -0
  102. package/.framework/src/instructions/deliveries.md +59 -0
  103. package/.framework/src/instructions/guide/00-orientation.md +106 -0
  104. package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
  105. package/.framework/src/instructions/guide/02-project-map.md +147 -0
  106. package/.framework/src/instructions/guide/03-domain-model.md +223 -0
  107. package/.framework/src/instructions/guide/04-first-app.md +227 -0
  108. package/.framework/src/instructions/guide/05-glossary.md +183 -0
  109. package/.framework/src/instructions/integrations.md +96 -0
  110. package/.framework/src/instructions/internal/cil-markers.md +83 -0
  111. package/.framework/src/instructions/invites.md +60 -0
  112. package/.framework/src/instructions/kb.md +80 -0
  113. package/.framework/src/instructions/logs.md +77 -0
  114. package/.framework/src/instructions/observability.md +61 -0
  115. package/.framework/src/instructions/operations/deployment.md +115 -0
  116. package/.framework/src/instructions/operations/migrations.md +125 -0
  117. package/.framework/src/instructions/operations/security-checklist.md +148 -0
  118. package/.framework/src/instructions/operations/troubleshooting.md +170 -0
  119. package/.framework/src/instructions/operations/upgrade.md +116 -0
  120. package/.framework/src/instructions/pipeline-executions.md +62 -0
  121. package/.framework/src/instructions/pipelines.md +78 -0
  122. package/.framework/src/instructions/prompts.md +95 -0
  123. package/.framework/src/instructions/reference/api/admin-data.md +162 -0
  124. package/.framework/src/instructions/reference/api/auth.md +113 -0
  125. package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
  126. package/.framework/src/instructions/reference/app-manifest.md +150 -0
  127. package/.framework/src/instructions/reference/cli.md +124 -0
  128. package/.framework/src/instructions/reference/database.md +132 -0
  129. package/.framework/src/instructions/reference/design-schema.md +280 -0
  130. package/.framework/src/instructions/reference/env-vars.md +133 -0
  131. package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
  132. package/.framework/src/instructions/reference/functions/admin-data.md +195 -0
  133. package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
  134. package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
  135. package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
  136. package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
  137. package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
  138. package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
  139. package/.framework/src/instructions/reference/functions/apps.md +140 -0
  140. package/.framework/src/instructions/reference/functions/auth.md +99 -0
  141. package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
  142. package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
  143. package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
  144. package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
  145. package/.framework/src/instructions/reference/functions/index.md +103 -0
  146. package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
  147. package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
  148. package/.framework/src/instructions/reference/functions/integrations.md +130 -0
  149. package/.framework/src/instructions/reference/functions/invites.md +182 -0
  150. package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
  151. package/.framework/src/instructions/reference/functions/kb.md +166 -0
  152. package/.framework/src/instructions/reference/functions/logs.md +141 -0
  153. package/.framework/src/instructions/reference/functions/observability.md +105 -0
  154. package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
  155. package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
  156. package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
  157. package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
  158. package/.framework/src/instructions/reference/functions/roles.md +121 -0
  159. package/.framework/src/instructions/reference/functions/security.md +140 -0
  160. package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
  161. package/.framework/src/instructions/reference/functions/system.md +106 -0
  162. package/.framework/src/instructions/reference/functions/tests.md +97 -0
  163. package/.framework/src/instructions/reference/functions/timers.md +117 -0
  164. package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
  165. package/.framework/src/instructions/reference/functions/triggers.md +140 -0
  166. package/.framework/src/instructions/reference/functions/types.md +146 -0
  167. package/.framework/src/instructions/reference/seeds.md +126 -0
  168. package/.framework/src/instructions/reference/shared-modules.md +127 -0
  169. package/.framework/src/instructions/reference/spine-config.md +114 -0
  170. package/.framework/src/instructions/roles.md +80 -0
  171. package/.framework/src/instructions/runtime-detail.md +70 -0
  172. package/.framework/src/instructions/runtime-list.md +77 -0
  173. package/.framework/src/instructions/security.md +67 -0
  174. package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
  175. package/.framework/src/instructions/tasks/add-a-role.md +96 -0
  176. package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
  177. package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
  178. package/.framework/src/instructions/tasks/add-a-type.md +151 -0
  179. package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
  180. package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
  181. package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
  182. package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
  183. package/.framework/src/instructions/tasks/package-and-install-an-app.md +127 -0
  184. package/.framework/src/instructions/tasks/test-your-code.md +108 -0
  185. package/.framework/src/instructions/tasks/write-a-function.md +132 -0
  186. package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
  187. package/.framework/src/instructions/testing.md +59 -0
  188. package/.framework/src/instructions/timers.md +82 -0
  189. package/.framework/src/instructions/triggers.md +69 -0
  190. package/.framework/src/instructions/types.md +93 -0
  191. package/.framework/src/lib/branding.ts +128 -0
  192. package/.framework/src/pages/NoAppPage.tsx +3 -1
  193. package/.framework/src/pages/NotFoundPage.tsx +62 -31
  194. package/.framework/src/pages/SetupPage.tsx +5 -2
  195. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
  196. package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
  197. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
  198. package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
  199. package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
  200. package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
  201. package/.framework/src/pages/admin/AppsPage.tsx +104 -66
  202. package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
  203. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
  204. package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
  205. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
  206. package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
  207. package/.framework/src/pages/admin/LogsPage.tsx +144 -76
  208. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
  209. package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
  210. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
  211. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
  212. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
  213. package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
  214. package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
  215. package/.framework/src/pages/admin/RolesPage.tsx +86 -43
  216. package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
  217. package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
  218. package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
  219. package/.framework/src/pages/admin/TimersPage.tsx +90 -62
  220. package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
  221. package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
  222. package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
  223. package/.framework/src/pages/admin/TypesPage.tsx +90 -48
  224. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
  225. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
  226. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
  227. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
  228. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
  229. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
  230. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
  231. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
  232. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
  233. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
  234. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
  235. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
  236. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
  237. package/.framework/src/pages/auth/AuthConfirmPage.tsx +3 -1
  238. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +3 -1
  239. package/.framework/src/pages/auth/LoginPage.tsx +4 -2
  240. package/.framework/src/pages/auth/RegisterPage.tsx +3 -1
  241. package/.framework/templates/agent/AGENTS.md +150 -0
  242. package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
  243. package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
  244. package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
  245. package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
  246. package/.framework/templates/agent/skills/spine-install-app/SKILL.md +72 -0
  247. package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
  248. package/.framework/templates/agent/skills/spine-new-app/SKILL.md +67 -0
  249. package/.framework/templates/agent/skills/spine-new-function/SKILL.md +65 -0
  250. package/.framework/templates/agent/skills/spine-new-type/SKILL.md +65 -0
  251. package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
  252. package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
  253. package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
  254. package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
  255. package/.framework/templates/project.json +5 -1
  256. package/.framework/tests/unit/account-scoping-gates.test.ts +392 -0
  257. package/.framework/tests/unit/agent-files.test.ts +355 -0
  258. package/.framework/tests/unit/agent-runner.test.ts +496 -47
  259. package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
  260. package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
  261. package/.framework/tests/unit/bootstrap.test.ts +242 -0
  262. package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
  263. package/.framework/tests/unit/debug-auth.test.ts +38 -0
  264. package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
  265. package/.framework/tests/unit/episode-lease.test.ts +695 -0
  266. package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
  267. package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
  268. package/.framework/tests/unit/kb-ingest-lease.test.ts +19 -0
  269. package/.framework/tests/unit/logging-app-id.test.ts +75 -0
  270. package/.framework/tests/unit/pipeline-runner-background.test.ts +120 -0
  271. package/.framework/tests/unit/pipeline-runner.test.ts +153 -1
  272. package/.framework/tests/unit/principal-cache.test.ts +15 -0
  273. package/.framework/tests/unit/system-context-denial.test.ts +145 -0
  274. package/.framework/tests/unit/system-cron.test.ts +240 -0
  275. package/.framework/tests/unit/timers.test.ts +159 -0
  276. package/.framework/tests/unit/trigger-engine.test.ts +278 -91
  277. package/.framework/tests/unit/trigger-scheduler.test.ts +78 -0
  278. package/README.md +125 -166
  279. package/config/tsconfig.cli.json +2 -2
  280. package/netlify.toml +5 -0
  281. package/package.json +15 -4
  282. package/templates/project/package-lock.json +2 -2
  283. package/.framework/docs/admin-routes.md +0 -76
  284. package/.framework/docs/api-docs-progress.md +0 -38
  285. package/.framework/docs/api-governance.md +0 -146
  286. package/.framework/docs/api-testing-results.md +0 -212
  287. package/.framework/docs/assembly-launch-guide.md +0 -138
  288. package/.framework/docs/audit-results.md +0 -590
  289. package/.framework/docs/db-api-inventory.md +0 -95
  290. package/.framework/docs/gap-remediation-backlog.md +0 -103
  291. package/.framework/docs/ui-adoption-verification.md +0 -111
  292. package/.framework/docs/ui-api-coverage.md +0 -84
  293. package/.framework/docs/v2-compatibility-audit.md +0 -228
  294. package/.framework/mcp/index.ts +0 -133
  295. package/.framework/mcp/load-env.ts +0 -60
  296. package/.framework/mcp/shared/app-manifest.ts +0 -275
  297. package/.framework/mcp/shared/db.ts +0 -477
  298. package/.framework/mcp/shared/kb.ts +0 -118
  299. package/.framework/mcp/tools/architect.ts +0 -431
  300. package/.framework/mcp/tools/cil/context.ts +0 -345
  301. package/.framework/mcp/tools/cil/graph.ts +0 -242
  302. package/.framework/mcp/tools/cil/ingest.ts +0 -1217
  303. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
  304. package/.framework/mcp/tools/cil/pipeline.ts +0 -767
  305. package/.framework/mcp/tools/cil/project.ts +0 -791
  306. package/.framework/mcp/tools/cil/retrieval.ts +0 -336
  307. package/.framework/mcp/tools/cil/search-core.ts +0 -454
  308. package/.framework/mcp/tools/cil/search.ts +0 -97
  309. package/.framework/mcp/tools/cil/suggest.ts +0 -186
  310. package/.framework/mcp/tools/cil/validate.ts +0 -1369
  311. package/.framework/mcp/tools/kb/delete.ts +0 -139
  312. package/.framework/mcp/tools/kb/index.ts +0 -52
  313. package/.framework/mcp/tools/kb/ingest.ts +0 -84
  314. package/.framework/mcp/tools/kb/list-types.ts +0 -102
  315. package/.framework/mcp/tools/kb/publish.ts +0 -100
  316. package/.framework/mcp/tools/kb/reindex.ts +0 -86
  317. package/.framework/mcp/tools/kb/revoke.ts +0 -85
  318. package/.framework/mcp/tools/kb/search.ts +0 -101
  319. package/.framework/mcp/tools/kb/upsert.ts +0 -125
  320. package/.framework/mcp/tools/observability.ts +0 -510
@@ -52,15 +52,14 @@ import { adminDb } from './_shared/db'
52
52
  import { emitLog } from './_shared/audit'
53
53
  import { isSystemAdmin } from './_shared/principal'
54
54
  import { PermissionEngine, sanitizeRecordData } from './_shared/permissions'
55
+ // CIL[END stable_id="~/.framework/functions/apps.ts:module_header:module_header"]
55
56
  // CIL[DOC-VECTOR type="context" content="purpose='Application management handlers and CRUD operations for public.apps'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
56
57
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
57
58
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
58
59
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
59
60
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
60
61
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
61
- // CIL[END stable_id="~/.framework/functions/apps.ts:module_header:module_header"]
62
62
 
63
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:permissions:constant" type="constant" identity="permissions" parent="~/.framework/functions/apps.ts"]
64
63
  // CIL[DOC-MACRO purpose="Type alias shim for PermissionEngine"]
65
64
  // CIL[DOC-RESPONSIBILITY responsibility="Reference PermissionEngine with loose typing for app handlers"]
66
65
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -68,15 +67,15 @@ import { PermissionEngine, sanitizeRecordData } from './_shared/permissions'
68
67
  // CIL[DOC-MICRO logic_summary="Casts PermissionEngine to any to avoid strict type errors in this module" notable_decisions="Should be replaced by a properly typed export from the permissions engine"]
69
68
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
70
69
  // CIL[DOC-STABILITY stability="stable"]
70
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:permissions:constant" type="constant" identity="permissions" parent="~/.framework/functions/apps.ts"]
71
71
  const permissions = PermissionEngine as any
72
+ // CIL[END stable_id="~/.framework/functions/apps.ts:permissions:constant"]
72
73
  // CIL[DOC-VECTOR type="context" content="purpose='Type alias shim for PermissionEngine'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
73
74
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
74
75
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
75
76
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
76
77
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
77
78
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
78
- // CIL[END stable_id="~/.framework/functions/apps.ts:permissions:constant"]
79
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:list:constant" type="constant" identity="list" parent="~/.framework/functions/apps.ts"]
80
79
  // CIL[DOC-MACRO purpose="List apps for an account with optional filters"]
81
80
  // CIL[DOC-RESPONSIBILITY responsibility="Return a sanitized list of apps accessible to the caller's roles"]
82
81
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -84,6 +83,7 @@ const permissions = PermissionEngine as any
84
83
  // CIL[DOC-MICRO logic_summary="Resolves target account, selects adminDb for system admins, calls get_account_apps RPC, and sanitizes each record" notable_decisions="Defaults include_system to true unless explicitly false; uses sanitizeRecordData per row"]
85
84
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
86
85
  // CIL[DOC-STABILITY stability="stable"]
86
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:list:constant" type="constant" identity="list" parent="~/.framework/functions/apps.ts"]
87
87
  export const list = createHandler(async (ctx, body) => {
88
88
  const { include_system, include_inactive, account_id } = ctx.query || {}
89
89
 
@@ -117,14 +117,13 @@ export const list = createHandler(async (ctx, body) => {
117
117
 
118
118
  return sanitized
119
119
  })
120
+ // CIL[END stable_id="~/.framework/functions/apps.ts:list:constant"]
120
121
  // CIL[DOC-VECTOR type="context" content="purpose='List apps for an account with optional filters'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
121
122
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
122
123
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
123
124
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
124
125
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
125
126
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
126
- // CIL[END stable_id="~/.framework/functions/apps.ts:list:constant"]
127
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:get:constant" type="constant" identity="get" parent="~/.framework/functions/apps.ts"]
128
127
  // CIL[DOC-MACRO purpose="Fetch a single active app by id or slug"]
129
128
  // CIL[DOC-RESPONSIBILITY responsibility="Return a sanitized app record matching the requested id or slug"]
130
129
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -132,6 +131,7 @@ export const list = createHandler(async (ctx, body) => {
132
131
  // CIL[DOC-MICRO logic_summary="Queries the apps table by id or slug, limits to active records, and returns sanitized data" notable_decisions="Prefers id over slug; uses .single() to enforce a single result"]
133
132
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
134
133
  // CIL[DOC-STABILITY stability="stable"]
134
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:get:constant" type="constant" identity="get" parent="~/.framework/functions/apps.ts"]
135
135
  export const get = createHandler(async (ctx, body) => {
136
136
  const { id, slug } = ctx.query || {}
137
137
 
@@ -159,14 +159,13 @@ export const get = createHandler(async (ctx, body) => {
159
159
 
160
160
  return await sanitizeRecordData(ctx, data, 'app')
161
161
  })
162
+ // CIL[END stable_id="~/.framework/functions/apps.ts:get:constant"]
162
163
  // CIL[DOC-VECTOR type="context" content="purpose='Fetch a single active app by id or slug'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
163
164
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
164
165
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
165
166
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
166
167
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
167
168
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
168
- // CIL[END stable_id="~/.framework/functions/apps.ts:get:constant"]
169
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:getSchema:constant" type="constant" identity="getSchema" parent="~/.framework/functions/apps.ts"]
170
169
  // CIL[DOC-MACRO purpose="Retrieve the design schema for an app by slug"]
171
170
  // CIL[DOC-RESPONSIBILITY responsibility="Return the schema payload from the get_app_schema RPC"]
172
171
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -174,6 +173,7 @@ export const get = createHandler(async (ctx, body) => {
174
173
  // CIL[DOC-MICRO logic_summary="Validates the slug and invokes the get_app_schema RPC, returning the result" notable_decisions="Relies on a database stored procedure for schema generation"]
175
174
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
176
175
  // CIL[DOC-STABILITY stability="stable"]
176
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:getSchema:constant" type="constant" identity="getSchema" parent="~/.framework/functions/apps.ts"]
177
177
  export const getSchema = createHandler(async (ctx, body) => {
178
178
  const { slug } = ctx.query || {}
179
179
 
@@ -188,14 +188,13 @@ export const getSchema = createHandler(async (ctx, body) => {
188
188
 
189
189
  return data
190
190
  })
191
+ // CIL[END stable_id="~/.framework/functions/apps.ts:getSchema:constant"]
191
192
  // CIL[DOC-VECTOR type="context" content="purpose='Retrieve the design schema for an app by slug'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
192
193
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
193
194
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
194
195
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
195
196
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
196
197
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
197
- // CIL[END stable_id="~/.framework/functions/apps.ts:getSchema:constant"]
198
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:create:constant" type="constant" identity="create" parent="~/.framework/functions/apps.ts"]
199
198
  // CIL[DOC-MACRO purpose="Create a new app record"]
200
199
  // CIL[DOC-RESPONSIBILITY responsibility="Validate input and permissions, insert a new app row, and emit an audit log"]
201
200
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -203,8 +202,9 @@ export const getSchema = createHandler(async (ctx, body) => {
203
202
  // CIL[DOC-MICRO logic_summary="Enforces required fields and auth, checks create permission, ensures slug uniqueness, inserts with defaults, and emits an audit event" notable_decisions="Defaults version, app_type, source, route_prefix, and min_role; only system admins bypass permission checks"]
204
203
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
205
204
  // CIL[DOC-STABILITY stability="stable"]
205
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:create:constant" type="constant" identity="create" parent="~/.framework/functions/apps.ts"]
206
206
  export const create = createHandler(async (ctx, body) => {
207
- const { slug, name, description, icon, color, version, app_type, source, owner_account_id, config, nav_items, min_role, integration_deps, metadata, route_prefix, renderer } = body
207
+ const { slug, name, description, icon, color, version, app_type, source, owner_account_id, config, nav_items, min_role, required_roles, integration_deps, metadata, route_prefix, renderer } = body
208
208
 
209
209
  if (!slug || !name) {
210
210
  throw new Error('slug and name are required')
@@ -239,7 +239,7 @@ export const create = createHandler(async (ctx, body) => {
239
239
  throw new Error('App slug already exists')
240
240
  }
241
241
 
242
- const { data, error: err } = await ctx.db
242
+ const { data, error: err } = await adminDb
243
243
  .from('apps')
244
244
  .insert({
245
245
  slug,
@@ -254,6 +254,7 @@ export const create = createHandler(async (ctx, body) => {
254
254
  config: config || {},
255
255
  nav_items: nav_items || [],
256
256
  min_role: min_role || 'member',
257
+ required_roles: required_roles || [],
257
258
  integration_deps: integration_deps || [],
258
259
  metadata: metadata || {},
259
260
  route_prefix: route_prefix !== undefined ? route_prefix : ('/' + slug),
@@ -270,14 +271,13 @@ export const create = createHandler(async (ctx, body) => {
270
271
 
271
272
  return data
272
273
  })
274
+ // CIL[END stable_id="~/.framework/functions/apps.ts:create:constant"]
273
275
  // CIL[DOC-VECTOR type="context" content="purpose='Create a new app record'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
274
276
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
275
277
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
276
278
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
277
279
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
278
280
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
279
- // CIL[END stable_id="~/.framework/functions/apps.ts:create:constant"]
280
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:update:constant" type="constant" identity="update" parent="~/.framework/functions/apps.ts"]
281
281
  // CIL[DOC-MACRO purpose="Update an existing app"]
282
282
  // CIL[DOC-RESPONSIBILITY responsibility="Validate the caller, load the current record, check field-level permissions, and apply updates"]
283
283
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -285,6 +285,7 @@ export const create = createHandler(async (ctx, body) => {
285
285
  // CIL[DOC-MICRO logic_summary="Finds the current record, validates update permissions, sets updated_at, persists changes, and emits an audit event" notable_decisions="Strips body id from updates; uses validateUpdatePermissions to enforce field-level access"]
286
286
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
287
287
  // CIL[DOC-STABILITY stability="stable"]
288
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:update:constant" type="constant" identity="update" parent="~/.framework/functions/apps.ts"]
288
289
  export const update = createHandler(async (ctx, body) => {
289
290
  const id = body?.id || ctx.query?.id
290
291
  const { id: _bodyId, ...updates } = body || {}
@@ -320,7 +321,7 @@ export const update = createHandler(async (ctx, body) => {
320
321
  throw new Error(fieldValidation.error)
321
322
  }
322
323
 
323
- const { data, error: err } = await ctx.db
324
+ const { data, error: err } = await adminDb
324
325
  .from('apps')
325
326
  .update({
326
327
  ...updates,
@@ -336,14 +337,13 @@ export const update = createHandler(async (ctx, body) => {
336
337
 
337
338
  return data
338
339
  })
340
+ // CIL[END stable_id="~/.framework/functions/apps.ts:update:constant"]
339
341
  // CIL[DOC-VECTOR type="context" content="purpose='Update an existing app'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
340
342
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
341
343
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
342
344
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
343
345
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
344
346
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
345
- // CIL[END stable_id="~/.framework/functions/apps.ts:update:constant"]
346
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:remove:constant" type="constant" identity="remove" parent="~/.framework/functions/apps.ts"]
347
347
  // CIL[DOC-MACRO purpose="Soft-delete an app"]
348
348
  // CIL[DOC-RESPONSIBILITY responsibility="Set is_active to false for an app after authentication and existence checks"]
349
349
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -351,6 +351,7 @@ export const update = createHandler(async (ctx, body) => {
351
351
  // CIL[DOC-MICRO logic_summary="Loads the record, flips the is_active flag and updated_at, and emits an audit event" notable_decisions="Performs a soft delete rather than a hard delete"]
352
352
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
353
353
  // CIL[DOC-STABILITY stability="stable"]
354
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:remove:constant" type="constant" identity="remove" parent="~/.framework/functions/apps.ts"]
354
355
  export const remove = createHandler(async (ctx, body) => {
355
356
  const id = body?.id || ctx.query?.id
356
357
 
@@ -373,7 +374,19 @@ export const remove = createHandler(async (ctx, body) => {
373
374
  throw new Error('App not found')
374
375
  }
375
376
 
376
- const { data, error: err } = await ctx.db
377
+ if (!permissions.isSystemAdmin(ctx)) {
378
+ const perms = await permissions.resolveFirstSurfacePermissions(
379
+ ctx.principal.id,
380
+ ctx.accountId!,
381
+ 'app',
382
+ 'delete'
383
+ )
384
+ if (!perms.canDelete) {
385
+ throw new Error('Insufficient permissions to delete apps')
386
+ }
387
+ }
388
+
389
+ const { data, error: err } = await adminDb
377
390
  .from('apps')
378
391
  .update({
379
392
  is_active: false,
@@ -389,14 +402,13 @@ export const remove = createHandler(async (ctx, body) => {
389
402
 
390
403
  return data
391
404
  })
405
+ // CIL[END stable_id="~/.framework/functions/apps.ts:remove:constant"]
392
406
  // CIL[DOC-VECTOR type="context" content="purpose='Soft-delete an app'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
393
407
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
394
408
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
395
409
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
396
410
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
397
411
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
398
- // CIL[END stable_id="~/.framework/functions/apps.ts:remove:constant"]
399
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:checkAvailability:constant" type="constant" identity="checkAvailability" parent="~/.framework/functions/apps.ts"]
400
412
  // CIL[DOC-MACRO purpose="Check whether a slug is available for an account"]
401
413
  // CIL[DOC-RESPONSIBILITY responsibility="Return an availability boolean from the is_app_available RPC"]
402
414
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -404,6 +416,7 @@ export const remove = createHandler(async (ctx, body) => {
404
416
  // CIL[DOC-MICRO logic_summary="Validates the slug and account, then calls the is_app_available RPC" notable_decisions="Uses an account-scoped stored procedure to determine availability"]
405
417
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
406
418
  // CIL[DOC-STABILITY stability="stable"]
419
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:checkAvailability:constant" type="constant" identity="checkAvailability" parent="~/.framework/functions/apps.ts"]
407
420
  export const checkAvailability = createHandler(async (ctx, body) => {
408
421
  const { slug } = ctx.query || {}
409
422
 
@@ -425,14 +438,13 @@ export const checkAvailability = createHandler(async (ctx, body) => {
425
438
 
426
439
  return { available: data }
427
440
  })
441
+ // CIL[END stable_id="~/.framework/functions/apps.ts:checkAvailability:constant"]
428
442
  // CIL[DOC-VECTOR type="context" content="purpose='Check whether a slug is available for an account'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
429
443
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
430
444
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
431
445
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
432
446
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
433
447
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
434
- // CIL[END stable_id="~/.framework/functions/apps.ts:checkAvailability:constant"]
435
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:updateVersion:constant" type="constant" identity="updateVersion" parent="~/.framework/functions/apps.ts"]
436
448
  // CIL[DOC-MACRO purpose="Update an app version via a stored procedure"]
437
449
  // CIL[DOC-RESPONSIBILITY responsibility="Bump the version of an app and emit an audit log"]
438
450
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -440,6 +452,7 @@ export const checkAvailability = createHandler(async (ctx, body) => {
440
452
  // CIL[DOC-MICRO logic_summary="Validates inputs, calls the update_app_version RPC, and emits an audit event" notable_decisions="RPC encapsulates version logic and any related triggers"]
441
453
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
442
454
  // CIL[DOC-STABILITY stability="stable"]
455
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:updateVersion:constant" type="constant" identity="updateVersion" parent="~/.framework/functions/apps.ts"]
443
456
  export const updateVersion = createHandler(async (ctx, body) => {
444
457
  const { id, version } = body
445
458
 
@@ -447,7 +460,11 @@ export const updateVersion = createHandler(async (ctx, body) => {
447
460
  throw new Error('App ID and version are required')
448
461
  }
449
462
 
450
- const { data, error: err } = await ctx.db
463
+ if (!permissions.isSystemAdmin(ctx)) {
464
+ throw new Error('Insufficient permissions to update app version')
465
+ }
466
+
467
+ const { data, error: err } = await adminDb
451
468
  .rpc('update_app_version', {
452
469
  app_id: id,
453
470
  new_version: version
@@ -459,14 +476,13 @@ export const updateVersion = createHandler(async (ctx, body) => {
459
476
 
460
477
  return { success: true }
461
478
  })
479
+ // CIL[END stable_id="~/.framework/functions/apps.ts:updateVersion:constant"]
462
480
  // CIL[DOC-VECTOR type="context" content="purpose='Update an app version via a stored procedure'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
463
481
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
464
482
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
465
483
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
466
484
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
467
485
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
468
- // CIL[END stable_id="~/.framework/functions/apps.ts:updateVersion:constant"]
469
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/apps.ts"]
470
486
  // CIL[DOC-MACRO purpose="Dispatch incoming app requests to the correct handler by HTTP method and action"]
471
487
  // CIL[DOC-RESPONSIBILITY responsibility="Route GET/POST/PATCH/DELETE methods to the appropriate list, get, schema, create, update, remove, and version handlers"]
472
488
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -474,6 +490,7 @@ export const updateVersion = createHandler(async (ctx, body) => {
474
490
  // CIL[DOC-MICRO logic_summary="Switches on HTTP method and query params to dispatch to the appropriate app operation" notable_decisions="GET with id or slug maps to get; action schema/available handled; POST action version or create; PATCH update; DELETE remove"]
475
491
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
476
492
  // CIL[DOC-STABILITY stability="stable"]
493
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/apps.ts"]
477
494
  export const handler = createHandler(async (ctx, body) => {
478
495
  const method = ctx.query?.method || 'GET'
479
496
 
@@ -504,10 +521,10 @@ export const handler = createHandler(async (ctx, body) => {
504
521
  throw new Error(`Unsupported method: ${method}`)
505
522
  }
506
523
  })
524
+ // CIL[END stable_id="~/.framework/functions/apps.ts:handler:constant"]
507
525
  // CIL[DOC-VECTOR type="context" content="purpose='Dispatch incoming app requests to the correct handler by HTTP method and action'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
508
526
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
509
527
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
510
528
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
511
529
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
512
530
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
513
- // CIL[END stable_id="~/.framework/functions/apps.ts:handler:constant"]
@@ -168,9 +168,9 @@ interface ChunkProposal {
168
168
  // CIL[DOC-MICRO logic_summary="Holds the static LANGUAGE_MAP value" notable_decisions="Static value used across cil-ingest"]
169
169
  const LANGUAGE_MAP: Record<string, string> = {
170
170
  '.ts': 'typescript',
171
- '.tsx': 'typescript',
171
+ '.tsx': 'typescriptreact',
172
172
  '.js': 'javascript',
173
- '.jsx': 'javascript',
173
+ '.jsx': 'javascriptreact',
174
174
  '.sql': 'sql',
175
175
  '.py': 'python',
176
176
  '.go': 'go',
@@ -1606,9 +1606,9 @@ async function pass2Chunk(
1606
1606
  for (const fileItem of fileItems || []) {
1607
1607
  const relPath: string = fileItem.data?.file_path || fileItem.title
1608
1608
  const absPath = path.join(repoPath, relPath)
1609
- const language = fileItem.data?.language || 'unknown'
1609
+ const language = detectLanguage(relPath)
1610
1610
 
1611
- if (!['typescript', 'javascript'].includes(language)) continue
1611
+ if (!['typescript', 'typescriptreact', 'javascript', 'javascriptreact'].includes(language)) continue
1612
1612
 
1613
1613
  if (!forceReprocess && alreadyChunkedFileIds.has(fileItem.id)) continue
1614
1614
 
@@ -1628,13 +1628,23 @@ async function pass2Chunk(
1628
1628
 
1629
1629
  const rawContent = fs.readFileSync(absPath, 'utf-8')
1630
1630
  const rawLines = rawContent.split('\n')
1631
- // Blank (rather than remove) CIL marker/DOC lines when force-reprocessing:
1631
+ // Blank (rather than remove) CIL BEGIN/END marker lines when force-reprocessing:
1632
1632
  // filtering them out shifts every line index, so stored line_start/line_end
1633
1633
  // land in stripped-file coordinates and validate_file reports false drift.
1634
1634
  // Blank lines are invisible to the AST proposer and collapse in
1635
1635
  // computeContentHash, keeping hashes identical to store_markers output.
1636
+ // DOC tags are intentionally preserved — they are source-of-truth docs.
1637
+ // markerResidue tracks blanked marker slots so the write pass can drop
1638
+ // residue that ends up adjacent to a fresh marker (prevents +1 drift).
1639
+ const markerResidue = new Set<number>()
1636
1640
  const lines = forceReprocess
1637
- ? rawLines.map((l: string) => (/^\/\/\s*CIL\[/.test(l.trim()) || /^\s*\/\*\s*CIL\[/.test(l.trim())) ? '' : l)
1641
+ ? rawLines.map((l: string, i: number) => {
1642
+ if (/^\/\/\s*CIL\[(?:BEGIN|END)\b/.test(l.trim()) || /^\s*\/\*\s*CIL\[(?:BEGIN|END)\b/.test(l.trim())) {
1643
+ markerResidue.add(i)
1644
+ return ''
1645
+ }
1646
+ return l
1647
+ })
1638
1648
  : rawLines
1639
1649
  const content = lines.join('\n')
1640
1650
 
@@ -1832,7 +1842,7 @@ async function pass2Chunk(
1832
1842
  },
1833
1843
  })
1834
1844
 
1835
- approvedChunks.push({ name: proposal.name, stable_id: proposal.stable_id, line_start: proposal.line_start, line_end: proposal.line_end, marker_line_end: proposal.marker_line_end, chunk_type: proposal.chunk_type, is_proposal: true })
1845
+ approvedChunks.push({ name: proposal.name, stable_id: proposal.stable_id, parent_stable_id: proposal.parent_stable_id || canonicalPath, line_start: proposal.line_start, line_end: proposal.line_end, marker_line_end: proposal.marker_line_end, chunk_type: proposal.chunk_type, is_proposal: true })
1836
1846
  chunksQueued++
1837
1847
  }
1838
1848
  }
@@ -1844,25 +1854,47 @@ async function pass2Chunk(
1844
1854
  let resultLines = [...lines]
1845
1855
 
1846
1856
 
1847
- const sorted = [...approvedChunks].sort((a, b) => b.line_start - a.line_start)
1848
-
1849
- for (const chunk of sorted) {
1850
- const startLine = resultLines[chunk.line_start - 1]
1857
+ // Compute every insertion index against the pre-insertion `lines`, then
1858
+ // apply splices bottom-up. Indexing the mutating resultLines (the old
1859
+ // approach) broke on nested chunks: declarations inside a component
1860
+ // shifted its closing lines, so the parent's END marker landed mid-JSX.
1861
+ const insertions: { idx: number; begin: boolean; text: string }[] = []
1862
+ for (const chunk of approvedChunks) {
1863
+ const startLine = lines[chunk.line_start - 1]
1851
1864
 
1852
1865
  if (startLine && ANY_MARKER_RE.test(startLine.trim())) continue
1853
1866
 
1854
1867
  const startMarker = chunk.is_proposal ? proposalStartMarker(chunk.name) : chunkStartMarker(chunk.stable_id, chunk.chunk_type, chunk.name, chunk.parent_stable_id)
1855
1868
  const endMarker = chunk.is_proposal ? proposalEndMarker(chunk.name) : chunkEndMarker(chunk.stable_id)
1856
- const startIdx = markerInsertIdx(resultLines, chunk.line_start)
1869
+ const startIdx = markerInsertIdx(lines, chunk.line_start)
1857
1870
 
1858
1871
  const endIdx = chunk.chunk_type === 'module_header'
1859
1872
  ? chunk.marker_line_end
1860
- : markerEndInsertIdx(resultLines, chunk.line_start, chunk.marker_line_end)
1873
+ : markerEndInsertIdx(lines, chunk.line_start, chunk.marker_line_end)
1861
1874
 
1862
- resultLines.splice(endIdx, 0, endMarker)
1863
- resultLines.splice(startIdx, 0, startMarker)
1875
+ insertions.push({ idx: startIdx, begin: true, text: startMarker })
1876
+ insertions.push({ idx: endIdx, begin: false, text: endMarker })
1864
1877
  markersWritten++
1865
1878
  }
1879
+ insertions.sort((a, b) => b.idx - a.idx || (a.begin === b.begin ? 0 : a.begin ? -1 : 1))
1880
+ for (const ins of insertions) {
1881
+ resultLines.splice(ins.idx, 0, ins.text)
1882
+ if (markerResidue.size) {
1883
+ const shifted = new Set<number>()
1884
+ for (const r of markerResidue) shifted.add(r >= ins.idx ? r + 1 : r)
1885
+ markerResidue.clear()
1886
+ shifted.forEach(r => markerResidue.add(r))
1887
+ }
1888
+ }
1889
+ // Remove the blanked old-marker slots after fresh markers are in place.
1890
+ // Fresh markers occupy equivalent positions, so this is a swap where
1891
+ // markers did not move — and it prevents residue lines from ratcheting
1892
+ // +1 line per pass wherever old and new positions disagree.
1893
+ for (let i = resultLines.length - 1; i >= 0; i--) {
1894
+ if (markerResidue.has(i) && (resultLines[i] || '').trim() === '') {
1895
+ resultLines.splice(i, 1)
1896
+ }
1897
+ }
1866
1898
 
1867
1899
 
1868
1900
  fs.writeFileSync(absPath, resultLines.join('\n'), 'utf-8')
@@ -1873,6 +1905,7 @@ async function pass2Chunk(
1873
1905
  id: fileItem.id,
1874
1906
  data: {
1875
1907
  ...fileItem.data,
1908
+ language,
1876
1909
  stored_hash: fileHash,
1877
1910
  file_hash: fileHash,
1878
1911
  content_hash: fileHash,
@@ -24,14 +24,14 @@
24
24
 
25
25
 
26
26
  import { createHandler } from './_shared/middleware'
27
+ import { isSystemAdmin } from './_shared/principal'
28
+ // CIL[END stable_id="~/.framework/functions/debug-auth.ts:module_header:module_header"]
27
29
  // CIL[DOC-VECTOR type="context" content="purpose='Netlify function for debugging authentication state and JWT token resolution'; No verified external callers; imports: .framework/functions/_shared/middleware.ts"]
28
30
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
29
31
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
30
32
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
31
33
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
32
34
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
33
- // CIL[END stable_id="~/.framework/functions/debug-auth.ts:module_header:module_header"]
34
- // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:debug:constant" type="constant" identity="debug" parent="~/.framework/functions/debug-auth.ts"]
35
35
  // CIL[DOC-MACRO purpose="Return a debug payload showing whether a principal and selected environment variables are present"]
36
36
  // CIL[DOC-RESPONSIBILITY responsibility="Builds a safe, read-only debug response from request context and process.env"]
37
37
  // CIL[DOC-CONTEXT module="framework/functions" layer="functions" related_files=".framework/functions/_shared/middleware.ts,.framework/functions/debug-auth.ts"]
@@ -39,6 +39,7 @@ import { createHandler } from './_shared/middleware'
39
39
  // CIL[DOC-MICRO logic_summary="Checks the request context for a principal and masks environment variable presence" notable_decisions="Only reports SET/NOT_SET for sensitive env values"]
40
40
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
41
41
  // CIL[DOC-STABILITY stability="stable"]
42
+ // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:debug:constant" type="constant" identity="debug" parent="~/.framework/functions/debug-auth.ts"]
42
43
  const debug = createHandler(async (ctx, _body) => {
43
44
  const envObj = (globalThis as any).process?.env || {}
44
45
  return {
@@ -54,14 +55,13 @@ const debug = createHandler(async (ctx, _body) => {
54
55
  }
55
56
  }
56
57
  })
58
+ // CIL[END stable_id="~/.framework/functions/debug-auth.ts:debug:constant"]
57
59
  // CIL[DOC-VECTOR type="context" content="purpose='Return a debug payload showing whether a principal and selected environment variables are present'; No verified external callers; imports: .framework/functions/_shared/middleware.ts"]
58
60
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
59
61
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
60
62
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
61
63
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
62
64
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
63
- // CIL[END stable_id="~/.framework/functions/debug-auth.ts:debug:constant"]
64
- // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:testJwt:constant" type="constant" identity="testJwt" parent="~/.framework/functions/debug-auth.ts"]
65
65
  // CIL[DOC-MACRO purpose="Validate and return the resolved JWT principal for a request"]
66
66
  // CIL[DOC-RESPONSIBILITY responsibility="Verifies a principal exists and returns its identity and account association"]
67
67
  // CIL[DOC-CONTEXT module="framework/functions" layer="functions" related_files=".framework/functions/_shared/middleware.ts,.framework/functions/debug-auth.ts"]
@@ -69,6 +69,7 @@ const debug = createHandler(async (ctx, _body) => {
69
69
  // CIL[DOC-MICRO logic_summary="Returns principal data or an error if authentication did not resolve" notable_decisions="Includes accountId from the request context"]
70
70
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
71
71
  // CIL[DOC-STABILITY stability="stable"]
72
+ // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:testJwt:constant" type="constant" identity="testJwt" parent="~/.framework/functions/debug-auth.ts"]
72
73
  const testJwt = createHandler(async (ctx, _body) => {
73
74
  const envObj = (globalThis as any).process?.env || {}
74
75
  if (!ctx.principal) {
@@ -89,14 +90,13 @@ const testJwt = createHandler(async (ctx, _body) => {
89
90
  }
90
91
  }
91
92
  })
93
+ // CIL[END stable_id="~/.framework/functions/debug-auth.ts:testJwt:constant"]
92
94
  // CIL[DOC-VECTOR type="context" content="purpose='Validate and return the resolved JWT principal for a request'; No verified external callers; imports: .framework/functions/_shared/middleware.ts"]
93
95
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
94
96
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
95
97
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
96
98
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
97
99
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
98
- // CIL[END stable_id="~/.framework/functions/debug-auth.ts:testJwt:constant"]
99
- // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:handler:function" type="function" identity="handler" parent="~/.framework/functions/debug-auth.ts"]
100
100
  // CIL[DOC-MACRO purpose="Route incoming requests to the debug or testJwt handler"]
101
101
  // CIL[DOC-RESPONSIBILITY responsibility="Dispatches by query method to the appropriate handler and returns the result"]
102
102
  // CIL[DOC-CONTEXT module="framework/functions" layer="functions" related_files=".framework/functions/_shared/middleware.ts,.framework/functions/debug-auth.ts"]
@@ -104,10 +104,16 @@ const testJwt = createHandler(async (ctx, _body) => {
104
104
  // CIL[DOC-MICRO logic_summary="Reads the method query parameter, switches to debug or testJwt, and awaits the handler" notable_decisions="Defaults unknown methods to debug"]
105
105
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
106
106
  // CIL[DOC-STABILITY stability="stable"]
107
+ // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:handler:function" type="function" identity="handler" parent="~/.framework/functions/debug-auth.ts"]
107
108
  export async function handler(event: any, context: any) {
108
109
  const method = event.queryStringParameters?.method || 'debug'
109
110
 
110
111
  const ctx = await createHandler(async (ctx, _body) => {
112
+ if (!isSystemAdmin(ctx.principal)) {
113
+ const e: any = new Error('system_admin required')
114
+ e.statusCode = 403
115
+ throw e
116
+ }
111
117
  switch (method) {
112
118
  case 'debug':
113
119
  return await debug(ctx, _body)
@@ -120,10 +126,10 @@ export async function handler(event: any, context: any) {
120
126
 
121
127
  return ctx
122
128
  }
129
+ // CIL[END stable_id="~/.framework/functions/debug-auth.ts:handler:function"]
123
130
  // CIL[DOC-VECTOR type="context" content="purpose='Route incoming requests to the debug or testJwt handler'; No verified external callers; imports: .framework/functions/_shared/middleware.ts"]
124
131
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
125
132
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
126
133
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
127
134
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
128
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
129
- // CIL[END stable_id="~/.framework/functions/debug-auth.ts:handler:function"]
135
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]