cc-devflow 4.5.11 → 4.5.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/.claude/skills/cc-act/CHANGELOG.md +18 -0
  2. package/.claude/skills/cc-act/PLAYBOOK.md +17 -269
  3. package/.claude/skills/cc-act/SKILL.md +38 -425
  4. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_INDEX_TEMPLATE.md +2 -13
  5. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_TEMPLATE.md +1 -9
  6. package/.claude/skills/cc-act/assets/PR_BRIEF_TEMPLATE.md +21 -177
  7. package/.claude/skills/cc-act/references/closure-contract.md +12 -63
  8. package/.claude/skills/cc-act/references/git-commit-guidelines.md +5 -5
  9. package/.claude/skills/cc-act/scripts/cc-act-common.sh +5 -322
  10. package/.claude/skills/cc-act/scripts/detect-ship-target.sh +11 -2
  11. package/.claude/skills/cc-act/scripts/inspect-git-index.sh +58 -0
  12. package/.claude/skills/cc-act/scripts/render-pr-brief.sh +40 -440
  13. package/.claude/skills/cc-act/scripts/verify-act-gate.sh +10 -50
  14. package/.claude/skills/cc-check/CHANGELOG.md +18 -0
  15. package/.claude/skills/cc-check/PLAYBOOK.md +19 -273
  16. package/.claude/skills/cc-check/SKILL.md +33 -456
  17. package/.claude/skills/cc-check/references/review-contract.md +12 -147
  18. package/.claude/skills/cc-dev/CHANGELOG.md +15 -0
  19. package/.claude/skills/cc-dev/PLAYBOOK.md +1 -1
  20. package/.claude/skills/cc-dev/SKILL.md +52 -137
  21. package/.claude/skills/cc-dev/scripts/resolve-cc-devflow.sh +181 -0
  22. package/.claude/skills/cc-do/CHANGELOG.md +11 -0
  23. package/.claude/skills/cc-do/PLAYBOOK.md +19 -113
  24. package/.claude/skills/cc-do/SKILL.md +39 -245
  25. package/.claude/skills/cc-do/references/execution-recovery.md +15 -109
  26. package/.claude/skills/cc-do/scripts/cc-do-common.sh +5 -57
  27. package/.claude/skills/cc-do/scripts/check-task-status.sh +35 -65
  28. package/.claude/skills/cc-do/scripts/mark-task-complete.sh +9 -46
  29. package/.claude/skills/cc-do/scripts/select-ready-tasks.sh +29 -97
  30. package/.claude/skills/cc-investigate/CHANGELOG.md +16 -0
  31. package/.claude/skills/cc-investigate/PLAYBOOK.md +20 -180
  32. package/.claude/skills/cc-investigate/SKILL.md +64 -246
  33. package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +48 -98
  34. package/.claude/skills/cc-investigate/references/investigation-contract.md +14 -218
  35. package/.claude/skills/cc-next/CHANGELOG.md +6 -0
  36. package/.claude/skills/cc-next/PLAYBOOK.md +12 -8
  37. package/.claude/skills/cc-next/SKILL.md +34 -140
  38. package/.claude/skills/cc-plan/CHANGELOG.md +16 -0
  39. package/.claude/skills/cc-plan/PLAYBOOK.md +22 -161
  40. package/.claude/skills/cc-plan/SKILL.md +45 -295
  41. package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +30 -228
  42. package/.claude/skills/cc-plan/references/planning-contract.md +24 -161
  43. package/.claude/skills/cc-plan/scripts/next-change-key.sh +8 -44
  44. package/.claude/skills/cc-plan/scripts/parse-task-dependencies.js +2 -2
  45. package/.claude/skills/cc-plan/scripts/validate-scope.sh +1 -1
  46. package/.claude/skills/cc-pr-land/SKILL.md +14 -114
  47. package/.claude/skills/cc-pr-review/CHANGELOG.md +4 -0
  48. package/.claude/skills/cc-pr-review/SKILL.md +20 -103
  49. package/.claude/skills/cc-review/CHANGELOG.md +17 -0
  50. package/.claude/skills/cc-review/PLAYBOOK.md +13 -86
  51. package/.claude/skills/cc-review/SKILL.md +53 -241
  52. package/.claude/skills/cc-review/references/e2e-and-plugin-verification.md +2 -2
  53. package/.claude/skills/cc-review/references/implementation-review-branch.md +7 -147
  54. package/.claude/skills/cc-review/references/plan-review-branch.md +5 -147
  55. package/.claude/skills/cc-review/references/review-methods.md +10 -218
  56. package/.claude/skills/cc-review/scripts/collect-review-context.sh +4 -63
  57. package/.claude/skills/cc-roadmap/PLAYBOOK.md +1 -1
  58. package/.claude/skills/cc-roadmap/SKILL.md +3 -3
  59. package/.claude/skills/cc-simplify/CHANGELOG.md +7 -0
  60. package/.claude/skills/cc-simplify/SKILL.md +26 -21
  61. package/.claude/skills/cc-spec-init/PLAYBOOK.md +12 -48
  62. package/.claude/skills/cc-spec-init/SKILL.md +29 -132
  63. package/.claude/skills/cc-spec-init/references/spec-contract.md +8 -17
  64. package/CHANGELOG.md +13 -0
  65. package/bin/cc-devflow-cli.js +20 -260
  66. package/bin/cc-devflow.js +44 -7
  67. package/docs/commands/README.md +1 -1
  68. package/docs/commands/README.zh-CN.md +1 -1
  69. package/docs/examples/README.md +1 -1
  70. package/docs/examples/START-HERE.md +14 -15
  71. package/docs/examples/example-bindings.json +11 -11
  72. package/docs/examples/full-design-blocked/README.md +4 -6
  73. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/{planning/tasks.md → task.md} +20 -15
  74. package/docs/examples/local-handoff/README.md +8 -11
  75. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/pr-brief.md +31 -0
  76. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/{planning/tasks.md → task.md} +18 -13
  77. package/docs/examples/pdca-loop/README.md +6 -9
  78. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/pr-brief.md +9 -11
  79. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/{planning/tasks.md → task.md} +18 -13
  80. package/docs/examples/scripts/check-example-bindings.sh +11 -62
  81. package/docs/guides/artifact-contract.md +10 -40
  82. package/docs/guides/getting-started.md +8 -8
  83. package/docs/guides/getting-started.zh-CN.md +8 -8
  84. package/docs/guides/minimize-artifacts.md +16 -130
  85. package/docs/guides/project-postmortem.md +14 -71
  86. package/lib/compiler/__tests__/skills-registry.test.js +9 -8
  87. package/lib/compiler/resource-copier.js +29 -0
  88. package/lib/skill-runtime/__tests__/archive-change.test.js +2 -2
  89. package/lib/skill-runtime/__tests__/benchmark-skills.test.js +3 -3
  90. package/lib/skill-runtime/__tests__/cli-bootstrap.integration.test.js +14 -4
  91. package/lib/skill-runtime/errors.js +3 -3
  92. package/lib/skill-runtime/index.js +5 -23
  93. package/lib/skill-runtime/paths.js +5 -52
  94. package/lib/skill-runtime/query-registry.js +4 -4
  95. package/lib/skill-runtime/query.js +89 -201
  96. package/lib/skill-runtime/store.js +4 -40
  97. package/lib/skill-runtime/trace.js +2 -2
  98. package/package.json +2 -5
  99. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_PRINCIPLES_TEMPLATE.md +0 -29
  100. package/.claude/skills/cc-act/assets/RELEASE_NOTE_TEMPLATE.md +0 -54
  101. package/.claude/skills/cc-act/scripts/generate-status-report.sh +0 -92
  102. package/.claude/skills/cc-act/scripts/sync-act-docs.sh +0 -355
  103. package/.claude/skills/cc-check/assets/REPORT_CARD_TEMPLATE.json +0 -234
  104. package/.claude/skills/cc-check/scripts/render-report-card.js +0 -438
  105. package/.claude/skills/cc-check/scripts/verify-gate.sh +0 -85
  106. package/.claude/skills/cc-do/scripts/build-task-context.sh +0 -175
  107. package/.claude/skills/cc-do/scripts/record-review-decision.sh +0 -88
  108. package/.claude/skills/cc-do/scripts/recover-workflow.sh +0 -82
  109. package/.claude/skills/cc-do/scripts/run-problem-analysis.sh +0 -70
  110. package/.claude/skills/cc-do/scripts/verify-task-gates.sh +0 -109
  111. package/.claude/skills/cc-do/scripts/write-task-checkpoint.sh +0 -92
  112. package/.claude/skills/cc-investigate/assets/TASK_MANIFEST_TEMPLATE.json +0 -224
  113. package/.claude/skills/cc-plan/assets/TASK_MANIFEST_TEMPLATE.json +0 -178
  114. package/.claude/skills/cc-spec-init/assets/CHANGE_META_TEMPLATE.json +0 -28
  115. package/.claude/skills/cc-spec-init/scripts/validate-spec-links.sh +0 -45
  116. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/design.md +0 -234
  117. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/task-manifest.json +0 -488
  118. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/review/report-card.json +0 -189
  119. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/resume-index.md +0 -39
  120. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/status.md +0 -29
  121. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/design.md +0 -123
  122. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/task-manifest.json +0 -292
  123. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/review/report-card.json +0 -136
  124. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/status.md +0 -29
  125. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/design.md +0 -124
  126. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json +0 -292
  127. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/review/report-card.json +0 -136
  128. package/docs/get-shit-done-strategy-audit.md +0 -518
  129. package/docs/skill-runtime-migration.md +0 -46
  130. package/lib/skill-runtime/__tests__/approve.test.js +0 -92
  131. package/lib/skill-runtime/__tests__/autopilot.test.js +0 -253
  132. package/lib/skill-runtime/__tests__/benchmark-artifacts.test.js +0 -165
  133. package/lib/skill-runtime/__tests__/delegation.test.js +0 -97
  134. package/lib/skill-runtime/__tests__/dispatch.test.js +0 -237
  135. package/lib/skill-runtime/__tests__/intent.test.js +0 -203
  136. package/lib/skill-runtime/__tests__/lifecycle.test.js +0 -169
  137. package/lib/skill-runtime/__tests__/planner.tdd.test.js +0 -331
  138. package/lib/skill-runtime/__tests__/prepare-pr.test.js +0 -126
  139. package/lib/skill-runtime/__tests__/query.test.js +0 -860
  140. package/lib/skill-runtime/__tests__/readiness.test.js +0 -53
  141. package/lib/skill-runtime/__tests__/release.test.js +0 -85
  142. package/lib/skill-runtime/__tests__/review-check-integration.test.js +0 -148
  143. package/lib/skill-runtime/__tests__/review-records.test.js +0 -619
  144. package/lib/skill-runtime/__tests__/runtime.integration.test.js +0 -351
  145. package/lib/skill-runtime/__tests__/schemas.test.js +0 -337
  146. package/lib/skill-runtime/__tests__/task-contract-migrate.test.js +0 -137
  147. package/lib/skill-runtime/__tests__/task-contract.test.js +0 -874
  148. package/lib/skill-runtime/__tests__/team-state.test.js +0 -51
  149. package/lib/skill-runtime/__tests__/verify-artifacts.test.js +0 -203
  150. package/lib/skill-runtime/__tests__/worker-run.test.js +0 -275
  151. package/lib/skill-runtime/__tests__/worker.test.js +0 -56
  152. package/lib/skill-runtime/__tests__/workflow-context-legacy-fallback.test.js +0 -31
  153. package/lib/skill-runtime/__tests__/workflow-context.test.js +0 -98
  154. package/lib/skill-runtime/artifacts.js +0 -88
  155. package/lib/skill-runtime/context-index.js +0 -545
  156. package/lib/skill-runtime/delegation.js +0 -533
  157. package/lib/skill-runtime/intent.js +0 -309
  158. package/lib/skill-runtime/lifecycle.js +0 -294
  159. package/lib/skill-runtime/operations/CLAUDE.md +0 -19
  160. package/lib/skill-runtime/operations/approve.js +0 -81
  161. package/lib/skill-runtime/operations/autopilot-core.js +0 -337
  162. package/lib/skill-runtime/operations/autopilot-execution.js +0 -307
  163. package/lib/skill-runtime/operations/autopilot-shared.js +0 -48
  164. package/lib/skill-runtime/operations/autopilot.js +0 -163
  165. package/lib/skill-runtime/operations/dispatch.js +0 -416
  166. package/lib/skill-runtime/operations/init.js +0 -60
  167. package/lib/skill-runtime/operations/janitor.js +0 -61
  168. package/lib/skill-runtime/operations/plan.js +0 -59
  169. package/lib/skill-runtime/operations/prepare-pr.js +0 -25
  170. package/lib/skill-runtime/operations/release.js +0 -99
  171. package/lib/skill-runtime/operations/resume.js +0 -126
  172. package/lib/skill-runtime/operations/review-records.js +0 -265
  173. package/lib/skill-runtime/operations/snapshot.js +0 -45
  174. package/lib/skill-runtime/operations/task-contract.js +0 -593
  175. package/lib/skill-runtime/operations/verify.js +0 -170
  176. package/lib/skill-runtime/operations/worker-run.js +0 -531
  177. package/lib/skill-runtime/operations/worker.js +0 -33
  178. package/lib/skill-runtime/planner.js +0 -539
  179. package/lib/skill-runtime/readiness.js +0 -84
  180. package/lib/skill-runtime/review-records.js +0 -123
  181. package/lib/skill-runtime/review.js +0 -855
  182. package/lib/skill-runtime/schemas.js +0 -746
  183. package/lib/skill-runtime/task-contract.js +0 -188
  184. package/lib/skill-runtime/team-state.js +0 -122
  185. package/lib/skill-runtime/workflow-context.js +0 -748
