thothctl 0.30.3__tar.gz → 0.31.0__tar.gz
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.
- {thothctl-0.30.3 → thothctl-0.31.0}/PKG-INFO +1 -1
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/init/commands/env.py +47 -2
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/init/commands/project.py +27 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/common/.thothcf_module.toml +2 -1
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/document/iac_grunt_graph.py +139 -7
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_template/project_templates.py +3 -0
- thothctl-0.31.0/src/thothctl/services/init/environment/install_skills.py +212 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/convert/get_project_data.py +1 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/version.py +1 -1
- thothctl-0.31.0/tests/test_install_skills.py +110 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/.devcontainer/Dockerfile +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/.devcontainer/README.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/.devcontainer/devcontainer.json +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/.github/workflows/docs.yml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/.github/workflows/python-publish.yml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/.gitignore +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/.pre-commit-config.yaml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/.pydocstyle +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/.readthedocs.yaml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/CHANGELOG.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/CONTRIBUTING.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/Dockerfile +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/LICENSE +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/README.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/catalog/catalog-info.yaml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/dashboard/README.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/ai-review/README.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/ai-review/agent_specifications.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/ai-review/agentcore.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/blast-radius.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/check_environment.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/check_iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/check_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/check_project_iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/check_space.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/cost-analysis-quick-reference.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/cost-analysis.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/customizing_rules.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/deps-advanced.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/deps.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/drift-detection.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/check/plan.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/dashboard/dashboard_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/document/customizing_docs.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/document/document_iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/document/document_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/document/iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/document/mermaid_examples.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/document/mermaid_quickref.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/document/use_cases.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/generate/generate_components.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/generate/generate_iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/generate/generate_stacks.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/init/init.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/init/init_space.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/inventory/CHANGELOG.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/inventory/frameworks/terraform.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/inventory/frameworks/terragrunt.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/inventory/iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/inventory/inventory_iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/inventory/inventory_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/list/list_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/list/list_projects.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/list/list_spaces.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/mcp/mcp.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/project/iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/project/project_cleanup.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/project/project_convert.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/project/project_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/project/project_upgrade.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/project/use_cases.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/remove/remove_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/remove/remove_project.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/remove/remove_space.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/scan/iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/scan/scan_iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/scan/scan_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/scan/use_cases.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/space/space_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/upgrade/upgrade_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/workflow/workflow_devsecops.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/commands/workflow/workflow_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/concepts.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/cross_platform_support.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/framework_architecture.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/infrastructure_composition.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/policy_as_code.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/roadmap_fdi.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/software_architecture.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/space_configuration.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/specs/phase1.10_plan_validation.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/specs/phase1.9_composition_generation.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/specs/phase1_intent_to_iac.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/specs/phase2.5.1_autonomy_model.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/use_cases/README.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/use_cases/ai_dlc.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/use_cases/check_command.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/use_cases/devsecops_quickstart.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/use_cases/devsecops_sdlc.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/use_cases/inventory_command.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/use_cases/platform_engineering_templates.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/use_cases/space_management.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/use_cases/tasks/create_template.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/framework/use_cases/tasks/workflow_implementation_plan.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/how_it_works.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/img/commnad_init.png +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/img/framework/thothforge-framework.svg +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/img/framework/thothfr.png +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/img/icon-light.png +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/img/icon.png +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/img/init_project.gif +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/img/stable/scan_report_example.png +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/includes/abbreviations.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/index.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/installation/devcontainer_setup.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/installation/linux_installation.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/installation/windows_installation.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/javascripts/tablesort.js +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/mcp.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/navigation.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/quick_start.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/requirements.txt +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/stylesheets/extra-enhanced.css +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/stylesheets/extra.css +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/telemetry.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/template_engine/cli_commands_audit.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/template_engine/for_developers.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/template_engine/for_platform_engineers.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/template_engine/github_templates.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/template_engine/template_engine.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/toolkit_overview.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/troubleshooting/linux_troubleshooting.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/troubleshooting/macos_troubleshooting.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/troubleshooting/troubleshooting.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/troubleshooting/windows_troubleshooting.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/docs/whats_new.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/mkdocs.yaml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/pyproject.toml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/scripts/check_output_consistency.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/scripts/run_mcp_server.sh +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/application/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/autocomplete.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/analyze.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/apply_fix.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/configure.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/configure_decisions.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/decide.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/history.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/improve.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/orchestrate.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/override.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/report.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/ai_review/commands/serve.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/check/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/check/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/check/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/check/commands/config.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/check/commands/environment.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/check/commands/iac.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/check/commands/project/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/check/commands/project/iac.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/check/commands/project.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/check/commands/space.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/dashboard/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/dashboard/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/dashboard/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/dashboard/commands/launch.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/document/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/document/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/document/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/document/commands/iac.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/generate/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/generate/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/generate/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/generate/commands/component.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/generate/commands/iac.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/generate/commands/stacks.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/init/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/init/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/init/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/init/commands/space.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/init/commands/template.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/inventory/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/inventory/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/inventory/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/inventory/commands/check.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/inventory/commands/iac.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/list/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/list/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/list/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/list/commands/projects.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/list/commands/spaces.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/list/commands/templates.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/mcp/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/mcp/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/mcp/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/mcp/commands/register.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/mcp/commands/server.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/mcp/commands/status.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/mcp/commands/stop.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/project/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/project/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/project/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/project/commands/bootstrap.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/project/commands/cleanup.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/project/commands/convert.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/project/commands/upgrade.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/quickstart/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/quickstart/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/remove/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/remove/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/remove/project.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/remove/space.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/scan/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/scan/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/scan/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/scan/commands/iac.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/space/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/space/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/space/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/space/commands/activate.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/space/commands/deactivate.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/space/commands/export_space.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/space/commands/import_space.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/space/commands/show.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/space/commands/update.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/upgrade/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/workflow/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/workflow/cli.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/workflow/commands/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/workflow/commands/devsecops.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/commands/workflow/commands/run.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/common/.thothcf.setup.toml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/common/.thothcf_home.toml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/common/.thothcf_project.toml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/common/.thothcf_template_parameters.toml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/common/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/common/common.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/common/terragrunt/.thothcf_project.toml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/config/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/config/constants.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/config/default_values.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/config/defaults.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/config/models.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/config/settings.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/config/template_config.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/config/template_configs.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/config/templates.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/config/validation.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/cli_ui.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/commands.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/config.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/azure_devops/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/azure_devops/get_azure_devops.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/azure_devops/pull_request_comments.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/github/get_github.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/github/pull_request_comments.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/integrate_messages_services/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/integrate_messages_services/microsoft_teams.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/integrate_messages_services/sent_message_teams.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/pattern_names.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/pr_comments/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/integrations/pr_comments/pr_comment_publisher.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/logger.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/telemetry.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/core/version_tools.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/domain/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/domain/interfaces/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/domain/models/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/mcp/README.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/mcp/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/mcp/server.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/agentcore/agentcore.json +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/ai_agent.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/analyzers/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/analyzers/code_reviewer.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/analyzers/context_builder.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/analyzers/report_analyzer.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/analyzers/risk_assessor.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/bedrock_agent_api.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/config/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/config/ai_settings.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/config/autonomy.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/config/decision_rules.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/decision_engine.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/main.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/memory.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/orchestrator.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/pr_decision_publisher.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/providers/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/providers/azure_provider.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/providers/bedrock_agent_provider.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/providers/bedrock_provider.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/providers/kiro_provider.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/providers/ollama_provider.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/providers/openai_provider.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/safety/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/safety/safety_guard.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/strands_agent.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/tracing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/utils/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/utils/cost_tracker.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/utils/fix_patterns.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/utils/fix_prompts.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/utils/formatters.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/ai_review/utils/prompts.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/environment/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/environment/check_environment.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/org_policy_loader.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/blast_radius_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cfn_blast_radius_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/check_origin_version.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/check_project_structure.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/cost_analyzer.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/models/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/models/cloudformation_mapper.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/models/cost_models.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/aws_pricing_client.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/base_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/apigateway_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/bedrock_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/cloudwatch_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/dynamodb_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/ebs_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/ec2_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/ecr_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/ecs_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/eip_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/eks_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/elb_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/free_resources_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/kms_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/lambda_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/msk_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/rds_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/s3_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/secrets_manager_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/pricing/providers/vpc_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/cost/unified_cost_report.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/drift/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/drift/cfn_drift_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/drift/drift_ai.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/drift/drift_history.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/drift/drift_policy.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/drift/drift_report.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/drift/drift_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/drift/models.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/risk_assessment.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/project/validate_project_structure.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/rule_merger.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/rules_compiler.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/check/stack_optimizer/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/dashboard/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/dashboard/dashboard_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/dashboard/data_loader.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/document/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/document/architecture_renderer.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/document/create_documentation.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/document/files_content.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/document/files_scan.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/document/iac_documentation.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/document/iac_grunt_info.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/document/topology_generator.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_stacks/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_stacks/config_generator.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_stacks/remote_config_generation.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_stacks/stack_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_stacks/templates/terragrunt.hcl.j2 +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_stacks/terragrunt.hcl +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_template/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_template/config.yaml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_template/create_code.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_template/create_component.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_template/create_component_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_template/create_stacks.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_template/create_template.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_template/files_content.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/create_template/github_template_loader.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/code_generator.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/composition_models.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/context_builder.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/generation_history.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/intent_decomposer.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/intent_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/models.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/parameter_resolver.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/plan_runner.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/plan_validator.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/project_assembler.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/prompts.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/scaffold_loader.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/state_resolver.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/generate/intent/validator.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/environment/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/environment/install_tools.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/environment/prerequisite_checker.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/environment/tool_packs.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/project/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/project/project.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/space/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/space/example_space.toml +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/space/export_import.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/space/inheritance.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/space/space.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/init/space/terraform_module_cache.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/cdk_parsers.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/cdk_sbom_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/changelog_parser.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/defectdojo_publisher.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/dtrack_publisher.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/inventory_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/models.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/module_compatibility_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/report_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/schema_compatibility_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/secobserve_publisher.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/terragrunt_parser.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/update_versions.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/inventory/version_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/mcp/README.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/mcp/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/mcp/simple_http_server.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/mcp/stdio_server.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/bootstrap/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/bootstrap/bootstrap_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/cleanup/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/cleanup/clean_project.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/cleanup/clean_space.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/convert/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/convert/conversion_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/convert/post_init.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/convert/project_converter.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/convert/project_defaults.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/convert/set_project_parameters.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/create_terramate/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/create_terramate/create_terramate_stacks.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/create_terramate/detect_changes_stacks.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/create_terramate/manage_terramate_stacks.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/upgrade/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/project/upgrade/upgrade_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/compliance_review.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/import_reports.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/models.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/report_parser.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/sarif_output.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scan_history.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scan_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scanners/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scanners/checkov.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scanners/kics.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scanners/opa.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scanners/scan_reports.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scanners/scanners.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scanners/terraform_compliance.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scanners/tfsec.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/scan/scanners/trivy.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/custom_workflow_engine.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/models.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/phases/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/phases/base.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/phases/build.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/phases/deploy.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/phases/develop.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/phases/monitor.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/phases/plan.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/phases/secure.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/phases/test.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/services/workflow/workflow_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/templates/ai_reports/pr_comment.md +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/templates/reports/inventory_report.html +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/templates/reports/inventory_report.js +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/templates/unified_report_styles.css +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/banner.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/create_compliance_html_reports.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/create_html_reports.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/delete_directory.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/fix_report_styling.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/render_scan_report.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/report_html_utils.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/templates/dashboard.html +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/templates/index_report.html +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/templates/individual_report.html +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/templates/simple_report.html +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/templates/unified_report_styles.css +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/templates/unified_scan_report.html +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/templates/unified_simple_report.html +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/common/templates/xunit_report.html +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/crypto.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/git_changes.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/manage_backend_resources/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/manage_backend_resources/manage_backend_resources.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/modules_ops/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/modules_ops/terraform_module_details.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/modules_ops/terraform_modules_fetcher.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/platform_utils.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/process_hcl/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/process_hcl/analyze_terraform_plan.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/process_hcl/graph_manager.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/process_hcl/graph_terragrunt_dependencies.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/process_hcl/process_terraform_file.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/process_hcl/risk_analyzing_terraform_plan.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/sync_workspaces/__init__.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/sync_workspaces/sync_terraform_workspaces.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/sync_workspaces/sync_terragrunt_workspaces.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/template_loader.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/utils/thoth_colors.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/src/thothctl/wellcome_banner.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/conftest.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_agentcore_entrypoint.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_ai_apply_fix.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_ai_autonomy.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_ai_decision_engine.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_ai_fix_patterns.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_ai_memory.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_ai_orchestrator.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_ai_pr_decision.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_ai_safety_guard.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_aws_pricing_client.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_azure_devops_pr_comments.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_bedrock_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_cdk_inventory.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_cdk_language_selection.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_cfn_blast_radius.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_cfn_drift_detection.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_context_steering.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_cost_analyzer.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_cost_models.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_cost_policy_enforcement.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_cost_pr_comments.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_dashboard_loading_fix.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_dashboard_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_defectdojo_publisher.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_drift.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_drift_detection.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_dtrack_publisher.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_ec2_pricing.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_generate_iac_codegen.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_generate_iac_context.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_generate_iac_prompts.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_generate_iac_service.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_generate_iac_validator.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_github_pr_comments.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_iac_cost_integration.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_init_ai_tools.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_init_template_params.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_intent_quick_wins.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_intent_rules_integration.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_inventory_pr_comments.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_kics_scanner.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_kiro_provider.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_mermaid_edge_labels.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_new_cost_providers.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_opa_data_files.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_parallel_scan.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_plan_validation.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_platform_utils.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_pr_comment_publisher.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_provider_source_url_fix.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_provider_versions.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_rules_compiler.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_scan_cfn_support.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_scan_command.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_scan_pr_comments.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_space_command.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_space_management.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_stack_optimizer.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_template_url_fix.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_terragrunt_parser.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_topology_generator.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tests/test_workflow_integration.py +0 -0
- {thothctl-0.30.3 → thothctl-0.31.0}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: thothctl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.31.0
|
|
4
4
|
Summary: A CLI for Developer Control Plane. Accelerate your cloud IaC deployments.
|
|
5
5
|
Project-URL: SourceCode, https://github.com/thothforge/thothctl
|
|
6
6
|
Project-URL: HomePage, https://github.com/thothforge/thothctl
|
|
@@ -30,17 +30,24 @@ class EnvInitCommand(ClickCommand):
|
|
|
30
30
|
operation_system: str,
|
|
31
31
|
project_type: Optional[str] = None,
|
|
32
32
|
with_aidlc: bool = False,
|
|
33
|
+
with_skills: Optional[str] = "all",
|
|
33
34
|
**kwargs,
|
|
34
35
|
) -> None:
|
|
35
36
|
"""Execute environment initialization."""
|
|
36
37
|
if project_type:
|
|
37
|
-
self._init_env_with_pack(
|
|
38
|
+
self._init_env_with_pack(
|
|
39
|
+
operation_system, project_type, with_aidlc, with_skills
|
|
40
|
+
)
|
|
38
41
|
else:
|
|
39
42
|
# Legacy behavior: show all tools for manual selection
|
|
40
43
|
bootstrap_env(so=operation_system)
|
|
41
44
|
|
|
42
45
|
def _init_env_with_pack(
|
|
43
|
-
self,
|
|
46
|
+
self,
|
|
47
|
+
operation_system: str,
|
|
48
|
+
project_type: str,
|
|
49
|
+
with_aidlc: bool = False,
|
|
50
|
+
with_skills: Optional[str] = "all",
|
|
44
51
|
) -> None:
|
|
45
52
|
"""Initialize environment using project-type tool pack."""
|
|
46
53
|
from colorama import Fore
|
|
@@ -162,6 +169,36 @@ class EnvInitCommand(ClickCommand):
|
|
|
162
169
|
# AI-DLC workflow rules (optional)
|
|
163
170
|
self._handle_aidlc_installation(console, project_type, with_aidlc)
|
|
164
171
|
|
|
172
|
+
# AI agent skills (dynamic install from upstream repos)
|
|
173
|
+
self._handle_skills_installation(console, with_skills)
|
|
174
|
+
|
|
175
|
+
def _handle_skills_installation(self, console, with_skills: Optional[str]) -> None:
|
|
176
|
+
"""Dynamically install AI agent skills into ./.kiro/skills/.
|
|
177
|
+
|
|
178
|
+
Skills require Kiro, so only install when a .kiro/ directory exists in the
|
|
179
|
+
current working directory.
|
|
180
|
+
"""
|
|
181
|
+
from ....services.init.environment.install_skills import (
|
|
182
|
+
install_skills,
|
|
183
|
+
resolve_requested_skills,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
names = resolve_requested_skills(with_skills or "")
|
|
187
|
+
if not names:
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
kiro_dir = Path.cwd() / ".kiro"
|
|
191
|
+
if not kiro_dir.exists():
|
|
192
|
+
console.print(
|
|
193
|
+
"[yellow]⏭️ Skipping skill install — no .kiro/ in current "
|
|
194
|
+
"directory (skills require Kiro).[/yellow]"
|
|
195
|
+
)
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
console.print()
|
|
199
|
+
console.print(f"[bold]🧠 Installing skill(s): {', '.join(names)}[/bold]")
|
|
200
|
+
install_skills(names, target_dir=str(Path.cwd()))
|
|
201
|
+
|
|
165
202
|
def _handle_aidlc_installation(
|
|
166
203
|
self, console, project_type: str, with_aidlc: bool
|
|
167
204
|
) -> None:
|
|
@@ -268,4 +305,12 @@ cli = EnvInitCommand.as_click_command(
|
|
|
268
305
|
help="Install AI-DLC workflow rules for Kiro (.kiro/steering/). "
|
|
269
306
|
"Non-interactive; in interactive mode, you'll be prompted.",
|
|
270
307
|
),
|
|
308
|
+
click.option(
|
|
309
|
+
"--with-skills",
|
|
310
|
+
default="all",
|
|
311
|
+
help="Dynamically install AI agent skills from their upstream repos into "
|
|
312
|
+
"./.kiro/skills/ (requires a .kiro/ directory). Defaults to 'all' "
|
|
313
|
+
"distributable skills. Use a comma-separated list (e.g. 'devsecops') to "
|
|
314
|
+
"select, or 'none' to opt out.",
|
|
315
|
+
),
|
|
271
316
|
)
|
|
@@ -93,6 +93,7 @@ class ProjectInitCommand(ClickCommand):
|
|
|
93
93
|
language: str = None,
|
|
94
94
|
ai_tools: Optional[str] = None,
|
|
95
95
|
with_aidlc: bool = False,
|
|
96
|
+
with_skills: Optional[str] = "all",
|
|
96
97
|
**kwargs,
|
|
97
98
|
) -> None:
|
|
98
99
|
"""Execute project initialization"""
|
|
@@ -213,6 +214,23 @@ class ProjectInitCommand(ClickCommand):
|
|
|
213
214
|
|
|
214
215
|
install_aidlc_rules(target_dir=str(project_path))
|
|
215
216
|
|
|
217
|
+
# Dynamically install AI agent skills from their upstream repos.
|
|
218
|
+
# Skills live under .kiro/skills/, so only install when Kiro is kept.
|
|
219
|
+
if with_skills and (project_path / ".kiro").exists():
|
|
220
|
+
from ....services.init.environment.install_skills import (
|
|
221
|
+
install_skills,
|
|
222
|
+
resolve_requested_skills,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
names = resolve_requested_skills(with_skills)
|
|
226
|
+
if names:
|
|
227
|
+
self.ui.print_info(f"🧠 Installing skill(s): {', '.join(names)}")
|
|
228
|
+
install_skills(names, target_dir=str(project_path))
|
|
229
|
+
elif with_skills:
|
|
230
|
+
self.ui.print_warning(
|
|
231
|
+
"Skipping skill install — .kiro/ was not kept (requires Kiro)."
|
|
232
|
+
)
|
|
233
|
+
|
|
216
234
|
self.ui.print_success(f"✨ Project '{project_name}' initialized successfully!")
|
|
217
235
|
|
|
218
236
|
def _select_template(
|
|
@@ -710,4 +728,13 @@ cli = ProjectInitCommand.as_click_command(help="Initialize a new project")(
|
|
|
710
728
|
help="Install AI-DLC workflow rules for Kiro (.kiro/steering/). "
|
|
711
729
|
"Provides structured requirement → design → implementation workflows.",
|
|
712
730
|
),
|
|
731
|
+
click.option(
|
|
732
|
+
"--with-skills",
|
|
733
|
+
default="all",
|
|
734
|
+
help="Dynamically install AI agent skills from their upstream repos into "
|
|
735
|
+
".kiro/skills/ (keeps canonical skills in sync, avoids scaffold drift). "
|
|
736
|
+
"Defaults to 'all' distributable skills. Use a comma-separated list "
|
|
737
|
+
"(e.g. 'devsecops') to select, or 'none' to opt out. Only skills with an "
|
|
738
|
+
"upstream repo are installable; scaffold-bundled skills are left untouched.",
|
|
739
|
+
),
|
|
713
740
|
)
|
|
@@ -431,16 +431,23 @@ class DependencyGraphGenerator:
|
|
|
431
431
|
def _generate_graph(self, directory: Path) -> Optional[str]:
|
|
432
432
|
"""Generate graph using terragrunt.
|
|
433
433
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
434
|
+
To show the COMPLETE dependency DAG (full blast radius) for the stack
|
|
435
|
+
being documented, `terragrunt dag graph` is run from the terragrunt
|
|
436
|
+
project root (where ``root.hcl`` lives). Running from a leaf only
|
|
437
|
+
reports that unit's *direct* dependencies, which hides transitive
|
|
438
|
+
dependencies (dependencies-of-dependencies).
|
|
439
|
+
|
|
440
|
+
The full-project DAG from the root is then filtered down to only the
|
|
441
|
+
nodes reachable from the current stack (its transitive dependency
|
|
442
|
+
closure), so each stack's graph shows its complete hierarchy without
|
|
443
|
+
unrelated sibling stacks.
|
|
438
444
|
"""
|
|
439
|
-
|
|
445
|
+
resolved = directory.resolve()
|
|
446
|
+
run_dir, stack_key = self._compute_run_context(resolved)
|
|
440
447
|
|
|
441
448
|
command = ["terragrunt", "dag", "graph", "--non-interactive"]
|
|
442
449
|
|
|
443
|
-
stdout, stderr, return_code = self.executor.execute(command,
|
|
450
|
+
stdout, stderr, return_code = self.executor.execute(command, run_dir)
|
|
444
451
|
|
|
445
452
|
if return_code != 0:
|
|
446
453
|
self.logger.error("Terragrunt command failed: %s", stderr)
|
|
@@ -454,8 +461,26 @@ class DependencyGraphGenerator:
|
|
|
454
461
|
)
|
|
455
462
|
return None
|
|
456
463
|
|
|
464
|
+
# If we ran from the terragrunt root for a specific stack, filter the
|
|
465
|
+
# full DAG down to that stack's transitive dependency closure.
|
|
466
|
+
if stack_key is not None:
|
|
467
|
+
filtered = self._filter_dag_to_stack(stdout, stack_key)
|
|
468
|
+
if filtered is None:
|
|
469
|
+
# Stack not found in DAG or has no dependencies — nothing to render
|
|
470
|
+
self.logger.debug(
|
|
471
|
+
"Stack %s not found in DAG or has no dependencies", stack_key
|
|
472
|
+
)
|
|
473
|
+
return None
|
|
474
|
+
stdout = filtered
|
|
475
|
+
# Re-check for emptiness after filtering (isolated stack)
|
|
476
|
+
if "->" not in stdout.strip():
|
|
477
|
+
self.logger.debug(
|
|
478
|
+
"Isolated stack %s (no dependencies), skipping graph", stack_key
|
|
479
|
+
)
|
|
480
|
+
return None
|
|
481
|
+
|
|
457
482
|
# Also skip if the only node is "." with no edges (isolated stack)
|
|
458
|
-
if '"."' in
|
|
483
|
+
if '"."' in stdout.strip() and "->" not in stdout.strip():
|
|
459
484
|
self.logger.debug(
|
|
460
485
|
"Isolated stack %s (no dependencies), skipping graph", directory
|
|
461
486
|
)
|
|
@@ -516,6 +541,113 @@ class DependencyGraphGenerator:
|
|
|
516
541
|
current = parent
|
|
517
542
|
return directory
|
|
518
543
|
|
|
544
|
+
def _compute_run_context(self, directory: Path):
|
|
545
|
+
"""Decide where to run `terragrunt dag graph` and which node to focus.
|
|
546
|
+
|
|
547
|
+
Returns a tuple ``(run_dir, stack_key)``:
|
|
548
|
+
- ``run_dir``: directory to run ``terragrunt dag graph`` from.
|
|
549
|
+
- ``stack_key``: the current stack's node key as it appears in the DAG
|
|
550
|
+
produced from ``run_dir`` (i.e. the stack path relative to the
|
|
551
|
+
terragrunt root), or ``None`` when ``directory`` is itself a
|
|
552
|
+
stacks root and the full DAG should be rendered as-is.
|
|
553
|
+
|
|
554
|
+
For a leaf stack we run from the terragrunt root so the DAG includes
|
|
555
|
+
transitive dependencies, then filter to this stack's closure.
|
|
556
|
+
"""
|
|
557
|
+
resolved = directory.resolve()
|
|
558
|
+
|
|
559
|
+
# Is this directory itself a stacks root (has multiple child units)?
|
|
560
|
+
child_hcl_files = [
|
|
561
|
+
f
|
|
562
|
+
for f in resolved.rglob("terragrunt.hcl")
|
|
563
|
+
if ".terragrunt-cache" not in str(f) and f.parent != resolved
|
|
564
|
+
]
|
|
565
|
+
if len(child_hcl_files) > 1:
|
|
566
|
+
# Already a root/aggregate context — render the full DAG as-is.
|
|
567
|
+
return resolved, None
|
|
568
|
+
|
|
569
|
+
# Leaf stack: run from the terragrunt root for the complete DAG.
|
|
570
|
+
root = self._find_terragrunt_root(resolved)
|
|
571
|
+
if root == resolved:
|
|
572
|
+
# No root.hcl found above — fall back to running from the leaf.
|
|
573
|
+
return resolved, None
|
|
574
|
+
|
|
575
|
+
try:
|
|
576
|
+
stack_key = str(resolved.relative_to(root))
|
|
577
|
+
except ValueError:
|
|
578
|
+
# resolved is not under root — fall back to leaf behavior.
|
|
579
|
+
return resolved, None
|
|
580
|
+
|
|
581
|
+
return root, stack_key
|
|
582
|
+
|
|
583
|
+
def _filter_dag_to_stack(self, dot_content: str, stack_key: str):
|
|
584
|
+
"""Filter a full-project DAG to a stack's transitive dependency closure.
|
|
585
|
+
|
|
586
|
+
Parses the DOT graph, performs a DFS from ``stack_key`` following
|
|
587
|
+
dependency edges, and emits a new DOT containing only the reachable
|
|
588
|
+
nodes/edges. The focal stack's node is relabeled to ``"."`` so the
|
|
589
|
+
downstream path-simplification (which maps ``"."`` to the stack name)
|
|
590
|
+
continues to work.
|
|
591
|
+
|
|
592
|
+
Returns the filtered DOT string, or ``None`` if the stack has no
|
|
593
|
+
node in the graph or no dependency edges.
|
|
594
|
+
"""
|
|
595
|
+
import re
|
|
596
|
+
|
|
597
|
+
# Normalize key (strip any trailing slash)
|
|
598
|
+
stack_key = stack_key.rstrip("/")
|
|
599
|
+
|
|
600
|
+
# Parse edges: source -> target
|
|
601
|
+
adjacency = {}
|
|
602
|
+
all_nodes = set()
|
|
603
|
+
edge_re = re.compile(r'"([^"]+)"\s*->\s*"([^"]+)"')
|
|
604
|
+
node_re = re.compile(r'^\s*"([^"]+)"\s*;')
|
|
605
|
+
for line in dot_content.split("\n"):
|
|
606
|
+
m = edge_re.search(line)
|
|
607
|
+
if m:
|
|
608
|
+
src, dst = m.group(1), m.group(2)
|
|
609
|
+
adjacency.setdefault(src, set()).add(dst)
|
|
610
|
+
all_nodes.add(src)
|
|
611
|
+
all_nodes.add(dst)
|
|
612
|
+
continue
|
|
613
|
+
nm = node_re.match(line)
|
|
614
|
+
if nm:
|
|
615
|
+
all_nodes.add(nm.group(1))
|
|
616
|
+
|
|
617
|
+
if stack_key not in all_nodes:
|
|
618
|
+
return None
|
|
619
|
+
|
|
620
|
+
# DFS from the stack following dependency edges (transitive closure).
|
|
621
|
+
reachable = set()
|
|
622
|
+
stack = [stack_key]
|
|
623
|
+
while stack:
|
|
624
|
+
node = stack.pop()
|
|
625
|
+
if node in reachable:
|
|
626
|
+
continue
|
|
627
|
+
reachable.add(node)
|
|
628
|
+
for nxt in adjacency.get(node, ()): # dependencies of node
|
|
629
|
+
if nxt not in reachable:
|
|
630
|
+
stack.append(nxt)
|
|
631
|
+
|
|
632
|
+
# If the stack has no outgoing dependency edges, there is nothing
|
|
633
|
+
# meaningful to render.
|
|
634
|
+
if not adjacency.get(stack_key):
|
|
635
|
+
return None
|
|
636
|
+
|
|
637
|
+
def relabel(node: str) -> str:
|
|
638
|
+
return "." if node == stack_key else node
|
|
639
|
+
|
|
640
|
+
# Rebuild DOT with only reachable nodes/edges.
|
|
641
|
+
lines = ["digraph {"]
|
|
642
|
+
for node in sorted(reachable):
|
|
643
|
+
lines.append(f'\t"{relabel(node)}" ;')
|
|
644
|
+
for src in sorted(reachable):
|
|
645
|
+
for dst in sorted(adjacency.get(src, ())):
|
|
646
|
+
if dst in reachable:
|
|
647
|
+
lines.append(f'\t"{relabel(src)}" -> "{relabel(dst)}";')
|
|
648
|
+
lines.append("}")
|
|
649
|
+
return "\n".join(lines)
|
|
650
|
+
|
|
519
651
|
def _parse_terragrunt_hcl(self, hcl_path: Path) -> dict:
|
|
520
652
|
"""Parse a terragrunt.hcl file to extract dependency information."""
|
|
521
653
|
import hcl2
|
|
@@ -29,6 +29,7 @@ terraform_template = [
|
|
|
29
29
|
"name": "catalog",
|
|
30
30
|
"contents": [
|
|
31
31
|
{"type": "file", "name": "mkdocs.yaml"},
|
|
32
|
+
{"type": "file", "name": "zensical.toml"},
|
|
32
33
|
{"type": "file", "name": "catalog-info.yaml"},
|
|
33
34
|
{
|
|
34
35
|
"type": "directory",
|
|
@@ -126,6 +127,7 @@ terragrunt_template = [
|
|
|
126
127
|
"name": "catalog",
|
|
127
128
|
"contents": [
|
|
128
129
|
{"type": "file", "name": "mkdocs.yaml"},
|
|
130
|
+
{"type": "file", "name": "zensical.toml"},
|
|
129
131
|
{"type": "file", "name": "catalog-info.yaml"},
|
|
130
132
|
{
|
|
131
133
|
"type": "directory",
|
|
@@ -213,6 +215,7 @@ terraform_module_template = [
|
|
|
213
215
|
"name": "catalog",
|
|
214
216
|
"contents": [
|
|
215
217
|
{"type": "file", "name": "mkdocs.yaml"},
|
|
218
|
+
{"type": "file", "name": "zensical.toml"},
|
|
216
219
|
{"type": "file", "name": "catalog-info.yaml"},
|
|
217
220
|
{
|
|
218
221
|
"type": "directory",
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""Dynamic installation of AI agent skills from upstream Git repositories.
|
|
2
|
+
|
|
3
|
+
Skills are reusable knowledge packages that live under ``.kiro/skills/<name>/``.
|
|
4
|
+
Historically they were baked into every scaffold template, which caused drift
|
|
5
|
+
between a scaffold's embedded copy and the canonical upstream repository.
|
|
6
|
+
|
|
7
|
+
This module installs skills *dynamically* at ``init`` time from their upstream
|
|
8
|
+
GitHub repositories (mirroring ``install_aidlc_rules``), so the canonical repo
|
|
9
|
+
is the single source of truth.
|
|
10
|
+
|
|
11
|
+
Only skills that have a known upstream repository are dynamically installable.
|
|
12
|
+
Skills authored by third parties or carrying scaffold-local modifications
|
|
13
|
+
(e.g. ``terraform-skill``) are intentionally NOT in the registry — they stay
|
|
14
|
+
bundled in the scaffold and are never overwritten by this installer.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import io
|
|
18
|
+
import shutil
|
|
19
|
+
import tempfile
|
|
20
|
+
import zipfile
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import Dict, List, Optional
|
|
23
|
+
|
|
24
|
+
import requests
|
|
25
|
+
from colorama import Fore
|
|
26
|
+
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
# Skill registry
|
|
29
|
+
# ---------------------------------------------------------------------------
|
|
30
|
+
# Maps a skill name to its upstream source. Add an entry here when a skill gets
|
|
31
|
+
# a canonical GitHub repository so it can be installed dynamically.
|
|
32
|
+
#
|
|
33
|
+
# repo : "owner/name" GitHub repository slug.
|
|
34
|
+
# ref : git ref (branch/tag) to download when no release is published.
|
|
35
|
+
# use_release: if True, prefer the latest GitHub release asset/zipball,
|
|
36
|
+
# falling back to ``ref`` when there is no release.
|
|
37
|
+
# subdir : path *inside* the downloaded archive that contains the skill
|
|
38
|
+
# payload (SKILL.md + references/). "" means the archive root.
|
|
39
|
+
#
|
|
40
|
+
# NOTE ON INTENTIONAL OMISSIONS:
|
|
41
|
+
# - terraform-skill → third-party (Anton Babenko), scaffold-local mods; DO NOT auto-install.
|
|
42
|
+
# - thothctl-framework → no upstream repo yet; scaffold-bundled.
|
|
43
|
+
# - iac-versioning-commits → no upstream repo yet; scaffold-bundled.
|
|
44
|
+
SKILL_REGISTRY: Dict[str, Dict] = {
|
|
45
|
+
"devsecops": {
|
|
46
|
+
"repo": "thothforge/thothctl-devsecops-skill",
|
|
47
|
+
"ref": "main",
|
|
48
|
+
"use_release": True,
|
|
49
|
+
"subdir": "",
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def available_skills() -> List[str]:
|
|
55
|
+
"""Return the names of skills that can be installed dynamically."""
|
|
56
|
+
return sorted(SKILL_REGISTRY.keys())
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _resolve_zip_url(repo: str, ref: str, use_release: bool) -> Optional[str]:
|
|
60
|
+
"""Resolve a downloadable zip URL for a repo.
|
|
61
|
+
|
|
62
|
+
Prefers the latest release when ``use_release`` is set and a release exists;
|
|
63
|
+
otherwise falls back to the branch/tag zipball.
|
|
64
|
+
"""
|
|
65
|
+
if use_release:
|
|
66
|
+
api_url = f"https://api.github.com/repos/{repo}/releases/latest"
|
|
67
|
+
try:
|
|
68
|
+
resp = requests.get(api_url, timeout=30)
|
|
69
|
+
if resp.status_code == 200:
|
|
70
|
+
data = resp.json()
|
|
71
|
+
for asset in data.get("assets", []):
|
|
72
|
+
if asset.get("name", "").endswith(".zip"):
|
|
73
|
+
return asset["browser_download_url"]
|
|
74
|
+
if data.get("zipball_url"):
|
|
75
|
+
return data["zipball_url"]
|
|
76
|
+
except requests.RequestException:
|
|
77
|
+
# Fall through to branch zipball.
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
# Branch/tag zipball (works even without any published release).
|
|
81
|
+
return f"https://api.github.com/repos/{repo}/zipball/{ref}"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _find_skill_payload(extract_root: Path, subdir: str) -> Optional[Path]:
|
|
85
|
+
"""Locate the directory holding SKILL.md inside an extracted archive.
|
|
86
|
+
|
|
87
|
+
GitHub zipballs wrap everything in a single top-level ``<owner>-<repo>-<sha>/``
|
|
88
|
+
directory, so we search for SKILL.md rather than assuming a fixed depth.
|
|
89
|
+
"""
|
|
90
|
+
# Enter the single wrapper directory produced by GitHub zipballs, if present.
|
|
91
|
+
entries = [p for p in extract_root.iterdir() if p.is_dir()]
|
|
92
|
+
search_root = entries[0] if len(entries) == 1 else extract_root
|
|
93
|
+
|
|
94
|
+
if subdir:
|
|
95
|
+
candidate = search_root / subdir
|
|
96
|
+
return candidate if (candidate / "SKILL.md").exists() else None
|
|
97
|
+
|
|
98
|
+
# subdir == "" → the skill payload is at the archive root.
|
|
99
|
+
if (search_root / "SKILL.md").exists():
|
|
100
|
+
return search_root
|
|
101
|
+
|
|
102
|
+
# Fallback: first directory that directly contains a SKILL.md.
|
|
103
|
+
for skill_md in search_root.rglob("SKILL.md"):
|
|
104
|
+
return skill_md.parent
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def install_skill(skill_name: str, target_dir: str = ".") -> bool:
|
|
109
|
+
"""Install a single skill from its upstream repo into ``.kiro/skills/<name>/``.
|
|
110
|
+
|
|
111
|
+
:param skill_name: Registry key (see ``SKILL_REGISTRY``).
|
|
112
|
+
:param target_dir: Project root directory (where ``.kiro/`` lives).
|
|
113
|
+
:return: True on success, False otherwise.
|
|
114
|
+
"""
|
|
115
|
+
entry = SKILL_REGISTRY.get(skill_name)
|
|
116
|
+
if not entry:
|
|
117
|
+
print(
|
|
118
|
+
f"{Fore.YELLOW}⚠️ Skill '{skill_name}' has no upstream repository; "
|
|
119
|
+
f"skipping dynamic install (it is bundled in the scaffold).{Fore.RESET}"
|
|
120
|
+
)
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
repo = entry["repo"]
|
|
124
|
+
ref = entry.get("ref", "main")
|
|
125
|
+
use_release = entry.get("use_release", False)
|
|
126
|
+
subdir = entry.get("subdir", "")
|
|
127
|
+
|
|
128
|
+
print(f"{Fore.MAGENTA}Installing skill '{skill_name}' from {repo}...{Fore.RESET}")
|
|
129
|
+
|
|
130
|
+
zip_url = _resolve_zip_url(repo, ref, use_release)
|
|
131
|
+
if not zip_url:
|
|
132
|
+
print(f"{Fore.RED}❌ Could not resolve a download URL for {repo}{Fore.RESET}")
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
zip_response = requests.get(zip_url, timeout=60, allow_redirects=True)
|
|
137
|
+
zip_response.raise_for_status()
|
|
138
|
+
|
|
139
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
140
|
+
tmp_path = Path(tmpdir)
|
|
141
|
+
with zipfile.ZipFile(io.BytesIO(zip_response.content)) as zf:
|
|
142
|
+
zf.extractall(tmp_path)
|
|
143
|
+
|
|
144
|
+
payload = _find_skill_payload(tmp_path, subdir)
|
|
145
|
+
if not payload:
|
|
146
|
+
print(
|
|
147
|
+
f"{Fore.RED}❌ Could not find SKILL.md in {repo} "
|
|
148
|
+
f"(subdir='{subdir or '<root>'}'){Fore.RESET}"
|
|
149
|
+
)
|
|
150
|
+
return False
|
|
151
|
+
|
|
152
|
+
dst = Path(target_dir) / ".kiro" / "skills" / skill_name
|
|
153
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
154
|
+
if dst.exists():
|
|
155
|
+
shutil.rmtree(dst)
|
|
156
|
+
# Copy payload contents into .kiro/skills/<skill_name>/
|
|
157
|
+
shutil.copytree(payload, dst)
|
|
158
|
+
# Drop any VCS metadata that may have ridden along.
|
|
159
|
+
for junk in (".git", ".github"):
|
|
160
|
+
junk_path = dst / junk
|
|
161
|
+
if junk_path.exists():
|
|
162
|
+
shutil.rmtree(junk_path, ignore_errors=True)
|
|
163
|
+
|
|
164
|
+
print(
|
|
165
|
+
f"{Fore.GREEN} ✅ Installed skill '{skill_name}' → "
|
|
166
|
+
f".kiro/skills/{skill_name}/{Fore.RESET}"
|
|
167
|
+
)
|
|
168
|
+
return True
|
|
169
|
+
|
|
170
|
+
except requests.RequestException as e:
|
|
171
|
+
print(f"{Fore.RED}❌ Failed to download skill '{skill_name}': {e}{Fore.RESET}")
|
|
172
|
+
return False
|
|
173
|
+
except (zipfile.BadZipFile, OSError) as e:
|
|
174
|
+
print(f"{Fore.RED}❌ Failed to extract skill '{skill_name}': {e}{Fore.RESET}")
|
|
175
|
+
return False
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def install_skills(skill_names: List[str], target_dir: str = ".") -> Dict[str, bool]:
|
|
179
|
+
"""Install multiple skills. Returns a map of skill_name → success."""
|
|
180
|
+
results: Dict[str, bool] = {}
|
|
181
|
+
for name in skill_names:
|
|
182
|
+
results[name] = install_skill(name, target_dir=target_dir)
|
|
183
|
+
return results
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def resolve_requested_skills(requested: str) -> List[str]:
|
|
187
|
+
"""Translate a CLI ``--with-skills`` value into concrete registry names.
|
|
188
|
+
|
|
189
|
+
Accepts:
|
|
190
|
+
- "all" → every skill in the registry
|
|
191
|
+
- "none"/"false"/"off"/"" → nothing (opt-out)
|
|
192
|
+
- "devsecops,foo" → comma-separated explicit list
|
|
193
|
+
Unknown names are warned about and dropped.
|
|
194
|
+
"""
|
|
195
|
+
if not requested:
|
|
196
|
+
return []
|
|
197
|
+
normalized = requested.strip().lower()
|
|
198
|
+
if normalized in ("none", "false", "off", "no"):
|
|
199
|
+
return []
|
|
200
|
+
if normalized == "all":
|
|
201
|
+
return available_skills()
|
|
202
|
+
|
|
203
|
+
names = [n.strip() for n in requested.split(",") if n.strip()]
|
|
204
|
+
valid, unknown = [], []
|
|
205
|
+
for n in names:
|
|
206
|
+
(valid if n in SKILL_REGISTRY else unknown).append(n)
|
|
207
|
+
if unknown:
|
|
208
|
+
print(
|
|
209
|
+
f"{Fore.YELLOW}⚠️ Unknown/undistributable skill(s): {', '.join(unknown)}. "
|
|
210
|
+
f"Available: {', '.join(available_skills())}{Fore.RESET}"
|
|
211
|
+
)
|
|
212
|
+
return valid
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Tests for dynamic skill installation (install_skills)."""
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import zipfile
|
|
5
|
+
from unittest.mock import MagicMock, patch
|
|
6
|
+
|
|
7
|
+
from thothctl.services.init.environment import install_skills
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _make_github_zipball(files: dict) -> bytes:
|
|
11
|
+
"""Build an in-memory zip that mimics a GitHub zipball.
|
|
12
|
+
|
|
13
|
+
GitHub wraps everything under a single top-level ``<owner>-<repo>-<sha>/``
|
|
14
|
+
directory. ``files`` maps archive-relative paths (under that wrapper) to
|
|
15
|
+
their text content.
|
|
16
|
+
"""
|
|
17
|
+
buf = io.BytesIO()
|
|
18
|
+
wrapper = "thothforge-thothctl-devsecops-skill-abc1234"
|
|
19
|
+
with zipfile.ZipFile(buf, "w") as zf:
|
|
20
|
+
for rel, content in files.items():
|
|
21
|
+
zf.writestr(f"{wrapper}/{rel}", content)
|
|
22
|
+
return buf.getvalue()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_resolve_requested_skills_all():
|
|
26
|
+
assert install_skills.resolve_requested_skills("all") == install_skills.available_skills()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_resolve_requested_skills_explicit_and_unknown():
|
|
30
|
+
# Known skill kept, unknown dropped.
|
|
31
|
+
result = install_skills.resolve_requested_skills("devsecops,does-not-exist")
|
|
32
|
+
assert result == ["devsecops"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_resolve_requested_skills_empty():
|
|
36
|
+
assert install_skills.resolve_requested_skills("") == []
|
|
37
|
+
assert install_skills.resolve_requested_skills(None) == []
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_resolve_requested_skills_optout_keywords():
|
|
41
|
+
for word in ("none", "None", "NONE", "false", "off", "no"):
|
|
42
|
+
assert install_skills.resolve_requested_skills(word) == [], word
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_install_skill_unknown_returns_false(tmp_path):
|
|
46
|
+
assert install_skills.install_skill("terraform-skill", target_dir=str(tmp_path)) is False
|
|
47
|
+
# Nothing should have been written.
|
|
48
|
+
assert not (tmp_path / ".kiro").exists()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_install_skill_devsecops_from_zipball(tmp_path):
|
|
52
|
+
"""install_skill downloads, finds SKILL.md, and copies into .kiro/skills/<name>/."""
|
|
53
|
+
zip_bytes = _make_github_zipball(
|
|
54
|
+
{
|
|
55
|
+
"SKILL.md": "# DevSecOps Skill\n",
|
|
56
|
+
"references/sdlc_phases.md": "phases\n",
|
|
57
|
+
"references/command_reference.md": "commands\n",
|
|
58
|
+
# Simulate VCS junk that must be stripped.
|
|
59
|
+
".github/workflows/ci.yml": "ci\n",
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
fake_release = MagicMock()
|
|
64
|
+
fake_release.status_code = 404 # force zipball fallback (no release)
|
|
65
|
+
|
|
66
|
+
fake_zip = MagicMock()
|
|
67
|
+
fake_zip.content = zip_bytes
|
|
68
|
+
fake_zip.raise_for_status = MagicMock()
|
|
69
|
+
|
|
70
|
+
def fake_get(url, *args, **kwargs):
|
|
71
|
+
if "releases/latest" in url:
|
|
72
|
+
return fake_release
|
|
73
|
+
return fake_zip
|
|
74
|
+
|
|
75
|
+
with patch.object(install_skills.requests, "get", side_effect=fake_get):
|
|
76
|
+
ok = install_skills.install_skill("devsecops", target_dir=str(tmp_path))
|
|
77
|
+
|
|
78
|
+
assert ok is True
|
|
79
|
+
dst = tmp_path / ".kiro" / "skills" / "devsecops"
|
|
80
|
+
assert (dst / "SKILL.md").exists()
|
|
81
|
+
assert (dst / "references" / "sdlc_phases.md").exists()
|
|
82
|
+
assert (dst / "references" / "command_reference.md").exists()
|
|
83
|
+
# VCS junk stripped.
|
|
84
|
+
assert not (dst / ".github").exists()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_install_skill_overwrites_existing(tmp_path):
|
|
88
|
+
"""Re-installing replaces a stale copy rather than merging into it."""
|
|
89
|
+
dst = tmp_path / ".kiro" / "skills" / "devsecops"
|
|
90
|
+
dst.mkdir(parents=True)
|
|
91
|
+
(dst / "STALE.md").write_text("old")
|
|
92
|
+
|
|
93
|
+
zip_bytes = _make_github_zipball({"SKILL.md": "# fresh\n"})
|
|
94
|
+
fake_release = MagicMock()
|
|
95
|
+
fake_release.status_code = 404
|
|
96
|
+
fake_zip = MagicMock()
|
|
97
|
+
fake_zip.content = zip_bytes
|
|
98
|
+
fake_zip.raise_for_status = MagicMock()
|
|
99
|
+
|
|
100
|
+
with patch.object(
|
|
101
|
+
install_skills.requests,
|
|
102
|
+
"get",
|
|
103
|
+
side_effect=lambda url, *a, **k: fake_release if "releases/latest" in url else fake_zip,
|
|
104
|
+
):
|
|
105
|
+
ok = install_skills.install_skill("devsecops", target_dir=str(tmp_path))
|
|
106
|
+
|
|
107
|
+
assert ok is True
|
|
108
|
+
assert (dst / "SKILL.md").exists()
|
|
109
|
+
# Stale file from the previous copy must be gone.
|
|
110
|
+
assert not (dst / "STALE.md").exists()
|
|
File without changes
|