@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.
Files changed (389) hide show
  1. package/README.md +425 -0
  2. package/bin/3rdloop.mjs +48 -0
  3. package/lib/cli.js +741 -0
  4. package/lib/config.js +318 -0
  5. package/lib/doctor.js +114 -0
  6. package/lib/exit-codes.js +31 -0
  7. package/lib/opencode.js +156 -0
  8. package/lib/orch.js +427 -0
  9. package/lib/queries.js +264 -0
  10. package/lib/runner.js +979 -0
  11. package/lib/step.js +326 -0
  12. package/lib/ui.js +223 -0
  13. package/lib/workflow.js +291 -0
  14. package/lib/workflows.js +132 -0
  15. package/package.json +50 -0
  16. package/vendor/Server/Agent/SkillSelector/README.md +344 -0
  17. package/vendor/Server/Agent/SkillSelector/core/Agent.js +207 -0
  18. package/vendor/Server/Agent/SkillSelector/index.js +14 -0
  19. package/vendor/Server/Agent/SkillSelector/llm/llmClient.js +313 -0
  20. package/vendor/Server/Agent/SkillSelector/llm/prompts.js +161 -0
  21. package/vendor/Server/Agent/SkillSelector/llm/reactSteps.js +144 -0
  22. package/vendor/Server/Agent/SkillSelector/matcher/fuzzyMatcher.js +433 -0
  23. package/vendor/Server/Agent/SkillSelector/scanner/skillScanner.js +382 -0
  24. package/vendor/Server/Agent/SkillSelector/types.js +63 -0
  25. package/vendor/Server/Agent/SkillSelector/utils/actionWords.js +60 -0
  26. package/vendor/Server/Brain/AnalysisStrategies.js +422 -0
  27. package/vendor/Server/Brain/Brain.js +686 -0
  28. package/vendor/Server/Brain/DecompositionStrategies.js +621 -0
  29. package/vendor/Server/Brain/PlanPersistence.js +196 -0
  30. package/vendor/Server/Brain/SkillExecutor.js +251 -0
  31. package/vendor/Server/Brain/index.js +11 -0
  32. package/vendor/Server/CLI/cli.js +243 -0
  33. package/vendor/Server/CLI/opencode/index.js +804 -0
  34. package/vendor/Server/CLI/opencode.js +5 -0
  35. package/vendor/Server/DbUse/MessageArchive.js +61 -0
  36. package/vendor/Server/DbUse/StorageManager.js +107 -0
  37. package/vendor/Server/DbUse/adapters/BaseAdapter.js +94 -0
  38. package/vendor/Server/DbUse/adapters/FileAdapter.js +138 -0
  39. package/vendor/Server/DbUse/adapters/JsonAdapter.js +138 -0
  40. package/vendor/Server/DbUse/adapters/JsonlAdapter.js +114 -0
  41. package/vendor/Server/DbUse/adapters/SqliteAdapter.js +157 -0
  42. package/vendor/Server/DbUse/index.js +160 -0
  43. package/vendor/Server/DbUse/stores/SessionStore.js +279 -0
  44. package/vendor/Server/DbUse/stores/TaskExecutionStore.js +133 -0
  45. package/vendor/Server/DbUse/stores/TaskRegistryStore.js +262 -0
  46. package/vendor/Server/DbUse/stores/TaskStepStore.js +279 -0
  47. package/vendor/Server/FlexRunner/FlexRunner.js +1759 -0
  48. package/vendor/Server/FlexRunner/index.js +12 -0
  49. package/vendor/Server/Knowledge/KnowledgeImporter.js +523 -0
  50. package/vendor/Server/Knowledge/KnowledgeManager.js +341 -0
  51. package/vendor/Server/Knowledge/index.js +33 -0
  52. package/vendor/Server/LoopEngine/LoopEngine.js +1133 -0
  53. package/vendor/Server/LoopEngine/index.js +11 -0
  54. package/vendor/Server/Orchestrator/Orchestrator.js +1425 -0
  55. package/vendor/Server/Orchestrator/StepNode.js +312 -0
  56. package/vendor/Server/Orchestrator/index.js +13 -0
  57. package/vendor/Server/Routes/controllers/BrainController.js +241 -0
  58. package/vendor/Server/Routes/controllers/FlexRunnerController.js +1125 -0
  59. package/vendor/Server/Routes/controllers/HealthController.js +44 -0
  60. package/vendor/Server/Routes/controllers/KnowledgeImportController.js +355 -0
  61. package/vendor/Server/Routes/controllers/LoopEngineController.js +788 -0
  62. package/vendor/Server/Routes/controllers/OrchestratorController.js +911 -0
  63. package/vendor/Server/Routes/controllers/StatsController.js +57 -0
  64. package/vendor/Server/Routes/controllers/StreamController.js +67 -0
  65. package/vendor/Server/Routes/library/logger.js +179 -0
  66. package/vendor/Server/Routes/library/zipArchive.js +172 -0
  67. package/vendor/Server/Routes/router/Router.js +204 -0
  68. package/vendor/Server/Routes/routes/brain.js +47 -0
  69. package/vendor/Server/Routes/routes/flexrunner.js +72 -0
  70. package/vendor/Server/Routes/routes/health.js +28 -0
  71. package/vendor/Server/Routes/routes/index.js +57 -0
  72. package/vendor/Server/Routes/routes/knowledge.js +55 -0
  73. package/vendor/Server/Routes/routes/loopengine.js +58 -0
  74. package/vendor/Server/Routes/routes/orchestrator.js +61 -0
  75. package/vendor/Server/Routes/routes/registry.js +98 -0
  76. package/vendor/Server/Routes/routes/stats.js +23 -0
  77. package/vendor/Server/Routes/routes/stream.js +30 -0
  78. package/vendor/Server/Routes/server.js +202 -0
  79. package/vendor/Server/Routes/sse/SseHub.js +308 -0
  80. package/vendor/Server/Skills/acceptance-check/SKILL.md +174 -0
  81. package/vendor/Server/Skills/acceptance-check/references/PHASE1_ARTIFACT_COLLECTION.md +52 -0
  82. package/vendor/Server/Skills/acceptance-check/references/PHASE2_CRITERIA_EVALUATION.md +77 -0
  83. package/vendor/Server/Skills/arkts-code-check/SKILL.md +314 -0
  84. package/vendor/Server/Skills/arkts-code-check/references/CODE_CHECK_GUIDE.md +160 -0
  85. package/vendor/Server/Skills/arkts-code-check/references/FILE_TYPE_GUIDE.md +29 -0
  86. package/vendor/Server/Skills/arkts-code-check/references/PHASE1_INFO_COLLECTION.md +222 -0
  87. package/vendor/Server/Skills/arkts-code-check/references/REPORT_TEMPLATE.md +220 -0
  88. package/vendor/Server/Skills/arkts-library-compile-validate/SKILL.md +329 -0
  89. package/vendor/Server/Skills/arkts-library-compile-validate/scripts/build.ps1 +93 -0
  90. package/vendor/Server/Skills/arkts-library-compile-validate/scripts/code-linter.cjs +433 -0
  91. package/vendor/Server/Skills/arkts-library-compile-validate/scripts/migrate.cjs +851 -0
  92. package/vendor/Server/Skills/arkts-library-compile-validate/scripts/ohpm-switch.cjs +789 -0
  93. package/vendor/Server/Skills/arkts-library-demo-code/SKILL.md +291 -0
  94. package/vendor/Server/Skills/arkts-library-demo-code/references/API_SIGNATURE_CHECKS.md +68 -0
  95. package/vendor/Server/Skills/arkts-library-demo-code/references/BUILD_VALIDATION.md +184 -0
  96. package/vendor/Server/Skills/arkts-library-demo-code/references/CODE_STANDARDS.md +337 -0
  97. package/vendor/Server/Skills/arkts-library-demo-code/references/EXAMPLES.md +400 -0
  98. package/vendor/Server/Skills/arkts-library-demo-code/references/SYSTEM_API_LOOKUP.md +99 -0
  99. package/vendor/Server/Skills/arkts-library-demo-code/references/TEMPLATE.md +544 -0
  100. package/vendor/Server/Skills/arkts-library-demo-code/scripts/build.ps1 +93 -0
  101. package/vendor/Server/Skills/arkts-library-demo-code/scripts/code-linter.cjs +433 -0
  102. package/vendor/Server/Skills/arkts-library-demo-code/scripts/migrate.cjs +851 -0
  103. package/vendor/Server/Skills/arkts-library-demo-code/scripts/ohpm-switch.cjs +789 -0
  104. package/vendor/Server/Skills/arkts-library-demo-coverage/SKILL.md +174 -0
  105. package/vendor/Server/Skills/arkts-library-demo-scenario/SKILL.md +321 -0
  106. package/vendor/Server/Skills/arkts-library-demo-scenario/references/EXAMPLES.md +100 -0
  107. package/vendor/Server/Skills/arkts-library-demo-scenario/references/TEMPLATE.md +185 -0
  108. package/vendor/Server/Skills/arkts-library-documentation-quality-check/SKILL.md +234 -0
  109. package/vendor/Server/Skills/arkts-library-documentation-quality-check/assets/REPORT_TEMPLATE.md +103 -0
  110. package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/CHECK_DIMENSIONS.md +89 -0
  111. package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/COMPLIANCE_CHECKLIST.md +62 -0
  112. package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/KB_QUERY_GUIDE.md +108 -0
  113. package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/MCP_TOOL_DISCOVERY.md +124 -0
  114. package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/REPORT_TEMPLATE.md +90 -0
  115. package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/SCORING_FORMULA.md +57 -0
  116. package/vendor/Server/Skills/arkts-library-documentation-quality-check/scripts/validate-skill.cjs +259 -0
  117. package/vendor/Server/Skills/arkts-library-interface-spec/SKILL.md +97 -0
  118. package/vendor/Server/Skills/arkts-library-memory-leak-check/SKILL.md +392 -0
  119. package/vendor/Server/Skills/arkts-library-source-clone/SKILL.md +113 -0
  120. package/vendor/Server/Skills/arkts-library-stability-check/SKILL.md +313 -0
  121. package/vendor/Server/Skills/arkts-library-stability-check/assets/REPORT_TEMPLATE.md +154 -0
  122. package/vendor/Server/Skills/arkts-library-stability-check/references/CHECKLIST.md +166 -0
  123. package/vendor/Server/Skills/arkts-library-stability-check/references/CODE_EXAMPLES.md +309 -0
  124. package/vendor/Server/Skills/arkts-library-stability-check/references/SCORING_RULES.md +90 -0
  125. package/vendor/Server/Skills/arkts-library-stability-check/scripts/validate-skill.cjs +282 -0
  126. package/vendor/Server/Skills/arkts-library-test-coverage-check/SKILL.md +361 -0
  127. package/vendor/Server/Skills/arkts-library-test-coverage-check/assets/REPORT_TEMPLATE.md +146 -0
  128. package/vendor/Server/Skills/arkts-library-test-coverage-check/references/CHECKLIST.md +253 -0
  129. package/vendor/Server/Skills/arkts-library-test-coverage-check/references/MCP_TOOL_USAGE.md +115 -0
  130. package/vendor/Server/Skills/arkts-library-test-coverage-check/scripts/validate-skill.cjs +263 -0
  131. package/vendor/Server/Skills/arkts-library-xts-code/SKILL.md +455 -0
  132. package/vendor/Server/Skills/arkts-library-xts-code/assets/report-template.md +60 -0
  133. package/vendor/Server/Skills/arkts-library-xts-code/references/ACCESS_MODIFIER_PRECHECK.md +76 -0
  134. package/vendor/Server/Skills/arkts-library-xts-code/references/BUILD_VERIFICATION.md +200 -0
  135. package/vendor/Server/Skills/arkts-library-xts-code/references/CODE_STANDARDS.md +519 -0
  136. package/vendor/Server/Skills/arkts-library-xts-code/references/SUBAGENT_PROMPT_TEMPLATE.md +276 -0
  137. package/vendor/Server/Skills/arkts-library-xts-code/references/SYSTEM_API_LOOKUP.md +93 -0
  138. package/vendor/Server/Skills/arkts-library-xts-code/references/XTS_TEMPLATE.md +767 -0
  139. package/vendor/Server/Skills/arkts-library-xts-code/scripts/build.ps1 +93 -0
  140. package/vendor/Server/Skills/arkts-library-xts-code/scripts/code-linter.cjs +433 -0
  141. package/vendor/Server/Skills/arkts-library-xts-code/scripts/migrate.cjs +851 -0
  142. package/vendor/Server/Skills/arkts-library-xts-code/scripts/ohpm-switch.cjs +789 -0
  143. package/vendor/Server/Skills/arkts-library-xts-code/scripts/precheck-access-modifiers.cjs +221 -0
  144. package/vendor/Server/Skills/arkts-library-xts-code-fix/SKILL.md +229 -0
  145. package/vendor/Server/Skills/arkts-library-xts-coverage/SKILL.md +97 -0
  146. package/vendor/Server/Skills/arkts-library-xts-doc/SKILL.md +194 -0
  147. package/vendor/Server/Skills/arkts-library-xts-doc/references/EXAMPLES.md +576 -0
  148. package/vendor/Server/Skills/arkts-library-xts-doc/references/TEMPLATE.md +575 -0
  149. package/vendor/Server/Skills/arkts-library-xts-doc/references/TESTABILITY_GUIDE.md +182 -0
  150. package/vendor/Server/Skills/arkts-library-xts-execution/SKILL.md +491 -0
  151. package/vendor/Server/Skills/arkts-library-xts-execution/references/error-fixing-examples.md +217 -0
  152. package/vendor/Server/Skills/arkts-library-xts-execution/scripts/build.ps1 +93 -0
  153. package/vendor/Server/Skills/arkts-library-xts-execution/scripts/code-linter.cjs +433 -0
  154. package/vendor/Server/Skills/arkts-library-xts-execution/scripts/migrate.cjs +851 -0
  155. package/vendor/Server/Skills/arkts-library-xts-execution/scripts/ohpm-switch.cjs +789 -0
  156. package/vendor/Server/Skills/flutter-code-check/SKILL.md +299 -0
  157. package/vendor/Server/Skills/flutter-code-check/assets/OUTPUT_TEMPLATE.md +312 -0
  158. package/vendor/Server/Skills/flutter-code-check/references/CHECKLIST.md +190 -0
  159. package/vendor/Server/Skills/flutter-code-check/references/PLATFORMS.md +134 -0
  160. package/vendor/Server/Skills/flutter-code-check/scripts/validate-skill.cjs +259 -0
  161. package/vendor/Server/Skills/flutter-interface/README.md +75 -0
  162. package/vendor/Server/Skills/flutter-interface/SKILL.md +291 -0
  163. package/vendor/Server/Skills/flutter-interface/references/EXAMPLES.md +336 -0
  164. package/vendor/Server/Skills/flutter-interface/references/GIT_CLONE_GUIDE.md +190 -0
  165. package/vendor/Server/Skills/flutter-interface/references/SCRIPT_REFERENCE.md +258 -0
  166. package/vendor/Server/Skills/flutter-interface/references/TEMPLATE.md +254 -0
  167. package/vendor/Server/Skills/flutter-library-consistency-check/SKILL.md +518 -0
  168. package/vendor/Server/Skills/flutter-library-consistency-check/references/CHECKLIST.md +382 -0
  169. package/vendor/Server/Skills/flutter-library-consistency-check/references/FUNCTION_COMPARISON_GUIDE.md +342 -0
  170. package/vendor/Server/Skills/flutter-library-consistency-check/references/PLATFORM_LIMITATION_GUIDE.md +71 -0
  171. package/vendor/Server/Skills/flutter-library-documentation-quality-check/SKILL.md +519 -0
  172. package/vendor/Server/Skills/flutter-library-documentation-quality-check/references/CHECKLIST.md +407 -0
  173. package/vendor/Server/Skills/flutter-library-memory-leak-check/SKILL.md +653 -0
  174. package/vendor/Server/Skills/flutter-library-memory-leak-check/references/CHECKLIST.md +397 -0
  175. package/vendor/Server/Skills/flutter-library-stability-check/SKILL.md +745 -0
  176. package/vendor/Server/Skills/flutter-library-stability-check/references/CHECKLIST.md +721 -0
  177. package/vendor/Server/Skills/flutter-library-test-coverage-check/SKILL.md +414 -0
  178. package/vendor/Server/Skills/flutter-library-test-coverage-check/assets/REPORT_TEMPLATE.md +150 -0
  179. package/vendor/Server/Skills/flutter-library-test-coverage-check/references/CHECKLIST.md +304 -0
  180. package/vendor/Server/Skills/flutter-library-test-coverage-check/references/SCORING_RULES.md +265 -0
  181. package/vendor/Server/Skills/flutter-library-test-coverage-check/references/SCRIPT_USAGE.md +286 -0
  182. package/vendor/Server/Skills/knowledge-import/SKILL.md +383 -0
  183. package/vendor/Server/Skills/knowledge-import/references/MCP_TOOL_USAGE.md +165 -0
  184. package/vendor/Server/Skills/knowledge-import/references/SKILL_LOCATOR_GUIDE.md +91 -0
  185. package/vendor/Server/Skills/knowledge-import/references/SKILL_OPTIMIZATION_GUIDE.md +127 -0
  186. package/vendor/Server/Skills/ohos-lib-pr-push/SKILL.md +301 -0
  187. package/vendor/Server/Skills/ohos-lib-pr-push/assets/PR_ISSUE_TEMPLATE.md +105 -0
  188. package/vendor/Server/Skills/ohos-lib-pr-push/references/GITCODE_API.md +127 -0
  189. package/vendor/Server/Skills/ohos-lib-pr-push/scripts/gitcode-api.cjs +208 -0
  190. package/vendor/Server/Skills/rn-code-check/SKILL.md +321 -0
  191. package/vendor/Server/Skills/rn-code-check/references/API-GUIDE.md +235 -0
  192. package/vendor/Server/Skills/rn-code-check/references/CHECKLIST.md +189 -0
  193. package/vendor/Server/Skills/rn-code-check/references/REPORT-TEMPLATE.md +247 -0
  194. package/vendor/Server/Skills/rn-lib-add-example/SKILL.md +198 -0
  195. package/vendor/Server/Skills/rn-lib-add-example/references/APP_RENAME_GUIDE.md +40 -0
  196. package/vendor/Server/Skills/rn-lib-add-example/references/SHELL_ADAPTATION_CHECKLIST.md +78 -0
  197. package/vendor/Server/Skills/rn-lib-add-example/references/TEMPLATE_REPO_GUIDE.md +70 -0
  198. package/vendor/Server/Skills/rn-lib-add-example/references/VERIFICATION_GUIDE.md +47 -0
  199. package/vendor/Server/Skills/rn-lib-add-example/scripts/create-example.cjs +252 -0
  200. package/vendor/Server/Skills/rn-lib-update-doc/SKILL.md +176 -0
  201. package/vendor/Server/Skills/rn-lib-update-doc/config.json +5 -0
  202. package/vendor/Server/Skills/rn-lib-update-doc/references/changelog-template.md +35 -0
  203. package/vendor/Server/Skills/rn-lib-update-doc/references/format-diff.md +137 -0
  204. package/vendor/Server/Skills/rn-lib-update-doc/references/link-registry.json +33 -0
  205. package/vendor/Server/Skills/rn-lib-update-doc/references/model-0.4.2-overview.md +40 -0
  206. package/vendor/Server/Skills/rn-lib-update-doc/references/model-0.4.2.md +429 -0
  207. package/vendor/Server/Skills/rn-lib-update-doc/scripts/detect-readme-format.cjs +105 -0
  208. package/vendor/Server/Skills/rn-lib-update-doc/scripts/find-usage-doc.cjs +90 -0
  209. package/vendor/Server/Skills/rn-lib-update-doc/scripts/link-verify.cjs +213 -0
  210. package/vendor/Server/Skills/rn-lib-update-doc/scripts/normalize-changelog.cjs +73 -0
  211. package/vendor/Server/Skills/rn-lib-update-doc/scripts/normalize-package-meta.cjs +258 -0
  212. package/vendor/Server/Skills/rn-lib-update-doc/scripts/normalize-readme-links.cjs +341 -0
  213. package/vendor/Server/Skills/rn-lib-update-doc/scripts/resolve-usage-docs.cjs +67 -0
  214. package/vendor/Server/Skills/rn-library-consistency-check/SKILL.md +299 -0
  215. package/vendor/Server/Skills/rn-library-consistency-check/assets/REPORT_TEMPLATE.md +293 -0
  216. package/vendor/Server/Skills/rn-library-consistency-check/references/ARKTS_COMPONENT_CHECK_GUIDE.md +857 -0
  217. package/vendor/Server/Skills/rn-library-consistency-check/references/ARKTS_TURBOMODULE_CHECK_GUIDE.md +856 -0
  218. package/vendor/Server/Skills/rn-library-consistency-check/references/CHECKLIST.md +157 -0
  219. package/vendor/Server/Skills/rn-library-consistency-check/references/CPP_COMPONENT_CHECK_GUIDE.md +801 -0
  220. package/vendor/Server/Skills/rn-library-consistency-check/references/CPP_TURBOMODULE_CHECK_GUIDE.md +684 -0
  221. package/vendor/Server/Skills/rn-library-consistency-check/references/FUNCTION_COMPARISON_GUIDE.md +233 -0
  222. package/vendor/Server/Skills/rn-library-consistency-check/references/NATIVE_COMPONENT_IDENTIFICATION.md +1373 -0
  223. package/vendor/Server/Skills/rn-library-consistency-check/references/SCORING_STANDARD.md +220 -0
  224. package/vendor/Server/Skills/rn-library-consistency-check/scripts/validate-skill.py +245 -0
  225. package/vendor/Server/Skills/rn-library-documentation-quality-check/SKILL.md +263 -0
  226. package/vendor/Server/Skills/rn-library-documentation-quality-check/assets/MODEL.md +414 -0
  227. package/vendor/Server/Skills/rn-library-documentation-quality-check/assets/MODEL_en.md +413 -0
  228. package/vendor/Server/Skills/rn-library-documentation-quality-check/assets/REPORT_TEMPLATE.md +311 -0
  229. package/vendor/Server/Skills/rn-library-documentation-quality-check/references/CHECK_CHECKLIST.md +355 -0
  230. package/vendor/Server/Skills/rn-library-documentation-quality-check/references/CROSS_VALIDATION_GUIDE.md +115 -0
  231. package/vendor/Server/Skills/rn-library-documentation-quality-check/references/DOC_COLLECTION_GUIDE.md +139 -0
  232. package/vendor/Server/Skills/rn-library-documentation-quality-check/references/EXAMPLES.md +586 -0
  233. package/vendor/Server/Skills/rn-library-documentation-quality-check/references/GOTCHAS.md +57 -0
  234. package/vendor/Server/Skills/rn-library-documentation-quality-check/scripts/validate-skill.py +259 -0
  235. package/vendor/Server/Skills/rn-library-interface-analyzer/SKILL.md +301 -0
  236. package/vendor/Server/Skills/rn-library-interface-analyzer/assets/REPORT_TEMPLATE.md +148 -0
  237. package/vendor/Server/Skills/rn-library-interface-analyzer/references/DOC_ANNOTATION_GUIDE.md +118 -0
  238. package/vendor/Server/Skills/rn-library-interface-analyzer/references/SCRIPT_USAGE_GUIDE.md +168 -0
  239. package/vendor/Server/Skills/rn-library-interface-analyzer/references/URL_PARSING_RULES.md +176 -0
  240. package/vendor/Server/Skills/rn-library-issue-generalizer/SKILL.md +274 -0
  241. package/vendor/Server/Skills/rn-library-issue-generalizer/assets/case-template.md +45 -0
  242. package/vendor/Server/Skills/rn-library-issue-generalizer/assets/rule-template.md +25 -0
  243. package/vendor/Server/Skills/rn-library-issue-generalizer/references/PR_FETCH_GUIDE.md +61 -0
  244. package/vendor/Server/Skills/rn-library-issue-generalizer/references/RULE_TEMPLATE_GUIDE.md +165 -0
  245. package/vendor/Server/Skills/rn-library-issue-generalizer/scripts/fetch-pr-info.py +239 -0
  246. package/vendor/Server/Skills/rn-library-known-issue-check/SKILL.md +263 -0
  247. package/vendor/Server/Skills/rn-library-known-issue-check/assets/REPORT_TEMPLATE.md +96 -0
  248. package/vendor/Server/Skills/rn-library-known-issue-check/references/COMPLIANCE_CHECKLIST.md +58 -0
  249. package/vendor/Server/Skills/rn-library-known-issue-check/references/INSPECTION_GUIDE.md +99 -0
  250. package/vendor/Server/Skills/rn-library-known-issue-check/references/PRESCREEN_GUIDE.md +64 -0
  251. package/vendor/Server/Skills/rn-library-known-issue-check/references/SOURCE_PREP_GUIDE.md +75 -0
  252. package/vendor/Server/Skills/rn-library-known-issue-check/scripts/validate-known-issue-report.py +164 -0
  253. package/vendor/Server/Skills/rn-library-memory-leak-check/SKILL.md +339 -0
  254. package/vendor/Server/Skills/rn-library-memory-leak-check/assets/REPORT_TEMPLATE.md +83 -0
  255. package/vendor/Server/Skills/rn-library-memory-leak-check/references/CHECKLIST.md +859 -0
  256. package/vendor/Server/Skills/rn-library-memory-leak-check/references/HARMONY_CODE_PATTERNS.md +122 -0
  257. package/vendor/Server/Skills/rn-library-memory-leak-check/scripts/scan_harmony_code.py +279 -0
  258. package/vendor/Server/Skills/rn-library-stability-check/SKILL.md +273 -0
  259. package/vendor/Server/Skills/rn-library-stability-check/assets/REPORT_TEMPLATE.md +129 -0
  260. package/vendor/Server/Skills/rn-library-stability-check/references/CHECKLIST.md +581 -0
  261. package/vendor/Server/Skills/rn-library-stability-check/references/SCORING_RULES.md +138 -0
  262. package/vendor/Server/Skills/rn-library-stability-check/scripts/scan-harmony-code.py +168 -0
  263. package/vendor/Server/Skills/rn-library-test-coverage-check/SKILL.md +506 -0
  264. package/vendor/Server/Skills/rn-library-test-coverage-check/references/CHECKLIST.md +280 -0
  265. package/vendor/Server/Skills/rn-library-test-coverage-check/references/DEMO_LOCATION.md +221 -0
  266. package/vendor/Server/Skills/rn-library-test-coverage-check/references/REPORT_TEMPLATE.md +209 -0
  267. package/vendor/Server/Skills/rn-library-test-coverage-check/references/SCRIPT_USAGE.md +325 -0
  268. package/vendor/Server/Skills/rn-ohos-xts-generator/SKILL.md +279 -0
  269. package/vendor/Server/Skills/rn-ohos-xts-generator/assets/TEST_FILE_TEMPLATES.md +404 -0
  270. package/vendor/Server/Skills/rn-ohos-xts-generator/references/BUILD_TROUBLESHOOTING.md +185 -0
  271. package/vendor/Server/Skills/rn-ohos-xts-generator/references/BUILD_WORKFLOW.md +265 -0
  272. package/vendor/Server/Skills/rn-ohos-xts-generator/references/COMMON_CONFIG.md +189 -0
  273. package/vendor/Server/Skills/rn-ohos-xts-generator/references/CONFIG_GUIDE.md +203 -0
  274. package/vendor/Server/Skills/rn-ohos-xts-generator/references/COVERAGE_ANALYZER.md +147 -0
  275. package/vendor/Server/Skills/rn-ohos-xts-generator/references/DESIGN_DOC_GUIDE.md +148 -0
  276. package/vendor/Server/Skills/rn-ohos-xts-generator/references/GENERATION_FLOW.md +165 -0
  277. package/vendor/Server/Skills/rn-ohos-xts-generator/references/GENERATION_STRATEGY.md +195 -0
  278. package/vendor/Server/Skills/rn-ohos-xts-generator/references/HARMONY_SCANNER.md +249 -0
  279. package/vendor/Server/Skills/rn-ohos-xts-generator/references/JEST_FRAMEWORK.md +235 -0
  280. package/vendor/Server/Skills/rn-ohos-xts-generator/references/PLATFORM_COMPAT.md +161 -0
  281. package/vendor/Server/Skills/rn-ohos-xts-generator/references/RN_TEST_PATTERNS.md +413 -0
  282. package/vendor/Server/Skills/rn-ohos-xts-generator/references/SOURCE_PARSER.md +235 -0
  283. package/vendor/Server/Skills/rn-ohos-xts-generator/references/TEST_CONVENTIONS.md +245 -0
  284. package/vendor/Server/Skills/rn-ohos-xts-generator/references/TROUBLESHOOTING.md +282 -0
  285. package/vendor/Server/Skills/rn-ohos-xts-generator/references/USAGE_GUIDE.md +251 -0
  286. package/vendor/Server/Skills/rnoh-cptf-api-test/SKILL.md +469 -0
  287. package/vendor/Server/Skills/rnoh-cptf-api-test/assets/CPTF_TEST_TEMPLATE.md +310 -0
  288. package/vendor/Server/Skills/rnoh-cptf-api-test/assets/DEMO_PAGE_TEMPLATE.md +303 -0
  289. package/vendor/Server/Skills/rnoh-cptf-api-test/references/CPTF_TEST_GENERATION_GUIDE.md +421 -0
  290. package/vendor/Server/Skills/rnoh-cptf-api-test/references/DEMO_GENERATION_GUIDE.md +358 -0
  291. package/vendor/Server/Skills/rnoh-cptf-api-test/references/QUALITY_CHECKLIST.md +114 -0
  292. package/vendor/Server/Skills/rnoh-cptf-api-test/references/SPEC_PARSING_GUIDE.md +274 -0
  293. package/vendor/Server/Skills/rnoh-cptf-api-test/scripts/validate-rnoh-cptf-api-test.sh +185 -0
  294. package/vendor/Server/Skills/rnoh-cptf-demo-test/SKILL.md +191 -0
  295. package/vendor/Server/Skills/rnoh-cptf-demo-test/assets/TEST_TEMPLATE.md +216 -0
  296. package/vendor/Server/Skills/rnoh-cptf-demo-test/references/CPTF_SETUP.md +107 -0
  297. package/vendor/Server/Skills/rnoh-cptf-demo-test/references/DEMO_ANALYSIS.md +120 -0
  298. package/vendor/Server/Skills/rnoh-cptf-demo-test/scripts/validate-rnoh-cptf-test.sh +108 -0
  299. package/vendor/Server/Skills/rnoh-cptf-test-run/SKILL.md +237 -0
  300. package/vendor/Server/Skills/rnoh-cptf-test-run/references/DEBUG_PLAYBOOK.md +261 -0
  301. package/vendor/Server/Skills/rnoh-cptf-test-run/scripts/validate-run-env.sh +112 -0
  302. package/vendor/Server/Skills/rnoh-lib-code-adapt/SKILL.md +498 -0
  303. package/vendor/Server/Skills/rnoh-lib-code-adapt/references/adapt-checklist.md +270 -0
  304. package/vendor/Server/Skills/rnoh-lib-code-adapt/references/api-migration-checklist.md +164 -0
  305. package/vendor/Server/Skills/rnoh-lib-code-adapt/references/common-compile-errors.md +556 -0
  306. package/vendor/Server/Skills/rnoh-lib-code-adapt/references/deveco-cli-tools.md +459 -0
  307. package/vendor/Server/Skills/rnoh-lib-code-adapt/references/edge-cases.md +65 -0
  308. package/vendor/Server/Skills/rnoh-lib-code-adapt/references/har-tgz-build.md +512 -0
  309. package/vendor/Server/Skills/rnoh-lib-code-adapt/references/version-compat-matrix.md +132 -0
  310. package/vendor/Server/Skills/rnoh-lib-code-adapt/scripts/auto-integrate.sh +424 -0
  311. package/vendor/Server/Skills/rnoh-lib-demo-coverage/SKILL.md +137 -0
  312. package/vendor/Server/Skills/rnoh-lib-demo-create/SKILL.md +306 -0
  313. package/vendor/Server/Skills/rnoh-lib-demo-create/assets/DEMO_PAGE_TEMPLATE.md +485 -0
  314. package/vendor/Server/Skills/rnoh-lib-demo-create/assets/INDEX_TEMPLATE.md +172 -0
  315. package/vendor/Server/Skills/rnoh-lib-demo-create/references/DEMO_CODE_RULES.md +422 -0
  316. package/vendor/Server/Skills/rnoh-lib-demo-create/references/QUALITY_CHECKLIST.md +95 -0
  317. package/vendor/Server/Skills/rnoh-lib-demo-create/references/SOURCE_EXPLORATION.md +169 -0
  318. package/vendor/Server/Skills/rnoh-lib-demo-doc/SKILL.md +554 -0
  319. package/vendor/Server/Skills/rnoh-lib-demo-doc/assets/DEMO_DOC_TEMPLATE.md +106 -0
  320. package/vendor/Server/Skills/rnoh-lib-demo-doc/references/COVERAGE_INCREMENTAL.md +216 -0
  321. package/vendor/Server/Skills/rnoh-lib-demo-doc/references/DEMO_DESIGN_RULES.md +413 -0
  322. package/vendor/Server/Skills/rnoh-lib-demo-doc/references/OUTPUT_FORMAT.md +269 -0
  323. package/vendor/Server/Skills/rnoh-lib-demo-doc/references/QUALITY_CHECKLIST.md +98 -0
  324. package/vendor/Server/Skills/rnoh-lib-func-test/SKILL.md +337 -0
  325. package/vendor/Server/Skills/rnoh-lib-rnt-search/SKILL.md +722 -0
  326. package/vendor/Server/Skills/rnoh-lib-rnt-search/assets/PORT_REPORT_TEMPLATE.md +219 -0
  327. package/vendor/Server/Skills/rnoh-lib-rnt-search/references/DEMO_PORTING_GUIDE.md +345 -0
  328. package/vendor/Server/Skills/rnoh-lib-rnt-search/references/PORT_VERIFICATION.md +269 -0
  329. package/vendor/Server/Skills/rnoh-lib-rnt-search/references/RNT_PROJECT_STRUCTURE.md +173 -0
  330. package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/analyze-demo-deps.cjs +267 -0
  331. package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/detect-rnoh-version.cjs +174 -0
  332. package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/find-rnt-demo.sh +111 -0
  333. package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/port-demo.sh +186 -0
  334. package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/read-lib-meta.cjs +150 -0
  335. package/vendor/Server/Skills/rnoh-lib-test-align/SKILL.md +296 -0
  336. package/vendor/Server/Skills/rnoh-lib-test-align/references/jest-troubleshooting.md +371 -0
  337. package/vendor/Server/Skills/rnoh-lib-test-align/references/port-test-demo-guide.md +212 -0
  338. package/vendor/Server/Skills/rnoh-lib-test-align/references/runtime-troubleshooting.md +345 -0
  339. package/vendor/Server/Skills/rnoh-lib-test-align/references/unit-test-template.md +223 -0
  340. package/vendor/Server/Skills/rnoh-lib-test-align/scripts/port-test-demo.sh +1053 -0
  341. package/vendor/Server/Skills/rnoh-lib-version-diff/SKILL.md +255 -0
  342. package/vendor/Server/Skills/rnoh-lib-version-diff/references/OHOS_ADAPTATION.md +77 -0
  343. package/vendor/Server/Skills/rnoh-lib-version-diff/references/OHOS_API_LOOKUP.md +224 -0
  344. package/vendor/Server/Skills/rnoh-lib-version-diff/references/script-reference.md +174 -0
  345. package/vendor/Server/Skills/rnoh-lib-version-diff/scripts/detect-upstream-version.js +967 -0
  346. package/vendor/Server/Skills/rnoh-lib-version-diff/scripts/generate-diff.js +1798 -0
  347. package/vendor/Server/Skills/rnoh-lib-version-diff/scripts/package.json +5 -0
  348. package/vendor/Server/Skills/rnoh-lib-version-diff/templates/report-template.md +137 -0
  349. package/vendor/Server/Skills/rnoh-lib-xts-coverage/SKILL.md +145 -0
  350. package/vendor/Server/Skills/skill-generator/SKILL.md +365 -0
  351. package/vendor/Server/Skills/skill-generator/assets/SKILL_TEMPLATE.md +183 -0
  352. package/vendor/Server/Skills/skill-generator/references/COMPLIANCE_CHECKLIST.md +82 -0
  353. package/vendor/Server/Skills/skill-generator/references/KB_QUERY_GUIDE.md +110 -0
  354. package/vendor/Server/Skills/skill-generator/references/MCP_TOOL_DISCOVERY.md +122 -0
  355. package/vendor/Server/Skills/skill-generator/references/SKILL_SPEC.md +121 -0
  356. package/vendor/Server/Skills/skill-generator/scripts/validate-skill.cjs +259 -0
  357. package/vendor/Server/Skills/task-analysis/SKILL.md +234 -0
  358. package/vendor/Server/Skills/task-analysis/assets/OUTPUT_EXAMPLES.md +160 -0
  359. package/vendor/Server/Skills/task-analysis/references/ACCEPTANCE_CRITERIA_GUIDE.md +190 -0
  360. package/vendor/Server/Skills/task-analysis/references/ANALYSIS_SCHEMA.md +224 -0
  361. package/vendor/Server/Skills/task-analysis/references/INTEGRATION_CONTEXT.md +162 -0
  362. package/vendor/Server/Skills/task-analysis/references/LESSONS_LEARNED.md +55 -0
  363. package/vendor/Server/Skills/task-analysis/references/REPLAN_CONTEXT_GUIDE.md +126 -0
  364. package/vendor/Server/Skills/task-analysis/scripts/validate-analysis-output.sh +256 -0
  365. package/vendor/Server/Skills/task-decomposition/SKILL.md +529 -0
  366. package/vendor/Server/Skills/task-decomposition/assets/OUTPUT_EXAMPLES.md +451 -0
  367. package/vendor/Server/Skills/task-decomposition/references/ACCEPTANCE_CRITERIA_GUIDE.md +179 -0
  368. package/vendor/Server/Skills/task-decomposition/references/DEPENDENCY_GRAPH_GUIDE.md +152 -0
  369. package/vendor/Server/Skills/task-decomposition/references/INTEGRATION_CONTEXT.md +175 -0
  370. package/vendor/Server/Skills/task-decomposition/references/REPLAN_CONTEXT_GUIDE.md +195 -0
  371. package/vendor/Server/Skills/task-decomposition/references/TASK_DECOMPOSITION_TEMPLATES.md +226 -0
  372. package/vendor/Server/Skills/task-decomposition/scripts/list-available-skills.cjs +263 -0
  373. package/vendor/Server/Skills/task-decomposition/scripts/skill-blacklist.json +29 -0
  374. package/vendor/Server/Skills/task-decomposition/scripts/validate-decomposition-output.cjs +376 -0
  375. package/vendor/Server/Skills/task-decomposition/scripts/validate-param-consistency.cjs +259 -0
  376. package/vendor/Server/Skills/task-decomposition/scripts/validate-specified-skills.cjs +216 -0
  377. package/vendor/Server/Skills/task-decomposition/scripts/validate-step-graph.cjs +425 -0
  378. package/vendor/Server/Skills/tpc-cpp-check/SKILL.md +427 -0
  379. package/vendor/Server/Skills/tpc-cpp-check/references/CHECKLIST.md +214 -0
  380. package/vendor/Server/Skills/tpc-cpp-check/references/HPKBUILD_GUIDE.md +235 -0
  381. package/vendor/Server/Skills/tpc-cpp-check/references/REPORT_TEMPLATE.md +250 -0
  382. package/vendor/Server/TestCheck/TestCheck.js +775 -0
  383. package/vendor/Server/TestCheck/index.js +11 -0
  384. package/vendor/Server/library/McpToolGuide.js +280 -0
  385. package/vendor/Server/library/StatsService.js +127 -0
  386. package/vendor/Server/library/cstTime.js +16 -0
  387. package/vendor/Server/package.json +17 -0
  388. package/vendor/VERSION +3 -0
  389. package/workflows/pr-check.mjs +106 -0
