@s_s/harmonia 1.2.0 → 1.4.0

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 (180) hide show
  1. package/README.md +140 -392
  2. package/build/cli/setup.d.ts +4 -2
  3. package/build/cli/setup.js +44 -18
  4. package/build/cli/setup.js.map +1 -1
  5. package/build/core/action-registry.d.ts +36 -0
  6. package/build/core/action-registry.js +53 -0
  7. package/build/core/action-registry.js.map +1 -0
  8. package/build/core/artifacts.d.ts +66 -0
  9. package/build/core/artifacts.js +178 -0
  10. package/build/core/artifacts.js.map +1 -0
  11. package/build/core/dispatch.d.ts +18 -11
  12. package/build/core/dispatch.js +43 -33
  13. package/build/core/dispatch.js.map +1 -1
  14. package/build/core/issues.d.ts +37 -0
  15. package/build/core/issues.js +100 -0
  16. package/build/core/issues.js.map +1 -0
  17. package/build/core/overrides.d.ts +19 -26
  18. package/build/core/overrides.js +32 -98
  19. package/build/core/overrides.js.map +1 -1
  20. package/build/core/plugin.d.ts +86 -0
  21. package/build/core/plugin.js +332 -0
  22. package/build/core/plugin.js.map +1 -0
  23. package/build/core/registry.d.ts +36 -3
  24. package/build/core/registry.js +63 -5
  25. package/build/core/registry.js.map +1 -1
  26. package/build/core/reviews.d.ts +13 -13
  27. package/build/core/reviews.js +31 -32
  28. package/build/core/reviews.js.map +1 -1
  29. package/build/core/schema.d.ts +43 -15
  30. package/build/core/schema.js +124 -20
  31. package/build/core/schema.js.map +1 -1
  32. package/build/core/state.d.ts +29 -22
  33. package/build/core/state.js +49 -81
  34. package/build/core/state.js.map +1 -1
  35. package/build/core/steps.d.ts +15 -15
  36. package/build/core/steps.js +32 -33
  37. package/build/core/steps.js.map +1 -1
  38. package/build/core/tree-utils.d.ts +52 -0
  39. package/build/core/tree-utils.js +226 -0
  40. package/build/core/tree-utils.js.map +1 -0
  41. package/build/core/types.d.ts +417 -117
  42. package/build/core/types.js +15 -1
  43. package/build/core/types.js.map +1 -1
  44. package/build/core/workflow-engine.d.ts +68 -0
  45. package/build/core/workflow-engine.js +821 -0
  46. package/build/core/workflow-engine.js.map +1 -0
  47. package/build/core/workflow-validator.d.ts +22 -0
  48. package/build/core/workflow-validator.js +489 -0
  49. package/build/core/workflow-validator.js.map +1 -0
  50. package/build/index.js +28 -25
  51. package/build/index.js.map +1 -1
  52. package/build/setup/inject.d.ts +4 -4
  53. package/build/setup/inject.js +6 -6
  54. package/build/setup/inject.js.map +1 -1
  55. package/build/setup/templates.d.ts +9 -7
  56. package/build/setup/templates.js +68 -103
  57. package/build/setup/templates.js.map +1 -1
  58. package/build/tools/artifact-approve.d.ts +8 -0
  59. package/build/tools/artifact-approve.js +94 -0
  60. package/build/tools/artifact-approve.js.map +1 -0
  61. package/build/tools/artifact-schema.d.ts +12 -0
  62. package/build/tools/artifact-schema.js +148 -0
  63. package/build/tools/artifact-schema.js.map +1 -0
  64. package/build/tools/artifact-tools.d.ts +18 -0
  65. package/build/tools/artifact-tools.js +465 -0
  66. package/build/tools/artifact-tools.js.map +1 -0
  67. package/build/tools/{report-dispatch.d.ts → dispatch-report.d.ts} +7 -3
  68. package/build/tools/dispatch-report.js +261 -0
  69. package/build/tools/dispatch-report.js.map +1 -0
  70. package/build/tools/engine-helpers.d.ts +41 -0
  71. package/build/tools/engine-helpers.js +182 -0
  72. package/build/tools/engine-helpers.js.map +1 -0
  73. package/build/tools/get-project-status.d.ts +6 -4
  74. package/build/tools/get-project-status.js +308 -246
  75. package/build/tools/get-project-status.js.map +1 -1
  76. package/build/tools/get-role-prompt.d.ts +1 -1
  77. package/build/tools/get-role-prompt.js +7 -41
  78. package/build/tools/get-role-prompt.js.map +1 -1
  79. package/build/tools/issue-tools.d.ts +10 -0
  80. package/build/tools/issue-tools.js +169 -0
  81. package/build/tools/issue-tools.js.map +1 -0
  82. package/build/tools/iteration-start.d.ts +7 -4
  83. package/build/tools/iteration-start.js +51 -20
  84. package/build/tools/iteration-start.js.map +1 -1
  85. package/build/tools/loop-done.d.ts +11 -0
  86. package/build/tools/loop-done.js +109 -0
  87. package/build/tools/loop-done.js.map +1 -0
  88. package/build/tools/patch-start.d.ts +16 -0
  89. package/build/tools/patch-start.js +122 -0
  90. package/build/tools/patch-start.js.map +1 -0
  91. package/build/tools/project-init.d.ts +5 -5
  92. package/build/tools/project-init.js +47 -18
  93. package/build/tools/project-init.js.map +1 -1
  94. package/build/tools/role-dispatch.d.ts +55 -0
  95. package/build/tools/role-dispatch.js +508 -0
  96. package/build/tools/role-dispatch.js.map +1 -0
  97. package/build/tools/utils.d.ts +40 -0
  98. package/build/tools/utils.js +97 -0
  99. package/build/tools/utils.js.map +1 -0
  100. package/package.json +1 -1
  101. package/{build/hooks/claude-code.js → workflows/dev/hooks/claude.js} +34 -23
  102. package/{build → workflows/dev}/hooks/content.js +27 -18
  103. package/workflows/dev/hooks/index.js +52 -0
  104. package/{build → workflows/dev}/hooks/openclaw.js +31 -20
  105. package/{build → workflows/dev}/hooks/opencode.js +31 -20
  106. package/workflows/dev/roles/architect.md +68 -28
  107. package/workflows/dev/roles/coordinator.md +103 -0
  108. package/workflows/dev/roles/developer.md +5 -5
  109. package/workflows/dev/roles/tester.md +19 -19
  110. package/workflows/dev/schemas/api-contract.json +42 -0
  111. package/workflows/dev/schemas/api-design.json +30 -13
  112. package/workflows/dev/schemas/data-model.json +20 -7
  113. package/workflows/dev/schemas/prd.completeness-check.json +6 -5
  114. package/workflows/dev/schemas/prd.draft.json +13 -5
  115. package/workflows/dev/schemas/prd.final.json +34 -11
  116. package/workflows/dev/schemas/prd.json +29 -11
  117. package/workflows/dev/schemas/prd.requirements.json +6 -5
  118. package/workflows/dev/schemas/prototype.json +6 -2
  119. package/workflows/dev/schemas/task-breakdown.coarse.json +4 -3
  120. package/workflows/dev/schemas/task-breakdown.dependencies.json +5 -4
  121. package/workflows/dev/schemas/task-breakdown.detailed.json +8 -3
  122. package/workflows/dev/schemas/task-breakdown.final.json +8 -3
  123. package/workflows/dev/schemas/task-breakdown.json +8 -3
  124. package/workflows/dev/schemas/tech-design.analysis.json +6 -5
  125. package/workflows/dev/schemas/tech-design.draft.json +14 -5
  126. package/workflows/dev/schemas/tech-design.final.json +39 -13
  127. package/workflows/dev/schemas/tech-design.json +34 -13
  128. package/workflows/dev/schemas/tech-design.research.json +21 -0
  129. package/workflows/dev/schemas/test-plan.json +17 -7
  130. package/workflows/dev/schemas/test-report.json +26 -9
  131. package/workflows/dev/schemas/user-stories.json +7 -3
  132. package/workflows/dev/tools/index.js +23 -0
  133. package/workflows/dev/workflow.json +234 -101
  134. package/build/core/docs.d.ts +0 -32
  135. package/build/core/docs.js +0 -91
  136. package/build/core/docs.js.map +0 -1
  137. package/build/core/workflow.d.ts +0 -33
  138. package/build/core/workflow.js +0 -140
  139. package/build/core/workflow.js.map +0 -1
  140. package/build/hooks/claude-code.d.ts +0 -20
  141. package/build/hooks/claude-code.js.map +0 -1
  142. package/build/hooks/content.d.ts +0 -43
  143. package/build/hooks/content.js.map +0 -1
  144. package/build/hooks/install.d.ts +0 -40
  145. package/build/hooks/install.js +0 -63
  146. package/build/hooks/install.js.map +0 -1
  147. package/build/hooks/openclaw.d.ts +0 -24
  148. package/build/hooks/openclaw.js.map +0 -1
  149. package/build/hooks/opencode.d.ts +0 -29
  150. package/build/hooks/opencode.js.map +0 -1
  151. package/build/tools/approve-doc.d.ts +0 -6
  152. package/build/tools/approve-doc.js +0 -108
  153. package/build/tools/approve-doc.js.map +0 -1
  154. package/build/tools/dispatch-role.d.ts +0 -16
  155. package/build/tools/dispatch-role.js +0 -277
  156. package/build/tools/dispatch-role.js.map +0 -1
  157. package/build/tools/doc-tools.d.ts +0 -16
  158. package/build/tools/doc-tools.js +0 -389
  159. package/build/tools/doc-tools.js.map +0 -1
  160. package/build/tools/override-tools.d.ts +0 -6
  161. package/build/tools/override-tools.js +0 -129
  162. package/build/tools/override-tools.js.map +0 -1
  163. package/build/tools/report-dispatch.js +0 -194
  164. package/build/tools/report-dispatch.js.map +0 -1
  165. package/build/tools/set-scale.d.ts +0 -6
  166. package/build/tools/set-scale.js +0 -107
  167. package/build/tools/set-scale.js.map +0 -1
  168. package/build/tools/setup-project.d.ts +0 -8
  169. package/build/tools/setup-project.js +0 -116
  170. package/build/tools/setup-project.js.map +0 -1
  171. package/build/tools/update-phase.d.ts +0 -12
  172. package/build/tools/update-phase.js +0 -159
  173. package/build/tools/update-phase.js.map +0 -1
  174. package/workflows/dev/roles/pm.md +0 -99
  175. package/workflows/dev/schemas/deploy.json +0 -20
  176. package/workflows/dev/schemas/fsd.json +0 -25
  177. package/workflows/dev/schemas/project-plan.json +0 -20
  178. package/workflows/dev/schemas/retrospective.json +0 -20
  179. package/workflows/dev/schemas/risk-assessment.json +0 -15
  180. package/workflows/dev/schemas/tech-design.api-contract.json +0 -20
