@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
@@ -1,256 +1,90 @@
1
1
  import * as ts from 'typescript';
2
2
  import { ErrorCode } from '../error-codes.js';
3
3
  import { extractStringLiteral } from '../utils/extract-node-value.js';
4
- /**
5
- * Extract wire configuration from object literal
6
- */
7
- function extractWiresConfig(wiresNode, checker) {
8
- const wires = {};
9
- for (const prop of wiresNode.properties) {
10
- if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
11
- continue;
12
- const propName = prop.name.text;
13
- if (propName === 'http' && ts.isArrayLiteralExpression(prop.initializer)) {
14
- wires.http = [];
15
- for (const elem of prop.initializer.elements) {
16
- if (ts.isObjectLiteralExpression(elem)) {
17
- const httpWire = {};
18
- for (const httpProp of elem.properties) {
19
- if (!ts.isPropertyAssignment(httpProp) ||
20
- !ts.isIdentifier(httpProp.name))
21
- continue;
22
- const httpPropName = httpProp.name.text;
23
- if (httpPropName === 'route') {
24
- httpWire.route = extractStringLiteral(httpProp.initializer, checker);
25
- }
26
- else if (httpPropName === 'method') {
27
- httpWire.method = extractStringLiteral(httpProp.initializer, checker);
28
- }
29
- else if (httpPropName === 'startNode') {
30
- httpWire.startNode = extractStringLiteral(httpProp.initializer, checker);
31
- }
32
- }
33
- if (httpWire.route && httpWire.method && httpWire.startNode) {
34
- wires.http.push(httpWire);
35
- }
36
- }
37
- }
38
- }
39
- else if (propName === 'channel' &&
40
- ts.isArrayLiteralExpression(prop.initializer)) {
41
- wires.channel = [];
42
- for (const elem of prop.initializer.elements) {
43
- if (ts.isObjectLiteralExpression(elem)) {
44
- const channelWire = {};
45
- for (const channelProp of elem.properties) {
46
- if (!ts.isPropertyAssignment(channelProp) ||
47
- !ts.isIdentifier(channelProp.name))
48
- continue;
49
- const channelPropName = channelProp.name.text;
50
- if (channelPropName === 'name') {
51
- channelWire.name = extractStringLiteral(channelProp.initializer, checker);
52
- }
53
- else if (channelPropName === 'onConnect') {
54
- channelWire.onConnect = extractStringLiteral(channelProp.initializer, checker);
55
- }
56
- else if (channelPropName === 'onDisconnect') {
57
- channelWire.onDisconnect = extractStringLiteral(channelProp.initializer, checker);
58
- }
59
- else if (channelPropName === 'onMessage') {
60
- channelWire.onMessage = extractStringLiteral(channelProp.initializer, checker);
61
- }
62
- }
63
- if (channelWire.name) {
64
- wires.channel.push(channelWire);
65
- }
66
- }
67
- }
68
- }
69
- else if (propName === 'queue' &&
70
- ts.isArrayLiteralExpression(prop.initializer)) {
71
- wires.queue = [];
72
- for (const elem of prop.initializer.elements) {
73
- if (ts.isObjectLiteralExpression(elem)) {
74
- const queueWire = {};
75
- for (const queueProp of elem.properties) {
76
- if (!ts.isPropertyAssignment(queueProp) ||
77
- !ts.isIdentifier(queueProp.name))
78
- continue;
79
- const queuePropName = queueProp.name.text;
80
- if (queuePropName === 'name') {
81
- queueWire.name = extractStringLiteral(queueProp.initializer, checker);
82
- }
83
- else if (queuePropName === 'startNode') {
84
- queueWire.startNode = extractStringLiteral(queueProp.initializer, checker);
85
- }
86
- }
87
- if (queueWire.name && queueWire.startNode) {
88
- wires.queue.push(queueWire);
89
- }
90
- }
91
- }
92
- }
93
- else if (propName === 'cli' &&
94
- ts.isArrayLiteralExpression(prop.initializer)) {
95
- wires.cli = [];
96
- for (const elem of prop.initializer.elements) {
97
- if (ts.isObjectLiteralExpression(elem)) {
98
- const cliWire = {};
99
- for (const cliProp of elem.properties) {
100
- if (!ts.isPropertyAssignment(cliProp) ||
101
- !ts.isIdentifier(cliProp.name))
102
- continue;
103
- const cliPropName = cliProp.name.text;
104
- if (cliPropName === 'command') {
105
- cliWire.command = extractStringLiteral(cliProp.initializer, checker);
106
- }
107
- else if (cliPropName === 'startNode') {
108
- cliWire.startNode = extractStringLiteral(cliProp.initializer, checker);
109
- }
110
- }
111
- if (cliWire.command && cliWire.startNode) {
112
- wires.cli.push(cliWire);
113
- }
114
- }
115
- }
116
- }
117
- else if (propName === 'mcp' &&
118
- ts.isObjectLiteralExpression(prop.initializer)) {
119
- const mcpWires = {};
120
- for (const mcpProp of prop.initializer.properties) {
121
- if (!ts.isPropertyAssignment(mcpProp) || !ts.isIdentifier(mcpProp.name))
122
- continue;
123
- const mcpPropName = mcpProp.name.text;
124
- if (mcpPropName === 'tool' &&
125
- ts.isArrayLiteralExpression(mcpProp.initializer)) {
126
- mcpWires.tool = extractMcpToolWireArray(mcpProp.initializer, checker);
127
- }
128
- else if (mcpPropName === 'prompt' &&
129
- ts.isArrayLiteralExpression(mcpProp.initializer)) {
130
- mcpWires.prompt = extractMcpToolWireArray(mcpProp.initializer, checker);
131
- }
132
- else if (mcpPropName === 'resource' &&
133
- ts.isArrayLiteralExpression(mcpProp.initializer)) {
134
- mcpWires.resource = extractMcpResourceWireArray(mcpProp.initializer, checker);
135
- }
4
+ function extractAstValue(expr, refParamName, templateParamName) {
5
+ if (ts.isStringLiteral(expr)) {
6
+ return expr.text;
7
+ }
8
+ if (ts.isNumericLiteral(expr)) {
9
+ return Number(expr.text);
10
+ }
11
+ if (expr.kind === ts.SyntaxKind.TrueKeyword) {
12
+ return true;
13
+ }
14
+ if (expr.kind === ts.SyntaxKind.FalseKeyword) {
15
+ return false;
16
+ }
17
+ if (expr.kind === ts.SyntaxKind.NullKeyword) {
18
+ return null;
19
+ }
20
+ if (ts.isCallExpression(expr)) {
21
+ const callee = expr.expression;
22
+ if (ts.isIdentifier(callee)) {
23
+ if (callee.text === refParamName) {
24
+ const args = expr.arguments;
25
+ const nodeId = args[0] && ts.isStringLiteral(args[0]) ? args[0].text : 'unknown';
26
+ const path = args[1] && ts.isStringLiteral(args[1]) ? args[1].text : undefined;
27
+ return { $ref: nodeId, path };
136
28
  }
137
- if (mcpWires.tool || mcpWires.prompt || mcpWires.resource) {
138
- wires.mcp = mcpWires;
139
- }
140
- }
141
- else if (propName === 'schedule' &&
142
- ts.isArrayLiteralExpression(prop.initializer)) {
143
- wires.schedule = [];
144
- for (const elem of prop.initializer.elements) {
145
- if (ts.isObjectLiteralExpression(elem)) {
146
- const scheduleWire = {};
147
- for (const scheduleProp of elem.properties) {
148
- if (!ts.isPropertyAssignment(scheduleProp) ||
149
- !ts.isIdentifier(scheduleProp.name))
150
- continue;
151
- const schedulePropName = scheduleProp.name.text;
152
- if (schedulePropName === 'cron') {
153
- scheduleWire.cron = extractStringLiteral(scheduleProp.initializer, checker);
154
- }
155
- else if (schedulePropName === 'interval') {
156
- scheduleWire.interval = extractStringLiteral(scheduleProp.initializer, checker);
29
+ if (templateParamName && callee.text === templateParamName) {
30
+ const templateStr = expr.arguments[0] && ts.isStringLiteral(expr.arguments[0])
31
+ ? expr.arguments[0].text
32
+ : '';
33
+ const refsArg = expr.arguments[1];
34
+ const refs = [];
35
+ if (refsArg && ts.isArrayLiteralExpression(refsArg)) {
36
+ for (const el of refsArg.elements) {
37
+ const resolved = extractAstValue(el, refParamName, templateParamName);
38
+ if (typeof resolved === 'object' &&
39
+ resolved !== null &&
40
+ '$ref' in resolved) {
41
+ refs.push(resolved);
157
42
  }
158
- else if (schedulePropName === 'startNode') {
159
- scheduleWire.startNode = extractStringLiteral(scheduleProp.initializer, checker);
160
- }
161
- }
162
- if ((scheduleWire.cron || scheduleWire.interval) &&
163
- scheduleWire.startNode) {
164
- wires.schedule.push(scheduleWire);
165
43
  }
166
44
  }
167
- }
168
- }
169
- else if (propName === 'trigger' &&
170
- ts.isArrayLiteralExpression(prop.initializer)) {
171
- wires.trigger = [];
172
- for (const elem of prop.initializer.elements) {
173
- if (ts.isObjectLiteralExpression(elem)) {
174
- const triggerWire = {};
175
- for (const triggerProp of elem.properties) {
176
- if (!ts.isPropertyAssignment(triggerProp) ||
177
- !ts.isIdentifier(triggerProp.name))
178
- continue;
179
- const triggerPropName = triggerProp.name.text;
180
- if (triggerPropName === 'name') {
181
- triggerWire.name = extractStringLiteral(triggerProp.initializer, checker);
182
- }
183
- else if (triggerPropName === 'startNode') {
184
- triggerWire.startNode = extractStringLiteral(triggerProp.initializer, checker);
185
- }
186
- }
187
- if (triggerWire.name && triggerWire.startNode) {
188
- wires.trigger.push(triggerWire);
189
- }
45
+ const parts = [];
46
+ const expressions = [];
47
+ const regex = /\$(\d+)/g;
48
+ let lastIndex = 0;
49
+ let match;
50
+ while ((match = regex.exec(templateStr)) !== null) {
51
+ parts.push(templateStr.slice(lastIndex, match.index));
52
+ const refIndex = parseInt(match[1], 10);
53
+ expressions.push(refs[refIndex] ?? { $ref: 'unknown' });
54
+ lastIndex = regex.lastIndex;
190
55
  }
56
+ parts.push(templateStr.slice(lastIndex));
57
+ return { $template: { parts, expressions } };
191
58
  }
192
59
  }
193
60
  }
194
- return wires;
195
- }
196
- /**
197
- * Helper to extract MCP wire arrays for tool/prompt (name field)
198
- */
199
- function extractMcpToolWireArray(arrayNode, checker) {
200
- const result = [];
201
- for (const elem of arrayNode.elements) {
202
- if (ts.isObjectLiteralExpression(elem)) {
203
- let name;
204
- let startNode;
205
- for (const prop of elem.properties) {
206
- if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
207
- continue;
208
- const propName = prop.name.text;
209
- if (propName === 'name') {
210
- name = extractStringLiteral(prop.initializer, checker);
211
- }
212
- else if (propName === 'startNode') {
213
- startNode = extractStringLiteral(prop.initializer, checker);
214
- }
215
- }
216
- if (name && startNode) {
217
- result.push({ name, startNode });
218
- }
61
+ if (ts.isArrayLiteralExpression(expr)) {
62
+ return expr.elements.map((el) => extractAstValue(el, refParamName, templateParamName));
63
+ }
64
+ if (ts.isObjectLiteralExpression(expr)) {
65
+ const obj = {};
66
+ for (const prop of expr.properties) {
67
+ if (!ts.isPropertyAssignment(prop))
68
+ continue;
69
+ const key = ts.isIdentifier(prop.name)
70
+ ? prop.name.text
71
+ : ts.isStringLiteral(prop.name)
72
+ ? prop.name.text
73
+ : null;
74
+ if (!key)
75
+ continue;
76
+ obj[key] = extractAstValue(prop.initializer, refParamName, templateParamName);
219
77
  }
78
+ return obj;
220
79
  }
221
- return result;
222
- }
223
- /**
224
- * Helper to extract MCP wire arrays for resource (uri field)
225
- */
226
- function extractMcpResourceWireArray(arrayNode, checker) {
227
- const result = [];
228
- for (const elem of arrayNode.elements) {
229
- if (ts.isObjectLiteralExpression(elem)) {
230
- let uri;
231
- let startNode;
232
- for (const prop of elem.properties) {
233
- if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
234
- continue;
235
- const propName = prop.name.text;
236
- if (propName === 'uri') {
237
- uri = extractStringLiteral(prop.initializer, checker);
238
- }
239
- else if (propName === 'startNode') {
240
- startNode = extractStringLiteral(prop.initializer, checker);
241
- }
242
- }
243
- if (uri && startNode) {
244
- result.push({ uri, startNode });
245
- }
80
+ if (ts.isPrefixUnaryExpression(expr)) {
81
+ if (expr.operator === ts.SyntaxKind.MinusToken &&
82
+ ts.isNumericLiteral(expr.operand)) {
83
+ return -Number(expr.operand.text);
246
84
  }
247
85
  }
248
- return result;
86
+ return undefined;
249
87
  }
250
- /**
251
- * Extract input mapping from an arrow function
252
- * Parses: (ref) => ({ key: ref('nodeId', 'path'), key2: 'literal' })
253
- */
254
88
  function extractInputMapping(node, _checker) {
255
89
  if (!ts.isArrowFunction(node)) {
256
90
  return {};
@@ -279,6 +113,9 @@ function extractInputMapping(node, _checker) {
279
113
  const refParamName = node.parameters.length > 0 && ts.isIdentifier(node.parameters[0].name)
280
114
  ? node.parameters[0].name.text
281
115
  : 'ref';
116
+ const templateParamName = node.parameters.length > 1 && ts.isIdentifier(node.parameters[1].name)
117
+ ? node.parameters[1].name.text
118
+ : undefined;
282
119
  const input = {};
283
120
  for (const prop of bodyObj.properties) {
284
121
  if (!ts.isPropertyAssignment(prop))
@@ -290,32 +127,9 @@ function extractInputMapping(node, _checker) {
290
127
  : null;
291
128
  if (!key)
292
129
  continue;
293
- if (ts.isCallExpression(prop.initializer)) {
294
- const callExpr = prop.initializer.expression;
295
- if (ts.isIdentifier(callExpr) && callExpr.text === refParamName) {
296
- const args = prop.initializer.arguments;
297
- const nodeIdArg = args[0];
298
- const pathArg = args[1];
299
- const nodeId = nodeIdArg && ts.isStringLiteral(nodeIdArg)
300
- ? nodeIdArg.text
301
- : 'unknown';
302
- const path = pathArg && ts.isStringLiteral(pathArg) ? pathArg.text : undefined;
303
- input[key] = { $ref: nodeId, path };
304
- continue;
305
- }
306
- }
307
- if (ts.isStringLiteral(prop.initializer)) {
308
- input[key] = prop.initializer.text;
309
- }
310
- else if (ts.isNumericLiteral(prop.initializer)) {
311
- input[key] = Number(prop.initializer.text);
312
- }
313
- else if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword ||
314
- prop.initializer.kind === ts.SyntaxKind.FalseKeyword) {
315
- input[key] = prop.initializer.kind === ts.SyntaxKind.TrueKeyword;
316
- }
317
- else if (prop.initializer.kind === ts.SyntaxKind.NullKeyword) {
318
- input[key] = null;
130
+ const value = extractAstValue(prop.initializer, refParamName, templateParamName);
131
+ if (value !== undefined) {
132
+ input[key] = value;
319
133
  }
320
134
  }
321
135
  return input;
@@ -357,35 +171,6 @@ function extractNextConfig(node, _checker) {
357
171
  }
358
172
  return undefined;
359
173
  }
360
- /**
361
- * Extract definition object from wireWorkflow call
362
- */
363
- function extractDefinitionObject(firstArg) {
364
- if (ts.isObjectLiteralExpression(firstArg)) {
365
- return firstArg;
366
- }
367
- if (ts.isArrowFunction(firstArg)) {
368
- const body = firstArg.body;
369
- if (ts.isObjectLiteralExpression(body)) {
370
- return body;
371
- }
372
- if (ts.isParenthesizedExpression(body)) {
373
- if (ts.isObjectLiteralExpression(body.expression)) {
374
- return body.expression;
375
- }
376
- }
377
- if (ts.isBlock(body)) {
378
- for (const stmt of body.statements) {
379
- if (ts.isReturnStatement(stmt) && stmt.expression) {
380
- if (ts.isObjectLiteralExpression(stmt.expression)) {
381
- return stmt.expression;
382
- }
383
- }
384
- }
385
- }
386
- }
387
- return undefined;
388
- }
389
174
  /**
390
175
  * Compute entry node IDs from graph nodes
391
176
  */
@@ -416,77 +201,46 @@ function computeEntryNodeIds(graphNodes) {
416
201
  return Object.keys(graphNodes).filter((nodeId) => !hasIncomingEdge.has(nodeId));
417
202
  }
418
203
  /**
419
- * Extract pikkuWorkflowGraph config from a variable reference or call expression
420
- * New format: pikkuWorkflowGraph({ nodes: {...}, wires: {...}, config: {...} })
204
+ * Extract pikkuWorkflowGraph config from an object literal argument
421
205
  */
422
- function extractPikkuWorkflowGraphConfig(node, checker) {
423
- // If it's an identifier, resolve to the declaration
424
- if (ts.isIdentifier(node)) {
425
- const symbol = checker.getSymbolAtLocation(node);
426
- if (symbol) {
427
- const declarations = symbol.getDeclarations();
428
- if (declarations && declarations.length > 0) {
429
- const decl = declarations[0];
430
- if (ts.isVariableDeclaration(decl) && decl.initializer) {
431
- const result = extractPikkuWorkflowGraphConfig(decl.initializer, checker);
432
- if (result) {
433
- // Use the variable name as exportedName
434
- result.exportedName = ts.isIdentifier(decl.name)
435
- ? decl.name.text
436
- : undefined;
437
- }
438
- return result;
439
- }
440
- }
206
+ function extractWorkflowGraphConfig(configArg, checker) {
207
+ let name;
208
+ let description;
209
+ let tags;
210
+ let disabled;
211
+ let nodesNode;
212
+ let configNode;
213
+ for (const prop of configArg.properties) {
214
+ if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
215
+ continue;
216
+ const propName = prop.name.text;
217
+ if (propName === 'name') {
218
+ name = extractStringLiteral(prop.initializer, checker);
441
219
  }
442
- return undefined;
443
- }
444
- // If it's a call expression to pikkuWorkflowGraph
445
- if (ts.isCallExpression(node)) {
446
- const expr = node.expression;
447
- if (ts.isIdentifier(expr) && expr.text === 'pikkuWorkflowGraph') {
448
- const configArg = node.arguments[0];
449
- if (configArg && ts.isObjectLiteralExpression(configArg)) {
450
- let name;
451
- let description;
452
- let tags;
453
- let wires;
454
- let nodesNode;
455
- let configNode;
456
- for (const prop of configArg.properties) {
457
- if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
458
- continue;
459
- const propName = prop.name.text;
460
- if (propName === 'name') {
461
- name = extractStringLiteral(prop.initializer, checker);
462
- }
463
- else if (propName === 'description') {
464
- description = extractStringLiteral(prop.initializer, checker);
465
- }
466
- else if (propName === 'tags' &&
467
- ts.isArrayLiteralExpression(prop.initializer)) {
468
- tags = prop.initializer.elements
469
- .filter(ts.isStringLiteral)
470
- .map((el) => el.text);
471
- }
472
- else if (propName === 'wires' &&
473
- ts.isObjectLiteralExpression(prop.initializer)) {
474
- wires = extractWiresConfig(prop.initializer, checker);
475
- }
476
- else if (propName === 'nodes' &&
477
- ts.isObjectLiteralExpression(prop.initializer)) {
478
- nodesNode = prop.initializer;
479
- }
480
- else if (propName === 'config' &&
481
- ts.isObjectLiteralExpression(prop.initializer)) {
482
- configNode = prop.initializer;
483
- }
484
- }
485
- return { name, description, tags, wires, nodesNode, configNode };
220
+ else if (propName === 'description') {
221
+ description = extractStringLiteral(prop.initializer, checker);
222
+ }
223
+ else if (propName === 'disabled') {
224
+ if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) {
225
+ disabled = true;
486
226
  }
487
227
  }
228
+ else if (propName === 'tags' &&
229
+ ts.isArrayLiteralExpression(prop.initializer)) {
230
+ tags = prop.initializer.elements
231
+ .filter(ts.isStringLiteral)
232
+ .map((el) => el.text);
233
+ }
234
+ else if (propName === 'nodes' &&
235
+ ts.isObjectLiteralExpression(prop.initializer)) {
236
+ nodesNode = prop.initializer;
237
+ }
238
+ else if (propName === 'config' &&
239
+ ts.isObjectLiteralExpression(prop.initializer)) {
240
+ configNode = prop.initializer;
241
+ }
488
242
  }
489
- return undefined;
243
+ return { name, description, tags, disabled, nodesNode, configNode };
490
244
  }
491
245
  /**
492
246
  * Extract graph nodes from the new pikkuWorkflowGraph format
@@ -513,6 +267,10 @@ function extractGraphFromNewFormat(nodesNode, configNode, checker, state) {
513
267
  if (rpcName) {
514
268
  nodeRpcMap[nodeId] = rpcName;
515
269
  state.rpc.invokedFunctions.add(rpcName);
270
+ const funcFile = state.functions.files.get(rpcName);
271
+ if (funcFile && !state.rpc.internalFiles.has(rpcName)) {
272
+ state.rpc.internalFiles.set(rpcName, funcFile);
273
+ }
516
274
  }
517
275
  }
518
276
  // Initialize nodes with their RPC names
@@ -573,87 +331,66 @@ function extractNodeConfigFromObject(obj, checker) {
573
331
  return { next, onError, input };
574
332
  }
575
333
  /**
576
- * Inspector for wireWorkflow() calls with graph definitions
577
- * Detects: wireWorkflow({ wires: {...}, graph: pikkuWorkflowGraphResult })
334
+ * Inspector for pikkuWorkflowGraph() calls
335
+ * Detects: pikkuWorkflowGraph({ nodes: {...}, config: {...} })
336
+ * or: export const x = pikkuWorkflowGraph({...}) where the call is found via variable declaration
578
337
  */
579
338
  export const addWorkflowGraph = (logger, node, checker, state) => {
580
339
  if (!ts.isCallExpression(node)) {
581
340
  return;
582
341
  }
583
342
  const expression = node.expression;
584
- if (!ts.isIdentifier(expression) || expression.text !== 'wireWorkflow') {
343
+ if (!ts.isIdentifier(expression) ||
344
+ expression.text !== 'pikkuWorkflowGraph') {
585
345
  return;
586
346
  }
587
347
  const args = node.arguments;
588
348
  const firstArg = args[0];
589
349
  if (!firstArg) {
590
- logger.critical(ErrorCode.MISSING_FUNC, 'wireWorkflow requires an argument');
350
+ logger.critical(ErrorCode.MISSING_FUNC, 'pikkuWorkflowGraph requires an argument');
591
351
  return;
592
352
  }
593
- const definitionObj = extractDefinitionObject(firstArg);
594
- if (!definitionObj) {
595
- logger.critical(ErrorCode.MISSING_FUNC, 'wireWorkflow requires an object argument');
596
- return;
597
- }
598
- // Check if this is a graph workflow (has 'graph' property)
599
- let graphPropNode;
600
- let enabled = true; // Default to true
601
- for (const prop of definitionObj.properties) {
602
- if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
603
- continue;
604
- const propName = prop.name.text;
605
- if (propName === 'graph') {
606
- graphPropNode = prop.initializer;
607
- }
608
- else if (propName === 'enabled') {
609
- // Check if enabled is explicitly set to false
610
- if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) {
611
- enabled = false;
612
- }
613
- }
614
- // Note: We no longer extract wires from wireWorkflow - they come from pikkuWorkflowGraph
615
- }
616
- // If no graph property, this is a DSL workflow - skip (handled by add-workflow.ts)
617
- if (!graphPropNode) {
353
+ if (!ts.isObjectLiteralExpression(firstArg)) {
354
+ logger.critical(ErrorCode.MISSING_FUNC, 'pikkuWorkflowGraph requires an object argument');
618
355
  return;
619
356
  }
620
- // Extract config from the pikkuWorkflowGraph result
621
- const graphConfig = extractPikkuWorkflowGraphConfig(graphPropNode, checker);
357
+ const graphConfig = extractWorkflowGraphConfig(firstArg, checker);
622
358
  if (!graphConfig) {
623
- logger.critical(ErrorCode.MISSING_NAME, 'wireWorkflow with graph requires a pikkuWorkflowGraph');
359
+ logger.critical(ErrorCode.MISSING_NAME, 'pikkuWorkflowGraph: failed to extract config');
624
360
  return;
625
361
  }
626
- // Use explicit name or fall back to exported variable name
362
+ // Resolve exportedName from variable declaration if this is `export const x = pikkuWorkflowGraph({...})`
363
+ const parent = node.parent;
364
+ if (!graphConfig.exportedName &&
365
+ parent &&
366
+ ts.isVariableDeclaration(parent) &&
367
+ ts.isIdentifier(parent.name)) {
368
+ graphConfig.exportedName = parent.name.text;
369
+ }
627
370
  const workflowName = graphConfig.name || graphConfig.exportedName;
628
371
  if (!workflowName) {
629
- logger.critical(ErrorCode.MISSING_NAME, 'wireWorkflow with graph requires a pikkuWorkflowGraph with a name property or exported variable name');
372
+ logger.critical(ErrorCode.MISSING_NAME, 'pikkuWorkflowGraph requires a name property or exported variable name');
630
373
  return;
631
374
  }
632
- // Extract graph nodes from the new format (nodes + config properties)
633
375
  let graphNodes = {};
634
376
  if (graphConfig.nodesNode) {
635
377
  graphNodes = extractGraphFromNewFormat(graphConfig.nodesNode, graphConfig.configNode, checker, state);
636
378
  }
637
379
  const entryNodeIds = computeEntryNodeIds(graphNodes);
638
- // Use wires from pikkuWorkflowGraph (not from wireWorkflow)
639
- const wires = graphConfig.wires || {};
640
380
  const serialized = {
641
381
  name: workflowName,
642
- pikkuFuncName: workflowName,
382
+ pikkuFuncId: workflowName,
643
383
  source: 'graph',
644
384
  description: graphConfig.description,
645
385
  tags: graphConfig.tags,
646
- wires,
647
386
  nodes: graphNodes,
648
387
  entryNodeIds,
649
388
  };
650
- // Only add if enabled (or not explicitly disabled)
651
- if (enabled) {
652
- state.workflows.graphMeta[workflowName] = serialized;
653
- // Store file path and exported name for import generation
654
- state.workflows.graphFiles.set(workflowName, {
655
- path: node.getSourceFile().fileName,
656
- exportedName: graphConfig.exportedName || workflowName,
657
- });
658
- }
389
+ if (graphConfig.disabled)
390
+ return;
391
+ state.workflows.graphMeta[workflowName] = serialized;
392
+ state.workflows.graphFiles.set(workflowName, {
393
+ path: node.getSourceFile().fileName,
394
+ exportedName: graphConfig.exportedName || workflowName,
395
+ });
659
396
  };