soloforge 1.2.20 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -3
- package/dist/adapters/claude_code/claude_md.d.ts +1 -2
- package/dist/adapters/claude_code/claude_md.d.ts.map +1 -1
- package/dist/adapters/claude_code/claude_md.js +47 -4
- package/dist/adapters/claude_code/claude_md.js.map +1 -1
- package/dist/adapters/claude_code/hooks.d.ts.map +1 -1
- package/dist/adapters/claude_code/hooks.js +2 -1
- package/dist/adapters/claude_code/hooks.js.map +1 -1
- package/dist/adapters/claude_code/server.js +4 -3
- package/dist/adapters/claude_code/server.js.map +1 -1
- package/dist/adapters/claude_code/tools.d.ts +282 -1
- package/dist/adapters/claude_code/tools.d.ts.map +1 -1
- package/dist/adapters/claude_code/tools.js +1366 -40
- package/dist/adapters/claude_code/tools.js.map +1 -1
- package/dist/adapters/codex/codex_config.d.ts.map +1 -1
- package/dist/adapters/codex/codex_config.js +3 -2
- package/dist/adapters/codex/codex_config.js.map +1 -1
- package/dist/adapters/codex/codex_rules.d.ts.map +1 -1
- package/dist/adapters/codex/codex_rules.js +2 -1
- package/dist/adapters/codex/codex_rules.js.map +1 -1
- package/dist/adapters/shared/workflow_template.d.ts.map +1 -1
- package/dist/adapters/shared/workflow_template.js +8 -1
- package/dist/adapters/shared/workflow_template.js.map +1 -1
- package/dist/adapters/trae/trae_config.d.ts +0 -5
- package/dist/adapters/trae/trae_config.d.ts.map +1 -1
- package/dist/adapters/trae/trae_config.js +2 -1
- package/dist/adapters/trae/trae_config.js.map +1 -1
- package/dist/adapters/trae/trae_rules.d.ts.map +1 -1
- package/dist/adapters/trae/trae_rules.js +2 -1
- package/dist/adapters/trae/trae_rules.js.map +1 -1
- package/dist/bin/config_commands.d.ts.map +1 -1
- package/dist/bin/config_commands.js +34 -33
- package/dist/bin/config_commands.js.map +1 -1
- package/dist/bin/soloforge.d.ts.map +1 -1
- package/dist/bin/soloforge.js +1256 -160
- package/dist/bin/soloforge.js.map +1 -1
- package/dist/engine/adapter_prompt_contract.d.ts +60 -0
- package/dist/engine/adapter_prompt_contract.d.ts.map +1 -0
- package/dist/engine/adapter_prompt_contract.js +163 -0
- package/dist/engine/adapter_prompt_contract.js.map +1 -0
- package/dist/engine/architecture_decision_workshop.d.ts +58 -0
- package/dist/engine/architecture_decision_workshop.d.ts.map +1 -0
- package/dist/engine/architecture_decision_workshop.js +118 -0
- package/dist/engine/architecture_decision_workshop.js.map +1 -0
- package/dist/engine/architecture_design_contract.d.ts +49 -0
- package/dist/engine/architecture_design_contract.d.ts.map +1 -0
- package/dist/engine/architecture_design_contract.js +169 -0
- package/dist/engine/architecture_design_contract.js.map +1 -0
- package/dist/engine/artifact_contract_registry.d.ts.map +1 -1
- package/dist/engine/artifact_contract_registry.js +7 -14
- package/dist/engine/artifact_contract_registry.js.map +1 -1
- package/dist/engine/{batch1_manifest.d.ts → asset_manifest.d.ts} +8 -8
- package/dist/engine/asset_manifest.d.ts.map +1 -0
- package/dist/engine/{batch1_manifest.js → asset_manifest.js} +63 -9
- package/dist/engine/asset_manifest.js.map +1 -0
- package/dist/engine/audit_pool.d.ts.map +1 -1
- package/dist/engine/audit_pool.js +5 -4
- package/dist/engine/audit_pool.js.map +1 -1
- package/dist/engine/audit_sampler.d.ts.map +1 -1
- package/dist/engine/audit_sampler.js +2 -1
- package/dist/engine/audit_sampler.js.map +1 -1
- package/dist/engine/audit_verifier.d.ts.map +1 -1
- package/dist/engine/audit_verifier.js +5 -4
- package/dist/engine/audit_verifier.js.map +1 -1
- package/dist/engine/brainstorm_contract.d.ts +46 -0
- package/dist/engine/brainstorm_contract.d.ts.map +1 -0
- package/dist/engine/brainstorm_contract.js +136 -0
- package/dist/engine/brainstorm_contract.js.map +1 -0
- package/dist/engine/capability_action_advisor.d.ts.map +1 -1
- package/dist/engine/capability_action_advisor.js +8 -7
- package/dist/engine/capability_action_advisor.js.map +1 -1
- package/dist/engine/capability_registry.d.ts.map +1 -1
- package/dist/engine/capability_registry.js +0 -7
- package/dist/engine/capability_registry.js.map +1 -1
- package/dist/engine/capability_state_store.d.ts.map +1 -1
- package/dist/engine/capability_state_store.js +7 -6
- package/dist/engine/capability_state_store.js.map +1 -1
- package/dist/engine/change_coordinator.d.ts.map +1 -1
- package/dist/engine/change_coordinator.js +4 -3
- package/dist/engine/change_coordinator.js.map +1 -1
- package/dist/engine/chinese_semantic_priority.d.ts +62 -0
- package/dist/engine/chinese_semantic_priority.d.ts.map +1 -0
- package/dist/engine/chinese_semantic_priority.js +153 -0
- package/dist/engine/chinese_semantic_priority.js.map +1 -0
- package/dist/engine/coding_readiness_gate.d.ts +46 -0
- package/dist/engine/coding_readiness_gate.d.ts.map +1 -0
- package/dist/engine/coding_readiness_gate.js +175 -0
- package/dist/engine/coding_readiness_gate.js.map +1 -0
- package/dist/engine/cognitive_anchor.d.ts.map +1 -1
- package/dist/engine/cognitive_anchor.js +7 -6
- package/dist/engine/cognitive_anchor.js.map +1 -1
- package/dist/engine/command_execution_contract.d.ts.map +1 -1
- package/dist/engine/command_execution_contract.js +13 -12
- package/dist/engine/command_execution_contract.js.map +1 -1
- package/dist/engine/confidence_scorer.d.ts.map +1 -1
- package/dist/engine/confidence_scorer.js +2 -1
- package/dist/engine/confidence_scorer.js.map +1 -1
- package/dist/engine/config_precedence_contract.d.ts.map +1 -1
- package/dist/engine/config_precedence_contract.js +9 -8
- package/dist/engine/config_precedence_contract.js.map +1 -1
- package/dist/engine/conflict_gate.d.ts.map +1 -1
- package/dist/engine/conflict_gate.js +4 -3
- package/dist/engine/conflict_gate.js.map +1 -1
- package/dist/engine/consumable_asset_registry.d.ts +4 -0
- package/dist/engine/consumable_asset_registry.d.ts.map +1 -1
- package/dist/engine/consumable_asset_registry.js +370 -0
- package/dist/engine/consumable_asset_registry.js.map +1 -1
- package/dist/engine/consumption_trace_store.d.ts +50 -0
- package/dist/engine/consumption_trace_store.d.ts.map +1 -0
- package/dist/engine/consumption_trace_store.js +84 -0
- package/dist/engine/consumption_trace_store.js.map +1 -0
- package/dist/engine/contract_guard.d.ts.map +1 -1
- package/dist/engine/contract_guard.js +7 -6
- package/dist/engine/contract_guard.js.map +1 -1
- package/dist/engine/contract_registry.d.ts +1 -1
- package/dist/engine/contract_registry.d.ts.map +1 -1
- package/dist/engine/contract_registry.js +511 -38
- package/dist/engine/contract_registry.js.map +1 -1
- package/dist/engine/convention_detector.d.ts.map +1 -1
- package/dist/engine/convention_detector.js +4 -3
- package/dist/engine/convention_detector.js.map +1 -1
- package/dist/engine/core_engineering_principles.d.ts.map +1 -1
- package/dist/engine/core_engineering_principles.js +4 -14
- package/dist/engine/core_engineering_principles.js.map +1 -1
- package/dist/engine/core_experience_principle.d.ts +194 -0
- package/dist/engine/core_experience_principle.d.ts.map +1 -0
- package/dist/engine/core_experience_principle.js +349 -0
- package/dist/engine/core_experience_principle.js.map +1 -0
- package/dist/engine/debt_reporter.d.ts.map +1 -1
- package/dist/engine/debt_reporter.js +3 -2
- package/dist/engine/debt_reporter.js.map +1 -1
- package/dist/engine/debt_tracker.d.ts.map +1 -1
- package/dist/engine/debt_tracker.js +8 -7
- package/dist/engine/debt_tracker.js.map +1 -1
- package/dist/engine/debug_log.d.ts +4 -1
- package/dist/engine/debug_log.d.ts.map +1 -1
- package/dist/engine/debug_log.js +4 -6
- package/dist/engine/debug_log.js.map +1 -1
- package/dist/engine/debugger.d.ts.map +1 -1
- package/dist/engine/debugger.js +5 -4
- package/dist/engine/debugger.js.map +1 -1
- package/dist/engine/decision_contract.d.ts.map +1 -1
- package/dist/engine/decision_contract.js +4 -3
- package/dist/engine/decision_contract.js.map +1 -1
- package/dist/engine/delivery.d.ts.map +1 -1
- package/dist/engine/delivery.js +16 -15
- package/dist/engine/delivery.js.map +1 -1
- package/dist/engine/delivery_readiness.d.ts +5 -1
- package/dist/engine/delivery_readiness.d.ts.map +1 -1
- package/dist/engine/delivery_readiness.js +24 -2
- package/dist/engine/delivery_readiness.js.map +1 -1
- package/dist/engine/dependency_scanner.d.ts.map +1 -1
- package/dist/engine/dependency_scanner.js +6 -5
- package/dist/engine/dependency_scanner.js.map +1 -1
- package/dist/engine/design_artifact_pack.d.ts +44 -0
- package/dist/engine/design_artifact_pack.d.ts.map +1 -0
- package/dist/engine/design_artifact_pack.js +167 -0
- package/dist/engine/design_artifact_pack.js.map +1 -0
- package/dist/engine/detail_discipline.d.ts +40 -0
- package/dist/engine/detail_discipline.d.ts.map +1 -0
- package/dist/engine/detail_discipline.js +107 -0
- package/dist/engine/detail_discipline.js.map +1 -0
- package/dist/engine/developer_sovereignty.d.ts.map +1 -1
- package/dist/engine/developer_sovereignty.js +6 -5
- package/dist/engine/developer_sovereignty.js.map +1 -1
- package/dist/engine/diff_ownership.d.ts.map +1 -1
- package/dist/engine/diff_ownership.js +9 -8
- package/dist/engine/diff_ownership.js.map +1 -1
- package/dist/engine/diff_ownership_store.d.ts.map +1 -1
- package/dist/engine/diff_ownership_store.js +8 -7
- package/dist/engine/diff_ownership_store.js.map +1 -1
- package/dist/engine/documentation_governance.d.ts +55 -0
- package/dist/engine/documentation_governance.d.ts.map +1 -0
- package/dist/engine/documentation_governance.js +249 -0
- package/dist/engine/documentation_governance.js.map +1 -0
- package/dist/engine/dual_layer_mechanism_registry.d.ts +6 -4
- package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -1
- package/dist/engine/dual_layer_mechanism_registry.js +851 -11
- package/dist/engine/dual_layer_mechanism_registry.js.map +1 -1
- package/dist/engine/enforcement_guard.d.ts.map +1 -1
- package/dist/engine/enforcement_guard.js +14 -0
- package/dist/engine/enforcement_guard.js.map +1 -1
- package/dist/engine/escape_report.d.ts.map +1 -1
- package/dist/engine/escape_report.js +4 -3
- package/dist/engine/escape_report.js.map +1 -1
- package/dist/engine/evidence_grounding_contract.d.ts +137 -0
- package/dist/engine/evidence_grounding_contract.d.ts.map +1 -0
- package/dist/engine/evidence_grounding_contract.js +410 -0
- package/dist/engine/evidence_grounding_contract.js.map +1 -0
- package/dist/engine/evolution_regression_gate.d.ts +42 -0
- package/dist/engine/evolution_regression_gate.d.ts.map +1 -0
- package/dist/engine/evolution_regression_gate.js +159 -0
- package/dist/engine/evolution_regression_gate.js.map +1 -0
- package/dist/engine/existing_system_analysis.d.ts +37 -0
- package/dist/engine/existing_system_analysis.d.ts.map +1 -0
- package/dist/engine/existing_system_analysis.js +151 -0
- package/dist/engine/existing_system_analysis.js.map +1 -0
- package/dist/engine/exploration.d.ts.map +1 -1
- package/dist/engine/exploration.js +7 -6
- package/dist/engine/exploration.js.map +1 -1
- package/dist/engine/extension_contract.d.ts +50 -0
- package/dist/engine/extension_contract.d.ts.map +1 -0
- package/dist/engine/extension_contract.js +158 -0
- package/dist/engine/extension_contract.js.map +1 -0
- package/dist/engine/extension_platform_contracts.d.ts +712 -0
- package/dist/engine/extension_platform_contracts.d.ts.map +1 -0
- package/dist/engine/extension_platform_contracts.js +42 -0
- package/dist/engine/extension_platform_contracts.js.map +1 -0
- package/dist/engine/extension_scenario_registry.d.ts +30 -0
- package/dist/engine/extension_scenario_registry.d.ts.map +1 -0
- package/dist/engine/extension_scenario_registry.js +976 -0
- package/dist/engine/extension_scenario_registry.js.map +1 -0
- package/dist/engine/failure_classifier.d.ts.map +1 -1
- package/dist/engine/failure_classifier.js +9 -8
- package/dist/engine/failure_classifier.js.map +1 -1
- package/dist/engine/feasibility_checker.d.ts.map +1 -1
- package/dist/engine/feasibility_checker.js +5 -4
- package/dist/engine/feasibility_checker.js.map +1 -1
- package/dist/engine/first_principles.d.ts +35 -0
- package/dist/engine/first_principles.d.ts.map +1 -0
- package/dist/engine/first_principles.js +128 -0
- package/dist/engine/first_principles.js.map +1 -0
- package/dist/engine/{batch1_scenario_registry.d.ts → foundation_scenario_registry.d.ts} +15 -15
- package/dist/engine/foundation_scenario_registry.d.ts.map +1 -0
- package/dist/engine/{batch1_scenario_registry.js → foundation_scenario_registry.js} +22 -25
- package/dist/engine/foundation_scenario_registry.js.map +1 -0
- package/dist/engine/{batch1_scenario_runners.d.ts → foundation_scenario_runners.d.ts} +1 -1
- package/dist/engine/foundation_scenario_runners.d.ts.map +1 -0
- package/dist/engine/{batch1_scenario_runners.js → foundation_scenario_runners.js} +8 -7
- package/dist/engine/foundation_scenario_runners.js.map +1 -0
- package/dist/engine/git_deps.d.ts.map +1 -1
- package/dist/engine/git_deps.js +2 -1
- package/dist/engine/git_deps.js.map +1 -1
- package/dist/engine/governance_report.d.ts.map +1 -1
- package/dist/engine/governance_report.js +10 -9
- package/dist/engine/governance_report.js.map +1 -1
- package/dist/engine/impact_analyzer.d.ts.map +1 -1
- package/dist/engine/impact_analyzer.js +5 -4
- package/dist/engine/impact_analyzer.js.map +1 -1
- package/dist/engine/implementation_roadmap_registry.d.ts +1 -1
- package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -1
- package/dist/engine/implementation_roadmap_registry.js +348 -82
- package/dist/engine/implementation_roadmap_registry.js.map +1 -1
- package/dist/engine/input_material_contract_registry.d.ts.map +1 -1
- package/dist/engine/input_material_contract_registry.js +4 -3
- package/dist/engine/input_material_contract_registry.js.map +1 -1
- package/dist/engine/instruction_contract.d.ts +75 -0
- package/dist/engine/instruction_contract.d.ts.map +1 -0
- package/dist/engine/instruction_contract.js +185 -0
- package/dist/engine/instruction_contract.js.map +1 -0
- package/dist/engine/intent_expander.d.ts.map +1 -1
- package/dist/engine/intent_expander.js +353 -1
- package/dist/engine/intent_expander.js.map +1 -1
- package/dist/engine/intent_router.d.ts +11 -2
- package/dist/engine/intent_router.d.ts.map +1 -1
- package/dist/engine/intent_router.js +121 -1
- package/dist/engine/intent_router.js.map +1 -1
- package/dist/engine/intent_signal_extractor.d.ts +3 -0
- package/dist/engine/intent_signal_extractor.d.ts.map +1 -1
- package/dist/engine/intent_signal_extractor.js +49 -0
- package/dist/engine/intent_signal_extractor.js.map +1 -1
- package/dist/engine/io_controller.d.ts.map +1 -1
- package/dist/engine/io_controller.js +8 -7
- package/dist/engine/io_controller.js.map +1 -1
- package/dist/engine/java_quality_guard.d.ts.map +1 -1
- package/dist/engine/java_quality_guard.js +5 -18
- package/dist/engine/java_quality_guard.js.map +1 -1
- package/dist/engine/job_manager.d.ts.map +1 -1
- package/dist/engine/job_manager.js +8 -7
- package/dist/engine/job_manager.js.map +1 -1
- package/dist/engine/knowledge_acceptance_registry.d.ts +35 -0
- package/dist/engine/knowledge_acceptance_registry.d.ts.map +1 -0
- package/dist/engine/knowledge_acceptance_registry.js +271 -0
- package/dist/engine/knowledge_acceptance_registry.js.map +1 -0
- package/dist/engine/knowledge_asset_audit.d.ts +65 -0
- package/dist/engine/knowledge_asset_audit.d.ts.map +1 -0
- package/dist/engine/knowledge_asset_audit.js +230 -0
- package/dist/engine/knowledge_asset_audit.js.map +1 -0
- package/dist/engine/knowledge_asset_consumer.d.ts +150 -0
- package/dist/engine/knowledge_asset_consumer.d.ts.map +1 -0
- package/dist/engine/knowledge_asset_consumer.js +279 -0
- package/dist/engine/knowledge_asset_consumer.js.map +1 -0
- package/dist/engine/knowledge_asset_generation_gate.d.ts +38 -0
- package/dist/engine/knowledge_asset_generation_gate.d.ts.map +1 -0
- package/dist/engine/knowledge_asset_generation_gate.js +131 -0
- package/dist/engine/knowledge_asset_generation_gate.js.map +1 -0
- package/dist/engine/knowledge_asset_migration.d.ts +117 -0
- package/dist/engine/knowledge_asset_migration.d.ts.map +1 -0
- package/dist/engine/knowledge_asset_migration.js +204 -0
- package/dist/engine/knowledge_asset_migration.js.map +1 -0
- package/dist/engine/knowledge_asset_schema.d.ts +97 -0
- package/dist/engine/knowledge_asset_schema.d.ts.map +1 -0
- package/dist/engine/knowledge_asset_schema.js +413 -0
- package/dist/engine/knowledge_asset_schema.js.map +1 -0
- package/dist/engine/knowledge_config_loader.d.ts.map +1 -1
- package/dist/engine/knowledge_config_loader.js +5 -4
- package/dist/engine/knowledge_config_loader.js.map +1 -1
- package/dist/engine/knowledge_consumption_snapshot.d.ts +91 -0
- package/dist/engine/knowledge_consumption_snapshot.d.ts.map +1 -0
- package/dist/engine/knowledge_consumption_snapshot.js +113 -0
- package/dist/engine/knowledge_consumption_snapshot.js.map +1 -0
- package/dist/engine/knowledge_evolution.d.ts +82 -0
- package/dist/engine/knowledge_evolution.d.ts.map +1 -0
- package/dist/engine/knowledge_evolution.js +272 -0
- package/dist/engine/knowledge_evolution.js.map +1 -0
- package/dist/engine/knowledge_lifecycle.d.ts +70 -10
- package/dist/engine/knowledge_lifecycle.d.ts.map +1 -1
- package/dist/engine/knowledge_lifecycle.js +238 -4
- package/dist/engine/knowledge_lifecycle.js.map +1 -1
- package/dist/engine/knowledge_manager.d.ts.map +1 -1
- package/dist/engine/knowledge_manager.js +9 -8
- package/dist/engine/knowledge_manager.js.map +1 -1
- package/dist/engine/knowledge_scenario_registry.d.ts +21 -0
- package/dist/engine/knowledge_scenario_registry.d.ts.map +1 -0
- package/dist/engine/knowledge_scenario_registry.js +337 -0
- package/dist/engine/knowledge_scenario_registry.js.map +1 -0
- package/dist/engine/knowledge_sovereignty.d.ts.map +1 -1
- package/dist/engine/knowledge_sovereignty.js +5 -4
- package/dist/engine/knowledge_sovereignty.js.map +1 -1
- package/dist/engine/knowledge_template_contracts.d.ts +244 -0
- package/dist/engine/knowledge_template_contracts.d.ts.map +1 -0
- package/dist/engine/knowledge_template_contracts.js +26 -0
- package/dist/engine/knowledge_template_contracts.js.map +1 -0
- package/dist/engine/language_policy.d.ts +69 -12
- package/dist/engine/language_policy.d.ts.map +1 -1
- package/dist/engine/language_policy.js +129 -8
- package/dist/engine/language_policy.js.map +1 -1
- package/dist/engine/llm_gateway.d.ts.map +1 -1
- package/dist/engine/llm_gateway.js +10 -9
- package/dist/engine/llm_gateway.js.map +1 -1
- package/dist/engine/local_docker_acceptance.d.ts +94 -0
- package/dist/engine/local_docker_acceptance.d.ts.map +1 -0
- package/dist/engine/local_docker_acceptance.js +312 -0
- package/dist/engine/local_docker_acceptance.js.map +1 -0
- package/dist/engine/logger.d.ts +64 -0
- package/dist/engine/logger.d.ts.map +1 -0
- package/dist/engine/logger.js +115 -0
- package/dist/engine/logger.js.map +1 -0
- package/dist/engine/main_path_integration_contract.d.ts.map +1 -1
- package/dist/engine/main_path_integration_contract.js +43 -42
- package/dist/engine/main_path_integration_contract.js.map +1 -1
- package/dist/engine/mechanism_contract_registry.d.ts.map +1 -1
- package/dist/engine/mechanism_contract_registry.js +514 -17
- package/dist/engine/mechanism_contract_registry.js.map +1 -1
- package/dist/engine/metric_governance.d.ts +51 -0
- package/dist/engine/metric_governance.d.ts.map +1 -0
- package/dist/engine/metric_governance.js +138 -0
- package/dist/engine/metric_governance.js.map +1 -0
- package/dist/engine/migration_guard.d.ts.map +1 -1
- package/dist/engine/migration_guard.js +6 -5
- package/dist/engine/migration_guard.js.map +1 -1
- package/dist/engine/mutation_audit.d.ts.map +1 -1
- package/dist/engine/mutation_audit.js +6 -5
- package/dist/engine/mutation_audit.js.map +1 -1
- package/dist/engine/observability.d.ts +11 -0
- package/dist/engine/observability.d.ts.map +1 -1
- package/dist/engine/observability.js +60 -8
- package/dist/engine/observability.js.map +1 -1
- package/dist/engine/onboarding.d.ts.map +1 -1
- package/dist/engine/onboarding.js +17 -16
- package/dist/engine/onboarding.js.map +1 -1
- package/dist/engine/plan_proposal_gate.d.ts +131 -0
- package/dist/engine/plan_proposal_gate.d.ts.map +1 -0
- package/dist/engine/plan_proposal_gate.js +340 -0
- package/dist/engine/plan_proposal_gate.js.map +1 -0
- package/dist/engine/platform_context.d.ts +44 -0
- package/dist/engine/platform_context.d.ts.map +1 -0
- package/dist/engine/platform_context.js +169 -0
- package/dist/engine/platform_context.js.map +1 -0
- package/dist/engine/policy_drift_detector.d.ts.map +1 -1
- package/dist/engine/policy_drift_detector.js +8 -7
- package/dist/engine/policy_drift_detector.js.map +1 -1
- package/dist/engine/regression_matrix.d.ts.map +1 -1
- package/dist/engine/regression_matrix.js +15 -14
- package/dist/engine/regression_matrix.js.map +1 -1
- package/dist/engine/release_compatibility.d.ts +62 -0
- package/dist/engine/release_compatibility.d.ts.map +1 -0
- package/dist/engine/release_compatibility.js +145 -0
- package/dist/engine/release_compatibility.js.map +1 -0
- package/dist/engine/release_gate.d.ts +29 -0
- package/dist/engine/release_gate.d.ts.map +1 -0
- package/dist/engine/release_gate.js +675 -0
- package/dist/engine/release_gate.js.map +1 -0
- package/dist/engine/release_gate_scenario_registry.d.ts +65 -0
- package/dist/engine/release_gate_scenario_registry.d.ts.map +1 -0
- package/dist/engine/release_gate_scenario_registry.js +717 -0
- package/dist/engine/release_gate_scenario_registry.js.map +1 -0
- package/dist/engine/release_readiness_gate.d.ts +44 -0
- package/dist/engine/release_readiness_gate.d.ts.map +1 -0
- package/dist/engine/release_readiness_gate.js +1660 -0
- package/dist/engine/release_readiness_gate.js.map +1 -0
- package/dist/engine/risk_sampler.d.ts.map +1 -1
- package/dist/engine/risk_sampler.js +4 -3
- package/dist/engine/risk_sampler.js.map +1 -1
- package/dist/engine/runtime_safety.d.ts.map +1 -1
- package/dist/engine/runtime_safety.js +18 -17
- package/dist/engine/runtime_safety.js.map +1 -1
- package/dist/engine/scaffolder.d.ts.map +1 -1
- package/dist/engine/scaffolder.js +4 -3
- package/dist/engine/scaffolder.js.map +1 -1
- package/dist/engine/scope_lease.d.ts.map +1 -1
- package/dist/engine/scope_lease.js +4 -3
- package/dist/engine/scope_lease.js.map +1 -1
- package/dist/engine/semantic_evidence.d.ts.map +1 -1
- package/dist/engine/semantic_evidence.js +4 -3
- package/dist/engine/semantic_evidence.js.map +1 -1
- package/dist/engine/state_fact_classifier.d.ts +47 -0
- package/dist/engine/state_fact_classifier.d.ts.map +1 -0
- package/dist/engine/state_fact_classifier.js +158 -0
- package/dist/engine/state_fact_classifier.js.map +1 -0
- package/dist/engine/task_context.d.ts +34 -5
- package/dist/engine/task_context.d.ts.map +1 -1
- package/dist/engine/task_context.js +175 -49
- package/dist/engine/task_context.js.map +1 -1
- package/dist/engine/task_planner.d.ts.map +1 -1
- package/dist/engine/task_planner.js +6 -5
- package/dist/engine/task_planner.js.map +1 -1
- package/dist/engine/team_awareness.d.ts.map +1 -1
- package/dist/engine/team_awareness.js +2 -1
- package/dist/engine/team_awareness.js.map +1 -1
- package/dist/engine/technology_decision.d.ts +38 -0
- package/dist/engine/technology_decision.d.ts.map +1 -0
- package/dist/engine/technology_decision.js +120 -0
- package/dist/engine/technology_decision.js.map +1 -0
- package/dist/engine/template_manifest_io.d.ts +47 -0
- package/dist/engine/template_manifest_io.d.ts.map +1 -0
- package/dist/engine/template_manifest_io.js +151 -0
- package/dist/engine/template_manifest_io.js.map +1 -0
- package/dist/engine/template_mechanism_auditor.d.ts.map +1 -1
- package/dist/engine/template_mechanism_auditor.js +5 -4
- package/dist/engine/template_mechanism_auditor.js.map +1 -1
- package/dist/engine/template_sync.d.ts +98 -0
- package/dist/engine/template_sync.d.ts.map +1 -0
- package/dist/engine/template_sync.js +355 -0
- package/dist/engine/template_sync.js.map +1 -0
- package/dist/engine/test_generator.d.ts.map +1 -1
- package/dist/engine/test_generator.js +5 -4
- package/dist/engine/test_generator.js.map +1 -1
- package/dist/engine/test_quality.d.ts.map +1 -1
- package/dist/engine/test_quality.js +5 -4
- package/dist/engine/test_quality.js.map +1 -1
- package/dist/engine/tool_invocation_contract_registry.d.ts.map +1 -1
- package/dist/engine/tool_invocation_contract_registry.js +32 -31
- package/dist/engine/tool_invocation_contract_registry.js.map +1 -1
- package/dist/engine/traceability.d.ts.map +1 -1
- package/dist/engine/traceability.js +6 -5
- package/dist/engine/traceability.js.map +1 -1
- package/dist/engine/user_feedback_contract.d.ts.map +1 -1
- package/dist/engine/user_feedback_contract.js +81 -19
- package/dist/engine/user_feedback_contract.js.map +1 -1
- package/dist/engine/user_promise.d.ts +67 -0
- package/dist/engine/user_promise.d.ts.map +1 -0
- package/dist/engine/user_promise.js +436 -0
- package/dist/engine/user_promise.js.map +1 -0
- package/dist/engine/verifier.d.ts +6 -10
- package/dist/engine/verifier.d.ts.map +1 -1
- package/dist/engine/verifier.js +112 -1
- package/dist/engine/verifier.js.map +1 -1
- package/dist/engine/workflow_contract_registry.d.ts.map +1 -1
- package/dist/engine/workflow_contract_registry.js +128 -10
- package/dist/engine/workflow_contract_registry.js.map +1 -1
- package/dist/engine/workflow_template_pack.d.ts +71 -0
- package/dist/engine/workflow_template_pack.d.ts.map +1 -0
- package/dist/engine/workflow_template_pack.js +246 -0
- package/dist/engine/workflow_template_pack.js.map +1 -0
- package/dist/engine/workspace_resumer.d.ts.map +1 -1
- package/dist/engine/workspace_resumer.js +9 -8
- package/dist/engine/workspace_resumer.js.map +1 -1
- package/dist/engine/zero_config_init.d.ts.map +1 -1
- package/dist/engine/zero_config_init.js +16 -15
- package/dist/engine/zero_config_init.js.map +1 -1
- package/dist/git/operations.d.ts.map +1 -1
- package/dist/git/operations.js +18 -17
- package/dist/git/operations.js.map +1 -1
- package/dist/index.js +10 -9
- package/dist/index.js.map +1 -1
- package/dist/knowledge/conflict_detector.d.ts.map +1 -1
- package/dist/knowledge/conflict_detector.js +2 -1
- package/dist/knowledge/conflict_detector.js.map +1 -1
- package/dist/knowledge/health_checker.d.ts.map +1 -1
- package/dist/knowledge/health_checker.js +5 -4
- package/dist/knowledge/health_checker.js.map +1 -1
- package/dist/knowledge/index_manager.js +4 -4
- package/dist/knowledge/index_manager.js.map +1 -1
- package/dist/knowledge/loader.d.ts.map +1 -1
- package/dist/knowledge/loader.js +20 -14
- package/dist/knowledge/loader.js.map +1 -1
- package/dist/knowledge/writer.d.ts.map +1 -1
- package/dist/knowledge/writer.js +7 -6
- package/dist/knowledge/writer.js.map +1 -1
- package/dist/types.d.ts +40 -8
- package/dist/types.d.ts.map +1 -1
- package/package.json +14 -5
- package/templates/knowledge/acceptance_templates/API/346/216/245/345/217/243/350/247/204/346/240/274/346/226/207/346/241/243/346/250/241/347/211/210.md +74 -0
- package/templates/knowledge/acceptance_templates/Bug/345/210/206/346/236/220/346/250/241/347/211/210.md +27 -3
- package/templates/knowledge/acceptance_templates/POC/347/273/223/350/256/272/346/250/241/347/211/210.md +27 -3
- package/templates/knowledge/acceptance_templates//345/211/215/347/253/257/351/241/265/351/235/242/351/252/214/346/224/266/346/270/205/345/215/225.md +30 -3
- package/templates/knowledge/acceptance_templates//345/216/237/345/236/213/350/257/264/346/230/216/346/250/241/347/211/210.md +31 -3
- package/templates/knowledge/acceptance_templates//345/220/216/347/253/257API/351/252/214/346/224/266/346/270/205/345/215/225.md +29 -3
- package/templates/knowledge/acceptance_templates//345/256/211/345/205/250/345/256/241/350/256/241/346/250/241/347/211/210.md +27 -3
- package/templates/knowledge/acceptance_templates//346/200/247/350/203/275/345/210/206/346/236/220/346/250/241/347/211/210.md +27 -3
- package/templates/knowledge/acceptance_templates//346/212/200/346/234/257/351/200/211/345/236/213/351/252/214/346/224/266/346/270/205/345/215/225.md +30 -3
- package/templates/knowledge/acceptance_templates//346/216/245/345/217/243/345/257/271/346/216/245/346/226/271/346/241/210/346/250/241/347/211/210.md +26 -3
- package/templates/knowledge/acceptance_templates//346/216/245/345/217/243/350/256/276/350/256/241/346/250/241/347/211/210.md +27 -3
- package/templates/knowledge/acceptance_templates//346/225/205/351/232/234/345/244/215/347/233/230/346/250/241/347/211/210.md +28 -3
- package/templates/knowledge/acceptance_templates//346/225/260/346/215/256/345/272/223/345/217/230/346/233/264/346/226/271/346/241/210/346/250/241/347/211/210.md +26 -3
- package/templates/knowledge/acceptance_templates//346/225/260/346/215/256/345/272/223/345/217/230/346/233/264/351/252/214/346/224/266/346/270/205/345/215/225.md +31 -3
- package/templates/knowledge/acceptance_templates//346/225/260/346/215/256/345/272/223/350/256/276/350/256/241/346/226/207/346/241/243/346/250/241/347/211/210.md +59 -0
- package/templates/knowledge/acceptance_templates//346/236/266/346/236/204/350/256/276/350/256/241/346/250/241/347/211/210.md +54 -10
- package/templates/knowledge/acceptance_templates//346/265/213/350/257/225/350/256/241/345/210/222/346/250/241/347/211/210.md +27 -3
- package/templates/knowledge/acceptance_templates//350/256/276/350/256/241/344/270/200/350/207/264/346/200/247/351/252/214/346/224/266/346/212/245/345/221/212/346/250/241/347/211/210.md +47 -0
- package/templates/knowledge/acceptance_templates//350/257/246/347/273/206/350/256/276/350/256/241/346/250/241/347/211/210.md +26 -3
- package/templates/knowledge/acceptance_templates//350/277/201/347/247/273/350/257/204/344/274/260/346/250/241/347/211/210.md +27 -3
- package/templates/knowledge/acceptance_templates//351/200/232/347/224/250/350/264/250/351/207/217/351/252/214/346/224/266/346/270/205/345/215/225.md +30 -3
- package/templates/knowledge/acceptance_templates//351/207/215/346/236/204/346/226/271/346/241/210/346/250/241/347/211/210.md +27 -3
- package/templates/knowledge/acceptance_templates//351/234/200/346/261/202/345/210/206/346/236/220/346/250/241/347/211/210.md +27 -3
- package/templates/knowledge/checklists//344/270/273/351/223/276/350/267/257/346/216/245/345/205/245/351/252/214/346/224/266/346/270/205/345/215/225.md +29 -0
- package/templates/knowledge/checklists//344/274/232/350/257/235/346/201/242/345/244/215.md +30 -8
- package/templates/knowledge/checklists//345/267/245/344/275/234/346/265/201/351/252/214/346/224/266/346/270/205/345/215/225.md +30 -0
- package/templates/knowledge/checklists//346/240/270/345/277/203/345/267/245/347/250/213/346/211/247/350/241/214/351/252/214/346/224/266/346/270/205/345/215/225.md +29 -0
- package/templates/knowledge/checklists//347/237/245/350/257/206/346/263/250/345/205/245/351/252/214/346/224/266/346/270/205/345/215/225.md +30 -0
- package/templates/knowledge/checklists//351/232/220/347/247/201/345/256/241/346/237/245/346/270/205/345/215/225.md +29 -0
- package/templates/knowledge/checklists//351/252/214/350/257/201/351/252/214/346/224/266/346/270/205/345/215/225.md +29 -0
- package/templates/knowledge/domain//345/244/232/347/247/237/346/210/267.md +28 -3
- package/templates/knowledge/domain//345/256/241/350/256/241/346/227/245/345/277/227.md +27 -3
- package/templates/knowledge/domain//345/257/274/345/205/245/345/257/274/345/207/272/350/247/204/345/210/231.md +30 -3
- package/templates/knowledge/domain//345/267/245/344/275/234/346/265/201/345/274/225/346/223/216.md +32 -3
- package/templates/knowledge/domain//346/212/245/350/241/250/347/273/237/350/256/241.md +31 -3
- package/templates/knowledge/domain//346/224/257/344/273/230/350/247/204/345/210/231.md +31 -3
- package/templates/knowledge/domain//346/225/260/346/215/256/346/235/203/351/231/220.md +28 -3
- package/templates/knowledge/domain//351/200/232/347/224/250/346/234/272/346/242/260/346/235/241/346/254/276.md +30 -3
- package/templates/knowledge/domain//351/200/232/347/237/245/350/247/204/345/210/231.md +31 -3
- package/templates/knowledge/patterns/core/Diff/345/275/222/345/261/236/350/277/275/350/270/252.md +24 -7
- package/templates/knowledge/patterns/core/Java/350/264/250/351/207/217/351/227/250/347/246/201.md +25 -7
- package/templates/knowledge/patterns/core/LLM/351/242/204/347/256/227/347/275/221/345/205/263.md +24 -7
- package/templates/knowledge/patterns/core//344/273/273/345/212/241/344/270/212/344/270/213/346/226/207/347/224/237/345/221/275/345/221/250/346/234/237.md +24 -7
- package/templates/knowledge/patterns/core//344/273/273/345/212/241/347/256/241/347/220/206/345/231/250.md +25 -7
- package/templates/knowledge/patterns/core//344/275/234/347/224/250/345/237/237/344/270/216/345/257/206/351/222/245/346/213/246/346/210/252.md +24 -7
- package/templates/knowledge/patterns/core//344/275/234/347/224/250/345/237/237/347/247/237/347/272/246.md +25 -7
- package/templates/knowledge/patterns/core//345/206/262/347/252/201/351/227/250/347/246/201.md +24 -7
- package/templates/knowledge/patterns/core//345/206/263/347/255/226/347/275/221/345/205/263.md +26 -7
- package/templates/knowledge/patterns/core//345/217/230/345/274/202/345/256/241/350/256/241.md +25 -7
- package/templates/knowledge/patterns/core//345/233/236/345/275/222/347/237/251/351/230/265.md +24 -7
- package/templates/knowledge/patterns/core//345/267/245/344/275/234/345/214/272/344/272/222/346/226/245/351/224/201.md +24 -7
- package/templates/knowledge/patterns/core//345/267/245/344/275/234/345/214/272/345/224/244/351/206/222.md +24 -7
- package/templates/knowledge/patterns/core//345/271/266/345/217/221/351/224/201.md +26 -7
- package/templates/knowledge/patterns/core//345/274/200/345/217/221/350/200/205/345/256/252/346/263/225.md +26 -7
- package/templates/knowledge/patterns/core//346/225/217/346/204/237/344/277/241/346/201/257/346/211/253/346/217/217.md +24 -7
- package/templates/knowledge/patterns/core//346/262/273/347/220/206/350/277/220/350/241/214/346/227/266/345/276/252/347/216/257.md +25 -7
- package/templates/knowledge/patterns/core//346/265/201/345/274/217/345/277/203/350/267/263.md +25 -7
- package/templates/knowledge/patterns/core//347/237/245/350/257/206/344/270/273/346/235/203.md +25 -7
- package/templates/knowledge/patterns/core//350/257/255/344/271/211/350/257/201/346/215/256.md +24 -7
- package/templates/knowledge/patterns/core//350/277/220/350/241/214/345/256/211/345/205/250/345/214/205.md +25 -7
- package/templates/knowledge/patterns/core//351/233/266/351/205/215/347/275/256/345/210/235/345/247/213/345/214/226.md +24 -7
- package/templates/knowledge/patterns/core//351/252/214/350/257/201/345/221/275/344/273/244/347/224/237/346/210/220.md +24 -7
- package/templates/knowledge/procedures/Schema/345/217/230/346/233/264/346/265/201/346/260/264/347/272/277.md +29 -3
- package/templates/knowledge/procedures//344/270/273/351/223/276/350/267/257/346/216/245/345/205/245/351/252/214/350/257/201/346/265/201/347/250/213.md +33 -0
- package/templates/knowledge/procedures//344/273/243/347/240/201/351/227/250/347/246/201/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//344/273/273/345/212/241/346/213/206/350/247/243/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//345/212/237/350/203/275/345/274/200/345/217/221/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//345/221/275/344/273/244/346/211/247/350/241/214/346/265/201/347/250/213.md +34 -0
- package/templates/knowledge/procedures//345/256/211/345/205/250/345/212/240/345/233/272/346/265/201/346/260/264/347/272/277.md +30 -3
- package/templates/knowledge/procedures//345/267/245/345/205/267/350/260/203/347/224/250/346/265/201/347/250/213.md +34 -0
- package/templates/knowledge/procedures//346/200/247/350/203/275/346/265/201/346/260/264/347/272/277.md +30 -3
- package/templates/knowledge/procedures//346/204/217/345/233/276/350/267/257/347/224/261/346/265/201/347/250/213.md +34 -0
- package/templates/knowledge/procedures//346/216/245/345/217/243/351/233/206/346/210/220/346/265/201/346/260/264/347/272/277.md +30 -3
- package/templates/knowledge/procedures//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273/346/265/201/347/250/213.md +29 -3
- package/templates/knowledge/procedures//346/234/254/345/234/260/346/265/217/350/247/210/345/231/250/351/252/214/346/224/266/345/267/245/344/275/234/346/265/201.md +99 -0
- package/templates/knowledge/procedures//346/236/266/346/236/204/345/206/263/347/255/226/347/240/224/350/256/250/345/267/245/344/275/234/346/265/201.md +51 -0
- package/templates/knowledge/procedures//346/236/266/346/236/204/350/256/276/350/256/241/345/267/245/344/275/234/346/265/201.md +104 -0
- package/templates/knowledge/procedures//346/236/266/346/236/204/350/256/276/350/256/241/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//346/246/202/345/277/265/351/252/214/350/257/201/346/265/201/346/260/264/347/272/277.md +30 -3
- package/templates/knowledge/procedures//346/265/213/350/257/225/344/274/230/345/205/210/347/274/226/347/240/201/345/267/245/344/275/234/346/265/201.md +91 -0
- package/templates/knowledge/procedures//346/272/220/347/240/201/345/216/237/345/236/213/344/272/244/344/273/230/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//347/216/260/346/234/211/347/263/273/347/273/237/345/267/256/350/267/235/345/210/206/346/236/220/345/267/245/344/275/234/346/265/201.md +97 -0
- package/templates/knowledge/procedures//347/237/245/350/257/206/347/273/264/346/212/244/346/265/201/346/260/264/347/272/277.md +30 -3
- package/templates/knowledge/procedures//347/264/247/346/200/245/344/277/256/345/244/215/346/265/201/346/260/264/347/272/277.md +30 -3
- package/templates/knowledge/procedures//347/264/247/346/200/245/344/277/256/345/244/215/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//347/274/226/347/240/201/345/211/215/346/276/204/346/270/205/346/265/201/347/250/213.md +33 -0
- package/templates/knowledge/procedures//347/274/272/351/231/267/344/277/256/345/244/215/346/265/201/346/260/264/347/272/277.md +30 -3
- package/templates/knowledge/procedures//350/207/252/344/270/273/351/200/211/345/236/213/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//350/256/276/350/256/241/344/272/247/347/211/251/347/224/237/346/210/220/344/270/216/345/244/215/351/252/214/345/267/245/344/275/234/346/265/201.md +45 -0
- package/templates/knowledge/procedures//350/257/246/347/273/206/350/256/276/350/256/241/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//350/260/203/350/257/225/346/216/222/346/237/245/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//350/277/201/347/247/273/346/265/201/346/260/264/347/272/277.md +30 -3
- package/templates/knowledge/procedures//351/203/250/347/275/262/345/217/221/345/270/203/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//351/207/215/346/236/204/346/265/201/346/260/264/347/272/277.md +30 -3
- package/templates/knowledge/procedures//351/233/206/346/210/220/351/252/214/350/257/201/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//351/234/200/346/261/202/346/276/204/346/270/205/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/procedures//351/252/214/346/224/266/346/265/213/350/257/225/350/247/204/345/210/222.md +30 -3
- package/templates/knowledge/procedures//351/252/214/350/257/201/350/256/241/345/210/222/346/265/201/347/250/213.md +30 -3
- package/templates/knowledge/review_rules//344/272/244/344/273/230/345/256/214/345/244/207/346/200/247/345/256/241/346/237/245/350/247/204/345/210/231.md +24 -3
- package/templates/knowledge/review_rules//345/256/211/345/205/250/345/256/241/346/237/245/350/247/204/345/210/231.md +24 -3
- package/templates/knowledge/review_rules//345/271/266/345/217/221/345/256/241/346/237/245/350/247/204/345/210/231.md +23 -3
- package/templates/knowledge/review_rules//346/200/247/350/203/275/345/256/241/346/237/245/350/247/204/345/210/231.md +24 -3
- package/templates/knowledge/review_rules//346/216/245/345/217/243/345/245/221/347/272/246/345/256/241/346/237/245/350/247/204/345/210/231.md +23 -3
- package/templates/knowledge/review_rules//346/236/266/346/236/204/345/256/241/346/237/245/350/247/204/345/210/231.md +24 -3
- package/templates/knowledge/review_rules//350/264/250/351/207/217/345/256/241/346/237/245/350/247/204/345/210/231.md +24 -3
- package/templates/knowledge/rules//344/272/247/347/211/251/345/245/221/347/272/246/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//344/273/273/345/212/241/344/270/212/344/270/213/346/226/207/347/224/237/345/221/275/345/221/250/346/234/237/350/247/204/345/210/231.md +65 -0
- package/templates/knowledge/rules//345/221/275/344/273/244/346/211/247/350/241/214/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//345/267/245/344/275/234/346/265/201/345/245/221/347/272/246/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//345/267/245/344/275/234/346/265/201/346/250/241/346/235/277/345/214/205/350/247/204/345/210/231.md +48 -0
- package/templates/knowledge/rules//345/267/245/345/205/267/350/260/203/347/224/250/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//346/204/217/345/233/276/350/267/257/347/224/261/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//346/211/247/350/241/214/345/256/210/345/215/253/350/257/204/344/274/260/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//346/211/251/345/261/225/347/224/237/345/221/275/345/221/250/346/234/237/350/247/204/345/210/231.md +48 -0
- package/templates/knowledge/rules//346/212/200/346/234/257/345/206/263/347/255/226/344/270/273/346/235/203/350/247/204/345/210/231.md +64 -0
- package/templates/knowledge/rules//346/225/217/346/204/237/344/277/241/346/201/257/345/244/204/347/220/206/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//346/226/275/345/267/245/346/214/207/344/273/244/345/245/221/347/272/246/350/247/204/345/210/231.md +78 -0
- package/templates/knowledge/rules//346/236/266/346/236/204/345/206/263/347/255/226/347/240/224/350/256/250/350/247/204/345/210/231.md +49 -0
- package/templates/knowledge/rules//346/240/270/345/277/203/344/275/223/351/252/214/345/216/237/345/210/231.md +50 -0
- package/templates/knowledge/rules//346/240/270/345/277/203/345/267/245/347/250/213/346/211/247/350/241/214/345/216/237/345/210/231.md +35 -0
- package/templates/knowledge/rules//346/263/250/345/206/214/350/241/250/345/237/272/347/241/200/350/256/276/346/226/275/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//346/274/224/350/277/233/345/233/236/345/275/222/350/247/204/345/210/231.md +51 -0
- package/templates/knowledge/rules//346/274/224/350/277/233/345/233/236/345/275/222/351/227/250/346/216/247/350/247/204/345/210/231.md +74 -0
- package/templates/knowledge/rules//347/224/250/346/210/267/345/217/215/351/246/210/345/245/221/347/272/246/350/247/204/345/210/231.md +35 -0
- package/templates/knowledge/rules//347/237/245/350/257/206/346/263/250/345/205/245/350/276/271/347/225/214/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//347/237/245/350/257/206/350/265/204/344/272/247/346/262/273/347/220/206/350/247/204/345/210/231.md +61 -0
- package/templates/knowledge/rules//347/254/254/344/270/200/346/200/247/345/216/237/347/220/206/346/216/250/347/220/206/350/247/204/345/210/231.md +73 -0
- package/templates/knowledge/rules//347/273/206/350/212/202/347/272/252/345/276/213/350/247/204/345/210/231.md +67 -0
- package/templates/knowledge/rules//350/204/221/346/232/264/344/270/216/346/226/271/346/241/210/346/216/242/347/264/242/350/247/204/345/210/231.md +66 -0
- package/templates/knowledge/rules//350/256/241/345/210/222/345/211/215/347/275/256/351/227/250/350/247/204/345/210/231.md +59 -0
- package/templates/knowledge/rules//350/256/276/350/256/241/344/272/247/347/211/251/345/214/205/350/247/204/345/210/231.md +55 -0
- package/templates/knowledge/rules//350/257/201/346/215/256/351/251/261/345/212/250/344/270/216/345/217/215/345/271/273/350/247/211/350/247/204/345/210/231.md +75 -0
- package/templates/knowledge/rules//350/267/250/345/271/263/345/217/260/350/267/257/345/276/204/345/256/211/345/205/250/350/247/204/345/210/231.md +48 -0
- package/templates/knowledge/rules//350/276/223/345/205/245/346/235/220/346/226/231/345/245/221/347/272/246/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//351/205/215/347/275/256/344/274/230/345/205/210/347/272/247/350/247/204/345/210/231.md +35 -0
- package/templates/knowledge/rules//351/230/262/345/255/244/345/262/233/345/256/236/347/216/260/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//351/233/266/351/205/215/347/275/256/345/210/235/345/247/213/345/214/226/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/rules//351/252/214/350/257/201/345/245/221/347/272/246/350/247/204/345/210/231.md +36 -0
- package/templates/knowledge/templates//345/256/241/346/237/245/346/221/230/350/246/201.md +26 -7
- package/templates/patterns/API/350/256/276/350/256/241/350/247/204/350/214/203.md +30 -3
- package/templates/patterns/Docker/351/203/250/347/275/262/350/247/204/350/214/203.md +29 -3
- package/templates/patterns/Git/346/223/215/344/275/234/350/247/204/350/214/203.md +33 -3
- package/templates/patterns/N/345/212/2401/346/237/245/350/257/242/350/247/204/350/214/203.md +31 -3
- package/templates/patterns/React/345/210/227/350/241/250/350/241/250/346/240/274/350/247/204/350/214/203.md +30 -3
- package/templates/patterns/React/346/216/245/345/217/243/351/233/206/346/210/220/350/247/204/350/214/203.md +31 -3
- package/templates/patterns/React/347/212/266/346/200/201/347/256/241/347/220/206/350/247/204/350/214/203.md +31 -3
- package/templates/patterns/React/347/273/204/344/273/266/350/247/204/350/214/203.md +30 -3
- package/templates/patterns/React/350/241/250/345/215/225/350/247/204/350/214/203.md +30 -3
- package/templates/patterns/React/350/267/257/347/224/261/350/247/204/350/214/203.md +31 -3
- package/templates/patterns/Schema/345/205/274/345/256/271/350/247/204/350/214/203.md +30 -3
- package/templates/patterns/Vue/347/212/266/346/200/201/347/256/241/347/220/206/350/247/204/350/214/203.md +29 -3
- package/templates/patterns/Vue/347/273/204/344/273/266/350/247/204/350/214/203.md +33 -3
- package/templates/patterns/Vue/350/267/257/347/224/261/350/247/204/350/214/203.md +28 -3
- package/templates/patterns//344/272/213/344/273/266/351/251/261/345/212/250/350/247/204/350/214/203.md +32 -3
- package/templates/patterns//344/272/213/345/212/241/346/250/241/345/274/217/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//344/274/230/351/233/205/345/201/234/346/234/272/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//345/205/250/346/240/210/346/265/201/347/250/213/344/277/256/345/244/215.md +30 -3
- package/templates/patterns//345/210/206/351/241/265/346/237/245/350/257/242/350/247/204/350/214/203.md +34 -3
- package/templates/patterns//345/211/215/347/253/257/346/200/247/350/203/275/350/247/204/350/214/203.md +32 -3
- package/templates/patterns//345/221/275/345/220/215/350/247/204/350/214/203.md +30 -3
- package/templates/patterns//345/233/275/351/231/205/345/214/226/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//345/242/236/345/210/240/346/224/271/346/237/245/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//345/244/226/351/203/250/344/276/235/350/265/226/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//345/245/221/347/272/246/345/205/274/345/256/271/350/247/204/350/214/203.md +28 -3
- package/templates/patterns//345/256/232/346/227/266/344/273/273/345/212/241/350/247/204/350/214/203.md +32 -3
- package/templates/patterns//345/256/236/346/227/266/346/216/250/351/200/201/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//345/267/245/347/250/213/347/272/252/345/276/213.md +30 -3
- package/templates/patterns//345/271/266/345/217/221/346/216/247/345/210/266/350/247/204/350/214/203.md +34 -3
- package/templates/patterns//345/274/202/346/255/245/345/257/274/345/207/272/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//346/216/245/345/217/243/345/245/221/347/272/246/350/247/204/350/214/203.md +29 -3
- package/templates/patterns//346/220/234/347/264/242/346/250/241/345/274/217/350/247/204/350/214/203.md +33 -3
- package/templates/patterns//346/225/260/346/215/256/351/232/220/347/247/201/350/247/204/350/214/203.md +34 -3
- package/templates/patterns//346/226/207/344/273/266/344/270/212/344/274/240/350/247/204/350/214/203.md +30 -3
- package/templates/patterns//346/227/240/351/232/234/347/242/215/350/247/204/350/214/203.md +30 -3
- package/templates/patterns//346/227/245/345/277/227/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//346/235/203/351/231/220/350/256/244/350/257/201/350/247/204/350/214/203.md +34 -3
- package/templates/patterns//346/236/266/346/236/204/347/272/242/347/272/277.md +28 -3
- package/templates/patterns//346/265/213/350/257/225/350/264/250/351/207/217/350/247/204/350/214/203.md +30 -3
- package/templates/patterns//347/206/224/346/226/255/351/231/215/347/272/247/350/247/204/350/214/203.md +32 -3
- package/templates/patterns//347/212/266/346/200/201/346/265/201/350/275/254/350/247/204/350/214/203.md +29 -3
- package/templates/patterns//347/272/246/346/235/237/345/256/236/347/216/260/350/247/204/350/214/203.md +32 -3
- package/templates/patterns//347/274/223/345/255/230/347/255/226/347/225/245/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//347/274/226/347/240/201/350/264/250/351/207/217/350/247/204/350/214/203.md +30 -3
- package/templates/patterns//347/274/272/351/231/267/347/256/241/347/220/206/350/247/204/350/214/203.md +29 -3
- package/templates/patterns//350/260/203/350/257/225/346/226/271/346/263/225/350/256/272.md +30 -3
- package/templates/patterns//350/276/223/345/205/245/346/240/241/351/252/214/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//351/224/231/350/257/257/345/244/204/347/220/206/350/247/204/350/214/203.md +31 -3
- package/templates/patterns//351/224/231/350/257/257/350/276/271/347/225/214/350/247/204/350/214/203.md +33 -3
- package/templates/patterns//351/242/206/345/237/237/351/251/261/345/212/250/350/256/276/350/256/241/350/247/204/350/214/203.md +30 -3
- package/dist/engine/batch1_manifest.d.ts.map +0 -1
- package/dist/engine/batch1_manifest.js.map +0 -1
- package/dist/engine/batch1_scenario_registry.d.ts.map +0 -1
- package/dist/engine/batch1_scenario_registry.js.map +0 -1
- package/dist/engine/batch1_scenario_runners.d.ts.map +0 -1
- package/dist/engine/batch1_scenario_runners.js.map +0 -1
package/dist/bin/soloforge.js
CHANGED
|
@@ -16,10 +16,11 @@ import { cmdConfigResolve, cmdConfigExplain, cmdConfigConfirm, cmdConfigUnset, l
|
|
|
16
16
|
import { resolveCurrentProjectConfigReports, validateConfigPrecedence, } from "../engine/config_precedence_contract.js";
|
|
17
17
|
import { isReadForbidden } from "../engine/privacy_secret_contract.js";
|
|
18
18
|
import { routeIntent } from "../engine/intent_router.js";
|
|
19
|
-
import { debugLog } from "../engine/
|
|
19
|
+
import { debugLog, debug, userInfo, userWarn, userError, internalWarn, jsonSafeError, initLoggerFromEnv } from "../engine/logger.js";
|
|
20
20
|
const command = process.argv[2];
|
|
21
21
|
const args = process.argv.slice(3);
|
|
22
22
|
async function main() {
|
|
23
|
+
initLoggerFromEnv();
|
|
23
24
|
switch (command) {
|
|
24
25
|
case "init":
|
|
25
26
|
if (args.includes("--auto")) {
|
|
@@ -59,8 +60,38 @@ async function main() {
|
|
|
59
60
|
case "audit-template-mechanisms":
|
|
60
61
|
await cmdAuditTemplateMechanisms();
|
|
61
62
|
break;
|
|
63
|
+
case "audit-design-artifacts":
|
|
64
|
+
await cmdAuditDesignArtifacts();
|
|
65
|
+
break;
|
|
66
|
+
case "upgrade-design-artifacts":
|
|
67
|
+
await cmdUpgradeDesignArtifacts();
|
|
68
|
+
break;
|
|
62
69
|
case "validate-batch1":
|
|
63
|
-
|
|
70
|
+
userWarn("⚠️ validate-batch1 是历史施工命令,不代表正式发布通过。请使用 validate-release。");
|
|
71
|
+
await cmdValidateFoundation();
|
|
72
|
+
break;
|
|
73
|
+
case "validate-batch3":
|
|
74
|
+
userWarn("⚠️ validate-batch3 是历史施工命令,不代表正式发布通过。请使用 validate-release。");
|
|
75
|
+
await cmdValidateKnowledge();
|
|
76
|
+
break;
|
|
77
|
+
case "validate-batch5":
|
|
78
|
+
userWarn("⚠️ validate-batch5 是历史施工命令,不代表正式发布通过。请使用 validate-release。");
|
|
79
|
+
await cmdValidateReleaseGate();
|
|
80
|
+
break;
|
|
81
|
+
case "validate-release":
|
|
82
|
+
await cmdValidateReleaseGate();
|
|
83
|
+
break;
|
|
84
|
+
case "sync-templates":
|
|
85
|
+
await cmdSyncTemplates();
|
|
86
|
+
break;
|
|
87
|
+
case "sync-adapters":
|
|
88
|
+
await cmdSyncAdapters();
|
|
89
|
+
break;
|
|
90
|
+
case "migrate":
|
|
91
|
+
await cmdMigrate();
|
|
92
|
+
break;
|
|
93
|
+
case "validate-new-issue":
|
|
94
|
+
await cmdValidateNewIssue();
|
|
64
95
|
break;
|
|
65
96
|
case "generate-trae":
|
|
66
97
|
await cmdGenerateTrae();
|
|
@@ -89,20 +120,23 @@ async function main() {
|
|
|
89
120
|
await cmdConfigUnset();
|
|
90
121
|
break;
|
|
91
122
|
default:
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
123
|
+
userInfo("用法: soloforge config <resolve|explain|confirm|unset> [options]");
|
|
124
|
+
userInfo("");
|
|
125
|
+
userInfo(" resolve 解析配置字段优先级(只读,显示所有候选来源)");
|
|
126
|
+
userInfo(" explain 解释指定字段的来源和优先级(只读,中文输出)");
|
|
127
|
+
userInfo(" confirm 确认配置字段值(写入 config + evidence)");
|
|
128
|
+
userInfo(" unset 移除指定字段的确认配置和 evidence");
|
|
98
129
|
}
|
|
99
130
|
break;
|
|
100
131
|
}
|
|
101
132
|
case "status":
|
|
102
133
|
await cmdStatus();
|
|
103
134
|
break;
|
|
135
|
+
case "cleanup":
|
|
136
|
+
await cmdCleanup();
|
|
137
|
+
break;
|
|
104
138
|
default:
|
|
105
|
-
|
|
139
|
+
userInfo(`SoloForge CLI
|
|
106
140
|
|
|
107
141
|
用法: soloforge <命令>
|
|
108
142
|
|
|
@@ -121,17 +155,27 @@ async function main() {
|
|
|
121
155
|
validate 验证项目配置和知识文件(config.yaml 可选,缺失时自动推断)
|
|
122
156
|
validate-mechanisms 验证双层机制承载模型完整性(模板层 + 机制层)
|
|
123
157
|
audit-template-mechanisms 扫描模板与机制注册表交叉校验(--json 输出完整报告,--changed-only 仅检查变更文件)
|
|
158
|
+
audit-design-artifacts 审计架构/数据库/API 设计产物包(只读,--json 输出报告)
|
|
159
|
+
upgrade-design-artifacts 生成存量设计资产升级计划(默认 dry-run,--apply --confirm 仅建立已归档迁移基线)
|
|
160
|
+
validate-release 验证发布门禁(契约、场景矩阵、消费 trace、双层机制、回归基线)
|
|
161
|
+
validate-batch1 [历史] 仅基础契约验证,不代表正式发布通过
|
|
162
|
+
validate-batch3 [历史] 仅知识模板验证,不代表正式发布通过
|
|
163
|
+
validate-batch5 [历史] 仅发布门禁验证,不代表正式发布通过
|
|
164
|
+
sync-templates 同步模板到项目(默认 dry-run,--apply 需 --confirm)
|
|
165
|
+
sync-adapters 同步适配器 Prompt(默认 dry-run,--apply 需 --confirm)
|
|
166
|
+
migrate 迁移项目 .soloforge/(默认 dry-run,--apply 需确认)
|
|
124
167
|
version 显示 SoloForge 版本信息
|
|
125
168
|
config resolve 解析配置字段优先级(只读)
|
|
126
169
|
config explain 解释配置字段来源(只读,中文)
|
|
127
170
|
config confirm <field> <value> 确认配置字段(写入 config + evidence)
|
|
128
171
|
config unset <field> 移除确认配置
|
|
129
172
|
status 显示当前项目的 SoloForge 状态
|
|
173
|
+
cleanup 清理过期任务和 evidence(默认 dry-run,--apply 执行实际清理)
|
|
130
174
|
`);
|
|
131
175
|
}
|
|
132
176
|
}
|
|
133
177
|
async function cmdInitAuto() {
|
|
134
|
-
|
|
178
|
+
debug("CLI", "执行 cmdInitAuto");
|
|
135
179
|
const dryRun = args.includes("--dry-run");
|
|
136
180
|
const projectPathArg = getArgValue("--project-path");
|
|
137
181
|
const projectPath = projectPathArg ? path.resolve(projectPathArg) : process.cwd();
|
|
@@ -142,50 +186,50 @@ async function cmdInitAuto() {
|
|
|
142
186
|
// 层 3: 字段级 evidence
|
|
143
187
|
const evidence = generateConfigEvidence(fp, draft, "auto");
|
|
144
188
|
// 展示探测结果 + evidence
|
|
145
|
-
|
|
146
|
-
|
|
189
|
+
userInfo("\nSoloForge 自动配置探测结果:");
|
|
190
|
+
userInfo("=".repeat(50));
|
|
147
191
|
for (const [key, field] of Object.entries(evidence.fields)) {
|
|
148
192
|
const icon = field.confidence === "high" ? "✅" : field.confidence === "medium" ? "⚠️" : "❓";
|
|
149
193
|
const valStr = typeof field.value === "object" ? JSON.stringify(field.value) : String(field.value);
|
|
150
|
-
|
|
151
|
-
|
|
194
|
+
userInfo(` ${icon} ${key}: ${valStr} (${field.confidence}, ${field.confidence_source})`);
|
|
195
|
+
userInfo(` 证据: ${field.evidence.join(", ")}`);
|
|
152
196
|
}
|
|
153
|
-
|
|
154
|
-
|
|
197
|
+
userInfo("=".repeat(50));
|
|
198
|
+
userInfo(`综合置信度: ${draft.confidence}`);
|
|
155
199
|
if (draft.advisory_notes.length > 0) {
|
|
156
|
-
|
|
200
|
+
userInfo("建议:");
|
|
157
201
|
for (const note of draft.advisory_notes) {
|
|
158
|
-
|
|
202
|
+
userInfo(` - ${note}`);
|
|
159
203
|
}
|
|
160
204
|
}
|
|
161
205
|
// Schema 校验 (advisory)
|
|
162
206
|
const validation = validateConfigDraft(draft);
|
|
163
207
|
if (validation.warnings.length > 0) {
|
|
164
|
-
|
|
208
|
+
userInfo("\nschema 建议:");
|
|
165
209
|
for (const w of validation.warnings) {
|
|
166
|
-
|
|
210
|
+
userInfo(` ⚠️ ${w}`);
|
|
167
211
|
}
|
|
168
212
|
}
|
|
169
213
|
if (!validation.valid) {
|
|
170
|
-
|
|
214
|
+
userInfo("\nschema 错误:");
|
|
171
215
|
for (const e of validation.errors) {
|
|
172
|
-
|
|
216
|
+
userInfo(` ❌ ${e}`);
|
|
173
217
|
}
|
|
174
|
-
|
|
218
|
+
userInfo("\n配置校验失败,请手动运行 `soloforge init --interactive`。");
|
|
175
219
|
return;
|
|
176
220
|
}
|
|
177
221
|
if (dryRun) {
|
|
178
|
-
|
|
222
|
+
userInfo("\n[dry-run] 不写入文件。使用不带 --dry-run 的命令执行写入。");
|
|
179
223
|
return;
|
|
180
224
|
}
|
|
181
225
|
// 写入门禁: 所有必要字段必须 high confidence + detected/user_declared/confirmed
|
|
182
226
|
const gate = canAutoWrite(evidence);
|
|
183
227
|
if (!gate.allowed) {
|
|
184
|
-
|
|
228
|
+
userInfo(`\n⚠️ 存在低/中置信度配置项,拒绝写入:`);
|
|
185
229
|
for (const f of gate.blockedFields) {
|
|
186
|
-
|
|
230
|
+
userInfo(` - ${f}`);
|
|
187
231
|
}
|
|
188
|
-
|
|
232
|
+
userInfo("请使用 `soloforge init --interactive` 或 `soloforge init --blueprint \"...\"` 生成配置。");
|
|
189
233
|
return;
|
|
190
234
|
}
|
|
191
235
|
// 写入配置 + evidence
|
|
@@ -245,9 +289,9 @@ function writeConfigWithEvidence(projectPath, draft, evidence) {
|
|
|
245
289
|
fss.writeFileSync(evidencePath, JSON.stringify(existing, null, 2), "utf-8");
|
|
246
290
|
}
|
|
247
291
|
catch (e) {
|
|
248
|
-
|
|
292
|
+
internalWarn("CLI", `更新 evidence 文件失败: ${e instanceof Error ? e.message : String(e)}`);
|
|
249
293
|
}
|
|
250
|
-
|
|
294
|
+
userInfo(`\n✅ .soloforge/config.yaml + config.evidence.json created`);
|
|
251
295
|
}
|
|
252
296
|
function hashConfigValue(str) {
|
|
253
297
|
return crypto.createHash("sha256").update(str).digest("hex").slice(0, 16);
|
|
@@ -261,18 +305,18 @@ function mapLegacySource(source) {
|
|
|
261
305
|
}
|
|
262
306
|
}
|
|
263
307
|
async function cmdInitBlueprint() {
|
|
264
|
-
|
|
308
|
+
debug("CLI", "执行 cmdInitBlueprint");
|
|
265
309
|
const blueprintText = getArgValue("--blueprint");
|
|
266
310
|
if (!blueprintText) {
|
|
267
|
-
|
|
311
|
+
userError("❌ --blueprint 需要提供描述文本,例如: soloforge init --blueprint \"Spring Boot + React 的 B2B 内部管理系统\"");
|
|
268
312
|
return;
|
|
269
313
|
}
|
|
270
314
|
const projectPathArg = getArgValue("--project-path");
|
|
271
315
|
const projectPath = projectPathArg ? path.resolve(projectPathArg) : process.cwd();
|
|
272
316
|
const parsed = parseBlueprint(blueprintText);
|
|
273
317
|
if (!parsed.parsed) {
|
|
274
|
-
|
|
275
|
-
|
|
318
|
+
userInfo("⚠️ 无法从蓝图文本解析技术栈,请使用 --interactive。");
|
|
319
|
+
userInfo("支持的框架关键词: Spring Boot, Go, Rust, Gradle, React, Vue, Angular, Next.js, Nuxt");
|
|
276
320
|
return;
|
|
277
321
|
}
|
|
278
322
|
// 从解析的蓝图构建草稿
|
|
@@ -335,7 +379,7 @@ function blueprintFrontendCommands(framework) {
|
|
|
335
379
|
}
|
|
336
380
|
}
|
|
337
381
|
async function cmdInit() {
|
|
338
|
-
|
|
382
|
+
debug("CLI", "执行 cmdInit");
|
|
339
383
|
const interactive = args.includes("--interactive");
|
|
340
384
|
const adapter = getArgValue("--adapter") || "claude-code";
|
|
341
385
|
const projectPathArg = getArgValue("--project-path");
|
|
@@ -368,7 +412,7 @@ async function cmdInit() {
|
|
|
368
412
|
writeConfigWithEvidence(projectPath, config.draft, config.evidence);
|
|
369
413
|
}
|
|
370
414
|
else if (!process.stdin.isTTY) {
|
|
371
|
-
|
|
415
|
+
userInfo("⚠️ interactive requires TTY. 请使用 --auto 或 --blueprint。");
|
|
372
416
|
}
|
|
373
417
|
}
|
|
374
418
|
// 生成 .mcp.json(SoloForge + Playwright)
|
|
@@ -389,7 +433,7 @@ async function cmdInit() {
|
|
|
389
433
|
},
|
|
390
434
|
};
|
|
391
435
|
fss.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
392
|
-
|
|
436
|
+
userInfo("✅ .mcp.json 已创建(soloforge + playwright)");
|
|
393
437
|
}
|
|
394
438
|
// 生成 hooks
|
|
395
439
|
await cmdGenerateHooks(projectPath);
|
|
@@ -399,7 +443,7 @@ async function cmdInit() {
|
|
|
399
443
|
// 生成 Trae IDE 配置
|
|
400
444
|
if (adapter === "trae" || adapter === "all") {
|
|
401
445
|
await cmdGenerateTraeInner(projectPath);
|
|
402
|
-
|
|
446
|
+
userInfo("💡 提示: 使用项目级 .trae/ 配置需在 Trae 中开启 beta flag");
|
|
403
447
|
}
|
|
404
448
|
// 生成 Codex App 配置
|
|
405
449
|
if (adapter === "codex" || adapter === "all") {
|
|
@@ -410,7 +454,7 @@ async function cmdInit() {
|
|
|
410
454
|
await copyKnowledgeTemplates(projectPath);
|
|
411
455
|
// 确保 .gitignore 包含必要条目
|
|
412
456
|
ensureGitignore(projectPath);
|
|
413
|
-
|
|
457
|
+
userInfo(`\n✅ SoloForge 初始化完成 (适配器: ${adapter})。${adapter === "trae" ? "请打开 Trae IDE 开始使用。" :
|
|
414
458
|
adapter === "codex" ? "请打开 Codex App 开始使用。" :
|
|
415
459
|
adapter === "all" ? "可在 Claude Code、Trae IDE 或 Codex App 中使用。" :
|
|
416
460
|
"请打开 Claude Code 开始使用。"}`);
|
|
@@ -421,14 +465,25 @@ async function copyGlobalPatterns(projectPath) {
|
|
|
421
465
|
const templatesDir = path.resolve(import.meta.dirname, "..", "..", "templates", "patterns");
|
|
422
466
|
if (fss.existsSync(templatesDir)) {
|
|
423
467
|
const files = fss.readdirSync(templatesDir).filter((f) => f.endsWith(".md"));
|
|
468
|
+
let copiedCount = 0;
|
|
469
|
+
let skippedCount = 0;
|
|
424
470
|
for (const f of files) {
|
|
425
471
|
const src = path.join(templatesDir, f);
|
|
426
472
|
const dest = path.join(globalDir, f);
|
|
427
473
|
if (!fss.existsSync(dest)) {
|
|
428
474
|
fss.copyFileSync(src, dest);
|
|
475
|
+
copiedCount++;
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
skippedCount++;
|
|
429
479
|
}
|
|
430
480
|
}
|
|
431
|
-
|
|
481
|
+
const parts = [];
|
|
482
|
+
if (copiedCount > 0)
|
|
483
|
+
parts.push(`新增 ${copiedCount} 个`);
|
|
484
|
+
if (skippedCount > 0)
|
|
485
|
+
parts.push(`跳过 ${skippedCount} 个(已存在)`);
|
|
486
|
+
userInfo(`✅ 全局模板 ~/.soloforge/patterns/: ${parts.length > 0 ? parts.join(",") : `${files.length} 个(已全部存在)`}`);
|
|
432
487
|
}
|
|
433
488
|
}
|
|
434
489
|
async function copyKnowledgeTemplates(projectPath) {
|
|
@@ -453,7 +508,7 @@ async function copyKnowledgeTemplates(projectPath) {
|
|
|
453
508
|
}
|
|
454
509
|
}
|
|
455
510
|
if (copiedCount > 0) {
|
|
456
|
-
|
|
511
|
+
userInfo(`✅ ${copiedCount} 个知识模板已复制到 .soloforge/knowledge/`);
|
|
457
512
|
}
|
|
458
513
|
}
|
|
459
514
|
}
|
|
@@ -468,7 +523,7 @@ async function generateAdapterConfigs(projectPath, adapter) {
|
|
|
468
523
|
},
|
|
469
524
|
};
|
|
470
525
|
fss.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
471
|
-
|
|
526
|
+
userInfo("✅ .mcp.json 已创建(soloforge + playwright)");
|
|
472
527
|
}
|
|
473
528
|
await cmdGenerateHooks(projectPath);
|
|
474
529
|
await cmdGenerateClaudeMdInner(projectPath);
|
|
@@ -486,7 +541,7 @@ function ensureGitignore(projectPath) {
|
|
|
486
541
|
if (missing.length > 0) {
|
|
487
542
|
const addition = (content.endsWith("\n") ? "" : "\n") + missing.join("\n") + "\n";
|
|
488
543
|
fss.appendFileSync(gitignorePath, addition, "utf-8");
|
|
489
|
-
|
|
544
|
+
userInfo(`✅ .gitignore 已更新: ${missing.join(", ")}`);
|
|
490
545
|
}
|
|
491
546
|
}
|
|
492
547
|
async function cmdGenerateHooks(projectPath) {
|
|
@@ -507,7 +562,7 @@ async function cmdGenerateHooks(projectPath) {
|
|
|
507
562
|
// 仅 merge hooks 字段,保留用户的 permissions/env 等设置
|
|
508
563
|
existing.hooks = hooksConfig.hooks;
|
|
509
564
|
fss.writeFileSync(settingsPath, JSON.stringify(existing, null, 2), "utf-8");
|
|
510
|
-
|
|
565
|
+
userInfo("✅ .claude/settings.json 已更新 hooks 配置");
|
|
511
566
|
}
|
|
512
567
|
async function cmdGenerateClaudeMd() {
|
|
513
568
|
await cmdGenerateClaudeMdInner(process.cwd());
|
|
@@ -524,16 +579,16 @@ async function cmdGenerateCodexInner(projectPath) {
|
|
|
524
579
|
fss.mkdirSync(codexDir, { recursive: true });
|
|
525
580
|
const tomlContent = generateCodexMcpConfig(projectPath);
|
|
526
581
|
fss.writeFileSync(path.join(codexDir, "config.toml"), tomlContent, "utf-8");
|
|
527
|
-
|
|
582
|
+
userInfo("✅ .codex/config.toml 已创建");
|
|
528
583
|
// 生成 .codex/hooks.json
|
|
529
584
|
const hooksContent = generateCodexHooksConfig();
|
|
530
585
|
fss.writeFileSync(path.join(codexDir, "hooks.json"), hooksContent, "utf-8");
|
|
531
|
-
|
|
586
|
+
userInfo("✅ .codex/hooks.json 已创建");
|
|
532
587
|
// 生成 AGENTS.md
|
|
533
588
|
const { config } = await resolveProjectConfig(projectPath);
|
|
534
589
|
const agentsContent = generateCodexAgentsMd(config);
|
|
535
590
|
fss.writeFileSync(path.join(projectPath, "AGENTS.md"), agentsContent, "utf-8");
|
|
536
|
-
|
|
591
|
+
userInfo("✅ AGENTS.md 已创建");
|
|
537
592
|
}
|
|
538
593
|
async function cmdGenerateTraeInner(projectPath) {
|
|
539
594
|
// 生成 .trae/mcp.json
|
|
@@ -542,20 +597,20 @@ async function cmdGenerateTraeInner(projectPath) {
|
|
|
542
597
|
const traeMcpPath = path.join(traeDir, "mcp.json");
|
|
543
598
|
const traeMcpConfig = generateTraeMcpConfig(projectPath);
|
|
544
599
|
fss.writeFileSync(traeMcpPath, JSON.stringify(traeMcpConfig, null, 2), "utf-8");
|
|
545
|
-
|
|
600
|
+
userInfo("✅ .trae/mcp.json created");
|
|
546
601
|
// 生成 .trae/rules/project_rules.md
|
|
547
602
|
const rulesDir = path.join(traeDir, "rules");
|
|
548
603
|
fss.mkdirSync(rulesDir, { recursive: true });
|
|
549
604
|
const { config } = await resolveProjectConfig(projectPath);
|
|
550
605
|
const rulesContent = generateTraeRules(config);
|
|
551
606
|
fss.writeFileSync(path.join(rulesDir, "project_rules.md"), rulesContent, "utf-8");
|
|
552
|
-
|
|
607
|
+
userInfo("✅ .trae/rules/project_rules.md created");
|
|
553
608
|
}
|
|
554
609
|
async function cmdGenerateClaudeMdInner(projectPath) {
|
|
555
610
|
const { config } = await resolveProjectConfig(projectPath);
|
|
556
611
|
const content = generateClaudeMd(config);
|
|
557
612
|
fss.writeFileSync(path.join(projectPath, "CLAUDE.md"), content, "utf-8");
|
|
558
|
-
|
|
613
|
+
userInfo("✅ CLAUDE.md created");
|
|
559
614
|
}
|
|
560
615
|
async function cmdCheckWrite() {
|
|
561
616
|
debugLog("CLI: 执行 cmdCheckWrite");
|
|
@@ -591,16 +646,24 @@ async function cmdCheckWrite() {
|
|
|
591
646
|
}
|
|
592
647
|
// 加载配置
|
|
593
648
|
const projectPath = resolveProjectPath();
|
|
594
|
-
const { config } = await resolveProjectConfig(projectPath);
|
|
649
|
+
const { config, source } = await resolveProjectConfig(projectPath);
|
|
595
650
|
// 从配置中收集所有允许路径
|
|
596
|
-
|
|
651
|
+
let allowedPaths = [
|
|
597
652
|
...(config.scope.backend || []),
|
|
598
653
|
...(config.scope.frontend || []),
|
|
599
654
|
...config.repos.flatMap((r) => r.scope || []),
|
|
600
655
|
].map((p) => path.resolve(projectPath, p));
|
|
656
|
+
if (source === "inferred" || allowedPaths.length === 0) {
|
|
657
|
+
allowedPaths = [...new Set([...allowedPaths, projectPath])];
|
|
658
|
+
}
|
|
601
659
|
// 使用 scope_controller 统一检查
|
|
602
660
|
const { checkScope } = await import("../engine/scope_controller.js");
|
|
603
|
-
const
|
|
661
|
+
const rawTargetFilePath = path.isAbsolute(filePath) ? filePath : path.resolve(projectPath, filePath);
|
|
662
|
+
const projectRealPath = fss.realpathSync(projectPath);
|
|
663
|
+
const targetFilePath = rawTargetFilePath === projectPath || rawTargetFilePath.startsWith(projectPath + path.sep)
|
|
664
|
+
? path.join(projectRealPath, path.relative(projectPath, rawTargetFilePath))
|
|
665
|
+
: rawTargetFilePath;
|
|
666
|
+
const result = checkScope(targetFilePath, allowedPaths, content || undefined);
|
|
604
667
|
// 隐私/秘密契约:禁止读取的模式
|
|
605
668
|
if (isReadForbidden(filePath)) {
|
|
606
669
|
process.stdout.write(JSON.stringify({
|
|
@@ -624,12 +687,37 @@ async function cmdCheckWrite() {
|
|
|
624
687
|
process.exit(0);
|
|
625
688
|
}
|
|
626
689
|
if (result.severity === "warning") {
|
|
627
|
-
|
|
690
|
+
jsonSafeError(JSON.stringify(result));
|
|
691
|
+
}
|
|
692
|
+
// 问题六十二: Claude Code 直接 Edit/Write 也必须遵守设计产物就绪门。
|
|
693
|
+
// 设计资产本身允许继续修订;非设计文件在产物包复验通过前禁止写入。
|
|
694
|
+
const relativeFilePath = path.relative(projectRealPath, targetFilePath).replaceAll(path.sep, "/");
|
|
695
|
+
const isDesignArtifactFile = /^docs\/architecture\//.test(relativeFilePath) ||
|
|
696
|
+
/^docs\/api\/openapi\.(?:ya?ml|json)$/.test(relativeFilePath) ||
|
|
697
|
+
/^db\/(?:migrations|schema)\//.test(relativeFilePath);
|
|
698
|
+
if (!isDesignArtifactFile) {
|
|
699
|
+
const { TaskContextManager } = await import("../engine/task_context.js");
|
|
700
|
+
const stateDir = path.join(projectPath, ".soloforge", "state");
|
|
701
|
+
if (fss.existsSync(stateDir)) {
|
|
702
|
+
const manager = new TaskContextManager(stateDir);
|
|
703
|
+
const currentTask = await manager.getCurrentTask();
|
|
704
|
+
const designPack = currentTask?.design_artifact_pack;
|
|
705
|
+
if (designPack && designPack.status !== "implementation_ready") {
|
|
706
|
+
process.stdout.write(JSON.stringify({
|
|
707
|
+
hookSpecificOutput: {
|
|
708
|
+
hookEventName: "PreToolUse",
|
|
709
|
+
permissionDecision: "deny",
|
|
710
|
+
permissionDecisionReason: `设计产物包状态为 ${designPack.status},请先完善 docs/architecture、docs/api/openapi 或 db/migrations|schema 并通过复验,再写入业务实现`,
|
|
711
|
+
},
|
|
712
|
+
}));
|
|
713
|
+
process.exit(0);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
628
716
|
}
|
|
629
717
|
process.exit(0); // 允许
|
|
630
718
|
}
|
|
631
719
|
catch (e) {
|
|
632
|
-
|
|
720
|
+
userError(`SoloForge 写入检查错误: ${e instanceof Error ? e.message : String(e)}`);
|
|
633
721
|
process.exit(1);
|
|
634
722
|
}
|
|
635
723
|
}
|
|
@@ -639,16 +727,20 @@ function resolveProjectPath() {
|
|
|
639
727
|
try {
|
|
640
728
|
const stat = fss.statSync(envPath);
|
|
641
729
|
if (!stat.isDirectory()) {
|
|
642
|
-
|
|
730
|
+
userWarn(`⚠️ SOLOFORGE_PROJECT (${envPath}) 不是目录,回退到 cwd`);
|
|
643
731
|
return process.cwd();
|
|
644
732
|
}
|
|
645
733
|
return envPath;
|
|
646
734
|
}
|
|
647
735
|
catch {
|
|
648
|
-
|
|
736
|
+
userWarn(`⚠️ SOLOFORGE_PROJECT (${envPath}) 路径不存在,回退到 cwd`);
|
|
649
737
|
return process.cwd();
|
|
650
738
|
}
|
|
651
739
|
}
|
|
740
|
+
const projectPathArg = getArgValue("--project-path");
|
|
741
|
+
if (projectPathArg) {
|
|
742
|
+
return path.resolve(projectPathArg);
|
|
743
|
+
}
|
|
652
744
|
return process.cwd();
|
|
653
745
|
}
|
|
654
746
|
async function cmdPostBash() {
|
|
@@ -699,12 +791,12 @@ async function cmdPrePrompt() {
|
|
|
699
791
|
}
|
|
700
792
|
}
|
|
701
793
|
catch (e) {
|
|
702
|
-
|
|
794
|
+
internalWarn("CLI", "pre-prompt hook 错误:", e);
|
|
703
795
|
}
|
|
704
796
|
process.exit(0);
|
|
705
797
|
}
|
|
706
798
|
async function checkEvidenceWarnings(projectPath) {
|
|
707
|
-
|
|
799
|
+
debug("CLI", "执行 checkEvidenceWarnings —", projectPath);
|
|
708
800
|
const warnings = [];
|
|
709
801
|
const configPath = path.join(projectPath, ".soloforge", "config.yaml");
|
|
710
802
|
const evidencePath = path.join(projectPath, ".soloforge", "config.evidence.json");
|
|
@@ -773,16 +865,16 @@ function getConfigFieldValue(config, key) {
|
|
|
773
865
|
return obj;
|
|
774
866
|
}
|
|
775
867
|
async function cmdValidate() {
|
|
776
|
-
|
|
777
|
-
const projectPath =
|
|
868
|
+
debug("CLI", "执行 cmdValidate");
|
|
869
|
+
const projectPath = resolveProjectPath();
|
|
778
870
|
try {
|
|
779
871
|
const { config, source } = await resolveProjectConfig(projectPath);
|
|
780
872
|
if (source === "inferred") {
|
|
781
|
-
|
|
782
|
-
|
|
873
|
+
userInfo("ℹ️ 未找到 .soloforge/config.yaml — 使用自动推断的配置。");
|
|
874
|
+
userInfo(" 运行 'soloforge init --auto' 可持久化。");
|
|
783
875
|
}
|
|
784
876
|
else {
|
|
785
|
-
|
|
877
|
+
userInfo("✅ config.yaml 有效");
|
|
786
878
|
}
|
|
787
879
|
// 使用共享函数验证配置优先级
|
|
788
880
|
let hasHardFail = false;
|
|
@@ -793,43 +885,122 @@ async function cmdValidate() {
|
|
|
793
885
|
const advisory = findings.filter(f => f.severity === "advisory");
|
|
794
886
|
if (hardFails.length > 0) {
|
|
795
887
|
hasHardFail = true;
|
|
796
|
-
|
|
888
|
+
userInfo(`❌ 配置优先级: ${hardFails.length} hard_fail`);
|
|
797
889
|
for (const f of hardFails) {
|
|
798
|
-
|
|
890
|
+
userInfo(` - [${f.rule}] ${f.field_path ?? "N/A"}: ${f.message}`);
|
|
799
891
|
}
|
|
800
892
|
}
|
|
801
893
|
if (advisory.length > 0) {
|
|
802
|
-
|
|
894
|
+
userInfo(`⚠️ 配置优先级: ${advisory.length} advisory`);
|
|
803
895
|
for (const f of advisory) {
|
|
804
|
-
|
|
896
|
+
userInfo(` - [${f.rule}] ${f.field_path ?? "N/A"}: ${f.message}`);
|
|
805
897
|
}
|
|
806
898
|
}
|
|
807
899
|
if (hardFails.length === 0 && advisory.length === 0) {
|
|
808
|
-
|
|
900
|
+
userInfo("✅ 配置优先级验证通过");
|
|
809
901
|
}
|
|
810
902
|
}
|
|
811
903
|
catch { }
|
|
812
904
|
// Evidence 检查
|
|
813
905
|
const evidenceWarnings = await checkEvidenceWarnings(projectPath);
|
|
814
906
|
for (const w of evidenceWarnings) {
|
|
815
|
-
|
|
907
|
+
userInfo(`⚠️ evidence: ${w}`);
|
|
816
908
|
}
|
|
817
909
|
// 检查知识文件
|
|
818
910
|
const knowledgeDir = getProjectKnowledgeDir(config);
|
|
819
911
|
if (fss.existsSync(knowledgeDir)) {
|
|
820
912
|
const { KnowledgeIndexManager } = await import("../knowledge/index_manager.js");
|
|
821
|
-
const index = new KnowledgeIndexManager(config);
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
913
|
+
const index = new KnowledgeIndexManager(config, { watch: false });
|
|
914
|
+
try {
|
|
915
|
+
await index.build();
|
|
916
|
+
const entries = index.getAllEntries();
|
|
917
|
+
userInfo(`✅ ${entries.project.length} 条项目知识已索引`);
|
|
918
|
+
const issues = await index.checkHealth();
|
|
919
|
+
if (issues.length > 0) {
|
|
920
|
+
userInfo(`⚠️ ${issues.length} 个健康问题:`);
|
|
921
|
+
for (const { entry, issue } of issues) {
|
|
922
|
+
userInfo(` - ${entry.name}: ${issue}`);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
finally {
|
|
927
|
+
await index.close();
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
// 扩展清单校验 (problem-39: validateExtensionManifest)
|
|
931
|
+
try {
|
|
932
|
+
const { validateExtensionManifest } = await import("../engine/extension_contract.js");
|
|
933
|
+
const extResult = validateExtensionManifest({ extension_id: "soloforge-cli-validate", name: "SoloForge CLI 验证", version: "1.0.0", provider: "soloforge", extension_type: "workflow", contract_ids: [], capability_ids: [], permissions: ["read_project"], entrypoints: [], outputs: [], default_state: "disabled", compatibility: { min_soloforge_version: "1.0.0" } }, { extension_id: "soloforge-cli-validate", claimed_capabilities: [], claimed_enforcement: "advisory", third_party: false });
|
|
934
|
+
if (extResult.violations.length > 0) {
|
|
935
|
+
userInfo(" ✗ 扩展清单校验失败:");
|
|
936
|
+
for (const v of extResult.violations)
|
|
937
|
+
userInfo(` - ${v}`);
|
|
938
|
+
hasHardFail = true;
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
userInfo(" ✓ 扩展清单校验通过");
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
catch (e) {
|
|
945
|
+
userInfo(` ⚠ 扩展清单校验异常: ${e instanceof Error ? e.message : String(e)}`);
|
|
946
|
+
}
|
|
947
|
+
// 平台兼容性检查 (problem-40: normalizePathRef via generatePlatformReport)
|
|
948
|
+
try {
|
|
949
|
+
const { generatePlatformReport } = await import("../engine/platform_context.js");
|
|
950
|
+
const platform = {
|
|
951
|
+
os: process.platform,
|
|
952
|
+
arch: process.arch,
|
|
953
|
+
shell: (process.env.SHELL?.includes("zsh") ? "zsh" : process.env.SHELL?.includes("fish") ? "fish" : "bash"),
|
|
954
|
+
path_case_sensitive: process.platform !== "darwin" && process.platform !== "win32",
|
|
955
|
+
path_separator: process.platform === "win32" ? "\\" : "/",
|
|
956
|
+
line_ending: process.platform === "win32" ? "crlf" : "lf",
|
|
957
|
+
supports_symlink: process.platform !== "win32",
|
|
958
|
+
workspace_realpath: projectPath,
|
|
959
|
+
};
|
|
960
|
+
const platformReport = generatePlatformReport(platform, ["package.json", "tsconfig.json"], process.cwd());
|
|
961
|
+
if (platformReport.platform_compatibility_status === "blocked") {
|
|
962
|
+
userInfo(` ✗ 平台兼容性阻断: ${platformReport.issues_found.join(", ")}`);
|
|
963
|
+
hasHardFail = true;
|
|
964
|
+
}
|
|
965
|
+
else {
|
|
966
|
+
userInfo(` ✓ 平台兼容性检查: ${platformReport.platform_compatibility_status}`);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
catch (e) {
|
|
970
|
+
userInfo(` ⚠ 平台兼容性检查异常: ${e instanceof Error ? e.message : String(e)}`);
|
|
971
|
+
}
|
|
972
|
+
// README 命令漂移检测 (problem-30: detectReadmeDrift via validateUserPromise)
|
|
973
|
+
try {
|
|
974
|
+
const { validateUserPromise, getCliCommandContracts } = await import("../engine/user_promise.js");
|
|
975
|
+
const { extractReadmeCommands } = await import("../engine/knowledge_scenario_registry.js");
|
|
976
|
+
const fs = await import("node:fs");
|
|
977
|
+
const pathMod = await import("node:path");
|
|
978
|
+
const readmePath = pathMod.join(projectPath, "README.md");
|
|
979
|
+
if (fs.existsSync(readmePath)) {
|
|
980
|
+
const readmeContent = fs.readFileSync(readmePath, "utf-8");
|
|
981
|
+
const readmeCommands = extractReadmeCommands(readmeContent);
|
|
982
|
+
const promiseResult = validateUserPromise(readmeCommands, getCliCommandContracts());
|
|
983
|
+
const hardFails = promiseResult.findings.filter(f => f.severity === "hard_fail");
|
|
984
|
+
const warnings = promiseResult.findings.filter(f => f.severity === "warning");
|
|
985
|
+
if (hardFails.length > 0) {
|
|
986
|
+
userInfo(" ✗ README 命令漂移:");
|
|
987
|
+
for (const hf of hardFails)
|
|
988
|
+
userInfo(` - ${hf.message_zh}`);
|
|
989
|
+
hasHardFail = true;
|
|
990
|
+
}
|
|
991
|
+
else if (warnings.length > 0) {
|
|
992
|
+
userInfo(" ⚠ README 命令漂移警告:");
|
|
993
|
+
for (const w of warnings)
|
|
994
|
+
userInfo(` - ${w.message_zh}`);
|
|
995
|
+
}
|
|
996
|
+
else {
|
|
997
|
+
userInfo(" ✓ README 命令一致性检查通过");
|
|
830
998
|
}
|
|
831
999
|
}
|
|
832
1000
|
}
|
|
1001
|
+
catch (e) {
|
|
1002
|
+
userInfo(` ⚠ README 命令漂移检测异常: ${e instanceof Error ? e.message : String(e)}`);
|
|
1003
|
+
}
|
|
833
1004
|
// 双层机制验证 (仅限 SoloForge 自身源码目录)
|
|
834
1005
|
if (fss.existsSync(path.join(projectPath, "src", "engine", "dual_layer_mechanism_registry.ts"))) {
|
|
835
1006
|
const { validateMechanismLayerMaps } = await import("../engine/dual_layer_mechanism_registry.js");
|
|
@@ -837,29 +1008,78 @@ async function cmdValidate() {
|
|
|
837
1008
|
const dlHard = dlFindings.filter((f) => f.severity === "hard_fail");
|
|
838
1009
|
const dlAdvisory = dlFindings.filter((f) => f.severity === "advisory");
|
|
839
1010
|
if (dlHard.length > 0) {
|
|
840
|
-
|
|
1011
|
+
userInfo(`❌ 双层机制验证: ${dlHard.length} hard_fail`);
|
|
841
1012
|
for (const f of dlHard) {
|
|
842
|
-
|
|
1013
|
+
userInfo(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
|
|
843
1014
|
}
|
|
844
|
-
|
|
1015
|
+
userError(`❌ validate 失败: 双层机制存在 ${dlHard.length} hard_fail`);
|
|
845
1016
|
process.exit(1);
|
|
846
1017
|
}
|
|
847
1018
|
else {
|
|
848
|
-
|
|
1019
|
+
userInfo(`✅ 双层机制验证: ${dlAdvisory.length} advisory, 0 hard_fail`);
|
|
1020
|
+
}
|
|
1021
|
+
// problem-34: 测试策略覆盖验证 — 从 contract_registry 真实元数据构建
|
|
1022
|
+
try {
|
|
1023
|
+
const { validateTestStrategy } = await import("../engine/test_strategy.js");
|
|
1024
|
+
const { getAllContracts } = await import("../engine/contract_registry.js");
|
|
1025
|
+
const enforcedContracts = getAllContracts().filter((c) => c.state === "enforced");
|
|
1026
|
+
let tsHardFail = false;
|
|
1027
|
+
let tsChecked = 0;
|
|
1028
|
+
let tsPending = 0;
|
|
1029
|
+
for (const c of enforcedContracts) {
|
|
1030
|
+
const hasTests = c.test_files && c.test_files.length > 0;
|
|
1031
|
+
const hasLifecycle = c.lifecycle_test_files && c.lifecycle_test_files.length > 0;
|
|
1032
|
+
if (!hasTests) {
|
|
1033
|
+
// enforced 契约无测试文件元数据 → hard_fail,不得用 required_test_types:[] 掩盖
|
|
1034
|
+
userInfo(`❌ 测试策略: ${c.contract_id} — enforced 契约缺少 test_files 元数据,无法验证覆盖`);
|
|
1035
|
+
tsHardFail = true;
|
|
1036
|
+
tsPending++;
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
1039
|
+
const coverage = {
|
|
1040
|
+
contract_id: c.contract_id,
|
|
1041
|
+
required_test_types: ["unit"],
|
|
1042
|
+
coverage_status: hasLifecycle ? "satisfied" : "partial",
|
|
1043
|
+
satisfied_types: ["unit"],
|
|
1044
|
+
missing_types: hasLifecycle ? [] : ["lifecycle"],
|
|
1045
|
+
test_files: c.test_files || [],
|
|
1046
|
+
has_lifecycle_test: hasLifecycle,
|
|
1047
|
+
has_must_fail_case: false,
|
|
1048
|
+
};
|
|
1049
|
+
const tsErrors = validateTestStrategy(c.contract_id, true, coverage);
|
|
1050
|
+
tsChecked++;
|
|
1051
|
+
for (const e of tsErrors) {
|
|
1052
|
+
if (e.severity === "hard_fail") {
|
|
1053
|
+
tsHardFail = true;
|
|
1054
|
+
userInfo(`❌ 测试策略: ${c.contract_id} — ${e.error}`);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
if (tsHardFail) {
|
|
1059
|
+
userError(`❌ 测试策略覆盖验证失败: ${tsChecked} 个已检查, ${tsPending} 个元数据缺失`);
|
|
1060
|
+
hasHardFail = true;
|
|
1061
|
+
}
|
|
1062
|
+
else {
|
|
1063
|
+
userInfo(`✅ 测试策略覆盖: 已检查 ${tsChecked} 个 enforced 契约`);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
catch (e) {
|
|
1067
|
+
userError(`❌ 测试策略验证异常: ${e.message}`);
|
|
1068
|
+
hasHardFail = true;
|
|
849
1069
|
}
|
|
850
1070
|
} // 双层机制检查结束
|
|
851
1071
|
if (hasHardFail) {
|
|
852
|
-
|
|
1072
|
+
userError("❌ validate 失败: 配置优先级存在 hard_fail");
|
|
853
1073
|
process.exit(1);
|
|
854
1074
|
}
|
|
855
1075
|
}
|
|
856
1076
|
catch (e) {
|
|
857
|
-
|
|
1077
|
+
userError(`❌ 验证失败: ${e.message}`);
|
|
858
1078
|
process.exit(1);
|
|
859
1079
|
}
|
|
860
1080
|
}
|
|
861
1081
|
async function cmdValidateMechanisms() {
|
|
862
|
-
|
|
1082
|
+
debug("CLI", "执行 cmdValidateMechanisms");
|
|
863
1083
|
// 从编译后的二进制位置推导根目录: dist/bin/soloforge.js -> 项目根
|
|
864
1084
|
const soloforgeRoot = path.resolve(import.meta.dirname, "..", "..");
|
|
865
1085
|
const projectPath = fss.existsSync(path.join(soloforgeRoot, "src", "engine"))
|
|
@@ -871,47 +1091,68 @@ async function cmdValidateMechanisms() {
|
|
|
871
1091
|
const hardFails = findings.filter((f) => f.severity === "hard_fail");
|
|
872
1092
|
const advisory = findings.filter((f) => f.severity === "advisory");
|
|
873
1093
|
if (findings.length === 0) {
|
|
874
|
-
|
|
1094
|
+
userInfo("✅ 所有双层机制映射验证通过,无发现。");
|
|
875
1095
|
process.exit(0);
|
|
876
1096
|
return;
|
|
877
1097
|
}
|
|
878
1098
|
if (advisory.length > 0) {
|
|
879
|
-
|
|
1099
|
+
userInfo(`⚠️ advisory findings (${advisory.length}):`);
|
|
880
1100
|
for (const f of advisory) {
|
|
881
|
-
|
|
1101
|
+
userInfo(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
|
|
882
1102
|
}
|
|
883
1103
|
}
|
|
884
1104
|
if (hardFails.length > 0) {
|
|
885
|
-
|
|
1105
|
+
userInfo(`❌ hard_fail findings (${hardFails.length}):`);
|
|
886
1106
|
for (const f of hardFails) {
|
|
887
|
-
|
|
1107
|
+
userInfo(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
|
|
1108
|
+
}
|
|
1109
|
+
userInfo(`\n❌ 双层机制验证失败: ${hardFails.length} hard_fail`);
|
|
1110
|
+
process.exit(1);
|
|
1111
|
+
}
|
|
1112
|
+
userInfo(`\n✅ 双层机制验证通过,${advisory.length} advisory findings`);
|
|
1113
|
+
// problem-15: 机制族实现一致性验证
|
|
1114
|
+
try {
|
|
1115
|
+
const { validateMechanismFamilies } = await import("../engine/mechanism_family_registry.js");
|
|
1116
|
+
const familyFindings = validateMechanismFamilies();
|
|
1117
|
+
const familyHardFails = familyFindings.filter((f) => f.severity === "hard_fail");
|
|
1118
|
+
if (familyHardFails.length > 0) {
|
|
1119
|
+
userInfo(`\n❌ 机制族验证失败 (${familyHardFails.length} hard_fail):`);
|
|
1120
|
+
for (const f of familyHardFails)
|
|
1121
|
+
userInfo(` - ${f.mechanism_id}: ${f.message_zh}`);
|
|
1122
|
+
process.exit(1);
|
|
1123
|
+
}
|
|
1124
|
+
else if (familyFindings.length > 0) {
|
|
1125
|
+
userInfo(`\n📊 机制族验证: ${familyFindings.length} advisory`);
|
|
888
1126
|
}
|
|
889
|
-
|
|
1127
|
+
}
|
|
1128
|
+
catch (e) {
|
|
1129
|
+
userError(`❌ 机制族验证异常: ${e.message}`);
|
|
890
1130
|
process.exit(1);
|
|
891
1131
|
}
|
|
892
|
-
console.log(`\n✅ 双层机制验证通过,${advisory.length} advisory findings`);
|
|
893
1132
|
// 审计摘要
|
|
894
1133
|
try {
|
|
895
1134
|
const { auditTemplateMechanisms } = await import("../engine/template_mechanism_auditor.js");
|
|
896
1135
|
const audit = auditTemplateMechanisms(projectPath);
|
|
897
1136
|
if (audit.hard_fail_count > 0) {
|
|
898
|
-
|
|
1137
|
+
userInfo(`\n❌ 模板审计摘要: ${audit.hard_fail_count} hard_fail, ${audit.unmapped_template_assets.length} unmapped`);
|
|
1138
|
+
process.exit(1);
|
|
899
1139
|
}
|
|
900
1140
|
else {
|
|
901
|
-
|
|
1141
|
+
userInfo(`\n📊 模板审计: ${audit.total_template_files} 文件, ${audit.unmapped_template_assets.length} unmapped, ${audit.advisory_count} advisory`);
|
|
902
1142
|
}
|
|
903
1143
|
}
|
|
904
|
-
catch {
|
|
905
|
-
|
|
1144
|
+
catch (e) {
|
|
1145
|
+
userError(`❌ 模板审计异常: ${e.message}`);
|
|
1146
|
+
process.exit(1);
|
|
906
1147
|
}
|
|
907
1148
|
}
|
|
908
1149
|
catch (e) {
|
|
909
|
-
|
|
1150
|
+
userError(`❌ validate-mechanisms 失败: ${e.message}`);
|
|
910
1151
|
process.exit(1);
|
|
911
1152
|
}
|
|
912
1153
|
}
|
|
913
1154
|
async function cmdAuditTemplateMechanisms() {
|
|
914
|
-
|
|
1155
|
+
debug("CLI", "执行 cmdAuditTemplateMechanisms");
|
|
915
1156
|
const asJson = args.includes("--json");
|
|
916
1157
|
const changedOnly = args.includes("--changed-only");
|
|
917
1158
|
// 从编译后的二进制位置推导根目录
|
|
@@ -923,108 +1164,718 @@ async function cmdAuditTemplateMechanisms() {
|
|
|
923
1164
|
const { auditTemplateMechanisms } = await import("../engine/template_mechanism_auditor.js");
|
|
924
1165
|
const report = auditTemplateMechanisms(projectPath);
|
|
925
1166
|
if (asJson) {
|
|
926
|
-
|
|
1167
|
+
userInfo(JSON.stringify(report, null, 2));
|
|
927
1168
|
if (report.hard_fail_count > 0) {
|
|
928
1169
|
process.exit(1);
|
|
929
1170
|
}
|
|
930
1171
|
return;
|
|
931
1172
|
}
|
|
932
1173
|
// 人类可读输出
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1174
|
+
userInfo(`模板-机制审计报告 (${report.generated_at})`);
|
|
1175
|
+
userInfo(` 模板文件: ${report.total_template_files}`);
|
|
1176
|
+
userInfo(` 注册资产: ${report.total_registered_assets}`);
|
|
1177
|
+
userInfo(` 机制总数: ${report.total_mechanisms}`);
|
|
1178
|
+
userInfo("");
|
|
938
1179
|
if (report.unmapped_template_assets.length > 0) {
|
|
939
|
-
|
|
1180
|
+
userInfo(`⚠️ 未注册模板 (${report.unmapped_template_assets.length}):`);
|
|
940
1181
|
for (const u of report.unmapped_template_assets) {
|
|
941
|
-
|
|
1182
|
+
userInfo(` - ${u.path}`);
|
|
942
1183
|
}
|
|
943
1184
|
}
|
|
944
1185
|
if (report.unconsumed_template_assets.length > 0) {
|
|
945
|
-
|
|
1186
|
+
userInfo(`⚠️ 未消费资产 (${report.unconsumed_template_assets.length}):`);
|
|
946
1187
|
for (const u of report.unconsumed_template_assets) {
|
|
947
|
-
|
|
1188
|
+
userInfo(` - ${u.path} (mode=${u.consumption_mode})`);
|
|
948
1189
|
}
|
|
949
1190
|
}
|
|
950
1191
|
if (report.code_only_mechanisms.length > 0) {
|
|
951
|
-
|
|
1192
|
+
userInfo(`⚠️ 仅代码机制 (无模板层):`);
|
|
952
1193
|
for (const m of report.code_only_mechanisms) {
|
|
953
|
-
|
|
1194
|
+
userInfo(` - ${m.mechanism_id} (${m.priority}, ${m.status})`);
|
|
954
1195
|
}
|
|
955
1196
|
}
|
|
956
1197
|
if (report.template_only_mechanisms.length > 0) {
|
|
957
|
-
|
|
1198
|
+
userInfo(`⚠️ 仅模板机制 (无代码层):`);
|
|
958
1199
|
for (const m of report.template_only_mechanisms) {
|
|
959
|
-
|
|
1200
|
+
userInfo(` - ${m.mechanism_id} (${m.priority}, ${m.status})`);
|
|
960
1201
|
}
|
|
961
1202
|
}
|
|
962
1203
|
if (report.required_assets_without_enforcer.length > 0) {
|
|
963
|
-
|
|
1204
|
+
userInfo(`❌ Required 资产无 enforcer (${report.required_assets_without_enforcer.length}):`);
|
|
964
1205
|
for (const r of report.required_assets_without_enforcer) {
|
|
965
|
-
|
|
1206
|
+
userInfo(` - ${r.path} (mechanism=${r.owner_mechanism_id})`);
|
|
966
1207
|
}
|
|
967
1208
|
}
|
|
968
1209
|
if (report.overpromised_adapter_rules.length > 0) {
|
|
969
|
-
|
|
1210
|
+
userInfo(`❌ 适配器过度承诺 (${report.overpromised_adapter_rules.length}):`);
|
|
970
1211
|
for (const o of report.overpromised_adapter_rules) {
|
|
971
|
-
|
|
1212
|
+
userInfo(` - ${o.source_file}: ${o.promised_mechanism_id} (${o.promise_keywords.join(",")})`);
|
|
972
1213
|
}
|
|
973
1214
|
}
|
|
974
1215
|
if (report.deprecated_assets_injected.length > 0) {
|
|
975
|
-
|
|
1216
|
+
userInfo(`⚠️ Deprecated 资产仍被注入:`);
|
|
976
1217
|
for (const d of report.deprecated_assets_injected) {
|
|
977
|
-
|
|
1218
|
+
userInfo(` - ${d.path}`);
|
|
978
1219
|
}
|
|
979
1220
|
}
|
|
980
1221
|
if (report.template_mechanism_drift.length > 0) {
|
|
981
1222
|
const driftHard = report.template_mechanism_drift.filter((f) => f.severity === "hard_fail");
|
|
982
1223
|
const driftAdvisory = report.template_mechanism_drift.filter((f) => f.severity === "advisory");
|
|
983
1224
|
if (driftAdvisory.length > 0) {
|
|
984
|
-
|
|
1225
|
+
userInfo(`⚠️ 漂移 advisory (${driftAdvisory.length}):`);
|
|
985
1226
|
for (const f of driftAdvisory) {
|
|
986
|
-
|
|
1227
|
+
userInfo(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
|
|
987
1228
|
}
|
|
988
1229
|
}
|
|
989
1230
|
if (driftHard.length > 0) {
|
|
990
|
-
|
|
1231
|
+
userInfo(`❌ 漂移 hard_fail (${driftHard.length}):`);
|
|
991
1232
|
for (const f of driftHard) {
|
|
992
|
-
|
|
1233
|
+
userInfo(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
|
|
993
1234
|
}
|
|
994
1235
|
}
|
|
995
1236
|
}
|
|
996
|
-
|
|
1237
|
+
userInfo("");
|
|
997
1238
|
if (report.hard_fail_count > 0) {
|
|
998
|
-
|
|
999
|
-
process.exit(1);
|
|
1239
|
+
userInfo(`❌ 审计失败: ${report.hard_fail_count} hard_fail, ${report.advisory_count} advisory`);
|
|
1000
1240
|
}
|
|
1001
1241
|
else {
|
|
1002
|
-
|
|
1242
|
+
userInfo(`✅ 审计通过: 0 hard_fail, ${report.advisory_count} advisory`);
|
|
1243
|
+
}
|
|
1244
|
+
// problem-57: 知识资产 schema 审计
|
|
1245
|
+
try {
|
|
1246
|
+
const { auditKnowledgeAssets, parseAssetFile } = await import("../engine/knowledge_asset_audit.js");
|
|
1247
|
+
const knowledgeDirs = [
|
|
1248
|
+
path.join(projectPath, "templates", "knowledge", "procedures"),
|
|
1249
|
+
path.join(projectPath, "templates", "knowledge", "rules"),
|
|
1250
|
+
path.join(projectPath, "templates", "knowledge", "checklists"),
|
|
1251
|
+
path.join(projectPath, "templates", "knowledge", "acceptance_templates"),
|
|
1252
|
+
path.join(projectPath, "templates", "knowledge", "review_rules"),
|
|
1253
|
+
path.join(projectPath, "templates", "knowledge", "workflow_templates"),
|
|
1254
|
+
];
|
|
1255
|
+
const assets = [];
|
|
1256
|
+
for (const dir of knowledgeDirs) {
|
|
1257
|
+
if (!fss.existsSync(dir))
|
|
1258
|
+
continue;
|
|
1259
|
+
for (const entry of fss.readdirSync(dir).filter((f) => f.endsWith(".md"))) {
|
|
1260
|
+
const fp = path.join(dir, entry);
|
|
1261
|
+
const content = fss.readFileSync(fp, "utf-8");
|
|
1262
|
+
assets.push(parseAssetFile(fp, content));
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
if (assets.length > 0) {
|
|
1266
|
+
const kaReport = auditKnowledgeAssets(assets);
|
|
1267
|
+
userInfo("");
|
|
1268
|
+
userInfo("知识资产审计:");
|
|
1269
|
+
userInfo(` 资产数: ${kaReport.total_assets}`);
|
|
1270
|
+
userInfo(` 通过: ${kaReport.passed ? "✓" : "✗"}`);
|
|
1271
|
+
userInfo(` hard_fail: ${kaReport.hard_fail_count}, warning: ${kaReport.warning_count}`);
|
|
1272
|
+
for (const f of kaReport.findings) {
|
|
1273
|
+
const icon = f.severity === "hard_fail" ? "❌" : "⚠️";
|
|
1274
|
+
userInfo(` ${icon} ${f.asset_id ?? f.file_path}: ${f.detail} (${f.kind})`);
|
|
1275
|
+
}
|
|
1276
|
+
if (kaReport.hard_fail_count > 0) {
|
|
1277
|
+
userInfo(`❌ 知识资产审计有 ${kaReport.hard_fail_count} hard_fail`);
|
|
1278
|
+
process.exit(1);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
catch (e) {
|
|
1283
|
+
userError(`❌ 知识资产审计异常: ${e.message}`);
|
|
1284
|
+
process.exit(1);
|
|
1285
|
+
}
|
|
1286
|
+
if (report.hard_fail_count > 0) {
|
|
1287
|
+
process.exit(1);
|
|
1003
1288
|
}
|
|
1004
1289
|
}
|
|
1005
1290
|
catch (e) {
|
|
1006
|
-
|
|
1291
|
+
userError(`❌ audit-template-mechanisms 失败: ${e.message}`);
|
|
1292
|
+
process.exit(1);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
async function cmdAuditDesignArtifacts() {
|
|
1296
|
+
debug("CLI", "执行 cmdAuditDesignArtifacts");
|
|
1297
|
+
const isJson = args.includes("--json");
|
|
1298
|
+
const projectPath = resolveProjectPath();
|
|
1299
|
+
const { createDesignArtifactPack, verifyDesignArtifactPack } = await import("../engine/design_artifact_pack.js");
|
|
1300
|
+
const contract = createDesignArtifactPack("design-artifact-audit-cli");
|
|
1301
|
+
const result = verifyDesignArtifactPack(projectPath, contract);
|
|
1302
|
+
if (isJson) {
|
|
1303
|
+
userInfo(JSON.stringify({ command: "audit-design-artifacts", project_path: projectPath, ...result }, null, 2));
|
|
1304
|
+
}
|
|
1305
|
+
else {
|
|
1306
|
+
userInfo(`设计产物包审计: ${projectPath}`);
|
|
1307
|
+
userInfo(` 状态: ${result.status}`);
|
|
1308
|
+
userInfo(` 已检查文件: ${result.checked_files.length}`);
|
|
1309
|
+
userInfo(` hard_fail: ${result.findings.filter((finding) => finding.severity === "hard_fail").length}`);
|
|
1310
|
+
for (const finding of result.findings) {
|
|
1311
|
+
userInfo(` ${finding.severity === "hard_fail" ? "❌" : "⚠️"} [${finding.code}] ${finding.message_zh}`);
|
|
1312
|
+
}
|
|
1313
|
+
if (result.passed)
|
|
1314
|
+
userInfo("✅ 设计产物包复验通过,可作为后续实现输入");
|
|
1315
|
+
}
|
|
1316
|
+
if (!result.passed)
|
|
1317
|
+
process.exit(1);
|
|
1318
|
+
}
|
|
1319
|
+
/**
|
|
1320
|
+
* 存量设计资产升级只负责安全建立复验基线与归档原文。
|
|
1321
|
+
* 修正文档内容仍须经 AI 草案和用户确认后写入,再由 audit 命令真实复验。
|
|
1322
|
+
*/
|
|
1323
|
+
async function cmdUpgradeDesignArtifacts() {
|
|
1324
|
+
debug("CLI", "执行 cmdUpgradeDesignArtifacts");
|
|
1325
|
+
const apply = args.includes("--apply");
|
|
1326
|
+
const confirm = args.includes("--confirm");
|
|
1327
|
+
const isJson = args.includes("--json");
|
|
1328
|
+
const projectPath = resolveProjectPath();
|
|
1329
|
+
const { createDesignArtifactPack, verifyDesignArtifactPack } = await import("../engine/design_artifact_pack.js");
|
|
1330
|
+
const contract = createDesignArtifactPack("design-artifact-upgrade-cli");
|
|
1331
|
+
const audit = verifyDesignArtifactPack(projectPath, contract);
|
|
1332
|
+
const presentFiles = audit.checked_files.filter((relativePath) => fss.existsSync(path.join(projectPath, relativePath)));
|
|
1333
|
+
const output = {
|
|
1334
|
+
command: "upgrade-design-artifacts",
|
|
1335
|
+
mode: apply ? "apply" : "dry_run",
|
|
1336
|
+
status: audit.passed ? "implementation_ready" : "needs_revalidation",
|
|
1337
|
+
present_files: presentFiles,
|
|
1338
|
+
findings: audit.findings,
|
|
1339
|
+
next_steps: audit.passed
|
|
1340
|
+
? ["设计产物已符合当前标准,无需覆盖现有文件"]
|
|
1341
|
+
: ["保留原文归档", "基于 findings 生成修订草案", "用户确认后写入修订文档/OpenAPI/SQL", "重新执行 audit-design-artifacts"],
|
|
1342
|
+
};
|
|
1343
|
+
if (!apply) {
|
|
1344
|
+
if (isJson)
|
|
1345
|
+
userInfo(JSON.stringify(output, null, 2));
|
|
1346
|
+
else {
|
|
1347
|
+
userInfo("设计产物升级计划: dry-run(不会修改现有文档)");
|
|
1348
|
+
userInfo(` 当前状态: ${output.status}`);
|
|
1349
|
+
userInfo(` 已发现现有资产: ${presentFiles.length}`);
|
|
1350
|
+
userInfo(` 待修复项: ${audit.findings.length}`);
|
|
1351
|
+
userInfo(" 使用 --apply --confirm 仅归档现有基线并登记 needs_revalidation;修订内容仍须用户确认。");
|
|
1352
|
+
}
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
if (!confirm) {
|
|
1356
|
+
userError("❌ upgrade-design-artifacts --apply 必须同时提供 --confirm,禁止静默改写或归档现有设计文档");
|
|
1357
|
+
process.exit(1);
|
|
1358
|
+
}
|
|
1359
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
1360
|
+
const archiveDir = path.join(projectPath, ".soloforge", "design-artifacts", "archive", timestamp);
|
|
1361
|
+
fss.mkdirSync(archiveDir, { recursive: true });
|
|
1362
|
+
for (const relativePath of presentFiles) {
|
|
1363
|
+
const target = path.join(archiveDir, relativePath);
|
|
1364
|
+
fss.mkdirSync(path.dirname(target), { recursive: true });
|
|
1365
|
+
fss.copyFileSync(path.join(projectPath, relativePath), target);
|
|
1366
|
+
}
|
|
1367
|
+
const contractDir = path.join(projectPath, ".soloforge", "design-artifacts");
|
|
1368
|
+
fss.mkdirSync(contractDir, { recursive: true });
|
|
1369
|
+
fss.writeFileSync(path.join(contractDir, "upgrade-contract.json"), JSON.stringify({
|
|
1370
|
+
...contract,
|
|
1371
|
+
status: audit.passed ? "implementation_ready" : "needs_revalidation",
|
|
1372
|
+
baseline_hashes: audit.hashes,
|
|
1373
|
+
findings: audit.findings,
|
|
1374
|
+
verified_at: new Date().toISOString(),
|
|
1375
|
+
archive_dir: path.relative(projectPath, archiveDir),
|
|
1376
|
+
write_policy: "原文仅归档;修订文档须由用户确认后另行写入并重新复验",
|
|
1377
|
+
}, null, 2), "utf-8");
|
|
1378
|
+
const appliedOutput = { ...output, archive_dir: path.relative(projectPath, archiveDir), original_documents_overwritten: false };
|
|
1379
|
+
if (isJson)
|
|
1380
|
+
userInfo(JSON.stringify(appliedOutput, null, 2));
|
|
1381
|
+
else {
|
|
1382
|
+
userInfo(`✅ 已归档现有设计基线: ${appliedOutput.archive_dir}`);
|
|
1383
|
+
userInfo(" 未覆盖现有设计文档;请确认修订草案后重新执行复验。");
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
async function cmdValidateKnowledge() {
|
|
1387
|
+
debug("CLI", "执行 cmdValidateKnowledge");
|
|
1388
|
+
const { validateContractRegistry } = await import("../engine/contract_registry.js");
|
|
1389
|
+
const { listProblemsByBatch } = await import("../engine/implementation_roadmap_registry.js");
|
|
1390
|
+
const { runAllKnowledgeScenarios, extractReadmeCommands } = await import("../engine/knowledge_scenario_registry.js");
|
|
1391
|
+
const { listKnowledgeIssueDetailAcceptances, validateKnowledgeIssueDetailAcceptance, } = await import("../engine/knowledge_acceptance_registry.js");
|
|
1392
|
+
const isJson = args.includes("--json");
|
|
1393
|
+
const cwd = process.cwd();
|
|
1394
|
+
const fs = await import("node:fs");
|
|
1395
|
+
const pathModule = await import("node:path");
|
|
1396
|
+
// 收集项目文件集合
|
|
1397
|
+
const existingFiles = new Set();
|
|
1398
|
+
function walkDir(dir, prefix) {
|
|
1399
|
+
try {
|
|
1400
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
1401
|
+
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
1402
|
+
if (entry.isDirectory()) {
|
|
1403
|
+
walkDir(pathModule.join(dir, entry.name), rel);
|
|
1404
|
+
}
|
|
1405
|
+
else {
|
|
1406
|
+
existingFiles.add(rel);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
catch { /* 忽略不存在目录 */ }
|
|
1411
|
+
}
|
|
1412
|
+
walkDir(pathModule.join(cwd, "src"), "src");
|
|
1413
|
+
walkDir(pathModule.join(cwd, "tests"), "tests");
|
|
1414
|
+
// 验证契约注册表
|
|
1415
|
+
const contractFindings = validateContractRegistry(existingFiles);
|
|
1416
|
+
const hardFails = contractFindings.filter((f) => f.severity === "hard_fail");
|
|
1417
|
+
// 验证 知识模板问题状态
|
|
1418
|
+
const knowledgeProblems = listProblemsByBatch("batch-3");
|
|
1419
|
+
const allImplemented = knowledgeProblems.every((p) => p.status === "implemented_verified");
|
|
1420
|
+
// 读取真实 README 并提取命令
|
|
1421
|
+
let readmeCommands;
|
|
1422
|
+
try {
|
|
1423
|
+
const readmeContent = fs.readFileSync(pathModule.join(cwd, "README.md"), "utf-8");
|
|
1424
|
+
readmeCommands = extractReadmeCommands(readmeContent);
|
|
1425
|
+
}
|
|
1426
|
+
catch { /* README 不存在时跳过 */ }
|
|
1427
|
+
// 运行真实场景矩阵
|
|
1428
|
+
const scenarioResults = runAllKnowledgeScenarios(readmeCommands);
|
|
1429
|
+
const scenariosPass = scenarioResults.every((s) => s.status === "PASS");
|
|
1430
|
+
// 验证 IssueDetailAcceptance 注册表
|
|
1431
|
+
const acceptances = listKnowledgeIssueDetailAcceptances();
|
|
1432
|
+
const acceptanceFindings = acceptances.flatMap((a) => validateKnowledgeIssueDetailAcceptance(a));
|
|
1433
|
+
const acceptanceHardFails = acceptanceFindings.filter((f) => f.severity === "hard_fail");
|
|
1434
|
+
const result = {
|
|
1435
|
+
knowledge_problems: knowledgeProblems.length,
|
|
1436
|
+
all_implemented_verified: allImplemented,
|
|
1437
|
+
contract_hard_fails: hardFails.length,
|
|
1438
|
+
issue_acceptances: acceptances.length,
|
|
1439
|
+
acceptance_hard_fails: acceptanceHardFails.length,
|
|
1440
|
+
scenarios_pass: scenariosPass,
|
|
1441
|
+
scenario_results: scenarioResults.map((s) => ({
|
|
1442
|
+
scenario_id: s.scenario_id,
|
|
1443
|
+
scenario_name: s.scenario_name,
|
|
1444
|
+
status: s.status,
|
|
1445
|
+
evidence: s.evidence,
|
|
1446
|
+
failures: s.failures.length,
|
|
1447
|
+
})),
|
|
1448
|
+
};
|
|
1449
|
+
if (isJson) {
|
|
1450
|
+
userInfo(JSON.stringify(result, null, 2));
|
|
1451
|
+
}
|
|
1452
|
+
else {
|
|
1453
|
+
userInfo("═══ Batch 3 验证 ═══");
|
|
1454
|
+
userInfo(` 问题数: ${knowledgeProblems.length}`);
|
|
1455
|
+
userInfo(` 全部 implemented_verified: ${allImplemented ? "✓" : "✗"}`);
|
|
1456
|
+
userInfo(` 契约 hard_fail: ${hardFails.length}`);
|
|
1457
|
+
for (const f of hardFails) {
|
|
1458
|
+
userInfo(` ✗ ${f.contract_id}: ${f.message_zh}`);
|
|
1459
|
+
}
|
|
1460
|
+
userInfo(` IssueDetailAcceptance: ${acceptances.length} 条, hard_fail: ${acceptanceHardFails.length}`);
|
|
1461
|
+
for (const f of acceptanceHardFails) {
|
|
1462
|
+
userInfo(` ✗ ${f.issue_id}: ${f.message_zh}`);
|
|
1463
|
+
}
|
|
1464
|
+
userInfo(` 场景矩阵:`);
|
|
1465
|
+
for (const s of scenarioResults) {
|
|
1466
|
+
const icon = s.status === "PASS" ? "✓" : "✗";
|
|
1467
|
+
userInfo(` ${icon} ${s.scenario_id}: ${s.scenario_name} — ${s.status}`);
|
|
1468
|
+
for (const ev of s.evidence) {
|
|
1469
|
+
userInfo(` ✓ ${ev}`);
|
|
1470
|
+
}
|
|
1471
|
+
for (const fl of s.failures) {
|
|
1472
|
+
userInfo(` ✗ ${fl}`);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
const overallPass = allImplemented && hardFails.length === 0 && scenariosPass && acceptanceHardFails.length === 0;
|
|
1476
|
+
userInfo(overallPass ? "\n✅ Batch 3 验证通过" : "\n❌ Batch 3 验证失败");
|
|
1477
|
+
}
|
|
1478
|
+
const overallPass = allImplemented && hardFails.length === 0 && scenariosPass && acceptanceHardFails.length === 0;
|
|
1479
|
+
process.exit(overallPass ? 0 : 1);
|
|
1480
|
+
}
|
|
1481
|
+
async function cmdSyncTemplates() {
|
|
1482
|
+
debug("CLI", "执行 cmdSyncTemplates");
|
|
1483
|
+
const apply = args.includes("--apply");
|
|
1484
|
+
const confirm = args.includes("--confirm");
|
|
1485
|
+
const isJson = args.includes("--json");
|
|
1486
|
+
const { executeSync, validateSyncSafety, computeTemplateAssetVersions } = await import("../engine/template_sync.js");
|
|
1487
|
+
const { validateWorkflowTemplatePack, createWorkflowTemplatePackContract, createWorkflowTemplateEntry, createTemplateConsumptionEvidence, } = await import("../engine/workflow_template_pack.js");
|
|
1488
|
+
const { buildTemplateManifestFromSource, computeFileHashes, loadProjectManifest, saveProjectManifest, writeFileSyncRecursive, sha256Hex, hashFile, } = await import("../engine/template_manifest_io.js");
|
|
1489
|
+
const projectPath = process.cwd();
|
|
1490
|
+
const packageRoot = path.resolve(import.meta.dirname, "..", "..");
|
|
1491
|
+
const sourceDir = args.find((a) => a.startsWith("--source="))?.slice("--source=".length) ?? path.join(packageRoot, "templates");
|
|
1492
|
+
// 读取当前包版本
|
|
1493
|
+
let packageVersion = "0.0.0";
|
|
1494
|
+
try {
|
|
1495
|
+
const pkgJson = JSON.parse(fss.readFileSync(path.join(packageRoot, "package.json"), "utf-8"));
|
|
1496
|
+
packageVersion = pkgJson.version;
|
|
1497
|
+
}
|
|
1498
|
+
catch { /* 回退 */ }
|
|
1499
|
+
// 构建源清单(真实模板文件)
|
|
1500
|
+
const sourceManifest = buildTemplateManifestFromSource(sourceDir, packageVersion);
|
|
1501
|
+
// 加载已安装清单
|
|
1502
|
+
const installedManifest = loadProjectManifest(projectPath) ?? [];
|
|
1503
|
+
// 计算哈希(Map key 用相对路径,与 computeTemplateAssetVersions 查找键一致)
|
|
1504
|
+
const sourceHashes = new Map();
|
|
1505
|
+
for (const e of sourceManifest) {
|
|
1506
|
+
const h = hashFile(path.join(packageRoot, e.source_path));
|
|
1507
|
+
if (h !== null)
|
|
1508
|
+
sourceHashes.set(e.source_path, h);
|
|
1509
|
+
}
|
|
1510
|
+
const baseManifest = installedManifest.length > 0 ? installedManifest : sourceManifest;
|
|
1511
|
+
const currentHashes = new Map();
|
|
1512
|
+
for (const e of baseManifest) {
|
|
1513
|
+
const h = hashFile(path.join(projectPath, e.target_path));
|
|
1514
|
+
if (h !== null)
|
|
1515
|
+
currentHashes.set(e.target_path, h);
|
|
1516
|
+
}
|
|
1517
|
+
// 计算差异(首次安装用 sourceManifest 作为基准,全部为 missing)
|
|
1518
|
+
const assets = computeTemplateAssetVersions(baseManifest, currentHashes, sourceHashes);
|
|
1519
|
+
// problem-53: 工作流模板包完整性校验 — 用真实 manifest 数据构建 pack
|
|
1520
|
+
const wfPackEntries = sourceManifest
|
|
1521
|
+
.filter(e => e.asset_kind === "workflow_template")
|
|
1522
|
+
.map(e => createWorkflowTemplateEntry("architecture_design", e.target_path));
|
|
1523
|
+
const wfConsumptionEvidences = assets
|
|
1524
|
+
.filter(a => wfPackEntries.some(w => w.template_path === a.target_path))
|
|
1525
|
+
.map(a => createTemplateConsumptionEvidence(a.target_path));
|
|
1526
|
+
if (wfPackEntries.length > 0) {
|
|
1527
|
+
const wfPack = createWorkflowTemplatePackContract({
|
|
1528
|
+
workflows: wfPackEntries,
|
|
1529
|
+
mechanism_consumption_map: sourceManifest
|
|
1530
|
+
.filter(e => e.asset_kind === "workflow_template")
|
|
1531
|
+
.map(e => ({ template_path: e.target_path, consumed_mechanism_id: `mc-${e.asset_id}`, consumption_type: "route_trigger", evidence_required: true })),
|
|
1532
|
+
});
|
|
1533
|
+
const wfResult = validateWorkflowTemplatePack(wfPack, wfConsumptionEvidences);
|
|
1534
|
+
if (!wfResult.valid && !isJson) {
|
|
1535
|
+
userInfo(` ⚠ 工作流模板包校验: ${wfResult.violations.length} 个违规`);
|
|
1536
|
+
for (const v of wfResult.violations)
|
|
1537
|
+
userInfo(` - ${v}`);
|
|
1538
|
+
}
|
|
1539
|
+
if (!wfResult.valid && apply) {
|
|
1540
|
+
// 校验失败阻断 apply
|
|
1541
|
+
internalWarn("CLI", `工作流模板包校验失败,apply 已阻断。违规: ${wfResult.violations.join("; ")}`);
|
|
1542
|
+
process.exit(1);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
const safeCheck = validateSyncSafety(assets);
|
|
1546
|
+
const syncResult = executeSync({ dry_run: !apply, apply, confirm, project_path: projectPath, source_path: sourceDir }, assets, sourceManifest);
|
|
1547
|
+
// apply 模式:真实文件复制
|
|
1548
|
+
if (apply && confirm && syncResult.success && syncResult.backup_path) {
|
|
1549
|
+
const backupDir = syncResult.backup_path;
|
|
1550
|
+
fss.mkdirSync(backupDir, { recursive: true });
|
|
1551
|
+
const assetMap = new Map(assets.map((a) => [a.asset_id, a]));
|
|
1552
|
+
const updatedManifest = [...sourceManifest];
|
|
1553
|
+
for (const assetId of [...syncResult.report.added, ...syncResult.report.updated]) {
|
|
1554
|
+
const asset = assetMap.get(assetId);
|
|
1555
|
+
if (!asset)
|
|
1556
|
+
continue;
|
|
1557
|
+
const srcAbs = path.join(packageRoot, asset.source_path);
|
|
1558
|
+
const tgtAbs = path.join(projectPath, asset.target_path);
|
|
1559
|
+
// 备份已有文件
|
|
1560
|
+
if (fss.existsSync(tgtAbs)) {
|
|
1561
|
+
const backupFile = path.join(backupDir, path.basename(tgtAbs));
|
|
1562
|
+
fss.copyFileSync(tgtAbs, backupFile);
|
|
1563
|
+
}
|
|
1564
|
+
// 复制源文件到目标
|
|
1565
|
+
writeFileSyncRecursive(tgtAbs, fss.readFileSync(srcAbs));
|
|
1566
|
+
// 更新清单中的 installed_hash
|
|
1567
|
+
const idx = updatedManifest.findIndex((e) => e.asset_id === assetId);
|
|
1568
|
+
if (idx >= 0) {
|
|
1569
|
+
updatedManifest[idx] = {
|
|
1570
|
+
...updatedManifest[idx],
|
|
1571
|
+
installed_hash: asset.source_hash,
|
|
1572
|
+
installed_at: new Date().toISOString(),
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
// 持久化清单
|
|
1577
|
+
saveProjectManifest(projectPath, updatedManifest);
|
|
1578
|
+
}
|
|
1579
|
+
if (isJson) {
|
|
1580
|
+
userInfo(JSON.stringify({
|
|
1581
|
+
command: "sync-templates",
|
|
1582
|
+
mode: apply ? "apply" : "dry_run",
|
|
1583
|
+
total_assets: assets.length,
|
|
1584
|
+
safe: safeCheck.safe,
|
|
1585
|
+
result: syncResult.success,
|
|
1586
|
+
dry_run: syncResult.dry_run,
|
|
1587
|
+
report: syncResult.report,
|
|
1588
|
+
}, null, 2));
|
|
1589
|
+
}
|
|
1590
|
+
else {
|
|
1591
|
+
userInfo(apply ? "模板同步: apply 模式" : "模板同步: dry-run 模式(不写入文件)");
|
|
1592
|
+
userInfo(` 资产总数: ${assets.length}`);
|
|
1593
|
+
userInfo(` 安全检查: ${safeCheck.safe ? "✓" : "✗"}`);
|
|
1594
|
+
userInfo(` 结果: ${syncResult.success ? "成功" : "失败"}`);
|
|
1595
|
+
userInfo(` 新增: ${syncResult.report.added.length}`);
|
|
1596
|
+
userInfo(` 更新: ${syncResult.report.updated.length}`);
|
|
1597
|
+
userInfo(` 跳过(用户修改): ${syncResult.report.skipped_user_modified.length}`);
|
|
1598
|
+
userInfo(` 废弃: ${syncResult.report.deprecated.length}`);
|
|
1599
|
+
if (!apply)
|
|
1600
|
+
userInfo(" 使用 --apply --confirm 应用同步");
|
|
1601
|
+
}
|
|
1602
|
+
if (!syncResult.success)
|
|
1007
1603
|
process.exit(1);
|
|
1604
|
+
}
|
|
1605
|
+
async function cmdSyncAdapters() {
|
|
1606
|
+
debug("CLI", "执行 cmdSyncAdapters");
|
|
1607
|
+
const apply = args.includes("--apply");
|
|
1608
|
+
const confirm = args.includes("--confirm");
|
|
1609
|
+
const isJson = args.includes("--json");
|
|
1610
|
+
const { syncAdapterPrompts, validateAdapterPrompt, REQUIRED_ADAPTER_SECTIONS, } = await import("../engine/adapter_prompt_contract.js");
|
|
1611
|
+
const { writeFileSyncRecursive, sha256Hex, hashFile, } = await import("../engine/template_manifest_io.js");
|
|
1612
|
+
const projectPath = process.cwd();
|
|
1613
|
+
// 加载项目配置(回退到默认)
|
|
1614
|
+
let config;
|
|
1615
|
+
try {
|
|
1616
|
+
const resolved = await resolveProjectConfig(projectPath);
|
|
1617
|
+
config = resolved.config;
|
|
1618
|
+
}
|
|
1619
|
+
catch {
|
|
1620
|
+
config = {
|
|
1621
|
+
name: "default", tech_stack: { backend: { lang: "", framework: "", version: "" }, frontend: { lang: "", framework: "", version: "" } },
|
|
1622
|
+
product_profile: "general", repos: [], build_commands: { backend: {}, frontend: {} }, scope: { backend: [], frontend: [] },
|
|
1623
|
+
};
|
|
1624
|
+
}
|
|
1625
|
+
// 适配器生成器
|
|
1626
|
+
const { generateClaudeMd } = await import("../adapters/claude_code/claude_md.js");
|
|
1627
|
+
const { generateCodexAgentsMd } = await import("../adapters/codex/codex_rules.js");
|
|
1628
|
+
const { generateTraeRules } = await import("../adapters/trae/trae_rules.js");
|
|
1629
|
+
const sections = [...REQUIRED_ADAPTER_SECTIONS];
|
|
1630
|
+
// 适配器 installed hash 记录文件
|
|
1631
|
+
const ADAPTER_HASH_FILE = ".soloforge/adapter_hashes.json";
|
|
1632
|
+
// 加载已安装的适配器 hash 记录
|
|
1633
|
+
let installedAdapterHashes = {};
|
|
1634
|
+
try {
|
|
1635
|
+
const hashContent = fss.readFileSync(path.join(projectPath, ADAPTER_HASH_FILE), "utf-8");
|
|
1636
|
+
installedAdapterHashes = JSON.parse(hashContent);
|
|
1637
|
+
}
|
|
1638
|
+
catch { /* 首次无记录 */ }
|
|
1639
|
+
const adapterContracts = [
|
|
1640
|
+
{
|
|
1641
|
+
adapter_id: "claude-code", host_type: "claude_code",
|
|
1642
|
+
prompt_path: "CLAUDE.md",
|
|
1643
|
+
generated_from_contract_version: "1",
|
|
1644
|
+
required_sections: sections,
|
|
1645
|
+
forbidden_claims: [],
|
|
1646
|
+
sync_required: true,
|
|
1647
|
+
next_allowed_tools: ["sf_classify", "sf_expand", "sf_verify", "sf_learn", "sf_deliver", "sf_review"],
|
|
1648
|
+
},
|
|
1649
|
+
{
|
|
1650
|
+
adapter_id: "codex", host_type: "codex",
|
|
1651
|
+
prompt_path: "AGENTS.md",
|
|
1652
|
+
generated_from_contract_version: "1",
|
|
1653
|
+
required_sections: sections,
|
|
1654
|
+
forbidden_claims: [],
|
|
1655
|
+
sync_required: true,
|
|
1656
|
+
next_allowed_tools: ["sf_classify", "sf_expand", "sf_verify", "sf_learn"],
|
|
1657
|
+
},
|
|
1658
|
+
{
|
|
1659
|
+
adapter_id: "trae", host_type: "cursor",
|
|
1660
|
+
prompt_path: ".trae/rules/project_rules.md",
|
|
1661
|
+
generated_from_contract_version: "1",
|
|
1662
|
+
required_sections: sections,
|
|
1663
|
+
forbidden_claims: [],
|
|
1664
|
+
sync_required: true,
|
|
1665
|
+
next_allowed_tools: ["sf_classify", "sf_expand", "sf_verify", "sf_learn"],
|
|
1666
|
+
},
|
|
1667
|
+
];
|
|
1668
|
+
// 验证所有适配器
|
|
1669
|
+
const validations = syncAdapterPrompts(adapterContracts, { dry_run: !apply, apply, confirm });
|
|
1670
|
+
// 适配器内容生成
|
|
1671
|
+
const generators = {
|
|
1672
|
+
"claude-code": () => generateClaudeMd(config),
|
|
1673
|
+
"codex": () => generateCodexAgentsMd(config),
|
|
1674
|
+
"trae": () => generateTraeRules(config),
|
|
1675
|
+
};
|
|
1676
|
+
// apply 模式:写入合规的适配器文件
|
|
1677
|
+
const writtenFiles = [];
|
|
1678
|
+
const skippedFiles = [];
|
|
1679
|
+
if (apply && confirm) {
|
|
1680
|
+
const updatedHashes = { ...installedAdapterHashes };
|
|
1681
|
+
for (const contract of adapterContracts) {
|
|
1682
|
+
const validation = validations.find((v) => v.adapter_id === contract.adapter_id);
|
|
1683
|
+
if (!validation?.compliant) {
|
|
1684
|
+
skippedFiles.push(`${contract.adapter_id}: 不合规,跳过`);
|
|
1685
|
+
continue;
|
|
1686
|
+
}
|
|
1687
|
+
const targetPath = path.join(projectPath, contract.prompt_path);
|
|
1688
|
+
const generator = generators[contract.adapter_id];
|
|
1689
|
+
if (!generator)
|
|
1690
|
+
continue;
|
|
1691
|
+
const content = generator();
|
|
1692
|
+
const generatedHash = sha256Hex(content);
|
|
1693
|
+
// 用户修改检测:文件存在且 hash 与已安装 hash 不一致
|
|
1694
|
+
if (fss.existsSync(targetPath)) {
|
|
1695
|
+
const diskHash = hashFile(targetPath);
|
|
1696
|
+
const installedHash = installedAdapterHashes[contract.adapter_id];
|
|
1697
|
+
if (diskHash && installedHash && diskHash !== installedHash) {
|
|
1698
|
+
// 文件被用户修改,不得覆盖
|
|
1699
|
+
skippedFiles.push(`${contract.adapter_id}: 用户已修改,跳过`);
|
|
1700
|
+
continue;
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
// 首次安装或内容有变化:写入
|
|
1704
|
+
writeFileSyncRecursive(targetPath, content);
|
|
1705
|
+
writtenFiles.push(contract.prompt_path);
|
|
1706
|
+
updatedHashes[contract.adapter_id] = generatedHash;
|
|
1707
|
+
}
|
|
1708
|
+
// 持久化 hash 记录
|
|
1709
|
+
writeFileSyncRecursive(path.join(projectPath, ADAPTER_HASH_FILE), JSON.stringify(updatedHashes, null, 2));
|
|
1710
|
+
}
|
|
1711
|
+
if (isJson) {
|
|
1712
|
+
userInfo(JSON.stringify({
|
|
1713
|
+
command: "sync-adapters",
|
|
1714
|
+
mode: apply ? "apply" : "dry_run",
|
|
1715
|
+
adapter_count: adapterContracts.length,
|
|
1716
|
+
validations,
|
|
1717
|
+
written: writtenFiles,
|
|
1718
|
+
skipped: skippedFiles,
|
|
1719
|
+
}, null, 2));
|
|
1720
|
+
}
|
|
1721
|
+
else {
|
|
1722
|
+
userInfo(apply ? "适配器同步: apply 模式" : "适配器同步: dry-run 模式(不写入文件)");
|
|
1723
|
+
userInfo(` 适配器数量: ${adapterContracts.length}`);
|
|
1724
|
+
for (const v of validations) {
|
|
1725
|
+
const icon = v.compliant ? "✓" : "✗";
|
|
1726
|
+
userInfo(` ${icon} ${v.adapter_id}: ${v.compliant ? "合规" : "不合规"}`);
|
|
1727
|
+
for (const f of v.findings) {
|
|
1728
|
+
if (f.severity !== "info")
|
|
1729
|
+
userInfo(` ${f.severity === "critical" ? "✗" : "⚠"} ${f.message_zh}`);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
if (writtenFiles.length > 0) {
|
|
1733
|
+
userInfo(` 已写入: ${writtenFiles.join(", ")}`);
|
|
1734
|
+
}
|
|
1735
|
+
if (skippedFiles.length > 0) {
|
|
1736
|
+
userInfo(` 已跳过: ${skippedFiles.join("; ")}`);
|
|
1737
|
+
}
|
|
1738
|
+
if (!apply)
|
|
1739
|
+
userInfo(" 使用 --apply --confirm 应用同步");
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
async function cmdMigrate() {
|
|
1743
|
+
debug("CLI", "执行 cmdMigrate");
|
|
1744
|
+
const apply = args.includes("--apply");
|
|
1745
|
+
const confirm = args.includes("--confirm");
|
|
1746
|
+
const isJson = args.includes("--json");
|
|
1747
|
+
const { createMigrationPlan, getCurrentCompatibility, validateMigrationSafety, generateVersionFile } = await import("../engine/release_compatibility.js");
|
|
1748
|
+
const { loadProjectVersion, saveProjectVersion, writeFileSyncRecursive } = await import("../engine/template_manifest_io.js");
|
|
1749
|
+
const projectPath = process.cwd();
|
|
1750
|
+
const compat = getCurrentCompatibility();
|
|
1751
|
+
const toVersion = compat.package_version;
|
|
1752
|
+
// 读取项目已安装版本,不存在视为首次
|
|
1753
|
+
const installed = loadProjectVersion(projectPath);
|
|
1754
|
+
const fromVersion = installed?.soloforge_package_version ?? "0.0.0";
|
|
1755
|
+
// 版本相同,无需迁移
|
|
1756
|
+
if (fromVersion === toVersion) {
|
|
1757
|
+
if (isJson) {
|
|
1758
|
+
userInfo(JSON.stringify({
|
|
1759
|
+
command: "migrate",
|
|
1760
|
+
mode: "noop",
|
|
1761
|
+
success: true,
|
|
1762
|
+
dry_run: !apply,
|
|
1763
|
+
safe: true,
|
|
1764
|
+
message: `已是最新版本 ${toVersion}`,
|
|
1765
|
+
from_version: fromVersion,
|
|
1766
|
+
to_version: toVersion,
|
|
1767
|
+
}, null, 2));
|
|
1768
|
+
}
|
|
1769
|
+
else {
|
|
1770
|
+
userInfo(`项目迁移: 已是最新版本 ${toVersion}`);
|
|
1771
|
+
userInfo(` 当前版本: ${fromVersion}`);
|
|
1772
|
+
}
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1775
|
+
// 先生成真实迁移计划
|
|
1776
|
+
const plan = createMigrationPlan({ dry_run: !apply, apply, confirm, project_path: projectPath, from_version: fromVersion, to_version: toVersion }, compat);
|
|
1777
|
+
// 基于真实 plan 做安全检查
|
|
1778
|
+
const safetyCheck = validateMigrationSafety(plan.plan, apply, !!confirm);
|
|
1779
|
+
// apply --confirm 模式且安全通过时:创建备份 + 写入 version.json
|
|
1780
|
+
if (apply && confirm && plan.success && safetyCheck.safe && plan.backup_path) {
|
|
1781
|
+
const backupDir = path.join(projectPath, plan.backup_path);
|
|
1782
|
+
fss.mkdirSync(backupDir, { recursive: true });
|
|
1783
|
+
// 备份已有 version.json
|
|
1784
|
+
const versionPath = path.join(projectPath, ".soloforge/version.json");
|
|
1785
|
+
if (fss.existsSync(versionPath)) {
|
|
1786
|
+
fss.copyFileSync(versionPath, path.join(backupDir, "version.json"));
|
|
1787
|
+
}
|
|
1788
|
+
// 写入新版本文件
|
|
1789
|
+
const versionContent = generateVersionFile(toVersion, compat.contract_registry_version);
|
|
1790
|
+
// 合并 created_at(首次用新时间,升级保留原时间)
|
|
1791
|
+
if (installed?.created_at) {
|
|
1792
|
+
versionContent.created_at = installed.created_at;
|
|
1793
|
+
}
|
|
1794
|
+
saveProjectVersion(projectPath, versionContent);
|
|
1795
|
+
}
|
|
1796
|
+
const success = plan.success && safetyCheck.safe;
|
|
1797
|
+
if (isJson) {
|
|
1798
|
+
userInfo(JSON.stringify({
|
|
1799
|
+
command: "migrate",
|
|
1800
|
+
mode: apply ? "apply" : "dry_run",
|
|
1801
|
+
success,
|
|
1802
|
+
dry_run: plan.dry_run,
|
|
1803
|
+
safe: safetyCheck.safe,
|
|
1804
|
+
from_version: fromVersion,
|
|
1805
|
+
to_version: toVersion,
|
|
1806
|
+
plan: plan.plan,
|
|
1807
|
+
backup_path: plan.backup_path,
|
|
1808
|
+
}, null, 2));
|
|
1008
1809
|
}
|
|
1810
|
+
else {
|
|
1811
|
+
userInfo(apply ? "项目迁移: apply 模式" : "项目迁移: dry-run 模式(不写入文件)");
|
|
1812
|
+
userInfo(` 结果: ${success ? "成功" : "失败"}`);
|
|
1813
|
+
userInfo(` 从版本: ${fromVersion}`);
|
|
1814
|
+
userInfo(` 到版本: ${toVersion}`);
|
|
1815
|
+
userInfo(` 安全检查: ${safetyCheck.safe ? "✓" : "✗"}`);
|
|
1816
|
+
userInfo(` 需迁移: ${plan.plan.required_migrations.length}`);
|
|
1817
|
+
userInfo(` 自动应用: ${plan.plan.auto_applicable.length}`);
|
|
1818
|
+
userInfo(` 需人工: ${plan.plan.requires_human.length}`);
|
|
1819
|
+
if (!apply)
|
|
1820
|
+
userInfo(" 使用 --apply --confirm 执行迁移");
|
|
1821
|
+
}
|
|
1822
|
+
if (!success)
|
|
1823
|
+
process.exit(1);
|
|
1009
1824
|
}
|
|
1010
|
-
async function
|
|
1011
|
-
|
|
1825
|
+
async function cmdValidateReleaseGate() {
|
|
1826
|
+
const isJson = args.includes("--json");
|
|
1827
|
+
debug("CLI", "执行 cmdValidateReleaseGate");
|
|
1828
|
+
const { runReleaseReadinessGate } = await import("../engine/release_readiness_gate.js");
|
|
1829
|
+
const result = await runReleaseReadinessGate(process.cwd());
|
|
1830
|
+
if (isJson) {
|
|
1831
|
+
userInfo(JSON.stringify({
|
|
1832
|
+
passed: result.passed,
|
|
1833
|
+
hard_fail_count: result.hard_fail_count,
|
|
1834
|
+
hard_fails: result.hard_fails,
|
|
1835
|
+
phases: result.phases,
|
|
1836
|
+
}, null, 2));
|
|
1837
|
+
}
|
|
1838
|
+
else {
|
|
1839
|
+
userInfo("══════════════════════════════════════════════════════════════");
|
|
1840
|
+
userInfo(`发布结论: ${result.passed ? "PASS" : "FAIL"}`);
|
|
1841
|
+
userInfo(`hard_fail 数量: ${result.hard_fail_count}`);
|
|
1842
|
+
userInfo("══════════════════════════════════════════════════════════════");
|
|
1843
|
+
userInfo();
|
|
1844
|
+
for (const p of result.phases) {
|
|
1845
|
+
userInfo(` ${p.hard_fail_count === 0 ? "[PASS]" : "[FAIL]"} ${p.name} — ${p.hard_fail_count} hard_fail`);
|
|
1846
|
+
}
|
|
1847
|
+
if (result.hard_fails.length > 0) {
|
|
1848
|
+
userInfo();
|
|
1849
|
+
userInfo("━━━ hard_fail 明细 ━━━");
|
|
1850
|
+
for (let i = 0; i < result.hard_fails.length; i++) {
|
|
1851
|
+
const hf = result.hard_fails[i];
|
|
1852
|
+
userInfo(`[${i + 1}] ${hf.code}: ${hf.message}`);
|
|
1853
|
+
userInfo(` 涉及: ${hf.files.join(", ")}`);
|
|
1854
|
+
userInfo(` 下一步: ${hf.nextStep}`);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
if (!result.passed)
|
|
1859
|
+
process.exit(1);
|
|
1860
|
+
}
|
|
1861
|
+
async function cmdValidateFoundation() {
|
|
1862
|
+
debug("CLI", "执行 cmdValidateFoundation");
|
|
1012
1863
|
const { validateMechanismLayerMaps, listMechanismLayerMaps } = await import("../engine/dual_layer_mechanism_registry.js");
|
|
1013
1864
|
const { auditTemplateMechanisms } = await import("../engine/template_mechanism_auditor.js");
|
|
1014
|
-
const {
|
|
1865
|
+
const { validateFoundationScenarios, validateFoundationProblemMatrix } = await import("../engine/foundation_scenario_registry.js");
|
|
1015
1866
|
const cwd = process.cwd();
|
|
1016
1867
|
const maps = listMechanismLayerMaps();
|
|
1017
1868
|
const mechFindings = validateMechanismLayerMaps(maps, cwd);
|
|
1018
1869
|
const mechanismsPass = mechFindings.filter((f) => f.severity === "hard_fail").length === 0;
|
|
1019
1870
|
const auditReport = auditTemplateMechanisms(cwd);
|
|
1020
1871
|
const auditPass = auditReport.hard_fail_count === 0;
|
|
1021
|
-
const scenarioResults = await
|
|
1872
|
+
const scenarioResults = await validateFoundationScenarios(mechanismsPass, auditPass, true);
|
|
1022
1873
|
const allPass = scenarioResults.every((s) => s.status === "PASS");
|
|
1023
1874
|
const isJson = process.argv.includes("--json");
|
|
1024
1875
|
if (isJson) {
|
|
1025
|
-
const problemMatrix =
|
|
1876
|
+
const problemMatrix = validateFoundationProblemMatrix(cwd);
|
|
1026
1877
|
const problemAllPass = problemMatrix.every((p) => Object.values(p.dimensions).every((d) => d.status === "PASS"));
|
|
1027
|
-
|
|
1878
|
+
userInfo(JSON.stringify({
|
|
1028
1879
|
mechanisms_pass: mechanismsPass,
|
|
1029
1880
|
audit_pass: auditPass,
|
|
1030
1881
|
all_pass: allPass && problemAllPass,
|
|
@@ -1036,71 +1887,173 @@ async function cmdValidateBatch1() {
|
|
|
1036
1887
|
else {
|
|
1037
1888
|
for (const s of scenarioResults) {
|
|
1038
1889
|
const icon = s.status === "PASS" ? "✓" : "✗";
|
|
1039
|
-
|
|
1890
|
+
userInfo(`${icon} ${s.scenario_id}: ${s.scenario_name} — ${s.status}`);
|
|
1040
1891
|
for (const r of s.rules) {
|
|
1041
1892
|
const ri = r.status === "PASS" ? " ✓" : " ✗";
|
|
1042
|
-
|
|
1893
|
+
userInfo(`${ri} ${r.rule}: ${r.evidence}`);
|
|
1043
1894
|
}
|
|
1044
1895
|
}
|
|
1045
|
-
|
|
1896
|
+
userInfo(allPass ? "\n所有场景通过" : "\n部分场景失败");
|
|
1046
1897
|
}
|
|
1047
1898
|
process.exit(allPass ? 0 : 1);
|
|
1048
1899
|
}
|
|
1900
|
+
/**
|
|
1901
|
+
* 新增问题/issue 演进门控 — problem-54 真实消费入口。
|
|
1902
|
+
* 用法: soloforge validate-new-issue --title="问题标题" --batch=2 [--json]
|
|
1903
|
+
*/
|
|
1904
|
+
async function cmdValidateNewIssue() {
|
|
1905
|
+
debug("CLI", "执行 cmdValidateNewIssue");
|
|
1906
|
+
const title = getArgValue("--title") ?? "";
|
|
1907
|
+
const batchStr = getArgValue("--batch");
|
|
1908
|
+
const batch = batchStr ? parseInt(batchStr, 10) : 0;
|
|
1909
|
+
const isJson = args.includes("--json");
|
|
1910
|
+
if (!title) {
|
|
1911
|
+
userError("❌ 错误: --title 必须提供");
|
|
1912
|
+
process.exit(1);
|
|
1913
|
+
}
|
|
1914
|
+
const { performEvolutionGate, checkDuplicateIssue, createNewIssueRegressionGate, } = await import("../engine/evolution_regression_gate.js");
|
|
1915
|
+
// 从 implementation_roadmap_registry 加载真实已有问题
|
|
1916
|
+
const { listAllProblems } = await import("../engine/implementation_roadmap_registry.js");
|
|
1917
|
+
const allProblems = listAllProblems();
|
|
1918
|
+
// 精确重复检测: label 精确匹配(不子串),title 语义包含,id 精确匹配
|
|
1919
|
+
const lower = title.toLowerCase();
|
|
1920
|
+
const matchedProblemMap = new Map();
|
|
1921
|
+
for (const p of allProblems) {
|
|
1922
|
+
let matched = false;
|
|
1923
|
+
// id 精确匹配
|
|
1924
|
+
if (p.id.toLowerCase() === lower)
|
|
1925
|
+
matched = true;
|
|
1926
|
+
// label 精确匹配
|
|
1927
|
+
if (p.label.toLowerCase() === lower)
|
|
1928
|
+
matched = true;
|
|
1929
|
+
// label 前缀匹配: "问题四十一" 匹配 "问题四十一(Brainstorm)"
|
|
1930
|
+
if (p.label.toLowerCase().startsWith(lower + "("))
|
|
1931
|
+
matched = true;
|
|
1932
|
+
// 完整 title 的包含匹配(title 是长描述,子串匹配合理)
|
|
1933
|
+
if (lower.length >= 2 && p.title.toLowerCase().includes(lower))
|
|
1934
|
+
matched = true;
|
|
1935
|
+
// 输入包含完整 title(输入更长时)
|
|
1936
|
+
if (lower.length >= 4 && p.title.length >= 4 && lower.includes(p.title.toLowerCase()))
|
|
1937
|
+
matched = true;
|
|
1938
|
+
if (matched) {
|
|
1939
|
+
matchedProblemMap.set(p.id, { id: p.id, label: p.label, title: p.title });
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
const deduplicatedIds = [...matchedProblemMap.keys()];
|
|
1943
|
+
const matchedDetails = [...matchedProblemMap.values()];
|
|
1944
|
+
// 稳定 slug: 基于标题哈希而非 Date.now
|
|
1945
|
+
const titleSlug = title
|
|
1946
|
+
.toLowerCase()
|
|
1947
|
+
.replace(/[^a-z0-9一-鿿]+/g, "-")
|
|
1948
|
+
.replace(/^-|-$/g, "")
|
|
1949
|
+
.slice(0, 40);
|
|
1950
|
+
const hashSuffix = crypto.createHash("sha256").update(title).digest("hex").slice(0, 8);
|
|
1951
|
+
const candidateId = `problem-new-${titleSlug}-${hashSuffix}`;
|
|
1952
|
+
const gate = createNewIssueRegressionGate({
|
|
1953
|
+
issue_candidate_id: candidateId,
|
|
1954
|
+
candidate_title: title,
|
|
1955
|
+
});
|
|
1956
|
+
// 重复检测 — 写入去重后的 ID 列表
|
|
1957
|
+
gate.duplicate_check.possible_duplicates = deduplicatedIds;
|
|
1958
|
+
// 演进门控
|
|
1959
|
+
const result = performEvolutionGate(gate);
|
|
1960
|
+
const output = {
|
|
1961
|
+
title,
|
|
1962
|
+
batch,
|
|
1963
|
+
candidate_id: candidateId,
|
|
1964
|
+
existing_issues_checked: allProblems.length,
|
|
1965
|
+
duplicate_detected: gate.duplicate_check.possible_duplicates.length > 0,
|
|
1966
|
+
duplicates: [...new Set(gate.duplicate_check.possible_duplicates)],
|
|
1967
|
+
matched_duplicate_details: matchedDetails,
|
|
1968
|
+
gate_status: result.gate_status,
|
|
1969
|
+
can_proceed: result.allowed,
|
|
1970
|
+
reasons: result.reasons,
|
|
1971
|
+
};
|
|
1972
|
+
if (isJson) {
|
|
1973
|
+
userInfo(JSON.stringify(output, null, 2));
|
|
1974
|
+
}
|
|
1975
|
+
else {
|
|
1976
|
+
userInfo(`问题演进门控: ${output.gate_status}`);
|
|
1977
|
+
userInfo(` 已检查 ${allProblems.length} 个既有问题`);
|
|
1978
|
+
if (output.duplicate_detected) {
|
|
1979
|
+
userInfo(` ⚠ 重复检测: 发现 ${output.duplicates.join(", ")}`);
|
|
1980
|
+
for (const d of matchedDetails) {
|
|
1981
|
+
userInfo(` - ${d.id}: ${d.label} — ${d.title}`);
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
if (result.reasons.length > 0) {
|
|
1985
|
+
userInfo(` 原因:`);
|
|
1986
|
+
for (const r of result.reasons)
|
|
1987
|
+
userInfo(` - ${r}`);
|
|
1988
|
+
}
|
|
1989
|
+
if (output.can_proceed) {
|
|
1990
|
+
userInfo(` ✓ 可继续: 问题新增已通过演进门控 (候选ID: ${candidateId})`);
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
if (!output.can_proceed) {
|
|
1994
|
+
process.exit(1);
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1049
1997
|
async function cmdStatus() {
|
|
1050
|
-
|
|
1051
|
-
const projectPath =
|
|
1052
|
-
|
|
1998
|
+
debug("CLI", "执行 cmdStatus");
|
|
1999
|
+
const projectPath = resolveProjectPath();
|
|
2000
|
+
userInfo(`SoloForge 状态: ${projectPath}`);
|
|
1053
2001
|
const { config, source } = await resolveProjectConfig(projectPath);
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
2002
|
+
userInfo(` 配置来源: ${source === "config_file" ? "config.yaml" : "自动推断"}`);
|
|
2003
|
+
userInfo(` 产品: ${config.product_profile}`);
|
|
2004
|
+
userInfo(` 后端: ${config.tech_stack.backend.framework || "未配置"}`);
|
|
2005
|
+
userInfo(` 前端: ${config.tech_stack.frontend.framework || "未配置"}`);
|
|
1058
2006
|
// 逐字段配置优先级状态
|
|
1059
2007
|
try {
|
|
1060
2008
|
const { resolutions, entries } = await resolveCurrentProjectConfigReports(projectPath);
|
|
1061
2009
|
if (resolutions.length > 0) {
|
|
1062
|
-
|
|
1063
|
-
|
|
2010
|
+
userInfo("");
|
|
2011
|
+
userInfo(" 字段解析状态:");
|
|
1064
2012
|
for (const r of resolutions) {
|
|
1065
2013
|
const stale = r.stale_warning ? " ⚠️ stale" : "";
|
|
1066
2014
|
const conflict = r.conflict_report ? " ⚠️ conflict" : "";
|
|
1067
|
-
|
|
2015
|
+
userInfo(` ${r.field_path}: ${JSON.stringify(r.resolved_value)} (${r.source}${stale}${conflict})`);
|
|
1068
2016
|
}
|
|
1069
2017
|
}
|
|
1070
2018
|
const schemaPath = path.join(projectPath, ".soloforge", "config.evidence.json");
|
|
1071
2019
|
if (fss.existsSync(schemaPath)) {
|
|
1072
2020
|
try {
|
|
1073
2021
|
const raw = JSON.parse(fss.readFileSync(schemaPath, "utf-8"));
|
|
1074
|
-
|
|
2022
|
+
userInfo(` evidence: schema_version=${raw.schema_version ?? 1}, ${entries.length} 条`);
|
|
1075
2023
|
}
|
|
1076
2024
|
catch {
|
|
1077
|
-
|
|
2025
|
+
userInfo(" evidence: 无法解析");
|
|
1078
2026
|
}
|
|
1079
2027
|
}
|
|
1080
2028
|
else if (source === "config_file") {
|
|
1081
|
-
|
|
2029
|
+
userInfo(" evidence: ⚠️ config.evidence.json 缺失");
|
|
1082
2030
|
}
|
|
1083
2031
|
}
|
|
1084
2032
|
catch { }
|
|
1085
2033
|
// Evidence 警告
|
|
1086
2034
|
const evidenceWarnings = await checkEvidenceWarnings(projectPath);
|
|
1087
2035
|
for (const w of evidenceWarnings) {
|
|
1088
|
-
|
|
2036
|
+
userInfo(` ⚠️ evidence: ${w}`);
|
|
1089
2037
|
}
|
|
1090
2038
|
const knowledgeDir = getProjectKnowledgeDir(config);
|
|
1091
2039
|
if (fss.existsSync(knowledgeDir)) {
|
|
1092
2040
|
const { KnowledgeIndexManager } = await import("../knowledge/index_manager.js");
|
|
1093
|
-
const index = new KnowledgeIndexManager(config);
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
2041
|
+
const index = new KnowledgeIndexManager(config, { watch: false });
|
|
2042
|
+
try {
|
|
2043
|
+
await index.build();
|
|
2044
|
+
const entries = index.getAllEntries();
|
|
2045
|
+
userInfo(` 知识: ${entries.global.length} 全局 + ${entries.project.length} 项目`);
|
|
2046
|
+
}
|
|
2047
|
+
finally {
|
|
2048
|
+
await index.close();
|
|
2049
|
+
}
|
|
1097
2050
|
}
|
|
1098
2051
|
else {
|
|
1099
|
-
|
|
2052
|
+
userInfo(" 知识: 未初始化");
|
|
1100
2053
|
}
|
|
1101
2054
|
}
|
|
1102
2055
|
async function interactiveConfig(projectPath) {
|
|
1103
|
-
|
|
2056
|
+
debug("CLI", "执行 interactiveConfig");
|
|
1104
2057
|
if (!process.stdin.isTTY)
|
|
1105
2058
|
return undefined;
|
|
1106
2059
|
const readline = await import("node:readline");
|
|
@@ -1146,22 +2099,165 @@ async function interactiveConfig(projectPath) {
|
|
|
1146
2099
|
return { draft, evidence };
|
|
1147
2100
|
}
|
|
1148
2101
|
function cmdVersion() {
|
|
1149
|
-
|
|
2102
|
+
debug("CLI", "执行 cmdVersion");
|
|
1150
2103
|
// dist/bin/soloforge.js → dist/package.json (local) 或 package.json (global npm)
|
|
1151
2104
|
const pkgPath = path.resolve(import.meta.dirname, "..", "package.json");
|
|
1152
2105
|
try {
|
|
1153
2106
|
const pkg = JSON.parse(fss.readFileSync(pkgPath, "utf-8"));
|
|
1154
|
-
|
|
2107
|
+
userInfo("SoloForge v" + pkg.version);
|
|
1155
2108
|
}
|
|
1156
2109
|
catch {
|
|
1157
2110
|
// 回退: 从 dist 同级目录查找
|
|
1158
2111
|
const altPath = path.resolve(import.meta.dirname, "..", "..", "package.json");
|
|
1159
2112
|
const pkg = JSON.parse(fss.readFileSync(altPath, "utf-8"));
|
|
1160
|
-
|
|
2113
|
+
userInfo("SoloForge v" + pkg.version);
|
|
1161
2114
|
}
|
|
1162
2115
|
}
|
|
1163
|
-
|
|
2116
|
+
async function cmdCleanup() {
|
|
2117
|
+
debug("CLI", "执行 cmdCleanup");
|
|
2118
|
+
const dryRun = !args.includes("--apply");
|
|
2119
|
+
const projectPath = process.cwd();
|
|
2120
|
+
const stateDir = path.join(projectPath, ".soloforge", "state");
|
|
2121
|
+
let hasError = false;
|
|
2122
|
+
userInfo(`SoloForge 清理: ${projectPath}`);
|
|
2123
|
+
userInfo(` 模式: ${dryRun ? "dry-run(仅评估)" : "⚠️ 实际清理"}`);
|
|
2124
|
+
// 收集所有 evidence 引用来源:task-*.json 中的 evidence 文件名 / evidence id
|
|
2125
|
+
const referencedEvidenceIds = new Set();
|
|
2126
|
+
// 扫描 task context 文件中的 evidence 引用
|
|
2127
|
+
if (fss.existsSync(stateDir)) {
|
|
2128
|
+
for (const f of fss.readdirSync(stateDir).filter((f) => f.startsWith("task-") && f.endsWith(".json"))) {
|
|
2129
|
+
try {
|
|
2130
|
+
const content = fss.readFileSync(path.join(stateDir, f), "utf-8");
|
|
2131
|
+
const ctx = JSON.parse(content);
|
|
2132
|
+
// 从 verification_evidence 收集引用
|
|
2133
|
+
if (ctx.verification_evidence && typeof ctx.verification_evidence === "object") {
|
|
2134
|
+
for (const [key, val] of Object.entries(ctx.verification_evidence)) {
|
|
2135
|
+
if (typeof val === "string")
|
|
2136
|
+
referencedEvidenceIds.add(val);
|
|
2137
|
+
referencedEvidenceIds.add(key);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
// 从 artifacts 的 evidence_refs 收集
|
|
2141
|
+
if (Array.isArray(ctx.output_artifacts)) {
|
|
2142
|
+
for (const art of ctx.output_artifacts) {
|
|
2143
|
+
if (art.evidence_refs && Array.isArray(art.evidence_refs)) {
|
|
2144
|
+
for (const ref of art.evidence_refs)
|
|
2145
|
+
referencedEvidenceIds.add(ref);
|
|
2146
|
+
}
|
|
2147
|
+
if (art.artifact_id)
|
|
2148
|
+
referencedEvidenceIds.add(art.artifact_id);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
// 从 delivery_report 收集
|
|
2152
|
+
if (ctx.delivery_report && typeof ctx.delivery_report === "object") {
|
|
2153
|
+
const dr = ctx.delivery_report;
|
|
2154
|
+
if (dr.evidence_refs && Array.isArray(dr.evidence_refs)) {
|
|
2155
|
+
for (const ref of dr.evidence_refs)
|
|
2156
|
+
referencedEvidenceIds.add(ref);
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
// 从 governance_report 收集
|
|
2160
|
+
if (ctx.governance_report && typeof ctx.governance_report === "string") {
|
|
2161
|
+
referencedEvidenceIds.add(ctx.governance_report);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
catch {
|
|
2165
|
+
// 跳过不可解析文件
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
// 1. TaskContext 清理(使用 retention_policy)
|
|
2170
|
+
if (fss.existsSync(stateDir)) {
|
|
2171
|
+
try {
|
|
2172
|
+
const { TaskContextManager } = await import("../engine/task_context.js");
|
|
2173
|
+
const mgr = new TaskContextManager(stateDir);
|
|
2174
|
+
const result = await mgr.cleanup(dryRun);
|
|
2175
|
+
userInfo("");
|
|
2176
|
+
userInfo(" TaskContext 清理:");
|
|
2177
|
+
userInfo(` 已清理: ${result.removed} 条`);
|
|
2178
|
+
userInfo(` 受保护(被引用不可删除): ${result.protected} 条`);
|
|
2179
|
+
userInfo(` 禁止内容检出: ${result.forbidden_content_hits.length > 0 ? result.forbidden_content_hits.join("; ") : "无"}`);
|
|
2180
|
+
userInfo(` dry_run: ${result.dry_run}`);
|
|
2181
|
+
if (result.forbidden_content_hits.length > 0) {
|
|
2182
|
+
userError(` ❌ TaskContext 包含禁止内容,清理中止`);
|
|
2183
|
+
hasError = true;
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
catch (e) {
|
|
2187
|
+
userError(` ❌ TaskContext 清理失败: ${e.message}`);
|
|
2188
|
+
process.exit(1);
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
else {
|
|
2192
|
+
userInfo(" TaskContext: 状态目录不存在,跳过");
|
|
2193
|
+
}
|
|
2194
|
+
// 2. Evidence 文件清理(真实引用扫描)
|
|
2195
|
+
const evidenceDir = path.join(projectPath, ".soloforge");
|
|
2196
|
+
if (fss.existsSync(evidenceDir)) {
|
|
2197
|
+
try {
|
|
2198
|
+
const { evaluateCleanup, checkForbiddenContent } = await import("../engine/retention_policy.js");
|
|
2199
|
+
const evidenceFiles = fss.readdirSync(evidenceDir)
|
|
2200
|
+
.filter((f) => f.endsWith(".json") && !f.startsWith("config."))
|
|
2201
|
+
.map((f) => {
|
|
2202
|
+
const fp = path.join(evidenceDir, f);
|
|
2203
|
+
const stat = fss.statSync(fp);
|
|
2204
|
+
const ageDays = Math.max(0, (Date.now() - stat.mtimeMs) / (24 * 60 * 60 * 1000));
|
|
2205
|
+
const content = fss.readFileSync(fp, "utf-8");
|
|
2206
|
+
const forbiddenHits = checkForbiddenContent("evidence", content);
|
|
2207
|
+
// 真实引用检查: evidence 文件名或内容中的 id 出现在引用集合中
|
|
2208
|
+
const isReferenced = referencedEvidenceIds.has(f) || referencedEvidenceIds.has(f.replace(/\.json$/, ""));
|
|
2209
|
+
return { name: f, age_days: ageDays, is_referenced: isReferenced, forbidden: forbiddenHits };
|
|
2210
|
+
});
|
|
2211
|
+
const records = evidenceFiles.map(e => ({ id: e.name, age_days: e.age_days, is_referenced: e.is_referenced }));
|
|
2212
|
+
const result = evaluateCleanup("evidence", records, dryRun);
|
|
2213
|
+
userInfo("");
|
|
2214
|
+
userInfo(" Evidence 清理:");
|
|
2215
|
+
userInfo(` 总文件: ${result.total_records}`);
|
|
2216
|
+
userInfo(` 可清理: ${result.eligible_for_cleanup}`);
|
|
2217
|
+
userInfo(` 受保护: ${result.protected_records}`);
|
|
2218
|
+
userInfo(` dry_run: ${result.dry_run}`);
|
|
2219
|
+
if (result.cleanup_candidates.length > 0) {
|
|
2220
|
+
userInfo(` 清理候选: ${result.cleanup_candidates.join(", ")}`);
|
|
2221
|
+
}
|
|
2222
|
+
const forbiddenFiles = evidenceFiles.filter(e => e.forbidden.length > 0);
|
|
2223
|
+
if (forbiddenFiles.length > 0) {
|
|
2224
|
+
userInfo(" ❌ 禁止内容检出:");
|
|
2225
|
+
for (const f of forbiddenFiles) {
|
|
2226
|
+
userInfo(` ${f.name}: ${f.forbidden.join(", ")}`);
|
|
2227
|
+
}
|
|
2228
|
+
hasError = true;
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
catch (e) {
|
|
2232
|
+
userError(` ❌ Evidence 清理失败: ${e.message}`);
|
|
2233
|
+
process.exit(1);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
// 3. 列出所有保留策略
|
|
2237
|
+
try {
|
|
2238
|
+
const { listRetentionPolicies } = await import("../engine/retention_policy.js");
|
|
2239
|
+
const policies = listRetentionPolicies();
|
|
2240
|
+
userInfo("");
|
|
2241
|
+
userInfo(" 保留策略:");
|
|
2242
|
+
for (const p of policies) {
|
|
2243
|
+
userInfo(` ${p.policy_id}: ${p.record_type}, 最大 ${p.max_age_days} 天 / ${p.max_count} 条, dry_run_default=${p.dry_run_default}`);
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
catch (e) {
|
|
2247
|
+
userError(` ❌ 保留策略加载失败: ${e.message}`);
|
|
2248
|
+
process.exit(1);
|
|
2249
|
+
}
|
|
2250
|
+
if (hasError)
|
|
2251
|
+
process.exit(1);
|
|
2252
|
+
}
|
|
2253
|
+
main().catch((e) => { internalWarn("CLI", "启动失败:", e); process.exit(1); });
|
|
1164
2254
|
function getArgValue(flag) {
|
|
2255
|
+
// 支持 --flag=value 格式
|
|
2256
|
+
const eqPrefix = flag + "=";
|
|
2257
|
+
const eqIdx = args.findIndex((a) => a.startsWith(eqPrefix));
|
|
2258
|
+
if (eqIdx !== -1) {
|
|
2259
|
+
return args[eqIdx].slice(eqPrefix.length) || undefined;
|
|
2260
|
+
}
|
|
1165
2261
|
const idx = args.indexOf(flag);
|
|
1166
2262
|
if (idx === -1 || idx + 1 >= args.length)
|
|
1167
2263
|
return undefined;
|