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,811 @@
1
+ import { mkdir, stat, writeFile } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { buildNameTraceEntries } from "../analysis/names/index.js";
4
+ import {
5
+ ensureOutputDirectoryEmpty,
6
+ OutputDirectoryNotEmptyError,
7
+ } from "../core/output-guard.js";
8
+ import { renderReqDraft } from "../generation/index.js";
9
+ import {
10
+ GenerationError,
11
+ filterRenderableAreas,
12
+ loadStage2AreaGraph,
13
+ loadStage2GapAudit,
14
+ loadStage2InputWithReport,
15
+ sortAreasReachableFirst,
16
+ } from "../stage2-input.js";
17
+ import { loadStage2NameTraceabilityInput } from "../stage2-name-trace-input.js";
18
+ import {
19
+ createClaudeBackend,
20
+ createCommandBackend,
21
+ createOpencodeBackend,
22
+ } from "./backend.js";
23
+ import { linkGapAuditToReqModel } from "./gap-audit-link.js";
24
+ import {
25
+ mergeAreaReqMarkdown,
26
+ mergeAreaReqTxt,
27
+ mergeReqMarkdown,
28
+ mergeReqTxt,
29
+ } from "./merge.js";
30
+ import { buildNameTraceLookup } from "./name-trace.js";
31
+ import {
32
+ defaultCheckScriptPath,
33
+ expandAreaRenderItems,
34
+ expandRenderItems,
35
+ prepareAreaInputs,
36
+ prepareFeatureInputs,
37
+ renderAllAreas,
38
+ renderAllAreasUnified,
39
+ renderAllFeatures,
40
+ renderAllFeaturesUnified,
41
+ writeRenderList,
42
+ } from "./orchestrate.js";
43
+ // overviewQuoteCheck is kept in overview.ts for programmatic use by other modules
44
+ import { runPostMergeAudit } from "./post-merge-fix.js";
45
+ import { exportSpecHandoff } from "../spec-handoff.js";
46
+ import {
47
+ snapshotAreaReq,
48
+ snapshotAreaReqTxt,
49
+ snapshotReq,
50
+ snapshotReqTxt,
51
+ writeReqTxtFiles,
52
+ } from "./snapshot.js";
53
+ class AgentUsageError extends Error {}
54
+ function parseMode(value) {
55
+ if (value === undefined) return "subagent";
56
+ if (value === "subagent" || value === "shell" || value === "shell-legacy")
57
+ return value;
58
+ throw new AgentUsageError(
59
+ `--mode must be "subagent", "shell", or "shell-legacy", got ${value}`,
60
+ );
61
+ }
62
+ const agentValueOptions = new Set([
63
+ "input",
64
+ "output",
65
+ "resume",
66
+ "mode",
67
+ "project-root",
68
+ "backend",
69
+ "agent-name",
70
+ "ai-command",
71
+ "spec-output",
72
+ "concurrency",
73
+ "max-retries",
74
+ "backoff-ms",
75
+ ]);
76
+ function takeValue(args, index, name, inline) {
77
+ const value = inline ?? args[index + 1];
78
+ if (
79
+ value === undefined ||
80
+ value.trim().length === 0 ||
81
+ (inline === undefined && value.startsWith("--"))
82
+ ) {
83
+ throw new AgentUsageError(`Option requires a value: --${name}`);
84
+ }
85
+ return value;
86
+ }
87
+ function positiveInteger(value, name) {
88
+ const result = Number(value);
89
+ if (!Number.isSafeInteger(result) || result <= 0) {
90
+ throw new AgentUsageError(
91
+ `--${name} must be a positive integer, got ${value}`,
92
+ );
93
+ }
94
+ return result;
95
+ }
96
+ export function parseAgentArguments(args) {
97
+ const normalized = args[0] === "--" ? args.slice(1) : args;
98
+ const values = new Map();
99
+ let snapshot = false;
100
+ let perFeature = false;
101
+ let withUnreachableArea = false;
102
+ let noAuditFix = false;
103
+ for (let index = 0; index < normalized.length; index += 1) {
104
+ const token = normalized[index];
105
+ if (token === "--snapshot") {
106
+ if (snapshot)
107
+ throw new AgentUsageError("--snapshot may be provided once");
108
+ snapshot = true;
109
+ continue;
110
+ }
111
+ if (token === "--per-feature") {
112
+ if (perFeature)
113
+ throw new AgentUsageError("--per-feature may be provided once");
114
+ perFeature = true;
115
+ continue;
116
+ }
117
+ if (token === "--with-unreachable-area") {
118
+ if (withUnreachableArea) {
119
+ throw new AgentUsageError(
120
+ "--with-unreachable-area may be provided once",
121
+ );
122
+ }
123
+ withUnreachableArea = true;
124
+ continue;
125
+ }
126
+ if (token === "--no-audit-fix") {
127
+ if (noAuditFix)
128
+ throw new AgentUsageError("--no-audit-fix may be provided once");
129
+ noAuditFix = true;
130
+ continue;
131
+ }
132
+ if (!token.startsWith("--")) {
133
+ throw new AgentUsageError(`Unexpected argument: ${token}`);
134
+ }
135
+ const separator = token.indexOf("=");
136
+ const name = token.slice(2, separator === -1 ? undefined : separator);
137
+ if (!agentValueOptions.has(name)) {
138
+ throw new AgentUsageError(`Unknown option: --${name}`);
139
+ }
140
+ if (values.has(name)) {
141
+ throw new AgentUsageError(`Option may be provided once: --${name}`);
142
+ }
143
+ const inline = separator === -1 ? undefined : token.slice(separator + 1);
144
+ values.set(name, takeValue(normalized, index, name, inline));
145
+ if (inline === undefined) index += 1;
146
+ }
147
+ const input = values.get("input");
148
+ if (input === undefined) {
149
+ throw new AgentUsageError("Missing required option: --input");
150
+ }
151
+ const inputDirectory = resolve(input);
152
+ const mode = parseMode(values.get("mode"));
153
+ const resume = values.has("resume");
154
+ if (resume && values.has("output")) {
155
+ throw new AgentUsageError("--resume cannot be combined with --output");
156
+ }
157
+ if (resume && mode !== "shell") {
158
+ throw new AgentUsageError("--resume requires --mode shell");
159
+ }
160
+ if (resume && snapshot) {
161
+ throw new AgentUsageError("--resume cannot be combined with --snapshot");
162
+ }
163
+ const outputExplicit = values.has("output");
164
+ return {
165
+ inputDirectory,
166
+ outputDirectory: resume
167
+ ? resolve(values.get("resume"))
168
+ : outputExplicit
169
+ ? resolve(values.get("output"))
170
+ : join(inputDirectory, "generation"),
171
+ projectRoot: values.has("project-root")
172
+ ? resolve(values.get("project-root"))
173
+ : undefined,
174
+ mode,
175
+ backendName: values.get("backend") ?? "claude",
176
+ agentName: values.get("agent-name") ?? "reqgen-renderer",
177
+ aiCommand: values.get("ai-command"),
178
+ specOutputDirectory: values.has("spec-output")
179
+ ? resolve(values.get("spec-output"))
180
+ : undefined,
181
+ concurrency: values.has("concurrency")
182
+ ? positiveInteger(values.get("concurrency"), "concurrency")
183
+ : 8,
184
+ maxRetries: values.has("max-retries")
185
+ ? positiveInteger(values.get("max-retries"), "max-retries")
186
+ : 5,
187
+ backoffMs: values.has("backoff-ms")
188
+ ? positiveInteger(values.get("backoff-ms"), "backoff-ms")
189
+ : 5000,
190
+ snapshot,
191
+ perFeature,
192
+ withUnreachableArea,
193
+ noAuditFix,
194
+ outputExplicit,
195
+ resume,
196
+ };
197
+ }
198
+ function buildBackend(options) {
199
+ if (options.aiCommand !== undefined) {
200
+ return createCommandBackend(options.aiCommand);
201
+ }
202
+ if (options.backendName === "claude") {
203
+ return createClaudeBackend({ legacy: options.mode === "shell-legacy" });
204
+ }
205
+ if (options.backendName === "opencode") {
206
+ return createOpencodeBackend();
207
+ }
208
+ throw new AgentUsageError(
209
+ `Unknown backend: ${options.backendName} (use --ai-command for custom backends)`,
210
+ );
211
+ }
212
+ function summary(status, options, totalAreas, totalFeatures, aiRendered) {
213
+ return JSON.stringify(
214
+ {
215
+ status,
216
+ output: options.outputDirectory,
217
+ renderDir: join(options.outputDirectory, "rendering"),
218
+ totalAreas,
219
+ totalFeatures,
220
+ aiRendered,
221
+ fallback: totalFeatures - aiRendered,
222
+ },
223
+ null,
224
+ 2,
225
+ );
226
+ }
227
+ function aiRenderedCountArea(results) {
228
+ let aiRendered = 0;
229
+ for (const areaResult of results.values()) {
230
+ if (areaResult.status !== "ok") continue;
231
+ for (const featureResult of areaResult.features.values()) {
232
+ if (featureResult.status === "ok" && featureResult.body !== undefined) {
233
+ aiRendered += 1;
234
+ }
235
+ }
236
+ }
237
+ return aiRendered;
238
+ }
239
+ function aiRenderedCountFeature(results) {
240
+ let aiRendered = 0;
241
+ for (const result of results.values()) {
242
+ if (result.status === "ok" && result.body !== undefined) aiRendered += 1;
243
+ }
244
+ return aiRendered;
245
+ }
246
+ /** Recomputed via renderReqDraft (Stage 1's deterministic layer, unchanged)
247
+ * rather than reading generation/req.md off disk — the merge template
248
+ * is then always hash-verified against this run's req-model/area-graph
249
+ * instead of trusting a plain text file that could be stale or hand-edited.
250
+ * The Agent-rendered output still overwrites req.md in the end. */
251
+ async function loadTemplate(inputDirectory, report, fullReqModel) {
252
+ const graph = await loadStage2AreaGraph(inputDirectory, report, fullReqModel);
253
+ return renderReqDraft(fullReqModel, graph);
254
+ }
255
+ // runPostMergeAudit is in post-merge-fix.ts
256
+ async function runSnapshot(options, io) {
257
+ const { reqModel: loadedReqModel, report } = await loadStage2InputWithReport(
258
+ options.inputDirectory,
259
+ );
260
+ const sortedReqModel = sortAreasReachableFirst(loadedReqModel);
261
+ const reqModel = filterRenderableAreas(sortedReqModel);
262
+ const renderDir = join(options.outputDirectory, "rendering");
263
+ // Always produce both formats: req.md (markdown) + req-{idx}.txt (plain text).
264
+ const templateText = await loadTemplate(
265
+ options.inputDirectory,
266
+ report,
267
+ reqModel,
268
+ );
269
+ const graph = await loadStage2AreaGraph(
270
+ options.inputDirectory,
271
+ report,
272
+ reqModel,
273
+ );
274
+ if (options.perFeature) {
275
+ const mergeOptions = {
276
+ includeUnreachableAreas: options.withUnreachableArea,
277
+ };
278
+ const mdResult = await snapshotReq(
279
+ reqModel,
280
+ reqModel,
281
+ renderDir,
282
+ options.outputDirectory,
283
+ templateText,
284
+ mergeOptions,
285
+ );
286
+ const txtResult = await snapshotReqTxt(
287
+ reqModel,
288
+ reqModel,
289
+ graph,
290
+ renderDir,
291
+ options.outputDirectory,
292
+ mergeOptions,
293
+ );
294
+ io.stdout(
295
+ JSON.stringify(
296
+ {
297
+ status: "ok",
298
+ md: mdResult,
299
+ txt: txtResult,
300
+ },
301
+ null,
302
+ 2,
303
+ ) + "\n",
304
+ );
305
+ } else {
306
+ const mergeOptions = {
307
+ includeUnreachableAreas: options.withUnreachableArea,
308
+ };
309
+ const mdResult = await snapshotAreaReq(
310
+ reqModel,
311
+ reqModel,
312
+ renderDir,
313
+ options.outputDirectory,
314
+ templateText,
315
+ mergeOptions,
316
+ );
317
+ const txtResult = await snapshotAreaReqTxt(
318
+ reqModel,
319
+ reqModel,
320
+ graph,
321
+ renderDir,
322
+ options.outputDirectory,
323
+ mergeOptions,
324
+ );
325
+ io.stdout(
326
+ JSON.stringify(
327
+ {
328
+ status: "ok",
329
+ md: mdResult,
330
+ txt: txtResult,
331
+ },
332
+ null,
333
+ 2,
334
+ ) + "\n",
335
+ );
336
+ }
337
+ await runRequestedSpecHandoff(options, io);
338
+ return 0;
339
+ }
340
+ /** Export only when the caller explicitly asks for it. Keeping this opt-in
341
+ * preserves the existing Stage 2 output layout while allowing a single
342
+ * Stage 2 invocation to hand its result directly to `$a2h-spec-generate`. */
343
+ async function runRequestedSpecHandoff(options, io) {
344
+ if (options.specOutputDirectory === undefined) return;
345
+ const result = await exportSpecHandoff({
346
+ inputDirectory: options.inputDirectory,
347
+ stage2Directory: options.outputDirectory,
348
+ outputDirectory: options.specOutputDirectory,
349
+ mode: options.perFeature ? "feature" : "area",
350
+ includeUnreachableAreas: options.withUnreachableArea,
351
+ // The Stage 2 output directory is an explicitly selected generated path;
352
+ // refreshing its handoff is safe and avoids stale page batches on resume.
353
+ replace: true,
354
+ });
355
+ io.stdout(
356
+ `${JSON.stringify(
357
+ {
358
+ status: "spec-handoff",
359
+ outputDirectory: result.outputDirectory,
360
+ manifestPath: result.manifestPath,
361
+ batches: result.manifest.batches.length,
362
+ requirements: result.manifest.batches.reduce(
363
+ (sum, batch) => sum + batch.requirementCount,
364
+ 0,
365
+ ),
366
+ warnings: result.manifest.warnings,
367
+ },
368
+ null,
369
+ 2,
370
+ )}\n`,
371
+ );
372
+ }
373
+ async function loadGapAuditLinks(inputDirectory, report, fullReqModel) {
374
+ const gapAudit = await loadStage2GapAudit(
375
+ inputDirectory,
376
+ report,
377
+ fullReqModel,
378
+ );
379
+ return linkGapAuditToReqModel(fullReqModel, gapAudit);
380
+ }
381
+ /** Absent when the Stage 1 run predates source-facts.json/area-graph.json;
382
+ * the Agent then degrades to blind exploration for everyone. */
383
+ async function loadNameTrace(inputDirectory, reqModel) {
384
+ const input = await loadStage2NameTraceabilityInput(inputDirectory, reqModel);
385
+ if (input === undefined) return undefined;
386
+ return buildNameTraceLookup(buildNameTraceEntries({ ...input, reqModel }));
387
+ }
388
+ /** `reqModel` (post-filterRenderableAreas) decides what gets sent to the
389
+ * Agent; `fullReqModel` must be the same, unfiltered req-model templateText
390
+ * was rendered from, so the merge walk's Area/Feature positions line up with
391
+ * the template text — filtering some Areas out of rendering must not desync
392
+ * it from the template it is walking. */
393
+ async function runRenderPerFeature(
394
+ reqModel,
395
+ fullReqModel,
396
+ options,
397
+ io,
398
+ templateText,
399
+ graph,
400
+ nameTrace,
401
+ gapAuditLinks,
402
+ backend,
403
+ renderDir,
404
+ analysisMode,
405
+ unified,
406
+ ) {
407
+ const items = expandRenderItems(reqModel);
408
+ const totalAreas = reqModel.areas.length;
409
+ const totalFeatures = items.length;
410
+ const results = new Map();
411
+ let interrupted = false;
412
+ process.once("SIGINT", () => {
413
+ interrupted = true;
414
+ io.stdout(
415
+ summary(
416
+ "interrupted",
417
+ options,
418
+ totalAreas,
419
+ totalFeatures,
420
+ aiRenderedCountFeature(results),
421
+ ) + "\n",
422
+ );
423
+ process.exit(0);
424
+ });
425
+ const agentOpts = {
426
+ backend,
427
+ projectRoot: options.projectRoot,
428
+ inputDirectory: options.inputDirectory,
429
+ outputDirectory: options.outputDirectory,
430
+ analysisMode,
431
+ launchMode: options.mode,
432
+ renderDir,
433
+ agentName: options.agentName,
434
+ concurrency: options.concurrency,
435
+ maxRetries: options.maxRetries,
436
+ backoffMs: options.backoffMs,
437
+ nameTrace,
438
+ gapAuditLinks,
439
+ noAuditFix: options.noAuditFix,
440
+ resume: options.resume,
441
+ };
442
+ const rendered = unified
443
+ ? await renderAllFeaturesUnified(items, reqModel, agentOpts)
444
+ : await renderAllFeatures(items, reqModel, agentOpts);
445
+ for (const [id, result] of rendered) results.set(id, result);
446
+ if (!interrupted) {
447
+ // Always write both formats: req.md (markdown) + req-{idx}.txt (plain text).
448
+ const mergeOptions = {
449
+ includeUnreachableAreas: options.withUnreachableArea,
450
+ };
451
+ const mdText = mergeReqMarkdown(
452
+ fullReqModel,
453
+ reqModel,
454
+ results,
455
+ templateText,
456
+ mergeOptions,
457
+ );
458
+ const txtAreas = mergeReqTxt(
459
+ fullReqModel,
460
+ reqModel,
461
+ results,
462
+ graph,
463
+ mergeOptions,
464
+ );
465
+ await writeFile(join(options.outputDirectory, "req.md"), mdText, "utf8");
466
+ await writeReqTxtFiles(options.outputDirectory, txtAreas);
467
+ // Post-merge audit + optional fix agent (shell / shell-legacy modes)
468
+ if (!options.noAuditFix) {
469
+ await runPostMergeAudit(
470
+ join(options.outputDirectory, "req.md"),
471
+ options.inputDirectory,
472
+ options.outputDirectory,
473
+ options.mode,
474
+ io,
475
+ );
476
+ }
477
+ await runRequestedSpecHandoff(options, io);
478
+ io.stdout(
479
+ summary(
480
+ "ok",
481
+ options,
482
+ totalAreas,
483
+ totalFeatures,
484
+ aiRenderedCountFeature(results),
485
+ ) + "\n",
486
+ );
487
+ }
488
+ }
489
+ /** See runRenderPerFeature for why both a renderable and a full req-model
490
+ * are needed. */
491
+ async function runRenderPerArea(
492
+ reqModel,
493
+ fullReqModel,
494
+ options,
495
+ io,
496
+ templateText,
497
+ graph,
498
+ nameTrace,
499
+ gapAuditLinks,
500
+ backend,
501
+ renderDir,
502
+ analysisMode,
503
+ unified,
504
+ ) {
505
+ const items = expandAreaRenderItems(reqModel);
506
+ const totalAreas = reqModel.areas.length;
507
+ const totalFeatures = items.reduce(
508
+ (sum, item) => sum + item.area.features.length,
509
+ 0,
510
+ );
511
+ const results = new Map();
512
+ let interrupted = false;
513
+ process.once("SIGINT", () => {
514
+ interrupted = true;
515
+ io.stdout(
516
+ summary(
517
+ "interrupted",
518
+ options,
519
+ totalAreas,
520
+ totalFeatures,
521
+ aiRenderedCountArea(results),
522
+ ) + "\n",
523
+ );
524
+ process.exit(0);
525
+ });
526
+ const agentOpts = {
527
+ backend,
528
+ projectRoot: options.projectRoot,
529
+ inputDirectory: options.inputDirectory,
530
+ outputDirectory: options.outputDirectory,
531
+ analysisMode,
532
+ launchMode: options.mode,
533
+ renderDir,
534
+ agentName: options.agentName,
535
+ concurrency: options.concurrency,
536
+ maxRetries: options.maxRetries,
537
+ backoffMs: options.backoffMs,
538
+ nameTrace,
539
+ gapAuditLinks,
540
+ noAuditFix: options.noAuditFix,
541
+ resume: options.resume,
542
+ };
543
+ const rendered = unified
544
+ ? await renderAllAreasUnified(items, reqModel, agentOpts)
545
+ : await renderAllAreas(items, reqModel, agentOpts);
546
+ for (const [id, result] of rendered) results.set(id, result);
547
+ if (!interrupted) {
548
+ // Always write both formats: req.md (markdown) + req-{idx}.txt (plain text).
549
+ const mergeOptions = {
550
+ includeUnreachableAreas: options.withUnreachableArea,
551
+ };
552
+ await writeFile(
553
+ join(options.outputDirectory, "req.md"),
554
+ mergeAreaReqMarkdown(
555
+ fullReqModel,
556
+ reqModel,
557
+ results,
558
+ templateText,
559
+ mergeOptions,
560
+ ),
561
+ "utf8",
562
+ );
563
+ const txtAreas = mergeAreaReqTxt(
564
+ fullReqModel,
565
+ reqModel,
566
+ results,
567
+ graph,
568
+ mergeOptions,
569
+ );
570
+ await writeReqTxtFiles(options.outputDirectory, txtAreas);
571
+ // Post-merge audit + optional fix agent (shell / shell-legacy modes)
572
+ if (!options.noAuditFix) {
573
+ await runPostMergeAudit(
574
+ join(options.outputDirectory, "req.md"),
575
+ options.inputDirectory,
576
+ options.outputDirectory,
577
+ options.mode,
578
+ io,
579
+ );
580
+ }
581
+ await runRequestedSpecHandoff(options, io);
582
+ io.stdout(
583
+ summary(
584
+ "ok",
585
+ options,
586
+ totalAreas,
587
+ totalFeatures,
588
+ aiRenderedCountArea(results),
589
+ ) + "\n",
590
+ );
591
+ }
592
+ }
593
+ function prepareSummary(
594
+ options,
595
+ checkScriptPath,
596
+ totalAreas,
597
+ entries,
598
+ renderList,
599
+ ) {
600
+ return JSON.stringify(
601
+ {
602
+ status: "ok",
603
+ mode: "subagent",
604
+ output: options.outputDirectory,
605
+ renderDir: join(options.outputDirectory, "rendering"),
606
+ checkScript: checkScriptPath,
607
+ renderList: renderList.listPath,
608
+ renderManifest: renderList.manifestPath,
609
+ totalAreas,
610
+ total: entries.length,
611
+ done: renderList.done,
612
+ pending: renderList.pending,
613
+ entries,
614
+ },
615
+ null,
616
+ 2,
617
+ );
618
+ }
619
+ /** ADR-0005: writes task.md + expected.json for every renderable unit, plus
620
+ * render-list.md/render-manifest.json (see writeRenderList) — never spawns a
621
+ * backend. Turning each manifest entry into an output.json is the job of a
622
+ * subagent, dispatched by the main Agent running a2h-app-req-gen (see
623
+ * references/subagent-render.md), not this CLI process. Idempotent and safe
624
+ * to rerun anytime, including to resume an interrupted batch: it never
625
+ * touches draft.json/output.json, and always recomputes render-list.md from
626
+ * whichever output.json files already exist on disk. */
627
+ async function runPrepare(options, io) {
628
+ if (options.specOutputDirectory !== undefined) {
629
+ throw new AgentUsageError(
630
+ "--spec-output requires finalized Stage 2 output; omit it during subagent preparation " +
631
+ "and pass it to the later --snapshot invocation",
632
+ );
633
+ }
634
+ if (options.projectRoot === undefined) {
635
+ throw new AgentUsageError(
636
+ "--mode subagent requires --project-root <android-project> " +
637
+ "(the subagent's read-only exploration boundary)",
638
+ );
639
+ }
640
+ const { reqModel: loadedReqModel, report } = await loadStage2InputWithReport(
641
+ options.inputDirectory,
642
+ );
643
+ const sortedReqModel = sortAreasReachableFirst(loadedReqModel);
644
+ const reqModel = filterRenderableAreas(sortedReqModel);
645
+ const nameTrace = await loadNameTrace(options.inputDirectory, reqModel);
646
+ const gapAuditLinks = await loadGapAuditLinks(
647
+ options.inputDirectory,
648
+ report,
649
+ sortedReqModel,
650
+ );
651
+ const renderDir = join(options.outputDirectory, "rendering");
652
+ const analysisMode = report.semanticCompleteness ?? "unknown";
653
+ const prepareOpts = {
654
+ projectRoot: options.projectRoot,
655
+ analysisMode,
656
+ renderDir,
657
+ gapAuditLinks,
658
+ nameTrace,
659
+ };
660
+ const entries = options.perFeature
661
+ ? await prepareFeatureInputs(
662
+ expandRenderItems(reqModel),
663
+ reqModel,
664
+ prepareOpts,
665
+ )
666
+ : await prepareAreaInputs(
667
+ expandAreaRenderItems(reqModel),
668
+ reqModel,
669
+ prepareOpts,
670
+ );
671
+ const checkScriptPath = defaultCheckScriptPath();
672
+ const renderList = await writeRenderList(
673
+ options.outputDirectory,
674
+ checkScriptPath,
675
+ entries,
676
+ );
677
+ io.stdout(
678
+ prepareSummary(
679
+ options,
680
+ checkScriptPath,
681
+ reqModel.areas.length,
682
+ entries,
683
+ renderList,
684
+ ) + "\n",
685
+ );
686
+ return 0;
687
+ }
688
+ async function runRender(options, io) {
689
+ if (options.projectRoot === undefined) {
690
+ throw new AgentUsageError(
691
+ "--mode shell requires --project-root <android-project> " +
692
+ "(the Agent read-only exploration boundary)",
693
+ );
694
+ }
695
+ const { reqModel: loadedReqModel, report } = await loadStage2InputWithReport(
696
+ options.inputDirectory,
697
+ );
698
+ const sortedReqModel = sortAreasReachableFirst(loadedReqModel);
699
+ const reqModel = filterRenderableAreas(sortedReqModel);
700
+ const nameTrace = await loadNameTrace(options.inputDirectory, reqModel);
701
+ const gapAuditLinks = await loadGapAuditLinks(
702
+ options.inputDirectory,
703
+ report,
704
+ sortedReqModel,
705
+ );
706
+ const templateText = await loadTemplate(
707
+ options.inputDirectory,
708
+ report,
709
+ sortedReqModel,
710
+ );
711
+ // Load graph for both md-out (via loadTemplate above) and txt modes.
712
+ const graph = await loadStage2AreaGraph(
713
+ options.inputDirectory,
714
+ report,
715
+ sortedReqModel,
716
+ );
717
+ const backend = buildBackend(options);
718
+ const renderDir = join(options.outputDirectory, "rendering");
719
+ await mkdir(renderDir, { recursive: true });
720
+ const analysisMode = report.semanticCompleteness ?? "unknown";
721
+ // The unified task-file protocol is implemented by the Claude backend in
722
+ // ordinary shell mode. Custom commands and opencode still receive the
723
+ // inline prompt; passing them a task path silently produced invalid JSON in
724
+ // the old routing rule.
725
+ const unified =
726
+ options.mode === "shell" &&
727
+ options.aiCommand === undefined &&
728
+ options.backendName === "claude";
729
+ if (options.perFeature) {
730
+ await runRenderPerFeature(
731
+ reqModel,
732
+ sortedReqModel,
733
+ options,
734
+ io,
735
+ templateText,
736
+ graph,
737
+ nameTrace,
738
+ gapAuditLinks,
739
+ backend,
740
+ renderDir,
741
+ analysisMode,
742
+ unified,
743
+ );
744
+ } else {
745
+ await runRenderPerArea(
746
+ reqModel,
747
+ sortedReqModel,
748
+ options,
749
+ io,
750
+ templateText,
751
+ graph,
752
+ nameTrace,
753
+ gapAuditLinks,
754
+ backend,
755
+ renderDir,
756
+ analysisMode,
757
+ unified,
758
+ );
759
+ }
760
+ return 0;
761
+ }
762
+ export async function runAgentStage2(argv, io) {
763
+ let options;
764
+ try {
765
+ options = parseAgentArguments(argv);
766
+ } catch (error) {
767
+ io.stderr(`${error instanceof Error ? error.message : String(error)}\n`);
768
+ return 2;
769
+ }
770
+ try {
771
+ if (options.resume) {
772
+ let isDirectory = false;
773
+ try {
774
+ isDirectory = (await stat(options.outputDirectory)).isDirectory();
775
+ } catch {
776
+ // Report a usage error below rather than silently starting a new run.
777
+ }
778
+ if (!isDirectory) {
779
+ io.stderr(
780
+ `--resume directory does not exist: ${options.outputDirectory}\n`,
781
+ );
782
+ return 2;
783
+ }
784
+ }
785
+ // Guard: refuse to overwrite an existing output directory when the user
786
+ // explicitly set --output. Auto-generated default paths and --snapshot
787
+ // mode (which must read existing output.json) are exempt.
788
+ if (options.outputExplicit && !options.snapshot) {
789
+ try {
790
+ await ensureOutputDirectoryEmpty(options.outputDirectory);
791
+ } catch (error) {
792
+ if (error instanceof OutputDirectoryNotEmptyError) {
793
+ io.stderr(error.message + "\n");
794
+ return 2;
795
+ }
796
+ throw error;
797
+ }
798
+ }
799
+ if (options.snapshot) return await runSnapshot(options, io);
800
+ return options.mode === "shell" || options.mode === "shell-legacy"
801
+ ? await runRender(options, io)
802
+ : await runPrepare(options, io);
803
+ } catch (error) {
804
+ const details =
805
+ error instanceof GenerationError ? (error.details ?? []) : [];
806
+ io.stderr(
807
+ `Stage 2 (agent) failed: ${error instanceof Error ? error.message : String(error)}\n${details.map((detail) => `${detail}\n`).join("")}`,
808
+ );
809
+ return 1;
810
+ }
811
+ }