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,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
- };