@pikku/inspector 0.10.2 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/add/add-channel.js +11 -10
  3. package/dist/add/add-file-with-factory.js +10 -10
  4. package/dist/add/add-functions.js +65 -44
  5. package/dist/add/add-http-route.js +5 -4
  6. package/dist/add/add-mcp-prompt.js +6 -5
  7. package/dist/add/add-mcp-resource.js +6 -5
  8. package/dist/add/add-mcp-tool.js +6 -5
  9. package/dist/add/add-middleware.js +1 -1
  10. package/dist/add/add-permission.js +1 -1
  11. package/dist/add/add-queue-worker.js +6 -5
  12. package/dist/add/add-schedule.js +5 -4
  13. package/dist/add/add-workflow.d.ts +6 -0
  14. package/dist/add/add-workflow.js +178 -0
  15. package/dist/error-codes.d.ts +5 -1
  16. package/dist/error-codes.js +5 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.js +1 -0
  19. package/dist/inspector.js +13 -5
  20. package/dist/types.d.ts +27 -9
  21. package/dist/utils/extract-function-node.d.ts +10 -0
  22. package/dist/utils/extract-function-node.js +38 -0
  23. package/dist/utils/extract-node-value.d.ts +32 -0
  24. package/dist/utils/extract-node-value.js +103 -0
  25. package/dist/utils/extract-service-metadata.d.ts +19 -0
  26. package/dist/utils/extract-service-metadata.js +244 -0
  27. package/dist/utils/get-files-and-methods.d.ts +3 -3
  28. package/dist/utils/get-files-and-methods.js +3 -3
  29. package/dist/utils/get-property-value.d.ts +13 -6
  30. package/dist/utils/get-property-value.js +51 -43
  31. package/dist/utils/post-process.d.ts +9 -0
  32. package/dist/utils/post-process.js +30 -3
  33. package/dist/utils/serialize-inspector-state.d.ts +21 -4
  34. package/dist/utils/serialize-inspector-state.js +18 -8
  35. package/dist/utils/type-utils.d.ts +4 -0
  36. package/dist/utils/type-utils.js +55 -0
  37. package/dist/utils/write-service-metadata.d.ts +13 -0
  38. package/dist/utils/write-service-metadata.js +37 -0
  39. package/dist/visit.js +4 -2
  40. package/dist/workflow/extract-simple-workflow.d.ts +15 -0
  41. package/dist/workflow/extract-simple-workflow.js +803 -0
  42. package/dist/workflow/patterns.d.ts +39 -0
  43. package/dist/workflow/patterns.js +138 -0
  44. package/dist/workflow/validation.d.ts +28 -0
  45. package/dist/workflow/validation.js +124 -0
  46. package/package.json +4 -4
  47. package/src/add/add-channel.ts +37 -17
  48. package/src/add/add-file-with-factory.ts +10 -10
  49. package/src/add/add-functions.ts +81 -57
  50. package/src/add/add-http-route.ts +10 -5
  51. package/src/add/add-mcp-prompt.ts +11 -7
  52. package/src/add/add-mcp-resource.ts +11 -7
  53. package/src/add/add-mcp-tool.ts +11 -7
  54. package/src/add/add-middleware.ts +1 -1
  55. package/src/add/add-permission.ts +1 -1
  56. package/src/add/add-queue-worker.ts +11 -12
  57. package/src/add/add-schedule.ts +10 -5
  58. package/src/add/add-workflow.ts +241 -0
  59. package/src/error-codes.ts +6 -0
  60. package/src/index.ts +2 -0
  61. package/src/inspector.ts +19 -5
  62. package/src/types.ts +24 -9
  63. package/src/utils/extract-function-node.ts +58 -0
  64. package/src/utils/extract-node-value.ts +132 -0
  65. package/src/utils/extract-service-metadata.ts +353 -0
  66. package/src/utils/filter-inspector-state.test.ts +3 -3
  67. package/src/utils/filter-utils.test.ts +45 -51
  68. package/src/utils/get-files-and-methods.ts +11 -11
  69. package/src/utils/get-property-value.ts +60 -53
  70. package/src/utils/permissions.test.ts +3 -3
  71. package/src/utils/post-process.ts +56 -3
  72. package/src/utils/serialize-inspector-state.ts +37 -15
  73. package/src/utils/test-data/inspector-state.json +13 -9
  74. package/src/utils/type-utils.ts +69 -0
  75. package/src/utils/write-service-metadata.ts +51 -0
  76. package/src/visit.ts +5 -3
  77. package/src/workflow/extract-simple-workflow.ts +1035 -0
  78. package/src/workflow/patterns.ts +182 -0
  79. package/src/workflow/validation.ts +153 -0
  80. package/tsconfig.tsbuildinfo +1 -1
  81. package/src/add/add-mcp-prompt.ts.tmp +0 -0
  82. package/src/add/add-mcp-resource.ts.tmp +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## 0.11.0
