@vfarcic/dot-ai 1.9.1 → 1.10.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.
@@ -1 +1 @@
1
- {"version":3,"file":"generate-manifests.d.ts","sourceRoot":"","sources":["../../src/tools/generate-manifests.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,OAAO,EAAE,KAAK,EAA0B,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAgBhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AA8E5D,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAC/D,eAAO,MAAM,kCAAkC,+IAC+F,CAAC;AAG/I,eAAO,MAAM,mCAAmC;;;CAa/C,CAAC;AAq8BF;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,EACrD,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CA0WxD"}
1
+ {"version":3,"file":"generate-manifests.d.ts","sourceRoot":"","sources":["../../src/tools/generate-manifests.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,OAAO,EAAE,KAAK,EAA0B,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAgBhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAuH5D,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAC/D,eAAO,MAAM,kCAAkC,+IAC+F,CAAC;AAG/I,eAAO,MAAM,mCAAmC;;;CAa/C,CAAC;AAs8BF;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,EACrD,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAkXxD"}
@@ -61,22 +61,33 @@ const request_context_1 = require("../interfaces/request-context");
61
61
  const rbac_1 = require("../core/rbac");
62
62
  // PRD #359: All helm operations via unified plugin registry
63
63
  /**
64
- * PRD #392 Milestone 2: Build agent instructions based on deploy permission.
65
- * When the user has 'apply' permission, includes the deploy option.
66
- * When they don't, explains that deploying requires 'apply' permission.
64
+ * PRD #392 Milestone 2 + PRD #395: Build unified agent instructions.
65
+ * Presents save locally, deploy to cluster, and push to Git as equal options.
66
+ * RBAC determines whether deploy is available.
67
67
  */
68
- async function buildDeployInstructions(outputPath, outputFormat) {
69
- const writeInstr = `Write the files to "${outputPath}".`;
70
- const formatInstr = outputFormat === 'helm' ? ' The output is a Helm chart.' : outputFormat === 'raw' ? '' : ' The output is a Kustomize overlay.';
68
+ async function buildAgentInstructions(outputPath, outputFormat) {
69
+ const formatNote = outputFormat === 'helm'
70
+ ? ' (Helm chart)'
71
+ : outputFormat === 'kustomize'
72
+ ? ' (Kustomize overlay)'
73
+ : '';
74
+ const parts = [
75
+ `Manifests generated${formatNote}. Present the user with these options:`,
76
+ `1. **Save locally**: Write the files to "${outputPath}" — no further server call needed, you already have the file contents.`,
77
+ ];
71
78
  const identity = (0, request_context_1.getCurrentIdentity)();
72
79
  const rbacResult = await (0, rbac_1.checkToolAccess)(identity, {
73
80
  toolName: 'recommend',
74
81
  verb: 'apply',
75
82
  });
76
83
  if (rbacResult.allowed) {
77
- return `${writeInstr}${formatInstr} If immediate deployment is desired, call the recommend tool with stage: "deployManifests".`;
84
+ parts.push('2. **Deploy to cluster**: Call the recommend tool with stage: "deployManifests" to apply directly.');
85
+ }
86
+ else {
87
+ parts.push("2. **Deploy to cluster**: Not available — requires 'apply' permission on 'recommend'.");
78
88
  }
79
- return `${writeInstr}${formatInstr} Deploying manifests requires 'apply' permission on 'recommend', which is not granted for the current user. Save the files locally or push to Git to apply them through your own workflow.`;
89
+ parts.push('3. **Push to Git** (GitOps): Call the recommend tool with stage: "pushToGit", providing repoUrl and targetPath. Recommended for Argo CD/Flux workflows.');
90
+ return parts.join('\n');
80
91
  }
81
92
  /**
82
93
  * Ensure tmp directory exists
@@ -115,6 +126,24 @@ function buildHelmCommandForDisplay(chart, releaseName, namespace, valuesPath) {
115
126
  return parts.join(' ');
116
127
  }
117
128
  const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
129
+ // PRD #395: Unified nextActions — save locally, deploy, or push to Git as equal options
130
+ const NEXT_ACTIONS = [
131
+ {
132
+ action: 'saveLocally',
133
+ description: 'Save files locally (no server call needed — files are in the response)',
134
+ },
135
+ {
136
+ action: 'deployManifests',
137
+ description: 'Apply directly to cluster',
138
+ stage: 'deployManifests',
139
+ },
140
+ {
141
+ action: 'pushToGit',
142
+ description: 'Push to Git repository for GitOps (Argo CD, Flux)',
143
+ stage: 'pushToGit',
144
+ requiredParams: ['repoUrl', 'targetPath'],
145
+ },
146
+ ];
118
147
  // Tool metadata for direct MCP registration
119
148
  exports.GENERATEMANIFESTS_TOOL_NAME = 'generateManifests';
120
149
  exports.GENERATEMANIFESTS_TOOL_DESCRIPTION = 'Generate final Kubernetes manifests from fully configured solution (ONLY after completing ALL stages: required, basic, advanced, and open)';
@@ -544,6 +573,7 @@ async function handleHelmGeneration(solution, solutionId, dotAI, logger, request
544
573
  namespace: namespace,
545
574
  validationAttempts: attempt,
546
575
  timestamp: new Date().toISOString(),
576
+ nextActions: [NEXT_ACTIONS[0], NEXT_ACTIONS[1]], // saveLocally + deployManifests for Helm (pushToGit not yet supported)
547
577
  ...(visualizationUrl ? { visualizationUrl } : {}),
548
578
  };
549
579
  // Build content blocks - JSON for REST API, agent instruction for MCP agents
@@ -935,7 +965,8 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
935
965
  validationAttempts: attempt,
936
966
  packagingAttempts: packagingResult.attempts,
937
967
  timestamp: new Date().toISOString(),
938
- agentInstructions: await buildDeployInstructions(outputPath, outputFormat),
968
+ nextActions: NEXT_ACTIONS,
969
+ agentInstructions: await buildAgentInstructions(outputPath, outputFormat),
939
970
  ...(visualizationUrl ? { visualizationUrl } : {}),
940
971
  };
941
972
  // Build content blocks - JSON for REST API, agent instruction for MCP agents
@@ -977,7 +1008,8 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
977
1008
  files: [{ relativePath: 'manifests.yaml', content: manifests }],
978
1009
  validationAttempts: attempt,
979
1010
  timestamp: new Date().toISOString(),
980
- agentInstructions: await buildDeployInstructions(outputPath, outputFormat),
1011
+ nextActions: NEXT_ACTIONS,
1012
+ agentInstructions: await buildAgentInstructions(outputPath, outputFormat),
981
1013
  ...(visualizationUrl ? { visualizationUrl } : {}),
982
1014
  };
983
1015
  // Build content blocks - JSON for REST API, agent instruction for MCP agents
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Push to Git Tool - Push generated manifests to a Git repository
3
+ *
4
+ * PRD #395: Git Push Recommend Integration
5
+ *
6
+ * This stage allows users to push generated manifests directly to a Git
7
+ * repository, enabling GitOps workflows with Argo CD, Flux, etc.
8
+ */
9
+ import { z } from 'zod';
10
+ import { DotAI } from '../core/index';
11
+ import { Logger } from '../core/error-handling';
12
+ import { GenericSessionManager } from '../core/generic-session-manager';
13
+ import type { SolutionData } from './recommend';
14
+ export declare const PUSHTOGIT_TOOL_NAME = "pushToGit";
15
+ export declare const PUSHTOGIT_TOOL_DESCRIPTION = "Push generated manifests to a Git repository for GitOps workflows (Argo CD, Flux). Use after generateManifests stage.";
16
+ export declare const PUSHTOGIT_TOOL_INPUT_SCHEMA: {
17
+ solutionId: z.ZodString;
18
+ repoUrl: z.ZodString;
19
+ targetPath: z.ZodString;
20
+ branch: z.ZodOptional<z.ZodString>;
21
+ commitMessage: z.ZodOptional<z.ZodString>;
22
+ authorName: z.ZodOptional<z.ZodString>;
23
+ authorEmail: z.ZodOptional<z.ZodString>;
24
+ interaction_id: z.ZodOptional<z.ZodString>;
25
+ };
26
+ interface PushToGitArgs {
27
+ solutionId: string;
28
+ repoUrl: string;
29
+ targetPath: string;
30
+ branch?: string;
31
+ commitMessage?: string;
32
+ authorName?: string;
33
+ authorEmail?: string;
34
+ interaction_id?: string;
35
+ }
36
+ export declare function handlePushToGitTool(args: PushToGitArgs, dotAI: DotAI, logger: Logger, requestId: string, sessionManager?: GenericSessionManager<SolutionData>): Promise<{
37
+ content: {
38
+ type: 'text';
39
+ text: string;
40
+ }[];
41
+ }>;
42
+ export {};
43
+ //# sourceMappingURL=push-to-git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-to-git.d.ts","sourceRoot":"","sources":["../../src/tools/push-to-git.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,OAAO,EAAE,KAAK,EAA0B,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAShD,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAC/C,eAAO,MAAM,0BAA0B,0HACkF,CAAC;AAE1H,eAAO,MAAM,2BAA2B;;;;;;;;;CAwBvC,CAAC;AAEF,UAAU,aAAa;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAaD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,qBAAqB,CAAC,YAAY,CAAC,GACnD,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAiUxD"}
@@ -0,0 +1,335 @@
1
+ "use strict";
2
+ /**
3
+ * Push to Git Tool - Push generated manifests to a Git repository
4
+ *
5
+ * PRD #395: Git Push Recommend Integration
6
+ *
7
+ * This stage allows users to push generated manifests directly to a Git
8
+ * repository, enabling GitOps workflows with Argo CD, Flux, etc.
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.PUSHTOGIT_TOOL_INPUT_SCHEMA = exports.PUSHTOGIT_TOOL_DESCRIPTION = exports.PUSHTOGIT_TOOL_NAME = void 0;
45
+ exports.handlePushToGitTool = handlePushToGitTool;
46
+ const zod_1 = require("zod");
47
+ const fs = __importStar(require("fs"));
48
+ const os = __importStar(require("os"));
49
+ const path = __importStar(require("path"));
50
+ const crypto_1 = require("crypto");
51
+ const error_handling_1 = require("../core/error-handling");
52
+ const index_1 = require("../core/index");
53
+ const generic_session_manager_1 = require("../core/generic-session-manager");
54
+ const git_utils_1 = require("../core/git-utils");
55
+ const visualization_1 = require("../core/visualization");
56
+ exports.PUSHTOGIT_TOOL_NAME = 'pushToGit';
57
+ exports.PUSHTOGIT_TOOL_DESCRIPTION = 'Push generated manifests to a Git repository for GitOps workflows (Argo CD, Flux). Use after generateManifests stage.';
58
+ exports.PUSHTOGIT_TOOL_INPUT_SCHEMA = {
59
+ solutionId: zod_1.z
60
+ .string()
61
+ .regex(/^sol-\d+-[a-f0-9]{8}$/)
62
+ .describe('The solution ID to push manifests for'),
63
+ repoUrl: zod_1.z.string().url().describe('Git repository URL (HTTPS)'),
64
+ targetPath: zod_1.z
65
+ .string()
66
+ .describe('Path within repository where manifests will be stored (e.g., "apps/postgresql/")'),
67
+ branch: zod_1.z.string().optional().describe('Git branch (default: main)'),
68
+ commitMessage: zod_1.z
69
+ .string()
70
+ .optional()
71
+ .describe('Commit message (default: "Add {resource} deployment")'),
72
+ authorName: zod_1.z.string().optional().describe('Git author name'),
73
+ authorEmail: zod_1.z.string().optional().describe('Git author email'),
74
+ interaction_id: zod_1.z
75
+ .string()
76
+ .optional()
77
+ .describe('INTERNAL ONLY - Do not populate. Used for evaluation dataset generation.'),
78
+ };
79
+ function sanitizeRelativePath(relativePath) {
80
+ if (relativePath.startsWith('/')) {
81
+ throw new Error('Relative path cannot be absolute');
82
+ }
83
+ const normalized = path.posix.normalize(relativePath);
84
+ if (normalized.startsWith('..') || path.posix.isAbsolute(normalized)) {
85
+ throw new Error('Relative path cannot escape target directory');
86
+ }
87
+ return normalized;
88
+ }
89
+ async function handlePushToGitTool(args, dotAI, logger, requestId, sessionManager) {
90
+ return await error_handling_1.ErrorHandler.withErrorHandling(async () => {
91
+ logger.info('Handling pushToGit request', {
92
+ requestId,
93
+ solutionId: args.solutionId,
94
+ repoUrl: (0, git_utils_1.scrubCredentials)(args.repoUrl),
95
+ targetPath: args.targetPath,
96
+ branch: args.branch,
97
+ });
98
+ const sm = sessionManager || new generic_session_manager_1.GenericSessionManager('sol');
99
+ const session = sm.getSession(args.solutionId);
100
+ if (!session) {
101
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.HIGH, `Solution not found: ${args.solutionId}`, {
102
+ operation: 'push_to_git',
103
+ component: 'PushToGitTool',
104
+ requestId,
105
+ input: { solutionId: args.solutionId },
106
+ suggestedActions: [
107
+ 'Verify the solution ID is correct',
108
+ 'Ensure generateManifests stage was completed first',
109
+ 'Check that the session has not expired',
110
+ ],
111
+ });
112
+ }
113
+ const solution = session.data;
114
+ if (!solution.generatedManifests) {
115
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.HIGH, 'No manifests found. Run generateManifests stage first.', {
116
+ operation: 'push_to_git',
117
+ component: 'PushToGitTool',
118
+ requestId,
119
+ input: { solutionId: args.solutionId },
120
+ suggestedActions: [
121
+ 'Call recommend tool with stage: generateManifests first',
122
+ 'Ensure the solution was fully configured',
123
+ ],
124
+ });
125
+ }
126
+ if (solution.generatedManifests.type === 'helm') {
127
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.HIGH, 'GitOps push for Helm charts is not yet supported. Use the deployManifests stage to install directly, or wait for a future release with Argo CD Application / Flux HelmRelease support.', {
128
+ operation: 'push_to_git',
129
+ component: 'PushToGitTool',
130
+ requestId,
131
+ input: { solutionId: args.solutionId },
132
+ suggestedActions: [
133
+ 'Use deployManifests stage to install Helm chart directly',
134
+ 'Wait for future release with GitOps Helm support (Argo CD Application / Flux HelmRelease)',
135
+ ],
136
+ });
137
+ }
138
+ const authConfig = (0, git_utils_1.getGitAuthConfigFromEnv)();
139
+ if (!authConfig.pat && !authConfig.githubApp) {
140
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.CONFIGURATION, error_handling_1.ErrorSeverity.HIGH, 'No Git authentication configured. Set DOT_AI_GIT_TOKEN or configure GitHub App.', {
141
+ operation: 'push_to_git',
142
+ component: 'PushToGitTool',
143
+ requestId,
144
+ input: { repoUrl: (0, git_utils_1.scrubCredentials)(args.repoUrl) },
145
+ suggestedActions: [
146
+ 'Set DOT_AI_GIT_TOKEN environment variable with a valid PAT',
147
+ 'Or configure GitHub App authentication (GITHUB_APP_ENABLED, GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY)',
148
+ ],
149
+ });
150
+ }
151
+ const branch = args.branch || 'main';
152
+ const defaultCommitMessage = `Add ${solution.intent || 'deployment'} manifests`;
153
+ const commitMessage = args.commitMessage || defaultCommitMessage;
154
+ const rawTargetPath = args.targetPath.trim();
155
+ if (rawTargetPath === '' ||
156
+ rawTargetPath.startsWith('/') ||
157
+ rawTargetPath.startsWith('~') ||
158
+ rawTargetPath.includes('\\') ||
159
+ rawTargetPath.includes('..')) {
160
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.HIGH, 'Invalid target path: use a relative repository path without "/", "~", "\\", or ".."', {
161
+ operation: 'push_to_git',
162
+ component: 'PushToGitTool',
163
+ requestId,
164
+ input: { targetPath: args.targetPath },
165
+ suggestedActions: [
166
+ 'Use a relative repository path such as "apps/postgresql"',
167
+ ],
168
+ });
169
+ }
170
+ const targetPath = rawTargetPath.replace(/\/+$/, '');
171
+ const tmpDir = path.join(os.tmpdir(), `dot-ai-git-${args.solutionId}-${(0, crypto_1.randomUUID)()}`);
172
+ logger.info('Cloning repository', {
173
+ repoUrl: (0, git_utils_1.scrubCredentials)(args.repoUrl),
174
+ branch,
175
+ tmpDir,
176
+ });
177
+ try {
178
+ fs.rmSync(tmpDir, { recursive: true, force: true });
179
+ try {
180
+ await (0, git_utils_1.cloneRepo)(args.repoUrl, tmpDir, { branch, depth: 1 });
181
+ }
182
+ catch (cloneError) {
183
+ const errorMessage = cloneError instanceof Error
184
+ ? cloneError.message
185
+ : String(cloneError);
186
+ logger.error('Failed to clone repository', cloneError, {
187
+ repoUrl: (0, git_utils_1.scrubCredentials)(args.repoUrl),
188
+ branch,
189
+ });
190
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.NETWORK, error_handling_1.ErrorSeverity.HIGH, `Failed to clone repository: ${errorMessage}`, {
191
+ operation: 'push_to_git',
192
+ component: 'PushToGitTool',
193
+ requestId,
194
+ input: { repoUrl: (0, git_utils_1.scrubCredentials)(args.repoUrl), branch },
195
+ suggestedActions: [
196
+ 'Verify the repository URL is correct',
197
+ 'Check that the branch exists',
198
+ 'Ensure your token has read access to the repository',
199
+ ],
200
+ });
201
+ }
202
+ const files = [];
203
+ // Handle raw/kustomize manifests (Helm is rejected earlier in validation)
204
+ const manifestFiles = solution.generatedManifests.files;
205
+ if (manifestFiles && manifestFiles.length > 0) {
206
+ for (const file of manifestFiles) {
207
+ const sanitizedPath = sanitizeRelativePath(file.relativePath);
208
+ files.push({
209
+ path: path.posix.join(targetPath, sanitizedPath),
210
+ content: file.content,
211
+ });
212
+ }
213
+ }
214
+ if (files.length === 0) {
215
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.HIGH, 'No files to push. Manifests may be empty or missing content.', {
216
+ operation: 'push_to_git',
217
+ component: 'PushToGitTool',
218
+ requestId,
219
+ input: { solutionId: args.solutionId },
220
+ suggestedActions: [
221
+ 'Verify generateManifests completed successfully',
222
+ 'Check that manifests contain content',
223
+ ],
224
+ });
225
+ }
226
+ logger.info('Pushing files to repository', {
227
+ fileCount: files.length,
228
+ targetPath,
229
+ branch,
230
+ });
231
+ const filesPreview = files.map(f => ({
232
+ path: f.path,
233
+ size: f.content.length,
234
+ lines: f.content.split('\n').length,
235
+ }));
236
+ let pushResult;
237
+ try {
238
+ pushResult = await (0, git_utils_1.pushRepo)(tmpDir, files, commitMessage, {
239
+ branch,
240
+ author: args.authorName
241
+ ? {
242
+ name: args.authorName,
243
+ email: args.authorEmail || 'dot-ai@users.noreply.github.com',
244
+ }
245
+ : undefined,
246
+ });
247
+ }
248
+ catch (pushError) {
249
+ const errorMessage = pushError instanceof Error ? pushError.message : String(pushError);
250
+ logger.error('Failed to push to repository', pushError, {
251
+ repoUrl: (0, git_utils_1.scrubCredentials)(args.repoUrl),
252
+ branch,
253
+ targetPath,
254
+ });
255
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.NETWORK, error_handling_1.ErrorSeverity.HIGH, `Failed to push to repository: ${errorMessage}`, {
256
+ operation: 'push_to_git',
257
+ component: 'PushToGitTool',
258
+ requestId,
259
+ input: {
260
+ repoUrl: (0, git_utils_1.scrubCredentials)(args.repoUrl),
261
+ branch,
262
+ targetPath,
263
+ },
264
+ suggestedActions: [
265
+ 'Ensure your token has write access to the repository',
266
+ 'Check for merge conflicts (pull latest changes first)',
267
+ 'Verify the branch exists or can be created',
268
+ ],
269
+ });
270
+ }
271
+ sm.updateSession(args.solutionId, {
272
+ stage: 'pushed',
273
+ gitPush: {
274
+ repoUrl: (0, git_utils_1.scrubCredentials)(args.repoUrl),
275
+ path: targetPath,
276
+ branch: pushResult.branch,
277
+ commitSha: pushResult.commitSha,
278
+ pushedAt: new Date().toISOString(),
279
+ },
280
+ });
281
+ const visualizationUrl = (0, visualization_1.getVisualizationUrl)(args.solutionId);
282
+ const response = {
283
+ success: true,
284
+ status: 'manifests_pushed',
285
+ solutionId: args.solutionId,
286
+ gitPush: {
287
+ repoUrl: (0, git_utils_1.scrubCredentials)(args.repoUrl),
288
+ path: targetPath,
289
+ branch: pushResult.branch,
290
+ commitSha: pushResult.commitSha,
291
+ filesPushed: pushResult.filesAdded,
292
+ pushedAt: new Date().toISOString(),
293
+ },
294
+ filesPreview,
295
+ gitopsMessage: `Manifests pushed successfully. Your GitOps controller (Argo CD/Flux) will sync these changes automatically.`,
296
+ timestamp: new Date().toISOString(),
297
+ ...(visualizationUrl ? { visualizationUrl } : {}),
298
+ };
299
+ logger.info('Push to Git completed successfully', {
300
+ solutionId: args.solutionId,
301
+ commitSha: pushResult.commitSha,
302
+ branch: pushResult.branch,
303
+ });
304
+ const content = [
305
+ {
306
+ type: 'text',
307
+ text: JSON.stringify(response, null, 2),
308
+ },
309
+ ];
310
+ const agentDisplayBlock = (0, index_1.buildAgentDisplayBlock)({ visualizationUrl });
311
+ if (agentDisplayBlock) {
312
+ content.push(agentDisplayBlock);
313
+ }
314
+ return { content };
315
+ }
316
+ finally {
317
+ try {
318
+ fs.rmSync(tmpDir, { recursive: true, force: true });
319
+ }
320
+ catch (cleanupError) {
321
+ logger.warn('Failed to cleanup temporary git directory', {
322
+ tmpDir,
323
+ error: cleanupError instanceof Error
324
+ ? cleanupError.message
325
+ : String(cleanupError),
326
+ });
327
+ }
328
+ }
329
+ }, {
330
+ operation: 'push_to_git',
331
+ component: 'PushToGitTool',
332
+ requestId,
333
+ input: { ...args, repoUrl: (0, git_utils_1.scrubCredentials)(args.repoUrl) },
334
+ });
335
+ }
@@ -16,11 +16,17 @@ export declare const RECOMMEND_TOOL_INPUT_SCHEMA: {
16
16
  solutionId: z.ZodOptional<z.ZodString>;
17
17
  answers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
18
18
  timeout: z.ZodOptional<z.ZodNumber>;
19
+ repoUrl: z.ZodOptional<z.ZodString>;
20
+ targetPath: z.ZodOptional<z.ZodString>;
21
+ branch: z.ZodOptional<z.ZodString>;
22
+ commitMessage: z.ZodOptional<z.ZodString>;
23
+ authorName: z.ZodOptional<z.ZodString>;
24
+ authorEmail: z.ZodOptional<z.ZodString>;
19
25
  interaction_id: z.ZodOptional<z.ZodString>;
20
26
  };
21
27
  export interface SolutionData {
22
28
  toolName: 'recommend';
23
- stage?: 'solutions' | 'questions' | 'manifests' | 'deployed';
29
+ stage?: 'solutions' | 'questions' | 'manifests' | 'pushed' | 'deployed';
24
30
  intent: string;
25
31
  type: string;
26
32
  score: number;
@@ -67,6 +73,13 @@ export interface SolutionData {
67
73
  validationAttempts?: number;
68
74
  packagingAttempts?: number;
69
75
  };
76
+ gitPush?: {
77
+ repoUrl: string;
78
+ path: string;
79
+ branch: string;
80
+ commitSha?: string;
81
+ pushedAt?: string;
82
+ };
70
83
  currentQuestionStage?: 'required' | 'basic' | 'advanced' | 'open';
71
84
  nextQuestionStage?: string | null;
72
85
  allSolutions?: Array<{
@@ -95,6 +108,12 @@ interface RecommendToolArgs {
95
108
  solutionId?: string;
96
109
  answers?: Record<string, unknown>;
97
110
  timeout?: number;
111
+ repoUrl?: string;
112
+ targetPath?: string;
113
+ branch?: string;
114
+ commitMessage?: string;
115
+ authorName?: string;
116
+ authorEmail?: string;
98
117
  interaction_id?: string;
99
118
  }
100
119
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"recommend.d.ts","sourceRoot":"","sources":["../../src/tools/recommend.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recommend.d.ts","sourceRoot":"","sources":["../../src/tools/recommend.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,7 @@ const choose_solution_1 = require("./choose-solution");
14
14
  const answer_question_1 = require("./answer-question");
15
15
  const generate_manifests_1 = require("./generate-manifests");
16
16
  const deploy_manifests_1 = require("./deploy-manifests");
17
+ const push_to_git_1 = require("./push-to-git");
17
18
  const shared_prompt_loader_1 = require("../core/shared-prompt-loader");
18
19
  const request_context_1 = require("../interfaces/request-context");
19
20
  const rbac_1 = require("../core/rbac");
@@ -27,15 +28,22 @@ exports.RECOMMEND_TOOL_NAME = 'recommend';
27
28
  exports.RECOMMEND_TOOL_DESCRIPTION = 'Deploy applications, infrastructure, and services using Kubernetes resources with AI recommendations. Supports cloud resources via operators like Crossplane, cluster management via CAPI, and traditional Kubernetes workloads. Describe what you want to deploy. Does NOT handle policy creation, organizational patterns, or resource capabilities - use manageOrgData for those.';
28
29
  // Zod schema for MCP registration (unified tool with stage routing)
29
30
  exports.RECOMMEND_TOOL_INPUT_SCHEMA = {
30
- stage: zod_1.z.string().optional().describe('Deployment workflow stage: "recommend" (default), "chooseSolution", "answerQuestion:required", "answerQuestion:basic", "answerQuestion:advanced", "answerQuestion:open", "generateManifests", "deployManifests". Defaults to "recommend" if omitted.'),
31
+ stage: zod_1.z.string().optional().describe('Deployment workflow stage: "recommend" (default), "chooseSolution", "answerQuestion:required", "answerQuestion:basic", "answerQuestion:advanced", "answerQuestion:open", "generateManifests", "pushToGit", "deployManifests". Defaults to "recommend" if omitted.'),
31
32
  intent: zod_1.z.string().min(1).max(1000).optional().describe('What the user wants to deploy, create, setup, install, or run on Kubernetes. Examples: "deploy web application", "create PostgreSQL database", "setup Redis cache", "install Prometheus monitoring", "configure Ingress controller", "provision storage volumes", "launch MongoDB operator", "run Node.js API", "setup CI/CD pipeline", "create load balancer", "install Grafana dashboard", "deploy React frontend"'),
32
33
  final: zod_1.z.boolean().optional().describe('Set to true to skip intent clarification and proceed directly with recommendations. If false or omitted, the tool will analyze the intent and provide clarification questions to help improve recommendation quality.'),
33
34
  // Parameters for chooseSolution stage
34
- solutionId: zod_1.z.string().optional().describe('Solution ID for chooseSolution, answerQuestion, generateManifests, and deployManifests stages'),
35
+ solutionId: zod_1.z.string().optional().describe('Solution ID for chooseSolution, answerQuestion, generateManifests, pushToGit, and deployManifests stages'),
35
36
  // Parameters for answerQuestion stage (stage parameter contains the config stage like "answerQuestion:required")
36
37
  answers: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe('User answers for answerQuestion stage'),
37
38
  // Parameters for deployManifests stage
38
39
  timeout: zod_1.z.number().optional().describe('Deployment timeout in seconds for deployManifests stage'),
40
+ // Parameters for pushToGit stage (PRD #395)
41
+ repoUrl: zod_1.z.string().url().optional().describe('Git repository URL for pushToGit stage (HTTPS)'),
42
+ targetPath: zod_1.z.string().optional().describe('Path within repository for pushToGit stage (e.g., "apps/postgresql/")'),
43
+ branch: zod_1.z.string().optional().describe('Git branch for pushToGit stage (default: main)'),
44
+ commitMessage: zod_1.z.string().optional().describe('Commit message for pushToGit stage'),
45
+ authorName: zod_1.z.string().optional().describe('Git author name for pushToGit stage'),
46
+ authorEmail: zod_1.z.string().optional().describe('Git author email for pushToGit stage'),
39
47
  interaction_id: zod_1.z.string().optional().describe('INTERNAL ONLY - Do not populate. Used for evaluation dataset generation.')
40
48
  };
41
49
  /**
@@ -72,6 +80,9 @@ async function handleRecommendTool(args, dotAI, logger, requestId, pluginManager
72
80
  // Stage-based routing: extract stage and route to appropriate handler
73
81
  const stage = args.stage || 'recommend'; // Default to 'recommend' if not specified
74
82
  logger.debug('Handling recommend request with stage routing', { requestId, stage, intent: args?.intent });
83
+ // Initialize session manager (shared across stages)
84
+ const sessionManager = new generic_session_manager_1.GenericSessionManager('sol');
85
+ logger.debug('Session manager initialized', { requestId });
75
86
  // Route to appropriate handler based on stage
76
87
  if (stage === 'chooseSolution') {
77
88
  return await (0, choose_solution_1.handleChooseSolutionTool)(args, dotAI, logger, requestId);
@@ -117,13 +128,23 @@ async function handleRecommendTool(args, dotAI, logger, requestId, pluginManager
117
128
  // PRD #359: Uses unified plugin registry for kubectl operations
118
129
  return await (0, deploy_manifests_1.handleDeployManifestsTool)(args, dotAI, logger, requestId);
119
130
  }
131
+ // PRD #395: pushToGit stage for GitOps workflows
132
+ if (stage === 'pushToGit') {
133
+ return await (0, push_to_git_1.handlePushToGitTool)({
134
+ solutionId: args.solutionId || '',
135
+ repoUrl: args.repoUrl || '',
136
+ targetPath: args.targetPath || '',
137
+ branch: args.branch,
138
+ commitMessage: args.commitMessage,
139
+ authorName: args.authorName,
140
+ authorEmail: args.authorEmail,
141
+ interaction_id: args.interaction_id,
142
+ }, dotAI, logger, requestId, sessionManager);
143
+ }
120
144
  // Default: recommend stage (original recommend logic)
121
145
  // Input validation is handled automatically by MCP SDK with Zod schema
122
146
  // args are already validated and typed when we reach this point
123
147
  // AI provider is already initialized and validated in dotAI.ai
124
- // Initialize session manager
125
- const sessionManager = new generic_session_manager_1.GenericSessionManager('sol');
126
- logger.debug('Session manager initialized', { requestId });
127
148
  logger.info('Starting resource recommendation process', {
128
149
  requestId,
129
150
  intent: args.intent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vfarcic/dot-ai",
3
- "version": "1.9.1",
3
+ "version": "1.10.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",
package/scripts/dot-ai.nu CHANGED
@@ -7,7 +7,7 @@
7
7
  # > main apply dot-ai --provider openai --model gpt-4o
8
8
  # > main apply dot-ai --enable-tracing true
9
9
  def "main apply dot-ai" [
10
- --stack-version = "0.18.0",
10
+ --stack-version = "0.44.0",
11
11
  --anthropic-api-key = "",
12
12
  --openai-api-key = "",
13
13
  --auth-token = "my-secret-token",
@@ -71,6 +71,8 @@ def "main apply dot-ai" [
71
71
  # Update .env with auth token for MCP clients
72
72
  $"export DOT_AI_AUTH_TOKEN=($auth_token)\n" | save --append .env
73
73
 
74
+ $"export DOT_AI_URL=http://($host)\n" | save --append .env
75
+
74
76
  if $enable_tracing {
75
77
  print $"Tracing enabled: Traces will be sent to (ansi yellow_bold)Jaeger in observability namespace(ansi reset)"
76
78
  }