solokit 0.1.1__py3-none-any.whl
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.
- solokit/__init__.py +10 -0
- solokit/__version__.py +3 -0
- solokit/cli.py +374 -0
- solokit/core/__init__.py +1 -0
- solokit/core/cache.py +102 -0
- solokit/core/command_runner.py +278 -0
- solokit/core/config.py +453 -0
- solokit/core/config_validator.py +204 -0
- solokit/core/constants.py +291 -0
- solokit/core/error_formatter.py +279 -0
- solokit/core/error_handlers.py +346 -0
- solokit/core/exceptions.py +1567 -0
- solokit/core/file_ops.py +309 -0
- solokit/core/logging_config.py +166 -0
- solokit/core/output.py +99 -0
- solokit/core/performance.py +57 -0
- solokit/core/protocols.py +141 -0
- solokit/core/types.py +312 -0
- solokit/deployment/__init__.py +1 -0
- solokit/deployment/executor.py +411 -0
- solokit/git/__init__.py +1 -0
- solokit/git/integration.py +619 -0
- solokit/init/__init__.py +41 -0
- solokit/init/claude_commands_installer.py +87 -0
- solokit/init/dependency_installer.py +313 -0
- solokit/init/docs_structure.py +90 -0
- solokit/init/env_generator.py +160 -0
- solokit/init/environment_validator.py +334 -0
- solokit/init/git_hooks_installer.py +71 -0
- solokit/init/git_setup.py +188 -0
- solokit/init/gitignore_updater.py +195 -0
- solokit/init/initial_commit.py +145 -0
- solokit/init/initial_scans.py +109 -0
- solokit/init/orchestrator.py +246 -0
- solokit/init/readme_generator.py +207 -0
- solokit/init/session_structure.py +239 -0
- solokit/init/template_installer.py +424 -0
- solokit/learning/__init__.py +1 -0
- solokit/learning/archiver.py +115 -0
- solokit/learning/categorizer.py +126 -0
- solokit/learning/curator.py +428 -0
- solokit/learning/extractor.py +352 -0
- solokit/learning/reporter.py +351 -0
- solokit/learning/repository.py +254 -0
- solokit/learning/similarity.py +342 -0
- solokit/learning/validator.py +144 -0
- solokit/project/__init__.py +1 -0
- solokit/project/init.py +1162 -0
- solokit/project/stack.py +436 -0
- solokit/project/sync_plugin.py +438 -0
- solokit/project/tree.py +375 -0
- solokit/quality/__init__.py +1 -0
- solokit/quality/api_validator.py +424 -0
- solokit/quality/checkers/__init__.py +25 -0
- solokit/quality/checkers/base.py +114 -0
- solokit/quality/checkers/context7.py +221 -0
- solokit/quality/checkers/custom.py +162 -0
- solokit/quality/checkers/deployment.py +323 -0
- solokit/quality/checkers/documentation.py +179 -0
- solokit/quality/checkers/formatting.py +161 -0
- solokit/quality/checkers/integration.py +394 -0
- solokit/quality/checkers/linting.py +159 -0
- solokit/quality/checkers/security.py +261 -0
- solokit/quality/checkers/spec_completeness.py +127 -0
- solokit/quality/checkers/tests.py +184 -0
- solokit/quality/env_validator.py +306 -0
- solokit/quality/gates.py +655 -0
- solokit/quality/reporters/__init__.py +10 -0
- solokit/quality/reporters/base.py +25 -0
- solokit/quality/reporters/console.py +98 -0
- solokit/quality/reporters/json_reporter.py +34 -0
- solokit/quality/results.py +98 -0
- solokit/session/__init__.py +1 -0
- solokit/session/briefing/__init__.py +245 -0
- solokit/session/briefing/documentation_loader.py +53 -0
- solokit/session/briefing/formatter.py +476 -0
- solokit/session/briefing/git_context.py +282 -0
- solokit/session/briefing/learning_loader.py +212 -0
- solokit/session/briefing/milestone_builder.py +78 -0
- solokit/session/briefing/orchestrator.py +137 -0
- solokit/session/briefing/stack_detector.py +51 -0
- solokit/session/briefing/tree_generator.py +52 -0
- solokit/session/briefing/work_item_loader.py +209 -0
- solokit/session/briefing.py +353 -0
- solokit/session/complete.py +1188 -0
- solokit/session/status.py +246 -0
- solokit/session/validate.py +452 -0
- solokit/templates/.claude/commands/end.md +109 -0
- solokit/templates/.claude/commands/init.md +159 -0
- solokit/templates/.claude/commands/learn-curate.md +88 -0
- solokit/templates/.claude/commands/learn-search.md +62 -0
- solokit/templates/.claude/commands/learn-show.md +69 -0
- solokit/templates/.claude/commands/learn.md +136 -0
- solokit/templates/.claude/commands/start.md +114 -0
- solokit/templates/.claude/commands/status.md +22 -0
- solokit/templates/.claude/commands/validate.md +27 -0
- solokit/templates/.claude/commands/work-delete.md +119 -0
- solokit/templates/.claude/commands/work-graph.md +139 -0
- solokit/templates/.claude/commands/work-list.md +26 -0
- solokit/templates/.claude/commands/work-new.md +114 -0
- solokit/templates/.claude/commands/work-next.md +25 -0
- solokit/templates/.claude/commands/work-show.md +24 -0
- solokit/templates/.claude/commands/work-update.md +141 -0
- solokit/templates/CHANGELOG.md +17 -0
- solokit/templates/WORK_ITEM_TYPES.md +141 -0
- solokit/templates/__init__.py +1 -0
- solokit/templates/bug_spec.md +217 -0
- solokit/templates/config.schema.json +150 -0
- solokit/templates/dashboard_refine/base/.gitignore +36 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/layout.tsx +22 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/page.tsx +68 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/users/page.tsx +77 -0
- solokit/templates/dashboard_refine/base/app/globals.css +60 -0
- solokit/templates/dashboard_refine/base/app/layout.tsx +23 -0
- solokit/templates/dashboard_refine/base/app/page.tsx +9 -0
- solokit/templates/dashboard_refine/base/components/client-refine-wrapper.tsx +21 -0
- solokit/templates/dashboard_refine/base/components/layout/header.tsx +44 -0
- solokit/templates/dashboard_refine/base/components/layout/sidebar.tsx +82 -0
- solokit/templates/dashboard_refine/base/components/ui/button.tsx +53 -0
- solokit/templates/dashboard_refine/base/components/ui/card.tsx +78 -0
- solokit/templates/dashboard_refine/base/components/ui/table.tsx +116 -0
- solokit/templates/dashboard_refine/base/components.json +16 -0
- solokit/templates/dashboard_refine/base/lib/refine.tsx +65 -0
- solokit/templates/dashboard_refine/base/lib/utils.ts +13 -0
- solokit/templates/dashboard_refine/base/next.config.ts +10 -0
- solokit/templates/dashboard_refine/base/package.json.template +40 -0
- solokit/templates/dashboard_refine/base/postcss.config.mjs +8 -0
- solokit/templates/dashboard_refine/base/providers/refine-provider.tsx +26 -0
- solokit/templates/dashboard_refine/base/tailwind.config.ts +57 -0
- solokit/templates/dashboard_refine/base/tsconfig.json +27 -0
- solokit/templates/dashboard_refine/docker/Dockerfile +57 -0
- solokit/templates/dashboard_refine/docker/docker-compose.prod.yml +31 -0
- solokit/templates/dashboard_refine/docker/docker-compose.yml +21 -0
- solokit/templates/dashboard_refine/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/dashboard_refine/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/dashboard_refine/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/dashboard_refine/tier-1-essential/package.json.tier1.template +57 -0
- solokit/templates/dashboard_refine/tier-1-essential/tests/setup.ts +26 -0
- solokit/templates/dashboard_refine/tier-1-essential/tests/unit/example.test.tsx +73 -0
- solokit/templates/dashboard_refine/tier-2-standard/package.json.tier2.template +62 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/eslint.config.mjs +22 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/package.json.tier3.template +79 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/stryker.conf.json +38 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/dashboard.spec.ts +88 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/user-management.spec.ts +102 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/integration/dashboard.test.tsx +90 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/type-coverage.json +16 -0
- solokit/templates/dashboard_refine/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/dashboard_refine/tier-4-production/k6/dashboard-load-test.js +70 -0
- solokit/templates/dashboard_refine/tier-4-production/next.config.ts +46 -0
- solokit/templates/dashboard_refine/tier-4-production/package.json.tier4.template +89 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/deployment_spec.md +500 -0
- solokit/templates/feature_spec.md +248 -0
- solokit/templates/fullstack_nextjs/base/.gitignore +36 -0
- solokit/templates/fullstack_nextjs/base/app/api/example/route.ts +65 -0
- solokit/templates/fullstack_nextjs/base/app/globals.css +27 -0
- solokit/templates/fullstack_nextjs/base/app/layout.tsx +20 -0
- solokit/templates/fullstack_nextjs/base/app/page.tsx +32 -0
- solokit/templates/fullstack_nextjs/base/components/example-component.tsx +20 -0
- solokit/templates/fullstack_nextjs/base/lib/prisma.ts +17 -0
- solokit/templates/fullstack_nextjs/base/lib/utils.ts +13 -0
- solokit/templates/fullstack_nextjs/base/lib/validations.ts +20 -0
- solokit/templates/fullstack_nextjs/base/next.config.ts +7 -0
- solokit/templates/fullstack_nextjs/base/package.json.template +32 -0
- solokit/templates/fullstack_nextjs/base/postcss.config.mjs +8 -0
- solokit/templates/fullstack_nextjs/base/prisma/schema.prisma +21 -0
- solokit/templates/fullstack_nextjs/base/tailwind.config.ts +19 -0
- solokit/templates/fullstack_nextjs/base/tsconfig.json +27 -0
- solokit/templates/fullstack_nextjs/docker/Dockerfile +60 -0
- solokit/templates/fullstack_nextjs/docker/docker-compose.prod.yml +57 -0
- solokit/templates/fullstack_nextjs/docker/docker-compose.yml +47 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/package.json.tier1.template +48 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/api/example.test.ts +88 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/setup.ts +22 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/unit/example.test.tsx +22 -0
- solokit/templates/fullstack_nextjs/tier-2-standard/package.json.tier2.template +52 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/eslint.config.mjs +39 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/package.json.tier3.template +68 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/stryker.conf.json +33 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/e2e/flow.spec.ts +59 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/integration/api.test.ts +165 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/type-coverage.json +12 -0
- solokit/templates/fullstack_nextjs/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/fullstack_nextjs/tier-4-production/k6/load-test.js +45 -0
- solokit/templates/fullstack_nextjs/tier-4-production/next.config.ts +46 -0
- solokit/templates/fullstack_nextjs/tier-4-production/package.json.tier4.template +77 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/git-hooks/prepare-commit-msg +24 -0
- solokit/templates/integration_test_spec.md +363 -0
- solokit/templates/learnings.json +15 -0
- solokit/templates/ml_ai_fastapi/base/.gitignore +104 -0
- solokit/templates/ml_ai_fastapi/base/alembic/env.py +96 -0
- solokit/templates/ml_ai_fastapi/base/alembic.ini +114 -0
- solokit/templates/ml_ai_fastapi/base/pyproject.toml.template +91 -0
- solokit/templates/ml_ai_fastapi/base/requirements.txt.template +28 -0
- solokit/templates/ml_ai_fastapi/base/src/__init__.py +5 -0
- solokit/templates/ml_ai_fastapi/base/src/api/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/api/dependencies.py +20 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/example.py +134 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/health.py +66 -0
- solokit/templates/ml_ai_fastapi/base/src/core/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/core/config.py +64 -0
- solokit/templates/ml_ai_fastapi/base/src/core/database.py +50 -0
- solokit/templates/ml_ai_fastapi/base/src/main.py +64 -0
- solokit/templates/ml_ai_fastapi/base/src/models/__init__.py +7 -0
- solokit/templates/ml_ai_fastapi/base/src/models/example.py +61 -0
- solokit/templates/ml_ai_fastapi/base/src/services/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/services/example.py +115 -0
- solokit/templates/ml_ai_fastapi/docker/Dockerfile +59 -0
- solokit/templates/ml_ai_fastapi/docker/docker-compose.prod.yml +112 -0
- solokit/templates/ml_ai_fastapi/docker/docker-compose.yml +77 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pyproject.toml.tier1.template +112 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pyrightconfig.json +41 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pytest.ini +69 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/requirements-dev.txt +17 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/ruff.toml +81 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/conftest.py +72 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/test_main.py +49 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/test_example.py +113 -0
- solokit/templates/ml_ai_fastapi/tier-2-standard/pyproject.toml.tier2.template +130 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/locustfile.py +99 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/mutmut_config.py +53 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/pyproject.toml.tier3.template +150 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/conftest.py +74 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/test_api.py +131 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/pyproject.toml.tier4.template +162 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/requirements-prod.txt +25 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/api/routes/metrics.py +19 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/logging.py +74 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/monitoring.py +68 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/sentry.py +66 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/logging.py +79 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/tracing.py +60 -0
- solokit/templates/refactor_spec.md +287 -0
- solokit/templates/saas_t3/base/.gitignore +36 -0
- solokit/templates/saas_t3/base/app/api/trpc/[trpc]/route.ts +33 -0
- solokit/templates/saas_t3/base/app/globals.css +27 -0
- solokit/templates/saas_t3/base/app/layout.tsx +23 -0
- solokit/templates/saas_t3/base/app/page.tsx +31 -0
- solokit/templates/saas_t3/base/lib/api.tsx +77 -0
- solokit/templates/saas_t3/base/lib/utils.ts +13 -0
- solokit/templates/saas_t3/base/next.config.ts +7 -0
- solokit/templates/saas_t3/base/package.json.template +38 -0
- solokit/templates/saas_t3/base/postcss.config.mjs +8 -0
- solokit/templates/saas_t3/base/prisma/schema.prisma +20 -0
- solokit/templates/saas_t3/base/server/api/root.ts +19 -0
- solokit/templates/saas_t3/base/server/api/routers/example.ts +28 -0
- solokit/templates/saas_t3/base/server/api/trpc.ts +52 -0
- solokit/templates/saas_t3/base/server/db.ts +17 -0
- solokit/templates/saas_t3/base/tailwind.config.ts +19 -0
- solokit/templates/saas_t3/base/tsconfig.json +27 -0
- solokit/templates/saas_t3/docker/Dockerfile +60 -0
- solokit/templates/saas_t3/docker/docker-compose.prod.yml +59 -0
- solokit/templates/saas_t3/docker/docker-compose.yml +49 -0
- solokit/templates/saas_t3/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/saas_t3/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/saas_t3/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/saas_t3/tier-1-essential/package.json.tier1.template +54 -0
- solokit/templates/saas_t3/tier-1-essential/tests/setup.ts +22 -0
- solokit/templates/saas_t3/tier-1-essential/tests/unit/example.test.tsx +24 -0
- solokit/templates/saas_t3/tier-2-standard/package.json.tier2.template +58 -0
- solokit/templates/saas_t3/tier-3-comprehensive/eslint.config.mjs +39 -0
- solokit/templates/saas_t3/tier-3-comprehensive/package.json.tier3.template +74 -0
- solokit/templates/saas_t3/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/saas_t3/tier-3-comprehensive/stryker.conf.json +34 -0
- solokit/templates/saas_t3/tier-3-comprehensive/tests/e2e/home.spec.ts +41 -0
- solokit/templates/saas_t3/tier-3-comprehensive/tests/integration/api.test.ts +44 -0
- solokit/templates/saas_t3/tier-3-comprehensive/type-coverage.json +12 -0
- solokit/templates/saas_t3/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/saas_t3/tier-4-production/k6/load-test.js +51 -0
- solokit/templates/saas_t3/tier-4-production/next.config.ts +46 -0
- solokit/templates/saas_t3/tier-4-production/package.json.tier4.template +83 -0
- solokit/templates/saas_t3/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/saas_t3/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/saas_t3/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/saas_t3/tier-4-production/vercel.json +37 -0
- solokit/templates/security_spec.md +287 -0
- solokit/templates/stack-versions.yaml +617 -0
- solokit/templates/status_update.json +6 -0
- solokit/templates/template-registry.json +257 -0
- solokit/templates/work_items.json +11 -0
- solokit/testing/__init__.py +1 -0
- solokit/testing/integration_runner.py +550 -0
- solokit/testing/performance.py +637 -0
- solokit/visualization/__init__.py +1 -0
- solokit/visualization/dependency_graph.py +788 -0
- solokit/work_items/__init__.py +1 -0
- solokit/work_items/creator.py +217 -0
- solokit/work_items/delete.py +264 -0
- solokit/work_items/get_dependencies.py +185 -0
- solokit/work_items/get_dependents.py +113 -0
- solokit/work_items/get_metadata.py +121 -0
- solokit/work_items/get_next_recommendations.py +133 -0
- solokit/work_items/manager.py +235 -0
- solokit/work_items/milestones.py +137 -0
- solokit/work_items/query.py +376 -0
- solokit/work_items/repository.py +267 -0
- solokit/work_items/scheduler.py +184 -0
- solokit/work_items/spec_parser.py +838 -0
- solokit/work_items/spec_validator.py +493 -0
- solokit/work_items/updater.py +157 -0
- solokit/work_items/validator.py +205 -0
- solokit-0.1.1.dist-info/METADATA +640 -0
- solokit-0.1.1.dist-info/RECORD +323 -0
- solokit-0.1.1.dist-info/WHEEL +5 -0
- solokit-0.1.1.dist-info/entry_points.txt +2 -0
- solokit-0.1.1.dist-info/licenses/LICENSE +21 -0
- solokit-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Claude Commands Installer Module
|
|
3
|
+
|
|
4
|
+
Installs Claude Code slash commands to project .claude/commands directory.
|
|
5
|
+
This enables project-specific slash commands like /start, /end, /work-new, etc.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
import shutil
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from solokit.core.exceptions import FileOperationError, TemplateNotFoundError
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def install_claude_commands(project_root: Path | None = None) -> list[Path]:
|
|
20
|
+
"""
|
|
21
|
+
Install Claude Code slash commands from package to project .claude/commands directory.
|
|
22
|
+
|
|
23
|
+
This enables users who installed via PyPI to use slash commands in their project
|
|
24
|
+
without the /sk: prefix (e.g., /start instead of /sk:start).
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
project_root: Root directory of the project. Defaults to current working directory.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
List of installed command file paths
|
|
31
|
+
|
|
32
|
+
Raises:
|
|
33
|
+
TemplateNotFoundError: If .claude/commands directory is not found in package.
|
|
34
|
+
FileOperationError: If command installation fails.
|
|
35
|
+
"""
|
|
36
|
+
if project_root is None:
|
|
37
|
+
project_root = Path.cwd()
|
|
38
|
+
|
|
39
|
+
# Destination: project's .claude/commands directory
|
|
40
|
+
commands_dest_dir = project_root / ".claude" / "commands"
|
|
41
|
+
|
|
42
|
+
# Source: .claude/commands from the installed package templates
|
|
43
|
+
# Commands are stored in templates/.claude/commands to ensure they're packaged in the wheel
|
|
44
|
+
package_dir = Path(__file__).parent.parent
|
|
45
|
+
commands_source_dir = package_dir / "templates" / ".claude" / "commands"
|
|
46
|
+
|
|
47
|
+
# Check if source commands directory exists
|
|
48
|
+
if not commands_source_dir.exists():
|
|
49
|
+
raise TemplateNotFoundError(
|
|
50
|
+
template_name=".claude/commands",
|
|
51
|
+
template_path=str(package_dir),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
installed_commands = []
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
# Create .claude/commands directory in project
|
|
58
|
+
commands_dest_dir.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
logger.debug(f"Created directory: {commands_dest_dir.relative_to(project_root)}")
|
|
60
|
+
|
|
61
|
+
# Copy all .md command files
|
|
62
|
+
command_files = list(commands_source_dir.glob("*.md"))
|
|
63
|
+
|
|
64
|
+
if not command_files:
|
|
65
|
+
logger.warning(
|
|
66
|
+
f"No .md files found in {commands_source_dir}. "
|
|
67
|
+
"Slash commands may not work properly."
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
for cmd_file in command_files:
|
|
71
|
+
dest_file = commands_dest_dir / cmd_file.name
|
|
72
|
+
shutil.copy2(cmd_file, dest_file)
|
|
73
|
+
installed_commands.append(dest_file)
|
|
74
|
+
logger.debug(f"Installed command: {cmd_file.name}")
|
|
75
|
+
|
|
76
|
+
logger.info(f"Installed {len(installed_commands)} Claude Code slash commands")
|
|
77
|
+
logger.info("You can now use slash commands like /start, /end, /work-new in Claude Code")
|
|
78
|
+
|
|
79
|
+
except Exception as e:
|
|
80
|
+
raise FileOperationError(
|
|
81
|
+
operation="install",
|
|
82
|
+
file_path=str(commands_dest_dir),
|
|
83
|
+
details=f"Failed to install Claude Code commands: {str(e)}",
|
|
84
|
+
cause=e,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return installed_commands
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dependency Installer Module
|
|
3
|
+
|
|
4
|
+
Handles dependency installation using exact versions from stack-versions.yaml.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Literal, cast
|
|
13
|
+
|
|
14
|
+
import yaml
|
|
15
|
+
|
|
16
|
+
from solokit.core.command_runner import CommandRunner
|
|
17
|
+
from solokit.core.exceptions import CommandExecutionError, FileOperationError
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def load_stack_versions() -> dict[str, Any]:
|
|
23
|
+
"""
|
|
24
|
+
Load validated versions from stack-versions.yaml.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Stack versions dictionary
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
FileOperationError: If file not found or invalid YAML
|
|
31
|
+
"""
|
|
32
|
+
versions_file = Path(__file__).parent.parent / "templates" / "stack-versions.yaml"
|
|
33
|
+
|
|
34
|
+
if not versions_file.exists():
|
|
35
|
+
raise FileOperationError(
|
|
36
|
+
operation="load",
|
|
37
|
+
file_path=str(versions_file),
|
|
38
|
+
details="stack-versions.yaml not found",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
with open(versions_file) as f:
|
|
43
|
+
return cast(dict[str, Any], yaml.safe_load(f))
|
|
44
|
+
except yaml.YAMLError as e:
|
|
45
|
+
raise FileOperationError(
|
|
46
|
+
operation="parse",
|
|
47
|
+
file_path=str(versions_file),
|
|
48
|
+
details=f"Invalid YAML: {str(e)}",
|
|
49
|
+
cause=e,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_installation_commands(
|
|
54
|
+
stack_id: str,
|
|
55
|
+
tier: str,
|
|
56
|
+
) -> dict[str, Any]:
|
|
57
|
+
"""
|
|
58
|
+
Get installation commands for a stack and tier.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
stack_id: Stack identifier (e.g., "saas_t3")
|
|
62
|
+
tier: Tier level (e.g., "tier-1")
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Installation commands dictionary from stack-versions.yaml
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
FileOperationError: If stack or tier not found
|
|
69
|
+
"""
|
|
70
|
+
versions = load_stack_versions()
|
|
71
|
+
|
|
72
|
+
if stack_id not in versions["stacks"]:
|
|
73
|
+
raise FileOperationError(
|
|
74
|
+
operation="lookup",
|
|
75
|
+
file_path="stack-versions.yaml",
|
|
76
|
+
details=f"Stack '{stack_id}' not found in versions file",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
stack = versions["stacks"][stack_id]
|
|
80
|
+
|
|
81
|
+
if "installation" not in stack:
|
|
82
|
+
raise FileOperationError(
|
|
83
|
+
operation="lookup",
|
|
84
|
+
file_path="stack-versions.yaml",
|
|
85
|
+
details=f"No installation commands found for stack '{stack_id}'",
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return cast(dict[str, Any], stack["installation"])
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def install_npm_dependencies(
|
|
92
|
+
template_id: str,
|
|
93
|
+
tier: Literal[
|
|
94
|
+
"tier-1-essential", "tier-2-standard", "tier-3-comprehensive", "tier-4-production"
|
|
95
|
+
],
|
|
96
|
+
project_root: Path | None = None,
|
|
97
|
+
) -> bool:
|
|
98
|
+
"""
|
|
99
|
+
Install npm dependencies for a Next.js-based stack.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
template_id: Template identifier (e.g., "saas_t3")
|
|
103
|
+
tier: Quality tier
|
|
104
|
+
project_root: Project root directory
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
True if installation succeeded
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
CommandExecutionError: If npm installation fails critically
|
|
111
|
+
"""
|
|
112
|
+
if project_root is None:
|
|
113
|
+
project_root = Path.cwd()
|
|
114
|
+
|
|
115
|
+
# Map template_id to stack_id
|
|
116
|
+
template_to_stack = {
|
|
117
|
+
"saas_t3": "saas_t3",
|
|
118
|
+
"dashboard_refine": "dashboard_refine",
|
|
119
|
+
"fullstack_nextjs": "fullstack_nextjs",
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
stack_id = template_to_stack.get(template_id)
|
|
123
|
+
if not stack_id:
|
|
124
|
+
logger.warning(f"Unknown template ID: {template_id}")
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
# Get installation commands
|
|
128
|
+
installation = get_installation_commands(stack_id, tier)
|
|
129
|
+
|
|
130
|
+
logger.info("Installing npm dependencies...")
|
|
131
|
+
logger.info("This may take several minutes...")
|
|
132
|
+
|
|
133
|
+
runner = CommandRunner(default_timeout=600, working_dir=project_root) # 10 min timeout
|
|
134
|
+
|
|
135
|
+
# Map tier to command keys
|
|
136
|
+
tier_to_command_key = {
|
|
137
|
+
"tier-1-essential": ["base", "tier1"],
|
|
138
|
+
"tier-2-standard": ["base", "tier1", "tier2"],
|
|
139
|
+
"tier-3-comprehensive": ["base", "tier1", "tier2", "tier3"],
|
|
140
|
+
"tier-4-production": ["base", "tier1", "tier2", "tier3", "tier4_dev", "tier4_prod"],
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
command_keys = tier_to_command_key.get(tier, ["base"])
|
|
144
|
+
|
|
145
|
+
# Run installation commands sequentially
|
|
146
|
+
for command_key in command_keys:
|
|
147
|
+
if command_key not in installation["commands"]:
|
|
148
|
+
logger.warning(f"Command key '{command_key}' not found for {stack_id}")
|
|
149
|
+
continue
|
|
150
|
+
|
|
151
|
+
command_str = installation["commands"][command_key]
|
|
152
|
+
logger.info(f"Running: {command_key}...")
|
|
153
|
+
|
|
154
|
+
# Parse command string and run
|
|
155
|
+
result = runner.run(["sh", "-c", command_str], check=False)
|
|
156
|
+
|
|
157
|
+
if not result.success:
|
|
158
|
+
logger.error(f"Failed to install {command_key}: {result.stderr}")
|
|
159
|
+
raise CommandExecutionError(
|
|
160
|
+
command=command_str,
|
|
161
|
+
returncode=result.returncode,
|
|
162
|
+
stderr=result.stderr,
|
|
163
|
+
context={"tier": tier, "command_key": command_key},
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
logger.info(f"✓ Installed {command_key}")
|
|
167
|
+
|
|
168
|
+
logger.info("✅ All npm dependencies installed successfully")
|
|
169
|
+
return True
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def install_python_dependencies(
|
|
173
|
+
tier: Literal[
|
|
174
|
+
"tier-1-essential", "tier-2-standard", "tier-3-comprehensive", "tier-4-production"
|
|
175
|
+
],
|
|
176
|
+
python_binary: str | None = None,
|
|
177
|
+
project_root: Path | None = None,
|
|
178
|
+
) -> bool:
|
|
179
|
+
"""
|
|
180
|
+
Install Python dependencies for ML/AI FastAPI stack.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
tier: Quality tier
|
|
184
|
+
python_binary: Python binary to use (e.g., "python3.11")
|
|
185
|
+
project_root: Project root directory
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
True if installation succeeded
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
CommandExecutionError: If pip installation fails critically
|
|
192
|
+
"""
|
|
193
|
+
if project_root is None:
|
|
194
|
+
project_root = Path.cwd()
|
|
195
|
+
|
|
196
|
+
if python_binary is None:
|
|
197
|
+
python_binary = sys.executable
|
|
198
|
+
|
|
199
|
+
# Get installation commands
|
|
200
|
+
installation = get_installation_commands("ml_ai_fastapi", tier)
|
|
201
|
+
|
|
202
|
+
logger.info("Setting up Python virtual environment...")
|
|
203
|
+
|
|
204
|
+
runner = CommandRunner(default_timeout=600, working_dir=project_root)
|
|
205
|
+
|
|
206
|
+
# Create virtual environment
|
|
207
|
+
venv_path = project_root / "venv"
|
|
208
|
+
if not venv_path.exists():
|
|
209
|
+
result = runner.run([python_binary, "-m", "venv", "venv"], check=False)
|
|
210
|
+
if not result.success:
|
|
211
|
+
raise CommandExecutionError(
|
|
212
|
+
command=f"{python_binary} -m venv venv",
|
|
213
|
+
returncode=result.returncode,
|
|
214
|
+
stderr=result.stderr,
|
|
215
|
+
)
|
|
216
|
+
logger.info("✓ Created virtual environment")
|
|
217
|
+
else:
|
|
218
|
+
logger.info("Virtual environment already exists")
|
|
219
|
+
|
|
220
|
+
# Determine pip path
|
|
221
|
+
pip_path = venv_path / "bin" / "pip"
|
|
222
|
+
if not pip_path.exists():
|
|
223
|
+
# Windows
|
|
224
|
+
pip_path = venv_path / "Scripts" / "pip"
|
|
225
|
+
|
|
226
|
+
# Upgrade pip
|
|
227
|
+
logger.info("Upgrading pip...")
|
|
228
|
+
result = runner.run([str(pip_path), "install", "--upgrade", "pip"], check=False)
|
|
229
|
+
if result.success:
|
|
230
|
+
logger.info("✓ Upgraded pip")
|
|
231
|
+
|
|
232
|
+
# Install dependencies
|
|
233
|
+
logger.info("Installing Python dependencies...")
|
|
234
|
+
logger.info("This may take several minutes...")
|
|
235
|
+
|
|
236
|
+
# Map tier to command keys (incremental installation)
|
|
237
|
+
tier_to_command_key = {
|
|
238
|
+
"tier-1-essential": ["base", "tier1"],
|
|
239
|
+
"tier-2-standard": ["base", "tier1", "tier2"],
|
|
240
|
+
"tier-3-comprehensive": ["base", "tier1", "tier2", "tier3"],
|
|
241
|
+
"tier-4-production": ["base", "tier1", "tier2", "tier3", "tier4_dev", "tier4_prod"],
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
command_keys = tier_to_command_key.get(tier, ["base"])
|
|
245
|
+
|
|
246
|
+
for command_key in command_keys:
|
|
247
|
+
if command_key not in installation["commands"]:
|
|
248
|
+
logger.warning(f"Command key '{command_key}' not found for ml_ai_fastapi")
|
|
249
|
+
continue
|
|
250
|
+
|
|
251
|
+
command_str = installation["commands"][command_key]
|
|
252
|
+
# Replace 'pip install' with full pip path
|
|
253
|
+
command_str = command_str.replace("pip install", f"{pip_path} install")
|
|
254
|
+
|
|
255
|
+
logger.info(f"Running: {command_key}...")
|
|
256
|
+
|
|
257
|
+
result = runner.run(["sh", "-c", command_str], check=False)
|
|
258
|
+
|
|
259
|
+
if not result.success:
|
|
260
|
+
logger.error(f"Failed to install {command_key}: {result.stderr}")
|
|
261
|
+
raise CommandExecutionError(
|
|
262
|
+
command=command_str,
|
|
263
|
+
returncode=result.returncode,
|
|
264
|
+
stderr=result.stderr,
|
|
265
|
+
context={"tier": tier, "command_key": command_key},
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
logger.info(f"✓ Installed {command_key}")
|
|
269
|
+
|
|
270
|
+
# Run security fixes if available
|
|
271
|
+
if "security_fixes" in installation["commands"]:
|
|
272
|
+
logger.info("Applying security fixes...")
|
|
273
|
+
command_str = installation["commands"]["security_fixes"]
|
|
274
|
+
command_str = command_str.replace("pip install", f"{pip_path} install")
|
|
275
|
+
|
|
276
|
+
result = runner.run(["sh", "-c", command_str], check=False)
|
|
277
|
+
if result.success:
|
|
278
|
+
logger.info("✓ Applied security fixes")
|
|
279
|
+
else:
|
|
280
|
+
logger.warning("Security fixes failed (non-critical)")
|
|
281
|
+
|
|
282
|
+
logger.info("✅ All Python dependencies installed successfully")
|
|
283
|
+
return True
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def install_dependencies(
|
|
287
|
+
template_id: str,
|
|
288
|
+
tier: Literal[
|
|
289
|
+
"tier-1-essential", "tier-2-standard", "tier-3-comprehensive", "tier-4-production"
|
|
290
|
+
],
|
|
291
|
+
python_binary: str | None = None,
|
|
292
|
+
project_root: Path | None = None,
|
|
293
|
+
) -> bool:
|
|
294
|
+
"""
|
|
295
|
+
Install dependencies for a template based on its package manager.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
template_id: Template identifier
|
|
299
|
+
tier: Quality tier
|
|
300
|
+
python_binary: Python binary for Python projects
|
|
301
|
+
project_root: Project root directory
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
True if installation succeeded
|
|
305
|
+
|
|
306
|
+
Raises:
|
|
307
|
+
CommandExecutionError: If installation fails critically
|
|
308
|
+
"""
|
|
309
|
+
# Determine package manager from template ID
|
|
310
|
+
if template_id == "ml_ai_fastapi":
|
|
311
|
+
return install_python_dependencies(tier, python_binary, project_root)
|
|
312
|
+
else:
|
|
313
|
+
return install_npm_dependencies(template_id, tier, project_root)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Documentation Structure Module
|
|
3
|
+
|
|
4
|
+
Creates documentation directory structure.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from solokit.core.exceptions import FileOperationError
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_docs_structure(project_root: Path | None = None) -> list[Path]:
|
|
18
|
+
"""
|
|
19
|
+
Create documentation directory structure.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
project_root: Project root directory
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
List of created directory paths
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
FileOperationError: If directory creation fails
|
|
29
|
+
"""
|
|
30
|
+
if project_root is None:
|
|
31
|
+
project_root = Path.cwd()
|
|
32
|
+
|
|
33
|
+
docs_dir = project_root / "docs"
|
|
34
|
+
created_dirs = []
|
|
35
|
+
|
|
36
|
+
directories = [
|
|
37
|
+
docs_dir / "architecture",
|
|
38
|
+
docs_dir / "architecture" / "decisions", # ADRs
|
|
39
|
+
docs_dir / "api",
|
|
40
|
+
docs_dir / "guides",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
for dir_path in directories:
|
|
45
|
+
dir_path.mkdir(parents=True, exist_ok=True)
|
|
46
|
+
created_dirs.append(dir_path)
|
|
47
|
+
logger.debug(f"Created {dir_path.relative_to(project_root)}")
|
|
48
|
+
|
|
49
|
+
# Create placeholder README files
|
|
50
|
+
(docs_dir / "architecture" / "README.md").write_text(
|
|
51
|
+
"# Architecture\n\nArchitecture documentation and decisions.\n"
|
|
52
|
+
)
|
|
53
|
+
(docs_dir / "api" / "README.md").write_text(
|
|
54
|
+
"# API Documentation\n\nAPI documentation goes here.\n"
|
|
55
|
+
)
|
|
56
|
+
(docs_dir / "guides" / "development.md").write_text(
|
|
57
|
+
"# Development Guide\n\nDevelopment setup and workflow.\n"
|
|
58
|
+
)
|
|
59
|
+
(docs_dir / "guides" / "deployment.md").write_text(
|
|
60
|
+
"# Deployment Guide\n\nDeployment instructions.\n"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Create SECURITY.md
|
|
64
|
+
security_path = docs_dir / "SECURITY.md"
|
|
65
|
+
security_path.write_text(
|
|
66
|
+
"""# Security Policy
|
|
67
|
+
|
|
68
|
+
## Reporting a Vulnerability
|
|
69
|
+
|
|
70
|
+
If you discover a security vulnerability, please report it to the project maintainers.
|
|
71
|
+
|
|
72
|
+
## Security Best Practices
|
|
73
|
+
|
|
74
|
+
- Never commit secrets or credentials
|
|
75
|
+
- Use environment variables for sensitive configuration
|
|
76
|
+
- Keep dependencies up to date
|
|
77
|
+
- Follow secure coding practices
|
|
78
|
+
"""
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
logger.info(f"Created docs/ structure with {len(created_dirs)} directories")
|
|
82
|
+
return created_dirs
|
|
83
|
+
|
|
84
|
+
except Exception as e:
|
|
85
|
+
raise FileOperationError(
|
|
86
|
+
operation="create",
|
|
87
|
+
file_path=str(docs_dir),
|
|
88
|
+
details=f"Failed to create documentation structure: {str(e)}",
|
|
89
|
+
cause=e,
|
|
90
|
+
)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Environment File Generator Module
|
|
3
|
+
|
|
4
|
+
Generates .env.example and .editorconfig files.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from solokit.core.exceptions import FileOperationError
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def generate_editorconfig(project_root: Path | None = None) -> Path:
|
|
18
|
+
"""
|
|
19
|
+
Generate .editorconfig for universal editor configuration.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
project_root: Project root directory
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Path to .editorconfig file
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
FileOperationError: If file creation fails
|
|
29
|
+
"""
|
|
30
|
+
if project_root is None:
|
|
31
|
+
project_root = Path.cwd()
|
|
32
|
+
|
|
33
|
+
editorconfig_path = project_root / ".editorconfig"
|
|
34
|
+
|
|
35
|
+
content = """root = true
|
|
36
|
+
|
|
37
|
+
[*]
|
|
38
|
+
indent_style = space
|
|
39
|
+
indent_size = 2
|
|
40
|
+
end_of_line = lf
|
|
41
|
+
charset = utf-8
|
|
42
|
+
trim_trailing_whitespace = true
|
|
43
|
+
insert_final_newline = true
|
|
44
|
+
|
|
45
|
+
[*.md]
|
|
46
|
+
trim_trailing_whitespace = false
|
|
47
|
+
|
|
48
|
+
[*.py]
|
|
49
|
+
indent_size = 4
|
|
50
|
+
|
|
51
|
+
[Makefile]
|
|
52
|
+
indent_style = tab
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
editorconfig_path.write_text(content)
|
|
57
|
+
logger.info("Generated .editorconfig")
|
|
58
|
+
return editorconfig_path
|
|
59
|
+
except Exception as e:
|
|
60
|
+
raise FileOperationError(
|
|
61
|
+
operation="write",
|
|
62
|
+
file_path=str(editorconfig_path),
|
|
63
|
+
details=f"Failed to write .editorconfig: {str(e)}",
|
|
64
|
+
cause=e,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def generate_env_example_nextjs(project_root: Path) -> Path:
|
|
69
|
+
"""Generate .env.example for Next.js stacks."""
|
|
70
|
+
env_path = project_root / ".env.example"
|
|
71
|
+
|
|
72
|
+
content = """# Database
|
|
73
|
+
DATABASE_URL="postgresql://user:password@localhost:5432/dbname"
|
|
74
|
+
|
|
75
|
+
# Next.js
|
|
76
|
+
NEXTAUTH_SECRET=""
|
|
77
|
+
NEXTAUTH_URL="http://localhost:3000"
|
|
78
|
+
|
|
79
|
+
# API
|
|
80
|
+
API_BASE_URL="http://localhost:3000/api"
|
|
81
|
+
|
|
82
|
+
# Optional: Error Tracking (Tier 4)
|
|
83
|
+
SENTRY_DSN=""
|
|
84
|
+
|
|
85
|
+
# Optional: Analytics (Tier 4)
|
|
86
|
+
NEXT_PUBLIC_VERCEL_ANALYTICS_ID=""
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
env_path.write_text(content)
|
|
90
|
+
return env_path
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def generate_env_example_python(project_root: Path) -> Path:
|
|
94
|
+
"""Generate .env.example for Python stacks."""
|
|
95
|
+
env_path = project_root / ".env.example"
|
|
96
|
+
|
|
97
|
+
content = """# Database
|
|
98
|
+
DATABASE_URL="postgresql://user:password@localhost:5432/dbname"
|
|
99
|
+
|
|
100
|
+
# API
|
|
101
|
+
API_HOST="0.0.0.0"
|
|
102
|
+
API_PORT=8000
|
|
103
|
+
API_RELOAD=true
|
|
104
|
+
|
|
105
|
+
# Security
|
|
106
|
+
SECRET_KEY="your-secret-key-here"
|
|
107
|
+
ALLOWED_ORIGINS="http://localhost:3000,http://localhost:8000"
|
|
108
|
+
|
|
109
|
+
# Optional: Monitoring (Tier 4)
|
|
110
|
+
SENTRY_DSN=""
|
|
111
|
+
PROMETHEUS_PORT=9090
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
env_path.write_text(content)
|
|
115
|
+
return env_path
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def generate_env_files(template_id: str, project_root: Path | None = None) -> list[Path]:
|
|
119
|
+
"""
|
|
120
|
+
Generate environment template files.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
template_id: Template identifier
|
|
124
|
+
project_root: Project root directory
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
List of created file paths
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
FileOperationError: If file creation fails
|
|
131
|
+
"""
|
|
132
|
+
if project_root is None:
|
|
133
|
+
project_root = Path.cwd()
|
|
134
|
+
|
|
135
|
+
created_files = []
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
# Generate .editorconfig (universal)
|
|
139
|
+
editorconfig_path = generate_editorconfig(project_root)
|
|
140
|
+
created_files.append(editorconfig_path)
|
|
141
|
+
|
|
142
|
+
# Generate .env.example based on template type
|
|
143
|
+
if template_id == "ml_ai_fastapi":
|
|
144
|
+
env_path = generate_env_example_python(project_root)
|
|
145
|
+
else:
|
|
146
|
+
env_path = generate_env_example_nextjs(project_root)
|
|
147
|
+
|
|
148
|
+
created_files.append(env_path)
|
|
149
|
+
logger.info("Generated .env.example")
|
|
150
|
+
|
|
151
|
+
logger.info(f"Generated {len(created_files)} environment files")
|
|
152
|
+
return created_files
|
|
153
|
+
|
|
154
|
+
except Exception as e:
|
|
155
|
+
raise FileOperationError(
|
|
156
|
+
operation="create",
|
|
157
|
+
file_path=str(project_root),
|
|
158
|
+
details=f"Failed to generate environment files: {str(e)}",
|
|
159
|
+
cause=e,
|
|
160
|
+
)
|