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,33 @@
1
+ import { normalizeAreaTitleFacts } from "./area-titles.js";
2
+ import { normalizeAndroidFacts, prepareAndroidStructure } from "./android.js";
3
+ import { SourceFactsBuilder } from "./builder.js";
4
+ import { normalizeComposeFacts } from "./compose.js";
5
+ import { normalizeComposeCallSiteFacts } from "./compose-call-sites.js";
6
+ import { normalizeInteractionEffects } from "./interaction-effects.js";
7
+ import { normalizeJvmFacts, prepareJvmStructure } from "./jvm.js";
8
+ import { normalizePendingIntentFacts } from "./pending-intents.js";
9
+ import { normalizeRouteStateVariants } from "./route-state-variants.js";
10
+ import { NormalizationState } from "./state.js";
11
+ export function buildSourceFacts(input) {
12
+ const builder = new SourceFactsBuilder(input.caseId, {
13
+ ...input.android.target,
14
+ ...(input.sourceSnapshot ? { sourceSnapshot: input.sourceSnapshot } : {}),
15
+ });
16
+ const state = new NormalizationState(
17
+ builder,
18
+ input.android.manifest.packageName,
19
+ );
20
+ // Component identities must exist before calls and XML controls establish
21
+ // their strong owner references.
22
+ prepareAndroidStructure(input.android, state);
23
+ const jvmIndex = prepareJvmStructure(input.jvm, state);
24
+ normalizeAndroidFacts(input.android, state);
25
+ normalizeComposeFacts(input.android, input.jvm, state);
26
+ normalizeJvmFacts(input.jvm, state, jvmIndex);
27
+ normalizeComposeCallSiteFacts(input.android, input.jvm, state);
28
+ normalizeAreaTitleFacts(input.android, state, jvmIndex);
29
+ normalizePendingIntentFacts(input.jvm, state);
30
+ normalizeInteractionEffects(input.jvm, state);
31
+ normalizeRouteStateVariants(input.jvm, state);
32
+ return builder.finish();
33
+ }
@@ -0,0 +1,565 @@
1
+ function objectValue(value) {
2
+ return value !== null && typeof value === "object" && !Array.isArray(value)
3
+ ? value
4
+ : undefined;
5
+ }
6
+ function object(record, key) {
7
+ return objectValue(record.data[key]);
8
+ }
9
+ function objectText(value, key) {
10
+ const candidate = value?.[key];
11
+ return typeof candidate === "string" && candidate.trim().length > 0
12
+ ? candidate.trim()
13
+ : undefined;
14
+ }
15
+ function text(record, key) {
16
+ const candidate = record.data[key];
17
+ return typeof candidate === "string" && candidate.trim().length > 0
18
+ ? candidate.trim()
19
+ : undefined;
20
+ }
21
+ function boolean(record, key) {
22
+ const candidate = record.data[key];
23
+ return typeof candidate === "boolean" ? candidate : undefined;
24
+ }
25
+ function sourceKind(record) {
26
+ const language = text(record, "language");
27
+ if (language === "kotlin" || record.location?.path.endsWith(".kt")) {
28
+ return "kotlin";
29
+ }
30
+ if (language === "java" || record.location?.path.endsWith(".java")) {
31
+ return "java";
32
+ }
33
+ return "other";
34
+ }
35
+ function recordLocation(record, anchor, symbol) {
36
+ if (!record.location) return undefined;
37
+ return {
38
+ sourceKind: sourceKind(record),
39
+ path: record.location.path,
40
+ anchor,
41
+ range: {
42
+ startLine: Math.max(1, record.location.startLine),
43
+ endLine: Math.max(
44
+ Math.max(1, record.location.startLine),
45
+ record.location.endLine,
46
+ ),
47
+ ...(record.location.startColumn >= 1
48
+ ? { startColumn: record.location.startColumn }
49
+ : {}),
50
+ ...(record.location.endColumn >= 1
51
+ ? { endColumn: record.location.endColumn }
52
+ : {}),
53
+ },
54
+ ...(symbol ? { symbol } : {}),
55
+ };
56
+ }
57
+ function appendBinding(bindings, record) {
58
+ const callRef = text(record, "callRef");
59
+ if (!callRef) return;
60
+ const values = bindings.get(callRef) ?? [];
61
+ values.push(record);
62
+ bindings.set(callRef, values);
63
+ }
64
+ function buildIndex(jvm) {
65
+ const callsById = new Map();
66
+ const resolvedCalls = [];
67
+ const bindingsByCallRef = new Map();
68
+ const methodsBySignature = new Map();
69
+ const returnsByCallableRef = new Map();
70
+ for (const record of jvm.body) {
71
+ if (record.kind === "resolved-call" || record.kind === "unresolved-call") {
72
+ callsById.set(record.id, record);
73
+ if (record.kind === "resolved-call") resolvedCalls.push(record);
74
+ } else if (record.kind === "call-argument-binding") {
75
+ appendBinding(bindingsByCallRef, record);
76
+ } else if (record.kind === "method-declaration") {
77
+ const signature = text(record, "signature");
78
+ if (signature) {
79
+ const values = methodsBySignature.get(signature) ?? [];
80
+ values.push(record);
81
+ methodsBySignature.set(signature, values);
82
+ }
83
+ } else if (record.kind === "return") {
84
+ const callableRef = text(record, "enclosingCallableRef");
85
+ if (!callableRef) continue;
86
+ const values = returnsByCallableRef.get(callableRef) ?? [];
87
+ values.push(record);
88
+ returnsByCallableRef.set(callableRef, values);
89
+ }
90
+ }
91
+ return {
92
+ callsById,
93
+ resolvedCalls: resolvedCalls.sort((left, right) =>
94
+ left.id.localeCompare(right.id, "en"),
95
+ ),
96
+ bindingsByCallRef,
97
+ methodsBySignature,
98
+ returnsByCallableRef,
99
+ };
100
+ }
101
+ function expression(binding) {
102
+ return object(binding, "expression");
103
+ }
104
+ /**
105
+ * Follows only analyzer-provided expression structure. In particular, this
106
+ * deliberately does not parse argumentSource, initializerSource, or source.
107
+ */
108
+ function callRefFromExpression(value, visited = new Set()) {
109
+ if (!value || visited.has(value)) return undefined;
110
+ visited.add(value);
111
+ const direct = objectText(value, "callRef");
112
+ if (direct) return direct;
113
+ const symbol = objectValue(value.resolvedSymbol);
114
+ const initializer = objectValue(symbol?.initializer);
115
+ return initializer ? callRefFromExpression(initializer, visited) : undefined;
116
+ }
117
+ function classFromExpression(value, visited = new Set()) {
118
+ if (!value || visited.has(value)) return undefined;
119
+ visited.add(value);
120
+ const literal = objectValue(value.classLiteral);
121
+ const direct = objectText(literal, "resolvedClassQualifiedName");
122
+ if (direct) return direct;
123
+ const symbol = objectValue(value.resolvedSymbol);
124
+ const initializer = objectValue(symbol?.initializer);
125
+ return initializer ? classFromExpression(initializer, visited) : undefined;
126
+ }
127
+ function resourceFromExpression(value, resourceType) {
128
+ const resource = objectValue(value?.resourceReference);
129
+ return objectText(resource, "resourceType") === resourceType
130
+ ? objectText(resource, "resourceName")
131
+ : undefined;
132
+ }
133
+ function uniqueString(values) {
134
+ const unique = [...new Set(values.filter((value) => value !== undefined))];
135
+ return unique.length === 1 ? unique[0] : undefined;
136
+ }
137
+ function isRemoteViewsClick(call) {
138
+ return (
139
+ text(call, "targetOwnerQualifiedName") === "android.widget.RemoteViews" &&
140
+ text(call, "targetName") === "setOnClickPendingIntent"
141
+ );
142
+ }
143
+ function isRemoteViewsConstructor(call) {
144
+ return (
145
+ text(call, "targetOwnerQualifiedName") === "android.widget.RemoteViews" &&
146
+ text(call, "targetName") === "RemoteViews" &&
147
+ boolean(call, "targetConstructor") === true
148
+ );
149
+ }
150
+ function isNotificationContentIntent(call) {
151
+ const owner = text(call, "targetOwnerQualifiedName");
152
+ return (
153
+ text(call, "targetName") === "setContentIntent" &&
154
+ (owner === "android.app.Notification.Builder" ||
155
+ owner === "androidx.core.app.NotificationCompat.Builder")
156
+ );
157
+ }
158
+ function isActivityPendingIntent(call) {
159
+ return (
160
+ text(call, "targetOwnerQualifiedName") === "android.app.PendingIntent" &&
161
+ text(call, "targetName") === "getActivity"
162
+ );
163
+ }
164
+ function isIntentConstructor(call) {
165
+ return (
166
+ text(call, "targetOwnerQualifiedName") === "android.content.Intent" &&
167
+ text(call, "targetName") === "Intent" &&
168
+ boolean(call, "targetConstructor") === true
169
+ );
170
+ }
171
+ function callsReferencedByBindings(callRef, index) {
172
+ const refs = (index.bindingsByCallRef.get(callRef) ?? [])
173
+ .map((binding) => callRefFromExpression(expression(binding)))
174
+ .filter((ref) => ref !== undefined);
175
+ return [...new Set(refs)]
176
+ .map((ref) => index.callsById.get(ref))
177
+ .filter((call) => call !== undefined);
178
+ }
179
+ function receiverInitializerCall(call, index) {
180
+ const receiver = object(call, "receiverResolvedSymbol");
181
+ const initializer = objectValue(receiver?.initializer);
182
+ const callRef = callRefFromExpression(initializer);
183
+ return callRef ? index.callsById.get(callRef) : undefined;
184
+ }
185
+ function layoutForRemoteViews(clickCall, index) {
186
+ const constructor = receiverInitializerCall(clickCall, index);
187
+ if (!constructor || !isRemoteViewsConstructor(constructor)) {
188
+ return undefined;
189
+ }
190
+ return uniqueString(
191
+ (index.bindingsByCallRef.get(constructor.id) ?? []).map((binding) =>
192
+ resourceFromExpression(expression(binding), "layout"),
193
+ ),
194
+ );
195
+ }
196
+ function intentForPendingIntent(pendingIntent, index) {
197
+ const candidates = callsReferencedByBindings(pendingIntent.id, index).filter(
198
+ isIntentConstructor,
199
+ );
200
+ return candidates.length === 1 ? candidates[0] : undefined;
201
+ }
202
+ function targetForIntent(intent, index) {
203
+ return uniqueString(
204
+ (index.bindingsByCallRef.get(intent.id) ?? []).map((binding) =>
205
+ classFromExpression(expression(binding)),
206
+ ),
207
+ );
208
+ }
209
+ function uniqueRecords(records) {
210
+ return [
211
+ ...new Map(records.map((record) => [record.id, record])).values(),
212
+ ].sort((left, right) => left.id.localeCompare(right.id, "en"));
213
+ }
214
+ function directActivityPendingIntent(call, index) {
215
+ if (!isActivityPendingIntent(call)) return undefined;
216
+ const intentCall = intentForPendingIntent(call, index);
217
+ const targetClass = intentCall
218
+ ? targetForIntent(intentCall, index)
219
+ : undefined;
220
+ return intentCall && targetClass
221
+ ? {
222
+ pendingIntentCall: call,
223
+ intentCall,
224
+ targetClass,
225
+ flowRecords: uniqueRecords([call, intentCall]),
226
+ }
227
+ : undefined;
228
+ }
229
+ function activityPendingIntentFromExpression(
230
+ value,
231
+ index,
232
+ visitedDeclarations = new Set(),
233
+ ) {
234
+ const callRef = callRefFromExpression(value);
235
+ const call = callRef ? index.callsById.get(callRef) : undefined;
236
+ return call
237
+ ? activityPendingIntentFromCall(call, index, visitedDeclarations)
238
+ : undefined;
239
+ }
240
+ function activityPendingIntentFromCall(call, index, visitedDeclarations) {
241
+ const direct = directActivityPendingIntent(call, index);
242
+ if (direct) return direct;
243
+ const targetSignature = text(call, "targetSignature");
244
+ const declarations = targetSignature
245
+ ? (index.methodsBySignature.get(targetSignature) ?? [])
246
+ : [];
247
+ const declaration = declarations.length === 1 ? declarations[0] : undefined;
248
+ if (!declaration || visitedDeclarations.has(declaration.id)) {
249
+ return undefined;
250
+ }
251
+ const returns = [
252
+ ...(index.returnsByCallableRef.get(declaration.id) ?? []),
253
+ ].sort((left, right) => left.id.localeCompare(right.id, "en"));
254
+ if (returns.length === 0) return undefined;
255
+ const nextVisited = new Set(visitedDeclarations);
256
+ nextVisited.add(declaration.id);
257
+ const resolutions = returns.map((record) =>
258
+ activityPendingIntentFromExpression(
259
+ object(record, "expression"),
260
+ index,
261
+ nextVisited,
262
+ ),
263
+ );
264
+ // A partially understood factory is not a unique static route. Every
265
+ // observed return must resolve and all of them must agree on one Activity.
266
+ if (resolutions.some((resolution) => resolution === undefined)) {
267
+ return undefined;
268
+ }
269
+ const resolved = resolutions;
270
+ const targetClass = uniqueString(
271
+ resolved.map((resolution) => resolution.targetClass),
272
+ );
273
+ if (!targetClass) return undefined;
274
+ const representative = [...resolved].sort((left, right) =>
275
+ left.pendingIntentCall.id.localeCompare(right.pendingIntentCall.id, "en"),
276
+ )[0];
277
+ return {
278
+ pendingIntentCall: representative.pendingIntentCall,
279
+ intentCall: representative.intentCall,
280
+ targetClass,
281
+ flowRecords: uniqueRecords([
282
+ call,
283
+ declaration,
284
+ ...returns,
285
+ ...resolved.flatMap((resolution) => resolution.flowRecords),
286
+ ]),
287
+ };
288
+ }
289
+ function activityPendingIntentArgument(call, index) {
290
+ const bindings = (index.bindingsByCallRef.get(call.id) ?? []).filter(
291
+ (binding) => text(binding, "parameterType") === "android.app.PendingIntent",
292
+ );
293
+ return bindings.length === 1
294
+ ? activityPendingIntentFromExpression(expression(bindings[0]), index)
295
+ : undefined;
296
+ }
297
+ function resourceIdForClick(clickCall, index) {
298
+ return uniqueString(
299
+ (index.bindingsByCallRef.get(clickCall.id) ?? []).map((binding) =>
300
+ resourceFromExpression(expression(binding), "id"),
301
+ ),
302
+ );
303
+ }
304
+ function widgetControl(state, clickCall, layout, resourceId) {
305
+ const enclosingClass = text(clickCall, "enclosingClass");
306
+ const enclosingOwner = enclosingClass
307
+ ? state.componentByQualifiedName.get(enclosingClass)
308
+ : undefined;
309
+ const enclosingWidget =
310
+ enclosingOwner && state.componentTypeById.get(enclosingOwner) === "widget"
311
+ ? enclosingOwner
312
+ : undefined;
313
+ let candidates = [...(state.uiByLayout.get(layout) ?? [])]
314
+ .map((id) => state.builder.fact(id))
315
+ .filter(
316
+ (fact) =>
317
+ fact?.kind === "ui-element" &&
318
+ fact.data.resourceId === resourceId &&
319
+ state.componentTypeById.get(fact.data.ownerKey) === "widget",
320
+ );
321
+ if (enclosingWidget) {
322
+ const owned = candidates.filter(
323
+ (fact) =>
324
+ fact?.kind === "ui-element" && fact.data.ownerKey === enclosingWidget,
325
+ );
326
+ if (owned.length > 0) candidates = owned;
327
+ }
328
+ const unique = [
329
+ ...new Map(candidates.map((fact) => [fact?.id, fact])).values(),
330
+ ];
331
+ const control = unique.length === 1 ? unique[0] : undefined;
332
+ return control?.kind === "ui-element"
333
+ ? {
334
+ controlRef: control.id,
335
+ widgetRef: control.data.ownerKey,
336
+ }
337
+ : undefined;
338
+ }
339
+ function resolveRemoteViewsClick(state, clickCall, index) {
340
+ const layout = layoutForRemoteViews(clickCall, index);
341
+ const resourceId = resourceIdForClick(clickCall, index);
342
+ const pendingIntent = activityPendingIntentArgument(clickCall, index);
343
+ if (!layout || !resourceId || !pendingIntent) return undefined;
344
+ const control = widgetControl(state, clickCall, layout, resourceId);
345
+ if (!control) return undefined;
346
+ return {
347
+ clickCall,
348
+ pendingIntentCall: pendingIntent.pendingIntentCall,
349
+ intentCall: pendingIntent.intentCall,
350
+ targetClass: pendingIntent.targetClass,
351
+ layout,
352
+ resourceId,
353
+ ...control,
354
+ };
355
+ }
356
+ function addRemoteViewsClickFacts(state, resolution) {
357
+ const clickSignature =
358
+ text(resolution.clickCall, "targetSignature") ??
359
+ "android.widget.RemoteViews#setOnClickPendingIntent";
360
+ const pendingSignature =
361
+ text(resolution.pendingIntentCall, "targetSignature") ??
362
+ "android.app.PendingIntent#getActivity";
363
+ const clickLocation = recordLocation(
364
+ resolution.clickCall,
365
+ `remote-views-click:${resolution.layout}/${resolution.resourceId}`,
366
+ clickSignature,
367
+ );
368
+ const pendingLocation = recordLocation(
369
+ resolution.pendingIntentCall,
370
+ `activity-pending-intent:${resolution.targetClass}`,
371
+ pendingSignature,
372
+ );
373
+ const targetLocation = recordLocation(
374
+ resolution.intentCall,
375
+ `explicit-intent-target:${resolution.targetClass}`,
376
+ resolution.targetClass,
377
+ );
378
+ if (!clickLocation || !pendingLocation || !targetLocation) return;
379
+ const targetRef = state.ensureComponent(
380
+ resolution.targetClass,
381
+ "activity",
382
+ targetLocation,
383
+ "explicit Activity PendingIntent target",
384
+ "high",
385
+ { uiTechnology: "views" },
386
+ );
387
+ const callbackRef = state.builder.addFact("callback", {
388
+ identity: [
389
+ { kind: "component", value: resolution.widgetRef },
390
+ {
391
+ kind: "callback",
392
+ value:
393
+ `remote-views:${resolution.clickCall.id}:` +
394
+ resolution.pendingIntentCall.id,
395
+ },
396
+ ],
397
+ confidence: "high",
398
+ support: [
399
+ {
400
+ location: clickLocation,
401
+ role: "RemoteViews PendingIntent click binding",
402
+ },
403
+ {
404
+ location: pendingLocation,
405
+ role: "resolved activity PendingIntent factory",
406
+ },
407
+ ],
408
+ data: {
409
+ ownerKey: resolution.widgetRef,
410
+ callableSymbol: `${clickSignature} -> ${pendingSignature}`,
411
+ callbackKind: "function",
412
+ },
413
+ relatedFactRefs: [resolution.widgetRef],
414
+ });
415
+ const interactionRef = state.builder.addFact("interaction-binding", {
416
+ identity: [
417
+ { kind: "control", value: resolution.controlRef },
418
+ { kind: "callback", value: callbackRef },
419
+ { kind: "semantic-key", value: clickSignature },
420
+ ],
421
+ confidence: "high",
422
+ support: [
423
+ {
424
+ location: clickLocation,
425
+ role: "resolved RemoteViews click interaction",
426
+ },
427
+ ],
428
+ data: {
429
+ elementKey: resolution.controlRef,
430
+ callbackKey: callbackRef,
431
+ trigger: "click",
432
+ bindingApi: clickSignature,
433
+ },
434
+ relatedFactRefs: [resolution.controlRef, callbackRef],
435
+ });
436
+ const effectRef = state.builder.addFact("behavior-effect", {
437
+ identity: [
438
+ { kind: "callback", value: callbackRef },
439
+ { kind: "component", value: targetRef },
440
+ { kind: "semantic-key", value: "activity-pending-intent" },
441
+ ],
442
+ confidence: "high",
443
+ support: [
444
+ {
445
+ location: pendingLocation,
446
+ role: "PendingIntent launches an Activity",
447
+ },
448
+ {
449
+ location: targetLocation,
450
+ role: "explicit Intent component target",
451
+ },
452
+ ],
453
+ data: {
454
+ callbackKey: callbackRef,
455
+ effectKind: "navigate-area",
456
+ targetKey: targetRef,
457
+ },
458
+ relatedFactRefs: [callbackRef, targetRef, interactionRef],
459
+ });
460
+ state.builder.addFact("navigation-target", {
461
+ identity: [
462
+ { kind: "semantic-key", value: effectRef },
463
+ { kind: "component", value: targetRef },
464
+ ],
465
+ confidence: "high",
466
+ support: [
467
+ {
468
+ location: targetLocation,
469
+ role: "explicit Activity class in PendingIntent Intent",
470
+ },
471
+ ],
472
+ data: {
473
+ effectKey: effectRef,
474
+ targetKind: "component",
475
+ targetKey: targetRef,
476
+ },
477
+ relatedFactRefs: [effectRef, targetRef],
478
+ });
479
+ }
480
+ function addNotificationEntry(state, consumer, resolution) {
481
+ const consumerSignature =
482
+ text(consumer, "targetSignature") ??
483
+ `${text(consumer, "targetOwnerQualifiedName") ?? "Notification.Builder"}` +
484
+ "#setContentIntent";
485
+ const consumerLocation = recordLocation(
486
+ consumer,
487
+ `notification-content-intent:${consumer.id}`,
488
+ consumerSignature,
489
+ );
490
+ const targetLocation = recordLocation(
491
+ resolution.intentCall,
492
+ `explicit-intent-target:${resolution.targetClass}`,
493
+ resolution.targetClass,
494
+ );
495
+ if (!consumerLocation || !targetLocation) return;
496
+ const targetRef = state.ensureComponent(
497
+ resolution.targetClass,
498
+ "activity",
499
+ targetLocation,
500
+ "explicit notification Activity target",
501
+ "high",
502
+ { uiTechnology: "views" },
503
+ );
504
+ const flowSupport = resolution.flowRecords.flatMap((record) => {
505
+ const location = recordLocation(
506
+ record,
507
+ `notification-pending-intent-flow:${record.id}`,
508
+ text(record, "targetSignature") ??
509
+ text(record, "signature") ??
510
+ resolution.targetClass,
511
+ );
512
+ return location
513
+ ? [
514
+ {
515
+ location,
516
+ role:
517
+ record.kind === "return"
518
+ ? "local PendingIntent factory return"
519
+ : "resolved notification PendingIntent flow",
520
+ },
521
+ ]
522
+ : [];
523
+ });
524
+ state.builder.addFact("entry-point", {
525
+ identity: [
526
+ { kind: "entry", value: "notification" },
527
+ { kind: "component", value: targetRef },
528
+ { kind: "semantic-key", value: consumer.id },
529
+ ],
530
+ confidence: "high",
531
+ support: [
532
+ {
533
+ location: consumerLocation,
534
+ role: "Notification builder consumes content PendingIntent",
535
+ },
536
+ ...flowSupport,
537
+ ],
538
+ data: {
539
+ entryKind: "notification",
540
+ category: "alternate",
541
+ componentKey: targetRef,
542
+ conditionKeys: [],
543
+ },
544
+ relatedFactRefs: [targetRef],
545
+ });
546
+ }
547
+ /**
548
+ * Resolves only consumed activity PendingIntents. Merely constructing or
549
+ * returning a PendingIntent is intentionally not treated as a notification
550
+ * entry; an entry kind requires a corresponding consuming API.
551
+ */
552
+ export function normalizePendingIntentFacts(jvm, state) {
553
+ if (!jvm) return;
554
+ const index = buildIndex(jvm);
555
+ for (const call of index.resolvedCalls) {
556
+ if (isRemoteViewsClick(call)) {
557
+ const resolution = resolveRemoteViewsClick(state, call, index);
558
+ if (resolution) addRemoteViewsClickFacts(state, resolution);
559
+ }
560
+ if (isNotificationContentIntent(call)) {
561
+ const resolution = activityPendingIntentArgument(call, index);
562
+ if (resolution) addNotificationEntry(state, call, resolution);
563
+ }
564
+ }
565
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Android resource names and generated ViewBinding properties use two
3
+ * spellings for the same source identity. A layout ID may be written as
4
+ * `search_btn`, while the generated property is `searchBtn`. Some projects
5
+ * also use lower-camel IDs directly in XML, so neither spelling can be
6
+ * treated as the one canonical serialized value.
7
+ *
8
+ * These helpers deliberately keep a small, reversible alias set. We do not
9
+ * remove separators or case-fold arbitrary strings: if two controls share an
10
+ * alias in one owner, callers will see both candidates and retain the
11
+ * ambiguity instead of silently joining them.
12
+ */
13
+ export function camelToSnakeResourceId(value) {
14
+ return value
15
+ .replace(/([a-z0-9])([A-Z])/gu, "$1_$2")
16
+ .replace(/([A-Z]+)([A-Z][a-z])/gu, "$1_$2")
17
+ .toLowerCase();
18
+ }
19
+ export function snakeToLowerCamelResourceId(value) {
20
+ return value.replace(/_+([A-Za-z0-9])/gu, (_match, next) =>
21
+ next.toUpperCase(),
22
+ );
23
+ }
24
+ export function resourceIdAliases(value) {
25
+ const exact = value.trim();
26
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(exact)) {
27
+ return exact.length > 0 ? [exact] : [];
28
+ }
29
+ const snake = camelToSnakeResourceId(exact);
30
+ return [
31
+ ...new Set([
32
+ exact,
33
+ snake,
34
+ snakeToLowerCamelResourceId(exact),
35
+ snakeToLowerCamelResourceId(snake),
36
+ ]),
37
+ ];
38
+ }
39
+ export function resourceIdsEquivalent(left, right) {
40
+ const rightAliases = new Set(resourceIdAliases(right));
41
+ return resourceIdAliases(left).some((alias) => rightAliases.has(alias));
42
+ }