@pikku/inspector 0.11.0 → 0.11.2

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 (109) hide show
  1. package/CHANGELOG.md +32 -2
  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-forge-credential.d.ts +8 -0
  5. package/dist/add/add-forge-credential.js +77 -0
  6. package/dist/add/add-forge-node.d.ts +7 -0
  7. package/dist/add/add-forge-node.js +77 -0
  8. package/dist/add/add-functions.js +158 -51
  9. package/dist/add/add-http-route.js +28 -4
  10. package/dist/add/add-mcp-prompt.js +6 -5
  11. package/dist/add/add-mcp-resource.js +6 -5
  12. package/dist/add/add-mcp-tool.js +6 -5
  13. package/dist/add/add-middleware.js +1 -1
  14. package/dist/add/add-permission.js +1 -1
  15. package/dist/add/add-queue-worker.js +6 -5
  16. package/dist/add/add-rpc-invocations.d.ts +3 -0
  17. package/dist/add/add-rpc-invocations.js +51 -25
  18. package/dist/add/add-schedule.js +5 -4
  19. package/dist/add/add-workflow-graph.d.ts +6 -0
  20. package/dist/add/add-workflow-graph.js +659 -0
  21. package/dist/add/add-workflow.d.ts +1 -1
  22. package/dist/add/add-workflow.js +191 -69
  23. package/dist/error-codes.d.ts +3 -0
  24. package/dist/error-codes.js +3 -0
  25. package/dist/index.d.ts +5 -0
  26. package/dist/index.js +3 -0
  27. package/dist/inspector.js +29 -9
  28. package/dist/types.d.ts +47 -8
  29. package/dist/utils/extract-function-name.js +7 -7
  30. package/dist/utils/extract-function-node.d.ts +10 -0
  31. package/dist/utils/extract-function-node.js +38 -0
  32. package/dist/utils/extract-node-value.d.ts +8 -0
  33. package/dist/utils/extract-node-value.js +24 -0
  34. package/dist/utils/extract-service-metadata.d.ts +19 -0
  35. package/dist/utils/extract-service-metadata.js +244 -0
  36. package/dist/utils/get-files-and-methods.d.ts +3 -3
  37. package/dist/utils/get-files-and-methods.js +3 -3
  38. package/dist/utils/get-property-value.d.ts +14 -6
  39. package/dist/utils/get-property-value.js +55 -43
  40. package/dist/utils/post-process.d.ts +9 -0
  41. package/dist/utils/post-process.js +30 -3
  42. package/dist/utils/serialize-inspector-state.d.ts +42 -6
  43. package/dist/utils/serialize-inspector-state.js +36 -10
  44. package/dist/utils/workflow/dsl/deserialize-dsl-workflow.d.ts +24 -0
  45. package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +898 -0
  46. package/dist/utils/workflow/dsl/extract-dsl-workflow.d.ts +17 -0
  47. package/dist/utils/workflow/dsl/extract-dsl-workflow.js +1284 -0
  48. package/dist/utils/workflow/dsl/index.d.ts +7 -0
  49. package/dist/utils/workflow/dsl/index.js +7 -0
  50. package/dist/utils/workflow/dsl/patterns.d.ts +60 -0
  51. package/dist/utils/workflow/dsl/patterns.js +218 -0
  52. package/dist/utils/workflow/dsl/validation.d.ts +30 -0
  53. package/dist/utils/workflow/dsl/validation.js +142 -0
  54. package/dist/utils/workflow/graph/convert-dsl-to-graph.d.ts +13 -0
  55. package/dist/utils/workflow/graph/convert-dsl-to-graph.js +316 -0
  56. package/dist/utils/workflow/graph/index.d.ts +6 -0
  57. package/dist/utils/workflow/graph/index.js +6 -0
  58. package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +43 -0
  59. package/dist/utils/workflow/graph/serialize-workflow-graph.js +152 -0
  60. package/dist/utils/workflow/graph/workflow-graph.types.d.ts +229 -0
  61. package/dist/utils/workflow/graph/workflow-graph.types.js +38 -0
  62. package/dist/utils/write-service-metadata.d.ts +13 -0
  63. package/dist/utils/write-service-metadata.js +37 -0
  64. package/dist/visit.js +8 -2
  65. package/package.json +16 -4
  66. package/src/add/add-channel.ts +37 -17
  67. package/src/add/add-file-with-factory.ts +10 -10
  68. package/src/add/add-forge-credential.ts +119 -0
  69. package/src/add/add-forge-node.ts +132 -0
  70. package/src/add/add-functions.ts +199 -69
  71. package/src/add/add-http-route.ts +34 -5
  72. package/src/add/add-mcp-prompt.ts +11 -7
  73. package/src/add/add-mcp-resource.ts +11 -7
  74. package/src/add/add-mcp-tool.ts +11 -7
  75. package/src/add/add-middleware.ts +1 -1
  76. package/src/add/add-permission.ts +1 -1
  77. package/src/add/add-queue-worker.ts +11 -12
  78. package/src/add/add-rpc-invocations.ts +61 -31
  79. package/src/add/add-schedule.ts +10 -5
  80. package/src/add/add-workflow-graph.ts +864 -0
  81. package/src/add/add-workflow.ts +212 -116
  82. package/src/error-codes.ts +3 -0
  83. package/src/index.ts +12 -0
  84. package/src/inspector.ts +36 -10
  85. package/src/types.ts +43 -9
  86. package/src/utils/extract-function-name.ts +7 -7
  87. package/src/utils/extract-function-node.ts +58 -0
  88. package/src/utils/extract-node-value.ts +31 -0
  89. package/src/utils/extract-service-metadata.ts +353 -0
  90. package/src/utils/filter-inspector-state.test.ts +3 -3
  91. package/src/utils/filter-utils.test.ts +45 -51
  92. package/src/utils/get-files-and-methods.ts +11 -11
  93. package/src/utils/get-property-value.ts +67 -53
  94. package/src/utils/permissions.test.ts +3 -3
  95. package/src/utils/post-process.ts +56 -3
  96. package/src/utils/serialize-inspector-state.ts +67 -19
  97. package/src/utils/test-data/inspector-state.json +9 -9
  98. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +1180 -0
  99. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +1608 -0
  100. package/src/utils/workflow/dsl/index.ts +11 -0
  101. package/src/utils/workflow/dsl/patterns.ts +279 -0
  102. package/src/utils/workflow/dsl/validation.ts +180 -0
  103. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +415 -0
  104. package/src/utils/workflow/graph/index.ts +6 -0
  105. package/src/utils/workflow/graph/serialize-workflow-graph.ts +223 -0
  106. package/src/utils/workflow/graph/workflow-graph.types.ts +280 -0
  107. package/src/utils/write-service-metadata.ts +51 -0
  108. package/src/visit.ts +9 -3
  109. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -1,11 +1,41 @@
