vigthoria-cli 1.9.19 → 1.9.21
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 +24 -0
- package/dist/commands/chat.js +345 -10
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +1 -1
package/dist/commands/chat.d.ts
CHANGED
|
@@ -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;
|
package/dist/commands/chat.js
CHANGED
|
@@ -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
|
|
2386
|
-
console.log(' /exit
|
|
2387
|
-
console.log(' /agent
|
|
2388
|
-
console.log(' /operator
|
|
2389
|
-
console.log(' /context
|
|
2390
|
-
console.log(' /memory
|
|
2391
|
-
console.log(' /compact
|
|
2392
|
-
console.log(' /clear
|
|
2393
|
-
console.log(' /save
|
|
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.
|
|
8
|
+
$CLI_VERSION = "1.9.21"
|
|
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.
|
|
29
|
+
CLI_VERSION="1.9.21"
|
|
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"
|