2
+
3
+ ## 0.11.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 4b811db: chore: updating all dependencies
8
+ - 28aeb7f: breaking: extract docs in the wiring meta
9
+ - ce902b1: feat: adding in pikkuSimpleWorkflowFunc
10
+ - 06e1a31: breaking: change session services to wire services
11
+ - Updated dependencies [4b811db]
12
+ - Updated dependencies [e12a00c]
13
+ - Updated dependencies [4579434]
14
+ - Updated dependencies [28aeb7f]
15
+ - Updated dependencies [ce902b1]
16
+ - Updated dependencies [06e1a31]
17
+ - @pikku/core@0.11.1
18
+
19
+ ### Minor Changes
20
+
21
+ - Add workflow inspection and analysis
22
+ - Add enhanced type extraction utilities
23
+
1
24
  # @pikku/inspector
2
25
 
3
26
  ## 0.10.2
@@ -1,6 +1,6 @@
1
1
  import * as ts from 'typescript';
2
2
  import { ErrorCode } from '../error-codes.js';
3
- import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
3
+ import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
4
4
  import { pathToRegexp } from 'path-to-regexp';
5
5
  import { extractFunctionName } from '../utils/extract-function-name.js';
6
6
  import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
@@ -143,7 +143,7 @@ export function addMessagesRoutes(logger, obj, state, checker) {
143
143
  if (fnMeta) {
144
144
  // Resolve middleware for this route
145
145
  const routeTags = ts.isObjectLiteralExpression(init)
146
- ? getPropertyTags(init, 'channel', channelKey, logger)
146
+ ? getCommonWireMetaData(init, 'Channel message', routeKey, logger).tags
147
147
  : undefined;
148
148
  const routeMiddleware = ts.isObjectLiteralExpression(init)
149
149
  ? resolveMiddleware(state, init, routeTags, checker)
@@ -165,7 +165,7 @@ export function addMessagesRoutes(logger, obj, state, checker) {
165
165
  if (fnMeta) {
166
166
  // Resolve middleware for this route
167
167
  const routeTags = ts.isObjectLiteralExpression(init)
168
- ? getPropertyTags(init, 'channel', channelKey, logger)
168
+ ? getCommonWireMetaData(init, 'Channel message', routeKey, logger).tags
169
169
  : undefined;
170
170
  const routeMiddleware = ts.isObjectLiteralExpression(init)
171
171
  ? resolveMiddleware(state, init, routeTags, checker)
@@ -198,7 +198,7 @@ export function addMessagesRoutes(logger, obj, state, checker) {
198
198
  if (fnMeta) {
199
199
  // Resolve middleware for this route
200
200
  const routeTags = ts.isObjectLiteralExpression(init)
201
- ? getPropertyTags(init, 'channel', channelKey, logger)
201
+ ? getCommonWireMetaData(init, 'Channel message', routeKey, logger).tags
202
202
  : undefined;
203
203
  const routeMiddleware = ts.isObjectLiteralExpression(init)
204
204
  ? resolveMiddleware(state, init, routeTags, checker)
@@ -217,7 +217,7 @@ export function addMessagesRoutes(logger, obj, state, checker) {
217
217
  if (fnMeta) {
218
218
  // Resolve middleware for this route
219
219
  const routeTags = ts.isObjectLiteralExpression(init)
220
- ? getPropertyTags(init, 'channel', channelKey, logger)
220
+ ? getCommonWireMetaData(init, 'Channel message', routeKey, logger).tags
221
221
  : undefined;
222
222
  const routeMiddleware = ts.isObjectLiteralExpression(init)
223
223
  ? resolveMiddleware(state, init, routeTags, checker)
@@ -281,7 +281,7 @@ export function addMessagesRoutes(logger, obj, state, checker) {
281
281
  if (fnMeta) {
282
282
  // Resolve middleware for this route
283
283
  const routeTags = ts.isObjectLiteralExpression(init)
284
- ? getPropertyTags(init, 'channel', channelKey, logger)
284
+ ? getCommonWireMetaData(init, 'Channel message', routeKey, logger).tags
285
285
  : undefined;
286
286
  const routeMiddleware = ts.isObjectLiteralExpression(init)
287
287
  ? resolveMiddleware(state, init, routeTags, checker)
@@ -310,7 +310,7 @@ export function addMessagesRoutes(logger, obj, state, checker) {
310
310
  // Resolve middleware and permissions for this route
311
311
  // Check if the route config is an object literal with middleware/permissions
312
312
  const routeTags = ts.isObjectLiteralExpression(init)
313
- ? getPropertyTags(init, 'channel', channelKey, logger)
313
+ ? getCommonWireMetaData(init, 'Channel message', routeKey, logger).tags
314
314
  : undefined;
315
315
  const routeMiddleware = ts.isObjectLiteralExpression(init)
316
316
  ? resolveMiddleware(state, init, routeTags, checker)
@@ -349,8 +349,7 @@ export const addChannel = (logger, node, checker, state, options) => {
349
349
  .keys.filter((k) => k.type === 'param')
350
350
  .map((k) => k.name)
351
351
  : [];
352
- const docs = getPropertyValue(obj, 'docs');
353
- const tags = getPropertyTags(obj, 'Channel', route, logger);
352
+ const { tags, summary, description, errors } = getCommonWireMetaData(obj, 'Channel', name, logger);
354
353
  const query = getPropertyValue(obj, 'query');
355
354
  const connect = getPropertyAssignmentInitializer(obj, 'onConnect', true, checker);
356
355
  const disconnect = getPropertyAssignmentInitializer(obj, 'onDisconnect', true, checker);
@@ -421,7 +420,9 @@ export const addChannel = (logger, node, checker, state, options) => {
421
420
  : null,
422
421
  message,
423
422
  messageWirings,
424
- docs: docs ?? undefined,
423
+ summary,
424
+ description,
425
+ errors,
425
426
  tags: tags ?? undefined,
426
427
  middleware,
427
428
  };
@@ -4,7 +4,7 @@ import { extractServicesFromFunction } from '../utils/extract-services.js';
4
4
  const wrapperFunctionMap = {
5
5
  pikkuConfig: 'CreateConfig',
6
6
  pikkuServices: 'CreateSingletonServices',
7
- pikkuSessionServices: 'CreateSessionServices',
7
+ pikkuWireServices: 'CreateWireServices',
8
8
  };
9
9
  export const addFileWithFactory = (node, checker, methods = new Map(), expectedTypeName, state) => {
10
10
  if (ts.isVariableDeclaration(node)) {
@@ -37,8 +37,8 @@ export const addFileWithFactory = (node, checker, methods = new Map(), expectedT
37
37
  typePath: typeDeclarationPath,
38
38
  });
39
39
  methods.set(fileName, variables);
40
- // Extract singleton services for CreateSessionServices factories
41
- if (expectedTypeName === 'CreateSessionServices' &&
40
+ // Extract singleton services for CreateWireServices factories
41
+ if (expectedTypeName === 'CreateWireServices' &&
42
42
  state &&
43
43
  callExpression.arguments.length > 0) {
44
44
  const firstArg = callExpression.arguments[0];
@@ -51,7 +51,7 @@ export const addFileWithFactory = (node, checker, methods = new Map(), expectedT
51
51
  }
52
52
  if (functionNode) {
53
53
  const servicesMeta = extractServicesFromFunction(functionNode);
54
- state.sessionServicesMeta.set(variableName, servicesMeta.services);
54
+ state.wireServicesMeta.set(variableName, servicesMeta.services);
55
55
  }
56
56
  }
57
57
  return; // Early return since we found a match
@@ -77,8 +77,8 @@ export const addFileWithFactory = (node, checker, methods = new Map(), expectedT
77
77
  typePath: typeDeclarationPath,
78
78
  });
79
79
  methods.set(fileName, variables);
80
- // Extract singleton services for CreateSessionServices factories
81
- if (expectedTypeName === 'CreateSessionServices' &&
80
+ // Extract singleton services for CreateWireServices factories
81
+ if (expectedTypeName === 'CreateWireServices' &&
82
82
  state &&
83
83
  node.initializer) {
84
84
  let functionNode;
@@ -90,7 +90,7 @@ export const addFileWithFactory = (node, checker, methods = new Map(), expectedT
90
90
  }
91
91
  if (functionNode) {
92
92
  const servicesMeta = extractServicesFromFunction(functionNode);
93
- state.sessionServicesMeta.set(variableName, servicesMeta.services);
93
+ state.wireServicesMeta.set(variableName, servicesMeta.services);
94
94
  }
95
95
  }
96
96
  }
@@ -111,8 +111,8 @@ export const addFileWithFactory = (node, checker, methods = new Map(), expectedT
111
111
  typePath: typeDeclarationPath,
112
112
  });
113
113
  methods.set(fileName, variables);
114
- // Extract singleton services for CreateSessionServices factories
115
- if (expectedTypeName === 'CreateSessionServices' &&
114
+ // Extract singleton services for CreateWireServices factories
115
+ if (expectedTypeName === 'CreateWireServices' &&
116
116
  state &&
117
117
  node.initializer) {
118
118
  let functionNode;
@@ -124,7 +124,7 @@ export const addFileWithFactory = (node, checker, methods = new Map(), expectedT
124
124
  }
125
125
  if (functionNode) {
126
126
  const servicesMeta = extractServicesFromFunction(functionNode);
127
- state.sessionServicesMeta.set(variableName, servicesMeta.services);
127
+ state.wireServicesMeta.set(variableName, servicesMeta.services);
128
128
  }
129
129
  }
130
130
  }
@@ -1,7 +1,7 @@
1
1
  import * as ts from 'typescript';
2
2
  import { extractFunctionName } from '../utils/extract-function-name.js';
3
- import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
4
- import { getPropertyValue } from '../utils/get-property-value.js';
3
+ import { extractFunctionNode } from '../utils/extract-function-node.js';
4
+ import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
5
5
  import { resolveMiddleware } from '../utils/middleware.js';
6
6
  const isValidVariableName = (name) => {
7
7
  const regex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
@@ -232,41 +232,34 @@ export const addFunctions = (logger, node, checker, state) => {
232
232
  return;
233
233
  const { pikkuFuncName, name, explicitName, exportedName } = extractFunctionName(node, checker, state.rootDir);
234
234
  let tags;
235
+ let summary;
236
+ let description;
237
+ let errors;
235
238
  let expose;
236
- let docs;
239
+ let internal;
237
240
  let objectNode;
238
- // determine the actual handler expression:
239
- // either the `func` prop or the first argument directly
240
- let handlerNode = args[0];
241
- let isDirectFunction = true; // Default to direct function format
242
- if (ts.isObjectLiteralExpression(handlerNode)) {
243
- isDirectFunction = false; // This is object format with func property
244
- objectNode = handlerNode;
245
- tags = getPropertyValue(handlerNode, 'tags') || undefined;
246
- expose = getPropertyValue(handlerNode, 'expose');
247
- docs = getPropertyValue(handlerNode, 'docs');
248
- const fnProp = getPropertyAssignmentInitializer(handlerNode, 'func', true, checker);
249
- if (!fnProp ||
250
- (!ts.isArrowFunction(fnProp) && !ts.isFunctionExpression(fnProp))) {
251
- logger.error(`• No valid 'func' property found for ${pikkuFuncName}.`);
252
- // Create stub metadata to prevent "function not found" errors in wirings
253
- state.functions.meta[pikkuFuncName] = {
254
- pikkuFuncName,
255
- name,
256
- services: { optimized: false, services: [] },
257
- inputSchemaName: null,
258
- outputSchemaName: null,
259
- inputs: [],
260
- outputs: [],
261
- middleware: undefined,
262
- };
263
- return;
264
- }
265
- handlerNode = fnProp;
241
+ // Extract the function node using shared utility
242
+ const firstArg = args[0];
243
+ const { funcNode: handlerNode, resolvedFunc, isDirectFunction, } = extractFunctionNode(firstArg, checker);
244
+ // Extract config properties if using object form
245
+ if (ts.isObjectLiteralExpression(firstArg)) {
246
+ objectNode = firstArg;
247
+ const metadata = getCommonWireMetaData(firstArg, 'Function', name, logger);
248
+ tags = metadata.tags;
249
+ summary = metadata.summary;
250
+ description = metadata.description;
251
+ errors = metadata.errors;
252
+ expose = getPropertyValue(firstArg, 'expose');
253
+ internal = getPropertyValue(firstArg, 'internal');
266
254
  }
267
- if (!ts.isArrowFunction(handlerNode) &&
268
- !ts.isFunctionExpression(handlerNode)) {
269
- logger.error(`• Handler for ${name} is not a function.`);
255
+ // Pick the handler: use resolvedFunc when it exists and is a function, otherwise fall back to handlerNode
256
+ const handler = resolvedFunc &&
257
+ (ts.isArrowFunction(resolvedFunc) || ts.isFunctionExpression(resolvedFunc))
258
+ ? resolvedFunc
259
+ : handlerNode;
260
+ // Validate that we got a valid function
261
+ if (!ts.isArrowFunction(handler) && !ts.isFunctionExpression(handler)) {
262
+ logger.error(`• No valid 'func' property found for ${pikkuFuncName}.`);
270
263
  // Create stub metadata to prevent "function not found" errors in wirings
271
264
  state.functions.meta[pikkuFuncName] = {
272
265
  pikkuFuncName,
@@ -284,7 +277,7 @@ export const addFunctions = (logger, node, checker, state) => {
284
277
  optimized: true,
285
278
  services: [],
286
279
  };
287
- const firstParam = handlerNode.parameters[0];
280
+ const firstParam = handler.parameters[0];
288
281
  if (firstParam) {
289
282
  if (ts.isObjectBindingPattern(firstParam.name)) {
290
283
  for (const elem of firstParam.name.elements) {
@@ -302,6 +295,21 @@ export const addFunctions = (logger, node, checker, state) => {
302
295
  services.optimized = false;
303
296
  }
304
297
  }
298
+ // --- Extract used wires from third parameter ---
299
+ const usedWires = [];
300
+ const thirdParam = handler.parameters[2];
301
+ if (thirdParam && ts.isObjectBindingPattern(thirdParam.name)) {
302
+ for (const elem of thirdParam.name.elements) {
303
+ const propertyName = elem.propertyName && ts.isIdentifier(elem.propertyName)
304
+ ? elem.propertyName.text
305
+ : ts.isIdentifier(elem.name)
306
+ ? elem.name.text
307
+ : undefined;
308
+ if (propertyName) {
309
+ usedWires.push(propertyName);
310
+ }
311
+ }
312
+ }
305
313
  // --- Generics → ts.Type[], unwrapped from Promise ---
306
314
  const genericTypes = (typeArguments ?? [])
307
315
  .map((tn) => checker.getTypeFromTypeNode(tn))
@@ -319,7 +327,7 @@ export const addFunctions = (logger, node, checker, state) => {
319
327
  outputNames = getNamesAndTypes(checker, state.functions.typesMap, 'Output', name, genericTypes[1]).names;
320
328
  }
321
329
  else {
322
- const sig = checker.getSignatureFromDeclaration(handlerNode);
330
+ const sig = checker.getSignatureFromDeclaration(handler);
323
331
  if (sig) {
324
332
  const rawRet = checker.getReturnTypeOfSignature(sig);
325
333
  const unwrapped = unwrapPromise(checker, rawRet);
@@ -329,6 +337,10 @@ export const addFunctions = (logger, node, checker, state) => {
329
337
  if (inputNames.length > 1) {
330
338
  logger.warn('More than one input type detected, only the first one will be used as a schema.');
331
339
  }
340
+ // Store the input type for later use
341
+ if (inputTypes.length > 0) {
342
+ state.typesLookup.set(pikkuFuncName, inputTypes);
343
+ }
332
344
  // --- resolve middleware ---
333
345
  const middleware = objectNode
334
346
  ? resolveMiddleware(state, objectNode, tags, checker)
@@ -337,20 +349,20 @@ export const addFunctions = (logger, node, checker, state) => {
337
349
  pikkuFuncName,
338
350
  name,
339
351
  services,
352
+ usedWires: usedWires.length > 0 ? usedWires : undefined,
340
353
  inputSchemaName: inputNames[0] ?? null,
341
354
  outputSchemaName: outputNames[0] ?? null,
342
355
  inputs: inputNames.filter((n) => n !== 'void') ?? null,
343
356
  outputs: outputNames.filter((n) => n !== 'void') ?? null,
344
357
  expose: expose || undefined,
358
+ internal: internal || undefined,
345
359
  tags: tags || undefined,
346
- docs: docs || undefined,
347
- isDirectFunction,
360
+ summary,
361
+ description,
362
+ errors,
348
363
  middleware,
364
+ isDirectFunction,
349
365
  };
350
- // Store the input type for later use
351
- if (inputTypes.length > 0) {
352
- state.typesLookup.set(pikkuFuncName, inputTypes);
353
- }
354
366
  // Store function file location for wiring generation
355
367
  if (exportedName) {
356
368
  state.functions.files.set(pikkuFuncName, {
@@ -358,11 +370,20 @@ export const addFunctions = (logger, node, checker, state) => {
358
370
  exportedName,
359
371
  });
360
372
  }
373
+ // Workflow functions don't get registered as RPC functions,
374
+ // they are their own type handled by add-workdflow
375
+ if (expression.text.includes('Workflow')) {
376
+ return;
377
+ }
361
378
  if (exportedName || explicitName) {
362
379
  if (!exportedName) {
363
380
  logger.error(`• Function with explicit name '${name}' is not exported, this is not allowed.`);
364
381
  return;
365
382
  }
383
+ // Mark internal functions as invoked to force bundling
384
+ if (internal) {
385
+ state.rpc.invokedFunctions.add(pikkuFuncName);
386
+ }
366
387
  if (expose) {
367
388
  state.rpc.exposedMeta[name] = pikkuFuncName;
368
389
  state.rpc.exposedFiles.set(name, {
@@ -376,8 +397,8 @@ export const addFunctions = (logger, node, checker, state) => {
376
397
  state.rpc.internalMeta[name] = pikkuFuncName;
377
398
  // But we only import the actual function if it's actually invoked to keep
378
399
  // bundle size down
379
- if (state.rpc.invokedFunctions.has(pikkuFuncName) || expose) {
380
- state.rpc.internalFiles.set(name, {
400
+ if (state.rpc.invokedFunctions.has(pikkuFuncName) || expose || internal) {
401
+ state.rpc.internalFiles.set(pikkuFuncName, {
381
402
  path: node.getSourceFile().fileName,
382
403
  exportedName,
383
404
  });
@@ -1,5 +1,5 @@
1
1
  import * as ts from 'typescript';
2
- import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
2
+ import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
3
3
  import { pathToRegexp } from 'path-to-regexp';
4
4
  import { extractFunctionName } from '../utils/extract-function-name.js';
5
5
  import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
@@ -47,8 +47,7 @@ export const addHTTPRoute = (logger, node, checker, state, options) => {
47
47
  const keys = pathToRegexp(route).keys;
48
48
  const params = keys.filter((k) => k.type === 'param').map((k) => k.name);
49
49
  const method = getPropertyValue(obj, 'method')?.toLowerCase() || 'get';
50
- const docs = getPropertyValue(obj, 'docs') || undefined;
51
- const tags = getPropertyTags(obj, 'HTTP route', route, logger);
50
+ const { tags, summary, description, errors } = getCommonWireMetaData(obj, 'HTTP route', route, logger);
52
51
  const query = getPropertyValue(obj, 'query') || [];
53
52
  // --- find the referenced function name first for filtering ---
54
53
  const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
@@ -85,7 +84,9 @@ export const addHTTPRoute = (logger, node, checker, state, options) => {
85
84
  params: params.length > 0 ? params : undefined,
86
85
  query: query.length > 0 ? query : undefined,
87
86
  inputTypes,
88
- docs,
87
+ summary,
88
+ description,
89
+ errors,
89
90
  tags,
90
91
  middleware,
91
92
  permissions,
@@ -1,5 +1,5 @@
1
1
  import * as ts from 'typescript';
2
- import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
2
+ import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
3
3
  import { extractWireNames } from '../utils/post-process.js';
4
4
  import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js';
5
5
  import { extractFunctionName } from '../utils/extract-function-name.js';
@@ -24,8 +24,7 @@ export const addMCPPrompt = (logger, node, checker, state, options) => {
24
24
  if (ts.isObjectLiteralExpression(firstArg)) {
25
25
  const obj = firstArg;
26
26
  const nameValue = getPropertyValue(obj, 'name');
27
- const descriptionValue = getPropertyValue(obj, 'description');
28
- const tags = getPropertyTags(obj, 'MCP prompt', nameValue, logger);
27
+ const { tags, summary, description, errors } = getCommonWireMetaData(obj, 'MCP prompt', nameValue, logger);
29
28
  const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
30
29
  if (!funcInitializer) {
31
30
  logger.critical(ErrorCode.MISSING_FUNC, `No valid 'func' property for MCP prompt '${nameValue}'.`);
@@ -38,7 +37,7 @@ export const addMCPPrompt = (logger, node, checker, state, options) => {
38
37
  logger.critical(ErrorCode.MISSING_NAME, "MCP prompt is missing the required 'name' property.");
39
38
  return;
40
39
  }
41
- if (!descriptionValue) {
40
+ if (!description) {
42
41
  logger.critical(ErrorCode.MISSING_DESCRIPTION, `MCP prompt '${nameValue}' is missing a description.`);
43
42
  return;
44
43
  }
@@ -62,7 +61,9 @@ export const addMCPPrompt = (logger, node, checker, state, options) => {
62
61
  state.mcpEndpoints.promptsMeta[nameValue] = {
63
62
  pikkuFuncName,
64
63
  name: nameValue,
65
- description: descriptionValue,
64
+ description,
65
+ summary,
66
+ errors,
66
67
  tags,
67
68
  inputSchema,
68
69
  outputSchema,
@@ -1,5 +1,5 @@
1
1
  import * as ts from 'typescript';
2
- import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
2
+ import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
3
3
  import { extractWireNames } from '../utils/post-process.js';
4
4
  import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js';
5
5
  import { extractFunctionName } from '../utils/extract-function-name.js';
@@ -25,9 +25,8 @@ export const addMCPResource = (logger, node, checker, state, options) => {
25
25
  const obj = firstArg;
26
26
  const uriValue = getPropertyValue(obj, 'uri');
27
27
  const titleValue = getPropertyValue(obj, 'title');
28
- const descriptionValue = getPropertyValue(obj, 'description');
28
+ const { tags, summary, description, errors } = getCommonWireMetaData(obj, 'MCP resource', uriValue, logger);
29
29
  const streamingValue = getPropertyValue(obj, 'streaming');
30
- const tags = getPropertyTags(obj, 'MCP resource', uriValue, logger);
31
30
  if (streamingValue === true) {
32
31
  logger.warn(`MCP resource '${uriValue}' has streaming enabled, but streaming is not yet supported.`);
33
32
  }
@@ -47,7 +46,7 @@ export const addMCPResource = (logger, node, checker, state, options) => {
47
46
  logger.critical(ErrorCode.MISSING_TITLE, `MCP resource '${uriValue}' is missing the required 'title' property.`);
48
47
  return;
49
48
  }
50
- if (!descriptionValue) {
49
+ if (!description) {
51
50
  logger.critical(ErrorCode.MISSING_DESCRIPTION, `MCP resource '${uriValue}' is missing a description.`);
52
51
  return;
53
52
  }
@@ -72,7 +71,9 @@ export const addMCPResource = (logger, node, checker, state, options) => {
72
71
  pikkuFuncName,
73
72
  uri: uriValue,
74
73
  title: titleValue,
75
- description: descriptionValue,
74
+ description,
75
+ summary,
76
+ errors,
76
77
  ...(streamingValue !== null && { streaming: streamingValue }),
77
78
  tags,
78
79
  inputSchema,
@@ -1,5 +1,5 @@
1
1
  import * as ts from 'typescript';
2
- import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
2
+ import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
3
3
  import { extractWireNames } from '../utils/post-process.js';
4
4
  import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js';
5
5
  import { extractFunctionName } from '../utils/extract-function-name.js';
@@ -25,9 +25,8 @@ export const addMCPTool = (logger, node, checker, state, options) => {
25
25
  const obj = firstArg;
26
26
  const nameValue = getPropertyValue(obj, 'name');
27
27
  const titleValue = getPropertyValue(obj, 'title');
28
- const descriptionValue = getPropertyValue(obj, 'description');
28
+ const { tags, summary, description, errors } = getCommonWireMetaData(obj, 'MCP tool', nameValue, logger);
29
29
  const streamingValue = getPropertyValue(obj, 'streaming');
30
- const tags = getPropertyTags(obj, 'MCP tool', nameValue, logger);
31
30
  if (streamingValue === true) {
32
31
  logger.warn(`MCP tool '${nameValue}' has streaming enabled, but streaming is not yet supported.`);
33
32
  }
@@ -43,7 +42,7 @@ export const addMCPTool = (logger, node, checker, state, options) => {
43
42
  logger.critical(ErrorCode.MISSING_NAME, "MCP tool is missing the required 'name' property.");
44
43
  return;
45
44
  }
46
- if (!descriptionValue) {
45
+ if (!description) {
47
46
  logger.critical(ErrorCode.MISSING_DESCRIPTION, `MCP tool '${nameValue}' is missing a description.`);
48
47
  return;
49
48
  }
@@ -68,7 +67,9 @@ export const addMCPTool = (logger, node, checker, state, options) => {
68
67
  pikkuFuncName,
69
68
  name: nameValue,
70
69
  title: titleValue || undefined,
71
- description: descriptionValue,
70
+ description,
71
+ summary,
72
+ errors,
72
73
  ...(streamingValue !== null && { streaming: streamingValue }),
73
74
  tags,
74
75
  inputSchema,
@@ -92,7 +92,7 @@ export const addMiddleware = (logger, node, checker, state) => {
92
92
  }
93
93
  else {
94
94
  // No pikkuMiddleware wrapper found - extract from factory's return value directly
95
- // Factory pattern: (config) => (services, interaction, next) => { ... }
95
+ // Factory pattern: (config) => (services, wire, next) => { ... }
96
96
  if (ts.isArrowFunction(factoryNode) ||
97
97
  ts.isFunctionExpression(factoryNode)) {
98
98
  const factoryBody = factoryNode.body;
@@ -92,7 +92,7 @@ export const addPermission = (logger, node, checker, state) => {
92
92
  }
93
93
  else {
94
94
  // No pikkuPermission wrapper found - extract from factory's return value directly
95
- // Factory pattern: (config) => (services, data, session) => { ... }
95
+ // Factory pattern: (config) => (services, data, wire) => { ... }
96
96
  if (ts.isArrowFunction(factoryNode) ||
97
97
  ts.isFunctionExpression(factoryNode)) {
98
98
  const factoryBody = factoryNode.body;
@@ -1,11 +1,11 @@
1
1
  import * as ts from 'typescript';
2
- import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
2
+ import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
3
3
  import { extractFunctionName } from '../utils/extract-function-name.js';
4
4
  import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
5
5
  import { resolveMiddleware } from '../utils/middleware.js';
6
6
  import { extractWireNames } from '../utils/post-process.js';
7
7
  import { ErrorCode } from '../error-codes.js';
8
- export const addQueueWorker = (logger, node, checker, state, options) => {
8
+ export const addQueueWorker = (logger, node, checker, state) => {
9
9
  if (!ts.isCallExpression(node)) {
10
10
  return;
11
11
  }
@@ -22,8 +22,7 @@ export const addQueueWorker = (logger, node, checker, state, options) => {
22
22
  if (ts.isObjectLiteralExpression(firstArg)) {
23
23
  const obj = firstArg;
24
24
  const queueName = getPropertyValue(obj, 'queueName');
25
- const docs = getPropertyValue(obj, 'docs') || undefined;
26
- const tags = getPropertyTags(obj, 'Queue worker', queueName, logger);
25
+ const { tags, summary, description, errors } = getCommonWireMetaData(obj, 'Queue worker', queueName, logger);
27
26
  // --- find the referenced function ---
28
27
  const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
29
28
  if (!funcInitializer) {
@@ -44,7 +43,9 @@ export const addQueueWorker = (logger, node, checker, state, options) => {
44
43
  state.queueWorkers.meta[queueName] = {
45
44
  pikkuFuncName,
46
45
  queueName,
47
- docs,
46
+ summary,
47
+ description,
48
+ errors,
48
49
  tags,
49
50
  middleware,
50
51
  };
@@ -1,5 +1,5 @@
1
1
  import * as ts from 'typescript';
2
- import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
2
+ import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
3
3
  import { extractFunctionName } from '../utils/extract-function-name.js';
4
4
  import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
5
5
  import { resolveMiddleware } from '../utils/middleware.js';
@@ -23,8 +23,7 @@ export const addSchedule = (logger, node, checker, state, options) => {
23
23
  const obj = firstArg;
24
24
  const nameValue = getPropertyValue(obj, 'name');
25
25
  const scheduleValue = getPropertyValue(obj, 'schedule');
26
- const docs = getPropertyValue(obj, 'docs') || undefined;
27
- const tags = getPropertyTags(obj, 'Scheduler', nameValue, logger);
26
+ const { tags, summary, description, errors } = getCommonWireMetaData(obj, 'Scheduler', nameValue, logger);
28
27
  const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
29
28
  if (!funcInitializer) {
30
29
  logger.critical(ErrorCode.MISSING_FUNC, `No valid 'func' property for scheduled task '${nameValue}'.`);
@@ -44,7 +43,9 @@ export const addSchedule = (logger, node, checker, state, options) => {
44
43
  pikkuFuncName,
45
44
  name: nameValue,
46
45
  schedule: scheduleValue,
47
- docs,
46
+ summary,
47
+ description,
48
+ errors,
48
49
  tags,
49
50
  middleware,
50
51
  };
@@ -0,0 +1,6 @@
1
+ import { AddWiring } from '../types.js';
2
+ /**
3
+ * Inspector for pikkuWorkflow() and pikkuSimpleWorkflow() calls
4
+ * Detects workflow registration and extracts metadata
5
+ */
6
+ export declare const addWorkflow: AddWiring;