@mison/wecom-cleaner 1.3.0 → 1.3.2

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.md CHANGED
@@ -168,10 +168,10 @@ GitHub 备选方式(无 npm 包依赖):
168
168
  curl -fsSL https://raw.githubusercontent.com/MisonL/wecom-cleaner/main/scripts/install-skill.sh | bash
169
169
  ```
170
170
 
171
- 若需安装指定版本标签(例如 `v1.3.0`):
171
+ 若需安装指定版本标签(例如 `v1.3.2`):
172
172
 
173
173
  ```bash
174
- curl -fsSL https://raw.githubusercontent.com/MisonL/wecom-cleaner/main/scripts/install-skill.sh | bash -s -- --ref v1.3.0
174
+ curl -fsSL https://raw.githubusercontent.com/MisonL/wecom-cleaner/main/scripts/install-skill.sh | bash -s -- --ref v1.3.2
175
175
  ```
176
176
 
177
177
  Agent 侧统一任务入口脚本(位于 `skills/wecom-cleaner-agent/scripts/`):
@@ -238,6 +238,9 @@ wecom-cleaner --space-governance \
238
238
  # 回收区治理(按策略执行)
239
239
  wecom-cleaner --recycle-maintain --dry-run false --yes
240
240
 
241
+ # 年月清理(三阶段协议:预演 -> 执行 -> 复核)
242
+ wecom-cleaner --cleanup-monthly --accounts all --cutoff-month 2024-04 --run-task preview-execute-verify --yes
243
+
241
244
  # 批次恢复(冲突策略:重命名)
242
245
  wecom-cleaner --restore-batch 20260226-105009-ffa098 --conflict rename
243
246
 
@@ -251,13 +254,15 @@ wecom-cleaner --check-update --output text
251
254
  wecom-cleaner --upgrade npm --upgrade-yes
252
255
 
253
256
  # 执行升级(GitHub 托管脚本方式)
254
- wecom-cleaner --upgrade github-script --upgrade-version 1.3.1 --upgrade-yes
257
+ wecom-cleaner --upgrade github-script --upgrade-version 1.3.2 --upgrade-yes
255
258
  ```
256
259
 
257
260
  ### 输出与兼容参数
258
261
 
259
262
  - `--output json|text`:无交互输出格式,默认 `json`。
260
263
  - `--json`:兼容别名,等价于 `--output json`。
264
+ - `--run-task preview|execute|preview-execute-verify`:阶段任务协议(推荐给 Agent)。
265
+ - `--scan-debug off|summary|full`:扫描诊断信息输出等级。
261
266
  - `--mode`:兼容参数,建议迁移到动作参数(如 `--cleanup-monthly`)。
262
267
  - `--save-config`:将本次全局配置参数写回 `config.json`。
263
268
  - `--help` / `-h`:输出命令帮助并退出。
@@ -280,6 +285,7 @@ wecom-cleaner --upgrade github-script --upgrade-version 1.3.1 --upgrade-yes
280
285
  - `summary.rootPathCount`:涉及的清理根目录数量
281
286
  - `summary.accountCount` / `monthCount` / `categoryCount` / `externalRootCount`
282
287
  - `summary.cutoffMonth`:截止月份(当使用 `--cutoff-month` 时)
288
+ - `summary.runTaskMode` / `summary.taskDecision`:阶段协议模式与决策(仅 `--run-task`)
283
289
 
284
290
  `cleanup-monthly` 还会在 `data.report` 中返回可展示明细:
285
291
 
@@ -288,6 +294,9 @@ wecom-cleaner --upgrade github-script --upgrade-version 1.3.1 --upgrade-yes
288
294
  - `data.report.matched.rootStats`:按根目录统计(条目数、体积)
289
295
  - `data.report.matched.topPaths`:按体积 Top 路径样例
290
296
  - `data.report.executed.byCategory/byMonth/byRoot`:真实执行落地统计(成功/跳过/失败 + 体积)
297
+ - `data.taskPhases`:阶段执行明细(预演/执行/复核)
298
+ - `data.taskCard`:面向用户的任务卡片聚合结果
299
+ - `data.scanDebug`:扫描诊断(当 `--scan-debug summary|full`)
291
300
 
292
301
  #### `analysis-only`
293
302
 
@@ -355,6 +364,8 @@ wecom-cleaner --upgrade github-script --upgrade-version 1.3.1 --upgrade-yes
355
364
  - `--theme <auto|light|dark>`:Logo 主题
356
365
  - `--interactive`:即使携带参数也进入交互流程(可配合 `--mode`)
357
366
  - `--force`:锁异常场景下强制清理并继续(兜底参数,通常无需)
367
+ - `--run-task preview|execute|preview-execute-verify`:阶段任务协议(推荐无交互自动化调用)
368
+ - `--scan-debug off|summary|full`:附加扫描诊断信息
358
369
 
359
370
  ### `--theme` 可选值
360
371
 
@@ -438,8 +449,8 @@ npm run pack:tgz:dry-run
438
449
 
