@pikku/inspector 0.11.1 → 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 (189) hide show
  1. package/CHANGELOG.md +26 -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 +327 -59
  9. package/dist/add/add-http-route.d.ts +19 -10
  10. package/dist/add/add-http-route.js +153 -44
  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.d.ts +3 -0
  23. package/dist/add/add-rpc-invocations.js +65 -25
  24. package/dist/add/add-schedule.js +11 -5
  25. package/dist/add/add-secret.d.ts +3 -0
  26. package/dist/add/add-secret.js +82 -0
  27. package/dist/add/add-trigger.d.ts +2 -0
  28. package/dist/add/add-trigger.js +87 -0
  29. package/dist/add/add-variable.d.ts +1 -0
  30. package/dist/add/add-variable.js +8 -0
  31. package/dist/add/add-workflow-graph.d.ts +7 -0
  32. package/dist/add/add-workflow-graph.js +396 -0
  33. package/dist/add/add-workflow.js +124 -26
  34. package/dist/error-codes.d.ts +16 -1
  35. package/dist/error-codes.js +21 -1
  36. package/dist/index.d.ts +9 -5
  37. package/dist/index.js +5 -2
  38. package/dist/inspector.d.ts +1 -1
  39. package/dist/inspector.js +106 -13
  40. package/dist/schema-generator.d.ts +1 -0
  41. package/dist/schema-generator.js +1 -0
  42. package/dist/types-map.js +10 -1
  43. package/dist/types.d.ts +180 -30
  44. package/dist/utils/compute-required-schemas.d.ts +4 -0
  45. package/dist/utils/compute-required-schemas.js +41 -0
  46. package/dist/utils/contract-hashes.d.ts +35 -0
  47. package/dist/utils/contract-hashes.js +202 -0
  48. package/dist/utils/custom-types-generator.d.ts +9 -0
  49. package/dist/utils/custom-types-generator.js +71 -0
  50. package/dist/utils/detect-schema-vendor.d.ts +22 -0
  51. package/dist/utils/detect-schema-vendor.js +76 -0
  52. package/dist/utils/ensure-function-metadata.d.ts +5 -2
  53. package/dist/utils/ensure-function-metadata.js +220 -6
  54. package/dist/utils/extract-function-name.d.ts +5 -16
  55. package/dist/utils/extract-function-name.js +93 -298
  56. package/dist/utils/extract-services.d.ts +2 -1
  57. package/dist/utils/extract-services.js +25 -1
  58. package/dist/utils/filter-inspector-state.js +107 -23
  59. package/dist/utils/get-property-value.d.ts +8 -2
  60. package/dist/utils/get-property-value.js +33 -4
  61. package/dist/utils/hash.d.ts +2 -0
  62. package/dist/utils/hash.js +23 -0
  63. package/dist/utils/middleware.d.ts +7 -30
  64. package/dist/utils/middleware.js +80 -66
  65. package/dist/utils/permissions.d.ts +2 -2
  66. package/dist/utils/permissions.js +10 -10
  67. package/dist/utils/post-process.d.ts +9 -10
  68. package/dist/utils/post-process.js +231 -24
  69. package/dist/utils/resolve-external-package.d.ts +12 -0
  70. package/dist/utils/resolve-external-package.js +34 -0
  71. package/dist/utils/resolve-function-types.d.ts +6 -0
  72. package/dist/utils/resolve-function-types.js +29 -0
  73. package/dist/utils/resolve-identifier.d.ts +10 -0
  74. package/dist/utils/resolve-identifier.js +36 -0
  75. package/dist/utils/resolve-versions.d.ts +2 -0
  76. package/dist/utils/resolve-versions.js +78 -0
  77. package/dist/utils/schema-generator.d.ts +9 -0
  78. package/dist/utils/schema-generator.js +209 -0
  79. package/dist/utils/serialize-inspector-state.d.ts +73 -13
  80. package/dist/utils/serialize-inspector-state.js +102 -6
  81. package/dist/utils/serialize-mcp-json.d.ts +2 -0
  82. package/dist/utils/serialize-mcp-json.js +99 -0
  83. package/dist/utils/serialize-middleware-groups-meta.d.ts +12 -0
  84. package/dist/utils/serialize-middleware-groups-meta.js +28 -0
  85. package/dist/utils/serialize-openapi-json.d.ts +85 -0
  86. package/dist/utils/serialize-openapi-json.js +151 -0
  87. package/dist/utils/serialize-permissions-groups-meta.d.ts +6 -0
  88. package/dist/utils/serialize-permissions-groups-meta.js +31 -0
  89. package/dist/utils/workflow/dsl/deserialize-dsl-workflow.d.ts +24 -0
  90. package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +830 -0
  91. package/dist/{workflow/extract-simple-workflow.d.ts → utils/workflow/dsl/extract-dsl-workflow.d.ts} +4 -2
  92. package/dist/{workflow/extract-simple-workflow.js → utils/workflow/dsl/extract-dsl-workflow.js} +572 -72
  93. package/dist/utils/workflow/dsl/index.d.ts +7 -0
  94. package/dist/utils/workflow/dsl/index.js +7 -0
  95. package/dist/{workflow → utils/workflow/dsl}/patterns.d.ts +21 -0
  96. package/dist/{workflow → utils/workflow/dsl}/patterns.js +90 -10
  97. package/dist/{workflow → utils/workflow/dsl}/validation.d.ts +2 -0
  98. package/dist/{workflow → utils/workflow/dsl}/validation.js +25 -7
  99. package/dist/utils/workflow/graph/convert-dsl-to-graph.d.ts +13 -0
  100. package/dist/utils/workflow/graph/convert-dsl-to-graph.js +318 -0
  101. package/dist/utils/workflow/graph/finalize-workflow-wires.d.ts +3 -0
  102. package/dist/utils/workflow/graph/finalize-workflow-wires.js +276 -0
  103. package/dist/utils/workflow/graph/finalize-workflows.d.ts +2 -0
  104. package/dist/utils/workflow/graph/finalize-workflows.js +75 -0
  105. package/dist/utils/workflow/graph/index.d.ts +8 -0
  106. package/dist/utils/workflow/graph/index.js +8 -0
  107. package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +35 -0
  108. package/dist/utils/workflow/graph/serialize-workflow-graph.js +150 -0
  109. package/dist/utils/workflow/graph/workflow-graph.types.d.ts +203 -0
  110. package/dist/utils/workflow/graph/workflow-graph.types.js +38 -0
  111. package/dist/visit.js +13 -2
  112. package/package.json +26 -4
  113. package/src/add/add-ai-agent.ts +468 -0
  114. package/src/add/add-channel.ts +82 -79
  115. package/src/add/add-cli.ts +49 -20
  116. package/src/add/add-file-with-factory.ts +2 -0
  117. package/src/add/add-functions.ts +429 -71
  118. package/src/add/add-http-route.ts +246 -65
  119. package/src/add/add-http-routes.ts +228 -0
  120. package/src/add/add-keyed-wiring.ts +151 -0
  121. package/src/add/add-mcp-prompt.ts +26 -15
  122. package/src/add/add-mcp-resource.ts +27 -15
  123. package/src/add/add-middleware.ts +482 -80
  124. package/src/add/add-permission.ts +199 -40
  125. package/src/add/add-queue-worker.ts +24 -19
  126. package/src/add/add-rpc-invocations.ts +78 -31
  127. package/src/add/add-schedule.ts +16 -11
  128. package/src/add/add-secret.ts +140 -0
  129. package/src/add/add-trigger.ts +154 -0
  130. package/src/add/add-variable.ts +9 -0
  131. package/src/add/add-workflow-graph.ts +522 -0
  132. package/src/add/add-workflow.ts +117 -30
  133. package/src/error-codes.ts +26 -1
  134. package/src/index.ts +27 -8
  135. package/src/inspector.ts +145 -17
  136. package/src/schema-generator.ts +1 -0
  137. package/src/types-map.ts +12 -1
  138. package/src/types.ts +192 -51
  139. package/src/utils/compute-required-schemas.ts +49 -0
  140. package/src/utils/contract-hashes.test.ts +528 -0
  141. package/src/utils/contract-hashes.ts +290 -0
  142. package/src/utils/custom-types-generator.ts +88 -0
  143. package/src/utils/detect-schema-vendor.ts +90 -0
  144. package/src/utils/ensure-function-metadata.ts +324 -7
  145. package/src/utils/extract-function-name.ts +108 -358
  146. package/src/utils/extract-services.ts +35 -2
  147. package/src/utils/filter-inspector-state.test.ts +34 -20
  148. package/src/utils/filter-inspector-state.ts +140 -31
  149. package/src/utils/get-property-value.ts +50 -5
  150. package/src/utils/hash.ts +26 -0
  151. package/src/utils/middleware.test.ts +204 -0
  152. package/src/utils/middleware.ts +129 -67
  153. package/src/utils/permissions.test.ts +35 -12
  154. package/src/utils/permissions.ts +10 -10
  155. package/src/utils/post-process.ts +283 -43
  156. package/src/utils/resolve-external-package.ts +42 -0
  157. package/src/utils/resolve-function-types.ts +42 -0
  158. package/src/utils/resolve-identifier.ts +46 -0
  159. package/src/utils/resolve-versions.test.ts +249 -0
  160. package/src/utils/resolve-versions.ts +105 -0
  161. package/src/utils/schema-generator.ts +329 -0
  162. package/src/utils/serialize-inspector-state.ts +181 -20
  163. package/src/utils/serialize-mcp-json.ts +145 -0
  164. package/src/utils/serialize-middleware-groups-meta.ts +33 -0
  165. package/src/utils/serialize-openapi-json.ts +277 -0
  166. package/src/utils/serialize-permissions-groups-meta.ts +35 -0
  167. package/src/utils/test-data/inspector-state.json +69 -66
  168. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +1104 -0
  169. package/src/{workflow/extract-simple-workflow.ts → utils/workflow/dsl/extract-dsl-workflow.ts} +678 -85
  170. package/src/utils/workflow/dsl/index.ts +11 -0
  171. package/src/{workflow → utils/workflow/dsl}/patterns.ts +108 -11
  172. package/src/{workflow → utils/workflow/dsl}/validation.ts +34 -7
  173. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +422 -0
  174. package/src/utils/workflow/graph/finalize-workflow-wires.ts +310 -0
  175. package/src/utils/workflow/graph/finalize-workflows.ts +100 -0
  176. package/src/utils/workflow/graph/index.ts +11 -0
  177. package/src/utils/workflow/graph/serialize-workflow-graph.ts +216 -0
  178. package/src/utils/workflow/graph/workflow-graph.types.ts +231 -0
  179. package/src/visit.ts +14 -2
  180. package/tsconfig.tsbuildinfo +1 -1
  181. package/dist/add/add-mcp-tool.d.ts +0 -2
  182. package/dist/add/add-mcp-tool.js +0 -81
  183. package/dist/utils/extract-service-metadata.d.ts +0 -19
  184. package/dist/utils/extract-service-metadata.js +0 -244
  185. package/dist/utils/write-service-metadata.d.ts +0 -13
  186. package/dist/utils/write-service-metadata.js +0 -37
  187. package/src/add/add-mcp-tool.ts +0 -141
  188. package/src/utils/extract-service-metadata.ts +0 -353
  189. package/src/utils/write-service-metadata.ts +0 -51
