@leclabs/agent-flow-navigator-mcp 1.0.0 → 1.1.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 +17 -17
- package/index.js +23 -6
- package/package.json +1 -1
- package/store.js +40 -8
package/README.md
CHANGED
|
@@ -60,34 +60,34 @@ Navigator returns: Step 2 of 8 - "Implement changes"
|
|
|
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
74
|
The primary tool for workflow navigation.
|
|
75
75
|
|
|
76
|
-
| Parameter
|
|
77
|
-
|
|
|
78
|
-
| `workflowType` | string
|
|
79
|
-
| `description`
|
|
80
|
-
| `taskFilePath` | string
|
|
81
|
-
| `result`
|
|
76
|
+
| Parameter | Type | Description |
|
|
77
|
+
| -------------- | -------------------- | --------------------------------------------------------- |
|
|
78
|
+
| `workflowType` | string | Workflow ID (for start only, e.g., "feature-development") |
|
|
79
|
+
| `description` | string | User's task description (for start) |
|
|
80
|
+
| `taskFilePath` | string | Path to task file (for advance/current) |
|
|
81
|
+
| `result` | "passed" \| "failed" | Step result (for advance) |
|
|
82
82
|
|
|
83
83
|
### Diagram
|
|
84
84
|
|
|
85
85
|
Generates a mermaid diagram for visualizing workflow structure.
|
|
86
86
|
|
|
87
|
-
| Parameter
|
|
88
|
-
|
|
|
87
|
+
| Parameter | Type | Description |
|
|
88
|
+
| -------------- | ------ | ----------------------------------- |
|
|
89
89
|
| `workflowType` | string | Workflow ID to visualize (required) |
|
|
90
|
-
| `currentStep`
|
|
90
|
+
| `currentStep` | string | Optional step to highlight |
|
|
91
91
|
|
|
92
92
|
## Architecture Overview
|
|
93
93
|
|
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
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
|
/**
|