soloforge 1.2.7 → 1.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -321
- package/dist/adapters/claude_code/claude_md.d.ts +5 -0
- package/dist/adapters/claude_code/claude_md.d.ts.map +1 -1
- package/dist/adapters/claude_code/claude_md.js +6 -0
- package/dist/adapters/claude_code/claude_md.js.map +1 -1
- package/dist/adapters/claude_code/hooks.d.ts +4 -0
- package/dist/adapters/claude_code/hooks.d.ts.map +1 -1
- package/dist/adapters/claude_code/hooks.js +5 -0
- package/dist/adapters/claude_code/hooks.js.map +1 -1
- package/dist/adapters/claude_code/server.d.ts.map +1 -1
- package/dist/adapters/claude_code/server.js +9 -21
- package/dist/adapters/claude_code/server.js.map +1 -1
- package/dist/adapters/claude_code/tools.d.ts +5 -0
- package/dist/adapters/claude_code/tools.d.ts.map +1 -1
- package/dist/adapters/claude_code/tools.js +619 -205
- package/dist/adapters/claude_code/tools.js.map +1 -1
- package/dist/adapters/codex/codex_config.d.ts +9 -0
- package/dist/adapters/codex/codex_config.d.ts.map +1 -1
- package/dist/adapters/codex/codex_config.js +11 -3
- package/dist/adapters/codex/codex_config.js.map +1 -1
- package/dist/adapters/codex/codex_rules.d.ts +5 -0
- package/dist/adapters/codex/codex_rules.d.ts.map +1 -1
- package/dist/adapters/codex/codex_rules.js +8 -1
- package/dist/adapters/codex/codex_rules.js.map +1 -1
- package/dist/adapters/shared/workflow_template.d.ts +5 -0
- package/dist/adapters/shared/workflow_template.d.ts.map +1 -1
- package/dist/adapters/shared/workflow_template.js +32 -79
- package/dist/adapters/shared/workflow_template.js.map +1 -1
- package/dist/adapters/trae/trae_config.d.ts +4 -0
- package/dist/adapters/trae/trae_config.d.ts.map +1 -1
- package/dist/adapters/trae/trae_config.js +5 -7
- package/dist/adapters/trae/trae_config.js.map +1 -1
- package/dist/adapters/trae/trae_rules.d.ts +5 -0
- package/dist/adapters/trae/trae_rules.d.ts.map +1 -1
- package/dist/adapters/trae/trae_rules.js +7 -1
- package/dist/adapters/trae/trae_rules.js.map +1 -1
- package/dist/bin/config_commands.d.ts +33 -0
- package/dist/bin/config_commands.d.ts.map +1 -0
- package/dist/bin/config_commands.js +222 -0
- package/dist/bin/config_commands.js.map +1 -0
- package/dist/bin/soloforge.js +609 -119
- package/dist/bin/soloforge.js.map +1 -1
- package/dist/engine/artifact_contract_registry.d.ts +138 -0
- package/dist/engine/artifact_contract_registry.d.ts.map +1 -0
- package/dist/engine/artifact_contract_registry.js +427 -0
- package/dist/engine/artifact_contract_registry.js.map +1 -0
- package/dist/engine/audit_pool.d.ts +40 -0
- package/dist/engine/audit_pool.d.ts.map +1 -1
- package/dist/engine/audit_pool.js +37 -1
- package/dist/engine/audit_pool.js.map +1 -1
- package/dist/engine/audit_sampler.d.ts +5 -0
- package/dist/engine/audit_sampler.d.ts.map +1 -1
- package/dist/engine/audit_sampler.js +6 -0
- package/dist/engine/audit_sampler.js.map +1 -1
- package/dist/engine/audit_verifier.d.ts.map +1 -1
- package/dist/engine/audit_verifier.js +5 -1
- package/dist/engine/audit_verifier.js.map +1 -1
- package/dist/engine/batch1_manifest.d.ts +61 -0
- package/dist/engine/batch1_manifest.d.ts.map +1 -0
- package/dist/engine/batch1_manifest.js +220 -0
- package/dist/engine/batch1_manifest.js.map +1 -0
- package/dist/engine/batch1_reality_gate.d.ts +40 -0
- package/dist/engine/batch1_reality_gate.d.ts.map +1 -0
- package/dist/engine/batch1_reality_gate.js +290 -0
- package/dist/engine/batch1_reality_gate.js.map +1 -0
- package/dist/engine/batch1_scenario_registry.d.ts +62 -0
- package/dist/engine/batch1_scenario_registry.d.ts.map +1 -0
- package/dist/engine/batch1_scenario_registry.js +392 -0
- package/dist/engine/batch1_scenario_registry.js.map +1 -0
- package/dist/engine/batch1_scenario_runners.d.ts +42 -0
- package/dist/engine/batch1_scenario_runners.d.ts.map +1 -0
- package/dist/engine/batch1_scenario_runners.js +292 -0
- package/dist/engine/batch1_scenario_runners.js.map +1 -0
- package/dist/engine/capability_action_advisor.d.ts +3 -0
- package/dist/engine/capability_action_advisor.d.ts.map +1 -1
- package/dist/engine/capability_action_advisor.js +10 -0
- package/dist/engine/capability_action_advisor.js.map +1 -1
- package/dist/engine/capability_registry.d.ts +21 -0
- package/dist/engine/capability_registry.d.ts.map +1 -1
- package/dist/engine/capability_registry.js +113 -0
- package/dist/engine/capability_registry.js.map +1 -1
- package/dist/engine/capability_state_store.d.ts +63 -0
- package/dist/engine/capability_state_store.d.ts.map +1 -1
- package/dist/engine/capability_state_store.js +49 -1
- package/dist/engine/capability_state_store.js.map +1 -1
- package/dist/engine/change_coordinator.d.ts.map +1 -1
- package/dist/engine/change_coordinator.js +5 -4
- package/dist/engine/change_coordinator.js.map +1 -1
- package/dist/engine/classifier.d.ts +15 -5
- package/dist/engine/classifier.d.ts.map +1 -1
- package/dist/engine/classifier.js +70 -69
- package/dist/engine/classifier.js.map +1 -1
- package/dist/engine/code_reviewer.d.ts +14 -0
- package/dist/engine/code_reviewer.d.ts.map +1 -1
- package/dist/engine/code_reviewer.js +109 -10
- package/dist/engine/code_reviewer.js.map +1 -1
- package/dist/engine/cognitive_anchor.d.ts +14 -0
- package/dist/engine/cognitive_anchor.d.ts.map +1 -1
- package/dist/engine/cognitive_anchor.js +26 -2
- package/dist/engine/cognitive_anchor.js.map +1 -1
- package/dist/engine/command_execution_contract.d.ts +226 -0
- package/dist/engine/command_execution_contract.d.ts.map +1 -0
- package/dist/engine/command_execution_contract.js +571 -0
- package/dist/engine/command_execution_contract.js.map +1 -0
- package/dist/engine/confidence_scorer.d.ts.map +1 -1
- package/dist/engine/confidence_scorer.js +1 -0
- package/dist/engine/confidence_scorer.js.map +1 -1
- package/dist/engine/config_precedence_contract.d.ts +269 -0
- package/dist/engine/config_precedence_contract.d.ts.map +1 -0
- package/dist/engine/config_precedence_contract.js +948 -0
- package/dist/engine/config_precedence_contract.js.map +1 -0
- package/dist/engine/conflict_gate.d.ts +13 -0
- package/dist/engine/conflict_gate.d.ts.map +1 -1
- package/dist/engine/conflict_gate.js +20 -2
- package/dist/engine/conflict_gate.js.map +1 -1
- package/dist/engine/consumable_asset_registry.d.ts +46 -0
- package/dist/engine/consumable_asset_registry.d.ts.map +1 -0
- package/dist/engine/consumable_asset_registry.js +758 -0
- package/dist/engine/consumable_asset_registry.js.map +1 -0
- package/dist/engine/contract_guard.d.ts +4 -0
- package/dist/engine/contract_guard.d.ts.map +1 -1
- package/dist/engine/contract_guard.js +15 -7
- package/dist/engine/contract_guard.js.map +1 -1
- package/dist/engine/convention_detector.d.ts.map +1 -1
- package/dist/engine/convention_detector.js +5 -2
- package/dist/engine/convention_detector.js.map +1 -1
- package/dist/engine/core_engineering_principles.d.ts +155 -0
- package/dist/engine/core_engineering_principles.d.ts.map +1 -0
- package/dist/engine/core_engineering_principles.js +426 -0
- package/dist/engine/core_engineering_principles.js.map +1 -0
- package/dist/engine/debt_reporter.d.ts.map +1 -1
- package/dist/engine/debt_reporter.js +3 -1
- package/dist/engine/debt_reporter.js.map +1 -1
- package/dist/engine/debt_tracker.d.ts.map +1 -1
- package/dist/engine/debt_tracker.js +9 -3
- package/dist/engine/debt_tracker.js.map +1 -1
- package/dist/engine/debugger.d.ts.map +1 -1
- package/dist/engine/debugger.js +2 -0
- package/dist/engine/debugger.js.map +1 -1
- package/dist/engine/decision_contract.d.ts +11 -2
- package/dist/engine/decision_contract.d.ts.map +1 -1
- package/dist/engine/decision_contract.js +17 -2
- package/dist/engine/decision_contract.js.map +1 -1
- package/dist/engine/delivery.d.ts +7 -0
- package/dist/engine/delivery.d.ts.map +1 -1
- package/dist/engine/delivery.js +89 -36
- package/dist/engine/delivery.js.map +1 -1
- package/dist/engine/dependency_scanner.d.ts.map +1 -1
- package/dist/engine/dependency_scanner.js +14 -9
- package/dist/engine/dependency_scanner.js.map +1 -1
- package/dist/engine/developer_sovereignty.d.ts.map +1 -1
- package/dist/engine/developer_sovereignty.js +8 -2
- package/dist/engine/developer_sovereignty.js.map +1 -1
- package/dist/engine/diff_ownership.d.ts.map +1 -1
- package/dist/engine/diff_ownership.js +8 -0
- package/dist/engine/diff_ownership.js.map +1 -1
- package/dist/engine/diff_ownership_store.d.ts +26 -10
- package/dist/engine/diff_ownership_store.d.ts.map +1 -1
- package/dist/engine/diff_ownership_store.js +47 -20
- package/dist/engine/diff_ownership_store.js.map +1 -1
- package/dist/engine/dual_layer_mechanism_registry.d.ts +66 -0
- package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -0
- package/dist/engine/dual_layer_mechanism_registry.js +1077 -0
- package/dist/engine/dual_layer_mechanism_registry.js.map +1 -0
- package/dist/engine/escape_report.d.ts +50 -0
- package/dist/engine/escape_report.d.ts.map +1 -1
- package/dist/engine/escape_report.js +38 -0
- package/dist/engine/escape_report.js.map +1 -1
- package/dist/engine/evolver.d.ts.map +1 -1
- package/dist/engine/evolver.js +12 -2
- package/dist/engine/evolver.js.map +1 -1
- package/dist/engine/exploration.d.ts.map +1 -1
- package/dist/engine/exploration.js +87 -0
- package/dist/engine/exploration.js.map +1 -1
- package/dist/engine/failure_classifier.d.ts.map +1 -1
- package/dist/engine/failure_classifier.js +8 -0
- package/dist/engine/failure_classifier.js.map +1 -1
- package/dist/engine/feasibility_checker.d.ts +8 -0
- package/dist/engine/feasibility_checker.d.ts.map +1 -1
- package/dist/engine/feasibility_checker.js +12 -0
- package/dist/engine/feasibility_checker.js.map +1 -1
- package/dist/engine/git_deps.d.ts +4 -1
- package/dist/engine/git_deps.d.ts.map +1 -1
- package/dist/engine/git_deps.js +5 -1
- package/dist/engine/git_deps.js.map +1 -1
- package/dist/engine/governance_report.d.ts +57 -1
- package/dist/engine/governance_report.d.ts.map +1 -1
- package/dist/engine/governance_report.js +91 -1
- package/dist/engine/governance_report.js.map +1 -1
- package/dist/engine/impact_analyzer.d.ts.map +1 -1
- package/dist/engine/impact_analyzer.js +5 -1
- package/dist/engine/impact_analyzer.js.map +1 -1
- package/dist/engine/implementation_roadmap_registry.d.ts +105 -0
- package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -0
- package/dist/engine/implementation_roadmap_registry.js +813 -0
- package/dist/engine/implementation_roadmap_registry.js.map +1 -0
- package/dist/engine/input_material_contract_registry.d.ts +185 -0
- package/dist/engine/input_material_contract_registry.d.ts.map +1 -0
- package/dist/engine/input_material_contract_registry.js +563 -0
- package/dist/engine/input_material_contract_registry.js.map +1 -0
- package/dist/engine/intent_expander.d.ts +8 -27
- package/dist/engine/intent_expander.d.ts.map +1 -1
- package/dist/engine/intent_expander.js +1170 -139
- package/dist/engine/intent_expander.js.map +1 -1
- package/dist/engine/intent_router.d.ts +82 -0
- package/dist/engine/intent_router.d.ts.map +1 -0
- package/dist/engine/intent_router.js +458 -0
- package/dist/engine/intent_router.js.map +1 -0
- package/dist/engine/io_controller.d.ts.map +1 -1
- package/dist/engine/io_controller.js +25 -13
- package/dist/engine/io_controller.js.map +1 -1
- package/dist/engine/java_quality_guard.d.ts.map +1 -1
- package/dist/engine/java_quality_guard.js +8 -4
- package/dist/engine/java_quality_guard.js.map +1 -1
- package/dist/engine/job_manager.d.ts +35 -0
- package/dist/engine/job_manager.d.ts.map +1 -1
- package/dist/engine/job_manager.js +53 -9
- package/dist/engine/job_manager.js.map +1 -1
- package/dist/engine/knowledge_config_loader.d.ts +12 -1
- package/dist/engine/knowledge_config_loader.d.ts.map +1 -1
- package/dist/engine/knowledge_config_loader.js +50 -10
- package/dist/engine/knowledge_config_loader.js.map +1 -1
- package/dist/engine/knowledge_injection_boundary.d.ts +56 -0
- package/dist/engine/knowledge_injection_boundary.d.ts.map +1 -0
- package/dist/engine/knowledge_injection_boundary.js +561 -0
- package/dist/engine/knowledge_injection_boundary.js.map +1 -0
- package/dist/engine/knowledge_manager.d.ts +73 -0
- package/dist/engine/knowledge_manager.d.ts.map +1 -1
- package/dist/engine/knowledge_manager.js +163 -21
- package/dist/engine/knowledge_manager.js.map +1 -1
- package/dist/engine/knowledge_sovereignty.d.ts +1 -0
- package/dist/engine/knowledge_sovereignty.d.ts.map +1 -1
- package/dist/engine/knowledge_sovereignty.js +8 -3
- package/dist/engine/knowledge_sovereignty.js.map +1 -1
- package/dist/engine/llm_gateway.d.ts +74 -3
- package/dist/engine/llm_gateway.d.ts.map +1 -1
- package/dist/engine/llm_gateway.js +75 -4
- package/dist/engine/llm_gateway.js.map +1 -1
- package/dist/engine/main_path_integration_contract.d.ts +383 -0
- package/dist/engine/main_path_integration_contract.d.ts.map +1 -0
- package/dist/engine/main_path_integration_contract.js +1581 -0
- package/dist/engine/main_path_integration_contract.js.map +1 -0
- package/dist/engine/mechanism_contract_registry.d.ts +59 -0
- package/dist/engine/mechanism_contract_registry.d.ts.map +1 -0
- package/dist/engine/mechanism_contract_registry.js +484 -0
- package/dist/engine/mechanism_contract_registry.js.map +1 -0
- package/dist/engine/migration_guard.d.ts.map +1 -1
- package/dist/engine/migration_guard.js +24 -15
- package/dist/engine/migration_guard.js.map +1 -1
- package/dist/engine/mutation_audit.d.ts +10 -0
- package/dist/engine/mutation_audit.d.ts.map +1 -1
- package/dist/engine/mutation_audit.js +19 -2
- package/dist/engine/mutation_audit.js.map +1 -1
- package/dist/engine/observability.d.ts.map +1 -1
- package/dist/engine/observability.js +17 -6
- package/dist/engine/observability.js.map +1 -1
- package/dist/engine/onboarding.d.ts.map +1 -1
- package/dist/engine/onboarding.js +20 -4
- package/dist/engine/onboarding.js.map +1 -1
- package/dist/engine/policy_drift_detector.d.ts +6 -0
- package/dist/engine/policy_drift_detector.d.ts.map +1 -1
- package/dist/engine/policy_drift_detector.js +16 -0
- package/dist/engine/policy_drift_detector.js.map +1 -1
- package/dist/engine/privacy_secret_contract.d.ts +320 -0
- package/dist/engine/privacy_secret_contract.d.ts.map +1 -0
- package/dist/engine/privacy_secret_contract.js +874 -0
- package/dist/engine/privacy_secret_contract.js.map +1 -0
- package/dist/engine/regression_matrix.d.ts +21 -8
- package/dist/engine/regression_matrix.d.ts.map +1 -1
- package/dist/engine/regression_matrix.js +37 -8
- package/dist/engine/regression_matrix.js.map +1 -1
- package/dist/engine/risk_sampler.d.ts +6 -0
- package/dist/engine/risk_sampler.d.ts.map +1 -1
- package/dist/engine/risk_sampler.js +9 -0
- package/dist/engine/risk_sampler.js.map +1 -1
- package/dist/engine/runtime_safety.d.ts.map +1 -1
- package/dist/engine/runtime_safety.js +7 -3
- package/dist/engine/runtime_safety.js.map +1 -1
- package/dist/engine/scaffolder.d.ts.map +1 -1
- package/dist/engine/scaffolder.js +7 -1
- package/dist/engine/scaffolder.js.map +1 -1
- package/dist/engine/scope_controller.d.ts.map +1 -1
- package/dist/engine/scope_controller.js +12 -1
- package/dist/engine/scope_controller.js.map +1 -1
- package/dist/engine/scope_lease.d.ts +43 -0
- package/dist/engine/scope_lease.d.ts.map +1 -1
- package/dist/engine/scope_lease.js +44 -0
- package/dist/engine/scope_lease.js.map +1 -1
- package/dist/engine/semantic_evidence.d.ts +6 -0
- package/dist/engine/semantic_evidence.d.ts.map +1 -1
- package/dist/engine/semantic_evidence.js +9 -0
- package/dist/engine/semantic_evidence.js.map +1 -1
- package/dist/engine/task_context.d.ts +36 -1
- package/dist/engine/task_context.d.ts.map +1 -1
- package/dist/engine/task_context.js +252 -13
- package/dist/engine/task_context.js.map +1 -1
- package/dist/engine/task_planner.d.ts.map +1 -1
- package/dist/engine/task_planner.js +13 -3
- package/dist/engine/task_planner.js.map +1 -1
- package/dist/engine/team_awareness.d.ts.map +1 -1
- package/dist/engine/team_awareness.js +8 -7
- package/dist/engine/team_awareness.js.map +1 -1
- package/dist/engine/template_mechanism_auditor.d.ts +93 -0
- package/dist/engine/template_mechanism_auditor.d.ts.map +1 -0
- package/dist/engine/template_mechanism_auditor.js +622 -0
- package/dist/engine/template_mechanism_auditor.js.map +1 -0
- package/dist/engine/test_generator.d.ts.map +1 -1
- package/dist/engine/test_generator.js +6 -0
- package/dist/engine/test_generator.js.map +1 -1
- package/dist/engine/test_quality.d.ts +6 -0
- package/dist/engine/test_quality.d.ts.map +1 -1
- package/dist/engine/test_quality.js +26 -10
- package/dist/engine/test_quality.js.map +1 -1
- package/dist/engine/tool_invocation_contract_registry.d.ts +136 -0
- package/dist/engine/tool_invocation_contract_registry.d.ts.map +1 -0
- package/dist/engine/tool_invocation_contract_registry.js +731 -0
- package/dist/engine/tool_invocation_contract_registry.js.map +1 -0
- package/dist/engine/traceability.d.ts +3 -0
- package/dist/engine/traceability.d.ts.map +1 -1
- package/dist/engine/traceability.js +12 -4
- package/dist/engine/traceability.js.map +1 -1
- package/dist/engine/user_feedback_contract.d.ts +162 -0
- package/dist/engine/user_feedback_contract.d.ts.map +1 -0
- package/dist/engine/user_feedback_contract.js +356 -0
- package/dist/engine/user_feedback_contract.js.map +1 -0
- package/dist/engine/verifier.d.ts +6 -1
- package/dist/engine/verifier.d.ts.map +1 -1
- package/dist/engine/verifier.js +114 -1
- package/dist/engine/verifier.js.map +1 -1
- package/dist/engine/workflow_contract_registry.d.ts +70 -0
- package/dist/engine/workflow_contract_registry.d.ts.map +1 -0
- package/dist/engine/workflow_contract_registry.js +501 -0
- package/dist/engine/workflow_contract_registry.js.map +1 -0
- package/dist/engine/workspace_resumer.d.ts.map +1 -1
- package/dist/engine/workspace_resumer.js +8 -0
- package/dist/engine/workspace_resumer.js.map +1 -1
- package/dist/engine/zero_config_init.d.ts +67 -2
- package/dist/engine/zero_config_init.d.ts.map +1 -1
- package/dist/engine/zero_config_init.js +410 -28
- package/dist/engine/zero_config_init.js.map +1 -1
- package/dist/git/operations.d.ts +101 -0
- package/dist/git/operations.d.ts.map +1 -1
- package/dist/git/operations.js +125 -9
- package/dist/git/operations.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/knowledge/conflict_detector.d.ts +6 -0
- package/dist/knowledge/conflict_detector.d.ts.map +1 -1
- package/dist/knowledge/conflict_detector.js +7 -0
- package/dist/knowledge/conflict_detector.js.map +1 -1
- package/dist/knowledge/health_checker.d.ts +16 -0
- package/dist/knowledge/health_checker.d.ts.map +1 -1
- package/dist/knowledge/health_checker.js +24 -1
- package/dist/knowledge/health_checker.js.map +1 -1
- package/dist/knowledge/index_manager.d.ts +140 -2
- package/dist/knowledge/index_manager.d.ts.map +1 -1
- package/dist/knowledge/index_manager.js +186 -26
- package/dist/knowledge/index_manager.js.map +1 -1
- package/dist/knowledge/loader.d.ts +8 -1
- package/dist/knowledge/loader.d.ts.map +1 -1
- package/dist/knowledge/loader.js +56 -2
- package/dist/knowledge/loader.js.map +1 -1
- package/dist/knowledge/writer.d.ts +49 -1
- package/dist/knowledge/writer.d.ts.map +1 -1
- package/dist/knowledge/writer.js +55 -1
- package/dist/knowledge/writer.js.map +1 -1
- package/dist/types.d.ts +255 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +29 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +7 -7
- package/templates/knowledge/acceptance_templates//345/216/237/345/236/213/350/257/264/346/230/216/346/250/241/347/211/210.md +30 -2
- package/templates/knowledge/checklists//344/270/273/351/223/276/350/267/257/346/216/245/345/205/245/351/252/214/346/224/266/346/270/205/345/215/225.md +16 -0
- package/templates/knowledge/checklists//345/267/245/344/275/234/346/265/201/351/252/214/346/224/266/346/270/205/345/215/225.md +17 -0
- package/templates/knowledge/checklists//346/240/270/345/277/203/345/267/245/347/250/213/346/211/247/350/241/214/351/252/214/346/224/266/346/270/205/345/215/225.md +43 -0
- package/templates/knowledge/checklists//347/237/245/350/257/206/346/263/250/345/205/245/351/252/214/346/224/266/346/270/205/345/215/225.md +17 -0
- package/templates/knowledge/checklists//351/232/220/347/247/201/345/256/241/346/237/245/346/270/205/345/215/225.md +15 -0
- package/templates/knowledge/checklists//351/252/214/350/257/201/351/252/214/346/224/266/346/270/205/345/215/225.md +16 -0
- package/templates/knowledge/patterns/core//345/206/263/347/255/226/347/275/221/345/205/263.md +1 -0
- package/templates/knowledge/procedures//344/270/273/351/223/276/350/267/257/346/216/245/345/205/245/351/252/214/350/257/201/346/265/201/347/250/213.md +23 -0
- package/templates/knowledge/procedures//345/221/275/344/273/244/346/211/247/350/241/214/346/265/201/347/250/213.md +19 -0
- package/templates/knowledge/procedures//345/267/245/345/205/267/350/260/203/347/224/250/346/265/201/347/250/213.md +15 -0
- package/templates/knowledge/procedures//346/204/217/345/233/276/350/267/257/347/224/261/346/265/201/347/250/213.md +15 -0
- package/templates/knowledge/procedures/{Figma → /346/272/220/347/240/201/345/216/237/345/236/213}/344/272/244/344/273/230/346/265/201/347/250/213.md +5 -5
- package/templates/knowledge/procedures//347/274/226/347/240/201/345/211/215/346/276/204/346/270/205/346/265/201/347/250/213.md +53 -0
- package/templates/knowledge/rules//344/272/247/347/211/251/345/245/221/347/272/246/350/247/204/345/210/231.md +21 -0
- package/templates/knowledge/rules//345/221/275/344/273/244/346/211/247/350/241/214/350/247/204/345/210/231.md +25 -0
- package/templates/knowledge/rules//345/267/245/344/275/234/346/265/201/345/245/221/347/272/246/350/247/204/345/210/231.md +20 -0
- package/templates/knowledge/rules//345/267/245/345/205/267/350/260/203/347/224/250/350/247/204/345/210/231.md +25 -0
- package/templates/knowledge/rules//346/204/217/345/233/276/350/267/257/347/224/261/350/247/204/345/210/231.md +26 -0
- package/templates/knowledge/rules//346/211/247/350/241/214/345/256/210/345/215/253/350/257/204/344/274/260/350/247/204/345/210/231.md +24 -0
- package/templates/knowledge/rules//346/225/217/346/204/237/344/277/241/346/201/257/345/244/204/347/220/206/350/247/204/345/210/231.md +20 -0
- package/templates/knowledge/rules//346/240/270/345/277/203/345/267/245/347/250/213/346/211/247/350/241/214/345/216/237/345/210/231.md +125 -0
- package/templates/knowledge/rules//346/263/250/345/206/214/350/241/250/345/237/272/347/241/200/350/256/276/346/226/275/350/247/204/345/210/231.md +26 -0
- package/templates/knowledge/rules//347/224/250/346/210/267/345/217/215/351/246/210/345/245/221/347/272/246/350/247/204/345/210/231.md +22 -0
- package/templates/knowledge/rules//347/237/245/350/257/206/346/263/250/345/205/245/350/276/271/347/225/214/350/247/204/345/210/231.md +25 -0
- package/templates/knowledge/rules//350/276/223/345/205/245/346/235/220/346/226/231/345/245/221/347/272/246/350/247/204/345/210/231.md +27 -0
- package/templates/knowledge/rules//351/205/215/347/275/256/344/274/230/345/205/210/347/272/247/350/247/204/345/210/231.md +22 -0
- package/templates/knowledge/rules//351/230/262/345/255/244/345/262/233/345/256/236/347/216/260/350/247/204/345/210/231.md +24 -0
- package/templates/knowledge/rules//351/233/266/351/205/215/347/275/256/345/210/235/345/247/213/345/214/226/350/247/204/345/210/231.md +28 -0
- package/templates/knowledge/rules//351/252/214/350/257/201/345/245/221/347/272/246/350/247/204/345/210/231.md +25 -0
- package/templates/knowledge/templates/{review_summary.md → /345/256/241/346/237/245/346/221/230/350/246/201.md} +1 -1
- package/templates/config.yaml +0 -53
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import fss from "node:fs";
|
|
4
|
+
import crypto from "node:crypto";
|
|
5
|
+
import { findToolInvocationContractByName, createToolTrace, validateToolInvocation, } from "../../engine/tool_invocation_contract_registry.js";
|
|
4
6
|
import { classify } from "../../engine/classifier.js";
|
|
7
|
+
import { shouldEnterSoloForge } from "../../engine/intent_router.js";
|
|
5
8
|
import { expand } from "../../engine/intent_expander.js";
|
|
6
9
|
import { generateVerifyCommands } from "../../engine/verifier.js";
|
|
7
10
|
import { evolve } from "../../engine/evolver.js";
|
|
@@ -21,6 +24,7 @@ import { checkFeasibility } from "../../engine/feasibility_checker.js";
|
|
|
21
24
|
import { debugError } from "../../engine/debugger.js";
|
|
22
25
|
import { generateReport } from "../../engine/observability.js";
|
|
23
26
|
import { generateReport as generateGovernanceReport } from "../../engine/governance_report.js";
|
|
27
|
+
import { resolveCurrentProjectConfigReports } from "../../engine/config_precedence_contract.js";
|
|
24
28
|
import { analyzeMigration } from "../../engine/migration_guard.js";
|
|
25
29
|
import { generateTestGuide } from "../../engine/test_generator.js";
|
|
26
30
|
import { analyzeTestQuality } from "../../engine/test_quality.js";
|
|
@@ -39,6 +43,10 @@ import { EscapeReportStore } from "../../engine/escape_report.js";
|
|
|
39
43
|
import { sampleAuditItems } from "../../engine/audit_sampler.js";
|
|
40
44
|
import { decideAction } from "../../engine/capability_action_advisor.js";
|
|
41
45
|
import { CapabilityStateStore } from "../../engine/capability_state_store.js";
|
|
46
|
+
import { auditIntegration, buildMainPathIntegrationContracts, } from "../../engine/main_path_integration_contract.js";
|
|
47
|
+
import { validateMechanismLayerMaps, listMechanismLayerMaps, } from "../../engine/dual_layer_mechanism_registry.js";
|
|
48
|
+
import { classifyIngestionStatus } from "../../engine/input_material_contract_registry.js";
|
|
49
|
+
import { verifyArtifact, } from "../../engine/artifact_contract_registry.js";
|
|
42
50
|
// ── Zod Schema 定义 ──
|
|
43
51
|
const ClassifySchema = {
|
|
44
52
|
intent: z.string().describe("开发者意图描述"),
|
|
@@ -47,6 +55,7 @@ const ClassifySchema = {
|
|
|
47
55
|
const ExpandSchema = {
|
|
48
56
|
task_id: z.string().describe("sf_classify 返回的任务 ID"),
|
|
49
57
|
clarification_answers: z.array(z.string()).optional().describe("对澄清问题的回答"),
|
|
58
|
+
input_material_confirmations: z.array(z.string()).optional().describe("已确认安全的输入材料路径列表"),
|
|
50
59
|
};
|
|
51
60
|
const VerifySchema = {
|
|
52
61
|
task_id: z.string().describe("任务 ID"),
|
|
@@ -146,22 +155,277 @@ const ExploreSchema = {
|
|
|
146
155
|
* @param server - MCP 服务器实例
|
|
147
156
|
* @param deps - SoloForge 核心依赖项
|
|
148
157
|
*/
|
|
158
|
+
/**
|
|
159
|
+
* 注册所有 MCP 工具到服务器实例。
|
|
160
|
+
* @param server - McpServer 实例
|
|
161
|
+
* @param deps - 工具依赖项(配置、知识索引、任务上下文)
|
|
162
|
+
*/
|
|
149
163
|
export function registerTools(server, deps) {
|
|
164
|
+
console.error("[soloForge] 工具注册: 开始注册 MCP 工具...");
|
|
150
165
|
const { config, knowledgeIndex, taskContext } = deps;
|
|
151
166
|
const projectPath = config._projectPath || process.cwd();
|
|
152
167
|
// H1: LLM Gateway — Token 预算熔断,防止单任务 Token 超支
|
|
153
168
|
const gateway = deps.gateway ?? new LLMGateway();
|
|
154
169
|
// H4: IO Controller — 工作区互斥锁,防止外部修改导致的静默覆盖
|
|
155
170
|
const ioController = new IOController(projectPath);
|
|
156
|
-
//
|
|
171
|
+
// ── 统一网关 : 唯一工具调用边界 ──
|
|
172
|
+
/** 计算 sf_status cancel 的动态 category */
|
|
173
|
+
function computeEffectiveCategory(toolName, args, contract) {
|
|
174
|
+
if (toolName === "sf_status" && (args.action === "cancel" || args.job_action === "job_cancel")) {
|
|
175
|
+
return "normal_controlled";
|
|
176
|
+
}
|
|
177
|
+
return contract.category;
|
|
178
|
+
}
|
|
179
|
+
/** 计算 sf_status cancel 的动态 side_effects */
|
|
180
|
+
function computeEffectiveSideEffects(toolName, args, contract) {
|
|
181
|
+
if (toolName === "sf_status" && (args.action === "cancel" || args.job_action === "job_cancel")) {
|
|
182
|
+
return ["task_context_write"];
|
|
183
|
+
}
|
|
184
|
+
return contract.side_effects;
|
|
185
|
+
}
|
|
186
|
+
/** State precheck: validate task status before contract guard */
|
|
187
|
+
const STATE_PRECHECKS = {
|
|
188
|
+
sf_verify: ["executing", "retrying"],
|
|
189
|
+
sf_learn: ["verifying", "executing"],
|
|
190
|
+
sf_expand: ["classifying", "expanding", "clarifying"],
|
|
191
|
+
};
|
|
192
|
+
const STATE_ERROR_LABELS = {
|
|
193
|
+
sf_verify: "不可验证",
|
|
194
|
+
sf_learn: "不可学习",
|
|
195
|
+
sf_expand: "不可膨胀",
|
|
196
|
+
};
|
|
197
|
+
/** 授权模型: explicit > dynamic write gate > destructive gate > workflow gate > category default */
|
|
198
|
+
function checkAuth(toolName, args, contract, ctx, effectiveCategory) {
|
|
199
|
+
// 1. Explicit confirmation
|
|
200
|
+
if (args.confirm === true || args.authorized === true || args.authorization_token) {
|
|
201
|
+
return { required: true, granted: true, reason: "explicit confirmation" };
|
|
202
|
+
}
|
|
203
|
+
// 2. Dynamic write upgrade: cancel/job_cancel from read_only to write → must confirm
|
|
204
|
+
if (effectiveCategory && effectiveCategory !== contract.category && effectiveCategory !== "read_only_bypass") {
|
|
205
|
+
return { required: true, granted: false, reason: "dynamic write upgrade requires explicit confirmation" };
|
|
206
|
+
}
|
|
207
|
+
// 3. Destructive side effects always require explicit
|
|
208
|
+
const destructive = ["git_commit", "git_push", "pr_create", "external_write"];
|
|
209
|
+
if (contract.side_effects.some((e) => destructive.includes(e))) {
|
|
210
|
+
return { required: true, granted: false, reason: "destructive side effects require explicit confirmation" };
|
|
211
|
+
}
|
|
212
|
+
// 4. Standalone strict tools (no workflow required, no task context) → handler does own checks
|
|
213
|
+
if (contract.category === "strict_controlled" && !ctx && !contract.requires_workflow) {
|
|
214
|
+
return { required: false, granted: true, reason: "standalone strict tool" };
|
|
215
|
+
}
|
|
216
|
+
// 5. Workflow contract gate for strict_controlled
|
|
217
|
+
if (contract.category === "strict_controlled" && ctx?.last_tool_trace) {
|
|
218
|
+
const allowed = ctx.last_tool_trace.next_allowed_tools ?? [];
|
|
219
|
+
if (allowed.includes(toolName)) {
|
|
220
|
+
return { required: true, granted: true, reason: "workflow contract gate" };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// 5b. State-based fallback: strict tool with valid-state task but no tool_trace
|
|
224
|
+
if (contract.category === "strict_controlled" && ctx && !ctx.last_tool_trace && contract.requires_workflow) {
|
|
225
|
+
const validStates = STATE_PRECHECKS[toolName];
|
|
226
|
+
if (validStates && validStates.includes(ctx.status)) {
|
|
227
|
+
return { required: true, granted: true, reason: "task in valid state for tool" };
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// 5c. Non-strict tools: auto-grant unless requires_authorization
|
|
231
|
+
if (contract.category === "read_only_bypass" || contract.category === "normal_controlled") {
|
|
232
|
+
if (contract.requires_authorization) {
|
|
233
|
+
return { required: true, granted: false, reason: "tool requires explicit authorization" };
|
|
234
|
+
}
|
|
235
|
+
return { required: false, granted: true, reason: "non-strict category" };
|
|
236
|
+
}
|
|
237
|
+
return { required: true, granted: false, reason: "no authorization source" };
|
|
238
|
+
}
|
|
157
239
|
function registerSafeTool(name, desc, schema, handler) {
|
|
158
240
|
server.tool(name, desc, schema, async (args) => {
|
|
241
|
+
const invocationId = `inv-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
242
|
+
const taskId = args.task_id;
|
|
243
|
+
const contract = findToolInvocationContractByName(name);
|
|
244
|
+
// No contract → hard fail
|
|
245
|
+
if (!contract) {
|
|
246
|
+
return {
|
|
247
|
+
content: [{ type: "text", text: JSON.stringify({ error: `工具 ${name} 未注册契约` }) }],
|
|
248
|
+
isError: true,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const effectiveCategory = computeEffectiveCategory(name, args, contract);
|
|
252
|
+
const effectiveSideEffects = computeEffectiveSideEffects(name, args, contract);
|
|
253
|
+
// Load TaskContext
|
|
254
|
+
let ctx = null;
|
|
255
|
+
if (taskId) {
|
|
256
|
+
ctx = await taskContext.load(taskId);
|
|
257
|
+
}
|
|
258
|
+
// State precheck: validate task status before contract guard
|
|
259
|
+
if (taskId && STATE_PRECHECKS[name] && ctx) {
|
|
260
|
+
const validStates = STATE_PRECHECKS[name];
|
|
261
|
+
if (!validStates.includes(ctx.status)) {
|
|
262
|
+
const label = STATE_ERROR_LABELS[name] ?? "状态不正确";
|
|
263
|
+
return {
|
|
264
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
265
|
+
error: `任务状态 ${ctx.status} ${label},需要 ${validStates.join(" 或 ")}`,
|
|
266
|
+
status: ctx.status,
|
|
267
|
+
}) }],
|
|
268
|
+
isError: true,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// Strict controlled without task_id
|
|
273
|
+
const isStandaloneStrict = !contract.requires_workflow;
|
|
274
|
+
if (contract.category === "strict_controlled" && !taskId && !isStandaloneStrict) {
|
|
275
|
+
return {
|
|
276
|
+
content: [{ type: "text", text: JSON.stringify({ error: `strict controlled 工具 ${name} 需要 task_id` }) }],
|
|
277
|
+
isError: true,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
// Authorization
|
|
281
|
+
const authorization = checkAuth(name, args, contract, ctx ?? undefined, effectiveCategory);
|
|
282
|
+
// Authorization denied → hard fail for gateway-level denials only
|
|
283
|
+
// (dynamic write upgrade, destructive ops, strict_controlled with no auth source)
|
|
284
|
+
// Handler-level authorization (e.g. sf_capability_update confirm) is left to the handler
|
|
285
|
+
const gatewayDenial = !authorization.granted &&
|
|
286
|
+
authorization.reason !== "tool requires explicit authorization";
|
|
287
|
+
if (gatewayDenial) {
|
|
288
|
+
const blockedTrace = createToolTrace({
|
|
289
|
+
tool_name: name, invocation_id: invocationId, task_id: taskId,
|
|
290
|
+
actual_side_effects: effectiveSideEffects,
|
|
291
|
+
next_allowed_tools: contract.default_next_tools,
|
|
292
|
+
forbidden_tools: contract.forbidden_next_tools,
|
|
293
|
+
authorization, bypass: undefined,
|
|
294
|
+
});
|
|
295
|
+
const authViolation = {
|
|
296
|
+
invocation_id: invocationId, tool_name: name,
|
|
297
|
+
violation_type: "missing_authorization", severity: "hard_fail",
|
|
298
|
+
reason: authorization.reason ?? "authorization denied",
|
|
299
|
+
recovery: "提供 confirm=true / authorized=true / authorization_token",
|
|
300
|
+
};
|
|
301
|
+
if (taskId && ctx) {
|
|
302
|
+
await taskContext.setToolTrace(taskId, blockedTrace, [authViolation]);
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
306
|
+
error: authViolation.reason, violation: authViolation,
|
|
307
|
+
tool_trace: blockedTrace,
|
|
308
|
+
next_allowed_tools: contract.default_next_tools,
|
|
309
|
+
forbidden_tools: contract.forbidden_next_tools,
|
|
310
|
+
}) }],
|
|
311
|
+
isError: true,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
// Bypass for read_only_bypass
|
|
315
|
+
const bypass = effectiveCategory === "read_only_bypass"
|
|
316
|
+
? { allowed: true, reason: "read_only" } : undefined;
|
|
317
|
+
// Contract validation
|
|
318
|
+
const lastTrace = ctx?.last_tool_trace;
|
|
319
|
+
// Build effective contract override for dynamic tools (e.g., sf_status cancel)
|
|
320
|
+
let contractOverride;
|
|
321
|
+
if (effectiveCategory !== contract.category || effectiveSideEffects !== contract.side_effects) {
|
|
322
|
+
contractOverride = { ...contract, category: effectiveCategory, side_effects: effectiveSideEffects };
|
|
323
|
+
}
|
|
324
|
+
// Workflow ID: only from real expansion trace
|
|
325
|
+
const explicitWorkflowId = ctx?.expansion?.workflow_trace?.workflow_id;
|
|
326
|
+
const violations = validateToolInvocation({
|
|
327
|
+
tool_name: name,
|
|
328
|
+
current_next_allowed: lastTrace?.next_allowed_tools ?? [],
|
|
329
|
+
current_forbidden: lastTrace?.forbidden_tools ?? [],
|
|
330
|
+
authorization,
|
|
331
|
+
bypass,
|
|
332
|
+
actual_side_effects: effectiveSideEffects,
|
|
333
|
+
workflow_id: explicitWorkflowId,
|
|
334
|
+
_contractOverride: contractOverride,
|
|
335
|
+
});
|
|
336
|
+
// State-based fallback: downgrade contract_state_mismatch from hard_fail to require_human
|
|
337
|
+
if (authorization.reason === "task in valid state for tool") {
|
|
338
|
+
for (const v of violations) {
|
|
339
|
+
if (v.violation_type === "contract_state_mismatch" && v.severity === "hard_fail") {
|
|
340
|
+
v.severity = "require_human";
|
|
341
|
+
v.reason += " (state-based fallback: no real workflow_id)";
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// Hard-fail violations → block
|
|
346
|
+
const hardFail = violations.find(v => v.severity === "hard_fail");
|
|
347
|
+
if (hardFail) {
|
|
348
|
+
const blockedTrace = createToolTrace({
|
|
349
|
+
tool_name: name, invocation_id: invocationId, task_id: taskId,
|
|
350
|
+
actual_side_effects: effectiveSideEffects,
|
|
351
|
+
next_allowed_tools: contract.default_next_tools,
|
|
352
|
+
forbidden_tools: contract.forbidden_next_tools,
|
|
353
|
+
authorization, bypass,
|
|
354
|
+
});
|
|
355
|
+
if (taskId && ctx) {
|
|
356
|
+
await taskContext.setToolTrace(taskId, blockedTrace, violations);
|
|
357
|
+
}
|
|
358
|
+
return {
|
|
359
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
360
|
+
error: hardFail.reason, violation: hardFail,
|
|
361
|
+
tool_trace: blockedTrace,
|
|
362
|
+
next_allowed_tools: contract.default_next_tools,
|
|
363
|
+
forbidden_tools: contract.forbidden_next_tools,
|
|
364
|
+
}) }],
|
|
365
|
+
isError: true,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
// Execute handler
|
|
159
369
|
try {
|
|
160
|
-
|
|
370
|
+
const raw = await handler(args);
|
|
371
|
+
// Pass through if handler returned { content } directly
|
|
372
|
+
if (raw && typeof raw === "object" && "content" in raw && Array.isArray(raw.content)) {
|
|
373
|
+
return raw;
|
|
374
|
+
}
|
|
375
|
+
// Extract data from { result } pattern
|
|
376
|
+
const data = raw?.result !== undefined ? raw.result : raw;
|
|
377
|
+
const hasError = !!(data && typeof data === "object" && "error" in data);
|
|
378
|
+
// Build trace
|
|
379
|
+
const trace = createToolTrace({
|
|
380
|
+
tool_name: name, invocation_id: invocationId, task_id: taskId,
|
|
381
|
+
workflow_id: ctx?.expansion?.workflow_trace?.workflow_id,
|
|
382
|
+
actual_side_effects: effectiveSideEffects,
|
|
383
|
+
next_allowed_tools: contract.default_next_tools,
|
|
384
|
+
forbidden_tools: contract.forbidden_next_tools,
|
|
385
|
+
authorization, bypass,
|
|
386
|
+
});
|
|
387
|
+
// Write trace to TaskContext
|
|
388
|
+
if (taskId) {
|
|
389
|
+
await taskContext.setToolTrace(taskId, trace, violations.length > 0 ? violations : undefined);
|
|
390
|
+
}
|
|
391
|
+
// Decorate response with trace + next/forbidden
|
|
392
|
+
const response = {
|
|
393
|
+
...data,
|
|
394
|
+
tool_trace: trace,
|
|
395
|
+
next_allowed_tools: contract.default_next_tools,
|
|
396
|
+
forbidden_tools: contract.forbidden_next_tools,
|
|
397
|
+
};
|
|
398
|
+
// State-based fallback: expose degraded workflow in response
|
|
399
|
+
if (authorization.reason === "task in valid state for tool") {
|
|
400
|
+
response.degraded_workflow = true;
|
|
401
|
+
response.workflow_source = "state-based-fallback";
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
|
|
405
|
+
isError: hasError ? true : undefined,
|
|
406
|
+
};
|
|
161
407
|
}
|
|
162
408
|
catch (err) {
|
|
409
|
+
const errorTrace = createToolTrace({
|
|
410
|
+
tool_name: name, invocation_id: invocationId, task_id: taskId,
|
|
411
|
+
actual_side_effects: effectiveSideEffects,
|
|
412
|
+
next_allowed_tools: contract.default_next_tools,
|
|
413
|
+
forbidden_tools: contract.forbidden_next_tools,
|
|
414
|
+
authorization, bypass,
|
|
415
|
+
});
|
|
416
|
+
if (taskId) {
|
|
417
|
+
try {
|
|
418
|
+
await taskContext.setToolTrace(taskId, errorTrace);
|
|
419
|
+
}
|
|
420
|
+
catch { /* best effort */ }
|
|
421
|
+
}
|
|
163
422
|
return {
|
|
164
|
-
content: [{ type: "text", text: JSON.stringify({
|
|
423
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
424
|
+
error: err instanceof Error ? err.message : String(err),
|
|
425
|
+
tool_trace: errorTrace,
|
|
426
|
+
next_allowed_tools: contract.default_next_tools,
|
|
427
|
+
forbidden_tools: contract.forbidden_next_tools,
|
|
428
|
+
}) }],
|
|
165
429
|
isError: true,
|
|
166
430
|
};
|
|
167
431
|
}
|
|
@@ -169,6 +433,10 @@ export function registerTools(server, deps) {
|
|
|
169
433
|
}
|
|
170
434
|
// 加载认知锚点上下文 — 必须提供相关性参数,禁止全量加载
|
|
171
435
|
function loadRelevantAnchors(query) {
|
|
436
|
+
console.error("[soloForge] 工具注册: 加载认知锚点");
|
|
437
|
+
return _loadRelevantAnchorsInner(query);
|
|
438
|
+
}
|
|
439
|
+
function _loadRelevantAnchorsInner(query) {
|
|
172
440
|
const stateDir = taskContext.getStateDir();
|
|
173
441
|
const mapPath = path.join(stateDir, "cognitive.map.json");
|
|
174
442
|
const mapData = readMapJson(mapPath);
|
|
@@ -219,61 +487,52 @@ export function registerTools(server, deps) {
|
|
|
219
487
|
stale_anchor: a.stale_anchor,
|
|
220
488
|
}));
|
|
221
489
|
}
|
|
490
|
+
console.error("[soloForge] 工具注册: 批量注册核心/辅助/知识维护工具...");
|
|
222
491
|
// ── sf_classify: 意图分类入口,创建任务上下文并返回分类结果 ──
|
|
223
492
|
registerSafeTool("sf_classify", "分析开发者意图,返回任务类型、风险、复杂度和执行策略", ClassifySchema, async (args) => {
|
|
224
493
|
// 检查是否存在进行中的任务
|
|
225
494
|
const existing = await taskContext.getCurrentTask();
|
|
226
495
|
if (existing && !["done", "failed"].includes(existing.status)) {
|
|
227
496
|
return {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}),
|
|
237
|
-
}],
|
|
238
|
-
isError: true,
|
|
497
|
+
result: {
|
|
498
|
+
error: "存在未完成的任务",
|
|
499
|
+
warning: "存在未完成的任务",
|
|
500
|
+
existing_task_id: existing.task_id,
|
|
501
|
+
existing_status: existing.status,
|
|
502
|
+
existing_intent: existing.intent,
|
|
503
|
+
hint: "调用 sf_status action=cancel 取消旧任务,或继续完成它",
|
|
504
|
+
},
|
|
239
505
|
};
|
|
240
506
|
}
|
|
241
507
|
// 创建任务上下文
|
|
242
508
|
const ctx = await taskContext.create(args.intent, config.product_profile);
|
|
243
|
-
const input = { intent: args.intent, project_path: projectPath };
|
|
509
|
+
const input = { intent: args.intent, project_path: projectPath, task_id: ctx.task_id };
|
|
244
510
|
const classification = classify(input);
|
|
245
511
|
// 存储分类结果
|
|
246
512
|
await taskContext.setClassification(ctx.task_id, classification);
|
|
247
|
-
if (classification.
|
|
513
|
+
if (!shouldEnterSoloForge(classification.route_decision)) {
|
|
248
514
|
await taskContext.updateStatus(ctx.task_id, "done");
|
|
249
515
|
}
|
|
250
516
|
return {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
...classification,
|
|
256
|
-
}, null, 2),
|
|
257
|
-
}],
|
|
517
|
+
result: {
|
|
518
|
+
task_id: ctx.task_id,
|
|
519
|
+
...classification,
|
|
520
|
+
},
|
|
258
521
|
};
|
|
259
522
|
});
|
|
260
523
|
// ── sf_expand: 意图膨胀,生成结构化 prompt 并注入计划上下文 ──
|
|
261
524
|
registerSafeTool("sf_expand", "将意图膨胀为结构化 prompt,包含 scope、验收标准和知识匹配。当存在计划时自动注入当前阶段上下文和输出模板", ExpandSchema, async (args) => {
|
|
262
525
|
const ctx = await taskContext.load(args.task_id);
|
|
263
526
|
if (!ctx || !ctx.classification) {
|
|
264
|
-
return {
|
|
265
|
-
content: [{ type: "text", text: JSON.stringify({ error: "任务不存在或尚未分类,请先调用 sf_classify" }) }],
|
|
266
|
-
isError: true,
|
|
267
|
-
};
|
|
527
|
+
return { result: { error: "任务不存在或尚未分类,请先调用 sf_classify" } };
|
|
268
528
|
}
|
|
269
|
-
// 状态守卫:classifying → expanding
|
|
270
|
-
if (ctx.status === "classifying") {
|
|
529
|
+
// 状态守卫:classifying/expanding/clarifying → expanding
|
|
530
|
+
if (ctx.status === "classifying" || ctx.status === "clarifying") {
|
|
271
531
|
await taskContext.updateStatus(args.task_id, "expanding");
|
|
272
532
|
}
|
|
273
533
|
else if (ctx.status !== "expanding") {
|
|
274
534
|
return {
|
|
275
|
-
|
|
276
|
-
isError: true,
|
|
535
|
+
result: { error: `任务状态 ${ctx.status} 不可膨胀,需要 classifying 或 expanding`, status: ctx.status },
|
|
277
536
|
};
|
|
278
537
|
}
|
|
279
538
|
// 构建计划上下文(如果存在计划)
|
|
@@ -324,7 +583,10 @@ export function registerTools(server, deps) {
|
|
|
324
583
|
config,
|
|
325
584
|
knowledgeIndex,
|
|
326
585
|
clarificationAnswers: args.clarification_answers,
|
|
586
|
+
route_decision: ctx.classification?.route_decision,
|
|
327
587
|
plan_context: planContext,
|
|
588
|
+
input_material_confirmations: args.input_material_confirmations,
|
|
589
|
+
task_id: args.task_id,
|
|
328
590
|
});
|
|
329
591
|
}
|
|
330
592
|
catch (expandErr) {
|
|
@@ -343,12 +605,26 @@ export function registerTools(server, deps) {
|
|
|
343
605
|
gateway.endTask();
|
|
344
606
|
}
|
|
345
607
|
expansion.task_id = args.task_id;
|
|
608
|
+
// Input Material Contract: 处理 hard-blocking 结果
|
|
609
|
+
// Privacy Gate: 隐私/敏感信息策略阻断
|
|
610
|
+
const isBlocked = expansion.prompt.startsWith("## 阻塞:输入材料禁止读取")
|
|
611
|
+
|| expansion.prompt.startsWith("## 阻塞:隐私/敏感信息策略");
|
|
612
|
+
const isMaterialClarification = expansion.prompt.startsWith("## 澄清请求") && expansion.input_materials?.some((m) => m.access_mode !== "forbidden" && classifyIngestionStatus(m.path_or_ref) === "requires_confirmation");
|
|
346
613
|
// 注入 H1/H4 advisory warnings
|
|
347
614
|
const advisories = {};
|
|
348
615
|
if (h1Warning)
|
|
349
616
|
advisories.h1_advisory = h1Warning;
|
|
350
617
|
if (h4LockWarning)
|
|
351
618
|
advisories.h4_advisory = h4LockWarning;
|
|
619
|
+
// Config precedence warnings
|
|
620
|
+
if (expansion.config_resolution_reports && expansion.config_resolution_reports.length > 0) {
|
|
621
|
+
const configWarnings = expansion.config_resolution_reports
|
|
622
|
+
.filter(r => r.conflicts.length > 0)
|
|
623
|
+
.map(r => r.conflicts.map(c => `${c.reason}`).join("; "));
|
|
624
|
+
if (configWarnings.length > 0) {
|
|
625
|
+
advisories.config_precedence_warnings = configWarnings;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
352
628
|
// 决策契约 advisory: 校验 expand 输出是否包含默认决策字段
|
|
353
629
|
const decisionContract = validateDecisionOutput(expansion);
|
|
354
630
|
if (!decisionContract.passed) {
|
|
@@ -357,6 +633,10 @@ export function registerTools(server, deps) {
|
|
|
357
633
|
// 存储膨胀结果
|
|
358
634
|
try {
|
|
359
635
|
await taskContext.setExpansion(args.task_id, expansion);
|
|
636
|
+
// 存储产物记录
|
|
637
|
+
if (expansion.output_artifact_record) {
|
|
638
|
+
await taskContext.setArtifact(args.task_id, expansion.output_artifact_record);
|
|
639
|
+
}
|
|
360
640
|
}
|
|
361
641
|
catch (setErr) {
|
|
362
642
|
try {
|
|
@@ -367,9 +647,17 @@ export function registerTools(server, deps) {
|
|
|
367
647
|
}
|
|
368
648
|
throw setErr;
|
|
369
649
|
}
|
|
370
|
-
//
|
|
650
|
+
// 转换到下一阶段:blocked → failed, clarification → clarifying, else → executing
|
|
371
651
|
try {
|
|
372
|
-
|
|
652
|
+
if (isBlocked) {
|
|
653
|
+
await taskContext.updateStatus(args.task_id, "failed");
|
|
654
|
+
}
|
|
655
|
+
else if (expansion.prompt.startsWith("## 澄清请求")) {
|
|
656
|
+
await taskContext.updateStatus(args.task_id, "clarifying");
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
await taskContext.updateStatus(args.task_id, "executing");
|
|
660
|
+
}
|
|
373
661
|
}
|
|
374
662
|
catch (updateErr) {
|
|
375
663
|
try {
|
|
@@ -380,11 +668,11 @@ export function registerTools(server, deps) {
|
|
|
380
668
|
}
|
|
381
669
|
throw updateErr;
|
|
382
670
|
}
|
|
671
|
+
const expandPayload = Object.keys(advisories).length > 0
|
|
672
|
+
? { ...expansion, advisories }
|
|
673
|
+
: expansion;
|
|
383
674
|
return {
|
|
384
|
-
|
|
385
|
-
type: "text",
|
|
386
|
-
text: JSON.stringify(Object.keys(advisories).length > 0 ? { ...expansion, advisories } : expansion, null, 2),
|
|
387
|
-
}],
|
|
675
|
+
result: expandPayload,
|
|
388
676
|
};
|
|
389
677
|
});
|
|
390
678
|
// ── sf_verify: 生成验证命令(构建、测试、验收检查) ──
|
|
@@ -392,15 +680,13 @@ export function registerTools(server, deps) {
|
|
|
392
680
|
const ctx = await taskContext.load(args.task_id);
|
|
393
681
|
if (!ctx) {
|
|
394
682
|
return {
|
|
395
|
-
|
|
396
|
-
isError: true,
|
|
683
|
+
result: { error: "任务不存在" },
|
|
397
684
|
};
|
|
398
685
|
}
|
|
399
686
|
const VALID_VERIFY_STATES = ["executing", "retrying"];
|
|
400
687
|
if (!VALID_VERIFY_STATES.includes(ctx.status)) {
|
|
401
688
|
return {
|
|
402
|
-
|
|
403
|
-
isError: true,
|
|
689
|
+
result: { error: `任务状态 ${ctx.status} 不可验证,需要 executing 或 retrying`, status: ctx.status },
|
|
404
690
|
};
|
|
405
691
|
}
|
|
406
692
|
const acceptanceItems = ctx.expansion
|
|
@@ -411,14 +697,68 @@ export function registerTools(server, deps) {
|
|
|
411
697
|
const h4Warning = !integrity.clean
|
|
412
698
|
? { warning: `H4 advisory: ${integrity.message}`, dirty_files: integrity.dirty_files }
|
|
413
699
|
: undefined;
|
|
414
|
-
const verifyResult = generateVerifyCommands(config, args.changed_files, acceptanceItems);
|
|
700
|
+
const verifyResult = generateVerifyCommands(config, args.changed_files, acceptanceItems, ctx?.expansion?.workflow_trace?.route);
|
|
415
701
|
verifyResult.task_id = args.task_id;
|
|
702
|
+
// Artifact lifecycle check : draft → verified requires ArtifactVerificationResult.passed
|
|
703
|
+
let artifactVerificationResult;
|
|
704
|
+
let artifactFileMissing = false;
|
|
705
|
+
if (ctx.artifact_output && ctx.artifact_output.status === "draft") {
|
|
706
|
+
// Resolve artifact file and compute hash before verification
|
|
707
|
+
const artifact = ctx.artifact_output;
|
|
708
|
+
const fullPath = path.join(projectPath, artifact.path);
|
|
709
|
+
if (fss.existsSync(fullPath)) {
|
|
710
|
+
const fileContent = fss.readFileSync(fullPath);
|
|
711
|
+
const hash = crypto.createHash("sha256").update(fileContent).digest("hex");
|
|
712
|
+
artifact.hash = `sha256:${hash}`;
|
|
713
|
+
if (!artifact.evidence_refs.some(r => r.startsWith("file:artifact:"))) {
|
|
714
|
+
artifact.evidence_refs.push(`file:artifact:path=${artifact.path} hash=sha256:${hash}`);
|
|
715
|
+
}
|
|
716
|
+
// Save updated artifact with hash
|
|
717
|
+
const ctxForHash = await taskContext.load(args.task_id);
|
|
718
|
+
if (ctxForHash?.artifact_output) {
|
|
719
|
+
ctxForHash.artifact_output.hash = artifact.hash;
|
|
720
|
+
if (!ctxForHash.artifact_output.evidence_refs.some(r => r.startsWith("file:artifact:"))) {
|
|
721
|
+
ctxForHash.artifact_output.evidence_refs.push(`file:artifact:path=${artifact.path} hash=sha256:${hash}`);
|
|
722
|
+
}
|
|
723
|
+
await taskContext.save(ctxForHash);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
artifactFileMissing = true;
|
|
728
|
+
}
|
|
729
|
+
artifactVerificationResult = verifyArtifact(artifact.kind, artifact);
|
|
730
|
+
}
|
|
416
731
|
// 记录变更文件
|
|
417
732
|
await taskContext.setExecution(args.task_id, args.changed_files);
|
|
733
|
+
// Mark no_change_artifact when no real files changed but artifact exists
|
|
734
|
+
if (args.changed_files.length === 0 && ctx.artifact_output) {
|
|
735
|
+
const execCtx = await taskContext.load(args.task_id);
|
|
736
|
+
if (execCtx?.execution) {
|
|
737
|
+
execCtx.execution.no_change_artifact = true;
|
|
738
|
+
await taskContext.save(execCtx);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
418
741
|
// 生成验证命令成功后再转换状态,避免操作失败导致任务卡在 verifying
|
|
742
|
+
if (ctx.status === "retrying") {
|
|
743
|
+
await taskContext.updateStatus(args.task_id, "executing");
|
|
744
|
+
}
|
|
419
745
|
await taskContext.updateStatus(args.task_id, "verifying");
|
|
420
746
|
// 存储验证结果
|
|
421
747
|
await taskContext.setVerification(args.task_id, verifyResult);
|
|
748
|
+
// Artifact lifecycle transition: draft → verified only if ArtifactVerificationResult.passed
|
|
749
|
+
if (ctx.artifact_output && ctx.artifact_output.status === "draft" && artifactVerificationResult?.passed) {
|
|
750
|
+
const evidenceRef = `verification:${ctx.task_id}:checks=${artifactVerificationResult.checks.length}:summary=${artifactVerificationResult.summary.slice(0, 60)}`;
|
|
751
|
+
try {
|
|
752
|
+
await taskContext.updateArtifactStatus(args.task_id, {
|
|
753
|
+
status: "verified",
|
|
754
|
+
evidenceRef,
|
|
755
|
+
hasVerification: true,
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
catch {
|
|
759
|
+
// Transition blocked — artifact stays draft, pipeline continues
|
|
760
|
+
}
|
|
761
|
+
}
|
|
422
762
|
// 认知锚点上下文回放(按变更文件相关性)
|
|
423
763
|
const verifyAnchors = loadRelevantAnchors({ file_paths: args.changed_files });
|
|
424
764
|
const verifyExtras = {};
|
|
@@ -426,11 +766,18 @@ export function registerTools(server, deps) {
|
|
|
426
766
|
verifyExtras.h4_advisory = h4Warning;
|
|
427
767
|
if (verifyAnchors && verifyAnchors.length > 0)
|
|
428
768
|
verifyExtras.cognitive_anchors = verifyAnchors;
|
|
769
|
+
if (ctx.artifact_output && ctx.artifact_output.status === "draft" && artifactVerificationResult && !artifactVerificationResult.passed) {
|
|
770
|
+
const reason = artifactFileMissing
|
|
771
|
+
? `产物文件不存在 (${ctx.artifact_output.path}),无法计算 hash`
|
|
772
|
+
: artifactVerificationResult.summary;
|
|
773
|
+
verifyExtras.artifact_warning = `产物验收检查未通过: ${reason}`;
|
|
774
|
+
verifyExtras.artifact_verification = artifactVerificationResult;
|
|
775
|
+
}
|
|
776
|
+
const verifyPayload = Object.keys(verifyExtras).length > 0
|
|
777
|
+
? { ...verifyResult, ...verifyExtras }
|
|
778
|
+
: verifyResult;
|
|
429
779
|
return {
|
|
430
|
-
|
|
431
|
-
type: "text",
|
|
432
|
-
text: JSON.stringify(Object.keys(verifyExtras).length > 0 ? { ...verifyResult, ...verifyExtras } : verifyResult, null, 2),
|
|
433
|
-
}],
|
|
780
|
+
result: verifyPayload,
|
|
434
781
|
};
|
|
435
782
|
});
|
|
436
783
|
// ── sf_learn: 从执行结果中提取知识,支持重试循环控制 ──
|
|
@@ -438,15 +785,13 @@ export function registerTools(server, deps) {
|
|
|
438
785
|
const ctx = await taskContext.load(args.task_id);
|
|
439
786
|
if (!ctx) {
|
|
440
787
|
return {
|
|
441
|
-
|
|
442
|
-
isError: true,
|
|
788
|
+
result: { error: "任务不存在" },
|
|
443
789
|
};
|
|
444
790
|
}
|
|
445
791
|
const VALID_LEARN_STATES = ["verifying", "executing"];
|
|
446
792
|
if (!VALID_LEARN_STATES.includes(ctx.status)) {
|
|
447
793
|
return {
|
|
448
|
-
|
|
449
|
-
isError: true,
|
|
794
|
+
result: { error: `任务状态 ${ctx.status} 不可学习,需要 verifying 或 executing`, status: ctx.status },
|
|
450
795
|
};
|
|
451
796
|
}
|
|
452
797
|
// 如适用,记录失败
|
|
@@ -478,15 +823,28 @@ export function registerTools(server, deps) {
|
|
|
478
823
|
learnResult.retry_hint = `第 ${attemptCount}/${maxAttempts} 次尝试失败,${args.failure_type === "scope_insufficient" ? "需要扩大范围" : "请修复后重试"}`;
|
|
479
824
|
}
|
|
480
825
|
else {
|
|
481
|
-
//
|
|
482
|
-
const
|
|
826
|
+
// 检查主链路集成 — 即使 build/test 全绿,孤岛仍阻断 done
|
|
827
|
+
const integrationBlocked = ctx.verification?.main_path_integration
|
|
828
|
+
&& !ctx.verification.main_path_integration.passed;
|
|
829
|
+
// 核心工程执行原则门禁 — required 原则失败不能进入 completed
|
|
830
|
+
const principlesBlocked = ctx.verification?.core_principles
|
|
831
|
+
&& !ctx.verification.core_principles.overall_passed;
|
|
832
|
+
const finalStatus = args.result === "failure"
|
|
833
|
+
? "failed"
|
|
834
|
+
: (integrationBlocked || principlesBlocked) ? "retrying" : "done";
|
|
483
835
|
await taskContext.updateStatus(args.task_id, finalStatus);
|
|
836
|
+
if (integrationBlocked && finalStatus === "retrying") {
|
|
837
|
+
learnResult.retry_hint = "主链路集成检查失败: 存在孤岛模块,请接入主链路后重试";
|
|
838
|
+
}
|
|
839
|
+
if (principlesBlocked && finalStatus === "retrying") {
|
|
840
|
+
const failedPrinciples = ctx.verification.core_principles.principles
|
|
841
|
+
.filter((p) => p.status === "failed")
|
|
842
|
+
.map((p) => p.principle_id);
|
|
843
|
+
learnResult.retry_hint = `核心工程执行原则检查失败: ${failedPrinciples.join(", ")},请修复后重试`;
|
|
844
|
+
}
|
|
484
845
|
}
|
|
485
846
|
return {
|
|
486
|
-
|
|
487
|
-
type: "text",
|
|
488
|
-
text: JSON.stringify(learnResult, null, 2),
|
|
489
|
-
}],
|
|
847
|
+
result: learnResult,
|
|
490
848
|
};
|
|
491
849
|
});
|
|
492
850
|
// ── sf_status: 任务状态查询(current/recent/resume/cancel) ──
|
|
@@ -496,8 +854,7 @@ export function registerTools(server, deps) {
|
|
|
496
854
|
if (args.job_action) {
|
|
497
855
|
if (!args.job_id) {
|
|
498
856
|
return {
|
|
499
|
-
|
|
500
|
-
isError: true,
|
|
857
|
+
result: { error: "job 操作需要 job_id" },
|
|
501
858
|
};
|
|
502
859
|
}
|
|
503
860
|
const jm = new JobManager(taskContext.getStateDir());
|
|
@@ -506,47 +863,39 @@ export function registerTools(server, deps) {
|
|
|
506
863
|
const status = await jm.getJobStatus(args.job_id, taskId);
|
|
507
864
|
if (!status) {
|
|
508
865
|
return {
|
|
509
|
-
|
|
510
|
-
isError: true,
|
|
866
|
+
result: { error: `job ${args.job_id} 不存在或已过期` },
|
|
511
867
|
};
|
|
512
868
|
}
|
|
513
869
|
return {
|
|
514
|
-
|
|
870
|
+
result: { job: status },
|
|
515
871
|
};
|
|
516
872
|
}
|
|
517
873
|
if (args.job_action === "job_resume") {
|
|
518
874
|
const checkpoint = await jm.resumeFromCheckpoint(args.job_id, taskId);
|
|
519
875
|
if (!checkpoint) {
|
|
520
876
|
return {
|
|
521
|
-
|
|
522
|
-
isError: true,
|
|
877
|
+
result: { error: `job ${args.job_id} 无可恢复的 checkpoint` },
|
|
523
878
|
};
|
|
524
879
|
}
|
|
525
880
|
return {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
cognitive_anchor: checkpoint.cognitive_anchor,
|
|
535
|
-
}, null, 2),
|
|
536
|
-
}],
|
|
881
|
+
result: {
|
|
882
|
+
advisory: "job 恢复为 advisory 操作,需确认 checkpoint 数据与当前状态一致",
|
|
883
|
+
job_id: checkpoint.job_id,
|
|
884
|
+
task_id: checkpoint.task_id,
|
|
885
|
+
phase: checkpoint.phase,
|
|
886
|
+
checkpoint_number: checkpoint.checkpoint_number,
|
|
887
|
+
cognitive_anchor: checkpoint.cognitive_anchor,
|
|
888
|
+
},
|
|
537
889
|
};
|
|
538
890
|
}
|
|
539
891
|
if (args.job_action === "job_cancel") {
|
|
540
892
|
const removed = await jm.cancelJob(args.job_id, taskId);
|
|
541
893
|
return {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
cancelled: removed,
|
|
548
|
-
}),
|
|
549
|
-
}],
|
|
894
|
+
result: {
|
|
895
|
+
advisory: "job 取消为 advisory 操作",
|
|
896
|
+
job_id: args.job_id,
|
|
897
|
+
cancelled: removed,
|
|
898
|
+
},
|
|
550
899
|
};
|
|
551
900
|
}
|
|
552
901
|
}
|
|
@@ -557,7 +906,7 @@ export function registerTools(server, deps) {
|
|
|
557
906
|
: await taskContext.getCurrentTask();
|
|
558
907
|
if (!ctx) {
|
|
559
908
|
return {
|
|
560
|
-
|
|
909
|
+
result: { message: "当前无活跃任务" },
|
|
561
910
|
};
|
|
562
911
|
}
|
|
563
912
|
const resumable = taskContext.isResumable(ctx);
|
|
@@ -599,78 +948,61 @@ export function registerTools(server, deps) {
|
|
|
599
948
|
// JobManager advisory — ignore errors
|
|
600
949
|
}
|
|
601
950
|
return {
|
|
602
|
-
|
|
951
|
+
result: result,
|
|
603
952
|
};
|
|
604
953
|
}
|
|
605
954
|
case "recent": {
|
|
606
955
|
const recent = await taskContext.listRecent(10);
|
|
607
956
|
return {
|
|
608
|
-
|
|
957
|
+
result: { tasks: recent },
|
|
609
958
|
};
|
|
610
959
|
}
|
|
611
960
|
case "resume": {
|
|
612
961
|
if (!args.task_id) {
|
|
613
962
|
return {
|
|
614
|
-
|
|
615
|
-
isError: true,
|
|
963
|
+
result: { error: "恢复任务需要 task_id" },
|
|
616
964
|
};
|
|
617
965
|
}
|
|
618
966
|
const ctx = await taskContext.load(args.task_id);
|
|
619
967
|
if (!ctx) {
|
|
620
968
|
return {
|
|
621
|
-
|
|
622
|
-
isError: true,
|
|
969
|
+
result: { error: "任务不存在" },
|
|
623
970
|
};
|
|
624
971
|
}
|
|
625
972
|
if (!taskContext.isResumable(ctx)) {
|
|
626
973
|
return {
|
|
627
|
-
|
|
628
|
-
isError: true,
|
|
974
|
+
result: { error: `任务状态 ${ctx.status} 不可恢复`, status: ctx.status },
|
|
629
975
|
};
|
|
630
976
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
intent: ctx.intent,
|
|
637
|
-
status: ctx.status,
|
|
638
|
-
resume_hint: taskContext.getResumeHint(ctx),
|
|
639
|
-
classification: ctx.classification,
|
|
640
|
-
expansion: ctx.expansion ? {
|
|
641
|
-
scope: ctx.expansion.scope,
|
|
642
|
-
matched_patterns: ctx.expansion.matched_patterns,
|
|
643
|
-
} : undefined,
|
|
644
|
-
execution: ctx.execution ? {
|
|
645
|
-
changed_files: ctx.execution.changed_files,
|
|
646
|
-
attempt_count: ctx.execution.attempt_count,
|
|
647
|
-
} : undefined,
|
|
648
|
-
cognitive_anchors: ctx.execution?.changed_files?.length
|
|
649
|
-
? loadRelevantAnchors({ file_paths: ctx.execution.changed_files })
|
|
650
|
-
: undefined,
|
|
651
|
-
}, null, 2),
|
|
652
|
-
}],
|
|
977
|
+
const resumeResult = {
|
|
978
|
+
task_id: ctx.task_id,
|
|
979
|
+
intent: ctx.intent,
|
|
980
|
+
status: ctx.status,
|
|
981
|
+
resume_hint: taskContext.getResumeHint(ctx),
|
|
653
982
|
};
|
|
983
|
+
if (ctx.execution)
|
|
984
|
+
resumeResult.execution = ctx.execution;
|
|
985
|
+
const resumeAnchors = ctx.execution?.changed_files
|
|
986
|
+
? loadRelevantAnchors({ file_paths: ctx.execution.changed_files })
|
|
987
|
+
: undefined;
|
|
988
|
+
if (resumeAnchors && resumeAnchors.length > 0)
|
|
989
|
+
resumeResult.cognitive_anchors = resumeAnchors;
|
|
990
|
+
return { result: resumeResult };
|
|
654
991
|
}
|
|
655
992
|
case "cancel": {
|
|
656
993
|
if (!args.task_id) {
|
|
657
994
|
return {
|
|
658
|
-
|
|
659
|
-
isError: true,
|
|
995
|
+
result: { error: "取消任务需要 task_id" },
|
|
660
996
|
};
|
|
661
997
|
}
|
|
662
998
|
const cancelled = await taskContext.cancel(args.task_id);
|
|
663
999
|
return {
|
|
664
|
-
|
|
665
|
-
type: "text",
|
|
666
|
-
text: JSON.stringify({ task_id: args.task_id, cancelled }),
|
|
667
|
-
}],
|
|
1000
|
+
result: { task_id: args.task_id, cancelled },
|
|
668
1001
|
};
|
|
669
1002
|
}
|
|
670
1003
|
default:
|
|
671
1004
|
return {
|
|
672
|
-
|
|
673
|
-
isError: true,
|
|
1005
|
+
result: { error: `未知操作: ${action}` },
|
|
674
1006
|
};
|
|
675
1007
|
}
|
|
676
1008
|
});
|
|
@@ -679,8 +1011,7 @@ export function registerTools(server, deps) {
|
|
|
679
1011
|
const ctx = await taskContext.load(args.task_id);
|
|
680
1012
|
if (!ctx?.classification) {
|
|
681
1013
|
return {
|
|
682
|
-
|
|
683
|
-
isError: true,
|
|
1014
|
+
result: { error: "任务不存在或尚未分类" },
|
|
684
1015
|
};
|
|
685
1016
|
}
|
|
686
1017
|
const result = planTask({
|
|
@@ -692,7 +1023,7 @@ export function registerTools(server, deps) {
|
|
|
692
1023
|
result.task_id = args.task_id;
|
|
693
1024
|
await taskContext.setPlanning(args.task_id, result);
|
|
694
1025
|
return {
|
|
695
|
-
|
|
1026
|
+
result: result,
|
|
696
1027
|
};
|
|
697
1028
|
});
|
|
698
1029
|
// ── sf_plan_advance: 推进多阶段计划到下一步 ──
|
|
@@ -700,8 +1031,7 @@ export function registerTools(server, deps) {
|
|
|
700
1031
|
const ctx = await taskContext.load(args.task_id);
|
|
701
1032
|
if (!ctx?.planning || ctx.planning.sub_tasks.length === 0) {
|
|
702
1033
|
return {
|
|
703
|
-
|
|
704
|
-
isError: true,
|
|
1034
|
+
result: { error: "任务没有多阶段计划,请先调用 sf_plan" },
|
|
705
1035
|
};
|
|
706
1036
|
}
|
|
707
1037
|
const plan = ctx.planning;
|
|
@@ -709,38 +1039,33 @@ export function registerTools(server, deps) {
|
|
|
709
1039
|
const previousStepTitle = previousStep?.title ?? "未知";
|
|
710
1040
|
const nextIndex = plan.current_step_index + 1;
|
|
711
1041
|
if (nextIndex >= plan.sub_tasks.length) {
|
|
712
|
-
return {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
}, null, 2) }],
|
|
721
|
-
};
|
|
1042
|
+
return { result: {
|
|
1043
|
+
task_id: args.task_id,
|
|
1044
|
+
previous_step: previousStepTitle,
|
|
1045
|
+
current_step_index: plan.current_step_index,
|
|
1046
|
+
total_steps: plan.sub_tasks.length,
|
|
1047
|
+
is_completed: true,
|
|
1048
|
+
message: `所有 ${plan.sub_tasks.length} 个阶段已完成`,
|
|
1049
|
+
} };
|
|
722
1050
|
}
|
|
723
1051
|
// 推进阶段索引
|
|
724
1052
|
plan.current_step_index = nextIndex;
|
|
725
1053
|
await taskContext.setPlanning(args.task_id, plan);
|
|
726
1054
|
const nextStep = plan.sub_tasks[nextIndex];
|
|
727
1055
|
return {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
message: `阶段推进: ${previousStepTitle} → ${nextStep.title}`,
|
|
742
|
-
}, null, 2),
|
|
743
|
-
}],
|
|
1056
|
+
result: {
|
|
1057
|
+
task_id: args.task_id,
|
|
1058
|
+
previous_step: previousStepTitle,
|
|
1059
|
+
current_step_index: nextIndex,
|
|
1060
|
+
current_step: {
|
|
1061
|
+
id: nextStep.id,
|
|
1062
|
+
title: nextStep.title,
|
|
1063
|
+
output_path: nextStep.output_path,
|
|
1064
|
+
},
|
|
1065
|
+
total_steps: plan.sub_tasks.length,
|
|
1066
|
+
is_completed: false,
|
|
1067
|
+
message: `阶段推进: ${previousStepTitle} → ${nextStep.title}`,
|
|
1068
|
+
},
|
|
744
1069
|
};
|
|
745
1070
|
});
|
|
746
1071
|
// ── sf_analyze: 影响范围分析,建议是否扩大作用域 ──
|
|
@@ -748,8 +1073,7 @@ export function registerTools(server, deps) {
|
|
|
748
1073
|
const ctx = await taskContext.load(args.task_id);
|
|
749
1074
|
if (!ctx?.expansion) {
|
|
750
1075
|
return {
|
|
751
|
-
|
|
752
|
-
isError: true,
|
|
1076
|
+
result: { error: "任务尚未膨胀,请先调用 sf_expand" },
|
|
753
1077
|
};
|
|
754
1078
|
}
|
|
755
1079
|
const result = await analyzeImpact({
|
|
@@ -766,17 +1090,14 @@ export function registerTools(server, deps) {
|
|
|
766
1090
|
if (!decisionContract.passed) {
|
|
767
1091
|
advisoryExtras.decision_contract_advisory = decisionContract.advisory;
|
|
768
1092
|
}
|
|
769
|
-
return {
|
|
770
|
-
content: [{ type: "text", text: JSON.stringify(Object.keys(advisoryExtras).length > 0 ? { ...result, ...advisoryExtras } : result, null, 2) }],
|
|
771
|
-
};
|
|
1093
|
+
return { result: Object.keys(advisoryExtras).length > 0 ? { ...result, ...advisoryExtras } : result };
|
|
772
1094
|
});
|
|
773
1095
|
// ── sf_review: 代码审查(质量、安全、性能、技术债务) ──
|
|
774
1096
|
registerSafeTool("sf_review", "审查代码变更的质量、安全、性能和技术债务。hotfix 场景可跳过。建议性,不强制修复", ReviewSchema, async (args) => {
|
|
775
1097
|
const ctx = await taskContext.load(args.task_id);
|
|
776
1098
|
if (!ctx) {
|
|
777
1099
|
return {
|
|
778
|
-
|
|
779
|
-
isError: true,
|
|
1100
|
+
result: { error: "任务不存在" },
|
|
780
1101
|
};
|
|
781
1102
|
}
|
|
782
1103
|
const tracker = new DebtTracker(projectPath);
|
|
@@ -797,29 +1118,22 @@ export function registerTools(server, deps) {
|
|
|
797
1118
|
if (!decisionContract.passed) {
|
|
798
1119
|
reviewExtras.decision_contract_advisory = decisionContract.advisory;
|
|
799
1120
|
}
|
|
800
|
-
return {
|
|
801
|
-
content: [{ type: "text", text: JSON.stringify(Object.keys(reviewExtras).length > 0 ? { ...result, ...reviewExtras } : result, null, 2) }],
|
|
802
|
-
};
|
|
1121
|
+
return { result: Object.keys(reviewExtras).length > 0 ? { ...result, ...reviewExtras } : result };
|
|
803
1122
|
});
|
|
804
1123
|
// ── sf_scaffold: 生成标准化代码骨架 ──
|
|
805
1124
|
registerSafeTool("sf_scaffold", "根据项目模板生成标准化代码骨架(Controller/Service/DTO/测试等)。仅在 task_type=scaffold 时使用", ScaffoldSchema, async (args) => {
|
|
806
1125
|
const ctx = await taskContext.load(args.task_id);
|
|
807
1126
|
if (!ctx?.classification) {
|
|
808
1127
|
return {
|
|
809
|
-
|
|
810
|
-
isError: true,
|
|
1128
|
+
result: { error: "任务不存在或尚未分类" },
|
|
811
1129
|
};
|
|
812
1130
|
}
|
|
813
1131
|
if (ctx.classification.task_type !== "scaffold") {
|
|
814
1132
|
return {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
current_type: ctx.classification.task_type,
|
|
820
|
-
}),
|
|
821
|
-
}],
|
|
822
|
-
isError: true,
|
|
1133
|
+
result: {
|
|
1134
|
+
error: "sf_scaffold 仅适用于 scaffold 类型任务",
|
|
1135
|
+
current_type: ctx.classification.task_type,
|
|
1136
|
+
},
|
|
823
1137
|
};
|
|
824
1138
|
}
|
|
825
1139
|
const result = await generateScaffold({
|
|
@@ -830,7 +1144,7 @@ export function registerTools(server, deps) {
|
|
|
830
1144
|
});
|
|
831
1145
|
result.task_id = args.task_id;
|
|
832
1146
|
return {
|
|
833
|
-
|
|
1147
|
+
result: result,
|
|
834
1148
|
};
|
|
835
1149
|
});
|
|
836
1150
|
// ── sf_deliver: 自动提交、推送、创建 PR ──
|
|
@@ -838,8 +1152,7 @@ export function registerTools(server, deps) {
|
|
|
838
1152
|
const ctx = await taskContext.load(args.task_id);
|
|
839
1153
|
if (!ctx) {
|
|
840
1154
|
return {
|
|
841
|
-
|
|
842
|
-
isError: true,
|
|
1155
|
+
result: { error: "任务不存在" },
|
|
843
1156
|
};
|
|
844
1157
|
}
|
|
845
1158
|
// H4: 交付前工作区完整性检查 — advisory 模式,仅警告不阻断
|
|
@@ -847,6 +1160,41 @@ export function registerTools(server, deps) {
|
|
|
847
1160
|
const h4DeliverWarning = !deliverIntegrity.clean
|
|
848
1161
|
? { warning: `H4 advisory: ${deliverIntegrity.message}`, dirty_files: deliverIntegrity.dirty_files }
|
|
849
1162
|
: undefined;
|
|
1163
|
+
// Artifact status gate : deliver requires artifact status = accepted with evidence
|
|
1164
|
+
if (ctx.artifact_output) {
|
|
1165
|
+
const status = ctx.artifact_output.status;
|
|
1166
|
+
if (status === "draft") {
|
|
1167
|
+
return {
|
|
1168
|
+
result: {
|
|
1169
|
+
error: `产物状态为 ${status},需先通过验证 (verified) 并确认 (accepted) 才能交付`,
|
|
1170
|
+
artifact_id: ctx.artifact_output.artifact_id,
|
|
1171
|
+
current_status: status,
|
|
1172
|
+
},
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
if (status === "verified") {
|
|
1176
|
+
return {
|
|
1177
|
+
result: {
|
|
1178
|
+
error: `产物状态为 ${status},需人工确认或后续 workflow 采用后变为 accepted 才能交付`,
|
|
1179
|
+
artifact_id: ctx.artifact_output.artifact_id,
|
|
1180
|
+
current_status: status,
|
|
1181
|
+
},
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
// accepted must have confirmation evidence
|
|
1185
|
+
if (status === "accepted") {
|
|
1186
|
+
const hasAcceptanceEvidence = ctx.artifact_output.evidence_refs.some((r) => r.includes("acceptance") || r.includes("workflow_adoption"));
|
|
1187
|
+
if (!hasAcceptanceEvidence) {
|
|
1188
|
+
return {
|
|
1189
|
+
result: {
|
|
1190
|
+
error: `产物状态为 accepted 但缺少确认证据 (acceptance/workflow_adoption evidence_ref)`,
|
|
1191
|
+
artifact_id: ctx.artifact_output.artifact_id,
|
|
1192
|
+
current_status: status,
|
|
1193
|
+
},
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
850
1198
|
const result = await deliver({
|
|
851
1199
|
taskContext: ctx,
|
|
852
1200
|
config,
|
|
@@ -858,10 +1206,7 @@ export function registerTools(server, deps) {
|
|
|
858
1206
|
});
|
|
859
1207
|
await taskContext.setDelivery(args.task_id, result);
|
|
860
1208
|
return {
|
|
861
|
-
|
|
862
|
-
type: "text",
|
|
863
|
-
text: JSON.stringify(h4DeliverWarning ? { ...result, h4_advisory: h4DeliverWarning } : result, null, 2),
|
|
864
|
-
}],
|
|
1209
|
+
result: h4DeliverWarning ? { ...result, h4_advisory: h4DeliverWarning } : result,
|
|
865
1210
|
};
|
|
866
1211
|
});
|
|
867
1212
|
// ── sf_coord_check: 预测性冲突检测和跨仓库协调 ──
|
|
@@ -873,7 +1218,7 @@ export function registerTools(server, deps) {
|
|
|
873
1218
|
gitOps: realGitOps,
|
|
874
1219
|
});
|
|
875
1220
|
return {
|
|
876
|
-
|
|
1221
|
+
result: result,
|
|
877
1222
|
};
|
|
878
1223
|
});
|
|
879
1224
|
// ── sf_team_status: 团队活动流和工作负载查询 ──
|
|
@@ -886,7 +1231,7 @@ export function registerTools(server, deps) {
|
|
|
886
1231
|
knowledgeIndex: args.include_knowledge ? knowledgeIndex : undefined,
|
|
887
1232
|
});
|
|
888
1233
|
return {
|
|
889
|
-
|
|
1234
|
+
result: result,
|
|
890
1235
|
};
|
|
891
1236
|
});
|
|
892
1237
|
// ── sf_contract_check: API 契约变更检测 ──
|
|
@@ -903,7 +1248,7 @@ export function registerTools(server, deps) {
|
|
|
903
1248
|
gitOps: realGitOps,
|
|
904
1249
|
});
|
|
905
1250
|
return {
|
|
906
|
-
|
|
1251
|
+
result: result,
|
|
907
1252
|
};
|
|
908
1253
|
});
|
|
909
1254
|
// ── sf_onboard: 新人分步引导 ──
|
|
@@ -917,7 +1262,7 @@ export function registerTools(server, deps) {
|
|
|
917
1262
|
reset: args.reset,
|
|
918
1263
|
});
|
|
919
1264
|
return {
|
|
920
|
-
|
|
1265
|
+
result: result,
|
|
921
1266
|
};
|
|
922
1267
|
});
|
|
923
1268
|
// ── sf_feasibility_check: 任务可行性评估 ──
|
|
@@ -925,13 +1270,12 @@ export function registerTools(server, deps) {
|
|
|
925
1270
|
const ctx = await taskContext.load(args.task_id);
|
|
926
1271
|
if (!ctx?.classification) {
|
|
927
1272
|
return {
|
|
928
|
-
|
|
929
|
-
isError: true,
|
|
1273
|
+
result: { error: "任务不存在或未完成分类,请先调用 sf_classify" },
|
|
930
1274
|
};
|
|
931
1275
|
}
|
|
932
1276
|
const result = checkFeasibility(ctx.classification, config);
|
|
933
1277
|
return {
|
|
934
|
-
|
|
1278
|
+
result: result,
|
|
935
1279
|
};
|
|
936
1280
|
});
|
|
937
1281
|
// ── sf_debug: 智能排障(解析错误 → 根因分析 → 修复方案) ──
|
|
@@ -942,7 +1286,7 @@ export function registerTools(server, deps) {
|
|
|
942
1286
|
];
|
|
943
1287
|
const result = debugError(args.error_output, args.task_id || `debug-${Date.now()}`, projectScope);
|
|
944
1288
|
return {
|
|
945
|
-
|
|
1289
|
+
result: result,
|
|
946
1290
|
};
|
|
947
1291
|
});
|
|
948
1292
|
// ── sf_observability: 系统可观测和运行报告 ──
|
|
@@ -952,35 +1296,35 @@ export function registerTools(server, deps) {
|
|
|
952
1296
|
const capability = getCapabilitySummary();
|
|
953
1297
|
const output = { ...result, capability };
|
|
954
1298
|
return {
|
|
955
|
-
|
|
1299
|
+
result: output,
|
|
956
1300
|
};
|
|
957
1301
|
});
|
|
958
1302
|
// ── sf_migration_check: 数据库迁移安全性分析 ──
|
|
959
1303
|
registerSafeTool("sf_migration_check", "分析数据库迁移文件安全性:检测破坏性操作(DROP/DELETE/TRUNCATE)并生成回滚建议", MigrationCheckSchema, async (args) => {
|
|
960
1304
|
const result = analyzeMigration(args.content, args.filename);
|
|
961
1305
|
return {
|
|
962
|
-
|
|
1306
|
+
result: result,
|
|
963
1307
|
};
|
|
964
1308
|
});
|
|
965
1309
|
// ── sf_test_guide: 基于变更文件生成测试指引 ──
|
|
966
1310
|
registerSafeTool("sf_test_guide", "根据变更文件类型生成测试指引:推荐测试类型、场景、Mock 点和断言模板", TestGuideSchema, async (args) => {
|
|
967
1311
|
const result = generateTestGuide(args.changed_files, [], config);
|
|
968
1312
|
return {
|
|
969
|
-
|
|
1313
|
+
result: result,
|
|
970
1314
|
};
|
|
971
1315
|
});
|
|
972
1316
|
// ── sf_test_quality: 测试文件质量五维评分 ──
|
|
973
1317
|
registerSafeTool("sf_test_quality", "评估测试文件质量:断言密度、边界覆盖、命名、重复率、场景覆盖五维评分", TestQualitySchema, async (args) => {
|
|
974
1318
|
const result = analyzeTestQuality(args.content, args.filename);
|
|
975
1319
|
return {
|
|
976
|
-
|
|
1320
|
+
result: result,
|
|
977
1321
|
};
|
|
978
1322
|
});
|
|
979
1323
|
// ── sf_dependency_scan: 依赖漏洞扫描 ──
|
|
980
1324
|
registerSafeTool("sf_dependency_scan", "扫描依赖声明文件漏洞:已知 CVE 规则匹配、未锁定版本检测、支持 npm/maven/gradle", DependencyScanSchema, async (args) => {
|
|
981
1325
|
const result = scanDependencies(args.content, args.filename);
|
|
982
1326
|
return {
|
|
983
|
-
|
|
1327
|
+
result: result,
|
|
984
1328
|
};
|
|
985
1329
|
});
|
|
986
1330
|
// ── sf_debt_report: 技术债务报告生成 ──
|
|
@@ -988,7 +1332,7 @@ export function registerTools(server, deps) {
|
|
|
988
1332
|
const tracker = new DebtTracker(projectPath);
|
|
989
1333
|
const result = await generateDebtReport(tracker);
|
|
990
1334
|
return {
|
|
991
|
-
|
|
1335
|
+
result: result,
|
|
992
1336
|
};
|
|
993
1337
|
});
|
|
994
1338
|
// ── sf_explore: 自主技术选型与方案证伪 ──
|
|
@@ -1010,15 +1354,13 @@ export function registerTools(server, deps) {
|
|
|
1010
1354
|
if (!decisionContract.passed) {
|
|
1011
1355
|
exploreExtras.decision_contract_advisory = decisionContract.advisory;
|
|
1012
1356
|
}
|
|
1013
|
-
return {
|
|
1014
|
-
content: [{ type: "text", text: JSON.stringify(Object.keys(exploreExtras).length > 0 ? { ...result, ...exploreExtras } : result, null, 2) }],
|
|
1015
|
-
};
|
|
1357
|
+
return { result: Object.keys(exploreExtras).length > 0 ? { ...result, ...exploreExtras } : result };
|
|
1016
1358
|
});
|
|
1017
1359
|
// ── sf_knowledge_audit: 知识库健康审计 ──
|
|
1018
1360
|
registerSafeTool("sf_knowledge_audit", "审计知识库:识别过时条目、重复触发词、格式缺失、覆盖缺口。定期执行或手动触发", {}, async () => {
|
|
1019
1361
|
const result = await auditKnowledge(knowledgeIndex, config);
|
|
1020
1362
|
return {
|
|
1021
|
-
|
|
1363
|
+
result: result,
|
|
1022
1364
|
};
|
|
1023
1365
|
});
|
|
1024
1366
|
// ── sf_knowledge_add: 新增知识条目(默认保存为草稿) ──
|
|
@@ -1042,7 +1384,7 @@ export function registerTools(server, deps) {
|
|
|
1042
1384
|
auto_enrich: args.auto_enrich,
|
|
1043
1385
|
}, config);
|
|
1044
1386
|
return {
|
|
1045
|
-
|
|
1387
|
+
result: result,
|
|
1046
1388
|
};
|
|
1047
1389
|
});
|
|
1048
1390
|
// ── sf_knowledge_update: 更新已有知识条目(自动创建备份) ──
|
|
@@ -1068,7 +1410,7 @@ export function registerTools(server, deps) {
|
|
|
1068
1410
|
await knowledgeIndex.reload();
|
|
1069
1411
|
}
|
|
1070
1412
|
return {
|
|
1071
|
-
|
|
1413
|
+
result: result,
|
|
1072
1414
|
};
|
|
1073
1415
|
});
|
|
1074
1416
|
// ── sf_resume_workspace: 工作区状态唤醒(解决前端刷新导致UUID丢失) ──
|
|
@@ -1104,7 +1446,7 @@ export function registerTools(server, deps) {
|
|
|
1104
1446
|
// JobManager advisory — ignore errors
|
|
1105
1447
|
}
|
|
1106
1448
|
return {
|
|
1107
|
-
|
|
1449
|
+
result: result,
|
|
1108
1450
|
};
|
|
1109
1451
|
});
|
|
1110
1452
|
// ── sf_audit_sample: 从审计池按风险加权抽样生成抽检清单 ──
|
|
@@ -1118,7 +1460,7 @@ export function registerTools(server, deps) {
|
|
|
1118
1460
|
const seed = args.seed ?? 0;
|
|
1119
1461
|
const result = sampleAuditItems(items, seed);
|
|
1120
1462
|
return {
|
|
1121
|
-
|
|
1463
|
+
result: result,
|
|
1122
1464
|
};
|
|
1123
1465
|
});
|
|
1124
1466
|
// ── sf_escape_report: 记录逃逸/误伤/工具故障报告 ──
|
|
@@ -1157,7 +1499,7 @@ export function registerTools(server, deps) {
|
|
|
1157
1499
|
};
|
|
1158
1500
|
store.append(report);
|
|
1159
1501
|
return {
|
|
1160
|
-
|
|
1502
|
+
result: { recorded: true, escape_id: report.escape_id },
|
|
1161
1503
|
};
|
|
1162
1504
|
});
|
|
1163
1505
|
// ── sf_capability_update: 根据复盘结果更新 Capability Registry ──
|
|
@@ -1188,7 +1530,7 @@ export function registerTools(server, deps) {
|
|
|
1188
1530
|
confirm: args.confirm,
|
|
1189
1531
|
}, currentState, cap?.id ?? null, escapeReports);
|
|
1190
1532
|
return {
|
|
1191
|
-
|
|
1533
|
+
result: result,
|
|
1192
1534
|
};
|
|
1193
1535
|
});
|
|
1194
1536
|
// ── sf_governance_report: 治理健康报告 ──
|
|
@@ -1213,9 +1555,81 @@ export function registerTools(server, deps) {
|
|
|
1213
1555
|
});
|
|
1214
1556
|
// Generate sample decisions for sampled_count
|
|
1215
1557
|
const sampleResult = sampleAuditItems(auditItems, seed);
|
|
1216
|
-
|
|
1558
|
+
// Dual-layer mechanism findings
|
|
1559
|
+
const dlFindings = validateMechanismLayerMaps();
|
|
1560
|
+
const dlMechanismCount = listMechanismLayerMaps().length;
|
|
1561
|
+
// Collect artifact records from recent tasks
|
|
1562
|
+
const recentTasks = await taskContext.listRecent(20);
|
|
1563
|
+
const artifacts = [];
|
|
1564
|
+
for (const t of recentTasks) {
|
|
1565
|
+
const tCtx = await taskContext.load(t.task_id);
|
|
1566
|
+
if (tCtx?.artifact_output)
|
|
1567
|
+
artifacts.push(tCtx.artifact_output);
|
|
1568
|
+
}
|
|
1569
|
+
// Collect config resolution reports — use shared function for real data
|
|
1570
|
+
let configReports = [];
|
|
1571
|
+
let configEntries = [];
|
|
1572
|
+
try {
|
|
1573
|
+
const resolved = await resolveCurrentProjectConfigReports(projectPath);
|
|
1574
|
+
configReports = resolved.reports;
|
|
1575
|
+
configEntries = resolved.entries;
|
|
1576
|
+
}
|
|
1577
|
+
catch (e) {
|
|
1578
|
+
console.error(`[soloForge] 配置报告解析失败: ${e instanceof Error ? e.message : String(e)}`);
|
|
1579
|
+
}
|
|
1580
|
+
// Also include reports from recent task contexts
|
|
1581
|
+
for (const t of recentTasks) {
|
|
1582
|
+
const tCtx = await taskContext.load(t.task_id);
|
|
1583
|
+
if (tCtx?.expansion?.config_resolution_reports) {
|
|
1584
|
+
configReports.push(...tCtx.expansion.config_resolution_reports);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
const report = generateGovernanceReport(auditStats, auditItems, escapeReports, escapeStats, decisions, new Date(), sampleResult.decisions, dlFindings, dlMechanismCount, artifacts.length > 0 ? artifacts : undefined, configReports.length > 0 ? configReports : undefined, configEntries.length > 0 ? configEntries : undefined);
|
|
1588
|
+
return {
|
|
1589
|
+
result: report,
|
|
1590
|
+
};
|
|
1591
|
+
});
|
|
1592
|
+
// ── sf_audit_integration: 主链路集成审计 ──
|
|
1593
|
+
const AuditIntegrationSchema = {
|
|
1594
|
+
changed_files: z.array(z.string()).optional().describe("只审计指定的变更文件列表"),
|
|
1595
|
+
json_output: z.boolean().optional().describe("以 JSON 格式输出(默认为人类可读文本)"),
|
|
1596
|
+
};
|
|
1597
|
+
registerSafeTool("sf_audit_integration", "审计生产代码的主链路集成状态,检测孤岛模块(只被测试导入、无生产代码调用的模块)", AuditIntegrationSchema, async (args) => {
|
|
1598
|
+
const projectPath = config._projectPath || process.cwd();
|
|
1599
|
+
// Use scope-aware production file collection (supports multi-repo, multi-lang)
|
|
1600
|
+
const { collectAllProductionFiles } = await import("../../engine/main_path_integration_contract.js");
|
|
1601
|
+
const allProdFiles = collectAllProductionFiles(projectPath, config);
|
|
1602
|
+
if (allProdFiles.length === 0) {
|
|
1603
|
+
return {
|
|
1604
|
+
result: { error: "未找到生产源文件" },
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
const targetFiles = args.changed_files
|
|
1608
|
+
? allProdFiles.filter((rel) => args.changed_files.some((cf) => rel === cf || rel.startsWith(cf.replace(/\.(ts|tsx|js|jsx|java|kt|go|py)$/, ""))))
|
|
1609
|
+
: allProdFiles;
|
|
1610
|
+
const contracts = buildMainPathIntegrationContracts(projectPath, targetFiles, config);
|
|
1611
|
+
const report = auditIntegration(contracts);
|
|
1612
|
+
if (args.json_output) {
|
|
1613
|
+
return {
|
|
1614
|
+
result: report,
|
|
1615
|
+
};
|
|
1616
|
+
}
|
|
1617
|
+
const lines = [];
|
|
1618
|
+
lines.push("主链路集成审计报告");
|
|
1619
|
+
lines.push(`受检模块: ${targetFiles.length} | 孤岛: ${report.orphan_modules.length} | 仅测试: ${report.test_only_modules.length} | 仅注册: ${report.registry_only_modules.length}`);
|
|
1620
|
+
lines.push("");
|
|
1621
|
+
for (const finding of report.findings) {
|
|
1622
|
+
const icon = finding.severity === "hard_fail" ? "X" : finding.severity === "warning" ? "~" : "i";
|
|
1623
|
+
lines.push(`${icon} ${finding.module_path}: ${finding.reason}`);
|
|
1624
|
+
if (finding.recommended_action) {
|
|
1625
|
+
lines.push(` -> ${finding.recommended_action}`);
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
if (report.findings.length === 0) {
|
|
1629
|
+
lines.push("所有受检模块已通过集成检查。");
|
|
1630
|
+
}
|
|
1217
1631
|
return {
|
|
1218
|
-
|
|
1632
|
+
result: { text: lines.join("\n") },
|
|
1219
1633
|
};
|
|
1220
1634
|
});
|
|
1221
1635
|
}
|