@vfarcic/dot-ai 1.0.2 → 1.1.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 (228) hide show
  1. package/README.md +1 -0
  2. package/dist/core/ai-provider.interface.d.ts +12 -8
  3. package/dist/core/ai-provider.interface.d.ts.map +1 -1
  4. package/dist/core/artifacthub.d.ts +1 -1
  5. package/dist/core/artifacthub.d.ts.map +1 -1
  6. package/dist/core/base-vector-service.d.ts +22 -9
  7. package/dist/core/base-vector-service.d.ts.map +1 -1
  8. package/dist/core/base-vector-service.js +106 -37
  9. package/dist/core/capabilities.d.ts.map +1 -1
  10. package/dist/core/capabilities.js +5 -2
  11. package/dist/core/capability-operations.d.ts +55 -7
  12. package/dist/core/capability-operations.d.ts.map +1 -1
  13. package/dist/core/capability-operations.js +1 -3
  14. package/dist/core/capability-scan-workflow.d.ts +64 -8
  15. package/dist/core/capability-scan-workflow.d.ts.map +1 -1
  16. package/dist/core/capability-scan-workflow.js +14 -13
  17. package/dist/core/capability-tools.d.ts +1 -1
  18. package/dist/core/capability-tools.d.ts.map +1 -1
  19. package/dist/core/capability-tools.js +1 -1
  20. package/dist/core/capability-vector-service.d.ts +3 -4
  21. package/dist/core/capability-vector-service.d.ts.map +1 -1
  22. package/dist/core/capability-vector-service.js +2 -2
  23. package/dist/core/command-executor.d.ts +3 -4
  24. package/dist/core/command-executor.d.ts.map +1 -1
  25. package/dist/core/command-executor.js +8 -4
  26. package/dist/core/crd-availability.d.ts +3 -5
  27. package/dist/core/crd-availability.d.ts.map +1 -1
  28. package/dist/core/crd-availability.js +8 -18
  29. package/dist/core/deploy-operation.d.ts +6 -5
  30. package/dist/core/deploy-operation.d.ts.map +1 -1
  31. package/dist/core/deploy-operation.js +16 -10
  32. package/dist/core/discovery.d.ts +6 -14
  33. package/dist/core/discovery.d.ts.map +1 -1
  34. package/dist/core/discovery.js +35 -51
  35. package/dist/core/embedding-service.d.ts.map +1 -1
  36. package/dist/core/embedding-service.js +1 -1
  37. package/dist/core/error-handling.d.ts +13 -13
  38. package/dist/core/error-handling.d.ts.map +1 -1
  39. package/dist/core/error-handling.js +2 -3
  40. package/dist/core/generic-session-manager.d.ts +2 -2
  41. package/dist/core/generic-session-manager.d.ts.map +1 -1
  42. package/dist/core/helm-types.d.ts +5 -5
  43. package/dist/core/helm-types.d.ts.map +1 -1
  44. package/dist/core/index.d.ts +4 -11
  45. package/dist/core/index.d.ts.map +1 -1
  46. package/dist/core/index.js +8 -14
  47. package/dist/core/knowledge-types.d.ts +114 -0
  48. package/dist/core/knowledge-types.d.ts.map +1 -0
  49. package/dist/core/knowledge-types.js +10 -0
  50. package/dist/core/memory.d.ts +12 -12
  51. package/dist/core/memory.d.ts.map +1 -1
  52. package/dist/core/mermaid-tools.d.ts +24 -1
  53. package/dist/core/mermaid-tools.d.ts.map +1 -1
  54. package/dist/core/mermaid-tools.js +10 -8
  55. package/dist/core/packaging.d.ts +23 -1
  56. package/dist/core/packaging.d.ts.map +1 -1
  57. package/dist/core/pattern-operations.d.ts +32 -9
  58. package/dist/core/pattern-operations.d.ts.map +1 -1
  59. package/dist/core/pattern-operations.js +17 -22
  60. package/dist/core/pattern-vector-service.d.ts +3 -4
  61. package/dist/core/pattern-vector-service.d.ts.map +1 -1
  62. package/dist/core/pattern-vector-service.js +2 -2
  63. package/dist/core/platform-utils.d.ts +2 -2
  64. package/dist/core/platform-utils.d.ts.map +1 -1
  65. package/dist/core/plugin-manager.d.ts +6 -2
  66. package/dist/core/plugin-manager.d.ts.map +1 -1
  67. package/dist/core/plugin-manager.js +9 -16
  68. package/dist/core/plugin-registry.d.ts +59 -0
  69. package/dist/core/plugin-registry.d.ts.map +1 -0
  70. package/dist/core/plugin-registry.js +80 -0
  71. package/dist/core/policy-operations.d.ts +101 -21
  72. package/dist/core/policy-operations.d.ts.map +1 -1
  73. package/dist/core/policy-operations.js +45 -47
  74. package/dist/core/policy-vector-service.d.ts +3 -4
  75. package/dist/core/policy-vector-service.d.ts.map +1 -1
  76. package/dist/core/policy-vector-service.js +2 -2
  77. package/dist/core/providers/host-provider.d.ts +1 -1
  78. package/dist/core/providers/host-provider.d.ts.map +1 -1
  79. package/dist/core/providers/host-provider.js +2 -2
  80. package/dist/core/providers/provider-debug-utils.d.ts +2 -2
  81. package/dist/core/providers/provider-debug-utils.d.ts.map +1 -1
  82. package/dist/core/providers/tool-utils.d.ts +10 -2
  83. package/dist/core/providers/tool-utils.d.ts.map +1 -1
  84. package/dist/core/providers/tool-utils.js +2 -2
  85. package/dist/core/providers/vercel-provider.d.ts.map +1 -1
  86. package/dist/core/providers/vercel-provider.js +29 -23
  87. package/dist/core/resource-tools.d.ts +29 -1
  88. package/dist/core/resource-tools.d.ts.map +1 -1
  89. package/dist/core/resource-vector-service.d.ts +3 -4
  90. package/dist/core/resource-vector-service.d.ts.map +1 -1
  91. package/dist/core/resource-vector-service.js +2 -2
  92. package/dist/core/schema.d.ts +15 -14
  93. package/dist/core/schema.d.ts.map +1 -1
  94. package/dist/core/schema.js +32 -34
  95. package/dist/core/shared-prompt-loader.d.ts +1 -1
  96. package/dist/core/shared-prompt-loader.d.ts.map +1 -1
  97. package/dist/core/solution-cr.js +1 -1
  98. package/dist/core/solution-utils.d.ts +22 -3
  99. package/dist/core/solution-utils.d.ts.map +1 -1
  100. package/dist/core/solution-utils.js +1 -1
  101. package/dist/core/telemetry/client.d.ts +0 -6
  102. package/dist/core/telemetry/client.d.ts.map +1 -1
  103. package/dist/core/telemetry/client.js +6 -17
  104. package/dist/core/telemetry/config.js +1 -1
  105. package/dist/core/telemetry/index.d.ts +1 -1
  106. package/dist/core/telemetry/index.d.ts.map +1 -1
  107. package/dist/core/telemetry/index.js +1 -2
  108. package/dist/core/tracing/tool-tracing.d.ts +1 -1
  109. package/dist/core/tracing/tool-tracing.d.ts.map +1 -1
  110. package/dist/core/unified-creation-session.d.ts +15 -8
  111. package/dist/core/unified-creation-session.d.ts.map +1 -1
  112. package/dist/core/unified-creation-session.js +19 -19
  113. package/dist/core/unified-creation-types.d.ts +2 -2
  114. package/dist/core/unified-creation-types.d.ts.map +1 -1
  115. package/dist/core/visualization.d.ts +1 -1
  116. package/dist/core/visualization.d.ts.map +1 -1
  117. package/dist/core/workflow.d.ts +8 -5
  118. package/dist/core/workflow.d.ts.map +1 -1
  119. package/dist/evaluation/dataset-analyzer.d.ts +13 -7
  120. package/dist/evaluation/dataset-analyzer.d.ts.map +1 -1
  121. package/dist/evaluation/dataset-analyzer.js +1 -1
  122. package/dist/evaluation/datasets/loader.d.ts +2 -2
  123. package/dist/evaluation/datasets/loader.d.ts.map +1 -1
  124. package/dist/evaluation/eval-runner.js +7 -5
  125. package/dist/evaluation/evaluators/base-comparative.d.ts +1 -1
  126. package/dist/evaluation/evaluators/base-comparative.d.ts.map +1 -1
  127. package/dist/evaluation/evaluators/base-comparative.js +4 -3
  128. package/dist/evaluation/evaluators/base.d.ts +5 -5
  129. package/dist/evaluation/evaluators/base.d.ts.map +1 -1
  130. package/dist/evaluation/evaluators/capability-comparative.js +1 -1
  131. package/dist/evaluation/platform-synthesizer.d.ts.map +1 -1
  132. package/dist/interfaces/mcp.d.ts.map +1 -1
  133. package/dist/interfaces/mcp.js +26 -15
  134. package/dist/interfaces/openapi-generator.d.ts +116 -12
  135. package/dist/interfaces/openapi-generator.d.ts.map +1 -1
  136. package/dist/interfaces/openapi-generator.js +490 -199
  137. package/dist/interfaces/rest-api.d.ts +28 -6
  138. package/dist/interfaces/rest-api.d.ts.map +1 -1
  139. package/dist/interfaces/rest-api.js +436 -245
  140. package/dist/interfaces/rest-registry.d.ts +4 -4
  141. package/dist/interfaces/rest-registry.d.ts.map +1 -1
  142. package/dist/interfaces/rest-registry.js +6 -5
  143. package/dist/interfaces/rest-route-registry.d.ts +165 -0
  144. package/dist/interfaces/rest-route-registry.d.ts.map +1 -0
  145. package/dist/interfaces/rest-route-registry.js +230 -0
  146. package/dist/interfaces/routes/index.d.ts +22 -0
  147. package/dist/interfaces/routes/index.d.ts.map +1 -0
  148. package/dist/interfaces/routes/index.js +347 -0
  149. package/dist/interfaces/schemas/common.d.ts +177 -0
  150. package/dist/interfaces/schemas/common.d.ts.map +1 -0
  151. package/dist/interfaces/schemas/common.js +102 -0
  152. package/dist/interfaces/schemas/events.d.ts +131 -0
  153. package/dist/interfaces/schemas/events.d.ts.map +1 -0
  154. package/dist/interfaces/schemas/events.js +66 -0
  155. package/dist/interfaces/schemas/index.d.ts +21 -0
  156. package/dist/interfaces/schemas/index.d.ts.map +1 -0
  157. package/dist/interfaces/schemas/index.js +138 -0
  158. package/dist/interfaces/schemas/knowledge.d.ts +210 -0
  159. package/dist/interfaces/schemas/knowledge.d.ts.map +1 -0
  160. package/dist/interfaces/schemas/knowledge.js +117 -0
  161. package/dist/interfaces/schemas/logs.d.ts +82 -0
  162. package/dist/interfaces/schemas/logs.d.ts.map +1 -0
  163. package/dist/interfaces/schemas/logs.js +46 -0
  164. package/dist/interfaces/schemas/prompts.d.ts +191 -0
  165. package/dist/interfaces/schemas/prompts.d.ts.map +1 -0
  166. package/dist/interfaces/schemas/prompts.js +91 -0
  167. package/dist/interfaces/schemas/resources.d.ts +378 -0
  168. package/dist/interfaces/schemas/resources.d.ts.map +1 -0
  169. package/dist/interfaces/schemas/resources.js +173 -0
  170. package/dist/interfaces/schemas/sessions.d.ts +90 -0
  171. package/dist/interfaces/schemas/sessions.d.ts.map +1 -0
  172. package/dist/interfaces/schemas/sessions.js +56 -0
  173. package/dist/interfaces/schemas/tools.d.ts +194 -0
  174. package/dist/interfaces/schemas/tools.d.ts.map +1 -0
  175. package/dist/interfaces/schemas/tools.js +101 -0
  176. package/dist/interfaces/schemas/visualization.d.ts +373 -0
  177. package/dist/interfaces/schemas/visualization.d.ts.map +1 -0
  178. package/dist/interfaces/schemas/visualization.js +134 -0
  179. package/dist/mcp/server.js +5 -4
  180. package/dist/tools/answer-question.d.ts +1 -1
  181. package/dist/tools/answer-question.d.ts.map +1 -1
  182. package/dist/tools/answer-question.js +9 -8
  183. package/dist/tools/deploy-manifests.d.ts +4 -2
  184. package/dist/tools/deploy-manifests.d.ts.map +1 -1
  185. package/dist/tools/deploy-manifests.js +10 -6
  186. package/dist/tools/generate-manifests.d.ts.map +1 -1
  187. package/dist/tools/generate-manifests.js +28 -20
  188. package/dist/tools/index.d.ts +1 -0
  189. package/dist/tools/index.d.ts.map +1 -1
  190. package/dist/tools/index.js +6 -1
  191. package/dist/tools/manage-knowledge.d.ts +77 -0
  192. package/dist/tools/manage-knowledge.d.ts.map +1 -0
  193. package/dist/tools/manage-knowledge.js +573 -0
  194. package/dist/tools/operate-analysis.d.ts +31 -2
  195. package/dist/tools/operate-analysis.d.ts.map +1 -1
  196. package/dist/tools/operate-execution.d.ts +2 -3
  197. package/dist/tools/operate-execution.d.ts.map +1 -1
  198. package/dist/tools/operate-execution.js +7 -7
  199. package/dist/tools/operate.d.ts +7 -2
  200. package/dist/tools/operate.d.ts.map +1 -1
  201. package/dist/tools/operate.js +2 -2
  202. package/dist/tools/organizational-data.d.ts +30 -4
  203. package/dist/tools/organizational-data.d.ts.map +1 -1
  204. package/dist/tools/organizational-data.js +24 -19
  205. package/dist/tools/project-setup/discovery.d.ts.map +1 -1
  206. package/dist/tools/project-setup/generate-scope.d.ts +1 -1
  207. package/dist/tools/project-setup/generate-scope.d.ts.map +1 -1
  208. package/dist/tools/project-setup/types.d.ts +1 -0
  209. package/dist/tools/project-setup/types.d.ts.map +1 -1
  210. package/dist/tools/prompts.d.ts +28 -2
  211. package/dist/tools/prompts.d.ts.map +1 -1
  212. package/dist/tools/query.d.ts +17 -3
  213. package/dist/tools/query.d.ts.map +1 -1
  214. package/dist/tools/query.js +1 -7
  215. package/dist/tools/recommend.d.ts +24 -6
  216. package/dist/tools/recommend.d.ts.map +1 -1
  217. package/dist/tools/recommend.js +18 -15
  218. package/dist/tools/remediate.d.ts +12 -3
  219. package/dist/tools/remediate.d.ts.map +1 -1
  220. package/dist/tools/remediate.js +22 -14
  221. package/dist/tools/version.d.ts +19 -5
  222. package/dist/tools/version.d.ts.map +1 -1
  223. package/dist/tools/version.js +106 -54
  224. package/package.json +11 -5
  225. package/prompts/knowledge-ask.md +29 -0
  226. package/dist/core/vector-db-service.d.ts +0 -108
  227. package/dist/core/vector-db-service.d.ts.map +0 -1
  228. package/dist/core/vector-db-service.js +0 -647
