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
@@ -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
- });