@@ -428,6 +428,7 @@ async function mirrorDirectoryRecursive(sourceDir, targetDir, options = {}) {
428
428
 
429
429
  if (!dryRun) {
430
430
  await fs.promises.mkdir(targetDir, { recursive: true, mode: 0o755 });
431
+ await pruneMirroredDirectoryRecursive(sourceDir, targetDir, options);
431
432
  }
432
433
 
433
434
  for (const entry of entries) {
@@ -473,6 +474,34 @@ async function mirrorDirectoryRecursive(sourceDir, targetDir, options = {}) {
473
474
  return result;
474
475
  }
475
476
 
477
+ async function pruneMirroredDirectoryRecursive(sourceDir, targetDir, options = {}) {
478
+ const { verbose = false } = options;
479
+
480
+ if (!fs.existsSync(targetDir)) {
481
+ return;
482
+ }
483
+
484
+ const targetEntries = await fs.promises.readdir(targetDir, { withFileTypes: true });
485
+ await Promise.all(
486
+ targetEntries.map(async (entry) => {
487
+ const sourcePath = path.join(sourceDir, entry.name);
488
+ const targetPath = path.join(targetDir, entry.name);
489
+
490
+ if (!fs.existsSync(sourcePath)) {
491
+ await fs.promises.rm(targetPath, { recursive: true, force: true });
492
+ if (verbose) {
493
+ console.log(`Pruned stale skill file: ${path.relative(process.cwd(), targetPath)}`);
494
+ }
495
+ return;
496
+ }
497
+
498
+ if (entry.isDirectory()) {
499
+ await pruneMirroredDirectoryRecursive(sourcePath, targetPath, options);
500
+ }
501
+ })
502
+ );
503
+ }
504
+
476
505
  // ============================================================
477
506
  // clearResourceCache - 清除资源缓存(用于测试)
478
507
  // ============================================================
@@ -61,13 +61,13 @@ describe('restoreChange', () => {
61
61
  const repoRoot = makeTempRepo();
62
62
  const archivedDir = path.join(repoRoot, 'devflow', 'changes', 'archive', '2026-04', 'REQ-002-restored');
63
63
  fs.mkdirSync(archivedDir, { recursive: true });
64
- fs.writeFileSync(path.join(archivedDir, 'tasks.md'), '- [ ] task');
64
+ fs.writeFileSync(path.join(archivedDir, 'task.md'), '- [ ] task');
65
65
 
66
66
  const result = restoreChange(repoRoot, archivedDir);
67
67
 
68
68
  expect(result.changeKey).toBe('REQ-002-restored');
69
69
  expect(fs.existsSync(result.restored)).toBe(true);
70
- expect(fs.existsSync(path.join(result.restored, 'tasks.md'))).toBe(true);
70
+ expect(fs.existsSync(path.join(result.restored, 'task.md'))).toBe(true);
71
71
  expect(fs.existsSync(archivedDir)).toBe(false);
72
72
 
73
73
  fs.rmSync(repoRoot, { recursive: true, force: true });
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * [INPUT]: 依赖 scripts/benchmark-skills.js 导出的 runBenchmarkSkills 和临时 skill fixture。
3
- * [OUTPUT]: 验证 benchmark:skills 对 SKILL.md 入口体积执行 byte/line 预算。
3
+ * [OUTPUT]: 验证 benchmark:skills 对 SKILL.md 入口体积执行 byte/line advisory 预算。
4
4
  * [POS]: skill 入口瘦身基准的 Red/Green 证据。
5
5
  * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
6
  */
@@ -78,12 +78,12 @@ describe('benchmark:skills', () => {
78
78
  });
79
79
  });
80
80
 
81
- test('exits 1 when cc-plan grows past the byte budget', () => {
81
+ test('reports advisory failure without blocking when cc-plan grows past the byte budget', () => {
82
82
  writeSkill(repoRoot, 'cc-plan', skillBody({ filler: 'x'.repeat(17000) }));
83
83
 
84
84
  const result = runBenchmarkSkills(repoRoot);
85
85
 
86
- expect(result.code).toBe(1);
86
+ expect(result.code).toBe(0);
87
87
  expect(result.rows[0]).toMatchObject({
88
88
  skill: 'cc-plan',
89
89
  correctness_pass: false,
@@ -108,7 +108,8 @@ describe('cc-devflow cli distribution bootstrap', () => {
108
108
 
109
109
  expect(skillContent).not.toContain('<!-- CC-DEVFLOW OUTPUT POLICY START -->');
110
110
  expect(skillContent).not.toContain('文档语言: zh-CN');
111
- expect(skillContent).toContain('cc-devflow config resolve --format policy');
111
+ expect(skillContent).toContain('resolve-cc-devflow.sh');
112
+ expect(skillContent).toContain('bash "$DEVFLOW" config resolve --format policy');
112
113
  expect(fs.readFileSync(path.join(customSkillDir, 'SKILL.md'), 'utf8')).toBe('# Custom Skill\n');
113
114
  });
114
115
 
@@ -177,7 +178,10 @@ describe('cc-devflow cli distribution bootstrap', () => {
177
178
  expect(runCli(['init', '--dir', repoRoot], repoRoot).status).toBe(0);
178
179
 
179
180
  const targetSkill = path.join(repoRoot, '.claude', 'skills', 'cc-roadmap', 'SKILL.md');
181
+ const staleManagedFile = path.join(repoRoot, '.claude', 'skills', 'cc-act', 'assets', 'STALE.md');
182
+ fs.mkdirSync(path.dirname(staleManagedFile), { recursive: true });
180
183
  fs.writeFileSync(targetSkill, '# local override\n');
184
+ fs.writeFileSync(staleManagedFile, '# stale\n');
181
185
 
182
186
  const result = runCli(['init', '--dir', repoRoot, '--force'], repoRoot);
183
187
  expect(result.status).toBe(0);
@@ -186,10 +190,14 @@ describe('cc-devflow cli distribution bootstrap', () => {
186
190
  fs.readFileSync(path.join(TEMPLATE_ROOT, 'skills', 'cc-roadmap', 'SKILL.md'), 'utf8')
187
191
  );
188
192
  expect(fs.existsSync(`${targetSkill}.new`)).toBe(false);
193
+ expect(fs.existsSync(staleManagedFile)).toBe(false);
189
194
  });
190
195
 
191
196
  test('adapt mirrors public skills into .codex/skills for Codex', () => {
192
197
  expect(runCli(['init', '--dir', repoRoot], repoRoot).status).toBe(0);
198
+ const staleCodexAsset = path.join(repoRoot, '.codex', 'skills', 'cc-act', 'assets', 'STALE.md');
199
+ fs.mkdirSync(path.dirname(staleCodexAsset), { recursive: true });
200
+ fs.writeFileSync(staleCodexAsset, '# stale\n');
193
201
 
194
202
  const result = runCli(['adapt', '--cwd', repoRoot, '--platform', 'codex'], repoRoot);
195
203
  expect(result.status).toBe(0);
@@ -202,6 +210,7 @@ describe('cc-devflow cli distribution bootstrap', () => {
202
210
  expect(fs.existsSync(path.join(repoRoot, '.codex', 'skills', 'cc-review', 'SKILL.md'))).toBe(true);
203
211
  expect(fs.existsSync(path.join(repoRoot, '.codex', 'skills', 'cc-check', 'SKILL.md'))).toBe(true);
204
212
  expect(fs.existsSync(path.join(repoRoot, '.codex', 'skills', 'cc-act', 'SKILL.md'))).toBe(true);
213
+ expect(fs.existsSync(staleCodexAsset)).toBe(false);
205
214
 
206
215
  const codexInvestigateSkill = fs.readFileSync(
207
216
  path.join(repoRoot, '.codex', 'skills', 'cc-investigate', 'SKILL.md'),
@@ -217,9 +226,9 @@ describe('cc-devflow cli distribution bootstrap', () => {
217
226
  expect(codexDoSkill.data.writes).toEqual(
218
227
  expect.arrayContaining([
219
228
  expect.objectContaining({
220
- path: 'devflow/changes/<change-key>/execution/tasks/<task-id>/events.jsonl',
229
+ path: 'devflow/changes/<change-key>/task.md',
221
230
  durability: 'durable',
222
- required: false
231
+ required: true
223
232
  })
224
233
  ])
225
234
  );
@@ -277,7 +286,8 @@ describe('cc-devflow cli distribution bootstrap', () => {
277
286
  );
278
287
  expect(codexPlanSkill).not.toContain('<!-- CC-DEVFLOW OUTPUT POLICY START -->');
279
288
  expect(codexPlanSkill).not.toContain('文档语言: zh-CN');
280
- expect(codexPlanSkill).toContain('cc-devflow config resolve --format policy');
289
+ expect(codexPlanSkill).toContain('resolve-cc-devflow.sh');
290
+ expect(codexPlanSkill).toContain('bash "$DEVFLOW" config resolve --format policy');
281
291
  });
282
292
 
283
293
  test('adapt preserves pre-existing non-public Codex skills and does not mirror new private ones', () => {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * [INPUT]: 接收 runtime/query/compiler 边界抛出的错误或失败字段。
3
- * [OUTPUT]: 生成可序列化 named error,保留 artifact refs 与 rescue action。
3
+ * [OUTPUT]: 生成可序列化 named error,保留 refs 与 rescue action。
4
4
  * [POS]: skill runtime 的失败语义层,避免用 null/false/string 表达可恢复失败。
5
5
  * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
6
  */
@@ -10,7 +10,7 @@ class SkillRuntimeError extends Error {
10
10
  super(message);
11
11
  this.name = name;
12
12
  this.artifactRefs = options.artifactRefs || [];
13
- this.rescueAction = options.rescueAction || 'inspect-runtime-artifacts';
13
+ this.rescueAction = options.rescueAction || 'inspect-task-md-and-git-history';
14
14
  this.details = options.details || {};
15
15
  }
16
16
  }
@@ -27,7 +27,7 @@ function serializeError(error, fallbackName = 'SkillRuntimeError') {
27
27
  name,
28
28
  message,
29
29
  artifactRefs: error?.artifactRefs || [],
30
- rescueAction: error?.rescueAction || 'inspect-runtime-artifacts',
30
+ rescueAction: error?.rescueAction || 'inspect-task-md-and-git-history',
31
31
  details: error?.details || {}
32
32
  };
33
33
  }
@@ -1,44 +1,26 @@
1
1
  /**
2
- * [INPUT]: 依赖 skill runtime 各模块。
3
- * [OUTPUT]: 统一导出 schema/store/planner/query 与 operations 入口。
4
- * [POS]: skill runtime 模块聚合出口,被内部测试与脚本使用。
2
+ * [INPUT]: 依赖 skill runtime 基础模块。
3
+ * [OUTPUT]: 统一导出 config/path/store/query helpers。
4
+ * [POS]: skill runtime 模块聚合出口,只保留 CLI 仍需的轻量能力。
5
5
  * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
6
  */
7
7
 
8
8
  const store = require('./store');
9
- const schemas = require('./schemas');
10
- const planner = require('./planner');
11
9
  const query = require('./query');
12
10
  const queryRegistry = require('./query-registry');
13
11
  const errors = require('./errors');
14
12
  const trace = require('./trace');
15
- const readiness = require('./readiness');
16
- const intent = require('./intent');
17
- const artifacts = require('./artifacts');
18
- const lifecycle = require('./lifecycle');
19
- const teamState = require('./team-state');
20
- const delegation = require('./delegation');
21
13
  const paths = require('./paths');
22
14
  const config = require('./config');
23
- const worker = require('./operations/worker');
24
- const workerRun = require('./operations/worker-run');
15
+ const archiveChange = require('./archive-change');
25
16
 
26
17
  module.exports = {
27
18
  ...store,
28
- ...schemas,
29
- ...planner,
30
19
  ...query,
31
20
  ...queryRegistry,
32
21
  ...errors,
33
22
  ...trace,
34
- ...readiness,
35
- ...artifacts,
36
- ...intent,
37
- ...lifecycle,
38
- ...teamState,
39
- ...delegation,
40
23
  ...paths,
41
24
  ...config,
42
- ...worker,
43
- ...workerRun
25
+ ...archiveChange
44
26
  };
@@ -1,6 +1,6 @@
1
1
  /**
2
- * [INPUT]: 依赖 fs/path,接收 repoRoot/changeId/taskId/workerId 等定位参数。
3
- * [OUTPUT]: 对外提供 devflow canonical layout 的唯一路径解析能力。
2
+ * [INPUT]: 依赖 fs/path,接收 repoRoot/changeId 等定位参数。
3
+ * [OUTPUT]: 对外提供 devflow canonical change layout 的唯一路径解析能力。
4
4
  * [POS]: skill runtime 的路径真相源,完整 change key 才是目录身份。
5
5
  * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
6
  */
@@ -70,10 +70,6 @@ function getChangesRoot(repoRoot) {
70
70
  return path.join(getDevflowRoot(repoRoot), 'changes');
71
71
  }
72
72
 
73
- function getWorkspacesRoot(repoRoot) {
74
- return path.join(getDevflowRoot(repoRoot), 'workspaces');
75
- }
76
-
77
73
  function listChangeKeys(repoRoot) {
78
74
  const changesRoot = getChangesRoot(repoRoot);
79
75
  if (!fs.existsSync(changesRoot)) {
@@ -196,56 +192,15 @@ function nextChangeKey(repoRoot, prefix, description) {
196
192
  function getChangePaths(repoRoot, changeId, options = {}) {
197
193
  const changeKey = resolveChangeKey(repoRoot, changeId, options);
198
194
  const changeDir = path.join(getChangesRoot(repoRoot), changeKey);
199
- const metaDir = path.join(changeDir, 'meta');
200
- const planningDir = path.join(changeDir, 'planning');
201
- const executionDir = path.join(changeDir, 'execution');
202
- const reviewDir = path.join(changeDir, 'review');
203
195
  const handoffDir = path.join(changeDir, 'handoff');
204
196
 
205
197
  return {
206
198
  changeId,
207
199
  changeKey,
208
200
  changeDir,
209
- metaDir,
210
- planningDir,
211
- executionDir,
212
- reviewDir,
213
201
  handoffDir,
214
- tasksDir: path.join(executionDir, 'tasks'),
215
- workersDir: path.join(executionDir, 'workers'),
216
- workspacesDir: path.join(getWorkspacesRoot(repoRoot), changeKey)
217
- };
218
- }
219
-
220
- function getTaskPaths(repoRoot, changeId, taskId, options = {}) {
221
- const change = getChangePaths(repoRoot, changeId, options);
222
- const taskDir = path.join(change.tasksDir, taskId);
223
-
224
- return {
225
- ...change,
226
- taskId,
227
- taskDir,
228
- eventsPath: path.join(taskDir, 'events.jsonl')
229
- };
230
- }
231
-
232
- function getWorkerPaths(repoRoot, changeId, workerId, options = {}) {
233
- const change = getChangePaths(repoRoot, changeId, options);
234
- const workspacePath = path.join(change.workspacesDir, workerId);
235
- const workerDir = path.join(workspacePath, '.runtime');
236
-
237
- return {
238
- ...change,
239
- workerId,
240
- workerDir,
241
- sharedRuntimeDir: path.join(change.workspacesDir, '.runtime'),
242
- assignmentPath: path.join(workerDir, 'assignment.md'),
243
- promptPath: path.join(workerDir, 'prompt.md'),
244
- launchPath: path.join(workerDir, 'launch.md'),
245
- statePath: path.join(workerDir, 'state.md'),
246
- journalPath: path.join(workerDir, 'journal.md'),
247
- sessionLogPath: path.join(workerDir, 'session.log'),
248
- workspacePath
202
+ taskPath: path.join(changeDir, 'task.md'),
203
+ prBriefPath: path.join(handoffDir, 'pr-brief.md')
249
204
  };
250
205
  }
251
206
 
@@ -256,11 +211,9 @@ module.exports = {
256
211
  getChangeSlug,
257
212
  getDevflowRoot,
258
213
  getChangesRoot,
259
- getWorkspacesRoot,
260
214
  nextChangeKey,
261
215
  resolveChangeKey,
262
216
  buildChangeKey,
263
217
  getChangePaths,
264
- getTaskPaths,
265
- getWorkerPaths
218
+ assertChangeId
266
219
  };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * [INPUT]: 接收 query id、repoRoot/changeId 与只读 handler registry。
3
- * [OUTPUT]: 返回 typed query result:ok/data 或 named error,并附 operational trace。
4
- * [POS]: skill runtime 的查询分发表,只读派生已有 artifact,不承载 workflow 语义。
3
+ * [OUTPUT]: 返回 typed query result:ok/data 或 named error,并附 trace。
4
+ * [POS]: skill runtime 的查询分发表,只读派生 task.md Git 语义。
5
5
  * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
6
  */
7
7
 
@@ -59,7 +59,7 @@ function createQueryRegistry(entries) {
59
59
  `Missing required query artifact: ${missingRefs.join(', ')}`,
60
60
  {
61
61
  artifactRefs: missingRefs,
62
- rescueAction: 'create required workflow artifacts before running this query'
62
+ rescueAction: 'create task.md before running this query'
63
63
  }
64
64
  );
65
65
  }
@@ -84,7 +84,7 @@ function createQueryRegistry(entries) {
84
84
  event: `query.${queryId}.failed`,
85
85
  changeId: context.changeId,
86
86
  artifactRefs,
87
- nextAction: error.rescueAction || 'inspect-workflow-artifacts'
87
+ nextAction: error.rescueAction || 'inspect-task-md-and-git-history'
88
88
  })
89
89
  };
90
90
  }
@@ -1,238 +1,126 @@
1
1
  /**
2
- * [INPUT]: 依赖 store/artifacts/lifecycle 读取 requirement 工件,接收 repoRoot、changeId 和可选 changeKey。
3
- * [OUTPUT]: 对外提供 typed query registry 与兼容查询函数,附 named error 和 trace shape
4
- * [POS]: skill runtime 的薄查询兼容层,只读 artifact 与共享 lifecycle 语义,不再自带流程推导副本。
2
+ * [INPUT]: 依赖 task.md、handoff/pr-brief.md Git 状态。
3
+ * [OUTPUT]: 提供 Git-first workflow-context 查询,不读取流程 JSON
4
+ * [POS]: cc-devflow CLI 的只读上下文层;Git 是历史真相,task.md 是任务真相。
5
5
  * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
6
  */
7
7
 
8
- const {
9
- getRuntimeStatePath,
10
- getTaskManifestPath,
11
- getReportCardPath,
12
- exists,
13
- readJson
14
- } = require('./store');
15
- const { getIntentPrBriefPath } = require('./artifacts');
16
- const { deriveManifestExecutionState } = require('./planner');
17
- const {
18
- getApprovalState,
19
- deriveLifecycleStage,
20
- deriveTaskProgress,
21
- isTaskCompletedStatus
22
- } = require('./lifecycle');
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const { spawnSync } = require('child_process');
23
11
  const { createQueryRegistry } = require('./query-registry');
24
- const { namedError } = require('./errors');
25
- const { deriveShipReadiness } = require('./readiness');
26
- const {
27
- getWorkflowContext,
28
- getWorkflowContextArtifactRefs,
29
- getWorkflowContextRequiredArtifactRefs
30
- } = require('./workflow-context');
31
-
32
- async function readQueryArtifact(filePath, { required = true } = {}) {
33
- try {
34
- const value = await readJson(filePath, null);
35
-
36
- if (required && value === null) {
37
- throw namedError(
38
- 'MissingQueryArtifactError',
39
- `Missing required query artifact: ${filePath}`,
40
- {
41
- artifactRefs: [filePath],
42
- rescueAction: 'create required workflow artifacts before running this query'
43
- }
44
- );
45
- }
46
-
47
- return value;
48
- } catch (error) {
49
- if (error.name === 'MissingQueryArtifactError') {
50
- throw error;
51
- }
12
+ const { getChangePaths } = require('./paths');
13
+ const { createTrace } = require('./trace');
52
14
 
53
- throw namedError(
54
- 'InvalidQueryArtifactError',
55
- `Invalid query artifact ${filePath}: ${error.message}`,
56
- {
57
- artifactRefs: [filePath],
58
- rescueAction: 'repair or regenerate the invalid workflow artifact before running this query',
59
- details: {
60
- cause: error.name || 'Error'
61
- }
62
- }
63
- );
64
- }
15
+ function readTextIfExists(filePath) {
16
+ return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : null;
65
17
  }
66
18
 
67
- /**
68
- * 获取任务进度统计
69
- * @param {string} repoRoot - 仓库根目录
70
- * @param {string} changeId - 需求 ID
71
- * @returns {Promise<Object>} 进度统计对象
72
- */
73
- async function getProgress(repoRoot, changeId, options = {}) {
74
- const manifestPath = getTaskManifestPath(repoRoot, changeId, options);
75
- const manifest = await readQueryArtifact(manifestPath);
76
- return deriveTaskProgress(manifest.tasks || []);
77
- }
19
+ function runGit(repoRoot, args) {
20
+ const result = spawnSync('git', args, {
21
+ cwd: repoRoot,
22
+ encoding: 'utf8'
23
+ });
78
24
 
79
- /**
80
- * 获取下一个待执行的任务
81
- * @param {string} repoRoot - 仓库根目录
82
- * @param {string} changeId - 需求 ID
83
- * @returns {Promise<Object|null>} 下一个任务对象或 null
84
- */
85
- async function getNextTask(repoRoot, changeId, options = {}) {
86
- const manifestPath = getTaskManifestPath(repoRoot, changeId, options);
87
- const manifest = await readQueryArtifact(manifestPath);
88
- const executionState = deriveManifestExecutionState(manifest.tasks || []);
89
- const activePhase = executionState.activePhase;
90
- const completedIds = new Set(
91
- (manifest.tasks || [])
92
- .filter((task) => isTaskCompletedStatus(task.status))
93
- .map((task) => task.id)
94
- );
95
- const currentTaskId = manifest.currentTaskId ?? executionState.currentTaskId;
96
-
97
- if (currentTaskId) {
98
- const currentTask = manifest.tasks.find((task) => task.id === currentTaskId);
99
- if (currentTask && currentTask.status === 'pending') {
100
- return currentTask;
101
- }
25
+ if (result.status !== 0) {
26
+ return null;
102
27
  }
103
28
 
104
- const nextTask = (manifest.tasks || []).find((task) => {
105
- if (task.status !== 'pending') {
106
- return false;
107
- }
29
+ return result.stdout.trim();
30
+ }
108
31
 
109
- if (activePhase !== null && activePhase !== undefined && (task.phase || 1) !== activePhase) {
110
- return false;
111
- }
32
+ function parseTaskSummary(markdown) {
33
+ const lines = String(markdown || '').split(/\r?\n/);
34
+ const tasks = [];
112
35
 
113
- return (task.dependsOn || []).every((depId) => completedIds.has(depId));
114
- });
36
+ for (const line of lines) {
37
+ const match = line.match(/^\s*-\s+\[( |x|X)\]\s+((?:T\d+|[A-Z]+-\d+)[^:\n]*)(?::\s*)?(.*)$/);
38
+ if (!match) continue;
115
39
 
116
- return nextTask || null;
117
- }
40
+ tasks.push({
41
+ id: match[2].trim().split(/\s+/)[0],
42
+ title: (match[3] || match[2]).trim(),
43
+ status: match[1].toLowerCase() === 'x' ? 'done' : 'pending'
44
+ });
45
+ }
118
46
 
119
- /**
120
- * 获取完整的聚合状态视图
121
- * @param {string} repoRoot - 仓库根目录
122
- * @param {string} changeId - 需求 ID
123
- * @returns {Promise<Object>} 完整状态对象
124
- */
125
- async function getFullState(repoRoot, changeId, options = {}) {
126
- const statePath = getRuntimeStatePath(repoRoot, changeId, options);
127
- const reportPath = getReportCardPath(repoRoot, changeId, options);
128
- const prBriefPath = getIntentPrBriefPath(repoRoot, changeId, options);
129
-
130
- const [state, manifest, hasPrBrief] = await Promise.all([
131
- readQueryArtifact(statePath),
132
- readQueryArtifact(getTaskManifestPath(repoRoot, changeId, options)),
133
- exists(prBriefPath)
134
- ]);
135
- const progress = await getProgress(repoRoot, changeId, options);
136
- const nextTask = await getNextTask(repoRoot, changeId, options);
137
- const report = await readQueryArtifact(reportPath, { required: false });
47
+ const completed = tasks.filter((task) => task.status === 'done').length;
48
+ const next = tasks.find((task) => task.status === 'pending') || null;
138
49
 
139
50
  return {
140
- lifecycle: {
141
- changeId: state.changeId,
142
- goal: state.goal,
143
- status: state.status,
144
- initializedAt: state.initializedAt,
145
- plannedAt: state.plannedAt,
146
- verifiedAt: state.verifiedAt,
147
- releasedAt: state.releasedAt,
148
- updatedAt: state.updatedAt,
149
- stage: deriveLifecycleStage({ state, manifest, report, hasPrBrief }),
150
- approval: getApprovalState(state, manifest)
151
- },
152
- progress,
153
- nextTask,
154
- delivery: {
155
- prBriefPath: hasPrBrief ? prBriefPath : null
156
- },
157
- quality: report ? {
158
- overall: report.overall,
159
- verdict: report.verdict || (report.overall === 'pass' ? 'pass' : 'fail'),
160
- reviewStatus: report.review?.status || 'skipped',
161
- reviewFindings: (report.review?.findings || []).length,
162
- blockingFindings: report.blockingFindings,
163
- timestamp: report.timestamp
164
- } : null
51
+ total: tasks.length,
52
+ completed,
53
+ pending: tasks.length - completed,
54
+ next
165
55
  };
166
56
  }
167
57
 
168
- async function getShipReadiness(repoRoot, changeId, options = {}) {
169
- const reportPath = getReportCardPath(repoRoot, changeId, options);
170
- const report = await readJson(reportPath, null);
171
-
172
- if (!report) {
173
- throw namedError(
174
- 'MissingReportCardError',
175
- `Missing report card for ${changeId}`,
176
- {
177
- artifactRefs: [reportPath],
178
- rescueAction: 'run cc-check and create review/report-card.json before cc-act'
179
- }
180
- );
181
- }
58
+ function getWorkflowContextArtifactRefs(repoRoot, changeId, options = {}) {
59
+ const change = getChangePaths(repoRoot, changeId, options);
60
+ return [
61
+ path.join(change.changeDir, 'task.md'),
62
+ path.join(change.handoffDir, 'pr-brief.md')
63
+ ];
64
+ }
182
65
 
183
- return deriveShipReadiness(report, { reportPath });
66
+ function getWorkflowContextRequiredArtifactRefs(repoRoot, changeId, options = {}) {
67
+ const change = getChangePaths(repoRoot, changeId, options);
68
+ return [path.join(change.changeDir, 'task.md')];
184
69
  }
185
70
 
186
- function queryArtifactRefs(repoRoot, changeId, names, options = {}) {
187
- const refs = {
188
- manifest: getTaskManifestPath(repoRoot, changeId, options),
189
- state: getRuntimeStatePath(repoRoot, changeId, options),
190
- report: getReportCardPath(repoRoot, changeId, options),
191
- prBrief: getIntentPrBriefPath(repoRoot, changeId, options)
192
- };
71
+ async function getWorkflowContext(repoRoot, changeId, options = {}) {
72
+ const change = getChangePaths(repoRoot, changeId, options);
73
+ const taskPath = path.join(change.changeDir, 'task.md');
74
+ const prBriefPath = path.join(change.handoffDir, 'pr-brief.md');
75
+ const taskMarkdown = readTextIfExists(taskPath) || '';
76
+ const taskSummary = parseTaskSummary(taskMarkdown);
193
77
 
194
- return names.map((name) => refs[name]).filter(Boolean);
78
+ const branch = runGit(repoRoot, ['branch', '--show-current']) || '';
79
+ const head = runGit(repoRoot, ['rev-parse', '--short', 'HEAD']) || '';
80
+ const status = runGit(repoRoot, ['status', '--short']) || '';
81
+ const recentCommits = runGit(repoRoot, ['log', '--oneline', '-5']) || '';
82
+
83
+ return {
84
+ changeId,
85
+ changeKey: change.changeKey,
86
+ nextAction: {
87
+ skill: taskSummary.next ? 'cc-do' : 'cc-check',
88
+ taskId: taskSummary.next ? taskSummary.next.id : null
89
+ },
90
+ files: {
91
+ task: taskPath,
92
+ prBrief: fs.existsSync(prBriefPath) ? prBriefPath : null
93
+ },
94
+ taskSummary,
95
+ git: {
96
+ branch,
97
+ head,
98
+ dirty: status.length > 0,
99
+ status: status ? status.split(/\r?\n/) : [],
100
+ recentCommits: recentCommits ? recentCommits.split(/\r?\n/) : []
101
+ }
102
+ };
195
103
  }
196
104
 
197
105
  const registry = createQueryRegistry([
198
- {
199
- id: 'progress',
200
- artifactRefs: ({ repoRoot, changeId, changeKey }) => queryArtifactRefs(repoRoot, changeId, ['manifest'], { changeKey }),
201
- requiredArtifactRefs: ({ repoRoot, changeId, changeKey }) => queryArtifactRefs(repoRoot, changeId, ['manifest'], { changeKey }),
202
- handler: ({ repoRoot, changeId, changeKey }) => getProgress(repoRoot, changeId, { changeKey })
203
- },
204
- {
205
- id: 'next-task',
206
- artifactRefs: ({ repoRoot, changeId, changeKey }) => queryArtifactRefs(repoRoot, changeId, ['manifest'], { changeKey }),
207
- requiredArtifactRefs: ({ repoRoot, changeId, changeKey }) => queryArtifactRefs(repoRoot, changeId, ['manifest'], { changeKey }),
208
- handler: ({ repoRoot, changeId, changeKey }) => getNextTask(repoRoot, changeId, { changeKey })
209
- },
210
- {
211
- id: 'full-state',
212
- artifactRefs: ({ repoRoot, changeId, changeKey }) => queryArtifactRefs(repoRoot, changeId, ['state', 'manifest', 'report', 'prBrief'], { changeKey }),
213
- requiredArtifactRefs: ({ repoRoot, changeId, changeKey }) => queryArtifactRefs(repoRoot, changeId, ['state', 'manifest'], { changeKey }),
214
- handler: ({ repoRoot, changeId, changeKey }) => getFullState(repoRoot, changeId, { changeKey })
215
- },
216
- {
217
- id: 'ship-readiness',
218
- artifactRefs: ({ repoRoot, changeId, changeKey }) => queryArtifactRefs(repoRoot, changeId, ['report'], { changeKey }),
219
- handler: ({ repoRoot, changeId, changeKey }) => getShipReadiness(repoRoot, changeId, { changeKey })
220
- },
221
106
  {
222
107
  id: 'workflow-context',
223
- artifactRefs: ({ repoRoot, changeId, changeKey }) => getWorkflowContextArtifactRefs(repoRoot, changeId, { changeKey }),
224
- requiredArtifactRefs: ({ repoRoot, changeId, changeKey }) => getWorkflowContextRequiredArtifactRefs(repoRoot, changeId, { changeKey }),
225
- nextAction: 'read-compact-workflow-context',
108
+ artifactRefs: ({ repoRoot, changeId, changeKey }) => (
109
+ getWorkflowContextArtifactRefs(repoRoot, changeId, { changeKey })
110
+ ),
111
+ requiredArtifactRefs: ({ repoRoot, changeId, changeKey }) => (
112
+ getWorkflowContextRequiredArtifactRefs(repoRoot, changeId, { changeKey })
113
+ ),
114
+ nextAction: 'read-task-md-and-git-history',
226
115
  handler: ({ repoRoot, changeId, changeKey }) => getWorkflowContext(repoRoot, changeId, { changeKey })
227
116
  }
228
117
  ]);
229
118
 
230
119
  module.exports = {
231
- getProgress,
232
- getNextTask,
233
- getFullState,
234
- getShipReadiness,
235
120
  getWorkflowContext,
121
+ getWorkflowContextArtifactRefs,
122
+ getWorkflowContextRequiredArtifactRefs,
236
123
  listQueryIds: registry.listQueryIds,
237
- runQuery: registry.runQuery
124
+ runQuery: registry.runQuery,
125
+ createTrace
238
126
  };