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,227 @@
1
+ /// <reference types="node" />
2
+ /**
3
+ * @module cli/commands/test
4
+ * @audience installer
5
+ * @layer cli
6
+ * @stability stable
7
+ *
8
+ * `spine test` command — unified test runner for all 4 test surfaces.
9
+ * Runs Vitest tests and persists results to Supabase via the custom reporter.
10
+ *
11
+ * **Commands:**
12
+ * | Subcommand | Description |
13
+ * |-------------------------|-------------------------------------------------------|
14
+ * | `test` | Run all test suites |
15
+ * | `test unit` | Run unit tests only |
16
+ * | `test integration` | Run integration tests only |
17
+ * | `test api` | Run API tests only |
18
+ * | `test ui` | Run UI/Playwright tests only |
19
+ * | `test --json` | Output structured JSON summary |
20
+ * | `test --watch` | Run in watch mode (for unit/integration) |
21
+ *
22
+ * **Test surfaces:**
23
+ * - **unit**: Fast tests, no DB (v2-core/tests/unit/)
24
+ * - **integration**: DB tests with fixtures (v2-core/tests/integration/)
25
+ * - **api**: HTTP fetch tests against localhost:8888 (v2-core/tests/api/)
26
+ * - **ui**: Playwright browser tests (v2-core/tests/ui/)
27
+ *
28
+ * **Results:**
29
+ * All test runs are persisted to `public.test_runs` and `public.test_results`
30
+ * via the custom Vitest reporter (v2-core/tests/reporter.ts).
31
+ *
32
+ * **Usage:**
33
+ * ```bash
34
+ * spine test
35
+ * spine test unit --watch
36
+ * spine test integration --json
37
+ * spine test api
38
+ * spine test ui
39
+ * ```
40
+ *
41
+ * @seeAlso tests/reporter.ts (custom Vitest reporter)
42
+ * @seeAlso functions/tests.ts (API endpoint for querying results)
43
+ * @seeAlso pages/admin/TestingDashboard.tsx (UI for viewing results)
44
+ */
45
+
46
+ import type { Command } from 'commander'
47
+ import { spawn } from 'child_process'
48
+ import { resolve, dirname } from 'path'
49
+ import { fileURLToPath } from 'url'
50
+
51
+ const __filename = fileURLToPath(import.meta.url)
52
+ const __dirname = dirname(__filename)
53
+ const PROJECT_ROOT = resolve(__dirname, '../../../')
54
+
55
+ // ─── TYPES ─────────────────────────────────────────────────────────────────
56
+
57
+ type TestSuite = 'unit' | 'integration' | 'api' | 'ui' | 'all'
58
+
59
+ // ─── SUITE CONFIGURATION ───────────────────────────────────────────────────
60
+
61
+ const SUITES: Record<string, { pattern: string; runner: 'vitest' | 'playwright' | 'node' }> = {
62
+ unit: { pattern: 'v2-core/tests/unit', runner: 'vitest' },
63
+ integration: { pattern: 'v2-core/tests/integration', runner: 'vitest' },
64
+ api: { pattern: 'v2-core/tests/api', runner: 'vitest' },
65
+ ui: { pattern: 'v2-core/tests/ui', runner: 'playwright' }
66
+ }
67
+
68
+ // ─── COMMAND REGISTRATION ──────────────────────────────────────────────────
69
+
70
+ export function registerTestCommands(program: Command) {
71
+ const testCmd = program
72
+ .command('test [suite]')
73
+ .description('Run Spine test suites')
74
+ .option('--json', 'Output as JSON')
75
+ .option('--watch', 'Watch mode (unit/integration only)')
76
+ .option('--reporter <name>', 'Vitest reporter', 'default')
77
+ .action(async (suiteArg: string | undefined, opts) => {
78
+ const suite: TestSuite = (suiteArg || 'all') as TestSuite
79
+
80
+ // Validate suite
81
+ if (suite !== 'all' && !SUITES[suite]) {
82
+ console.error(`\n❌ Unknown test suite: ${suite}`)
83
+ console.log('Valid suites: unit, integration, api, ui, all')
84
+ process.exit(1)
85
+ }
86
+
87
+ // Determine which suites to run
88
+ const suitesToRun = suite === 'all'
89
+ ? ['unit', 'integration', 'api', 'ui']
90
+ : [suite]
91
+
92
+ console.log(`\n🧪 Running Spine test suites: ${suitesToRun.join(', ')}\n`)
93
+
94
+ const results: Array<{ suite: string; exitCode: number; passed: boolean }> = []
95
+
96
+ for (const s of suitesToRun) {
97
+ const config = SUITES[s]
98
+ console.log(`\n▶️ ${s.toUpperCase()} tests (${config.runner})`)
99
+ console.log('-'.repeat(40))
100
+
101
+ try {
102
+ let exitCode: number
103
+
104
+ if (config.runner === 'vitest') {
105
+ exitCode = await runVitest(s, opts)
106
+ } else if (config.runner === 'playwright') {
107
+ exitCode = await runPlaywright(s, opts)
108
+ } else {
109
+ exitCode = await runNode(s, opts)
110
+ }
111
+
112
+ results.push({ suite: s, exitCode, passed: exitCode === 0 })
113
+
114
+ if (exitCode === 0) {
115
+ console.log(`✓ ${s} tests passed\n`)
116
+ } else {
117
+ console.error(`✗ ${s} tests failed (exit ${exitCode})\n`)
118
+ }
119
+
120
+ } catch (err: any) {
121
+ console.error(`\n❌ Error running ${s} tests:`, err.message)
122
+ results.push({ suite: s, exitCode: 1, passed: false })
123
+ }
124
+ }
125
+
126
+ // Summary
127
+ console.log('\n' + '='.repeat(50))
128
+ console.log('Test Run Summary')
129
+ console.log('='.repeat(50))
130
+
131
+ const totalPassed = results.filter(r => r.passed).length
132
+ const totalFailed = results.filter(r => !r.passed).length
133
+
134
+ for (const r of results) {
135
+ const icon = r.passed ? '✓' : '✗'
136
+ const status = r.passed ? 'PASSED' : 'FAILED'
137
+ console.log(`${icon} ${r.suite.padEnd(12)} ${status}`)
138
+ }
139
+
140
+ console.log()
141
+ console.log(`Total: ${totalPassed} passed, ${totalFailed} failed`)
142
+
143
+ // JSON output
144
+ if (opts.json) {
145
+ const jsonOutput = {
146
+ suites: results.map(r => ({
147
+ suite: r.suite,
148
+ status: r.passed ? 'passed' : 'failed',
149
+ exit_code: r.exitCode
150
+ })),
151
+ summary: {
152
+ total: results.length,
153
+ passed: totalPassed,
154
+ failed: totalFailed
155
+ }
156
+ }
157
+ console.log('\n' + JSON.stringify(jsonOutput, null, 2))
158
+ }
159
+
160
+ // Exit code
161
+ process.exit(totalFailed > 0 ? 1 : 0)
162
+ })
163
+ }
164
+
165
+ // ─── RUNNER IMPLEMENTATIONS ────────────────────────────────────────────────
166
+
167
+ async function runVitest(suite: string, opts: any): Promise<number> {
168
+ const config = SUITES[suite]
169
+ const args = [
170
+ 'run',
171
+ config.pattern,
172
+ '--config', resolve(PROJECT_ROOT, 'vitest.config.ts')
173
+ ]
174
+
175
+ if (opts.watch) {
176
+ args[0] = 'watch' // Replace 'run' with 'watch'
177
+ }
178
+
179
+ // Custom reporters - include both default and our custom reporter
180
+ if (opts.reporter === 'default') {
181
+ args.push('--reporter=default')
182
+ args.push('--reporter=' + resolve(PROJECT_ROOT, 'v2-core/tests/reporter.ts'))
183
+ } else {
184
+ args.push(`--reporter=${opts.reporter}`)
185
+ }
186
+
187
+ return runCommand('npx', ['vitest', ...args], PROJECT_ROOT)
188
+ }
189
+
190
+ async function runPlaywright(suite: string, opts: any): Promise<number> {
191
+ // Playwright tests run against a running dev server
192
+ // We need to ensure the server is running or start it
193
+ console.log(' (Playwright tests require dev server on localhost:8888)')
194
+
195
+ const args = ['playwright', 'test', SUITES[suite].pattern]
196
+
197
+ if (opts.json) {
198
+ args.push('--reporter=json')
199
+ }
200
+
201
+ return runCommand('npx', args, PROJECT_ROOT)
202
+ }
203
+
204
+ async function runNode(suite: string, opts: any): Promise<number> {
205
+ // For custom test scripts that aren't Vitest or Playwright
206
+ const args = [SUITES[suite].pattern]
207
+ return runCommand('node', args, PROJECT_ROOT)
208
+ }
209
+
210
+ function runCommand(command: string, args: string[], cwd: string): Promise<number> {
211
+ return new Promise((resolve, reject) => {
212
+ const proc = spawn(command, args, {
213
+ cwd,
214
+ stdio: 'inherit',
215
+ env: process.env,
216
+ shell: true
217
+ })
218
+
219
+ proc.on('exit', (code) => {
220
+ resolve(code || 0)
221
+ })
222
+
223
+ proc.on('error', (err) => {
224
+ reject(err)
225
+ })
226
+ })
227
+ }
@@ -0,0 +1,166 @@
1
+ /// <reference types="node" />
2
+ /**
3
+ * @module cli/commands/uninstall-app
4
+ * @audience installer
5
+ * @layer cli
6
+ * @stability stable
7
+ *
8
+ * `spine-framework uninstall-app <slug>` — Soft-uninstall an app.
9
+ *
10
+ * Deactivates the app's types, link types, and triggers in the database.
11
+ * Does NOT delete data (items, threads, etc.) — those remain for audit.
12
+ * Does NOT remove filesystem files — the app code stays in custom/apps/.
13
+ *
14
+ * To fully remove: manually delete the app directory after uninstall.
15
+ *
16
+ * **Usage:**
17
+ * ```bash
18
+ * spine-framework uninstall-app cortex
19
+ * spine-framework uninstall-app cortex --hard # Also deactivate items
20
+ * ```
21
+ */
22
+
23
+ import type { Command } from 'commander'
24
+ import { adminDb } from '../../functions/_shared/index.ts'
25
+
26
+ interface UninstallOptions {
27
+ hard: boolean
28
+ dryRun: boolean
29
+ }
30
+
31
+ async function uninstallApp(slug: string, options: UninstallOptions): Promise<void> {
32
+ console.log(`\n🗑️ Uninstalling app '${slug}'...\n`)
33
+
34
+ // 1. Find the app
35
+ const { data: app, error: appErr } = await adminDb
36
+ .from('apps')
37
+ .select('id, name')
38
+ .eq('slug', slug)
39
+ .single()
40
+
41
+ if (appErr || !app) {
42
+ console.error(` ❌ App '${slug}' not found in database`)
43
+ process.exit(1)
44
+ }
45
+
46
+ const appId = app.id
47
+
48
+ // 2. Deactivate types
49
+ if (options.dryRun) {
50
+ const { data: types } = await adminDb
51
+ .from('types').select('slug').eq('app_id', appId).eq('is_active', true)
52
+ console.log(` [dry-run] Would deactivate ${types?.length || 0} types`)
53
+ } else {
54
+ const { data: updated } = await adminDb
55
+ .from('types')
56
+ .update({ is_active: false })
57
+ .eq('app_id', appId)
58
+ .eq('is_active', true)
59
+ .select('id')
60
+
61
+ console.log(` ✓ Deactivated ${updated?.length || 0} types`)
62
+ }
63
+
64
+ // 3. Deactivate link types
65
+ if (options.dryRun) {
66
+ const { data: lt } = await adminDb
67
+ .from('link_types').select('slug').eq('app_id', appId).eq('is_active', true)
68
+ console.log(` [dry-run] Would deactivate ${lt?.length || 0} link types`)
69
+ } else {
70
+ const { data: updated } = await adminDb
71
+ .from('link_types')
72
+ .update({ is_active: false })
73
+ .eq('app_id', appId)
74
+ .eq('is_active', true)
75
+ .select('id')
76
+
77
+ console.log(` ✓ Deactivated ${updated?.length || 0} link types`)
78
+ }
79
+
80
+ // 4. Deactivate triggers
81
+ if (options.dryRun) {
82
+ const { data: triggers } = await adminDb
83
+ .from('triggers').select('name').eq('app_id', appId).eq('is_active', true)
84
+ console.log(` [dry-run] Would deactivate ${triggers?.length || 0} triggers`)
85
+ } else {
86
+ const { data: updated } = await adminDb
87
+ .from('triggers')
88
+ .update({ is_active: false })
89
+ .eq('app_id', appId)
90
+ .eq('is_active', true)
91
+ .select('id')
92
+
93
+ console.log(` ✓ Deactivated ${updated?.length || 0} triggers`)
94
+ }
95
+
96
+ // 5. Hard mode: deactivate items of this app's types
97
+ if (options.hard) {
98
+ if (options.dryRun) {
99
+ const { data: types } = await adminDb
100
+ .from('types').select('id').eq('app_id', appId)
101
+ const typeIds = types?.map(t => t.id) || []
102
+ if (typeIds.length > 0) {
103
+ const { data: items } = await adminDb
104
+ .from('items').select('id').in('type_id', typeIds).eq('is_active', true)
105
+ console.log(` [dry-run] Would deactivate ${items?.length || 0} items (--hard)`)
106
+ }
107
+ } else {
108
+ const { data: types } = await adminDb
109
+ .from('types').select('id').eq('app_id', appId)
110
+ const typeIds = types?.map(t => t.id) || []
111
+
112
+ if (typeIds.length > 0) {
113
+ const { data: updated } = await adminDb
114
+ .from('items')
115
+ .update({ is_active: false })
116
+ .in('type_id', typeIds)
117
+ .eq('is_active', true)
118
+ .select('id')
119
+
120
+ console.log(` ✓ Deactivated ${updated?.length || 0} items (--hard)`)
121
+ }
122
+ }
123
+ }
124
+
125
+ // 6. Mark installation as disabled
126
+ if (!options.dryRun) {
127
+ await adminDb
128
+ .from('app_installations')
129
+ .update({ is_enabled: false, updated_at: new Date().toISOString() })
130
+ .eq('app_slug', slug)
131
+ }
132
+
133
+ // 7. Deactivate app record
134
+ if (!options.dryRun) {
135
+ await adminDb
136
+ .from('apps')
137
+ .update({ is_active: false })
138
+ .eq('id', appId)
139
+
140
+ console.log(` ✓ App '${slug}' deactivated`)
141
+ }
142
+
143
+ console.log(`\n✅ App '${app.name}' uninstalled (soft-delete)`)
144
+ if (!options.hard) {
145
+ console.log(` Items created by this app are preserved.`)
146
+ console.log(` Use --hard to also deactivate items.`)
147
+ }
148
+ console.log(` App files remain in custom/apps/${slug}/ — delete manually if desired.`)
149
+ }
150
+
151
+ export function registerUninstallAppCommands(program: Command) {
152
+ program
153
+ .command('uninstall-app <slug>')
154
+ .description('Soft-uninstall an app (deactivate types, triggers, link types)')
155
+ .option('--hard', 'Also deactivate items created by this app', false)
156
+ .option('--dry-run', 'Show what would happen without making changes', false)
157
+ .action(async (slug, opts) => {
158
+ try {
159
+ await uninstallApp(slug, opts)
160
+ } catch (err: any) {
161
+ console.error('Error:', err.message)
162
+ if (process.env.SPINE_CLI_DEBUG) console.error(err.stack)
163
+ process.exit(1)
164
+ }
165
+ })
166
+ }
@@ -0,0 +1,268 @@
1
+ /// <reference types="node" />
2
+ /**
3
+ * @module cli/context
4
+ * @audience installer
5
+ * @layer cli
6
+ * @stability stable
7
+ *
8
+ * CLI context builder and output utilities. This is the CLI equivalent of
9
+ * `createHandler()` in `middleware.ts` — it resolves the principal, picks the
10
+ * correct Supabase client, and returns a `CoreContext` that every CLI command
11
+ * passes directly to core functions.
12
+ *
13
+ * **Environment variables read from `.xenv` or `process.env`:**
14
+ * | Variable | Required | Purpose |
15
+ * |---------------------------|----------|------------------------------------|
16
+ * | `SUPABASE_URL` | yes | Project API URL |
17
+ * | `SUPABASE_SERVICE_ROLE_KEY` | yes | Service-role client (admin ops) |
18
+ * | `SUPABASE_ANON_KEY` | yes | User-scoped client (JWT mode) |
19
+ * | `SPINE_CLI_ACCOUNT_ID` | no | Default account scope |
20
+ * | `SPINE_CLI_JWT` | no | Human principal (Supabase JWT) |
21
+ * | `SPINE_CLI_API_KEY` | no | Machine principal (hashed key) |
22
+ * | `SPINE_CLI_DEBUG` | no | Print stack traces on error |
23
+ *
24
+ * **Principal resolution priority** (first match wins):
25
+ * 1. `SPINE_CLI_JWT` → human principal (RLS-scoped `getUserDb`)
26
+ * 2. `SPINE_CLI_API_KEY` → machine principal (`adminDb`)
27
+ * 3. Fallback → `SYSTEM_PRINCIPAL` (`adminDb` — admin ops only)
28
+ *
29
+ * @seeAlso functions/_shared/middleware.ts (createHandler — server-side equivalent)
30
+ * @seeAlso functions/_shared/principal.ts (Principal type and SYSTEM_PRINCIPAL)
31
+ * @seeAlso cli/index.ts (entry point that imports all commands)
32
+ */
33
+
34
+ import { readFileSync, existsSync } from 'fs'
35
+ import { resolve, dirname } from 'path'
36
+ import { fileURLToPath } from 'url'
37
+ import { CoreContext, adminDb, SYSTEM_PRINCIPAL, Principal, getUserDb } from '../functions/_shared/index.ts'
38
+
39
+ const __filename = fileURLToPath(import.meta.url)
40
+ const __dirname = dirname(__filename)
41
+
42
+ // ─── ENV LOADING ────────────────────────────────────────────────────────────
43
+
44
+ // ─── CHUNK_START: CLI_CONTEXT_LOAD_ENV ──────────────────────────────────────────────
45
+ /**
46
+ * @chunk-id CLI_CONTEXT_LOAD_ENV_1_0_0
47
+ * @version 1.0.0
48
+ * @hash 0adefa52a0c93821ee538ffe32a4069061bd75e7cada7175b11be3e11027e369
49
+ * @macro Environment Variable Loader
50
+ * @micro Reads .xenv file and populates process.env with missing vars
51
+ * @inputs none — reads from .xenv file path
52
+ * @outputs void — mutates process.env
53
+ * @depends-on [fs, path]
54
+ * @depended-by [buildCliContext]
55
+ * @side-effects [mutates process.env, file system reads]
56
+ * @tags environment, configuration, cli, dotenv
57
+ */
58
+ function loadEnv() {
59
+ const envPath = resolve(__dirname, '../.xenv')
60
+ if (existsSync(envPath)) {
61
+ const lines = readFileSync(envPath, 'utf8').split('\n')
62
+ for (const line of lines) {
63
+ const trimmed = line.trim()
64
+ if (!trimmed || trimmed.startsWith('#')) continue
65
+ const eqIdx = trimmed.indexOf('=')
66
+ if (eqIdx === -1) continue
67
+ const key = trimmed.slice(0, eqIdx).trim()
68
+ const value = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '')
69
+ if (!process.env[key]) {
70
+ process.env[key] = value
71
+ }
72
+ }
73
+ }
74
+ }
75
+ // ─── CHUNK_END: CLI_CONTEXT_LOAD_ENV ────────────────────────────────────────────────
76
+
77
+ // ─── TYPES ──────────────────────────────────────────────────────────────────
78
+
79
+ /**
80
+ * Options passed from CLI command `.action()` callbacks to `buildCliContext`.
81
+ *
82
+ * @inputSpec account: string | undefined — UUID of the target account; overrides
83
+ * `SPINE_CLI_ACCOUNT_ID` if both are present.
84
+ * @calledBy All `registerXxxCommands` functions before calling core functions
85
+ */
86
+ export interface CliOptions {
87
+ account?: string
88
+ }
89
+
90
+ // ─── CONTEXT BUILDER ─────────────────────────────────────────────────────────
91
+
92
+ // ─── CHUNK_START: CLI_CONTEXT_BUILD ──────────────────────────────────────────────
93
+ /**
94
+ * @chunk-id CLI_CONTEXT_BUILD_1_0_0
95
+ * @version 1.0.0
96
+ * @hash 501162983b1b24e9a15267ca7b8398b3733f540b2a65a96d8277ec3d780f2003
97
+ * @macro CLI Context Builder
98
+ * @micro Constructs CoreContext with principal resolution and Supabase client
99
+ * @inputs opts: CliOptions — Optional overrides including account ID
100
+ * @outputs CoreContext — Fully resolved context with principal, DB client, and request ID
101
+ * @depends-on [loadEnv, adminDb, getUserDb, SYSTEM_PRINCIPAL]
102
+ * @depended-by [All CLI command handlers]
103
+ * @side-effects [DB queries, environment reads, crypto.randomUUID]
104
+ * @tags cli, authentication, principal-resolution, context
105
+ */
106
+ export async function buildCliContext(opts: CliOptions = {}): Promise<CoreContext> {
107
+ loadEnv()
108
+
109
+ if (!process.env.SUPABASE_URL || !process.env.SUPABASE_SERVICE_ROLE_KEY) {
110
+ throw new Error(
111
+ 'Missing required env vars: SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.\n' +
112
+ 'Set them in v2-core/.xenv or export them before running spine commands.'
113
+ )
114
+ }
115
+
116
+ const accountId = opts.account || process.env.SPINE_CLI_ACCOUNT_ID || null
117
+ const requestId = crypto.randomUUID()
118
+
119
+ // Machine API key auth
120
+ const apiKey = process.env.SPINE_CLI_API_KEY
121
+ if (apiKey) {
122
+ const { data: keyRecord } = await adminDb
123
+ .from('api_keys')
124
+ .select('id, account_id, scopes, principal_id')
125
+ .eq('key_hash', apiKey)
126
+ .eq('is_active', true)
127
+ .single()
128
+
129
+ if (!keyRecord) {
130
+ throw new Error('Invalid or inactive SPINE_CLI_API_KEY')
131
+ }
132
+
133
+ const principal: Principal = {
134
+ id: keyRecord.principal_id || keyRecord.id,
135
+ type: 'machine',
136
+ accountId: keyRecord.account_id,
137
+ scopes: keyRecord.scopes || [],
138
+ provenance: {
139
+ sourceType: 'api_key',
140
+ createdBy: null,
141
+ apiKeyId: keyRecord.id,
142
+ invokedAt: new Date().toISOString()
143
+ }
144
+ }
145
+
146
+ return {
147
+ principal,
148
+ accountId: accountId || keyRecord.account_id,
149
+ db: adminDb,
150
+ requestId
151
+ }
152
+ }
153
+
154
+ // JWT auth (human principal)
155
+ const jwt = process.env.SPINE_CLI_JWT
156
+ if (jwt) {
157
+ const userDb = getUserDb(jwt)
158
+ const { data: { user } } = await userDb.auth.getUser()
159
+
160
+ if (!user) {
161
+ throw new Error('Invalid or expired SPINE_CLI_JWT')
162
+ }
163
+
164
+ const { data: person } = await adminDb
165
+ .from('people')
166
+ .select('id, full_name, email, roles:people_roles(role:roles(slug))')
167
+ .eq('auth_user_id', user.id)
168
+ .single()
169
+
170
+ const roles = (person?.roles as any[])?.map((r: any) => r.role?.slug).filter(Boolean) || []
171
+
172
+ const principal: Principal = {
173
+ id: person?.id || user.id,
174
+ type: 'human',
175
+ accountId: accountId,
176
+ displayName: person?.full_name || user.email,
177
+ email: person?.email || user.email,
178
+ roles,
179
+ provenance: {
180
+ sourceType: 'jwt',
181
+ createdBy: person?.id || user.id,
182
+ invokedAt: new Date().toISOString()
183
+ },
184
+ authContext: { jwt }
185
+ }
186
+
187
+ return {
188
+ principal,
189
+ accountId,
190
+ db: userDb,
191
+ requestId
192
+ }
193
+ }
194
+
195
+ // Fallback: system principal (admin ops)
196
+ return {
197
+ principal: SYSTEM_PRINCIPAL,
198
+ accountId,
199
+ db: adminDb,
200
+ requestId
201
+ }
202
+ }
203
+ // ─── CHUNK_END: CLI_CONTEXT_BUILD ────────────────────────────────────────────────
204
+
205
+ // ─── OUTPUT UTILITIES ─────────────────────────────────────────────────────────
206
+
207
+ // ─── CHUNK_START: CLI_CONTEXT_PRINT_RESULT ──────────────────────────────────────────────
208
+ /**
209
+ * @chunk-id CLI_CONTEXT_PRINT_RESULT_1_0_0
210
+ * @version 1.0.0
211
+ * @hash 06e492defa9012290a5c8b2d4fca27f01df11bdc194ffbdf4f4b4518aa683c2b
212
+ * @macro CLI Output Formatter
213
+ * @micro Pretty-prints query results as JSON or ASCII tables
214
+ * @inputs data: any — Result data to display (array or single value)
215
+ * @inputs opts: { json?: boolean } — Output format options
216
+ * @outputs void — Console output only
217
+ * @depends-on [console, JSON]
218
+ * @depended-by [All CLI command list/get handlers]
219
+ * @side-effects [console.log output]
220
+ * @tags cli, output, formatting, tables, json
221
+ */
222
+ export function printResult(data: any, opts: { json?: boolean } = {}) {
223
+ if (opts.json) {
224
+ console.log(JSON.stringify(data, null, 2))
225
+ return
226
+ }
227
+
228
+ if (Array.isArray(data)) {
229
+ if (data.length === 0) {
230
+ console.log('(no results)')
231
+ return
232
+ }
233
+ const keys = Object.keys(data[0])
234
+ const rows = data.map(row => keys.map(k => String(row[k] ?? '')))
235
+ const widths = keys.map((k, i) => Math.max(k.length, ...rows.map(r => r[i].length)))
236
+ const hr = widths.map(w => '-'.repeat(w)).join(' ')
237
+ console.log(keys.map((k, i) => k.padEnd(widths[i])).join(' '))
238
+ console.log(hr)
239
+ rows.forEach(row => console.log(row.map((v, i) => v.padEnd(widths[i])).join(' ')))
240
+ console.log(`\n(${data.length} row${data.length !== 1 ? 's' : ''})`)
241
+ } else {
242
+ console.log(JSON.stringify(data, null, 2))
243
+ }
244
+ }
245
+ // ─── CHUNK_END: CLI_CONTEXT_PRINT_RESULT ────────────────────────────────────────────────
246
+
247
+ // ─── CHUNK_START: CLI_CONTEXT_HANDLE_ERROR ──────────────────────────────────────────────
248
+ /**
249
+ * @chunk-id CLI_CONTEXT_HANDLE_ERROR_1_0_0
250
+ * @version 1.0.0
251
+ * @hash 61aca7e4bce61b5b790e8f27ef3f505a6a6fe9a8cd6643e577f610d9dd15b1cd
252
+ * @macro CLI Error Handler
253
+ * @micro Prints formatted error and exits with proper debug information
254
+ * @inputs err: any — Error object or string message
255
+ * @outputs void — Process termination (exit code 1)
256
+ * @depends-on [console, process]
257
+ * @depended-by [All CLI command action handlers]
258
+ * @side-effects [console.error output, process.exit]
259
+ * @tags cli, error-handling, debug, process-exit
260
+ */
261
+ export function handleError(err: any) {
262
+ console.error(`\nError: ${err.message || err}`)
263
+ if (process.env.SPINE_CLI_DEBUG) {
264
+ console.error(err.stack)
265
+ }
266
+ process.exit(1)
267
+ }
268
+ // ─── CHUNK_END: CLI_CONTEXT_HANDLE_ERROR ────────────────────────────────────────────────
@@ -0,0 +1,36 @@
1
+ /// <reference types="node" />
2
+ /**
3
+ * @module cli/env-loader
4
+ * @audience installer
5
+ * @layer cli
6
+ * @stability stable
7
+ *
8
+ * Side-effect module: loads `v2-core/.xenv` into `process.env` before any
9
+ * other CLI module is imported. Must be the first import in `cli/index.ts`
10
+ * so that `db.ts` (which reads env vars at module-load time) sees the values.
11
+ *
12
+ * @sideEffects Mutates process.env — only sets keys not already present
13
+ */
14
+
15
+ import { readFileSync, existsSync } from 'fs'
16
+ import { resolve, dirname } from 'path'
17
+ import { fileURLToPath } from 'url'
18
+
19
+ const __filename = fileURLToPath(import.meta.url)
20
+ const __dirname = dirname(__filename)
21
+
22
+ const envPath = resolve(__dirname, '../.xenv')
23
+ if (existsSync(envPath)) {
24
+ const lines = readFileSync(envPath, 'utf8').split('\n')
25
+ for (const line of lines) {
26
+ const trimmed = line.trim()
27
+ if (!trimmed || trimmed.startsWith('#')) continue
28
+ const eqIdx = trimmed.indexOf('=')
29
+ if (eqIdx === -1) continue
30
+ const key = trimmed.slice(0, eqIdx).trim()
31
+ const value = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '')
32
+ if (!process.env[key]) {
33
+ process.env[key] = value
34
+ }
35
+ }
36
+ }