@vfarcic/dot-ai 0.173.0 → 0.175.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 (40) hide show
  1. package/README.md +1 -0
  2. package/dist/core/base-vector-service.d.ts +6 -0
  3. package/dist/core/base-vector-service.d.ts.map +1 -1
  4. package/dist/core/base-vector-service.js +13 -0
  5. package/dist/core/capability-tools.d.ts +38 -0
  6. package/dist/core/capability-tools.d.ts.map +1 -0
  7. package/dist/core/capability-tools.js +202 -0
  8. package/dist/core/resource-tools.d.ts +38 -0
  9. package/dist/core/resource-tools.d.ts.map +1 -0
  10. package/dist/core/resource-tools.js +216 -0
  11. package/dist/core/resource-vector-service.d.ts +12 -0
  12. package/dist/core/resource-vector-service.d.ts.map +1 -1
  13. package/dist/core/resource-vector-service.js +16 -5
  14. package/dist/core/tracing/qdrant-tracing.d.ts +1 -1
  15. package/dist/core/tracing/qdrant-tracing.d.ts.map +1 -1
  16. package/dist/core/user-prompts-loader.d.ts +66 -0
  17. package/dist/core/user-prompts-loader.d.ts.map +1 -0
  18. package/dist/core/user-prompts-loader.js +319 -0
  19. package/dist/core/vector-db-service.d.ts +6 -0
  20. package/dist/core/vector-db-service.d.ts.map +1 -1
  21. package/dist/core/vector-db-service.js +32 -0
  22. package/dist/interfaces/mcp.d.ts.map +1 -1
  23. package/dist/interfaces/mcp.js +10 -2
  24. package/dist/interfaces/resource-sync-handler.d.ts.map +1 -1
  25. package/dist/interfaces/resource-sync-handler.js +4 -1
  26. package/dist/interfaces/rest-api.d.ts +8 -0
  27. package/dist/interfaces/rest-api.d.ts.map +1 -1
  28. package/dist/interfaces/rest-api.js +98 -2
  29. package/dist/tools/prompts.d.ts +21 -3
  30. package/dist/tools/prompts.d.ts.map +1 -1
  31. package/dist/tools/prompts.js +166 -26
  32. package/dist/tools/query.d.ts +34 -0
  33. package/dist/tools/query.d.ts.map +1 -0
  34. package/dist/tools/query.js +209 -0
  35. package/package.json +1 -1
  36. package/prompts/query-system.md +15 -0
  37. package/scripts/crossplane.nu +8 -58
  38. package/scripts/dot-ai.nu +23 -9
  39. package/shared-prompts/prd-create.md +6 -2
  40. package/shared-prompts/prd-start.md +17 -3
@@ -10,6 +10,7 @@ exports.RestApiRouter = exports.HttpStatus = void 0;
10
10
  const node_url_1 = require("node:url");
11
11
  const openapi_generator_1 = require("./openapi-generator");
12
12
  const resource_sync_handler_1 = require("./resource-sync-handler");
13
+ const prompts_1 = require("../tools/prompts");
13
14
  /**
14
15
  * HTTP status codes for REST responses
15
16
  */
@@ -118,6 +119,25 @@ class RestApiRouter {
118
119
  await this.sendErrorResponse(res, requestId, HttpStatus.NOT_FOUND, 'NOT_FOUND', 'Unknown resources endpoint');
119
120
  }
120
121
  break;
122
+ case 'prompts':
123
+ if (req.method === 'GET') {
124
+ await this.handlePromptsListRequest(req, res, requestId);
125
+ }
126
+ else {
127
+ await this.sendErrorResponse(res, requestId, HttpStatus.METHOD_NOT_ALLOWED, 'METHOD_NOT_ALLOWED', 'Only GET method allowed for prompts list');
128
+ }
129
+ break;
130
+ case 'prompt':
131
+ if (req.method === 'POST' && pathMatch.promptName) {
132
+ await this.handlePromptsGetRequest(req, res, requestId, pathMatch.promptName, body);
133
+ }
134
+ else if (req.method !== 'POST') {
135
+ await this.sendErrorResponse(res, requestId, HttpStatus.METHOD_NOT_ALLOWED, 'METHOD_NOT_ALLOWED', 'Only POST method allowed for prompt get');
136
+ }
137
+ else {
138
+ await this.sendErrorResponse(res, requestId, HttpStatus.BAD_REQUEST, 'BAD_REQUEST', 'Prompt name is required');
139
+ }
140
+ break;
121
141
  default:
