vigthoria-cli 1.11.0 → 1.11.3
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/background.d.ts +1 -0
- package/dist/commands/background.js +55 -1
- package/dist/commands/chat.d.ts +2 -0
- package/dist/commands/chat.js +79 -38
- package/dist/index.js +4 -0
- package/dist/utils/agentRunOutcome.d.ts +2 -0
- package/dist/utils/agentRunOutcome.js +26 -3
- package/dist/utils/api.js +4 -2
- package/dist/utils/session.d.ts +1 -0
- package/package.json +3 -2
- package/scripts/release/validate-no-go-gates.sh +4 -1
|
@@ -15,5 +15,6 @@ export declare class BackgroundCommand {
|
|
|
15
15
|
status(jobId: string, options?: BackgroundOptions): Promise<void>;
|
|
16
16
|
apply(jobId: string, options?: BackgroundOptions): Promise<void>;
|
|
17
17
|
cancel(jobId: string, options?: BackgroundOptions): Promise<void>;
|
|
18
|
+
private extractBackgroundOutcome;
|
|
18
19
|
}
|
|
19
20
|
export {};
|
|
@@ -82,8 +82,9 @@ export class BackgroundCommand {
|
|
|
82
82
|
try {
|
|
83
83
|
const job = await this.api.getV3BackgroundJob(jobId);
|
|
84
84
|
spinner.stop();
|
|
85
|
+
const outcome = this.extractBackgroundOutcome(job);
|
|
85
86
|
if (options.json) {
|
|
86
|
-
console.log(JSON.stringify(job, null, 2));
|
|
87
|
+
console.log(JSON.stringify({ ...job, outcomeTruth: outcome }, null, 2));
|
|
87
88
|
return;
|
|
88
89
|
}
|
|
89
90
|
console.log(chalk.bold(`\nBackground Job ${chalk.cyan(job.job_id)}\n`));
|
|
@@ -91,6 +92,12 @@ export class BackgroundCommand {
|
|
|
91
92
|
console.log(`Files: ${job.file_count || 0}`);
|
|
92
93
|
console.log(`Updated: ${job.updated_at || '-'}`);
|
|
93
94
|
console.log(`Workspace: ${job.local_workspace_path || job.workspace_name || '-'}`);
|
|
95
|
+
if (outcome.tasksTotal > 0 || outcome.tasksCompleted > 0) {
|
|
96
|
+
console.log(`Tasks: ${outcome.tasksCompleted}/${outcome.tasksTotal}${outcome.success === true ? chalk.green(' (complete)') : outcome.success === false ? chalk.red(' (incomplete)') : ''}`);
|
|
97
|
+
}
|
|
98
|
+
if (outcome.headline) {
|
|
99
|
+
console.log(chalk.gray(`Outcome: ${outcome.headline}`));
|
|
100
|
+
}
|
|
94
101
|
if (job.error)
|
|
95
102
|
console.log(chalk.red(`Error: ${job.error}`));
|
|
96
103
|
console.log(chalk.gray(`\n${String(job.request || '').slice(0, 500)}`));
|
|
@@ -157,4 +164,51 @@ export class BackgroundCommand {
|
|
|
157
164
|
this.logger.error(error?.message || String(error));
|
|
158
165
|
}
|
|
159
166
|
}
|
|
167
|
+
extractBackgroundOutcome(job) {
|
|
168
|
+
const result = (job?.result && typeof job.result === 'object') ? job.result : {};
|
|
169
|
+
const events = Array.isArray(job?.events) ? job.events : [];
|
|
170
|
+
let tasksCompleted = Number(result.tasks_completed ?? result.tasksCompleted ?? 0);
|
|
171
|
+
let tasksTotal = Number(result.tasks_total ?? result.tasksTotal ?? 0);
|
|
172
|
+
let success = typeof result.success === 'boolean' ? result.success : null;
|
|
173
|
+
for (const event of events) {
|
|
174
|
+
if (!event || typeof event !== 'object')
|
|
175
|
+
continue;
|
|
176
|
+
if (event.type === 'result' || event.event === 'result') {
|
|
177
|
+
const payload = event.data || event.payload || event;
|
|
178
|
+
if (payload && typeof payload === 'object') {
|
|
179
|
+
if (payload.tasks_completed != null)
|
|
180
|
+
tasksCompleted = Number(payload.tasks_completed);
|
|
181
|
+
if (payload.tasksCompleted != null)
|
|
182
|
+
tasksCompleted = Number(payload.tasksCompleted);
|
|
183
|
+
if (payload.tasks_total != null)
|
|
184
|
+
tasksTotal = Number(payload.tasks_total);
|
|
185
|
+
if (payload.tasksTotal != null)
|
|
186
|
+
tasksTotal = Number(payload.tasksTotal);
|
|
187
|
+
if (typeof payload.success === 'boolean')
|
|
188
|
+
success = payload.success;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (success == null && tasksTotal > 0) {
|
|
193
|
+
success = tasksCompleted >= tasksTotal;
|
|
194
|
+
}
|
|
195
|
+
if (success == null && job?.status === 'completed') {
|
|
196
|
+
success = true;
|
|
197
|
+
}
|
|
198
|
+
if (success == null && job?.status === 'failed') {
|
|
199
|
+
success = false;
|
|
200
|
+
}
|
|
201
|
+
let headline = '';
|
|
202
|
+
if (tasksTotal > 0) {
|
|
203
|
+
headline = success === true
|
|
204
|
+
? `All ${tasksTotal} task(s) completed`
|
|
205
|
+
: success === false
|
|
206
|
+
? `${tasksCompleted}/${tasksTotal} task(s) completed`
|
|
207
|
+
: `${tasksCompleted}/${tasksTotal} task(s) reported`;
|
|
208
|
+
}
|
|
209
|
+
else if (typeof result.message === 'string' && result.message.trim()) {
|
|
210
|
+
headline = result.message.trim();
|
|
211
|
+
}
|
|
212
|
+
return { tasksCompleted, tasksTotal, success, headline };
|
|
213
|
+
}
|
|
160
214
|
}
|
package/dist/commands/chat.d.ts
CHANGED
package/dist/commands/chat.js
CHANGED
|
@@ -13,7 +13,7 @@ import { TaskDisplay } from '../utils/task-display.js';
|
|
|
13
13
|
import { ProjectMemoryService } from '../utils/project-memory.js';
|
|
14
14
|
import { buildPersonaOverlay, normalizePersonaMode } from '../utils/persona.js';
|
|
15
15
|
import { runAgentSessionMenu, shouldShowAgentSessionMenu } from './agent-session-menu.js';
|
|
16
|
-
import { evaluateExecutorSuccess, handleTaskEvent, noteAnalysisToolUse, } from '../utils/agentRunOutcome.js';
|
|
16
|
+
import { createLiveOutcome, evaluateExecutorSuccess, handleTaskEvent, noteAnalysisToolUse, } from '../utils/agentRunOutcome.js';
|
|
17
17
|
const DEFAULT_V3_AGENT_TIMEOUT_MS = (() => {
|
|
18
18
|
const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS;
|
|
19
19
|
if (!rawValue) {
|
|
@@ -477,6 +477,10 @@ export class ChatCommand {
|
|
|
477
477
|
*/
|
|
478
478
|
isOperatorDirectAnswerable(prompt) {
|
|
479
479
|
const trimmed = prompt.trim();
|
|
480
|
+
// Infrastructure status pings are never repo-grounded analysis.
|
|
481
|
+
if (/^(status(\s+check)?|health(\s+check)?|ping)$/i.test(trimmed)) {
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
480
484
|
// ── Exclusion guard: any prompt that references code artefacts,
|
|
481
485
|
// file paths, or analysis verbs MUST go through a tool-backed path
|
|
482
486
|
// (BMAD or agent loop), never the toolless direct-answer shortcut.
|
|
@@ -711,6 +715,9 @@ export class ChatCommand {
|
|
|
711
715
|
}
|
|
712
716
|
}
|
|
713
717
|
writeV3StreamText(spinner, text) {
|
|
718
|
+
if (this.jsonOutput) {
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
714
721
|
const safeText = this.sanitizeV3VisibleStreamText(this.sanitizeServerPath(text));
|
|
715
722
|
if (!safeText) {
|
|
716
723
|
return;
|
|
@@ -1137,14 +1144,14 @@ export class ChatCommand {
|
|
|
1137
1144
|
}
|
|
1138
1145
|
console.log(chalk.green(`Using workspace: ${this.currentProjectPath}`));
|
|
1139
1146
|
}
|
|
1140
|
-
if (this.jsonOutput && !options.prompt) {
|
|
1141
|
-
throw new Error('--json is only supported together with --prompt.');
|
|
1147
|
+
if (this.jsonOutput && !options.prompt && !options.retry && !options.continue) {
|
|
1148
|
+
throw new Error('--json is only supported together with --prompt, --retry, or --continue.');
|
|
1142
1149
|
}
|
|
1143
1150
|
this.ensureProjectWorkspace();
|
|
1144
1151
|
this.directPromptMode = Boolean(options.prompt);
|
|
1145
1152
|
this.directToolContinuationCount = 0;
|
|
1146
1153
|
this.tools = new AgenticTools(this.logger, this.currentProjectPath, async (action) => this.requestPermission(action), this.autoApprove);
|
|
1147
|
-
this.initializeSession(options.resume === true);
|
|
1154
|
+
this.initializeSession(options.resume === true || options.retry === true || options.continue === true);
|
|
1148
1155
|
// ── Commando Bridge: connect if --bridge was specified ──────────
|
|
1149
1156
|
if (options.bridge) {
|
|
1150
1157
|
const bridgeClient = new BridgeClient({
|
|
@@ -1169,6 +1176,18 @@ export class ChatCommand {
|
|
|
1169
1176
|
this.logger.error(this.operatorAccessMessage());
|
|
1170
1177
|
return;
|
|
1171
1178
|
}
|
|
1179
|
+
if (options.retry || options.continue) {
|
|
1180
|
+
if (!this.agentMode) {
|
|
1181
|
+
throw new Error('--retry and --continue require agent mode.');
|
|
1182
|
+
}
|
|
1183
|
+
const followUp = options.retry ? this.buildRetryPrompt() : this.buildContinuePrompt();
|
|
1184
|
+
if (!followUp) {
|
|
1185
|
+
throw new Error('No previous agent run to retry or continue. Run an agent prompt first with the same --project, or use --resume.');
|
|
1186
|
+
}
|
|
1187
|
+
this.directPromptMode = true;
|
|
1188
|
+
await this.runAgentTurn(followUp);
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1172
1191
|
if (options.prompt) {
|
|
1173
1192
|
const bridgePromptTimeoutMs = (() => {
|
|
1174
1193
|
const rawValue = process.env.VIGTHORIA_BRIDGE_PROMPT_TIMEOUT_MS || process.env.V3_BRIDGE_PROMPT_TIMEOUT_MS;
|
|
@@ -1404,6 +1423,9 @@ export class ChatCommand {
|
|
|
1404
1423
|
this.agentMode = this.currentSession.agentMode || this.agentMode;
|
|
1405
1424
|
this.operatorMode = this.currentSession.operatorMode || this.operatorMode;
|
|
1406
1425
|
this.currentModel = this.currentSession.model || this.currentModel;
|
|
1426
|
+
if (this.currentSession.lastAgentRunOutcome) {
|
|
1427
|
+
this.lastAgentRunOutcome = this.currentSession.lastAgentRunOutcome;
|
|
1428
|
+
}
|
|
1407
1429
|
return;
|
|
1408
1430
|
}
|
|
1409
1431
|
}
|
|
@@ -2368,20 +2390,11 @@ export class ChatCommand {
|
|
|
2368
2390
|
}).start();
|
|
2369
2391
|
// Live run telemetry, used both for the final summary block and for /retry, /continue.
|
|
2370
2392
|
const liveOutcome = {
|
|
2371
|
-
|
|
2372
|
-
tasksTotal: 0,
|
|
2373
|
-
failedTaskIds: new Set(),
|
|
2393
|
+
...createLiveOutcome(),
|
|
2374
2394
|
unfinishedTaskIds: new Set(),
|
|
2375
2395
|
qualityScore: null,
|
|
2376
2396
|
qualityMissing: [],
|
|
2377
2397
|
qualityBlockers: [],
|
|
2378
|
-
plannerError: null,
|
|
2379
|
-
executorError: null,
|
|
2380
|
-
executorFailed: false,
|
|
2381
|
-
analysisToolsUsed: 0,
|
|
2382
|
-
changedFileCount: 0,
|
|
2383
|
-
requiresWorkspaceChanges: false,
|
|
2384
|
-
workspaceHasOutput: false,
|
|
2385
2398
|
};
|
|
2386
2399
|
const parsePlannerSummary = (raw) => {
|
|
2387
2400
|
if (!raw || typeof raw !== 'string')
|
|
@@ -2498,7 +2511,7 @@ export class ChatCommand {
|
|
|
2498
2511
|
else if (event.type === 'executor_complete') {
|
|
2499
2512
|
const summary = event.summary || {};
|
|
2500
2513
|
handleTaskEvent(summary, liveOutcome);
|
|
2501
|
-
if (summary.status === 'failed') {
|
|
2514
|
+
if (summary.status === 'failed' || summary.status === 'stalled_error') {
|
|
2502
2515
|
const err = typeof summary.error === 'string' ? summary.error.trim() : '';
|
|
2503
2516
|
if (err && !liveOutcome.executorError)
|
|
2504
2517
|
liveOutcome.executorError = err;
|
|
@@ -2510,6 +2523,10 @@ export class ChatCommand {
|
|
|
2510
2523
|
noteAnalysisToolUse(toolName, liveOutcome);
|
|
2511
2524
|
}
|
|
2512
2525
|
else if (event.type === 'complete') {
|
|
2526
|
+
const tt = Number(event.tasks_total);
|
|
2527
|
+
if (Number.isFinite(tt) && tt > 0) {
|
|
2528
|
+
liveOutcome.tasksTotal = tt;
|
|
2529
|
+
}
|
|
2513
2530
|
if (Number(event.discovery_tools_used) > 0) {
|
|
2514
2531
|
liveOutcome.analysisToolsUsed = Math.max(liveOutcome.analysisToolsUsed, Number(event.discovery_tools_used));
|
|
2515
2532
|
}
|
|
@@ -2589,20 +2606,7 @@ export class ChatCommand {
|
|
|
2589
2606
|
if (!this.jsonOutput && previewGate?.required && previewGate?.passed !== true && workspaceHasOutput) {
|
|
2590
2607
|
console.log(chalk.yellow(`Template Service preview gate did not fully validate this output, but generated workspace files were preserved${previewGate?.error ? `: ${previewGate.error}` : '.'}`));
|
|
2591
2608
|
}
|
|
2592
|
-
if (this.
|
|
2593
|
-
console.log(JSON.stringify({
|
|
2594
|
-
success,
|
|
2595
|
-
mode: 'agent',
|
|
2596
|
-
model: routingPolicy.selectedModel,
|
|
2597
|
-
routingPolicy,
|
|
2598
|
-
taskId: response.taskId || null,
|
|
2599
|
-
contextId: response.contextId || null,
|
|
2600
|
-
partial: response.partial === true,
|
|
2601
|
-
content: response.content || 'V3 agent workflow completed.',
|
|
2602
|
-
metadata: response.metadata || {},
|
|
2603
|
-
}, null, 2));
|
|
2604
|
-
}
|
|
2605
|
-
else if (this.v3StreamingStarted) {
|
|
2609
|
+
if (this.v3StreamingStarted) {
|
|
2606
2610
|
// Content was already streamed to stdout in real-time; skip duplicate print.
|
|
2607
2611
|
if (!this.jsonOutput) {
|
|
2608
2612
|
console.log(chalk.gray(`Agent routing: ${routingPolicy.cloudSelected ? 'Vigthoria Cloud' : 'V3 Agent'}`));
|
|
@@ -2720,6 +2724,9 @@ export class ChatCommand {
|
|
|
2720
2724
|
}
|
|
2721
2725
|
taskDisplay.finalize();
|
|
2722
2726
|
// ────────────────────────────────────────────────────────────────
|
|
2727
|
+
if (!executorSucceeded) {
|
|
2728
|
+
process.exitCode = 1;
|
|
2729
|
+
}
|
|
2723
2730
|
this.lastAgentRunOutcome = {
|
|
2724
2731
|
prompt,
|
|
2725
2732
|
taskId: response.taskId || null,
|
|
@@ -2747,7 +2754,35 @@ export class ChatCommand {
|
|
|
2747
2754
|
if (!this.jsonOutput && !this.directPromptMode) {
|
|
2748
2755
|
this.printAgentRunSummary(this.lastAgentRunOutcome, runEvaluation, changedFileCount);
|
|
2749
2756
|
}
|
|
2750
|
-
this.
|
|
2757
|
+
if (this.jsonOutput) {
|
|
2758
|
+
if (!executorSucceeded) {
|
|
2759
|
+
process.exitCode = 1;
|
|
2760
|
+
}
|
|
2761
|
+
console.log(JSON.stringify({
|
|
2762
|
+
success: executorSucceeded,
|
|
2763
|
+
mode: 'agent',
|
|
2764
|
+
model: routingPolicy.selectedModel,
|
|
2765
|
+
routingPolicy,
|
|
2766
|
+
taskId: response.taskId || null,
|
|
2767
|
+
contextId: response.contextId || null,
|
|
2768
|
+
partial: response.partial === true || (!executorSucceeded && liveOutcome.tasksSucceeded > 0),
|
|
2769
|
+
content: response.content || runEvaluation.statusHeadline,
|
|
2770
|
+
statusHeadline: runEvaluation.statusHeadline,
|
|
2771
|
+
tasksSucceeded: liveOutcome.tasksSucceeded,
|
|
2772
|
+
tasksTotal: liveOutcome.tasksTotal,
|
|
2773
|
+
metadata: {
|
|
2774
|
+
...(response.metadata || {}),
|
|
2775
|
+
outcomeTruth: {
|
|
2776
|
+
executorSucceeded,
|
|
2777
|
+
uiTheme: runEvaluation.uiTheme,
|
|
2778
|
+
tasksSucceeded: liveOutcome.tasksSucceeded,
|
|
2779
|
+
tasksTotal: liveOutcome.tasksTotal,
|
|
2780
|
+
},
|
|
2781
|
+
previewGate,
|
|
2782
|
+
},
|
|
2783
|
+
}, null, 2));
|
|
2784
|
+
}
|
|
2785
|
+
this.messages.push({ role: 'assistant', content: response.content || runEvaluation.statusHeadline });
|
|
2751
2786
|
watcher?.stop();
|
|
2752
2787
|
return true;
|
|
2753
2788
|
}
|
|
@@ -2776,6 +2811,10 @@ export class ChatCommand {
|
|
|
2776
2811
|
: 'Agent mode is unavailable right now. Please retry shortly or run vigthoria login if the issue persists.';
|
|
2777
2812
|
this.logger.error(errorMessage);
|
|
2778
2813
|
this.messages.push({ role: 'assistant', content: errorMessage });
|
|
2814
|
+
liveOutcome.streamAborted = true;
|
|
2815
|
+
if (!liveOutcome.executorError) {
|
|
2816
|
+
liveOutcome.executorError = safeDetail || 'Connection aborted';
|
|
2817
|
+
}
|
|
2779
2818
|
// Resolve any half-rendered TaskDisplay spinners before the prompt
|
|
2780
2819
|
// comes back, otherwise the user sees `⟳ Execute tasks` next to `>`.
|
|
2781
2820
|
try {
|
|
@@ -2807,30 +2846,32 @@ export class ChatCommand {
|
|
|
2807
2846
|
workspaceSyncIssue: null,
|
|
2808
2847
|
finishedAt: Date.now(),
|
|
2809
2848
|
};
|
|
2849
|
+
if (!this.jsonOutput) {
|
|
2850
|
+
process.exitCode = 1;
|
|
2851
|
+
}
|
|
2810
2852
|
if (this.jsonOutput) {
|
|
2811
2853
|
process.exitCode = 1;
|
|
2812
2854
|
console.log(JSON.stringify({
|
|
2813
2855
|
success: false,
|
|
2814
2856
|
mode: 'agent',
|
|
2815
2857
|
model: routingPolicy.selectedModel,
|
|
2816
|
-
partial:
|
|
2858
|
+
partial: liveOutcome.tasksSucceeded > 0 && liveOutcome.tasksTotal > 0,
|
|
2817
2859
|
content: '',
|
|
2818
2860
|
error: errorMessage,
|
|
2861
|
+
statusHeadline: evaluateExecutorSuccess(liveOutcome).statusHeadline,
|
|
2862
|
+
tasksSucceeded: liveOutcome.tasksSucceeded,
|
|
2863
|
+
tasksTotal: liveOutcome.tasksTotal,
|
|
2819
2864
|
metadata: { executionPath: 'v3-agent' },
|
|
2820
2865
|
}, null, 2));
|
|
2821
2866
|
}
|
|
2822
2867
|
else if (!this.directPromptMode) {
|
|
2823
2868
|
const failedEval = evaluateExecutorSuccess({
|
|
2869
|
+
...liveOutcome,
|
|
2824
2870
|
executorFailed: true,
|
|
2825
|
-
plannerError: liveOutcome.plannerError,
|
|
2826
2871
|
executorError: liveOutcome.executorError || safeDetail,
|
|
2827
|
-
tasksTotal: liveOutcome.tasksTotal,
|
|
2828
|
-
tasksSucceeded: liveOutcome.tasksSucceeded,
|
|
2829
2872
|
changedFileCount: 0,
|
|
2830
2873
|
requiresWorkspaceChanges: this.taskRequiresWorkspaceChanges(prompt),
|
|
2831
2874
|
workspaceHasOutput: this.api.hasAgentWorkspaceOutput(workspaceContext),
|
|
2832
|
-
failedTaskIds: liveOutcome.failedTaskIds,
|
|
2833
|
-
analysisToolsUsed: liveOutcome.analysisToolsUsed,
|
|
2834
2875
|
});
|
|
2835
2876
|
this.printAgentRunSummary(this.lastAgentRunOutcome, failedEval, 0);
|
|
2836
2877
|
}
|
|
@@ -3312,16 +3353,15 @@ export class ChatCommand {
|
|
|
3312
3353
|
}
|
|
3313
3354
|
const o = this.lastAgentRunOutcome;
|
|
3314
3355
|
const statusEval = evaluateExecutorSuccess({
|
|
3356
|
+
...createLiveOutcome(),
|
|
3315
3357
|
executorFailed: o.failedTaskIds.length > 0,
|
|
3316
3358
|
plannerError: o.plannerError,
|
|
3317
3359
|
executorError: o.executorError,
|
|
3318
3360
|
tasksTotal: o.tasksTotal,
|
|
3319
3361
|
tasksSucceeded: o.tasksSucceeded,
|
|
3320
|
-
changedFileCount: 0,
|
|
3321
3362
|
requiresWorkspaceChanges: this.taskRequiresWorkspaceChanges(o.prompt),
|
|
3322
3363
|
workspaceHasOutput: o.hasOutput,
|
|
3323
3364
|
failedTaskIds: new Set(o.failedTaskIds),
|
|
3324
|
-
analysisToolsUsed: 0,
|
|
3325
3365
|
});
|
|
3326
3366
|
this.printAgentRunSummary(o, statusEval, 0);
|
|
3327
3367
|
}
|
|
@@ -4132,6 +4172,7 @@ export class ChatCommand {
|
|
|
4132
4172
|
this.currentSession.agentMode = this.agentMode;
|
|
4133
4173
|
this.currentSession.operatorMode = this.operatorMode;
|
|
4134
4174
|
this.currentSession.messages = [...this.messages];
|
|
4175
|
+
this.currentSession.lastAgentRunOutcome = this.lastAgentRunOutcome;
|
|
4135
4176
|
this.currentSession = this.sessionManager.compactInMemory(this.currentSession);
|
|
4136
4177
|
this.messages = [...this.currentSession.messages];
|
|
4137
4178
|
this.sessionManager.save(this.currentSession);
|
package/dist/index.js
CHANGED
|
@@ -614,6 +614,8 @@ export async function main(args) {
|
|
|
614
614
|
.option('--prompt <text>', 'Run a single agent prompt directly and exit')
|
|
615
615
|
.option('-w, --workflow <selector>', 'Run the prompt through a named or explicit VigFlow workflow target')
|
|
616
616
|
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
617
|
+
.option('--retry', 'Retry failed tasks from the last agent run in this workspace session', false)
|
|
618
|
+
.option('--continue', 'Continue unfinished tasks from the last agent run in this workspace session', false)
|
|
617
619
|
.option('--auto-approve', 'Auto-approve all actions (dangerous!)', false)
|
|
618
620
|
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
619
621
|
.action(async (options) => {
|
|
@@ -630,6 +632,8 @@ export async function main(args) {
|
|
|
630
632
|
autoApprove: options.autoApprove,
|
|
631
633
|
prompt: options.prompt,
|
|
632
634
|
bridge: options.bridge,
|
|
635
|
+
retry: options.retry,
|
|
636
|
+
continue: options.continue,
|
|
633
637
|
});
|
|
634
638
|
});
|
|
635
639
|
program
|
|
@@ -12,7 +12,9 @@ export interface LiveOutcome {
|
|
|
12
12
|
requiresWorkspaceChanges: boolean;
|
|
13
13
|
workspaceHasOutput: boolean;
|
|
14
14
|
failedTaskIds: Set<string>;
|
|
15
|
+
completedTaskIds: Set<string>;
|
|
15
16
|
analysisToolsUsed: number;
|
|
17
|
+
streamAborted?: boolean;
|
|
16
18
|
}
|
|
17
19
|
export interface TaskSummaryEvent {
|
|
18
20
|
status?: string;
|
|
@@ -13,24 +13,36 @@ export function createLiveOutcome() {
|
|
|
13
13
|
requiresWorkspaceChanges: false,
|
|
14
14
|
workspaceHasOutput: false,
|
|
15
15
|
failedTaskIds: new Set(),
|
|
16
|
+
completedTaskIds: new Set(),
|
|
16
17
|
analysisToolsUsed: 0,
|
|
18
|
+
streamAborted: false,
|
|
17
19
|
};
|
|
18
20
|
}
|
|
19
21
|
/** Process executor_complete / task summary events from the V3 SSE stream. */
|
|
20
22
|
export function handleTaskEvent(summary, liveOutcome) {
|
|
21
23
|
const tid = summary.task_id || summary.id;
|
|
22
24
|
const status = String(summary.status || '').toLowerCase();
|
|
25
|
+
if (!liveOutcome.completedTaskIds) {
|
|
26
|
+
liveOutcome.completedTaskIds = new Set();
|
|
27
|
+
}
|
|
23
28
|
if (status === 'completed' || status === 'success') {
|
|
24
29
|
if (tid) {
|
|
25
|
-
|
|
30
|
+
const id = String(tid);
|
|
31
|
+
if (liveOutcome.completedTaskIds.has(id))
|
|
32
|
+
return;
|
|
33
|
+
liveOutcome.completedTaskIds.add(id);
|
|
34
|
+
liveOutcome.failedTaskIds.delete(id);
|
|
26
35
|
}
|
|
27
36
|
liveOutcome.tasksSucceeded += 1;
|
|
28
37
|
}
|
|
29
|
-
else if (status === 'failed' || status === 'blocked') {
|
|
38
|
+
else if (status === 'failed' || status === 'blocked' || status === 'stalled_error') {
|
|
30
39
|
if (tid) {
|
|
31
40
|
liveOutcome.failedTaskIds.add(String(tid));
|
|
32
41
|
}
|
|
33
42
|
liveOutcome.executorFailed = true;
|
|
43
|
+
if (status === 'stalled_error') {
|
|
44
|
+
liveOutcome.streamAborted = true;
|
|
45
|
+
}
|
|
34
46
|
}
|
|
35
47
|
}
|
|
36
48
|
const READ_DISCOVERY_TOOLS = new Set([
|
|
@@ -57,7 +69,18 @@ export function noteAnalysisToolUse(toolName, liveOutcome) {
|
|
|
57
69
|
export function evaluateExecutorSuccess(liveOutcome) {
|
|
58
70
|
const hasFatalError = liveOutcome.executorFailed
|
|
59
71
|
|| Boolean(liveOutcome.plannerError)
|
|
60
|
-
|| Boolean(liveOutcome.executorError)
|
|
72
|
+
|| Boolean(liveOutcome.executorError)
|
|
73
|
+
|| Boolean(liveOutcome.streamAborted);
|
|
74
|
+
if (liveOutcome.streamAborted && liveOutcome.tasksTotal > 0) {
|
|
75
|
+
const partial = liveOutcome.tasksSucceeded > 0;
|
|
76
|
+
return {
|
|
77
|
+
executorSucceeded: false,
|
|
78
|
+
statusHeadline: partial
|
|
79
|
+
? `⚠ ${liveOutcome.tasksSucceeded}/${liveOutcome.tasksTotal} tasks completed — connection aborted`
|
|
80
|
+
: `✕ Connection aborted — 0/${liveOutcome.tasksTotal} tasks completed`,
|
|
81
|
+
uiTheme: 'warning',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
61
84
|
if (hasFatalError && liveOutcome.tasksTotal === 0) {
|
|
62
85
|
return {
|
|
63
86
|
executorSucceeded: false,
|
package/dist/utils/api.js
CHANGED
|
@@ -1648,6 +1648,8 @@ export class APIClient {
|
|
|
1648
1648
|
const serverWorkspacePath = this.resolveServerBindableWorkspacePath(resolvedContext);
|
|
1649
1649
|
const localWorkspaceName = this.getDisplayWorkspaceName(targetPath);
|
|
1650
1650
|
const localWorkspaceRef = localWorkspaceName ? `vigthoria://local-workspace/${localWorkspaceName}` : null;
|
|
1651
|
+
const rawBrain = resolvedContext.vigthoriaBrain || resolvedContext.vigthoria_brain || null;
|
|
1652
|
+
const dedupedBrain = rawBrain ? this.dedupeBrainPayload(rawBrain) : null;
|
|
1651
1653
|
return JSON.stringify({
|
|
1652
1654
|
workspace: this.buildPublicWorkspaceDescriptor(resolvedContext.workspace, {
|
|
1653
1655
|
localWorkspacePath: targetPath,
|
|
@@ -1681,8 +1683,8 @@ export class APIClient {
|
|
|
1681
1683
|
contextId: resolvedContext.contextId,
|
|
1682
1684
|
traceId: resolvedContext.traceId,
|
|
1683
1685
|
requestStartedAt: resolvedContext.requestStartedAt,
|
|
1684
|
-
vigthoriaBrain:
|
|
1685
|
-
vigthoria_brain:
|
|
1686
|
+
vigthoriaBrain: dedupedBrain,
|
|
1687
|
+
vigthoria_brain: dedupedBrain,
|
|
1686
1688
|
});
|
|
1687
1689
|
}
|
|
1688
1690
|
extractEmergencyAppName(message = '', fallback = 'Signal Desk') {
|
package/dist/utils/session.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigthoria-cli",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.3",
|
|
4
4
|
"description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"start": "node dist/index.js",
|
|
37
37
|
"dev": "ts-node src/index.ts",
|
|
38
38
|
"test": "npm run test:cli",
|
|
39
|
-
"test:
|
|
39
|
+
"test:agent:outcome": "npm run build && node scripts/test-agent-run-outcome.js",
|
|
40
|
+
"test:cli": "npm run build && npm run precheck:services && node scripts/test-cli-suite.js && npm run test:agent:outcome",
|
|
40
41
|
"test:regression": "npm run build && node scripts/test-regression-1.6.22.js",
|
|
41
42
|
"test:agent:smoke": "npm run build && node scripts/test-agent-smoke.js",
|
|
42
43
|
"test:agent:routing": "npm run build && node scripts/test-agent-routing-policy.js",
|
|
@@ -76,7 +76,7 @@ $CLI hyper-loop status >/tmp/vig-hyperloop.txt
|
|
|
76
76
|
$CLI devtools connect >/tmp/vig-devtools.txt
|
|
77
77
|
|
|
78
78
|
echo "[6.11] operator flow"
|
|
79
|
-
$CLI operator --prompt "
|
|
79
|
+
$CLI operator --prompt "reply with exactly: OK" --json >/tmp/vig-operator.json
|
|
80
80
|
python3 - << 'PY'
|
|
81
81
|
import json
|
|
82
82
|
j=json.load(open('/tmp/vig-operator.json'))
|
|
@@ -131,4 +131,7 @@ assert fb.get('reason') == 'governance-blocked-model', j
|
|
|
131
131
|
print('[pass] governance fallback metadata')
|
|
132
132
|
PY
|
|
133
133
|
|
|
134
|
+
echo "[outcome-truth] agent run outcome regression"
|
|
135
|
+
npm run test:agent:outcome
|
|
136
|
+
|
|
134
137
|
echo "ALL NO-GO GATES PASSED"
|