@harmonyos-arkts/d2h 0.0.0-stage → 0.1.1

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 (74) hide show
  1. package/.claude-plugin/marketplace.json +13 -0
  2. package/.claude-plugin/plugin.json +7 -0
  3. package/README.md +177 -2
  4. package/agents/android-to-hmos-00-orchestrator.md +312 -0
  5. package/agents/d2h.md +168 -0
  6. package/bin/install-opencode.mjs +57 -0
  7. package/install-opencode.sh +160 -0
  8. package/opencode/agents.json +16 -0
  9. package/package.json +43 -4
  10. package/schemas/android-source-manifest.schema.json +25 -0
  11. package/schemas/checkpoint-provenance.schema.json +67 -0
  12. package/schemas/final-acceptance.schema.json +29 -0
  13. package/schemas/managed-evidence-index.schema.json +15 -0
  14. package/schemas/managed-evidence.schema.json +114 -0
  15. package/schemas/migration-config.schema.json +51 -0
  16. package/schemas/migration-report-index.schema.json +39 -0
  17. package/schemas/migration-report-item.schema.json +51 -0
  18. package/schemas/migration-report-summary.schema.json +25 -0
  19. package/schemas/migration-status.schema.json +202 -0
  20. package/schemas/preflight.schema.json +60 -0
  21. package/schemas/source-order-audit.schema.json +16 -0
  22. package/schemas/source-provenance-event.schema.json +19 -0
  23. package/schemas/spec-app-shard.schema.json +45 -0
  24. package/schemas/spec-fact-corrections-shard.schema.json +13 -0
  25. package/schemas/spec-features-shard.schema.json +43 -0
  26. package/schemas/spec-index.schema.json +26 -0
  27. package/schemas/spec-interactions-shard.schema.json +40 -0
  28. package/schemas/spec-page.schema.json +98 -0
  29. package/schemas/spec-pages-index.schema.json +1 -0
  30. package/schemas/spec-unresolved-shard.schema.json +1 -0
  31. package/schemas/task-envelope.schema.json +55 -0
  32. package/schemas/task-plan.schema.json +123 -0
  33. package/skills/android2hmos_resources_convert/SKILL.md +162 -0
  34. package/skills/android2hmos_resources_convert/references/image-conversion-rules.md +230 -0
  35. package/skills/android2hmos_resources_convert/references/svg-fix-patterns.md +175 -0
  36. package/skills/android2hmos_resources_convert/references/xml-drawable-to-svg-rules.md +513 -0
  37. package/skills/appgraph-rule-audit/SKILL.md +58 -0
  38. package/skills/appgraph-rule-audit/references/audit-contract.md +47 -0
  39. package/skills/appgraph-rule-audit/references/recommendation-schema.md +41 -0
  40. package/skills/appgraph-rule-audit/schemas/rule-opportunities.schema.json +125 -0
  41. package/skills/arkts-app-identity/SKILL.md +238 -0
  42. package/skills/arkts-i18n/SKILL.md +496 -0
  43. package/skills/arkts-i18n/evals/evals.json +84 -0
  44. package/skills/arkts-i18n/references/code-examples.md +302 -0
  45. package/skills/arkts-i18n/references/common-pitfalls.md +391 -0
  46. package/skills/arkts-i18n/references/dynamic-language-switch.md +604 -0
  47. package/skills/arkts-i18n/references/hardcoded-string-scanner.md +348 -0
  48. package/skills/arkts-i18n/references/language-codes.md +104 -0
  49. package/skills/arkts-i18n/references/resource-file-structure.md +775 -0
  50. package/skills/arkts-i18n/references/static-vs-dynamic.md +242 -0
  51. package/skills/arkts-i18n/references/v1-compat.md +244 -0
  52. package/skills/arkts-i18n/scripts/audit_i18n_completeness.sh +174 -0
  53. package/skills/arkts-icon-sizing/SKILL.md +211 -0
  54. package/skills/arkts-icon-sizing/scripts/icon_audit.py +131 -0
  55. package/skills/arkts-icon-sizing/scripts/icon_autofix.py +88 -0
  56. package/skills/arkts-icon-sizing/scripts/icon_dims.py +179 -0
  57. package/skills/arkts-icon-sizing/scripts/icon_fix.py +119 -0
  58. package/skills/arkts-mvvm-architecture/SKILL.md +613 -0
  59. package/skills/harmonyos-migration-playbook/SKILL.md +56 -0
  60. package/skills/harmonyos-migration-playbook/agents/openai.yaml +7 -0
  61. package/skills/harmonyos-migration-playbook/references/arkts-compile.md +24 -0
  62. package/skills/harmonyos-migration-playbook/references/harmony-runtime.md +53 -0
  63. package/skills/harmonyos-migration-playbook/references/lesson-lifecycle.md +45 -0
  64. package/skills/harmonyos-migration-playbook/references/protocol-e2e.md +23 -0
  65. package/skills/harmonyos-migration-playbook/references/ui-automation.md +52 -0
  66. package/skills/harmonyos-migration-playbook/references/windows-environment.md +38 -0
  67. package/skills/maintaining-migration-report/SKILL.md +155 -0
  68. package/skills/native-library-substitution/SKILL.md +385 -0
  69. package/skills/native-library-substitution/references/native-library-substitution.json +56906 -0
  70. package/skills/native-library-substitution/references/native-library-substitution.md +163 -0
  71. package/skills/preparing-migration-workspace/SKILL.md +124 -0
  72. package/skills/preparing-migration-workspace/toolchain.json +43 -0
  73. package/skills/reviewing-migration-process/SKILL.md +62 -0
  74. package/src/install-opencode.mjs +110 -0
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/spec-fact-corrections-shard.schema.json",
4
+ "title": "SPEC Semantic Corrections",
5
+ "type": "object",
6
+ "required": ["shardVersion", "factCorrections", "exclusions"],
7
+ "properties": { "shardVersion": { "const": "2.0.0" }, "factCorrections": { "type": "array", "items": { "$ref": "#/$defs/correction" } }, "exclusions": { "type": "array" } },
8
+ "$defs": { "correction": { "type": "object", "required": ["id", "entityKind", "operation", "targetRef", "factValue", "semanticValue", "reason", "sourceEvidence"], "properties": {
9
+ "id": { "type": "string", "minLength": 1 }, "entityKind": { "enum": ["surface", "control", "entry", "interaction"] }, "operation": { "enum": ["add", "update", "remove"] }, "targetRef": { "type": "string", "minLength": 1 },
10
+ "factValue": { "type": ["object", "null"] }, "semanticValue": { "type": ["object", "null"] }, "reason": { "type": "string", "minLength": 1 },
11
+ "sourceEvidence": { "type": "array", "minItems": 1, "items": { "type": "object", "required": ["file"], "properties": { "file": { "type": "string", "minLength": 1 }, "symbol": { "type": ["string", "null"] }, "line": { "type": ["integer", "null"] }, "endLine": { "type": ["integer", "null"] } }, "additionalProperties": false } }
12
+ }, "additionalProperties": false } }, "additionalProperties": false
13
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/spec-features-shard.schema.json",
4
+ "title": "SPEC Business Features Shard",
5
+ "type": "object",
6
+ "required": ["shardVersion", "domains", "features"],
7
+ "properties": {
8
+ "shardVersion": { "const": "2.0.0" },
9
+ "domains": { "type": "array", "items": { "$ref": "#/$defs/domain" } },
10
+ "features": { "type": "array", "items": { "$ref": "#/$defs/feature" } }
11
+ },
12
+ "$defs": {
13
+ "text": { "type": "string", "minLength": 1 },
14
+ "nullableText": { "type": ["string", "null"], "minLength": 1 },
15
+ "refs": { "type": "array", "uniqueItems": true, "items": { "$ref": "#/$defs/text" } },
16
+ "domain": {
17
+ "type": "object",
18
+ "required": ["id", "parentDomainRef", "name", "description", "featureRefs"],
19
+ "properties": {
20
+ "id": { "$ref": "#/$defs/text" },
21
+ "parentDomainRef": { "$ref": "#/$defs/nullableText" },
22
+ "name": { "$ref": "#/$defs/text" },
23
+ "description": { "$ref": "#/$defs/text" },
24
+ "featureRefs": { "$ref": "#/$defs/refs" }
25
+ },
26
+ "additionalProperties": false
27
+ },
28
+ "feature": {
29
+ "type": "object",
30
+ "required": ["id", "domainRef", "parentFeatureRef", "name", "description", "entryRefs"],
31
+ "properties": {
32
+ "id": { "$ref": "#/$defs/text" },
33
+ "domainRef": { "$ref": "#/$defs/text" },
34
+ "parentFeatureRef": { "$ref": "#/$defs/nullableText" },
35
+ "name": { "$ref": "#/$defs/text" },
36
+ "description": { "$ref": "#/$defs/text" },
37
+ "entryRefs": { "$ref": "#/$defs/refs" }
38
+ },
39
+ "additionalProperties": false
40
+ }
41
+ },
42
+ "additionalProperties": false
43
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/spec-index.schema.json",
4
+ "title": "Sharded SPEC Index",
5
+ "type": "object",
6
+ "required": ["specVersion", "shardFormatVersion", "language", "generation", "files", "counts", "factsSha256", "specSha256"],
7
+ "properties": {
8
+ "specVersion": { "const": "2.0.0" },
9
+ "shardFormatVersion": { "const": "2.0.0" },
10
+ "language": { "const": "zh-CN" },
11
+ "generation": { "type": "object" },
12
+ "files": {
13
+ "type": "object",
14
+ "required": ["facts", "semantics"],
15
+ "properties": {
16
+ "facts": { "type": "object", "required": ["app", "pages", "interactions", "unresolved"], "additionalProperties": { "type": "string", "minLength": 1 } },
17
+ "semantics": { "type": "object", "required": ["app", "pages", "interactions", "features", "unresolved", "corrections"], "additionalProperties": { "type": "string", "minLength": 1 } }
18
+ },
19
+ "additionalProperties": false
20
+ },
21
+ "counts": { "type": "object" },
22
+ "factsSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
23
+ "specSha256": { "type": ["string", "null"], "pattern": "^[a-f0-9]{64}$" }
24
+ },
25
+ "additionalProperties": false
26
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/spec-interactions-shard.schema.json",
4
+ "title": "SPEC 2.0.0 Interaction Facts Shard",
5
+ "type": "object",
6
+ "required": ["shardVersion", "interactions"],
7
+ "properties": {
8
+ "shardVersion": { "const": "2.0.0" },
9
+ "interactions": {
10
+ "type": "array",
11
+ "items": {
12
+ "type": "object",
13
+ "required": ["id", "relation", "fromRef", "toRef", "confidence", "sourceEvidence"],
14
+ "properties": {
15
+ "id": { "type": "string", "minLength": 1 },
16
+ "relation": { "enum": ["opens", "navigates-to", "launches-for-result"] },
17
+ "fromRef": { "type": "string", "minLength": 1 },
18
+ "toRef": { "type": "string", "minLength": 1 },
19
+ "confidence": { "type": "number", "minimum": 0, "maximum": 1 },
20
+ "sourceEvidence": {
21
+ "type": "array",
22
+ "items": {
23
+ "type": "object",
24
+ "required": ["file", "symbol", "line", "endLine"],
25
+ "properties": {
26
+ "file": { "type": "string", "minLength": 1 },
27
+ "symbol": { "type": ["string", "null"] },
28
+ "line": { "type": ["integer", "null"], "minimum": 1 },
29
+ "endLine": { "type": ["integer", "null"], "minimum": 1 }
30
+ },
31
+ "additionalProperties": false
32
+ }
33
+ }
34
+ },
35
+ "additionalProperties": false
36
+ }
37
+ }
38
+ },
39
+ "additionalProperties": false
40
+ }
@@ -0,0 +1,98 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/spec-page.schema.json",
4
+ "title": "SPEC 2.0.0 Surface Facts Shard",
5
+ "type": "object",
6
+ "required": ["shardVersion", "kind", "surface", "controls", "entries"],
7
+ "properties": {
8
+ "shardVersion": { "const": "2.0.0" },
9
+ "kind": { "const": "surface-facts" },
10
+ "surface": {
11
+ "type": "object",
12
+ "required": ["surfaceRef", "surfaceName", "surfaceType", "parentSurfaceRefs", "relation", "status", "sourceEvidence"],
13
+ "properties": {
14
+ "surfaceRef": { "type": "string", "minLength": 1 },
15
+ "surfaceName": { "type": "string", "minLength": 1 },
16
+ "surfaceType": { "type": "string", "minLength": 1 },
17
+ "parentSurfaceRefs": { "$ref": "#/$defs/refs" },
18
+ "relation": { "const": "hosts" },
19
+ "status": { "enum": ["root", "determined", "multiple", "unresolved"] },
20
+ "sourceEvidence": { "$ref": "#/$defs/evidenceList" }
21
+ },
22
+ "additionalProperties": false
23
+ },
24
+ "controls": { "type": "array", "items": { "$ref": "#/$defs/control" } },
25
+ "entries": { "type": "array", "items": { "$ref": "#/$defs/entry" } }
26
+ },
27
+ "$defs": {
28
+ "refs": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
29
+ "evidence": {
30
+ "type": "object",
31
+ "required": ["file", "symbol", "line", "endLine"],
32
+ "properties": {
33
+ "file": { "type": "string", "minLength": 1 },
34
+ "symbol": { "type": ["string", "null"] },
35
+ "line": { "type": ["integer", "null"], "minimum": 1 },
36
+ "endLine": { "type": ["integer", "null"], "minimum": 1 }
37
+ },
38
+ "additionalProperties": false
39
+ },
40
+ "evidenceList": { "type": "array", "items": { "$ref": "#/$defs/evidence" } },
41
+ "control": {
42
+ "type": "object",
43
+ "required": ["controlRef", "sourceCarrierRef", "name", "surfaceRef", "status", "sourceEvidence"],
44
+ "properties": {
45
+ "controlRef": { "type": "string", "minLength": 1 },
46
+ "sourceCarrierRef": { "type": "string", "minLength": 1 },
47
+ "name": { "type": "string", "minLength": 1 },
48
+ "surfaceRef": { "type": "string", "minLength": 1 },
49
+ "status": { "const": "determined" },
50
+ "sourceEvidence": { "$ref": "#/$defs/evidenceList" }
51
+ },
52
+ "additionalProperties": false
53
+ },
54
+ "entry": {
55
+ "type": "object",
56
+ "required": ["entryRef", "triggerCategory", "componentType", "ownershipStatus", "surfaceRef", "surfaceName", "surfaceType", "carrierRef", "carrierName", "carrierStatus", "event", "displayLabel", "handlerNames", "callTrace", "sourceEvidence", "warnings"],
57
+ "properties": {
58
+ "entryRef": { "type": "string", "minLength": 1 },
59
+ "triggerCategory": { "enum": ["user", "system", "application"] },
60
+ "componentType": { "enum": ["activity", "fragment", "dialog", "service", "receiver", "provider", "control", "custom-view", "unknown"] },
61
+ "ownershipStatus": { "enum": ["determined", "ambiguous", "unresolved"] },
62
+ "surfaceRef": { "type": ["string", "null"] },
63
+ "surfaceName": { "type": "string" },
64
+ "surfaceType": { "type": "string" },
65
+ "carrierRef": { "type": ["string", "null"] },
66
+ "carrierName": { "type": "string" },
67
+ "carrierStatus": { "enum": ["determined", "category-only", "not-applicable", "unknown"] },
68
+ "event": { "type": "string", "minLength": 1 },
69
+ "displayLabel": { "type": "string", "minLength": 1 },
70
+ "handlerNames": { "$ref": "#/$defs/refs" },
71
+ "callTrace": {
72
+ "type": "object",
73
+ "required": ["handlerRefs", "codeRefs", "callEdges", "truncated", "coverageWarnings"],
74
+ "properties": {
75
+ "handlerRefs": { "$ref": "#/$defs/refs" },
76
+ "codeRefs": { "type": "array", "items": { "type": "object" } },
77
+ "callEdges": {
78
+ "type": "array",
79
+ "items": {
80
+ "type": "object",
81
+ "required": ["from", "to"],
82
+ "properties": { "from": { "type": "string", "minLength": 1 }, "to": { "type": "string", "minLength": 1 } },
83
+ "additionalProperties": false
84
+ }
85
+ },
86
+ "truncated": { "type": "boolean" },
87
+ "coverageWarnings": { "type": "array", "items": { "type": "string" } }
88
+ },
89
+ "additionalProperties": false
90
+ },
91
+ "sourceEvidence": { "$ref": "#/$defs/evidenceList" },
92
+ "warnings": { "type": "array", "items": { "type": "string" } }
93
+ },
94
+ "additionalProperties": false
95
+ }
96
+ },
97
+ "additionalProperties": false
98
+ }
@@ -0,0 +1 @@
1
+ {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://harmonyos-ai.dev/schemas/spec-pages-index.schema.json","title":"SPEC Facts or Semantics Pages Index","type":"object","required":["indexVersion","pages","unassignedEntriesFile"],"properties":{"indexVersion":{"const":"2.0.0"},"pages":{"type":"array","items":{"type":"object","required":["surfaceRef","file"],"properties":{"surfaceRef":{"type":"string","minLength":1},"surfaceType":{"type":"string","minLength":1},"file":{"type":"string","pattern":"^(facts|semantics)/pages/.+\\.json$"}},"additionalProperties":false}},"unassignedEntriesFile":{"type":["string","null"]}},"additionalProperties":false}
@@ -0,0 +1 @@
1
+ {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://harmonyos-ai.dev/schemas/spec-unresolved-shard.schema.json","title":"SPEC Unresolved Semantics Shard","type":"object","required":["shardVersion","reviews"],"properties":{"shardVersion":{"const":"2.0.0"},"reviews":{"type":"array","items":{"type":"object","required":["unresolvedRef","decision","featureRef","reason"],"properties":{"unresolvedRef":{"type":"string","minLength":1},"decision":{"enum":["pending","covered-by-feature","excluded","accepted-unknown"]},"featureRef":{"type":["string","null"]},"reason":{"type":["string","null"]}},"additionalProperties":false}}},"additionalProperties":false}
@@ -0,0 +1,55 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/task-envelope.schema.json",
4
+ "title": "Android to HarmonyOS Task Envelope Page",
5
+ "type": "object",
6
+ "required": ["taskEnvelopeVersion", "taskPlanSha256", "task", "brief", "coreFacts", "sourceContext", "continuation"],
7
+ "properties": {
8
+ "taskEnvelopeVersion": { "const": "1.0.0" },
9
+ "taskPlanSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
10
+ "task": { "type": "object" },
11
+ "brief": { "type": "string", "minLength": 1 },
12
+ "coreFacts": { "type": "array" },
13
+ "sourceContext": {
14
+ "description": "Bounded source location indexes only. Source text/snippets are forbidden.",
15
+ "type": "array",
16
+ "maxItems": 200,
17
+ "items": { "$ref": "#/$defs/sourceIndex" }
18
+ },
19
+ "continuation": {
20
+ "type": "object",
21
+ "required": ["cursor", "remainingSourceContext"],
22
+ "properties": {
23
+ "cursor": { "type": ["string", "null"] },
24
+ "remainingSourceContext": { "type": "integer", "minimum": 0 }
25
+ },
26
+ "additionalProperties": false
27
+ }
28
+ },
29
+ "$defs": {
30
+ "sourceIndex": {
31
+ "type": "object",
32
+ "required": ["kind", "value"],
33
+ "properties": {
34
+ "kind": { "enum": ["source-evidence", "code-ref"] },
35
+ "value": {
36
+ "type": "object",
37
+ "properties": {
38
+ "id": { "type": "string" },
39
+ "file": { "type": "string", "minLength": 1 },
40
+ "name": { "type": "string" },
41
+ "symbol": { "type": ["string", "null"] },
42
+ "kind": { "type": "string" },
43
+ "type": { "type": "string" },
44
+ "line": { "type": ["integer", "null"], "minimum": 1 },
45
+ "startLine": { "type": "integer", "minimum": 1 },
46
+ "endLine": { "type": ["integer", "null"], "minimum": 1 }
47
+ },
48
+ "additionalProperties": false
49
+ }
50
+ },
51
+ "additionalProperties": false
52
+ }
53
+ },
54
+ "additionalProperties": false
55
+ }
@@ -0,0 +1,123 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/task-plan.schema.json",
4
+ "title": "Android to HarmonyOS Task Plan",
5
+ "type": "object",
6
+ "required": ["taskPlanVersion", "planningModelVersion", "factsAdapterVersion", "plannerPolicyVersion", "baseline", "entryResolution", "tasks", "ownership", "planningWarnings"],
7
+ "properties": {
8
+ "taskPlanVersion": { "const": "1.0.0" },
9
+ "planningModelVersion": { "const": "1.0.0" },
10
+ "factsAdapterVersion": { "const": "1.0.0" },
11
+ "plannerPolicyVersion": { "const": "1.1.0" },
12
+ "baseline": {
13
+ "type": "object",
14
+ "required": ["factsSha256", "planningInputSha256", "androidFingerprint", "specVersion", "factsWireVersion"],
15
+ "properties": {
16
+ "factsSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
17
+ "planningInputSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
18
+ "androidFingerprint": { "type": ["string", "null"], "pattern": "^[a-f0-9]{64}$" },
19
+ "specVersion": { "type": "string", "minLength": 1 },
20
+ "factsWireVersion": { "const": "2.0.0" }
21
+ },
22
+ "additionalProperties": false
23
+ },
24
+ "entryResolution": {
25
+ "type": "object",
26
+ "required": ["launcherSurfaceRefs", "launcherEntryRefs", "origin"],
27
+ "properties": {
28
+ "launcherSurfaceRefs": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
29
+ "launcherEntryRefs": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
30
+ "origin": { "enum": ["explicit-fact", "launch-entry-fact", "unresolved"] }
31
+ },
32
+ "additionalProperties": false
33
+ },
34
+ "tasks": { "type": "array", "items": { "$ref": "#/$defs/task" } },
35
+ "ownership": {
36
+ "type": "object",
37
+ "required": ["primaryOwnerByFactRef", "supportingTaskIdsByFactRef"],
38
+ "properties": {
39
+ "primaryOwnerByFactRef": { "type": "object", "additionalProperties": { "type": "string", "minLength": 1 } },
40
+ "supportingTaskIdsByFactRef": { "type": "object", "additionalProperties": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } } }
41
+ },
42
+ "additionalProperties": false
43
+ },
44
+ "planningWarnings": { "type": "array", "items": { "$ref": "#/$defs/warning" } }
45
+ },
46
+ "$defs": {
47
+ "warning": {
48
+ "type": "object",
49
+ "required": ["code", "message", "relatedRefs"],
50
+ "properties": {
51
+ "code": { "type": "string", "minLength": 1 },
52
+ "message": { "type": "string", "minLength": 1 },
53
+ "relatedRefs": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }
54
+ },
55
+ "additionalProperties": false
56
+ },
57
+ "evidence": {
58
+ "type": "object",
59
+ "required": ["file", "symbol", "line", "endLine"],
60
+ "properties": {
61
+ "file": { "type": "string", "minLength": 1 },
62
+ "symbol": { "type": ["string", "null"] },
63
+ "line": { "type": ["integer", "null"], "minimum": 1 },
64
+ "endLine": { "type": ["integer", "null"], "minimum": 1 }
65
+ },
66
+ "additionalProperties": false
67
+ },
68
+ "task": {
69
+ "type": "object",
70
+ "required": ["id", "type", "title", "primaryFactRefs", "supportingFactRefs", "dependsOnTaskIds", "closure", "acceptance", "estimate"],
71
+ "properties": {
72
+ "id": { "type": "string", "pattern": "^task:[a-f0-9]{16}$" },
73
+ "type": { "enum": ["resolution", "bootstrap", "capability", "journey", "assembly", "regression"] },
74
+ "title": { "type": "string", "minLength": 1 },
75
+ "primaryFactRefs": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
76
+ "supportingFactRefs": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
77
+ "dependsOnTaskIds": { "type": "array", "uniqueItems": true, "items": { "type": "string", "pattern": "^task:[a-f0-9]{16}$" } },
78
+ "closure": {
79
+ "type": "object",
80
+ "required": ["entryRefs", "surfaceRefs", "controlRefs", "interactionRefs", "sourceEvidence", "codeRefs", "unresolvedRefs", "warningRefs", "requiresSourceReview"],
81
+ "properties": {
82
+ "entryRefs": { "$ref": "#/$defs/refs" },
83
+ "surfaceRefs": { "$ref": "#/$defs/refs" },
84
+ "controlRefs": { "$ref": "#/$defs/refs" },
85
+ "interactionRefs": { "$ref": "#/$defs/refs" },
86
+ "sourceEvidence": { "type": "array", "items": { "$ref": "#/$defs/evidence" } },
87
+ "codeRefs": { "type": "array", "items": { "type": "object" } },
88
+ "unresolvedRefs": { "$ref": "#/$defs/refs" },
89
+ "warningRefs": { "$ref": "#/$defs/refs" },
90
+ "requiresSourceReview": { "type": "boolean" }
91
+ },
92
+ "additionalProperties": false
93
+ },
94
+ "acceptance": {
95
+ "type": "object",
96
+ "required": ["observableOutcome", "requiredFactRefs", "verificationRequirements", "reportRefs"],
97
+ "properties": {
98
+ "observableOutcome": { "type": "string", "minLength": 1 },
99
+ "requiredFactRefs": { "$ref": "#/$defs/refs" },
100
+ "verificationRequirements": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
101
+ "reportRefs": { "$ref": "#/$defs/refs" }
102
+ },
103
+ "additionalProperties": false
104
+ },
105
+ "estimate": {
106
+ "type": "object",
107
+ "required": ["factCount", "sourceFileCount", "traceNodeCount", "estimatedFactTokens", "downstreamUnlockCount"],
108
+ "properties": {
109
+ "factCount": { "type": "integer", "minimum": 0 },
110
+ "sourceFileCount": { "type": "integer", "minimum": 0 },
111
+ "traceNodeCount": { "type": "integer", "minimum": 0 },
112
+ "estimatedFactTokens": { "type": "integer", "minimum": 0 },
113
+ "downstreamUnlockCount": { "type": "integer", "minimum": 0 }
114
+ },
115
+ "additionalProperties": false
116
+ }
117
+ },
118
+ "additionalProperties": false
119
+ },
120
+ "refs": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }
121
+ },
122
+ "additionalProperties": false
123
+ }
@@ -0,0 +1,162 @@
1
+ ---
2
+ name: android2hmos_resources_convert
3
+ description: >-
4
+ Android 图片资源迁移到 HarmonyOS:位图(png/jpg/webp/gif/bmp)、nine-patch(.9.png)、mipmap 启动图标、
5
+ 自适应图标(adaptive-icon → layered_image.json)以及 XML drawable(vector/shape/layer-list/selector → SVG)。
6
+ 当用户要求把 Android 项目的图标、图片、drawable 资产迁移/转换到鸿蒙工程(res/ → resources/…/media/),
7
+ 处理限定符目录映射(drawable-hdpi、drawable-night、mipmap-anydpi-v26 等),或修复迁移后图片在鸿蒙上
8
+ 显示空白/错误时触发。即使只说「迁移图标」「图片没迁移」「矢量图转 SVG」也应触发。
9
+ 不处理 values 资源(strings/colors/dimens 的迁移归 arkts-i18n)、布局、Lottie 和字体。
10
+ type: domain
11
+ domain: migration
12
+ tags: [migration, resources, android, images, svg, drawable]
13
+ ---
14
+
15
+ # Android → HarmonyOS 图片资源转换
16
+
17
+ 本 skill 只转换**图片类资源**:位图文件(png/jpg/webp/gif/bmp)、nine-patch 图片、启动图标(mipmap、自适应图标),
18
+ 以及作为图片渲染的 XML drawable(`<vector>`、`<shape>`、`<layer-list>`、`<selector>`)→ SVG。
19
+ values 资源(strings/colors/dimens 的迁移)、布局、Lottie、字体明确不在范围内;`values*/colors.xml` 和
20
+ `values*/dimens.xml` 只作为解析 drawable 内 `@color:`/`@dimen:` 引用的查找来源被读取。
21
+
22
+ ## 参考文档
23
+
24
+ | 要做什么 | 读什么 |
25
+ |---|---|
26
+ | 拷贝/转换位图、nine-patch、mipmap、自适应图标;限定符目录映射 | `references/image-conversion-rules.md` |
27
+ | Android XML Drawable(vector/shape/layer-list/selector)转 SVG | `references/xml-drawable-to-svg-rules.md` |
28
+ | 修复 SVG 显示问题(空白/不可见/尺寸错误/残留 Android 语法) | `references/svg-fix-patterns.md` |
29
+
30
+ ## 输入
31
+
32
+ 1. **Android 工程路径** — Android Gradle 工程根目录(含 `build.gradle` 或 `build.gradle.kts`)。
33
+ 2. **HarmonyOS 工程路径** — 由 Preflight 创建或复用的工程(见 `preparing-migration-workspace`),通常是迁移工作区下的 `ohos/`,或 `.migration/config.json` 中 `--harmony-project` 配置的路径。图片写入 `<harmony>/entry/src/main/resources/`。本 skill 不创建工程壳;`ohos/` 尚不存在时先运行 Preflight。
34
+
35
+ ## 工作流
36
+
37
+ ### 第 1 步:校验输入
38
+
39
+ 1. 确认 Android 工程路径存在且含 `build.gradle` 或 `build.gradle.kts`。
40
+ 2. 通过 `droid2hmos status <ANDROID_PROJECT>` 或 `.migration/config.json` 确认 HarmonyOS 工程位置,并确认 `entry/src/main/resources/` 存在;不存在时停止并先补 Preflight,不要猜测工程结构。
41
+
42
+ ### 第 2 步:确定资源来源
43
+
44
+ 使用工程源码 `res/` 目录:
45
+
46
+ - 首选 `<android_project>/app/src/main/res/`
47
+ - 多模块工程同时检查其它模块目录
48
+ - 使用 flavor source set 时一并纳入(如 `app/src/debug/res/`、`app/src/flavor/res/`)
49
+
50
+ 恒定从源码 `res/` 转换:仅由库依赖(AAR)提供的图片不在源码 `res/` 中,这类引用在报告中记为 unresolved,不尝试回收。
51
+
52
+ ### 第 3 步:清点与分类
53
+
54
+ 扫描资源来源中的每个 `drawable*/` 和 `mipmap*/` 目录。对每个文件按**内容**分类(`.xml` 文件读根元素判断,绝不只按目录名分类):
55
+
56
+ | 分类 | 判定 | 路由 |
57
+ |---|---|---|
58
+ | 位图 | `.png`、`.jpg`、`.jpeg`、`.gif`、`.webp`、`.bmp` | 直接拷贝(第 4.1 步) |
59
+ | Nine-patch | `.9.png` | 拷贝 + 重命名(第 4.1 步) |
60
+ | XML drawable:vector/shape/layer-list | `.xml`,根 `<vector>` / `<shape>` / `<layer-list>` | 转 SVG(第 4.2 步) |
61
+ | XML drawable:selector | `.xml`,根 `<selector>` | 提取默认状态 → SVG(第 4.2 步) |
62
+ | 自适应图标 | `.xml`,根 `<adaptive-icon>` | 转 layered-image JSON(第 4.3 步) |
63
+ | ripple/animated-vector/animated-selector/transition/level-list 等 | `.xml`,对应根元素 | 不可映射 — 记入报告 |
64
+
65
+ 忽略 `values*/`、`layout*/`、`menu/`、`raw/`、`font/`、`xml/`、`anim*/`、`color/` — 超出范围。只有 `values*/colors.xml` 和 `values*/dimens.xml` 被读取,用于解析 drawable 内的 `@color:`/`@dimen:` 引用(第 4.4 步)。
66
+
67
+ ### 第 4 步:转换
68
+
69
+ 转换前先读 `references/image-conversion-rules.md`。四条路由概要:
70
+
71
+ **4.1 位图与 nine-patch → `media/`**
72
+ - 拷贝到限定符映射后的 `media/` 目录(完整限定符算法见 image-conversion-rules.md)
73
+ - `.9.png` → 重命名为 `<name>_9.png`(HarmonyOS 禁止资源文件名中含 `.`,仅允许最后扩展名分隔符)。nine-patch 拉伸语义丢失 — 报告中记录
74
+
75
+ **4.2 XML drawable → `media/` 中的 `.svg`**
76
+ - 严格按 `references/xml-drawable-to-svg-rules.md` 执行 — 尤其是强制保留 `clip-path`、三分支 `fill` 规则和渐变处理
77
+ - 每生成一个 SVG 后,执行该文档中的自检(clip-path 数量、fill 规则、viewBox 匹配)
78
+
79
+ **4.3 自适应图标 → layered-image JSON**
80
+ - `<adaptive-icon>` → `<name>_layered_image.json`,只含 `background`/`foreground` 键
81
+ - `@drawable/xxx`、`@mipmap/xxx` → `$media:xxx`;`@color/xxx` → 生成纯色 PNG(`<color_name>_bg.png`)— layered-image 不接受 `$color:` 引用
82
+ - `monochrome` 不写入 JSON,但其引用的 drawable 仍按普通图片转换
83
+
84
+ **4.4 解析 drawable 内引用**
85
+ - SVG 填充/描边中的 `@color/name` → 从 `values*/colors.xml` 解析(沿引用链;兜底 `#000000` + 记录)
86
+ - SVG 尺寸中的 `@dimen/name` → 从 `values*/dimens.xml` 解析(兜底:合理默认值 + 记录)
87
+ - 未解析引用(库专属资源不在源码 `res/`)记入报告,绝不静默丢弃
88
+
89
+ ### 第 5 步:完整性校验
90
+
91
+ 1. 第 3 步发现的每个文件都有且只有一个结局:已转换,或在报告中列为 unmappable/unmapped
92
+ 2. 每个转换产物都实际存在于 HarmonyOS 工程
93
+ 3. 生成的 layered-image JSON 中每个 `$media:xxx` 引用都指向 `media/` 中存在的文件
94
+ 4. 每个转换后的 SVG 通过 `references/xml-drawable-to-svg-rules.md` 的自检
95
+ 5. HarmonyOS 工程已有 `.ets` 文件时,扫描 `$r('app.media.xxx')` 并核对每个引用的图片存在(已有 media 文件**不覆盖** — 合并,冲突记录)
96
+
97
+ ### 第 6 步:生成报告
98
+
99
+ 按 `maintaining-migration-report` 的轻量原则,把转换报告落盘到迁移工作区(如 `.migration/` 下)或直接向用户呈现,结构如下:
100
+
101
+ ```
102
+ # Android to HarmonyOS Image Conversion Report
103
+
104
+ ## Resource Source
105
+ - Resource source: source res/ (library-only images not included)
106
+ - Resource source path: <path>
107
+
108
+ ## Summary
109
+ - Image files found (bitmap/9-patch/XML drawable/adaptive icon): <count per class>
110
+ - Successfully converted: <count>
111
+ - Unmappable (ripple/animated-vector/etc.): <count>
112
+ - Unmapped (unsupported qualifiers): <count>
113
+ - Unresolved color/dimen references: <count>
114
+
115
+ ## Converted Images
116
+ | Android Source | HarmonyOS Target | Type | Notes |
117
+ |---|---|---|---|
118
+
119
+ ## Qualifier Mappings Applied
120
+ | Android Qualifier Dir | HarmonyOS Qualifier Dir | Files Converted |
121
+ |---|---|---|---|
122
+
123
+ ## Unmappable Resources
124
+ | Android Source | Reason |
125
+ |---|---|
126
+
127
+ ## Unresolved References
128
+ | Resource File | Reference | Reason | Likely Source |
129
+ |---|---|---|---|
130
+
131
+ ## Verification Results
132
+ - All image files accounted for: Yes/No
133
+ - All $media references satisfied: Yes/No
134
+ - SVG self-checks passed: Yes/No
135
+ ```
136
+
137
+ 影响行为的结论(不可映射资源、丢失的 nine-patch 语义、未解析引用)必须回流到对应报告分片的说明,或按 orchestrator 约定写入 `discoveries.json`;不要只留在一次性报告里。
138
+
139
+ ### 第 7 步:Git 检查点
140
+
141
+ 一个连贯、已校验的转换批次完成后,按仓库约定创建检查点(只纳入 HarmonyOS 工程内的资源文件):
142
+
143
+ ```text
144
+ droid2hmos checkpoint create <ANDROID_PROJECT> --message <MESSAGE> --include <harmony>/entry/src/main/resources
145
+ ```
146
+
147
+ ## 重要说明
148
+
149
+ - **XML drawable 转换是关键**:vector/shape/layer-list/selector 必须转成 SVG,不能跳过。转换前务必读 `references/xml-drawable-to-svg-rules.md` — 其中的属性映射表就是规范。
150
+ - **SVG 渲染问题**(空白、不可见、尺寸错误、残留 `android:` 语法)按 `references/svg-fix-patterns.md` 处理,不做临时猜测。
151
+ - **限定符目录是映射,不是保留**:`drawable-hdpi` → `ldpi/media/`(两平台 DPI 标签不同);`night` → `dark`;`land` → `horizontal`;`v<N>` 剥离;`sw<N>dp`/`w<N>dp`/屏幕尺寸限定符整目录跳过。完整算法见 `references/image-conversion-rules.md`。
152
+ - **转换恒定从源码 `res/` 出发**:仅库依赖(AAR)提供的图片不在其中;对它们的引用按 unresolved 报告,不做恢复。
153
+ - 资源名保持 Android 原拼写 — 它们是标识符。
154
+ - 解析 Android XML 时正确处理命名空间、注释和 CDATA;按 local name 匹配属性。
155
+
156
+ ## 与其他 skill 的关系
157
+
158
+ - **preparing-migration-workspace**:⭐ 前置依赖。本 skill 需要 Preflight 已创建或复用的 HarmonyOS 工程(`ohos/`)。
159
+ - **arkts-app-identity**:它处理 App 级身份资源(app.json5 图标字段、版本号、包名);本 skill 负责 res/ 全量图片资产进 `media/`。启动器图标的位图/分层资产由本 skill 转换,app.json5 的接线归它。
160
+ - **arkts-icon-sizing**:图片资产就位后,它修 `.ets` 消费侧丢失的 `.width()/.height()`;本 skill 只管资源侧。
161
+ - **arkts-i18n**:values 资源(string.json 等)的迁移归它;本 skill 只把 colors.xml/dimens.xml 当查找源。
162
+ - **maintaining-migration-report**:转换结论回流报告分片的轻量约定。