vigthoria-cli 1.6.26 → 1.6.28
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/commands/chat.js +31 -7
- package/dist/commands/edit.d.ts +3 -1
- package/dist/commands/edit.js +44 -2
- package/dist/index.js +4 -5
- package/dist/utils/api.js +21 -6
- package/package.json +1 -1
package/dist/commands/chat.js
CHANGED
|
@@ -421,11 +421,33 @@ class ChatCommand {
|
|
|
421
421
|
return;
|
|
422
422
|
}
|
|
423
423
|
if (options.prompt) {
|
|
424
|
+
// Wrap in a timeout to guarantee bridge cleanup even if the agent
|
|
425
|
+
// loop hangs (e.g. model takes forever on a turn).
|
|
426
|
+
const BRIDGE_TIMEOUT_MS = 180_000; // 3 minutes max for a single prompt
|
|
427
|
+
let timedOut = false;
|
|
428
|
+
const timeoutId = options.bridge
|
|
429
|
+
? setTimeout(() => {
|
|
430
|
+
timedOut = true;
|
|
431
|
+
const b = (0, bridge_client_js_1.getBridgeClient)();
|
|
432
|
+
if (b) {
|
|
433
|
+
b.emitEnd({ reason: 'timeout' });
|
|
434
|
+
b.destroy();
|
|
435
|
+
}
|
|
436
|
+
if (!this.jsonOutput) {
|
|
437
|
+
this.logger.error('Bridge prompt timed out after 3 minutes.');
|
|
438
|
+
}
|
|
439
|
+
process.exitCode = 1;
|
|
440
|
+
}, BRIDGE_TIMEOUT_MS)
|
|
441
|
+
: null;
|
|
424
442
|
await this.handleDirectPrompt(options.prompt);
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
bridge.
|
|
443
|
+
if (timeoutId)
|
|
444
|
+
clearTimeout(timeoutId);
|
|
445
|
+
if (!timedOut) {
|
|
446
|
+
const bridge = (0, bridge_client_js_1.getBridgeClient)();
|
|
447
|
+
if (bridge) {
|
|
448
|
+
bridge.emitEnd({ reason: 'prompt-complete' });
|
|
449
|
+
bridge.destroy();
|
|
450
|
+
}
|
|
429
451
|
}
|
|
430
452
|
return;
|
|
431
453
|
}
|
|
@@ -980,13 +1002,15 @@ class ChatCommand {
|
|
|
980
1002
|
if (toolCalls.length === 0) {
|
|
981
1003
|
// Phase 5: Quality gate — if the agent tries to conclude on the first
|
|
982
1004
|
// turn without any discovery, push it to gather evidence first.
|
|
983
|
-
|
|
1005
|
+
// Applies to diagnostic prompts AND any direct-prompt agent call where
|
|
1006
|
+
// the model failed to invoke tools (prevents truncated output).
|
|
1007
|
+
if (turn === 0 && this.agentToolEvidence.discovery === 0 && (this.isDiagnosticPrompt(prompt) || this.directPromptMode)) {
|
|
984
1008
|
this.messages.push({
|
|
985
1009
|
role: 'system',
|
|
986
1010
|
content: [
|
|
987
1011
|
'Quality gate: you concluded without using any discovery tools (list_dir, glob, read_file, grep).',
|
|
988
|
-
'
|
|
989
|
-
'Use list_dir
|
|
1012
|
+
'You MUST use tools to gather concrete evidence before providing your answer.',
|
|
1013
|
+
'Use list_dir to explore the workspace, then read_file or grep to inspect relevant files.',
|
|
990
1014
|
].join('\n'),
|
|
991
1015
|
});
|
|
992
1016
|
this.directToolContinuationCount += 1;
|
package/dist/commands/edit.d.ts
CHANGED
|
@@ -23,9 +23,11 @@ export declare class EditCommand {
|
|
|
23
23
|
private extractCode;
|
|
24
24
|
/**
|
|
25
25
|
* Detect and remove duplicated content in model output.
|
|
26
|
-
* Models sometimes output the code twice
|
|
26
|
+
* Models sometimes output the code twice or three times.
|
|
27
|
+
* Applies iteratively until no further duplicates are found.
|
|
27
28
|
*/
|
|
28
29
|
private deduplicateCode;
|
|
30
|
+
private deduplicateOnce;
|
|
29
31
|
private showDiffAndConfirm;
|
|
30
32
|
private showFullDiff;
|
|
31
33
|
private applyFix;
|
package/dist/commands/edit.js
CHANGED
|
@@ -133,7 +133,24 @@ Return the complete modified file content:`,
|
|
|
133
133
|
try {
|
|
134
134
|
const result = await this.api.fixCode(file.content, file.language, options.type);
|
|
135
135
|
spinner.stop();
|
|
136
|
+
// Deduplicate the fixed output — models sometimes repeat code 2-3x
|
|
137
|
+
result.fixed = this.deduplicateCode(result.fixed);
|
|
136
138
|
if (result.changes.length === 0) {
|
|
139
|
+
// Even if the diff engine found no structured changes, the fixed
|
|
140
|
+
// code may still differ (e.g. single-char operator swap). Show a
|
|
141
|
+
// diff and let the user decide instead of silently discarding.
|
|
142
|
+
if (result.fixed && result.fixed !== file.content) {
|
|
143
|
+
this.logger.section('Found 1 issue(s)');
|
|
144
|
+
console.log(chalk_1.default.yellow('1. Operator/character-level fix detected'));
|
|
145
|
+
console.log();
|
|
146
|
+
if (options.apply) {
|
|
147
|
+
await this.applyFix(file.path, file.content, result.fixed);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
await this.showDiffAndConfirm(file.path, file.content, result.fixed);
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
137
154
|
this.logger.success('No issues found!');
|
|
138
155
|
return;
|
|
139
156
|
}
|
|
@@ -180,14 +197,39 @@ Return the complete modified file content:`,
|
|
|
180
197
|
}
|
|
181
198
|
/**
|
|
182
199
|
* Detect and remove duplicated content in model output.
|
|
183
|
-
* Models sometimes output the code twice
|
|
200
|
+
* Models sometimes output the code twice or three times.
|
|
201
|
+
* Applies iteratively until no further duplicates are found.
|
|
184
202
|
*/
|
|
185
203
|
deduplicateCode(code) {
|
|
204
|
+
let result = code;
|
|
205
|
+
// Iterate up to 3 times to handle triple+ duplication
|
|
206
|
+
for (let pass = 0; pass < 3; pass++) {
|
|
207
|
+
const deduped = this.deduplicateOnce(result);
|
|
208
|
+
if (deduped === result)
|
|
209
|
+
break;
|
|
210
|
+
result = deduped;
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
214
|
+
deduplicateOnce(code) {
|
|
186
215
|
const lines = code.split('\n');
|
|
187
216
|
const len = lines.length;
|
|
188
217
|
if (len < 4)
|
|
189
218
|
return code;
|
|
190
|
-
//
|
|
219
|
+
// Pass 1: Remove adjacent duplicate non-empty lines (model stutter)
|
|
220
|
+
const deduped = [];
|
|
221
|
+
for (let i = 0; i < lines.length; i++) {
|
|
222
|
+
const trimmed = lines[i].trim();
|
|
223
|
+
const prevTrimmed = deduped.length > 0 ? deduped[deduped.length - 1].trim() : null;
|
|
224
|
+
if (trimmed && trimmed === prevTrimmed) {
|
|
225
|
+
continue; // skip consecutive duplicate
|
|
226
|
+
}
|
|
227
|
+
deduped.push(lines[i]);
|
|
228
|
+
}
|
|
229
|
+
if (deduped.length < lines.length) {
|
|
230
|
+
return deduped.join('\n');
|
|
231
|
+
}
|
|
232
|
+
// Pass 2: Check if the second half is a near-duplicate of the first half
|
|
191
233
|
for (let splitAt = Math.floor(len * 0.4); splitAt <= Math.ceil(len * 0.6); splitAt++) {
|
|
192
234
|
const firstHalf = lines.slice(0, splitAt);
|
|
193
235
|
const secondHalf = lines.slice(splitAt).filter(l => l.trim() !== '');
|
package/dist/index.js
CHANGED
|
@@ -98,7 +98,7 @@ function getVersion() {
|
|
|
98
98
|
catch (e) {
|
|
99
99
|
// Fallback to hardcoded version
|
|
100
100
|
}
|
|
101
|
-
return '1.6.
|
|
101
|
+
return '1.6.27';
|
|
102
102
|
}
|
|
103
103
|
const VERSION = getVersion();
|
|
104
104
|
/**
|
|
@@ -576,10 +576,9 @@ async function main() {
|
|
|
576
576
|
force: options.force
|
|
577
577
|
});
|
|
578
578
|
});
|
|
579
|
-
// Default repo action shows
|
|
580
|
-
repoCommand.action(
|
|
581
|
-
|
|
582
|
-
await repo.list({});
|
|
579
|
+
// Default repo action shows help with available subcommands
|
|
580
|
+
repoCommand.action(() => {
|
|
581
|
+
repoCommand.outputHelp();
|
|
583
582
|
});
|
|
584
583
|
// ==================== DEPLOY COMMANDS ====================
|
|
585
584
|
// Deploy command - Host projects on Vigthoria
|
package/dist/utils/api.js
CHANGED
|
@@ -50,7 +50,7 @@ class APIClient {
|
|
|
50
50
|
// Main Vigthoria Coder API (coder.vigthoria.io)
|
|
51
51
|
this.client = axios_1.default.create({
|
|
52
52
|
baseURL: config.get('apiUrl'),
|
|
53
|
-
timeout:
|
|
53
|
+
timeout: 300000, // 5 minutes — covers review, fix, and agent relay flows
|
|
54
54
|
httpsAgent,
|
|
55
55
|
headers: {
|
|
56
56
|
'Content-Type': 'application/json',
|
|
@@ -3374,7 +3374,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3374
3374
|
* for a pure programming language like JavaScript, Python, etc.
|
|
3375
3375
|
*/
|
|
3376
3376
|
codeContainsDomPollution(code) {
|
|
3377
|
-
const domPatterns = /document\.(createElement|querySelector|getElementById|getElementsBy|body|head|addEventListener)|innerHTML|\.style\.(cssText|position|transform|animation)|@keyframes|\.appendChild|\.removeChild|window\.(onload|addEventListener)/;
|
|
3377
|
+
const domPatterns = /document\.(createElement|querySelector|getElementById|getElementsBy|body|head|addEventListener)|innerHTML|\.style\.(cssText|position|transform|animation)|@keyframes|\.appendChild|\.removeChild|window\.(onload|addEventListener)|CSSAnimation|new\s+Animation\b|\.getAnimations\s*\(|\.animate\s*\(/;
|
|
3378
3378
|
return domPatterns.test(code);
|
|
3379
3379
|
}
|
|
3380
3380
|
/**
|
|
@@ -3388,7 +3388,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3388
3388
|
let braceDepth = 0;
|
|
3389
3389
|
for (const line of lines) {
|
|
3390
3390
|
// Detect start of DOM blocks
|
|
3391
|
-
if (/document\.|\.style\.|\.appendChild|\.removeChild|\.textContent\s*=|@keyframes|addEventListener/.test(line) && !insideDomBlock) {
|
|
3391
|
+
if (/document\.|\.style\.|\.appendChild|\.removeChild|\.textContent\s*=|@keyframes|addEventListener|CSSAnimation|\.getAnimations|\.animate\s*\(/.test(line) && !insideDomBlock) {
|
|
3392
3392
|
insideDomBlock = true;
|
|
3393
3393
|
braceDepth = 0;
|
|
3394
3394
|
}
|
|
@@ -3456,7 +3456,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3456
3456
|
// even when the server only reports style issues like console.log.
|
|
3457
3457
|
const heuristic = this.heuristicCodeIssues(code, language);
|
|
3458
3458
|
for (const h of heuristic) {
|
|
3459
|
-
//
|
|
3459
|
+
// Always include critical logic bugs (severity error) from heuristics
|
|
3460
|
+
// regardless of server results — these catch wrong-operator bugs the
|
|
3461
|
+
// server frequently misses.
|
|
3462
|
+
if (h.severity === 'error') {
|
|
3463
|
+
const exactDuplicate = issues.some((existing) => existing.line === h.line && existing.message === h.message);
|
|
3464
|
+
if (!exactDuplicate) {
|
|
3465
|
+
issues.push(h);
|
|
3466
|
+
}
|
|
3467
|
+
continue;
|
|
3468
|
+
}
|
|
3469
|
+
// For non-critical heuristics, avoid duplicating issues the server
|
|
3470
|
+
// already reported on the same line with the same type.
|
|
3460
3471
|
const isDuplicate = issues.some((existing) => existing.line === h.line && existing.type === h.type);
|
|
3461
3472
|
if (!isDuplicate) {
|
|
3462
3473
|
issues.push(h);
|
|
@@ -3578,7 +3589,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3578
3589
|
if (fixType === 'bugs' || fixType === 'logic')
|
|
3579
3590
|
return issue.type === 'logic' || issue.severity === 'error';
|
|
3580
3591
|
if (fixType === 'syntax')
|
|
3581
|
-
return issue.severity === 'error';
|
|
3592
|
+
return issue.type !== 'logic' && issue.severity === 'error';
|
|
3582
3593
|
if (fixType === 'style')
|
|
3583
3594
|
return issue.type === 'style' || issue.type === 'quality';
|
|
3584
3595
|
if (fixType === 'security')
|
|
@@ -3619,7 +3630,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3619
3630
|
// a semantic diff using LCS so inserted/removed lines don't cause
|
|
3620
3631
|
// every subsequent line to appear as changed.
|
|
3621
3632
|
if (changes.length === 0 && fixed !== code) {
|
|
3622
|
-
|
|
3633
|
+
// Use a clean reason string — strip verbose static-analysis hints
|
|
3634
|
+
const cleanReason = relevantIssues.length > 0
|
|
3635
|
+
? relevantIssues.map(i => i.message).join('; ')
|
|
3636
|
+
: 'AI-suggested fix';
|
|
3637
|
+
changes = this.computeSemanticDiff(code, fixed, cleanReason);
|
|
3623
3638
|
}
|
|
3624
3639
|
return { fixed, changes };
|
|
3625
3640
|
}
|