@pikku/inspector 0.11.2 → 0.12.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.
Files changed (182) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/OPTIMIZATION-PLAN.md +195 -0
  3. package/dist/add/add-ai-agent.d.ts +2 -0
  4. package/dist/add/add-ai-agent.js +314 -0
  5. package/dist/add/add-channel.js +69 -61
  6. package/dist/add/add-cli.js +36 -18
  7. package/dist/add/add-file-with-factory.js +2 -0
  8. package/dist/add/add-functions.js +250 -75
  9. package/dist/add/add-http-route.d.ts +19 -10
  10. package/dist/add/add-http-route.js +152 -66
  11. package/dist/add/add-http-routes.d.ts +5 -0
  12. package/dist/add/add-http-routes.js +159 -0
  13. package/dist/add/add-keyed-wiring.d.ts +12 -0
  14. package/dist/add/add-keyed-wiring.js +97 -0
  15. package/dist/add/add-mcp-prompt.js +14 -9
  16. package/dist/add/add-mcp-resource.js +14 -9
  17. package/dist/add/add-middleware.d.ts +1 -4
  18. package/dist/add/add-middleware.js +364 -79
  19. package/dist/add/add-permission.d.ts +1 -1
  20. package/dist/add/add-permission.js +152 -40
  21. package/dist/add/add-queue-worker.js +18 -12
  22. package/dist/add/add-rpc-invocations.js +14 -0
  23. package/dist/add/add-schedule.js +11 -5
  24. package/dist/add/add-secret.d.ts +3 -0
  25. package/dist/add/add-secret.js +82 -0
  26. package/dist/add/add-trigger.d.ts +2 -0
  27. package/dist/add/add-trigger.js +87 -0
  28. package/dist/add/add-variable.d.ts +1 -0
  29. package/dist/add/add-variable.js +8 -0
  30. package/dist/add/add-workflow-graph.d.ts +3 -2
  31. package/dist/add/add-workflow-graph.js +143 -406
  32. package/dist/add/add-workflow.js +6 -4
  33. package/dist/error-codes.d.ts +14 -1
  34. package/dist/error-codes.js +19 -1
  35. package/dist/index.d.ts +9 -8
  36. package/dist/index.js +5 -4
  37. package/dist/inspector.d.ts +1 -1
  38. package/dist/inspector.js +91 -14
  39. package/dist/schema-generator.d.ts +1 -0
  40. package/dist/schema-generator.js +1 -0
  41. package/dist/types-map.js +10 -1
  42. package/dist/types.d.ts +163 -39
  43. package/dist/utils/compute-required-schemas.d.ts +4 -0
  44. package/dist/utils/compute-required-schemas.js +41 -0
  45. package/dist/utils/contract-hashes.d.ts +35 -0
  46. package/dist/utils/contract-hashes.js +202 -0
  47. package/dist/utils/custom-types-generator.d.ts +9 -0
  48. package/dist/utils/custom-types-generator.js +71 -0
  49. package/dist/utils/detect-schema-vendor.d.ts +22 -0
  50. package/dist/utils/detect-schema-vendor.js +76 -0
  51. package/dist/utils/ensure-function-metadata.d.ts +5 -2
  52. package/dist/utils/ensure-function-metadata.js +220 -6
  53. package/dist/utils/extract-function-name.d.ts +5 -16
  54. package/dist/utils/extract-function-name.js +86 -291
  55. package/dist/utils/extract-services.d.ts +2 -1
  56. package/dist/utils/extract-services.js +25 -1
  57. package/dist/utils/filter-inspector-state.js +107 -23
  58. package/dist/utils/get-property-value.d.ts +6 -1
  59. package/dist/utils/get-property-value.js +28 -3
  60. package/dist/utils/hash.d.ts +2 -0
  61. package/dist/utils/hash.js +23 -0
  62. package/dist/utils/middleware.d.ts +7 -30
  63. package/dist/utils/middleware.js +80 -66
  64. package/dist/utils/permissions.d.ts +2 -2
  65. package/dist/utils/permissions.js +10 -10
  66. package/dist/utils/post-process.d.ts +9 -10
  67. package/dist/utils/post-process.js +231 -24
  68. package/dist/utils/resolve-external-package.d.ts +12 -0
  69. package/dist/utils/resolve-external-package.js +34 -0
  70. package/dist/utils/resolve-function-types.d.ts +6 -0
  71. package/dist/utils/resolve-function-types.js +29 -0
  72. package/dist/utils/resolve-identifier.d.ts +10 -0
  73. package/dist/utils/resolve-identifier.js +36 -0
  74. package/dist/utils/resolve-versions.d.ts +2 -0
  75. package/dist/utils/resolve-versions.js +78 -0
  76. package/dist/utils/schema-generator.d.ts +9 -0
  77. package/dist/utils/schema-generator.js +209 -0
  78. package/dist/utils/serialize-inspector-state.d.ts +59 -22
  79. package/dist/utils/serialize-inspector-state.js +92 -20
  80. package/dist/utils/serialize-mcp-json.d.ts +2 -0
  81. package/dist/utils/serialize-mcp-json.js +99 -0
  82. package/dist/utils/serialize-middleware-groups-meta.d.ts +12 -0
  83. package/dist/utils/serialize-middleware-groups-meta.js +28 -0
  84. package/dist/utils/serialize-openapi-json.d.ts +85 -0
  85. package/dist/utils/serialize-openapi-json.js +151 -0
  86. package/dist/utils/serialize-permissions-groups-meta.d.ts +6 -0
  87. package/dist/utils/serialize-permissions-groups-meta.js +31 -0
  88. package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +34 -102
  89. package/dist/utils/workflow/dsl/extract-dsl-workflow.js +23 -4
  90. package/dist/utils/workflow/graph/convert-dsl-to-graph.js +12 -10
  91. package/dist/utils/workflow/graph/finalize-workflow-wires.d.ts +3 -0
  92. package/dist/utils/workflow/graph/finalize-workflow-wires.js +276 -0
  93. package/dist/utils/workflow/graph/finalize-workflows.d.ts +2 -0
  94. package/dist/utils/workflow/graph/finalize-workflows.js +75 -0
  95. package/dist/utils/workflow/graph/index.d.ts +2 -0
  96. package/dist/utils/workflow/graph/index.js +2 -0
  97. package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +0 -8
  98. package/dist/utils/workflow/graph/serialize-workflow-graph.js +1 -3
  99. package/dist/utils/workflow/graph/workflow-graph.types.d.ts +53 -79
  100. package/dist/utils/workflow/graph/workflow-graph.types.js +1 -1
  101. package/dist/visit.js +11 -6
  102. package/package.json +14 -4
  103. package/src/add/add-ai-agent.ts +468 -0
  104. package/src/add/add-channel.ts +82 -79
  105. package/src/add/add-cli.ts +49 -20
  106. package/src/add/add-file-with-factory.ts +2 -0
  107. package/src/add/add-functions.ts +330 -86
  108. package/src/add/add-http-route.ts +245 -88
  109. package/src/add/add-http-routes.ts +228 -0
  110. package/src/add/add-keyed-wiring.ts +151 -0
  111. package/src/add/add-mcp-prompt.ts +26 -15
  112. package/src/add/add-mcp-resource.ts +27 -15
  113. package/src/add/add-middleware.ts +482 -80
  114. package/src/add/add-permission.ts +199 -40
  115. package/src/add/add-queue-worker.ts +24 -19
  116. package/src/add/add-rpc-invocations.ts +17 -0
  117. package/src/add/add-schedule.ts +16 -11
  118. package/src/add/add-secret.ts +140 -0
  119. package/src/add/add-trigger.ts +154 -0
  120. package/src/add/add-variable.ts +9 -0
  121. package/src/add/add-workflow-graph.ts +180 -522
  122. package/src/add/add-workflow.ts +5 -4
  123. package/src/error-codes.ts +24 -1
  124. package/src/index.ts +22 -13
  125. package/src/inspector.ts +129 -17
  126. package/src/schema-generator.ts +1 -0
  127. package/src/types-map.ts +12 -1
  128. package/src/types.ts +175 -58
  129. package/src/utils/compute-required-schemas.ts +49 -0
  130. package/src/utils/contract-hashes.test.ts +528 -0
  131. package/src/utils/contract-hashes.ts +290 -0
  132. package/src/utils/custom-types-generator.ts +88 -0
  133. package/src/utils/detect-schema-vendor.ts +90 -0
  134. package/src/utils/ensure-function-metadata.ts +324 -7
  135. package/src/utils/extract-function-name.ts +101 -351
  136. package/src/utils/extract-services.ts +35 -2
  137. package/src/utils/filter-inspector-state.test.ts +34 -20
  138. package/src/utils/filter-inspector-state.ts +140 -31
  139. package/src/utils/get-property-value.ts +42 -4
  140. package/src/utils/hash.ts +26 -0
  141. package/src/utils/middleware.test.ts +204 -0
  142. package/src/utils/middleware.ts +129 -67
  143. package/src/utils/permissions.test.ts +35 -12
  144. package/src/utils/permissions.ts +10 -10
  145. package/src/utils/post-process.ts +283 -43
  146. package/src/utils/resolve-external-package.ts +42 -0
  147. package/src/utils/resolve-function-types.ts +42 -0
  148. package/src/utils/resolve-identifier.ts +46 -0
  149. package/src/utils/resolve-versions.test.ts +249 -0
  150. package/src/utils/resolve-versions.ts +105 -0
  151. package/src/utils/schema-generator.ts +329 -0
  152. package/src/utils/serialize-inspector-state.ts +163 -40
  153. package/src/utils/serialize-mcp-json.ts +145 -0
  154. package/src/utils/serialize-middleware-groups-meta.ts +33 -0
  155. package/src/utils/serialize-openapi-json.ts +277 -0
  156. package/src/utils/serialize-permissions-groups-meta.ts +35 -0
  157. package/src/utils/test-data/inspector-state.json +69 -66
  158. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +43 -119
  159. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +24 -4
  160. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +17 -10
  161. package/src/utils/workflow/graph/finalize-workflow-wires.ts +310 -0
  162. package/src/utils/workflow/graph/finalize-workflows.ts +100 -0
  163. package/src/utils/workflow/graph/index.ts +5 -0
  164. package/src/utils/workflow/graph/serialize-workflow-graph.ts +1 -8
  165. package/src/utils/workflow/graph/workflow-graph.types.ts +29 -78
  166. package/src/visit.ts +12 -6
  167. package/tsconfig.tsbuildinfo +1 -1
  168. package/dist/add/add-forge-credential.d.ts +0 -8
  169. package/dist/add/add-forge-credential.js +0 -77
  170. package/dist/add/add-forge-node.d.ts +0 -7
  171. package/dist/add/add-forge-node.js +0 -77
  172. package/dist/add/add-mcp-tool.d.ts +0 -2
  173. package/dist/add/add-mcp-tool.js +0 -81
  174. package/dist/utils/extract-service-metadata.d.ts +0 -19
  175. package/dist/utils/extract-service-metadata.js +0 -244
  176. package/dist/utils/write-service-metadata.d.ts +0 -13
  177. package/dist/utils/write-service-metadata.js +0 -37
  178. package/src/add/add-forge-credential.ts +0 -119
  179. package/src/add/add-forge-node.ts +0 -132
  180. package/src/add/add-mcp-tool.ts +0 -141
  181. package/src/utils/extract-service-metadata.ts +0 -353
  182. package/src/utils/write-service-metadata.ts +0 -51