122
142
  await this.sendErrorResponse(res, requestId, HttpStatus.NOT_FOUND, 'NOT_FOUND', 'Unknown API endpoint');
123
143
  }
@@ -139,6 +159,8 @@ class RestApiRouter {
139
159
  // /api/v1/tools/{toolName} -> tool execution
140
160
  // /api/v1/openapi -> OpenAPI spec
141
161
  // /api/v1/resources/sync -> resource sync from controller
162
+ // /api/v1/prompts -> prompts list
163
+ // /api/v1/prompts/{promptName} -> prompt get
142
164
  const basePath = `${this.config.basePath}/${this.config.version}`;
143
165
  if (!pathname.startsWith(basePath)) {
144
166
  return null;
@@ -162,6 +184,16 @@ class RestApiRouter {
162
184
  if (cleanPath === 'resources/sync') {
163
185
  return { endpoint: 'resources', action: 'sync' };
164
186
  }
187
+ // Handle prompts endpoints
188
+ if (cleanPath === 'prompts') {
189
+ return { endpoint: 'prompts' };
190
+ }
191
+ if (cleanPath.startsWith('prompts/')) {
192
+ const promptName = cleanPath.substring(8); // Remove 'prompts/'
193
+ if (promptName) {
194
+ return { endpoint: 'prompt', promptName };
195
+ }
196
+ }
165
197
  return null;
166
198
  }
167
199
  /**
@@ -272,12 +304,13 @@ class RestApiRouter {
272
304
  });
273
305
  }
274
306
  catch (error) {
307
+ const errorMessage = error instanceof Error ? error.message : String(error);
275
308
  this.logger.error('Tool execution failed', error instanceof Error ? error : new Error(String(error)), {
276
309
  requestId,
277
310
  toolName,
278
- errorMessage: error instanceof Error ? error.message : String(error)
311
+ errorMessage
279
312
  });
280
- await this.sendErrorResponse(res, requestId, HttpStatus.INTERNAL_SERVER_ERROR, 'EXECUTION_ERROR', 'Tool execution failed');
313
+ await this.sendErrorResponse(res, requestId, HttpStatus.INTERNAL_SERVER_ERROR, 'EXECUTION_ERROR', errorMessage);
281
314
  }
282
315
  }
283
316
  /**
@@ -346,6 +379,69 @@ class RestApiRouter {
346
379
  await this.sendErrorResponse(res, requestId, HttpStatus.INTERNAL_SERVER_ERROR, 'SYNC_ERROR', 'Resource sync failed', { error: errorMessage });
347
380
  }
348
381
  }
382
+ /**
383
+ * Handle prompts list requests
384
+ */
385
+ async handlePromptsListRequest(req, res, requestId) {
386
+ try {
387
+ this.logger.info('Processing prompts list request', { requestId });
388
+ const result = await (0, prompts_1.handlePromptsListRequest)({}, this.logger, requestId);
389
+ const response = {
390
+ success: true,
391
+ data: result,
392
+ meta: {
393
+ timestamp: new Date().toISOString(),
394
+ requestId,
395
+ version: this.config.version
396
+ }
397
+ };
398
+ await this.sendJsonResponse(res, HttpStatus.OK, response);
399
+ this.logger.info('Prompts list request completed', {
400
+ requestId,
401
+ promptCount: result.prompts?.length || 0
402
+ });
403
+ }
404
+ catch (error) {
405
+ this.logger.error('Prompts list request failed', error instanceof Error ? error : new Error(String(error)), {
406
+ requestId
407
+ });
408
+ await this.sendErrorResponse(res, requestId, HttpStatus.INTERNAL_SERVER_ERROR, 'PROMPTS_LIST_ERROR', 'Failed to list prompts');
409
+ }
410
+ }
411
+ /**
412
+ * Handle prompt get requests
413
+ */
414
+ async handlePromptsGetRequest(req, res, requestId, promptName, body) {
415
+ try {
416
+ this.logger.info('Processing prompt get request', { requestId, promptName });
417
+ const result = await (0, prompts_1.handlePromptsGetRequest)({ name: promptName, arguments: body?.arguments }, this.logger, requestId);
418
+ const response = {
419
+ success: true,
420
+ data: result,
421
+ meta: {
422
+ timestamp: new Date().toISOString(),
423
+ requestId,
424
+ version: this.config.version
425
+ }
426
+ };
427
+ await this.sendJsonResponse(res, HttpStatus.OK, response);
428
+ this.logger.info('Prompt get request completed', {
429
+ requestId,
430
+ promptName
431
+ });
432
+ }
433
+ catch (error) {
434
+ const errorMessage = error instanceof Error ? error.message : String(error);
435
+ this.logger.error('Prompt get request failed', error instanceof Error ? error : new Error(String(error)), {
436
+ requestId,
437
+ promptName
438
+ });
439
+ // Check if it's a validation error (missing required arguments or prompt not found)
440
+ const isValidationError = errorMessage.includes('Missing required arguments') ||
441
+ errorMessage.includes('Prompt not found');
442
+ await this.sendErrorResponse(res, requestId, isValidationError ? HttpStatus.BAD_REQUEST : HttpStatus.INTERNAL_SERVER_ERROR, isValidationError ? 'VALIDATION_ERROR' : 'PROMPT_GET_ERROR', errorMessage);
443
+ }
444
+ }
349
445
  /**
350
446
  * Set CORS headers
351
447
  */
@@ -2,24 +2,42 @@
2
2
  * MCP Prompts Handler - Manages shared prompt library
3
3
  */
4
4
  import { Logger } from '../core/error-handling';
5
+ export interface PromptArgument {
6
+ name: string;
7
+ description?: string;
8
+ required?: boolean;
9
+ }
5
10
  export interface PromptMetadata {
6
11
  name: string;
7
12
  description: string;
8
13
  category: string;
14
+ arguments?: PromptArgument[];
9
15
  }
10
16
  export interface Prompt {
11
17
  name: string;
12
18
  description: string;
13
19
  content: string;
20
+ arguments?: PromptArgument[];
21
+ source: 'built-in' | 'user';
14
22
  }
15
23
  /**
16
24
  * Loads and parses a prompt file with YAML frontmatter
17
25
  */
18
- export declare function loadPromptFile(filePath: string): Prompt;
26
+ export declare function loadPromptFile(filePath: string, source?: 'built-in' | 'user'): Prompt;
27
+ /**
28
+ * Loads built-in prompts from the shared-prompts directory
29
+ */
30
+ export declare function loadBuiltInPrompts(logger: Logger, baseDir?: string): Prompt[];
31
+ /**
32
+ * Merge built-in and user prompts with collision detection
33
+ * Built-in prompts take precedence over user prompts with the same name
34
+ */
35
+ export declare function mergePrompts(builtInPrompts: Prompt[], userPrompts: Prompt[], logger: Logger): Prompt[];
19
36
  /**
20
- * Loads all prompts from the shared-prompts directory
37
+ * Loads all prompts (built-in + user) with collision detection
38
+ * This is the main entry point for loading prompts
21
39
  */
22
- export declare function loadAllPrompts(logger: Logger, baseDir?: string): Prompt[];
40
+ export declare function loadAllPrompts(logger: Logger, baseDir?: string, forceRefresh?: boolean): Promise<Prompt[]>;
23
41
  /**
24
42
  * Handle prompts/list MCP request
25
43
  */
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/tools/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAOhD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA4CvD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAoCzE;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,CAsCd;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,CAoEd"}
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/tools/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAOhD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;CAC7B;AA8ED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,UAAU,GAAG,MAAmB,GAAG,MAAM,CAmCjG;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAoC7E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,cAAc,EAAE,MAAM,EAAE,EACxB,WAAW,EAAE,MAAM,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,MAAM,EAAE,CAgBV;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,YAAY,GAAE,OAAe,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BnB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,CA4Cd;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,CAiGd"}
@@ -37,16 +37,90 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  })();
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.loadPromptFile = loadPromptFile;
40
+ exports.loadBuiltInPrompts = loadBuiltInPrompts;
41
+ exports.mergePrompts = mergePrompts;
40
42
  exports.loadAllPrompts = loadAllPrompts;