@@ -2,23 +2,31 @@
2
2
  /**
3
3
  * OpenAPI 3.0 Specification Generator
4
4
  *
5
- * Automatically generates OpenAPI 3.0 documentation from the tool registry.
6
- * Creates comprehensive API documentation with proper schemas and examples.
5
+ * Automatically generates OpenAPI 3.0 documentation from the tool registry
6
+ * and REST route registry.
7
+ *
8
+ * PRD #354: REST API Route Registry with Auto-Generated OpenAPI and Test Fixtures
9
+ * - Generates paths from RestRouteRegistry for all REST endpoints
10
+ * - Converts Zod schemas to JSON Schema for complete API documentation
7
11
  */
8
12
  Object.defineProperty(exports, "__esModule", { value: true });
9
13
  exports.OpenApiGenerator = void 0;
14
+ const zod_to_json_schema_1 = require("zod-to-json-schema");
10
15
  /**
11
16
  * OpenAPI 3.0 specification generator
12
17
  */
13
18
  class OpenApiGenerator {
14
- registry;
19
+ toolRegistry;
20
+ routeRegistry;
15
21
  logger;
16
22
  config;
17
23
  specCache;
18
24
  lastCacheUpdate = 0;
19
25
  cacheValidityMs = 60000; // 1 minute
20
- constructor(registry, logger, config = {}) {
21
- this.registry = registry;
26
+ schemaCache = new Map();
27
+ constructor(toolRegistry, logger, config = {}, routeRegistry) {
28
+ this.toolRegistry = toolRegistry;
29
+ this.routeRegistry = routeRegistry;
22
30
  this.logger = logger;
23
31
  this.config = {
24
32
  title: 'DevOps AI Toolkit REST API',
@@ -27,7 +35,7 @@ class OpenApiGenerator {
27
35
  basePath: '/api',
28
36
  apiVersion: 'v1',
29
37
  serverUrl: 'http://localhost:3456',
30
- ...config
38
+ ...config,
31
39
  };
32
40
  }
33
41
  /**
@@ -36,23 +44,45 @@ class OpenApiGenerator {
36
44
  generateSpec() {
37
45
  // Check cache validity
38
46
  const now = Date.now();
39
- if (this.specCache && (now - this.lastCacheUpdate) < this.cacheValidityMs) {
47
+ if (this.specCache && now - this.lastCacheUpdate < this.cacheValidityMs) {
40
48
  this.logger.debug('Returning cached OpenAPI specification');
41
49
  return this.specCache;
42
50
  }
43
51
  this.logger.info('Generating OpenAPI 3.0 specification', {
44
- toolCount: this.registry.getToolCount(),
45
- cacheExpired: !this.specCache || (now - this.lastCacheUpdate) >= this.cacheValidityMs
52
+ toolCount: this.toolRegistry.getToolCount(),
53
+ routeCount: this.routeRegistry?.getRouteCount() ?? 0,
54
+ cacheExpired: !this.specCache || now - this.lastCacheUpdate >= this.cacheValidityMs,
46
55
  });
47
- const tools = this.registry.getAllTools();
48
- const categories = this.registry.getCategories();
56
+ const tools = this.toolRegistry.getAllTools();
57
+ const categories = this.toolRegistry.getCategories();
58
+ // Generate paths from tool registry (MCP tools)
59
+ const toolPaths = this.generateToolPaths(tools);
60
+ // Generate paths from route registry (REST endpoints) - PRD #354
61
+ const routePaths = this.routeRegistry
62
+ ? this.generateRoutePaths()
63
+ : {};
64
+ // Generate component schemas
65
+ const toolSchemas = this.generateToolSchemas(tools);
66
+ const routeSchemas = this.routeRegistry
67
+ ? this.generateRouteSchemas()
68
+ : {};
49
69
  const spec = {
50
70
  openapi: '3.0.0',
51
71
  info: this.generateInfo(),
52
72
  servers: this.generateServers(),
53
- paths: this.generatePaths(tools),
54
- components: this.generateComponents(tools),
55
- tags: this.generateTags(categories)
73
+ paths: {
74
+ ...this.generateBasePaths(),
75
+ ...toolPaths,
76
+ ...routePaths,
77
+ },
78
+ components: {
79
+ schemas: {
80
+ ...this.generateBaseSchemas(),
81
+ ...toolSchemas,
82
+ ...routeSchemas,
83
+ },
84
+ },
85
+ tags: this.generateTags(categories),
56
86
  };
57
87
  // Cache the generated spec
58
88
  this.specCache = spec;
@@ -60,7 +90,7 @@ class OpenApiGenerator {
60
90
  this.logger.info('OpenAPI specification generated successfully', {
61
91
  pathCount: Object.keys(spec.paths).length,
62
92
  componentCount: Object.keys(spec.components?.schemas || {}).length,
63
- tagCount: spec.tags?.length || 0
93
+ tagCount: spec.tags?.length || 0,
64
94
  });
65
95
  return spec;
66
96
  }
@@ -96,11 +126,10 @@ class OpenApiGenerator {
96
126
  ];
97
127
  }
98
128
  /**
99
- * Generate paths for all endpoints
129
+ * Generate base paths (MCP Protocol endpoints)
100
130
  */
101
- generatePaths(tools) {
131
+ generateBasePaths() {
102
132
  const paths = {};
103
- const basePath = `${this.config.basePath}/${this.config.apiVersion}`;
104
133
  // MCP Protocol Endpoints
105
134
  paths['/'] = {
106
135
  get: {
@@ -115,20 +144,20 @@ class OpenApiGenerator {
115
144
  'text/event-stream': {
116
145
  schema: {
117
146
  type: 'string',
118
- description: 'Server-Sent Events stream'
119
- }
120
- }
121
- }
147
+ description: 'Server-Sent Events stream',
148
+ },
149
+ },
150
+ },
122
151
  },
123
152
  405: {
124
153
  description: 'Method not allowed - server does not support SSE',
125
154
  content: {
126
155
  'application/json': {
127
- schema: { $ref: '#/components/schemas/ErrorResponse' }
128
- }
129
- }
130
- }
131
- }
156
+ schema: { $ref: '#/components/schemas/ErrorResponse' },
157
+ },
158
+ },
159
+ },
160
+ },
132
161
  },
