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.
- package/.framework/README.md +129 -0
- package/.framework/cli/bin.cjs +14 -0
- package/.framework/cli/commands/agents.ts +153 -0
- package/.framework/cli/commands/auth.ts +94 -0
- package/.framework/cli/commands/create-app.ts +185 -0
- package/.framework/cli/commands/dev.ts +295 -0
- package/.framework/cli/commands/doctor.ts +442 -0
- package/.framework/cli/commands/generate.ts +332 -0
- package/.framework/cli/commands/init.ts +272 -0
- package/.framework/cli/commands/install-app.ts +391 -0
- package/.framework/cli/commands/items.ts +253 -0
- package/.framework/cli/commands/migrations.ts +141 -0
- package/.framework/cli/commands/pipelines.ts +166 -0
- package/.framework/cli/commands/status.ts +197 -0
- package/.framework/cli/commands/system.ts +184 -0
- package/.framework/cli/commands/test.ts +227 -0
- package/.framework/cli/commands/uninstall-app.ts +166 -0
- package/.framework/cli/context.ts +268 -0
- package/.framework/cli/env-loader.ts +36 -0
- package/.framework/cli/index.ts +106 -0
- package/.framework/cli/welcome.cjs +45 -0
- package/.framework/docs/API.md +384 -0
- package/.framework/docs/STABILITY.md +52 -0
- package/.framework/docs/admin-routes.md +76 -0
- package/.framework/docs/api-docs-progress.md +38 -0
- package/.framework/docs/api-governance.md +146 -0
- package/.framework/docs/api-testing-results.md +212 -0
- package/.framework/docs/apis/admin-configs.md +567 -0
- package/.framework/docs/apis/admin-data.md +272 -0
- package/.framework/docs/apis/index.md +231 -0
- package/.framework/docs/apis/internal.md +295 -0
- package/.framework/docs/apis/runtime.md +537 -0
- package/.framework/docs/assembly-launch-guide.md +138 -0
- package/.framework/docs/audit-results.md +590 -0
- package/.framework/docs/authorization-model.md +170 -0
- package/.framework/docs/db-api-inventory.md +95 -0
- package/.framework/docs/examples/custom-app/README.md +77 -0
- package/.framework/docs/examples/custom-function/README.md +27 -0
- package/.framework/docs/examples/custom-function/handler.ts +48 -0
- package/.framework/docs/examples/custom-webhook/README.md +68 -0
- package/.framework/docs/gap-remediation-backlog.md +103 -0
- package/.framework/docs/guides/cli-guide.md +224 -0
- package/.framework/docs/guides/getting-started.md +103 -0
- package/.framework/docs/guides/import-guide.md +193 -0
- package/.framework/docs/guides/testing-guide.md +229 -0
- package/.framework/docs/permission-examples.md +326 -0
- package/.framework/docs/ui-adoption-verification.md +111 -0
- package/.framework/docs/ui-api-coverage.md +84 -0
- package/.framework/docs/v2-compatibility-audit.md +228 -0
- package/.framework/functions/.gitkeep +1 -0
- package/.framework/functions/_shared/agent-runner.ts +1097 -0
- package/.framework/functions/_shared/app-manifest.ts +184 -0
- package/.framework/functions/_shared/audit.ts +150 -0
- package/.framework/functions/_shared/db.ts +174 -0
- package/.framework/functions/_shared/index.ts +382 -0
- package/.framework/functions/_shared/middleware.ts +490 -0
- package/.framework/functions/_shared/permissions.ts +1325 -0
- package/.framework/functions/_shared/pipeline-runner.ts +731 -0
- package/.framework/functions/_shared/principal.ts +760 -0
- package/.framework/functions/_shared/schema-utils.ts +967 -0
- package/.framework/functions/_shared/testing.ts +258 -0
- package/.framework/functions/_shared/trigger-engine.ts +425 -0
- package/.framework/functions/_shared/webhook-registration.ts +168 -0
- package/.framework/functions/_shared/webhook-registry.ts +129 -0
- package/.framework/functions/account-nodes.ts +111 -0
- package/.framework/functions/admin-data.ts +606 -0
- package/.framework/functions/ai-agents.ts +323 -0
- package/.framework/functions/api-keys.ts +376 -0
- package/.framework/functions/apps.ts +483 -0
- package/.framework/functions/auth.ts +196 -0
- package/.framework/functions/debug-auth.ts +107 -0
- package/.framework/functions/embeddings.ts +556 -0
- package/.framework/functions/integration-routes.ts +523 -0
- package/.framework/functions/integrations.ts +319 -0
- package/.framework/functions/item-progress.ts +272 -0
- package/.framework/functions/logs.ts +438 -0
- package/.framework/functions/observability.ts +275 -0
- package/.framework/functions/pipeline-executions.ts +494 -0
- package/.framework/functions/pipelines.ts +485 -0
- package/.framework/functions/prompt-configs.ts +339 -0
- package/.framework/functions/roles.ts +387 -0
- package/.framework/functions/system-cron.ts +742 -0
- package/.framework/functions/system.ts +323 -0
- package/.framework/functions/tests.ts +119 -0
- package/.framework/functions/timers.ts +357 -0
- package/.framework/functions/triggers.ts +563 -0
- package/.framework/functions/types.ts +604 -0
- package/.framework/migrations/000_foundation.sql +1256 -0
- package/.framework/migrations/001_seed.sql +92 -0
- package/.framework/migrations/002_seed_constraints.sql +13 -0
- package/.framework/migrations/003_auth_user_trigger.sql +59 -0
- package/.framework/src/App.tsx +126 -0
- package/.framework/src/apps/admin/index.tsx +173 -0
- package/.framework/src/components/AppWrapper.tsx +56 -0
- package/.framework/src/components/CustomAppLoader.tsx +116 -0
- package/.framework/src/components/admin/AdminListPage.tsx +151 -0
- package/.framework/src/components/admin/AdminSidebar.tsx +166 -0
- package/.framework/src/components/admin/AdminStatsCard.tsx +62 -0
- package/.framework/src/components/admin/SortableTableHeader.tsx +42 -0
- package/.framework/src/components/app-shell/GenericAppShell.tsx +181 -0
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +200 -0
- package/.framework/src/components/app-shell/GenericListPage.tsx +116 -0
- package/.framework/src/components/app-sidebar.tsx +228 -0
- package/.framework/src/components/auth/ProtectedRoute.tsx +88 -0
- package/.framework/src/components/layout/AppShell.tsx +91 -0
- package/.framework/src/components/layout/Header.tsx +88 -0
- package/.framework/src/components/layout/Layout.tsx +95 -0
- package/.framework/src/components/layout/Sidebar.tsx +329 -0
- package/.framework/src/components/runtime/DataDetailHeader.tsx +77 -0
- package/.framework/src/components/runtime/DataDetailPage.tsx +171 -0
- package/.framework/src/components/runtime/DataFilters.tsx +91 -0
- package/.framework/src/components/runtime/DataHeader.tsx +68 -0
- package/.framework/src/components/runtime/DataListPage.tsx +124 -0
- package/.framework/src/components/runtime/DataStats.tsx +70 -0
- package/.framework/src/components/runtime/DataTable.tsx +174 -0
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +134 -0
- package/.framework/src/components/runtime/index.ts +18 -0
- package/.framework/src/components/search-form.tsx +29 -0
- package/.framework/src/components/shared/AgentView.tsx +213 -0
- package/.framework/src/components/shared/FieldRenderer.tsx +478 -0
- package/.framework/src/components/shared/SchemaFields.tsx +226 -0
- package/.framework/src/components/ui/DataTable.tsx +343 -0
- package/.framework/src/components/ui/Form.tsx +281 -0
- package/.framework/src/components/ui/ItemCard.tsx +296 -0
- package/.framework/src/components/ui/ItemListView.tsx +308 -0
- package/.framework/src/components/ui/LoadingSpinner.tsx +52 -0
- package/.framework/src/components/ui/Modal.tsx +61 -0
- package/.framework/src/components/ui/RichTextEditor.tsx +210 -0
- package/.framework/src/components/ui/accordion.tsx +82 -0
- package/.framework/src/components/ui/alert-dialog.tsx +197 -0
- package/.framework/src/components/ui/alert.tsx +76 -0
- package/.framework/src/components/ui/aspect-ratio.tsx +11 -0
- package/.framework/src/components/ui/avatar.tsx +110 -0
- package/.framework/src/components/ui/badge.tsx +49 -0
- package/.framework/src/components/ui/breadcrumb.tsx +122 -0
- package/.framework/src/components/ui/button-group.tsx +83 -0
- package/.framework/src/components/ui/button.tsx +65 -0
- package/.framework/src/components/ui/calendar.tsx +222 -0
- package/.framework/src/components/ui/card.tsx +100 -0
- package/.framework/src/components/ui/carousel.tsx +240 -0
- package/.framework/src/components/ui/chart.tsx +373 -0
- package/.framework/src/components/ui/checkbox.tsx +31 -0
- package/.framework/src/components/ui/collapsible.tsx +33 -0
- package/.framework/src/components/ui/combobox.tsx +299 -0
- package/.framework/src/components/ui/command.tsx +193 -0
- package/.framework/src/components/ui/context-menu.tsx +261 -0
- package/.framework/src/components/ui/dialog.tsx +165 -0
- package/.framework/src/components/ui/direction.tsx +22 -0
- package/.framework/src/components/ui/drawer.tsx +132 -0
- package/.framework/src/components/ui/dropdown-menu.tsx +269 -0
- package/.framework/src/components/ui/empty.tsx +104 -0
- package/.framework/src/components/ui/field.tsx +238 -0
- package/.framework/src/components/ui/hover-card.tsx +42 -0
- package/.framework/src/components/ui/input-group.tsx +153 -0
- package/.framework/src/components/ui/input-otp.tsx +87 -0
- package/.framework/src/components/ui/input.tsx +19 -0
- package/.framework/src/components/ui/item.tsx +196 -0
- package/.framework/src/components/ui/kbd.tsx +26 -0
- package/.framework/src/components/ui/label.tsx +22 -0
- package/.framework/src/components/ui/menubar.tsx +277 -0
- package/.framework/src/components/ui/native-select.tsx +61 -0
- package/.framework/src/components/ui/navigation-menu.tsx +164 -0
- package/.framework/src/components/ui/pagination.tsx +129 -0
- package/.framework/src/components/ui/popover.tsx +87 -0
- package/.framework/src/components/ui/progress.tsx +31 -0
- package/.framework/src/components/ui/radio-group.tsx +42 -0
- package/.framework/src/components/ui/resizable.tsx +50 -0
- package/.framework/src/components/ui/scroll-area.tsx +53 -0
- package/.framework/src/components/ui/select.tsx +195 -0
- package/.framework/src/components/ui/separator.tsx +26 -0
- package/.framework/src/components/ui/sheet.tsx +145 -0
- package/.framework/src/components/ui/sidebar.tsx +706 -0
- package/.framework/src/components/ui/skeleton.tsx +13 -0
- package/.framework/src/components/ui/slider.tsx +59 -0
- package/.framework/src/components/ui/sonner.tsx +47 -0
- package/.framework/src/components/ui/spinner.tsx +10 -0
- package/.framework/src/components/ui/switch.tsx +33 -0
- package/.framework/src/components/ui/table-primitives.tsx +141 -0
- package/.framework/src/components/ui/table.tsx +114 -0
- package/.framework/src/components/ui/tabs.tsx +90 -0
- package/.framework/src/components/ui/textarea.tsx +18 -0
- package/.framework/src/components/ui/toggle-group.tsx +89 -0
- package/.framework/src/components/ui/toggle.tsx +45 -0
- package/.framework/src/components/ui/tooltip.tsx +57 -0
- package/.framework/src/contexts/AppContext.tsx +133 -0
- package/.framework/src/contexts/AuthContext.tsx +371 -0
- package/.framework/src/hooks/use-mobile.ts +19 -0
- package/.framework/src/hooks/useApi.ts +526 -0
- package/.framework/src/hooks/useApps.ts +114 -0
- package/.framework/src/hooks/useEntityList.ts +190 -0
- package/.framework/src/hooks/useEntityRecord.ts +308 -0
- package/.framework/src/hooks/useForm.ts +307 -0
- package/.framework/src/hooks/useListSchema.ts +264 -0
- package/.framework/src/hooks/useSchemaRecord.ts +223 -0
- package/.framework/src/index.css +128 -0
- package/.framework/src/lib/api.ts +156 -0
- package/.framework/src/lib/supabase.ts +94 -0
- package/.framework/src/lib/utils.ts +317 -0
- package/.framework/src/main.tsx +27 -0
- package/.framework/src/pages/DashboardPage.tsx +181 -0
- package/.framework/src/pages/NotFoundPage.tsx +39 -0
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +161 -0
- package/.framework/src/pages/admin/AIAgentsPage.tsx +318 -0
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +199 -0
- package/.framework/src/pages/admin/APIKeysPage.tsx +303 -0
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +523 -0
- package/.framework/src/pages/admin/AppDetailPage.tsx +493 -0
- package/.framework/src/pages/admin/AppsPage.tsx +355 -0
- package/.framework/src/pages/admin/DesignedPage.tsx +491 -0
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +534 -0
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +424 -0
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +176 -0
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +109 -0
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +402 -0
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +187 -0
- package/.framework/src/pages/admin/IntegrationsPage.tsx +301 -0
- package/.framework/src/pages/admin/LogsPage.tsx +283 -0
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +85 -0
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +470 -0
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +183 -0
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +279 -0
- package/.framework/src/pages/admin/PipelinesPage.tsx +390 -0
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +299 -0
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +292 -0
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +434 -0
- package/.framework/src/pages/admin/RoleDetailPage.tsx +273 -0
- package/.framework/src/pages/admin/RolesPage.tsx +292 -0
- package/.framework/src/pages/admin/SelectTestPage.tsx +61 -0
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +588 -0
- package/.framework/src/pages/admin/SimpleDashboard.tsx +387 -0
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +172 -0
- package/.framework/src/pages/admin/TestingDashboard.tsx +257 -0
- package/.framework/src/pages/admin/TimerDetailPage.tsx +151 -0
- package/.framework/src/pages/admin/TimersPage.tsx +376 -0
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +149 -0
- package/.framework/src/pages/admin/TriggersPage.tsx +381 -0
- package/.framework/src/pages/admin/TypeDetailPage.tsx +694 -0
- package/.framework/src/pages/admin/TypesPage.tsx +295 -0
- package/.framework/src/pages/auth/LoginPage.tsx +188 -0
- package/.framework/src/pages/auth/RegisterPage.tsx +163 -0
- package/.framework/src/pages/spine-framework/APIPage.tsx +17 -0
- package/.framework/src/pages/spine-framework/CLIPage.tsx +25 -0
- package/.framework/src/types/auth.ts +125 -0
- package/.framework/src/types/types.ts +407 -0
- package/STRUCTURE.md +150 -0
- package/config/components.json +25 -0
- package/config/deno.lock +108 -0
- package/config/package-lock.json +17183 -0
- package/config/postcss.config.cjs +10 -0
- package/config/tailwind.config.cjs +78 -0
- package/config/tsconfig.build.json +32 -0
- package/config/tsconfig.cli.json +18 -0
- package/config/tsconfig.json +41 -0
- package/config/tsconfig.node.json +17 -0
- package/config/tsconfig.node.tsbuildinfo +1 -0
- package/config/tsconfig.tsbuildinfo +1 -0
- package/config/typedoc.json +16 -0
- package/config/vite.config.d.ts +2 -0
- package/config/vite.config.ts +72 -0
- package/dist/cli/commands/agents.d.ts +39 -0
- package/dist/cli/commands/agents.d.ts.map +1 -0
- package/dist/cli/commands/auth.d.ts +36 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/create-app.d.ts +23 -0
- package/dist/cli/commands/create-app.d.ts.map +1 -0
- package/dist/cli/commands/dev.d.ts +39 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/doctor.d.ts +42 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/generate.d.ts +36 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/init.d.ts +30 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/install-app.d.ts +30 -0
- package/dist/cli/commands/install-app.d.ts.map +1 -0
- package/dist/cli/commands/items.d.ts +45 -0
- package/dist/cli/commands/items.d.ts.map +1 -0
- package/dist/cli/commands/migrations.d.ts +41 -0
- package/dist/cli/commands/migrations.d.ts.map +1 -0
- package/dist/cli/commands/pipelines.d.ts +40 -0
- package/dist/cli/commands/pipelines.d.ts.map +1 -0
- package/dist/cli/commands/status.d.ts +23 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/system.d.ts +29 -0
- package/dist/cli/commands/system.d.ts.map +1 -0
- package/dist/cli/commands/test.d.ts +46 -0
- package/dist/cli/commands/test.d.ts.map +1 -0
- package/dist/cli/commands/uninstall-app.d.ts +23 -0
- package/dist/cli/commands/uninstall-app.d.ts.map +1 -0
- package/dist/cli/context.d.ts +88 -0
- package/dist/cli/context.d.ts.map +1 -0
- package/dist/cli/env-loader.d.ts +14 -0
- package/dist/cli/env-loader.d.ts.map +1 -0
- package/dist/cli/index.d.ts +41 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/functions/_shared/agent-runner.d.ts +156 -0
- package/dist/functions/_shared/agent-runner.d.ts.map +1 -0
- package/dist/functions/_shared/app-manifest.d.ts +68 -0
- package/dist/functions/_shared/app-manifest.d.ts.map +1 -0
- package/dist/functions/_shared/audit.d.ts +91 -0
- package/dist/functions/_shared/audit.d.ts.map +1 -0
- package/dist/functions/_shared/db.d.ts +125 -0
- package/dist/functions/_shared/db.d.ts.map +1 -0
- package/dist/functions/_shared/index.d.ts +298 -0
- package/dist/functions/_shared/index.d.ts.map +1 -0
- package/dist/functions/_shared/middleware.d.ts +315 -0
- package/dist/functions/_shared/middleware.d.ts.map +1 -0
- package/dist/functions/_shared/permissions.d.ts +626 -0
- package/dist/functions/_shared/permissions.d.ts.map +1 -0
- package/dist/functions/_shared/pipeline-runner.d.ts +124 -0
- package/dist/functions/_shared/pipeline-runner.d.ts.map +1 -0
- package/dist/functions/_shared/principal.d.ts +284 -0
- package/dist/functions/_shared/principal.d.ts.map +1 -0
- package/dist/functions/_shared/schema-utils.d.ts +181 -0
- package/dist/functions/_shared/schema-utils.d.ts.map +1 -0
- package/dist/functions/_shared/testing.d.ts +172 -0
- package/dist/functions/_shared/testing.d.ts.map +1 -0
- package/dist/functions/_shared/trigger-engine.d.ts +140 -0
- package/dist/functions/_shared/trigger-engine.d.ts.map +1 -0
- package/dist/functions/_shared/webhook-registration.d.ts +81 -0
- package/dist/functions/_shared/webhook-registration.d.ts.map +1 -0
- package/dist/functions/_shared/webhook-registry.d.ts +57 -0
- package/dist/functions/_shared/webhook-registry.d.ts.map +1 -0
- package/dist/functions/account-nodes.d.ts +48 -0
- package/dist/functions/account-nodes.d.ts.map +1 -0
- package/dist/functions/admin-data.d.ts +178 -0
- package/dist/functions/admin-data.d.ts.map +1 -0
- package/dist/functions/ai-agents.d.ts +125 -0
- package/dist/functions/ai-agents.d.ts.map +1 -0
- package/dist/functions/api-keys.d.ts +140 -0
- package/dist/functions/api-keys.d.ts.map +1 -0
- package/dist/functions/apps.d.ts +163 -0
- package/dist/functions/apps.d.ts.map +1 -0
- package/dist/functions/auth.d.ts +74 -0
- package/dist/functions/auth.d.ts.map +1 -0
- package/dist/functions/debug-auth.d.ts +33 -0
- package/dist/functions/debug-auth.d.ts.map +1 -0
- package/dist/functions/embeddings.d.ts +205 -0
- package/dist/functions/embeddings.d.ts.map +1 -0
- package/dist/functions/integration-routes.d.ts +45 -0
- package/dist/functions/integration-routes.d.ts.map +1 -0
- package/dist/functions/integrations.d.ts +124 -0
- package/dist/functions/integrations.d.ts.map +1 -0
- package/dist/functions/item-progress.d.ts +41 -0
- package/dist/functions/item-progress.d.ts.map +1 -0
- package/dist/functions/logs.d.ts +162 -0
- package/dist/functions/logs.d.ts.map +1 -0
- package/dist/functions/observability.d.ts +123 -0
- package/dist/functions/observability.d.ts.map +1 -0
- package/dist/functions/pipeline-executions.d.ts +190 -0
- package/dist/functions/pipeline-executions.d.ts.map +1 -0
- package/dist/functions/pipelines.d.ts +171 -0
- package/dist/functions/pipelines.d.ts.map +1 -0
- package/dist/functions/prompt-configs.d.ts +125 -0
- package/dist/functions/prompt-configs.d.ts.map +1 -0
- package/dist/functions/roles.d.ts +118 -0
- package/dist/functions/roles.d.ts.map +1 -0
- package/dist/functions/system-cron.d.ts +65 -0
- package/dist/functions/system-cron.d.ts.map +1 -0
- package/dist/functions/system.d.ts +29 -0
- package/dist/functions/system.d.ts.map +1 -0
- package/dist/functions/tests.d.ts +28 -0
- package/dist/functions/tests.d.ts.map +1 -0
- package/dist/functions/timers.d.ts +139 -0
- package/dist/functions/timers.d.ts.map +1 -0
- package/dist/functions/triggers.d.ts +203 -0
- package/dist/functions/triggers.d.ts.map +1 -0
- package/dist/functions/types.d.ts +151 -0
- package/dist/functions/types.d.ts.map +1 -0
- package/dist/src/types/types.d.ts +364 -0
- package/dist/src/types/types.d.ts.map +1 -0
- package/package.json +192 -0
- package/scripts/app-install-cli.ts +286 -0
- package/scripts/assemble-frontend.sh +79 -0
- package/scripts/assemble-functions.sh +62 -0
- package/scripts/assemble.sh +35 -0
- package/scripts/boundary-check.sh +106 -0
- package/scripts/build-manifest.sh +80 -0
- package/scripts/check-core-integrity.sh +82 -0
- package/scripts/ingest-chunks.cjs +202 -0
- package/scripts/kb-chunk-parser.cjs +312 -0
- package/scripts/kb-chunk-parser.ts +330 -0
- package/scripts/load-test-app-install.ts +484 -0
- package/scripts/netlify-dev-wrapper.sh +22 -0
- package/scripts/verify-integrity.sh +69 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* @module cli/commands/migrations
|
|
4
|
+
* @audience installer
|
|
5
|
+
* @layer cli
|
|
6
|
+
* @stability stable
|
|
7
|
+
*
|
|
8
|
+
* `spine migrations` command group. Read-only inspection of the migration
|
|
9
|
+
* state. Does NOT apply or roll back migrations — use the Supabase CLI for
|
|
10
|
+
* that. These commands are intended for verifying the state of a deployed
|
|
11
|
+
* instance during setup or debugging.
|
|
12
|
+
*
|
|
13
|
+
* **Commands:**
|
|
14
|
+
* | Subcommand | Description |
|
|
15
|
+
* |-----------------------|-----------------------------------------------------|
|
|
16
|
+
* | `migrations list` | Show all applied migrations from `schema_migrations`|
|
|
17
|
+
* | `migrations status` | Diff local `.sql` files against applied migrations |
|
|
18
|
+
*
|
|
19
|
+
* **Authorization:** Uses `adminDb` (service-role) with an explicit
|
|
20
|
+
* `.schema('public')` override to reach `schema_migrations`. Requires
|
|
21
|
+
* `SUPABASE_SERVICE_ROLE_KEY` with public schema access.
|
|
22
|
+
*
|
|
23
|
+
* **Usage:**
|
|
24
|
+
* ```bash
|
|
25
|
+
* spine migrations list
|
|
26
|
+
* spine migrations status
|
|
27
|
+
* spine migrations status --json
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @seeAlso v2-core/migrations/ (local .sql migration files)
|
|
31
|
+
* @seeAlso cli/context.ts (buildCliContext)
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import type { Command } from 'commander'
|
|
35
|
+
import { readdirSync, existsSync } from 'fs'
|
|
36
|
+
import { resolve, dirname } from 'path'
|
|
37
|
+
import { fileURLToPath } from 'url'
|
|
38
|
+
import { buildCliContext, printResult, handleError } from '../context.ts'
|
|
39
|
+
import { adminDb } from '../../functions/_shared/index.ts'
|
|
40
|
+
|
|
41
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
42
|
+
const __dirname = dirname(__filename)
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Registers the `migrations` subcommand group on the root Commander program.
|
|
46
|
+
*
|
|
47
|
+
* @param program - The root `spine` Commander instance
|
|
48
|
+
* @sideEffects Adds `migrations list` and `migrations status` subcommands to `program`
|
|
49
|
+
* @calledBy cli/index.ts
|
|
50
|
+
*/
|
|
51
|
+
export function registerMigrationCommands(program: Command) {
|
|
52
|
+
const migrations = program
|
|
53
|
+
.command('migrations')
|
|
54
|
+
.description('Database migration inspection')
|
|
55
|
+
|
|
56
|
+
migrations
|
|
57
|
+
.command('list')
|
|
58
|
+
.description('List applied migrations from supabase schema_migrations')
|
|
59
|
+
.option('--json', 'Output as JSON')
|
|
60
|
+
.action(async (opts) => {
|
|
61
|
+
try {
|
|
62
|
+
await buildCliContext()
|
|
63
|
+
|
|
64
|
+
const { data, error } = await adminDb
|
|
65
|
+
.schema('supabase_migrations' as any)
|
|
66
|
+
.from('schema_migrations' as any)
|
|
67
|
+
.select('version, name, executed_at')
|
|
68
|
+
.order('version', { ascending: true })
|
|
69
|
+
|
|
70
|
+
if (error) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`Could not query migrations: ${error.message}\n` +
|
|
73
|
+
'Ensure SUPABASE_SERVICE_ROLE_KEY has access to the public schema.'
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
printResult(data || [], { json: opts.json })
|
|
78
|
+
} catch (err: any) {
|
|
79
|
+
handleError(err)
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
migrations
|
|
84
|
+
.command('status')
|
|
85
|
+
.description('Compare local migration files against applied migrations')
|
|
86
|
+
.option('--json', 'Output as JSON')
|
|
87
|
+
.action(async (opts) => {
|
|
88
|
+
try {
|
|
89
|
+
await buildCliContext()
|
|
90
|
+
|
|
91
|
+
const migrationsDir = resolve(__dirname, '../../migrations')
|
|
92
|
+
|
|
93
|
+
if (!existsSync(migrationsDir)) {
|
|
94
|
+
throw new Error(`Migrations directory not found: ${migrationsDir}`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const localFiles = readdirSync(migrationsDir)
|
|
98
|
+
.filter((f: string) => f.endsWith('.sql'))
|
|
99
|
+
.sort()
|
|
100
|
+
|
|
101
|
+
const { data: applied, error } = await adminDb
|
|
102
|
+
.schema('supabase_migrations' as any)
|
|
103
|
+
.from('schema_migrations' as any)
|
|
104
|
+
.select('version')
|
|
105
|
+
|
|
106
|
+
if (error) {
|
|
107
|
+
throw new Error(`Could not query migrations: ${error.message}`)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const appliedVersions = new Set(
|
|
111
|
+
(applied || []).map((r: any) => r.version)
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
const status = localFiles.map((file: string) => {
|
|
115
|
+
const version = file.replace('.sql', '')
|
|
116
|
+
const isApplied = appliedVersions.has(version)
|
|
117
|
+
return {
|
|
118
|
+
file,
|
|
119
|
+
version,
|
|
120
|
+
status: isApplied ? 'applied' : 'pending'
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
if (opts.json) {
|
|
125
|
+
console.log(JSON.stringify(status, null, 2))
|
|
126
|
+
} else {
|
|
127
|
+
console.log('\nMigration Status')
|
|
128
|
+
console.log('─'.repeat(60))
|
|
129
|
+
for (const m of status as Array<{file: string; status: string}>) {
|
|
130
|
+
const icon = m.status === 'applied' ? '✓' : '○'
|
|
131
|
+
console.log(` ${icon} ${m.file.padEnd(40)} ${m.status}`)
|
|
132
|
+
}
|
|
133
|
+
const pending = status.filter(m => m.status === 'pending').length
|
|
134
|
+
console.log(`\n ${status.length - pending} applied, ${pending} pending`)
|
|
135
|
+
console.log()
|
|
136
|
+
}
|
|
137
|
+
} catch (err: any) {
|
|
138
|
+
handleError(err)
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* @module cli/commands/pipelines
|
|
4
|
+
* @audience installer
|
|
5
|
+
* @layer cli
|
|
6
|
+
* @stability stable
|
|
7
|
+
*
|
|
8
|
+
* `spine pipelines` command group. Lists, inspects, and triggers pipeline
|
|
9
|
+
* execution directly from the terminal or an agentic IDE. `pipelines run`
|
|
10
|
+
* calls `runPipeline` — the same function used by API handlers and timers —
|
|
11
|
+
* so CLI executions are fully recorded in `pipeline_executions`.
|
|
12
|
+
*
|
|
13
|
+
* **Commands:**
|
|
14
|
+
* | Subcommand | Description |
|
|
15
|
+
* |---------------------------------------|------------------------------------------|
|
|
16
|
+
* | `pipelines list [--account] [--all]` | List active (or all) pipelines |
|
|
17
|
+
* | `pipelines get <id>` | Show pipeline details |
|
|
18
|
+
* | `pipelines run <id> [--data <json>]` | Execute a pipeline and show stage output |
|
|
19
|
+
* | `pipelines executions <id>` | List recent executions for a pipeline |
|
|
20
|
+
*
|
|
21
|
+
* **Usage:**
|
|
22
|
+
* ```bash
|
|
23
|
+
* spine pipelines list --account <id>
|
|
24
|
+
* spine pipelines run <uuid> --data '{"key":"value"}' --json
|
|
25
|
+
* spine pipelines executions <uuid> --limit 20
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @seeAlso cli/context.ts (buildCliContext)
|
|
29
|
+
* @seeAlso functions/_shared/pipeline-runner.ts (runPipeline)
|
|
30
|
+
* @seeAlso functions/pipeline-executions.ts (API query endpoint)
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import type { Command } from 'commander'
|
|
34
|
+
import { buildCliContext, printResult, handleError } from '../context.ts'
|
|
35
|
+
import { runPipeline, adminDb } from '../../functions/_shared/index.ts'
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Registers the `pipelines` subcommand group on the root Commander program.
|
|
39
|
+
*
|
|
40
|
+
* @param program - The root `spine` Commander instance
|
|
41
|
+
* @sideEffects Adds `pipelines list/get/run/executions` subcommands to `program`
|
|
42
|
+
* @calledBy cli/index.ts
|
|
43
|
+
*/
|
|
44
|
+
export function registerPipelineCommands(program: Command) {
|
|
45
|
+
const pipelines = program
|
|
46
|
+
.command('pipelines')
|
|
47
|
+
.description('Pipeline management and execution')
|
|
48
|
+
|
|
49
|
+
pipelines
|
|
50
|
+
.command('list')
|
|
51
|
+
.description('List all active pipelines')
|
|
52
|
+
.option('--account <id>', 'Filter by account ID')
|
|
53
|
+
.option('--json', 'Output as JSON')
|
|
54
|
+
.option('--all', 'Include inactive pipelines')
|
|
55
|
+
.action(async (opts) => {
|
|
56
|
+
try {
|
|
57
|
+
const ctx = await buildCliContext({ account: opts.account })
|
|
58
|
+
|
|
59
|
+
let query = adminDb
|
|
60
|
+
.from('pipelines')
|
|
61
|
+
.select('id, name, description, is_active, created_at')
|
|
62
|
+
.order('name')
|
|
63
|
+
|
|
64
|
+
if (!opts.all) {
|
|
65
|
+
query = query.eq('is_active', true)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (ctx.accountId) {
|
|
69
|
+
query = query.eq('account_id', ctx.accountId)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { data, error } = await query
|
|
73
|
+
|
|
74
|
+
if (error) throw new Error(error.message)
|
|
75
|
+
printResult(data || [], { json: opts.json })
|
|
76
|
+
} catch (err: any) {
|
|
77
|
+
handleError(err)
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
pipelines
|
|
82
|
+
.command('get <id>')
|
|
83
|
+
.description('Show pipeline details')
|
|
84
|
+
.option('--json', 'Output as JSON')
|
|
85
|
+
.action(async (id, opts) => {
|
|
86
|
+
try {
|
|
87
|
+
await buildCliContext()
|
|
88
|
+
|
|
89
|
+
const { data, error } = await adminDb
|
|
90
|
+
.from('pipelines')
|
|
91
|
+
.select('*')
|
|
92
|
+
.eq('id', id)
|
|
93
|
+
.single()
|
|
94
|
+
|
|
95
|
+
if (error || !data) throw new Error(error?.message || `Pipeline not found: ${id}`)
|
|
96
|
+
printResult(data, { json: opts.json })
|
|
97
|
+
} catch (err: any) {
|
|
98
|
+
handleError(err)
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
pipelines
|
|
103
|
+
.command('run <id>')
|
|
104
|
+
.description('Execute a pipeline')
|
|
105
|
+
.option('--data <json>', 'Trigger data as JSON string', '{}')
|
|
106
|
+
.option('--account <id>', 'Account scope for the execution')
|
|
107
|
+
.option('--json', 'Output result as JSON')
|
|
108
|
+
.action(async (id, opts) => {
|
|
109
|
+
try {
|
|
110
|
+
const ctx = await buildCliContext({ account: opts.account })
|
|
111
|
+
|
|
112
|
+
let triggerData: any = {}
|
|
113
|
+
try {
|
|
114
|
+
triggerData = JSON.parse(opts.data)
|
|
115
|
+
} catch {
|
|
116
|
+
throw new Error(`--data must be valid JSON. Got: ${opts.data}`)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log(`Running pipeline ${id}...`)
|
|
120
|
+
const result = await runPipeline(id, triggerData, ctx)
|
|
121
|
+
|
|
122
|
+
if (opts.json) {
|
|
123
|
+
console.log(JSON.stringify(result, null, 2))
|
|
124
|
+
} else {
|
|
125
|
+
const icon = result.status === 'completed' ? '✓' : '✗'
|
|
126
|
+
console.log(`\n${icon} Pipeline ${result.status}`)
|
|
127
|
+
console.log(` Execution ID: ${result.executionId}`)
|
|
128
|
+
console.log(` Duration: ${result.durationMs}ms`)
|
|
129
|
+
console.log(` Stages: ${result.stages.length}`)
|
|
130
|
+
result.stages.forEach((s: any, i: number) => {
|
|
131
|
+
const stageIcon = s.status === 'success' ? '✓' : s.status === 'skipped' ? '○' : '✗'
|
|
132
|
+
console.log(` ${stageIcon} [${i}] ${s.stageType} (${s.durationMs}ms)${s.error ? ` — ${s.error}` : ''}`)
|
|
133
|
+
})
|
|
134
|
+
if (result.error) {
|
|
135
|
+
console.log(`\n Error: ${result.error}`)
|
|
136
|
+
}
|
|
137
|
+
console.log()
|
|
138
|
+
}
|
|
139
|
+
} catch (err: any) {
|
|
140
|
+
handleError(err)
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
pipelines
|
|
145
|
+
.command('executions <id>')
|
|
146
|
+
.description('List recent executions for a pipeline')
|
|
147
|
+
.option('--limit <n>', 'Number of executions to show', '10')
|
|
148
|
+
.option('--json', 'Output as JSON')
|
|
149
|
+
.action(async (id, opts) => {
|
|
150
|
+
try {
|
|
151
|
+
await buildCliContext()
|
|
152
|
+
|
|
153
|
+
const { data, error } = await adminDb
|
|
154
|
+
.from('pipeline_executions')
|
|
155
|
+
.select('id, status, started_at, completed_at, duration_ms, error_message')
|
|
156
|
+
.eq('pipeline_id', id)
|
|
157
|
+
.order('started_at', { ascending: false })
|
|
158
|
+
.limit(parseInt(opts.limit))
|
|
159
|
+
|
|
160
|
+
if (error) throw new Error(error.message)
|
|
161
|
+
printResult(data || [], { json: opts.json })
|
|
162
|
+
} catch (err: any) {
|
|
163
|
+
handleError(err)
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* @module cli/commands/status
|
|
4
|
+
* @audience installer
|
|
5
|
+
* @layer cli
|
|
6
|
+
* @stability stable
|
|
7
|
+
*
|
|
8
|
+
* `spine-framework status` — Show the current state of the Spine installation.
|
|
9
|
+
*
|
|
10
|
+
* Displays:
|
|
11
|
+
* - Database connection status
|
|
12
|
+
* - Installed apps and their seed state
|
|
13
|
+
* - Migration history
|
|
14
|
+
* - Webhook handler registrations
|
|
15
|
+
*
|
|
16
|
+
* **Usage:**
|
|
17
|
+
* ```bash
|
|
18
|
+
* spine-framework status
|
|
19
|
+
* spine-framework status --json
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type { Command } from 'commander'
|
|
24
|
+
import { existsSync, readdirSync } from 'fs'
|
|
25
|
+
import { resolve, dirname } from 'path'
|
|
26
|
+
import { fileURLToPath } from 'url'
|
|
27
|
+
import { adminDb } from '../../functions/_shared/index.ts'
|
|
28
|
+
import { discoverManifests } from '../../functions/_shared/app-manifest.ts'
|
|
29
|
+
|
|
30
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
31
|
+
const __dirname = dirname(__filename)
|
|
32
|
+
const PROJECT_ROOT = resolve(__dirname, '../../../')
|
|
33
|
+
|
|
34
|
+
interface StatusOptions {
|
|
35
|
+
json: boolean
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface StatusReport {
|
|
39
|
+
database: { connected: boolean; error?: string }
|
|
40
|
+
apps: Array<{ slug: string; name: string; hasManifest: boolean; hasSeed: boolean; installed: boolean }>
|
|
41
|
+
webhookHandlers: Array<{ name: string; functionName: string; isActive: boolean }>
|
|
42
|
+
typeCounts: { total: number; byApp: Record<string, number> }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function gatherStatus(): Promise<StatusReport> {
|
|
46
|
+
const report: StatusReport = {
|
|
47
|
+
database: { connected: false },
|
|
48
|
+
apps: [],
|
|
49
|
+
webhookHandlers: [],
|
|
50
|
+
typeCounts: { total: 0, byApp: {} },
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 1. Database connection
|
|
54
|
+
try {
|
|
55
|
+
const { data, error } = await adminDb
|
|
56
|
+
.from('apps')
|
|
57
|
+
.select('slug')
|
|
58
|
+
.limit(1)
|
|
59
|
+
|
|
60
|
+
if (error) {
|
|
61
|
+
report.database = { connected: false, error: error.message }
|
|
62
|
+
} else {
|
|
63
|
+
report.database = { connected: true }
|
|
64
|
+
}
|
|
65
|
+
} catch (err: any) {
|
|
66
|
+
report.database = { connected: false, error: err.message }
|
|
67
|
+
return report
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 2. Apps — merge filesystem + database
|
|
71
|
+
const manifests = discoverManifests()
|
|
72
|
+
const { data: dbApps } = await adminDb
|
|
73
|
+
.from('apps')
|
|
74
|
+
.select('slug, name, is_active')
|
|
75
|
+
.eq('is_active', true)
|
|
76
|
+
.order('slug')
|
|
77
|
+
|
|
78
|
+
const { data: installations } = await adminDb
|
|
79
|
+
.from('app_installations')
|
|
80
|
+
.select('app_slug, is_enabled')
|
|
81
|
+
|
|
82
|
+
const installedSlugs = new Set(
|
|
83
|
+
(installations || []).filter(i => i.is_enabled).map(i => i.app_slug)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
const allSlugs = new Set([
|
|
87
|
+
...manifests.map(m => m.slug),
|
|
88
|
+
...(dbApps || []).map(a => a.slug).filter(s => s !== 'spine-core'),
|
|
89
|
+
])
|
|
90
|
+
|
|
91
|
+
for (const slug of allSlugs) {
|
|
92
|
+
const manifest = manifests.find(m => m.slug === slug)
|
|
93
|
+
const dbApp = dbApps?.find(a => a.slug === slug)
|
|
94
|
+
const seedDir = resolve(PROJECT_ROOT, `custom/apps/${slug}/seed`)
|
|
95
|
+
|
|
96
|
+
report.apps.push({
|
|
97
|
+
slug,
|
|
98
|
+
name: dbApp?.name || slug,
|
|
99
|
+
hasManifest: !!manifest,
|
|
100
|
+
hasSeed: existsSync(seedDir) && readdirSync(seedDir).some(f => f.endsWith('.json')),
|
|
101
|
+
installed: installedSlugs.has(slug),
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 3. Webhook handlers
|
|
106
|
+
const { data: handlers } = await adminDb
|
|
107
|
+
.from('webhook_handlers')
|
|
108
|
+
.select('name, function_name, is_active')
|
|
109
|
+
.order('name')
|
|
110
|
+
|
|
111
|
+
report.webhookHandlers = (handlers || []).map(h => ({
|
|
112
|
+
name: h.name,
|
|
113
|
+
functionName: h.function_name,
|
|
114
|
+
isActive: h.is_active,
|
|
115
|
+
}))
|
|
116
|
+
|
|
117
|
+
// 4. Type counts by app
|
|
118
|
+
const { data: types } = await adminDb
|
|
119
|
+
.from('types')
|
|
120
|
+
.select('slug, app_id, apps!inner(slug)')
|
|
121
|
+
.eq('is_active', true)
|
|
122
|
+
|
|
123
|
+
report.typeCounts.total = types?.length || 0
|
|
124
|
+
for (const t of types || []) {
|
|
125
|
+
const appSlug = (t as any).apps?.slug || 'unassigned'
|
|
126
|
+
report.typeCounts.byApp[appSlug] = (report.typeCounts.byApp[appSlug] || 0) + 1
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return report
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function printStatus(report: StatusReport): void {
|
|
133
|
+
console.log('\n🔍 Spine Framework Status\n')
|
|
134
|
+
|
|
135
|
+
// Database
|
|
136
|
+
if (report.database.connected) {
|
|
137
|
+
console.log(' 📡 Database: ✅ Connected')
|
|
138
|
+
} else {
|
|
139
|
+
console.log(` 📡 Database: ❌ ${report.database.error || 'Not connected'}`)
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Apps
|
|
144
|
+
console.log(`\n 📱 Apps (${report.apps.length}):`)
|
|
145
|
+
if (report.apps.length === 0) {
|
|
146
|
+
console.log(' (none)')
|
|
147
|
+
} else {
|
|
148
|
+
for (const app of report.apps) {
|
|
149
|
+
const status = [
|
|
150
|
+
app.hasManifest ? '📋 manifest' : '',
|
|
151
|
+
app.hasSeed ? '🌱 seed' : '',
|
|
152
|
+
app.installed ? '✅ installed' : '⬜ not installed',
|
|
153
|
+
].filter(Boolean).join(' ')
|
|
154
|
+
console.log(` ${app.slug.padEnd(24)} ${status}`)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Webhook handlers
|
|
159
|
+
console.log(`\n 🔗 Webhook Handlers (${report.webhookHandlers.length}):`)
|
|
160
|
+
if (report.webhookHandlers.length === 0) {
|
|
161
|
+
console.log(' (none)')
|
|
162
|
+
} else {
|
|
163
|
+
for (const h of report.webhookHandlers) {
|
|
164
|
+
const status = h.isActive ? '✅' : '❌'
|
|
165
|
+
console.log(` ${status} ${h.name.padEnd(24)} → ${h.functionName}`)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Types
|
|
170
|
+
console.log(`\n 📊 Types (${report.typeCounts.total} total):`)
|
|
171
|
+
for (const [app, count] of Object.entries(report.typeCounts.byApp).sort()) {
|
|
172
|
+
console.log(` ${app.padEnd(24)} ${count} types`)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
console.log('')
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function registerStatusCommands(program: Command) {
|
|
179
|
+
program
|
|
180
|
+
.command('status')
|
|
181
|
+
.description('Show the current state of the Spine installation')
|
|
182
|
+
.option('--json', 'Output as JSON', false)
|
|
183
|
+
.action(async (opts: StatusOptions) => {
|
|
184
|
+
try {
|
|
185
|
+
const report = await gatherStatus()
|
|
186
|
+
if (opts.json) {
|
|
187
|
+
console.log(JSON.stringify(report, null, 2))
|
|
188
|
+
} else {
|
|
189
|
+
printStatus(report)
|
|
190
|
+
}
|
|
191
|
+
} catch (err: any) {
|
|
192
|
+
console.error('Error:', err.message)
|
|
193
|
+
if (process.env.SPINE_CLI_DEBUG) console.error(err.stack)
|
|
194
|
+
process.exit(1)
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* @module cli/commands/system
|
|
4
|
+
* @audience installer
|
|
5
|
+
* @layer cli
|
|
6
|
+
* @stability stable
|
|
7
|
+
*
|
|
8
|
+
* `spine system` command — CLI interface to system discovery endpoints.
|
|
9
|
+
* Queries the running Spine instance for manifest, health, and OpenAPI spec.
|
|
10
|
+
*
|
|
11
|
+
* **Commands:**
|
|
12
|
+
* | Subcommand | Description |
|
|
13
|
+
* |-------------------------|-------------------------------------------------------|
|
|
14
|
+
* | `system manifest` | Fetch and display system manifest |
|
|
15
|
+
* | `system health` | Fetch and display health check results |
|
|
16
|
+
* | `system openapi` | Fetch OpenAPI spec (outputs JSON) |
|
|
17
|
+
* | `system --json` | Output as JSON for all subcommands |
|
|
18
|
+
*
|
|
19
|
+
* **Usage:**
|
|
20
|
+
* ```bash
|
|
21
|
+
* spine system manifest
|
|
22
|
+
* spine system health --json
|
|
23
|
+
* spine system openapi > openapi.json
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @seeAlso functions/system.ts (HTTP endpoints this CLI consumes)
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import type { Command } from 'commander'
|
|
30
|
+
import { buildCliContext, printResult, handleError } from '../context.ts'
|
|
31
|
+
|
|
32
|
+
// ─── API CLIENT ────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
async function fetchSystemEndpoint(ctx: any, action: string): Promise<any> {
|
|
35
|
+
const supabaseUrl = process.env.SUPABASE_URL
|
|
36
|
+
if (!supabaseUrl) {
|
|
37
|
+
throw new Error('SUPABASE_URL not configured')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Construct the Netlify function URL
|
|
41
|
+
// When running locally, this is http://localhost:8888/.netlify/functions/system
|
|
42
|
+
// We'll try localhost:8888 first, then fall back to production URL if configured
|
|
43
|
+
const localUrl = 'http://localhost:8888/.netlify/functions/system'
|
|
44
|
+
const url = `${localUrl}?action=${action}`
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const response = await fetch(url, {
|
|
48
|
+
method: 'GET',
|
|
49
|
+
headers: {
|
|
50
|
+
'Accept': 'application/json',
|
|
51
|
+
'x-app-id': 'cli-system'
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
const text = await response.text()
|
|
57
|
+
throw new Error(`HTTP ${response.status}: ${text}`)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return await response.json()
|
|
61
|
+
} catch (err: any) {
|
|
62
|
+
// If local fails, try direct Supabase function invoke (for production)
|
|
63
|
+
if (err.message.includes('fetch failed') || err.message.includes('ECONNREFUSED')) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
'Cannot connect to local dev server. ' +
|
|
66
|
+
'Ensure `spine dev` or `netlify dev` is running on port 8888.'
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
throw err
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ─── COMMAND REGISTRATION ────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
export function registerSystemCommands(program: Command) {
|
|
76
|
+
const system = program
|
|
77
|
+
.command('system')
|
|
78
|
+
.description('System discovery and health commands')
|
|
79
|
+
|
|
80
|
+
system
|
|
81
|
+
.command('manifest')
|
|
82
|
+
.description('Fetch system manifest (version, functions, migrations)')
|
|
83
|
+
.option('--json', 'Output as JSON')
|
|
84
|
+
.action(async (opts) => {
|
|
85
|
+
try {
|
|
86
|
+
const ctx = await buildCliContext()
|
|
87
|
+
const result = await fetchSystemEndpoint(ctx, 'manifest')
|
|
88
|
+
|
|
89
|
+
if (opts.json) {
|
|
90
|
+
console.log(JSON.stringify(result, null, 2))
|
|
91
|
+
} else {
|
|
92
|
+
console.log('\n📋 Spine System Manifest')
|
|
93
|
+
console.log('─'.repeat(50))
|
|
94
|
+
|
|
95
|
+
if (result.data) {
|
|
96
|
+
const m = result.data
|
|
97
|
+
console.log(`Version: ${m.version}`)
|
|
98
|
+
console.log(`Schema: ${m.schema}`)
|
|
99
|
+
console.log(`Migrations: ${m.migrations?.applied || 0} applied` +
|
|
100
|
+
(m.migrations?.pending ? `, ${m.migrations.pending} pending` : ''))
|
|
101
|
+
console.log(`Functions: ${m.functions?.length || 0} endpoints`)
|
|
102
|
+
console.log(`Integrity: ${m.integrity?.verified ? '✓ verified' : '⚠ not verified'}`)
|
|
103
|
+
|
|
104
|
+
if (m.functions?.length > 0) {
|
|
105
|
+
console.log('\nAvailable Functions:')
|
|
106
|
+
for (const fn of m.functions.slice(0, 10)) {
|
|
107
|
+
console.log(` • ${fn.name} (${fn.methods.join(',')})`)
|
|
108
|
+
}
|
|
109
|
+
if (m.functions.length > 10) {
|
|
110
|
+
console.log(` ... and ${m.functions.length - 10} more`)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
console.log('No manifest data returned')
|
|
115
|
+
}
|
|
116
|
+
console.log()
|
|
117
|
+
}
|
|
118
|
+
} catch (err: any) {
|
|
119
|
+
handleError(err)
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
system
|
|
124
|
+
.command('health')
|
|
125
|
+
.description('Fetch health check status')
|
|
126
|
+
.option('--json', 'Output as JSON')
|
|
127
|
+
.action(async (opts) => {
|
|
128
|
+
try {
|
|
129
|
+
const ctx = await buildCliContext()
|
|
130
|
+
const result = await fetchSystemEndpoint(ctx, 'health')
|
|
131
|
+
|
|
132
|
+
if (opts.json) {
|
|
133
|
+
console.log(JSON.stringify(result, null, 2))
|
|
134
|
+
} else {
|
|
135
|
+
console.log('\n🏥 Spine Health Check')
|
|
136
|
+
console.log('─'.repeat(50))
|
|
137
|
+
|
|
138
|
+
if (result.data) {
|
|
139
|
+
const h = result.data
|
|
140
|
+
const statusIcon = h.status === 'healthy' ? '✓' :
|
|
141
|
+
h.status === 'degraded' ? '⚠' : '✗'
|
|
142
|
+
console.log(`Status: ${statusIcon} ${h.status.toUpperCase()}`)
|
|
143
|
+
console.log()
|
|
144
|
+
|
|
145
|
+
if (h.checks) {
|
|
146
|
+
for (const [name, check] of Object.entries(h.checks)) {
|
|
147
|
+
const c = check as any
|
|
148
|
+
const icon = c.connected || c.current || c.verified ? '✓' :
|
|
149
|
+
c.status === 'passed' ? '✓' : '⚠'
|
|
150
|
+
console.log(`${icon} ${name}:`)
|
|
151
|
+
if (c.latency_ms !== undefined) {
|
|
152
|
+
console.log(` latency: ${c.latency_ms}ms`)
|
|
153
|
+
}
|
|
154
|
+
if (c.applied !== undefined) {
|
|
155
|
+
console.log(` applied: ${c.applied}, pending: ${c.pending}`)
|
|
156
|
+
}
|
|
157
|
+
if (c.last_suite) {
|
|
158
|
+
console.log(` last run: ${c.last_suite} (${c.last_status})`)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
console.log('No health data returned')
|
|
164
|
+
}
|
|
165
|
+
console.log()
|
|
166
|
+
}
|
|
167
|
+
} catch (err: any) {
|
|
168
|
+
handleError(err)
|
|
169
|
+
}
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
system
|
|
173
|
+
.command('openapi')
|
|
174
|
+
.description('Fetch OpenAPI specification')
|
|
175
|
+
.action(async () => {
|
|
176
|
+
try {
|
|
177
|
+
const ctx = await buildCliContext()
|
|
178
|
+
const result = await fetchSystemEndpoint(ctx, 'openapi')
|
|
179
|
+
console.log(JSON.stringify(result.data || result, null, 2))
|
|
180
|
+
} catch (err: any) {
|
|
181
|
+
handleError(err)
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
}
|