agentic-dev 0.2.10 → 0.2.12
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/README.md +50 -29
- package/bin/agentic-dev.mjs +656 -124
- package/lib/scaffold.mjs +109 -6
- package/package.json +8 -22
- package/.agent/prd.json +0 -29
- package/.agent/progress.txt +0 -1
- package/.agent/prompt.md +0 -21
- package/.agent/ralph-loop-state.json +0 -13
- package/.agent/ralph-supervisor-state.json +0 -12
- package/.agent/ralph-supervisor.sh +0 -238
- package/.agent/ralph.sh +0 -305
- package/.agent/runs/README.md +0 -7
- package/.agent/sdd-build-ast-audit.json +0 -13
- package/.claude/CLAUDE.md +0 -44
- package/.claude/agentic-dev.json +0 -3
- package/.claude/agents/ai-dev.md +0 -27
- package/.claude/agents/backend-dev.md +0 -26
- package/.claude/agents/db-dev.md +0 -26
- package/.claude/agents/devops.md +0 -27
- package/.claude/agents/frontend-dev.md +0 -25
- package/.claude/agents/github-ops.md +0 -25
- package/.claude/agents/test-dev.md +0 -26
- package/.claude/agents/uiux-designer.md +0 -25
- package/.claude/settings.json +0 -49
- package/.claude/settings.local.json +0 -8
- package/.claude/skills/sdd/SKILL.md +0 -189
- package/.claude/skills/sdd/agents/openai.yaml +0 -4
- package/.claude/skills/sdd/references/section-map.md +0 -67
- package/.claude/workspace-config.json +0 -3
- package/.codex/agentic-dev.json +0 -3
- package/.codex/agents/README.md +0 -22
- package/.codex/agents/api.toml +0 -11
- package/.codex/agents/architecture.toml +0 -11
- package/.codex/agents/ci.toml +0 -11
- package/.codex/agents/gitops.toml +0 -11
- package/.codex/agents/orchestrator.toml +0 -11
- package/.codex/agents/quality.toml +0 -11
- package/.codex/agents/runtime.toml +0 -11
- package/.codex/agents/security.toml +0 -11
- package/.codex/agents/specs.toml +0 -11
- package/.codex/agents/ui.toml +0 -11
- package/.codex/config.toml +0 -46
- package/.codex/skills/SKILL.md +0 -13
- package/.codex/skills/sdd/SKILL.md +0 -189
- package/.codex/skills/sdd/agents/openai.yaml +0 -4
- package/.codex/skills/sdd/references/section-map.md +0 -67
- package/.dockerignore +0 -8
- package/.env.example +0 -50
- package/.gitignore +0 -16
- package/AGENTS.md +0 -86
- package/SDD_SKILL.md +0 -589
- package/client/admin/.dockerignore +0 -3
- package/client/admin/.env.example +0 -1
- package/client/admin/Dockerfile +0 -16
- package/client/admin/Dockerfile.dev +0 -18
- package/client/admin/README.md +0 -20
- package/client/admin/index.html +0 -12
- package/client/admin/package.json +0 -41
- package/client/admin/postcss.config.js +0 -6
- package/client/admin/scripts/ui-parity-admin-adapter.mjs +0 -65
- package/client/admin/src/api/alerts.ts +0 -33
- package/client/admin/src/api/client.ts +0 -71
- package/client/admin/src/api/orders.ts +0 -33
- package/client/admin/src/api/support.ts +0 -11
- package/client/admin/src/app/App.tsx +0 -23
- package/client/admin/src/auth/AuthProvider.tsx +0 -122
- package/client/admin/src/auth/ProtectedRoute.tsx +0 -22
- package/client/admin/src/auth/auth-client.ts +0 -38
- package/client/admin/src/auth/types.ts +0 -18
- package/client/admin/src/components/AdminNotificationsDrawer.tsx +0 -162
- package/client/admin/src/components/AdminShell.tsx +0 -76
- package/client/admin/src/components/ui/button.tsx +0 -34
- package/client/admin/src/components/ui/input.tsx +0 -21
- package/client/admin/src/lib/cn.ts +0 -6
- package/client/admin/src/lib/specRouteCatalog.json +0 -30
- package/client/admin/src/lib/specScreens.json +0 -22
- package/client/admin/src/main.tsx +0 -17
- package/client/admin/src/pages/AdminDashboardPage.tsx +0 -171
- package/client/admin/src/pages/AdminLoginPage.tsx +0 -75
- package/client/admin/src/pages/AdminQueuePage.tsx +0 -107
- package/client/admin/src/pages/AdminSupportPage.tsx +0 -61
- package/client/admin/src/styles/globals.css +0 -17
- package/client/admin/src/theme-vars.ts +0 -18
- package/client/admin/src/theme.ts +0 -25
- package/client/admin/src/vite-env.d.ts +0 -1
- package/client/admin/tailwind.config.js +0 -8
- package/client/admin/tsconfig.json +0 -25
- package/client/admin/vite.config.ts +0 -12
- package/client/landing/.dockerignore +0 -3
- package/client/landing/.env.example +0 -1
- package/client/landing/Dockerfile +0 -16
- package/client/landing/Dockerfile.dev +0 -18
- package/client/landing/README.md +0 -18
- package/client/landing/index.html +0 -12
- package/client/landing/package.json +0 -41
- package/client/landing/postcss.config.js +0 -6
- package/client/landing/scripts/ui-parity-landing-adapter.mjs +0 -65
- package/client/landing/src/App.tsx +0 -21
- package/client/landing/src/api/catalog.ts +0 -30
- package/client/landing/src/api/client.ts +0 -30
- package/client/landing/src/auth/AuthProvider.tsx +0 -122
- package/client/landing/src/auth/ProtectedRoute.tsx +0 -22
- package/client/landing/src/auth/auth-client.ts +0 -38
- package/client/landing/src/auth/types.ts +0 -18
- package/client/landing/src/components/LandingShell.tsx +0 -34
- package/client/landing/src/lib/specRouteCatalog.json +0 -23
- package/client/landing/src/lib/specScreens.json +0 -17
- package/client/landing/src/main.tsx +0 -17
- package/client/landing/src/pages/LandingHomePage.tsx +0 -215
- package/client/landing/src/pages/LandingLoginPage.tsx +0 -90
- package/client/landing/src/pages/LandingWorkspacePage.tsx +0 -126
- package/client/landing/src/styles/globals.css +0 -17
- package/client/landing/src/theme-vars.ts +0 -16
- package/client/landing/src/theme.ts +0 -21
- package/client/landing/src/vite-env.d.ts +0 -1
- package/client/landing/tailwind.config.js +0 -8
- package/client/landing/tsconfig.json +0 -25
- package/client/landing/vite.config.ts +0 -12
- package/client/mobile/.dockerignore +0 -2
- package/client/mobile/.env.example +0 -1
- package/client/mobile/Dockerfile +0 -16
- package/client/mobile/Dockerfile.dev +0 -18
- package/client/mobile/README.md +0 -19
- package/client/mobile/index.html +0 -12
- package/client/mobile/package.json +0 -42
- package/client/mobile/postcss.config.js +0 -6
- package/client/mobile/scripts/ui-parity-mobile-adapter.mjs +0 -67
- package/client/mobile/src/App.tsx +0 -1
- package/client/mobile/src/api/client.ts +0 -62
- package/client/mobile/src/api/fulfillment.ts +0 -55
- package/client/mobile/src/api/shipping.ts +0 -56
- package/client/mobile/src/app/App.tsx +0 -23
- package/client/mobile/src/auth/AuthProvider.tsx +0 -122
- package/client/mobile/src/auth/ProtectedRoute.tsx +0 -27
- package/client/mobile/src/auth/auth-client.ts +0 -38
- package/client/mobile/src/auth/types.ts +0 -18
- package/client/mobile/src/components/InShell.tsx +0 -74
- package/client/mobile/src/components/ui/button.tsx +0 -35
- package/client/mobile/src/components/ui/card.tsx +0 -15
- package/client/mobile/src/components/ui/input.tsx +0 -21
- package/client/mobile/src/lib/cn.ts +0 -6
- package/client/mobile/src/lib/specRouteCatalog.json +0 -26
- package/client/mobile/src/lib/specScreens.json +0 -22
- package/client/mobile/src/lib/useSpeechRecognitionInput.ts +0 -271
- package/client/mobile/src/main.tsx +0 -17
- package/client/mobile/src/pages/DashboardPage.tsx +0 -172
- package/client/mobile/src/pages/FulfillmentPage.tsx +0 -138
- package/client/mobile/src/pages/LoginPage.tsx +0 -74
- package/client/mobile/src/pages/ShippingPage.tsx +0 -338
- package/client/mobile/src/styles/globals.css +0 -23
- package/client/mobile/src/theme-vars.ts +0 -16
- package/client/mobile/src/theme.ts +0 -21
- package/client/mobile/src/vite-env.d.ts +0 -1
- package/client/mobile/tailwind.config.js +0 -8
- package/client/mobile/tsconfig.json +0 -25
- package/client/mobile/vite.config.ts +0 -12
- package/client/web/.dockerignore +0 -3
- package/client/web/.env.example +0 -1
- package/client/web/Dockerfile +0 -16
- package/client/web/Dockerfile.dev +0 -18
- package/client/web/README.md +0 -47
- package/client/web/index.html +0 -12
- package/client/web/package.json +0 -42
- package/client/web/postcss.config.js +0 -6
- package/client/web/scripts/ui-parity-web-adapter.mjs +0 -66
- package/client/web/src/api/client.ts +0 -30
- package/client/web/src/api/orders.ts +0 -42
- package/client/web/src/app/App.tsx +0 -21
- package/client/web/src/auth/AuthProvider.tsx +0 -122
- package/client/web/src/auth/ProtectedRoute.tsx +0 -22
- package/client/web/src/auth/auth-client.ts +0 -38
- package/client/web/src/auth/types.ts +0 -18
- package/client/web/src/components/AppShell.tsx +0 -59
- package/client/web/src/components/ui/button.tsx +0 -35
- package/client/web/src/components/ui/card.tsx +0 -7
- package/client/web/src/components/ui/input.tsx +0 -21
- package/client/web/src/lib/cn.ts +0 -6
- package/client/web/src/lib/specRouteCatalog.json +0 -23
- package/client/web/src/lib/specScreens.json +0 -17
- package/client/web/src/main.tsx +0 -17
- package/client/web/src/pages/DashboardPage.tsx +0 -158
- package/client/web/src/pages/LoginPage.tsx +0 -72
- package/client/web/src/pages/OrdersPage.tsx +0 -123
- package/client/web/src/styles/globals.css +0 -17
- package/client/web/src/theme-vars.ts +0 -18
- package/client/web/src/theme.ts +0 -25
- package/client/web/src/vite-env.d.ts +0 -1
- package/client/web/tailwind.config.js +0 -8
- package/client/web/tsconfig.json +0 -25
- package/client/web/vite.config.ts +0 -12
- package/compose.yml +0 -206
- package/infra/compose/.env.dev.example +0 -28
- package/infra/compose/.env.prod.example +0 -29
- package/infra/compose/README.md +0 -35
- package/infra/compose/dev.yml +0 -125
- package/infra/compose/prod.yml +0 -126
- package/infra/terraform/README.md +0 -34
- package/infra/terraform/aws/data/.terraform.lock.hcl +0 -25
- package/infra/terraform/aws/data/README.md +0 -18
- package/infra/terraform/aws/data/main.tf +0 -147
- package/infra/terraform/aws/data/outputs.tf +0 -14
- package/infra/terraform/aws/data/variables.tf +0 -57
- package/infra/terraform/aws/data/versions.tf +0 -10
- package/infra/terraform/aws/domain/.terraform.lock.hcl +0 -25
- package/infra/terraform/aws/domain/README.md +0 -20
- package/infra/terraform/aws/domain/env/dev.tfvars.example +0 -6
- package/infra/terraform/aws/domain/env/prod.tfvars.example +0 -7
- package/infra/terraform/aws/domain/main.tf +0 -149
- package/infra/terraform/aws/domain/outputs.tf +0 -29
- package/infra/terraform/aws/domain/variables.tf +0 -58
- package/infra/terraform/aws/domain/versions.tf +0 -10
- package/infra/terraform/openstack/README.md +0 -38
- package/infra/terraform/openstack/dev/.terraform.lock.hcl +0 -24
- package/infra/terraform/openstack/dev/README.md +0 -18
- package/infra/terraform/openstack/dev/main.tf +0 -49
- package/infra/terraform/openstack/dev/providers.tf +0 -15
- package/infra/terraform/openstack/dev/terraform.tfvars.example +0 -54
- package/infra/terraform/openstack/dev/variables.tf +0 -210
- package/infra/terraform/openstack/dev/versions.tf +0 -10
- package/infra/terraform/openstack/modules/environment_host/main.tf +0 -143
- package/infra/terraform/openstack/modules/environment_host/outputs.tf +0 -25
- package/infra/terraform/openstack/modules/environment_host/templates/docker-host-user-data.sh.tftpl +0 -40
- package/infra/terraform/openstack/modules/environment_host/variables.tf +0 -145
- package/infra/terraform/openstack/modules/environment_host/versions.tf +0 -7
- package/infra/terraform/openstack/prod/.terraform.lock.hcl +0 -24
- package/infra/terraform/openstack/prod/README.md +0 -18
- package/infra/terraform/openstack/prod/main.tf +0 -49
- package/infra/terraform/openstack/prod/providers.tf +0 -15
- package/infra/terraform/openstack/prod/terraform.tfvars.example +0 -55
- package/infra/terraform/openstack/prod/variables.tf +0 -210
- package/infra/terraform/openstack/prod/versions.tf +0 -10
- package/infra/terraform/openstack/server/.terraform.lock.hcl +0 -45
- package/infra/terraform/openstack/server/README.md +0 -47
- package/infra/terraform/openstack/server/main.tf +0 -161
- package/infra/terraform/openstack/server/outputs.tf +0 -30
- package/infra/terraform/openstack/server/providers.tf +0 -30
- package/infra/terraform/openstack/server/templates/server-user-data.sh.tftpl +0 -50
- package/infra/terraform/openstack/server/variables.tf +0 -233
- package/infra/terraform/openstack/server/zz_aspace.auto.tfvars.example.json +0 -29
- package/pnpm-workspace.yaml +0 -2
- package/scripts/dev/audit_sdd_build_ast.py +0 -277
- package/sdd/01_planning/01_feature/INDEX.md +0 -16
- package/sdd/01_planning/01_feature/README.md +0 -76
- package/sdd/01_planning/01_feature/alerts_feature_spec.md +0 -55
- package/sdd/01_planning/01_feature/auth_feature_spec.md +0 -57
- package/sdd/01_planning/01_feature/catalog_feature_spec.md +0 -61
- package/sdd/01_planning/01_feature/fulfillment_feature_spec.md +0 -58
- package/sdd/01_planning/01_feature/health_feature_spec.md +0 -52
- package/sdd/01_planning/01_feature/inventory_feature_spec.md +0 -60
- package/sdd/01_planning/01_feature/order_feature_spec.md +0 -63
- package/sdd/01_planning/01_feature/shipping_feature_spec.md +0 -55
- package/sdd/01_planning/01_feature/support_feature_spec.md +0 -53
- package/sdd/01_planning/01_feature/user_feature_spec.md +0 -54
- package/sdd/01_planning/02_screen/INDEX.md +0 -13
- package/sdd/01_planning/02_screen/README.md +0 -41
- package/sdd/01_planning/02_screen/admin_screen_spec.pdf +0 -0
- package/sdd/01_planning/02_screen/assets/README.md +0 -16
- package/sdd/01_planning/02_screen/assets/example/README.md +0 -13
- package/sdd/01_planning/02_screen/landing_screen_spec.pdf +0 -0
- package/sdd/01_planning/02_screen/mobile_screen_spec.pdf +0 -0
- package/sdd/01_planning/02_screen/web_screen_spec.pdf +0 -0
- package/sdd/01_planning/03_architecture/INDEX.md +0 -9
- package/sdd/01_planning/03_architecture/README.md +0 -25
- package/sdd/01_planning/03_architecture/architecture_document_structure.md +0 -77
- package/sdd/01_planning/03_architecture/backend/README.md +0 -10
- package/sdd/01_planning/03_architecture/frontend/README.md +0 -12
- package/sdd/01_planning/03_architecture/infra/README.md +0 -10
- package/sdd/01_planning/03_architecture/tech-research/README.md +0 -4
- package/sdd/01_planning/03_architecture/templates_system_architecture.md +0 -84
- package/sdd/01_planning/04_data/INDEX.md +0 -4
- package/sdd/01_planning/04_data/README.md +0 -10
- package/sdd/01_planning/04_data/templates_data_modeling.md +0 -119
- package/sdd/01_planning/05_api/README.md +0 -12
- package/sdd/01_planning/05_api/templates_api_contract.md +0 -90
- package/sdd/01_planning/06_iac/README.md +0 -11
- package/sdd/01_planning/06_iac/templates_runtime_and_cicd_baseline.md +0 -46
- package/sdd/01_planning/07_integration/README.md +0 -11
- package/sdd/01_planning/07_integration/templates_frontend_api_integration.md +0 -46
- package/sdd/01_planning/08_nonfunctional/README.md +0 -7
- package/sdd/01_planning/09_security/README.md +0 -7
- package/sdd/01_planning/10_test/README.md +0 -12
- package/sdd/01_planning/10_test/templates_test_strategy.md +0 -60
- package/sdd/01_planning/INDEX.md +0 -19
- package/sdd/01_planning/README.md +0 -17
- package/sdd/02_plan/01_feature/README.md +0 -34
- package/sdd/02_plan/01_feature/_feature_todo_template.md +0 -29
- package/sdd/02_plan/02_screen/INDEX.md +0 -19
- package/sdd/02_plan/02_screen/README.md +0 -39
- package/sdd/02_plan/02_screen/_screen_todo_template.md +0 -60
- package/sdd/02_plan/03_architecture/README.md +0 -23
- package/sdd/02_plan/03_architecture/architecture_document_governance.md +0 -40
- package/sdd/02_plan/03_architecture/build_ast_runtime_tree_governance.md +0 -53
- package/sdd/02_plan/03_architecture/repository_governance.md +0 -39
- package/sdd/02_plan/03_architecture/runtime_and_structure_governance.md +0 -38
- package/sdd/02_plan/03_architecture/templates-hexagonal-template-architecture.md +0 -9
- package/sdd/02_plan/03_architecture/toolchain_governance.md +0 -98
- package/sdd/02_plan/04_data/README.md +0 -5
- package/sdd/02_plan/05_api/README.md +0 -5
- package/sdd/02_plan/06_iac/README.md +0 -11
- package/sdd/02_plan/06_iac/dev_runtime_delivery.md +0 -36
- package/sdd/02_plan/06_iac/template_runtime_delivery.md +0 -50
- package/sdd/02_plan/07_integration/README.md +0 -5
- package/sdd/02_plan/07_integration/frontend_live_integration.md +0 -31
- package/sdd/02_plan/08_nonfunctional/README.md +0 -5
- package/sdd/02_plan/08_nonfunctional/repository_hygiene.md +0 -26
- package/sdd/02_plan/09_security/README.md +0 -5
- package/sdd/02_plan/10_test/README.md +0 -11
- package/sdd/02_plan/10_test/regression_verification.md +0 -39
- package/sdd/02_plan/10_test/templates/README.md +0 -8
- package/sdd/02_plan/10_test/templates/ui_parity_web_contract.template.yaml +0 -23
- package/sdd/02_plan/10_test/verification_strategy.md +0 -43
- package/sdd/02_plan/99_generated/from_planning/ui_parity/.gitkeep +0 -1
- package/sdd/02_plan/README.md +0 -40
- package/sdd/03_build/01_feature/README.md +0 -20
- package/sdd/03_build/01_feature/domain/README.md +0 -3
- package/sdd/03_build/01_feature/domain/account_and_access.md +0 -20
- package/sdd/03_build/01_feature/domain/catalog_and_inventory.md +0 -20
- package/sdd/03_build/01_feature/domain/ordering_and_fulfillment.md +0 -21
- package/sdd/03_build/01_feature/domain/support_and_observability.md +0 -21
- package/sdd/03_build/01_feature/domain_surfaces.md +0 -28
- package/sdd/03_build/01_feature/service/README.md +0 -3
- package/sdd/03_build/01_feature/service/admin_surface.md +0 -15
- package/sdd/03_build/01_feature/service/landing_surface.md +0 -13
- package/sdd/03_build/01_feature/service/mobile_surface.md +0 -14
- package/sdd/03_build/01_feature/service/web_surface.md +0 -14
- package/sdd/03_build/02_screen/README.md +0 -25
- package/sdd/03_build/02_screen/_screen_build_template.md +0 -26
- package/sdd/03_build/02_screen/admin/README.md +0 -5
- package/sdd/03_build/02_screen/landing/README.md +0 -5
- package/sdd/03_build/02_screen/mobile/README.md +0 -5
- package/sdd/03_build/02_screen/web/README.md +0 -5
- package/sdd/03_build/03_architecture/README.md +0 -10
- package/sdd/03_build/03_architecture/architecture_document_governance.md +0 -30
- package/sdd/03_build/03_architecture/build_ast_runtime_tree_governance.md +0 -24
- package/sdd/03_build/03_architecture/repository_governance.md +0 -18
- package/sdd/03_build/03_architecture/toolchain_governance.md +0 -36
- package/sdd/03_build/06_iac/README.md +0 -3
- package/sdd/03_build/06_iac/dev_runtime_delivery.md +0 -10
- package/sdd/03_build/06_iac/template_runtime_delivery.md +0 -49
- package/sdd/03_build/07_integration/README.md +0 -3
- package/sdd/03_build/07_integration/frontend_live_integration.md +0 -11
- package/sdd/03_build/08_nonfunctional/README.md +0 -3
- package/sdd/03_build/08_nonfunctional/repository_hygiene.md +0 -10
- package/sdd/03_build/10_test/README.md +0 -9
- package/sdd/03_build/10_test/regression_verification.md +0 -16
- package/sdd/03_build/10_test/verification_harness.md +0 -11
- package/sdd/03_build/README.md +0 -35
- package/sdd/03_verify/01_feature/README.md +0 -5
- package/sdd/03_verify/01_feature/domain_verification.md +0 -14
- package/sdd/03_verify/01_feature/service_verification.md +0 -22
- package/sdd/03_verify/02_screen/README.md +0 -6
- package/sdd/03_verify/02_screen/_screen_verify_template.md +0 -20
- package/sdd/03_verify/02_screen/admin/README.md +0 -4
- package/sdd/03_verify/02_screen/landing/README.md +0 -4
- package/sdd/03_verify/02_screen/mobile/README.md +0 -4
- package/sdd/03_verify/02_screen/web/README.md +0 -4
- package/sdd/03_verify/03_architecture/README.md +0 -10
- package/sdd/03_verify/03_architecture/architecture_document_governance.md +0 -15
- package/sdd/03_verify/03_architecture/build_ast_runtime_tree_governance.md +0 -28
- package/sdd/03_verify/03_architecture/repository_governance.md +0 -16
- package/sdd/03_verify/03_architecture/toolchain_governance.md +0 -58
- package/sdd/03_verify/06_iac/README.md +0 -3
- package/sdd/03_verify/06_iac/dev_runtime_delivery.md +0 -10
- package/sdd/03_verify/06_iac/template_runtime_delivery.md +0 -42
- package/sdd/03_verify/07_integration/README.md +0 -3
- package/sdd/03_verify/07_integration/frontend_live_integration.md +0 -16
- package/sdd/03_verify/08_nonfunctional/README.md +0 -3
- package/sdd/03_verify/08_nonfunctional/repository_hygiene.md +0 -14
- package/sdd/03_verify/10_test/README.md +0 -9
- package/sdd/03_verify/10_test/regression_verification.md +0 -16
- package/sdd/03_verify/10_test/ui_parity/README.md +0 -4
- package/sdd/03_verify/10_test/ui_parity/loop_runs/.gitkeep +0 -0
- package/sdd/03_verify/10_test/ui_parity/reference/.gitkeep +0 -0
- package/sdd/03_verify/10_test/ui_parity/staged_runs/.gitkeep +0 -0
- package/sdd/03_verify/10_test/verification_harness.md +0 -17
- package/sdd/03_verify/README.md +0 -22
- package/sdd/05_operate/01_runbooks/.gitkeep +0 -1
- package/sdd/05_operate/01_runbooks/README.md +0 -4
- package/sdd/05_operate/02_delivery_status/README.md +0 -4
- package/sdd/05_operate/02_delivery_status/service_status.md +0 -16
- package/sdd/05_operate/README.md +0 -12
- package/sdd/99_toolchain/01_automation/.gitkeep +0 -1
- package/sdd/99_toolchain/01_automation/README.md +0 -76
- package/sdd/99_toolchain/01_automation/agentic-dev/analyze_proof_results.py +0 -132
- package/sdd/99_toolchain/01_automation/agentic-dev/analyze_route_gap.py +0 -85
- package/sdd/99_toolchain/01_automation/agentic-dev/assets/repo-contract.template.json +0 -75
- package/sdd/99_toolchain/01_automation/agentic-dev/bootstrap_frontend_parity.sh +0 -84
- package/sdd/99_toolchain/01_automation/agentic-dev/init_frontend_parity.sh +0 -33
- package/sdd/99_toolchain/01_automation/agentic-dev/init_repo_contract.sh +0 -51
- package/sdd/99_toolchain/01_automation/agentic-dev/repo-contract.json +0 -76
- package/sdd/99_toolchain/01_automation/agentic-dev/resolve_frontend_target.py +0 -52
- package/sdd/99_toolchain/01_automation/agentic-dev/resolve_repo_contract.py +0 -56
- package/sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh +0 -100
- package/sdd/99_toolchain/01_automation/agentic-dev/run_repo_phase.sh +0 -140
- package/sdd/99_toolchain/01_automation/agentic-dev/validate_json_schema.py +0 -39
- package/sdd/99_toolchain/01_automation/agentic-parity-harness-design.md +0 -291
- package/sdd/99_toolchain/01_automation/assets/admin_screen_capture/dashboard.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/admin_screen_capture/login.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/admin_screen_capture/queue.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/admin_screen_capture/support.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/landing_screen_capture/home.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/landing_screen_capture/login.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/landing_screen_capture/workspace.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/mobile_screen_capture/dashboard.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/mobile_screen_capture/fulfillment.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/mobile_screen_capture/login.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/web_screen_capture/dashboard.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/web_screen_capture/login.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/web_screen_capture/orders.png +0 -0
- package/sdd/99_toolchain/01_automation/build_asset_recipes.py +0 -10
- package/sdd/99_toolchain/01_automation/build_screen_spec_pdf.py +0 -427
- package/sdd/99_toolchain/01_automation/capture_screen_assets.mjs +0 -148
- package/sdd/99_toolchain/01_automation/harness-layout.md +0 -34
- package/sdd/99_toolchain/01_automation/parity-execution-tooling-design.md +0 -319
- package/sdd/99_toolchain/01_automation/playwright_exactness_manifest.py +0 -21
- package/sdd/99_toolchain/01_automation/run_playwright_exactness.py +0 -87
- package/sdd/99_toolchain/01_automation/screen_spec_manifest.py +0 -321
- package/sdd/99_toolchain/01_automation/spec_asset_builder.py +0 -274
- package/sdd/99_toolchain/01_automation/ui-contract-projection.md +0 -79
- package/sdd/99_toolchain/01_automation/ui-parity/README.md +0 -60
- package/sdd/99_toolchain/01_automation/ui-parity/cli/extract-reference-pages.mjs +0 -2
- package/sdd/99_toolchain/01_automation/ui-parity/cli/materialize-reference-assets.mjs +0 -58
- package/sdd/99_toolchain/01_automation/ui-parity/cli/normalize-reference-assets.mjs +0 -2
- package/sdd/99_toolchain/01_automation/ui-parity/cli/route-gap-report.mjs +0 -187
- package/sdd/99_toolchain/01_automation/ui-parity/cli/run-proof.mjs +0 -50
- package/sdd/99_toolchain/01_automation/ui-parity/cli/scaffold-contract.mjs +0 -62
- package/sdd/99_toolchain/01_automation/ui-parity/cli/upload-parity1.mjs +0 -2
- package/sdd/99_toolchain/01_automation/ui-parity/contracts/collector-metadata.schema.json +0 -33
- package/sdd/99_toolchain/01_automation/ui-parity/contracts/proof-result.schema.json +0 -76
- package/sdd/99_toolchain/01_automation/ui-parity/contracts/route-gap-report.schema.json +0 -95
- package/sdd/99_toolchain/01_automation/ui-parity/core/capture-runner.mjs +0 -55
- package/sdd/99_toolchain/01_automation/ui-parity/core/load-adapter.mjs +0 -25
- package/sdd/99_toolchain/01_automation/ui-parity/core/load-contract.mjs +0 -81
- package/sdd/99_toolchain/01_automation/ui-parity/core/paths.mjs +0 -23
- package/sdd/99_toolchain/01_automation/ui-parity/core/proof-runner.mjs +0 -255
- package/sdd/99_toolchain/01_automation/ui-parity/interfaces/ui-parity-artifact-layout.md +0 -23
- package/sdd/99_toolchain/01_automation/ui-parity/interfaces/ui-parity-proof-interface.md +0 -60
- package/sdd/99_toolchain/01_automation/ui-parity/interfaces/ui-parity-route-gap-interface.md +0 -82
- package/sdd/99_toolchain/01_automation/ui-parity/runtime/playwright-runtime.mjs +0 -16
- package/sdd/99_toolchain/01_automation/ui-parity/runtime/static-runtime.mjs +0 -6
- package/sdd/99_toolchain/02_policies/.gitkeep +0 -1
- package/sdd/99_toolchain/02_policies/build-ast-governance-policy.md +0 -22
- package/sdd/99_toolchain/02_policies/compose-runtime-baseline-policy.md +0 -24
- package/sdd/99_toolchain/02_policies/convention-storage-policy.md +0 -26
- package/sdd/99_toolchain/02_policies/main-push-before-dev-deploy-policy.md +0 -27
- package/sdd/99_toolchain/02_policies/regression-verification-policy.md +0 -22
- package/sdd/99_toolchain/03_templates/.gitkeep +0 -1
- package/sdd/99_toolchain/03_templates/asset_recipe_manifest.example.py +0 -38
- package/sdd/99_toolchain/03_templates/generated_assets/README.md +0 -11
- package/sdd/99_toolchain/03_templates/generated_assets/example-brand-lockup.svg +0 -3
- package/sdd/99_toolchain/03_templates/generated_assets/example-brand-mark.svg +0 -3
- package/sdd/99_toolchain/03_templates/generated_assets/example-brand-wordmark.svg +0 -3
- package/sdd/99_toolchain/03_templates/playwright_exactness_manifest.example.py +0 -21
- package/sdd/99_toolchain/README.md +0 -23
- package/sdd/README.md +0 -21
- package/server/.dockerignore +0 -4
- package/server/.env.example +0 -19
- package/server/Dockerfile +0 -22
- package/server/Dockerfile.dev +0 -19
- package/server/README.md +0 -33
- package/server/__init__.py +0 -0
- package/server/api/__init__.py +0 -1
- package/server/api/http/__init__.py +0 -4
- package/server/api/http/app.py +0 -53
- package/server/api/http/router.py +0 -24
- package/server/config.py +0 -52
- package/server/contexts/__init__.py +0 -12
- package/server/contexts/alerts/__init__.py +0 -1
- package/server/contexts/alerts/application/__init__.py +0 -13
- package/server/contexts/alerts/application/services.py +0 -41
- package/server/contexts/alerts/contracts/__init__.py +0 -3
- package/server/contexts/alerts/contracts/http/__init__.py +0 -3
- package/server/contexts/alerts/contracts/http/router.py +0 -37
- package/server/contexts/alerts/domain/__init__.py +0 -15
- package/server/contexts/alerts/domain/models.py +0 -29
- package/server/contexts/alerts/infrastructure/__init__.py +0 -11
- package/server/contexts/alerts/infrastructure/repository.py +0 -41
- package/server/contexts/auth/__init__.py +0 -1
- package/server/contexts/auth/application/__init__.py +0 -3
- package/server/contexts/auth/application/ports.py +0 -10
- package/server/contexts/auth/application/services.py +0 -64
- package/server/contexts/auth/contracts/__init__.py +0 -4
- package/server/contexts/auth/contracts/http/__init__.py +0 -4
- package/server/contexts/auth/contracts/http/dependencies.py +0 -37
- package/server/contexts/auth/contracts/http/router.py +0 -19
- package/server/contexts/auth/domain/__init__.py +0 -3
- package/server/contexts/auth/domain/models.py +0 -24
- package/server/contexts/auth/infrastructure/__init__.py +0 -4
- package/server/contexts/auth/infrastructure/adapters/memory.py +0 -19
- package/server/contexts/auth/infrastructure/adapters/mongodb.py +0 -24
- package/server/contexts/auth/infrastructure/adapters/sqlalchemy.py +0 -74
- package/server/contexts/auth/infrastructure/repository.py +0 -28
- package/server/contexts/catalog/__init__.py +0 -1
- package/server/contexts/catalog/application/__init__.py +0 -28
- package/server/contexts/catalog/application/ports.py +0 -15
- package/server/contexts/catalog/application/services.py +0 -154
- package/server/contexts/catalog/contracts/__init__.py +0 -3
- package/server/contexts/catalog/contracts/http/__init__.py +0 -3
- package/server/contexts/catalog/contracts/http/router.py +0 -60
- package/server/contexts/catalog/domain/__init__.py +0 -45
- package/server/contexts/catalog/domain/models.py +0 -113
- package/server/contexts/catalog/infrastructure/__init__.py +0 -4
- package/server/contexts/catalog/infrastructure/adapters/memory.py +0 -62
- package/server/contexts/catalog/infrastructure/repository.py +0 -8
- package/server/contexts/fulfillment/__init__.py +0 -1
- package/server/contexts/fulfillment/application/__init__.py +0 -13
- package/server/contexts/fulfillment/application/ports.py +0 -20
- package/server/contexts/fulfillment/application/services.py +0 -85
- package/server/contexts/fulfillment/contracts/__init__.py +0 -3
- package/server/contexts/fulfillment/contracts/http/__init__.py +0 -3
- package/server/contexts/fulfillment/contracts/http/router.py +0 -40
- package/server/contexts/fulfillment/domain/__init__.py +0 -25
- package/server/contexts/fulfillment/domain/models.py +0 -73
- package/server/contexts/fulfillment/infrastructure/__init__.py +0 -13
- package/server/contexts/fulfillment/infrastructure/adapters/memory.py +0 -43
- package/server/contexts/fulfillment/infrastructure/repository.py +0 -97
- package/server/contexts/health/__init__.py +0 -1
- package/server/contexts/health/application/__init__.py +0 -3
- package/server/contexts/health/application/services.py +0 -2
- package/server/contexts/health/contracts/__init__.py +0 -3
- package/server/contexts/health/contracts/http/__init__.py +0 -3
- package/server/contexts/health/contracts/http/router.py +0 -10
- package/server/contexts/inventory/__init__.py +0 -1
- package/server/contexts/inventory/application/__init__.py +0 -28
- package/server/contexts/inventory/application/ports.py +0 -11
- package/server/contexts/inventory/application/services.py +0 -214
- package/server/contexts/inventory/contracts/__init__.py +0 -3
- package/server/contexts/inventory/contracts/http/__init__.py +0 -3
- package/server/contexts/inventory/contracts/http/router.py +0 -82
- package/server/contexts/inventory/domain/__init__.py +0 -33
- package/server/contexts/inventory/domain/models.py +0 -93
- package/server/contexts/inventory/infrastructure/__init__.py +0 -4
- package/server/contexts/inventory/infrastructure/adapters/memory.py +0 -24
- package/server/contexts/inventory/infrastructure/repository.py +0 -8
- package/server/contexts/orders/__init__.py +0 -1
- package/server/contexts/orders/application/__init__.py +0 -19
- package/server/contexts/orders/application/services.py +0 -127
- package/server/contexts/orders/contracts/__init__.py +0 -3
- package/server/contexts/orders/contracts/http/__init__.py +0 -3
- package/server/contexts/orders/contracts/http/router.py +0 -82
- package/server/contexts/orders/domain/__init__.py +0 -29
- package/server/contexts/orders/domain/models.py +0 -95
- package/server/contexts/orders/infrastructure/__init__.py +0 -7
- package/server/contexts/orders/infrastructure/repository.py +0 -104
- package/server/contexts/shipping/__init__.py +0 -1
- package/server/contexts/shipping/application/__init__.py +0 -13
- package/server/contexts/shipping/application/services.py +0 -92
- package/server/contexts/shipping/contracts/__init__.py +0 -3
- package/server/contexts/shipping/contracts/http/__init__.py +0 -3
- package/server/contexts/shipping/contracts/http/router.py +0 -40
- package/server/contexts/shipping/domain/__init__.py +0 -19
- package/server/contexts/shipping/domain/models.py +0 -48
- package/server/contexts/shipping/infrastructure/__init__.py +0 -9
- package/server/contexts/shipping/infrastructure/repository.py +0 -50
- package/server/contexts/support/__init__.py +0 -1
- package/server/contexts/support/application/__init__.py +0 -13
- package/server/contexts/support/application/services.py +0 -29
- package/server/contexts/support/contracts/__init__.py +0 -3
- package/server/contexts/support/contracts/http/__init__.py +0 -3
- package/server/contexts/support/contracts/http/router.py +0 -40
- package/server/contexts/support/domain/__init__.py +0 -13
- package/server/contexts/support/domain/models.py +0 -27
- package/server/contexts/support/infrastructure/__init__.py +0 -11
- package/server/contexts/support/infrastructure/repository.py +0 -70
- package/server/contexts/user/__init__.py +0 -1
- package/server/contexts/user/application/__init__.py +0 -3
- package/server/contexts/user/application/ports.py +0 -11
- package/server/contexts/user/application/services.py +0 -44
- package/server/contexts/user/contracts/__init__.py +0 -3
- package/server/contexts/user/contracts/http/__init__.py +0 -3
- package/server/contexts/user/contracts/http/router.py +0 -26
- package/server/contexts/user/domain/__init__.py +0 -3
- package/server/contexts/user/domain/models.py +0 -22
- package/server/contexts/user/infrastructure/__init__.py +0 -3
- package/server/contexts/user/infrastructure/adapters/memory.py +0 -27
- package/server/contexts/user/infrastructure/adapters/mongodb.py +0 -41
- package/server/contexts/user/infrastructure/adapters/sqlalchemy.py +0 -94
- package/server/contexts/user/infrastructure/factory.py +0 -28
- package/server/data/README.md +0 -24
- package/server/data/bootstrap/alerts.json +0 -38
- package/server/data/bootstrap/auth_accounts.json +0 -18
- package/server/data/bootstrap/catalog_products.json +0 -179
- package/server/data/bootstrap/fulfillment_events.json +0 -5
- package/server/data/bootstrap/fulfillment_notes.json +0 -5
- package/server/data/bootstrap/fulfillment_tasks.json +0 -50
- package/server/data/bootstrap/inventory_levels.json +0 -80
- package/server/data/bootstrap/orders.json +0 -62
- package/server/data/bootstrap/shipping_shipments.json +0 -50
- package/server/data/bootstrap/support_faqs.json +0 -26
- package/server/data/bootstrap/users.json +0 -20
- package/server/data/bootstrap_loader.py +0 -15
- package/server/docker-entrypoint.sh +0 -56
- package/server/main.py +0 -3
- package/server/pyproject.toml +0 -36
- package/server/shared/__init__.py +0 -1
- package/server/shared/application/__init__.py +0 -3
- package/server/shared/application/health.py +0 -2
- package/server/shared/infrastructure/__init__.py +0 -10
- package/server/shared/infrastructure/runtime.py +0 -6
- package/server/shared/infrastructure/security.py +0 -33
- package/server/tests/e2e/test_domain_feature_flows.py +0 -483
- package/server/tests/test_health.py +0 -49
- package/server/uv.lock +0 -1169
package/bin/agentic-dev.mjs
CHANGED
|
@@ -5,15 +5,86 @@ import process from "node:process";
|
|
|
5
5
|
import * as readline from "node:readline";
|
|
6
6
|
import { createInterface } from "node:readline/promises";
|
|
7
7
|
import {
|
|
8
|
+
DEFAULT_TEMPLATE_OWNER,
|
|
8
9
|
ensureTargetDir,
|
|
9
10
|
fetchTemplateRepos,
|
|
10
11
|
installTemplateRepo,
|
|
11
12
|
parseArgs,
|
|
12
13
|
resolveTemplateRepo,
|
|
13
|
-
selectTemplateRepo,
|
|
14
14
|
usage,
|
|
15
15
|
} from "../lib/scaffold.mjs";
|
|
16
16
|
|
|
17
|
+
const DEFAULT_TARGET_DIR = ".";
|
|
18
|
+
const DEFAULT_APP_MODE = "fullstack";
|
|
19
|
+
const DEFAULT_AI_PROVIDERS = ["codex", "claude"];
|
|
20
|
+
|
|
21
|
+
const GITHUB_AUTH_CHOICES = [
|
|
22
|
+
{
|
|
23
|
+
label: "public",
|
|
24
|
+
value: "public",
|
|
25
|
+
description: "Use public template-* repos from say828 without a token",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
label: "env",
|
|
29
|
+
value: "env",
|
|
30
|
+
description: "Use GH_TOKEN, GITHUB_TOKEN, or AGENTIC_GITHUB_TOKEN from the shell",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
label: "pat",
|
|
34
|
+
value: "pat",
|
|
35
|
+
description: "Paste a GitHub PAT for this run only",
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const APP_MODE_CHOICES = [
|
|
40
|
+
{
|
|
41
|
+
label: "fullstack",
|
|
42
|
+
value: "fullstack",
|
|
43
|
+
description: "Install dependencies and run frontend parity bootstrap",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
label: "frontend",
|
|
47
|
+
value: "frontend",
|
|
48
|
+
description: "Keep frontend-focused setup with browser install and parity bootstrap",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
label: "backend",
|
|
52
|
+
value: "backend",
|
|
53
|
+
description: "Install workspace dependencies but skip browser install and parity bootstrap",
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const AI_PROVIDER_CHOICES = [
|
|
58
|
+
{
|
|
59
|
+
label: "codex",
|
|
60
|
+
value: "codex",
|
|
61
|
+
description: "Keep Codex workspace config in the generated repo",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
label: "claude",
|
|
65
|
+
value: "claude",
|
|
66
|
+
description: "Keep Claude workspace config in the generated repo",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
label: "ollama",
|
|
70
|
+
value: "ollama",
|
|
71
|
+
description: "Record Ollama as a provider in setup metadata",
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const CONFIRM_CHOICES = [
|
|
76
|
+
{
|
|
77
|
+
label: "Proceed",
|
|
78
|
+
value: "proceed",
|
|
79
|
+
description: "Run clone, install, and bootstrap now",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
label: "Cancel",
|
|
83
|
+
value: "cancel",
|
|
84
|
+
description: "Stop without writing files",
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
|
|
17
88
|
function clearMenu(lines) {
|
|
18
89
|
if (lines <= 0) {
|
|
19
90
|
return;
|
|
@@ -22,29 +93,318 @@ function clearMenu(lines) {
|
|
|
22
93
|
readline.clearScreenDown(process.stdout);
|
|
23
94
|
}
|
|
24
95
|
|
|
25
|
-
function
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
96
|
+
function inferProjectName(targetDir) {
|
|
97
|
+
const normalized = (targetDir || DEFAULT_TARGET_DIR).trim() || DEFAULT_TARGET_DIR;
|
|
98
|
+
const resolved = path.resolve(process.cwd(), normalized);
|
|
99
|
+
return path.basename(resolved);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function directoryHasUserFiles(targetDir) {
|
|
103
|
+
const normalized = (targetDir || DEFAULT_TARGET_DIR).trim() || DEFAULT_TARGET_DIR;
|
|
104
|
+
const resolved = path.resolve(process.cwd(), normalized);
|
|
105
|
+
if (!fs.existsSync(resolved)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const entries = fs
|
|
110
|
+
.readdirSync(resolved, { withFileTypes: true })
|
|
111
|
+
.filter((entry) => entry.name !== ".git");
|
|
112
|
+
return entries.length > 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function normalizeProviders(providers) {
|
|
116
|
+
const normalized = Array.isArray(providers)
|
|
117
|
+
? providers.map((provider) => provider.trim()).filter(Boolean)
|
|
118
|
+
: [];
|
|
119
|
+
if (normalized.length > 0) {
|
|
120
|
+
return [...new Set(normalized)];
|
|
121
|
+
}
|
|
122
|
+
return [...DEFAULT_AI_PROVIDERS];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function uniqueProviders(providers) {
|
|
126
|
+
return Array.isArray(providers)
|
|
127
|
+
? [...new Set(providers.map((provider) => provider.trim()).filter(Boolean))]
|
|
128
|
+
: [];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function hydrateOptions(options) {
|
|
132
|
+
const state = {
|
|
133
|
+
targetDir: (options.targetDir || DEFAULT_TARGET_DIR).trim() || DEFAULT_TARGET_DIR,
|
|
134
|
+
projectName: (options.projectName || "").trim(),
|
|
135
|
+
template: (options.template || "").trim(),
|
|
136
|
+
githubAuthMode: (options.githubAuthMode || "public").trim() || "public",
|
|
137
|
+
githubPat: options.githubPat || "",
|
|
138
|
+
appMode: (options.appMode || DEFAULT_APP_MODE).trim() || DEFAULT_APP_MODE,
|
|
139
|
+
aiProviders: normalizeProviders(options.aiProviders),
|
|
140
|
+
force: Boolean(options.force),
|
|
141
|
+
skipBootstrap: Boolean(options.skipBootstrap),
|
|
142
|
+
owner: options.owner || DEFAULT_TEMPLATE_OWNER,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
if (!state.projectName) {
|
|
146
|
+
state.projectName = inferProjectName(state.targetDir);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return state;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function applyRuntimeGitHubAuth(state) {
|
|
153
|
+
if (state.githubAuthMode === "pat" && state.githubPat) {
|
|
154
|
+
process.env.AGENTIC_GITHUB_TOKEN = state.githubPat;
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (state.githubAuthMode === "public") {
|
|
159
|
+
delete process.env.AGENTIC_GITHUB_TOKEN;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function sanitizeStateForInstall(state) {
|
|
164
|
+
return {
|
|
165
|
+
...state,
|
|
166
|
+
targetDir: (state.targetDir || DEFAULT_TARGET_DIR).trim() || DEFAULT_TARGET_DIR,
|
|
167
|
+
projectName: (state.projectName || inferProjectName(state.targetDir)).trim(),
|
|
168
|
+
aiProviders: normalizeProviders(state.aiProviders),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function buildTemplateChoices(repos) {
|
|
173
|
+
return repos.map((repo) => ({
|
|
174
|
+
label: repo.name,
|
|
175
|
+
value: repo.name,
|
|
176
|
+
description: repo.description || "Public template repo",
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function buildSteps(state, repos) {
|
|
181
|
+
const steps = [
|
|
182
|
+
{
|
|
183
|
+
key: "targetDir",
|
|
184
|
+
type: "text",
|
|
185
|
+
label: "Project directory",
|
|
186
|
+
description: "Type the destination directory, then press Enter. Use ←/→ to move between screens.",
|
|
187
|
+
placeholder: DEFAULT_TARGET_DIR,
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
key: "projectName",
|
|
191
|
+
type: "text",
|
|
192
|
+
label: "Project name",
|
|
193
|
+
description: "Written into scaffold metadata and Claude workspace nickname.",
|
|
194
|
+
placeholder: inferProjectName(state.targetDir),
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
key: "githubAuthMode",
|
|
198
|
+
type: "single",
|
|
199
|
+
label: "GitHub auth mode",
|
|
200
|
+
description: "Choose how this run should access template repos.",
|
|
201
|
+
choices: GITHUB_AUTH_CHOICES,
|
|
202
|
+
},
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
if (state.githubAuthMode === "pat") {
|
|
206
|
+
steps.push({
|
|
207
|
+
key: "githubPat",
|
|
208
|
+
type: "password",
|
|
209
|
+
label: "GitHub PAT",
|
|
210
|
+
description: "Used only for this run. The token is not written into the generated repo.",
|
|
211
|
+
placeholder: "",
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
steps.push(
|
|
216
|
+
{
|
|
217
|
+
key: "template",
|
|
218
|
+
type: "single",
|
|
219
|
+
label: `Template repo from ${state.owner}`,
|
|
220
|
+
description: "Pick the public template-* repo to scaffold.",
|
|
221
|
+
choices: buildTemplateChoices(repos),
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
key: "appMode",
|
|
225
|
+
type: "single",
|
|
226
|
+
label: "App mode",
|
|
227
|
+
description: "Choose how much of the bootstrap flow should run after clone.",
|
|
228
|
+
choices: APP_MODE_CHOICES,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
key: "aiProviders",
|
|
232
|
+
type: "multi",
|
|
233
|
+
label: "AI providers",
|
|
234
|
+
description: "Use Space to toggle. At least one provider must stay selected.",
|
|
235
|
+
choices: AI_PROVIDER_CHOICES,
|
|
236
|
+
},
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
if (!state.force && directoryHasUserFiles(state.targetDir)) {
|
|
240
|
+
steps.push({
|
|
241
|
+
key: "force",
|
|
242
|
+
type: "single",
|
|
243
|
+
label: "Target directory is not empty",
|
|
244
|
+
description: "Choose whether scaffolding may continue in the current directory.",
|
|
245
|
+
choices: [
|
|
246
|
+
{
|
|
247
|
+
label: "Continue",
|
|
248
|
+
value: true,
|
|
249
|
+
description: "Allow scaffolding into the existing directory",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
label: "Cancel",
|
|
253
|
+
value: false,
|
|
254
|
+
description: "Stop without changing files",
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
steps.push({
|
|
261
|
+
key: "confirm",
|
|
262
|
+
type: "confirm",
|
|
263
|
+
label: "Review and run",
|
|
264
|
+
description: "Confirm every choice before the CLI starts cloning or installing.",
|
|
265
|
+
choices: CONFIRM_CHOICES,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
return steps;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function stepValue(state, step) {
|
|
272
|
+
if (step.key === "targetDir") {
|
|
273
|
+
return state.targetDir || step.placeholder || DEFAULT_TARGET_DIR;
|
|
274
|
+
}
|
|
275
|
+
if (step.key === "projectName") {
|
|
276
|
+
return state.projectName || step.placeholder || inferProjectName(state.targetDir);
|
|
277
|
+
}
|
|
278
|
+
if (step.key === "githubPat") {
|
|
279
|
+
return state.githubPat || "";
|
|
280
|
+
}
|
|
281
|
+
return state[step.key];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function renderHeader(step, index, total) {
|
|
285
|
+
return [
|
|
286
|
+
`Agentic Dev Setup ${index + 1}/${total}`,
|
|
287
|
+
step.label,
|
|
288
|
+
step.description,
|
|
289
|
+
"",
|
|
290
|
+
];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function renderTextStep(step, state, buffers, index, total) {
|
|
294
|
+
const lines = renderHeader(step, index, total);
|
|
295
|
+
if (!buffers.has(step.key)) {
|
|
296
|
+
buffers.set(step.key, stepValue(state, step) || "");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const rawValue = buffers.get(step.key);
|
|
300
|
+
const displayValue =
|
|
301
|
+
step.type === "password" ? "*".repeat(rawValue.length) : rawValue || step.placeholder || "";
|
|
302
|
+
|
|
303
|
+
lines.push(`Value: ${displayValue}`);
|
|
304
|
+
lines.push("");
|
|
305
|
+
lines.push("Controls: type text, Backspace to edit, Enter or → to continue, ← to go back.");
|
|
306
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
307
|
+
return lines.length;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function renderSingleChoiceStep(step, state, cursors, index, total) {
|
|
311
|
+
const lines = renderHeader(step, index, total);
|
|
312
|
+
if (!cursors.has(step.key)) {
|
|
313
|
+
const currentValue = stepValue(state, step);
|
|
314
|
+
const currentIndex = Math.max(
|
|
315
|
+
0,
|
|
316
|
+
step.choices.findIndex((choice) => choice.value === currentValue),
|
|
317
|
+
);
|
|
318
|
+
cursors.set(step.key, currentIndex >= 0 ? currentIndex : 0);
|
|
31
319
|
}
|
|
320
|
+
|
|
321
|
+
const cursor = cursors.get(step.key);
|
|
322
|
+
step.choices.forEach((choice, choiceIndex) => {
|
|
323
|
+
const pointer = choiceIndex === cursor ? ">" : " ";
|
|
324
|
+
const suffix = choice.description ? ` - ${choice.description}` : "";
|
|
325
|
+
lines.push(`${pointer} ${choice.label}${suffix}`);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
lines.push("");
|
|
329
|
+
lines.push("Controls: ↑/↓ to choose, Enter or → to continue, ← to go back.");
|
|
32
330
|
process.stdout.write(`${lines.join("\n")}\n`);
|
|
33
331
|
return lines.length;
|
|
34
332
|
}
|
|
35
333
|
|
|
36
|
-
function
|
|
37
|
-
const lines =
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const summary = choices[index].description ? ` - ${choices[index].description}` : "";
|
|
41
|
-
lines.push(`${pointer} ${choices[index].label}${summary}`);
|
|
334
|
+
function renderMultiChoiceStep(step, state, cursors, index, total) {
|
|
335
|
+
const lines = renderHeader(step, index, total);
|
|
336
|
+
if (!cursors.has(step.key)) {
|
|
337
|
+
cursors.set(step.key, 0);
|
|
42
338
|
}
|
|
339
|
+
|
|
340
|
+
const selected = new Set(uniqueProviders(stepValue(state, step)));
|
|
341
|
+
const cursor = cursors.get(step.key);
|
|
342
|
+
step.choices.forEach((choice, choiceIndex) => {
|
|
343
|
+
const pointer = choiceIndex === cursor ? ">" : " ";
|
|
344
|
+
const checked = selected.has(choice.value) ? "[x]" : "[ ]";
|
|
345
|
+
const suffix = choice.description ? ` - ${choice.description}` : "";
|
|
346
|
+
lines.push(`${pointer} ${checked} ${choice.label}${suffix}`);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
lines.push("");
|
|
350
|
+
lines.push("Controls: ↑/↓ to move, Space to toggle, Enter or → to continue, ← to go back.");
|
|
43
351
|
process.stdout.write(`${lines.join("\n")}\n`);
|
|
44
352
|
return lines.length;
|
|
45
353
|
}
|
|
46
354
|
|
|
47
|
-
|
|
355
|
+
function executionPreview(state, selectedRepo) {
|
|
356
|
+
const lines = [
|
|
357
|
+
`Project directory: ${path.resolve(process.cwd(), state.targetDir)}`,
|
|
358
|
+
`Project name: ${state.projectName}`,
|
|
359
|
+
`GitHub auth mode: ${state.githubAuthMode}`,
|
|
360
|
+
`Template repo: ${selectedRepo?.name || state.template}`,
|
|
361
|
+
`App mode: ${state.appMode}`,
|
|
362
|
+
`AI providers: ${state.aiProviders.join(", ")}`,
|
|
363
|
+
`Allow non-empty directory: ${state.force ? "yes" : "no"}`,
|
|
364
|
+
];
|
|
365
|
+
|
|
366
|
+
if (state.githubAuthMode === "pat") {
|
|
367
|
+
lines.push(`GitHub PAT supplied: ${state.githubPat ? "yes" : "no"}`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
lines.push("Run plan:");
|
|
371
|
+
lines.push(` 1. Clone ${selectedRepo?.name || state.template}`);
|
|
372
|
+
lines.push(" 2. Copy .env.example to .env if needed");
|
|
373
|
+
lines.push(" 3. Run pnpm install");
|
|
374
|
+
if (state.appMode === "backend") {
|
|
375
|
+
lines.push(" 4. Skip browser install and parity bootstrap");
|
|
376
|
+
} else {
|
|
377
|
+
lines.push(" 4. Install Playwright Chromium for the default frontend target");
|
|
378
|
+
lines.push(" 5. Run frontend parity bootstrap");
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return lines;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function renderConfirmStep(step, state, repos, cursors, index, total) {
|
|
385
|
+
const lines = renderHeader(step, index, total);
|
|
386
|
+
const selectedRepo = resolveTemplateRepo(state.template, repos);
|
|
387
|
+
executionPreview(state, selectedRepo).forEach((line) => lines.push(line));
|
|
388
|
+
lines.push("");
|
|
389
|
+
|
|
390
|
+
if (!cursors.has(step.key)) {
|
|
391
|
+
cursors.set(step.key, 0);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const cursor = cursors.get(step.key);
|
|
395
|
+
step.choices.forEach((choice, choiceIndex) => {
|
|
396
|
+
const pointer = choiceIndex === cursor ? ">" : " ";
|
|
397
|
+
const suffix = choice.description ? ` - ${choice.description}` : "";
|
|
398
|
+
lines.push(`${pointer} ${choice.label}${suffix}`);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
lines.push("");
|
|
402
|
+
lines.push("Controls: ↑/↓ to choose, Enter or → to confirm, ← to go back.");
|
|
403
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
404
|
+
return lines.length;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async function runInteractiveSession(render, onInput) {
|
|
48
408
|
const stdin = process.stdin;
|
|
49
409
|
const stdout = process.stdout;
|
|
50
410
|
const previousRawMode = typeof stdin.setRawMode === "function" ? stdin.isRaw : undefined;
|
|
@@ -90,74 +450,202 @@ async function runArrowMenu(render, onInput) {
|
|
|
90
450
|
});
|
|
91
451
|
}
|
|
92
452
|
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return runArrowMenu(
|
|
98
|
-
() => renderRepoSelect(`Public template repos from ${owner}:`, repos, cursor),
|
|
99
|
-
(chunk, rerender) => {
|
|
100
|
-
if (chunk === "\u0003") {
|
|
101
|
-
throw new Error("Prompt cancelled");
|
|
102
|
-
}
|
|
103
|
-
if (chunk === "\r" || chunk === "\n") {
|
|
104
|
-
return repos[cursor].name;
|
|
105
|
-
}
|
|
106
|
-
if (chunk === "\u001b[A") {
|
|
107
|
-
cursor = (cursor - 1 + repos.length) % repos.length;
|
|
108
|
-
rerender();
|
|
109
|
-
} else if (chunk === "\u001b[B") {
|
|
110
|
-
cursor = (cursor + 1) % repos.length;
|
|
111
|
-
rerender();
|
|
112
|
-
}
|
|
113
|
-
return undefined;
|
|
114
|
-
},
|
|
115
|
-
);
|
|
453
|
+
function validateStepValue(step, state, value) {
|
|
454
|
+
if (step.key === "targetDir") {
|
|
455
|
+
const trimmed = value.trim() || DEFAULT_TARGET_DIR;
|
|
456
|
+
return trimmed;
|
|
116
457
|
}
|
|
117
458
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
459
|
+
if (step.key === "projectName") {
|
|
460
|
+
const trimmed = value.trim();
|
|
461
|
+
if (!trimmed) {
|
|
462
|
+
throw new Error("Project name cannot be empty.");
|
|
463
|
+
}
|
|
464
|
+
return trimmed;
|
|
465
|
+
}
|
|
125
466
|
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.log(error.message);
|
|
467
|
+
if (step.key === "githubPat") {
|
|
468
|
+
const trimmed = value.trim();
|
|
469
|
+
if (!trimmed) {
|
|
470
|
+
throw new Error("GitHub PAT cannot be empty.");
|
|
132
471
|
}
|
|
472
|
+
return trimmed;
|
|
133
473
|
}
|
|
474
|
+
|
|
475
|
+
if (step.key === "aiProviders") {
|
|
476
|
+
const providers = normalizeProviders(value);
|
|
477
|
+
if (providers.length === 0) {
|
|
478
|
+
throw new Error("Select at least one AI provider.");
|
|
479
|
+
}
|
|
480
|
+
return providers;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (step.key === "force" && value === false) {
|
|
484
|
+
throw new Error("Prompt cancelled");
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return value;
|
|
134
488
|
}
|
|
135
489
|
|
|
136
|
-
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
490
|
+
function setStateValue(state, step, value) {
|
|
491
|
+
if (step.key === "targetDir") {
|
|
492
|
+
const previousInferred = inferProjectName(state.targetDir);
|
|
493
|
+
state.targetDir = value;
|
|
494
|
+
if (!state.projectName || state.projectName === previousInferred) {
|
|
495
|
+
state.projectName = inferProjectName(value);
|
|
496
|
+
}
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
state[step.key] = value;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
async function runWizard(initialState, repos) {
|
|
504
|
+
const state = sanitizeStateForInstall(initialState);
|
|
505
|
+
const buffers = new Map();
|
|
506
|
+
const cursors = new Map();
|
|
507
|
+
let stepIndex = 0;
|
|
508
|
+
|
|
509
|
+
return runInteractiveSession(
|
|
510
|
+
() => {
|
|
511
|
+
const steps = buildSteps(state, repos);
|
|
512
|
+
if (stepIndex >= steps.length) {
|
|
513
|
+
stepIndex = steps.length - 1;
|
|
514
|
+
}
|
|
515
|
+
const step = steps[stepIndex];
|
|
516
|
+
process.stdout.write("\n");
|
|
517
|
+
if (step.type === "text" || step.type === "password") {
|
|
518
|
+
return renderTextStep(step, state, buffers, stepIndex, steps.length);
|
|
519
|
+
}
|
|
520
|
+
if (step.type === "multi") {
|
|
521
|
+
return renderMultiChoiceStep(step, state, cursors, stepIndex, steps.length);
|
|
522
|
+
}
|
|
523
|
+
if (step.type === "confirm") {
|
|
524
|
+
return renderConfirmStep(step, state, repos, cursors, stepIndex, steps.length);
|
|
525
|
+
}
|
|
526
|
+
return renderSingleChoiceStep(step, state, cursors, stepIndex, steps.length);
|
|
527
|
+
},
|
|
528
|
+
(chunk, rerender) => {
|
|
529
|
+
const steps = buildSteps(state, repos);
|
|
530
|
+
const step = steps[stepIndex];
|
|
531
|
+
|
|
532
|
+
if (chunk === "\u0003") {
|
|
533
|
+
throw new Error("Prompt cancelled");
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (step.type === "text" || step.type === "password") {
|
|
537
|
+
if (!buffers.has(step.key)) {
|
|
538
|
+
buffers.set(step.key, stepValue(state, step) || "");
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (chunk === "\u007f") {
|
|
542
|
+
buffers.set(step.key, buffers.get(step.key).slice(0, -1));
|
|
543
|
+
rerender();
|
|
544
|
+
return undefined;
|
|
145
545
|
}
|
|
146
|
-
|
|
147
|
-
|
|
546
|
+
|
|
547
|
+
if (chunk === "\u001b[D") {
|
|
548
|
+
if (stepIndex > 0) {
|
|
549
|
+
stepIndex -= 1;
|
|
550
|
+
rerender();
|
|
551
|
+
}
|
|
552
|
+
return undefined;
|
|
148
553
|
}
|
|
149
|
-
|
|
150
|
-
|
|
554
|
+
|
|
555
|
+
if (chunk === "\r" || chunk === "\n" || chunk === "\u001b[C") {
|
|
556
|
+
const nextValue = validateStepValue(step, state, buffers.get(step.key));
|
|
557
|
+
setStateValue(state, step, nextValue);
|
|
558
|
+
const nextSteps = buildSteps(state, repos);
|
|
559
|
+
if (stepIndex < nextSteps.length - 1) {
|
|
560
|
+
stepIndex += 1;
|
|
561
|
+
rerender();
|
|
562
|
+
return undefined;
|
|
563
|
+
}
|
|
564
|
+
return sanitizeStateForInstall(state);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (/^[\x20-\x7e]$/.test(chunk)) {
|
|
568
|
+
buffers.set(step.key, `${buffers.get(step.key)}${chunk}`);
|
|
151
569
|
rerender();
|
|
152
|
-
}
|
|
153
|
-
|
|
570
|
+
}
|
|
571
|
+
return undefined;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (!cursors.has(step.key)) {
|
|
575
|
+
const currentValue = stepValue(state, step);
|
|
576
|
+
const initialIndex = Math.max(
|
|
577
|
+
0,
|
|
578
|
+
step.choices.findIndex((choice) => choice.value === currentValue),
|
|
579
|
+
);
|
|
580
|
+
cursors.set(step.key, initialIndex >= 0 ? initialIndex : 0);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (chunk === "\u001b[D") {
|
|
584
|
+
if (stepIndex > 0) {
|
|
585
|
+
stepIndex -= 1;
|
|
154
586
|
rerender();
|
|
155
587
|
}
|
|
156
588
|
return undefined;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if (chunk === "\u001b[A") {
|
|
592
|
+
const nextCursor = (cursors.get(step.key) - 1 + step.choices.length) % step.choices.length;
|
|
593
|
+
cursors.set(step.key, nextCursor);
|
|
594
|
+
rerender();
|
|
595
|
+
return undefined;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (chunk === "\u001b[B") {
|
|
599
|
+
const nextCursor = (cursors.get(step.key) + 1) % step.choices.length;
|
|
600
|
+
cursors.set(step.key, nextCursor);
|
|
601
|
+
rerender();
|
|
602
|
+
return undefined;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (step.type === "multi" && chunk === " ") {
|
|
606
|
+
const selected = new Set(uniqueProviders(state.aiProviders));
|
|
607
|
+
const currentChoice = step.choices[cursors.get(step.key)];
|
|
608
|
+
if (selected.has(currentChoice.value)) {
|
|
609
|
+
selected.delete(currentChoice.value);
|
|
610
|
+
} else {
|
|
611
|
+
selected.add(currentChoice.value);
|
|
612
|
+
}
|
|
613
|
+
state.aiProviders = [...selected];
|
|
614
|
+
rerender();
|
|
615
|
+
return undefined;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (chunk === "\r" || chunk === "\n" || chunk === "\u001b[C") {
|
|
619
|
+
if (step.type === "multi") {
|
|
620
|
+
const providers = validateStepValue(step, state, state.aiProviders);
|
|
621
|
+
setStateValue(state, step, providers);
|
|
622
|
+
} else {
|
|
623
|
+
const selectedChoice = step.choices[cursors.get(step.key)];
|
|
624
|
+
if (step.type === "confirm") {
|
|
625
|
+
if (selectedChoice.value === "cancel") {
|
|
626
|
+
throw new Error("Prompt cancelled");
|
|
627
|
+
}
|
|
628
|
+
return sanitizeStateForInstall(state);
|
|
629
|
+
}
|
|
630
|
+
const nextValue = validateStepValue(step, state, selectedChoice.value);
|
|
631
|
+
setStateValue(state, step, nextValue);
|
|
632
|
+
}
|
|
160
633
|
|
|
634
|
+
const nextSteps = buildSteps(state, repos);
|
|
635
|
+
if (stepIndex < nextSteps.length - 1) {
|
|
636
|
+
stepIndex += 1;
|
|
637
|
+
rerender();
|
|
638
|
+
return undefined;
|
|
639
|
+
}
|
|
640
|
+
return sanitizeStateForInstall(state);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return undefined;
|
|
644
|
+
},
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
async function promptForChoice(rl, label, choices) {
|
|
161
649
|
console.log("");
|
|
162
650
|
console.log(label);
|
|
163
651
|
choices.forEach((choice, index) => {
|
|
@@ -174,6 +662,7 @@ async function promptForChoice(rl, label, choices) {
|
|
|
174
662
|
return choices[index].value;
|
|
175
663
|
}
|
|
176
664
|
}
|
|
665
|
+
|
|
177
666
|
const exact = choices.find((choice) => choice.label === answer || choice.value === answer);
|
|
178
667
|
if (exact) {
|
|
179
668
|
return exact.value;
|
|
@@ -182,81 +671,94 @@ async function promptForChoice(rl, label, choices) {
|
|
|
182
671
|
}
|
|
183
672
|
}
|
|
184
673
|
|
|
185
|
-
function
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
674
|
+
async function promptForMultiChoice(rl, label, choices, defaults) {
|
|
675
|
+
console.log("");
|
|
676
|
+
console.log(label);
|
|
677
|
+
console.log("Enter one or more labels separated by commas.");
|
|
678
|
+
choices.forEach((choice, index) => {
|
|
679
|
+
const summary = choice.description ? ` - ${choice.description}` : "";
|
|
680
|
+
console.log(` ${index + 1}. ${choice.label}${summary}`);
|
|
681
|
+
});
|
|
682
|
+
console.log("");
|
|
190
683
|
|
|
191
|
-
|
|
192
|
-
.
|
|
193
|
-
|
|
194
|
-
|
|
684
|
+
while (true) {
|
|
685
|
+
const answer = (await rl.question(`Providers [${defaults.join(",")}]: `)).trim();
|
|
686
|
+
const selected = normalizeProviders(
|
|
687
|
+
answer
|
|
688
|
+
? answer.split(",").map((entry) => entry.trim())
|
|
689
|
+
: defaults,
|
|
690
|
+
);
|
|
691
|
+
const invalid = selected.filter(
|
|
692
|
+
(provider) => !choices.some((choice) => choice.value === provider),
|
|
693
|
+
);
|
|
694
|
+
if (invalid.length === 0 && selected.length > 0) {
|
|
695
|
+
return selected;
|
|
696
|
+
}
|
|
697
|
+
console.log(`Invalid providers: ${invalid.join(", ")}`);
|
|
698
|
+
}
|
|
195
699
|
}
|
|
196
700
|
|
|
197
|
-
function
|
|
701
|
+
function printFallbackPlan(state, repos) {
|
|
702
|
+
const selectedRepo = resolveTemplateRepo(state.template, repos);
|
|
198
703
|
console.log("");
|
|
199
|
-
console.log(
|
|
200
|
-
console.log(` Project directory: ${path.resolve(process.cwd(), options.targetDir)}`);
|
|
201
|
-
console.log(` Template repo: ${options.template}`);
|
|
202
|
-
console.log(` GitHub owner: ${options.owner}`);
|
|
203
|
-
console.log(` Allow non-empty directory: ${options.force ? "yes" : "no"}`);
|
|
204
|
-
console.log(` Run install/bootstrap: ${options.skipBootstrap ? "no" : "yes"}`);
|
|
704
|
+
executionPreview(state, selectedRepo).forEach((line) => console.log(line));
|
|
205
705
|
}
|
|
206
706
|
|
|
207
|
-
async function
|
|
208
|
-
|
|
209
|
-
throw new Error("`--yes` requires both target directory and template repo.");
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (options.targetDir && options.template) {
|
|
213
|
-
return options;
|
|
214
|
-
}
|
|
215
|
-
|
|
707
|
+
async function promptLinearly(initialState, repos) {
|
|
708
|
+
const state = sanitizeStateForInstall(initialState);
|
|
216
709
|
const rl = createInterface({
|
|
217
710
|
input: process.stdin,
|
|
218
711
|
output: process.stdout,
|
|
219
712
|
});
|
|
220
713
|
|
|
221
714
|
try {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
715
|
+
const targetDirAnswer = await rl.question(`Project directory [${state.targetDir}]: `);
|
|
716
|
+
state.targetDir = targetDirAnswer.trim() || state.targetDir;
|
|
717
|
+
|
|
718
|
+
const defaultProjectName = inferProjectName(state.targetDir);
|
|
719
|
+
const projectNameAnswer = await rl.question(`Project name [${state.projectName || defaultProjectName}]: `);
|
|
720
|
+
state.projectName = projectNameAnswer.trim() || state.projectName || defaultProjectName;
|
|
721
|
+
|
|
722
|
+
state.githubAuthMode = await promptForChoice(rl, "GitHub auth mode", GITHUB_AUTH_CHOICES);
|
|
723
|
+
if (state.githubAuthMode === "pat") {
|
|
724
|
+
state.githubPat = (await rl.question("GitHub PAT: ")).trim();
|
|
725
|
+
if (!state.githubPat) {
|
|
726
|
+
throw new Error("GitHub PAT cannot be empty.");
|
|
227
727
|
}
|
|
228
728
|
}
|
|
229
729
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (!
|
|
235
|
-
|
|
236
|
-
{
|
|
237
|
-
|
|
730
|
+
state.template = await promptForChoice(rl, `Template repo from ${state.owner}`, buildTemplateChoices(repos));
|
|
731
|
+
state.appMode = await promptForChoice(rl, "App mode", APP_MODE_CHOICES);
|
|
732
|
+
state.aiProviders = await promptForMultiChoice(rl, "AI providers", AI_PROVIDER_CHOICES, state.aiProviders);
|
|
733
|
+
|
|
734
|
+
if (!state.force && directoryHasUserFiles(state.targetDir)) {
|
|
735
|
+
state.force = await promptForChoice(rl, "Target directory is not empty", [
|
|
736
|
+
{
|
|
737
|
+
label: "Continue",
|
|
738
|
+
value: true,
|
|
739
|
+
description: "Allow scaffolding into the existing directory",
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
label: "Cancel",
|
|
743
|
+
value: false,
|
|
744
|
+
description: "Stop without changing files",
|
|
745
|
+
},
|
|
238
746
|
]);
|
|
239
|
-
if (!
|
|
747
|
+
if (!state.force) {
|
|
240
748
|
throw new Error("Prompt cancelled");
|
|
241
749
|
}
|
|
242
|
-
options.force = true;
|
|
243
750
|
}
|
|
244
751
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
{ label: "Cancel", value: false, description: "Stop before running commands" },
|
|
250
|
-
]);
|
|
251
|
-
if (!proceed) {
|
|
252
|
-
throw new Error("Prompt cancelled");
|
|
253
|
-
}
|
|
752
|
+
printFallbackPlan(state, repos);
|
|
753
|
+
const confirmation = await promptForChoice(rl, "Run scaffold now?", CONFIRM_CHOICES);
|
|
754
|
+
if (confirmation !== "proceed") {
|
|
755
|
+
throw new Error("Prompt cancelled");
|
|
254
756
|
}
|
|
255
757
|
} finally {
|
|
256
758
|
rl.close();
|
|
257
759
|
}
|
|
258
760
|
|
|
259
|
-
return
|
|
761
|
+
return sanitizeStateForInstall(state);
|
|
260
762
|
}
|
|
261
763
|
|
|
262
764
|
function printSuccess(result) {
|
|
@@ -277,6 +779,25 @@ function printSuccess(result) {
|
|
|
277
779
|
}
|
|
278
780
|
}
|
|
279
781
|
|
|
782
|
+
function validateNonInteractiveState(state) {
|
|
783
|
+
if (!state.targetDir) {
|
|
784
|
+
throw new Error("`--yes` requires a target directory.");
|
|
785
|
+
}
|
|
786
|
+
if (!state.template) {
|
|
787
|
+
throw new Error("`--yes` requires a template repo.");
|
|
788
|
+
}
|
|
789
|
+
if (!state.projectName) {
|
|
790
|
+
state.projectName = inferProjectName(state.targetDir);
|
|
791
|
+
}
|
|
792
|
+
if (state.githubAuthMode === "pat" && !state.githubPat) {
|
|
793
|
+
throw new Error("`--github-auth pat` requires `--github-pat`.");
|
|
794
|
+
}
|
|
795
|
+
if (!Array.isArray(state.aiProviders) || state.aiProviders.length === 0) {
|
|
796
|
+
state.aiProviders = [...DEFAULT_AI_PROVIDERS];
|
|
797
|
+
}
|
|
798
|
+
return state;
|
|
799
|
+
}
|
|
800
|
+
|
|
280
801
|
async function main() {
|
|
281
802
|
let options;
|
|
282
803
|
try {
|
|
@@ -308,18 +829,29 @@ async function main() {
|
|
|
308
829
|
}
|
|
309
830
|
|
|
310
831
|
try {
|
|
311
|
-
const
|
|
832
|
+
const state = hydrateOptions(options);
|
|
833
|
+
applyRuntimeGitHubAuth(state);
|
|
834
|
+
const repos = await fetchTemplateRepos({ owner: state.owner });
|
|
312
835
|
if (repos.length === 0) {
|
|
313
|
-
throw new Error(`No public template-* repos found for ${
|
|
836
|
+
throw new Error(`No public template-* repos found for ${state.owner}.`);
|
|
314
837
|
}
|
|
315
838
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
839
|
+
const resolvedState = options.yes
|
|
840
|
+
? validateNonInteractiveState(sanitizeStateForInstall(state))
|
|
841
|
+
: process.stdin.isTTY && process.stdout.isTTY
|
|
842
|
+
? await runWizard(state, repos)
|
|
843
|
+
: await promptLinearly(state, repos);
|
|
844
|
+
|
|
845
|
+
applyRuntimeGitHubAuth(resolvedState);
|
|
846
|
+
const selectedRepo = resolveTemplateRepo(resolvedState.template, repos);
|
|
847
|
+
const destinationRoot = ensureTargetDir(resolvedState.targetDir, {
|
|
848
|
+
force: resolvedState.force,
|
|
849
|
+
});
|
|
319
850
|
const result = installTemplateRepo({
|
|
320
851
|
destinationRoot: path.resolve(destinationRoot),
|
|
321
852
|
templateRepo: selectedRepo,
|
|
322
|
-
|
|
853
|
+
setupSelections: resolvedState,
|
|
854
|
+
skipBootstrap: resolvedState.skipBootstrap,
|
|
323
855
|
});
|
|
324
856
|
printSuccess(result);
|
|
325
857
|
} catch (error) {
|