android2harmony 0.1.6 → 0.1.8

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 (227) hide show
  1. package/agents/api-analyzer.md +113 -0
  2. package/agents/app-action.md +122 -0
  3. package/agents/code-reviewer.md +191 -295
  4. package/agents/coder.md +377 -0
  5. package/agents/self-tester.md +8 -8
  6. package/agents/spec-designer.md +56 -0
  7. package/package.json +1 -1
  8. package/skills/a2h-app-req-gen/SKILL.md +174 -0
  9. package/skills/a2h-app-req-gen/references/spec-handoff.md +99 -0
  10. package/skills/a2h-app-req-gen/references/subagent-render.md +115 -0
  11. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/build.gradle.kts +41 -0
  12. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradle/wrapper/gradle-wrapper.jar +0 -0
  13. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradle/wrapper/gradle-wrapper.properties +8 -0
  14. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradle.properties +3 -0
  15. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradlew +251 -0
  16. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradlew.bat +94 -0
  17. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/settings.gradle.kts +17 -0
  18. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawAnalysisDetector.java +1911 -0
  19. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawIssueRegistry.java +37 -0
  20. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawJson.java +146 -0
  21. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawLocation.java +96 -0
  22. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawRecordWriter.java +227 -0
  23. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/resources/META-INF/services/com.android.tools.lint.client.api.IssueRegistry +1 -0
  24. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/resources/dev/reqgen/analyzer/jvm/raw-record-v1.schema.json +93 -0
  25. package/skills/a2h-app-req-gen/scripts/reqgen/assets/dashboard.html +151 -0
  26. package/skills/a2h-app-req-gen/scripts/reqgen/gradle/reqgen-lint.init.gradle +60 -0
  27. package/skills/a2h-app-req-gen/scripts/reqgen/gradle/reqgen-model.init.gradle +204 -0
  28. package/skills/a2h-app-req-gen/scripts/reqgen/package.json +14 -0
  29. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/backend.js +323 -0
  30. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/cli.js +811 -0
  31. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/gap-audit-link.js +62 -0
  32. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/index.js +66 -0
  33. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/merge.js +605 -0
  34. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/name-trace.js +153 -0
  35. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/orchestrate.js +1324 -0
  36. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/output-parse.js +50 -0
  37. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/overview.js +10 -0
  38. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/pool.js +23 -0
  39. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/post-merge-fix.js +146 -0
  40. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/prompt-loader.js +51 -0
  41. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/prompt.js +967 -0
  42. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/prompts.md +301 -0
  43. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/serve.js +78 -0
  44. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/short-id.js +46 -0
  45. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/snapshot.js +267 -0
  46. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/types.js +1 -0
  47. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/validate.js +122 -0
  48. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/callback-call-sites.js +62 -0
  49. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/gap-audit/build.js +1291 -0
  50. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/gap-audit/index.js +1 -0
  51. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/area-ownership.js +392 -0
  52. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/build.js +1995 -0
  53. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/callback-flow.js +277 -0
  54. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/component-variants.js +725 -0
  55. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/index.js +15 -0
  56. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/names/index.js +12 -0
  57. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/names/policy.js +469 -0
  58. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/names/traceability.js +468 -0
  59. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/req-model/build.js +1066 -0
  60. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/req-model/index.js +1 -0
  61. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/android-interaction-registry.js +174 -0
  62. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/android.js +1062 -0
  63. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/area-titles.js +678 -0
  64. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/builder.js +350 -0
  65. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/compose-api-registry.js +395 -0
  66. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/compose-call-sites.js +2008 -0
  67. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/compose.js +9059 -0
  68. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/dynamic-repeated-call-sites.js +529 -0
  69. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/index.js +1 -0
  70. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/interaction-effects.js +1149 -0
  71. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/jvm.js +6272 -0
  72. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/normalize.js +33 -0
  73. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/pending-intents.js +565 -0
  74. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/resource-id.js +42 -0
  75. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/route-state-variants.js +781 -0
  76. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/state.js +234 -0
  77. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/types.js +1 -0
  78. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/extract.js +40 -0
  79. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/index.js +6 -0
  80. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/manifest.js +513 -0
  81. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/resources.js +398 -0
  82. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/types.js +1 -0
  83. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/views.js +447 -0
  84. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/xml-parser.js +175 -0
  85. package/skills/a2h-app-req-gen/scripts/reqgen/src/cli.js +398 -0
  86. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/area-graph.js +1 -0
  87. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/artifact.js +1 -0
  88. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/common.js +16 -0
  89. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/diagnostic.js +10 -0
  90. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/gap-audit.js +14 -0
  91. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/index.js +11 -0
  92. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/name-traceability.js +26 -0
  93. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/raw-fact.js +40 -0
  94. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/req-model.js +1 -0
  95. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/run.js +19 -0
  96. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/semantic-completeness.js +11 -0
  97. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/source-facts.js +1 -0
  98. package/skills/a2h-app-req-gen/scripts/reqgen/src/core/output-guard.js +41 -0
  99. package/skills/a2h-app-req-gen/scripts/reqgen/src/core/stable-id.js +92 -0
  100. package/skills/a2h-app-req-gen/scripts/reqgen/src/dashboard-cli.js +169 -0
  101. package/skills/a2h-app-req-gen/scripts/reqgen/src/diagnostics.js +104 -0
  102. package/skills/a2h-app-req-gen/scripts/reqgen/src/dump/dump.js +1028 -0
  103. package/skills/a2h-app-req-gen/scripts/reqgen/src/dump/index.js +1 -0
  104. package/skills/a2h-app-req-gen/scripts/reqgen/src/dump-cli.js +251 -0
  105. package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/artifacts.js +49 -0
  106. package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/index.js +18 -0
  107. package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/quality-report.js +125 -0
  108. package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/render.js +353 -0
  109. package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/types.js +2 -0
  110. package/skills/a2h-app-req-gen/scripts/reqgen/src/graph/paths.js +474 -0
  111. package/skills/a2h-app-req-gen/scripts/reqgen/src/jvm/index.js +15 -0
  112. package/skills/a2h-app-req-gen/scripts/reqgen/src/jvm/protocol.js +408 -0
  113. package/skills/a2h-app-req-gen/scripts/reqgen/src/jvm/runner.js +452 -0
  114. package/skills/a2h-app-req-gen/scripts/reqgen/src/pipeline/index.js +8 -0
  115. package/skills/a2h-app-req-gen/scripts/reqgen/src/pipeline/output.js +165 -0
  116. package/skills/a2h-app-req-gen/scripts/reqgen/src/pipeline/run-stage1.js +891 -0
  117. package/skills/a2h-app-req-gen/scripts/reqgen/src/project/discovery.js +299 -0
  118. package/skills/a2h-app-req-gen/scripts/reqgen/src/project/gradle-model.js +358 -0
  119. package/skills/a2h-app-req-gen/scripts/reqgen/src/project/gradle-runner.js +165 -0
  120. package/skills/a2h-app-req-gen/scripts/reqgen/src/project/resource-profile.js +60 -0
  121. package/skills/a2h-app-req-gen/scripts/reqgen/src/project/types.js +1 -0
  122. package/skills/a2h-app-req-gen/scripts/reqgen/src/spec-handoff-cli.js +151 -0
  123. package/skills/a2h-app-req-gen/scripts/reqgen/src/spec-handoff.js +1004 -0
  124. package/skills/a2h-app-req-gen/scripts/reqgen/src/stage2-cli.js +109 -0
  125. package/skills/a2h-app-req-gen/scripts/reqgen/src/stage2-input.js +419 -0
  126. package/skills/a2h-app-req-gen/scripts/reqgen/src/stage2-name-trace-input.js +95 -0
  127. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/area-graph.js +444 -0
  128. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/index.js +7 -0
  129. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/req-model.js +580 -0
  130. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/req-text.js +195 -0
  131. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/semantic-area-graph.js +1431 -0
  132. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/types.js +1 -0
  133. package/skills/a2h-app-req-gen/scripts/reqgen-audit.mjs +298 -0
  134. package/skills/a2h-app-req-gen/scripts/reqgen-selfcheck.mjs +555 -0
  135. package/skills/a2h-code-review/SKILL.md +379 -0
  136. package/skills/{hmos-integration-test → a2h-integration-test}/README.md +6 -6
  137. package/skills/{hmos-integration-test → a2h-integration-test}/SKILL.md +6 -6
  138. package/skills/{hmos-integration-test → a2h-integration-test}/scripts/report-tool.mjs +1 -1
  139. package/skills/a2h-spec-design/SKILL.md +330 -0
  140. package/skills/a2h-spec-design/scripts/inspect_spec_design_inputs.mjs +207 -0
  141. package/skills/a2h-spec-design/scripts/move_spec_technical_reference.mjs +198 -0
  142. package/skills/a2h-spec-design/scripts/validate_spec_design_output.mjs +256 -0
  143. package/skills/a2h-spec-generate/SKILL.md +696 -0
  144. package/skills/a2h-spec-generate/references/trace-template.md +115 -0
  145. package/skills/a2h-spec-generate/scripts/parse_requirements.mjs +537 -0
  146. package/skills/a2h-spec-generate/template/REQ.txt +22 -0
  147. package/skills/a2h-spec-generate/template/REQ.xlsx +0 -0
  148. package/skills/a2h-spec-implement/SKILL.md +548 -0
  149. package/skills/a2h-spec-implement/references/harmony-pitfalls.md +186 -0
  150. package/skills/a2h-spec-implement/references/l1-unit-test.md +185 -0
  151. package/skills/a2h-spec-implement/references/l3-e2e-uitest.md +167 -0
  152. package/skills/a2h-spec-implement/references/test-core.md +132 -0
  153. package/skills/a2h-spec-implement/rules/arkts/arkts-standards.md +184 -0
  154. package/skills/a2h-spec-implement/rules/arkts/conventions/coding-style.md +96 -0
  155. package/skills/a2h-spec-implement/rules/arkts/conventions/security.md +126 -0
  156. package/skills/a2h-spec-implement/rules/arkts/language/arkts-rules.md +650 -0
  157. package/skills/a2h-spec-implement/rules/arkts/language/arkui-structure-rules.md +173 -0
  158. package/skills/a2h-spec-implement/rules/arkts/language/ts-to-arkts-rewrites.md +58 -0
  159. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md +648 -0
  160. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md +2089 -0
  161. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md +1033 -0
  162. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md +1183 -0
  163. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md +576 -0
  164. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md +297 -0
  165. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md +395 -0
  166. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md +903 -0
  167. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md +106 -0
  168. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md +1178 -0
  169. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md +911 -0
  170. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +355 -0
  171. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md +11 -0
  172. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/!!/350/257/255/346/263/225/357/274/232/345/217/214/345/220/221/347/273/221/345/256/232.md +216 -0
  173. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Computed/350/243/205/351/245/260/345/231/250/357/274/232/350/256/241/347/256/227/345/261/236/346/200/247.md +442 -0
  174. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Event/350/243/205/351/245/260/345/231/250/357/274/232/350/247/204/350/214/203/347/273/204/344/273/266/350/276/223/345/207/272.md +169 -0
  175. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Local/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/351/203/250/347/212/266/346/200/201.md +763 -0
  176. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Monitor/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/344/277/256/346/224/271/345/274/202/346/255/245/347/233/221/345/220/254.md +2088 -0
  177. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@ObservedV2/350/243/205/351/245/260/345/231/250/345/222/214@Trace/350/243/205/351/245/260/345/231/250/357/274/232/347/261/273/345/261/236/346/200/247/345/217/230/345/214/226/350/247/202/346/265/213.md +1258 -0
  178. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Once/357/274/232/345/210/235/345/247/213/345/214/226/345/220/214/346/255/245/344/270/200/346/254/241.md +175 -0
  179. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Param/357/274/232/347/273/204/344/273/266/345/244/226/351/203/250/350/276/223/345/205/245.md +850 -0
  180. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Provider/350/243/205/351/245/260/345/231/250/345/222/214@Consumer/350/243/205/351/245/260/345/231/250/357/274/232/350/267/250/347/273/204/344/273/266/345/261/202/347/272/247/345/217/214/345/220/221/345/220/214/346/255/245.md +862 -0
  181. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Type/350/243/205/351/245/260/345/231/250/357/274/232/346/240/207/350/256/260/347/261/273/345/261/236/346/200/247/347/232/204/347/261/273/345/236/213.md +110 -0
  182. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/AppStorageV2/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200UI/347/212/266/346/200/201/345/255/230/345/202/250.md +301 -0
  183. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/MVVM/346/250/241/345/274/217/357/274/210V2/357/274/211.md +1411 -0
  184. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/PersistenceV2/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +1392 -0
  185. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/getTarget/346/216/245/345/217/243/357/274/232/350/216/267/345/217/226/347/212/266/346/200/201/347/256/241/347/220/206/346/241/206/346/236/266/344/273/243/347/220/206/345/211/215/347/232/204/345/216/237/345/247/213/345/257/271/350/261/241.md +288 -0
  186. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/makeObserved/346/216/245/345/217/243/357/274/232/345/260/206/351/235/236/350/247/202/345/257/237/346/225/260/346/215/256/345/217/230/344/270/272/345/217/257/350/247/202/345/257/237/346/225/260/346/215/256.md +768 -0
  187. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2//347/212/266/346/200/201/347/256/241/347/220/206V1/345/222/214V2/346/267/267/347/224/250/346/214/207/345/257/274/357/274/210API version 19/345/217/212/344/271/213/345/220/216/357/274/211.md" +829 -0
  188. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2//347/212/266/346/200/201/347/256/241/347/220/206/346/246/202/350/277/260.md +184 -0
  189. package/skills/a2h-spec-implement/rules/arkts/ui/component-cookbook.md +431 -0
  190. package/skills/a2h-spec-implement/rules/arkts/ui/state-management.md +152 -0
  191. package/skills/a2h-spec-implement/rules/arkts/ui/ui-quality.md +67 -0
  192. package/skills/a2h-spec-implement/rules/arkts/ui/ui-runtime-diagnosis.md +32 -0
  193. package/skills/a2h-spec-implement/rules/pipeline/build/package-set-collection.md +43 -0
  194. package/skills/a2h-spec-implement/scripts/_lib/common.mjs +97 -0
  195. package/skills/a2h-spec-implement/scripts/_lib/config.mjs +70 -0
  196. package/skills/a2h-spec-implement/scripts/_lib/lessons_cli.mjs +48 -0
  197. package/skills/a2h-spec-implement/scripts/build_lessons.mjs +24 -0
  198. package/skills/a2h-spec-implement/scripts/code_pattern_lessons.mjs +26 -0
  199. package/skills/a2h-spec-implement/scripts/device_ui.mjs +433 -0
  200. package/skills/a2h-spec-implement/scripts/device_ui_core.mjs +895 -0
  201. package/skills/a2h-spec-implement/scripts/ledger/aggregate_run.mjs +207 -0
  202. package/skills/a2h-spec-implement/scripts/manifest/emit_summary_line.mjs +37 -0
  203. package/skills/a2h-spec-implement/scripts/manifest/finalize_run.mjs +115 -0
  204. package/skills/a2h-spec-implement/scripts/manifest/render_final_summary.mjs +78 -0
  205. package/skills/a2h-spec-implement/scripts/manifest/root_mirror.mjs +137 -0
  206. package/skills/a2h-spec-implement/scripts/package.json +12 -0
  207. package/skills/a2h-spec-implement/scripts/state_propagation_check.mjs +676 -0
  208. package/skills/a2h-spec-implement/scripts/test/l2_run.mjs +244 -0
  209. package/skills/a2h-spec-implement/scripts/test/tp_coverage.mjs +231 -0
  210. package/skills/a2h-spec-implement/scripts/ui_memory.mjs +161 -0
  211. package/skills/a2h-spec-implement/scripts/utils/ensure_app.mjs +134 -0
  212. package/skills/a2h-ui-transfer/SKILL.md +20 -9
  213. package/skills/a2h-ui-transfer/scripts/arkts_static_check.js +80 -0
  214. package/skills/hmos-convert-pipeline/SKILL.md +7 -5
  215. package/skills/hmos-incremental-ui-align/README.md +7 -7
  216. package/skills/hmos-incremental-ui-align/SKILL.md +1 -1
  217. package/skills/hmos-incremental-ui-align/page_align.md +1 -1
  218. package/skills/hmos-spec-generate/SKILL.md +2 -2
  219. package/skills/hmos-spec-generate/scripts/parse_requirements.mjs +537 -0
  220. package/skills/hmos-fix-build-errors/SKILL.md +0 -266
  221. package/skills/hmos-fix-build-errors/references/arkts-strict-patterns.md +0 -219
  222. package/skills/hmos-fix-build-errors/references/known-patterns.md +0 -157
  223. package/skills/hmos-fix-build-errors/references/rdb-entity-pattern.md +0 -131
  224. package/skills/hmos-spec-generate/scripts/parse_requirements.ts +0 -515
  225. /package/skills/{hmos-integration-test → a2h-integration-test}/scripts/resolve-metadata-tool.mjs +0 -0
  226. /package/skills/{hmos-integration-test → a2h-integration-test}/scripts/self-test-runner.mjs +0 -0
  227. /package/skills/{hmos-integration-test → a2h-integration-test}/scripts/testcases-tool.mjs +0 -0