439
450
  当前基线(主分支):
440
451
 
441
- - 单元测试:`100/100` 通过。
442
- - 覆盖率:`statements 87.63%`,`branches 74.03%`,`functions 92.47%`,`lines 87.63%`。
452
+ - 单元测试:`107/107` 通过。
453
+ - 覆盖率:`statements 87.66%`,`branches 74.38%`,`functions 92.47%`,`lines 87.66%`。
443
454
  - 全菜单 smoke:通过(含恢复冲突分支与 doctor JSON 分支)。
444
455
 
445
456
  ## 测试矩阵
@@ -482,7 +493,7 @@ npm run pack:tgz
482
493
  npm run pack:release-assets
483
494
 
484
495
  # 2) 推送主分支与标签
485
- VERSION="1.3.0"
496
+ VERSION="1.3.2"
486
497
  git push origin main
487
498
  git tag "v${VERSION}"
488
499
  git push origin "v${VERSION}"
@@ -122,7 +122,7 @@
122
122
  - 使用 `c8` 输出覆盖率报告。
123
123
  - 门禁阈值:`lines/statements >= 75%`,`functions >= 80%`,`branches >= 60%`。
124
124
  - 命令:`npm run test:coverage` / `npm run test:coverage:check`。
125
- - `v1.1.0` 基线:`statements 86.57%`,`branches 73.96%`,`functions 93.25%`,`lines 86.57%`。
125
+ - `v1.3.2` 基线:`statements 87.66%`,`branches 74.38%`,`functions 92.47%`,`lines 87.66%`。
126
126
 
127
127
  4. 端到端回归
128
128
 
@@ -142,17 +142,17 @@ npm run pack:tgz:dry-run
142
142
 
143
143
  1. 版本与产物
144
144
 
145
- - `package.json` / `package-lock.json`:`1.1.0`
146
- - `native/manifest.json`:版本与 `baseUrl` 对齐 `v1.1.0`
145
+ - `package.json` / `package-lock.json`:`1.3.2`
146
+ - `native/manifest.json`:版本与 `baseUrl` 对齐当前发布标签
147
147
  - 默认打包双架构核心:`darwin-x64` + `darwin-arm64`
148
148
 
149
149
  2. GitHub Release
150
150
 
151
151
  ```bash
152
152
  git push origin main
153
- git tag v1.1.0
154
- git push origin v1.1.0
155
- gh release create v1.1.0 --title "v1.1.0" --notes-file docs/releases/v1.1.0.md wecom-cleaner-1.1.0.tgz
153
+ git tag v1.3.2
154
+ git push origin v1.3.2
155
+ gh release create v1.3.2 --title "v1.3.2" --notes-file docs/releases/v1.3.2.md wecom-cleaner-1.3.2.tgz
156
156
  ```
157
157
 
158
158
  3. npm 发布
@@ -34,6 +34,10 @@
34
34
  - 默认 `dry-run`(不执行真实删除/恢复)。
35
35
  - 真实执行需显式传 `--yes`。
36
36
  - 若传 `--dry-run false` 且未传 `--yes`,退出码为 `3`。
37
+ - 可通过 `--run-task` 启用阶段协议:
38
+ - `preview`:仅预演阶段。
39
+ - `execute`:仅真实执行阶段(破坏性动作需 `--yes`)。
40
+ - `preview-execute-verify`:预演 -> 真实执行 -> 同条件复核(预演命中 `0` 时自动跳过执行与复核)。
37
41
 
38
42
  ## 4. 输出协议
39
43
 
@@ -41,6 +45,8 @@
41
45
 
42
46
  - `--output json|text`(默认 `json`)
43
47
  - `--json` 为兼容别名(等价 `--output json`)
48
+ - `--run-task preview|execute|preview-execute-verify`(推荐破坏性动作使用)
49
+ - `--scan-debug off|summary|full`(默认 `off`)
44
50
 
45
51
  JSON 顶层字段:
46
52
 
@@ -53,6 +59,9 @@ JSON 顶层字段:
53
59
  - `data`:动作明细数据
54
60
  - `meta`:元信息(版本、耗时、引擎、时间戳等)
55
61
  - `data.userFacingSummary`:统一的用户侧结果摘要(范围 + 结果 + 关键分布)
62
+ - `data.taskPhases`:阶段协议明细(仅在 `--run-task` 时返回)
63
+ - `data.taskCard`:阶段任务卡片(仅在 `--run-task` 时返回)
64
+ - `data.scanDebug`:扫描诊断信息(仅在 `--scan-debug summary|full` 时返回)
56
65
 
57
66
  `cleanup_monthly` 常见 `summary` 字段:
58
67
 
@@ -215,6 +224,8 @@ JSON 顶层字段:
215
224
  - `--upgrade-channel <stable|pre>`:更新通道(稳定版/预发布)
216
225
  - `--upgrade-version <x.y.z>`:升级到指定版本
217
226
  - `--upgrade-yes`:确认执行升级(无此参数将拒绝执行升级)
