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.
- package/agents/api-analyzer.md +113 -0
- package/agents/app-action.md +122 -0
- package/agents/code-reviewer.md +191 -295
- package/agents/coder.md +377 -0
- package/agents/self-tester.md +8 -8
- package/agents/spec-designer.md +56 -0
- package/package.json +1 -1
- package/skills/a2h-app-req-gen/SKILL.md +174 -0
- package/skills/a2h-app-req-gen/references/spec-handoff.md +99 -0
- package/skills/a2h-app-req-gen/references/subagent-render.md +115 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/build.gradle.kts +41 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradle/wrapper/gradle-wrapper.properties +8 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradle.properties +3 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradlew +251 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradlew.bat +94 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/settings.gradle.kts +17 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawAnalysisDetector.java +1911 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawIssueRegistry.java +37 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawJson.java +146 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawLocation.java +96 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawRecordWriter.java +227 -0
- 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
- package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/resources/dev/reqgen/analyzer/jvm/raw-record-v1.schema.json +93 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/assets/dashboard.html +151 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/gradle/reqgen-lint.init.gradle +60 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/gradle/reqgen-model.init.gradle +204 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/package.json +14 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/backend.js +323 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/cli.js +811 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/gap-audit-link.js +62 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/index.js +66 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/merge.js +605 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/name-trace.js +153 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/orchestrate.js +1324 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/output-parse.js +50 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/overview.js +10 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/pool.js +23 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/post-merge-fix.js +146 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/prompt-loader.js +51 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/prompt.js +967 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/prompts.md +301 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/serve.js +78 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/short-id.js +46 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/snapshot.js +267 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/types.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/validate.js +122 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/callback-call-sites.js +62 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/gap-audit/build.js +1291 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/gap-audit/index.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/area-ownership.js +392 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/build.js +1995 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/callback-flow.js +277 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/component-variants.js +725 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/index.js +15 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/names/index.js +12 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/names/policy.js +469 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/names/traceability.js +468 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/req-model/build.js +1066 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/req-model/index.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/android-interaction-registry.js +174 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/android.js +1062 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/area-titles.js +678 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/builder.js +350 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/compose-api-registry.js +395 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/compose-call-sites.js +2008 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/compose.js +9059 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/dynamic-repeated-call-sites.js +529 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/index.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/interaction-effects.js +1149 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/jvm.js +6272 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/normalize.js +33 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/pending-intents.js +565 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/resource-id.js +42 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/route-state-variants.js +781 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/state.js +234 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/types.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/android/extract.js +40 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/android/index.js +6 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/android/manifest.js +513 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/android/resources.js +398 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/android/types.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/android/views.js +447 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/android/xml-parser.js +175 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/cli.js +398 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/area-graph.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/artifact.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/common.js +16 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/diagnostic.js +10 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/gap-audit.js +14 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/index.js +11 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/name-traceability.js +26 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/raw-fact.js +40 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/req-model.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/run.js +19 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/semantic-completeness.js +11 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/source-facts.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/core/output-guard.js +41 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/core/stable-id.js +92 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/dashboard-cli.js +169 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/diagnostics.js +104 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/dump/dump.js +1028 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/dump/index.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/dump-cli.js +251 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/artifacts.js +49 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/index.js +18 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/quality-report.js +125 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/render.js +353 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/types.js +2 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/graph/paths.js +474 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/jvm/index.js +15 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/jvm/protocol.js +408 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/jvm/runner.js +452 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/pipeline/index.js +8 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/pipeline/output.js +165 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/pipeline/run-stage1.js +891 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/project/discovery.js +299 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/project/gradle-model.js +358 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/project/gradle-runner.js +165 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/project/resource-profile.js +60 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/project/types.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/spec-handoff-cli.js +151 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/spec-handoff.js +1004 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/stage2-cli.js +109 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/stage2-input.js +419 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/stage2-name-trace-input.js +95 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/area-graph.js +444 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/index.js +7 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/req-model.js +580 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/req-text.js +195 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/semantic-area-graph.js +1431 -0
- package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/types.js +1 -0
- package/skills/a2h-app-req-gen/scripts/reqgen-audit.mjs +298 -0
- package/skills/a2h-app-req-gen/scripts/reqgen-selfcheck.mjs +555 -0
- package/skills/a2h-code-review/SKILL.md +379 -0
- package/skills/{hmos-integration-test → a2h-integration-test}/README.md +6 -6
- package/skills/{hmos-integration-test → a2h-integration-test}/SKILL.md +6 -6
- package/skills/{hmos-integration-test → a2h-integration-test}/scripts/report-tool.mjs +1 -1
- package/skills/a2h-spec-design/SKILL.md +330 -0
- package/skills/a2h-spec-design/scripts/inspect_spec_design_inputs.mjs +207 -0
- package/skills/a2h-spec-design/scripts/move_spec_technical_reference.mjs +198 -0
- package/skills/a2h-spec-design/scripts/validate_spec_design_output.mjs +256 -0
- package/skills/a2h-spec-generate/SKILL.md +696 -0
- package/skills/a2h-spec-generate/references/trace-template.md +115 -0
- package/skills/a2h-spec-generate/scripts/parse_requirements.mjs +537 -0
- package/skills/a2h-spec-generate/template/REQ.txt +22 -0
- package/skills/a2h-spec-generate/template/REQ.xlsx +0 -0
- package/skills/a2h-spec-implement/SKILL.md +548 -0
- package/skills/a2h-spec-implement/references/harmony-pitfalls.md +186 -0
- package/skills/a2h-spec-implement/references/l1-unit-test.md +185 -0
- package/skills/a2h-spec-implement/references/l3-e2e-uitest.md +167 -0
- package/skills/a2h-spec-implement/references/test-core.md +132 -0
- package/skills/a2h-spec-implement/rules/arkts/arkts-standards.md +184 -0
- package/skills/a2h-spec-implement/rules/arkts/conventions/coding-style.md +96 -0
- package/skills/a2h-spec-implement/rules/arkts/conventions/security.md +126 -0
- package/skills/a2h-spec-implement/rules/arkts/language/arkts-rules.md +650 -0
- package/skills/a2h-spec-implement/rules/arkts/language/arkui-structure-rules.md +173 -0
- package/skills/a2h-spec-implement/rules/arkts/language/ts-to-arkts-rewrites.md +58 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/skills/a2h-spec-implement/rules/arkts/ui/component-cookbook.md +431 -0
- package/skills/a2h-spec-implement/rules/arkts/ui/state-management.md +152 -0
- package/skills/a2h-spec-implement/rules/arkts/ui/ui-quality.md +67 -0
- package/skills/a2h-spec-implement/rules/arkts/ui/ui-runtime-diagnosis.md +32 -0
- package/skills/a2h-spec-implement/rules/pipeline/build/package-set-collection.md +43 -0
- package/skills/a2h-spec-implement/scripts/_lib/common.mjs +97 -0
- package/skills/a2h-spec-implement/scripts/_lib/config.mjs +70 -0
- package/skills/a2h-spec-implement/scripts/_lib/lessons_cli.mjs +48 -0
- package/skills/a2h-spec-implement/scripts/build_lessons.mjs +24 -0
- package/skills/a2h-spec-implement/scripts/code_pattern_lessons.mjs +26 -0
- package/skills/a2h-spec-implement/scripts/device_ui.mjs +433 -0
- package/skills/a2h-spec-implement/scripts/device_ui_core.mjs +895 -0
- package/skills/a2h-spec-implement/scripts/ledger/aggregate_run.mjs +207 -0
- package/skills/a2h-spec-implement/scripts/manifest/emit_summary_line.mjs +37 -0
- package/skills/a2h-spec-implement/scripts/manifest/finalize_run.mjs +115 -0
- package/skills/a2h-spec-implement/scripts/manifest/render_final_summary.mjs +78 -0
- package/skills/a2h-spec-implement/scripts/manifest/root_mirror.mjs +137 -0
- package/skills/a2h-spec-implement/scripts/package.json +12 -0
- package/skills/a2h-spec-implement/scripts/state_propagation_check.mjs +676 -0
- package/skills/a2h-spec-implement/scripts/test/l2_run.mjs +244 -0
- package/skills/a2h-spec-implement/scripts/test/tp_coverage.mjs +231 -0
- package/skills/a2h-spec-implement/scripts/ui_memory.mjs +161 -0
- package/skills/a2h-spec-implement/scripts/utils/ensure_app.mjs +134 -0
- package/skills/a2h-ui-transfer/SKILL.md +20 -9
- package/skills/a2h-ui-transfer/scripts/arkts_static_check.js +80 -0
- package/skills/hmos-convert-pipeline/SKILL.md +7 -5
- package/skills/hmos-incremental-ui-align/README.md +7 -7
- package/skills/hmos-incremental-ui-align/SKILL.md +1 -1
- package/skills/hmos-incremental-ui-align/page_align.md +1 -1
- package/skills/hmos-spec-generate/SKILL.md +2 -2
- package/skills/hmos-spec-generate/scripts/parse_requirements.mjs +537 -0
- package/skills/hmos-fix-build-errors/SKILL.md +0 -266
- package/skills/hmos-fix-build-errors/references/arkts-strict-patterns.md +0 -219
- package/skills/hmos-fix-build-errors/references/known-patterns.md +0 -157
- package/skills/hmos-fix-build-errors/references/rdb-entity-pattern.md +0 -131
- package/skills/hmos-spec-generate/scripts/parse_requirements.ts +0 -515
- /package/skills/{hmos-integration-test → a2h-integration-test}/scripts/resolve-metadata-tool.mjs +0 -0
- /package/skills/{hmos-integration-test → a2h-integration-test}/scripts/self-test-runner.mjs +0 -0
- /package/skills/{hmos-integration-test → a2h-integration-test}/scripts/testcases-tool.mjs +0 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
mergeAreaReqMarkdown,
|
|
5
|
+
mergeAreaReqTxt,
|
|
6
|
+
mergeReqMarkdown,
|
|
7
|
+
mergeReqTxt,
|
|
8
|
+
} from "./merge.js";
|
|
9
|
+
import {
|
|
10
|
+
areaDirFor,
|
|
11
|
+
expandAreaRenderItems,
|
|
12
|
+
expandRenderItems,
|
|
13
|
+
renderDirFor,
|
|
14
|
+
} from "./orchestrate.js";
|
|
15
|
+
/** Read a finalized per-Feature output written by either Stage 2 dispatch
|
|
16
|
+
* mode. Exported for downstream handoff adapters so they can consume the
|
|
17
|
+
* structured result without reverse-parsing req text. */
|
|
18
|
+
export async function readAttempt(file) {
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(await readFile(file, "utf8"));
|
|
21
|
+
// A partially-written or failed output.json counts as "not rendered" —
|
|
22
|
+
// and so does a not-yet-finalized one: in subagent mode (ADR-0005)
|
|
23
|
+
// outputPath is first written by the subagent's own raw judgment (which
|
|
24
|
+
// can legitimately carry status "ok" before it has passed self-check)
|
|
25
|
+
// and only overwritten in place once `finalize` runs, so `finalized`
|
|
26
|
+
// must hold too, not just `status`.
|
|
27
|
+
return parsed.finalized === true &&
|
|
28
|
+
parsed.status === "ok" &&
|
|
29
|
+
typeof parsed.body === "string"
|
|
30
|
+
? parsed
|
|
31
|
+
: undefined;
|
|
32
|
+
} catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Read a finalized per-Area output written by Stage 2. */
|
|
37
|
+
export async function readAreaAttempt(file) {
|
|
38
|
+
try {
|
|
39
|
+
const parsed = JSON.parse(await readFile(file, "utf8"));
|
|
40
|
+
// A partially-written or failed output.json counts as "not rendered" —
|
|
41
|
+
// see readAttempt above for why `finalized` must hold too, not just
|
|
42
|
+
// `status`.
|
|
43
|
+
if (parsed.status !== "ok" || parsed.finalized !== true) return undefined;
|
|
44
|
+
const features = new Map();
|
|
45
|
+
for (const [id, featureResult] of Object.entries(parsed.features ?? {})) {
|
|
46
|
+
if (
|
|
47
|
+
featureResult.status === "ok" &&
|
|
48
|
+
typeof featureResult.body === "string"
|
|
49
|
+
) {
|
|
50
|
+
features.set(id, featureResult);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
status: "ok",
|
|
55
|
+
areaId: parsed.areaId,
|
|
56
|
+
...(parsed.areaDescription === undefined
|
|
57
|
+
? {}
|
|
58
|
+
: { areaDescription: parsed.areaDescription }),
|
|
59
|
+
...(parsed.accessPath === undefined
|
|
60
|
+
? {}
|
|
61
|
+
: { accessPath: parsed.accessPath }),
|
|
62
|
+
...(parsed.reachable === undefined
|
|
63
|
+
? {}
|
|
64
|
+
: { reachable: parsed.reachable }),
|
|
65
|
+
features,
|
|
66
|
+
...(parsed.addedFeatures === undefined
|
|
67
|
+
? {}
|
|
68
|
+
: { addedFeatures: parsed.addedFeatures }),
|
|
69
|
+
...(parsed.hasFeature === false ? { hasFeature: false } : {}),
|
|
70
|
+
attempt: parsed.attempt,
|
|
71
|
+
};
|
|
72
|
+
} catch {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Offline merge: reads rendering/ output.json files only, never touches a
|
|
77
|
+
* backend. Failed/missing entries fall back to the template body.
|
|
78
|
+
* `renderableReqModel` (post-filterRenderableAreas) decides which output.json
|
|
79
|
+
* files to look for; `fullReqModel` must be the same, unfiltered req-model
|
|
80
|
+
* templateText was rendered from, so the merge walk's Area/Feature positions
|
|
81
|
+
* line up with the template text — filtering only some Areas out of
|
|
82
|
+
* rendering must not desync it from the template it is walking. */
|
|
83
|
+
export async function snapshotReq(
|
|
84
|
+
renderableReqModel,
|
|
85
|
+
fullReqModel,
|
|
86
|
+
renderDir,
|
|
87
|
+
outputDirectory,
|
|
88
|
+
templateText,
|
|
89
|
+
mergeOptions = {},
|
|
90
|
+
clock = Date.now,
|
|
91
|
+
) {
|
|
92
|
+
const items = expandRenderItems(renderableReqModel);
|
|
93
|
+
const results = new Map();
|
|
94
|
+
for (const item of items) {
|
|
95
|
+
const file = path.join(
|
|
96
|
+
renderDir,
|
|
97
|
+
renderDirFor(item.feature.id),
|
|
98
|
+
"output.json",
|
|
99
|
+
);
|
|
100
|
+
const attempt = await readAttempt(file);
|
|
101
|
+
if (attempt !== undefined) results.set(item.feature.id, attempt);
|
|
102
|
+
}
|
|
103
|
+
const timestamp = new Date(clock()).toISOString().replace(/[:.]/g, "-");
|
|
104
|
+
const snapshotFile = path.join(outputDirectory, `req-${timestamp}.md`);
|
|
105
|
+
await writeFile(
|
|
106
|
+
snapshotFile,
|
|
107
|
+
mergeReqMarkdown(
|
|
108
|
+
fullReqModel,
|
|
109
|
+
renderableReqModel,
|
|
110
|
+
results,
|
|
111
|
+
templateText,
|
|
112
|
+
mergeOptions,
|
|
113
|
+
),
|
|
114
|
+
"utf8",
|
|
115
|
+
);
|
|
116
|
+
return {
|
|
117
|
+
snapshotFile,
|
|
118
|
+
total: items.length,
|
|
119
|
+
aiRendered: results.size,
|
|
120
|
+
fallback: items.length - results.size,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** Offline merge for per-Area rendering: reads rendering/ output.json files.
|
|
124
|
+
* See snapshotReq for why both a renderable and a full req-model are needed. */
|
|
125
|
+
export async function snapshotAreaReq(
|
|
126
|
+
renderableReqModel,
|
|
127
|
+
fullReqModel,
|
|
128
|
+
renderDir,
|
|
129
|
+
outputDirectory,
|
|
130
|
+
templateText,
|
|
131
|
+
mergeOptions = {},
|
|
132
|
+
clock = Date.now,
|
|
133
|
+
) {
|
|
134
|
+
const items = expandAreaRenderItems(renderableReqModel);
|
|
135
|
+
const areaResults = new Map();
|
|
136
|
+
let totalFeatures = 0;
|
|
137
|
+
let aiRendered = 0;
|
|
138
|
+
for (const item of items) {
|
|
139
|
+
totalFeatures += item.area.features.length;
|
|
140
|
+
const file = path.join(renderDir, areaDirFor(item.area.id), "output.json");
|
|
141
|
+
const attempt = await readAreaAttempt(file);
|
|
142
|
+
if (attempt !== undefined) {
|
|
143
|
+
areaResults.set(item.area.id, attempt);
|
|
144
|
+
aiRendered += attempt.features.size;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const timestamp = new Date(clock()).toISOString().replace(/[:.]/g, "-");
|
|
148
|
+
const snapshotFile = path.join(outputDirectory, `req-${timestamp}.md`);
|
|
149
|
+
await writeFile(
|
|
150
|
+
snapshotFile,
|
|
151
|
+
mergeAreaReqMarkdown(
|
|
152
|
+
fullReqModel,
|
|
153
|
+
renderableReqModel,
|
|
154
|
+
areaResults,
|
|
155
|
+
templateText,
|
|
156
|
+
mergeOptions,
|
|
157
|
+
),
|
|
158
|
+
"utf8",
|
|
159
|
+
);
|
|
160
|
+
return {
|
|
161
|
+
snapshotFile,
|
|
162
|
+
totalAreas: items.length,
|
|
163
|
+
totalFeatures,
|
|
164
|
+
aiRendered,
|
|
165
|
+
fallback: totalFeatures - aiRendered,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/** Write this run's compact req-N.txt sequence and remove only obsolete files
|
|
169
|
+
* in the Stage 2-owned numbered naming scheme. This keeps reruns from
|
|
170
|
+
* retaining an empty/stale file whose Area no longer has a Feature. */
|
|
171
|
+
export async function writeReqTxtFiles(outputDirectory, txtAreas) {
|
|
172
|
+
await mkdir(outputDirectory, { recursive: true });
|
|
173
|
+
await Promise.all(
|
|
174
|
+
txtAreas.map((content, index) =>
|
|
175
|
+
writeFile(
|
|
176
|
+
path.join(outputDirectory, `req-${index + 1}.txt`),
|
|
177
|
+
content,
|
|
178
|
+
"utf8",
|
|
179
|
+
),
|
|
180
|
+
),
|
|
181
|
+
);
|
|
182
|
+
const currentNames = new Set(
|
|
183
|
+
txtAreas.map((_, index) => `req-${index + 1}.txt`),
|
|
184
|
+
);
|
|
185
|
+
const entries = await readdir(outputDirectory, { withFileTypes: true });
|
|
186
|
+
await Promise.all(
|
|
187
|
+
entries.flatMap((entry) =>
|
|
188
|
+
entry.isFile() &&
|
|
189
|
+
/^req-\d+\.txt$/u.test(entry.name) &&
|
|
190
|
+
!currentNames.has(entry.name)
|
|
191
|
+
? [unlink(path.join(outputDirectory, entry.name))]
|
|
192
|
+
: [],
|
|
193
|
+
),
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
/** Offline merge for per-Area rendering → per-area req-{idx}.txt files. */
|
|
197
|
+
export async function snapshotAreaReqTxt(
|
|
198
|
+
renderableReqModel,
|
|
199
|
+
fullReqModel,
|
|
200
|
+
graph,
|
|
201
|
+
renderDir,
|
|
202
|
+
outputDirectory,
|
|
203
|
+
mergeOptions = {},
|
|
204
|
+
) {
|
|
205
|
+
const items = expandAreaRenderItems(renderableReqModel);
|
|
206
|
+
const areaResults = new Map();
|
|
207
|
+
let totalFeatures = 0;
|
|
208
|
+
let aiRendered = 0;
|
|
209
|
+
for (const item of items) {
|
|
210
|
+
totalFeatures += item.area.features.length;
|
|
211
|
+
const file = path.join(renderDir, areaDirFor(item.area.id), "output.json");
|
|
212
|
+
const attempt = await readAreaAttempt(file);
|
|
213
|
+
if (attempt !== undefined) {
|
|
214
|
+
areaResults.set(item.area.id, attempt);
|
|
215
|
+
aiRendered += attempt.features.size;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const txtAreas = mergeAreaReqTxt(
|
|
219
|
+
fullReqModel,
|
|
220
|
+
renderableReqModel,
|
|
221
|
+
areaResults,
|
|
222
|
+
graph,
|
|
223
|
+
mergeOptions,
|
|
224
|
+
);
|
|
225
|
+
await writeReqTxtFiles(outputDirectory, txtAreas);
|
|
226
|
+
return {
|
|
227
|
+
totalAreas: txtAreas.length,
|
|
228
|
+
totalFeatures,
|
|
229
|
+
aiRendered,
|
|
230
|
+
fallback: totalFeatures - aiRendered,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/** Offline merge for per-Feature rendering → per-area req-{idx}.txt files. */
|
|
234
|
+
export async function snapshotReqTxt(
|
|
235
|
+
renderableReqModel,
|
|
236
|
+
fullReqModel,
|
|
237
|
+
graph,
|
|
238
|
+
renderDir,
|
|
239
|
+
outputDirectory,
|
|
240
|
+
mergeOptions = {},
|
|
241
|
+
) {
|
|
242
|
+
const items = expandRenderItems(renderableReqModel);
|
|
243
|
+
const results = new Map();
|
|
244
|
+
for (const item of items) {
|
|
245
|
+
const file = path.join(
|
|
246
|
+
renderDir,
|
|
247
|
+
renderDirFor(item.feature.id),
|
|
248
|
+
"output.json",
|
|
249
|
+
);
|
|
250
|
+
const attempt = await readAttempt(file);
|
|
251
|
+
if (attempt !== undefined) results.set(item.feature.id, attempt);
|
|
252
|
+
}
|
|
253
|
+
const txtAreas = mergeReqTxt(
|
|
254
|
+
fullReqModel,
|
|
255
|
+
renderableReqModel,
|
|
256
|
+
results,
|
|
257
|
+
graph,
|
|
258
|
+
mergeOptions,
|
|
259
|
+
);
|
|
260
|
+
await writeReqTxtFiles(outputDirectory, txtAreas);
|
|
261
|
+
return {
|
|
262
|
+
totalAreas: txtAreas.length,
|
|
263
|
+
totalFeatures: items.length,
|
|
264
|
+
aiRendered: results.size,
|
|
265
|
+
fallback: items.length - results.size,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
async function checkCitation(citation, resolvedRoot, readFileFn) {
|
|
4
|
+
// Agents often echo absolute paths from their own Read/Grep tools even
|
|
5
|
+
// though the prompt asks for project-relative paths — accept either, but
|
|
6
|
+
// still enforce the project.root boundary.
|
|
7
|
+
const resolvedFile = path.isAbsolute(citation.file)
|
|
8
|
+
? path.resolve(citation.file)
|
|
9
|
+
: path.resolve(resolvedRoot, citation.file);
|
|
10
|
+
if (
|
|
11
|
+
resolvedFile !== resolvedRoot &&
|
|
12
|
+
!resolvedFile.startsWith(resolvedRoot + path.sep)
|
|
13
|
+
) {
|
|
14
|
+
return { citation, reason: "outside-project-root" };
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
await readFileFn(resolvedFile);
|
|
18
|
+
} catch {
|
|
19
|
+
return { citation, reason: "file-not-found" };
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
export async function validateCitations(
|
|
24
|
+
citations,
|
|
25
|
+
projectRoot,
|
|
26
|
+
readFileFn = (file) => readFile(file, "utf8"),
|
|
27
|
+
) {
|
|
28
|
+
const resolvedRoot = path.resolve(projectRoot);
|
|
29
|
+
const invalid = [];
|
|
30
|
+
for (const citation of citations) {
|
|
31
|
+
const problem = await checkCitation(citation, resolvedRoot, readFileFn);
|
|
32
|
+
if (problem !== undefined) invalid.push(problem);
|
|
33
|
+
}
|
|
34
|
+
return { valid: invalid.length === 0, invalid };
|
|
35
|
+
}
|
|
36
|
+
function deepEqual(a, b) {
|
|
37
|
+
if (a === b) return true;
|
|
38
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
39
|
+
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
40
|
+
}
|
|
41
|
+
if (
|
|
42
|
+
typeof a === "object" &&
|
|
43
|
+
typeof b === "object" &&
|
|
44
|
+
a !== null &&
|
|
45
|
+
b !== null
|
|
46
|
+
) {
|
|
47
|
+
const ka = Object.keys(a);
|
|
48
|
+
const kb = Object.keys(b);
|
|
49
|
+
if (ka.length !== kb.length) return false;
|
|
50
|
+
return ka.every((k) => deepEqual(a[k], b[k]));
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
// controlType is deliberately skipped: the new model's `trigger` carries
|
|
55
|
+
// different semantics than the old control.type (SPEC-0001 open question,
|
|
56
|
+
//评审倾向跳过). Only default/options are compared.
|
|
57
|
+
export function validateRestatedFacts(restatedFacts, feature) {
|
|
58
|
+
const mismatches = [];
|
|
59
|
+
const expectedDefault =
|
|
60
|
+
feature.defaultValue?.status === "resolved"
|
|
61
|
+
? feature.defaultValue.value
|
|
62
|
+
: undefined;
|
|
63
|
+
if (
|
|
64
|
+
expectedDefault !== undefined &&
|
|
65
|
+
!deepEqual(restatedFacts.default, expectedDefault)
|
|
66
|
+
) {
|
|
67
|
+
mismatches.push("default");
|
|
68
|
+
}
|
|
69
|
+
const expectedOptions = new Set(
|
|
70
|
+
feature.options.map((option) => option.value),
|
|
71
|
+
);
|
|
72
|
+
const actualOptions = new Set(restatedFacts.options ?? []);
|
|
73
|
+
const optionsMatch =
|
|
74
|
+
expectedOptions.size === actualOptions.size &&
|
|
75
|
+
[...expectedOptions].every((label) => actualOptions.has(label));
|
|
76
|
+
if (!optionsMatch) mismatches.push("options");
|
|
77
|
+
return { valid: mismatches.length === 0, mismatches };
|
|
78
|
+
}
|
|
79
|
+
/** Placeholder "待确认" must never survive into the final title.
|
|
80
|
+
* Resolved UI-literal names (translatable=false) must appear verbatim —
|
|
81
|
+
* the Agent may rewrite a code-identifier name (translatable=true), but
|
|
82
|
+
* it must not alter a name Stage 1 already resolved from UI text.
|
|
83
|
+
* Quote consistency is deferred to a non-blocking audit (overview.ts). */
|
|
84
|
+
export function validateTitle(agentTitle, parts) {
|
|
85
|
+
const problems = [];
|
|
86
|
+
// Still-pending: placeholder must be replaced
|
|
87
|
+
if (!parts.areaResolved && agentTitle.includes("Area 名称待确认")) {
|
|
88
|
+
problems.push("area-segment-still-pending");
|
|
89
|
+
}
|
|
90
|
+
if (!parts.featureResolved && agentTitle.includes("控件名称待确认")) {
|
|
91
|
+
problems.push("feature-segment-still-pending");
|
|
92
|
+
}
|
|
93
|
+
// Resolved UI-literal name must survive verbatim
|
|
94
|
+
if (
|
|
95
|
+
parts.areaResolved &&
|
|
96
|
+
!parts.areaTranslatable &&
|
|
97
|
+
!agentTitle.includes(parts.areaName)
|
|
98
|
+
) {
|
|
99
|
+
problems.push("resolved-area-segment-rewritten");
|
|
100
|
+
}
|
|
101
|
+
if (
|
|
102
|
+
parts.featureResolved &&
|
|
103
|
+
!parts.featureTranslatable &&
|
|
104
|
+
!agentTitle.includes(parts.featureName)
|
|
105
|
+
) {
|
|
106
|
+
problems.push("resolved-feature-segment-rewritten");
|
|
107
|
+
}
|
|
108
|
+
return { valid: problems.length === 0, problems };
|
|
109
|
+
}
|
|
110
|
+
/** Same rules as validateTitle, applied to every member of a merged req item
|
|
111
|
+
* (see FeatureRenderResult.mergedRequirementIds) — the one shared title must
|
|
112
|
+
* satisfy each merged Control's own name-inclusion requirement. Degenerates
|
|
113
|
+
* to validateTitle's result for a single-member list (the ordinary,
|
|
114
|
+
* non-merged case). */
|
|
115
|
+
export function validateTitleForMembers(agentTitle, partsList) {
|
|
116
|
+
const problems = new Set();
|
|
117
|
+
for (const parts of partsList) {
|
|
118
|
+
for (const problem of validateTitle(agentTitle, parts).problems)
|
|
119
|
+
problems.add(problem);
|
|
120
|
+
}
|
|
121
|
+
return { valid: problems.size === 0, problems: [...problems] };
|
|
122
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export function executionFlowsForward(flowKind) {
|
|
2
|
+
return (
|
|
3
|
+
flowKind === "listener-invocation" ||
|
|
4
|
+
flowKind === "direct-call" ||
|
|
5
|
+
flowKind === "event-channel"
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* True only for value-flow edges that represent an argument supplied to one
|
|
10
|
+
* concrete invocation. Declaration aliases intentionally have no call-site
|
|
11
|
+
* identity and keep their previous context-free behavior.
|
|
12
|
+
*/
|
|
13
|
+
export function isCallSiteArgumentStep(step) {
|
|
14
|
+
return (
|
|
15
|
+
step.flowKind === "argument-to-parameter" ||
|
|
16
|
+
(step.flowKind === "method-reference" &&
|
|
17
|
+
(step.callSiteKey !== undefined || step.parameterName !== undefined))
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Maintains the minimum call string needed to pair a formal callback slot
|
|
22
|
+
* with the actual callback supplied at the same invocation.
|
|
23
|
+
*
|
|
24
|
+
* A direct call pushes its raw call-site identity. Traversing a callback
|
|
25
|
+
* argument backwards (formal slot -> actual implementation) must match and
|
|
26
|
+
* pop that identity. If execution starts inside a reusable declaration there
|
|
27
|
+
* is no call-site frame; a unique actual is safe, while multiple actuals are
|
|
28
|
+
* deliberately rejected instead of being cross-wired.
|
|
29
|
+
*/
|
|
30
|
+
export function advanceCallSiteStack(
|
|
31
|
+
current,
|
|
32
|
+
step,
|
|
33
|
+
reverseArgumentCandidateCount,
|
|
34
|
+
) {
|
|
35
|
+
if (step.flowKind === "direct-call" && step.callSiteKey) {
|
|
36
|
+
return {
|
|
37
|
+
accepted: true,
|
|
38
|
+
callSiteStack: [...current, step.callSiteKey],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (!isCallSiteArgumentStep(step)) {
|
|
42
|
+
return { accepted: true, callSiteStack: current };
|
|
43
|
+
}
|
|
44
|
+
const expected = current.at(-1);
|
|
45
|
+
if (expected !== undefined) {
|
|
46
|
+
if (step.callSiteKey !== undefined) {
|
|
47
|
+
if (step.callSiteKey !== expected) {
|
|
48
|
+
return { accepted: false, callSiteStack: current };
|
|
49
|
+
}
|
|
50
|
+
} else if (reverseArgumentCandidateCount !== 1) {
|
|
51
|
+
return { accepted: false, callSiteStack: current };
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
accepted: true,
|
|
55
|
+
callSiteStack: current.slice(0, -1),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (reverseArgumentCandidateCount !== 1) {
|
|
59
|
+
return { accepted: false, callSiteStack: current };
|
|
60
|
+
}
|
|
61
|
+
return { accepted: true, callSiteStack: current };
|
|
62
|
+
}
|