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.
@@ -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
  }
@@ -17,6 +17,8 @@ interface ChatOptions {
17
17
  json?: boolean;
18
18
  bridge?: string;
19
19
  grant?: boolean;
20
+ retry?: boolean;
21
+ continue?: boolean;
20
22
  }
21
23
  export declare class ChatCommand {
22
24
  private config;
@@ -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
- tasksSucceeded: 0,
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.jsonOutput) {
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.messages.push({ role: 'assistant', content: response.content || 'V3 agent workflow completed.' });
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: false,
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
- liveOutcome.failedTaskIds.delete(String(tid));
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: resolvedContext.vigthoriaBrain || null,
1685
- vigthoria_brain: resolvedContext.vigthoriaBrain || null,
1686
+ vigthoriaBrain: dedupedBrain,
1687
+ vigthoria_brain: dedupedBrain,
1686
1688
  });
1687
1689
  }
1688
1690
  extractEmergencyAppName(message = '', fallback = 'Signal Desk') {
@@ -46,6 +46,7 @@ export interface Session {
46
46
  updatedAt: string;
47
47
  agentMode: boolean;
48
48
  operatorMode?: boolean;
49
+ lastAgentRunOutcome?: Record<string, unknown> | null;
49
50
  }
50
51
  export declare class SessionManager {
51
52
  private sessionsDir;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigthoria-cli",
3
- "version": "1.11.0",
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:cli": "npm run build && npm run precheck:services && node scripts/test-cli-suite.js",
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 "status check" --json >/tmp/vig-operator.json
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"