@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
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ /**
3
+ * Query Tool - Natural Language Cluster Intelligence
4
+ *
5
+ * Provides natural language query interface to discover and understand
6
+ * cluster capabilities and resources.
7
+ *
8
+ * PRD #291: Cluster Query Tool - Natural Language Cluster Intelligence
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.QUERY_TOOL_INPUT_SCHEMA = exports.QUERY_TOOL_DESCRIPTION = exports.QUERY_TOOL_NAME = void 0;
45
+ exports.handleQueryTool = handleQueryTool;
46
+ const zod_1 = require("zod");
47
+ const error_handling_1 = require("../core/error-handling");
48
+ const ai_provider_factory_1 = require("../core/ai-provider-factory");
49
+ const capability_tools_1 = require("../core/capability-tools");
50
+ const resource_tools_1 = require("../core/resource-tools");
51
+ const kubectl_tools_1 = require("../core/kubectl-tools");
52
+ const fs = __importStar(require("fs"));
53
+ const path = __importStar(require("path"));
54
+ // Tool metadata for MCP registration
55
+ exports.QUERY_TOOL_NAME = 'query';
56
+ exports.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?"';
57
+ // Zod schema for MCP registration
58
+ exports.QUERY_TOOL_INPUT_SCHEMA = {
59
+ intent: zod_1.z.string().min(1).max(1000).describe('Natural language query about the cluster'),
60
+ interaction_id: zod_1.z.string().optional().describe('INTERNAL ONLY - Do not populate. Used for evaluation dataset generation.')
61
+ };
62
+ /**
63
+ * Parse the AI's final JSON response for summary only
64
+ */
65
+ function parseSummary(aiResponse) {
66
+ try {
67
+ // Find JSON in the response
68
+ const firstBraceIndex = aiResponse.indexOf('{');
69
+ if (firstBraceIndex === -1) {
70
+ // No JSON found, use the response as summary
71
+ return aiResponse.trim() || 'No summary provided';
72
+ }
73
+ // Track brace depth to find complete JSON object
74
+ let braceCount = 0;
75
+ let inString = false;
76
+ let escapeNext = false;
77
+ let jsonEndIndex = -1;
78
+ for (let i = firstBraceIndex; i < aiResponse.length; i++) {
79
+ const char = aiResponse[i];
80
+ if (escapeNext) {
81
+ escapeNext = false;
82
+ continue;
83
+ }
84
+ if (char === '\\') {
85
+ escapeNext = true;
86
+ continue;
87
+ }
88
+ if (char === '"') {
89
+ inString = !inString;
90
+ continue;
91
+ }
92
+ if (inString)
93
+ continue;
94
+ if (char === '{')
95
+ braceCount++;
96
+ if (char === '}') {
97
+ braceCount--;
98
+ if (braceCount === 0) {
99
+ jsonEndIndex = i + 1;
100
+ break;
101
+ }
102
+ }
103
+ }
104
+ if (jsonEndIndex === -1) {
105
+ return aiResponse.trim() || 'No summary provided';
106
+ }
107
+ const jsonString = aiResponse.substring(firstBraceIndex, jsonEndIndex);
108
+ const parsed = JSON.parse(jsonString);
109
+ return parsed.summary || 'No summary provided';
110
+ }
111
+ catch (error) {
112
+ // If parsing fails, use the raw response as summary
113
+ return aiResponse.trim() || 'No summary provided';
114
+ }
115
+ }
116
+ /**
117
+ * Main query tool handler
118
+ */
119
+ async function handleQueryTool(args) {
120
+ const requestId = `query_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
121
+ const logger = new error_handling_1.ConsoleLogger('QueryTool');
122
+ try {
123
+ // Validate input
124
+ const intent = args.intent;
125
+ if (!intent || typeof intent !== 'string') {
126
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.MEDIUM, 'Intent is required and must be a string', { operation: 'input_validation', component: 'QueryTool' });
127
+ }
128
+ logger.info('Processing query', { requestId, intent });
129
+ // Initialize AI provider
130
+ const aiProvider = (0, ai_provider_factory_1.createAIProvider)();
131
+ // Load system prompt
132
+ const promptPath = path.join(__dirname, '..', '..', 'prompts', 'query-system.md');
133
+ const systemPrompt = fs.readFileSync(promptPath, 'utf8');
134
+ // Combined tool executor for capability, resource, and kubectl tools
135
+ const executeQueryTools = async (toolName, input) => {
136
+ // Route to appropriate executor based on tool name
137
+ if (toolName.startsWith('search_capabilities') || toolName.startsWith('query_capabilities')) {
138
+ return (0, capability_tools_1.executeCapabilityTools)(toolName, input);
139
+ }
140
+ if (toolName.startsWith('search_resources') || toolName.startsWith('query_resources')) {
141
+ return (0, resource_tools_1.executeResourceTools)(toolName, input);
142
+ }
143
+ if (toolName.startsWith('kubectl_')) {
144
+ return (0, kubectl_tools_1.executeKubectlTools)(toolName, input);
145
+ }
146
+ return {
147
+ success: false,
148
+ error: `Unknown tool: ${toolName}`,
149
+ message: `Tool '${toolName}' is not implemented in query tool`
150
+ };
151
+ };
152
+ // Read-only kubectl tools for live cluster queries
153
+ const KUBECTL_READONLY_TOOLS = [
154
+ kubectl_tools_1.KUBECTL_API_RESOURCES_TOOL,
155
+ kubectl_tools_1.KUBECTL_GET_TOOL,
156
+ kubectl_tools_1.KUBECTL_DESCRIBE_TOOL,
157
+ kubectl_tools_1.KUBECTL_LOGS_TOOL,
158
+ kubectl_tools_1.KUBECTL_EVENTS_TOOL,
159
+ kubectl_tools_1.KUBECTL_GET_CRD_SCHEMA_TOOL
160
+ ];
161
+ // Execute tool loop with capability, resource, and kubectl tools
162
+ const result = await aiProvider.toolLoop({
163
+ systemPrompt,
164
+ userMessage: intent,
165
+ tools: [...capability_tools_1.CAPABILITY_TOOLS, ...resource_tools_1.RESOURCE_TOOLS, ...KUBECTL_READONLY_TOOLS],
166
+ toolExecutor: executeQueryTools,
167
+ maxIterations: 10,
168
+ operation: 'query',
169
+ evaluationContext: {
170
+ user_intent: intent
171
+ },
172
+ interaction_id: args.interaction_id
173
+ });
174
+ // Extract data from execution record (reliable, not AI self-reporting)
175
+ const toolsUsed = [...new Set(result.toolCallsExecuted.map(tc => tc.tool))];
176
+ const summary = parseSummary(result.finalMessage);
177
+ logger.info('Query completed', {
178
+ requestId,
179
+ iterations: result.iterations,
180
+ toolsUsed
181
+ });
182
+ const output = {
183
+ success: true,
184
+ summary,
185
+ toolsUsed,
186
+ iterations: result.iterations
187
+ };
188
+ return {
189
+ content: [
190
+ {
191
+ type: 'text',
192
+ text: JSON.stringify(output, null, 2)
193
+ }
194
+ ]
195
+ };
196
+ }
197
+ catch (error) {
198
+ logger.error('Query failed', error, { requestId });
199
+ if (error instanceof Error && 'category' in error) {
200
+ throw error;
201
+ }
202
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.UNKNOWN, error_handling_1.ErrorSeverity.HIGH, `Query tool failed: ${error instanceof Error ? error.message : 'Unknown error'}`, {
203
+ operation: 'query_tool_execution',
204
+ component: 'QueryTool',
205
+ requestId,
206
+ input: { intent: args.intent }
207
+ });
208
+ }
209
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vfarcic/dot-ai",
3
- "version": "0.173.0",
3
+ "version": "0.175.0",
4
4
  "description": "AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance",
5
5
  "mcpName": "io.github.vfarcic/dot-ai",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,15 @@
1
+ # Kubernetes Cluster Query Agent
2
+
3
+ You are a Kubernetes cluster analyst. Use the available tools to answer the user's query.
4
+
5
+ ## Output Format
6
+
7
+ When you have gathered sufficient information, respond with ONLY this JSON:
8
+
9
+ ```json
10
+ {
11
+ "summary": "Human-readable summary of what was found"
12
+ }
13
+ ```
14
+
15
+ No text before or after the JSON.
@@ -38,15 +38,13 @@ def --env "main apply crossplane" [
38
38
  setup aws
39
39
  } else if $provider == "azure" {
40
40
  setup azure --skip-login $skip_login
41
- } else if $provider == "upcloud" {
42
- setup upcloud
43
41
  }
44
42
 
45
43
  if $app_config {
46
44
 
47
45
  print $"\n(ansi green_bold)Applying `dot-application` Configuration...(ansi reset)\n"
48
46
 
49
- let version = "v3.0.31"
47
+ let version = "v3.0.46"
50
48
  {
51
49
  apiVersion: "pkg.crossplane.io/v1"
52
50
  kind: "Configuration"
@@ -99,7 +97,7 @@ def --env "main apply crossplane" [
99
97
  if ($db_config or $db_provider) and $provider == "google" {
100
98
 
101
99
  start $"https://console.cloud.google.com/marketplace/product/google/sqladmin.googleapis.com?project=($provider_data.project_id)"
102
-
100
+
103
101
  print $"\n(ansi yellow_bold)ENABLE(ansi reset) the API.\nPress the (ansi yellow_bold)enter key(ansi reset) to continue.\n"
104
102
  input
105
103
 
@@ -109,7 +107,7 @@ def --env "main apply crossplane" [
109
107
 
110
108
  print $"\n(ansi green_bold)Applying `dot-sql` Configuration...(ansi reset)\n"
111
109
 
112
- let version = "v2.1.83"
110
+ let version = "v2.2.11"
113
111
  {
114
112
  apiVersion: "pkg.crossplane.io/v1"
115
113
  kind: "Configuration"
@@ -120,7 +118,7 @@ def --env "main apply crossplane" [
120
118
  } else if $db_provider {
121
119
 
122
120
  apply db-provider $provider
123
-
121
+
124
122
  }
125
123
 
126
124
  if $github_config {
@@ -155,7 +153,7 @@ def --env "main apply crossplane" [
155
153
  verbs: ["*"]
156
154
  }]
157
155
  } | to yaml | kubectl apply --filename -
158
-
156
+
159
157
 
160
158
  {
161
159
  apiVersion: "v1"
@@ -325,12 +323,12 @@ def "main delete crossplane" [
325
323
  --namespace: string
326
324
  ] {
327
325
 
328
- if ($kind | is-not-empty) and ($name | is-not-empty) and ($namespace | is-not-empty) {
326
+ if ($kind | is-not-empty) and ($name | is-not-empty) and ($namespace | is-not-empty) {
329
327
  kubectl --namespace $namespace delete $kind $name
330
328
  }
331
329
 
332
330
  print $"\nWaiting for (ansi green_bold)Crossplane managed resources(ansi reset) to be deleted...\n"
333
-
331
+
334
332
  mut command = { kubectl get managed --output name }
335
333
  if ($name | is-not-empty) {
336
334
  $command = {
@@ -435,7 +433,7 @@ def "apply providerconfig" [
435
433
  }
436
434
  }
437
435
  } | to yaml | kubectl apply --filename -
438
-
436
+
439
437
  } else if $provider == "azure" {
440
438
 
441
439
  {
@@ -454,24 +452,6 @@ def "apply providerconfig" [
454
452
  }
455
453
  } | to yaml | kubectl apply --filename -
456
454
 
457
- } else if $provider == "upcloud" {
458
-
459
- {
460
- apiVersion: "provider.upcloud.com/v1beta1"
461
- kind: "ProviderConfig"
462
- metadata: { name: default }
463
- spec: {
464
- credentials: {
465
- source: "Secret"
466
- secretRef: {
467
- namespace: "crossplane-system"
468
- name: "upcloud-creds"
469
- key: "creds"
470
- }
471
- }
472
- }
473
- } | to yaml | kubectl apply --filename -
474
-
475
455
  }
476
456
 
477
457
  }
@@ -658,33 +638,3 @@ def "setup azure" [
658
638
  )
659
639
 
660
640
  }
661
-
662
- def "setup upcloud" [] {
663
-
664
- print $"\nInstalling (ansi green_bold)Crossplane UpCloud Provider(ansi reset)...\n"
665
-
666
- if UPCLOUD_USERNAME not-in $env {
667
- $env.UPCLOUD_USERNAME = input $"(ansi yellow_bold)UpCloud Username: (ansi reset)"
668
- }
669
- $"export UPCLOUD_USERNAME=($env.UPCLOUD_USERNAME)\n"
670
- | save --append .env
671
-
672
- if UPCLOUD_PASSWORD not-in $env {
673
- $env.UPCLOUD_PASSWORD = input $"(ansi yellow_bold)UpCloud Password: (ansi reset)"
674
- }
675
- $"export UPCLOUD_PASSWORD=($env.UPCLOUD_PASSWORD)\n"
676
- | save --append .env
677
-
678
- {
679
- apiVersion: "v1"
680
- kind: "Secret"
681
- metadata: {
682
- name: "upcloud-creds"
683
- }
684
- type: "Opaque"
685
- stringData: {
686
- creds: $"{\"username\": \"($env.UPCLOUD_USERNAME)\", \"password\": \"($env.UPCLOUD_PASSWORD)\"}"
687
- }
688
- } | to yaml | kubectl --namespace crossplane-system apply --filename -
689
-
690
- }
package/scripts/dot-ai.nu CHANGED
@@ -1,5 +1,25 @@
1
1
  #!/usr/bin/env nu
2
2
 
3
+ # Installs DevOps AI Controller
4
+ #
5
+ # Examples:
6
+ # > main apply dot-ai-controller
7
+ # > main apply dot-ai-controller --controller-version 0.17.0
8
+ def "main apply dot-ai-controller" [
9
+ --controller-version = "0.37.0"
10
+ ] {
11
+
12
+ (
13
+ helm upgrade --install dot-ai-controller
14
+ $"oci://ghcr.io/vfarcic/dot-ai-controller/charts/dot-ai-controller:($controller_version)"
15
+ --namespace dot-ai --create-namespace
16
+ --wait
17
+ )
18
+
19
+ print $"DevOps AI Controller (ansi yellow_bold)($controller_version)(ansi reset) installed in (ansi yellow_bold)dot-ai(ansi reset) namespace"
20
+
21
+ }
22
+
3
23
  # Installs DevOps AI Toolkit with MCP server support and controller
4
24
  #
5
25
  # Examples:
@@ -14,8 +34,8 @@ def "main apply dot-ai" [
14
34
  --ingress-enabled = true,
15
35
  --ingress-class = "nginx",
16
36
  --host = "dot-ai.127.0.0.1.nip.io",
17
- --version = "0.140.0",
18
- --controller-version = "0.16.0",
37
+ --version = "0.171.0",
38
+ --controller-version = "0.37.0",
19
39
  --enable-tracing = false
20
40
  ] {
21
41
 
@@ -44,12 +64,7 @@ def "main apply dot-ai" [
44
64
  []
45
65
  }
46
66
 
47
- (
48
- helm upgrade --install dot-ai-controller
49
- $"oci://ghcr.io/vfarcic/dot-ai-controller/charts/dot-ai-controller:($controller_version)"
50
- --namespace dot-ai --create-namespace
51
- --wait
52
- )
67
+ main apply dot-ai-controller --controller-version $controller_version
53
68
 
54
69
  (
55
70
  helm upgrade --install dot-ai-mcp
@@ -67,7 +82,6 @@ def "main apply dot-ai" [
67
82
  --wait
68
83
  )
69
84
 
70
- print $"DevOps AI Controller (ansi yellow_bold)($controller_version)(ansi reset) installed in (ansi yellow_bold)dot-ai(ansi reset) namespace"
71
85
  print $"DevOps AI Toolkit is available at (ansi yellow_bold)http://($host)(ansi reset)"
72
86
 
73
87
  if $enable_tracing {
@@ -34,12 +34,16 @@ Work through the PRD template focusing on project management, milestone tracking
34
34
 
35
35
  **Key Principle**: Focus on 5-10 major milestones rather than exhaustive task lists. Each milestone should represent meaningful progress that can be clearly validated.
36
36
 
37
+ **Consider Including** (when applicable to the project/feature):
38
+ - **Tests** - If the project has tests, include a milestone for test coverage of new functionality
39
+ - **Documentation** - If the feature is user-facing, include a milestone for docs following existing project patterns
40
+
37
41
  **Good Milestones Examples:**
38
42
  - [ ] Core functionality implemented and working
39
- - [ ] Documentation complete and tested
43
+ - [ ] Tests passing for new functionality (if project has test suite)
44
+ - [ ] Documentation complete following existing patterns (if user-facing feature)
40
45
  - [ ] Integration with existing systems working
41
46
  - [ ] Feature ready for user testing
42
- - [ ] Feature launched and available
43
47
 
44
48
  **Avoid Micro-Tasks:**
45
49
  - ❌ Update README.md file
@@ -2,6 +2,10 @@
2
2
  name: prd-start
3
3
  description: Start working on a PRD implementation
4
4
  category: project-management
5
+ arguments:
6
+ - name: prdNumber
7
+ description: PRD number to start working on (e.g., 306)
8
+ required: false
5
9
  ---
6
10
 
7
11
  # PRD Start - Begin Implementation Work
@@ -20,9 +24,19 @@ You are helping initiate active implementation work on a specific Product Requir
20
24
  4. **Identify Starting Point** - Determine the best first implementation task
21
25
  5. **Begin Implementation** - Launch into actual development work
22
26
 
23
- ## Step 0: Context Awareness Check
27
+ ## Step 0: Check for PRD Argument
24
28
 
25
- **FIRST: Check if PRD context is already clear from recent conversation:**
29
+ **If `prdNumber` argument is provided ({{prdNumber}}):**
30
+ - Skip Step 0 context check and Step 1 auto-detection
31
+ - Use PRD #{{prdNumber}} directly
32
+ - Proceed to Step 2 (PRD Readiness Validation)
33
+
34
+ **If `prdNumber` argument is NOT provided:**
35
+ - Continue to context awareness check below
36
+
37
+ ## Step 0b: Context Awareness Check
38
+
39
+ **Check if PRD context is already clear from recent conversation:**
26
40
 
27
41
  **Skip detection/analysis if recent conversation shows:**
28
42
  - **Recent PRD work discussed** - "We just worked on PRD 29", "Just completed PRD update", etc.
@@ -31,7 +45,7 @@ You are helping initiate active implementation work on a specific Product Requir
31
45
  - **Clear work context** - Discussion of specific features, tasks, or requirements for a known PRD
32
46
 
33
47
  **If context is clear:**
34
- - Skip to Step 2 (PRD Readiness Validation) using the known PRD
48
+ - Skip to Step 2 (PRD Readiness Validation) using the known PRD
35
49
  - Use conversation history to understand current state and recent progress
36
50
  - Proceed directly with readiness validation based on known PRD status
37
51