@harmonyos-arkts/d2h 0.1.11 → 0.1.12

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 (126) hide show
  1. package/.claude-plugin/marketplace.json +15 -13
  2. package/.claude-plugin/plugin.json +13 -7
  3. package/AGENTS.md +5 -5
  4. package/README.md +212 -212
  5. package/agents/android-to-hmos-00-orchestrator.md +318 -318
  6. package/agents/d2h.md +157 -157
  7. package/dist/bin/install-opencode.js +30 -30
  8. package/docs/environment-check.md +86 -86
  9. package/install-opencode.sh +160 -160
  10. package/opencode/agents.json +16 -16
  11. package/opencode/vscode-d2h-package.json +7 -7
  12. package/opencode/vscode-d2h-plugin.mjs +29 -29
  13. package/package.json +54 -54
  14. package/schemas/android-source-manifest.schema.json +25 -25
  15. package/schemas/checkpoint-provenance.schema.json +67 -67
  16. package/schemas/final-acceptance.schema.json +29 -29
  17. package/schemas/managed-evidence-index.schema.json +15 -15
  18. package/schemas/managed-evidence.schema.json +114 -114
  19. package/schemas/migration-config.schema.json +51 -51
  20. package/schemas/migration-report-index.schema.json +39 -39
  21. package/schemas/migration-report-item.schema.json +51 -51
  22. package/schemas/migration-report-summary.schema.json +25 -25
  23. package/schemas/migration-status.schema.json +202 -202
  24. package/schemas/preflight.schema.json +60 -60
  25. package/schemas/source-order-audit.schema.json +16 -16
  26. package/schemas/source-provenance-event.schema.json +19 -19
  27. package/schemas/spec-app-shard.schema.json +45 -45
  28. package/schemas/spec-fact-corrections-shard.schema.json +13 -13
  29. package/schemas/spec-features-shard.schema.json +43 -43
  30. package/schemas/spec-index.schema.json +26 -26
  31. package/schemas/spec-interactions-shard.schema.json +40 -40
  32. package/schemas/spec-page.schema.json +98 -98
  33. package/schemas/spec-pages-index.schema.json +1 -1
  34. package/schemas/spec-unresolved-shard.schema.json +1 -1
  35. package/schemas/task-envelope.schema.json +109 -109
  36. package/schemas/task-plan.schema.json +341 -341
  37. package/scripts/check-environment.mjs +320 -320
  38. package/skills/android2hmos_resources_convert/SKILL.md +180 -180
  39. package/skills/android2hmos_resources_convert/references/image-conversion-rules.md +230 -230
  40. package/skills/android2hmos_resources_convert/references/svg-fix-patterns.md +175 -175
  41. package/skills/android2hmos_resources_convert/references/xml-drawable-to-svg-rules.md +513 -513
  42. package/skills/arkts-app-identity/SKILL.md +238 -238
  43. package/skills/arkts-i18n/SKILL.md +496 -496
  44. package/skills/arkts-i18n/evals/evals.json +84 -84
  45. package/skills/arkts-i18n/references/code-examples.md +302 -302
  46. package/skills/arkts-i18n/references/common-pitfalls.md +391 -391
  47. package/skills/arkts-i18n/references/dynamic-language-switch.md +604 -604
  48. package/skills/arkts-i18n/references/hardcoded-string-scanner.md +348 -348
  49. package/skills/arkts-i18n/references/language-codes.md +104 -104
  50. package/skills/arkts-i18n/references/resource-file-structure.md +775 -775
  51. package/skills/arkts-i18n/references/static-vs-dynamic.md +242 -242
  52. package/skills/arkts-i18n/references/v1-compat.md +244 -244
  53. package/skills/arkts-i18n/scripts/audit_i18n_completeness.sh +174 -174
  54. package/skills/arkts-icon-sizing/SKILL.md +211 -211
  55. package/skills/arkts-icon-sizing/scripts/icon_audit.py +131 -131
  56. package/skills/arkts-icon-sizing/scripts/icon_autofix.py +88 -88
  57. package/skills/arkts-icon-sizing/scripts/icon_dims.py +179 -179
  58. package/skills/arkts-icon-sizing/scripts/icon_fix.py +119 -119
  59. package/skills/arkts-mvvm-architecture/SKILL.md +613 -613
  60. package/skills/d2h-hypium-forge/SKILL.md +309 -309
  61. package/skills/d2h-hypium-forge/references/functional-spec-template.md +140 -140
  62. package/skills/d2h-hypium-forge/references/official-api.md +135 -135
  63. package/skills/d2h-hypium-forge/references/pitfalls.md +98 -98
  64. package/skills/d2h-hypium-forge/references/testability-template.md +71 -71
  65. package/skills/d2h-hypium-forge/scripts/_common_template.py +659 -659
  66. package/skills/d2h-hypium-forge/scripts/analyze_results.py +165 -165
  67. package/skills/d2h-hypium-forge/scripts/assert_audit.py +107 -107
  68. package/skills/d2h-hypium-forge/scripts/collect_runtime_pages.py +169 -169
  69. package/skills/d2h-hypium-forge/scripts/forge_report.py +325 -325
  70. package/skills/d2h-hypium-forge/scripts/inject_resource_ids.py +114 -114
  71. package/skills/d2h-hypium-forge/scripts/lint_asserts.py +80 -80
  72. package/skills/d2h-hypium-forge/scripts/lint_locate.py +60 -60
  73. package/skills/d2h-hypium-forge/scripts/merge_appgraph.py +249 -249
  74. package/skills/d2h-hypium-forge/scripts/precondition.py +140 -140
  75. package/skills/d2h-hypium-forge/scripts/preinject_ids.py +232 -232
  76. package/skills/d2h-hypium-forge/scripts/probe.py +197 -197
  77. package/skills/d2h-hypium-forge/scripts/run_direct.py +823 -823
  78. package/skills/d2h-hypium-forge/scripts/run_parallel.py +121 -121
  79. package/skills/d2h-hypium-forge/scripts/scan_features.py +255 -255
  80. package/skills/d2h-hypium-forge/scripts/upgrade_asserts.py +66 -66
  81. package/skills/d2h-hypium-forge/scripts/validate_scenarios.py +84 -84
  82. package/skills/d2h-page-develop/SKILL.md +112 -112
  83. package/skills/d2h-page-develop/agents/openai.yaml +7 -7
  84. package/skills/d2h-page-spec-generate/SKILL.md +206 -206
  85. package/skills/d2h-page-spec-generate/scripts/build_batch_report.py +227 -227
  86. package/skills/d2h-utg-ai-generate/SKILL.md +128 -128
  87. package/skills/d2h-utg-ai-generate/references/click-paths-schema.json +76 -76
  88. package/skills/d2h-utg-ai-generate/references/extraction-guide.md +34 -34
  89. package/skills/d2h-utg-ai-generate/references/facts-contract.md +96 -96
  90. package/skills/d2h-utg-ai-generate/references/page-schema.json +61 -61
  91. package/skills/d2h-utg-ai-generate/references/utg-schema.json +89 -89
  92. package/skills/d2h-utg-ai-generate/scripts/build_page_json.py +314 -314
  93. package/skills/d2h-utg-ai-generate/scripts/build_utg.py +123 -123
  94. package/skills/d2h-utg-ai-generate/scripts/capture_from_page_json.ts +280 -280
  95. package/skills/d2h-utg-ai-generate/scripts/utg_common.py +524 -524
  96. package/skills/d2h-utg-ai-generate/scripts/utg_html.py +489 -489
  97. package/skills/d2h-utg-ai-generate/scripts/validate_utg.py +69 -69
  98. package/skills/d2h-utg-ai-generate/scripts/vendor/D3-LICENSE +13 -13
  99. package/skills/d2h-utg-ai-generate/scripts/vendor/d3-7.9.0.min.js +2 -2
  100. package/skills/d2h-utg-ai-generate/tests/test_pipeline.py +369 -369
  101. package/skills/d2h-utg-static-generate/SKILL.md +73 -73
  102. package/skills/d2h-utg-static-generate/references/discoveries.md +38 -38
  103. package/skills/d2h-utg-static-generate/scripts/generate.py +499 -499
  104. package/skills/d2h-utg-static-generate/tests/test_static.py +335 -335
  105. package/skills/d2h-utg-static-generate/tests/verify-offline-html.py +60 -60
  106. package/skills/d2h-utg-static-generate/tests/verify-produced-fixture.py +131 -131
  107. package/skills/harmonyos-migration-playbook/SKILL.md +83 -83
  108. package/skills/harmonyos-migration-playbook/agents/openai.yaml +7 -7
  109. package/skills/harmonyos-migration-playbook/references/arkts-compile.md +24 -24
  110. package/skills/harmonyos-migration-playbook/references/harmony-runtime.md +53 -53
  111. package/skills/harmonyos-migration-playbook/references/lesson-lifecycle.md +45 -45
  112. package/skills/harmonyos-migration-playbook/references/protocol-e2e.md +23 -23
  113. package/skills/harmonyos-migration-playbook/references/ui-automation.md +53 -53
  114. package/skills/harmonyos-migration-playbook/references/windows-environment.md +38 -38
  115. package/skills/maintaining-migration-report/SKILL.md +144 -144
  116. package/skills/maintaining-migration-report/references/final-acceptance.md +48 -48
  117. package/skills/maintaining-migration-report/references/source-provenance.md +66 -66
  118. package/skills/managing-d2h-toolchain/SKILL.md +24 -24
  119. package/skills/managing-d2h-toolchain/environment-requirements.json +16 -16
  120. package/skills/managing-d2h-toolchain/scripts/manage-toolchain.mjs +98 -98
  121. package/skills/managing-d2h-toolchain/toolchain.json +16 -16
  122. package/skills/native-library-substitution/SKILL.md +384 -384
  123. package/skills/native-library-substitution/references/native-library-substitution.json +56905 -56905
  124. package/skills/native-library-substitution/references/native-library-substitution.md +163 -163
  125. package/skills/preparing-migration-workspace/SKILL.md +131 -131
  126. package/skills/reviewing-migration-process/SKILL.md +62 -62
