@vfarcic/dot-ai 1.16.1 → 1.16.3
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/README.md +1 -0
- package/dist/core/ai-provider-factory.d.ts.map +1 -1
- package/dist/core/ai-provider-factory.js +1 -0
- package/dist/core/internal-tools.d.ts.map +1 -1
- package/dist/core/internal-tools.js +18 -8
- package/dist/tools/answer-question.d.ts +21 -0
- package/dist/tools/answer-question.d.ts.map +1 -1
- package/dist/tools/answer-question.js +13 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-provider-factory.d.ts","sourceRoot":"","sources":["../../src/core/ai-provider-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"ai-provider-factory.d.ts","sourceRoot":"","sources":["../../src/core/ai-provider-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAiCvE;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAiB;IAC5B;;;;;;OAMG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU;IA+BnD;;;;;;;;;;OAUG;IACH,MAAM,CAAC,aAAa,IAAI,UAAU;IAsGlC;;;;;OAKG;IACH,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAWrD;;;;OAIG;IACH,MAAM,CAAC,qBAAqB,IAAI,MAAM,EAAE;IAMxC;;;;;OAKG;IACH,MAAM,CAAC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAGxD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAE7C"}
|
|
@@ -30,6 +30,7 @@ const PROVIDER_ENV_KEYS = {
|
|
|
30
30
|
kimi: 'MOONSHOT_API_KEY', // PRD #353: Moonshot AI Kimi K2.5
|
|
31
31
|
alibaba: 'ALIBABA_API_KEY', // PRD #382: Alibaba Qwen 3.5 Plus
|
|
32
32
|
xai: 'XAI_API_KEY',
|
|
33
|
+
custom: 'CUSTOM_LLM_API_KEY', // PRD #194 / Issue #474: Explicit opt-in to custom OpenAI-compatible endpoint
|
|
33
34
|
};
|
|
34
35
|
const IMPLEMENTED_PROVIDERS = Object.keys(model_config_1.CURRENT_MODELS);
|
|
35
36
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal-tools.d.ts","sourceRoot":"","sources":["../../src/core/internal-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAsBvE;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAUlE;
|
|
1
|
+
{"version":3,"file":"internal-tools.d.ts","sourceRoot":"","sources":["../../src/core/internal-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAsBvE;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAUlE;AAgBD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAkD3C;AAiHD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,iBAAiB,GACzB;IACE,OAAO,EAAE,IAAI,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,GACD;IACE,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf,GACD;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA4ItC;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CAqB1E;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,GAAE,MAAuB,GAAG,IAAI,CAuBxE"}
|
|
@@ -89,9 +89,7 @@ function validatePathWithinClones(inputPath) {
|
|
|
89
89
|
function repoUrlToDirectoryName(repoUrl) {
|
|
90
90
|
try {
|
|
91
91
|
const url = new URL(repoUrl);
|
|
92
|
-
const repoPath = url.pathname
|
|
93
|
-
.replace(/^\//, '')
|
|
94
|
-
.replace(/\.git$/, '');
|
|
92
|
+
const repoPath = url.pathname.replace(/^\//, '').replace(/\.git$/, '');
|
|
95
93
|
return (0, solution_utils_js_1.sanitizeIntentForLabel)(repoPath);
|
|
96
94
|
}
|
|
97
95
|
catch {
|
|
@@ -196,7 +194,7 @@ function handleFsList(args) {
|
|
|
196
194
|
return `Error: path is not a directory: ${inputPath}`;
|
|
197
195
|
}
|
|
198
196
|
const entries = fs.readdirSync(resolved, { withFileTypes: true });
|
|
199
|
-
return entries.map(
|
|
197
|
+
return entries.map(entry => ({
|
|
200
198
|
name: entry.name,
|
|
201
199
|
type: entry.isDirectory() ? 'directory' : 'file',
|
|
202
200
|
}));
|
|
@@ -257,7 +255,10 @@ async function handleGitCreatePr(args) {
|
|
|
257
255
|
return { success: false, error: 'repoPath is required' };
|
|
258
256
|
}
|
|
259
257
|
if (!files || !Array.isArray(files) || files.length === 0) {
|
|
260
|
-
return {
|
|
258
|
+
return {
|
|
259
|
+
success: false,
|
|
260
|
+
error: 'files array is required and must not be empty',
|
|
261
|
+
};
|
|
261
262
|
}
|
|
262
263
|
if (!title) {
|
|
263
264
|
return { success: false, error: 'title is required' };
|
|
@@ -324,6 +325,12 @@ async function handleGitCreatePr(args) {
|
|
|
324
325
|
body,
|
|
325
326
|
head: branchName,
|
|
326
327
|
base: baseBranch,
|
|
328
|
+
// Test-only switch: integration tests set this so PRs they create
|
|
329
|
+
// don't trigger CodeRabbit (which has drafts: false in .coderabbit.yaml).
|
|
330
|
+
// Production never sets this env var.
|
|
331
|
+
...(process.env.DOT_AI_GIT_CREATE_DRAFT_PRS === 'true' && {
|
|
332
|
+
draft: true,
|
|
333
|
+
}),
|
|
327
334
|
}),
|
|
328
335
|
signal: AbortSignal.timeout(30000),
|
|
329
336
|
});
|
|
@@ -356,7 +363,7 @@ async function handleGitCreatePr(args) {
|
|
|
356
363
|
*/
|
|
357
364
|
function createInternalToolExecutor(sessionId) {
|
|
358
365
|
const handlers = {
|
|
359
|
-
git_clone:
|
|
366
|
+
git_clone: args => handleGitClone(args, sessionId),
|
|
360
367
|
fs_list: handleFsList,
|
|
361
368
|
fs_read: handleFsRead,
|
|
362
369
|
git_create_pr: handleGitCreatePr,
|
|
@@ -380,7 +387,9 @@ function createInternalToolExecutor(sessionId) {
|
|
|
380
387
|
*/
|
|
381
388
|
function cleanupOldClones(maxAgeMs = DEFAULT_TTL_MS) {
|
|
382
389
|
const clonesDir = getClonesDir();
|
|
383
|
-
fs.promises
|
|
390
|
+
fs.promises
|
|
391
|
+
.access(clonesDir)
|
|
392
|
+
.then(async () => {
|
|
384
393
|
const now = Date.now();
|
|
385
394
|
const entries = await fs.promises.readdir(clonesDir);
|
|
386
395
|
for (const entry of entries) {
|
|
@@ -395,7 +404,8 @@ function cleanupOldClones(maxAgeMs = DEFAULT_TTL_MS) {
|
|
|
395
404
|
// Ignore errors during cleanup (e.g., concurrent deletion)
|
|
396
405
|
}
|
|
397
406
|
}
|
|
398
|
-
})
|
|
407
|
+
})
|
|
408
|
+
.catch(() => {
|
|
399
409
|
// Directory doesn't exist yet, nothing to clean
|
|
400
410
|
});
|
|
401
411
|
}
|
|
@@ -4,6 +4,22 @@
|
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { DotAI } from '../core/index';
|
|
6
6
|
import { Logger } from '../core/error-handling';
|
|
7
|
+
interface QuestionValidation {
|
|
8
|
+
required?: boolean;
|
|
9
|
+
message?: string;
|
|
10
|
+
min?: number;
|
|
11
|
+
max?: number;
|
|
12
|
+
pattern?: string;
|
|
13
|
+
options?: string[];
|
|
14
|
+
}
|
|
15
|
+
interface Question {
|
|
16
|
+
id?: string;
|
|
17
|
+
question: string;
|
|
18
|
+
type?: 'text' | 'number' | 'boolean' | 'select' | 'multiSelect';
|
|
19
|
+
validation?: QuestionValidation;
|
|
20
|
+
answer?: unknown;
|
|
21
|
+
options?: string[];
|
|
22
|
+
}
|
|
7
23
|
export declare const ANSWERQUESTION_TOOL_NAME = "answerQuestion";
|
|
8
24
|
export declare const ANSWERQUESTION_TOOL_DESCRIPTION = "Process user answers and return remaining questions or completion status. For open stage, use \"open\" as the answer key.";
|
|
9
25
|
export declare const ANSWERQUESTION_TOOL_INPUT_SCHEMA: {
|
|
@@ -17,6 +33,10 @@ export declare const ANSWERQUESTION_TOOL_INPUT_SCHEMA: {
|
|
|
17
33
|
answers: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
18
34
|
interaction_id: z.ZodOptional<z.ZodString>;
|
|
19
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Validate answer against question schema
|
|
38
|
+
*/
|
|
39
|
+
export declare function validateAnswer(answer: unknown, question: Question): string | null;
|
|
20
40
|
/**
|
|
21
41
|
* Direct MCP tool handler for answerQuestion functionality
|
|
22
42
|
*/
|
|
@@ -31,4 +51,5 @@ export declare function handleAnswerQuestionTool(args: {
|
|
|
31
51
|
text: string;
|
|
32
52
|
}[];
|
|
33
53
|
}>;
|
|
54
|
+
export {};
|
|
34
55
|
//# sourceMappingURL=answer-question.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"answer-question.d.ts","sourceRoot":"","sources":["../../src/tools/answer-question.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"answer-question.d.ts","sourceRoot":"","sources":["../../src/tools/answer-question.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAUhD,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,UAAU,QAAQ;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAC;IAChE,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAgDD,eAAO,MAAM,wBAAwB,mBAAmB,CAAC;AACzD,eAAO,MAAM,+BAA+B,8HAC+E,CAAC;AAG5H,eAAO,MAAM,gCAAgC;;;;;;;;;;CAmB5C,CAAC;AAIF;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,QAAQ,GACjB,MAAM,GAAG,IAAI,CA4Ef;AAyiBD;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE;IACJ,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;IAClD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,EACD,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAgZxD"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ANSWERQUESTION_TOOL_INPUT_SCHEMA = exports.ANSWERQUESTION_TOOL_DESCRIPTION = exports.ANSWERQUESTION_TOOL_NAME = void 0;
|
|
7
|
+
exports.validateAnswer = validateAnswer;
|
|
7
8
|
exports.handleAnswerQuestionTool = handleAnswerQuestionTool;
|
|
8
9
|
const zod_1 = require("zod");
|
|
9
10
|
const error_handling_1 = require("../core/error-handling");
|
|
@@ -36,9 +37,19 @@ exports.ANSWERQUESTION_TOOL_INPUT_SCHEMA = {
|
|
|
36
37
|
* Validate answer against question schema
|
|
37
38
|
*/
|
|
38
39
|
function validateAnswer(answer, question) {
|
|
39
|
-
// Check required validation
|
|
40
|
+
// Check required validation.
|
|
41
|
+
// Issue #474: For 'select' questions, empty string is a valid answer when it
|
|
42
|
+
// is explicitly listed in `options` (e.g., options=["", "soft", "hard"] where
|
|
43
|
+
// "" represents the "none/disabled" choice). Skip the empty-string rejection
|
|
44
|
+
// in that case so the question's own option list is the source of truth.
|
|
45
|
+
const emptyAnswer = answer === undefined || answer === null || answer === '';
|
|
46
|
+
const isExplicitEmptySelectOption = question.type === 'select' &&
|
|
47
|
+
answer === '' &&
|
|
48
|
+
Array.isArray(question.options) &&
|
|
49
|
+
question.options.includes('');
|
|
40
50
|
if (question.validation?.required &&
|
|
41
|
-
|
|
51
|
+
emptyAnswer &&
|
|
52
|
+
!isExplicitEmptySelectOption) {
|
|
42
53
|
return question.validation.message || `${question.question} is required`;
|
|
43
54
|
}
|
|
44
55
|
// Skip validation if answer is empty and not required
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vfarcic/dot-ai",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.3",
|
|
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",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"ts-node": "^10.9.0",
|
|
104
104
|
"typescript": "^5.0.0",
|
|
105
105
|
"typescript-eslint": "^8.54.0",
|
|
106
|
-
"uuid": "^
|
|
106
|
+
"uuid": "^14.0.0",
|
|
107
107
|
"vitest": "^3.2.4"
|
|
108
108
|
},
|
|
109
109
|
"dependencies": {
|