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