@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,87 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { inflateRawSync } from 'node:zlib';
3
+
4
+ const CENTRAL_SIGNATURE = 0x02014b50;
5
+ const END_SIGNATURE = 0x06054b50;
6
+ const LOCAL_SIGNATURE = 0x04034b50;
7
+
8
+ function assertRange(buffer, offset, length, label) {
9
+ if (offset < 0 || length < 0 || offset + length > buffer.length) {
10
+ throw new Error(`Invalid ZIP ${label} range`);
11
+ }
12
+ }
13
+
14
+ function endOfCentralDirectory(buffer) {
15
+ if (buffer.length < 22) throw new Error('ZIP archive is truncated');
16
+ const minimum = Math.max(0, buffer.length - 65_557);
17
+ for (let offset = buffer.length - 22; offset >= minimum; offset -= 1) {
18
+ if (buffer.readUInt32LE(offset) === END_SIGNATURE) return offset;
19
+ }
20
+ throw new Error('ZIP end of central directory not found');
21
+ }
22
+
23
+ function centralEntries(buffer) {
24
+ const end = endOfCentralDirectory(buffer);
25
+ const count = buffer.readUInt16LE(end + 10);
26
+ const size = buffer.readUInt32LE(end + 12);
27
+ const start = buffer.readUInt32LE(end + 16);
28
+ if (count === 0xffff || size === 0xffffffff || start === 0xffffffff) {
29
+ throw new Error('ZIP64 archives are not supported');
30
+ }
31
+ assertRange(buffer, start, size, 'central directory');
32
+ const entries = [];
33
+ let offset = start;
34
+ for (let index = 0; index < count; index += 1) {
35
+ assertRange(buffer, offset, 46, 'central header');
36
+ if (buffer.readUInt32LE(offset) !== CENTRAL_SIGNATURE) throw new Error('Invalid ZIP central header');
37
+ const flags = buffer.readUInt16LE(offset + 8);
38
+ const method = buffer.readUInt16LE(offset + 10);
39
+ const compressedSize = buffer.readUInt32LE(offset + 20);
40
+ const uncompressedSize = buffer.readUInt32LE(offset + 24);
41
+ const nameLength = buffer.readUInt16LE(offset + 28);
42
+ const extraLength = buffer.readUInt16LE(offset + 30);
43
+ const commentLength = buffer.readUInt16LE(offset + 32);
44
+ const localOffset = buffer.readUInt32LE(offset + 42);
45
+ assertRange(buffer, offset + 46, nameLength + extraLength + commentLength, 'central entry');
46
+ const name = buffer.subarray(offset + 46, offset + 46 + nameLength).toString('utf8');
47
+ entries.push({ name, flags, method, compressedSize, uncompressedSize, localOffset });
48
+ offset += 46 + nameLength + extraLength + commentLength;
49
+ }
50
+ return entries;
51
+ }
52
+
53
+ function entryContent(buffer, entry, maxEntrySize) {
54
+ if ((entry.flags & 0x1) !== 0) throw new Error(`Encrypted ZIP entry is not supported: ${entry.name}`);
55
+ if (entry.uncompressedSize > maxEntrySize) throw new Error(`ZIP entry is too large: ${entry.name}`);
56
+ assertRange(buffer, entry.localOffset, 30, 'local header');
57
+ if (buffer.readUInt32LE(entry.localOffset) !== LOCAL_SIGNATURE) throw new Error('Invalid ZIP local header');
58
+ const nameLength = buffer.readUInt16LE(entry.localOffset + 26);
59
+ const extraLength = buffer.readUInt16LE(entry.localOffset + 28);
60
+ const dataOffset = entry.localOffset + 30 + nameLength + extraLength;
61
+ assertRange(buffer, dataOffset, entry.compressedSize, 'entry data');
62
+ const compressed = buffer.subarray(dataOffset, dataOffset + entry.compressedSize);
63
+ const content = entry.method === 0 ? Buffer.from(compressed)
64
+ : entry.method === 8 ? inflateRawSync(compressed)
65
+ : null;
66
+ if (!content) throw new Error(`Unsupported ZIP compression method ${entry.method}: ${entry.name}`);
67
+ if (content.length !== entry.uncompressedSize) throw new Error(`ZIP entry size mismatch: ${entry.name}`);
68
+ return content;
69
+ }
70
+
71
+ export async function listZipEntries(archivePath) {
72
+ return centralEntries(await readFile(archivePath)).map(entry => entry.name);
73
+ }
74
+
75
+ export async function readZipTextEntries(archivePath, predicate = () => true, {
76
+ maxEntrySize = 16 * 1024 * 1024,
77
+ maxTotalSize = 64 * 1024 * 1024,
78
+ } = {}) {
79
+ const buffer = await readFile(archivePath);
80
+ const selected = centralEntries(buffer).filter(entry => predicate(entry.name));
81
+ const total = selected.reduce((sum, entry) => sum + entry.uncompressedSize, 0);
82
+ if (total > maxTotalSize) throw new Error('Selected ZIP entries exceed the allowed total size');
83
+ return selected.map(entry => ({
84
+ name: entry.name,
85
+ text: entryContent(buffer, entry, maxEntrySize).toString('utf8'),
86
+ }));
87
+ }
@@ -0,0 +1,60 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { access, mkdir, readdir, readFile, stat } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { atomicWriteFile } from '../platform/fs.mjs';
5
+
6
+ export function sha256(value) {
7
+ return createHash('sha256').update(value).digest('hex');
8
+ }
9
+
10
+ export async function sha256File(file) {
11
+ return sha256(await readFile(file));
12
+ }
13
+
14
+ export async function exists(target) {
15
+ try {
16
+ await stat(target);
17
+ return true;
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+
23
+ export function portableRelative(root, target) {
24
+ return path.relative(root, target).split(path.sep).join('/');
25
+ }
26
+
27
+ export function resolveInside(root,file) {
28
+ const base=path.resolve(root),target=path.resolve(base,file),relative=path.relative(base,target);
29
+ if(relative==='..'||relative.startsWith(`..${path.sep}`)||path.isAbsolute(relative))throw new Error(`Path escapes project root: ${file}`);
30
+ return target;
31
+ }
32
+
33
+ export async function listFiles(root, predicate = () => true, visitDirectory = () => true, { allowMissing = false } = {}) {
34
+ if (allowMissing && !await pathExists(root)) return [];
35
+ const results = [];
36
+ async function visit(directory) {
37
+ const entries = await readdir(directory, { withFileTypes: true });
38
+ entries.sort((left, right) => left.name.localeCompare(right.name));
39
+ for (const entry of entries) {
40
+ const target = path.join(directory, entry.name);
41
+ if (entry.isDirectory() && visitDirectory(target)) await visit(target);
42
+ else if (entry.isFile() && predicate(target)) results.push(target);
43
+ }
44
+ }
45
+ await visit(root);
46
+ return results;
47
+ }
48
+
49
+ export async function ensureDir(directory) {
50
+ await mkdir(directory, { recursive: true });
51
+ }
52
+
53
+ export async function atomicWrite(target, content) {
54
+ await atomicWriteFile(target, content, { ensureDirectory: ensureDir });
55
+ }
56
+
57
+ export async function pathExists(file) {
58
+ try { await access(file); return true; }
59
+ catch (error) { if (['ENOENT', 'ENOTDIR'].includes(error.code)) return false; throw error; }
60
+ }
@@ -0,0 +1,74 @@
1
+ import { randomBytes, createHash } from 'node:crypto';
2
+ import { mkdir, realpath, stat, writeFile } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { errorWithCode } from './errors.mjs';
5
+ import { relativePathInside } from './paths.mjs';
6
+
7
+ const digest = bytes => createHash('sha256').update(bytes).digest('hex');
8
+
9
+ export function batchArtifactPaths(directory, batchId, mode = 'upgrade') {
10
+ if (!/^[a-f0-9]{12}$/.test(batchId)) throw errorWithCode('扫描批次 ID 必须为 12 位小写十六进制', 'SCAN_BATCH_INVALID');
11
+ if (!['upgrade', 'deprecated'].includes(mode)) throw errorWithCode('扫描批次模式无效', 'SCAN_BATCH_INVALID');
12
+ const api = /^[a-z]:[\\/]|^\\\\/i.test(directory) ? path.win32 : path;
13
+ const scanDirectory = api.resolve(directory);
14
+ const internalDirectory = api.join(scanDirectory, '.internal');
15
+ const scannerDirectory = api.join(internalDirectory, 'scanner');
16
+ const deliveryDirectory = api.join(scanDirectory, mode);
17
+ const scanStamp = api.basename(scanDirectory);
18
+ if (mode === 'deprecated' && !/^\d{14}(?:-[2-9]\d*|-1\d+)?$/.test(scanStamp))
19
+ throw errorWithCode('废弃 API 批次目录必须使用扫描时间戳', 'SCAN_BATCH_INVALID');
20
+ const stem = mode === 'deprecated' ? `apiChange_${scanStamp}` : `scan-results-${batchId}`;
21
+ return {
22
+ schemaVersion: 4, batchId, mode, scanDirectory, internalDirectory, scannerDirectory, deliveryDirectory,
23
+ ...(mode === 'deprecated' ? { scanStamp } : {}),
24
+ batchMetadataPath: api.join(internalDirectory, 'scan-batch.json'),
25
+ rawCsv: api.join(deliveryDirectory, `${stem}.csv`),
26
+ adaptedCsv: api.join(deliveryDirectory, `adapted-results-${batchId}.csv`),
27
+ scanJson: api.join(scannerDirectory, `${stem}.scan.json`),
28
+ validationCsv: mode === 'deprecated' ? api.join(scannerDirectory, `${stem}.validation.csv`) : null,
29
+ coverageJson: api.join(scannerDirectory, 'coverage.json'),
30
+ diagnosticsJson: api.join(scannerDirectory, 'diagnostics.json'),
31
+ };
32
+ }
33
+
34
+ export async function assertBatchDirectory(layout, directory) {
35
+ if (relativePathInside(layout.scanDirectory, directory) === null
36
+ || relativePathInside(await realpath(layout.scanDirectory), await realpath(directory)) === null
37
+ || !(await stat(directory)).isDirectory())
38
+ throw errorWithCode('内部目录越过扫描批次边界或不是目录', 'SCAN_BATCH_INVALID', { path: directory });
39
+ }
40
+
41
+ // Check each existing parent before creating children, including Windows junctions.
42
+ export async function ensureBatchDirectory(layout, directory) {
43
+ const relative = relativePathInside(layout.scanDirectory, directory);
44
+ if (relative === null) throw errorWithCode('内部目录越过扫描批次边界', 'SCAN_BATCH_INVALID', { path: directory });
45
+ let current = layout.scanDirectory;
46
+ await assertBatchDirectory(layout, current);
47
+ for (const part of relative.split(/[\\/]/).filter(Boolean)) {
48
+ current = path.join(current, part);
49
+ try { await mkdir(current); }
50
+ catch (error) { if (error.code !== 'EEXIST') throw error; }
51
+ await assertBatchDirectory(layout, current);
52
+ }
53
+ }
54
+
55
+ export async function createScanBatch(outputRoot, directory, { idFactory = () => randomBytes(6).toString('hex'), mode = 'upgrade' } = {}) {
56
+ if (!['upgrade', 'deprecated'].includes(mode)) throw errorWithCode('扫描批次模式无效', 'SCAN_BATCH_INVALID');
57
+ const registry = path.join(outputRoot, '.batch-ids');
58
+ await mkdir(registry, { recursive: true });
59
+ if (relativePathInside(await realpath(outputRoot), await realpath(registry)) === null
60
+ || relativePathInside(await realpath(outputRoot), await realpath(directory)) === null)
61
+ throw errorWithCode('扫描批次目录越过输出边界', 'SCAN_BATCH_INVALID');
62
+ for (let attempt = 0; attempt < 32; attempt++) {
63
+ const paths = batchArtifactPaths(directory, idFactory(), mode);
64
+ await ensureBatchDirectory(paths, paths.internalDirectory);
65
+ await ensureBatchDirectory(paths, paths.deliveryDirectory);
66
+ const content = JSON.stringify({ schemaVersion: 4, batchId: paths.batchId, mode,
67
+ ...(mode === 'deprecated' ? { scanStamp: paths.scanStamp } : {}), createdAt: new Date().toISOString() }, null, 2) + '\n';
68
+ try { await writeFile(path.join(registry, paths.batchId), content, { flag: 'wx' }); }
69
+ catch (error) { if (error.code === 'EEXIST') continue; throw error; }
70
+ await writeFile(paths.batchMetadataPath, content, { flag: 'wx' });
71
+ return { ...paths, createdAt: JSON.parse(content).createdAt, batchMetadataSha256: digest(content) };
72
+ }
73
+ throw errorWithCode('扫描批次 ID 连续冲突,请重试', 'SCAN_BATCH_COLLISION');
74
+ }
@@ -0,0 +1,29 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ // The index lists only current document paths and official overview entries.
5
+ // Custom reference corpora without a sidecar retain their existing behavior.
6
+ export async function loadChangelogIndex(referenceRoot) {
7
+ const file = path.join(path.dirname(referenceRoot), `${path.basename(referenceRoot)}-index.json`);
8
+ let text;
9
+ try { text = await readFile(file, 'utf8'); }
10
+ catch (error) {
11
+ if (error.code === 'ENOENT') return { documents: [], overview: [] };
12
+ throw error;
13
+ }
14
+ const index = JSON.parse(text);
15
+ if (index.schemaVersion !== 1 || !Array.isArray(index.documents) || !Array.isArray(index.overview))
16
+ throw new Error(`Invalid changelog index: ${file}`);
17
+ const paths = new Map();
18
+ for (const document of index.documents) {
19
+ const value = document?.path;
20
+ if (typeof value !== 'string' || !value || path.posix.isAbsolute(value) || path.win32.isAbsolute(value)
21
+ || value.split(/[\\/]/).some(part => !part || part === '.' || part === '..'))
22
+ throw new Error(`Invalid changelog document path: ${value}`);
23
+ const key = value.replaceAll('\\', '/').toLowerCase();
24
+ if (paths.has(key)) throw new Error('Duplicate changelog document path');
25
+ paths.set(key, document);
26
+ document.path = value.replaceAll('\\', '/');
27
+ }
28
+ return index;
29
+ }
@@ -0,0 +1,40 @@
1
+ import { canonicalHarmonyVersion, parseHarmonyVersion } from './version.mjs';
2
+ import { errorWithCode } from './errors.mjs';
3
+
4
+ export function inspectDevEcoCompatibility(productInfo, targetVersion, contentsRoot = null) {
5
+ const target = typeof targetVersion === 'object' ? targetVersion : parseHarmonyVersion(targetVersion);
6
+ const installedVersion = typeof productInfo?.version === 'string' ? productInfo.version : null;
7
+ const match = installedVersion?.trim().match(/^(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?$/);
8
+ const numbers = match ? match.slice(1).filter(value => value !== undefined).map(Number) : null;
9
+ const result = {
10
+ status: 'UNRESOLVED',
11
+ installedVersion,
12
+ requiredVersion: target.platformVersion,
13
+ targetVersion: canonicalHarmonyVersion(target),
14
+ contentsRoot,
15
+ metadataPath: productInfo?.file ?? null,
16
+ };
17
+ if (!numbers?.every(Number.isSafeInteger)) return result;
18
+ const required = target.platformVersion.split('.').map(Number);
19
+ const different = required.findIndex((value, index) => numbers[index] !== value);
20
+ result.status = different !== -1 && numbers[different] < required[different] ? 'TOO_OLD' : 'COMPATIBLE';
21
+ return result;
22
+ }
23
+
24
+ export function assertDevEcoCompatibility(compatibility) {
25
+ if (compatibility.status === 'COMPATIBLE') return;
26
+ const error = compatibility.status === 'TOO_OLD'
27
+ ? errorWithCode(
28
+ `本地 DevEco Studio 版本 ${compatibility.installedVersion} 低于目标 ${compatibility.targetVersion} `
29
+ + `所需的最低版本 ${compatibility.requiredVersion},该目标不在当前环境扫描范围内。`
30
+ + '请降低预期目标版本或升级本地 DevEco Studio。',
31
+ 'DEVECO_TARGET_NOT_COVERED', compatibility,
32
+ )
33
+ : errorWithCode(
34
+ '无法准确识别本地 DevEco Studio 版本,已停止扫描。'
35
+ + '请修复本地环境或通过 --deveco-home 指定具有有效 product-info.json 的 DevEco Studio 安装后重试。',
36
+ 'DEVECO_VERSION_UNRESOLVED', compatibility,
37
+ );
38
+ error.stage = 'VALIDATE_DEVECO_VERSION';
39
+ throw error;
40
+ }
@@ -0,0 +1,30 @@
1
+ export function normalizeDocumentUrl(value, { fragment = true } = {}) {
2
+ try {
3
+ const url = new URL(value);
4
+ if (!['http:', 'https:'].includes(url.protocol)) return null;
5
+ if (url.hostname === 'developer.huawei.com') url.pathname = url.pathname
6
+ .replace(/\/doc\/(?:harmonyos-releases|doccenter-release-notes)\//, '/doc/doccenter-release-notes/');
7
+ url.pathname = url.pathname.replace(/\/$/, '');
8
+ if (!fragment) url.hash = '';
9
+ return url.href;
10
+ } catch { return null; }
11
+ }
12
+
13
+ export function entryUrl(value) {
14
+ const normalized = normalizeDocumentUrl(value);
15
+ if (!normalized) return null;
16
+ const hash = new URL(normalized).hash;
17
+ return hash.length > 1 && !/^#scan-/i.test(hash) ? normalized : null;
18
+ }
19
+
20
+ // A syntactically valid backend URL is not evidence of a public change identity.
21
+ export function ruleDocumentLink(rule, providedUrl, { requireEntry = true } = {}) {
22
+ const expected = requireEntry ? entryUrl(rule.url) : normalizeDocumentUrl(rule.url);
23
+ const supplied = normalizeDocumentUrl(providedUrl);
24
+ const rejectedReason = !supplied ? null : /^#scan-/i.test(new URL(supplied).hash)
25
+ ? 'SYNTHETIC_SCAN_ANCHOR' : supplied !== expected ? 'RULE_LINK_MISMATCH' : null;
26
+ return { url: expected ?? '', source: expected ? supplied === expected ? 'VERIFIED_DEVECO_REPORT'
27
+ : rule.documentLink?.source ?? 'VERIFIED_RULE' : null,
28
+ ...(rejectedReason ? { originalUrl: providedUrl, rejectedReason } : {}),
29
+ ...(!expected ? { reason: rule.documentLink?.reason ?? 'DOCUMENT_ENTRY_NOT_VERIFIED' } : {}) };
30
+ }
@@ -0,0 +1,41 @@
1
+ function stackLines(error, limit) {
2
+ if (typeof error?.stack !== 'string' || !error.stack) return undefined;
3
+ return error.stack.split(/\r?\n/).slice(0, limit).join('\n');
4
+ }
5
+
6
+ export function serializeError(error, {
7
+ command = undefined,
8
+ stage = undefined,
9
+ maxStackLines = 50,
10
+ maxCauseDepth = 4,
11
+ depth = 0,
12
+ } = {}) {
13
+ const source = error && typeof error === 'object' ? error : new Error(String(error));
14
+ const result = {
15
+ name: source.name ?? 'Error',
16
+ code: source.code ?? undefined,
17
+ message: source.message ?? String(source),
18
+ command: command ?? source.command ?? undefined,
19
+ stage: source.stage ?? stage ?? undefined,
20
+ stack: stackLines(source, maxStackLines),
21
+ details: source.details ?? undefined,
22
+ validationErrors: source.validationErrors ?? undefined,
23
+ artifactPaths: source.artifactPaths ?? undefined,
24
+ cleanupWarning: source.cleanupWarning ?? undefined,
25
+ };
26
+ if (source.cause !== undefined && depth < maxCauseDepth) {
27
+ result.cause = serializeError(source.cause, {
28
+ maxStackLines,
29
+ maxCauseDepth,
30
+ depth: depth + 1,
31
+ });
32
+ }
33
+ return result;
34
+ }
35
+
36
+ export function errorWithCode(message, code, details = undefined) {
37
+ const error = new Error(message);
38
+ error.code = code;
39
+ if (details !== undefined) error.details = details;
40
+ return error;
41
+ }
@@ -0,0 +1,72 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { chmod, rename, rm, stat, writeFile } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+
5
+ const RETRYABLE_CODES = new Set(['EACCES', 'EBUSY', 'EPERM']);
6
+
7
+ function wait(durationMs) {
8
+ return new Promise((resolve) => setTimeout(resolve, durationMs));
9
+ }
10
+
11
+ export async function retryFileOperation(operation, { maxRetries = 4, retryDelayMs = 25 } = {}) {
12
+ let lastError;
13
+ for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
14
+ try {
15
+ return await operation();
16
+ } catch (error) {
17
+ lastError = error;
18
+ if (!RETRYABLE_CODES.has(error.code) || attempt === maxRetries) throw error;
19
+ await wait(retryDelayMs * (attempt + 1));
20
+ }
21
+ }
22
+ throw lastError;
23
+ }
24
+
25
+ async function existingMode(target) {
26
+ try { return (await stat(target)).mode; } catch { return null; }
27
+ }
28
+
29
+ export async function replaceStagedPath(staged, target, { platform = process.platform } = {}) {
30
+ let replacementError = null;
31
+ try {
32
+ await retryFileOperation(() => rename(staged, target));
33
+ return;
34
+ } catch (error) {
35
+ const directoryReplacement = error.code === 'EEXIST' || error.code === 'ENOTEMPTY';
36
+ const windowsReplacement = platform === 'win32' && RETRYABLE_CODES.has(error.code);
37
+ if (!directoryReplacement && !windowsReplacement) throw error;
38
+ replacementError = error;
39
+ }
40
+ try { await stat(target); } catch { throw replacementError; }
41
+ const backup = path.join(path.dirname(target), `.${path.basename(target)}.${randomUUID()}.bak`);
42
+ let movedOriginal = false;
43
+ try {
44
+ await retryFileOperation(() => rename(target, backup));
45
+ movedOriginal = true;
46
+ await retryFileOperation(() => rename(staged, target));
47
+ await rm(backup, { recursive: true, force: true, maxRetries: 4, retryDelay: 25 });
48
+ } catch (error) {
49
+ if (movedOriginal) {
50
+ await rm(target, { recursive: true, force: true, maxRetries: 4, retryDelay: 25 });
51
+ try { await retryFileOperation(() => rename(backup, target)); } catch { /* Preserve the original error. */ }
52
+ }
53
+ throw error;
54
+ }
55
+ }
56
+
57
+ export async function atomicWriteFile(target, content, {
58
+ ensureDirectory,
59
+ platform = process.platform,
60
+ } = {}) {
61
+ if (ensureDirectory) await ensureDirectory(path.dirname(target));
62
+ const temporary = path.join(path.dirname(target), `.${path.basename(target)}.${randomUUID()}.tmp`);
63
+ const mode = await existingMode(target);
64
+ try {
65
+ await writeFile(temporary, content);
66
+ if (mode !== null) await chmod(temporary, mode);
67
+ await replaceStagedPath(temporary, target, { platform });
68
+ } catch (error) {
69
+ await rm(temporary, { recursive: true, force: true, maxRetries: 4, retryDelay: 25 });
70
+ throw error;
71
+ }
72
+ }
@@ -0,0 +1,34 @@
1
+ import path from 'node:path';
2
+
3
+ function pathApi(platform) {
4
+ return platform === 'win32' ? path.win32 : path.posix;
5
+ }
6
+
7
+ export function normalizeComparablePath(value, platform = process.platform) {
8
+ const api = pathApi(platform);
9
+ const normalized = api.normalize(api.resolve(String(value)));
10
+ return platform === 'win32' ? normalized.toLowerCase() : normalized;
11
+ }
12
+
13
+ export function samePath(left, right, platform = process.platform) {
14
+ return normalizeComparablePath(left, platform) === normalizeComparablePath(right, platform);
15
+ }
16
+
17
+ export function portablePath(value) {
18
+ return String(value).replaceAll('\\', '/');
19
+ }
20
+
21
+ export function relativePathInside(root, file, platform = process.platform) {
22
+ const api = pathApi(platform);
23
+ const relative = api.relative(api.resolve(root), api.resolve(file));
24
+ if (relative === '..' || relative.startsWith(`..${api.sep}`) || api.isAbsolute(relative)) return null;
25
+ return portablePath(relative);
26
+ }
27
+
28
+ export function comparableCodeLocation(value, root = null, platform = process.platform) {
29
+ const match = String(value).match(/^(.*?)(:\d+(?::\d+)?)?$/);
30
+ let file = match[1];
31
+ if (root && pathApi(platform).isAbsolute(file)) file = relativePathInside(root, file, platform) ?? file;
32
+ file = portablePath(file);
33
+ return (platform === 'win32' ? file.toLowerCase() : file) + (match[2] ?? '');
34
+ }
@@ -0,0 +1,154 @@
1
+ import { spawn } from 'node:child_process';
2
+ import path from 'node:path';
3
+
4
+ const WINDOWS_SHELL_EXTENSIONS = new Set(['.cmd', '.bat']);
5
+ const WINDOWS_META_CHARACTERS = /([()%!^"<>&|;, *?])/g;
6
+
7
+ export function prependPath(env, directories, platform = process.platform) {
8
+ const result = { ...env };
9
+ const keys = Object.keys(env).filter(key => platform === 'win32' ? key.toLowerCase() === 'path' : key === 'PATH');
10
+ const key = keys[0] ?? 'PATH';
11
+ const previous = env.PATH ?? env[key] ?? '';
12
+ for (const name of keys) delete result[name];
13
+ result[key] = [...directories.filter(Boolean), previous].filter(Boolean).join(platform === 'win32' ? ';' : ':');
14
+ return result;
15
+ }
16
+
17
+ function assertCommandValue(value) {
18
+ const text = String(value);
19
+ if (/[\0\r\n]/.test(text)) throw new Error('Command arguments cannot contain NUL or newlines');
20
+ return text;
21
+ }
22
+
23
+ function escapeWindowsCommand(value) {
24
+ return assertCommandValue(value).replace(WINDOWS_META_CHARACTERS, '^$1');
25
+ }
26
+
27
+ function escapeWindowsArgument(value) {
28
+ let escaped = assertCommandValue(value);
29
+ escaped = escaped.replace(/(\\*)"/g, '$1$1\\"');
30
+ escaped = escaped.replace(/(\\*)$/, '$1$1');
31
+ escaped = `"${escaped}"`;
32
+ return escaped.replace(WINDOWS_META_CHARACTERS, '^$1');
33
+ }
34
+
35
+ export function commandInvocation(command, args = [], platform = process.platform, env = process.env) {
36
+ const extension = path.extname(command).toLowerCase();
37
+ if (platform === 'win32' && WINDOWS_SHELL_EXTENSIONS.has(extension)) {
38
+ const executable = env.ComSpec || env.COMSPEC || 'cmd.exe';
39
+ const commandLine = [escapeWindowsCommand(command), ...args.map(escapeWindowsArgument)].join(' ');
40
+ return {
41
+ command: executable,
42
+ args: ['/d', '/s', '/v:off', '/c', `"${commandLine}"`],
43
+ windowsVerbatimArguments: true,
44
+ };
45
+ }
46
+ return { command, args, windowsVerbatimArguments: false };
47
+ }
48
+
49
+ function waitForClose(child, timeoutMs) {
50
+ return new Promise((resolve) => {
51
+ if (child.exitCode !== null || child.signalCode !== null) {
52
+ resolve(true);
53
+ return;
54
+ }
55
+ const timer = setTimeout(() => resolve(false), timeoutMs);
56
+ child.once('close', () => {
57
+ clearTimeout(timer);
58
+ resolve(true);
59
+ });
60
+ });
61
+ }
62
+
63
+ async function taskkill(pid, env) {
64
+ await new Promise((resolve) => {
65
+ const executable = env.SystemRoot
66
+ ? path.win32.join(env.SystemRoot, 'System32', 'taskkill.exe')
67
+ : 'taskkill.exe';
68
+ const child = spawn(executable, ['/pid', String(pid), '/t', '/f'], {
69
+ env,
70
+ shell: false,
71
+ windowsHide: true,
72
+ stdio: 'ignore',
73
+ });
74
+ child.once('error', () => resolve());
75
+ child.once('close', () => resolve());
76
+ });
77
+ }
78
+
79
+ export async function terminateProcessTree(child, {
80
+ platform = process.platform,
81
+ env = process.env,
82
+ detached = false,
83
+ graceMs = 3000,
84
+ } = {}) {
85
+ if (!child?.pid || child.exitCode !== null || child.signalCode !== null) return;
86
+ if (platform === 'win32') {
87
+ await taskkill(child.pid, env);
88
+ if (child.exitCode === null && child.signalCode === null) child.kill('SIGTERM');
89
+ return;
90
+ }
91
+ const signal = (name) => {
92
+ try {
93
+ if (detached) process.kill(-child.pid, name);
94
+ else child.kill(name);
95
+ } catch {
96
+ try { child.kill(name); } catch { /* The process already exited. */ }
97
+ }
98
+ };
99
+ signal('SIGTERM');
100
+ if (!(await waitForClose(child, graceMs))) signal('SIGKILL');
101
+ }
102
+
103
+ export function runProcess(command, args = [], options = {}) {
104
+ const platform = options.platform ?? process.platform;
105
+ const env = options.env ?? process.env;
106
+ const invocation = commandInvocation(command, args, platform, env);
107
+ return new Promise((resolve) => {
108
+ let settled = false;
109
+ let stdout = '';
110
+ let stderr = '';
111
+ let timedOut = false;
112
+ let outputError = null;
113
+ const child = spawn(invocation.command, invocation.args, {
114
+ cwd: options.cwd,
115
+ env,
116
+ shell: false,
117
+ windowsHide: true,
118
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments,
119
+ detached: options.detached === true,
120
+ stdio: ['ignore', 'pipe', 'pipe'],
121
+ });
122
+ const finish = (result) => {
123
+ if (settled) return;
124
+ settled = true;
125
+ if (timer) clearTimeout(timer);
126
+ resolve({ stdout, stderr, timedOut, ...result });
127
+ };
128
+ const timer = options.timeoutMs
129
+ ? setTimeout(() => {
130
+ timedOut = true;
131
+ void terminateProcessTree(child, {
132
+ platform,
133
+ env,
134
+ detached: options.detached === true,
135
+ graceMs: options.terminationGraceMs,
136
+ });
137
+ }, options.timeoutMs)
138
+ : null;
139
+ child.stdout?.setEncoding('utf8');
140
+ child.stderr?.setEncoding('utf8');
141
+ const output = (chunk, stream) => {
142
+ if (stream === 'stdout') { if (options.captureStdout !== false) stdout += chunk; } else stderr += chunk;
143
+ if (!outputError) try { options.onOutput?.(chunk, stream); }
144
+ catch (error) {
145
+ outputError = error.message;
146
+ void terminateProcessTree(child, { platform, env, detached: options.detached === true, graceMs: options.terminationGraceMs });
147
+ }
148
+ };
149
+ child.stdout?.on('data', (chunk) => output(chunk, 'stdout'));
150
+ child.stderr?.on('data', (chunk) => output(chunk, 'stderr'));
151
+ child.once('error', (error) => finish({ exitCode: null, signal: null, error: error.message }));
152
+ child.once('close', (exitCode, signal) => finish({ exitCode, signal, error: outputError }));
153
+ });
154
+ }
@@ -0,0 +1,7 @@
1
+ import { errorWithCode } from './errors.mjs';
2
+
3
+ export function requireScanMode(mode) {
4
+ if (!['upgrade', 'deprecated'].includes(mode))
5
+ throw errorWithCode('--mode must be explicitly set to upgrade or deprecated', 'SCAN_MODE_INVALID');
6
+ return mode;
7
+ }
@@ -0,0 +1,7 @@
1
+ // Rule identities, CSV records and physical locations are separate units.
2
+ export function findingStatistics(rows) {
3
+ const identities = rows.map(row => row['Rule ID'] || (row['Source Reference']
4
+ ? `${row['Source Reference']}\0${row['Changed in SDK']}` : null));
5
+ return { ruleCount: identities.every(Boolean) ? new Set(identities).size : null,
6
+ rowCount: rows.length, codeLocationCount: new Set(rows.map(row => row['Code Location'])).size };
7
+ }