@@ -1,169 +1,169 @@
1
- #!/usr/bin/env python3
2
- """
3
- collect_runtime_pages.py — 运行时页面文本采集器(设计前置,消灭上下文假设错位)。
4
-
5
- 流程: 启动 App → dump 首页 → 逐个点击底部 Tab → dump →
6
- 对每个已 dump 页面提取「可点击文本」(clickable 或短文本按钮类)逐个浅层点击 → dump 新页面 → 返回。
7
- 产出 runtime_pages.json: [{"key": "home|tab:我的|click:设置", "texts": [...], "hints": [...], "from": 父页key}]
8
-
9
- 用法: collect_runtime_pages.py --device 127.0.0.1:5559 --bundle com.x [--max-pages 20] [--out runtime_pages.json]
10
- """
11
- import argparse
12
- import json
13
- import re
14
- import subprocess
15
- import time
16
-
17
- from hypium import BY, MatchPattern
18
-
19
- HDC = '/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc'
20
-
21
-
22
- def dump_texts(sn, tag):
23
- """hdc dumpLayout → (texts, clickable_texts, hints)。"""
24
- dev = f'/data/local/tmp/rp_{tag}.json'
25
- subprocess.run(['bash', '-c', f'{HDC} -t {sn} shell uitest dumpLayout -p {dev}'],
26
- capture_output=True, timeout=30)
27
- local = f'/tmp/rp_{tag}.json'
28
- subprocess.run(['bash', '-c', f'{HDC} -t {sn} file recv {dev} {local}'],
29
- capture_output=True, timeout=30)
30
- try:
31
- d = json.load(open(local, encoding='utf-8'))
32
- except Exception:
33
- return [], [], []
34
- texts, clickables, hints = [], [], []
35
-
36
- def walk(n):
37
- a = n.get('attributes', {})
38
- t = a.get('text')
39
- if t:
40
- ts = str(t).strip()
41
- if ts and len(ts) < 20 and not re.match(r'^[\d:,.\s]+$', ts):
42
- texts.append(ts)
43
- if str(a.get('clickable')) == 'true':
44
- clickables.append(ts)
45
- if a.get('hint'):
46
- hints.append(str(a['hint'])[:16])
47
- for c in n.get('children', []) or []:
48
- walk(c)
49
-
50
- walk(d)
51
- seen_t, seen_c = [], []
52
- for t in texts:
53
- if t not in seen_t:
54
- seen_t.append(t)
55
- for t in clickables:
56
- if t not in seen_c:
57
- seen_c.append(t)
58
- return seen_t, seen_c, hints
59
-
60
-
61
- def main():
62
- ap = argparse.ArgumentParser()
63
- ap.add_argument('--device', required=True)
64
- ap.add_argument('--bundle', required=True)
65
- ap.add_argument('--ability', default='EntryAbility')
66
- ap.add_argument('--max-pages', type=int, default=18)
67
- ap.add_argument('--out', default='runtime_pages.json')
68
- args = ap.parse_args()
69
-
70
- from hypium import UiDriver
71
- d = UiDriver.connect(device_sn=args.device)
72
- # 热启动(冷启动后 UI agent 短暂不可用,实测文本点击会静默失败)
73
- d.start_app(args.bundle, args.ability)
74
- for _ in range(20):
75
- try:
76
- if d.find_component(BY.text('首页')):
77
- break
78
- except Exception:
79
- pass
80
- time.sleep(1)
81
- time.sleep(2)
82
-
83
- pages = []
84
- queue = [] # (key, clickable_texts) 待浅探
85
-
86
- def cap(key):
87
- texts, clicks, hints = dump_texts(args.device, abs(hash(key)) % 10000)
88
- pages.append({'key': key, 'texts': texts[:40], 'clickables': clicks[:15], 'hints': hints[:5]})
89
- print(f'[+] {key}: {len(texts)} 文本 / {len(clicks)} 可点', flush=True)
90
- return clicks
91
-
92
- clicks = cap('home')
93
- queue.append(('home', clicks))
94
-
95
- # 底部 Tab(取 home 可点文本中位于常见 Tab 词表的)
96
- TABS = ['首页', '主页', '分类', '购物车', '我的', '预约', '课程', '发现']
97
- if not clicks:
98
- clicks = [t for t in pages[0]['texts'] if 2 <= len(t) <= 6]
99
- pages[0]['clickables'] = clicks
100
- tab_hits = [t for t in clicks if any(tw in t for tw in TABS)]
101
- for t in tab_hits[:5]:
102
- try:
103
- click_text(d, t)
104
- time.sleep(1.8)
105
- key = f'tab:{t}'
106
- c2 = cap(key)
107
- queue.append((key, c2))
108
- # 回 home 供下一个 tab 点击
109
- try:
110
- click_text(d, '首页')
111
- except Exception:
112
- d.press_back()
113
- time.sleep(1.5)
114
- except Exception as e:
115
- print(f' [x] tab {t}: {str(e)[:60]}', flush=True)
116
-
117
- # BFS 浅层:每页最多取 2 个入口点击(限页数)
118
- visited_clicks = set()
119
- while len(pages) < args.max_pages and queue:
120
- pkey, clicks = queue.pop(0)
121
- if not clicks:
122
- pg = next((p for p in pages if p['key'] == pkey), None)
123
- clicks = [t for t in (pg['texts'] if pg else []) if 2 <= len(t) <= 6]
124
- n = 0
125
- for t in clicks:
126
- if len(pages) >= args.max_pages or n >= 2:
127
- break
128
- if t in visited_clicks or len(t) < 2 or t in ('返回', '确定', '取消'):
129
- continue
130
- visited_clicks.add(t)
131
- try:
132
- click_text(d, t)
133
- time.sleep(1.8)
134
- key = f'{pkey}>{t}'
135
- c3 = cap(key)
136
- queue.append((key, c3))
137
- n += 1
138
- except Exception:
139
- continue
140
- finally:
141
- try:
142
- d.press_back(); time.sleep(1.2)
143
- except Exception:
144
- pass
145
-
146
- json.dump(pages, open(args.out, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
147
- print(f'采集完成: {len(pages)} 页 → {args.out}')
148
-
149
-
150
- def click_text(d, txt, wait=6):
151
- import time as _t
152
- deadline = _t.time() + wait
153
- while _t.time() < deadline:
154
- try:
155
- comps = d.find_all_components(BY.text(txt, MatchPattern.CONTAINS))
156
- if comps:
157
- c = comps[-1]
158
- b = c.getBounds()
159
- d.touch(((b.left + b.right) // 2, (b.top + b.bottom) // 2))
160
- _t.sleep(1.2)
161
- return
162
- except Exception:
163
- pass
164
- _t.sleep(0.4)
165
- raise AssertionError('not clickable: ' + txt)
166
-
167
-
168
- if __name__ == '__main__':
169
- main()
1
+ #!/usr/bin/env python3
2
+ """
3
+ collect_runtime_pages.py — 运行时页面文本采集器(设计前置,消灭上下文假设错位)。
4
+
5
+ 流程: 启动 App → dump 首页 → 逐个点击底部 Tab → dump →
6
+ 对每个已 dump 页面提取「可点击文本」(clickable 或短文本按钮类)逐个浅层点击 → dump 新页面 → 返回。
7
+ 产出 runtime_pages.json: [{"key": "home|tab:我的|click:设置", "texts": [...], "hints": [...], "from": 父页key}]
8
+
9
+ 用法: collect_runtime_pages.py --device 127.0.0.1:5559 --bundle com.x [--max-pages 20] [--out runtime_pages.json]
10
+ """
11
+ import argparse
12
+ import json
13
+ import re
14
+ import subprocess
15
+ import time
16
+
17
+ from hypium import BY, MatchPattern
18
+
19
+ HDC = '/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc'
20
+
21
+
22
+ def dump_texts(sn, tag):
23
+ """hdc dumpLayout → (texts, clickable_texts, hints)。"""
24
+ dev = f'/data/local/tmp/rp_{tag}.json'
25
+ subprocess.run(['bash', '-c', f'{HDC} -t {sn} shell uitest dumpLayout -p {dev}'],
26
+ capture_output=True, timeout=30)
27
+ local = f'/tmp/rp_{tag}.json'
28
+ subprocess.run(['bash', '-c', f'{HDC} -t {sn} file recv {dev} {local}'],
29
+ capture_output=True, timeout=30)
30
+ try:
31
+ d = json.load(open(local, encoding='utf-8'))
32
+ except Exception:
33
+ return [], [], []
34
+ texts, clickables, hints = [], [], []
35
+
36
+ def walk(n):
37
+ a = n.get('attributes', {})
38
+ t = a.get('text')
39
+ if t:
40
+ ts = str(t).strip()
41
+ if ts and len(ts) < 20 and not re.match(r'^[\d:,.\s]+$', ts):
42
+ texts.append(ts)
43
+ if str(a.get('clickable')) == 'true':
44
+ clickables.append(ts)
45
+ if a.get('hint'):
46
+ hints.append(str(a['hint'])[:16])
47
+ for c in n.get('children', []) or []:
48
+ walk(c)
49
+
50
+ walk(d)
51
+ seen_t, seen_c = [], []
52
+ for t in texts:
53
+ if t not in seen_t:
54
+ seen_t.append(t)
55
+ for t in clickables:
56
+ if t not in seen_c:
57
+ seen_c.append(t)
58
+ return seen_t, seen_c, hints
59
+
60
+
61
+ def main():
62
+ ap = argparse.ArgumentParser()
63
+ ap.add_argument('--device', required=True)
64
+ ap.add_argument('--bundle', required=True)
65
+ ap.add_argument('--ability', default='EntryAbility')
66
+ ap.add_argument('--max-pages', type=int, default=18)
67
+ ap.add_argument('--out', default='runtime_pages.json')
68
+ args = ap.parse_args()
69
+
70
+ from hypium import UiDriver
71
+ d = UiDriver.connect(device_sn=args.device)
72
+ # 热启动(冷启动后 UI agent 短暂不可用,实测文本点击会静默失败)
73
+ d.start_app(args.bundle, args.ability)
74
+ for _ in range(20):
75
+ try:
76
+ if d.find_component(BY.text('首页')):
77
+ break
78
+ except Exception:
79
+ pass
80
+ time.sleep(1)
81
+ time.sleep(2)
82
+
83
+ pages = []
84
+ queue = [] # (key, clickable_texts) 待浅探
85
+
86
+ def cap(key):
87
+ texts, clicks, hints = dump_texts(args.device, abs(hash(key)) % 10000)
88
+ pages.append({'key': key, 'texts': texts[:40], 'clickables': clicks[:15], 'hints': hints[:5]})
89
+ print(f'[+] {key}: {len(texts)} 文本 / {len(clicks)} 可点', flush=True)
90
+ return clicks
91
+
92
+ clicks = cap('home')
93
+ queue.append(('home', clicks))
94
+
95
+ # 底部 Tab(取 home 可点文本中位于常见 Tab 词表的)
96
+ TABS = ['首页', '主页', '分类', '购物车', '我的', '预约', '课程', '发现']
97
+ if not clicks:
98
+ clicks = [t for t in pages[0]['texts'] if 2 <= len(t) <= 6]
99
+ pages[0]['clickables'] = clicks
100
+ tab_hits = [t for t in clicks if any(tw in t for tw in TABS)]
101
+ for t in tab_hits[:5]:
102
+ try:
103
+ click_text(d, t)
104
+ time.sleep(1.8)
105
+ key = f'tab:{t}'
106
+ c2 = cap(key)
107
+ queue.append((key, c2))
108
+ # 回 home 供下一个 tab 点击
109
+ try:
110
+ click_text(d, '首页')
111
+ except Exception:
112
+ d.press_back()
113
+ time.sleep(1.5)
114
+ except Exception as e:
115
+ print(f' [x] tab {t}: {str(e)[:60]}', flush=True)
116
+
117
+ # BFS 浅层:每页最多取 2 个入口点击(限页数)
118
+ visited_clicks = set()
119
+ while len(pages) < args.max_pages and queue:
120
+ pkey, clicks = queue.pop(0)
121
+ if not clicks:
122
+ pg = next((p for p in pages if p['key'] == pkey), None)
123
+ clicks = [t for t in (pg['texts'] if pg else []) if 2 <= len(t) <= 6]
124
+ n = 0
125
+ for t in clicks:
126
+ if len(pages) >= args.max_pages or n >= 2:
127
+ break
128
+ if t in visited_clicks or len(t) < 2 or t in ('返回', '确定', '取消'):
129
+ continue
130
+ visited_clicks.add(t)
131
+ try:
132
+ click_text(d, t)
133
+ time.sleep(1.8)
134
+ key = f'{pkey}>{t}'
135
+ c3 = cap(key)
136
+ queue.append((key, c3))
137
+ n += 1
138
+ except Exception:
139
+ continue
140
+ finally:
141
+ try:
142
+ d.press_back(); time.sleep(1.2)
143
+ except Exception:
144
+ pass
145
+
146
+ json.dump(pages, open(args.out, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
147
+ print(f'采集完成: {len(pages)} 页 → {args.out}')
148
+
149
+
150
+ def click_text(d, txt, wait=6):
151
+ import time as _t
152
+ deadline = _t.time() + wait
153
+ while _t.time() < deadline:
154
+ try:
155
+ comps = d.find_all_components(BY.text(txt, MatchPattern.CONTAINS))
156
+ if comps:
157
+ c = comps[-1]
158
+ b = c.getBounds()
159
+ d.touch(((b.left + b.right) // 2, (b.top + b.bottom) // 2))
160
+ _t.sleep(1.2)
161
+ return
162
+ except Exception:
163
+ pass
164
+ _t.sleep(0.4)
165
+ raise AssertionError('not clickable: ' + txt)
166
+
167
+
168
+ if __name__ == '__main__':
169
+ main()