133
162
  post: {
134
163
  summary: 'Send MCP JSON-RPC message',
@@ -151,10 +180,10 @@ class OpenApiGenerator {
151
180
  capabilities: {},
152
181
  clientInfo: {
153
182
  name: 'example-client',
154
- version: '1.0.0'
155
- }
156
- }
157
- }
183
+ version: '1.0.0',
184
+ },
185
+ },
186
+ },
158
187
  },
159
188
  toolCall: {
160
189
  summary: 'Call a tool',
@@ -164,81 +193,48 @@ class OpenApiGenerator {
164
193
  method: 'tools/call',
165
194
  params: {
166
195
  name: 'version',
167
- arguments: {}
168
- }
169
- }
170
- }
171
- }
172
- }
173
- }
196
+ arguments: {},
197
+ },
198
+ },
199
+ },
200
+ },
201
+ },
202
+ },
174
203
  },
175
204
  responses: {
176
205
  200: {
177
206
  description: 'JSON-RPC response or SSE stream',
178
207
  content: {
179
208
  'application/json': {
180
- schema: { $ref: '#/components/schemas/McpJsonRpcResponse' }
209
+ schema: { $ref: '#/components/schemas/McpJsonRpcResponse' },
181
210
  },
182
211
  'text/event-stream': {
183
212
  schema: {
184
213
  type: 'string',
185
- description: 'Server-Sent Events stream with JSON-RPC messages'
186
- }
187
- }
188
- }
214
+ description: 'Server-Sent Events stream with JSON-RPC messages',
215
+ },
216
+ },
217
+ },
189
218
  },
