spine-framework 0.1.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 (385) hide show
  1. package/.framework/README.md +129 -0
  2. package/.framework/cli/bin.cjs +14 -0
  3. package/.framework/cli/commands/agents.ts +153 -0
  4. package/.framework/cli/commands/auth.ts +94 -0
  5. package/.framework/cli/commands/create-app.ts +185 -0
  6. package/.framework/cli/commands/dev.ts +295 -0
  7. package/.framework/cli/commands/doctor.ts +442 -0
  8. package/.framework/cli/commands/generate.ts +332 -0
  9. package/.framework/cli/commands/init.ts +272 -0
  10. package/.framework/cli/commands/install-app.ts +391 -0
  11. package/.framework/cli/commands/items.ts +253 -0
  12. package/.framework/cli/commands/migrations.ts +141 -0
  13. package/.framework/cli/commands/pipelines.ts +166 -0
  14. package/.framework/cli/commands/status.ts +197 -0
  15. package/.framework/cli/commands/system.ts +184 -0
  16. package/.framework/cli/commands/test.ts +227 -0
  17. package/.framework/cli/commands/uninstall-app.ts +166 -0
  18. package/.framework/cli/context.ts +268 -0
  19. package/.framework/cli/env-loader.ts +36 -0
  20. package/.framework/cli/index.ts +106 -0
  21. package/.framework/cli/welcome.cjs +45 -0
  22. package/.framework/docs/API.md +384 -0
  23. package/.framework/docs/STABILITY.md +52 -0
  24. package/.framework/docs/admin-routes.md +76 -0
  25. package/.framework/docs/api-docs-progress.md +38 -0
  26. package/.framework/docs/api-governance.md +146 -0
  27. package/.framework/docs/api-testing-results.md +212 -0
  28. package/.framework/docs/apis/admin-configs.md +567 -0
  29. package/.framework/docs/apis/admin-data.md +272 -0
  30. package/.framework/docs/apis/index.md +231 -0
  31. package/.framework/docs/apis/internal.md +295 -0
  32. package/.framework/docs/apis/runtime.md +537 -0
  33. package/.framework/docs/assembly-launch-guide.md +138 -0
  34. package/.framework/docs/audit-results.md +590 -0
  35. package/.framework/docs/authorization-model.md +170 -0
  36. package/.framework/docs/db-api-inventory.md +95 -0
  37. package/.framework/docs/examples/custom-app/README.md +77 -0
  38. package/.framework/docs/examples/custom-function/README.md +27 -0
  39. package/.framework/docs/examples/custom-function/handler.ts +48 -0
  40. package/.framework/docs/examples/custom-webhook/README.md +68 -0
  41. package/.framework/docs/gap-remediation-backlog.md +103 -0
  42. package/.framework/docs/guides/cli-guide.md +224 -0
  43. package/.framework/docs/guides/getting-started.md +103 -0
  44. package/.framework/docs/guides/import-guide.md +193 -0
  45. package/.framework/docs/guides/testing-guide.md +229 -0
  46. package/.framework/docs/permission-examples.md +326 -0
  47. package/.framework/docs/ui-adoption-verification.md +111 -0
  48. package/.framework/docs/ui-api-coverage.md +84 -0
  49. package/.framework/docs/v2-compatibility-audit.md +228 -0
  50. package/.framework/functions/.gitkeep +1 -0
  51. package/.framework/functions/_shared/agent-runner.ts +1097 -0
  52. package/.framework/functions/_shared/app-manifest.ts +184 -0
  53. package/.framework/functions/_shared/audit.ts +150 -0
  54. package/.framework/functions/_shared/db.ts +174 -0
  55. package/.framework/functions/_shared/index.ts +382 -0
  56. package/.framework/functions/_shared/middleware.ts +490 -0
  57. package/.framework/functions/_shared/permissions.ts +1325 -0
  58. package/.framework/functions/_shared/pipeline-runner.ts +731 -0
  59. package/.framework/functions/_shared/principal.ts +760 -0
  60. package/.framework/functions/_shared/schema-utils.ts +967 -0
  61. package/.framework/functions/_shared/testing.ts +258 -0
  62. package/.framework/functions/_shared/trigger-engine.ts +425 -0
  63. package/.framework/functions/_shared/webhook-registration.ts +168 -0
  64. package/.framework/functions/_shared/webhook-registry.ts +129 -0
  65. package/.framework/functions/account-nodes.ts +111 -0
  66. package/.framework/functions/admin-data.ts +606 -0
  67. package/.framework/functions/ai-agents.ts +323 -0
  68. package/.framework/functions/api-keys.ts +376 -0
  69. package/.framework/functions/apps.ts +483 -0
  70. package/.framework/functions/auth.ts +196 -0
  71. package/.framework/functions/debug-auth.ts +107 -0
  72. package/.framework/functions/embeddings.ts +556 -0
  73. package/.framework/functions/integration-routes.ts +523 -0
  74. package/.framework/functions/integrations.ts +319 -0
  75. package/.framework/functions/item-progress.ts +272 -0
  76. package/.framework/functions/logs.ts +438 -0
  77. package/.framework/functions/observability.ts +275 -0
  78. package/.framework/functions/pipeline-executions.ts +494 -0
  79. package/.framework/functions/pipelines.ts +485 -0
  80. package/.framework/functions/prompt-configs.ts +339 -0
  81. package/.framework/functions/roles.ts +387 -0
  82. package/.framework/functions/system-cron.ts +742 -0
  83. package/.framework/functions/system.ts +323 -0
  84. package/.framework/functions/tests.ts +119 -0
  85. package/.framework/functions/timers.ts +357 -0
  86. package/.framework/functions/triggers.ts +563 -0
  87. package/.framework/functions/types.ts +604 -0
  88. package/.framework/migrations/000_foundation.sql +1256 -0
  89. package/.framework/migrations/001_seed.sql +92 -0
  90. package/.framework/migrations/002_seed_constraints.sql +13 -0
  91. package/.framework/migrations/003_auth_user_trigger.sql +59 -0
  92. package/.framework/src/App.tsx +126 -0
  93. package/.framework/src/apps/admin/index.tsx +173 -0
  94. package/.framework/src/components/AppWrapper.tsx +56 -0
  95. package/.framework/src/components/CustomAppLoader.tsx +116 -0
  96. package/.framework/src/components/admin/AdminListPage.tsx +151 -0
  97. package/.framework/src/components/admin/AdminSidebar.tsx +166 -0
  98. package/.framework/src/components/admin/AdminStatsCard.tsx +62 -0
  99. package/.framework/src/components/admin/SortableTableHeader.tsx +42 -0
  100. package/.framework/src/components/app-shell/GenericAppShell.tsx +181 -0
  101. package/.framework/src/components/app-shell/GenericDetailPage.tsx +200 -0
  102. package/.framework/src/components/app-shell/GenericListPage.tsx +116 -0
  103. package/.framework/src/components/app-sidebar.tsx +228 -0
  104. package/.framework/src/components/auth/ProtectedRoute.tsx +88 -0
  105. package/.framework/src/components/layout/AppShell.tsx +91 -0
  106. package/.framework/src/components/layout/Header.tsx +88 -0
  107. package/.framework/src/components/layout/Layout.tsx +95 -0
  108. package/.framework/src/components/layout/Sidebar.tsx +329 -0
  109. package/.framework/src/components/runtime/DataDetailHeader.tsx +77 -0
  110. package/.framework/src/components/runtime/DataDetailPage.tsx +171 -0
  111. package/.framework/src/components/runtime/DataFilters.tsx +91 -0
  112. package/.framework/src/components/runtime/DataHeader.tsx +68 -0
  113. package/.framework/src/components/runtime/DataListPage.tsx +124 -0
  114. package/.framework/src/components/runtime/DataStats.tsx +70 -0
  115. package/.framework/src/components/runtime/DataTable.tsx +174 -0
  116. package/.framework/src/components/runtime/SchemaDetailForm.tsx +134 -0
  117. package/.framework/src/components/runtime/index.ts +18 -0
  118. package/.framework/src/components/search-form.tsx +29 -0
  119. package/.framework/src/components/shared/AgentView.tsx +213 -0
  120. package/.framework/src/components/shared/FieldRenderer.tsx +478 -0
  121. package/.framework/src/components/shared/SchemaFields.tsx +226 -0
  122. package/.framework/src/components/ui/DataTable.tsx +343 -0
  123. package/.framework/src/components/ui/Form.tsx +281 -0
  124. package/.framework/src/components/ui/ItemCard.tsx +296 -0
  125. package/.framework/src/components/ui/ItemListView.tsx +308 -0
  126. package/.framework/src/components/ui/LoadingSpinner.tsx +52 -0
  127. package/.framework/src/components/ui/Modal.tsx +61 -0
  128. package/.framework/src/components/ui/RichTextEditor.tsx +210 -0
  129. package/.framework/src/components/ui/accordion.tsx +82 -0
  130. package/.framework/src/components/ui/alert-dialog.tsx +197 -0
  131. package/.framework/src/components/ui/alert.tsx +76 -0
  132. package/.framework/src/components/ui/aspect-ratio.tsx +11 -0
  133. package/.framework/src/components/ui/avatar.tsx +110 -0
  134. package/.framework/src/components/ui/badge.tsx +49 -0
  135. package/.framework/src/components/ui/breadcrumb.tsx +122 -0
  136. package/.framework/src/components/ui/button-group.tsx +83 -0
  137. package/.framework/src/components/ui/button.tsx +65 -0
  138. package/.framework/src/components/ui/calendar.tsx +222 -0
  139. package/.framework/src/components/ui/card.tsx +100 -0
  140. package/.framework/src/components/ui/carousel.tsx +240 -0
  141. package/.framework/src/components/ui/chart.tsx +373 -0
  142. package/.framework/src/components/ui/checkbox.tsx +31 -0
  143. package/.framework/src/components/ui/collapsible.tsx +33 -0
  144. package/.framework/src/components/ui/combobox.tsx +299 -0
  145. package/.framework/src/components/ui/command.tsx +193 -0
  146. package/.framework/src/components/ui/context-menu.tsx +261 -0
  147. package/.framework/src/components/ui/dialog.tsx +165 -0
  148. package/.framework/src/components/ui/direction.tsx +22 -0
  149. package/.framework/src/components/ui/drawer.tsx +132 -0
  150. package/.framework/src/components/ui/dropdown-menu.tsx +269 -0
  151. package/.framework/src/components/ui/empty.tsx +104 -0
  152. package/.framework/src/components/ui/field.tsx +238 -0
  153. package/.framework/src/components/ui/hover-card.tsx +42 -0
  154. package/.framework/src/components/ui/input-group.tsx +153 -0
  155. package/.framework/src/components/ui/input-otp.tsx +87 -0
  156. package/.framework/src/components/ui/input.tsx +19 -0
  157. package/.framework/src/components/ui/item.tsx +196 -0
  158. package/.framework/src/components/ui/kbd.tsx +26 -0
  159. package/.framework/src/components/ui/label.tsx +22 -0
  160. package/.framework/src/components/ui/menubar.tsx +277 -0
  161. package/.framework/src/components/ui/native-select.tsx +61 -0
  162. package/.framework/src/components/ui/navigation-menu.tsx +164 -0
  163. package/.framework/src/components/ui/pagination.tsx +129 -0
  164. package/.framework/src/components/ui/popover.tsx +87 -0
  165. package/.framework/src/components/ui/progress.tsx +31 -0
  166. package/.framework/src/components/ui/radio-group.tsx +42 -0
  167. package/.framework/src/components/ui/resizable.tsx +50 -0
  168. package/.framework/src/components/ui/scroll-area.tsx +53 -0
  169. package/.framework/src/components/ui/select.tsx +195 -0
  170. package/.framework/src/components/ui/separator.tsx +26 -0
  171. package/.framework/src/components/ui/sheet.tsx +145 -0
  172. package/.framework/src/components/ui/sidebar.tsx +706 -0
  173. package/.framework/src/components/ui/skeleton.tsx +13 -0
  174. package/.framework/src/components/ui/slider.tsx +59 -0
  175. package/.framework/src/components/ui/sonner.tsx +47 -0
  176. package/.framework/src/components/ui/spinner.tsx +10 -0
  177. package/.framework/src/components/ui/switch.tsx +33 -0
  178. package/.framework/src/components/ui/table-primitives.tsx +141 -0
  179. package/.framework/src/components/ui/table.tsx +114 -0
  180. package/.framework/src/components/ui/tabs.tsx +90 -0
  181. package/.framework/src/components/ui/textarea.tsx +18 -0
  182. package/.framework/src/components/ui/toggle-group.tsx +89 -0
  183. package/.framework/src/components/ui/toggle.tsx +45 -0
  184. package/.framework/src/components/ui/tooltip.tsx +57 -0
  185. package/.framework/src/contexts/AppContext.tsx +133 -0
  186. package/.framework/src/contexts/AuthContext.tsx +371 -0
  187. package/.framework/src/hooks/use-mobile.ts +19 -0
  188. package/.framework/src/hooks/useApi.ts +526 -0
  189. package/.framework/src/hooks/useApps.ts +114 -0
  190. package/.framework/src/hooks/useEntityList.ts +190 -0
  191. package/.framework/src/hooks/useEntityRecord.ts +308 -0
  192. package/.framework/src/hooks/useForm.ts +307 -0
  193. package/.framework/src/hooks/useListSchema.ts +264 -0
  194. package/.framework/src/hooks/useSchemaRecord.ts +223 -0
  195. package/.framework/src/index.css +128 -0
  196. package/.framework/src/lib/api.ts +156 -0
  197. package/.framework/src/lib/supabase.ts +94 -0
  198. package/.framework/src/lib/utils.ts +317 -0
  199. package/.framework/src/main.tsx +27 -0
  200. package/.framework/src/pages/DashboardPage.tsx +181 -0
  201. package/.framework/src/pages/NotFoundPage.tsx +39 -0
  202. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +161 -0
  203. package/.framework/src/pages/admin/AIAgentsPage.tsx +318 -0
  204. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +199 -0
  205. package/.framework/src/pages/admin/APIKeysPage.tsx +303 -0
  206. package/.framework/src/pages/admin/AlertsConfigPage.tsx +523 -0
  207. package/.framework/src/pages/admin/AppDetailPage.tsx +493 -0
  208. package/.framework/src/pages/admin/AppsPage.tsx +355 -0
  209. package/.framework/src/pages/admin/DesignedPage.tsx +491 -0
  210. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +534 -0
  211. package/.framework/src/pages/admin/EmbeddingsPage.tsx +424 -0
  212. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +176 -0
  213. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +109 -0
  214. package/.framework/src/pages/admin/IntegratedDashboard.tsx +402 -0
  215. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +187 -0
  216. package/.framework/src/pages/admin/IntegrationsPage.tsx +301 -0
  217. package/.framework/src/pages/admin/LogsPage.tsx +283 -0
  218. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +85 -0
  219. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +470 -0
  220. package/.framework/src/pages/admin/PipelineDetailPage.tsx +183 -0
  221. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +279 -0
  222. package/.framework/src/pages/admin/PipelinesPage.tsx +390 -0
  223. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +299 -0
  224. package/.framework/src/pages/admin/PromptConfigsPage.tsx +292 -0
  225. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +434 -0
  226. package/.framework/src/pages/admin/RoleDetailPage.tsx +273 -0
  227. package/.framework/src/pages/admin/RolesPage.tsx +292 -0
  228. package/.framework/src/pages/admin/SelectTestPage.tsx +61 -0
  229. package/.framework/src/pages/admin/ShadcnTestPage.tsx +588 -0
  230. package/.framework/src/pages/admin/SimpleDashboard.tsx +387 -0
  231. package/.framework/src/pages/admin/TestRunDetailPage.tsx +172 -0
  232. package/.framework/src/pages/admin/TestingDashboard.tsx +257 -0
  233. package/.framework/src/pages/admin/TimerDetailPage.tsx +151 -0
  234. package/.framework/src/pages/admin/TimersPage.tsx +376 -0
  235. package/.framework/src/pages/admin/TriggerDetailPage.tsx +149 -0
  236. package/.framework/src/pages/admin/TriggersPage.tsx +381 -0
  237. package/.framework/src/pages/admin/TypeDetailPage.tsx +694 -0
  238. package/.framework/src/pages/admin/TypesPage.tsx +295 -0
  239. package/.framework/src/pages/auth/LoginPage.tsx +188 -0
  240. package/.framework/src/pages/auth/RegisterPage.tsx +163 -0
  241. package/.framework/src/pages/spine-framework/APIPage.tsx +17 -0
  242. package/.framework/src/pages/spine-framework/CLIPage.tsx +25 -0
  243. package/.framework/src/types/auth.ts +125 -0
  244. package/.framework/src/types/types.ts +407 -0
  245. package/STRUCTURE.md +150 -0
  246. package/config/components.json +25 -0
  247. package/config/deno.lock +108 -0
  248. package/config/package-lock.json +17183 -0
  249. package/config/postcss.config.cjs +10 -0
  250. package/config/tailwind.config.cjs +78 -0
  251. package/config/tsconfig.build.json +32 -0
  252. package/config/tsconfig.cli.json +18 -0
  253. package/config/tsconfig.json +41 -0
  254. package/config/tsconfig.node.json +17 -0
  255. package/config/tsconfig.node.tsbuildinfo +1 -0
  256. package/config/tsconfig.tsbuildinfo +1 -0
  257. package/config/typedoc.json +16 -0
  258. package/config/vite.config.d.ts +2 -0
  259. package/config/vite.config.ts +72 -0
  260. package/dist/cli/commands/agents.d.ts +39 -0
  261. package/dist/cli/commands/agents.d.ts.map +1 -0
  262. package/dist/cli/commands/auth.d.ts +36 -0
  263. package/dist/cli/commands/auth.d.ts.map +1 -0
  264. package/dist/cli/commands/create-app.d.ts +23 -0
  265. package/dist/cli/commands/create-app.d.ts.map +1 -0
  266. package/dist/cli/commands/dev.d.ts +39 -0
  267. package/dist/cli/commands/dev.d.ts.map +1 -0
  268. package/dist/cli/commands/doctor.d.ts +42 -0
  269. package/dist/cli/commands/doctor.d.ts.map +1 -0
  270. package/dist/cli/commands/generate.d.ts +36 -0
  271. package/dist/cli/commands/generate.d.ts.map +1 -0
  272. package/dist/cli/commands/init.d.ts +30 -0
  273. package/dist/cli/commands/init.d.ts.map +1 -0
  274. package/dist/cli/commands/install-app.d.ts +30 -0
  275. package/dist/cli/commands/install-app.d.ts.map +1 -0
  276. package/dist/cli/commands/items.d.ts +45 -0
  277. package/dist/cli/commands/items.d.ts.map +1 -0
  278. package/dist/cli/commands/migrations.d.ts +41 -0
  279. package/dist/cli/commands/migrations.d.ts.map +1 -0
  280. package/dist/cli/commands/pipelines.d.ts +40 -0
  281. package/dist/cli/commands/pipelines.d.ts.map +1 -0
  282. package/dist/cli/commands/status.d.ts +23 -0
  283. package/dist/cli/commands/status.d.ts.map +1 -0
  284. package/dist/cli/commands/system.d.ts +29 -0
  285. package/dist/cli/commands/system.d.ts.map +1 -0
  286. package/dist/cli/commands/test.d.ts +46 -0
  287. package/dist/cli/commands/test.d.ts.map +1 -0
  288. package/dist/cli/commands/uninstall-app.d.ts +23 -0
  289. package/dist/cli/commands/uninstall-app.d.ts.map +1 -0
  290. package/dist/cli/context.d.ts +88 -0
  291. package/dist/cli/context.d.ts.map +1 -0
  292. package/dist/cli/env-loader.d.ts +14 -0
  293. package/dist/cli/env-loader.d.ts.map +1 -0
  294. package/dist/cli/index.d.ts +41 -0
  295. package/dist/cli/index.d.ts.map +1 -0
  296. package/dist/functions/_shared/agent-runner.d.ts +156 -0
  297. package/dist/functions/_shared/agent-runner.d.ts.map +1 -0
  298. package/dist/functions/_shared/app-manifest.d.ts +68 -0
  299. package/dist/functions/_shared/app-manifest.d.ts.map +1 -0
  300. package/dist/functions/_shared/audit.d.ts +91 -0
  301. package/dist/functions/_shared/audit.d.ts.map +1 -0
  302. package/dist/functions/_shared/db.d.ts +125 -0
  303. package/dist/functions/_shared/db.d.ts.map +1 -0
  304. package/dist/functions/_shared/index.d.ts +298 -0
  305. package/dist/functions/_shared/index.d.ts.map +1 -0
  306. package/dist/functions/_shared/middleware.d.ts +315 -0
  307. package/dist/functions/_shared/middleware.d.ts.map +1 -0
  308. package/dist/functions/_shared/permissions.d.ts +626 -0
  309. package/dist/functions/_shared/permissions.d.ts.map +1 -0
  310. package/dist/functions/_shared/pipeline-runner.d.ts +124 -0
  311. package/dist/functions/_shared/pipeline-runner.d.ts.map +1 -0
  312. package/dist/functions/_shared/principal.d.ts +284 -0
  313. package/dist/functions/_shared/principal.d.ts.map +1 -0
  314. package/dist/functions/_shared/schema-utils.d.ts +181 -0
  315. package/dist/functions/_shared/schema-utils.d.ts.map +1 -0
  316. package/dist/functions/_shared/testing.d.ts +172 -0
  317. package/dist/functions/_shared/testing.d.ts.map +1 -0
  318. package/dist/functions/_shared/trigger-engine.d.ts +140 -0
  319. package/dist/functions/_shared/trigger-engine.d.ts.map +1 -0
  320. package/dist/functions/_shared/webhook-registration.d.ts +81 -0
  321. package/dist/functions/_shared/webhook-registration.d.ts.map +1 -0
  322. package/dist/functions/_shared/webhook-registry.d.ts +57 -0
  323. package/dist/functions/_shared/webhook-registry.d.ts.map +1 -0
  324. package/dist/functions/account-nodes.d.ts +48 -0
  325. package/dist/functions/account-nodes.d.ts.map +1 -0
  326. package/dist/functions/admin-data.d.ts +178 -0
  327. package/dist/functions/admin-data.d.ts.map +1 -0
  328. package/dist/functions/ai-agents.d.ts +125 -0
  329. package/dist/functions/ai-agents.d.ts.map +1 -0
  330. package/dist/functions/api-keys.d.ts +140 -0
  331. package/dist/functions/api-keys.d.ts.map +1 -0
  332. package/dist/functions/apps.d.ts +163 -0
  333. package/dist/functions/apps.d.ts.map +1 -0
  334. package/dist/functions/auth.d.ts +74 -0
  335. package/dist/functions/auth.d.ts.map +1 -0
  336. package/dist/functions/debug-auth.d.ts +33 -0
  337. package/dist/functions/debug-auth.d.ts.map +1 -0
  338. package/dist/functions/embeddings.d.ts +205 -0
  339. package/dist/functions/embeddings.d.ts.map +1 -0
  340. package/dist/functions/integration-routes.d.ts +45 -0
  341. package/dist/functions/integration-routes.d.ts.map +1 -0
  342. package/dist/functions/integrations.d.ts +124 -0
  343. package/dist/functions/integrations.d.ts.map +1 -0
  344. package/dist/functions/item-progress.d.ts +41 -0
  345. package/dist/functions/item-progress.d.ts.map +1 -0
  346. package/dist/functions/logs.d.ts +162 -0
  347. package/dist/functions/logs.d.ts.map +1 -0
  348. package/dist/functions/observability.d.ts +123 -0
  349. package/dist/functions/observability.d.ts.map +1 -0
  350. package/dist/functions/pipeline-executions.d.ts +190 -0
  351. package/dist/functions/pipeline-executions.d.ts.map +1 -0
  352. package/dist/functions/pipelines.d.ts +171 -0
  353. package/dist/functions/pipelines.d.ts.map +1 -0
  354. package/dist/functions/prompt-configs.d.ts +125 -0
  355. package/dist/functions/prompt-configs.d.ts.map +1 -0
  356. package/dist/functions/roles.d.ts +118 -0
  357. package/dist/functions/roles.d.ts.map +1 -0
  358. package/dist/functions/system-cron.d.ts +65 -0
  359. package/dist/functions/system-cron.d.ts.map +1 -0
  360. package/dist/functions/system.d.ts +29 -0
  361. package/dist/functions/system.d.ts.map +1 -0
  362. package/dist/functions/tests.d.ts +28 -0
  363. package/dist/functions/tests.d.ts.map +1 -0
  364. package/dist/functions/timers.d.ts +139 -0
  365. package/dist/functions/timers.d.ts.map +1 -0
  366. package/dist/functions/triggers.d.ts +203 -0
  367. package/dist/functions/triggers.d.ts.map +1 -0
  368. package/dist/functions/types.d.ts +151 -0
  369. package/dist/functions/types.d.ts.map +1 -0
  370. package/dist/src/types/types.d.ts +364 -0
  371. package/dist/src/types/types.d.ts.map +1 -0
  372. package/package.json +192 -0
  373. package/scripts/app-install-cli.ts +286 -0
  374. package/scripts/assemble-frontend.sh +79 -0
  375. package/scripts/assemble-functions.sh +62 -0
  376. package/scripts/assemble.sh +35 -0
  377. package/scripts/boundary-check.sh +106 -0
  378. package/scripts/build-manifest.sh +80 -0
  379. package/scripts/check-core-integrity.sh +82 -0
  380. package/scripts/ingest-chunks.cjs +202 -0
  381. package/scripts/kb-chunk-parser.cjs +312 -0
  382. package/scripts/kb-chunk-parser.ts +330 -0
  383. package/scripts/load-test-app-install.ts +484 -0
  384. package/scripts/netlify-dev-wrapper.sh +22 -0
  385. package/scripts/verify-integrity.sh +69 -0
