icdev 1.0.0__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.
- icdev/__init__.py +18 -0
- icdev/_paths.py +85 -0
- icdev/_version.py +3 -0
- icdev/data/__init__.py +1 -0
- icdev/data/args/__init__.py +1 -0
- icdev/data/args/agent_authority.yaml +61 -0
- icdev/data/args/agent_config.yaml +355 -0
- icdev/data/args/agentic_fitness.yaml +31 -0
- icdev/data/args/ai_governance_config.yaml +137 -0
- icdev/data/args/atlas_critique_config.yaml +66 -0
- icdev/data/args/bedrock_models.yaml +63 -0
- icdev/data/args/cicd_config.yaml +82 -0
- icdev/data/args/classification_config.yaml +232 -0
- icdev/data/args/cli_config.yaml +154 -0
- icdev/data/args/cloud_config.yaml +63 -0
- icdev/data/args/code_pattern_config.yaml +151 -0
- icdev/data/args/code_quality_config.yaml +47 -0
- icdev/data/args/companion_registry.yaml +202 -0
- icdev/data/args/context_config.yaml +82 -0
- icdev/data/args/csp_monitor_config.yaml +268 -0
- icdev/data/args/cui_markings.yaml +35 -0
- icdev/data/args/db_config.yaml +40 -0
- icdev/data/args/deployment_profiles.yaml +248 -0
- icdev/data/args/dev_profile_config.yaml +144 -0
- icdev/data/args/devsecops_config.yaml +286 -0
- icdev/data/args/endpoint_security_config.yaml +137 -0
- icdev/data/args/extension_config.yaml +79 -0
- icdev/data/args/file_access_tiers.yaml +88 -0
- icdev/data/args/framework_registry.yaml +415 -0
- icdev/data/args/innovation_config.yaml +431 -0
- icdev/data/args/installation_manifest.yaml +1087 -0
- icdev/data/args/llm_config.yaml +495 -0
- icdev/data/args/maintenance_config.yaml +55 -0
- icdev/data/args/memory_config.yaml +83 -0
- icdev/data/args/monitoring_config.yaml +127 -0
- icdev/data/args/mosa_config.yaml +190 -0
- icdev/data/args/nlq_config.yaml +35 -0
- icdev/data/args/observability_config.yaml +39 -0
- icdev/data/args/observability_tracing_config.yaml +170 -0
- icdev/data/args/oscal_tools_config.yaml +43 -0
- icdev/data/args/owasp_agentic_config.yaml +171 -0
- icdev/data/args/phase_registry.yaml +618 -0
- icdev/data/args/project_defaults.yaml +235 -0
- icdev/data/args/prompt_chains.yaml +163 -0
- icdev/data/args/resilience_config.yaml +50 -0
- icdev/data/args/ricoas_config.yaml +191 -0
- icdev/data/args/role_personas.yaml +362 -0
- icdev/data/args/scaling_config.yaml +176 -0
- icdev/data/args/security_gates.yaml +685 -0
- icdev/data/args/skill_injection_config.yaml +322 -0
- icdev/data/args/spec_config.yaml +53 -0
- icdev/data/args/supply_chain_config.yaml +76 -0
- icdev/data/args/translation_config.yaml +228 -0
- icdev/data/args/workflow_templates/ato_acceleration.yaml +54 -0
- icdev/data/args/workflow_templates/build_deploy.yaml +63 -0
- icdev/data/args/workflow_templates/full_compliance.yaml +43 -0
- icdev/data/args/workflow_templates/security_hardening.yaml +55 -0
- icdev/data/args/worktree_config.yaml +34 -0
- icdev/data/args/zta_config.yaml +247 -0
- icdev/data/context/__init__.py +1 -0
- icdev/data/context/agent/__init__.py +1 -0
- icdev/data/context/agent/response_schemas/__init__.py +1 -0
- icdev/data/context/agent/response_schemas/debate_position.json +46 -0
- icdev/data/context/agent/response_schemas/fitness_scorecard.json +74 -0
- icdev/data/context/agent/response_schemas/review_decision.json +39 -0
- icdev/data/context/agent/response_schemas/task_decomposition.json +82 -0
- icdev/data/context/agent/response_schemas/veto_decision.json +40 -0
- icdev/data/context/agentic/__init__.py +1 -0
- icdev/data/context/agentic/architecture_patterns.md +269 -0
- icdev/data/context/agentic/capability_registry.yaml +202 -0
- icdev/data/context/agentic/csp_mcp_registry.yaml +280 -0
- icdev/data/context/agentic/fitness_rubric.md +56 -0
- icdev/data/context/agentic/governance_baseline.md +205 -0
- icdev/data/context/ci/__init__.py +1 -0
- icdev/data/context/ci/worktree_templates.json +44 -0
- icdev/data/context/cloud/__init__.py +1 -0
- icdev/data/context/cloud/csp_service_registry.json +739 -0
- icdev/data/context/compliance/__init__.py +1 -0
- icdev/data/context/compliance/atlas_mitigations.json +293 -0
- icdev/data/context/compliance/atlas_techniques.json +833 -0
- icdev/data/context/compliance/cisa_sbd_requirements.json +432 -0
- icdev/data/context/compliance/cjis_security_policy.json +522 -0
- icdev/data/context/compliance/cmmc_practices.json +2494 -0
- icdev/data/context/compliance/cmmc_report_template.md +142 -0
- icdev/data/context/compliance/cnssi_1253_overlay.json +109 -0
- icdev/data/context/compliance/control_crosswalk.json +1914 -0
- icdev/data/context/compliance/control_families/__init__.py +1 -0
- icdev/data/context/compliance/csp_certifications.json +251 -0
- icdev/data/context/compliance/cssp_report_template.md +193 -0
- icdev/data/context/compliance/cui_templates/__init__.py +1 -0
- icdev/data/context/compliance/cui_templates/banner_block.txt +4 -0
- icdev/data/context/compliance/cui_templates/code_header.txt +8 -0
- icdev/data/context/compliance/cui_templates/document_template.md +35 -0
- icdev/data/context/compliance/data_type_framework_map.json +321 -0
- icdev/data/context/compliance/data_type_registry.json +147 -0
- icdev/data/context/compliance/dod_cssp_8530.json +463 -0
- icdev/data/context/compliance/eu_ai_act_annex_iii.json +108 -0
- icdev/data/context/compliance/export_templates/__init__.py +1 -0
- icdev/data/context/compliance/export_templates/emass_controls.csv.j2 +4 -0
- icdev/data/context/compliance/export_templates/evidence_package.md.j2 +39 -0
- icdev/data/context/compliance/export_templates/executive_summary.md.j2 +55 -0
- icdev/data/context/compliance/export_templates/poam_tracking.csv.j2 +4 -0
- icdev/data/context/compliance/fedramp_20x_ksi_schemas.json +133 -0
- icdev/data/context/compliance/fedramp_high_baseline.json +4370 -0
- icdev/data/context/compliance/fedramp_moderate_baseline.json +2183 -0
- icdev/data/context/compliance/fedramp_report_template.md +181 -0
- icdev/data/context/compliance/fips_200_areas.json +362 -0
- icdev/data/context/compliance/gao_ai_accountability.json +262 -0
- icdev/data/context/compliance/hipaa_security_rule.json +720 -0
- icdev/data/context/compliance/hitrust_csf_v11.json +930 -0
- icdev/data/context/compliance/impact_level_profiles.json +251 -0
- icdev/data/context/compliance/incident_response_template.md +1110 -0
- icdev/data/context/compliance/iso27001_2022_controls.json +750 -0
- icdev/data/context/compliance/iso27001_nist_bridge.json +382 -0
- icdev/data/context/compliance/iso42001_controls.json +254 -0
- icdev/data/context/compliance/ivv_checklist_template.md +80 -0
- icdev/data/context/compliance/ivv_report_template.md +116 -0
- icdev/data/context/compliance/ivv_requirements.json +372 -0
- icdev/data/context/compliance/mosa_crosswalk.json +327 -0
- icdev/data/context/compliance/mosa_framework.json +250 -0
- icdev/data/context/compliance/narrative_templates/AC.md.j2 +101 -0
- icdev/data/context/compliance/narrative_templates/AU.md.j2 +106 -0
- icdev/data/context/compliance/narrative_templates/IA.md.j2 +104 -0
- icdev/data/context/compliance/narrative_templates/SC.md.j2 +102 -0
- icdev/data/context/compliance/narrative_templates/SI.md.j2 +111 -0
- icdev/data/context/compliance/narrative_templates/__init__.py +1 -0
- icdev/data/context/compliance/narrative_templates/default.md.j2 +50 -0
- icdev/data/context/compliance/narrative_templates/executive_summary.j2 +27 -0
- icdev/data/context/compliance/narrative_templates/poam_milestone.j2 +19 -0
- icdev/data/context/compliance/narrative_templates/ssp_section.j2 +11 -0
- icdev/data/context/compliance/nist_800_171_controls.json +1552 -0
- icdev/data/context/compliance/nist_800_207_crosswalk.json +399 -0
- icdev/data/context/compliance/nist_800_207_zta.json +258 -0
- icdev/data/context/compliance/nist_800_53.json +324 -0
- icdev/data/context/compliance/nist_ai_600_1_genai.json +326 -0
- icdev/data/context/compliance/nist_ai_rmf.json +206 -0
- icdev/data/context/compliance/nist_sp_800_60_types.json +1667 -0
- icdev/data/context/compliance/omb_m25_21_high_impact_ai.json +248 -0
- icdev/data/context/compliance/omb_m26_04_unbiased_ai.json +262 -0
- icdev/data/context/compliance/owasp_agentic_asi.json +133 -0
- icdev/data/context/compliance/owasp_agentic_threats.json +285 -0
- icdev/data/context/compliance/owasp_llm_top10.json +274 -0
- icdev/data/context/compliance/pci_dss_v4.json +510 -0
- icdev/data/context/compliance/poam_template.md +117 -0
- icdev/data/context/compliance/safeai_controls.json +512 -0
- icdev/data/context/compliance/sbd_report_template.md +77 -0
- icdev/data/context/compliance/siem_config_templates/__init__.py +1 -0
- icdev/data/context/compliance/siem_config_templates/filebeat.yml +213 -0
- icdev/data/context/compliance/siem_config_templates/log_sources.json +208 -0
- icdev/data/context/compliance/soc2_trust_criteria.json +661 -0
- icdev/data/context/compliance/ssp_template.md +432 -0
- icdev/data/context/compliance/stig_templates/__init__.py +1 -0
- icdev/data/context/compliance/stig_templates/webapp_stig.json +139 -0
- icdev/data/context/compliance/xai_requirements.json +108 -0
- icdev/data/context/dashboard/__init__.py +1 -0
- icdev/data/context/dashboard/nlq_examples.json +50 -0
- icdev/data/context/dashboard/schema_descriptions.json +23 -0
- icdev/data/context/integration/__init__.py +1 -0
- icdev/data/context/integration/approval_workflows.json +32 -0
- icdev/data/context/integration/gitlab_field_mappings.json +33 -0
- icdev/data/context/integration/jira_field_mappings.json +32 -0
- icdev/data/context/integration/reqif_export_schema.json +23 -0
- icdev/data/context/integration/servicenow_field_mappings.json +22 -0
- icdev/data/context/languages/__init__.py +1 -0
- icdev/data/context/languages/framework_patterns.json +205 -0
- icdev/data/context/languages/language_registry.json +279 -0
- icdev/data/context/llm/__init__.py +1 -0
- icdev/data/context/llm/example_provider.py +86 -0
- icdev/data/context/mbse/__init__.py +1 -0
- icdev/data/context/mbse/des_report_template.md +162 -0
- icdev/data/context/mbse/des_requirements.json +411 -0
- icdev/data/context/mbse/digital_thread_patterns.json +403 -0
- icdev/data/context/mbse/reqif_schema.json +280 -0
- icdev/data/context/mbse/sysml_element_types.json +432 -0
- icdev/data/context/modernization/__init__.py +1 -0
- icdev/data/context/modernization/db_type_mappings.json +148 -0
- icdev/data/context/modernization/decomposition_patterns.json +284 -0
- icdev/data/context/modernization/framework_migration_patterns.json +359 -0
- icdev/data/context/modernization/migration_report_template.md +168 -0
- icdev/data/context/modernization/seven_rs_catalog.json +369 -0
- icdev/data/context/modernization/version_upgrade_rules.json +279 -0
- icdev/data/context/oscal/NIST_SP-800-53_rev5_catalog.json +254987 -0
- icdev/data/context/oscal/README.md +43 -0
- icdev/data/context/patterns/__init__.py +1 -0
- icdev/data/context/profiles/__init__.py +1 -0
- icdev/data/context/profiles/dod_baseline_v1.yaml +145 -0
- icdev/data/context/profiles/fedramp_baseline_v1.yaml +143 -0
- icdev/data/context/profiles/financial_baseline_v1.yaml +142 -0
- icdev/data/context/profiles/healthcare_baseline_v1.yaml +135 -0
- icdev/data/context/profiles/law_enforcement_v1.yaml +129 -0
- icdev/data/context/profiles/startup_v1.yaml +134 -0
- icdev/data/context/requirements/__init__.py +1 -0
- icdev/data/context/requirements/ambiguity_patterns.json +97 -0
- icdev/data/context/requirements/boundary_impact_rules.json +123 -0
- icdev/data/context/requirements/default_constitutions.json +67 -0
- icdev/data/context/requirements/document_extraction_rules.json +58 -0
- icdev/data/context/requirements/gap_patterns.json +108 -0
- icdev/data/context/requirements/readiness_rubric.json +78 -0
- icdev/data/context/requirements/red_alternative_patterns.json +210 -0
- icdev/data/context/requirements/safe_templates.json +72 -0
- icdev/data/context/requirements/spec_quality_checklist.json +122 -0
- icdev/data/context/simulation/__init__.py +1 -0
- icdev/data/context/simulation/architecture_patterns.json +36 -0
- icdev/data/context/simulation/coa_templates.json +38 -0
- icdev/data/context/simulation/cost_models.json +23 -0
- icdev/data/context/simulation/risk_categories.json +46 -0
- icdev/data/context/supply_chain/__init__.py +1 -0
- icdev/data/context/supply_chain/isa_templates.json +129 -0
- icdev/data/context/supply_chain/nist_800_161_controls.json +247 -0
- icdev/data/context/supply_chain/scrm_risk_matrix.json +147 -0
- icdev/data/context/templates/__init__.py +1 -0
- icdev/data/context/templates/ansible/__init__.py +1 -0
- icdev/data/context/templates/ansible/playbooks/__init__.py +1 -0
- icdev/data/context/templates/ansible/roles/__init__.py +1 -0
- icdev/data/context/templates/gitlab_ci/__init__.py +1 -0
- icdev/data/context/templates/grafana/__init__.py +1 -0
- icdev/data/context/templates/kubernetes/__init__.py +1 -0
- icdev/data/context/templates/project/__init__.py +1 -0
- icdev/data/context/templates/project/api/__init__.py +1 -0
- icdev/data/context/templates/project/cli/__init__.py +1 -0
- icdev/data/context/templates/project/data_pipeline/__init__.py +1 -0
- icdev/data/context/templates/project/iac/__init__.py +1 -0
- icdev/data/context/templates/project/javascript_frontend/__init__.py +1 -0
- icdev/data/context/templates/project/javascript_frontend/src/__init__.py +1 -0
- icdev/data/context/templates/project/javascript_frontend/tests/__init__.py +1 -0
- icdev/data/context/templates/project/microservice/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/src/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/tests/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/tests/features/__init__.py +1 -0
- icdev/data/context/templates/project/python_backend/tests/steps/__init__.py +1 -0
- icdev/data/context/templates/terraform/__init__.py +1 -0
- icdev/data/context/templates/terraform/govcloud_base/__init__.py +1 -0
- icdev/data/context/templates/terraform/modules/__init__.py +1 -0
- icdev/data/context/tone/__init__.py +1 -0
- icdev/data/context/translation/dependency_mappings.json +186 -0
- icdev/data/context/translation/type_mappings.json +149 -0
- icdev/data/docs/README.md +187 -0
- icdev/data/docs/__init__.py +1 -0
- icdev/data/docs/admin/gateway-guide.md +338 -0
- icdev/data/docs/admin/marketplace-guide.md +396 -0
- icdev/data/docs/admin/monitoring-guide.md +509 -0
- icdev/data/docs/architecture/compliance-framework.md +764 -0
- icdev/data/docs/architecture/database-schema.md +689 -0
- icdev/data/docs/architecture/gotcha-framework.md +518 -0
- icdev/data/docs/architecture/multi-agent-system.md +603 -0
- icdev/data/docs/dx/README.md +106 -0
- icdev/data/docs/dx/__init__.py +1 -0
- icdev/data/docs/dx/ci-cd-integration.md +378 -0
- icdev/data/docs/dx/claude-code-guide.md +213 -0
- icdev/data/docs/dx/companion-guide.md +232 -0
- icdev/data/docs/dx/dev-profiles.md +309 -0
- icdev/data/docs/dx/icdev-yaml-spec.md +219 -0
- icdev/data/docs/dx/integration-tiers.md +279 -0
- icdev/data/docs/dx/llm-routing-guide.md +456 -0
- icdev/data/docs/dx/quickstart.md +192 -0
- icdev/data/docs/dx/sdk-reference.md +356 -0
- icdev/data/docs/dx/unified-mcp-setup.md +525 -0
- icdev/data/docs/features/__init__.py +1 -0
- icdev/data/docs/features/phase-01-gotcha-framework.md +249 -0
- icdev/data/docs/features/phase-02-atlas-build-workflow.md +223 -0
- icdev/data/docs/features/phase-03-tdd-bdd-testing.md +261 -0
- icdev/data/docs/features/phase-04-nist-compliance.md +255 -0
- icdev/data/docs/features/phase-05-security-scanning.md +229 -0
- icdev/data/docs/features/phase-06-infrastructure-deployment.md +288 -0
- icdev/data/docs/features/phase-07-code-review-gates.md +276 -0
- icdev/data/docs/features/phase-08-self-healing.md +223 -0
- icdev/data/docs/features/phase-09-monitoring-observability.md +230 -0
- icdev/data/docs/features/phase-10-dashboard-web-ui.md +218 -0
- icdev/data/docs/features/phase-11-multi-agent-architecture.md +272 -0
- icdev/data/docs/features/phase-12-integration-testing.md +228 -0
- icdev/data/docs/features/phase-13-cicd-integration.md +257 -0
- icdev/data/docs/features/phase-14-secure-by-design-ivv.md +240 -0
- icdev/data/docs/features/phase-15-maintenance-audit.md +192 -0
- icdev/data/docs/features/phase-16-ato-acceleration.md +228 -0
- icdev/data/docs/features/phase-17-multi-framework-compliance.md +223 -0
- icdev/data/docs/features/phase-18-mbse-integration.md +242 -0
- icdev/data/docs/features/phase-19-agentic-generation.md +202 -0
- icdev/data/docs/features/phase-20-fips-security-categorization.md +198 -0
- icdev/data/docs/features/phase-21-saas-multi-tenancy.md +273 -0
- icdev/data/docs/features/phase-22-federated-gotcha-marketplace.md +242 -0
- icdev/data/docs/features/phase-23-universal-compliance-platform.md +238 -0
- icdev/data/docs/features/phase-24-devsecops-pipeline-security.md +198 -0
- icdev/data/docs/features/phase-25-zero-trust-architecture.md +220 -0
- icdev/data/docs/features/phase-26-dod-mosa.md +205 -0
- icdev/data/docs/features/phase-27-cli-capabilities.md +222 -0
- icdev/data/docs/features/phase-28-remote-command-gateway.md +235 -0
- icdev/data/docs/features/phase-29-proactive-monitoring.md +212 -0
- icdev/data/docs/features/phase-30-dashboard-auth.md +215 -0
- icdev/data/docs/features/phase-31-dashboard-ux-low-impact.md +188 -0
- icdev/data/docs/features/phase-32-dashboard-ux-medium-impact.md +223 -0
- icdev/data/docs/features/phase-33-modular-installation.md +218 -0
- icdev/data/docs/features/phase-34-dev-profiles.md +239 -0
- icdev/data/docs/features/phase-35-innovation-engine.md +257 -0
- icdev/data/docs/features/phase-36-evolutionary-intelligence.md +351 -0
- icdev/data/docs/features/phase-37-mitre-atlas-integration.md +485 -0
- icdev/data/docs/features/phase-38-cloud-agnostic-architecture.md +1033 -0
- icdev/data/docs/features/phase-39-observability-operations.md +178 -0
- icdev/data/docs/features/phase-40-nlq-compliance-queries.md +176 -0
- icdev/data/docs/features/phase-41-parallel-cicd.md +169 -0
- icdev/data/docs/features/phase-42-framework-planning.md +177 -0
- icdev/data/docs/features/phase-43-cross-language-translation.md +225 -0
- icdev/data/docs/features/phase-44-innovation-adaptation.md +227 -0
- icdev/data/docs/features/phase-45-owasp-agentic-security.md +239 -0
- icdev/data/docs/features/phase-46-observability-traceability-xai.md +240 -0
- icdev/data/docs/features/phase-47-unified-mcp-gateway.md +257 -0
- icdev/data/docs/features/phase-48-ai-transparency.md +203 -0
- icdev/data/docs/features/phase-49-ai-accountability.md +243 -0
- icdev/data/docs/features/phase-50-ai-governance-intake-chat.md +195 -0
- icdev/data/docs/features/phase-51-unified-chat-dashboard.md +240 -0
- icdev/data/docs/features/phase-52-code-intelligence.md +244 -0
- icdev/data/docs/features/phase-53-fedramp-20x-owasp-asi.md +359 -0
- icdev/data/docs/features/phase-54-slsa-swft-orchestration.md +379 -0
- icdev/data/docs/features/phase-55-a2a-v03-mcp-oauth.md +322 -0
- icdev/data/docs/features/phase-56-evidence-lineage.md +352 -0
- icdev/data/docs/features/phase-57-eu-ai-act-iron-bank.md +319 -0
- icdev/data/docs/features/phase-58-creative-engine.md +370 -0
- icdev/data/docs/features/phase-59-govcon-intelligence.md +535 -0
- icdev/data/docs/features/phase-60-cpmp.md +528 -0
- icdev/data/docs/features/phase-61-orchestration-improvements.md +534 -0
- icdev/data/docs/operations/dashboard-guide.md +354 -0
- icdev/data/docs/operations/deployment-guide.md +556 -0
- icdev/data/docs/operations/saas-admin-guide.md +439 -0
- icdev/data/docs/operations/security-operations-guide.md +733 -0
- icdev/data/docs/runbooks/backup-restore.md +412 -0
- icdev/data/docs/runbooks/troubleshooting.md +499 -0
- icdev/data/features/__init__.py +1 -0
- icdev/data/features/cicd_integration.feature +41 -0
- icdev/data/features/compliance_gates.feature +46 -0
- icdev/data/features/dashboard.feature +72 -0
- icdev/data/features/environment.py +25 -0
- icdev/data/features/project_management.feature +32 -0
- icdev/data/features/requirements_intake.feature +42 -0
- icdev/data/features/saas_platform.feature +53 -0
- icdev/data/features/security_scanning.feature +36 -0
- icdev/data/features/steps/__init__.py +1 -0
- icdev/data/features/steps/cicd_steps.py +465 -0
- icdev/data/features/steps/compliance_steps.py +308 -0
- icdev/data/features/steps/dashboard_steps.py +88 -0
- icdev/data/features/steps/project_steps.py +126 -0
- icdev/data/features/steps/requirements_intake_steps.py +689 -0
- icdev/data/features/steps/saas_platform_steps.py +572 -0
- icdev/data/features/steps/security_steps.py +236 -0
- icdev/data/features/steps/testing_steps.py +226 -0
- icdev/data/features/testing_pipeline.feature +42 -0
- icdev/data/goals/__init__.py +1 -0
- icdev/data/goals/agent_management.md +144 -0
- icdev/data/goals/agentic_generation.md +345 -0
- icdev/data/goals/agentic_threat_model.md +309 -0
- icdev/data/goals/ai_accountability.md +90 -0
- icdev/data/goals/ai_governance_intake.md +132 -0
- icdev/data/goals/ai_transparency.md +76 -0
- icdev/data/goals/atlas_integration.md +405 -0
- icdev/data/goals/ato_acceleration.md +139 -0
- icdev/data/goals/boundary_supply_chain.md +206 -0
- icdev/data/goals/build_app.md +544 -0
- icdev/data/goals/cicd_integration.md +86 -0
- icdev/data/goals/claude_dir_maintenance.md +77 -0
- icdev/data/goals/cli_capabilities.md +340 -0
- icdev/data/goals/cloud_agnostic.md +312 -0
- icdev/data/goals/code_intelligence.md +197 -0
- icdev/data/goals/code_review.md +94 -0
- icdev/data/goals/compliance_workflow.md +858 -0
- icdev/data/goals/continuous_harmonization.md +140 -0
- icdev/data/goals/cross_language_translation.md +171 -0
- icdev/data/goals/dashboard.md +142 -0
- icdev/data/goals/deploy_workflow.md +390 -0
- icdev/data/goals/devsecops_workflow.md +408 -0
- icdev/data/goals/evolutionary_intelligence.md +305 -0
- icdev/data/goals/external_integration.md +113 -0
- icdev/data/goals/framework_planning.md +63 -0
- icdev/data/goals/init_project.md +235 -0
- icdev/data/goals/innovation_engine.md +199 -0
- icdev/data/goals/integration_testing.md +189 -0
- icdev/data/goals/maintenance_audit.md +196 -0
- icdev/data/goals/manifest.md +56 -0
- icdev/data/goals/mbse_integration.md +504 -0
- icdev/data/goals/modernization_workflow.md +618 -0
- icdev/data/goals/monitoring.md +126 -0
- icdev/data/goals/mosa_workflow.md +463 -0
- icdev/data/goals/multi_agent_orchestration.md +68 -0
- icdev/data/goals/nlq_compliance.md +63 -0
- icdev/data/goals/observability.md +64 -0
- icdev/data/goals/observability_traceability_xai.md +154 -0
- icdev/data/goals/owasp_agentic_security.md +395 -0
- icdev/data/goals/parallel_cicd.md +61 -0
- icdev/data/goals/requirements_intake.md +213 -0
- icdev/data/goals/sbd_ivv_workflow.md +195 -0
- icdev/data/goals/security_categorization.md +133 -0
- icdev/data/goals/security_scan.md +381 -0
- icdev/data/goals/self_healing.md +120 -0
- icdev/data/goals/simulation_engine.md +111 -0
- icdev/data/goals/tdd_workflow.md +403 -0
- icdev/data/goals/zero_trust_architecture.md +403 -0
- icdev/data/hardprompts/__init__.py +1 -0
- icdev/data/hardprompts/agent/__init__.py +1 -0
- icdev/data/hardprompts/agent/agentic_architect.md +100 -0
- icdev/data/hardprompts/agent/debate_prompt.md +32 -0
- icdev/data/hardprompts/agent/fitness_evaluation.md +48 -0
- icdev/data/hardprompts/agent/governance_review.md +214 -0
- icdev/data/hardprompts/agent/reviewer_prompt.md +34 -0
- icdev/data/hardprompts/agent/skill_design.md +172 -0
- icdev/data/hardprompts/agent/task_decomposition.md +275 -0
- icdev/data/hardprompts/agent/veto_check_prompt.md +33 -0
- icdev/data/hardprompts/architect/__init__.py +1 -0
- icdev/data/hardprompts/architect/api_design.md +283 -0
- icdev/data/hardprompts/architect/data_model.md +277 -0
- icdev/data/hardprompts/architect/system_design.md +180 -0
- icdev/data/hardprompts/builder/__init__.py +1 -0
- icdev/data/hardprompts/builder/code_generation.md +59 -0
- icdev/data/hardprompts/builder/refactor.md +58 -0
- icdev/data/hardprompts/builder/scaffold_project.md +69 -0
- icdev/data/hardprompts/builder/test_generation.md +87 -0
- icdev/data/hardprompts/ci/__init__.py +1 -0
- icdev/data/hardprompts/ci/worktree_setup.md +35 -0
- icdev/data/hardprompts/compliance/__init__.py +1 -0
- icdev/data/hardprompts/compliance/cmmc_assessment.md +63 -0
- icdev/data/hardprompts/compliance/cssp_assessment.md +75 -0
- icdev/data/hardprompts/compliance/cui_marking.md +86 -0
- icdev/data/hardprompts/compliance/fedramp_assessment.md +55 -0
- icdev/data/hardprompts/compliance/ivv_assessment.md +96 -0
- icdev/data/hardprompts/compliance/poam_generation.md +57 -0
- icdev/data/hardprompts/compliance/sbd_assessment.md +101 -0
- icdev/data/hardprompts/compliance/security_categorization.md +74 -0
- icdev/data/hardprompts/compliance/ssp_generation.md +56 -0
- icdev/data/hardprompts/compliance/stig_evaluation.md +63 -0
- icdev/data/hardprompts/dashboard/__init__.py +1 -0
- icdev/data/hardprompts/dashboard/nlq_system_prompt.md +26 -0
- icdev/data/hardprompts/infra/__init__.py +1 -0
- icdev/data/hardprompts/infra/k8s_manifests.md +118 -0
- icdev/data/hardprompts/infra/pipeline_generation.md +160 -0
- icdev/data/hardprompts/infra/terraform_generation.md +92 -0
- icdev/data/hardprompts/integration/__init__.py +1 -0
- icdev/data/hardprompts/integration/approval_review.md +17 -0
- icdev/data/hardprompts/integration/jira_mapping.md +25 -0
- icdev/data/hardprompts/integration/servicenow_mapping.md +14 -0
- icdev/data/hardprompts/knowledge/__init__.py +1 -0
- icdev/data/hardprompts/knowledge/pattern_detection.md +73 -0
- icdev/data/hardprompts/knowledge/recommendation_engine.md +90 -0
- icdev/data/hardprompts/knowledge/root_cause_analysis.md +91 -0
- icdev/data/hardprompts/maintenance/__init__.py +1 -0
- icdev/data/hardprompts/maintenance/maintenance_assessment.md +82 -0
- icdev/data/hardprompts/mbse/__init__.py +1 -0
- icdev/data/hardprompts/mbse/digital_thread.md +67 -0
- icdev/data/hardprompts/mbse/model_import.md +62 -0
- icdev/data/hardprompts/mbse/model_to_code.md +65 -0
- icdev/data/hardprompts/modernization/__init__.py +1 -0
- icdev/data/hardprompts/modernization/legacy_analysis.md +93 -0
- icdev/data/hardprompts/modernization/migration_planning.md +150 -0
- icdev/data/hardprompts/modernization/seven_r_assessment.md +107 -0
- icdev/data/hardprompts/requirements/__init__.py +1 -0
- icdev/data/hardprompts/requirements/bdd_generation.md +35 -0
- icdev/data/hardprompts/requirements/clarification_prioritization.md +29 -0
- icdev/data/hardprompts/requirements/decomposition.md +60 -0
- icdev/data/hardprompts/requirements/document_extraction.md +45 -0
- icdev/data/hardprompts/requirements/gap_detection.md +70 -0
- icdev/data/hardprompts/requirements/intake_conversation.md +101 -0
- icdev/data/hardprompts/requirements/readiness_assessment.md +39 -0
- icdev/data/hardprompts/requirements/spec_quality.md +33 -0
- icdev/data/hardprompts/requirements/traceability_analysis.md +23 -0
- icdev/data/hardprompts/security/__init__.py +1 -0
- icdev/data/hardprompts/security/endpoint_security.md +78 -0
- icdev/data/hardprompts/security/threat_model.md +70 -0
- icdev/data/hardprompts/security/vulnerability_assessment.md +81 -0
- icdev/data/hardprompts/simulation/__init__.py +1 -0
- icdev/data/hardprompts/simulation/architecture_impact.md +27 -0
- icdev/data/hardprompts/simulation/coa_alternative.md +27 -0
- icdev/data/hardprompts/simulation/coa_generation.md +25 -0
- icdev/data/hardprompts/simulation/compliance_impact.md +28 -0
- icdev/data/hardprompts/simulation/cost_estimation.md +33 -0
- icdev/data/hardprompts/simulation/risk_assessment.md +28 -0
- icdev/data/hardprompts/translation/code_translation.md +68 -0
- icdev/data/hardprompts/translation/dependency_suggestion.md +44 -0
- icdev/data/hardprompts/translation/test_translation.md +64 -0
- icdev/data/hardprompts/translation/translation_repair.md +59 -0
- icdev/py.typed +0 -0
- icdev/tools/__init__.py +1 -0
- icdev/tools/_gen_formatter.py +12 -0
- icdev/tools/a2a/__init__.py +1 -0
- icdev/tools/a2a/agent_cards/architect.json +43 -0
- icdev/tools/a2a/agent_cards/builder.json +50 -0
- icdev/tools/a2a/agent_cards/compliance.json +57 -0
- icdev/tools/a2a/agent_cards/devsecops.json +71 -0
- icdev/tools/a2a/agent_cards/infra.json +57 -0
- icdev/tools/a2a/agent_cards/integration.json +57 -0
- icdev/tools/a2a/agent_cards/knowledge.json +43 -0
- icdev/tools/a2a/agent_cards/mbse.json +57 -0
- icdev/tools/a2a/agent_cards/modernization.json +50 -0
- icdev/tools/a2a/agent_cards/monitor.json +43 -0
- icdev/tools/a2a/agent_cards/orchestrator.json +36 -0
- icdev/tools/a2a/agent_cards/requirements_analyst.json +64 -0
- icdev/tools/a2a/agent_cards/security.json +50 -0
- icdev/tools/a2a/agent_cards/simulation.json +57 -0
- icdev/tools/a2a/agent_cards/supply_chain.json +50 -0
- icdev/tools/a2a/agent_client.py +349 -0
- icdev/tools/a2a/agent_registry.py +412 -0
- icdev/tools/a2a/agent_server.py +579 -0
- icdev/tools/a2a/task.py +200 -0
- icdev/tools/agent/__init__.py +2 -0
- icdev/tools/agent/a2a_agent_card_generator.py +285 -0
- icdev/tools/agent/a2a_discovery_server.py +250 -0
- icdev/tools/agent/agent_executor.py +529 -0
- icdev/tools/agent/agent_memory.py +557 -0
- icdev/tools/agent/agent_models.py +51 -0
- icdev/tools/agent/atlas_critique.py +908 -0
- icdev/tools/agent/authority.py +443 -0
- icdev/tools/agent/bedrock_client.py +1075 -0
- icdev/tools/agent/collaboration.py +871 -0
- icdev/tools/agent/dispatcher_mode.py +665 -0
- icdev/tools/agent/mailbox.py +575 -0
- icdev/tools/agent/prompt_chain_executor.py +1064 -0
- icdev/tools/agent/session_purpose.py +350 -0
- icdev/tools/agent/skill_router.py +638 -0
- icdev/tools/agent/skill_selector.py +486 -0
- icdev/tools/agent/team_orchestrator.py +1108 -0
- icdev/tools/agent/token_tracker.py +290 -0
- icdev/tools/analysis/__init__.py +1 -0
- icdev/tools/analysis/code_analyzer.py +780 -0
- icdev/tools/analysis/runtime_feedback.py +389 -0
- icdev/tools/audit/__init__.py +1 -0
- icdev/tools/audit/audit_logger.py +196 -0
- icdev/tools/audit/audit_query.py +157 -0
- icdev/tools/audit/decision_recorder.py +72 -0
- icdev/tools/builder/__init__.py +1 -0
- icdev/tools/builder/agentic_fitness.py +534 -0
- icdev/tools/builder/agentic_test_templates/test_a2a_callback.py +117 -0
- icdev/tools/builder/agentic_test_templates/test_a2a_lifecycle.feature +52 -0
- icdev/tools/builder/agentic_test_templates/test_agent_card.feature +37 -0
- icdev/tools/builder/agentic_test_templates/test_agent_health.py +128 -0
- icdev/tools/builder/agentic_test_templates/test_memory_system.feature +50 -0
- icdev/tools/builder/agentic_test_templates/test_skill_execution.feature +40 -0
- icdev/tools/builder/app_blueprint.py +1583 -0
- icdev/tools/builder/child_app_generator.py +2852 -0
- icdev/tools/builder/claude_md_generator.py +1734 -0
- icdev/tools/builder/code_generator.py +3703 -0
- icdev/tools/builder/db_init_generator.py +1709 -0
- icdev/tools/builder/dev_profile_manager.py +954 -0
- icdev/tools/builder/formatter.py +768 -0
- icdev/tools/builder/goal_adapter.py +592 -0
- icdev/tools/builder/gotcha_validator.py +812 -0
- icdev/tools/builder/language_support.py +441 -0
- icdev/tools/builder/linter.py +976 -0
- icdev/tools/builder/profile_detector.py +657 -0
- icdev/tools/builder/profile_md_generator.py +723 -0
- icdev/tools/builder/scaffolder.py +1590 -0
- icdev/tools/builder/scaffolder_extended.py +1771 -0
- icdev/tools/builder/test_writer.py +950 -0
- icdev/tools/ci/__init__.py +2 -0
- icdev/tools/ci/connectors/__init__.py +2 -0
- icdev/tools/ci/connectors/base_connector.py +80 -0
- icdev/tools/ci/connectors/connector_registry.py +188 -0
- icdev/tools/ci/connectors/mattermost_connector.py +159 -0
- icdev/tools/ci/connectors/slack_connector.py +197 -0
- icdev/tools/ci/core/__init__.py +2 -0
- icdev/tools/ci/core/air_gap_detector.py +115 -0
- icdev/tools/ci/core/comment_handler.py +192 -0
- icdev/tools/ci/core/conversation_manager.py +479 -0
- icdev/tools/ci/core/event_envelope.py +500 -0
- icdev/tools/ci/core/event_router.py +443 -0
- icdev/tools/ci/core/failure_parser.py +397 -0
- icdev/tools/ci/core/recovery_engine.py +527 -0
- icdev/tools/ci/modules/__init__.py +2 -0
- icdev/tools/ci/modules/agent.py +271 -0
- icdev/tools/ci/modules/git_ops.py +175 -0
- icdev/tools/ci/modules/state.py +117 -0
- icdev/tools/ci/modules/vcs.py +303 -0
- icdev/tools/ci/modules/workflow_ops.py +295 -0
- icdev/tools/ci/modules/worktree.py +340 -0
- icdev/tools/ci/pipeline_config_generator.py +558 -0
- icdev/tools/ci/triggers/__init__.py +2 -0
- icdev/tools/ci/triggers/gitlab_task_monitor.py +330 -0
- icdev/tools/ci/triggers/poll_trigger.py +237 -0
- icdev/tools/ci/triggers/webhook_server.py +356 -0
- icdev/tools/ci/workflows/__init__.py +2 -0
- icdev/tools/ci/workflows/icdev_build.py +140 -0
- icdev/tools/ci/workflows/icdev_comply.py +284 -0
- icdev/tools/ci/workflows/icdev_document.py +152 -0
- icdev/tools/ci/workflows/icdev_e2e.py +188 -0
- icdev/tools/ci/workflows/icdev_patch.py +186 -0
- icdev/tools/ci/workflows/icdev_plan.py +202 -0
- icdev/tools/ci/workflows/icdev_plan_build.py +41 -0
- icdev/tools/ci/workflows/icdev_plan_build_test.py +46 -0
- icdev/tools/ci/workflows/icdev_plan_build_test_review.py +47 -0
- icdev/tools/ci/workflows/icdev_review.py +126 -0
- icdev/tools/ci/workflows/icdev_sdlc.py +261 -0
- icdev/tools/ci/workflows/icdev_test.py +240 -0
- icdev/tools/cli/__init__.py +1 -0
- icdev/tools/cli/output_formatter.py +756 -0
- icdev/tools/cli_formatter.py +42 -0
- icdev/tools/cloud/__init__.py +11 -0
- icdev/tools/cloud/cloud_mode_manager.py +364 -0
- icdev/tools/cloud/csp_changelog.py +383 -0
- icdev/tools/cloud/csp_health_checker.py +268 -0
- icdev/tools/cloud/csp_monitor.py +951 -0
- icdev/tools/cloud/iam_provider.py +593 -0
- icdev/tools/cloud/kms_provider.py +346 -0
- icdev/tools/cloud/monitoring_provider.py +628 -0
- icdev/tools/cloud/provider_factory.py +376 -0
- icdev/tools/cloud/region_validator.py +345 -0
- icdev/tools/cloud/registry_provider.py +563 -0
- icdev/tools/cloud/secrets_provider.py +486 -0
- icdev/tools/cloud/storage_provider.py +446 -0
- icdev/tools/compat/__init__.py +21 -0
- icdev/tools/compat/cli_harmonizer.py +251 -0
- icdev/tools/compat/datetime_utils.py +18 -0
- icdev/tools/compat/db_utils.py +160 -0
- icdev/tools/compat/platform_utils.py +123 -0
- icdev/tools/compliance/__init__.py +1 -0
- icdev/tools/compliance/accountability_manager.py +397 -0
- icdev/tools/compliance/ai_accountability_audit.py +294 -0
- icdev/tools/compliance/ai_impact_assessor.py +273 -0
- icdev/tools/compliance/ai_incident_response.py +301 -0
- icdev/tools/compliance/ai_inventory_manager.py +239 -0
- icdev/tools/compliance/ai_reassessment_scheduler.py +256 -0
- icdev/tools/compliance/ai_transparency_audit.py +248 -0
- icdev/tools/compliance/atlas_assessor.py +278 -0
- icdev/tools/compliance/atlas_report_generator.py +1211 -0
- icdev/tools/compliance/base_assessor.py +597 -0
- icdev/tools/compliance/cato_monitor.py +1385 -0
- icdev/tools/compliance/cato_scheduler.py +699 -0
- icdev/tools/compliance/cjis_assessor.py +76 -0
- icdev/tools/compliance/classification_manager.py +1353 -0
- icdev/tools/compliance/cmmc_assessor.py +1491 -0
- icdev/tools/compliance/cmmc_report_generator.py +1100 -0
- icdev/tools/compliance/compliance_detector.py +463 -0
- icdev/tools/compliance/compliance_exporter.py +427 -0
- icdev/tools/compliance/compliance_status.py +825 -0
- icdev/tools/compliance/control_mapper.py +505 -0
- icdev/tools/compliance/crosswalk_engine.py +1203 -0
- icdev/tools/compliance/cssp_assessor.py +1045 -0
- icdev/tools/compliance/cssp_evidence_collector.py +729 -0
- icdev/tools/compliance/cssp_report_generator.py +1116 -0
- icdev/tools/compliance/cui_marker.py +388 -0
- icdev/tools/compliance/diagram_validator.py +600 -0
- icdev/tools/compliance/emass/__init__.py +2 -0
- icdev/tools/compliance/emass/emass_client.py +840 -0
- icdev/tools/compliance/emass/emass_export.py +777 -0
- icdev/tools/compliance/emass/emass_sync.py +826 -0
- icdev/tools/compliance/eu_ai_act_classifier.py +194 -0
- icdev/tools/compliance/evidence_collector.py +468 -0
- icdev/tools/compliance/fairness_assessor.py +316 -0
- icdev/tools/compliance/fedramp_assessor.py +1808 -0
- icdev/tools/compliance/fedramp_authorization_packager.py +137 -0
- icdev/tools/compliance/fedramp_ksi_generator.py +355 -0
- icdev/tools/compliance/fedramp_report_generator.py +1128 -0
- icdev/tools/compliance/fips199_categorizer.py +881 -0
- icdev/tools/compliance/fips200_validator.py +315 -0
- icdev/tools/compliance/gao_ai_assessor.py +231 -0
- icdev/tools/compliance/gao_evidence_builder.py +308 -0
- icdev/tools/compliance/hipaa_assessor.py +78 -0
- icdev/tools/compliance/hitrust_assessor.py +49 -0
- icdev/tools/compliance/incident_response_plan.py +718 -0
- icdev/tools/compliance/iso27001_assessor.py +92 -0
- icdev/tools/compliance/iso42001_assessor.py +114 -0
- icdev/tools/compliance/ivv_assessor.py +2327 -0
- icdev/tools/compliance/ivv_report_generator.py +1662 -0
- icdev/tools/compliance/model_card_generator.py +297 -0
- icdev/tools/compliance/mosa_assessor.py +117 -0
- icdev/tools/compliance/multi_regime_assessor.py +451 -0
- icdev/tools/compliance/narrative_generator.py +1013 -0
- icdev/tools/compliance/nist_800_207_assessor.py +191 -0
- icdev/tools/compliance/nist_ai_600_1_assessor.py +188 -0
- icdev/tools/compliance/nist_ai_rmf_assessor.py +110 -0
- icdev/tools/compliance/nist_lookup.py +245 -0
- icdev/tools/compliance/omb_m25_21_assessor.py +228 -0
- icdev/tools/compliance/omb_m26_04_assessor.py +188 -0
- icdev/tools/compliance/oscal_catalog_adapter.py +395 -0
- icdev/tools/compliance/oscal_generator.py +2170 -0
- icdev/tools/compliance/oscal_tools.py +1182 -0
- icdev/tools/compliance/owasp_agentic_assessor.py +226 -0
- icdev/tools/compliance/owasp_asi_assessor.py +200 -0
- icdev/tools/compliance/owasp_llm_assessor.py +244 -0
- icdev/tools/compliance/pci_dss_assessor.py +80 -0
- icdev/tools/compliance/pi_compliance_tracker.py +1461 -0
- icdev/tools/compliance/poam_generator.py +405 -0
- icdev/tools/compliance/resolve_marking.py +283 -0
- icdev/tools/compliance/sbd_assessor.py +2068 -0
- icdev/tools/compliance/sbd_report_generator.py +1236 -0
- icdev/tools/compliance/sbom_generator.py +1008 -0
- icdev/tools/compliance/siem_config_generator.py +674 -0
- icdev/tools/compliance/slsa_attestation_generator.py +490 -0
- icdev/tools/compliance/soc2_assessor.py +77 -0
- icdev/tools/compliance/ssp_generator.py +573 -0
- icdev/tools/compliance/stig_checker.py +727 -0
- icdev/tools/compliance/swft_evidence_bundler.py +337 -0
- icdev/tools/compliance/system_card_generator.py +309 -0
- icdev/tools/compliance/traceability_matrix.py +1281 -0
- icdev/tools/compliance/universal_classification_manager.py +1172 -0
- icdev/tools/compliance/xacta/__init__.py +2 -0
- icdev/tools/compliance/xacta/xacta_client.py +449 -0
- icdev/tools/compliance/xacta/xacta_export.py +557 -0
- icdev/tools/compliance/xacta/xacta_sync.py +333 -0
- icdev/tools/compliance/xai_assessor.py +231 -0
- icdev/tools/dashboard/__init__.py +1 -0
- icdev/tools/dashboard/api/__init__.py +1 -0
- icdev/tools/dashboard/api/_pipeline_state.py +17 -0
- icdev/tools/dashboard/api/activity.py +206 -0
- icdev/tools/dashboard/api/admin.py +176 -0
- icdev/tools/dashboard/api/agents.py +53 -0
- icdev/tools/dashboard/api/ai_accountability.py +163 -0
- icdev/tools/dashboard/api/ai_transparency.py +198 -0
- icdev/tools/dashboard/api/audit.py +58 -0
- icdev/tools/dashboard/api/batch.py +666 -0
- icdev/tools/dashboard/api/chat.py +241 -0
- icdev/tools/dashboard/api/cicd.py +219 -0
- icdev/tools/dashboard/api/code_quality.py +223 -0
- icdev/tools/dashboard/api/compliance.py +171 -0
- icdev/tools/dashboard/api/cpmp.py +915 -0
- icdev/tools/dashboard/api/diagrams.py +65 -0
- icdev/tools/dashboard/api/events.py +250 -0
- icdev/tools/dashboard/api/evidence.py +99 -0
- icdev/tools/dashboard/api/fedramp_20x.py +77 -0
- icdev/tools/dashboard/api/govcon.py +1095 -0
- icdev/tools/dashboard/api/intake.py +1171 -0
- icdev/tools/dashboard/api/lineage.py +163 -0
- icdev/tools/dashboard/api/metrics.py +155 -0
- icdev/tools/dashboard/api/nlq.py +72 -0
- icdev/tools/dashboard/api/orchestration.py +472 -0
- icdev/tools/dashboard/api/oscal.py +183 -0
- icdev/tools/dashboard/api/prod_audit.py +183 -0
- icdev/tools/dashboard/api/projects.py +191 -0
- icdev/tools/dashboard/api/proposals.py +1084 -0
- icdev/tools/dashboard/api/traces.py +363 -0
- icdev/tools/dashboard/api/usage.py +234 -0
- icdev/tools/dashboard/app.py +1986 -0
- icdev/tools/dashboard/auth.py +500 -0
- icdev/tools/dashboard/byok.py +245 -0
- icdev/tools/dashboard/chat_manager.py +675 -0
- icdev/tools/dashboard/config.py +116 -0
- icdev/tools/dashboard/diagram_definitions.py +642 -0
- icdev/tools/dashboard/nlq_processor.py +323 -0
- icdev/tools/dashboard/phase_loader.py +136 -0
- icdev/tools/dashboard/sse_manager.py +89 -0
- icdev/tools/dashboard/state_tracker.py +267 -0
- icdev/tools/dashboard/static/css/style.css +706 -0
- icdev/tools/dashboard/static/css/ux.css +2047 -0
- icdev/tools/dashboard/static/js/activity.js +322 -0
- icdev/tools/dashboard/static/js/api.js +161 -0
- icdev/tools/dashboard/static/js/batch.js +814 -0
- icdev/tools/dashboard/static/js/charts.js +618 -0
- icdev/tools/dashboard/static/js/chat.js +1514 -0
- icdev/tools/dashboard/static/js/kanban.js +113 -0
- icdev/tools/dashboard/static/js/live.js +569 -0
- icdev/tools/dashboard/static/js/mermaid-icdev.js +332 -0
- icdev/tools/dashboard/static/js/proposals.js +588 -0
- icdev/tools/dashboard/static/js/shortcuts.js +544 -0
- icdev/tools/dashboard/static/js/tables.js +652 -0
- icdev/tools/dashboard/static/js/tour.js +524 -0
- icdev/tools/dashboard/static/js/ux.js +942 -0
- icdev/tools/dashboard/templates/404.html +10 -0
- icdev/tools/dashboard/templates/activity.html +80 -0
- icdev/tools/dashboard/templates/admin/users.html +144 -0
- icdev/tools/dashboard/templates/ai_accountability.html +235 -0
- icdev/tools/dashboard/templates/ai_transparency.html +263 -0
- icdev/tools/dashboard/templates/base.html +104 -0
- icdev/tools/dashboard/templates/batch.html +23 -0
- icdev/tools/dashboard/templates/chat.html +332 -0
- icdev/tools/dashboard/templates/children.html +149 -0
- icdev/tools/dashboard/templates/cicd.html +253 -0
- icdev/tools/dashboard/templates/code_quality.html +214 -0
- icdev/tools/dashboard/templates/cpmp/cor_detail.html +220 -0
- icdev/tools/dashboard/templates/cpmp/cor_portal.html +91 -0
- icdev/tools/dashboard/templates/cpmp/deliverable_detail.html +197 -0
- icdev/tools/dashboard/templates/cpmp/detail.html +578 -0
- icdev/tools/dashboard/templates/cpmp/portfolio.html +202 -0
- icdev/tools/dashboard/templates/dev_profiles.html +304 -0
- icdev/tools/dashboard/templates/diagrams.html +224 -0
- icdev/tools/dashboard/templates/events/timeline.html +232 -0
- icdev/tools/dashboard/templates/evidence.html +134 -0
- icdev/tools/dashboard/templates/fedramp_20x.html +207 -0
- icdev/tools/dashboard/templates/gateway.html +244 -0
- icdev/tools/dashboard/templates/govcon/capabilities.html +135 -0
- icdev/tools/dashboard/templates/govcon/pipeline.html +214 -0
- icdev/tools/dashboard/templates/govcon/requirements.html +120 -0
- icdev/tools/dashboard/templates/index.html +254 -0
- icdev/tools/dashboard/templates/lineage.html +141 -0
- icdev/tools/dashboard/templates/login.html +51 -0
- icdev/tools/dashboard/templates/monitoring/overview.html +193 -0
- icdev/tools/dashboard/templates/orchestration/dashboard.html +545 -0
- icdev/tools/dashboard/templates/oscal.html +263 -0
- icdev/tools/dashboard/templates/phases.html +150 -0
- icdev/tools/dashboard/templates/prod_audit.html +280 -0
- icdev/tools/dashboard/templates/profile.html +183 -0
- icdev/tools/dashboard/templates/projects/detail.html +583 -0
- icdev/tools/dashboard/templates/projects/list.html +47 -0
- icdev/tools/dashboard/templates/proposals/detail.html +1253 -0
- icdev/tools/dashboard/templates/proposals/list.html +179 -0
- icdev/tools/dashboard/templates/proposals/section_detail.html +193 -0
- icdev/tools/dashboard/templates/provenance.html +181 -0
- icdev/tools/dashboard/templates/query/nlq.html +234 -0
- icdev/tools/dashboard/templates/quick_paths.html +69 -0
- icdev/tools/dashboard/templates/traces.html +155 -0
- icdev/tools/dashboard/templates/translation_detail.html +199 -0
- icdev/tools/dashboard/templates/translations.html +162 -0
- icdev/tools/dashboard/templates/usage.html +225 -0
- icdev/tools/dashboard/templates/wizard.html +539 -0
- icdev/tools/dashboard/templates/xai.html +208 -0
- icdev/tools/dashboard/ux_helpers.py +962 -0
- icdev/tools/dashboard/websocket.py +81 -0
- icdev/tools/db/__init__.py +1 -0
- icdev/tools/db/backup.py +312 -0
- icdev/tools/db/backup_manager.py +832 -0
- icdev/tools/db/init_icdev_db.py +5900 -0
- icdev/tools/db/migrate.py +178 -0
- icdev/tools/db/migration_runner.py +549 -0
- icdev/tools/db/migrations/001_baseline/meta.json +9 -0
- icdev/tools/db/migrations/001_baseline/up.py +68 -0
- icdev/tools/db/migrations/002_memory_enhancements/down.sql +8 -0
- icdev/tools/db/migrations/002_memory_enhancements/meta.json +9 -0
- icdev/tools/db/migrations/002_memory_enhancements/up.py +118 -0
- icdev/tools/db/migrations/003_dev_profiles/meta.json +8 -0
- icdev/tools/db/migrations/003_dev_profiles/up.py +93 -0
- icdev/tools/db/migrations/004_innovation_engine/down.py +19 -0
- icdev/tools/db/migrations/004_innovation_engine/up.py +227 -0
- icdev/tools/db/migrations/005_phase_37_ai_security/down.py +19 -0
- icdev/tools/db/migrations/005_phase_37_ai_security/up.py +258 -0
- icdev/tools/db/migrations/006_phase_36_evolution/down.py +21 -0
- icdev/tools/db/migrations/006_phase_36_evolution/up.py +323 -0
- icdev/tools/db/migrations/007_phase_38_cloud/down.py +14 -0
- icdev/tools/db/migrations/007_phase_38_cloud/up.py +110 -0
- icdev/tools/db/migrations/008_phase36_37_integration/up.py +55 -0
- icdev/tools/db/migrations/__init__.py +2 -0
- icdev/tools/devsecops/__init__.py +2 -0
- icdev/tools/devsecops/attestation_manager.py +458 -0
- icdev/tools/devsecops/network_segmentation_generator.py +614 -0
- icdev/tools/devsecops/pdp_config_generator.py +1256 -0
- icdev/tools/devsecops/pipeline_security_generator.py +484 -0
- icdev/tools/devsecops/policy_generator.py +653 -0
- icdev/tools/devsecops/profile_manager.py +388 -0
- icdev/tools/devsecops/service_mesh_generator.py +1073 -0
- icdev/tools/devsecops/zta_maturity_scorer.py +368 -0
- icdev/tools/devsecops/zta_terraform_generator.py +1303 -0
- icdev/tools/dx/__init__.py +3 -0
- icdev/tools/dx/companion.py +266 -0
- icdev/tools/dx/instruction_generator.py +753 -0
- icdev/tools/dx/mcp_config_generator.py +282 -0
- icdev/tools/dx/skill_translator.py +425 -0
- icdev/tools/dx/tool_detector.py +144 -0
- icdev/tools/extensions/__init__.py +21 -0
- icdev/tools/extensions/builtins/010_ai_governance_chat.py +277 -0
- icdev/tools/extensions/builtins/__init__.py +2 -0
- icdev/tools/extensions/extension_manager.py +455 -0
- icdev/tools/infra/__init__.py +1 -0
- icdev/tools/infra/ansible_generator.py +869 -0
- icdev/tools/infra/dockerfile_generator.py +361 -0
- icdev/tools/infra/infra_status.py +393 -0
- icdev/tools/infra/ironbank_metadata_generator.py +411 -0
- icdev/tools/infra/k8s_generator.py +1002 -0
- icdev/tools/infra/pipeline_generator.py +832 -0
- icdev/tools/infra/rollback.py +400 -0
- icdev/tools/infra/terraform_generator.py +1142 -0
- icdev/tools/infra/terraform_generator_azure.py +1254 -0
- icdev/tools/infra/terraform_generator_gcp.py +953 -0
- icdev/tools/infra/terraform_generator_ibm.py +360 -0
- icdev/tools/infra/terraform_generator_oci.py +919 -0
- icdev/tools/infra/terraform_generator_onprem.py +319 -0
- icdev/tools/innovation/__init__.py +8 -0
- icdev/tools/innovation/competitive_intel.py +492 -0
- icdev/tools/innovation/innovation_manager.py +681 -0
- icdev/tools/innovation/introspective_analyzer.py +774 -0
- icdev/tools/innovation/register_external_patterns.py +440 -0
- icdev/tools/innovation/signal_ranker.py +1038 -0
- icdev/tools/innovation/solution_generator.py +697 -0
- icdev/tools/innovation/standards_monitor.py +466 -0
- icdev/tools/innovation/trend_detector.py +1046 -0
- icdev/tools/innovation/triage_engine.py +1149 -0
- icdev/tools/innovation/web_scanner.py +894 -0
- icdev/tools/installer/__init__.py +1 -0
- icdev/tools/installer/compliance_configurator.py +637 -0
- icdev/tools/installer/installer.py +1711 -0
- icdev/tools/installer/module_registry.py +805 -0
- icdev/tools/installer/platform_setup.py +961 -0
- icdev/tools/integration/__init__.py +2 -0
- icdev/tools/integration/approval_manager.py +561 -0
- icdev/tools/integration/doors_exporter.py +627 -0
- icdev/tools/integration/gitlab_connector.py +784 -0
- icdev/tools/integration/jira_connector.py +774 -0
- icdev/tools/integration/servicenow_connector.py +693 -0
- icdev/tools/knowledge/__init__.py +1 -0
- icdev/tools/knowledge/knowledge_ingest.py +293 -0
- icdev/tools/knowledge/pattern_detector.py +693 -0
- icdev/tools/knowledge/recommendation_engine.py +461 -0
- icdev/tools/knowledge/self_heal_analyzer.py +504 -0
- icdev/tools/llm/__init__.py +72 -0
- icdev/tools/llm/anthropic_provider.py +170 -0
- icdev/tools/llm/azure_openai_provider.py +338 -0
- icdev/tools/llm/bedrock_provider.py +315 -0
- icdev/tools/llm/embedding_provider.py +438 -0
- icdev/tools/llm/gemini_provider.py +381 -0
- icdev/tools/llm/ibm_watsonx_provider.py +232 -0
- icdev/tools/llm/oci_genai_provider.py +462 -0
- icdev/tools/llm/ollama_provider.py +340 -0
- icdev/tools/llm/openai_provider.py +225 -0
- icdev/tools/llm/provider.py +355 -0
- icdev/tools/llm/provider_sdk.py +175 -0
- icdev/tools/llm/router.py +780 -0
- icdev/tools/llm/vertex_ai_provider.py +374 -0
- icdev/tools/maintenance/__init__.py +2 -0
- icdev/tools/maintenance/dependency_scanner.py +1030 -0
- icdev/tools/maintenance/maintenance_auditor.py +815 -0
- icdev/tools/maintenance/remediation_engine.py +966 -0
- icdev/tools/maintenance/vulnerability_checker.py +987 -0
- icdev/tools/mbse/__init__.py +3 -0
- icdev/tools/mbse/des_assessor.py +1186 -0
- icdev/tools/mbse/des_report_generator.py +800 -0
- icdev/tools/mbse/diagram_extractor.py +811 -0
- icdev/tools/mbse/digital_thread.py +1665 -0
- icdev/tools/mbse/model_code_generator.py +1122 -0
- icdev/tools/mbse/model_control_mapper.py +420 -0
- icdev/tools/mbse/pi_model_tracker.py +1093 -0
- icdev/tools/mbse/reqif_parser.py +1483 -0
- icdev/tools/mbse/sync_engine.py +1805 -0
- icdev/tools/mbse/xmi_parser.py +1573 -0
- icdev/tools/mcp/__init__.py +1 -0
- icdev/tools/mcp/base_server.py +535 -0
- icdev/tools/mcp/builder_server.py +725 -0
- icdev/tools/mcp/compliance_server.py +1407 -0
- icdev/tools/mcp/context_indexer.py +199 -0
- icdev/tools/mcp/context_server.py +305 -0
- icdev/tools/mcp/core_server.py +679 -0
- icdev/tools/mcp/devsecops_server.py +432 -0
- icdev/tools/mcp/gap_handlers.py +1079 -0
- icdev/tools/mcp/gateway_server.py +339 -0
- icdev/tools/mcp/generate_registry.py +623 -0
- icdev/tools/mcp/infra_server.py +264 -0
- icdev/tools/mcp/innovation_server.py +316 -0
- icdev/tools/mcp/integration_server.py +527 -0
- icdev/tools/mcp/knowledge_server.py +429 -0
- icdev/tools/mcp/maintenance_server.py +248 -0
- icdev/tools/mcp/marketplace_server.py +499 -0
- icdev/tools/mcp/mbse_server.py +398 -0
- icdev/tools/mcp/modernization_server.py +496 -0
- icdev/tools/mcp/observability_server.py +354 -0
- icdev/tools/mcp/requirements_server.py +415 -0
- icdev/tools/mcp/simulation_server.py +468 -0
- icdev/tools/mcp/standalone/__init__.py +2 -0
- icdev/tools/mcp/standalone/builder.py +59 -0
- icdev/tools/mcp/standalone/compliance.py +59 -0
- icdev/tools/mcp/standalone/core.py +59 -0
- icdev/tools/mcp/standalone/knowledge.py +59 -0
- icdev/tools/mcp/standalone/maintenance.py +59 -0
- icdev/tools/mcp/supply_chain_server.py +476 -0
- icdev/tools/mcp/tool_registry.py +2008 -0
- icdev/tools/mcp/unified_server.py +158 -0
- icdev/tools/memory/__init__.py +2 -0
- icdev/tools/memory/auto_capture.py +347 -0
- icdev/tools/memory/embed_memory.py +158 -0
- icdev/tools/memory/history_compressor.py +334 -0
- icdev/tools/memory/hybrid_search.py +236 -0
- icdev/tools/memory/maintenance_cron.py +289 -0
- icdev/tools/memory/memory_consolidation.py +444 -0
- icdev/tools/memory/memory_db.py +133 -0
- icdev/tools/memory/memory_read.py +102 -0
- icdev/tools/memory/memory_write.py +222 -0
- icdev/tools/memory/semantic_search.py +139 -0
- icdev/tools/memory/time_decay.py +435 -0
- icdev/tools/modernization/__init__.py +3 -0
- icdev/tools/modernization/architecture_extractor.py +734 -0
- icdev/tools/modernization/compliance_bridge.py +1499 -0
- icdev/tools/modernization/db_migration_planner.py +1385 -0
- icdev/tools/modernization/doc_generator.py +1428 -0
- icdev/tools/modernization/framework_migrator.py +1525 -0
- icdev/tools/modernization/legacy_analyzer.py +1948 -0
- icdev/tools/modernization/migration_code_generator.py +1639 -0
- icdev/tools/modernization/migration_report_generator.py +1653 -0
- icdev/tools/modernization/migration_tracker.py +1726 -0
- icdev/tools/modernization/monolith_decomposer.py +1508 -0
- icdev/tools/modernization/seven_r_assessor.py +1658 -0
- icdev/tools/modernization/strangler_fig_manager.py +1705 -0
- icdev/tools/modernization/ui_analyzer.py +771 -0
- icdev/tools/modernization/version_migrator.py +1392 -0
- icdev/tools/monitor/__init__.py +1 -0
- icdev/tools/monitor/alert_correlator.py +495 -0
- icdev/tools/monitor/auto_resolver.py +612 -0
- icdev/tools/monitor/health_checker.py +509 -0
- icdev/tools/monitor/heartbeat_daemon.py +792 -0
- icdev/tools/monitor/log_analyzer.py +516 -0
- icdev/tools/monitor/metric_collector.py +496 -0
- icdev/tools/mosa/__init__.py +10 -0
- icdev/tools/mosa/icd_generator.py +370 -0
- icdev/tools/mosa/modular_design_analyzer.py +683 -0
- icdev/tools/mosa/mosa_code_enforcer.py +349 -0
- icdev/tools/mosa/tsp_generator.py +265 -0
- icdev/tools/observability/__init__.py +100 -0
- icdev/tools/observability/genai_attributes.py +88 -0
- icdev/tools/observability/instrumentation.py +140 -0
- icdev/tools/observability/mlflow_exporter.py +194 -0
- icdev/tools/observability/otel_tracer.py +168 -0
- icdev/tools/observability/provenance/__init__.py +3 -0
- icdev/tools/observability/provenance/prov_recorder.py +324 -0
- icdev/tools/observability/shap/__init__.py +3 -0
- icdev/tools/observability/shap/agent_shap.py +275 -0
- icdev/tools/observability/sqlite_tracer.py +361 -0
- icdev/tools/observability/trace_context.py +205 -0
- icdev/tools/observability/tracer.py +230 -0
- icdev/tools/orchestration/__init__.py +2 -0
- icdev/tools/orchestration/workflow_composer.py +361 -0
- icdev/tools/project/__init__.py +1 -0
- icdev/tools/project/manifest_loader.py +418 -0
- icdev/tools/project/project_create.py +350 -0
- icdev/tools/project/project_list.py +174 -0
- icdev/tools/project/project_scaffold.py +1715 -0
- icdev/tools/project/project_status.py +479 -0
- icdev/tools/project/session_context_builder.py +757 -0
- icdev/tools/project/validate_manifest.py +55 -0
- icdev/tools/registry/__init__.py +10 -0
- icdev/tools/registry/absorption_engine.py +832 -0
- icdev/tools/registry/capability_evaluator.py +668 -0
- icdev/tools/registry/child_registry.py +617 -0
- icdev/tools/registry/cross_pollinator.py +1065 -0
- icdev/tools/registry/genome_manager.py +671 -0
- icdev/tools/registry/learning_collector.py +912 -0
- icdev/tools/registry/propagation_manager.py +942 -0
- icdev/tools/registry/staging_manager.py +742 -0
- icdev/tools/registry/telemetry_collector.py +423 -0
- icdev/tools/requirements/__init__.py +1 -0
- icdev/tools/requirements/ai_governance_scorer.py +208 -0
- icdev/tools/requirements/boundary_analyzer.py +1293 -0
- icdev/tools/requirements/clarification_engine.py +618 -0
- icdev/tools/requirements/complexity_scorer.py +387 -0
- icdev/tools/requirements/consistency_analyzer.py +803 -0
- icdev/tools/requirements/constitution_manager.py +605 -0
- icdev/tools/requirements/decomposition_engine.py +778 -0
- icdev/tools/requirements/document_extractor.py +1016 -0
- icdev/tools/requirements/elicitation_techniques.py +519 -0
- icdev/tools/requirements/gap_detector.py +271 -0
- icdev/tools/requirements/intake_engine.py +2188 -0
- icdev/tools/requirements/prd_generator.py +847 -0
- icdev/tools/requirements/prd_validator.py +595 -0
- icdev/tools/requirements/readiness_scorer.py +313 -0
- icdev/tools/requirements/spec_organizer.py +1029 -0
- icdev/tools/requirements/spec_quality_checker.py +1097 -0
- icdev/tools/requirements/traceability_builder.py +579 -0
- icdev/tools/resilience/__init__.py +34 -0
- icdev/tools/resilience/circuit_breaker.py +340 -0
- icdev/tools/resilience/correlation.py +150 -0
- icdev/tools/resilience/errors.py +81 -0
- icdev/tools/resilience/retry.py +95 -0
- icdev/tools/schemas/__init__.py +27 -0
- icdev/tools/schemas/chat.py +61 -0
- icdev/tools/schemas/compliance.py +56 -0
- icdev/tools/schemas/core.py +85 -0
- icdev/tools/schemas/innovation.py +37 -0
- icdev/tools/schemas/validation.py +109 -0
- icdev/tools/sdk/__init__.py +3 -0
- icdev/tools/sdk/icdev_client.py +218 -0
- icdev/tools/security/__init__.py +1 -0
- icdev/tools/security/agent_output_validator.py +330 -0
- icdev/tools/security/agent_trust_scorer.py +466 -0
- icdev/tools/security/ai_bom_generator.py +725 -0
- icdev/tools/security/ai_telemetry_logger.py +469 -0
- icdev/tools/security/atlas_red_team.py +543 -0
- icdev/tools/security/code_pattern_scanner.py +378 -0
- icdev/tools/security/confabulation_detector.py +271 -0
- icdev/tools/security/container_scanner.py +491 -0
- icdev/tools/security/dependency_auditor.py +944 -0
- icdev/tools/security/endpoint_security_scanner.py +579 -0
- icdev/tools/security/mcp_tool_authorizer.py +243 -0
- icdev/tools/security/prompt_injection_detector.py +737 -0
- icdev/tools/security/sast_runner.py +948 -0
- icdev/tools/security/secret_detector.py +378 -0
- icdev/tools/security/tool_chain_validator.py +357 -0
- icdev/tools/security/vuln_scanner.py +539 -0
- icdev/tools/simulation/__init__.py +2 -0
- icdev/tools/simulation/coa_generator.py +1552 -0
- icdev/tools/simulation/monte_carlo.py +758 -0
- icdev/tools/simulation/scenario_manager.py +1073 -0
- icdev/tools/simulation/simulation_engine.py +1104 -0
- icdev/tools/supply_chain/__init__.py +2 -0
- icdev/tools/supply_chain/cve_triager.py +705 -0
- icdev/tools/supply_chain/dependency_graph.py +645 -0
- icdev/tools/supply_chain/isa_manager.py +540 -0
- icdev/tools/supply_chain/scrm_assessor.py +546 -0
- icdev/tools/testing/__init__.py +2 -0
- icdev/tools/testing/acceptance_validator.py +411 -0
- icdev/tools/testing/claude_dir_validator.py +831 -0
- icdev/tools/testing/data_types.py +199 -0
- icdev/tools/testing/e2e_runner.py +715 -0
- icdev/tools/testing/fuzz_cli.py +306 -0
- icdev/tools/testing/health_check.py +483 -0
- icdev/tools/testing/platform_check.py +143 -0
- icdev/tools/testing/production_audit.py +1862 -0
- icdev/tools/testing/production_remediate.py +804 -0
- icdev/tools/testing/screenshot_validator.py +539 -0
- icdev/tools/testing/smoke_test.py +283 -0
- icdev/tools/testing/test_agent_models.py +117 -0
- icdev/tools/testing/test_orchestrator.py +957 -0
- icdev/tools/testing/utils.py +229 -0
- icdev/tools/translation/__init__.py +17 -0
- icdev/tools/translation/code_translator.py +550 -0
- icdev/tools/translation/dependency_mapper.py +277 -0
- icdev/tools/translation/feature_map.py +395 -0
- icdev/tools/translation/project_assembler.py +439 -0
- icdev/tools/translation/source_extractor.py +609 -0
- icdev/tools/translation/test_translator.py +333 -0
- icdev/tools/translation/translation_manager.py +582 -0
- icdev/tools/translation/translation_validator.py +662 -0
- icdev/tools/translation/type_checker.py +371 -0
- icdev-1.0.0.dist-info/METADATA +868 -0
- icdev-1.0.0.dist-info/RECORD +1105 -0
- icdev-1.0.0.dist-info/WHEEL +5 -0
- icdev-1.0.0.dist-info/entry_points.txt +9 -0
- icdev-1.0.0.dist-info/licenses/LICENSE +254 -0
- icdev-1.0.0.dist-info/licenses/NOTICE +268 -0
- icdev-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,2852 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# CUI // SP-CTI
|
|
3
|
+
# Controlled by: Department of Defense
|
|
4
|
+
# CUI Category: CTI
|
|
5
|
+
# Distribution: D
|
|
6
|
+
# POC: ICDEV System Administrator
|
|
7
|
+
"""Child App Generator - generates mini-ICDEV clone applications from blueprints.
|
|
8
|
+
|
|
9
|
+
This is the core engine for ICDEV Phase 19 agentic app generation. Every child
|
|
10
|
+
app includes the full GOTCHA framework, ATLAS workflow, own agents, memory system,
|
|
11
|
+
and CI/CD — everything except the ability to generate new applications.
|
|
12
|
+
|
|
13
|
+
Decision D21: Copy-and-adapt over template library.
|
|
14
|
+
Decision D28: 3-layer grandchild prevention.
|
|
15
|
+
Decision D29: Port offset for child agents.
|
|
16
|
+
|
|
17
|
+
CLI: python tools/builder/child_app_generator.py --blueprint bp.json --project-path /tmp --name my-app --json
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import json
|
|
22
|
+
import logging
|
|
23
|
+
import os
|
|
24
|
+
import re
|
|
25
|
+
import shutil
|
|
26
|
+
import sqlite3
|
|
27
|
+
import subprocess
|
|
28
|
+
import sys
|
|
29
|
+
import uuid
|
|
30
|
+
from datetime import datetime, timedelta, timezone
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
33
|
+
from icdev._paths import get_project_root
|
|
34
|
+
|
|
35
|
+
BASE_DIR = get_project_root()
|
|
36
|
+
# Use centralized DB path resolution (D152 pattern)
|
|
37
|
+
try:
|
|
38
|
+
from icdev.tools.compat.db_utils import get_icdev_db_path
|
|
39
|
+
DB_PATH = get_icdev_db_path()
|
|
40
|
+
except ImportError:
|
|
41
|
+
DB_PATH = BASE_DIR / "data" / "icdev.db"
|
|
42
|
+
|
|
43
|
+
logger = logging.getLogger("icdev.child_app_generator")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Sister module imports (graceful fallback)
|
|
47
|
+
def _import_sister(module_name, func_name):
|
|
48
|
+
"""Lazy import helper for sister modules."""
|
|
49
|
+
try:
|
|
50
|
+
mod = __import__(f"tools.builder.{module_name}", fromlist=[func_name])
|
|
51
|
+
return getattr(mod, func_name)
|
|
52
|
+
except (ImportError, AttributeError):
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
from icdev.tools.audit.audit_logger import log_event as audit_log_event
|
|
58
|
+
except ImportError:
|
|
59
|
+
def audit_log_event(**kwargs):
|
|
60
|
+
logger.debug("audit_logger unavailable — %s", kwargs.get("action", ""))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _get_child_app_model_config() -> dict:
|
|
64
|
+
"""Get model config for child apps from llm_config.yaml or defaults."""
|
|
65
|
+
try:
|
|
66
|
+
from icdev.tools.llm.router import LLMRouter
|
|
67
|
+
router = LLMRouter()
|
|
68
|
+
_p, model_id, _mc = router.get_provider_for_function("child_app")
|
|
69
|
+
if model_id:
|
|
70
|
+
provider = "bedrock" if "anthropic." in model_id else "openai"
|
|
71
|
+
return {"provider": provider, "model_id": model_id}
|
|
72
|
+
except Exception:
|
|
73
|
+
pass
|
|
74
|
+
return {
|
|
75
|
+
"provider": "bedrock",
|
|
76
|
+
"model_id": "anthropic.claude-sonnet-4-5-20250929-v1:0",
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# ---------------------------------------------------------------------------
|
|
81
|
+
# Constants
|
|
82
|
+
# ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
# ICDEV base ports — used for port remapping
|
|
85
|
+
ICDEV_PORTS = {
|
|
86
|
+
"orchestrator": 8443, "architect": 8444, "builder": 8445,
|
|
87
|
+
"compliance": 8446, "security": 8447, "infrastructure": 8448,
|
|
88
|
+
"knowledge": 8449, "monitor": 8450, "mbse": 8451,
|
|
89
|
+
"modernization": 8452,
|
|
90
|
+
# D-CHILD-1: Enterprise agents
|
|
91
|
+
"requirements_analyst": 8453, "supply_chain": 8454,
|
|
92
|
+
"simulation": 8455, "devsecops_zta": 8457,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# D-CHILD-3: Parent-only directories — never copied to child apps
|
|
96
|
+
PARENT_ONLY_DIRS = {
|
|
97
|
+
"tools/govcon", "tools/saas", "tools/creative", "tools/innovation",
|
|
98
|
+
"tools/marketplace", "tools/translation", "tools/gateway", "tools/rfx",
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# D-CHILD-3: Parent-only Claude Code artifacts — excluded from child inheritance
|
|
102
|
+
PARENT_ONLY_COMMANDS = {"icdev-agentic.md", "icdev-innovate.md", "icdev-translate.md"}
|
|
103
|
+
PARENT_ONLY_SKILLS = {"icdev-innovate", "icdev-market"}
|
|
104
|
+
PARENT_ONLY_E2E = {"saas_portal.md"}
|
|
105
|
+
PARENT_ONLY_TEMPLATES = {"proposals", "cpmp", "govcon", "rfx"}
|
|
106
|
+
PARENT_ONLY_API_MODULES = {"proposals.py", "cpmp.py", "govcon.py"}
|
|
107
|
+
# D-CHILD-10: Parent-only context directories — excluded from bulk context/ copy
|
|
108
|
+
PARENT_ONLY_CONTEXT = {
|
|
109
|
+
"govcon", "marketplace", "translation", "modernization",
|
|
110
|
+
}
|
|
111
|
+
# D-CHILD-10: Parent-only static JS files
|
|
112
|
+
PARENT_ONLY_STATIC_JS = {"proposals.js"}
|
|
113
|
+
# D-CHILD-10: Skill-to-capability mapping — skills excluded when capability is off
|
|
114
|
+
SKILL_CAPABILITY_MAP = {
|
|
115
|
+
"icdev-mbse": "mbse",
|
|
116
|
+
"icdev-modernize": "modernization",
|
|
117
|
+
"icdev-secure": "security",
|
|
118
|
+
"icdev-query": "dashboard",
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Files that MUST NOT be copied to child apps (grandchild prevention D28)
|
|
122
|
+
GENERATION_TOOLS = {
|
|
123
|
+
"agentic_fitness.py", "app_blueprint.py", "child_app_generator.py",
|
|
124
|
+
"claude_md_generator.py", "goal_adapter.py", "db_init_generator.py",
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# Builder tools that ARE safe to copy
|
|
128
|
+
SAFE_BUILDER_TOOLS = {
|
|
129
|
+
"scaffolder.py", "scaffolder_extended.py", "code_generator.py",
|
|
130
|
+
"test_writer.py", "linter.py", "formatter.py", "language_support.py",
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Full directory tree for child apps
|
|
134
|
+
DIRECTORY_TREE = [
|
|
135
|
+
"goals",
|
|
136
|
+
"tools/agent", "tools/a2a", "tools/audit", "tools/memory",
|
|
137
|
+
"tools/knowledge", "tools/monitor", "tools/db", "tools/project",
|
|
138
|
+
"tools/testing", "tools/ci/triggers", "tools/ci/workflows",
|
|
139
|
+
"tools/infra", "tools/maintenance", "tools/mcp", "tools/builder",
|
|
140
|
+
"tools/security", # D-EPSEC-7: security is always-on, not conditional
|
|
141
|
+
"tools/llm", "tools/compat", "tools/cli", # D-CHILD-9: fundamental infra
|
|
142
|
+
"args", "context/agentic", "context/compliance", "context/languages",
|
|
143
|
+
"hardprompts/agent", "hardprompts/security", # D-EPSEC-7
|
|
144
|
+
"memory/logs", "data",
|
|
145
|
+
".claude/commands/e2e", ".tmp",
|
|
146
|
+
"k8s", "docker", "features/steps", "tests",
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
# Conditional directories — only created when capability is enabled
|
|
150
|
+
CONDITIONAL_DIRS = {
|
|
151
|
+
"compliance": [
|
|
152
|
+
"tools/compliance", "tools/compliance/xacta",
|
|
153
|
+
"tools/compliance/emass", "hardprompts/compliance",
|
|
154
|
+
"context/compliance",
|
|
155
|
+
],
|
|
156
|
+
# "security" removed — now always-on via DIRECTORY_TREE (D-EPSEC-7)
|
|
157
|
+
"mbse": ["tools/mbse", "context/mbse", "hardprompts/mbse"],
|
|
158
|
+
"dashboard": [
|
|
159
|
+
"tools/dashboard", "tools/dashboard/templates",
|
|
160
|
+
"tools/dashboard/static", "tools/dashboard/api",
|
|
161
|
+
],
|
|
162
|
+
# D-CHILD-1: Enterprise capability directories
|
|
163
|
+
"ricoas": [
|
|
164
|
+
"tools/requirements", "tools/supply_chain", "tools/simulation",
|
|
165
|
+
"tools/integration", "context/requirements",
|
|
166
|
+
],
|
|
167
|
+
"devsecops_zta": ["tools/devsecops", "context/devsecops"],
|
|
168
|
+
"observability": [
|
|
169
|
+
"tools/observability", "tools/observability/shap",
|
|
170
|
+
"tools/observability/provenance",
|
|
171
|
+
],
|
|
172
|
+
"code_intelligence": ["tools/analysis"],
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# ---------------------------------------------------------------------------
|
|
177
|
+
# Adaptation Functions
|
|
178
|
+
# ---------------------------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
def _apply_adaptations(content: str, adaptations: List[str], blueprint: dict) -> str:
|
|
181
|
+
"""Apply a list of text adaptations to file content."""
|
|
182
|
+
app_name = blueprint["app_name"]
|
|
183
|
+
classification = blueprint.get("classification", "CUI")
|
|
184
|
+
|
|
185
|
+
for adaptation in adaptations:
|
|
186
|
+
if adaptation == "db_rename":
|
|
187
|
+
content = content.replace("icdev.db", f"{app_name}.db")
|
|
188
|
+
content = content.replace("data/icdev.db", f"data/{app_name}.db")
|
|
189
|
+
content = content.replace('"icdev"', f'"{app_name}"')
|
|
190
|
+
|
|
191
|
+
elif adaptation == "port_remap":
|
|
192
|
+
for agent in blueprint.get("agents", []):
|
|
193
|
+
old_port = ICDEV_PORTS.get(agent["name"])
|
|
194
|
+
if old_port:
|
|
195
|
+
content = content.replace(str(old_port), str(agent["port"]))
|
|
196
|
+
|
|
197
|
+
elif adaptation == "app_name_replace":
|
|
198
|
+
# Replace identifiers but preserve CUI header structure
|
|
199
|
+
content = re.sub(
|
|
200
|
+
r'\bICDEV\b', app_name.upper().replace('-', '_'), content)
|
|
201
|
+
content = re.sub(
|
|
202
|
+
r'\bicdev\b', app_name.lower().replace('-', '_'), content)
|
|
203
|
+
|
|
204
|
+
elif adaptation == "bot_identifier_replace":
|
|
205
|
+
bot_id = blueprint.get("cicd_config", {}).get(
|
|
206
|
+
"bot_identifier", f"[{app_name.upper()}-BOT]")
|
|
207
|
+
content = content.replace("[ICDEV-BOT]", bot_id)
|
|
208
|
+
|
|
209
|
+
elif adaptation == "classification_update":
|
|
210
|
+
if classification == "SECRET":
|
|
211
|
+
content = content.replace("CUI // SP-CTI", "SECRET // NOFORN")
|
|
212
|
+
content = content.replace(
|
|
213
|
+
"CUI Category: CTI", "Classification: SECRET")
|
|
214
|
+
|
|
215
|
+
elif adaptation == "impact_level_update":
|
|
216
|
+
impact = blueprint.get("impact_level", "IL4")
|
|
217
|
+
content = re.sub(r'\bIL[2456]\b', impact, content)
|
|
218
|
+
|
|
219
|
+
# Other adaptations: endpoint_remap, agent_filter, goal_filter,
|
|
220
|
+
# selective_copy, tls_cert_path, threshold_adjust are handled
|
|
221
|
+
# at the step level rather than as text replacements.
|
|
222
|
+
|
|
223
|
+
return content
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _copy_and_adapt_file(
|
|
227
|
+
src: Path, dest: Path, adaptations: List[str], blueprint: dict
|
|
228
|
+
) -> bool:
|
|
229
|
+
"""Copy a single file with adaptations applied."""
|
|
230
|
+
try:
|
|
231
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
232
|
+
|
|
233
|
+
# Binary files: copy directly
|
|
234
|
+
if src.suffix in {
|
|
235
|
+
'.pyc', '.so', '.dll', '.png', '.jpg',
|
|
236
|
+
'.gif', '.ico', '.woff', '.woff2',
|
|
237
|
+
}:
|
|
238
|
+
shutil.copy2(src, dest)
|
|
239
|
+
return True
|
|
240
|
+
|
|
241
|
+
# Text files: read, adapt, write
|
|
242
|
+
try:
|
|
243
|
+
content = src.read_text(encoding="utf-8")
|
|
244
|
+
except UnicodeDecodeError:
|
|
245
|
+
shutil.copy2(src, dest)
|
|
246
|
+
return True
|
|
247
|
+
|
|
248
|
+
adapted = _apply_adaptations(content, adaptations, blueprint)
|
|
249
|
+
dest.write_text(adapted, encoding="utf-8")
|
|
250
|
+
return True
|
|
251
|
+
except Exception as e:
|
|
252
|
+
logger.warning("Failed to copy %s -> %s: %s", src, dest, e)
|
|
253
|
+
return False
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _copy_directory(
|
|
257
|
+
src_dir: Path, dest_dir: Path, adaptations: List[str], blueprint: dict,
|
|
258
|
+
exclude_files: Optional[set] = None,
|
|
259
|
+
skip_subdirs: Optional[set] = None,
|
|
260
|
+
) -> Tuple[int, int]:
|
|
261
|
+
"""Copy a directory tree with adaptations. Returns (copied, skipped).
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
skip_subdirs: Set of immediate subdirectory names to skip entirely.
|
|
265
|
+
E.g. {"govcon", "marketplace"} skips context/govcon/*.
|
|
266
|
+
"""
|
|
267
|
+
exclude_files = exclude_files or set()
|
|
268
|
+
skip_subdirs = skip_subdirs or set()
|
|
269
|
+
copied = 0
|
|
270
|
+
skipped = 0
|
|
271
|
+
|
|
272
|
+
if not src_dir.exists():
|
|
273
|
+
logger.warning("Source directory does not exist: %s", src_dir)
|
|
274
|
+
return 0, 0
|
|
275
|
+
|
|
276
|
+
for src_file in sorted(src_dir.rglob("*")):
|
|
277
|
+
if not src_file.is_file():
|
|
278
|
+
continue
|
|
279
|
+
if src_file.name in exclude_files:
|
|
280
|
+
logger.debug("Skipping excluded file: %s", src_file.name)
|
|
281
|
+
skipped += 1
|
|
282
|
+
continue
|
|
283
|
+
if src_file.suffix == '.pyc' or '__pycache__' in str(src_file):
|
|
284
|
+
continue
|
|
285
|
+
# D-CHILD-10: Skip files under parent-only subdirectories
|
|
286
|
+
if skip_subdirs:
|
|
287
|
+
rel_parts = src_file.relative_to(src_dir).parts
|
|
288
|
+
if rel_parts and rel_parts[0] in skip_subdirs:
|
|
289
|
+
logger.debug("Skipping parent-only subdir: %s", rel_parts[0])
|
|
290
|
+
skipped += 1
|
|
291
|
+
continue
|
|
292
|
+
|
|
293
|
+
rel = src_file.relative_to(src_dir)
|
|
294
|
+
dest_file = dest_dir / rel
|
|
295
|
+
|
|
296
|
+
if _copy_and_adapt_file(src_file, dest_file, adaptations, blueprint):
|
|
297
|
+
copied += 1
|
|
298
|
+
else:
|
|
299
|
+
skipped += 1
|
|
300
|
+
|
|
301
|
+
return copied, skipped
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
# ---------------------------------------------------------------------------
|
|
305
|
+
# Step 1: Create Directory Tree
|
|
306
|
+
# ---------------------------------------------------------------------------
|
|
307
|
+
|
|
308
|
+
def step_01_create_directory_tree(child_root: Path, blueprint: dict) -> dict:
|
|
309
|
+
"""Step 1: Create the full GOTCHA directory structure."""
|
|
310
|
+
created_dirs = []
|
|
311
|
+
capabilities = blueprint.get("capabilities", {})
|
|
312
|
+
|
|
313
|
+
# Always-on directories
|
|
314
|
+
for dir_path in DIRECTORY_TREE:
|
|
315
|
+
full_path = child_root / dir_path
|
|
316
|
+
full_path.mkdir(parents=True, exist_ok=True)
|
|
317
|
+
created_dirs.append(str(dir_path))
|
|
318
|
+
|
|
319
|
+
# Conditional directories
|
|
320
|
+
for cap_name, dirs in CONDITIONAL_DIRS.items():
|
|
321
|
+
if capabilities.get(cap_name, False):
|
|
322
|
+
for dir_path in dirs:
|
|
323
|
+
full_path = child_root / dir_path
|
|
324
|
+
full_path.mkdir(parents=True, exist_ok=True)
|
|
325
|
+
created_dirs.append(str(dir_path))
|
|
326
|
+
|
|
327
|
+
logger.info("Step 1: Created %d directories", len(created_dirs))
|
|
328
|
+
return {"directories_created": len(created_dirs), "dirs": created_dirs}
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# ---------------------------------------------------------------------------
|
|
332
|
+
# Step 2: Copy and Adapt Tools
|
|
333
|
+
# ---------------------------------------------------------------------------
|
|
334
|
+
|
|
335
|
+
def step_02_copy_and_adapt_tools(
|
|
336
|
+
child_root: Path, blueprint: dict, icdev_root: Path
|
|
337
|
+
) -> dict:
|
|
338
|
+
"""Step 2: Copy ICDEV tools to child app with adaptations applied."""
|
|
339
|
+
manifest = blueprint.get("file_manifest", [])
|
|
340
|
+
total_copied = 0
|
|
341
|
+
total_skipped = 0
|
|
342
|
+
results = []
|
|
343
|
+
|
|
344
|
+
for entry in manifest:
|
|
345
|
+
source = entry.get("source", "")
|
|
346
|
+
dest = entry.get("dest", source)
|
|
347
|
+
adaptations = entry.get("adaptations", [])
|
|
348
|
+
|
|
349
|
+
# D-CHILD-3: Skip parent-only directories
|
|
350
|
+
if any(source == d or source.startswith(d + "/") for d in PARENT_ONLY_DIRS):
|
|
351
|
+
total_skipped += 1
|
|
352
|
+
results.append({"source": source, "status": "skipped_parent_only"})
|
|
353
|
+
continue
|
|
354
|
+
|
|
355
|
+
src_path = icdev_root / source
|
|
356
|
+
dest_path = child_root / dest
|
|
357
|
+
|
|
358
|
+
if src_path.is_file():
|
|
359
|
+
# Single file copy
|
|
360
|
+
if _copy_and_adapt_file(src_path, dest_path, adaptations, blueprint):
|
|
361
|
+
total_copied += 1
|
|
362
|
+
results.append({"source": source, "status": "copied"})
|
|
363
|
+
else:
|
|
364
|
+
total_skipped += 1
|
|
365
|
+
results.append({"source": source, "status": "skipped"})
|
|
366
|
+
|
|
367
|
+
elif src_path.is_dir():
|
|
368
|
+
# Directory copy with exclusions
|
|
369
|
+
exclude = set()
|
|
370
|
+
|
|
371
|
+
# For tools/builder/, only copy safe tools
|
|
372
|
+
if source == "tools/builder" or source.startswith("tools/builder"):
|
|
373
|
+
exclude = GENERATION_TOOLS
|
|
374
|
+
|
|
375
|
+
# D-CHILD-10: For context/ bulk copy, skip parent-only subdirs
|
|
376
|
+
skip_subdirs: set = set()
|
|
377
|
+
if source.rstrip("/") == "context":
|
|
378
|
+
skip_subdirs = PARENT_ONLY_CONTEXT
|
|
379
|
+
|
|
380
|
+
copied, skipped = _copy_directory(
|
|
381
|
+
src_path, dest_path, adaptations, blueprint,
|
|
382
|
+
exclude_files=exclude,
|
|
383
|
+
skip_subdirs=skip_subdirs,
|
|
384
|
+
)
|
|
385
|
+
total_copied += copied
|
|
386
|
+
total_skipped += skipped
|
|
387
|
+
results.append({
|
|
388
|
+
"source": source, "status": "copied",
|
|
389
|
+
"files_copied": copied, "files_skipped": skipped,
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
else:
|
|
393
|
+
logger.warning(
|
|
394
|
+
"Source not found: %s (entry=%s)", src_path, source)
|
|
395
|
+
results.append({"source": source, "status": "not_found"})
|
|
396
|
+
|
|
397
|
+
logger.info(
|
|
398
|
+
"Step 2: Copied %d files, skipped %d", total_copied, total_skipped)
|
|
399
|
+
return {
|
|
400
|
+
"files_copied": total_copied,
|
|
401
|
+
"files_skipped": total_skipped,
|
|
402
|
+
"entries": results,
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
# ---------------------------------------------------------------------------
|
|
407
|
+
# Step 3: Agent Infrastructure
|
|
408
|
+
# ---------------------------------------------------------------------------
|
|
409
|
+
|
|
410
|
+
def _get_agent_skills(agent_name: str, blueprint: dict) -> list:
|
|
411
|
+
"""Return skills for an agent based on its role.
|
|
412
|
+
|
|
413
|
+
Priority:
|
|
414
|
+
1. Blueprint agent 'skills' field (if provided by the blueprint)
|
|
415
|
+
2. Known ICDEV defaults (orchestrator, architect, builder, etc.)
|
|
416
|
+
3. Auto-generated from the agent's 'role' description
|
|
417
|
+
"""
|
|
418
|
+
# 1. Check blueprint for explicit skills
|
|
419
|
+
for agent in blueprint.get("agents", []):
|
|
420
|
+
if agent.get("name") == agent_name and agent.get("skills"):
|
|
421
|
+
return agent["skills"]
|
|
422
|
+
|
|
423
|
+
# 2. Known ICDEV defaults for standard agents
|
|
424
|
+
skills_map = {
|
|
425
|
+
"orchestrator": [
|
|
426
|
+
{
|
|
427
|
+
"id": "task-dispatch",
|
|
428
|
+
"name": "Task Dispatch",
|
|
429
|
+
"description": "Route tasks to appropriate agents",
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
"id": "workflow-manage",
|
|
433
|
+
"name": "Workflow Management",
|
|
434
|
+
"description": "Manage multi-step workflows",
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
"architect": [
|
|
438
|
+
{
|
|
439
|
+
"id": "system-design",
|
|
440
|
+
"name": "System Design",
|
|
441
|
+
"description": "Design system architecture",
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"id": "atlas-workflow",
|
|
445
|
+
"name": "ATLAS Workflow",
|
|
446
|
+
"description": "Execute ATLAS build phases",
|
|
447
|
+
},
|
|
448
|
+
],
|
|
449
|
+
"builder": [
|
|
450
|
+
{
|
|
451
|
+
"id": "code-generate",
|
|
452
|
+
"name": "Code Generation",
|
|
453
|
+
"description": "Generate code from specs",
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
"id": "tdd-cycle",
|
|
457
|
+
"name": "TDD Cycle",
|
|
458
|
+
"description": "RED-GREEN-REFACTOR cycle",
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
"id": "scaffold",
|
|
462
|
+
"name": "Scaffold",
|
|
463
|
+
"description": "Scaffold new projects",
|
|
464
|
+
},
|
|
465
|
+
],
|
|
466
|
+
"compliance": [
|
|
467
|
+
{
|
|
468
|
+
"id": "ssp-generate",
|
|
469
|
+
"name": "SSP Generation",
|
|
470
|
+
"description": "Generate System Security Plans",
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
"id": "ato-assess",
|
|
474
|
+
"name": "ATO Assessment",
|
|
475
|
+
"description": "Assess ATO readiness",
|
|
476
|
+
},
|
|
477
|
+
],
|
|
478
|
+
"security": [
|
|
479
|
+
{
|
|
480
|
+
"id": "sast-scan",
|
|
481
|
+
"name": "SAST Scan",
|
|
482
|
+
"description": "Static analysis security testing",
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
"id": "dep-audit",
|
|
486
|
+
"name": "Dependency Audit",
|
|
487
|
+
"description": "Audit dependencies for vulns",
|
|
488
|
+
},
|
|
489
|
+
],
|
|
490
|
+
"knowledge": [
|
|
491
|
+
{
|
|
492
|
+
"id": "pattern-detect",
|
|
493
|
+
"name": "Pattern Detection",
|
|
494
|
+
"description": "Detect patterns in failures",
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
"id": "self-heal",
|
|
498
|
+
"name": "Self Heal",
|
|
499
|
+
"description": "Auto-remediate known issues",
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
"monitor": [
|
|
503
|
+
{
|
|
504
|
+
"id": "log-analyze",
|
|
505
|
+
"name": "Log Analysis",
|
|
506
|
+
"description": "Analyze application logs",
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
"id": "health-check",
|
|
510
|
+
"name": "Health Check",
|
|
511
|
+
"description": "Check system health",
|
|
512
|
+
},
|
|
513
|
+
],
|
|
514
|
+
}
|
|
515
|
+
if agent_name in skills_map:
|
|
516
|
+
return skills_map[agent_name]
|
|
517
|
+
|
|
518
|
+
# 3. Auto-generate skills from the agent's role description
|
|
519
|
+
for agent in blueprint.get("agents", []):
|
|
520
|
+
if agent.get("name") == agent_name:
|
|
521
|
+
role = agent.get("role", agent_name)
|
|
522
|
+
return [
|
|
523
|
+
{
|
|
524
|
+
"id": f"{agent_name}-primary",
|
|
525
|
+
"name": role.split(",")[0].strip().title()
|
|
526
|
+
if role else agent_name.title(),
|
|
527
|
+
"description": role or f"{agent_name} agent capabilities",
|
|
528
|
+
},
|
|
529
|
+
]
|
|
530
|
+
return []
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def _generate_agent_config(
|
|
534
|
+
agents: list, app_name: str, blueprint: dict
|
|
535
|
+
) -> str:
|
|
536
|
+
"""Generate agent_config.yaml content."""
|
|
537
|
+
try:
|
|
538
|
+
import yaml
|
|
539
|
+
config = {
|
|
540
|
+
"application": app_name,
|
|
541
|
+
"classification": blueprint.get("classification", "CUI"),
|
|
542
|
+
"agents": {},
|
|
543
|
+
}
|
|
544
|
+
for agent in agents:
|
|
545
|
+
config["agents"][agent["name"]] = {
|
|
546
|
+
"port": agent["port"],
|
|
547
|
+
"role": agent.get("role", ""),
|
|
548
|
+
"health_endpoint": agent.get(
|
|
549
|
+
"health_endpoint",
|
|
550
|
+
f"https://localhost:{agent['port']}/health",
|
|
551
|
+
),
|
|
552
|
+
"tls": {
|
|
553
|
+
"enabled": True,
|
|
554
|
+
"cert_path": (
|
|
555
|
+
f"/etc/ssl/certs/{app_name}-{agent['name']}.crt"
|
|
556
|
+
),
|
|
557
|
+
},
|
|
558
|
+
"model": _get_child_app_model_config(),
|
|
559
|
+
}
|
|
560
|
+
return yaml.dump(config, default_flow_style=False, sort_keys=False)
|
|
561
|
+
except ImportError:
|
|
562
|
+
# Fallback: manual YAML generation
|
|
563
|
+
lines = [
|
|
564
|
+
f"# Agent configuration for {app_name}",
|
|
565
|
+
f"application: {app_name}",
|
|
566
|
+
f"classification: {blueprint.get('classification', 'CUI')}",
|
|
567
|
+
"agents:",
|
|
568
|
+
]
|
|
569
|
+
for agent in agents:
|
|
570
|
+
lines.append(f" {agent['name']}:")
|
|
571
|
+
lines.append(f" port: {agent['port']}")
|
|
572
|
+
lines.append(f" role: \"{agent.get('role', '')}\"")
|
|
573
|
+
lines.append(
|
|
574
|
+
f" health_endpoint: "
|
|
575
|
+
f"\"https://localhost:{agent['port']}/health\""
|
|
576
|
+
)
|
|
577
|
+
return "\n".join(lines) + "\n"
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
def _generate_mcp_stubs(
|
|
581
|
+
mcp_dir: Path, agents: list, app_name: str, blueprint: dict
|
|
582
|
+
) -> int:
|
|
583
|
+
"""Generate MCP server stub files for each agent role."""
|
|
584
|
+
classification = blueprint.get("classification", "CUI")
|
|
585
|
+
cui_line = (
|
|
586
|
+
"SECRET // NOFORN" if classification == "SECRET" else "CUI // SP-CTI"
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
stubs_written = 0
|
|
590
|
+
# Map known ICDEV agent roles to MCP server names
|
|
591
|
+
mcp_map = {
|
|
592
|
+
"orchestrator": "core_server",
|
|
593
|
+
"architect": "core_server", # shared
|
|
594
|
+
"builder": "builder_server",
|
|
595
|
+
"compliance": "compliance_server",
|
|
596
|
+
"security": "security_server",
|
|
597
|
+
"knowledge": "knowledge_server",
|
|
598
|
+
"monitor": "monitor_server",
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
written_servers = set()
|
|
602
|
+
for agent in agents:
|
|
603
|
+
# Use known mapping for standard agents, derive name for custom agents
|
|
604
|
+
server_name = mcp_map.get(
|
|
605
|
+
agent["name"], f"{agent['name']}_server")
|
|
606
|
+
if server_name in written_servers:
|
|
607
|
+
continue
|
|
608
|
+
written_servers.add(server_name)
|
|
609
|
+
|
|
610
|
+
stub_content = (
|
|
611
|
+
f'#!/usr/bin/env python3\n'
|
|
612
|
+
f'# {cui_line}\n'
|
|
613
|
+
f'"""MCP Server: {server_name} for {app_name}\n'
|
|
614
|
+
f'\n'
|
|
615
|
+
f'Provides tool-calling interface for Claude Code integration.\n'
|
|
616
|
+
f'Transport: stdio\n'
|
|
617
|
+
f'"""\n'
|
|
618
|
+
f'\n'
|
|
619
|
+
f'import json\n'
|
|
620
|
+
f'import sys\n'
|
|
621
|
+
f'import logging\n'
|
|
622
|
+
f'\n'
|
|
623
|
+
f'logger = logging.getLogger("{app_name}.mcp.{server_name}")\n'
|
|
624
|
+
f'\n'
|
|
625
|
+
f'\n'
|
|
626
|
+
f'def handle_request(request: dict) -> dict:\n'
|
|
627
|
+
f' """Handle incoming MCP JSON-RPC request."""\n'
|
|
628
|
+
f' method = request.get("method", "")\n'
|
|
629
|
+
f' params = request.get("params", {{}})\n'
|
|
630
|
+
f' request_id = request.get("id")\n'
|
|
631
|
+
f'\n'
|
|
632
|
+
f' # Tool dispatch based on method\n'
|
|
633
|
+
f' handlers = {{}} # Populated by tool registration\n'
|
|
634
|
+
f'\n'
|
|
635
|
+
f' handler = handlers.get(method)\n'
|
|
636
|
+
f' if handler:\n'
|
|
637
|
+
f' try:\n'
|
|
638
|
+
f' result = handler(params)\n'
|
|
639
|
+
f' return {{"jsonrpc": "2.0", "id": request_id, "result": result}}\n'
|
|
640
|
+
f' except Exception as e:\n'
|
|
641
|
+
f' return {{\n'
|
|
642
|
+
f' "jsonrpc": "2.0", "id": request_id,\n'
|
|
643
|
+
f' "error": {{"code": -32603, "message": str(e)}},\n'
|
|
644
|
+
f' }}\n'
|
|
645
|
+
f'\n'
|
|
646
|
+
f' return {{\n'
|
|
647
|
+
f' "jsonrpc": "2.0", "id": request_id,\n'
|
|
648
|
+
f' "error": {{"code": -32601, "message": f"Method not found: {{method}}"}},\n'
|
|
649
|
+
f' }}\n'
|
|
650
|
+
f'\n'
|
|
651
|
+
f'\n'
|
|
652
|
+
f'def main():\n'
|
|
653
|
+
f' """Run MCP server in stdio mode."""\n'
|
|
654
|
+
f' logger.info("Starting {server_name} MCP server for {app_name}")\n'
|
|
655
|
+
f' for line in sys.stdin:\n'
|
|
656
|
+
f' line = line.strip()\n'
|
|
657
|
+
f' if not line:\n'
|
|
658
|
+
f' continue\n'
|
|
659
|
+
f' try:\n'
|
|
660
|
+
f' request = json.loads(line)\n'
|
|
661
|
+
f' response = handle_request(request)\n'
|
|
662
|
+
f' sys.stdout.write(json.dumps(response) + "\\n")\n'
|
|
663
|
+
f' sys.stdout.flush()\n'
|
|
664
|
+
f' except json.JSONDecodeError:\n'
|
|
665
|
+
f' error = {{\n'
|
|
666
|
+
f' "jsonrpc": "2.0", "id": None,\n'
|
|
667
|
+
f' "error": {{"code": -32700, "message": "Parse error"}},\n'
|
|
668
|
+
f' }}\n'
|
|
669
|
+
f' sys.stdout.write(json.dumps(error) + "\\n")\n'
|
|
670
|
+
f' sys.stdout.flush()\n'
|
|
671
|
+
f'\n'
|
|
672
|
+
f'\n'
|
|
673
|
+
f'if __name__ == "__main__":\n'
|
|
674
|
+
f' main()\n'
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
stub_path = mcp_dir / f"{server_name}.py"
|
|
678
|
+
stub_path.write_text(stub_content, encoding="utf-8")
|
|
679
|
+
stubs_written += 1
|
|
680
|
+
|
|
681
|
+
return stubs_written
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
def _generate_dashboard_stub(
|
|
685
|
+
child_root: Path, blueprint: dict
|
|
686
|
+
) -> bool:
|
|
687
|
+
"""Generate a minimal capability-driven Flask dashboard stub.
|
|
688
|
+
|
|
689
|
+
Instead of copying ICDEV's dashboard (which has ICDEV-specific routes),
|
|
690
|
+
generate a minimal Flask app with routes driven by the child app's
|
|
691
|
+
enabled capabilities. The child app developer fills in domain-specific
|
|
692
|
+
logic.
|
|
693
|
+
|
|
694
|
+
The generated dashboard adapts to any app type — multi-agent, single
|
|
695
|
+
service, data pipeline, CLI tool, etc.
|
|
696
|
+
"""
|
|
697
|
+
app_name = blueprint["app_name"]
|
|
698
|
+
classification = blueprint.get("classification", "CUI")
|
|
699
|
+
agents = blueprint.get("agents", [])
|
|
700
|
+
capabilities = blueprint.get("capabilities", {})
|
|
701
|
+
demo_mode = blueprint.get("demo_mode", False)
|
|
702
|
+
|
|
703
|
+
cui_line = (
|
|
704
|
+
"SECRET // NOFORN" if classification == "SECRET" else "CUI // SP-CTI"
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
# Demo banner HTML (orange, top + bottom of every page, like CUI banners)
|
|
708
|
+
demo_banner_style = (
|
|
709
|
+
".demo-banner { background: #e65100; color: #fff; text-align: center; "
|
|
710
|
+
"padding: 6px; font-weight: bold; font-size: 0.85rem; "
|
|
711
|
+
"letter-spacing: 1px; }"
|
|
712
|
+
)
|
|
713
|
+
demo_banner_top = (
|
|
714
|
+
'<div class="demo-banner">'
|
|
715
|
+
"DEMONSTRATION ONLY \\u2014 NOT FOR OPERATIONAL USE"
|
|
716
|
+
"</div>"
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
# Build nav links and page functions based on enabled capabilities
|
|
720
|
+
nav_links = ['"<a href=\\"/\\">Home</a>"']
|
|
721
|
+
page_functions = []
|
|
722
|
+
|
|
723
|
+
# Home page — always present
|
|
724
|
+
page_functions.append(
|
|
725
|
+
' @app.route("/")\n'
|
|
726
|
+
' def home():\n'
|
|
727
|
+
' return _render("Home", "<h2>Welcome</h2>"\n'
|
|
728
|
+
f' "<p>{app_name} dashboard.</p>")\n'
|
|
729
|
+
)
|
|
730
|
+
|
|
731
|
+
# Agents page — only if the app has agents
|
|
732
|
+
if agents:
|
|
733
|
+
nav_links.append('"<a href=\\"/agents\\">Agents</a>"')
|
|
734
|
+
agent_list_items = "".join(
|
|
735
|
+
f'<li><strong>{a["name"]}</strong> (port {a.get("port", "?")}) '
|
|
736
|
+
f'\\u2014 {a.get("role", "")}</li>'
|
|
737
|
+
for a in agents
|
|
738
|
+
)
|
|
739
|
+
page_functions.append(
|
|
740
|
+
' @app.route("/agents")\n'
|
|
741
|
+
' def agents_page():\n'
|
|
742
|
+
f' return _render("Agents", "<h2>Agents</h2>"\n'
|
|
743
|
+
f' "<ul>{agent_list_items}</ul>")\n'
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
# Compliance page — only if compliance capability enabled
|
|
747
|
+
if capabilities.get("compliance", False):
|
|
748
|
+
nav_links.append('"<a href=\\"/compliance\\">Compliance</a>"')
|
|
749
|
+
page_functions.append(
|
|
750
|
+
' @app.route("/compliance")\n'
|
|
751
|
+
' def compliance_page():\n'
|
|
752
|
+
' # TODO: Add compliance status from DB\n'
|
|
753
|
+
' return _render("Compliance",\n'
|
|
754
|
+
' "<h2>Compliance</h2>"\n'
|
|
755
|
+
' "<p>Compliance status placeholder.</p>")\n'
|
|
756
|
+
)
|
|
757
|
+
|
|
758
|
+
# Security page — only if security capability enabled
|
|
759
|
+
if capabilities.get("security", False):
|
|
760
|
+
nav_links.append('"<a href=\\"/security\\">Security</a>"')
|
|
761
|
+
page_functions.append(
|
|
762
|
+
' @app.route("/security")\n'
|
|
763
|
+
' def security_page():\n'
|
|
764
|
+
' # TODO: Add security scan results from DB\n'
|
|
765
|
+
' return _render("Security",\n'
|
|
766
|
+
' "<h2>Security</h2>"\n'
|
|
767
|
+
' "<p>Security scan placeholder.</p>")\n'
|
|
768
|
+
)
|
|
769
|
+
|
|
770
|
+
# API health endpoint — always present
|
|
771
|
+
page_functions.append(
|
|
772
|
+
' @app.route("/api/health")\n'
|
|
773
|
+
' def api_health():\n'
|
|
774
|
+
f' return jsonify({{"status": "healthy", '
|
|
775
|
+
f'"app": "{app_name}"}})\n'
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
nav_html = "\n ".join(nav_links)
|
|
779
|
+
|
|
780
|
+
stub_content = (
|
|
781
|
+
f'#!/usr/bin/env python3\n'
|
|
782
|
+
f'# {cui_line}\n'
|
|
783
|
+
f'"""{app_name} Dashboard — Flask SSR + HTMX\n'
|
|
784
|
+
f'\n'
|
|
785
|
+
f'Generated by ICDEV child app generator.\n'
|
|
786
|
+
f'Customize routes and pages for your domain.\n'
|
|
787
|
+
f'"""\n'
|
|
788
|
+
f'\n'
|
|
789
|
+
f'import sqlite3\n'
|
|
790
|
+
f'from pathlib import Path\n'
|
|
791
|
+
f'from flask import Flask, jsonify\n'
|
|
792
|
+
f'\n'
|
|
793
|
+
f'DB_PATH = str(Path(__file__).resolve().parent.parent.parent\n'
|
|
794
|
+
f' / "data" / "{app_name}.db")\n'
|
|
795
|
+
f'\n'
|
|
796
|
+
f'\n'
|
|
797
|
+
f'def _layout(title: str, body: str) -> str:\n'
|
|
798
|
+
f' """Wrap page body in HTML layout."""\n'
|
|
799
|
+
f' return (\n'
|
|
800
|
+
f' "<!DOCTYPE html><html><head>"\n'
|
|
801
|
+
f' f"<title>{{title}} — {app_name}</title>"\n'
|
|
802
|
+
f' "<style>"\n'
|
|
803
|
+
f' "body {{ font-family: system-ui; margin: 2rem; "\n'
|
|
804
|
+
f' "background: #1a1a2e; color: #e0e0e0; }}"\n'
|
|
805
|
+
f' "a {{ color: #64b5f6; }} nav {{ margin-bottom: 1.5rem; }}"\n'
|
|
806
|
+
f' "nav a {{ margin-right: 1rem; }}"\n'
|
|
807
|
+
f' ".card {{ background: #16213e; padding: 1rem; "\n'
|
|
808
|
+
f' "border-radius: 8px; margin: 0.5rem 0; }}"\n'
|
|
809
|
+
f' "{demo_banner_style if demo_mode else ""}"\n'
|
|
810
|
+
f' "</style></head><body>"\n'
|
|
811
|
+
f' "{demo_banner_top if demo_mode else ""}"\n'
|
|
812
|
+
f' "<h1>{app_name}</h1>"\n'
|
|
813
|
+
f' "<nav>"\n'
|
|
814
|
+
f' {nav_html}\n'
|
|
815
|
+
f' "</nav>"\n'
|
|
816
|
+
f' f"{{body}}"\n'
|
|
817
|
+
f' "{demo_banner_top if demo_mode else ""}"\n'
|
|
818
|
+
f' "</body></html>"\n'
|
|
819
|
+
f' )\n'
|
|
820
|
+
f'\n'
|
|
821
|
+
f'\n'
|
|
822
|
+
f'def _render(title: str, body: str) -> str:\n'
|
|
823
|
+
f' """Render a page with the standard layout."""\n'
|
|
824
|
+
f' return _layout(title, body)\n'
|
|
825
|
+
f'\n'
|
|
826
|
+
f'\n'
|
|
827
|
+
f'def create_app() -> Flask:\n'
|
|
828
|
+
f' """Create and configure the Flask application."""\n'
|
|
829
|
+
f' app = Flask(__name__)\n'
|
|
830
|
+
f'\n'
|
|
831
|
+
)
|
|
832
|
+
|
|
833
|
+
for fn in page_functions:
|
|
834
|
+
stub_content += fn + "\n"
|
|
835
|
+
|
|
836
|
+
stub_content += (
|
|
837
|
+
f' return app\n'
|
|
838
|
+
f'\n'
|
|
839
|
+
f'\n'
|
|
840
|
+
f'app = create_app()\n'
|
|
841
|
+
f'\n'
|
|
842
|
+
f'\n'
|
|
843
|
+
f'if __name__ == "__main__":\n'
|
|
844
|
+
f' app.run(host="0.0.0.0", port=5000, debug=os.environ.get("FLASK_DEBUG", "false").lower() == "true")\n'
|
|
845
|
+
)
|
|
846
|
+
|
|
847
|
+
dash_dir = child_root / "tools" / "dashboard"
|
|
848
|
+
dash_dir.mkdir(parents=True, exist_ok=True)
|
|
849
|
+
(dash_dir / "app.py").write_text(stub_content, encoding="utf-8")
|
|
850
|
+
return True
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
def _strip_govcon_from_dashboard(content: str) -> str:
|
|
854
|
+
"""Remove GovProposal/CPMP/GovCon imports and registrations from app.py.
|
|
855
|
+
|
|
856
|
+
D-CHILD-3: Children never receive GovProposal functionality.
|
|
857
|
+
|
|
858
|
+
The parent's govcon init block looks like::
|
|
859
|
+
|
|
860
|
+
# D-CHILD-6: ...
|
|
861
|
+
import os as _os
|
|
862
|
+
_GOVCON_ENABLED = _os.environ.get(...)
|
|
863
|
+
_HAS_GOVCON = False
|
|
864
|
+
if _GOVCON_ENABLED:
|
|
865
|
+
try:
|
|
866
|
+
from icdev.tools.dashboard.api.proposals import proposals_api
|
|
867
|
+
...
|
|
868
|
+
_HAS_GOVCON = True
|
|
869
|
+
except ImportError:
|
|
870
|
+
_HAS_GOVCON = False
|
|
871
|
+
|
|
872
|
+
This function replaces that entire block with a single constant::
|
|
873
|
+
|
|
874
|
+
_HAS_GOVCON = False # D-CHILD-3: GovCon disabled in child apps
|
|
875
|
+
"""
|
|
876
|
+
lines = content.split("\n")
|
|
877
|
+
filtered = []
|
|
878
|
+
# --- State: govcon init block removal ---
|
|
879
|
+
in_govcon_init = False
|
|
880
|
+
govcon_init_done = False
|
|
881
|
+
govcon_init_indent = 0
|
|
882
|
+
# --- State: inline route block removal ---
|
|
883
|
+
skip_route_block = False
|
|
884
|
+
|
|
885
|
+
for line in lines:
|
|
886
|
+
stripped = line.strip()
|
|
887
|
+
|
|
888
|
+
# ── Govcon init block: detect start ────────────────────────
|
|
889
|
+
if not govcon_init_done and not in_govcon_init:
|
|
890
|
+
if "_GOVCON_ENABLED" in stripped and "=" in stripped:
|
|
891
|
+
in_govcon_init = True
|
|
892
|
+
# Also retroactively remove the preceding comment + import _os
|
|
893
|
+
# that belong to this block
|
|
894
|
+
while filtered and filtered[-1].strip() in (
|
|
895
|
+
"# D-CHILD-6: GovProposal/CPMP/GovCon conditionally loaded",
|
|
896
|
+
"import os as _os",
|
|
897
|
+
"",
|
|
898
|
+
):
|
|
899
|
+
filtered.pop()
|
|
900
|
+
# Emit the replacement constant
|
|
901
|
+
filtered.append(
|
|
902
|
+
"_HAS_GOVCON = False "
|
|
903
|
+
"# D-CHILD-3: GovCon disabled in child apps"
|
|
904
|
+
)
|
|
905
|
+
continue
|
|
906
|
+
|
|
907
|
+
# ── Govcon init block: skip body ───────────────────────────
|
|
908
|
+
if in_govcon_init:
|
|
909
|
+
# The block ends when we hit a top-level statement (indent 0)
|
|
910
|
+
# that is NOT part of the if/try/except/else structure and is
|
|
911
|
+
# NOT a blank line.
|
|
912
|
+
if stripped == "":
|
|
913
|
+
continue # skip blank lines inside the block
|
|
914
|
+
indent = len(line) - len(line.lstrip())
|
|
915
|
+
if indent == 0 and stripped not in ("", ) and not stripped.startswith(
|
|
916
|
+
("if _GOVCON_ENABLED", "_HAS_GOVCON", "else:")
|
|
917
|
+
):
|
|
918
|
+
# This line is the FIRST line AFTER the govcon init block
|
|
919
|
+
in_govcon_init = False
|
|
920
|
+
govcon_init_done = True
|
|
921
|
+
# fall through to normal processing for this line
|
|
922
|
+
else:
|
|
923
|
+
continue # still inside the govcon init block
|
|
924
|
+
|
|
925
|
+
# ── Skip GovProposal blueprint imports and registrations ───
|
|
926
|
+
if any(mod in stripped for mod in (
|
|
927
|
+
"from tools.dashboard.api.proposals",
|
|
928
|
+
"from tools.dashboard.api.govcon",
|
|
929
|
+
"from tools.dashboard.api.cpmp",
|
|
930
|
+
)):
|
|
931
|
+
continue
|
|
932
|
+
|
|
933
|
+
if any(mod in stripped for mod in (
|
|
934
|
+
"proposals_api", "govcon_api", "cpmp_api",
|
|
935
|
+
)):
|
|
936
|
+
if "register_blueprint" in stripped or "import" in stripped:
|
|
937
|
+
continue
|
|
938
|
+
|
|
939
|
+
# ── Skip GovProposal/CPMP inline route blocks ─────────────
|
|
940
|
+
if any(pat in stripped for pat in (
|
|
941
|
+
'def proposals_', 'def cpmp_', 'def govcon_',
|
|
942
|
+
'@app.route("/proposals', '@app.route("/cpmp',
|
|
943
|
+
'@app.route("/govcon',
|
|
944
|
+
'SECTION_TRANSITIONS',
|
|
945
|
+
)):
|
|
946
|
+
skip_route_block = True
|
|
947
|
+
continue
|
|
948
|
+
|
|
949
|
+
# End skip block at next function/route decorator
|
|
950
|
+
if skip_route_block and (stripped.startswith("@app.route") or
|
|
951
|
+
stripped.startswith("def ") or
|
|
952
|
+
stripped.startswith("# ===")):
|
|
953
|
+
if not any(k in stripped for k in ("/proposals", "/cpmp", "/govcon",
|
|
954
|
+
"proposals_", "cpmp_", "govcon_")):
|
|
955
|
+
skip_route_block = False
|
|
956
|
+
|
|
957
|
+
if skip_route_block:
|
|
958
|
+
continue
|
|
959
|
+
|
|
960
|
+
filtered.append(line)
|
|
961
|
+
|
|
962
|
+
return "\n".join(filtered)
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
def _copy_full_dashboard(
|
|
966
|
+
child_root: Path, blueprint: dict, icdev_root: Path,
|
|
967
|
+
) -> dict:
|
|
968
|
+
"""D-CHILD-4: Copy full 40+ page dashboard to child app.
|
|
969
|
+
|
|
970
|
+
Copies all dashboard components except GovProposal/CPMP/GovCon content.
|
|
971
|
+
Falls back to _generate_dashboard_stub() if source doesn't exist.
|
|
972
|
+
"""
|
|
973
|
+
dash_src = icdev_root / "tools" / "dashboard"
|
|
974
|
+
if not dash_src.exists():
|
|
975
|
+
_generate_dashboard_stub(child_root, blueprint)
|
|
976
|
+
return {"mode": "stub", "reason": "dashboard source not found"}
|
|
977
|
+
|
|
978
|
+
dash_dst = child_root / "tools" / "dashboard"
|
|
979
|
+
dash_dst.mkdir(parents=True, exist_ok=True)
|
|
980
|
+
copied = 0
|
|
981
|
+
|
|
982
|
+
# 1. Copy app.py with GovProposal stripped
|
|
983
|
+
app_src = dash_src / "app.py"
|
|
984
|
+
if app_src.exists():
|
|
985
|
+
content = app_src.read_text(encoding="utf-8", errors="replace")
|
|
986
|
+
content = _strip_govcon_from_dashboard(content)
|
|
987
|
+
content = _apply_adaptations(content, ["app_name_replace", "db_rename"], blueprint)
|
|
988
|
+
(dash_dst / "app.py").write_text(content, encoding="utf-8")
|
|
989
|
+
copied += 1
|
|
990
|
+
|
|
991
|
+
# 2. Copy templates (excluding PARENT_ONLY_TEMPLATES)
|
|
992
|
+
tpl_src = dash_src / "templates"
|
|
993
|
+
if tpl_src.exists():
|
|
994
|
+
tpl_dst = dash_dst / "templates"
|
|
995
|
+
tpl_dst.mkdir(parents=True, exist_ok=True)
|
|
996
|
+
for item in sorted(tpl_src.rglob("*")):
|
|
997
|
+
if item.is_file():
|
|
998
|
+
rel = item.relative_to(tpl_src)
|
|
999
|
+
# Skip parent-only template directories
|
|
1000
|
+
if any(rel.parts[0] == d for d in PARENT_ONLY_TEMPLATES
|
|
1001
|
+
if len(rel.parts) > 0):
|
|
1002
|
+
continue
|
|
1003
|
+
dst_file = tpl_dst / rel
|
|
1004
|
+
dst_file.parent.mkdir(parents=True, exist_ok=True)
|
|
1005
|
+
shutil.copy2(str(item), str(dst_file))
|
|
1006
|
+
copied += 1
|
|
1007
|
+
|
|
1008
|
+
# 3. Copy API modules (excluding PARENT_ONLY_API_MODULES)
|
|
1009
|
+
api_src = dash_src / "api"
|
|
1010
|
+
if api_src.exists():
|
|
1011
|
+
api_dst = dash_dst / "api"
|
|
1012
|
+
api_dst.mkdir(parents=True, exist_ok=True)
|
|
1013
|
+
for item in sorted(api_src.glob("*.py")):
|
|
1014
|
+
if item.name in PARENT_ONLY_API_MODULES:
|
|
1015
|
+
continue
|
|
1016
|
+
dst_file = api_dst / item.name
|
|
1017
|
+
content = item.read_text(encoding="utf-8", errors="replace")
|
|
1018
|
+
content = _apply_adaptations(content, ["app_name_replace", "db_rename"], blueprint)
|
|
1019
|
+
dst_file.write_text(content, encoding="utf-8")
|
|
1020
|
+
copied += 1
|
|
1021
|
+
|
|
1022
|
+
# 4. Copy static assets (JS, CSS) — excluding parent-only JS
|
|
1023
|
+
static_src = dash_src / "static"
|
|
1024
|
+
if static_src.exists():
|
|
1025
|
+
c, _ = _copy_directory(
|
|
1026
|
+
static_src, dash_dst / "static", [], blueprint,
|
|
1027
|
+
exclude_files=PARENT_ONLY_STATIC_JS,
|
|
1028
|
+
)
|
|
1029
|
+
copied += c
|
|
1030
|
+
|
|
1031
|
+
# 5. Copy helper modules (auth.py, ux_helpers.py, etc.)
|
|
1032
|
+
for helper in ("auth.py", "ux_helpers.py", "__init__.py"):
|
|
1033
|
+
helper_src = dash_src / helper
|
|
1034
|
+
if helper_src.exists():
|
|
1035
|
+
content = helper_src.read_text(encoding="utf-8", errors="replace")
|
|
1036
|
+
content = _apply_adaptations(
|
|
1037
|
+
content, ["app_name_replace", "db_rename"], blueprint
|
|
1038
|
+
)
|
|
1039
|
+
(dash_dst / helper).write_text(content, encoding="utf-8")
|
|
1040
|
+
copied += 1
|
|
1041
|
+
|
|
1042
|
+
logger.info("Step 3: Full dashboard copied — %d files (GovProposal stripped)", copied)
|
|
1043
|
+
return {"mode": "full", "files_copied": copied}
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
def step_03_agent_infrastructure(
|
|
1047
|
+
child_root: Path, blueprint: dict, icdev_root: Optional[Path] = None
|
|
1048
|
+
) -> dict:
|
|
1049
|
+
"""Step 3: Generate agent cards, config, and MCP server stubs."""
|
|
1050
|
+
icdev_root = icdev_root or BASE_DIR
|
|
1051
|
+
agents = blueprint.get("agents", [])
|
|
1052
|
+
app_name = blueprint["app_name"]
|
|
1053
|
+
cards_written = 0
|
|
1054
|
+
|
|
1055
|
+
# Generate agent cards
|
|
1056
|
+
agent_cards_dir = child_root / "tools" / "agent" / "cards"
|
|
1057
|
+
agent_cards_dir.mkdir(parents=True, exist_ok=True)
|
|
1058
|
+
|
|
1059
|
+
for agent in agents:
|
|
1060
|
+
card = {
|
|
1061
|
+
"name": f"{app_name}-{agent['name']}",
|
|
1062
|
+
"description": agent.get("role", ""),
|
|
1063
|
+
"url": f"https://localhost:{agent['port']}",
|
|
1064
|
+
"version": "1.0.0",
|
|
1065
|
+
"capabilities": {
|
|
1066
|
+
"streaming": False,
|
|
1067
|
+
"pushNotifications": False,
|
|
1068
|
+
},
|
|
1069
|
+
"skills": _get_agent_skills(agent["name"], blueprint),
|
|
1070
|
+
"authentication": {
|
|
1071
|
+
"schemes": [{"scheme": "mutual-tls"}],
|
|
1072
|
+
},
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
card_path = agent_cards_dir / f"{agent['name']}_card.json"
|
|
1076
|
+
card_path.write_text(
|
|
1077
|
+
json.dumps(card, indent=2), encoding="utf-8")
|
|
1078
|
+
cards_written += 1
|
|
1079
|
+
|
|
1080
|
+
# Generate agent_config.yaml
|
|
1081
|
+
agent_config = _generate_agent_config(agents, app_name, blueprint)
|
|
1082
|
+
config_path = child_root / "args" / "agent_config.yaml"
|
|
1083
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1084
|
+
config_path.write_text(agent_config, encoding="utf-8")
|
|
1085
|
+
|
|
1086
|
+
# Generate MCP server stubs for each agent
|
|
1087
|
+
mcp_dir = child_root / "tools" / "mcp"
|
|
1088
|
+
mcp_dir.mkdir(parents=True, exist_ok=True)
|
|
1089
|
+
mcp_stubs_written = _generate_mcp_stubs(
|
|
1090
|
+
mcp_dir, agents, app_name, blueprint)
|
|
1091
|
+
|
|
1092
|
+
# D-CHILD-4: Full dashboard copy (replaces minimal stub)
|
|
1093
|
+
dashboard_result = {"mode": "none"}
|
|
1094
|
+
capabilities = blueprint.get("capabilities", {})
|
|
1095
|
+
if capabilities.get("dashboard", False):
|
|
1096
|
+
dashboard_result = _copy_full_dashboard(child_root, blueprint, icdev_root)
|
|
1097
|
+
|
|
1098
|
+
logger.info(
|
|
1099
|
+
"Step 3: %d agent cards, 1 config, %d MCP stubs, dashboard=%s",
|
|
1100
|
+
cards_written, mcp_stubs_written, dashboard_result.get("mode"),
|
|
1101
|
+
)
|
|
1102
|
+
return {
|
|
1103
|
+
"agent_cards": cards_written,
|
|
1104
|
+
"mcp_stubs": mcp_stubs_written,
|
|
1105
|
+
"dashboard": dashboard_result,
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
# ---------------------------------------------------------------------------
|
|
1110
|
+
# Step 4: Memory Bootstrap
|
|
1111
|
+
# ---------------------------------------------------------------------------
|
|
1112
|
+
|
|
1113
|
+
def step_04_memory_bootstrap(child_root: Path, blueprint: dict) -> dict:
|
|
1114
|
+
"""Step 4: Bootstrap memory system with child identity."""
|
|
1115
|
+
app_name = blueprint["app_name"]
|
|
1116
|
+
classification = blueprint.get("classification", "CUI")
|
|
1117
|
+
impact_level = blueprint.get("impact_level", "IL4")
|
|
1118
|
+
agents = blueprint.get("agents", [])
|
|
1119
|
+
architecture = blueprint.get(
|
|
1120
|
+
"fitness_scorecard", {}).get("architecture", "hybrid")
|
|
1121
|
+
parent_cb = blueprint.get("parent_callback", {})
|
|
1122
|
+
|
|
1123
|
+
# Create MEMORY.md with blueprint-enriched content
|
|
1124
|
+
timestamp = datetime.now(tz=timezone.utc).isoformat()
|
|
1125
|
+
|
|
1126
|
+
demo_mode = blueprint.get("demo_mode", False)
|
|
1127
|
+
|
|
1128
|
+
# Extract capabilities list from blueprint
|
|
1129
|
+
capabilities = blueprint.get("capabilities", {})
|
|
1130
|
+
active_caps = [k for k, v in capabilities.items()
|
|
1131
|
+
if v] if isinstance(capabilities, dict) else []
|
|
1132
|
+
|
|
1133
|
+
# Extract description/purpose if provided
|
|
1134
|
+
description = blueprint.get("description", "")
|
|
1135
|
+
purpose = blueprint.get("purpose", "")
|
|
1136
|
+
scorecard = blueprint.get("fitness_scorecard", {})
|
|
1137
|
+
spec = scorecard.get("spec", description or purpose or "")
|
|
1138
|
+
|
|
1139
|
+
memory_content = (
|
|
1140
|
+
f"# MEMORY.md — {app_name}\n"
|
|
1141
|
+
f"\n"
|
|
1142
|
+
f"## Identity\n"
|
|
1143
|
+
f"- **Application:** {app_name}\n"
|
|
1144
|
+
f"- **Generated by:** ICDEV (parent application)\n"
|
|
1145
|
+
f"- **Classification:** {classification}\n"
|
|
1146
|
+
f"- **Impact Level:** {impact_level}\n"
|
|
1147
|
+
f"- **Architecture:** {architecture}\n"
|
|
1148
|
+
)
|
|
1149
|
+
|
|
1150
|
+
if demo_mode:
|
|
1151
|
+
memory_content += (
|
|
1152
|
+
f"- **Mode:** DEMONSTRATION ONLY\n"
|
|
1153
|
+
f" - This is a demo application. Do NOT use for operational or classified data.\n"
|
|
1154
|
+
)
|
|
1155
|
+
|
|
1156
|
+
# Agent details — only if the app has agents
|
|
1157
|
+
if agents:
|
|
1158
|
+
memory_content += f"- **Agents:** {len(agents)}\n"
|
|
1159
|
+
for a in agents:
|
|
1160
|
+
role = a.get("role", "")
|
|
1161
|
+
port = a.get("port", "")
|
|
1162
|
+
if role:
|
|
1163
|
+
memory_content += (
|
|
1164
|
+
f" - **{a['name'].title()}** (port {port}): {role}\n"
|
|
1165
|
+
)
|
|
1166
|
+
else:
|
|
1167
|
+
memory_content += (
|
|
1168
|
+
f" - **{a['name'].title()}** (port {port})\n"
|
|
1169
|
+
)
|
|
1170
|
+
|
|
1171
|
+
memory_content += f"- **Generated at:** {timestamp}\n"
|
|
1172
|
+
|
|
1173
|
+
if spec:
|
|
1174
|
+
memory_content += (
|
|
1175
|
+
f"\n"
|
|
1176
|
+
f"## Purpose\n"
|
|
1177
|
+
f"{spec}\n"
|
|
1178
|
+
)
|
|
1179
|
+
|
|
1180
|
+
if active_caps:
|
|
1181
|
+
memory_content += (
|
|
1182
|
+
f"\n"
|
|
1183
|
+
f"## Capabilities\n"
|
|
1184
|
+
)
|
|
1185
|
+
for cap in active_caps:
|
|
1186
|
+
memory_content += f"- {cap}\n"
|
|
1187
|
+
|
|
1188
|
+
memory_content += (
|
|
1189
|
+
f"\n"
|
|
1190
|
+
f"## User Preferences\n"
|
|
1191
|
+
f"(To be populated during first session)\n"
|
|
1192
|
+
f"\n"
|
|
1193
|
+
f"## Key Facts\n"
|
|
1194
|
+
f"- This is a generated child application of ICDEV\n"
|
|
1195
|
+
f"- This application CANNOT generate child applications "
|
|
1196
|
+
f"(grandchild prevention)\n"
|
|
1197
|
+
f"- ATLAS workflow does not include fitness assessment step\n"
|
|
1198
|
+
)
|
|
1199
|
+
if parent_cb.get("enabled"):
|
|
1200
|
+
memory_content += (
|
|
1201
|
+
f"- Parent ICDEV callback URL: "
|
|
1202
|
+
f"{parent_cb.get('url', 'N/A')}\n"
|
|
1203
|
+
)
|
|
1204
|
+
memory_content += (
|
|
1205
|
+
"\n"
|
|
1206
|
+
"## Session History\n"
|
|
1207
|
+
"(Populated automatically by memory system)\n"
|
|
1208
|
+
)
|
|
1209
|
+
|
|
1210
|
+
memory_path = child_root / "memory" / "MEMORY.md"
|
|
1211
|
+
memory_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1212
|
+
memory_path.write_text(memory_content, encoding="utf-8")
|
|
1213
|
+
|
|
1214
|
+
# Create empty daily log for today
|
|
1215
|
+
today = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d")
|
|
1216
|
+
log_path = child_root / "memory" / "logs" / f"{today}.md"
|
|
1217
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1218
|
+
log_path.write_text(
|
|
1219
|
+
f"# {app_name} — Daily Log {today}\n\n", encoding="utf-8")
|
|
1220
|
+
|
|
1221
|
+
logger.info("Step 4: Memory bootstrapped (MEMORY.md + daily log)")
|
|
1222
|
+
return {"memory_md": str(memory_path), "daily_log": str(log_path)}
|
|
1223
|
+
|
|
1224
|
+
|
|
1225
|
+
# ---------------------------------------------------------------------------
|
|
1226
|
+
# Step 5: DB Init Script
|
|
1227
|
+
# ---------------------------------------------------------------------------
|
|
1228
|
+
|
|
1229
|
+
def step_05_db_init_script(child_root: Path, blueprint: dict) -> dict:
|
|
1230
|
+
"""Step 5: Generate standalone DB init script for child app."""
|
|
1231
|
+
# Try to import sister module
|
|
1232
|
+
write_init_script_fn = _import_sister(
|
|
1233
|
+
"db_init_generator", "write_init_script")
|
|
1234
|
+
|
|
1235
|
+
if write_init_script_fn:
|
|
1236
|
+
output_dir = child_root / "tools" / "db"
|
|
1237
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
1238
|
+
script_path = write_init_script_fn(blueprint, output_dir)
|
|
1239
|
+
logger.info("Step 5: DB init script generated at %s", script_path)
|
|
1240
|
+
return {"script_path": str(script_path), "method": "db_init_generator"}
|
|
1241
|
+
|
|
1242
|
+
# Fallback: generate a minimal init script inline
|
|
1243
|
+
app_name = blueprint["app_name"]
|
|
1244
|
+
sanitized = re.sub(
|
|
1245
|
+
r'[^a-z0-9_]', '_', app_name.lower().replace('-', '_'))
|
|
1246
|
+
|
|
1247
|
+
script_content = (
|
|
1248
|
+
'#!/usr/bin/env python3\n'
|
|
1249
|
+
'# CUI // SP-CTI\n'
|
|
1250
|
+
f'"""{app_name} database initialization."""\n'
|
|
1251
|
+
'\n'
|
|
1252
|
+
'import sqlite3\n'
|
|
1253
|
+
'import sys\n'
|
|
1254
|
+
'from pathlib import Path\n'
|
|
1255
|
+
'\n'
|
|
1256
|
+
'DB_PATH = Path(__file__).resolve().parent.parent.parent / "data"'
|
|
1257
|
+
f' / "{app_name}.db"\n'
|
|
1258
|
+
'\n'
|
|
1259
|
+
'\n'
|
|
1260
|
+
'def init_db(db_path=None):\n'
|
|
1261
|
+
' db_path = db_path or str(DB_PATH)\n'
|
|
1262
|
+
' Path(db_path).parent.mkdir(parents=True, exist_ok=True)\n'
|
|
1263
|
+
' conn = sqlite3.connect(db_path)\n'
|
|
1264
|
+
' conn.execute(\n'
|
|
1265
|
+
' "CREATE TABLE IF NOT EXISTS projects "\n'
|
|
1266
|
+
' "(id TEXT PRIMARY KEY, name TEXT, status TEXT '\
|
|
1267
|
+
"DEFAULT 'active', \"\n"
|
|
1268
|
+
' "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"\n'
|
|
1269
|
+
' )\n'
|
|
1270
|
+
' conn.execute(\n'
|
|
1271
|
+
' "CREATE TABLE IF NOT EXISTS audit_trail "\n'
|
|
1272
|
+
' "(id TEXT PRIMARY KEY, event_type TEXT, action TEXT, "\n'
|
|
1273
|
+
' "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"\n'
|
|
1274
|
+
' )\n'
|
|
1275
|
+
' conn.commit()\n'
|
|
1276
|
+
' tables = [\n'
|
|
1277
|
+
' r[0] for r in conn.execute(\n'
|
|
1278
|
+
' "SELECT name FROM sqlite_master WHERE type=\'table\'"\n'
|
|
1279
|
+
' ).fetchall()\n'
|
|
1280
|
+
' ]\n'
|
|
1281
|
+
f' print(f"{app_name} database initialized at {{db_path}}")\n'
|
|
1282
|
+
' print(f"Tables created ({len(tables)}): '
|
|
1283
|
+
'{\\", \\".join(sorted(tables))}")\n'
|
|
1284
|
+
' conn.close()\n'
|
|
1285
|
+
'\n'
|
|
1286
|
+
'\n'
|
|
1287
|
+
'if __name__ == "__main__":\n'
|
|
1288
|
+
' init_db()\n'
|
|
1289
|
+
)
|
|
1290
|
+
|
|
1291
|
+
output_dir = child_root / "tools" / "db"
|
|
1292
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
1293
|
+
script_path = output_dir / f"init_{sanitized}_db.py"
|
|
1294
|
+
script_path.write_text(script_content, encoding="utf-8")
|
|
1295
|
+
|
|
1296
|
+
logger.info(
|
|
1297
|
+
"Step 5: DB init script (fallback) generated at %s", script_path)
|
|
1298
|
+
return {"script_path": str(script_path), "method": "fallback"}
|
|
1299
|
+
|
|
1300
|
+
|
|
1301
|
+
# ---------------------------------------------------------------------------
|
|
1302
|
+
# Step 6: Goals and Hardprompts
|
|
1303
|
+
# ---------------------------------------------------------------------------
|
|
1304
|
+
|
|
1305
|
+
def step_06_goals_and_hardprompts(
|
|
1306
|
+
child_root: Path, blueprint: dict, icdev_root: Path
|
|
1307
|
+
) -> dict:
|
|
1308
|
+
"""Step 6: Copy and adapt goals + hardprompts using goal_adapter."""
|
|
1309
|
+
adapt_goals_fn = _import_sister("goal_adapter", "adapt_goals")
|
|
1310
|
+
|
|
1311
|
+
if adapt_goals_fn:
|
|
1312
|
+
result = adapt_goals_fn(blueprint, icdev_root, child_root)
|
|
1313
|
+
logger.info(
|
|
1314
|
+
"Step 6: Goals adapted — %d goals, %d hardprompts",
|
|
1315
|
+
result.get("goals_copied", 0),
|
|
1316
|
+
result.get("hardprompts_copied", 0),
|
|
1317
|
+
)
|
|
1318
|
+
return result
|
|
1319
|
+
|
|
1320
|
+
# Fallback: copy goals manually
|
|
1321
|
+
goals_config = blueprint.get("goals_config", [])
|
|
1322
|
+
goals_dir = child_root / "goals"
|
|
1323
|
+
goals_dir.mkdir(parents=True, exist_ok=True)
|
|
1324
|
+
|
|
1325
|
+
goal_files = {
|
|
1326
|
+
"build_app": "build_app.md",
|
|
1327
|
+
"tdd_workflow": "tdd_workflow.md",
|
|
1328
|
+
"compliance_workflow": "compliance_workflow.md",
|
|
1329
|
+
"security_scan": "security_scan.md",
|
|
1330
|
+
"deploy_workflow": "deploy_workflow.md",
|
|
1331
|
+
"monitoring": "monitoring.md",
|
|
1332
|
+
"self_healing": "self_healing.md",
|
|
1333
|
+
"agent_management": "agent_management.md",
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
copied = 0
|
|
1337
|
+
for goal_name in goals_config:
|
|
1338
|
+
filename = goal_files.get(goal_name)
|
|
1339
|
+
if filename:
|
|
1340
|
+
src = icdev_root / "goals" / filename
|
|
1341
|
+
if src.exists():
|
|
1342
|
+
shutil.copy2(src, goals_dir / filename)
|
|
1343
|
+
copied += 1
|
|
1344
|
+
|
|
1345
|
+
# Generate minimal manifest
|
|
1346
|
+
manifest_content = f"# Goals Manifest — {blueprint['app_name']}\n\n"
|
|
1347
|
+
manifest_content += "| Goal | File |\n|------|------|\n"
|
|
1348
|
+
for goal_name in goals_config:
|
|
1349
|
+
filename = goal_files.get(goal_name, f"{goal_name}.md")
|
|
1350
|
+
manifest_content += f"| {goal_name} | goals/{filename} |\n"
|
|
1351
|
+
(goals_dir / "manifest.md").write_text(
|
|
1352
|
+
manifest_content, encoding="utf-8")
|
|
1353
|
+
|
|
1354
|
+
logger.info("Step 6: Goals copied (fallback) — %d goals", copied)
|
|
1355
|
+
return {"goals_copied": copied, "method": "fallback"}
|
|
1356
|
+
|
|
1357
|
+
|
|
1358
|
+
# ============================================================
|
|
1359
|
+
# STEP 7: Args + Context
|
|
1360
|
+
# ============================================================
|
|
1361
|
+
|
|
1362
|
+
|
|
1363
|
+
def step_07_args_and_context(child_root: Path, blueprint: dict, icdev_root: Path) -> dict:
|
|
1364
|
+
"""Step 7: Copy and adapt args/ and context/ configuration files."""
|
|
1365
|
+
blueprint["app_name"]
|
|
1366
|
+
capabilities = blueprint.get("capabilities", {})
|
|
1367
|
+
copied = 0
|
|
1368
|
+
|
|
1369
|
+
# --- Args files ---
|
|
1370
|
+
args_dir = child_root / "args"
|
|
1371
|
+
args_dir.mkdir(parents=True, exist_ok=True)
|
|
1372
|
+
|
|
1373
|
+
args_files = [
|
|
1374
|
+
("args/project_defaults.yaml", ["app_name_replace", "port_remap"]),
|
|
1375
|
+
("args/monitoring_config.yaml", ["endpoint_remap", "app_name_replace"]),
|
|
1376
|
+
# D-EPSEC-7: Security config always copied (not conditional on compliance)
|
|
1377
|
+
("args/security_gates.yaml", []),
|
|
1378
|
+
("args/endpoint_security_config.yaml", []),
|
|
1379
|
+
("args/code_pattern_config.yaml", []),
|
|
1380
|
+
]
|
|
1381
|
+
if capabilities.get("compliance"):
|
|
1382
|
+
args_files.append(("args/cui_markings.yaml", ["classification_update"]))
|
|
1383
|
+
|
|
1384
|
+
# D-CHILD-1: Enterprise capability args files
|
|
1385
|
+
if capabilities.get("ricoas"):
|
|
1386
|
+
args_files.append(("args/ricoas_config.yaml", []))
|
|
1387
|
+
if capabilities.get("devsecops_zta"):
|
|
1388
|
+
args_files.append(("args/devsecops_config.yaml", []))
|
|
1389
|
+
args_files.append(("args/zta_config.yaml", []))
|
|
1390
|
+
if capabilities.get("ai_security"):
|
|
1391
|
+
args_files.append(("args/owasp_agentic_config.yaml", []))
|
|
1392
|
+
if capabilities.get("observability"):
|
|
1393
|
+
args_files.append(("args/observability_tracing_config.yaml", []))
|
|
1394
|
+
if capabilities.get("code_intelligence"):
|
|
1395
|
+
args_files.append(("args/code_quality_config.yaml", []))
|
|
1396
|
+
if capabilities.get("ai_governance"):
|
|
1397
|
+
args_files.append(("args/ai_governance_config.yaml", []))
|
|
1398
|
+
|
|
1399
|
+
for rel_path, adaptations in args_files:
|
|
1400
|
+
src = icdev_root / rel_path
|
|
1401
|
+
dest = child_root / rel_path
|
|
1402
|
+
if src.exists():
|
|
1403
|
+
if _copy_and_adapt_file(src, dest, adaptations, blueprint):
|
|
1404
|
+
copied += 1
|
|
1405
|
+
else:
|
|
1406
|
+
logger.debug("Args file not found: %s", src)
|
|
1407
|
+
|
|
1408
|
+
# --- Context files ---
|
|
1409
|
+
ctx_src = icdev_root / "context"
|
|
1410
|
+
ctx_dest = child_root / "context"
|
|
1411
|
+
|
|
1412
|
+
# Always copy: context/languages/
|
|
1413
|
+
lang_src = ctx_src / "languages"
|
|
1414
|
+
if lang_src.exists():
|
|
1415
|
+
c, _ = _copy_directory(lang_src, ctx_dest / "languages", [], blueprint)
|
|
1416
|
+
copied += c
|
|
1417
|
+
|
|
1418
|
+
# Copy context/agentic/ (without fitness rubric — ICDEV-only)
|
|
1419
|
+
agentic_src = ctx_src / "agentic"
|
|
1420
|
+
if agentic_src.exists():
|
|
1421
|
+
c, _ = _copy_directory(
|
|
1422
|
+
agentic_src, ctx_dest / "agentic", [], blueprint,
|
|
1423
|
+
exclude_files={"fitness_rubric.md"})
|
|
1424
|
+
copied += c
|
|
1425
|
+
|
|
1426
|
+
# Conditional: context/compliance/
|
|
1427
|
+
if capabilities.get("compliance"):
|
|
1428
|
+
comp_src = ctx_src / "compliance"
|
|
1429
|
+
if comp_src.exists():
|
|
1430
|
+
c, _ = _copy_directory(
|
|
1431
|
+
comp_src, ctx_dest / "compliance",
|
|
1432
|
+
["classification_update"], blueprint)
|
|
1433
|
+
copied += c
|
|
1434
|
+
|
|
1435
|
+
# Conditional: context/mbse/
|
|
1436
|
+
if capabilities.get("mbse"):
|
|
1437
|
+
mbse_src = ctx_src / "mbse"
|
|
1438
|
+
if mbse_src.exists():
|
|
1439
|
+
c, _ = _copy_directory(mbse_src, ctx_dest / "mbse", [], blueprint)
|
|
1440
|
+
copied += c
|
|
1441
|
+
|
|
1442
|
+
# --- DevSecOps/ZTA inheritance (D122) ---
|
|
1443
|
+
# When parent project has a DevSecOps profile or ZTA is active,
|
|
1444
|
+
# copy devsecops configs and tools to child app
|
|
1445
|
+
devsecops_profile = blueprint.get("devsecops_profile") or {}
|
|
1446
|
+
zta_active = blueprint.get("zta_active", False) or devsecops_profile.get("zta_enabled", False)
|
|
1447
|
+
|
|
1448
|
+
if devsecops_profile or zta_active:
|
|
1449
|
+
# Copy DevSecOps config files
|
|
1450
|
+
for cfg in ("args/devsecops_config.yaml", "args/zta_config.yaml"):
|
|
1451
|
+
cfg_src = icdev_root / cfg
|
|
1452
|
+
cfg_dest = child_root / cfg
|
|
1453
|
+
if cfg_src.exists():
|
|
1454
|
+
if _copy_and_adapt_file(cfg_src, cfg_dest, [], blueprint):
|
|
1455
|
+
copied += 1
|
|
1456
|
+
|
|
1457
|
+
# Copy DevSecOps tools directory
|
|
1458
|
+
devsecops_src = icdev_root / "tools" / "devsecops"
|
|
1459
|
+
if devsecops_src.exists():
|
|
1460
|
+
c, _ = _copy_directory(
|
|
1461
|
+
devsecops_src, child_root / "tools" / "devsecops",
|
|
1462
|
+
["app_name_replace"], blueprint)
|
|
1463
|
+
copied += c
|
|
1464
|
+
|
|
1465
|
+
# Copy NIST 800-207 compliance catalog + crosswalk
|
|
1466
|
+
for zta_file in ("context/compliance/nist_800_207_zta.json",
|
|
1467
|
+
"context/compliance/nist_800_207_crosswalk.json"):
|
|
1468
|
+
zta_src = icdev_root / zta_file
|
|
1469
|
+
zta_dest = child_root / zta_file
|
|
1470
|
+
if zta_src.exists():
|
|
1471
|
+
if _copy_and_adapt_file(zta_src, zta_dest, [], blueprint):
|
|
1472
|
+
copied += 1
|
|
1473
|
+
|
|
1474
|
+
# Copy NIST 800-207 assessor
|
|
1475
|
+
assessor_src = icdev_root / "tools" / "compliance" / "nist_800_207_assessor.py"
|
|
1476
|
+
assessor_dest = child_root / "tools" / "compliance" / "nist_800_207_assessor.py"
|
|
1477
|
+
if assessor_src.exists():
|
|
1478
|
+
if _copy_and_adapt_file(assessor_src, assessor_dest, ["app_name_replace"], blueprint):
|
|
1479
|
+
copied += 1
|
|
1480
|
+
|
|
1481
|
+
logger.info("Step 7: DevSecOps/ZTA inheritance applied (%s profile, ZTA=%s)",
|
|
1482
|
+
devsecops_profile.get("maturity_level", "detected"), zta_active)
|
|
1483
|
+
|
|
1484
|
+
# --- MOSA inheritance (D127) ---
|
|
1485
|
+
# When parent project is DoD/IC with MOSA enabled, copy MOSA config,
|
|
1486
|
+
# tools, and compliance artifacts to child app
|
|
1487
|
+
mosa_enabled = blueprint.get("mosa_enabled", False)
|
|
1488
|
+
if not mosa_enabled:
|
|
1489
|
+
# Auto-detect from impact level or customer org
|
|
1490
|
+
il = blueprint.get("impact_level", "").upper()
|
|
1491
|
+
org = (blueprint.get("customer_org") or "").lower()
|
|
1492
|
+
if il in ("IL4", "IL5", "IL6") or any(k in org for k in ["dod", "defense", "military"]):
|
|
1493
|
+
mosa_enabled = True
|
|
1494
|
+
|
|
1495
|
+
if mosa_enabled:
|
|
1496
|
+
# Copy MOSA config
|
|
1497
|
+
mosa_cfg_src = icdev_root / "args" / "mosa_config.yaml"
|
|
1498
|
+
mosa_cfg_dest = child_root / "args" / "mosa_config.yaml"
|
|
1499
|
+
if mosa_cfg_src.exists():
|
|
1500
|
+
if _copy_and_adapt_file(mosa_cfg_src, mosa_cfg_dest, [], blueprint):
|
|
1501
|
+
copied += 1
|
|
1502
|
+
|
|
1503
|
+
# Copy tools/mosa/ package
|
|
1504
|
+
mosa_tools_src = icdev_root / "tools" / "mosa"
|
|
1505
|
+
if mosa_tools_src.exists():
|
|
1506
|
+
c, _ = _copy_directory(mosa_tools_src, child_root / "tools" / "mosa",
|
|
1507
|
+
["app_name_replace"], blueprint)
|
|
1508
|
+
copied += c
|
|
1509
|
+
|
|
1510
|
+
# Copy MOSA catalog and crosswalk
|
|
1511
|
+
for mosa_file in ("mosa_framework.json", "mosa_crosswalk.json"):
|
|
1512
|
+
src = icdev_root / "context" / "compliance" / mosa_file
|
|
1513
|
+
dest = child_root / "context" / "compliance" / mosa_file
|
|
1514
|
+
if src.exists():
|
|
1515
|
+
if _copy_and_adapt_file(src, dest, [], blueprint):
|
|
1516
|
+
copied += 1
|
|
1517
|
+
|
|
1518
|
+
# Copy MOSA assessor
|
|
1519
|
+
assessor_src = icdev_root / "tools" / "compliance" / "mosa_assessor.py"
|
|
1520
|
+
assessor_dest = child_root / "tools" / "compliance" / "mosa_assessor.py"
|
|
1521
|
+
if assessor_src.exists():
|
|
1522
|
+
if _copy_and_adapt_file(assessor_src, assessor_dest, ["app_name_replace"], blueprint):
|
|
1523
|
+
copied += 1
|
|
1524
|
+
|
|
1525
|
+
logger.info("Step 7: MOSA inheritance applied (DoD MOSA enabled)")
|
|
1526
|
+
|
|
1527
|
+
logger.info("Step 7: Copied %d args/context files", copied)
|
|
1528
|
+
return {"files_copied": copied}
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
# ============================================================
|
|
1532
|
+
# STEP 8: A2A Callback Client
|
|
1533
|
+
# ============================================================
|
|
1534
|
+
|
|
1535
|
+
|
|
1536
|
+
def step_08_a2a_callback_client(child_root: Path, blueprint: dict) -> dict:
|
|
1537
|
+
"""Step 8: Generate A2A callback client for parent ICDEV communication."""
|
|
1538
|
+
app_name = blueprint["app_name"]
|
|
1539
|
+
parent_cb = blueprint.get("parent_callback", {})
|
|
1540
|
+
classification = blueprint.get("classification", "CUI")
|
|
1541
|
+
cui_line = "SECRET // NOFORN" if classification == "SECRET" else "CUI // SP-CTI"
|
|
1542
|
+
|
|
1543
|
+
default_url = parent_cb.get("url", "")
|
|
1544
|
+
auth_method = parent_cb.get("auth", "none")
|
|
1545
|
+
|
|
1546
|
+
client_content = f'''#!/usr/bin/env python3
|
|
1547
|
+
# {cui_line}
|
|
1548
|
+
# Controlled by: Department of Defense
|
|
1549
|
+
# CUI Category: CTI
|
|
1550
|
+
"""A2A Callback Client — calls parent ICDEV for capabilities not included locally.
|
|
1551
|
+
|
|
1552
|
+
This child application ({app_name}) can request services from its parent ICDEV
|
|
1553
|
+
instance using the A2A protocol (JSON-RPC 2.0).
|
|
1554
|
+
|
|
1555
|
+
Excluded capabilities (must call parent for):
|
|
1556
|
+
- Application generation (agentic fitness, blueprint, scaffolding)
|
|
1557
|
+
- Application modernization (7R assessment, migration)
|
|
1558
|
+
|
|
1559
|
+
Environment variable: ICDEV_PARENT_CALLBACK_URL
|
|
1560
|
+
"""
|
|
1561
|
+
|
|
1562
|
+
import json
|
|
1563
|
+
import logging
|
|
1564
|
+
import os
|
|
1565
|
+
import uuid
|
|
1566
|
+
from urllib.error import HTTPError, URLError
|
|
1567
|
+
from urllib.request import Request, urlopen
|
|
1568
|
+
|
|
1569
|
+
PARENT_URL = os.environ.get("ICDEV_PARENT_CALLBACK_URL", "{default_url}")
|
|
1570
|
+
AUTH_METHOD = "{auth_method}"
|
|
1571
|
+
|
|
1572
|
+
logger = logging.getLogger("{app_name}.a2a_callback")
|
|
1573
|
+
|
|
1574
|
+
|
|
1575
|
+
def call_parent(method: str, params: dict = None, timeout: int = 30) -> dict:
|
|
1576
|
+
"""Send JSON-RPC 2.0 request to parent ICDEV.
|
|
1577
|
+
|
|
1578
|
+
Args:
|
|
1579
|
+
method: The RPC method name (e.g. "modernization.analyze_legacy").
|
|
1580
|
+
params: Optional parameters dict.
|
|
1581
|
+
timeout: Request timeout in seconds.
|
|
1582
|
+
|
|
1583
|
+
Returns:
|
|
1584
|
+
Response result dict, or error dict on failure.
|
|
1585
|
+
"""
|
|
1586
|
+
if not PARENT_URL:
|
|
1587
|
+
return {{"error": "ICDEV_PARENT_CALLBACK_URL not configured"}}
|
|
1588
|
+
|
|
1589
|
+
request_id = str(uuid.uuid4())
|
|
1590
|
+
payload = {{
|
|
1591
|
+
"jsonrpc": "2.0",
|
|
1592
|
+
"id": request_id,
|
|
1593
|
+
"method": method,
|
|
1594
|
+
"params": params or {{}},
|
|
1595
|
+
}}
|
|
1596
|
+
|
|
1597
|
+
headers = {{"Content-Type": "application/json"}}
|
|
1598
|
+
if AUTH_METHOD == "mtls":
|
|
1599
|
+
# mTLS handled at transport level; no additional auth header needed
|
|
1600
|
+
pass
|
|
1601
|
+
elif AUTH_METHOD == "bearer":
|
|
1602
|
+
token = os.environ.get("ICDEV_PARENT_AUTH_TOKEN", "")
|
|
1603
|
+
if token:
|
|
1604
|
+
headers["Authorization"] = f"Bearer {{token}}"
|
|
1605
|
+
|
|
1606
|
+
try:
|
|
1607
|
+
req = Request(
|
|
1608
|
+
PARENT_URL,
|
|
1609
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
1610
|
+
headers=headers,
|
|
1611
|
+
method="POST",
|
|
1612
|
+
)
|
|
1613
|
+
with urlopen(req, timeout=timeout) as resp:
|
|
1614
|
+
body = json.loads(resp.read().decode("utf-8"))
|
|
1615
|
+
if "error" in body:
|
|
1616
|
+
logger.warning("Parent returned error: %s", body["error"])
|
|
1617
|
+
return {{"error": body["error"]}}
|
|
1618
|
+
return body.get("result", {{}})
|
|
1619
|
+
except HTTPError as e:
|
|
1620
|
+
logger.error("HTTP error calling parent: %s %s", e.code, e.reason)
|
|
1621
|
+
return {{"error": f"HTTP {{e.code}}: {{e.reason}}"}}
|
|
1622
|
+
except URLError as e:
|
|
1623
|
+
logger.error("Connection error calling parent: %s", e.reason)
|
|
1624
|
+
return {{"error": f"Connection failed: {{e.reason}}"}}
|
|
1625
|
+
except Exception as e:
|
|
1626
|
+
logger.error("Unexpected error calling parent: %s", e)
|
|
1627
|
+
return {{"error": str(e)}}
|
|
1628
|
+
|
|
1629
|
+
|
|
1630
|
+
def check_health() -> bool:
|
|
1631
|
+
"""Check if parent ICDEV is reachable."""
|
|
1632
|
+
if not PARENT_URL:
|
|
1633
|
+
return False
|
|
1634
|
+
try:
|
|
1635
|
+
health_url = PARENT_URL.rstrip("/").rsplit("/", 1)[0] + "/health"
|
|
1636
|
+
req = Request(health_url, method="GET")
|
|
1637
|
+
with urlopen(req, timeout=5) as resp:
|
|
1638
|
+
return resp.status == 200
|
|
1639
|
+
except Exception:
|
|
1640
|
+
return False
|
|
1641
|
+
|
|
1642
|
+
|
|
1643
|
+
def list_parent_capabilities() -> list:
|
|
1644
|
+
"""Query parent for available capabilities."""
|
|
1645
|
+
result = call_parent("system.list_methods")
|
|
1646
|
+
if "error" in result:
|
|
1647
|
+
return []
|
|
1648
|
+
return result.get("methods", [])
|
|
1649
|
+
|
|
1650
|
+
|
|
1651
|
+
if __name__ == "__main__":
|
|
1652
|
+
import sys
|
|
1653
|
+
if "--health" in sys.argv:
|
|
1654
|
+
ok = check_health()
|
|
1655
|
+
print(f"Parent health: {{'ok' if ok else 'unreachable'}}")
|
|
1656
|
+
sys.exit(0 if ok else 1)
|
|
1657
|
+
caps = list_parent_capabilities()
|
|
1658
|
+
print(f"Parent capabilities: {{len(caps)}}")
|
|
1659
|
+
for cap in caps:
|
|
1660
|
+
print(f" - {{cap}}")
|
|
1661
|
+
'''
|
|
1662
|
+
|
|
1663
|
+
client_path = child_root / "tools" / "a2a" / "icdev_callback_client.py"
|
|
1664
|
+
client_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1665
|
+
client_path.write_text(client_content, encoding="utf-8")
|
|
1666
|
+
|
|
1667
|
+
logger.info("Step 8: A2A callback client generated (parent=%s)",
|
|
1668
|
+
"enabled" if parent_cb.get("enabled") else "disabled")
|
|
1669
|
+
return {
|
|
1670
|
+
"client_path": str(client_path),
|
|
1671
|
+
"parent_enabled": parent_cb.get("enabled", False),
|
|
1672
|
+
"parent_url": default_url,
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
|
|
1676
|
+
# ============================================================
|
|
1677
|
+
# STEP 9: CI/CD Setup
|
|
1678
|
+
# ============================================================
|
|
1679
|
+
|
|
1680
|
+
|
|
1681
|
+
def step_09_cicd_setup(child_root: Path, blueprint: dict, icdev_root: Path) -> dict:
|
|
1682
|
+
"""Step 9: Copy CI/CD tools and Claude Code commands."""
|
|
1683
|
+
blueprint["app_name"]
|
|
1684
|
+
copied = 0
|
|
1685
|
+
|
|
1686
|
+
# Copy tools/ci/
|
|
1687
|
+
ci_src = icdev_root / "tools" / "ci"
|
|
1688
|
+
ci_dest = child_root / "tools" / "ci"
|
|
1689
|
+
if ci_src.exists():
|
|
1690
|
+
c, _ = _copy_directory(
|
|
1691
|
+
ci_src, ci_dest,
|
|
1692
|
+
["bot_identifier_replace", "app_name_replace"], blueprint)
|
|
1693
|
+
copied += c
|
|
1694
|
+
|
|
1695
|
+
# NOTE: .claude/commands/ is handled by step_09c_claude_code_config()
|
|
1696
|
+
# with proper PARENT_ONLY_COMMANDS and PARENT_ONLY_E2E filtering.
|
|
1697
|
+
|
|
1698
|
+
# Generate .gitignore
|
|
1699
|
+
gitignore_content = """# Python
|
|
1700
|
+
__pycache__/
|
|
1701
|
+
*.py[cod]
|
|
1702
|
+
*.egg-info/
|
|
1703
|
+
dist/
|
|
1704
|
+
build/
|
|
1705
|
+
.eggs/
|
|
1706
|
+
|
|
1707
|
+
# Environment
|
|
1708
|
+
.env
|
|
1709
|
+
.venv/
|
|
1710
|
+
env/
|
|
1711
|
+
venv/
|
|
1712
|
+
|
|
1713
|
+
# Data
|
|
1714
|
+
data/*.db
|
|
1715
|
+
data/*.db-journal
|
|
1716
|
+
|
|
1717
|
+
# IDE
|
|
1718
|
+
.idea/
|
|
1719
|
+
.vscode/
|
|
1720
|
+
*.swp
|
|
1721
|
+
*.swo
|
|
1722
|
+
|
|
1723
|
+
# Temp
|
|
1724
|
+
.tmp/
|
|
1725
|
+
*.log
|
|
1726
|
+
|
|
1727
|
+
# OS
|
|
1728
|
+
.DS_Store
|
|
1729
|
+
Thumbs.db
|
|
1730
|
+
"""
|
|
1731
|
+
gitignore_path = child_root / ".gitignore"
|
|
1732
|
+
gitignore_path.write_text(gitignore_content, encoding="utf-8")
|
|
1733
|
+
copied += 1
|
|
1734
|
+
|
|
1735
|
+
# Generate requirements.txt
|
|
1736
|
+
requirements = [
|
|
1737
|
+
"pyyaml>=6.0", "jinja2>=3.1", "flask>=3.0",
|
|
1738
|
+
"pytest>=8.0", "pytest-cov>=5.0", "behave>=1.2",
|
|
1739
|
+
"requests>=2.31", "boto3>=1.34",
|
|
1740
|
+
"cyclonedx-bom>=4.0", "bandit>=1.7",
|
|
1741
|
+
"pip-audit>=2.7", "detect-secrets>=1.4",
|
|
1742
|
+
]
|
|
1743
|
+
if blueprint.get("capabilities", {}).get("mbse"):
|
|
1744
|
+
requirements.append("# MBSE: no additional deps (stdlib xml.etree)")
|
|
1745
|
+
req_path = child_root / "requirements.txt"
|
|
1746
|
+
req_path.write_text("\n".join(requirements) + "\n", encoding="utf-8")
|
|
1747
|
+
copied += 1
|
|
1748
|
+
|
|
1749
|
+
logger.info("Step 9: CI/CD setup — %d files copied", copied)
|
|
1750
|
+
return {"files_copied": copied}
|
|
1751
|
+
|
|
1752
|
+
|
|
1753
|
+
# ============================================================
|
|
1754
|
+
# STEP 9b: License Files
|
|
1755
|
+
# ============================================================
|
|
1756
|
+
|
|
1757
|
+
|
|
1758
|
+
def _copy_license_files(
|
|
1759
|
+
child_root: Path, blueprint: dict, icdev_root: Path
|
|
1760
|
+
) -> dict:
|
|
1761
|
+
"""Copy ICDEV license validator (and optionally generator) to child app.
|
|
1762
|
+
|
|
1763
|
+
For demo apps, also auto-generates a 30-day trial license file.
|
|
1764
|
+
|
|
1765
|
+
Args:
|
|
1766
|
+
child_root: Root directory of the child app.
|
|
1767
|
+
blueprint: Blueprint dict.
|
|
1768
|
+
icdev_root: ICDEV project root.
|
|
1769
|
+
|
|
1770
|
+
Returns:
|
|
1771
|
+
Dict with files copied and license info.
|
|
1772
|
+
"""
|
|
1773
|
+
app_name = blueprint["app_name"]
|
|
1774
|
+
demo_mode = blueprint.get("demo_mode", False)
|
|
1775
|
+
files_copied = []
|
|
1776
|
+
|
|
1777
|
+
# Create licensing directory in child app
|
|
1778
|
+
lic_dir = child_root / "tools" / "saas" / "licensing"
|
|
1779
|
+
lic_dir.mkdir(parents=True, exist_ok=True)
|
|
1780
|
+
|
|
1781
|
+
# Create __init__.py files for the package path
|
|
1782
|
+
for pkg_dir in [
|
|
1783
|
+
child_root / "tools" / "saas",
|
|
1784
|
+
lic_dir,
|
|
1785
|
+
]:
|
|
1786
|
+
init_file = pkg_dir / "__init__.py"
|
|
1787
|
+
if not init_file.exists():
|
|
1788
|
+
init_file.write_text("", encoding="utf-8")
|
|
1789
|
+
|
|
1790
|
+
# Always copy license_validator.py
|
|
1791
|
+
validator_src = icdev_root / "tools" / "saas" / "licensing" / "license_validator.py"
|
|
1792
|
+
if validator_src.exists():
|
|
1793
|
+
_copy_and_adapt_file(
|
|
1794
|
+
validator_src, lic_dir / "license_validator.py",
|
|
1795
|
+
["app_name_replace"], blueprint
|
|
1796
|
+
)
|
|
1797
|
+
files_copied.append("license_validator.py")
|
|
1798
|
+
|
|
1799
|
+
# Demo: also copy generator + create trial license
|
|
1800
|
+
license_info = None
|
|
1801
|
+
if demo_mode:
|
|
1802
|
+
gen_src = icdev_root / "tools" / "saas" / "licensing" / "license_generator.py"
|
|
1803
|
+
if gen_src.exists():
|
|
1804
|
+
_copy_and_adapt_file(
|
|
1805
|
+
gen_src, lic_dir / "license_generator.py",
|
|
1806
|
+
["app_name_replace"], blueprint
|
|
1807
|
+
)
|
|
1808
|
+
files_copied.append("license_generator.py")
|
|
1809
|
+
|
|
1810
|
+
# Auto-generate 30-day demo license
|
|
1811
|
+
expires_at = (
|
|
1812
|
+
datetime.now(tz=timezone.utc) + timedelta(days=30)
|
|
1813
|
+
).isoformat()
|
|
1814
|
+
license_info = {
|
|
1815
|
+
"license_id": f"demo-{uuid.uuid4().hex[:12]}",
|
|
1816
|
+
"customer": f"{app_name}-demo",
|
|
1817
|
+
"tier": "starter",
|
|
1818
|
+
"max_projects": 5,
|
|
1819
|
+
"max_users": 3,
|
|
1820
|
+
"allowed_il_levels": ["IL2"],
|
|
1821
|
+
"issued_at": datetime.now(tz=timezone.utc).isoformat(),
|
|
1822
|
+
"expires_at": expires_at,
|
|
1823
|
+
"signature": "",
|
|
1824
|
+
"demo": True,
|
|
1825
|
+
}
|
|
1826
|
+
data_dir = child_root / "data"
|
|
1827
|
+
data_dir.mkdir(parents=True, exist_ok=True)
|
|
1828
|
+
lic_path = data_dir / "license.json"
|
|
1829
|
+
lic_path.write_text(
|
|
1830
|
+
json.dumps(license_info, indent=2), encoding="utf-8"
|
|
1831
|
+
)
|
|
1832
|
+
files_copied.append("data/license.json")
|
|
1833
|
+
|
|
1834
|
+
# D-CHILD-5: AGPL-3.0 license for government deliveries
|
|
1835
|
+
license_type = blueprint.get("license", "AGPL-3.0")
|
|
1836
|
+
if license_type == "AGPL-3.0":
|
|
1837
|
+
agpl_text = (
|
|
1838
|
+
f"GNU AFFERO GENERAL PUBLIC LICENSE\n"
|
|
1839
|
+
f"Version 3, 19 November 2007\n\n"
|
|
1840
|
+
f"Copyright (C) {datetime.now(tz=timezone.utc).year} "
|
|
1841
|
+
f"{blueprint.get('customer_org', 'ICDEV Enterprise Delivery')}\n\n"
|
|
1842
|
+
f"This program is free software: you can redistribute it and/or modify\n"
|
|
1843
|
+
f"it under the terms of the GNU Affero General Public License as\n"
|
|
1844
|
+
f"published by the Free Software Foundation, either version 3 of the\n"
|
|
1845
|
+
f"License, or (at your option) any later version.\n\n"
|
|
1846
|
+
f"This program is distributed in the hope that it will be useful,\n"
|
|
1847
|
+
f"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
|
1848
|
+
f"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
|
1849
|
+
f"GNU Affero General Public License for more details.\n\n"
|
|
1850
|
+
f"You should have received a copy of the GNU Affero General Public\n"
|
|
1851
|
+
f"License along with this program. If not, see\n"
|
|
1852
|
+
f"<https://www.gnu.org/licenses/>.\n\n"
|
|
1853
|
+
f"---\n"
|
|
1854
|
+
f"Application: {app_name}\n"
|
|
1855
|
+
f"Generated by: ICDEV Enterprise Delivery (D374)\n"
|
|
1856
|
+
f"License grants free internal use for government operations.\n"
|
|
1857
|
+
f"Network use (SaaS) requires AGPL-3.0 source disclosure.\n"
|
|
1858
|
+
)
|
|
1859
|
+
lic_path = child_root / "LICENSE"
|
|
1860
|
+
lic_path.write_text(agpl_text, encoding="utf-8")
|
|
1861
|
+
files_copied.append("LICENSE (AGPL-3.0)")
|
|
1862
|
+
|
|
1863
|
+
logger.info(
|
|
1864
|
+
"Step 9b: License files copied: %s (demo=%s, license=%s)",
|
|
1865
|
+
files_copied, demo_mode, license_type,
|
|
1866
|
+
)
|
|
1867
|
+
return {
|
|
1868
|
+
"files_copied": files_copied,
|
|
1869
|
+
"demo_mode": demo_mode,
|
|
1870
|
+
"license_info": license_info,
|
|
1871
|
+
"license_type": license_type,
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
|
|
1875
|
+
# ============================================================
|
|
1876
|
+
# STEP 9c: Claude Code Configuration Inheritance (D-CHILD-2)
|
|
1877
|
+
# ============================================================
|
|
1878
|
+
|
|
1879
|
+
|
|
1880
|
+
def step_09c_claude_code_config(
|
|
1881
|
+
child_root: Path, blueprint: dict, icdev_root: Path,
|
|
1882
|
+
) -> dict:
|
|
1883
|
+
"""Step 9c: Copy .claude/ directory artifacts from parent to child.
|
|
1884
|
+
|
|
1885
|
+
D-CHILD-2: .claude/ is a first-class generation artifact.
|
|
1886
|
+
D-CHILD-3: PARENT_ONLY_COMMANDS/SKILLS/E2E are excluded.
|
|
1887
|
+
"""
|
|
1888
|
+
files_copied: List[str] = []
|
|
1889
|
+
files_skipped: List[str] = []
|
|
1890
|
+
claude_src = icdev_root / ".claude"
|
|
1891
|
+
|
|
1892
|
+
if not claude_src.exists():
|
|
1893
|
+
logger.info("Step 9c: No .claude directory found in ICDEV root — skipping")
|
|
1894
|
+
return {"files_copied": [], "files_skipped": [], "skipped": True}
|
|
1895
|
+
|
|
1896
|
+
claude_dst = child_root / ".claude"
|
|
1897
|
+
|
|
1898
|
+
# --- Hooks (copy all from .claude/hooks/) ---
|
|
1899
|
+
hooks_src = claude_src / "hooks"
|
|
1900
|
+
if hooks_src.exists():
|
|
1901
|
+
hooks_dst = claude_dst / "hooks"
|
|
1902
|
+
hooks_dst.mkdir(parents=True, exist_ok=True)
|
|
1903
|
+
for hook_file in sorted(hooks_src.glob("*")):
|
|
1904
|
+
if hook_file.is_file():
|
|
1905
|
+
dst_file = hooks_dst / hook_file.name
|
|
1906
|
+
content = hook_file.read_text(encoding="utf-8", errors="replace")
|
|
1907
|
+
# Adapt pre_tool_use.py: filter APPEND_ONLY_TABLES to child's schema
|
|
1908
|
+
if hook_file.name == "pre_tool_use.py":
|
|
1909
|
+
content = _adapt_pre_tool_use_for_child(content, blueprint)
|
|
1910
|
+
dst_file.write_text(content, encoding="utf-8")
|
|
1911
|
+
files_copied.append(f".claude/hooks/{hook_file.name}")
|
|
1912
|
+
|
|
1913
|
+
# --- Commands (exclude PARENT_ONLY_COMMANDS) ---
|
|
1914
|
+
cmds_src = claude_src / "commands"
|
|
1915
|
+
if cmds_src.exists():
|
|
1916
|
+
cmds_dst = claude_dst / "commands"
|
|
1917
|
+
cmds_dst.mkdir(parents=True, exist_ok=True)
|
|
1918
|
+
for cmd_file in sorted(cmds_src.glob("*.md")):
|
|
1919
|
+
if cmd_file.name in PARENT_ONLY_COMMANDS:
|
|
1920
|
+
files_skipped.append(f".claude/commands/{cmd_file.name}")
|
|
1921
|
+
continue
|
|
1922
|
+
dst_file = cmds_dst / cmd_file.name
|
|
1923
|
+
content = cmd_file.read_text(encoding="utf-8", errors="replace")
|
|
1924
|
+
content = content.replace("ICDEV", blueprint["app_name"])
|
|
1925
|
+
dst_file.write_text(content, encoding="utf-8")
|
|
1926
|
+
files_copied.append(f".claude/commands/{cmd_file.name}")
|
|
1927
|
+
|
|
1928
|
+
# E2E specs (exclude PARENT_ONLY_E2E)
|
|
1929
|
+
e2e_src = cmds_src / "e2e"
|
|
1930
|
+
if e2e_src.exists():
|
|
1931
|
+
e2e_dst = cmds_dst / "e2e"
|
|
1932
|
+
e2e_dst.mkdir(parents=True, exist_ok=True)
|
|
1933
|
+
for e2e_file in sorted(e2e_src.glob("*.md")):
|
|
1934
|
+
if e2e_file.name in PARENT_ONLY_E2E:
|
|
1935
|
+
files_skipped.append(f".claude/commands/e2e/{e2e_file.name}")
|
|
1936
|
+
continue
|
|
1937
|
+
dst_file = e2e_dst / e2e_file.name
|
|
1938
|
+
content = e2e_file.read_text(encoding="utf-8", errors="replace")
|
|
1939
|
+
dst_file.write_text(content, encoding="utf-8")
|
|
1940
|
+
files_copied.append(f".claude/commands/e2e/{e2e_file.name}")
|
|
1941
|
+
|
|
1942
|
+
# --- Skills (exclude PARENT_ONLY_SKILLS + capability-gated, D-CHILD-10) ---
|
|
1943
|
+
capabilities = blueprint.get("capabilities", {})
|
|
1944
|
+
skills_src = claude_src / "skills"
|
|
1945
|
+
if skills_src.exists():
|
|
1946
|
+
skills_dst = claude_dst / "skills"
|
|
1947
|
+
skills_dst.mkdir(parents=True, exist_ok=True)
|
|
1948
|
+
for skill_dir in sorted(skills_src.iterdir()):
|
|
1949
|
+
if not skill_dir.is_dir():
|
|
1950
|
+
continue
|
|
1951
|
+
# Check parent-only exclusion
|
|
1952
|
+
if skill_dir.name in PARENT_ONLY_SKILLS:
|
|
1953
|
+
files_skipped.append(f".claude/skills/{skill_dir.name}/")
|
|
1954
|
+
continue
|
|
1955
|
+
# Check capability-gated skills
|
|
1956
|
+
required_cap = SKILL_CAPABILITY_MAP.get(skill_dir.name)
|
|
1957
|
+
if required_cap and not capabilities.get(required_cap, False):
|
|
1958
|
+
files_skipped.append(f".claude/skills/{skill_dir.name}/")
|
|
1959
|
+
logger.debug(
|
|
1960
|
+
"Skipping skill %s — requires capability %s",
|
|
1961
|
+
skill_dir.name, required_cap,
|
|
1962
|
+
)
|
|
1963
|
+
continue
|
|
1964
|
+
dst_skill = skills_dst / skill_dir.name
|
|
1965
|
+
shutil.copytree(
|
|
1966
|
+
str(skill_dir), str(dst_skill), dirs_exist_ok=True
|
|
1967
|
+
)
|
|
1968
|
+
files_copied.append(f".claude/skills/{skill_dir.name}/")
|
|
1969
|
+
|
|
1970
|
+
# --- settings.json ---
|
|
1971
|
+
settings_src = claude_src / "settings.json"
|
|
1972
|
+
if settings_src.exists():
|
|
1973
|
+
settings_dst = claude_dst / "settings.json"
|
|
1974
|
+
content = settings_src.read_text(encoding="utf-8", errors="replace")
|
|
1975
|
+
content = content.replace("ICDEV", blueprint["app_name"])
|
|
1976
|
+
settings_dst.write_text(content, encoding="utf-8")
|
|
1977
|
+
files_copied.append(".claude/settings.json")
|
|
1978
|
+
|
|
1979
|
+
# --- file_access_tiers.yaml ---
|
|
1980
|
+
tiers_src = icdev_root / "args" / "file_access_tiers.yaml"
|
|
1981
|
+
if tiers_src.exists():
|
|
1982
|
+
tiers_dst = child_root / "args" / "file_access_tiers.yaml"
|
|
1983
|
+
tiers_dst.parent.mkdir(parents=True, exist_ok=True)
|
|
1984
|
+
shutil.copy2(str(tiers_src), str(tiers_dst))
|
|
1985
|
+
files_copied.append("args/file_access_tiers.yaml")
|
|
1986
|
+
|
|
1987
|
+
logger.info(
|
|
1988
|
+
"Step 9c: Claude Code config — %d files copied, %d excluded (parent-only)",
|
|
1989
|
+
len(files_copied), len(files_skipped)
|
|
1990
|
+
)
|
|
1991
|
+
return {
|
|
1992
|
+
"files_copied": files_copied,
|
|
1993
|
+
"files_skipped": files_skipped,
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
|
|
1997
|
+
def _adapt_pre_tool_use_for_child(content: str, blueprint: dict) -> str:
|
|
1998
|
+
"""Filter APPEND_ONLY_TABLES in pre_tool_use.py to child's DB schema.
|
|
1999
|
+
|
|
2000
|
+
Only keeps table names that exist in the child's enabled capability
|
|
2001
|
+
table groups. This prevents the hook from referencing tables that
|
|
2002
|
+
don't exist in the child's database.
|
|
2003
|
+
"""
|
|
2004
|
+
# Ensure project root is in sys.path for deferred import
|
|
2005
|
+
_project_root = str(Path(__file__).resolve().parent.parent.parent)
|
|
2006
|
+
if _project_root not in sys.path:
|
|
2007
|
+
sys.path.insert(0, _project_root)
|
|
2008
|
+
from icdev.tools.builder.db_init_generator import (
|
|
2009
|
+
CORE_TABLES, CAPABILITY_TABLE_MAP,
|
|
2010
|
+
)
|
|
2011
|
+
|
|
2012
|
+
# Collect all table names present in the child's schema
|
|
2013
|
+
child_tables: set = set(CORE_TABLES.keys())
|
|
2014
|
+
capabilities = blueprint.get("capabilities", {})
|
|
2015
|
+
for cap_name, enabled in capabilities.items():
|
|
2016
|
+
if enabled and cap_name in CAPABILITY_TABLE_MAP:
|
|
2017
|
+
child_tables.update(CAPABILITY_TABLE_MAP[cap_name].keys())
|
|
2018
|
+
|
|
2019
|
+
# Find the APPEND_ONLY_TABLES set in the hook and filter it
|
|
2020
|
+
# Pattern: APPEND_ONLY_TABLES = { ... }
|
|
2021
|
+
import re as _re
|
|
2022
|
+
pattern = _re.compile(
|
|
2023
|
+
r"(APPEND_ONLY_TABLES\s*=\s*\{)(.*?)(\})",
|
|
2024
|
+
_re.DOTALL,
|
|
2025
|
+
)
|
|
2026
|
+
match = pattern.search(content)
|
|
2027
|
+
if not match:
|
|
2028
|
+
return content # Hook doesn't have the expected pattern — return as-is
|
|
2029
|
+
|
|
2030
|
+
# Parse existing table names from the set literal
|
|
2031
|
+
raw_tables = match.group(2)
|
|
2032
|
+
table_names = _re.findall(r'"([^"]+)"', raw_tables)
|
|
2033
|
+
|
|
2034
|
+
# Keep only tables in the child's schema
|
|
2035
|
+
filtered = [t for t in table_names if t in child_tables]
|
|
2036
|
+
filtered_str = ",\n ".join(f'"{t}"' for t in sorted(filtered))
|
|
2037
|
+
|
|
2038
|
+
replacement = f"{match.group(1)}\n {filtered_str},\n{match.group(3)}"
|
|
2039
|
+
content = content[:match.start()] + replacement + content[match.end():]
|
|
2040
|
+
|
|
2041
|
+
return content
|
|
2042
|
+
|
|
2043
|
+
|
|
2044
|
+
# ============================================================
|
|
2045
|
+
# STEP 10: CSP MCP Server Configuration
|
|
2046
|
+
# ============================================================
|
|
2047
|
+
|
|
2048
|
+
|
|
2049
|
+
def step_10_csp_mcp_config(child_root: Path, blueprint: dict) -> dict:
|
|
2050
|
+
"""Step 10: Generate .mcp.json and CSP integration files."""
|
|
2051
|
+
app_name = blueprint["app_name"]
|
|
2052
|
+
agents = blueprint.get("agents", [])
|
|
2053
|
+
csp_servers = blueprint.get("csp_mcp_servers", [])
|
|
2054
|
+
cloud_config = blueprint.get("cloud_provider", {})
|
|
2055
|
+
provider = cloud_config.get("provider", "aws")
|
|
2056
|
+
|
|
2057
|
+
# Build .mcp.json combining agent MCP servers + CSP MCP servers
|
|
2058
|
+
mcp_config: Dict[str, Any] = {"mcpServers": {}}
|
|
2059
|
+
|
|
2060
|
+
# Agent MCP servers
|
|
2061
|
+
mcp_server_map = {
|
|
2062
|
+
"orchestrator": "core_server", "architect": "core_server",
|
|
2063
|
+
"builder": "builder_server", "compliance": "compliance_server",
|
|
2064
|
+
"security": "security_server", "knowledge": "knowledge_server",
|
|
2065
|
+
"monitor": "monitor_server",
|
|
2066
|
+
# D-CHILD-1: Enterprise agent MCP servers
|
|
2067
|
+
"requirements_analyst": "requirements_server",
|
|
2068
|
+
"supply_chain": "supply_chain_server",
|
|
2069
|
+
"simulation": "simulation_server",
|
|
2070
|
+
"devsecops_zta": "devsecops_server",
|
|
2071
|
+
}
|
|
2072
|
+
added_servers = set()
|
|
2073
|
+
for agent in agents:
|
|
2074
|
+
server_name = mcp_server_map.get(agent["name"])
|
|
2075
|
+
if server_name and server_name not in added_servers:
|
|
2076
|
+
added_servers.add(server_name)
|
|
2077
|
+
key = f"{app_name}-{server_name.replace('_', '-')}"
|
|
2078
|
+
mcp_config["mcpServers"][key] = {
|
|
2079
|
+
"command": "python",
|
|
2080
|
+
"args": [f"tools/mcp/{server_name}.py"],
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
# CSP MCP servers
|
|
2084
|
+
for server in csp_servers:
|
|
2085
|
+
server_name = server.get("name", "")
|
|
2086
|
+
if server_name:
|
|
2087
|
+
mcp_config["mcpServers"][server_name] = {
|
|
2088
|
+
"command": "npx",
|
|
2089
|
+
"args": ["-y", server_name],
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
mcp_path = child_root / ".mcp.json"
|
|
2093
|
+
mcp_path.write_text(json.dumps(mcp_config, indent=2), encoding="utf-8")
|
|
2094
|
+
|
|
2095
|
+
# Generate args/csp_mcp_config.yaml
|
|
2096
|
+
csp_config_lines = [
|
|
2097
|
+
f"# CSP MCP Configuration for {app_name}",
|
|
2098
|
+
f"provider: {provider}",
|
|
2099
|
+
f"region: {cloud_config.get('region', 'us-gov-west-1')}",
|
|
2100
|
+
f"govcloud: {str(cloud_config.get('govcloud', False)).lower()}",
|
|
2101
|
+
"mcp_servers:",
|
|
2102
|
+
]
|
|
2103
|
+
for server in csp_servers:
|
|
2104
|
+
name = server.get("name", "unknown")
|
|
2105
|
+
cat = server.get("category", "core")
|
|
2106
|
+
csp_config_lines.append(f" - name: \"{name}\"")
|
|
2107
|
+
csp_config_lines.append(f" category: \"{cat}\"")
|
|
2108
|
+
csp_config_lines.append(" transport: stdio")
|
|
2109
|
+
|
|
2110
|
+
csp_config_path = child_root / "args" / "csp_mcp_config.yaml"
|
|
2111
|
+
csp_config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
2112
|
+
csp_config_path.write_text("\n".join(csp_config_lines) + "\n", encoding="utf-8")
|
|
2113
|
+
|
|
2114
|
+
# Generate context/agentic/csp_integration.md
|
|
2115
|
+
integration_lines = [
|
|
2116
|
+
f"# CSP Integration — {app_name}",
|
|
2117
|
+
"",
|
|
2118
|
+
f"## Cloud Provider: {provider.upper()}",
|
|
2119
|
+
f"- **Region:** {cloud_config.get('region', 'us-gov-west-1')}",
|
|
2120
|
+
f"- **GovCloud:** {'Yes' if cloud_config.get('govcloud') else 'No'}",
|
|
2121
|
+
"",
|
|
2122
|
+
"## Available MCP Servers",
|
|
2123
|
+
"",
|
|
2124
|
+
"| Server | Category | Description |",
|
|
2125
|
+
"|--------|----------|-------------|",
|
|
2126
|
+
]
|
|
2127
|
+
for server in csp_servers:
|
|
2128
|
+
integration_lines.append(
|
|
2129
|
+
f"| {server.get('name', '')} | {server.get('category', '')} "
|
|
2130
|
+
f"| {server.get('description', '')} |")
|
|
2131
|
+
|
|
2132
|
+
integration_lines.extend([
|
|
2133
|
+
"",
|
|
2134
|
+
"## Usage",
|
|
2135
|
+
"",
|
|
2136
|
+
"These MCP servers are configured in `.mcp.json` and available to Claude Code.",
|
|
2137
|
+
"Use them for cloud-native operations specific to the target deployment environment.",
|
|
2138
|
+
"",
|
|
2139
|
+
f"For capabilities not available via {provider.upper()} MCP servers, use the A2A",
|
|
2140
|
+
"callback to parent ICDEV.",
|
|
2141
|
+
])
|
|
2142
|
+
|
|
2143
|
+
integration_path = child_root / "context" / "agentic" / "csp_integration.md"
|
|
2144
|
+
integration_path.parent.mkdir(parents=True, exist_ok=True)
|
|
2145
|
+
integration_path.write_text("\n".join(integration_lines) + "\n", encoding="utf-8")
|
|
2146
|
+
|
|
2147
|
+
logger.info("Step 10: CSP MCP config — %d servers for %s",
|
|
2148
|
+
len(csp_servers), provider)
|
|
2149
|
+
return {
|
|
2150
|
+
"mcp_json": str(mcp_path),
|
|
2151
|
+
"csp_config": str(csp_config_path),
|
|
2152
|
+
"csp_integration": str(integration_path),
|
|
2153
|
+
"total_mcp_servers": len(mcp_config["mcpServers"]),
|
|
2154
|
+
"csp_servers": len(csp_servers),
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
|
|
2158
|
+
# ============================================================
|
|
2159
|
+
# STEP 11b: README Generation
|
|
2160
|
+
# ============================================================
|
|
2161
|
+
|
|
2162
|
+
# Human-readable capability descriptions for the README "sell" section
|
|
2163
|
+
CAP_DESCRIPTIONS: Dict[str, str] = {
|
|
2164
|
+
"compliance": "ATO Compliance — SSP, POAM, STIG, SBOM, CUI markings, NIST 800-53, FedRAMP, CMMC",
|
|
2165
|
+
"security": "Security Scanning — SAST (Bandit), dependency audit, secret detection, container scanning",
|
|
2166
|
+
"testing": "Testing Framework — pytest unit + behave BDD + Playwright E2E + security gates",
|
|
2167
|
+
"multi_agent": "Multi-Agent Architecture — A2A protocol, agent cards, MCP servers, domain routing",
|
|
2168
|
+
"cicd": "CI/CD Integration — GitHub Actions + GitLab CI, webhooks, poll triggers, slash commands",
|
|
2169
|
+
"mbse": "Model-Based Systems Engineering — SysML, DOORS NG, digital thread, model-code sync",
|
|
2170
|
+
"monitoring": "Production Monitoring — Log analysis, metrics, alerts, health checks, self-healing",
|
|
2171
|
+
"dashboard": "Web Dashboard — Flask SSR, real-time updates, role-based views, accessibility",
|
|
2172
|
+
"knowledge": "Knowledge Base — Pattern detection, self-healing, ML recommendations",
|
|
2173
|
+
"modernization": "App Modernization — 7R assessment, version/framework migration, strangler fig",
|
|
2174
|
+
"supply_chain": "Supply Chain Intelligence — Dependency graph, SBOM aggregation, ISA lifecycle, CVE triage",
|
|
2175
|
+
"simulation": "Digital Program Twin — 6-dimension simulation, Monte Carlo, COA generation",
|
|
2176
|
+
"devsecops": "DevSecOps — Pipeline security, policy-as-code (Kyverno/OPA), image attestation",
|
|
2177
|
+
"zta": "Zero Trust Architecture — 7-pillar maturity, NIST 800-207, service mesh, mTLS",
|
|
2178
|
+
"mosa": "DoD MOSA — Modular Open Systems, ICD/TSP generation, modularity analysis",
|
|
2179
|
+
"marketplace": "GOTCHA Marketplace — Federated asset sharing, 7-gate security pipeline",
|
|
2180
|
+
"innovation": "Innovation Engine — Autonomous self-improvement, web scanning, trend detection",
|
|
2181
|
+
"translation": "Cross-Language Translation — 5-phase hybrid pipeline, 30 language pairs",
|
|
2182
|
+
"observability": "Observability & XAI — Distributed tracing, provenance, AgentSHAP attribution",
|
|
2183
|
+
"ai_transparency": "AI Transparency — Model/system cards, AI inventory, fairness, confabulation detection",
|
|
2184
|
+
"ai_accountability": "AI Accountability — Oversight plans, CAIO designation, incident response",
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
|
|
2188
|
+
def _generate_readme(child_root: Path, blueprint: dict) -> dict:
|
|
2189
|
+
"""Generate README.md that tells the ICDEV story and lists capabilities used.
|
|
2190
|
+
|
|
2191
|
+
Args:
|
|
2192
|
+
child_root: Root directory of the generated child app.
|
|
2193
|
+
blueprint: Blueprint dict from app_blueprint.py.
|
|
2194
|
+
|
|
2195
|
+
Returns:
|
|
2196
|
+
Dict with readme_path and sections_count.
|
|
2197
|
+
"""
|
|
2198
|
+
app_name = blueprint["app_name"]
|
|
2199
|
+
classification = blueprint.get("classification", "CUI")
|
|
2200
|
+
impact_level = blueprint.get("impact_level", "IL4")
|
|
2201
|
+
demo_mode = blueprint.get("demo_mode", False)
|
|
2202
|
+
agents = blueprint.get("agents", [])
|
|
2203
|
+
capabilities = blueprint.get("capabilities", {})
|
|
2204
|
+
scorecard = blueprint.get("fitness_scorecard", {})
|
|
2205
|
+
|
|
2206
|
+
active_caps = sorted(k for k, v in capabilities.items() if v)
|
|
2207
|
+
description = (
|
|
2208
|
+
blueprint.get("description", "")
|
|
2209
|
+
or blueprint.get("purpose", "")
|
|
2210
|
+
or scorecard.get("spec", "")
|
|
2211
|
+
)
|
|
2212
|
+
|
|
2213
|
+
sections: list = []
|
|
2214
|
+
|
|
2215
|
+
# Demo banner
|
|
2216
|
+
if demo_mode:
|
|
2217
|
+
sections.append(
|
|
2218
|
+
"> **DEMONSTRATION ONLY** — This application is a demo build. "
|
|
2219
|
+
"It uses PUBLIC classification and must NOT be used for operational, "
|
|
2220
|
+
"classified, or sensitive data.\n"
|
|
2221
|
+
)
|
|
2222
|
+
|
|
2223
|
+
# Title + ICDEV intro
|
|
2224
|
+
sections.append(f"# {app_name}\n")
|
|
2225
|
+
sections.append(
|
|
2226
|
+
f"**Built with [ICDEV](https://github.com/icdev) — the Intelligent "
|
|
2227
|
+
f"Coding Development platform.**\n\n"
|
|
2228
|
+
f"ICDEV is a meta-builder that autonomously constructs Gov/DoD applications "
|
|
2229
|
+
f"using the GOTCHA framework (Goals, Orchestration, Tools, Args, Context, "
|
|
2230
|
+
f"Hard Prompts) and the ATLAS workflow (Architect → Trace → Link → Assemble "
|
|
2231
|
+
f"→ Stress-test). It handles the full SDLC with TDD/BDD, NIST 800-53 RMF "
|
|
2232
|
+
f"compliance, and self-healing capabilities.\n"
|
|
2233
|
+
)
|
|
2234
|
+
|
|
2235
|
+
# Classification badge
|
|
2236
|
+
sections.append(
|
|
2237
|
+
f"**Classification:** `{classification}` | **Impact Level:** `{impact_level}`\n"
|
|
2238
|
+
)
|
|
2239
|
+
|
|
2240
|
+
# Purpose
|
|
2241
|
+
if description:
|
|
2242
|
+
sections.append(f"## Purpose\n\n{description}\n")
|
|
2243
|
+
|
|
2244
|
+
# Architecture
|
|
2245
|
+
sections.append(
|
|
2246
|
+
"## Architecture\n\n"
|
|
2247
|
+
"This application follows the **GOTCHA 6-Layer Framework**:\n\n"
|
|
2248
|
+
"| Layer | Role |\n"
|
|
2249
|
+
"|-------|------|\n"
|
|
2250
|
+
"| **Goals** | Process definitions — what to achieve, which tools, expected outputs |\n"
|
|
2251
|
+
"| **Orchestration** | AI reads goals → decides tool order → applies args → references context |\n"
|
|
2252
|
+
"| **Tools** | Python scripts, one job each. Deterministic. |\n"
|
|
2253
|
+
"| **Args** | YAML/JSON behavior settings |\n"
|
|
2254
|
+
"| **Context** | Static reference material |\n"
|
|
2255
|
+
"| **Hard Prompts** | Reusable LLM instruction templates |\n"
|
|
2256
|
+
)
|
|
2257
|
+
|
|
2258
|
+
# ICDEV Capabilities Used — the "sell" section
|
|
2259
|
+
if active_caps:
|
|
2260
|
+
sections.append("## ICDEV Capabilities Used\n")
|
|
2261
|
+
sections.append(
|
|
2262
|
+
"This application leverages the following ICDEV capabilities:\n"
|
|
2263
|
+
)
|
|
2264
|
+
for cap in active_caps:
|
|
2265
|
+
desc = CAP_DESCRIPTIONS.get(cap, cap.replace("_", " ").title())
|
|
2266
|
+
sections.append(f"- **{cap}** — {desc}")
|
|
2267
|
+
sections.append("") # blank line
|
|
2268
|
+
|
|
2269
|
+
# Agents
|
|
2270
|
+
if agents:
|
|
2271
|
+
sections.append("## Agents\n")
|
|
2272
|
+
sections.append("| Agent | Port | Role |")
|
|
2273
|
+
sections.append("|-------|------|------|")
|
|
2274
|
+
for a in agents:
|
|
2275
|
+
name = a.get("name", "unknown")
|
|
2276
|
+
port = a.get("port", "?")
|
|
2277
|
+
role = a.get("role", "")
|
|
2278
|
+
sections.append(f"| {name.title()} | {port} | {role} |")
|
|
2279
|
+
sections.append("")
|
|
2280
|
+
|
|
2281
|
+
# Compliance Posture
|
|
2282
|
+
if capabilities.get("compliance", False):
|
|
2283
|
+
sections.append(
|
|
2284
|
+
"## Compliance Posture\n\n"
|
|
2285
|
+
"This application includes compliance tooling for:\n"
|
|
2286
|
+
"- NIST 800-53 Rev 5 control mapping\n"
|
|
2287
|
+
"- FedRAMP Moderate/High baselines\n"
|
|
2288
|
+
"- CMMC Level 2/3 practices\n"
|
|
2289
|
+
"- ATO artifacts: SSP, POAM, STIG checklist, SBOM\n"
|
|
2290
|
+
"- CUI markings applied at generation time\n"
|
|
2291
|
+
)
|
|
2292
|
+
|
|
2293
|
+
# Quick Start
|
|
2294
|
+
quick_start_cmds = [
|
|
2295
|
+
"# Initialize database",
|
|
2296
|
+
"python tools/db/init_db.py",
|
|
2297
|
+
"",
|
|
2298
|
+
"# Load memory",
|
|
2299
|
+
"python tools/memory/memory_read.py --format markdown",
|
|
2300
|
+
]
|
|
2301
|
+
if capabilities.get("dashboard", False):
|
|
2302
|
+
quick_start_cmds += ["", "# Start dashboard", "python tools/dashboard/app.py"]
|
|
2303
|
+
if capabilities.get("testing", False):
|
|
2304
|
+
quick_start_cmds += ["", "# Run tests", "pytest tests/ -v"]
|
|
2305
|
+
|
|
2306
|
+
sections.append("## Quick Start\n")
|
|
2307
|
+
sections.append("```bash")
|
|
2308
|
+
sections.extend(quick_start_cmds)
|
|
2309
|
+
sections.append("```\n")
|
|
2310
|
+
|
|
2311
|
+
# Footer
|
|
2312
|
+
gen_date = blueprint.get("generated_at", datetime.now(tz=timezone.utc).isoformat())
|
|
2313
|
+
sections.append("---\n")
|
|
2314
|
+
sections.append(
|
|
2315
|
+
f"*Generated by ICDEV on {gen_date[:10]}*\n"
|
|
2316
|
+
)
|
|
2317
|
+
|
|
2318
|
+
readme_content = "\n".join(sections)
|
|
2319
|
+
readme_path = child_root / "README.md"
|
|
2320
|
+
readme_path.write_text(readme_content, encoding="utf-8")
|
|
2321
|
+
|
|
2322
|
+
logger.info("Step 11b: README.md generated (%d sections)", len(sections))
|
|
2323
|
+
return {"readme_path": str(readme_path), "sections_count": len(sections)}
|
|
2324
|
+
|
|
2325
|
+
|
|
2326
|
+
# ============================================================
|
|
2327
|
+
# STEP 11: Dynamic CLAUDE.md
|
|
2328
|
+
# ============================================================
|
|
2329
|
+
|
|
2330
|
+
|
|
2331
|
+
def step_11_dynamic_claude_md(child_root: Path, blueprint: dict) -> dict:
|
|
2332
|
+
"""Step 11: Generate dynamic CLAUDE.md using claude_md_generator."""
|
|
2333
|
+
generate_fn = _import_sister("claude_md_generator", "generate_claude_md")
|
|
2334
|
+
|
|
2335
|
+
if generate_fn:
|
|
2336
|
+
content = generate_fn(blueprint)
|
|
2337
|
+
method = "claude_md_generator"
|
|
2338
|
+
else:
|
|
2339
|
+
# Fallback: minimal CLAUDE.md
|
|
2340
|
+
app_name = blueprint["app_name"]
|
|
2341
|
+
agents = blueprint.get("agents", [])
|
|
2342
|
+
content = f"""# CLAUDE.md
|
|
2343
|
+
|
|
2344
|
+
This file provides guidance to Claude Code when working with {app_name}.
|
|
2345
|
+
|
|
2346
|
+
---
|
|
2347
|
+
|
|
2348
|
+
## Architecture: GOTCHA Framework
|
|
2349
|
+
|
|
2350
|
+
This is a 6-layer agentic system: Goals, Orchestration, Tools, Args, Context, Hard Prompts.
|
|
2351
|
+
|
|
2352
|
+
### Key Files
|
|
2353
|
+
- `goals/manifest.md` — Index of all goal workflows
|
|
2354
|
+
- `tools/manifest.md` — Master list of all tools
|
|
2355
|
+
- `memory/MEMORY.md` — Long-term facts and preferences
|
|
2356
|
+
|
|
2357
|
+
### Session Start Protocol
|
|
2358
|
+
1. Read `memory/MEMORY.md`
|
|
2359
|
+
2. Read today's daily log
|
|
2360
|
+
3. Or run: `python tools/memory/memory_read.py --format markdown`
|
|
2361
|
+
|
|
2362
|
+
---
|
|
2363
|
+
|
|
2364
|
+
## {app_name} System
|
|
2365
|
+
|
|
2366
|
+
### Agents ({len(agents)})
|
|
2367
|
+
|
|
2368
|
+
| Agent | Port | Role |
|
|
2369
|
+
|-------|------|------|
|
|
2370
|
+
"""
|
|
2371
|
+
for a in agents:
|
|
2372
|
+
content += f"| {a['name']} | {a['port']} | {a.get('role', '')} |\n"
|
|
2373
|
+
|
|
2374
|
+
content += """
|
|
2375
|
+
---
|
|
2376
|
+
|
|
2377
|
+
## Guardrails
|
|
2378
|
+
|
|
2379
|
+
- Always check `tools/manifest.md` before writing a new script
|
|
2380
|
+
- Verify tool output format before chaining
|
|
2381
|
+
- **This application CANNOT generate child applications**
|
|
2382
|
+
- Audit trail is append-only — NEVER add UPDATE/DELETE operations
|
|
2383
|
+
|
|
2384
|
+
---
|
|
2385
|
+
|
|
2386
|
+
## Continuous Improvement
|
|
2387
|
+
|
|
2388
|
+
Every failure strengthens the system. Be direct. Be reliable. Get it done.
|
|
2389
|
+
"""
|
|
2390
|
+
method = "fallback"
|
|
2391
|
+
|
|
2392
|
+
claude_md_path = child_root / "CLAUDE.md"
|
|
2393
|
+
claude_md_path.write_text(content, encoding="utf-8")
|
|
2394
|
+
|
|
2395
|
+
line_count = content.count("\n") + 1
|
|
2396
|
+
logger.info("Step 11: CLAUDE.md generated (%d lines, method=%s)",
|
|
2397
|
+
line_count, method)
|
|
2398
|
+
return {"claude_md_path": str(claude_md_path), "lines": line_count, "method": method}
|
|
2399
|
+
|
|
2400
|
+
|
|
2401
|
+
# ============================================================
|
|
2402
|
+
# STEP 12: Audit + Registration
|
|
2403
|
+
# ============================================================
|
|
2404
|
+
|
|
2405
|
+
|
|
2406
|
+
def step_12_audit_and_registration(
|
|
2407
|
+
child_root: Path, blueprint: dict, db_path: Path
|
|
2408
|
+
) -> dict:
|
|
2409
|
+
"""Step 12: Log to ICDEV audit trail and register in child_app_registry."""
|
|
2410
|
+
app_name = blueprint["app_name"]
|
|
2411
|
+
blueprint_hash = blueprint.get("blueprint_hash", "")
|
|
2412
|
+
|
|
2413
|
+
# Audit log
|
|
2414
|
+
audit_log_event(
|
|
2415
|
+
event_type="child_app_generated",
|
|
2416
|
+
actor="child-app-generator",
|
|
2417
|
+
action=f"Generated child app '{app_name}' at {child_root}",
|
|
2418
|
+
project_id=blueprint.get("fitness_scorecard", {}).get("project_id", ""),
|
|
2419
|
+
details=json.dumps({
|
|
2420
|
+
"app_name": app_name,
|
|
2421
|
+
"blueprint_hash": blueprint_hash,
|
|
2422
|
+
"agents": len(blueprint.get("agents", [])),
|
|
2423
|
+
"capabilities": sum(1 for v in blueprint.get("capabilities", {}).values() if v),
|
|
2424
|
+
}),
|
|
2425
|
+
)
|
|
2426
|
+
|
|
2427
|
+
# Register in child_app_registry table
|
|
2428
|
+
registered = False
|
|
2429
|
+
try:
|
|
2430
|
+
if db_path.exists():
|
|
2431
|
+
conn = sqlite3.connect(str(db_path))
|
|
2432
|
+
conn.execute(
|
|
2433
|
+
"INSERT OR REPLACE INTO child_app_registry "
|
|
2434
|
+
"(id, parent_project_id, child_name, child_path, blueprint_hash, "
|
|
2435
|
+
"capabilities, agent_count, cloud_provider, callback_url, classification) "
|
|
2436
|
+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
2437
|
+
(
|
|
2438
|
+
str(uuid.uuid4()),
|
|
2439
|
+
blueprint.get("fitness_scorecard", {}).get("project_id", ""),
|
|
2440
|
+
app_name,
|
|
2441
|
+
str(child_root),
|
|
2442
|
+
blueprint_hash,
|
|
2443
|
+
json.dumps(blueprint.get("capabilities", {})),
|
|
2444
|
+
len(blueprint.get("agents", [])),
|
|
2445
|
+
blueprint.get("cloud_provider", {}).get("provider", "aws"),
|
|
2446
|
+
blueprint.get("parent_callback", {}).get("url", ""),
|
|
2447
|
+
blueprint.get("classification", "CUI"),
|
|
2448
|
+
),
|
|
2449
|
+
)
|
|
2450
|
+
conn.commit()
|
|
2451
|
+
conn.close()
|
|
2452
|
+
registered = True
|
|
2453
|
+
logger.info("Step 12: Registered child app in ICDEV database")
|
|
2454
|
+
except Exception as e:
|
|
2455
|
+
logger.warning("Step 12: Failed to register in DB: %s", e)
|
|
2456
|
+
|
|
2457
|
+
# Phase 36 integration: write genome manifest to child directory
|
|
2458
|
+
genome_version = None
|
|
2459
|
+
try:
|
|
2460
|
+
if db_path.exists():
|
|
2461
|
+
gconn = sqlite3.connect(str(db_path))
|
|
2462
|
+
gconn.row_factory = sqlite3.Row
|
|
2463
|
+
row = gconn.execute(
|
|
2464
|
+
"SELECT version, content_hash, genome_data "
|
|
2465
|
+
"FROM genome_versions ORDER BY created_at DESC LIMIT 1"
|
|
2466
|
+
).fetchone()
|
|
2467
|
+
if row:
|
|
2468
|
+
genome_version = row["version"]
|
|
2469
|
+
genome_manifest = {
|
|
2470
|
+
"parent_id": blueprint.get("fitness_scorecard", {}).get(
|
|
2471
|
+
"project_id", "icdev-parent"
|
|
2472
|
+
),
|
|
2473
|
+
"genome_version": row["version"],
|
|
2474
|
+
"content_hash": row["content_hash"],
|
|
2475
|
+
"capabilities_baseline": json.loads(row["genome_data"])
|
|
2476
|
+
if row["genome_data"] else {},
|
|
2477
|
+
"generation_timestamp": datetime.now(tz=timezone.utc).isoformat(),
|
|
2478
|
+
"grandchild_prevention": True,
|
|
2479
|
+
}
|
|
2480
|
+
gm_path = child_root / "data" / "genome_manifest.json"
|
|
2481
|
+
gm_path.parent.mkdir(parents=True, exist_ok=True)
|
|
2482
|
+
gm_path.write_text(
|
|
2483
|
+
json.dumps(genome_manifest, indent=2), encoding="utf-8"
|
|
2484
|
+
)
|
|
2485
|
+
logger.info(
|
|
2486
|
+
"Step 12: Wrote genome manifest (v%s) to child",
|
|
2487
|
+
genome_version,
|
|
2488
|
+
)
|
|
2489
|
+
gconn.close()
|
|
2490
|
+
except Exception as e:
|
|
2491
|
+
logger.warning("Step 12: Genome manifest write failed: %s", e)
|
|
2492
|
+
|
|
2493
|
+
# Generate summary report in child app
|
|
2494
|
+
summary = {
|
|
2495
|
+
"app_name": app_name,
|
|
2496
|
+
"child_root": str(child_root),
|
|
2497
|
+
"blueprint_hash": blueprint_hash,
|
|
2498
|
+
"agents": len(blueprint.get("agents", [])),
|
|
2499
|
+
"capabilities": {k: v for k, v in blueprint.get("capabilities", {}).items() if v},
|
|
2500
|
+
"cloud_provider": blueprint.get("cloud_provider", {}).get("provider", "aws"),
|
|
2501
|
+
"classification": blueprint.get("classification", "CUI"),
|
|
2502
|
+
"genome_version": genome_version,
|
|
2503
|
+
"generated_at": datetime.now(tz=timezone.utc).isoformat(),
|
|
2504
|
+
"generated_by": "icdev/child_app_generator",
|
|
2505
|
+
}
|
|
2506
|
+
summary_path = child_root / "data" / "generation_summary.json"
|
|
2507
|
+
summary_path.parent.mkdir(parents=True, exist_ok=True)
|
|
2508
|
+
summary_path.write_text(json.dumps(summary, indent=2), encoding="utf-8")
|
|
2509
|
+
|
|
2510
|
+
logger.info("Step 12: Audit complete, registered=%s", registered)
|
|
2511
|
+
return {"registered": registered, "summary_path": str(summary_path)}
|
|
2512
|
+
|
|
2513
|
+
|
|
2514
|
+
# ============================================================
|
|
2515
|
+
# STEP 13: Production Audit
|
|
2516
|
+
# ============================================================
|
|
2517
|
+
|
|
2518
|
+
|
|
2519
|
+
def step_13_production_audit(child_root: Path, blueprint: dict) -> dict:
|
|
2520
|
+
"""Run production audit on the generated child app.
|
|
2521
|
+
|
|
2522
|
+
Invokes ICDEV's production_audit.py as a subprocess with the child app
|
|
2523
|
+
as the working directory, then stores the results in the child app's
|
|
2524
|
+
data directory.
|
|
2525
|
+
|
|
2526
|
+
Args:
|
|
2527
|
+
child_root: Root directory of the child app.
|
|
2528
|
+
blueprint: Blueprint dict.
|
|
2529
|
+
|
|
2530
|
+
Returns:
|
|
2531
|
+
Dict with audit results summary.
|
|
2532
|
+
"""
|
|
2533
|
+
audit_script = BASE_DIR / "tools" / "testing" / "production_audit.py"
|
|
2534
|
+
if not audit_script.exists():
|
|
2535
|
+
logger.warning("Step 13: production_audit.py not found, skipping")
|
|
2536
|
+
return {"skipped": True, "reason": "audit script not found"}
|
|
2537
|
+
|
|
2538
|
+
try:
|
|
2539
|
+
env = {**os.environ, "PYTHONDONTWRITEBYTECODE": "1"}
|
|
2540
|
+
result = subprocess.run(
|
|
2541
|
+
[sys.executable, str(audit_script), "--json"],
|
|
2542
|
+
capture_output=True, text=True, cwd=str(child_root),
|
|
2543
|
+
timeout=120, env=env,
|
|
2544
|
+
)
|
|
2545
|
+
|
|
2546
|
+
# Parse JSON output
|
|
2547
|
+
audit_data = {}
|
|
2548
|
+
if result.stdout.strip():
|
|
2549
|
+
try:
|
|
2550
|
+
audit_data = json.loads(result.stdout.strip())
|
|
2551
|
+
except json.JSONDecodeError:
|
|
2552
|
+
audit_data = {"raw_output": result.stdout[:2000]}
|
|
2553
|
+
|
|
2554
|
+
# Store audit results in child app
|
|
2555
|
+
data_dir = child_root / "data"
|
|
2556
|
+
data_dir.mkdir(parents=True, exist_ok=True)
|
|
2557
|
+
audit_path = data_dir / "production_audit.json"
|
|
2558
|
+
audit_path.write_text(
|
|
2559
|
+
json.dumps(audit_data, indent=2, default=str), encoding="utf-8"
|
|
2560
|
+
)
|
|
2561
|
+
|
|
2562
|
+
# Summary
|
|
2563
|
+
checks = audit_data.get("checks", [])
|
|
2564
|
+
passed = sum(1 for c in checks if c.get("status") == "pass")
|
|
2565
|
+
failed = sum(1 for c in checks if c.get("status") == "fail")
|
|
2566
|
+
total = len(checks)
|
|
2567
|
+
|
|
2568
|
+
logger.info(
|
|
2569
|
+
"Step 13: Production audit complete — %d/%d passed, %d failed",
|
|
2570
|
+
passed, total, failed
|
|
2571
|
+
)
|
|
2572
|
+
return {
|
|
2573
|
+
"audit_path": str(audit_path),
|
|
2574
|
+
"total_checks": total,
|
|
2575
|
+
"passed": passed,
|
|
2576
|
+
"failed": failed,
|
|
2577
|
+
"exit_code": result.returncode,
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
except subprocess.TimeoutExpired:
|
|
2581
|
+
logger.warning("Step 13: Production audit timed out (120s)")
|
|
2582
|
+
return {"skipped": True, "reason": "timeout"}
|
|
2583
|
+
except Exception as e:
|
|
2584
|
+
logger.warning("Step 13: Production audit failed: %s", e)
|
|
2585
|
+
return {"skipped": True, "reason": str(e)}
|
|
2586
|
+
|
|
2587
|
+
|
|
2588
|
+
# ============================================================
|
|
2589
|
+
# STEP 14: GOTCHA Compliance Validation
|
|
2590
|
+
# ============================================================
|
|
2591
|
+
|
|
2592
|
+
|
|
2593
|
+
def step_14_gotcha_validation(child_root: Path, blueprint: dict) -> dict:
|
|
2594
|
+
"""Step 14: Validate GOTCHA framework compliance of generated child app.
|
|
2595
|
+
|
|
2596
|
+
Runs the gotcha_validator to verify all 6 GOTCHA layers are populated
|
|
2597
|
+
and ATLAS workflow structure is present. This ensures child apps follow
|
|
2598
|
+
the GOTCHA framework as mandated by build_app.md.
|
|
2599
|
+
|
|
2600
|
+
BMAD-adapted: adversarial validation — assumes the build is incomplete
|
|
2601
|
+
until proven otherwise.
|
|
2602
|
+
"""
|
|
2603
|
+
validate_fn = _import_sister("gotcha_validator", "validate")
|
|
2604
|
+
|
|
2605
|
+
if validate_fn:
|
|
2606
|
+
report = validate_fn(child_root)
|
|
2607
|
+
report_dict = report.to_dict()
|
|
2608
|
+
|
|
2609
|
+
# Store validation results in child app
|
|
2610
|
+
data_dir = child_root / "data"
|
|
2611
|
+
data_dir.mkdir(parents=True, exist_ok=True)
|
|
2612
|
+
report_path = data_dir / "gotcha_validation.json"
|
|
2613
|
+
report_path.write_text(
|
|
2614
|
+
json.dumps(report_dict, indent=2, default=str), encoding="utf-8"
|
|
2615
|
+
)
|
|
2616
|
+
|
|
2617
|
+
# Log warnings for failed checks
|
|
2618
|
+
for check in report_dict.get("checks", []):
|
|
2619
|
+
if check.get("status") == "fail":
|
|
2620
|
+
logger.warning(
|
|
2621
|
+
"GOTCHA validation FAIL: %s — %s (fix: %s)",
|
|
2622
|
+
check.get("check_id"), check.get("message"),
|
|
2623
|
+
check.get("fix_suggestion"),
|
|
2624
|
+
)
|
|
2625
|
+
elif check.get("status") == "warn":
|
|
2626
|
+
logger.info(
|
|
2627
|
+
"GOTCHA validation WARN: %s — %s",
|
|
2628
|
+
check.get("check_id"), check.get("message"),
|
|
2629
|
+
)
|
|
2630
|
+
|
|
2631
|
+
logger.info(
|
|
2632
|
+
"Step 14: GOTCHA validation — score %.0f%% (%d/%d passed, %d failed)",
|
|
2633
|
+
report_dict.get("score", 0) * 100,
|
|
2634
|
+
report_dict.get("passed_checks", 0),
|
|
2635
|
+
report_dict.get("total_checks", 0),
|
|
2636
|
+
report_dict.get("failed_checks", 0),
|
|
2637
|
+
)
|
|
2638
|
+
return {
|
|
2639
|
+
"report_path": str(report_path),
|
|
2640
|
+
"overall_pass": report_dict.get("overall_pass", False),
|
|
2641
|
+
"score": report_dict.get("score", 0),
|
|
2642
|
+
"passed": report_dict.get("passed_checks", 0),
|
|
2643
|
+
"failed": report_dict.get("failed_checks", 0),
|
|
2644
|
+
"warned": report_dict.get("warned_checks", 0),
|
|
2645
|
+
"layer_summary": report_dict.get("layer_summary", {}),
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
# Fallback: basic directory existence check
|
|
2649
|
+
logger.warning("Step 14: gotcha_validator not available, running basic check")
|
|
2650
|
+
gotcha_dirs = ["goals", "tools", "args", "context", "hardprompts", "memory"]
|
|
2651
|
+
present = [d for d in gotcha_dirs if (child_root / d).is_dir()]
|
|
2652
|
+
missing = [d for d in gotcha_dirs if d not in present]
|
|
2653
|
+
|
|
2654
|
+
if missing:
|
|
2655
|
+
logger.warning("Step 14: Missing GOTCHA directories: %s", ", ".join(missing))
|
|
2656
|
+
|
|
2657
|
+
return {
|
|
2658
|
+
"method": "fallback",
|
|
2659
|
+
"overall_pass": len(missing) == 0,
|
|
2660
|
+
"present": present,
|
|
2661
|
+
"missing": missing,
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
|
|
2665
|
+
# ============================================================
|
|
2666
|
+
# MAIN ORCHESTRATOR
|
|
2667
|
+
# ============================================================
|
|
2668
|
+
|
|
2669
|
+
|
|
2670
|
+
def generate_child_app(
|
|
2671
|
+
blueprint: dict,
|
|
2672
|
+
project_path: str,
|
|
2673
|
+
name: str,
|
|
2674
|
+
icdev_root: Optional[Path] = None,
|
|
2675
|
+
db_path: Optional[Path] = None,
|
|
2676
|
+
) -> dict:
|
|
2677
|
+
"""Generate a complete child application from a blueprint.
|
|
2678
|
+
|
|
2679
|
+
Executes 17 steps sequentially (12 core + 9b license + 9c claude config +
|
|
2680
|
+
11b README + 13 audit + 14 GOTCHA validation), collecting results from each.
|
|
2681
|
+
|
|
2682
|
+
Args:
|
|
2683
|
+
blueprint: Complete blueprint dict from app_blueprint.py.
|
|
2684
|
+
project_path: Parent directory for the child app.
|
|
2685
|
+
name: Child application name.
|
|
2686
|
+
icdev_root: Path to ICDEV project root (auto-detected if None).
|
|
2687
|
+
db_path: Path to ICDEV database (auto-detected if None).
|
|
2688
|
+
|
|
2689
|
+
Returns:
|
|
2690
|
+
Summary dict with step results and overall status.
|
|
2691
|
+
"""
|
|
2692
|
+
child_root = Path(project_path) / name
|
|
2693
|
+
icdev_root = icdev_root or BASE_DIR
|
|
2694
|
+
db_path = db_path or DB_PATH
|
|
2695
|
+
|
|
2696
|
+
logger.info("Generating child app '%s' at %s", name, child_root)
|
|
2697
|
+
start_time = datetime.now(tz=timezone.utc)
|
|
2698
|
+
|
|
2699
|
+
results: Dict[str, Any] = {
|
|
2700
|
+
"app_name": name,
|
|
2701
|
+
"child_root": str(child_root),
|
|
2702
|
+
"icdev_root": str(icdev_root),
|
|
2703
|
+
"steps": {},
|
|
2704
|
+
"status": "success",
|
|
2705
|
+
"errors": [],
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
# Define steps with their signatures
|
|
2709
|
+
steps: List[Tuple[str, Any]] = [
|
|
2710
|
+
("01_directory_tree", lambda: step_01_create_directory_tree(child_root, blueprint)),
|
|
2711
|
+
("02_copy_adapt_tools", lambda: step_02_copy_and_adapt_tools(child_root, blueprint, icdev_root)),
|
|
2712
|
+
("03_agent_infra", lambda: step_03_agent_infrastructure(child_root, blueprint, icdev_root)),
|
|
2713
|
+
("04_memory_bootstrap", lambda: step_04_memory_bootstrap(child_root, blueprint)),
|
|
2714
|
+
("05_db_init_script", lambda: step_05_db_init_script(child_root, blueprint)),
|
|
2715
|
+
("06_goals_hardprompts", lambda: step_06_goals_and_hardprompts(child_root, blueprint, icdev_root)),
|
|
2716
|
+
("07_args_context", lambda: step_07_args_and_context(child_root, blueprint, icdev_root)),
|
|
2717
|
+
("08_a2a_callback", lambda: step_08_a2a_callback_client(child_root, blueprint)),
|
|
2718
|
+
("09_cicd_setup", lambda: step_09_cicd_setup(child_root, blueprint, icdev_root)),
|
|
2719
|
+
("09b_license", lambda: _copy_license_files(child_root, blueprint, icdev_root)),
|
|
2720
|
+
("09c_claude_config", lambda: step_09c_claude_code_config(child_root, blueprint, icdev_root)),
|
|
2721
|
+
("10_csp_mcp_config", lambda: step_10_csp_mcp_config(child_root, blueprint)),
|
|
2722
|
+
("11_claude_md", lambda: step_11_dynamic_claude_md(child_root, blueprint)),
|
|
2723
|
+
("11b_readme", lambda: _generate_readme(child_root, blueprint)),
|
|
2724
|
+
("12_audit_register", lambda: step_12_audit_and_registration(child_root, blueprint, db_path)),
|
|
2725
|
+
("13_production_audit", lambda: step_13_production_audit(child_root, blueprint)),
|
|
2726
|
+
("14_gotcha_validation", lambda: step_14_gotcha_validation(child_root, blueprint)),
|
|
2727
|
+
]
|
|
2728
|
+
|
|
2729
|
+
for step_name, step_fn in steps:
|
|
2730
|
+
try:
|
|
2731
|
+
logger.info("Running step: %s", step_name)
|
|
2732
|
+
step_result = step_fn()
|
|
2733
|
+
results["steps"][step_name] = {"status": "success", **(step_result or {})}
|
|
2734
|
+
except Exception as e:
|
|
2735
|
+
logger.error("Step %s failed: %s", step_name, e, exc_info=True)
|
|
2736
|
+
results["steps"][step_name] = {"status": "error", "error": str(e)}
|
|
2737
|
+
results["errors"].append(f"{step_name}: {e}")
|
|
2738
|
+
|
|
2739
|
+
# Compute overall status
|
|
2740
|
+
failed_steps = [s for s, r in results["steps"].items() if r.get("status") == "error"]
|
|
2741
|
+
if failed_steps:
|
|
2742
|
+
results["status"] = "partial" if len(failed_steps) < len(steps) else "failed"
|
|
2743
|
+
|
|
2744
|
+
elapsed = (datetime.now(tz=timezone.utc) - start_time).total_seconds()
|
|
2745
|
+
results["elapsed_seconds"] = round(elapsed, 2)
|
|
2746
|
+
results["failed_steps"] = failed_steps
|
|
2747
|
+
|
|
2748
|
+
logger.info(
|
|
2749
|
+
"Child app '%s' generation %s in %.1fs (%d/%d steps succeeded)",
|
|
2750
|
+
name, results["status"], elapsed,
|
|
2751
|
+
len(steps) - len(failed_steps), len(steps),
|
|
2752
|
+
)
|
|
2753
|
+
return results
|
|
2754
|
+
|
|
2755
|
+
|
|
2756
|
+
# ============================================================
|
|
2757
|
+
# CLI
|
|
2758
|
+
# ============================================================
|
|
2759
|
+
|
|
2760
|
+
|
|
2761
|
+
def main():
|
|
2762
|
+
"""CLI entry point for child app generation."""
|
|
2763
|
+
parser = argparse.ArgumentParser(
|
|
2764
|
+
description="Generate mini-ICDEV clone child application from blueprint",
|
|
2765
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
2766
|
+
epilog="Example:\n python tools/builder/child_app_generator.py "
|
|
2767
|
+
"--blueprint bp.json --project-path /tmp --name my-app --json",
|
|
2768
|
+
)
|
|
2769
|
+
parser.add_argument("--blueprint", required=True,
|
|
2770
|
+
help="Path to blueprint JSON file")
|
|
2771
|
+
parser.add_argument("--project-path", required=True,
|
|
2772
|
+
help="Parent directory for the child app")
|
|
2773
|
+
parser.add_argument("--name", required=True,
|
|
2774
|
+
help="Child application name")
|
|
2775
|
+
parser.add_argument("--icdev-root",
|
|
2776
|
+
help="Path to ICDEV root (default: auto-detect)")
|
|
2777
|
+
parser.add_argument("--db-path",
|
|
2778
|
+
help="Path to ICDEV database (default: data/icdev.db)")
|
|
2779
|
+
parser.add_argument("--json", action="store_true",
|
|
2780
|
+
help="Output results as JSON")
|
|
2781
|
+
parser.add_argument("--verbose", action="store_true",
|
|
2782
|
+
help="Enable debug logging")
|
|
2783
|
+
|
|
2784
|
+
args = parser.parse_args()
|
|
2785
|
+
|
|
2786
|
+
level = logging.DEBUG if args.verbose else logging.INFO
|
|
2787
|
+
logging.basicConfig(
|
|
2788
|
+
level=level,
|
|
2789
|
+
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
|
|
2790
|
+
)
|
|
2791
|
+
|
|
2792
|
+
# Load blueprint
|
|
2793
|
+
bp_path = Path(args.blueprint)
|
|
2794
|
+
if not bp_path.exists():
|
|
2795
|
+
logger.error("Blueprint file not found: %s", bp_path)
|
|
2796
|
+
sys.exit(1)
|
|
2797
|
+
|
|
2798
|
+
try:
|
|
2799
|
+
with open(bp_path) as f:
|
|
2800
|
+
blueprint = json.load(f)
|
|
2801
|
+
except (json.JSONDecodeError, IOError) as e:
|
|
2802
|
+
logger.error("Failed to load blueprint: %s", e)
|
|
2803
|
+
sys.exit(1)
|
|
2804
|
+
|
|
2805
|
+
# Resolve paths
|
|
2806
|
+
icdev_root = Path(args.icdev_root) if args.icdev_root else BASE_DIR
|
|
2807
|
+
db_path = Path(args.db_path) if args.db_path else DB_PATH
|
|
2808
|
+
|
|
2809
|
+
# Generate child app
|
|
2810
|
+
results = generate_child_app(
|
|
2811
|
+
blueprint=blueprint,
|
|
2812
|
+
project_path=args.project_path,
|
|
2813
|
+
name=args.name,
|
|
2814
|
+
icdev_root=icdev_root,
|
|
2815
|
+
db_path=db_path,
|
|
2816
|
+
)
|
|
2817
|
+
|
|
2818
|
+
if args.json:
|
|
2819
|
+
print(json.dumps(results, indent=2))
|
|
2820
|
+
else:
|
|
2821
|
+
status = results["status"]
|
|
2822
|
+
steps = results["steps"]
|
|
2823
|
+
succeeded = sum(1 for r in steps.values() if r.get("status") == "success")
|
|
2824
|
+
total = len(steps)
|
|
2825
|
+
|
|
2826
|
+
print(f"\n{'=' * 60}")
|
|
2827
|
+
print(f"Child App Generation: {results['app_name']}")
|
|
2828
|
+
print(f"{'=' * 60}")
|
|
2829
|
+
print(f"Status: {status.upper()}")
|
|
2830
|
+
print(f"Location: {results['child_root']}")
|
|
2831
|
+
print(f"Steps: {succeeded}/{total} succeeded")
|
|
2832
|
+
print(f"Elapsed: {results.get('elapsed_seconds', 0)}s")
|
|
2833
|
+
|
|
2834
|
+
if results.get("errors"):
|
|
2835
|
+
print("\nErrors:")
|
|
2836
|
+
for err in results["errors"]:
|
|
2837
|
+
print(f" - {err}")
|
|
2838
|
+
|
|
2839
|
+
print("\nStep Results:")
|
|
2840
|
+
for step_name, step_result in steps.items():
|
|
2841
|
+
icon = "OK" if step_result.get("status") == "success" else "FAIL"
|
|
2842
|
+
print(f" [{icon}] {step_name}")
|
|
2843
|
+
|
|
2844
|
+
if status == "success":
|
|
2845
|
+
print("\nNext steps:")
|
|
2846
|
+
print(f" cd {results['child_root']}")
|
|
2847
|
+
print(" python tools/memory/memory_read.py --format markdown")
|
|
2848
|
+
print(" python tools/db/init_*_db.py")
|
|
2849
|
+
|
|
2850
|
+
|
|
2851
|
+
if __name__ == "__main__":
|
|
2852
|
+
main()
|