@ohos-cpf/3rdloop 0.0.1
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 +425 -0
- package/bin/3rdloop.mjs +48 -0
- package/lib/cli.js +741 -0
- package/lib/config.js +318 -0
- package/lib/doctor.js +114 -0
- package/lib/exit-codes.js +31 -0
- package/lib/opencode.js +156 -0
- package/lib/orch.js +427 -0
- package/lib/queries.js +264 -0
- package/lib/runner.js +979 -0
- package/lib/step.js +326 -0
- package/lib/ui.js +223 -0
- package/lib/workflow.js +291 -0
- package/lib/workflows.js +132 -0
- package/package.json +50 -0
- package/vendor/Server/Agent/SkillSelector/README.md +344 -0
- package/vendor/Server/Agent/SkillSelector/core/Agent.js +207 -0
- package/vendor/Server/Agent/SkillSelector/index.js +14 -0
- package/vendor/Server/Agent/SkillSelector/llm/llmClient.js +313 -0
- package/vendor/Server/Agent/SkillSelector/llm/prompts.js +161 -0
- package/vendor/Server/Agent/SkillSelector/llm/reactSteps.js +144 -0
- package/vendor/Server/Agent/SkillSelector/matcher/fuzzyMatcher.js +433 -0
- package/vendor/Server/Agent/SkillSelector/scanner/skillScanner.js +382 -0
- package/vendor/Server/Agent/SkillSelector/types.js +63 -0
- package/vendor/Server/Agent/SkillSelector/utils/actionWords.js +60 -0
- package/vendor/Server/Brain/AnalysisStrategies.js +422 -0
- package/vendor/Server/Brain/Brain.js +686 -0
- package/vendor/Server/Brain/DecompositionStrategies.js +621 -0
- package/vendor/Server/Brain/PlanPersistence.js +196 -0
- package/vendor/Server/Brain/SkillExecutor.js +251 -0
- package/vendor/Server/Brain/index.js +11 -0
- package/vendor/Server/CLI/cli.js +243 -0
- package/vendor/Server/CLI/opencode/index.js +804 -0
- package/vendor/Server/CLI/opencode.js +5 -0
- package/vendor/Server/DbUse/MessageArchive.js +61 -0
- package/vendor/Server/DbUse/StorageManager.js +107 -0
- package/vendor/Server/DbUse/adapters/BaseAdapter.js +94 -0
- package/vendor/Server/DbUse/adapters/FileAdapter.js +138 -0
- package/vendor/Server/DbUse/adapters/JsonAdapter.js +138 -0
- package/vendor/Server/DbUse/adapters/JsonlAdapter.js +114 -0
- package/vendor/Server/DbUse/adapters/SqliteAdapter.js +157 -0
- package/vendor/Server/DbUse/index.js +160 -0
- package/vendor/Server/DbUse/stores/SessionStore.js +279 -0
- package/vendor/Server/DbUse/stores/TaskExecutionStore.js +133 -0
- package/vendor/Server/DbUse/stores/TaskRegistryStore.js +262 -0
- package/vendor/Server/DbUse/stores/TaskStepStore.js +279 -0
- package/vendor/Server/FlexRunner/FlexRunner.js +1759 -0
- package/vendor/Server/FlexRunner/index.js +12 -0
- package/vendor/Server/Knowledge/KnowledgeImporter.js +523 -0
- package/vendor/Server/Knowledge/KnowledgeManager.js +341 -0
- package/vendor/Server/Knowledge/index.js +33 -0
- package/vendor/Server/LoopEngine/LoopEngine.js +1133 -0
- package/vendor/Server/LoopEngine/index.js +11 -0
- package/vendor/Server/Orchestrator/Orchestrator.js +1425 -0
- package/vendor/Server/Orchestrator/StepNode.js +312 -0
- package/vendor/Server/Orchestrator/index.js +13 -0
- package/vendor/Server/Routes/controllers/BrainController.js +241 -0
- package/vendor/Server/Routes/controllers/FlexRunnerController.js +1125 -0
- package/vendor/Server/Routes/controllers/HealthController.js +44 -0
- package/vendor/Server/Routes/controllers/KnowledgeImportController.js +355 -0
- package/vendor/Server/Routes/controllers/LoopEngineController.js +788 -0
- package/vendor/Server/Routes/controllers/OrchestratorController.js +911 -0
- package/vendor/Server/Routes/controllers/StatsController.js +57 -0
- package/vendor/Server/Routes/controllers/StreamController.js +67 -0
- package/vendor/Server/Routes/library/logger.js +179 -0
- package/vendor/Server/Routes/library/zipArchive.js +172 -0
- package/vendor/Server/Routes/router/Router.js +204 -0
- package/vendor/Server/Routes/routes/brain.js +47 -0
- package/vendor/Server/Routes/routes/flexrunner.js +72 -0
- package/vendor/Server/Routes/routes/health.js +28 -0
- package/vendor/Server/Routes/routes/index.js +57 -0
- package/vendor/Server/Routes/routes/knowledge.js +55 -0
- package/vendor/Server/Routes/routes/loopengine.js +58 -0
- package/vendor/Server/Routes/routes/orchestrator.js +61 -0
- package/vendor/Server/Routes/routes/registry.js +98 -0
- package/vendor/Server/Routes/routes/stats.js +23 -0
- package/vendor/Server/Routes/routes/stream.js +30 -0
- package/vendor/Server/Routes/server.js +202 -0
- package/vendor/Server/Routes/sse/SseHub.js +308 -0
- package/vendor/Server/Skills/acceptance-check/SKILL.md +174 -0
- package/vendor/Server/Skills/acceptance-check/references/PHASE1_ARTIFACT_COLLECTION.md +52 -0
- package/vendor/Server/Skills/acceptance-check/references/PHASE2_CRITERIA_EVALUATION.md +77 -0
- package/vendor/Server/Skills/arkts-code-check/SKILL.md +314 -0
- package/vendor/Server/Skills/arkts-code-check/references/CODE_CHECK_GUIDE.md +160 -0
- package/vendor/Server/Skills/arkts-code-check/references/FILE_TYPE_GUIDE.md +29 -0
- package/vendor/Server/Skills/arkts-code-check/references/PHASE1_INFO_COLLECTION.md +222 -0
- package/vendor/Server/Skills/arkts-code-check/references/REPORT_TEMPLATE.md +220 -0
- package/vendor/Server/Skills/arkts-library-compile-validate/SKILL.md +329 -0
- package/vendor/Server/Skills/arkts-library-compile-validate/scripts/build.ps1 +93 -0
- package/vendor/Server/Skills/arkts-library-compile-validate/scripts/code-linter.cjs +433 -0
- package/vendor/Server/Skills/arkts-library-compile-validate/scripts/migrate.cjs +851 -0
- package/vendor/Server/Skills/arkts-library-compile-validate/scripts/ohpm-switch.cjs +789 -0
- package/vendor/Server/Skills/arkts-library-demo-code/SKILL.md +291 -0
- package/vendor/Server/Skills/arkts-library-demo-code/references/API_SIGNATURE_CHECKS.md +68 -0
- package/vendor/Server/Skills/arkts-library-demo-code/references/BUILD_VALIDATION.md +184 -0
- package/vendor/Server/Skills/arkts-library-demo-code/references/CODE_STANDARDS.md +337 -0
- package/vendor/Server/Skills/arkts-library-demo-code/references/EXAMPLES.md +400 -0
- package/vendor/Server/Skills/arkts-library-demo-code/references/SYSTEM_API_LOOKUP.md +99 -0
- package/vendor/Server/Skills/arkts-library-demo-code/references/TEMPLATE.md +544 -0
- package/vendor/Server/Skills/arkts-library-demo-code/scripts/build.ps1 +93 -0
- package/vendor/Server/Skills/arkts-library-demo-code/scripts/code-linter.cjs +433 -0
- package/vendor/Server/Skills/arkts-library-demo-code/scripts/migrate.cjs +851 -0
- package/vendor/Server/Skills/arkts-library-demo-code/scripts/ohpm-switch.cjs +789 -0
- package/vendor/Server/Skills/arkts-library-demo-coverage/SKILL.md +174 -0
- package/vendor/Server/Skills/arkts-library-demo-scenario/SKILL.md +321 -0
- package/vendor/Server/Skills/arkts-library-demo-scenario/references/EXAMPLES.md +100 -0
- package/vendor/Server/Skills/arkts-library-demo-scenario/references/TEMPLATE.md +185 -0
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/SKILL.md +234 -0
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/assets/REPORT_TEMPLATE.md +103 -0
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/CHECK_DIMENSIONS.md +89 -0
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/COMPLIANCE_CHECKLIST.md +62 -0
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/KB_QUERY_GUIDE.md +108 -0
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/MCP_TOOL_DISCOVERY.md +124 -0
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/REPORT_TEMPLATE.md +90 -0
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/SCORING_FORMULA.md +57 -0
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/scripts/validate-skill.cjs +259 -0
- package/vendor/Server/Skills/arkts-library-interface-spec/SKILL.md +97 -0
- package/vendor/Server/Skills/arkts-library-memory-leak-check/SKILL.md +392 -0
- package/vendor/Server/Skills/arkts-library-source-clone/SKILL.md +113 -0
- package/vendor/Server/Skills/arkts-library-stability-check/SKILL.md +313 -0
- package/vendor/Server/Skills/arkts-library-stability-check/assets/REPORT_TEMPLATE.md +154 -0
- package/vendor/Server/Skills/arkts-library-stability-check/references/CHECKLIST.md +166 -0
- package/vendor/Server/Skills/arkts-library-stability-check/references/CODE_EXAMPLES.md +309 -0
- package/vendor/Server/Skills/arkts-library-stability-check/references/SCORING_RULES.md +90 -0
- package/vendor/Server/Skills/arkts-library-stability-check/scripts/validate-skill.cjs +282 -0
- package/vendor/Server/Skills/arkts-library-test-coverage-check/SKILL.md +361 -0
- package/vendor/Server/Skills/arkts-library-test-coverage-check/assets/REPORT_TEMPLATE.md +146 -0
- package/vendor/Server/Skills/arkts-library-test-coverage-check/references/CHECKLIST.md +253 -0
- package/vendor/Server/Skills/arkts-library-test-coverage-check/references/MCP_TOOL_USAGE.md +115 -0
- package/vendor/Server/Skills/arkts-library-test-coverage-check/scripts/validate-skill.cjs +263 -0
- package/vendor/Server/Skills/arkts-library-xts-code/SKILL.md +455 -0
- package/vendor/Server/Skills/arkts-library-xts-code/assets/report-template.md +60 -0
- package/vendor/Server/Skills/arkts-library-xts-code/references/ACCESS_MODIFIER_PRECHECK.md +76 -0
- package/vendor/Server/Skills/arkts-library-xts-code/references/BUILD_VERIFICATION.md +200 -0
- package/vendor/Server/Skills/arkts-library-xts-code/references/CODE_STANDARDS.md +519 -0
- package/vendor/Server/Skills/arkts-library-xts-code/references/SUBAGENT_PROMPT_TEMPLATE.md +276 -0
- package/vendor/Server/Skills/arkts-library-xts-code/references/SYSTEM_API_LOOKUP.md +93 -0
- package/vendor/Server/Skills/arkts-library-xts-code/references/XTS_TEMPLATE.md +767 -0
- package/vendor/Server/Skills/arkts-library-xts-code/scripts/build.ps1 +93 -0
- package/vendor/Server/Skills/arkts-library-xts-code/scripts/code-linter.cjs +433 -0
- package/vendor/Server/Skills/arkts-library-xts-code/scripts/migrate.cjs +851 -0
- package/vendor/Server/Skills/arkts-library-xts-code/scripts/ohpm-switch.cjs +789 -0
- package/vendor/Server/Skills/arkts-library-xts-code/scripts/precheck-access-modifiers.cjs +221 -0
- package/vendor/Server/Skills/arkts-library-xts-code-fix/SKILL.md +229 -0
- package/vendor/Server/Skills/arkts-library-xts-coverage/SKILL.md +97 -0
- package/vendor/Server/Skills/arkts-library-xts-doc/SKILL.md +194 -0
- package/vendor/Server/Skills/arkts-library-xts-doc/references/EXAMPLES.md +576 -0
- package/vendor/Server/Skills/arkts-library-xts-doc/references/TEMPLATE.md +575 -0
- package/vendor/Server/Skills/arkts-library-xts-doc/references/TESTABILITY_GUIDE.md +182 -0
- package/vendor/Server/Skills/arkts-library-xts-execution/SKILL.md +491 -0
- package/vendor/Server/Skills/arkts-library-xts-execution/references/error-fixing-examples.md +217 -0
- package/vendor/Server/Skills/arkts-library-xts-execution/scripts/build.ps1 +93 -0
- package/vendor/Server/Skills/arkts-library-xts-execution/scripts/code-linter.cjs +433 -0
- package/vendor/Server/Skills/arkts-library-xts-execution/scripts/migrate.cjs +851 -0
- package/vendor/Server/Skills/arkts-library-xts-execution/scripts/ohpm-switch.cjs +789 -0
- package/vendor/Server/Skills/flutter-code-check/SKILL.md +299 -0
- package/vendor/Server/Skills/flutter-code-check/assets/OUTPUT_TEMPLATE.md +312 -0
- package/vendor/Server/Skills/flutter-code-check/references/CHECKLIST.md +190 -0
- package/vendor/Server/Skills/flutter-code-check/references/PLATFORMS.md +134 -0
- package/vendor/Server/Skills/flutter-code-check/scripts/validate-skill.cjs +259 -0
- package/vendor/Server/Skills/flutter-interface/README.md +75 -0
- package/vendor/Server/Skills/flutter-interface/SKILL.md +291 -0
- package/vendor/Server/Skills/flutter-interface/references/EXAMPLES.md +336 -0
- package/vendor/Server/Skills/flutter-interface/references/GIT_CLONE_GUIDE.md +190 -0
- package/vendor/Server/Skills/flutter-interface/references/SCRIPT_REFERENCE.md +258 -0
- package/vendor/Server/Skills/flutter-interface/references/TEMPLATE.md +254 -0
- package/vendor/Server/Skills/flutter-library-consistency-check/SKILL.md +518 -0
- package/vendor/Server/Skills/flutter-library-consistency-check/references/CHECKLIST.md +382 -0
- package/vendor/Server/Skills/flutter-library-consistency-check/references/FUNCTION_COMPARISON_GUIDE.md +342 -0
- package/vendor/Server/Skills/flutter-library-consistency-check/references/PLATFORM_LIMITATION_GUIDE.md +71 -0
- package/vendor/Server/Skills/flutter-library-documentation-quality-check/SKILL.md +519 -0
- package/vendor/Server/Skills/flutter-library-documentation-quality-check/references/CHECKLIST.md +407 -0
- package/vendor/Server/Skills/flutter-library-memory-leak-check/SKILL.md +653 -0
- package/vendor/Server/Skills/flutter-library-memory-leak-check/references/CHECKLIST.md +397 -0
- package/vendor/Server/Skills/flutter-library-stability-check/SKILL.md +745 -0
- package/vendor/Server/Skills/flutter-library-stability-check/references/CHECKLIST.md +721 -0
- package/vendor/Server/Skills/flutter-library-test-coverage-check/SKILL.md +414 -0
- package/vendor/Server/Skills/flutter-library-test-coverage-check/assets/REPORT_TEMPLATE.md +150 -0
- package/vendor/Server/Skills/flutter-library-test-coverage-check/references/CHECKLIST.md +304 -0
- package/vendor/Server/Skills/flutter-library-test-coverage-check/references/SCORING_RULES.md +265 -0
- package/vendor/Server/Skills/flutter-library-test-coverage-check/references/SCRIPT_USAGE.md +286 -0
- package/vendor/Server/Skills/knowledge-import/SKILL.md +383 -0
- package/vendor/Server/Skills/knowledge-import/references/MCP_TOOL_USAGE.md +165 -0
- package/vendor/Server/Skills/knowledge-import/references/SKILL_LOCATOR_GUIDE.md +91 -0
- package/vendor/Server/Skills/knowledge-import/references/SKILL_OPTIMIZATION_GUIDE.md +127 -0
- package/vendor/Server/Skills/ohos-lib-pr-push/SKILL.md +301 -0
- package/vendor/Server/Skills/ohos-lib-pr-push/assets/PR_ISSUE_TEMPLATE.md +105 -0
- package/vendor/Server/Skills/ohos-lib-pr-push/references/GITCODE_API.md +127 -0
- package/vendor/Server/Skills/ohos-lib-pr-push/scripts/gitcode-api.cjs +208 -0
- package/vendor/Server/Skills/rn-code-check/SKILL.md +321 -0
- package/vendor/Server/Skills/rn-code-check/references/API-GUIDE.md +235 -0
- package/vendor/Server/Skills/rn-code-check/references/CHECKLIST.md +189 -0
- package/vendor/Server/Skills/rn-code-check/references/REPORT-TEMPLATE.md +247 -0
- package/vendor/Server/Skills/rn-lib-add-example/SKILL.md +198 -0
- package/vendor/Server/Skills/rn-lib-add-example/references/APP_RENAME_GUIDE.md +40 -0
- package/vendor/Server/Skills/rn-lib-add-example/references/SHELL_ADAPTATION_CHECKLIST.md +78 -0
- package/vendor/Server/Skills/rn-lib-add-example/references/TEMPLATE_REPO_GUIDE.md +70 -0
- package/vendor/Server/Skills/rn-lib-add-example/references/VERIFICATION_GUIDE.md +47 -0
- package/vendor/Server/Skills/rn-lib-add-example/scripts/create-example.cjs +252 -0
- package/vendor/Server/Skills/rn-lib-update-doc/SKILL.md +176 -0
- package/vendor/Server/Skills/rn-lib-update-doc/config.json +5 -0
- package/vendor/Server/Skills/rn-lib-update-doc/references/changelog-template.md +35 -0
- package/vendor/Server/Skills/rn-lib-update-doc/references/format-diff.md +137 -0
- package/vendor/Server/Skills/rn-lib-update-doc/references/link-registry.json +33 -0
- package/vendor/Server/Skills/rn-lib-update-doc/references/model-0.4.2-overview.md +40 -0
- package/vendor/Server/Skills/rn-lib-update-doc/references/model-0.4.2.md +429 -0
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/detect-readme-format.cjs +105 -0
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/find-usage-doc.cjs +90 -0
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/link-verify.cjs +213 -0
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/normalize-changelog.cjs +73 -0
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/normalize-package-meta.cjs +258 -0
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/normalize-readme-links.cjs +341 -0
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/resolve-usage-docs.cjs +67 -0
- package/vendor/Server/Skills/rn-library-consistency-check/SKILL.md +299 -0
- package/vendor/Server/Skills/rn-library-consistency-check/assets/REPORT_TEMPLATE.md +293 -0
- package/vendor/Server/Skills/rn-library-consistency-check/references/ARKTS_COMPONENT_CHECK_GUIDE.md +857 -0
- package/vendor/Server/Skills/rn-library-consistency-check/references/ARKTS_TURBOMODULE_CHECK_GUIDE.md +856 -0
- package/vendor/Server/Skills/rn-library-consistency-check/references/CHECKLIST.md +157 -0
- package/vendor/Server/Skills/rn-library-consistency-check/references/CPP_COMPONENT_CHECK_GUIDE.md +801 -0
- package/vendor/Server/Skills/rn-library-consistency-check/references/CPP_TURBOMODULE_CHECK_GUIDE.md +684 -0
- package/vendor/Server/Skills/rn-library-consistency-check/references/FUNCTION_COMPARISON_GUIDE.md +233 -0
- package/vendor/Server/Skills/rn-library-consistency-check/references/NATIVE_COMPONENT_IDENTIFICATION.md +1373 -0
- package/vendor/Server/Skills/rn-library-consistency-check/references/SCORING_STANDARD.md +220 -0
- package/vendor/Server/Skills/rn-library-consistency-check/scripts/validate-skill.py +245 -0
- package/vendor/Server/Skills/rn-library-documentation-quality-check/SKILL.md +263 -0
- package/vendor/Server/Skills/rn-library-documentation-quality-check/assets/MODEL.md +414 -0
- package/vendor/Server/Skills/rn-library-documentation-quality-check/assets/MODEL_en.md +413 -0
- package/vendor/Server/Skills/rn-library-documentation-quality-check/assets/REPORT_TEMPLATE.md +311 -0
- package/vendor/Server/Skills/rn-library-documentation-quality-check/references/CHECK_CHECKLIST.md +355 -0
- package/vendor/Server/Skills/rn-library-documentation-quality-check/references/CROSS_VALIDATION_GUIDE.md +115 -0
- package/vendor/Server/Skills/rn-library-documentation-quality-check/references/DOC_COLLECTION_GUIDE.md +139 -0
- package/vendor/Server/Skills/rn-library-documentation-quality-check/references/EXAMPLES.md +586 -0
- package/vendor/Server/Skills/rn-library-documentation-quality-check/references/GOTCHAS.md +57 -0
- package/vendor/Server/Skills/rn-library-documentation-quality-check/scripts/validate-skill.py +259 -0
- package/vendor/Server/Skills/rn-library-interface-analyzer/SKILL.md +301 -0
- package/vendor/Server/Skills/rn-library-interface-analyzer/assets/REPORT_TEMPLATE.md +148 -0
- package/vendor/Server/Skills/rn-library-interface-analyzer/references/DOC_ANNOTATION_GUIDE.md +118 -0
- package/vendor/Server/Skills/rn-library-interface-analyzer/references/SCRIPT_USAGE_GUIDE.md +168 -0
- package/vendor/Server/Skills/rn-library-interface-analyzer/references/URL_PARSING_RULES.md +176 -0
- package/vendor/Server/Skills/rn-library-issue-generalizer/SKILL.md +274 -0
- package/vendor/Server/Skills/rn-library-issue-generalizer/assets/case-template.md +45 -0
- package/vendor/Server/Skills/rn-library-issue-generalizer/assets/rule-template.md +25 -0
- package/vendor/Server/Skills/rn-library-issue-generalizer/references/PR_FETCH_GUIDE.md +61 -0
- package/vendor/Server/Skills/rn-library-issue-generalizer/references/RULE_TEMPLATE_GUIDE.md +165 -0
- package/vendor/Server/Skills/rn-library-issue-generalizer/scripts/fetch-pr-info.py +239 -0
- package/vendor/Server/Skills/rn-library-known-issue-check/SKILL.md +263 -0
- package/vendor/Server/Skills/rn-library-known-issue-check/assets/REPORT_TEMPLATE.md +96 -0
- package/vendor/Server/Skills/rn-library-known-issue-check/references/COMPLIANCE_CHECKLIST.md +58 -0
- package/vendor/Server/Skills/rn-library-known-issue-check/references/INSPECTION_GUIDE.md +99 -0
- package/vendor/Server/Skills/rn-library-known-issue-check/references/PRESCREEN_GUIDE.md +64 -0
- package/vendor/Server/Skills/rn-library-known-issue-check/references/SOURCE_PREP_GUIDE.md +75 -0
- package/vendor/Server/Skills/rn-library-known-issue-check/scripts/validate-known-issue-report.py +164 -0
- package/vendor/Server/Skills/rn-library-memory-leak-check/SKILL.md +339 -0
- package/vendor/Server/Skills/rn-library-memory-leak-check/assets/REPORT_TEMPLATE.md +83 -0
- package/vendor/Server/Skills/rn-library-memory-leak-check/references/CHECKLIST.md +859 -0
- package/vendor/Server/Skills/rn-library-memory-leak-check/references/HARMONY_CODE_PATTERNS.md +122 -0
- package/vendor/Server/Skills/rn-library-memory-leak-check/scripts/scan_harmony_code.py +279 -0
- package/vendor/Server/Skills/rn-library-stability-check/SKILL.md +273 -0
- package/vendor/Server/Skills/rn-library-stability-check/assets/REPORT_TEMPLATE.md +129 -0
- package/vendor/Server/Skills/rn-library-stability-check/references/CHECKLIST.md +581 -0
- package/vendor/Server/Skills/rn-library-stability-check/references/SCORING_RULES.md +138 -0
- package/vendor/Server/Skills/rn-library-stability-check/scripts/scan-harmony-code.py +168 -0
- package/vendor/Server/Skills/rn-library-test-coverage-check/SKILL.md +506 -0
- package/vendor/Server/Skills/rn-library-test-coverage-check/references/CHECKLIST.md +280 -0
- package/vendor/Server/Skills/rn-library-test-coverage-check/references/DEMO_LOCATION.md +221 -0
- package/vendor/Server/Skills/rn-library-test-coverage-check/references/REPORT_TEMPLATE.md +209 -0
- package/vendor/Server/Skills/rn-library-test-coverage-check/references/SCRIPT_USAGE.md +325 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/SKILL.md +279 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/assets/TEST_FILE_TEMPLATES.md +404 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/BUILD_TROUBLESHOOTING.md +185 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/BUILD_WORKFLOW.md +265 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/COMMON_CONFIG.md +189 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/CONFIG_GUIDE.md +203 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/COVERAGE_ANALYZER.md +147 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/DESIGN_DOC_GUIDE.md +148 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/GENERATION_FLOW.md +165 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/GENERATION_STRATEGY.md +195 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/HARMONY_SCANNER.md +249 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/JEST_FRAMEWORK.md +235 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/PLATFORM_COMPAT.md +161 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/RN_TEST_PATTERNS.md +413 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/SOURCE_PARSER.md +235 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/TEST_CONVENTIONS.md +245 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/TROUBLESHOOTING.md +282 -0
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/USAGE_GUIDE.md +251 -0
- package/vendor/Server/Skills/rnoh-cptf-api-test/SKILL.md +469 -0
- package/vendor/Server/Skills/rnoh-cptf-api-test/assets/CPTF_TEST_TEMPLATE.md +310 -0
- package/vendor/Server/Skills/rnoh-cptf-api-test/assets/DEMO_PAGE_TEMPLATE.md +303 -0
- package/vendor/Server/Skills/rnoh-cptf-api-test/references/CPTF_TEST_GENERATION_GUIDE.md +421 -0
- package/vendor/Server/Skills/rnoh-cptf-api-test/references/DEMO_GENERATION_GUIDE.md +358 -0
- package/vendor/Server/Skills/rnoh-cptf-api-test/references/QUALITY_CHECKLIST.md +114 -0
- package/vendor/Server/Skills/rnoh-cptf-api-test/references/SPEC_PARSING_GUIDE.md +274 -0
- package/vendor/Server/Skills/rnoh-cptf-api-test/scripts/validate-rnoh-cptf-api-test.sh +185 -0
- package/vendor/Server/Skills/rnoh-cptf-demo-test/SKILL.md +191 -0
- package/vendor/Server/Skills/rnoh-cptf-demo-test/assets/TEST_TEMPLATE.md +216 -0
- package/vendor/Server/Skills/rnoh-cptf-demo-test/references/CPTF_SETUP.md +107 -0
- package/vendor/Server/Skills/rnoh-cptf-demo-test/references/DEMO_ANALYSIS.md +120 -0
- package/vendor/Server/Skills/rnoh-cptf-demo-test/scripts/validate-rnoh-cptf-test.sh +108 -0
- package/vendor/Server/Skills/rnoh-cptf-test-run/SKILL.md +237 -0
- package/vendor/Server/Skills/rnoh-cptf-test-run/references/DEBUG_PLAYBOOK.md +261 -0
- package/vendor/Server/Skills/rnoh-cptf-test-run/scripts/validate-run-env.sh +112 -0
- package/vendor/Server/Skills/rnoh-lib-code-adapt/SKILL.md +498 -0
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/adapt-checklist.md +270 -0
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/api-migration-checklist.md +164 -0
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/common-compile-errors.md +556 -0
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/deveco-cli-tools.md +459 -0
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/edge-cases.md +65 -0
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/har-tgz-build.md +512 -0
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/version-compat-matrix.md +132 -0
- package/vendor/Server/Skills/rnoh-lib-code-adapt/scripts/auto-integrate.sh +424 -0
- package/vendor/Server/Skills/rnoh-lib-demo-coverage/SKILL.md +137 -0
- package/vendor/Server/Skills/rnoh-lib-demo-create/SKILL.md +306 -0
- package/vendor/Server/Skills/rnoh-lib-demo-create/assets/DEMO_PAGE_TEMPLATE.md +485 -0
- package/vendor/Server/Skills/rnoh-lib-demo-create/assets/INDEX_TEMPLATE.md +172 -0
- package/vendor/Server/Skills/rnoh-lib-demo-create/references/DEMO_CODE_RULES.md +422 -0
- package/vendor/Server/Skills/rnoh-lib-demo-create/references/QUALITY_CHECKLIST.md +95 -0
- package/vendor/Server/Skills/rnoh-lib-demo-create/references/SOURCE_EXPLORATION.md +169 -0
- package/vendor/Server/Skills/rnoh-lib-demo-doc/SKILL.md +554 -0
- package/vendor/Server/Skills/rnoh-lib-demo-doc/assets/DEMO_DOC_TEMPLATE.md +106 -0
- package/vendor/Server/Skills/rnoh-lib-demo-doc/references/COVERAGE_INCREMENTAL.md +216 -0
- package/vendor/Server/Skills/rnoh-lib-demo-doc/references/DEMO_DESIGN_RULES.md +413 -0
- package/vendor/Server/Skills/rnoh-lib-demo-doc/references/OUTPUT_FORMAT.md +269 -0
- package/vendor/Server/Skills/rnoh-lib-demo-doc/references/QUALITY_CHECKLIST.md +98 -0
- package/vendor/Server/Skills/rnoh-lib-func-test/SKILL.md +337 -0
- package/vendor/Server/Skills/rnoh-lib-rnt-search/SKILL.md +722 -0
- package/vendor/Server/Skills/rnoh-lib-rnt-search/assets/PORT_REPORT_TEMPLATE.md +219 -0
- package/vendor/Server/Skills/rnoh-lib-rnt-search/references/DEMO_PORTING_GUIDE.md +345 -0
- package/vendor/Server/Skills/rnoh-lib-rnt-search/references/PORT_VERIFICATION.md +269 -0
- package/vendor/Server/Skills/rnoh-lib-rnt-search/references/RNT_PROJECT_STRUCTURE.md +173 -0
- package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/analyze-demo-deps.cjs +267 -0
- package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/detect-rnoh-version.cjs +174 -0
- package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/find-rnt-demo.sh +111 -0
- package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/port-demo.sh +186 -0
- package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/read-lib-meta.cjs +150 -0
- package/vendor/Server/Skills/rnoh-lib-test-align/SKILL.md +296 -0
- package/vendor/Server/Skills/rnoh-lib-test-align/references/jest-troubleshooting.md +371 -0
- package/vendor/Server/Skills/rnoh-lib-test-align/references/port-test-demo-guide.md +212 -0
- package/vendor/Server/Skills/rnoh-lib-test-align/references/runtime-troubleshooting.md +345 -0
- package/vendor/Server/Skills/rnoh-lib-test-align/references/unit-test-template.md +223 -0
- package/vendor/Server/Skills/rnoh-lib-test-align/scripts/port-test-demo.sh +1053 -0
- package/vendor/Server/Skills/rnoh-lib-version-diff/SKILL.md +255 -0
- package/vendor/Server/Skills/rnoh-lib-version-diff/references/OHOS_ADAPTATION.md +77 -0
- package/vendor/Server/Skills/rnoh-lib-version-diff/references/OHOS_API_LOOKUP.md +224 -0
- package/vendor/Server/Skills/rnoh-lib-version-diff/references/script-reference.md +174 -0
- package/vendor/Server/Skills/rnoh-lib-version-diff/scripts/detect-upstream-version.js +967 -0
- package/vendor/Server/Skills/rnoh-lib-version-diff/scripts/generate-diff.js +1798 -0
- package/vendor/Server/Skills/rnoh-lib-version-diff/scripts/package.json +5 -0
- package/vendor/Server/Skills/rnoh-lib-version-diff/templates/report-template.md +137 -0
- package/vendor/Server/Skills/rnoh-lib-xts-coverage/SKILL.md +145 -0
- package/vendor/Server/Skills/skill-generator/SKILL.md +365 -0
- package/vendor/Server/Skills/skill-generator/assets/SKILL_TEMPLATE.md +183 -0
- package/vendor/Server/Skills/skill-generator/references/COMPLIANCE_CHECKLIST.md +82 -0
- package/vendor/Server/Skills/skill-generator/references/KB_QUERY_GUIDE.md +110 -0
- package/vendor/Server/Skills/skill-generator/references/MCP_TOOL_DISCOVERY.md +122 -0
- package/vendor/Server/Skills/skill-generator/references/SKILL_SPEC.md +121 -0
- package/vendor/Server/Skills/skill-generator/scripts/validate-skill.cjs +259 -0
- package/vendor/Server/Skills/task-analysis/SKILL.md +234 -0
- package/vendor/Server/Skills/task-analysis/assets/OUTPUT_EXAMPLES.md +160 -0
- package/vendor/Server/Skills/task-analysis/references/ACCEPTANCE_CRITERIA_GUIDE.md +190 -0
- package/vendor/Server/Skills/task-analysis/references/ANALYSIS_SCHEMA.md +224 -0
- package/vendor/Server/Skills/task-analysis/references/INTEGRATION_CONTEXT.md +162 -0
- package/vendor/Server/Skills/task-analysis/references/LESSONS_LEARNED.md +55 -0
- package/vendor/Server/Skills/task-analysis/references/REPLAN_CONTEXT_GUIDE.md +126 -0
- package/vendor/Server/Skills/task-analysis/scripts/validate-analysis-output.sh +256 -0
- package/vendor/Server/Skills/task-decomposition/SKILL.md +529 -0
- package/vendor/Server/Skills/task-decomposition/assets/OUTPUT_EXAMPLES.md +451 -0
- package/vendor/Server/Skills/task-decomposition/references/ACCEPTANCE_CRITERIA_GUIDE.md +179 -0
- package/vendor/Server/Skills/task-decomposition/references/DEPENDENCY_GRAPH_GUIDE.md +152 -0
- package/vendor/Server/Skills/task-decomposition/references/INTEGRATION_CONTEXT.md +175 -0
- package/vendor/Server/Skills/task-decomposition/references/REPLAN_CONTEXT_GUIDE.md +195 -0
- package/vendor/Server/Skills/task-decomposition/references/TASK_DECOMPOSITION_TEMPLATES.md +226 -0
- package/vendor/Server/Skills/task-decomposition/scripts/list-available-skills.cjs +263 -0
- package/vendor/Server/Skills/task-decomposition/scripts/skill-blacklist.json +29 -0
- package/vendor/Server/Skills/task-decomposition/scripts/validate-decomposition-output.cjs +376 -0
- package/vendor/Server/Skills/task-decomposition/scripts/validate-param-consistency.cjs +259 -0
- package/vendor/Server/Skills/task-decomposition/scripts/validate-specified-skills.cjs +216 -0
- package/vendor/Server/Skills/task-decomposition/scripts/validate-step-graph.cjs +425 -0
- package/vendor/Server/Skills/tpc-cpp-check/SKILL.md +427 -0
- package/vendor/Server/Skills/tpc-cpp-check/references/CHECKLIST.md +214 -0
- package/vendor/Server/Skills/tpc-cpp-check/references/HPKBUILD_GUIDE.md +235 -0
- package/vendor/Server/Skills/tpc-cpp-check/references/REPORT_TEMPLATE.md +250 -0
- package/vendor/Server/TestCheck/TestCheck.js +775 -0
- package/vendor/Server/TestCheck/index.js +11 -0
- package/vendor/Server/library/McpToolGuide.js +280 -0
- package/vendor/Server/library/StatsService.js +127 -0
- package/vendor/Server/library/cstTime.js +16 -0
- package/vendor/Server/package.json +17 -0
- package/vendor/VERSION +3 -0
- package/workflows/pr-check.mjs +106 -0
package/lib/runner.js
ADDED
|
@@ -0,0 +1,979 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* runner.js —— 核心引擎装配与执行
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* - 参照 Server/Routes/server.js 组装共享依赖(不启动 HTTP)
|
|
6
|
+
* - 提供 run / submit / abort / wait / progress / result / list 的执行能力
|
|
7
|
+
* - 注入自定义 flexRunnerFactory,使每个 FlexRunner 复用同一 CLIController 与
|
|
8
|
+
* 同一存储门面(确保 Session 存档写入用户数据目录,而非 vendor/db)
|
|
9
|
+
*
|
|
10
|
+
* 依赖注入链(对照 server.js):
|
|
11
|
+
* CLIController ─┐
|
|
12
|
+
* createStorage ─┼→ OrchestratorController →(flexRunnerFactory)→ FlexRunner(cli+storage)
|
|
13
|
+
* BrainController ─(Brain{cli})→ SkillExecutor{cli}
|
|
14
|
+
* TestCheck{storage}
|
|
15
|
+
* LoopEngine{brainController, orchestratorController, testCheck, storage}
|
|
16
|
+
*
|
|
17
|
+
* 数据目录(A3):createStorage({ rootDir }) 注入用户隔离目录。
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
import fs from 'node:fs';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
|
|
24
|
+
// ─── vendor 路径解析 ─────────────────────────────────────────────────────────
|
|
25
|
+
// 优先用 vendor/Server 下的副本(发布态);开发期允许回退到仓库 Server/ 源码。
|
|
26
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
27
|
+
export const CLI_ROOT = path.resolve(moduleDir, '..');
|
|
28
|
+
|
|
29
|
+
let _serverModuleRoot = null;
|
|
30
|
+
function resolveVendorServer(cliRoot) {
|
|
31
|
+
if (_serverModuleRoot) return _serverModuleRoot;
|
|
32
|
+
|
|
33
|
+
const vendorServer = path.join(cliRoot, 'vendor', 'Server');
|
|
34
|
+
if (fs.existsSync(vendorServer)) {
|
|
35
|
+
_serverModuleRoot = vendorServer;
|
|
36
|
+
return vendorServer;
|
|
37
|
+
}
|
|
38
|
+
// 回退:直接引用仓库 Server/(开发期 npm link 场景)
|
|
39
|
+
const repoServer = path.resolve(cliRoot, '..', 'Server');
|
|
40
|
+
if (fs.existsSync(repoServer)) {
|
|
41
|
+
_serverModuleRoot = repoServer;
|
|
42
|
+
return repoServer;
|
|
43
|
+
}
|
|
44
|
+
throw new Error(
|
|
45
|
+
`无法定位核心引擎目录:期望 cli/vendor/Server 或仓库 Server/。` +
|
|
46
|
+
`请先运行 npm run prepack(或 clone 仓库到 cli/ 的上一级)`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 动态导入核心引擎模块
|
|
51
|
+
let _modules = null;
|
|
52
|
+
async function _loadCore(cliRoot) {
|
|
53
|
+
if (_modules) return _modules;
|
|
54
|
+
const serverRoot = resolveVendorServer(cliRoot);
|
|
55
|
+
|
|
56
|
+
// 使用绝对 file URL 导入,避免 Windows 下路径格式问题
|
|
57
|
+
async function imp(p) {
|
|
58
|
+
const u = new URL(`file://${path.join(serverRoot, p).replace(/\\/g, '/')}`);
|
|
59
|
+
return import(u.href);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const [dbUse, loopEngine, brainMod, orchestratorMod, testCheckMod, cliMod, flexRunnerMod, knowledgeMod] = await Promise.all([
|
|
63
|
+
imp('DbUse/index.js'),
|
|
64
|
+
imp('LoopEngine/index.js'),
|
|
65
|
+
imp('Brain/index.js'),
|
|
66
|
+
imp('Orchestrator/index.js'),
|
|
67
|
+
imp('TestCheck/index.js'),
|
|
68
|
+
imp('CLI/cli.js'),
|
|
69
|
+
imp('FlexRunner/index.js'),
|
|
70
|
+
imp('Knowledge/index.js'),
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
_modules = {
|
|
74
|
+
createStorage: dbUse.createStorage,
|
|
75
|
+
LoopEngine: loopEngine.LoopEngine,
|
|
76
|
+
LoopStatus: loopEngine.LoopStatus,
|
|
77
|
+
Brain: brainMod.Brain,
|
|
78
|
+
Orchestrator: orchestratorMod.Orchestrator,
|
|
79
|
+
OrchestratorStatus: orchestratorMod.OrchestratorStatus,
|
|
80
|
+
TestCheck: testCheckMod.TestCheck,
|
|
81
|
+
CheckStatus: testCheckMod.CheckStatus,
|
|
82
|
+
CLIController: cliMod.CLIController,
|
|
83
|
+
FlexRunner: flexRunnerMod.FlexRunner || flexRunnerMod.default,
|
|
84
|
+
KnowledgeManager: knowledgeMod.KnowledgeManager || knowledgeMod.default,
|
|
85
|
+
serverRoot,
|
|
86
|
+
};
|
|
87
|
+
return _modules;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 运行时上下文:一次 CLI 命令调用期间持有的引擎实例。
|
|
92
|
+
*
|
|
93
|
+
* 同一个 taskId 的 run/wait/abort/progress 应复用同一批控制器实例,
|
|
94
|
+
* 避免重复创建 CLIController(opencode 连接)与 storage(SQLite 连接)。
|
|
95
|
+
*/
|
|
96
|
+
class RunContext {
|
|
97
|
+
/**
|
|
98
|
+
* @param {object} opts
|
|
99
|
+
* @param {string} opts.projectRoot
|
|
100
|
+
* @param {string} opts.dataDir
|
|
101
|
+
* @param {string} opts.skillDir
|
|
102
|
+
* @param {string} opts.cliType
|
|
103
|
+
* @param {boolean} opts.verbose
|
|
104
|
+
*/
|
|
105
|
+
constructor(opts = {}) {
|
|
106
|
+
this.projectRoot = opts.projectRoot || process.cwd();
|
|
107
|
+
this.dataDir = opts.dataDir || '';
|
|
108
|
+
this.skillDir = opts.skillDir || '';
|
|
109
|
+
this.cliType = opts.cliType || 'opencode';
|
|
110
|
+
this.verbose = !!opts.verbose;
|
|
111
|
+
this._ready = false;
|
|
112
|
+
this.cliRoot = opts.cliRoot || CLI_ROOT;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** 惰性初始化并返回核心模块引用 */
|
|
116
|
+
async _init() {
|
|
117
|
+
if (this._ready) return;
|
|
118
|
+
const core = await _loadCore(this.cliRoot);
|
|
119
|
+
this.core = core;
|
|
120
|
+
|
|
121
|
+
// ── storage:注入用户数据目录 ──
|
|
122
|
+
this.storage = core.createStorage({ rootDir: this.dataDir });
|
|
123
|
+
|
|
124
|
+
// ── CLIController:共享实例,archive 指向本 storage 的 SessionStore ──
|
|
125
|
+
this.cli = new core.CLIController(this.cliType, {
|
|
126
|
+
archive: this.storage.messageArchive(),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// ── controllers:与 server.js 对齐 ──
|
|
130
|
+
this.orchestratorController = new (await this._importOrchestratorController())({
|
|
131
|
+
storage: this.storage,
|
|
132
|
+
flexRunnerFactory: null,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// 注入共享 cli:Brain/TestCheck 若不注入,会惰性 new CLIController('opencode')
|
|
136
|
+
// 其默认 MessageArchive 基于 vendor/Server 相对路径上溯 → 落到 cli/db/Session(数据错位)。
|
|
137
|
+
// 注入后会话归档统一写用户数据目录。
|
|
138
|
+
this.brainController = new (await this._importBrainController())({
|
|
139
|
+
storage: this.storage,
|
|
140
|
+
skillDirectory: this.skillDir,
|
|
141
|
+
orchestratorController: this.orchestratorController,
|
|
142
|
+
cli: this.cli,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
this.testCheck = new core.TestCheck({
|
|
146
|
+
storage: this.storage,
|
|
147
|
+
skillDirectory: this.skillDir,
|
|
148
|
+
cli: this.cli, // 注入共享 cli,避免审核会话落到 cli/db/Session
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
this.loopEngineController = new (await this._importLoopEngineController())({
|
|
152
|
+
storage: this.storage,
|
|
153
|
+
brainController: this.brainController,
|
|
154
|
+
orchestratorController: this.orchestratorController,
|
|
155
|
+
testCheck: this.testCheck,
|
|
156
|
+
skillDirectory: this.skillDir,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// ── 注入自定义 flexRunnerFactory,让每个 FlexRunner 复用 cli/storage ──
|
|
160
|
+
// 复刻 Orchestrator._createFlexRunner 的 initContext 参数并注入 cli/storage,
|
|
161
|
+
// 避免 OpenCodeCLI 内部 new MessageArchive() 落到 vendor/db。
|
|
162
|
+
// 注意:此处必须用普通 function(非箭头),因为 Orchestrator 以
|
|
163
|
+
// this.flexRunnerFactory(node, inputReport) 调用,this 即 Orchestrator 实例,
|
|
164
|
+
// 可访问 _taskId / _loopCount。
|
|
165
|
+
this.orchestratorController.flexRunnerFactory = createOrchestratorFlexRunnerFactory(this);
|
|
166
|
+
this._ready = true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** 动态导入 OrchestratorController(在 Routes 下,单独 import) */
|
|
170
|
+
async _importOrchestratorController() {
|
|
171
|
+
const serverRoot = resolveVendorServer(this.cliRoot);
|
|
172
|
+
const url = `file://${path.join(serverRoot, 'Routes', 'controllers', 'OrchestratorController.js').replace(/\\/g, '/')}`;
|
|
173
|
+
const mod = await import(url);
|
|
174
|
+
return mod.default;
|
|
175
|
+
}
|
|
176
|
+
async _importBrainController() {
|
|
177
|
+
const serverRoot = resolveVendorServer(this.cliRoot);
|
|
178
|
+
const url = `file://${path.join(serverRoot, 'Routes', 'controllers', 'BrainController.js').replace(/\\/g, '/')}`;
|
|
179
|
+
const mod = await import(url);
|
|
180
|
+
return mod.default;
|
|
181
|
+
}
|
|
182
|
+
async _importLoopEngineController() {
|
|
183
|
+
const serverRoot = resolveVendorServer(this.cliRoot);
|
|
184
|
+
const url = `file://${path.join(serverRoot, 'Routes', 'controllers', 'LoopEngineController.js').replace(/\\/g, '/')}`;
|
|
185
|
+
const mod = await import(url);
|
|
186
|
+
return mod.default;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* 创建 LoopEngine 实例(组装完整闭环)。
|
|
191
|
+
* @returns {import('../vendor/Server/LoopEngine/index.js').LoopEngine}
|
|
192
|
+
*/
|
|
193
|
+
createLoopEngine() {
|
|
194
|
+
return new this.core.LoopEngine({
|
|
195
|
+
storage: this.storage,
|
|
196
|
+
brainController: this.brainController,
|
|
197
|
+
orchestratorController: this.orchestratorController,
|
|
198
|
+
testCheck: this.testCheck,
|
|
199
|
+
skillDirectory: this.skillDir,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* 关闭所有存储连接(SQLite 等)。
|
|
205
|
+
*/
|
|
206
|
+
async close() {
|
|
207
|
+
if (this.storage && typeof this.storage.close === 'function') {
|
|
208
|
+
await this.storage.close();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 创建一个 RunContext 实例(便捷工厂)。
|
|
215
|
+
* @param {object} opts
|
|
216
|
+
* @returns {RunContext}
|
|
217
|
+
*/
|
|
218
|
+
export function createRunContext(opts = {}) {
|
|
219
|
+
const ctx = new RunContext(opts);
|
|
220
|
+
return ctx;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* 提交任务并启动大循环。
|
|
225
|
+
*
|
|
226
|
+
* 与 HTTP 模式不同,这里直接调 LoopEngine.startLoop(),同步等待大循环结束
|
|
227
|
+
* (因为 CLI 进程不能像 Server 一样 fire-and-forget 后退出)。
|
|
228
|
+
*
|
|
229
|
+
* @param {object} params
|
|
230
|
+
* @param {RunContext} params.ctx
|
|
231
|
+
* @param {string} params.taskDescription
|
|
232
|
+
* @param {string} [params.taskId]
|
|
233
|
+
* @param {number} [params.maxLoops]
|
|
234
|
+
* @param {string} [params.acceptanceCriteria]
|
|
235
|
+
* @param {function} [params.onProgress] - 进度回调(每轮轮询触发)
|
|
236
|
+
* @returns {Promise<object>} LoopResult
|
|
237
|
+
*/
|
|
238
|
+
export async function submitAndRun(params = {}) {
|
|
239
|
+
const { ctx, taskDescription } = params;
|
|
240
|
+
await ctx._init();
|
|
241
|
+
|
|
242
|
+
if (!taskDescription) throw new Error('taskDescription 为必填项');
|
|
243
|
+
|
|
244
|
+
const engine = ctx.createLoopEngine();
|
|
245
|
+
|
|
246
|
+
const result = await engine.startLoop({
|
|
247
|
+
taskDescription,
|
|
248
|
+
taskId: params.taskId,
|
|
249
|
+
maxLoops: params.maxLoops || 3,
|
|
250
|
+
acceptanceCriteria: params.acceptanceCriteria,
|
|
251
|
+
skillDirectory: ctx.skillDir,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// 清理:终止后释放 orchestrator 重型引用(与 controller .finally 对齐)
|
|
255
|
+
try {
|
|
256
|
+
ctx.orchestratorController.disposeOrchestrator(result.taskId);
|
|
257
|
+
} catch { /* 忽略 */ }
|
|
258
|
+
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* 清理已存在的同 taskId 旧实例(中断恢复语义 v1)。
|
|
264
|
+
* 归档旧 loop.json 后允许重建新任务。
|
|
265
|
+
*/
|
|
266
|
+
export async function archiveTaskIfExists(ctx, taskId) {
|
|
267
|
+
await ctx._init();
|
|
268
|
+
const taskDir = path.join(ctx.dataDir, 'task', taskId);
|
|
269
|
+
const loopFile = path.join(taskDir, 'loop.json');
|
|
270
|
+
if (fs.existsSync(loopFile)) {
|
|
271
|
+
const archiveFile = `${loopFile}.archived_${Date.now()}`;
|
|
272
|
+
fs.renameSync(loopFile, archiveFile);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* 查询任务进度(磁盘直读 loop.json,不依赖内存实例)。
|
|
278
|
+
* @returns {Promise<object|null>}
|
|
279
|
+
*/
|
|
280
|
+
export async function readTaskProgress(ctx, taskId) {
|
|
281
|
+
await ctx._init();
|
|
282
|
+
try {
|
|
283
|
+
const json = ctx.storage.json('task');
|
|
284
|
+
const state = await json.read(`${taskId}/loop`);
|
|
285
|
+
return state || null;
|
|
286
|
+
} catch {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* 中止任务。
|
|
293
|
+
*
|
|
294
|
+
* 由于嵌入式模式任务在 CLI 进程内执行,abort 时先从内存恢复 LoopEngine 实例
|
|
295
|
+
* 调用 abortLoop,再 fallback 修改磁盘状态(若任务已不在内存)。
|
|
296
|
+
*
|
|
297
|
+
* @param {RunContext} ctx
|
|
298
|
+
* @param {string} taskId
|
|
299
|
+
* @returns {Promise<boolean>}
|
|
300
|
+
*/
|
|
301
|
+
export async function abortTask(ctx, taskId) {
|
|
302
|
+
// 确保 storage/controller 已初始化(abort 命令的 ctx 可能是全新的)
|
|
303
|
+
await ctx._init();
|
|
304
|
+
|
|
305
|
+
// 1. 尝试内存实例 abort(嵌入式下任务在进程内)
|
|
306
|
+
if (ctx.loopEngineController) {
|
|
307
|
+
try {
|
|
308
|
+
const engine = ctx.loopEngineController._getEngine ? ctx.loopEngineController._getEngine(taskId) : null;
|
|
309
|
+
if (engine) {
|
|
310
|
+
const ok = await engine.abortLoop(taskId);
|
|
311
|
+
if (ok) {
|
|
312
|
+
try {
|
|
313
|
+
ctx.orchestratorController.disposeOrchestrator(taskId);
|
|
314
|
+
} catch { /* 忽略 */ }
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
} catch { /* 未找到,继续 fallback */ }
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// 2. Fallback:修改磁盘状态标记为 aborted
|
|
322
|
+
const state = readTaskProgressSync(ctx, taskId);
|
|
323
|
+
if (!state) {
|
|
324
|
+
// 未找到任务
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
if (TERMINAL_STATES.includes(state.status)) {
|
|
328
|
+
return false; // 已终态,无需中止
|
|
329
|
+
}
|
|
330
|
+
try {
|
|
331
|
+
const json = ctx.storage.json('task');
|
|
332
|
+
state.status = 'aborted';
|
|
333
|
+
state.aborted = true;
|
|
334
|
+
state.endTime = new Date().toISOString().slice(0, 19).replace('T', ' ');
|
|
335
|
+
state.error = '由 CLI abort 命令终止';
|
|
336
|
+
await json.write(`${taskId}/loop`, state);
|
|
337
|
+
return true;
|
|
338
|
+
} catch (err) {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 终态集合(避免引入循环依赖)
|
|
344
|
+
const TERMINAL_STATES = ['passed', 'failed', 'aborted', 'error'];
|
|
345
|
+
|
|
346
|
+
/** 同步读取 loop.json(供 abortTask fallback) */
|
|
347
|
+
function readTaskProgressSync(ctx, taskId) {
|
|
348
|
+
try {
|
|
349
|
+
const taskDir = path.join(ctx.dataDir, 'task', taskId);
|
|
350
|
+
const loopFile = path.join(taskDir, 'loop.json');
|
|
351
|
+
if (fs.existsSync(loopFile)) {
|
|
352
|
+
return JSON.parse(fs.readFileSync(loopFile, 'utf8'));
|
|
353
|
+
}
|
|
354
|
+
const orchFile = path.join(taskDir, 'orchestration.json');
|
|
355
|
+
if (fs.existsSync(orchFile)) {
|
|
356
|
+
return JSON.parse(fs.readFileSync(orchFile, 'utf8'));
|
|
357
|
+
}
|
|
358
|
+
return null;
|
|
359
|
+
} catch {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* 列出所有任务(扫描 loop.json / orchestration.json)。
|
|
366
|
+
* @returns {Promise<object[]>}
|
|
367
|
+
*/
|
|
368
|
+
export async function listTasks(ctx, opts = {}) {
|
|
369
|
+
await ctx._init();
|
|
370
|
+
const taskRoot = path.join(ctx.dataDir, 'task');
|
|
371
|
+
if (!fs.existsSync(taskRoot)) return [];
|
|
372
|
+
|
|
373
|
+
const entries = fs.readdirSync(taskRoot, { withFileTypes: true });
|
|
374
|
+
const tasks = [];
|
|
375
|
+
|
|
376
|
+
for (const entry of entries) {
|
|
377
|
+
if (!entry.isDirectory()) continue;
|
|
378
|
+
const taskId = entry.name;
|
|
379
|
+
// 优先 loop.json,其次 orchestration.json
|
|
380
|
+
let data = null;
|
|
381
|
+
try {
|
|
382
|
+
data = JSON.parse(fs.readFileSync(path.join(taskRoot, taskId, 'loop.json'), 'utf8'));
|
|
383
|
+
} catch {
|
|
384
|
+
try {
|
|
385
|
+
data = JSON.parse(fs.readFileSync(path.join(taskRoot, taskId, 'orchestration.json'), 'utf8'));
|
|
386
|
+
} catch { /* 跳过损坏任务 */ }
|
|
387
|
+
}
|
|
388
|
+
if (!data) continue;
|
|
389
|
+
|
|
390
|
+
tasks.push({
|
|
391
|
+
taskId,
|
|
392
|
+
status: data.status || 'idle',
|
|
393
|
+
currentLoop: data.currentLoop ?? data.loopCount ?? 0,
|
|
394
|
+
maxLoops: data.maxLoops ?? 3,
|
|
395
|
+
startTime: data.startTime || null,
|
|
396
|
+
endTime: data.endTime || null,
|
|
397
|
+
passed: data.status === 'passed',
|
|
398
|
+
error: data.error || null,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// 按开始时间降序
|
|
403
|
+
tasks.sort((a, b) => String(b.startTime || '').localeCompare(String(a.startTime || '')));
|
|
404
|
+
return tasks;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// ═══ 单步执行(FlexRunner 直连,不经过 Brain/Orchestrator/LoopEngine) ═══════
|
|
408
|
+
|
|
409
|
+
let _activeStandaloneRunner = null;
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* 创建"独立单步" FlexRunner 实例并注入共享依赖。
|
|
413
|
+
*
|
|
414
|
+
* 复刻 RunContext._init() 中 flexRunnerFactory 的注入逻辑(cli/storage/knowledgeManager),
|
|
415
|
+
* 避免 opencode 会话归档/知识沉淀落到 vendor 相对路径。与编排版差异:
|
|
416
|
+
* - 参数从 CLI 显式传入,而非 Orchestrator node 对象
|
|
417
|
+
* - 不注入 onSessionCreated(无 SSE),sessionId 由返回结果带出
|
|
418
|
+
*
|
|
419
|
+
* @param {RunContext} ctx
|
|
420
|
+
* @param {object} params
|
|
421
|
+
* @param {string} params.taskId
|
|
422
|
+
* @param {number} params.stepId
|
|
423
|
+
* @param {string} params.taskDescription
|
|
424
|
+
* @param {string} [params.skillDirectory]
|
|
425
|
+
* @param {string} [params.specifiedSkill] - 指定的 SKILL name 或目录名(跳过 SkillSelector 匹配)
|
|
426
|
+
* @param {string} [params.taskDir]
|
|
427
|
+
* @param {string} [params.inputReport]
|
|
428
|
+
* @param {number} [params.maxRetries]
|
|
429
|
+
* @param {number} [params.bigLoopIndex]
|
|
430
|
+
* @returns {Promise<import('../vendor/Server/FlexRunner/index.js').FlexRunner>}
|
|
431
|
+
*/
|
|
432
|
+
export async function createStandaloneFlexRunner(ctx, params) {
|
|
433
|
+
const FlexRunnerCtor = ctx.core.FlexRunner;
|
|
434
|
+
const runner = new FlexRunnerCtor();
|
|
435
|
+
|
|
436
|
+
// 知识沉淀:注入指向正确数据目录的 KnowledgeManager
|
|
437
|
+
let knowledgeManager = null;
|
|
438
|
+
const KnowledgeManagerCtor = ctx.core.KnowledgeManager || null;
|
|
439
|
+
if (KnowledgeManagerCtor && ctx.storage && typeof ctx.storage.json === 'function') {
|
|
440
|
+
try {
|
|
441
|
+
const km = new KnowledgeManagerCtor({ jsonAdapter: ctx.storage.json('Knowledge') });
|
|
442
|
+
await km.init();
|
|
443
|
+
knowledgeManager = km;
|
|
444
|
+
} catch { /* 注入失败则跳过(内部会惰性加载) */ }
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
await runner.initContext({
|
|
448
|
+
taskId: params.taskId,
|
|
449
|
+
stepId: Number(params.stepId) || 1,
|
|
450
|
+
dependId: 0,
|
|
451
|
+
nextStepId: 0,
|
|
452
|
+
failStepId: 0,
|
|
453
|
+
taskDescription: params.taskDescription,
|
|
454
|
+
skillDirectory: params.skillDirectory || ctx.skillDir || '',
|
|
455
|
+
specifiedSkill: params.specifiedSkill || '',
|
|
456
|
+
taskDir: params.taskDir,
|
|
457
|
+
inputReport: params.inputReport || '',
|
|
458
|
+
maxRetries: params.maxRetries ?? 3,
|
|
459
|
+
bigLoopIndex: params.bigLoopIndex || 0,
|
|
460
|
+
cli: ctx.cli,
|
|
461
|
+
storage: ctx.storage,
|
|
462
|
+
knowledgeManager,
|
|
463
|
+
});
|
|
464
|
+
return runner;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* 运行单个步骤(阻塞直到成功或重试耗尽)。
|
|
469
|
+
*
|
|
470
|
+
* 流程:createStandaloneFlexRunner → while(canRetry()) executeStart()。
|
|
471
|
+
* 结束后写精简 loop.json(isSingleExecution:true),供 3rdloop list/progress/result 可见。
|
|
472
|
+
*
|
|
473
|
+
* @param {RunContext} ctx
|
|
474
|
+
* @param {object} params
|
|
475
|
+
* @param {string} params.taskId
|
|
476
|
+
* @param {number} params.stepId
|
|
477
|
+
* @param {string} params.taskDescription
|
|
478
|
+
* @param {string} [params.skillDirectory]
|
|
479
|
+
* @param {string} [params.specifiedSkill] - 指定的 SKILL name 或目录名(跳过 SkillSelector 匹配)
|
|
480
|
+
* @param {string} [params.taskDir]
|
|
481
|
+
* @param {string} [params.inputReport]
|
|
482
|
+
* @param {number} [params.maxRetries]
|
|
483
|
+
* @param {number} [params.bigLoopIndex]
|
|
484
|
+
* @returns {Promise<{ taskId: string, stepId: number, success: boolean, resultPath: string|null, nextStepId: number, error: string|null, executeStep: number }>}
|
|
485
|
+
*/
|
|
486
|
+
export async function runStandaloneStep(ctx, params) {
|
|
487
|
+
await ctx._init();
|
|
488
|
+
|
|
489
|
+
if (!params.taskDescription) throw new Error('taskDescription 为必填项');
|
|
490
|
+
if (!params.taskId) throw new Error('taskId 为必填项');
|
|
491
|
+
|
|
492
|
+
// 保证 taskDir 存在(opencode session 需要工作目录)
|
|
493
|
+
const taskId = params.taskId;
|
|
494
|
+
const taskDir = params.taskDir || path.join(ctx.dataDir, 'task', taskId);
|
|
495
|
+
fs.mkdirSync(taskDir, { recursive: true });
|
|
496
|
+
params = { ...params, taskDir };
|
|
497
|
+
|
|
498
|
+
const startTime = _nowLocal();
|
|
499
|
+
|
|
500
|
+
// 写初始 loop.json(executing,使任务立即可见)
|
|
501
|
+
await _writeStandaloneLoopJson(ctx, {
|
|
502
|
+
taskId,
|
|
503
|
+
taskDescription: params.taskDescription,
|
|
504
|
+
taskDir,
|
|
505
|
+
skillDirectory: params.skillDirectory || ctx.skillDir || '',
|
|
506
|
+
status: 'executing',
|
|
507
|
+
startTime,
|
|
508
|
+
endTime: null,
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
const runner = await createStandaloneFlexRunner(ctx, params);
|
|
512
|
+
_activeStandaloneRunner = runner;
|
|
513
|
+
|
|
514
|
+
try {
|
|
515
|
+
let result = null;
|
|
516
|
+
let lastError = null;
|
|
517
|
+
while (runner.canRetry()) {
|
|
518
|
+
try {
|
|
519
|
+
result = await runner.executeStart();
|
|
520
|
+
if (result.success) break;
|
|
521
|
+
lastError = null;
|
|
522
|
+
} catch (err) {
|
|
523
|
+
lastError = err.message;
|
|
524
|
+
}
|
|
525
|
+
if (result?.success) break;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const success = !!(result && result.success);
|
|
529
|
+
const finalState = {
|
|
530
|
+
taskId,
|
|
531
|
+
taskDescription: params.taskDescription,
|
|
532
|
+
taskDir,
|
|
533
|
+
skillDirectory: params.skillDirectory || ctx.skillDir || '',
|
|
534
|
+
status: success ? 'passed' : 'failed',
|
|
535
|
+
startTime,
|
|
536
|
+
endTime: _nowLocal(),
|
|
537
|
+
};
|
|
538
|
+
await _writeStandaloneLoopJson(ctx, finalState);
|
|
539
|
+
|
|
540
|
+
return {
|
|
541
|
+
taskId,
|
|
542
|
+
stepId: Number(params.stepId) || 1,
|
|
543
|
+
success,
|
|
544
|
+
resultPath: result?.resultPath || null,
|
|
545
|
+
nextStepId: result?.nextStepId || 0,
|
|
546
|
+
error: lastError || (success ? null : '执行失败,重试耗尽'),
|
|
547
|
+
executeStep: runner.retryTimes ?? 0,
|
|
548
|
+
};
|
|
549
|
+
} finally {
|
|
550
|
+
_activeStandaloneRunner = null;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* 中止独立单步执行(由信号处理调用)。
|
|
556
|
+
* @param {RunContext} ctx
|
|
557
|
+
* @param {string} taskId
|
|
558
|
+
* @param {number} [stepId]
|
|
559
|
+
* @returns {Promise<boolean>}
|
|
560
|
+
*/
|
|
561
|
+
export async function abortStandaloneStep(ctx, taskId, stepId = 1) {
|
|
562
|
+
if (_activeStandaloneRunner) {
|
|
563
|
+
try {
|
|
564
|
+
await _activeStandaloneRunner.controlExecution('abort');
|
|
565
|
+
} catch { /* 忽略 */ }
|
|
566
|
+
return true;
|
|
567
|
+
}
|
|
568
|
+
// Fallback:磁盘标记 aborted
|
|
569
|
+
try {
|
|
570
|
+
const taskDir = path.join(ctx.dataDir, 'task', taskId);
|
|
571
|
+
const loopFile = path.join(taskDir, 'loop.json');
|
|
572
|
+
if (fs.existsSync(loopFile)) {
|
|
573
|
+
const state = JSON.parse(fs.readFileSync(loopFile, 'utf8'));
|
|
574
|
+
state.status = 'aborted';
|
|
575
|
+
state.aborted = true;
|
|
576
|
+
state.endTime = _nowLocal();
|
|
577
|
+
state.error = '由 CLI abort 命令终止';
|
|
578
|
+
await ctx.storage.json('task').write(`${taskId}/loop`, state);
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
581
|
+
} catch { /* 忽略 */ }
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/** 写精简版 loop.json(单步执行任务,格式与 FlexRunnerController._writeSingleLoopJson 对齐)。 */
|
|
586
|
+
async function _writeStandaloneLoopJson(ctx, { taskId, taskDescription, taskDir, skillDirectory, status, startTime, endTime, error = null }) {
|
|
587
|
+
try {
|
|
588
|
+
// 映射 loop 状态到 orchestrator 状态(用于前端 rounds 渲染)
|
|
589
|
+
let orchStatus;
|
|
590
|
+
if (status === 'executing') orchStatus = 'running';
|
|
591
|
+
else if (status === 'passed') orchStatus = 'completed';
|
|
592
|
+
else if (status === 'aborted') orchStatus = 'aborted';
|
|
593
|
+
else orchStatus = 'failed';
|
|
594
|
+
|
|
595
|
+
const state = {
|
|
596
|
+
taskId,
|
|
597
|
+
taskDescription,
|
|
598
|
+
userAcceptanceCriteria: '',
|
|
599
|
+
taskDir,
|
|
600
|
+
skillDirectory,
|
|
601
|
+
maxLoops: 1,
|
|
602
|
+
currentLoop: 1,
|
|
603
|
+
status,
|
|
604
|
+
startTime: startTime || _nowLocal(),
|
|
605
|
+
endTime,
|
|
606
|
+
error,
|
|
607
|
+
aborted: status === 'aborted',
|
|
608
|
+
isSingleExecution: true,
|
|
609
|
+
rounds: [{
|
|
610
|
+
loop: 0,
|
|
611
|
+
startTime: startTime || _nowLocal(),
|
|
612
|
+
endTime,
|
|
613
|
+
passed: status === 'passed',
|
|
614
|
+
error,
|
|
615
|
+
planningIsReplan: false,
|
|
616
|
+
planningStepCount: 1,
|
|
617
|
+
orchestratorStatus: orchStatus,
|
|
618
|
+
}],
|
|
619
|
+
persistedAt: _nowLocal(),
|
|
620
|
+
};
|
|
621
|
+
await ctx.storage.json('task').write(`${taskId}/loop`, state);
|
|
622
|
+
} catch { /* 写 loop.json 失败不影响主流程 */ }
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/** 本地时间字符串(+08:00 CST,与 nowCST() 对齐的简化实现)。 */
|
|
626
|
+
function _nowLocal() {
|
|
627
|
+
const d = new Date();
|
|
628
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
629
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}+08:00`;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// ═══ 任务注册表(SQLite,db/TaskRegistry/registry.db) ═══
|
|
633
|
+
// 与 OrchestratorController._registerTask / _patchRegistryFinalState 语义对齐:
|
|
634
|
+
// 前端历史列表(如 PR 检视页 taskIdPrefix=codecheck_)从注册表分页查询,
|
|
635
|
+
// CLI 提交的编排任务若不入表,前端将看不到。写入失败只警告、不阻断主流程。
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* 注册任务摘要到注册表(对齐 OrchestratorController._registerTask)。
|
|
639
|
+
* @param {import('./runner.js').RunContext} ctx
|
|
640
|
+
* @param {object} entry - { taskId, taskType, status, title, description, createdAt, metadata }
|
|
641
|
+
* @private
|
|
642
|
+
*/
|
|
643
|
+
async function _registryUpsert(ctx, entry) {
|
|
644
|
+
try {
|
|
645
|
+
const registry = ctx.storage.taskRegistryStore();
|
|
646
|
+
if (!registry) return;
|
|
647
|
+
await registry.upsert(entry);
|
|
648
|
+
} catch (err) {
|
|
649
|
+
console.warn(`[runner] 注册任务摘要失败: ${err.message}`);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* 任务终态时回写注册表 status + 结构化指标(对齐 _patchRegistryFinalState)。
|
|
655
|
+
* 多步骤时合并各步骤 metrics(后完成的覆盖同名字段)。
|
|
656
|
+
* @param {import('./runner.js').RunContext} ctx
|
|
657
|
+
* @param {string} taskId
|
|
658
|
+
* @param {object} progress - orch.getProgress() 返回的快照
|
|
659
|
+
* @private
|
|
660
|
+
*/
|
|
661
|
+
async function _registryPatchFinalState(ctx, taskId, progress) {
|
|
662
|
+
try {
|
|
663
|
+
const registry = ctx.storage.taskRegistryStore();
|
|
664
|
+
if (!registry) return;
|
|
665
|
+
|
|
666
|
+
let metrics = null;
|
|
667
|
+
for (const s of (progress.steps || [])) {
|
|
668
|
+
if (s.metrics && typeof s.metrics === 'object') {
|
|
669
|
+
metrics = { ...(metrics || {}), ...s.metrics };
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
const patch = { status: progress.status || 'completed' };
|
|
674
|
+
if (metrics) {
|
|
675
|
+
const existing = await registry.get(taskId);
|
|
676
|
+
const existingMeta = existing && existing.metadata && typeof existing.metadata === 'object'
|
|
677
|
+
? existing.metadata
|
|
678
|
+
: {};
|
|
679
|
+
patch.metadata = { ...existingMeta, ...metrics };
|
|
680
|
+
}
|
|
681
|
+
await registry.patch(taskId, patch);
|
|
682
|
+
} catch (err) {
|
|
683
|
+
console.warn(`[runner] 回写编排终态注册表失败: ${err.message}`);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// ═══ 编排(Orchestrator 多步骤依赖,对应 POST /api/orchestrator/load|start) ═══
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* 创建编排版 flexRunnerFactory(与 RunContext._init 中注入的完全一致)。
|
|
691
|
+
*
|
|
692
|
+
* 提取为独立函数供两类使用方复用:
|
|
693
|
+
* - RunContext._init 注入 orchestratorController(大循环 LoopEngine 编排)
|
|
694
|
+
* - 3rdloop orch run/start 创建独立 Orchestrator 实例
|
|
695
|
+
*
|
|
696
|
+
* 注入共享 cli/storage/knowledgeManager,避免 FlexRunner 内部默认实例
|
|
697
|
+
* 落到 vendor/Server 相对路径(cli/db 数据错位教训)。
|
|
698
|
+
*
|
|
699
|
+
* @param {RunContext} ctx
|
|
700
|
+
* @returns {Function} async (node, inputReport) => FlexRunner
|
|
701
|
+
*/
|
|
702
|
+
export function createOrchestratorFlexRunnerFactory(ctx) {
|
|
703
|
+
const sharedCli = ctx.cli;
|
|
704
|
+
const sharedStorage = ctx.storage;
|
|
705
|
+
const FlexRunnerCtor = ctx.core.FlexRunner;
|
|
706
|
+
const KnowledgeManagerCtor = ctx.core.KnowledgeManager || null;
|
|
707
|
+
|
|
708
|
+
// 必须用普通 function(非箭头):Orchestrator 以 this.flexRunnerFactory(node, inputReport)
|
|
709
|
+
// 调用,this 即 Orchestrator 实例,可访问 _taskId / _loopCount。
|
|
710
|
+
return async function (node, inputReport) {
|
|
711
|
+
const runner = new FlexRunnerCtor();
|
|
712
|
+
|
|
713
|
+
// 知识沉淀:注入指向正确数据目录的 KnowledgeManager,
|
|
714
|
+
// 避免 FlexRunner 内部 new KnowledgeManager() 用默认 createStorage()
|
|
715
|
+
// 落到 vendor/Server 相对路径 → cli/db/Knowledge(数据错位)。
|
|
716
|
+
let knowledgeManager = null;
|
|
717
|
+
if (KnowledgeManagerCtor && sharedStorage && typeof sharedStorage.json === 'function') {
|
|
718
|
+
try {
|
|
719
|
+
const km = new KnowledgeManagerCtor({ jsonAdapter: sharedStorage.json('Knowledge') });
|
|
720
|
+
await km.init();
|
|
721
|
+
knowledgeManager = km;
|
|
722
|
+
} catch { /* 注入失败则跳过(内部会惰性加载,仅位置不理想) */ }
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
await runner.initContext({
|
|
726
|
+
taskId: this._taskId,
|
|
727
|
+
stepId: Number(node.stepId) || 0,
|
|
728
|
+
dependId: Number(node.dependencies[0]) || 0,
|
|
729
|
+
nextStepId: Number(node.nextStepId) || 0,
|
|
730
|
+
failStepId: Number(node.failStepId) || 0,
|
|
731
|
+
taskDescription: node.taskDescription,
|
|
732
|
+
skillDirectory: node.skillDirectory,
|
|
733
|
+
specifiedSkill: node.specifiedSkill || '',
|
|
734
|
+
taskDir: node.taskDir,
|
|
735
|
+
inputReport,
|
|
736
|
+
maxRetries: node.maxRetries,
|
|
737
|
+
bigLoopIndex: this._loopCount || 0,
|
|
738
|
+
onSessionCreated: (sessionId) => {
|
|
739
|
+
node.sessionId = sessionId || '';
|
|
740
|
+
},
|
|
741
|
+
// ── 复用共享实例(避免重复创建 opencode / SQLite 连接)──
|
|
742
|
+
cli: sharedCli,
|
|
743
|
+
storage: sharedStorage,
|
|
744
|
+
knowledgeManager, // 注入共享 KnowledgeManager(正确数据目录)
|
|
745
|
+
});
|
|
746
|
+
return runner;
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/** 当前进程内最近一次启动的 Orchestrator(供 abort 控制)。 */
|
|
751
|
+
let _activeOrchestrator = null;
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* 创建指定任务的 Orchestrator 实例。
|
|
755
|
+
*
|
|
756
|
+
* 注意:任务定义会覆盖同 taskId 的磁盘旧状态(loadTask 内部 _persistState 会重写)。
|
|
757
|
+
*
|
|
758
|
+
* @param {RunContext} ctx
|
|
759
|
+
* @param {object} taskDef - 与 Orchestrator.loadTask 对齐的任务定义
|
|
760
|
+
* @param {function} [onProgress] - 可选进度回调(每步执行后触发)
|
|
761
|
+
* @returns {Promise<object>} getProgress() 快照
|
|
762
|
+
*/
|
|
763
|
+
export async function orchLoad(ctx, taskDef) {
|
|
764
|
+
await ctx._init();
|
|
765
|
+
if (!taskDef || !taskDef.taskId) throw new Error('taskId 为必填项');
|
|
766
|
+
if (!Array.isArray(taskDef.steps) || taskDef.steps.length === 0) {
|
|
767
|
+
throw new Error('steps 为必填项且不能为空');
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
const core = ctx.core;
|
|
771
|
+
const orch = new core.Orchestrator({
|
|
772
|
+
storage: ctx.storage,
|
|
773
|
+
flexRunnerFactory: createOrchestratorFlexRunnerFactory(ctx),
|
|
774
|
+
});
|
|
775
|
+
await orch.loadTask({
|
|
776
|
+
...taskDef,
|
|
777
|
+
skillDirectory: taskDef.skillDirectory || ctx.skillDir || '',
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
// 注册任务摘要到注册表(与 OrchestratorController.load 对齐,供前端历史列表查询)
|
|
781
|
+
const firstStep = taskDef.steps[0] || {};
|
|
782
|
+
await _registryUpsert(ctx, {
|
|
783
|
+
taskId: taskDef.taskId,
|
|
784
|
+
taskType: 'orchestrator',
|
|
785
|
+
status: 'loaded',
|
|
786
|
+
title: (firstStep.taskDescription || taskDef.title || '').slice(0, 200),
|
|
787
|
+
description: taskDef.title || firstStep.taskDescription || '',
|
|
788
|
+
createdAt: new Date().toISOString(),
|
|
789
|
+
metadata: { stepCount: taskDef.steps.length }
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
orch.dispose();
|
|
793
|
+
|
|
794
|
+
return { status: orch.status, progress: orch.getProgress() };
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* 编排启动(从磁盘恢复 → 校验 LOADED → start() 阻塞到终态)。
|
|
799
|
+
*
|
|
800
|
+
* @param {RunContext} ctx
|
|
801
|
+
* @param {string} taskId
|
|
802
|
+
* @param {function} [onProgress] - 进度回调(每步执行后触发)
|
|
803
|
+
* @returns {Promise<object>} { status, progress, passed, error, resultPath }
|
|
804
|
+
*/
|
|
805
|
+
export async function orchStart(ctx, taskId) {
|
|
806
|
+
await ctx._init();
|
|
807
|
+
if (!taskId) throw new Error('taskId 为必填项');
|
|
808
|
+
|
|
809
|
+
// 1. 从磁盘读 orchestration.json
|
|
810
|
+
const taskDir = path.join(ctx.dataDir, 'task', taskId);
|
|
811
|
+
const orchFile = path.join(taskDir, 'orchestration.json');
|
|
812
|
+
if (!fs.existsSync(orchFile)) {
|
|
813
|
+
throw new Error(`未找到编排任务: taskId=${taskId},请先执行 3rdloop orch load`);
|
|
814
|
+
}
|
|
815
|
+
let state;
|
|
816
|
+
try {
|
|
817
|
+
state = JSON.parse(fs.readFileSync(orchFile, 'utf8'));
|
|
818
|
+
} catch {
|
|
819
|
+
throw new Error(`编排状态文件损坏: ${orchFile}`);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// 2. 恢复内存实例
|
|
823
|
+
const core = ctx.core;
|
|
824
|
+
const orch = new core.Orchestrator({
|
|
825
|
+
storage: ctx.storage,
|
|
826
|
+
flexRunnerFactory: createOrchestratorFlexRunnerFactory(ctx),
|
|
827
|
+
});
|
|
828
|
+
await orch.restoreState(state);
|
|
829
|
+
|
|
830
|
+
// 3. 校验状态
|
|
831
|
+
if (orch.status !== core.OrchestratorStatus.LOADED) {
|
|
832
|
+
throw new Error(`编排任务当前状态为 ${orch.status},仅 LOADED 状态可启动(已加载未执行)`);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// 4. 阻塞执行
|
|
836
|
+
_activeOrchestrator = orch;
|
|
837
|
+
try {
|
|
838
|
+
const result = await orch.start();
|
|
839
|
+
const progress = orch.getProgress();
|
|
840
|
+
const status = result.status;
|
|
841
|
+
|
|
842
|
+
// 写精简 loop.json,使 3rdloop list/progress/result 可见
|
|
843
|
+
await _writeOrchestrationLoopJson(ctx, {
|
|
844
|
+
taskId,
|
|
845
|
+
taskDescription: state.taskDescription || '',
|
|
846
|
+
taskDir: progress.taskDir || taskDir,
|
|
847
|
+
status: _orchStatusToLoopStatus(status),
|
|
848
|
+
startTime: progress.startTime || _nowLocal(),
|
|
849
|
+
endTime: progress.endTime || _nowLocal(),
|
|
850
|
+
error: progress.error || null,
|
|
851
|
+
orchestratorStatus: status,
|
|
852
|
+
stats: progress.stats,
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
// 回写注册表终态(status + 结构化指标,与 OrchestratorController 终态回写对齐)
|
|
856
|
+
await _registryPatchFinalState(ctx, taskId, progress);
|
|
857
|
+
|
|
858
|
+
// 汇总各步产物路径
|
|
859
|
+
const resultPaths = (progress.steps || [])
|
|
860
|
+
.filter(s => s.resultPath)
|
|
861
|
+
.map(s => ({ stepId: s.stepId, resultPath: s.resultPath }));
|
|
862
|
+
|
|
863
|
+
return {
|
|
864
|
+
taskId,
|
|
865
|
+
status,
|
|
866
|
+
passed: status === core.OrchestratorStatus.COMPLETED,
|
|
867
|
+
progress,
|
|
868
|
+
error: progress.error || null,
|
|
869
|
+
resultPaths,
|
|
870
|
+
};
|
|
871
|
+
} finally {
|
|
872
|
+
_activeOrchestrator = null;
|
|
873
|
+
try { orch.dispose(); } catch { /* 忽略 */ }
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* 编排控制:abort / pause / resume。
|
|
879
|
+
*
|
|
880
|
+
* 嵌入式模式下任务在发起方进程内运行,控制命令先尝试命中当前进程内
|
|
881
|
+
* 正在运行的 _activeOrchestrator;否则从磁盘恢复实例调用对应控制方法。
|
|
882
|
+
* 跨进程无法中断另一进程的运行中任务(v1 与 3rdloop run 语义一致,接受现状)。
|
|
883
|
+
*
|
|
884
|
+
* @param {RunContext} ctx
|
|
885
|
+
* @param {string} taskId
|
|
886
|
+
* @param {'abort'|'pause'|'resume'} action
|
|
887
|
+
* @returns {Promise<{ok: boolean, status: string|null, error: string|null}>}
|
|
888
|
+
*/
|
|
889
|
+
export async function orchControl(ctx, taskId, action) {
|
|
890
|
+
await ctx._init();
|
|
891
|
+
|
|
892
|
+
let orch = null;
|
|
893
|
+
if (_activeOrchestrator && _activeOrchestrator.taskId === taskId) {
|
|
894
|
+
orch = _activeOrchestrator; // 当前进程内存实例
|
|
895
|
+
} else if (ctx.orchestratorController?._orchestrators?.has(taskId)) {
|
|
896
|
+
orch = ctx.orchestratorController._orchestrators.get(taskId); // 大循环上下文
|
|
897
|
+
} else {
|
|
898
|
+
// 磁盘恢复(尽力而为,主要覆盖 LOADED/已终态任务的 pause/resume 语义)
|
|
899
|
+
const taskDir = path.join(ctx.dataDir, 'task', taskId);
|
|
900
|
+
const orchFile = path.join(taskDir, 'orchestration.json');
|
|
901
|
+
if (fs.existsSync(orchFile)) {
|
|
902
|
+
try {
|
|
903
|
+
const state = JSON.parse(fs.readFileSync(orchFile, 'utf8'));
|
|
904
|
+
const core = ctx.core;
|
|
905
|
+
orch = new core.Orchestrator({
|
|
906
|
+
storage: ctx.storage,
|
|
907
|
+
flexRunnerFactory: createOrchestratorFlexRunnerFactory(ctx),
|
|
908
|
+
});
|
|
909
|
+
await orch.restoreState(state);
|
|
910
|
+
// 控制操作只能在正确的状态下生效,交给各自方法自校验
|
|
911
|
+
} catch { orch = null; }
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
if (!orch) return { ok: false, status: null, error: `未找到编排任务: taskId=${taskId}` };
|
|
916
|
+
|
|
917
|
+
let ok = false;
|
|
918
|
+
try {
|
|
919
|
+
if (action === 'abort') ok = await orch.abort();
|
|
920
|
+
else if (action === 'pause') ok = await orch.pause();
|
|
921
|
+
else ok = await orch.resume();
|
|
922
|
+
} catch (err) {
|
|
923
|
+
return { ok: false, status: orch.status || null, error: err.message };
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
const status = orch.status || null;
|
|
927
|
+
// 磁盘恢复实例控制后弃置(避免泄漏连接)
|
|
928
|
+
if (orch !== _activeOrchestrator && orch !== ctx.orchestratorController?._orchestrators?.get(taskId)) {
|
|
929
|
+
try { orch.dispose(); } catch { /* 忽略 */ }
|
|
930
|
+
}
|
|
931
|
+
return { ok, status, error: null };
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/** 编排终态集合(OrchestratorStatus 中不可继续执行的态)。 */
|
|
935
|
+
export const ORCH_TERMINAL_STATUSES = [
|
|
936
|
+
'completed', 'failed', 'aborted', 'deadlocked'
|
|
937
|
+
];
|
|
938
|
+
|
|
939
|
+
/** 映射 OrchestratorStatus → loop.json 的 status 字段。 */
|
|
940
|
+
function _orchStatusToLoopStatus(status) {
|
|
941
|
+
if (status === 'completed') return 'passed';
|
|
942
|
+
if (status === 'aborted') return 'aborted';
|
|
943
|
+
return 'failed';
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
/** 写精简版 loop.json(编排任务,isOrchestration:true)。 */
|
|
947
|
+
async function _writeOrchestrationLoopJson(ctx, { taskId, taskDescription, taskDir, status, startTime, endTime, error, orchestratorStatus, stats }) {
|
|
948
|
+
try {
|
|
949
|
+
const stepCount = stats && typeof stats.total === 'number' ? stats.total : 0;
|
|
950
|
+
const state = {
|
|
951
|
+
taskId,
|
|
952
|
+
taskDescription,
|
|
953
|
+
userAcceptanceCriteria: '',
|
|
954
|
+
taskDir,
|
|
955
|
+
skillDirectory: ctx.skillDir || '',
|
|
956
|
+
maxLoops: 1,
|
|
957
|
+
currentLoop: 1,
|
|
958
|
+
status,
|
|
959
|
+
startTime: startTime || _nowLocal(),
|
|
960
|
+
endTime,
|
|
961
|
+
error,
|
|
962
|
+
aborted: status === 'aborted',
|
|
963
|
+
isOrchestration: true,
|
|
964
|
+
rounds: [{
|
|
965
|
+
loop: 0,
|
|
966
|
+
startTime: startTime || _nowLocal(),
|
|
967
|
+
endTime,
|
|
968
|
+
passed: status === 'passed',
|
|
969
|
+
error,
|
|
970
|
+
planningIsReplan: false,
|
|
971
|
+
planningStepCount: stepCount,
|
|
972
|
+
orchestratorStatus,
|
|
973
|
+
}],
|
|
974
|
+
stats: stats || null,
|
|
975
|
+
persistedAt: _nowLocal(),
|
|
976
|
+
};
|
|
977
|
+
await ctx.storage.json('task').write(`${taskId}/loop`, state);
|
|
978
|
+
} catch { /* 写 loop.json 失败不影响主流程 */ }
|
|
979
|
+
}
|