deveco-harness 0.1.0
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/README.en.md +71 -0
- package/README.md +71 -0
- package/deveco-harness.example.jsonc +32 -0
- package/dist/index.js +758 -0
- package/package.json +48 -0
- package/prompts/build.txt +164 -0
- package/prompts/plan.txt +118 -0
- package/skills/arkts-error-fixes/README.md +151 -0
- package/skills/arkts-error-fixes/SKILL.md +150 -0
- package/skills/arkts-error-fixes/assets/AnyTypeError.ets +269 -0
- package/skills/arkts-error-fixes/assets/AppStorageError.ets +22 -0
- package/skills/arkts-error-fixes/assets/ArrowFunctionConversionError.ets +42 -0
- package/skills/arkts-error-fixes/assets/AvoidAreaTypeError.ets +43 -0
- package/skills/arkts-error-fixes/assets/BreakpointTypeError.ets +71 -0
- package/skills/arkts-error-fixes/assets/CatchClauseTypeError.ets +54 -0
- package/skills/arkts-error-fixes/assets/ColorConsistencyError.ets +88 -0
- package/skills/arkts-error-fixes/assets/ColorPropertyError.ets +39 -0
- package/skills/arkts-error-fixes/assets/ContextTypeError.ets +105 -0
- package/skills/arkts-error-fixes/assets/DecoratorStateError.ets +64 -0
- package/skills/arkts-error-fixes/assets/DisplayListenerTypeError.ets +129 -0
- package/skills/arkts-error-fixes/assets/DuplicateEntryError.ets +35 -0
- package/skills/arkts-error-fixes/assets/ESObjectTypeError.ets +137 -0
- package/skills/arkts-error-fixes/assets/FontColorPropertyError.ets +42 -0
- package/skills/arkts-error-fixes/assets/FunctionReturnTypeError.ets +41 -0
- package/skills/arkts-error-fixes/assets/IDataSourceError.ets +79 -0
- package/skills/arkts-error-fixes/assets/ImplementationNotAllowedError.ets +38 -0
- package/skills/arkts-error-fixes/assets/InterfaceMethodSignatureError.ets +43 -0
- package/skills/arkts-error-fixes/assets/NotificationError.ets +34 -0
- package/skills/arkts-error-fixes/assets/ObjectLiteralInterfaceError.ets +49 -0
- package/skills/arkts-error-fixes/assets/ObjectLiteralTypeError.ets +54 -0
- package/skills/arkts-error-fixes/assets/ObjectSpreadError.ets +29 -0
- package/skills/arkts-error-fixes/assets/PossiblyNullError.ets +32 -0
- package/skills/arkts-error-fixes/assets/ResourceConversionError.ets +159 -0
- package/skills/arkts-error-fixes/assets/StandaloneFunctionContext.ets +116 -0
- package/skills/arkts-error-fixes/assets/StandaloneFunctionError.ets +85 -0
- package/skills/arkts-error-fixes/assets/StorageLinkDefaultError.ets +41 -0
- package/skills/arkts-error-fixes/assets/TitleButtonRectTypeError.ets +86 -0
- package/skills/arkts-error-fixes/assets/UnusedVariableWarning.ets +102 -0
- package/skills/arkts-error-fixes/assets/UtilityTypeError.ets +176 -0
- package/skills/arkts-error-fixes/assets/WindowRectSizeError.ets +65 -0
- package/skills/arkts-error-fixes/assets/WindowTypeError.ets +37 -0
- package/skills/arkts-error-fixes/reference/any_type_errors.md +433 -0
- package/skills/arkts-error-fixes/reference/appstorage_errors.md +95 -0
- package/skills/arkts-error-fixes/reference/arrow_function_conversion_errors.md +163 -0
- package/skills/arkts-error-fixes/reference/avoid_area_type_errors.md +59 -0
- package/skills/arkts-error-fixes/reference/breakpoint_type_errors.md +122 -0
- package/skills/arkts-error-fixes/reference/catch_clause_type_errors.md +89 -0
- package/skills/arkts-error-fixes/reference/color_consistency_errors.md +209 -0
- package/skills/arkts-error-fixes/reference/color_property_errors.md +136 -0
- package/skills/arkts-error-fixes/reference/context_type_errors.md +260 -0
- package/skills/arkts-error-fixes/reference/decorator_state_errors.md +109 -0
- package/skills/arkts-error-fixes/reference/display_listener_type_errors.md +149 -0
- package/skills/arkts-error-fixes/reference/duplicate_entry_errors.md +193 -0
- package/skills/arkts-error-fixes/reference/esobject_type_errors.md +110 -0
- package/skills/arkts-error-fixes/reference/fontcolor_property_errors.md +104 -0
- package/skills/arkts-error-fixes/reference/function_return_type_errors.md +194 -0
- package/skills/arkts-error-fixes/reference/idata_source_errors.md +77 -0
- package/skills/arkts-error-fixes/reference/implementation_not_allowed_errors.md +191 -0
- package/skills/arkts-error-fixes/reference/interface_method_signature_errors.md +143 -0
- package/skills/arkts-error-fixes/reference/notification_errors.md +110 -0
- package/skills/arkts-error-fixes/reference/object_literal_interface_errors.md +156 -0
- package/skills/arkts-error-fixes/reference/object_literal_type_errors.md +110 -0
- package/skills/arkts-error-fixes/reference/object_spread_errors.md +105 -0
- package/skills/arkts-error-fixes/reference/possibly_null_errors.md +156 -0
- package/skills/arkts-error-fixes/reference/resource_conversion_errors.md +154 -0
- package/skills/arkts-error-fixes/reference/standalone_function_errors.md +68 -0
- package/skills/arkts-error-fixes/reference/storage_link_default_errors.md +124 -0
- package/skills/arkts-error-fixes/reference/title_button_rect_type_errors.md +167 -0
- package/skills/arkts-error-fixes/reference/unused_variable_warnings.md +295 -0
- package/skills/arkts-error-fixes/reference/utility_type_errors.md +290 -0
- package/skills/arkts-error-fixes/reference/window_rect_size_errors.md +70 -0
- package/skills/arkts-error-fixes/reference/window_type_errors.md +95 -0
- package/skills/arkts-grammar-standards/SKILL.md +71 -0
- package/skills/arkts-grammar-standards/references/basic-syntax.md +103 -0
- package/skills/arkts-grammar-standards/references/restrictions.md +100 -0
- package/skills/arkts-grammar-standards/references/topic-aliases.json +93 -0
- package/skills/arkts-grammar-standards/references/ts-diff.md +108 -0
- package/skills/arkts-runtime-fix/SKILL.md +152 -0
- package/skills/arkts-runtime-fix/SKILL_CN.md +123 -0
- package/skills/arkts-runtime-fix/evals/evals.json +17 -0
- package/skills/arkts-runtime-fix/scripts/collect-hilog.mjs +116 -0
- package/skills/arkts-runtime-fix/scripts/collect-hilog.ts +115 -0
- package/skills/arkts-runtime-fix/scripts/fetch-faultlog.mjs +117 -0
- package/skills/arkts-runtime-fix/scripts/fetch-faultlog.ts +116 -0
- package/skills/arkts-runtime-fix/scripts/jscrash-report.mjs +149 -0
- package/skills/arkts-runtime-fix/scripts/parse-jscrash-log.mjs +126 -0
- package/skills/arkts-runtime-fix/scripts/parse-jscrash-log.ts +126 -0
- package/skills/arkts-runtime-fix/scripts/probe-faultlogger.mjs +160 -0
- package/skills/arkts-runtime-fix/scripts/probe-faultlogger.ts +160 -0
- package/skills/arkts-runtime-fix/scripts/shared/hdc.mjs +107 -0
- package/skills/arkts-runtime-fix/scripts/shared/hdc.ts +58 -0
- package/skills/arkts-runtime-fix/scripts/shared/jscrash-faultlogger.mjs +143 -0
- package/skills/arkts-runtime-fix/scripts/shared/jscrash-faultlogger.ts +148 -0
- package/skills/arkts-runtime-fix/scripts/shared/jscrash-parse.mjs +389 -0
- package/skills/arkts-runtime-fix/scripts/shared/jscrash-parse.ts +409 -0
- package/skills/arkts-runtime-fix/scripts/shared/utils.mjs +27 -0
- package/skills/arkts-runtime-fix/scripts/shared/utils.ts +27 -0
- package/skills/arkui-knowledge/SKILL.md +90 -0
- package/skills/arkui-knowledge/references/api-guardrails.md +60 -0
- package/skills/arkui-knowledge/references/common-mistakes.md +119 -0
- package/skills/arkui-knowledge/references/component-cookbook.md +135 -0
- package/skills/arkui-knowledge/references/ui-quality-checklist.md +36 -0
- package/skills/deveco-create-project/SKILL.md +144 -0
- package/skills/deveco-create-project/application/AppScope/app.json5 +10 -0
- package/skills/deveco-create-project/application/AppScope/resources/base/element/string.json +8 -0
- package/skills/deveco-create-project/application/AppScope/resources/base/media/background.png +0 -0
- package/skills/deveco-create-project/application/AppScope/resources/base/media/foreground.png +0 -0
- package/skills/deveco-create-project/application/AppScope/resources/base/media/layered_image.json +7 -0
- package/skills/deveco-create-project/application/build-profile.json5 +42 -0
- package/skills/deveco-create-project/application/code-linter.json5 +32 -0
- package/skills/deveco-create-project/application/entry/build-profile.json5 +33 -0
- package/skills/deveco-create-project/application/entry/hvigorfile.ts +7 -0
- package/skills/deveco-create-project/application/entry/obfuscation-rules.txt +23 -0
- package/skills/deveco-create-project/application/entry/oh-package.json5 +10 -0
- package/skills/deveco-create-project/application/entry/src/main/ets/entryability/EntryAbility.ets +63 -0
- package/skills/deveco-create-project/application/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets +31 -0
- package/skills/deveco-create-project/application/entry/src/main/ets/pages/Index.ets +38 -0
- package/skills/deveco-create-project/application/entry/src/main/module.json5 +50 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/element/color.json +8 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/element/float.json +8 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/element/string.json +16 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/media/background.png +0 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/media/foreground.png +0 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/media/layered_image.json +7 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/media/startIcon.png +0 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/profile/backup_config.json +3 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/profile/main_pages.json +5 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/dark/element/color.json +8 -0
- package/skills/deveco-create-project/application/hvigor/hvigor-config.json5 +23 -0
- package/skills/deveco-create-project/application/hvigorfile.ts +7 -0
- package/skills/deveco-create-project/application/oh-package.json5 +10 -0
- package/skills/deveco-create-project/scripts/copy-template.mjs +216 -0
- package/skills/deveco-create-project/scripts/copy-template.ts +214 -0
- package/skills/deveco-create-project/scripts/detect-sdk.mjs +82 -0
- package/skills/deveco-create-project/scripts/detect-sdk.ts +95 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: arkts-runtime-fix
|
|
3
|
+
description: Load for ArkTS/JavaScript jscrash, runtime crash, uncaught exception, stack trace, faultlog, or hilog diagnosis. Also load when the app 闪退/崩溃/白屏, exits after 点击/启动/launch, or build succeeds but runtime fails (no compile error). Use before broad Read/Glob on crash-only tasks.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Harmony JSCrash Fixes
|
|
7
|
+
|
|
8
|
+
Use this skill to diagnose and fix ArkTS or JavaScript runtime crashes with minimal edits.
|
|
9
|
+
|
|
10
|
+
Use this skill's private Node scripts under `skills/arkts-runtime-fix/scripts/` to parse crash evidence, inspect recent faultlogger entries, or collect hilog when no better evidence is available.
|
|
11
|
+
|
|
12
|
+
If `node` is unavailable, stop and explain that the private scripts cannot run.
|
|
13
|
+
|
|
14
|
+
## When To Load
|
|
15
|
+
|
|
16
|
+
Load this skill when the issue looks like one of these:
|
|
17
|
+
|
|
18
|
+
- Runtime logs show `TypeError`, `ReferenceError`, `RangeError`, `SyntaxError`, `BusinessError`, or similar exceptions.
|
|
19
|
+
- The app exits, flashes back, or white-screens during launch or after a tap.
|
|
20
|
+
- The user provides a `jscrash` log, stack trace, or a temporary log file with `@file`.
|
|
21
|
+
- Build succeeds, but runtime behavior fails immediately.
|
|
22
|
+
|
|
23
|
+
## Core Approach
|
|
24
|
+
|
|
25
|
+
Prefer a concrete crash anchor before broad code exploration. A good anchor can come from:
|
|
26
|
+
|
|
27
|
+
- a provided crash log
|
|
28
|
+
- a stack trace
|
|
29
|
+
- a clear page or module named by the user
|
|
30
|
+
- a recent device-side faultlog or hilog when no better evidence is available
|
|
31
|
+
|
|
32
|
+
Avoid broad `Read` / `Glob` / `Explore` across the whole project until you have at least one concrete anchor such as:
|
|
33
|
+
|
|
34
|
+
- `error_type`
|
|
35
|
+
- `error_message`
|
|
36
|
+
- `suspected_file`
|
|
37
|
+
- `top_stack`
|
|
38
|
+
- or a clearly named crash entry point from the user
|
|
39
|
+
|
|
40
|
+
Do not over-collect logs. If the user already gave enough crash evidence, parse that evidence first and move into focused reading and minimal fixes.
|
|
41
|
+
|
|
42
|
+
## Tool And Script Contract
|
|
43
|
+
|
|
44
|
+
### Private Node scripts
|
|
45
|
+
|
|
46
|
+
Run the private scripts through Shell like this:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node "{SKILL_DIR}/scripts/<script>.mjs" ...
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`{SKILL_DIR}` is the absolute path of this skill directory at runtime.
|
|
53
|
+
|
|
54
|
+
Scripts print stable `key: value` text to stdout. A non-zero exit code means the current step could not continue and the agent should report the reason instead of guessing.
|
|
55
|
+
|
|
56
|
+
## Preferred Flows
|
|
57
|
+
|
|
58
|
+
### Case A: The user already provided raw crash text
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node "{SKILL_DIR}/scripts/jscrash-report.mjs" --log-text "{crashLog}" --bundle-name "{bundleName}" --include-text
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Case B: The user provided `@file` or a local log path
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
node "{SKILL_DIR}/scripts/parse-jscrash-log.mjs" --log-file "{logFilePath}" --bundle-name "{bundleName}" --include-text
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Case C: The user only described symptoms and did not provide logs
|
|
71
|
+
|
|
72
|
+
Log collection is optional here. Use it when you still need a concrete runtime anchor.
|
|
73
|
+
|
|
74
|
+
Before collecting device evidence:
|
|
75
|
+
|
|
76
|
+
1. Read `AppScope/app.json5` and take the exact `app.bundleName` value (for example `com.example.hmos.sample`). Use that string as `{bundleName}` in every script below.
|
|
77
|
+
2. Do not guess `bundleName` from `vendor`, module folder names, or prefixes such as `com.example`.
|
|
78
|
+
3. Resolve the target device:
|
|
79
|
+
- If the user provided a `deviceId`, use it for every device-side command.
|
|
80
|
+
- If no `deviceId` is provided, call `hdc_log(action="list_devices")` first.
|
|
81
|
+
- If exactly one device is connected, use that device.
|
|
82
|
+
- If multiple devices are connected, ask the user which device to inspect. Do not probe faultlogger, fetch faultlog, or collect hilog until the user selects a device.
|
|
83
|
+
- If no devices are connected, report that device-side evidence cannot be collected and ask for a connected device or a local crash log.
|
|
84
|
+
|
|
85
|
+
After the user reproduces the crash on the selected device, inspect recent faultlogger evidence:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
node "{SKILL_DIR}/scripts/probe-faultlogger.mjs" --bundle-name "{bundleName}" --device-id "{deviceId}" --max-age-minutes "30" --limit "10"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If `status: found`, fetch and parse the latest faultlog:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
node "{SKILL_DIR}/scripts/fetch-faultlog.mjs" --faultlog-name "{latestFaultlog}" --device-id "{deviceId}" --output-dir "{tempDir}"
|
|
95
|
+
node "{SKILL_DIR}/scripts/parse-jscrash-log.mjs" --log-file "{localFaultlogPath}" --bundle-name "{bundleName}" --source file --include-text
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
If `status: not_found`, do not broad-read the project or guess from symptoms alone. Ask the user to reproduce the crash on the selected device, then probe faultlogger again immediately.
|
|
99
|
+
|
|
100
|
+
If faultlogger is unavailable, the reproduced crash still does not create a matching faultlog, or the parsed faultlog is still not enough, fall back to hilog:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
node "{SKILL_DIR}/scripts/collect-hilog.mjs" --device-id "{deviceId}" --lines "4000" --output-dir "{tempDir}"
|
|
104
|
+
node "{SKILL_DIR}/scripts/parse-jscrash-log.mjs" --log-file "{hilogPathFromCollect}" --bundle-name "{bundleName}" --source hilog --include-text
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Output Contract
|
|
108
|
+
|
|
109
|
+
The leading `key: value` block from `jscrash-report.mjs` and `parse-jscrash-log.mjs` includes:
|
|
110
|
+
|
|
111
|
+
- `status`: `detected` | `no_crash_signature` | `parse_failed`
|
|
112
|
+
- `source`: `file` | `text` | `hilog` and similar sources
|
|
113
|
+
- `error_type`
|
|
114
|
+
- `error_message`
|
|
115
|
+
- `suspected_file`
|
|
116
|
+
- `top_stack`: `|`-joined frames
|
|
117
|
+
- `keywords`: comma-separated
|
|
118
|
+
- `next_action`
|
|
119
|
+
|
|
120
|
+
`--include-text` appends a human-readable summary after the structured block.
|
|
121
|
+
|
|
122
|
+
If `status: no_crash_signature`, explain that the evidence is weak and ask for a better log, clearer repro, or an additional runtime clue before broad code reading.
|
|
123
|
+
|
|
124
|
+
## Common Crash Signatures
|
|
125
|
+
|
|
126
|
+
| Signature | Typical Cause | First Fix Direction |
|
|
127
|
+
|---|---|---|
|
|
128
|
+
| `TypeError` on property access | Null or undefined state during render or lifecycle | Guard null state, initialize earlier, or move logic to a safer lifecycle |
|
|
129
|
+
| `ReferenceError` | Wrong scope, stale import, missing symbol | Fix symbol ownership, import path, or callback capture |
|
|
130
|
+
| `RangeError` | Invalid index, recursion loop, oversized access | Add bounds checks, break loops, clamp indexes |
|
|
131
|
+
| `BusinessError` / `ParameterError` | Framework API preconditions not met | Validate args, permissions, or call timing |
|
|
132
|
+
|
|
133
|
+
## Interpretation Rules
|
|
134
|
+
|
|
135
|
+
- Prefer application frames over framework noise.
|
|
136
|
+
- Treat the first concrete `.ets`, `.ts`, or `.js` path as the starting point, not the final truth.
|
|
137
|
+
- If the user gave repro steps, trust them over a simplistic stack-only guess.
|
|
138
|
+
- If the stack points to a non-entry page, assume an interaction-triggered path unless evidence proves a cold-start crash.
|
|
139
|
+
- Do not refactor broadly. Fix the crash path first.
|
|
140
|
+
|
|
141
|
+
## Conversational Shape
|
|
142
|
+
|
|
143
|
+
1. Say what evidence you already have.
|
|
144
|
+
2. If logs are missing, say whether you are using faultlogger or hilog to get a better anchor.
|
|
145
|
+
3. Once you have an anchor, switch into focused code reading and minimal fixing.
|
|
146
|
+
|
|
147
|
+
## Constraints
|
|
148
|
+
|
|
149
|
+
- Never claim a crash fix from prompt reasoning alone.
|
|
150
|
+
- Never replace a root-cause fix with retries, arbitrary delays, or broad defensive rewrites.
|
|
151
|
+
- If unfamiliar `@ohos.*` or `@kit.*` APIs are involved, check their constraints before editing.
|
|
152
|
+
- This skill does not decide the final compile / run / verification order; the primary agent owns that.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: arkts-runtime-fix-cn
|
|
3
|
+
description: ArkTS Runtime Fix 的中文参考版本,仅用于保留中文说明,不作为主入口 skill。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ArkTS Runtime Fix(中文参考)
|
|
7
|
+
|
|
8
|
+
本技能通过 **skill 私有脚本**(Node)完成证据采集与结构化解析,不再使用全局崩溃分析工具。执行前若环境无 `node`,须停止并向用户说明。
|
|
9
|
+
|
|
10
|
+
## 症状与触发
|
|
11
|
+
|
|
12
|
+
在以下情况必须加载本技能:
|
|
13
|
+
|
|
14
|
+
- 日志中出现 `TypeError`、`ReferenceError`、`RangeError`、`SyntaxError`、`BusinessError` 等运行时异常
|
|
15
|
+
- 应用启动闪退、白屏、点击后崩溃
|
|
16
|
+
- 用户提供 `jscrash` 日志、堆栈、`@file` 临时日志文件
|
|
17
|
+
- 构建成功但运行期立即失败
|
|
18
|
+
|
|
19
|
+
## 证据优先约束
|
|
20
|
+
|
|
21
|
+
在已拿到以下锚点之前,避免对工程做大规模 `Read` / `Glob` / `Explore`:
|
|
22
|
+
|
|
23
|
+
- `error_type`
|
|
24
|
+
- `error_message`
|
|
25
|
+
- `suspected_file`
|
|
26
|
+
- `top_stack`
|
|
27
|
+
- 或者用户明确指出的崩溃页面 / 模块
|
|
28
|
+
|
|
29
|
+
在证据不足时,可以执行本节的私有脚本、向用户追问复现与包名、或读取用户已显式给出的单个日志文件路径。
|
|
30
|
+
|
|
31
|
+
一旦锚点齐备,再定向读取疑似 `ets/ts/js` 与相关导航入口,做最小修改。
|
|
32
|
+
|
|
33
|
+
## 私有脚本执行约定
|
|
34
|
+
|
|
35
|
+
所有脚本通过 Shell 执行,形式与 `deveco-create-project` 一致:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
node "{SKILL_DIR}/scripts/<script>.mjs" ...
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`{SKILL_DIR}` 由执行环境替换为当前技能根目录的绝对路径。脚本 `stdout` 采用稳定 `key: value` 行文本;退出码非 0 表示当前步骤无法继续,应向用户报告 `next_action` 中的原因并停止。
|
|
42
|
+
|
|
43
|
+
## 场景 A:用户已提供原始日志文本
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
node "{SKILL_DIR}/scripts/jscrash-report.mjs" --log-text "{crashLog}" --bundle-name "{bundleName}" --include-text
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 场景 B:用户提供 `@file` 或本地日志路径
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node "{SKILL_DIR}/scripts/parse-jscrash-log.mjs" --log-file "{logFilePath}" --bundle-name "{bundleName}" --include-text
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 场景 C:仅有症状,无日志
|
|
56
|
+
|
|
57
|
+
设备采证前必须先读取 `AppScope/app.json5` 中的 `app.bundleName`,作为后续 `--bundle-name` 的精确值;禁止用 `vendor`、`com.example` 或模块目录名猜测。
|
|
58
|
+
|
|
59
|
+
先探测 faultlogger 近期 `jscrash-*.log`:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
node "{SKILL_DIR}/scripts/probe-faultlogger.mjs" --bundle-name "{bundleName}" --device-id "{deviceId}" --max-age-minutes "30" --limit "10"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- 若输出 `status: found`:读取 `latest_faultlog` 或 `candidates`,再拉取并解析:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
node "{SKILL_DIR}/scripts/fetch-faultlog.mjs" --faultlog-name "{latestFaultlog}" --device-id "{deviceId}" --output-dir "{tempDir}"
|
|
69
|
+
node "{SKILL_DIR}/scripts/parse-jscrash-log.mjs" --log-file "{localFaultlogPath}" --bundle-name "{bundleName}" --source file --include-text
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- 若输出 `status: not_found` 或 `status: probe_failed`:可按需进入 hilog 兜底采集:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
node "{SKILL_DIR}/scripts/collect-hilog.mjs" --device-id "{deviceId}" --lines "4000" --output-dir "{tempDir}"
|
|
76
|
+
node "{SKILL_DIR}/scripts/parse-jscrash-log.mjs" --log-file "{hilogPathFromCollect}" --bundle-name "{bundleName}" --source hilog --include-text
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 解析输出字段契约
|
|
80
|
+
|
|
81
|
+
`jscrash-report.mjs` 和 `parse-jscrash-log.mjs` 首段 `key: value` 行包含:
|
|
82
|
+
|
|
83
|
+
- `status`: `detected` | `no_crash_signature` | `parse_failed`
|
|
84
|
+
- `source`: `file` | `text` | `hilog` 等
|
|
85
|
+
- `error_type`
|
|
86
|
+
- `error_message`
|
|
87
|
+
- `suspected_file`
|
|
88
|
+
- `top_stack`: 以 `|` 分隔的帧列表
|
|
89
|
+
- `keywords`: 逗号分隔
|
|
90
|
+
- `next_action`
|
|
91
|
+
|
|
92
|
+
`--include-text` 会在其后追加人类可读完整报告。
|
|
93
|
+
|
|
94
|
+
若 `status: no_crash_signature`,须向用户说明证据不足,请求复现或更完整日志后再读代码。
|
|
95
|
+
|
|
96
|
+
## 常见崩溃签名
|
|
97
|
+
|
|
98
|
+
| 签名 | 常见原因 | 优先修复方向 |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| `TypeError` 属性访问 | 渲染 / 生命周期空状态 | 空值保护、提前初始化、调整生命周期 |
|
|
101
|
+
| `ReferenceError` | 作用域 / 导入 / 闭包 | 修正符号、导入路径或回调捕获 |
|
|
102
|
+
| `RangeError` | 下标 / 递归 / 长度 | 边界检查、断环、限制索引 |
|
|
103
|
+
| `BusinessError` / `ParameterError` | API 前置条件 | 校验参数、权限与调用时机 |
|
|
104
|
+
|
|
105
|
+
## 解释规则
|
|
106
|
+
|
|
107
|
+
- 应用栈优先于框架噪声;首个具体 `.ets/.ts/.js` 路径是起点而非唯一根因。
|
|
108
|
+
- 若用户给出复现步骤,步骤优先于单纯堆栈推断。
|
|
109
|
+
- 若堆栈指向非入口页,默认视为交互触发路径,除非证据表明仅冷启动。
|
|
110
|
+
- 不做大范围重构,先消除崩溃路径。
|
|
111
|
+
|
|
112
|
+
## 交互建议
|
|
113
|
+
|
|
114
|
+
1. 先说明当前已有的证据。
|
|
115
|
+
2. 如果证据不足,再说明是否按需检查 faultlogger 或 hilog。
|
|
116
|
+
3. 一旦拿到锚点,就切换到定向读代码和最小修复。
|
|
117
|
+
|
|
118
|
+
## 约束
|
|
119
|
+
|
|
120
|
+
- 不得仅凭推理声称已修复崩溃。
|
|
121
|
+
- 不得用重试、随意延时或大面积防御性改写替代根因修复。
|
|
122
|
+
- 涉及不熟悉的 `@ohos.*` / `@kit.*` API 时,应先查证约束再改代码。
|
|
123
|
+
- 本技能不决定最终的编译 / 运行 / 验证顺序;主 Agent 负责后续验证。
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "arkts-runtime-fix",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "点击应用就闪退,没有日志",
|
|
7
|
+
"expected_output": "加载 arkts-runtime-fix;优先从用户现有证据中建立 crash anchor;若缺少可用日志,可选地先 probe-faultlogger,命中则 fetch-faultlog 再 parse-jscrash-log,仍不足时再 collect-hilog;在拿到明确 anchor 前不大范围 Read/Glob 工程",
|
|
8
|
+
"files": []
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": 2,
|
|
12
|
+
"prompt": "这是 jscrash 日志:TypeError ... at entry/src/main/ets/pages/Index.ets:10:5",
|
|
13
|
+
"expected_output": "直接 node 执行 jscrash-report.mjs(--log-text)或 parse-jscrash-log.mjs(--log-file),基于现有日志建立 anchor,再定向读取 Index.ets 相关入口,不额外拉取设备日志",
|
|
14
|
+
"files": []
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Huawei Device Co., Ltd.
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
5
|
+
* You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
* See the License for the specific language governing permissions and
|
|
13
|
+
* limitations under the License.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import fsp from 'node:fs/promises';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import process from 'node:process';
|
|
20
|
+
import { resolveHdcOrThrow, runHdc, targetArgs } from './shared/hdc.mjs';
|
|
21
|
+
import { printKv, toErrorMessage } from './shared/utils.mjs';
|
|
22
|
+
|
|
23
|
+
function cleanLines(input) {
|
|
24
|
+
return input
|
|
25
|
+
.split(/\r?\n/)
|
|
26
|
+
.map((line) => line.trimEnd())
|
|
27
|
+
.filter((line) => line.trim().length > 0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function parseArgs(argv) {
|
|
31
|
+
const map = new Map();
|
|
32
|
+
const optionalKeys = new Set(['device-id']);
|
|
33
|
+
|
|
34
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
35
|
+
const t = argv[i];
|
|
36
|
+
if (!t.startsWith('--')) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const key = t.slice(2);
|
|
40
|
+
const val = argv[i + 1];
|
|
41
|
+
if (!val || val.startsWith('--')) {
|
|
42
|
+
if (optionalKeys.has(key)) {
|
|
43
|
+
map.set(key, '');
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
throw new Error(`Missing value for --${key}`);
|
|
48
|
+
}
|
|
49
|
+
map.set(key, val);
|
|
50
|
+
i += 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const outputDir = map.get('output-dir');
|
|
54
|
+
if (!outputDir) {
|
|
55
|
+
throw new Error('Required: --output-dir');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
outputDir,
|
|
60
|
+
deviceId: map.get('device-id') ?? '',
|
|
61
|
+
lines: Number(map.get('lines') ?? '4000'),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function printCollectFailed(nextAction) {
|
|
66
|
+
printKv({
|
|
67
|
+
status: 'collect_failed',
|
|
68
|
+
source: 'device_hilog',
|
|
69
|
+
log_file: '',
|
|
70
|
+
log_excerpt: '',
|
|
71
|
+
next_action: nextAction,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function collectHilogText(hdc, deviceId, lines) {
|
|
76
|
+
const out = await runHdc([hdc, ...targetArgs(deviceId), 'shell', 'hilog', '-x']);
|
|
77
|
+
if (out.exitCode !== 0) {
|
|
78
|
+
throw new Error(out.stderr || out.stdout || `hdc hilog -x failed (code=${out.exitCode})`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const all = cleanLines(out.stdout);
|
|
82
|
+
return all.slice(Math.max(0, all.length - lines)).join('\n');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function writeHilogSnapshot(outputDir, recent) {
|
|
86
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
87
|
+
const logFile = path.join(outputDir, `hilog-${Date.now()}.txt`);
|
|
88
|
+
await fsp.writeFile(logFile, recent, 'utf8');
|
|
89
|
+
return logFile;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function printCollected(logFile, recent) {
|
|
93
|
+
printKv({
|
|
94
|
+
status: 'collected',
|
|
95
|
+
source: 'device_hilog',
|
|
96
|
+
log_file: logFile,
|
|
97
|
+
log_excerpt: recent.slice(0, 800),
|
|
98
|
+
next_action: `A hilog snapshot is available. Parse it with parse-jscrash-log.mjs --log-file "${logFile}" --source hilog if you want more crash detail.`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function main() {
|
|
103
|
+
try {
|
|
104
|
+
const { outputDir, deviceId, lines } = parseArgs(process.argv.slice(2));
|
|
105
|
+
const hdc = await resolveHdcOrThrow();
|
|
106
|
+
const recent = await collectHilogText(hdc, deviceId, lines);
|
|
107
|
+
const logFile = await writeHilogSnapshot(outputDir, recent);
|
|
108
|
+
printCollected(logFile, recent);
|
|
109
|
+
process.exit(0);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
printCollectFailed(toErrorMessage(err));
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
await main();
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Huawei Device Co., Ltd.
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
5
|
+
* You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
* See the License for the specific language governing permissions and
|
|
13
|
+
* limitations under the License.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import process from 'node:process';
|
|
19
|
+
import { resolveHdcOrThrow, runHdc, targetArgs } from './shared/hdc';
|
|
20
|
+
import { printKv, toErrorMessage } from './shared/utils';
|
|
21
|
+
|
|
22
|
+
function cleanLines(input: string) {
|
|
23
|
+
return input
|
|
24
|
+
.split(/\r?\n/)
|
|
25
|
+
.map((line) => line.trimEnd())
|
|
26
|
+
.filter((line) => line.trim().length > 0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseArgs(argv: string[]) {
|
|
30
|
+
const map = new Map<string, string>();
|
|
31
|
+
const optionalKeys = new Set(['device-id']);
|
|
32
|
+
|
|
33
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
34
|
+
const t = argv[i];
|
|
35
|
+
if (!t.startsWith('--')) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const key = t.slice(2);
|
|
39
|
+
const val = argv[i + 1];
|
|
40
|
+
if (!val || val.startsWith('--')) {
|
|
41
|
+
if (optionalKeys.has(key)) {
|
|
42
|
+
map.set(key, '');
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
throw new Error(`Missing value for --${key}`);
|
|
47
|
+
}
|
|
48
|
+
map.set(key, val);
|
|
49
|
+
i += 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const outputDir = map.get('output-dir');
|
|
53
|
+
if (!outputDir) {
|
|
54
|
+
throw new Error('Required: --output-dir');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
outputDir,
|
|
59
|
+
deviceId: map.get('device-id') ?? '',
|
|
60
|
+
lines: Number(map.get('lines') ?? '4000'),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function printCollectFailed(nextAction: string) {
|
|
65
|
+
printKv({
|
|
66
|
+
status: 'collect_failed',
|
|
67
|
+
source: 'device_hilog',
|
|
68
|
+
log_file: '',
|
|
69
|
+
log_excerpt: '',
|
|
70
|
+
next_action: nextAction,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function collectHilogText(hdc: string, deviceId: string, lines: number) {
|
|
75
|
+
const out = await runHdc([hdc, ...targetArgs(deviceId), 'shell', 'hilog', '-x']);
|
|
76
|
+
if (out.exitCode !== 0) {
|
|
77
|
+
throw new Error(out.stderr || out.stdout || `hdc hilog -x failed (code=${out.exitCode})`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const all = cleanLines(out.stdout);
|
|
81
|
+
return all.slice(Math.max(0, all.length - lines)).join('\n');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function writeHilogSnapshot(outputDir: string, recent: string) {
|
|
85
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
86
|
+
const logFile = path.join(outputDir, `hilog-${Date.now()}.txt`);
|
|
87
|
+
await Bun.write(logFile, recent);
|
|
88
|
+
return logFile;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function printCollected(logFile: string, recent: string) {
|
|
92
|
+
printKv({
|
|
93
|
+
status: 'collected',
|
|
94
|
+
source: 'device_hilog',
|
|
95
|
+
log_file: logFile,
|
|
96
|
+
log_excerpt: recent.slice(0, 800),
|
|
97
|
+
next_action: `A hilog snapshot is available. Parse it with parse-jscrash-log.ts --log-file "${logFile}" --source hilog if you want more crash detail.`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function main() {
|
|
102
|
+
try {
|
|
103
|
+
const { outputDir, deviceId, lines } = parseArgs(process.argv.slice(2));
|
|
104
|
+
const hdc = await resolveHdcOrThrow();
|
|
105
|
+
const recent = await collectHilogText(hdc, deviceId, lines);
|
|
106
|
+
const logFile = await writeHilogSnapshot(outputDir, recent);
|
|
107
|
+
printCollected(logFile, recent);
|
|
108
|
+
process.exit(0);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
printCollectFailed(toErrorMessage(err));
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await main();
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Huawei Device Co., Ltd.
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
5
|
+
* You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
* See the License for the specific language governing permissions and
|
|
13
|
+
* limitations under the License.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import process from 'node:process';
|
|
19
|
+
import fsp from 'node:fs/promises';
|
|
20
|
+
import { resolveHdcOrThrow, runHdc, targetArgs } from './shared/hdc.mjs';
|
|
21
|
+
import { printKv, toErrorMessage } from './shared/utils.mjs';
|
|
22
|
+
|
|
23
|
+
function parseArgs(argv) {
|
|
24
|
+
const map = new Map();
|
|
25
|
+
const optionalKeys = new Set(['device-id']);
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
28
|
+
const t = argv[i];
|
|
29
|
+
if (!t.startsWith('--')) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const key = t.slice(2);
|
|
33
|
+
const val = argv[i + 1];
|
|
34
|
+
if (!val || val.startsWith('--')) {
|
|
35
|
+
if (optionalKeys.has(key)) {
|
|
36
|
+
map.set(key, '');
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
throw new Error(`Missing value for --${key}`);
|
|
41
|
+
}
|
|
42
|
+
map.set(key, val);
|
|
43
|
+
i += 1;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const faultlogName = map.get('faultlog-name');
|
|
47
|
+
const outputDir = map.get('output-dir');
|
|
48
|
+
if (!faultlogName || !outputDir) {
|
|
49
|
+
throw new Error('Required: --faultlog-name and --output-dir');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
faultlogName,
|
|
54
|
+
outputDir,
|
|
55
|
+
deviceId: map.get('device-id') ?? '',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function normalizeRemoteName(name) {
|
|
60
|
+
return name.endsWith('.log') ? name : `${name}.log`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function printFetchFailed(faultlogName, remotePath, nextAction) {
|
|
64
|
+
printKv({
|
|
65
|
+
status: 'fetch_failed',
|
|
66
|
+
faultlog_name: faultlogName,
|
|
67
|
+
remote_path: remotePath,
|
|
68
|
+
local_path: '',
|
|
69
|
+
next_action: nextAction,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function recvFaultlog(hdc, deviceId, remotePath, localPath) {
|
|
74
|
+
const args = [hdc, ...targetArgs(deviceId), 'file', 'recv', remotePath, localPath];
|
|
75
|
+
const out = await runHdc(args);
|
|
76
|
+
if (out.exitCode !== 0) {
|
|
77
|
+
throw new Error(out.stderr || out.stdout || `hdc file recv failed (code=${out.exitCode})`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await fsp.access(localPath).catch(() => {
|
|
81
|
+
throw new Error('Local file missing after recv.');
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function printFetched(faultlogName, remotePath, localPath) {
|
|
86
|
+
printKv({
|
|
87
|
+
status: 'fetched',
|
|
88
|
+
faultlog_name: faultlogName,
|
|
89
|
+
remote_path: remotePath,
|
|
90
|
+
local_path: localPath,
|
|
91
|
+
next_action: `parse-jscrash-log.mjs --log-file "${localPath}"`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function main() {
|
|
96
|
+
let faultlogName = '';
|
|
97
|
+
let remotePath = '';
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const args = parseArgs(process.argv.slice(2));
|
|
101
|
+
const base = normalizeRemoteName(path.basename(args.faultlogName.trim()));
|
|
102
|
+
faultlogName = base;
|
|
103
|
+
remotePath = `/data/log/faultlog/faultlogger/${base}`;
|
|
104
|
+
const hdc = await resolveHdcOrThrow();
|
|
105
|
+
|
|
106
|
+
fs.mkdirSync(args.outputDir, { recursive: true });
|
|
107
|
+
const localPath = path.join(args.outputDir, base);
|
|
108
|
+
await recvFaultlog(hdc, args.deviceId, remotePath, localPath);
|
|
109
|
+
printFetched(base, remotePath, localPath);
|
|
110
|
+
process.exit(0);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
printFetchFailed(faultlogName, remotePath, toErrorMessage(err));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
await main();
|