227
+ - `--run-task preview|execute|preview-execute-verify`:无交互阶段协议
228
+ - `--scan-debug off|summary|full`:扫描诊断输出等级
218
229
 
219
230
  ## 7. 动作参数
220
231
 
@@ -39,6 +39,8 @@
39
39
  - dry-run(预演)
40
40
  - 真实执行(`--dry-run false --yes`)
41
41
  - 真实执行后复核(同条件二次运行)
42
+ - 阶段协议(`--run-task preview|execute|preview-execute-verify`)
43
+ - 扫描诊断(`--scan-debug summary|full`)
42
44
 
43
45
  ### 维度 E:异常与边界
44
46
 
@@ -92,13 +94,15 @@
92
94
 
93
95
  1. `cleanup_monthly`:`--cutoff-month` + `--output json` + dry-run(有目标 / 无目标)
94
96
  2. `cleanup_monthly`:真实执行 + 复核(复核命中应下降或归零)
95
- 3. `space_governance`:`suggested-only` 与 `allow-recent-active` 组合
96
- 4. `restore`:`skip/overwrite/rename` 三冲突策略
97
- 5. `recycle_maintain`:`disabled` / `no_candidate` / `partial_failed`
98
- 6. `doctor`:只读模式不创建状态目录
99
- 7. `check_update`:npm 正常 / npm 失败回退 GitHub / 全部失败
100
- 8. `upgrade`:未确认拒绝、已是最新不执行、执行失败可返回非 0
101
- 9. Agent 报告脚本:成功、无目标、失败三态退出码与卡片完整性
97
+ 3. `cleanup_monthly`:`--run-task preview-execute-verify --yes`(阶段字段稳定)
98
+ 4. `cleanup_monthly`:`--scan-debug summary/full`(诊断字段稳定)
99
+ 5. `space_governance`:`suggested-only` `allow-recent-active` 组合
100
+ 6. `restore`:`skip/overwrite/rename` 三冲突策略
101
+ 7. `recycle_maintain`:`disabled` / `no_candidate` / `partial_failed`
102
+ 8. `doctor`:只读模式不创建状态目录
103
+ 9. `check_update`:npm 正常 / npm 失败回退 GitHub / 全部失败
104
+ 10. `upgrade`:未确认拒绝、已是最新不执行、执行失败可返回非 0
105
+ 11. Agent 报告脚本:成功、无目标、失败三态退出码与卡片完整性
102
106
 
103
107
  ## 当前门禁(执行顺序)
104
108
 