190
219
  400: {
191
220
  description: 'Bad request - invalid JSON-RPC message',
192
221
  content: {
193
222
  'application/json': {
194
- schema: { $ref: '#/components/schemas/McpJsonRpcError' }
195
- }
196
- }
197
- }
198
- }
199
- }
200
- };
201
- // Tool discovery endpoint
202
- paths[`${basePath}/tools`] = {
203
- get: {
204
- summary: 'Discover available tools',
205
- description: 'Get a list of all available tools with their schemas and metadata',
206
- tags: ['Tool Discovery'],
207
- parameters: [
208
- {
209
- name: 'category',
210
- in: 'query',
211
- description: 'Filter tools by category',
212
- required: false,
213
- schema: { type: 'string' }
214
- },
215
- {
216
- name: 'tag',
217
- in: 'query',
218
- description: 'Filter tools by tag',
219
- required: false,
220
- schema: { type: 'string' }
223
+ schema: { $ref: '#/components/schemas/McpJsonRpcError' },
224
+ },
225
+ },
221
226
  },
222
- {
223
- name: 'search',
224
- in: 'query',
225
- description: 'Search tools by name or description',
226
- required: false,
227
- schema: { type: 'string' }
228
- }
229
- ],
230
- responses: {
231
- 200: {
232
- description: 'List of available tools',
233
- content: {
234
- 'application/json': {
235
- schema: { $ref: '#/components/schemas/ToolDiscoveryResponse' }
236
- }
237
- }
238
- }
239
- }
240
- }
227
+ },
228
+ },
241
229
  };
