@leclabs/agent-flow-navigator-mcp 1.0.0 → 1.2.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/README.md +99 -150
- package/catalog/workflows/build-review-murder-board.json +110 -0
- package/catalog/workflows/build-review-quick.json +108 -0
- package/catalog/workflows/refactor.json +236 -0
- package/copier.js +21 -58
- package/engine.js +16 -2
- package/index.js +23 -6
- package/package.json +2 -2
- package/store.js +40 -8
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A workflow state machine MCP server that navigates agents through DAG-based workflows.
|
|
6
6
|
|
|
7
|
-
Navigator tracks task state and evaluates graph edges
|
|
7
|
+
Navigator tracks task state and evaluates graph edges -- it tells the orchestrator _where to go next_, but doesn't drive. Think of it like a GPS: you tell it where you are and what happened, it tells you where to go.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -39,104 +39,119 @@ Add to your `.mcp.json`:
|
|
|
39
39
|
|
|
40
40
|
Navigator works with the [flow plugin](https://github.com/leclabs/agent-toolkit/tree/main/plugins/flow) to provide structured workflow execution:
|
|
41
41
|
|
|
42
|
-
1. **Initialize workflows**
|
|
43
|
-
2. **Start a task**
|
|
44
|
-
3. **Follow the flow**
|
|
45
|
-
4. **Advance on completion**
|
|
42
|
+
1. **Initialize workflows** -- Copy workflow templates to your project with `CopyWorkflows`
|
|
43
|
+
2. **Start a task** -- Use `Navigate` with a workflow type and description
|
|
44
|
+
3. **Follow the flow** -- Navigator tells you the current step and what to do
|
|
45
|
+
4. **Advance on completion** -- Report `passed` or `failed` to move to the next step
|
|
46
46
|
|
|
47
47
|
```
|
|
48
48
|
User: "Add dark mode support"
|
|
49
49
|
↓
|
|
50
50
|
Navigate(workflowType: "feature-development", description: "Add dark mode support")
|
|
51
51
|
↓
|
|
52
|
-
Navigator returns:
|
|
52
|
+
Navigator returns: currentStep: "parse_requirements", stage: "planning"
|
|
53
53
|
↓
|
|
54
|
-
Agent executes step, then calls Navigate(result: "passed")
|
|
54
|
+
Agent executes step, then calls Navigate(taskFilePath: "...", result: "passed")
|
|
55
55
|
↓
|
|
56
|
-
Navigator returns:
|
|
56
|
+
Navigator returns: currentStep: "explore_codebase", stage: "planning"
|
|
57
57
|
↓
|
|
58
58
|
... continues through workflow ...
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
## MCP Tools Reference
|
|
62
62
|
|
|
63
|
-
| Tool
|
|
64
|
-
|
|
|
65
|
-
| `Navigate`
|
|
66
|
-
| `Diagram`
|
|
67
|
-
| `ListWorkflows`
|
|
68
|
-
| `SelectWorkflow` | Get workflow selection dialog for user interaction
|
|
69
|
-
| `CopyWorkflows`
|
|
70
|
-
| `ListCatalog`
|
|
63
|
+
| Tool | Description |
|
|
64
|
+
| ---------------- | ------------------------------------------------------------ |
|
|
65
|
+
| `Navigate` | Start a workflow, get current state, or advance to next step |
|
|
66
|
+
| `Diagram` | Generate a mermaid flowchart for a workflow |
|
|
67
|
+
| `ListWorkflows` | List all available workflows |
|
|
68
|
+
| `SelectWorkflow` | Get workflow selection dialog for user interaction |
|
|
69
|
+
| `CopyWorkflows` | Copy workflows from catalog to project |
|
|
70
|
+
| `ListCatalog` | List workflows available in the catalog |
|
|
71
71
|
|
|
72
72
|
### Navigate
|
|
73
73
|
|
|
74
|
-
The primary tool
|
|
74
|
+
The primary tool. Operates in 3 modes:
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
|
81
|
-
|
|
|
76
|
+
- **Start**: Pass `workflowType` + `description` to begin a workflow
|
|
77
|
+
- **Current**: Pass `taskFilePath` to get current step state
|
|
78
|
+
- **Advance**: Pass `taskFilePath` + `result` to move to the next step
|
|
79
|
+
|
|
80
|
+
| Parameter | Type | Description |
|
|
81
|
+
| -------------- | -------------------- | --------------------------------------------------------- |
|
|
82
|
+
| `workflowType` | string | Workflow ID (for start only, e.g., "feature-development") |
|
|
83
|
+
| `description` | string | User's task description (for start) |
|
|
84
|
+
| `taskFilePath` | string | Path to task file (for advance/current) |
|
|
85
|
+
| `result` | "passed" \| "failed" | Step result (for advance) |
|
|
82
86
|
|
|
83
87
|
### Diagram
|
|
84
88
|
|
|
85
89
|
Generates a mermaid diagram for visualizing workflow structure.
|
|
86
90
|
|
|
87
|
-
| Parameter
|
|
88
|
-
|
|
|
91
|
+
| Parameter | Type | Description |
|
|
92
|
+
| -------------- | ------ | ----------------------------------- |
|
|
89
93
|
| `workflowType` | string | Workflow ID to visualize (required) |
|
|
90
|
-
| `currentStep`
|
|
94
|
+
| `currentStep` | string | Optional step to highlight |
|
|
95
|
+
|
|
96
|
+
### ListWorkflows
|
|
97
|
+
|
|
98
|
+
Lists available workflows, filterable by source.
|
|
99
|
+
|
|
100
|
+
| Parameter | Type | Description |
|
|
101
|
+
| --------- | ------ | --------------------------------------------------------------------------- |
|
|
102
|
+
| `source` | string | Filter: `"project"`, `"catalog"`, or `"all"`. Defaults to project if exists |
|
|
103
|
+
|
|
104
|
+
### SelectWorkflow
|
|
105
|
+
|
|
106
|
+
Returns a workflow selection dialog for user interaction. No parameters.
|
|
107
|
+
|
|
108
|
+
### CopyWorkflows
|
|
109
|
+
|
|
110
|
+
Copies workflows from catalog to the project's `.flow/workflows/` directory.
|
|
111
|
+
|
|
112
|
+
| Parameter | Type | Description |
|
|
113
|
+
| ------------- | -------- | -------------------------------------- |
|
|
114
|
+
| `workflowIds` | string[] | Workflow IDs to copy. Empty = copy all |
|
|
91
115
|
|
|
92
|
-
|
|
116
|
+
### ListCatalog
|
|
117
|
+
|
|
118
|
+
Lists workflows available in the built-in catalog. No parameters.
|
|
119
|
+
|
|
120
|
+
## Architecture
|
|
93
121
|
|
|
94
122
|
```
|
|
95
|
-
|
|
96
|
-
│
|
|
97
|
-
│ (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
│
|
|
107
|
-
│
|
|
108
|
-
│
|
|
109
|
-
│
|
|
110
|
-
│ │
|
|
111
|
-
│
|
|
112
|
-
│
|
|
113
|
-
│
|
|
114
|
-
│
|
|
115
|
-
|
|
116
|
-
│ │ (Next Step?) │ │ (Pending Syncs) │ │
|
|
117
|
-
│ └──────────────────┘ └──────────────────┘ │
|
|
118
|
-
│ │
|
|
119
|
-
└─────────────────────────┬───────────────────────────────────────────┘
|
|
120
|
-
│
|
|
121
|
-
┌───────────────┼───────────────┐
|
|
122
|
-
│ get_next_tasks│ advance_task │
|
|
123
|
-
│ "What's next?"│ "I got X" │
|
|
124
|
-
▼ ▼ │
|
|
125
|
-
┌─────────────────────────────────────────┴───────────────────────────┐
|
|
126
|
-
│ ORCHESTRATOR │
|
|
127
|
-
│ (Receives directions, executes, persists, confirms syncs) │
|
|
128
|
-
└─────────────────────────────────────────────────────────────────────┘
|
|
123
|
+
┌─────────────────────────────────────────────────┐
|
|
124
|
+
│ ORCHESTRATOR │
|
|
125
|
+
│ (Executes tasks, delegates to subagents) │
|
|
126
|
+
└──────────────────────┬──────────────────────────┘
|
|
127
|
+
│
|
|
128
|
+
Navigate ───────┼─────── Diagram
|
|
129
|
+
ListWorkflows ──┤ CopyWorkflows
|
|
130
|
+
SelectWorkflow ─┤ ListCatalog
|
|
131
|
+
│
|
|
132
|
+
┌──────────────────────┴──────────────────────────┐
|
|
133
|
+
│ NAVIGATOR │
|
|
134
|
+
│ (Workflow State Machine MCP) │
|
|
135
|
+
│ │
|
|
136
|
+
│ ┌──────────────────┐ ┌──────────────────┐ │
|
|
137
|
+
│ │ Workflow Store │ │ Edge Evaluator │ │
|
|
138
|
+
│ │ (Graph Defs) │ │ (Next Step?) │ │
|
|
139
|
+
│ └──────────────────┘ └──────────────────┘ │
|
|
140
|
+
│ │
|
|
141
|
+
│ Write-through: state transitions persist │
|
|
142
|
+
│ atomically to the task file on disk │
|
|
143
|
+
└─────────────────────────────────────────────────┘
|
|
129
144
|
```
|
|
130
145
|
|
|
131
146
|
### Key Concepts
|
|
132
147
|
|
|
133
|
-
| Concept | Description
|
|
134
|
-
| ----------------------- |
|
|
135
|
-
| **Workflow Definition** | A DAG blueprint describing how to execute a type of work (nodes + conditional edges)
|
|
136
|
-
| **
|
|
137
|
-
| **
|
|
138
|
-
| **Conditional Edges** | Edges with `on` condition (passed/failed)
|
|
139
|
-
| **HITL Escalation** | When retries are exhausted, tasks route to end nodes with `escalation: "hitl"`
|
|
148
|
+
| Concept | Description |
|
|
149
|
+
| ----------------------- | ------------------------------------------------------------------------------------- |
|
|
150
|
+
| **Workflow Definition** | A DAG blueprint describing how to execute a type of work (nodes + conditional edges) |
|
|
151
|
+
| **Navigate 3-Mode API** | Start a workflow, get current state, or advance -- one tool, three calling patterns |
|
|
152
|
+
| **Write-Through** | State transitions are persisted to the task file atomically on every advance |
|
|
153
|
+
| **Conditional Edges** | Edges with `on` condition (passed/failed) -- retry logic is on nodes via `maxRetries` |
|
|
154
|
+
| **HITL Escalation** | When retries are exhausted, tasks route to end nodes with `escalation: "hitl"` |
|
|
140
155
|
|
|
141
156
|
## Workflow Definition Schema
|
|
142
157
|
|
|
@@ -159,89 +174,24 @@ Generates a mermaid diagram for visualizing workflow structure.
|
|
|
159
174
|
|
|
160
175
|
### Task/Gate Node Properties
|
|
161
176
|
|
|
162
|
-
| Property | Description
|
|
163
|
-
| ------------ |
|
|
164
|
-
| `name` | Human-readable name (required)
|
|
165
|
-
| `outputs` | Possible outcomes (default: `["passed", "failed"]`)
|
|
166
|
-
| `maxRetries` | Retry count on failure before following "failed" edge
|
|
167
|
-
| `agent` | Agent type to perform this task
|
|
168
|
-
| `stage` | Workflow phase
|
|
177
|
+
| Property | Description |
|
|
178
|
+
| ------------ | -------------------------------------------------------------------- |
|
|
179
|
+
| `name` | Human-readable name (required) |
|
|
180
|
+
| `outputs` | Possible outcomes (default: `["passed", "failed"]`) |
|
|
181
|
+
| `maxRetries` | Retry count on failure before following "failed" edge |
|
|
182
|
+
| `agent` | Agent type to perform this task |
|
|
183
|
+
| `stage` | Workflow phase (e.g., planning, development, verification, delivery) |
|
|
184
|
+
| `metadata` | Arbitrary key-value data for workflow tooling and extensions |
|
|
169
185
|
|
|
170
186
|
### Edge Properties
|
|
171
187
|
|
|
172
|
-
| Property
|
|
173
|
-
|
|
|
174
|
-
| `from`
|
|
175
|
-
| `to`
|
|
176
|
-
| `on`
|
|
177
|
-
| `label`
|
|
178
|
-
|
|
179
|
-
## Advanced Usage
|
|
180
|
-
|
|
181
|
-
### Loading Workflow Definitions
|
|
182
|
-
|
|
183
|
-
```json
|
|
184
|
-
{
|
|
185
|
-
"tool": "load_workflow",
|
|
186
|
-
"arguments": {
|
|
187
|
-
"id": "ui-reconstruction",
|
|
188
|
-
"definition": {
|
|
189
|
-
"nodes": {
|
|
190
|
-
"start": { "type": "start" },
|
|
191
|
-
"analyze": { "type": "task", "name": "Analyze Components" },
|
|
192
|
-
"review": { "type": "gate", "name": "Review Analysis", "maxRetries": 3 },
|
|
193
|
-
"end": { "type": "end", "result": "success" },
|
|
194
|
-
"hitl": { "type": "end", "result": "blocked", "escalation": "hitl" }
|
|
195
|
-
},
|
|
196
|
-
"edges": [
|
|
197
|
-
{ "from": "start", "to": "analyze" },
|
|
198
|
-
{ "from": "analyze", "to": "review" },
|
|
199
|
-
{ "from": "review", "to": "analyze", "on": "failed", "label": "Retry on failure" },
|
|
200
|
-
{ "from": "review", "to": "hitl", "on": "max_retries_exceeded", "label": "Escalate after 3 failures" },
|
|
201
|
-
{ "from": "review", "to": "end", "on": "passed" }
|
|
202
|
-
]
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### Task Tree Management
|
|
209
|
-
|
|
210
|
-
Load a priority queue of tasks:
|
|
211
|
-
|
|
212
|
-
```json
|
|
213
|
-
{
|
|
214
|
-
"tool": "load_task_tree",
|
|
215
|
-
"arguments": {
|
|
216
|
-
"tasks": [
|
|
217
|
-
{
|
|
218
|
-
"id": "task-001",
|
|
219
|
-
"issueId": "ISSUE-042",
|
|
220
|
-
"workflowType": "ui-reconstruction",
|
|
221
|
-
"currentStep": "start",
|
|
222
|
-
"priority": 100,
|
|
223
|
-
"status": "PENDING",
|
|
224
|
-
"context": { "targetUrl": "https://example.com" }
|
|
225
|
-
}
|
|
226
|
-
]
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### Advancing Tasks
|
|
232
|
-
|
|
233
|
-
After executing a task step:
|
|
234
|
-
|
|
235
|
-
```json
|
|
236
|
-
{
|
|
237
|
-
"tool": "advance_task",
|
|
238
|
-
"arguments": {
|
|
239
|
-
"taskId": "task-001",
|
|
240
|
-
"result": "passed",
|
|
241
|
-
"output": "Analysis complete, found 5 components"
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
```
|
|
188
|
+
| Property | Description |
|
|
189
|
+
| ----------- | -------------------------------------------------------------- |
|
|
190
|
+
| `from` | Source node ID |
|
|
191
|
+
| `to` | Target node ID |
|
|
192
|
+
| `on` | Output value that triggers this edge (for conditional routing) |
|
|
193
|
+
| `label` | Human-readable edge description |
|
|
194
|
+
| `condition` | Expression for future conditional routing (informational) |
|
|
245
195
|
|
|
246
196
|
## Testing
|
|
247
197
|
|
|
@@ -253,8 +203,7 @@ npm test
|
|
|
253
203
|
|
|
254
204
|
- [GitHub Repository](https://github.com/leclabs/agent-toolkit)
|
|
255
205
|
- [Flow Plugin](https://github.com/leclabs/agent-toolkit/tree/main/plugins/flow)
|
|
256
|
-
- [Full Documentation](https://github.com/leclabs/agent-toolkit/tree/main/packages/agent-flow-navigator-mcp)
|
|
257
206
|
|
|
258
207
|
## License
|
|
259
208
|
|
|
260
|
-
|
|
209
|
+
ISC
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "build-review-murder-board",
|
|
3
|
+
"name": "Build-Review Murder Board",
|
|
4
|
+
"description": "High-scrutiny iterative build-review loop. A fresh reviewer agent tears apart each build attempt with maximum rigor. Ideal for critical changes requiring independent verification.",
|
|
5
|
+
"nodes": {
|
|
6
|
+
"start": {
|
|
7
|
+
"type": "start",
|
|
8
|
+
"name": "Start",
|
|
9
|
+
"description": "Build-review cycle begins"
|
|
10
|
+
},
|
|
11
|
+
"build": {
|
|
12
|
+
"type": "task",
|
|
13
|
+
"name": "Build",
|
|
14
|
+
"description": "Implement or revise the changes based on requirements or review feedback",
|
|
15
|
+
"agent": "Developer",
|
|
16
|
+
"stage": "development"
|
|
17
|
+
},
|
|
18
|
+
"review": {
|
|
19
|
+
"type": "gate",
|
|
20
|
+
"name": "Murder Board Review",
|
|
21
|
+
"description": "Independent high-scrutiny review. Reviewer must be a fresh agent with no prior context of this build. Approval requires confidence score >= 80.",
|
|
22
|
+
"agent": "Reviewer",
|
|
23
|
+
"stage": "verification",
|
|
24
|
+
"maxRetries": 3,
|
|
25
|
+
"config": {
|
|
26
|
+
"scrutinyLevel": 5,
|
|
27
|
+
"blindShot": true,
|
|
28
|
+
"approvalThreshold": 80
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"lint_format": {
|
|
32
|
+
"type": "gate",
|
|
33
|
+
"name": "Lint & Format",
|
|
34
|
+
"description": "Run lint and format checks. Auto-fix issues where possible.",
|
|
35
|
+
"agent": "Developer",
|
|
36
|
+
"stage": "delivery",
|
|
37
|
+
"maxRetries": 3
|
|
38
|
+
},
|
|
39
|
+
"commit": {
|
|
40
|
+
"type": "task",
|
|
41
|
+
"name": "Commit Changes",
|
|
42
|
+
"description": "Commit all changes with a descriptive message summarizing the work done",
|
|
43
|
+
"agent": "Developer",
|
|
44
|
+
"stage": "delivery"
|
|
45
|
+
},
|
|
46
|
+
"end_success": {
|
|
47
|
+
"type": "end",
|
|
48
|
+
"result": "success",
|
|
49
|
+
"name": "Approved",
|
|
50
|
+
"description": "Build passed murder board review and delivered"
|
|
51
|
+
},
|
|
52
|
+
"hitl_blocked": {
|
|
53
|
+
"type": "end",
|
|
54
|
+
"result": "blocked",
|
|
55
|
+
"escalation": "hitl",
|
|
56
|
+
"name": "Review Blocked",
|
|
57
|
+
"description": "Build failed murder board review after all retries - needs human intervention"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"edges": [
|
|
61
|
+
{
|
|
62
|
+
"from": "start",
|
|
63
|
+
"to": "build"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"from": "build",
|
|
67
|
+
"to": "review"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"from": "review",
|
|
71
|
+
"to": "build",
|
|
72
|
+
"on": "failed",
|
|
73
|
+
"label": "Revise build based on review feedback"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"from": "review",
|
|
77
|
+
"to": "hitl_blocked",
|
|
78
|
+
"on": "failed",
|
|
79
|
+
"label": "Review failures exhausted retries"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"from": "review",
|
|
83
|
+
"to": "lint_format",
|
|
84
|
+
"on": "passed",
|
|
85
|
+
"label": "Review passed, run lint checks"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"from": "lint_format",
|
|
89
|
+
"to": "commit",
|
|
90
|
+
"on": "passed",
|
|
91
|
+
"label": "Lint passes, commit changes"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"from": "lint_format",
|
|
95
|
+
"to": "build",
|
|
96
|
+
"on": "failed",
|
|
97
|
+
"label": "Fix lint/format issues"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"from": "lint_format",
|
|
101
|
+
"to": "hitl_blocked",
|
|
102
|
+
"on": "failed",
|
|
103
|
+
"label": "Lint issues persist"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"from": "commit",
|
|
107
|
+
"to": "end_success"
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "build-review-quick",
|
|
3
|
+
"name": "Build-Review Quick",
|
|
4
|
+
"description": "Low-scrutiny iterative build-review loop. A lightweight review pass ensures basic correctness before delivery. Suited for low-risk or well-understood changes.",
|
|
5
|
+
"nodes": {
|
|
6
|
+
"start": {
|
|
7
|
+
"type": "start",
|
|
8
|
+
"name": "Start",
|
|
9
|
+
"description": "Build-review cycle begins"
|
|
10
|
+
},
|
|
11
|
+
"build": {
|
|
12
|
+
"type": "task",
|
|
13
|
+
"name": "Build",
|
|
14
|
+
"description": "Implement or revise the changes based on requirements or review feedback",
|
|
15
|
+
"agent": "Developer",
|
|
16
|
+
"stage": "development"
|
|
17
|
+
},
|
|
18
|
+
"review": {
|
|
19
|
+
"type": "gate",
|
|
20
|
+
"name": "Quick Review",
|
|
21
|
+
"description": "Lightweight review checking basic correctness and completeness",
|
|
22
|
+
"agent": "Reviewer",
|
|
23
|
+
"stage": "verification",
|
|
24
|
+
"maxRetries": 2,
|
|
25
|
+
"config": {
|
|
26
|
+
"scrutinyLevel": 1
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"lint_format": {
|
|
30
|
+
"type": "gate",
|
|
31
|
+
"name": "Lint & Format",
|
|
32
|
+
"description": "Run lint and format checks. Auto-fix issues where possible.",
|
|
33
|
+
"agent": "Developer",
|
|
34
|
+
"stage": "delivery",
|
|
35
|
+
"maxRetries": 3
|
|
36
|
+
},
|
|
37
|
+
"commit": {
|
|
38
|
+
"type": "task",
|
|
39
|
+
"name": "Commit Changes",
|
|
40
|
+
"description": "Commit all changes with a descriptive message summarizing the work done",
|
|
41
|
+
"agent": "Developer",
|
|
42
|
+
"stage": "delivery"
|
|
43
|
+
},
|
|
44
|
+
"end_success": {
|
|
45
|
+
"type": "end",
|
|
46
|
+
"result": "success",
|
|
47
|
+
"name": "Complete",
|
|
48
|
+
"description": "Build passed review and delivered"
|
|
49
|
+
},
|
|
50
|
+
"hitl_blocked": {
|
|
51
|
+
"type": "end",
|
|
52
|
+
"result": "blocked",
|
|
53
|
+
"escalation": "hitl",
|
|
54
|
+
"name": "Blocked",
|
|
55
|
+
"description": "Build failed review after all retries - needs human intervention"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"edges": [
|
|
59
|
+
{
|
|
60
|
+
"from": "start",
|
|
61
|
+
"to": "build"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"from": "build",
|
|
65
|
+
"to": "review"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"from": "review",
|
|
69
|
+
"to": "build",
|
|
70
|
+
"on": "failed",
|
|
71
|
+
"label": "Revise build based on review feedback"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"from": "review",
|
|
75
|
+
"to": "hitl_blocked",
|
|
76
|
+
"on": "failed",
|
|
77
|
+
"label": "Review failures exhausted retries"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"from": "review",
|
|
81
|
+
"to": "lint_format",
|
|
82
|
+
"on": "passed",
|
|
83
|
+
"label": "Review passed, run lint checks"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"from": "lint_format",
|
|
87
|
+
"to": "commit",
|
|
88
|
+
"on": "passed",
|
|
89
|
+
"label": "Lint passes, commit changes"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"from": "lint_format",
|
|
93
|
+
"to": "build",
|
|
94
|
+
"on": "failed",
|
|
95
|
+
"label": "Fix lint/format issues"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"from": "lint_format",
|
|
99
|
+
"to": "hitl_blocked",
|
|
100
|
+
"on": "failed",
|
|
101
|
+
"label": "Lint issues persist"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"from": "commit",
|
|
105
|
+
"to": "end_success"
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "refactor",
|
|
3
|
+
"name": "Refactor",
|
|
4
|
+
"description": "Transform outdated codebases into modern equivalents using Functional Core / Imperative Shell architecture. Separates pure business logic from side effects.",
|
|
5
|
+
"nodes": {
|
|
6
|
+
"start": {
|
|
7
|
+
"type": "start",
|
|
8
|
+
"name": "Start",
|
|
9
|
+
"description": "Refactoring workflow begins"
|
|
10
|
+
},
|
|
11
|
+
"analyze_structure": {
|
|
12
|
+
"type": "task",
|
|
13
|
+
"name": "Analyze Structure",
|
|
14
|
+
"description": "Map current architecture: modules, dependencies, entry points. Identify coupling and cohesion issues.",
|
|
15
|
+
"agent": "Planner",
|
|
16
|
+
"stage": "analysis"
|
|
17
|
+
},
|
|
18
|
+
"identify_debt": {
|
|
19
|
+
"type": "task",
|
|
20
|
+
"name": "Identify Technical Debt",
|
|
21
|
+
"description": "Find code smells, anti-patterns, outdated practices. Document violations of SOLID, DRY, and separation of concerns.",
|
|
22
|
+
"agent": "Planner",
|
|
23
|
+
"stage": "analysis"
|
|
24
|
+
},
|
|
25
|
+
"classify_components": {
|
|
26
|
+
"type": "task",
|
|
27
|
+
"name": "Classify Components",
|
|
28
|
+
"description": "Categorize code into Functional Core (pure logic, no side effects) vs Imperative Shell (I/O, state, external calls).",
|
|
29
|
+
"agent": "Planner",
|
|
30
|
+
"stage": "analysis"
|
|
31
|
+
},
|
|
32
|
+
"design_refactor": {
|
|
33
|
+
"type": "task",
|
|
34
|
+
"name": "Design Refactor Plan",
|
|
35
|
+
"description": "Create transformation plan: define functional core boundaries, shell interfaces, and migration sequence.",
|
|
36
|
+
"agent": "Planner",
|
|
37
|
+
"stage": "planning"
|
|
38
|
+
},
|
|
39
|
+
"plan_review": {
|
|
40
|
+
"type": "gate",
|
|
41
|
+
"name": "Review Plan",
|
|
42
|
+
"description": "Verify refactor plan maintains behavioral equivalence while achieving architectural goals.",
|
|
43
|
+
"agent": "Reviewer",
|
|
44
|
+
"stage": "planning",
|
|
45
|
+
"maxRetries": 2,
|
|
46
|
+
"config": {
|
|
47
|
+
"scrutinyLevel": 3
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"extract_core": {
|
|
51
|
+
"type": "task",
|
|
52
|
+
"name": "Extract Functional Core",
|
|
53
|
+
"description": "Refactor pure business logic into functional core: no side effects, deterministic, testable in isolation.",
|
|
54
|
+
"agent": "Developer",
|
|
55
|
+
"stage": "development"
|
|
56
|
+
},
|
|
57
|
+
"isolate_shell": {
|
|
58
|
+
"type": "task",
|
|
59
|
+
"name": "Isolate Imperative Shell",
|
|
60
|
+
"description": "Wrap side effects (I/O, state, external services) in thin imperative shell that coordinates functional core.",
|
|
61
|
+
"agent": "Developer",
|
|
62
|
+
"stage": "development"
|
|
63
|
+
},
|
|
64
|
+
"write_tests": {
|
|
65
|
+
"type": "task",
|
|
66
|
+
"name": "Write Tests",
|
|
67
|
+
"description": "Add tests verifying behavioral equivalence. Unit tests for functional core, integration tests for shell.",
|
|
68
|
+
"agent": "Tester",
|
|
69
|
+
"stage": "development"
|
|
70
|
+
},
|
|
71
|
+
"run_tests": {
|
|
72
|
+
"type": "gate",
|
|
73
|
+
"name": "Run Tests",
|
|
74
|
+
"description": "Execute test suite. Verify refactored code produces identical behavior to original.",
|
|
75
|
+
"agent": "Tester",
|
|
76
|
+
"stage": "verification",
|
|
77
|
+
"maxRetries": 3
|
|
78
|
+
},
|
|
79
|
+
"code_review": {
|
|
80
|
+
"type": "gate",
|
|
81
|
+
"name": "Code Review",
|
|
82
|
+
"description": "Review architecture: clean functional/shell separation, no hidden side effects in core, shell is minimal.",
|
|
83
|
+
"agent": "Reviewer",
|
|
84
|
+
"stage": "verification",
|
|
85
|
+
"maxRetries": 2,
|
|
86
|
+
"config": {
|
|
87
|
+
"scrutinyLevel": 3
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"lint_format": {
|
|
91
|
+
"type": "gate",
|
|
92
|
+
"name": "Lint & Format",
|
|
93
|
+
"description": "Run lint and format checks. Auto-fix issues where possible.",
|
|
94
|
+
"agent": "Developer",
|
|
95
|
+
"stage": "delivery",
|
|
96
|
+
"maxRetries": 3
|
|
97
|
+
},
|
|
98
|
+
"commit": {
|
|
99
|
+
"type": "task",
|
|
100
|
+
"name": "Commit Changes",
|
|
101
|
+
"description": "Commit all changes with a descriptive message summarizing the refactoring",
|
|
102
|
+
"agent": "Developer",
|
|
103
|
+
"stage": "delivery"
|
|
104
|
+
},
|
|
105
|
+
"end_success": {
|
|
106
|
+
"type": "end",
|
|
107
|
+
"result": "success",
|
|
108
|
+
"name": "Complete",
|
|
109
|
+
"description": "Refactoring completed successfully"
|
|
110
|
+
},
|
|
111
|
+
"hitl_analysis_failed": {
|
|
112
|
+
"type": "end",
|
|
113
|
+
"result": "blocked",
|
|
114
|
+
"escalation": "hitl",
|
|
115
|
+
"name": "Analysis Blocked",
|
|
116
|
+
"description": "Analysis or planning needs human guidance"
|
|
117
|
+
},
|
|
118
|
+
"hitl_dev_failed": {
|
|
119
|
+
"type": "end",
|
|
120
|
+
"result": "blocked",
|
|
121
|
+
"escalation": "hitl",
|
|
122
|
+
"name": "Development Blocked",
|
|
123
|
+
"description": "Development or verification needs human intervention"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"edges": [
|
|
127
|
+
{
|
|
128
|
+
"from": "start",
|
|
129
|
+
"to": "analyze_structure"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"from": "analyze_structure",
|
|
133
|
+
"to": "identify_debt"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"from": "identify_debt",
|
|
137
|
+
"to": "classify_components"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"from": "classify_components",
|
|
141
|
+
"to": "design_refactor"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"from": "design_refactor",
|
|
145
|
+
"to": "plan_review"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"from": "plan_review",
|
|
149
|
+
"to": "design_refactor",
|
|
150
|
+
"on": "failed",
|
|
151
|
+
"label": "Revise plan based on feedback"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"from": "plan_review",
|
|
155
|
+
"to": "hitl_analysis_failed",
|
|
156
|
+
"on": "failed",
|
|
157
|
+
"label": "Planning exhausted retries"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"from": "plan_review",
|
|
161
|
+
"to": "extract_core",
|
|
162
|
+
"on": "passed",
|
|
163
|
+
"label": "Plan approved, begin refactoring"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"from": "extract_core",
|
|
167
|
+
"to": "isolate_shell"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"from": "isolate_shell",
|
|
171
|
+
"to": "write_tests"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"from": "write_tests",
|
|
175
|
+
"to": "run_tests"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"from": "run_tests",
|
|
179
|
+
"to": "extract_core",
|
|
180
|
+
"on": "failed",
|
|
181
|
+
"label": "Fix failing tests"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"from": "run_tests",
|
|
185
|
+
"to": "hitl_dev_failed",
|
|
186
|
+
"on": "failed",
|
|
187
|
+
"label": "Tests keep failing"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"from": "run_tests",
|
|
191
|
+
"to": "code_review",
|
|
192
|
+
"on": "passed",
|
|
193
|
+
"label": "Tests pass, ready for review"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"from": "code_review",
|
|
197
|
+
"to": "extract_core",
|
|
198
|
+
"on": "failed",
|
|
199
|
+
"label": "Address review feedback"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"from": "code_review",
|
|
203
|
+
"to": "hitl_dev_failed",
|
|
204
|
+
"on": "failed",
|
|
205
|
+
"label": "Review issues persist"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"from": "code_review",
|
|
209
|
+
"to": "lint_format",
|
|
210
|
+
"on": "passed",
|
|
211
|
+
"label": "Code approved, run lint checks"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"from": "lint_format",
|
|
215
|
+
"to": "commit",
|
|
216
|
+
"on": "passed",
|
|
217
|
+
"label": "Lint passes, commit changes"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"from": "lint_format",
|
|
221
|
+
"to": "extract_core",
|
|
222
|
+
"on": "failed",
|
|
223
|
+
"label": "Fix lint/format issues"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"from": "lint_format",
|
|
227
|
+
"to": "hitl_dev_failed",
|
|
228
|
+
"on": "failed",
|
|
229
|
+
"label": "Lint issues persist"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"from": "commit",
|
|
233
|
+
"to": "end_success"
|
|
234
|
+
}
|
|
235
|
+
]
|
|
236
|
+
}
|
package/copier.js
CHANGED
|
@@ -12,78 +12,41 @@
|
|
|
12
12
|
export function generateFlowReadme() {
|
|
13
13
|
return `# Flow Plugin
|
|
14
14
|
|
|
15
|
-
DAG-based workflow orchestration for
|
|
16
|
-
|
|
17
|
-
## Overview
|
|
18
|
-
|
|
19
|
-
Flow provides structured workflows that guide tasks through defined stages (planning → development → verification → delivery). Each step can be delegated to specialized subagents.
|
|
15
|
+
DAG-based workflow orchestration for AI agents.
|
|
20
16
|
|
|
21
17
|
## Quick Start
|
|
22
18
|
|
|
23
|
-
Workflows work immediately from the built-in catalog - no setup required:
|
|
24
|
-
|
|
25
19
|
\`\`\`bash
|
|
26
|
-
#
|
|
27
|
-
/flow:
|
|
20
|
+
# Load the orchestrator at session start
|
|
21
|
+
/flow:prime
|
|
28
22
|
|
|
29
|
-
#
|
|
30
|
-
feat
|
|
31
|
-
bug: Fix login error # → bug-fix workflow
|
|
32
|
-
task: Update config file # → quick-task workflow
|
|
23
|
+
# Create a task using a command
|
|
24
|
+
/flow:feat "add user authentication"
|
|
33
25
|
|
|
34
|
-
#
|
|
35
|
-
/flow:
|
|
26
|
+
# Execute all pending tasks
|
|
27
|
+
/flow:go
|
|
36
28
|
\`\`\`
|
|
37
29
|
|
|
38
30
|
## Commands
|
|
39
31
|
|
|
40
|
-
| Command | Description |
|
|
41
|
-
|
|
42
|
-
| \`/flow:
|
|
43
|
-
| \`/flow:
|
|
44
|
-
| \`/flow:task
|
|
45
|
-
| \`/flow:
|
|
46
|
-
| \`/flow:
|
|
47
|
-
| \`/flow:
|
|
48
|
-
| \`/flow:
|
|
49
|
-
| \`/flow:
|
|
50
|
-
| \`/flow:init\` | Copy workflows to .flow/workflows/ for customization |
|
|
51
|
-
| \`/flow:load\` | Reload workflows after editing .flow/workflows/ |
|
|
52
|
-
|
|
53
|
-
## Available Workflows
|
|
54
|
-
|
|
55
|
-
- **quick-task** - Minimal: understand → execute → verify (best for simple tasks)
|
|
56
|
-
- **agile-task** - Simple: analyze → implement → test → review
|
|
57
|
-
- **feature-development** - Full lifecycle: requirements → planning → implementation → testing → PR
|
|
58
|
-
- **bug-fix** - Bug workflow: reproduce → investigate → fix → verify → PR
|
|
59
|
-
- **test-coverage** - Analyze coverage gaps and write tests
|
|
60
|
-
- **context-optimization** - Optimize agent context and instructions
|
|
61
|
-
- **ui-reconstruction** - Reconstruct UI components from screenshots or designs
|
|
32
|
+
| Command | Workflow | Description |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| \`/flow:feat\` | feature-development | New feature with planning + review |
|
|
35
|
+
| \`/flow:bug\` | bug-fix | Bug investigation and fix |
|
|
36
|
+
| \`/flow:task\` | agile-task | General development task |
|
|
37
|
+
| \`/flow:fix\` | quick-task | Quick fix, minimal ceremony |
|
|
38
|
+
| \`/flow:spec\` | test-coverage | Analyze and improve test coverage |
|
|
39
|
+
| \`/flow:ctx\` | context-optimization | Optimize agent context and prompts |
|
|
40
|
+
| \`/flow:ui\` | ui-reconstruction | Reconstruct UI from reference |
|
|
41
|
+
| \`/flow:go\` | _(runs queue)_ | Execute all pending tasks |
|
|
62
42
|
|
|
63
|
-
|
|
43
|
+
Use \`/flow:task-create "description" <workflow-id>\` for workflows without command shortcuts.
|
|
64
44
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
\`\`\`bash
|
|
68
|
-
# Copy catalog workflows to .flow/workflows/ for editing
|
|
69
|
-
/flow:init
|
|
70
|
-
|
|
71
|
-
# Edit .flow/workflows/{workflow}/workflow.json
|
|
72
|
-
# Then reload
|
|
73
|
-
/flow:load
|
|
74
|
-
\`\`\`
|
|
75
|
-
|
|
76
|
-
**Customization options:**
|
|
77
|
-
- Modify step definitions in workflow.json
|
|
78
|
-
- Add custom \`instructions\` to steps for project-specific guidance
|
|
79
|
-
- Create new workflows by adding new directories
|
|
45
|
+
## Available Workflows
|
|
80
46
|
|
|
81
|
-
|
|
47
|
+
Workflows are defined in \`.flow/workflows/\`. Edit \`workflow.json\` to customize, then run \`/flow:load\` to reload.
|
|
82
48
|
|
|
83
|
-
|
|
84
|
-
2. **Task Metadata** - Workflow state stored in Claude Code task metadata
|
|
85
|
-
3. **Subagent Delegation** - Steps delegated to specialized agents (planner, developer, tester, reviewer)
|
|
86
|
-
4. **Retry Logic** - Failed steps retry with configurable limits, escalate to HITL if exceeded
|
|
49
|
+
See [Flow Plugin docs](https://github.com/leclabs/agent-toolkit/tree/main/plugins/flow) for the full workflow catalog.
|
|
87
50
|
`;
|
|
88
51
|
}
|
|
89
52
|
|
package/engine.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - Edge to end node = escalation (taken if retries exhausted)
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { existsSync, readFileSync } from "fs";
|
|
16
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Read and parse a task file
|
|
@@ -58,6 +58,9 @@ export function getTerminalType(node) {
|
|
|
58
58
|
export function toSubagentRef(agentId) {
|
|
59
59
|
if (!agentId) return null;
|
|
60
60
|
if (agentId.startsWith("@")) return agentId;
|
|
61
|
+
// Namespaced: "org:developer" -> "@org:developer"
|
|
62
|
+
if (agentId.includes(":")) return `@${agentId}`;
|
|
63
|
+
// Simple: "developer" -> "@flow:developer"
|
|
61
64
|
return `@flow:${agentId}`;
|
|
62
65
|
}
|
|
63
66
|
|
|
@@ -454,7 +457,7 @@ export class WorkflowEngine {
|
|
|
454
457
|
action = "advance";
|
|
455
458
|
}
|
|
456
459
|
|
|
457
|
-
|
|
460
|
+
const response = buildNavigateResponse(
|
|
458
461
|
workflowType,
|
|
459
462
|
evaluation.nextStep,
|
|
460
463
|
nextStepDef,
|
|
@@ -463,5 +466,16 @@ export class WorkflowEngine {
|
|
|
463
466
|
retryCount,
|
|
464
467
|
description
|
|
465
468
|
);
|
|
469
|
+
|
|
470
|
+
// Write-through: persist state transition to task file
|
|
471
|
+
if (taskFilePath) {
|
|
472
|
+
const task = readTaskFile(taskFilePath);
|
|
473
|
+
if (task) {
|
|
474
|
+
task.metadata = { ...task.metadata, ...response.metadata };
|
|
475
|
+
writeFileSync(taskFilePath, JSON.stringify(task, null, 2));
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return response;
|
|
466
480
|
}
|
|
467
481
|
}
|
package/index.js
CHANGED
|
@@ -64,7 +64,7 @@ function loadProjectWorkflows(dirPath) {
|
|
|
64
64
|
try {
|
|
65
65
|
const content = JSON.parse(readFileSync(workflowFile, "utf-8"));
|
|
66
66
|
if (validateWorkflow(id, content)) {
|
|
67
|
-
store.loadDefinition(id, content);
|
|
67
|
+
store.loadDefinition(id, content, "project");
|
|
68
68
|
loaded.push(id);
|
|
69
69
|
}
|
|
70
70
|
} catch (e) {
|
|
@@ -90,7 +90,7 @@ function loadCatalogWorkflows(dirPath) {
|
|
|
90
90
|
try {
|
|
91
91
|
const content = JSON.parse(readFileSync(join(dirPath, file), "utf-8"));
|
|
92
92
|
if (validateWorkflow(id, content)) {
|
|
93
|
-
store.loadDefinition(id, content);
|
|
93
|
+
store.loadDefinition(id, content, "catalog");
|
|
94
94
|
loaded.push(id);
|
|
95
95
|
}
|
|
96
96
|
} catch (e) {
|
|
@@ -157,10 +157,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
157
157
|
},
|
|
158
158
|
{
|
|
159
159
|
name: "ListWorkflows",
|
|
160
|
-
description: "List
|
|
160
|
+
description: "List available workflows. Filters by source when project workflows exist.",
|
|
161
161
|
inputSchema: {
|
|
162
162
|
type: "object",
|
|
163
|
-
properties: {
|
|
163
|
+
properties: {
|
|
164
|
+
source: {
|
|
165
|
+
type: "string",
|
|
166
|
+
enum: ["all", "project", "catalog"],
|
|
167
|
+
description: "Filter by source. Default: 'project' if project workflows exist, else 'all'.",
|
|
168
|
+
},
|
|
169
|
+
},
|
|
164
170
|
},
|
|
165
171
|
},
|
|
166
172
|
{
|
|
@@ -228,9 +234,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
228
234
|
}
|
|
229
235
|
|
|
230
236
|
case "ListWorkflows": {
|
|
237
|
+
// Default to project-only if project workflows exist
|
|
238
|
+
const hasProject = store.hasProjectWorkflows();
|
|
239
|
+
const filter = args.source || (hasProject ? "project" : "all");
|
|
240
|
+
const workflows = store.listWorkflows(filter);
|
|
231
241
|
return jsonResponse({
|
|
232
242
|
schemaVersion: 2,
|
|
233
|
-
workflows
|
|
243
|
+
workflows,
|
|
244
|
+
filter,
|
|
245
|
+
hasProjectWorkflows: hasProject,
|
|
246
|
+
hint:
|
|
247
|
+
hasProject && filter === "project"
|
|
248
|
+
? "Showing project workflows. Use source='all' to include catalog."
|
|
249
|
+
: undefined,
|
|
234
250
|
});
|
|
235
251
|
}
|
|
236
252
|
|
|
@@ -245,6 +261,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
245
261
|
throw new Error(`Workflow '${args.workflowType}' not found`);
|
|
246
262
|
}
|
|
247
263
|
|
|
264
|
+
const source = store.getSource(args.workflowType);
|
|
248
265
|
const markdown = generateDiagram(wfDef, args.currentStep);
|
|
249
266
|
|
|
250
267
|
// Save diagram to file
|
|
@@ -254,7 +271,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
254
271
|
const filePath = join(DIAGRAMS_PATH, `${args.workflowType}.md`);
|
|
255
272
|
writeFileSync(filePath, markdown);
|
|
256
273
|
|
|
257
|
-
return jsonResponse({ savedTo: filePath });
|
|
274
|
+
return jsonResponse({ savedTo: filePath, source });
|
|
258
275
|
}
|
|
259
276
|
|
|
260
277
|
case "CopyWorkflows": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leclabs/agent-flow-navigator-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "MCP server that navigates agents through DAG-based workflows",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "leclabs",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"type": "module",
|
|
16
16
|
"scripts": {
|
|
17
17
|
"start": "node index.js",
|
|
18
|
-
"test": "node --test engine.test.js diagram.test.js store.test.js dialog.test.js copier.test.js catalog.test.js"
|
|
18
|
+
"test": "node --test engine.test.js diagram.test.js store.test.js dialog.test.js copier.test.js catalog.test.js refactor-workflow.test.js build-review-workflow.test.js"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
21
|
"mcp",
|
package/store.js
CHANGED
|
@@ -29,16 +29,19 @@ export function validateWorkflow(id, content) {
|
|
|
29
29
|
export class WorkflowStore {
|
|
30
30
|
constructor() {
|
|
31
31
|
this.workflows = new Map();
|
|
32
|
+
this.sources = new Map(); // Track source: "catalog" | "project"
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Load a workflow definition into the store
|
|
36
37
|
* @param {string} id - Workflow identifier
|
|
37
38
|
* @param {Object} workflow - Workflow definition
|
|
39
|
+
* @param {string} source - Source: "catalog" | "project"
|
|
38
40
|
* @returns {string} The workflow id
|
|
39
41
|
*/
|
|
40
|
-
loadDefinition(id, workflow) {
|
|
42
|
+
loadDefinition(id, workflow, source = "catalog") {
|
|
41
43
|
this.workflows.set(id, workflow);
|
|
44
|
+
this.sources.set(id, source);
|
|
42
45
|
return id;
|
|
43
46
|
}
|
|
44
47
|
|
|
@@ -53,15 +56,43 @@ export class WorkflowStore {
|
|
|
53
56
|
|
|
54
57
|
/**
|
|
55
58
|
* List all loaded workflows with metadata
|
|
59
|
+
* @param {string} filter - Filter by source: "all" | "project" | "catalog"
|
|
56
60
|
* @returns {Array} Array of workflow summaries
|
|
57
61
|
*/
|
|
58
|
-
listWorkflows() {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
listWorkflows(filter = "all") {
|
|
63
|
+
const results = [];
|
|
64
|
+
for (const [id, wf] of this.workflows.entries()) {
|
|
65
|
+
const source = this.sources.get(id) || "catalog";
|
|
66
|
+
if (filter !== "all" && source !== filter) continue;
|
|
67
|
+
results.push({
|
|
68
|
+
id,
|
|
69
|
+
name: wf.name || id,
|
|
70
|
+
description: wf.description || "",
|
|
71
|
+
stepCount: Object.keys(wf.nodes || {}).length,
|
|
72
|
+
source,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return results;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Check if any project workflows exist
|
|
80
|
+
* @returns {boolean}
|
|
81
|
+
*/
|
|
82
|
+
hasProjectWorkflows() {
|
|
83
|
+
for (const source of this.sources.values()) {
|
|
84
|
+
if (source === "project") return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get the source of a workflow
|
|
91
|
+
* @param {string} id - Workflow identifier
|
|
92
|
+
* @returns {string|undefined} Source or undefined
|
|
93
|
+
*/
|
|
94
|
+
getSource(id) {
|
|
95
|
+
return this.sources.get(id);
|
|
65
96
|
}
|
|
66
97
|
|
|
67
98
|
/**
|
|
@@ -78,6 +109,7 @@ export class WorkflowStore {
|
|
|
78
109
|
*/
|
|
79
110
|
clear() {
|
|
80
111
|
this.workflows.clear();
|
|
112
|
+
this.sources.clear();
|
|
81
113
|
}
|
|
82
114
|
|
|
83
115
|
/**
|