@pipefy/pipefy-process-coder 0.1.0 → 0.1.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/.agents/skills/ppc-pipefy-flow-authoring/SKILL.md +262 -262
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/01-main-2-danfe-consulta.json +247 -247
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/01-main-2-webhook-retorno-consulta.json +589 -589
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/01-main-4-recebimento-barramento.json +1391 -1391
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/02-subflow-2-danfe-retorno.json +623 -623
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/02-subflow-4-criacao-operacao.json +636 -636
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/03-subflow-4-criacao-titulo.json +3642 -3642
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/04-subflow-4-criacao-cedente.json +863 -863
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/04-subflow-4-criacao-sacado.json +799 -799
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/README.md +42 -42
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/hml-01-subflow-1-titulo-acompanhamento-cobranca.json +581 -581
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/hml-01-subflow-1-titulo-nfe-monitoramento.json +503 -503
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/hml-01-subflow-1-titulo-retorno-bancario.json +562 -562
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/hml-02-subflow-2-retorno-consulta-cedente.json +557 -557
- package/.agents/skills/ppc-pipefy-flow-authoring/examples/hml-02-subflow-2-retorno-consulta-sacado.json +609 -609
- package/.agents/skills/ppc-pipefy-pipe-authoring/SKILL.md +146 -146
- package/.agents/skills/ppc-pipefy-process-design/SKILL.md +127 -127
- package/.agents/skills/ppc-pipefy-workspace/SKILL.md +91 -91
- package/AGENTS.md +465 -456
- package/README.md +825 -807
- package/bin/pipe.js +25 -4
- package/dist/apply/adopt.js +128 -0
- package/dist/apply/agentops.js +42 -0
- package/dist/apply/compile.js +722 -0
- package/dist/apply/execute.js +277 -0
- package/dist/apply/flowops.js +293 -0
- package/dist/apply/idmap.js +233 -0
- package/dist/apply/mutations.js +704 -0
- package/dist/apply/registry.js +348 -0
- package/dist/apply/types.js +18 -0
- package/dist/cli/args.js +79 -0
- package/dist/cli.js +187 -0
- package/dist/codec/flow.js +164 -0
- package/dist/codec/pack.js +88 -0
- package/dist/codec/roundtrip.js +86 -0
- package/dist/codec/unpack.js +181 -0
- package/dist/commands/agents.js +145 -0
- package/dist/commands/apply.js +982 -0
- package/dist/commands/context.js +79 -0
- package/dist/commands/create.js +63 -0
- package/dist/commands/diff.js +294 -0
- package/dist/commands/flows.js +348 -0
- package/dist/commands/misc.js +528 -0
- package/dist/commands/plan.js +301 -0
- package/dist/commands/pull.js +511 -0
- package/dist/commands/runs.js +74 -0
- package/dist/commands/skills.js +131 -0
- package/dist/commands/verify.js +205 -0
- package/dist/config.js +125 -0
- package/dist/diff/agents.js +80 -0
- package/dist/diff/diff.js +983 -0
- package/dist/diff/flow.js +258 -0
- package/{src/diff/html.ts → dist/diff/html.js} +274 -322
- package/dist/diff/render.js +90 -0
- package/dist/model/payload.js +84 -0
- package/dist/model/tree.js +7 -0
- package/dist/model/volatile.js +54 -0
- package/dist/pipefy/agents.js +122 -0
- package/dist/pipefy/automations.js +155 -0
- package/dist/pipefy/capability.js +84 -0
- package/dist/pipefy/client.js +204 -0
- package/dist/pipefy/discovery.js +148 -0
- package/dist/pipefy/internal.js +315 -0
- package/dist/pipefy/ipaas.js +269 -0
- package/dist/pipefy/reconstruct.js +674 -0
- package/dist/pipefy/reference.js +172 -0
- package/dist/pipefy/snapshot.js +185 -0
- package/dist/pipefy/toolkit.js +158 -0
- package/dist/report/integrations.js +165 -0
- package/dist/report/run.js +355 -0
- package/dist/util/fsx.js +50 -0
- package/dist/util/git.js +25 -0
- package/dist/util/json.js +56 -0
- package/dist/util/log.js +69 -0
- package/dist/util/pool.js +42 -0
- package/dist/util/slug.js +23 -0
- package/dist/util/tui.js +287 -0
- package/dist/validate/index.js +86 -0
- package/dist/validate/integrity.js +370 -0
- package/dist/validate/reference.js +120 -0
- package/dist/validate/schema.js +278 -0
- package/dist/workspace/agents.js +245 -0
- package/{src/workspace/docs.ts → dist/workspace/docs.js} +367 -407
- package/dist/workspace/flows.js +149 -0
- package/dist/workspace/layout.js +146 -0
- package/dist/workspace/lock.js +83 -0
- package/dist/workspace/read.js +168 -0
- package/dist/workspace/reference.js +24 -0
- package/dist/workspace/stamp.js +234 -0
- package/dist/workspace/write.js +194 -0
- package/package.json +37 -35
- package/src/apply/adopt.ts +0 -150
- package/src/apply/agentops.ts +0 -71
- package/src/apply/compile.ts +0 -875
- package/src/apply/execute.ts +0 -336
- package/src/apply/flowops.ts +0 -399
- package/src/apply/idmap.ts +0 -241
- package/src/apply/mutations.ts +0 -955
- package/src/apply/registry.ts +0 -430
- package/src/apply/types.ts +0 -134
- package/src/cli/args.ts +0 -88
- package/src/cli.ts +0 -211
- package/src/codec/flow.ts +0 -199
- package/src/codec/pack.ts +0 -103
- package/src/codec/roundtrip.ts +0 -94
- package/src/codec/unpack.ts +0 -198
- package/src/commands/agents.ts +0 -184
- package/src/commands/apply.ts +0 -1144
- package/src/commands/context.ts +0 -119
- package/src/commands/create.ts +0 -79
- package/src/commands/diff.ts +0 -314
- package/src/commands/flows.ts +0 -414
- package/src/commands/misc.ts +0 -644
- package/src/commands/plan.ts +0 -331
- package/src/commands/pull.ts +0 -567
- package/src/commands/runs.ts +0 -83
- package/src/commands/skills.ts +0 -137
- package/src/commands/verify.ts +0 -253
- package/src/config.ts +0 -168
- package/src/diff/agents.ts +0 -122
- package/src/diff/diff.ts +0 -1130
- package/src/diff/flow.ts +0 -318
- package/src/diff/render.ts +0 -101
- package/src/model/payload.ts +0 -154
- package/src/model/tree.ts +0 -99
- package/src/model/volatile.ts +0 -55
- package/src/pipefy/agents.ts +0 -165
- package/src/pipefy/automations.ts +0 -219
- package/src/pipefy/capability.ts +0 -119
- package/src/pipefy/client.ts +0 -267
- package/src/pipefy/discovery.ts +0 -209
- package/src/pipefy/internal.ts +0 -380
- package/src/pipefy/ipaas.ts +0 -365
- package/src/pipefy/reconstruct.ts +0 -775
- package/src/pipefy/reference.ts +0 -251
- package/src/pipefy/snapshot.ts +0 -245
- package/src/pipefy/toolkit.ts +0 -200
- package/src/report/integrations.ts +0 -231
- package/src/report/run.ts +0 -475
- package/src/util/fsx.ts +0 -45
- package/src/util/git.ts +0 -32
- package/src/util/json.ts +0 -55
- package/src/util/log.ts +0 -76
- package/src/util/pool.ts +0 -48
- package/src/util/slug.ts +0 -26
- package/src/util/tui.ts +0 -335
- package/src/validate/index.ts +0 -123
- package/src/validate/integrity.ts +0 -387
- package/src/validate/reference.ts +0 -136
- package/src/validate/schema.ts +0 -328
- package/src/workspace/agents.ts +0 -290
- package/src/workspace/flows.ts +0 -191
- package/src/workspace/layout.ts +0 -165
- package/src/workspace/lock.ts +0 -148
- package/src/workspace/read.ts +0 -165
- package/src/workspace/reference.ts +0 -24
- package/src/workspace/stamp.ts +0 -301
- package/src/workspace/write.ts +0 -225
- /package/{src → dist}/pipefy/toolkit_bearer.py +0 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { canonicalString } from "../util/json.js";
|
|
2
|
+
import { flowIdOf, isNewFlow } from "../workspace/flows.js";
|
|
3
|
+
/**
|
|
4
|
+
* Keys that never carry intent and must not produce a change.
|
|
5
|
+
*
|
|
6
|
+
* `sampleData` is generated by testing a step, `lastUpdatedDate` moves on every
|
|
7
|
+
* write, and the server-minted ids move whenever a version is created. Comparing
|
|
8
|
+
* them would make every flow permanently dirty.
|
|
9
|
+
*/
|
|
10
|
+
const VOLATILE_NODE_KEYS = new Set(['sampleData', 'lastUpdatedDate']);
|
|
11
|
+
const VOLATILE_FLOW_KEYS = new Set([
|
|
12
|
+
'created',
|
|
13
|
+
'updated',
|
|
14
|
+
'publishedVersionId',
|
|
15
|
+
'operationStatus',
|
|
16
|
+
'timeSavedPerRun',
|
|
17
|
+
'createdBy',
|
|
18
|
+
'updatedBy',
|
|
19
|
+
'ownerId',
|
|
20
|
+
'externalId',
|
|
21
|
+
'id',
|
|
22
|
+
'flowId',
|
|
23
|
+
'projectId',
|
|
24
|
+
'templateId',
|
|
25
|
+
'backupFiles',
|
|
26
|
+
/**
|
|
27
|
+
* Derived by the API from the inline `{{connections[...]}}` references rather
|
|
28
|
+
* than supplied, so it is an echo of the nodes and never an intent of its own.
|
|
29
|
+
*/
|
|
30
|
+
'connectionIds',
|
|
31
|
+
'state',
|
|
32
|
+
]);
|
|
33
|
+
const comparableNode = (n) => {
|
|
34
|
+
const out = {};
|
|
35
|
+
for (const [k, v] of Object.entries(n)) {
|
|
36
|
+
if (VOLATILE_NODE_KEYS.has(k))
|
|
37
|
+
continue;
|
|
38
|
+
if (k.startsWith('_'))
|
|
39
|
+
continue; // link metadata is compared separately, as structure
|
|
40
|
+
if (k === 'settings' && v && typeof v === 'object') {
|
|
41
|
+
const s = {};
|
|
42
|
+
for (const [sk, sv] of Object.entries(v)) {
|
|
43
|
+
if (VOLATILE_NODE_KEYS.has(sk))
|
|
44
|
+
continue;
|
|
45
|
+
s[sk] = sv;
|
|
46
|
+
}
|
|
47
|
+
out[k] = s;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
out[k] = v;
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
};
|
|
54
|
+
const nodeDeltas = (before, after) => {
|
|
55
|
+
const a = comparableNode(before);
|
|
56
|
+
const b = comparableNode(after);
|
|
57
|
+
const keys = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort();
|
|
58
|
+
const out = [];
|
|
59
|
+
for (const k of keys) {
|
|
60
|
+
if (canonicalString(a[k]) !== canonicalString(b[k]))
|
|
61
|
+
out.push({ key: k, before: a[k], after: b[k] });
|
|
62
|
+
}
|
|
63
|
+
// Structure: a node whose place in the chain moved is a change even when its
|
|
64
|
+
// settings are identical.
|
|
65
|
+
for (const link of ['_nextAction', '_firstLoopAction', '_children']) {
|
|
66
|
+
if (canonicalString(before[link]) !== canonicalString(after[link])) {
|
|
67
|
+
out.push({ key: link, before: before[link], after: after[link] });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
};
|
|
72
|
+
const flowLabel = (tree) => String(tree.version['displayName'] ?? flowIdOf(tree) ?? 'flow');
|
|
73
|
+
/** Match flows by id, then by display name for one the workspace is creating. */
|
|
74
|
+
const matchFlows = (before, after) => {
|
|
75
|
+
const pairs = [];
|
|
76
|
+
const added = [];
|
|
77
|
+
const removed = [...before];
|
|
78
|
+
for (const a of after) {
|
|
79
|
+
const id = flowIdOf(a);
|
|
80
|
+
let hitAt = id ? removed.findIndex((b) => flowIdOf(b) === id) : -1;
|
|
81
|
+
if (hitAt < 0 && isNewFlow(a)) {
|
|
82
|
+
hitAt = removed.findIndex((b) => flowLabel(b) === flowLabel(a));
|
|
83
|
+
}
|
|
84
|
+
if (hitAt >= 0) {
|
|
85
|
+
pairs.push([removed[hitAt], a]);
|
|
86
|
+
removed.splice(hitAt, 1);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
added.push(a);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { pairs, added, removed };
|
|
93
|
+
};
|
|
94
|
+
export const diffFlows = (before, after) => {
|
|
95
|
+
const changes = [];
|
|
96
|
+
const skipped = [];
|
|
97
|
+
if (!before || !after) {
|
|
98
|
+
return { changes, skipped: [{ reason: 'one side has no flows section, so flows are not diffed' }] };
|
|
99
|
+
}
|
|
100
|
+
if (before.meta.coverage !== 'complete' || after.meta.coverage !== 'complete') {
|
|
101
|
+
/**
|
|
102
|
+
* The whole reason coverage exists. A pipe whose iPaaS could not be reached
|
|
103
|
+
* reports zero flows, and diffing that against a workspace that has some would
|
|
104
|
+
* propose deleting every one of them.
|
|
105
|
+
*/
|
|
106
|
+
return {
|
|
107
|
+
changes,
|
|
108
|
+
skipped: [
|
|
109
|
+
{
|
|
110
|
+
reason: `flows coverage is ${before.meta.coverage}/${after.meta.coverage}, not complete — ` +
|
|
111
|
+
'not diffed, because absence here is not evidence of absence',
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const { pairs, added, removed } = matchFlows(before.flows, after.flows);
|
|
117
|
+
for (const tree of added) {
|
|
118
|
+
changes.push({
|
|
119
|
+
op: 'flow.create',
|
|
120
|
+
key: `flow:new:${flowLabel(tree)}`,
|
|
121
|
+
label: `create flow "${flowLabel(tree)}" (${tree.nodes.length} nodes)`,
|
|
122
|
+
flowId: null,
|
|
123
|
+
flowName: flowLabel(tree),
|
|
124
|
+
afterFlow: tree,
|
|
125
|
+
deltas: [],
|
|
126
|
+
flags: [],
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
for (const tree of removed) {
|
|
130
|
+
changes.push({
|
|
131
|
+
op: 'flow.delete',
|
|
132
|
+
key: `flow:${flowIdOf(tree)}`,
|
|
133
|
+
label: `delete flow "${flowLabel(tree)}"`,
|
|
134
|
+
flowId: flowIdOf(tree),
|
|
135
|
+
flowName: flowLabel(tree),
|
|
136
|
+
beforeFlow: tree,
|
|
137
|
+
deltas: [],
|
|
138
|
+
flags: ['destructive'],
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
for (const [b, a] of pairs) {
|
|
142
|
+
const flowId = flowIdOf(a) ?? flowIdOf(b);
|
|
143
|
+
const name = flowLabel(a);
|
|
144
|
+
if (flowLabel(b) !== flowLabel(a)) {
|
|
145
|
+
changes.push({
|
|
146
|
+
op: 'flow.rename',
|
|
147
|
+
key: `flow:${flowId}:name`,
|
|
148
|
+
label: `rename flow "${flowLabel(b)}" → "${flowLabel(a)}"`,
|
|
149
|
+
flowId,
|
|
150
|
+
flowName: name,
|
|
151
|
+
deltas: [{ key: 'displayName', before: flowLabel(b), after: flowLabel(a) }],
|
|
152
|
+
flags: [],
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (String(b.flow['status'] ?? '') !== String(a.flow['status'] ?? '')) {
|
|
156
|
+
changes.push({
|
|
157
|
+
op: 'flow.status',
|
|
158
|
+
key: `flow:${flowId}:status`,
|
|
159
|
+
label: `flow "${name}" ${b.flow['status']} → ${a.flow['status']}`,
|
|
160
|
+
flowId,
|
|
161
|
+
flowName: name,
|
|
162
|
+
deltas: [{ key: 'status', before: b.flow['status'], after: a.flow['status'] }],
|
|
163
|
+
// Enabling a flow arms it against live traffic. That is never incidental.
|
|
164
|
+
flags: String(a.flow['status']) === 'ENABLED' ? ['arms-flow'] : [],
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const beforeNodes = new Map(b.nodes.map((n) => [n.name, n]));
|
|
168
|
+
const afterNodes = new Map(a.nodes.map((n) => [n.name, n]));
|
|
169
|
+
for (const [nodeName, node] of afterNodes) {
|
|
170
|
+
const prior = beforeNodes.get(nodeName);
|
|
171
|
+
if (!prior) {
|
|
172
|
+
changes.push({
|
|
173
|
+
op: 'node.create',
|
|
174
|
+
key: `flow:${flowId}:node:${nodeName}`,
|
|
175
|
+
label: `flow "${name}": add ${nodeName} [${node.type}] ${String(node['displayName'] ?? '')}`.trim(),
|
|
176
|
+
flowId,
|
|
177
|
+
flowName: name,
|
|
178
|
+
nodeName,
|
|
179
|
+
after: node,
|
|
180
|
+
/**
|
|
181
|
+
* The whole intended tree, not just the node: `ADD_ACTION` needs the
|
|
182
|
+
* parent this node hangs from, and that is a property of where `node`
|
|
183
|
+
* sits in the chain — found by scanning every node's `_nextAction` /
|
|
184
|
+
* `_firstLoopAction` / `_children` for `nodeName` (apply/flowops.ts
|
|
185
|
+
* `parentOf`), the same lookup a brand-new flow's build already uses.
|
|
186
|
+
*/
|
|
187
|
+
afterFlow: a,
|
|
188
|
+
deltas: [],
|
|
189
|
+
flags: [],
|
|
190
|
+
});
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const deltas = nodeDeltas(prior, node);
|
|
194
|
+
if (!deltas.length)
|
|
195
|
+
continue;
|
|
196
|
+
const isTrigger = nodeName === 'trigger';
|
|
197
|
+
changes.push({
|
|
198
|
+
op: isTrigger ? 'trigger.update' : 'node.update',
|
|
199
|
+
key: `flow:${flowId}:node:${nodeName}`,
|
|
200
|
+
label: `flow "${name}": ${isTrigger ? 'trigger' : nodeName} — ${deltas.map((d) => d.key).join(', ')}`,
|
|
201
|
+
flowId,
|
|
202
|
+
flowName: name,
|
|
203
|
+
nodeName,
|
|
204
|
+
before: prior,
|
|
205
|
+
after: node,
|
|
206
|
+
deltas,
|
|
207
|
+
flags: [],
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
for (const [nodeName, node] of beforeNodes) {
|
|
211
|
+
if (afterNodes.has(nodeName))
|
|
212
|
+
continue;
|
|
213
|
+
changes.push({
|
|
214
|
+
op: 'node.delete',
|
|
215
|
+
key: `flow:${flowId}:node:${nodeName}`,
|
|
216
|
+
label: `flow "${name}": delete ${nodeName} [${node.type}]`,
|
|
217
|
+
flowId,
|
|
218
|
+
flowName: name,
|
|
219
|
+
nodeName,
|
|
220
|
+
before: node,
|
|
221
|
+
deltas: [],
|
|
222
|
+
flags: ['destructive'],
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return { changes, skipped };
|
|
227
|
+
};
|
|
228
|
+
export const renderFlowChanges = (cs) => {
|
|
229
|
+
const lines = [];
|
|
230
|
+
for (const s of cs.skipped)
|
|
231
|
+
lines.push(` flows not diffed: ${s.reason}`);
|
|
232
|
+
if (!cs.changes.length) {
|
|
233
|
+
if (!cs.skipped.length)
|
|
234
|
+
lines.push(' flows: no changes');
|
|
235
|
+
return lines.join('\n');
|
|
236
|
+
}
|
|
237
|
+
const byFlow = new Map();
|
|
238
|
+
for (const c of cs.changes) {
|
|
239
|
+
const k = c.flowId ?? `new:${c.flowName}`;
|
|
240
|
+
byFlow.set(k, [...(byFlow.get(k) ?? []), c]);
|
|
241
|
+
}
|
|
242
|
+
for (const [, group] of byFlow) {
|
|
243
|
+
lines.push('');
|
|
244
|
+
lines.push(` ${group[0]?.flowName ?? 'flow'}`);
|
|
245
|
+
for (const c of group) {
|
|
246
|
+
const mark = c.flags.includes('destructive') ? '-' : c.op.endsWith('create') ? '+' : '~';
|
|
247
|
+
lines.push(` ${mark} ${c.label}`);
|
|
248
|
+
for (const d of c.deltas.slice(0, 6)) {
|
|
249
|
+
const short = (v) => {
|
|
250
|
+
const s = canonicalString(v);
|
|
251
|
+
return s.length > 90 ? `${s.slice(0, 90)}…` : s;
|
|
252
|
+
};
|
|
253
|
+
lines.push(` ${d.key}: ${short(d.before)} -> ${short(d.after)}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return lines.join('\n');
|
|
258
|
+
};
|