@pikku/inspector 0.11.2 → 0.12.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/CHANGELOG.md +36 -1
- package/OPTIMIZATION-PLAN.md +195 -0
- package/dist/add/add-ai-agent.d.ts +2 -0
- package/dist/add/add-ai-agent.js +314 -0
- package/dist/add/add-channel.js +81 -61
- package/dist/add/add-cli.d.ts +1 -1
- package/dist/add/add-cli.js +42 -19
- package/dist/add/add-file-extends-core-type.d.ts +1 -1
- package/dist/add/add-file-with-config.d.ts +1 -1
- package/dist/add/add-file-with-factory.d.ts +1 -1
- package/dist/add/add-file-with-factory.js +2 -0
- package/dist/add/add-functions.d.ts +1 -1
- package/dist/add/add-functions.js +256 -82
- package/dist/add/add-http-route.d.ts +20 -10
- package/dist/add/add-http-route.js +156 -66
- package/dist/add/add-http-routes.d.ts +5 -0
- package/dist/add/add-http-routes.js +160 -0
- package/dist/add/add-keyed-wiring.d.ts +12 -0
- package/dist/add/add-keyed-wiring.js +97 -0
- package/dist/add/add-mcp-prompt.d.ts +1 -1
- package/dist/add/add-mcp-prompt.js +14 -9
- package/dist/add/add-mcp-resource.d.ts +1 -1
- package/dist/add/add-mcp-resource.js +14 -9
- package/dist/add/add-middleware.d.ts +1 -4
- package/dist/add/add-middleware.js +364 -79
- package/dist/add/add-permission.d.ts +1 -1
- package/dist/add/add-permission.js +152 -40
- package/dist/add/add-queue-worker.d.ts +1 -1
- package/dist/add/add-queue-worker.js +18 -12
- package/dist/add/add-rpc-invocations.d.ts +3 -3
- package/dist/add/add-rpc-invocations.js +24 -10
- package/dist/add/add-schedule.d.ts +1 -1
- package/dist/add/add-schedule.js +11 -5
- package/dist/add/add-secret.d.ts +3 -0
- package/dist/add/add-secret.js +82 -0
- package/dist/add/add-trigger.d.ts +2 -0
- package/dist/add/add-trigger.js +87 -0
- package/dist/add/add-variable.d.ts +1 -0
- package/dist/add/add-variable.js +8 -0
- package/dist/add/add-wire-addon.d.ts +7 -0
- package/dist/add/add-wire-addon.js +70 -0
- package/dist/add/add-workflow-graph.d.ts +3 -2
- package/dist/add/add-workflow-graph.js +143 -406
- package/dist/add/add-workflow.d.ts +1 -1
- package/dist/add/add-workflow.js +6 -4
- package/dist/error-codes.d.ts +15 -1
- package/dist/error-codes.js +20 -1
- package/dist/index.d.ts +9 -8
- package/dist/index.js +5 -4
- package/dist/inspector.d.ts +2 -2
- package/dist/inspector.js +95 -15
- package/dist/schema-generator.d.ts +1 -0
- package/dist/schema-generator.js +1 -0
- package/dist/types-map.js +10 -1
- package/dist/types.d.ts +180 -50
- package/dist/utils/compute-required-schemas.d.ts +4 -0
- package/dist/utils/compute-required-schemas.js +40 -0
- package/dist/utils/contract-hashes.d.ts +52 -0
- package/dist/utils/contract-hashes.js +269 -0
- package/dist/utils/custom-types-generator.d.ts +9 -0
- package/dist/utils/custom-types-generator.js +71 -0
- package/dist/utils/detect-schema-vendor.d.ts +22 -0
- package/dist/utils/detect-schema-vendor.js +76 -0
- package/dist/utils/does-type-extend-core-type.d.ts +1 -1
- package/dist/utils/ensure-function-metadata.d.ts +6 -3
- package/dist/utils/ensure-function-metadata.js +220 -6
- package/dist/utils/extract-function-name.d.ts +5 -16
- package/dist/utils/extract-function-name.js +86 -291
- package/dist/utils/extract-services.d.ts +2 -1
- package/dist/utils/extract-services.js +25 -1
- package/dist/utils/filter-inspector-state.d.ts +1 -1
- package/dist/utils/filter-inspector-state.js +107 -23
- package/dist/utils/filter-utils.d.ts +2 -2
- package/dist/utils/get-files-and-methods.d.ts +1 -1
- package/dist/utils/get-property-value.d.ts +6 -1
- package/dist/utils/get-property-value.js +28 -3
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.js +23 -0
- package/dist/utils/middleware.d.ts +9 -32
- package/dist/utils/middleware.js +80 -66
- package/dist/utils/permissions.d.ts +4 -4
- package/dist/utils/permissions.js +10 -10
- package/dist/utils/post-process.d.ts +11 -11
- package/dist/utils/post-process.js +247 -24
- package/dist/utils/resolve-addon-package.d.ts +16 -0
- package/dist/utils/resolve-addon-package.js +34 -0
- package/dist/utils/resolve-function-types.d.ts +6 -0
- package/dist/utils/resolve-function-types.js +29 -0
- package/dist/utils/resolve-identifier.d.ts +10 -0
- package/dist/utils/resolve-identifier.js +36 -0
- package/dist/utils/resolve-versions.d.ts +2 -0
- package/dist/utils/resolve-versions.js +78 -0
- package/dist/utils/schema-generator.d.ts +9 -0
- package/dist/utils/schema-generator.js +209 -0
- package/dist/utils/serialize-inspector-state.d.ts +70 -23
- package/dist/utils/serialize-inspector-state.js +98 -22
- package/dist/utils/serialize-mcp-json.d.ts +2 -0
- package/dist/utils/serialize-mcp-json.js +99 -0
- package/dist/utils/serialize-middleware-groups-meta.d.ts +12 -0
- package/dist/utils/serialize-middleware-groups-meta.js +28 -0
- package/dist/utils/serialize-openapi-json.d.ts +85 -0
- package/dist/utils/serialize-openapi-json.js +151 -0
- package/dist/utils/serialize-permissions-groups-meta.d.ts +6 -0
- package/dist/utils/serialize-permissions-groups-meta.js +31 -0
- package/dist/utils/validate-auth-sessionless.d.ts +3 -0
- package/dist/utils/validate-auth-sessionless.js +14 -0
- package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +34 -102
- package/dist/utils/workflow/dsl/extract-dsl-workflow.d.ts +1 -1
- package/dist/utils/workflow/dsl/extract-dsl-workflow.js +23 -4
- package/dist/utils/workflow/graph/convert-dsl-to-graph.js +12 -10
- package/dist/utils/workflow/graph/finalize-workflow-wires.d.ts +3 -0
- package/dist/utils/workflow/graph/finalize-workflow-wires.js +276 -0
- package/dist/utils/workflow/graph/finalize-workflows.d.ts +2 -0
- package/dist/utils/workflow/graph/finalize-workflows.js +75 -0
- package/dist/utils/workflow/graph/index.d.ts +2 -0
- package/dist/utils/workflow/graph/index.js +2 -0
- package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +0 -8
- package/dist/utils/workflow/graph/serialize-workflow-graph.js +1 -3
- package/dist/utils/workflow/graph/workflow-graph.types.d.ts +53 -79
- package/dist/utils/workflow/graph/workflow-graph.types.js +1 -1
- package/dist/visit.d.ts +1 -1
- package/dist/visit.js +13 -6
- package/package.json +14 -4
- package/src/add/add-ai-agent.ts +468 -0
- package/src/add/add-channel.ts +103 -79
- package/src/add/add-cli.ts +68 -24
- package/src/add/add-file-extends-core-type.ts +1 -1
- package/src/add/add-file-with-config.ts +1 -1
- package/src/add/add-file-with-factory.ts +3 -1
- package/src/add/add-functions.ts +349 -103
- package/src/add/add-http-route.ts +263 -89
- package/src/add/add-http-routes.ts +229 -0
- package/src/add/add-keyed-wiring.ts +151 -0
- package/src/add/add-mcp-prompt.ts +27 -16
- package/src/add/add-mcp-resource.ts +28 -16
- package/src/add/add-middleware.ts +482 -80
- package/src/add/add-permission.ts +199 -40
- package/src/add/add-queue-worker.ts +25 -20
- package/src/add/add-rpc-invocations.ts +28 -11
- package/src/add/add-schedule.ts +17 -12
- package/src/add/add-secret.ts +140 -0
- package/src/add/add-trigger.ts +154 -0
- package/src/add/add-variable.ts +9 -0
- package/src/add/add-wire-addon.ts +80 -0
- package/src/add/add-workflow-graph.ts +180 -522
- package/src/add/add-workflow.ts +7 -6
- package/src/error-codes.ts +25 -1
- package/src/index.ts +23 -13
- package/src/inspector.ts +139 -19
- package/src/schema-generator.ts +1 -0
- package/src/types-map.ts +12 -1
- package/src/types.ts +199 -69
- package/src/utils/compute-required-schemas.ts +48 -0
- package/src/utils/contract-hashes.test.ts +553 -0
- package/src/utils/contract-hashes.ts +386 -0
- package/src/utils/custom-types-generator.ts +88 -0
- package/src/utils/detect-schema-vendor.ts +90 -0
- package/src/utils/does-type-extend-core-type.ts +1 -1
- package/src/utils/ensure-function-metadata.ts +325 -8
- package/src/utils/extract-function-name.ts +101 -351
- package/src/utils/extract-services.ts +35 -2
- package/src/utils/filter-inspector-state.test.ts +37 -25
- package/src/utils/filter-inspector-state.ts +146 -32
- package/src/utils/filter-utils.test.ts +1 -1
- package/src/utils/filter-utils.ts +2 -2
- package/src/utils/get-files-and-methods.ts +1 -1
- package/src/utils/get-property-value.ts +42 -4
- package/src/utils/hash.ts +26 -0
- package/src/utils/middleware.test.ts +204 -0
- package/src/utils/middleware.ts +131 -69
- package/src/utils/permissions.test.ts +35 -12
- package/src/utils/permissions.ts +12 -12
- package/src/utils/post-process.ts +306 -44
- package/src/utils/resolve-addon-package.ts +49 -0
- package/src/utils/resolve-function-types.ts +42 -0
- package/src/utils/resolve-identifier.ts +46 -0
- package/src/utils/resolve-versions.test.ts +249 -0
- package/src/utils/resolve-versions.ts +105 -0
- package/src/utils/schema-generator.ts +329 -0
- package/src/utils/serialize-inspector-state.ts +184 -43
- package/src/utils/serialize-mcp-json.ts +145 -0
- package/src/utils/serialize-middleware-groups-meta.ts +33 -0
- package/src/utils/serialize-openapi-json.ts +277 -0
- package/src/utils/serialize-permissions-groups-meta.ts +35 -0
- package/src/utils/test-data/inspector-state.json +69 -66
- package/src/utils/validate-auth-sessionless.ts +29 -0
- package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +43 -119
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +26 -6
- package/src/utils/workflow/graph/convert-dsl-to-graph.ts +17 -10
- package/src/utils/workflow/graph/finalize-workflow-wires.ts +310 -0
- package/src/utils/workflow/graph/finalize-workflows.ts +100 -0
- package/src/utils/workflow/graph/index.ts +5 -0
- package/src/utils/workflow/graph/serialize-workflow-graph.ts +1 -8
- package/src/utils/workflow/graph/workflow-graph.types.ts +29 -78
- package/src/visit.ts +19 -7
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/add/add-forge-credential.d.ts +0 -8
- package/dist/add/add-forge-credential.js +0 -77
- package/dist/add/add-forge-node.d.ts +0 -7
- package/dist/add/add-forge-node.js +0 -77
- package/dist/add/add-mcp-tool.d.ts +0 -2
- package/dist/add/add-mcp-tool.js +0 -81
- package/dist/utils/extract-service-metadata.d.ts +0 -19
- package/dist/utils/extract-service-metadata.js +0 -244
- package/dist/utils/write-service-metadata.d.ts +0 -13
- package/dist/utils/write-service-metadata.js +0 -37
- package/src/add/add-forge-credential.ts +0 -119
- package/src/add/add-forge-node.ts +0 -132
- package/src/add/add-mcp-tool.ts +0 -141
- package/src/utils/extract-service-metadata.ts +0 -353
- package/src/utils/write-service-metadata.ts +0 -51
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
function makeNodeId(step, index, prefix) {
|
|
2
|
+
if ('stepName' in step && step.stepName) {
|
|
3
|
+
return step.stepName;
|
|
4
|
+
}
|
|
5
|
+
return `${prefix}_${index}`;
|
|
6
|
+
}
|
|
1
7
|
/**
|
|
2
8
|
* Check if a node is a terminal flow (no next step should follow)
|
|
3
9
|
*/
|
|
@@ -41,14 +47,15 @@ function convertInputSource(source) {
|
|
|
41
47
|
* Convert a single DSL step to graph node(s)
|
|
42
48
|
*/
|
|
43
49
|
function convertStepToNode(step, index, steps, nodeIdPrefix = 'step') {
|
|
44
|
-
const nodeId =
|
|
45
|
-
const nextNodeId = index < steps.length - 1
|
|
50
|
+
const nodeId = makeNodeId(step, index, nodeIdPrefix);
|
|
51
|
+
const nextNodeId = index < steps.length - 1
|
|
52
|
+
? makeNodeId(steps[index + 1], index + 1, nodeIdPrefix)
|
|
53
|
+
: undefined;
|
|
46
54
|
switch (step.type) {
|
|
47
55
|
case 'rpc': {
|
|
48
56
|
const node = {
|
|
49
57
|
nodeId,
|
|
50
58
|
rpcName: step.rpcName,
|
|
51
|
-
stepName: step.stepName,
|
|
52
59
|
next: nextNodeId,
|
|
53
60
|
};
|
|
54
61
|
if (step.inputs) {
|
|
@@ -78,7 +85,6 @@ function convertStepToNode(step, index, steps, nodeIdPrefix = 'step') {
|
|
|
78
85
|
const node = {
|
|
79
86
|
nodeId,
|
|
80
87
|
flow: 'sleep',
|
|
81
|
-
stepName: step.stepName,
|
|
82
88
|
duration: step.duration,
|
|
83
89
|
next: nextNodeId,
|
|
84
90
|
};
|
|
@@ -88,7 +94,6 @@ function convertStepToNode(step, index, steps, nodeIdPrefix = 'step') {
|
|
|
88
94
|
const node = {
|
|
89
95
|
nodeId,
|
|
90
96
|
flow: 'inline',
|
|
91
|
-
stepName: step.stepName,
|
|
92
97
|
description: step.description,
|
|
93
98
|
next: nextNodeId,
|
|
94
99
|
};
|
|
@@ -201,7 +206,6 @@ function convertStepToNode(step, index, steps, nodeIdPrefix = 'step') {
|
|
|
201
206
|
const node = {
|
|
202
207
|
nodeId,
|
|
203
208
|
flow: 'fanout',
|
|
204
|
-
stepName: step.stepName,
|
|
205
209
|
sourceVar: step.sourceVar,
|
|
206
210
|
itemVar: step.itemVar,
|
|
207
211
|
mode: step.mode,
|
|
@@ -286,20 +290,18 @@ export function convertDslToGraph(workflowName, meta) {
|
|
|
286
290
|
for (const node of nodes) {
|
|
287
291
|
nodesRecord[node.nodeId] = node;
|
|
288
292
|
}
|
|
289
|
-
|
|
290
|
-
const entryNodeIds = nodes.length > 0 ? ['step_0'] : [];
|
|
293
|
+
const entryNodeIds = nodes.length > 0 ? [nodes[0].nodeId] : [];
|
|
291
294
|
// Determine source type based on dsl flag:
|
|
292
295
|
// - dsl === true: pure DSL workflow, can be serialized
|
|
293
296
|
// - dsl === false: complex workflow with inline steps, not serializable
|
|
294
297
|
const source = meta.dsl === false ? 'complex' : 'dsl';
|
|
295
298
|
return {
|
|
296
299
|
name: workflowName,
|
|
297
|
-
|
|
300
|
+
pikkuFuncId: meta.pikkuFuncId,
|
|
298
301
|
source,
|
|
299
302
|
description: meta.description,
|
|
300
303
|
tags: meta.tags,
|
|
301
304
|
context: meta.context,
|
|
302
|
-
wires: {}, // DSL workflows don't have explicit wires in meta
|
|
303
305
|
nodes: nodesRecord,
|
|
304
306
|
entryNodeIds,
|
|
305
307
|
};
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
function parseWorkflowFuncId(pikkuFuncId) {
|
|
2
|
+
for (const prefix of ['workflowStart:', 'workflow:']) {
|
|
3
|
+
if (pikkuFuncId.startsWith(prefix)) {
|
|
4
|
+
return { workflowName: pikkuFuncId.slice(prefix.length) };
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
if (pikkuFuncId.startsWith('graphStart:')) {
|
|
8
|
+
const rest = pikkuFuncId.slice('graphStart:'.length);
|
|
9
|
+
const colonIdx = rest.indexOf(':');
|
|
10
|
+
if (colonIdx !== -1) {
|
|
11
|
+
return {
|
|
12
|
+
workflowName: rest.slice(0, colonIdx),
|
|
13
|
+
startNode: rest.slice(colonIdx + 1),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
function resolveStartNode(parsed, graph) {
|
|
20
|
+
return parsed.startNode ?? graph.entryNodeIds[0];
|
|
21
|
+
}
|
|
22
|
+
function getOrCreateWires(graph) {
|
|
23
|
+
if (!graph.wires) {
|
|
24
|
+
graph.wires = {};
|
|
25
|
+
}
|
|
26
|
+
return graph.wires;
|
|
27
|
+
}
|
|
28
|
+
export function finalizeWorkflowHelperTypes(state) {
|
|
29
|
+
const { functions, workflows } = state;
|
|
30
|
+
const graphMeta = workflows.graphMeta;
|
|
31
|
+
for (const meta of Object.values(functions.meta)) {
|
|
32
|
+
if (meta.functionType !== 'helper')
|
|
33
|
+
continue;
|
|
34
|
+
if (meta.pikkuFuncId.startsWith('workflowStatus:'))
|
|
35
|
+
continue;
|
|
36
|
+
const parsed = parseWorkflowFuncId(meta.pikkuFuncId);
|
|
37
|
+
if (!parsed)
|
|
38
|
+
continue;
|
|
39
|
+
const graph = graphMeta[parsed.workflowName];
|
|
40
|
+
if (!graph)
|
|
41
|
+
continue;
|
|
42
|
+
const startNodeId = resolveStartNode(parsed, graph);
|
|
43
|
+
const startNode = graph.nodes[startNodeId];
|
|
44
|
+
if (!startNode || !('rpcName' in startNode))
|
|
45
|
+
continue;
|
|
46
|
+
const rpcMeta = functions.meta[startNode.rpcName];
|
|
47
|
+
if (!rpcMeta)
|
|
48
|
+
continue;
|
|
49
|
+
if (rpcMeta.inputSchemaName) {
|
|
50
|
+
meta.inputSchemaName = rpcMeta.inputSchemaName;
|
|
51
|
+
}
|
|
52
|
+
if (rpcMeta.inputs && rpcMeta.inputs.length > 0) {
|
|
53
|
+
meta.inputs = rpcMeta.inputs;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function finalizeWorkflowWires(state) {
|
|
58
|
+
const { workflows } = state;
|
|
59
|
+
const graphMeta = workflows.graphMeta;
|
|
60
|
+
scanHTTP(state, graphMeta);
|
|
61
|
+
scanScheduledTasks(state, graphMeta);
|
|
62
|
+
scanTriggers(state, graphMeta);
|
|
63
|
+
scanQueueWorkers(state, graphMeta);
|
|
64
|
+
scanChannels(state, graphMeta);
|
|
65
|
+
scanMCPEndpoints(state, graphMeta);
|
|
66
|
+
scanCLI(state, graphMeta);
|
|
67
|
+
}
|
|
68
|
+
function scanHTTP(state, graphMeta) {
|
|
69
|
+
for (const [method, routes] of Object.entries(state.http.meta)) {
|
|
70
|
+
for (const [route, meta] of Object.entries(routes)) {
|
|
71
|
+
const parsed = parseWorkflowFuncId(meta.pikkuFuncId);
|
|
72
|
+
if (!parsed)
|
|
73
|
+
continue;
|
|
74
|
+
const graph = graphMeta[parsed.workflowName];
|
|
75
|
+
if (!graph)
|
|
76
|
+
continue;
|
|
77
|
+
const wires = getOrCreateWires(graph);
|
|
78
|
+
if (!wires.http)
|
|
79
|
+
wires.http = [];
|
|
80
|
+
wires.http.push({
|
|
81
|
+
route,
|
|
82
|
+
method,
|
|
83
|
+
startNode: resolveStartNode(parsed, graph),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function scanScheduledTasks(state, graphMeta) {
|
|
89
|
+
for (const meta of Object.values(state.scheduledTasks.meta)) {
|
|
90
|
+
const parsed = parseWorkflowFuncId(meta.pikkuFuncId);
|
|
91
|
+
if (!parsed)
|
|
92
|
+
continue;
|
|
93
|
+
const graph = graphMeta[parsed.workflowName];
|
|
94
|
+
if (!graph)
|
|
95
|
+
continue;
|
|
96
|
+
const wires = getOrCreateWires(graph);
|
|
97
|
+
if (!wires.schedule)
|
|
98
|
+
wires.schedule = [];
|
|
99
|
+
wires.schedule.push({
|
|
100
|
+
cron: meta.schedule,
|
|
101
|
+
startNode: resolveStartNode(parsed, graph),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function scanTriggers(state, graphMeta) {
|
|
106
|
+
for (const meta of Object.values(state.triggers.meta)) {
|
|
107
|
+
const parsed = parseWorkflowFuncId(meta.pikkuFuncId);
|
|
108
|
+
if (!parsed)
|
|
109
|
+
continue;
|
|
110
|
+
const graph = graphMeta[parsed.workflowName];
|
|
111
|
+
if (!graph)
|
|
112
|
+
continue;
|
|
113
|
+
const wires = getOrCreateWires(graph);
|
|
114
|
+
if (!wires.trigger)
|
|
115
|
+
wires.trigger = [];
|
|
116
|
+
wires.trigger.push({
|
|
117
|
+
name: meta.name,
|
|
118
|
+
startNode: resolveStartNode(parsed, graph),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function scanQueueWorkers(state, graphMeta) {
|
|
123
|
+
for (const meta of Object.values(state.queueWorkers.meta)) {
|
|
124
|
+
const parsed = parseWorkflowFuncId(meta.pikkuFuncId);
|
|
125
|
+
if (!parsed)
|
|
126
|
+
continue;
|
|
127
|
+
const graph = graphMeta[parsed.workflowName];
|
|
128
|
+
if (!graph)
|
|
129
|
+
continue;
|
|
130
|
+
const wires = getOrCreateWires(graph);
|
|
131
|
+
if (!wires.queue)
|
|
132
|
+
wires.queue = [];
|
|
133
|
+
wires.queue.push({
|
|
134
|
+
name: meta.name,
|
|
135
|
+
startNode: resolveStartNode(parsed, graph),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function scanChannels(state, graphMeta) {
|
|
140
|
+
for (const channelMeta of Object.values(state.channels.meta)) {
|
|
141
|
+
const wire = {
|
|
142
|
+
name: channelMeta.name,
|
|
143
|
+
route: channelMeta.route,
|
|
144
|
+
};
|
|
145
|
+
let targetWorkflow;
|
|
146
|
+
if (channelMeta.connect) {
|
|
147
|
+
const parsed = parseWorkflowFuncId(channelMeta.connect.pikkuFuncId);
|
|
148
|
+
if (parsed) {
|
|
149
|
+
const graph = graphMeta[parsed.workflowName];
|
|
150
|
+
if (graph) {
|
|
151
|
+
targetWorkflow = graph;
|
|
152
|
+
wire.onConnect = resolveStartNode(parsed, graph);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (channelMeta.disconnect) {
|
|
157
|
+
const parsed = parseWorkflowFuncId(channelMeta.disconnect.pikkuFuncId);
|
|
158
|
+
if (parsed) {
|
|
159
|
+
const graph = graphMeta[parsed.workflowName];
|
|
160
|
+
if (graph) {
|
|
161
|
+
targetWorkflow = targetWorkflow ?? graph;
|
|
162
|
+
wire.onDisconnect = resolveStartNode(parsed, graph);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (channelMeta.message) {
|
|
167
|
+
const parsed = parseWorkflowFuncId(channelMeta.message.pikkuFuncId);
|
|
168
|
+
if (parsed) {
|
|
169
|
+
const graph = graphMeta[parsed.workflowName];
|
|
170
|
+
if (graph) {
|
|
171
|
+
targetWorkflow = targetWorkflow ?? graph;
|
|
172
|
+
wire.onMessage = resolveStartNode(parsed, graph);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
for (const [routingProp, routeMap] of Object.entries(channelMeta.messageWirings)) {
|
|
177
|
+
for (const [routeValue, messageMeta] of Object.entries(routeMap)) {
|
|
178
|
+
const parsed = parseWorkflowFuncId(messageMeta.pikkuFuncId);
|
|
179
|
+
if (!parsed)
|
|
180
|
+
continue;
|
|
181
|
+
const graph = graphMeta[parsed.workflowName];
|
|
182
|
+
if (!graph)
|
|
183
|
+
continue;
|
|
184
|
+
targetWorkflow = targetWorkflow ?? graph;
|
|
185
|
+
if (!wire.onMessageRoute)
|
|
186
|
+
wire.onMessageRoute = {};
|
|
187
|
+
wire.onMessageRoute[`${routingProp}:${routeValue}`] = resolveStartNode(parsed, graph);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (targetWorkflow) {
|
|
191
|
+
const wires = getOrCreateWires(targetWorkflow);
|
|
192
|
+
if (!wires.channel)
|
|
193
|
+
wires.channel = [];
|
|
194
|
+
wires.channel.push(wire);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function scanMCPEndpoints(state, graphMeta) {
|
|
199
|
+
for (const meta of Object.values(state.mcpEndpoints.toolsMeta)) {
|
|
200
|
+
const parsed = parseWorkflowFuncId(meta.pikkuFuncId);
|
|
201
|
+
if (!parsed)
|
|
202
|
+
continue;
|
|
203
|
+
const graph = graphMeta[parsed.workflowName];
|
|
204
|
+
if (!graph)
|
|
205
|
+
continue;
|
|
206
|
+
const wires = getOrCreateWires(graph);
|
|
207
|
+
if (!wires.mcp)
|
|
208
|
+
wires.mcp = {};
|
|
209
|
+
if (!wires.mcp.tool)
|
|
210
|
+
wires.mcp.tool = [];
|
|
211
|
+
wires.mcp.tool.push({
|
|
212
|
+
name: meta.name,
|
|
213
|
+
startNode: resolveStartNode(parsed, graph),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
for (const meta of Object.values(state.mcpEndpoints.promptsMeta)) {
|
|
217
|
+
const parsed = parseWorkflowFuncId(meta.pikkuFuncId);
|
|
218
|
+
if (!parsed)
|
|
219
|
+
continue;
|
|
220
|
+
const graph = graphMeta[parsed.workflowName];
|
|
221
|
+
if (!graph)
|
|
222
|
+
continue;
|
|
223
|
+
const wires = getOrCreateWires(graph);
|
|
224
|
+
if (!wires.mcp)
|
|
225
|
+
wires.mcp = {};
|
|
226
|
+
if (!wires.mcp.prompt)
|
|
227
|
+
wires.mcp.prompt = [];
|
|
228
|
+
wires.mcp.prompt.push({
|
|
229
|
+
name: meta.name,
|
|
230
|
+
startNode: resolveStartNode(parsed, graph),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
for (const meta of Object.values(state.mcpEndpoints.resourcesMeta)) {
|
|
234
|
+
const parsed = parseWorkflowFuncId(meta.pikkuFuncId);
|
|
235
|
+
if (!parsed)
|
|
236
|
+
continue;
|
|
237
|
+
const graph = graphMeta[parsed.workflowName];
|
|
238
|
+
if (!graph)
|
|
239
|
+
continue;
|
|
240
|
+
const wires = getOrCreateWires(graph);
|
|
241
|
+
if (!wires.mcp)
|
|
242
|
+
wires.mcp = {};
|
|
243
|
+
if (!wires.mcp.resource)
|
|
244
|
+
wires.mcp.resource = [];
|
|
245
|
+
wires.mcp.resource.push({
|
|
246
|
+
uri: meta.uri,
|
|
247
|
+
startNode: resolveStartNode(parsed, graph),
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function visitCLICommands(commands, programName, path, graphMeta) {
|
|
252
|
+
for (const [name, command] of Object.entries(commands)) {
|
|
253
|
+
const currentPath = [...path, name];
|
|
254
|
+
const parsed = parseWorkflowFuncId(command.pikkuFuncId);
|
|
255
|
+
if (parsed) {
|
|
256
|
+
const graph = graphMeta[parsed.workflowName];
|
|
257
|
+
if (graph) {
|
|
258
|
+
const wires = getOrCreateWires(graph);
|
|
259
|
+
if (!wires.cli)
|
|
260
|
+
wires.cli = [];
|
|
261
|
+
wires.cli.push({
|
|
262
|
+
command: `${programName} ${currentPath.join(' ')}`,
|
|
263
|
+
startNode: resolveStartNode(parsed, graph),
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (command.subcommands) {
|
|
268
|
+
visitCLICommands(command.subcommands, programName, currentPath, graphMeta);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function scanCLI(state, graphMeta) {
|
|
273
|
+
for (const program of Object.values(state.cli.meta.programs)) {
|
|
274
|
+
visitCLICommands(program.commands, program.program, [], graphMeta);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { isVersionedId, formatVersionedId, parseVersionedId } from '@pikku/core';
|
|
2
|
+
import { canonicalJSON, hashString } from '../../hash.js';
|
|
3
|
+
import { convertDslToGraph } from './convert-dsl-to-graph.js';
|
|
4
|
+
export function finalizeWorkflows(state) {
|
|
5
|
+
const { workflows, functions } = state;
|
|
6
|
+
const functionsMeta = functions.meta;
|
|
7
|
+
for (const [name, meta] of Object.entries(workflows.meta)) {
|
|
8
|
+
const graph = convertDslToGraph(name, meta);
|
|
9
|
+
stampVersionsOnGraph(graph, functionsMeta);
|
|
10
|
+
computeStepHashes(graph, functionsMeta);
|
|
11
|
+
graph.graphHash = computeGraphHash(graph);
|
|
12
|
+
workflows.graphMeta[name] = graph;
|
|
13
|
+
}
|
|
14
|
+
for (const graph of Object.values(workflows.graphMeta)) {
|
|
15
|
+
if (graph.graphHash) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
stampVersionsOnGraph(graph, functionsMeta);
|
|
19
|
+
computeStepHashes(graph, functionsMeta);
|
|
20
|
+
graph.graphHash = computeGraphHash(graph);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function stampVersionsOnGraph(graph, functionsMeta) {
|
|
24
|
+
for (const node of Object.values(graph.nodes)) {
|
|
25
|
+
if (!('rpcName' in node) || typeof node.rpcName !== 'string') {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (isVersionedId(node.rpcName)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const meta = functionsMeta[node.rpcName];
|
|
32
|
+
if (meta?.version !== undefined) {
|
|
33
|
+
node.rpcName = formatVersionedId(node.rpcName, meta.version);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const latestVersion = findLatestVersion(node.rpcName, functionsMeta);
|
|
37
|
+
if (latestVersion > 0) {
|
|
38
|
+
node.rpcName = formatVersionedId(node.rpcName, latestVersion);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function findLatestVersion(baseName, functionsMeta) {
|
|
44
|
+
let max = 0;
|
|
45
|
+
for (const id of Object.keys(functionsMeta)) {
|
|
46
|
+
const parsed = parseVersionedId(id);
|
|
47
|
+
if (parsed.baseName === baseName && parsed.version !== null) {
|
|
48
|
+
max = Math.max(max, parsed.version);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return max;
|
|
52
|
+
}
|
|
53
|
+
function computeStepHashes(graph, functionsMeta) {
|
|
54
|
+
for (const node of Object.values(graph.nodes)) {
|
|
55
|
+
if (!('rpcName' in node) || typeof node.rpcName !== 'string') {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const rpcName = node.rpcName;
|
|
59
|
+
let meta = functionsMeta[rpcName];
|
|
60
|
+
if (!meta) {
|
|
61
|
+
const { baseName } = parseVersionedId(rpcName);
|
|
62
|
+
meta = functionsMeta[baseName];
|
|
63
|
+
}
|
|
64
|
+
;
|
|
65
|
+
node.stepHash = hashString(`${node.nodeId}:${meta?.contractHash ?? ''}`, 12);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function computeGraphHash(graph) {
|
|
69
|
+
return hashString(canonicalJSON({
|
|
70
|
+
source: graph.source,
|
|
71
|
+
context: graph.context,
|
|
72
|
+
nodes: graph.nodes,
|
|
73
|
+
entryNodeIds: graph.entryNodeIds,
|
|
74
|
+
}), 12);
|
|
75
|
+
}
|
|
@@ -4,3 +4,5 @@
|
|
|
4
4
|
export * from './workflow-graph.types.js';
|
|
5
5
|
export { serializeWorkflowGraph } from './serialize-workflow-graph.js';
|
|
6
6
|
export { convertDslToGraph } from './convert-dsl-to-graph.js';
|
|
7
|
+
export { finalizeWorkflows } from './finalize-workflows.js';
|
|
8
|
+
export { finalizeWorkflowHelperTypes, finalizeWorkflowWires, } from './finalize-workflow-wires.js';
|
|
@@ -4,3 +4,5 @@
|
|
|
4
4
|
export * from './workflow-graph.types.js';
|
|
5
5
|
export { serializeWorkflowGraph } from './serialize-workflow-graph.js';
|
|
6
6
|
export { convertDslToGraph } from './convert-dsl-to-graph.js';
|
|
7
|
+
export { finalizeWorkflows } from './finalize-workflows.js';
|
|
8
|
+
export { finalizeWorkflowHelperTypes, finalizeWorkflowWires, } from './finalize-workflow-wires.js';
|
|
@@ -7,13 +7,6 @@ import type { SerializedWorkflowGraph, DataRef, SerializedNext } from './workflo
|
|
|
7
7
|
*/
|
|
8
8
|
export declare function serializeWorkflowGraph(definition: {
|
|
9
9
|
name: string;
|
|
10
|
-
wires: {
|
|
11
|
-
http?: {
|
|
12
|
-
route: string;
|
|
13
|
-
method: string;
|
|
14
|
-
};
|
|
15
|
-
queue?: string;
|
|
16
|
-
};
|
|
17
10
|
graph: Record<string, {
|
|
18
11
|
func: {
|
|
19
12
|
name?: string;
|
|
@@ -32,7 +25,6 @@ export declare function serializeWorkflowGraph(definition: {
|
|
|
32
25
|
*/
|
|
33
26
|
export declare function deserializeWorkflowGraph(serialized: SerializedWorkflowGraph): {
|
|
34
27
|
name: string;
|
|
35
|
-
wires: SerializedWorkflowGraph['wires'];
|
|
36
28
|
graph: Record<string, {
|
|
37
29
|
rpcName: string;
|
|
38
30
|
input: Record<string, unknown | DataRef>;
|
|
@@ -116,11 +116,10 @@ export function serializeWorkflowGraph(definition, options) {
|
|
|
116
116
|
}
|
|
117
117
|
return {
|
|
118
118
|
name: definition.name,
|
|
119
|
-
|
|
119
|
+
pikkuFuncId: definition.name, // For graph workflows, pikkuFuncId is the workflow name
|
|
120
120
|
source: 'graph',
|
|
121
121
|
description: options?.description,
|
|
122
122
|
tags: options?.tags,
|
|
123
|
-
wires: definition.wires,
|
|
124
123
|
nodes,
|
|
125
124
|
entryNodeIds,
|
|
126
125
|
};
|
|
@@ -145,7 +144,6 @@ export function deserializeWorkflowGraph(serialized) {
|
|
|
145
144
|
}
|
|
146
145
|
return {
|
|
147
146
|
name: serialized.name,
|
|
148
|
-
wires: serialized.wires,
|
|
149
147
|
graph,
|
|
150
148
|
entryNodeIds: serialized.entryNodeIds,
|
|
151
149
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Serialized types for workflow graphs
|
|
3
3
|
* These are extracted by the inspector and stored as JSON
|
|
4
|
-
* Can be created from code (
|
|
4
|
+
* Can be created from code (pikkuWorkflowGraph) or UI
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
7
|
* Reference to data from another node or trigger
|
|
@@ -96,6 +96,8 @@ export interface FunctionNode extends BaseNode {
|
|
|
96
96
|
input?: Record<string, unknown | DataRef>;
|
|
97
97
|
/** Output variable name for storing result */
|
|
98
98
|
outputVar?: string;
|
|
99
|
+
/** Hash of nodeId + RPC input/output schemas for version detection */
|
|
100
|
+
stepHash?: string;
|
|
99
101
|
}
|
|
100
102
|
/**
|
|
101
103
|
* Flow node - control flow only, no RPC call
|
|
@@ -118,81 +120,6 @@ export declare const isFunctionNode: (node: SerializedGraphNode) => node is Func
|
|
|
118
120
|
* Type guard for flow nodes
|
|
119
121
|
*/
|
|
120
122
|
export declare const isFlowNode: (node: SerializedGraphNode) => node is FlowNode;
|
|
121
|
-
/**
|
|
122
|
-
* HTTP wire configuration with startNode
|
|
123
|
-
*/
|
|
124
|
-
export interface HttpWire {
|
|
125
|
-
route: string;
|
|
126
|
-
method: 'get' | 'post' | 'put' | 'patch' | 'delete';
|
|
127
|
-
startNode: string;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Channel wire configuration
|
|
131
|
-
*/
|
|
132
|
-
export interface ChannelWire {
|
|
133
|
-
name: string;
|
|
134
|
-
onConnect?: string;
|
|
135
|
-
onDisconnect?: string;
|
|
136
|
-
onMessage?: string;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Queue wire configuration
|
|
140
|
-
*/
|
|
141
|
-
export interface QueueWire {
|
|
142
|
-
name: string;
|
|
143
|
-
startNode: string;
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* CLI wire configuration
|
|
147
|
-
*/
|
|
148
|
-
export interface CliWire {
|
|
149
|
-
command: string;
|
|
150
|
-
startNode: string;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* MCP wire configurations
|
|
154
|
-
*/
|
|
155
|
-
export interface McpWires {
|
|
156
|
-
tool?: Array<{
|
|
157
|
-
name: string;
|
|
158
|
-
startNode: string;
|
|
159
|
-
}>;
|
|
160
|
-
prompt?: Array<{
|
|
161
|
-
name: string;
|
|
162
|
-
startNode: string;
|
|
163
|
-
}>;
|
|
164
|
-
resource?: Array<{
|
|
165
|
-
uri: string;
|
|
166
|
-
startNode: string;
|
|
167
|
-
}>;
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Schedule wire configuration
|
|
171
|
-
*/
|
|
172
|
-
export interface ScheduleWire {
|
|
173
|
-
cron?: string;
|
|
174
|
-
interval?: string;
|
|
175
|
-
startNode: string;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Trigger wire configuration
|
|
179
|
-
*/
|
|
180
|
-
export interface TriggerWire {
|
|
181
|
-
name: string;
|
|
182
|
-
startNode: string;
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* All wire configurations for workflows
|
|
186
|
-
*/
|
|
187
|
-
export interface WorkflowWiresConfig {
|
|
188
|
-
http?: HttpWire[];
|
|
189
|
-
channel?: ChannelWire[];
|
|
190
|
-
queue?: QueueWire[];
|
|
191
|
-
cli?: CliWire[];
|
|
192
|
-
mcp?: McpWires;
|
|
193
|
-
schedule?: ScheduleWire[];
|
|
194
|
-
trigger?: TriggerWire[];
|
|
195
|
-
}
|
|
196
123
|
/**
|
|
197
124
|
* Workflow source type
|
|
198
125
|
* - 'dsl': Pure DSL workflow (pikkuWorkflowFunc) - can be round-tripped to code
|
|
@@ -207,7 +134,7 @@ export interface SerializedWorkflowGraph {
|
|
|
207
134
|
/** Workflow name */
|
|
208
135
|
name: string;
|
|
209
136
|
/** Pikku function name (for runtime registration) */
|
|
210
|
-
|
|
137
|
+
pikkuFuncId: string;
|
|
211
138
|
/** Source type: 'dsl' for pikkuWorkflowFunc, 'graph' for pikkuWorkflowGraph */
|
|
212
139
|
source: WorkflowSourceType;
|
|
213
140
|
/** Optional description */
|
|
@@ -216,12 +143,59 @@ export interface SerializedWorkflowGraph {
|
|
|
216
143
|
tags?: string[];
|
|
217
144
|
/** Workflow context/state variables (from Zod schema) */
|
|
218
145
|
context?: WorkflowContext;
|
|
219
|
-
/** Wires - how the workflow is triggered */
|
|
220
|
-
wires: WorkflowWiresConfig;
|
|
221
146
|
/** Serialized nodes */
|
|
222
147
|
nodes: Record<string, SerializedGraphNode>;
|
|
223
148
|
/** Entry node(s) - first nodes to execute */
|
|
224
149
|
entryNodeIds: string[];
|
|
150
|
+
/** Hash of graph topology (nodes, edges, input mappings) */
|
|
151
|
+
graphHash?: string;
|
|
152
|
+
/** Wire entry points (HTTP, channel, queue, etc.) that trigger this workflow */
|
|
153
|
+
wires?: WorkflowWires;
|
|
154
|
+
}
|
|
155
|
+
export interface WorkflowWires {
|
|
156
|
+
http?: Array<{
|
|
157
|
+
route: string;
|
|
158
|
+
method: string;
|
|
159
|
+
startNode: string;
|
|
160
|
+
}>;
|
|
161
|
+
channel?: Array<{
|
|
162
|
+
name: string;
|
|
163
|
+
route: string;
|
|
164
|
+
onConnect?: string;
|
|
165
|
+
onMessage?: string;
|
|
166
|
+
onDisconnect?: string;
|
|
167
|
+
onMessageRoute?: Record<string, string>;
|
|
168
|
+
}>;
|
|
169
|
+
queue?: Array<{
|
|
170
|
+
name: string;
|
|
171
|
+
startNode: string;
|
|
172
|
+
}>;
|
|
173
|
+
cli?: Array<{
|
|
174
|
+
command: string;
|
|
175
|
+
startNode: string;
|
|
176
|
+
}>;
|
|
177
|
+
mcp?: {
|
|
178
|
+
tool?: Array<{
|
|
179
|
+
name: string;
|
|
180
|
+
startNode: string;
|
|
181
|
+
}>;
|
|
182
|
+
prompt?: Array<{
|
|
183
|
+
name: string;
|
|
184
|
+
startNode: string;
|
|
185
|
+
}>;
|
|
186
|
+
resource?: Array<{
|
|
187
|
+
uri: string;
|
|
188
|
+
startNode: string;
|
|
189
|
+
}>;
|
|
190
|
+
};
|
|
191
|
+
schedule?: Array<{
|
|
192
|
+
cron: string;
|
|
193
|
+
startNode: string;
|
|
194
|
+
}>;
|
|
195
|
+
trigger?: Array<{
|
|
196
|
+
name: string;
|
|
197
|
+
startNode: string;
|
|
198
|
+
}>;
|
|
225
199
|
}
|
|
226
200
|
/**
|
|
227
201
|
* All workflow graphs (serialized)
|
package/dist/visit.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { InspectorState, InspectorLogger, InspectorOptions } from './types.js';
|
|
2
|
+
import type { InspectorState, InspectorLogger, InspectorOptions } from './types.js';
|
|
3
3
|
export declare const visitSetup: (logger: InspectorLogger, checker: ts.TypeChecker, node: ts.Node, state: InspectorState, options: InspectorOptions) => void;
|
|
4
4
|
export declare const visitRoutes: (logger: InspectorLogger, checker: ts.TypeChecker, node: ts.Node, state: InspectorState, options: InspectorOptions) => void;
|