@vfarcic/dot-ai 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/git-utils.d.ts +53 -0
- package/dist/core/git-utils.d.ts.map +1 -0
- package/dist/core/git-utils.js +268 -0
- package/dist/core/user-prompts-loader.d.ts +0 -5
- package/dist/core/user-prompts-loader.d.ts.map +1 -1
- package/dist/core/user-prompts-loader.js +11 -35
- package/dist/interfaces/rest-api.d.ts.map +1 -1
- package/dist/interfaces/rest-api.js +40 -24
- package/dist/tools/organizational-data.d.ts +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared git operations for the MCP server layer.
|
|
5
|
+
* Provides authenticated clone, pull, and push using simple-git.
|
|
6
|
+
*
|
|
7
|
+
* PRD #362: Git Operations for Recommend Tool
|
|
8
|
+
*
|
|
9
|
+
* Environment variables:
|
|
10
|
+
* - DOT_AI_GIT_TOKEN: PAT authentication token
|
|
11
|
+
* - GITHUB_APP_ENABLED: Enable GitHub App authentication
|
|
12
|
+
* - GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY, GITHUB_APP_INSTALLATION_ID: GitHub App config
|
|
13
|
+
*/
|
|
14
|
+
export interface GitAuthConfig {
|
|
15
|
+
pat?: string;
|
|
16
|
+
githubApp?: {
|
|
17
|
+
appId: string;
|
|
18
|
+
privateKey: string;
|
|
19
|
+
installationId?: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare function scrubCredentials(message: string): string;
|
|
23
|
+
export declare function getAuthenticatedUrl(repoUrl: string, token: string): string;
|
|
24
|
+
export declare function getAuthToken(authConfig: GitAuthConfig): Promise<string>;
|
|
25
|
+
export declare function getGitAuthConfigFromEnv(): GitAuthConfig;
|
|
26
|
+
export interface CloneOptions {
|
|
27
|
+
branch?: string;
|
|
28
|
+
depth?: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function cloneRepo(repoUrl: string, targetDir: string, opts?: CloneOptions): Promise<{
|
|
31
|
+
localPath: string;
|
|
32
|
+
branch: string;
|
|
33
|
+
}>;
|
|
34
|
+
export declare function pullRepo(repoPath: string): Promise<{
|
|
35
|
+
branch: string;
|
|
36
|
+
}>;
|
|
37
|
+
export interface PushOptions {
|
|
38
|
+
branch?: string;
|
|
39
|
+
author?: {
|
|
40
|
+
name: string;
|
|
41
|
+
email: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export interface PushResult {
|
|
45
|
+
commitSha: string | undefined;
|
|
46
|
+
branch: string;
|
|
47
|
+
filesAdded: string[];
|
|
48
|
+
}
|
|
49
|
+
export declare function pushRepo(repoPath: string, files: Array<{
|
|
50
|
+
path: string;
|
|
51
|
+
content: string;
|
|
52
|
+
}>, commitMessage: string, opts?: PushOptions): Promise<PushResult>;
|
|
53
|
+
//# sourceMappingURL=git-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-utils.d.ts","sourceRoot":"","sources":["../../src/core/git-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAYH,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE;QACV,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AASD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK1E;AA2ED,wBAAsB,YAAY,CAAC,UAAU,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAc7E;AAED,wBAAgB,uBAAuB,IAAI,aAAa,CAyBvD;AAeD,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAsBhD;AAID,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAyB7B;AAID,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,EAC/C,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,WAAW,GACjB,OAAO,CAAC,UAAU,CAAC,CAyErB"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Git Utilities
|
|
4
|
+
*
|
|
5
|
+
* Shared git operations for the MCP server layer.
|
|
6
|
+
* Provides authenticated clone, pull, and push using simple-git.
|
|
7
|
+
*
|
|
8
|
+
* PRD #362: Git Operations for Recommend Tool
|
|
9
|
+
*
|
|
10
|
+
* Environment variables:
|
|
11
|
+
* - DOT_AI_GIT_TOKEN: PAT authentication token
|
|
12
|
+
* - GITHUB_APP_ENABLED: Enable GitHub App authentication
|
|
13
|
+
* - GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY, GITHUB_APP_INSTALLATION_ID: GitHub App config
|
|
14
|
+
*/
|
|
15
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
18
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
19
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
20
|
+
}
|
|
21
|
+
Object.defineProperty(o, k2, desc);
|
|
22
|
+
}) : (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
o[k2] = m[k];
|
|
25
|
+
}));
|
|
26
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
27
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
28
|
+
}) : function(o, v) {
|
|
29
|
+
o["default"] = v;
|
|
30
|
+
});
|
|
31
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
32
|
+
var ownKeys = function(o) {
|
|
33
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
34
|
+
var ar = [];
|
|
35
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
36
|
+
return ar;
|
|
37
|
+
};
|
|
38
|
+
return ownKeys(o);
|
|
39
|
+
};
|
|
40
|
+
return function (mod) {
|
|
41
|
+
if (mod && mod.__esModule) return mod;
|
|
42
|
+
var result = {};
|
|
43
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
44
|
+
__setModuleDefault(result, mod);
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
})();
|
|
48
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
49
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
50
|
+
};
|
|
51
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
+
exports.scrubCredentials = scrubCredentials;
|
|
53
|
+
exports.getAuthenticatedUrl = getAuthenticatedUrl;
|
|
54
|
+
exports.getAuthToken = getAuthToken;
|
|
55
|
+
exports.getGitAuthConfigFromEnv = getGitAuthConfigFromEnv;
|
|
56
|
+
exports.cloneRepo = cloneRepo;
|
|
57
|
+
exports.pullRepo = pullRepo;
|
|
58
|
+
exports.pushRepo = pushRepo;
|
|
59
|
+
const simple_git_1 = __importDefault(require("simple-git"));
|
|
60
|
+
const jwt = __importStar(require("jsonwebtoken"));
|
|
61
|
+
const fs = __importStar(require("fs"));
|
|
62
|
+
const path = __importStar(require("path"));
|
|
63
|
+
const FETCH_TIMEOUT_MS = 30000;
|
|
64
|
+
const GIT_TIMEOUT_MS = 120000; // 2 minutes for git operations
|
|
65
|
+
// ─── Auth helpers ───
|
|
66
|
+
function scrubCredentials(message) {
|
|
67
|
+
return message
|
|
68
|
+
.replace(/\/\/x-access-token:[^@]+@/g, '//***@')
|
|
69
|
+
.replace(/\/\/[^/:][^@]*:[^@]+@/g, '//***@');
|
|
70
|
+
}
|
|
71
|
+
function getAuthenticatedUrl(repoUrl, token) {
|
|
72
|
+
const url = new URL(repoUrl);
|
|
73
|
+
url.username = 'x-access-token';
|
|
74
|
+
url.password = token;
|
|
75
|
+
return url.toString();
|
|
76
|
+
}
|
|
77
|
+
async function fetchWithTimeout(url, options, timeoutMs = FETCH_TIMEOUT_MS) {
|
|
78
|
+
const controller = new AbortController();
|
|
79
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
80
|
+
try {
|
|
81
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
clearTimeout(timeout);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function generateGitHubAppJWT(appId, privateKey) {
|
|
88
|
+
const now = Math.floor(Date.now() / 1000);
|
|
89
|
+
return jwt.sign({ iat: now - 60, exp: now + 10 * 60, iss: appId }, privateKey, { algorithm: 'RS256' });
|
|
90
|
+
}
|
|
91
|
+
async function getGitHubAppInstallationToken(appId, privateKey, installationId) {
|
|
92
|
+
const appJWT = generateGitHubAppJWT(appId, privateKey);
|
|
93
|
+
let installId = installationId;
|
|
94
|
+
if (!installId) {
|
|
95
|
+
const resp = await fetchWithTimeout('https://api.github.com/app/installations', {
|
|
96
|
+
headers: {
|
|
97
|
+
Authorization: `Bearer ${appJWT}`,
|
|
98
|
+
Accept: 'application/vnd.github.v3+json',
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
if (!resp.ok) {
|
|
102
|
+
throw new Error(`Failed to list installations: ${resp.statusText}`);
|
|
103
|
+
}
|
|
104
|
+
const installations = (await resp.json());
|
|
105
|
+
if (installations.length === 0) {
|
|
106
|
+
throw new Error('No GitHub App installations found');
|
|
107
|
+
}
|
|
108
|
+
installId = String(installations[0].id);
|
|
109
|
+
}
|
|
110
|
+
const tokenResp = await fetchWithTimeout(`https://api.github.com/app/installations/${installId}/access_tokens`, {
|
|
111
|
+
method: 'POST',
|
|
112
|
+
headers: {
|
|
113
|
+
Authorization: `Bearer ${appJWT}`,
|
|
114
|
+
Accept: 'application/vnd.github.v3+json',
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
if (!tokenResp.ok) {
|
|
118
|
+
throw new Error(`Failed to get installation token: ${tokenResp.statusText}`);
|
|
119
|
+
}
|
|
120
|
+
const data = (await tokenResp.json());
|
|
121
|
+
return { token: data.token, expiresAt: data.expires_at };
|
|
122
|
+
}
|
|
123
|
+
async function getAuthToken(authConfig) {
|
|
124
|
+
if (authConfig.pat)
|
|
125
|
+
return authConfig.pat;
|
|
126
|
+
if (authConfig.githubApp) {
|
|
127
|
+
const { appId, privateKey, installationId } = authConfig.githubApp;
|
|
128
|
+
const tokenData = await getGitHubAppInstallationToken(appId, privateKey, installationId);
|
|
129
|
+
return tokenData.token;
|
|
130
|
+
}
|
|
131
|
+
throw new Error('No authentication method configured. Provide either PAT or GitHub App credentials.');
|
|
132
|
+
}
|
|
133
|
+
function getGitAuthConfigFromEnv() {
|
|
134
|
+
const pat = process.env.DOT_AI_GIT_TOKEN;
|
|
135
|
+
const githubAppEnabled = process.env.GITHUB_APP_ENABLED === 'true';
|
|
136
|
+
if (pat)
|
|
137
|
+
return { pat };
|
|
138
|
+
if (githubAppEnabled) {
|
|
139
|
+
const appId = process.env.GITHUB_APP_ID;
|
|
140
|
+
const privateKey = process.env.GITHUB_APP_PRIVATE_KEY;
|
|
141
|
+
const installationId = process.env.GITHUB_APP_INSTALLATION_ID;
|
|
142
|
+
if (!appId || !privateKey) {
|
|
143
|
+
throw new Error('GitHub App enabled but GITHUB_APP_ID or GITHUB_APP_PRIVATE_KEY not set');
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
githubApp: {
|
|
147
|
+
appId,
|
|
148
|
+
privateKey: privateKey.replace(/\\n/g, '\n'),
|
|
149
|
+
installationId,
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return {};
|
|
154
|
+
}
|
|
155
|
+
// ─── Git options helper ───
|
|
156
|
+
function gitOptions(baseDir) {
|
|
157
|
+
return {
|
|
158
|
+
baseDir: baseDir || process.cwd(),
|
|
159
|
+
binary: 'git',
|
|
160
|
+
maxConcurrentProcesses: 6,
|
|
161
|
+
timeout: { block: GIT_TIMEOUT_MS },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
async function cloneRepo(repoUrl, targetDir, opts) {
|
|
165
|
+
const authConfig = getGitAuthConfigFromEnv();
|
|
166
|
+
const token = await getAuthToken(authConfig);
|
|
167
|
+
const authUrl = getAuthenticatedUrl(repoUrl, token);
|
|
168
|
+
const git = (0, simple_git_1.default)(gitOptions());
|
|
169
|
+
const cloneOptions = [];
|
|
170
|
+
if (opts?.branch) {
|
|
171
|
+
cloneOptions.push('--branch', opts.branch);
|
|
172
|
+
}
|
|
173
|
+
if (opts?.depth) {
|
|
174
|
+
cloneOptions.push('--depth', String(opts.depth));
|
|
175
|
+
}
|
|
176
|
+
await git.clone(authUrl, targetDir, cloneOptions);
|
|
177
|
+
const repoGit = (0, simple_git_1.default)(targetDir);
|
|
178
|
+
const status = await repoGit.status();
|
|
179
|
+
const branch = status.current || opts?.branch || 'main';
|
|
180
|
+
return { localPath: targetDir, branch };
|
|
181
|
+
}
|
|
182
|
+
// ─── Pull ───
|
|
183
|
+
async function pullRepo(repoPath) {
|
|
184
|
+
const authConfig = getGitAuthConfigFromEnv();
|
|
185
|
+
const token = await getAuthToken(authConfig);
|
|
186
|
+
const git = (0, simple_git_1.default)(gitOptions(repoPath));
|
|
187
|
+
const remotes = await git.getRemotes(true);
|
|
188
|
+
const origin = remotes.find(r => r.name === 'origin');
|
|
189
|
+
const originalOriginUrl = origin?.refs.fetch;
|
|
190
|
+
if (originalOriginUrl) {
|
|
191
|
+
const authUrl = getAuthenticatedUrl(originalOriginUrl, token);
|
|
192
|
+
await git.remote(['set-url', 'origin', authUrl]);
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
await git.pull('origin', undefined, ['--ff-only']);
|
|
196
|
+
const status = await git.status();
|
|
197
|
+
return { branch: status.current || 'main' };
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
// Restore original origin URL to prevent auth tokens persisting in .git/config
|
|
201
|
+
if (originalOriginUrl) {
|
|
202
|
+
await git.remote(['set-url', 'origin', originalOriginUrl]);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async function pushRepo(repoPath, files, commitMessage, opts) {
|
|
207
|
+
const git = (0, simple_git_1.default)(gitOptions(repoPath));
|
|
208
|
+
if (opts?.branch) {
|
|
209
|
+
const branches = await git.branchLocal();
|
|
210
|
+
if (!branches.all.includes(opts.branch)) {
|
|
211
|
+
await git.checkoutLocalBranch(opts.branch);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
await git.checkout(opts.branch);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
for (const file of files) {
|
|
218
|
+
const repoRoot = path.resolve(repoPath);
|
|
219
|
+
const fullPath = path.resolve(repoPath, file.path);
|
|
220
|
+
if (!fullPath.startsWith(repoRoot + path.sep) && fullPath !== repoRoot) {
|
|
221
|
+
throw new Error(`Path traversal detected: "${file.path}" attempts to write outside repository directory`);
|
|
222
|
+
}
|
|
223
|
+
const dir = path.dirname(fullPath);
|
|
224
|
+
if (!fs.existsSync(dir)) {
|
|
225
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
226
|
+
}
|
|
227
|
+
fs.writeFileSync(fullPath, file.content);
|
|
228
|
+
}
|
|
229
|
+
await git.add(files.map(f => f.path));
|
|
230
|
+
const gitUserName = opts?.author?.name || process.env.GIT_AUTHOR_NAME || 'dot-ai-bot';
|
|
231
|
+
const gitUserEmail = opts?.author?.email ||
|
|
232
|
+
process.env.GIT_AUTHOR_EMAIL ||
|
|
233
|
+
'dot-ai@users.noreply.github.com';
|
|
234
|
+
await git.addConfig('user.name', gitUserName);
|
|
235
|
+
await git.addConfig('user.email', gitUserEmail);
|
|
236
|
+
const commitResult = await git.commit(commitMessage);
|
|
237
|
+
if (!commitResult.commit) {
|
|
238
|
+
return {
|
|
239
|
+
commitSha: undefined,
|
|
240
|
+
branch: (await git.status()).current || 'main',
|
|
241
|
+
filesAdded: [],
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const authConfig = getGitAuthConfigFromEnv();
|
|
245
|
+
const token = await getAuthToken(authConfig);
|
|
246
|
+
const remotes = await git.getRemotes(true);
|
|
247
|
+
const origin = remotes.find(r => r.name === 'origin');
|
|
248
|
+
let originalOriginUrl;
|
|
249
|
+
if (origin) {
|
|
250
|
+
originalOriginUrl = origin.refs.fetch;
|
|
251
|
+
const authUrl = getAuthenticatedUrl(originalOriginUrl, token);
|
|
252
|
+
await git.remote(['set-url', 'origin', authUrl]);
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const currentBranch = (await git.status()).current || 'main';
|
|
256
|
+
await git.push('origin', currentBranch, ['--set-upstream']);
|
|
257
|
+
return {
|
|
258
|
+
commitSha: commitResult.commit,
|
|
259
|
+
branch: currentBranch,
|
|
260
|
+
filesAdded: files.map(f => f.path),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
if (origin && originalOriginUrl) {
|
|
265
|
+
await git.remote(['set-url', 'origin', originalOriginUrl]);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
@@ -40,11 +40,6 @@ export declare function getUserPromptsConfig(): UserPromptsConfig | null;
|
|
|
40
40
|
* Tries project-relative tmp first, falls back to system temp
|
|
41
41
|
*/
|
|
42
42
|
export declare function getCacheDirectory(): string;
|
|
43
|
-
/**
|
|
44
|
-
* Insert authentication token into git URL
|
|
45
|
-
* Works with any HTTPS git URL (GitHub, GitLab, Gitea, Bitbucket, etc.)
|
|
46
|
-
*/
|
|
47
|
-
export declare function insertTokenInUrl(url: string, token: string): string;
|
|
48
43
|
/**
|
|
49
44
|
* Sanitize URL for logging (remove credentials)
|
|
50
45
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-prompts-loader.d.ts","sourceRoot":"","sources":["../../src/core/user-prompts-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,MAAM,EAA8B,MAAM,kBAAkB,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,UAAU,UAAU;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,iBAAiB,GAAG,IAAI,CAsB/D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAqB1C;AAED
|
|
1
|
+
{"version":3,"file":"user-prompts-loader.d.ts","sourceRoot":"","sources":["../../src/core/user-prompts-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,MAAM,EAA8B,MAAM,kBAAkB,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,UAAU,UAAU;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,iBAAiB,GAAG,IAAI,CAsB/D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAqB1C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUzD;AAgOD;;;GAGG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,YAAY,GAAE,OAAe,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CA4FnB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,UAAU,GAAG,IAAI,CAE5D"}
|
|
@@ -48,7 +48,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
48
48
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
49
|
exports.getUserPromptsConfig = getUserPromptsConfig;
|
|
50
50
|
exports.getCacheDirectory = getCacheDirectory;
|
|
51
|
-
exports.insertTokenInUrl = insertTokenInUrl;
|
|
52
51
|
exports.sanitizeUrlForLogging = sanitizeUrlForLogging;
|
|
53
52
|
exports.loadUserPrompts = loadUserPrompts;
|
|
54
53
|
exports.clearUserPromptsCache = clearUserPromptsCache;
|
|
@@ -56,7 +55,7 @@ exports.getUserPromptsCacheState = getUserPromptsCacheState;
|
|
|
56
55
|
const fs = __importStar(require("fs"));
|
|
57
56
|
const path = __importStar(require("path"));
|
|
58
57
|
const os = __importStar(require("os"));
|
|
59
|
-
const
|
|
58
|
+
const git_utils_1 = require("./git-utils");
|
|
60
59
|
const prompts_1 = require("../tools/prompts");
|
|
61
60
|
// In-memory cache state (persists across requests within same process)
|
|
62
61
|
let cacheState = null;
|
|
@@ -104,21 +103,6 @@ function getCacheDirectory() {
|
|
|
104
103
|
return path.join(os.tmpdir(), 'dot-ai-user-prompts');
|
|
105
104
|
}
|
|
106
105
|
}
|
|
107
|
-
/**
|
|
108
|
-
* Insert authentication token into git URL
|
|
109
|
-
* Works with any HTTPS git URL (GitHub, GitLab, Gitea, Bitbucket, etc.)
|
|
110
|
-
*/
|
|
111
|
-
function insertTokenInUrl(url, token) {
|
|
112
|
-
try {
|
|
113
|
-
const parsed = new URL(url);
|
|
114
|
-
parsed.username = token;
|
|
115
|
-
return parsed.toString();
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
// If URL parsing fails, return original
|
|
119
|
-
return url;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
106
|
/**
|
|
123
107
|
* Sanitize URL for logging (remove credentials)
|
|
124
108
|
*/
|
|
@@ -147,13 +131,10 @@ function isValidGitBranch(branch) {
|
|
|
147
131
|
* Clone the user prompts repository
|
|
148
132
|
*/
|
|
149
133
|
async function cloneRepository(config, localPath, logger) {
|
|
150
|
-
// Validate branch name
|
|
134
|
+
// Validate branch name as defense-in-depth
|
|
151
135
|
if (!isValidGitBranch(config.branch)) {
|
|
152
136
|
throw new Error(`Invalid branch name: ${config.branch}`);
|
|
153
137
|
}
|
|
154
|
-
const authUrl = config.gitToken
|
|
155
|
-
? insertTokenInUrl(config.repoUrl, config.gitToken)
|
|
156
|
-
: config.repoUrl;
|
|
157
138
|
const sanitizedUrl = sanitizeUrlForLogging(config.repoUrl);
|
|
158
139
|
logger.info('Cloning user prompts repository', {
|
|
159
140
|
url: sanitizedUrl,
|
|
@@ -170,9 +151,10 @@ async function cloneRepository(config, localPath, logger) {
|
|
|
170
151
|
if (fs.existsSync(localPath)) {
|
|
171
152
|
fs.rmSync(localPath, { recursive: true, force: true });
|
|
172
153
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
154
|
+
await (0, git_utils_1.cloneRepo)(config.repoUrl, localPath, {
|
|
155
|
+
branch: config.branch,
|
|
156
|
+
depth: 1,
|
|
157
|
+
});
|
|
176
158
|
logger.info('Successfully cloned user prompts repository', {
|
|
177
159
|
url: sanitizedUrl,
|
|
178
160
|
branch: config.branch,
|
|
@@ -180,10 +162,9 @@ async function cloneRepository(config, localPath, logger) {
|
|
|
180
162
|
}
|
|
181
163
|
catch (error) {
|
|
182
164
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
183
|
-
|
|
184
|
-
const sanitizedError = config.gitToken
|
|
165
|
+
const sanitizedError = (0, git_utils_1.scrubCredentials)(config.gitToken
|
|
185
166
|
? errorMessage.replaceAll(config.gitToken, '***')
|
|
186
|
-
: errorMessage;
|
|
167
|
+
: errorMessage);
|
|
187
168
|
logger.error('Failed to clone user prompts repository', new Error(sanitizedError), {
|
|
188
169
|
url: sanitizedUrl,
|
|
189
170
|
branch: config.branch,
|
|
@@ -201,21 +182,16 @@ async function pullRepository(config, localPath, logger) {
|
|
|
201
182
|
localPath,
|
|
202
183
|
});
|
|
203
184
|
try {
|
|
204
|
-
|
|
205
|
-
if (config.gitToken) {
|
|
206
|
-
const authUrl = insertTokenInUrl(config.repoUrl, config.gitToken);
|
|
207
|
-
await (0, platform_utils_1.execAsync)(`git -C "${localPath}" remote set-url origin "${authUrl}"`);
|
|
208
|
-
}
|
|
209
|
-
await (0, platform_utils_1.execAsync)(`git -C "${localPath}" pull --ff-only`);
|
|
185
|
+
await (0, git_utils_1.pullRepo)(localPath);
|
|
210
186
|
logger.debug('Successfully pulled user prompts repository', {
|
|
211
187
|
url: sanitizedUrl,
|
|
212
188
|
});
|
|
213
189
|
}
|
|
214
190
|
catch (error) {
|
|
215
191
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
216
|
-
const sanitizedError = config.gitToken
|
|
192
|
+
const sanitizedError = (0, git_utils_1.scrubCredentials)(config.gitToken
|
|
217
193
|
? errorMessage.replaceAll(config.gitToken, '***')
|
|
218
|
-
: errorMessage;
|
|
194
|
+
: errorMessage);
|
|
219
195
|
logger.warn('Failed to pull user prompts repository, using cached version', {
|
|
220
196
|
url: sanitizedUrl,
|
|
221
197
|
error: sanitizedError,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../src/interfaces/rest-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE5D,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAAE,iBAAiB,EAAc,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAoCtC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../src/interfaces/rest-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -603,30 +603,41 @@ class RestApiRouter {
|
|
|
603
603
|
if (includeStatus &&
|
|
604
604
|
result.resources.length > 0 &&
|
|
605
605
|
(0, plugin_registry_1.isPluginInitialized)()) {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
const
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
const
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
606
|
+
// Process status fetches in batches to avoid overwhelming the
|
|
607
|
+
// agentic-tools pod with concurrent kubectl processes
|
|
608
|
+
const batchSize = 5;
|
|
609
|
+
const enrichedResources = [];
|
|
610
|
+
for (let i = 0; i < result.resources.length; i += batchSize) {
|
|
611
|
+
const batch = result.resources.slice(i, i + batchSize);
|
|
612
|
+
const batchResults = await Promise.all(batch.map(async (resource) => {
|
|
613
|
+
const resourceType = resource.apiGroup
|
|
614
|
+
? `${resource.kind.toLowerCase()}.${resource.apiGroup}`
|
|
615
|
+
: resource.kind.toLowerCase();
|
|
616
|
+
const resourceId = `${resourceType}/${resource.name}`;
|
|
617
|
+
const pluginResponse = await (0, plugin_registry_1.invokePluginTool)('agentic-tools', 'kubectl_get_resource_json', {
|
|
618
|
+
resource: resourceId,
|
|
619
|
+
namespace: resource.namespace,
|
|
620
|
+
field: 'status',
|
|
621
|
+
});
|
|
622
|
+
if (pluginResponse.success && pluginResponse.result) {
|
|
623
|
+
const pluginResult = pluginResponse.result;
|
|
624
|
+
if (pluginResult.success && pluginResult.data) {
|
|
625
|
+
try {
|
|
626
|
+
return {
|
|
627
|
+
...resource,
|
|
628
|
+
status: JSON.parse(pluginResult.data),
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
catch {
|
|
632
|
+
return resource;
|
|
633
|
+
}
|
|
624
634
|
}
|
|
625
635
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
636
|
+
return resource;
|
|
637
|
+
}));
|
|
638
|
+
enrichedResources.push(...batchResults);
|
|
639
|
+
}
|
|
640
|
+
result.resources = enrichedResources;
|
|
630
641
|
}
|
|
631
642
|
const response = {
|
|
632
643
|
success: true,
|
|
@@ -1064,7 +1075,9 @@ class RestApiRouter {
|
|
|
1064
1075
|
*/
|
|
1065
1076
|
async handlePromptsCacheRefresh(req, res, requestId) {
|
|
1066
1077
|
try {
|
|
1067
|
-
this.logger.info('Processing prompts cache refresh request', {
|
|
1078
|
+
this.logger.info('Processing prompts cache refresh request', {
|
|
1079
|
+
requestId,
|
|
1080
|
+
});
|
|
1068
1081
|
const prompts = await (0, prompts_1.loadAllPrompts)(this.logger, undefined, true);
|
|
1069
1082
|
const hasUserPromptsRepo = !!process.env.DOT_AI_USER_PROMPTS_REPO;
|
|
1070
1083
|
const source = hasUserPromptsRepo ? 'built-in+repository' : 'built-in';
|
|
@@ -1782,7 +1795,10 @@ class RestApiRouter {
|
|
|
1782
1795
|
*/
|
|
1783
1796
|
async handleCreateUser(_req, res, requestId, body) {
|
|
1784
1797
|
try {
|
|
1785
|
-
if (!body ||
|
|
1798
|
+
if (!body ||
|
|
1799
|
+
typeof body !== 'object' ||
|
|
1800
|
+
!('email' in body) ||
|
|
1801
|
+
!('password' in body)) {
|
|
1786
1802
|
await this.sendErrorResponse(res, requestId, HttpStatus.BAD_REQUEST, 'INVALID_REQUEST', 'Request body must include email and password');
|
|
1787
1803
|
return;
|
|
1788
1804
|
}
|
|
@@ -21,10 +21,10 @@ export declare const ORGANIZATIONAL_DATA_TOOL_INPUT_SCHEMA: {
|
|
|
21
21
|
operation: z.ZodEnum<{
|
|
22
22
|
search: "search";
|
|
23
23
|
get: "get";
|
|
24
|
+
progress: "progress";
|
|
24
25
|
create: "create";
|
|
25
26
|
list: "list";
|
|
26
27
|
delete: "delete";
|
|
27
|
-
progress: "progress";
|
|
28
28
|
deleteAll: "deleteAll";
|
|
29
29
|
scan: "scan";
|
|
30
30
|
analyze: "analyze";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vfarcic/dot-ai",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
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",
|
|
@@ -90,6 +90,7 @@
|
|
|
90
90
|
"@types/express": "^5.0.6",
|
|
91
91
|
"@types/glob": "^9.0.0",
|
|
92
92
|
"@types/handlebars": "^4.0.40",
|
|
93
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
93
94
|
"@types/node": "^22.0.0",
|
|
94
95
|
"@types/uuid": "^10.0.0",
|
|
95
96
|
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
@@ -126,8 +127,10 @@
|
|
|
126
127
|
"ai": "^5.0.60",
|
|
127
128
|
"bcryptjs": "^3.0.3",
|
|
128
129
|
"handlebars": "^4.7.8",
|
|
130
|
+
"jsonwebtoken": "^9.0.3",
|
|
129
131
|
"mermaid": "^10.9.5",
|
|
130
132
|
"posthog-node": "^5.23.0",
|
|
133
|
+
"simple-git": "^3.32.3",
|
|
131
134
|
"yaml": "^2.8.0"
|
|
132
135
|
},
|
|
133
136
|
"optionalDependencies": {
|