@leclabs/agent-flow-navigator-mcp 1.2.0 → 1.3.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.
- package/catalog/workflows/agile-task.json +6 -0
- package/catalog/workflows/bug-fix.json +12 -0
- package/catalog/workflows/build-review-murder-board.json +6 -0
- package/catalog/workflows/build-review-quick.json +6 -0
- package/catalog/workflows/context-optimization.json +24 -5
- package/catalog/workflows/feature-development.json +12 -0
- package/catalog/workflows/hitl-test.json +46 -0
- package/catalog/workflows/quick-task.json +6 -0
- package/catalog/workflows/refactor.json +12 -0
- package/catalog/workflows/test-coverage.json +6 -0
- package/catalog/workflows/ui-reconstruction.json +18 -0
- package/engine.js +120 -25
- package/index.js +10 -4
- package/package.json +1 -1
- package/types.d.ts +2 -0
|
@@ -148,6 +148,18 @@
|
|
|
148
148
|
{
|
|
149
149
|
"from": "commit",
|
|
150
150
|
"to": "end_success"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"from": "hitl_cannot_reproduce",
|
|
154
|
+
"to": "reproduce",
|
|
155
|
+
"on": "passed",
|
|
156
|
+
"label": "Human provided reproduction info, resume"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"from": "hitl_fix_failed",
|
|
160
|
+
"to": "write_fix",
|
|
161
|
+
"on": "passed",
|
|
162
|
+
"label": "Human resolved fix issue, resume"
|
|
151
163
|
}
|
|
152
164
|
]
|
|
153
165
|
}
|
|
@@ -61,12 +61,19 @@
|
|
|
61
61
|
"name": "Complete",
|
|
62
62
|
"description": "Context optimization complete"
|
|
63
63
|
},
|
|
64
|
-
"
|
|
64
|
+
"hitl_design_failed": {
|
|
65
65
|
"type": "end",
|
|
66
66
|
"result": "blocked",
|
|
67
67
|
"escalation": "hitl",
|
|
68
|
-
"name": "Needs Help",
|
|
69
|
-
"description": "
|
|
68
|
+
"name": "Design Needs Help",
|
|
69
|
+
"description": "Design optimization needs human guidance"
|
|
70
|
+
},
|
|
71
|
+
"hitl_verify_failed": {
|
|
72
|
+
"type": "end",
|
|
73
|
+
"result": "blocked",
|
|
74
|
+
"escalation": "hitl",
|
|
75
|
+
"name": "Verification Needs Help",
|
|
76
|
+
"description": "Verification needs human intervention"
|
|
70
77
|
}
|
|
71
78
|
},
|
|
72
79
|
"edges": [
|
|
@@ -94,7 +101,7 @@
|
|
|
94
101
|
},
|
|
95
102
|
{
|
|
96
103
|
"from": "review_design",
|
|
97
|
-
"to": "
|
|
104
|
+
"to": "hitl_design_failed",
|
|
98
105
|
"on": "failed",
|
|
99
106
|
"label": "Design needs human input"
|
|
100
107
|
},
|
|
@@ -116,7 +123,7 @@
|
|
|
116
123
|
},
|
|
117
124
|
{
|
|
118
125
|
"from": "verify",
|
|
119
|
-
"to": "
|
|
126
|
+
"to": "hitl_verify_failed",
|
|
120
127
|
"on": "failed",
|
|
121
128
|
"label": "Verification failed"
|
|
122
129
|
},
|
|
@@ -125,6 +132,18 @@
|
|
|
125
132
|
"to": "end_success",
|
|
126
133
|
"on": "passed",
|
|
127
134
|
"label": "Optimization verified"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"from": "hitl_design_failed",
|
|
138
|
+
"to": "design_improvements",
|
|
139
|
+
"on": "passed",
|
|
140
|
+
"label": "Human resolved design issue, resume"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"from": "hitl_verify_failed",
|
|
144
|
+
"to": "implement",
|
|
145
|
+
"on": "passed",
|
|
146
|
+
"label": "Human resolved verification issue, resume"
|
|
128
147
|
}
|
|
129
148
|
]
|
|
130
149
|
}
|
|
@@ -220,6 +220,18 @@
|
|
|
220
220
|
{
|
|
221
221
|
"from": "create_pr",
|
|
222
222
|
"to": "end_success"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"from": "hitl_plan_failed",
|
|
226
|
+
"to": "create_plan",
|
|
227
|
+
"on": "passed",
|
|
228
|
+
"label": "Human resolved planning issue, resume"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"from": "hitl_impl_failed",
|
|
232
|
+
"to": "implement",
|
|
233
|
+
"on": "passed",
|
|
234
|
+
"label": "Human resolved implementation issue, resume"
|
|
223
235
|
}
|
|
224
236
|
]
|
|
225
237
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "hitl-test",
|
|
3
|
+
"name": "HITL Test",
|
|
4
|
+
"description": "Minimal workflow for testing HITL recovery: work, gate, escalate, human resumes.",
|
|
5
|
+
"nodes": {
|
|
6
|
+
"start": {
|
|
7
|
+
"type": "start",
|
|
8
|
+
"name": "Start"
|
|
9
|
+
},
|
|
10
|
+
"work": {
|
|
11
|
+
"type": "task",
|
|
12
|
+
"name": "Do Work",
|
|
13
|
+
"description": "Do the thing",
|
|
14
|
+
"agent": "Developer",
|
|
15
|
+
"stage": "development"
|
|
16
|
+
},
|
|
17
|
+
"check": {
|
|
18
|
+
"type": "gate",
|
|
19
|
+
"name": "Check",
|
|
20
|
+
"description": "Pass or fail",
|
|
21
|
+
"agent": "Reviewer",
|
|
22
|
+
"stage": "verification",
|
|
23
|
+
"maxRetries": 1
|
|
24
|
+
},
|
|
25
|
+
"end_success": {
|
|
26
|
+
"type": "end",
|
|
27
|
+
"result": "success",
|
|
28
|
+
"name": "Done"
|
|
29
|
+
},
|
|
30
|
+
"hitl_blocked": {
|
|
31
|
+
"type": "end",
|
|
32
|
+
"result": "blocked",
|
|
33
|
+
"escalation": "hitl",
|
|
34
|
+
"name": "Blocked",
|
|
35
|
+
"description": "Needs human help"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"edges": [
|
|
39
|
+
{ "from": "start", "to": "work" },
|
|
40
|
+
{ "from": "work", "to": "check" },
|
|
41
|
+
{ "from": "check", "to": "end_success", "on": "passed" },
|
|
42
|
+
{ "from": "check", "to": "work", "on": "failed", "label": "Retry" },
|
|
43
|
+
{ "from": "check", "to": "hitl_blocked", "on": "failed", "label": "Escalate" },
|
|
44
|
+
{ "from": "hitl_blocked", "to": "work", "on": "passed", "label": "Human fixed it, resume" }
|
|
45
|
+
]
|
|
46
|
+
}
|
|
@@ -231,6 +231,18 @@
|
|
|
231
231
|
{
|
|
232
232
|
"from": "commit",
|
|
233
233
|
"to": "end_success"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"from": "hitl_analysis_failed",
|
|
237
|
+
"to": "design_refactor",
|
|
238
|
+
"on": "passed",
|
|
239
|
+
"label": "Human resolved analysis issue, resume"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"from": "hitl_dev_failed",
|
|
243
|
+
"to": "extract_core",
|
|
244
|
+
"on": "passed",
|
|
245
|
+
"label": "Human resolved development issue, resume"
|
|
234
246
|
}
|
|
235
247
|
]
|
|
236
248
|
}
|
|
@@ -236,6 +236,24 @@
|
|
|
236
236
|
{
|
|
237
237
|
"from": "commit",
|
|
238
238
|
"to": "end_success"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"from": "hitl_ir_failed",
|
|
242
|
+
"to": "ir_component_tree",
|
|
243
|
+
"on": "passed",
|
|
244
|
+
"label": "Human resolved IR issue, resume"
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"from": "hitl_build_failed",
|
|
248
|
+
"to": "uiRebuild_build",
|
|
249
|
+
"on": "passed",
|
|
250
|
+
"label": "Human resolved build issue, resume"
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"from": "hitl_final_failed",
|
|
254
|
+
"to": "uiRebuild_build",
|
|
255
|
+
"on": "passed",
|
|
256
|
+
"label": "Human resolved final review issue, resume"
|
|
239
257
|
}
|
|
240
258
|
]
|
|
241
259
|
}
|
package/engine.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
17
|
+
import { join } from "path";
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Read and parse a task file
|
|
@@ -52,16 +53,56 @@ export function getTerminalType(node) {
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
|
-
*
|
|
56
|
-
* e.g.,
|
|
56
|
+
* Return agent ID as-is from workflow definition.
|
|
57
|
+
* Prefixing (e.g., @flow:) is the caller's responsibility.
|
|
57
58
|
*/
|
|
58
59
|
export function toSubagentRef(agentId) {
|
|
59
60
|
if (!agentId) return null;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
return agentId;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Workflow emoji mapping for task subjects
|
|
66
|
+
*/
|
|
67
|
+
const WORKFLOW_EMOJIS = {
|
|
68
|
+
"feature-development": "✨",
|
|
69
|
+
"bug-fix": "🐛",
|
|
70
|
+
"agile-task": "📋",
|
|
71
|
+
"context-optimization": "🔧",
|
|
72
|
+
"quick-task": "⚡",
|
|
73
|
+
"ui-reconstruction": "🎨",
|
|
74
|
+
"test-coverage": "🧪",
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Build formatted task subject for write-through
|
|
79
|
+
*/
|
|
80
|
+
export function buildTaskSubject(taskId, userDescription, workflowType, stepId, subagent, terminal, maxRetries, retryCount) {
|
|
81
|
+
const emoji = WORKFLOW_EMOJIS[workflowType] || "";
|
|
82
|
+
const line1 = `#${taskId} ${userDescription}${emoji ? ` ${emoji}` : ""}`;
|
|
83
|
+
|
|
84
|
+
let line2;
|
|
85
|
+
if (terminal === "success") {
|
|
86
|
+
line2 = `→ ${workflowType} · completed ✓`;
|
|
87
|
+
} else if (terminal === "hitl" || terminal === "failure") {
|
|
88
|
+
line2 = `→ ${workflowType} · ${stepId} · HITL`;
|
|
89
|
+
} else {
|
|
90
|
+
const agent = subagent ? `(${subagent})` : "(direct)";
|
|
91
|
+
const retries = maxRetries > 0 ? ` · retries: ${retryCount}/${maxRetries}` : "";
|
|
92
|
+
line2 = `→ ${workflowType} · ${stepId} ${agent}${retries}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return `${line1}\n${line2}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Build activeForm for task spinner display
|
|
100
|
+
*/
|
|
101
|
+
export function buildTaskActiveForm(stepName, subagent, terminal) {
|
|
102
|
+
if (terminal === "success") return "Completed";
|
|
103
|
+
if (terminal === "hitl" || terminal === "failure") return "HITL - Needs human help";
|
|
104
|
+
const agent = subagent ? ` (${subagent})` : "";
|
|
105
|
+
return `${stepName}${agent}`;
|
|
65
106
|
}
|
|
66
107
|
|
|
67
108
|
/**
|
|
@@ -71,8 +112,13 @@ export function getBaselineInstructions(stepId, stepName) {
|
|
|
71
112
|
const id = stepId.toLowerCase();
|
|
72
113
|
const name = (stepName || "").toLowerCase();
|
|
73
114
|
|
|
74
|
-
//
|
|
75
|
-
if (id.includes("
|
|
115
|
+
// Review steps (checked early — "plan_review" is a review, not a plan)
|
|
116
|
+
if (id.includes("review")) {
|
|
117
|
+
return "Check for correctness, code quality, and adherence to project standards. Verify the implementation meets requirements.";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Analysis/Requirements steps
|
|
121
|
+
if (id.includes("analyze") || id.includes("analysis") || id.includes("parse") || id.includes("requirements") || name.includes("analyze")) {
|
|
76
122
|
return "Review the task requirements carefully. Identify key constraints, dependencies, and acceptance criteria. Create a clear plan before proceeding.";
|
|
77
123
|
}
|
|
78
124
|
if (id.includes("plan") || id.includes("design") || name.includes("plan")) {
|
|
@@ -90,16 +136,16 @@ export function getBaselineInstructions(stepId, stepName) {
|
|
|
90
136
|
return "Improve code structure without changing behavior. Ensure all tests pass before and after changes.";
|
|
91
137
|
}
|
|
92
138
|
|
|
139
|
+
// Lint/format steps
|
|
140
|
+
if (id.includes("lint") || id.includes("format")) {
|
|
141
|
+
return "Run linting and formatting checks. Auto-fix issues where possible. Flag any issues that require manual attention.";
|
|
142
|
+
}
|
|
143
|
+
|
|
93
144
|
// Testing steps
|
|
94
145
|
if (id.includes("test") || id.includes("verify") || id.includes("validate")) {
|
|
95
146
|
return "Verify the implementation works correctly. Test happy paths, edge cases, and error conditions. Document any issues found.";
|
|
96
147
|
}
|
|
97
148
|
|
|
98
|
-
// Review steps
|
|
99
|
-
if (id.includes("review")) {
|
|
100
|
-
return "Check for correctness, code quality, and adherence to project standards. Verify the implementation meets requirements.";
|
|
101
|
-
}
|
|
102
|
-
|
|
103
149
|
// Documentation steps
|
|
104
150
|
if (id.includes("document") || id.includes("readme")) {
|
|
105
151
|
return "Write clear, concise documentation. Focus on what users need to know, not implementation details.";
|
|
@@ -127,18 +173,30 @@ export function getBaselineInstructions(stepId, stepName) {
|
|
|
127
173
|
return "Complete this step thoroughly. Document your findings and any decisions made.";
|
|
128
174
|
}
|
|
129
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Build context loading instructions from step-level context_files.
|
|
178
|
+
* Returns a markdown section or null if no context declared.
|
|
179
|
+
*/
|
|
180
|
+
export function buildContextInstructions({ contextFiles, projectRoot }) {
|
|
181
|
+
if (!contextFiles?.length || !projectRoot) return null;
|
|
182
|
+
const lines = contextFiles.map((file) => `- Read file: ${join(projectRoot, file)}`);
|
|
183
|
+
return `## Context\n\nBefore beginning, load the following:\n${lines.join("\n")}`;
|
|
184
|
+
}
|
|
185
|
+
|
|
130
186
|
/**
|
|
131
187
|
* Build orchestrator instructions for task creation/update
|
|
132
188
|
* Returns null for terminal nodes (no further work)
|
|
133
189
|
*/
|
|
134
|
-
function buildOrchestratorInstructions(workflowType, stepId, stage, subagent, stepInstructions, description) {
|
|
190
|
+
function buildOrchestratorInstructions(workflowType, stepId, stage, subagent, stepInstructions, description, contextBlock) {
|
|
135
191
|
if (!stepInstructions) return null; // Terminal nodes have no instructions
|
|
136
192
|
|
|
137
193
|
const delegationPrefix = subagent ? `Invoke ${subagent} to complete the following task: ` : "";
|
|
138
194
|
|
|
139
|
-
|
|
195
|
+
let result = `${delegationPrefix}${stepInstructions.guidance}
|
|
140
196
|
|
|
141
197
|
${description || "{task description}"}`;
|
|
198
|
+
if (contextBlock) result += `\n\n${contextBlock}`;
|
|
199
|
+
return result;
|
|
142
200
|
}
|
|
143
201
|
|
|
144
202
|
/**
|
|
@@ -152,7 +210,9 @@ function buildNavigateResponse(
|
|
|
152
210
|
action,
|
|
153
211
|
retriesIncremented = false,
|
|
154
212
|
retryCount = 0,
|
|
155
|
-
description = null
|
|
213
|
+
description = null,
|
|
214
|
+
resetRetryCount = false,
|
|
215
|
+
projectRoot = null
|
|
156
216
|
) {
|
|
157
217
|
const stage = stepDef.stage || null;
|
|
158
218
|
const subagent = stepDef.agent ? toSubagentRef(stepDef.agent) : null;
|
|
@@ -167,16 +227,27 @@ function buildNavigateResponse(
|
|
|
167
227
|
guidance: stepDef.instructions || getBaselineInstructions(stepId, stepDef.name),
|
|
168
228
|
};
|
|
169
229
|
|
|
230
|
+
// Build context block from step-level context_files
|
|
231
|
+
const contextBlock = isTerminal
|
|
232
|
+
? null
|
|
233
|
+
: buildContextInstructions({ contextFiles: stepDef.context_files, projectRoot });
|
|
234
|
+
|
|
170
235
|
// Build orchestrator instructions for all non-terminal actions
|
|
171
236
|
const orchestratorInstructions = isTerminal
|
|
172
237
|
? null
|
|
173
|
-
: buildOrchestratorInstructions(workflowType, stepId, stage, subagent, stepInstructions, description);
|
|
238
|
+
: buildOrchestratorInstructions(workflowType, stepId, stage, subagent, stepInstructions, description, contextBlock);
|
|
174
239
|
|
|
175
240
|
// Build metadata for task storage
|
|
241
|
+
// Increment on retry, reset on start or explicit forward progress (conditional advance),
|
|
242
|
+
// preserve on unconditional advances within retry loops and escalations
|
|
176
243
|
const metadata = {
|
|
177
244
|
workflowType,
|
|
178
245
|
currentStep: stepId,
|
|
179
|
-
retryCount: retriesIncremented
|
|
246
|
+
retryCount: retriesIncremented
|
|
247
|
+
? retryCount + 1
|
|
248
|
+
: action === "start" || resetRetryCount
|
|
249
|
+
? 0
|
|
250
|
+
: retryCount,
|
|
180
251
|
};
|
|
181
252
|
|
|
182
253
|
return {
|
|
@@ -187,6 +258,7 @@ function buildNavigateResponse(
|
|
|
187
258
|
terminal: getTerminalType(stepDef),
|
|
188
259
|
action,
|
|
189
260
|
retriesIncremented,
|
|
261
|
+
maxRetries: stepDef.maxRetries || 0,
|
|
190
262
|
orchestratorInstructions,
|
|
191
263
|
metadata,
|
|
192
264
|
};
|
|
@@ -357,7 +429,7 @@ export class WorkflowEngine {
|
|
|
357
429
|
* @param {string} [options.description] - User's task description
|
|
358
430
|
* @returns {Object} Navigation response with currentStep, stepInstructions, terminal, action, metadata, etc.
|
|
359
431
|
*/
|
|
360
|
-
navigate({ taskFilePath, workflowType, result, description } = {}) {
|
|
432
|
+
navigate({ taskFilePath, workflowType, result, description, projectRoot } = {}) {
|
|
361
433
|
let currentStep = null;
|
|
362
434
|
let retryCount = 0;
|
|
363
435
|
|
|
@@ -417,7 +489,7 @@ export class WorkflowEngine {
|
|
|
417
489
|
throw new Error(`First step '${firstEdge.to}' not found in workflow`);
|
|
418
490
|
}
|
|
419
491
|
|
|
420
|
-
return buildNavigateResponse(workflowType, firstEdge.to, firstStepDef, "start", false, 0, description);
|
|
492
|
+
return buildNavigateResponse(workflowType, firstEdge.to, firstStepDef, "start", false, 0, description, false, projectRoot);
|
|
421
493
|
}
|
|
422
494
|
|
|
423
495
|
// Case 2: currentStep but no result - return current state
|
|
@@ -427,7 +499,7 @@ export class WorkflowEngine {
|
|
|
427
499
|
throw new Error(`Step '${currentStep}' not found in workflow '${workflowType}'`);
|
|
428
500
|
}
|
|
429
501
|
|
|
430
|
-
return buildNavigateResponse(workflowType, currentStep, stepDef, "current", false, retryCount, description);
|
|
502
|
+
return buildNavigateResponse(workflowType, currentStep, stepDef, "current", false, retryCount, description, false, projectRoot);
|
|
431
503
|
}
|
|
432
504
|
|
|
433
505
|
// Case 3: currentStep and result - advance to next step
|
|
@@ -447,9 +519,13 @@ export class WorkflowEngine {
|
|
|
447
519
|
}
|
|
448
520
|
|
|
449
521
|
// Determine action and whether retries incremented
|
|
522
|
+
const currentStepDef = nodes[currentStep];
|
|
523
|
+
const isHitlResume = getTerminalType(currentStepDef) === "hitl";
|
|
450
524
|
const isRetry = evaluation.action === "retry";
|
|
451
525
|
let action;
|
|
452
|
-
if (
|
|
526
|
+
if (isHitlResume) {
|
|
527
|
+
action = "advance"; // Human fixed it → fresh advance, retryCount resets
|
|
528
|
+
} else if (isRetry) {
|
|
453
529
|
action = "retry";
|
|
454
530
|
} else if (getTerminalType(nextStepDef) === "hitl") {
|
|
455
531
|
action = "escalate";
|
|
@@ -457,6 +533,10 @@ export class WorkflowEngine {
|
|
|
457
533
|
action = "advance";
|
|
458
534
|
}
|
|
459
535
|
|
|
536
|
+
// Only reset retryCount on genuine forward progress (conditional edge like on:"passed")
|
|
537
|
+
// Unconditional advances within retry loops (e.g., work → gate) preserve the count
|
|
538
|
+
const resetRetryCount = action === "advance" && evaluation.action === "conditional";
|
|
539
|
+
|
|
460
540
|
const response = buildNavigateResponse(
|
|
461
541
|
workflowType,
|
|
462
542
|
evaluation.nextStep,
|
|
@@ -464,14 +544,29 @@ export class WorkflowEngine {
|
|
|
464
544
|
action,
|
|
465
545
|
isRetry,
|
|
466
546
|
retryCount,
|
|
467
|
-
description
|
|
547
|
+
description,
|
|
548
|
+
resetRetryCount,
|
|
549
|
+
projectRoot
|
|
468
550
|
);
|
|
469
551
|
|
|
470
|
-
// Write-through: persist state transition to task file
|
|
552
|
+
// Write-through: persist state transition and presentation to task file
|
|
471
553
|
if (taskFilePath) {
|
|
472
554
|
const task = readTaskFile(taskFilePath);
|
|
473
555
|
if (task) {
|
|
556
|
+
const userDesc = task.metadata?.userDescription || "";
|
|
474
557
|
task.metadata = { ...task.metadata, ...response.metadata };
|
|
558
|
+
task.subject = buildTaskSubject(
|
|
559
|
+
task.id, userDesc, response.metadata.workflowType,
|
|
560
|
+
response.currentStep, response.subagent, response.terminal,
|
|
561
|
+
response.maxRetries, response.metadata.retryCount
|
|
562
|
+
);
|
|
563
|
+
task.activeForm = buildTaskActiveForm(
|
|
564
|
+
response.stepInstructions?.name || response.currentStep,
|
|
565
|
+
response.subagent, response.terminal
|
|
566
|
+
);
|
|
567
|
+
if (response.orchestratorInstructions) {
|
|
568
|
+
task.description = response.orchestratorInstructions;
|
|
569
|
+
}
|
|
475
570
|
writeFileSync(taskFilePath, JSON.stringify(task, null, 2));
|
|
476
571
|
}
|
|
477
572
|
}
|
package/index.js
CHANGED
|
@@ -186,6 +186,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
186
186
|
properties: {
|
|
187
187
|
workflowType: { type: "string", description: "Workflow ID to visualize" },
|
|
188
188
|
currentStep: { type: "string", description: "Optional: highlight this step" },
|
|
189
|
+
filePath: {
|
|
190
|
+
type: "string",
|
|
191
|
+
description: "Optional: absolute path to save the diagram. Defaults to .flow/diagrams/{workflowType}.md",
|
|
192
|
+
},
|
|
189
193
|
},
|
|
190
194
|
required: ["workflowType"],
|
|
191
195
|
},
|
|
@@ -229,6 +233,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
229
233
|
workflowType: args.workflowType,
|
|
230
234
|
result: args.result,
|
|
231
235
|
description: args.description,
|
|
236
|
+
projectRoot: PROJECT_ROOT,
|
|
232
237
|
});
|
|
233
238
|
return jsonResponse(result);
|
|
234
239
|
}
|
|
@@ -264,11 +269,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
264
269
|
const source = store.getSource(args.workflowType);
|
|
265
270
|
const markdown = generateDiagram(wfDef, args.currentStep);
|
|
266
271
|
|
|
267
|
-
// Save diagram to file
|
|
268
|
-
|
|
269
|
-
|
|
272
|
+
// Save diagram to file (use provided path or default)
|
|
273
|
+
const filePath = args.filePath || join(DIAGRAMS_PATH, `${args.workflowType}.md`);
|
|
274
|
+
const fileDir = dirname(filePath);
|
|
275
|
+
if (!existsSync(fileDir)) {
|
|
276
|
+
mkdirSync(fileDir, { recursive: true });
|
|
270
277
|
}
|
|
271
|
-
const filePath = join(DIAGRAMS_PATH, `${args.workflowType}.md`);
|
|
272
278
|
writeFileSync(filePath, markdown);
|
|
273
279
|
|
|
274
280
|
return jsonResponse({ savedTo: filePath, source });
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -51,6 +51,7 @@ export interface TaskNode {
|
|
|
51
51
|
outputs?: string[];
|
|
52
52
|
maxRetries?: number;
|
|
53
53
|
config?: Record<string, unknown>;
|
|
54
|
+
context_files?: string[];
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
@@ -66,6 +67,7 @@ export interface GateNode {
|
|
|
66
67
|
outputs?: string[];
|
|
67
68
|
maxRetries?: number;
|
|
68
69
|
config?: Record<string, unknown>;
|
|
70
|
+
context_files?: string[];
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
/**
|