@@ -3,7 +3,7 @@ import { AddWiring, InspectorState } from '../types.js'
3
3
  import { extractFunctionName } from '../utils/extract-function-name.js'
4
4
  import { extractFunctionNode } from '../utils/extract-function-node.js'
5
5
  import { ErrorCode } from '../error-codes.js'
6
- import { WorkflowStepMeta } from '@pikku/core/workflow'
6
+ import { WorkflowStepMeta, WorkflowContext } from '@pikku/core/workflow'
7
7
  import {
8
8
  extractStringLiteral,
9
9
  isStringLike,
@@ -11,8 +11,62 @@ import {
11
11
  extractDescription,
12
12
  extractDuration,
13
13
  } from '../utils/extract-node-value.js'
14
- import { extractSimpleWorkflow } from '../workflow/extract-simple-workflow.js'
15
14
  import { getCommonWireMetaData } from '../utils/get-property-value.js'
15
+ import { extractDSLWorkflow } from '../utils/workflow/dsl/extract-dsl-workflow.js'
16
+
17
+ /**
18
+ * Recursively check if any step has inline type (non-serializable)
19
+ */
20
+ function hasInlineSteps(steps: WorkflowStepMeta[]): boolean {
21
+ for (const step of steps) {
22
+ if (step.type === 'inline') {
23
+ return true
24
+ } else if (step.type === 'branch') {
25
+ for (const branch of step.branches) {
26
+ if (hasInlineSteps(branch.steps)) return true
27
+ }
28
+ if (step.elseSteps && hasInlineSteps(step.elseSteps)) return true
29
+ } else if (step.type === 'switch' && step.cases) {
30
+ for (const c of step.cases) {
31
+ if (c.steps && hasInlineSteps(c.steps)) return true
32
+ }
33
+ if (step.defaultSteps && hasInlineSteps(step.defaultSteps)) return true
34
+ } else if (step.type === 'fanout' && step.child) {
35
+ if (hasInlineSteps([step.child])) return true
36
+ } else if (step.type === 'parallel' && step.children) {
37
+ if (hasInlineSteps(step.children)) return true
38
+ }
39
+ }
40
+ return false
41
+ }
42
+
43
+ /**
44
+ * Recursively collect all RPC names from workflow steps
45
+ */
46
+ function collectInvokedRPCs(
47
+ steps: WorkflowStepMeta[],
48
+ rpcs: Set<string>
49
+ ): void {
50
+ for (const step of steps) {
51
+ if (step.type === 'rpc' && step.rpcName) {
52
+ rpcs.add(step.rpcName)
53
+ } else if (step.type === 'branch') {
54
+ for (const branch of step.branches) {
55
+ collectInvokedRPCs(branch.steps, rpcs)
56
+ }
57
+ if (step.elseSteps) collectInvokedRPCs(step.elseSteps, rpcs)
58
+ } else if (step.type === 'switch' && step.cases) {
59
+ for (const c of step.cases) {
60
+ if (c.steps) collectInvokedRPCs(c.steps, rpcs)
61
+ }
62
+ if (step.defaultSteps) collectInvokedRPCs(step.defaultSteps, rpcs)
63
+ } else if (step.type === 'fanout' && step.child) {
64
+ collectInvokedRPCs([step.child], rpcs)
65
+ } else if (step.type === 'parallel' && step.children) {
66
+ collectInvokedRPCs(step.children, rpcs)
67
+ }
68
+ }
69
+ }
16
70
 
17
71
  /**
18
72
  * Scan for workflow.do(), workflow.sleep(), and workflow.cancel() calls to extract workflow steps
@@ -87,13 +141,10 @@ function getWorkflowInvocations(
87
141
  }
88
142
  }
89
143
 
90
- // Don't recurse into nested functions - only look at top-level workflow calls
144
+ // Recurse into children, including arrow functions (for Promise.all callbacks)
145
+ // but skip function declarations (which would be separate functions)
91
146
  ts.forEachChild(node, (child) => {
92
- if (
93
- ts.isFunctionDeclaration(child) ||
94
- ts.isFunctionExpression(child) ||
95
- ts.isArrowFunction(child)
96
- ) {
147
+ if (ts.isFunctionDeclaration(child)) {
97
148
  return
98
149
  }
99
150
  getWorkflowInvocations(child, checker, state, workflowName, steps)
@@ -117,11 +168,11 @@ export const addWorkflow: AddWiring = (logger, node, checker, state) => {
117
168
  return
118
169
  }
119
170
 
120
- let wrapperType: 'simple' | 'regular' | null = null
171
+ let wrapperType: 'dsl' | 'regular' | null = null
121
172
  if (expression.text === 'pikkuWorkflowFunc') {
173
+ wrapperType = 'dsl'
174
+ } else if (expression.text === 'pikkuWorkflowComplexFunc') {
122
175
  wrapperType = 'regular'
123
- } else if (expression.text === 'pikkuSimpleWorkflowFunc') {
124
- wrapperType = 'simple'
125
176
  } else {
126
177
  return
127
178
  }
@@ -131,7 +182,7 @@ export const addWorkflow: AddWiring = (logger, node, checker, state) => {
131
182
  }
132
183
 
133
184
  // Extract workflow name and metadata using same logic as add-functions
134
- const { pikkuFuncName, name, exportedName } = extractFunctionName(
185
+ const { pikkuFuncId, name, exportedName } = extractFunctionName(
135
186
  node,
136
187
  checker,
137
188
  state.rootDir
@@ -163,6 +214,7 @@ export const addWorkflow: AddWiring = (logger, node, checker, state) => {
163
214
  workflowName,
164
215
  logger
165
216
  )
217
+ if (metadata.disabled) return
166
218
  tags = metadata.tags
167
219
  summary = metadata.summary
168
220
  description = metadata.description
@@ -191,48 +243,83 @@ export const addWorkflow: AddWiring = (logger, node, checker, state) => {
191
243
 
192
244
  // Track workflow file for wiring generation
193
245
  if (exportedName) {
194
- state.workflows.files.set(pikkuFuncName, {
246
+ state.workflows.files.set(pikkuFuncId, {
195
247
  path: node.getSourceFile().fileName,
196
248
  exportedName,
197
249
  })
198
250
  }
199
251
 
200
252
  let steps: WorkflowStepMeta[] = []
201
- let simple: boolean | undefined = undefined
253
+ let context: WorkflowContext | undefined = undefined
254
+ let dsl: boolean | undefined = undefined
202
255
 
203
- // Try simple workflow extraction first
256
+ // Try DSL workflow extraction first
204
257
  // Pass the whole CallExpression node so findWorkflowFunction can find the arrow function
205
- const result = extractSimpleWorkflow(node, checker)
258
+ const result = extractDSLWorkflow(node, checker)
206
259
 
207
260
  if (result.status === 'ok' && result.steps) {
208
- // Simple extraction succeeded
261
+ // Extraction succeeded
209
262
  steps = result.steps
210
- simple = true
263
+ context = result.context
264
+
265
+ // Check if workflow contains inline steps (non-serializable)
266
+ if (hasInlineSteps(steps)) {
267
+ if (wrapperType === 'dsl') {
268
+ // pikkuWorkflowFunc should not have inline steps
269
+ logger.critical(
270
+ ErrorCode.INVALID_DSL_WORKFLOW,
271
+ `Workflow '${workflowName}' uses pikkuWorkflowFunc but contains inline steps which are not allowed in DSL workflows. Use pikkuWorkflowComplexFunc instead.`
272
+ )
273
+ return
274
+ }
275
+ // pikkuWorkflowComplexFunc with inline steps is marked as non-dsl
276
+ dsl = false
277
+ } else {
278
+ // pikkuWorkflowComplexFunc is always non-dsl, pikkuWorkflowFunc is dsl
279
+ dsl = wrapperType === 'dsl'
280
+ }
281
+
282
+ // Collect all invoked RPCs from workflow steps
283
+ const rpcs = new Set<string>()
284
+ collectInvokedRPCs(steps, rpcs)
285
+ for (const rpc of rpcs) {
286
+ state.rpc.invokedFunctions.add(rpc)
287
+ }
211
288
  } else {
212
- // Simple extraction failed
213
- if (wrapperType === 'simple') {
214
- // For pikkuSimpleWorkflowFunc, this is a critical error
289
+ // DSL extraction failed
290
+ if (wrapperType === 'dsl') {
291
+ // For pikkuWorkflowFunc, this is a critical error
292
+ // But still track RPC invocations for function registration
293
+ getWorkflowInvocations(resolvedFunc, checker, state, workflowName, steps)
215
294
  logger.critical(
216
- ErrorCode.INVALID_SIMPLE_WORKFLOW,
217
- `Workflow '${workflowName}' uses pikkuSimpleWorkflowFunc but does not conform to simple workflow DSL:\n${result.reason || 'Unknown error'}`
295
+ ErrorCode.INVALID_DSL_WORKFLOW,
296
+ `Workflow '${workflowName}' uses pikkuWorkflowFunc but does not conform to DSL workflow rules:\n${result.reason || 'Unknown error'}`
218
297
  )
219
298
  return
220
299
  } else {
221
- // For pikkuWorkflowFunc, fall back to basic extraction
300
+ // For pikkuWorkflowComplexFunc, fall back to basic extraction
222
301
  logger.debug(
223
- `Workflow '${workflowName}' could not be extracted as simple workflow: ${result.reason || 'Unknown error'}. Falling back to basic extraction.`
302
+ `Workflow '${workflowName}' could not be extracted as DSL workflow: ${result.reason || 'Unknown error'}. Falling back to basic extraction.`
224
303
  )
225
- simple = false
304
+ dsl = false
226
305
  }
227
306
  }
228
307
 
229
- getWorkflowInvocations(resolvedFunc, checker, state, workflowName, steps)
308
+ /**
309
+ * For non-dsl workflows or pikkuWorkflowComplexFunc, run basic extraction
310
+ * to ensure all RPC invocations are tracked for function registration.
311
+ * This catches RPCs in Promise.all callbacks and other patterns DSL can't extract.
312
+ */
313
+ if (!dsl || wrapperType === 'regular') {
314
+ getWorkflowInvocations(resolvedFunc, checker, state, workflowName, steps)
315
+ }
230
316
 
231
317
  state.workflows.meta[workflowName] = {
232
- pikkuFuncName,
233
- workflowName,
318
+ pikkuFuncId,
319
+ name: workflowName,
234
320
  steps,
235
- simple,
321
+ context,
322
+ dsl,
236
323
  summary,
237
324
  description,
238
325
  errors,
@@ -11,6 +11,7 @@ export enum ErrorCode {
11
11
  // Validation errors
12
12
  MISSING_NAME = 'PKU111',
13
13
  MISSING_DESCRIPTION = 'PKU123',
14
+ INVALID_VALUE = 'PKU124',
14
15
  MISSING_URI = 'PKU220',
15
16
  MISSING_FUNC = 'PKU236',
16
17
  INVALID_TAGS_TYPE = 'PKU247',
@@ -21,7 +22,7 @@ export enum ErrorCode {
21
22
  CLI_CLIENTSIDE_RENDERER_HAS_SERVICES = 'PKU672',
22
23
  DYNAMIC_STEP_NAME = 'PKU529',
23
24
  WORKFLOW_ORCHESTRATOR_NOT_CONFIGURED = 'PKU600',
24
- INVALID_SIMPLE_WORKFLOW = 'PKU641',
25
+ INVALID_DSL_WORKFLOW = 'PKU641',
25
26
 
26
27
  // Configuration errors
27
28
  CONFIG_TYPE_NOT_FOUND = 'PKU426',
@@ -29,11 +30,16 @@ export enum ErrorCode {
29
30
  SCHEMA_NO_ROOT = 'PKU431',
30
31
  SCHEMA_GENERATION_ERROR = 'PKU456',
31
32
  SCHEMA_LOAD_ERROR = 'PKU488',
33
+ INLINE_SCHEMA = 'PKU489',
32
34
 
33
35
  // Function errors
34
36
  FUNCTION_METADATA_NOT_FOUND = 'PKU559',
35
37
  HANDLER_NOT_RESOLVED = 'PKU568',
36
38
 
39
+ // HTTP Route errors
40
+ ROUTE_PARAM_MISMATCH = 'PKU571',
41
+ ROUTE_QUERY_MISMATCH = 'PKU572',
42
+
37
43
  // Middleware/Permission errors
38
44
  MIDDLEWARE_HANDLER_INVALID = 'PKU685',
39
45
  MIDDLEWARE_TAG_INVALID = 'PKU715',
@@ -44,6 +50,25 @@ export enum ErrorCode {
44
50
  PERMISSION_EMPTY_ARRAY = 'PKU937',
45
51
  PERMISSION_PATTERN_INVALID = 'PKU975',
46
52
 
53
+ // Versioning errors
54
+ DUPLICATE_FUNCTION_VERSION = 'PKU850',
55
+
56
+ // Contract versioning errors
57
+ MANIFEST_MISSING = 'PKU860',
58
+ FUNCTION_VERSION_MODIFIED = 'PKU861',
59
+ CONTRACT_CHANGED_REQUIRES_BUMP = 'PKU862',
60
+ VERSION_REGRESSION_OR_CONFLICT = 'PKU863',
61
+ VERSION_GAP_NOT_ALLOWED = 'PKU864',
62
+ MANIFEST_INTEGRITY_ERROR = 'PKU865',
63
+
64
+ // Model configuration errors
65
+ MISSING_MODEL = 'PKU145',
66
+ INVALID_MODEL = 'PKU146',
67
+
68
+ // Optimization diagnostics
69
+ SERVICES_NOT_DESTRUCTURED = 'PKU410',
70
+ WIRES_NOT_DESTRUCTURED = 'PKU411',
71
+
47
72
  // Feature Flag
48
73
  WORKFLOW_MULTI_QUEUE_NOT_SUPPORTED = 'PKU901',
49
74
  }
package/src/index.ts CHANGED
@@ -1,12 +1,7 @@
1
1
  export { inspect, getInitialInspectorState } from './inspector.js'
2
- export { getFilesAndMethods } from './utils/get-files-and-methods.js'
3
2
  export type { TypesMap } from './types-map.js'
4
3
  export type * from './types.js'
5
- export type { InspectorState } from './types.js'
6
- export type {
7
- FilesAndMethods,
8
- FilesAndMethodsErrors,
9
- } from './utils/get-files-and-methods.js'
4
+ export type { FilesAndMethodsErrors } from './utils/get-files-and-methods.js'
10
5
  export { ErrorCode } from './error-codes.js'
11
6
  export {
12
7
  serializeInspectorState,
@@ -14,5 +9,29 @@ export {
14
9
  } from './utils/serialize-inspector-state.js'
15
10
  export type { SerializableInspectorState } from './utils/serialize-inspector-state.js'
16
11
  export { filterInspectorState } from './utils/filter-inspector-state.js'
17
- export { writeAllServiceMetadata } from './utils/write-service-metadata.js'
18
- export type { ServiceMetadata } from './utils/extract-service-metadata.js'
12
+ export {
13
+ generateCustomTypes,
14
+ sanitizeTypeName,
15
+ } from './utils/custom-types-generator.js'
16
+ export {
17
+ createEmptyManifest,
18
+ serializeManifest,
19
+ } from './utils/contract-hashes.js'
20
+ export type {
21
+ ContractEntry,
22
+ VersionValidateError,
23
+ VersionManifest,
24
+ VersionManifestEntry,
25
+ } from './utils/contract-hashes.js'
26
+ export { serializeMCPJson } from './utils/serialize-mcp-json.js'
27
+ export type { OpenAPISpecInfo } from './utils/serialize-openapi-json.js'
28
+ export {
29
+ deserializeDslWorkflow,
30
+ deserializeGraphWorkflow,
31
+ deserializeAllDslWorkflows,
32
+ } from './utils/workflow/dsl/index.js'
33
+ export { getFilesAndMethods } from './utils/get-files-and-methods.js'
34
+ export type {
35
+ SerializedWorkflowGraph,
36
+ SerializedWorkflowGraphs,
37
+ } from './utils/workflow/graph/index.js'
package/src/inspector.ts CHANGED
@@ -7,8 +7,31 @@ import { getFilesAndMethods } from './utils/get-files-and-methods.js'
7
7
  import { findCommonAncestor } from './utils/find-root-dir.js'
8
8
  import {
9
9
  aggregateRequiredServices,
10
- extractServiceInterfaceMetadata,
10
+ validateSecretOverrides,
11
+ validateAgentModels,
12
+ validateAgentOverrides,
13
+ computeResolvedIOTypes,
14
+ computeMiddlewareGroupsMeta,
15
+ computePermissionsGroupsMeta,
16
+ computeRequiredSchemas,
17
+ computeDiagnostics,
11
18
  } from './utils/post-process.js'
19
+ import { generateOpenAPISpec } from './utils/serialize-openapi-json.js'
20
+ import { pikkuState } from '@pikku/core'
21
+ import { resolveLatestVersions } from './utils/resolve-versions.js'
22
+ import { finalizeWorkflows } from './utils/workflow/graph/finalize-workflows.js'
23
+ import {
24
+ finalizeWorkflowHelperTypes,
25
+ finalizeWorkflowWires,
26
+ } from './utils/workflow/graph/finalize-workflow-wires.js'
27
+ import { generateAllSchemas } from './utils/schema-generator.js'
28
+ import {
29
+ computeContractHashes,
30
+ extractContractsFromMeta,
31
+ updateManifest,
32
+ createEmptyManifest,
33
+ validateContracts,
34
+ } from './utils/contract-hashes.js'
12
35
 
13
36
  /**
14
37
  * Creates an initial/empty inspector state with all required properties initialized
@@ -29,6 +52,8 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
29
52
  filesAndMethods: {},
30
53
  filesAndMethodsErrors: new Map(),
31
54
  typesLookup: new Map(),
55
+ schemaLookup: new Map(),
56
+ schemas: {},
32
57
  functions: {
33
58
  typesMap: new TypesMap(),
34
59
  meta: {},
@@ -53,6 +78,11 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
53
78
  files: new Set(),
54
79
  meta: {},
55
80
  },
81
+ triggers: {
82
+ meta: {},
83
+ sourceMeta: {},
84
+ files: new Set(),
85
+ },
56
86
  scheduledTasks: {
57
87
  meta: {},
58
88
  files: new Set(),
@@ -64,6 +94,9 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
64
94
  workflows: {
65
95
  meta: {},
66
96
  files: new Map(),
97
+ graphMeta: {},
98
+ graphFiles: new Map(),
99
+ invokedWorkflows: new Set(),
67
100
  },
68
101
  rpc: {
69
102
  internalMeta: {},
@@ -71,6 +104,7 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
71
104
  exposedMeta: {},
72
105
  exposedFiles: new Map(),
73
106
  invokedFunctions: new Set(),
107
+ usedExternalPackages: new Set(),
74
108
  },
75
109
  mcpEndpoints: {
76
110
  resourcesMeta: {},
@@ -78,6 +112,10 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
78
112
  promptsMeta: {},
79
113
  files: new Set(),
80
114
  },
115
+ agents: {
116
+ agentsMeta: {},
117
+ files: new Map(),
118
+ },
81
119
  cli: {
82
120
  meta: {
83
121
  programs: {},
@@ -85,12 +123,39 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
85
123
  },
86
124
  files: new Set(),
87
125
  },
88
- middleware: {
126
+ nodes: {
89
127
  meta: {},
128
+ files: new Set(),
129
+ },
130
+ secrets: {
131
+ definitions: [],
132
+ files: new Set(),
133
+ },
134
+ variables: {
135
+ definitions: [],
136
+ files: new Set(),
137
+ },
138
+ manifest: {
139
+ initial: null,
140
+ current: null,
141
+ errors: [],
142
+ },
143
+ middleware: {
144
+ definitions: {},
145
+ instances: {},
146
+ tagMiddleware: new Map(),
147
+ },
148
+ channelMiddleware: {
149
+ definitions: {},
150
+ instances: {},
90
151
  tagMiddleware: new Map(),
91
152
  },
153
+ aiMiddleware: {
154
+ definitions: {},
155
+ },
92
156
  permissions: {
93
- meta: {},
157
+ definitions: {},
158
+ instances: {},
94
159
  tagPermissions: new Map(),
95
160
  },
96
161
  serviceAggregation: {
@@ -101,22 +166,41 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
101
166
  allSingletonServices: [],
102
167
  allWireServices: [],
103
168
  },
104
- serviceMetadata: [],
169
+ resolvedIOTypes: {},
170
+ middlewareGroupsMeta: {
171
+ definitions: {},
172
+ instances: {},
173
+ httpGroups: {},
174
+ tagGroups: {},
175
+ channelMiddleware: {
176
+ definitions: {},
177
+ instances: {},
178
+ tagGroups: {},
179
+ },
180
+ },
181
+ permissionsGroupsMeta: {
182
+ definitions: {},
183
+ httpGroups: {},
184
+ tagGroups: {},
185
+ },
186
+ requiredSchemas: new Set(),
187
+ openAPISpec: null,
188
+ diagnostics: [],
105
189
  }
106
190
  }
107
191
 
108
- export const inspect = (
192
+ export const inspect = async (
109
193
  logger: InspectorLogger,
110
194
  routeFiles: string[],
111
195
  options: InspectorOptions = {}
112
- ): InspectorState => {
196
+ ): Promise<InspectorState> => {
113
197
  const startProgram = performance.now()
114
198
  const program = ts.createProgram(routeFiles, {
115
199
  target: ts.ScriptTarget.ESNext,
116
- module: ts.ModuleKind.CommonJS,
200
+ module: ts.ModuleKind.Node16,
117
201
  skipLibCheck: true,
118
202
  skipDefaultLibCheck: true,
119
- moduleResolution: ts.ModuleResolutionKind.Node10,
203
+ moduleResolution: ts.ModuleResolutionKind.Node16,
120
204
  types: [],
121
205
  allowJs: false,
122
206
  checkJs: false,
@@ -131,15 +215,19 @@ export const inspect = (
131
215
  `Got type checker in ${(performance.now() - startChecker).toFixed(2)}ms`
132
216
  )
133
217
 
218
+ // Use provided rootDir or infer from source files
219
+ const rootDir = options.rootDir || findCommonAncestor(routeFiles)
220
+
134
221
  const startSourceFiles = performance.now()
135
- const sourceFiles = program.getSourceFiles()
222
+ // Filter source files to only include files within the project rootDir
223
+ // This prevents picking up types from external packages (including workspace symlinks)
224
+ const sourceFiles = program
225
+ .getSourceFiles()
226
+ .filter((sf) => sf.fileName.startsWith(rootDir))
136
227
  logger.debug(
137
228
  `Got source files in ${(performance.now() - startSourceFiles).toFixed(2)}ms`
138
229
  )
139
230
 
140
- // Infer root directory from source files
141
- const rootDir = findCommonAncestor(routeFiles)
142
-
143
231
  const state = getInitialInspectorState(rootDir)
144
232
 
145
233
  // First sweep: add all functions
@@ -164,6 +252,32 @@ export const inspect = (
164
252
  logger.debug(
165
253
  `Visit routes phase completed in ${(performance.now() - startRoutes).toFixed(2)}ms`
166
254
  )
255
+
256
+ resolveLatestVersions(state, logger)
257
+
258
+ if (options.schemaConfig) {
259
+ state.schemas = await generateAllSchemas(
260
+ logger,
261
+ options.schemaConfig,
262
+ state
263
+ )
264
+ computeContractHashes(
265
+ state.schemas,
266
+ state.functions.typesMap,
267
+ state.functions.meta
268
+ )
269
+ computeRequiredSchemas(state, options)
270
+ }
271
+
272
+ state.manifest.initial = options.manifest ?? null
273
+ const contracts = extractContractsFromMeta(state.functions.meta)
274
+ const baseManifest = state.manifest.initial ?? createEmptyManifest()
275
+ state.manifest.current = updateManifest(baseManifest, contracts)
276
+ state.manifest.errors = validateContracts(baseManifest, contracts).errors
277
+
278
+ finalizeWorkflows(state)
279
+ finalizeWorkflowHelperTypes(state)
280
+ finalizeWorkflowWires(state)
167
281
  }
168
282
 
169
283
  // Populate filesAndMethods
@@ -182,11 +296,25 @@ export const inspect = (
182
296
  `Aggregate required services completed in ${(performance.now() - startAggregate).toFixed(2)}ms`
183
297
  )
184
298
 
185
- const startServiceMeta = performance.now()
186
- extractServiceInterfaceMetadata(state, checker)
187
- logger.debug(
188
- `Extract service metadata completed in ${(performance.now() - startServiceMeta).toFixed(2)}ms`
189
- )
299
+ computeResolvedIOTypes(state)
300
+ computeMiddlewareGroupsMeta(state)
301
+ computePermissionsGroupsMeta(state)
302
+ computeDiagnostics(state)
303
+
304
+ if (options.openAPI) {
305
+ state.openAPISpec = await generateOpenAPISpec(
306
+ logger,
307
+ state.functions.meta,
308
+ state.http.meta,
309
+ state.schemas,
310
+ options.openAPI.additionalInfo,
311
+ pikkuState(null, 'misc', 'errors')
312
+ )
313
+ }
314
+
315
+ validateSecretOverrides(logger, state, options.externalPackages)
316
+ validateAgentModels(logger, state, options.modelConfig)
317
+ validateAgentOverrides(logger, state, options.modelConfig)
190
318
  }
191
319
 
192
320
  return state
@@ -0,0 +1 @@
1
+ export { generateAllSchemas } from './utils/schema-generator.js'
package/src/types-map.ts CHANGED
@@ -28,7 +28,18 @@ export class TypesMap {
28
28
  uniqueName: string
29
29
  path: string | null
30
30
  } {
31
- if (['string', 'number', 'boolean', 'null'].includes(name)) {
31
+ if (
32
+ [
33
+ 'string',
34
+ 'number',
35
+ 'boolean',
36
+ 'null',
37
+ 'undefined',
38
+ 'void',
39
+ 'unknown',
40
+ 'never',
41
+ ].includes(name)
42
+ ) {
32
43
  return {
33
44
  originalName: name,
34
45
  uniqueName: name,