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,163 +0,0 @@
1
- /**
2
- * [INPUT]: 依赖 autopilot shared/core/execution runner,接收 changeId、goal、from、resume 等推进参数。
3
- * [OUTPUT]: 作为兼容入口串联最小阶段闭环,写入 autopilot 起止日志,并返回当前阶段、已执行步骤、resume 索引与 PR brief 路径。
4
- * [POS]: skill runtime 的 autopilot 兼容入口,只保留阶段顺序与总结果汇总。
5
- * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
- */
7
-
8
- const {
9
- exists
10
- } = require('../store');
11
- const {
12
- getIntentResumeIndexPath
13
- } = require('../artifacts');
14
- const { syncIntentMemory } = require('../intent');
15
- const {
16
- normalizeStage,
17
- stageIndex,
18
- resolveCompletedStage,
19
- runDiscoverStage,
20
- runConvergeStage,
21
- runApprovalStage,
22
- runDelegateStage,
23
- runFinishStages
24
- } = require('./autopilot-core');
25
- const {
26
- loadState
27
- } = require('./autopilot-shared');
28
- const {
29
- runExecutionStage
30
- } = require('./autopilot-execution');
31
-
32
- async function runAutopilot({
33
- repoRoot,
34
- changeId,
35
- goal,
36
- from,
37
- resume = false,
38
- overwrite = false,
39
- parallel = 3,
40
- maxRetries,
41
- strict = false,
42
- skipReview = false,
43
- release = false,
44
- workerProvider,
45
- workerProviderArgs,
46
- workerCommand
47
- }) {
48
- const executed = [];
49
- const fromIndex = stageIndex(from);
50
- const resolveResumeIndexPath = async () => (
51
- await exists(getIntentResumeIndexPath(repoRoot, changeId))
52
- ? getIntentResumeIndexPath(repoRoot, changeId)
53
- : null
54
- );
55
-
56
- await syncIntentMemory(repoRoot, changeId, {
57
- event: 'autopilot_started',
58
- reason: `Autopilot entered at stage ${normalizeStage(from) || 'discover'}`
59
- });
60
-
61
- let snapshot = await loadState(repoRoot, changeId);
62
-
63
- snapshot = await runDiscoverStage({
64
- repoRoot,
65
- changeId,
66
- goal,
67
- fromIndex,
68
- executed,
69
- snapshot
70
- });
71
-
72
- snapshot = await runConvergeStage({
73
- repoRoot,
74
- changeId,
75
- goal,
76
- fromIndex,
77
- overwrite,
78
- executed,
79
- snapshot
80
- });
81
-
82
- const approvalResult = await runApprovalStage({
83
- repoRoot,
84
- changeId,
85
- fromIndex,
86
- executed,
87
- snapshot
88
- });
89
- snapshot = approvalResult.snapshot;
90
-
91
- if (approvalResult.shouldStop) {
92
- const completedStage = resolveCompletedStage(snapshot);
93
- await syncIntentMemory(repoRoot, changeId, {
94
- event: 'autopilot_finished',
95
- reason: `Autopilot stopped at stage ${completedStage}`
96
- });
97
-
98
- return {
99
- changeId,
100
- executed,
101
- currentStage: completedStage,
102
- lifecycleStatus: snapshot.state?.status || 'unknown',
103
- reportOverall: snapshot.report?.overall || null,
104
- resumeIndexPath: await resolveResumeIndexPath(),
105
- prBriefPath: null
106
- };
107
- }
108
-
109
- snapshot = await runDelegateStage({
110
- repoRoot,
111
- changeId,
112
- fromIndex,
113
- executed,
114
- snapshot
115
- });
116
-
117
- snapshot = await runExecutionStage({
118
- repoRoot,
119
- changeId,
120
- fromIndex,
121
- snapshot,
122
- executed,
123
- parallel,
124
- maxRetries,
125
- resume,
126
- workerProvider,
127
- workerProviderArgs,
128
- workerCommand
129
- });
130
-
131
- const finishResult = await runFinishStages({
132
- repoRoot,
133
- changeId,
134
- from,
135
- fromIndex,
136
- strict,
137
- skipReview,
138
- release,
139
- executed,
140
- snapshot
141
- });
142
- snapshot = finishResult.snapshot;
143
-
144
- const completedStage = resolveCompletedStage(snapshot);
145
- await syncIntentMemory(repoRoot, changeId, {
146
- event: 'autopilot_finished',
147
- reason: `Autopilot stopped at stage ${completedStage}`
148
- });
149
-
150
- return {
151
- changeId,
152
- executed,
153
- currentStage: completedStage,
154
- lifecycleStatus: snapshot.state?.status || 'unknown',
155
- reportOverall: snapshot.report?.overall || null,
156
- resumeIndexPath: await resolveResumeIndexPath(),
157
- prBriefPath: finishResult.prBriefPath
158
- };
159
- }
160
-
161
- module.exports = {
162
- runAutopilot
163
- };
@@ -1,416 +0,0 @@
1
- /**
2
- * [INPUT]: 依赖 manifest/events 与 shell 执行能力,接收并行度与重试参数。
3
- * [OUTPUT]: 更新 task-manifest 状态,失败或 debug 时写入每任务 events.jsonl。
4
- * [POS]: skill runtime Stage-4 执行入口,被内部执行与恢复链路复用。
5
- * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
- */
7
-
8
- const {
9
- nowIso,
10
- appendJsonl,
11
- writeJson,
12
- readJson,
13
- runCommand,
14
- getTaskManifestPath,
15
- getRuntimeStatePath,
16
- getEventsPath
17
- } = require('../store');
18
- const { parseManifest } = require('../schemas');
19
- const { applyManifestExecutionState } = require('../planner');
20
- const { syncIntentMemory } = require('../intent');
21
- const {
22
- summarizeTaskStates,
23
- classifyDelegationMode,
24
- getApprovalState,
25
- isExecutionApproved
26
- } = require('../lifecycle');
27
- const {
28
- findAssignment,
29
- ensureWorkerWorkspace,
30
- updateAssignmentStatus,
31
- updateWorkerState,
32
- appendWorkerJournal,
33
- appendMessageBus
34
- } = require('../delegation');
35
-
36
- function toSessionId(taskId) {
37
- return `${taskId}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
38
- }
39
-
40
- function dependenciesPassed(task, taskMap) {
41
- return task.dependsOn.every((depId) => {
42
- const dep = taskMap.get(depId);
43
- return dep && dep.status === 'passed';
44
- });
45
- }
46
-
47
- function dependenciesFailed(task, taskMap) {
48
- return task.dependsOn.some((depId) => {
49
- const dep = taskMap.get(depId);
50
- return dep && (dep.status === 'failed' || dep.status === 'skipped');
51
- });
52
- }
53
-
54
- function hasTouchConflict(task, lockedTouches) {
55
- if (!task.touches || task.touches.length === 0) {
56
- return false;
57
- }
58
-
59
- return task.touches.some((filePath) => lockedTouches.has(filePath));
60
- }
61
-
62
- function selectBatch(readyTasks, parallel) {
63
- const selected = [];
64
- const lockedTouches = new Set();
65
-
66
- for (const task of readyTasks) {
67
- if (selected.length >= parallel) {
68
- break;
69
- }
70
-
71
- if (hasTouchConflict(task, lockedTouches)) {
72
- continue;
73
- }
74
-
75
- selected.push(task);
76
- for (const touched of task.touches) {
77
- lockedTouches.add(touched);
78
- }
79
- }
80
-
81
- return selected;
82
- }
83
-
84
- async function writeEvent(repoRoot, changeId, taskId, event, debug = false) {
85
- if (!debug && !String(event.type || '').includes('failed') && !String(event.type || '').includes('rejected')) {
86
- return;
87
- }
88
- const eventsPath = getEventsPath(repoRoot, changeId, taskId);
89
- await appendJsonl(eventsPath, event);
90
- }
91
-
92
- async function writeManifest(repoRoot, changeId, manifest) {
93
- const manifestPath = getTaskManifestPath(repoRoot, changeId);
94
- applyManifestExecutionState(manifest, nowIso());
95
- await writeJson(manifestPath, manifest);
96
- }
97
-
98
- async function executeTask({ repoRoot, changeId, task, retryOverride, debug = false }) {
99
- const assignment = await findAssignment(repoRoot, changeId, task.id);
100
- const worker = await ensureWorkerWorkspace(repoRoot, changeId, assignment);
101
- const sessionId = toSessionId(task.id);
102
- const commands = [...task.run, ...task.checks];
103
- const taskRetry = Number.isInteger(retryOverride) ? retryOverride : task.maxRetries;
104
- const maxAttempts = Math.max(1, taskRetry + 1);
105
- const expectedPlanVersion = task.planVersion || 1;
106
-
107
- if (assignment) {
108
- await updateAssignmentStatus(repoRoot, changeId, task.id, {
109
- status: 'running',
110
- workspace: worker.workspacePath,
111
- sessionId,
112
- summary: worker.mode === 'worktree'
113
- ? `Worker ${assignment.workerId} running in worktree`
114
- : `Worker ${assignment.workerId} fell back to controller workspace: ${worker.reason}`
115
- });
116
- await updateWorkerState(repoRoot, changeId, assignment.workerId, {
117
- role: assignment.role,
118
- planVersion: expectedPlanVersion,
119
- status: 'running',
120
- currentTask: task.id,
121
- workspace: worker.workspacePath
122
- });
123
- await appendWorkerJournal(
124
- repoRoot,
125
- changeId,
126
- assignment.workerId,
127
- `started ${task.id} in ${worker.mode === 'worktree' ? worker.workspacePath : 'controller workspace'}`
128
- );
129
- await appendMessageBus(
130
- repoRoot,
131
- changeId,
132
- `${assignment.workerId} started ${task.id} in ${worker.mode === 'worktree' ? worker.workspacePath : 'controller workspace'}`
133
- );
134
- }
135
-
136
- while (task.attempts < maxAttempts) {
137
- task.attempts += 1;
138
- task.status = 'running';
139
-
140
- await writeEvent(repoRoot, changeId, task.id, {
141
- type: 'task_started',
142
- changeId,
143
- taskId: task.id,
144
- sessionId,
145
- attempt: task.attempts,
146
- timestamp: nowIso()
147
- }, debug);
148
-
149
- let failed = false;
150
- let failureMessage = '';
151
-
152
- for (const command of commands) {
153
- const result = await runCommand(command, {
154
- cwd: worker.cwd,
155
- timeoutMs: 30 * 60 * 1000
156
- });
157
-
158
- await writeEvent(repoRoot, changeId, task.id, {
159
- type: 'command_finished',
160
- changeId,
161
- taskId: task.id,
162
- sessionId,
163
- attempt: task.attempts,
164
- command,
165
- code: result.code,
166
- durationMs: result.durationMs,
167
- timestamp: nowIso()
168
- }, debug);
169
-
170
- if (result.code !== 0) {
171
- failed = true;
172
- failureMessage = (result.stderr || result.stdout || 'Command failed').trim();
173
- break;
174
- }
175
- }
176
-
177
- if (!failed) {
178
- const latestManifest = parseManifest(await readJson(getTaskManifestPath(repoRoot, changeId)));
179
- const latestPlanVersion = latestManifest.metadata?.planVersion || 1;
180
-
181
- if (latestPlanVersion !== expectedPlanVersion) {
182
- failed = true;
183
- failureMessage = `Stale result rejected: task ran with plan_version ${expectedPlanVersion} but current plan_version is ${latestPlanVersion}`;
184
- }
185
- }
186
-
187
- if (!failed) {
188
- task.status = 'passed';
189
- task.lastError = undefined;
190
-
191
- await writeEvent(repoRoot, changeId, task.id, {
192
- type: 'task_passed',
193
- changeId,
194
- taskId: task.id,
195
- sessionId,
196
- attempts: task.attempts,
197
- timestamp: nowIso()
198
- }, debug);
199
-
200
- if (assignment) {
201
- await updateAssignmentStatus(repoRoot, changeId, task.id, {
202
- status: 'completed',
203
- workspace: worker.workspacePath,
204
- sessionId,
205
- summary: `Worker ${assignment.workerId} completed task successfully`
206
- });
207
- await updateWorkerState(repoRoot, changeId, assignment.workerId, {
208
- role: assignment.role,
209
- planVersion: expectedPlanVersion,
210
- status: 'idle',
211
- currentTask: 'none',
212
- workspace: worker.workspacePath
213
- });
214
- await appendWorkerJournal(repoRoot, changeId, assignment.workerId, `completed ${task.id}`);
215
- await appendMessageBus(repoRoot, changeId, `${assignment.workerId} completed ${task.id}`);
216
- }
217
-
218
- return;
219
- }
220
-
221
- task.status = 'failed';
222
- task.lastError = failureMessage;
223
-
224
- await writeEvent(repoRoot, changeId, task.id, {
225
- type: failureMessage.includes('Stale result rejected') ? 'task_stale_rejected' : 'task_failed',
226
- changeId,
227
- taskId: task.id,
228
- sessionId,
229
- attempt: task.attempts,
230
- error: failureMessage,
231
- timestamp: nowIso()
232
- }, debug);
233
-
234
- if (assignment) {
235
- await updateAssignmentStatus(repoRoot, changeId, task.id, {
236
- status: 'failed',
237
- workspace: worker.workspacePath,
238
- sessionId,
239
- summary: failureMessage.slice(0, 240)
240
- });
241
- await updateWorkerState(repoRoot, changeId, assignment.workerId, {
242
- role: assignment.role,
243
- planVersion: expectedPlanVersion,
244
- status: 'idle',
245
- currentTask: 'none',
246
- workspace: worker.workspacePath
247
- });
248
- await appendWorkerJournal(
249
- repoRoot,
250
- changeId,
251
- assignment.workerId,
252
- `failed ${task.id}: ${failureMessage.slice(0, 120)}`
253
- );
254
- await appendMessageBus(repoRoot, changeId, `${assignment.workerId} failed ${task.id}: ${failureMessage.slice(0, 120)}`);
255
- }
256
- }
257
- }
258
-
259
- function isTaskIncluded(task, executionScope, state) {
260
- if (executionScope === 'direct') {
261
- return classifyDelegationMode(task, state || {}) === 'direct';
262
- }
263
-
264
- return true;
265
- }
266
-
267
- async function runDispatch({
268
- repoRoot,
269
- changeId,
270
- parallel = 3,
271
- maxRetries,
272
- resume = false,
273
- executionScope = 'all',
274
- debug = false
275
- }) {
276
- const manifestPath = getTaskManifestPath(repoRoot, changeId);
277
- const manifest = parseManifest(await readJson(manifestPath));
278
- const activePlanVersion = manifest.metadata?.planVersion || 1;
279
-
280
- // Update change-state.json to in_progress on first dispatch
281
- const statePath = getRuntimeStatePath(repoRoot, changeId);
282
- const state = await readJson(statePath, null);
283
- const stateExists = require('fs').existsSync(statePath);
284
- const approval = getApprovalState(state, manifest);
285
- if (!isExecutionApproved(state, manifest)) {
286
- await syncIntentMemory(repoRoot, changeId, {
287
- event: 'dispatch_blocked_unapproved',
288
- reason: `Plan version ${approval.planVersion || activePlanVersion} must be approved before execute`
289
- });
290
-
291
- return {
292
- changeId,
293
- manifestPath,
294
- summary: summarizeTaskStates(manifest.tasks),
295
- success: false,
296
- reason: `Execution blocked until plan_version ${approval.planVersion || activePlanVersion} is approved. Return to the cc-plan approval gate and keep execution mode ${approval.executionMode}.`
297
- };
298
- }
299
-
300
- if (stateExists) {
301
- if (state.status === 'planned' || state.status === 'initialized') {
302
- state.status = 'in_progress';
303
- state.updatedAt = nowIso();
304
- await writeJson(statePath, state);
305
- }
306
- }
307
-
308
- if (resume) {
309
- for (const task of manifest.tasks) {
310
- if (task.status === 'running') {
311
- task.status = 'pending';
312
- }
313
- }
314
- }
315
-
316
- for (const task of manifest.tasks) {
317
- task.planVersion = activePlanVersion;
318
- }
319
-
320
- await syncIntentMemory(repoRoot, changeId, {
321
- event: resume ? 'resume_started' : 'dispatch_started',
322
- reason: resume ? 'Resume flow entered dispatch loop' : 'Dispatch flow entered execution loop'
323
- });
324
-
325
- const safeParallel = Math.max(1, Number.parseInt(parallel, 10) || 1);
326
-
327
- while (true) {
328
- const taskMap = new Map(manifest.tasks.map((task) => [task.id, task]));
329
- const pending = manifest.tasks.filter((task) =>
330
- task.status === 'pending' && isTaskIncluded(task, executionScope, state)
331
- );
332
-
333
- if (pending.length === 0) {
334
- break;
335
- }
336
-
337
- for (const task of pending) {
338
- if (dependenciesFailed(task, taskMap)) {
339
- task.status = 'skipped';
340
- task.lastError = 'Blocked by failed dependency';
341
- }
342
- }
343
-
344
- const ready = manifest.tasks.filter(
345
- (task) => task.status === 'pending' &&
346
- isTaskIncluded(task, executionScope, state) &&
347
- dependenciesPassed(task, taskMap)
348
- );
349
-
350
- if (ready.length === 0) {
351
- await writeManifest(repoRoot, changeId, manifest);
352
-
353
- await syncIntentMemory(repoRoot, changeId, {
354
- event: 'dispatch_blocked',
355
- reason: 'No ready tasks left after dependency evaluation'
356
- });
357
-
358
- return {
359
- changeId,
360
- manifestPath,
361
- summary: summarizeTaskStates(manifest.tasks),
362
- success: false,
363
- reason: 'No ready tasks left. Check dependencies and failed tasks.'
364
- };
365
- }
366
-
367
- const batch = selectBatch(ready, safeParallel);
368
-
369
- if (batch.length === 0) {
370
- const firstReady = ready[0];
371
- batch.push(firstReady);
372
- }
373
-
374
- await Promise.all(
375
- batch.map((task) =>
376
- executeTask({
377
- repoRoot,
378
- changeId,
379
- task,
380
- retryOverride: Number.isInteger(maxRetries) ? maxRetries : undefined,
381
- debug
382
- })
383
- )
384
- );
385
-
386
- await writeManifest(repoRoot, changeId, manifest);
387
- await syncIntentMemory(repoRoot, changeId, {
388
- event: 'dispatch_batch_completed',
389
- reason: `Completed batch of ${batch.length} task(s)`
390
- });
391
- }
392
-
393
- await writeManifest(repoRoot, changeId, manifest);
394
-
395
- const summary = summarizeTaskStates(manifest.tasks);
396
- const scopedPending = manifest.tasks.filter((task) =>
397
- ['pending', 'running', 'failed'].includes(task.status) && isTaskIncluded(task, executionScope, state)
398
- );
399
- const success = scopedPending.length === 0;
400
-
401
- await syncIntentMemory(repoRoot, changeId, {
402
- event: success ? 'dispatch_completed' : 'dispatch_incomplete',
403
- reason: success ? 'All executable tasks completed' : 'Dispatch loop ended with unresolved tasks'
404
- });
405
-
406
- return {
407
- changeId,
408
- manifestPath,
409
- summary,
410
- success
411
- };
412
- }
413
-
414
- module.exports = {
415
- runDispatch
416
- };
@@ -1,60 +0,0 @@
1
- /**
2
- * [INPUT]: 依赖 store 提供 repo/change 路径与读写能力,接收 changeId/goal 初始化参数。
3
- * [OUTPUT]: 写入 canonical devflow 目录与 change-state.json,返回初始化摘要。
4
- * [POS]: skill runtime Stage-1 初始化入口,供内部初始化链路复用。
5
- * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
- */
7
-
8
- const {
9
- nowIso,
10
- ensureDir,
11
- writeJson,
12
- readJson,
13
- getChangeDir,
14
- getRuntimeStatePath
15
- } = require('../store');
16
- const { getChangePaths, getChangeSlug } = require('../paths');
17
-
18
- async function runInit({ repoRoot, changeId, goal }) {
19
- const changePaths = getChangePaths(repoRoot, changeId, { goal });
20
- const changeDir = getChangeDir(repoRoot, changeId, { goal });
21
- const statePath = getRuntimeStatePath(repoRoot, changeId, { goal });
22
-
23
- await ensureDir(changeDir);
24
- await ensureDir(changePaths.metaDir);
25
- await ensureDir(changePaths.planningDir);
26
- await ensureDir(changePaths.reviewDir);
27
- await ensureDir(changePaths.handoffDir);
28
-
29
- const previous = (await readJson(statePath, {})) || {};
30
- const createdAt = previous.createdAt || nowIso();
31
- const nextState = {
32
- changeId,
33
- changeKey: changePaths.changeKey,
34
- slug: getChangeSlug(changeId, changePaths.changeKey),
35
- createdAt,
36
- goal: goal || previous.goal || `Deliver ${changeId} safely with task-state truth.`,
37
- status: 'initialized',
38
- initializedAt: previous.initializedAt || nowIso(),
39
- approval: {
40
- status: 'pending',
41
- executionMode: previous.approval?.executionMode || 'delegate'
42
- },
43
- updatedAt: nowIso()
44
- };
45
-
46
- await writeJson(statePath, nextState);
47
-
48
- return {
49
- changeId,
50
- changeDir,
51
- runtimeDir: changePaths.executionDir,
52
- changeKey: changePaths.changeKey,
53
- statePath,
54
- status: nextState.status
55
- };
56
- }
57
-
58
- module.exports = {
59
- runInit
60
- };
@@ -1,61 +0,0 @@
1
- /**
2
- * [INPUT]: 依赖 devflow/changes 下 execution/tasks 目录与 mtime,接收保留小时阈值。
3
- * [OUTPUT]: 删除过期任务运行态目录,并输出清理统计。
4
- * [POS]: skill runtime 熵清理入口,被 CLI `harness:janitor` 调用。
5
- * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
- */
7
-
8
- const fs = require('fs');
9
- const path = require('path');
10
- const {
11
- listDirectories,
12
- getRuntimeRoot
13
- } = require('../store');
14
-
15
- async function removeDirectoryRecursive(dirPath) {
16
- await fs.promises.rm(dirPath, { recursive: true, force: true });
17
- }
18
-
19
- async function runJanitor({ repoRoot, hours = 72 }) {
20
- const runtimeRoot = getRuntimeRoot(repoRoot);
21
- const cutoffMs = Date.now() - Number(hours) * 60 * 60 * 1000;
22
-
23
- const changeDirs = await listDirectories(runtimeRoot);
24
- let removedTaskDirs = 0;
25
- let removedChangeDirs = 0;
26
-
27
- for (const changeDir of changeDirs) {
28
- const taskDirs = await listDirectories(path.join(changeDir, 'execution', 'tasks'));
29
-
30
- for (const taskDir of taskDirs) {
31
- const stat = await fs.promises.stat(taskDir);
32
- const isStale = stat.mtimeMs < cutoffMs;
33
- if (!isStale) {
34
- continue;
35
- }
36
-
37
- await removeDirectoryRecursive(taskDir);
38
- removedTaskDirs += 1;
39
- }
40
-
41
- const remaining = await listDirectories(path.join(changeDir, 'execution', 'tasks'));
42
- if (remaining.length === 0) {
43
- const stat = await fs.promises.stat(changeDir);
44
- if (stat.mtimeMs < cutoffMs) {
45
- await removeDirectoryRecursive(path.join(changeDir, 'execution', 'tasks'));
46
- removedChangeDirs += 1;
47
- }
48
- }
49
- }
50
-
51
- return {
52
- runtimeRoot,
53
- removedTaskDirs,
54
- removedChangeDirs,
55
- cutoffHours: Number(hours)
56
- };
57
- }
58
-
59
- module.exports = {
60
- runJanitor
61
- };