230
+ return paths;
231
+ }
232
+ /**
233
+ * Generate paths for MCP tool endpoints
234
+ */
235
+ generateToolPaths(tools) {
236
+ const paths = {};
237
+ const basePath = `${this.config.basePath}/${this.config.apiVersion}`;
242
238
  // Individual tool execution endpoints
243
239
  for (const tool of tools) {
244
240
  paths[`${basePath}/tools/${tool.name}`] = {
@@ -251,99 +247,303 @@ class OpenApiGenerator {
251
247
  content: {
252
248
  'application/json': {
253
249
  schema: { $ref: `#/components/schemas/${tool.name}Request` },
254
- example: this.generateExampleForTool(tool)
255
- }
256
- }
250
+ example: this.generateExampleForTool(tool),
251
+ },
252
+ },
257
253
  },
258
254
  responses: {
259
255
  200: {
260
256
  description: 'Tool execution result',
261
257
  content: {
262
258
  'application/json': {
263
- schema: { $ref: '#/components/schemas/ToolExecutionResponse' }
264
- }
265
- }
259
+ schema: { $ref: '#/components/schemas/ToolExecutionResponse' },
260
+ },
261
+ },
266
262
  },
267
263
  400: {
268
264
  description: 'Bad request - invalid parameters',
269
265
  content: {
270
266
  'application/json': {
271
- schema: { $ref: '#/components/schemas/ErrorResponse' }
272
- }
273
- }
267
+ schema: { $ref: '#/components/schemas/ErrorResponse' },
268
+ },
269
+ },
274
270
  },
275
271
  404: {
276
272
  description: 'Tool not found',
277
273
  content: {
278
274
  'application/json': {
279
- schema: { $ref: '#/components/schemas/ErrorResponse' }
280
- }
281
- }
275
+ schema: { $ref: '#/components/schemas/ErrorResponse' },
276
+ },
277
+ },
282
278
  },
283
279
  500: {
284
280
  description: 'Internal server error',
285
281
  content: {
286
282
  'application/json': {
287
- schema: { $ref: '#/components/schemas/ErrorResponse' }
288
- }
289
- }
290
- }
291
- }
292
- }
283
+ schema: { $ref: '#/components/schemas/ErrorResponse' },
284
+ },
285
+ },
286
+ },
287
+ },
288
+ },
293
289
  };
294
290
  }
295
- // OpenAPI specification endpoint
296
- paths[`${basePath}/openapi`] = {
297
- get: {
298
- summary: 'Get OpenAPI specification',
299
- description: 'Returns the complete OpenAPI 3.0 specification for this API',
300
- tags: ['Documentation'],
301
- responses: {
302
- 200: {
303
- description: 'OpenAPI specification',
304
- content: {
305
- 'application/json': {
306
- schema: {
307
- type: 'object',
308
- description: 'OpenAPI 3.0 specification'
309
- }
310
- }
311
- }
312
- }
313
- }
291
+ return paths;
292
+ }
293
+ /**
294
+ * Generate paths from REST route registry
295
+ * PRD #354: Auto-generates OpenAPI paths from registered routes
296
+ */
297
+ generateRoutePaths() {
298
+ if (!this.routeRegistry) {
299
+ return {};
300
+ }
301
+ const paths = {};
302
+ const routes = this.routeRegistry.getAllRoutes();
303
+ for (const route of routes) {
304
+ const openApiPath = this.convertPathToOpenApi(route.path);
305
+ const method = route.method.toLowerCase();
306
+ // Initialize path object if not exists
307
+ if (!paths[openApiPath]) {
308
+ paths[openApiPath] = {};
314
309
  }
315
- };
310
+ paths[openApiPath][method] = this.routeToOpenApiOperation(route);
311
+ }
316
312
  return paths;
317
313
  }
318
314
  /**
319
- * Generate component schemas
315
+ * Convert Express-style path to OpenAPI path format
316
+ * Example: "/api/v1/visualize/:sessionId" -> "/api/v1/visualize/{sessionId}"
317
+ */
318
+ convertPathToOpenApi(path) {
319
+ return path.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, '{$1}');
320
+ }
321
+ /**
322
+ * Convert a route definition to an OpenAPI operation object
323
+ */
324
+ routeToOpenApiOperation(route) {
325
+ const operation = {
326
+ summary: route.description,
327
+ description: route.description,
328
+ tags: route.tags,
329
+ responses: {},
330
+ };
331
+ // Add path parameters
332
+ const pathParams = this.extractPathParams(route.path);
333
+ if (pathParams.length > 0 || route.query) {
334
+ operation.parameters = [];
335
+ // Add path parameters
336
+ for (const paramName of pathParams) {
337
+ const paramSchema = this.getParamSchemaFromRoute(route, paramName);
338
+ operation.parameters.push({
339
+ name: paramName,
340
+ in: 'path',
341
+ required: true,
342
+ description: paramSchema?.description || `${paramName} parameter`,
343
+ schema: paramSchema || { type: 'string' },
344
+ });
345
+ }
346
+ // Add query parameters from Zod schema
347
+ if (route.query) {
348
+ const queryParams = this.zodSchemaToParameters(route.query, 'query');
349
+ operation.parameters.push(...queryParams);
350
+ }
351
+ }
352
+ // Add request body for POST/PUT/DELETE with body schema
353
+ if (route.body && ['POST', 'PUT', 'DELETE'].includes(route.method)) {
354
+ const schemaName = this.getSchemaName(route, 'Request');
355
+ operation.requestBody = {
356
+ required: true,
357
+ content: {
358
+ 'application/json': {
359
+ schema: { $ref: `#/components/schemas/${schemaName}` },
360
+ },
361
+ },
362
+ };
363
+ }
364
+ // Add success response
365
+ const responseSchemaName = this.getSchemaName(route, 'Response');
366
+ operation.responses['200'] = {
367
+ description: 'Successful response',
368
+ content: {
369
+ 'application/json': {
370
+ schema: { $ref: `#/components/schemas/${responseSchemaName}` },
371
+ },
372
+ },
373
+ };
374
+ // Add error responses
375
+ if (route.errorResponses) {
376
+ for (const statusCode of Object.keys(route.errorResponses)) {
377
+ const errorSchemaName = this.getSchemaName(route, `Error${statusCode}`);
378
+ operation.responses[statusCode] = {
379
+ description: this.getErrorDescription(Number(statusCode)),
380
+ content: {
381
+ 'application/json': {
382
+ schema: { $ref: `#/components/schemas/${errorSchemaName}` },
383
+ },
384
+ },
385
+ };
386
+ }
387
+ }
388
+ return operation;
389
+ }
390
+ /**
391
+ * Extract path parameter names from a route path
320
392
  */
