@hmos-library-adapter/fast 0.0.17-beta.0 → 0.0.17-beta.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 (149) hide show
  1. package/node_modules/@hmos-library-adapter/executer/README.md +2 -2
  2. package/node_modules/@hmos-library-adapter/executer/shared/skill-map.json +5 -1
  3. package/node_modules/@hmos-library-adapter/executer/shared/skills/arkts-rules/SKILL.md +400 -0
  4. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/CHANGELOG.md +1391 -0
  5. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/COMPATIBILITY.md +53 -0
  6. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/README.md +123 -0
  7. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/SKILL.md +48 -0
  8. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/agents/upgrade-assess-change.md +37 -0
  9. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/agents/upgrade-fix-file.md +23 -0
  10. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/package.json +19 -0
  11. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/26.0.0/beta1-changes-for-all-apps.md +1793 -0
  12. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/26.0.0/beta1-ux-style-and-effect-changes.md +288 -0
  13. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/26.0.0/beta2-changes-for-all-apps.md +148 -0
  14. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/26.0.0/release-changes-for-all-apps.md +662 -0
  15. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.1(13)/beta3-os-api-behavior-changes.md +652 -0
  16. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.1(13)/beta3-ux-style-and-effect-changes.md +222 -0
  17. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.1(13)/release-os-api-behavior-changes.md +444 -0
  18. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.1(13)/release-ux-style-and-effect-changes.md +221 -0
  19. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.2(14)/os-api-behavior-changes.md +1767 -0
  20. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.2(14)/ux-style-and-effect-changes.md +134 -0
  21. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.3(15)/beta1-os-api-behavior-changes.md +430 -0
  22. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.3(15)/beta1-ux-style-and-effect-changes.md +49 -0
  23. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.3(15)/beta2-os-api-behavior-changes.md +240 -0
  24. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.3(15)/beta2-ux-style-and-effect-changes.md +90 -0
  25. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.0.3(15)/release-os-api-behavior-changes.md +69 -0
  26. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.1.0(18)/os-api-behavior-changes.md +1294 -0
  27. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/5.1.0(18)/ux-style-and-effect-changes.md +147 -0
  28. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/6.0.0(20)/beta1-os-api-behavior-changes.md +1019 -0
  29. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/6.0.0(20)/beta1-ux-style-and-effect-changes.md +153 -0
  30. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/6.0.0(20)/beta2-os-api-behavior-changes.md +662 -0
  31. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/6.0.0(20)/beta2-ux-style-and-effect-changes.md +78 -0
  32. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/6.0.0(20)/beta3-os-api-behavior-changes.md +167 -0
  33. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/6.0.0(20)/beta5-os-api-behavior-changes.md +52 -0
  34. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs/6.1.0(23)/changes-for-all-apps.md +397 -0
  35. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/changelogs-index.json +883 -0
  36. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/common/arkts-coding-standards.md +53 -0
  37. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/common/compatibility.md +207 -0
  38. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/common/native-adaptation.md +21 -0
  39. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/common/runtime-functional-tests.md +62 -0
  40. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/common/sdk-versions.md +77 -0
  41. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/common/troubleshooting.md +54 -0
  42. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/common/verification.md +79 -0
  43. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/common/workflow-scan.md +41 -0
  44. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/deprecated/context-migration.md +274 -0
  45. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/deprecated/deprecated-api-adaptation.md +157 -0
  46. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/deprecated/deprecated-api-examples.md +219 -0
  47. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/toolchain/hvigor.md +50 -0
  48. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/upgrade/har-upgrade.md +60 -0
  49. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/upgrade/scanner-missed-cases.md +171 -0
  50. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/upgrade/upgrade-compatibility.md +112 -0
  51. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/upgrade/upgrade-examples.md +289 -0
  52. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/references/upgrade/upgrade-workflow.md +122 -0
  53. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/references/generate-behavior-policy.mjs +96 -0
  54. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/references/references.mjs +9 -0
  55. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/regression/compare-deprecated.mjs +57 -0
  56. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/regression/compare-golden.mjs +130 -0
  57. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/regression/regress-deprecated.mjs +120 -0
  58. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/test/behavior-catalog-generation.test.mjs +59 -0
  59. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/test/behavior-local-sources.test.mjs +44 -0
  60. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/test/changelog-index.test.mjs +66 -0
  61. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/test/compare-golden.test.mjs +103 -0
  62. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/test/fixtures/behavior/local-sources.csv +5 -0
  63. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/test/references.test.mjs +16 -0
  64. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/test/skill-content.test.mjs +139 -0
  65. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/test/skill-frontmatter.test.mjs +11 -0
  66. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/test/test-suite.test.mjs +65 -0
  67. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/validation/skill-content.mjs +125 -0
  68. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/validation/skill-frontmatter.mjs +6 -0
  69. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/maintenance/validation/validate-skill.mjs +57 -0
  70. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/CHANGELOG.md +506 -0
  71. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/GOLDEN_VALIDATION.md +42 -0
  72. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/README.md +137 -0
  73. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/behavior/behavior-policy.mjs +117 -0
  74. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/behavior/upgrade-coverage.mjs +29 -0
  75. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/bin/deveco-worker-compat.cjs +21 -0
  76. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/bin/harmony-api-scan.mjs +17 -0
  77. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/core/cli.mjs +416 -0
  78. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/core/deveco.mjs +348 -0
  79. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/core/project.mjs +81 -0
  80. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/core/rules.mjs +425 -0
  81. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/core/runtime-identity.mjs +23 -0
  82. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/core/scan-runner.mjs +521 -0
  83. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/core/sdk-deprecations.mjs +204 -0
  84. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/data/behavior-change-policy.json +4378 -0
  85. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/deprecated/arkts-deprecations.mjs +363 -0
  86. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/deprecated/build-log.mjs +72 -0
  87. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/native/native.mjs +95 -0
  88. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/package.json +16 -0
  89. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/batch-layout.test.mjs +94 -0
  90. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/behavior-policy.test.mjs +75 -0
  91. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/build-log.test.mjs +69 -0
  92. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/cli.test.mjs +102 -0
  93. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/csv.test.mjs +35 -0
  94. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/deprecations.test.mjs +283 -0
  95. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/deveco.test.mjs +262 -0
  96. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/helpers/scan-batch.mjs +10 -0
  97. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/native.test.mjs +108 -0
  98. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/project.test.mjs +42 -0
  99. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/rules.test.mjs +190 -0
  100. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/runtime-identity.test.mjs +53 -0
  101. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/scan-mode.test.mjs +38 -0
  102. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/scan-runner.test.mjs +481 -0
  103. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/scan-scope.test.mjs +110 -0
  104. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/source-inputs.test.mjs +64 -0
  105. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/scanner/test/upgrade.test.mjs +164 -0
  106. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/format/args.mjs +66 -0
  107. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/format/csv.mjs +85 -0
  108. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/format/json5.mjs +92 -0
  109. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/format/upgrade-results.mjs +45 -0
  110. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/format/zip.mjs +87 -0
  111. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/io/fs-utils.mjs +60 -0
  112. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/artifact-layout.mjs +74 -0
  113. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/changelog-index.mjs +29 -0
  114. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/deveco-version.mjs +40 -0
  115. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/document-links.mjs +30 -0
  116. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/errors.mjs +41 -0
  117. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/fs.mjs +72 -0
  118. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/paths.mjs +34 -0
  119. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/process.mjs +154 -0
  120. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/scan-mode.mjs +7 -0
  121. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/scan-statistics.mjs +7 -0
  122. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/scan-version-catalog.json +43 -0
  123. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/scan-versions.mjs +51 -0
  124. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/sdk-layout.mjs +27 -0
  125. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/source-scope.mjs +108 -0
  126. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/source-types.mjs +7 -0
  127. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/platform/version.mjs +76 -0
  128. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/test/deveco-version.test.mjs +50 -0
  129. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/test/document-links.test.mjs +13 -0
  130. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/test/errors.test.mjs +40 -0
  131. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/test/fs-utils.test.mjs +31 -0
  132. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/test/platform-paths.test.mjs +19 -0
  133. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/test/process-utils.test.mjs +68 -0
  134. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/test/scan-versions.test.mjs +26 -0
  135. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/test/sdk-version.test.mjs +17 -0
  136. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/shared/test/upgrade-results.test.mjs +140 -0
  137. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/scripts/test-suite.mjs +29 -0
  138. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/templates/deprecated-report.md +86 -0
  139. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/templates/progress.md +150 -0
  140. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/templates/results.md +110 -0
  141. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/templates/upgrade-report.md +105 -0
  142. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/templates/upgrade-spec.md +58 -0
  143. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-api-upgrade-adapter/templates/upgrade-test-report.md +47 -0
  144. package/node_modules/@hmos-library-adapter/executer/shared/skills/harmonyos-knowledge/SKILL.md +70 -0
  145. package/node_modules/@hmos-library-adapter/executer/src/config.js +3 -4
  146. package/node_modules/@hmos-library-adapter/executer/src/doctor.js +1 -1
  147. package/node_modules/@hmos-library-adapter/executer/src/install.js +1 -1
  148. package/node_modules/@hmos-library-adapter/executer/src/paths.js +4 -4
  149. package/package.json +1 -1
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env node
2
+ import { readFile, writeFile } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { parseArgs, requireString } from '../../shared/format/args.mjs';
5
+ import { parseCsv } from '../../shared/format/csv.mjs';
6
+ import { canonicalHarmonyVersion as canonicalVersion } from '../../shared/platform/version.mjs';
7
+ import { comparableCodeLocation } from '../../shared/platform/paths.mjs';
8
+
9
+ function titleText(value) {
10
+ const match = String(value).match(/^=HYPERLINK\("(?:[^"]|"")*","((?:[^"]|"")*)"\)$/i);
11
+ return match ? match[1].replaceAll('""', '"') : String(value);
12
+ }
13
+
14
+ function normalizeLocation(value, projectRoot) {
15
+ return comparableCodeLocation(value, projectRoot);
16
+ }
17
+
18
+ function normalizeVersion(value) {
19
+ try {
20
+ return canonicalVersion(String(value));
21
+ } catch {
22
+ return String(value).trim();
23
+ }
24
+ }
25
+
26
+ function normalizedKey(row, projectRoot) {
27
+ return [
28
+ String(row['Api Definition']).replace(/\s+/g, ' ').trim(),
29
+ row.Language,
30
+ normalizeVersion(row['Changed in SDK']),
31
+ titleText(row.Title),
32
+ normalizeLocation(row['Code Location'], projectRoot),
33
+ row['Change Type'],
34
+ ].join('\u0000');
35
+ }
36
+
37
+ function multiset(rows, projectRoot, keyOf = normalizedKey) {
38
+ const result = new Map();
39
+ for (const row of rows) {
40
+ const key = keyOf(row, projectRoot);
41
+ const record = result.get(key) ?? { count: 0, row };
42
+ record.count += 1;
43
+ result.set(key, record);
44
+ }
45
+ return result;
46
+ }
47
+
48
+ function difference(left, right) {
49
+ const rows = [];
50
+ for (const [key, value] of left) {
51
+ const remaining = value.count - (right.get(key)?.count ?? 0);
52
+ for (let index = 0; index < Math.max(0, remaining); index += 1) rows.push(value.row);
53
+ }
54
+ return rows;
55
+ }
56
+
57
+ function isDevEcoRule(row) {
58
+ if (row['Detection Source'] && row['Detection Source'] !== 'DEVECO') return false;
59
+ if (!('Rule ID' in row)) return true;
60
+ return !isAdditionalDocumentRule(row);
61
+ }
62
+
63
+ function isAdditionalDocumentRule(row) {
64
+ return String(row['Source Reference']).replaceAll('\\', '/').includes('/API变更清单/');
65
+ }
66
+
67
+ const args = parseArgs(process.argv.slice(2));
68
+ const goldenPath = path.resolve(requireString(args, 'golden'));
69
+ const actualPath = path.resolve(requireString(args, 'actual'));
70
+ const projectRoot = args.project ? path.resolve(args.project) : null;
71
+ const outputPath = args.output ? path.resolve(args.output) : null;
72
+ const scanJsonPath = args['scan-json'] ? path.resolve(args['scan-json']) : null;
73
+ const golden = parseCsv(await readFile(goldenPath, 'utf8')).rows;
74
+ const actualCsv = parseCsv(await readFile(actualPath, 'utf8'));
75
+ const scan = scanJsonPath ? JSON.parse(await readFile(scanJsonPath, 'utf8')) : null;
76
+ if (!scan && actualCsv.headers.includes('Replacement API') && !actualCsv.headers.includes('Rule ID'))
77
+ throw new Error('Reduced deprecated CSV requires --scan-json for source and symbol identities');
78
+ const fullFindings = scan ? scan.findings : actualCsv.rows;
79
+ const allActual = scan?.mode === 'deprecated' && Array.isArray(scan.actionGroups)
80
+ ? scan.actionGroups.map(group => ({
81
+ ...group.occurrences[0],
82
+ 'Action Type': group.actionType, 'Policy ID': group.policyId,
83
+ 'Occurrence Count': group.occurrenceCount, 'Trigger Evidence': group.triggerEvidence,
84
+ }))
85
+ : scan ? fullFindings.filter(finding => finding.includedInCsv !== false) : actualCsv.rows;
86
+ if (scan) {
87
+ const visibleKey = row => JSON.stringify(actualCsv.headers.map(header => {
88
+ if (header === 'Code Location') return normalizeLocation(row[header], projectRoot);
89
+ if (header === 'Changed in SDK') return normalizeVersion(row[header] ?? '');
90
+ return String(row[header] ?? '');
91
+ }));
92
+ const csvRows = multiset(actualCsv.rows, projectRoot, visibleKey);
93
+ const reportedRows = multiset(allActual, projectRoot, visibleKey);
94
+ if (difference(csvRows, reportedRows).length || difference(reportedRows, csvRows).length)
95
+ throw new Error('Actual CSV does not match reported scan JSON rows: visible fields or multiplicity differ');
96
+ }
97
+ const actual = allActual.filter(isDevEcoRule);
98
+ const fullActual = fullFindings.filter(isDevEcoRule);
99
+ const deprecated = allActual.filter((row) => row['Change Operation'] === 'API_DEPRECATED' || row['Change Type'] === 'Deprecated API');
100
+ const goldenSet = multiset(golden, projectRoot);
101
+ const actualSet = multiset(actual, projectRoot);
102
+ const fullActualSet = multiset(fullActual, projectRoot);
103
+ const missing = difference(goldenSet, fullActualSet);
104
+ const notReported = difference(goldenSet, actualSet);
105
+ const extra = difference(actualSet, goldenSet);
106
+ const matched = golden.length - missing.length;
107
+ const report = {
108
+ schemaVersion: scanJsonPath ? 2 : 1,
109
+ goldenPath,
110
+ actualPath,
111
+ scanJsonPath,
112
+ projectRoot,
113
+ goldenRows: golden.length,
114
+ actualDevEcoRows: fullActual.length,
115
+ reportedDevEcoRows: actual.length,
116
+ filteredGoldenRows: Math.max(0, notReported.length - missing.length),
117
+ actualAdditionalDocumentRules: allActual.filter(isAdditionalDocumentRule).length,
118
+ actualDeprecatedRows: deprecated.length,
119
+ actualDistinctDeprecatedApis: new Set(deprecated.map((row) => row['API Symbol ID']
120
+ || [row['Rule ID'] ?? '', row['Api Definition']].join('\u0000'))).size,
121
+ matchedRows: matched,
122
+ missingRows: missing.length,
123
+ extraRows: extra.length,
124
+ recall: golden.length === 0 ? 1 : matched / golden.length,
125
+ precision: actual.length === 0 ? (golden.length === 0 ? 1 : 0) : (actual.length - extra.length) / actual.length,
126
+ missingSample: missing.slice(0, 100),
127
+ extraSample: extra.slice(0, 100),
128
+ };
129
+ if (outputPath) await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`);
130
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
@@ -0,0 +1,120 @@
1
+ import { finished } from 'node:stream/promises';
2
+ import { createWriteStream } from 'node:fs';
3
+ import { cp, mkdir, readFile, mkdtemp } from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import os from 'node:os';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { parseArgs, requireString, stringList } from '../../shared/format/args.mjs';
8
+ import { discoverDevEco } from '../../scanner/core/deveco.mjs';
9
+ import { buildSdkCatalog } from '../../scanner/core/sdk-deprecations.mjs';
10
+ import { loadProject } from '../../scanner/core/project.mjs';
11
+ import { atomicWrite, exists, sha256 } from '../../shared/io/fs-utils.mjs';
12
+ import { compareDeprecated } from './compare-deprecated.mjs';
13
+ import { runProcess, prependPath } from '../../shared/platform/process.mjs';
14
+
15
+ const scannerRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../scanner');
16
+ const args = parseArgs(process.argv.slice(2));
17
+ const projects = stringList(args.project);
18
+ const refs = stringList(args.ref);
19
+ if (!projects.length || refs.length !== projects.length) throw new Error('Pass matching repeated --project and --ref arguments');
20
+ const toolchain = await discoverDevEco(requireString(args, 'sdk'));
21
+ for (const name of ['java', 'ohpm', 'hvigorw']) if (!toolchain[name]) throw new Error(`Build tool is missing: ${name}`);
22
+ const output = path.resolve(args['output-dir'] || await mkdtemp(path.join(os.tmpdir(), 'deprecated-regression-')));
23
+ await mkdir(output, { recursive: true });
24
+ const environment = prependPath({ ...process.env, DEVECO_SDK_HOME: toolchain.sdkRoot, JAVA_HOME: path.dirname(path.dirname(toolchain.java)) },
25
+ [path.dirname(process.execPath), path.dirname(toolchain.ohpm), path.dirname(toolchain.hvigorw), path.dirname(toolchain.java)]);
26
+ async function run(command, argv, cwd, logPath = null) {
27
+ const stream = logPath ? createWriteStream(logPath) : null;
28
+ const complete = stream ? finished(stream) : Promise.resolve();
29
+ let streamError = null, text = '';
30
+ complete.catch(error => { streamError = error; });
31
+ try {
32
+ const result = await runProcess(command, argv, { cwd, env: environment, detached: true, timeoutMs: 30 * 60_000,
33
+ onOutput(chunk) { text += chunk; if (streamError) throw streamError; stream?.write(chunk); } });
34
+ if (result.error) throw new Error(result.error);
35
+ return { code: result.timedOut ? 124 : result.exitCode ?? 1, text };
36
+ } finally {
37
+ stream?.end();
38
+ await complete;
39
+ }
40
+ }
41
+ const cases = [];
42
+ for (const [index, original] of projects.entries()) {
43
+ const name = path.basename(original);
44
+ const caseRoot = path.join(output, name);
45
+ const checkout = path.join(caseRoot, 'project');
46
+ await mkdir(caseRoot, { recursive: true });
47
+ if (await exists(checkout)) {
48
+ if (!args['reuse-checkouts']) throw new Error(`Checkout already exists: ${checkout}; choose a new output directory or --reuse-checkouts`);
49
+ const origin = await run('git', ['remote', 'get-url', 'origin'], checkout);
50
+ const head = await run('git', ['rev-parse', 'HEAD'], checkout);
51
+ const desired = await run('git', ['rev-parse', refs[index]], checkout);
52
+ if (origin.text.trim() !== original || head.text !== desired.text) throw new Error('Refusing to reuse a different checkout');
53
+ } else {
54
+ const clone = await run('git', ['clone', '--no-hardlinks', '--no-checkout', original, checkout], output);
55
+ if (clone.code) throw new Error(clone.text);
56
+ const checkoutResult = await run('git', ['checkout', '--detach', refs[index]], checkout);
57
+ if (checkoutResult.code) throw new Error(checkoutResult.text);
58
+ }
59
+ if (args['use-project-build-profile']) await cp(path.join(original, 'build-profile.json5'), path.join(checkout, 'build-profile.json5'));
60
+ const project = await loadProject(checkout, 'default');
61
+ for (const relative of ['oh_modules', ...project.modules.map(item => `${item.relativeRoot}/oh_modules`),
62
+ ...project.modules.map(item => `${item.relativeRoot}/src/main/resources/rawfile`)]) {
63
+ const source = path.join(original, relative);
64
+ if (await exists(source)) await cp(source, path.join(checkout, relative), { recursive: true, verbatimSymlinks: true, force: false, errorOnExist: false });
65
+ }
66
+ for (const [command, argv] of [[toolchain.java, ['-version']], [process.execPath, ['-v']],
67
+ [toolchain.ohpm, ['-v']], [toolchain.hvigorw, ['-v']]]) {
68
+ const result = await run(command, argv, checkout);
69
+ if (result.code) throw new Error(`Environment check failed: ${command}\n${result.text}`);
70
+ }
71
+ if (!environment.DEVECO_SDK_HOME) throw new Error('DEVECO_SDK_HOME missing');
72
+ console.log(`${name}: isolated checkout ready; non-incremental assembleApp`);
73
+ const logPath = path.join(caseRoot, 'build.log');
74
+ const before = await loadProject(checkout, 'default');
75
+ const build = await run(toolchain.hvigorw, ['--mode', 'project', '-p', 'product=default', 'assembleApp', '--analyze=normal', '--parallel', '--no-incremental', '--no-daemon'], checkout, logPath);
76
+ const after = await loadProject(checkout, 'default');
77
+ const catalog = await buildSdkCatalog(toolchain);
78
+ const record = { name, original, revision: refs[index], checkout,
79
+ buildProfileSource: args['use-project-build-profile'] ? 'CURRENT_PROJECT_CONFIG' : 'GIT_BASELINE_CONFIG', buildProfileHash: after.buildProfileHash,
80
+ buildExitCode: build.code, buildSourceStable: before.sourceSnapshot === after.sourceSnapshot && before.buildProfileHash === after.buildProfileHash };
81
+ cases.push(record);
82
+ await atomicWrite(path.join(output, 'regression.json'), JSON.stringify({ cases }, null, 2));
83
+ if (build.code || !record.buildSourceStable) { console.log(`${name}: build/input verification failed; see ${logPath}`); continue; }
84
+ const evidencePath = path.join(caseRoot, 'build-evidence.json');
85
+ await atomicWrite(evidencePath, JSON.stringify({ schemaVersion: 1, projectRoot: after.root, product: 'default',
86
+ logHash: sha256(await readFile(logPath)), sourceSnapshot: after.sourceSnapshot, sdkSnapshot: catalog.snapshot,
87
+ buildProfileHash: after.buildProfileHash,
88
+ targetSdk: catalog.coverage.targetSdk, nonIncremental: true, status: 'PASSED' }, null, 2));
89
+ const scanResults = [];
90
+ for (const round of [1, 2]) {
91
+ const destination = path.join(caseRoot, `scan-${round}`);
92
+ console.log(`${name}: scan ${round}/2`);
93
+ const result = await run(process.execPath, [path.join(scannerRoot, 'bin/harmony-api-scan.mjs'), 'scan', '--mode', 'deprecated', '--project', checkout,
94
+ '--sdk', toolchain.sdkRoot, '--from', args.from || '5.0.0(12)', '--to', args.to || catalog.coverage.targetSdk,
95
+ '--product', 'default', '--native-build', 'off', '--output-dir', destination], scannerRoot, path.join(caseRoot, `scan-${round}.log`));
96
+ const report = result.code === 0 ? JSON.parse(result.text).result : null;
97
+ scanResults.push({ code: result.code, destination, outputCsv: report?.outputCsv, scanJson: report?.scanJson });
98
+ }
99
+ record.scanExitCodes = scanResults.map(item => item.code);
100
+ if (scanResults.every(item => item.code === 0)) {
101
+ const comparison = await compareDeprecated({ project: checkout, buildLog: logPath,
102
+ scanJson: scanResults[0].scanJson, buildProjectRoot: after.root, buildEvidence: evidencePath });
103
+ await atomicWrite(path.join(caseRoot, 'comparison.json'), JSON.stringify(comparison, null, 2));
104
+ record.projectGoldCount = comparison.projectGoldCount;
105
+ record.projectMissingCount = comparison.projectMissingCount;
106
+ record.scannerOnlyCount = comparison.scannerOnlyCount;
107
+ record.csvIdentical = sha256(await readFile(scanResults[0].outputCsv)) === sha256(await readFile(scanResults[1].outputCsv));
108
+ const scans = await Promise.all(scanResults.map(item => readFile(item.scanJson, 'utf8')));
109
+ const snapshots = scans.map(text => { const { batchId, ...snapshot } = JSON.parse(text); return JSON.stringify(snapshot); });
110
+ record.scanJsonIdentical = snapshots[0] === snapshots[1];
111
+ record.deprecatedCount = JSON.parse(scans[0]).findings.filter(item => item['Change Operation'] === 'API_DEPRECATED').length;
112
+ console.log(`${name}: project gold ${record.projectGoldCount}, missing ${record.projectMissingCount}, deprecated ${record.deprecatedCount}, deterministic ${record.csvIdentical && record.scanJsonIdentical}`);
113
+ }
114
+ await atomicWrite(path.join(output, 'regression.json'), JSON.stringify({ cases }, null, 2));
115
+ }
116
+ const passed = cases.length === projects.length && cases.every(item => item.buildExitCode === 0 && item.buildSourceStable
117
+ && item.scanExitCodes?.every(code => code === 0) && item.projectMissingCount === 0 && item.csvIdentical && item.scanJsonIdentical);
118
+ await atomicWrite(path.join(output, 'regression.json'), JSON.stringify({ status: passed ? 'PASSED' : 'FAILED', cases }, null, 2));
119
+ console.log(`Regression ${passed ? 'PASSED' : 'FAILED'}: ${output}`);
120
+ if (!passed) process.exitCode = 1;
@@ -0,0 +1,59 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { execFile } from 'node:child_process';
4
+ import { promisify } from 'node:util';
5
+ import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
6
+ import { fileURLToPath } from 'node:url';
7
+ import path from 'node:path';
8
+ import os from 'node:os';
9
+ import { stringifyCsv } from '../../shared/format/csv.mjs';
10
+ import { behaviorSourceHash, loadBehaviorPolicy, validateBehaviorPolicySources } from '../../scanner/behavior/behavior-policy.mjs';
11
+ import { sha256 } from '../../shared/io/fs-utils.mjs';
12
+
13
+ const run = promisify(execFile);
14
+
15
+ test('catalog generation keeps official facts and stable identities without full-mode action heuristics', async t => {
16
+ const root = await mkdtemp(path.join(os.tmpdir(), 'catalog-source-中文 空格-'));
17
+ t.after(() => rm(root, { recursive: true, force: true }));
18
+ const refs = path.join(root, 'changelogs');
19
+ const newPath = path.posix.join('26.0.0', 'beta1-changes.md');
20
+ await mkdir(path.dirname(path.join(refs, newPath)), { recursive: true });
21
+ const original = '# 文档\n\n## 字体默认布局变更\n', row = {
22
+ Title: '字体默认布局变更', 'Source URL': 'https://example.test/change#font',
23
+ 'Changed in SDK': '26.0.0(26) Beta1', 'Affected Versions': 'ALL', 'Affected Device Types': 'phone',
24
+ Scope: 'UX Style/Effect', 'Requires Adaptation': '是', 'Change Type': 'UX Style/Effect Change',
25
+ 'Adaptation Basis': '官方原因', 'Adaptation Guidance': '官方指导:检查布局。',
26
+ };
27
+ await writeFile(path.join(root, 'changelogs-index.json'), JSON.stringify({ schemaVersion: 1,
28
+ documents: [{ path: newPath }], overview: [] }));
29
+ const script = fileURLToPath(new URL('../references/generate-behavior-policy.mjs', import.meta.url));
30
+ for (const [sourcePath, newline] of [[newPath, '\n'], [newPath, '\r\n'], [newPath.replaceAll('/', '\\'), '\n']]) {
31
+ await writeFile(path.join(refs, newPath), original.replaceAll('\n', newline));
32
+ const record = { ...row, 'Source Reference': `${sourcePath}:3` };
33
+ const catalog = path.join(root, '来源.csv'), output = path.join(root, 'catalog.json');
34
+ const baseline = { ...record, 'Source Reference': '5.0.0(12)/missing.md:1' };
35
+ await writeFile(catalog, stringifyCsv(Object.keys(record), [baseline, record]));
36
+ await run(process.execPath, [script, '--catalog', catalog, '--references', refs, '--output', output]);
37
+ const generated = await loadBehaviorPolicy(output), entry = generated.entries[0];
38
+ assert.equal(entry.apiLevel, 26);
39
+ assert.equal(entry.sourceReference, `${newPath}:3`);
40
+ assert.equal(entry.policyId, `font-${sha256(`${newPath}:3`).slice(0, 8)}`);
41
+ assert.equal(entry.sourceFileHash, behaviorSourceHash(original));
42
+ assert.equal(entry.documentConclusion, '是'); assert.equal(entry.rationale, '官方原因');
43
+ assert.equal(entry.triggerEvidence, row['Adaptation Guidance']);
44
+ assert.deepEqual(generated.counts, { 'UX Visual Layout Change': 1 });
45
+ for (const field of ['actionType', 'detectionMode', 'staticChecks', 'validationType', 'validationGuidance'])
46
+ assert.ok(!Object.hasOwn(entry, field));
47
+ assert.equal((await validateBehaviorPolicySources(generated, refs)).status, 'COMPLETE');
48
+ assert.equal(JSON.parse(await readFile(output, 'utf8')).entryCount, 1);
49
+ }
50
+ const catalog = path.join(root, '来源.csv'), output = path.join(root, 'catalog.json');
51
+ const saved = await readFile(output);
52
+ for (const unknownPath of [path.posix.join('26.0.0', 'unregistered.md'),
53
+ path.posix.join('26.0.0', 'OS平台能力', '正文.md'), path.posix.join('26.0.0', 'Beta1-正文.md')]) {
54
+ const record = { ...row, 'Source Reference': `${unknownPath}:3` };
55
+ await writeFile(catalog, stringifyCsv(Object.keys(record), [record]));
56
+ await assert.rejects(run(process.execPath, [script, '--catalog', catalog, '--references', refs, '--output', output]), /Unknown changelog source/);
57
+ assert.deepEqual(await readFile(output), saved);
58
+ }
59
+ });
@@ -0,0 +1,44 @@
1
+ // Corpus and documentation contracts only; these do not certify model reading or business applicability.
2
+ import test from 'node:test';
3
+ import assert from 'node:assert/strict';
4
+ import { readFile } from 'node:fs/promises';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { parseCsv } from '../../shared/format/csv.mjs';
8
+ import { loadChangelogIndex } from '../../shared/platform/changelog-index.mjs';
9
+ import { canonicalHarmonyVersion, compareHarmonyVersions } from '../../shared/platform/version.mjs';
10
+
11
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
12
+ const references = path.join(root, 'references');
13
+ const changelogs = path.join(references, 'changelogs');
14
+ const expected = [
15
+ ['CH2026010615012', 966],
16
+ ['CH2026031846233', 36],
17
+ ['CH2026032761266', 146],
18
+ ['CH2026032801249', 87],
19
+ ];
20
+
21
+ test('four-change fixture resolves current local headings and exact versions', async () => {
22
+ const { rows } = parseCsv(await readFile(new URL('./fixtures/behavior/local-sources.csv', import.meta.url), 'utf8'));
23
+ const index = await loadChangelogIndex(changelogs);
24
+ const policy = JSON.parse(await readFile(path.join(root, 'scripts', 'scanner', 'data', 'behavior-change-policy.json'), 'utf8'));
25
+ assert.deepEqual(rows.map(row => row['Rule ID']), expected.map(([id]) => id));
26
+ assert.equal(new Set(rows.map(row => row['Source Reference'])).size, 4);
27
+ for (const [i, row] of rows.entries()) {
28
+ const [id, line] = expected[i];
29
+ const source = row['Source Reference'];
30
+ const relative = source.replace(/:\d+$/, '');
31
+ assert.ok(source.endsWith(`:${line}`));
32
+ const document = index.documents.find(entry => entry.path === relative);
33
+ assert.ok(document, source);
34
+ const contents = (await readFile(path.join(changelogs, relative), 'utf8')).split(/\r?\n/);
35
+ assert.equal(contents[line - 1].replace(/^#+\s+/, ''), row.Title);
36
+ const matches = policy.entries.filter(entry => entry.sourceReference === source
37
+ && compareHarmonyVersions(entry.changedInSdk, row['Changed in SDK']) === 0);
38
+ assert.equal(matches.length, 1, `${id}: exact official identity`);
39
+ assert.equal(new URL(matches[0].sourceUrl).hash, `#${id.toLowerCase()}`);
40
+ assert.equal(compareHarmonyVersions(matches[0].changedInSdk, '26.0.0(26) Beta2'), -1);
41
+ assert.equal(compareHarmonyVersions(matches[0].changedInSdk, '26.0.0(26) Release'), -1);
42
+ assert.equal(canonicalHarmonyVersion(row['Changed in SDK']), '26.0.0(26) Beta1');
43
+ }
44
+ });
@@ -0,0 +1,66 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtemp, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
4
+ import { fileURLToPath } from 'node:url';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import { loadChangelogIndex } from '../../shared/platform/changelog-index.mjs';
8
+ import { referenceDigest } from '../references/references.mjs';
9
+
10
+ const skillRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
11
+ const referenceRoot = path.join(skillRoot, 'references', 'changelogs');
12
+
13
+ test('bundled corpus has 24 intact ASCII-named source documents under seven API13+ versions', async () => {
14
+ const index = await loadChangelogIndex(referenceRoot);
15
+ const versions = (await readdir(referenceRoot, { withFileTypes: true })).filter(entry => entry.name !== '.DS_Store');
16
+ assert.equal(versions.length, 7);
17
+ assert.ok(!versions.some(entry => entry.name === '5.0.0(12)'));
18
+ assert.ok(versions.every(entry => entry.isDirectory()));
19
+ const actual = [];
20
+ for (const version of versions) {
21
+ const files = (await readdir(path.join(referenceRoot, version.name), { withFileTypes: true }))
22
+ .filter(entry => entry.name !== '.DS_Store');
23
+ assert.ok(files.length > 0);
24
+ assert.ok(files.every(entry => entry.isFile() && entry.name.endsWith('.md')));
25
+ actual.push(...files.map(entry => path.posix.join(version.name, entry.name)));
26
+ }
27
+ assert.equal(index.documents.length, 24);
28
+ assert.deepEqual(actual.sort(), index.documents.map(entry => entry.path).sort());
29
+ assert.equal(new Set(actual.map(file => file.toLowerCase())).size, 24);
30
+ assert.ok(actual.every(file => /^[\x20-\x7e]+$/.test(file)));
31
+ assert.equal(index.overview.length, 195);
32
+ assert.ok(index.overview.every(entry => entry.version !== '5.0.0(12)'));
33
+ assert.ok(index.overview.every(entry => !Object.hasOwn(entry, 'originalSourceReference')));
34
+ for (const document of index.documents) {
35
+ assert.deepEqual(Object.keys(document).sort(), ['path', 'sha256']);
36
+ const file = path.join(referenceRoot, document.path);
37
+ assert.equal(await referenceDigest(file), document.sha256, document.path);
38
+ const text = await readFile(file, 'utf8');
39
+ for (const field of ['变更原因', '变更影响', '适配指导']) assert.ok(text.includes(`**${field}**`), document.path);
40
+ }
41
+ });
42
+
43
+ test('current document paths handle Windows separators and reject unsafe or duplicate identities', async t => {
44
+ const root = await mkdtemp(path.join(os.tmpdir(), 'changelog-中文 空格-'));
45
+ t.after(() => rm(root, { recursive: true, force: true }));
46
+ const refs = path.join(root, 'changelogs'), file = path.join(root, 'changelogs-index.json');
47
+ await mkdir(refs);
48
+ assert.deepEqual(await loadChangelogIndex(refs), { documents: [], overview: [] });
49
+ const source = { path: path.posix.join('26.0.0', 'beta1-changes.md') };
50
+ const document = { schemaVersion: 1, documents: [source], overview: [] };
51
+ await writeFile(file, JSON.stringify(document));
52
+ assert.deepEqual(await loadChangelogIndex(refs), document);
53
+ await writeFile(file, JSON.stringify({ ...document, documents: [{ path: source.path.replaceAll('/', '\\') }] }));
54
+ assert.deepEqual(await loadChangelogIndex(refs), document);
55
+ for (const value of [path.posix.join('..', 'outside.md'), path.win32.join('C:\\', 'outside.md'),
56
+ path.posix.join('/', 'outside.md'), '26.0.0/../outside.md', '26.0.0//file.md', '', 7]) {
57
+ await writeFile(file, JSON.stringify({ ...document, documents: [{ path: value }] }));
58
+ await assert.rejects(loadChangelogIndex(refs), /Invalid changelog document path/);
59
+ }
60
+ for (const duplicate of [source.path, source.path.toUpperCase(), source.path.replaceAll('/', '\\')]) {
61
+ await writeFile(file, JSON.stringify({ ...document, documents: [source, { path: duplicate }] }));
62
+ await assert.rejects(loadChangelogIndex(refs), /Duplicate changelog document path/);
63
+ }
64
+ await writeFile(file, '{');
65
+ await assert.rejects(loadChangelogIndex(refs), SyntaxError);
66
+ });
@@ -0,0 +1,103 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtemp, rm, writeFile } from 'node:fs/promises';
4
+ import { runProcess } from '../../shared/platform/process.mjs';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { DEPRECATED_HEADERS, stringifyCsv, UPGRADE_HEADERS } from '../../shared/format/csv.mjs';
9
+
10
+ const packageRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
11
+
12
+ async function run(command, args) {
13
+ const result = await runProcess(command, args, { timeoutMs: 30_000, detached: true });
14
+ return { ...result, code: result.exitCode };
15
+ }
16
+
17
+ test('counts documented no-adaptation rows as covered through scan JSON', async () => {
18
+ const root = await mkdtemp(path.join(os.tmpdir(), 'scanner-golden-audit-'));
19
+ const golden = path.join(root, 'golden.csv');
20
+ const actual = path.join(root, 'actual.csv');
21
+ const scanJson = path.join(root, 'apiChange.scan.json');
22
+ const base = {
23
+ 'Api Definition': 'run(): void', Language: 'ArkTS', 'Changed in SDK': '6.0.0(20) Beta1',
24
+ 'Affected Versions': 'ALL', Fixed: 'Unfixed', 'Change Type': 'API Behavior Change',
25
+ };
26
+ const reported = { ...base, Title: '需要适配', 'Code Location': 'entry/A.ets:1', 'Rule ID': 'r1', 'Change Operation': 'API_BEHAVIOR', 'Source Reference': 'behavior.md:1' };
27
+ const filtered = { ...base, Title: '无需适配', 'Code Location': 'entry/A.ets:2', 'Rule ID': 'r2', 'Change Operation': 'API_BEHAVIOR', 'Source Reference': 'behavior.md:2', includedInCsv: false, disposition: 'FILTERED_COMPATIBLE', filterReason: 'DOCUMENTED_NO_ADAPTATION' };
28
+ const headers = ['Api Definition', 'Language', 'Changed in SDK', 'Affected Versions', 'Title', 'Code Location', 'Fixed', 'Change Type'];
29
+ await writeFile(golden, stringifyCsv(headers, [reported, filtered]));
30
+ await writeFile(actual, stringifyCsv(UPGRADE_HEADERS, [reported]));
31
+ await writeFile(scanJson, `${JSON.stringify({ findings: [{ ...reported, includedInCsv: true }, filtered] })}\n`);
32
+
33
+ const result = await run(process.execPath, [
34
+ path.join(packageRoot, 'regression', 'compare-golden.mjs'),
35
+ '--golden', golden,
36
+ '--actual', actual,
37
+ '--scan-json', scanJson,
38
+ ]);
39
+ assert.equal(result.code, 0, result.stderr);
40
+ const report = JSON.parse(result.stdout);
41
+ assert.equal(report.matchedRows, 2);
42
+ assert.equal(report.missingRows, 0);
43
+ assert.equal(report.filteredGoldenRows, 1);
44
+ assert.equal(report.reportedDevEcoRows, 1);
45
+ assert.equal(report.recall, 1);
46
+ });
47
+
48
+ for (const mode of ['upgrade', 'deprecated']) {
49
+ test(`${mode} golden comparison checks reduced CSV multiplicity and uses complete JSON identities`, async t => {
50
+ const root = await mkdtemp(path.join(os.tmpdir(), 'reduced-golden-中文 '));
51
+ t.after(() => rm(root, { recursive: true, force: true }));
52
+ const golden = path.join(root, 'golden.csv'), actual = path.join(root, 'actual.csv'), scanJson = path.join(root, 'scan.json');
53
+ const headers = mode === 'upgrade' ? UPGRADE_HEADERS : DEPRECATED_HEADERS;
54
+ const findings = [1, 8].map(Column => ({
55
+ 'Api Definition': 'old(): void', Language: 'ArkTS', 'Changed in SDK': '6.0.0(20) Beta1',
56
+ 'Affected Versions': 'ALL', Title: '变更', 'Code Location': 'entry/A.ets:1', Fixed: 'Unfixed',
57
+ 'Change Type': mode === 'upgrade' ? 'API Behavior Change' : 'Deprecated API',
58
+ 'Rule ID': 'same-rule', 'Source Reference': 'behavior.md:1', 'Replacement API': 'new()',
59
+ 'API Symbol ID': `symbol-${Column}`, 'Detection Source': mode === 'upgrade' ? 'DEVECO' : 'SDK_STATE',
60
+ Column, includedInCsv: true,
61
+ }));
62
+ const rows = [...findings].reverse();
63
+ const scan = { mode, findings, ...(mode === 'deprecated' ? { actionGroups: rows.map(row => ({ occurrences: [row] })) } : {}) };
64
+ await writeFile(golden, stringifyCsv(headers, mode === 'upgrade' ? findings : []));
65
+ await writeFile(actual, stringifyCsv(headers, rows));
66
+ await writeFile(scanJson, JSON.stringify(scan));
67
+ const compare = () => run(process.execPath, [path.join(packageRoot, 'regression', 'compare-golden.mjs'),
68
+ '--golden', golden, '--actual', actual, '--scan-json', scanJson]);
69
+ const result = await compare();
70
+ assert.equal(result.code, 0, result.stderr);
71
+ const report = JSON.parse(result.stdout);
72
+ assert.equal(report.reportedDevEcoRows, mode === 'upgrade' ? 2 : 0);
73
+ assert.equal(report.actualDeprecatedRows, mode === 'deprecated' ? 2 : 0);
74
+ assert.equal(report.actualDistinctDeprecatedApis, mode === 'deprecated' ? 2 : 0);
75
+ assert.equal(report.actualAdditionalDocumentRules, 0);
76
+ assert.equal(report.missingRows, 0);
77
+ if (mode === 'deprecated') {
78
+ const missingJson = await run(process.execPath, [path.join(packageRoot, 'regression', 'compare-golden.mjs'),
79
+ '--golden', golden, '--actual', actual]);
80
+ assert.equal(missingJson.code, 1);
81
+ assert.match(missingJson.stderr, /requires --scan-json/);
82
+ }
83
+ for (const invalid of [[rows[0]], [...rows, rows[0]], [{ ...rows[0], Title: '错误标题' }, rows[1]]]) {
84
+ await writeFile(actual, stringifyCsv(headers, invalid));
85
+ const mismatch = await compare();
86
+ assert.equal(mismatch.code, 1);
87
+ assert.match(mismatch.stderr, /CSV does not match reported scan JSON/);
88
+ }
89
+ });
90
+ }
91
+
92
+ test('golden comparison strips a native absolute project root and preserves line and column',async()=>{
93
+ const root=await mkdtemp(path.join(os.tmpdir(),'golden spaces 中文-'));
94
+ const golden=path.join(root,'golden.csv'),actual=path.join(root,'actual.csv');
95
+ const row={'Api Definition':'api(): void',Language:'ArkTS','Changed in SDK':'26',Title:'变更','Code Location':'entry/A.ets:12:4','Change Type':'API Behavior Change'};
96
+ const absolute=path.join(root,'entry/A.ets')+':12:4';
97
+ await writeFile(golden,stringifyCsv(Object.keys(row),[{...row,'Code Location':process.platform==='win32'?absolute.toUpperCase():absolute}]));
98
+ await writeFile(actual,stringifyCsv(Object.keys(row),[row]));
99
+ const result=await run(process.execPath,[path.join(packageRoot,'regression/compare-golden.mjs'),'--golden',golden,'--actual',actual,'--project',root]);
100
+ assert.equal(result.code,0,result.stderr);
101
+ const report=JSON.parse(result.stdout);
102
+ assert.equal(report.missingRows,0);assert.equal(report.extraRows,0);
103
+ });
@@ -0,0 +1,5 @@
1
+ Api Definition,Language,Changed in SDK,Affected Versions,Title,Code Location,Fixed,Change Type,Rule ID,Change Operation,Source Reference
2
+ declare class CommonMethod<T>,ArkTS,7.0.0(26) Beta1,ALL,ArkUI接口新增仅支持Stage模型的约束,entry/src/main/ets/pages/Index.ets:243,Unfixed,API Definition Change,CH2026010615012,API_DEFINITION,26.0.0/beta1-changes-for-all-apps.md:966
3
+ declare const Button: ButtonInterface,ArkTS,7.0.0(26) Beta1,26.0.0(26) - 26.0.0(26),表单类组件触摸热区最小高度变更,entry/src/main/ets/pages/Index.ets:294,Unfixed,UX Visual Layout Change,CH2026031846233,UX_VISUAL,26.0.0/beta1-ux-style-and-effect-changes.md:36
4
+ declare function showToast(options: ShowToastOptions): void,ArkTS,7.0.0(26) Beta1,26.0.0(26) - 26.0.0(26),Dialog、Toast、AlphabetIndexer和文本选择菜单默认开启沉浸式系统材质,entry/src/main/ets/pages/Index.ets:125,Unfixed,UX Visual Layout Change,CH2026032761266,UX_VISUAL,26.0.0/beta1-ux-style-and-effect-changes.md:146
5
+ declare function showToast(options: ShowToastOptions): void,ArkTS,7.0.0(26) Beta1,26.0.0(26) - 26.0.0(26),内置文本的组件文本样式优化,entry/src/main/ets/pages/Index.ets:125,Unfixed,UX Visual Layout Change,CH2026032801249,UX_VISUAL,26.0.0/beta1-ux-style-and-effect-changes.md:87
@@ -0,0 +1,16 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {mkdtemp,writeFile,rm} from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import {referenceDigest} from '../references/references.mjs';
7
+
8
+ test('reference text hashes are stable across BOM and line endings', async t => {
9
+ const root = await mkdtemp(path.join(os.tmpdir(), 'adapter-reference-hash-'));
10
+ t.after(() => rm(root, { recursive: true, force: true }));
11
+ const lf = path.join(root, 'lf.md');
12
+ const crlf = path.join(root, 'crlf.md');
13
+ await writeFile(lf, '标题\n内容\n');
14
+ await writeFile(crlf, '\ufeff标题\r\n内容\r\n');
15
+ assert.equal(await referenceDigest(lf), await referenceDigest(crlf));
16
+ });