vigthoria-cli 1.6.14 → 1.6.16
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.d.ts +3 -0
- package/dist/commands/chat.js +65 -11
- package/dist/utils/api.d.ts +2 -1
- package/dist/utils/api.js +102 -6
- package/package.json +1 -1
package/dist/commands/chat.d.ts
CHANGED
|
@@ -50,6 +50,9 @@ export declare class ChatCommand {
|
|
|
50
50
|
private buildTaskShapingInstructions;
|
|
51
51
|
private buildExecutionPrompt;
|
|
52
52
|
private getPromptRuntimeContext;
|
|
53
|
+
private v3IterationCount;
|
|
54
|
+
private v3ToolCallCount;
|
|
55
|
+
private v3LastActivity;
|
|
53
56
|
private describeV3AgentTool;
|
|
54
57
|
private updateV3AgentSpinner;
|
|
55
58
|
private updateOperatorSpinner;
|
package/dist/commands/chat.js
CHANGED
|
@@ -47,9 +47,9 @@ const api_js_1 = require("../utils/api.js");
|
|
|
47
47
|
const tools_js_1 = require("../utils/tools.js");
|
|
48
48
|
const session_js_1 = require("../utils/session.js");
|
|
49
49
|
const DEFAULT_V3_AGENT_TIMEOUT_MS = (() => {
|
|
50
|
-
const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS || '
|
|
50
|
+
const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS || '3900000';
|
|
51
51
|
const parsed = Number.parseInt(rawValue, 10);
|
|
52
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed :
|
|
52
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 3900000;
|
|
53
53
|
})();
|
|
54
54
|
class ChatCommand {
|
|
55
55
|
config;
|
|
@@ -227,37 +227,87 @@ class ChatCommand {
|
|
|
227
227
|
devtoolsBridgeEndpoint: bridgeStatus.endpoint,
|
|
228
228
|
};
|
|
229
229
|
}
|
|
230
|
+
v3IterationCount = 0;
|
|
231
|
+
v3ToolCallCount = 0;
|
|
232
|
+
v3LastActivity = Date.now();
|
|
230
233
|
describeV3AgentTool(toolName) {
|
|
231
234
|
const normalized = String(toolName || '').toLowerCase();
|
|
232
235
|
if (/read|grep|search|list|find|glob/.test(normalized)) {
|
|
233
|
-
return '
|
|
236
|
+
return 'Reading project files';
|
|
234
237
|
}
|
|
235
238
|
if (/write|edit|patch|create|delete|replace|rename/.test(normalized)) {
|
|
236
|
-
return '
|
|
239
|
+
return 'Writing changes';
|
|
237
240
|
}
|
|
238
241
|
if (/test|lint|build|run|exec|terminal/.test(normalized)) {
|
|
239
|
-
return '
|
|
242
|
+
return 'Running verification';
|
|
240
243
|
}
|
|
241
|
-
|
|
244
|
+
if (/hyperloop/.test(normalized)) {
|
|
245
|
+
return 'Hyperloop processing';
|
|
246
|
+
}
|
|
247
|
+
return 'Working';
|
|
242
248
|
}
|
|
243
249
|
updateV3AgentSpinner(spinner, event) {
|
|
244
250
|
if (!event || typeof event !== 'object') {
|
|
245
251
|
return;
|
|
246
252
|
}
|
|
253
|
+
this.v3LastActivity = Date.now();
|
|
247
254
|
if (event.type === 'tool_call') {
|
|
248
|
-
|
|
255
|
+
this.v3ToolCallCount += 1;
|
|
256
|
+
const toolDesc = this.describeV3AgentTool(event.tool || event.name || event.tool_name);
|
|
257
|
+
const toolTarget = event.arguments?.path || event.arguments?.file_path || event.arguments?.pattern || '';
|
|
258
|
+
const shortTarget = toolTarget ? ` → ${String(toolTarget).split('/').slice(-2).join('/')}` : '';
|
|
259
|
+
spinner.text = chalk_1.default.cyan(`[${this.v3IterationCount}/${this.v3ToolCallCount}] `) + `${toolDesc}${shortTarget}`;
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (event.type === 'tool_result') {
|
|
263
|
+
const success = event.success !== false;
|
|
264
|
+
const toolName = event.name || event.tool || '';
|
|
265
|
+
const indicator = success ? chalk_1.default.green('✓') : chalk_1.default.red('✗');
|
|
266
|
+
spinner.text = `${indicator} ${toolName} complete — next step...`;
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (event.type === 'thinking') {
|
|
270
|
+
this.v3IterationCount += 1;
|
|
271
|
+
const iterText = event.content || '';
|
|
272
|
+
const iterMatch = iterText.match(/Iteration (\d+)/i);
|
|
273
|
+
const iterNum = iterMatch ? iterMatch[1] : String(this.v3IterationCount);
|
|
274
|
+
spinner.text = chalk_1.default.cyan(`[Iteration ${iterNum}] `) + 'Analyzing...';
|
|
249
275
|
return;
|
|
250
276
|
}
|
|
251
277
|
if (event.type === 'message') {
|
|
252
|
-
|
|
278
|
+
const preview = String(event.content || '').slice(0, 80).replace(/\n/g, ' ');
|
|
279
|
+
spinner.text = chalk_1.default.cyan('[Response] ') + (preview || 'Writing response...');
|
|
253
280
|
return;
|
|
254
281
|
}
|
|
255
282
|
if (event.type === 'complete') {
|
|
256
|
-
|
|
283
|
+
const elapsed = event.elapsed || '';
|
|
284
|
+
const iters = event.iterations || this.v3IterationCount;
|
|
285
|
+
const tools = event.tool_calls || this.v3ToolCallCount;
|
|
286
|
+
spinner.text = chalk_1.default.green('✓ ') + `Complete — ${iters} iterations, ${tools} tool calls${elapsed ? `, ${elapsed}` : ''}`;
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (event.type === 'plan') {
|
|
290
|
+
const planKind = event.plan?.task_kind || event.task_kind || '';
|
|
291
|
+
spinner.text = chalk_1.default.cyan('[Plan] ') + `Task: ${planKind || 'analyzing'}...`;
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (event.type === 'error') {
|
|
295
|
+
if (event.checkpointed) {
|
|
296
|
+
spinner.text = chalk_1.default.yellow('[Checkpoint] ') + 'Budget reached — auto-continuing...';
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
spinner.text = chalk_1.default.red('[Error] ') + (event.message || 'Agent error');
|
|
300
|
+
}
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (event.type === 'context') {
|
|
304
|
+
spinner.text = chalk_1.default.cyan('[Context] ') + 'Workspace bound...';
|
|
257
305
|
return;
|
|
258
306
|
}
|
|
259
|
-
if (event.type === '
|
|
260
|
-
|
|
307
|
+
if (event.type === 'start') {
|
|
308
|
+
this.v3IterationCount = 0;
|
|
309
|
+
this.v3ToolCallCount = 0;
|
|
310
|
+
spinner.text = chalk_1.default.cyan('[Start] ') + 'Agent initialized...';
|
|
261
311
|
}
|
|
262
312
|
}
|
|
263
313
|
updateOperatorSpinner(spinner, event) {
|
|
@@ -856,6 +906,10 @@ class ChatCommand {
|
|
|
856
906
|
const runtimeContext = await this.getPromptRuntimeContext(prompt);
|
|
857
907
|
const routingPolicy = this.resolveAgentExecutionPolicy(prompt);
|
|
858
908
|
const rescueEligible = this.isSaaSRescuePrompt(prompt);
|
|
909
|
+
// Reset streaming counters for new workflow
|
|
910
|
+
this.v3IterationCount = 0;
|
|
911
|
+
this.v3ToolCallCount = 0;
|
|
912
|
+
this.v3LastActivity = Date.now();
|
|
859
913
|
const spinner = this.jsonOutput ? null : (0, ora_1.default)({
|
|
860
914
|
text: routingPolicy.cloudSelected ? 'Routing heavy task to Vigthoria Cloud...' : 'Routing to V3 Agent...',
|
|
861
915
|
spinner: 'clock',
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -188,6 +188,7 @@ export declare class APIClient {
|
|
|
188
188
|
private getAccessToken;
|
|
189
189
|
getV3AgentBaseUrls(preferLocal?: boolean): string[];
|
|
190
190
|
getV3AgentRunUrl(baseUrl: string): string;
|
|
191
|
+
getV3AgentContinueUrl(baseUrl: string): string;
|
|
191
192
|
getOperatorBaseUrls(): string[];
|
|
192
193
|
getOperatorStreamUrl(baseUrl: string): string;
|
|
193
194
|
getMcpBaseUrls(): string[];
|
|
@@ -244,7 +245,7 @@ export declare class APIClient {
|
|
|
244
245
|
};
|
|
245
246
|
waitForAgentWorkspaceSettle(context?: Record<string, any>, options?: Record<string, any>): Promise<void>;
|
|
246
247
|
extractExpectedWorkspaceFiles(message?: string, context?: Record<string, any>): string[];
|
|
247
|
-
captureV3AgentStreamMutation(event: any, streamedFiles: Record<string, string
|
|
248
|
+
captureV3AgentStreamMutation(event: any, streamedFiles: Record<string, string>, serverRoot?: string | null): void;
|
|
248
249
|
recoverAgentWorkspaceFiles(context?: Record<string, any>, streamedFiles?: Record<string, string>, expectedFiles?: string[]): void;
|
|
249
250
|
normalizeAgentWorkspaceRelativePath(rawPath: string, rootPath?: string): string;
|
|
250
251
|
ensureAgentFrontendPolish(message?: string, context?: Record<string, any>): Promise<void>;
|
package/dist/utils/api.js
CHANGED
|
@@ -26,9 +26,9 @@ const DEFAULT_V3_AGENT_IDLE_TIMEOUT_MS = (() => {
|
|
|
26
26
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : 90000;
|
|
27
27
|
})();
|
|
28
28
|
const DEFAULT_OPERATOR_TIMEOUT_MS = (() => {
|
|
29
|
-
const rawValue = process.env.VIGTHORIA_OPERATOR_TIMEOUT_MS || process.env.OPERATOR_TIMEOUT_MS || '
|
|
29
|
+
const rawValue = process.env.VIGTHORIA_OPERATOR_TIMEOUT_MS || process.env.OPERATOR_TIMEOUT_MS || '3900000';
|
|
30
30
|
const parsed = Number.parseInt(rawValue, 10);
|
|
31
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed :
|
|
31
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 3900000;
|
|
32
32
|
})();
|
|
33
33
|
class APIClient {
|
|
34
34
|
client;
|
|
@@ -276,6 +276,12 @@ class APIClient {
|
|
|
276
276
|
}
|
|
277
277
|
return `${baseUrl}/api/v3-agent/run`;
|
|
278
278
|
}
|
|
279
|
+
getV3AgentContinueUrl(baseUrl) {
|
|
280
|
+
if (/127\.0\.0\.1:8030|localhost:8030/.test(baseUrl)) {
|
|
281
|
+
return `${baseUrl}/api/agent/continue`;
|
|
282
|
+
}
|
|
283
|
+
return `${baseUrl}/api/v3-agent/continue`;
|
|
284
|
+
}
|
|
279
285
|
getOperatorBaseUrls() {
|
|
280
286
|
const configuredModelsApiUrl = String(this.config.get('modelsApiUrl') || 'https://api.vigthoria.io').replace(/\/$/, '');
|
|
281
287
|
const urls = [
|
|
@@ -1684,13 +1690,13 @@ menu {
|
|
|
1684
1690
|
addMatches(context.agentPrompt);
|
|
1685
1691
|
return Array.from(candidates);
|
|
1686
1692
|
}
|
|
1687
|
-
captureV3AgentStreamMutation(event, streamedFiles) {
|
|
1693
|
+
captureV3AgentStreamMutation(event, streamedFiles, serverRoot) {
|
|
1688
1694
|
if (!event || event.type !== 'tool_call' || !streamedFiles) {
|
|
1689
1695
|
return;
|
|
1690
1696
|
}
|
|
1691
1697
|
const args = event.arguments || {};
|
|
1692
1698
|
if ((event.name === 'write_file' || event.name === 'edit_file') && typeof args.path === 'string') {
|
|
1693
|
-
const filePath = this.normalizeAgentWorkspaceRelativePath(args.path);
|
|
1699
|
+
const filePath = this.normalizeAgentWorkspaceRelativePath(args.path, serverRoot || undefined);
|
|
1694
1700
|
if (!filePath) {
|
|
1695
1701
|
return;
|
|
1696
1702
|
}
|
|
@@ -1708,9 +1714,21 @@ menu {
|
|
|
1708
1714
|
}
|
|
1709
1715
|
recoverAgentWorkspaceFiles(context = {}, streamedFiles = {}, expectedFiles = []) {
|
|
1710
1716
|
const rootPath = this.resolveAgentTargetPath(context);
|
|
1711
|
-
if (!rootPath ||
|
|
1717
|
+
if (!rootPath || Object.keys(streamedFiles).length === 0) {
|
|
1712
1718
|
return;
|
|
1713
1719
|
}
|
|
1720
|
+
// Create the local workspace directory if it doesn't exist yet.
|
|
1721
|
+
// This is needed for remote CLI clients where the user specified a
|
|
1722
|
+
// path (e.g., C:\vigthoria\Apps\pacman_rogue) that may not have
|
|
1723
|
+
// been created before the V3 run.
|
|
1724
|
+
if (!fs_1.default.existsSync(rootPath)) {
|
|
1725
|
+
try {
|
|
1726
|
+
fs_1.default.mkdirSync(rootPath, { recursive: true });
|
|
1727
|
+
}
|
|
1728
|
+
catch {
|
|
1729
|
+
return;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1714
1732
|
const targets = expectedFiles.length > 0 ? expectedFiles : Object.keys(streamedFiles);
|
|
1715
1733
|
for (const targetPath of targets) {
|
|
1716
1734
|
const relativePath = this.normalizeAgentWorkspaceRelativePath(targetPath, rootPath);
|
|
@@ -2142,6 +2160,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2142
2160
|
const events = [];
|
|
2143
2161
|
let final = null;
|
|
2144
2162
|
let contextId = response.headers.get('x-context-id') || String(context.contextId || '').trim() || null;
|
|
2163
|
+
let serverWorkspaceRoot = null;
|
|
2145
2164
|
const streamedFiles = {};
|
|
2146
2165
|
const idleTimeoutMs = context.agentIdleTimeoutMs || DEFAULT_V3_AGENT_IDLE_TIMEOUT_MS;
|
|
2147
2166
|
while (true) {
|
|
@@ -2208,7 +2227,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2208
2227
|
if (!contextId && typeof event.context_id === 'string' && event.context_id.trim()) {
|
|
2209
2228
|
contextId = event.context_id.trim();
|
|
2210
2229
|
}
|
|
2211
|
-
|
|
2230
|
+
if (!serverWorkspaceRoot && event.type === 'context' && typeof event.workspace_root === 'string' && event.workspace_root.trim()) {
|
|
2231
|
+
serverWorkspaceRoot = event.workspace_root.trim();
|
|
2232
|
+
}
|
|
2233
|
+
this.captureV3AgentStreamMutation(event, streamedFiles, serverWorkspaceRoot);
|
|
2212
2234
|
if (typeof context.onStreamEvent === 'function') {
|
|
2213
2235
|
try {
|
|
2214
2236
|
context.onStreamEvent(event);
|
|
@@ -2218,6 +2240,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2218
2240
|
}
|
|
2219
2241
|
}
|
|
2220
2242
|
if (event.type === 'error') {
|
|
2243
|
+
if (event.checkpointed && event.task_id) {
|
|
2244
|
+
// Agent checkpointed — return data so caller can auto-continue
|
|
2245
|
+
return {
|
|
2246
|
+
task_id: event.task_id,
|
|
2247
|
+
context_id: contextId,
|
|
2248
|
+
result: final || event,
|
|
2249
|
+
events,
|
|
2250
|
+
files: streamedFiles,
|
|
2251
|
+
partial: true,
|
|
2252
|
+
checkpointed: true,
|
|
2253
|
+
checkpointed_task_id: event.task_id,
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2221
2256
|
if (this.hasAgentWorkspaceOutput(context)) {
|
|
2222
2257
|
return {
|
|
2223
2258
|
task_id: events.find((entry) => entry && entry.task_id)?.task_id || null,
|
|
@@ -2241,6 +2276,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2241
2276
|
result: final,
|
|
2242
2277
|
events,
|
|
2243
2278
|
files: streamedFiles,
|
|
2279
|
+
serverWorkspaceRoot: serverWorkspaceRoot || null,
|
|
2244
2280
|
};
|
|
2245
2281
|
}
|
|
2246
2282
|
async runV3AgentWorkflow(message, context = {}) {
|
|
@@ -2295,6 +2331,66 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2295
2331
|
throw new Error(`V3 agent ${response.status}: ${errorText.slice(0, 200)}`);
|
|
2296
2332
|
}
|
|
2297
2333
|
const data = await this.collectV3AgentStream(response, requestExecutionContext);
|
|
2334
|
+
// Auto-continuation: if the agent checkpointed (budget exceeded), continue automatically
|
|
2335
|
+
if (data.checkpointed && data.checkpointed_task_id) {
|
|
2336
|
+
const maxContinuations = 10;
|
|
2337
|
+
let continuationData = data;
|
|
2338
|
+
let continuations = 0;
|
|
2339
|
+
while (continuationData.checkpointed && continuationData.checkpointed_task_id && continuations < maxContinuations) {
|
|
2340
|
+
continuations++;
|
|
2341
|
+
if (typeof requestExecutionContext.onStreamEvent === 'function') {
|
|
2342
|
+
try {
|
|
2343
|
+
requestExecutionContext.onStreamEvent({
|
|
2344
|
+
type: 'message',
|
|
2345
|
+
content: `Auto-continuing task (phase ${continuations + 1})...`,
|
|
2346
|
+
});
|
|
2347
|
+
}
|
|
2348
|
+
catch { /* ignore */ }
|
|
2349
|
+
}
|
|
2350
|
+
const continueBody = {
|
|
2351
|
+
task_id: continuationData.checkpointed_task_id,
|
|
2352
|
+
context: requestBody.context,
|
|
2353
|
+
context_id: requestBody.context_id,
|
|
2354
|
+
mcp_context_id: requestBody.mcp_context_id,
|
|
2355
|
+
stream: true,
|
|
2356
|
+
};
|
|
2357
|
+
const continueController = new AbortController();
|
|
2358
|
+
const continueTimeoutId = setTimeout(() => continueController.abort(), timeoutMs);
|
|
2359
|
+
try {
|
|
2360
|
+
const continueHeaders = await this.getV3AgentHeaders();
|
|
2361
|
+
const continueResponse = await fetch(this.getV3AgentContinueUrl(baseUrl), {
|
|
2362
|
+
method: 'POST',
|
|
2363
|
+
headers: { ...continueHeaders, 'Content-Type': 'application/json' },
|
|
2364
|
+
body: JSON.stringify(continueBody),
|
|
2365
|
+
signal: continueController.signal,
|
|
2366
|
+
});
|
|
2367
|
+
if (!continueResponse.ok) {
|
|
2368
|
+
break; // Fall through to normal completion with partial data
|
|
2369
|
+
}
|
|
2370
|
+
continuationData = await this.collectV3AgentStream(continueResponse, requestExecutionContext);
|
|
2371
|
+
}
|
|
2372
|
+
catch {
|
|
2373
|
+
break; // Fall through to normal completion with partial data
|
|
2374
|
+
}
|
|
2375
|
+
finally {
|
|
2376
|
+
clearTimeout(continueTimeoutId);
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
// Use the final continuation data for workspace recovery
|
|
2380
|
+
this.recoverAgentWorkspaceFiles(executionContext, continuationData.files || {}, expectedFiles);
|
|
2381
|
+
await this.waitForAgentWorkspaceSettle(executionContext, { expectedFiles });
|
|
2382
|
+
await this.ensureAgentFrontendPolish(message, executionContext);
|
|
2383
|
+
const previewGate = await this.runTemplateServicePreviewGate(message, executionContext);
|
|
2384
|
+
const finalContextId = continuationData.context_id || data.context_id || response.headers.get('x-context-id') || requestExecutionContext.contextId || null;
|
|
2385
|
+
return {
|
|
2386
|
+
content: this.formatV3AgentResponse(continuationData) || this.formatV3AgentResponse(data),
|
|
2387
|
+
taskId: continuationData.task_id || data.task_id || null,
|
|
2388
|
+
contextId: finalContextId,
|
|
2389
|
+
backendUrl: baseUrl,
|
|
2390
|
+
partial: continuationData.checkpointed === true,
|
|
2391
|
+
metadata: { source: 'v3-agent', mode: 'agent', contextId: finalContextId, continuations, previewGate },
|
|
2392
|
+
};
|
|
2393
|
+
}
|
|
2298
2394
|
const contextId = data.context_id || response.headers.get('x-context-id') || requestExecutionContext.contextId || null;
|
|
2299
2395
|
const mcpContextId = response.headers.get('x-mcp-context-id') || requestExecutionContext.mcpContextId || null;
|
|
2300
2396
|
this.recoverAgentWorkspaceFiles(executionContext, data.files || {}, expectedFiles);
|