@@ -0,0 +1,804 @@
1
+ import { createOpencodeClient } from '@opencode-ai/sdk';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import MessageArchive from '../../DbUse/MessageArchive.js';
5
+ import { nowCST } from '../../library/cstTime.js';
6
+ import { createLogger } from '../../Routes/library/logger.js';
7
+
8
+ /**
9
+ * OpenCode CLI 适配器
10
+ * 通过 @opencode-ai/sdk 与运行中的 opencode 服务通信,提供统一的 Session 管理接口。
11
+ *
12
+ * 依赖环境变量(可由 options 覆盖):
13
+ * OPENCODE_HOST - opencode 服务主机(默认 localhost)
14
+ * OPENCODE_PORT - opencode 服务端口(默认 4096)
15
+ */
16
+ class OpenCodeCLI {
17
+ /**
18
+ * @param {object} options
19
+ * @param {string} [options.host] - opencode 服务主机
20
+ * @param {string} [options.port] - opencode 服务端口
21
+ * @param {string} [options.baseUrl] - 完整 baseUrl,优先级高于 host/port
22
+ * @param {import('../../DbUse/MessageArchive.js').default} [options.archive] - 消息存档服务
23
+ */
24
+ constructor(options = {}) {
25
+ this.host = options.host || process.env.OPENCODE_HOST || 'localhost';
26
+ this.port = options.port || process.env.OPENCODE_PORT || '4096';
27
+ this.baseUrl = options.baseUrl || `http://${this.host}:${this.port}`;
28
+ this.client = null;
29
+ // 消息存档:用于保留对话消息、判断 opencode 是否长时间无新响应(防卡死)
30
+ this.archive = options.archive ?? new MessageArchive();
31
+ // 记录各 session 首次进入 busy/retry 的时间戳(ms),用于"busy 停滞兜底"判定
32
+ this._busySince = {};
33
+ this._init();
34
+ }
35
+
36
+ // ─── 初始化 ────────────────────────────────────────────────────────────────
37
+
38
+ _init() {
39
+ try {
40
+ this.client = createOpencodeClient({ baseUrl: this.baseUrl });
41
+ this._log('info', `已连接至 ${this.baseUrl}`);
42
+ } catch (error) {
43
+ this._log('error', `初始化失败: ${error.message}`);
44
+ throw error;
45
+ }
46
+ }
47
+
48
+ // ─── 运行状态检查 ──────────────────────────────────────────────────────────
49
+
50
+ async checkHealth() {
51
+ try {
52
+ // 轻量健康检查:只调用 session.list() 验证连通性
53
+ // 不再为每个 session 拉取全量消息(原 listSessions 会拉所有 session 的所有消息)
54
+ await this.client.session.list();
55
+ return { status: 'ok', message: 'OpenCode CLI is healthy', target: this.baseUrl };
56
+ } catch (error) {
57
+ this._log('warn', `checkHealth: 连接失败 — ${error.message}`);
58
+ return {
59
+ status: 'error',
60
+ message: `Health check failed: ${error.message}`,
61
+ error: error.message
62
+ };
63
+ }
64
+ }
65
+
66
+ // ─── Session 管理 ──────────────────────────────────────────────────────────
67
+
68
+ /**
69
+ * 获取所有 Session(附带状态)
70
+ *
71
+ * 优化:不再为每个 session 拉取全量消息来判断状态。
72
+ * 仅返回 session 元信息,状态通过 checkSessionStatus 按需查询。
73
+ * 原实现对 N 个 session 发起 N 个并发 HTTP 请求拉全量消息,
74
+ * session 数量多时会压垮 OpenCode 服务。
75
+ */
76
+ async listSessions() {
77
+ this._log('info', 'listSessions 开始');
78
+ try {
79
+ const sessions = await this.client.session.list();
80
+ // 只返回 session 元信息,不拉取消息
81
+ const result = sessions.data.map(s => ({ ...s, status: 'unknown' }));
82
+ this._log('info', `listSessions 完成,共 ${result.length} 个 Session`);
83
+ return result;
84
+ } catch (error) {
85
+ this._log('error', `listSessions 失败: ${error.message}`);
86
+ throw new Error(`Failed to list sessions: ${error.message}`);
87
+ }
88
+ }
89
+
90
+ /**
91
+ * 获取指定 Session(含状态)
92
+ *
93
+ * 使用 session.get() 获取元信息 + session.status() 获取运行状态,
94
+ * 不再拉取全量消息。
95
+ *
96
+ * @param {string} sessionId
97
+ * @returns {Promise<object>} Session 元信息(含 status 字段)
98
+ */
99
+ async getSession(sessionId) {
100
+ this._log('info', `getSession id=${sessionId}`);
101
+ try {
102
+ const [sessionRes, statusMap] = await Promise.all([
103
+ this.client.session.get({ path: { id: sessionId } }),
104
+ this.client.session.status({ query: {} }).catch(() => ({ data: {} }))
105
+ ]);
106
+ const session = sessionRes.data;
107
+ const rawStatus = statusMap.data?.[sessionId];
108
+ const status = this._mapSessionStatus(rawStatus);
109
+ const result = { ...session, status };
110
+ this._log('info', `getSession 完成,status=${status}`);
111
+ return result;
112
+ } catch (error) {
113
+ this._log('error', `getSession 失败 id=${sessionId}: ${error.message}`);
114
+ throw new Error(`Failed to get session: ${error.message}`);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * 将 opencode SessionStatus 映射为统一状态
120
+ * busy → running, retry → running, idle → idle, 其他 → unknown
121
+ */
122
+ _mapSessionStatus(rawStatus) {
123
+ if (!rawStatus || !rawStatus.type) return 'unknown';
124
+ switch (rawStatus.type) {
125
+ case 'busy':
126
+ case 'retry':
127
+ return 'running';
128
+ case 'idle':
129
+ return 'idle';
130
+ default:
131
+ return 'unknown';
132
+ }
133
+ }
134
+
135
+ /**
136
+ * 删除 Session
137
+ * @param {string} sessionId
138
+ */
139
+ async deleteSession(sessionId) {
140
+ this._log('info', `deleteSession id=${sessionId}`);
141
+ try {
142
+ const result = await this.client.session.delete({ path: { id: sessionId } });
143
+ this._log('info', `deleteSession 成功 id=${sessionId}`);
144
+ return result.data;
145
+ } catch (error) {
146
+ this._log('error', `deleteSession 失败 id=${sessionId}: ${error.message}`);
147
+ throw new Error(`Failed to delete session: ${error.message}`);
148
+ }
149
+ // 保留本地存档文件,不删除(用于事后审计/对比)
150
+ }
151
+
152
+ /**
153
+ * 终止 Session(中断正在运行的任务)
154
+ * @param {string} sessionId
155
+ */
156
+ async abortSession(sessionId) {
157
+ this._log('info', `abortSession id=${sessionId}`);
158
+ try {
159
+ const result = await this.client.session.abort({ path: { id: sessionId } });
160
+ this._log('info', `abortSession 成功 id=${sessionId}`);
161
+ return result.data;
162
+ } catch (error) {
163
+ this._log('error', `abortSession 失败 id=${sessionId}: ${error.message}`);
164
+ throw new Error(`Failed to abort session: ${error.message}`);
165
+ }
166
+ }
167
+
168
+ /**
169
+ * 向指定 Session 发送消息
170
+ * @param {string} sessionId
171
+ * @param {string} message
172
+ */
173
+ async sendMessage(sessionId, message) {
174
+ try {
175
+ await this.client.session.promptAsync({
176
+ path: { id: sessionId },
177
+ body: {
178
+ parts: [{ type: 'text', text: message }],
179
+ noReply: false
180
+ },
181
+ url: `/session/${sessionId}/prompt_async`
182
+ });
183
+ // 用户消息不由这里归档,统一由 checkSessionStatus / getSessionMessages
184
+ // 从远端拉取归档,确保所有消息用 opencode id 去重,避免重复
185
+ this._log('info', `sendMessage 成功 id=${sessionId}`);
186
+ return { success: true };
187
+ } catch (error) {
188
+ this._log('error', `sendMessage 失败 id=${sessionId}: ${error.message}`);
189
+ throw new Error(`Failed to send message: ${error.message}`);
190
+ }
191
+ }
192
+
193
+ /**
194
+ * 向指定 Session 发送消息并同步等待 AI 回复完成
195
+ *
196
+ * 使用 opencode SDK 的 session.prompt()(同步版本),发送消息后阻塞等待
197
+ * AI 生成完整回复,然后直接返回 AssistantMessage 及其 parts。
198
+ *
199
+ * 与 sendMessage 的区别:
200
+ * sendMessage → promptAsync,发送后立即返回,不等 AI 回复(fire-and-forget)
201
+ * sendAndWaitMessage → prompt,发送后等待 AI 回复完成再返回
202
+ *
203
+ * 适用场景:
204
+ * - 需要立即获取 AI 回复内容,不适合轮询等待
205
+ * - 简单问答、单轮对话
206
+ * - 调用方需要同步拿到结果继续处理
207
+ *
208
+ * ⚠️ 注意:AI 回复可能耗时较长(几十秒到几分钟),调用方需设置合理的超时。
209
+ *
210
+ * @param {string} sessionId
211
+ * @param {string} message - 发送的消息
212
+ * @returns {Promise<{ success: boolean, response: object, content: string }>}
213
+ * response: opencode 返回的完整 AssistantMessage(含 info + parts)
214
+ * content: AI 回复的文本内容(从 parts 中提取拼接)
215
+ */
216
+ async sendAndWaitMessage(sessionId, message) {
217
+ try {
218
+ const result = await this.client.session.prompt({
219
+ path: { id: sessionId },
220
+ body: {
221
+ parts: [{ type: 'text', text: message }],
222
+ noReply: false
223
+ },
224
+ url: `/session/${sessionId}/message`
225
+ });
226
+ const assistantMsg = result.data;
227
+ // 从 parts 中提取文本内容
228
+ const textParts = (assistantMsg.parts || []).filter(p => p.type === 'text');
229
+ const content = textParts.map(p => p.text).join('\n');
230
+ this._log('info',
231
+ `sendAndWaitMessage 成功 id=${sessionId}, ` +
232
+ `回复长度=${content.length}字, finish=${assistantMsg.info?.finish ?? 'N/A'}`);
233
+ // 用户消息 + AI 回复均不由这里归档,统一由 getSessionMessages
234
+ // 从远端拉取归档,确保用 opencode id 去重
235
+ return {
236
+ success: true,
237
+ response: assistantMsg,
238
+ content
239
+ };
240
+ } catch (error) {
241
+ this._log('error', `sendAndWaitMessage 失败 id=${sessionId}: ${error.message}`);
242
+ throw new Error(`Failed to send and wait message: ${error.message}`);
243
+ }
244
+ }
245
+
246
+ /**
247
+ * 向指定 Session 注入提示词/上下文(不触发 AI 响应)
248
+ *
249
+ * 利用 opencode SDK 的 noReply: true 能力,将文本作为 UserMessage
250
+ * 注入对话历史,但不会触发 AI 生成回复。
251
+ *
252
+ * 适用场景:
253
+ * - 对话过程中动态补充上下文、规则、指令
254
+ * - 插件向会话注入参考信息,不打断当前 AI 任务
255
+ * - 追加系统级约束(如代码规范、输出格式要求)
256
+ *
257
+ * 与 sendMessage 的区别:
258
+ * sendMessage → noReply: false,发送后 AI 会生成回复
259
+ * injectPrompt → noReply: true,仅注入上下文,AI 不回复
260
+ *
261
+ * @param {string} sessionId
262
+ * @param {string} message - 要注入的提示词/上下文
263
+ * @returns {Promise<{ success: boolean }>}
264
+ */
265
+ async injectPrompt(sessionId, message) {
266
+ this._log('debug', `injectPrompt id=${sessionId}`);
267
+ this._log('debug', ` message (前100字): ${message.slice(0, 100)}${message.length > 100 ? '...' : ''}`);
268
+ try {
269
+ await this.client.session.promptAsync({
270
+ path: { id: sessionId },
271
+ body: {
272
+ parts: [{ type: 'text', text: message }],
273
+ noReply: true
274
+ },
275
+ url: `/session/${sessionId}/prompt_async`
276
+ });
277
+ // 注入的上下文消息不由这里归档,统一由 getSessionMessages
278
+ // 从远端拉取归档,确保用 opencode id 去重
279
+ this._log('info', `injectPrompt 成功 id=${sessionId}(已注入上下文,不触发 AI 响应)`);
280
+ return { success: true };
281
+ } catch (error) {
282
+ this._log('error', `injectPrompt 失败 id=${sessionId}: ${error.message}`);
283
+ throw new Error(`Failed to inject prompt: ${error.message}`);
284
+ }
285
+ }
286
+
287
+ /**
288
+ * 创建新 Session,可选附带初始提示词
289
+ * @param {string} title - Session 标题
290
+ * @param {string} [prompt] - 初始提示词(可选)
291
+ * @param {object} [options]
292
+ * @param {string} [options.cwd] - 工作目录(通过 opencode session.create 的 query.directory 设定)
293
+ */
294
+ async startSession(title, prompt, options = {}) {
295
+ const cwd = options.cwd;
296
+ this._log('info', `startSession title="${title}"${cwd ? ` cwd="${cwd}"` : ''}`);
297
+
298
+ // 前置检查:如果指定了 cwd,确保目录存在
299
+ // opencode session.create 不会检查目录是否存在,但 promptAsync 时会
300
+ // realPath 检查,目录不存在时静默失败(返回 204,tokens=0+0)。
301
+ if (cwd) {
302
+ try {
303
+ const stats = fs.statSync(cwd);
304
+ if (!stats.isDirectory()) {
305
+ throw new Error(`cwd 不是目录: ${cwd}`);
306
+ }
307
+ } catch (statErr) {
308
+ if (statErr.code === 'ENOENT') {
309
+ this._log('info', `startSession: cwd 不存在,自动创建 ${cwd}`);
310
+ fs.mkdirSync(cwd, { recursive: true });
311
+ } else {
312
+ throw new Error(`startSession: cwd 检查失败: ${statErr.message}`);
313
+ }
314
+ }
315
+ }
316
+
317
+ try {
318
+ // opencode SDK session.create 支持 query.directory 参数,
319
+ // 用于指定该 Session 的工作目录(git clone、文件读写等操作均在此目录下执行)
320
+ const createParams = { body: { title } };
321
+ if (cwd) {
322
+ createParams.query = { directory: cwd };
323
+ }
324
+ const session = await this.client.session.create(createParams);
325
+ const sessionId = session.data.id;
326
+ this._log('info', `Session 已创建 id=${sessionId}${cwd ? ` directory="${cwd}"` : ''}`);
327
+
328
+ // 初始化存档元信息
329
+ await this.archive.patchMeta(sessionId, {
330
+ sessionId,
331
+ title,
332
+ cliType: 'opencode',
333
+ createdAt: nowCST(),
334
+ status: 'idle'
335
+ }).catch(e => {
336
+ this._log('warn', `startSession: 初始化存档 meta 失败 id=${sessionId}: ${e.message}`);
337
+ });
338
+
339
+ if (prompt) {
340
+ await this.client.session.promptAsync({
341
+ path: { id: sessionId },
342
+ body: {
343
+ parts: [{ type: 'text', text: prompt }],
344
+ noReply: false
345
+ },
346
+ url: `/session/${sessionId}/prompt_async`
347
+ });
348
+ // 初始 prompt 的用户消息不由这里归档,统一由 checkSessionStatus /
349
+ // getSessionMessages 从远端拉取归档,确保用 opencode id 去重
350
+ await this.archive.patchMeta(sessionId, { status: 'running' }).catch(() => {});
351
+ }
352
+
353
+ return {
354
+ sessionId,
355
+ action: 'create',
356
+ message: prompt ? '已创建新 Session 并开始执行' : '已创建新 Session'
357
+ };
358
+ } catch (error) {
359
+ this._log('error', `startSession 失败: ${error.message}`);
360
+ throw new Error(`Failed to start session: ${error.message}`);
361
+ }
362
+ }
363
+
364
+ /**
365
+ * 查询 Session 当前状态
366
+ * @param {string} sessionId
367
+ * @returns {{ status: 'completed'|'running'|'unknown', lastMessage?: object }}
368
+ */
369
+ async checkSessionStatus(sessionId) {
370
+ try {
371
+ // ── 快路径:先查 session.status(),busy/retry 时直接返回 running,不拉消息 ──
372
+ // session.status() 返回 {[id]: {type: "busy"|"idle"|"retry"}},极轻量
373
+ // 只有 idle 时才需要拉最后一条消息检查 finish/error 判断 completed/error
374
+ let statusMap;
375
+ try {
376
+ statusMap = await this.client.session.status({ query: {} });
377
+ } catch (e) {
378
+ this._log('warn', `checkSessionStatus: session.status() 失败,降级为拉消息: ${e.message}`);
379
+ }
380
+ const rawStatus = statusMap?.data?.[sessionId];
381
+ if (rawStatus && (rawStatus.type === 'busy' || rawStatus.type === 'retry')) {
382
+ // AI 正在生成,无需拉消息(快路径)
383
+ // 但若 busy 持续过久(超过停滞阈值),则降级拉最后一条消息兜底:
384
+ // opencode 的 session.status() 在任务实际完成后仍可能长时间保持 busy,
385
+ // 仅依赖 status 会永远无法识别已完成的 finish:"stop" 消息,导致上层轮询超时。
386
+ const now = Date.now();
387
+ if (!this._busySince[sessionId]) {
388
+ this._busySince[sessionId] = now;
389
+ }
390
+ // 复用存档的卡死阈值(默认 5 分钟),作为 busy 停滞兜底的超时判定
391
+ const stallThresholdMs = this.archive?._store?.stallThresholdMs ?? 5 * 60 * 1000;
392
+ const busyDurationMs = now - this._busySince[sessionId];
393
+
394
+ if (busyDurationMs >= stallThresholdMs) {
395
+ // busy 停滞超阈值 → 检查消息层,识别是否实际已完成
396
+ this._log('warn',
397
+ `checkSessionStatus: session ${sessionId} busy 持续 ${Math.round(busyDurationMs / 1000)}s,降级检查消息层`);
398
+ const fallback = await this._checkMessageLayer(sessionId);
399
+ if (fallback) {
400
+ return fallback;
401
+ }
402
+ }
403
+
404
+ const checkRes = await this.archive.recordCheck(sessionId, {
405
+ lastMessageId: null,
406
+ status: 'running'
407
+ }).catch(() => ({ stalled: false, stallDurationMs: null, hasNewMessage: false }));
408
+ return {
409
+ status: checkRes.stalled ? 'stalled' : 'running',
410
+ stallDurationMs: checkRes.stallDurationMs,
411
+ stalled: !!checkRes.stalled,
412
+ hasNewMessage: false
413
+ };
414
+ }
415
+ // 非 busy/retry:清除停滞计时,避免脏状态
416
+ delete this._busySince[sessionId];
417
+
418
+ // ── idle 或 status 查询失败:拉最后 1 条消息判断 completed/error/running ──
419
+ const messages = await this.client.session.messages({
420
+ path: { id: sessionId },
421
+ query: { limit: 1 },
422
+ });
423
+ const data = messages.data;
424
+
425
+ if (!data || data.length === 0) {
426
+ return { status: 'unknown' };
427
+ }
428
+
429
+ const lastMessage = data[data.length - 1];
430
+
431
+ // 出错 / 被中断
432
+ if (lastMessage.info?.error) {
433
+ const errName = lastMessage.info.error.name ?? 'UnknownError';
434
+ this._log('warn', `checkSessionStatus: 检测到错误 ${errName},status=error`);
435
+ await this.archive.recordCheck(sessionId, {
436
+ lastMessageId: this._msgDedupeKey(lastMessage),
437
+ status: 'error'
438
+ }).catch(() => {});
439
+ // 错误结束时也自动归档全量消息
440
+ await this._autoArchive(sessionId, 'error');
441
+ return { status: 'error', error: lastMessage.info.error, lastMessage };
442
+ }
443
+
444
+ // 正常完成
445
+ const isCompleted = this._isCompletedMessage(lastMessage);
446
+
447
+ const status = isCompleted ? 'completed' : 'running';
448
+
449
+ // 状态检查 + 卡死检测
450
+ const dedupeKey = this._msgDedupeKey(lastMessage);
451
+ const checkRes = await this.archive.recordCheck(sessionId, {
452
+ lastMessageId: dedupeKey,
453
+ status
454
+ }).catch(() => ({ stalled: false, stallDurationMs: null, hasNewMessage: false }));
455
+
456
+ // 若检测到停滞(running 状态下长时间无新 assistant 消息)
457
+ const finalStatus = checkRes.stalled ? 'stalled' : status;
458
+ if (checkRes.stalled) {
459
+ this._log('warn',
460
+ `checkSessionStatus: 检测到停滞 id=${sessionId}, 已 ${Math.round((checkRes.stallDurationMs || 0) / 1000)}s 无新响应`);
461
+ }
462
+
463
+ // session 完成时自动归档全量消息(写入 .jsonl)
464
+ if (isCompleted) {
465
+ await this._autoArchive(sessionId, 'completed');
466
+ }
467
+
468
+ return {
469
+ status: finalStatus,
470
+ lastMessage,
471
+ // 卡死检测相关字段
472
+ stallDurationMs: checkRes.stallDurationMs,
473
+ stalled: !!checkRes.stalled,
474
+ hasNewMessage: !!checkRes.hasNewMessage
475
+ };
476
+ } catch (error) {
477
+ this._log('warn', `checkSessionStatus 异常 id=${sessionId}: ${error.message}`);
478
+ return { status: 'unknown' };
479
+ }
480
+ }
481
+
482
+ /**
483
+ * 判断 opencode 消息是否为正常完成(finish='stop' 且含 text part)。
484
+ *
485
+ * 供 checkSessionStatus 的 idle 分支与 busy 停滞兜底分支共用,避免判定逻辑漂移。
486
+ *
487
+ * @param {object} lastMessage - opencode 原始消息
488
+ * @returns {boolean}
489
+ * @private
490
+ */
491
+ _isCompletedMessage(lastMessage) {
492
+ return Boolean(
493
+ lastMessage &&
494
+ lastMessage.info?.finish === 'stop' &&
495
+ Array.isArray(lastMessage.parts) &&
496
+ lastMessage.parts.some(p => p.type === 'text')
497
+ );
498
+ }
499
+
500
+ /**
501
+ * 从消息层检查 session 是否实际已完成/出错。
502
+ *
503
+ * 用于 busy/retry 停滞兜底:拉取最后 1 条消息,若已 finish='stop' 或 info.error,
504
+ * 则返回对应的 completed/error 状态;否则返回 null(表示任务确实仍在运行)。
505
+ *
506
+ * 注意:本方法不更新 _busySince——由调用方在返回非 completed/error 时继续累积。
507
+ *
508
+ * @param {string} sessionId
509
+ * @returns {Promise<object|null>} 已终态时返回状态对象;仍在运行返回 null
510
+ * @private
511
+ */
512
+ async _checkMessageLayer(sessionId) {
513
+ try {
514
+ const messages = await this.client.session.messages({
515
+ path: { id: sessionId },
516
+ query: { limit: 1 },
517
+ });
518
+ const data = messages.data;
519
+ if (!data || data.length === 0) {
520
+ return null;
521
+ }
522
+
523
+ const lastMessage = data[data.length - 1];
524
+
525
+ // 出错 / 被中断
526
+ if (lastMessage.info?.error) {
527
+ const errName = lastMessage.info.error.name ?? 'UnknownError';
528
+ this._log('warn', `checkSessionStatus: busy 兜底检测到错误 ${errName},status=error`);
529
+ await this.archive.recordCheck(sessionId, {
530
+ lastMessageId: this._msgDedupeKey(lastMessage),
531
+ status: 'error'
532
+ }).catch(() => {});
533
+ await this._autoArchive(sessionId, 'error');
534
+ delete this._busySince[sessionId];
535
+ return { status: 'error', error: lastMessage.info.error, lastMessage };
536
+ }
537
+
538
+ // 正常完成(finish='stop' 且含 text)
539
+ if (this._isCompletedMessage(lastMessage)) {
540
+ this._log('info', `checkSessionStatus: busy 兜底确认 session ${sessionId} 已完成`);
541
+ const dedupeKey = this._msgDedupeKey(lastMessage);
542
+ await this.archive.recordCheck(sessionId, {
543
+ lastMessageId: dedupeKey,
544
+ status: 'completed'
545
+ }).catch(() => {});
546
+ await this._autoArchive(sessionId, 'completed');
547
+ delete this._busySince[sessionId];
548
+ return {
549
+ status: 'completed',
550
+ lastMessage,
551
+ stallDurationMs: null,
552
+ stalled: false,
553
+ hasNewMessage: true
554
+ };
555
+ }
556
+
557
+ // 仍在运行:刷新 busySince(避免一次长消息生成被误判),返回 null 表示继续等待
558
+ this._busySince[sessionId] = Date.now();
559
+ return null;
560
+ } catch (err) {
561
+ this._log('warn', `checkSessionStatus: busy 兜底检查消息失败 id=${sessionId}: ${err.message}`);
562
+ return null;
563
+ }
564
+ }
565
+
566
+ /**
567
+ * 生成 opencode 消息的去重键
568
+ * 优先用消息 id(全局唯一);无 id 时用 role+finish+时间+内容文本长度
569
+ * 注意:不使用 parts 长度,因为 checkSessionStatus(limit=1) 与 getSessionMessages(全量)
570
+ * 返回的 parts 结构可能不同,导致同一条消息算出不同去重键而重复归档。
571
+ */
572
+ _msgDedupeKey(msg) {
573
+ const id = msg.id ?? msg.info?.id;
574
+ if (id) return String(id);
575
+ const role = msg.info?.role ?? 'unknown';
576
+ const finish = msg.info?.finish ?? '';
577
+ const ts = msg.info?.time?.created ?? msg.timestamp ?? '';
578
+ const textParts = (msg.parts || []).filter(p => p.type === 'text');
579
+ const content = textParts.map(p => p.text).join('\n');
580
+ return `${role}:${finish}:${ts}:${content.length}`;
581
+ }
582
+
583
+ /**
584
+ * 将 opencode 原始消息转换为精简归档格式
585
+ *
586
+ * 只保留核心对话字段(role / content / finish / timestamp / id),
587
+ * 去掉 raw 原始结构(含 parts / tokens / cost / reasoning 等),
588
+ * 使归档文件轻量可读,关注实际发生了哪些对话。
589
+ */
590
+ _toArchiveMessage(msg) {
591
+ const role = msg.info?.role ?? 'unknown';
592
+ const textParts = (msg.parts || []).filter(p => p.type === 'text');
593
+ const content = textParts.map(p => p.text).join('\n');
594
+ // opencode 时间在 info.time.created(epoch 毫秒),非 ISO 字符串
595
+ const createdMs = msg.info?.time?.created;
596
+ const timestamp = createdMs != null
597
+ ? nowCST(createdMs)
598
+ : (msg.timestamp ?? nowCST());
599
+ return {
600
+ id: msg.id ?? msg.info?.id,
601
+ role,
602
+ content,
603
+ finish: msg.info?.finish ?? null,
604
+ timestamp
605
+ };
606
+ }
607
+
608
+ /**
609
+ * 自动归档 — session 完成或出错时全量拉取消息并写入 .jsonl
610
+ *
611
+ * checkSessionStatus 平时只用 limit=1 查状态(不归档),
612
+ * 但当检测到 session 已结束(completed / error)时,
613
+ * 应自动全量拉取消息归档,确保 .jsonl 文件生成。
614
+ *
615
+ * 归档采用 appendMessages 增量去重,重复调用安全无副作用。
616
+ *
617
+ * @param {string} sessionId
618
+ * @param {'completed'|'error'} reason - 触发归档的原因
619
+ * @private
620
+ */
621
+ async _autoArchive(sessionId, reason) {
622
+ try {
623
+ const messages = await this.client.session.messages({ path: { id: sessionId } });
624
+ const data = messages.data || [];
625
+ const archRes = await this.archive.appendMessages(
626
+ sessionId,
627
+ data.map(m => this._toArchiveMessage(m))
628
+ );
629
+ this._log('info',
630
+ `自动归档 id=${sessionId} reason=${reason} — appended=${archRes.appended} skipped=${archRes.skipped}`);
631
+ } catch (e) {
632
+ this._log('warn', `自动归档失败 id=${sessionId} reason=${reason}: ${e.message}`);
633
+ }
634
+ }
635
+
636
+ /**
637
+ * 获取 Session 消息历史
638
+ * @param {string} sessionId
639
+ */
640
+ async getSessionMessages(sessionId) {
641
+ this._log('info', `getSessionMessages id=${sessionId}`);
642
+ try {
643
+ const messages = await this.client.session.messages({ path: { id: sessionId } });
644
+ const data = messages.data || [];
645
+ // 增量归档全量消息(首次拉取或补档),await 确保调用方能立即读取归档结果
646
+ const archRes = await this.archive.appendMessages(
647
+ sessionId,
648
+ data.map(m => this._toArchiveMessage(m))
649
+ ).catch(e => {
650
+ this._log('warn', `getSessionMessages: 归档失败 id=${sessionId}: ${e.message}`);
651
+ return { appended: 0, skipped: 0 };
652
+ });
653
+ this._log('debug', `getSessionMessages: 归档 appended=${archRes.appended} skipped=${archRes.skipped}`);
654
+ return data;
655
+ } catch (error) {
656
+ this._log('error', `getSessionMessages 失败 id=${sessionId}: ${error.message}`);
657
+ throw new Error(`Failed to get session messages: ${error.message}`);
658
+ }
659
+ }
660
+
661
+ /**
662
+ * 实时查看当前对话消息(运行中安全调用)
663
+ *
664
+ * 从远端拉取当前已有消息并转为精简格式返回,**不写入本地存档**。
665
+ * 适用于对话进行中查看 "目前聊了什么",不影响后续归档去重。
666
+ *
667
+ * @param {string} sessionId
668
+ * @returns {Promise<Array<{id,role,content,finish,timestamp}>>}
669
+ */
670
+ async getLiveMessages(sessionId) {
671
+ this._log('info', `getLiveMessages id=${sessionId}`);
672
+ try {
673
+ const messages = await this.client.session.messages({ path: { id: sessionId } });
674
+ const data = messages.data || [];
675
+ return data.map(m => this._toArchiveMessage(m));
676
+ } catch (error) {
677
+ this._log('error', `getLiveMessages 失败 id=${sessionId}: ${error.message}`);
678
+ throw new Error(`Failed to get live messages: ${error.message}`);
679
+ }
680
+ }
681
+
682
+ /**
683
+ * 导出完整对话(合并远端 + 本地,支持运行中 / 已结束)
684
+ *
685
+ * 流程:
686
+ * 1. 从远端拉取全量消息(运行中也能拿到已生成的部分)
687
+ * 2. 增量归档到本地 jsonl(去重,补全运行中缺失的消息)
688
+ * 3. 合并本地已归档消息,按 seq 排序
689
+ * 4. 按 format 返回结构化结果
690
+ *
691
+ * @param {string} sessionId
692
+ * @param {object} [opts]
693
+ * @param {'json'|'markdown'} [opts.format='json'] - 导出格式
694
+ * @returns {Promise<object|string>}
695
+ * format='json' → { sessionId, meta, messages: [...] }
696
+ * format='markdown' → Markdown 字符串
697
+ */
698
+ async exportSession(sessionId, opts = {}) {
699
+ const format = opts.format || 'json';
700
+ this._log('info', `exportSession id=${sessionId} format=${format}`);
701
+ try {
702
+ // 1. 远端拉取全量消息
703
+ const messages = await this.client.session.messages({ path: { id: sessionId } });
704
+ const data = messages.data || [];
705
+
706
+ // 2. 增量归档(去重补档,运行中也能持久化已有消息)
707
+ const archRes = await this.archive.appendMessages(
708
+ sessionId,
709
+ data.map(m => this._toArchiveMessage(m))
710
+ ).catch(e => {
711
+ this._log('warn', `exportSession: 归档失败 id=${sessionId}: ${e.message}`);
712
+ return { appended: 0, skipped: 0 };
713
+ });
714
+ this._log('debug', `exportSession: 归档 appended=${archRes.appended} skipped=${archRes.skipped}`);
715
+
716
+ // 3. 读本地归档(合并后按 seq 排序,确保完整且有序)
717
+ const archivedMessages = await this.archive.readMessages(sessionId);
718
+ const meta = await this.archive.readMeta(sessionId);
719
+ const messages_sorted = archivedMessages.sort((a, b) => (a.seq || 0) - (b.seq || 0));
720
+
721
+ // 4. 按格式输出
722
+ if (format === 'markdown') {
723
+ return this._toMarkdown(meta, messages_sorted);
724
+ }
725
+ return {
726
+ sessionId,
727
+ meta,
728
+ messages: messages_sorted
729
+ };
730
+ } catch (error) {
731
+ this._log('error', `exportSession 失败 id=${sessionId}: ${error.message}`);
732
+ throw new Error(`Failed to export session: ${error.message}`);
733
+ }
734
+ }
735
+
736
+ /**
737
+ * 将对话消息渲染为 Markdown 格式
738
+ * @param {object} meta - Session 元信息
739
+ * @param {Array} messages - 已归档消息列表
740
+ * @returns {string}
741
+ */
742
+ _toMarkdown(meta, messages) {
743
+ const lines = [];
744
+ lines.push(`# ${meta.title || meta.sessionId}`);
745
+ lines.push('');
746
+ lines.push(`> **Session ID**: ${meta.sessionId} `);
747
+ lines.push(`> **CLI 类型**: ${meta.cliType || 'N/A'} `);
748
+ lines.push(`> **创建时间**: ${meta.createdAt || 'N/A'} `);
749
+ lines.push(`> **状态**: ${meta.status || 'N/A'} `);
750
+ lines.push(`> **消息数**: ${messages.length} `);
751
+ lines.push('');
752
+ lines.push('---');
753
+ lines.push('');
754
+ for (const msg of messages) {
755
+ const roleLabel = msg.role === 'user' ? '🧑 User' : (msg.role === 'assistant' ? '🤖 Assistant' : msg.role);
756
+ const ts = msg.timestamp || '';
757
+ lines.push(`### ${roleLabel}`);
758
+ lines.push(`*${ts}*`);
759
+ lines.push('');
760
+ lines.push(msg.content || '(empty)');
761
+ lines.push('');
762
+ }
763
+ return lines.join('\n');
764
+ }
765
+
766
+ /**
767
+ * 读取本地已归档的消息(不请求远端,用于事后审计/对比)
768
+ * @param {string} sessionId
769
+ * @returns {Promise<Array<object>>}
770
+ */
771
+ async getArchivedMessages(sessionId) {
772
+ return this.archive.readMessages(sessionId);
773
+ }
774
+
775
+ /**
776
+ * 读取本地存档元信息(含 lastResponseAt / archivedCount 等)
777
+ * @param {string} sessionId
778
+ * @returns {Promise<object>}
779
+ */
780
+ async getArchiveMeta(sessionId) {
781
+ return this.archive.readMeta(sessionId);
782
+ }
783
+
784
+ // ─── 内部方法 ──────────────────────────────────────────────────────────────
785
+
786
+ _log(level, msg) {
787
+ const logger = createLogger('OpenCodeCLI');
788
+ switch (level) {
789
+ case 'error':
790
+ logger.error(`❌ ${msg}`);
791
+ break;
792
+ case 'warn':
793
+ logger.warn(`⚠️ ${msg}`);
794
+ break;
795
+ case 'debug':
796
+ logger.debug(`🔍 ${msg}`);
797
+ break;
798
+ default:
799
+ logger.info(`ℹ️ ${msg}`);
800
+ }
801
+ }
802
+ }
803
+
804
+ export default OpenCodeCLI;