soloforge 1.2.8 → 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/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//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 +1 -1
- 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
|
@@ -1,7 +1,53 @@
|
|
|
1
1
|
import Handlebars from "handlebars";
|
|
2
|
+
/**
|
|
3
|
+
* 意图膨胀器 — 将分类结果扩展为包含完整上下文的 AI 执行 prompt。
|
|
4
|
+
*
|
|
5
|
+
* 根据 route_decision.execution_shape 选择不同 prompt 模板:
|
|
6
|
+
* - code_execution_prompt: 代码修改任务
|
|
7
|
+
* - single_artifact_prompt: 单产物生成任务
|
|
8
|
+
* - source_extraction_prompt: 源码/材料提取任务
|
|
9
|
+
* - read_only_analysis_prompt: 只读分析任务
|
|
10
|
+
*/
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import fss from "node:fs";
|
|
14
|
+
import matter from "gray-matter";
|
|
2
15
|
import { detectConventions } from "./convention_detector.js";
|
|
3
|
-
|
|
4
|
-
|
|
16
|
+
import { selectPromptTemplate } from "./intent_router.js";
|
|
17
|
+
import { enforceKnowledgeInjectionBoundary, validateInjectionReport, getInjectedEntryIds } from "./knowledge_injection_boundary.js";
|
|
18
|
+
import { createInputMaterial, createIngestionEvidence, buildPromptInjectionPlan, classifyIngestionStatus, } from "./input_material_contract_registry.js";
|
|
19
|
+
import { resolveWorkflow } from "./workflow_contract_registry.js";
|
|
20
|
+
import { createOutputArtifact, getDefaultArtifactPath } from "./artifact_contract_registry.js";
|
|
21
|
+
import { findToolInvocationContractByName } from "./tool_invocation_contract_registry.js";
|
|
22
|
+
import { resolveCurrentProjectConfigReports } from "./config_precedence_contract.js";
|
|
23
|
+
import { evaluatePrivacyGate, redactSensitiveText, } from "./privacy_secret_contract.js";
|
|
24
|
+
import { getTaskLevel, getRequiredPrinciples, getEnforcementLevel, listCorePrinciples } from "./core_engineering_principles.js";
|
|
25
|
+
import { listMechanismLayerMaps } from "./dual_layer_mechanism_registry.js";
|
|
26
|
+
// 配置优先级:委托给 resolveCurrentProjectConfigReports (shared function)
|
|
27
|
+
// ── 产物类型映射 ──
|
|
28
|
+
function mapToArtifactKind(kind) {
|
|
29
|
+
if (kind === "unknown")
|
|
30
|
+
return "custom";
|
|
31
|
+
if (kind === "design_doc")
|
|
32
|
+
return "design_doc";
|
|
33
|
+
if (kind === "api_spec")
|
|
34
|
+
return "api_spec";
|
|
35
|
+
if (kind === "task_breakdown")
|
|
36
|
+
return "task_breakdown";
|
|
37
|
+
if (kind === "root_cause")
|
|
38
|
+
return "root_cause";
|
|
39
|
+
if (kind === "acceptance_checklist")
|
|
40
|
+
return "acceptance_checklist";
|
|
41
|
+
if (kind === "interaction_spec")
|
|
42
|
+
return "interaction_spec";
|
|
43
|
+
if (kind === "domain_model")
|
|
44
|
+
return "domain_model";
|
|
45
|
+
// 其他类型均为合法的 ArtifactKind 值
|
|
46
|
+
return kind;
|
|
47
|
+
}
|
|
48
|
+
// ── Prompt 模板 ──
|
|
49
|
+
// 1. code_execution_prompt: 允许修改业务源码,需要 scope 和验证
|
|
50
|
+
const CODE_EXECUTION_TEMPLATE = Handlebars.compile(`## 任务
|
|
5
51
|
{{intent}}
|
|
6
52
|
|
|
7
53
|
## 项目上下文
|
|
@@ -58,83 +104,747 @@ const PROMPT_TEMPLATE = Handlebars.compile(`## 任务
|
|
|
58
104
|
**注意**: 当前无领域知识匹配,请保守操作,只修改必要文件。
|
|
59
105
|
{{/if}}
|
|
60
106
|
`);
|
|
107
|
+
// 2. single_artifact_prompt: 默认不允许修改业务源码,必须有 output_artifact.path
|
|
108
|
+
const SINGLE_ARTIFACT_TEMPLATE = Handlebars.compile(`## 任务
|
|
109
|
+
{{intent}}
|
|
110
|
+
|
|
111
|
+
## 产物要求
|
|
112
|
+
- 产物类型: {{output_artifact.kind}}
|
|
113
|
+
- 输出路径: {{output_artifact.path}}
|
|
114
|
+
{{#if output_artifact.template}}
|
|
115
|
+
- 参考模板: {{output_artifact.template}}
|
|
116
|
+
{{/if}}
|
|
117
|
+
|
|
118
|
+
## 项目上下文
|
|
119
|
+
- 技术栈: {{tech_stack}}
|
|
120
|
+
- 产品类型: {{product_profile}}
|
|
121
|
+
|
|
122
|
+
{{#if matched_knowledge}}
|
|
123
|
+
## 适用知识
|
|
124
|
+
{{#each matched_knowledge}}
|
|
125
|
+
### {{this.name}}
|
|
126
|
+
{{this.content}}
|
|
127
|
+
|
|
128
|
+
{{/each}}
|
|
129
|
+
{{/if}}
|
|
130
|
+
|
|
131
|
+
## 约束
|
|
132
|
+
- 默认不允许修改业务源码
|
|
133
|
+
- 只允许写入指定产物路径
|
|
134
|
+
- 产物必须结构完整、证据充分、可交接
|
|
135
|
+
|
|
136
|
+
## 验收标准
|
|
137
|
+
{{#if acceptance.automated}}
|
|
138
|
+
### 自动验证
|
|
139
|
+
{{#each acceptance.automated}}
|
|
140
|
+
- [{{this.id}}] {{this.description}}
|
|
141
|
+
{{/each}}
|
|
142
|
+
{{/if}}
|
|
143
|
+
### 人工验证
|
|
144
|
+
- 产物完整性: 章节齐全,无空白占位
|
|
145
|
+
- 证据充分: 关键结论有引用或出处
|
|
146
|
+
- 可交接性: 下游可基于此产物继续工作
|
|
147
|
+
|
|
148
|
+
{{#if degraded}}
|
|
149
|
+
**注意**: 当前无专用模板,请按同类通用产物结构输出。
|
|
150
|
+
{{/if}}
|
|
151
|
+
`);
|
|
152
|
+
// 3. source_extraction_prompt: 只读输入材料,不允许修改项目源码
|
|
153
|
+
const SOURCE_EXTRACTION_TEMPLATE = Handlebars.compile(`## 任务
|
|
154
|
+
{{intent}}
|
|
155
|
+
|
|
156
|
+
## 输入材料
|
|
157
|
+
{{#each input_materials}}
|
|
158
|
+
- 类型: {{this.kind}}{{#if this.path}},路径: {{this.path}}{{/if}}{{#if this.ingestion_status}},状态: {{this.ingestion_status}}{{/if}}(只读)
|
|
159
|
+
{{/each}}
|
|
160
|
+
|
|
161
|
+
{{#if input_material_contract_notes}}
|
|
162
|
+
## 输入材料契约检查
|
|
163
|
+
{{#each input_material_contract_notes}}
|
|
164
|
+
- {{this}}
|
|
165
|
+
{{/each}}
|
|
166
|
+
{{/if}}
|
|
167
|
+
|
|
168
|
+
## 产物要求
|
|
169
|
+
- 产物类型: {{output_artifact.kind}}
|
|
170
|
+
- 输出路径: {{output_artifact.path}}
|
|
171
|
+
{{#if output_artifact.template}}
|
|
172
|
+
- 参考模板: {{output_artifact.template}}
|
|
173
|
+
{{/if}}
|
|
174
|
+
{{#if pipeline_hint}}
|
|
175
|
+
- 流程提示: {{pipeline_hint}}
|
|
176
|
+
{{/if}}
|
|
177
|
+
|
|
178
|
+
{{#if matched_knowledge}}
|
|
179
|
+
## 适用知识
|
|
180
|
+
{{#each matched_knowledge}}
|
|
181
|
+
### {{this.name}}
|
|
182
|
+
{{this.content}}
|
|
183
|
+
|
|
184
|
+
{{/each}}
|
|
185
|
+
{{/if}}
|
|
186
|
+
|
|
187
|
+
## 约束
|
|
188
|
+
- 输入材料只读,不得修改
|
|
189
|
+
- 不允许修改项目业务源码 (src/)
|
|
190
|
+
- 可将 zip 解压到临时目录读取
|
|
191
|
+
- 源码中无法确认的信息必须标记 [Manual Confirm]
|
|
192
|
+
- 必须标注证据来源(哪个文件/哪段代码)
|
|
193
|
+
- 禁止使用 Figma MCP、浏览器运行态、figma.site、截图或纯 Design 文件补充信息
|
|
194
|
+
|
|
195
|
+
## 验收标准
|
|
196
|
+
### 产物完整性
|
|
197
|
+
- 产物结构完整、章节齐全
|
|
198
|
+
- 每条信息有源码出处
|
|
199
|
+
- 缺失信息标记 [Manual Confirm]
|
|
200
|
+
|
|
201
|
+
{{#if degraded}}
|
|
202
|
+
**注意**: 当前无专用模板,请按通用提取产物结构输出。
|
|
203
|
+
{{/if}}
|
|
204
|
+
`);
|
|
205
|
+
// 4. read_only_analysis_prompt: 只读分析,默认不写文件
|
|
206
|
+
const READ_ONLY_ANALYSIS_TEMPLATE = Handlebars.compile(`## 任务
|
|
207
|
+
{{intent}}
|
|
208
|
+
|
|
209
|
+
## 项目上下文
|
|
210
|
+
- 技术栈: {{tech_stack}}
|
|
211
|
+
- 产品类型: {{product_profile}}
|
|
212
|
+
|
|
213
|
+
{{#if matched_knowledge}}
|
|
214
|
+
## 适用知识
|
|
215
|
+
{{#each matched_knowledge}}
|
|
216
|
+
### {{this.name}}
|
|
217
|
+
{{this.content}}
|
|
218
|
+
|
|
219
|
+
{{/each}}
|
|
220
|
+
{{/if}}
|
|
221
|
+
|
|
222
|
+
## 约束
|
|
223
|
+
- 默认不允许修改业务源码
|
|
224
|
+
- 只读分析当前项目或指定材料
|
|
225
|
+
- 输出结论、证据、风险和建议
|
|
226
|
+
- 默认不写文件,除非明确指定输出路径
|
|
227
|
+
|
|
228
|
+
{{#if output_artifact}}
|
|
229
|
+
## 输出要求
|
|
230
|
+
- 输出路径: {{output_artifact.path}}
|
|
231
|
+
{{/if}}
|
|
232
|
+
|
|
233
|
+
## 分析要求
|
|
234
|
+
- 给出明确结论
|
|
235
|
+
- 列出支撑证据
|
|
236
|
+
- 标注风险和假设
|
|
237
|
+
- 给出建议(如有)
|
|
238
|
+
`);
|
|
239
|
+
// 5. verification_only_prompt: 验证命令生成,不修改源码
|
|
240
|
+
const VERIFICATION_ONLY_TEMPLATE = Handlebars.compile(`## 任务
|
|
241
|
+
{{intent}}
|
|
242
|
+
|
|
243
|
+
## 验证目标
|
|
244
|
+
{{#if relevant_files}}
|
|
245
|
+
### 相关文件
|
|
246
|
+
{{#each relevant_files}}
|
|
247
|
+
- {{this.path}} ({{this.reason}})
|
|
248
|
+
{{/each}}
|
|
249
|
+
{{/if}}
|
|
250
|
+
|
|
251
|
+
## 约束
|
|
252
|
+
- 默认不允许修改业务源码
|
|
253
|
+
- 只生成验证命令和检查逻辑
|
|
254
|
+
- 输出验证结果(通过/失败/需人工确认)
|
|
255
|
+
|
|
256
|
+
## 验证要求
|
|
257
|
+
- 列出具体验证命令
|
|
258
|
+
- 标注预期结果
|
|
259
|
+
- 标注不确定项
|
|
260
|
+
`);
|
|
261
|
+
// 6. direct_answer_prompt: 直接回答,不进入代码执行
|
|
262
|
+
const DIRECT_ANSWER_TEMPLATE = Handlebars.compile(`## 任务
|
|
263
|
+
{{intent}}
|
|
264
|
+
|
|
265
|
+
## 要求
|
|
266
|
+
- 直接回答用户问题
|
|
267
|
+
- 不修改任何项目文件
|
|
268
|
+
- 给出明确结论和依据
|
|
269
|
+
`);
|
|
270
|
+
/** 保留旧模板名为 CODE_EXECUTION_TEMPLATE 的别名(兼容旧测试) */
|
|
271
|
+
const PROMPT_TEMPLATE = CODE_EXECUTION_TEMPLATE;
|
|
272
|
+
/** 将 PromptInjectionPlan 渲染为 Markdown 段落(统一注入,避免模板内重复) */
|
|
273
|
+
function renderPromptInjectionPlan(plan) {
|
|
274
|
+
const sections = [];
|
|
275
|
+
if (plan.evidence_refs.length > 0) {
|
|
276
|
+
sections.push("## 材料证据引用\n" + plan.evidence_refs.map((r) => "- " + r).join("\n"));
|
|
277
|
+
}
|
|
278
|
+
if (plan.required_summary.length > 0) {
|
|
279
|
+
sections.push("## 必需材料摘要\n" + plan.required_summary.map((s) => "- " + s).join("\n"));
|
|
280
|
+
}
|
|
281
|
+
if (plan.forbidden_notes.length > 0) {
|
|
282
|
+
sections.push("## 禁止/不可用材料\n" + plan.forbidden_notes.map((n) => "- " + n).join("\n"));
|
|
283
|
+
}
|
|
284
|
+
if (plan.manual_confirm_list.length > 0) {
|
|
285
|
+
sections.push("## 人工确认项\n" + plan.manual_confirm_list.map((c) => "- " + c).join("\n"));
|
|
286
|
+
}
|
|
287
|
+
if (plan.allowed_sources.length > 0) {
|
|
288
|
+
sections.push("## 允许的材料来源\n" + plan.allowed_sources.map((s) => "- " + s).join("\n"));
|
|
289
|
+
}
|
|
290
|
+
if (plan.forbidden_sources.length > 0) {
|
|
291
|
+
sections.push("## 禁止的材料来源\n" + plan.forbidden_sources.map((s) => "- " + s).join("\n"));
|
|
292
|
+
}
|
|
293
|
+
return sections.length > 0 ? "---\n\n" + sections.join("\n\n") : "";
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* 根据执行形态选择 prompt 模板。
|
|
297
|
+
*/
|
|
298
|
+
function chooseTemplate(templateName) {
|
|
299
|
+
switch (templateName) {
|
|
300
|
+
case "single_artifact_prompt": return SINGLE_ARTIFACT_TEMPLATE;
|
|
301
|
+
case "source_extraction_prompt": return SOURCE_EXTRACTION_TEMPLATE;
|
|
302
|
+
case "read_only_analysis_prompt": return READ_ONLY_ANALYSIS_TEMPLATE;
|
|
303
|
+
case "verification_only_prompt": return VERIFICATION_ONLY_TEMPLATE;
|
|
304
|
+
case "direct_answer_prompt": return DIRECT_ANSWER_TEMPLATE;
|
|
305
|
+
case "code_execution_prompt":
|
|
306
|
+
default: return CODE_EXECUTION_TEMPLATE;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* 解析澄清答案,将路径注入 route_decision.input_materials,
|
|
311
|
+
* 清除已解决的 missing_required_inputs。
|
|
312
|
+
* 返回新的 route_decision(不修改原对象)。
|
|
313
|
+
*/
|
|
314
|
+
function resolveClarificationAnswers(decision, intent, answers) {
|
|
315
|
+
const resolved = {
|
|
316
|
+
...decision,
|
|
317
|
+
input_materials: decision.input_materials.map((m) => ({ ...m })),
|
|
318
|
+
missing_required_inputs: [...decision.missing_required_inputs],
|
|
319
|
+
};
|
|
320
|
+
const addedPaths = [];
|
|
321
|
+
for (const answer of answers) {
|
|
322
|
+
// 提取路径 - absolute paths starting with /
|
|
323
|
+
const absPathPattern = /(?<![^\s])\/[^\s\]]+/g;
|
|
324
|
+
for (const m of answer.matchAll(absPathPattern)) {
|
|
325
|
+
const p = m[0];
|
|
326
|
+
if (p && p.length > 1 && !addedPaths.includes(p)) {
|
|
327
|
+
addedPaths.push(p);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// 提取相对路径 (word/word.ext 模式)
|
|
331
|
+
const relPathPattern = /[\w][\w.\-]*(?:\/[\w.\-]+)+\.[\w]+/g;
|
|
332
|
+
for (const m of answer.matchAll(relPathPattern)) {
|
|
333
|
+
const p = m[0];
|
|
334
|
+
if (p && !addedPaths.includes(p) && !addedPaths.some((ap) => ap.endsWith("/" + p))) {
|
|
335
|
+
addedPaths.push(p);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
for (const p of addedPaths) {
|
|
340
|
+
if (resolved.input_materials.some((m) => m.path === p))
|
|
341
|
+
continue;
|
|
342
|
+
let kind = "file";
|
|
343
|
+
if (/\.(zip|tar\.gz|gz|rar|7z|jar|war)$/i.test(p))
|
|
344
|
+
kind = "archive";
|
|
345
|
+
else if (/\.log$/i.test(p))
|
|
346
|
+
kind = "log";
|
|
347
|
+
else if (/\.(md|txt|doc|pdf|docx)$/i.test(p))
|
|
348
|
+
kind = "doc";
|
|
349
|
+
else if (/\.(java|py|ts|tsx|js|jsx|go|rs)$/i.test(p))
|
|
350
|
+
kind = "file";
|
|
351
|
+
resolved.input_materials.push({ kind, path: p, required: true });
|
|
352
|
+
}
|
|
353
|
+
// 仅清除路径类型的缺失输入(保留非路径问题如"哪个框架?")
|
|
354
|
+
if (addedPaths.length > 0) {
|
|
355
|
+
resolved.missing_required_inputs = resolved.missing_required_inputs.filter((m) => !/path|路径|目录|文件|folder|directory|file/i.test(m));
|
|
356
|
+
}
|
|
357
|
+
return resolved;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* 获取 sf_expand 契约的 next_allowed_tools 和 forbidden_tools。
|
|
361
|
+
*/
|
|
362
|
+
function getExpandContractTools() {
|
|
363
|
+
const contract = findToolInvocationContractByName("sf_expand");
|
|
364
|
+
return {
|
|
365
|
+
next_allowed_tools: contract?.default_next_tools ?? [],
|
|
366
|
+
forbidden_tools: contract?.forbidden_next_tools ?? [],
|
|
367
|
+
};
|
|
368
|
+
}
|
|
61
369
|
/**
|
|
62
370
|
* 将分类结果扩展为完整的 AI 执行 prompt 和配套元数据。
|
|
63
|
-
* @param input - 膨胀输入,包含意图、分类结果、项目配置、知识索引等
|
|
64
|
-
* @returns 膨胀结果,包含 prompt / scope / 验收标准 / 执行契约 / 不确定性触发条件
|
|
65
371
|
*/
|
|
66
372
|
export async function expand(input) {
|
|
373
|
+
console.error("[soloForge] 意图膨胀: 开始扩展,路由=%s", input.route_decision?.route ?? input.classification?.task_type ?? "unknown");
|
|
67
374
|
const { intent, classification, projectPath, config, knowledgeIndex } = input;
|
|
68
|
-
|
|
375
|
+
let routeDecision = input.route_decision ?? classification.route_decision;
|
|
376
|
+
const templateName = routeDecision ? selectPromptTemplate(routeDecision) : "code_execution_prompt";
|
|
377
|
+
// 配置优先级解析 — 使用共享函数
|
|
378
|
+
let configResolution;
|
|
379
|
+
try {
|
|
380
|
+
configResolution = await resolveCurrentProjectConfigReports(projectPath);
|
|
381
|
+
}
|
|
382
|
+
catch (e) {
|
|
383
|
+
console.error("[soloForge] 意图扩展: 配置优先级解析失败 —", e);
|
|
384
|
+
configResolution = { reports: [], resolutions: [], warnings: [], entries: [] };
|
|
385
|
+
}
|
|
386
|
+
const configWarnings = configResolution.warnings;
|
|
387
|
+
// 消费澄清答案:解析路径,更新 input_materials,清除已解决的 missing_required_inputs
|
|
388
|
+
if (input.clarificationAnswers && input.clarificationAnswers.length > 0 && routeDecision) {
|
|
389
|
+
routeDecision = resolveClarificationAnswers(routeDecision, intent, input.clarificationAnswers);
|
|
390
|
+
}
|
|
391
|
+
// ── Privacy gate— 提前到所有 early-return 之前 ──
|
|
392
|
+
const privacyGate = evaluatePrivacyGate({
|
|
393
|
+
intent,
|
|
394
|
+
input_materials: input.route_decision?.input_materials?.map((m) => ({ path_or_ref: m.path ?? "" })) ?? [],
|
|
395
|
+
});
|
|
396
|
+
const safeIntent = privacyGate.redacted_text ?? redactSensitiveText(intent, "intent").redacted;
|
|
397
|
+
const safeGoal = redactSensitiveText(intent.slice(0, 200), "intent_goal").redacted;
|
|
398
|
+
// 提前创建产物记录 (在所有 early-return 之前),确保所有路径都携带它
|
|
399
|
+
// task_id 为必需 — block if missing
|
|
400
|
+
let outputArtifactRecord;
|
|
401
|
+
if (routeDecision?.output_artifact && routeDecision.execution_shape !== "none" && routeDecision.execution_shape !== "code_execution") {
|
|
402
|
+
const artifactKind = mapToArtifactKind(routeDecision.output_artifact.kind);
|
|
403
|
+
if (!input.task_id) {
|
|
404
|
+
// task_id 缺失时始终阻止 for artifact routes
|
|
405
|
+
return {
|
|
406
|
+
task_id: "",
|
|
407
|
+
prompt: `## 阻塞:产物缺少 task_id\n\n任务: ${safeIntent}\n\nexpand() 收到 task_id 为空,无法创建产物记录。`,
|
|
408
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
409
|
+
acceptance: { automated: [], manual: [] },
|
|
410
|
+
matched_patterns: [],
|
|
411
|
+
matched_knowledge: [],
|
|
412
|
+
is_legacy_code: false,
|
|
413
|
+
degraded: true,
|
|
414
|
+
contract: {
|
|
415
|
+
goal: safeGoal,
|
|
416
|
+
scope: [],
|
|
417
|
+
constraints: ["task_id 缺失"],
|
|
418
|
+
verification: [],
|
|
419
|
+
stop_conditions: ["task_id 缺失"],
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
// 收集源材料引用 from routeDecision.input_materials
|
|
424
|
+
const sourceMaterialRefs = routeDecision.input_materials
|
|
425
|
+
.filter((m) => m.path)
|
|
426
|
+
.map((m) => m.path);
|
|
427
|
+
// 冲突时拒绝 with input.task_id
|
|
428
|
+
if (routeDecision.output_artifact.taskId && routeDecision.output_artifact.taskId !== input.task_id) {
|
|
429
|
+
return {
|
|
430
|
+
task_id: input.task_id,
|
|
431
|
+
prompt: `## Contract Error: task_id 不一致\n\nrouteDecision.taskId=${routeDecision.output_artifact.taskId} !== input.task_id=${input.task_id}`,
|
|
432
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
433
|
+
acceptance: { automated: [], manual: [] },
|
|
434
|
+
matched_patterns: [], matched_knowledge: [],
|
|
435
|
+
is_legacy_code: false, degraded: true,
|
|
436
|
+
contract: { goal: safeGoal, scope: [], constraints: ["task_id 不一致"], verification: [], stop_conditions: ["task_id 不一致"] },
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
// 路径始终使用 input.task_id
|
|
440
|
+
outputArtifactRecord = createOutputArtifact({
|
|
441
|
+
kind: artifactKind,
|
|
442
|
+
task_id: input.task_id,
|
|
443
|
+
workflow_id: "pending",
|
|
444
|
+
created_by: "intent_expander",
|
|
445
|
+
path: getDefaultArtifactPath(artifactKind, input.task_id),
|
|
446
|
+
source_material_refs: sourceMaterialRefs,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
// ── 工作流契约解析 ──
|
|
450
|
+
let workflowContract = undefined;
|
|
451
|
+
let workflowGovernanceFindings = [];
|
|
452
|
+
if (routeDecision) {
|
|
453
|
+
workflowContract = resolveWorkflow(routeDecision);
|
|
454
|
+
// 提前绑定 workflow_id to artifact record
|
|
455
|
+
if (workflowContract && outputArtifactRecord) {
|
|
456
|
+
outputArtifactRecord.workflow_id = workflowContract.id;
|
|
457
|
+
}
|
|
458
|
+
console.error("[soloForge] 意图膨胀: 工作流契约已解析,workflow=%s", workflowContract?.id ?? "none");
|
|
459
|
+
if (!workflowContract) {
|
|
460
|
+
return {
|
|
461
|
+
task_id: "",
|
|
462
|
+
prompt: `## 阻塞:无工作流契约\n\n任务: ${safeIntent}\n\nroute="${routeDecision.route}" + execution_shape="${routeDecision.execution_shape}" 没有匹配的工作流契约。\n\n请检查意图路由配置。`,
|
|
463
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
464
|
+
acceptance: { automated: [], manual: [] },
|
|
465
|
+
matched_patterns: [],
|
|
466
|
+
matched_knowledge: [],
|
|
467
|
+
is_legacy_code: false,
|
|
468
|
+
degraded: true,
|
|
469
|
+
workflow_trace: {
|
|
470
|
+
workflow_id: "none",
|
|
471
|
+
route: routeDecision.route,
|
|
472
|
+
execution_shape: routeDecision.execution_shape,
|
|
473
|
+
mutation_allowed: routeDecision.mutation_allowed,
|
|
474
|
+
required_mechanisms: [],
|
|
475
|
+
governance_findings: [{ severity: "hard_fail", rule: "gc-no-workflow", message: `no workflow contract for ${routeDecision.route}+${routeDecision.execution_shape}` }],
|
|
476
|
+
degraded: true,
|
|
477
|
+
state_transition_target: "none",
|
|
478
|
+
},
|
|
479
|
+
contract: {
|
|
480
|
+
goal: safeGoal,
|
|
481
|
+
scope: [],
|
|
482
|
+
constraints: ["无工作流契约"],
|
|
483
|
+
verification: [],
|
|
484
|
+
stop_conditions: ["无工作流契约"],
|
|
485
|
+
},
|
|
486
|
+
output_artifact_record: outputArtifactRecord,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
// mutation_allowed 一致性检查
|
|
490
|
+
if (workflowContract.mutation_allowed !== routeDecision.mutation_allowed) {
|
|
491
|
+
return {
|
|
492
|
+
task_id: "",
|
|
493
|
+
prompt: `## 阻塞:mutation_allowed 不一致\n\n任务: ${safeIntent}\n\n工作流 "${workflowContract.id}" 的 mutation_allowed=${workflowContract.mutation_allowed} 与 route_decision 的 mutation_allowed=${routeDecision.mutation_allowed} 不一致。`,
|
|
494
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
495
|
+
acceptance: { automated: [], manual: [] },
|
|
496
|
+
matched_patterns: [],
|
|
497
|
+
matched_knowledge: [],
|
|
498
|
+
is_legacy_code: false,
|
|
499
|
+
degraded: true,
|
|
500
|
+
workflow_trace: {
|
|
501
|
+
workflow_id: workflowContract.id,
|
|
502
|
+
route: routeDecision.route,
|
|
503
|
+
execution_shape: routeDecision.execution_shape,
|
|
504
|
+
mutation_allowed: workflowContract.mutation_allowed,
|
|
505
|
+
required_mechanisms: workflowContract.required_mechanisms,
|
|
506
|
+
governance_findings: [{ severity: "hard_fail", rule: "gc-mutation-mismatch", message: `mutation_allowed mismatch: workflow=${workflowContract.mutation_allowed} route=${routeDecision.mutation_allowed}` }],
|
|
507
|
+
degraded: true,
|
|
508
|
+
state_transition_target: "none",
|
|
509
|
+
},
|
|
510
|
+
contract: {
|
|
511
|
+
goal: safeGoal,
|
|
512
|
+
scope: [],
|
|
513
|
+
constraints: ["mutation_allowed 不一致"],
|
|
514
|
+
verification: [],
|
|
515
|
+
stop_conditions: ["mutation_allowed 不一致"],
|
|
516
|
+
},
|
|
517
|
+
output_artifact_record: outputArtifactRecord,
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
// prompt_template 一致性检查
|
|
521
|
+
if (workflowContract.prompt_template !== templateName) {
|
|
522
|
+
return {
|
|
523
|
+
task_id: "",
|
|
524
|
+
prompt: `## 阻塞:prompt_template 不一致\n\n任务: ${safeIntent}\n\n工作流 "${workflowContract.id}" 要求 prompt_template="${workflowContract.prompt_template}",但 selectPromptTemplate 返回 "${templateName}"。`,
|
|
525
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
526
|
+
acceptance: { automated: [], manual: [] },
|
|
527
|
+
matched_patterns: [],
|
|
528
|
+
matched_knowledge: [],
|
|
529
|
+
is_legacy_code: false,
|
|
530
|
+
degraded: true,
|
|
531
|
+
workflow_trace: {
|
|
532
|
+
workflow_id: workflowContract.id,
|
|
533
|
+
route: routeDecision.route,
|
|
534
|
+
execution_shape: routeDecision.execution_shape,
|
|
535
|
+
mutation_allowed: workflowContract.mutation_allowed,
|
|
536
|
+
required_mechanisms: workflowContract.required_mechanisms,
|
|
537
|
+
governance_findings: [{ severity: "hard_fail", rule: "gc-prompt-template-mismatch", message: `prompt_template mismatch: workflow="${workflowContract.prompt_template}" selected="${templateName}"` }],
|
|
538
|
+
degraded: true,
|
|
539
|
+
state_transition_target: "none",
|
|
540
|
+
},
|
|
541
|
+
contract: {
|
|
542
|
+
goal: safeGoal,
|
|
543
|
+
scope: [],
|
|
544
|
+
constraints: ["prompt_template 不一致"],
|
|
545
|
+
verification: [],
|
|
546
|
+
stop_conditions: ["prompt_template 不一致"],
|
|
547
|
+
},
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
// 缺少必需输入时返回澄清,不生成执行 prompt(在 workflow resolution 之后)
|
|
552
|
+
if (routeDecision && routeDecision.missing_required_inputs.length > 0) {
|
|
553
|
+
console.error("[soloForge] 意图膨胀: 缺少必需输入 %d 项,返回澄清请求", routeDecision.missing_required_inputs.length);
|
|
554
|
+
return buildClarificationResult(intent, routeDecision, config, workflowContract, safeIntent, safeGoal);
|
|
555
|
+
}
|
|
556
|
+
// ── 输入材料契约 ──
|
|
557
|
+
let inputMaterials;
|
|
558
|
+
let ingestionEvidences;
|
|
559
|
+
let promptInjectionPlan;
|
|
560
|
+
const contractNotes = [];
|
|
561
|
+
if (routeDecision && routeDecision.input_materials.length > 0) {
|
|
562
|
+
const pathMaterials = routeDecision.input_materials.filter((m) => m.path);
|
|
563
|
+
if (pathMaterials.length > 0) {
|
|
564
|
+
const materials = pathMaterials.map((m) => createInputMaterial({ path_or_ref: m.path }));
|
|
565
|
+
inputMaterials = materials;
|
|
566
|
+
ingestionEvidences = materials.map((m) => createIngestionEvidence(m));
|
|
567
|
+
for (const m of materials) {
|
|
568
|
+
if (m.access_mode === "forbidden") {
|
|
569
|
+
contractNotes.push(`[FORBIDDEN] ${m.path_or_ref}: 禁止读取`);
|
|
570
|
+
}
|
|
571
|
+
else if (m.trust_level === "external_unverified" || m.trust_level === "derived" || m.trust_level === "ai_generated") {
|
|
572
|
+
contractNotes.push(`[Manual Confirm] ${m.path_or_ref}: 信任等级=${m.trust_level}`);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
promptInjectionPlan = buildPromptInjectionPlan(materials, ingestionEvidences);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
// ── 输入材料硬阻断──
|
|
579
|
+
if (inputMaterials) {
|
|
580
|
+
const forbiddenMaterials = inputMaterials.filter((m) => m.access_mode === "forbidden");
|
|
581
|
+
if (forbiddenMaterials.length > 0) {
|
|
582
|
+
const forbiddenPaths = forbiddenMaterials.map((m) => m.path_or_ref).join(", ");
|
|
583
|
+
console.error("[soloForge] 意图膨胀: 输入材料禁止读取: %s", forbiddenPaths);
|
|
584
|
+
return {
|
|
585
|
+
task_id: "",
|
|
586
|
+
prompt: `## 阻塞:输入材料禁止读取\n\n任务: ${safeIntent}\n\n以下材料路径触发禁止规则,不得读取:\n${forbiddenMaterials.map((m) => " - " + m.path_or_ref).join("\\n")}\n\n请移除这些材料后重新调用。`,
|
|
587
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
588
|
+
acceptance: { automated: [], manual: [] },
|
|
589
|
+
matched_patterns: [],
|
|
590
|
+
matched_knowledge: [],
|
|
591
|
+
is_legacy_code: false,
|
|
592
|
+
degraded: true,
|
|
593
|
+
input_materials: inputMaterials,
|
|
594
|
+
ingestion_evidences: ingestionEvidences,
|
|
595
|
+
prompt_injection_plan: promptInjectionPlan,
|
|
596
|
+
contract: {
|
|
597
|
+
goal: safeGoal,
|
|
598
|
+
scope: [],
|
|
599
|
+
constraints: ["输入材料包含禁止路径"],
|
|
600
|
+
verification: [],
|
|
601
|
+
stop_conditions: [],
|
|
602
|
+
},
|
|
603
|
+
output_artifact_record: outputArtifactRecord,
|
|
604
|
+
workflow_trace: workflowContract ? {
|
|
605
|
+
workflow_id: workflowContract.id,
|
|
606
|
+
route: routeDecision.route,
|
|
607
|
+
execution_shape: routeDecision.execution_shape,
|
|
608
|
+
mutation_allowed: workflowContract.mutation_allowed,
|
|
609
|
+
required_mechanisms: workflowContract.required_mechanisms,
|
|
610
|
+
governance_findings: [{ severity: "hard_fail", rule: "gc-forbidden-material", message: `材料禁止读取: ${forbiddenPaths}` }],
|
|
611
|
+
degraded: true,
|
|
612
|
+
state_transition_target: "none",
|
|
613
|
+
} : undefined,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
const confirmations = input.input_material_confirmations ?? [];
|
|
617
|
+
const requiresConfirmationMaterials = inputMaterials.filter((m) => m.access_mode !== "forbidden"
|
|
618
|
+
&& classifyIngestionStatus(m.path_or_ref) === "requires_confirmation"
|
|
619
|
+
&& !confirmations.includes(m.path_or_ref));
|
|
620
|
+
if (requiresConfirmationMaterials.length > 0) {
|
|
621
|
+
const confirmPaths = requiresConfirmationMaterials.map((m) => m.path_or_ref);
|
|
622
|
+
return {
|
|
623
|
+
task_id: "",
|
|
624
|
+
prompt: `## 澄清请求\n\n任务: ${safeIntent}\n\n以下输入材料需要人工确认后才能使用:\n${confirmPaths.map((p) => " - " + p).join("\\n")}\n\n请确认以上材料安全性后,通过 input_material_confirmations 参数重新调用。`,
|
|
625
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
626
|
+
acceptance: { automated: [], manual: [] },
|
|
627
|
+
matched_patterns: [],
|
|
628
|
+
matched_knowledge: [],
|
|
629
|
+
is_legacy_code: false,
|
|
630
|
+
degraded: true,
|
|
631
|
+
input_materials: inputMaterials,
|
|
632
|
+
ingestion_evidences: ingestionEvidences,
|
|
633
|
+
prompt_injection_plan: promptInjectionPlan,
|
|
634
|
+
contract: {
|
|
635
|
+
goal: safeGoal,
|
|
636
|
+
scope: [],
|
|
637
|
+
constraints: ["输入材料需要确认"],
|
|
638
|
+
verification: [],
|
|
639
|
+
stop_conditions: [],
|
|
640
|
+
},
|
|
641
|
+
output_artifact_record: outputArtifactRecord,
|
|
642
|
+
workflow_trace: workflowContract ? {
|
|
643
|
+
workflow_id: workflowContract.id,
|
|
644
|
+
route: routeDecision.route,
|
|
645
|
+
execution_shape: routeDecision.execution_shape,
|
|
646
|
+
mutation_allowed: workflowContract.mutation_allowed,
|
|
647
|
+
required_mechanisms: workflowContract.required_mechanisms,
|
|
648
|
+
governance_findings: [],
|
|
649
|
+
degraded: true,
|
|
650
|
+
state_transition_target: "clarifying",
|
|
651
|
+
} : undefined,
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
// ── 隐私硬阻断门禁 (privacyGate 已在顶部计算) ──
|
|
656
|
+
const privacyLabels = privacyGate.labels;
|
|
657
|
+
const privacyRedactions = privacyGate.redaction_records;
|
|
658
|
+
const privacyFindings = privacyGate.findings;
|
|
659
|
+
// 硬阻断: 意图或输入材料中包含密钥/凭证
|
|
660
|
+
if (privacyGate.hard_fail) {
|
|
661
|
+
console.error("[soloForge] 意图膨胀: 隐私策略阻断,包含 %d 个禁止来源", privacyGate.blocked_sources.length);
|
|
662
|
+
return {
|
|
663
|
+
task_id: "",
|
|
664
|
+
prompt: [
|
|
665
|
+
"## 阻塞:隐私/敏感信息策略",
|
|
666
|
+
"",
|
|
667
|
+
"任务内容已因隐私策略脱敏",
|
|
668
|
+
"",
|
|
669
|
+
"隐私门禁触发 hard_fail,以下来源包含禁止级别的敏感信息:",
|
|
670
|
+
...privacyGate.blocked_sources.map((s) => " - " + s),
|
|
671
|
+
"",
|
|
672
|
+
"治理发现:",
|
|
673
|
+
...privacyGate.findings.map((f) => ` [${f.severity}] ${f.rule}: ${f.message}`),
|
|
674
|
+
"",
|
|
675
|
+
"请移除敏感信息后重新调用。",
|
|
676
|
+
].join("\n"),
|
|
677
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
678
|
+
acceptance: { automated: [], manual: [] },
|
|
679
|
+
matched_patterns: [],
|
|
680
|
+
matched_knowledge: [],
|
|
681
|
+
is_legacy_code: false,
|
|
682
|
+
degraded: true,
|
|
683
|
+
sensitivity_labels: privacyLabels.length > 0 ? privacyLabels : undefined,
|
|
684
|
+
redaction_records: privacyRedactions.length > 0 ? privacyRedactions : undefined,
|
|
685
|
+
privacy_findings: privacyFindings.length > 0 ? privacyFindings : undefined,
|
|
686
|
+
contract: {
|
|
687
|
+
goal: safeGoal,
|
|
688
|
+
scope: [],
|
|
689
|
+
constraints: ["隐私/敏感信息策略阻断"],
|
|
690
|
+
verification: [],
|
|
691
|
+
stop_conditions: ["隐私/敏感信息策略阻断"],
|
|
692
|
+
},
|
|
693
|
+
input_materials: inputMaterials,
|
|
694
|
+
ingestion_evidences: ingestionEvidences,
|
|
695
|
+
prompt_injection_plan: promptInjectionPlan,
|
|
696
|
+
output_artifact_record: outputArtifactRecord,
|
|
697
|
+
workflow_trace: workflowContract ? {
|
|
698
|
+
workflow_id: workflowContract.id,
|
|
699
|
+
route: routeDecision.route,
|
|
700
|
+
execution_shape: routeDecision.execution_shape,
|
|
701
|
+
mutation_allowed: workflowContract.mutation_allowed,
|
|
702
|
+
required_mechanisms: workflowContract.required_mechanisms,
|
|
703
|
+
governance_findings: privacyFindings.map((f) => ({ severity: f.severity, rule: f.rule, message: f.message })),
|
|
704
|
+
degraded: true,
|
|
705
|
+
state_transition_target: "none",
|
|
706
|
+
} : undefined,
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
// 1. 查询知识库(路由驱动匹配)
|
|
69
710
|
const scopeFilters = classification.affected_repos.length > 0
|
|
70
711
|
? classification.affected_repos
|
|
71
712
|
: ["shared"];
|
|
72
|
-
// 分级运行: quick_fix 模式减少知识匹配量以控制 Token 成本
|
|
73
713
|
const knowledgeLimit = classification.strategy === "quick_fix" ? 2 : 5;
|
|
74
714
|
const skipHeavyAnalysis = classification.strategy === "quick_fix";
|
|
75
|
-
const matchedEntries = knowledgeIndex
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
715
|
+
const matchedEntries = queryKnowledgeForRoute(knowledgeIndex, intent, scopeFilters, config, routeDecision, knowledgeLimit);
|
|
716
|
+
// 知识注入边界( 三道门过滤)
|
|
717
|
+
const productFilters = [config.product_profile];
|
|
718
|
+
const injectionReport = enforceKnowledgeInjectionBoundary(matchedEntries, routeDecision, scopeFilters, undefined, knowledgeLimit, productFilters);
|
|
719
|
+
const injectedIds = new Set(getInjectedEntryIds(injectionReport));
|
|
720
|
+
const filteredEntries = matchedEntries.filter((e) => injectedIds.has(e.id));
|
|
721
|
+
if (filteredEntries.length > 0) {
|
|
722
|
+
knowledgeIndex.markUsed(filteredEntries.map((e) => e.id));
|
|
723
|
+
}
|
|
724
|
+
// 治理校验:validateInjectionReport
|
|
725
|
+
const governanceFindings = validateInjectionReport(injectionReport);
|
|
726
|
+
const hardFails = governanceFindings.filter((f) => f.severity === "hard_fail");
|
|
727
|
+
const hasMissingRequiredKnowledge = injectionReport.missing_required_knowledge && injectionReport.missing_required_knowledge.length > 0;
|
|
728
|
+
// 存储治理发现 in report
|
|
729
|
+
injectionReport.governance_findings = governanceFindings;
|
|
730
|
+
const degraded = filteredEntries.length === 0 && injectionReport.injected_required.length === 0;
|
|
731
|
+
// 任何 hard_fail 都阻止 from validateInjectionReport — not just missing_required_knowledge
|
|
732
|
+
if (hardFails.length > 0) {
|
|
733
|
+
console.error("[soloForge] 意图膨胀: 注入校验失败,%d 个 hard_fail", hardFails.length);
|
|
734
|
+
const failMessages = hardFails.map((f) => f.message).join("\n");
|
|
735
|
+
const missingDesc = hasMissingRequiredKnowledge
|
|
736
|
+
? injectionReport.missing_required_knowledge.map((m) => m.reason).join("\n")
|
|
737
|
+
: "";
|
|
738
|
+
const missingSection = missingDesc ? `\n\n缺少的必需知识:\n${missingDesc}` : "";
|
|
739
|
+
return {
|
|
740
|
+
task_id: "",
|
|
741
|
+
prompt: `## 阻塞:注入校验失败\n\n任务: ${safeIntent}\n\n以下硬性校验未通过:\n${failMessages}${missingSection}\n\n请修正后重新调用。`,
|
|
742
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
743
|
+
acceptance: { automated: [], manual: [] },
|
|
744
|
+
matched_patterns: [],
|
|
745
|
+
matched_knowledge: [],
|
|
746
|
+
is_legacy_code: false,
|
|
747
|
+
degraded: true,
|
|
748
|
+
injection_report: injectionReport,
|
|
749
|
+
input_materials: inputMaterials,
|
|
750
|
+
ingestion_evidences: ingestionEvidences,
|
|
751
|
+
prompt_injection_plan: promptInjectionPlan,
|
|
752
|
+
contract: {
|
|
753
|
+
goal: safeGoal,
|
|
754
|
+
scope: [],
|
|
755
|
+
constraints: ["注入校验失败,等待修正"],
|
|
756
|
+
verification: [],
|
|
757
|
+
stop_conditions: ["注入校验失败"],
|
|
758
|
+
},
|
|
759
|
+
output_artifact_record: outputArtifactRecord,
|
|
760
|
+
workflow_trace: workflowContract ? {
|
|
761
|
+
workflow_id: workflowContract.id,
|
|
762
|
+
route: routeDecision?.route ?? "",
|
|
763
|
+
execution_shape: routeDecision?.execution_shape ?? "",
|
|
764
|
+
mutation_allowed: workflowContract.mutation_allowed,
|
|
765
|
+
required_mechanisms: workflowContract.required_mechanisms,
|
|
766
|
+
governance_findings: workflowGovernanceFindings,
|
|
767
|
+
degraded: true,
|
|
768
|
+
state_transition_target: "none",
|
|
769
|
+
} : undefined,
|
|
770
|
+
};
|
|
84
771
|
}
|
|
85
|
-
|
|
86
|
-
// 2. 检测遗留惯例(quick_fix 跳过以节省 Token)
|
|
772
|
+
// 2. 检测遗留惯例(只对 code_execution 执行)
|
|
87
773
|
const legacyConventions = [];
|
|
88
774
|
let isLegacyCode = false;
|
|
89
|
-
if (!skipHeavyAnalysis && !degraded && classification.affected_repos.length > 0) {
|
|
775
|
+
if (templateName === "code_execution_prompt" && !skipHeavyAnalysis && !degraded && classification.affected_repos.length > 0) {
|
|
90
776
|
try {
|
|
91
777
|
const repoDirs = classification.affected_repos
|
|
92
778
|
.map((r) => config.repos.find((repo) => repo.name === r)?.path)
|
|
93
779
|
.filter(Boolean);
|
|
94
|
-
// 检查仓库中第一个已存在文件的惯例
|
|
95
780
|
const conventions = await detectConventions(repoDirs.map((d) => `${d}/src`).slice(0, 3), projectPath, config.conventions_file);
|
|
96
781
|
if (conventions.length > 0) {
|
|
97
782
|
isLegacyCode = true;
|
|
98
783
|
legacyConventions.push(...conventions.map((c) => c.convention));
|
|
99
784
|
}
|
|
100
785
|
}
|
|
101
|
-
catch {
|
|
786
|
+
catch (e) {
|
|
787
|
+
console.error("[soloForge] 意图扩展: 惯例检测失败 —", e);
|
|
102
788
|
// 惯例检测为尽力而为
|
|
103
789
|
}
|
|
104
790
|
}
|
|
105
|
-
// 3. 确定 scope
|
|
106
|
-
const scope = resolveScope(config, classification, degraded);
|
|
791
|
+
// 3. 确定 scope(非代码任务使用简化 scope)
|
|
792
|
+
const scope = resolveScope(config, classification, degraded, routeDecision);
|
|
107
793
|
// 4. 生成验收标准
|
|
108
|
-
const acceptance = generateAcceptance(intent, classification,
|
|
794
|
+
const acceptance = generateAcceptance(intent, classification, filteredEntries, config, degraded, routeDecision);
|
|
109
795
|
// 5. 组装 prompt
|
|
110
796
|
const techStack = buildTechStackLabel(config);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
797
|
+
const template = chooseTemplate(templateName);
|
|
798
|
+
const templateData = buildTemplateData(safeIntent, techStack, config, classification, scope, filteredEntries, legacyConventions, isLegacyCode, acceptance, degraded, routeDecision);
|
|
799
|
+
if (promptInjectionPlan)
|
|
800
|
+
templateData.prompt_injection_plan = promptInjectionPlan;
|
|
801
|
+
// ── 双层机制模板注入( 路由/状态过滤) ──
|
|
802
|
+
const dlMechanisms = listMechanismLayerMaps();
|
|
803
|
+
const currentRoute = routeDecision?.route ?? "";
|
|
804
|
+
const currentWorkflow = workflowContract?.id ?? "";
|
|
805
|
+
const dlRules = [];
|
|
806
|
+
for (const mech of dlMechanisms) {
|
|
807
|
+
// 仅 dual_layer_enforced or experimental_dual_layer mechanisms inject
|
|
808
|
+
if (mech.status !== "dual_layer_enforced" && mech.status !== "experimental_dual_layer")
|
|
809
|
+
continue;
|
|
810
|
+
// 路由必须匹配 mechanism's injected_routes
|
|
811
|
+
if (mech.injected_routes && mech.injected_routes.length > 0 && currentRoute) {
|
|
812
|
+
if (!mech.injected_routes.includes(currentRoute))
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
// 工作流必须匹配 mechanism's injected_workflows
|
|
816
|
+
if (mech.injected_workflows && mech.injected_workflows.length > 0 && currentWorkflow) {
|
|
817
|
+
if (!mech.injected_workflows.includes(currentWorkflow))
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
// 仅注入必需资产; supporting are handled by knowledge injection boundary
|
|
821
|
+
const requiredAssets = mech.template_assets.filter((ta) => ta.consumption_mode === "required");
|
|
822
|
+
for (const ra of requiredAssets) {
|
|
823
|
+
try {
|
|
824
|
+
const content = fss.readFileSync(ra.path, "utf-8").trim();
|
|
825
|
+
if (content)
|
|
826
|
+
dlRules.push(`[${mech.mechanism_name}] ${content}`);
|
|
827
|
+
}
|
|
828
|
+
catch (e) {
|
|
829
|
+
console.error("[soloForge] 意图扩展: 双层机制模板加载失败 —", e);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
if (dlRules.length > 0) {
|
|
834
|
+
templateData.dual_layer_rules = dlRules;
|
|
835
|
+
const existing = templateData.matched_knowledge;
|
|
836
|
+
if (existing) {
|
|
837
|
+
existing.push({ name: "强制机制规则(双层注入)", content: dlRules.join("\n\n") });
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
let prompt = template(templateData);
|
|
841
|
+
console.error("[soloForge] 意图膨胀: Prompt 模板渲染完成,模板=%s", templateName);
|
|
842
|
+
// 5.1 注入计划阶段上下文
|
|
132
843
|
if (input.plan_context) {
|
|
133
844
|
prompt = injectPlanContext(prompt, input.plan_context, knowledgeIndex);
|
|
134
845
|
}
|
|
135
|
-
// 6. 使用计数已通过 markUsed 更新,无需重复递增
|
|
136
846
|
// 7. 生成执行契约(能力 1)
|
|
137
|
-
const contract = buildExecutionContract(
|
|
847
|
+
const contract = buildExecutionContract(safeIntent, classification, scope, acceptance);
|
|
138
848
|
// 8. 生成不确定性触发条件(quick_fix 跳过)
|
|
139
849
|
const uncertaintyTriggers = skipHeavyAnalysis
|
|
140
850
|
? []
|
|
@@ -143,12 +853,12 @@ export async function expand(input) {
|
|
|
143
853
|
const breakerResult = checkCircuitBreaker({
|
|
144
854
|
intent,
|
|
145
855
|
classification,
|
|
146
|
-
matchedEntries,
|
|
856
|
+
matchedEntries: filteredEntries,
|
|
147
857
|
degraded,
|
|
148
858
|
});
|
|
149
|
-
// 熔断触发时: 注入头脑风暴 prompt,不阻止流程但标记 tripped
|
|
150
859
|
let circuitBreakerOutput;
|
|
151
860
|
if (breakerResult.tripped) {
|
|
861
|
+
console.error("[soloForge] 意图膨胀: 意图熔断触发,置信度=%.2f", breakerResult.confidence);
|
|
152
862
|
circuitBreakerOutput = breakerResult;
|
|
153
863
|
prompt += `
|
|
154
864
|
|
|
@@ -167,38 +877,365 @@ ${breakerResult.brainstorm.blind_spots.map((s) => `- ${s}`).join("\n")}
|
|
|
167
877
|
### 【闭环逼问】
|
|
168
878
|
${breakerResult.brainstorm.decision_questions.map((q, i) => `${i + 1}. ${q.question}\n A) ${q.option_a}\n B) ${q.option_b}`).join("\n\n")}
|
|
169
879
|
|
|
170
|
-
**注意**:
|
|
880
|
+
**注意**: ${routeDecision?.execution_shape === "code_execution"
|
|
881
|
+
? "请等待人类决策后再输出执行代码。"
|
|
882
|
+
: "请先补齐阻塞输入,或在产物中标记 [Manual Confirm] 后再生成产物。"}
|
|
171
883
|
`;
|
|
172
884
|
}
|
|
885
|
+
const expandTools = getExpandContractTools();
|
|
886
|
+
if (contractNotes.length > 0) {
|
|
887
|
+
prompt += "\n\n---\n\n## 输入材料契约检查\n" + contractNotes.join("\n");
|
|
888
|
+
}
|
|
889
|
+
// 追加配置优先级警告 to prompt
|
|
890
|
+
if (configWarnings.length > 0) {
|
|
891
|
+
prompt += "\n\n---\n\n## 配置优先级警告\n" + configWarnings.join("\n");
|
|
892
|
+
}
|
|
893
|
+
// 核心工程执行原则注入
|
|
894
|
+
const coreTaskLevel = getTaskLevel(routeDecision?.route, routeDecision?.execution_shape);
|
|
895
|
+
const coreRequiredPrinciples = getRequiredPrinciples(coreTaskLevel);
|
|
896
|
+
if (coreRequiredPrinciples.length > 0) {
|
|
897
|
+
const principleLines = listCorePrinciples()
|
|
898
|
+
.filter((p) => getEnforcementLevel(p.id, coreTaskLevel) !== "not_applicable")
|
|
899
|
+
.map((p) => {
|
|
900
|
+
const level = getEnforcementLevel(p.id, coreTaskLevel);
|
|
901
|
+
const tag = level === "required" ? "[REQUIRED]" : "[advisory]";
|
|
902
|
+
return `- **${tag} ${p.name} (${p.chinese_name})**: ${p.rule}`;
|
|
903
|
+
});
|
|
904
|
+
prompt += "\n\n---\n\n## 核心工程执行原则 (任务等级: " + coreTaskLevel + ")\n" + principleLines.join("\n");
|
|
905
|
+
prompt += "\n\n> 以上原则中 [REQUIRED] 为硬性要求,违反将导致验证失败。[advisory] 为建议性要求。";
|
|
906
|
+
}
|
|
907
|
+
// 注入 prompt_injection_plan 段落 into prompt (unified for all routes)
|
|
908
|
+
if (promptInjectionPlan) {
|
|
909
|
+
const rendered = renderPromptInjectionPlan(promptInjectionPlan);
|
|
910
|
+
if (rendered) {
|
|
911
|
+
prompt += "\n\n" + rendered;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
// 用真实引用丰富产物 before returning
|
|
915
|
+
if (outputArtifactRecord) {
|
|
916
|
+
// 绑定知识引用 from matched knowledge entries
|
|
917
|
+
outputArtifactRecord.knowledge_refs = filteredEntries.map((e) => e.id);
|
|
918
|
+
// 绑定摄取证据引用
|
|
919
|
+
if (ingestionEvidences && ingestionEvidences.length > 0) {
|
|
920
|
+
outputArtifactRecord.evidence_refs = ingestionEvidences
|
|
921
|
+
.filter((ie) => ie.access_mode !== "forbidden")
|
|
922
|
+
.map((ie) => `ingestion:${ie.material_id}:${ie.source_ref}`);
|
|
923
|
+
}
|
|
924
|
+
// 解析 workflow_id from workflow contract
|
|
925
|
+
if (workflowContract) {
|
|
926
|
+
outputArtifactRecord.workflow_id = workflowContract.id;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
console.error("[soloForge] 意图膨胀: 扩展完成,degraded=%s, 匹配知识=%d 条", degraded ? "true" : "false", filteredEntries.length);
|
|
173
930
|
return {
|
|
174
|
-
task_id: "",
|
|
931
|
+
task_id: "",
|
|
175
932
|
prompt,
|
|
176
933
|
scope,
|
|
177
934
|
acceptance,
|
|
178
|
-
matched_patterns:
|
|
179
|
-
matched_knowledge:
|
|
935
|
+
matched_patterns: filteredEntries.map((e) => e.name),
|
|
936
|
+
matched_knowledge: filteredEntries.map((e) => e.name),
|
|
937
|
+
injection_report: injectionReport,
|
|
180
938
|
is_legacy_code: isLegacyCode,
|
|
181
939
|
legacy_conventions: legacyConventions.length > 0 ? legacyConventions : undefined,
|
|
182
940
|
degraded,
|
|
183
941
|
contract,
|
|
184
942
|
uncertainty_triggers: uncertaintyTriggers.length > 0 ? uncertaintyTriggers : undefined,
|
|
185
943
|
circuit_breaker: circuitBreakerOutput,
|
|
944
|
+
next_allowed_tools: expandTools.next_allowed_tools,
|
|
945
|
+
forbidden_tools: expandTools.forbidden_tools,
|
|
946
|
+
input_materials: inputMaterials,
|
|
947
|
+
ingestion_evidences: ingestionEvidences,
|
|
948
|
+
prompt_injection_plan: promptInjectionPlan,
|
|
949
|
+
output_artifact_record: outputArtifactRecord,
|
|
950
|
+
sensitivity_labels: privacyLabels.length > 0 ? privacyLabels : undefined,
|
|
951
|
+
redaction_records: privacyRedactions.length > 0 ? privacyRedactions : undefined,
|
|
952
|
+
privacy_findings: privacyFindings.length > 0 ? privacyFindings : undefined,
|
|
953
|
+
config_resolution_reports: configResolution.reports.length > 0 ? configResolution.reports : undefined,
|
|
954
|
+
workflow_trace: workflowContract ? {
|
|
955
|
+
workflow_id: workflowContract.id,
|
|
956
|
+
route: routeDecision?.route ?? "",
|
|
957
|
+
execution_shape: routeDecision?.execution_shape ?? "",
|
|
958
|
+
mutation_allowed: workflowContract.mutation_allowed,
|
|
959
|
+
required_mechanisms: workflowContract.required_mechanisms,
|
|
960
|
+
governance_findings: workflowGovernanceFindings,
|
|
961
|
+
degraded,
|
|
962
|
+
state_transition_target: workflowContract.allowed_state_transitions[0] ?? "none",
|
|
963
|
+
checked_items: buildCheckedItems(workflowContract, routeDecision),
|
|
964
|
+
} : undefined,
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
function buildCheckedItems(contract, routeDecision) {
|
|
968
|
+
const items = [
|
|
969
|
+
"workflow_resolved",
|
|
970
|
+
"mutation_allowed_checked",
|
|
971
|
+
"prompt_template_checked",
|
|
972
|
+
"required_mechanisms_declared",
|
|
973
|
+
];
|
|
974
|
+
if (routeDecision && !routeDecision.mutation_allowed) {
|
|
975
|
+
items.push("read_only_scope_checked");
|
|
976
|
+
}
|
|
977
|
+
return items;
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* 缺少必需输入时返回澄清结果(不生成执行 prompt)。
|
|
981
|
+
*/
|
|
982
|
+
function buildClarificationResult(intent, routeDecision, config, workflowContract, safeIntent, safeGoal) {
|
|
983
|
+
const clarification = routeDecision.missing_required_inputs.join("\n");
|
|
984
|
+
return {
|
|
985
|
+
task_id: "",
|
|
986
|
+
prompt: `## 澄清请求\n\n任务: ${safeIntent}\n\n缺少必需输入:\n${clarification}\n\n请补充以上信息后重新调用。`,
|
|
987
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
988
|
+
acceptance: { automated: [], manual: [] },
|
|
989
|
+
matched_patterns: [],
|
|
990
|
+
matched_knowledge: [],
|
|
991
|
+
is_legacy_code: false,
|
|
992
|
+
degraded: true,
|
|
993
|
+
contract: {
|
|
994
|
+
goal: safeGoal,
|
|
995
|
+
scope: [],
|
|
996
|
+
constraints: ["缺少必需输入,等待澄清"],
|
|
997
|
+
verification: [],
|
|
998
|
+
stop_conditions: [],
|
|
999
|
+
},
|
|
1000
|
+
workflow_trace: workflowContract ? {
|
|
1001
|
+
workflow_id: workflowContract.id,
|
|
1002
|
+
route: routeDecision.route,
|
|
1003
|
+
execution_shape: routeDecision.execution_shape,
|
|
1004
|
+
mutation_allowed: workflowContract.mutation_allowed,
|
|
1005
|
+
required_mechanisms: workflowContract.required_mechanisms,
|
|
1006
|
+
governance_findings: [],
|
|
1007
|
+
degraded: true,
|
|
1008
|
+
state_transition_target: "clarifying",
|
|
1009
|
+
} : undefined,
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* 根据 pipeline_hint 名称加载内置流程模板。
|
|
1014
|
+
*/
|
|
1015
|
+
function loadBuiltinByPipeline(pipelineName) {
|
|
1016
|
+
const entries = [];
|
|
1017
|
+
// pipeline_hint 格式: source-prototype-to-delivery:step-1 → 找源码原型交付流程.md
|
|
1018
|
+
const nameToTemplate = {
|
|
1019
|
+
"source-prototype-to-delivery": "源码原型交付流程.md",
|
|
1020
|
+
};
|
|
1021
|
+
const templateFile = nameToTemplate[pipelineName];
|
|
1022
|
+
if (templateFile) {
|
|
1023
|
+
const entry = loadBuiltinTemplate(templateFile, "procedures");
|
|
1024
|
+
if (entry)
|
|
1025
|
+
entries.push(entry);
|
|
1026
|
+
}
|
|
1027
|
+
return entries;
|
|
1028
|
+
}
|
|
1029
|
+
/** 包内模板知识库根目录 */
|
|
1030
|
+
function getTemplatesRoot() {
|
|
1031
|
+
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
1032
|
+
return path.resolve(thisDir, "..", "..", "templates", "knowledge");
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* 当知识索引中没有找到内置模板时,从 templates/knowledge/ 加载为 KnowledgeEntry。
|
|
1036
|
+
* 只加载指定名称的文件。
|
|
1037
|
+
*/
|
|
1038
|
+
function loadBuiltinTemplate(fileName, subDir) {
|
|
1039
|
+
const templatesRoot = getTemplatesRoot();
|
|
1040
|
+
const safeName = path.basename(fileName); // basename 防止路径穿越
|
|
1041
|
+
const filePath = path.join(templatesRoot, subDir, safeName);
|
|
1042
|
+
try {
|
|
1043
|
+
if (!fss.existsSync(filePath))
|
|
1044
|
+
return null;
|
|
1045
|
+
const raw = fss.readFileSync(filePath, "utf-8");
|
|
1046
|
+
const { data, content: body } = matter(raw);
|
|
1047
|
+
const name = data.name || path.basename(fileName, ".md");
|
|
1048
|
+
const type = inferTypeFromSubDir(subDir);
|
|
1049
|
+
return {
|
|
1050
|
+
id: `builtin-${name}`,
|
|
1051
|
+
file_path: filePath,
|
|
1052
|
+
name,
|
|
1053
|
+
type,
|
|
1054
|
+
when: data.when || "",
|
|
1055
|
+
body,
|
|
1056
|
+
scope: data.scope || ["shared"],
|
|
1057
|
+
products: data.products || ["*"],
|
|
1058
|
+
tech_stack: data.tech_stack,
|
|
1059
|
+
created_at: data.created_at || new Date().toISOString().split("T")[0],
|
|
1060
|
+
updated_at: data.updated_at || new Date().toISOString().split("T")[0],
|
|
1061
|
+
usage_count: 0,
|
|
1062
|
+
confidence: data.confidence ?? 1.0,
|
|
1063
|
+
status: "active",
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
catch (e) {
|
|
1067
|
+
console.error("[soloForge] 意图扩展: 内置模板加载失败 —", e);
|
|
1068
|
+
return null;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
function inferTypeFromSubDir(subDir) {
|
|
1072
|
+
if (subDir.includes("procedures"))
|
|
1073
|
+
return "pipeline_procedure";
|
|
1074
|
+
if (subDir.includes("acceptance_templates"))
|
|
1075
|
+
return "acceptance_template";
|
|
1076
|
+
if (subDir.includes("review_rules"))
|
|
1077
|
+
return "review_rule";
|
|
1078
|
+
if (subDir.includes("domain"))
|
|
1079
|
+
return "domain";
|
|
1080
|
+
return "pattern";
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* 路由驱动的知识匹配。
|
|
1084
|
+
* 优先使用 pipeline_hint、output_artifact.kind、route + execution_shape,
|
|
1085
|
+
* 降级为同类型通用产物 prompt,不退化成编码 prompt。
|
|
1086
|
+
*/
|
|
1087
|
+
function queryKnowledgeForRoute(knowledgeIndex, intent, scopeFilters, config, routeDecision, limit) {
|
|
1088
|
+
if (!routeDecision) {
|
|
1089
|
+
// 无 route_decision 时回退到旧逻辑
|
|
1090
|
+
return knowledgeIndex.query({
|
|
1091
|
+
scope: scopeFilters,
|
|
1092
|
+
products: [config.product_profile],
|
|
1093
|
+
keywords: extractKeywords(intent),
|
|
1094
|
+
limit,
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
const seen = new Set();
|
|
1098
|
+
const results = [];
|
|
1099
|
+
function addEntries(entries) {
|
|
1100
|
+
for (const e of entries) {
|
|
1101
|
+
if (!seen.has(e.id)) {
|
|
1102
|
+
seen.add(e.id);
|
|
1103
|
+
results.push(e);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
// 优先级 1: pipeline_hint 精确匹配(不提前 return)
|
|
1108
|
+
if (routeDecision.pipeline_hint) {
|
|
1109
|
+
const pipelineName = routeDecision.pipeline_hint.split(":")[0];
|
|
1110
|
+
const pipelineResults = knowledgeIndex.query({
|
|
1111
|
+
scope: scopeFilters,
|
|
1112
|
+
products: [config.product_profile],
|
|
1113
|
+
type: "pipeline_procedure",
|
|
1114
|
+
keywords: extractKeywords(pipelineName),
|
|
1115
|
+
limit: 3,
|
|
1116
|
+
});
|
|
1117
|
+
addEntries(pipelineResults);
|
|
1118
|
+
// 内置模板回退: pipeline_hint 名称未命中时从 templates/knowledge/ 加载
|
|
1119
|
+
if (pipelineResults.length === 0) {
|
|
1120
|
+
const builtin = loadBuiltinByPipeline(pipelineName);
|
|
1121
|
+
if (builtin)
|
|
1122
|
+
addEntries(builtin);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
// 优先级 2: output_artifact.kind 映射 acceptance_template(不提前 return)
|
|
1126
|
+
if (routeDecision.output_artifact?.kind) {
|
|
1127
|
+
// 先按 template 文件名精确匹配
|
|
1128
|
+
const templateName = routeDecision.output_artifact.template;
|
|
1129
|
+
if (templateName) {
|
|
1130
|
+
const allTemplates = knowledgeIndex.query({
|
|
1131
|
+
scope: scopeFilters,
|
|
1132
|
+
products: [config.product_profile],
|
|
1133
|
+
type: "acceptance_template",
|
|
1134
|
+
keywords: [],
|
|
1135
|
+
limit: 100,
|
|
1136
|
+
});
|
|
1137
|
+
const exactMatch = allTemplates.find((e) => matchesTemplateByName(e, templateName));
|
|
1138
|
+
if (exactMatch)
|
|
1139
|
+
addEntries([exactMatch]);
|
|
1140
|
+
// 内置模板回退: template 名称未命中时从 templates/knowledge/acceptance_templates/ 加载
|
|
1141
|
+
if (!exactMatch) {
|
|
1142
|
+
const builtinTemplate = loadBuiltinTemplate(templateName, "acceptance_templates");
|
|
1143
|
+
if (builtinTemplate)
|
|
1144
|
+
addEntries([builtinTemplate]);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
// 再按 artifact kind 关键词匹配
|
|
1148
|
+
const artifactKeywords = {
|
|
1149
|
+
prototype_spec: ["原型", "prototype", "原型说明"],
|
|
1150
|
+
api_spec: ["接口", "API", "接口设计"],
|
|
1151
|
+
design_doc: ["设计", "架构", "详细设计"],
|
|
1152
|
+
test_plan: ["测试", "测试计划"],
|
|
1153
|
+
migration_plan: ["迁移", "迁移方案"],
|
|
1154
|
+
review_report: ["审查", "review"],
|
|
1155
|
+
task_breakdown: ["任务", "拆解"],
|
|
1156
|
+
root_cause: ["根因", "分析"],
|
|
1157
|
+
incident_review: ["故障", "复盘"],
|
|
1158
|
+
};
|
|
1159
|
+
const artifactKws = artifactKeywords[routeDecision.output_artifact.kind] ?? [];
|
|
1160
|
+
if (artifactKws.length > 0) {
|
|
1161
|
+
const templateResults = knowledgeIndex.query({
|
|
1162
|
+
scope: scopeFilters,
|
|
1163
|
+
products: [config.product_profile],
|
|
1164
|
+
type: "acceptance_template",
|
|
1165
|
+
keywords: artifactKws,
|
|
1166
|
+
limit: 2,
|
|
1167
|
+
});
|
|
1168
|
+
addEntries(templateResults);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
// 优先级 3: intent keywords 补充(填满 limit)
|
|
1172
|
+
if (results.length < limit) {
|
|
1173
|
+
const keywordResults = knowledgeIndex.query({
|
|
1174
|
+
scope: scopeFilters,
|
|
1175
|
+
products: [config.product_profile],
|
|
1176
|
+
keywords: extractKeywords(intent),
|
|
1177
|
+
limit: limit,
|
|
1178
|
+
});
|
|
1179
|
+
addEntries(keywordResults);
|
|
1180
|
+
}
|
|
1181
|
+
return results.slice(0, limit);
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* 根据执行形态构建模板数据。
|
|
1185
|
+
*/
|
|
1186
|
+
function buildTemplateData(intent, techStack, config, classification, scope, matchedEntries, legacyConventions, isLegacyCode, acceptance, degraded, routeDecision) {
|
|
1187
|
+
const base = {
|
|
1188
|
+
intent,
|
|
1189
|
+
tech_stack: techStack,
|
|
1190
|
+
product_profile: config.product_profile,
|
|
1191
|
+
affected_repos: classification.affected_repos.join(", "),
|
|
1192
|
+
matched_knowledge: matchedEntries.map((e) => ({
|
|
1193
|
+
name: e.name,
|
|
1194
|
+
content: e.body || e.when,
|
|
1195
|
+
})),
|
|
1196
|
+
relevant_files: scope.allowed_paths.slice(0, 10).map((p) => ({ path: p, reason: "scope 允许路径" })),
|
|
1197
|
+
is_legacy_code: isLegacyCode,
|
|
1198
|
+
legacy_conventions: legacyConventions,
|
|
1199
|
+
scope: {
|
|
1200
|
+
allowed_paths: scope.allowed_paths.join(", "),
|
|
1201
|
+
new_files_allowed: scope.new_files_allowed,
|
|
1202
|
+
new_file_patterns: scope.new_file_patterns?.join(", "),
|
|
1203
|
+
},
|
|
1204
|
+
acceptance,
|
|
1205
|
+
degraded,
|
|
186
1206
|
};
|
|
1207
|
+
if (routeDecision) {
|
|
1208
|
+
base.output_artifact = routeDecision.output_artifact;
|
|
1209
|
+
base.input_materials = routeDecision.input_materials;
|
|
1210
|
+
// 根据 ingestion_status 构建 input_material_contract_notes
|
|
1211
|
+
const contractTemplateNotes = [];
|
|
1212
|
+
for (const m of routeDecision.input_materials) {
|
|
1213
|
+
if (m.ingestion_status === "forbidden")
|
|
1214
|
+
contractTemplateNotes.push("FORBIDDEN: " + (m.path ?? "") + " 禁止读取");
|
|
1215
|
+
else if (m.ingestion_status === "requires_confirmation")
|
|
1216
|
+
contractTemplateNotes.push("REQUIRES_CONFIRMATION: " + (m.path ?? "") + " 需确认");
|
|
1217
|
+
}
|
|
1218
|
+
base.input_material_contract_notes = contractTemplateNotes.length > 0 ? contractTemplateNotes : undefined;
|
|
1219
|
+
base.pipeline_hint = routeDecision.pipeline_hint;
|
|
1220
|
+
}
|
|
1221
|
+
return base;
|
|
187
1222
|
}
|
|
188
1223
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
1224
|
+
* 按模板文件名精确匹配知识条目。
|
|
1225
|
+
* 匹配 entry.name、file basename (with/without extension)。
|
|
1226
|
+
*/
|
|
1227
|
+
function matchesTemplateByName(entry, templateName) {
|
|
1228
|
+
const requested = templateName.trim();
|
|
1229
|
+
const fileName = path.basename(entry.file_path);
|
|
1230
|
+
const fileStem = path.basename(entry.file_path, path.extname(entry.file_path));
|
|
1231
|
+
return [entry.name, fileName, fileStem].some((c) => c.trim() === requested);
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* 注入计划阶段上下文(P2 + P3)
|
|
197
1235
|
*/
|
|
198
1236
|
function injectPlanContext(prompt, planContext, knowledgeIndex) {
|
|
199
1237
|
const { current_step, previous_outputs } = planContext;
|
|
200
1238
|
const sections = [];
|
|
201
|
-
// 上一步产出(P3: 产物系统,通过文件传递上下文)
|
|
202
1239
|
const prevEntries = Object.entries(previous_outputs);
|
|
203
1240
|
if (prevEntries.length > 0) {
|
|
204
1241
|
sections.push("## 前序阶段产出");
|
|
@@ -208,22 +1245,19 @@ function injectPlanContext(prompt, planContext, knowledgeIndex) {
|
|
|
208
1245
|
}
|
|
209
1246
|
}
|
|
210
1247
|
}
|
|
211
|
-
// 输出格式模板(P2: 模板是护栏不是笼子)
|
|
212
1248
|
if (current_step.output_template) {
|
|
213
1249
|
const templateEntries = knowledgeIndex.query({
|
|
214
1250
|
type: "acceptance_template",
|
|
215
1251
|
keywords: [],
|
|
216
1252
|
});
|
|
217
|
-
const matched = templateEntries.find((e) => e
|
|
1253
|
+
const matched = templateEntries.find((e) => matchesOutputTemplate(e, current_step.output_template));
|
|
218
1254
|
if (matched?.body) {
|
|
219
1255
|
sections.push(`## 输出格式参考(模板: ${current_step.output_template})\n${matched.body}`);
|
|
220
1256
|
}
|
|
221
1257
|
}
|
|
222
|
-
// 输出路径(P3: 产出保存位置)
|
|
223
1258
|
if (current_step.output_path) {
|
|
224
1259
|
sections.push(`## 产出保存\n将本阶段产出写入: ${current_step.output_path}`);
|
|
225
1260
|
}
|
|
226
|
-
// 建议工具(P2: AI 自主决定是否使用)
|
|
227
1261
|
if (current_step.suggested_tools && current_step.suggested_tools.length > 0) {
|
|
228
1262
|
sections.push(`## 建议工具(可选)\n${current_step.suggested_tools.map((t) => `- ${t}`).join("\n")}`);
|
|
229
1263
|
}
|
|
@@ -231,26 +1265,49 @@ function injectPlanContext(prompt, planContext, knowledgeIndex) {
|
|
|
231
1265
|
return prompt;
|
|
232
1266
|
return `${prompt}\n\n---\n\n## 当前计划阶段\n正在执行: **${current_step.title}**\n${current_step.description}\n\n${sections.join("\n\n")}`;
|
|
233
1267
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
1268
|
+
function matchesOutputTemplate(entry, outputTemplate) {
|
|
1269
|
+
const requested = normalizeTemplateName(outputTemplate);
|
|
1270
|
+
const fileName = path.basename(entry.file_path);
|
|
1271
|
+
const fileStem = path.basename(entry.file_path, path.extname(entry.file_path));
|
|
1272
|
+
return [
|
|
1273
|
+
entry.name,
|
|
1274
|
+
fileName,
|
|
1275
|
+
fileStem,
|
|
1276
|
+
].some((candidate) => normalizeTemplateName(candidate) === requested);
|
|
1277
|
+
}
|
|
1278
|
+
function normalizeTemplateName(name) {
|
|
1279
|
+
return name.trim();
|
|
1280
|
+
}
|
|
239
1281
|
function extractKeywords(intent) {
|
|
240
|
-
// 简单关键词提取: 按常见分隔符拆分,过滤短词
|
|
241
1282
|
return intent
|
|
242
1283
|
.replace(/[的了吗呢把被在从对和与或是]/g, " ")
|
|
243
1284
|
.split(/[\s,,、;;]+/)
|
|
244
1285
|
.filter((w) => w.length >= 2);
|
|
245
1286
|
}
|
|
246
1287
|
/**
|
|
247
|
-
*
|
|
248
|
-
* @param config - 项目配置
|
|
249
|
-
* @param classification - 分类结果
|
|
250
|
-
* @param degraded - 是否处于降级模式(无知识匹配时降级,禁止新建文件)
|
|
251
|
-
* @returns 作用域结果,包含 allowed_paths / readonly_paths / new_files_allowed
|
|
1288
|
+
* 解析 scope: 非代码任务使用简化 scope。
|
|
252
1289
|
*/
|
|
253
|
-
function resolveScope(config, classification, degraded) {
|
|
1290
|
+
function resolveScope(config, classification, degraded, routeDecision) {
|
|
1291
|
+
// 非代码任务: scope 仅允许 .soloforge/output/ 和产物路径
|
|
1292
|
+
if (routeDecision && !routeDecision.mutation_allowed) {
|
|
1293
|
+
const outputArtifact = routeDecision.output_artifact;
|
|
1294
|
+
const allowedPaths = [];
|
|
1295
|
+
if (outputArtifact?.path) {
|
|
1296
|
+
// 只允许写产物路径所在的目录
|
|
1297
|
+
const dir = outputArtifact.path.replace(/\/[^/]+$/, "");
|
|
1298
|
+
allowedPaths.push(dir);
|
|
1299
|
+
}
|
|
1300
|
+
else {
|
|
1301
|
+
allowedPaths.push(".soloforge/output/");
|
|
1302
|
+
}
|
|
1303
|
+
return {
|
|
1304
|
+
allowed_paths: allowedPaths,
|
|
1305
|
+
readonly_paths: config.repos.flatMap((r) => r.scope),
|
|
1306
|
+
new_files_allowed: true,
|
|
1307
|
+
new_file_patterns: ["*.md"],
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
// 代码修改任务: 原有逻辑
|
|
254
1311
|
const allowedPaths = [];
|
|
255
1312
|
for (const repoName of classification.affected_repos) {
|
|
256
1313
|
const repo = config.repos.find((r) => r.name === repoName);
|
|
@@ -258,12 +1315,10 @@ function resolveScope(config, classification, degraded) {
|
|
|
258
1315
|
allowedPaths.push(...repo.scope);
|
|
259
1316
|
}
|
|
260
1317
|
}
|
|
261
|
-
// 无匹配仓库或降级时回退到默认 scope
|
|
262
1318
|
if (allowedPaths.length === 0) {
|
|
263
1319
|
allowedPaths.push(...(config.scope.backend || []));
|
|
264
1320
|
allowedPaths.push(...(config.scope.frontend || []));
|
|
265
1321
|
}
|
|
266
|
-
// 计算 readonly_paths: 不在受影响仓库 scope 内但属于项目的路径
|
|
267
1322
|
const readonlyPaths = [];
|
|
268
1323
|
for (const repo of config.repos) {
|
|
269
1324
|
if (!classification.affected_repos.includes(repo.name)) {
|
|
@@ -275,24 +1330,46 @@ function resolveScope(config, classification, degraded) {
|
|
|
275
1330
|
readonly_paths: readonlyPaths,
|
|
276
1331
|
new_files_allowed: !degraded,
|
|
277
1332
|
new_file_patterns: !degraded && classification.strategy === "full_pipeline"
|
|
278
|
-
? ["**/*"]
|
|
1333
|
+
? ["**/*"]
|
|
279
1334
|
: undefined,
|
|
280
1335
|
};
|
|
281
1336
|
}
|
|
282
1337
|
/**
|
|
283
|
-
* 生成验收标准:
|
|
284
|
-
* @param intent - 用户意图
|
|
285
|
-
* @param classification - 分类结果
|
|
286
|
-
* @param matchedEntries - 匹配的知识条目
|
|
287
|
-
* @param _config - 项目配置(预留参数)
|
|
288
|
-
* @param degraded - 是否处于降级模式
|
|
289
|
-
* @returns 自动验收项和人工验收项
|
|
1338
|
+
* 生成验收标准: 根据执行形态选择不同验收。
|
|
290
1339
|
*/
|
|
291
|
-
function generateAcceptance(intent, classification, matchedEntries, _config, degraded) {
|
|
1340
|
+
function generateAcceptance(intent, classification, matchedEntries, _config, degraded, routeDecision) {
|
|
292
1341
|
const automated = [];
|
|
293
1342
|
const manual = [];
|
|
1343
|
+
// 非代码任务: 产物验收而非编译/测试
|
|
1344
|
+
if (routeDecision && routeDecision.execution_shape !== "code_execution") {
|
|
1345
|
+
if (routeDecision.output_artifact?.path) {
|
|
1346
|
+
automated.push({
|
|
1347
|
+
id: "A-artifact-exists",
|
|
1348
|
+
description: `产物文件已生成: ${routeDecision.output_artifact.path}`,
|
|
1349
|
+
type: "automated",
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
automated.push({
|
|
1353
|
+
id: "A-completeness",
|
|
1354
|
+
description: "产物结构完整,无空白占位",
|
|
1355
|
+
type: "automated",
|
|
1356
|
+
});
|
|
1357
|
+
manual.push({
|
|
1358
|
+
id: "M-quality",
|
|
1359
|
+
description: "产物质量满足可交接标准",
|
|
1360
|
+
type: "manual",
|
|
1361
|
+
});
|
|
1362
|
+
// 从知识中解析验收项
|
|
1363
|
+
for (const entry of matchedEntries) {
|
|
1364
|
+
if (entry.body) {
|
|
1365
|
+
const items = parseAcceptanceItems(entry.body);
|
|
1366
|
+
automated.push(...items);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
return { automated, manual };
|
|
1370
|
+
}
|
|
1371
|
+
// 代码修改任务: 原有逻辑
|
|
294
1372
|
if (degraded) {
|
|
295
|
-
// 降级模式: 仅基本验收(sf_verify 独立生成 build/test 命令,此处仅声明验收项)
|
|
296
1373
|
automated.push({
|
|
297
1374
|
id: "A-build",
|
|
298
1375
|
description: "编译通过,无类型错误",
|
|
@@ -305,20 +1382,17 @@ function generateAcceptance(intent, classification, matchedEntries, _config, deg
|
|
|
305
1382
|
});
|
|
306
1383
|
return { automated, manual };
|
|
307
1384
|
}
|
|
308
|
-
// 完整模式: 构建 + 模式特定 + 任务类型验收
|
|
309
1385
|
automated.push({
|
|
310
1386
|
id: "A-build",
|
|
311
1387
|
description: "编译通过,无类型错误",
|
|
312
1388
|
type: "automated",
|
|
313
1389
|
});
|
|
314
|
-
// 模式特定验收: 从知识正文中解析 ## 验收项
|
|
315
1390
|
for (const entry of matchedEntries) {
|
|
316
1391
|
if (entry.body) {
|
|
317
1392
|
const items = parseAcceptanceItems(entry.body);
|
|
318
1393
|
automated.push(...items);
|
|
319
1394
|
}
|
|
320
1395
|
}
|
|
321
|
-
// 任务类型特定的人工验收项
|
|
322
1396
|
if (classification.task_type === "feature") {
|
|
323
1397
|
manual.push({
|
|
324
1398
|
id: "M-ux",
|
|
@@ -335,12 +1409,6 @@ function generateAcceptance(intent, classification, matchedEntries, _config, deg
|
|
|
335
1409
|
}
|
|
336
1410
|
return { automated, manual };
|
|
337
1411
|
}
|
|
338
|
-
/**
|
|
339
|
-
* 从知识条目的 Markdown 正文中解析 "## 验收项" 下的验收条目。
|
|
340
|
-
* 支持 `(check: 命令)` 语法提取自动检查命令。
|
|
341
|
-
* @param body - 知识条目的 Markdown 正文
|
|
342
|
-
* @returns 解析到的验收项数组
|
|
343
|
-
*/
|
|
344
1412
|
function parseAcceptanceItems(body) {
|
|
345
1413
|
const items = [];
|
|
346
1414
|
if (!body.includes("## 验收项"))
|
|
@@ -355,7 +1423,6 @@ function parseAcceptanceItems(body) {
|
|
|
355
1423
|
if (inSection && line.startsWith("## "))
|
|
356
1424
|
break;
|
|
357
1425
|
if (inSection) {
|
|
358
|
-
// 支持 (check: ...) 提取 check_command
|
|
359
1426
|
const match = line.match(/- \[([A-Z]+-\d+)\]\s*(.+?)(?:\s*\(check:\s*(.+)\))?$/);
|
|
360
1427
|
if (match) {
|
|
361
1428
|
const item = { id: match[1], description: match[2].trim(), type: "automated" };
|
|
@@ -367,11 +1434,6 @@ function parseAcceptanceItems(body) {
|
|
|
367
1434
|
}
|
|
368
1435
|
return items;
|
|
369
1436
|
}
|
|
370
|
-
/**
|
|
371
|
-
* 构建技术栈标签字符串,用于 prompt 中展示项目技术栈信息。
|
|
372
|
-
* @param config - 项目配置
|
|
373
|
-
* @returns 技术栈标签,如 "spring-boot 3.x + react 18"
|
|
374
|
-
*/
|
|
375
1437
|
function buildTechStackLabel(config) {
|
|
376
1438
|
const parts = [];
|
|
377
1439
|
if (config.tech_stack.backend.framework) {
|
|
@@ -383,19 +1445,9 @@ function buildTechStackLabel(config) {
|
|
|
383
1445
|
return parts.join(" + ") || "未知";
|
|
384
1446
|
}
|
|
385
1447
|
// ── 能力 1: 执行契约 ──
|
|
386
|
-
/**
|
|
387
|
-
* 构建执行契约: 根据风险和复杂度生成约束条件和停止条件。
|
|
388
|
-
* 高风险任务收紧约束并限制修复循环次数。
|
|
389
|
-
* @param intent - 用户意图
|
|
390
|
-
* @param classification - 分类结果
|
|
391
|
-
* @param scope - 作用域
|
|
392
|
-
* @param acceptance - 验收标准
|
|
393
|
-
* @returns 执行契约
|
|
394
|
-
*/
|
|
395
1448
|
function buildExecutionContract(intent, classification, scope, acceptance) {
|
|
396
1449
|
const constraints = [];
|
|
397
1450
|
const stopConditions = [];
|
|
398
|
-
// 按 risk 级别收紧约束
|
|
399
1451
|
if (classification.risk === "high") {
|
|
400
1452
|
constraints.push("高风险任务:每个变更文件必须有明确来源(任务卡/缺陷/设计锚点)");
|
|
401
1453
|
constraints.push("禁止顺手重构或范围外变更");
|
|
@@ -423,8 +1475,6 @@ function buildExecutionContract(intent, classification, scope, acceptance) {
|
|
|
423
1475
|
};
|
|
424
1476
|
}
|
|
425
1477
|
// ── 能力 4: 不确定性协议 ──
|
|
426
|
-
// 不确定性模式表: 识别高风险领域(DDL 变更、权限、金额、跨系统、状态机、破坏性操作、并发、敏感数据)
|
|
427
|
-
// 每个模式包含: 正则匹配、触发类型、描述、选项及权衡、推荐方案
|
|
428
1478
|
const UNCERTAINTY_PATTERNS = [
|
|
429
1479
|
{
|
|
430
1480
|
pattern: /(?:表结构|DDL|加字段|删字段|改字段|索引|migration)/i,
|
|
@@ -507,13 +1557,6 @@ const UNCERTAINTY_PATTERNS = [
|
|
|
507
1557
|
recommendation: "传输+存储均加密",
|
|
508
1558
|
},
|
|
509
1559
|
];
|
|
510
|
-
/**
|
|
511
|
-
* 根据意图文本和分类结果生成不确定性触发条件。
|
|
512
|
-
* 高风险 + 高歧义时额外追加确认触发。
|
|
513
|
-
* @param classification - 分类结果
|
|
514
|
-
* @param intent - 用户意图文本
|
|
515
|
-
* @returns 匹配到的不确定性触发条件数组
|
|
516
|
-
*/
|
|
517
1560
|
function buildUncertaintyTriggers(classification, intent) {
|
|
518
1561
|
const triggers = [];
|
|
519
1562
|
for (const pattern of UNCERTAINTY_PATTERNS) {
|
|
@@ -526,7 +1569,6 @@ function buildUncertaintyTriggers(classification, intent) {
|
|
|
526
1569
|
});
|
|
527
1570
|
}
|
|
528
1571
|
}
|
|
529
|
-
// 高风险 + 高歧义 = 额外确认
|
|
530
1572
|
if (classification.risk === "high" && classification.ambiguity === "high") {
|
|
531
1573
|
triggers.push({
|
|
532
1574
|
trigger_type: "high_risk_high_ambiguity",
|
|
@@ -540,31 +1582,27 @@ function buildUncertaintyTriggers(classification, intent) {
|
|
|
540
1582
|
}
|
|
541
1583
|
return triggers;
|
|
542
1584
|
}
|
|
543
|
-
/** 熔断置信度阈值: 低于此值禁止输出执行代码 */
|
|
544
1585
|
const CONFIDENCE_THRESHOLD = 0.95;
|
|
545
1586
|
/**
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
1587
|
+
* 意图熔断器 — 评估意图理解置信度,低于阈值时触发熔断并生成头脑风暴辅助决策。
|
|
1588
|
+
* @param params - 熔断器参数,包含意图、分类结果、匹配知识条目和降级标记
|
|
1589
|
+
* @returns 熔断结果,包含是否触发、置信度、原因和头脑风暴输出
|
|
549
1590
|
*/
|
|
550
1591
|
export function checkCircuitBreaker(params) {
|
|
551
1592
|
const { intent, classification, matchedEntries, degraded } = params;
|
|
552
1593
|
let confidence = 1.0;
|
|
553
|
-
// 维度 1: 知识匹配度(权重 0.35)
|
|
554
1594
|
if (degraded || matchedEntries.length === 0) {
|
|
555
1595
|
confidence -= 0.35;
|
|
556
1596
|
}
|
|
557
1597
|
else if (matchedEntries.length < 2) {
|
|
558
1598
|
confidence -= 0.15;
|
|
559
1599
|
}
|
|
560
|
-
// 维度 2: 分类一致性(权重 0.35)— ambiguity 非 low 或 strategy 为 skip 时扣分
|
|
561
1600
|
if (classification.ambiguity === "high") {
|
|
562
1601
|
confidence -= 0.35;
|
|
563
1602
|
}
|
|
564
1603
|
else if (classification.ambiguity === "medium") {
|
|
565
1604
|
confidence -= 0.15;
|
|
566
1605
|
}
|
|
567
|
-
// 维度 3: 意图明确性(权重 0.30)— 关键词密度不足时扣分
|
|
568
1606
|
const keywords = extractKeywords(intent);
|
|
569
1607
|
if (keywords.length < 2) {
|
|
570
1608
|
confidence -= 0.20;
|
|
@@ -572,10 +1610,7 @@ export function checkCircuitBreaker(params) {
|
|
|
572
1610
|
else if (keywords.length < 3) {
|
|
573
1611
|
confidence -= 0.10;
|
|
574
1612
|
}
|
|
575
|
-
//
|
|
576
|
-
if (degraded) {
|
|
577
|
-
confidence -= 0.10;
|
|
578
|
-
}
|
|
1613
|
+
// degraded 已在上方 L1826 扣除 -0.35,此处不重复扣分
|
|
579
1614
|
confidence = Math.max(0, Math.min(1, confidence));
|
|
580
1615
|
if (confidence < CONFIDENCE_THRESHOLD) {
|
|
581
1616
|
return {
|
|
@@ -587,10 +1622,6 @@ export function checkCircuitBreaker(params) {
|
|
|
587
1622
|
}
|
|
588
1623
|
return { tripped: false, confidence };
|
|
589
1624
|
}
|
|
590
|
-
/**
|
|
591
|
-
* 生成头脑风暴结构: 逻辑盲区 + 三轨演进 + 闭环逼问。
|
|
592
|
-
* 熔断触发时由 AI 补充具体内容,此处生成骨架。
|
|
593
|
-
*/
|
|
594
1625
|
function generateBrainstorm(intent, classification, _matchedEntries) {
|
|
595
1626
|
const taskLabel = classification.task_type === "feature" ? "新功能" :
|
|
596
1627
|
classification.task_type === "bugfix" ? "缺陷修复" :
|