vigthoria-cli 1.10.48 → 1.10.49

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.
@@ -1,57 +1,18 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.ChatCommand = void 0;
40
- const chalk_1 = __importDefault(require("chalk"));
41
- const fs = __importStar(require("fs"));
42
- const os = __importStar(require("os"));
43
- const path = __importStar(require("path"));
44
- const readline = __importStar(require("readline"));
45
- const logger_js_1 = require("../utils/logger.js");
46
- const api_js_1 = require("../utils/api.js");
47
- const tools_js_1 = require("../utils/tools.js");
48
- const session_js_1 = require("../utils/session.js");
49
- const bridge_client_js_1 = require("../utils/bridge-client.js");
50
- const workspace_stream_js_1 = require("../utils/workspace-stream.js");
51
- const task_display_js_1 = require("../utils/task-display.js");
52
- const project_memory_js_1 = require("../utils/project-memory.js");
53
- const persona_js_1 = require("../utils/persona.js");
54
- const agent_session_menu_js_1 = require("./agent-session-menu.js");
1
+ import chalk from 'chalk';
2
+ import * as fs from 'fs';
3
+ import * as os from 'os';
4
+ import * as path from 'path';
5
+ import * as readline from 'readline';
6
+ import { createSpinner } from '../utils/logger.js';
7
+ import { APIClient, CLIError, classifyError, formatCLIError, sanitizeUserFacingErrorText, sanitizeUserFacingPathText, propagateError, VIGTHORIA_SERVER_TEMPORARILY_UNAVAILABLE_MESSAGE } from '../utils/api.js';
8
+ import { AgenticTools, robustifyStreamResponse } from '../utils/tools.js';
9
+ import { SessionManager } from '../utils/session.js';
10
+ import { BridgeClient, getBridgeClient } from '../utils/bridge-client.js';
11
+ import { WorkspaceWatcher } from '../utils/workspace-stream.js';
12
+ import { TaskDisplay } from '../utils/task-display.js';
13
+ import { ProjectMemoryService } from '../utils/project-memory.js';
14
+ import { buildPersonaOverlay, normalizePersonaMode } from '../utils/persona.js';
15
+ import { runAgentSessionMenu, shouldShowAgentSessionMenu } from './agent-session-menu.js';
55
16
  const DEFAULT_V3_AGENT_TIMEOUT_MS = (() => {
56
17
  const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS;
57
18
  if (!rawValue) {
@@ -76,7 +37,7 @@ const DEFAULT_V3_AGENT_SOFT_TIMEOUT_MS = (() => {
76
37
  const parsed = Number.parseInt(rawValue, 10);
77
38
  return Number.isFinite(parsed) && parsed > 0 ? parsed : 180000;
78
39
  })();
79
- class ChatCommand {
40
+ export class ChatCommand {
80
41
  config;
81
42
  logger;
82
43
  api;
@@ -103,6 +64,7 @@ class ChatCommand {
103
64
  modelGovernanceFallback = null;
104
65
  retryPromptSignature = null;
105
66
  retryPromptStreak = 0;
67
+ v3SuppressThinkingStream = false;
106
68
  // Last completed Agent run — used by /retry, /continue, and the final summary block.
107
69
  lastAgentRunOutcome = null;
108
70
  isJwtExpirationError(error) {
@@ -152,32 +114,32 @@ class ChatCommand {
152
114
  message.includes('aborted');
153
115
  }
154
116
  toUserFacingApiError(error, context) {
155
- const classified = (0, api_js_1.classifyError)(error);
117
+ const classified = classifyError(error);
156
118
  const status = classified.statusCode || (this.isJwtExpirationError(error) ? 401 : 500);
157
119
  if (this.isJwtExpirationError(error) || classified.category === 'auth') {
158
- return new api_js_1.CLIError('Your Vigthoria session has expired. Run `vigthoria login` to authenticate again.', 'auth', { statusCode: 401 });
120
+ return new CLIError('Your Vigthoria session has expired. Run `vigthoria login` to authenticate again.', 'auth', { statusCode: 401 });
159
121
  }
160
122
  // Preserve structured API classification first (auth/model/network/etc.)
161
123
  // so upstream responses are not relabeled by message heuristics.
162
124
  if (classified.category === 'timeout') {
163
- return new api_js_1.CLIError(`${context} timed out. Check your connection and try again.`, 'timeout', { statusCode: status });
125
+ return new CLIError(`${context} timed out. Check your connection and try again.`, 'timeout', { statusCode: status });
164
126
  }
165
127
  if (classified.category === 'network') {
166
- return new api_js_1.CLIError(`${context} could not reach the Vigthoria API. Check your network connection and try again.`, 'network', { statusCode: status });
128
+ return new CLIError(`${context} could not reach the Vigthoria API. Check your network connection and try again.`, 'network', { statusCode: status });
167
129
  }
168
130
  if (classified.category === 'model_backend') {
169
- return new api_js_1.CLIError(api_js_1.VIGTHORIA_SERVER_TEMPORARILY_UNAVAILABLE_MESSAGE, 'model_backend', { statusCode: status, endpoint: classified.endpoint });
131
+ return new CLIError(VIGTHORIA_SERVER_TEMPORARILY_UNAVAILABLE_MESSAGE, 'model_backend', { statusCode: status, endpoint: classified.endpoint });
170
132
  }
171
- const message = (0, api_js_1.sanitizeUserFacingErrorText)(classified.message || `${context} failed`);
172
- return new api_js_1.CLIError(message, 'model_backend', { statusCode: status, endpoint: classified.endpoint });
133
+ const message = sanitizeUserFacingErrorText(classified.message || `${context} failed`);
134
+ return new CLIError(message, 'model_backend', { statusCode: status, endpoint: classified.endpoint });
173
135
  }
174
136
  handleApiError(error, context) {
175
137
  const userFacingError = this.toUserFacingApiError(error, context);
176
138
  if (!this.jsonOutput) {
177
- console.error(chalk_1.default.red(`${context} failed: ${userFacingError.message}`));
139
+ console.error(chalk.red(`${context} failed: ${userFacingError.message}`));
178
140
  }
179
141
  const original = error && typeof error === 'object' ? error : { message: String(error) };
180
- (0, api_js_1.propagateError)({
142
+ propagateError({
181
143
  ...original,
182
144
  message: userFacingError.message,
183
145
  statusCode: userFacingError.statusCode,
@@ -378,10 +340,10 @@ class ChatCommand {
378
340
  getActivePersonaMode() {
379
341
  if (this.personaOverride)
380
342
  return this.personaOverride;
381
- return (0, persona_js_1.normalizePersonaMode)(this.config.get('persona')) || 'default';
343
+ return normalizePersonaMode(this.config.get('persona')) || 'default';
382
344
  }
383
345
  buildActivePersonaOverlay() {
384
- return (0, persona_js_1.buildPersonaOverlay)(this.getActivePersonaMode(), this.getLastUserPrompt());
346
+ return buildPersonaOverlay(this.getActivePersonaMode(), this.getLastUserPrompt());
385
347
  }
386
348
  isDiagnosticPrompt(prompt) {
387
349
  return /(startup|start up|won'?t start|doesn'?t start|crash|crashes|error|errors|failing|fails|issue|issues|bug|bugs|diagnos|debug|runtime|log|logs|exception|traceback|stack trace|yaml|blocking|blocker)/i.test(prompt);
@@ -489,12 +451,12 @@ class ChatCommand {
489
451
  return candidate;
490
452
  }
491
453
  if (!this.jsonOutput) {
492
- console.log(chalk_1.default.yellow(`Ignoring path outside allowed workspace roots: ${candidate}`));
454
+ console.log(chalk.yellow(`Ignoring path outside allowed workspace roots: ${candidate}`));
493
455
  if (allowedRoots.length > 0) {
494
456
  const displayRoots = allowedRoots.map((root) => root.replace(/\\/g, '/')).join(', ');
495
- console.log(chalk_1.default.gray(`Allowed roots: ${displayRoots}`));
457
+ console.log(chalk.gray(`Allowed roots: ${displayRoots}`));
496
458
  }
497
- console.log(chalk_1.default.gray('To allow unrestricted prompt path overrides, set VIGTHORIA_ALLOW_UNSCOPED_PROMPT_PATHS=1.'));
459
+ console.log(chalk.gray('To allow unrestricted prompt path overrides, set VIGTHORIA_ALLOW_UNSCOPED_PROMPT_PATHS=1.'));
498
460
  }
499
461
  return null;
500
462
  }
@@ -596,7 +558,7 @@ class ChatCommand {
596
558
  }
597
559
  try {
598
560
  if (!this.projectMemory) {
599
- this.projectMemory = new project_memory_js_1.ProjectMemoryService(this.currentProjectPath);
561
+ this.projectMemory = new ProjectMemoryService(this.currentProjectPath);
600
562
  }
601
563
  const status = this.projectMemory.getStatus();
602
564
  const context = this.projectMemory.buildContextForPrompt(prompt);
@@ -622,7 +584,7 @@ class ChatCommand {
622
584
  }
623
585
  try {
624
586
  if (!this.projectMemory) {
625
- this.projectMemory = new project_memory_js_1.ProjectMemoryService(this.currentProjectPath);
587
+ this.projectMemory = new ProjectMemoryService(this.currentProjectPath);
626
588
  }
627
589
  this.projectMemory.remember(type, text, { source: 'vigthoria-cli', mode, model: this.currentModel });
628
590
  }
@@ -644,7 +606,7 @@ class ChatCommand {
644
606
  const devtoolsBridgeAllowed = /^(1|true|yes)$/i.test(String(process.env.VIGTHORIA_DEVTOOLS_BRIDGE_ALLOWED || process.env.VIGTHORIA_BRIDGE_ALLOWED || ''));
645
607
  if (!devtoolsBridgeAllowed) {
646
608
  if (!this.jsonOutput) {
647
- console.log(chalk_1.default.yellow('Browser task detected. DevTools Bridge is opt-in; the agent will ask before relying on local browser tooling.'));
609
+ console.log(chalk.yellow('Browser task detected. DevTools Bridge is opt-in; the agent will ask before relying on local browser tooling.'));
648
610
  }
649
611
  return {
650
612
  ...runtimeContext,
@@ -656,10 +618,10 @@ class ChatCommand {
656
618
  }
657
619
  const bridgeStatus = await this.callApi('Checking DevTools Bridge status', () => this.api.getDevtoolsBridgeStatus(), 0);
658
620
  if (!this.jsonOutput && bridgeStatus.ok) {
659
- console.log(chalk_1.default.gray(`Browser task detected. DevTools Bridge is reachable at ${bridgeStatus.endpoint}.`));
621
+ console.log(chalk.gray(`Browser task detected. DevTools Bridge is reachable at ${bridgeStatus.endpoint}.`));
660
622
  }
661
623
  else if (!this.jsonOutput) {
662
- console.log(chalk_1.default.yellow(`Browser task detected. DevTools Bridge is not running at ${bridgeStatus.endpoint}.`));
624
+ console.log(chalk.yellow(`Browser task detected. DevTools Bridge is not running at ${bridgeStatus.endpoint}.`));
663
625
  }
664
626
  return {
665
627
  ...runtimeContext,
@@ -680,7 +642,7 @@ class ChatCommand {
680
642
  sanitizeServerPath(text) {
681
643
  if (!text)
682
644
  return text;
683
- return (0, api_js_1.sanitizeUserFacingPathText)(this.stripHiddenThoughtBlocks(text));
645
+ return sanitizeUserFacingPathText(this.stripHiddenThoughtBlocks(text));
684
646
  }
685
647
  stripHiddenThoughtBlocks(text) {
686
648
  if (!text)
@@ -722,12 +684,12 @@ class ChatCommand {
722
684
  const source = (event && typeof event === 'object' && !Buffer.isBuffer(event) && !(event instanceof Uint8Array))
723
685
  ? (event.body ?? event.stream ?? event.response ?? event)
724
686
  : event;
725
- for await (const chunk of (0, tools_js_1.robustifyStreamResponse)(source)) {
687
+ for await (const chunk of robustifyStreamResponse(source)) {
726
688
  this.v3LastActivity = Date.now();
727
689
  if (chunk.type === 'error') {
728
690
  if (spinner.isSpinning)
729
691
  spinner.stop();
730
- process.stderr.write(chalk_1.default.red(`\nStream error: ${chunk.content}\n`));
692
+ process.stderr.write(chalk.red(`\nStream error: ${chunk.content}\n`));
731
693
  continue;
732
694
  }
733
695
  if (chunk.content) {
@@ -739,11 +701,11 @@ class ChatCommand {
739
701
  const message = error instanceof Error ? error.message : String(error);
740
702
  if (spinner.isSpinning)
741
703
  spinner.stop();
742
- process.stderr.write(chalk_1.default.red(`\nStream error: ${message}\n`));
704
+ process.stderr.write(chalk.red(`\nStream error: ${message}\n`));
743
705
  }
744
706
  }
745
707
  writeV3StreamText(spinner, text) {
746
- const safeText = this.sanitizeServerPath(text);
708
+ const safeText = this.sanitizeV3VisibleStreamText(this.sanitizeServerPath(text));
747
709
  if (!safeText) {
748
710
  return;
749
711
  }
@@ -759,13 +721,41 @@ class ChatCommand {
759
721
  }
760
722
  process.stdout.write(safeText);
761
723
  }
724
+ sanitizeV3VisibleStreamText(text) {
725
+ let output = String(text || '');
726
+ if (!output)
727
+ return '';
728
+ output = output.replace(/<\/think>/gi, '</thinking>');
729
+ output = output.replace(/<think>/gi, '<thinking>');
730
+ if (this.v3SuppressThinkingStream) {
731
+ const closeIdx = output.search(/<\/thinking>/i);
732
+ if (closeIdx < 0) {
733
+ return '';
734
+ }
735
+ output = output.slice(closeIdx).replace(/^<\/thinking>/i, '');
736
+ this.v3SuppressThinkingStream = false;
737
+ }
738
+ output = output.replace(/<thinking>[\s\S]*?<\/thinking>/gi, '');
739
+ if (/<thinking>/i.test(output)) {
740
+ output = output.replace(/<thinking>[\s\S]*$/i, '');
741
+ this.v3SuppressThinkingStream = true;
742
+ }
743
+ output = output
744
+ .replace(/```json\s*\[\s*\{[\s\S]*?"tool"[\s\S]*?\}\s*\]\s*```/gi, '')
745
+ .replace(/```json\s*\{[\s\S]*?"tool"[\s\S]*?\}\s*```/gi, '')
746
+ .replace(/^\s*(?:json\s*)?\[\s*\{[\s\S]*?"tool"[\s\S]*$/gim, '')
747
+ .replace(/^\s*(?:list_dir|read_file|write_file|edit_file|glob|grep|bash)\s*$/gim, '')
748
+ .replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, '')
749
+ .replace(/\n{3,}/g, '\n\n');
750
+ return output;
751
+ }
762
752
  updateV3AgentSpinner(spinner, event) {
763
753
  if (this.isRawV3StreamPayload(event)) {
764
754
  this.consumeV3StreamPayload(spinner, event).catch((error) => {
765
755
  const message = error instanceof Error ? error.message : String(error);
766
756
  if (spinner.isSpinning)
767
757
  spinner.stop();
768
- process.stderr.write(chalk_1.default.red(`\nStream error: ${message}\n`));
758
+ process.stderr.write(chalk.red(`\nStream error: ${message}\n`));
769
759
  });
770
760
  return;
771
761
  }
@@ -779,7 +769,7 @@ class ChatCommand {
779
769
  const toolTarget = event.arguments?.path || event.arguments?.file_path || event.arguments?.pattern || '';
780
770
  const sanitizedTarget = this.sanitizeServerPath(String(toolTarget));
781
771
  const shortTarget = sanitizedTarget ? ` → ${sanitizedTarget.replace(/\\/g, '/').split('/').slice(-2).join('/')}` : '';
782
- const stepLabel = chalk_1.default.cyan(` [${this.v3IterationCount}/${this.v3ToolCallCount}]`) + ` ${toolDesc}${shortTarget}`;
772
+ const stepLabel = chalk.cyan(` [${this.v3IterationCount}/${this.v3ToolCallCount}]`) + ` ${toolDesc}${shortTarget}`;
783
773
  if (spinner.isSpinning)
784
774
  spinner.stop();
785
775
  process.stderr.write(stepLabel + '\n');
@@ -788,11 +778,11 @@ class ChatCommand {
788
778
  const toolName = event.name || event.tool || '';
789
779
  if ((toolName === 'write_file' || toolName === 'edit_file') && typeof args.content === 'string') {
790
780
  const len = args.content.length;
791
- process.stderr.write(chalk_1.default.gray(` ${len > 1000 ? Math.round(len / 1024) + ' KB' : len + ' bytes'} content\n`));
781
+ process.stderr.write(chalk.gray(` ${len > 1000 ? Math.round(len / 1024) + ' KB' : len + ' bytes'} content\n`));
792
782
  }
793
783
  else if (toolName === 'bash' && typeof args.command === 'string') {
794
784
  const command = this.sanitizeServerPath(args.command);
795
- process.stderr.write(chalk_1.default.gray(` $ ${command.slice(0, 120)}${command.length > 120 ? '…' : ''}\n`));
785
+ process.stderr.write(chalk.gray(` $ ${command.slice(0, 120)}${command.length > 120 ? '…' : ''}\n`));
796
786
  }
797
787
  spinner.start();
798
788
  spinner.text = `Running ${toolDesc}...`;
@@ -801,7 +791,7 @@ class ChatCommand {
801
791
  if (event.type === 'tool_result') {
802
792
  const success = event.success !== false;
803
793
  const toolName = event.name || event.tool || '';
804
- const indicator = success ? chalk_1.default.green(' ✓') : chalk_1.default.red(' ✗');
794
+ const indicator = success ? chalk.green(' ✓') : chalk.red(' ✗');
805
795
  if (spinner.isSpinning)
806
796
  spinner.stop();
807
797
  process.stderr.write(`${indicator} ${toolName}\n`);
@@ -811,11 +801,11 @@ class ChatCommand {
811
801
  if (!success && output) {
812
802
  const sanitizedError = this.sanitizeServerPath(typeof event.error === 'string' ? event.error : output);
813
803
  const lines = sanitizedError.split('\n').slice(0, 4);
814
- process.stderr.write(chalk_1.default.red(` ${lines.join('\n ')}\n`));
804
+ process.stderr.write(chalk.red(` ${lines.join('\n ')}\n`));
815
805
  }
816
806
  else if (success && output && output.length > 0) {
817
807
  const brief = output.split('\n')[0].slice(0, 120);
818
- process.stderr.write(chalk_1.default.gray(` ${brief}${output.length > 120 ? '…' : ''}\n`));
808
+ process.stderr.write(chalk.gray(` ${brief}${output.length > 120 ? '…' : ''}\n`));
819
809
  }
820
810
  spinner.start();
821
811
  spinner.text = 'Next step...';
@@ -830,7 +820,7 @@ class ChatCommand {
830
820
  const iterText = this.sanitizeServerPath(event.content || '');
831
821
  if (spinner.isSpinning)
832
822
  spinner.stop();
833
- process.stderr.write(chalk_1.default.cyan(`\n── ${iterText || `Iteration ${this.v3IterationCount}`} ──\n`));
823
+ process.stderr.write(chalk.cyan(`\n── ${iterText || `Iteration ${this.v3IterationCount}`} ──\n`));
834
824
  spinner.start();
835
825
  spinner.text = 'Analyzing...';
836
826
  return;
@@ -844,7 +834,7 @@ class ChatCommand {
844
834
  this.writeV3StreamText(spinner, text);
845
835
  }
846
836
  else {
847
- spinner.text = chalk_1.default.cyan('[Response] ') + 'Writing response...';
837
+ spinner.text = chalk.cyan('[Response] ') + 'Writing response...';
848
838
  }
849
839
  return;
850
840
  }
@@ -862,15 +852,15 @@ class ChatCommand {
862
852
  const fail = event.tasks_failed ?? 0;
863
853
  statLine += ` — ${ok} tasks done`;
864
854
  if (fail > 0)
865
- statLine += chalk_1.default.yellow(`, ${fail} failed`);
855
+ statLine += chalk.yellow(`, ${fail} failed`);
866
856
  }
867
- process.stderr.write(chalk_1.default.green(`\n✓ Complete`) + ` — ${statLine}\n`);
857
+ process.stderr.write(chalk.green(`\n✓ Complete`) + ` — ${statLine}\n`);
868
858
  // Show seal quality score if available
869
859
  if (event.seal_score && typeof event.seal_score.overall === 'number') {
870
860
  const score = event.seal_score.overall;
871
861
  const tier = event.seal_score.tier || '';
872
- const scoreColor = score >= 7 ? chalk_1.default.green : score >= 5 ? chalk_1.default.yellow : chalk_1.default.red;
873
- process.stderr.write(chalk_1.default.cyan(' [Quality] ') + scoreColor(`${score}/10`) + (tier ? chalk_1.default.gray(` (${tier})`) : '') + '\n');
862
+ const scoreColor = score >= 7 ? chalk.green : score >= 5 ? chalk.yellow : chalk.red;
863
+ process.stderr.write(chalk.cyan(' [Quality] ') + scoreColor(`${score}/10`) + (tier ? chalk.gray(` (${tier})`) : '') + '\n');
874
864
  }
875
865
  return;
876
866
  }
@@ -887,33 +877,33 @@ class ChatCommand {
887
877
  }
888
878
  if (spinner.isSpinning)
889
879
  spinner.stop();
890
- process.stderr.write(chalk_1.default.cyan(` [Plan] `) + `Task: ${planKind || 'analyzing'}`);
880
+ process.stderr.write(chalk.cyan(` [Plan] `) + `Task: ${planKind || 'analyzing'}`);
891
881
  if (quality)
892
- process.stderr.write(chalk_1.default.gray(` (${quality})`));
882
+ process.stderr.write(chalk.gray(` (${quality})`));
893
883
  process.stderr.write('\n');
894
884
  if (summary) {
895
- process.stderr.write(chalk_1.default.gray(` ${summary}\n`));
885
+ process.stderr.write(chalk.gray(` ${summary}\n`));
896
886
  }
897
887
  if (status === 'planning' && Number.isFinite(Number(plan.elapsed_seconds))) {
898
- process.stderr.write(chalk_1.default.gray(` elapsed: ${plan.elapsed_seconds}s\n`));
888
+ process.stderr.write(chalk.gray(` elapsed: ${plan.elapsed_seconds}s\n`));
899
889
  }
900
890
  if (Array.isArray(plan.tasks) && plan.tasks.length > 0) {
901
- process.stderr.write(chalk_1.default.gray(` ${plan.total_tasks || plan.tasks.length} tasks:\n`));
891
+ process.stderr.write(chalk.gray(` ${plan.total_tasks || plan.tasks.length} tasks:\n`));
902
892
  for (const t of plan.tasks.slice(0, 10)) {
903
893
  const targets = Array.isArray(t.targets) && t.targets.length ? ` → ${t.targets.map((target) => this.sanitizeServerPath(String(target))).join(', ')}` : '';
904
- process.stderr.write(chalk_1.default.gray(` • ${this.sanitizeServerPath(String(t.title || t.id))}${targets}\n`));
894
+ process.stderr.write(chalk.gray(` • ${this.sanitizeServerPath(String(t.title || t.id))}${targets}\n`));
905
895
  }
906
896
  if (plan.tasks.length > 10) {
907
- process.stderr.write(chalk_1.default.gray(` ... and ${plan.tasks.length - 10} more\n`));
897
+ process.stderr.write(chalk.gray(` ... and ${plan.tasks.length - 10} more\n`));
908
898
  }
909
899
  }
910
900
  if (Array.isArray(plan.notes) && plan.notes.length > 0) {
911
901
  for (const note of plan.notes.slice(0, 3)) {
912
- process.stderr.write(chalk_1.default.gray(` note: ${this.sanitizeServerPath(String(note))}\n`));
902
+ process.stderr.write(chalk.gray(` note: ${this.sanitizeServerPath(String(note))}\n`));
913
903
  }
914
904
  }
915
905
  if (Array.isArray(plan.target_files) && plan.target_files.length > 0) {
916
- process.stderr.write(chalk_1.default.gray(` Files: ${plan.target_files.map((filePath) => this.sanitizeServerPath(String(filePath))).join(', ')}\n`));
906
+ process.stderr.write(chalk.gray(` Files: ${plan.target_files.map((filePath) => this.sanitizeServerPath(String(filePath))).join(', ')}\n`));
917
907
  }
918
908
  spinner.start();
919
909
  spinner.text = status === 'planning' ? 'Planning...' : 'Executing plan...';
@@ -922,7 +912,7 @@ class ChatCommand {
922
912
  if (event.type === 'executor_start') {
923
913
  if (spinner.isSpinning)
924
914
  spinner.stop();
925
- process.stderr.write(chalk_1.default.cyan(' [Executor] ') + `Starting ${this.sanitizeServerPath(String(event.task_id || 'task'))}${event.title ? ` - ${this.sanitizeServerPath(String(event.title))}` : ''}
915
+ process.stderr.write(chalk.cyan(' [Executor] ') + `Starting ${this.sanitizeServerPath(String(event.task_id || 'task'))}${event.title ? ` - ${this.sanitizeServerPath(String(event.title))}` : ''}
926
916
  `);
927
917
  spinner.start();
928
918
  spinner.text = 'Vigthoria Executor running...';
@@ -931,8 +921,8 @@ class ChatCommand {
931
921
  if (event.type === 'executor_error') {
932
922
  if (spinner.isSpinning)
933
923
  spinner.stop();
934
- const msg = (0, api_js_1.sanitizeUserFacingErrorText)(String(event.error || 'Executor error')) || 'Executor error';
935
- process.stderr.write(chalk_1.default.red(' [Executor] ') + `Vigthoria Executor encountered an issue: ${msg}
924
+ const msg = sanitizeUserFacingErrorText(String(event.error || 'Executor error')) || 'Executor error';
925
+ process.stderr.write(chalk.red(' [Executor] ') + `Vigthoria Executor encountered an issue: ${msg}
936
926
  `);
937
927
  spinner.start();
938
928
  spinner.text = 'Recovering executor...';
@@ -945,11 +935,11 @@ class ChatCommand {
945
935
  const status = String(summary.status || 'completed');
946
936
  const changed = Array.isArray(summary.changed_files) ? summary.changed_files.length : 0;
947
937
  if (status === 'failed') {
948
- process.stderr.write(chalk_1.default.red(' [Executor] ') + `Vigthoria Executor task failed${summary.task_id ? ` (${summary.task_id})` : ''}.
938
+ process.stderr.write(chalk.red(' [Executor] ') + `Vigthoria Executor task failed${summary.task_id ? ` (${summary.task_id})` : ''}.
949
939
  `);
950
940
  }
951
941
  else {
952
- process.stderr.write(chalk_1.default.green(' [Executor] ') + `Task completed${summary.task_id ? ` (${summary.task_id})` : ''}${changed ? `, ${changed} files changed` : ''}.
942
+ process.stderr.write(chalk.green(' [Executor] ') + `Task completed${summary.task_id ? ` (${summary.task_id})` : ''}${changed ? `, ${changed} files changed` : ''}.
953
943
  `);
954
944
  }
955
945
  spinner.start();
@@ -959,11 +949,11 @@ class ChatCommand {
959
949
  if (event.type === 'file_mutation') {
960
950
  const rawPath = typeof event.path === 'string' ? this.sanitizeServerPath(event.path) : '';
961
951
  const filePath = rawPath ? rawPath.replace(/\\/g, '/').split('/').slice(-2).join('/') : '';
962
- const action = event.action === 'delete' ? chalk_1.default.red('deleted') : chalk_1.default.green('wrote');
952
+ const action = event.action === 'delete' ? chalk.red('deleted') : chalk.green('wrote');
963
953
  if (filePath) {
964
954
  if (spinner.isSpinning)
965
955
  spinner.stop();
966
- process.stderr.write(chalk_1.default.cyan(' [File] ') + `${action} ${filePath}\n`);
956
+ process.stderr.write(chalk.cyan(' [File] ') + `${action} ${filePath}\n`);
967
957
  spinner.start();
968
958
  }
969
959
  return;
@@ -972,23 +962,23 @@ class ChatCommand {
972
962
  if (event.checkpointed) {
973
963
  if (spinner.isSpinning)
974
964
  spinner.stop();
975
- process.stderr.write(chalk_1.default.yellow(' [Checkpoint] ') + 'Budget reached — auto-continuing...\n');
965
+ process.stderr.write(chalk.yellow(' [Checkpoint] ') + 'Budget reached — auto-continuing...\n');
976
966
  spinner.start();
977
967
  }
978
968
  else {
979
969
  if (spinner.isSpinning)
980
970
  spinner.stop();
981
- const message = (0, api_js_1.sanitizeUserFacingErrorText)(String(event.message || 'Agent error')) || 'Agent error';
971
+ const message = sanitizeUserFacingErrorText(String(event.message || 'Agent error')) || 'Agent error';
982
972
  const plannerLike = /plan|planner|dependency graph/i.test(message);
983
973
  const executorLike = /executor|task failed|iteration/i.test(message);
984
974
  if (plannerLike) {
985
- process.stderr.write(chalk_1.default.red(' [Planner] ') + `Vigthoria Planner encountered an issue: ${this.sanitizeServerPath(message)}\n`);
975
+ process.stderr.write(chalk.red(' [Planner] ') + `Vigthoria Planner encountered an issue: ${this.sanitizeServerPath(message)}\n`);
986
976
  }
987
977
  else if (executorLike) {
988
- process.stderr.write(chalk_1.default.red(' [Executor] ') + `Vigthoria Executor encountered an issue: ${this.sanitizeServerPath(message)}\n`);
978
+ process.stderr.write(chalk.red(' [Executor] ') + `Vigthoria Executor encountered an issue: ${this.sanitizeServerPath(message)}\n`);
989
979
  }
990
980
  else {
991
- process.stderr.write(chalk_1.default.red(' [Error] ') + this.sanitizeServerPath(message) + '\n');
981
+ process.stderr.write(chalk.red(' [Error] ') + this.sanitizeServerPath(message) + '\n');
992
982
  }
993
983
  }
994
984
  return;
@@ -996,7 +986,7 @@ class ChatCommand {
996
986
  if (event.type === 'context') {
997
987
  if (spinner.isSpinning)
998
988
  spinner.stop();
999
- process.stderr.write(chalk_1.default.cyan(' [Context] ') + 'Workspace bound\n');
989
+ process.stderr.write(chalk.cyan(' [Context] ') + 'Workspace bound\n');
1000
990
  spinner.start();
1001
991
  spinner.text = 'Starting agent...';
1002
992
  return;
@@ -1006,7 +996,7 @@ class ChatCommand {
1006
996
  this.v3ToolCallCount = 0;
1007
997
  if (spinner.isSpinning)
1008
998
  spinner.stop();
1009
- process.stderr.write(chalk_1.default.cyan(' [Start] ') + 'Agent initialized\n');
999
+ process.stderr.write(chalk.cyan(' [Start] ') + 'Agent initialized\n');
1010
1000
  spinner.start();
1011
1001
  spinner.text = 'Working...';
1012
1002
  return;
@@ -1020,7 +1010,7 @@ class ChatCommand {
1020
1010
  if (spinner.isSpinning)
1021
1011
  spinner.stop();
1022
1012
  if (fallbackMessage) {
1023
- process.stderr.write(chalk_1.default.cyan(' [V3] ') + `${fallbackMessage}\n`);
1013
+ process.stderr.write(chalk.cyan(' [V3] ') + `${fallbackMessage}\n`);
1024
1014
  }
1025
1015
  spinner.start();
1026
1016
  spinner.text = fallbackStatus || fallbackStage || 'Working...';
@@ -1034,7 +1024,7 @@ class ChatCommand {
1034
1024
  if (event.type === 'started') {
1035
1025
  if (spinner.isSpinning)
1036
1026
  spinner.stop();
1037
- process.stderr.write(chalk_1.default.cyan(' [Operator] ') + 'Starting BMAD workflow...\n');
1027
+ process.stderr.write(chalk.cyan(' [Operator] ') + 'Starting BMAD workflow...\n');
1038
1028
  spinner.start();
1039
1029
  spinner.text = 'Connecting...';
1040
1030
  return;
@@ -1042,7 +1032,7 @@ class ChatCommand {
1042
1032
  if (event.type === 'connected') {
1043
1033
  if (spinner.isSpinning)
1044
1034
  spinner.stop();
1045
- process.stderr.write(chalk_1.default.green(' ✓') + ' Connected to BMAD stream\n');
1035
+ process.stderr.write(chalk.green(' ✓') + ' Connected to BMAD stream\n');
1046
1036
  spinner.start();
1047
1037
  spinner.text = 'Working...';
1048
1038
  return;
@@ -1051,7 +1041,7 @@ class ChatCommand {
1051
1041
  const agentName = event.agent || 'BMAD agent';
1052
1042
  if (spinner.isSpinning)
1053
1043
  spinner.stop();
1054
- process.stderr.write(chalk_1.default.cyan(` [Agent] `) + agentName + '\n');
1044
+ process.stderr.write(chalk.cyan(` [Agent] `) + agentName + '\n');
1055
1045
  spinner.start();
1056
1046
  spinner.text = `Running ${agentName}...`;
1057
1047
  return;
@@ -1061,7 +1051,7 @@ class ChatCommand {
1061
1051
  const statusText = `${event.status || 'Working'}${progress}`;
1062
1052
  if (spinner.isSpinning)
1063
1053
  spinner.stop();
1064
- process.stderr.write(chalk_1.default.cyan(' [Status] ') + statusText + '\n');
1054
+ process.stderr.write(chalk.cyan(' [Status] ') + statusText + '\n');
1065
1055
  spinner.start();
1066
1056
  spinner.text = statusText;
1067
1057
  return;
@@ -1069,15 +1059,15 @@ class ChatCommand {
1069
1059
  if (event.type === 'result') {
1070
1060
  if (spinner.isSpinning)
1071
1061
  spinner.stop();
1072
- process.stderr.write(chalk_1.default.green('\n ✓ Operator workflow complete\n'));
1062
+ process.stderr.write(chalk.green('\n ✓ Operator workflow complete\n'));
1073
1063
  return;
1074
1064
  }
1075
1065
  }
1076
1066
  constructor(config, logger) {
1077
1067
  this.config = config;
1078
1068
  this.logger = logger;
1079
- this.api = new api_js_1.APIClient(config, logger);
1080
- this.sessionManager = new session_js_1.SessionManager();
1069
+ this.api = new APIClient(config, logger);
1070
+ this.sessionManager = new SessionManager();
1081
1071
  }
1082
1072
  async run(options) {
1083
1073
  if (!this.config.isAuthenticated()) {
@@ -1103,8 +1093,8 @@ class ChatCommand {
1103
1093
  this.currentModel = this.resolveInitialModel(options);
1104
1094
  this.applyNoAgentGovernance(String(options.model || this.currentModel || ''));
1105
1095
  this.currentProjectPath = this.resolveProjectPath(options);
1106
- if ((this.agentMode || this.operatorMode) && (0, agent_session_menu_js_1.shouldShowAgentSessionMenu)(options)) {
1107
- const sessionConfig = await (0, agent_session_menu_js_1.runAgentSessionMenu)({
1096
+ if ((this.agentMode || this.operatorMode) && shouldShowAgentSessionMenu(options)) {
1097
+ const sessionConfig = await runAgentSessionMenu({
1108
1098
  workspacePath: this.currentProjectPath,
1109
1099
  autoApprove: this.autoApprove,
1110
1100
  });
@@ -1114,7 +1104,7 @@ class ChatCommand {
1114
1104
  if (sessionConfig.debugMode) {
1115
1105
  process.env.DEBUG = process.env.DEBUG || 'vigthoria:*';
1116
1106
  }
1117
- console.log(chalk_1.default.green(`Using workspace: ${this.currentProjectPath}`));
1107
+ console.log(chalk.green(`Using workspace: ${this.currentProjectPath}`));
1118
1108
  }
1119
1109
  if (this.jsonOutput && !options.prompt) {
1120
1110
  throw new Error('--json is only supported together with --prompt.');
@@ -1122,11 +1112,11 @@ class ChatCommand {
1122
1112
  this.ensureProjectWorkspace();
1123
1113
  this.directPromptMode = Boolean(options.prompt);
1124
1114
  this.directToolContinuationCount = 0;
1125
- this.tools = new tools_js_1.AgenticTools(this.logger, this.currentProjectPath, async (action) => this.requestPermission(action), this.autoApprove);
1115
+ this.tools = new AgenticTools(this.logger, this.currentProjectPath, async (action) => this.requestPermission(action), this.autoApprove);
1126
1116
  this.initializeSession(options.resume === true);
1127
1117
  // ── Commando Bridge: connect if --bridge was specified ──────────
1128
1118
  if (options.bridge) {
1129
- const bridgeClient = new bridge_client_js_1.BridgeClient({
1119
+ const bridgeClient = new BridgeClient({
1130
1120
  bridgeUrl: options.bridge,
1131
1121
  apiKey: this.config.get('authToken'),
1132
1122
  onAdminCommand: (cmd) => this.handleAdminCommand(cmd),
@@ -1161,7 +1151,7 @@ class ChatCommand {
1161
1151
  const timeoutId = options.bridge && bridgePromptTimeoutMs > 0
1162
1152
  ? setTimeout(() => {
1163
1153
  timedOut = true;
1164
- const b = (0, bridge_client_js_1.getBridgeClient)();
1154
+ const b = getBridgeClient();
1165
1155
  if (b) {
1166
1156
  b.emitEnd({ reason: 'timeout' });
1167
1157
  b.destroy();
@@ -1176,7 +1166,7 @@ class ChatCommand {
1176
1166
  if (timeoutId)
1177
1167
  clearTimeout(timeoutId);
1178
1168
  if (!timedOut) {
1179
- const bridge = (0, bridge_client_js_1.getBridgeClient)();
1169
+ const bridge = getBridgeClient();
1180
1170
  if (bridge) {
1181
1171
  bridge.emitEnd({ reason: 'prompt-complete' });
1182
1172
  bridge.destroy();
@@ -1188,7 +1178,7 @@ class ChatCommand {
1188
1178
  process.exit(process.exitCode ?? 0);
1189
1179
  }
1190
1180
  await this.startInteractiveChat();
1191
- const bridge = (0, bridge_client_js_1.getBridgeClient)();
1181
+ const bridge = getBridgeClient();
1192
1182
  if (bridge) {
1193
1183
  bridge.emitEnd({ reason: 'interactive-exit' });
1194
1184
  bridge.destroy();
@@ -1198,24 +1188,24 @@ class ChatCommand {
1198
1188
  handleAdminCommand(cmd) {
1199
1189
  switch (cmd.action) {
1200
1190
  case 'ping':
1201
- (0, bridge_client_js_1.getBridgeClient)()?.emitModelResponse({ model: this.currentModel, chars: 0, hasToolCalls: false, preview: 'pong' });
1191
+ getBridgeClient()?.emitModelResponse({ model: this.currentModel, chars: 0, hasToolCalls: false, preview: 'pong' });
1202
1192
  break;
1203
1193
  case 'set-model':
1204
1194
  if (cmd.params?.value && typeof cmd.params.value === 'string') {
1205
1195
  this.currentModel = cmd.params.value;
1206
- (0, bridge_client_js_1.getBridgeClient)()?.emitModeChange({ mode: this.operatorMode ? 'operator' : this.agentMode ? 'agent' : 'chat', model: this.currentModel });
1196
+ getBridgeClient()?.emitModeChange({ mode: this.operatorMode ? 'operator' : this.agentMode ? 'agent' : 'chat', model: this.currentModel });
1207
1197
  if (!this.jsonOutput)
1208
- console.log(chalk_1.default.yellow(`[bridge] Model changed to: ${this.currentModel}`));
1198
+ console.log(chalk.yellow(`[bridge] Model changed to: ${this.currentModel}`));
1209
1199
  }
1210
1200
  break;
1211
1201
  case 'abort':
1212
1202
  if (!this.jsonOutput)
1213
- console.log(chalk_1.default.red(`[bridge] Abort requested by admin`));
1214
- (0, bridge_client_js_1.getBridgeClient)()?.emitEnd({ reason: 'admin-abort' });
1203
+ console.log(chalk.red(`[bridge] Abort requested by admin`));
1204
+ getBridgeClient()?.emitEnd({ reason: 'admin-abort' });
1215
1205
  process.exit(0);
1216
1206
  break;
1217
1207
  default:
1218
- (0, bridge_client_js_1.getBridgeClient)()?.emitError({ message: `Unknown admin command: ${cmd.action}` });
1208
+ getBridgeClient()?.emitError({ message: `Unknown admin command: ${cmd.action}` });
1219
1209
  }
1220
1210
  }
1221
1211
  ensureProjectWorkspace() {
@@ -1251,13 +1241,13 @@ class ChatCommand {
1251
1241
  // Guardrail: do not watch broad home/root scopes on interactive shells.
1252
1242
  if (normalized.toLowerCase() === normalizedHome.toLowerCase()) {
1253
1243
  if (!this.jsonOutput) {
1254
- console.log(chalk_1.default.gray('Info: workspace watcher disabled for home directory scope.'));
1244
+ console.log(chalk.gray('Info: workspace watcher disabled for home directory scope.'));
1255
1245
  }
1256
1246
  return false;
1257
1247
  }
1258
1248
  if (/^[a-zA-Z]:\/$/.test(normalized) || normalized === '/') {
1259
1249
  if (!this.jsonOutput) {
1260
- console.log(chalk_1.default.gray('Info: workspace watcher disabled for filesystem root scope.'));
1250
+ console.log(chalk.gray('Info: workspace watcher disabled for filesystem root scope.'));
1261
1251
  }
1262
1252
  return false;
1263
1253
  }
@@ -1273,7 +1263,7 @@ class ChatCommand {
1273
1263
  const explicitPath = this.resolvePromptWorkspacePath(options.prompt, process.cwd());
1274
1264
  if (explicitPath) {
1275
1265
  if (!this.jsonOutput) {
1276
- console.log(chalk_1.default.gray(`📁 Using project path from prompt: ${explicitPath}`));
1266
+ console.log(chalk.gray(`📁 Using project path from prompt: ${explicitPath}`));
1277
1267
  }
1278
1268
  return explicitPath;
1279
1269
  }
@@ -1375,7 +1365,7 @@ class ChatCommand {
1375
1365
  return path.join(rootPath, `${folderName}-${Date.now()}`);
1376
1366
  }
1377
1367
  initializeSession(resume) {
1378
- this.projectMemory = new project_memory_js_1.ProjectMemoryService(this.currentProjectPath);
1368
+ this.projectMemory = new ProjectMemoryService(this.currentProjectPath);
1379
1369
  if (resume) {
1380
1370
  this.currentSession = this.sessionManager.getLatest(this.currentProjectPath);
1381
1371
  if (this.currentSession) {
@@ -1421,11 +1411,11 @@ class ChatCommand {
1421
1411
  // Suppress all setup banners in direct-prompt mode so only the final
1422
1412
  // answer reaches stdout. Interactive (REPL) mode still shows them.
1423
1413
  if (!this.jsonOutput) {
1424
- console.log(chalk_1.default.cyan('Running single prompt in direct mode.'));
1425
- console.log(chalk_1.default.gray(`Model: ${this.currentModel}`));
1426
- console.log(chalk_1.default.gray(`Project: ${this.currentProjectPath}`));
1414
+ console.log(chalk.cyan('Running single prompt in direct mode.'));
1415
+ console.log(chalk.gray(`Model: ${this.currentModel}`));
1416
+ console.log(chalk.gray(`Project: ${this.currentProjectPath}`));
1427
1417
  if (this.workflowTarget) {
1428
- console.log(chalk_1.default.gray(`Workflow target: ${this.workflowTarget}`));
1418
+ console.log(chalk.gray(`Workflow target: ${this.workflowTarget}`));
1429
1419
  }
1430
1420
  console.log();
1431
1421
  }
@@ -1489,7 +1479,7 @@ class ChatCommand {
1489
1479
  const runtimeContext = await this.getPromptRuntimeContext(prompt);
1490
1480
  const resolvedWorkflow = await this.callApi('Resolve VigFlow workflow', () => this.api.resolveVigFlowWorkflow(selector));
1491
1481
  const invocationMode = this.operatorMode ? 'operator' : this.agentMode ? 'agent' : 'chat';
1492
- const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({ text: `Running workflow ${resolvedWorkflow.name}...`, spinner: 'clock' }).start();
1482
+ const spinner = this.jsonOutput ? null : createSpinner({ text: `Running workflow ${resolvedWorkflow.name}...`, spinner: 'clock' }).start();
1493
1483
  try {
1494
1484
  const execution = await this.callApi('Run VigFlow workflow', () => this.api.runVigFlowWorkflow(resolvedWorkflow.id, {
1495
1485
  data: {
@@ -1538,9 +1528,9 @@ class ChatCommand {
1538
1528
  return;
1539
1529
  }
1540
1530
  this.logger.success(`Workflow target ${resolvedWorkflow.name} ${execution.status}`);
1541
- console.log(chalk_1.default.gray(`Workflow ID: ${resolvedWorkflow.id}`));
1542
- console.log(chalk_1.default.gray(`Execution ID: ${execution.executionId}`));
1543
- console.log(chalk_1.default.gray(`Mode: ${invocationMode}`));
1531
+ console.log(chalk.gray(`Workflow ID: ${resolvedWorkflow.id}`));
1532
+ console.log(chalk.gray(`Execution ID: ${execution.executionId}`));
1533
+ console.log(chalk.gray(`Mode: ${invocationMode}`));
1544
1534
  if (content) {
1545
1535
  console.log(content);
1546
1536
  }
@@ -1583,9 +1573,9 @@ class ChatCommand {
1583
1573
  await this.runLocalAgentLoop(prompt);
1584
1574
  return;
1585
1575
  }
1586
- (0, bridge_client_js_1.getBridgeClient)()?.emitPrompt({ prompt, mode: 'operator', model: this.currentModel });
1576
+ getBridgeClient()?.emitPrompt({ prompt, mode: 'operator', model: this.currentModel });
1587
1577
  const runtimeContext = await this.getPromptRuntimeContext(prompt);
1588
- const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({ text: 'Thinking like an operator...', spinner: 'clock' }).start();
1578
+ const spinner = this.jsonOutput ? null : createSpinner({ text: 'Thinking like an operator...', spinner: 'clock' }).start();
1589
1579
  const workflowType = 'full';
1590
1580
  const executionPrompt = this.buildExecutionPrompt(prompt);
1591
1581
  try {
@@ -1613,7 +1603,7 @@ class ChatCommand {
1613
1603
  const isPolicyAck = /^(i will follow|i understand|i('ll| will) adhere|understood[.,!]|sure[.,!]|provide your|waiting for|i('ll| will) proceed)/i.test(responseText)
1614
1604
  || (responseText.length < 200 && /follow the instructions|next instruction|ready to assist/i.test(responseText));
1615
1605
  if (isPolicyAck) {
1616
- throw new api_js_1.CLIError('Operator workflow returned a non-actionable acknowledgement instead of a grounded result.', 'model_backend');
1606
+ throw new CLIError('Operator workflow returned a non-actionable acknowledgement instead of a grounded result.', 'model_backend');
1617
1607
  }
1618
1608
  if (this.jsonOutput) {
1619
1609
  console.log(JSON.stringify({
@@ -1629,7 +1619,7 @@ class ChatCommand {
1629
1619
  else {
1630
1620
  console.log(response.content || 'Operator workflow completed.');
1631
1621
  if (response.savedWorkflow?.id) {
1632
- console.log(chalk_1.default.gray(`Saved VigFlow workflow: ${response.savedWorkflow.id}${response.savedWorkflow.name ? ` (${response.savedWorkflow.name})` : ''}`));
1622
+ console.log(chalk.gray(`Saved VigFlow workflow: ${response.savedWorkflow.id}${response.savedWorkflow.name ? ` (${response.savedWorkflow.name})` : ''}`));
1633
1623
  }
1634
1624
  }
1635
1625
  this.rememberBrainEvent('validation', `GoA operator workflow completed${response.workflowId ? ` workflow ${response.workflowId}` : ''}${response.savedWorkflow?.id ? ` saved VigFlow ${response.savedWorkflow.id}` : ''}.`, 'operator');
@@ -1640,8 +1630,8 @@ class ChatCommand {
1640
1630
  if (spinner) {
1641
1631
  spinner.stop();
1642
1632
  }
1643
- const cliErr = error instanceof api_js_1.CLIError ? error : (0, api_js_1.classifyError)(error);
1644
- const errorMsg = (0, api_js_1.formatCLIError)(cliErr);
1633
+ const cliErr = error instanceof CLIError ? error : classifyError(error);
1634
+ const errorMsg = formatCLIError(cliErr);
1645
1635
  if (!this.jsonOutput) {
1646
1636
  this.logger.error('Operator workflow failed');
1647
1637
  }
@@ -1668,8 +1658,8 @@ class ChatCommand {
1668
1658
  * BMAD orchestrator to scan the workspace.
1669
1659
  */
1670
1660
  async runOperatorDirectAnswer(prompt) {
1671
- (0, bridge_client_js_1.getBridgeClient)()?.emitPrompt({ prompt, mode: 'operator-direct', model: this.currentModel });
1672
- const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({ text: 'Operator (direct)...', spinner: 'clock' }).start();
1661
+ getBridgeClient()?.emitPrompt({ prompt, mode: 'operator-direct', model: this.currentModel });
1662
+ const spinner = this.jsonOutput ? null : createSpinner({ text: 'Operator (direct)...', spinner: 'clock' }).start();
1673
1663
  try {
1674
1664
  let operatorGrounding = [
1675
1665
  'You are Vigthoria Operator, a DevOps and infrastructure analysis assistant.',
@@ -1701,7 +1691,7 @@ class ChatCommand {
1701
1691
  const isPolicyAck = /^(i will follow|i understand|i('ll| will) adhere|understood[.,!]|sure[.,!]|provide your|waiting for|i('ll| will) proceed)/i.test(content)
1702
1692
  || (content.length < 200 && /follow the instructions|next instruction|ready to assist/i.test(content));
1703
1693
  if (isPolicyAck || !content) {
1704
- throw new api_js_1.CLIError('Operator returned a non-actionable acknowledgement instead of a grounded result.', 'model_backend');
1694
+ throw new CLIError('Operator returned a non-actionable acknowledgement instead of a grounded result.', 'model_backend');
1705
1695
  }
1706
1696
  if (this.jsonOutput) {
1707
1697
  console.log(JSON.stringify({
@@ -1721,8 +1711,8 @@ class ChatCommand {
1721
1711
  catch (error) {
1722
1712
  if (spinner)
1723
1713
  spinner.stop();
1724
- const cliErr = error instanceof api_js_1.CLIError ? error : (0, api_js_1.classifyError)(error);
1725
- const errorMsg = (0, api_js_1.formatCLIError)(cliErr);
1714
+ const cliErr = error instanceof CLIError ? error : classifyError(error);
1715
+ const errorMsg = formatCLIError(cliErr);
1726
1716
  if (this.jsonOutput) {
1727
1717
  process.exitCode = 1;
1728
1718
  console.log(JSON.stringify({
@@ -1754,8 +1744,8 @@ class ChatCommand {
1754
1744
  this.currentSession.agentMode = true;
1755
1745
  this.currentSession.model = this.currentModel;
1756
1746
  }
1757
- console.log(chalk_1.default.yellow('This request needs file access, so I am switching to Agent mode and working in this workspace now.'));
1758
- console.log(chalk_1.default.gray('You do not need to confirm with "yes"; I will continue until the agent run finishes or reports a blocker.'));
1747
+ console.log(chalk.yellow('This request needs file access, so I am switching to Agent mode and working in this workspace now.'));
1748
+ console.log(chalk.gray('You do not need to confirm with "yes"; I will continue until the agent run finishes or reports a blocker.'));
1759
1749
  await this.runAgentTurn(promptToRun);
1760
1750
  return;
1761
1751
  }
@@ -1814,8 +1804,8 @@ class ChatCommand {
1814
1804
  }
1815
1805
  }
1816
1806
  this.messages.push({ role: 'user', content: this.buildExecutionPrompt(prompt) });
1817
- (0, bridge_client_js_1.getBridgeClient)()?.emitPrompt({ prompt, mode: 'chat', model: this.currentModel });
1818
- const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({ text: 'Thinking...', spinner: 'clock' }).start();
1807
+ getBridgeClient()?.emitPrompt({ prompt, mode: 'chat', model: this.currentModel });
1808
+ const spinner = this.jsonOutput ? null : createSpinner({ text: 'Thinking...', spinner: 'clock' }).start();
1819
1809
  try {
1820
1810
  const response = await this.callApi('Send chat message', () => this.api.chat(this.getMessagesForModel(), this.currentModel));
1821
1811
  if (spinner)
@@ -1839,7 +1829,7 @@ class ChatCommand {
1839
1829
  console.log(finalText);
1840
1830
  }
1841
1831
  else {
1842
- console.log(chalk_1.default.yellow('The model returned an empty response. Try rephrasing your question, or use --agent mode for grounded repo analysis.'));
1832
+ console.log(chalk.yellow('The model returned an empty response. Try rephrasing your question, or use --agent mode for grounded repo analysis.'));
1843
1833
  }
1844
1834
  this.messages.push({ role: 'assistant', content: response.message || '' });
1845
1835
  this.saveSession();
@@ -1847,8 +1837,8 @@ class ChatCommand {
1847
1837
  catch (error) {
1848
1838
  if (spinner)
1849
1839
  spinner.stop();
1850
- const cliErr = error instanceof api_js_1.CLIError ? error : (0, api_js_1.classifyError)(error);
1851
- const errorMsg = (0, api_js_1.formatCLIError)(cliErr);
1840
+ const cliErr = error instanceof CLIError ? error : classifyError(error);
1841
+ const errorMsg = formatCLIError(cliErr);
1852
1842
  if (this.jsonOutput) {
1853
1843
  process.exitCode = 1;
1854
1844
  console.log(JSON.stringify({
@@ -1905,13 +1895,13 @@ class ChatCommand {
1905
1895
  this.directToolContinuationCount = 0;
1906
1896
  this.agentToolEvidence = { discovery: 0, mutation: 0, searchFailed: 0 };
1907
1897
  this.tools.clearSessionApprovals();
1908
- (0, bridge_client_js_1.getBridgeClient)()?.emitPrompt({ prompt, mode: this.operatorMode ? 'operator' : 'agent', model: this.currentModel });
1898
+ getBridgeClient()?.emitPrompt({ prompt, mode: this.operatorMode ? 'operator' : 'agent', model: this.currentModel });
1909
1899
  this.ensureAgentSystemPrompt();
1910
1900
  this.messages.push({ role: 'user', content: this.buildScopedUserPrompt(prompt) });
1911
1901
  this.saveSession();
1912
1902
  const maxTurns = 10;
1913
1903
  for (let turn = 0; turn < maxTurns; turn += 1) {
1914
- const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({ text: turn === 0 ? 'Planning...' : 'Continuing...', spinner: 'clock' }).start();
1904
+ const spinner = this.jsonOutput ? null : createSpinner({ text: turn === 0 ? 'Planning...' : 'Continuing...', spinner: 'clock' }).start();
1915
1905
  let response;
1916
1906
  try {
1917
1907
  response = await this.callApi('Send agent chat message', () => this.api.chat(this.getMessagesForModel(), this.currentModel), 0);
@@ -1952,8 +1942,8 @@ class ChatCommand {
1952
1942
  }
1953
1943
  }
1954
1944
  else {
1955
- const cliErr = firstErr instanceof api_js_1.CLIError ? firstErr : (0, api_js_1.classifyError)(firstErr);
1956
- const formatted = (0, api_js_1.formatCLIError)(cliErr);
1945
+ const cliErr = firstErr instanceof CLIError ? firstErr : classifyError(firstErr);
1946
+ const formatted = formatCLIError(cliErr);
1957
1947
  if (spinner)
1958
1948
  spinner.stop();
1959
1949
  this.rememberBrainEvent('issue', 'Agent API preflight failed: ' + formatted, 'agent');
@@ -1983,7 +1973,7 @@ class ChatCommand {
1983
1973
  this.messages.push({ role: 'assistant', content: assistantMessage });
1984
1974
  const toolCalls = this.extractToolCalls(assistantMessage);
1985
1975
  const visibleText = this.stripToolPayloads(assistantMessage).trim();
1986
- (0, bridge_client_js_1.getBridgeClient)()?.emitModelResponse({
1976
+ getBridgeClient()?.emitModelResponse({
1987
1977
  model: this.currentModel,
1988
1978
  chars: assistantMessage.length,
1989
1979
  hasToolCalls: toolCalls.length > 0,
@@ -2064,8 +2054,8 @@ class ChatCommand {
2064
2054
  catch (error) {
2065
2055
  if (spinner)
2066
2056
  spinner.stop();
2067
- const cliErr = error instanceof api_js_1.CLIError ? error : (0, api_js_1.classifyError)(error);
2068
- const errorMsg = (0, api_js_1.formatCLIError)(cliErr);
2057
+ const cliErr = error instanceof CLIError ? error : classifyError(error);
2058
+ const errorMsg = formatCLIError(cliErr);
2069
2059
  this.rememberBrainEvent('issue', `Agent turn failed: ${errorMsg}`, 'agent');
2070
2060
  if (this.jsonOutput) {
2071
2061
  process.exitCode = 1;
@@ -2125,12 +2115,12 @@ class ChatCommand {
2125
2115
  args: { path: targetFile },
2126
2116
  };
2127
2117
  if (!this.jsonOutput) {
2128
- console.log(chalk_1.default.cyan(`⚙ Executing: ${readCall.tool}`));
2118
+ console.log(chalk.cyan(`⚙ Executing: ${readCall.tool}`));
2129
2119
  }
2130
2120
  const readResult = await this.tools.execute(readCall);
2131
2121
  const readSummary = this.formatToolResult(readCall, readResult);
2132
2122
  if (!this.jsonOutput) {
2133
- console.log(readResult.success ? chalk_1.default.gray(readSummary) : chalk_1.default.red(readSummary));
2123
+ console.log(readResult.success ? chalk.gray(readSummary) : chalk.red(readSummary));
2134
2124
  }
2135
2125
  if (readResult.success && readResult.output) {
2136
2126
  this.messages.push({ role: 'system', content: readSummary });
@@ -2152,12 +2142,12 @@ class ChatCommand {
2152
2142
  args: { path: targetFile },
2153
2143
  };
2154
2144
  if (!this.jsonOutput) {
2155
- console.log(chalk_1.default.cyan(`⚙ Executing: ${readCall.tool}`));
2145
+ console.log(chalk.cyan(`⚙ Executing: ${readCall.tool}`));
2156
2146
  }
2157
2147
  const readResult = await this.tools.execute(readCall);
2158
2148
  const readSummary = this.formatToolResult(readCall, readResult);
2159
2149
  if (!this.jsonOutput) {
2160
- console.log(readResult.success ? chalk_1.default.gray(readSummary) : chalk_1.default.red(readSummary));
2150
+ console.log(readResult.success ? chalk.gray(readSummary) : chalk.red(readSummary));
2161
2151
  }
2162
2152
  this.messages.push({ role: 'system', content: readSummary });
2163
2153
  if (!readResult.success || !readResult.output) {
@@ -2200,12 +2190,12 @@ class ChatCommand {
2200
2190
  },
2201
2191
  };
2202
2192
  if (!this.jsonOutput) {
2203
- console.log(chalk_1.default.cyan(`⚙ Executing: ${writeCall.tool}`));
2193
+ console.log(chalk.cyan(`⚙ Executing: ${writeCall.tool}`));
2204
2194
  }
2205
2195
  const writeResult = await this.tools.execute(writeCall);
2206
2196
  const writeSummary = this.formatToolResult(writeCall, writeResult);
2207
2197
  if (!this.jsonOutput) {
2208
- console.log(writeResult.success ? chalk_1.default.gray(writeSummary) : chalk_1.default.red(writeSummary));
2198
+ console.log(writeResult.success ? chalk.gray(writeSummary) : chalk.red(writeSummary));
2209
2199
  }
2210
2200
  this.messages.push({ role: 'system', content: writeSummary });
2211
2201
  if (!writeResult.success) {
@@ -2241,10 +2231,10 @@ class ChatCommand {
2241
2231
  console.log(`Updated ${targetFile}.`);
2242
2232
  if (previewGate.required) {
2243
2233
  if (previewGate.passed) {
2244
- console.log(chalk_1.default.gray(`Template Service preview gate: passed via ${previewGate.backendUrl || 'unknown backend'}`));
2234
+ console.log(chalk.gray(`Template Service preview gate: passed via ${previewGate.backendUrl || 'unknown backend'}`));
2245
2235
  }
2246
2236
  else {
2247
- console.log(chalk_1.default.yellow(`Template Service preview gate: failed${previewGate.error ? ` - ${previewGate.error}` : ''}`));
2237
+ console.log(chalk.yellow(`Template Service preview gate: failed${previewGate.error ? ` - ${previewGate.error}` : ''}`));
2248
2238
  }
2249
2239
  }
2250
2240
  }
@@ -2254,6 +2244,9 @@ class ChatCommand {
2254
2244
  const normalized = prompt.trim().toLowerCase().replace(/[.!?]+$/g, '').replace(/\s+/g, ' ');
2255
2245
  return /^(ja|ja bitte|ja bitte mach das|mach das|bitte mach das|genau|ok|okay|yes|yes please|please do|do it|go ahead|continue|proceed|make it so)$/.test(normalized);
2256
2246
  }
2247
+ taskRequiresWorkspaceChanges(prompt) {
2248
+ return /\b(build|create|make|implement|complete|fix|repair|edit|modify|write|generate|add|finish|scaffold|game|app|website|html5|frontend|component|feature)\b/i.test(prompt);
2249
+ }
2257
2250
  getPreviousActionablePrompt() {
2258
2251
  if (this.lastActionableUserInput && !this.isConfirmationFollowUp(this.lastActionableUserInput)) {
2259
2252
  return this.lastActionableUserInput;
@@ -2297,7 +2290,7 @@ class ChatCommand {
2297
2290
  try {
2298
2291
  promptWorkspacePath = this.resolvePromptWorkspacePath(prompt, this.currentProjectPath);
2299
2292
  if (promptWorkspacePath && !this.jsonOutput) {
2300
- console.log(chalk_1.default.cyan(`📁 Workspace from prompt: ${promptWorkspacePath}`));
2293
+ console.log(chalk.cyan(`📁 Workspace from prompt: ${promptWorkspacePath}`));
2301
2294
  }
2302
2295
  }
2303
2296
  catch {
@@ -2314,15 +2307,15 @@ class ChatCommand {
2314
2307
  // STREAMING: Log routing decision transparently to user
2315
2308
  if (!this.jsonOutput) {
2316
2309
  console.log();
2317
- console.log(chalk_1.default.gray('━━━ ROUTING DECISION ━━━'));
2318
- console.log(chalk_1.default.gray(`Reason: ${routingPolicy.routeReason}`));
2319
- console.log(chalk_1.default.gray(`Model: ${routingPolicy.selectedModel}`));
2320
- console.log(chalk_1.default.gray(`Cloud Eligible: ${routingPolicy.cloudEligible}`));
2321
- console.log(chalk_1.default.gray(`Cloud Selected: ${routingPolicy.cloudSelected}`));
2310
+ console.log(chalk.gray('━━━ ROUTING DECISION ━━━'));
2311
+ console.log(chalk.gray(`Reason: ${routingPolicy.routeReason}`));
2312
+ console.log(chalk.gray(`Model: ${routingPolicy.selectedModel}`));
2313
+ console.log(chalk.gray(`Cloud Eligible: ${routingPolicy.cloudEligible}`));
2314
+ console.log(chalk.gray(`Cloud Selected: ${routingPolicy.cloudSelected}`));
2322
2315
  if (routingPolicy.heavyTask) {
2323
- console.log(chalk_1.default.gray(`Task Complexity: HEAVY`));
2316
+ console.log(chalk.gray(`Task Complexity: HEAVY`));
2324
2317
  }
2325
- console.log(chalk_1.default.gray('━'.repeat(30)));
2318
+ console.log(chalk.gray('━'.repeat(30)));
2326
2319
  console.log();
2327
2320
  }
2328
2321
  // Reset streaming counters for new workflow
@@ -2330,9 +2323,9 @@ class ChatCommand {
2330
2323
  this.v3ToolCallCount = 0;
2331
2324
  this.v3LastActivity = Date.now();
2332
2325
  this.v3StreamingStarted = false;
2333
- const taskDisplay = new task_display_js_1.TaskDisplay(['Analyse workspace', 'Execute tasks', 'Validate output', 'Self-heal'], !this.jsonOutput);
2326
+ const taskDisplay = new TaskDisplay(['Analyse workspace', 'Execute tasks', 'Validate output', 'Self-heal'], !this.jsonOutput);
2334
2327
  taskDisplay.start(0);
2335
- const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({
2328
+ const spinner = this.jsonOutput ? null : createSpinner({
2336
2329
  text: routingPolicy.cloudSelected ? 'Routing heavy task to Vigthoria Cloud...' : 'Routing to V3 Agent...',
2337
2330
  spinner: 'clock',
2338
2331
  }).start();
@@ -2401,7 +2394,7 @@ class ChatCommand {
2401
2394
  // Start workspace watcher for bidirectional real-time sync
2402
2395
  let watcher = null;
2403
2396
  if (this.shouldStartWorkspaceWatcher(workspacePath)) {
2404
- watcher = new workspace_stream_js_1.WorkspaceWatcher({
2397
+ watcher = new WorkspaceWatcher({
2405
2398
  workspaceRoot: workspacePath,
2406
2399
  onFileChange: (relativePath, content, action) => {
2407
2400
  this.logger.debug(`Local change detected: ${action} ${relativePath}`);
@@ -2510,6 +2503,8 @@ class ChatCommand {
2510
2503
  }
2511
2504
  const previewGate = (response.metadata?.previewGate || null);
2512
2505
  const workspaceHasOutput = this.api.hasAgentWorkspaceOutput(workspaceContext);
2506
+ const changedFileCount = response.changedFiles ? Object.keys(response.changedFiles).length : 0;
2507
+ const requiresWorkspaceChanges = this.taskRequiresWorkspaceChanges(prompt);
2513
2508
  const success = previewGate?.required === true
2514
2509
  ? (previewGate?.passed === true || workspaceHasOutput)
2515
2510
  : true;
@@ -2545,7 +2540,7 @@ class ChatCommand {
2545
2540
  return true;
2546
2541
  }
2547
2542
  if (!this.jsonOutput && previewGate?.required && previewGate?.passed !== true && workspaceHasOutput) {
2548
- console.log(chalk_1.default.yellow(`Template Service preview gate did not fully validate this output, but generated workspace files were preserved${previewGate?.error ? `: ${previewGate.error}` : '.'}`));
2543
+ console.log(chalk.yellow(`Template Service preview gate did not fully validate this output, but generated workspace files were preserved${previewGate?.error ? `: ${previewGate.error}` : '.'}`));
2549
2544
  }
2550
2545
  if (this.jsonOutput) {
2551
2546
  console.log(JSON.stringify({
@@ -2563,41 +2558,41 @@ class ChatCommand {
2563
2558
  else if (this.v3StreamingStarted) {
2564
2559
  // Content was already streamed to stdout in real-time; skip duplicate print.
2565
2560
  if (!this.jsonOutput) {
2566
- console.log(chalk_1.default.gray(`Agent routing: ${routingPolicy.cloudSelected ? 'Vigthoria Cloud' : 'V3 Agent'}`));
2561
+ console.log(chalk.gray(`Agent routing: ${routingPolicy.cloudSelected ? 'Vigthoria Cloud' : 'V3 Agent'}`));
2567
2562
  }
2568
2563
  }
2569
2564
  else if (response.content) {
2570
2565
  if (!this.directPromptMode) {
2571
- console.log(chalk_1.default.gray(`Agent routing: ${routingPolicy.cloudSelected ? 'Vigthoria Cloud' : 'V3 Agent'}`));
2566
+ console.log(chalk.gray(`Agent routing: ${routingPolicy.cloudSelected ? 'Vigthoria Cloud' : 'V3 Agent'}`));
2572
2567
  }
2573
2568
  console.log(response.content);
2574
2569
  }
2575
2570
  else {
2576
2571
  if (!this.directPromptMode) {
2577
- console.log(chalk_1.default.gray(`Agent routing: ${routingPolicy.cloudSelected ? 'Vigthoria Cloud' : 'V3 Agent'}`));
2572
+ console.log(chalk.gray(`Agent routing: ${routingPolicy.cloudSelected ? 'Vigthoria Cloud' : 'V3 Agent'}`));
2578
2573
  }
2579
2574
  console.log('V3 agent workflow completed.');
2580
2575
  }
2581
2576
  if (!this.jsonOutput && previewGate?.required) {
2582
2577
  if (previewGate.passed) {
2583
- console.log(chalk_1.default.gray(`Template Service preview gate: passed via ${previewGate.backendUrl || 'unknown backend'}`));
2578
+ console.log(chalk.gray(`Template Service preview gate: passed via ${previewGate.backendUrl || 'unknown backend'}`));
2584
2579
  }
2585
2580
  else {
2586
- console.log(chalk_1.default.yellow(`Template Service preview gate: failed${previewGate.error ? ` - ${previewGate.error}` : ''}`));
2581
+ console.log(chalk.yellow(`Template Service preview gate: failed${previewGate.error ? ` - ${previewGate.error}` : ''}`));
2587
2582
  }
2588
2583
  }
2589
2584
  // Show change summary for files touched by the agent
2590
2585
  if (!this.jsonOutput && !this.directPromptMode && response.changedFiles) {
2591
- const fileCount = Object.keys(response.changedFiles).length;
2586
+ const fileCount = changedFileCount;
2592
2587
  if (fileCount > 0) {
2593
- console.log(chalk_1.default.gray(`\nFiles changed: ${fileCount}`));
2588
+ console.log(chalk.gray(`\nFiles changed: ${fileCount}`));
2594
2589
  for (const relPath of Object.keys(response.changedFiles).slice(0, 15)) {
2595
- console.log(chalk_1.default.gray(` ${chalk_1.default.green('+')} ${relPath}`));
2590
+ console.log(chalk.gray(` ${chalk.green('+')} ${relPath}`));
2596
2591
  }
2597
2592
  if (fileCount > 15) {
2598
- console.log(chalk_1.default.gray(` ... and ${fileCount - 15} more`));
2593
+ console.log(chalk.gray(` ... and ${fileCount - 15} more`));
2599
2594
  }
2600
- console.log(chalk_1.default.gray(`Run ${chalk_1.default.cyan('vigthoria preview --diff')} for full visual diffs.`));
2595
+ console.log(chalk.gray(`Run ${chalk.cyan('vigthoria preview --diff')} for full visual diffs.`));
2601
2596
  }
2602
2597
  }
2603
2598
  // Resolve the Execute-tasks spinner: only mark it ✓ when the run actually
@@ -2608,7 +2603,11 @@ class ChatCommand {
2608
2603
  const executorSucceeded = !liveOutcome.executorFailed
2609
2604
  && !liveOutcome.plannerError
2610
2605
  && !liveOutcome.executorError
2611
- && workspaceHasOutput;
2606
+ && workspaceHasOutput
2607
+ && (!requiresWorkspaceChanges || changedFileCount > 0);
2608
+ if (!executorSucceeded && requiresWorkspaceChanges && changedFileCount === 0 && !liveOutcome.executorError) {
2609
+ liveOutcome.executorError = 'No workspace files were changed for a build/edit request.';
2610
+ }
2612
2611
  if (executorSucceeded) {
2613
2612
  taskDisplay.complete(1);
2614
2613
  }
@@ -2635,8 +2634,8 @@ class ChatCommand {
2635
2634
  }
2636
2635
  selfHealTool = healResult.tool || null;
2637
2636
  if (!this.directPromptMode) {
2638
- const hs = healResult.passed ? chalk_1.default.green('passed') : chalk_1.default.yellow('partial');
2639
- console.log(chalk_1.default.gray(`Self-healing: ${hs} (${healResult.tool})`));
2637
+ const hs = healResult.passed ? chalk.green('passed') : chalk.yellow('partial');
2638
+ console.log(chalk.gray(`Self-healing: ${hs} (${healResult.tool})`));
2640
2639
  }
2641
2640
  }
2642
2641
  else {
@@ -2673,12 +2672,11 @@ class ChatCommand {
2673
2672
  hasOutput: workspaceHasOutput,
2674
2673
  selfHealStatus,
2675
2674
  selfHealTool,
2676
- plannerError: liveOutcome.plannerError ? (0, api_js_1.sanitizeUserFacingErrorText)(liveOutcome.plannerError) : null,
2677
- executorError: liveOutcome.executorError ? (0, api_js_1.sanitizeUserFacingErrorText)(liveOutcome.executorError) : null,
2675
+ plannerError: liveOutcome.plannerError ? sanitizeUserFacingErrorText(liveOutcome.plannerError) : null,
2676
+ executorError: liveOutcome.executorError ? sanitizeUserFacingErrorText(liveOutcome.executorError) : null,
2678
2677
  finishedAt: Date.now(),
2679
2678
  };
2680
2679
  if (!this.jsonOutput && !this.directPromptMode) {
2681
- const changedFileCount = response.changedFiles ? Object.keys(response.changedFiles).length : 0;
2682
2680
  this.printAgentRunSummary(this.lastAgentRunOutcome, executorSucceeded, changedFileCount);
2683
2681
  }
2684
2682
  this.messages.push({ role: 'assistant', content: response.content || 'V3 agent workflow completed.' });
@@ -2698,13 +2696,13 @@ class ChatCommand {
2698
2696
  spinner.stop();
2699
2697
  }
2700
2698
  this.logger.warn('Falling back to legacy CLI agent loop');
2701
- this.logger.debug(`V3 agent workflow unavailable: ${(0, api_js_1.sanitizeUserFacingErrorText)(error.message || '')}`);
2699
+ this.logger.debug(`V3 agent workflow unavailable: ${sanitizeUserFacingErrorText(error.message || '')}`);
2702
2700
  return false;
2703
2701
  }
2704
2702
  if (spinner) {
2705
2703
  spinner.stop();
2706
2704
  }
2707
- const safeDetail = (0, api_js_1.sanitizeUserFacingErrorText)(error.message || '');
2705
+ const safeDetail = sanitizeUserFacingErrorText(error.message || '');
2708
2706
  const errorMessage = safeDetail
2709
2707
  ? `Agent mode is unavailable right now. ${safeDetail}`
2710
2708
  : 'Agent mode is unavailable right now. Please retry shortly or run vigthoria login if the issue persists.';
@@ -2733,8 +2731,8 @@ class ChatCommand {
2733
2731
  hasOutput: this.api.hasAgentWorkspaceOutput(workspaceContext),
2734
2732
  selfHealStatus: 'skipped',
2735
2733
  selfHealTool: null,
2736
- plannerError: liveOutcome.plannerError ? (0, api_js_1.sanitizeUserFacingErrorText)(liveOutcome.plannerError) : null,
2737
- executorError: liveOutcome.executorError ? (0, api_js_1.sanitizeUserFacingErrorText)(liveOutcome.executorError) : safeDetail || null,
2734
+ plannerError: liveOutcome.plannerError ? sanitizeUserFacingErrorText(liveOutcome.plannerError) : null,
2735
+ executorError: liveOutcome.executorError ? sanitizeUserFacingErrorText(liveOutcome.executorError) : safeDetail || null,
2738
2736
  finishedAt: Date.now(),
2739
2737
  };
2740
2738
  if (this.jsonOutput) {
@@ -2764,7 +2762,7 @@ class ChatCommand {
2764
2762
  spinner.stop();
2765
2763
  }
2766
2764
  if (!this.jsonOutput) {
2767
- console.log(chalk_1.default.yellow(`V3 recovery: ${recovery.message} Retrying once...`));
2765
+ console.log(chalk.yellow(`V3 recovery: ${recovery.message} Retrying once...`));
2768
2766
  }
2769
2767
  this.v3IterationCount = 0;
2770
2768
  this.v3ToolCallCount = 0;
@@ -2808,7 +2806,7 @@ class ChatCommand {
2808
2806
  }, null, 2));
2809
2807
  }
2810
2808
  else if (!this.v3StreamingStarted && retryResponse.content) {
2811
- console.log(chalk_1.default.gray(`Agent routing: ${routingPolicy.cloudSelected ? 'Vigthoria Cloud' : 'V3 Agent'}`));
2809
+ console.log(chalk.gray(`Agent routing: ${routingPolicy.cloudSelected ? 'Vigthoria Cloud' : 'V3 Agent'}`));
2812
2810
  console.log(retryResponse.content);
2813
2811
  }
2814
2812
  this.messages.push({ role: 'assistant', content: retryResponse.content || 'V3 agent workflow completed after recovery.' });
@@ -2825,10 +2823,10 @@ class ChatCommand {
2825
2823
  ? 'Interactive Agent Chat'
2826
2824
  : 'Interactive Chat';
2827
2825
  this.logger.section(this.workflowTarget ? `${chatTitle} Via Workflow Target` : chatTitle);
2828
- console.log(chalk_1.default.gray('Type /help for commands. Type /exit to quit.'));
2829
- console.log(chalk_1.default.gray('Multi-line: end a line with \\ or start a block with {{{ and end with }}}'));
2826
+ console.log(chalk.gray('Type /help for commands. Type /exit to quit.'));
2827
+ console.log(chalk.gray('Multi-line: end a line with \\ or start a block with {{{ and end with }}}'));
2830
2828
  if (this.workflowTarget) {
2831
- console.log(chalk_1.default.gray(`Workflow target: ${this.workflowTarget}`));
2829
+ console.log(chalk.gray(`Workflow target: ${this.workflowTarget}`));
2832
2830
  }
2833
2831
  const rl = readline.createInterface({
2834
2832
  input: process.stdin,
@@ -2838,17 +2836,17 @@ class ChatCommand {
2838
2836
  const readMultiLineInput = async () => {
2839
2837
  const lines = [];
2840
2838
  let firstLine = await new Promise((resolve) => {
2841
- rl.question(chalk_1.default.blue('> '), resolve);
2839
+ rl.question(chalk.blue('> '), resolve);
2842
2840
  });
2843
2841
  // Check for {{{ block mode
2844
2842
  if (firstLine.trim() === '{{{' || firstLine.trim().endsWith('{{{')) {
2845
2843
  if (firstLine.trim() !== '{{{') {
2846
2844
  lines.push(firstLine.trim().replace(/\{\{\{$/, '').trim());
2847
2845
  }
2848
- console.log(chalk_1.default.gray(' (multi-line mode: type }}} on its own line to finish)'));
2846
+ console.log(chalk.gray(' (multi-line mode: type }}} on its own line to finish)'));
2849
2847
  while (true) {
2850
2848
  const line = await new Promise((resolve) => {
2851
- rl.question(chalk_1.default.gray(' '), resolve);
2849
+ rl.question(chalk.gray(' '), resolve);
2852
2850
  });
2853
2851
  if (line.trim() === '}}}')
2854
2852
  break;
@@ -2860,7 +2858,7 @@ class ChatCommand {
2860
2858
  while (firstLine.endsWith('\\')) {
2861
2859
  lines.push(firstLine.slice(0, -1));
2862
2860
  firstLine = await new Promise((resolve) => {
2863
- rl.question(chalk_1.default.gray(' '), resolve);
2861
+ rl.question(chalk.gray(' '), resolve);
2864
2862
  });
2865
2863
  }
2866
2864
  lines.push(firstLine);
@@ -2901,8 +2899,8 @@ class ChatCommand {
2901
2899
  else {
2902
2900
  this.syncInteractiveModeModel('chat');
2903
2901
  }
2904
- console.log(chalk_1.default.yellow(`Agent mode: ${this.agentMode ? 'ON' : 'OFF'}`));
2905
- console.log(chalk_1.default.gray(`Model: ${this.currentModel}`));
2902
+ console.log(chalk.yellow(`Agent mode: ${this.agentMode ? 'ON' : 'OFF'}`));
2903
+ console.log(chalk.gray(`Model: ${this.currentModel}`));
2906
2904
  if (this.currentSession) {
2907
2905
  this.currentSession.agentMode = this.agentMode;
2908
2906
  this.currentSession.operatorMode = this.operatorMode;
@@ -2924,8 +2922,8 @@ class ChatCommand {
2924
2922
  else {
2925
2923
  this.syncInteractiveModeModel('chat');
2926
2924
  }
2927
- console.log(chalk_1.default.yellow(`Operator mode: ${this.operatorMode ? 'ON' : 'OFF'}`));
2928
- console.log(chalk_1.default.gray(`Model: ${this.currentModel}`));
2925
+ console.log(chalk.yellow(`Operator mode: ${this.operatorMode ? 'ON' : 'OFF'}`));
2926
+ console.log(chalk.gray(`Model: ${this.currentModel}`));
2929
2927
  if (this.currentSession) {
2930
2928
  this.currentSession.agentMode = this.agentMode;
2931
2929
  this.currentSession.operatorMode = this.operatorMode;
@@ -2936,7 +2934,7 @@ class ChatCommand {
2936
2934
  }
2937
2935
  if (trimmed === '/clear') {
2938
2936
  this.messages = [];
2939
- console.log(chalk_1.default.yellow('Conversation cleared.'));
2937
+ console.log(chalk.yellow('Conversation cleared.'));
2940
2938
  continue;
2941
2939
  }
2942
2940
  if (trimmed === '/status') {
@@ -2946,7 +2944,7 @@ class ChatCommand {
2946
2944
  if (trimmed === '/retry') {
2947
2945
  const followUp = this.buildRetryPrompt();
2948
2946
  if (!followUp) {
2949
- console.log(chalk_1.default.yellow('Nothing to retry — run an agent task first.'));
2947
+ console.log(chalk.yellow('Nothing to retry — run an agent task first.'));
2950
2948
  continue;
2951
2949
  }
2952
2950
  const nextSignature = this.computeRetryPromptSignature();
@@ -2960,11 +2958,11 @@ class ChatCommand {
2960
2958
  if (this.retryPromptStreak >= 3) {
2961
2959
  const continuePrompt = this.buildContinuePrompt();
2962
2960
  if (continuePrompt) {
2963
- console.log(chalk_1.default.yellow('Repeated /retry detected with the same failing task set. Escalating to /continue to avoid planner loops.'));
2961
+ console.log(chalk.yellow('Repeated /retry detected with the same failing task set. Escalating to /continue to avoid planner loops.'));
2964
2962
  if (!this.agentMode) {
2965
2963
  this.agentMode = true;
2966
2964
  this.syncInteractiveModeModel('agent');
2967
- console.log(chalk_1.default.gray('Agent mode re-enabled for continuation.'));
2965
+ console.log(chalk.gray('Agent mode re-enabled for continuation.'));
2968
2966
  }
2969
2967
  await this.runAgentTurn(continuePrompt);
2970
2968
  continue;
@@ -2973,34 +2971,34 @@ class ChatCommand {
2973
2971
  if (!this.agentMode) {
2974
2972
  this.agentMode = true;
2975
2973
  this.syncInteractiveModeModel('agent');
2976
- console.log(chalk_1.default.gray('Agent mode re-enabled for retry.'));
2974
+ console.log(chalk.gray('Agent mode re-enabled for retry.'));
2977
2975
  }
2978
2976
  await this.runAgentTurn(followUp);
2979
2977
  continue;
2980
2978
  }
2981
- if (trimmed === '/continue') {
2979
+ if (trimmed === '/continue' || trimmed === '/contiunue' || trimmed === '/contiune') {
2982
2980
  const followUp = this.buildContinuePrompt();
2983
2981
  if (!followUp) {
2984
- console.log(chalk_1.default.yellow('Nothing to continue — run an agent task first.'));
2982
+ console.log(chalk.yellow('Nothing to continue — run an agent task first.'));
2985
2983
  continue;
2986
2984
  }
2987
2985
  if (!this.agentMode) {
2988
2986
  this.agentMode = true;
2989
2987
  this.syncInteractiveModeModel('agent');
2990
- console.log(chalk_1.default.gray('Agent mode re-enabled for continuation.'));
2988
+ console.log(chalk.gray('Agent mode re-enabled for continuation.'));
2991
2989
  }
2992
2990
  await this.runAgentTurn(followUp);
2993
2991
  continue;
2994
2992
  }
2995
2993
  if (trimmed === '/save') {
2996
2994
  this.saveSession();
2997
- console.log(chalk_1.default.green('Session saved.'));
2995
+ console.log(chalk.green('Session saved.'));
2998
2996
  continue;
2999
2997
  }
3000
2998
  if (trimmed.startsWith('/model ')) {
3001
2999
  this.currentModel = trimmed.slice(7).trim() || this.currentModel;
3002
3000
  this.modelExplicitlySelected = true;
3003
- console.log(chalk_1.default.yellow(`Model changed to: ${this.currentModel}`));
3001
+ console.log(chalk.yellow(`Model changed to: ${this.currentModel}`));
3004
3002
  if (this.currentSession) {
3005
3003
  this.currentSession.model = this.currentModel;
3006
3004
  this.saveSession();
@@ -3048,71 +3046,102 @@ class ChatCommand {
3048
3046
  * - Never leave the spinners (`⟳`, `–`) ambiguous when the prompt returns.
3049
3047
  */
3050
3048
  printAgentRunSummary(outcome, executorSucceeded, changedFileCount) {
3051
- const bar = chalk_1.default.gray('─'.repeat(63));
3052
- const ok = chalk_1.default.green('✓');
3053
- const warn = chalk_1.default.yellow('⚠');
3054
- const bad = chalk_1.default.red('✗');
3049
+ const bar = chalk.gray('─'.repeat(63));
3050
+ const ok = chalk.green('✓');
3051
+ const warn = chalk.yellow('⚠');
3052
+ const bad = chalk.red('✗');
3055
3053
  const failedList = outcome.failedTaskIds.slice(0, 8);
3056
3054
  const unfinishedList = outcome.unfinishedTaskIds.slice(0, 8);
3057
3055
  const hasTaskInfo = outcome.tasksTotal > 0 || failedList.length > 0 || unfinishedList.length > 0;
3058
3056
  console.log('');
3059
3057
  console.log(bar);
3060
3058
  if (executorSucceeded && outcome.selfHealStatus !== 'partial' && outcome.selfHealStatus !== 'failed' && failedList.length === 0) {
3061
- console.log(`${ok} ${chalk_1.default.bold('Agent run finished')}${changedFileCount ? chalk_1.default.gray(` — ${changedFileCount} file${changedFileCount === 1 ? '' : 's'} changed`) : ''}`);
3059
+ console.log(`${ok} ${chalk.bold('Agent run finished')}${changedFileCount ? chalk.gray(` — ${changedFileCount} file${changedFileCount === 1 ? '' : 's'} changed`) : ''}`);
3062
3060
  }
3063
3061
  else if (executorSucceeded) {
3064
- console.log(`${warn} ${chalk_1.default.bold('Agent run finished with warnings')}${changedFileCount ? chalk_1.default.gray(` — ${changedFileCount} file${changedFileCount === 1 ? '' : 's'} changed`) : ''}`);
3062
+ console.log(`${warn} ${chalk.bold('Agent run finished with warnings')}${changedFileCount ? chalk.gray(` — ${changedFileCount} file${changedFileCount === 1 ? '' : 's'} changed`) : ''}`);
3065
3063
  }
3066
3064
  else {
3067
- console.log(`${bad} ${chalk_1.default.bold('Agent run did not complete')}${changedFileCount ? chalk_1.default.gray(` — ${changedFileCount} file${changedFileCount === 1 ? '' : 's'} changed`) : ''}`);
3065
+ console.log(`${bad} ${chalk.bold('Agent run did not complete')}${changedFileCount ? chalk.gray(` — ${changedFileCount} file${changedFileCount === 1 ? '' : 's'} changed`) : ''}`);
3068
3066
  }
3069
3067
  if (hasTaskInfo) {
3070
3068
  const succ = outcome.tasksTotal > 0 ? `${outcome.tasksSucceeded}/${outcome.tasksTotal}` : `${outcome.tasksSucceeded}`;
3071
- console.log(chalk_1.default.gray(` Tasks completed: ${succ}`));
3069
+ console.log(chalk.gray(` Tasks completed: ${succ}`));
3072
3070
  if (failedList.length > 0) {
3073
- const more = outcome.failedTaskIds.length > failedList.length ? chalk_1.default.gray(` (+${outcome.failedTaskIds.length - failedList.length} more)`) : '';
3074
- console.log(chalk_1.default.gray(' Failed: ') + chalk_1.default.red(failedList.join(', ')) + more);
3071
+ const more = outcome.failedTaskIds.length > failedList.length ? chalk.gray(` (+${outcome.failedTaskIds.length - failedList.length} more)`) : '';
3072
+ console.log(chalk.gray(' Failed: ') + chalk.red(failedList.join(', ')) + more);
3075
3073
  }
3076
3074
  if (unfinishedList.length > 0) {
3077
- const more = outcome.unfinishedTaskIds.length > unfinishedList.length ? chalk_1.default.gray(` (+${outcome.unfinishedTaskIds.length - unfinishedList.length} more)`) : '';
3078
- console.log(chalk_1.default.gray(' Pending: ') + chalk_1.default.yellow(unfinishedList.join(', ')) + more);
3075
+ const more = outcome.unfinishedTaskIds.length > unfinishedList.length ? chalk.gray(` (+${outcome.unfinishedTaskIds.length - unfinishedList.length} more)`) : '';
3076
+ console.log(chalk.gray(' Pending: ') + chalk.yellow(unfinishedList.join(', ')) + more);
3079
3077
  }
3080
3078
  }
3081
3079
  if (typeof outcome.qualityScore === 'number') {
3082
3080
  const score = outcome.qualityScore.toFixed(1);
3083
- const colour = outcome.qualityScore >= 70 ? chalk_1.default.green : outcome.qualityScore >= 30 ? chalk_1.default.yellow : chalk_1.default.red;
3084
- console.log(chalk_1.default.gray(' Quality: ') + colour(`${score}/100`));
3081
+ const colour = outcome.qualityScore >= 70 ? chalk.green : outcome.qualityScore >= 30 ? chalk.yellow : chalk.red;
3082
+ console.log(chalk.gray(' Quality: ') + colour(`${score}/100`));
3085
3083
  }
3086
3084
  if (outcome.qualityBlockers.length > 0) {
3087
3085
  const list = outcome.qualityBlockers.slice(0, 3).join('; ');
3088
- const more = outcome.qualityBlockers.length > 3 ? chalk_1.default.gray(` (+${outcome.qualityBlockers.length - 3} more)`) : '';
3089
- console.log(chalk_1.default.gray(' Blockers: ') + chalk_1.default.yellow(list) + more);
3086
+ const more = outcome.qualityBlockers.length > 3 ? chalk.gray(` (+${outcome.qualityBlockers.length - 3} more)`) : '';
3087
+ console.log(chalk.gray(' Blockers: ') + chalk.yellow(list) + more);
3090
3088
  }
3091
3089
  if (outcome.qualityMissing.length > 0) {
3092
3090
  const list = outcome.qualityMissing.slice(0, 5).join(', ');
3093
- const more = outcome.qualityMissing.length > 5 ? chalk_1.default.gray(` (+${outcome.qualityMissing.length - 5} more)`) : '';
3094
- console.log(chalk_1.default.gray(' Missing: ') + chalk_1.default.yellow(list) + more);
3091
+ const more = outcome.qualityMissing.length > 5 ? chalk.gray(` (+${outcome.qualityMissing.length - 5} more)`) : '';
3092
+ console.log(chalk.gray(' Missing: ') + chalk.yellow(list) + more);
3095
3093
  }
3096
3094
  if (outcome.plannerError) {
3097
- console.log(chalk_1.default.gray(' Planner: ') + chalk_1.default.red(outcome.plannerError.slice(0, 140)));
3095
+ console.log(chalk.gray(' Planner: ') + chalk.red(outcome.plannerError.slice(0, 140)));
3098
3096
  }
3099
3097
  if (outcome.executorError) {
3100
- console.log(chalk_1.default.gray(' Executor: ') + chalk_1.default.red(outcome.executorError.slice(0, 140)));
3098
+ console.log(chalk.gray(' Executor: ') + chalk.red(outcome.executorError.slice(0, 140)));
3099
+ }
3100
+ console.log('');
3101
+ console.log(chalk.gray('Result:'));
3102
+ if (executorSucceeded) {
3103
+ const filePart = changedFileCount > 0
3104
+ ? ` and updated ${changedFileCount} workspace file${changedFileCount === 1 ? '' : 's'}`
3105
+ : '';
3106
+ console.log(' ' + chalk.green(`The ${chalk.bold('Agent')} mode completed the request${filePart}.`));
3107
+ }
3108
+ else {
3109
+ console.log(' ' + chalk.yellow('The Agent mode stopped before every requested task was confirmed complete.'));
3101
3110
  }
3102
3111
  console.log('');
3103
- console.log(chalk_1.default.gray('What you can do next:'));
3112
+ console.log(chalk.gray('What was done:'));
3113
+ if (hasTaskInfo) {
3114
+ const taskLine = outcome.tasksTotal > 0
3115
+ ? `${outcome.tasksSucceeded} of ${outcome.tasksTotal} planned task${outcome.tasksTotal === 1 ? '' : 's'} finished`
3116
+ : `${outcome.tasksSucceeded} task update${outcome.tasksSucceeded === 1 ? '' : 's'} reported`;
3117
+ console.log(' ' + chalk.white(taskLine + '.'));
3118
+ }
3119
+ else if (changedFileCount > 0) {
3120
+ console.log(' ' + chalk.white(`Workspace changes were produced and are ready for review.`));
3121
+ }
3122
+ else if (outcome.hasOutput) {
3123
+ console.log(' ' + chalk.white('The assistant returned a final answer for your request.'));
3124
+ }
3125
+ else {
3126
+ console.log(' ' + chalk.white('No final workspace output was confirmed.'));
3127
+ }
3128
+ if (outcome.selfHealStatus && outcome.selfHealStatus !== 'skipped') {
3129
+ console.log(' ' + chalk.white(`Self-check status: ${outcome.selfHealStatus}.`));
3130
+ }
3131
+ console.log('');
3132
+ console.log(chalk.gray('What you can do next:'));
3104
3133
  if (failedList.length > 0 || unfinishedList.length > 0 || !executorSucceeded) {
3105
- console.log(' ' + chalk_1.default.cyan('/retry') + chalk_1.default.gray(' resume the failed/unfinished tasks only'));
3106
- console.log(' ' + chalk_1.default.cyan('/continue') + chalk_1.default.gray(' ask the agent to keep working from this state'));
3134
+ console.log(' ' + chalk.cyan('/retry') + chalk.gray(' resume the failed/unfinished tasks only'));
3135
+ console.log(' ' + chalk.cyan('/continue') + chalk.gray(' ask the agent to keep working from this state'));
3107
3136
  }
3108
3137
  else {
3109
- console.log(' ' + chalk_1.default.cyan('/continue') + chalk_1.default.gray(' add a follow-up instruction in this thread'));
3138
+ console.log(' ' + chalk.cyan('type your next request') + chalk.gray(' continue the conversation'));
3110
3139
  }
3111
3140
  if (changedFileCount > 0) {
3112
- console.log(' ' + chalk_1.default.cyan('vigthoria preview --diff') + chalk_1.default.gray(' inspect the file changes'));
3141
+ console.log(' ' + chalk.cyan('vigthoria preview --diff') + chalk.gray(' inspect the file changes'));
3113
3142
  }
3114
- console.log(' ' + chalk_1.default.cyan('/status') + chalk_1.default.gray(' re-print this summary later'));
3115
- console.log(' ' + chalk_1.default.cyan('/exit') + chalk_1.default.gray(' leave interactive chat'));
3143
+ console.log(' ' + chalk.cyan('/status') + chalk.gray(' re-print this summary later'));
3144
+ console.log(' ' + chalk.cyan('/exit') + chalk.gray(' leave interactive chat'));
3116
3145
  console.log(bar);
3117
3146
  console.log('');
3118
3147
  }
@@ -3160,21 +3189,24 @@ class ChatCommand {
3160
3189
  return null;
3161
3190
  const remaining = [...new Set([...o.failedTaskIds, ...o.unfinishedTaskIds])];
3162
3191
  const taskList = remaining.length > 0 ? `\nRemaining tasks to finish: ${remaining.join(', ')}.` : '';
3192
+ const mustChangeFiles = this.taskRequiresWorkspaceChanges(o.prompt)
3193
+ ? '\nThis was a build/edit request. Do not stop after analysis or tool JSON; make real workspace file changes and verify them before finishing.'
3194
+ : '';
3163
3195
  const blockerLine = o.qualityBlockers.length > 0
3164
3196
  ? `\nKnown blockers to address: ${o.qualityBlockers.slice(0, 3).join('; ')}.`
3165
3197
  : '';
3166
3198
  const missingLine = o.qualityMissing.length > 0
3167
3199
  ? `\nMissing pieces: ${o.qualityMissing.slice(0, 6).join(', ')}.`
3168
3200
  : '';
3169
- 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}`;
3201
+ return `Continue the previous agent run from the current workspace state without re-doing already-completed work.${taskList}${mustChangeFiles}${blockerLine}${missingLine}\nOriginal request was: ${o.prompt}`;
3170
3202
  }
3171
3203
  /**
3172
3204
  * Re-print the last agent run summary, or guide the user when there isn't one.
3173
3205
  */
3174
3206
  showAgentRunStatus() {
3175
3207
  if (!this.lastAgentRunOutcome) {
3176
- console.log(chalk_1.default.yellow('No agent run has finished in this session yet.'));
3177
- console.log(chalk_1.default.gray('Toggle agent mode with /agent and send a request to start one.'));
3208
+ console.log(chalk.yellow('No agent run has finished in this session yet.'));
3209
+ console.log(chalk.gray('Toggle agent mode with /agent and send a request to start one.'));
3178
3210
  return;
3179
3211
  }
3180
3212
  const o = this.lastAgentRunOutcome;
@@ -3187,45 +3219,45 @@ class ChatCommand {
3187
3219
  }
3188
3220
  showContext() {
3189
3221
  if (!this.currentSession) {
3190
- console.log(chalk_1.default.yellow('No active session.'));
3222
+ console.log(chalk.yellow('No active session.'));
3191
3223
  return;
3192
3224
  }
3193
- console.log(chalk_1.default.cyan(this.getCurrentSessionInfo()));
3225
+ console.log(chalk.cyan(this.getCurrentSessionInfo()));
3194
3226
  if (this.currentSession.memorySummary?.trim()) {
3195
3227
  console.log();
3196
- console.log(chalk_1.default.white('Compact Session Memory:'));
3197
- console.log(chalk_1.default.gray(this.currentSession.memorySummary.trim()));
3228
+ console.log(chalk.white('Compact Session Memory:'));
3229
+ console.log(chalk.gray(this.currentSession.memorySummary.trim()));
3198
3230
  }
3199
3231
  else {
3200
- console.log(chalk_1.default.gray('No compact session memory summary yet.'));
3232
+ console.log(chalk.gray('No compact session memory summary yet.'));
3201
3233
  }
3202
3234
  const runtime = this.getRuntimeEnvironmentContext();
3203
3235
  console.log();
3204
- console.log(chalk_1.default.white('Runtime Environment:'));
3205
- console.log(chalk_1.default.gray(`Platform: ${runtime.platform} (${runtime.osPlatform})`));
3206
- console.log(chalk_1.default.gray(`Machine scope: ${runtime.machineScope}`));
3207
- console.log(chalk_1.default.gray(`Workspace: ${runtime.workspacePath}`));
3208
- console.log(chalk_1.default.gray(`CWD: ${runtime.cwd}`));
3209
- console.log(chalk_1.default.gray(`Server-bindable workspace: ${runtime.serverBindableWorkspace ? 'yes' : 'no'}`));
3236
+ console.log(chalk.white('Runtime Environment:'));
3237
+ console.log(chalk.gray(`Platform: ${runtime.platform} (${runtime.osPlatform})`));
3238
+ console.log(chalk.gray(`Machine scope: ${runtime.machineScope}`));
3239
+ console.log(chalk.gray(`Workspace: ${runtime.workspacePath}`));
3240
+ console.log(chalk.gray(`CWD: ${runtime.cwd}`));
3241
+ console.log(chalk.gray(`Server-bindable workspace: ${runtime.serverBindableWorkspace ? 'yes' : 'no'}`));
3210
3242
  this.showProjectMemory();
3211
3243
  }
3212
3244
  showProjectMemory() {
3213
3245
  if (!this.projectMemory) {
3214
- this.projectMemory = new project_memory_js_1.ProjectMemoryService(this.currentProjectPath);
3246
+ this.projectMemory = new ProjectMemoryService(this.currentProjectPath);
3215
3247
  }
3216
3248
  const status = this.projectMemory.getStatus();
3217
3249
  console.log();
3218
- console.log(chalk_1.default.white('Project Brain:'));
3219
- console.log(chalk_1.default.gray(`Path: ${status.memoryDir}`));
3220
- console.log(chalk_1.default.gray(`Items: ${status.itemCount}`));
3250
+ console.log(chalk.white('Project Brain:'));
3251
+ console.log(chalk.gray(`Path: ${status.memoryDir}`));
3252
+ console.log(chalk.gray(`Items: ${status.itemCount}`));
3221
3253
  const typeSummary = Object.entries(status.typeCounts).map(([type, count]) => `${type}=${count}`).join(', ');
3222
3254
  if (typeSummary) {
3223
- console.log(chalk_1.default.gray(`Types: ${typeSummary}`));
3255
+ console.log(chalk.gray(`Types: ${typeSummary}`));
3224
3256
  }
3225
3257
  }
3226
3258
  compactCurrentSession() {
3227
3259
  if (!this.currentSession) {
3228
- console.log(chalk_1.default.yellow('No active session.'));
3260
+ console.log(chalk.yellow('No active session.'));
3229
3261
  return;
3230
3262
  }
3231
3263
  this.currentSession.messages = [...this.messages];
@@ -3233,7 +3265,7 @@ class ChatCommand {
3233
3265
  this.messages = [...this.currentSession.messages];
3234
3266
  this.sessionManager.save(this.currentSession);
3235
3267
  if (!this.projectMemory) {
3236
- this.projectMemory = new project_memory_js_1.ProjectMemoryService(this.currentProjectPath);
3268
+ this.projectMemory = new ProjectMemoryService(this.currentProjectPath);
3237
3269
  }
3238
3270
  this.projectMemory.rememberConversation(this.messages, {
3239
3271
  source: 'manual-compact',
@@ -3241,7 +3273,7 @@ class ChatCommand {
3241
3273
  model: this.currentModel,
3242
3274
  sessionSummary: this.currentSession.memorySummary || '',
3243
3275
  });
3244
- console.log(chalk_1.default.green('Session compacted into memory summary and project brain.'));
3276
+ console.log(chalk.green('Session compacted into memory summary and project brain.'));
3245
3277
  }
3246
3278
  ensureAgentSystemPrompt() {
3247
3279
  const hasSystemPrompt = this.messages.some((message) => message.role === 'system' && message.content.includes('Vigthoria CLI agent operating contract'));
@@ -3254,7 +3286,7 @@ class ChatCommand {
3254
3286
  });
3255
3287
  }
3256
3288
  buildAgentSystemPrompt() {
3257
- const toolCatalog = tools_js_1.AgenticTools.getToolDefinitions()
3289
+ const toolCatalog = AgenticTools.getToolDefinitions()
3258
3290
  .map((tool) => {
3259
3291
  const params = tool.parameters
3260
3292
  .map((param) => `${param.name}${param.required ? ' (required)' : ''}`)
@@ -3907,15 +3939,15 @@ class ChatCommand {
3907
3939
  const verbose = !this.jsonOutput;
3908
3940
  for (const call of toolCalls) {
3909
3941
  if (verbose) {
3910
- console.log(chalk_1.default.cyan(`⚙ Executing: ${call.tool}`));
3942
+ console.log(chalk.cyan(`⚙ Executing: ${call.tool}`));
3911
3943
  }
3912
- (0, bridge_client_js_1.getBridgeClient)()?.emitToolCall({ tool: call.tool, args: call.args });
3944
+ getBridgeClient()?.emitToolCall({ tool: call.tool, args: call.args });
3913
3945
  let result = await this.tools.execute(call);
3914
3946
  // Phase 2: If a search tool failed (search_failed), retry with alternate approach
3915
3947
  const searchStatus = result.metadata?.searchStatus;
3916
3948
  if (call.tool === 'grep' && searchStatus === 'search_failed') {
3917
3949
  if (verbose) {
3918
- console.log(chalk_1.default.yellow(`⚠ Search backend failed, retrying with alternate method...`));
3950
+ console.log(chalk.yellow(`⚠ Search backend failed, retrying with alternate method...`));
3919
3951
  }
3920
3952
  // Force Node-native fallback by re-executing with a note
3921
3953
  const fallbackResult = await this.tools.execute({
@@ -3928,10 +3960,10 @@ class ChatCommand {
3928
3960
  }
3929
3961
  const summary = this.formatToolResult(call, result);
3930
3962
  if (verbose) {
3931
- console.log(result.success ? chalk_1.default.gray(summary) : chalk_1.default.red(summary));
3963
+ console.log(result.success ? chalk.gray(summary) : chalk.red(summary));
3932
3964
  }
3933
3965
  this.messages.push({ role: 'system', content: summary });
3934
- (0, bridge_client_js_1.getBridgeClient)()?.emitToolResult({ tool: call.tool, success: result.success, preview: (result.output || result.error || '').slice(0, 300) });
3966
+ getBridgeClient()?.emitToolResult({ tool: call.tool, success: result.success, preview: (result.output || result.error || '').slice(0, 300) });
3935
3967
  // Phase 5: Track tool evidence for quality gates
3936
3968
  const finalStatus = result.metadata?.searchStatus;
3937
3969
  if (finalStatus === 'search_failed') {
@@ -3996,7 +4028,7 @@ class ChatCommand {
3996
4028
  this.messages = [...this.currentSession.messages];
3997
4029
  this.sessionManager.save(this.currentSession);
3998
4030
  if (!this.projectMemory) {
3999
- this.projectMemory = new project_memory_js_1.ProjectMemoryService(this.currentProjectPath);
4031
+ this.projectMemory = new ProjectMemoryService(this.currentProjectPath);
4000
4032
  }
4001
4033
  this.projectMemory.rememberConversation(this.messages, {
4002
4034
  source: 'cli-session',
@@ -4015,7 +4047,7 @@ class ChatCommand {
4015
4047
  });
4016
4048
  console.log(action);
4017
4049
  const answer = await new Promise((resolve) => {
4018
- rl.question(chalk_1.default.yellow('Approve? [y]es / [n]o / [a]ll this turn / [p]ersist: '), resolve);
4050
+ rl.question(chalk.yellow('Approve? [y]es / [n]o / [a]ll this turn / [p]ersist: '), resolve);
4019
4051
  });
4020
4052
  rl.close();
4021
4053
  const normalized = answer.trim().toLowerCase();
@@ -4038,4 +4070,3 @@ class ChatCommand {
4038
4070
  return [...this.messages];
4039
4071
  }
4040
4072
  }
4041
- exports.ChatCommand = ChatCommand;