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,134 @@
1
+ #!/usr/bin/env node
2
+ // ensure_app.mjs — guarantee the project's app is installed on a device (Phase 1 grounding gate).
3
+ //
4
+ // node scripts/utils/ensure_app.mjs --project <harmonyos-project-path> --device <serial> [--bundle <name>]
5
+ //
6
+ // Deterministic, idempotent: probe installed → done; absent → devecocli build (release, signed
7
+ // per rules/pipeline/build/build.md) → hdc install -r (cd + basename, per testing/test-core.md
8
+ // § Device channel & install) → re-probe. Never uninstalls, never reinstalls an installed app
9
+ // (an app-HAP reinstall re-signs and drops persisted URI grants — measured).
10
+ //
11
+ // stdout contract: exactly ONE line —
12
+ // ENSURE_APP: installed bundle=<b> device=<d>
13
+ // ENSURE_APP: built+installed bundle=<b> device=<d> haps=<n>
14
+ // ENSURE_APP: FAILED <stage>: <reason>
15
+ // Diagnostics (build-log tail etc.) go to stderr. Exit 0 on installed/built+installed, 1 on FAILED.
16
+ import { spawnSync } from "node:child_process";
17
+ import fs from "node:fs";
18
+ import path from "node:path";
19
+ import { ensureHdcOnPath, hdcRun } from "../device_ui_core.mjs";
20
+
21
+ // ---------- args ----------
22
+ function parseArgs(argv) {
23
+ const a = { project: "", device: "", bundle: "" };
24
+ for (let i = 0; i < argv.length; i++) {
25
+ const t = argv[i];
26
+ if (t === "--project") a.project = argv[++i];
27
+ else if (t === "--device") a.device = argv[++i];
28
+ else if (t === "--bundle") a.bundle = argv[++i];
29
+ else if (t === "-h" || t === "--help") a.help = true;
30
+ }
31
+ return a;
32
+ }
33
+ const args = parseArgs(process.argv.slice(2));
34
+ if (args.help || !args.project || !args.device) {
35
+ console.error("Usage: node scripts/utils/ensure_app.mjs --project <harmonyos-project-path> --device <serial> [--bundle <name>]");
36
+ process.exit(args.help ? 0 : 1);
37
+ }
38
+
39
+ function ok(line) { console.log(line); process.exit(0); }
40
+ function fail(stage, reason) { console.log(`ENSURE_APP: FAILED ${stage}: ${reason}`); process.exit(1); }
41
+
42
+ const project = path.resolve(args.project);
43
+ if (!fs.existsSync(project)) fail("args", `project not found: ${project}`);
44
+
45
+ // ---------- bundle name (AppScope/app.json5) ----------
46
+ let bundle = args.bundle;
47
+ if (!bundle) {
48
+ const appJson = path.join(project, "AppScope", "app.json5");
49
+ try {
50
+ const m = fs.readFileSync(appJson, "utf8").match(/"bundleName"\s*:\s*"([^"]+)"/);
51
+ if (m) bundle = m[1];
52
+ } catch { /* fall through */ }
53
+ if (!bundle) fail("args", `bundleName not resolvable from ${appJson} (pass --bundle)`);
54
+ }
55
+
56
+ // ---------- probe installed ----------
57
+ if (!ensureHdcOnPath()) fail("probe", "hdc not on PATH and not locatable via conf.yaml DEVECO_PATH/DEVECO_SDK_HOME");
58
+ // hdc exits 0 even on an unreachable device (error text on stdout) — verify the target is
59
+ // actually connected before trusting any shell output.
60
+ const targets = hdcRun(null, ["list", "targets"], 15000);
61
+ if (targets.error || !(targets.stdout || "").split(/\r?\n/).some((l) => l.trim() === args.device)) {
62
+ fail("probe", `device ${args.device} not in \`hdc list targets\`: ${((targets.stdout || targets.stderr || "") + "").trim().slice(0, 200)}`);
63
+ }
64
+ function isInstalled() {
65
+ const p = hdcRun(args.device, ["shell", "bm", "dump", "-a"], 30000);
66
+ const out = p.stdout || "";
67
+ if (p.error || p.status !== 0 || /\[Fail\]/i.test(out)) {
68
+ fail("probe", `bm dump failed on ${args.device}: ${((p.stderr || out || String(p.error)) + "").trim().slice(0, 200)}`);
69
+ }
70
+ // `bm dump -a` lists bundle names one per line; exact-token match (avoid prefix collisions).
71
+ return out.split(/\r?\n/).some((l) => l.trim() === bundle);
72
+ }
73
+ if (isInstalled()) ok(`ENSURE_APP: installed bundle=${bundle} device=${args.device}`);
74
+
75
+ // ---------- build (release = signed output; debug is compile-check only per build.md) ----------
76
+ console.error(`[ensure_app] ${bundle} not installed on ${args.device} — building current code (devecocli build, release)…`);
77
+ const build = spawnSync("devecocli build", {
78
+ cwd: project, shell: true, encoding: "utf8", timeout: 600000,
79
+ windowsHide: true, maxBuffer: 64 * 1024 * 1024,
80
+ });
81
+ const buildLog = (build.stdout || "") + (build.stderr || "");
82
+ if (build.error || build.status !== 0 || !/BUILD SUCCESSFUL/i.test(buildLog)) {
83
+ console.error(buildLog.split(/\r?\n/).slice(-30).join("\n"));
84
+ fail("build", `devecocli build rc=${build.status ?? build.error} (log tail on stderr)`);
85
+ }
86
+
87
+ // ---------- collect package set (per-module <mod>/build/default/outputs/default) ----------
88
+ // Signing mode follows the project: a product referencing a signingConfig emits *-signed.hap,
89
+ // `app.signingConfigs: []` emits *-unsigned.hap and cannot emit anything else. Take signed when
90
+ // present, else unsigned — rejecting the unsigned variant yields no package set at all, which
91
+ // disables the device layer and misreports a build-config fact as a missing artifact.
92
+ const outDirs = [];
93
+ for (const mod of fs.readdirSync(project, { withFileTypes: true })) {
94
+ if (!mod.isDirectory()) continue;
95
+ const out = path.join(project, mod.name, "build", "default", "outputs", "default");
96
+ if (fs.existsSync(out)) outDirs.push(out);
97
+ }
98
+ const collect = (suffix) => {
99
+ const acc = []; // { dir, name }
100
+ for (const dir of outDirs) {
101
+ for (const f of fs.readdirSync(dir)) {
102
+ if (f.endsWith(`-${suffix}.hap`) || f.endsWith(".hsp")) acc.push({ dir, name: f });
103
+ }
104
+ }
105
+ return acc;
106
+ };
107
+ let mode = "signed";
108
+ let pkgs = collect("signed");
109
+ if (!pkgs.some((p) => p.name.endsWith(".hap"))) {
110
+ const unsignedPkgs = collect("unsigned");
111
+ if (unsignedPkgs.some((p) => p.name.endsWith(".hap"))) {
112
+ mode = "unsigned";
113
+ pkgs = unsignedPkgs;
114
+ console.error("[ensure_app] no signed HAP — installing the unsigned package set; a device that refuses it is an environment result, not a code defect");
115
+ }
116
+ }
117
+ if (!pkgs.length) fail("install", "build produced no *-signed.hap and no *-unsigned.hap (see build.md § Pinned command)");
118
+
119
+ // ---------- install (one transaction; cd + basename — hdc mangles non-Windows paths) ----------
120
+ const byDir = new Map();
121
+ for (const p of pkgs) { if (!byDir.has(p.dir)) byDir.set(p.dir, []); byDir.get(p.dir).push(p.name); }
122
+ for (const [dir, names] of byDir) {
123
+ const p = spawnSync("hdc", ["-t", args.device, "install", "-r", ...names], {
124
+ cwd: dir, encoding: "utf8", timeout: 120000, windowsHide: true,
125
+ });
126
+ const outText = ((p.stdout || "") + (p.stderr || "")).trim();
127
+ if (p.error || p.status !== 0 || /error|fail/i.test(outText)) {
128
+ fail("install", `hdc install -r ${names.join(" ")}: ${outText.slice(0, 300)}`);
129
+ }
130
+ }
131
+
132
+ // ---------- re-probe ----------
133
+ if (!isInstalled()) fail("install", `install reported success but ${bundle} still absent in bm dump -a`);
134
+ ok(`ENSURE_APP: built+installed bundle=${bundle} device=${args.device} haps=${pkgs.length} mode=${mode}`);
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: a2h-ui-transfer
3
- description: Batch-convert multiple Android Activity UI snapshots to HarmonyOS ArkUI (ArkTS) pages. Use when the user wants to migrate Android UI pages to HarmonyOS in bulk, port multiple Activity screens to ArkTS, or run an Android-to-HarmonyOS UI conversion across a folder of page snapshots (page_NNNN_ActivityName). Includes Lottie animation handling — greps the Lottie Animation Resources section out of the conversion report produced by a2h-resource-convert, binds each Lottie JSON to the host Activity/Fragment, and passes only the relevant entries to each per-page sub-agent so the generated ArkTS page implements the animation with @ohos/lottie (loaded from rawfile/lottie/) mirroring the Android hosting logic. Triggers on phrases like "把安卓页面迁移到鸿蒙", "Android UI 转鸿蒙", "批量转 ArkTS", "a2h-ui-transfer", or any request that supplies an Android project path + Harmony project path + a directory of page snapshots.
3
+ description: Batch-convert multiple Android Activity UI snapshots to HarmonyOS ArkUI (ArkTS) pages. Use when the user wants to migrate Android UI pages to HarmonyOS. Triggers on phrases like "把安卓页面迁移到鸿蒙", "Android UI 转鸿蒙", "批量转 ArkTS", "a2h-ui-transfer", or any request that supplies an Android project path + Harmony project path + a directory of page snapshots.
4
4
  ---
