@ohos-cpf/3rdloop 0.0.8 → 0.0.10

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 (220) hide show
  1. package/README.md +43 -0
  2. package/lib/cli.js +38 -5
  3. package/lib/doctor.js +111 -10
  4. package/lib/knowledge.js +440 -0
  5. package/lib/mcp.js +498 -0
  6. package/package.json +6 -2
  7. package/vendor/Archive/data/.index/meta.json +7 -0
  8. package/vendor/Archive/data/.index/search.db +0 -0
  9. package/vendor/Archive/data/docs/experiences/arkts-check-tool-pitfalls-baseline-comparison.md +13 -0
  10. package/vendor/Archive/data/docs/experiences/arkts-deep-path-import-recognition.md +31 -0
  11. package/vendor/Archive/data/docs/experiences/arkts-demo-coverage-entry-file-case-mismatch.md +25 -0
  12. package/vendor/Archive/data/docs/experiences/arkts-demo-coverage-import-trailing-slash.md +20 -0
  13. package/vendor/Archive/data/docs/experiences/arkts-library-source-files-may-be-ts.md +18 -0
  14. package/vendor/Archive/data/docs/experiences/arkts-typedarray-buffer-interface-cast-compile-fixes.md +36 -0
  15. package/vendor/Archive/data/docs/experiences/arkts-xts-compile-error-clustering-fix.md +24 -0
  16. package/vendor/Archive/data/docs/experiences/arkts-xts-doc-expected-value-runtime-probe.md +35 -0
  17. package/vendor/Archive/data/docs/experiences/arkts-xts-fixture-rawfile-testability-injection.md +33 -0
  18. package/vendor/Archive/data/docs/experiences/code-linter-chinese-comment-false-positive.md +16 -0
  19. package/vendor/Archive/data/docs/experiences/esobject-new-expression-variable-tracking.md +33 -0
  20. package/vendor/Archive/data/docs/experiences/filesystem-case-sensitivity-module-resolution.md +31 -0
  21. package/vendor/Archive/data/docs/experiences/gitcode-clone-redirect-warning-normal.md +13 -0
  22. package/vendor/Archive/data/docs/experiences/kn_msgvq1w585ec8319.md +77 -0
  23. package/vendor/Archive/data/docs/experiences/kn_msovnm6rd46de72c.md +98 -0
  24. package/vendor/Archive/data/docs/experiences/kn_mspt8vntfe708576.md +87 -0
  25. package/vendor/Archive/data/docs/experiences/kn_mspu1ei77adbbb48.md +133 -0
  26. package/vendor/Archive/data/docs/experiences/kn_mspubgak8d30bfce.md +128 -0
  27. package/vendor/Archive/data/docs/experiences/kn_mspug2de3cb1f7c3.md +115 -0
  28. package/vendor/Archive/data/docs/experiences/kn_skill_opt_001.md +38 -0
  29. package/vendor/Archive/data/docs/experiences/loop-artifacts-verification-evidence-triangle.md +19 -0
  30. package/vendor/Archive/data/docs/experiences/macos-bash-replace-build-ps1.md +19 -0
  31. package/vendor/Archive/data/docs/experiences/macos-bsd-diff-q-illegal-option.md +15 -0
  32. package/vendor/Archive/data/docs/experiences/migrate-cjs-compatible-api-version-map-limit.md +17 -0
  33. package/vendor/Archive/data/docs/experiences/mp3agic-arkts-library-behavior-quirks.md +21 -0
  34. package/vendor/Archive/data/docs/experiences/ohos-face-detection-scan-api-mapping.md +15 -0
  35. package/vendor/Archive/data/docs/experiences/pr-metadata-and-diff-integrity-verification.md +12 -0
  36. package/vendor/Archive/data/docs/experiences/rn-coverage-index-signature-pseudo-member-false-negative.md +32 -0
  37. package/vendor/Archive/data/docs/experiences/rn-memory-check-severity-calibration.md +21 -0
  38. package/vendor/Archive/data/docs/experiences/rn-platform-specific-api-exclusion-evidence.md +24 -0
  39. package/vendor/Archive/data/docs/experiences/rn-upstream-version-diff-pitfalls.md +17 -0
  40. package/vendor/Archive/data/docs/experiences/rn-version-gap-risk-rating-rules.md +13 -0
  41. package/vendor/Archive/data/docs/experiences/rn-view-lib-native-contract-diff-fabric-spec.md +16 -0
  42. package/vendor/Archive/data/docs/experiences/rnoh-adapter-package-version-field-semantics.md +18 -0
  43. package/vendor/Archive/data/docs/experiences/rnoh-arkts-sqlite-rows-array-format.md +18 -0
  44. package/vendor/Archive/data/docs/experiences/rnoh-dependency-residue-scan-strategy.md +18 -0
  45. package/vendor/Archive/data/docs/experiences/rnoh-example-local-lib-dep-use-tgz.md +53 -0
  46. package/vendor/Archive/data/docs/experiences/rnoh-example-prereserve-rntesterlist.md +17 -0
  47. package/vendor/Archive/data/docs/experiences/rnoh-example-template-compatiblesdkversion-upgrade.md +29 -0
  48. package/vendor/Archive/data/docs/experiences/rnoh-example-turbomodule-shell-adaptation-checklist.md +41 -0
  49. package/vendor/Archive/data/docs/experiences/rnoh-mcp-build-project-tool-risk.md +18 -0
  50. package/vendor/Archive/data/docs/experiences/rnoh-npm-devdependencies-version-precheck.md +29 -0
  51. package/vendor/Archive/data/docs/experiences/rnoh-repo-baseline-version-verification.md +13 -0
  52. package/vendor/Archive/data/docs/experiences/rnoh-repo-upstream-directory-mapping.md +18 -0
  53. package/vendor/Archive/data/docs/experiences/rnoh-stateless-library-zero-leak-verification.md +31 -0
  54. package/vendor/Archive/data/docs/experiences/rnoh-template-npmrc-credential-removal.md +15 -0
  55. package/vendor/Archive/data/docs/experiences/rnoh-turbomodule-codegen-wiring-verification.md +19 -0
  56. package/vendor/Archive/data/docs/experiences/rnoh-turbomodule-cpp-methodmap-compatibility-check.md +20 -0
  57. package/vendor/Archive/data/docs/experiences/scenario-doc-vs-source-signature-diff-four-patterns.md +24 -0
  58. package/vendor/Archive/data/docs/experiences/static-analysis-grep-cross-validation.md +29 -0
  59. package/vendor/Archive/demo.js +489 -0
  60. package/vendor/Archive/index.js +43 -0
  61. package/vendor/Archive/package.json +16 -0
  62. package/vendor/Archive/src/constants.js +83 -0
  63. package/vendor/Archive/src/data/stopwords.txt +110 -0
  64. package/vendor/Archive/src/data/synonyms.json +25 -0
  65. package/vendor/Archive/src/data/terms.txt +59 -0
  66. package/vendor/Archive/src/db/sqlite-backend.js +312 -0
  67. package/vendor/Archive/src/db/sqlite-schema.js +64 -0
  68. package/vendor/Archive/src/engine.js +501 -0
  69. package/vendor/Archive/src/index/index-manager.js +203 -0
  70. package/vendor/Archive/src/index/index-state.js +94 -0
  71. package/vendor/Archive/src/index/search-text-builder.js +106 -0
  72. package/vendor/Archive/src/index.js +22 -0
  73. package/vendor/Archive/src/parser/api-identifiers.js +121 -0
  74. package/vendor/Archive/src/parser/api-suffixes.js +48 -0
  75. package/vendor/Archive/src/parser/heading-normalize.js +40 -0
  76. package/vendor/Archive/src/parser/markdown-splitter.js +215 -0
  77. package/vendor/Archive/src/search/catalog-routing.js +87 -0
  78. package/vendor/Archive/src/search/fts-search.js +289 -0
  79. package/vendor/Archive/src/search/query-normalizer.js +159 -0
  80. package/vendor/Archive/src/search/query-rewriter.js +72 -0
  81. package/vendor/Archive/src/search/search-engine.js +72 -0
  82. package/vendor/Archive/src/search/snippet.js +64 -0
  83. package/vendor/Archive/src/store/dir-store.js +103 -0
  84. package/vendor/Archive/src/store/doc-store.js +36 -0
  85. package/vendor/Archive/src/tokenizer/lexicon.js +151 -0
  86. package/vendor/Archive/src/tokenizer/tokenizer.js +167 -0
  87. package/vendor/Archive/src/types.js +86 -0
  88. package/vendor/Archive/src/utils/hash.js +16 -0
  89. package/vendor/Archive/src/utils/lock.js +73 -0
  90. package/vendor/Archive/src/utils/path-safety.js +96 -0
  91. package/vendor/Archive/src/utils/paths.js +39 -0
  92. package/vendor/BadCase/rn/INDEX.md +127 -0
  93. package/vendor/BadCase/rn/cases/KI-001-webview/350/247/206/351/242/221/346/227/240/346/263/225/346/250/252/345/261/217.md +52 -0
  94. package/vendor/BadCase/rn/cases/KI-002-fastImage/347/203/255/346/233/264/346/226/260/345/233/276/347/211/207/345/244/261/350/264/245.md +37 -0
  95. package/vendor/BadCase/rn/cases/KI-003-wechat/347/274/251/347/225/245/345/233/276/346/234/254/345/234/260/345/233/276/347/211/207.md +62 -0
  96. package/vendor/BadCase/rn/cases/KI-004-wechat/345/233/236/350/260/203/346/227/266/345/272/217.md +47 -0
  97. package/vendor/BadCase/rn/cases/KI-005-geolocation/345/257/274/345/205/245/350/267/257/345/276/204/345/220/216/347/274/200.md +31 -0
  98. package/vendor/BadCase/rn/cases/KI-006-SmartRefreshLayout/346/231/272/350/203/275/346/214/207/351/222/210/345/264/251/346/272/203.md +55 -0
  99. package/vendor/BadCase/rn/cases/KI-007-orientation-locker/344/274/240/346/204/237/345/231/250/345/210/235/345/247/213/345/214/226.md +58 -0
  100. package/vendor/BadCase/rn/cases/KI-008-orientation-locker/344/274/240/346/204/237/345/231/250/345/274/225/347/224/250/350/256/241/346/225/260.md +47 -0
  101. package/vendor/BadCase/rn/cases/KI-009-pager-view/345/265/214/345/245/227/346/273/221/345/212/250.md +38 -0
  102. package/vendor/BadCase/rn/cases/KI-010-screens/346/211/213/345/212/277/345/206/262/347/252/201.md +48 -0
  103. package/vendor/BadCase/rn/cases/KI-011-spring-scrollview/346/211/213/345/212/277/351/207/215/345/244/215/347/273/221/345/256/232.md +49 -0
  104. package/vendor/BadCase/rn/cases/KI-012-qr-camera/346/250/252/345/261/217/351/200/202/351/205/215.md +59 -0
  105. package/vendor/BadCase/rn/cases/KI-013-webview/346/267/261/350/211/262/346/250/241/345/274/217/350/203/214/346/231/257/350/211/262.md +37 -0
  106. package/vendor/BadCase/rn/cases/KI-014-amap-geolocation/345/233/236/350/260/203/347/274/272/345/244/261.md +42 -0
  107. package/vendor/BadCase/rn/cases/KI-015-reanimated/350/277/220/350/241/214/346/227/266/346/236/220/346/236/204/345/264/251/346/272/203.md +54 -0
  108. package/vendor/BadCase/rn/cases/KI-016-fs/346/226/207/344/273/266/350/257/273/345/217/226/347/274/226/347/240/201.md +58 -0
  109. package/vendor/BadCase/rn/cases/KI-017-blob-util/345/217/202/346/225/260/347/274/226/347/240/201/351/224/231/350/257/257.md +39 -0
  110. package/vendor/BadCase/rn/cases/KI-018-modal/345/274/271/347/252/227/351/227/252/347/203/201.md +53 -0
  111. package/vendor/BadCase/rn/cases/KI-019-code-push/351/207/215/345/220/257/351/200/273/350/276/221/345/244/261/346/225/210.md +79 -0
  112. package/vendor/BadCase/rn/cases/KI-020-netinfo/346/225/217/346/204/237/344/277/241/346/201/257/346/263/204/351/234/262.md +60 -0
  113. package/vendor/BadCase/rn/cases/KI-021-video/346/234/254/345/234/260/350/247/206/351/242/221/346/222/255/346/224/276/345/274/202/345/270/270.md +79 -0
  114. package/vendor/BadCase/rn/cases/KI-022-audio-recorder-player/346/236/232/344/270/276/347/274/272/345/244/261.md +38 -0
  115. package/vendor/BadCase/rn/cases/KI-023-svg/346/270/220/345/217/230/347/273/247/346/211/277/345/244/261/346/225/210.md +62 -0
  116. package/vendor/BadCase/rn/generalization-log.md +55 -0
  117. package/vendor/BadCase/rn/pr-info/rntpc_react-native-SmartRefreshLayout-32.json +328 -0
  118. package/vendor/BadCase/rn/pr-info/rntpc_react-native-SmartRefreshLayout-32.md +382 -0
  119. package/vendor/BadCase/rn/pr-info/rntpc_react-native-amap-geolocation-27.json +1351 -0
  120. package/vendor/BadCase/rn/pr-info/rntpc_react-native-amap-geolocation-27.md +1176 -0
  121. package/vendor/BadCase/rn/pr-info/rntpc_react-native-audio-recorder-player-22.json +538 -0
  122. package/vendor/BadCase/rn/pr-info/rntpc_react-native-audio-recorder-player-22.md +1488 -0
  123. package/vendor/BadCase/rn/pr-info/rntpc_react-native-blob-util-23.json +211 -0
  124. package/vendor/BadCase/rn/pr-info/rntpc_react-native-blob-util-23.md +35 -0
  125. package/vendor/BadCase/rn/pr-info/rntpc_react-native-code-push-17.json +2048 -0
  126. package/vendor/BadCase/rn/pr-info/rntpc_react-native-code-push-17.md +3866 -0
  127. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fast-image-102.json +198 -0
  128. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fast-image-102.md +40 -0
  129. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fs-38.json +751 -0
  130. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fs-38.md +883 -0
  131. package/vendor/BadCase/rn/pr-info/rntpc_react-native-geolocation-24.json +1544 -0
  132. package/vendor/BadCase/rn/pr-info/rntpc_react-native-geolocation-24.md +2598 -0
  133. package/vendor/BadCase/rn/pr-info/rntpc_react-native-modal-20.json +246 -0
  134. package/vendor/BadCase/rn/pr-info/rntpc_react-native-modal-20.md +554 -0
  135. package/vendor/BadCase/rn/pr-info/rntpc_react-native-netinfo-31.json +211 -0
  136. package/vendor/BadCase/rn/pr-info/rntpc_react-native-netinfo-31.md +54 -0
  137. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-45.json +1626 -0
  138. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-45.md +2213 -0
  139. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-51.json +208 -0
  140. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-51.md +77 -0
  141. package/vendor/BadCase/rn/pr-info/rntpc_react-native-pager-view-32.json +377 -0
  142. package/vendor/BadCase/rn/pr-info/rntpc_react-native-pager-view-32.md +174 -0
  143. package/vendor/BadCase/rn/pr-info/rntpc_react-native-qr-decode-image-camera-37.json +232 -0
  144. package/vendor/BadCase/rn/pr-info/rntpc_react-native-qr-decode-image-camera-37.md +194 -0
  145. package/vendor/BadCase/rn/pr-info/rntpc_react-native-reanimated-82.json +198 -0
  146. package/vendor/BadCase/rn/pr-info/rntpc_react-native-reanimated-82.md +67 -0
  147. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-87.json +198 -0
  148. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-87.md +38 -0
  149. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-93.json +208 -0
  150. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-93.md +34 -0
  151. package/vendor/BadCase/rn/pr-info/rntpc_react-native-spring-scrollview-38.json +222 -0
  152. package/vendor/BadCase/rn/pr-info/rntpc_react-native-spring-scrollview-38.md +56 -0
  153. package/vendor/BadCase/rn/pr-info/rntpc_react-native-svg-117.json +463 -0
  154. package/vendor/BadCase/rn/pr-info/rntpc_react-native-svg-117.md +383 -0
  155. package/vendor/BadCase/rn/pr-info/rntpc_react-native-video-66.json +464 -0
  156. package/vendor/BadCase/rn/pr-info/rntpc_react-native-video-66.md +565 -0
  157. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-112.json +198 -0
  158. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-112.md +47 -0
  159. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-121.json +232 -0
  160. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-121.md +422 -0
  161. package/vendor/BadCase/rn/pr-info/rntpc_react-native-wechat-lib-15.json +295 -0
  162. package/vendor/BadCase/rn/pr-info/rntpc_react-native-wechat-lib-15.md +1038 -0
  163. package/vendor/BadCase/rn/rules/R-01-/345/205/250/345/261/217/347/252/227/345/217/243/347/212/266/346/200/201/347/256/241/347/220/206/345/256/214/346/225/264/346/200/247.md +20 -0
  164. package/vendor/BadCase/rn/rules/R-02-/350/265/204/346/272/220URI/345/275/242/346/200/201/345/210/206/346/224/257/350/246/206/347/233/226.md +21 -0
  165. package/vendor/BadCase/rn/rules/R-03-/351/231/204/345/261/236/346/223/215/344/275/234/345/244/261/350/264/245/351/230/273/346/226/255/344/270/273/346/265/201/347/250/213.md +20 -0
  166. package/vendor/BadCase/rn/rules/R-04-/345/274/202/346/255/245/345/233/236/350/260/203/346/263/250/345/206/214/346/227/266/345/272/217.md +20 -0
  167. package/vendor/BadCase/rn/rules/R-05-/346/250/241/345/235/227/345/257/274/345/205/245/350/267/257/345/276/204/350/247/204/350/214/203.md +19 -0
  168. package/vendor/BadCase/rn/rules/R-06-/344/274/240/346/204/237/345/231/250/347/241/254/344/273/266/346/235/203/351/231/220/346/214/211/351/234/200/350/216/267/345/217/226.md +21 -0
  169. package/vendor/BadCase/rn/rules/R-07-/346/231/272/350/203/275/346/214/207/351/222/210/347/224/237/345/221/275/345/221/250/346/234/237/347/256/241/347/220/206.md +20 -0
  170. package/vendor/BadCase/rn/rules/R-08-/346/211/213/345/212/277/344/272/213/344/273/266/346/263/250/345/206/214/344/270/216/345/206/262/347/252/201/345/244/204/347/220/206.md +22 -0
  171. package/vendor/BadCase/rn/rules/R-09-/346/250/252/347/253/226/345/261/217/345/244/232/345/275/242/346/200/201/345/270/203/345/261/200/351/200/202/351/205/215.md +20 -0
  172. package/vendor/BadCase/rn/rules/R-10-/346/267/261/350/211/262/346/250/241/345/274/217/344/270/273/351/242/230/351/242/234/350/211/262/351/200/202/351/205/215.md +19 -0
  173. package/vendor/BadCase/rn/rules/R-11-/346/216/245/345/217/243/345/233/236/350/260/203/345/256/236/347/216/260/345/256/214/346/225/264/346/200/247.md +20 -0
  174. package/vendor/BadCase/rn/rules/R-12-/345/216/237/347/224/237/350/277/220/350/241/214/346/227/266/350/265/204/346/272/220/346/236/220/346/236/204/346/227/266/345/272/217.md +20 -0
  175. package/vendor/BadCase/rn/rules/R-13-/346/226/207/344/273/266/346/225/260/346/215/256/347/274/226/347/240/201/344/270/216/346/240/274/345/274/217/345/205/274/345/256/271.md +21 -0
  176. package/vendor/BadCase/rn/rules/R-14-/345/212/250/347/224/273/345/210/235/345/247/213/345/214/226/346/227/266/345/272/217/344/270/216/347/212/266/346/200/201/345/220/214/346/255/245.md +20 -0
  177. package/vendor/BadCase/rn/rules/R-15-/347/212/266/346/200/201/346/214/201/344/271/205/345/214/226/344/270/216/351/207/215/345/220/257/351/200/273/350/276/221/344/270/200/350/207/264/346/200/247.md +20 -0
  178. package/vendor/BadCase/rn/rules/R-16-/346/225/217/346/204/237/344/277/241/346/201/257/346/227/245/345/277/227/346/263/204/351/234/262.md +19 -0
  179. package/vendor/BadCase/rn/rules/R-17-/345/252/222/344/275/223/350/265/204/346/272/220/347/224/237/345/221/275/345/221/250/346/234/237/344/270/216/351/224/231/350/257/257/345/244/204/347/220/206.md +21 -0
  180. package/vendor/BadCase/rn/rules/R-18-/350/203/275/345/212/233/346/236/232/344/270/276/351/205/215/347/275/256/345/256/214/346/225/264/346/200/247.md +19 -0
  181. package/vendor/BadCase/rn/rules/R-19-/345/233/276/345/275/242/346/270/262/346/237/223/345/261/236/346/200/247/347/273/247/346/211/277/344/270/216/351/207/215/347/275/256.md +19 -0
  182. package/vendor/MCP/README.md +490 -0
  183. package/vendor/MCP/config.json +29 -0
  184. package/vendor/MCP/package.json +23 -0
  185. package/vendor/MCP/scripts/analyze-demo-coverage.cjs +1203 -0
  186. package/vendor/MCP/scripts/analyze-xts-coverage.cjs +1245 -0
  187. package/vendor/MCP/scripts/deveco_docs.js +247 -0
  188. package/vendor/MCP/scripts/extract-interfaces.cjs +1487 -0
  189. package/vendor/MCP/scripts/flutter-analyze-demo-coverage.cjs +666 -0
  190. package/vendor/MCP/scripts/flutter-analyze-xts-coverage.cjs +684 -0
  191. package/vendor/MCP/scripts/flutter-extract-interfaces.cjs +1251 -0
  192. package/vendor/MCP/scripts/flutter-render-spec-doc.cjs +351 -0
  193. package/vendor/MCP/scripts/render-spec-doc.cjs +347 -0
  194. package/vendor/MCP/scripts/rn-analyze-demo-coverage.cjs +645 -0
  195. package/vendor/MCP/scripts/rn-analyze-test-coverage.cjs +614 -0
  196. package/vendor/MCP/scripts/rn-extract-interfaces.cjs +1462 -0
  197. package/vendor/MCP/scripts/rn-render-spec-doc.cjs +327 -0
  198. package/vendor/MCP/scripts/rn-scan-exports.cjs +1336 -0
  199. package/vendor/MCP/src/client/MCPClientPool.js +220 -0
  200. package/vendor/MCP/src/config/ConfigLoader.js +189 -0
  201. package/vendor/MCP/src/executor/ScriptExecutor.js +110 -0
  202. package/vendor/MCP/src/gateway/Gateway.js +451 -0
  203. package/vendor/MCP/src/index.js +87 -0
  204. package/vendor/MCP/src/library/KBToolProvider.js +229 -0
  205. package/vendor/MCP/src/library/logger.js +60 -0
  206. package/vendor/MCP/src/registry/ScriptRegistry.js +238 -0
  207. package/vendor/MCP/src/registry/ToolRegistry.js +111 -0
  208. package/vendor/MCP/src/types.js +115 -0
  209. package/vendor/Server/Skills/arkts-library-test-coverage-check/references/MCP_TOOL_USAGE.md +4 -2
  210. package/vendor/Server/Skills/arkts-library-xts-coverage/SKILL.md +3 -3
  211. package/vendor/Server/Skills/knowledge-import/SKILL.md +1 -1
  212. package/vendor/Server/Skills/knowledge-import/references/MCP_TOOL_USAGE.md +12 -4
  213. package/vendor/Server/Skills/ohos-lib-pr-push/SKILL.md +5 -4
  214. package/vendor/Server/Skills/rn-library-issue-generalizer/SKILL.md +2 -2
  215. package/vendor/Server/Skills/rn-library-known-issue-check/SKILL.md +2 -2
  216. package/vendor/Server/Skills/rnoh-lib-demo-coverage/SKILL.md +1 -2
  217. package/vendor/Server/Skills/rnoh-lib-test-align/references/port-test-demo-guide.md +1 -1
  218. package/vendor/Server/Skills/rnoh-lib-xts-coverage/SKILL.md +1 -2
  219. package/vendor/Server/package.json +5 -1
  220. package/vendor/VERSION +3 -3