321
- generateComponents(tools) {
393
+ extractPathParams(path) {
394
+ const params = [];
395
+ const regex = /:([a-zA-Z_][a-zA-Z0-9_]*)/g;
396
+ let match;
397
+ while ((match = regex.exec(path)) !== null) {
398
+ params.push(match[1]);
399
+ }
400
+ return params;
401
+ }
402
+ /**
403
+ * Get parameter schema from route's params Zod schema
404
+ */
405
+ getParamSchemaFromRoute(route, paramName) {
406
+ if (!route.params) {
407
+ return { type: 'string' };
408
+ }
409
+ try {
410
+ const jsonSchema = this.zodSchemaToJsonSchema(route.params);
411
+ return jsonSchema.properties?.[paramName] || { type: 'string' };
412
+ }
413
+ catch {
414
+ return { type: 'string' };
415
+ }
416
+ }
417
+ /**
418
+ * Convert Zod schema to OpenAPI parameters array
419
+ */
420
+ zodSchemaToParameters(schema, location) {
421
+ const parameters = [];
422
+ try {
423
+ const jsonSchema = this.zodSchemaToJsonSchema(schema);
424
+ const properties = jsonSchema.properties || {};
425
+ const required = jsonSchema.required || [];
426
+ for (const [name, propSchema] of Object.entries(properties)) {
427
+ const propObj = propSchema;
428
+ parameters.push({
429
+ name,
430
+ in: location,
431
+ required: required.includes(name),
432
+ description: propObj.description || `${name} parameter`,
433
+ schema: propObj,
434
+ });
435
+ }
436
+ }
437
+ catch (error) {
438
+ this.logger.warn('Failed to convert Zod schema to parameters', {
439
+ error: error instanceof Error ? error.message : String(error),
440
+ });
441
+ }
442
+ return parameters;
443
+ }
444
+ /**
445
+ * Generate unique schema name for a route
446
+ */
447
+ getSchemaName(route, suffix) {
448
+ // Convert path to PascalCase name
449
+ // e.g., "/api/v1/visualize/:sessionId" -> "VisualizeSessionId"
450
+ const pathParts = route.path
451
+ .replace(/^\/api\/v\d+\//, '') // Remove /api/v1/ prefix
452
+ .split('/')
453
+ .filter((part) => part.length > 0)
454
+ .map((part) => {
455
+ // Remove : prefix for params and capitalize
456
+ const cleaned = part.replace(/^:/, '');
457
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
458
+ });
459
+ const baseName = pathParts.join('');
460
+ return `${baseName}${route.method.charAt(0)}${route.method.slice(1).toLowerCase()}${suffix}`;
461
+ }
462
+ /**
463
+ * Get human-readable error description for status code
464
+ */
465
+ getErrorDescription(statusCode) {
466
+ const descriptions = {
467
+ 400: 'Bad request - invalid parameters',
468
+ 401: 'Unauthorized - authentication required',
469
+ 403: 'Forbidden - insufficient permissions',
470
+ 404: 'Not found',
471
+ 405: 'Method not allowed',
472
+ 409: 'Conflict',
473
+ 422: 'Unprocessable entity',
474
+ 500: 'Internal server error',
475
+ 502: 'Bad gateway',
476
+ 503: 'Service unavailable',
477
+ };
478
+ return descriptions[statusCode] || `Error ${statusCode}`;
479
+ }
480
+ /**
481
+ * Convert Zod schema to JSON Schema with caching
482
+ */
483
+ zodSchemaToJsonSchema(schema) {
484
+ const cacheKey = JSON.stringify(schema);
485
+ if (this.schemaCache.has(cacheKey)) {
486
+ return this.schemaCache.get(cacheKey);
487
+ }
488
+ try {
489
+ // The zodToJsonSchema function accepts ZodSchema but TypeScript needs a cast
490
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Zod type compatibility workaround
491
+ const jsonSchema = (0, zod_to_json_schema_1.zodToJsonSchema)(schema, {
492
+ target: 'openApi3',
493
+ $refStrategy: 'none', // Inline all schemas
494
+ });
495
+ // Remove $schema property if present (not valid in OpenAPI component schemas)
496
+ const result = { ...jsonSchema };
497
+ delete result.$schema;
498
+ this.schemaCache.set(cacheKey, result);
499
+ return result;
500
+ }
501
+ catch (error) {
502
+ this.logger.warn('Failed to convert Zod schema to JSON Schema', {
503
+ error: error instanceof Error ? error.message : String(error),
504
+ });
505
+ return { type: 'object' };
506
+ }
507
+ }
508
+ /**
509
+ * Generate base component schemas (shared across all endpoints)
510
+ */
511
+ generateBaseSchemas() {
322
512
  const schemas = {};
323
513
  // Base response schemas
324
514
  schemas.RestApiResponse = {
325
515
  type: 'object',
326
516
  properties: {
327
- success: { type: 'boolean', description: 'Whether the request was successful' },
517
+ success: {
518
+ type: 'boolean',
519
+ description: 'Whether the request was successful',
520
+ },
328
521
  data: { type: 'object', description: 'Response data' },
329
522
  error: {
330
523
  type: 'object',
331
524
  properties: {
332
525
  code: { type: 'string', description: 'Error code' },
333
526
  message: { type: 'string', description: 'Error message' },
334
- details: { type: 'object', description: 'Additional error details' }
335
- }
527
+ details: { type: 'object', description: 'Additional error details' },
528
+ },
336
529
  },
337
530
  meta: {
338
531
  type: 'object',
339
532
  properties: {
340
- timestamp: { type: 'string', format: 'date-time', description: 'Response timestamp' },
341
- requestId: { type: 'string', description: 'Unique request identifier' },
342
- version: { type: 'string', description: 'API version' }
343
- }
344
- }
533
+ timestamp: {
534
+ type: 'string',
535
+ format: 'date-time',
536
+ description: 'Response timestamp',
537
+ },
538
+ requestId: {
539
+ type: 'string',
540
+ description: 'Unique request identifier',
541
+ },
542
+ version: { type: 'string', description: 'API version' },
543
+ },
544
+ },
345
545
  },
346
- required: ['success']
546
+ required: ['success'],
347
547
  };
