vigthoria-cli 1.6.42 → 1.6.44
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/auth.js +17 -13
- package/dist/commands/bridge.js +2 -0
- package/dist/commands/chat.d.ts +19 -0
- package/dist/commands/chat.js +190 -9
- package/dist/index.js +1 -1
- package/dist/utils/api.js +1 -0
- package/dist/utils/tools.js +14 -6
- package/package.json +2 -2
package/dist/commands/auth.js
CHANGED
|
@@ -138,6 +138,7 @@ class AuthCommand {
|
|
|
138
138
|
this.logger.warn('Not logged in');
|
|
139
139
|
console.log();
|
|
140
140
|
console.log(chalk_1.default.gray('Run `vigthoria login` to authenticate'));
|
|
141
|
+
this.api.destroy();
|
|
141
142
|
return;
|
|
142
143
|
}
|
|
143
144
|
const email = this.config.get('email');
|
|
@@ -174,6 +175,7 @@ class AuthCommand {
|
|
|
174
175
|
console.log();
|
|
175
176
|
// Run ALL three probes in parallel — they are independent.
|
|
176
177
|
const spinner = (0, logger_js_1.createSpinner)('Checking API, capabilities and auth...').start();
|
|
178
|
+
let capabilityTimeout = null;
|
|
177
179
|
const [apiStatus, capabilityStatus, tokenValidation] = await Promise.all([
|
|
178
180
|
this.api.getHealthStatus(),
|
|
179
181
|
Promise.race([
|
|
@@ -182,16 +184,20 @@ class AuthCommand {
|
|
|
182
184
|
projectPath: process.cwd(),
|
|
183
185
|
targetPath: process.cwd(),
|
|
184
186
|
}),
|
|
185
|
-
new Promise(resolve =>
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
187
|
+
new Promise(resolve => {
|
|
188
|
+
capabilityTimeout = setTimeout(() => resolve({
|
|
189
|
+
overallOk: false,
|
|
190
|
+
v3Agent: { name: 'V3 Agent', endpoint: '', ok: false, error: 'Timed out (8s)' },
|
|
191
|
+
hyperLoop: { name: 'Hyper Loop', endpoint: '', ok: false, error: 'Timed out (8s)' },
|
|
192
|
+
repoMemory: { name: 'Repo Memory', endpoint: '', ok: false, error: 'Timed out (8s)' },
|
|
193
|
+
devtoolsBridge: { name: 'DevTools Bridge', endpoint: '', ok: false, error: 'Timed out (8s)' },
|
|
194
|
+
}), 8000);
|
|
195
|
+
}),
|
|
192
196
|
]),
|
|
193
197
|
this.api.validateToken(),
|
|
194
198
|
]);
|
|
199
|
+
if (capabilityTimeout)
|
|
200
|
+
clearTimeout(capabilityTimeout);
|
|
195
201
|
spinner.stop();
|
|
196
202
|
// --- Display API Status ---
|
|
197
203
|
console.log(chalk_1.default.white('API Status:'));
|
|
@@ -249,13 +255,11 @@ class AuthCommand {
|
|
|
249
255
|
console.log(chalk_1.default.gray(' Bridge Auth: ') + (capabilityStatus.devtoolsBridge.ok ? chalk_1.default.green('Connected') : chalk_1.default.gray('N/A — bridge not running')) + chalk_1.default.gray(' (used by --bridge flag only)'));
|
|
250
256
|
console.log();
|
|
251
257
|
// Graceful exit — destroy keep-alive agents so the event loop drains
|
|
252
|
-
// naturally
|
|
253
|
-
//
|
|
254
|
-
//
|
|
258
|
+
// naturally. Setting exitCode (not calling process.exit()) avoids the
|
|
259
|
+
// libuv UV_HANDLE_CLOSING assertion on Windows that occurs when
|
|
260
|
+
// process.exit() is invoked while socket handles are mid-close.
|
|
255
261
|
this.api.destroy();
|
|
256
|
-
|
|
257
|
-
// 150 ms, force exit (unref'd so it won't block a clean drain).
|
|
258
|
-
setTimeout(() => process.exit(0), 150).unref();
|
|
262
|
+
process.exitCode = 0;
|
|
259
263
|
}
|
|
260
264
|
printLoginSuccess() {
|
|
261
265
|
const email = this.config.get('email');
|
package/dist/commands/bridge.js
CHANGED
|
@@ -32,6 +32,8 @@ class BridgeCommand {
|
|
|
32
32
|
? chalk_1.default.green('Local browser observability is available for debugging flows.')
|
|
33
33
|
: chalk_1.default.gray('Start the DevTools Bridge to enable local browser observability.')));
|
|
34
34
|
console.log();
|
|
35
|
+
this.api.destroy();
|
|
36
|
+
process.exitCode = 0;
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
39
|
exports.BridgeCommand = BridgeCommand;
|
package/dist/commands/chat.d.ts
CHANGED
|
@@ -60,6 +60,13 @@ export declare class ChatCommand {
|
|
|
60
60
|
* file scanning, or infrastructure changes.
|
|
61
61
|
*/
|
|
62
62
|
private isOperatorDirectAnswerable;
|
|
63
|
+
/**
|
|
64
|
+
* Returns true when the prompt references code artefacts, file paths,
|
|
65
|
+
* or analysis verbs that require tool-backed file reading to answer
|
|
66
|
+
* correctly. Used to route operator prompts through the agent loop
|
|
67
|
+
* instead of the toolless BMAD/direct-answer path.
|
|
68
|
+
*/
|
|
69
|
+
private isRepoGroundedPrompt;
|
|
63
70
|
private inferAgentTaskType;
|
|
64
71
|
private buildTaskShapingInstructions;
|
|
65
72
|
private buildExecutionPrompt;
|
|
@@ -124,10 +131,22 @@ export declare class ChatCommand {
|
|
|
124
131
|
private isProtectedFileReferenceSafe;
|
|
125
132
|
private isProtectedFileReference;
|
|
126
133
|
private buildContinuationPrompt;
|
|
134
|
+
/**
|
|
135
|
+
* Extract Key* / event-handler identifiers from tool results grouped by
|
|
136
|
+
* file, then compute which identifiers actually overlap across files.
|
|
137
|
+
* Returns a formatted hint string, or empty string if not applicable.
|
|
138
|
+
*/
|
|
139
|
+
private computeCrossFileKeyEvidence;
|
|
127
140
|
private extractToolCalls;
|
|
128
141
|
private parseToolPayload;
|
|
129
142
|
private stripToolPayloads;
|
|
130
143
|
private extractFinalFileContent;
|
|
144
|
+
/**
|
|
145
|
+
* Synthesize a best-effort answer from tool evidence already collected
|
|
146
|
+
* in the message history. Used as a fallback when the model API fails
|
|
147
|
+
* on a continuation turn after evidence was gathered.
|
|
148
|
+
*/
|
|
149
|
+
private synthesizeEvidenceFromHistory;
|
|
131
150
|
private resolveDirectModeCompletion;
|
|
132
151
|
private isDirectModeFollowUpQuestion;
|
|
133
152
|
private buildLocalAnalysisFallback;
|
package/dist/commands/chat.js
CHANGED
|
@@ -216,11 +216,38 @@ class ChatCommand {
|
|
|
216
216
|
*/
|
|
217
217
|
isOperatorDirectAnswerable(prompt) {
|
|
218
218
|
const trimmed = prompt.trim();
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
219
|
+
// ── Exclusion guard: any prompt that references code artefacts,
|
|
220
|
+
// file paths, or analysis verbs MUST go through a tool-backed path
|
|
221
|
+
// (BMAD or agent loop), never the toolless direct-answer shortcut.
|
|
222
|
+
const repoGrounded = /\b(src\/|\.js\b|\.ts\b|\.py\b|\.jsx\b|\.tsx\b|\.css\b|\.html\b|\.json\b|\.yaml\b|\.yml\b)/i.test(trimmed)
|
|
223
|
+
|| /\b(file|folder|directory|module|class|function|method|variable|handler|listener|binding|conflict|bug|issue|error)\b/i.test(trimmed)
|
|
224
|
+
|| /\b(inspect|analyze|analyse|audit|review|find|diagnose|debug|trace|compare|diff|check|investigate)\b/i.test(trimmed)
|
|
225
|
+
|| /\b(Camera|InputManager|keydown|KeyS|KeyA|KeyW|stopPropagation|addEventListener|handleKeyDown)\b/.test(trimmed)
|
|
226
|
+
|| /\/[a-zA-Z]/.test(trimmed) // slash-prefixed paths
|
|
227
|
+
|| /[A-Z][a-z]+\.[a-z_][a-zA-Z]+/.test(trimmed) // ClassName.methodName
|
|
228
|
+
|| /\b(key\s*code|keydown|keyup|key\s*bind|event\s*listener|event\s*handler|addEventListener|handleKey|onKey)\b/i.test(trimmed);
|
|
229
|
+
if (repoGrounded)
|
|
230
|
+
return false;
|
|
231
|
+
// Only truly trivial prompts are direct-answerable: short echo/smoke
|
|
232
|
+
// prompts and factual questions with no code or repo reference.
|
|
233
|
+
const isTrivialEcho = trimmed.length < 120
|
|
234
|
+
&& /^(reply with|say|echo|respond with|return|ping|hello|hi|test|status|what is \d|how much is)\b/i.test(trimmed);
|
|
235
|
+
return isTrivialEcho;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Returns true when the prompt references code artefacts, file paths,
|
|
239
|
+
* or analysis verbs that require tool-backed file reading to answer
|
|
240
|
+
* correctly. Used to route operator prompts through the agent loop
|
|
241
|
+
* instead of the toolless BMAD/direct-answer path.
|
|
242
|
+
*/
|
|
243
|
+
isRepoGroundedPrompt(prompt) {
|
|
244
|
+
const trimmed = prompt.trim();
|
|
245
|
+
return /\b(src\/|\.js\b|\.ts\b|\.py\b|\.jsx\b|\.tsx\b|\.css\b|\.html\b|\.json\b)/i.test(trimmed)
|
|
246
|
+
|| /\b(file|folder|module|class|function|method|handler|listener|binding|conflict|bug|error)\b/i.test(trimmed)
|
|
247
|
+
|| /\b(inspect|analyze|analyse|audit|review|find|diagnose|debug|trace|compare|diff|check|investigate)\b/i.test(trimmed)
|
|
248
|
+
|| /\/[a-zA-Z]/.test(trimmed)
|
|
249
|
+
|| /[A-Z][a-z]+\.[a-z_][a-zA-Z]+/.test(trimmed) // ClassName.methodName patterns
|
|
250
|
+
|| /\b(key\s*code|keydown|keyup|key\s*bind|event\s*listener|event\s*handler|addEventListener|handleKey|onKey)\b/i.test(trimmed);
|
|
224
251
|
}
|
|
225
252
|
inferAgentTaskType(prompt) {
|
|
226
253
|
if (this.isDiagnosticPrompt(prompt))
|
|
@@ -798,6 +825,16 @@ class ChatCommand {
|
|
|
798
825
|
await this.runOperatorDirectAnswer(prompt);
|
|
799
826
|
return;
|
|
800
827
|
}
|
|
828
|
+
// ── Repo-grounded operator path: use the agent loop with tools ──
|
|
829
|
+
// Prompts that reference files, code symbols, or analysis verbs need
|
|
830
|
+
// tool access to read actual file contents. Route these through the
|
|
831
|
+
// local agent loop (which has read_file, grep, etc.) instead of the
|
|
832
|
+
// toolless BMAD SSE workflow which cannot read files and will fabricate.
|
|
833
|
+
if (this.isRepoGroundedPrompt(prompt) && this.tools) {
|
|
834
|
+
this.operatorMode = true;
|
|
835
|
+
await this.runLocalAgentLoop(prompt);
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
801
838
|
(0, bridge_client_js_1.getBridgeClient)()?.emitPrompt({ prompt, mode: 'operator', model: this.currentModel });
|
|
802
839
|
const runtimeContext = await this.getPromptRuntimeContext(prompt);
|
|
803
840
|
const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({ text: 'Thinking like an operator...', spinner: 'clock' }).start();
|
|
@@ -1096,10 +1133,52 @@ class ChatCommand {
|
|
|
1096
1133
|
const maxTurns = 10;
|
|
1097
1134
|
for (let turn = 0; turn < maxTurns; turn += 1) {
|
|
1098
1135
|
const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({ text: turn === 0 ? 'Planning...' : 'Continuing...', spinner: 'clock' }).start();
|
|
1136
|
+
let response;
|
|
1137
|
+
try {
|
|
1138
|
+
response = await this.api.chat(this.getMessagesForModel(), this.currentModel);
|
|
1139
|
+
}
|
|
1140
|
+
catch (firstErr) {
|
|
1141
|
+
// If we already gathered evidence and the model API fails on a
|
|
1142
|
+
// continuation turn, retry once after a short delay.
|
|
1143
|
+
if (turn > 0 && this.agentToolEvidence.discovery > 0) {
|
|
1144
|
+
this.logger.debug('Agent continuation API call failed, retrying once...');
|
|
1145
|
+
try {
|
|
1146
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
1147
|
+
response = await this.api.chat(this.getMessagesForModel(), this.currentModel);
|
|
1148
|
+
}
|
|
1149
|
+
catch (retryErr) {
|
|
1150
|
+
// Retry also failed — synthesize an answer from evidence
|
|
1151
|
+
if (spinner)
|
|
1152
|
+
spinner.stop();
|
|
1153
|
+
const evidenceSummary = this.synthesizeEvidenceFromHistory();
|
|
1154
|
+
if (evidenceSummary) {
|
|
1155
|
+
const fallbackContent = `[Agent recovered from backend failure — answer synthesized from gathered evidence]\n\n${evidenceSummary}`;
|
|
1156
|
+
if (this.jsonOutput) {
|
|
1157
|
+
console.log(JSON.stringify({
|
|
1158
|
+
success: true,
|
|
1159
|
+
mode: 'agent',
|
|
1160
|
+
model: this.currentModel,
|
|
1161
|
+
partial: true,
|
|
1162
|
+
content: fallbackContent,
|
|
1163
|
+
metadata: { executionPath: 'local-agent-loop', recovered: true },
|
|
1164
|
+
}, null, 2));
|
|
1165
|
+
}
|
|
1166
|
+
else {
|
|
1167
|
+
console.log(fallbackContent);
|
|
1168
|
+
}
|
|
1169
|
+
this.saveSession();
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
throw retryErr;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
else {
|
|
1176
|
+
throw firstErr;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
if (spinner)
|
|
1180
|
+
spinner.stop();
|
|
1099
1181
|
try {
|
|
1100
|
-
const response = await this.api.chat(this.getMessagesForModel(), this.currentModel);
|
|
1101
|
-
if (spinner)
|
|
1102
|
-
spinner.stop();
|
|
1103
1182
|
const assistantMessage = response.message || '';
|
|
1104
1183
|
this.messages.push({ role: 'assistant', content: assistantMessage });
|
|
1105
1184
|
const toolCalls = this.extractToolCalls(assistantMessage);
|
|
@@ -1896,6 +1975,11 @@ class ChatCommand {
|
|
|
1896
1975
|
if (searchFailed > 0) {
|
|
1897
1976
|
evidenceLines.push(`Warning: ${searchFailed} search tool call(s) failed. Do not treat failed searches as evidence that something is missing.`);
|
|
1898
1977
|
}
|
|
1978
|
+
// Cross-file overlap: extract Key* identifiers per file from tool results
|
|
1979
|
+
const crossFileEvidence = this.computeCrossFileKeyEvidence();
|
|
1980
|
+
if (crossFileEvidence) {
|
|
1981
|
+
evidenceLines.push(crossFileEvidence);
|
|
1982
|
+
}
|
|
1899
1983
|
return [
|
|
1900
1984
|
`Tool results received for direct mode step ${this.directToolContinuationCount + 1}.`,
|
|
1901
1985
|
`Original user request: ${this.lastActionableUserInput}`,
|
|
@@ -1912,6 +1996,75 @@ class ChatCommand {
|
|
|
1912
1996
|
'Do not ask follow-up questions or drift into unrelated tasks.',
|
|
1913
1997
|
].join('\n');
|
|
1914
1998
|
}
|
|
1999
|
+
/**
|
|
2000
|
+
* Extract Key* / event-handler identifiers from tool results grouped by
|
|
2001
|
+
* file, then compute which identifiers actually overlap across files.
|
|
2002
|
+
* Returns a formatted hint string, or empty string if not applicable.
|
|
2003
|
+
*/
|
|
2004
|
+
computeCrossFileKeyEvidence() {
|
|
2005
|
+
const fileKeyMap = new Map();
|
|
2006
|
+
// Match standalone Key* codes like KeyA, KeyS, KeyW etc.
|
|
2007
|
+
// Exclude false positives from method names like handleKeyDown, KeyboardEvent
|
|
2008
|
+
const keyPattern = /(?<![a-z])Key[A-Z](?![a-z])/g;
|
|
2009
|
+
let currentFile = '';
|
|
2010
|
+
for (const msg of this.messages) {
|
|
2011
|
+
if (msg.role !== 'system')
|
|
2012
|
+
continue;
|
|
2013
|
+
// Detect which file a tool result is about from "File: xxx" tag
|
|
2014
|
+
const fileTag = msg.content.match(/^Tool (?:read_file|grep) (?:succeeded|FAILED)\.\nFile: (.+)/m);
|
|
2015
|
+
if (fileTag) {
|
|
2016
|
+
currentFile = fileTag[1].trim();
|
|
2017
|
+
}
|
|
2018
|
+
if (!currentFile)
|
|
2019
|
+
continue;
|
|
2020
|
+
// Extract keys from code content, filtering out method name false positives
|
|
2021
|
+
const cleanedContent = msg.content
|
|
2022
|
+
.replace(/handleKeyDown|handleKeyUp|onKeyDown|onKeyUp|_onKeyDown|_onKeyUp|KeyboardEvent|keydown|keyup/gi, '___');
|
|
2023
|
+
const keys = cleanedContent.match(keyPattern);
|
|
2024
|
+
if (keys) {
|
|
2025
|
+
if (!fileKeyMap.has(currentFile)) {
|
|
2026
|
+
fileKeyMap.set(currentFile, new Set());
|
|
2027
|
+
}
|
|
2028
|
+
const keySet = fileKeyMap.get(currentFile);
|
|
2029
|
+
for (const k of keys)
|
|
2030
|
+
keySet.add(k);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
if (fileKeyMap.size < 2)
|
|
2034
|
+
return '';
|
|
2035
|
+
// Compute overlap
|
|
2036
|
+
const allFiles = [...fileKeyMap.keys()];
|
|
2037
|
+
const allKeys = new Set();
|
|
2038
|
+
for (const ks of fileKeyMap.values())
|
|
2039
|
+
for (const k of ks)
|
|
2040
|
+
allKeys.add(k);
|
|
2041
|
+
const overlapping = [];
|
|
2042
|
+
const unique = new Map();
|
|
2043
|
+
for (const key of allKeys) {
|
|
2044
|
+
const filesWithKey = allFiles.filter(f => fileKeyMap.get(f).has(key));
|
|
2045
|
+
if (filesWithKey.length > 1) {
|
|
2046
|
+
overlapping.push(key);
|
|
2047
|
+
}
|
|
2048
|
+
else {
|
|
2049
|
+
const file = filesWithKey[0];
|
|
2050
|
+
if (!unique.has(file))
|
|
2051
|
+
unique.set(file, []);
|
|
2052
|
+
unique.get(file).push(key);
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
const lines = ['MANDATORY CROSS-FILE EVIDENCE (computed from actual tool output — this is ground truth):'];
|
|
2056
|
+
if (overlapping.length > 0) {
|
|
2057
|
+
lines.push(`CONFIRMED CONFLICTING keys (found in MULTIPLE files): ${overlapping.join(', ')}`);
|
|
2058
|
+
}
|
|
2059
|
+
else {
|
|
2060
|
+
lines.push('WARNING: No keys found in multiple files — there may be no actual key conflict.');
|
|
2061
|
+
}
|
|
2062
|
+
for (const [file, keys] of unique) {
|
|
2063
|
+
lines.push(`Keys found ONLY in ${file} (NOT in other files): ${keys.join(', ')}`);
|
|
2064
|
+
}
|
|
2065
|
+
lines.push('CONSTRAINT: Your answer MUST list ONLY the keys from the "CONFIRMED CONFLICTING" line above as conflicting. Keys listed as "ONLY in [file]" MUST NOT be reported as conflicts. This data was computed from the exact tool output and overrides any assumption.');
|
|
2066
|
+
return lines.join('\n');
|
|
2067
|
+
}
|
|
1915
2068
|
extractToolCalls(message) {
|
|
1916
2069
|
const calls = [];
|
|
1917
2070
|
const seen = new Set();
|
|
@@ -1973,6 +2126,30 @@ class ChatCommand {
|
|
|
1973
2126
|
}
|
|
1974
2127
|
return trimmed;
|
|
1975
2128
|
}
|
|
2129
|
+
/**
|
|
2130
|
+
* Synthesize a best-effort answer from tool evidence already collected
|
|
2131
|
+
* in the message history. Used as a fallback when the model API fails
|
|
2132
|
+
* on a continuation turn after evidence was gathered.
|
|
2133
|
+
*/
|
|
2134
|
+
synthesizeEvidenceFromHistory() {
|
|
2135
|
+
const toolOutputs = [];
|
|
2136
|
+
for (const msg of this.messages) {
|
|
2137
|
+
if (msg.role === 'system' && msg.content.includes('Tool results')) {
|
|
2138
|
+
// Collect tool result summaries
|
|
2139
|
+
toolOutputs.push(msg.content);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
if (toolOutputs.length === 0)
|
|
2143
|
+
return '';
|
|
2144
|
+
// Extract file contents and grep results from tool outputs
|
|
2145
|
+
const evidence = ['Evidence gathered before backend failure:\n'];
|
|
2146
|
+
for (const output of toolOutputs) {
|
|
2147
|
+
// Truncate long outputs but keep the key evidence
|
|
2148
|
+
const trimmed = output.length > 3000 ? output.slice(0, 3000) + '\n[...truncated]' : output;
|
|
2149
|
+
evidence.push(trimmed);
|
|
2150
|
+
}
|
|
2151
|
+
return evidence.join('\n---\n');
|
|
2152
|
+
}
|
|
1976
2153
|
resolveDirectModeCompletion(prompt, visibleText) {
|
|
1977
2154
|
const normalized = (visibleText || '').trim();
|
|
1978
2155
|
if (normalized && !this.isDirectModeFollowUpQuestion(normalized)) {
|
|
@@ -2110,6 +2287,10 @@ class ChatCommand {
|
|
|
2110
2287
|
}
|
|
2111
2288
|
formatToolResult(call, result) {
|
|
2112
2289
|
const parts = [`Tool ${call.tool} ${result.success ? 'succeeded' : 'FAILED'}.`];
|
|
2290
|
+
// Include file path for read_file/grep so cross-file evidence can be computed
|
|
2291
|
+
if (call.args.path) {
|
|
2292
|
+
parts.push(`File: ${call.args.path}`);
|
|
2293
|
+
}
|
|
2113
2294
|
// Include search status classification for the agent to reason about
|
|
2114
2295
|
const searchStatus = result.metadata?.searchStatus;
|
|
2115
2296
|
if (searchStatus) {
|
|
@@ -2127,7 +2308,7 @@ class ChatCommand {
|
|
|
2127
2308
|
return parts.join('\n');
|
|
2128
2309
|
}
|
|
2129
2310
|
truncateText(text) {
|
|
2130
|
-
const maxLength =
|
|
2311
|
+
const maxLength = 12000;
|
|
2131
2312
|
if (text.length <= maxLength) {
|
|
2132
2313
|
return text;
|
|
2133
2314
|
}
|
package/dist/index.js
CHANGED
package/dist/utils/api.js
CHANGED
|
@@ -148,6 +148,7 @@ class APIClient {
|
|
|
148
148
|
this.selfHostedModelRouterClient = selfHostedModelsApiUrl ? axios_1.default.create({
|
|
149
149
|
baseURL: selfHostedModelsApiUrl,
|
|
150
150
|
timeout: 240000,
|
|
151
|
+
httpsAgent,
|
|
151
152
|
headers: {
|
|
152
153
|
'Content-Type': 'application/json',
|
|
153
154
|
'User-Agent': `Vigthoria-CLI/${process.env.npm_package_version || '1.6.9'}`,
|
package/dist/utils/tools.js
CHANGED
|
@@ -624,12 +624,20 @@ class AgenticTools {
|
|
|
624
624
|
}
|
|
625
625
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
626
626
|
const lines = content.split('\n');
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
if (
|
|
631
|
-
|
|
632
|
-
|
|
627
|
+
// Clamp start_line: API is 1-based; the model sometimes emits 0 or
|
|
628
|
+
// negative values. Silently clamp to valid range instead of failing.
|
|
629
|
+
let rawStart = args.start_line ? parseInt(args.start_line) : 1;
|
|
630
|
+
if (rawStart < 1)
|
|
631
|
+
rawStart = 1;
|
|
632
|
+
if (rawStart > lines.length)
|
|
633
|
+
rawStart = lines.length;
|
|
634
|
+
const startLine = rawStart - 1; // convert to 0-based
|
|
635
|
+
let rawEnd = args.end_line ? parseInt(args.end_line) : lines.length;
|
|
636
|
+
if (rawEnd < rawStart)
|
|
637
|
+
rawEnd = rawStart;
|
|
638
|
+
if (rawEnd > lines.length)
|
|
639
|
+
rawEnd = lines.length;
|
|
640
|
+
const endLine = rawEnd;
|
|
633
641
|
const selectedLines = lines.slice(startLine, Math.min(endLine, lines.length));
|
|
634
642
|
return {
|
|
635
643
|
success: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigthoria-cli",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.44",
|
|
4
4
|
"description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -86,4 +86,4 @@
|
|
|
86
86
|
"engines": {
|
|
87
87
|
"node": ">=18.0.0"
|
|
88
88
|
}
|
|
89
|
-
}
|
|
89
|
+
}
|