vigthoria-cli 1.9.19 → 1.9.20

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.
@@ -40,6 +40,7 @@ export declare class ChatCommand {
40
40
  private savePlanToVigFlow;
41
41
  private jsonOutput;
42
42
  private modelGovernanceFallback;
43
+ private lastAgentRunOutcome;
43
44
  private isJwtExpirationError;
44
45
  private isNetworkError;
45
46
  private isTimeoutError;
@@ -140,6 +141,29 @@ export declare class ChatCommand {
140
141
  private tryRecoverV3ServiceAndRetry;
141
142
  private startInteractiveChat;
142
143
  private showHelp;
144
+ /**
145
+ * Print a clear, opinionated end-of-run summary after every agent workflow.
146
+ *
147
+ * Goals:
148
+ * - User can answer "Did it succeed?" in one glance.
149
+ * - User can answer "What do I type next?" without reading 200 scrollback lines.
150
+ * - Never leave the spinners (`⟳`, `–`) ambiguous when the prompt returns.
151
+ */
152
+ private printAgentRunSummary;
153
+ /**
154
+ * Build the prompt sent to the agent when the user types `/retry`.
155
+ * Resumes only the failed/unfinished tasks from the previous run.
156
+ */
157
+ private buildRetryPrompt;
158
+ /**
159
+ * Build the prompt sent to the agent when the user types `/continue`.
160
+ * Tells the agent to keep working from the current workspace state.
161
+ */
162
+ private buildContinuePrompt;
163
+ /**
164
+ * Re-print the last agent run summary, or guide the user when there isn't one.
165
+ */
166
+ private showAgentRunStatus;
143
167
  private showContext;
144
168
  private showProjectMemory;
145
169
  private compactCurrentSession;
@@ -59,6 +59,8 @@ export class ChatCommand {
59
59
  savePlanToVigFlow = false;
60
60
  jsonOutput = false;
61
61
  modelGovernanceFallback = null;
62
+ // Last completed Agent run — used by /retry, /continue, and the final summary block.
63
+ lastAgentRunOutcome = null;
62
64
  isJwtExpirationError(error) {
63
65
  const candidate = error;
64
66
  const message = `${candidate?.message || ''} ${typeof candidate?.details === 'string' ? candidate.details : ''}`.toLowerCase();
@@ -1934,6 +1936,60 @@ export class ChatCommand {
1934
1936
  text: routingPolicy.cloudSelected ? 'Routing heavy task to Vigthoria Cloud...' : 'Routing to V3 Agent...',
1935
1937
  spinner: 'clock',
1936
1938
  }).start();
1939
+ // Live run telemetry, used both for the final summary block and for /retry, /continue.
1940
+ const liveOutcome = {
1941
+ tasksSucceeded: 0,
1942
+ tasksTotal: 0,
1943
+ failedTaskIds: new Set(),
1944
+ unfinishedTaskIds: new Set(),
1945
+ qualityScore: null,
1946
+ qualityMissing: [],
1947
+ qualityBlockers: [],
1948
+ plannerError: null,
1949
+ executorError: null,
1950
+ executorFailed: false,
1951
+ };
1952
+ const parsePlannerSummary = (raw) => {
1953
+ if (!raw || typeof raw !== 'string')
1954
+ return;
1955
+ const succ = raw.match(/(\d+)\s*\/\s*(\d+)\s+tasks?\s+succeeded/i);
1956
+ if (succ) {
1957
+ liveOutcome.tasksSucceeded = Number(succ[1]) || 0;
1958
+ liveOutcome.tasksTotal = Number(succ[2]) || 0;
1959
+ }
1960
+ const failed = raw.match(/Failed\s+tasks?:\s*([^.\n]+)/i);
1961
+ if (failed) {
1962
+ failed[1].split(/[,\s]+/).map(s => s.trim()).filter(Boolean)
1963
+ .forEach(t => liveOutcome.failedTaskIds.add(t));
1964
+ }
1965
+ const unfinished = raw.match(/Unfinished\s+tasks?:\s*([^.\n]+)/i);
1966
+ if (unfinished) {
1967
+ unfinished[1].split(/[,\s]+/).map(s => s.trim()).filter(Boolean)
1968
+ .forEach(t => liveOutcome.unfinishedTaskIds.add(t));
1969
+ }
1970
+ const qScore = raw.match(/Quality\s+audit:\s*([0-9.]+)\s*\/\s*100/i);
1971
+ if (qScore) {
1972
+ const n = Number(qScore[1]);
1973
+ if (Number.isFinite(n))
1974
+ liveOutcome.qualityScore = n;
1975
+ }
1976
+ const blockers = raw.match(/Quality\s+blockers?:\s*([^\n]+?)(?:\s+Quality\s+audit|$)/i);
1977
+ if (blockers) {
1978
+ blockers[1].split(/;/).map(s => s.trim()).filter(Boolean)
1979
+ .forEach(b => {
1980
+ if (!liveOutcome.qualityBlockers.includes(b))
1981
+ liveOutcome.qualityBlockers.push(b);
1982
+ });
1983
+ }
1984
+ const missingFeatures = raw.match(/Missing\s+features?:\s*([^\n]+)/i);
1985
+ if (missingFeatures) {
1986
+ missingFeatures[1].split(/[,;]/).map(s => s.trim()).filter(Boolean)
1987
+ .forEach(m => {
1988
+ if (!liveOutcome.qualityMissing.includes(m))
1989
+ liveOutcome.qualityMissing.push(m);
1990
+ });
1991
+ }
1992
+ };
1937
1993
  const executionPrompt = this.buildExecutionPrompt(contextualPrompt);
1938
1994
  const agentTaskType = this.inferAgentTaskType(contextualPrompt);
1939
1995
  const workspaceContext = {
@@ -1976,10 +2032,45 @@ export class ChatCommand {
1976
2032
  if (event.type === 'plan') {
1977
2033
  taskDisplay.complete(0);
1978
2034
  taskDisplay.start(1);
2035
+ const tasks = event?.plan?.tasks;
2036
+ if (Array.isArray(tasks))
2037
+ liveOutcome.tasksTotal = tasks.length;
1979
2038
  }
1980
2039
  else if (event.type === 'executor_start') {
1981
2040
  taskDisplay.start(1);
1982
2041
  }
2042
+ else if (event.type === 'executor_complete') {
2043
+ const summary = event.summary || {};
2044
+ const tid = summary.task_id || summary.id;
2045
+ if (summary.status === 'failed') {
2046
+ if (tid)
2047
+ liveOutcome.failedTaskIds.add(String(tid));
2048
+ liveOutcome.executorFailed = true;
2049
+ }
2050
+ else if (summary.status === 'completed' || summary.status === 'success') {
2051
+ if (tid)
2052
+ liveOutcome.failedTaskIds.delete(String(tid));
2053
+ liveOutcome.tasksSucceeded += 1;
2054
+ }
2055
+ }
2056
+ else if (event.type === 'executor_error') {
2057
+ const msg = typeof event.error === 'string' ? event.error : '';
2058
+ if (msg)
2059
+ liveOutcome.executorError = msg;
2060
+ }
2061
+ else if (event.type === 'error') {
2062
+ const msg = typeof event.message === 'string' ? event.message : '';
2063
+ if (/plan|planner|dependency graph/i.test(msg)) {
2064
+ if (!liveOutcome.plannerError)
2065
+ liveOutcome.plannerError = msg;
2066
+ parsePlannerSummary(msg);
2067
+ }
2068
+ else if (/executor|task failed|iteration/i.test(msg)) {
2069
+ if (!liveOutcome.executorError)
2070
+ liveOutcome.executorError = msg;
2071
+ parsePlannerSummary(msg);
2072
+ }
2073
+ }
1983
2074
  else if (event.type === 'complete') {
1984
2075
  taskDisplay.complete(1);
1985
2076
  }
@@ -2087,8 +2178,26 @@ export class ChatCommand {
2087
2178
  console.log(chalk.gray(`Run ${chalk.cyan('vigthoria preview --diff')} for full visual diffs.`));
2088
2179
  }
2089
2180
  }
2181
+ // Resolve the Execute-tasks spinner: only mark it ✓ when the run actually
2182
+ // produced real, validated output. Otherwise the user just saw a wall of
2183
+ // executor errors and the spinner needs to clearly say "failed", not "✓".
2184
+ let selfHealStatus = null;
2185
+ let selfHealTool = null;
2186
+ const executorSucceeded = !liveOutcome.executorFailed
2187
+ && !liveOutcome.plannerError
2188
+ && !liveOutcome.executorError
2189
+ && workspaceHasOutput;
2190
+ if (executorSucceeded) {
2191
+ taskDisplay.complete(1);
2192
+ }
2193
+ else {
2194
+ const failDetail = liveOutcome.failedTaskIds.size > 0
2195
+ ? `failed: ${[...liveOutcome.failedTaskIds].slice(0, 4).join(', ')}`
2196
+ : (liveOutcome.executorError ? 'executor error' : (liveOutcome.plannerError ? 'planner error' : 'incomplete'));
2197
+ taskDisplay.fail(1, failDetail);
2198
+ }
2090
2199
  // ── Self-healing validation ──────────────────────────────────────
2091
- if (this.currentProjectPath && !this.jsonOutput && success) {
2200
+ if (this.currentProjectPath && !this.jsonOutput && success && executorSucceeded) {
2092
2201
  try {
2093
2202
  taskDisplay.start(2, 'validating...');
2094
2203
  const healResult = await this.api.runSelfHealingCycle(executionPrompt, this.currentProjectPath, workspaceContext);
@@ -2096,10 +2205,13 @@ export class ChatCommand {
2096
2205
  taskDisplay.complete(2);
2097
2206
  if (healResult.passed) {
2098
2207
  taskDisplay.complete(3);
2208
+ selfHealStatus = 'passed';
2099
2209
  }
2100
2210
  else {
2101
2211
  taskDisplay.fail(3, healResult.tool);
2212
+ selfHealStatus = 'partial';
2102
2213
  }
2214
+ selfHealTool = healResult.tool || null;
2103
2215
  if (!this.directPromptMode) {
2104
2216
  const hs = healResult.passed ? chalk.green('passed') : chalk.yellow('partial');
2105
2217
  console.log(chalk.gray(`Self-healing: ${hs} (${healResult.tool})`));
@@ -2108,20 +2220,45 @@ export class ChatCommand {
2108
2220
  else {
2109
2221
  taskDisplay.skip(2);
2110
2222
  taskDisplay.skip(3);
2223
+ selfHealStatus = 'skipped';
2111
2224
  }
2112
2225
  }
2113
2226
  catch (error) {
2114
2227
  this.logger.debug(`Self-healing validation failed: ${error instanceof Error ? error.message : String(error)}`);
2115
2228
  taskDisplay.skip(2);
2116
2229
  taskDisplay.skip(3);
2230
+ selfHealStatus = 'failed';
2117
2231
  }
2118
2232
  }
2119
2233
  else {
2120
2234
  taskDisplay.skip(2);
2121
2235
  taskDisplay.skip(3);
2236
+ selfHealStatus = 'skipped';
2122
2237
  }
2123
2238
  taskDisplay.finalize();
2124
2239
  // ────────────────────────────────────────────────────────────────
2240
+ this.lastAgentRunOutcome = {
2241
+ prompt,
2242
+ taskId: response.taskId || null,
2243
+ contextId: response.contextId || null,
2244
+ tasksSucceeded: liveOutcome.tasksSucceeded,
2245
+ tasksTotal: liveOutcome.tasksTotal,
2246
+ failedTaskIds: [...liveOutcome.failedTaskIds],
2247
+ unfinishedTaskIds: [...liveOutcome.unfinishedTaskIds],
2248
+ qualityScore: liveOutcome.qualityScore,
2249
+ qualityMissing: liveOutcome.qualityMissing,
2250
+ qualityBlockers: liveOutcome.qualityBlockers,
2251
+ hasOutput: workspaceHasOutput,
2252
+ selfHealStatus,
2253
+ selfHealTool,
2254
+ plannerError: liveOutcome.plannerError ? sanitizeUserFacingErrorText(liveOutcome.plannerError) : null,
2255
+ executorError: liveOutcome.executorError ? sanitizeUserFacingErrorText(liveOutcome.executorError) : null,
2256
+ finishedAt: Date.now(),
2257
+ };
2258
+ if (!this.jsonOutput && !this.directPromptMode) {
2259
+ const changedFileCount = response.changedFiles ? Object.keys(response.changedFiles).length : 0;
2260
+ this.printAgentRunSummary(this.lastAgentRunOutcome, executorSucceeded, changedFileCount);
2261
+ }
2125
2262
  this.messages.push({ role: 'assistant', content: response.content || 'V3 agent workflow completed.' });
2126
2263
  watcher?.stop();
2127
2264
  return true;
@@ -2151,6 +2288,33 @@ export class ChatCommand {
2151
2288
  : 'Agent mode is unavailable right now. Please retry shortly or run vigthoria login if the issue persists.';
2152
2289
  this.logger.error(errorMessage);
2153
2290
  this.messages.push({ role: 'assistant', content: errorMessage });
2291
+ // Resolve any half-rendered TaskDisplay spinners before the prompt
2292
+ // comes back, otherwise the user sees `⟳ Execute tasks` next to `>`.
2293
+ try {
2294
+ taskDisplay.fail(1, 'agent unavailable');
2295
+ taskDisplay.skip(2);
2296
+ taskDisplay.skip(3);
2297
+ taskDisplay.finalize();
2298
+ }
2299
+ catch (_) { /* render is best-effort */ }
2300
+ this.lastAgentRunOutcome = {
2301
+ prompt,
2302
+ taskId: null,
2303
+ contextId: null,
2304
+ tasksSucceeded: liveOutcome.tasksSucceeded,
2305
+ tasksTotal: liveOutcome.tasksTotal,
2306
+ failedTaskIds: [...liveOutcome.failedTaskIds],
2307
+ unfinishedTaskIds: [...liveOutcome.unfinishedTaskIds],
2308
+ qualityScore: liveOutcome.qualityScore,
2309
+ qualityMissing: liveOutcome.qualityMissing,
2310
+ qualityBlockers: liveOutcome.qualityBlockers,
2311
+ hasOutput: this.api.hasAgentWorkspaceOutput(workspaceContext),
2312
+ selfHealStatus: 'skipped',
2313
+ selfHealTool: null,
2314
+ plannerError: liveOutcome.plannerError ? sanitizeUserFacingErrorText(liveOutcome.plannerError) : null,
2315
+ executorError: liveOutcome.executorError ? sanitizeUserFacingErrorText(liveOutcome.executorError) : safeDetail || null,
2316
+ finishedAt: Date.now(),
2317
+ };
2154
2318
  if (this.jsonOutput) {
2155
2319
  process.exitCode = 1;
2156
2320
  console.log(JSON.stringify({
@@ -2163,6 +2327,9 @@ export class ChatCommand {
2163
2327
  metadata: { executionPath: 'v3-agent' },
2164
2328
  }, null, 2));
2165
2329
  }
2330
+ else if (!this.directPromptMode) {
2331
+ this.printAgentRunSummary(this.lastAgentRunOutcome, false, 0);
2332
+ }
2166
2333
  return true;
2167
2334
  }
2168
2335
  }
@@ -2350,6 +2517,38 @@ export class ChatCommand {
2350
2517
  console.log(chalk.yellow('Conversation cleared.'));
2351
2518
  continue;
2352
2519
  }
2520
+ if (trimmed === '/status') {
2521
+ this.showAgentRunStatus();
2522
+ continue;
2523
+ }
2524
+ if (trimmed === '/retry') {
2525
+ const followUp = this.buildRetryPrompt();
2526
+ if (!followUp) {
2527
+ console.log(chalk.yellow('Nothing to retry — run an agent task first.'));
2528
+ continue;
2529
+ }
2530
+ if (!this.agentMode) {
2531
+ this.agentMode = true;
2532
+ this.syncInteractiveModeModel('agent');
2533
+ console.log(chalk.gray('Agent mode re-enabled for retry.'));
2534
+ }
2535
+ await this.runAgentTurn(followUp);
2536
+ continue;
2537
+ }
2538
+ if (trimmed === '/continue') {
2539
+ const followUp = this.buildContinuePrompt();
2540
+ if (!followUp) {
2541
+ console.log(chalk.yellow('Nothing to continue — run an agent task first.'));
2542
+ continue;
2543
+ }
2544
+ if (!this.agentMode) {
2545
+ this.agentMode = true;
2546
+ this.syncInteractiveModeModel('agent');
2547
+ console.log(chalk.gray('Agent mode re-enabled for continuation.'));
2548
+ }
2549
+ await this.runAgentTurn(followUp);
2550
+ continue;
2551
+ }
2353
2552
  if (trimmed === '/save') {
2354
2553
  this.saveSession();
2355
2554
  console.log(chalk.green('Session saved.'));
@@ -2382,17 +2581,153 @@ export class ChatCommand {
2382
2581
  showHelp() {
2383
2582
  console.log('');
2384
2583
  console.log('Commands:');
2385
- console.log(' /help Show this help');
2386
- console.log(' /exit Exit chat');
2387
- console.log(' /agent Toggle agent mode');
2388
- console.log(' /operator Toggle BMAD operator mode');
2389
- console.log(' /context Show current session and project memory');
2390
- console.log(' /memory Show Vigthoria project brain status');
2391
- console.log(' /compact Compact current session into memory summary');
2392
- console.log(' /clear Clear conversation');
2393
- console.log(' /save Save session');
2584
+ console.log(' /help Show this help');
2585
+ console.log(' /exit Exit chat');
2586
+ console.log(' /agent Toggle agent mode');
2587
+ console.log(' /operator Toggle BMAD operator mode');
2588
+ console.log(' /context Show current session and project memory');
2589
+ console.log(' /memory Show Vigthoria project brain status');
2590
+ console.log(' /compact Compact current session into memory summary');
2591
+ console.log(' /clear Clear conversation');
2592
+ console.log(' /save Save session');
2394
2593
  console.log(' /model <name> Change model');
2594
+ console.log(' /status Show the last agent run outcome');
2595
+ console.log(' /retry Re-run the last failed agent task');
2596
+ console.log(' /continue Ask the agent to keep working on unfinished tasks');
2597
+ console.log('');
2598
+ }
2599
+ /**
2600
+ * Print a clear, opinionated end-of-run summary after every agent workflow.
2601
+ *
2602
+ * Goals:
2603
+ * - User can answer "Did it succeed?" in one glance.
2604
+ * - User can answer "What do I type next?" without reading 200 scrollback lines.
2605
+ * - Never leave the spinners (`⟳`, `–`) ambiguous when the prompt returns.
2606
+ */
2607
+ printAgentRunSummary(outcome, executorSucceeded, changedFileCount) {
2608
+ const bar = chalk.gray('─'.repeat(63));
2609
+ const ok = chalk.green('✓');
2610
+ const warn = chalk.yellow('⚠');
2611
+ const bad = chalk.red('✗');
2612
+ const failedList = outcome.failedTaskIds.slice(0, 8);
2613
+ const unfinishedList = outcome.unfinishedTaskIds.slice(0, 8);
2614
+ const hasTaskInfo = outcome.tasksTotal > 0 || failedList.length > 0 || unfinishedList.length > 0;
2615
+ console.log('');
2616
+ console.log(bar);
2617
+ if (executorSucceeded && outcome.selfHealStatus !== 'partial' && outcome.selfHealStatus !== 'failed' && failedList.length === 0) {
2618
+ console.log(`${ok} ${chalk.bold('Agent run finished')}${changedFileCount ? chalk.gray(` — ${changedFileCount} file${changedFileCount === 1 ? '' : 's'} changed`) : ''}`);
2619
+ }
2620
+ else if (executorSucceeded) {
2621
+ console.log(`${warn} ${chalk.bold('Agent run finished with warnings')}${changedFileCount ? chalk.gray(` — ${changedFileCount} file${changedFileCount === 1 ? '' : 's'} changed`) : ''}`);
2622
+ }
2623
+ else {
2624
+ console.log(`${bad} ${chalk.bold('Agent run did not complete')}${changedFileCount ? chalk.gray(` — ${changedFileCount} file${changedFileCount === 1 ? '' : 's'} changed`) : ''}`);
2625
+ }
2626
+ if (hasTaskInfo) {
2627
+ const succ = outcome.tasksTotal > 0 ? `${outcome.tasksSucceeded}/${outcome.tasksTotal}` : `${outcome.tasksSucceeded}`;
2628
+ console.log(chalk.gray(` Tasks completed: ${succ}`));
2629
+ if (failedList.length > 0) {
2630
+ const more = outcome.failedTaskIds.length > failedList.length ? chalk.gray(` (+${outcome.failedTaskIds.length - failedList.length} more)`) : '';
2631
+ console.log(chalk.gray(' Failed: ') + chalk.red(failedList.join(', ')) + more);
2632
+ }
2633
+ if (unfinishedList.length > 0) {
2634
+ const more = outcome.unfinishedTaskIds.length > unfinishedList.length ? chalk.gray(` (+${outcome.unfinishedTaskIds.length - unfinishedList.length} more)`) : '';
2635
+ console.log(chalk.gray(' Pending: ') + chalk.yellow(unfinishedList.join(', ')) + more);
2636
+ }
2637
+ }
2638
+ if (typeof outcome.qualityScore === 'number') {
2639
+ const score = outcome.qualityScore.toFixed(1);
2640
+ const colour = outcome.qualityScore >= 70 ? chalk.green : outcome.qualityScore >= 30 ? chalk.yellow : chalk.red;
2641
+ console.log(chalk.gray(' Quality: ') + colour(`${score}/100`));
2642
+ }
2643
+ if (outcome.qualityBlockers.length > 0) {
2644
+ const list = outcome.qualityBlockers.slice(0, 3).join('; ');
2645
+ const more = outcome.qualityBlockers.length > 3 ? chalk.gray(` (+${outcome.qualityBlockers.length - 3} more)`) : '';
2646
+ console.log(chalk.gray(' Blockers: ') + chalk.yellow(list) + more);
2647
+ }
2648
+ if (outcome.qualityMissing.length > 0) {
2649
+ const list = outcome.qualityMissing.slice(0, 5).join(', ');
2650
+ const more = outcome.qualityMissing.length > 5 ? chalk.gray(` (+${outcome.qualityMissing.length - 5} more)`) : '';
2651
+ console.log(chalk.gray(' Missing: ') + chalk.yellow(list) + more);
2652
+ }
2653
+ if (outcome.plannerError) {
2654
+ console.log(chalk.gray(' Planner: ') + chalk.red(outcome.plannerError.slice(0, 140)));
2655
+ }
2656
+ if (outcome.executorError) {
2657
+ console.log(chalk.gray(' Executor: ') + chalk.red(outcome.executorError.slice(0, 140)));
2658
+ }
2395
2659
  console.log('');
2660
+ console.log(chalk.gray('What you can do next:'));
2661
+ if (failedList.length > 0 || unfinishedList.length > 0 || !executorSucceeded) {
2662
+ console.log(' ' + chalk.cyan('/retry') + chalk.gray(' resume the failed/unfinished tasks only'));
2663
+ console.log(' ' + chalk.cyan('/continue') + chalk.gray(' ask the agent to keep working from this state'));
2664
+ }
2665
+ else {
2666
+ console.log(' ' + chalk.cyan('/continue') + chalk.gray(' add a follow-up instruction in this thread'));
2667
+ }
2668
+ if (changedFileCount > 0) {
2669
+ console.log(' ' + chalk.cyan('vigthoria preview --diff') + chalk.gray(' inspect the file changes'));
2670
+ }
2671
+ console.log(' ' + chalk.cyan('/status') + chalk.gray(' re-print this summary later'));
2672
+ console.log(' ' + chalk.cyan('/exit') + chalk.gray(' leave interactive chat'));
2673
+ console.log(bar);
2674
+ console.log('');
2675
+ }
2676
+ /**
2677
+ * Build the prompt sent to the agent when the user types `/retry`.
2678
+ * Resumes only the failed/unfinished tasks from the previous run.
2679
+ */
2680
+ buildRetryPrompt() {
2681
+ const o = this.lastAgentRunOutcome;
2682
+ if (!o || !o.prompt)
2683
+ return null;
2684
+ const remaining = [...new Set([...o.failedTaskIds, ...o.unfinishedTaskIds])];
2685
+ const taskList = remaining.length > 0 ? remaining.join(', ') : '';
2686
+ const blockerLine = o.qualityBlockers.length > 0
2687
+ ? `\nKnown blockers to address: ${o.qualityBlockers.slice(0, 3).join('; ')}.`
2688
+ : '';
2689
+ const missingLine = o.qualityMissing.length > 0
2690
+ ? `\nMissing pieces: ${o.qualityMissing.slice(0, 6).join(', ')}.`
2691
+ : '';
2692
+ if (taskList) {
2693
+ return `Resume the previous agent run. Re-execute only these tasks and make them pass: ${taskList}.${blockerLine}${missingLine}\nOriginal request was: ${o.prompt}`;
2694
+ }
2695
+ return `Retry the previous request and make sure it finishes successfully.${blockerLine}${missingLine}\nOriginal request was: ${o.prompt}`;
2696
+ }
2697
+ /**
2698
+ * Build the prompt sent to the agent when the user types `/continue`.
2699
+ * Tells the agent to keep working from the current workspace state.
2700
+ */
2701
+ buildContinuePrompt() {
2702
+ const o = this.lastAgentRunOutcome;
2703
+ if (!o || !o.prompt)
2704
+ return null;
2705
+ const remaining = [...new Set([...o.failedTaskIds, ...o.unfinishedTaskIds])];
2706
+ const taskList = remaining.length > 0 ? `\nRemaining tasks to finish: ${remaining.join(', ')}.` : '';
2707
+ const blockerLine = o.qualityBlockers.length > 0
2708
+ ? `\nKnown blockers to address: ${o.qualityBlockers.slice(0, 3).join('; ')}.`
2709
+ : '';
2710
+ const missingLine = o.qualityMissing.length > 0
2711
+ ? `\nMissing pieces: ${o.qualityMissing.slice(0, 6).join(', ')}.`
2712
+ : '';
2713
+ return `Continue the previous agent run from the current workspace state without re-doing already-completed work.${taskList}${blockerLine}${missingLine}\nOriginal request was: ${o.prompt}`;
2714
+ }
2715
+ /**
2716
+ * Re-print the last agent run summary, or guide the user when there isn't one.
2717
+ */
2718
+ showAgentRunStatus() {
2719
+ if (!this.lastAgentRunOutcome) {
2720
+ console.log(chalk.yellow('No agent run has finished in this session yet.'));
2721
+ console.log(chalk.gray('Toggle agent mode with /agent and send a request to start one.'));
2722
+ return;
2723
+ }
2724
+ const o = this.lastAgentRunOutcome;
2725
+ const executorSucceeded = o.failedTaskIds.length === 0
2726
+ && o.unfinishedTaskIds.length === 0
2727
+ && !o.plannerError
2728
+ && !o.executorError
2729
+ && o.hasOutput;
2730
+ this.printAgentRunSummary(o, executorSucceeded, 0);
2396
2731
  }
2397
2732
  showContext() {
2398
2733
  if (!this.currentSession) {
package/install.ps1 CHANGED
@@ -5,7 +5,7 @@
5
5
  $ErrorActionPreference = "Stop"
6
6
 
7
7
  # Configuration
8
- $CLI_VERSION = "1.9.1"
8
+ $CLI_VERSION = "1.9.20"
9
9
  $INSTALL_DIR = "$env:USERPROFILE\.vigthoria"
10
10
  $NPM_PACKAGE = "vigthoria-cli"
11
11
  $GIT_PACKAGE_URL = "git+https://market.vigthoria.io/vigthoria/vigthoria-cli.git"
package/install.sh CHANGED
@@ -26,7 +26,7 @@ else
26
26
  fi
27
27
 
28
28
  # Configuration
29
- CLI_VERSION="1.9.1"
29
+ CLI_VERSION="1.9.20"
30
30
  INSTALL_DIR="$HOME/.vigthoria"
31
31
  REPO_URL="https://market.vigthoria.io/vigthoria/vigthoria-cli"
32
32
  GIT_PACKAGE_URL="git+https://market.vigthoria.io/vigthoria/vigthoria-cli.git"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigthoria-cli",
3
- "version": "1.9.19",
3
+ "version": "1.9.20",
4
4
  "description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",