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,3703 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# CUI // SP-CTI
|
|
3
|
+
"""Code Generator — generates implementation code from specifications.
|
|
4
|
+
|
|
5
|
+
Implements:
|
|
6
|
+
- generate_from_spec(project_path, spec, language) -> creates source files
|
|
7
|
+
- Generates modules in Python, Java, Go, TypeScript, Rust, and C#
|
|
8
|
+
- Applies CUI header in correct comment style per language
|
|
9
|
+
- Logs audit trail event (code_generated)
|
|
10
|
+
- CLI: python tools/builder/code_generator.py --project-path PATH --spec "REST API endpoint for users" --language python
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import json
|
|
15
|
+
import re
|
|
16
|
+
import sqlite3
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any, Dict, List, Optional
|
|
19
|
+
from icdev._paths import get_project_root
|
|
20
|
+
|
|
21
|
+
BASE_DIR = get_project_root()
|
|
22
|
+
DB_PATH = BASE_DIR / "data" / "icdev.db"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _build_profile_context(project_id, task_type="code_generation"):
|
|
26
|
+
"""Build dev profile context for LLM prompt injection (Phase 34, D187).
|
|
27
|
+
|
|
28
|
+
Calls inject_for_task() to extract relevant dimensions as markdown.
|
|
29
|
+
Returns empty string if no profile exists (graceful fallback).
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
from icdev.tools.builder.dev_profile_manager import inject_for_task
|
|
33
|
+
context = inject_for_task(project_id, task_type)
|
|
34
|
+
return context or ""
|
|
35
|
+
except (ImportError, Exception):
|
|
36
|
+
return ""
|
|
37
|
+
|
|
38
|
+
CUI_HEADER = '''\
|
|
39
|
+
# CUI // SP-CTI
|
|
40
|
+
# Controlled by: Department of Defense
|
|
41
|
+
# CUI Category: CTI
|
|
42
|
+
# Distribution: D
|
|
43
|
+
# POC: ICDEV System Administrator
|
|
44
|
+
'''
|
|
45
|
+
|
|
46
|
+
CUI_HEADER_C_STYLE = '''\
|
|
47
|
+
// CUI // SP-CTI
|
|
48
|
+
// Controlled by: Department of Defense
|
|
49
|
+
// CUI Category: CTI
|
|
50
|
+
// Distribution: D
|
|
51
|
+
// POC: ICDEV System Administrator
|
|
52
|
+
'''
|
|
53
|
+
|
|
54
|
+
CUI_HEADERS = {
|
|
55
|
+
"python": CUI_HEADER,
|
|
56
|
+
"java": CUI_HEADER_C_STYLE,
|
|
57
|
+
"go": CUI_HEADER_C_STYLE,
|
|
58
|
+
"typescript": CUI_HEADER_C_STYLE,
|
|
59
|
+
"rust": CUI_HEADER_C_STYLE,
|
|
60
|
+
"csharp": CUI_HEADER_C_STYLE,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _slugify(text: str) -> str:
|
|
65
|
+
"""Convert text to a Python-safe module name."""
|
|
66
|
+
slug = re.sub(r"[^\w\s]", "", text.lower().strip())
|
|
67
|
+
slug = re.sub(r"[\s-]+", "_", slug)
|
|
68
|
+
slug = re.sub(r"_+", "_", slug).strip("_")
|
|
69
|
+
return slug[:60]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _detect_spec_type(spec: str) -> str:
|
|
73
|
+
"""Detect the type of code to generate from the spec text."""
|
|
74
|
+
spec_lower = spec.lower()
|
|
75
|
+
# Phase 19: Agentic spec types (check before generic types to avoid false matches)
|
|
76
|
+
if any(kw in spec_lower for kw in ["agent skill", "a2a skill", "skill handler", "register_skill", "dispatch"]):
|
|
77
|
+
return "agent_skill"
|
|
78
|
+
elif any(kw in spec_lower for kw in ["llm service", "bedrock", "inference", "llm client"]):
|
|
79
|
+
return "llm_service"
|
|
80
|
+
elif any(kw in spec_lower for kw in ["prompt template", "hardprompt", "prompt manager"]):
|
|
81
|
+
return "prompt_template"
|
|
82
|
+
elif any(kw in spec_lower for kw in ["collaborate", "multi-agent", "handoff", "agent collaboration"]):
|
|
83
|
+
return "agent_collaboration"
|
|
84
|
+
elif any(kw in spec_lower for kw in ["model config", "agent card", "agent config"]):
|
|
85
|
+
return "model_config"
|
|
86
|
+
# Phase 26: MOSA interface spec types
|
|
87
|
+
elif any(kw in spec_lower for kw in ["mosa interface", "interface contract", "icd interface",
|
|
88
|
+
"open interface", "modular interface"]):
|
|
89
|
+
return "mosa_interface"
|
|
90
|
+
# Original spec types
|
|
91
|
+
elif any(kw in spec_lower for kw in ["api", "endpoint", "rest", "route", "http"]):
|
|
92
|
+
return "api"
|
|
93
|
+
elif any(kw in spec_lower for kw in ["model", "schema", "table", "database", "orm"]):
|
|
94
|
+
return "model"
|
|
95
|
+
elif any(kw in spec_lower for kw in ["service", "business logic", "handler", "processor"]):
|
|
96
|
+
return "service"
|
|
97
|
+
elif any(kw in spec_lower for kw in ["cli", "command", "argparse", "command-line"]):
|
|
98
|
+
return "cli"
|
|
99
|
+
elif any(kw in spec_lower for kw in ["util", "helper", "utility", "common"]):
|
|
100
|
+
return "utility"
|
|
101
|
+
elif any(kw in spec_lower for kw in ["middleware", "decorator", "wrapper"]):
|
|
102
|
+
return "middleware"
|
|
103
|
+
elif any(kw in spec_lower for kw in ["config", "settings", "configuration"]):
|
|
104
|
+
return "config"
|
|
105
|
+
else:
|
|
106
|
+
return "module"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _extract_entity_name(spec: str) -> str:
|
|
110
|
+
"""Extract the primary entity/resource name from the spec."""
|
|
111
|
+
spec_lower = spec.lower()
|
|
112
|
+
# Try common patterns: "... for users", "... for orders", "User management"
|
|
113
|
+
patterns = [
|
|
114
|
+
r"for\s+(\w+)",
|
|
115
|
+
r"(\w+)\s+management",
|
|
116
|
+
r"(\w+)\s+service",
|
|
117
|
+
r"(\w+)\s+api",
|
|
118
|
+
r"(\w+)\s+endpoint",
|
|
119
|
+
r"(\w+)\s+model",
|
|
120
|
+
r"(\w+)\s+handler",
|
|
121
|
+
]
|
|
122
|
+
for pattern in patterns:
|
|
123
|
+
match = re.search(pattern, spec_lower)
|
|
124
|
+
if match:
|
|
125
|
+
name = match.group(1)
|
|
126
|
+
# Skip generic words
|
|
127
|
+
if name not in ("a", "an", "the", "rest", "api", "http", "new", "simple", "basic"):
|
|
128
|
+
return name
|
|
129
|
+
# Fallback: use slugified spec
|
|
130
|
+
return _slugify(spec)[:20] or "module"
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _generate_api_code(entity: str, spec: str, secure: bool = True) -> str:
|
|
134
|
+
"""Generate a Flask/FastAPI API endpoint module.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
entity: Resource name (e.g. "user", "contract").
|
|
138
|
+
spec: Specification text.
|
|
139
|
+
secure: Include auth decorators and input validation (D-EPSEC-5).
|
|
140
|
+
Set to False only via --no-auth CLI flag.
|
|
141
|
+
"""
|
|
142
|
+
class_name = entity.capitalize()
|
|
143
|
+
|
|
144
|
+
# Auth decorator and validation helper — self-contained (no external import)
|
|
145
|
+
auth_block = ""
|
|
146
|
+
if secure:
|
|
147
|
+
auth_block = '''
|
|
148
|
+
from functools import wraps
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def require_auth(f):
|
|
152
|
+
"""Require authenticated user (NIST AC-3). Self-contained decorator."""
|
|
153
|
+
@wraps(f)
|
|
154
|
+
def decorated(*args, **kwargs):
|
|
155
|
+
from flask import g
|
|
156
|
+
user = getattr(g, "current_user", None)
|
|
157
|
+
if not user:
|
|
158
|
+
return jsonify({"error": "Authentication required"}), 401
|
|
159
|
+
return f(*args, **kwargs)
|
|
160
|
+
return decorated
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _validate_fields(data, required=None):
|
|
164
|
+
"""Validate input fields (NIST SI-10). Returns error message or None."""
|
|
165
|
+
if not isinstance(data, dict):
|
|
166
|
+
return "Request body must be a JSON object"
|
|
167
|
+
if required:
|
|
168
|
+
missing = [f for f in required if f not in data or data[f] is None]
|
|
169
|
+
if missing:
|
|
170
|
+
return f"Missing required fields: {', '.join(missing)}"
|
|
171
|
+
return None
|
|
172
|
+
|
|
173
|
+
'''
|
|
174
|
+
|
|
175
|
+
# Route decorators
|
|
176
|
+
auth_dec = "\n @require_auth" if secure else ""
|
|
177
|
+
|
|
178
|
+
# Validation on write methods
|
|
179
|
+
validate_create = ""
|
|
180
|
+
validate_update = ""
|
|
181
|
+
if secure:
|
|
182
|
+
validate_create = '''
|
|
183
|
+
err = _validate_fields(data)
|
|
184
|
+
if err:
|
|
185
|
+
return jsonify({{"error": err}}), 400'''
|
|
186
|
+
validate_update = '''
|
|
187
|
+
err = _validate_fields(data)
|
|
188
|
+
if err:
|
|
189
|
+
return jsonify({{"error": err}}), 400'''
|
|
190
|
+
|
|
191
|
+
return f'''{CUI_HEADER}
|
|
192
|
+
"""API endpoints for {entity} resource.
|
|
193
|
+
|
|
194
|
+
Spec: {spec}
|
|
195
|
+
Generated by ICDEV Builder - code_generator.py
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
import json
|
|
199
|
+
import uuid
|
|
200
|
+
from datetime import datetime, timezone
|
|
201
|
+
from typing import Any, Dict, List, Optional
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
from flask import Blueprint, jsonify, request
|
|
205
|
+
except ImportError:
|
|
206
|
+
Blueprint = None
|
|
207
|
+
{auth_block}
|
|
208
|
+
|
|
209
|
+
def create_blueprint() -> "Blueprint":
|
|
210
|
+
"""Create and return the {entity} API blueprint."""
|
|
211
|
+
bp = Blueprint("{entity}", __name__, url_prefix="/api/{entity}")
|
|
212
|
+
|
|
213
|
+
# In-memory store (replace with database in production)
|
|
214
|
+
_store: Dict[str, dict] = {{}}
|
|
215
|
+
|
|
216
|
+
@bp.route("", methods=["GET"]){auth_dec}
|
|
217
|
+
def list_{entity}():
|
|
218
|
+
"""List all {entity} records.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
JSON array of {entity} records.
|
|
222
|
+
"""
|
|
223
|
+
items = list(_store.values())
|
|
224
|
+
return jsonify({{"data": items, "count": len(items)}})
|
|
225
|
+
|
|
226
|
+
@bp.route("/<item_id>", methods=["GET"]){auth_dec}
|
|
227
|
+
def get_{entity}(item_id: str):
|
|
228
|
+
"""Get a single {entity} by ID.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
item_id: The unique identifier.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
JSON object of the {entity} record, or 404.
|
|
235
|
+
"""
|
|
236
|
+
item = _store.get(item_id)
|
|
237
|
+
if not item:
|
|
238
|
+
return jsonify({{"error": f"{class_name} not found: {{item_id}}"}}), 404
|
|
239
|
+
return jsonify(item)
|
|
240
|
+
|
|
241
|
+
@bp.route("", methods=["POST"]){auth_dec}
|
|
242
|
+
def create_{entity}():
|
|
243
|
+
"""Create a new {entity} record.
|
|
244
|
+
|
|
245
|
+
Expects:
|
|
246
|
+
JSON body with {entity} data.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Created {entity} record with generated ID.
|
|
250
|
+
"""
|
|
251
|
+
data = request.get_json(silent=True) or {{}}{validate_create}
|
|
252
|
+
item_id = str(uuid.uuid4())
|
|
253
|
+
record = {{
|
|
254
|
+
"id": item_id,
|
|
255
|
+
**data,
|
|
256
|
+
"created_at": datetime.now(timezone.utc).isoformat() + "Z",
|
|
257
|
+
"updated_at": datetime.now(timezone.utc).isoformat() + "Z",
|
|
258
|
+
}}
|
|
259
|
+
_store[item_id] = record
|
|
260
|
+
return jsonify(record), 201
|
|
261
|
+
|
|
262
|
+
@bp.route("/<item_id>", methods=["PUT"]){auth_dec}
|
|
263
|
+
def update_{entity}(item_id: str):
|
|
264
|
+
"""Update an existing {entity} record.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
item_id: The unique identifier.
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
Updated {entity} record, or 404.
|
|
271
|
+
"""
|
|
272
|
+
if item_id not in _store:
|
|
273
|
+
return jsonify({{"error": f"{class_name} not found: {{item_id}}"}}), 404
|
|
274
|
+
data = request.get_json(silent=True) or {{}}{validate_update}
|
|
275
|
+
_store[item_id].update(data)
|
|
276
|
+
_store[item_id]["updated_at"] = datetime.now(timezone.utc).isoformat() + "Z"
|
|
277
|
+
return jsonify(_store[item_id])
|
|
278
|
+
|
|
279
|
+
@bp.route("/<item_id>", methods=["DELETE"]){auth_dec}
|
|
280
|
+
def delete_{entity}(item_id: str):
|
|
281
|
+
"""Delete a {entity} record.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
item_id: The unique identifier.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
204 No Content on success, or 404.
|
|
288
|
+
"""
|
|
289
|
+
if item_id not in _store:
|
|
290
|
+
return jsonify({{"error": f"{class_name} not found: {{item_id}}"}}), 404
|
|
291
|
+
del _store[item_id]
|
|
292
|
+
return "", 204
|
|
293
|
+
|
|
294
|
+
return bp
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
# Standalone usage
|
|
298
|
+
if __name__ == "__main__":
|
|
299
|
+
try:
|
|
300
|
+
from flask import Flask
|
|
301
|
+
app = Flask(__name__)
|
|
302
|
+
app.register_blueprint(create_blueprint())
|
|
303
|
+
app.run(debug=os.environ.get("FLASK_DEBUG", "false").lower() == "true", port=5000)
|
|
304
|
+
except ImportError:
|
|
305
|
+
print("Flask is required. Install with: pip install flask")
|
|
306
|
+
'''
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _generate_model_code(entity: str, spec: str) -> str:
|
|
310
|
+
"""Generate a data model module."""
|
|
311
|
+
class_name = entity.capitalize()
|
|
312
|
+
return f'''{CUI_HEADER}
|
|
313
|
+
"""Data model for {entity}.
|
|
314
|
+
|
|
315
|
+
Spec: {spec}
|
|
316
|
+
Generated by ICDEV Builder - code_generator.py
|
|
317
|
+
"""
|
|
318
|
+
|
|
319
|
+
import uuid
|
|
320
|
+
from dataclasses import dataclass, field, asdict
|
|
321
|
+
from datetime import datetime, timezone
|
|
322
|
+
from typing import Any, Dict, List, Optional
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
@dataclass
|
|
326
|
+
class {class_name}:
|
|
327
|
+
"""Represents a {entity} entity.
|
|
328
|
+
|
|
329
|
+
Attributes:
|
|
330
|
+
id: Unique identifier (UUID).
|
|
331
|
+
name: Human-readable name.
|
|
332
|
+
description: Optional description.
|
|
333
|
+
status: Current status (active, inactive, archived).
|
|
334
|
+
metadata: Additional key-value metadata.
|
|
335
|
+
created_at: Creation timestamp (ISO 8601).
|
|
336
|
+
updated_at: Last update timestamp (ISO 8601).
|
|
337
|
+
"""
|
|
338
|
+
id: str = ""
|
|
339
|
+
name: str = ""
|
|
340
|
+
description: str = ""
|
|
341
|
+
status: str = "active"
|
|
342
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
343
|
+
created_at: str = ""
|
|
344
|
+
updated_at: str = ""
|
|
345
|
+
|
|
346
|
+
def __post_init__(self) -> None:
|
|
347
|
+
if not self.id:
|
|
348
|
+
self.id = str(uuid.uuid4())
|
|
349
|
+
now = datetime.now(timezone.utc).isoformat() + "Z"
|
|
350
|
+
if not self.created_at:
|
|
351
|
+
self.created_at = now
|
|
352
|
+
if not self.updated_at:
|
|
353
|
+
self.updated_at = now
|
|
354
|
+
|
|
355
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
356
|
+
"""Serialize to dictionary."""
|
|
357
|
+
return asdict(self)
|
|
358
|
+
|
|
359
|
+
@classmethod
|
|
360
|
+
def from_dict(cls, data: Dict[str, Any]) -> "{class_name}":
|
|
361
|
+
"""Deserialize from dictionary."""
|
|
362
|
+
return cls(
|
|
363
|
+
id=data.get("id", ""),
|
|
364
|
+
name=data.get("name", ""),
|
|
365
|
+
description=data.get("description", ""),
|
|
366
|
+
status=data.get("status", "active"),
|
|
367
|
+
metadata=data.get("metadata", {{}}) ,
|
|
368
|
+
created_at=data.get("created_at", ""),
|
|
369
|
+
updated_at=data.get("updated_at", ""),
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
def validate(self) -> List[str]:
|
|
373
|
+
"""Validate the model. Returns list of validation errors."""
|
|
374
|
+
errors = []
|
|
375
|
+
if not self.name:
|
|
376
|
+
errors.append("name is required")
|
|
377
|
+
if self.status not in ("active", "inactive", "archived"):
|
|
378
|
+
errors.append(f"invalid status: {{self.status}}")
|
|
379
|
+
return errors
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
class {class_name}Repository:
|
|
383
|
+
"""Repository for {entity} CRUD operations.
|
|
384
|
+
|
|
385
|
+
Uses SQLite for persistence. Replace with production database as needed.
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
def __init__(self, db_path: str) -> None:
|
|
389
|
+
self.db_path = db_path
|
|
390
|
+
|
|
391
|
+
def create(self, item: {class_name}) -> {class_name}:
|
|
392
|
+
"""Create a new {entity} record."""
|
|
393
|
+
import sqlite3
|
|
394
|
+
conn = sqlite3.connect(self.db_path)
|
|
395
|
+
try:
|
|
396
|
+
c = conn.cursor()
|
|
397
|
+
c.execute(
|
|
398
|
+
"INSERT INTO {entity} (id, name, description, status, metadata, created_at, updated_at) "
|
|
399
|
+
"VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
400
|
+
(item.id, item.name, item.description, item.status,
|
|
401
|
+
str(item.metadata), item.created_at, item.updated_at),
|
|
402
|
+
)
|
|
403
|
+
conn.commit()
|
|
404
|
+
finally:
|
|
405
|
+
conn.close()
|
|
406
|
+
return item
|
|
407
|
+
|
|
408
|
+
def get(self, item_id: str) -> Optional[{class_name}]:
|
|
409
|
+
"""Get a {entity} by ID."""
|
|
410
|
+
import sqlite3
|
|
411
|
+
conn = sqlite3.connect(self.db_path)
|
|
412
|
+
conn.row_factory = sqlite3.Row
|
|
413
|
+
try:
|
|
414
|
+
c = conn.cursor()
|
|
415
|
+
c.execute("SELECT * FROM {entity} WHERE id = ?", (item_id,))
|
|
416
|
+
row = c.fetchone()
|
|
417
|
+
if row:
|
|
418
|
+
return {class_name}.from_dict(dict(row))
|
|
419
|
+
return None
|
|
420
|
+
finally:
|
|
421
|
+
conn.close()
|
|
422
|
+
|
|
423
|
+
def list_all(self) -> List[{class_name}]:
|
|
424
|
+
"""List all {entity} records."""
|
|
425
|
+
import sqlite3
|
|
426
|
+
conn = sqlite3.connect(self.db_path)
|
|
427
|
+
conn.row_factory = sqlite3.Row
|
|
428
|
+
try:
|
|
429
|
+
c = conn.cursor()
|
|
430
|
+
c.execute("SELECT * FROM {entity} ORDER BY created_at DESC")
|
|
431
|
+
return [{class_name}.from_dict(dict(row)) for row in c.fetchall()]
|
|
432
|
+
finally:
|
|
433
|
+
conn.close()
|
|
434
|
+
|
|
435
|
+
def delete(self, item_id: str) -> bool:
|
|
436
|
+
"""Delete a {entity} by ID."""
|
|
437
|
+
import sqlite3
|
|
438
|
+
conn = sqlite3.connect(self.db_path)
|
|
439
|
+
try:
|
|
440
|
+
c = conn.cursor()
|
|
441
|
+
c.execute("DELETE FROM {entity} WHERE id = ?", (item_id,))
|
|
442
|
+
conn.commit()
|
|
443
|
+
return c.rowcount > 0
|
|
444
|
+
finally:
|
|
445
|
+
conn.close()
|
|
446
|
+
'''
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def _generate_service_code(entity: str, spec: str) -> str:
|
|
450
|
+
"""Generate a service/business logic module."""
|
|
451
|
+
class_name = entity.capitalize()
|
|
452
|
+
return f'''{CUI_HEADER}
|
|
453
|
+
"""Service layer for {entity} business logic.
|
|
454
|
+
|
|
455
|
+
Spec: {spec}
|
|
456
|
+
Generated by ICDEV Builder - code_generator.py
|
|
457
|
+
"""
|
|
458
|
+
|
|
459
|
+
import logging
|
|
460
|
+
from datetime import datetime, timezone
|
|
461
|
+
from typing import Any, Dict, List, Optional
|
|
462
|
+
|
|
463
|
+
logger = logging.getLogger(__name__)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
class {class_name}Service:
|
|
467
|
+
"""Business logic for {entity} operations.
|
|
468
|
+
|
|
469
|
+
Encapsulates validation, transformation, and coordination logic
|
|
470
|
+
separate from HTTP handling and data access.
|
|
471
|
+
"""
|
|
472
|
+
|
|
473
|
+
def __init__(self, repository: Any = None) -> None:
|
|
474
|
+
"""Initialize the service.
|
|
475
|
+
|
|
476
|
+
Args:
|
|
477
|
+
repository: Data access object for {entity} persistence.
|
|
478
|
+
"""
|
|
479
|
+
self.repository = repository
|
|
480
|
+
|
|
481
|
+
def create(self, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
482
|
+
"""Create a new {entity}.
|
|
483
|
+
|
|
484
|
+
Args:
|
|
485
|
+
data: Input data for the new {entity}.
|
|
486
|
+
|
|
487
|
+
Returns:
|
|
488
|
+
The created {entity} as a dict.
|
|
489
|
+
|
|
490
|
+
Raises:
|
|
491
|
+
ValueError: If validation fails.
|
|
492
|
+
"""
|
|
493
|
+
errors = self._validate(data)
|
|
494
|
+
if errors:
|
|
495
|
+
raise ValueError(f"Validation failed: {{'; '.join(errors)}}")
|
|
496
|
+
|
|
497
|
+
data["created_at"] = datetime.now(timezone.utc).isoformat() + "Z"
|
|
498
|
+
data["updated_at"] = data["created_at"]
|
|
499
|
+
|
|
500
|
+
if self.repository:
|
|
501
|
+
result = self.repository.create(data)
|
|
502
|
+
logger.info(f"{class_name} created: {{result.get('id', 'unknown')}}")
|
|
503
|
+
return result
|
|
504
|
+
return data
|
|
505
|
+
|
|
506
|
+
def get(self, item_id: str) -> Optional[Dict[str, Any]]:
|
|
507
|
+
"""Retrieve a {entity} by ID.
|
|
508
|
+
|
|
509
|
+
Args:
|
|
510
|
+
item_id: Unique identifier.
|
|
511
|
+
|
|
512
|
+
Returns:
|
|
513
|
+
The {entity} dict or None if not found.
|
|
514
|
+
"""
|
|
515
|
+
if self.repository:
|
|
516
|
+
return self.repository.get(item_id)
|
|
517
|
+
return None
|
|
518
|
+
|
|
519
|
+
def update(self, item_id: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
520
|
+
"""Update an existing {entity}.
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
item_id: Unique identifier.
|
|
524
|
+
data: Fields to update.
|
|
525
|
+
|
|
526
|
+
Returns:
|
|
527
|
+
Updated {entity} dict, or None if not found.
|
|
528
|
+
"""
|
|
529
|
+
data["updated_at"] = datetime.now(timezone.utc).isoformat() + "Z"
|
|
530
|
+
if self.repository:
|
|
531
|
+
return self.repository.update(item_id, data)
|
|
532
|
+
return data
|
|
533
|
+
|
|
534
|
+
def delete(self, item_id: str) -> bool:
|
|
535
|
+
"""Delete a {entity}.
|
|
536
|
+
|
|
537
|
+
Args:
|
|
538
|
+
item_id: Unique identifier.
|
|
539
|
+
|
|
540
|
+
Returns:
|
|
541
|
+
True if deleted, False if not found.
|
|
542
|
+
"""
|
|
543
|
+
if self.repository:
|
|
544
|
+
return self.repository.delete(item_id)
|
|
545
|
+
return False
|
|
546
|
+
|
|
547
|
+
def list_all(self, filters: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
|
|
548
|
+
"""List {entity} records with optional filtering.
|
|
549
|
+
|
|
550
|
+
Args:
|
|
551
|
+
filters: Optional filter criteria.
|
|
552
|
+
|
|
553
|
+
Returns:
|
|
554
|
+
List of {entity} dicts.
|
|
555
|
+
"""
|
|
556
|
+
if self.repository:
|
|
557
|
+
return self.repository.list_all(filters)
|
|
558
|
+
return []
|
|
559
|
+
|
|
560
|
+
def _validate(self, data: Dict[str, Any]) -> List[str]:
|
|
561
|
+
"""Validate {entity} data.
|
|
562
|
+
|
|
563
|
+
Args:
|
|
564
|
+
data: Data to validate.
|
|
565
|
+
|
|
566
|
+
Returns:
|
|
567
|
+
List of validation error messages (empty if valid).
|
|
568
|
+
"""
|
|
569
|
+
errors = []
|
|
570
|
+
if not data.get("name"):
|
|
571
|
+
errors.append("name is required")
|
|
572
|
+
return errors
|
|
573
|
+
'''
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def _generate_cli_code(entity: str, spec: str) -> str:
|
|
577
|
+
"""Generate a CLI tool module."""
|
|
578
|
+
return f'''{CUI_HEADER}
|
|
579
|
+
"""CLI tool for {entity}.
|
|
580
|
+
|
|
581
|
+
Spec: {spec}
|
|
582
|
+
Generated by ICDEV Builder - code_generator.py
|
|
583
|
+
"""
|
|
584
|
+
|
|
585
|
+
import argparse
|
|
586
|
+
import json
|
|
587
|
+
import sys
|
|
588
|
+
from typing import Any, Dict
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def handle_create(args: argparse.Namespace) -> None:
|
|
592
|
+
"""Handle the create command."""
|
|
593
|
+
data = {{"name": args.name}}
|
|
594
|
+
if args.description:
|
|
595
|
+
data["description"] = args.description
|
|
596
|
+
print(json.dumps({{"status": "created", "data": data}}, indent=2))
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
def handle_list(args: argparse.Namespace) -> None:
|
|
600
|
+
"""Handle the list command."""
|
|
601
|
+
print(json.dumps({{"status": "ok", "data": [], "count": 0}}, indent=2))
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
def handle_get(args: argparse.Namespace) -> None:
|
|
605
|
+
"""Handle the get command."""
|
|
606
|
+
print(json.dumps({{"status": "ok", "id": args.id}}, indent=2))
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
def handle_delete(args: argparse.Namespace) -> None:
|
|
610
|
+
"""Handle the delete command."""
|
|
611
|
+
print(json.dumps({{"status": "deleted", "id": args.id}}, indent=2))
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
def main() -> None:
|
|
615
|
+
"""Entry point for the {entity} CLI."""
|
|
616
|
+
parser = argparse.ArgumentParser(description="{entity} CLI tool")
|
|
617
|
+
sub = parser.add_subparsers(dest="command", help="Available commands")
|
|
618
|
+
|
|
619
|
+
# create
|
|
620
|
+
p_create = sub.add_parser("create", help="Create a new {entity}")
|
|
621
|
+
p_create.add_argument("--name", required=True, help="Name")
|
|
622
|
+
p_create.add_argument("--description", help="Description")
|
|
623
|
+
|
|
624
|
+
# list
|
|
625
|
+
sub.add_parser("list", help="List all {entity} records")
|
|
626
|
+
|
|
627
|
+
# get
|
|
628
|
+
p_get = sub.add_parser("get", help="Get a {entity} by ID")
|
|
629
|
+
p_get.add_argument("--id", required=True, help="ID")
|
|
630
|
+
|
|
631
|
+
# delete
|
|
632
|
+
p_del = sub.add_parser("delete", help="Delete a {entity}")
|
|
633
|
+
p_del.add_argument("--id", required=True, help="ID")
|
|
634
|
+
|
|
635
|
+
parser.add_argument("--json", action="store_true", dest="json_output", help="JSON output")
|
|
636
|
+
args = parser.parse_args()
|
|
637
|
+
|
|
638
|
+
if not args.command:
|
|
639
|
+
parser.print_help()
|
|
640
|
+
sys.exit(1)
|
|
641
|
+
|
|
642
|
+
handlers = {{
|
|
643
|
+
"create": handle_create,
|
|
644
|
+
"list": handle_list,
|
|
645
|
+
"get": handle_get,
|
|
646
|
+
"delete": handle_delete,
|
|
647
|
+
}}
|
|
648
|
+
handlers[args.command](args)
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
if __name__ == "__main__":
|
|
652
|
+
main()
|
|
653
|
+
'''
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
def _generate_module_code(entity: str, spec: str) -> str:
|
|
657
|
+
"""Generate a generic Python module."""
|
|
658
|
+
class_name = entity.capitalize()
|
|
659
|
+
return f'''{CUI_HEADER}
|
|
660
|
+
"""Module: {entity}
|
|
661
|
+
|
|
662
|
+
Spec: {spec}
|
|
663
|
+
Generated by ICDEV Builder - code_generator.py
|
|
664
|
+
"""
|
|
665
|
+
|
|
666
|
+
import logging
|
|
667
|
+
from typing import Any, Dict, List, Optional
|
|
668
|
+
|
|
669
|
+
logger = logging.getLogger(__name__)
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
class {class_name}:
|
|
673
|
+
"""Main class for {entity} functionality.
|
|
674
|
+
|
|
675
|
+
Provides core operations as defined by the specification.
|
|
676
|
+
"""
|
|
677
|
+
|
|
678
|
+
def __init__(self, config: Optional[Dict[str, Any]] = None) -> None:
|
|
679
|
+
"""Initialize {class_name}.
|
|
680
|
+
|
|
681
|
+
Args:
|
|
682
|
+
config: Optional configuration dictionary.
|
|
683
|
+
"""
|
|
684
|
+
self.config = config or {{}}
|
|
685
|
+
logger.info(f"{class_name} initialized")
|
|
686
|
+
|
|
687
|
+
def process(self, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
688
|
+
"""Process input data and return results.
|
|
689
|
+
|
|
690
|
+
Args:
|
|
691
|
+
data: Input data to process.
|
|
692
|
+
|
|
693
|
+
Returns:
|
|
694
|
+
Processed result dictionary.
|
|
695
|
+
"""
|
|
696
|
+
logger.info(f"Processing data: {{list(data.keys())}}")
|
|
697
|
+
result = {{
|
|
698
|
+
"status": "processed",
|
|
699
|
+
"input_keys": list(data.keys()),
|
|
700
|
+
"output": data,
|
|
701
|
+
}}
|
|
702
|
+
return result
|
|
703
|
+
|
|
704
|
+
def validate(self, data: Dict[str, Any]) -> List[str]:
|
|
705
|
+
"""Validate input data.
|
|
706
|
+
|
|
707
|
+
Args:
|
|
708
|
+
data: Data to validate.
|
|
709
|
+
|
|
710
|
+
Returns:
|
|
711
|
+
List of validation error messages (empty if valid).
|
|
712
|
+
"""
|
|
713
|
+
errors = []
|
|
714
|
+
if not data:
|
|
715
|
+
errors.append("data cannot be empty")
|
|
716
|
+
return errors
|
|
717
|
+
'''
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
# ---------------------------------------------------------------------------
|
|
721
|
+
# Java code generators
|
|
722
|
+
# ---------------------------------------------------------------------------
|
|
723
|
+
|
|
724
|
+
def _generate_java_api_code(entity: str, spec: str, secure: bool = True) -> str:
|
|
725
|
+
"""Generate a Spring Boot REST controller (Java)."""
|
|
726
|
+
class_name = entity.capitalize()
|
|
727
|
+
auth_import = ""
|
|
728
|
+
auth_ann = ""
|
|
729
|
+
valid_ann = ""
|
|
730
|
+
if secure:
|
|
731
|
+
auth_import = "\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport jakarta.validation.Valid;"
|
|
732
|
+
auth_ann = '\n @PreAuthorize("isAuthenticated()")'
|
|
733
|
+
valid_ann = "@Valid "
|
|
734
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
735
|
+
package com.icdev.api;
|
|
736
|
+
|
|
737
|
+
import org.springframework.http.HttpStatus;
|
|
738
|
+
import org.springframework.http.ResponseEntity;
|
|
739
|
+
import org.springframework.web.bind.annotation.*;
|
|
740
|
+
{auth_import}
|
|
741
|
+
import java.util.*;
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* REST API controller for {entity}.
|
|
745
|
+
*
|
|
746
|
+
* Spec: {spec}
|
|
747
|
+
* Generated by ICDEV Builder - code_generator.py
|
|
748
|
+
*/
|
|
749
|
+
@RestController
|
|
750
|
+
@RequestMapping("/api/{entity}")
|
|
751
|
+
public class {class_name}Controller {{
|
|
752
|
+
|
|
753
|
+
private final {class_name}Service service;
|
|
754
|
+
|
|
755
|
+
public {class_name}Controller({class_name}Service service) {{
|
|
756
|
+
this.service = service;
|
|
757
|
+
}}
|
|
758
|
+
|
|
759
|
+
@GetMapping{auth_ann}
|
|
760
|
+
public ResponseEntity<List<Map<String, Object>>> list() {{
|
|
761
|
+
List<Map<String, Object>> items = service.listAll();
|
|
762
|
+
return ResponseEntity.ok(items);
|
|
763
|
+
}}
|
|
764
|
+
|
|
765
|
+
@GetMapping("/{{id}}"){auth_ann}
|
|
766
|
+
public ResponseEntity<Map<String, Object>> get(@PathVariable String id) {{
|
|
767
|
+
Map<String, Object> item = service.getById(id);
|
|
768
|
+
if (item == null) {{
|
|
769
|
+
return ResponseEntity.notFound().build();
|
|
770
|
+
}}
|
|
771
|
+
return ResponseEntity.ok(item);
|
|
772
|
+
}}
|
|
773
|
+
|
|
774
|
+
@PostMapping{auth_ann}
|
|
775
|
+
public ResponseEntity<Map<String, Object>> create({valid_ann}@RequestBody Map<String, Object> data) {{
|
|
776
|
+
Map<String, Object> created = service.create(data);
|
|
777
|
+
return ResponseEntity.status(HttpStatus.CREATED).body(created);
|
|
778
|
+
}}
|
|
779
|
+
|
|
780
|
+
@PutMapping("/{{id}}"){auth_ann}
|
|
781
|
+
public ResponseEntity<Map<String, Object>> update(@PathVariable String id, {valid_ann}@RequestBody Map<String, Object> data) {{
|
|
782
|
+
Map<String, Object> updated = service.update(id, data);
|
|
783
|
+
if (updated == null) {{
|
|
784
|
+
return ResponseEntity.notFound().build();
|
|
785
|
+
}}
|
|
786
|
+
return ResponseEntity.ok(updated);
|
|
787
|
+
}}
|
|
788
|
+
|
|
789
|
+
@DeleteMapping("/{{id}}"){auth_ann}
|
|
790
|
+
public ResponseEntity<Void> delete(@PathVariable String id) {{
|
|
791
|
+
boolean deleted = service.delete(id);
|
|
792
|
+
if (!deleted) {{
|
|
793
|
+
return ResponseEntity.notFound().build();
|
|
794
|
+
}}
|
|
795
|
+
return ResponseEntity.noContent().build();
|
|
796
|
+
}}
|
|
797
|
+
}}
|
|
798
|
+
'''
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
def _generate_java_model_code(entity: str, spec: str) -> str:
|
|
802
|
+
"""Generate a JPA entity model (Java)."""
|
|
803
|
+
class_name = entity.capitalize()
|
|
804
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
805
|
+
package com.icdev.model;
|
|
806
|
+
|
|
807
|
+
import jakarta.persistence.*;
|
|
808
|
+
import java.time.Instant;
|
|
809
|
+
import java.util.UUID;
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* Data model for {entity}.
|
|
813
|
+
*
|
|
814
|
+
* Spec: {spec}
|
|
815
|
+
* Generated by ICDEV Builder - code_generator.py
|
|
816
|
+
*/
|
|
817
|
+
@Entity
|
|
818
|
+
@Table(name = "{entity}")
|
|
819
|
+
public class {class_name} {{
|
|
820
|
+
|
|
821
|
+
@Id
|
|
822
|
+
private String id;
|
|
823
|
+
|
|
824
|
+
@Column(nullable = false)
|
|
825
|
+
private String name;
|
|
826
|
+
|
|
827
|
+
private String description;
|
|
828
|
+
|
|
829
|
+
@Column(nullable = false)
|
|
830
|
+
private String status = "active";
|
|
831
|
+
|
|
832
|
+
@Column(name = "created_at", nullable = false)
|
|
833
|
+
private Instant createdAt;
|
|
834
|
+
|
|
835
|
+
@Column(name = "updated_at", nullable = false)
|
|
836
|
+
private Instant updatedAt;
|
|
837
|
+
|
|
838
|
+
public {class_name}() {{
|
|
839
|
+
this.id = UUID.randomUUID().toString();
|
|
840
|
+
this.createdAt = Instant.now();
|
|
841
|
+
this.updatedAt = Instant.now();
|
|
842
|
+
}}
|
|
843
|
+
|
|
844
|
+
public {class_name}(String name, String description) {{
|
|
845
|
+
this();
|
|
846
|
+
this.name = name;
|
|
847
|
+
this.description = description;
|
|
848
|
+
}}
|
|
849
|
+
|
|
850
|
+
// Getters and setters
|
|
851
|
+
public String getId() {{ return id; }}
|
|
852
|
+
public void setId(String id) {{ this.id = id; }}
|
|
853
|
+
|
|
854
|
+
public String getName() {{ return name; }}
|
|
855
|
+
public void setName(String name) {{ this.name = name; }}
|
|
856
|
+
|
|
857
|
+
public String getDescription() {{ return description; }}
|
|
858
|
+
public void setDescription(String description) {{ this.description = description; }}
|
|
859
|
+
|
|
860
|
+
public String getStatus() {{ return status; }}
|
|
861
|
+
public void setStatus(String status) {{ this.status = status; }}
|
|
862
|
+
|
|
863
|
+
public Instant getCreatedAt() {{ return createdAt; }}
|
|
864
|
+
public void setCreatedAt(Instant createdAt) {{ this.createdAt = createdAt; }}
|
|
865
|
+
|
|
866
|
+
public Instant getUpdatedAt() {{ return updatedAt; }}
|
|
867
|
+
public void setUpdatedAt(Instant updatedAt) {{ this.updatedAt = updatedAt; }}
|
|
868
|
+
|
|
869
|
+
@PreUpdate
|
|
870
|
+
protected void onUpdate() {{
|
|
871
|
+
this.updatedAt = Instant.now();
|
|
872
|
+
}}
|
|
873
|
+
}}
|
|
874
|
+
'''
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
def _generate_java_service_code(entity: str, spec: str) -> str:
|
|
878
|
+
"""Generate a Spring service class (Java)."""
|
|
879
|
+
class_name = entity.capitalize()
|
|
880
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
881
|
+
package com.icdev.service;
|
|
882
|
+
|
|
883
|
+
import com.icdev.model.{class_name};
|
|
884
|
+
import org.springframework.stereotype.Service;
|
|
885
|
+
|
|
886
|
+
import java.util.*;
|
|
887
|
+
import java.util.logging.Logger;
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* Service layer for {entity} business logic.
|
|
891
|
+
*
|
|
892
|
+
* Spec: {spec}
|
|
893
|
+
* Generated by ICDEV Builder - code_generator.py
|
|
894
|
+
*/
|
|
895
|
+
@Service
|
|
896
|
+
public class {class_name}Service {{
|
|
897
|
+
|
|
898
|
+
private static final Logger logger = Logger.getLogger({class_name}Service.class.getName());
|
|
899
|
+
private final Map<String, Map<String, Object>> store = new LinkedHashMap<>();
|
|
900
|
+
|
|
901
|
+
public {class_name}Service() {{
|
|
902
|
+
logger.info("{class_name}Service initialized");
|
|
903
|
+
}}
|
|
904
|
+
|
|
905
|
+
public Map<String, Object> create(Map<String, Object> data) {{
|
|
906
|
+
String id = UUID.randomUUID().toString();
|
|
907
|
+
data.put("id", id);
|
|
908
|
+
data.put("created_at", java.time.Instant.now().toString());
|
|
909
|
+
data.put("updated_at", java.time.Instant.now().toString());
|
|
910
|
+
store.put(id, data);
|
|
911
|
+
logger.info("{class_name} created: " + id);
|
|
912
|
+
return data;
|
|
913
|
+
}}
|
|
914
|
+
|
|
915
|
+
public Map<String, Object> getById(String id) {{
|
|
916
|
+
return store.get(id);
|
|
917
|
+
}}
|
|
918
|
+
|
|
919
|
+
public List<Map<String, Object>> listAll() {{
|
|
920
|
+
return new ArrayList<>(store.values());
|
|
921
|
+
}}
|
|
922
|
+
|
|
923
|
+
public Map<String, Object> update(String id, Map<String, Object> data) {{
|
|
924
|
+
if (!store.containsKey(id)) {{
|
|
925
|
+
return null;
|
|
926
|
+
}}
|
|
927
|
+
store.get(id).putAll(data);
|
|
928
|
+
store.get(id).put("updated_at", java.time.Instant.now().toString());
|
|
929
|
+
return store.get(id);
|
|
930
|
+
}}
|
|
931
|
+
|
|
932
|
+
public boolean delete(String id) {{
|
|
933
|
+
return store.remove(id) != null;
|
|
934
|
+
}}
|
|
935
|
+
}}
|
|
936
|
+
'''
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
# ---------------------------------------------------------------------------
|
|
940
|
+
# Go code generators
|
|
941
|
+
# ---------------------------------------------------------------------------
|
|
942
|
+
|
|
943
|
+
def _generate_go_api_code(entity: str, spec: str, secure: bool = True) -> str:
|
|
944
|
+
"""Generate a net/http handler (Go)."""
|
|
945
|
+
auth_check = ""
|
|
946
|
+
if secure:
|
|
947
|
+
auth_check = """
|
|
948
|
+
// Auth middleware check (NIST AC-3)
|
|
949
|
+
if !authMiddleware(w, r) {{
|
|
950
|
+
return
|
|
951
|
+
}}"""
|
|
952
|
+
auth_func = ""
|
|
953
|
+
if secure:
|
|
954
|
+
auth_func = """
|
|
955
|
+
// authMiddleware verifies the request is authenticated (NIST AC-3).
|
|
956
|
+
// Replace with your actual auth mechanism.
|
|
957
|
+
func authMiddleware(w http.ResponseWriter, r *http.Request) bool {{
|
|
958
|
+
token := r.Header.Get("Authorization")
|
|
959
|
+
if token == "" {{
|
|
960
|
+
http.Error(w, `{{"error":"authentication required"}}`, http.StatusUnauthorized)
|
|
961
|
+
return false
|
|
962
|
+
}}
|
|
963
|
+
return true
|
|
964
|
+
}}
|
|
965
|
+
"""
|
|
966
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
967
|
+
package api
|
|
968
|
+
|
|
969
|
+
// API handlers for {entity}.
|
|
970
|
+
//
|
|
971
|
+
// Spec: {spec}
|
|
972
|
+
// Generated by ICDEV Builder - code_generator.py
|
|
973
|
+
|
|
974
|
+
import (
|
|
975
|
+
"encoding/json"
|
|
976
|
+
"net/http"
|
|
977
|
+
"strings"
|
|
978
|
+
"sync"
|
|
979
|
+
)
|
|
980
|
+
{auth_func}
|
|
981
|
+
type {entity.capitalize()}Handler struct {{
|
|
982
|
+
mu sync.RWMutex
|
|
983
|
+
store map[string]map[string]interface{{}}
|
|
984
|
+
}}
|
|
985
|
+
|
|
986
|
+
func New{entity.capitalize()}Handler() *{entity.capitalize()}Handler {{
|
|
987
|
+
return &{entity.capitalize()}Handler{{
|
|
988
|
+
store: make(map[string]map[string]interface{{}}),
|
|
989
|
+
}}
|
|
990
|
+
}}
|
|
991
|
+
|
|
992
|
+
func (h *{entity.capitalize()}Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {{
|
|
993
|
+
w.Header().Set("Content-Type", "application/json"){auth_check}
|
|
994
|
+
switch r.Method {{
|
|
995
|
+
case http.MethodGet:
|
|
996
|
+
h.handleGet(w, r)
|
|
997
|
+
case http.MethodPost:
|
|
998
|
+
h.handlePost(w, r)
|
|
999
|
+
case http.MethodPut:
|
|
1000
|
+
h.handlePut(w, r)
|
|
1001
|
+
case http.MethodDelete:
|
|
1002
|
+
h.handleDelete(w, r)
|
|
1003
|
+
default:
|
|
1004
|
+
http.Error(w, `{{"error":"method not allowed"}}`, http.StatusMethodNotAllowed)
|
|
1005
|
+
}}
|
|
1006
|
+
}}
|
|
1007
|
+
|
|
1008
|
+
func (h *{entity.capitalize()}Handler) handleGet(w http.ResponseWriter, r *http.Request) {{
|
|
1009
|
+
id := strings.TrimPrefix(r.URL.Path, "/api/{entity}/")
|
|
1010
|
+
h.mu.RLock()
|
|
1011
|
+
defer h.mu.RUnlock()
|
|
1012
|
+
if id == "" || id == "/api/{entity}" {{
|
|
1013
|
+
items := make([]map[string]interface{{}}, 0, len(h.store))
|
|
1014
|
+
for _, v := range h.store {{
|
|
1015
|
+
items = append(items, v)
|
|
1016
|
+
}}
|
|
1017
|
+
json.NewEncoder(w).Encode(map[string]interface{{}}{{"data": items, "count": len(items)}})
|
|
1018
|
+
return
|
|
1019
|
+
}}
|
|
1020
|
+
item, ok := h.store[id]
|
|
1021
|
+
if !ok {{
|
|
1022
|
+
http.Error(w, `{{"error":"not found"}}`, http.StatusNotFound)
|
|
1023
|
+
return
|
|
1024
|
+
}}
|
|
1025
|
+
json.NewEncoder(w).Encode(item)
|
|
1026
|
+
}}
|
|
1027
|
+
|
|
1028
|
+
func (h *{entity.capitalize()}Handler) handlePost(w http.ResponseWriter, r *http.Request) {{
|
|
1029
|
+
var data map[string]interface{{}}
|
|
1030
|
+
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {{
|
|
1031
|
+
http.Error(w, `{{"error":"invalid json"}}`, http.StatusBadRequest)
|
|
1032
|
+
return
|
|
1033
|
+
}}
|
|
1034
|
+
h.mu.Lock()
|
|
1035
|
+
defer h.mu.Unlock()
|
|
1036
|
+
// TODO: Generate UUID for id
|
|
1037
|
+
data["id"] = "generated-id"
|
|
1038
|
+
h.store[data["id"].(string)] = data
|
|
1039
|
+
w.WriteHeader(http.StatusCreated)
|
|
1040
|
+
json.NewEncoder(w).Encode(data)
|
|
1041
|
+
}}
|
|
1042
|
+
|
|
1043
|
+
func (h *{entity.capitalize()}Handler) handlePut(w http.ResponseWriter, r *http.Request) {{
|
|
1044
|
+
id := strings.TrimPrefix(r.URL.Path, "/api/{entity}/")
|
|
1045
|
+
h.mu.Lock()
|
|
1046
|
+
defer h.mu.Unlock()
|
|
1047
|
+
if _, ok := h.store[id]; !ok {{
|
|
1048
|
+
http.Error(w, `{{"error":"not found"}}`, http.StatusNotFound)
|
|
1049
|
+
return
|
|
1050
|
+
}}
|
|
1051
|
+
var data map[string]interface{{}}
|
|
1052
|
+
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {{
|
|
1053
|
+
http.Error(w, `{{"error":"invalid json"}}`, http.StatusBadRequest)
|
|
1054
|
+
return
|
|
1055
|
+
}}
|
|
1056
|
+
for k, v := range data {{
|
|
1057
|
+
h.store[id][k] = v
|
|
1058
|
+
}}
|
|
1059
|
+
json.NewEncoder(w).Encode(h.store[id])
|
|
1060
|
+
}}
|
|
1061
|
+
|
|
1062
|
+
func (h *{entity.capitalize()}Handler) handleDelete(w http.ResponseWriter, r *http.Request) {{
|
|
1063
|
+
id := strings.TrimPrefix(r.URL.Path, "/api/{entity}/")
|
|
1064
|
+
h.mu.Lock()
|
|
1065
|
+
defer h.mu.Unlock()
|
|
1066
|
+
if _, ok := h.store[id]; !ok {{
|
|
1067
|
+
http.Error(w, `{{"error":"not found"}}`, http.StatusNotFound)
|
|
1068
|
+
return
|
|
1069
|
+
}}
|
|
1070
|
+
delete(h.store, id)
|
|
1071
|
+
w.WriteHeader(http.StatusNoContent)
|
|
1072
|
+
}}
|
|
1073
|
+
'''
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
def _generate_go_model_code(entity: str, spec: str) -> str:
|
|
1077
|
+
"""Generate a Go struct model with JSON tags."""
|
|
1078
|
+
class_name = entity.capitalize()
|
|
1079
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1080
|
+
package model
|
|
1081
|
+
|
|
1082
|
+
// {class_name} represents the {entity} data model.
|
|
1083
|
+
//
|
|
1084
|
+
// Spec: {spec}
|
|
1085
|
+
// Generated by ICDEV Builder - code_generator.py
|
|
1086
|
+
|
|
1087
|
+
import (
|
|
1088
|
+
"encoding/json"
|
|
1089
|
+
"time"
|
|
1090
|
+
)
|
|
1091
|
+
|
|
1092
|
+
type {class_name} struct {{
|
|
1093
|
+
ID string `json:"id"`
|
|
1094
|
+
Name string `json:"name"`
|
|
1095
|
+
Description string `json:"description,omitempty"`
|
|
1096
|
+
Status string `json:"status"`
|
|
1097
|
+
Metadata map[string]interface{{}} `json:"metadata,omitempty"`
|
|
1098
|
+
CreatedAt time.Time `json:"created_at"`
|
|
1099
|
+
UpdatedAt time.Time `json:"updated_at"`
|
|
1100
|
+
}}
|
|
1101
|
+
|
|
1102
|
+
func New{class_name}(name, description string) *{class_name} {{
|
|
1103
|
+
now := time.Now().UTC()
|
|
1104
|
+
return &{class_name}{{
|
|
1105
|
+
ID: "generated-id", // TODO: Use UUID library
|
|
1106
|
+
Name: name,
|
|
1107
|
+
Description: description,
|
|
1108
|
+
Status: "active",
|
|
1109
|
+
Metadata: make(map[string]interface{{}}),
|
|
1110
|
+
CreatedAt: now,
|
|
1111
|
+
UpdatedAt: now,
|
|
1112
|
+
}}
|
|
1113
|
+
}}
|
|
1114
|
+
|
|
1115
|
+
func (m *{class_name}) ToJSON() ([]byte, error) {{
|
|
1116
|
+
return json.Marshal(m)
|
|
1117
|
+
}}
|
|
1118
|
+
|
|
1119
|
+
func {class_name}FromJSON(data []byte) (*{class_name}, error) {{
|
|
1120
|
+
var m {class_name}
|
|
1121
|
+
if err := json.Unmarshal(data, &m); err != nil {{
|
|
1122
|
+
return nil, err
|
|
1123
|
+
}}
|
|
1124
|
+
return &m, nil
|
|
1125
|
+
}}
|
|
1126
|
+
|
|
1127
|
+
func (m *{class_name}) Validate() []string {{
|
|
1128
|
+
var errors []string
|
|
1129
|
+
if m.Name == "" {{
|
|
1130
|
+
errors = append(errors, "name is required")
|
|
1131
|
+
}}
|
|
1132
|
+
validStatuses := map[string]bool{{"active": true, "inactive": true, "archived": true}}
|
|
1133
|
+
if !validStatuses[m.Status] {{
|
|
1134
|
+
errors = append(errors, "invalid status: "+m.Status)
|
|
1135
|
+
}}
|
|
1136
|
+
return errors
|
|
1137
|
+
}}
|
|
1138
|
+
'''
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
def _generate_go_service_code(entity: str, spec: str) -> str:
|
|
1142
|
+
"""Generate a Go service with interface."""
|
|
1143
|
+
class_name = entity.capitalize()
|
|
1144
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1145
|
+
package service
|
|
1146
|
+
|
|
1147
|
+
// {class_name}Service provides business logic for {entity} operations.
|
|
1148
|
+
//
|
|
1149
|
+
// Spec: {spec}
|
|
1150
|
+
// Generated by ICDEV Builder - code_generator.py
|
|
1151
|
+
|
|
1152
|
+
import (
|
|
1153
|
+
"fmt"
|
|
1154
|
+
"log"
|
|
1155
|
+
"sync"
|
|
1156
|
+
)
|
|
1157
|
+
|
|
1158
|
+
// {class_name}Repository defines the data access interface.
|
|
1159
|
+
type {class_name}Repository interface {{
|
|
1160
|
+
Create(data map[string]interface{{}}) (map[string]interface{{}}, error)
|
|
1161
|
+
GetByID(id string) (map[string]interface{{}}, error)
|
|
1162
|
+
ListAll() ([]map[string]interface{{}}, error)
|
|
1163
|
+
Update(id string, data map[string]interface{{}}) (map[string]interface{{}}, error)
|
|
1164
|
+
Delete(id string) error
|
|
1165
|
+
}}
|
|
1166
|
+
|
|
1167
|
+
// {class_name}Service encapsulates business logic for {entity}.
|
|
1168
|
+
type {class_name}Service struct {{
|
|
1169
|
+
mu sync.RWMutex
|
|
1170
|
+
repo {class_name}Repository
|
|
1171
|
+
}}
|
|
1172
|
+
|
|
1173
|
+
// New{class_name}Service creates a new service instance.
|
|
1174
|
+
func New{class_name}Service(repo {class_name}Repository) *{class_name}Service {{
|
|
1175
|
+
return &{class_name}Service{{repo: repo}}
|
|
1176
|
+
}}
|
|
1177
|
+
|
|
1178
|
+
// Create validates and creates a new {entity}.
|
|
1179
|
+
func (s *{class_name}Service) Create(data map[string]interface{{}}) (map[string]interface{{}}, error) {{
|
|
1180
|
+
if err := s.validate(data); err != nil {{
|
|
1181
|
+
return nil, err
|
|
1182
|
+
}}
|
|
1183
|
+
s.mu.Lock()
|
|
1184
|
+
defer s.mu.Unlock()
|
|
1185
|
+
result, err := s.repo.Create(data)
|
|
1186
|
+
if err != nil {{
|
|
1187
|
+
return nil, fmt.Errorf("failed to create {entity}: %w", err)
|
|
1188
|
+
}}
|
|
1189
|
+
log.Printf("{class_name} created: %v", result["id"])
|
|
1190
|
+
return result, nil
|
|
1191
|
+
}}
|
|
1192
|
+
|
|
1193
|
+
// GetByID retrieves a {entity} by its ID.
|
|
1194
|
+
func (s *{class_name}Service) GetByID(id string) (map[string]interface{{}}, error) {{
|
|
1195
|
+
s.mu.RLock()
|
|
1196
|
+
defer s.mu.RUnlock()
|
|
1197
|
+
return s.repo.GetByID(id)
|
|
1198
|
+
}}
|
|
1199
|
+
|
|
1200
|
+
// ListAll returns all {entity} records.
|
|
1201
|
+
func (s *{class_name}Service) ListAll() ([]map[string]interface{{}}, error) {{
|
|
1202
|
+
s.mu.RLock()
|
|
1203
|
+
defer s.mu.RUnlock()
|
|
1204
|
+
return s.repo.ListAll()
|
|
1205
|
+
}}
|
|
1206
|
+
|
|
1207
|
+
// Update modifies an existing {entity}.
|
|
1208
|
+
func (s *{class_name}Service) Update(id string, data map[string]interface{{}}) (map[string]interface{{}}, error) {{
|
|
1209
|
+
s.mu.Lock()
|
|
1210
|
+
defer s.mu.Unlock()
|
|
1211
|
+
return s.repo.Update(id, data)
|
|
1212
|
+
}}
|
|
1213
|
+
|
|
1214
|
+
// Delete removes a {entity} by ID.
|
|
1215
|
+
func (s *{class_name}Service) Delete(id string) error {{
|
|
1216
|
+
s.mu.Lock()
|
|
1217
|
+
defer s.mu.Unlock()
|
|
1218
|
+
return s.repo.Delete(id)
|
|
1219
|
+
}}
|
|
1220
|
+
|
|
1221
|
+
func (s *{class_name}Service) validate(data map[string]interface{{}}) error {{
|
|
1222
|
+
if _, ok := data["name"]; !ok {{
|
|
1223
|
+
return fmt.Errorf("validation failed: name is required")
|
|
1224
|
+
}}
|
|
1225
|
+
return nil
|
|
1226
|
+
}}
|
|
1227
|
+
'''
|
|
1228
|
+
|
|
1229
|
+
|
|
1230
|
+
# ---------------------------------------------------------------------------
|
|
1231
|
+
# TypeScript code generators
|
|
1232
|
+
# ---------------------------------------------------------------------------
|
|
1233
|
+
|
|
1234
|
+
def _generate_typescript_api_code(entity: str, spec: str, secure: bool = True) -> str:
|
|
1235
|
+
"""Generate an Express router (TypeScript)."""
|
|
1236
|
+
class_name = entity.capitalize()
|
|
1237
|
+
auth_import = ""
|
|
1238
|
+
auth_mw = ""
|
|
1239
|
+
validate_import = ""
|
|
1240
|
+
validate_post = ""
|
|
1241
|
+
validate_put = ""
|
|
1242
|
+
if secure:
|
|
1243
|
+
auth_import = "\nimport { authMiddleware } from './middleware/auth';"
|
|
1244
|
+
auth_mw = ", authMiddleware"
|
|
1245
|
+
validate_import = """
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
* Validate required fields in request body (NIST SI-10).
|
|
1249
|
+
*/
|
|
1250
|
+
function validateBody(body: Record<string, unknown>, required: string[]): string | null {{
|
|
1251
|
+
if (!body || typeof body !== 'object') return 'Request body must be a JSON object';
|
|
1252
|
+
const missing = required.filter(f => !(f in body));
|
|
1253
|
+
return missing.length ? `Missing required fields: ${{missing.join(', ')}}` : null;
|
|
1254
|
+
}}"""
|
|
1255
|
+
validate_post = """
|
|
1256
|
+
const err = validateBody(req.body, []);
|
|
1257
|
+
if (err) return res.status(400).json({{ error: err }});"""
|
|
1258
|
+
validate_put = """
|
|
1259
|
+
const err = validateBody(req.body, []);
|
|
1260
|
+
if (err) return res.status(400).json({{ error: err }});"""
|
|
1261
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1262
|
+
/**
|
|
1263
|
+
* API routes for {entity}.
|
|
1264
|
+
*
|
|
1265
|
+
* Spec: {spec}
|
|
1266
|
+
* Generated by ICDEV Builder - code_generator.py
|
|
1267
|
+
*/
|
|
1268
|
+
|
|
1269
|
+
import {{ Router, Request, Response }} from 'express';
|
|
1270
|
+
import {{ {class_name}Service }} from './{entity}.service';{auth_import}
|
|
1271
|
+
|
|
1272
|
+
const router = Router();
|
|
1273
|
+
const service = new {class_name}Service();
|
|
1274
|
+
{validate_import}
|
|
1275
|
+
|
|
1276
|
+
/**
|
|
1277
|
+
* GET /api/{entity} - List all {entity} records.
|
|
1278
|
+
*/
|
|
1279
|
+
router.get('/'{auth_mw}, async (req: Request, res: Response) => {{
|
|
1280
|
+
try {{
|
|
1281
|
+
const items = await service.listAll();
|
|
1282
|
+
res.json({{ data: items, count: items.length }});
|
|
1283
|
+
}} catch (err) {{
|
|
1284
|
+
res.status(500).json({{ error: 'Internal server error' }});
|
|
1285
|
+
}}
|
|
1286
|
+
}});
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* GET /api/{entity}/:id - Get a single {entity} by ID.
|
|
1290
|
+
*/
|
|
1291
|
+
router.get('/:id'{auth_mw}, async (req: Request, res: Response) => {{
|
|
1292
|
+
try {{
|
|
1293
|
+
const item = await service.getById(req.params.id);
|
|
1294
|
+
if (!item) {{
|
|
1295
|
+
return res.status(404).json({{ error: '{class_name} not found' }});
|
|
1296
|
+
}}
|
|
1297
|
+
res.json(item);
|
|
1298
|
+
}} catch (err) {{
|
|
1299
|
+
res.status(500).json({{ error: 'Internal server error' }});
|
|
1300
|
+
}}
|
|
1301
|
+
}});
|
|
1302
|
+
|
|
1303
|
+
/**
|
|
1304
|
+
* POST /api/{entity} - Create a new {entity}.
|
|
1305
|
+
*/
|
|
1306
|
+
router.post('/'{auth_mw}, async (req: Request, res: Response) => {{
|
|
1307
|
+
try {{{validate_post}
|
|
1308
|
+
const created = await service.create(req.body);
|
|
1309
|
+
res.status(201).json(created);
|
|
1310
|
+
}} catch (err) {{
|
|
1311
|
+
res.status(400).json({{ error: (err as Error).message }});
|
|
1312
|
+
}}
|
|
1313
|
+
}});
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* PUT /api/{entity}/:id - Update an existing {entity}.
|
|
1317
|
+
*/
|
|
1318
|
+
router.put('/:id'{auth_mw}, async (req: Request, res: Response) => {{
|
|
1319
|
+
try {{{validate_put}
|
|
1320
|
+
const updated = await service.update(req.params.id, req.body);
|
|
1321
|
+
if (!updated) {{
|
|
1322
|
+
return res.status(404).json({{ error: '{class_name} not found' }});
|
|
1323
|
+
}}
|
|
1324
|
+
res.json(updated);
|
|
1325
|
+
}} catch (err) {{
|
|
1326
|
+
res.status(400).json({{ error: (err as Error).message }});
|
|
1327
|
+
}}
|
|
1328
|
+
}});
|
|
1329
|
+
|
|
1330
|
+
/**
|
|
1331
|
+
* DELETE /api/{entity}/:id - Delete a {entity}.
|
|
1332
|
+
*/
|
|
1333
|
+
router.delete('/:id'{auth_mw}, async (req: Request, res: Response) => {{
|
|
1334
|
+
try {{
|
|
1335
|
+
const deleted = await service.delete(req.params.id);
|
|
1336
|
+
if (!deleted) {{
|
|
1337
|
+
return res.status(404).json({{ error: '{class_name} not found' }});
|
|
1338
|
+
}}
|
|
1339
|
+
res.status(204).send();
|
|
1340
|
+
}} catch (err) {{
|
|
1341
|
+
res.status(500).json({{ error: 'Internal server error' }});
|
|
1342
|
+
}}
|
|
1343
|
+
}});
|
|
1344
|
+
|
|
1345
|
+
export default router;
|
|
1346
|
+
'''
|
|
1347
|
+
|
|
1348
|
+
|
|
1349
|
+
def _generate_typescript_model_code(entity: str, spec: str) -> str:
|
|
1350
|
+
"""Generate a TypeScript interface and class model."""
|
|
1351
|
+
class_name = entity.capitalize()
|
|
1352
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1353
|
+
/**
|
|
1354
|
+
* Data model for {entity}.
|
|
1355
|
+
*
|
|
1356
|
+
* Spec: {spec}
|
|
1357
|
+
* Generated by ICDEV Builder - code_generator.py
|
|
1358
|
+
*/
|
|
1359
|
+
|
|
1360
|
+
export interface I{class_name} {{
|
|
1361
|
+
id: string;
|
|
1362
|
+
name: string;
|
|
1363
|
+
description?: string;
|
|
1364
|
+
status: 'active' | 'inactive' | 'archived';
|
|
1365
|
+
metadata?: Record<string, unknown>;
|
|
1366
|
+
createdAt: string;
|
|
1367
|
+
updatedAt: string;
|
|
1368
|
+
}}
|
|
1369
|
+
|
|
1370
|
+
export class {class_name} implements I{class_name} {{
|
|
1371
|
+
id: string;
|
|
1372
|
+
name: string;
|
|
1373
|
+
description: string;
|
|
1374
|
+
status: 'active' | 'inactive' | 'archived';
|
|
1375
|
+
metadata: Record<string, unknown>;
|
|
1376
|
+
createdAt: string;
|
|
1377
|
+
updatedAt: string;
|
|
1378
|
+
|
|
1379
|
+
constructor(data: Partial<I{class_name}> = {{}}) {{
|
|
1380
|
+
const now = new Date().toISOString();
|
|
1381
|
+
this.id = data.id || crypto.randomUUID();
|
|
1382
|
+
this.name = data.name || '';
|
|
1383
|
+
this.description = data.description || '';
|
|
1384
|
+
this.status = data.status || 'active';
|
|
1385
|
+
this.metadata = data.metadata || {{}};
|
|
1386
|
+
this.createdAt = data.createdAt || now;
|
|
1387
|
+
this.updatedAt = data.updatedAt || now;
|
|
1388
|
+
}}
|
|
1389
|
+
|
|
1390
|
+
toJSON(): I{class_name} {{
|
|
1391
|
+
return {{
|
|
1392
|
+
id: this.id,
|
|
1393
|
+
name: this.name,
|
|
1394
|
+
description: this.description,
|
|
1395
|
+
status: this.status,
|
|
1396
|
+
metadata: this.metadata,
|
|
1397
|
+
createdAt: this.createdAt,
|
|
1398
|
+
updatedAt: this.updatedAt,
|
|
1399
|
+
}};
|
|
1400
|
+
}}
|
|
1401
|
+
|
|
1402
|
+
validate(): string[] {{
|
|
1403
|
+
const errors: string[] = [];
|
|
1404
|
+
if (!this.name) {{
|
|
1405
|
+
errors.push('name is required');
|
|
1406
|
+
}}
|
|
1407
|
+
if (!['active', 'inactive', 'archived'].includes(this.status)) {{
|
|
1408
|
+
errors.push(`invalid status: ${{this.status}}`);
|
|
1409
|
+
}}
|
|
1410
|
+
return errors;
|
|
1411
|
+
}}
|
|
1412
|
+
}}
|
|
1413
|
+
'''
|
|
1414
|
+
|
|
1415
|
+
|
|
1416
|
+
def _generate_typescript_service_code(entity: str, spec: str) -> str:
|
|
1417
|
+
"""Generate a TypeScript service class."""
|
|
1418
|
+
class_name = entity.capitalize()
|
|
1419
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1420
|
+
/**
|
|
1421
|
+
* Service layer for {entity} business logic.
|
|
1422
|
+
*
|
|
1423
|
+
* Spec: {spec}
|
|
1424
|
+
* Generated by ICDEV Builder - code_generator.py
|
|
1425
|
+
*/
|
|
1426
|
+
|
|
1427
|
+
import {{ I{class_name}, {class_name} }} from './{entity}.model';
|
|
1428
|
+
|
|
1429
|
+
export interface I{class_name}Repository {{
|
|
1430
|
+
create(data: Partial<I{class_name}>): Promise<I{class_name}>;
|
|
1431
|
+
getById(id: string): Promise<I{class_name} | null>;
|
|
1432
|
+
listAll(): Promise<I{class_name}[]>;
|
|
1433
|
+
update(id: string, data: Partial<I{class_name}>): Promise<I{class_name} | null>;
|
|
1434
|
+
delete(id: string): Promise<boolean>;
|
|
1435
|
+
}}
|
|
1436
|
+
|
|
1437
|
+
export class {class_name}Service {{
|
|
1438
|
+
private repository: I{class_name}Repository;
|
|
1439
|
+
|
|
1440
|
+
constructor(repository?: I{class_name}Repository) {{
|
|
1441
|
+
this.repository = repository || new InMemory{class_name}Repository();
|
|
1442
|
+
}}
|
|
1443
|
+
|
|
1444
|
+
async create(data: Partial<I{class_name}>): Promise<I{class_name}> {{
|
|
1445
|
+
const entity = new {class_name}(data);
|
|
1446
|
+
const errors = entity.validate();
|
|
1447
|
+
if (errors.length > 0) {{
|
|
1448
|
+
throw new Error(`Validation failed: ${{errors.join('; ')}}`);
|
|
1449
|
+
}}
|
|
1450
|
+
return this.repository.create(entity.toJSON());
|
|
1451
|
+
}}
|
|
1452
|
+
|
|
1453
|
+
async getById(id: string): Promise<I{class_name} | null> {{
|
|
1454
|
+
return this.repository.getById(id);
|
|
1455
|
+
}}
|
|
1456
|
+
|
|
1457
|
+
async listAll(): Promise<I{class_name}[]> {{
|
|
1458
|
+
return this.repository.listAll();
|
|
1459
|
+
}}
|
|
1460
|
+
|
|
1461
|
+
async update(id: string, data: Partial<I{class_name}>): Promise<I{class_name} | null> {{
|
|
1462
|
+
return this.repository.update(id, data);
|
|
1463
|
+
}}
|
|
1464
|
+
|
|
1465
|
+
async delete(id: string): Promise<boolean> {{
|
|
1466
|
+
return this.repository.delete(id);
|
|
1467
|
+
}}
|
|
1468
|
+
}}
|
|
1469
|
+
|
|
1470
|
+
class InMemory{class_name}Repository implements I{class_name}Repository {{
|
|
1471
|
+
private store = new Map<string, I{class_name}>();
|
|
1472
|
+
|
|
1473
|
+
async create(data: I{class_name}): Promise<I{class_name}> {{
|
|
1474
|
+
this.store.set(data.id, data);
|
|
1475
|
+
return data;
|
|
1476
|
+
}}
|
|
1477
|
+
|
|
1478
|
+
async getById(id: string): Promise<I{class_name} | null> {{
|
|
1479
|
+
return this.store.get(id) || null;
|
|
1480
|
+
}}
|
|
1481
|
+
|
|
1482
|
+
async listAll(): Promise<I{class_name}[]> {{
|
|
1483
|
+
return Array.from(this.store.values());
|
|
1484
|
+
}}
|
|
1485
|
+
|
|
1486
|
+
async update(id: string, data: Partial<I{class_name}>): Promise<I{class_name} | null> {{
|
|
1487
|
+
const existing = this.store.get(id);
|
|
1488
|
+
if (!existing) return null;
|
|
1489
|
+
const updated = {{ ...existing, ...data, updatedAt: new Date().toISOString() }};
|
|
1490
|
+
this.store.set(id, updated);
|
|
1491
|
+
return updated;
|
|
1492
|
+
}}
|
|
1493
|
+
|
|
1494
|
+
async delete(id: string): Promise<boolean> {{
|
|
1495
|
+
return this.store.delete(id);
|
|
1496
|
+
}}
|
|
1497
|
+
}}
|
|
1498
|
+
'''
|
|
1499
|
+
|
|
1500
|
+
|
|
1501
|
+
# ---------------------------------------------------------------------------
|
|
1502
|
+
# Rust code generators
|
|
1503
|
+
# ---------------------------------------------------------------------------
|
|
1504
|
+
|
|
1505
|
+
def _generate_rust_api_code(entity: str, spec: str, secure: bool = True) -> str:
|
|
1506
|
+
"""Generate Actix-web handlers (Rust)."""
|
|
1507
|
+
class_name = entity.capitalize()
|
|
1508
|
+
auth_use = ""
|
|
1509
|
+
auth_guard = ""
|
|
1510
|
+
if secure:
|
|
1511
|
+
auth_use = "\nuse actix_web::HttpRequest;"
|
|
1512
|
+
auth_guard = """
|
|
1513
|
+
|
|
1514
|
+
/// Auth guard — verify request has valid authorization (NIST AC-3).
|
|
1515
|
+
fn require_auth(req: &HttpRequest) -> Result<(), HttpResponse> {{
|
|
1516
|
+
match req.headers().get("Authorization") {{
|
|
1517
|
+
Some(_) => Ok(()),
|
|
1518
|
+
None => Err(HttpResponse::Unauthorized().json(json!({{ "error": "Authentication required" }}))),
|
|
1519
|
+
}}
|
|
1520
|
+
}}
|
|
1521
|
+
"""
|
|
1522
|
+
|
|
1523
|
+
auth_check_list = ""
|
|
1524
|
+
auth_check_get = ""
|
|
1525
|
+
auth_check_create = ""
|
|
1526
|
+
auth_check_delete = ""
|
|
1527
|
+
if secure:
|
|
1528
|
+
auth_check_list = """
|
|
1529
|
+
if let Err(resp) = require_auth(&req) {{ return resp; }}"""
|
|
1530
|
+
auth_check_get = """
|
|
1531
|
+
if let Err(resp) = require_auth(&req) {{ return resp; }}"""
|
|
1532
|
+
auth_check_create = """
|
|
1533
|
+
if let Err(resp) = require_auth(&req) {{ return resp; }}"""
|
|
1534
|
+
auth_check_delete = """
|
|
1535
|
+
if let Err(resp) = require_auth(&req) {{ return resp; }}"""
|
|
1536
|
+
|
|
1537
|
+
req_param_list = ", req: HttpRequest" if secure else ""
|
|
1538
|
+
req_param_get = "\n req: HttpRequest," if secure else ""
|
|
1539
|
+
req_param_create = "\n req: HttpRequest," if secure else ""
|
|
1540
|
+
req_param_delete = "\n req: HttpRequest," if secure else ""
|
|
1541
|
+
|
|
1542
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1543
|
+
//! API handlers for {entity}.
|
|
1544
|
+
//!
|
|
1545
|
+
//! Spec: {spec}
|
|
1546
|
+
//! Generated by ICDEV Builder - code_generator.py
|
|
1547
|
+
|
|
1548
|
+
use actix_web::{{web, HttpResponse, Responder}};
|
|
1549
|
+
use serde_json::json;
|
|
1550
|
+
use std::sync::Mutex;
|
|
1551
|
+
use std::collections::HashMap;{auth_use}
|
|
1552
|
+
|
|
1553
|
+
pub struct {class_name}State {{
|
|
1554
|
+
pub store: Mutex<HashMap<String, serde_json::Value>>,
|
|
1555
|
+
}}
|
|
1556
|
+
|
|
1557
|
+
impl {class_name}State {{
|
|
1558
|
+
pub fn new() -> Self {{
|
|
1559
|
+
{class_name}State {{
|
|
1560
|
+
store: Mutex::new(HashMap::new()),
|
|
1561
|
+
}}
|
|
1562
|
+
}}
|
|
1563
|
+
}}
|
|
1564
|
+
{auth_guard}
|
|
1565
|
+
pub async fn list_{entity}(data: web::Data<{class_name}State>{req_param_list}) -> impl Responder {{{auth_check_list}
|
|
1566
|
+
let store = data.store.lock().unwrap();
|
|
1567
|
+
let items: Vec<&serde_json::Value> = store.values().collect();
|
|
1568
|
+
HttpResponse::Ok().json(json!({{ "data": items, "count": items.len() }}))
|
|
1569
|
+
}}
|
|
1570
|
+
|
|
1571
|
+
pub async fn get_{entity}(
|
|
1572
|
+
data: web::Data<{class_name}State>,
|
|
1573
|
+
path: web::Path<String>,{req_param_get}
|
|
1574
|
+
) -> impl Responder {{{auth_check_get}
|
|
1575
|
+
let id = path.into_inner();
|
|
1576
|
+
let store = data.store.lock().unwrap();
|
|
1577
|
+
match store.get(&id) {{
|
|
1578
|
+
Some(item) => HttpResponse::Ok().json(item),
|
|
1579
|
+
None => HttpResponse::NotFound().json(json!({{ "error": "{class_name} not found" }})),
|
|
1580
|
+
}}
|
|
1581
|
+
}}
|
|
1582
|
+
|
|
1583
|
+
pub async fn create_{entity}(
|
|
1584
|
+
data: web::Data<{class_name}State>,
|
|
1585
|
+
body: web::Json<serde_json::Value>,{req_param_create}
|
|
1586
|
+
) -> impl Responder {{{auth_check_create}
|
|
1587
|
+
let mut store = data.store.lock().unwrap();
|
|
1588
|
+
let id = uuid::Uuid::new_v4().to_string();
|
|
1589
|
+
let mut record = body.into_inner();
|
|
1590
|
+
record["id"] = json!(id.clone());
|
|
1591
|
+
store.insert(id, record.clone());
|
|
1592
|
+
HttpResponse::Created().json(record)
|
|
1593
|
+
}}
|
|
1594
|
+
|
|
1595
|
+
pub async fn delete_{entity}(
|
|
1596
|
+
data: web::Data<{class_name}State>,
|
|
1597
|
+
path: web::Path<String>,{req_param_delete}
|
|
1598
|
+
) -> impl Responder {{{auth_check_delete}
|
|
1599
|
+
let id = path.into_inner();
|
|
1600
|
+
let mut store = data.store.lock().unwrap();
|
|
1601
|
+
match store.remove(&id) {{
|
|
1602
|
+
Some(_) => HttpResponse::NoContent().finish(),
|
|
1603
|
+
None => HttpResponse::NotFound().json(json!({{ "error": "{class_name} not found" }})),
|
|
1604
|
+
}}
|
|
1605
|
+
}}
|
|
1606
|
+
|
|
1607
|
+
pub fn configure(cfg: &mut web::ServiceConfig) {{
|
|
1608
|
+
cfg.service(
|
|
1609
|
+
web::resource("/api/{entity}")
|
|
1610
|
+
.route(web::get().to(list_{entity}))
|
|
1611
|
+
.route(web::post().to(create_{entity}))
|
|
1612
|
+
)
|
|
1613
|
+
.service(
|
|
1614
|
+
web::resource("/api/{entity}/{{id}}")
|
|
1615
|
+
.route(web::get().to(get_{entity}))
|
|
1616
|
+
.route(web::delete().to(delete_{entity}))
|
|
1617
|
+
);
|
|
1618
|
+
}}
|
|
1619
|
+
'''
|
|
1620
|
+
|
|
1621
|
+
|
|
1622
|
+
def _generate_rust_model_code(entity: str, spec: str) -> str:
|
|
1623
|
+
"""Generate a Rust struct with serde Serialize/Deserialize."""
|
|
1624
|
+
class_name = entity.capitalize()
|
|
1625
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1626
|
+
//! Data model for {entity}.
|
|
1627
|
+
//!
|
|
1628
|
+
//! Spec: {spec}
|
|
1629
|
+
//! Generated by ICDEV Builder - code_generator.py
|
|
1630
|
+
|
|
1631
|
+
use serde::{{Deserialize, Serialize}};
|
|
1632
|
+
use std::collections::HashMap;
|
|
1633
|
+
|
|
1634
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
1635
|
+
pub struct {class_name} {{
|
|
1636
|
+
pub id: String,
|
|
1637
|
+
pub name: String,
|
|
1638
|
+
#[serde(default)]
|
|
1639
|
+
pub description: String,
|
|
1640
|
+
#[serde(default = "default_status")]
|
|
1641
|
+
pub status: String,
|
|
1642
|
+
#[serde(default)]
|
|
1643
|
+
pub metadata: HashMap<String, serde_json::Value>,
|
|
1644
|
+
pub created_at: String,
|
|
1645
|
+
pub updated_at: String,
|
|
1646
|
+
}}
|
|
1647
|
+
|
|
1648
|
+
fn default_status() -> String {{
|
|
1649
|
+
"active".to_string()
|
|
1650
|
+
}}
|
|
1651
|
+
|
|
1652
|
+
impl {class_name} {{
|
|
1653
|
+
pub fn new(name: &str, description: &str) -> Self {{
|
|
1654
|
+
let now = chrono::Utc::now().to_rfc3339();
|
|
1655
|
+
{class_name} {{
|
|
1656
|
+
id: uuid::Uuid::new_v4().to_string(),
|
|
1657
|
+
name: name.to_string(),
|
|
1658
|
+
description: description.to_string(),
|
|
1659
|
+
status: "active".to_string(),
|
|
1660
|
+
metadata: HashMap::new(),
|
|
1661
|
+
created_at: now.clone(),
|
|
1662
|
+
updated_at: now,
|
|
1663
|
+
}}
|
|
1664
|
+
}}
|
|
1665
|
+
|
|
1666
|
+
pub fn validate(&self) -> Vec<String> {{
|
|
1667
|
+
let mut errors = Vec::new();
|
|
1668
|
+
if self.name.is_empty() {{
|
|
1669
|
+
errors.push("name is required".to_string());
|
|
1670
|
+
}}
|
|
1671
|
+
let valid_statuses = ["active", "inactive", "archived"];
|
|
1672
|
+
if !valid_statuses.contains(&self.status.as_str()) {{
|
|
1673
|
+
errors.push(format!("invalid status: {{}}", self.status));
|
|
1674
|
+
}}
|
|
1675
|
+
errors
|
|
1676
|
+
}}
|
|
1677
|
+
}}
|
|
1678
|
+
|
|
1679
|
+
impl Default for {class_name} {{
|
|
1680
|
+
fn default() -> Self {{
|
|
1681
|
+
Self::new("", "")
|
|
1682
|
+
}}
|
|
1683
|
+
}}
|
|
1684
|
+
'''
|
|
1685
|
+
|
|
1686
|
+
|
|
1687
|
+
def _generate_rust_service_code(entity: str, spec: str) -> str:
|
|
1688
|
+
"""Generate a Rust service with trait."""
|
|
1689
|
+
class_name = entity.capitalize()
|
|
1690
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1691
|
+
//! Service layer for {entity} business logic.
|
|
1692
|
+
//!
|
|
1693
|
+
//! Spec: {spec}
|
|
1694
|
+
//! Generated by ICDEV Builder - code_generator.py
|
|
1695
|
+
|
|
1696
|
+
use std::collections::HashMap;
|
|
1697
|
+
use std::sync::{{Arc, RwLock}};
|
|
1698
|
+
|
|
1699
|
+
pub trait {class_name}Repository: Send + Sync {{
|
|
1700
|
+
fn create(&self, data: HashMap<String, String>) -> Result<HashMap<String, String>, String>;
|
|
1701
|
+
fn get_by_id(&self, id: &str) -> Result<Option<HashMap<String, String>>, String>;
|
|
1702
|
+
fn list_all(&self) -> Result<Vec<HashMap<String, String>>, String>;
|
|
1703
|
+
fn update(&self, id: &str, data: HashMap<String, String>) -> Result<Option<HashMap<String, String>>, String>;
|
|
1704
|
+
fn delete(&self, id: &str) -> Result<bool, String>;
|
|
1705
|
+
}}
|
|
1706
|
+
|
|
1707
|
+
pub struct {class_name}Service {{
|
|
1708
|
+
repo: Arc<dyn {class_name}Repository>,
|
|
1709
|
+
}}
|
|
1710
|
+
|
|
1711
|
+
impl {class_name}Service {{
|
|
1712
|
+
pub fn new(repo: Arc<dyn {class_name}Repository>) -> Self {{
|
|
1713
|
+
{class_name}Service {{ repo }}
|
|
1714
|
+
}}
|
|
1715
|
+
|
|
1716
|
+
pub fn create(&self, data: HashMap<String, String>) -> Result<HashMap<String, String>, String> {{
|
|
1717
|
+
self.validate(&data)?;
|
|
1718
|
+
self.repo.create(data)
|
|
1719
|
+
}}
|
|
1720
|
+
|
|
1721
|
+
pub fn get_by_id(&self, id: &str) -> Result<Option<HashMap<String, String>>, String> {{
|
|
1722
|
+
self.repo.get_by_id(id)
|
|
1723
|
+
}}
|
|
1724
|
+
|
|
1725
|
+
pub fn list_all(&self) -> Result<Vec<HashMap<String, String>>, String> {{
|
|
1726
|
+
self.repo.list_all()
|
|
1727
|
+
}}
|
|
1728
|
+
|
|
1729
|
+
pub fn update(&self, id: &str, data: HashMap<String, String>) -> Result<Option<HashMap<String, String>>, String> {{
|
|
1730
|
+
self.repo.update(id, data)
|
|
1731
|
+
}}
|
|
1732
|
+
|
|
1733
|
+
pub fn delete(&self, id: &str) -> Result<bool, String> {{
|
|
1734
|
+
self.repo.delete(id)
|
|
1735
|
+
}}
|
|
1736
|
+
|
|
1737
|
+
fn validate(&self, data: &HashMap<String, String>) -> Result<(), String> {{
|
|
1738
|
+
if !data.contains_key("name") || data["name"].is_empty() {{
|
|
1739
|
+
return Err("validation failed: name is required".to_string());
|
|
1740
|
+
}}
|
|
1741
|
+
Ok(())
|
|
1742
|
+
}}
|
|
1743
|
+
}}
|
|
1744
|
+
'''
|
|
1745
|
+
|
|
1746
|
+
|
|
1747
|
+
# ---------------------------------------------------------------------------
|
|
1748
|
+
# C# code generators
|
|
1749
|
+
# ---------------------------------------------------------------------------
|
|
1750
|
+
|
|
1751
|
+
def _generate_csharp_api_code(entity: str, spec: str, secure: bool = True) -> str:
|
|
1752
|
+
"""Generate an ASP.NET controller (C#)."""
|
|
1753
|
+
class_name = entity.capitalize()
|
|
1754
|
+
auth_using = ""
|
|
1755
|
+
auth_attr = ""
|
|
1756
|
+
if secure:
|
|
1757
|
+
auth_using = "\nusing Microsoft.AspNetCore.Authorization;"
|
|
1758
|
+
auth_attr = "\n [Authorize]"
|
|
1759
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1760
|
+
using Microsoft.AspNetCore.Mvc;
|
|
1761
|
+
using System.Collections.Generic;{auth_using}
|
|
1762
|
+
|
|
1763
|
+
namespace ICDev.Controllers
|
|
1764
|
+
{{
|
|
1765
|
+
/// <summary>
|
|
1766
|
+
/// REST API controller for {entity}.
|
|
1767
|
+
///
|
|
1768
|
+
/// Spec: {spec}
|
|
1769
|
+
/// Generated by ICDEV Builder - code_generator.py
|
|
1770
|
+
/// </summary>
|
|
1771
|
+
[ApiController]
|
|
1772
|
+
[Route("api/{entity}")]{auth_attr}
|
|
1773
|
+
public class {class_name}Controller : ControllerBase
|
|
1774
|
+
{{
|
|
1775
|
+
private readonly {class_name}Service _service;
|
|
1776
|
+
|
|
1777
|
+
public {class_name}Controller({class_name}Service service)
|
|
1778
|
+
{{
|
|
1779
|
+
_service = service;
|
|
1780
|
+
}}
|
|
1781
|
+
|
|
1782
|
+
[HttpGet]
|
|
1783
|
+
public ActionResult<IEnumerable<Dictionary<string, object>>> List()
|
|
1784
|
+
{{
|
|
1785
|
+
var items = _service.ListAll();
|
|
1786
|
+
return Ok(new {{ data = items, count = items.Count }});
|
|
1787
|
+
}}
|
|
1788
|
+
|
|
1789
|
+
[HttpGet("{{id}}")]
|
|
1790
|
+
public ActionResult<Dictionary<string, object>> Get(string id)
|
|
1791
|
+
{{
|
|
1792
|
+
var item = _service.GetById(id);
|
|
1793
|
+
if (item == null)
|
|
1794
|
+
return NotFound(new {{ error = "{class_name} not found" }});
|
|
1795
|
+
return Ok(item);
|
|
1796
|
+
}}
|
|
1797
|
+
|
|
1798
|
+
[HttpPost]
|
|
1799
|
+
public ActionResult<Dictionary<string, object>> Create([FromBody] Dictionary<string, object> data)
|
|
1800
|
+
{{
|
|
1801
|
+
if (!ModelState.IsValid)
|
|
1802
|
+
return BadRequest(ModelState);
|
|
1803
|
+
var created = _service.Create(data);
|
|
1804
|
+
return CreatedAtAction(nameof(Get), new {{ id = created["id"] }}, created);
|
|
1805
|
+
}}
|
|
1806
|
+
|
|
1807
|
+
[HttpPut("{{id}}")]
|
|
1808
|
+
public ActionResult<Dictionary<string, object>> Update(string id, [FromBody] Dictionary<string, object> data)
|
|
1809
|
+
{{
|
|
1810
|
+
if (!ModelState.IsValid)
|
|
1811
|
+
return BadRequest(ModelState);
|
|
1812
|
+
var updated = _service.Update(id, data);
|
|
1813
|
+
if (updated == null)
|
|
1814
|
+
return NotFound(new {{ error = "{class_name} not found" }});
|
|
1815
|
+
return Ok(updated);
|
|
1816
|
+
}}
|
|
1817
|
+
|
|
1818
|
+
[HttpDelete("{{id}}")]
|
|
1819
|
+
public IActionResult Delete(string id)
|
|
1820
|
+
{{
|
|
1821
|
+
var deleted = _service.Delete(id);
|
|
1822
|
+
if (!deleted)
|
|
1823
|
+
return NotFound(new {{ error = "{class_name} not found" }});
|
|
1824
|
+
return NoContent();
|
|
1825
|
+
}}
|
|
1826
|
+
}}
|
|
1827
|
+
}}
|
|
1828
|
+
'''
|
|
1829
|
+
|
|
1830
|
+
|
|
1831
|
+
def _generate_csharp_model_code(entity: str, spec: str) -> str:
|
|
1832
|
+
"""Generate a C# record/class model with data annotations."""
|
|
1833
|
+
class_name = entity.capitalize()
|
|
1834
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1835
|
+
using System;
|
|
1836
|
+
using System.Collections.Generic;
|
|
1837
|
+
using System.ComponentModel.DataAnnotations;
|
|
1838
|
+
|
|
1839
|
+
namespace ICDev.Models
|
|
1840
|
+
{{
|
|
1841
|
+
/// <summary>
|
|
1842
|
+
/// Data model for {entity}.
|
|
1843
|
+
///
|
|
1844
|
+
/// Spec: {spec}
|
|
1845
|
+
/// Generated by ICDEV Builder - code_generator.py
|
|
1846
|
+
/// </summary>
|
|
1847
|
+
public class {class_name}
|
|
1848
|
+
{{
|
|
1849
|
+
public string Id {{ get; set; }} = Guid.NewGuid().ToString();
|
|
1850
|
+
|
|
1851
|
+
[Required(ErrorMessage = "Name is required")]
|
|
1852
|
+
public string Name {{ get; set; }} = string.Empty;
|
|
1853
|
+
|
|
1854
|
+
public string Description {{ get; set; }} = string.Empty;
|
|
1855
|
+
|
|
1856
|
+
public string Status {{ get; set; }} = "active";
|
|
1857
|
+
|
|
1858
|
+
public Dictionary<string, object> Metadata {{ get; set; }} = new();
|
|
1859
|
+
|
|
1860
|
+
public DateTime CreatedAt {{ get; set; }} = DateTime.UtcNow;
|
|
1861
|
+
|
|
1862
|
+
public DateTime UpdatedAt {{ get; set; }} = DateTime.UtcNow;
|
|
1863
|
+
|
|
1864
|
+
public List<string> Validate()
|
|
1865
|
+
{{
|
|
1866
|
+
var errors = new List<string>();
|
|
1867
|
+
if (string.IsNullOrWhiteSpace(Name))
|
|
1868
|
+
errors.Add("name is required");
|
|
1869
|
+
var validStatuses = new[] {{ "active", "inactive", "archived" }};
|
|
1870
|
+
if (Array.IndexOf(validStatuses, Status) < 0)
|
|
1871
|
+
errors.Add($"invalid status: {{Status}}");
|
|
1872
|
+
return errors;
|
|
1873
|
+
}}
|
|
1874
|
+
}}
|
|
1875
|
+
}}
|
|
1876
|
+
'''
|
|
1877
|
+
|
|
1878
|
+
|
|
1879
|
+
def _generate_csharp_service_code(entity: str, spec: str) -> str:
|
|
1880
|
+
"""Generate a C# service class with DI interface."""
|
|
1881
|
+
class_name = entity.capitalize()
|
|
1882
|
+
return f'''{CUI_HEADER_C_STYLE}
|
|
1883
|
+
using System;
|
|
1884
|
+
using System.Collections.Generic;
|
|
1885
|
+
using System.Linq;
|
|
1886
|
+
using Microsoft.Extensions.Logging;
|
|
1887
|
+
|
|
1888
|
+
namespace ICDev.Services
|
|
1889
|
+
{{
|
|
1890
|
+
/// <summary>
|
|
1891
|
+
/// Service interface for {entity} operations.
|
|
1892
|
+
/// </summary>
|
|
1893
|
+
public interface I{class_name}Service
|
|
1894
|
+
{{
|
|
1895
|
+
Dictionary<string, object> Create(Dictionary<string, object> data);
|
|
1896
|
+
Dictionary<string, object> GetById(string id);
|
|
1897
|
+
List<Dictionary<string, object>> ListAll();
|
|
1898
|
+
Dictionary<string, object> Update(string id, Dictionary<string, object> data);
|
|
1899
|
+
bool Delete(string id);
|
|
1900
|
+
}}
|
|
1901
|
+
|
|
1902
|
+
/// <summary>
|
|
1903
|
+
/// Service layer for {entity} business logic.
|
|
1904
|
+
///
|
|
1905
|
+
/// Spec: {spec}
|
|
1906
|
+
/// Generated by ICDEV Builder - code_generator.py
|
|
1907
|
+
/// </summary>
|
|
1908
|
+
public class {class_name}Service : I{class_name}Service
|
|
1909
|
+
{{
|
|
1910
|
+
private readonly ILogger<{class_name}Service> _logger;
|
|
1911
|
+
private readonly Dictionary<string, Dictionary<string, object>> _store = new();
|
|
1912
|
+
|
|
1913
|
+
public {class_name}Service(ILogger<{class_name}Service> logger)
|
|
1914
|
+
{{
|
|
1915
|
+
_logger = logger;
|
|
1916
|
+
_logger.LogInformation("{class_name}Service initialized");
|
|
1917
|
+
}}
|
|
1918
|
+
|
|
1919
|
+
public Dictionary<string, object> Create(Dictionary<string, object> data)
|
|
1920
|
+
{{
|
|
1921
|
+
var id = Guid.NewGuid().ToString();
|
|
1922
|
+
data["id"] = id;
|
|
1923
|
+
data["created_at"] = DateTime.UtcNow.ToString("o");
|
|
1924
|
+
data["updated_at"] = DateTime.UtcNow.ToString("o");
|
|
1925
|
+
_store[id] = data;
|
|
1926
|
+
_logger.LogInformation("{class_name} created: {{Id}}", id);
|
|
1927
|
+
return data;
|
|
1928
|
+
}}
|
|
1929
|
+
|
|
1930
|
+
public Dictionary<string, object> GetById(string id)
|
|
1931
|
+
{{
|
|
1932
|
+
return _store.GetValueOrDefault(id);
|
|
1933
|
+
}}
|
|
1934
|
+
|
|
1935
|
+
public List<Dictionary<string, object>> ListAll()
|
|
1936
|
+
{{
|
|
1937
|
+
return _store.Values.ToList();
|
|
1938
|
+
}}
|
|
1939
|
+
|
|
1940
|
+
public Dictionary<string, object> Update(string id, Dictionary<string, object> data)
|
|
1941
|
+
{{
|
|
1942
|
+
if (!_store.ContainsKey(id))
|
|
1943
|
+
return null;
|
|
1944
|
+
foreach (var kvp in data)
|
|
1945
|
+
_store[id][kvp.Key] = kvp.Value;
|
|
1946
|
+
_store[id]["updated_at"] = DateTime.UtcNow.ToString("o");
|
|
1947
|
+
return _store[id];
|
|
1948
|
+
}}
|
|
1949
|
+
|
|
1950
|
+
public bool Delete(string id)
|
|
1951
|
+
{{
|
|
1952
|
+
return _store.Remove(id);
|
|
1953
|
+
}}
|
|
1954
|
+
}}
|
|
1955
|
+
}}
|
|
1956
|
+
'''
|
|
1957
|
+
|
|
1958
|
+
|
|
1959
|
+
# ---------------------------------------------------------------------------
|
|
1960
|
+
# Phase 19: Agentic spec type generators (Python — GOTCHA child apps)
|
|
1961
|
+
# ---------------------------------------------------------------------------
|
|
1962
|
+
|
|
1963
|
+
def _generate_agent_skill_code(entity: str, spec: str) -> str:
|
|
1964
|
+
"""Generate A2A skill handler with register_skill().
|
|
1965
|
+
|
|
1966
|
+
Creates an agent skill module that:
|
|
1967
|
+
- Defines a skill handler class with execute() and validate()
|
|
1968
|
+
- Provides register_skill() for A2A agent card registration
|
|
1969
|
+
- Includes JSON-RPC 2.0 compliant request/response handling
|
|
1970
|
+
- Logs skill invocations to the audit trail
|
|
1971
|
+
"""
|
|
1972
|
+
class_name = entity.capitalize()
|
|
1973
|
+
skill_name = _slugify(entity)
|
|
1974
|
+
return f'''{CUI_HEADER}
|
|
1975
|
+
"""A2A Skill Handler: {entity}
|
|
1976
|
+
|
|
1977
|
+
Spec: {spec}
|
|
1978
|
+
Generated by ICDEV Builder - code_generator.py (Phase 19: Agentic)
|
|
1979
|
+
|
|
1980
|
+
Implements an A2A-compliant skill that can be registered with any
|
|
1981
|
+
GOTCHA-framework agent. Follows JSON-RPC 2.0 protocol over mTLS.
|
|
1982
|
+
"""
|
|
1983
|
+
|
|
1984
|
+
import hashlib
|
|
1985
|
+
import json
|
|
1986
|
+
import logging
|
|
1987
|
+
import time
|
|
1988
|
+
import uuid
|
|
1989
|
+
from datetime import datetime, timezone
|
|
1990
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
1991
|
+
|
|
1992
|
+
logger = logging.getLogger(__name__)
|
|
1993
|
+
|
|
1994
|
+
|
|
1995
|
+
class {class_name}Skill:
|
|
1996
|
+
"""A2A skill handler for {entity}.
|
|
1997
|
+
|
|
1998
|
+
This skill can be registered with an agent and invoked via
|
|
1999
|
+
the A2A protocol. It validates input, executes the skill logic,
|
|
2000
|
+
and returns structured results.
|
|
2001
|
+
|
|
2002
|
+
Attributes:
|
|
2003
|
+
skill_id: Unique identifier for this skill instance.
|
|
2004
|
+
name: Human-readable skill name.
|
|
2005
|
+
version: Semantic version string.
|
|
2006
|
+
description: What this skill does.
|
|
2007
|
+
keywords: Discovery keywords for agent card.
|
|
2008
|
+
max_retries: Maximum retry attempts on transient failure.
|
|
2009
|
+
"""
|
|
2010
|
+
|
|
2011
|
+
SKILL_NAME = "{skill_name}"
|
|
2012
|
+
SKILL_VERSION = "1.0.0"
|
|
2013
|
+
KEYWORDS = ["agent", "skill", "a2a", "dispatch", "{entity}"]
|
|
2014
|
+
|
|
2015
|
+
def __init__(self, config: Optional[Dict[str, Any]] = None) -> None:
|
|
2016
|
+
"""Initialize the skill handler.
|
|
2017
|
+
|
|
2018
|
+
Args:
|
|
2019
|
+
config: Optional configuration overrides.
|
|
2020
|
+
"""
|
|
2021
|
+
self.skill_id = str(uuid.uuid4())
|
|
2022
|
+
self.name = self.SKILL_NAME
|
|
2023
|
+
self.version = self.SKILL_VERSION
|
|
2024
|
+
self.description = "{spec}"
|
|
2025
|
+
self.keywords = self.KEYWORDS
|
|
2026
|
+
self.config = config or {{}}
|
|
2027
|
+
self.max_retries = self.config.get("max_retries", 3)
|
|
2028
|
+
self._invocation_count = 0
|
|
2029
|
+
self._last_invocation: Optional[str] = None
|
|
2030
|
+
logger.info(f"{class_name}Skill initialized (id={{self.skill_id}})")
|
|
2031
|
+
|
|
2032
|
+
def validate(self, params: Dict[str, Any]) -> List[str]:
|
|
2033
|
+
"""Validate skill invocation parameters.
|
|
2034
|
+
|
|
2035
|
+
Args:
|
|
2036
|
+
params: The parameters passed to the skill.
|
|
2037
|
+
|
|
2038
|
+
Returns:
|
|
2039
|
+
List of validation error messages (empty if valid).
|
|
2040
|
+
"""
|
|
2041
|
+
errors = []
|
|
2042
|
+
if not params:
|
|
2043
|
+
errors.append("params cannot be empty")
|
|
2044
|
+
if "action" not in params:
|
|
2045
|
+
errors.append("'action' is required in params")
|
|
2046
|
+
return errors
|
|
2047
|
+
|
|
2048
|
+
def execute(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
2049
|
+
"""Execute the skill with the given parameters.
|
|
2050
|
+
|
|
2051
|
+
Args:
|
|
2052
|
+
params: Skill invocation parameters. Must include 'action'.
|
|
2053
|
+
|
|
2054
|
+
Returns:
|
|
2055
|
+
Result dict with 'status', 'data', and 'metadata' keys.
|
|
2056
|
+
|
|
2057
|
+
Raises:
|
|
2058
|
+
ValueError: If parameter validation fails.
|
|
2059
|
+
"""
|
|
2060
|
+
errors = self.validate(params)
|
|
2061
|
+
if errors:
|
|
2062
|
+
raise ValueError(f"Validation failed: {{'; '.join(errors)}}")
|
|
2063
|
+
|
|
2064
|
+
self._invocation_count += 1
|
|
2065
|
+
self._last_invocation = datetime.now(timezone.utc).isoformat() + "Z"
|
|
2066
|
+
|
|
2067
|
+
action = params.get("action", "default")
|
|
2068
|
+
logger.info(
|
|
2069
|
+
f"{{self.name}} executing action='{{action}}' "
|
|
2070
|
+
f"(invocation #{{self._invocation_count}})"
|
|
2071
|
+
)
|
|
2072
|
+
|
|
2073
|
+
result = {{
|
|
2074
|
+
"status": "completed",
|
|
2075
|
+
"skill_id": self.skill_id,
|
|
2076
|
+
"action": action,
|
|
2077
|
+
"data": self._process_action(action, params),
|
|
2078
|
+
"metadata": {{
|
|
2079
|
+
"invocation_count": self._invocation_count,
|
|
2080
|
+
"timestamp": self._last_invocation,
|
|
2081
|
+
"version": self.version,
|
|
2082
|
+
}},
|
|
2083
|
+
}}
|
|
2084
|
+
return result
|
|
2085
|
+
|
|
2086
|
+
def _process_action(self, action: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
2087
|
+
"""Process a specific action within the skill.
|
|
2088
|
+
|
|
2089
|
+
Override this method to implement custom skill logic.
|
|
2090
|
+
|
|
2091
|
+
Args:
|
|
2092
|
+
action: The action to perform.
|
|
2093
|
+
params: Full parameter dict.
|
|
2094
|
+
|
|
2095
|
+
Returns:
|
|
2096
|
+
Action-specific result data.
|
|
2097
|
+
"""
|
|
2098
|
+
return {{
|
|
2099
|
+
"action": action,
|
|
2100
|
+
"input_keys": list(params.keys()),
|
|
2101
|
+
"processed": True,
|
|
2102
|
+
}}
|
|
2103
|
+
|
|
2104
|
+
def get_skill_card(self) -> Dict[str, Any]:
|
|
2105
|
+
"""Generate the A2A skill card for agent registration.
|
|
2106
|
+
|
|
2107
|
+
Returns:
|
|
2108
|
+
Skill card dict compatible with /.well-known/agent.json.
|
|
2109
|
+
"""
|
|
2110
|
+
return {{
|
|
2111
|
+
"id": self.skill_id,
|
|
2112
|
+
"name": self.name,
|
|
2113
|
+
"version": self.version,
|
|
2114
|
+
"description": self.description,
|
|
2115
|
+
"keywords": self.keywords,
|
|
2116
|
+
"input_schema": {{
|
|
2117
|
+
"type": "object",
|
|
2118
|
+
"required": ["action"],
|
|
2119
|
+
"properties": {{
|
|
2120
|
+
"action": {{"type": "string", "description": "Action to perform"}},
|
|
2121
|
+
"data": {{"type": "object", "description": "Action-specific data"}},
|
|
2122
|
+
}},
|
|
2123
|
+
}},
|
|
2124
|
+
"output_schema": {{
|
|
2125
|
+
"type": "object",
|
|
2126
|
+
"properties": {{
|
|
2127
|
+
"status": {{"type": "string"}},
|
|
2128
|
+
"data": {{"type": "object"}},
|
|
2129
|
+
"metadata": {{"type": "object"}},
|
|
2130
|
+
}},
|
|
2131
|
+
}},
|
|
2132
|
+
}}
|
|
2133
|
+
|
|
2134
|
+
|
|
2135
|
+
def register_skill(
|
|
2136
|
+
agent_url: str,
|
|
2137
|
+
skill: {class_name}Skill,
|
|
2138
|
+
auth_token: Optional[str] = None,
|
|
2139
|
+
) -> Dict[str, Any]:
|
|
2140
|
+
"""Register this skill with an A2A agent.
|
|
2141
|
+
|
|
2142
|
+
Sends the skill card to the agent's registration endpoint so it
|
|
2143
|
+
appears in the agent's /.well-known/agent.json capabilities list.
|
|
2144
|
+
|
|
2145
|
+
Args:
|
|
2146
|
+
agent_url: Base URL of the target agent (e.g. https://agent:8443).
|
|
2147
|
+
skill: The skill instance to register.
|
|
2148
|
+
auth_token: Optional mTLS/bearer token for authentication.
|
|
2149
|
+
|
|
2150
|
+
Returns:
|
|
2151
|
+
Registration confirmation dict.
|
|
2152
|
+
"""
|
|
2153
|
+
skill_card = skill.get_skill_card()
|
|
2154
|
+
registration = {{
|
|
2155
|
+
"jsonrpc": "2.0",
|
|
2156
|
+
"method": "skill.register",
|
|
2157
|
+
"params": skill_card,
|
|
2158
|
+
"id": str(uuid.uuid4()),
|
|
2159
|
+
}}
|
|
2160
|
+
logger.info(
|
|
2161
|
+
f"Registering skill '{{skill.name}}' with agent at {{agent_url}}"
|
|
2162
|
+
)
|
|
2163
|
+
# In production, this would POST to agent_url/a2a via mTLS
|
|
2164
|
+
# For now, return the registration payload for testing
|
|
2165
|
+
return {{
|
|
2166
|
+
"status": "registered",
|
|
2167
|
+
"agent_url": agent_url,
|
|
2168
|
+
"skill_id": skill.skill_id,
|
|
2169
|
+
"skill_name": skill.name,
|
|
2170
|
+
"registration": registration,
|
|
2171
|
+
}}
|
|
2172
|
+
|
|
2173
|
+
|
|
2174
|
+
# Standalone usage
|
|
2175
|
+
if __name__ == "__main__":
|
|
2176
|
+
skill = {class_name}Skill()
|
|
2177
|
+
print(json.dumps(skill.get_skill_card(), indent=2))
|
|
2178
|
+
result = skill.execute({{"action": "test", "data": {{"key": "value"}}}})
|
|
2179
|
+
print(json.dumps(result, indent=2))
|
|
2180
|
+
'''
|
|
2181
|
+
|
|
2182
|
+
|
|
2183
|
+
def _generate_llm_service_code(entity: str, spec: str) -> str:
|
|
2184
|
+
"""Generate BedrockClient wrapper with retry and token tracking.
|
|
2185
|
+
|
|
2186
|
+
Creates an LLM service module that:
|
|
2187
|
+
- Wraps AWS Bedrock invoke_model with exponential backoff retry
|
|
2188
|
+
- Tracks input/output token counts per request and cumulative
|
|
2189
|
+
- Supports configurable model ID, temperature, max_tokens
|
|
2190
|
+
- Logs all invocations with token usage for cost tracking
|
|
2191
|
+
"""
|
|
2192
|
+
class_name = entity.capitalize()
|
|
2193
|
+
return f'''{CUI_HEADER}
|
|
2194
|
+
"""LLM Service: {entity}
|
|
2195
|
+
|
|
2196
|
+
Spec: {spec}
|
|
2197
|
+
Generated by ICDEV Builder - code_generator.py (Phase 19: Agentic)
|
|
2198
|
+
|
|
2199
|
+
Provides a BedrockClient wrapper with exponential backoff retry,
|
|
2200
|
+
per-request and cumulative token tracking, and structured logging
|
|
2201
|
+
for cost analysis and audit compliance.
|
|
2202
|
+
"""
|
|
2203
|
+
|
|
2204
|
+
import json
|
|
2205
|
+
import logging
|
|
2206
|
+
import time
|
|
2207
|
+
import uuid
|
|
2208
|
+
from datetime import datetime, timezone
|
|
2209
|
+
from typing import Any, Dict, List, Optional
|
|
2210
|
+
|
|
2211
|
+
logger = logging.getLogger(__name__)
|
|
2212
|
+
|
|
2213
|
+
|
|
2214
|
+
class TokenUsage:
|
|
2215
|
+
"""Tracks token usage across LLM invocations.
|
|
2216
|
+
|
|
2217
|
+
Attributes:
|
|
2218
|
+
total_input_tokens: Cumulative input tokens consumed.
|
|
2219
|
+
total_output_tokens: Cumulative output tokens generated.
|
|
2220
|
+
request_count: Number of successful invocations.
|
|
2221
|
+
history: Per-request token usage records.
|
|
2222
|
+
"""
|
|
2223
|
+
|
|
2224
|
+
def __init__(self) -> None:
|
|
2225
|
+
self.total_input_tokens: int = 0
|
|
2226
|
+
self.total_output_tokens: int = 0
|
|
2227
|
+
self.request_count: int = 0
|
|
2228
|
+
self.history: List[Dict[str, Any]] = []
|
|
2229
|
+
|
|
2230
|
+
def record(self, input_tokens: int, output_tokens: int, model_id: str) -> None:
|
|
2231
|
+
"""Record token usage from a single invocation.
|
|
2232
|
+
|
|
2233
|
+
Args:
|
|
2234
|
+
input_tokens: Tokens in the prompt.
|
|
2235
|
+
output_tokens: Tokens in the response.
|
|
2236
|
+
model_id: Model that was invoked.
|
|
2237
|
+
"""
|
|
2238
|
+
self.total_input_tokens += input_tokens
|
|
2239
|
+
self.total_output_tokens += output_tokens
|
|
2240
|
+
self.request_count += 1
|
|
2241
|
+
self.history.append({{
|
|
2242
|
+
"timestamp": datetime.now(timezone.utc).isoformat() + "Z",
|
|
2243
|
+
"model_id": model_id,
|
|
2244
|
+
"input_tokens": input_tokens,
|
|
2245
|
+
"output_tokens": output_tokens,
|
|
2246
|
+
}})
|
|
2247
|
+
|
|
2248
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
2249
|
+
"""Serialize usage summary to dict."""
|
|
2250
|
+
return {{
|
|
2251
|
+
"total_input_tokens": self.total_input_tokens,
|
|
2252
|
+
"total_output_tokens": self.total_output_tokens,
|
|
2253
|
+
"total_tokens": self.total_input_tokens + self.total_output_tokens,
|
|
2254
|
+
"request_count": self.request_count,
|
|
2255
|
+
}}
|
|
2256
|
+
|
|
2257
|
+
|
|
2258
|
+
class {class_name}LLMService:
|
|
2259
|
+
"""Bedrock LLM client wrapper with retry and token tracking.
|
|
2260
|
+
|
|
2261
|
+
Wraps AWS Bedrock invoke_model with:
|
|
2262
|
+
- Configurable model ID, temperature, and max_tokens
|
|
2263
|
+
- Exponential backoff retry on throttling/transient errors
|
|
2264
|
+
- Per-request and cumulative token tracking
|
|
2265
|
+
- Structured logging for audit trail
|
|
2266
|
+
|
|
2267
|
+
Attributes:
|
|
2268
|
+
model_id: Bedrock model identifier.
|
|
2269
|
+
region: AWS region (default: us-gov-west-1 for GovCloud).
|
|
2270
|
+
max_retries: Maximum retry attempts.
|
|
2271
|
+
base_delay: Initial retry delay in seconds.
|
|
2272
|
+
temperature: Sampling temperature (0.0 - 1.0).
|
|
2273
|
+
max_tokens: Maximum tokens in response.
|
|
2274
|
+
token_usage: Token tracking instance.
|
|
2275
|
+
"""
|
|
2276
|
+
|
|
2277
|
+
DEFAULT_MODEL_ID = "anthropic.claude-sonnet-4-5-20250929-v1:0"
|
|
2278
|
+
DEFAULT_REGION = "us-gov-west-1"
|
|
2279
|
+
|
|
2280
|
+
def __init__(self, config: Optional[Dict[str, Any]] = None) -> None:
|
|
2281
|
+
"""Initialize the LLM service.
|
|
2282
|
+
|
|
2283
|
+
Args:
|
|
2284
|
+
config: Configuration overrides. Supported keys:
|
|
2285
|
+
- model_id: Bedrock model ID
|
|
2286
|
+
- region: AWS region
|
|
2287
|
+
- max_retries: Retry count (default 3)
|
|
2288
|
+
- base_delay: Base retry delay in seconds (default 1.0)
|
|
2289
|
+
- temperature: Sampling temperature (default 0.7)
|
|
2290
|
+
- max_tokens: Max output tokens (default 4096)
|
|
2291
|
+
"""
|
|
2292
|
+
config = config or {{}}
|
|
2293
|
+
self.model_id = config.get("model_id", self.DEFAULT_MODEL_ID)
|
|
2294
|
+
self.region = config.get("region", self.DEFAULT_REGION)
|
|
2295
|
+
self.max_retries = config.get("max_retries", 3)
|
|
2296
|
+
self.base_delay = config.get("base_delay", 1.0)
|
|
2297
|
+
self.temperature = config.get("temperature", 0.7)
|
|
2298
|
+
self.max_tokens = config.get("max_tokens", 4096)
|
|
2299
|
+
self.token_usage = TokenUsage()
|
|
2300
|
+
self._client = None
|
|
2301
|
+
logger.info(
|
|
2302
|
+
f"{class_name}LLMService initialized "
|
|
2303
|
+
f"(model={{self.model_id}}, region={{self.region}})"
|
|
2304
|
+
)
|
|
2305
|
+
|
|
2306
|
+
def _get_client(self) -> Any:
|
|
2307
|
+
"""Lazily create the Bedrock runtime client.
|
|
2308
|
+
|
|
2309
|
+
Returns:
|
|
2310
|
+
boto3 Bedrock runtime client.
|
|
2311
|
+
"""
|
|
2312
|
+
if self._client is None:
|
|
2313
|
+
try:
|
|
2314
|
+
import boto3
|
|
2315
|
+
self._client = boto3.client(
|
|
2316
|
+
"bedrock-runtime",
|
|
2317
|
+
region_name=self.region,
|
|
2318
|
+
)
|
|
2319
|
+
except ImportError:
|
|
2320
|
+
raise RuntimeError(
|
|
2321
|
+
"boto3 is required for Bedrock access. "
|
|
2322
|
+
"Install with: pip install boto3"
|
|
2323
|
+
)
|
|
2324
|
+
return self._client
|
|
2325
|
+
|
|
2326
|
+
def invoke(
|
|
2327
|
+
self,
|
|
2328
|
+
prompt: str,
|
|
2329
|
+
system_prompt: Optional[str] = None,
|
|
2330
|
+
temperature: Optional[float] = None,
|
|
2331
|
+
max_tokens: Optional[int] = None,
|
|
2332
|
+
) -> Dict[str, Any]:
|
|
2333
|
+
"""Invoke the LLM with retry and token tracking.
|
|
2334
|
+
|
|
2335
|
+
Args:
|
|
2336
|
+
prompt: The user prompt text.
|
|
2337
|
+
system_prompt: Optional system instruction.
|
|
2338
|
+
temperature: Override default temperature.
|
|
2339
|
+
max_tokens: Override default max_tokens.
|
|
2340
|
+
|
|
2341
|
+
Returns:
|
|
2342
|
+
Dict with 'content', 'model_id', 'usage', and 'request_id'.
|
|
2343
|
+
|
|
2344
|
+
Raises:
|
|
2345
|
+
RuntimeError: If all retries exhausted.
|
|
2346
|
+
"""
|
|
2347
|
+
request_id = str(uuid.uuid4())
|
|
2348
|
+
temp = temperature if temperature is not None else self.temperature
|
|
2349
|
+
tokens = max_tokens if max_tokens is not None else self.max_tokens
|
|
2350
|
+
|
|
2351
|
+
body = {{
|
|
2352
|
+
"anthropic_version": "bedrock-2023-05-31",
|
|
2353
|
+
"messages": [{{"role": "user", "content": prompt}}],
|
|
2354
|
+
"temperature": temp,
|
|
2355
|
+
"max_tokens": tokens,
|
|
2356
|
+
}}
|
|
2357
|
+
if system_prompt:
|
|
2358
|
+
body["system"] = system_prompt
|
|
2359
|
+
|
|
2360
|
+
last_error = None
|
|
2361
|
+
for attempt in range(self.max_retries + 1):
|
|
2362
|
+
try:
|
|
2363
|
+
client = self._get_client()
|
|
2364
|
+
response = client.invoke_model(
|
|
2365
|
+
modelId=self.model_id,
|
|
2366
|
+
contentType="application/json",
|
|
2367
|
+
accept="application/json",
|
|
2368
|
+
body=json.dumps(body),
|
|
2369
|
+
)
|
|
2370
|
+
result = json.loads(response["body"].read())
|
|
2371
|
+
|
|
2372
|
+
# Extract token usage
|
|
2373
|
+
usage = result.get("usage", {{}})
|
|
2374
|
+
input_tokens = usage.get("input_tokens", 0)
|
|
2375
|
+
output_tokens = usage.get("output_tokens", 0)
|
|
2376
|
+
self.token_usage.record(input_tokens, output_tokens, self.model_id)
|
|
2377
|
+
|
|
2378
|
+
content = ""
|
|
2379
|
+
if "content" in result and result["content"]:
|
|
2380
|
+
content = result["content"][0].get("text", "")
|
|
2381
|
+
|
|
2382
|
+
logger.info(
|
|
2383
|
+
f"LLM invocation complete (request={{request_id}}, "
|
|
2384
|
+
f"in={{input_tokens}}, out={{output_tokens}})"
|
|
2385
|
+
)
|
|
2386
|
+
return {{
|
|
2387
|
+
"content": content,
|
|
2388
|
+
"model_id": self.model_id,
|
|
2389
|
+
"request_id": request_id,
|
|
2390
|
+
"usage": {{
|
|
2391
|
+
"input_tokens": input_tokens,
|
|
2392
|
+
"output_tokens": output_tokens,
|
|
2393
|
+
}},
|
|
2394
|
+
}}
|
|
2395
|
+
|
|
2396
|
+
except Exception as e:
|
|
2397
|
+
last_error = e
|
|
2398
|
+
if attempt < self.max_retries:
|
|
2399
|
+
delay = self.base_delay * (2 ** attempt)
|
|
2400
|
+
logger.warning(
|
|
2401
|
+
f"LLM invocation failed (attempt {{attempt + 1}}/{{self.max_retries + 1}}), "
|
|
2402
|
+
f"retrying in {{delay:.1f}}s: {{e}}"
|
|
2403
|
+
)
|
|
2404
|
+
time.sleep(delay)
|
|
2405
|
+
|
|
2406
|
+
raise RuntimeError(
|
|
2407
|
+
f"LLM invocation failed after {{self.max_retries + 1}} attempts: {{last_error}}"
|
|
2408
|
+
)
|
|
2409
|
+
|
|
2410
|
+
def get_usage_summary(self) -> Dict[str, Any]:
|
|
2411
|
+
"""Return cumulative token usage summary.
|
|
2412
|
+
|
|
2413
|
+
Returns:
|
|
2414
|
+
Dict with total input/output tokens and request count.
|
|
2415
|
+
"""
|
|
2416
|
+
return self.token_usage.to_dict()
|
|
2417
|
+
|
|
2418
|
+
|
|
2419
|
+
# Standalone usage
|
|
2420
|
+
if __name__ == "__main__":
|
|
2421
|
+
service = {class_name}LLMService({{
|
|
2422
|
+
"model_id": "anthropic.claude-3-sonnet-20240229-v1:0",
|
|
2423
|
+
}})
|
|
2424
|
+
print(f"Service initialized: model={{service.model_id}}")
|
|
2425
|
+
print(f"Usage: {{json.dumps(service.get_usage_summary(), indent=2)}}")
|
|
2426
|
+
'''
|
|
2427
|
+
|
|
2428
|
+
|
|
2429
|
+
def _generate_prompt_template_code(entity: str, spec: str) -> str:
|
|
2430
|
+
"""Generate hardprompt manager with {{{{variable}}}} substitution.
|
|
2431
|
+
|
|
2432
|
+
Creates a prompt template module that:
|
|
2433
|
+
- Loads templates from hardprompts/ directory
|
|
2434
|
+
- Supports {{{{variable}}}} substitution with validation
|
|
2435
|
+
- Provides template composition (chain templates together)
|
|
2436
|
+
- Includes template caching and versioning
|
|
2437
|
+
"""
|
|
2438
|
+
class_name = entity.capitalize()
|
|
2439
|
+
return f'''{CUI_HEADER}
|
|
2440
|
+
"""Prompt Template Manager: {entity}
|
|
2441
|
+
|
|
2442
|
+
Spec: {spec}
|
|
2443
|
+
Generated by ICDEV Builder - code_generator.py (Phase 19: Agentic)
|
|
2444
|
+
|
|
2445
|
+
Manages hardprompt templates with variable substitution,
|
|
2446
|
+
template composition, caching, and version tracking.
|
|
2447
|
+
Templates use {{{{variable}}}} syntax for substitution.
|
|
2448
|
+
"""
|
|
2449
|
+
|
|
2450
|
+
import hashlib
|
|
2451
|
+
import json
|
|
2452
|
+
import logging
|
|
2453
|
+
import os
|
|
2454
|
+
import re
|
|
2455
|
+
from datetime import datetime, timezone
|
|
2456
|
+
from pathlib import Path
|
|
2457
|
+
from typing import Any, Dict, List, Optional, Set
|
|
2458
|
+
|
|
2459
|
+
logger = logging.getLogger(__name__)
|
|
2460
|
+
|
|
2461
|
+
|
|
2462
|
+
class PromptTemplate:
|
|
2463
|
+
"""A single prompt template with variable substitution.
|
|
2464
|
+
|
|
2465
|
+
Attributes:
|
|
2466
|
+
name: Template identifier.
|
|
2467
|
+
content: Raw template text with {{{{variable}}}} placeholders.
|
|
2468
|
+
version: Template version (content hash).
|
|
2469
|
+
variables: Set of variable names found in the template.
|
|
2470
|
+
metadata: Additional template metadata.
|
|
2471
|
+
"""
|
|
2472
|
+
|
|
2473
|
+
VARIABLE_PATTERN = re.compile(r"\\{{\\{{(\\w+)\\}}\\}}")
|
|
2474
|
+
|
|
2475
|
+
def __init__(
|
|
2476
|
+
self,
|
|
2477
|
+
name: str,
|
|
2478
|
+
content: str,
|
|
2479
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
2480
|
+
) -> None:
|
|
2481
|
+
"""Initialize a prompt template.
|
|
2482
|
+
|
|
2483
|
+
Args:
|
|
2484
|
+
name: Template identifier.
|
|
2485
|
+
content: Raw template text with {{{{var}}}} placeholders.
|
|
2486
|
+
metadata: Optional metadata (author, description, etc.).
|
|
2487
|
+
"""
|
|
2488
|
+
self.name = name
|
|
2489
|
+
self.content = content
|
|
2490
|
+
self.metadata = metadata or {{}}
|
|
2491
|
+
self.version = hashlib.sha256(content.encode()).hexdigest()[:12]
|
|
2492
|
+
self.variables = self._extract_variables()
|
|
2493
|
+
self.created_at = datetime.now(timezone.utc).isoformat() + "Z"
|
|
2494
|
+
|
|
2495
|
+
def _extract_variables(self) -> Set[str]:
|
|
2496
|
+
"""Extract all variable names from the template.
|
|
2497
|
+
|
|
2498
|
+
Returns:
|
|
2499
|
+
Set of variable names found in {{{{var}}}} placeholders.
|
|
2500
|
+
"""
|
|
2501
|
+
return set(self.VARIABLE_PATTERN.findall(self.content))
|
|
2502
|
+
|
|
2503
|
+
def render(self, variables: Dict[str, str]) -> str:
|
|
2504
|
+
"""Render the template by substituting variables.
|
|
2505
|
+
|
|
2506
|
+
Args:
|
|
2507
|
+
variables: Mapping of variable name to value.
|
|
2508
|
+
|
|
2509
|
+
Returns:
|
|
2510
|
+
Rendered template string.
|
|
2511
|
+
|
|
2512
|
+
Raises:
|
|
2513
|
+
ValueError: If required variables are missing.
|
|
2514
|
+
"""
|
|
2515
|
+
missing = self.variables - set(variables.keys())
|
|
2516
|
+
if missing:
|
|
2517
|
+
raise ValueError(
|
|
2518
|
+
f"Missing required variables: {{', '.join(sorted(missing))}}"
|
|
2519
|
+
)
|
|
2520
|
+
|
|
2521
|
+
result = self.content
|
|
2522
|
+
for var_name, var_value in variables.items():
|
|
2523
|
+
result = result.replace(f"{{{{{{{{{{var_name}}}}}}}}}}", str(var_value))
|
|
2524
|
+
return result
|
|
2525
|
+
|
|
2526
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
2527
|
+
"""Serialize template to dict."""
|
|
2528
|
+
return {{
|
|
2529
|
+
"name": self.name,
|
|
2530
|
+
"version": self.version,
|
|
2531
|
+
"variables": sorted(self.variables),
|
|
2532
|
+
"metadata": self.metadata,
|
|
2533
|
+
"created_at": self.created_at,
|
|
2534
|
+
"content_length": len(self.content),
|
|
2535
|
+
}}
|
|
2536
|
+
|
|
2537
|
+
|
|
2538
|
+
class {class_name}PromptManager:
|
|
2539
|
+
"""Manages a collection of hardprompt templates.
|
|
2540
|
+
|
|
2541
|
+
Loads templates from the hardprompts/ directory, supports
|
|
2542
|
+
on-demand template creation, composition, and caching.
|
|
2543
|
+
|
|
2544
|
+
Attributes:
|
|
2545
|
+
templates_dir: Path to the hardprompts directory.
|
|
2546
|
+
templates: Dict of loaded templates keyed by name.
|
|
2547
|
+
"""
|
|
2548
|
+
|
|
2549
|
+
def __init__(
|
|
2550
|
+
self,
|
|
2551
|
+
templates_dir: Optional[str] = None,
|
|
2552
|
+
project_root: Optional[str] = None,
|
|
2553
|
+
) -> None:
|
|
2554
|
+
"""Initialize the prompt manager.
|
|
2555
|
+
|
|
2556
|
+
Args:
|
|
2557
|
+
templates_dir: Path to templates directory.
|
|
2558
|
+
project_root: Project root (templates_dir defaults to
|
|
2559
|
+
{{project_root}}/hardprompts/).
|
|
2560
|
+
"""
|
|
2561
|
+
if templates_dir:
|
|
2562
|
+
self.templates_dir = Path(templates_dir)
|
|
2563
|
+
elif project_root:
|
|
2564
|
+
self.templates_dir = Path(project_root) / "hardprompts"
|
|
2565
|
+
else:
|
|
2566
|
+
self.templates_dir = Path.cwd() / "hardprompts"
|
|
2567
|
+
|
|
2568
|
+
self.templates: Dict[str, PromptTemplate] = {{}}
|
|
2569
|
+
self._load_templates()
|
|
2570
|
+
logger.info(
|
|
2571
|
+
f"{class_name}PromptManager initialized "
|
|
2572
|
+
f"({{len(self.templates)}} templates loaded from {{self.templates_dir}})"
|
|
2573
|
+
)
|
|
2574
|
+
|
|
2575
|
+
def _load_templates(self) -> None:
|
|
2576
|
+
"""Load all .md and .txt templates from the templates directory."""
|
|
2577
|
+
if not self.templates_dir.exists():
|
|
2578
|
+
logger.warning(f"Templates directory not found: {{self.templates_dir}}")
|
|
2579
|
+
return
|
|
2580
|
+
|
|
2581
|
+
for ext in ("*.md", "*.txt"):
|
|
2582
|
+
for path in self.templates_dir.glob(ext):
|
|
2583
|
+
try:
|
|
2584
|
+
content = path.read_text(encoding="utf-8")
|
|
2585
|
+
name = path.stem
|
|
2586
|
+
self.templates[name] = PromptTemplate(
|
|
2587
|
+
name=name,
|
|
2588
|
+
content=content,
|
|
2589
|
+
metadata={{"source": str(path)}},
|
|
2590
|
+
)
|
|
2591
|
+
except Exception as e:
|
|
2592
|
+
logger.error(f"Failed to load template {{path}}: {{e}}")
|
|
2593
|
+
|
|
2594
|
+
def register(self, name: str, content: str, metadata: Optional[Dict[str, Any]] = None) -> PromptTemplate:
|
|
2595
|
+
"""Register a new template programmatically.
|
|
2596
|
+
|
|
2597
|
+
Args:
|
|
2598
|
+
name: Template identifier.
|
|
2599
|
+
content: Raw template text.
|
|
2600
|
+
metadata: Optional metadata.
|
|
2601
|
+
|
|
2602
|
+
Returns:
|
|
2603
|
+
The created PromptTemplate instance.
|
|
2604
|
+
"""
|
|
2605
|
+
template = PromptTemplate(name=name, content=content, metadata=metadata)
|
|
2606
|
+
self.templates[name] = template
|
|
2607
|
+
logger.info(f"Template registered: {{name}} (v{{template.version}})")
|
|
2608
|
+
return template
|
|
2609
|
+
|
|
2610
|
+
def render(self, name: str, variables: Dict[str, str]) -> str:
|
|
2611
|
+
"""Render a named template with the given variables.
|
|
2612
|
+
|
|
2613
|
+
Args:
|
|
2614
|
+
name: Template name.
|
|
2615
|
+
variables: Variable substitutions.
|
|
2616
|
+
|
|
2617
|
+
Returns:
|
|
2618
|
+
Rendered string.
|
|
2619
|
+
|
|
2620
|
+
Raises:
|
|
2621
|
+
KeyError: If template not found.
|
|
2622
|
+
ValueError: If required variables are missing.
|
|
2623
|
+
"""
|
|
2624
|
+
if name not in self.templates:
|
|
2625
|
+
raise KeyError(f"Template not found: {{name}}")
|
|
2626
|
+
return self.templates[name].render(variables)
|
|
2627
|
+
|
|
2628
|
+
def compose(self, template_names: List[str], variables: Dict[str, str], separator: str = "\\n\\n") -> str:
|
|
2629
|
+
"""Compose multiple templates into a single prompt.
|
|
2630
|
+
|
|
2631
|
+
Args:
|
|
2632
|
+
template_names: Ordered list of template names.
|
|
2633
|
+
variables: Variable substitutions (applied to all).
|
|
2634
|
+
separator: String to join rendered templates.
|
|
2635
|
+
|
|
2636
|
+
Returns:
|
|
2637
|
+
Composed rendered string.
|
|
2638
|
+
"""
|
|
2639
|
+
parts = []
|
|
2640
|
+
for name in template_names:
|
|
2641
|
+
parts.append(self.render(name, variables))
|
|
2642
|
+
return separator.join(parts)
|
|
2643
|
+
|
|
2644
|
+
def list_templates(self) -> List[Dict[str, Any]]:
|
|
2645
|
+
"""List all loaded templates with metadata.
|
|
2646
|
+
|
|
2647
|
+
Returns:
|
|
2648
|
+
List of template summary dicts.
|
|
2649
|
+
"""
|
|
2650
|
+
return [t.to_dict() for t in self.templates.values()]
|
|
2651
|
+
|
|
2652
|
+
|
|
2653
|
+
# Standalone usage
|
|
2654
|
+
if __name__ == "__main__":
|
|
2655
|
+
manager = {class_name}PromptManager()
|
|
2656
|
+
print(f"Loaded {{len(manager.templates)}} templates")
|
|
2657
|
+
for info in manager.list_templates():
|
|
2658
|
+
print(f" {{info['name']}} (v{{info['version']}}): {{info['variables']}}")
|
|
2659
|
+
'''
|
|
2660
|
+
|
|
2661
|
+
|
|
2662
|
+
def _generate_agent_collaboration_code(entity: str, spec: str) -> str:
|
|
2663
|
+
"""Generate collaboration coordinator with authority checks.
|
|
2664
|
+
|
|
2665
|
+
Creates a multi-agent collaboration module that:
|
|
2666
|
+
- Coordinates task handoffs between agents
|
|
2667
|
+
- Enforces authority/permission checks before delegation
|
|
2668
|
+
- Tracks collaboration sessions with full audit trail
|
|
2669
|
+
- Supports parallel fan-out and sequential pipeline patterns
|
|
2670
|
+
"""
|
|
2671
|
+
class_name = entity.capitalize()
|
|
2672
|
+
return f'''{CUI_HEADER}
|
|
2673
|
+
"""Agent Collaboration Coordinator: {entity}
|
|
2674
|
+
|
|
2675
|
+
Spec: {spec}
|
|
2676
|
+
Generated by ICDEV Builder - code_generator.py (Phase 19: Agentic)
|
|
2677
|
+
|
|
2678
|
+
Coordinates multi-agent collaboration with authority checks,
|
|
2679
|
+
task handoff tracking, and structured audit trail. Supports
|
|
2680
|
+
fan-out (parallel) and pipeline (sequential) collaboration patterns.
|
|
2681
|
+
"""
|
|
2682
|
+
|
|
2683
|
+
import json
|
|
2684
|
+
import logging
|
|
2685
|
+
import uuid
|
|
2686
|
+
from datetime import datetime, timezone
|
|
2687
|
+
from enum import Enum
|
|
2688
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
2689
|
+
|
|
2690
|
+
logger = logging.getLogger(__name__)
|
|
2691
|
+
|
|
2692
|
+
|
|
2693
|
+
class CollaborationPattern(Enum):
|
|
2694
|
+
"""Supported multi-agent collaboration patterns."""
|
|
2695
|
+
PIPELINE = "pipeline" # Sequential A -> B -> C
|
|
2696
|
+
FAN_OUT = "fan_out" # Parallel A -> [B, C, D]
|
|
2697
|
+
HANDOFF = "handoff" # Single transfer A -> B
|
|
2698
|
+
ROUND_ROBIN = "round_robin" # Cyclic distribution
|
|
2699
|
+
|
|
2700
|
+
|
|
2701
|
+
class TaskStatus(Enum):
|
|
2702
|
+
"""Status of a collaboration task."""
|
|
2703
|
+
PENDING = "pending"
|
|
2704
|
+
DISPATCHED = "dispatched"
|
|
2705
|
+
IN_PROGRESS = "in_progress"
|
|
2706
|
+
COMPLETED = "completed"
|
|
2707
|
+
FAILED = "failed"
|
|
2708
|
+
REJECTED = "rejected"
|
|
2709
|
+
|
|
2710
|
+
|
|
2711
|
+
class AuthorityLevel(Enum):
|
|
2712
|
+
"""Agent authority levels for permission checks."""
|
|
2713
|
+
CORE = "core" # Orchestrator, Architect
|
|
2714
|
+
DOMAIN = "domain" # Builder, Compliance, Security, Infra, MBSE, Modernization
|
|
2715
|
+
SUPPORT = "support" # Knowledge, Monitor
|
|
2716
|
+
|
|
2717
|
+
|
|
2718
|
+
# Authority matrix: which levels can delegate to which
|
|
2719
|
+
AUTHORITY_MATRIX = {{
|
|
2720
|
+
AuthorityLevel.CORE: {{AuthorityLevel.CORE, AuthorityLevel.DOMAIN, AuthorityLevel.SUPPORT}},
|
|
2721
|
+
AuthorityLevel.DOMAIN: {{AuthorityLevel.DOMAIN, AuthorityLevel.SUPPORT}},
|
|
2722
|
+
AuthorityLevel.SUPPORT: {{AuthorityLevel.SUPPORT}},
|
|
2723
|
+
}}
|
|
2724
|
+
|
|
2725
|
+
|
|
2726
|
+
class CollaborationTask:
|
|
2727
|
+
"""A single task within a collaboration session.
|
|
2728
|
+
|
|
2729
|
+
Attributes:
|
|
2730
|
+
task_id: Unique task identifier.
|
|
2731
|
+
source_agent: Agent that created the task.
|
|
2732
|
+
target_agent: Agent that should execute the task.
|
|
2733
|
+
action: The action to perform.
|
|
2734
|
+
params: Task parameters.
|
|
2735
|
+
status: Current task status.
|
|
2736
|
+
result: Task result (set on completion).
|
|
2737
|
+
"""
|
|
2738
|
+
|
|
2739
|
+
def __init__(
|
|
2740
|
+
self,
|
|
2741
|
+
source_agent: str,
|
|
2742
|
+
target_agent: str,
|
|
2743
|
+
action: str,
|
|
2744
|
+
params: Optional[Dict[str, Any]] = None,
|
|
2745
|
+
) -> None:
|
|
2746
|
+
self.task_id = str(uuid.uuid4())
|
|
2747
|
+
self.source_agent = source_agent
|
|
2748
|
+
self.target_agent = target_agent
|
|
2749
|
+
self.action = action
|
|
2750
|
+
self.params = params or {{}}
|
|
2751
|
+
self.status = TaskStatus.PENDING
|
|
2752
|
+
self.result: Optional[Dict[str, Any]] = None
|
|
2753
|
+
self.created_at = datetime.now(timezone.utc).isoformat() + "Z"
|
|
2754
|
+
self.updated_at = self.created_at
|
|
2755
|
+
|
|
2756
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
2757
|
+
"""Serialize task to dict."""
|
|
2758
|
+
return {{
|
|
2759
|
+
"task_id": self.task_id,
|
|
2760
|
+
"source_agent": self.source_agent,
|
|
2761
|
+
"target_agent": self.target_agent,
|
|
2762
|
+
"action": self.action,
|
|
2763
|
+
"params": self.params,
|
|
2764
|
+
"status": self.status.value,
|
|
2765
|
+
"result": self.result,
|
|
2766
|
+
"created_at": self.created_at,
|
|
2767
|
+
"updated_at": self.updated_at,
|
|
2768
|
+
}}
|
|
2769
|
+
|
|
2770
|
+
|
|
2771
|
+
class {class_name}Coordinator:
|
|
2772
|
+
"""Coordinates multi-agent collaboration with authority enforcement.
|
|
2773
|
+
|
|
2774
|
+
Manages collaboration sessions, enforces the authority matrix,
|
|
2775
|
+
dispatches tasks to agents, and maintains a full audit trail
|
|
2776
|
+
of all handoffs and results.
|
|
2777
|
+
|
|
2778
|
+
Attributes:
|
|
2779
|
+
session_id: Current collaboration session ID.
|
|
2780
|
+
agents: Registered agents with their authority levels.
|
|
2781
|
+
tasks: All tasks in the current session.
|
|
2782
|
+
audit_log: Chronological log of all collaboration events.
|
|
2783
|
+
"""
|
|
2784
|
+
|
|
2785
|
+
def __init__(self, session_id: Optional[str] = None) -> None:
|
|
2786
|
+
"""Initialize the collaboration coordinator.
|
|
2787
|
+
|
|
2788
|
+
Args:
|
|
2789
|
+
session_id: Optional session ID (auto-generated if omitted).
|
|
2790
|
+
"""
|
|
2791
|
+
self.session_id = session_id or str(uuid.uuid4())
|
|
2792
|
+
self.agents: Dict[str, AuthorityLevel] = {{}}
|
|
2793
|
+
self.tasks: List[CollaborationTask] = []
|
|
2794
|
+
self.audit_log: List[Dict[str, Any]] = []
|
|
2795
|
+
self._task_handlers: Dict[str, Callable] = {{}}
|
|
2796
|
+
logger.info(f"{class_name}Coordinator initialized (session={{self.session_id}})")
|
|
2797
|
+
|
|
2798
|
+
def register_agent(self, agent_name: str, authority: AuthorityLevel) -> None:
|
|
2799
|
+
"""Register an agent with the coordinator.
|
|
2800
|
+
|
|
2801
|
+
Args:
|
|
2802
|
+
agent_name: Unique agent identifier.
|
|
2803
|
+
authority: Agent's authority level.
|
|
2804
|
+
"""
|
|
2805
|
+
self.agents[agent_name] = authority
|
|
2806
|
+
self._log_event("agent_registered", {{
|
|
2807
|
+
"agent": agent_name,
|
|
2808
|
+
"authority": authority.value,
|
|
2809
|
+
}})
|
|
2810
|
+
|
|
2811
|
+
def check_authority(self, source_agent: str, target_agent: str) -> bool:
|
|
2812
|
+
"""Check if source agent can delegate to target agent.
|
|
2813
|
+
|
|
2814
|
+
Args:
|
|
2815
|
+
source_agent: The delegating agent.
|
|
2816
|
+
target_agent: The receiving agent.
|
|
2817
|
+
|
|
2818
|
+
Returns:
|
|
2819
|
+
True if delegation is authorized.
|
|
2820
|
+
"""
|
|
2821
|
+
source_level = self.agents.get(source_agent)
|
|
2822
|
+
target_level = self.agents.get(target_agent)
|
|
2823
|
+
|
|
2824
|
+
if source_level is None:
|
|
2825
|
+
logger.warning(f"Unknown source agent: {{source_agent}}")
|
|
2826
|
+
return False
|
|
2827
|
+
if target_level is None:
|
|
2828
|
+
logger.warning(f"Unknown target agent: {{target_agent}}")
|
|
2829
|
+
return False
|
|
2830
|
+
|
|
2831
|
+
allowed = AUTHORITY_MATRIX.get(source_level, set())
|
|
2832
|
+
return target_level in allowed
|
|
2833
|
+
|
|
2834
|
+
def handoff(
|
|
2835
|
+
self,
|
|
2836
|
+
source_agent: str,
|
|
2837
|
+
target_agent: str,
|
|
2838
|
+
action: str,
|
|
2839
|
+
params: Optional[Dict[str, Any]] = None,
|
|
2840
|
+
) -> CollaborationTask:
|
|
2841
|
+
"""Create and dispatch a handoff task with authority check.
|
|
2842
|
+
|
|
2843
|
+
Args:
|
|
2844
|
+
source_agent: The delegating agent.
|
|
2845
|
+
target_agent: The receiving agent.
|
|
2846
|
+
action: Action to perform.
|
|
2847
|
+
params: Task parameters.
|
|
2848
|
+
|
|
2849
|
+
Returns:
|
|
2850
|
+
The created CollaborationTask.
|
|
2851
|
+
|
|
2852
|
+
Raises:
|
|
2853
|
+
PermissionError: If authority check fails.
|
|
2854
|
+
ValueError: If agents are not registered.
|
|
2855
|
+
"""
|
|
2856
|
+
if source_agent not in self.agents:
|
|
2857
|
+
raise ValueError(f"Source agent not registered: {{source_agent}}")
|
|
2858
|
+
if target_agent not in self.agents:
|
|
2859
|
+
raise ValueError(f"Target agent not registered: {{target_agent}}")
|
|
2860
|
+
|
|
2861
|
+
if not self.check_authority(source_agent, target_agent):
|
|
2862
|
+
self._log_event("authority_denied", {{
|
|
2863
|
+
"source": source_agent,
|
|
2864
|
+
"target": target_agent,
|
|
2865
|
+
"action": action,
|
|
2866
|
+
}})
|
|
2867
|
+
raise PermissionError(
|
|
2868
|
+
f"{{source_agent}} ({{self.agents[source_agent].value}}) "
|
|
2869
|
+
f"cannot delegate to {{target_agent}} ({{self.agents[target_agent].value}})"
|
|
2870
|
+
)
|
|
2871
|
+
|
|
2872
|
+
task = CollaborationTask(
|
|
2873
|
+
source_agent=source_agent,
|
|
2874
|
+
target_agent=target_agent,
|
|
2875
|
+
action=action,
|
|
2876
|
+
params=params,
|
|
2877
|
+
)
|
|
2878
|
+
task.status = TaskStatus.DISPATCHED
|
|
2879
|
+
task.updated_at = datetime.now(timezone.utc).isoformat() + "Z"
|
|
2880
|
+
self.tasks.append(task)
|
|
2881
|
+
|
|
2882
|
+
self._log_event("task_handoff", {{
|
|
2883
|
+
"task_id": task.task_id,
|
|
2884
|
+
"source": source_agent,
|
|
2885
|
+
"target": target_agent,
|
|
2886
|
+
"action": action,
|
|
2887
|
+
}})
|
|
2888
|
+
|
|
2889
|
+
logger.info(
|
|
2890
|
+
f"Handoff: {{source_agent}} -> {{target_agent}} "
|
|
2891
|
+
f"action='{{action}}' task_id={{task.task_id}}"
|
|
2892
|
+
)
|
|
2893
|
+
return task
|
|
2894
|
+
|
|
2895
|
+
def complete_task(self, task_id: str, result: Dict[str, Any]) -> None:
|
|
2896
|
+
"""Mark a task as completed with its result.
|
|
2897
|
+
|
|
2898
|
+
Args:
|
|
2899
|
+
task_id: Task to complete.
|
|
2900
|
+
result: Task result data.
|
|
2901
|
+
"""
|
|
2902
|
+
for task in self.tasks:
|
|
2903
|
+
if task.task_id == task_id:
|
|
2904
|
+
task.status = TaskStatus.COMPLETED
|
|
2905
|
+
task.result = result
|
|
2906
|
+
task.updated_at = datetime.now(timezone.utc).isoformat() + "Z"
|
|
2907
|
+
self._log_event("task_completed", {{
|
|
2908
|
+
"task_id": task_id,
|
|
2909
|
+
"target": task.target_agent,
|
|
2910
|
+
}})
|
|
2911
|
+
return
|
|
2912
|
+
raise ValueError(f"Task not found: {{task_id}}")
|
|
2913
|
+
|
|
2914
|
+
def fail_task(self, task_id: str, error: str) -> None:
|
|
2915
|
+
"""Mark a task as failed.
|
|
2916
|
+
|
|
2917
|
+
Args:
|
|
2918
|
+
task_id: Task to mark as failed.
|
|
2919
|
+
error: Error description.
|
|
2920
|
+
"""
|
|
2921
|
+
for task in self.tasks:
|
|
2922
|
+
if task.task_id == task_id:
|
|
2923
|
+
task.status = TaskStatus.FAILED
|
|
2924
|
+
task.result = {{"error": error}}
|
|
2925
|
+
task.updated_at = datetime.now(timezone.utc).isoformat() + "Z"
|
|
2926
|
+
self._log_event("task_failed", {{
|
|
2927
|
+
"task_id": task_id,
|
|
2928
|
+
"error": error,
|
|
2929
|
+
}})
|
|
2930
|
+
return
|
|
2931
|
+
raise ValueError(f"Task not found: {{task_id}}")
|
|
2932
|
+
|
|
2933
|
+
def get_session_summary(self) -> Dict[str, Any]:
|
|
2934
|
+
"""Get a summary of the current collaboration session.
|
|
2935
|
+
|
|
2936
|
+
Returns:
|
|
2937
|
+
Session summary with task counts and status breakdown.
|
|
2938
|
+
"""
|
|
2939
|
+
status_counts: Dict[str, int] = {{}}
|
|
2940
|
+
for task in self.tasks:
|
|
2941
|
+
status_counts[task.status.value] = status_counts.get(task.status.value, 0) + 1
|
|
2942
|
+
|
|
2943
|
+
return {{
|
|
2944
|
+
"session_id": self.session_id,
|
|
2945
|
+
"agent_count": len(self.agents),
|
|
2946
|
+
"task_count": len(self.tasks),
|
|
2947
|
+
"status_breakdown": status_counts,
|
|
2948
|
+
"audit_events": len(self.audit_log),
|
|
2949
|
+
}}
|
|
2950
|
+
|
|
2951
|
+
def _log_event(self, event_type: str, details: Dict[str, Any]) -> None:
|
|
2952
|
+
"""Append an event to the audit log.
|
|
2953
|
+
|
|
2954
|
+
Args:
|
|
2955
|
+
event_type: Type of collaboration event.
|
|
2956
|
+
details: Event-specific data.
|
|
2957
|
+
"""
|
|
2958
|
+
self.audit_log.append({{
|
|
2959
|
+
"timestamp": datetime.now(timezone.utc).isoformat() + "Z",
|
|
2960
|
+
"session_id": self.session_id,
|
|
2961
|
+
"event_type": event_type,
|
|
2962
|
+
"details": details,
|
|
2963
|
+
}})
|
|
2964
|
+
|
|
2965
|
+
|
|
2966
|
+
# Standalone usage
|
|
2967
|
+
if __name__ == "__main__":
|
|
2968
|
+
coord = {class_name}Coordinator()
|
|
2969
|
+
coord.register_agent("orchestrator", AuthorityLevel.CORE)
|
|
2970
|
+
coord.register_agent("builder", AuthorityLevel.DOMAIN)
|
|
2971
|
+
coord.register_agent("monitor", AuthorityLevel.SUPPORT)
|
|
2972
|
+
|
|
2973
|
+
task = coord.handoff("orchestrator", "builder", "generate_code", {{"spec": "REST API"}})
|
|
2974
|
+
coord.complete_task(task.task_id, {{"files": ["api.py"]}})
|
|
2975
|
+
|
|
2976
|
+
print(json.dumps(coord.get_session_summary(), indent=2))
|
|
2977
|
+
'''
|
|
2978
|
+
|
|
2979
|
+
|
|
2980
|
+
def _generate_model_config_code(entity: str, spec: str) -> str:
|
|
2981
|
+
"""Generate agent config + card generation module.
|
|
2982
|
+
|
|
2983
|
+
Creates a model/agent configuration module that:
|
|
2984
|
+
- Defines agent configuration dataclass with validation
|
|
2985
|
+
- Generates /.well-known/agent.json agent cards
|
|
2986
|
+
- Supports loading config from YAML/JSON files
|
|
2987
|
+
- Validates agent config against the GOTCHA framework schema
|
|
2988
|
+
"""
|
|
2989
|
+
class_name = entity.capitalize()
|
|
2990
|
+
return f'''{CUI_HEADER}
|
|
2991
|
+
"""Agent Configuration & Card Generator: {entity}
|
|
2992
|
+
|
|
2993
|
+
Spec: {spec}
|
|
2994
|
+
Generated by ICDEV Builder - code_generator.py (Phase 19: Agentic)
|
|
2995
|
+
|
|
2996
|
+
Provides agent configuration management and /.well-known/agent.json
|
|
2997
|
+
card generation for A2A protocol compliance. Supports loading from
|
|
2998
|
+
YAML/JSON and validation against the GOTCHA framework schema.
|
|
2999
|
+
"""
|
|
3000
|
+
|
|
3001
|
+
import hashlib
|
|
3002
|
+
import json
|
|
3003
|
+
import logging
|
|
3004
|
+
import os
|
|
3005
|
+
from dataclasses import asdict, dataclass, field
|
|
3006
|
+
from datetime import datetime, timezone
|
|
3007
|
+
from pathlib import Path
|
|
3008
|
+
from typing import Any, Dict, List, Optional
|
|
3009
|
+
|
|
3010
|
+
logger = logging.getLogger(__name__)
|
|
3011
|
+
|
|
3012
|
+
|
|
3013
|
+
# Valid agent tiers and their allowed ports
|
|
3014
|
+
AGENT_TIERS = {{
|
|
3015
|
+
"core": {{"ports": range(8443, 8445), "max_agents": 2}},
|
|
3016
|
+
"domain": {{"ports": range(8445, 8453), "max_agents": 8}},
|
|
3017
|
+
"support": {{"ports": range(8449, 8453), "max_agents": 4}},
|
|
3018
|
+
}}
|
|
3019
|
+
|
|
3020
|
+
# Required fields per agent tier
|
|
3021
|
+
TIER_REQUIREMENTS = {{
|
|
3022
|
+
"core": ["name", "port", "tier", "model_id", "tls_cert"],
|
|
3023
|
+
"domain": ["name", "port", "tier", "model_id"],
|
|
3024
|
+
"support": ["name", "port", "tier"],
|
|
3025
|
+
}}
|
|
3026
|
+
|
|
3027
|
+
|
|
3028
|
+
@dataclass
|
|
3029
|
+
class AgentSkillConfig:
|
|
3030
|
+
"""Configuration for a single agent skill.
|
|
3031
|
+
|
|
3032
|
+
Attributes:
|
|
3033
|
+
name: Skill name.
|
|
3034
|
+
version: Skill version.
|
|
3035
|
+
description: What the skill does.
|
|
3036
|
+
keywords: Discovery keywords.
|
|
3037
|
+
input_schema: JSON Schema for skill input.
|
|
3038
|
+
"""
|
|
3039
|
+
name: str = ""
|
|
3040
|
+
version: str = "1.0.0"
|
|
3041
|
+
description: str = ""
|
|
3042
|
+
keywords: List[str] = field(default_factory=list)
|
|
3043
|
+
input_schema: Dict[str, Any] = field(default_factory=dict)
|
|
3044
|
+
|
|
3045
|
+
|
|
3046
|
+
@dataclass
|
|
3047
|
+
class {class_name}AgentConfig:
|
|
3048
|
+
"""Full agent configuration for a GOTCHA framework agent.
|
|
3049
|
+
|
|
3050
|
+
Attributes:
|
|
3051
|
+
name: Agent name (e.g. 'builder', 'compliance').
|
|
3052
|
+
port: Agent listening port.
|
|
3053
|
+
tier: Agent tier (core, domain, support).
|
|
3054
|
+
model_id: Bedrock model ID for LLM inference.
|
|
3055
|
+
tls_cert: Path to TLS certificate.
|
|
3056
|
+
tls_key: Path to TLS private key.
|
|
3057
|
+
description: Human-readable description.
|
|
3058
|
+
skills: List of skill configurations.
|
|
3059
|
+
metadata: Additional key-value metadata.
|
|
3060
|
+
health_endpoint: Health check path (default /health).
|
|
3061
|
+
max_concurrent_tasks: Max parallel task limit.
|
|
3062
|
+
"""
|
|
3063
|
+
name: str = ""
|
|
3064
|
+
port: int = 8443
|
|
3065
|
+
tier: str = "domain"
|
|
3066
|
+
model_id: str = "anthropic.claude-3-sonnet-20240229-v1:0"
|
|
3067
|
+
tls_cert: str = ""
|
|
3068
|
+
tls_key: str = ""
|
|
3069
|
+
description: str = ""
|
|
3070
|
+
skills: List[AgentSkillConfig] = field(default_factory=list)
|
|
3071
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
3072
|
+
health_endpoint: str = "/health"
|
|
3073
|
+
max_concurrent_tasks: int = 10
|
|
3074
|
+
|
|
3075
|
+
def validate(self) -> List[str]:
|
|
3076
|
+
"""Validate the agent configuration.
|
|
3077
|
+
|
|
3078
|
+
Returns:
|
|
3079
|
+
List of validation error messages (empty if valid).
|
|
3080
|
+
"""
|
|
3081
|
+
errors = []
|
|
3082
|
+
if not self.name:
|
|
3083
|
+
errors.append("name is required")
|
|
3084
|
+
if not isinstance(self.port, int) or self.port < 1024 or self.port > 65535:
|
|
3085
|
+
errors.append(f"invalid port: {{self.port}} (must be 1024-65535)")
|
|
3086
|
+
if self.tier not in AGENT_TIERS:
|
|
3087
|
+
errors.append(f"invalid tier: {{self.tier}} (must be one of {{list(AGENT_TIERS.keys())}})")
|
|
3088
|
+
else:
|
|
3089
|
+
required = TIER_REQUIREMENTS.get(self.tier, [])
|
|
3090
|
+
for req_field in required:
|
|
3091
|
+
if not getattr(self, req_field, None):
|
|
3092
|
+
errors.append(f"{{req_field}} is required for tier '{{self.tier}}'")
|
|
3093
|
+
if self.max_concurrent_tasks < 1:
|
|
3094
|
+
errors.append("max_concurrent_tasks must be >= 1")
|
|
3095
|
+
return errors
|
|
3096
|
+
|
|
3097
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
3098
|
+
"""Serialize configuration to dict."""
|
|
3099
|
+
return asdict(self)
|
|
3100
|
+
|
|
3101
|
+
|
|
3102
|
+
def generate_agent_card(config: {class_name}AgentConfig) -> Dict[str, Any]:
|
|
3103
|
+
"""Generate a /.well-known/agent.json card from config.
|
|
3104
|
+
|
|
3105
|
+
Creates an A2A-compliant agent card that other agents use
|
|
3106
|
+
to discover capabilities and establish communication.
|
|
3107
|
+
|
|
3108
|
+
Args:
|
|
3109
|
+
config: Agent configuration.
|
|
3110
|
+
|
|
3111
|
+
Returns:
|
|
3112
|
+
Agent card dict suitable for serving at /.well-known/agent.json.
|
|
3113
|
+
|
|
3114
|
+
Raises:
|
|
3115
|
+
ValueError: If config validation fails.
|
|
3116
|
+
"""
|
|
3117
|
+
errors = config.validate()
|
|
3118
|
+
if errors:
|
|
3119
|
+
raise ValueError(f"Invalid config: {{'; '.join(errors)}}")
|
|
3120
|
+
|
|
3121
|
+
card = {{
|
|
3122
|
+
"name": config.name,
|
|
3123
|
+
"description": config.description or f"{{config.name}} agent ({{config.tier}} tier)",
|
|
3124
|
+
"url": f"https://{{config.name}}:{{config.port}}",
|
|
3125
|
+
"version": "1.0.0",
|
|
3126
|
+
"protocol": "a2a",
|
|
3127
|
+
"protocolVersion": "1.0",
|
|
3128
|
+
"tier": config.tier,
|
|
3129
|
+
"capabilities": {{
|
|
3130
|
+
"streaming": False,
|
|
3131
|
+
"pushNotifications": False,
|
|
3132
|
+
"maxConcurrentTasks": config.max_concurrent_tasks,
|
|
3133
|
+
}},
|
|
3134
|
+
"skills": [
|
|
3135
|
+
{{
|
|
3136
|
+
"id": f"{{config.name}}-{{skill.name}}",
|
|
3137
|
+
"name": skill.name,
|
|
3138
|
+
"version": skill.version,
|
|
3139
|
+
"description": skill.description,
|
|
3140
|
+
"keywords": skill.keywords,
|
|
3141
|
+
"inputSchema": skill.input_schema or {{
|
|
3142
|
+
"type": "object",
|
|
3143
|
+
"properties": {{
|
|
3144
|
+
"action": {{"type": "string"}},
|
|
3145
|
+
}},
|
|
3146
|
+
}},
|
|
3147
|
+
}}
|
|
3148
|
+
for skill in config.skills
|
|
3149
|
+
],
|
|
3150
|
+
"authentication": {{
|
|
3151
|
+
"type": "mtls",
|
|
3152
|
+
"certificate": config.tls_cert,
|
|
3153
|
+
}},
|
|
3154
|
+
"health": {{
|
|
3155
|
+
"endpoint": config.health_endpoint,
|
|
3156
|
+
"interval": "30s",
|
|
3157
|
+
}},
|
|
3158
|
+
"generated_at": datetime.now(timezone.utc).isoformat() + "Z",
|
|
3159
|
+
}}
|
|
3160
|
+
return card
|
|
3161
|
+
|
|
3162
|
+
|
|
3163
|
+
def load_config_from_file(config_path: str) -> {class_name}AgentConfig:
|
|
3164
|
+
"""Load agent configuration from a YAML or JSON file.
|
|
3165
|
+
|
|
3166
|
+
Args:
|
|
3167
|
+
config_path: Path to config file (.yaml, .yml, or .json).
|
|
3168
|
+
|
|
3169
|
+
Returns:
|
|
3170
|
+
Populated AgentConfig instance.
|
|
3171
|
+
|
|
3172
|
+
Raises:
|
|
3173
|
+
FileNotFoundError: If config file doesn't exist.
|
|
3174
|
+
ValueError: If file format is unsupported.
|
|
3175
|
+
"""
|
|
3176
|
+
path = Path(config_path)
|
|
3177
|
+
if not path.exists():
|
|
3178
|
+
raise FileNotFoundError(f"Config file not found: {{config_path}}")
|
|
3179
|
+
|
|
3180
|
+
content = path.read_text(encoding="utf-8")
|
|
3181
|
+
|
|
3182
|
+
if path.suffix in (".yaml", ".yml"):
|
|
3183
|
+
try:
|
|
3184
|
+
import yaml
|
|
3185
|
+
data = yaml.safe_load(content)
|
|
3186
|
+
except ImportError:
|
|
3187
|
+
raise RuntimeError("pyyaml is required for YAML config. Install with: pip install pyyaml")
|
|
3188
|
+
elif path.suffix == ".json":
|
|
3189
|
+
data = json.loads(content)
|
|
3190
|
+
else:
|
|
3191
|
+
raise ValueError(f"Unsupported config format: {{path.suffix}} (use .yaml, .yml, or .json)")
|
|
3192
|
+
|
|
3193
|
+
# Build skill configs
|
|
3194
|
+
skills = []
|
|
3195
|
+
for skill_data in data.get("skills", []):
|
|
3196
|
+
skills.append(AgentSkillConfig(**skill_data))
|
|
3197
|
+
|
|
3198
|
+
config = {class_name}AgentConfig(
|
|
3199
|
+
name=data.get("name", ""),
|
|
3200
|
+
port=data.get("port", 8443),
|
|
3201
|
+
tier=data.get("tier", "domain"),
|
|
3202
|
+
model_id=data.get("model_id", ""),
|
|
3203
|
+
tls_cert=data.get("tls_cert", ""),
|
|
3204
|
+
tls_key=data.get("tls_key", ""),
|
|
3205
|
+
description=data.get("description", ""),
|
|
3206
|
+
skills=skills,
|
|
3207
|
+
metadata=data.get("metadata", {{}}),
|
|
3208
|
+
health_endpoint=data.get("health_endpoint", "/health"),
|
|
3209
|
+
max_concurrent_tasks=data.get("max_concurrent_tasks", 10),
|
|
3210
|
+
)
|
|
3211
|
+
|
|
3212
|
+
logger.info(f"Loaded config for agent '{{config.name}}' from {{config_path}}")
|
|
3213
|
+
return config
|
|
3214
|
+
|
|
3215
|
+
|
|
3216
|
+
def save_agent_card(config: {class_name}AgentConfig, output_dir: str) -> str:
|
|
3217
|
+
"""Generate and save agent card to .well-known/agent.json.
|
|
3218
|
+
|
|
3219
|
+
Args:
|
|
3220
|
+
config: Agent configuration.
|
|
3221
|
+
output_dir: Output directory (agent.json placed in .well-known/).
|
|
3222
|
+
|
|
3223
|
+
Returns:
|
|
3224
|
+
Path to the generated agent.json file.
|
|
3225
|
+
"""
|
|
3226
|
+
card = generate_agent_card(config)
|
|
3227
|
+
out_path = Path(output_dir) / ".well-known"
|
|
3228
|
+
out_path.mkdir(parents=True, exist_ok=True)
|
|
3229
|
+
card_file = out_path / "agent.json"
|
|
3230
|
+
card_file.write_text(json.dumps(card, indent=2), encoding="utf-8")
|
|
3231
|
+
logger.info(f"Agent card saved: {{card_file}}")
|
|
3232
|
+
return str(card_file)
|
|
3233
|
+
|
|
3234
|
+
|
|
3235
|
+
# Standalone usage
|
|
3236
|
+
if __name__ == "__main__":
|
|
3237
|
+
config = {class_name}AgentConfig(
|
|
3238
|
+
name="example-agent",
|
|
3239
|
+
port=8445,
|
|
3240
|
+
tier="domain",
|
|
3241
|
+
model_id="anthropic.claude-3-sonnet-20240229-v1:0",
|
|
3242
|
+
description="Example GOTCHA agent",
|
|
3243
|
+
skills=[
|
|
3244
|
+
AgentSkillConfig(
|
|
3245
|
+
name="example_skill",
|
|
3246
|
+
description="An example skill",
|
|
3247
|
+
keywords=["example", "demo"],
|
|
3248
|
+
),
|
|
3249
|
+
],
|
|
3250
|
+
)
|
|
3251
|
+
card = generate_agent_card(config)
|
|
3252
|
+
print(json.dumps(card, indent=2))
|
|
3253
|
+
'''
|
|
3254
|
+
|
|
3255
|
+
|
|
3256
|
+
# ---------------------------------------------------------------------------
|
|
3257
|
+
# Phase 19: generate_from_blueprint — batch generation for GOTCHA child apps
|
|
3258
|
+
# ---------------------------------------------------------------------------
|
|
3259
|
+
|
|
3260
|
+
def generate_from_blueprint(
|
|
3261
|
+
project_path: str,
|
|
3262
|
+
blueprint: Dict[str, Any],
|
|
3263
|
+
language: str = "python",
|
|
3264
|
+
) -> List[str]:
|
|
3265
|
+
"""Generate common boilerplate files from a GOTCHA blueprint.
|
|
3266
|
+
|
|
3267
|
+
Takes a blueprint dict describing a child application and generates:
|
|
3268
|
+
- Agent skill handlers for each agent defined in the blueprint
|
|
3269
|
+
- An LLM service wrapper
|
|
3270
|
+
- A prompt template manager
|
|
3271
|
+
- Agent configuration/card modules
|
|
3272
|
+
|
|
3273
|
+
Args:
|
|
3274
|
+
project_path: Root path of the project.
|
|
3275
|
+
blueprint: Blueprint dict with keys:
|
|
3276
|
+
- name (str): Application name
|
|
3277
|
+
- agents (list[dict]): Agent definitions with 'name', 'tier', 'port', 'skills'
|
|
3278
|
+
- llm_config (dict, optional): LLM configuration overrides
|
|
3279
|
+
- templates_dir (str, optional): Path to hardprompt templates
|
|
3280
|
+
language: Target language (currently only 'python' for agentic types).
|
|
3281
|
+
|
|
3282
|
+
Returns:
|
|
3283
|
+
List of paths to all generated files.
|
|
3284
|
+
"""
|
|
3285
|
+
if language != "python":
|
|
3286
|
+
raise ValueError(
|
|
3287
|
+
f"Agentic blueprint generation currently supports Python only, got: {language}"
|
|
3288
|
+
)
|
|
3289
|
+
|
|
3290
|
+
project = Path(project_path)
|
|
3291
|
+
src_dir = project / "src"
|
|
3292
|
+
src_dir.mkdir(parents=True, exist_ok=True)
|
|
3293
|
+
|
|
3294
|
+
# Ensure __init__.py
|
|
3295
|
+
init_file = src_dir / "__init__.py"
|
|
3296
|
+
if not init_file.exists():
|
|
3297
|
+
init_file.write_text(f"{CUI_HEADER}\n", encoding="utf-8")
|
|
3298
|
+
|
|
3299
|
+
generated_files: List[str] = []
|
|
3300
|
+
app_name = blueprint.get("name", "app")
|
|
3301
|
+
|
|
3302
|
+
# 1. Generate agent skill handlers for each agent
|
|
3303
|
+
agents = blueprint.get("agents", [])
|
|
3304
|
+
for agent_def in agents:
|
|
3305
|
+
agent_name = agent_def.get("name", "agent")
|
|
3306
|
+
agent_spec = (
|
|
3307
|
+
f"A2A skill handler for {agent_name} agent in {app_name}. "
|
|
3308
|
+
f"Tier: {agent_def.get('tier', 'domain')}. "
|
|
3309
|
+
f"Skills: {', '.join(s.get('name', '') for s in agent_def.get('skills', []))}"
|
|
3310
|
+
)
|
|
3311
|
+
code = _generate_agent_skill_code(agent_name, agent_spec)
|
|
3312
|
+
filename = f"skill_{_slugify(agent_name)}.py"
|
|
3313
|
+
output_file = src_dir / filename
|
|
3314
|
+
output_file.write_text(code, encoding="utf-8")
|
|
3315
|
+
generated_files.append(str(output_file))
|
|
3316
|
+
print(f"Generated [python/agent_skill]: {output_file}")
|
|
3317
|
+
|
|
3318
|
+
# 2. Generate LLM service wrapper
|
|
3319
|
+
llm_spec = (
|
|
3320
|
+
f"Bedrock LLM service for {app_name}. "
|
|
3321
|
+
f"Model: {blueprint.get('llm_config', {}).get('model_id', 'default')}."
|
|
3322
|
+
)
|
|
3323
|
+
code = _generate_llm_service_code(app_name, llm_spec)
|
|
3324
|
+
filename = f"llm_service_{_slugify(app_name)}.py"
|
|
3325
|
+
output_file = src_dir / filename
|
|
3326
|
+
output_file.write_text(code, encoding="utf-8")
|
|
3327
|
+
generated_files.append(str(output_file))
|
|
3328
|
+
print(f"Generated [python/llm_service]: {output_file}")
|
|
3329
|
+
|
|
3330
|
+
# 3. Generate prompt template manager
|
|
3331
|
+
tmpl_spec = f"Hardprompt template manager for {app_name}."
|
|
3332
|
+
code = _generate_prompt_template_code(app_name, tmpl_spec)
|
|
3333
|
+
filename = f"prompt_manager_{_slugify(app_name)}.py"
|
|
3334
|
+
output_file = src_dir / filename
|
|
3335
|
+
output_file.write_text(code, encoding="utf-8")
|
|
3336
|
+
generated_files.append(str(output_file))
|
|
3337
|
+
print(f"Generated [python/prompt_template]: {output_file}")
|
|
3338
|
+
|
|
3339
|
+
# 4. Generate agent config/card modules for each agent
|
|
3340
|
+
for agent_def in agents:
|
|
3341
|
+
agent_name = agent_def.get("name", "agent")
|
|
3342
|
+
config_spec = (
|
|
3343
|
+
f"Agent config and card for {agent_name} in {app_name}. "
|
|
3344
|
+
f"Port: {agent_def.get('port', 8443)}. Tier: {agent_def.get('tier', 'domain')}."
|
|
3345
|
+
)
|
|
3346
|
+
code = _generate_model_config_code(agent_name, config_spec)
|
|
3347
|
+
filename = f"config_{_slugify(agent_name)}.py"
|
|
3348
|
+
output_file = src_dir / filename
|
|
3349
|
+
output_file.write_text(code, encoding="utf-8")
|
|
3350
|
+
generated_files.append(str(output_file))
|
|
3351
|
+
print(f"Generated [python/model_config]: {output_file}")
|
|
3352
|
+
|
|
3353
|
+
# Log audit trail
|
|
3354
|
+
_log_audit(project_path, generated_files, f"Blueprint generation for {app_name}")
|
|
3355
|
+
|
|
3356
|
+
return generated_files
|
|
3357
|
+
|
|
3358
|
+
|
|
3359
|
+
def _generate_mosa_interface_code(entity: str, spec: str) -> str:
|
|
3360
|
+
"""Generate MOSA interface module: abstract interface + concrete implementation.
|
|
3361
|
+
|
|
3362
|
+
Creates:
|
|
3363
|
+
- Abstract interface class (ABC) with method stubs
|
|
3364
|
+
- Concrete implementation skeleton
|
|
3365
|
+
- Interface test stub
|
|
3366
|
+
- OpenAPI stub reference comment
|
|
3367
|
+
"""
|
|
3368
|
+
entity_title = entity.replace("_", " ").title().replace(" ", "")
|
|
3369
|
+
return f'''#!/usr/bin/env python3
|
|
3370
|
+
# CUI // SP-CTI
|
|
3371
|
+
"""MOSA Interface: {entity_title}
|
|
3372
|
+
|
|
3373
|
+
Auto-generated MOSA interface contract.
|
|
3374
|
+
Specification: {spec}
|
|
3375
|
+
|
|
3376
|
+
MOSA Compliance:
|
|
3377
|
+
- MOSA-ARCH-1: Module boundary definition (ABC interface)
|
|
3378
|
+
- MOSA-INT-1: Interface control document required
|
|
3379
|
+
- MOSA-INT-2: Semantic versioning enforced
|
|
3380
|
+
- MOSA-STD-2: OpenAPI spec recommended for REST interfaces
|
|
3381
|
+
"""
|
|
3382
|
+
|
|
3383
|
+
from abc import ABC, abstractmethod
|
|
3384
|
+
from dataclasses import dataclass
|
|
3385
|
+
from typing import Any, Dict, List, Optional
|
|
3386
|
+
|
|
3387
|
+
|
|
3388
|
+
# --- Interface Contract ---
|
|
3389
|
+
|
|
3390
|
+
class I{entity_title}(ABC):
|
|
3391
|
+
"""Abstract interface for {entity_title}.
|
|
3392
|
+
|
|
3393
|
+
All consumers MUST use this interface, not the concrete implementation.
|
|
3394
|
+
This ensures MOSA loose coupling (MOSA-ARCH-2) and replaceability (MOSA-CS-1).
|
|
3395
|
+
"""
|
|
3396
|
+
|
|
3397
|
+
@abstractmethod
|
|
3398
|
+
def get(self, resource_id: str) -> Optional[Dict[str, Any]]:
|
|
3399
|
+
"""Retrieve a resource by ID."""
|
|
3400
|
+
...
|
|
3401
|
+
|
|
3402
|
+
@abstractmethod
|
|
3403
|
+
def list_all(self, filters: Optional[Dict] = None) -> List[Dict[str, Any]]:
|
|
3404
|
+
"""List resources with optional filters."""
|
|
3405
|
+
...
|
|
3406
|
+
|
|
3407
|
+
@abstractmethod
|
|
3408
|
+
def create(self, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
3409
|
+
"""Create a new resource."""
|
|
3410
|
+
...
|
|
3411
|
+
|
|
3412
|
+
@abstractmethod
|
|
3413
|
+
def update(self, resource_id: str, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
3414
|
+
"""Update an existing resource."""
|
|
3415
|
+
...
|
|
3416
|
+
|
|
3417
|
+
@abstractmethod
|
|
3418
|
+
def delete(self, resource_id: str) -> bool:
|
|
3419
|
+
"""Delete a resource by ID."""
|
|
3420
|
+
...
|
|
3421
|
+
|
|
3422
|
+
|
|
3423
|
+
# --- Data Transfer Objects ---
|
|
3424
|
+
|
|
3425
|
+
@dataclass
|
|
3426
|
+
class {entity_title}Request:
|
|
3427
|
+
"""Request DTO for {entity_title} operations."""
|
|
3428
|
+
data: Dict[str, Any]
|
|
3429
|
+
request_id: Optional[str] = None
|
|
3430
|
+
|
|
3431
|
+
|
|
3432
|
+
@dataclass
|
|
3433
|
+
class {entity_title}Response:
|
|
3434
|
+
"""Response DTO for {entity_title} operations."""
|
|
3435
|
+
success: bool
|
|
3436
|
+
data: Optional[Dict[str, Any]] = None
|
|
3437
|
+
error: Optional[str] = None
|
|
3438
|
+
|
|
3439
|
+
|
|
3440
|
+
# --- Concrete Implementation ---
|
|
3441
|
+
|
|
3442
|
+
class {entity_title}Impl(I{entity_title}):
|
|
3443
|
+
"""Concrete implementation of I{entity_title}.
|
|
3444
|
+
|
|
3445
|
+
This implementation can be swapped out for an alternative (MOSA-CS-1)
|
|
3446
|
+
as long as the replacement implements I{entity_title}.
|
|
3447
|
+
"""
|
|
3448
|
+
|
|
3449
|
+
def __init__(self):
|
|
3450
|
+
self._store: Dict[str, Dict] = {{}}
|
|
3451
|
+
|
|
3452
|
+
def get(self, resource_id: str) -> Optional[Dict[str, Any]]:
|
|
3453
|
+
return self._store.get(resource_id)
|
|
3454
|
+
|
|
3455
|
+
def list_all(self, filters: Optional[Dict] = None) -> List[Dict[str, Any]]:
|
|
3456
|
+
items = list(self._store.values())
|
|
3457
|
+
if filters:
|
|
3458
|
+
for key, val in filters.items():
|
|
3459
|
+
items = [i for i in items if i.get(key) == val]
|
|
3460
|
+
return items
|
|
3461
|
+
|
|
3462
|
+
def create(self, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
3463
|
+
import uuid
|
|
3464
|
+
rid = str(uuid.uuid4())
|
|
3465
|
+
record = {{"id": rid, **data}}
|
|
3466
|
+
self._store[rid] = record
|
|
3467
|
+
return record
|
|
3468
|
+
|
|
3469
|
+
def update(self, resource_id: str, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
3470
|
+
if resource_id not in self._store:
|
|
3471
|
+
raise KeyError(f"Resource {{resource_id}} not found")
|
|
3472
|
+
self._store[resource_id].update(data)
|
|
3473
|
+
return self._store[resource_id]
|
|
3474
|
+
|
|
3475
|
+
def delete(self, resource_id: str) -> bool:
|
|
3476
|
+
if resource_id in self._store:
|
|
3477
|
+
del self._store[resource_id]
|
|
3478
|
+
return True
|
|
3479
|
+
return False
|
|
3480
|
+
|
|
3481
|
+
|
|
3482
|
+
# --- Interface Version ---
|
|
3483
|
+
INTERFACE_VERSION = "1.0.0"
|
|
3484
|
+
# See docs/icd/{entity}_icd.md for full Interface Control Document
|
|
3485
|
+
# See openapi/{entity}_openapi.yaml for OpenAPI specification
|
|
3486
|
+
'''
|
|
3487
|
+
|
|
3488
|
+
|
|
3489
|
+
# Template dispatch table (Python — original + Phase 19 agentic + Phase 26 MOSA)
|
|
3490
|
+
_GENERATORS = {
|
|
3491
|
+
"api": _generate_api_code,
|
|
3492
|
+
"model": _generate_model_code,
|
|
3493
|
+
"service": _generate_service_code,
|
|
3494
|
+
"cli": _generate_cli_code,
|
|
3495
|
+
"utility": _generate_module_code,
|
|
3496
|
+
"middleware": _generate_module_code,
|
|
3497
|
+
"config": _generate_module_code,
|
|
3498
|
+
"module": _generate_module_code,
|
|
3499
|
+
# Phase 19: Agentic spec types
|
|
3500
|
+
"agent_skill": _generate_agent_skill_code,
|
|
3501
|
+
"llm_service": _generate_llm_service_code,
|
|
3502
|
+
"prompt_template": _generate_prompt_template_code,
|
|
3503
|
+
"agent_collaboration": _generate_agent_collaboration_code,
|
|
3504
|
+
"model_config": _generate_model_config_code,
|
|
3505
|
+
# Phase 26: MOSA interface
|
|
3506
|
+
"mosa_interface": _generate_mosa_interface_code,
|
|
3507
|
+
}
|
|
3508
|
+
|
|
3509
|
+
# Language-specific generator dispatch tables
|
|
3510
|
+
LANGUAGE_GENERATORS = {
|
|
3511
|
+
"python": _GENERATORS,
|
|
3512
|
+
"java": {
|
|
3513
|
+
"api": _generate_java_api_code,
|
|
3514
|
+
"model": _generate_java_model_code,
|
|
3515
|
+
"service": _generate_java_service_code,
|
|
3516
|
+
},
|
|
3517
|
+
"go": {
|
|
3518
|
+
"api": _generate_go_api_code,
|
|
3519
|
+
"model": _generate_go_model_code,
|
|
3520
|
+
"service": _generate_go_service_code,
|
|
3521
|
+
},
|
|
3522
|
+
"typescript": {
|
|
3523
|
+
"api": _generate_typescript_api_code,
|
|
3524
|
+
"model": _generate_typescript_model_code,
|
|
3525
|
+
"service": _generate_typescript_service_code,
|
|
3526
|
+
},
|
|
3527
|
+
"rust": {
|
|
3528
|
+
"api": _generate_rust_api_code,
|
|
3529
|
+
"model": _generate_rust_model_code,
|
|
3530
|
+
"service": _generate_rust_service_code,
|
|
3531
|
+
},
|
|
3532
|
+
"csharp": {
|
|
3533
|
+
"api": _generate_csharp_api_code,
|
|
3534
|
+
"model": _generate_csharp_model_code,
|
|
3535
|
+
"service": _generate_csharp_service_code,
|
|
3536
|
+
},
|
|
3537
|
+
}
|
|
3538
|
+
|
|
3539
|
+
|
|
3540
|
+
# File extension mapping per language
|
|
3541
|
+
_LANGUAGE_EXTENSIONS = {
|
|
3542
|
+
"python": ".py",
|
|
3543
|
+
"java": ".java",
|
|
3544
|
+
"go": ".go",
|
|
3545
|
+
"typescript": ".ts",
|
|
3546
|
+
"rust": ".rs",
|
|
3547
|
+
"csharp": ".cs",
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
|
|
3551
|
+
def generate_from_spec(
|
|
3552
|
+
project_path: str,
|
|
3553
|
+
spec: str,
|
|
3554
|
+
output_dir: Optional[str] = None,
|
|
3555
|
+
force_type: Optional[str] = None,
|
|
3556
|
+
language: str = "python",
|
|
3557
|
+
project_id: Optional[str] = None,
|
|
3558
|
+
secure: bool = True,
|
|
3559
|
+
) -> List[str]:
|
|
3560
|
+
"""Generate implementation code from a specification.
|
|
3561
|
+
|
|
3562
|
+
Args:
|
|
3563
|
+
project_path: Root path of the project.
|
|
3564
|
+
spec: Specification text describing what to generate.
|
|
3565
|
+
output_dir: Optional output directory (defaults to {project}/src/).
|
|
3566
|
+
force_type: Force a specific code type (api, model, service, cli, module).
|
|
3567
|
+
language: Target language (python, java, go, typescript, rust, csharp).
|
|
3568
|
+
project_id: Optional project ID for dev profile injection (Phase 34, D187).
|
|
3569
|
+
secure: Include auth decorators and input validation (D-EPSEC-5).
|
|
3570
|
+
Default True. Use --no-auth CLI flag to disable.
|
|
3571
|
+
|
|
3572
|
+
Returns:
|
|
3573
|
+
List of paths to generated files.
|
|
3574
|
+
"""
|
|
3575
|
+
# Phase 34: Build profile context for LLM-aware generation
|
|
3576
|
+
profile_context = ""
|
|
3577
|
+
if project_id:
|
|
3578
|
+
profile_context = _build_profile_context(project_id, "code_generation")
|
|
3579
|
+
project = Path(project_path)
|
|
3580
|
+
src_dir = Path(output_dir) if output_dir else project / "src"
|
|
3581
|
+
src_dir.mkdir(parents=True, exist_ok=True)
|
|
3582
|
+
|
|
3583
|
+
# Ensure __init__.py exists for Python projects
|
|
3584
|
+
if language == "python":
|
|
3585
|
+
init_file = src_dir / "__init__.py"
|
|
3586
|
+
if not init_file.exists():
|
|
3587
|
+
init_file.write_text(f"{CUI_HEADER}\n", encoding="utf-8")
|
|
3588
|
+
|
|
3589
|
+
# Detect code type and entity
|
|
3590
|
+
code_type = force_type or _detect_spec_type(spec)
|
|
3591
|
+
entity = _extract_entity_name(spec)
|
|
3592
|
+
|
|
3593
|
+
# Get language-specific generators
|
|
3594
|
+
lang_generators = LANGUAGE_GENERATORS.get(language)
|
|
3595
|
+
if not lang_generators:
|
|
3596
|
+
raise ValueError(
|
|
3597
|
+
f"Unsupported language: {language}. "
|
|
3598
|
+
f"Supported: {', '.join(LANGUAGE_GENERATORS.keys())}"
|
|
3599
|
+
)
|
|
3600
|
+
|
|
3601
|
+
# Find the generator for this code type
|
|
3602
|
+
generator = lang_generators.get(code_type)
|
|
3603
|
+
if not generator:
|
|
3604
|
+
# Fall back to module/generic generator if available, or error
|
|
3605
|
+
generator = lang_generators.get("module")
|
|
3606
|
+
if not generator:
|
|
3607
|
+
available = ", ".join(lang_generators.keys())
|
|
3608
|
+
raise ValueError(
|
|
3609
|
+
f"No '{code_type}' generator for language '{language}'. "
|
|
3610
|
+
f"Available types for {language}: {available}"
|
|
3611
|
+
)
|
|
3612
|
+
|
|
3613
|
+
# Pass secure flag to API generators (D-EPSEC-5)
|
|
3614
|
+
import inspect
|
|
3615
|
+
if "secure" in inspect.signature(generator).parameters:
|
|
3616
|
+
code = generator(entity, spec, secure=secure)
|
|
3617
|
+
else:
|
|
3618
|
+
code = generator(entity, spec)
|
|
3619
|
+
|
|
3620
|
+
# Write the file with appropriate extension
|
|
3621
|
+
ext = _LANGUAGE_EXTENSIONS.get(language, ".py")
|
|
3622
|
+
filename = f"{_slugify(entity)}{ext}"
|
|
3623
|
+
output_file = src_dir / filename
|
|
3624
|
+
output_file.write_text(code, encoding="utf-8")
|
|
3625
|
+
|
|
3626
|
+
generated_files = [str(output_file)]
|
|
3627
|
+
print(f"Generated [{language}/{code_type}]: {output_file}")
|
|
3628
|
+
|
|
3629
|
+
# Log audit trail
|
|
3630
|
+
_log_audit(project_path, generated_files, spec)
|
|
3631
|
+
|
|
3632
|
+
return generated_files
|
|
3633
|
+
|
|
3634
|
+
|
|
3635
|
+
def _log_audit(project_path: str, files: List[str], spec: str) -> None:
|
|
3636
|
+
"""Log code generation to the audit trail."""
|
|
3637
|
+
try:
|
|
3638
|
+
conn = sqlite3.connect(str(DB_PATH))
|
|
3639
|
+
c = conn.cursor()
|
|
3640
|
+
c.execute(
|
|
3641
|
+
"""INSERT INTO audit_trail (project_id, event_type, actor, action, details, affected_files, classification)
|
|
3642
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)""",
|
|
3643
|
+
(
|
|
3644
|
+
None,
|
|
3645
|
+
"code_generated",
|
|
3646
|
+
"builder/code_generator",
|
|
3647
|
+
f"Generated code from spec: {spec[:100]}",
|
|
3648
|
+
json.dumps({"spec": spec}),
|
|
3649
|
+
json.dumps(files),
|
|
3650
|
+
"CUI",
|
|
3651
|
+
),
|
|
3652
|
+
)
|
|
3653
|
+
conn.commit()
|
|
3654
|
+
conn.close()
|
|
3655
|
+
except Exception as e:
|
|
3656
|
+
print(f"Warning: audit logging failed: {e}")
|
|
3657
|
+
|
|
3658
|
+
|
|
3659
|
+
def main():
|
|
3660
|
+
parser = argparse.ArgumentParser(description="Generate implementation code from specifications")
|
|
3661
|
+
parser.add_argument("--project-path", required=True, help="Root path of the project")
|
|
3662
|
+
parser.add_argument("--spec", required=True, help="Specification text")
|
|
3663
|
+
parser.add_argument("--output-dir", help="Output directory (defaults to {project}/src/)")
|
|
3664
|
+
parser.add_argument(
|
|
3665
|
+
"--type",
|
|
3666
|
+
choices=[
|
|
3667
|
+
"api", "model", "service", "cli", "utility", "middleware", "config", "module",
|
|
3668
|
+
"agent_skill", "llm_service", "prompt_template", "agent_collaboration", "model_config",
|
|
3669
|
+
],
|
|
3670
|
+
help="Force a specific code type",
|
|
3671
|
+
)
|
|
3672
|
+
parser.add_argument(
|
|
3673
|
+
"--language", default="python",
|
|
3674
|
+
choices=["python", "java", "go", "typescript", "csharp", "rust"],
|
|
3675
|
+
help="Target language for code generation (default: python)",
|
|
3676
|
+
)
|
|
3677
|
+
parser.add_argument(
|
|
3678
|
+
"--project-id", default=None,
|
|
3679
|
+
help="Project ID for dev profile injection (Phase 34, D187)",
|
|
3680
|
+
)
|
|
3681
|
+
parser.add_argument(
|
|
3682
|
+
"--no-auth", action="store_true",
|
|
3683
|
+
help="Disable auth decorators and validation in generated API code (D-EPSEC-5). "
|
|
3684
|
+
"WARNING: Generated code will fail endpoint_security gate.",
|
|
3685
|
+
)
|
|
3686
|
+
args = parser.parse_args()
|
|
3687
|
+
|
|
3688
|
+
files = generate_from_spec(
|
|
3689
|
+
project_path=args.project_path,
|
|
3690
|
+
spec=args.spec,
|
|
3691
|
+
output_dir=args.output_dir,
|
|
3692
|
+
force_type=args.type,
|
|
3693
|
+
language=args.language,
|
|
3694
|
+
project_id=args.project_id,
|
|
3695
|
+
secure=not args.no_auth,
|
|
3696
|
+
)
|
|
3697
|
+
print(f"\nGenerated {len(files)} file(s) [{args.language}]:")
|
|
3698
|
+
for f in files:
|
|
3699
|
+
print(f" {f}")
|
|
3700
|
+
|
|
3701
|
+
|
|
3702
|
+
if __name__ == "__main__":
|
|
3703
|
+
main()
|