@@ -0,0 +1,508 @@
1
+ /**
2
+ * MCP Tool: role_dispatch
3
+ *
4
+ * Prepare all data needed to hand off a task to a team member role.
5
+ * Returns: role prompt (with overrides injected), session guidance,
6
+ * input artifacts, task brief, and dispatch tracking info.
7
+ *
8
+ * Node-based architecture: validates against workflow node states.
9
+ * Accepts an optional node_id parameter to target a specific task node.
10
+ *
11
+ * Session/parallel behavior is enforced by Core:
12
+ * - session: none → never searches for idle sessions
13
+ * - session: persistent → searches for idle sessions, directs reuse
14
+ * - session: optional → searches for idle sessions, suggests reuse
15
+ * - parallel: true + running dispatch → forces new session
16
+ *
17
+ * Automatically:
18
+ * - Creates a dispatch record for tracking
19
+ * - Enforces session/parallel strategy from role frontmatter
20
+ * - Triggers a dispatch_requested engine event
21
+ * - Returns nextAction from the workflow engine
22
+ *
23
+ * This tool does NOT launch agents — it only prepares the data.
24
+ * The coordinator decides how to pass this to the team member.
25
+ */
26
+ import { z } from 'zod';
27
+ import { readArtifact, listArtifacts, resolveArtifactDir } from '../core/artifacts.js';
28
+ import { getMergedOverrides, resolveRoleConfig } from '../core/overrides.js';
29
+ import { createDispatch, findIdleSession, hasRunningDispatch } from '../core/dispatch.js';
30
+ import { loadArtifactSchema, formatSchemaGuidance } from '../core/schema.js';
31
+ import { resolveActive, isError, buildOverrideSection } from './utils.js';
32
+ import { loadWorkflowForContext, processWorkflowEvent, formatNextAction, findTaskNode } from './engine-helpers.js';
33
+ import { collectTaskNodes, findAncestorLoopId } from '../core/tree-utils.js';
34
+ /**
35
+ * Find task nodes for a given role that are active or pending.
36
+ */
37
+ function findDispatchableNodes(wf, state, role) {
38
+ const allTasks = collectTaskNodes(wf.definition.root);
39
+ // Include floating nodes
40
+ if (wf.definition.floatingNodes) {
41
+ allTasks.push(...wf.definition.floatingNodes);
42
+ }
43
+ return allTasks.filter((t) => {
44
+ if (t.role !== role)
45
+ return false;
46
+ const nodeState = state.nodes[t.id];
47
+ return nodeState && (nodeState.status === 'active' || nodeState.status === 'pending');
48
+ });
49
+ }
50
+ /**
51
+ * Build session guidance text.
52
+ *
53
+ * Incorporates session type behavior, parallel status, model, and agent info.
54
+ * This replaces the former separate "## Configuration" section — all dispatch
55
+ * configuration info is now part of Session Guidance.
56
+ */
57
+ function buildSessionGuidance(params) {
58
+ const { idleSession, sessionType, model, agent, parallelForced } = params;
59
+ const lines = [];
60
+ // Consistent agent descriptor used across all Action lines
61
+ const agentDesc = agent ? `拉起 ${agent} 作为子 agent 执行任务` : '拉起子 agent 执行任务';
62
+ // Model/agent header
63
+ if (model) {
64
+ const agentSuffix = agent ? `,使用 ${agent}` : '';
65
+ lines.push(`**Model**: \`${model}\`${agentSuffix}`);
66
+ }
67
+ else if (agent) {
68
+ lines.push(`**Agent**: ${agent}`);
69
+ }
70
+ if (lines.length > 0)
71
+ lines.push('');
72
+ // Session guidance based on type and findings
73
+ if (parallelForced) {
74
+ // parallel=true and same role already has a running dispatch → force new session
75
+ lines.push(`**Session**: 该角色已有运行中的 dispatch,强制启动新会话(parallel 模式)`);
76
+ lines.push('');
77
+ lines.push(`**Action**: ${agentDesc}。`);
78
+ }
79
+ else if (idleSession) {
80
+ const agentId = idleSession.agentSessionId
81
+ ? `Agent session ID: \`${idleSession.agentSessionId}\``
82
+ : 'Agent session ID: not recorded';
83
+ const label = idleSession.label ? ` (${idleSession.label})` : '';
84
+ lines.push(`**Reusable session found**: ${idleSession.id}${label}`);
85
+ lines.push(`- ${agentId}`);
86
+ lines.push(`- Agent type: ${idleSession.agentType ?? 'unknown'}`);
87
+ lines.push(`- Last active: ${idleSession.lastActiveAt}`);
88
+ lines.push('');
89
+ if (sessionType === 'persistent') {
90
+ lines.push(`**Action**: 复用已有会话,而非启动新 agent。`);
91
+ lines.push(idleSession.agentSessionId
92
+ ? `使用 \`--resume ${idleSession.agentSessionId}\` 或 \`--session ${idleSession.agentSessionId}\` 恢复会话。`
93
+ : `注意: 该会话未记录 agent session ID,可能需要${agentDesc}。`);
94
+ }
95
+ else {
96
+ // optional — suggestion, not directive
97
+ lines.push(`**Suggestion**: 存在空闲会话,可复用也可启动新会话,由你决定。`);
98
+ if (idleSession.agentSessionId) {
99
+ lines.push(`如需复用: \`--resume ${idleSession.agentSessionId}\` 或 \`--session ${idleSession.agentSessionId}\``);
100
+ }
101
+ }
102
+ }
103
+ else {
104
+ // No idle session found (or session type is 'none')
105
+ if (sessionType === 'none') {
106
+ lines.push(`**Session**: 每次 dispatch 启动全新会话(session: none)`);
107
+ }
108
+ else {
109
+ lines.push(`**未找到可复用会话**`);
110
+ lines.push(`Session type: ${sessionType}`);
111
+ }
112
+ lines.push('');
113
+ lines.push(`**Action**: ${agentDesc}。`);
114
+ }
115
+ return lines.join('\n');
116
+ }
117
+ /**
118
+ * Get file extension from artifact definition format.
119
+ * - 'html' → '.html'
120
+ * - 'json' → '.json'
121
+ * - 'md' or undefined → '.md'
122
+ */
123
+ export function getFormatExtension(format) {
124
+ switch (format) {
125
+ case 'html':
126
+ return '.html';
127
+ case 'json':
128
+ return '.json';
129
+ default:
130
+ return '.md';
131
+ }
132
+ }
133
+ /**
134
+ * Resolve an artifact ID to a name + path reference.
135
+ *
136
+ * - Managed artifacts: resolves to full file path via format → extension mapping
137
+ * - Unmanaged artifacts: resolves to the output directory
138
+ * - Unknown artifacts: returns not-found
139
+ */
140
+ export function resolveInputReference(artifactId, wf, ioCtx, existingArtifacts) {
141
+ const artifactDef = wf.artifactDefinitions[artifactId];
142
+ if (!artifactDef) {
143
+ return {
144
+ id: artifactId,
145
+ name: artifactId,
146
+ path: '',
147
+ found: false,
148
+ };
149
+ }
150
+ if (artifactDef.unmanaged) {
151
+ // Unmanaged: resolve to directory
152
+ const dir = resolveArtifactDir(artifactDef.output, ioCtx);
153
+ return {
154
+ id: artifactId,
155
+ name: artifactDef.name,
156
+ path: dir,
157
+ found: true, // unmanaged dirs are always "available"
158
+ };
159
+ }
160
+ // Managed: resolve to full file path via format → extension
161
+ const dir = resolveArtifactDir(artifactDef.output, ioCtx);
162
+ const ext = getFormatExtension(artifactDef.format);
163
+ const filePath = `${dir}/${artifactId}${ext}`;
164
+ return {
165
+ id: artifactId,
166
+ name: artifactDef.name,
167
+ path: filePath,
168
+ found: existingArtifacts.has(artifactId),
169
+ };
170
+ }
171
+ /**
172
+ * Build Artifact Requirements section for the dispatch data package.
173
+ * Only includes schemas for artifacts associated with the dispatched role
174
+ * (via the role's capabilities).
175
+ */
176
+ async function buildArtifactRequirements(wf, workflowsDir, workflowName, role) {
177
+ const artifactDefs = wf.artifactDefinitions;
178
+ // Extract artifact IDs from role capabilities
179
+ const roleDef = wf.roles[role];
180
+ const roleArtifactIds = new Set();
181
+ if (roleDef?.frontmatter.capabilities) {
182
+ for (const cap of roleDef.frontmatter.capabilities) {
183
+ if (cap.artifact) {
184
+ roleArtifactIds.add(cap.artifact);
185
+ }
186
+ }
187
+ }
188
+ // If role has no artifact capabilities, skip
189
+ if (roleArtifactIds.size === 0)
190
+ return '';
191
+ const sections = [];
192
+ for (const artifactId of roleArtifactIds) {
193
+ const artifactDef = artifactDefs[artifactId];
194
+ if (!artifactDef || artifactDef.unmanaged)
195
+ continue;
196
+ // Load main schema
197
+ const schema = await loadArtifactSchema(workflowsDir, workflowName, artifactId);
198
+ // Load step schemas if artifact has steps
199
+ let stepSchemas;
200
+ if (artifactDef.steps && artifactDef.steps.length > 0) {
201
+ stepSchemas = [];
202
+ for (const step of artifactDef.steps) {
203
+ const stepSchema = await loadArtifactSchema(workflowsDir, workflowName, `${artifactId}.${step.id}`);
204
+ stepSchemas.push({ step, schema: stepSchema });
205
+ }
206
+ }
207
+ // Skip if no schema at all
208
+ if (!schema && (!stepSchemas || stepSchemas.every((s) => !s.schema)))
209
+ continue;
210
+ sections.push(formatSchemaGuidance(artifactId, artifactDef, schema, stepSchemas));
211
+ }
212
+ if (sections.length === 0)
213
+ return '';
214
+ return ['## Artifact Requirements', '', ...sections].join('\n');
215
+ }
216
+ export function registerDispatchRole(server, workflowsDir) {
217
+ server.tool('role_dispatch', "Prepare all data needed to dispatch a task to a team member. Returns the role's prompt (with capability overrides), configuration, input artifacts, task brief, and a dispatch tracking ID. Automatically searches for reusable sessions and provides guidance. Does NOT launch agents — you (coordinator) decide how to pass this to the team member. After launching, call dispatch_report to register the session.", {
218
+ project_name: z.string().describe('Project name'),
219
+ role: z.string().describe('Role ID to dispatch (e.g. architect, developer, tester)'),
220
+ task_brief: z
221
+ .string()
222
+ .describe('Task description for the team member — what they need to do, which tasks from the breakdown, specific instructions, etc.'),
223
+ node_id: z
224
+ .string()
225
+ .optional()
226
+ .describe('Target task node ID from the workflow tree. If omitted, automatically finds an active/pending task node for the specified role.'),
227
+ input_artifact_ids: z
228
+ .array(z.string())
229
+ .optional()
230
+ .describe('Supplementary artifact IDs to include as input references (name + path) for the team member. These are merged with the node-level inputArtifacts declaration. Note: only path references are provided, not content.'),
231
+ }, async ({ project_name, role, task_brief, node_id, input_artifact_ids }) => {
232
+ try {
233
+ const ctx = await resolveActive(project_name);
234
+ if (isError(ctx))
235
+ return ctx;
236
+ // Load project state and workflow plugin
237
+ const { wf, state } = await loadWorkflowForContext(workflowsDir, project_name, ctx);
238
+ // Validate role exists
239
+ const roleDef = wf.roles[role];
240
+ if (!roleDef) {
241
+ const available = Object.keys(wf.roles).join(', ');
242
+ return {
243
+ content: [
244
+ {
245
+ type: 'text',
246
+ text: `Role "${role}" not found. Available: ${available}`,
247
+ },
248
+ ],
249
+ isError: true,
250
+ };
251
+ }
252
+ // Resolve target task node
253
+ let targetNode;
254
+ if (node_id) {
255
+ // Explicit node_id — validate it
256
+ targetNode = findTaskNode(wf, node_id);
257
+ if (!targetNode) {
258
+ return {
259
+ content: [
260
+ {
261
+ type: 'text',
262
+ text: `Node "${node_id}" not found or is not a task node in the workflow.`,
263
+ },
264
+ ],
265
+ isError: true,
266
+ };
267
+ }
268
+ if (targetNode.role !== role) {
269
+ return {
270
+ content: [
271
+ {
272
+ type: 'text',
273
+ text: `Node "${node_id}" is assigned to role "${targetNode.role}", not "${role}".`,
274
+ },
275
+ ],
276
+ isError: true,
277
+ };
278
+ }
279
+ // Validate node state allows dispatch
280
+ const nodeState = state.nodes[node_id];
281
+ if (nodeState && nodeState.status !== 'active' && nodeState.status !== 'pending') {
282
+ return {
283
+ content: [
284
+ {
285
+ type: 'text',
286
+ text: `Node "${node_id}" is in status "${nodeState.status}" — cannot dispatch. Only active or pending nodes can be dispatched.`,
287
+ },
288
+ ],
289
+ isError: true,
290
+ };
291
+ }
292
+ }
293
+ else {
294
+ // Auto-find: look for active/pending task nodes for this role
295
+ const candidates = findDispatchableNodes(wf, state, role);
296
+ if (candidates.length === 0) {
297
+ return {
298
+ content: [
299
+ {
300
+ type: 'text',
301
+ text: `No active or pending task nodes found for role "${role}". Check project_status to see the current workflow state.`,
302
+ },
303
+ ],
304
+ isError: true,
305
+ };
306
+ }
307
+ // Prefer active over pending
308
+ targetNode = candidates.find((t) => state.nodes[t.id]?.status === 'active') ?? candidates[0];
309
+ }
310
+ const targetNodeId = targetNode.id;
311
+ // Build I/O context for artifact path resolution
312
+ const ioCtx = {
313
+ contextDir: ctx.dir,
314
+ projectDir: ctx.entry.dir,
315
+ contextLabel: ctx.activeContext,
316
+ };
317
+ // Get merged overrides
318
+ const overrides = await getMergedOverrides(project_name);
319
+ // Build the full prompt with overrides injected
320
+ const overrideSection = buildOverrideSection(role, overrides);
321
+ let fullPrompt = overrideSection ? `${roleDef.prompt}\n${overrideSection}` : roleDef.prompt;
322
+ // Execute beforeDispatch hooks (if defined on the target node)
323
+ const hookInjections = [];
324
+ if (targetNode.beforeDispatch) {
325
+ // Collect static inject text
326
+ if (targetNode.beforeDispatch.inject) {
327
+ hookInjections.push(...targetNode.beforeDispatch.inject);
328
+ }
329
+ // Execute registered actions
330
+ if (targetNode.beforeDispatch.actions && wf.actions) {
331
+ const nodeState = state.nodes[targetNodeId];
332
+ // Resolve loopIteration: find ancestor loop node and read its current iteration
333
+ let loopIteration;
334
+ const ancestorLoopId = findAncestorLoopId(wf.definition.root, targetNodeId);
335
+ if (ancestorLoopId) {
336
+ const loopState = state.nodes[ancestorLoopId];
337
+ if (loopState) {
338
+ loopIteration = loopState.currentIteration;
339
+ }
340
+ }
341
+ const actionCtx = {
342
+ nodeId: targetNodeId,
343
+ role,
344
+ retryCount: nodeState?.retryCount ?? 0,
345
+ projectName: project_name,
346
+ pluginConfig: wf.config,
347
+ workflowState: state,
348
+ artifacts: {
349
+ read: (artifactId) => readArtifact(artifactId, ioCtx, wf.artifactDefinitions[artifactId]),
350
+ list: () => listArtifacts(ioCtx, wf.artifactDefinitions),
351
+ },
352
+ loopIteration,
353
+ };
354
+ for (const actionName of targetNode.beforeDispatch.actions) {
355
+ const handler = wf.actions[actionName];
356
+ if (handler) {
357
+ try {
358
+ const result = await handler(actionCtx);
359
+ if (result.inject) {
360
+ hookInjections.push(...result.inject);
361
+ }
362
+ }
363
+ catch (err) {
364
+ console.warn(`[harmonia] beforeDispatch action "${actionName}" failed:`, err);
365
+ }
366
+ }
367
+ else {
368
+ console.warn(`[harmonia] beforeDispatch action "${actionName}" not registered`);
369
+ }
370
+ }
371
+ }
372
+ }
373
+ // Append hook injections to the role prompt
374
+ if (hookInjections.length > 0) {
375
+ fullPrompt += '\n\n' + hookInjections.join('\n\n');
376
+ }
377
+ // Resolve input artifact references (merge node declaration + coordinator parameter)
378
+ const nodeInputIds = targetNode.inputArtifacts ?? [];
379
+ const paramInputIds = input_artifact_ids ?? [];
380
+ const mergedInputIds = [...new Set([...nodeInputIds, ...paramInputIds])];
381
+ // List existing artifacts for reference resolution
382
+ const existingArtifacts = new Set(await listArtifacts(ioCtx, wf.artifactDefinitions));
383
+ // Resolve all input references
384
+ const inputRefs = mergedInputIds.map((id) => resolveInputReference(id, wf, ioCtx, existingArtifacts));
385
+ const foundRefs = inputRefs.filter((r) => r.found);
386
+ const missingRefs = inputRefs.filter((r) => !r.found);
387
+ // Resolve agent/model: override takes precedence over frontmatter
388
+ const roleConfig = resolveRoleConfig(role, overrides);
389
+ const modelDisplay = roleConfig.model ?? roleDef.frontmatter.model;
390
+ const agentDisplay = roleConfig.agent ?? roleDef.frontmatter.agent;
391
+ const sessionType = roleDef.frontmatter.session;
392
+ // Determine session strategy based on session type + parallel field
393
+ let idleSession = null;
394
+ let parallelForced = false;
395
+ if (sessionType === 'none') {
396
+ // session: none → never look for idle sessions
397
+ idleSession = null;
398
+ }
399
+ else if (roleDef.frontmatter.parallel) {
400
+ // parallel=true → check if same role has running dispatches
401
+ const hasRunning = await hasRunningDispatch(project_name, ctx.number, role, ctx.dir);
402
+ if (hasRunning) {
403
+ // Force new session — don't look for idle ones
404
+ parallelForced = true;
405
+ idleSession = null;
406
+ }
407
+ else {
408
+ // No running dispatch → follow normal session behavior
409
+ idleSession = await findIdleSession(project_name, ctx.number, role, ctx.dir);
410
+ }
411
+ }
412
+ else {
413
+ // session: persistent or optional → look for idle sessions
414
+ idleSession = await findIdleSession(project_name, ctx.number, role, ctx.dir);
415
+ }
416
+ // Create dispatch record
417
+ const dispatch = await createDispatch(project_name, ctx.number, role, task_brief, [], // expectedOutputs — determined dynamically by workflow engine
418
+ idleSession?.id, ctx.dir, targetNodeId);
419
+ // Trigger engine event: dispatch_requested
420
+ const engineResult = await processWorkflowEvent(workflowsDir, project_name, ctx, {
421
+ type: 'dispatch_requested',
422
+ nodeId: targetNodeId,
423
+ });
424
+ const nextActionText = formatNextAction(engineResult.nextAction);
425
+ // Build session guidance (now includes model/agent info — replaces ## Configuration)
426
+ const sessionGuidance = buildSessionGuidance({
427
+ idleSession,
428
+ sessionType,
429
+ model: modelDisplay,
430
+ agent: agentDisplay,
431
+ parallelForced,
432
+ });
433
+ // Build artifact requirements for expected outputs
434
+ const artifactRequirements = await buildArtifactRequirements(wf, workflowsDir, state.workflow, role);
435
+ const summary = [
436
+ `# Dispatch: ${role}`,
437
+ ``,
438
+ `## Dispatch Tracking`,
439
+ `- Dispatch ID: \`${dispatch.id}\``,
440
+ `- Status: ${dispatch.status}`,
441
+ `- Target Node: ${targetNodeId}`,
442
+ ``,
443
+ `## Session Guidance`,
444
+ sessionGuidance,
445
+ ``,
446
+ `## Task Brief`,
447
+ task_brief,
448
+ ``,
449
+ `## Project Context`,
450
+ `- Project: ${project_name}`,
451
+ `- Directory: ${state.projectDir}`,
452
+ `- Workflow: ${state.workflow}`,
453
+ ];
454
+ // Inject unmanaged artifact output path hints
455
+ const unmanagedHints = [];
456
+ for (const cap of roleDef.frontmatter.capabilities ?? []) {
457
+ if (!cap.artifact)
458
+ continue;
459
+ const def = wf.artifactDefinitions[cap.artifact];
460
+ if (!def?.unmanaged)
461
+ continue;
462
+ const outputDir = resolveArtifactDir(def.output, ioCtx);
463
+ unmanagedHints.push(`- **${cap.artifact}** (${def.name}): \`${outputDir}\``);
464
+ }
465
+ if (unmanagedHints.length > 0) {
466
+ summary.push(``, `## Unmanaged Artifact Output Paths`, `以下 artifact 由 agent 直接输出(非 artifact_write),请将产出写入对应路径:`, ...unmanagedHints);
467
+ }
468
+ summary.push(``, `## Input References (${foundRefs.length}${missingRefs.length > 0 ? `, ${missingRefs.length} missing` : ''})`);
469
+ if (foundRefs.length > 0) {
470
+ for (const ref of foundRefs) {
471
+ summary.push(`- **${ref.id}** (${ref.name}): \`${ref.path}\``);
472
+ }
473
+ }
474
+ if (missingRefs.length > 0) {
475
+ summary.push(``, `### Missing`);
476
+ for (const ref of missingRefs) {
477
+ summary.push(`- **${ref.id}** (${ref.name}): 未找到`);
478
+ }
479
+ }
480
+ summary.push(``, `## Next Step`, `After launching the agent, call \`dispatch_report\` with dispatch_id="${dispatch.id}" and the agent's session ID.`, `When the agent finishes, call \`dispatch_report\` again with status="completed" (or "failed").`);
481
+ if (artifactRequirements) {
482
+ summary.push(``, artifactRequirements);
483
+ }
484
+ summary.push(``, `## Role Prompt`, ``, fullPrompt);
485
+ summary.push(nextActionText);
486
+ return {
487
+ content: [
488
+ {
489
+ type: 'text',
490
+ text: summary.join('\n'),
491
+ },
492
+ ],
493
+ };
494
+ }
495
+ catch (err) {
496
+ return {
497
+ content: [
498
+ {
499
+ type: 'text',
500
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
501
+ },
502
+ ],
503
+ isError: true,
504
+ };
505
+ }
506
+ });
507
+ }
508
+ //# sourceMappingURL=role-dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role-dispatch.js","sourceRoot":"","sources":["../../src/tools/role-dispatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Shared utility for tool handlers — resolves the active context (iteration or patch)
3
+ * for a project. All tools that operate on iteration/patch-level data should use this
4
+ * instead of directly reading entry.currentIteration.
5
+ */
6
+ import type { ProjectEntry } from '../core/registry.js';
7
+ import type { OverrideConfig } from '../core/types.js';
8
+ export interface ResolvedContext {
9
+ entry: ProjectEntry;
10
+ /** The iteration or patch number */
11
+ number: number;
12
+ /** "iteration" or "patch" */
13
+ type: 'iteration' | 'patch';
14
+ /** Absolute path to the context directory (iter-N/ or patch-N/) */
15
+ dir: string;
16
+ /** The raw activeContext string, e.g. "iter-1" or "patch-2" */
17
+ activeContext: string;
18
+ }
19
+ type ToolResult = {
20
+ content: {
21
+ type: 'text';
22
+ text: string;
23
+ }[];
24
+ isError?: boolean;
25
+ };
26
+ /**
27
+ * Resolve the active context for a project. Returns either a ResolvedContext
28
+ * or a ToolResult error (to be returned directly from the tool handler).
29
+ */
30
+ export declare function resolveActive(projectName: string): Promise<ResolvedContext | ToolResult>;
31
+ /**
32
+ * Type guard: check if the result is an error (ToolResult) or a resolved context.
33
+ */
34
+ export declare function isError(result: ResolvedContext | ToolResult): result is ToolResult;
35
+ /**
36
+ * Build override instructions to inject into a role prompt.
37
+ * Shared by role-dispatch and get-role-prompt.
38
+ */
39
+ export declare function buildOverrideSection(roleId: string, overrides: OverrideConfig): string;
40
+ export {};
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Shared utility for tool handlers — resolves the active context (iteration or patch)
3
+ * for a project. All tools that operate on iteration/patch-level data should use this
4
+ * instead of directly reading entry.currentIteration.
5
+ */
6
+ import { getProject, resolveContextDir } from '../core/registry.js';
7
+ /**
8
+ * Resolve the active context for a project. Returns either a ResolvedContext
9
+ * or a ToolResult error (to be returned directly from the tool handler).
10
+ */
11
+ export async function resolveActive(projectName) {
12
+ const entry = await getProject(projectName);
13
+ if (!entry) {
14
+ return {
15
+ content: [
16
+ {
17
+ type: 'text',
18
+ text: `项目 "${projectName}" 未注册。请先调用 project_init 注册项目。`,
19
+ },
20
+ ],
21
+ isError: true,
22
+ };
23
+ }
24
+ if (!entry.activeContext) {
25
+ return {
26
+ content: [
27
+ {
28
+ type: 'text',
29
+ text: `项目 "${projectName}" 尚未开始迭代或补丁。请先调用 iteration_start 或 patch_start。`,
30
+ },
31
+ ],
32
+ isError: true,
33
+ };
34
+ }
35
+ const resolved = resolveContextDir(projectName, entry.activeContext);
36
+ if (!resolved) {
37
+ return {
38
+ content: [
39
+ {
40
+ type: 'text',
41
+ text: `项目 "${projectName}" 的 activeContext "${entry.activeContext}" 无法解析。数据可能已损坏。`,
42
+ },
43
+ ],
44
+ isError: true,
45
+ };
46
+ }
47
+ return {
48
+ entry,
49
+ number: resolved.number,
50
+ type: resolved.type,
51
+ dir: resolved.dir,
52
+ activeContext: entry.activeContext,
53
+ };
54
+ }
55
+ /**
56
+ * Type guard: check if the result is an error (ToolResult) or a resolved context.
57
+ */
58
+ export function isError(result) {
59
+ return 'content' in result && !('entry' in result);
60
+ }
61
+ /**
62
+ * Build override instructions to inject into a role prompt.
63
+ * Shared by role-dispatch and get-role-prompt.
64
+ */
65
+ export function buildOverrideSection(roleId, overrides) {
66
+ const roleOverrides = overrides.roles?.[roleId]?.capabilities;
67
+ if (!roleOverrides || Object.keys(roleOverrides).length === 0) {
68
+ return '';
69
+ }
70
+ const lines = [
71
+ '',
72
+ '## Enhanced Capabilities',
73
+ '',
74
+ 'The following capabilities have been configured to use external tools.',
75
+ 'Use the specified tool instead of built-in behavior for these actions.',
76
+ '',
77
+ ];
78
+ for (const [capId, override] of Object.entries(roleOverrides)) {
79
+ const o = override;
80
+ const toolRef = o.type === 'mcp' && o.server
81
+ ? `\`${o.server}\` MCP server's \`${o.tool}\` tool`
82
+ : `\`${o.tool}\` skill tool`;
83
+ let instruction = `- **${capId}**: Use ${toolRef}`;
84
+ if (o.params && Object.keys(o.params).length > 0) {
85
+ const paramStr = Object.entries(o.params)
86
+ .map(([k, v]) => `${k}: ${JSON.stringify(v)}`)
87
+ .join(', ');
88
+ instruction += ` with fixed parameters: ${paramStr}`;
89
+ }
90
+ if (o.notes) {
91
+ instruction += `. Note: ${o.notes}`;
92
+ }
93
+ lines.push(instruction);
94
+ }
95
+ return lines.join('\n');
96
+ }
97
+ //# sourceMappingURL=utils.js.map