cc-devflow 4.5.10 → 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 (187) hide show
  1. package/.claude/skills/cc-act/CHANGELOG.md +23 -0
  2. package/.claude/skills/cc-act/PLAYBOOK.md +17 -269
  3. package/.claude/skills/cc-act/SKILL.md +38 -418
  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 +24 -0
  15. package/.claude/skills/cc-check/PLAYBOOK.md +19 -273
  16. package/.claude/skills/cc-check/SKILL.md +33 -454
  17. package/.claude/skills/cc-check/references/review-contract.md +12 -147
  18. package/.claude/skills/cc-dev/CHANGELOG.md +20 -0
  19. package/.claude/skills/cc-dev/PLAYBOOK.md +1 -1
  20. package/.claude/skills/cc-dev/SKILL.md +52 -130
  21. package/.claude/skills/cc-dev/scripts/resolve-cc-devflow.sh +181 -0
  22. package/.claude/skills/cc-do/CHANGELOG.md +17 -0
  23. package/.claude/skills/cc-do/PLAYBOOK.md +19 -113
  24. package/.claude/skills/cc-do/SKILL.md +39 -236
  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 +23 -0
  31. package/.claude/skills/cc-investigate/PLAYBOOK.md +20 -180
  32. package/.claude/skills/cc-investigate/SKILL.md +65 -513
  33. package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +48 -95
  34. package/.claude/skills/cc-investigate/references/investigation-contract.md +14 -217
  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 +29 -0
  39. package/.claude/skills/cc-plan/PLAYBOOK.md +22 -161
  40. package/.claude/skills/cc-plan/SKILL.md +47 -640
  41. package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +30 -225
  42. package/.claude/skills/cc-plan/references/planning-contract.md +24 -160
  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 +27 -0
  65. package/README.md +5 -3
  66. package/README.zh-CN.md +5 -3
  67. package/bin/cc-devflow-cli.js +20 -260
  68. package/bin/cc-devflow.js +44 -7
  69. package/docs/commands/README.md +1 -1
  70. package/docs/commands/README.zh-CN.md +1 -1
  71. package/docs/examples/README.md +1 -1
  72. package/docs/examples/START-HERE.md +14 -14
  73. package/docs/examples/example-bindings.json +11 -11
  74. package/docs/examples/full-design-blocked/README.md +4 -6
  75. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/{planning/tasks.md → task.md} +20 -15
  76. package/docs/examples/local-handoff/README.md +8 -11
  77. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/pr-brief.md +31 -0
  78. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/{planning/tasks.md → task.md} +18 -13
  79. package/docs/examples/pdca-loop/README.md +6 -9
  80. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/pr-brief.md +9 -11
  81. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/{planning/tasks.md → task.md} +18 -13
  82. package/docs/examples/scripts/check-example-bindings.sh +11 -62
  83. package/docs/guides/artifact-contract.md +10 -36
  84. package/docs/guides/getting-started.md +8 -7
  85. package/docs/guides/getting-started.zh-CN.md +8 -7
  86. package/docs/guides/minimize-artifacts.md +16 -116
  87. package/docs/guides/project-postmortem.md +14 -71
  88. package/lib/compiler/__tests__/skills-registry.test.js +9 -8
  89. package/lib/compiler/resource-copier.js +29 -0
  90. package/lib/skill-runtime/__tests__/archive-change.test.js +2 -2
  91. package/lib/skill-runtime/__tests__/benchmark-skills.test.js +109 -0
  92. package/lib/skill-runtime/__tests__/cli-bootstrap.integration.test.js +14 -4
  93. package/lib/skill-runtime/errors.js +3 -3
  94. package/lib/skill-runtime/index.js +5 -23
  95. package/lib/skill-runtime/paths.js +5 -52
  96. package/lib/skill-runtime/query-registry.js +4 -4
  97. package/lib/skill-runtime/query.js +89 -201
  98. package/lib/skill-runtime/store.js +4 -40
  99. package/lib/skill-runtime/trace.js +2 -2
  100. package/package.json +5 -7
  101. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_PRINCIPLES_TEMPLATE.md +0 -29
  102. package/.claude/skills/cc-act/assets/RELEASE_NOTE_TEMPLATE.md +0 -54
  103. package/.claude/skills/cc-act/scripts/generate-status-report.sh +0 -92
  104. package/.claude/skills/cc-act/scripts/sync-act-docs.sh +0 -355
  105. package/.claude/skills/cc-check/assets/REPORT_CARD_TEMPLATE.json +0 -234
  106. package/.claude/skills/cc-check/scripts/render-report-card.js +0 -438
  107. package/.claude/skills/cc-check/scripts/verify-gate.sh +0 -85
  108. package/.claude/skills/cc-do/scripts/build-task-context.sh +0 -175
  109. package/.claude/skills/cc-do/scripts/record-review-decision.sh +0 -88
  110. package/.claude/skills/cc-do/scripts/recover-workflow.sh +0 -82
  111. package/.claude/skills/cc-do/scripts/run-problem-analysis.sh +0 -70
  112. package/.claude/skills/cc-do/scripts/verify-task-gates.sh +0 -109
  113. package/.claude/skills/cc-do/scripts/write-task-checkpoint.sh +0 -92
  114. package/.claude/skills/cc-investigate/assets/TASK_MANIFEST_TEMPLATE.json +0 -225
  115. package/.claude/skills/cc-plan/assets/TASK_MANIFEST_TEMPLATE.json +0 -179
  116. package/.claude/skills/cc-spec-init/assets/CHANGE_META_TEMPLATE.json +0 -28
  117. package/.claude/skills/cc-spec-init/scripts/validate-spec-links.sh +0 -45
  118. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/design.md +0 -234
  119. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/task-manifest.json +0 -488
  120. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/review/report-card.json +0 -189
  121. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/resume-index.md +0 -39
  122. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/status.md +0 -29
  123. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/design.md +0 -123
  124. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/task-manifest.json +0 -292
  125. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/review/report-card.json +0 -136
  126. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/status.md +0 -29
  127. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/design.md +0 -124
  128. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json +0 -292
  129. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/review/report-card.json +0 -136
  130. package/docs/get-shit-done-strategy-audit.md +0 -518
  131. package/docs/skill-runtime-migration.md +0 -46
  132. package/lib/skill-runtime/__tests__/approve.test.js +0 -92
  133. package/lib/skill-runtime/__tests__/autopilot.test.js +0 -253
  134. package/lib/skill-runtime/__tests__/benchmark-artifacts.test.js +0 -165
  135. package/lib/skill-runtime/__tests__/delegation.test.js +0 -97
  136. package/lib/skill-runtime/__tests__/dispatch.test.js +0 -237
  137. package/lib/skill-runtime/__tests__/intent.test.js +0 -203
  138. package/lib/skill-runtime/__tests__/lifecycle.test.js +0 -169
  139. package/lib/skill-runtime/__tests__/planner.tdd.test.js +0 -331
  140. package/lib/skill-runtime/__tests__/prepare-pr.test.js +0 -126
  141. package/lib/skill-runtime/__tests__/query.test.js +0 -860
  142. package/lib/skill-runtime/__tests__/readiness.test.js +0 -53
  143. package/lib/skill-runtime/__tests__/release.test.js +0 -85
  144. package/lib/skill-runtime/__tests__/review-check-integration.test.js +0 -148
  145. package/lib/skill-runtime/__tests__/review-records.test.js +0 -619
  146. package/lib/skill-runtime/__tests__/runtime.integration.test.js +0 -351
  147. package/lib/skill-runtime/__tests__/schemas.test.js +0 -337
  148. package/lib/skill-runtime/__tests__/task-contract-migrate.test.js +0 -137
  149. package/lib/skill-runtime/__tests__/task-contract.test.js +0 -783
  150. package/lib/skill-runtime/__tests__/team-state.test.js +0 -51
  151. package/lib/skill-runtime/__tests__/verify-artifacts.test.js +0 -203
  152. package/lib/skill-runtime/__tests__/worker-run.test.js +0 -275
  153. package/lib/skill-runtime/__tests__/worker.test.js +0 -56
  154. package/lib/skill-runtime/__tests__/workflow-context-legacy-fallback.test.js +0 -31
  155. package/lib/skill-runtime/__tests__/workflow-context.test.js +0 -98
  156. package/lib/skill-runtime/artifacts.js +0 -88
  157. package/lib/skill-runtime/context-index.js +0 -545
  158. package/lib/skill-runtime/delegation.js +0 -533
  159. package/lib/skill-runtime/intent.js +0 -309
  160. package/lib/skill-runtime/lifecycle.js +0 -294
  161. package/lib/skill-runtime/operations/CLAUDE.md +0 -19
  162. package/lib/skill-runtime/operations/approve.js +0 -81
  163. package/lib/skill-runtime/operations/autopilot-core.js +0 -337
  164. package/lib/skill-runtime/operations/autopilot-execution.js +0 -307
  165. package/lib/skill-runtime/operations/autopilot-shared.js +0 -48
  166. package/lib/skill-runtime/operations/autopilot.js +0 -163
  167. package/lib/skill-runtime/operations/dispatch.js +0 -416
  168. package/lib/skill-runtime/operations/init.js +0 -60
  169. package/lib/skill-runtime/operations/janitor.js +0 -61
  170. package/lib/skill-runtime/operations/plan.js +0 -59
  171. package/lib/skill-runtime/operations/prepare-pr.js +0 -25
  172. package/lib/skill-runtime/operations/release.js +0 -99
  173. package/lib/skill-runtime/operations/resume.js +0 -126
  174. package/lib/skill-runtime/operations/review-records.js +0 -265
  175. package/lib/skill-runtime/operations/snapshot.js +0 -45
  176. package/lib/skill-runtime/operations/task-contract.js +0 -524
  177. package/lib/skill-runtime/operations/verify.js +0 -170
  178. package/lib/skill-runtime/operations/worker-run.js +0 -531
  179. package/lib/skill-runtime/operations/worker.js +0 -33
  180. package/lib/skill-runtime/planner.js +0 -539
  181. package/lib/skill-runtime/readiness.js +0 -84
  182. package/lib/skill-runtime/review-records.js +0 -123
  183. package/lib/skill-runtime/review.js +0 -855
  184. package/lib/skill-runtime/schemas.js +0 -746
  185. package/lib/skill-runtime/task-contract.js +0 -187
  186. package/lib/skill-runtime/team-state.js +0 -122
  187. package/lib/skill-runtime/workflow-context.js +0 -748