348
548
  schemas.ToolExecutionResponse = {
349
549
  allOf: [
@@ -354,14 +554,23 @@ class OpenApiGenerator {
354
554
  data: {
355
555
  type: 'object',
356
556
  properties: {
357
- result: { type: 'object', description: 'Tool execution result' },
358
- tool: { type: 'string', description: 'Name of the executed tool' },
359
- executionTime: { type: 'number', description: 'Execution time in milliseconds' }
360
- }
361
- }
362
- }
363
- }
364
- ]
557
+ result: {
558
+ type: 'object',
559
+ description: 'Tool execution result',
560
+ },
561
+ tool: {
562
+ type: 'string',
563
+ description: 'Name of the executed tool',
564
+ },
565
+ executionTime: {
566
+ type: 'number',
567
+ description: 'Execution time in milliseconds',
568
+ },
569
+ },
570
+ },
571
+ },
572
+ },
573
+ ],
365
574
  };
366
575
  schemas.ToolDiscoveryResponse = {
367
576
  allOf: [
@@ -374,24 +583,27 @@ class OpenApiGenerator {
374
583
  properties: {
375
584
  tools: {
376
585
  type: 'array',
377
- items: { $ref: '#/components/schemas/ToolInfo' }
586
+ items: { $ref: '#/components/schemas/ToolInfo' },
587
+ },
588
+ total: {
589
+ type: 'number',
590
+ description: 'Total number of tools',
378
591
  },
379
- total: { type: 'number', description: 'Total number of tools' },
380
592
  categories: {
381
593
  type: 'array',
382
594
  items: { type: 'string' },
383
- description: 'Available tool categories'
595
+ description: 'Available tool categories',
384
596
  },
385
597
  tags: {
386
598
  type: 'array',
387
599
  items: { type: 'string' },
388
- description: 'Available tool tags'
389
- }
390
- }
391
- }
392
- }
393
- }
394
- ]
600
+ description: 'Available tool tags',
601
+ },
602
+ },
603
+ },
604
+ },
605
+ },
606
+ ],
395
607
  };
396
608
  schemas.ToolInfo = {
397
609
  type: 'object',
@@ -403,10 +615,10 @@ class OpenApiGenerator {
403
615
  tags: {
404
616
  type: 'array',
405
617
  items: { type: 'string' },
406
- description: 'Tool tags'
407
- }
618
+ description: 'Tool tags',
619
+ },
408
620
  },
409
- required: ['name', 'description', 'schema']
621
+ required: ['name', 'description', 'schema'],
410
622
  };
411
623
  schemas.ErrorResponse = {
412
624
  allOf: [
@@ -420,70 +632,128 @@ class OpenApiGenerator {
420
632
  properties: {
421
633
  code: { type: 'string' },
422
634
  message: { type: 'string' },
423
- details: { type: 'object' }
635
+ details: { type: 'object' },
424
636
  },
425
- required: ['code', 'message']
426
- }
637
+ required: ['code', 'message'],
638
+ },
427
639
  },
428
- required: ['error']
429
- }
430
- ]
640
+ required: ['error'],
641
+ },
642
+ ],
431
643
  };
432
644
  // MCP JSON-RPC schemas
433
645
  schemas.McpJsonRpcRequest = {
434
646
  type: 'object',
435
647
  description: 'JSON-RPC 2.0 request message for MCP protocol',
436
648
  properties: {
437
- jsonrpc: { type: 'string', enum: ['2.0'], description: 'JSON-RPC version' },
438
- id: { type: ['number', 'string', 'null'], description: 'Request identifier' },
439
- method: { type: 'string', description: 'Method name (e.g., initialize, tools/call, tools/list)' },
440
- params: { type: 'object', description: 'Method parameters' }
649
+ jsonrpc: {
650
+ type: 'string',
651
+ enum: ['2.0'],
652
+ description: 'JSON-RPC version',
653
+ },
654
+ id: {
655
+ type: ['number', 'string', 'null'],
656
+ description: 'Request identifier',
657
+ },
658
+ method: {
659
+ type: 'string',
660
+ description: 'Method name (e.g., initialize, tools/call, tools/list)',
661
+ },
662
+ params: { type: 'object', description: 'Method parameters' },
441
663
  },
442
- required: ['jsonrpc', 'method']
664
+ required: ['jsonrpc', 'method'],
443
665
  };
444
666
  schemas.McpJsonRpcResponse = {
445
667
  type: 'object',
446
668
  description: 'JSON-RPC 2.0 response message',
447
669
  properties: {
448
- jsonrpc: { type: 'string', enum: ['2.0'], description: 'JSON-RPC version' },
449
- id: { type: ['number', 'string', 'null'], description: 'Request identifier' },
670
+ jsonrpc: {
671
+ type: 'string',
672
+ enum: ['2.0'],
673
+ description: 'JSON-RPC version',
674
+ },
675
+ id: {
676
+ type: ['number', 'string', 'null'],
677
+ description: 'Request identifier',
678
+ },
450
679
  result: { type: 'object', description: 'Method result' },
451
680
  error: {
452
681
  type: 'object',
453
682
  properties: {
454
683
  code: { type: 'number', description: 'Error code' },
455
684
  message: { type: 'string', description: 'Error message' },
456
- data: { type: 'object', description: 'Additional error data' }
457
- }
458
- }
685
+ data: { type: 'object', description: 'Additional error data' },
686
+ },
687
+ },
459
688
  },
