flownav 0.2.0 → 0.2.1
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 +4 -1
- package/dist/graph.js +33 -2
- package/dist/viewer.js +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -185,12 +185,15 @@ Tool replies are written for an agent to act on. If a name matches several nodes
|
|
|
185
185
|
$ flownav explain order
|
|
186
186
|
error: "order" matches 5 nodes. Do not guess: ask the user which one they mean. Then use the workflow:node form.
|
|
187
187
|
1. Order intake › Order Webhook [webhook] use: wf-orders:Order Webhook
|
|
188
|
+
Webhook POST /orders (responseNode) · group "Intake" · starts the workflow
|
|
188
189
|
2. Order intake › Is Large Order [if] use: wf-orders:Is Large Order
|
|
190
|
+
IF 1 condition(s) · group "Intake" · after: Normalize
|
|
189
191
|
3. Order intake › Save Order [googleSheets] use: wf-orders:Save Order
|
|
192
|
+
googleSheets: append · group "Intake" · after: Is Large Order
|
|
190
193
|
...
|
|
191
194
|
```
|
|
192
195
|
|
|
193
|
-
If a partial name matches exactly one node, it resolves but the reply starts with a `NOTE:` asking the agent to confirm with the user before changing anything. To search a family of workflows, use `flownav find --match "<part of workflow name>" --name "<part of node name>"` (`--name` searches node names only; `--text` also searches parameters and code). The installed skill tells the agent to stop and ask in these cases. How reliably an agent follows that depends on the agent.
|
|
196
|
+
Each candidate carries one line of context (what the node does, its sticky-note group, and what feeds it or what it plugs into), so the agent can ask a specific question instead of "which one?". Workflow candidates show their trigger types and whether they are active. If a partial name matches exactly one node, it resolves but the reply starts with a `NOTE:` asking the agent to confirm with the user before changing anything. To search a family of workflows, use `flownav find --match "<part of workflow name>" --name "<part of node name>"` (`--name` searches node names only; `--text` also searches parameters and code). The installed skill tells the agent to stop and ask in these cases. How reliably an agent follows that depends on the agent.
|
|
194
197
|
|
|
195
198
|
## Reading code in small pieces
|
|
196
199
|
|
package/dist/graph.js
CHANGED
|
@@ -66,7 +66,14 @@ export class G {
|
|
|
66
66
|
const hits = exact.length ? exact : part;
|
|
67
67
|
if (!hits.length)
|
|
68
68
|
throw new Error(`No workflow matches "${q}". Run flownav_scan to list workflows.`);
|
|
69
|
-
const rows = hits.slice(0, 10).
|
|
69
|
+
const rows = hits.slice(0, 10).flatMap((w, i) => {
|
|
70
|
+
const trig = [...new Set(this.nodesOf(w.id).filter((n) => n.trigger).map((n) => shortType(n.type)))];
|
|
71
|
+
const state = w.active === undefined ? '' : w.active ? ', active' : ', inactive';
|
|
72
|
+
return [
|
|
73
|
+
` ${i + 1}. ${w.name} [id ${w.id}, ${w.nodeCount} nodes${state}]`,
|
|
74
|
+
` ${trig.length ? `started by: ${trig.slice(0, 4).join(', ')}` : 'no trigger of its own'}${w.errorWorkflow ? ' · has an error workflow' : ''}`,
|
|
75
|
+
];
|
|
76
|
+
});
|
|
70
77
|
if (hits.length > 10)
|
|
71
78
|
rows.push(` ... and ${hits.length - 10} more`);
|
|
72
79
|
throw new Error([`"${q}" matches ${hits.length} workflows. ${ASK} Then use its id.`, ...rows,
|
|
@@ -76,8 +83,32 @@ export class G {
|
|
|
76
83
|
resolveNode(q) {
|
|
77
84
|
return this.resolveNodeEx(q).node;
|
|
78
85
|
}
|
|
86
|
+
/** One line of context so the agent can tell candidates apart and ask a sharper question. */
|
|
87
|
+
contextLine(n) {
|
|
88
|
+
const bits = [n.summary];
|
|
89
|
+
if (n.group)
|
|
90
|
+
bits.push(`group "${n.group}"`);
|
|
91
|
+
if (n.disabled)
|
|
92
|
+
bits.push('disabled');
|
|
93
|
+
const names = (ids) => [...new Set(ids.map((id) => this.nodeById.get(id)?.name ?? id))];
|
|
94
|
+
const from = names(this.inE(n.id, ['main', 'capability']).map((e) => e.from));
|
|
95
|
+
const into = names(this.outE(n.id, ['capability']).map((e) => e.to));
|
|
96
|
+
if (n.trigger)
|
|
97
|
+
bits.push('starts the workflow');
|
|
98
|
+
else if (from.length)
|
|
99
|
+
bits.push(`after: ${from.slice(0, 2).join(', ')}${from.length > 2 ? ` (+${from.length - 2})` : ''}`);
|
|
100
|
+
else if (into.length)
|
|
101
|
+
bits.push(`plugs into: ${into.slice(0, 2).join(', ')}`);
|
|
102
|
+
else
|
|
103
|
+
bits.push('not connected to anything');
|
|
104
|
+
const line = bits.join(' · ');
|
|
105
|
+
return line.length > 150 ? `${line.slice(0, 149)}…` : line;
|
|
106
|
+
}
|
|
79
107
|
ambiguousNodes(q, hits) {
|
|
80
|
-
const rows = hits.slice(0, 10).
|
|
108
|
+
const rows = hits.slice(0, 10).flatMap((n, i) => [
|
|
109
|
+
` ${i + 1}. ${this.g.workflows[n.wf]?.name ?? n.wf} › ${n.name} [${shortType(n.type)}] use: ${n.wf}:${n.name}`,
|
|
110
|
+
` ${this.contextLine(n)}`,
|
|
111
|
+
]);
|
|
81
112
|
if (hits.length > 10)
|
|
82
113
|
rows.push(` ... and ${hits.length - 10} more`);
|
|
83
114
|
return [`"${q}" matches ${hits.length} nodes. ${ASK} Then use the workflow:node form.`, ...rows].join('\n');
|
package/dist/viewer.js
CHANGED
|
@@ -126,10 +126,11 @@ aside li button{width:100%;text-align:left;margin:2px 0;border-radius:6px;overfl
|
|
|
126
126
|
<script>
|
|
127
127
|
(function () {
|
|
128
128
|
var D = JSON.parse(document.getElementById('data').textContent);
|
|
129
|
-
var
|
|
129
|
+
var svg = document.getElementById('svg'), vp = document.getElementById('vp'), panel = document.getElementById('panel');
|
|
130
|
+
// The page's own <svg> element already carries the SVG namespace; reuse it for new elements.
|
|
131
|
+
var NS = svg.namespaceURI;
|
|
130
132
|
var NW = 176, NH = 38, COLW = 250, ROWH = 62, PAD = 36, HEAD = 34, GAP = 50;
|
|
131
133
|
var LAYER = { main: 1, capability: 1, calls: 1, on_error: 1, webhook_calls: 1 };
|
|
132
|
-
var svg = document.getElementById('svg'), vp = document.getElementById('vp'), panel = document.getElementById('panel');
|
|
133
134
|
|
|
134
135
|
function el(tag, attrs, parent, text) {
|
|
135
136
|
var e = document.createElementNS(NS, tag);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flownav",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "See what references an n8n node before you rename it. A typed graph of your workflows with a CLI and an MCP server, so AI agents read a few lines instead of the whole workflow JSON.",
|
|
5
5
|
"author": "Omer Turkenits",
|
|
6
6
|
"license": "MIT",
|