41
43
  exports.handlePromptsListRequest = handlePromptsListRequest;
42
44
  exports.handlePromptsGetRequest = handlePromptsGetRequest;
43
45
  const fs = __importStar(require("fs"));
44
46
  const path = __importStar(require("path"));
45
47
  const error_handling_1 = require("../core/error-handling");
48
+ /**
49
+ * Parses YAML frontmatter with support for nested arguments array
50
+ */
51
+ function parseYamlFrontmatter(yaml) {
52
+ const metadata = {};
53
+ const lines = yaml.split('\n');
54
+ let i = 0;
55
+ while (i < lines.length) {
56
+ const line = lines[i];
57
+ // Check for arguments array start
58
+ if (line.match(/^arguments:\s*$/)) {
59
+ const args = [];
60
+ i++;
61
+ // Parse array items (lines starting with " - ")
62
+ while (i < lines.length && lines[i].match(/^\s+-\s/)) {
63
+ const arg = { name: '' };
64
+ // First line of array item: " - name: value"
65
+ const firstLineMatch = lines[i].match(/^\s+-\s+(\w+):\s*(.*)$/);
66
+ if (firstLineMatch) {
67
+ const [, key, value] = firstLineMatch;
68
+ if (key === 'name') {
69
+ arg.name = value.trim().replace(/^["']|["']$/g, '');
70
+ }
71
+ else if (key === 'description') {
72
+ arg.description = value.trim().replace(/^["']|["']$/g, '');
73
+ }
74
+ else if (key === 'required') {
75
+ arg.required = value.trim().toLowerCase() === 'true';
76
+ }
77
+ }
78
+ i++;
79
+ // Continue parsing properties of this array item (lines starting with " ")
80
+ while (i < lines.length && lines[i].match(/^\s{4,}\w+:/)) {
81
+ const propMatch = lines[i].match(/^\s+(\w+):\s*(.*)$/);
82
+ if (propMatch) {
83
+ const [, key, value] = propMatch;
84
+ if (key === 'name') {
85
+ arg.name = value.trim().replace(/^["']|["']$/g, '');
86
+ }
87
+ else if (key === 'description') {
88
+ arg.description = value.trim().replace(/^["']|["']$/g, '');
89
+ }
90
+ else if (key === 'required') {
91
+ arg.required = value.trim().toLowerCase() === 'true';
92
+ }
93
+ }
94
+ i++;
95
+ }
96
+ if (arg.name) {
97
+ args.push(arg);
98
+ }
99
+ }
100
+ if (args.length > 0) {
101
+ metadata.arguments = args;
102
+ }
103
+ }
104
+ else {
105
+ // Simple key-value pair
106
+ const match = line.match(/^([^:]+):\s*(.+)$/);
107
+ if (match) {
108
+ const [, key, value] = match;
109
+ const cleanValue = value.trim().replace(/^["']|["']$/g, '');
110
+ const trimmedKey = key.trim();
111
+ if (trimmedKey !== 'arguments') {
112
+ metadata[trimmedKey] = cleanValue;
113
+ }
114
+ }
115
+ i++;
116
+ }
117
+ }
118
+ return metadata;
119
+ }
46
120
  /**
47
121
  * Loads and parses a prompt file with YAML frontmatter
48
122
  */
49
- function loadPromptFile(filePath) {
123
+ function loadPromptFile(filePath, source = 'built-in') {
50
124
  try {
51
125
  const content = fs.readFileSync(filePath, 'utf8');
52
126
  // Parse YAML frontmatter
@@ -55,18 +129,8 @@ function loadPromptFile(filePath) {
55
129
  throw new Error(`Invalid prompt file format: missing YAML frontmatter in ${filePath}`);
56
130
  }
57
131
  const [, frontmatterYaml, promptContent] = frontmatterMatch;
58
- // Simple YAML parsing for our specific format
59
- const metadata = {};
60
- const lines = frontmatterYaml.split('\n');
61
- for (const line of lines) {
62
- const match = line.match(/^([^:]+):\s*(.+)$/);
63
- if (match) {
64
- const [, key, value] = match;
65
- // Remove quotes if present
66
- const cleanValue = value.trim().replace(/^["']|["']$/g, '');
67
- metadata[key.trim()] = cleanValue;
68
- }
69
- }
132
+ // Parse YAML with support for arguments array
133
+ const metadata = parseYamlFrontmatter(frontmatterYaml);
70
134
  if (!metadata.name || !metadata.description || !metadata.category) {
71
135
  throw new Error(`Missing required metadata in ${filePath}: name, description, category`);
72
136
  }
@@ -74,6 +138,8 @@ function loadPromptFile(filePath) {
74
138
  name: metadata.name,
75
139
  description: metadata.description,
76
140
  content: promptContent.trim(),
141
+ arguments: metadata.arguments,
142
+ source,
77
143
  };
78
144
  }
79
145
  catch (error) {
@@ -81,9 +147,9 @@ function loadPromptFile(filePath) {
81
147
  }
82
148
  }
83
149
  /**
84
- * Loads all prompts from the shared-prompts directory
150
+ * Loads built-in prompts from the shared-prompts directory
85
151
  */
86
- function loadAllPrompts(logger, baseDir) {
152
+ function loadBuiltInPrompts(logger, baseDir) {
87
153
  try {
88
154
  const promptsDir = baseDir ?? path.join(__dirname, '..', '..', 'shared-prompts');
89
155
  if (!fs.existsSync(promptsDir)) {
@@ -96,15 +162,15 @@ function loadAllPrompts(logger, baseDir) {
96
162
  for (const file of promptFiles) {
97
163
  try {
98
164
  const filePath = path.join(promptsDir, file);
99
- const prompt = loadPromptFile(filePath);
165
+ const prompt = loadPromptFile(filePath, 'built-in');
100
166
  prompts.push(prompt);
101
- logger.debug('Loaded prompt', { name: prompt.name, file });
167
+ logger.debug('Loaded built-in prompt', { name: prompt.name, file });
102
168
  }
103
169
  catch (error) {
104
170
  logger.error(`Failed to load prompt file ${file}`, error);
105
171
  }
106
172
  }
107
- logger.info('Loaded prompts from shared library', {
173
+ logger.info('Loaded built-in prompts from shared library', {
108
174
  total: prompts.length,
109
175
  promptsDir,
110
176
  });
@@ -115,18 +181,71 @@ function loadAllPrompts(logger, baseDir) {
115
181
  return [];
116
182
  }
117
183
  }
184
+ /**
185
+ * Merge built-in and user prompts with collision detection
186
+ * Built-in prompts take precedence over user prompts with the same name
187
+ */
188
+ function mergePrompts(builtInPrompts, userPrompts, logger) {
189
+ const builtInNames = new Set(builtInPrompts.map(p => p.name));
190
+ const merged = [...builtInPrompts];
191
+ for (const userPrompt of userPrompts) {
192
+ if (builtInNames.has(userPrompt.name)) {
193
+ logger.warn('User prompt name collision with built-in prompt, skipping user prompt', {
194
+ name: userPrompt.name,
195
+ message: 'Built-in prompt takes precedence',
196
+ });
197
+ continue;
198
+ }
199
+ merged.push(userPrompt);
200
+ }
201
+ return merged;
202
+ }
203
+ /**
204
+ * Loads all prompts (built-in + user) with collision detection
205
+ * This is the main entry point for loading prompts
206
+ */
207
+ async function loadAllPrompts(logger, baseDir, forceRefresh = false) {
208
+ // Load built-in prompts (synchronous)
209
+ const builtInPrompts = loadBuiltInPrompts(logger, baseDir);
210
+ // Load user prompts from git repository (async, graceful failure)
211
+ let userPrompts = [];
212
+ try {
213
+ const { loadUserPrompts } = await Promise.resolve().then(() => __importStar(require('../core/user-prompts-loader.js')));
214
+ userPrompts = await loadUserPrompts(logger, forceRefresh);
215
+ }
216
+ catch (error) {
217
+ logger.debug('User prompts loader not available or failed', {
218
+ error: error instanceof Error ? error.message : 'Unknown error',
219
+ });
220
+ }
221
+ // Merge with collision detection
222
+ const allPrompts = mergePrompts(builtInPrompts, userPrompts, logger);
223
+ logger.info('Loaded all prompts', {
224
+ builtIn: builtInPrompts.length,
225
+ user: userPrompts.length,
226
+ total: allPrompts.length,
227
+ collisions: builtInPrompts.length + userPrompts.length - allPrompts.length,
228
+ });
229
+ return allPrompts;
230
+ }
118
231
  /**
119
232
  * Handle prompts/list MCP request
120
233
  */
121
234
  async function handlePromptsListRequest(args, logger, requestId) {
122
235
  try {
123
236
  logger.info('Processing prompts/list request', { requestId });
124
- const prompts = loadAllPrompts(logger, process.env.NODE_ENV === 'test' ? args?.baseDir : undefined);
125
- // Convert to MCP prompts/list response format
126
- const promptList = prompts.map(prompt => ({
127
- name: prompt.name,
128
- description: prompt.description,
129
- }));
237
+ const prompts = await loadAllPrompts(logger, process.env.NODE_ENV === 'test' ? args?.baseDir : undefined);
238
+ // Convert to MCP prompts/list response format (include arguments if present)
239
+ const promptList = prompts.map(prompt => {
240
+ const item = {
241
+ name: prompt.name,
242
+ description: prompt.description,
243
+ };
244
+ if (prompt.arguments && prompt.arguments.length > 0) {
245
+ item.arguments = prompt.arguments;
246
+ }
247
+ return item;
248
+ });
130
249
  logger.info('Prompts list generated', {
131
250
  requestId,
132
251
  promptCount: promptList.length,
@@ -157,7 +276,7 @@ async function handlePromptsGetRequest(args, logger, requestId) {
157
276
  if (!args.name) {
158
277
  throw new Error('Missing required parameter: name');
159
278
  }
160
- const prompts = loadAllPrompts(logger, process.env.NODE_ENV === 'test' ? args?.baseDir : undefined);
279
+ const prompts = await loadAllPrompts(logger, process.env.NODE_ENV === 'test' ? args?.baseDir : undefined);
161
280
  const prompt = prompts.find(p => p.name === args.name);
162
281
  if (!prompt) {
163
282
  throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.MEDIUM, `Prompt not found: ${args.name}`, {
@@ -166,9 +285,30 @@ async function handlePromptsGetRequest(args, logger, requestId) {
166
285
  requestId,
167
286
  });
168
287
  }
288
+ // Validate required arguments if prompt has arguments defined
289
+ const providedArgs = args.arguments || {};
290
+ if (prompt.arguments && prompt.arguments.length > 0) {
291
+ const missingRequired = prompt.arguments
292
+ .filter(arg => arg.required && !providedArgs[arg.name])
293
+ .map(arg => arg.name);
294
+ if (missingRequired.length > 0) {
295
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.MEDIUM, `Missing required arguments: ${missingRequired.join(', ')}`, {
296
+ operation: 'prompts_get',
297
+ component: 'PromptsHandler',
298
+ requestId,
299
+ input: { promptName: prompt.name, missingArguments: missingRequired },
300
+ });
301
+ }
302
+ }
303
+ // Substitute {{argumentName}} placeholders in content
304
+ let processedContent = prompt.content;
305
+ for (const [argName, argValue] of Object.entries(providedArgs)) {
306
+ processedContent = processedContent.replaceAll(`{{${argName}}}`, String(argValue));
307
+ }
169
308
  logger.info('Prompt found and returned', {
170
309
  requestId,
171
310
  promptName: prompt.name,
311
+ argumentsProvided: Object.keys(providedArgs).length,
172
312
  });
173
313
  // Convert to MCP prompts/get response format
174
314
  return {
@@ -178,7 +318,7 @@ async function handlePromptsGetRequest(args, logger, requestId) {
178
318
  role: 'user',
179
319
  content: {
180
320
  type: 'text',
181
- text: prompt.content,
321
+ text: processedContent,
182
322
  },
183
323
  },
184
324
  ],
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Query Tool - Natural Language Cluster Intelligence
3
+ *
4
+ * Provides natural language query interface to discover and understand
5
+ * cluster capabilities and resources.
6
+ *
7
+ * PRD #291: Cluster Query Tool - Natural Language Cluster Intelligence
8
+ */
9
+ import { z } from 'zod';
10
+ export declare const QUERY_TOOL_NAME = "query";
11
+ export declare const QUERY_TOOL_DESCRIPTION = "Natural language query interface for Kubernetes cluster intelligence. Ask any questions about your cluster resources, capabilities, and status in plain English. Examples: \"What databases are running?\", \"Describe the nginx deployment\", \"Show me pods in the kube-system namespace\", \"What operators are installed?\", \"Is my-postgres healthy?\"";
12
+ export declare const QUERY_TOOL_INPUT_SCHEMA: {
13
+ intent: z.ZodString;
14
+ interaction_id: z.ZodOptional<z.ZodString>;
15
+ };
16
+ export interface QueryInput {
17
+ intent: string;
18
+ interaction_id?: string;
19
+ }
20
+ export interface QueryOutput {
21
+ success: boolean;
22
+ summary: string;
23
+ toolsUsed: string[];
24
+ iterations: number;
25
+ error?: {
26
+ code: string;
27
+ message: string;
28
+ };
29
+ }
30
+ /**
31
+ * Main query tool handler
32
+ */
33
+ export declare function handleQueryTool(args: any): Promise<any>;
34
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAkBxB,eAAO,MAAM,eAAe,UAAU,CAAC;AACvC,eAAO,MAAM,sBAAsB,iWAAuV,CAAC;AAG3X,eAAO,MAAM,uBAAuB;;;CAGnC,CAAC;AAGF,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAGD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAgED;;GAEG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAiH7D"}