@@ -0,0 +1,31 @@
1
+ # v1.3.1
2
+
3
+ 发布日期:2026-02-27
4
+
5
+ ## 重点更新
6
+
7
+ - 新增无交互阶段协议 `--run-task`:
8
+ - `preview`:仅预演
9
+ - `execute`:仅执行
10
+ - `preview-execute-verify`:预演 -> 执行 -> 复核
11
+ - 无交互 JSON 新增阶段产物:
12
+ - `data.taskPhases`:阶段明细(状态、耗时、命中/成功/失败统计)
13
+ - `data.taskCard`:用户视角任务卡片(范围、结论、分布)
14
+ - 新增扫描诊断参数 `--scan-debug off|summary|full`:用于定位“扫描命中与预期不一致”问题。
15
+
16
+ ## CLI 与 Agent 协同
17
+
18
+ - `--help` 已补充 `--run-task` 与 `--scan-debug`。
19
+ - skills 文档与命令参考已同步:CLI 回退场景优先使用 `--run-task`,并读取 `taskCard/taskPhases`。
20
+
21
+ ## 测试与质量
22
+
23
+ - 新增/更新:
24
+ - `test/config.test.js`:新增 `--run-task` / `--scan-debug` 参数解析覆盖。
25
+ - `test/cli-non-interactive.test.js`:新增阶段协议与扫描诊断覆盖。
26
+ - 全量测试通过:`npm test`(107/107)。
27
+
28
+ ## 兼容性说明
29
+
30
+ - 旧的无交互调用方式保持兼容(不传 `--run-task` 时行为不变)。
31
+ - 文本输出保持原有动作卡片,新增阶段流程区块仅在 `--run-task` 时显示。
@@ -0,0 +1,38 @@
1
+ # v1.3.2
2
+
3
+ 发布日期:2026-02-27
4
+
5
+ ## 重点更新
6
+
7
+ - 4 个破坏性 Agent 报告脚本统一改为 `--run-task` 单入口(预演 / 执行 / 复核一致语义):
8
+ - `cleanup_monthly_report.sh`
9
+ - `space_governance_report.sh`
10
+ - `restore_batch_report.sh`
11
+ - `recycle_maintain_report.sh`
12
+ - Zig 核心版本号改为构建期自动注入,不再手工写死。
13
+ - `native/manifest.json` 升级到 `v1.3.2`,并同步 `darwin-x64`/`darwin-arm64` 双架构 SHA256。
14
+
15
+ ## 稳定性修复
16
+
17
+ - 修复 4 个报告脚本在错误分支下的变量展开风险:失败场景稳定返回非 0,避免自动化流程误判成功。
18
+ - 修复 Zig 核心 `--ping` 版本与包版本可能不一致的问题。
19
+
20
+ ## 文档同步
21
+
22
+ - README、实施计划、技能命令参考、升级脚本示例统一更新到 `v1.3.2`。
23
+
24
+ ## 验证结果
25
+
26
+ - 发布门禁全通过:`npm run release:gate`
27
+ - `format:check`
28
+ - `check`
29
+ - `test:coverage:check`
30
+ - `shellcheck(skills)`
31
+ - `e2e:smoke`
32
+ - `pack:tgz:dry-run`
33
+ - `pack:release-assets:dry-run`
34
+ - 覆盖率基线(`test:coverage:check`):
35
+ - `statements 87.66%`
36
+ - `branches 74.38%`
37
+ - `functions 92.47%`
38
+ - `lines 87.66%`
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "targets": {
5
5
  "darwin-x64": {
6
6
  "binaryName": "wecom-cleaner-core",
7
- "sha256": "1ea550528055b97e26a76de7d33ca7c445f7dcedf36b21c0cfe1ef7e0f9841bf",
8
- "url": "https://github.com/MisonL/wecom-cleaner/releases/download/v1.3.0/wecom-cleaner-core-v1.3.0-darwin-x64"
7
+ "sha256": "7cb303935b713397012e88431238fa3b44e416ba1ceb0b1a96f354f3c818108c",
8
+ "url": "https://github.com/MisonL/wecom-cleaner/releases/download/v1.3.2/wecom-cleaner-core-v1.3.2-darwin-x64"
9
9
  },
10
10
  "darwin-arm64": {
11
11
  "binaryName": "wecom-cleaner-core",
12
- "sha256": "2819be9b6108435d94f9a6f5cd0f4e219c335925239366f76fe8a22da023a736",
13
- "url": "https://github.com/MisonL/wecom-cleaner/releases/download/v1.3.0/wecom-cleaner-core-v1.3.0-darwin-arm64"
12
+ "sha256": "93a33ae854e2dc7778865e3d59c048ba8f3d3ff3e3f3d19ec0906c316c18e503",
13
+ "url": "https://github.com/MisonL/wecom-cleaner/releases/download/v1.3.2/wecom-cleaner-core-v1.3.2-darwin-arm64"
14
14
  }
15
15
  }
16
16
  }
@@ -2,6 +2,9 @@
2
2
  set -euo pipefail
3
3
 
4
4
  ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
5
+ PACKAGE_VERSION="$(node -p "JSON.parse(require('fs').readFileSync('${ROOT_DIR}/package.json', 'utf8')).version")"
6
+ VERSION_ZIG_PATH="${ROOT_DIR}/native/zig/src/version.zig"
7
+ printf 'pub const APP_VERSION = "%s";\n' "${PACKAGE_VERSION}" > "${VERSION_ZIG_PATH}"
5
8
 
6
9
  HOST_OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
7
10
  HOST_ARCH="$(uname -m)"
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const version_meta = @import("version.zig");
2
3
 
