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,781 @@
1
+ function object(value) {
2
+ return value !== null && typeof value === "object" && !Array.isArray(value)
3
+ ? value
4
+ : undefined;
5
+ }
6
+ function text(record, key) {
7
+ const value = record.data[key];
8
+ return typeof value === "string" && value.trim().length > 0
9
+ ? value.trim()
10
+ : undefined;
11
+ }
12
+ function objectText(value, key) {
13
+ const item = value?.[key];
14
+ return typeof item === "string" && item.trim().length > 0
15
+ ? item.trim()
16
+ : undefined;
17
+ }
18
+ function number(record, key) {
19
+ const value = record.data[key];
20
+ return typeof value === "number" && Number.isFinite(value)
21
+ ? value
22
+ : undefined;
23
+ }
24
+ function expression(binding) {
25
+ return object(binding.data.expression);
26
+ }
27
+ function sourceKind(record) {
28
+ const language = text(record, "language");
29
+ if (language === "kotlin" || record.location?.path.endsWith(".kt")) {
30
+ return "kotlin";
31
+ }
32
+ if (language === "java" || record.location?.path.endsWith(".java")) {
33
+ return "java";
34
+ }
35
+ return "other";
36
+ }
37
+ function recordLocation(record, anchor, symbol) {
38
+ if (!record.location) return undefined;
39
+ return {
40
+ sourceKind: sourceKind(record),
41
+ path: record.location.path,
42
+ anchor,
43
+ range: {
44
+ startLine: Math.max(1, record.location.startLine),
45
+ endLine: Math.max(record.location.startLine, record.location.endLine),
46
+ ...(record.location.startColumn >= 1
47
+ ? { startColumn: record.location.startColumn }
48
+ : {}),
49
+ ...(record.location.endColumn >= 1
50
+ ? { endColumn: record.location.endColumn }
51
+ : {}),
52
+ },
53
+ ...(symbol ? { symbol } : {}),
54
+ };
55
+ }
56
+ function append(map, key, record) {
57
+ const values = map.get(key) ?? [];
58
+ values.push(record);
59
+ map.set(key, values);
60
+ }
61
+ function sourceApiName(record) {
62
+ return (text(record, "targetName") ?? "").replace(/-.*$/u, "");
63
+ }
64
+ function methodKey(owner, name) {
65
+ return `${owner}\u0000${name}`;
66
+ }
67
+ function buildIndex(jvm) {
68
+ const recordsById = new Map();
69
+ const calls = [];
70
+ const bindings = [];
71
+ const mutableBindingsByCall = new Map();
72
+ const callablesById = new Map();
73
+ const callableParent = new Map();
74
+ const methodsBySignature = new Map();
75
+ const mutableMethodsByOwnerAndName = new Map();
76
+ for (const record of jvm.body) {
77
+ recordsById.set(record.id, record);
78
+ if (record.kind === "resolved-call") calls.push(record);
79
+ if (record.kind === "call-argument-binding") {
80
+ bindings.push(record);
81
+ const callRef = text(record, "callRef");
82
+ if (callRef) append(mutableBindingsByCall, callRef, record);
83
+ }
84
+ if (
85
+ record.kind === "method-declaration" ||
86
+ record.kind === "lambda-declaration"
87
+ ) {
88
+ callablesById.set(record.id, record);
89
+ const parent = text(record, "enclosingCallableRef");
90
+ if (parent) callableParent.set(record.id, parent);
91
+ }
92
+ if (record.kind === "method-declaration") {
93
+ const signature = text(record, "signature");
94
+ const owner = text(record, "ownerQualifiedName");
95
+ const name = text(record, "name");
96
+ if (signature) methodsBySignature.set(signature, record);
97
+ if (owner && name) {
98
+ append(mutableMethodsByOwnerAndName, methodKey(owner, name), record);
99
+ }
100
+ }
101
+ }
102
+ return {
103
+ recordsById,
104
+ calls: calls.sort((left, right) => left.id.localeCompare(right.id, "en")),
105
+ bindings,
106
+ bindingsByCall: new Map(
107
+ [...mutableBindingsByCall].map(([key, values]) => [
108
+ key,
109
+ values.sort(
110
+ (left, right) =>
111
+ (number(left, "argumentIndex") ?? Number.MAX_SAFE_INTEGER) -
112
+ (number(right, "argumentIndex") ?? Number.MAX_SAFE_INTEGER) ||
113
+ left.id.localeCompare(right.id, "en"),
114
+ ),
115
+ ]),
116
+ ),
117
+ callablesById,
118
+ callableParent,
119
+ methodsBySignature,
120
+ methodsByOwnerAndName: new Map(
121
+ [...mutableMethodsByOwnerAndName].map(([key, values]) => [
122
+ key,
123
+ values.sort((left, right) => left.id.localeCompare(right.id, "en")),
124
+ ]),
125
+ ),
126
+ };
127
+ }
128
+ function bindingsFor(index, callRef) {
129
+ return index.bindingsByCall.get(callRef) ?? [];
130
+ }
131
+ function parameterName(binding) {
132
+ return (
133
+ text(binding, "parameterName") ??
134
+ objectText(expression(binding), "namedArgument")
135
+ );
136
+ }
137
+ function bindingForParameter(index, callRef, name) {
138
+ return bindingsFor(index, callRef).find(
139
+ (binding) => parameterName(binding) === name,
140
+ );
141
+ }
142
+ function callableWithin(index, candidate, ancestor) {
143
+ const visited = new Set();
144
+ let current = candidate;
145
+ while (current && !visited.has(current)) {
146
+ if (current === ancestor) return true;
147
+ visited.add(current);
148
+ current = index.callableParent.get(current);
149
+ }
150
+ return false;
151
+ }
152
+ function targetMethod(index, call) {
153
+ const signature = text(call, "targetSignature");
154
+ const exact = signature ? index.methodsBySignature.get(signature) : undefined;
155
+ if (exact) return exact;
156
+ const owner = text(call, "targetOwnerQualifiedName");
157
+ const name = sourceApiName(call);
158
+ if (!owner || !name) return undefined;
159
+ const candidates =
160
+ index.methodsByOwnerAndName.get(methodKey(owner, name)) ?? [];
161
+ return candidates.length === 1 ? candidates[0] : undefined;
162
+ }
163
+ function methodParameters(method) {
164
+ const raw = method.data.parameters;
165
+ return Array.isArray(raw)
166
+ ? raw.flatMap((candidate, index) => {
167
+ const item = object(candidate);
168
+ const name = objectText(item, "name");
169
+ const type = objectText(item, "type");
170
+ return name && type ? [{ name, type, index }] : [];
171
+ })
172
+ : [];
173
+ }
174
+ function normalizedType(value) {
175
+ return (value ?? "")
176
+ .replace(/[?!]+$/gu, "")
177
+ .replace(/^java\.lang\./u, "")
178
+ .replace(/^kotlin\./u, "")
179
+ .toLowerCase();
180
+ }
181
+ function normalizedStateName(value) {
182
+ return value.replace(/[^a-z0-9]/giu, "").toLowerCase();
183
+ }
184
+ function staticScalar(summary) {
185
+ if (!summary || !Object.hasOwn(summary, "constantValue")) {
186
+ return { present: false };
187
+ }
188
+ const value = summary.constantValue;
189
+ return value === null ||
190
+ typeof value === "string" ||
191
+ typeof value === "boolean" ||
192
+ (typeof value === "number" && Number.isFinite(value))
193
+ ? { present: true, value: value }
194
+ : { present: false };
195
+ }
196
+ function resolvedSymbol(summary) {
197
+ return object(summary?.resolvedSymbol);
198
+ }
199
+ function routeSubjectCandidates(summary, depth = 0) {
200
+ if (!summary || depth > 16) return [];
201
+ const symbol = resolvedSymbol(summary);
202
+ const qualifiedName = objectText(symbol, "qualifiedName");
203
+ const direct =
204
+ objectText(symbol, "kind") === "class" && qualifiedName
205
+ ? [{ value: qualifiedName, depth }]
206
+ : [];
207
+ return [
208
+ ...direct,
209
+ ...routeSubjectCandidates(object(summary.receiverExpression), depth + 1),
210
+ ...routeSubjectCandidates(object(summary.selectorExpression), depth + 1),
211
+ ];
212
+ }
213
+ function destinationForRouteBinding(state, binding) {
214
+ const subjects = routeSubjectCandidates(expression(binding)).sort(
215
+ (left, right) =>
216
+ right.depth - left.depth || right.value.length - left.value.length,
217
+ );
218
+ for (const { value } of subjects) {
219
+ const matches = state.builder.facts("component").flatMap((fact) => {
220
+ if (
221
+ fact.kind !== "component" ||
222
+ fact.data.componentType !== "compose-destination" ||
223
+ !fact.data.qualifiedName.includes("#route-symbol:")
224
+ )
225
+ return [];
226
+ const encoded = fact.data.qualifiedName.slice(
227
+ fact.data.qualifiedName.lastIndexOf("#route-symbol:") +
228
+ "#route-symbol:".length,
229
+ );
230
+ let identity;
231
+ try {
232
+ identity = decodeURIComponent(encoded);
233
+ } catch {
234
+ return [];
235
+ }
236
+ return identity.includes(value) ? [fact.id] : [];
237
+ });
238
+ if (matches.length === 1) {
239
+ return { destinationRef: matches[0], routeSubject: value };
240
+ }
241
+ }
242
+ return undefined;
243
+ }
244
+ function bundleGetterType(call) {
245
+ const owner = text(call, "targetOwnerQualifiedName") ?? "";
246
+ if (!/(?:^|\.)(?:BaseBundle|Bundle)$/u.test(owner)) return undefined;
247
+ switch (sourceApiName(call)) {
248
+ case "getBoolean":
249
+ return "boolean";
250
+ case "getInt":
251
+ case "getLong":
252
+ case "getFloat":
253
+ case "getDouble":
254
+ return "number";
255
+ case "getString":
256
+ return "string";
257
+ default:
258
+ return undefined;
259
+ }
260
+ }
261
+ function bundleGetterKey(index, call) {
262
+ const binding =
263
+ bindingForParameter(index, call.id, "key") ??
264
+ bindingsFor(index, call.id)[0];
265
+ const scalar = binding
266
+ ? staticScalar(expression(binding))
267
+ : { present: false };
268
+ return scalar.present && typeof scalar.value === "string"
269
+ ? scalar.value
270
+ : undefined;
271
+ }
272
+ function expressionType(summary) {
273
+ const raw =
274
+ objectText(summary, "expressionType") ??
275
+ objectText(resolvedSymbol(summary), "type");
276
+ const normalized = normalizedType(raw);
277
+ if (normalized === "boolean") return "boolean";
278
+ if (["byte", "short", "int", "long", "float", "double"].includes(normalized))
279
+ return "number";
280
+ if (normalized === "string") return "string";
281
+ return normalized;
282
+ }
283
+ function slotForDestinationGetter(index, contentCallableRef, getter) {
284
+ const getterType = bundleGetterType(getter);
285
+ if (!getterType) return undefined;
286
+ const getterCount = index.calls.filter(
287
+ (call) =>
288
+ callableWithin(
289
+ index,
290
+ text(call, "enclosingCallableRef"),
291
+ contentCallableRef,
292
+ ) && bundleGetterType(call) === getterType,
293
+ ).length;
294
+ if (getterCount !== 1) return undefined;
295
+ const candidates = index.calls.flatMap((call) => {
296
+ if (
297
+ !callableWithin(
298
+ index,
299
+ text(call, "enclosingCallableRef"),
300
+ contentCallableRef,
301
+ )
302
+ )
303
+ return [];
304
+ const method = targetMethod(index, call);
305
+ if (!method || method.data.composable !== true) return [];
306
+ return bindingsFor(index, call.id).flatMap((binding) => {
307
+ const summary = expression(binding);
308
+ const symbol = resolvedSymbol(summary);
309
+ if (
310
+ objectText(symbol, "kind") !== "variable" ||
311
+ expressionType(summary) !== getterType
312
+ )
313
+ return [];
314
+ const name = parameterName(binding);
315
+ const parameter = methodParameters(method).find(
316
+ (candidate) =>
317
+ candidate.name === name ||
318
+ candidate.index === number(binding, "parameterIndex"),
319
+ );
320
+ return parameter
321
+ ? [{ method, name: parameter.name, type: parameter.type }]
322
+ : [];
323
+ });
324
+ });
325
+ const unique = new Map(
326
+ candidates.map((slot) => [`${slot.method.id}\u0000${slot.name}`, slot]),
327
+ );
328
+ return unique.size === 1 ? [...unique.values()][0] : undefined;
329
+ }
330
+ function expressionIsSlot(summary, slot) {
331
+ const symbol = resolvedSymbol(summary);
332
+ return (
333
+ objectText(symbol, "kind") === "parameter" &&
334
+ objectText(symbol, "name") === slot.name &&
335
+ normalizedType(objectText(symbol, "type")) === normalizedType(slot.type)
336
+ );
337
+ }
338
+ function propagatedSlots(index, initial) {
339
+ const result = new Map();
340
+ const queue = [initial];
341
+ for (let cursor = 0; cursor < queue.length && cursor < 128; cursor += 1) {
342
+ const slot = queue[cursor];
343
+ const slotKey = `${slot.method.id}\u0000${slot.name}`;
344
+ if (result.has(slotKey)) continue;
345
+ result.set(slotKey, slot);
346
+ for (const call of index.calls) {
347
+ if (
348
+ !callableWithin(
349
+ index,
350
+ text(call, "enclosingCallableRef"),
351
+ slot.method.id,
352
+ )
353
+ )
354
+ continue;
355
+ const target = targetMethod(index, call);
356
+ if (!target) continue;
357
+ for (const binding of bindingsFor(index, call.id)) {
358
+ if (!expressionIsSlot(expression(binding), slot)) continue;
359
+ const boundName = parameterName(binding);
360
+ const parameter = methodParameters(target).find(
361
+ (candidate) =>
362
+ candidate.name === boundName ||
363
+ candidate.index === number(binding, "parameterIndex"),
364
+ );
365
+ if (parameter) {
366
+ queue.push({
367
+ method: target,
368
+ name: parameter.name,
369
+ type: parameter.type,
370
+ });
371
+ }
372
+ }
373
+ }
374
+ }
375
+ return [...result.values()];
376
+ }
377
+ function conditionSlot(index, condition, slots) {
378
+ const structure = object(condition.data.expressionStructure);
379
+ return slots.find(
380
+ (slot) =>
381
+ callableWithin(
382
+ index,
383
+ text(condition, "enclosingCallableRef"),
384
+ slot.method.id,
385
+ ) && expressionIsSlot(structure, slot),
386
+ );
387
+ }
388
+ function conditionPolarity(call, conditionRef) {
389
+ const contexts = call.data.conditionContexts;
390
+ if (!Array.isArray(contexts)) return undefined;
391
+ for (const raw of contexts) {
392
+ const context = object(raw);
393
+ if (context?.conditionRef !== conditionRef) continue;
394
+ if (context.polarity === "true") return true;
395
+ if (context.polarity === "false") return false;
396
+ }
397
+ return undefined;
398
+ }
399
+ function visibleBranchCalls(index, condition, polarity) {
400
+ return index.calls.filter((call) => {
401
+ if (conditionPolarity(call, condition.id) !== polarity) return false;
402
+ const target = targetMethod(index, call);
403
+ return (
404
+ target?.data.composable === true ||
405
+ (text(call, "targetSignature") ?? "").includes(
406
+ "androidx.compose.runtime.Composer",
407
+ )
408
+ );
409
+ });
410
+ }
411
+ function materiallyDifferentBranches(left, right) {
412
+ if (left.length === 0 || right.length === 0) return false;
413
+ const semanticCalls = (values) =>
414
+ new Set(
415
+ values.map(
416
+ (call) =>
417
+ `${text(call, "targetOwnerQualifiedName") ?? ""}#${sourceApiName(call)}`,
418
+ ),
419
+ );
420
+ const a = semanticCalls(left);
421
+ const b = semanticCalls(right);
422
+ return (
423
+ [...a].some((value) => !b.has(value)) ||
424
+ [...b].some((value) => !a.has(value))
425
+ );
426
+ }
427
+ function destinationStates(index, state) {
428
+ const result = [];
429
+ for (const destinationCall of index.calls) {
430
+ if (
431
+ sourceApiName(destinationCall) !== "composable" ||
432
+ !(text(destinationCall, "targetOwnerQualifiedName") ?? "").startsWith(
433
+ "androidx.navigation.compose.",
434
+ )
435
+ )
436
+ continue;
437
+ const routeBinding =
438
+ bindingForParameter(index, destinationCall.id, "route") ??
439
+ bindingsFor(index, destinationCall.id)[0];
440
+ const destination = routeBinding
441
+ ? destinationForRouteBinding(state, routeBinding)
442
+ : undefined;
443
+ const content =
444
+ bindingForParameter(index, destinationCall.id, "content") ??
445
+ [...bindingsFor(index, destinationCall.id)]
446
+ .reverse()
447
+ .find(
448
+ (binding) => objectText(expression(binding), "kind") === "lambda",
449
+ );
450
+ const contentCallable = content
451
+ ? objectText(expression(content), "callableRef")
452
+ : undefined;
453
+ if (!destination || !contentCallable) continue;
454
+ const getters = index.calls.filter(
455
+ (call) =>
456
+ callableWithin(
457
+ index,
458
+ text(call, "enclosingCallableRef"),
459
+ contentCallable,
460
+ ) &&
461
+ bundleGetterType(call) !== undefined &&
462
+ bundleGetterKey(index, call) !== undefined,
463
+ );
464
+ for (const getter of getters) {
465
+ const initialSlot = slotForDestinationGetter(
466
+ index,
467
+ contentCallable,
468
+ getter,
469
+ );
470
+ if (!initialSlot) continue;
471
+ const slots = propagatedSlots(index, initialSlot);
472
+ for (const condition of index.recordsById.values()) {
473
+ if (condition.kind !== "condition") continue;
474
+ const slot = conditionSlot(index, condition, slots);
475
+ if (!slot) continue;
476
+ const trueCalls = visibleBranchCalls(index, condition, true);
477
+ const falseCalls = visibleBranchCalls(index, condition, false);
478
+ if (!materiallyDifferentBranches(trueCalls, falseCalls)) continue;
479
+ result.push({
480
+ destinationRef: destination.destinationRef,
481
+ routeSubject: destination.routeSubject,
482
+ stateKey: initialSlot.name,
483
+ routeKey: bundleGetterKey(index, getter),
484
+ getter,
485
+ condition,
486
+ conditionSlot: slot,
487
+ branchCalls: new Map([
488
+ [true, trueCalls],
489
+ [false, falseCalls],
490
+ ]),
491
+ });
492
+ }
493
+ }
494
+ }
495
+ const unique = new Map();
496
+ for (const item of result) {
497
+ unique.set(
498
+ `${item.destinationRef}\u0000${normalizedStateName(item.stateKey)}`,
499
+ item,
500
+ );
501
+ }
502
+ return [...unique.values()];
503
+ }
504
+ function callSitesForMethod(index, method) {
505
+ return index.calls.filter(
506
+ (call) => targetMethod(index, call)?.id === method.id,
507
+ );
508
+ }
509
+ function callableArgumentBindings(index, callableRef) {
510
+ return index.bindings.filter(
511
+ (binding) => objectText(expression(binding), "callableRef") === callableRef,
512
+ );
513
+ }
514
+ function callbackInvocationOrigins(
515
+ index,
516
+ lambdaRef,
517
+ parameter,
518
+ depth,
519
+ visited,
520
+ ) {
521
+ const result = [];
522
+ for (const actual of callableArgumentBindings(index, lambdaRef)) {
523
+ const parentRef = text(actual, "callRef");
524
+ const parent = parentRef ? index.recordsById.get(parentRef) : undefined;
525
+ const target = parent ? targetMethod(index, parent) : undefined;
526
+ const formal = parameterName(actual);
527
+ if (!parent || !target || !formal) continue;
528
+ for (const invocation of index.calls) {
529
+ if (
530
+ sourceApiName(invocation) !== "invoke" ||
531
+ !callableWithin(
532
+ index,
533
+ text(invocation, "enclosingCallableRef"),
534
+ target.id,
535
+ )
536
+ )
537
+ continue;
538
+ const receiver = object(invocation.data.receiverResolvedSymbol);
539
+ if (
540
+ objectText(receiver, "kind") !== "parameter" ||
541
+ objectText(receiver, "name") !== formal
542
+ )
543
+ continue;
544
+ const argument = bindingsFor(index, invocation.id)[0];
545
+ const callableRef = text(invocation, "enclosingCallableRef");
546
+ if (!argument || !callableRef) continue;
547
+ result.push(
548
+ ...resolveStaticOrigins(
549
+ index,
550
+ expression(argument),
551
+ invocation,
552
+ callableRef,
553
+ depth + 1,
554
+ visited,
555
+ [actual, parent, invocation, argument],
556
+ ),
557
+ );
558
+ }
559
+ }
560
+ return result;
561
+ }
562
+ function resolveStaticOrigins(
563
+ index,
564
+ summary,
565
+ context,
566
+ callableRef,
567
+ depth = 0,
568
+ visited = new Set(),
569
+ support = [],
570
+ ) {
571
+ if (!summary || depth > 16) return [];
572
+ const visitKey = [callableRef, context.id, JSON.stringify(summary)].join(
573
+ "\u0000",
574
+ );
575
+ if (visited.has(visitKey)) return [];
576
+ const nextVisited = new Set(visited).add(visitKey);
577
+ const scalar = staticScalar(summary);
578
+ if (scalar.present) {
579
+ return [
580
+ {
581
+ value: scalar.value,
582
+ callableRef,
583
+ support: [...support, context],
584
+ },
585
+ ];
586
+ }
587
+ const symbol = resolvedSymbol(summary);
588
+ const initializer = object(symbol?.initializer);
589
+ if (initializer) {
590
+ const initialized = resolveStaticOrigins(
591
+ index,
592
+ initializer,
593
+ context,
594
+ callableRef,
595
+ depth + 1,
596
+ nextVisited,
597
+ support,
598
+ );
599
+ if (initialized.length > 0) return initialized;
600
+ }
601
+ if (objectText(symbol, "kind") !== "parameter") return [];
602
+ const name = objectText(symbol, "name");
603
+ const callable = index.callablesById.get(callableRef);
604
+ if (!name || !callable) return [];
605
+ if (callable.kind === "lambda-declaration") {
606
+ return callbackInvocationOrigins(
607
+ index,
608
+ callableRef,
609
+ name,
610
+ depth,
611
+ nextVisited,
612
+ );
613
+ }
614
+ const parameter = methodParameters(callable).find(
615
+ (candidate) => candidate.name === name,
616
+ );
617
+ if (!parameter) return [];
618
+ return callSitesForMethod(index, callable).flatMap((call) => {
619
+ const actual = bindingsFor(index, call.id).find(
620
+ (binding) =>
621
+ parameterName(binding) === parameter.name ||
622
+ number(binding, "parameterIndex") === parameter.index,
623
+ );
624
+ const parentCallable = text(call, "enclosingCallableRef");
625
+ return actual && parentCallable
626
+ ? resolveStaticOrigins(
627
+ index,
628
+ expression(actual),
629
+ call,
630
+ parentCallable,
631
+ depth + 1,
632
+ nextVisited,
633
+ [...support, actual, call],
634
+ )
635
+ : [];
636
+ });
637
+ }
638
+ function routeBuilderOrigins(index, destination) {
639
+ const result = [];
640
+ for (const call of index.calls) {
641
+ if (text(call, "targetOwnerQualifiedName") !== destination.routeSubject) {
642
+ continue;
643
+ }
644
+ const method = targetMethod(index, call);
645
+ if (!method || normalizedType(text(method, "returnType")) !== "string") {
646
+ continue;
647
+ }
648
+ const parameter = methodParameters(method).find(
649
+ (candidate) =>
650
+ normalizedStateName(candidate.name) ===
651
+ normalizedStateName(destination.stateKey) ||
652
+ normalizedStateName(candidate.name) ===
653
+ normalizedStateName(destination.routeKey),
654
+ );
655
+ if (!parameter) continue;
656
+ const binding = bindingsFor(index, call.id).find(
657
+ (candidate) =>
658
+ parameterName(candidate) === parameter.name ||
659
+ number(candidate, "parameterIndex") === parameter.index,
660
+ );
661
+ const callableRef = text(call, "enclosingCallableRef");
662
+ if (!binding || !callableRef) continue;
663
+ result.push(
664
+ ...resolveStaticOrigins(
665
+ index,
666
+ expression(binding),
667
+ call,
668
+ callableRef,
669
+ 0,
670
+ new Set(),
671
+ [method, binding, call],
672
+ ),
673
+ );
674
+ }
675
+ const unique = new Map();
676
+ for (const origin of result) {
677
+ unique.set(
678
+ `${JSON.stringify(origin.value)}\u0000${origin.callableRef}`,
679
+ origin,
680
+ );
681
+ }
682
+ return [...unique.values()];
683
+ }
684
+ function uniqueSupport(records, anchor, role) {
685
+ const result = [
686
+ ...new Map(records.map((record) => [record.id, record])).values(),
687
+ ].flatMap((record) => {
688
+ const location = recordLocation(
689
+ record,
690
+ anchor,
691
+ text(record, "enclosingMethod") ?? text(record, "targetSignature"),
692
+ );
693
+ return location ? [{ location, role }] : [];
694
+ });
695
+ return result.length > 0 ? result : undefined;
696
+ }
697
+ /**
698
+ * Proves finite page variants only when all of these structured facts align:
699
+ * a Navigation Compose destination reads one typed Bundle argument, that
700
+ * value reaches a composable branch with materially different UI calls, and
701
+ * local route-builder call chains supply at least two concrete scalar values.
702
+ */
703
+ export function normalizeRouteStateVariants(jvm, state) {
704
+ if (!jvm) return;
705
+ const index = buildIndex(jvm);
706
+ for (const destination of destinationStates(index, state)) {
707
+ const origins = routeBuilderOrigins(index, destination);
708
+ const byValue = new Map();
709
+ for (const origin of origins) {
710
+ const callbackRef = state.callbackForRawCallable(origin.callableRef);
711
+ if (!callbackRef) continue;
712
+ const key = JSON.stringify(origin.value);
713
+ const values = byValue.get(key) ?? [];
714
+ values.push(origin);
715
+ byValue.set(key, values);
716
+ }
717
+ if (byValue.size < 2) continue;
718
+ for (const [valueKey, valueOrigins] of byValue) {
719
+ const value = JSON.parse(valueKey);
720
+ if (typeof value !== "boolean") continue;
721
+ const callbacks = [
722
+ ...new Set(
723
+ valueOrigins.flatMap((origin) => {
724
+ const callback = state.callbackForRawCallable(origin.callableRef);
725
+ return callback ? [callback] : [];
726
+ }),
727
+ ),
728
+ ].sort();
729
+ if (callbacks.length === 0) continue;
730
+ const expressionAnchor = `${destination.stateKey} = ${String(value)}`;
731
+ const branchCalls = destination.branchCalls.get(value) ?? [];
732
+ const supports = uniqueSupport(
733
+ [
734
+ destination.getter,
735
+ destination.condition,
736
+ ...branchCalls,
737
+ ...valueOrigins.flatMap((origin) => origin.support),
738
+ ],
739
+ `component-variant:${expressionAnchor}`,
740
+ "structured route scalar and mutually exclusive Compose UI branch",
741
+ );
742
+ if (!supports) continue;
743
+ const conditionRef = state.builder.addFact("condition", {
744
+ identity: [
745
+ { kind: "component", value: destination.destinationRef },
746
+ { kind: "semantic-key", value: expressionAnchor },
747
+ ],
748
+ confidence: "high",
749
+ support: supports,
750
+ data: {
751
+ ownerKey: destination.destinationRef,
752
+ expressionAnchor,
753
+ plainLanguage: `导航状态 ${destination.stateKey} 的值为 ${String(value)}`,
754
+ valueKind: "static",
755
+ },
756
+ relatedFactRefs: [destination.destinationRef],
757
+ });
758
+ state.builder.addFact("component-variant", {
759
+ identity: [
760
+ { kind: "component", value: destination.destinationRef },
761
+ { kind: "semantic-key", value: destination.stateKey },
762
+ { kind: "semantic-key", value: valueKey },
763
+ ],
764
+ confidence: "high",
765
+ support: supports,
766
+ data: {
767
+ componentKey: destination.destinationRef,
768
+ stateKey: `${destination.routeSubject}#${destination.stateKey}`,
769
+ value,
770
+ conditionKeys: [conditionRef],
771
+ entryCallbackKeys: callbacks,
772
+ },
773
+ relatedFactRefs: [
774
+ destination.destinationRef,
775
+ conditionRef,
776
+ ...callbacks,
777
+ ],
778
+ });
779
+ }
780
+ }
781
+ }