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,533 +0,0 @@
1
- /**
2
- * [INPUT]: 依赖 manifest 与 canonical devflow 路径,依赖 store 的文件读写能力,接收 repoRoot/changeId 以生成本地委派骨架。
3
- * [OUTPUT]: 对外提供 workspace scratch runtime 与 team-state 真相源能力。
4
- * [POS]: skill runtime 的本地委派桥接层,把 delegate/team 语义收口到 team-state + workspace scratch。
5
- * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
- */
7
-
8
- const path = require('path');
9
- const {
10
- ensureDir,
11
- writeText,
12
- exists,
13
- readText,
14
- runCommand,
15
- nowIso
16
- } = require('./store');
17
- const { classifyDelegationMode } = require('./lifecycle');
18
- const {
19
- readTeamState,
20
- writeTeamState,
21
- buildInitialTeamState,
22
- updateTeamState
23
- } = require('./team-state');
24
- const {
25
- getChangePaths,
26
- getWorkerPaths
27
- } = require('./paths');
28
-
29
- function getAssignmentsDir(repoRoot, changeId) {
30
- return getChangePaths(repoRoot, changeId).workspacesDir;
31
- }
32
-
33
- function getSharedRuntimeDir(repoRoot, changeId) {
34
- return path.join(getChangePaths(repoRoot, changeId).workspacesDir, '.runtime');
35
- }
36
-
37
- function getTeamMemoryPath(repoRoot, changeId) {
38
- return path.join(getSharedRuntimeDir(repoRoot, changeId), 'team-memory.md');
39
- }
40
-
41
- function getMessageBusPath(repoRoot, changeId) {
42
- return path.join(getSharedRuntimeDir(repoRoot, changeId), 'message-bus.md');
43
- }
44
-
45
- function getWorkerWorkspacePath(repoRoot, changeId, workerId) {
46
- return getWorkerPaths(repoRoot, changeId, workerId).workspacePath;
47
- }
48
-
49
- function getWorkersDir(repoRoot, changeId) {
50
- return getChangePaths(repoRoot, changeId).workspacesDir;
51
- }
52
-
53
- function getWorkerDir(repoRoot, changeId, workerId) {
54
- return getWorkerPaths(repoRoot, changeId, workerId).workerDir;
55
- }
56
-
57
- function getWorkerAssignmentPath(repoRoot, changeId, workerId) {
58
- return getWorkerPaths(repoRoot, changeId, workerId).assignmentPath;
59
- }
60
-
61
- function getWorkerStatePath(repoRoot, changeId, workerId) {
62
- return getWorkerPaths(repoRoot, changeId, workerId).statePath;
63
- }
64
-
65
- function getWorkerPromptPath(repoRoot, changeId, workerId) {
66
- return getWorkerPaths(repoRoot, changeId, workerId).promptPath;
67
- }
68
-
69
- function getWorkerJournalPath(repoRoot, changeId, workerId) {
70
- return getWorkerPaths(repoRoot, changeId, workerId).journalPath;
71
- }
72
-
73
- function getWorkerLaunchPath(repoRoot, changeId, workerId) {
74
- return getWorkerPaths(repoRoot, changeId, workerId).launchPath;
75
- }
76
-
77
- function getWorkerSessionLogPath(repoRoot, changeId, workerId) {
78
- return getWorkerPaths(repoRoot, changeId, workerId).sessionLogPath;
79
- }
80
-
81
- function guessWorkerRole(task) {
82
- if (task.type === 'TEST') {
83
- return 'qa-reviewer';
84
- }
85
- if (task.type === 'IMPL') {
86
- return 'dev-implementer';
87
- }
88
- return 'operator';
89
- }
90
-
91
- function buildOwnershipKey(task, state) {
92
- return JSON.stringify([
93
- classifyDelegationMode(task, state || {}),
94
- guessWorkerRole(task),
95
- [...(task.touches || [])].sort()
96
- ]);
97
- }
98
-
99
- function allocateWorkers(tasks, state) {
100
- const workerMap = new Map();
101
- const assignments = [];
102
- let sequence = 1;
103
-
104
- for (const task of tasks) {
105
- const route = classifyDelegationMode(task, state || {});
106
- if (route === 'direct') {
107
- assignments.push({
108
- taskId: task.id,
109
- route,
110
- workerId: 'main-agent',
111
- role: 'controller'
112
- });
113
- continue;
114
- }
115
-
116
- const key = buildOwnershipKey(task, state);
117
- if (!workerMap.has(key)) {
118
- const workerId = `${route}-${String(sequence).padStart(2, '0')}`;
119
- workerMap.set(key, {
120
- workerId,
121
- role: guessWorkerRole(task)
122
- });
123
- sequence += 1;
124
- }
125
-
126
- assignments.push({
127
- taskId: task.id,
128
- route,
129
- ...workerMap.get(key)
130
- });
131
- }
132
-
133
- return assignments;
134
- }
135
-
136
- async function detectCurrentBranch(repoRoot) {
137
- const branch = await runCommand('git rev-parse --abbrev-ref HEAD', { cwd: repoRoot });
138
- return branch.code === 0 ? branch.stdout.trim() : 'unknown';
139
- }
140
-
141
- async function ensureDelegationScaffold(repoRoot, changeId) {
142
- const change = getChangePaths(repoRoot, changeId);
143
- await ensureDir(change.executionDir);
144
- await ensureDir(change.workspacesDir);
145
- await ensureDir(getSharedRuntimeDir(repoRoot, changeId));
146
- }
147
-
148
- async function syncMessageBus(repoRoot, changeId, assignments, planVersion) {
149
- const busPath = getMessageBusPath(repoRoot, changeId);
150
- const existing = await readText(busPath, '');
151
- const header = existing.trim().length > 0 ? '' : '# Message Bus\n\n';
152
- const lines = [
153
- `## plan_version ${planVersion}`,
154
- '',
155
- ...assignments
156
- .filter((item) => item.route !== 'direct')
157
- .map((item) => `- ${item.workerId} queued for ${item.taskId} (${item.route})`)
158
- ];
159
-
160
- await writeText(busPath, `${existing}${header}${lines.join('\n')}\n\n`);
161
- }
162
-
163
- async function syncTeamMemory(repoRoot, changeId, manifest, assignments) {
164
- const teamMemoryPath = getTeamMemoryPath(repoRoot, changeId);
165
- const delegateAssignments = assignments.filter((item) => item.route !== 'direct');
166
- const content = [
167
- `# Team Memory: ${changeId}`,
168
- '',
169
- `- Plan Version: ${manifest.metadata?.planVersion || 1}`,
170
- `- Worker Count: ${new Set(delegateAssignments.map((item) => item.workerId)).size}`,
171
- '',
172
- '## Shared Constraints',
173
- '',
174
- '- change-state.json、task-manifest.json、team-state.json 是 durable truth。',
175
- '- workspace scratch 只保留运行态,不视为事实源。',
176
- '',
177
- '## Active Worker Ownership',
178
- '',
179
- ...(delegateAssignments.length > 0
180
- ? delegateAssignments.map((item) => `- ${item.workerId} (${item.role}) owns ${item.taskId}`)
181
- : ['- No delegate/team workers in current plan'])
182
- ].join('\n');
183
-
184
- await writeText(teamMemoryPath, `${content}\n`);
185
- }
186
-
187
- function groupAssignmentsByWorker(assignments) {
188
- return assignments
189
- .filter((item) => item.route !== 'direct')
190
- .reduce((map, item) => {
191
- if (!map.has(item.workerId)) {
192
- map.set(item.workerId, []);
193
- }
194
- map.get(item.workerId).push(item);
195
- return map;
196
- }, new Map());
197
- }
198
-
199
- async function syncAssignmentFiles(repoRoot, changeId, manifest, assignments, branch) {
200
- const grouped = groupAssignmentsByWorker(assignments);
201
-
202
- for (const [workerId, owned] of grouped.entries()) {
203
- const assignmentPath = getWorkerAssignmentPath(repoRoot, changeId, workerId);
204
- const role = owned[0].role;
205
- const workspace = getWorkerWorkspacePath(repoRoot, changeId, workerId);
206
- const lines = [
207
- `# Assignment: ${workerId}`,
208
- '',
209
- `- Worker: \`${workerId}\``,
210
- `- Role: \`${role}\``,
211
- `- Plan Version: ${manifest.metadata?.planVersion || 1}`,
212
- `- Branch: ${branch}`,
213
- `- Workspace: \`${workspace}\``,
214
- '',
215
- '## Owned Tasks',
216
- '',
217
- ...owned.map((assignment) => {
218
- const task = manifest.tasks.find((item) => item.id === assignment.taskId);
219
- return `- \`${assignment.taskId}\` ${task.title}`;
220
- }),
221
- '',
222
- '## Activity Log',
223
- '',
224
- '- queued'
225
- ];
226
-
227
- await writeText(assignmentPath, `${lines.join('\n')}\n`);
228
- }
229
- }
230
-
231
- async function syncWorkerFiles(repoRoot, changeId, manifest, assignments, branch) {
232
- const grouped = groupAssignmentsByWorker(assignments);
233
-
234
- for (const [workerId, owned] of grouped.entries()) {
235
- const role = owned[0].role;
236
- const workerDir = getWorkerDir(repoRoot, changeId, workerId);
237
- const workerPaths = getWorkerPaths(repoRoot, changeId, workerId);
238
- await ensureDir(workerDir);
239
-
240
- const state = [
241
- `# Worker State: ${workerId}`,
242
- '',
243
- `- Role: \`${role}\``,
244
- `- Plan Version: ${manifest.metadata?.planVersion || 1}`,
245
- '- Status: `idle`',
246
- '- Current Task: `none`',
247
- `- Branch: ${branch}`,
248
- `- Workspace: \`${workerPaths.workspacePath}\``
249
- ].join('\n');
250
-
251
- const journal = [
252
- `# Worker Journal: ${workerId}`,
253
- '',
254
- '## Initialized',
255
- '',
256
- `- Plan Version: ${manifest.metadata?.planVersion || 1}`,
257
- `- Assigned Tasks: ${owned.map((item) => item.taskId).join(', ')}`
258
- ].join('\n');
259
-
260
- await writeText(workerPaths.statePath, `${state}\n`);
261
- await writeText(workerPaths.journalPath, `${journal}\n`);
262
- }
263
- }
264
-
265
- async function syncTeamStateArtifacts(repoRoot, changeId, manifest, assignments, branch) {
266
- const delegateAssignments = assignments.filter((item) => item.route !== 'direct');
267
- if (delegateAssignments.length === 0) {
268
- return;
269
- }
270
-
271
- await writeTeamState(repoRoot, changeId, buildInitialTeamState(changeId, manifest, assignments, branch));
272
- }
273
-
274
- async function syncDelegationRuntime(repoRoot, changeId, manifest, state) {
275
- await ensureDelegationScaffold(repoRoot, changeId);
276
-
277
- const assignments = allocateWorkers(manifest.tasks || [], state);
278
- const branch = await detectCurrentBranch(repoRoot);
279
- const planVersion = manifest.metadata?.planVersion || 1;
280
-
281
- await syncWorkerFiles(repoRoot, changeId, manifest, assignments, branch);
282
- await syncAssignmentFiles(repoRoot, changeId, manifest, assignments, branch);
283
- await syncTeamMemory(repoRoot, changeId, manifest, assignments);
284
- await syncMessageBus(repoRoot, changeId, assignments, planVersion);
285
- await syncTeamStateArtifacts(repoRoot, changeId, manifest, assignments, branch);
286
-
287
- return {
288
- planVersion,
289
- assignments,
290
- delegatedCount: assignments.filter((item) => item.route !== 'direct').length,
291
- teamCount: assignments.filter((item) => item.route === 'team').length
292
- };
293
- }
294
-
295
- async function findAssignment(repoRoot, changeId, taskId) {
296
- const teamState = await readTeamState(repoRoot, changeId);
297
- if (!teamState?.team?.taskAssignments?.[taskId]) {
298
- return null;
299
- }
300
-
301
- const workerId = teamState.team.taskAssignments[taskId];
302
- const teammate = (teamState.team.teammates || []).find((item) => item.id === workerId);
303
- return {
304
- taskId,
305
- workerId,
306
- role: teammate?.role || 'developer',
307
- route: teamState.team.mode === 'parallel' ? 'team' : 'delegate'
308
- };
309
- }
310
-
311
- async function replaceSection(content, header, lines) {
312
- const next = lines.join('\n');
313
- const pattern = new RegExp(`## ${header}[\\s\\S]*?(?=\\n## |$)`, 'm');
314
- const section = `## ${header}\n\n${next}`;
315
-
316
- if (pattern.test(content)) {
317
- return content.replace(pattern, section);
318
- }
319
-
320
- return `${content.trimEnd()}\n\n${section}\n`;
321
- }
322
-
323
- async function updateAssignmentStatus(repoRoot, changeId, taskId, fields) {
324
- const assignment = await findAssignment(repoRoot, changeId, taskId);
325
- if (!assignment || assignment.workerId === 'main-agent') {
326
- return;
327
- }
328
-
329
- const assignmentPath = getWorkerAssignmentPath(repoRoot, changeId, assignment.workerId);
330
- if (!(await exists(assignmentPath))) {
331
- return;
332
- }
333
-
334
- const existing = await readText(assignmentPath, '');
335
- const logLines = existing.includes('## Activity Log')
336
- ? existing
337
- : await replaceSection(existing, 'Activity Log', ['- queued']);
338
- const message = [
339
- `- ${nowIso()} \`${taskId}\``,
340
- fields.status ? `status=\`${fields.status}\`` : '',
341
- fields.workspace ? `workspace=\`${fields.workspace}\`` : '',
342
- fields.sessionId ? `session=\`${fields.sessionId}\`` : '',
343
- fields.summary ? `summary=${fields.summary}` : ''
344
- ].filter(Boolean).join(' ');
345
-
346
- await writeText(assignmentPath, `${logLines.trimEnd()}\n${message}\n`);
347
- }
348
-
349
- async function updateWorkerState(repoRoot, changeId, workerId, fields) {
350
- const statePath = getWorkerStatePath(repoRoot, changeId, workerId);
351
- if (!(await exists(statePath))) {
352
- return;
353
- }
354
-
355
- const content = [
356
- `# Worker State: ${workerId}`,
357
- '',
358
- `- Role: \`${fields.role || 'developer'}\``,
359
- `- Plan Version: ${fields.planVersion || 1}`,
360
- `- Status: \`${fields.status || 'idle'}\``,
361
- `- Current Task: \`${fields.currentTask || 'none'}\``,
362
- `- Branch: ${fields.branch || 'unknown'}`,
363
- `- Workspace: \`${fields.workspace || 'pending'}\``
364
- ].join('\n');
365
- await writeText(statePath, `${content}\n`);
366
-
367
- await updateTeamState(repoRoot, changeId, (current) => {
368
- const teammates = [...(current.team?.teammates || [])];
369
- const nextIndex = teammates.findIndex((item) => item.id === workerId);
370
- if (nextIndex === -1) {
371
- return current;
372
- }
373
-
374
- teammates[nextIndex] = {
375
- ...teammates[nextIndex],
376
- status: fields.status || teammates[nextIndex].status,
377
- currentTask: fields.currentTask === 'none' ? null : (fields.currentTask || teammates[nextIndex].currentTask),
378
- lastActiveAt: nowIso()
379
- };
380
-
381
- return {
382
- ...current,
383
- updatedAt: nowIso(),
384
- team: {
385
- ...current.team,
386
- teammates,
387
- updatedAt: nowIso()
388
- }
389
- };
390
- });
391
- }
392
-
393
- async function appendWorkerJournal(repoRoot, changeId, workerId, message) {
394
- const journalPath = getWorkerJournalPath(repoRoot, changeId, workerId);
395
- const existing = await readText(journalPath, '');
396
- const header = existing.trim().length > 0 ? '' : `# Worker Journal: ${workerId}\n\n`;
397
- await writeText(journalPath, `${existing}${header}- ${message}\n`);
398
- }
399
-
400
- async function listWorkers(repoRoot, changeId) {
401
- const teamState = await readTeamState(repoRoot, changeId);
402
- if (!teamState?.team?.teammates) {
403
- return [];
404
- }
405
-
406
- return teamState.team.teammates.map((item) => ({
407
- workerId: item.id,
408
- role: item.role,
409
- status: item.status,
410
- currentTask: item.currentTask
411
- }));
412
- }
413
-
414
- async function buildWorkerHandoff(repoRoot, changeId, workerId) {
415
- const teamState = await readTeamState(repoRoot, changeId);
416
- if (!teamState?.team?.taskAssignments) {
417
- throw new Error(`No delegation runtime found for ${changeId}`);
418
- }
419
-
420
- const tasks = Object.entries(teamState.team.taskAssignments)
421
- .filter(([, assignedWorkerId]) => assignedWorkerId === workerId)
422
- .map(([taskId]) => taskId);
423
-
424
- if (tasks.length === 0) {
425
- throw new Error(`Worker ${workerId} has no assigned tasks`);
426
- }
427
-
428
- const teammate = (teamState.team.teammates || []).find((item) => item.id === workerId);
429
- const workerPaths = getWorkerPaths(repoRoot, changeId, workerId);
430
-
431
- return {
432
- changeId,
433
- workerId,
434
- role: teammate?.role || 'developer',
435
- status: teammate?.status || 'idle',
436
- planVersion: teamState.planVersion || 1,
437
- currentTask: teammate?.currentTask || null,
438
- taskIds: tasks,
439
- runtimeDir: workerPaths.workerDir,
440
- statePath: workerPaths.statePath,
441
- journalPath: workerPaths.journalPath,
442
- sessionLogPath: workerPaths.sessionLogPath,
443
- assignmentPath: workerPaths.assignmentPath,
444
- workspacePath: workerPaths.workspacePath
445
- };
446
- }
447
-
448
- async function appendMessageBus(repoRoot, changeId, message) {
449
- const busPath = getMessageBusPath(repoRoot, changeId);
450
- const existing = await readText(busPath, '');
451
- const header = existing.trim().length > 0 ? '' : '# Message Bus\n\n';
452
- await writeText(busPath, `${existing}${header}- ${message}\n`);
453
- }
454
-
455
- async function ensureWorkerWorkspace(repoRoot, changeId, assignment) {
456
- const fallback = {
457
- cwd: repoRoot,
458
- mode: 'fallback',
459
- workspacePath: repoRoot,
460
- reason: 'direct-or-no-worktree'
461
- };
462
-
463
- if (!assignment || assignment.workerId === 'main-agent') {
464
- return fallback;
465
- }
466
-
467
- const workspacePath = getWorkerWorkspacePath(repoRoot, changeId, assignment.workerId);
468
- if (await exists(workspacePath)) {
469
- return {
470
- cwd: workspacePath,
471
- mode: 'worktree',
472
- workspacePath,
473
- reason: 'reused'
474
- };
475
- }
476
-
477
- const hasGit = await runCommand('git rev-parse --show-toplevel', { cwd: repoRoot });
478
- if (hasGit.code !== 0) {
479
- return {
480
- cwd: repoRoot,
481
- mode: 'fallback',
482
- workspacePath: repoRoot,
483
- reason: 'git-unavailable'
484
- };
485
- }
486
-
487
- await ensureDir(path.dirname(workspacePath));
488
- const create = await runCommand(`git worktree add --detach "${workspacePath}" HEAD`, {
489
- cwd: repoRoot,
490
- timeoutMs: 60 * 1000
491
- });
492
- if (create.code !== 0) {
493
- return {
494
- cwd: repoRoot,
495
- mode: 'fallback',
496
- workspacePath: repoRoot,
497
- reason: (create.stderr || create.stdout || 'worktree add failed').trim().slice(0, 200)
498
- };
499
- }
500
-
501
- return {
502
- cwd: workspacePath,
503
- mode: 'worktree',
504
- workspacePath,
505
- reason: 'created'
506
- };
507
- }
508
-
509
- module.exports = {
510
- getAssignmentsDir,
511
- getSharedRuntimeDir,
512
- getTeamMemoryPath,
513
- getMessageBusPath,
514
- getWorkerWorkspacePath,
515
- getWorkersDir,
516
- getWorkerDir,
517
- getWorkerAssignmentPath,
518
- getWorkerStatePath,
519
- getWorkerPromptPath,
520
- getWorkerJournalPath,
521
- getWorkerLaunchPath,
522
- getWorkerSessionLogPath,
523
- allocateWorkers,
524
- syncDelegationRuntime,
525
- findAssignment,
526
- updateAssignmentStatus,
527
- updateWorkerState,
528
- appendWorkerJournal,
529
- listWorkers,
530
- buildWorkerHandoff,
531
- appendMessageBus,
532
- ensureWorkerWorkspace
533
- };