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,129 @@
|
|
|
1
|
+
# Spine v2 Frontend
|
|
2
|
+
|
|
3
|
+
This is the frontend shell for Spine v2, built with React, TypeScript, and Tailwind CSS.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
### Prerequisites
|
|
8
|
+
|
|
9
|
+
- Node.js 18+
|
|
10
|
+
- npm or yarn
|
|
11
|
+
- Supabase project
|
|
12
|
+
|
|
13
|
+
### Installation
|
|
14
|
+
|
|
15
|
+
1. Copy the environment file:
|
|
16
|
+
```bash
|
|
17
|
+
cp .env.example .env.local
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
2. Configure your Supabase credentials in `.env.local`:
|
|
21
|
+
```env
|
|
22
|
+
VITE_SUPABASE_URL=your_supabase_url
|
|
23
|
+
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
3. Install dependencies:
|
|
27
|
+
```bash
|
|
28
|
+
npm install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Development
|
|
32
|
+
|
|
33
|
+
Start the development server:
|
|
34
|
+
```bash
|
|
35
|
+
npm run dev
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The application will be available at `http://localhost:3001`.
|
|
39
|
+
|
|
40
|
+
### Build
|
|
41
|
+
|
|
42
|
+
Build for production:
|
|
43
|
+
```bash
|
|
44
|
+
npm run build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Functions
|
|
48
|
+
|
|
49
|
+
Start the Netlify functions server:
|
|
50
|
+
```bash
|
|
51
|
+
npm run functions:dev
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Project Structure
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
src/
|
|
58
|
+
āāā components/
|
|
59
|
+
ā āāā layout/ # Layout components (Header, Sidebar, etc.)
|
|
60
|
+
ā āāā ui/ # Reusable UI components
|
|
61
|
+
āāā contexts/ # React contexts (Auth, etc.)
|
|
62
|
+
āāā lib/ # Utility functions and configurations
|
|
63
|
+
āāā pages/ # Page components
|
|
64
|
+
ā āāā auth/ # Authentication pages
|
|
65
|
+
ā āāā admin/ # Admin pages
|
|
66
|
+
āāā types/ # TypeScript type definitions
|
|
67
|
+
āāā App.tsx # Main app component
|
|
68
|
+
āāā main.tsx # App entry point
|
|
69
|
+
āāā index.css # Global styles
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Features
|
|
73
|
+
|
|
74
|
+
- **Authentication**: Secure login/logout with Supabase
|
|
75
|
+
- **Layout**: Responsive sidebar navigation and header
|
|
76
|
+
- **Admin Interface**: Full admin pages for managing accounts, people, types, and apps
|
|
77
|
+
- **Item Management**: Generic item viewing and management
|
|
78
|
+
- **Dashboard**: Overview with statistics and recent activity
|
|
79
|
+
- **Type Safety**: Full TypeScript support throughout
|
|
80
|
+
|
|
81
|
+
## Key Components
|
|
82
|
+
|
|
83
|
+
### Authentication
|
|
84
|
+
- Uses Supabase Auth for secure authentication
|
|
85
|
+
- JWT token management with automatic refresh
|
|
86
|
+
- Role-based access control
|
|
87
|
+
|
|
88
|
+
### Layout System
|
|
89
|
+
- Responsive sidebar navigation
|
|
90
|
+
- Mobile-friendly with collapsible menu
|
|
91
|
+
- User profile and logout functionality
|
|
92
|
+
|
|
93
|
+
### Admin Pages
|
|
94
|
+
- **Accounts**: Multi-tenant account management
|
|
95
|
+
- **People**: User management across accounts
|
|
96
|
+
- **Types**: Item type schema management
|
|
97
|
+
- **Apps**: Application configuration and management
|
|
98
|
+
|
|
99
|
+
### Styling
|
|
100
|
+
- Tailwind CSS for utility-first styling
|
|
101
|
+
- Custom CSS variables for theming
|
|
102
|
+
- Component-based styling approach
|
|
103
|
+
|
|
104
|
+
## Environment Variables
|
|
105
|
+
|
|
106
|
+
| Variable | Description | Required |
|
|
107
|
+
|----------|-------------|----------|
|
|
108
|
+
| `VITE_SUPABASE_URL` | Supabase project URL | Yes |
|
|
109
|
+
| `VITE_SUPABASE_ANON_KEY` | Supabase anonymous key | Yes |
|
|
110
|
+
| `VITE_NETLIFY_FUNCTIONS_URL` | Netlify functions URL | No |
|
|
111
|
+
|
|
112
|
+
## Scripts
|
|
113
|
+
|
|
114
|
+
- `npm run dev` - Start development server
|
|
115
|
+
- `npm run build` - Build for production
|
|
116
|
+
- `npm run preview` - Preview production build
|
|
117
|
+
- `npm run functions:dev` - Start functions server
|
|
118
|
+
|
|
119
|
+
## Contributing
|
|
120
|
+
|
|
121
|
+
1. Follow the existing code style
|
|
122
|
+
2. Use TypeScript for all new code
|
|
123
|
+
3. Add proper error handling
|
|
124
|
+
4. Include loading states where appropriate
|
|
125
|
+
5. Test responsive design
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
This project is part of the Spine v2 framework.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Thin shebang wrapper ā invokes the TypeScript CLI via tsx.
|
|
3
|
+
// This file is the npm bin entry point for spine-framework.
|
|
4
|
+
const { execFileSync } = require('child_process')
|
|
5
|
+
const { resolve } = require('path')
|
|
6
|
+
|
|
7
|
+
const tsx = resolve(__dirname, '../../node_modules/.bin/tsx')
|
|
8
|
+
const entry = resolve(__dirname, 'index.ts')
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
execFileSync(tsx, [entry, ...process.argv.slice(2)], { stdio: 'inherit' })
|
|
12
|
+
} catch (e) {
|
|
13
|
+
process.exit(e.status ?? 1)
|
|
14
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* @module cli/commands/agents
|
|
4
|
+
* @audience installer
|
|
5
|
+
* @layer cli
|
|
6
|
+
* @stability stable
|
|
7
|
+
*
|
|
8
|
+
* `spine agents` command group. Sends messages to AI agent threads and
|
|
9
|
+
* inspects thread state from the terminal or an agentic IDE. `agents run`
|
|
10
|
+
* calls `runAgent` ā the same function used by API handlers ā so responses
|
|
11
|
+
* are recorded in the `messages` table like any other agent turn.
|
|
12
|
+
*
|
|
13
|
+
* **Commands:**
|
|
14
|
+
* | Subcommand | Description |
|
|
15
|
+
* |--------------------------------------------------|---------------------------------------|
|
|
16
|
+
* | `agents run <threadId> --message <text>` | Send a message and print the response |
|
|
17
|
+
* | `agents threads list [--account <id>]` | List agent threads |
|
|
18
|
+
* | `agents threads get <id> [--limit <n>]` | Show thread + recent messages |
|
|
19
|
+
*
|
|
20
|
+
* **Usage:**
|
|
21
|
+
* ```bash
|
|
22
|
+
* spine agents run <uuid> --message "Summarize the last 10 tickets" --json
|
|
23
|
+
* spine agents threads list --account <id> --limit 10
|
|
24
|
+
* spine agents threads get <uuid>
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @seeAlso cli/context.ts (buildCliContext)
|
|
28
|
+
* @seeAlso functions/_shared/agent-runner.ts (runAgent)
|
|
29
|
+
* @seeAlso functions/ai-agents.ts (agent configuration CRUD)
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import type { Command } from 'commander'
|
|
33
|
+
import { buildCliContext, printResult, handleError } from '../context.ts'
|
|
34
|
+
import { runAgent, adminDb } from '../../functions/_shared/index.ts'
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Registers the `agents` subcommand group on the root Commander program.
|
|
38
|
+
*
|
|
39
|
+
* @param program - The root `spine` Commander instance
|
|
40
|
+
* @sideEffects Adds `agents run`, `agents threads list/get` subcommands to `program`
|
|
41
|
+
* @calledBy cli/index.ts
|
|
42
|
+
*/
|
|
43
|
+
export function registerAgentCommands(program: Command) {
|
|
44
|
+
const agents = program
|
|
45
|
+
.command('agents')
|
|
46
|
+
.description('AI agent interaction')
|
|
47
|
+
|
|
48
|
+
agents
|
|
49
|
+
.command('run <threadId>')
|
|
50
|
+
.description('Send a message to an agent thread and get a response')
|
|
51
|
+
.requiredOption('--message <text>', 'The message to send')
|
|
52
|
+
.option('--account <id>', 'Account scope')
|
|
53
|
+
.option('--json', 'Output as JSON')
|
|
54
|
+
.action(async (threadId, opts) => {
|
|
55
|
+
try {
|
|
56
|
+
const ctx = await buildCliContext({ account: opts.account })
|
|
57
|
+
|
|
58
|
+
console.log(`Sending message to thread ${threadId}...`)
|
|
59
|
+
const response = await runAgent(threadId, opts.message, ctx)
|
|
60
|
+
|
|
61
|
+
if (opts.json) {
|
|
62
|
+
console.log(JSON.stringify(response, null, 2))
|
|
63
|
+
} else {
|
|
64
|
+
console.log('\nāāā Agent Response āāā')
|
|
65
|
+
console.log(response.content || JSON.stringify(response))
|
|
66
|
+
console.log('āāāāāāāāāāāāāāāāāāāāā')
|
|
67
|
+
if (response.data?.confidence !== undefined) {
|
|
68
|
+
console.log(`Confidence: ${(response.data.confidence * 100).toFixed(0)}%`)
|
|
69
|
+
}
|
|
70
|
+
console.log()
|
|
71
|
+
}
|
|
72
|
+
} catch (err: any) {
|
|
73
|
+
handleError(err)
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const threads = agents
|
|
78
|
+
.command('threads')
|
|
79
|
+
.description('Agent thread management')
|
|
80
|
+
|
|
81
|
+
threads
|
|
82
|
+
.command('list')
|
|
83
|
+
.description('List agent threads')
|
|
84
|
+
.option('--account <id>', 'Account scope')
|
|
85
|
+
.option('--limit <n>', 'Max results', '20')
|
|
86
|
+
.option('--json', 'Output as JSON')
|
|
87
|
+
.action(async (opts) => {
|
|
88
|
+
try {
|
|
89
|
+
const ctx = await buildCliContext({ account: opts.account })
|
|
90
|
+
|
|
91
|
+
let query = adminDb
|
|
92
|
+
.from('threads')
|
|
93
|
+
.select('id, title, status, created_at')
|
|
94
|
+
.order('created_at', { ascending: false })
|
|
95
|
+
.limit(parseInt(opts.limit))
|
|
96
|
+
|
|
97
|
+
if (ctx.accountId) {
|
|
98
|
+
query = query.eq('account_id', ctx.accountId)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const { data, error } = await query
|
|
102
|
+
if (error) throw new Error(error.message)
|
|
103
|
+
printResult(data || [], { json: opts.json })
|
|
104
|
+
} catch (err: any) {
|
|
105
|
+
handleError(err)
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
threads
|
|
110
|
+
.command('get <id>')
|
|
111
|
+
.description('Get thread details and recent messages')
|
|
112
|
+
.option('--limit <n>', 'Number of messages to show', '20')
|
|
113
|
+
.option('--json', 'Output as JSON')
|
|
114
|
+
.action(async (id, opts) => {
|
|
115
|
+
try {
|
|
116
|
+
await buildCliContext()
|
|
117
|
+
|
|
118
|
+
const { data: thread, error: threadError } = await adminDb
|
|
119
|
+
.from('threads')
|
|
120
|
+
.select('*')
|
|
121
|
+
.eq('id', id)
|
|
122
|
+
.single()
|
|
123
|
+
|
|
124
|
+
if (threadError || !thread) throw new Error(`Thread not found: ${id}`)
|
|
125
|
+
|
|
126
|
+
const { data: messages, error: msgError } = await adminDb
|
|
127
|
+
.from('messages')
|
|
128
|
+
.select('id, content, data, created_at')
|
|
129
|
+
.eq('thread_id', id)
|
|
130
|
+
.order('created_at', { ascending: true })
|
|
131
|
+
.limit(parseInt(opts.limit))
|
|
132
|
+
|
|
133
|
+
if (msgError) throw new Error(msgError.message)
|
|
134
|
+
|
|
135
|
+
if (opts.json) {
|
|
136
|
+
console.log(JSON.stringify({ thread, messages }, null, 2))
|
|
137
|
+
} else {
|
|
138
|
+
console.log(`\nThread: ${thread.title || thread.id}`)
|
|
139
|
+
console.log(`Status: ${thread.status || 'open'}`)
|
|
140
|
+
console.log('ā'.repeat(50))
|
|
141
|
+
for (const msg of messages || []) {
|
|
142
|
+
const msgType = msg.data?.message_type || 'message'
|
|
143
|
+
const prefix = msgType === 'human' ? 'You' : msgType === 'agent' ? 'Agent' : msgType
|
|
144
|
+
console.log(`\n[${prefix}] ${msg.created_at}`)
|
|
145
|
+
console.log(msg.content)
|
|
146
|
+
}
|
|
147
|
+
console.log()
|
|
148
|
+
}
|
|
149
|
+
} catch (err: any) {
|
|
150
|
+
handleError(err)
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module cli/commands/auth
|
|
3
|
+
* @audience installer
|
|
4
|
+
* @layer cli
|
|
5
|
+
* @stability stable
|
|
6
|
+
*
|
|
7
|
+
* `spine auth` command group. Exposes two subcommands for verifying and
|
|
8
|
+
* inspecting the currently configured CLI credentials without performing
|
|
9
|
+
* any data operations.
|
|
10
|
+
*
|
|
11
|
+
* **Commands:**
|
|
12
|
+
* | Subcommand | Description |
|
|
13
|
+
* |-------------------|-------------------------------------------------------|
|
|
14
|
+
* | `auth whoami` | Print the resolved principal for the current env |
|
|
15
|
+
* | `auth check` | Validate credentials; exit 0 on success, 1 on failure |
|
|
16
|
+
*
|
|
17
|
+
* **Usage:**
|
|
18
|
+
* ```bash
|
|
19
|
+
* spine auth whoami
|
|
20
|
+
* spine auth whoami --json
|
|
21
|
+
* spine auth check
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @seeAlso cli/context.ts (buildCliContext ā principal resolution)
|
|
25
|
+
* @seeAlso functions/auth.ts (API equivalent)
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import type { Command } from 'commander'
|
|
29
|
+
import { buildCliContext, handleError } from '../context.js'
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Registers the `auth` subcommand group on the root Commander program.
|
|
33
|
+
*
|
|
34
|
+
* @param program - The root `spine` Commander instance
|
|
35
|
+
* @sideEffects Adds `auth whoami` and `auth check` subcommands to `program`
|
|
36
|
+
* @calledBy cli/index.ts
|
|
37
|
+
*/
|
|
38
|
+
export function registerAuthCommands(program: Command) {
|
|
39
|
+
const auth = program
|
|
40
|
+
.command('auth')
|
|
41
|
+
.description('Authentication and identity commands')
|
|
42
|
+
|
|
43
|
+
auth
|
|
44
|
+
.command('whoami')
|
|
45
|
+
.description('Show the resolved principal for the current environment config')
|
|
46
|
+
.option('--json', 'Output as JSON')
|
|
47
|
+
.action(async (opts) => {
|
|
48
|
+
try {
|
|
49
|
+
const ctx = await buildCliContext()
|
|
50
|
+
const output = {
|
|
51
|
+
principal_id: ctx.principal.id,
|
|
52
|
+
principal_type: ctx.principal.type,
|
|
53
|
+
account_id: ctx.accountId,
|
|
54
|
+
display_name: ctx.principal.displayName,
|
|
55
|
+
email: ctx.principal.email,
|
|
56
|
+
roles: ctx.principal.roles,
|
|
57
|
+
scopes: ctx.principal.scopes,
|
|
58
|
+
request_id: ctx.requestId
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (opts.json) {
|
|
62
|
+
console.log(JSON.stringify(output, null, 2))
|
|
63
|
+
} else {
|
|
64
|
+
console.log('\nSpine CLI ā Current Identity')
|
|
65
|
+
console.log('ā'.repeat(40))
|
|
66
|
+
console.log(`Principal ID: ${output.principal_id}`)
|
|
67
|
+
console.log(`Type: ${output.principal_type}`)
|
|
68
|
+
console.log(`Account: ${output.account_id || '(none)'}`)
|
|
69
|
+
if (output.display_name) console.log(`Name: ${output.display_name}`)
|
|
70
|
+
if (output.email) console.log(`Email: ${output.email}`)
|
|
71
|
+
if (output.roles?.length) console.log(`Roles: ${output.roles.join(', ')}`)
|
|
72
|
+
if (output.scopes?.length) console.log(`Scopes: ${output.scopes.join(', ')}`)
|
|
73
|
+
console.log(`Request ID: ${output.request_id}`)
|
|
74
|
+
console.log()
|
|
75
|
+
}
|
|
76
|
+
} catch (err: any) {
|
|
77
|
+
handleError(err)
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
auth
|
|
82
|
+
.command('check')
|
|
83
|
+
.description('Validate credentials ā exits 0 if valid, 1 if not')
|
|
84
|
+
.action(async () => {
|
|
85
|
+
try {
|
|
86
|
+
await buildCliContext()
|
|
87
|
+
console.log('ā Credentials valid')
|
|
88
|
+
process.exit(0)
|
|
89
|
+
} catch (err: any) {
|
|
90
|
+
console.error(`ā ${err.message}`)
|
|
91
|
+
process.exit(1)
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* @module cli/commands/create-app
|
|
4
|
+
* @audience installer
|
|
5
|
+
* @layer cli
|
|
6
|
+
* @stability stable
|
|
7
|
+
*
|
|
8
|
+
* `spine-framework create-app <slug>` ā scaffold a new custom app.
|
|
9
|
+
*
|
|
10
|
+
* Creates the full directory structure under `custom/apps/{slug}/`:
|
|
11
|
+
* - manifest.json (app metadata, roles, routes, nav_items)
|
|
12
|
+
* - index.tsx (React entry point)
|
|
13
|
+
* - components/ (empty dir with .gitkeep)
|
|
14
|
+
*
|
|
15
|
+
* **Usage:**
|
|
16
|
+
* ```bash
|
|
17
|
+
* npm run spine-framework create-app my-app
|
|
18
|
+
* npm run spine-framework create-app my-app --name "My App" --role member
|
|
19
|
+
* npm run spine-framework create-app my-app --force
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type { Command } from 'commander'
|
|
24
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs'
|
|
25
|
+
import { resolve, dirname } from 'path'
|
|
26
|
+
import { fileURLToPath } from 'url'
|
|
27
|
+
import { adminDb } from '../../functions/_shared/index.ts'
|
|
28
|
+
|
|
29
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
30
|
+
const __dirname = dirname(__filename)
|
|
31
|
+
const PROJECT_ROOT = resolve(__dirname, '../../../')
|
|
32
|
+
|
|
33
|
+
function toTitleCase(slug: string): string {
|
|
34
|
+
return slug.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(' ')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function generateManifest(slug: string, name: string, role: string): string {
|
|
38
|
+
return JSON.stringify({
|
|
39
|
+
name,
|
|
40
|
+
slug,
|
|
41
|
+
description: `${name} app`,
|
|
42
|
+
version: "1.0.0",
|
|
43
|
+
required_roles: [role],
|
|
44
|
+
routes: [
|
|
45
|
+
`/${slug}`,
|
|
46
|
+
`/${slug}/dashboard`
|
|
47
|
+
],
|
|
48
|
+
nav_items: [
|
|
49
|
+
{
|
|
50
|
+
title: "Dashboard",
|
|
51
|
+
path: `/${slug}/dashboard`,
|
|
52
|
+
icon: "LayoutDashboard",
|
|
53
|
+
order: 1
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
features: [],
|
|
57
|
+
dependencies: [],
|
|
58
|
+
entry_point: "./index.tsx"
|
|
59
|
+
}, null, 2) + '\n'
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function generateIndexTsx(slug: string, name: string): string {
|
|
63
|
+
const componentName = slug.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('')
|
|
64
|
+
return `/**
|
|
65
|
+
* @module custom/apps/${slug}
|
|
66
|
+
* @audience custom
|
|
67
|
+
* @layer frontend-app
|
|
68
|
+
* @stability experimental
|
|
69
|
+
*
|
|
70
|
+
* Entry point for the ${name} app.
|
|
71
|
+
* Generated by spine-framework CLI on ${new Date().toISOString().split('T')[0]}.
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
import * as React from 'react'
|
|
75
|
+
import { Routes, Route, Navigate } from 'react-router-dom'
|
|
76
|
+
|
|
77
|
+
function ${componentName}Dashboard() {
|
|
78
|
+
return (
|
|
79
|
+
<div className="p-6">
|
|
80
|
+
<h1 className="text-2xl font-bold mb-2">${name}</h1>
|
|
81
|
+
<p className="text-slate-500">Welcome to ${name}. Edit custom/apps/${slug}/index.tsx to get started.</p>
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export default function ${componentName}App() {
|
|
87
|
+
return (
|
|
88
|
+
<Routes>
|
|
89
|
+
<Route path="/" element={<Navigate to="dashboard" replace />} />
|
|
90
|
+
<Route path="dashboard" element={<${componentName}Dashboard />} />
|
|
91
|
+
</Routes>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
`
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function createApp(slug: string, options: { name?: string; role: string; force: boolean }): Promise<void> {
|
|
98
|
+
const name = options.name || toTitleCase(slug)
|
|
99
|
+
const appDir = resolve(PROJECT_ROOT, `custom/apps/${slug}`)
|
|
100
|
+
|
|
101
|
+
console.log(`\nš§ Creating app '${slug}'...`)
|
|
102
|
+
|
|
103
|
+
if (existsSync(appDir) && !options.force) {
|
|
104
|
+
console.error(` ā App directory already exists: custom/apps/${slug}`)
|
|
105
|
+
console.error(` Use --force to overwrite`)
|
|
106
|
+
process.exit(1)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 1. Create directories
|
|
110
|
+
mkdirSync(resolve(appDir, 'components'), { recursive: true })
|
|
111
|
+
console.log(` ā Created custom/apps/${slug}/`)
|
|
112
|
+
console.log(` ā Created custom/apps/${slug}/components/`)
|
|
113
|
+
|
|
114
|
+
// 2. manifest.json
|
|
115
|
+
writeFileSync(
|
|
116
|
+
resolve(appDir, 'manifest.json'),
|
|
117
|
+
generateManifest(slug, name, options.role)
|
|
118
|
+
)
|
|
119
|
+
console.log(` ā Created custom/apps/${slug}/manifest.json`)
|
|
120
|
+
|
|
121
|
+
// 3. index.tsx
|
|
122
|
+
writeFileSync(
|
|
123
|
+
resolve(appDir, 'index.tsx'),
|
|
124
|
+
generateIndexTsx(slug, name)
|
|
125
|
+
)
|
|
126
|
+
console.log(` ā Created custom/apps/${slug}/index.tsx`)
|
|
127
|
+
|
|
128
|
+
// 4. components/.gitkeep
|
|
129
|
+
writeFileSync(resolve(appDir, 'components', '.gitkeep'), '')
|
|
130
|
+
|
|
131
|
+
// 5. Insert app record into database
|
|
132
|
+
console.log(` Registering app in database...`)
|
|
133
|
+
const { data: existing } = await adminDb
|
|
134
|
+
.from('apps')
|
|
135
|
+
.select('id')
|
|
136
|
+
.eq('slug', slug)
|
|
137
|
+
.single()
|
|
138
|
+
|
|
139
|
+
if (existing) {
|
|
140
|
+
console.log(` ā ļø App '${slug}' already exists in database (skipping insert)`)
|
|
141
|
+
} else {
|
|
142
|
+
const { error: insertErr } = await adminDb
|
|
143
|
+
.from('apps')
|
|
144
|
+
.insert({
|
|
145
|
+
slug,
|
|
146
|
+
name,
|
|
147
|
+
route_prefix: `/${slug}`,
|
|
148
|
+
renderer: 'custom',
|
|
149
|
+
is_active: true,
|
|
150
|
+
is_system: false,
|
|
151
|
+
min_role: options.role,
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
if (insertErr) {
|
|
155
|
+
console.error(` ā Database insert failed: ${insertErr.message}`)
|
|
156
|
+
console.error(` Run manually: INSERT INTO apps (slug, name, route_prefix, renderer, is_active)`)
|
|
157
|
+
console.error(` VALUES ('${slug}', '${name}', '/${slug}', 'custom', true);`)
|
|
158
|
+
} else {
|
|
159
|
+
console.log(` ā App registered in database`)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
console.log(`\nā
App '${name}' ready at custom/apps/${slug}/`)
|
|
164
|
+
console.log(`\n Next steps:`)
|
|
165
|
+
console.log(` 1. Edit custom/apps/${slug}/manifest.json to configure routes and nav`)
|
|
166
|
+
console.log(` 2. Edit custom/apps/${slug}/index.tsx to build your app`)
|
|
167
|
+
console.log(` 3. npm run assemble && netlify dev`)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function registerCreateAppCommands(program: Command) {
|
|
171
|
+
program
|
|
172
|
+
.command('create-app <slug>')
|
|
173
|
+
.description('Scaffold a new custom app in custom/apps/{slug}/')
|
|
174
|
+
.option('--name <name>', 'Display name for the app (defaults to title-cased slug)')
|
|
175
|
+
.option('--role <role>', 'Required role to access this app', 'member')
|
|
176
|
+
.option('--force', 'Overwrite existing files', false)
|
|
177
|
+
.action(async (slug, opts) => {
|
|
178
|
+
try {
|
|
179
|
+
await createApp(slug, opts)
|
|
180
|
+
} catch (err: any) {
|
|
181
|
+
console.error('Error:', err.message)
|
|
182
|
+
process.exit(1)
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
}
|