soloforge 1.2.7 → 1.2.9
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 +105 -321
- package/dist/adapters/claude_code/claude_md.d.ts +5 -0
- package/dist/adapters/claude_code/claude_md.d.ts.map +1 -1
- package/dist/adapters/claude_code/claude_md.js +6 -0
- package/dist/adapters/claude_code/claude_md.js.map +1 -1
- package/dist/adapters/claude_code/hooks.d.ts +4 -0
- package/dist/adapters/claude_code/hooks.d.ts.map +1 -1
- package/dist/adapters/claude_code/hooks.js +5 -0
- package/dist/adapters/claude_code/hooks.js.map +1 -1
- package/dist/adapters/claude_code/server.d.ts.map +1 -1
- package/dist/adapters/claude_code/server.js +9 -21
- package/dist/adapters/claude_code/server.js.map +1 -1
- package/dist/adapters/claude_code/tools.d.ts +5 -0
- package/dist/adapters/claude_code/tools.d.ts.map +1 -1
- package/dist/adapters/claude_code/tools.js +619 -205
- package/dist/adapters/claude_code/tools.js.map +1 -1
- package/dist/adapters/codex/codex_config.d.ts +9 -0
- package/dist/adapters/codex/codex_config.d.ts.map +1 -1
- package/dist/adapters/codex/codex_config.js +11 -3
- package/dist/adapters/codex/codex_config.js.map +1 -1
- package/dist/adapters/codex/codex_rules.d.ts +5 -0
- package/dist/adapters/codex/codex_rules.d.ts.map +1 -1
- package/dist/adapters/codex/codex_rules.js +8 -1
- package/dist/adapters/codex/codex_rules.js.map +1 -1
- package/dist/adapters/shared/workflow_template.d.ts +5 -0
- package/dist/adapters/shared/workflow_template.d.ts.map +1 -1
- package/dist/adapters/shared/workflow_template.js +32 -79
- package/dist/adapters/shared/workflow_template.js.map +1 -1
- package/dist/adapters/trae/trae_config.d.ts +4 -0
- package/dist/adapters/trae/trae_config.d.ts.map +1 -1
- package/dist/adapters/trae/trae_config.js +5 -7
- package/dist/adapters/trae/trae_config.js.map +1 -1
- package/dist/adapters/trae/trae_rules.d.ts +5 -0
- package/dist/adapters/trae/trae_rules.d.ts.map +1 -1
- package/dist/adapters/trae/trae_rules.js +7 -1
- package/dist/adapters/trae/trae_rules.js.map +1 -1
- package/dist/bin/config_commands.d.ts +33 -0
- package/dist/bin/config_commands.d.ts.map +1 -0
- package/dist/bin/config_commands.js +222 -0
- package/dist/bin/config_commands.js.map +1 -0
- package/dist/bin/soloforge.js +609 -119
- package/dist/bin/soloforge.js.map +1 -1
- package/dist/engine/artifact_contract_registry.d.ts +138 -0
- package/dist/engine/artifact_contract_registry.d.ts.map +1 -0
- package/dist/engine/artifact_contract_registry.js +427 -0
- package/dist/engine/artifact_contract_registry.js.map +1 -0
- package/dist/engine/audit_pool.d.ts +40 -0
- package/dist/engine/audit_pool.d.ts.map +1 -1
- package/dist/engine/audit_pool.js +37 -1
- package/dist/engine/audit_pool.js.map +1 -1
- package/dist/engine/audit_sampler.d.ts +5 -0
- package/dist/engine/audit_sampler.d.ts.map +1 -1
- package/dist/engine/audit_sampler.js +6 -0
- 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 -1
- package/dist/engine/audit_verifier.js.map +1 -1
- package/dist/engine/batch1_manifest.d.ts +61 -0
- package/dist/engine/batch1_manifest.d.ts.map +1 -0
- package/dist/engine/batch1_manifest.js +220 -0
- package/dist/engine/batch1_manifest.js.map +1 -0
- package/dist/engine/batch1_reality_gate.d.ts +40 -0
- package/dist/engine/batch1_reality_gate.d.ts.map +1 -0
- package/dist/engine/batch1_reality_gate.js +290 -0
- package/dist/engine/batch1_reality_gate.js.map +1 -0
- package/dist/engine/batch1_scenario_registry.d.ts +62 -0
- package/dist/engine/batch1_scenario_registry.d.ts.map +1 -0
- package/dist/engine/batch1_scenario_registry.js +392 -0
- package/dist/engine/batch1_scenario_registry.js.map +1 -0
- package/dist/engine/batch1_scenario_runners.d.ts +42 -0
- package/dist/engine/batch1_scenario_runners.d.ts.map +1 -0
- package/dist/engine/batch1_scenario_runners.js +292 -0
- package/dist/engine/batch1_scenario_runners.js.map +1 -0
- package/dist/engine/capability_action_advisor.d.ts +3 -0
- package/dist/engine/capability_action_advisor.d.ts.map +1 -1
- package/dist/engine/capability_action_advisor.js +10 -0
- package/dist/engine/capability_action_advisor.js.map +1 -1
- package/dist/engine/capability_registry.d.ts +21 -0
- package/dist/engine/capability_registry.d.ts.map +1 -1
- package/dist/engine/capability_registry.js +113 -0
- package/dist/engine/capability_registry.js.map +1 -1
- package/dist/engine/capability_state_store.d.ts +63 -0
- package/dist/engine/capability_state_store.d.ts.map +1 -1
- package/dist/engine/capability_state_store.js +49 -1
- 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 +5 -4
- package/dist/engine/change_coordinator.js.map +1 -1
- package/dist/engine/classifier.d.ts +15 -5
- package/dist/engine/classifier.d.ts.map +1 -1
- package/dist/engine/classifier.js +70 -69
- package/dist/engine/classifier.js.map +1 -1
- package/dist/engine/code_reviewer.d.ts +14 -0
- package/dist/engine/code_reviewer.d.ts.map +1 -1
- package/dist/engine/code_reviewer.js +109 -10
- package/dist/engine/code_reviewer.js.map +1 -1
- package/dist/engine/cognitive_anchor.d.ts +14 -0
- package/dist/engine/cognitive_anchor.d.ts.map +1 -1
- package/dist/engine/cognitive_anchor.js +26 -2
- package/dist/engine/cognitive_anchor.js.map +1 -1
- package/dist/engine/command_execution_contract.d.ts +226 -0
- package/dist/engine/command_execution_contract.d.ts.map +1 -0
- package/dist/engine/command_execution_contract.js +571 -0
- package/dist/engine/command_execution_contract.js.map +1 -0
- package/dist/engine/confidence_scorer.d.ts.map +1 -1
- package/dist/engine/confidence_scorer.js +1 -0
- package/dist/engine/confidence_scorer.js.map +1 -1
- package/dist/engine/config_precedence_contract.d.ts +269 -0
- package/dist/engine/config_precedence_contract.d.ts.map +1 -0
- package/dist/engine/config_precedence_contract.js +948 -0
- package/dist/engine/config_precedence_contract.js.map +1 -0
- package/dist/engine/conflict_gate.d.ts +13 -0
- package/dist/engine/conflict_gate.d.ts.map +1 -1
- package/dist/engine/conflict_gate.js +20 -2
- package/dist/engine/conflict_gate.js.map +1 -1
- package/dist/engine/consumable_asset_registry.d.ts +46 -0
- package/dist/engine/consumable_asset_registry.d.ts.map +1 -0
- package/dist/engine/consumable_asset_registry.js +758 -0
- package/dist/engine/consumable_asset_registry.js.map +1 -0
- package/dist/engine/contract_guard.d.ts +4 -0
- package/dist/engine/contract_guard.d.ts.map +1 -1
- package/dist/engine/contract_guard.js +15 -7
- package/dist/engine/contract_guard.js.map +1 -1
- package/dist/engine/convention_detector.d.ts.map +1 -1
- package/dist/engine/convention_detector.js +5 -2
- package/dist/engine/convention_detector.js.map +1 -1
- package/dist/engine/core_engineering_principles.d.ts +155 -0
- package/dist/engine/core_engineering_principles.d.ts.map +1 -0
- package/dist/engine/core_engineering_principles.js +426 -0
- package/dist/engine/core_engineering_principles.js.map +1 -0
- package/dist/engine/debt_reporter.d.ts.map +1 -1
- package/dist/engine/debt_reporter.js +3 -1
- 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 +9 -3
- package/dist/engine/debt_tracker.js.map +1 -1
- package/dist/engine/debugger.d.ts.map +1 -1
- package/dist/engine/debugger.js +2 -0
- package/dist/engine/debugger.js.map +1 -1
- package/dist/engine/decision_contract.d.ts +11 -2
- package/dist/engine/decision_contract.d.ts.map +1 -1
- package/dist/engine/decision_contract.js +17 -2
- package/dist/engine/decision_contract.js.map +1 -1
- package/dist/engine/delivery.d.ts +7 -0
- package/dist/engine/delivery.d.ts.map +1 -1
- package/dist/engine/delivery.js +89 -36
- package/dist/engine/delivery.js.map +1 -1
- package/dist/engine/dependency_scanner.d.ts.map +1 -1
- package/dist/engine/dependency_scanner.js +14 -9
- package/dist/engine/dependency_scanner.js.map +1 -1
- package/dist/engine/developer_sovereignty.d.ts.map +1 -1
- package/dist/engine/developer_sovereignty.js +8 -2
- package/dist/engine/developer_sovereignty.js.map +1 -1
- package/dist/engine/diff_ownership.d.ts.map +1 -1
- package/dist/engine/diff_ownership.js +8 -0
- package/dist/engine/diff_ownership.js.map +1 -1
- package/dist/engine/diff_ownership_store.d.ts +26 -10
- package/dist/engine/diff_ownership_store.d.ts.map +1 -1
- package/dist/engine/diff_ownership_store.js +47 -20
- package/dist/engine/diff_ownership_store.js.map +1 -1
- package/dist/engine/dual_layer_mechanism_registry.d.ts +66 -0
- package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -0
- package/dist/engine/dual_layer_mechanism_registry.js +1077 -0
- package/dist/engine/dual_layer_mechanism_registry.js.map +1 -0
- package/dist/engine/escape_report.d.ts +50 -0
- package/dist/engine/escape_report.d.ts.map +1 -1
- package/dist/engine/escape_report.js +38 -0
- package/dist/engine/escape_report.js.map +1 -1
- package/dist/engine/evolver.d.ts.map +1 -1
- package/dist/engine/evolver.js +12 -2
- package/dist/engine/evolver.js.map +1 -1
- package/dist/engine/exploration.d.ts.map +1 -1
- package/dist/engine/exploration.js +87 -0
- package/dist/engine/exploration.js.map +1 -1
- package/dist/engine/failure_classifier.d.ts.map +1 -1
- package/dist/engine/failure_classifier.js +8 -0
- package/dist/engine/failure_classifier.js.map +1 -1
- package/dist/engine/feasibility_checker.d.ts +8 -0
- package/dist/engine/feasibility_checker.d.ts.map +1 -1
- package/dist/engine/feasibility_checker.js +12 -0
- package/dist/engine/feasibility_checker.js.map +1 -1
- package/dist/engine/git_deps.d.ts +4 -1
- package/dist/engine/git_deps.d.ts.map +1 -1
- package/dist/engine/git_deps.js +5 -1
- package/dist/engine/git_deps.js.map +1 -1
- package/dist/engine/governance_report.d.ts +57 -1
- package/dist/engine/governance_report.d.ts.map +1 -1
- package/dist/engine/governance_report.js +91 -1
- 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 -1
- package/dist/engine/impact_analyzer.js.map +1 -1
- package/dist/engine/implementation_roadmap_registry.d.ts +105 -0
- package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -0
- package/dist/engine/implementation_roadmap_registry.js +813 -0
- package/dist/engine/implementation_roadmap_registry.js.map +1 -0
- package/dist/engine/input_material_contract_registry.d.ts +185 -0
- package/dist/engine/input_material_contract_registry.d.ts.map +1 -0
- package/dist/engine/input_material_contract_registry.js +563 -0
- package/dist/engine/input_material_contract_registry.js.map +1 -0
- package/dist/engine/intent_expander.d.ts +8 -27
- package/dist/engine/intent_expander.d.ts.map +1 -1
- package/dist/engine/intent_expander.js +1170 -139
- package/dist/engine/intent_expander.js.map +1 -1
- package/dist/engine/intent_router.d.ts +82 -0
- package/dist/engine/intent_router.d.ts.map +1 -0
- package/dist/engine/intent_router.js +458 -0
- package/dist/engine/intent_router.js.map +1 -0
- package/dist/engine/io_controller.d.ts.map +1 -1
- package/dist/engine/io_controller.js +25 -13
- 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 +8 -4
- package/dist/engine/java_quality_guard.js.map +1 -1
- package/dist/engine/job_manager.d.ts +35 -0
- package/dist/engine/job_manager.d.ts.map +1 -1
- package/dist/engine/job_manager.js +53 -9
- package/dist/engine/job_manager.js.map +1 -1
- package/dist/engine/knowledge_config_loader.d.ts +12 -1
- package/dist/engine/knowledge_config_loader.d.ts.map +1 -1
- package/dist/engine/knowledge_config_loader.js +50 -10
- package/dist/engine/knowledge_config_loader.js.map +1 -1
- package/dist/engine/knowledge_injection_boundary.d.ts +56 -0
- package/dist/engine/knowledge_injection_boundary.d.ts.map +1 -0
- package/dist/engine/knowledge_injection_boundary.js +561 -0
- package/dist/engine/knowledge_injection_boundary.js.map +1 -0
- package/dist/engine/knowledge_manager.d.ts +73 -0
- package/dist/engine/knowledge_manager.d.ts.map +1 -1
- package/dist/engine/knowledge_manager.js +163 -21
- package/dist/engine/knowledge_manager.js.map +1 -1
- package/dist/engine/knowledge_sovereignty.d.ts +1 -0
- package/dist/engine/knowledge_sovereignty.d.ts.map +1 -1
- package/dist/engine/knowledge_sovereignty.js +8 -3
- package/dist/engine/knowledge_sovereignty.js.map +1 -1
- package/dist/engine/llm_gateway.d.ts +74 -3
- package/dist/engine/llm_gateway.d.ts.map +1 -1
- package/dist/engine/llm_gateway.js +75 -4
- package/dist/engine/llm_gateway.js.map +1 -1
- package/dist/engine/main_path_integration_contract.d.ts +383 -0
- package/dist/engine/main_path_integration_contract.d.ts.map +1 -0
- package/dist/engine/main_path_integration_contract.js +1581 -0
- package/dist/engine/main_path_integration_contract.js.map +1 -0
- package/dist/engine/mechanism_contract_registry.d.ts +59 -0
- package/dist/engine/mechanism_contract_registry.d.ts.map +1 -0
- package/dist/engine/mechanism_contract_registry.js +484 -0
- package/dist/engine/mechanism_contract_registry.js.map +1 -0
- package/dist/engine/migration_guard.d.ts.map +1 -1
- package/dist/engine/migration_guard.js +24 -15
- package/dist/engine/migration_guard.js.map +1 -1
- package/dist/engine/mutation_audit.d.ts +10 -0
- package/dist/engine/mutation_audit.d.ts.map +1 -1
- package/dist/engine/mutation_audit.js +19 -2
- package/dist/engine/mutation_audit.js.map +1 -1
- package/dist/engine/observability.d.ts.map +1 -1
- package/dist/engine/observability.js +17 -6
- package/dist/engine/observability.js.map +1 -1
- package/dist/engine/onboarding.d.ts.map +1 -1
- package/dist/engine/onboarding.js +20 -4
- package/dist/engine/onboarding.js.map +1 -1
- package/dist/engine/policy_drift_detector.d.ts +6 -0
- package/dist/engine/policy_drift_detector.d.ts.map +1 -1
- package/dist/engine/policy_drift_detector.js +16 -0
- package/dist/engine/policy_drift_detector.js.map +1 -1
- package/dist/engine/privacy_secret_contract.d.ts +320 -0
- package/dist/engine/privacy_secret_contract.d.ts.map +1 -0
- package/dist/engine/privacy_secret_contract.js +874 -0
- package/dist/engine/privacy_secret_contract.js.map +1 -0
- package/dist/engine/regression_matrix.d.ts +21 -8
- package/dist/engine/regression_matrix.d.ts.map +1 -1
- package/dist/engine/regression_matrix.js +37 -8
- package/dist/engine/regression_matrix.js.map +1 -1
- package/dist/engine/risk_sampler.d.ts +6 -0
- package/dist/engine/risk_sampler.d.ts.map +1 -1
- package/dist/engine/risk_sampler.js +9 -0
- 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 +7 -3
- package/dist/engine/runtime_safety.js.map +1 -1
- package/dist/engine/scaffolder.d.ts.map +1 -1
- package/dist/engine/scaffolder.js +7 -1
- package/dist/engine/scaffolder.js.map +1 -1
- package/dist/engine/scope_controller.d.ts.map +1 -1
- package/dist/engine/scope_controller.js +12 -1
- package/dist/engine/scope_controller.js.map +1 -1
- package/dist/engine/scope_lease.d.ts +43 -0
- package/dist/engine/scope_lease.d.ts.map +1 -1
- package/dist/engine/scope_lease.js +44 -0
- package/dist/engine/scope_lease.js.map +1 -1
- package/dist/engine/semantic_evidence.d.ts +6 -0
- package/dist/engine/semantic_evidence.d.ts.map +1 -1
- package/dist/engine/semantic_evidence.js +9 -0
- package/dist/engine/semantic_evidence.js.map +1 -1
- package/dist/engine/task_context.d.ts +36 -1
- package/dist/engine/task_context.d.ts.map +1 -1
- package/dist/engine/task_context.js +252 -13
- 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 +13 -3
- 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 +8 -7
- package/dist/engine/team_awareness.js.map +1 -1
- package/dist/engine/template_mechanism_auditor.d.ts +93 -0
- package/dist/engine/template_mechanism_auditor.d.ts.map +1 -0
- package/dist/engine/template_mechanism_auditor.js +622 -0
- package/dist/engine/template_mechanism_auditor.js.map +1 -0
- package/dist/engine/test_generator.d.ts.map +1 -1
- package/dist/engine/test_generator.js +6 -0
- package/dist/engine/test_generator.js.map +1 -1
- package/dist/engine/test_quality.d.ts +6 -0
- package/dist/engine/test_quality.d.ts.map +1 -1
- package/dist/engine/test_quality.js +26 -10
- package/dist/engine/test_quality.js.map +1 -1
- package/dist/engine/tool_invocation_contract_registry.d.ts +136 -0
- package/dist/engine/tool_invocation_contract_registry.d.ts.map +1 -0
- package/dist/engine/tool_invocation_contract_registry.js +731 -0
- package/dist/engine/tool_invocation_contract_registry.js.map +1 -0
- package/dist/engine/traceability.d.ts +3 -0
- package/dist/engine/traceability.d.ts.map +1 -1
- package/dist/engine/traceability.js +12 -4
- package/dist/engine/traceability.js.map +1 -1
- package/dist/engine/user_feedback_contract.d.ts +162 -0
- package/dist/engine/user_feedback_contract.d.ts.map +1 -0
- package/dist/engine/user_feedback_contract.js +356 -0
- package/dist/engine/user_feedback_contract.js.map +1 -0
- package/dist/engine/verifier.d.ts +6 -1
- package/dist/engine/verifier.d.ts.map +1 -1
- package/dist/engine/verifier.js +114 -1
- package/dist/engine/verifier.js.map +1 -1
- package/dist/engine/workflow_contract_registry.d.ts +70 -0
- package/dist/engine/workflow_contract_registry.d.ts.map +1 -0
- package/dist/engine/workflow_contract_registry.js +501 -0
- package/dist/engine/workflow_contract_registry.js.map +1 -0
- package/dist/engine/workspace_resumer.d.ts.map +1 -1
- package/dist/engine/workspace_resumer.js +8 -0
- package/dist/engine/workspace_resumer.js.map +1 -1
- package/dist/engine/zero_config_init.d.ts +67 -2
- package/dist/engine/zero_config_init.d.ts.map +1 -1
- package/dist/engine/zero_config_init.js +410 -28
- package/dist/engine/zero_config_init.js.map +1 -1
- package/dist/git/operations.d.ts +101 -0
- package/dist/git/operations.d.ts.map +1 -1
- package/dist/git/operations.js +125 -9
- package/dist/git/operations.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/knowledge/conflict_detector.d.ts +6 -0
- package/dist/knowledge/conflict_detector.d.ts.map +1 -1
- package/dist/knowledge/conflict_detector.js +7 -0
- package/dist/knowledge/conflict_detector.js.map +1 -1
- package/dist/knowledge/health_checker.d.ts +16 -0
- package/dist/knowledge/health_checker.d.ts.map +1 -1
- package/dist/knowledge/health_checker.js +24 -1
- package/dist/knowledge/health_checker.js.map +1 -1
- package/dist/knowledge/index_manager.d.ts +140 -2
- package/dist/knowledge/index_manager.d.ts.map +1 -1
- package/dist/knowledge/index_manager.js +186 -26
- package/dist/knowledge/index_manager.js.map +1 -1
- package/dist/knowledge/loader.d.ts +8 -1
- package/dist/knowledge/loader.d.ts.map +1 -1
- package/dist/knowledge/loader.js +56 -2
- package/dist/knowledge/loader.js.map +1 -1
- package/dist/knowledge/writer.d.ts +49 -1
- package/dist/knowledge/writer.d.ts.map +1 -1
- package/dist/knowledge/writer.js +55 -1
- package/dist/knowledge/writer.js.map +1 -1
- package/dist/types.d.ts +255 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +29 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +7 -7
- package/templates/knowledge/acceptance_templates//345/216/237/345/236/213/350/257/264/346/230/216/346/250/241/347/211/210.md +30 -2
- 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 +16 -0
- 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 +17 -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 +43 -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 +17 -0
- package/templates/knowledge/checklists//351/232/220/347/247/201/345/256/241/346/237/245/346/270/205/345/215/225.md +15 -0
- package/templates/knowledge/checklists//351/252/214/350/257/201/351/252/214/346/224/266/346/270/205/345/215/225.md +16 -0
- package/templates/knowledge/patterns/core//345/206/263/347/255/226/347/275/221/345/205/263.md +1 -0
- 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 +23 -0
- package/templates/knowledge/procedures//345/221/275/344/273/244/346/211/247/350/241/214/346/265/201/347/250/213.md +19 -0
- package/templates/knowledge/procedures//345/267/245/345/205/267/350/260/203/347/224/250/346/265/201/347/250/213.md +15 -0
- package/templates/knowledge/procedures//346/204/217/345/233/276/350/267/257/347/224/261/346/265/201/347/250/213.md +15 -0
- package/templates/knowledge/procedures/{Figma → /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 +5 -5
- 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 +53 -0
- package/templates/knowledge/rules//344/272/247/347/211/251/345/245/221/347/272/246/350/247/204/345/210/231.md +21 -0
- package/templates/knowledge/rules//345/221/275/344/273/244/346/211/247/350/241/214/350/247/204/345/210/231.md +25 -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 +20 -0
- package/templates/knowledge/rules//345/267/245/345/205/267/350/260/203/347/224/250/350/247/204/345/210/231.md +25 -0
- package/templates/knowledge/rules//346/204/217/345/233/276/350/267/257/347/224/261/350/247/204/345/210/231.md +26 -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 +24 -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 +20 -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 +125 -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 +26 -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 +22 -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 +25 -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 +27 -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 +22 -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 +24 -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 +28 -0
- package/templates/knowledge/rules//351/252/214/350/257/201/345/245/221/347/272/246/350/247/204/345/210/231.md +25 -0
- package/templates/knowledge/templates/{review_summary.md → /345/256/241/346/237/245/346/221/230/350/246/201.md} +1 -1
- package/templates/config.yaml +0 -53
|
@@ -0,0 +1,948 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Precedence Contract
|
|
3
|
+
*
|
|
4
|
+
* 定义配置优先级、覆盖规则、冲突检测和治理检查。
|
|
5
|
+
* 解决"配置一旦存在,谁优先"的问题。
|
|
6
|
+
*
|
|
7
|
+
* 优先级 (高→低):
|
|
8
|
+
* user_task > cli_flag/mcp_param > confirmed_config > project_policy >
|
|
9
|
+
* fingerprint > blueprint > product_profile > knowledge_default > global_default
|
|
10
|
+
*
|
|
11
|
+
* 上位约束 (guard) 不可被任何配置覆盖。
|
|
12
|
+
*/
|
|
13
|
+
import crypto from "node:crypto";
|
|
14
|
+
import nodePath from "node:path";
|
|
15
|
+
import nodeFs from "node:fs";
|
|
16
|
+
import YAML from "yaml";
|
|
17
|
+
// ── 优先级顺序 (索引=排名, 数值越小优先级越高) ──
|
|
18
|
+
const PRECEDENCE_ORDER = [
|
|
19
|
+
"user_task",
|
|
20
|
+
"cli_flag",
|
|
21
|
+
"mcp_param",
|
|
22
|
+
"confirmed_config",
|
|
23
|
+
"project_policy",
|
|
24
|
+
"fingerprint",
|
|
25
|
+
"blueprint",
|
|
26
|
+
"product_profile",
|
|
27
|
+
"knowledge_default",
|
|
28
|
+
"global_default",
|
|
29
|
+
];
|
|
30
|
+
/** 证据元数据来源 — 映射到规范解析来源 */
|
|
31
|
+
const EVIDENCE_SOURCE_MAP = {
|
|
32
|
+
user_declared: "confirmed_config",
|
|
33
|
+
confirmed: "confirmed_config",
|
|
34
|
+
detected: "fingerprint",
|
|
35
|
+
};
|
|
36
|
+
const SOURCE_LIFETIME = {
|
|
37
|
+
user_task: "task",
|
|
38
|
+
cli_flag: "single_invocation",
|
|
39
|
+
mcp_param: "single_invocation",
|
|
40
|
+
confirmed_config: "project_persistent",
|
|
41
|
+
project_policy: "project_persistent",
|
|
42
|
+
fingerprint: "task",
|
|
43
|
+
blueprint: "project_persistent",
|
|
44
|
+
product_profile: "global",
|
|
45
|
+
knowledge_default: "global",
|
|
46
|
+
global_default: "global",
|
|
47
|
+
};
|
|
48
|
+
// ── 上位约束 (不可被任何配置覆盖) ──
|
|
49
|
+
/** 上位约束列表 — 这些约束不可被任何配置覆盖 */
|
|
50
|
+
export const UPPER_BOUND_GUARDS = [
|
|
51
|
+
"enforced_guard",
|
|
52
|
+
"privacy_secret_policy",
|
|
53
|
+
"contract_state",
|
|
54
|
+
"command_safety",
|
|
55
|
+
"delivery_authorization",
|
|
56
|
+
"data_sovereignty",
|
|
57
|
+
"destructive_action_gate",
|
|
58
|
+
"human_sovereignty",
|
|
59
|
+
];
|
|
60
|
+
// ── 优先级规则 ──
|
|
61
|
+
const PRECEDENCE_RULES = [
|
|
62
|
+
{
|
|
63
|
+
id: "pr-01",
|
|
64
|
+
higher_source: "user_task",
|
|
65
|
+
lower_source: "confirmed_config",
|
|
66
|
+
description: "用户本次指令优先于持久配置,但只在本次任务生效",
|
|
67
|
+
override_behavior: "selected",
|
|
68
|
+
requires_report: true,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "pr-02",
|
|
72
|
+
higher_source: "cli_flag",
|
|
73
|
+
lower_source: "confirmed_config",
|
|
74
|
+
description: "CLI 参数可临时覆盖 config,但不写入 config",
|
|
75
|
+
override_behavior: "selected",
|
|
76
|
+
requires_report: true,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "pr-03",
|
|
80
|
+
higher_source: "confirmed_config",
|
|
81
|
+
lower_source: "fingerprint",
|
|
82
|
+
description: "confirmed_config 优先于 fingerprint",
|
|
83
|
+
override_behavior: "overridden",
|
|
84
|
+
requires_report: true,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: "pr-04",
|
|
88
|
+
higher_source: "confirmed_config",
|
|
89
|
+
lower_source: "product_profile",
|
|
90
|
+
description: "product_profile 只能补充默认,不覆盖用户确认配置",
|
|
91
|
+
override_behavior: "overridden",
|
|
92
|
+
requires_report: false,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: "pr-05",
|
|
96
|
+
higher_source: "confirmed_config",
|
|
97
|
+
lower_source: "knowledge_default",
|
|
98
|
+
description: "knowledge_default 不能覆盖 config",
|
|
99
|
+
override_behavior: "overridden",
|
|
100
|
+
requires_report: false,
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: "pr-06",
|
|
104
|
+
higher_source: "fingerprint",
|
|
105
|
+
lower_source: "blueprint",
|
|
106
|
+
description: "fingerprint 优先于 blueprint,真实项目指纹出现后重新评估",
|
|
107
|
+
override_behavior: "overridden",
|
|
108
|
+
requires_report: true,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: "pr-07",
|
|
112
|
+
higher_source: "fingerprint",
|
|
113
|
+
lower_source: "product_profile",
|
|
114
|
+
description: "fingerprint 优先于 product_profile 默认",
|
|
115
|
+
override_behavior: "overridden",
|
|
116
|
+
requires_report: false,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: "pr-08",
|
|
120
|
+
higher_source: "fingerprint",
|
|
121
|
+
lower_source: "knowledge_default",
|
|
122
|
+
description: "fingerprint 优先于 knowledge_default",
|
|
123
|
+
override_behavior: "overridden",
|
|
124
|
+
requires_report: false,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: "pr-09",
|
|
128
|
+
higher_source: "product_profile",
|
|
129
|
+
lower_source: "knowledge_default",
|
|
130
|
+
description: "product_profile 优先于 knowledge_default",
|
|
131
|
+
override_behavior: "overridden",
|
|
132
|
+
requires_report: false,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: "pr-10",
|
|
136
|
+
higher_source: "knowledge_default",
|
|
137
|
+
lower_source: "global_default",
|
|
138
|
+
description: "knowledge_default 优先于 global_default",
|
|
139
|
+
override_behavior: "overridden",
|
|
140
|
+
requires_report: false,
|
|
141
|
+
},
|
|
142
|
+
];
|
|
143
|
+
const STALE_RULES = [
|
|
144
|
+
{
|
|
145
|
+
id: "stale-01",
|
|
146
|
+
trigger: "config_vs_fingerprint_mismatch",
|
|
147
|
+
severity: "warning",
|
|
148
|
+
description: "confirmed_config 与 fingerprint 冲突",
|
|
149
|
+
action: "不自动覆盖 confirmed_config,产生 stale/conflict report",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id: "stale-02",
|
|
153
|
+
trigger: "fingerprint_drift",
|
|
154
|
+
severity: "warning",
|
|
155
|
+
description: "fingerprint 发生变化(如 React→Vue),config 仍是旧值",
|
|
156
|
+
action: "产生 stale warning,不自动覆盖",
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: "stale-03",
|
|
160
|
+
trigger: "config_vs_blueprint_mismatch",
|
|
161
|
+
severity: "warning",
|
|
162
|
+
description: "blueprint 在空项目初期有效,真实项目指纹出现后应重新评估",
|
|
163
|
+
action: "提示重新评估,blueprint 降为 advisory",
|
|
164
|
+
},
|
|
165
|
+
];
|
|
166
|
+
// ── 查询函数 ──
|
|
167
|
+
/** 列出所有配置优先级规则
|
|
168
|
+
* @returns 优先级规则数组
|
|
169
|
+
*/
|
|
170
|
+
export function listPrecedenceRules() {
|
|
171
|
+
return PRECEDENCE_RULES;
|
|
172
|
+
}
|
|
173
|
+
/** 列出所有配置过期检测规则
|
|
174
|
+
* @returns 过期规则数组
|
|
175
|
+
*/
|
|
176
|
+
export function listStaleRules() {
|
|
177
|
+
return STALE_RULES;
|
|
178
|
+
}
|
|
179
|
+
/** 获取配置来源的优先级排名(数值越小优先级越高)
|
|
180
|
+
* @param source - 配置来源
|
|
181
|
+
* @returns 优先级排名索引
|
|
182
|
+
*/
|
|
183
|
+
export function getPrecedenceRank(source) {
|
|
184
|
+
return PRECEDENCE_ORDER.indexOf(source);
|
|
185
|
+
}
|
|
186
|
+
/** 获取配置来源的生命周期
|
|
187
|
+
* @param source - 配置来源
|
|
188
|
+
* @returns 生命周期类型
|
|
189
|
+
*/
|
|
190
|
+
export function getSourceLifetime(source) {
|
|
191
|
+
return SOURCE_LIFETIME[source];
|
|
192
|
+
}
|
|
193
|
+
/** 判断来源 a 的优先级是否高于来源 b
|
|
194
|
+
* @param a - 配置来源 a
|
|
195
|
+
* @param b - 配置来源 b
|
|
196
|
+
* @returns a 是否优先级更高
|
|
197
|
+
*/
|
|
198
|
+
export function isHigherPriority(a, b) {
|
|
199
|
+
return getPrecedenceRank(a) < getPrecedenceRank(b);
|
|
200
|
+
}
|
|
201
|
+
// ── 解析 ──
|
|
202
|
+
/** 解析单个配置字段 — 按优先级排序候选值并检测冲突
|
|
203
|
+
* @param fieldPath - 字段路径
|
|
204
|
+
* @param candidates - 候选值列表
|
|
205
|
+
* @returns 配置解析报告
|
|
206
|
+
*/
|
|
207
|
+
export function resolveConfigField(fieldPath, candidates) {
|
|
208
|
+
const sorted = [...candidates].sort((a, b) => getPrecedenceRank(a.source) - getPrecedenceRank(b.source));
|
|
209
|
+
const selected = sorted[0];
|
|
210
|
+
const conflicts = [];
|
|
211
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
212
|
+
const candidate = sorted[i];
|
|
213
|
+
if (JSON.stringify(candidate.value) !== JSON.stringify(selected.value)) {
|
|
214
|
+
conflicts.push({
|
|
215
|
+
source_a: selected.source,
|
|
216
|
+
source_b: candidate.source,
|
|
217
|
+
field_path: fieldPath,
|
|
218
|
+
reason: buildConflictReason(selected.source, candidate.source, fieldPath),
|
|
219
|
+
requires_human: candidate.source === "confirmed_config" && selected.source === "fingerprint"
|
|
220
|
+
? false
|
|
221
|
+
: isHighStakesField(fieldPath),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
field_path: fieldPath,
|
|
227
|
+
selected,
|
|
228
|
+
candidates: sorted,
|
|
229
|
+
conflicts,
|
|
230
|
+
lifetime: SOURCE_LIFETIME[selected.source],
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/** 解析所有配置字段
|
|
234
|
+
* @param fieldCandidates - 字段路径到候选值列表的映射
|
|
235
|
+
* @returns 所有字段的解析报告数组
|
|
236
|
+
*/
|
|
237
|
+
export function resolveAllFields(fieldCandidates) {
|
|
238
|
+
const reports = [];
|
|
239
|
+
for (const [fieldPath, candidates] of Object.entries(fieldCandidates)) {
|
|
240
|
+
if (candidates.length > 0) {
|
|
241
|
+
reports.push(resolveConfigField(fieldPath, candidates));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return reports;
|
|
245
|
+
}
|
|
246
|
+
/** 检查上位约束是否阻止该配置
|
|
247
|
+
* @param report - 配置解析报告
|
|
248
|
+
* @param guardId - 上位约束 ID
|
|
249
|
+
* @returns 约束检查结果
|
|
250
|
+
*/
|
|
251
|
+
export function checkGuardOverride(report, guardId) {
|
|
252
|
+
if (isGuardProtectedField(report.field_path, guardId)) {
|
|
253
|
+
console.error("[soloForge] 配置优先级: 字段 %s 被上位约束 %s 阻止", report.field_path, guardId);
|
|
254
|
+
return {
|
|
255
|
+
blocked: true,
|
|
256
|
+
report: {
|
|
257
|
+
...report,
|
|
258
|
+
overridden_by_guard: guardId,
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
return { blocked: false, report };
|
|
263
|
+
}
|
|
264
|
+
function isGuardProtectedField(fieldPath, guard) {
|
|
265
|
+
const GUARD_FIELDS = {
|
|
266
|
+
enforced_guard: ["*"],
|
|
267
|
+
privacy_secret_policy: ["delivery", "secrets", "accounts", "external_integrations"],
|
|
268
|
+
command_safety: ["destructive_command_policy", "verify_timeout"],
|
|
269
|
+
delivery_authorization: ["delivery.auto_push", "delivery.auto_pr", "delivery.deploy"],
|
|
270
|
+
data_sovereignty: ["core_knowledge", "compliance", "privacy_policy"],
|
|
271
|
+
destructive_action_gate: ["destructive_command_policy", "scope_exclusion"],
|
|
272
|
+
};
|
|
273
|
+
const protectedFields = GUARD_FIELDS[guard] ?? [];
|
|
274
|
+
if (protectedFields.includes("*"))
|
|
275
|
+
return true;
|
|
276
|
+
return protectedFields.some((f) => fieldPath.startsWith(f));
|
|
277
|
+
}
|
|
278
|
+
// ── 过期检测 ──
|
|
279
|
+
/** 检测配置是否过期 — 比较确认值与指纹值是否一致
|
|
280
|
+
* @param confirmedValue - 已确认的配置值
|
|
281
|
+
* @param fingerprintValue - 当前指纹值
|
|
282
|
+
* @returns 是否过期及警告信息
|
|
283
|
+
*/
|
|
284
|
+
export function detectStaleConfig(confirmedValue, fingerprintValue) {
|
|
285
|
+
if (confirmedValue.source !== "confirmed_config")
|
|
286
|
+
return { isStale: false, warning: "" };
|
|
287
|
+
if (fingerprintValue.source !== "fingerprint")
|
|
288
|
+
return { isStale: false, warning: "" };
|
|
289
|
+
if (JSON.stringify(confirmedValue.value) !== JSON.stringify(fingerprintValue.value)) {
|
|
290
|
+
console.error("[soloForge] 配置优先级: 字段 %s 配置过期,确认值与指纹不一致", confirmedValue.field_path);
|
|
291
|
+
return {
|
|
292
|
+
isStale: true,
|
|
293
|
+
warning: `config_stale_warning: ${confirmedValue.field_path} 的确认值 (${JSON.stringify(confirmedValue.value)}) 与当前 fingerprint (${JSON.stringify(fingerprintValue.value)}) 不一致 — 建议重新确认`,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
return { isStale: false, warning: "" };
|
|
297
|
+
}
|
|
298
|
+
// ── 字段分类写入规则 ──
|
|
299
|
+
/** C 类字段列表 — 仅允许人工确认写入,永不自动写入 */
|
|
300
|
+
export const C_CLASS_FIELDS = [
|
|
301
|
+
"product_mapping",
|
|
302
|
+
"delivery.auto_push",
|
|
303
|
+
"delivery.auto_pr",
|
|
304
|
+
"delivery.deploy",
|
|
305
|
+
"secrets",
|
|
306
|
+
"accounts",
|
|
307
|
+
"production_database",
|
|
308
|
+
"destructive_command_policy",
|
|
309
|
+
"external_integrations",
|
|
310
|
+
"compliance_policy",
|
|
311
|
+
"privacy_policy",
|
|
312
|
+
"core_knowledge_sovereignty",
|
|
313
|
+
];
|
|
314
|
+
/** 判断字段是否为 C 类字段
|
|
315
|
+
* @param fieldPath - 字段路径
|
|
316
|
+
* @returns 是否为 C 类字段
|
|
317
|
+
*/
|
|
318
|
+
export function isCClassField(fieldPath) {
|
|
319
|
+
return C_CLASS_FIELDS.some(f => fieldPath.startsWith(f));
|
|
320
|
+
}
|
|
321
|
+
/** 获取配置字段的分类(C 类或 B 类)
|
|
322
|
+
* @param fieldPath - 字段路径
|
|
323
|
+
* @param explicitClass - 显式指定的分类(可选)
|
|
324
|
+
* @returns 字段分类
|
|
325
|
+
*/
|
|
326
|
+
export function getConfigFieldClass(fieldPath, explicitClass) {
|
|
327
|
+
if (explicitClass)
|
|
328
|
+
return explicitClass;
|
|
329
|
+
if (isCClassField(fieldPath))
|
|
330
|
+
return "C";
|
|
331
|
+
return "B";
|
|
332
|
+
}
|
|
333
|
+
/** 判断字段是否允许自动写入
|
|
334
|
+
* @param fieldPath - 字段路径
|
|
335
|
+
* @param fieldClass - 字段分类
|
|
336
|
+
* @param source - 配置来源
|
|
337
|
+
* @returns 是否允许及原因
|
|
338
|
+
*/
|
|
339
|
+
export function canAutoWriteField(fieldPath, fieldClass, source) {
|
|
340
|
+
const canonical = mapEvidenceSource(source);
|
|
341
|
+
// C 类: 永不自动写入 (only confirmed_config allowed)
|
|
342
|
+
if (fieldClass === "C" || isCClassField(fieldPath)) {
|
|
343
|
+
if (canonical !== "confirmed_config") {
|
|
344
|
+
return { allowed: false, reason: `C 类字段 ${fieldPath} 不得自动写入,必须 user_declared 或 confirmed` };
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// B 类: 需要高置信 (confirmed_config or fingerprint)
|
|
348
|
+
if (fieldClass === "B") {
|
|
349
|
+
if (canonical !== "fingerprint" && canonical !== "confirmed_config") {
|
|
350
|
+
return { allowed: false, reason: `B 类字段 ${fieldPath} 需要高置信来源 (detected/user_declared/confirmed)` };
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// CLI flag 不静默写入 config
|
|
354
|
+
if (source === "cli_flag" || source === "mcp_param") {
|
|
355
|
+
return { allowed: false, reason: "CLI/MCP 参数不静默写入 config,仅对本次 invocation/task 有效" };
|
|
356
|
+
}
|
|
357
|
+
return { allowed: true, reason: "" };
|
|
358
|
+
}
|
|
359
|
+
// ── 证据来源映射 ──
|
|
360
|
+
/** 将证据元数据来源映射为规范配置来源
|
|
361
|
+
* @param source - 原始来源标识
|
|
362
|
+
* @returns 规范配置来源
|
|
363
|
+
*/
|
|
364
|
+
export function mapEvidenceSource(source) {
|
|
365
|
+
return EVIDENCE_SOURCE_MAP[source] ?? source;
|
|
366
|
+
}
|
|
367
|
+
// ── 证据工厂 ──
|
|
368
|
+
/** 创建配置值证据
|
|
369
|
+
* @param fieldPath - 字段路径
|
|
370
|
+
* @param value - 配置值
|
|
371
|
+
* @param source - 配置来源
|
|
372
|
+
* @param confidence - 置信度
|
|
373
|
+
* @param evidenceRef - 证据引用(可选)
|
|
374
|
+
* @returns 配置值证据
|
|
375
|
+
*/
|
|
376
|
+
export function createConfigValueEvidence(fieldPath, value, source, confidence, evidenceRef) {
|
|
377
|
+
return {
|
|
378
|
+
field_path: fieldPath,
|
|
379
|
+
value,
|
|
380
|
+
source,
|
|
381
|
+
confidence,
|
|
382
|
+
evidence_ref: evidenceRef,
|
|
383
|
+
updated_at: new Date().toISOString(),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
/** 创建配置证据条目
|
|
387
|
+
* @param fieldPath - 字段路径
|
|
388
|
+
* @param value - 配置值
|
|
389
|
+
* @param source - 配置来源
|
|
390
|
+
* @param options - 可选参数
|
|
391
|
+
* @param options.confidence - 置信度(可选,默认 1.0)
|
|
392
|
+
* @param options.evidence_refs - 证据引用列表(可选)
|
|
393
|
+
* @param options.confirmed_by - 确认者(可选)
|
|
394
|
+
* @param options.expires_at - 过期时间(可选)
|
|
395
|
+
* @returns 配置证据条目
|
|
396
|
+
*/
|
|
397
|
+
/**
|
|
398
|
+
* 创建配置证据条目。
|
|
399
|
+
* @param field - 配置字段名
|
|
400
|
+
* @param source - 证据来源
|
|
401
|
+
* @param value - 字段值
|
|
402
|
+
* @returns 证据条目
|
|
403
|
+
*/
|
|
404
|
+
export function createConfigEvidenceEntry(fieldPath, value, source, options) {
|
|
405
|
+
return {
|
|
406
|
+
field_path: fieldPath,
|
|
407
|
+
value_hash: hashValue(value),
|
|
408
|
+
source,
|
|
409
|
+
confidence: options?.confidence ?? 1.0,
|
|
410
|
+
evidence_refs: options?.evidence_refs ?? [],
|
|
411
|
+
confirmed_by: options?.confirmed_by,
|
|
412
|
+
lifetime: SOURCE_LIFETIME[source],
|
|
413
|
+
collected_at: new Date().toISOString(),
|
|
414
|
+
expires_at: options?.expires_at,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
/** 计算值的简易哈希
|
|
418
|
+
* @param value - 待哈希的值
|
|
419
|
+
* @returns 十六进制哈希字符串
|
|
420
|
+
*/
|
|
421
|
+
export function hashValue(value) {
|
|
422
|
+
const str = JSON.stringify(value);
|
|
423
|
+
return crypto.createHash("sha256").update(str).digest("hex").slice(0, 16);
|
|
424
|
+
}
|
|
425
|
+
// ── 中文解释 ──
|
|
426
|
+
/** 生成配置字段解析结果的中文解释
|
|
427
|
+
* @param report - 配置解析报告
|
|
428
|
+
* @returns 格式化的中文解释文本
|
|
429
|
+
*/
|
|
430
|
+
export function explainField(report) {
|
|
431
|
+
const lines = [];
|
|
432
|
+
const sel = report.selected;
|
|
433
|
+
lines.push(`字段: ${report.field_path}`);
|
|
434
|
+
lines.push(`当前值: ${JSON.stringify(sel.value)}`);
|
|
435
|
+
lines.push(`来源: ${sourceLabel(sel.source)} (优先级 ${getPrecedenceRank(sel.source) + 1}/${PRECEDENCE_ORDER.length})`);
|
|
436
|
+
lines.push(`生命周期: ${lifetimeLabel(report.lifetime)}`);
|
|
437
|
+
lines.push(`置信度: ${sel.confidence}`);
|
|
438
|
+
if (sel.evidence_ref) {
|
|
439
|
+
lines.push(`证据: ${sel.evidence_ref}`);
|
|
440
|
+
}
|
|
441
|
+
if (report.candidates.length > 1) {
|
|
442
|
+
lines.push(`其他候选:`);
|
|
443
|
+
for (let i = 1; i < report.candidates.length; i++) {
|
|
444
|
+
const c = report.candidates[i];
|
|
445
|
+
lines.push(` - ${sourceLabel(c.source)}: ${JSON.stringify(c.value)} (未被采用: ${notSelectedReason(report, c)})`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (report.overridden_by_guard) {
|
|
449
|
+
lines.push(`⚠️ 被上位约束 ${report.overridden_by_guard} 阻止`);
|
|
450
|
+
}
|
|
451
|
+
if (report.conflicts.length > 0) {
|
|
452
|
+
lines.push(`冲突:`);
|
|
453
|
+
for (const c of report.conflicts) {
|
|
454
|
+
lines.push(` - ${sourceLabel(c.source_a)} vs ${sourceLabel(c.source_b)}: ${c.reason}`);
|
|
455
|
+
if (c.requires_human) {
|
|
456
|
+
lines.push(` 需要人工确认`);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return lines.join("\n");
|
|
461
|
+
}
|
|
462
|
+
function sourceLabel(source) {
|
|
463
|
+
const labels = {
|
|
464
|
+
user_task: "用户本次指令",
|
|
465
|
+
cli_flag: "CLI 参数",
|
|
466
|
+
mcp_param: "MCP 参数",
|
|
467
|
+
confirmed_config: "已确认配置 (config.yaml)",
|
|
468
|
+
project_policy: "项目策略",
|
|
469
|
+
fingerprint: "文件指纹探测",
|
|
470
|
+
blueprint: "项目蓝图",
|
|
471
|
+
product_profile: "产品画像默认",
|
|
472
|
+
knowledge_default: "知识库默认",
|
|
473
|
+
global_default: "全局默认",
|
|
474
|
+
};
|
|
475
|
+
return labels[source];
|
|
476
|
+
}
|
|
477
|
+
function lifetimeLabel(lifetime) {
|
|
478
|
+
const labels = {
|
|
479
|
+
single_invocation: "单次调用",
|
|
480
|
+
task: "本次任务",
|
|
481
|
+
project_persistent: "项目持久",
|
|
482
|
+
global: "全局",
|
|
483
|
+
};
|
|
484
|
+
return labels[lifetime];
|
|
485
|
+
}
|
|
486
|
+
function notSelectedReason(report, candidate) {
|
|
487
|
+
const selectedRank = getPrecedenceRank(report.selected.source);
|
|
488
|
+
const candidateRank = getPrecedenceRank(candidate.source);
|
|
489
|
+
if (candidateRank > selectedRank) {
|
|
490
|
+
return `优先级低于 ${sourceLabel(report.selected.source)}`;
|
|
491
|
+
}
|
|
492
|
+
return "值相同,无冲突";
|
|
493
|
+
}
|
|
494
|
+
function buildConflictReason(higher, lower, fieldPath) {
|
|
495
|
+
return `${sourceLabel(higher)} 与 ${sourceLabel(lower)} 在字段 ${fieldPath} 上存在冲突`;
|
|
496
|
+
}
|
|
497
|
+
function isHighStakesField(fieldPath) {
|
|
498
|
+
const highStakes = [
|
|
499
|
+
"delivery", "scope", "product_profile", "secrets", "accounts",
|
|
500
|
+
"production_database", "destructive_command_policy", "compliance",
|
|
501
|
+
];
|
|
502
|
+
return highStakes.some((f) => fieldPath.startsWith(f));
|
|
503
|
+
}
|
|
504
|
+
// ── CLI 参数写入守卫 ──
|
|
505
|
+
/** 判断来源是否可安全写入配置(非 CLI/MCP 临时参数)
|
|
506
|
+
* @param source - 配置来源
|
|
507
|
+
* @returns 是否可安全写入
|
|
508
|
+
*/
|
|
509
|
+
export function isCliWriteSafe(source) {
|
|
510
|
+
return source !== "cli_flag" && source !== "mcp_param";
|
|
511
|
+
}
|
|
512
|
+
// ── 治理校验 ──
|
|
513
|
+
/** 执行配置优先级治理校验
|
|
514
|
+
* @param reports - 配置解析报告列表
|
|
515
|
+
* @param entries - 配置证据条目列表
|
|
516
|
+
* @returns 治理发现列表
|
|
517
|
+
*/
|
|
518
|
+
export function validateConfigPrecedence(reports, entries) {
|
|
519
|
+
console.error("[soloForge] 配置优先级: 开始治理校验,共 %d 个报告", reports.length);
|
|
520
|
+
const findings = [];
|
|
521
|
+
// 规则 1: CLI flag 不静默写入 config
|
|
522
|
+
for (const e of entries) {
|
|
523
|
+
if (e.source === "cli_flag" || e.source === "mcp_param") {
|
|
524
|
+
if (e.lifetime === "project_persistent") {
|
|
525
|
+
findings.push({
|
|
526
|
+
severity: "hard_fail",
|
|
527
|
+
rule: "gc-cli-no-persist",
|
|
528
|
+
field_path: e.field_path,
|
|
529
|
+
message: `CLI/MCP 参数 (${e.source}) 不应持久化到 config — ${e.field_path}`,
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
// 规则 2: fingerprint 不覆盖 confirmed_config
|
|
535
|
+
for (const r of reports) {
|
|
536
|
+
if (r.selected.source === "fingerprint") {
|
|
537
|
+
const hasConfirmed = r.candidates.some((c) => c.source === "confirmed_config");
|
|
538
|
+
if (hasConfirmed) {
|
|
539
|
+
findings.push({
|
|
540
|
+
severity: "hard_fail",
|
|
541
|
+
rule: "gc-fingerprint-no-override",
|
|
542
|
+
field_path: r.field_path,
|
|
543
|
+
message: `fingerprint 不应覆盖 confirmed_config — ${r.field_path}`,
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
// 规则 3: product_profile 不覆盖 config
|
|
549
|
+
for (const r of reports) {
|
|
550
|
+
if (r.selected.source === "product_profile") {
|
|
551
|
+
const hasConfirmed = r.candidates.some((c) => c.source === "confirmed_config");
|
|
552
|
+
if (hasConfirmed) {
|
|
553
|
+
findings.push({
|
|
554
|
+
severity: "hard_fail",
|
|
555
|
+
rule: "gc-profile-no-override",
|
|
556
|
+
field_path: r.field_path,
|
|
557
|
+
message: `product_profile 不应覆盖 confirmed_config — ${r.field_path}`,
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
// 规则 4: knowledge_default 不覆盖 config
|
|
563
|
+
for (const r of reports) {
|
|
564
|
+
if (r.selected.source === "knowledge_default") {
|
|
565
|
+
const hasConfig = r.candidates.some((c) => c.source === "confirmed_config" || c.source === "project_policy");
|
|
566
|
+
if (hasConfig) {
|
|
567
|
+
findings.push({
|
|
568
|
+
severity: "hard_fail",
|
|
569
|
+
rule: "gc-knowledge-no-override",
|
|
570
|
+
field_path: r.field_path,
|
|
571
|
+
message: `knowledge_default 不应覆盖 config — ${r.field_path}`,
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
// 规则 5: C 类字段不得自动写入 — only confirmed_config (from user_declared/confirmed) allowed
|
|
577
|
+
for (const e of entries) {
|
|
578
|
+
if (isCClassField(e.field_path)) {
|
|
579
|
+
const canonical = mapEvidenceSource(e.source);
|
|
580
|
+
if (canonical !== "confirmed_config") {
|
|
581
|
+
findings.push({
|
|
582
|
+
severity: "hard_fail",
|
|
583
|
+
rule: "gc-c-class-no-auto",
|
|
584
|
+
field_path: e.field_path,
|
|
585
|
+
message: `C 类字段 ${e.field_path} 不得自动写入 (当前来源: ${e.source})`,
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
// 规则 6: guard 不可被配置绕过 — check that guard-blocked fields stay blocked
|
|
591
|
+
for (const r of reports) {
|
|
592
|
+
if (r.overridden_by_guard) {
|
|
593
|
+
findings.push({
|
|
594
|
+
severity: "advisory",
|
|
595
|
+
rule: "gc-guard-block",
|
|
596
|
+
field_path: r.field_path,
|
|
597
|
+
message: `字段 ${r.field_path} 被上位约束 ${r.overridden_by_guard} 保护`,
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
// 规则 7: conflict 必须被报告 (advisory)
|
|
602
|
+
for (const r of reports) {
|
|
603
|
+
if (r.conflicts.length > 0) {
|
|
604
|
+
const configFpConflict = r.conflicts.find((c) => c.source_a === "confirmed_config" && c.source_b === "fingerprint");
|
|
605
|
+
if (configFpConflict) {
|
|
606
|
+
findings.push({
|
|
607
|
+
severity: "advisory",
|
|
608
|
+
rule: "gc-conflict-report",
|
|
609
|
+
field_path: r.field_path,
|
|
610
|
+
message: `字段 ${r.field_path} 存在 confirmed_config 与 fingerprint 冲突,已自动处理`,
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
// 规则 9: value_hash 不匹配 — 证据条目的 hash 必须与解析值一致
|
|
616
|
+
for (const r of reports) {
|
|
617
|
+
const entry = entries.find((e) => e.field_path === r.field_path);
|
|
618
|
+
if (entry) {
|
|
619
|
+
const computed = hashValue(r.selected.value);
|
|
620
|
+
if (entry.value_hash !== computed) {
|
|
621
|
+
findings.push({
|
|
622
|
+
severity: "hard_fail",
|
|
623
|
+
rule: "gc-evidence-hash-mismatch",
|
|
624
|
+
field_path: r.field_path,
|
|
625
|
+
message: `字段 ${r.field_path} evidence value_hash 不匹配 (entry=${entry.value_hash}, computed=${computed}) — evidence 可能过期`,
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
// 规则 10: blueprint 与 fingerprint/confirmed_config 不一致 (advisory)
|
|
631
|
+
for (const r of reports) {
|
|
632
|
+
const blueprintCandidate = r.candidates.find((c) => c.source === "blueprint");
|
|
633
|
+
if (!blueprintCandidate)
|
|
634
|
+
continue;
|
|
635
|
+
const higherCandidate = r.candidates.find((c) => c.source === "fingerprint" || c.source === "confirmed_config");
|
|
636
|
+
if (!higherCandidate)
|
|
637
|
+
continue;
|
|
638
|
+
if (JSON.stringify(blueprintCandidate.value) !== JSON.stringify(higherCandidate.value)) {
|
|
639
|
+
findings.push({
|
|
640
|
+
severity: "advisory",
|
|
641
|
+
rule: "gc-blueprint-mismatch",
|
|
642
|
+
field_path: r.field_path,
|
|
643
|
+
message: `字段 ${r.field_path} blueprint (${JSON.stringify(blueprintCandidate.value)}) 与 ${higherCandidate.source} (${JSON.stringify(higherCandidate.value)}) 不一致 — blueprint 可能需要更新`,
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
// 规则 8: 每个 resolved 字段应有 evidence
|
|
648
|
+
for (const r of reports) {
|
|
649
|
+
const hasEntry = entries.some((e) => e.field_path === r.field_path);
|
|
650
|
+
if (!hasEntry) {
|
|
651
|
+
findings.push({
|
|
652
|
+
severity: "advisory",
|
|
653
|
+
rule: "gc-evidence-required",
|
|
654
|
+
field_path: r.field_path,
|
|
655
|
+
message: `字段 ${r.field_path} 已解析但缺少 ConfigEvidenceEntry`,
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (findings.length > 0) {
|
|
660
|
+
const hardFails = findings.filter(f => f.severity === "hard_fail");
|
|
661
|
+
if (hardFails.length > 0) {
|
|
662
|
+
console.error("[soloForge] 配置优先级: 治理校验发现 %d 个 hard_fail", hardFails.length);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return findings;
|
|
666
|
+
}
|
|
667
|
+
// ── 中文冲突报告 ──
|
|
668
|
+
/** 生成配置冲突的中文报告
|
|
669
|
+
* @param report - 配置解析报告
|
|
670
|
+
* @returns 格式化的冲突报告文本
|
|
671
|
+
*/
|
|
672
|
+
export function buildConflictReport(report) {
|
|
673
|
+
const lines = [];
|
|
674
|
+
lines.push(`配置冲突报告: ${report.field_path}`);
|
|
675
|
+
lines.push(`当前采用: ${sourceLabel(report.selected.source)} = ${JSON.stringify(report.selected.value)}`);
|
|
676
|
+
lines.push(`生命周期: ${lifetimeLabel(report.lifetime)}`);
|
|
677
|
+
for (const c of report.conflicts) {
|
|
678
|
+
lines.push(`冲突: ${sourceLabel(c.source_a)} vs ${sourceLabel(c.source_b)}`);
|
|
679
|
+
lines.push(` 原因: ${c.reason}`);
|
|
680
|
+
if (c.requires_human) {
|
|
681
|
+
lines.push(` ⚠️ 需要人工确认`);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
if (report.overridden_by_guard) {
|
|
685
|
+
lines.push(`⚠️ 被上位约束 ${report.overridden_by_guard} 阻止`);
|
|
686
|
+
}
|
|
687
|
+
lines.push(`建议: ${buildResolutionAdvice(report)}`);
|
|
688
|
+
return lines.join("\n");
|
|
689
|
+
}
|
|
690
|
+
function buildResolutionAdvice(report) {
|
|
691
|
+
if (report.overridden_by_guard) {
|
|
692
|
+
return "上位约束生效,不可通过配置修改";
|
|
693
|
+
}
|
|
694
|
+
if (report.selected.source === "user_task") {
|
|
695
|
+
return "本次用户指令优先,仅对本次任务生效,不写入 config";
|
|
696
|
+
}
|
|
697
|
+
if (report.selected.source === "cli_flag" || report.selected.source === "mcp_param") {
|
|
698
|
+
return "CLI/MCP 参数仅对本次调用生效,不写入 config。如需持久化请使用 config confirm";
|
|
699
|
+
}
|
|
700
|
+
if (report.conflicts.some((c) => c.source_b === "fingerprint")) {
|
|
701
|
+
return "fingerprint 变化未自动覆盖 confirmed_config。如需更新请使用 soloforge init --interactive";
|
|
702
|
+
}
|
|
703
|
+
return "当前配置已正确解析";
|
|
704
|
+
}
|
|
705
|
+
export function resolveConfigFromSources(fields) {
|
|
706
|
+
const resolutions = [];
|
|
707
|
+
const reports = [];
|
|
708
|
+
const warnings = [];
|
|
709
|
+
for (const [fieldPath, rawSources] of Object.entries(fields)) {
|
|
710
|
+
let candidates;
|
|
711
|
+
// 检测旧格式与新 FieldCandidates 格式
|
|
712
|
+
if (Array.isArray(rawSources)) {
|
|
713
|
+
candidates = rawSources;
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
// 旧格式: { config_value, fingerprint_value, user_override }
|
|
717
|
+
const sources = rawSources;
|
|
718
|
+
candidates = [];
|
|
719
|
+
if (sources.user_override !== undefined) {
|
|
720
|
+
candidates.push(createConfigValueEvidence(fieldPath, sources.user_override, "user_task", 1.0));
|
|
721
|
+
}
|
|
722
|
+
if (sources.config_value !== undefined) {
|
|
723
|
+
candidates.push(createConfigValueEvidence(fieldPath, sources.config_value, "confirmed_config", 0.9));
|
|
724
|
+
}
|
|
725
|
+
if (sources.fingerprint_value !== undefined) {
|
|
726
|
+
candidates.push(createConfigValueEvidence(fieldPath, sources.fingerprint_value, "fingerprint", 0.8));
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
if (candidates.length === 0)
|
|
730
|
+
continue;
|
|
731
|
+
const report = resolveConfigField(fieldPath, candidates);
|
|
732
|
+
reports.push(report);
|
|
733
|
+
const resolution = {
|
|
734
|
+
field_path: fieldPath,
|
|
735
|
+
resolved_value: report.selected.value,
|
|
736
|
+
source: report.selected.source,
|
|
737
|
+
};
|
|
738
|
+
// 检测过期: confirmed_config 与 fingerprint 不一致
|
|
739
|
+
const configEv = candidates.find(c => c.source === "confirmed_config");
|
|
740
|
+
const fpEv = candidates.find(c => c.source === "fingerprint");
|
|
741
|
+
if (configEv && fpEv) {
|
|
742
|
+
const stale = detectStaleConfig(configEv, fpEv);
|
|
743
|
+
if (stale.isStale) {
|
|
744
|
+
resolution.stale_warning = stale.warning;
|
|
745
|
+
warnings.push(stale.warning);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
if (report.conflicts.length > 0) {
|
|
749
|
+
resolution.conflict_report = buildConflictReport(report);
|
|
750
|
+
}
|
|
751
|
+
resolutions.push(resolution);
|
|
752
|
+
}
|
|
753
|
+
return { resolutions, reports, warnings };
|
|
754
|
+
}
|
|
755
|
+
const DEFAULT_CONFIG_FIELDS = [
|
|
756
|
+
"product_profile",
|
|
757
|
+
"tech_stack.backend.framework",
|
|
758
|
+
"tech_stack.frontend.framework",
|
|
759
|
+
];
|
|
760
|
+
/**
|
|
761
|
+
* 共享函数,解析当前项目配置。
|
|
762
|
+
* 读取 config.yaml、实时指纹、证据条目,并接受所有候选来源。
|
|
763
|
+
* expand()、配置解析/解释、校验、状态、治理都必须复用此函数 — 不可重复逻辑。
|
|
764
|
+
*
|
|
765
|
+
* 证据条目不是候选值 — 仅用于校验:
|
|
766
|
+
* 检查来源/生命周期合规性和 value_hash 匹配。
|
|
767
|
+
*
|
|
768
|
+
* product_profile: fingerprint 候选仅来自确定性产品证据
|
|
769
|
+
* (package.json soloforge.product_profile),不使用技术形态推断。
|
|
770
|
+
*/
|
|
771
|
+
export async function resolveCurrentProjectConfigReports(projectPath, options) {
|
|
772
|
+
console.error("[soloForge] 配置优先级: 开始解析项目配置");
|
|
773
|
+
const { resolveProjectConfig } = await import("../knowledge/loader.js");
|
|
774
|
+
const { detectFingerprint } = await import("./zero_config_init.js");
|
|
775
|
+
const { loadConfigEvidenceEntries } = await import("../bin/config_commands.js");
|
|
776
|
+
const { config } = await resolveProjectConfig(projectPath);
|
|
777
|
+
let fp = null;
|
|
778
|
+
try {
|
|
779
|
+
fp = await detectFingerprint(projectPath);
|
|
780
|
+
}
|
|
781
|
+
catch (e) {
|
|
782
|
+
console.error("[soloForge] 配置优先级: 项目指纹检测失败 —", e);
|
|
783
|
+
}
|
|
784
|
+
// 证据条目仅用于校验 — 不作为候选值
|
|
785
|
+
const entries = loadConfigEvidenceEntries(projectPath);
|
|
786
|
+
const fields = options?.fields ?? DEFAULT_CONFIG_FIELDS;
|
|
787
|
+
const fieldCandidates = {};
|
|
788
|
+
for (const fieldPath of fields) {
|
|
789
|
+
const candidates = [];
|
|
790
|
+
// 1. user_task 覆盖 (最高优先级)
|
|
791
|
+
if (options?.user_task_overrides?.[fieldPath] !== undefined) {
|
|
792
|
+
candidates.push(createConfigValueEvidence(fieldPath, options.user_task_overrides[fieldPath], "user_task", 1.0, "user intent"));
|
|
793
|
+
}
|
|
794
|
+
// 2. cli_flag 覆盖
|
|
795
|
+
if (options?.cli_overrides?.[fieldPath] !== undefined) {
|
|
796
|
+
candidates.push(createConfigValueEvidence(fieldPath, options.cli_overrides[fieldPath], "cli_flag", 1.0, "cli flag"));
|
|
797
|
+
}
|
|
798
|
+
// 3. mcp_param 覆盖
|
|
799
|
+
if (options?.mcp_overrides?.[fieldPath] !== undefined) {
|
|
800
|
+
candidates.push(createConfigValueEvidence(fieldPath, options.mcp_overrides[fieldPath], "mcp_param", 1.0, "mcp param"));
|
|
801
|
+
}
|
|
802
|
+
// 4. confirmed_config 来自 config.yaml
|
|
803
|
+
const configVal = getConfigFieldValue(config, fieldPath);
|
|
804
|
+
if (configVal !== undefined) {
|
|
805
|
+
candidates.push(createConfigValueEvidence(fieldPath, configVal, "confirmed_config", 0.9, "config.yaml"));
|
|
806
|
+
}
|
|
807
|
+
// 5. project_policy — 从 .soloforge/policy.yaml 加载 (如存在)
|
|
808
|
+
const policyVal = loadProjectPolicyField(projectPath, fieldPath);
|
|
809
|
+
if (policyVal !== undefined) {
|
|
810
|
+
candidates.push(createConfigValueEvidence(fieldPath, policyVal, "project_policy", 0.85, "policy.yaml"));
|
|
811
|
+
}
|
|
812
|
+
// 6. fingerprint — 不用于 product_profile (不进行技术形态推断)
|
|
813
|
+
if (fp && fieldPath !== "product_profile") {
|
|
814
|
+
const fpVal = getFingerprintFieldValue(fp, fieldPath);
|
|
815
|
+
if (fpVal !== undefined) {
|
|
816
|
+
candidates.push(createConfigValueEvidence(fieldPath, fpVal, "fingerprint", 0.8, "file detection"));
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
// product_profile: 仅使用 package.json soloforge.product_profile 的确定性证据
|
|
820
|
+
if (fp && fieldPath === "product_profile") {
|
|
821
|
+
const productEvidence = detectProductEvidenceFromFingerprint(fp);
|
|
822
|
+
if (productEvidence !== null) {
|
|
823
|
+
candidates.push(createConfigValueEvidence(fieldPath, productEvidence.value, "fingerprint", 0.8, productEvidence.evidence[0]));
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
// 7. blueprint — 从 .soloforge/blueprint.yaml 加载 (如存在)
|
|
827
|
+
const blueprintVal = loadBlueprintField(projectPath, fieldPath);
|
|
828
|
+
if (blueprintVal !== undefined) {
|
|
829
|
+
candidates.push(createConfigValueEvidence(fieldPath, blueprintVal, "blueprint", 0.6, "blueprint"));
|
|
830
|
+
}
|
|
831
|
+
// 8. product_profile 作为默认值 — 仅在其他候选均未提供值时使用
|
|
832
|
+
// (product_profile 来自知识文件,非技术形态)
|
|
833
|
+
if (fieldPath === "product_profile" && candidates.length === 0) {
|
|
834
|
+
const profileDefault = loadProductProfileDefault(projectPath);
|
|
835
|
+
if (profileDefault !== undefined) {
|
|
836
|
+
candidates.push(createConfigValueEvidence(fieldPath, profileDefault, "product_profile", 0.4, "product profile default"));
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
// 9. knowledge_default (知识库默认)
|
|
840
|
+
const knowledgeDefault = loadKnowledgeDefault(projectPath, fieldPath);
|
|
841
|
+
if (knowledgeDefault !== undefined && candidates.length === 0) {
|
|
842
|
+
candidates.push(createConfigValueEvidence(fieldPath, knowledgeDefault, "knowledge_default", 0.3, "knowledge default"));
|
|
843
|
+
}
|
|
844
|
+
// 10. global_default — 硬编码回退值
|
|
845
|
+
const globalDefault = getGlobalDefault(fieldPath);
|
|
846
|
+
if (globalDefault !== undefined && candidates.length === 0) {
|
|
847
|
+
candidates.push(createConfigValueEvidence(fieldPath, globalDefault, "global_default", 0.1, "global default"));
|
|
848
|
+
}
|
|
849
|
+
fieldCandidates[fieldPath] = candidates;
|
|
850
|
+
}
|
|
851
|
+
const { resolutions, reports, warnings } = resolveConfigFromSources(fieldCandidates);
|
|
852
|
+
if (warnings.length > 0) {
|
|
853
|
+
console.error("[soloForge] 配置优先级: 发现 %d 个配置警告", warnings.length);
|
|
854
|
+
}
|
|
855
|
+
console.error("[soloForge] 配置优先级: 解析完成,共 %d 个字段", resolutions.length);
|
|
856
|
+
return { reports, resolutions, warnings, entries };
|
|
857
|
+
}
|
|
858
|
+
// ── 来源加载辅助函数 ──
|
|
859
|
+
function loadProjectPolicyField(projectPath, fieldPath) {
|
|
860
|
+
const policyPath = nodePath.join(projectPath, ".soloforge", "policy.yaml");
|
|
861
|
+
try {
|
|
862
|
+
const raw = nodeFs.readFileSync(policyPath, "utf-8");
|
|
863
|
+
const parsed = YAML.parse(raw);
|
|
864
|
+
return getConfigFieldValue(parsed ?? {}, fieldPath);
|
|
865
|
+
}
|
|
866
|
+
catch {
|
|
867
|
+
return undefined;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
function loadBlueprintField(projectPath, fieldPath) {
|
|
871
|
+
const blueprintPath = nodePath.join(projectPath, ".soloforge", "blueprint.yaml");
|
|
872
|
+
try {
|
|
873
|
+
const raw = nodeFs.readFileSync(blueprintPath, "utf-8");
|
|
874
|
+
const parsed = YAML.parse(raw);
|
|
875
|
+
return getConfigFieldValue(parsed ?? {}, fieldPath);
|
|
876
|
+
}
|
|
877
|
+
catch {
|
|
878
|
+
return undefined;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
function loadProductProfileDefault(projectPath) {
|
|
882
|
+
const profileDir = nodePath.join(projectPath, ".soloforge", "knowledge", "product_profiles");
|
|
883
|
+
try {
|
|
884
|
+
const files = nodeFs.readdirSync(profileDir).filter(f => f.endsWith(".md") || f.endsWith(".yaml"));
|
|
885
|
+
if (files.length > 0)
|
|
886
|
+
return files[0].replace(/.(md|yaml)$/, "");
|
|
887
|
+
}
|
|
888
|
+
catch { }
|
|
889
|
+
return undefined;
|
|
890
|
+
}
|
|
891
|
+
function loadKnowledgeDefault(projectPath, fieldPath) {
|
|
892
|
+
const defaultsPath = nodePath.join(projectPath, ".soloforge", "knowledge", "defaults.yaml");
|
|
893
|
+
try {
|
|
894
|
+
const raw = nodeFs.readFileSync(defaultsPath, "utf-8");
|
|
895
|
+
const parsed = YAML.parse(raw);
|
|
896
|
+
if (parsed && typeof parsed === "object")
|
|
897
|
+
return getConfigFieldValue(parsed, fieldPath);
|
|
898
|
+
}
|
|
899
|
+
catch { }
|
|
900
|
+
return undefined;
|
|
901
|
+
}
|
|
902
|
+
function getGlobalDefault(fieldPath) {
|
|
903
|
+
const defaults = {
|
|
904
|
+
"product_profile": "default",
|
|
905
|
+
};
|
|
906
|
+
return defaults[fieldPath];
|
|
907
|
+
}
|
|
908
|
+
function getConfigFieldValue(obj, fieldPath) {
|
|
909
|
+
const parts = fieldPath.split(".");
|
|
910
|
+
let current = obj;
|
|
911
|
+
for (const p of parts) {
|
|
912
|
+
if (current == null || typeof current !== "object")
|
|
913
|
+
return undefined;
|
|
914
|
+
current = current[p];
|
|
915
|
+
}
|
|
916
|
+
return current;
|
|
917
|
+
}
|
|
918
|
+
function getFingerprintFieldValue(fp, fieldPath) {
|
|
919
|
+
switch (fieldPath) {
|
|
920
|
+
case "tech_stack.backend.framework":
|
|
921
|
+
return fp.backend?.framework || undefined;
|
|
922
|
+
case "tech_stack.frontend.framework":
|
|
923
|
+
return fp.frontend?.framework || undefined;
|
|
924
|
+
default:
|
|
925
|
+
return undefined;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
function detectProductEvidenceFromFingerprint(fp) {
|
|
929
|
+
// 委托给 zero_config_init 的 detectProductEvidence
|
|
930
|
+
// 由于该函数未导出,此处复制其逻辑:
|
|
931
|
+
// 仅 package.json soloforge.product_profile 作为确定性证据
|
|
932
|
+
if (!fp.project_root)
|
|
933
|
+
return null;
|
|
934
|
+
const pkgPath = nodePath.join(fp.project_root, "package.json");
|
|
935
|
+
try {
|
|
936
|
+
const raw = nodeFs.readFileSync(pkgPath, "utf-8");
|
|
937
|
+
const data = JSON.parse(raw);
|
|
938
|
+
if (data.soloforge && typeof data.soloforge.product_profile === "string") {
|
|
939
|
+
const val = data.soloforge.product_profile;
|
|
940
|
+
if (val.length > 0) {
|
|
941
|
+
return { value: val, evidence: ["package.json soloforge.product_profile"] };
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
catch { }
|
|
946
|
+
return null;
|
|
947
|
+
}
|
|
948
|
+
//# sourceMappingURL=config_precedence_contract.js.map
|