@@ -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,2 @@
1
+ import type { InspectorState } from '../../../types.js';
2
+ export declare function finalizeWorkflows(state: InspectorState): void;
@@ -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
- pikkuFuncName: definition.name, // For graph workflows, pikkuFuncName is the workflow name
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 (wireWorkflow) or UI
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
- pikkuFuncName: string;
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)
@@ -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 (wireWorkflow) or UI
4
+ * Can be created from code (pikkuWorkflowGraph) or UI
5
5
  */
6
6
  /**
7
7
  * Check if value is a DataRef
package/dist/visit.js CHANGED
@@ -2,11 +2,12 @@ import * as ts from 'typescript';
2
2
  import { addFileWithFactory } from './add/add-file-with-factory.js';
3
3
  import { addFileExtendsCoreType } from './add/add-file-extends-core-type.js';
4
4
  import { addHTTPRoute } from './add/add-http-route.js';
5
+ import { addHTTPRoutes } from './add/add-http-routes.js';
5
6
  import { addSchedule } from './add/add-schedule.js';
7
+ import { addTrigger } from './add/add-trigger.js';
6
8
  import { addQueueWorker } from './add/add-queue-worker.js';
7
9
  import { addWorkflow } from './add/add-workflow.js';
8
10
  import { addMCPResource } from './add/add-mcp-resource.js';
9
- import { addMCPTool } from './add/add-mcp-tool.js';
10
11
  import { addMCPPrompt } from './add/add-mcp-prompt.js';
11
12
  import { addFunctions } from './add/add-functions.js';
12
13
  import { addChannel } from './add/add-channel.js';
@@ -14,9 +15,10 @@ import { addRPCInvocations } from './add/add-rpc-invocations.js';
14
15
  import { addMiddleware } from './add/add-middleware.js';
15
16
  import { addPermission } from './add/add-permission.js';
16
17
  import { addCLI, addCLIRenderers } from './add/add-cli.js';
17
- import { addForgeNode } from './add/add-forge-node.js';
18
- import { addForgeCredential } from './add/add-forge-credential.js';
18
+ import { addSecret, addOAuth2Credential } from './add/add-secret.js';
19
+ import { addVariable } from './add/add-variable.js';
19
20
  import { addWorkflowGraph } from './add/add-workflow-graph.js';
21
+ import { addAIAgent } from './add/add-ai-agent.js';
20
22
  export const visitSetup = (logger, checker, node, state, options) => {
21
23
  addFileExtendsCoreType(node, checker, state.singletonServicesTypeImportMap, 'CoreSingletonServices', state);
22
24
  addFileExtendsCoreType(node, checker, state.wireServicesTypeImportMap, 'CoreServices', state);
@@ -33,17 +35,20 @@ export const visitSetup = (logger, checker, node, state, options) => {
33
35
  };
34
36
  export const visitRoutes = (logger, checker, node, state, options) => {
35
37
  addFunctions(logger, node, checker, state, options);
38
+ addSecret(logger, node, checker, state, options);
39
+ addOAuth2Credential(logger, node, checker, state, options);
40
+ addVariable(logger, node, checker, state, options);
36
41
  addHTTPRoute(logger, node, checker, state, options);
42
+ addHTTPRoutes(logger, node, checker, state, options);
37
43
  addSchedule(logger, node, checker, state, options);
44
+ addTrigger(logger, node, checker, state, options);
38
45
  addQueueWorker(logger, node, checker, state, options);
39
46
  addChannel(logger, node, checker, state, options);
40
47
  addCLI(logger, node, checker, state, options);
41
48
  addCLIRenderers(logger, node, checker, state, options);
42
49
  addMCPResource(logger, node, checker, state, options);
43
- addMCPTool(logger, node, checker, state, options);
44
50
  addMCPPrompt(logger, node, checker, state, options);
45
- addForgeNode(logger, node, checker, state, options);
46
- addForgeCredential(logger, node, checker, state, options);
47
51
  addWorkflowGraph(logger, node, checker, state, options);
52
+ addAIAgent(logger, node, checker, state, options);
48
53
  ts.forEachChild(node, (child) => visitRoutes(logger, checker, child, state, options));
49
54
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/inspector",
3
- "version": "0.11.2",
3
+ "version": "0.12.0",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "BUSL-1.1",
6
6
  "type": "module",
@@ -12,6 +12,11 @@
12
12
  "import": "./dist/index.js",
13
13
  "default": "./dist/index.js"
14
14
  },
15
+ "./schema-generator": {
16
+ "types": "./dist/schema-generator.d.ts",
17
+ "import": "./dist/schema-generator.js",
18
+ "default": "./dist/schema-generator.js"
19
+ },
15
20
  "./workflow-graph": {
16
21
  "types": "./dist/utils/workflow/graph/index.d.ts",
17
22
  "import": "./dist/utils/workflow/graph/index.js",
@@ -28,12 +33,17 @@
28
33
  "test:coverage": "bash run-tests.sh --coverage"
29
34
  },
30
35
  "dependencies": {
31
- "@pikku/core": "^0.11.2",
36
+ "@openapi-contrib/json-schema-to-openapi-schema": "^4.3.1",
37
+ "@pikku/core": "^0.12.0",
32
38
  "path-to-regexp": "^8.3.0",
33
- "typescript": "^5.9"
39
+ "ts-json-schema-generator": "^2.5.0",
40
+ "tsx": "^4.21.0",
41
+ "typescript": "^5.9",
42
+ "zod": "^4.3.6",
43
+ "zod-to-ts": "^2.0.0"
34
44
  },
35
45
  "devDependencies": {
36
- "@types/node": "^24.10.1"
46
+ "@types/node": "^24.10.12"
37
47
  },
38
48
  "engines": {
39
49
  "node": ">=18"