@@ -0,0 +1,92 @@
1
+ -- =============================================================================
2
+ -- 001_seed.sql
3
+ -- Spine Framework — Bare minimum bootstrap data for a fresh install
4
+ -- Generated from live production DB audit: May 28, 2026
5
+ -- =============================================================================
6
+ -- Run AFTER 000_foundation.sql.
7
+ --
8
+ -- This file contains ONLY what is required for Spine to boot and for a
9
+ -- system_admin to log in and interact with the framework. Nothing more.
10
+ --
11
+ -- What requires seeding before the app can function:
12
+ -- 1. system_admin role — people.role_id FK target
13
+ -- 2. spine-core app — required by runtime; people/accounts ref app_id
14
+ -- 3. account type — accounts.type_id is NOT NULL
15
+ -- 4. person type — people.type_id is NOT NULL
16
+ -- 5. root system account — people.account_id is NOT NULL; the bootstrap
17
+ -- system_admin must belong to an account
18
+ --
19
+ -- Everything else (additional roles, app-specific types, tenant accounts,
20
+ -- app-owned link types) belongs in app seed files or is created via the admin UI.
21
+ -- =============================================================================
22
+
23
+ -- ---------------------------------------------------------------------------
24
+ -- 1. System Role
25
+ -- ---------------------------------------------------------------------------
26
+ INSERT INTO public.roles (slug, name, description, permissions, is_system, is_active, is_protected)
27
+ VALUES (
28
+ 'system_admin',
29
+ 'System Admin',
30
+ 'Full system access — can manage all accounts, types, and system configuration',
31
+ '["*"]'::jsonb,
32
+ true,
33
+ true,
34
+ true
35
+ )
36
+ ON CONFLICT DO NOTHING;
37
+
38
+ -- ---------------------------------------------------------------------------
39
+ -- 2. Spine Core App
40
+ -- ---------------------------------------------------------------------------
41
+ INSERT INTO public.apps (slug, name, description, version, app_type, source, is_active, is_system, min_role, config, nav_items, route_prefix, renderer, integration_deps, metadata)
42
+ VALUES (
43
+ 'spine-core',
44
+ 'Spine Core',
45
+ 'Core Spine runtime — provides accounts, people, items, threads, messages, links, attachments, watchers',
46
+ '1.0.0',
47
+ 'system',
48
+ 'builtin',
49
+ true,
50
+ true,
51
+ NULL,
52
+ '{}'::jsonb,
53
+ '[]'::jsonb,
54
+ NULL,
55
+ 'none',
56
+ '[]'::jsonb,
57
+ '{}'::jsonb
58
+ )
59
+ ON CONFLICT (slug) DO NOTHING;
60
+
61
+ -- ---------------------------------------------------------------------------
62
+ -- 3. Core Types
63
+ -- accounts.type_id and people.type_id are both NOT NULL, so these must exist
64
+ -- before any account or person can be created.
65
+ -- ---------------------------------------------------------------------------
66
+ INSERT INTO public.types (app_id, kind, slug, name, description, ownership, is_active)
67
+ VALUES
68
+ ((SELECT id FROM public.apps WHERE slug = 'spine-core'), 'account', 'account', 'Account', 'Organization or tenant account', 'pack', true),
69
+ ((SELECT id FROM public.apps WHERE slug = 'spine-core'), 'person', 'person', 'Person', 'User or contact person', 'pack', true)
70
+ ON CONFLICT (app_id, kind, slug) DO NOTHING;
71
+
72
+ -- ---------------------------------------------------------------------------
73
+ -- 4. Root System Account
74
+ -- The first system_admin person must belong to an account. This is the
75
+ -- bootstrap account for the Spine system itself.
76
+ -- NOTE: The system_admin person record is NOT seeded here — it is created
77
+ -- via Supabase Auth invite + the onboarding flow, which stamps type_id and
78
+ -- role_id onto the resulting people row.
79
+ -- ---------------------------------------------------------------------------
80
+ INSERT INTO public.accounts (type_id, slug, display_name, description, is_active)
81
+ VALUES (
82
+ (SELECT id FROM public.types WHERE kind = 'account' AND slug = 'account'),
83
+ 'spine-system',
84
+ 'Spine System',
85
+ 'Root system account for the Spine framework',
86
+ true
87
+ )
88
+ ON CONFLICT (slug) DO NOTHING;
89
+
90
+ -- NOTE: No link types are seeded here. All link types are app-owned.
91
+ -- Cortex seeds: account_signals, account_opportunities, analyzed_by, tagged_with
92
+ -- See custom/apps/cortex/seed/link-types.json
@@ -0,0 +1,13 @@
1
+ -- =============================================================================
2
+ -- 002_seed_constraints.sql
3
+ -- Adds unique constraints required for idempotent seed upserts
4
+ -- =============================================================================
5
+
6
+ -- link_types needs unique on (app_id, slug) for seed upserts
7
+ ALTER TABLE public.link_types ADD CONSTRAINT IF NOT EXISTS link_types_app_id_slug_key UNIQUE (app_id, slug);
8
+
9
+ -- triggers needs unique on (app_id, name) for seed upserts
10
+ ALTER TABLE public.triggers ADD CONSTRAINT IF NOT EXISTS triggers_app_id_name_key UNIQUE (app_id, name);
11
+
12
+ -- pipelines needs unique on (app_id, name) for seed upserts
13
+ ALTER TABLE public.pipelines ADD CONSTRAINT IF NOT EXISTS pipelines_app_id_name_key UNIQUE (app_id, name);
@@ -0,0 +1,59 @@
1
+ -- =============================================================================
2
+ -- 003_auth_user_trigger.sql
3
+ -- Creates a people record whenever a new Supabase auth user signs up.
4
+ -- Run AFTER 001_seed.sql (requires spine-system account and person type).
5
+ --
6
+ -- First user ever → system_admin role (bootstrap)
7
+ -- Subsequent users → no role (assigned later via admin invite flow)
8
+ -- =============================================================================
9
+
10
+ CREATE OR REPLACE FUNCTION public.handle_new_auth_user()
11
+ RETURNS TRIGGER LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$
12
+ DECLARE
13
+ v_account_id uuid;
14
+ v_type_id uuid;
15
+ v_role_id uuid;
16
+ v_is_first boolean;
17
+ BEGIN
18
+ SELECT id INTO v_account_id FROM public.accounts WHERE slug = 'spine-system' LIMIT 1;
19
+ SELECT id INTO v_type_id FROM public.types WHERE kind = 'person' AND slug = 'person' LIMIT 1;
20
+
21
+ IF v_account_id IS NULL OR v_type_id IS NULL THEN
22
+ RAISE WARNING 'handle_new_auth_user: spine-system account or person type not found — skipping people insert';
23
+ RETURN NEW;
24
+ END IF;
25
+
26
+ -- First person ever gets system_admin; subsequent users get no role
27
+ SELECT NOT EXISTS (SELECT 1 FROM public.people LIMIT 1) INTO v_is_first;
28
+ IF v_is_first THEN
29
+ SELECT id INTO v_role_id FROM public.roles WHERE slug = 'system_admin' LIMIT 1;
30
+ END IF;
31
+
32
+ INSERT INTO public.people (
33
+ id,
34
+ auth_uid,
35
+ email,
36
+ full_name,
37
+ account_id,
38
+ type_id,
39
+ role_id,
40
+ is_active
41
+ ) VALUES (
42
+ NEW.id,
43
+ NEW.id,
44
+ NEW.email,
45
+ COALESCE(NEW.raw_user_meta_data->>'full_name', split_part(NEW.email, '@', 1)),
46
+ v_account_id,
47
+ v_type_id,
48
+ v_role_id,
49
+ true
50
+ )
51
+ ON CONFLICT (id) DO NOTHING;
52
+
53
+ RETURN NEW;
54
+ END;
55
+ $$;
56
+
57
+ CREATE OR REPLACE TRIGGER on_auth_user_created
58
+ AFTER INSERT ON auth.users
59
+ FOR EACH ROW EXECUTE FUNCTION public.handle_new_auth_user();
@@ -0,0 +1,126 @@
1
+ import { Suspense, lazy } from 'react'
2
+ import { Routes, Route, Navigate } from 'react-router-dom'
3
+ import { useAuth } from './contexts/AuthContext'
4
+ import { LoadingSpinner } from './components/ui/LoadingSpinner'
5
+ import { LoginPage } from './pages/auth/LoginPage'
6
+ import { RegisterPage } from './pages/auth/RegisterPage'
7
+ import { NotFoundPage } from './pages/NotFoundPage'
8
+ import { DashboardPage } from './pages/DashboardPage'
9
+ import { AppWrapper } from './components/AppWrapper'
10
+ import { AppsRegistryProvider, useAppsRegistry } from './contexts/AppContext'
11
+ import { CustomAppLoader } from './components/CustomAppLoader'
12
+ import { GenericAppShell } from './components/app-shell/GenericAppShell'
13
+ import { APIPage } from './pages/spine-framework/APIPage'
14
+ import { CLIPage } from './pages/spine-framework/CLIPage'
15
+
16
+ const AdminApp = lazy(() => import('./apps/admin/index'))
17
+
18
+ function App() {
19
+ const { user, isLoading } = useAuth()
20
+
21
+ if (isLoading) {
22
+ return (
23
+ <div className="min-h-screen flex items-center justify-center bg-slate-50">
24
+ <div className="text-center">
25
+ <LoadingSpinner className="w-8 h-8 mx-auto mb-4" />
26
+ <p className="text-slate-600">Loading Spine...</p>
27
+ </div>
28
+ </div>
29
+ )
30
+ }
31
+
32
+ return (
33
+ <AppsRegistryProvider>
34
+ {!user ? (
35
+ <Routes>
36
+ <Route path="/login" element={<LoginPage />} />
37
+ <Route path="/register" element={<RegisterPage />} />
38
+ <Route path="*" element={<Navigate to="/login" replace />} />
39
+ </Routes>
40
+ ) : (
41
+ <AuthenticatedRouter />
42
+ )}
43
+ </AppsRegistryProvider>
44
+ )
45
+ }
46
+
47
+ function AuthenticatedRouter() {
48
+ const { routableApps: apps, loading } = useAppsRegistry()
49
+
50
+ if (loading) {
51
+ return (
52
+ <div className="min-h-screen flex items-center justify-center bg-slate-50">
53
+ <div className="text-center">
54
+ <LoadingSpinner className="w-8 h-8 mx-auto mb-4" />
55
+ <p className="text-slate-600">Loading apps...</p>
56
+ </div>
57
+ </div>
58
+ )
59
+ }
60
+
61
+ // Sort: explicit prefixes first, root (/) last
62
+ const sorted = [...apps]
63
+ .filter(app => app.slug !== 'spine-framework' && !app.route_prefix?.startsWith('/spine-framework'))
64
+ .sort((a, b) => {
65
+ if (a.route_prefix === '/') return 1
66
+ if (b.route_prefix === '/') return -1
67
+ return (b.route_prefix?.length || 0) - (a.route_prefix?.length || 0)
68
+ })
69
+
70
+ return (
71
+ <Suspense fallback={<div className="min-h-screen flex items-center justify-center"><LoadingSpinner /></div>}>
72
+ <Routes>
73
+ {/* Default redirect */}
74
+ <Route path="/" element={<Navigate to="/dashboard" replace />} />
75
+ <Route path="/dashboard" element={<DashboardPage />} />
76
+
77
+ {/* Login route for authenticated users (redirects to qualified app) */}
78
+ <Route path="/login" element={<LoginPage />} />
79
+
80
+ {/* ── Spine Framework namespace (reserved — no custom app may use this path) ── */}
81
+ <Route path="/spine-framework/admin/*" element={<AdminApp />} />
82
+ <Route path="/spine-framework/api" element={<APIPage />} />
83
+ <Route path="/spine-framework/cli" element={<CLIPage />} />
84
+
85
+ {/* Dynamic app routes */}
86
+ {sorted.map(app => {
87
+ const prefix = app.route_prefix!
88
+
89
+ if (app.renderer === 'custom') {
90
+ return (
91
+ <Route
92
+ key={app.slug}
93
+ path={`${prefix}/*`}
94
+ element={
95
+ <AppWrapper app={app}>
96
+ <CustomAppLoader slug={app.slug} />
97
+ </AppWrapper>
98
+ }
99
+ />
100
+ )
101
+ }
102
+
103
+ if (app.renderer === 'generic') {
104
+ return (
105
+ <Route
106
+ key={app.slug}
107
+ path={`${prefix}/*`}
108
+ element={
109
+ <AppWrapper app={app}>
110
+ <GenericAppShell app={app} />
111
+ </AppWrapper>
112
+ }
113
+ />
114
+ )
115
+ }
116
+
117
+ return null
118
+ })}
119
+
120
+ <Route path="*" element={<NotFoundPage />} />
121
+ </Routes>
122
+ </Suspense>
123
+ )
124
+ }
125
+
126
+ export default App
@@ -0,0 +1,173 @@
1
+ import { lazy, Suspense } from 'react'
2
+ import { Routes, Route, Navigate, useLocation } from 'react-router-dom'
3
+ import { LoadingSpinner } from '../../components/ui/LoadingSpinner'
4
+ import { NotFoundPage } from '../../pages/NotFoundPage'
5
+ import { useAuth } from '../../contexts/AuthContext'
6
+ import { AppShell } from '../../components/layout/AppShell'
7
+ import { AdminSidebar } from '../../components/admin/AdminSidebar'
8
+ import { TooltipProvider } from '../../components/ui/tooltip'
9
+
10
+ // Config list pages
11
+ const TypesPage = lazy(() => import('../../pages/admin/TypesPage').then(m => ({ default: m.TypesPage })))
12
+ const AppsPage = lazy(() => import('../../pages/admin/AppsPage').then(m => ({ default: m.AppsPage })))
13
+ const TypeDetailPage = lazy(() => import('../../pages/admin/TypeDetailPage').then(m => ({ default: m.TypeDetailPage })))
14
+ const PipelinesPage = lazy(() => import('../../pages/admin/PipelinesPage').then(m => ({ default: m.PipelinesPage })))
15
+ const TriggersPage = lazy(() => import('../../pages/admin/TriggersPage').then(m => ({ default: m.TriggersPage })))
16
+ const AIAgentsPage = lazy(() => import('../../pages/admin/AIAgentsPage').then(m => ({ default: m.AIAgentsPage })))
17
+ const EmbeddingsPage = lazy(() => import('../../pages/admin/EmbeddingsPage').then(m => ({ default: m.EmbeddingsPage })))
18
+ const TimersPage = lazy(() => import('../../pages/admin/TimersPage').then(m => ({ default: m.TimersPage })))
19
+ const IntegrationsPage = lazy(() => import('../../pages/admin/IntegrationsPage').then(m => ({ default: m.IntegrationsPage })))
20
+
21
+ // Config detail pages
22
+ const AppDetailPage = lazy(() => import('../../pages/admin/AppDetailPage').then(m => ({ default: m.AppDetailPage })))
23
+ const PipelineDetailPage = lazy(() => import('../../pages/admin/PipelineDetailPage').then(m => ({ default: m.PipelineDetailPage })))
24
+ const TriggerDetailPage = lazy(() => import('../../pages/admin/TriggerDetailPage').then(m => ({ default: m.TriggerDetailPage })))
25
+ const AIAgentDetailPage = lazy(() => import('../../pages/admin/AIAgentDetailPage').then(m => ({ default: m.AIAgentDetailPage })))
26
+ const EmbeddingDetailPage = lazy(() => import('../../pages/admin/EmbeddingDetailPage').then(m => ({ default: m.EmbeddingDetailPage })))
27
+ const TimerDetailPage = lazy(() => import('../../pages/admin/TimerDetailPage').then(m => ({ default: m.TimerDetailPage })))
28
+ const IntegrationDetailPage = lazy(() => import('../../pages/admin/IntegrationDetailPage').then(m => ({ default: m.IntegrationDetailPage })))
29
+ const RolesPage = lazy(() => import('../../pages/admin/RolesPage').then(m => ({ default: m.RolesPage })))
30
+ const RoleDetailPage = lazy(() => import('../../pages/admin/RoleDetailPage').then(m => ({ default: m.RoleDetailPage })))
31
+ const PromptConfigsPage = lazy(() => import('../../pages/admin/PromptConfigsPage').then(m => ({ default: m.PromptConfigsPage })))
32
+ const PromptConfigDetailPage = lazy(() => import('../../pages/admin/PromptConfigDetailPage').then(m => ({ default: m.PromptConfigDetailPage })))
33
+ const APIKeysPage = lazy(() => import('../../pages/admin/APIKeysPage').then(m => ({ default: m.APIKeysPage })))
34
+ const APIKeyDetailPage = lazy(() => import('../../pages/admin/APIKeyDetailPage').then(m => ({ default: m.APIKeyDetailPage })))
35
+
36
+ // Observability pages
37
+ const ObservabilityDashboard = lazy(() => import('../../pages/admin/ObservabilityDashboard').then(m => ({ default: m.ObservabilityDashboard })))
38
+ const PipelineExecutionsPage = lazy(() => import('../../pages/admin/PipelineExecutionsPage').then(m => ({ default: m.PipelineExecutionsPage })))
39
+ const LogsPage = lazy(() => import('../../pages/admin/LogsPage').then(m => ({ default: m.LogsPage })))
40
+ const AlertsConfigPage = lazy(() => import('../../pages/admin/AlertsConfigPage').then(m => ({ default: m.AlertsConfigPage })))
41
+
42
+ // Runtime data pages (unified)
43
+ const DataListPage = lazy(() => import('../../components/runtime/DataListPage').then(m => ({ default: m.DataListPage })))
44
+ const DataDetailPage = lazy(() => import('../../components/runtime/DataDetailPage').then(m => ({ default: m.DataDetailPage })))
45
+
46
+ // Testing pages
47
+ const TestingDashboard = lazy(() => import('../../pages/admin/TestingDashboard'))
48
+ const TestRunDetailPage = lazy(() => import('../../pages/admin/TestRunDetailPage').then(m => ({ default: m.TestRunDetailPage })))
49
+ const ShadcnTestPage = lazy(() => import('../../pages/admin/ShadcnTestPage').then(m => ({ default: m.ShadcnTestPage })))
50
+ const MinimalShadcnTestPage = lazy(() => import('../../pages/admin/MinimalShadcnTestPage').then(m => ({ default: m.MinimalShadcnTestPage })))
51
+ const IncrementalShadcnTestPage = lazy(() => import('../../pages/admin/IncrementalShadcnTestPage').then(m => ({ default: m.IncrementalShadcnTestPage })))
52
+ const ExtendedShadcnTestPage = lazy(() => import('../../pages/admin/ExtendedShadcnTestPage').then(m => ({ default: m.ExtendedShadcnTestPage })))
53
+ const SelectTestPage = lazy(() => import('../../pages/admin/SelectTestPage').then(m => ({ default: m.SelectTestPage })))
54
+ const DesignedPage = lazy(() => import('../../pages/admin/DesignedPage').then(m => ({ default: m.DesignedPage })))
55
+ const ProperlyDesignedPage = lazy(() => import('../../pages/admin/ProperlyDesignedPage').then(m => ({ default: m.ProperlyDesignedPage })))
56
+ const IntegratedDashboard = lazy(() => import('../../pages/admin/IntegratedDashboard').then(m => ({ default: m.IntegratedDashboard })))
57
+ const SimpleDashboard = lazy(() => import('../../pages/admin/SimpleDashboard').then(m => ({ default: m.SimpleDashboard })))
58
+
59
+ function AdminRoutes() {
60
+ const location = useLocation()
61
+
62
+ // Build breadcrumbs from current path
63
+ const pathSegments = location.pathname.split('/').filter(Boolean)
64
+ const breadcrumbs: { title: string; url?: string }[] = [{ title: 'Spine', url: '/dashboard' }]
65
+
66
+ // Add admin section
67
+ if (pathSegments.includes('admin')) {
68
+ breadcrumbs.push({ title: 'Admin', url: '/spine-framework/admin' })
69
+
70
+ // Add subsection
71
+ const section = pathSegments[2]
72
+ if (section) {
73
+ breadcrumbs.push({ title: section.charAt(0).toUpperCase() + section.slice(1) })
74
+ }
75
+ }
76
+
77
+ return (
78
+ <AppShell
79
+ sidebar={<AdminSidebar />}
80
+ breadcrumbs={breadcrumbs}
81
+ >
82
+ <Suspense fallback={<div className="min-h-[400px] flex items-center justify-center"><LoadingSpinner /></div>}>
83
+ <Routes>
84
+ {/* Default redirect → configs */}
85
+ <Route index element={<Navigate to="configs/types" replace />} />
86
+ <Route path="dashboard" element={<Navigate to="configs/types" replace />} />
87
+
88
+ {/* Configs section */}
89
+ <Route path="configs/types/new" element={<TypeDetailPage />} />
90
+ <Route path="configs/types/:id" element={<TypeDetailPage />} />
91
+ <Route path="configs/types" element={<TypesPage />} />
92
+ <Route path="configs/apps/new" element={<AppDetailPage />} />
93
+ <Route path="configs/apps/:id" element={<AppDetailPage />} />
94
+ <Route path="configs/apps" element={<AppsPage />} />
95
+ <Route path="configs/pipelines/new" element={<PipelineDetailPage />} />
96
+ <Route path="configs/pipelines/:id" element={<PipelineDetailPage />} />
97
+ <Route path="configs/pipelines" element={<PipelinesPage />} />
98
+ <Route path="configs/triggers/new" element={<TriggerDetailPage />} />
99
+ <Route path="configs/triggers/:id" element={<TriggerDetailPage />} />
100
+ <Route path="configs/triggers" element={<TriggersPage />} />
101
+ <Route path="configs/ai-agents/new" element={<AIAgentDetailPage />} />
102
+ <Route path="configs/ai-agents/:id" element={<AIAgentDetailPage />} />
103
+ <Route path="configs/ai-agents" element={<AIAgentsPage />} />
104
+ <Route path="configs/embeddings/new" element={<EmbeddingDetailPage />} />
105
+ <Route path="configs/embeddings/:id" element={<EmbeddingDetailPage />} />
106
+ <Route path="configs/embeddings" element={<EmbeddingsPage />} />
107
+ <Route path="configs/timers/new" element={<TimerDetailPage />} />
108
+ <Route path="configs/timers/:id" element={<TimerDetailPage />} />
109
+ <Route path="configs/timers" element={<TimersPage />} />
110
+ <Route path="configs/integrations/new" element={<IntegrationDetailPage />} />
111
+ <Route path="configs/integrations/:id" element={<IntegrationDetailPage />} />
112
+ <Route path="configs/integrations" element={<IntegrationsPage />} />
113
+ <Route path="configs/roles/new" element={<RoleDetailPage />} />
114
+ <Route path="configs/roles/:id" element={<RoleDetailPage />} />
115
+ <Route path="configs/roles" element={<RolesPage />} />
116
+ <Route path="configs/prompts/new" element={<PromptConfigDetailPage />} />
117
+ <Route path="configs/prompts/:id" element={<PromptConfigDetailPage />} />
118
+ <Route path="configs/prompts" element={<PromptConfigsPage />} />
119
+ <Route path="configs/api-keys/new" element={<APIKeyDetailPage />} />
120
+ <Route path="configs/api-keys/:id" element={<APIKeyDetailPage />} />
121
+ <Route path="configs/api-keys" element={<APIKeysPage />} />
122
+
123
+ {/* Observability section */}
124
+ <Route path="observability" element={<ObservabilityDashboard />} />
125
+ <Route path="observability/dashboard" element={<ObservabilityDashboard />} />
126
+ <Route path="observability/alerts" element={<AlertsConfigPage />} />
127
+ <Route path="observability/executions/:id" element={<PipelineExecutionsPage />} />
128
+ <Route path="observability/executions" element={<PipelineExecutionsPage />} />
129
+ <Route path="observability/logs" element={<LogsPage />} />
130
+
131
+ {/* Testing section */}
132
+ <Route path="testing/:run_id" element={<TestRunDetailPage />} />
133
+ <Route path="testing" element={<TestingDashboard />} />
134
+ <Route path="test/ui" element={<ShadcnTestPage />} />
135
+ <Route path="test/minimal" element={<MinimalShadcnTestPage />} />
136
+ <Route path="test/incremental" element={<IncrementalShadcnTestPage />} />
137
+ <Route path="test/extended" element={<ExtendedShadcnTestPage />} />
138
+ <Route path="test/select" element={<SelectTestPage />} />
139
+ <Route path="test/designed" element={<DesignedPage />} />
140
+ <Route path="test/properly-designed" element={<ProperlyDesignedPage />} />
141
+ <Route path="test/integrated" element={<IntegratedDashboard />} />
142
+ <Route path="test/simple" element={<SimpleDashboard />} />
143
+
144
+ {/* Runtime Data - Unified entity management */}
145
+ <Route path="runtime/:entity" element={<DataListPage />} />
146
+ <Route path="runtime/:entity/new" element={<DataDetailPage />} />
147
+ <Route path="runtime/:entity/:id" element={<DataDetailPage />} />
148
+
149
+ {/* Legacy data routes - redirect to runtime routes */}
150
+ <Route path="data/:entity" element={<Navigate to="../runtime/:entity" replace />} />
151
+ <Route path="data/:entity/create" element={<Navigate to="../runtime/:entity/new" replace />} />
152
+ <Route path="data/:entity/:id" element={<Navigate to="../runtime/:entity/:id" replace />} />
153
+
154
+ <Route path="*" element={<NotFoundPage />} />
155
+ </Routes>
156
+ </Suspense>
157
+ </AppShell>
158
+ )
159
+ }
160
+
161
+ export default function AdminApp() {
162
+ const { user } = useAuth()
163
+
164
+ if (!user?.is_system_admin) {
165
+ return <Navigate to="/dashboard" replace />
166
+ }
167
+
168
+ return (
169
+ <TooltipProvider>
170
+ <AdminRoutes />
171
+ </TooltipProvider>
172
+ )
173
+ }
@@ -0,0 +1,56 @@
1
+ import React from 'react'
2
+ import { Navigate } from 'react-router-dom'
3
+ import { useAuth } from '../contexts/AuthContext'
4
+ import { AppProvider } from '../contexts/AppContext'
5
+ import { AppRecord } from '../hooks/useApps'
6
+
7
+ interface AppWrapperProps {
8
+ app: AppRecord
9
+ children: React.ReactNode
10
+ }
11
+
12
+ /**
13
+ * Shared wrapper for all apps. Provides:
14
+ * - Auth gate: redirects to /login if unauthenticated
15
+ * - Role gate: shows 403 if user lacks app's min_role
16
+ * - App context: makes app record available via useCurrentApp()
17
+ */
18
+ export function AppWrapper({ app, children }: AppWrapperProps) {
19
+ const { user } = useAuth()
20
+
21
+ // Auth gate
22
+ if (!user) {
23
+ return <Navigate to="/login" replace />
24
+ }
25
+
26
+ // Role gate
27
+ if (app.min_role) {
28
+ const hasRole = user.roles?.includes('system_admin') || user.roles?.includes(app.min_role)
29
+ if (!hasRole) {
30
+ return (
31
+ <div className="min-h-screen flex items-center justify-center bg-slate-50">
32
+ <div className="text-center p-8">
33
+ <div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4">
34
+ <svg className="w-8 h-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
35
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
36
+ </svg>
37
+ </div>
38
+ <h1 className="text-2xl font-bold text-slate-900 mb-2">Access Denied</h1>
39
+ <p className="text-slate-600 mb-6">You don't have permission to access {app.name}.</p>
40
+ <div className="bg-slate-100 rounded-lg p-4 text-left">
41
+ <p className="text-sm text-slate-600 mb-2"><strong>Your roles:</strong> {user.roles?.join(', ') || 'None'}</p>
42
+ <p className="text-sm text-slate-600"><strong>Required:</strong> {app.min_role}</p>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ )
47
+ }
48
+ }
49
+
50
+ // App context
51
+ return (
52
+ <AppProvider app={app}>
53
+ {children}
54
+ </AppProvider>
55
+ )
56
+ }
@@ -0,0 +1,116 @@
1
+ import React, { lazy, Suspense, Component } from 'react'
2
+ import type { ReactNode } from 'react'
3
+ import { LoadingSpinner } from './ui/LoadingSpinner'
4
+
5
+ // ─── ERROR BOUNDARY ───────────────────────────────────────────────────────────
6
+
7
+ interface ErrorBoundaryProps {
8
+ slug: string
9
+ children: ReactNode
10
+ }
11
+
12
+ interface ErrorBoundaryState {
13
+ error: Error | null
14
+ }
15
+
16
+ class AppErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
17
+ constructor(props: ErrorBoundaryProps) {
18
+ super(props)
19
+ this.state = { error: null }
20
+ }
21
+
22
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
23
+ return { error }
24
+ }
25
+
26
+ render() {
27
+ if (this.state.error) {
28
+ return (
29
+ <div className="min-h-screen flex items-center justify-center bg-slate-50">
30
+ <div className="text-center p-8 max-w-lg">
31
+ <div className="w-16 h-16 bg-amber-100 rounded-full flex items-center justify-center mx-auto mb-4">
32
+ <svg className="w-8 h-8 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
33
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
34
+ </svg>
35
+ </div>
36
+ <h1 className="text-2xl font-bold text-slate-900 mb-2">App Load Error</h1>
37
+ <p className="text-slate-600 mb-4">
38
+ Failed to load the <strong>{this.props.slug}</strong> app.
39
+ </p>
40
+ <pre className="bg-slate-100 rounded-lg p-4 text-left text-sm text-red-600 overflow-auto mb-4">
41
+ {this.state.error.message}
42
+ </pre>
43
+ <p className="text-sm text-slate-500">
44
+ Check that <code>apps/{this.props.slug}/index.tsx</code> exists and exports a default component.
45
+ </p>
46
+ </div>
47
+ </div>
48
+ )
49
+ }
50
+
51
+ return this.props.children
52
+ }
53
+ }
54
+
55
+ // ─── LOADER ───────────────────────────────────────────────────────────────────
56
+
57
+ // Static glob maps — Vite analyzes these at build time and builds a complete
58
+ // module map. Runtime lookup is just a map key lookup, no dynamic string eval.
59
+ // Custom apps take precedence over core apps with the same slug.
60
+ const customAppModules = import.meta.glob('../../../custom/apps/*/index.tsx')
61
+ const coreAppModules = import.meta.glob('../apps/*/index.tsx')
62
+
63
+ // Module-level cache for lazy components to avoid re-creating on each render
64
+ const appModuleCache = new Map<string, React.LazyExoticComponent<React.ComponentType>>()
65
+
66
+ // Resolve the glob key for a given slug from the custom or core map.
67
+ function resolveAppLoader(slug: string): (() => Promise<{ default: React.ComponentType }>) | null {
68
+ // Check custom first (custom/apps/{slug}/index.tsx)
69
+ const customKey = `../../../custom/apps/${slug}/index.tsx`
70
+ if (customAppModules[customKey]) {
71
+ return customAppModules[customKey] as () => Promise<{ default: React.ComponentType }>
72
+ }
73
+ // Fall back to core (../apps/{slug}/index.tsx relative to this file)
74
+ const coreKey = `../apps/${slug}/index.tsx`
75
+ if (coreAppModules[coreKey]) {
76
+ return coreAppModules[coreKey] as () => Promise<{ default: React.ComponentType }>
77
+ }
78
+ return null
79
+ }
80
+
81
+ function getAppComponent(slug: string): React.LazyExoticComponent<React.ComponentType> {
82
+ if (!appModuleCache.has(slug)) {
83
+ const loader = resolveAppLoader(slug)
84
+ const LazyComponent = lazy(
85
+ loader
86
+ ? loader
87
+ : () => Promise.reject(new Error(`App "${slug}" not found. Expected apps/${slug}/index.tsx in custom/apps or .framework/src/apps.`))
88
+ )
89
+ appModuleCache.set(slug, LazyComponent)
90
+ }
91
+ return appModuleCache.get(slug)!
92
+ }
93
+
94
+ interface CustomAppLoaderProps {
95
+ slug: string
96
+ }
97
+
98
+ /**
99
+ * Lazy-loads a custom app component from apps/{slug}/index.tsx.
100
+ * Wraps in an error boundary so a broken app doesn't crash the entire site.
101
+ */
102
+ export function CustomAppLoader({ slug }: CustomAppLoaderProps) {
103
+ const AppComponent = getAppComponent(slug)
104
+
105
+ return (
106
+ <AppErrorBoundary slug={slug}>
107
+ <Suspense fallback={
108
+ <div className="min-h-screen flex items-center justify-center">
109
+ <LoadingSpinner />
110
+ </div>
111
+ }>
112
+ <AppComponent />
113
+ </Suspense>
114
+ </AppErrorBoundary>
115
+ )
116
+ }