@harmonyos-arkts/d2h 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.md +5 -0
- package/README.md +19 -18
- package/agents/android-to-hmos-00-orchestrator.md +1 -1
- package/agents/d2h.md +101 -285
- package/dist/bin/install-opencode.js +7 -2
- package/dist/src/install-opencode.js +20 -1
- package/dist/src/install-vscode.js +6 -3
- package/dist/src/metrics-plugin.js +20 -0
- package/package.json +2 -1
- package/scripts/check-environment.mjs +1 -2
- package/skills/d2h-hypium-forge/SKILL.md +59 -2
- package/skills/d2h-hypium-forge/scripts/_common_template.py +85 -40
- package/skills/d2h-hypium-forge/scripts/analyze_results.py +11 -2
- package/skills/d2h-hypium-forge/scripts/probe.py +197 -0
- package/skills/d2h-hypium-forge/scripts/run_direct.py +464 -33
- package/skills/d2h-page-develop/SKILL.md +112 -0
- package/skills/d2h-page-develop/agents/openai.yaml +7 -0
- package/skills/d2h-page-spec-generate/SKILL.md +206 -0
- package/skills/d2h-page-spec-generate/scripts/build_batch_report.py +227 -0
- package/skills/managing-d2h-toolchain/SKILL.md +14 -13
- package/skills/managing-d2h-toolchain/scripts/manage-toolchain.mjs +98 -0
- package/skills/appgraph-rule-audit/SKILL.md +0 -77
- package/skills/appgraph-rule-audit/references/audit-contract.md +0 -47
- package/skills/appgraph-rule-audit/references/recommendation-schema.md +0 -41
- package/skills/appgraph-rule-audit/schemas/rule-opportunities.schema.json +0 -125
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: d2h-page-develop
|
|
3
|
+
description: Implement ordered Android-to-HarmonyOS page tasks from pages.json, batch_report.md, and page-scoped spec.md files. Use during page development when the current agent must complete each page serially through ArkTS implementation, managed build, Python Hypium tests, scoped commits, migration-report evidence, and in-place ledger updates before starting the next page. Do not delegate page work to subagents.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Page development loop
|
|
7
|
+
|
|
8
|
+
Implement and verify one ordered page task at a time in the current agent. Own each page's complete loop and do not delegate page implementation, build, testing, reporting, commits, or ledger updates to subagents.
|
|
9
|
+
|
|
10
|
+
## Inputs and boundaries
|
|
11
|
+
|
|
12
|
+
- Use `.migration/page-specs/pages.json` as the immutable page order and `batch_report.md` as the mutable execution ledger.
|
|
13
|
+
- Use the selected page package's `spec.md` as the authority for page scope, behavior, acceptance sequences, Android evidence, and expected HarmonyOS files.
|
|
14
|
+
- Read `.migration/utg/page.json` when the Spec references a UTG node or the arrival path needs clarification. Read cited Android source before implementing behavior.
|
|
15
|
+
- Do not require or generate `ui-design.md`, copied screenshots, copied `view.xml`, or any other page-package artifact. Each `page_NNNN_<name>-<id>/` directory continues to contain only `spec.md`.
|
|
16
|
+
- Do not regenerate `pages.json`, page Specs, or `batch_report.md` during ordinary development. Correct an owning artifact only when current source proves it wrong, record the reason, and preserve execution history.
|
|
17
|
+
- Use `droid2hmos` managed build and test entry points. Do not use task-planning commands or static scripts to choose or execute page work.
|
|
18
|
+
- Preserve unrelated user changes. Never reset, discard, or include them in a page commit.
|
|
19
|
+
|
|
20
|
+
## Single-agent mode
|
|
21
|
+
|
|
22
|
+
1. Read `pages.json` and `batch_report.md`; use AI judgment to verify their task IDs, order, links, counts, and current states agree.
|
|
23
|
+
2. Select the earliest ordered page whose development/build/validation states are not `implemented/passed/passed` and whose declared dependencies are satisfied.
|
|
24
|
+
3. Resolve the page package, Android root, HarmonyOS root, repository root, current `HEAD`, Git status, device target, and task evidence directory.
|
|
25
|
+
4. Record the current `HEAD` and Git status as the task baseline, then execute the selected page through the complete per-page loop below.
|
|
26
|
+
5. Verify the resulting implementation, current managed build/test evidence, migration report, commits, batch ledger, and Git status.
|
|
27
|
+
6. If the page is incomplete or fails verification, repair the same page; do not select another page.
|
|
28
|
+
7. Only after the selected task is genuinely `implemented/passed/passed` may the current agent select the next task.
|
|
29
|
+
8. After all tasks are complete, explicitly enumerate every Python Hypium test list and run one managed batch regression. Append the batch evidence to `batch_report.md` and the migration report.
|
|
30
|
+
|
|
31
|
+
## Per-page execution
|
|
32
|
+
|
|
33
|
+
### 1. Claim and understand the page
|
|
34
|
+
|
|
35
|
+
- Confirm the task is the earliest incomplete eligible row and no other task is `in_progress`.
|
|
36
|
+
- Compare the checkout with the recorded task baseline. Preserve and avoid unrelated dirty files; if ownership conflicts with a build-affecting file, return the exact conflict instead of overwriting it.
|
|
37
|
+
- Mark only the selected task `in_progress` in the working copy of `batch_report.md`.
|
|
38
|
+
- Read the complete `spec.md`, the referenced `.migration/utg/page.json` node, every cited Fact, and every cited Android source file. Follow handlers, state transitions, repositories, navigation, persistence, error paths, and platform side effects far enough to establish the observable result.
|
|
39
|
+
- Inspect the HarmonyOS architecture, routes, resources, shared components, tests, and current implementation. Load `arkts-mvvm-architecture` before planning or writing ArkTS.
|
|
40
|
+
- Build a private checklist mapping every `F-xxx` to reachable code, a stable semantic locator, an executed test assertion, and an observable result. Do not create another planning file.
|
|
41
|
+
- Resume valid existing work for this same task instead of duplicating it.
|
|
42
|
+
|
|
43
|
+
### 2. Implement
|
|
44
|
+
|
|
45
|
+
- Implement all page-scoped UI, navigation, overlays, state transitions, persistence/data effects, error paths, resources, and required shared integration.
|
|
46
|
+
- Use the Android source and observable behavior for functional truth. Use HarmonyOS-native architecture and components for the target implementation.
|
|
47
|
+
- Give tested interactive elements stable, unique semantic locators. Do not add controls solely to make testing easier.
|
|
48
|
+
- Load the applicable domain Skill for identity, i18n, drawable conversion, icon sizing, or third-party substitution when the page touches that domain.
|
|
49
|
+
- Keep shared changes limited to capabilities this page actually needs and record downstream consumers.
|
|
50
|
+
- Do not leave stubs, fixed success values, swallowed errors, unreachable pages, placeholder controls, or TODO implementations.
|
|
51
|
+
|
|
52
|
+
### 3. Managed build
|
|
53
|
+
|
|
54
|
+
- Run a fresh, non-interactive, bounded build through `droid2hmos build harmony <ANDROID_PROJECT>` using the resolved project configuration.
|
|
55
|
+
- Save the exact command, exit status, timestamps, relevant log, produced HAP path, and HAP SHA-256 in the task evidence directory.
|
|
56
|
+
- Treat compilation errors caused or exposed by the implementation as work to fix. Repeat edit/build until the managed build passes.
|
|
57
|
+
- An older HAP, static analysis result, direct Hvigor run, or previous log is not current build evidence.
|
|
58
|
+
|
|
59
|
+
### 4. Managed page tests
|
|
60
|
+
|
|
61
|
+
- Load `d2h-hypium-forge`. Add or update executable Python Hypium tests for every `F-xxx`, with paired `.py` and `.json` test-list assets and stable semantic locators.
|
|
62
|
+
- Cover navigation or overlay lifecycle, state changes, data effects, and error behavior required by the Spec. Assertions must prove the declared result, not merely that a page or button exists.
|
|
63
|
+
- Run the affected lists through the managed entry point:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
droid2hmos test harmony <ANDROID_PROJECT> \
|
|
67
|
+
--runner python --hypium-project <HARMONY_PROJECT>/.hypium_forge \
|
|
68
|
+
--test-list <AFFECTED_LIST> --target <DEVICE> \
|
|
69
|
+
--ref <ACTUALLY_ASSERTED_REF>...
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- Save the exact command, result, native report/log, device target, timestamps, hashes, and returned `managedEvidence` in the task evidence directory.
|
|
73
|
+
- A written-but-unexecuted test, screenshot-only check, coordinate-only replay, direct local runner, old log, or zero-test result is not a pass.
|
|
74
|
+
- Fix implementation or test defects and repeat managed build/test until both pass. Only a persistent external environment, signing, or device failure may become `blocked`, after bounded retries with diagnostics recorded.
|
|
75
|
+
|
|
76
|
+
### 5. Report and commit
|
|
77
|
+
|
|
78
|
+
- Load `maintaining-migration-report` while evidence is fresh. Record real HarmonyOS files, Android source provenance, current managed evidence, differences, and source-proven discoveries; run report validation.
|
|
79
|
+
- Inspect Git status and diff. Stage only the selected page's implementation, resources, tests, necessary shared files, and a source-proven correction to this page's `spec.md` when required. Do not include unrelated changes.
|
|
80
|
+
- Create a scoped implementation commit only after the managed build and page tests pass. Record its commit ID.
|
|
81
|
+
- If build-affecting page changes remain after the commit, correct the commit and rerun build/test so the evidence proves the committed tree.
|
|
82
|
+
- Update the existing `batch_report.md` queue row, detail section, counts, evidence, files, implementation commit, timestamp, blocker, and chronological notes in place. Do not rerun `build_batch_report.py`.
|
|
83
|
+
- Set `implemented/passed/passed` only when all three states are supported by current evidence. Use AI inspection to confirm queue/detail/count consistency and preserve all prior history.
|
|
84
|
+
- Commit the ledger and immutable task evidence separately from the implementation commit. Do not create a self-referential commit field.
|
|
85
|
+
|
|
86
|
+
## Page completion verification
|
|
87
|
+
|
|
88
|
+
Before marking the page complete, confirm:
|
|
89
|
+
|
|
90
|
+
- every `F-xxx` has reachable implementation, a stable locator, and an actually executed assertion;
|
|
91
|
+
- the page is reachable from the real app entry without a test-only route or replacement control;
|
|
92
|
+
- build logs, HAP hash, test reports, managed evidence, and migration-report refs correspond to the implementation commit;
|
|
93
|
+
- `batch_report.md` is internally consistent and the selected row is `implemented/passed/passed`;
|
|
94
|
+
- both scoped commits exist and no uncommitted change owned by the page remains;
|
|
95
|
+
- user changes and other pages were not reset or included;
|
|
96
|
+
- no implementation defect was reclassified as a platform difference or external blocker.
|
|
97
|
+
|
|
98
|
+
If verification fails, repair the same task before selecting or starting the next task.
|
|
99
|
+
|
|
100
|
+
## Batch regression
|
|
101
|
+
|
|
102
|
+
After every page task is complete:
|
|
103
|
+
|
|
104
|
+
1. Enumerate every current Python Hypium test list explicitly; the Python runner does not use `--all`.
|
|
105
|
+
2. Run one managed command with all required `--test-list` values on the qualified device, using only refs actually asserted by the batch.
|
|
106
|
+
3. Require non-zero execution with no failures, errors, or ignored tests.
|
|
107
|
+
4. Append the managed batch evidence and timestamp to `batch_report.md`, then update and validate the migration report.
|
|
108
|
+
5. A targeted Python batch receipt does not replace the separate ArkTS `--all` receipt required by the Migration Kernel final completion gate.
|
|
109
|
+
|
|
110
|
+
## Final result
|
|
111
|
+
|
|
112
|
+
Return each task ID and page, final states, implementation and test files, managed build command/HAP/evidence, managed test command/evidence, implementation and ledger commit IDs, batch regression evidence, unrelated Git changes left untouched, and any genuine blocker or unresolved item.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "HarmonyOS Page Development Loop"
|
|
3
|
+
short_description: "按 spec.md 完成单页面受管开发、测试与提交闭环"
|
|
4
|
+
default_prompt: "Use $d2h-page-develop to serially implement ordered HarmonyOS page tasks from pages.json, batch_report.md, and spec.md in the current agent without delegating page work to subagents."
|
|
5
|
+
|
|
6
|
+
policy:
|
|
7
|
+
allow_implicit_invocation: true
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: d2h-page-spec-generate
|
|
3
|
+
description: Generate an AI-authored pages.json plan and page-scoped Android-to-HarmonyOS spec.md files from migration Facts, `.migration/utg/page.json`, source code, and existing HarmonyOS implementation, then build batch_report.md with the bundled renderer. Use when pages, dialogs, sheets, or page modes need evidence-backed development specifications and ordered execution records without copied UI artifacts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Page Spec generation
|
|
7
|
+
|
|
8
|
+
Generate one implementation-ready `spec.md` for every Android page, dialog, sheet, and behaviorally distinct page mode. The AI determines page boundaries, evidence mapping, dependencies, and development order by reading the actual migration workspace and source code.
|
|
9
|
+
|
|
10
|
+
Do not invoke task-planning, graph-generation, migration, or page-validation scripts. Do not modify Android source, HarmonyOS source, `.migration/spec/`, `.migration/utg/`, `.migration/tasks/`, or the migration report.
|
|
11
|
+
|
|
12
|
+
## Inputs
|
|
13
|
+
|
|
14
|
+
Resolve these paths before writing:
|
|
15
|
+
|
|
16
|
+
- `migration_root`: workspace containing `.migration/`.
|
|
17
|
+
- `spec_root`: `<migration_root>/.migration/spec`; require `index.json` and `facts/`.
|
|
18
|
+
- `page_plan`: require `<migration_root>/.migration/utg/page.json`; this is the source-derived page and navigation plan produced by the UTG stage.
|
|
19
|
+
- `android_root`: `.migration/config.json.androidProject`, unless explicitly supplied.
|
|
20
|
+
- `harmony_root`: `.migration/config.json.harmonyProject`, resolved relative to `migration_root` when not absolute, unless explicitly supplied.
|
|
21
|
+
- `legacy_tasks_root`: optional `<migration_root>/.migration/tasks`; use existing briefs, core facts, source context, and acceptance files only as read-only evidence from an older flow.
|
|
22
|
+
- `output_root`: default `<migration_root>/.migration/page-specs`.
|
|
23
|
+
|
|
24
|
+
Facts and legacy Task artifacts are indexes, not substitutes for Android source. Existing HarmonyOS files and tests are implementation evidence, not proof that a behavior is complete.
|
|
25
|
+
|
|
26
|
+
## Output contract
|
|
27
|
+
|
|
28
|
+
Each page unit contains only `spec.md`. `pages.json` and `batch_report.md` live at the output root:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
.migration/page-specs/
|
|
32
|
+
├── pages.json
|
|
33
|
+
├── batch_report.md
|
|
34
|
+
├── page_0001_<name>-<id>/
|
|
35
|
+
│ └── spec.md
|
|
36
|
+
├── page_0002_<name>-<id>/
|
|
37
|
+
│ └── spec.md
|
|
38
|
+
└── ...
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Directory names encode the AI-selected development order. Use a four-digit sequence and a stable unique suffix derived from the strongest page identity already present in Facts or `page.json`. Re-running against unchanged evidence must preserve existing directory names and order unless the evidence proves the previous boundary or dependency order was wrong.
|
|
42
|
+
|
|
43
|
+
## Workflow
|
|
44
|
+
|
|
45
|
+
### 1. Read the complete evidence index
|
|
46
|
+
|
|
47
|
+
1. Read `.migration/spec/index.json`, `facts/app.json`, all `facts/pages/*.json`, `facts/interactions.json`, and `facts/unresolved.json`.
|
|
48
|
+
2. Read `.migration/utg/page.json` completely. Use `pages[]` as the page/navigation index and consume each node's `node_id`, `kind`, `label`, `declared_at`, `required_state`, `expected`, `reachable`, `depth`, `ui_sequence`, `path_text`, `steps`, and `skip_reason` when present.
|
|
49
|
+
3. Treat `page.json.source.utg` and `page.json.source.click_paths` as provenance links. Read those referenced UTG artifacts only when page boundaries, transitions, guards, or selectors need clarification.
|
|
50
|
+
4. If legacy `.migration/tasks/` exists, read its package briefs and associated `core-facts.json`, `source-context.json`, and `acceptance.json` only to recover behavior refs and source closure. Never inherit its package boundary blindly and never execute its task commands.
|
|
51
|
+
5. Read the current migration report to understand existing mappings and unresolved items, without treating report status as proof of implementation.
|
|
52
|
+
6. Inspect HarmonyOS route registration, `.ets`/`.ts` components, shared state, resources, and tests to distinguish existing implementation from planned work.
|
|
53
|
+
|
|
54
|
+
### 2. Determine page units with AI reasoning
|
|
55
|
+
|
|
56
|
+
1. Start from `page.json.pages[]`, then join each page node to Facts surfaces, entries, controls, and interactions by stable ref, declared source, transition, and source behavior.
|
|
57
|
+
2. Treat independently reachable pages, dialogs, sheets, and behaviorally distinct add/edit or selection modes as separate units when they have their own user-visible lifecycle or acceptance flow.
|
|
58
|
+
3. Prefer exact ref or normalized identity matches between `page.json.pages[].node_id` and Facts surfaces. Then use labels, `declared_at`, parent relations, navigation steps, source symbols, controls, and Android source behavior.
|
|
59
|
+
4. Never assign behavior from name similarity alone. Record ambiguous mappings in the owning Spec under “未决项与平台差异”.
|
|
60
|
+
5. `capture=false`, an empty `expected`, or a `skip_reason` does not remove a source-proven page. Use those fields as evidence limitations and verify the page through Facts and Android source.
|
|
61
|
+
6. Do not create a fake page for background-only capabilities. Assign startup, notification, widget, receiver, persistence, or other shared responsibilities to the earliest real page that requires them and list downstream consumers.
|
|
62
|
+
7. Legacy page work packages may contain many unrelated surfaces. Split them by actual page lifecycle and behavior ownership rather than retaining the old aggregate.
|
|
63
|
+
|
|
64
|
+
### 3. Decide development order
|
|
65
|
+
|
|
66
|
+
Rate each dimension using an integer from 0 to 5, then calculate the score using the following formula:
|
|
67
|
+
|
|
68
|
+
`page_score = enablement × 9 + ordinary_reachability × 6 + shallowness × 5`(满分 100,分数越高越优先)。
|
|
69
|
+
|
|
70
|
+
- **Enablement (45%)** — use the highest evidence-backed enablement rating among the page's REQs. `5`: difficult to mock or bound, ambiguous in data ownership, and correctness-relevant across many features. `3`: reused across several features but cleanly isolatable. `1`: page-local. Repeated persistence keys, storage operations, data-flow hops, and consumers are evidence; a feature name is not.
|
|
71
|
+
- **Ordinary reachability (30%)** — `5`: reachable in normal app state. `3`: needs a common business state such as existing data, login, or permission. `0`: first-launch only or reachable only after clearing/resetting app-global state. Use intermediate ratings where evidence supports them.
|
|
72
|
+
- **Shallowness (25%)** — `5`: launch/main page; `4`: one page navigation; `3`: two; `2`: three; `1`: four or more. Derive depth from page boundaries in `page-path`, not click count. `__shared_capability__` uses neutral `3`.
|
|
73
|
+
|
|
74
|
+
When ordering, first satisfy evidence-backed prerequisites so that data or state providers precede their consumers. Sort all remaining pages by page_score in descending order, breaking ties by the normalized stable page_id in ascending order. Finally, assign consecutive order values starting from 1. Prerequisites may override score-based ordering; no other arbitrary reordering is allowed.
|
|
75
|
+
|
|
76
|
+
Write the ordered decisions to `<output_root>/pages.json` before creating page directories. Also write the ordinal, dependencies, and concise rationale into each Spec.
|
|
77
|
+
|
|
78
|
+
Use schema `d2h-page-plan/v1`. Every `pages[]` item must contain:
|
|
79
|
+
|
|
80
|
+
- consecutive one-based `order`;
|
|
81
|
+
- stable `page_id`, `kind`, `package`, and `page_path`;
|
|
82
|
+
- `spec_refs` and `req_refs` backed by Facts/source evidence;
|
|
83
|
+
- integer `page_score`;
|
|
84
|
+
- `decision_ledger.enablement.rating`, `ordinary_reachability.rating`, and `shallowness.rating`, with evidence and a concise calculation/rationale.
|
|
85
|
+
|
|
86
|
+
`package` must exactly match `page_NNNN_<name>-<id>`. Every `page.json` node must be represented by a page item or by an explicit exclusion/unmatched entry with a reason. The AI authors and checks this plan; do not use it as a substitute for reading source.
|
|
87
|
+
|
|
88
|
+
### 4. Verify source before writing
|
|
89
|
+
|
|
90
|
+
1. Open every cited Android `sourceEvidence.file` at the cited symbol or line.
|
|
91
|
+
2. Follow handlers, repositories, state transitions, navigation, persistence, error paths, and platform side effects far enough to establish the observable result.
|
|
92
|
+
3. Use `page.json` navigation steps, selectors, guards, expected-arrival rules, required state, and depth to reconstruct the semantic arrival path. Source-derived reachability is planning evidence, not runtime confirmation.
|
|
93
|
+
4. Translate selectors into semantic control names only when Facts, resources, or Android source support the mapping. Keep missing or ambiguous selectors explicitly unresolved.
|
|
94
|
+
5. Verify every listed Android path exists under `android_root`. Verify every HarmonyOS path marked `existing` exists under `harmony_root`; otherwise mark it `planned`.
|
|
95
|
+
|
|
96
|
+
### 5. Write only `spec.md`
|
|
97
|
+
|
|
98
|
+
Use these headings in every page Spec:
|
|
99
|
+
|
|
100
|
+
```markdown
|
|
101
|
+
# <页面名称> 迁移 Spec
|
|
102
|
+
|
|
103
|
+
## 页面范围
|
|
104
|
+
|
|
105
|
+
- 页面标识:<稳定标识>
|
|
106
|
+
- 页面类型:<page | dialog | sheet | mode | other>
|
|
107
|
+
- Android 到达路径:<从真实入口开始的语义路径>
|
|
108
|
+
- 负责范围:<本 Spec 负责的状态和行为>
|
|
109
|
+
- 排除范围:<相邻但属于其他 Spec 的责任>
|
|
110
|
+
|
|
111
|
+
## 开发顺序
|
|
112
|
+
|
|
113
|
+
- 顺序:<NNNN>
|
|
114
|
+
- 前置依赖:<无或其他页面标识/共享能力>
|
|
115
|
+
- 排序理由:<基于前置依赖和页面评分的说明>
|
|
116
|
+
|
|
117
|
+
## 页面功能
|
|
118
|
+
|
|
119
|
+
- F-001:<用户动作及其可观察结果。>
|
|
120
|
+
|
|
121
|
+
## UI 操作与验收
|
|
122
|
+
|
|
123
|
+
### F-001
|
|
124
|
+
|
|
125
|
+
1. <从真实应用入口进入当前页面。>
|
|
126
|
+
2. <定位并操作具有语义名称的控件。>
|
|
127
|
+
3. <断言可见状态、导航、数据效果或错误结果。>
|
|
128
|
+
|
|
129
|
+
## Android 证据
|
|
130
|
+
|
|
131
|
+
| 证据 | 路径 / Ref | 支持的结论 |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| Facts | <surface/entry/control/interaction ref> | <范围或行为> |
|
|
134
|
+
| Android 源码 | <android_root 相对路径及符号/行> | <触发、分支和结果> |
|
|
135
|
+
| UTG Page | `.migration/utg/page.json` 中的 <node_id> | <到达路径、深度、前置状态、导航步骤与证据限制> |
|
|
136
|
+
|
|
137
|
+
## HarmonyOS 实现范围
|
|
138
|
+
|
|
139
|
+
| 路径 | 状态 | 预期职责 / 校验点 |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| <harmony_root 相对路径> | existing 或 planned | <页面实现、共享影响和验收点> |
|
|
142
|
+
|
|
143
|
+
## 未决项与平台差异
|
|
144
|
+
|
|
145
|
+
- <没有时明确写“无”。>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
When a page has no independent interaction, write one display/reachability feature and acceptance sequence instead of leaving the feature sections empty.
|
|
149
|
+
|
|
150
|
+
### 6. Generate `batch_report.md`
|
|
151
|
+
|
|
152
|
+
After all page Specs are complete, generate `<output_root>/batch_report.md` from `pages.json` with the bundled renderer:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
python scripts/build_batch_report.py \
|
|
156
|
+
--pages-plan <output_root>/pages.json \
|
|
157
|
+
--output-root <output_root>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The script requires every planned package to contain `spec.md`, never requires `ui-design.md`, and refuses to overwrite an existing report.
|
|
161
|
+
|
|
162
|
+
The report must contain:
|
|
163
|
+
|
|
164
|
+
- the source `pages.json` path and SHA-256;
|
|
165
|
+
- generation timestamp and ordered page count;
|
|
166
|
+
- one queue row per page with stable task ID `PAGE-NNNN`, page identity, relative `spec.md` link, development status, build status, validation status, and blocker;
|
|
167
|
+
- one detail section per task with dependencies, implementation files, test files, implementation commit or source snapshot, build evidence, test evidence, last update, blocker, and chronological execution notes;
|
|
168
|
+
- summary counts that exactly match the queue and detail sections.
|
|
169
|
+
|
|
170
|
+
Use these status values:
|
|
171
|
+
|
|
172
|
+
- development: `pending | in_progress | implemented | blocked`;
|
|
173
|
+
- build: `not_run | passed | failed | blocked`;
|
|
174
|
+
- validation: `not_run | passed | failed | blocked`.
|
|
175
|
+
|
|
176
|
+
Initial generation uses `pending`, `not_run`, and `not_run`, with empty implementation, test, evidence, commit/snapshot, timestamp, and blocker fields. Do not infer completion from existing HarmonyOS files or local test artifacts.
|
|
177
|
+
|
|
178
|
+
Once development has started, never rerun the renderer or overwrite `batch_report.md`. Update the existing queue row, detail section, counts, and notes in place while preserving execution history. If `pages.json`, the Spec set, or order no longer matches an existing report, stop and report the mismatch for AI reconciliation instead of silently resetting statuses.
|
|
179
|
+
|
|
180
|
+
## Quality gates
|
|
181
|
+
|
|
182
|
+
- Every known source-proven page, dialog, sheet, and behaviorally distinct mode has exactly one `spec.md`, or its ownership is explicitly assigned to another Spec.
|
|
183
|
+
- Every distinct interaction has a unique `F-xxx`, and feature IDs match UI operation/acceptance sections one-to-one.
|
|
184
|
+
- Each feature states a user action and observable result, not an implementation instruction.
|
|
185
|
+
- Navigation, state changes, persistence, destructive confirmation, external intents, cancellation, dismissal, and error behavior remain explicit.
|
|
186
|
+
- Facts refs, `page.json` node IDs, Android source paths, and HarmonyOS paths are real and correctly classified.
|
|
187
|
+
- Existing HarmonyOS code or tests never cause a feature to be marked complete without current build and executed test evidence.
|
|
188
|
+
- Uncertainty remains explicit. Do not invent control names, outcomes, source mappings, runtime captures, or implementation status.
|
|
189
|
+
- Each `page_NNNN_<name>-<id>/` directory contains exactly one file named `spec.md`.
|
|
190
|
+
- `output_root` contains only `pages.json`, `batch_report.md`, and page directories; it contains no copied UI evidence, UI design, or generated validation artifact.
|
|
191
|
+
- Every page directory has exactly one queue row and one detail section in `batch_report.md`; task IDs, order, links, statuses, and counts agree.
|
|
192
|
+
- A task is complete only when development is `implemented` and both build and validation are `passed` with current evidence.
|
|
193
|
+
|
|
194
|
+
## Result
|
|
195
|
+
|
|
196
|
+
Return:
|
|
197
|
+
|
|
198
|
+
- the ordered page directory list and ordering rationale;
|
|
199
|
+
- the number of generated, updated, and unchanged Specs;
|
|
200
|
+
- the absolute `pages.json` path;
|
|
201
|
+
- unreachable pages, capture-disabled nodes, and pages with incomplete arrival rules in `page.json`;
|
|
202
|
+
- ambiguous mappings and unmatched Facts;
|
|
203
|
+
- unresolved selector steps;
|
|
204
|
+
- legacy aggregate packages that were split;
|
|
205
|
+
- the absolute `batch_report.md` path;
|
|
206
|
+
- the absolute `output_root`.
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Create the initial batch_report.md from a validated pages.json plan."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import hashlib
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
import tempfile
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def sha256(path: Path) -> str:
|
|
17
|
+
digest = hashlib.sha256()
|
|
18
|
+
with path.open("rb") as stream:
|
|
19
|
+
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
|
|
20
|
+
digest.update(chunk)
|
|
21
|
+
return digest.hexdigest()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def markdown_text(value: object) -> str:
|
|
25
|
+
return str(value).replace("|", "\\|").replace("\n", " ")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def require_int(value: object, where: str) -> int:
|
|
29
|
+
if not isinstance(value, int) or isinstance(value, bool):
|
|
30
|
+
raise ValueError(f"{where} must be an integer")
|
|
31
|
+
return value
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def main() -> int:
|
|
35
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
36
|
+
parser.add_argument("--pages-plan", required=True, type=Path)
|
|
37
|
+
parser.add_argument("--output-root", required=True, type=Path)
|
|
38
|
+
args = parser.parse_args()
|
|
39
|
+
|
|
40
|
+
pages_plan = args.pages_plan.resolve()
|
|
41
|
+
output_root = args.output_root.resolve()
|
|
42
|
+
report_path = output_root / "batch_report.md"
|
|
43
|
+
if not pages_plan.is_file():
|
|
44
|
+
raise FileNotFoundError(f"missing page plan: {pages_plan}")
|
|
45
|
+
if report_path.exists():
|
|
46
|
+
raise FileExistsError(
|
|
47
|
+
f"refusing to overwrite existing execution history: {report_path}; update it in place"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
payload = json.loads(pages_plan.read_text(encoding="utf-8"))
|
|
51
|
+
if not isinstance(payload, dict) or payload.get("schema_version") != "d2h-page-plan/v1":
|
|
52
|
+
raise ValueError("pages plan must use schema d2h-page-plan/v1")
|
|
53
|
+
pages = payload.get("pages")
|
|
54
|
+
if not isinstance(pages, list) or not pages:
|
|
55
|
+
raise ValueError("pages plan must contain a non-empty pages array")
|
|
56
|
+
|
|
57
|
+
normalized: list[dict[str, object]] = []
|
|
58
|
+
seen_packages: set[str] = set()
|
|
59
|
+
seen_page_ids: set[str] = set()
|
|
60
|
+
for index, page in enumerate(pages):
|
|
61
|
+
if not isinstance(page, dict):
|
|
62
|
+
raise ValueError(f"pages[{index}] must be an object")
|
|
63
|
+
order = require_int(page.get("order"), f"pages[{index}].order")
|
|
64
|
+
if order != index + 1:
|
|
65
|
+
raise ValueError(f"pages[{index}].order must be {index + 1}")
|
|
66
|
+
|
|
67
|
+
package = page.get("package")
|
|
68
|
+
page_id = page.get("page_id")
|
|
69
|
+
if not isinstance(package, str) or not package:
|
|
70
|
+
raise ValueError(f"pages[{index}].package must be a non-empty string")
|
|
71
|
+
if Path(package).name != package or not package.startswith(f"page_{order:04d}_"):
|
|
72
|
+
raise ValueError(
|
|
73
|
+
f"pages[{index}].package must be a single directory named page_{order:04d}_<name>-<id>"
|
|
74
|
+
)
|
|
75
|
+
if package in seen_packages:
|
|
76
|
+
raise ValueError(f"duplicate package: {package}")
|
|
77
|
+
seen_packages.add(package)
|
|
78
|
+
if not isinstance(page_id, str) or not page_id:
|
|
79
|
+
raise ValueError(f"pages[{index}].page_id must be a non-empty string")
|
|
80
|
+
if page_id in seen_page_ids:
|
|
81
|
+
raise ValueError(f"duplicate page_id: {page_id}")
|
|
82
|
+
seen_page_ids.add(page_id)
|
|
83
|
+
|
|
84
|
+
spec_path = output_root / package / "spec.md"
|
|
85
|
+
if not spec_path.is_file():
|
|
86
|
+
raise FileNotFoundError(
|
|
87
|
+
f"all page specs must exist before batch report generation; missing {spec_path}"
|
|
88
|
+
)
|
|
89
|
+
package_files = sorted(path.name for path in spec_path.parent.iterdir() if path.is_file())
|
|
90
|
+
if package_files != ["spec.md"]:
|
|
91
|
+
raise ValueError(
|
|
92
|
+
f"page package must contain only spec.md: {spec_path.parent} contains {package_files}"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
ledger = page.get("decision_ledger")
|
|
96
|
+
if not isinstance(ledger, dict):
|
|
97
|
+
raise ValueError(f"pages[{index}].decision_ledger must be an object")
|
|
98
|
+
dimensions: dict[str, int] = {}
|
|
99
|
+
for dimension in ("enablement", "ordinary_reachability", "shallowness"):
|
|
100
|
+
item = ledger.get(dimension)
|
|
101
|
+
if not isinstance(item, dict):
|
|
102
|
+
raise ValueError(f"pages[{index}].decision_ledger.{dimension} must be an object")
|
|
103
|
+
dimensions[dimension] = require_int(
|
|
104
|
+
item.get("rating"), f"pages[{index}].decision_ledger.{dimension}.rating"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
normalized.append(
|
|
108
|
+
{
|
|
109
|
+
"order": order,
|
|
110
|
+
"task_id": f"PAGE-{order:04d}",
|
|
111
|
+
"page_id": page_id,
|
|
112
|
+
"kind": page.get("kind", "page"),
|
|
113
|
+
"page_score": require_int(page.get("page_score"), f"pages[{index}].page_score"),
|
|
114
|
+
"package": package,
|
|
115
|
+
"page_path": page.get("page_path", []),
|
|
116
|
+
**dimensions,
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
created_at = datetime.now().astimezone().isoformat(timespec="seconds")
|
|
121
|
+
plan_link = Path(os.path.relpath(pages_plan, output_root)).as_posix()
|
|
122
|
+
lines = [
|
|
123
|
+
"# 页面开发批次执行记录",
|
|
124
|
+
"",
|
|
125
|
+
f"- 页面计划:[pages.json]({plan_link})",
|
|
126
|
+
f"- 页面计划 SHA-256:`{sha256(pages_plan)}`",
|
|
127
|
+
f"- 记录创建时间:`{created_at}`",
|
|
128
|
+
"- 更新规则:后续开发直接更新本文件;不要重新生成或覆盖已有执行历史。",
|
|
129
|
+
"",
|
|
130
|
+
"## 状态约定",
|
|
131
|
+
"",
|
|
132
|
+
"- 开发状态:`pending | in_progress | implemented | blocked`",
|
|
133
|
+
"- 构建状态:`not_run | passed | failed | blocked`",
|
|
134
|
+
"- 验证状态:`not_run | passed | failed | blocked`",
|
|
135
|
+
"- 完成条件:开发为 `implemented`,且构建、验证均为 `passed`。",
|
|
136
|
+
"",
|
|
137
|
+
"## 批次汇总",
|
|
138
|
+
"",
|
|
139
|
+
f"- 总任务:{len(normalized)}",
|
|
140
|
+
f"- 待开始:{len(normalized)}",
|
|
141
|
+
"- 进行中:0",
|
|
142
|
+
"- 已完成:0",
|
|
143
|
+
"- 阻塞:0",
|
|
144
|
+
"",
|
|
145
|
+
"## 执行队列",
|
|
146
|
+
"",
|
|
147
|
+
"| 任务 | 顺序 | 页面 | 类型 | 分数 | Spec | 开发 | 构建 | 验证 |",
|
|
148
|
+
"|---|---:|---|---|---:|---|---|---|---|",
|
|
149
|
+
]
|
|
150
|
+
for page in normalized:
|
|
151
|
+
spec_link = f"./{page['package']}/spec.md"
|
|
152
|
+
lines.append(
|
|
153
|
+
"| {task} | {order} | {page_id} | {kind} | {score} | "
|
|
154
|
+
"[spec.md]({spec}) | `pending` | `not_run` | `not_run` |".format(
|
|
155
|
+
task=page["task_id"],
|
|
156
|
+
order=page["order"],
|
|
157
|
+
page_id=markdown_text(page["page_id"]),
|
|
158
|
+
kind=markdown_text(page["kind"]),
|
|
159
|
+
score=page["page_score"],
|
|
160
|
+
spec=spec_link,
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
lines.extend(["", "## 任务记录"])
|
|
165
|
+
for page in normalized:
|
|
166
|
+
page_path = page["page_path"]
|
|
167
|
+
path_text = (
|
|
168
|
+
" → ".join(markdown_text(value) for value in page_path)
|
|
169
|
+
if isinstance(page_path, list)
|
|
170
|
+
else "—"
|
|
171
|
+
)
|
|
172
|
+
spec_link = f"./{page['package']}/spec.md"
|
|
173
|
+
lines.extend(
|
|
174
|
+
[
|
|
175
|
+
"",
|
|
176
|
+
f"### {page['task_id']} · {markdown_text(page['page_id'])}",
|
|
177
|
+
"",
|
|
178
|
+
f"- 执行顺序:{page['order']}",
|
|
179
|
+
f"- 页面路径:{path_text or '—'}",
|
|
180
|
+
f"- 页面分数:{page['page_score']}(enablement={page['enablement']},ordinary_reachability={page['ordinary_reachability']},shallowness={page['shallowness']})",
|
|
181
|
+
f"- 任务 Spec:[spec.md]({spec_link})",
|
|
182
|
+
"- 开发状态:`pending`",
|
|
183
|
+
"- 构建状态:`not_run`",
|
|
184
|
+
"- 验证状态:`not_run`",
|
|
185
|
+
"- 实现文件:—",
|
|
186
|
+
"- 测试文件:—",
|
|
187
|
+
"- 代码提交 / 源码快照:—",
|
|
188
|
+
"- 构建证据:—",
|
|
189
|
+
"- 测试证据:—",
|
|
190
|
+
"- 最后更新:—",
|
|
191
|
+
"- 阻塞原因:—",
|
|
192
|
+
"",
|
|
193
|
+
"#### 执行记录",
|
|
194
|
+
"",
|
|
195
|
+
"- 尚未开始。",
|
|
196
|
+
]
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
output_root.mkdir(parents=True, exist_ok=True)
|
|
200
|
+
report_text = "\n".join(lines) + "\n"
|
|
201
|
+
with tempfile.NamedTemporaryFile(
|
|
202
|
+
mode="w", encoding="utf-8", dir=output_root, prefix=".batch-report-", delete=False
|
|
203
|
+
) as stream:
|
|
204
|
+
stream.write(report_text)
|
|
205
|
+
temporary_path = Path(stream.name)
|
|
206
|
+
os.replace(temporary_path, report_path)
|
|
207
|
+
print(
|
|
208
|
+
json.dumps(
|
|
209
|
+
{
|
|
210
|
+
"ok": True,
|
|
211
|
+
"task_count": len(normalized),
|
|
212
|
+
"pages_plan": str(pages_plan),
|
|
213
|
+
"batch_report": str(report_path),
|
|
214
|
+
},
|
|
215
|
+
ensure_ascii=False,
|
|
216
|
+
indent=2,
|
|
217
|
+
)
|
|
218
|
+
)
|
|
219
|
+
return 0
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
if __name__ == "__main__":
|
|
223
|
+
try:
|
|
224
|
+
raise SystemExit(main())
|
|
225
|
+
except (FileNotFoundError, FileExistsError, ValueError, KeyError, json.JSONDecodeError) as error:
|
|
226
|
+
print(f"error: {error}", file=sys.stderr)
|
|
227
|
+
raise SystemExit(2)
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: managing-d2h-toolchain
|
|
3
|
-
description:
|
|
3
|
+
description: 独立检查、安装或升级迁移所需的精确版本 AppGraph 与 droid2hmos CLI。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# 管理迁移工具链
|
|
7
7
|
|
|
8
|
-
本 Skill
|
|
8
|
+
本 Skill 是迁移流程检查和维护 AppGraph、droid2hmos 的入口。`toolchain.json` 声明精确 npm 坐标及必需的命令能力;`environment-requirements.json` 声明主机环境约束。其他 Agent/Skill 只使用通过检查的 CLI,不自行选择版本或安装。以下脚本随 Skill 一起复制,直接由 Node.js 执行。
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## 检查与安装
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
- `d2h` 命令可用时先执行 `d2h --help`,确认支持 `install`、`upgrade`、`doctor`。需要通过 npx 调用时使用 `npx --yes @harmonyos-arkts/d2h@<packageVersion>`;Windows 使用 `npx.cmd`。不可用或记录缺失时,请调用方提供已批准的**精确 D2H 版本**完成首次安装,不猜测 `latest`。
|
|
14
|
-
- 源码开发使用当前仓库构建出的 `node dist/bin/install-opencode.js`,不要把 npm 上同版本的旧包误当成本地源码。修改 D2H 依赖版本时只改包内 `skills/managing-d2h-toolchain/toolchain.json`,同时更新环境约束、兼容性测试和发布版本。
|
|
12
|
+
在本 Skill 目录运行(Windows 可使用 `node.exe`):
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
```sh
|
|
15
|
+
node scripts/manage-toolchain.mjs check
|
|
16
|
+
node scripts/manage-toolchain.mjs install
|
|
17
|
+
```
|
|
17
18
|
|
|
18
|
-
1.
|
|
19
|
-
2.
|
|
20
|
-
3.
|
|
21
|
-
4.
|
|
19
|
+
1. 首先运行 `check`。脚本读取同目录 `toolchain.json`,分别调用 `appgraph --version`、`droid2hmos --version` 和清单中声明的命令能力探针,逐项报告指定版本、实际版本及能力。全部符合时退出码为 0;缺失或不符时退出码为 1。
|
|
20
|
+
2. `check` 失败时运行 `install`。脚本只对缺失、版本或能力不符的工具执行 `npm install --global <精确坐标>@<精确版本>`,随后重新检查。已符合要求的工具不会重装。安装失败或安装后仍不符合要求时停止迁移并报告错误;不能静默使用其他版本。
|
|
21
|
+
3. 已存在的全局 npm link 默认受保护。需要替换链接时,调用方须明确要求 `node scripts/manage-toolchain.mjs install --force`;它会重新安装清单中的全部精确版本。脚本不会修改链接指向的源码目录。
|
|
22
|
+
4. 安装完成后再运行一次 `check`,通过后才交给 `preparing-migration-workspace`。项目级 `droid2hmos preflight` 仍由准备 Skill 执行。
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
首次使用本 Skill 时,要求 Node.js 22.5–24.x 和 npm 可用。工具已符合清单要求时,`check` 直接通过,`install` 不重复安装。修改依赖版本时只修改本目录的 `toolchain.json`,同步更新环境约束和测试。其他 Skill 不执行 `npm install -g`、`npm update` 或浮动版本安装。
|