@@ -1,51 +0,0 @@
1
- const fs = require('fs');
2
- const os = require('os');
3
- const path = require('path');
4
-
5
- const {
6
- getTeamStatePath,
7
- readTeamState,
8
- writeTeamState
9
- } = require('../team-state');
10
-
11
- describe('team-state', () => {
12
- test('writes and reads the canonical truth state', async () => {
13
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-team-state-'));
14
- fs.writeFileSync(path.join(repoRoot, 'package.json'), JSON.stringify({ name: 'team-state-smoke', version: '1.0.0' }, null, 2));
15
-
16
- await writeTeamState(repoRoot, 'REQ-123', {
17
- status: 'delegated',
18
- phase: 'delegate',
19
- branch: 'main',
20
- planVersion: 4,
21
- team: {
22
- mode: 'parallel',
23
- lead: 'main-agent',
24
- teammates: [
25
- {
26
- id: 'delegate-01',
27
- role: 'dev-implementer',
28
- status: 'idle',
29
- currentTask: null,
30
- completedTasks: [],
31
- lastActiveAt: '2026-03-26T00:00:00.000Z'
32
- }
33
- ],
34
- taskAssignments: {
35
- T001: 'delegate-01'
36
- },
37
- createdAt: '2026-03-26T00:00:00.000Z',
38
- updatedAt: '2026-03-26T00:00:00.000Z'
39
- }
40
- });
41
-
42
- const truth = JSON.parse(fs.readFileSync(getTeamStatePath(repoRoot, 'REQ-123'), 'utf8'));
43
- const state = await readTeamState(repoRoot, 'REQ-123');
44
-
45
- expect(truth.changeId).toBe('REQ-123');
46
- expect(truth.team.taskAssignments.T001).toBe('delegate-01');
47
- expect(state.changeId).toBe('REQ-123');
48
- expect(state.planVersion).toBe(4);
49
- expect(state.phase).toBe('delegate');
50
- });
51
- });
@@ -1,203 +0,0 @@
1
- /**
2
- * [INPUT]: 依赖 scripts/verify-artifacts.js 导出的 runVerifyArtifacts 和临时 change fixture。
3
- * [OUTPUT]: 验证 verify:artifacts 只实现 C1-C10,返回稳定 exit code 和 JSON 报告。
4
- * [POS]: REQ-003-minimize-workflow-artifacts T016 的 Red/Green 证据。
5
- * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
- */
7
-
8
- const fs = require('fs');
9
- const os = require('os');
10
- const path = require('path');
11
- const { spawnSync } = require('child_process');
12
-
13
- const { runVerifyArtifacts } = require('../../../scripts/verify-artifacts');
14
-
15
- const REPO_ROOT = path.resolve(__dirname, '../../..');
16
- const VERIFY_SCRIPT = path.join(REPO_ROOT, 'scripts', 'verify-artifacts.js');
17
-
18
- function writeJson(filePath, value) {
19
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
20
- fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
21
- }
22
-
23
- function tasksMarkdown({ profile = 'standard', taskCount = 1, extraBody = '' } = {}) {
24
- const contract = [
25
- '# Tasks',
26
- '',
27
- '## Contract Summary',
28
- '',
29
- 'Change: REQ-900-valid-artifacts',
30
- 'Mode: plan',
31
- `Profile: ${profile}`,
32
- 'Approval: approved',
33
- '',
34
- 'Goal:',
35
- '- Keep artifact verification deterministic.',
36
- '',
37
- 'Do Not Do:',
38
- '- Do not add checks outside C1-C10.',
39
- '',
40
- 'Approved Direction:',
41
- '- Verify the minimized artifact shape.',
42
- '',
43
- 'Acceptance:',
44
- '- The verifier returns stable rule ids and exit codes.',
45
- '',
46
- 'Verification:',
47
- '',
48
- '```bash',
49
- 'npm run verify:artifacts',
50
- '```',
51
- '',
52
- 'Risk / Escalate If:',
53
- '- The rule table drifts from C1-C10.',
54
- ''
55
- ];
56
- const tasks = Array.from({ length: taskCount }, (_, index) => [
57
- `- [ ] T${String(index + 1).padStart(3, '0')} validate artifacts`,
58
- ' Goal: Exercise one verifier rule.',
59
- ' Files: `scripts/verify-artifacts.js`',
60
- ' Verification: npm run verify:artifacts',
61
- ` Vertical slice: Slice ${index + 1}`,
62
- ''
63
- ].join('\n'));
64
- return [...contract, extraBody, '## Phase 1', '', ...tasks].join('\n');
65
- }
66
-
67
- function seedValidChange(repoRoot, options = {}) {
68
- const changeKey = options.changeKey || 'REQ-900-valid-artifacts';
69
- const changeDir = path.join(repoRoot, 'devflow', 'changes', changeKey);
70
- const planningDir = path.join(changeDir, 'planning');
71
- fs.mkdirSync(planningDir, { recursive: true });
72
- fs.writeFileSync(path.join(planningDir, 'tasks.md'), tasksMarkdown(options));
73
- writeJson(path.join(planningDir, 'task-manifest.json'), {
74
- changeId: changeKey,
75
- createdAt: '2026-05-12T00:00:00.000Z',
76
- updatedAt: '2026-05-12T00:00:00.000Z',
77
- currentTaskId: null,
78
- tasks: [],
79
- metadata: {
80
- source: 'tasks.md',
81
- generatedBy: 'cc-devflow task-contract',
82
- planVersion: 1
83
- }
84
- });
85
- writeJson(path.join(changeDir, 'change-meta.json'), {
86
- changeId: changeKey,
87
- requirementId: changeKey,
88
- goal: ['Verify artifacts'],
89
- acceptance: ['Verifier passes'],
90
- specReference: {
91
- source: 'planning/tasks.md#contract-summary',
92
- change: changeKey,
93
- mode: 'plan',
94
- profile: options.profile || 'standard',
95
- approval: 'approved'
96
- },
97
- _meta: {
98
- generatedBy: 'cc-devflow task-contract',
99
- generatedAt: '2026-05-12T00:00:00.000Z'
100
- }
101
- });
102
- return { changeDir, planningDir, changeKey };
103
- }
104
-
105
- describe('verify:artifacts', () => {
106
- let repoRoot;
107
-
108
- beforeEach(() => {
109
- repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-verify-artifacts-'));
110
- writeJson(path.join(repoRoot, 'package.json'), {
111
- name: 'verify-artifacts-fixture',
112
- version: '0.0.0',
113
- scripts: {
114
- 'verify:artifacts': 'node scripts/verify-artifacts.js'
115
- }
116
- });
117
- });
118
-
119
- afterEach(() => {
120
- fs.rmSync(repoRoot, { recursive: true, force: true });
121
- });
122
-
123
- const ruleCases = [
124
- ['C1', 2, (ctx) => fs.writeFileSync(path.join(ctx.planningDir, 'design.md'), '# legacy design\n')],
125
- ['C2', 2, (ctx) => fs.writeFileSync(path.join(ctx.planningDir, 'analysis.md'), '# legacy analysis\n')],
126
- ['C3', 2, (ctx) => {
127
- const reviewDir = path.join(ctx.changeDir, 'review');
128
- fs.mkdirSync(reviewDir, { recursive: true });
129
- fs.writeFileSync(path.join(reviewDir, 'cc-review-report.md'), '# legacy review\n');
130
- }],
131
- ['C4', 3, (ctx) => fs.writeFileSync(path.join(ctx.planningDir, 'tasks.md'), '# Tasks\n\n- [ ] T001 no contract\n')],
132
- ['C5', 3, (ctx) => writeJson(path.join(ctx.planningDir, 'task-manifest.json'), {
133
- changeId: ctx.changeKey,
134
- createdAt: '2026-05-12T00:00:00.000Z',
135
- updatedAt: '2026-05-12T00:00:00.000Z',
136
- currentTaskId: null,
137
- tasks: [],
138
- metadata: { source: 'tasks.md', generatedBy: 'manual', planVersion: 1 }
139
- })],
140
- ['C6', 3, (ctx) => writeJson(path.join(ctx.changeDir, 'change-meta.json'), {
141
- _meta: { generatedBy: 'manual' }
142
- })],
143
- ['C7', 4, (ctx) => fs.writeFileSync(path.join(ctx.planningDir, 'tasks.md'), tasksMarkdown({
144
- profile: 'tiny',
145
- taskCount: 2
146
- }))],
147
- ['C8', 5, (ctx) => {
148
- const reviewDir = path.join(ctx.changeDir, 'review');
149
- fs.mkdirSync(reviewDir, { recursive: true });
150
- fs.writeFileSync(path.join(reviewDir, 'review-ledger.jsonl'), '{"event":"review-started"}\n');
151
- }],
152
- ['C9', 5, (ctx) => {
153
- const reviewDir = path.join(ctx.changeDir, 'review');
154
- fs.mkdirSync(reviewDir, { recursive: true });
155
- fs.writeFileSync(path.join(reviewDir, 'report-card.json'), '{"overall":"pass"}\n');
156
- }],
157
- ['C10', 6, (ctx) => fs.writeFileSync(path.join(ctx.planningDir, 'tasks.md'), tasksMarkdown({
158
- profile: 'standard',
159
- extraBody: 'x'.repeat(12000)
160
- }))]
161
- ];
162
-
163
- test.each(ruleCases)('%s returns exit code %i with JSON report', async (ruleId, exitCode, mutate) => {
164
- const ctx = seedValidChange(repoRoot, { changeKey: `REQ-9${ruleId.slice(1).padStart(2, '0')}-${ruleId.toLowerCase()}` });
165
- mutate(ctx);
166
-
167
- const result = await runVerifyArtifacts(repoRoot);
168
-
169
- expect(result.code).toBe(exitCode);
170
- expect(result.violations[0]).toMatchObject({ ruleId, exitCode });
171
- expect(result.checks).toHaveLength(10);
172
- });
173
-
174
- test('passes a valid generated change and skips grandfathered legacy directories', async () => {
175
- seedValidChange(repoRoot);
176
- const legacy = seedValidChange(repoRoot, { changeKey: 'REQ-001-legacy-fallback' });
177
- fs.writeFileSync(path.join(legacy.planningDir, 'design.md'), '# grandfathered design\n');
178
- const manifest = JSON.parse(fs.readFileSync(path.join(legacy.planningDir, 'task-manifest.json'), 'utf8'));
179
- manifest.metadata.generatedBy = 'skill:cc-plan';
180
- fs.writeFileSync(path.join(legacy.planningDir, 'task-manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
181
-
182
- const result = await runVerifyArtifacts(repoRoot);
183
-
184
- expect(result).toMatchObject({ code: 0, ok: true });
185
- expect(result.skippedLegacy.map((item) => item.changeKey)).toContain('REQ-001-legacy-fallback');
186
- });
187
-
188
- test('CLI prints stdout JSON and exits with the first violation code', () => {
189
- const ctx = seedValidChange(repoRoot);
190
- fs.writeFileSync(path.join(ctx.planningDir, 'design.md'), '# rogue design\n');
191
-
192
- const result = spawnSync(process.execPath, [VERIFY_SCRIPT, repoRoot], { encoding: 'utf8' });
193
- const report = JSON.parse(result.stdout);
194
-
195
- expect(result.status).toBe(2);
196
- expect(report.violations[0].ruleId).toBe('C1');
197
- });
198
-
199
- test('package.json exposes npm run verify:artifacts', () => {
200
- const pkg = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf8'));
201
- expect(pkg.scripts['verify:artifacts']).toBe('node scripts/verify-artifacts.js');
202
- });
203
- });
@@ -1,275 +0,0 @@
1
- const fs = require('fs');
2
- const os = require('os');
3
- const path = require('path');
4
-
5
- const { syncDelegationRuntime, buildWorkerHandoff, getMessageBusPath, getWorkerAssignmentPath } = require('../delegation');
6
- const {
7
- buildProviderPrompt,
8
- buildProviderCommand,
9
- runWorkerCommand
10
- } = require('../operations/worker-run');
11
- const {
12
- getRuntimeStatePath,
13
- getTaskManifestPath,
14
- getEventsPath
15
- } = require('../store');
16
-
17
- function writeJson(filePath, value) {
18
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
19
- fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
20
- }
21
-
22
- function createManifest() {
23
- return {
24
- changeId: 'REQ-123',
25
- goal: 'Run delegated worker command',
26
- createdAt: '2026-03-25T01:00:00.000Z',
27
- updatedAt: '2026-03-25T01:01:00.000Z',
28
- tasks: [
29
- {
30
- id: 'T002',
31
- title: 'Delegated task',
32
- type: 'IMPL',
33
- dependsOn: [],
34
- touches: ['src/a.ts', 'src/b.ts'],
35
- run: ['echo delegated'],
36
- checks: [],
37
- status: 'pending',
38
- attempts: 0,
39
- maxRetries: 1
40
- }
41
- ],
42
- metadata: {
43
- source: 'default',
44
- generatedBy: 'test',
45
- planVersion: 2
46
- }
47
- };
48
- }
49
-
50
- function createSharedWorkerManifest() {
51
- return {
52
- changeId: 'REQ-123',
53
- goal: 'Run delegated worker command',
54
- createdAt: '2026-03-25T01:00:00.000Z',
55
- updatedAt: '2026-03-25T01:01:00.000Z',
56
- tasks: [
57
- {
58
- id: 'T002',
59
- title: 'Delegated task one',
60
- type: 'IMPL',
61
- dependsOn: [],
62
- touches: ['src/a.ts', 'src/b.ts'],
63
- run: ['echo delegated-one'],
64
- checks: [],
65
- status: 'pending',
66
- attempts: 0,
67
- maxRetries: 1
68
- },
69
- {
70
- id: 'T003',
71
- title: 'Delegated task two',
72
- type: 'IMPL',
73
- dependsOn: [],
74
- touches: ['src/a.ts', 'src/b.ts'],
75
- run: ['echo delegated-two'],
76
- checks: [],
77
- status: 'pending',
78
- attempts: 0,
79
- maxRetries: 1
80
- }
81
- ],
82
- metadata: {
83
- source: 'default',
84
- generatedBy: 'test',
85
- planVersion: 2
86
- }
87
- };
88
- }
89
-
90
- function setupRepoRoot(prefix) {
91
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
92
- fs.writeFileSync(
93
- path.join(repoRoot, 'package.json'),
94
- JSON.stringify({ name: 'worker-run-test', version: '1.0.0' }, null, 2)
95
- );
96
- writeJson(getRuntimeStatePath(repoRoot, 'REQ-123'), {
97
- changeId: 'REQ-123',
98
- changeKey: 'REQ-123-run-delegated-worker-command',
99
- slug: 'run-delegated-worker-command',
100
- createdAt: '2026-03-25T01:00:00.000Z',
101
- goal: 'Run delegated worker command',
102
- status: 'planned',
103
- initializedAt: '2026-03-25T01:00:00.000Z',
104
- plannedAt: '2026-03-25T01:01:00.000Z',
105
- updatedAt: '2026-03-25T01:01:00.000Z'
106
- });
107
- return repoRoot;
108
- }
109
-
110
- function writeManifest(repoRoot, manifest) {
111
- writeJson(getTaskManifestPath(repoRoot, manifest.changeId), manifest);
112
- }
113
-
114
- describe('runWorkerCommand', () => {
115
- test('builds thin provider launch commands for codex and claude', () => {
116
- const codexCommand = buildProviderCommand({
117
- provider: 'codex',
118
- providerPromptPath: '/tmp/provider.md',
119
- providerLastMessagePath: '/tmp/last-message.md',
120
- providerTranscriptPath: '/tmp/transcript.jsonl',
121
- workspace: '/tmp/worktree',
122
- providerArgs: '--model gpt-5'
123
- });
124
- const claudeCommand = buildProviderCommand({
125
- provider: 'claude',
126
- providerPromptPath: '/tmp/provider.md',
127
- providerLastMessagePath: '/tmp/last-message.md',
128
- providerTranscriptPath: '/tmp/transcript.jsonl',
129
- workspace: '/tmp/worktree',
130
- providerArgs: '--model sonnet --permission-mode bypassPermissions'
131
- });
132
-
133
- expect(codexCommand).toContain('codex exec');
134
- expect(codexCommand).toContain('--dangerously-bypass-approvals-and-sandbox');
135
- expect(codexCommand).toContain('/tmp/transcript.jsonl');
136
- expect(claudeCommand).toContain('claude -p');
137
- expect(claudeCommand).toContain('--dangerously-skip-permissions');
138
- });
139
-
140
- test('runs local worker command and records only task status truth by default', async () => {
141
- const repoRoot = setupRepoRoot('cc-devflow-worker-run-pass-');
142
- const manifest = createManifest();
143
- writeManifest(repoRoot, manifest);
144
- const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
145
- const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
146
-
147
- const result = await runWorkerCommand({
148
- repoRoot,
149
- changeId: 'REQ-123',
150
- workerId,
151
- command: 'printf "worker-ok"'
152
- });
153
-
154
- const state = fs.readFileSync(result.sessionLogPath.replace('session.log', 'state.md'), 'utf8');
155
- const journal = fs.readFileSync(result.sessionLogPath.replace('session.log', 'journal.md'), 'utf8');
156
- const log = fs.readFileSync(result.sessionLogPath, 'utf8');
157
- const bus = fs.readFileSync(getMessageBusPath(repoRoot, 'REQ-123'), 'utf8');
158
- const assignment = fs.readFileSync(getWorkerAssignmentPath(repoRoot, 'REQ-123', workerId), 'utf8');
159
- const nextManifest = JSON.parse(fs.readFileSync(getTaskManifestPath(repoRoot, 'REQ-123'), 'utf8'));
160
- const runtimeState = JSON.parse(fs.readFileSync(getRuntimeStatePath(repoRoot, 'REQ-123'), 'utf8'));
161
-
162
- expect(result.status).toBe('completed');
163
- expect(state).toContain('Status: `completed`');
164
- expect(journal).toContain('completed (exit 0)');
165
- expect(log).toContain('worker-ok');
166
- expect(bus).toContain(`${workerId} completed T002`);
167
- expect(assignment).toContain('`T002` status=`completed`');
168
- expect(fs.existsSync(getEventsPath(repoRoot, 'REQ-123', 'T002'))).toBe(false);
169
- expect(fs.existsSync(path.join(repoRoot, 'devflow/changes/REQ-123-run-delegated-worker-command/execution/workers'))).toBe(false);
170
- expect(nextManifest.tasks[0].status).toBe('passed');
171
- expect(runtimeState.status).toBe('in_progress');
172
- });
173
-
174
- test('builds provider prompt from assignment plus live manifest task brief', async () => {
175
- const repoRoot = setupRepoRoot('cc-devflow-worker-run-provider-');
176
- const manifest = createManifest();
177
- writeManifest(repoRoot, manifest);
178
- const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
179
- const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
180
- const handoff = await buildWorkerHandoff(repoRoot, 'REQ-123', workerId);
181
-
182
- const providerPrompt = await buildProviderPrompt(repoRoot, handoff, 'T002');
183
-
184
- expect(providerPrompt).toContain('## Worker Assignment');
185
- expect(providerPrompt).toContain('## Selected Task Brief');
186
- expect(providerPrompt).toContain('Task: `T002`');
187
- expect(providerPrompt).toContain('Delegated task');
188
- });
189
-
190
- test('writes failure events and manifest error when local command exits non-zero', async () => {
191
- const repoRoot = setupRepoRoot('cc-devflow-worker-run-fail-');
192
- const manifest = createManifest();
193
- writeManifest(repoRoot, manifest);
194
- const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
195
- const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
196
-
197
- const result = await runWorkerCommand({
198
- repoRoot,
199
- changeId: 'REQ-123',
200
- workerId,
201
- command: 'echo boom >&2 && exit 7'
202
- });
203
-
204
- const state = fs.readFileSync(result.sessionLogPath.replace('session.log', 'state.md'), 'utf8');
205
- const log = fs.readFileSync(result.sessionLogPath, 'utf8');
206
- const assignment = fs.readFileSync(getWorkerAssignmentPath(repoRoot, 'REQ-123', workerId), 'utf8');
207
- const failedManifest = JSON.parse(fs.readFileSync(getTaskManifestPath(repoRoot, 'REQ-123'), 'utf8'));
208
- const events = fs.readFileSync(getEventsPath(repoRoot, 'REQ-123', 'T002'), 'utf8');
209
-
210
- expect(result.status).toBe('failed');
211
- expect(result.result.code).toBe(7);
212
- expect(state).toContain('Status: `failed`');
213
- expect(log).toContain('boom');
214
- expect(assignment).toContain('`T002` status=`failed`');
215
- expect(events).toContain('worker_run_failed');
216
- expect(failedManifest.tasks[0].status).toBe('failed');
217
- expect(failedManifest.tasks[0].lastError).toContain('boom');
218
- });
219
-
220
- test('updates only the selected task when a worker owns multiple assignments', async () => {
221
- const repoRoot = setupRepoRoot('cc-devflow-worker-run-multi-');
222
- const manifest = createSharedWorkerManifest();
223
- writeManifest(repoRoot, manifest);
224
- const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
225
- const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
226
-
227
- expect(delegation.assignments.find((item) => item.taskId === 'T003').workerId).toBe(workerId);
228
-
229
- const result = await runWorkerCommand({
230
- repoRoot,
231
- changeId: 'REQ-123',
232
- workerId,
233
- taskId: 'T003',
234
- command: 'printf "worker-t003"'
235
- });
236
-
237
- const assignment = fs.readFileSync(getWorkerAssignmentPath(repoRoot, 'REQ-123', workerId), 'utf8');
238
-
239
- expect(result.taskId).toBe('T003');
240
- expect(assignment).toContain('`T003` status=`completed`');
241
- expect(assignment).not.toContain('`T002` status=`completed`');
242
- const nextManifest = JSON.parse(fs.readFileSync(getTaskManifestPath(repoRoot, 'REQ-123'), 'utf8'));
243
- expect(nextManifest.tasks.find((task) => task.id === 'T002').status).toBe('pending');
244
- expect(nextManifest.tasks.find((task) => task.id === 'T003').status).toBe('passed');
245
- });
246
-
247
- test('blocks stale worker assignments when manifest planVersion has moved on', async () => {
248
- const repoRoot = setupRepoRoot('cc-devflow-worker-run-stale-plan-');
249
- const manifest = createManifest();
250
- writeManifest(repoRoot, manifest);
251
- const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
252
- const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
253
-
254
- writeManifest(repoRoot, {
255
- ...manifest,
256
- metadata: {
257
- ...manifest.metadata,
258
- planVersion: 3
259
- }
260
- });
261
-
262
- await expect(runWorkerCommand({
263
- repoRoot,
264
- changeId: 'REQ-123',
265
- workerId,
266
- command: 'printf "should-not-run" > blocked.txt'
267
- })).rejects.toMatchObject({
268
- name: 'StalePlanVersionError',
269
- rescueAction: 'rerun delegation sync for current planVersion before worker-run'
270
- });
271
-
272
- expect(fs.existsSync(path.join(repoRoot, 'blocked.txt'))).toBe(false);
273
- expect(fs.existsSync(getEventsPath(repoRoot, 'REQ-123', 'T002'))).toBe(false);
274
- });
275
- });
@@ -1,56 +0,0 @@
1
- const fs = require('fs');
2
- const os = require('os');
3
- const path = require('path');
4
-
5
- const { syncDelegationRuntime } = require('../delegation');
6
- const { runWorkerSession } = require('../operations/worker');
7
-
8
- describe('runWorkerSession', () => {
9
- test('returns stable handoff bundle for a delegated worker', async () => {
10
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-worker-session-'));
11
- fs.writeFileSync(path.join(repoRoot, 'package.json'), JSON.stringify({ name: 'worker-session', version: '1.0.0' }, null, 2));
12
-
13
- const manifest = {
14
- changeId: 'REQ-123',
15
- goal: 'Prepare worker session',
16
- createdAt: '2026-03-25T01:00:00.000Z',
17
- updatedAt: '2026-03-25T01:01:00.000Z',
18
- tasks: [
19
- {
20
- id: 'T002',
21
- title: 'Multi file delegated task',
22
- type: 'IMPL',
23
- dependsOn: [],
24
- touches: ['src/a.ts', 'src/b.ts'],
25
- run: ['echo delegated'],
26
- checks: [],
27
- status: 'pending',
28
- attempts: 0,
29
- maxRetries: 1
30
- }
31
- ],
32
- metadata: {
33
- source: 'default',
34
- generatedBy: 'test',
35
- planVersion: 2
36
- }
37
- };
38
-
39
- const delegation = await syncDelegationRuntime(repoRoot, 'REQ-123', manifest);
40
- const workerId = delegation.assignments.find((item) => item.taskId === 'T002').workerId;
41
- const handoff = await runWorkerSession({
42
- repoRoot,
43
- changeId: 'REQ-123',
44
- workerId
45
- });
46
-
47
- const journal = fs.readFileSync(handoff.journalPath, 'utf8');
48
- const state = fs.readFileSync(handoff.statePath, 'utf8');
49
-
50
- expect(handoff.workerId).toBe(workerId);
51
- expect(handoff.assignmentPath).toContain('assignment.md');
52
- expect(handoff.taskIds).toEqual(['T002']);
53
- expect(journal).toContain('handoff prepared');
54
- expect(state).toContain('Status: `handoff_ready`');
55
- });
56
- });
@@ -1,31 +0,0 @@
1
- /**
2
- * [INPUT]: 依赖 getWorkflowContext 查询 seam、仓库内真实 legacy workflow artifacts。
3
- * [OUTPUT]: 验证 legacy design.md fallback 在 compact context 中仍是一等合同入口。
4
- * [POS]: REQ-003-minimize-workflow-artifacts T010 的 Red/Green 证据。
5
- * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
- */
7
-
8
- const path = require('path');
9
-
10
- const { getWorkflowContext } = require('../query');
11
-
12
- const repoRoot = path.resolve(__dirname, '../../..');
13
-
14
- describe('workflow-context legacy fallback refs', () => {
15
- test.each([
16
- ['REQ-002', 'REQ-002-unified-roadmap-truth']
17
- ])('%s keeps design.md as the first fallback contract ref', async (changeId, changeKey) => {
18
- const context = await getWorkflowContext(repoRoot, changeId, { changeKey });
19
- const designRef = `devflow/changes/${changeKey}/planning/design.md#approved-direction`;
20
-
21
- expect(context.legacyFallback).toBe(true);
22
- expect(context.source.contract.path).toBe(`devflow/changes/${changeKey}/planning/design.md`);
23
- expect(context.progressiveDisclosure.defaultOpen[0]).toEqual(expect.objectContaining({
24
- ref: designRef,
25
- reason: 'primary task contract',
26
- exists: true
27
- }));
28
- expect(context.progressiveDisclosure.defaultOpen.every((entry) => entry.exists === true))
29
- .toBe(true);
30
- });
31
- });