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
package/dist/bin/soloforge.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import crypto from "node:crypto";
|
|
2
3
|
import fss from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
|
-
import {
|
|
5
|
+
import { resolveProjectConfig, getProjectKnowledgeDir, getGlobalPatternsDir } from "../knowledge/loader.js";
|
|
5
6
|
import { generateHooksConfig } from "../adapters/claude_code/hooks.js";
|
|
6
7
|
import { generateClaudeMd } from "../adapters/claude_code/hooks.js";
|
|
7
8
|
import { generateTraeRules } from "../adapters/trae/trae_rules.js";
|
|
8
9
|
import { generateTraeMcpConfig } from "../adapters/trae/trae_config.js";
|
|
9
10
|
import { generateCodexMcpConfig, generateCodexHooksConfig } from "../adapters/codex/codex_config.js";
|
|
10
11
|
import { generateCodexAgentsMd } from "../adapters/codex/codex_rules.js";
|
|
11
|
-
import { detectFingerprint, generateConfigDraft, validateConfigDraft } from "../engine/zero_config_init.js";
|
|
12
|
+
import { detectFingerprint, generateConfigDraft, validateConfigDraft, generateConfigEvidence, canAutoWrite, parseBlueprint, generateBlueprintEvidence, } from "../engine/zero_config_init.js";
|
|
12
13
|
import YAML from "yaml";
|
|
14
|
+
import { cmdConfigResolve, cmdConfigExplain, cmdConfigConfirm, cmdConfigUnset, loadConfigEvidenceEntries, } from "./config_commands.js";
|
|
15
|
+
import { resolveCurrentProjectConfigReports, validateConfigPrecedence, } from "../engine/config_precedence_contract.js";
|
|
16
|
+
import { isReadForbidden } from "../engine/privacy_secret_contract.js";
|
|
13
17
|
const command = process.argv[2];
|
|
14
18
|
const args = process.argv.slice(3);
|
|
15
19
|
async function main() {
|
|
@@ -18,6 +22,9 @@ async function main() {
|
|
|
18
22
|
if (args.includes("--auto")) {
|
|
19
23
|
await cmdInitAuto();
|
|
20
24
|
}
|
|
25
|
+
else if (args.includes("--blueprint")) {
|
|
26
|
+
await cmdInitBlueprint();
|
|
27
|
+
}
|
|
21
28
|
else {
|
|
22
29
|
await cmdInit();
|
|
23
30
|
}
|
|
@@ -40,6 +47,15 @@ async function main() {
|
|
|
40
47
|
case "validate":
|
|
41
48
|
await cmdValidate();
|
|
42
49
|
break;
|
|
50
|
+
case "validate-mechanisms":
|
|
51
|
+
await cmdValidateMechanisms();
|
|
52
|
+
break;
|
|
53
|
+
case "audit-template-mechanisms":
|
|
54
|
+
await cmdAuditTemplateMechanisms();
|
|
55
|
+
break;
|
|
56
|
+
case "validate-batch1":
|
|
57
|
+
await cmdValidateBatch1();
|
|
58
|
+
break;
|
|
43
59
|
case "generate-trae":
|
|
44
60
|
await cmdGenerateTrae();
|
|
45
61
|
break;
|
|
@@ -51,6 +67,31 @@ async function main() {
|
|
|
51
67
|
case "--version":
|
|
52
68
|
cmdVersion();
|
|
53
69
|
break;
|
|
70
|
+
case "config": {
|
|
71
|
+
const subCommand = args[0];
|
|
72
|
+
switch (subCommand) {
|
|
73
|
+
case "resolve":
|
|
74
|
+
await cmdConfigResolve();
|
|
75
|
+
break;
|
|
76
|
+
case "explain":
|
|
77
|
+
await cmdConfigExplain();
|
|
78
|
+
break;
|
|
79
|
+
case "confirm":
|
|
80
|
+
await cmdConfigConfirm();
|
|
81
|
+
break;
|
|
82
|
+
case "unset":
|
|
83
|
+
await cmdConfigUnset();
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
console.log("用法: soloforge config <resolve|explain|confirm|unset> [options]");
|
|
87
|
+
console.log("");
|
|
88
|
+
console.log(" resolve 解析配置字段优先级(只读,显示所有候选来源)");
|
|
89
|
+
console.log(" explain 解释指定字段的来源和优先级(只读,中文输出)");
|
|
90
|
+
console.log(" confirm 确认配置字段值(写入 config + evidence)");
|
|
91
|
+
console.log(" unset 移除指定字段的确认配置和 evidence");
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
54
95
|
case "status":
|
|
55
96
|
await cmdStatus();
|
|
56
97
|
break;
|
|
@@ -71,29 +112,37 @@ async function main() {
|
|
|
71
112
|
generate-codex 生成 .codex/ 配置和 AGENTS.md
|
|
72
113
|
check-write PreToolUse hook,用于范围检查(读取 TOOL_INPUT 环境变量)
|
|
73
114
|
post-bash PostToolUse hook,用于跟踪 Bash 执行结果
|
|
74
|
-
validate
|
|
115
|
+
validate 验证项目配置和知识文件(config.yaml 可选,缺失时自动推断)
|
|
116
|
+
validate-mechanisms 验证双层机制承载模型完整性(模板层 + 机制层)
|
|
117
|
+
audit-template-mechanisms 扫描模板与机制注册表交叉校验(--json 输出完整报告,--changed-only 仅检查变更文件)
|
|
75
118
|
version 显示 SoloForge 版本信息
|
|
76
|
-
|
|
119
|
+
config resolve 解析配置字段优先级(只读)
|
|
120
|
+
config explain 解释配置字段来源(只读,中文)
|
|
121
|
+
config confirm <field> <value> 确认配置字段(写入 config + evidence)
|
|
122
|
+
config unset <field> 移除确认配置
|
|
123
|
+
status 显示当前项目的 SoloForge 状态
|
|
77
124
|
`);
|
|
78
125
|
}
|
|
79
126
|
}
|
|
80
127
|
async function cmdInitAuto() {
|
|
128
|
+
console.error("[soloForge] CLI: 执行 cmdInitAuto");
|
|
81
129
|
const dryRun = args.includes("--dry-run");
|
|
82
|
-
const yesMode = args.includes("--yes");
|
|
83
130
|
const projectPathArg = getArgValue("--project-path");
|
|
84
131
|
const projectPath = projectPathArg ? path.resolve(projectPathArg) : process.cwd();
|
|
85
132
|
// 层 1: 确定性指纹探测
|
|
86
133
|
const fp = await detectFingerprint(projectPath);
|
|
87
134
|
// 层 2: 规则推导 → config 草案
|
|
88
135
|
const draft = generateConfigDraft(fp);
|
|
89
|
-
//
|
|
90
|
-
const
|
|
136
|
+
// 层 3: 字段级 evidence
|
|
137
|
+
const evidence = generateConfigEvidence(fp, draft, "auto");
|
|
138
|
+
// 展示探测结果 + evidence
|
|
91
139
|
console.log("\nSoloForge 自动配置探测结果:");
|
|
92
140
|
console.log("=".repeat(50));
|
|
93
|
-
for (const
|
|
94
|
-
const icon =
|
|
95
|
-
|
|
96
|
-
console.log(`
|
|
141
|
+
for (const [key, field] of Object.entries(evidence.fields)) {
|
|
142
|
+
const icon = field.confidence === "high" ? "✅" : field.confidence === "medium" ? "⚠️" : "❓";
|
|
143
|
+
const valStr = typeof field.value === "object" ? JSON.stringify(field.value) : String(field.value);
|
|
144
|
+
console.log(` ${icon} ${key}: ${valStr} (${field.confidence}, ${field.confidence_source})`);
|
|
145
|
+
console.log(` evidence: ${field.evidence.join(", ")}`);
|
|
97
146
|
}
|
|
98
147
|
console.log("=".repeat(50));
|
|
99
148
|
console.log(`综合置信度: ${draft.confidence}`);
|
|
@@ -123,21 +172,20 @@ async function cmdInitAuto() {
|
|
|
123
172
|
console.log("\n[dry-run] 不写入文件。使用不带 --dry-run 的命令执行写入。");
|
|
124
173
|
return;
|
|
125
174
|
}
|
|
126
|
-
//
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
console.log(
|
|
132
|
-
return;
|
|
175
|
+
// 写入门禁: 所有必要字段必须 high confidence + detected/user_declared/confirmed
|
|
176
|
+
const gate = canAutoWrite(evidence);
|
|
177
|
+
if (!gate.allowed) {
|
|
178
|
+
console.log(`\n⚠️ 存在低/中置信度配置项,拒绝写入:`);
|
|
179
|
+
for (const f of gate.blockedFields) {
|
|
180
|
+
console.log(` - ${f}`);
|
|
133
181
|
}
|
|
134
|
-
console.log("
|
|
182
|
+
console.log("请使用 `soloforge init --interactive` 或 `soloforge init --blueprint \"...\"` 生成配置。");
|
|
135
183
|
return;
|
|
136
184
|
}
|
|
137
|
-
// 写入配置
|
|
138
|
-
await finishInitAutoConfig(projectPath, draft);
|
|
185
|
+
// 写入配置 + evidence
|
|
186
|
+
await finishInitAutoConfig(projectPath, draft, evidence);
|
|
139
187
|
}
|
|
140
|
-
async function finishInitAutoConfig(projectPath, draft) {
|
|
188
|
+
async function finishInitAutoConfig(projectPath, draft, evidence) {
|
|
141
189
|
const dirs = [
|
|
142
190
|
".soloforge/state", ".soloforge/state/debt",
|
|
143
191
|
".soloforge/knowledge/patterns", ".soloforge/knowledge/patterns/core",
|
|
@@ -151,7 +199,16 @@ async function finishInitAutoConfig(projectPath, draft) {
|
|
|
151
199
|
for (const dir of dirs) {
|
|
152
200
|
fss.mkdirSync(path.join(projectPath, dir), { recursive: true });
|
|
153
201
|
}
|
|
202
|
+
writeConfigWithEvidence(projectPath, draft, evidence);
|
|
203
|
+
ensureGitignore(projectPath);
|
|
204
|
+
// 继续执行普通 init 的模板复制和适配器生成
|
|
205
|
+
await copyGlobalPatterns(projectPath);
|
|
206
|
+
await copyKnowledgeTemplates(projectPath);
|
|
207
|
+
await generateAdapterConfigs(projectPath, "claude-code");
|
|
208
|
+
}
|
|
209
|
+
function writeConfigWithEvidence(projectPath, draft, evidence) {
|
|
154
210
|
const configPath = path.join(projectPath, ".soloforge", "config.yaml");
|
|
211
|
+
const evidencePath = path.join(projectPath, ".soloforge", "config.evidence.json");
|
|
155
212
|
const yamlConfig = {
|
|
156
213
|
schema_version: 1,
|
|
157
214
|
name: draft.name,
|
|
@@ -162,48 +219,117 @@ async function finishInitAutoConfig(projectPath, draft) {
|
|
|
162
219
|
scope: draft.scope,
|
|
163
220
|
};
|
|
164
221
|
fss.writeFileSync(configPath, YAML.stringify(yamlConfig), "utf-8");
|
|
165
|
-
|
|
222
|
+
// Write legacy evidence format (backward compat) + schema v2 entries
|
|
223
|
+
fss.writeFileSync(evidencePath, JSON.stringify(evidence, null, 2), "utf-8");
|
|
224
|
+
// Also write schema v2 entries
|
|
225
|
+
const v2Entries = Object.entries(evidence.fields).map(([key, field]) => ({
|
|
226
|
+
field_path: key,
|
|
227
|
+
value_hash: hashConfigValue(JSON.stringify(field.value)),
|
|
228
|
+
source: mapLegacySource(field.confidence_source),
|
|
229
|
+
confidence: field.confidence === "high" ? 1.0 : field.confidence === "medium" ? 0.6 : 0.3,
|
|
230
|
+
evidence_refs: field.evidence || [],
|
|
231
|
+
lifetime: "project_persistent",
|
|
232
|
+
collected_at: evidence.generated_at || new Date().toISOString(),
|
|
233
|
+
}));
|
|
234
|
+
// Merge v2 entries into the evidence file
|
|
235
|
+
try {
|
|
236
|
+
const existing = JSON.parse(fss.readFileSync(evidencePath, "utf-8"));
|
|
237
|
+
existing.entries = v2Entries;
|
|
238
|
+
existing.updated_at = new Date().toISOString();
|
|
239
|
+
fss.writeFileSync(evidencePath, JSON.stringify(existing, null, 2), "utf-8");
|
|
240
|
+
}
|
|
241
|
+
catch (e) {
|
|
242
|
+
console.error(`[soloForge] 更新 evidence 文件失败: ${e instanceof Error ? e.message : String(e)}`);
|
|
243
|
+
}
|
|
244
|
+
console.log(`\n✅ .soloforge/config.yaml + config.evidence.json created`);
|
|
245
|
+
}
|
|
246
|
+
function hashConfigValue(str) {
|
|
247
|
+
return crypto.createHash("sha256").update(str).digest("hex").slice(0, 16);
|
|
248
|
+
}
|
|
249
|
+
function mapLegacySource(source) {
|
|
250
|
+
switch (source) {
|
|
251
|
+
case "detected": return "detected";
|
|
252
|
+
case "user_declared": return "user_declared";
|
|
253
|
+
case "confirmed": return "confirmed";
|
|
254
|
+
default: return "knowledge_default";
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async function cmdInitBlueprint() {
|
|
258
|
+
console.error("[soloForge] CLI: 执行 cmdInitBlueprint");
|
|
259
|
+
const blueprintText = getArgValue("--blueprint");
|
|
260
|
+
if (!blueprintText) {
|
|
261
|
+
console.error("❌ --blueprint 需要提供描述文本,例如: soloforge init --blueprint \"Spring Boot + React 的 B2B 内部管理系统\"");
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const projectPathArg = getArgValue("--project-path");
|
|
265
|
+
const projectPath = projectPathArg ? path.resolve(projectPathArg) : process.cwd();
|
|
266
|
+
const parsed = parseBlueprint(blueprintText);
|
|
267
|
+
if (!parsed.parsed) {
|
|
268
|
+
console.log("⚠️ 无法从蓝图文本解析技术栈,请使用 --interactive。");
|
|
269
|
+
console.log("支持的框架关键词: Spring Boot, Go, Rust, Gradle, React, Vue, Angular, Next.js, Nuxt");
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
// Build draft from parsed blueprint
|
|
273
|
+
const draft = {
|
|
274
|
+
name: path.basename(projectPath),
|
|
275
|
+
tech_stack: {
|
|
276
|
+
backend: parsed.tech_stack.backend ?? { lang: "", framework: "", version: "" },
|
|
277
|
+
frontend: parsed.tech_stack.frontend ?? { lang: "", framework: "", version: "" },
|
|
278
|
+
},
|
|
279
|
+
product_profile: parsed.product_profile ?? "default",
|
|
280
|
+
build_commands: {
|
|
281
|
+
backend: blueprintBackendCommands(parsed.tech_stack.backend?.framework),
|
|
282
|
+
frontend: blueprintFrontendCommands(parsed.tech_stack.frontend?.framework),
|
|
283
|
+
},
|
|
284
|
+
scope: {
|
|
285
|
+
backend: parsed.tech_stack.backend ? ["src/"] : [],
|
|
286
|
+
frontend: parsed.tech_stack.frontend ? ["src/"] : [],
|
|
287
|
+
},
|
|
288
|
+
advisory_notes: [],
|
|
289
|
+
confidence: "high",
|
|
290
|
+
};
|
|
291
|
+
const evidence = generateBlueprintEvidence(blueprintText, draft, projectPath);
|
|
292
|
+
// Create dirs + write config + evidence
|
|
293
|
+
const dirs = [
|
|
294
|
+
".soloforge/state", ".soloforge/state/debt",
|
|
295
|
+
".soloforge/knowledge/patterns", ".soloforge/knowledge/patterns/core",
|
|
296
|
+
".soloforge/knowledge/patterns/temp",
|
|
297
|
+
".soloforge/knowledge/procedures", ".soloforge/knowledge/domain/backend",
|
|
298
|
+
".soloforge/knowledge/domain/frontend", ".soloforge/knowledge/acceptance_templates",
|
|
299
|
+
".soloforge/knowledge/review_rules", ".soloforge/knowledge/product_profiles",
|
|
300
|
+
".soloforge/knowledge/checklists", ".soloforge/knowledge/templates",
|
|
301
|
+
".soloforge/staged",
|
|
302
|
+
];
|
|
303
|
+
for (const dir of dirs) {
|
|
304
|
+
fss.mkdirSync(path.join(projectPath, dir), { recursive: true });
|
|
305
|
+
}
|
|
306
|
+
writeConfigWithEvidence(projectPath, draft, evidence);
|
|
166
307
|
ensureGitignore(projectPath);
|
|
167
|
-
// 继续执行普通 init 的模板复制和适配器生成
|
|
168
308
|
await copyGlobalPatterns(projectPath);
|
|
169
309
|
await copyKnowledgeTemplates(projectPath);
|
|
170
310
|
await generateAdapterConfigs(projectPath, "claude-code");
|
|
171
311
|
}
|
|
172
|
-
function
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
evidence: fp.backend ? `inferred from ${fp.backend.framework}` : "no backend framework to infer from",
|
|
191
|
-
});
|
|
192
|
-
items.push({
|
|
193
|
-
key: "build_commands.frontend",
|
|
194
|
-
value: draft.build_commands.frontend?.build ?? "unknown",
|
|
195
|
-
confidence: fp.frontend ? "high" : "low",
|
|
196
|
-
evidence: fp.frontend ? `inferred from ${fp.frontend.framework}` : "no frontend framework to infer from",
|
|
197
|
-
});
|
|
198
|
-
items.push({
|
|
199
|
-
key: "scope.backend",
|
|
200
|
-
value: draft.scope.backend?.join(", ") ?? "none",
|
|
201
|
-
confidence: fp.backend && (draft.scope.backend?.length ?? 0) > 0 ? "high" : fp.backend ? "medium" : "low",
|
|
202
|
-
evidence: fp.backend ? `inferred from ${fp.backend.framework} conventions` : "unknown backend, no scope inferred",
|
|
203
|
-
});
|
|
204
|
-
return items;
|
|
312
|
+
function blueprintBackendCommands(framework) {
|
|
313
|
+
switch (framework) {
|
|
314
|
+
case "spring-boot": return { build: "./mvnw compile -q", test: "./mvnw test -q", full: "./mvnw verify -q" };
|
|
315
|
+
case "gradle": return { build: "./gradlew compileJava", test: "./gradlew test", full: "./gradlew check" };
|
|
316
|
+
case "stdlib": return { build: "go build ./...", test: "go test ./...", full: "go test -race ./..." };
|
|
317
|
+
case "cargo": return { build: "cargo build", test: "cargo test", full: "cargo test --all" };
|
|
318
|
+
default: return { build: "echo 'no backend build'", test: "echo 'no backend tests'", full: "echo 'no backend'" };
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function blueprintFrontendCommands(framework) {
|
|
322
|
+
switch (framework) {
|
|
323
|
+
case "react":
|
|
324
|
+
case "vue":
|
|
325
|
+
return { build: "npm run build", test: "npm test", full: "npm run build && npm test" };
|
|
326
|
+
case "angular":
|
|
327
|
+
return { build: "npx ng build", test: "npx ng test", full: "npx ng build && npx ng test" };
|
|
328
|
+
default: return { build: "echo 'no frontend build'", test: "echo 'no frontend tests'", full: "echo 'no frontend'" };
|
|
329
|
+
}
|
|
205
330
|
}
|
|
206
331
|
async function cmdInit() {
|
|
332
|
+
console.error("[soloForge] CLI: 执行 cmdInit");
|
|
207
333
|
const interactive = args.includes("--interactive");
|
|
208
334
|
const adapter = getArgValue("--adapter") || "claude-code";
|
|
209
335
|
const projectPathArg = getArgValue("--project-path");
|
|
@@ -228,14 +354,18 @@ async function cmdInit() {
|
|
|
228
354
|
for (const dir of dirs) {
|
|
229
355
|
fss.mkdirSync(path.join(projectPath, dir), { recursive: true });
|
|
230
356
|
}
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
357
|
+
// 仅 --interactive 模式生成 config.yaml + evidence;普通 init 不再生成
|
|
358
|
+
if (interactive) {
|
|
359
|
+
const config = await interactiveConfig(projectPath);
|
|
360
|
+
if (config) {
|
|
361
|
+
// config is { draft, evidence }
|
|
362
|
+
writeConfigWithEvidence(projectPath, config.draft, config.evidence);
|
|
363
|
+
}
|
|
364
|
+
else if (!process.stdin.isTTY) {
|
|
365
|
+
console.log("⚠️ interactive requires TTY. 请使用 --auto 或 --blueprint。");
|
|
366
|
+
}
|
|
237
367
|
}
|
|
238
|
-
// 生成 .mcp.json(SoloForge + Playwright
|
|
368
|
+
// 生成 .mcp.json(SoloForge + Playwright)
|
|
239
369
|
if (adapter === "claude-code" || adapter === "all") {
|
|
240
370
|
const mcpPath = path.join(projectPath, ".mcp.json");
|
|
241
371
|
if (!fss.existsSync(mcpPath)) {
|
|
@@ -250,14 +380,10 @@ async function cmdInit() {
|
|
|
250
380
|
command: "npx",
|
|
251
381
|
args: ["@playwright/mcp@latest", "--headless"],
|
|
252
382
|
},
|
|
253
|
-
figma: {
|
|
254
|
-
type: "http",
|
|
255
|
-
url: "https://mcp.figma.com/mcp",
|
|
256
|
-
},
|
|
257
383
|
},
|
|
258
384
|
};
|
|
259
385
|
fss.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
260
|
-
console.log("✅ .mcp.json created (soloforge + playwright
|
|
386
|
+
console.log("✅ .mcp.json created (soloforge + playwright)");
|
|
261
387
|
}
|
|
262
388
|
// 生成 hooks
|
|
263
389
|
await cmdGenerateHooks(projectPath);
|
|
@@ -333,11 +459,10 @@ async function generateAdapterConfigs(projectPath, adapter) {
|
|
|
333
459
|
mcpServers: {
|
|
334
460
|
soloforge: { command: "soloforge", args: ["mcp"], env: { SOLOFORGE_PROJECT: projectPath } },
|
|
335
461
|
playwright: { command: "npx", args: ["@playwright/mcp@latest", "--headless"] },
|
|
336
|
-
figma: { type: "http", url: "https://mcp.figma.com/mcp" },
|
|
337
462
|
},
|
|
338
463
|
};
|
|
339
464
|
fss.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
340
|
-
console.log("✅ .mcp.json created (soloforge + playwright
|
|
465
|
+
console.log("✅ .mcp.json created (soloforge + playwright)");
|
|
341
466
|
}
|
|
342
467
|
await cmdGenerateHooks(projectPath);
|
|
343
468
|
await cmdGenerateClaudeMdInner(projectPath);
|
|
@@ -399,7 +524,7 @@ async function cmdGenerateCodexInner(projectPath) {
|
|
|
399
524
|
fss.writeFileSync(path.join(codexDir, "hooks.json"), hooksContent, "utf-8");
|
|
400
525
|
console.log("✅ .codex/hooks.json created");
|
|
401
526
|
// 生成 AGENTS.md
|
|
402
|
-
const config = await
|
|
527
|
+
const { config } = await resolveProjectConfig(projectPath);
|
|
403
528
|
const agentsContent = generateCodexAgentsMd(config);
|
|
404
529
|
fss.writeFileSync(path.join(projectPath, "AGENTS.md"), agentsContent, "utf-8");
|
|
405
530
|
console.log("✅ AGENTS.md created");
|
|
@@ -415,18 +540,19 @@ async function cmdGenerateTraeInner(projectPath) {
|
|
|
415
540
|
// 生成 .trae/rules/project_rules.md
|
|
416
541
|
const rulesDir = path.join(traeDir, "rules");
|
|
417
542
|
fss.mkdirSync(rulesDir, { recursive: true });
|
|
418
|
-
const config = await
|
|
543
|
+
const { config } = await resolveProjectConfig(projectPath);
|
|
419
544
|
const rulesContent = generateTraeRules(config);
|
|
420
545
|
fss.writeFileSync(path.join(rulesDir, "project_rules.md"), rulesContent, "utf-8");
|
|
421
546
|
console.log("✅ .trae/rules/project_rules.md created");
|
|
422
547
|
}
|
|
423
548
|
async function cmdGenerateClaudeMdInner(projectPath) {
|
|
424
|
-
const config = await
|
|
549
|
+
const { config } = await resolveProjectConfig(projectPath);
|
|
425
550
|
const content = generateClaudeMd(config);
|
|
426
551
|
fss.writeFileSync(path.join(projectPath, "CLAUDE.md"), content, "utf-8");
|
|
427
552
|
console.log("✅ CLAUDE.md created");
|
|
428
553
|
}
|
|
429
554
|
async function cmdCheckWrite() {
|
|
555
|
+
console.error("[soloForge] CLI: 执行 cmdCheckWrite");
|
|
430
556
|
try {
|
|
431
557
|
// 检测运行环境: Claude Code 通过 TOOL_INPUT 环境变量,Codex 通过 stdin JSON
|
|
432
558
|
const isClaudeCode = !!process.env.TOOL_INPUT;
|
|
@@ -466,7 +592,7 @@ async function cmdCheckWrite() {
|
|
|
466
592
|
}
|
|
467
593
|
// 加载配置
|
|
468
594
|
const projectPath = resolveProjectPath();
|
|
469
|
-
const config = await
|
|
595
|
+
const { config } = await resolveProjectConfig(projectPath);
|
|
470
596
|
// 从配置中收集所有允许路径
|
|
471
597
|
const allowedPaths = [
|
|
472
598
|
...(config.scope.backend || []),
|
|
@@ -476,6 +602,28 @@ async function cmdCheckWrite() {
|
|
|
476
602
|
// 使用 scope_controller 统一检查
|
|
477
603
|
const { checkScope } = await import("../engine/scope_controller.js");
|
|
478
604
|
const result = checkScope(filePath, allowedPaths, content || undefined);
|
|
605
|
+
// Privacy / Secret Contract: forbidden read patterns
|
|
606
|
+
if (isReadForbidden(filePath)) {
|
|
607
|
+
if (isClaudeCode) {
|
|
608
|
+
console.error(JSON.stringify({
|
|
609
|
+
allowed: false,
|
|
610
|
+
reason: `隐私策略: ${filePath} 匹配禁止读取模式`,
|
|
611
|
+
has_secrets: true,
|
|
612
|
+
severity: "blocked",
|
|
613
|
+
}));
|
|
614
|
+
process.exit(1);
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
process.stdout.write(JSON.stringify({
|
|
618
|
+
hookSpecificOutput: {
|
|
619
|
+
hookEventName: "PreToolUse",
|
|
620
|
+
permissionDecision: "deny",
|
|
621
|
+
permissionDecisionReason: `隐私策略: ${filePath} 匹配禁止读取模式`,
|
|
622
|
+
},
|
|
623
|
+
}));
|
|
624
|
+
process.exit(0);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
479
627
|
if (result.severity === "blocked") {
|
|
480
628
|
if (isClaudeCode) {
|
|
481
629
|
console.error(JSON.stringify(result));
|
|
@@ -504,7 +652,7 @@ async function cmdCheckWrite() {
|
|
|
504
652
|
}
|
|
505
653
|
catch (e) {
|
|
506
654
|
console.error(`SoloForge check-write error: ${e instanceof Error ? e.message : String(e)}`);
|
|
507
|
-
process.exit(
|
|
655
|
+
process.exit(1); // 出错时拦截(fail-closed 策略:安全钩子宁可误拦也不放行)
|
|
508
656
|
}
|
|
509
657
|
}
|
|
510
658
|
function resolveProjectPath() {
|
|
@@ -526,20 +674,122 @@ function resolveProjectPath() {
|
|
|
526
674
|
return process.cwd();
|
|
527
675
|
}
|
|
528
676
|
async function cmdPostBash() {
|
|
677
|
+
console.error("[soloForge] CLI: 执行 cmdPostBash");
|
|
529
678
|
// Bash 的 PostToolUse hook — 目前为空操作占位符
|
|
530
679
|
// 未来: 跟踪命令结果,检测构建/测试失败
|
|
531
680
|
process.exit(0);
|
|
532
681
|
}
|
|
533
|
-
async function
|
|
534
|
-
|
|
682
|
+
async function checkEvidenceWarnings(projectPath) {
|
|
683
|
+
console.error("[soloForge] CLI: 执行 checkEvidenceWarnings — " + projectPath);
|
|
684
|
+
const warnings = [];
|
|
535
685
|
const configPath = path.join(projectPath, ".soloforge", "config.yaml");
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
686
|
+
const evidencePath = path.join(projectPath, ".soloforge", "config.evidence.json");
|
|
687
|
+
if (!fss.existsSync(configPath))
|
|
688
|
+
return warnings;
|
|
689
|
+
if (!fss.existsSync(evidencePath)) {
|
|
690
|
+
warnings.push("config.yaml exists but config.evidence.json is missing — source traceability lost");
|
|
691
|
+
return warnings;
|
|
692
|
+
}
|
|
693
|
+
// Check mtime staleness
|
|
694
|
+
try {
|
|
695
|
+
const configStat = fss.statSync(configPath);
|
|
696
|
+
const evidenceStat = fss.statSync(evidencePath);
|
|
697
|
+
if (configStat.mtimeMs > evidenceStat.mtimeMs) {
|
|
698
|
+
warnings.push("config.evidence.json is stale (config.yaml was modified after evidence was generated)");
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
catch { }
|
|
702
|
+
// Legacy field consistency check (schema v1 evidence)
|
|
703
|
+
try {
|
|
704
|
+
const evidenceRaw = JSON.parse(fss.readFileSync(evidencePath, "utf-8"));
|
|
705
|
+
const configContent = fss.readFileSync(configPath, "utf-8");
|
|
706
|
+
const config = YAML.parse(configContent);
|
|
707
|
+
for (const [key, field] of Object.entries(evidenceRaw.fields)) {
|
|
708
|
+
const actualValue = getConfigFieldValue(config, key);
|
|
709
|
+
if (actualValue !== undefined && JSON.stringify(field.value) !== JSON.stringify(actualValue)) {
|
|
710
|
+
warnings.push(`evidence field '${key}' value does not match config.yaml`);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
catch { }
|
|
715
|
+
// Config precedence validation using schema v2 entries
|
|
716
|
+
try {
|
|
717
|
+
const entries = loadConfigEvidenceEntries(projectPath);
|
|
718
|
+
// Check C-class auto-write violations
|
|
719
|
+
for (const e of entries) {
|
|
720
|
+
if (e.source === "cli_flag" || e.source === "mcp_param") {
|
|
721
|
+
if (e.lifetime === "project_persistent") {
|
|
722
|
+
warnings.push(`CLI/MCP parameter (${e.source}) persisted to config — field: ${e.field_path}`);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
// Run config precedence validation with live resolution
|
|
727
|
+
try {
|
|
728
|
+
const { reports } = await resolveCurrentProjectConfigReports(projectPath);
|
|
729
|
+
const findings = validateConfigPrecedence(reports, entries);
|
|
730
|
+
for (const f of findings) {
|
|
731
|
+
if (f.severity === "hard_fail") {
|
|
732
|
+
warnings.push(`[${f.rule}] ${f.message}`);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
catch { }
|
|
737
|
+
}
|
|
738
|
+
catch { }
|
|
739
|
+
return warnings;
|
|
740
|
+
}
|
|
741
|
+
function getConfigFieldValue(config, key) {
|
|
742
|
+
const parts = key.split(".");
|
|
743
|
+
let obj = config;
|
|
744
|
+
for (const part of parts) {
|
|
745
|
+
if (obj == null || typeof obj !== "object")
|
|
746
|
+
return undefined;
|
|
747
|
+
obj = obj[part];
|
|
539
748
|
}
|
|
749
|
+
return obj;
|
|
750
|
+
}
|
|
751
|
+
async function cmdValidate() {
|
|
752
|
+
console.error("[soloForge] CLI: 执行 cmdValidate");
|
|
753
|
+
const projectPath = process.cwd();
|
|
540
754
|
try {
|
|
541
|
-
const config = await
|
|
542
|
-
|
|
755
|
+
const { config, source } = await resolveProjectConfig(projectPath);
|
|
756
|
+
if (source === "inferred") {
|
|
757
|
+
console.log("ℹ️ No .soloforge/config.yaml found — using auto-inferred configuration.");
|
|
758
|
+
console.log(" Run 'soloforge init --auto' to persist.");
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
console.log("✅ config.yaml is valid");
|
|
762
|
+
}
|
|
763
|
+
// Config precedence validation using shared function
|
|
764
|
+
let hasHardFail = false;
|
|
765
|
+
try {
|
|
766
|
+
const { reports, entries } = await resolveCurrentProjectConfigReports(projectPath);
|
|
767
|
+
const findings = validateConfigPrecedence(reports, entries);
|
|
768
|
+
const hardFails = findings.filter(f => f.severity === "hard_fail");
|
|
769
|
+
const advisory = findings.filter(f => f.severity === "advisory");
|
|
770
|
+
if (hardFails.length > 0) {
|
|
771
|
+
hasHardFail = true;
|
|
772
|
+
console.log(`❌ 配置优先级: ${hardFails.length} hard_fail`);
|
|
773
|
+
for (const f of hardFails) {
|
|
774
|
+
console.log(` - [${f.rule}] ${f.field_path ?? "N/A"}: ${f.message}`);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
if (advisory.length > 0) {
|
|
778
|
+
console.log(`⚠️ 配置优先级: ${advisory.length} advisory`);
|
|
779
|
+
for (const f of advisory) {
|
|
780
|
+
console.log(` - [${f.rule}] ${f.field_path ?? "N/A"}: ${f.message}`);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
if (hardFails.length === 0 && advisory.length === 0) {
|
|
784
|
+
console.log("✅ 配置优先级验证通过");
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
catch { }
|
|
788
|
+
// Evidence checks
|
|
789
|
+
const evidenceWarnings = await checkEvidenceWarnings(projectPath);
|
|
790
|
+
for (const w of evidenceWarnings) {
|
|
791
|
+
console.log(`⚠️ evidence: ${w}`);
|
|
792
|
+
}
|
|
543
793
|
// 检查知识文件
|
|
544
794
|
const knowledgeDir = getProjectKnowledgeDir(config);
|
|
545
795
|
if (fss.existsSync(knowledgeDir)) {
|
|
@@ -556,19 +806,263 @@ async function cmdValidate() {
|
|
|
556
806
|
}
|
|
557
807
|
}
|
|
558
808
|
}
|
|
809
|
+
// 双层机制验证 (仅限 SoloForge 自身源码目录)
|
|
810
|
+
if (fss.existsSync(path.join(projectPath, "src", "engine", "dual_layer_mechanism_registry.ts"))) {
|
|
811
|
+
const { validateMechanismLayerMaps } = await import("../engine/dual_layer_mechanism_registry.js");
|
|
812
|
+
const dlFindings = validateMechanismLayerMaps();
|
|
813
|
+
const dlHard = dlFindings.filter((f) => f.severity === "hard_fail");
|
|
814
|
+
const dlAdvisory = dlFindings.filter((f) => f.severity === "advisory");
|
|
815
|
+
if (dlHard.length > 0) {
|
|
816
|
+
console.log(`❌ 双层机制验证: ${dlHard.length} hard_fail`);
|
|
817
|
+
for (const f of dlHard) {
|
|
818
|
+
console.log(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
|
|
819
|
+
}
|
|
820
|
+
console.error(`❌ validate 失败: 双层机制存在 ${dlHard.length} hard_fail`);
|
|
821
|
+
process.exit(1);
|
|
822
|
+
}
|
|
823
|
+
else {
|
|
824
|
+
console.log(`✅ 双层机制验证: ${dlAdvisory.length} advisory, 0 hard_fail`);
|
|
825
|
+
}
|
|
826
|
+
} // end dual-layer check
|
|
827
|
+
if (hasHardFail) {
|
|
828
|
+
console.error("❌ validate 失败: 配置优先级存在 hard_fail");
|
|
829
|
+
process.exit(1);
|
|
830
|
+
}
|
|
559
831
|
}
|
|
560
832
|
catch (e) {
|
|
561
833
|
console.error(`❌ 验证失败: ${e.message}`);
|
|
562
834
|
process.exit(1);
|
|
563
835
|
}
|
|
564
836
|
}
|
|
837
|
+
async function cmdValidateMechanisms() {
|
|
838
|
+
console.error("[soloForge] CLI: 执行 cmdValidateMechanisms");
|
|
839
|
+
// Resolve root from compiled binary location: dist/bin/soloforge.js -> project root
|
|
840
|
+
const soloforgeRoot = path.resolve(import.meta.dirname, "..", "..");
|
|
841
|
+
const projectPath = fss.existsSync(path.join(soloforgeRoot, "src", "engine"))
|
|
842
|
+
? soloforgeRoot
|
|
843
|
+
: process.cwd();
|
|
844
|
+
try {
|
|
845
|
+
const { validateMechanismLayerMaps } = await import("../engine/dual_layer_mechanism_registry.js");
|
|
846
|
+
const findings = validateMechanismLayerMaps(undefined, projectPath);
|
|
847
|
+
const hardFails = findings.filter((f) => f.severity === "hard_fail");
|
|
848
|
+
const advisory = findings.filter((f) => f.severity === "advisory");
|
|
849
|
+
if (findings.length === 0) {
|
|
850
|
+
console.log("✅ 所有双层机制映射验证通过,无发现。");
|
|
851
|
+
process.exit(0);
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
if (advisory.length > 0) {
|
|
855
|
+
console.log(`⚠️ advisory findings (${advisory.length}):`);
|
|
856
|
+
for (const f of advisory) {
|
|
857
|
+
console.log(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
if (hardFails.length > 0) {
|
|
861
|
+
console.log(`❌ hard_fail findings (${hardFails.length}):`);
|
|
862
|
+
for (const f of hardFails) {
|
|
863
|
+
console.log(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
|
|
864
|
+
}
|
|
865
|
+
console.log(`\n❌ 双层机制验证失败: ${hardFails.length} hard_fail`);
|
|
866
|
+
process.exit(1);
|
|
867
|
+
}
|
|
868
|
+
console.log(`\n✅ 双层机制验证通过,${advisory.length} advisory findings`);
|
|
869
|
+
// Audit summary
|
|
870
|
+
try {
|
|
871
|
+
const { auditTemplateMechanisms } = await import("../engine/template_mechanism_auditor.js");
|
|
872
|
+
const audit = auditTemplateMechanisms(projectPath);
|
|
873
|
+
if (audit.hard_fail_count > 0) {
|
|
874
|
+
console.log(`\n⚠️ 模板审计摘要: ${audit.hard_fail_count} hard_fail, ${audit.unmapped_template_assets.length} unmapped`);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
console.log(`\n📊 模板审计: ${audit.total_template_files} 文件, ${audit.unmapped_template_assets.length} unmapped, ${audit.advisory_count} advisory`);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
catch {
|
|
881
|
+
// audit is advisory, not blocking
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
catch (e) {
|
|
885
|
+
console.error(`❌ validate-mechanisms 失败: ${e.message}`);
|
|
886
|
+
process.exit(1);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
async function cmdAuditTemplateMechanisms() {
|
|
890
|
+
console.error("[soloForge] CLI: 执行 cmdAuditTemplateMechanisms");
|
|
891
|
+
const asJson = args.includes("--json");
|
|
892
|
+
const changedOnly = args.includes("--changed-only");
|
|
893
|
+
// Resolve root from compiled binary location
|
|
894
|
+
const soloforgeRoot = path.resolve(import.meta.dirname, "..", "..");
|
|
895
|
+
const projectPath = fss.existsSync(path.join(soloforgeRoot, "src", "engine"))
|
|
896
|
+
? soloforgeRoot
|
|
897
|
+
: process.cwd();
|
|
898
|
+
try {
|
|
899
|
+
const { auditTemplateMechanisms } = await import("../engine/template_mechanism_auditor.js");
|
|
900
|
+
const report = auditTemplateMechanisms(projectPath);
|
|
901
|
+
if (asJson) {
|
|
902
|
+
console.log(JSON.stringify(report, null, 2));
|
|
903
|
+
if (report.hard_fail_count > 0) {
|
|
904
|
+
process.exit(1);
|
|
905
|
+
}
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
// Human-readable output
|
|
909
|
+
console.log(`模板-机制审计报告 (${report.generated_at})`);
|
|
910
|
+
console.log(` 模板文件: ${report.total_template_files}`);
|
|
911
|
+
console.log(` 注册资产: ${report.total_registered_assets}`);
|
|
912
|
+
console.log(` 机制总数: ${report.total_mechanisms}`);
|
|
913
|
+
console.log("");
|
|
914
|
+
if (report.unmapped_template_assets.length > 0) {
|
|
915
|
+
console.log(`⚠️ 未注册模板 (${report.unmapped_template_assets.length}):`);
|
|
916
|
+
for (const u of report.unmapped_template_assets) {
|
|
917
|
+
console.log(` - ${u.path}`);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
if (report.unconsumed_template_assets.length > 0) {
|
|
921
|
+
console.log(`⚠️ 未消费资产 (${report.unconsumed_template_assets.length}):`);
|
|
922
|
+
for (const u of report.unconsumed_template_assets) {
|
|
923
|
+
console.log(` - ${u.path} (mode=${u.consumption_mode})`);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
if (report.code_only_mechanisms.length > 0) {
|
|
927
|
+
console.log(`⚠️ 仅代码机制 (无模板层):`);
|
|
928
|
+
for (const m of report.code_only_mechanisms) {
|
|
929
|
+
console.log(` - ${m.mechanism_id} (${m.priority}, ${m.status})`);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
if (report.template_only_mechanisms.length > 0) {
|
|
933
|
+
console.log(`⚠️ 仅模板机制 (无代码层):`);
|
|
934
|
+
for (const m of report.template_only_mechanisms) {
|
|
935
|
+
console.log(` - ${m.mechanism_id} (${m.priority}, ${m.status})`);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
if (report.required_assets_without_enforcer.length > 0) {
|
|
939
|
+
console.log(`❌ Required 资产无 enforcer (${report.required_assets_without_enforcer.length}):`);
|
|
940
|
+
for (const r of report.required_assets_without_enforcer) {
|
|
941
|
+
console.log(` - ${r.path} (mechanism=${r.owner_mechanism_id})`);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
if (report.overpromised_adapter_rules.length > 0) {
|
|
945
|
+
console.log(`❌ 适配器过度承诺 (${report.overpromised_adapter_rules.length}):`);
|
|
946
|
+
for (const o of report.overpromised_adapter_rules) {
|
|
947
|
+
console.log(` - ${o.source_file}: ${o.promised_mechanism_id} (${o.promise_keywords.join(",")})`);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
if (report.deprecated_assets_injected.length > 0) {
|
|
951
|
+
console.log(`⚠️ Deprecated 资产仍被注入:`);
|
|
952
|
+
for (const d of report.deprecated_assets_injected) {
|
|
953
|
+
console.log(` - ${d.path}`);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
if (report.template_mechanism_drift.length > 0) {
|
|
957
|
+
const driftHard = report.template_mechanism_drift.filter((f) => f.severity === "hard_fail");
|
|
958
|
+
const driftAdvisory = report.template_mechanism_drift.filter((f) => f.severity === "advisory");
|
|
959
|
+
if (driftAdvisory.length > 0) {
|
|
960
|
+
console.log(`⚠️ 漂移 advisory (${driftAdvisory.length}):`);
|
|
961
|
+
for (const f of driftAdvisory) {
|
|
962
|
+
console.log(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
if (driftHard.length > 0) {
|
|
966
|
+
console.log(`❌ 漂移 hard_fail (${driftHard.length}):`);
|
|
967
|
+
for (const f of driftHard) {
|
|
968
|
+
console.log(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
console.log("");
|
|
973
|
+
if (report.hard_fail_count > 0) {
|
|
974
|
+
console.log(`❌ 审计失败: ${report.hard_fail_count} hard_fail, ${report.advisory_count} advisory`);
|
|
975
|
+
process.exit(1);
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
console.log(`✅ 审计通过: 0 hard_fail, ${report.advisory_count} advisory`);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
catch (e) {
|
|
982
|
+
console.error(`❌ audit-template-mechanisms 失败: ${e.message}`);
|
|
983
|
+
process.exit(1);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
async function cmdValidateBatch1() {
|
|
987
|
+
console.error("[soloForge] CLI: 执行 cmdValidateBatch1");
|
|
988
|
+
const { validateMechanismLayerMaps, listMechanismLayerMaps } = await import("../engine/dual_layer_mechanism_registry.js");
|
|
989
|
+
const { auditTemplateMechanisms } = await import("../engine/template_mechanism_auditor.js");
|
|
990
|
+
const { validateBatch1Scenarios, validateBatch1ProblemMatrix } = await import("../engine/batch1_scenario_registry.js");
|
|
991
|
+
const cwd = process.cwd();
|
|
992
|
+
const maps = listMechanismLayerMaps();
|
|
993
|
+
const mechFindings = validateMechanismLayerMaps(maps, cwd);
|
|
994
|
+
const mechanismsPass = mechFindings.filter((f) => f.severity === "hard_fail").length === 0;
|
|
995
|
+
const auditReport = auditTemplateMechanisms(cwd);
|
|
996
|
+
const auditPass = auditReport.hard_fail_count === 0;
|
|
997
|
+
const scenarioResults = await validateBatch1Scenarios(mechanismsPass, auditPass, true);
|
|
998
|
+
const allPass = scenarioResults.every((s) => s.status === "PASS");
|
|
999
|
+
const isJson = process.argv.includes("--json");
|
|
1000
|
+
if (isJson) {
|
|
1001
|
+
const problemMatrix = validateBatch1ProblemMatrix(cwd);
|
|
1002
|
+
const problemAllPass = problemMatrix.every((p) => Object.values(p.dimensions).every((d) => d.status === "PASS"));
|
|
1003
|
+
console.log(JSON.stringify({
|
|
1004
|
+
mechanisms_pass: mechanismsPass,
|
|
1005
|
+
audit_pass: auditPass,
|
|
1006
|
+
all_pass: allPass && problemAllPass,
|
|
1007
|
+
problem_matrix_count: problemMatrix.length,
|
|
1008
|
+
problem_matrix: problemMatrix,
|
|
1009
|
+
scenarios: scenarioResults,
|
|
1010
|
+
}, null, 2));
|
|
1011
|
+
}
|
|
1012
|
+
else {
|
|
1013
|
+
for (const s of scenarioResults) {
|
|
1014
|
+
const icon = s.status === "PASS" ? "✓" : "✗";
|
|
1015
|
+
console.log(`${icon} ${s.scenario_id}: ${s.scenario_name} — ${s.status}`);
|
|
1016
|
+
for (const r of s.rules) {
|
|
1017
|
+
const ri = r.status === "PASS" ? " ✓" : " ✗";
|
|
1018
|
+
console.log(`${ri} ${r.rule}: ${r.evidence}`);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
console.log(allPass ? "\nAll scenarios PASS" : "\nSome scenarios FAIL");
|
|
1022
|
+
}
|
|
1023
|
+
process.exit(allPass ? 0 : 1);
|
|
1024
|
+
}
|
|
565
1025
|
async function cmdStatus() {
|
|
1026
|
+
console.error("[soloForge] CLI: 执行 cmdStatus");
|
|
566
1027
|
const projectPath = process.cwd();
|
|
567
1028
|
console.log(`SoloForge 状态: ${projectPath}`);
|
|
568
|
-
const config = await
|
|
1029
|
+
const { config, source } = await resolveProjectConfig(projectPath);
|
|
1030
|
+
console.log(` 配置来源: ${source === "config_file" ? "config.yaml" : "自动推断"}`);
|
|
569
1031
|
console.log(` 产品: ${config.product_profile}`);
|
|
570
1032
|
console.log(` 后端: ${config.tech_stack.backend.framework || "未配置"}`);
|
|
571
1033
|
console.log(` 前端: ${config.tech_stack.frontend.framework || "未配置"}`);
|
|
1034
|
+
// Per-field config precedence status
|
|
1035
|
+
try {
|
|
1036
|
+
const { resolutions, entries } = await resolveCurrentProjectConfigReports(projectPath);
|
|
1037
|
+
if (resolutions.length > 0) {
|
|
1038
|
+
console.log("");
|
|
1039
|
+
console.log(" 字段解析状态:");
|
|
1040
|
+
for (const r of resolutions) {
|
|
1041
|
+
const stale = r.stale_warning ? " ⚠️ stale" : "";
|
|
1042
|
+
const conflict = r.conflict_report ? " ⚠️ conflict" : "";
|
|
1043
|
+
console.log(` ${r.field_path}: ${JSON.stringify(r.resolved_value)} (${r.source}${stale}${conflict})`);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
const schemaPath = path.join(projectPath, ".soloforge", "config.evidence.json");
|
|
1047
|
+
if (fss.existsSync(schemaPath)) {
|
|
1048
|
+
try {
|
|
1049
|
+
const raw = JSON.parse(fss.readFileSync(schemaPath, "utf-8"));
|
|
1050
|
+
console.log(` evidence: schema_version=${raw.schema_version ?? 1}, ${entries.length} entries`);
|
|
1051
|
+
}
|
|
1052
|
+
catch {
|
|
1053
|
+
console.log(" evidence: 无法解析");
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
else if (source === "config_file") {
|
|
1057
|
+
console.log(" evidence: ⚠️ config.evidence.json 缺失");
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
catch { }
|
|
1061
|
+
// Evidence warnings
|
|
1062
|
+
const evidenceWarnings = await checkEvidenceWarnings(projectPath);
|
|
1063
|
+
for (const w of evidenceWarnings) {
|
|
1064
|
+
console.log(` ⚠️ evidence: ${w}`);
|
|
1065
|
+
}
|
|
572
1066
|
const knowledgeDir = getProjectKnowledgeDir(config);
|
|
573
1067
|
if (fss.existsSync(knowledgeDir)) {
|
|
574
1068
|
const { KnowledgeIndexManager } = await import("../knowledge/index_manager.js");
|
|
@@ -581,34 +1075,8 @@ async function cmdStatus() {
|
|
|
581
1075
|
console.log(" 知识: 未初始化");
|
|
582
1076
|
}
|
|
583
1077
|
}
|
|
584
|
-
function
|
|
585
|
-
|
|
586
|
-
const backendFramework = process.env.SOLOFORGE_BACKEND_FRAMEWORK || "spring-boot";
|
|
587
|
-
const frontendLang = process.env.SOLOFORGE_FRONTEND_LANG || "typescript";
|
|
588
|
-
const frontendFramework = process.env.SOLOFORGE_FRONTEND_FRAMEWORK || "react";
|
|
589
|
-
return {
|
|
590
|
-
schema_version: 1,
|
|
591
|
-
name: path.basename(projectPath),
|
|
592
|
-
tech_stack: {
|
|
593
|
-
backend: { lang: backendLang, framework: backendFramework, version: "3.x" },
|
|
594
|
-
frontend: { lang: frontendLang, framework: frontendFramework, version: "18" },
|
|
595
|
-
},
|
|
596
|
-
product_profile: "default",
|
|
597
|
-
repos: [
|
|
598
|
-
{ name: "backend", path: "./backend", lang: backendLang, framework: backendFramework, scope: ["src/main/java", "src/test/java"] },
|
|
599
|
-
{ name: "frontend", path: "./frontend", lang: frontendLang, framework: frontendFramework, scope: ["src"] },
|
|
600
|
-
],
|
|
601
|
-
build_commands: {
|
|
602
|
-
backend: { build: "cd backend && mvn compile -q", test: "cd backend && mvn test", full: "cd backend && mvn verify" },
|
|
603
|
-
frontend: { build: "cd frontend && npm run build", test: "cd frontend && npm test", full: "cd frontend && npm run build && npm test" },
|
|
604
|
-
},
|
|
605
|
-
scope: {
|
|
606
|
-
backend: ["backend/src"],
|
|
607
|
-
frontend: ["frontend/src"],
|
|
608
|
-
},
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
async function interactiveConfig() {
|
|
1078
|
+
async function interactiveConfig(projectPath) {
|
|
1079
|
+
console.error("[soloForge] CLI: 执行 interactiveConfig");
|
|
612
1080
|
if (!process.stdin.isTTY)
|
|
613
1081
|
return undefined;
|
|
614
1082
|
const readline = await import("node:readline");
|
|
@@ -619,20 +1087,42 @@ async function interactiveConfig() {
|
|
|
619
1087
|
const backendFramework = await ask("后端框架 (spring-boot): ") || "spring-boot";
|
|
620
1088
|
const frontendFramework = await ask("前端框架 (react): ") || "react";
|
|
621
1089
|
rl.close();
|
|
622
|
-
|
|
623
|
-
schema_version: 1,
|
|
1090
|
+
const draft = {
|
|
624
1091
|
name,
|
|
625
|
-
product_profile: product,
|
|
626
1092
|
tech_stack: {
|
|
627
|
-
backend: { lang: "java", framework: backendFramework, version: "" },
|
|
1093
|
+
backend: { lang: backendFramework === "go" ? "go" : "java", framework: backendFramework, version: "" },
|
|
628
1094
|
frontend: { lang: "typescript", framework: frontendFramework, version: "" },
|
|
629
1095
|
},
|
|
630
|
-
|
|
631
|
-
build_commands: {
|
|
632
|
-
|
|
1096
|
+
product_profile: product,
|
|
1097
|
+
build_commands: {
|
|
1098
|
+
backend: blueprintBackendCommands(backendFramework),
|
|
1099
|
+
frontend: blueprintFrontendCommands(frontendFramework),
|
|
1100
|
+
},
|
|
1101
|
+
scope: { backend: ["src/"], frontend: ["src/"] },
|
|
1102
|
+
advisory_notes: [],
|
|
1103
|
+
confidence: "high",
|
|
1104
|
+
};
|
|
1105
|
+
const src = "confirmed";
|
|
1106
|
+
const evidence = {
|
|
1107
|
+
schema_version: 1,
|
|
1108
|
+
generated_at: new Date().toISOString(),
|
|
1109
|
+
mode: "interactive",
|
|
1110
|
+
project_root: projectPath,
|
|
1111
|
+
fields: {
|
|
1112
|
+
"name": { value: name, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
|
|
1113
|
+
"tech_stack.backend": { value: draft.tech_stack.backend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
|
|
1114
|
+
"tech_stack.frontend": { value: draft.tech_stack.frontend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
|
|
1115
|
+
"build_commands.backend": { value: draft.build_commands.backend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
|
|
1116
|
+
"build_commands.frontend": { value: draft.build_commands.frontend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
|
|
1117
|
+
"product_profile": { value: product, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
|
|
1118
|
+
"scope.backend": { value: draft.scope.backend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
|
|
1119
|
+
"scope.frontend": { value: draft.scope.frontend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
|
|
1120
|
+
},
|
|
633
1121
|
};
|
|
1122
|
+
return { draft, evidence };
|
|
634
1123
|
}
|
|
635
1124
|
function cmdVersion() {
|
|
1125
|
+
console.error("[soloForge] CLI: 执行 cmdVersion");
|
|
636
1126
|
// dist/bin/soloforge.js → dist/package.json (local) 或 package.json (global npm)
|
|
637
1127
|
const pkgPath = path.resolve(import.meta.dirname, "..", "package.json");
|
|
638
1128
|
try {
|