@@ -0,0 +1,299 @@
1
+ import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
2
+ import { dirname, join, relative, resolve, sep } from "node:path";
3
+ import { hardFailure } from "../diagnostics.js";
4
+ const SETTINGS_NAMES = ["settings.gradle.kts", "settings.gradle"];
5
+ const BUILD_NAMES = ["build.gradle.kts", "build.gradle"];
6
+ function firstExisting(root, names) {
7
+ return names
8
+ .map((name) => join(root, name))
9
+ .find((path) => existsSync(path) && statSync(path).isFile());
10
+ }
11
+ function moduleDirectory(projectRoot, gradlePath) {
12
+ if (gradlePath === ":") {
13
+ return projectRoot;
14
+ }
15
+ return join(projectRoot, ...gradlePath.slice(1).split(":"));
16
+ }
17
+ function uniqueSorted(values) {
18
+ return [...new Set(values)].sort();
19
+ }
20
+ export function parseIncludedModules(settingsText) {
21
+ const modules = [];
22
+ const callPattern = /\binclude\s*\(([\s\S]*?)\)/gu;
23
+ for (const match of settingsText.matchAll(callPattern)) {
24
+ for (const value of match[1].matchAll(/["'](:[^"']+)["']/gu)) {
25
+ modules.push(value[1]);
26
+ }
27
+ }
28
+ const groovyPattern = /^\s*include\s+(.+)$/gmu;
29
+ for (const match of settingsText.matchAll(groovyPattern)) {
30
+ for (const value of match[1].matchAll(/["'](:[^"']+)["']/gu)) {
31
+ modules.push(value[1]);
32
+ }
33
+ }
34
+ return uniqueSorted(modules);
35
+ }
36
+ function block(text, name) {
37
+ const start = new RegExp(`\\b${name}\\s*\\{`, "u").exec(text);
38
+ if (!start) {
39
+ return undefined;
40
+ }
41
+ const open = text.indexOf("{", start.index);
42
+ let depth = 0;
43
+ let quote;
44
+ for (let index = open; index < text.length; index += 1) {
45
+ const character = text[index];
46
+ const previous = text[index - 1];
47
+ if (quote) {
48
+ if (character === quote && previous !== "\\") {
49
+ quote = undefined;
50
+ }
51
+ continue;
52
+ }
53
+ if (character === '"' || character === "'") {
54
+ quote = character;
55
+ } else if (character === "{") {
56
+ depth += 1;
57
+ } else if (character === "}") {
58
+ depth -= 1;
59
+ if (depth === 0) {
60
+ return text.slice(open + 1, index);
61
+ }
62
+ }
63
+ }
64
+ return undefined;
65
+ }
66
+ function assignedString(text, name) {
67
+ const patterns = [
68
+ new RegExp(`\\b${name}\\s*=\\s*["']([^"']+)["']`, "u"),
69
+ new RegExp(`\\b${name}\\s+["']([^"']+)["']`, "u"),
70
+ ];
71
+ for (const pattern of patterns) {
72
+ const value = pattern.exec(text)?.[1];
73
+ if (value) {
74
+ return value;
75
+ }
76
+ }
77
+ return undefined;
78
+ }
79
+ function parseNamedContainers(text) {
80
+ const names = [
81
+ ...text.matchAll(
82
+ /\b(?:create|maybeCreate|named|register)\s*\(\s*["']([^"']+)["']\s*\)/gu,
83
+ ),
84
+ ].map((match) => match[1]);
85
+ return uniqueSorted(names);
86
+ }
87
+ function upperCamel(value) {
88
+ return value.length === 0
89
+ ? value
90
+ : `${value[0].toUpperCase()}${value.slice(1)}`;
91
+ }
92
+ function buildVariants(buildTypes, productFlavors) {
93
+ if (productFlavors.length === 0) {
94
+ return buildTypes.map((buildType) => ({
95
+ name: buildType,
96
+ buildType,
97
+ productFlavors: [],
98
+ }));
99
+ }
100
+ // The frozen baseline uses at most one flavor dimension. A Gradle-derived
101
+ // model replaces this fallback before wider toolchain support is claimed.
102
+ return productFlavors.flatMap((flavor) =>
103
+ buildTypes.map((buildType) => ({
104
+ name: `${flavor.name}${upperCamel(buildType)}`,
105
+ buildType,
106
+ productFlavors: [flavor],
107
+ })),
108
+ );
109
+ }
110
+ function parseModule(projectRoot, gradlePath) {
111
+ const directory = moduleDirectory(projectRoot, gradlePath);
112
+ const buildFile = firstExisting(directory, BUILD_NAMES);
113
+ if (!buildFile) {
114
+ return undefined;
115
+ }
116
+ const text = readFileSync(buildFile, "utf8");
117
+ const hasAppliedPlugin = (pluginId) =>
118
+ text
119
+ .split(/\r?\n/u)
120
+ .some(
121
+ (line) =>
122
+ line.includes(pluginId) &&
123
+ !/\bapply\s+false\b/u.test(line) &&
124
+ (/\bid\s*\(/u.test(line) ||
125
+ /\bapply\s+plugin\s*:/u.test(line) ||
126
+ /\bplugins\.apply\s*\(/u.test(line)),
127
+ );
128
+ const kind = hasAppliedPlugin("com.android.application")
129
+ ? "application"
130
+ : hasAppliedPlugin("com.android.library")
131
+ ? "library"
132
+ : undefined;
133
+ if (!kind) {
134
+ return undefined;
135
+ }
136
+ const android = block(text, "android") ?? text;
137
+ const buildTypesBlock = block(android, "buildTypes") ?? "";
138
+ const parsedBuildTypes = parseNamedContainers(buildTypesBlock);
139
+ const buildTypes =
140
+ parsedBuildTypes.length > 0 ? parsedBuildTypes : ["debug", "release"];
141
+ const flavorsBlock = block(android, "productFlavors") ?? "";
142
+ const dimension = assignedString(android, "flavorDimensions");
143
+ const productFlavors = parseNamedContainers(flavorsBlock).map((name) => ({
144
+ name,
145
+ ...(dimension ? { dimension } : {}),
146
+ }));
147
+ const localProjectDependencies = uniqueSorted(
148
+ [...text.matchAll(/\bproject\s*\(\s*["'](:[^"']+)["']\s*\)/gu)].map(
149
+ (match) => match[1],
150
+ ),
151
+ );
152
+ return {
153
+ gradlePath,
154
+ directory,
155
+ buildFile,
156
+ kind,
157
+ namespace: assignedString(android, "namespace"),
158
+ applicationId: assignedString(
159
+ block(android, "defaultConfig") ?? android,
160
+ "applicationId",
161
+ ),
162
+ buildTypes,
163
+ productFlavors,
164
+ variants: buildVariants(buildTypes, productFlavors),
165
+ localProjectDependencies,
166
+ };
167
+ }
168
+ function ensureInside(root, candidate) {
169
+ const child = relative(root, candidate);
170
+ if (
171
+ child === ".." ||
172
+ child.startsWith(`..${sep}`) ||
173
+ child.startsWith("/") ||
174
+ /^[A-Za-z]:/u.test(child)
175
+ ) {
176
+ throw hardFailure(
177
+ "PROJECT_ROOT_ESCAPE",
178
+ "input",
179
+ `Resolved project path escapes the selected root: ${candidate}`,
180
+ );
181
+ }
182
+ }
183
+ export function discoverAndroidProject(projectRoot) {
184
+ const absoluteRoot = realpathSync(resolve(projectRoot));
185
+ const settingsFile = firstExisting(absoluteRoot, SETTINGS_NAMES);
186
+ if (!settingsFile) {
187
+ throw hardFailure(
188
+ "GRADLE_SETTINGS_MISSING",
189
+ "gradle",
190
+ `No settings.gradle(.kts) exists at ${absoluteRoot}`,
191
+ "Pass the Android Gradle root rather than an individual source folder.",
192
+ );
193
+ }
194
+ const included = parseIncludedModules(readFileSync(settingsFile, "utf8"));
195
+ const rootBuild = firstExisting(absoluteRoot, BUILD_NAMES);
196
+ const candidates = [...(rootBuild ? [":"] : []), ...included];
197
+ const modules = candidates
198
+ .map((path) => {
199
+ const directory = moduleDirectory(absoluteRoot, path);
200
+ ensureInside(absoluteRoot, resolve(directory));
201
+ return parseModule(absoluteRoot, path);
202
+ })
203
+ .filter((module) => module !== undefined)
204
+ .sort((left, right) =>
205
+ left.gradlePath.localeCompare(right.gradlePath, "en"),
206
+ );
207
+ if (modules.every((module) => module.kind !== "application")) {
208
+ throw hardFailure(
209
+ "APPLICATION_MODULE_MISSING",
210
+ "gradle",
211
+ "No Android application module was discovered.",
212
+ );
213
+ }
214
+ return {
215
+ projectRoot: absoluteRoot,
216
+ settingsFile,
217
+ modules,
218
+ };
219
+ }
220
+ function reachableModules(inventory, root) {
221
+ const byPath = new Map(
222
+ inventory.modules.map((module) => [module.gradlePath, module]),
223
+ );
224
+ const visited = new Set();
225
+ const queue = [root.gradlePath];
226
+ while (queue.length > 0) {
227
+ const path = queue.shift();
228
+ if (!path || visited.has(path)) {
229
+ continue;
230
+ }
231
+ visited.add(path);
232
+ const module = byPath.get(path);
233
+ module?.localProjectDependencies.forEach((dependency) =>
234
+ queue.push(dependency),
235
+ );
236
+ }
237
+ return [...visited]
238
+ .map((path) => byPath.get(path))
239
+ .filter((module) => module !== undefined)
240
+ .sort((left, right) =>
241
+ left.gradlePath.localeCompare(right.gradlePath, "en"),
242
+ );
243
+ }
244
+ export function selectProjectModel(inventory, options) {
245
+ const applications = inventory.modules.filter(
246
+ (module) => module.kind === "application",
247
+ );
248
+ const applicationModule = options.applicationModule
249
+ ? applications.find(
250
+ (module) => module.gradlePath === options.applicationModule,
251
+ )
252
+ : applications.length === 1
253
+ ? applications[0]
254
+ : undefined;
255
+ if (!applicationModule) {
256
+ throw hardFailure(
257
+ options.applicationModule
258
+ ? "APPLICATION_MODULE_UNKNOWN"
259
+ : "APPLICATION_MODULE_AMBIGUOUS",
260
+ "variant",
261
+ options.applicationModule
262
+ ? `Application module ${options.applicationModule} was not found.`
263
+ : `More than one application module exists: ${applications.map((module) => module.gradlePath).join(", ")}`,
264
+ "Select exactly one application module.",
265
+ );
266
+ }
267
+ const buildVariant = options.buildVariant
268
+ ? applicationModule.variants.find(
269
+ (variant) => variant.name === options.buildVariant,
270
+ )
271
+ : applicationModule.variants.length === 1
272
+ ? applicationModule.variants[0]
273
+ : undefined;
274
+ if (!buildVariant) {
275
+ throw hardFailure(
276
+ options.buildVariant
277
+ ? "BUILD_VARIANT_UNKNOWN"
278
+ : "BUILD_VARIANT_AMBIGUOUS",
279
+ "variant",
280
+ options.buildVariant
281
+ ? `Variant ${options.buildVariant} does not exist in ${applicationModule.gradlePath}.`
282
+ : `More than one variant exists in ${applicationModule.gradlePath}: ${applicationModule.variants.map((variant) => variant.name).join(", ")}`,
283
+ "Select exactly one build variant.",
284
+ );
285
+ }
286
+ return {
287
+ projectRoot: inventory.projectRoot,
288
+ applicationModule,
289
+ buildVariant,
290
+ reachableModules: reachableModules(inventory, applicationModule),
291
+ resourceConfiguration: options.resourceConfiguration,
292
+ };
293
+ }
294
+ export function projectRelativePath(projectRoot, path) {
295
+ return relative(projectRoot, resolve(path)).split(sep).join("/");
296
+ }
297
+ export function projectDirectoryFromSettings(settingsFile) {
298
+ return dirname(settingsFile);
299
+ }
@@ -0,0 +1,358 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { join, relative, resolve, sep } from "node:path";
3
+ import { hardFailure } from "../diagnostics.js";
4
+ import { runGradle, writeGradleProjectModel } from "./gradle-runner.js";
5
+ /**
6
+ * Convert every model filesystem field through an explicitly supplied mapper.
7
+ * Native execution uses the paths produced by Gradle unchanged; non-native
8
+ * executors must normalize their model before returning it or inject a mapper.
9
+ */
10
+ export function normalizeGradleProjectModelPaths(
11
+ model,
12
+ mapPath = (path) => path,
13
+ ) {
14
+ return {
15
+ ...model,
16
+ projectRoot: mapPath(model.projectRoot),
17
+ modules: model.modules.map((module) => ({
18
+ ...module,
19
+ directory: mapPath(module.directory),
20
+ buildFile: mapPath(module.buildFile),
21
+ sourceSets: module.sourceSets.map((sourceSet) => ({
22
+ ...sourceSet,
23
+ java: sourceSet.java.map(mapPath),
24
+ res: sourceSet.res.map(mapPath),
25
+ manifest: mapPath(sourceSet.manifest),
26
+ })),
27
+ })),
28
+ };
29
+ }
30
+ function isRecord(value) {
31
+ return value !== null && typeof value === "object" && !Array.isArray(value);
32
+ }
33
+ function stringArray(value) {
34
+ return Array.isArray(value) && value.every((item) => typeof item === "string")
35
+ ? value
36
+ : undefined;
37
+ }
38
+ function parseSourceSet(value, path) {
39
+ if (!isRecord(value)) {
40
+ throw new Error(`${path} must be an object`);
41
+ }
42
+ const java = stringArray(value.java);
43
+ const res = stringArray(value.res);
44
+ if (
45
+ typeof value.name !== "string" ||
46
+ !java ||
47
+ !res ||
48
+ typeof value.manifest !== "string"
49
+ ) {
50
+ throw new Error(`${path} has an invalid source-set shape`);
51
+ }
52
+ return {
53
+ name: value.name,
54
+ java,
55
+ res,
56
+ manifest: value.manifest,
57
+ };
58
+ }
59
+ function parseVariant(value, path) {
60
+ if (
61
+ !isRecord(value) ||
62
+ typeof value.name !== "string" ||
63
+ typeof value.buildType !== "string" ||
64
+ !Array.isArray(value.productFlavors)
65
+ ) {
66
+ throw new Error(`${path} has an invalid variant shape`);
67
+ }
68
+ const productFlavors = value.productFlavors.map((flavor, index) => {
69
+ if (!isRecord(flavor) || typeof flavor.name !== "string") {
70
+ throw new Error(`${path}.productFlavors[${index}] is invalid`);
71
+ }
72
+ return {
73
+ name: flavor.name,
74
+ ...(typeof flavor.dimension === "string"
75
+ ? { dimension: flavor.dimension }
76
+ : {}),
77
+ };
78
+ });
79
+ return {
80
+ name: value.name,
81
+ buildType: value.buildType,
82
+ productFlavors,
83
+ ...(typeof value.applicationId === "string"
84
+ ? { applicationId: value.applicationId }
85
+ : {}),
86
+ };
87
+ }
88
+ function parseModule(value, path) {
89
+ if (
90
+ !isRecord(value) ||
91
+ typeof value.gradlePath !== "string" ||
92
+ typeof value.directory !== "string" ||
93
+ typeof value.buildFile !== "string" ||
94
+ (value.kind !== "application" &&
95
+ value.kind !== "library" &&
96
+ value.kind !== "non-android-library") ||
97
+ !Array.isArray(value.variants) ||
98
+ !Array.isArray(value.sourceSets)
99
+ ) {
100
+ throw new Error(`${path} has an invalid Android module shape`);
101
+ }
102
+ const dependencies = stringArray(value.localProjectDependencies) ?? [];
103
+ return {
104
+ gradlePath: value.gradlePath,
105
+ directory: value.directory,
106
+ buildFile: value.buildFile,
107
+ kind: value.kind,
108
+ ...(typeof value.namespace === "string"
109
+ ? { namespace: value.namespace }
110
+ : {}),
111
+ variants: value.variants.map((variant, index) =>
112
+ parseVariant(variant, `${path}.variants[${index}]`),
113
+ ),
114
+ sourceSets: value.sourceSets.map((sourceSet, index) =>
115
+ parseSourceSet(sourceSet, `${path}.sourceSets[${index}]`),
116
+ ),
117
+ localProjectDependencies: dependencies,
118
+ };
119
+ }
120
+ export function parseGradleProjectModel(value) {
121
+ if (
122
+ !isRecord(value) ||
123
+ value.schemaVersion !== "1.0.0" ||
124
+ typeof value.projectRoot !== "string" ||
125
+ !Array.isArray(value.modules)
126
+ ) {
127
+ throw new Error("Gradle project model has an unsupported envelope");
128
+ }
129
+ return {
130
+ schemaVersion: "1.0.0",
131
+ projectRoot: value.projectRoot,
132
+ modules: value.modules.map((module, index) =>
133
+ parseModule(module, `modules[${index}]`),
134
+ ),
135
+ };
136
+ }
137
+ export async function loadGradleProjectModel(projectRoot, options) {
138
+ await writeGradleProjectModel(
139
+ projectRoot,
140
+ options.initScript,
141
+ options.outputPath,
142
+ options.runner,
143
+ );
144
+ try {
145
+ return normalizeGradleProjectModelPaths(
146
+ parseGradleProjectModel(
147
+ JSON.parse(readFileSync(options.outputPath, "utf8")),
148
+ ),
149
+ );
150
+ } catch (error) {
151
+ throw hardFailure(
152
+ "GRADLE_MODEL_INVALID",
153
+ "gradle",
154
+ `Gradle produced an invalid project model: ${error instanceof Error ? error.message : String(error)}`,
155
+ );
156
+ }
157
+ }
158
+ /**
159
+ * Android names a source set that combines multiple flavor dimensions in
160
+ * lower camel case (for example, `free` + `demo` becomes `freeDemo`).
161
+ */
162
+ export function combinedProductFlavorSourceSetName(variant) {
163
+ const flavors = variant.productFlavors.map((flavor) => flavor.name);
164
+ if (flavors.length < 2) return undefined;
165
+ return flavors
166
+ .map((flavor, index) =>
167
+ index === 0
168
+ ? flavor
169
+ : `${flavor[0]?.toUpperCase() ?? ""}${flavor.slice(1)}`,
170
+ )
171
+ .join("");
172
+ }
173
+ function activeNames(variant) {
174
+ const flavors = variant.productFlavors.map((flavor) => flavor.name);
175
+ const combinedFlavor = combinedProductFlavorSourceSetName(variant);
176
+ return [
177
+ "main",
178
+ ...flavors,
179
+ ...(combinedFlavor ? [combinedFlavor] : []),
180
+ variant.buildType,
181
+ variant.name,
182
+ ];
183
+ }
184
+ export function selectCompatibleModuleVariant(module, selected) {
185
+ const variant =
186
+ module.variants.find((candidate) => candidate.name === selected.name) ??
187
+ module.variants.find(
188
+ (candidate) =>
189
+ candidate.buildType === selected.buildType &&
190
+ candidate.productFlavors.length === 0,
191
+ );
192
+ if (!variant) {
193
+ throw hardFailure(
194
+ "DEPENDENCY_VARIANT_MISSING",
195
+ "variant",
196
+ `No compatible ${selected.name} source variant exists in ${module.gradlePath}.`,
197
+ );
198
+ }
199
+ return variant;
200
+ }
201
+ function selectModuleSourceSets(module, selected) {
202
+ // A non-android-library module has no variant concept and no res/manifest
203
+ // to merge — it contributes no source sets to resource/manifest merging.
204
+ if (module.kind === "non-android-library") return [];
205
+ const variant = selectCompatibleModuleVariant(module, selected);
206
+ const names = new Set(activeNames(variant));
207
+ return module.sourceSets.filter((sourceSet) => names.has(sourceSet.name));
208
+ }
209
+ function moduleClosure(model, root) {
210
+ const byPath = new Map(
211
+ model.modules.map((module) => [module.gradlePath, module]),
212
+ );
213
+ const visited = new Set();
214
+ const queue = [root.gradlePath];
215
+ while (queue.length > 0) {
216
+ const path = queue.shift();
217
+ if (!path || visited.has(path)) {
218
+ continue;
219
+ }
220
+ const module = byPath.get(path);
221
+ if (!module) {
222
+ throw hardFailure(
223
+ "LOCAL_MODULE_MISSING",
224
+ "gradle",
225
+ `Local dependency ${path} is absent from the Gradle model.`,
226
+ );
227
+ }
228
+ visited.add(path);
229
+ module.localProjectDependencies.forEach((dependency) =>
230
+ queue.push(dependency),
231
+ );
232
+ }
233
+ return [...visited]
234
+ .map((path) => byPath.get(path))
235
+ .filter((module) => module !== undefined)
236
+ .sort((left, right) =>
237
+ left.gradlePath.localeCompare(right.gradlePath, "en"),
238
+ );
239
+ }
240
+ export function selectGradleVariant(model, applicationModulePath, variantName) {
241
+ const applications = model.modules.filter(
242
+ (module) => module.kind === "application",
243
+ );
244
+ const applicationModule = applicationModulePath
245
+ ? applications.find((module) => module.gradlePath === applicationModulePath)
246
+ : applications.length === 1
247
+ ? applications[0]
248
+ : undefined;
249
+ if (!applicationModule) {
250
+ throw hardFailure(
251
+ applicationModulePath
252
+ ? "APPLICATION_MODULE_UNKNOWN"
253
+ : "APPLICATION_MODULE_AMBIGUOUS",
254
+ "variant",
255
+ applicationModulePath
256
+ ? `Unknown application module: ${applicationModulePath}`
257
+ : `Select one application module: ${applications.map((module) => module.gradlePath).join(", ")}`,
258
+ );
259
+ }
260
+ const variant = variantName
261
+ ? applicationModule.variants.find(
262
+ (candidate) => candidate.name === variantName,
263
+ )
264
+ : applicationModule.variants.length === 1
265
+ ? applicationModule.variants[0]
266
+ : undefined;
267
+ if (!variant) {
268
+ throw hardFailure(
269
+ variantName ? "BUILD_VARIANT_UNKNOWN" : "BUILD_VARIANT_AMBIGUOUS",
270
+ "variant",
271
+ variantName
272
+ ? `Unknown variant ${variantName} in ${applicationModule.gradlePath}.`
273
+ : `Select one variant in ${applicationModule.gradlePath}: ${applicationModule.variants.map((item) => item.name).join(", ")}`,
274
+ );
275
+ }
276
+ const reachableModules = moduleClosure(model, applicationModule);
277
+ const activeSourceSets = new Map(
278
+ reachableModules.map((module) => [
279
+ module.gradlePath,
280
+ selectModuleSourceSets(module, variant),
281
+ ]),
282
+ );
283
+ return {
284
+ model,
285
+ applicationModule,
286
+ variant,
287
+ reachableModules,
288
+ activeSourceSets,
289
+ };
290
+ }
291
+ function upperCamel(value) {
292
+ return value.length === 0
293
+ ? value
294
+ : `${value[0].toUpperCase()}${value.slice(1)}`;
295
+ }
296
+ function walkFiles(root) {
297
+ if (!existsSync(root) || !statSync(root).isDirectory()) {
298
+ return [];
299
+ }
300
+ const results = [];
301
+ for (const entry of readdirSync(root, { withFileTypes: true })) {
302
+ const path = join(root, entry.name);
303
+ if (entry.isDirectory()) {
304
+ results.push(...walkFiles(path));
305
+ } else if (entry.isFile()) {
306
+ results.push(path);
307
+ }
308
+ }
309
+ return results;
310
+ }
311
+ export async function prepareMergedManifest(selected, runner) {
312
+ const moduleTask =
313
+ selected.applicationModule.gradlePath === ":"
314
+ ? ""
315
+ : selected.applicationModule.gradlePath;
316
+ const variant = upperCamel(selected.variant.name);
317
+ const task = `${moduleTask}:process${variant}MainManifest`;
318
+ const result = await runGradle(
319
+ selected.model.projectRoot,
320
+ ["--no-daemon", "--console=plain", task],
321
+ runner,
322
+ );
323
+ if (result.exitCode !== 0) {
324
+ throw hardFailure(
325
+ "MERGED_MANIFEST_FAILED",
326
+ "manifest",
327
+ `Gradle task ${task} failed.`,
328
+ undefined,
329
+ {
330
+ stdoutTail: result.stdout.slice(-4_000),
331
+ stderrTail: result.stderr.slice(-4_000),
332
+ },
333
+ );
334
+ }
335
+ const candidates = walkFiles(
336
+ join(
337
+ selected.applicationModule.directory,
338
+ "build",
339
+ "intermediates",
340
+ "merged_manifest",
341
+ selected.variant.name,
342
+ ),
343
+ ).filter((path) => /AndroidManifest\.xml$/u.test(path));
344
+ if (candidates.length !== 1) {
345
+ throw hardFailure(
346
+ "MERGED_MANIFEST_AMBIGUOUS",
347
+ "manifest",
348
+ `Expected one merged main Manifest for ${selected.applicationModule.gradlePath}/${selected.variant.name}, found ${candidates.length}.`,
349
+ undefined,
350
+ {
351
+ candidates: candidates.map((path) =>
352
+ relative(selected.model.projectRoot, path).split(sep).join("/"),
353
+ ),
354
+ },
355
+ );
356
+ }
357
+ return resolve(candidates[0]);
358
+ }