@buaa_smat/hometrans 0.1.4 → 0.1.6
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/LICENSE +21 -21
- package/README.md +17 -18
- package/agents/build-fixer.md +6 -5
- package/agents/{logic-coding.md → logic-coder.md} +2 -2
- package/agents/logic-context-builder.md +1 -1
- package/agents/self-tester.md +19 -8
- package/package.json +1 -1
- package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/SKILL.md +3 -3
- package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/conversion-procedure.md +2 -2
- package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mappings/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +3 -5
- package/skills/{convert_pipeline → hmos-convert-pipeline}/SKILL.md +4 -4
- package/skills/hmos-fix-build-errors/SKILL.md +265 -0
- package/skills/hmos-fix-build-errors/references/arkts-strict-patterns.md +219 -0
- package/skills/hmos-fix-build-errors/references/known-patterns.md +157 -0
- package/skills/hmos-fix-build-errors/references/rdb-entity-pattern.md +131 -0
- package/skills/{hmos-ui-align → hmos-incremental-ui-align}/SKILL.md +4 -2
- package/skills/{hmos-ui-align → hmos-incremental-ui-align}/readme.md +5 -6
- package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +3 -5
- package/skills/{self-test → hmos-integration-test}/SKILL.md +1 -1
- package/skills/{self-test → hmos-integration-test}/readme.md +3 -3
- package/skills/{spec-generator-skill → hmos-spec-generate}/SKILL.md +1 -1
- package/agents/code-review-fix.md +0 -356
- package/dist/cli/config-store.js +0 -143
- package/dist/cli/config.js +0 -40
- package/dist/cli/index.js +0 -43
- package/dist/cli/init.js +0 -366
- package/dist/cli/mcp-setup.js +0 -262
- package/dist/cli/mcp.js +0 -94
- package/dist/cli/uninstall.js +0 -310
- package/dist/context/index.js +0 -788
- package/skills/code-dev-review-fix/SKILL.md +0 -279
- package/skills/code-dev-review-fix-workspace/evals/evals.json +0 -56
- package/skills/code-dev-review-fix-workspace/iteration-1/routing-results.md +0 -23
- package/skills/hmos-ui-align/config.json +0 -11
- /package/agents/{logic-coding → logic-coder}/scripts/platform_context_query.py +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mappings/android-to-harmonyOS-ui-interaction-mapping-reference.md +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mappings/android-to-harmonyOS-ui-layout-mapping-reference.md +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/@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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm/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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/references/mvvm//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" +0 -0
- /package/skills/{hmos-ui-align-batch → hmos-batch-ui-align}/scripts/android_parse_fast.py +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/config-example.json +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/diff_analysis.md +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/page_align.md +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/Comparison_Template.md +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/MVVM/346/250/241/345/274/217V1.md" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243//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" +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/UI_Analysis_Template.md +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/android-to-harmonyOS-ui-interaction-mapping-reference.md +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/references/android-to-harmonyOS-ui-layout-mapping-reference.md +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/scripts/app_feature_verify.py +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/scripts/navigation-capure.md +0 -0
- /package/skills/{hmos-ui-align → hmos-incremental-ui-align}/scripts/page_capture.py +0 -0
- /package/skills/{spec-generator-skill → hmos-spec-generate}/references/android-platform-tokens.md +0 -0
- /package/skills/{spec-generator-skill → hmos-spec-generate}/references/spec-sample-1.md +0 -0
- /package/skills/{spec-generator-skill → hmos-spec-generate}/references/spec-sample-2.md +0 -0
- /package/skills/{spec-generator-skill → hmos-spec-generate}/references/spec-sample-3.md +0 -0
- /package/skills/{spec-generator-skill → hmos-spec-generate}/references/step4-report-template.md +0 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# ArkTS 严格模式确定性修复 Pattern
|
|
2
|
+
# 适用于: ArkTS 严格模式编译错误
|
|
3
|
+
# 触发场景: 编译报错 arkts-no-xxx 系列
|
|
4
|
+
# 经验来源: EinkBro 迁移 (2026-03-26)
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Pattern 1: throw 语句
|
|
9
|
+
|
|
10
|
+
### 错误写法
|
|
11
|
+
```typescript
|
|
12
|
+
throw err; // ERROR: arkts-limited-throw
|
|
13
|
+
throw 'error string'; // ERROR: arkts-limited-throw
|
|
14
|
+
throw unknownVariable; // ERROR: arkts-limited-throw
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 正确写法
|
|
18
|
+
```typescript
|
|
19
|
+
throw new Error(String(error));
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 不需要修改的情况
|
|
23
|
+
```typescript
|
|
24
|
+
throw new Error('specific message'); // OK - 已经是 Error 实例
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Pattern 2: 对象字面量作为参数 (arkts-no-untyped-obj-literals)
|
|
30
|
+
|
|
31
|
+
### 错误写法
|
|
32
|
+
```typescript
|
|
33
|
+
// ERROR: Object literal must correspond to some explicitly declared class or interface
|
|
34
|
+
const response = await this.sendRequest(url, { contents });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 正确写法 — 先声明变量
|
|
38
|
+
```typescript
|
|
39
|
+
interface GeminiRequestBody {
|
|
40
|
+
contents: GeminiContent[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const requestBody: GeminiRequestBody = { contents };
|
|
44
|
+
const response = await this.sendRequest(url, requestBody);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 内联参数场景
|
|
48
|
+
```typescript
|
|
49
|
+
// 方法参数也是对象字面量,同样需要处理
|
|
50
|
+
httpRequest.request(url, {
|
|
51
|
+
method: http.RequestMethod.POST,
|
|
52
|
+
header: { 'Content-Type': 'application/json' },
|
|
53
|
+
extraData: JSON.stringify(body),
|
|
54
|
+
connectTimeout: 30000,
|
|
55
|
+
readTimeout: 30000
|
|
56
|
+
});
|
|
57
|
+
// ^ 这种场景 SDK 方法签名本身接受 object 类型,通常 OK
|
|
58
|
+
// 但自定义方法调用时必须用已声明接口的变量
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Pattern 3: Margin vertical 简写不支持
|
|
64
|
+
|
|
65
|
+
### 错误写法
|
|
66
|
+
```typescript
|
|
67
|
+
.margin({ vertical: 8 }); // ERROR: 'vertical' does not exist in type
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 正确写法
|
|
71
|
+
```typescript
|
|
72
|
+
.margin({ top: 8, bottom: 8 });
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 常见场景
|
|
76
|
+
| 错误 | 正确 |
|
|
77
|
+
|------|------|
|
|
78
|
+
| `.margin({ vertical: 8 })` | `.margin({ top: 8, bottom: 8 })` |
|
|
79
|
+
| `.margin({ horizontal: 16 })` | `.margin({ left: 16, right: 16 })` |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Pattern 4: List 内不能直接放 Divider
|
|
84
|
+
|
|
85
|
+
### 错误写法
|
|
86
|
+
```typescript
|
|
87
|
+
List() {
|
|
88
|
+
ForEach(items, (item) => {
|
|
89
|
+
ListItem() { /* ... */ }
|
|
90
|
+
})
|
|
91
|
+
Divider() // ERROR: List children must be ListItem only
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 正确写法 — 用 ListItem + border
|
|
96
|
+
```typescript
|
|
97
|
+
List() {
|
|
98
|
+
ForEach(items, (item) => {
|
|
99
|
+
ListItem() {
|
|
100
|
+
Column() {
|
|
101
|
+
Text(item.name)
|
|
102
|
+
}
|
|
103
|
+
.width('100%')
|
|
104
|
+
.padding(12)
|
|
105
|
+
.border({ width: { bottom: 1 }, color: '#E0E0E0' }) // 替代 Divider 分隔线
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 另一种方案 — border 直接在 ListItem 上
|
|
112
|
+
```typescript
|
|
113
|
+
ListItem() {
|
|
114
|
+
// content
|
|
115
|
+
}
|
|
116
|
+
.border({ width: { bottom: 1 }, color: '#E0E0E0' })
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Pattern 5: 数组字面量类型推断 (arkts-no-noninferrable-arr-literals)
|
|
122
|
+
|
|
123
|
+
### 错误写法
|
|
124
|
+
```typescript
|
|
125
|
+
const arr = [1, 2, 3].map(x => ({ val: x }));
|
|
126
|
+
// ERROR: Array literals must contain elements of only inferrable types
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 正确写法 — 显式类型
|
|
130
|
+
```typescript
|
|
131
|
+
interface Item { val: number; }
|
|
132
|
+
const arr: Item[] = [1, 2, 3].map((x): Item => ({ val: x }));
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Pattern 6: TextDecoder 不存在
|
|
138
|
+
|
|
139
|
+
### 错误写法
|
|
140
|
+
```typescript
|
|
141
|
+
const decoder = new TextDecoder(); // ERROR: Cannot find name 'TextDecoder'
|
|
142
|
+
const str = decoder.decode(data);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 正确写法
|
|
146
|
+
```typescript
|
|
147
|
+
const bytes = new Uint8Array(data);
|
|
148
|
+
let chunk = '';
|
|
149
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
150
|
+
chunk += String.fromCharCode(bytes[i]);
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Pattern 7: HTTP 组件事件名
|
|
157
|
+
|
|
158
|
+
| 错误事件 | 正确事件 | 说明 |
|
|
159
|
+
|---------|---------|------|
|
|
160
|
+
| `request.on('requestEnd', ...)` | `request.on('dataEnd', ...)` | 请求结束事件 |
|
|
161
|
+
| `request.on('error', ...)` | 改用 Promise 的 catch | HTTP 组件 error 事件签名不标准 |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Pattern 8: GeminiService 等自定义类缺少成员
|
|
166
|
+
|
|
167
|
+
### 错误场景
|
|
168
|
+
```typescript
|
|
169
|
+
class GeminiService {
|
|
170
|
+
private async sendRequest(url: string, body: object): Promise<Object> {
|
|
171
|
+
httpRequest.request(url, { extraData: JSON.stringify(body),
|
|
172
|
+
connectTimeout: this.timeout, // ERROR: Property 'timeout' does not exist
|
|
173
|
+
readTimeout: this.timeout
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// timeout 属性忘记声明
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 正确 — 确保所有成员都在类体内声明
|
|
181
|
+
```typescript
|
|
182
|
+
class GeminiService {
|
|
183
|
+
private timeout: number = 30000; // 在类体内声明
|
|
184
|
+
private async sendRequest(...) { ... }
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Pattern 9: Button 不支持 emoji
|
|
191
|
+
|
|
192
|
+
### 错误写法
|
|
193
|
+
```typescript
|
|
194
|
+
Button('X') // 有时 emoji 渲染异常
|
|
195
|
+
Button('🗑')
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 正确写法
|
|
199
|
+
```typescript
|
|
200
|
+
Button('Del') // 纯文本
|
|
201
|
+
Button('Copy')
|
|
202
|
+
Button('Back')
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 快速检查清单
|
|
208
|
+
|
|
209
|
+
遇到 ArkTS 编译错误时,按序检查:
|
|
210
|
+
|
|
211
|
+
1. throw → `throw new Error(String(x))`
|
|
212
|
+
2. 对象字面量作为参数 → 先赋值给显式类型变量
|
|
213
|
+
3. any / unknown → `Object` + `as Function` / `as SomeType`
|
|
214
|
+
4. // @ts-ignore → 禁止,必须用类型操作替代
|
|
215
|
+
5. ValuesBucket → 普通对象字面量 `{}`
|
|
216
|
+
6. margin { vertical } → `{ top, bottom }`
|
|
217
|
+
7. List 内 Divider → ListItem + border
|
|
218
|
+
8. TextDecoder → Uint8Array 遍历
|
|
219
|
+
9. `new SomeType()` 报错 → 检查是否是 type alias 而非 class
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Known Compile Error Patterns
|
|
2
|
+
|
|
3
|
+
> **This file is auto-maintained by `a2h-retrospect`.**
|
|
4
|
+
> Manual edits are allowed but may be overwritten when retrospect detects updated patterns.
|
|
5
|
+
> Last updated: 2026-03-27
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Pattern Index
|
|
10
|
+
|
|
11
|
+
| # | Error Code / Type | Frequency | Short Description |
|
|
12
|
+
|---|-------------------|-----------|-------------------|
|
|
13
|
+
| 1 | arkts-identifiers-as-prop-names | 85 | ValuesBucket computed property name |
|
|
14
|
+
| 2 | type mismatch (EventData) | 16 | EventData double type cast |
|
|
15
|
+
| 3 | arkts-no-untyped-obj-literals | 9 | Untyped object literal |
|
|
16
|
+
| 4 | type mismatch (promptAction) | 8 | promptAction button color type |
|
|
17
|
+
| 5 | type error (@Prop) | 3 | @Prop naming conflict |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. ValuesBucket Computed Property Name
|
|
22
|
+
|
|
23
|
+
- **Date**: 2026-03-27
|
|
24
|
+
- **Error code**: `arkts-identifiers-as-prop-names`
|
|
25
|
+
- **Frequency**: 85 occurrences
|
|
26
|
+
- **Source**: AntennaPod V1 migration (a2h-retrospect-report-2026-03-27)
|
|
27
|
+
|
|
28
|
+
**Error code**:
|
|
29
|
+
```typescript
|
|
30
|
+
const bucket: ValuesBucket = {
|
|
31
|
+
[ColumnName.TITLE]: title, // ERROR: computed property name not allowed
|
|
32
|
+
[ColumnName.URL]: url,
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Correct code**:
|
|
37
|
+
```typescript
|
|
38
|
+
const bucket: ValuesBucket = {};
|
|
39
|
+
bucket[ColumnName.TITLE] = title;
|
|
40
|
+
bucket[ColumnName.URL] = url;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Rule**: ArkTS forbids computed property names (`[expr]: value`) in object literals. Build the object first, then assign properties via bracket notation.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 2. EventData Double Type Cast
|
|
48
|
+
|
|
49
|
+
- **Date**: 2026-03-27
|
|
50
|
+
- **Error code**: type mismatch
|
|
51
|
+
- **Frequency**: 16 occurrences
|
|
52
|
+
- **Source**: AntennaPod V1 migration (a2h-retrospect-report-2026-03-27)
|
|
53
|
+
|
|
54
|
+
**Error code**:
|
|
55
|
+
```typescript
|
|
56
|
+
emitter.on({ eventId: 1 }, (data: emitter.EventData) => {
|
|
57
|
+
const value = data.data?.['key'] as string; // ERROR: data.data is optional Record, direct cast fails
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Correct code**:
|
|
62
|
+
```typescript
|
|
63
|
+
emitter.on({ eventId: 1 }, (data: emitter.EventData) => {
|
|
64
|
+
const raw = data.data as Record<string, Object>;
|
|
65
|
+
const value = raw['key'] as string;
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Rule**: `EventData.data` is typed `Record<string, Object> | undefined`. Access requires two steps: (1) cast to `Record<string, Object>`, (2) cast the extracted value to the target type.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 3. Untyped Object Literal
|
|
74
|
+
|
|
75
|
+
- **Date**: 2026-03-27
|
|
76
|
+
- **Error code**: `arkts-no-untyped-obj-literals`
|
|
77
|
+
- **Frequency**: 9 occurrences
|
|
78
|
+
- **Source**: AntennaPod V1 migration (a2h-retrospect-report-2026-03-27)
|
|
79
|
+
|
|
80
|
+
**Error code**:
|
|
81
|
+
```typescript
|
|
82
|
+
const options = {
|
|
83
|
+
title: 'Hello',
|
|
84
|
+
message: 'World',
|
|
85
|
+
}; // ERROR: object literal without explicit type annotation
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Correct code**:
|
|
89
|
+
```typescript
|
|
90
|
+
interface DialogOptions {
|
|
91
|
+
title: string;
|
|
92
|
+
message: string;
|
|
93
|
+
}
|
|
94
|
+
const options: DialogOptions = {
|
|
95
|
+
title: 'Hello',
|
|
96
|
+
message: 'World',
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Rule**: ArkTS requires all object literals to have an explicit type. Define an `interface` or `class` and annotate the variable.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 4. promptAction Button Color Type
|
|
105
|
+
|
|
106
|
+
- **Date**: 2026-03-27
|
|
107
|
+
- **Error code**: type mismatch
|
|
108
|
+
- **Frequency**: 8 occurrences
|
|
109
|
+
- **Source**: AntennaPod V1 migration (a2h-retrospect-report-2026-03-27)
|
|
110
|
+
|
|
111
|
+
**Error code**:
|
|
112
|
+
```typescript
|
|
113
|
+
promptAction.showDialog({
|
|
114
|
+
buttons: [
|
|
115
|
+
{ text: 'OK', color: '#ff0000' } // ERROR: color expects ResourceColor, not string
|
|
116
|
+
]
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Correct code**:
|
|
121
|
+
```typescript
|
|
122
|
+
promptAction.showDialog({
|
|
123
|
+
buttons: [
|
|
124
|
+
{ text: 'OK', color: Color.Red }
|
|
125
|
+
]
|
|
126
|
+
});
|
|
127
|
+
// Or use $r('app.color.xxx') for resource reference
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Rule**: `promptAction.showDialog` button `color` property expects `ResourceColor` type (Color enum or `$r()` resource reference), not a raw hex string.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 5. @Prop Naming Conflict
|
|
135
|
+
|
|
136
|
+
- **Date**: 2026-03-27
|
|
137
|
+
- **Error code**: type error
|
|
138
|
+
- **Frequency**: 3 occurrences
|
|
139
|
+
- **Source**: AntennaPod V1 migration (a2h-retrospect-report-2026-03-27)
|
|
140
|
+
|
|
141
|
+
**Error code**:
|
|
142
|
+
```typescript
|
|
143
|
+
@Component
|
|
144
|
+
struct MyComponent {
|
|
145
|
+
@Prop title: string = ''; // ERROR: 'title' conflicts with built-in component property
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Correct code**:
|
|
150
|
+
```typescript
|
|
151
|
+
@Component
|
|
152
|
+
struct MyComponent {
|
|
153
|
+
@Prop itemTitle: string = ''; // Renamed to avoid conflict
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Rule**: Certain property names (`title`, `content`, `action`, etc.) conflict with built-in component attributes. Prefix with a domain-specific qualifier (e.g., `itemTitle`, `feedTitle`).
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# RDB Entity 确定性修复 Pattern
|
|
2
|
+
# 适用于: ArkTS 严格模式 + @kit.ArkData relationalStore
|
|
3
|
+
# 触发场景: 迁移 Android RDB 实体类到 ArkTS 时
|
|
4
|
+
# 经验来源: EinkBro 迁移 (2026-03-26)
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Pattern 1: ValuesBucket 正确用法
|
|
9
|
+
|
|
10
|
+
### 错误写法 (编译报错)
|
|
11
|
+
```typescript
|
|
12
|
+
import { relationalStore, ValuesBucket } from '@kit.ArkData';
|
|
13
|
+
|
|
14
|
+
toValuesBucket(): ValuesBucket {
|
|
15
|
+
const bucket = new ValuesBucket(); // ERROR: 'ValuesBucket' only refers to a type
|
|
16
|
+
bucket.put('key', value); // ERROR: ValuesBucket has no .put() method
|
|
17
|
+
return bucket;
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 正确写法
|
|
22
|
+
```typescript
|
|
23
|
+
type EntityValuesBucket = Record<string, number | string | boolean | Uint8Array | null>;
|
|
24
|
+
|
|
25
|
+
toValuesBucket(): EntityValuesBucket {
|
|
26
|
+
const bucket: EntityValuesBucket = {};
|
|
27
|
+
bucket['key'] = value;
|
|
28
|
+
return bucket;
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**原因**: `ValuesBucket` 在 SDK 中是 type alias (`Record<string, ValueType>`),不是可实例化的类。
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Pattern 2: fromResultSet 参数类型 (禁止 any)
|
|
37
|
+
|
|
38
|
+
### 错误写法 (编译报错)
|
|
39
|
+
```typescript
|
|
40
|
+
// ArkTS 严格模式禁止 any
|
|
41
|
+
static fromResultSet(resultSet: any): EntityName { // ERROR: arkts-no-any-unknown
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 正确写法
|
|
45
|
+
```typescript
|
|
46
|
+
static fromResultSet(resultSet: Object): EntityName {
|
|
47
|
+
const rs = resultSet as Record<string, Object>;
|
|
48
|
+
const colIndex = (name: string): number =>
|
|
49
|
+
(rs['getColumnIndex'] as Function)(name) as number;
|
|
50
|
+
|
|
51
|
+
entity.field = (rs['getLong'] as Function)(colIndex('field_name')) as number;
|
|
52
|
+
entity.name = (rs['getString'] as Function)(colIndex('name')) as string;
|
|
53
|
+
return entity;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**替代方案** (更简洁但运行时开销略高):
|
|
58
|
+
```typescript
|
|
59
|
+
// 使用类型断言避免 any,运行时通过 Record<string, Function> 调用
|
|
60
|
+
static fromResultSet(resultSet: Object): EntityName {
|
|
61
|
+
const getCol = (name: string): number =>
|
|
62
|
+
(resultSet as Record<string, Function>)['getColumnIndex'](name) as number;
|
|
63
|
+
const getLong = (name: string): number =>
|
|
64
|
+
(resultSet as Record<string, Function>)['getLong'](getCol(name)) as number;
|
|
65
|
+
const getStr = (name: string): string =>
|
|
66
|
+
(resultSet as Record<string, Function>)['getString'](getCol(name)) as string;
|
|
67
|
+
|
|
68
|
+
const entity = new EntityName();
|
|
69
|
+
entity.id = getLong('id');
|
|
70
|
+
entity.name = getStr('name');
|
|
71
|
+
return entity;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Pattern 3: // @ts-ignore 不可用
|
|
78
|
+
|
|
79
|
+
### 错误尝试
|
|
80
|
+
```typescript
|
|
81
|
+
// @ts-ignore // ERROR: Switching off type checks with in-place comments is not allowed
|
|
82
|
+
static fromResultSet(resultSet: any): EntityName {
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 必须用 Pattern 2 替代
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Pattern 4: toValuesBucket() 返回类型注解
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
type EntityValuesBucket = Record<string, number | string | boolean | Uint8Array | null>;
|
|
93
|
+
|
|
94
|
+
toValuesBucket(): EntityValuesBucket {
|
|
95
|
+
const bucket: EntityValuesBucket = {} as EntityValuesBucket;
|
|
96
|
+
// ...
|
|
97
|
+
return bucket;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 完整 Entity 模板
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
type EntityValuesBucket = Record<string, number | string | boolean | Uint8Array | null>;
|
|
107
|
+
|
|
108
|
+
export class MyEntity {
|
|
109
|
+
id: number = 0;
|
|
110
|
+
name: string = '';
|
|
111
|
+
value: number = 0;
|
|
112
|
+
|
|
113
|
+
static fromResultSet(resultSet: Object): MyEntity {
|
|
114
|
+
const rs = resultSet as Record<string, Object>;
|
|
115
|
+
const col = (n: string): number => (rs['getColumnIndex'] as Function)(n) as number;
|
|
116
|
+
const entity = new MyEntity();
|
|
117
|
+
entity.id = (rs['getLong'] as Function)(col('id')) as number;
|
|
118
|
+
entity.name = (rs['getString'] as Function)(col('name')) as string;
|
|
119
|
+
entity.value = (rs['getLong'] as Function)(col('value')) as number;
|
|
120
|
+
return entity;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
toValuesBucket(): EntityValuesBucket {
|
|
124
|
+
const bucket: EntityValuesBucket = {} as EntityValuesBucket;
|
|
125
|
+
if (this.id > 0) { bucket['id'] = this.id; }
|
|
126
|
+
bucket['name'] = this.name;
|
|
127
|
+
bucket['value'] = this.value;
|
|
128
|
+
return bucket;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: hmos-ui-align
|
|
2
|
+
name: hmos-incremental-ui-align
|
|
3
3
|
description: "Automated HarmonyOS-Android UI alignment pipeline. Takes a natural language task description, automatically navigates to the target pages on both Android and HarmonyOS devices, captures view trees and screenshots, then aligns HarmonyOS code to match Android. Use this skill whenever the user wants to align a HarmonyOS page with its Android counterpart, fix visual differences between Android and HarmonyOS, add missing HarmonyOS pages based on Android, or describes a page path like '首页-设置-关于' that needs UI alignment. Also trigger on phrases like 'UI对齐', '页面对齐', '和安卓对齐', '鸿蒙页面修复','UI增量开发','align HarmonyOS with Android', or any request involving comparing and fixing HarmonyOS UI to match Android."
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -17,7 +17,9 @@ You are writing ArkTS codes.
|
|
|
17
17
|
- 不要做和用户需求无关的其他修改
|
|
18
18
|
-
|
|
19
19
|
## Step 0: Load Config
|
|
20
|
-
|
|
20
|
+
The user MUST specify the path to a `config.json` file when invoking this skill (e.g., as part of the request: "config: D:\path\to\config.json"). Read that file from the user-provided path. If the user did not provide a path, ask them for it before proceeding. See `config-example.json` in this skill's directory for the expected schema.
|
|
21
|
+
|
|
22
|
+
The config provides all fixed paths so the user only describes what needs to be aligned.
|
|
21
23
|
Key config fields:
|
|
22
24
|
- `android.app_name`, `android.package` — Android app info for navigation
|
|
23
25
|
- `android.project_dir` — Android source code root
|
|
@@ -45,7 +45,7 @@ HarmonyOS-Android UI 自动对齐流水线。
|
|
|
45
45
|
|
|
46
46
|
## 配置 `config.json`
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
首次使用前,自行准备一份 `config.json`(放任何位置都可以),调用 skill 时把它的**绝对路径**作为参数传给 skill。可复制同目录下的 `config-example.json` 作为模板。字段说明:
|
|
49
49
|
|
|
50
50
|
| 字段 | 说明 | 示例 |
|
|
51
51
|
|---|---|---|
|
|
@@ -65,10 +65,10 @@ HarmonyOS-Android UI 自动对齐流水线。
|
|
|
65
65
|
|
|
66
66
|
## 使用方式
|
|
67
67
|
|
|
68
|
-
在 Claude Code 里直接调用 skill
|
|
68
|
+
在 Claude Code 里直接调用 skill,**必须把准备好的 `config.json` 的绝对路径附在需求里**:
|
|
69
69
|
|
|
70
70
|
```
|
|
71
|
-
/hmos-ui-align <自然语言需求,描述要对齐的页面+点击路径>
|
|
71
|
+
/hmos-ui-align config: <绝对路径/config.json> <自然语言需求,描述要对齐的页面+点击路径>
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
### 写需求的三个要点
|
|
@@ -112,7 +112,7 @@ HarmonyOS-Android UI 自动对齐流水线。
|
|
|
112
112
|
skill 会严格按 `SKILL.md` 里的 5 步流水线跑:
|
|
113
113
|
|
|
114
114
|
### Step 0 · 加载 config
|
|
115
|
-
|
|
115
|
+
读用户指定路径下的 `config.json`,解析出所有路径和 API Key。
|
|
116
116
|
|
|
117
117
|
### Step 1 · 双端页面采集
|
|
118
118
|
1.1 解析你的需求,拆成一组「基础页」,每个基础页有 `android_nav_path` 和 `hmos_nav_path`
|
|
@@ -161,8 +161,7 @@ skill 会严格按 `SKILL.md` 里的 5 步流水线跑:
|
|
|
161
161
|
Agents/hmos-ui-align/
|
|
162
162
|
├── SKILL.md # 流水线定义(主 agent 执行逻辑)
|
|
163
163
|
├── readme.md # 本文档
|
|
164
|
-
├── config.json
|
|
165
|
-
├── config-example.json # 配置样例
|
|
164
|
+
├── config-example.json # 配置样例(实际使用的 config.json 由用户自备并显式传路径)
|
|
166
165
|
├── page_align.md # Step 3 的转换规则
|
|
167
166
|
├── diff_analysis.md # 内部说明
|
|
168
167
|
├── scripts/
|
|
@@ -2524,11 +2524,9 @@ Column() {
|
|
|
2524
2524
|
|
|
2525
2525
|
## 参考链接
|
|
2526
2526
|
|
|
2527
|
-
1. **
|
|
2528
|
-
2. **
|
|
2529
|
-
3. **
|
|
2530
|
-
4. **Android UI 组件总览**: https://developer.android.com/develop/ui
|
|
2531
|
-
5. **Material Design 3 规范**: https://m3.material.io/components
|
|
2527
|
+
1. **HarmonyOS 开发者文档**: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/
|
|
2528
|
+
2. **Android UI 组件总览**: https://developer.android.com/develop/ui
|
|
2529
|
+
3. **Material Design 3 规范**: https://m3.material.io/components
|
|
2532
2530
|
|
|
2533
2531
|
---
|
|
2534
2532
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: hmos-integration-test
|
|
3
3
|
description: "Run on-device self-test for a HarmonyOS app. Parse test_case.md, install the HAP, execute AutoTest, and produce a verification report. Optionally enters a test-and-fix loop. Triggers on phrases like '跑自测', '运行自测', '执行自测', '自动测试', '设备测试', '跑用例', '跑自动化测试', 'self test', 'run autotest'."
|
|
4
4
|
allowed-tools:
|
|
5
5
|
- Read
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
| 达到最大轮数 | `max_rounds_reached` | 已完成配置的最大轮数循环(`max-rounds`,默认 3),仍有失败未解决 |
|
|
160
160
|
| 编译未产出 HAP(异常) | `no_signed_hap` | build-fixer 未产出签名 HAP,无法继续测试 |
|
|
161
161
|
| 用例列表为空(异常) | `no_testcases` | `testcases.json` 里 0 条用例,没有可跑的内容。常见原因:解析阶段没识别到 `### Scenario:` 区块 |
|
|
162
|
-
| 自测 agent 早退(异常) | `agent_early_exit` | `self-tester` 在跑用例之前就退出了(设备没连、`config.yaml` 没填、`
|
|
162
|
+
| 自测 agent 早退(异常) | `agent_early_exit` | `self-tester` 在跑用例之前就退出了(设备没连、`config.yaml` 没填、`test-tools/autotest` 目录找不到(`env.TOOL_PATH` 未配置或失效)、batch 启动失败 / 超时 / 崩溃、`setup=false` 但所需 JSON 缺失等)。报告首行会是 `status: FAIL`,第二行 `reason: <原因>`。**这种情况下不会进入 fix 循环**——这些是环境/前置条件问题,不是应用缺陷 |
|
|
163
163
|
|
|
164
164
|
---
|
|
165
165
|
|
|
@@ -242,7 +242,7 @@ build-fixer 的输出摘要:编译状态、签名类型、迭代次数、修
|
|
|
242
242
|
- 操作系统:**Windows** 是主要测试目标;macOS/Linux 上的核心命令(`hdc`、`uv`、POSIX 工具链)也能跑,Skill 里涉及到的复制操作会按可用 shell 自适应
|
|
243
243
|
- `hdc` 已安装并在 PATH 中
|
|
244
244
|
- `uv` 已安装(Python 包管理)
|
|
245
|
-
-
|
|
245
|
+
- `<TOOL_PATH>/test-tools/autotest/config.yaml` 已配置真实 api_key(`TOOL_PATH` 取自 `~/.hometrans/config.json` 的 `env.TOOL_PATH`,默认即 `~/.hometrans/tools`;`ht init` 填好 `TEST_API_KEY` 后会自动写入)
|
|
246
246
|
- 鸿蒙真机通过 USB 连接,`hdc list targets` 能看到设备
|
|
247
247
|
- 签名后的 `.hap` 文件
|
|
248
248
|
|
|
@@ -262,7 +262,7 @@ A: 检查 USB 连接,跑 `hdc list targets` 看看有没有设备 SN。重新
|
|
|
262
262
|
|
|
263
263
|
**Q: 报 config.yaml missing 或 api_key 没填?**
|
|
264
264
|
|
|
265
|
-
A:
|
|
265
|
+
A: 在 AutoTest 目录 `<TOOL_PATH>/test-tools/autotest`(`TOOL_PATH` 取自 `~/.hometrans/config.json` 的 `env.TOOL_PATH`,默认 `~/.hometrans/tools`)下,复制 `config.yaml.example` 为 `config.yaml`,把 `YOUR_API_KEY_HERE` 替换成真实的 API Key。或者重新跑 `ht init` 并填入 `TEST_API_KEY`,它会自动生成。
|
|
266
266
|
|
|
267
267
|
**Q: 前置用例失败了要不要修代码?**
|
|
268
268
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: spec-
|
|
2
|
+
name: hmos-spec-generate
|
|
3
3
|
description: "Generate atomic-scenario requirement specs (markdown) from raw .txt requirement batches for Android-to-HarmonyOS migration. Reads a single .txt holding multiple REQ blocks (blank-line separated), explores the Android code graph via GitNexus, writes per-REQ trace files first then synthesizes specs from the trace. Triggers: spec generation, generate spec, requirement to spec, atomic scenarios, scenario decomposition, decompose scenarios, req to spec, code-trace-first, batch req txt."
|
|
4
4
|
license: MIT
|
|
5
5
|
allowed-tools:
|