1
- ## 0.11.0
1
+ ## 0.11.2
2
+
3
+ ## 0.11.2
4
+
5
+ ### Patch Changes
6
+
7
+ - db9c7bf: Add workflow graph inspection and DSL extraction
8
+ - Updated dependencies [db9c7bf]
9
+ - @pikku/core@0.11.2
10
+
11
+ ### Features
12
+
13
+ - f35e89da: Add workflow graph inspection and DSL extraction
14
+ - Workflow graph inspection with `add-workflow-graph.ts`
15
+ - DSL workflow extraction utilities (extract, deserialize, validate)
16
+ - DSL to graph conversion for metadata generation
17
+
18
+ ## 0.11.1
19
+
20
+ ### Patch Changes
21
+
22
+ - 4b811db: chore: updating all dependencies
23
+ - 28aeb7f: breaking: extract docs in the wiring meta
24
+ - ce902b1: feat: adding in pikkuSimpleWorkflowFunc
25
+ - 06e1a31: breaking: change session services to wire services
26
+ - Updated dependencies [4b811db]
27
+ - Updated dependencies [e12a00c]
28
+ - Updated dependencies [4579434]
29
+ - Updated dependencies [28aeb7f]
30
+ - Updated dependencies [ce902b1]
31
+ - Updated dependencies [06e1a31]
32
+ - @pikku/core@0.11.1
2
33
 
3
34
  ### Minor Changes
4
35
 
5
36
  - Add workflow inspection and analysis
6
37
  - Add enhanced type extraction utilities
