vigthoria-cli 1.6.15 → 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.
@@ -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;
@@ -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 || '1200000';
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 : 1200000;
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 'Planning... gathering project context';
236
+ return 'Reading project files';
234
237
  }
235
238
  if (/write|edit|patch|create|delete|replace|rename/.test(normalized)) {
236
- return 'Applying changes...';
239
+ return 'Writing changes';
237
240
  }
238
241
  if (/test|lint|build|run|exec|terminal/.test(normalized)) {
239
- return 'Validating changes...';
242
+ return 'Running verification';
240
243
  }
241
- return 'Working...';
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
- spinner.text = this.describeV3AgentTool(event.tool || event.name || event.tool_name);
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
- spinner.text = 'Writing response...';
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
- spinner.text = 'Finishing...';
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 === 'plan' || event.type === 'analysis' || event.type === 'thinking') {
260
- spinner.text = 'Planning...';
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',
@@ -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[];
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 || '1200000';
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 : 1200000;
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 = [
@@ -2234,6 +2240,19 @@ document.addEventListener('DOMContentLoaded', () => {
2234
2240
  }
2235
2241
  }
2236
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
+ }
2237
2256
  if (this.hasAgentWorkspaceOutput(context)) {
2238
2257
  return {
2239
2258
  task_id: events.find((entry) => entry && entry.task_id)?.task_id || null,
@@ -2312,6 +2331,66 @@ document.addEventListener('DOMContentLoaded', () => {
2312
2331
  throw new Error(`V3 agent ${response.status}: ${errorText.slice(0, 200)}`);
2313
2332
  }
2314
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
+ }
2315
2394
  const contextId = data.context_id || response.headers.get('x-context-id') || requestExecutionContext.contextId || null;
2316
2395
  const mcpContextId = response.headers.get('x-mcp-context-id') || requestExecutionContext.mcpContextId || null;
2317
2396
  this.recoverAgentWorkspaceFiles(executionContext, data.files || {}, expectedFiles);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigthoria-cli",
3
- "version": "1.6.15",
3
+ "version": "1.6.16",
4
4
  "description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
5
5
  "main": "dist/index.js",
6
6
  "files": [