3
4
  fn isAbsPath(path: []const u8) bool {
4
5
  return std.fs.path.isAbsolute(path);
@@ -57,7 +58,7 @@ fn dirTreeSize(dir: *std.fs.Dir) !u64 {
57
58
  }
58
59
 
59
60
  fn printPing(writer: *std.Io.Writer) !void {
60
- try writer.writeAll("{\"ok\":true,\"engine\":\"zig\",\"version\":\"1.3.0\"}\n");
61
+ try writer.print("{{\"ok\":true,\"engine\":\"zig\",\"version\":\"{s}\"}}\n", .{version_meta.APP_VERSION});
61
62
  }
62
63
 
63
64
  fn runDu(args: []const []const u8, writer: *std.Io.Writer) !void {
@@ -0,0 +1 @@
1
+ pub const APP_VERSION = "1.3.2";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mison/wecom-cleaner",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "企业微信本地聊天缓存清理工具(交互式 CLI/TUI)",
5
5
  "author": "MisonL",
6
6
  "license": "MIT",
@@ -16,10 +16,11 @@ description: 用于执行和编排 wecom-cleaner 的无交互 Agent 技能。当
16
16
  1. 全程只用无交互命令(禁止直接运行 `wecom-cleaner` 进入 TUI)。
17
17
  2. 优先脚本入口,禁止手写三步命令流(除非脚本失败或缺失)。
18
18
  3. 破坏性动作(清理/治理/恢复/回收区治理)默认预演;真实执行必须有明确授权。
19
- 4. 升级动作默认只做检查或预演(`--execute false`);真实升级必须有明确授权。
20
- 5. 若预演命中为 `0`,必须结束并说明“无需执行”,不得继续真实执行。
21
- 6. 最终汇报必须是中文用户视角,先结论再细节,并解释关键指标含义。
22
- 7. 禁止在终端回显完整 JSON;只输出人类可读摘要。
19
+ 4. 回退到 CLI 时,破坏性动作必须使用 `--run-task` 协议(`preview` 或 `preview-execute-verify`),禁止手工串联多次命令。
20
+ 5. 升级动作默认只做检查或预演(`--execute false`);真实升级必须有明确授权。
21
+ 6. 若预演命中为 `0`,必须结束并说明“无需执行”,不得继续真实执行。
22
+ 7. 最终汇报必须是中文用户视角,先结论再细节,并解释关键指标含义。
23
+ 8. 禁止在终端回显完整 JSON;只输出人类可读摘要。
23
24
 
24
25
  ## 动作到脚本映射(必须)
25
26
 
@@ -37,6 +38,7 @@ description: 用于执行和编排 wecom-cleaner 的无交互 Agent 技能。当
37
38
  1. 先判断用户意图对应哪个动作。
38
39
  2. 直接调用对应脚本。
39
40
  3. 脚本失败时,才回退到 `wecom-cleaner --<action> --output json` 手工流程。
41
+ 4. 回退流程里优先读取 `data.taskCard` 与 `data.taskPhases`,再读取 `summary/data.report` 细节。
40
42
 
41
43
  ## 脚本调用约定
42
44
 
@@ -44,6 +46,9 @@ description: 用于执行和编排 wecom-cleaner 的无交互 Agent 技能。当
44
46
  - 用户明确“现在执行/开始清理/确认执行”时才传 `--execute true`。
45
47
  - 破坏性动作脚本内部会做:预演 ->(可选)真实执行 ->(可选)复核。
46
48
  - 升级脚本默认“检查 + 预演”;只有明确授权才执行真实升级。
49
+ - CLI 回退时:
50
+ - 仅预演:`--run-task preview`
51
+ - 已授权执行:`--run-task preview-execute-verify --yes`
47
52
 
48
53
  推荐参数:
49
54
 
@@ -1,5 +1,5 @@
1
1
  interface:
2
2
  display_name: 'WeCom Cleaner Agent'
3
3
  short_description: '面向AI Agent的企业微信缓存清理与恢复无交互执行技能'
4
- default_prompt: '请使用 $wecom-cleaner-agent 执行任务:按用户意图自动选择 scripts/ 下对应报告脚本(cleanup/analysis/space/restore/recycle/doctor/check-update/upgrade),优先输出中文用户任务卡片;仅在脚本不可用时回退 wecom-cleaner --output json。'
4
+ default_prompt: '请使用 $wecom-cleaner-agent 执行任务:按用户意图自动选择 scripts/ 下对应报告脚本(cleanup/analysis/space/restore/recycle/doctor/check-update/upgrade),优先输出中文用户任务卡片;仅在脚本不可用时回退 wecom-cleaner --output json,并在破坏性动作中使用 --run-task(preview 或 preview-execute-verify)读取 data.taskCard/taskPhases。'
5
5
  brand_color: '#0EA5E9'
@@ -3,6 +3,11 @@
3
3
  ## 1. 首选入口:任务卡片脚本(统一体验)
4
4
 
5
5
  所有动作优先使用 `skills/wecom-cleaner-agent/scripts/` 下脚本,直接输出用户可读报告。
6
+ 其中破坏性动作脚本(年月清理/全量治理/恢复/回收区治理)已统一内置 `--run-task` 阶段协议:
7
+
8
+ - `--execute false` 等价于 `preview`
9
+ - `--execute true` 等价于 `preview-execute-verify --yes`
10
+ - 当命中目标为 `0` 时会自动跳过真实执行,且保留一致的任务卡片输出与退出码语义
6
11
 
7
12
  ### 1.1 年月清理
8
13
 
@@ -58,7 +63,7 @@ bash scripts/upgrade_report.sh --method npm --execute false
58
63
 
59
64
  # 明确授权后执行真实升级
60
65
  bash scripts/upgrade_report.sh --method npm --execute true
61
- bash scripts/upgrade_report.sh --method github-script --version 1.3.0 --execute true
66
+ bash scripts/upgrade_report.sh --method github-script --version 1.3.2 --execute true
62
67
  ```
63
68
 
64
69
  ## 2. 常用全局参数
@@ -75,25 +80,35 @@ bash scripts/upgrade_report.sh --method github-script --version 1.3.0 --execute
75
80
  ## 3. 回退方案:直接调用 wecom-cleaner
76
81
 
77
82
  仅在脚本不可用时使用直接命令,且保持 `--output json`。
83
+ 破坏性动作必须使用 `--run-task`,并优先消费 `data.taskCard` / `data.taskPhases`。
78
84
 
79
85
  ```bash
80
86
  # 年月清理(预演)
81
- wecom-cleaner --cleanup-monthly --accounts all --cutoff-month 2024-07 --output json
87
+ wecom-cleaner --cleanup-monthly --accounts all --cutoff-month 2024-07 --run-task preview --output json
82
88
 
83
- # 年月清理(真实执行)
84
- wecom-cleaner --cleanup-monthly --accounts all --cutoff-month 2024-07 --dry-run false --yes --output json
89
+ # 年月清理(真实执行 + 复核)
90
+ wecom-cleaner --cleanup-monthly --accounts all --cutoff-month 2024-07 --run-task preview-execute-verify --yes --output json
85
91
 
86
92
  # 会话分析
87
93
  wecom-cleaner --analysis-only --accounts all --output json
88
94
 
89
- # 全量空间治理
90
- wecom-cleaner --space-governance --accounts all --tiers safe,caution --output json
95
+ # 全量空间治理(预演)
96
+ wecom-cleaner --space-governance --accounts all --tiers safe,caution --run-task preview --output json
97
+
98
+ # 全量空间治理(真实执行 + 复核)
99
+ wecom-cleaner --space-governance --accounts all --tiers safe,caution --run-task preview-execute-verify --yes --output json
100
+
101
+ # 批次恢复(预演)
102
+ wecom-cleaner --restore-batch 20260226-154831-c418d9 --conflict rename --run-task preview --output json
103
+
104
+ # 批次恢复(真实执行 + 复核)
105
+ wecom-cleaner --restore-batch 20260226-154831-c418d9 --conflict rename --run-task preview-execute-verify --yes --output json
91
106
 
92
- # 批次恢复
93
- wecom-cleaner --restore-batch 20260226-154831-c418d9 --conflict rename --output json
107
+ # 回收区治理(预演)
108
+ wecom-cleaner --recycle-maintain --run-task preview --output json
94
109
 
95
- # 回收区治理
96
- wecom-cleaner --recycle-maintain --output json
110
+ # 回收区治理(真实执行 + 复核)
111
+ wecom-cleaner --recycle-maintain --run-task preview-execute-verify --yes --output json
97
112
 
98
113
  # 系统自检
99
114
  wecom-cleaner --doctor --output json
@@ -103,7 +118,7 @@ wecom-cleaner --check-update --output json
103
118
 
104
119
  # 程序升级(必须带 --upgrade-yes)
105
120
  wecom-cleaner --upgrade npm --upgrade-yes --output json
106
- wecom-cleaner --upgrade github-script --upgrade-version 1.3.0 --upgrade-yes --output json
121
+ wecom-cleaner --upgrade github-script --upgrade-version 1.3.2 --upgrade-yes --output json
107
122
  ```
108
123
 
109
124
  ## 4. 退出码约定
@@ -146,20 +146,22 @@ category_label_from_key() {
146
146
  esac
147
147
  }
148
148
 
149
- PREVIEW_JSON="$(mktemp -t wecom-cleaner-preview.XXXX.json)"
150
- EXEC_JSON="$(mktemp -t wecom-cleaner-exec.XXXX.json)"
151
- VERIFY_JSON="$(mktemp -t wecom-cleaner-verify.XXXX.json)"
152
- PREVIEW_ERR="$(mktemp -t wecom-cleaner-preview.XXXX.err)"
153
- EXEC_ERR="$(mktemp -t wecom-cleaner-exec.XXXX.err)"
154
- VERIFY_ERR="$(mktemp -t wecom-cleaner-verify.XXXX.err)"
149
+ RESULT_JSON="$(mktemp -t wecom-cleaner-task.XXXX.json)"
150
+ RESULT_ERR="$(mktemp -t wecom-cleaner-task.XXXX.err)"
151
+ PREVIEW_JSON="$RESULT_JSON"
152
+ EXEC_JSON="$RESULT_JSON"
153
+ RUN_TASK_MODE="preview"
154
+ if [[ "$EXECUTE" == "true" ]]; then
155
+ RUN_TASK_MODE="preview-execute-verify"
156
+ fi
155
157
 
156
158
  cleanup_tmp() {
157
- rm -f "$PREVIEW_JSON" "$EXEC_JSON" "$VERIFY_JSON" "$PREVIEW_ERR" "$EXEC_ERR" "$VERIFY_ERR"
159
+ rm -f "$RESULT_JSON" "$RESULT_ERR"
158
160
  }
159
161
  trap cleanup_tmp EXIT
160
162
 
161
163
  run_cmd_to_file() {
162
- local dry_run="$1"
164
+ local task_mode="$1"
163
165
  local output_file="$2"
164
166
  local err_file="$3"
165
167
  local cmd_parts=(
@@ -167,7 +169,7 @@ run_cmd_to_file() {
167
169
  --cutoff-month "$CUTOFF_MONTH"
168
170
  --accounts "$ACCOUNTS"
169
171
  --output json
170
- --dry-run "$dry_run"
172
+ --run-task "$task_mode"
171
173
  )
172
174
  if [[ -n "$ROOT" ]]; then
173
175
  cmd_parts+=(--root "$ROOT")
@@ -184,33 +186,30 @@ run_cmd_to_file() {
184
186
  if [[ -n "$EXTERNAL_ROOTS_SOURCE" ]]; then
185
187
  cmd_parts+=(--external-roots-source "$EXTERNAL_ROOTS_SOURCE")
186
188
  fi
187
- if [[ "$dry_run" == "false" ]]; then
189
+ if [[ "$task_mode" == "preview-execute-verify" ]]; then
188
190
  cmd_parts+=(--yes)
189
191
  fi
190
192
  if ! wecom-cleaner "${cmd_parts[@]}" >"$output_file" 2>"$err_file"; then
191
193
  local err_head
192
194
  err_head="$(head -n 3 "$err_file" 2>/dev/null || true)"
193
- echo "执行失败(dry-run=${dry_run}):${err_head:-未知错误}" >&2
195
+ echo "执行失败(run-task=${task_mode}):${err_head:-未知错误}" >&2
194
196
  return 1
195
197
  fi
196
198
  }
197
199
 
198
- run_cmd_to_file true "$PREVIEW_JSON" "$PREVIEW_ERR"
199
-
200
- preview_matched="$(jq -r '.summary.matchedTargets // 0' "$PREVIEW_JSON")"
201
- preview_matched_bytes="$(jq -r '.summary.matchedBytes // 0' "$PREVIEW_JSON")"
202
- preview_reclaimed="$(jq -r '.summary.reclaimedBytes // 0' "$PREVIEW_JSON")"
203
- preview_failed="$(jq -r '.summary.failedCount // 0' "$PREVIEW_JSON")"
204
- scope_accounts="$(jq -r '.summary.accountCount // 0' "$PREVIEW_JSON")"
205
- scope_months="$(jq -r '.summary.monthCount // 0' "$PREVIEW_JSON")"
206
- scope_categories="$(jq -r '.summary.categoryCount // 0' "$PREVIEW_JSON")"
207
- engine="$(jq -r '.meta.engine // "unknown"' "$PREVIEW_JSON")"
208
- duration_preview="$(jq -r '.meta.durationMs // 0' "$PREVIEW_JSON")"
209
- warnings_preview="$(jq -r '(.warnings // []) | length' "$PREVIEW_JSON")"
210
- errors_preview="$(jq -r '(.errors // []) | length' "$PREVIEW_JSON")"
211
- matched_month_start="$(jq -r '.summary.matchedMonthStart // .data.report.matched.monthRange.from // ""' "$PREVIEW_JSON")"
212
- matched_month_end="$(jq -r '.summary.matchedMonthEnd // .data.report.matched.monthRange.to // ""' "$PREVIEW_JSON")"
213
- root_path_count="$(jq -r '.summary.rootPathCount // (.data.report.matched.rootStats // [] | length)' "$PREVIEW_JSON")"
200
+ run_cmd_to_file "$RUN_TASK_MODE" "$RESULT_JSON" "$RESULT_ERR"
201
+
202
+ preview_matched="$(jq -r '((.data.taskPhases // [] | map(select(.name=="preview"))[0].stats.matchedTargets) // .summary.matchedTargets // 0) | tonumber? // 0' "$RESULT_JSON")"
203
+ preview_matched_bytes="$(jq -r '((.data.taskPhases // [] | map(select(.name=="preview"))[0].stats.matchedBytes) // .summary.matchedBytes // 0) | tonumber? // 0' "$RESULT_JSON")"
204
+ preview_reclaimed="$(jq -r '((.data.taskPhases // [] | map(select(.name=="preview"))[0].stats.reclaimedBytes) // .summary.reclaimedBytes // 0) | tonumber? // 0' "$RESULT_JSON")"
205
+ preview_failed="$(jq -r '((.data.taskPhases // [] | map(select(.name=="preview"))[0].stats.failedCount) // .summary.failedCount // 0) | tonumber? // 0' "$RESULT_JSON")"
206
+ scope_accounts="$(jq -r '.summary.accountCount // 0' "$RESULT_JSON")"
207
+ scope_months="$(jq -r '.summary.monthCount // 0' "$RESULT_JSON")"
208
+ scope_categories="$(jq -r '.summary.categoryCount // 0' "$RESULT_JSON")"
209
+ engine="$(jq -r '.data.engineUsed // .meta.engine // "unknown"' "$RESULT_JSON")"
210
+ matched_month_start="$(jq -r '.summary.matchedMonthStart // .data.report.matched.monthRange.from // ""' "$RESULT_JSON")"
211
+ matched_month_end="$(jq -r '.summary.matchedMonthEnd // .data.report.matched.monthRange.to // ""' "$RESULT_JSON")"
212
+ root_path_count="$(jq -r '.summary.rootPathCount // (.data.report.matched.rootStats // [] | length)' "$RESULT_JSON")"
214
213
 
215
214
  executed="false"
216
215
  execute_success=0
@@ -219,31 +218,16 @@ execute_failed=0
219
218
  execute_reclaimed=0
220
219
  execute_batch="-"
221
220
  verify_matched="$preview_matched"
222
- duration_exec=0
223
- duration_verify=0
224
- warnings_exec=0
225
- warnings_verify=0
226
- errors_exec=0
227
- errors_verify=0
228
-
229
- if [[ "$preview_matched" -gt 0 && "$EXECUTE" == "true" ]]; then
230
- run_cmd_to_file false "$EXEC_JSON" "$EXEC_ERR"
221
+ execute_phase_status="$(jq -r '.data.taskPhases // [] | map(select(.name=="execute"))[0].status // "missing"' "$RESULT_JSON")"
222
+ if [[ "$execute_phase_status" == "completed" ]]; then
231
223
  executed="true"
232
- execute_success="$(jq -r '.summary.successCount // 0' "$EXEC_JSON")"
233
- execute_skipped="$(jq -r '.summary.skippedCount // 0' "$EXEC_JSON")"
234
- execute_failed="$(jq -r '.summary.failedCount // 0' "$EXEC_JSON")"
235
- execute_reclaimed="$(jq -r '.summary.reclaimedBytes // 0' "$EXEC_JSON")"
236
- execute_batch="$(jq -r '.summary.batchId // "-"' "$EXEC_JSON")"
237
- duration_exec="$(jq -r '.meta.durationMs // 0' "$EXEC_JSON")"
238
- warnings_exec="$(jq -r '(.warnings // []) | length' "$EXEC_JSON")"
239
- errors_exec="$(jq -r '(.errors // []) | length' "$EXEC_JSON")"
240
-
241
- run_cmd_to_file true "$VERIFY_JSON" "$VERIFY_ERR"
242
- verify_matched="$(jq -r '.summary.matchedTargets // 0' "$VERIFY_JSON")"
243
- duration_verify="$(jq -r '.meta.durationMs // 0' "$VERIFY_JSON")"
244
- warnings_verify="$(jq -r '(.warnings // []) | length' "$VERIFY_JSON")"
245
- errors_verify="$(jq -r '(.errors // []) | length' "$VERIFY_JSON")"
224
+ execute_success="$(jq -r '((.data.taskPhases // [] | map(select(.name=="execute" and .status=="completed"))[0].stats.successCount) // .summary.successCount // 0) | tonumber? // 0' "$RESULT_JSON")"
225
+ execute_skipped="$(jq -r '((.data.taskPhases // [] | map(select(.name=="execute" and .status=="completed"))[0].stats.skippedCount) // .summary.skippedCount // 0) | tonumber? // 0' "$RESULT_JSON")"
226
+ execute_failed="$(jq -r '((.data.taskPhases // [] | map(select(.name=="execute" and .status=="completed"))[0].stats.failedCount) // .summary.failedCount // 0) | tonumber? // 0' "$RESULT_JSON")"
227
+ execute_reclaimed="$(jq -r '((.data.taskPhases // [] | map(select(.name=="execute" and .status=="completed"))[0].stats.reclaimedBytes) // .summary.reclaimedBytes // 0) | tonumber? // 0' "$RESULT_JSON")"
228
+ execute_batch="$(jq -r '((.data.taskPhases // [] | map(select(.name=="execute" and .status=="completed"))[0].stats.batchId) // .summary.batchId // "-")' "$RESULT_JSON")"
246
229
  fi
230
+ verify_matched="$(jq -r '((.data.taskPhases // [] | map(select(.name=="verify" and .status=="completed"))[0].stats.matchedTargets) // ((.data.taskPhases // [] | map(select(.name=="preview" and .status=="completed"))[0].stats.matchedTargets) // .summary.matchedTargets // 0)) | tonumber? // 0' "$RESULT_JSON")"
247
231
 
248
232
  if [[ "$executed" == "true" ]]; then
249
233
  conclusion="已完成"
@@ -256,9 +240,9 @@ else
256
240
  reason="已完成预演,等待授权执行真实清理。"
257
241
  fi
258
242
 
259
- duration_total=$((duration_preview + duration_exec + duration_verify))
260
- warnings_total=$((warnings_preview + warnings_exec + warnings_verify))
261
- errors_total=$((errors_preview + errors_exec + errors_verify))
243
+ duration_total="$(jq -r 'if ((.data.taskPhases // []) | length) > 0 then ([.data.taskPhases[] | (.durationMs // 0 | tonumber? // 0)] | add) else (.meta.durationMs // 0 | tonumber? // 0) end' "$RESULT_JSON")"
244
+ warnings_total="$(jq -r 'if ((.data.taskPhases // []) | length) > 0 then ([.data.taskPhases[] | (.warningCount // 0 | tonumber? // 0)] | add) else ((.warnings // []) | length) end' "$RESULT_JSON")"
245
+ errors_total="$(jq -r 'if ((.data.taskPhases // []) | length) > 0 then ([.data.taskPhases[] | (.errorCount // 0 | tonumber? // 0)] | add) else ((.errors // []) | length) end' "$RESULT_JSON")"
262
246
 
263
247
  selected_categories_human=""
264
248
  while IFS= read -r key; do