460
- required: ['jsonrpc', 'id']
689
+ required: ['jsonrpc', 'id'],
461
690
  };
462
691
  schemas.McpJsonRpcError = {
463
692
  type: 'object',
464
693
  description: 'JSON-RPC 2.0 error response',
465
694
  properties: {
466
- jsonrpc: { type: 'string', enum: ['2.0'], description: 'JSON-RPC version' },
467
- id: { type: ['number', 'string', 'null'], description: 'Request identifier' },
695
+ jsonrpc: {
696
+ type: 'string',
697
+ enum: ['2.0'],
698
+ description: 'JSON-RPC version',
699
+ },
700
+ id: {
701
+ type: ['number', 'string', 'null'],
702
+ description: 'Request identifier',
703
+ },
468
704
  error: {
469
705
  type: 'object',
470
706
  properties: {
471
707
  code: { type: 'number', description: 'Error code' },
472
708
  message: { type: 'string', description: 'Error message' },
473
- data: { type: 'object', description: 'Additional error data' }
709
+ data: { type: 'object', description: 'Additional error data' },
474
710
  },
475
- required: ['code', 'message']
476
- }
711
+ required: ['code', 'message'],
712
+ },
477
713
  },
478
- required: ['jsonrpc', 'id', 'error']
714
+ required: ['jsonrpc', 'id', 'error'],
479
715
  };
716
+ return schemas;
717
+ }
718
+ /**
719
+ * Generate schemas for MCP tool endpoints
720
+ */
721
+ generateToolSchemas(tools) {
722
+ const schemas = {};
480
723
  // Individual tool request schemas
481
724
  for (const tool of tools) {
482
725
  schemas[`${tool.name}Request`] = tool.schema;
483
726
  }
484
- return {
485
- schemas
486
- };
727
+ return schemas;
728
+ }
729
+ /**
730
+ * Generate schemas from REST route registry
731
+ * PRD #354: Auto-generates OpenAPI schemas from route Zod schemas
732
+ */
733
+ generateRouteSchemas() {
734
+ if (!this.routeRegistry) {
735
+ return {};
736
+ }
737
+ const schemas = {};
738
+ const routes = this.routeRegistry.getAllRoutes();
739
+ for (const route of routes) {
740
+ // Add response schema
741
+ const responseSchemaName = this.getSchemaName(route, 'Response');
742
+ schemas[responseSchemaName] = this.zodSchemaToJsonSchema(route.response);
743
+ // Add request body schema if present
744
+ if (route.body) {
745
+ const requestSchemaName = this.getSchemaName(route, 'Request');
746
+ schemas[requestSchemaName] = this.zodSchemaToJsonSchema(route.body);
747
+ }
748
+ // Add error response schemas
749
+ if (route.errorResponses) {
750
+ for (const [statusCode, errorSchema] of Object.entries(route.errorResponses)) {
751
+ const errorSchemaName = this.getSchemaName(route, `Error${statusCode}`);
752
+ schemas[errorSchemaName] = this.zodSchemaToJsonSchema(errorSchema);
753
+ }
754
+ }
755
+ }
756
+ return schemas;
487
757
  }
488
758
  /**
489
759
  * Generate tags for grouping endpoints
@@ -492,30 +762,51 @@ class OpenApiGenerator {
492
762
  const tags = [
493
763
  {
494
764
  name: 'MCP Protocol',
495
- description: 'Model Context Protocol endpoints for AI assistant integration via JSON-RPC and Server-Sent Events'
765
+ description: 'Model Context Protocol endpoints for AI assistant integration via JSON-RPC and Server-Sent Events',
496
766
  },
497
767
  {
498
768
  name: 'Tool Discovery',
499
- description: 'Endpoints for discovering available tools and their capabilities'
769
+ description: 'Endpoints for discovering available tools and their capabilities',
500
770
  },
501
771
  {
502
772
  name: 'Documentation',
503
- description: 'API documentation and specification endpoints'
504
- }
773
+ description: 'API documentation and specification endpoints',
774
+ },
505
775
  ];
506
- // Add category-based tags
776
+ // Track tag names to avoid duplicates
777
+ const tagNames = new Set(tags.map((t) => t.name));
778
+ // Add category-based tags from tool registry
507
779
  for (const category of categories) {
508
- tags.push({
509
- name: category,
510
- description: `${category} tools and operations`
511
- });
780
+ if (!tagNames.has(category)) {
781
+ tags.push({
782
+ name: category,
783
+ description: `${category} tools and operations`,
784
+ });
785
+ tagNames.add(category);
786
+ }
512
787
  }
513
788
  // Add generic tools tag for uncategorized tools
514
- if (this.registry.getAllTools().some(tool => !tool.category)) {
515
- tags.push({
516
- name: 'Tools',
517
- description: 'General purpose tools and utilities'
518
- });
789
+ if (this.toolRegistry.getAllTools().some((tool) => !tool.category)) {
790
+ if (!tagNames.has('Tools')) {
791
+ tags.push({
792
+ name: 'Tools',
793
+ description: 'General purpose tools and utilities',
794
+ });
795
+ tagNames.add('Tools');
796
+ }
797
+ }
798
+ // PRD #354: Add tags from route registry
799
+ if (this.routeRegistry) {
800
+ const routeTags = this.routeRegistry.getTags();
801
+ for (const routeTag of routeTags) {
802
+ if (!tagNames.has(routeTag)) {
803
+ tags.push({
804
+ name: routeTag,
805
+ description: `${routeTag} endpoints`,
806
+ });
807
+ tagNames.add(routeTag);
808
+ }
809
+ }
519
810
  }
520
811
  return tags;
521
812
  }