package/lib/mcp.js ADDED
@@ -0,0 +1,498 @@
1
+ /**
2
+ * mcp.js —— 3rdloop mcp:MCP Gateway 一键装配(install / uninstall / status)
3
+ *
4
+ * 背景:npm 包内 vendor/ 携带 MCP Gateway(vendor/MCP)、知识库检索引擎
5
+ * (vendor/Archive)、已知问题知识库种子(vendor/BadCase),但 AI CLI
6
+ * (opencode / deveco-code)需要在其**全局配置**里注册 mcp-gateway 才会在
7
+ * serve 启动时 spawn Gateway。本命令完成装配:
8
+ *
9
+ * 3rdloop mcp install [--cli opencode|deveco|all] [--force]
10
+ * ① 生成用户级 Gateway 配置 ~/.3lib/3rdloop/mcp/config.json
11
+ * - scriptsDir / enginePath → 包内(vendor,随包更新获得新脚本/引擎)
12
+ * - knowledgeBase.dataDir → ~/.3lib/3rdloop/kb-data(用户数据,跨版本不丢)
13
+ * ② 种子复制:kb-data(← vendor/Archive/data)、BadCase 副本
14
+ * (← vendor/BadCase,泛化 SKILL 的可写知识库)
15
+ * ③ 注册 mcp-gateway 到 ~/.config/opencode/opencode.json 与
16
+ * ~/.config/deveco/deveco.jsonc(保留其他字段,幂等可重跑)
17
+ *
18
+ * 3rdloop mcp uninstall [--cli ...] 仅移除注册条目(用户数据保留)
19
+ * 3rdloop mcp status 查看注册状态与路径
20
+ *
21
+ * 设计约束:
22
+ * - 仓库开发态(npm link,无 vendor/)自动回退仓库 MCP/、Archive/、BadCase/
23
+ * - 用户已有 ~/.3lib/3rdloop/mcp/config.json 时仅刷新路径字段,
24
+ * 保留 downstreamServers 等用户改动(--force 重置为包内默认)
25
+ * - deveco.jsonc 为 JSONC:容错解析(去注释重试),解析失败提示手动配置
26
+ */
27
+
28
+ import fs from 'node:fs';
29
+ import path from 'node:path';
30
+ import { fileURLToPath } from 'node:url';
31
+ import process from 'node:process';
32
+ import { resolveCliType } from './config.js';
33
+
34
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
35
+ export const CLI_ROOT = path.resolve(moduleDir, '..');
36
+
37
+ /** 注册到 AI CLI 全局配置的条目名(与既有生态约定一致) */
38
+ export const MCP_ENTRY_NAME = 'mcp-gateway';
39
+
40
+ /** AI CLI 全局配置文件位置(按平台) */
41
+ function aiCliConfigPaths() {
42
+ const home = process.env['HOME'] || process.env['USERPROFILE'] || '';
43
+ const configRoot = process.env['XDG_CONFIG_HOME'] || path.join(home, '.config');
44
+ return {
45
+ opencode: path.join(configRoot, 'opencode', 'opencode.json'),
46
+ 'deveco-code': path.join(configRoot, 'deveco', 'deveco.jsonc'),
47
+ };
48
+ }
49
+
50
+ // ─── 包内资产定位(vendor 优先,仓库开发态回退)────────────────────────
51
+
52
+ let _assetsCache = null;
53
+
54
+ /**
55
+ * 定位 MCP / Archive / BadCase 资产目录。
56
+ * @returns {{ mcpDir: string, archiveDir: string, badcaseDir: string, mode: 'vendor'|'repo' }}
57
+ * @throws {Error} vendor 与仓库路径均不存在
58
+ */
59
+ export function resolveAssets() {
60
+ if (_assetsCache) return _assetsCache;
61
+
62
+ const vendorDir = path.join(CLI_ROOT, 'vendor');
63
+ const repoRoot = path.resolve(CLI_ROOT, '..');
64
+
65
+ const tryDirs = [
66
+ { root: vendorDir, mode: 'vendor' },
67
+ { root: repoRoot, mode: 'repo' },
68
+ ];
69
+ for (const { root, mode } of tryDirs) {
70
+ const mcpDir = path.join(root, 'MCP');
71
+ if (fs.existsSync(path.join(mcpDir, 'src', 'index.js'))) {
72
+ _assetsCache = {
73
+ mcpDir,
74
+ archiveDir: path.join(root, 'Archive'),
75
+ badcaseDir: path.join(root, 'BadCase'),
76
+ mode,
77
+ };
78
+ return _assetsCache;
79
+ }
80
+ }
81
+ throw new Error(
82
+ `无法定位 MCP Gateway:期望 cli/vendor/MCP 或仓库 MCP/。` +
83
+ `npm 安装态请重装包(npm i -g @ohos-cpf/3rdloop),仓库态请在 cli/ 上一级执行`
84
+ );
85
+ }
86
+
87
+ // ─── 用户级路径 ────────────────────────────────────────────────────────
88
+
89
+ /**
90
+ * 用户级路径集合(kb 数据 / BadCase 副本 / Gateway 配置)。
91
+ * @param {string} user3libHome - ~/.3lib
92
+ */
93
+ export function userPaths(user3libHome) {
94
+ const loopHome = path.join(user3libHome, '3rdloop');
95
+ return {
96
+ loopHome,
97
+ mcpConfigDir: path.join(loopHome, 'mcp'),
98
+ mcpConfig: path.join(loopHome, 'mcp', 'config.json'),
99
+ kbDataDir: path.join(loopHome, 'kb-data'),
100
+ badcaseDir: path.join(loopHome, 'BadCase'),
101
+ };
102
+ }
103
+
104
+ // ─── 工具函数 ─────────────────────────────────────────────────────────
105
+
106
+ /** 递归复制目录(跳过 node_modules)。 */
107
+ function copyDir(src, dst) {
108
+ fs.mkdirSync(dst, { recursive: true });
109
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
110
+ if (entry.name === 'node_modules' || entry.name === '.git') continue;
111
+ const s = path.join(src, entry.name);
112
+ const d = path.join(dst, entry.name);
113
+ if (entry.isDirectory()) copyDir(s, d);
114
+ else fs.copyFileSync(s, d);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * 容错读取 JSON / JSONC 配置(带 // 与 /* 注释剥离重试)。
120
+ * @returns {{ ok: boolean, data: object|null, raw: string, error?: string }}
121
+ */
122
+ function readJsonc(file) {
123
+ let raw = '';
124
+ try {
125
+ raw = fs.readFileSync(file, 'utf8');
126
+ } catch (err) {
127
+ return { ok: false, data: null, raw: '', error: err.message };
128
+ }
129
+ try {
130
+ return { ok: true, data: JSON.parse(raw), raw };
131
+ } catch { /* 尝试剥注释 */ }
132
+ const stripped = raw
133
+ .replace(/\/\*[\s\S]*?\*\//g, '')
134
+ .replace(/(^|[^:"'\\])\/\/.*$/gm, '$1');
135
+ try {
136
+ return { ok: true, data: JSON.parse(stripped), raw };
137
+ } catch (err) {
138
+ return { ok: false, data: null, raw, error: `JSONC 解析失败: ${err.message}` };
139
+ }
140
+ }
141
+
142
+ /** 合并写入 AI CLI 全局配置的 mcp.mcp-gateway 条目(保留其他字段)。 */
143
+ function upsertMcpEntry(file, entry, { createIfMissing = true } = {}) {
144
+ const existed = fs.existsSync(file);
145
+ if (!existed && !createIfMissing) return { ok: true, skipped: true };
146
+
147
+ const parsed = existed ? readJsonc(file) : { ok: true, data: {} };
148
+ if (!parsed.ok) {
149
+ return { ok: false, error: `${file} ${parsed.error}(可手动编辑,或删除该文件后重跑 3rdloop mcp install)` };
150
+ }
151
+ const data = parsed.data || {};
152
+ if (!data.mcp || typeof data.mcp !== 'object') data.mcp = {};
153
+ data.mcp[MCP_ENTRY_NAME] = entry;
154
+
155
+ fs.mkdirSync(path.dirname(file), { recursive: true });
156
+ fs.writeFileSync(file, JSON.stringify(data, null, 2) + '\n');
157
+ return { ok: true, skipped: false, existed };
158
+ }
159
+
160
+ /** 从 AI CLI 全局配置移除 mcp.mcp-gateway 条目(文件不存在视为成功)。 */
161
+ function removeMcpEntry(file) {
162
+ if (!fs.existsSync(file)) return { ok: true, removed: false };
163
+ const parsed = readJsonc(file);
164
+ if (!parsed.ok) {
165
+ return { ok: false, error: `${file} ${parsed.error}(请手动删除其中的 "${MCP_ENTRY_NAME}" 条目)` };
166
+ }
167
+ const data = parsed.data || {};
168
+ let removed = false;
169
+ if (data.mcp && typeof data.mcp === 'object' && MCP_ENTRY_NAME in data.mcp) {
170
+ delete data.mcp[MCP_ENTRY_NAME];
171
+ removed = true;
172
+ fs.writeFileSync(file, JSON.stringify(data, null, 2) + '\n');
173
+ }
174
+ return { ok: true, removed };
175
+ }
176
+
177
+ /** 读取某 AI CLI 配置中 mcp-gateway 的注册状态。 */
178
+ function readMcpEntry(file) {
179
+ if (!fs.existsSync(file)) return { state: 'missing-file' };
180
+ const parsed = readJsonc(file);
181
+ if (!parsed.ok) return { state: 'parse-error', error: parsed.error };
182
+ const entry = parsed.data?.mcp?.[MCP_ENTRY_NAME];
183
+ if (!entry) return { state: 'missing-entry' };
184
+ return { state: 'registered', entry };
185
+ }
186
+
187
+ // ─── install ──────────────────────────────────────────────────────────
188
+
189
+ /**
190
+ * 生成/刷新用户级 Gateway 配置。
191
+ * 已存在时仅刷新 scriptsDir/enginePath/gateway/scripts 策略(保留 downstreamServers
192
+ * 与用户自定义 dataDir),force 时以包内 config 为模板重置。
193
+ */
194
+ function writeUserMcpConfig({ userMcpConfig, templateConfig, assets, kbDataDir, force }) {
195
+ const existed = fs.existsSync(userMcpConfig);
196
+ const current = existed ? readJsonc(userMcpConfig) : null;
197
+ if (existed && !current.ok) {
198
+ return { ok: false, error: `${userMcpConfig} ${current.error}(可 --force 覆盖或手动修复)` };
199
+ }
200
+
201
+ const tmplKb = templateConfig.knowledgeBase || {};
202
+ const curKb = (!force && existed && current.data?.knowledgeBase) || null;
203
+
204
+ let cfg;
205
+ if (curKb) {
206
+ // 刷新模式:以现有用户配置为基底
207
+ cfg = current.data;
208
+ cfg.scripts = { ...(templateConfig.scripts || {}), ...(cfg.scripts || {}) };
209
+ cfg.gateway = cfg.gateway || templateConfig.gateway;
210
+ } else {
211
+ // 首次 / --force:以包内模板为基底(深拷贝,含 scripts 策略/downstreamServers)
212
+ cfg = JSON.parse(JSON.stringify(templateConfig));
213
+ }
214
+ if (force) {
215
+ cfg.downstreamServers = templateConfig.downstreamServers || {};
216
+ cfg.gateway = templateConfig.gateway || cfg.gateway;
217
+ cfg.scripts = { ...(templateConfig.scripts || {}) };
218
+ }
219
+
220
+ // dataDir:仅当用户改过(≠ 模板默认相对值)才保留,否则统一指向用户 kb-data
221
+ const userSetDataDir = curKb && curKb.dataDir && curKb.dataDir !== tmplKb.dataDir
222
+ ? curKb.dataDir : null;
223
+ const finalDataDir = userSetDataDir || kbDataDir;
224
+
225
+ // 路径字段始终刷新为当前安装位置(包更新后路径不变,幂等无害)
226
+ cfg.scriptsDir = path.join(assets.mcpDir, 'scripts');
227
+ cfg.knowledgeBase = {
228
+ ...tmplKb,
229
+ ...(curKb || {}),
230
+ enabled: (curKb?.enabled) ?? tmplKb.enabled ?? true,
231
+ enginePath: path.join(assets.archiveDir, 'src', 'index.js'),
232
+ dataDir: finalDataDir,
233
+ };
234
+
235
+ fs.mkdirSync(path.dirname(userMcpConfig), { recursive: true });
236
+ fs.writeFileSync(userMcpConfig, JSON.stringify(cfg, null, 2) + '\n');
237
+ return { ok: true, existed, config: cfg };
238
+ }
239
+
240
+ /**
241
+ * 3rdloop mcp install 实现。
242
+ * @param {object} opts
243
+ * @param {string} opts.user3libHome - ~/.3lib
244
+ * @param {string[]} opts.rest - 命令参数(--cli / --force)
245
+ * @param {boolean} opts.jsonMode
246
+ * @returns {Promise<number>} 退出码
247
+ */
248
+ export async function mcpInstall({ user3libHome, rest = [], jsonMode = false }) {
249
+ const cliFilter = _parseCliFilter(rest); // 'all' | 'opencode' | 'deveco-code'
250
+ const force = rest.includes('--force');
251
+ const out = (data) => { if (jsonMode) process.stdout.write(JSON.stringify(data, null, 2) + '\n'); };
252
+ const log = (msg) => process.stderr.write(`${msg}\n`);
253
+
254
+ const assets = resolveAssets();
255
+ const up = userPaths(user3libHome);
256
+
257
+ // ① 包内模板 config(downstreamServers / gateway / 脚本策略)
258
+ const templateFile = path.join(assets.mcpDir, 'config.json');
259
+ if (!fs.existsSync(templateFile)) {
260
+ log(`错误: 未找到 Gateway 配置模板: ${templateFile}`);
261
+ return 1;
262
+ }
263
+ const templateConfig = JSON.parse(fs.readFileSync(templateFile, 'utf8'));
264
+
265
+ // ② 用户级 Gateway 配置
266
+ const writeResult = writeUserMcpConfig({
267
+ userMcpConfig: up.mcpConfig,
268
+ templateConfig,
269
+ assets,
270
+ kbDataDir: up.kbDataDir,
271
+ force,
272
+ });
273
+ if (!writeResult.ok) {
274
+ log(`错误: ${writeResult.error}`);
275
+ return 1;
276
+ }
277
+
278
+ // ③ 种子数据(目录已存在则跳过,保用户数据)
279
+ const seeds = [
280
+ { src: path.join(assets.archiveDir, 'data'), dst: up.kbDataDir, label: '知识库数据' },
281
+ { src: assets.badcaseDir, dst: up.badcaseDir, label: 'BadCase 已知问题知识库' },
282
+ ];
283
+ const seeded = [];
284
+ for (const { src, dst, label } of seeds) {
285
+ if (fs.existsSync(dst)) continue;
286
+ if (!fs.existsSync(src)) continue; // 仓库缺该资产时跳过(prepack 有警告)
287
+ copyDir(src, dst);
288
+ seeded.push({ label, dst });
289
+ }
290
+
291
+ // ④ 注册到 AI CLI 全局配置
292
+ const entry = {
293
+ command: ['node', path.join(assets.mcpDir, 'src', 'index.js'), '--config', up.mcpConfig],
294
+ enabled: true,
295
+ type: 'local',
296
+ };
297
+ const targets = cliFilter === 'all'
298
+ ? Object.keys(aiCliConfigPaths())
299
+ : [cliFilter];
300
+ const registered = [];
301
+ const failures = [];
302
+ for (const cliType of targets) {
303
+ const file = aiCliConfigPaths()[cliType];
304
+ const res = upsertMcpEntry(file, entry);
305
+ if (!res.ok) failures.push(res.error);
306
+ else registered.push({ cliType, file, existed: !!res.existed });
307
+ }
308
+ if (failures.length > 0) {
309
+ for (const f of failures) log(`错误: ${f}`);
310
+ return 1;
311
+ }
312
+
313
+ if (jsonMode) {
314
+ out({
315
+ ok: true,
316
+ mode: assets.mode,
317
+ userConfig: up.mcpConfig,
318
+ kbDataDir: up.kbDataDir,
319
+ badcaseDir: up.badcaseDir,
320
+ seeded,
321
+ registered,
322
+ });
323
+ } else {
324
+ log(`[3rdloop mcp] Gateway 来源: ${assets.mode === 'vendor' ? '包内 vendor/MCP' : '仓库 MCP/'}`);
325
+ log(`[3rdloop mcp] 用户配置: ${up.mcpConfig}${writeResult.existed && !force ? '(已存在,仅刷新路径)' : ''}`);
326
+ log(`[3rdloop mcp] 知识库数据目录: ${up.kbDataDir}`);
327
+ log(`[3rdloop mcp] BadCase 副本: ${up.badcaseDir}`);
328
+ for (const s of seeded) log(`[3rdloop mcp] 已种子复制 ${s.label} → ${s.dst}`);
329
+ for (const r of registered) {
330
+ log(`[3rdloop mcp] 已注册 ${MCP_ENTRY_NAME} → ${r.file}${r.existed ? '(覆盖旧条目)' : ''}`);
331
+ }
332
+ log(`[3rdloop mcp] 完成。重启 ${targets.join(' / ')} serve 后 AI 会话即可使用 MCP 工具`);
333
+ }
334
+ return 0;
335
+ }
336
+
337
+ // ─── uninstall / status ───────────────────────────────────────────────
338
+
339
+ export async function mcpUninstall({ rest = [], jsonMode = false }) {
340
+ const cliFilter = _parseCliFilter(rest);
341
+ const out = (data) => { if (jsonMode) process.stdout.write(JSON.stringify(data, null, 2) + '\n'); };
342
+ const log = (msg) => process.stderr.write(`${msg}\n`);
343
+
344
+ const targets = cliFilter === 'all' ? Object.keys(aiCliConfigPaths()) : [cliFilter];
345
+ const removed = [];
346
+ const failures = [];
347
+ for (const cliType of targets) {
348
+ const file = aiCliConfigPaths()[cliType];
349
+ const res = removeMcpEntry(file);
350
+ if (!res.ok) failures.push(res.error);
351
+ else if (res.removed) removed.push({ cliType, file });
352
+ }
353
+ if (failures.length > 0) {
354
+ for (const f of failures) log(`错误: ${f}`);
355
+ return 1;
356
+ }
357
+ if (jsonMode) out({ ok: true, removed });
358
+ else if (removed.length === 0) log('[3rdloop mcp] 未发现已注册的条目,无需卸载');
359
+ else for (const r of removed) log(`[3rdloop mcp] 已移除 ${MCP_ENTRY_NAME} → ${r.file}`);
360
+ log('[3rdloop mcp] 用户数据(kb-data / BadCase / config)已保留,可随时重新 install');
361
+ return 0;
362
+ }
363
+
364
+ export async function mcpStatus({ user3libHome, jsonMode = false }) {
365
+ const out = (data) => { if (jsonMode) process.stdout.write(JSON.stringify(data, null, 2) + '\n'); };
366
+ const log = (msg) => process.stderr.write(`${msg}\n`);
367
+
368
+ let assets;
369
+ try {
370
+ assets = resolveAssets();
371
+ } catch (err) {
372
+ if (jsonMode) out({ ok: false, error: err.message });
373
+ else log(`错误: ${err.message}`);
374
+ return 1;
375
+ }
376
+ const up = userPaths(user3libHome);
377
+
378
+ const registrations = {};
379
+ for (const [cliType, file] of Object.entries(aiCliConfigPaths())) {
380
+ const st = readMcpEntry(file);
381
+ registrations[cliType] = { file, state: st.state, entry: st.entry || null };
382
+ }
383
+
384
+ const result = {
385
+ ok: true,
386
+ mode: assets.mode,
387
+ gateway: path.join(assets.mcpDir, 'src', 'index.js'),
388
+ userConfig: up.mcpConfig,
389
+ userConfigExists: fs.existsSync(up.mcpConfig),
390
+ kbDataDir: up.kbDataDir,
391
+ kbDataSeeded: fs.existsSync(up.kbDataDir),
392
+ badcaseDir: up.badcaseDir,
393
+ badcaseSeeded: fs.existsSync(up.badcaseDir),
394
+ registrations,
395
+ };
396
+
397
+ if (jsonMode) {
398
+ out(result);
399
+ } else {
400
+ log(`Gateway 来源: ${assets.mode === 'vendor' ? '包内 vendor/MCP' : '仓库 MCP/'}(${result.gateway})`);
401
+ log(`用户配置: ${up.mcpConfig}${result.userConfigExists ? '' : '(未生成,先 3rdloop mcp install)'}`);
402
+ log(`知识库数据: ${up.kbDataDir}${result.kbDataSeeded ? '' : '(未初始化)'}`);
403
+ log(`BadCase 副本: ${up.badcaseDir}${result.badcaseSeeded ? '' : '(未初始化)'}`);
404
+ for (const [cliType, r] of Object.entries(registrations)) {
405
+ const icon = r.state === 'registered' ? '✓' : '✗';
406
+ const detail = r.state === 'registered'
407
+ ? `已注册 (${r.file})`
408
+ : r.state === 'missing-file' ? `未注册(配置文件不存在: ${r.file})`
409
+ : r.state === 'missing-entry' ? `未注册(${r.file} 无 ${MCP_ENTRY_NAME} 条目)`
410
+ : `解析失败: ${r.file}`;
411
+ log(`${icon} ${cliType}: ${detail}`);
412
+ }
413
+ const anyRegistered = Object.values(registrations).some(r => r.state === 'registered');
414
+ if (!anyRegistered) log('提示: 执行 3rdloop mcp install 完成装配');
415
+ }
416
+ return 0;
417
+ }
418
+
419
+ // ─── 命令入口 ─────────────────────────────────────────────────────────
420
+
421
+ /**
422
+ * 3rdloop mcp 命令入口(子命令分发)。
423
+ * @param {object} opts
424
+ * @param {string[]} opts.rest - flags.rest(含子命令与参数)
425
+ * @param {string} opts.user3libHome - ~/.3lib
426
+ * @param {boolean} opts.jsonMode
427
+ * @returns {Promise<number>} 退出码
428
+ */
429
+ export async function cmdMcp({ rest = [], user3libHome = '', jsonMode = false }) {
430
+ if (rest.includes('--help') || rest.includes('-h')) {
431
+ printMcpHelp();
432
+ return 0;
433
+ }
434
+
435
+ // 位置子命令 = 第一个非 flag 参数(--cli 的值跳过)
436
+ let subcommand = null;
437
+ for (let i = 0; i < rest.length; i++) {
438
+ if (rest[i] === '--cli') { i++; continue; }
439
+ if (rest[i].startsWith('--')) continue;
440
+ subcommand = rest[i];
441
+ break;
442
+ }
443
+
444
+ try {
445
+ if (subcommand === 'install') return await mcpInstall({ user3libHome, rest, jsonMode });
446
+ if (subcommand === 'uninstall') return await mcpUninstall({ rest, jsonMode });
447
+ if (subcommand === 'status') return await mcpStatus({ user3libHome, jsonMode });
448
+ if (subcommand === null && rest.length === 0) {
449
+ printMcpHelp();
450
+ return 0;
451
+ }
452
+ if (subcommand !== null) {
453
+ process.stderr.write(`未知子命令: ${subcommand}\n`);
454
+ } else {
455
+ process.stderr.write(`未知参数: ${rest.join(' ')}\n`);
456
+ }
457
+ printMcpHelp();
458
+ return 1;
459
+ } catch (err) {
460
+ process.stderr.write(`错误: ${err.message}\n`);
461
+ return 1;
462
+ }
463
+ }
464
+
465
+ // ─── 帮助 / 参数 ──────────────────────────────────────────────────────
466
+
467
+ function _parseCliFilter(rest) {
468
+ const idx = rest.indexOf('--cli');
469
+ const raw = idx !== -1 ? rest[idx + 1] : undefined;
470
+ if (!raw || raw === 'all') return 'all';
471
+ if (raw === 'opencode') return 'opencode';
472
+ if (raw === 'deveco' || raw === 'deveco-code') return 'deveco-code';
473
+ throw new Error(`非法 --cli 值: "${raw}"(可选: opencode | deveco | all)`);
474
+ }
475
+
476
+ export function printMcpHelp() {
477
+ process.stdout.write(`3rdloop mcp —— MCP Gateway 装配(npm 安装态必需,仓库开发态可选)
478
+
479
+ 用法:
480
+ 3rdloop mcp install [--cli opencode|deveco|all] [--force]
481
+ ① 生成用户级 Gateway 配置 ~/.3lib/3rdloop/mcp/config.json
482
+ (scriptsDir/enginePath 指向包内 vendor,kb 数据落在 ~/.3lib/3rdloop/kb-data)
483
+ ② 种子复制知识库数据(kb-data)与 BadCase 已知问题知识库到用户目录
484
+ ③ 注册 mcp-gateway 到 opencode / deveco 全局配置(幂等,可重跑)
485
+ --force 重置用户级配置为包内默认(downstreamServers 等)
486
+ 3rdloop mcp uninstall [--cli opencode|deveco|all]
487
+ 仅移除注册条目;用户数据(kb-data / BadCase / config)保留
488
+ 3rdloop mcp status
489
+ 查看注册状态、用户配置与数据目录
490
+
491
+ 说明:
492
+ - opencode/deveco serve 启动时会按全局配置自动 spawn MCP Gateway,
493
+ AI 会话即可调用 kb 搜索、覆盖率分析脚本等工具
494
+ - 安装/更新 npm 包后路径不变,注册条目持续有效;包更新后新脚本
495
+ 自动可用(scriptsDir 随包)
496
+ - 默认注册到 opencode 与 deveco 两处(--cli 可限定)
497
+ `);
498
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ohos-cpf/3rdloop",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "3rdLibraryLoop 三方库自动化检视 CLI:嵌入式复用核心引擎,任务生命周期管理(submit/run/wait/progress/abort/list/result/doctor)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,9 +43,13 @@
43
43
  "test": "node --test test/*.mjs"
44
44
  },
45
45
  "dependencies": {
46
+ "@modelcontextprotocol/sdk": "^1.0.0",
46
47
  "@opencode-ai/sdk": "^1.18.6",
47
48
  "better-sqlite3": "^13.0.1",
49
+ "chokidar": "^4.0.0",
48
50
  "dotenv": "^17.0.0",
49
- "openai": "^4.0.0"
51
+ "jieba-wasm": "^2.4.0",
52
+ "openai": "^4.0.0",
53
+ "typescript": "^5.5.4"
50
54
  }
51
55
  }
@@ -0,0 +1,7 @@
1
+ {
2
+ "indexVersion": "1.0.0",
3
+ "termsHash": "244653ada2b478d99365a03c7b7a50f73bf086d4966ce050d0db91494b883367",
4
+ "synonymsHash": "692fd79264100cf346359dcf57101ff7699d1e88c460a4ee7cc4c0d7b4e9936a",
5
+ "segmentCount": 44,
6
+ "builtAt": 1788338587090
7
+ }
@@ -0,0 +1,13 @@
1
+ ## arkts_check 独立工具使用坑:相对路径假阴性与环境误报甄别
2
+
3
+ ### 问题现象
4
+ 对 PR 新增的 `.ets` 文件以**相对路径**(如 `entry/src/ohosTest/...`)调用独立 arkts_check 工具时返回 "No errors found",看似零问题;改用**绝对路径**复查同一文件却立即报出多处错误(含真实 `arkts-no-any-unknown` 违规)。另有两类干扰:所有 `@ohos/*` import 均报 "Cannot find module";批量检查输出中混入大量非目标文件(master 既有文件)的历史存量错误,干扰统计。
5
+
6
+ ### 解决方案
7
+ 1. arkts_check 必须使用**绝对路径**调用;必要时用一个"已知有问题的文件"做**阳性对照**,验证工具确实在检查。
8
+ 2. `Cannot find module '@ohos/*'` 类错误是独立 linter 无法解析 ohpm 本地依赖(`@ohos/xxx` → `file:../library`)产生的**环境误报**,不计入问题统计。
9
+ 3. **基线对照法**:对 master 既有文件跑同样的检查作为基线——既有文件的违规属于历史存量,与本 PR 无关;将 PR 新增文件的报错与基线对比,即可区分"PR 引入"与"历史存量"。
10
+ 4. 批量调用 arkts_check 可能实际检查目录内全部文件,需对工具保存的完整输出**按目标文件名 grep 过滤**后再统计;单文件逐个检查更可控。
11
+
12
+ ### 结果
13
+ 在 mp3agic PR #53 检视中,通过绝对路径 + 基线对照确认:master 既有测试文件基线为 125+ 错误(大量历史存量 arkts-no-any-unknown),而 PR 新增代码仅 1 处真实违规,显著优于仓库基线。避免了"相对路径假阴性导致漏检"和"环境误报/历史存量导致误判"两类错误结论。
@@ -0,0 +1,31 @@
1
+ # ArkTS 测试代码的深层路径 import 风格与识别方法
2
+
3
+ ### 问题现象
4
+
5
+ 分析 ArkTS(鸿蒙)三方库的测试代码(XTS/Demo)时,测试文件的 import 存在两种风格:
6
+
7
+ ```ts
8
+ // 风格 A:包名导入
9
+ import { EncodedText, ID3v22Tag } from '@ohos/mp3agic'
10
+ // 风格 B:深层路径导入(直接指向库内源文件)
11
+ import { BufferTools } from '@ohos/mp3agic/src/main/ets/components/mp3agic/BufferTools'
12
+ import { MutableInteger } from '@ohos/mp3agic/src/main/ets/components/mp3agic/MutableInteger'
13
+ ```
14
+
15
+ 基于 import 匹配的静态分析工具若只匹配包名(`fromLib === libName || fromLib.endsWith('/' + libName.split('/').pop())`),风格 B 不满足任何条件,导致 `importedSymbols` 为空、整个测试文件被静默跳过。mp3agic 案例中一个 803 行、覆盖 28 个静态方法的测试文件被整体漏掉,且无任何告警。
16
+
17
+ ### 解决方案
18
+
19
+ 在包名匹配条件基础上增加深层路径前缀识别:
20
+
21
+ ```js
22
+ // AST 与正则引擎均需同步修改
23
+ if (fromLib !== libName && !fromLib.endsWith('/' + libName.split('/').pop())
24
+ && !fromLib.startsWith(libName + '/')) continue;
25
+ ```
26
+
27
+ AST 模式下还需在 `resolveModuleNames` 中将深层路径模块说明符映射到库目录下的真实源文件:`'@ohos/pkg/src/main/ets/...'` → `library/src/main/ets/...`(同时做小写键二次查找以兼容大小写差异)。
28
+
29
+ ### 结果
30
+
31
+ mp3agic 库 XTS 覆盖率分析结果从 8/271(2.95%)修正为 100/271(36.90%),与人工 grep 全量调用盘点逐类一致。结论:任何扫描 ArkTS 测试/示例代码做调用分析的工具,都必须同时兼容包名导入与深层路径导入两种风格,并在 import 均未被识别时输出告警。该修复已合入 `analyze-xts-coverage.cjs`(arkts-library-xts-coverage SKILL v1.1.0)。
@@ -0,0 +1,25 @@
1
+ ## ArkTS 库入口文件大小写不一致导致覆盖率分析静默低估
2
+
3
+ ### 问题现象
4
+
5
+ 修复 import 尾斜杠问题后,mp3agic Demo 覆盖率仍仅 58.67%(159/271),抽查发现 `Mp3File.getId3v1Tag`(6 处调用)、`Mp3v2CommentFrameData.setLanguage` 等明显漏判。用最小化调试脚本重现 AST Program 后发现 `let mp3file = new Mp3File(...)` 的推断类型是 `any`,且存在 `Cannot find module '@ohos/mp3agic'` 诊断。此缺陷只造成部分漏判而非全 0(共 29 个接口漏判),脚本对"有库 import 但匹配数为 0 的文件"不产生任何警告、退出码仍为 0,极难在常规测试中暴露。
6
+
7
+ ### 解决方案
8
+
9
+ **根因链**:`extract-interfaces.cjs` 的 `locateEntryFile` 候选路径硬编码 `library/Index.ets`(大写 I);mp3agic 仓库实际文件是 `library/index.ets`(小写 i);macOS 文件系统大小写不敏感,`fs.existsSync('Index.ets')` 通过,脚本拿到"看似有效"的错误大小写路径;`matchCoverageAST` 用该路径构造虚拟路径 key(`Index.ts`),而 `fileContents` Map 的 key 来自 `readdirSync` 的真实大小写(`index.ts`),精确匹配失败 → `resolveModuleNames` 解析不到模块 → 库类型全部坍缩为 `any` → 基于类型的调用匹配失效。
10
+
11
+ **修复方案**(2026-08-27 已落入脚本):
12
+ 1. `locateEntryFile` 返回前用 `fs.readdirSync(path.dirname(entryFile))` 核对文件名真实大小写并回写(toRealCase 辅助函数)
13
+ 2. `resolveModuleNames` 解析入口虚拟路径失败时对 `fileContents` keys 做大小写不敏感回退查找
14
+ 3. 新增静默失败告警防线:编译诊断出现 `Cannot find module '<库名>'`(TS 错误码 2307)时放弃 AST 结果、降级正则模式;文件有库 import 但匹配数为 0 时输出 ⚠️ 提示;覆盖率 0%/异常低(<10%)时在控制台与报告中输出「分析可信度警告」章节
15
+
16
+ **可复用诊断方法**:
17
+ - 用调试脚本打印 `checker.typeToString(getTypeAtLocation(varDecl))`,实例变量为 `any` 即模块解析失败
18
+ - 打印 `program.getSemanticDiagnostics()` 检查是否存在 `Cannot find module '<库名>'`
19
+ - 对报告"未覆盖"接口抽样 grep 真实调用数与报告交叉验证
20
+
21
+ **旧版本脚本应急 workaround**:复制 libroot 到临时目录(排除 .git),把 `library/index.ets` 重命名为 `Index.ets`,用 `--libroot` 指向副本。
22
+
23
+ ### 结果
24
+
25
+ 修复后在 macOS 上直接分析原始仓库(小写入口 + 尾斜杠 import)得到真实覆盖率 69.37%,与"临时副本改名"workaround 结果完全一致。平台差异提醒:入口大小写坑在 macOS(大小写不敏感文件系统)上表现为静默低估,在 Linux(大小写敏感)上表现为 `existsSync` 直接失败走降级逻辑,两者症状不同但同源。快速诊断口诀:"部分漏、变量 any → 查入口大小写"。
@@ -0,0 +1,20 @@
1
+ ## ArkTS Demo 覆盖率分析:import 路径尾斜杠导致 0% 误报
2
+
3
+ ### 问题现象
4
+
5
+ 运行 `analyze-demo-coverage.cjs`(AST 模式)分析 mp3agic 库 Demo 覆盖率,首轮输出 `Demo 匹配完成: 0/271 (0.00%)`,但 grep 确认 Demo 明确 import 了库的 18 个类。若不人工核验直接采信首轮结果,会得出"Demo 完全未覆盖库接口"的严重错误结论。任何 Demo 源码使用 `from '@ohos/xxx/'`(尾部带 `/`)写法的鸿蒙库都会触发此类 0% 误报。
6
+
7
+ ### 解决方案
8
+
9
+ **根因**:脚本 import 匹配判断 `fromLib === libName || fromLib.endsWith('/' + libName.split('/').pop())` 中,`'@ohos/mp3agic/'` 既不等于 `'@ohos/mp3agic'` 也不以 `'/mp3agic'` 结尾(结尾多了 `/`),所有 import 被静默跳过。正则模式 `extractImportsRegex` 与 AST 模式 `extractImportedSymbolsAST` 存在完全相同的判断缺陷;AST 模式 `resolveModuleNames` 中 `moduleName === libName` 同样失配,导致模块解析失败、库类型坍缩为 `any`。
10
+
11
+ **修复方案**(2026-08-27 已落入 `MCP/scripts/analyze-demo-coverage.cjs` 与 `analyze-xts-coverage.cjs`):
12
+ 1. 对模块说明符先做 `fromLib.replace(/\/+$/, '')` 归一化再比较(正则提取、AST 提取、resolveModuleNames 三处均需修改)
13
+ 2. 同时兼容子路径 import:`fromNorm.startsWith(libName + '/')`(如 `@ohos/xxx/src/...`)
14
+ 3. 默认导入检测正则追加 `(?:/[^'"]*)?` 容错尾斜杠/子路径
15
+
16
+ **旧版本脚本应急 workaround**:将 `entry/src/main/ets` 复制到临时目录,sed 去除 import 尾斜杠(mp3agic 案例 59 处),通过脚本已有的 `--src` 参数指向副本。
17
+
18
+ ### 结果
19
+
20
+ 修复后直接分析原始仓库即得真实覆盖率 69.37%(188/271),与人工核验值完全一致,无需任何副本 workaround。核心经验:覆盖率报告出现 0%/异常低值时,先 grep 确认 Demo 是否 import 了库——快速诊断口诀:"import 有、覆盖无 → 查尾斜杠"。
@@ -0,0 +1,18 @@
1
+ ## ArkTS 三方库源码文件可能是 .ts 扩展名——工程结构验证不要以 .ets 数量为唯一判据
2
+
3
+ ### 问题现象
4
+
5
+ 克隆 ArkTS 三方库 mp3agic(gitcode.com/CPF-ApplicationTPC/mp3agic)后,统计 `library/` 目录下 `.ets` 文件数仅得 1 个,一度怀疑源码缺失。且该库入口文件为小写 `index.ets`,与常见的大写 `Index.ets` 约定不一致。
6
+
7
+ ### 解决方案
8
+
9
+ 深入查看后确认:ArkTS 三方库的实现源码不一定是 `.ets` 文件。mp3agic 的 `library/src/main/ets/components/mp3agic/` 下全部 48 个源文件均为 `.ts` 扩展名(如 `Mp3File.ts`、`ID3v2.ts`),`library/` 下仅入口文件 `index.ets` 一个 `.ets` 文件。验证 ArkTS 库工程结构时应确认以下要素(而非统计 `.ets` 文件数):
10
+
11
+ - 入口文件(`index.ets` / `Index.ets`,匹配需大小写不敏感)
12
+ - `oh-package.json5`
13
+ - `src/main/module.json5`
14
+ - 源码目录存在(不限扩展名,`.ets` 与 `.ts` 均算)
15
+
16
+ ### 结果
17
+
18
+ 以 `oh-package.json5` / `module.json5` / 入口文件的存在作为工程结构有效性判据是可靠的,源码并未缺失。扫描 ArkTS 库源码时应同时包含 `*.ets` 与 `*.ts`(路径限定在 `src/main/ets/` 下),否则会完全遗漏 `.ts` 实现文件;入口统一从 `index.ets` 解析导出。另注意:macOS 文件系统大小写不敏感,`Index.ets` 字面匹配可偶然命中 `index.ets`,但在 Linux(大小写敏感文件系统)上按字面匹配会漏判,入口文件匹配必须显式做大小写不敏感处理。