5
5
 
6
6
  # a2h-ui-transfer — Android → HarmonyOS UI Batch Conversion
@@ -39,7 +39,7 @@ Extract these from the user's message (natural language, no fixed format):
39
39
 
40
40
  If a **required** path (`android_project_dir`, `harmony_project_dir`, `apk_path`) cannot be extracted from the user's message, **ask the user** — do not guess. `ui_info_root` and `pages` are optional and have the defaults described above; do not ask for them.
41
41
 
42
- ## Step 2 — Resource Conversion
42
+ ## Step 2 — Resource Conversion (use a sub-agent, type: general)
43
43
 
44
44
  Invoke the `a2h-resource-convert` skill with the following parameters (all snake_case, matching that skill's declared inputs):
45
45
  1. `android_project_dir` = `android_project_dir`
@@ -50,16 +50,16 @@ Invoke the `a2h-resource-convert` skill with the following parameters (all snake
50
50
 
51
51
  This skill batch-converts Android resources (strings, colors, drawables, images, etc.) to HarmonyOS resource format and generates the mapping document.
52
52
 
53
- **Two documents come out of that skill and they are not interchangeable — record both paths.** The **conversion report** (`<work_dir>/resource_conversion_report.md`, observed at `${harmony_project_dir}/.hometrans/resource_conversion_report.md`, ~180 KB) is aggregated and holds the **Vector Fidelity Issues** / **Lottie Animation Resources** / **Code-Defined Vector Icons** sections that Steps 4.5 and 5 need. The **mapping document** (`resource_mapping_path`) is the per-resource audit surface, **4–22 MB by design** (one observed file: 2.3 MB) and has **no Lottie section** — always `Grep <name>` it, never `Read` it whole: a truncated read drops rows that then look exactly like "that resource does not exist", and the page substitutes something that compiles.
53
+ **Two documents come out of that skill and they are not interchangeable — record both paths.** The **conversion report** (`<work_dir>/resource_conversion_report.md`, observed at `${harmony_project_dir}/.hometrans/resource_conversion_report.md`,) is aggregated and holds the **Vector Fidelity Issues** / **Lottie Animation Resources** / **Code-Defined Vector Icons** sections that Steps 4.5 and 5 need. The **mapping document** (`resource_mapping_path`) is the per-resource audit surface, **4–22 MB by design** — always `Grep <name>` it, never `Read` it whole: a truncated read drops rows that then look exactly like "that resource does not exist", and the page substitutes something that compiles.
54
54
 
55
- **Resolve `<app_module>` while you are here** — the module whose Gradle file applies the `com.android.application` plugin (grep `com.android.application` across `<android_project_dir>/*/build.gradle` and `*/build.gradle.kts`). It is **usually** `app/`, but do not assume that name: many projects use `mobile/`, `client/`, `androidApp/`, or a nested path. Store it relative to `<android_project_dir>` and use it everywhere below instead of a literal `app`. If several modules apply the plugin, ask the user which one corresponds to `apk_path`. This matches the resolution `a2h-resource-convert` does in its Step 2, so the two skills agree on the module.
55
+ **Resolve `<app_module>` ** — the module whose Gradle file applies the `com.android.application` plugin (grep `com.android.application` across `<android_project_dir>/*/build.gradle` and `*/build.gradle.kts`). It is **usually** `app/`, but do not assume that name: many projects use `mobile/`, `client/`, `androidApp/`, or a nested path. Store it relative to `<android_project_dir>` and use it everywhere below instead of a literal `app`. If several modules apply the plugin, ask the user which one corresponds to `apk_path`. This matches the resolution `a2h-resource-convert` does in its Step 2, so the two skills agree on the module.
56
56
 
57
- **Resolve `<ui_module>` here as well — the Harmony-side UI module, which is *not* always `entry`.** Read `${harmony_project_dir}/build-profile.json5` and take the `modules[]` entry whose `srcPath` holds a `module.json5` with `"type": "entry"`; store that `srcPath` relative to `harmony_project_dir`. A single-module project yields `entry`; a layered one yields a multi-segment path such as `products/phone`. **Every Harmony path from here on uses `<ui_module>`, never a literal `entry`** — pages, resources, the Step 6.0 static check, and the fidelity checker below. Getting this wrong is silent rather than loud: resources land in the module `a2h-resource-convert` resolved while pages are written to `entry/`, so every resource reference in every page dangles, and the static check — pointed at an `ets` directory that does not exist — scans zero files and reports a clean GATE. If several modules are `type: entry`, ask the user which one to convert into.
57
+ **Resolve `<ui_module>` — the Harmony-side UI module, which is *not* always `entry`.** Read `${harmony_project_dir}/build-profile.json5` and take the `modules[]` entry whose `srcPath` holds a `module.json5` with `"type": "entry"`; store that `srcPath` relative to `harmony_project_dir`. A single-module project yields `entry`; a layered one yields a multi-segment path such as `products/phone`. **Every Harmony path from here on uses `<ui_module>`, never a literal `entry`** — pages, resources, the Step 6.0 static check, and the fidelity checker below. Getting this wrong is silent rather than loud: resources land in the module `a2h-resource-convert` resolved while pages are written to `entry/`, so every resource reference in every page dangles, and the static check — pointed at an `ets` directory that does not exist — scans zero files and reports a clean GATE. If several modules are `type: entry`, ask the user which one to convert into.
58
58
 
59
59
  **Resource-fidelity gate before Step 5.** When that skill's report contains a **Vector Fidelity Issues** section with `error`-severity rows, fix the resources before starting per-page conversion. A drawable whose `clip-path` was dropped, or whose stroke-only path was given a solid `fill`, still has the correct file name — so every page that references it will pass Phase 5's reference checks and compile cleanly while rendering wrong. Fixing it after the pages are written means re-verifying every page that consumed it. If resources were converted in an earlier session (so no fresh report exists), you can run that skill's checker directly — it is static and needs no device:
60
60
 
61
61
  ```
62
- node <a2h-resource-convert-skill>/scripts/svg_fidelity_check.js \
62
+ node <a2h-resource-convert>/scripts/svg_fidelity_check.js \
63
63
  --android-res <android_project_dir>/<app_module>/src/main/res \
64
64
  --harmony-media <harmony_project_dir>/<ui_module>/src/main/resources/base/media
65
65
  ```
@@ -67,7 +67,7 @@ node <a2h-resource-convert-skill>/scripts/svg_fidelity_check.js \
67
67
  **App-identity gate — also before Step 5.** That skill's Toolchain step 2 points `AppScope/app.json5` and `abilities[0]` at the Android launcher icon and app name. Confirm it passed; nothing in Steps 5-7 covers it, and the failure is invisible to every check here — the pages compile and render fine while the app shows the DevEco default icon and is named `label` on the desktop. If resources were converted in an earlier session, run the gate directly (static, no device):
68
68
 
69
69
  ```
70
- node <a2h-resource-convert-skill>/scripts/app_identity.js --check --json <work_dir>/app_identity.json
70
+ node <a2h-resource-convert>/scripts/app_identity.js --check --json <work_dir>/app_identity.json
71
71
  ```
72
72
 
73
73
  `GATE: FAIL`, or a missing `app_identity.json` (the step never ran), means re-running that skill's Toolchain step 2 before continuing.
@@ -245,7 +245,7 @@ Why it exists: on a measured single-page run the sub-agent spent **11 turns (~5
245
245
 
246
246
  The unit of work is the **state group** from Step 4.2 — a group of one page (the common case) or of several isomorphic pages. Skip a whole group only when *every* member is `done` with its `output` present; otherwise convert the group, treating the already-done members as context. For a multi-state group, items 1-4 below apply **once per member state**, each labelled with its page id, and Phase 5 evidence is required per state.
247
247
 
248
- **For each page to convert**:
248
+ **Invoke a sub-agent(type:general) for each page to convert**:
249
249
 
250
250
  **The per-page conversion procedure lives in `./references/conversion-procedure.md`, and the sub-agent is the one that reads it** — the parent passes its absolute path (input 0 below).
251
251
 
@@ -317,6 +317,7 @@ After each page's conversion :
317
317
  | Resource keys exist in every qualifier group the page needs | script the lookup across `base/` and each locale dir |
318
318
  | Forbidden patterns absent | `.position(`/`.offset(`, `$r(\``, V1 decorators in a V2 project |
319
319
  | **V1 only: no `@Track` class exposes a getter to the UI** | `grep -n "get [a-zA-Z]*(" ` every `@Observed` class that contains `@Track`. A getter cannot be `@Track`ed, so reading it in `build()` throws `BusinessError 140110` on the **first frame** — while the field-side completeness check passes, the build succeeds, and GATE is clean. Backstop: GATE rule `track-class-getter-in-ui` |
320
+ | **Self-contained component wired into its host** | discharged at Step 5.5 (batch-level, not per-page): the parent imports each component and binds its trigger; a page's `done` during the batch is provisional for its triggers until Step 5.5 completes — GATE `orphan-component` zero is the batch-level discharge |
320
321
 
321
322
  When a sub-agent dies after writing code but before reporting, do not re-run it blindly: verify what is on disk against this list, and reconstruct only the missing evidence. Record in `batch_progress.json` which parts of the evidence were parent-reconstructed rather than sub-agent-attested, so a later reader can tell the two apart.
322
323
 
@@ -343,12 +344,20 @@ The conflict surface is narrow — the entry page plus shared VM/Model. A group
343
344
  **Rules when running concurrently:**
344
345
  1. **The first host-chain group goes first, alone.** It creates the entry page and the shared VM/Model that later groups extend, and it establishes the conventions (decorator paradigm, naming, resource style) that every later prompt cites. Do not start anything concurrently with it.
345
346
  2. After it completes, dispatch the remaining host-chain groups **serially** and the self-contained groups **concurrently alongside them**.
346
- 3. **A self-contained group's prompt must state that it may not edit the entry page or shared VM/Model.** If it discovers it genuinely needs to, it must report that instead of writing — the parent then does the wiring after the concurrent group completes, or reclassifies the group as host-chain on a later run. This is what keeps the static classification true at runtime.
347
+ 3. **A self-contained group's prompt must state that it may not edit the entry page or shared VM/Model.** If it discovers it genuinely needs to, it must report that instead of writing — the parent then does that wiring in **Step 5.5**, or reclassifies the group as host-chain on a later run. This is what keeps the static classification true at runtime.
347
348
  4. **`batch_progress.json` writes must be serialized by the parent.** Never let a sub-agent write it. Read-modify-write it yourself, one group at a time, after each group returns.
348
349
  5. If any group's actual write set turns out to violate its classification, treat the batch's parallel assumption as broken: finish serially and record it, so the next run classifies correctly.
349
350
 
350
351
  When in doubt, serialize — a wrong parallel call costs a corrupted file and a re-run, which is worse than the time saved.
351
352
 
353
+ ### Step 5.5 — Parent Wiring (after all groups return, before Step 6)
354
+
355
+ Self-contained groups write only their own component files — Scheduling rule 3 forbids their sub-agents from editing the entry page or shared VM/Model. That makes wiring each component into its host **the parent's job, and no one else's**: import the component in the host page, instantiate it, add a `@Local` show flag, and bind the trigger (the button / icon / menu entry that opens it) to toggle that flag; navigation-bearing triggers get `router.pushUrl`. A trigger that still calls a placeholder ViewModel method is unwired.
356
+
357
+ This was previously a subordinate clause in Scheduling rule 3, protected by no gate — and the failure is silent: every component file legal, the build green, resource checks green, while every trigger on the host page does nothing (observed: 11 components converted, 0 responsive icons). Hence the numbered step.
358
+
359
+ **Mechanical gate:** run `scripts/arkts_static_check.js`; GATE `orphan-component` (an exported struct that no file imports and no file instantiates can never render) must be **zero** before Step 6 begins. Wire components until it is.
360
+
352
361
  ## Step 6 — Unified Build Fix
353
362
 
354
363
  ### Step 6.0 — Static check first (cheap, runs before the build)
@@ -374,6 +383,8 @@ Three `[GATE]` rules read the *content* of referenced SVGs rather than the code,
374
383
 
375
384
  One `[GATE]` rule catches a defect that survives the entire pipeline otherwise: `entry-route-not-converted`. Registering a page in `main_pages.json` only makes it *routable*; what determines the launch screen is `loadContent()` in the `UIAbility`. When those disagree, every page converts correctly, the build succeeds, reference checks pass — and launching the app shows the DevEco scaffold's Hello World, with the converted work never displayed at all. The rule fires only when the project already contains converted pages, so a not-yet-converted project is not nagged.
376
385
 
386
+ Another `[GATE]` rule closes the assembly gap that `entry-route-not-converted` cannot see: `orphan-component`. A self-contained dialog or sheet component is written by a sub-agent forbidden to touch the host page; until the parent wires it in (Step 5.5), it is a legal file that nothing can ever render — every other check green, every trigger dead. The rule fires when an exported struct appears in no import and no instantiation, so an unwired batch cannot reach the build.
387
+
377
388
  Two of its GATE rules exist purely to turn a **compile error** into a sub-second lexical hit, so running the checker before the first build (not after it fails) is now worth real wall clock: `state-name-shadows-attribute` — a state field named `size`/`width`/`margin`/… collides with the `CustomComponent` base method, and the compiler's `10505001` text talks about type assignability while never hinting "rename it"; and `builder-invokes-callback-param` — a `@Builder` taking a `() => void` param and invoking it bare, which is `10905204`. Measured on one page: those two classes were **6 of the 8 errors in the first build**, each build round trip costing 45-70s against under a second for the checker. Both recur across pages — `size` is the most natural name any icon component reaches for.
378
389
 
379
390
  - **`[GATE]`** — zero-ambiguity defects. **Fix every one before building.** Doing this first is a real saving: an unterminated JSDoc block (a `*/` sequence inside a comment, e.g. from writing an evidence path like `foo_*/view.xml`) makes the compiler emit *hundreds* of errors whose line/column coordinates point into comment prose, so diagnosing it from build output means reverse-engineering phantom errors. The checker names it directly. Also gated: `$r()` template strings, `width('100%')` + horizontal margin on one element, V1/V2 paradigm mixing, `@ObservedV2`/`@Trace` used without its partner, missing window layer while pages declare `expandSafeArea`, and literal quote leakage in `element/string.json`.
@@ -31,6 +31,14 @@
31
31
  * 检查全过,唯一症状是启动后停在脚手架的 Hello World,转换成果一次也没显示过 ——
32
32
  * 只有真机启动能看见,但判据完全是词法的,故定为 GATE。
33
33
  * 它以「工程内已有转换产出页」为前提:空工程加载脚手架页是正确状态,不报。
34
+ *
35
+ * R13(orphan-component)针对第三个同源模式:**「写出来了」不等于「接上去了」**。
36
+ * 调度器把对话框/面板组判为 self-contained 时,子代理只写自己的组件文件、被禁止
37
+ * 改宿主页,接线责任落在父代理「并发组完成后的统一接线」上 —— 而那一步没有任何
38
+ * 门禁保护。一旦父级跳过:每个组件文件都合法、编译通过、资源闭环全绿,宿主页的
39
+ * 触发按钮却什么都不做,唯一症状是真机上「图标点了没反应」。判据完全词法:
40
+ * 非 @Entry 文件里 export struct 的名字,未出现在任何 import 中、也未在本文件内
41
+ * 实例化 —— 该组件永远不可能被渲染。同为 GATE。
34
42
  */
35
43
 
36
44
  import * as fs from 'fs';
@@ -1302,6 +1310,77 @@ function checkEntryRoute(scans, etsDir) {
1302
1310
  }
1303
1311
  }
1304
1312
 
1313
+ /**
1314
+ * GATE R13:孤儿组件 —— 已导出的自定义组件从未被 import,也从未在本文件内实例化。
1315
+ *
1316
+ * 失效模式(实测):批调度把对话框/底部弹窗/菜单组判为 self-contained,每个子代理
1317
+ * 只写自己的 `components/Xxx.ets` 且被禁止改宿主页;接线是父代理在并发组完成后的
1318
+ * 职责,但该步骤无门禁。父级一旦跳过,产出「每个零件都合格、但没装配」的工程:
1319
+ * 组件文件合法、编译通过、资源引用闭环全绿 —— 宿主页触发按钮调用的还是占位逻辑,
1320
+ * 症状只有真机上「点了没反应」。和 R11 同源:编译门禁抓不到、判据却纯词法。
1321
+ *
1322
+ * 判据(全部词法,零歧义):
1323
+ * 文件不含 @Entry(经 main_pages.json 路由加载的页不需要被 import);
1324
+ * 且其中 `export struct X` 的名字 X:
1325
+ * (1) 未出现在任何文件的 import 语句中(ArkTS 里 struct 非全局,不 import 就用不到);
1326
+ * (2) 也未在本文件内实例化(排除「导出仅供测试、本文件自用」的合法形态)。
1327
+ *
1328
+ * 豁免与边界:
1329
+ * - @Entry 文件整体豁免:入口 struct 靠路由加载,同文件的辅助 struct 通常由入口消费;
1330
+ * - 别名导入(`import { X as Y }`)按消费 X 计(取 as 之前的名字);
1331
+ * - `import type` 不算消费 —— 类型导入无法让组件渲染;
1332
+ * - 组件被另一个孤儿组件 import 时不报被引用方,只报顶层孤儿(责任指向可操作的那一层);
1333
+ * - 前置条件:工程内至少存在一个 @Entry 文件 —— 纯库模块(无页面)不适用本判据。
1334
+ */
1335
+ function checkOrphanComponents(scans) {
1336
+ if (!scans.some((s) => /@Entry\b/.test(s.text))) {
1337
+ return;
1338
+ }
1339
+
1340
+ // 1. 汇总所有 import 进来的名字(跨文件消费面)
1341
+ const namedImportRe = /import\s+(?:[A-Za-z_$][\w$]*\s*,\s*)?\{([^}]*)\}\s*from/g;
1342
+ const defaultImportRe = /import\s+([A-Za-z_$][\w$]*)\s+from/g;
1343
+ const importedNames = new Set();
1344
+ for (const s of scans) {
1345
+ let m;
1346
+ namedImportRe.lastIndex = 0;
1347
+ while ((m = namedImportRe.exec(s.text)) !== null) {
1348
+ // [^}]* 覆盖多行 import;`X as Y` 取 X(消费的是导出名)
1349
+ for (const part of m[1].split(',')) {
1350
+ const name = part.trim().split(/\s+as\s+/)[0].trim();
1351
+ if (name !== '') { importedNames.add(name); }
1352
+ }
1353
+ }
1354
+ defaultImportRe.lastIndex = 0;
1355
+ while ((m = defaultImportRe.exec(s.text)) !== null) {
1356
+ importedNames.add(m[1]);
1357
+ }
1358
+ }
1359
+
1360
+ // 2. 逐文件找未被消费的 export struct
1361
+ for (const s of scans) {
1362
+ if (/@Entry\b/.test(s.text)) { continue; }
1363
+ const lines = s.text.split('\n');
1364
+ for (let i = 0; i < lines.length; i++) {
1365
+ const dm = /export\s+struct\s+([A-Za-z_$][\w$]*)/.exec(lines[i]);
1366
+ if (dm === null) { continue; }
1367
+ const name = dm[1];
1368
+ if (importedNames.has(name)) { continue; }
1369
+ // 本文件内自用:声明行之外的 `Name(` 实例化(ArkUI 组件实例化形态 Name() / Name({...}))
1370
+ let selfUsed = false;
1371
+ const useRe = new RegExp('\\b' + name + '\\s*\\(');
1372
+ for (let j = 0; j < lines.length; j++) {
1373
+ if (j !== i && useRe.test(lines[j])) { selfUsed = true; break; }
1374
+ }
1375
+ if (selfUsed) { continue; }
1376
+ report('GATE', 'orphan-component', s.rel, i + 1,
1377
+ `导出的自定义组件 '${name}' 未被任何文件 import,也未在本文件内实例化 —— ` +
1378
+ '它永远无法被渲染。self-contained 调度的对话框/面板组件必须在宿主页' +
1379
+ '(或父级接线阶段)被 import 并挂到触发器上;若确为预留,请移出本批转换产物');
1380
+ }
1381
+ }
1382
+ }
1383
+
1305
1384
  /**
1306
1385
  * GATE R12: 代码字面尺寸与 measure_pack.json 实测值偏差超阈值。
1307
1386
  *
@@ -1561,6 +1640,7 @@ function main() {
1561
1640
  checkAndroidImmersive(scans, androidDir);
1562
1641
  }
1563
1642
  checkEntryRoute(scans, etsDir);
1643
+ checkOrphanComponents(scans);
1564
1644
 
1565
1645
  // GATE R12: 代码字面尺寸与 measure_pack 实测偏差超阈值。
1566
1646
  // --ui-info 显式指定 ui_info_root;不给时按 SKILL.md 的默认位置
@@ -58,6 +58,8 @@ The pipeline's sub-agents resolve each setting from the **OS environment variabl
58
58
 
59
59
  For each value, if the env var is unset, **ask the user**: for the DevEco path / model api_key, **ask the user** (for the api_key they may instead pass `skip_test=true`). Suggest setting the corresponding machine environment variable directly (`DEVECO_SDK_HOME` / `HOMETRANS_MODEL_API_KEY` / `HOMETRANS_TOOL_PATH`).
60
60
 
61
+ **External skill dependency.** Stage 2, 3b, and 4b delegate the signed build to the `a2h-fix-build-errors` skill, which is **not bundled in this plugin edition** — it ships with the broader HomeTrans distribution. Verify it is available in the same upfront pass; if it is not, stop and tell the user rather than substituting a guessed `hvigor` invocation. Every build gate in this pipeline (and the `AUTHORITATIVE_ENTRY` / `CURRENT_HAP` handoffs that depend on it) assumes a real signed build actually ran.
62
+
61
63
  ---
62
64
 
63
65
  ## Progress Tracking
@@ -163,10 +165,10 @@ For the Stage 4 loop, combine test and fix results into one row per round plus o
163
165
  Several stages below need the **full signed package set** — the entry HAP plus any in-app HSPs (and any feature HAP the build freshly produced) — so the self-tester installs them in one `hdc install -r` transaction (in-app HSPs cannot install standalone). Those stages call this procedure.
164
166
 
165
167
  **Inputs:**
166
- - `BUILD_ROOT` — the project root rebuilt by `hmos-fix-build-errors` (= `HMOS`).
168
+ - `BUILD_ROOT` — the project root rebuilt by `a2h-fix-build-errors` (= `HMOS`).
167
169
  - `DEST` — a dedicated `package-set/` directory to populate; **must never be the directory where you mirror the authoritative entry HAP** (step 1 clears `DEST`).
168
170
  - `BUILD_START` — a marker captured **immediately before** invoking the build stage, e.g. `touch "<DEST>/../.build_start_marker"` (or record a timestamp). Used to tell freshly-rebuilt artifacts from stale ones. A touched marker + `find -newer` avoids clock-skew between the build stage and the host.
169
- - `AUTHORITATIVE_ENTRY` — the authoritative signed entry HAP resolved directly from `HMOS/entry/build/default/outputs/default/` after `hmos-fix-build-errors` succeeds. Once resolved for the stage, treat it as authoritative regardless of mtime.
171
+ - `AUTHORITATIVE_ENTRY` — the authoritative signed entry HAP resolved directly from `HMOS/entry/build/default/outputs/default/` after `a2h-fix-build-errors` succeeds. Once resolved for the stage, treat it as authoritative regardless of mtime.
170
172
 
171
173
  **Procedure:**
172
174
  1. **Clear/create `DEST`** (remove prior contents, recreate) so stale packages never leak forward. `DEST` is a dedicated `package-set/` subdir, distinct from the location where you mirror the authoritative entry for this stage.
@@ -216,7 +218,7 @@ Prompt format (applies to both Stage 1 and Stage 1a): ONLY the key-value lines b
216
218
 
217
219
  ### Stage 2 — Compilation and Build
218
220
 
219
- 1. Invoke the `hmos-fix-build-errors` skill for a signed build of `HMOS`.
221
+ 1. Invoke the `a2h-fix-build-errors` skill for a signed build of `HMOS`.
220
222
  2. Capture `BUILD_START` just before invoking the skill.
221
223
  3. Treat the build stage as a compile/fix gate only — do **not** expect build-stage report or commit-info artifacts.
222
224
  4. After a successful build, resolve `AUTHORITATIVE_ENTRY` directly from `HMOS/entry/build/default/outputs/default/` (prefer `entry-default-signed.hap`, else the first `*-signed.hap`) and note it in the manifest.
@@ -267,7 +269,7 @@ For each `review_round` from `1..MAX_ROUNDS_REVIEW`, set `REVIEW_ROUND_DIR = OUT
267
269
  ##### Review Round Step B — Stage 3b Rebuild after Review Fix
268
270
 
269
271
  1. Mark Stage 3b `in_progress` when the first Stage 3b round begins.
270
- 2. Capture `BUILD_START` (touch a marker), then invoke the `hmos-fix-build-errors` skill for a signed rebuild of `HMOS`.
272
+ 2. Capture `BUILD_START` (touch a marker), then invoke the `a2h-fix-build-errors` skill for a signed rebuild of `HMOS`.
271
273
  3. Treat this as a compile/fix gate only — do **not** expect a rebuild report artifact in `REVIEW_ROUND_DIR`.
272
274
  4. If the build succeeds, resolve `AUTHORITATIVE_ENTRY` directly from `HMOS/entry/build/default/outputs/default/` (prefer `entry-default-signed.hap`, else the first `*-signed.hap`), note it in the manifest, and **then run Package-Set Collection** with `BUILD_ROOT = HMOS`, `DEST = REVIEW_ROUND_DIR/package-set/`, the resolved `AUTHORITATIVE_ENTRY`, and the captured `BUILD_START`; on success set `LAST_GOOD_REVIEW_SET = REVIEW_ROUND_DIR/package-set/`. **If the 3b build failed, do NOT run collection and keep the previous `LAST_GOOD_REVIEW_SET`** (a failed rebuild leaves stale sibling-module outputs on disk; the mtime gate already prevents harvesting them, and skipping collection avoids re-touching `LAST_GOOD_REVIEW_SET` with an entry-less set).
273
275
  5. Append one Defect Summary row for this round using the parsed Stage 3 stats, labeled `3 Loop - Round {review_round}`.
@@ -374,7 +376,7 @@ For each `round` from `1..MAX_ROUNDS_TEST`, set `ROUND_DIR = OUTPUT/round-{round
374
376
  ##### Round Step C — Stage 4b Rebuild after Self-Test Fix
375
377
 
376
378
  1. Mark Stage 4b `in_progress` when the first Stage 4b round begins.
377
- 2. Capture `BUILD_START` (touch a marker), then invoke the `hmos-fix-build-errors` skill for a signed rebuild of `HMOS`.
379
+ 2. Capture `BUILD_START` (touch a marker), then invoke the `a2h-fix-build-errors` skill for a signed rebuild of `HMOS`.
378
380
  3. Treat this as a compile/fix gate only — do **not** expect rebuild-stage report or commit-info artifacts in `ROUND_DIR`.
379
381
  4. ⚠️ **CRITICAL — Update `CURRENT_HAP` for the next round**: If the build succeeds, resolve `AUTHORITATIVE_ENTRY` directly from `HMOS/entry/build/default/outputs/default/` (prefer `entry-default-signed.hap`, else the first `*-signed.hap`), **run Package-Set Collection** with `BUILD_ROOT = HMOS`, `DEST = ROUND_DIR/package-set/`, that resolved `AUTHORITATIVE_ENTRY`, and the captured `BUILD_START`, and then set `CURRENT_HAP = ROUND_DIR/package-set/` so the next round's Stage 4 self-tester uses the freshly built set. If collection **fails** or yields zero HAPs, **keep the previous `CURRENT_HAP`** (the prior round's full set — fresher than any legacy single-file resolution) and record that this round produced no fresh package set.
380
382
  5. Append one Defect Summary row for this round by combining the parsed Stage 4 and Stage 4a results into a single row labeled `4 Loop - Round {round}`.
@@ -1,4 +1,4 @@
1
- # hmos-ui-align
1
+ # hmos-incremental-ui-align
2
2
 
3
3
  HarmonyOS-Android UI 自动对齐流水线。
4
4
 
@@ -73,7 +73,7 @@ HarmonyOS-Android UI 自动对齐流水线。
73
73
  在 Claude Code 里直接调用 skill,**把两个工程目录附在需求里**(可作为命名参数,也可在自然语言里说明):
74
74
 
75
75
  ```
76
- /hmos-ui-align android_project_dir: <安卓工程绝对路径> harmony_project_dir: <鸿蒙工程绝对路径>
76
+ /hmos-incremental-ui-align android_project_dir: <安卓工程绝对路径> harmony_project_dir: <鸿蒙工程绝对路径>
77
77
  <自然语言需求,描述要对齐的页面+点击路径>
78
78
  ```
79
79
 
@@ -92,20 +92,20 @@ HarmonyOS-Android UI 自动对齐流水线。
92
92
 
93
93
  **例 1(单个弹窗对齐)**
94
94
  ```
95
- /hmos-ui-align 鸿蒙版本app(登录状态下,进入首页-点击"AI智能填报"-点击"专业"筛选按钮)
95
+ /hmos-incremental-ui-align 鸿蒙版本app(登录状态下,进入首页-点击"AI智能填报"-点击"专业"筛选按钮)
96
96
  得到的弹窗样式和安卓同样路径得到的页面不一致,请修改鸿蒙源码将上述页面与安卓版本完全对齐
97
97
  ```
98
98
 
99
99
  **例 2(补齐缺失页面 + 调真实后台)**
100
100
  ```
101
- /hmos-ui-align 鸿蒙版本app(点击我的-超级会员组件)显示与安卓不一致,且安卓版本在超级会员
101
+ /hmos-incremental-ui-align 鸿蒙版本app(点击我的-超级会员组件)显示与安卓不一致,且安卓版本在超级会员
102
102
  上点击"会员中心"会跳到超级会员弹窗页,鸿蒙也没有这页。请修改鸿蒙源码将这些页面与安卓版本
103
103
  完全对齐,不要mock数据,调用真实后台数据
104
104
  ```
105
105
 
106
106
  **例 3(多级路径 + 多个页面)**
107
107
  ```
108
- /hmos-ui-align 鸿蒙版本(点击底部高考按钮 -> 带年纪查专业 -> 点击某一具体专业(如临床医学)
108
+ /hmos-incremental-ui-align 鸿蒙版本(点击底部高考按钮 -> 带年纪查专业 -> 点击某一具体专业(如临床医学)
109
109
  -> 点击就业分析,到达"专业就业健康度"展示页面)以及在"专业就业健康度"页面上点击"完整数
110
110
  据指标"到达的就业健康度详情页都和安卓同一路径的不一致。比较这些页面的差别并将他们在视觉
111
111
  效果上完全对齐,不要用mock数据,调用后台真实逻辑
@@ -164,7 +164,7 @@ skill 会严格按 `SKILL.md` 里的流水线跑:
164
164
  - 每个尺寸 / icon / alignment 都要回溯到安卓源码的 XML 或资源值,不允许"看起来差不多"
165
165
 
166
166
  ### Step 4 · 编译校验
167
- 若可用,调 `hmos-fix-build-errors` skill 确保工程能编过。**不会自动部署**。
167
+ 若可用,调 `a2h-fix-build-errors` skill 确保工程能编过。**不会自动部署**。
168
168
 
169
169
  ---
170
170
 
@@ -230,7 +230,7 @@ A: 可以。Step 2.2 会改从鸿蒙源码读,Step 3 会按安卓的实现规
230
230
  A: Step 1.3 默认扫描交互元素(tab / 弹窗 / 展开收起等)并递归采集。想关掉请在需求里写「只对齐主页面」。
231
231
 
232
232
  **Q: 改完会自动部署吗?**
233
- A: 不会。Step 4 只跑编译验证(如果 `hmos-fix-build-errors` skill 可用)。部署自己来。
233
+ A: 不会。Step 4 只跑编译验证(如果 `a2h-fix-build-errors` skill 可用)。部署自己来。
234
234
 
235
235
  **Q: 能不能只做差异分析、不改码?**
236
236
  A: 目前流水线是端到端的。如果只想要分析产物,跑完 Step 2 后手动中断即可,所有 `UI_Analysis.md` 和 `UI_comparison.md` 都会落盘在 `{capture_output_dir}/task_{timestamp}/` 下。
@@ -351,7 +351,7 @@ Read `fix_checklist.md` and verify every item is marked `[x]`. If any items rema
351
351
  **Coverage re-check**: For each page, the `<!-- source: ... | items=N -->` comment records how many items the script extracted. Confirm the number of `- [x]`/`- [~]` lines under each page heading still matches that `items=N` count — if fewer, items were silently dropped during the review pass; recover them from the page's `UI_comparison.md`.
352
352
 
353
353
  ## Step 4 validate and build (Main Agent)
354
- if available, use `hmos-fix-build-errors` skill to verify the project is compilable, do not deploy.
354
+ if available, use `a2h-fix-build-errors` skill to verify the project is compilable, do not deploy.
355
355
 
356
356
  ## Guidelines
357
357
  - **Preserve existing code**: When editing existing files, make targeted edits — never rewrite an entire file from scratch. Respect the existing code structure, variable names, and patterns.
@@ -28,7 +28,7 @@ Based on the diff analysis, flexibly combine editing and creation as needed —
28
28
 
29
29
  **Resource Conversion:**
30
30
  - For each resource referenced by the Android UI, find the corresponding mapping in `{harmony_project_dir}/entry/src/main/resources`
31
- - If a needed resource does not exist, use the **`hmos-resources-convert`** skill to convert it
31
+ - If a needed resource does not exist, use the **`a2h-resource-convert`** skill to convert it
32
32
 
33
33
  **Layout Conversion:**
34
34
  - Consult `./references/android-to-harmonyOS-ui-layout-mapping-reference.md` for all layout container mappings and layout attribute mappings
@@ -36,7 +36,7 @@ You are a **Spec Generator** that produces high-quality requirement specificatio
36
36
 
37
37
  ## Expected Output
38
38
 
39
- - One markdown spec file per requirement split out of `requirement_description_file`, written under `spec_output_dir` as **`<feature>-SPEC.md`**, where `<feature>` is the requirement title. The `-SPEC.md` suffix is required by the downstream `hmos-test-case-generation` skill, which only accepts a `spec-path` ending in it.
39
+ - One markdown spec file per requirement split out of `requirement_description_file`, written under `spec_output_dir` as **`<feature>-SPEC.md`**, where `<feature>` is the requirement title. The `-SPEC.md` suffix is required by the downstream `a2h-test-case-generation` skill, which only accepts a `spec-path` ending in it.
40
40
 
41
41
  ---
42
42
 
@@ -365,7 +365,7 @@ These are the authoring rules the final spec MUST follow:
365
365
  ### Step 0 — Validate inputs and split requirements
366
366
 
367
367
  1. Verify `requirement_description_file` exists and is a readable file, then split its content into individual requirements by input type. Keep each requirement's text verbatim and record them in order; do NOT analyze them yet. If no requirement can be extracted, stop and report the error.
368
- - **Excel type (`.xlsx` / `.xlsm` / `.csv`)**: run `node <skill-dir>/scripts/parse_requirements.ts --input <requirement_description_file> --json` via `Bash` to read the file content. Each item of the returned JSON array is one raw requirement: `uiPath` is the title, `description` is the requirement body. If the script errors, surface it verbatim and stop.
368
+ - **Excel type (`.xlsx` / `.xlsm` / `.csv`)**: run `node <skill-dir>/scripts/parse_requirements.mjs --input <requirement_description_file> --json` via `Bash` to read the file content. Each item of the returned JSON array is one raw requirement: `uiPath` is the title, `description` is the requirement body. If the script errors, surface it verbatim and stop.
369
369
  - **Text type (`.txt` / `.md`)**: read the content directly and split it into individual requirements (each requirement starts with a title line followed by its description; requirements are separated by blank lines).
370
370
  2. Verify `android_project_dir` exists and is a directory.
371
371
  3. Ensure `spec_output_dir` exists (create it if it does not).