7
38
 
8
-
9
39
  # @pikku/inspector
10
40
 
11
41
  ## 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
  }
@@ -0,0 +1,8 @@
1
+ import { AddWiring } from '../types.js';
2
+ /**
3
+ * Inspector for wireForgeCredential calls.
4
+ * Extracts metadata for Forge package credential declarations.
5
+ * Note: wireForgeCredential is metadata-only - no runtime behavior.
6
+ * Schema is stored as the variable name reference; actual Zod→JSON Schema conversion happens at CLI build time.
7
+ */
8
+ export declare const addForgeCredential: AddWiring;
@@ -0,0 +1,77 @@
1
+ import * as ts from 'typescript';
2
+ import { getPropertyValue } from '../utils/get-property-value.js';
3
+ import { ErrorCode } from '../error-codes.js';
4
+ /**
5
+ * Inspector for wireForgeCredential calls.
6
+ * Extracts metadata for Forge package credential declarations.
7
+ * Note: wireForgeCredential is metadata-only - no runtime behavior.
8
+ * Schema is stored as the variable name reference; actual Zod→JSON Schema conversion happens at CLI build time.
9
+ */
10
+ export const addForgeCredential = (logger, node, _checker, state, _options) => {
11
+ if (!ts.isCallExpression(node)) {
12
+ return;
13
+ }
14
+ const args = node.arguments;
15
+ const firstArg = args[0];
16
+ const expression = node.expression;
17
+ // Check if the call is to wireForgeCredential
18
+ if (!ts.isIdentifier(expression) ||
19
+ expression.text !== 'wireForgeCredential') {
20
+ return;
21
+ }
22
+ if (!firstArg) {
23
+ return;
24
+ }
25
+ if (ts.isObjectLiteralExpression(firstArg)) {
26
+ const obj = firstArg;
27
+ const nameValue = getPropertyValue(obj, 'name');
28
+ const displayNameValue = getPropertyValue(obj, 'displayName');
29
+ const descriptionValue = getPropertyValue(obj, 'description');
30
+ const secretIdValue = getPropertyValue(obj, 'secretId');
31
+ // Get schema variable name for later runtime import
32
+ let schemaVariableName = null;
33
+ for (const prop of obj.properties) {
34
+ if (ts.isPropertyAssignment(prop) &&
35
+ ts.isIdentifier(prop.name) &&
36
+ prop.name.text === 'schema') {
37
+ if (ts.isIdentifier(prop.initializer)) {
38
+ schemaVariableName = prop.initializer.text;
39
+ }
40
+ break;
41
+ }
42
+ }
43
+ // Validate required fields
44
+ if (!nameValue) {
45
+ logger.critical(ErrorCode.MISSING_NAME, "Forge credential is missing the required 'name' property.");
46
+ return;
47
+ }
48
+ if (!displayNameValue) {
49
+ logger.critical(ErrorCode.MISSING_NAME, `Forge credential '${nameValue}' is missing the required 'displayName' property.`);
50
+ return;
51
+ }
52
+ if (!secretIdValue) {
53
+ logger.critical(ErrorCode.MISSING_NAME, `Forge credential '${nameValue}' is missing the required 'secretId' property.`);
54
+ return;
55
+ }
56
+ if (!schemaVariableName) {
57
+ logger.critical(ErrorCode.MISSING_NAME, `Forge credential '${nameValue}' is missing the required 'schema' property or schema is not a variable reference.`);
58
+ return;
59
+ }
60
+ const sourceFile = node.getSourceFile().fileName;
61
+ state.forgeCredentials.files.add(sourceFile);
62
+ // Register the zod schema in the central zodLookup for deferred conversion
63
+ const schemaLookupName = `ForgeCredential_${nameValue}`;
64
+ state.zodLookup.set(schemaLookupName, {
65
+ variableName: schemaVariableName,
66
+ sourceFile,
67
+ });
68
+ // Store metadata - schema conversion happens later in schema-generator
69
+ state.forgeCredentials.meta[nameValue] = {
70
+ name: nameValue,
71
+ displayName: displayNameValue,
72
+ description: descriptionValue || undefined,
73
+ secretId: secretIdValue,
74
+ schema: schemaLookupName,
75
+ };
76
+ }
77
+ };
@@ -0,0 +1,7 @@
1
+ import { AddWiring } from '../types.js';
2
+ /**
3
+ * Inspector for wireForgeNode calls.
4
+ * Extracts metadata for Forge workflow builder nodes.
5
+ * Note: wireForgeNode is metadata-only - no runtime behavior.
6
+ */
7
+ export declare const addForgeNode: AddWiring;
@@ -0,0 +1,77 @@
1
+ import * as ts from 'typescript';
2
+ import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
3
+ import { ErrorCode } from '../error-codes.js';
4
+ /**
5
+ * Inspector for wireForgeNode calls.
6
+ * Extracts metadata for Forge workflow builder nodes.
7
+ * Note: wireForgeNode is metadata-only - no runtime behavior.
8
+ */
9
+ export const addForgeNode = (logger, node, checker, state, _options) => {
10
+ if (!ts.isCallExpression(node)) {
11
+ return;
12
+ }
13
+ const args = node.arguments;
14
+ const firstArg = args[0];
15
+ const expression = node.expression;
16
+ // Check if the call is to wireForgeNode
17
+ if (!ts.isIdentifier(expression) || expression.text !== 'wireForgeNode') {
18
+ return;
19
+ }
20
+ if (!firstArg) {
21
+ return;
22
+ }
23
+ if (ts.isObjectLiteralExpression(firstArg)) {
24
+ const obj = firstArg;
25
+ const nameValue = getPropertyValue(obj, 'name');
26
+ const displayNameValue = getPropertyValue(obj, 'displayName');
27
+ const categoryValue = getPropertyValue(obj, 'category');
28
+ const typeValue = getPropertyValue(obj, 'type');
29
+ const rpcValue = getPropertyValue(obj, 'rpc');
30
+ const errorOutputValue = getPropertyValue(obj, 'errorOutput');
31
+ const { tags, description } = getCommonWireMetaData(obj, 'Forge node', nameValue, logger);
32
+ // Validate required fields
33
+ if (!nameValue) {
34
+ logger.critical(ErrorCode.MISSING_NAME, "Forge node is missing the required 'name' property.");
35
+ return;
36
+ }
37
+ if (!displayNameValue) {
38
+ logger.critical(ErrorCode.MISSING_NAME, `Forge node '${nameValue}' is missing the required 'displayName' property.`);
39
+ return;
40
+ }
41
+ if (!categoryValue) {
42
+ logger.critical(ErrorCode.MISSING_NAME, `Forge node '${nameValue}' is missing the required 'category' property.`);
43
+ return;
44
+ }
45
+ if (!typeValue) {
46
+ logger.critical(ErrorCode.MISSING_NAME, `Forge node '${nameValue}' is missing the required 'type' property.`);
47
+ return;
48
+ }
49
+ if (!['trigger', 'action', 'end'].includes(typeValue)) {
50
+ logger.critical(ErrorCode.INVALID_VALUE, `Forge node '${nameValue}' has invalid type '${typeValue}'. Must be 'trigger', 'action', or 'end'.`);
51
+ return;
52
+ }
53
+ if (!rpcValue) {
54
+ logger.critical(ErrorCode.MISSING_NAME, `Forge node '${nameValue}' is missing the required 'rpc' property.`);
55
+ return;
56
+ }
57
+ // Get function metadata for input/output schemas
58
+ const fnMeta = state.functions.meta[rpcValue];
59
+ const inputSchemaName = fnMeta?.inputs?.[0] || null;
60
+ const outputSchemaName = fnMeta?.outputs?.[0] || null;
61
+ // Note: Category validation against forge.node.categories config
62
+ // is done at CLI build time, not during inspection
63
+ state.forgeNodes.files.add(node.getSourceFile().fileName);
64
+ state.forgeNodes.meta[nameValue] = {
65
+ name: nameValue,
66
+ displayName: displayNameValue,
67
+ category: categoryValue,
68
+ type: typeValue,
69
+ rpc: rpcValue,
70
+ description,
71
+ errorOutput: errorOutputValue ?? false,
72
+ inputSchemaName,
73
+ outputSchemaName,
74
+ tags,
75
+ };
76
+ }
77
+ };