vigthoria-cli 1.6.5 → 1.6.9

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.
Files changed (74) hide show
  1. package/README.md +9 -1
  2. package/dist/commands/auth.d.ts +0 -1
  3. package/dist/commands/auth.js +57 -6
  4. package/dist/commands/bridge.d.ts +7 -0
  5. package/dist/commands/bridge.js +31 -0
  6. package/dist/commands/chat.d.ts +27 -1
  7. package/dist/commands/chat.js +508 -14
  8. package/dist/commands/config.d.ts +0 -1
  9. package/dist/commands/config.js +10 -3
  10. package/dist/commands/deploy.d.ts +0 -1
  11. package/dist/commands/deploy.js +0 -1
  12. package/dist/commands/edit.d.ts +0 -1
  13. package/dist/commands/edit.js +0 -1
  14. package/dist/commands/explain.d.ts +0 -1
  15. package/dist/commands/explain.js +0 -1
  16. package/dist/commands/generate.d.ts +0 -1
  17. package/dist/commands/generate.js +0 -1
  18. package/dist/commands/hub.d.ts +0 -1
  19. package/dist/commands/hub.js +0 -1
  20. package/dist/commands/repo.d.ts +0 -1
  21. package/dist/commands/repo.js +0 -1
  22. package/dist/commands/review.d.ts +0 -1
  23. package/dist/commands/review.js +0 -1
  24. package/dist/commands/workflow.d.ts +31 -0
  25. package/dist/commands/workflow.js +140 -0
  26. package/dist/index.d.ts +2 -1
  27. package/dist/index.js +135 -11
  28. package/dist/utils/api.d.ts +210 -1
  29. package/dist/utils/api.js +1789 -47
  30. package/dist/utils/config.d.ts +14 -7
  31. package/dist/utils/config.js +22 -11
  32. package/dist/utils/files.d.ts +0 -1
  33. package/dist/utils/files.js +0 -1
  34. package/dist/utils/logger.d.ts +0 -1
  35. package/dist/utils/logger.js +0 -1
  36. package/dist/utils/session.d.ts +14 -2
  37. package/dist/utils/session.js +105 -4
  38. package/dist/utils/tools.d.ts +0 -1
  39. package/dist/utils/tools.js +0 -1
  40. package/package.json +23 -4
  41. package/dist/commands/auth.d.ts.map +0 -1
  42. package/dist/commands/auth.js.map +0 -1
  43. package/dist/commands/chat.d.ts.map +0 -1
  44. package/dist/commands/chat.js.map +0 -1
  45. package/dist/commands/config.d.ts.map +0 -1
  46. package/dist/commands/config.js.map +0 -1
  47. package/dist/commands/deploy.d.ts.map +0 -1
  48. package/dist/commands/deploy.js.map +0 -1
  49. package/dist/commands/edit.d.ts.map +0 -1
  50. package/dist/commands/edit.js.map +0 -1
  51. package/dist/commands/explain.d.ts.map +0 -1
  52. package/dist/commands/explain.js.map +0 -1
  53. package/dist/commands/generate.d.ts.map +0 -1
  54. package/dist/commands/generate.js.map +0 -1
  55. package/dist/commands/hub.d.ts.map +0 -1
  56. package/dist/commands/hub.js.map +0 -1
  57. package/dist/commands/repo.d.ts.map +0 -1
  58. package/dist/commands/repo.js.map +0 -1
  59. package/dist/commands/review.d.ts.map +0 -1
  60. package/dist/commands/review.js.map +0 -1
  61. package/dist/index.d.ts.map +0 -1
  62. package/dist/index.js.map +0 -1
  63. package/dist/utils/api.d.ts.map +0 -1
  64. package/dist/utils/api.js.map +0 -1
  65. package/dist/utils/config.d.ts.map +0 -1
  66. package/dist/utils/config.js.map +0 -1
  67. package/dist/utils/files.d.ts.map +0 -1
  68. package/dist/utils/files.js.map +0 -1
  69. package/dist/utils/logger.d.ts.map +0 -1
  70. package/dist/utils/logger.js.map +0 -1
  71. package/dist/utils/session.d.ts.map +0 -1
  72. package/dist/utils/session.js.map +0 -1
  73. package/dist/utils/tools.d.ts.map +0 -1
  74. package/dist/utils/tools.js.map +0 -1
@@ -39,11 +39,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.ChatCommand = void 0;
40
40
  const chalk_1 = __importDefault(require("chalk"));
41
41
  const ora_1 = __importDefault(require("ora"));
42
+ const fs = __importStar(require("fs"));
42
43
  const path = __importStar(require("path"));
43
44
  const readline = __importStar(require("readline"));
44
45
  const api_js_1 = require("../utils/api.js");
45
46
  const tools_js_1 = require("../utils/tools.js");
46
47
  const session_js_1 = require("../utils/session.js");
48
+ const DEFAULT_V3_AGENT_TIMEOUT_MS = (() => {
49
+ const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS || '1200000';
50
+ const parsed = Number.parseInt(rawValue, 10);
51
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 1200000;
52
+ })();
47
53
  class ChatCommand {
48
54
  config;
49
55
  logger;
@@ -59,6 +65,141 @@ class ChatCommand {
59
65
  directToolContinuationCount = 0;
60
66
  currentModel = 'code';
61
67
  autoApprove = false;
68
+ operatorMode = false;
69
+ workflowTarget = null;
70
+ savePlanToVigFlow = false;
71
+ jsonOutput = false;
72
+ hasOperatorAccess() {
73
+ return this.config.hasOperatorAccess();
74
+ }
75
+ operatorAccessMessage() {
76
+ const currentPlan = this.config.get('subscription').plan || 'free';
77
+ return `Operator mode requires Enterprise or admin access. Current plan: ${currentPlan}.`;
78
+ }
79
+ getMessagesForModel() {
80
+ const memoryContext = this.sessionManager.buildMemoryContext(this.currentSession);
81
+ const messages = [...this.messages];
82
+ if (!memoryContext) {
83
+ return messages;
84
+ }
85
+ const alreadyInjected = messages.some((message) => message.role === 'system' && message.content.includes('Session memory summary from earlier conversation turns.'));
86
+ if (alreadyInjected) {
87
+ return messages;
88
+ }
89
+ const insertionIndex = messages.findIndex((message) => message.role !== 'system');
90
+ const memoryMessage = {
91
+ role: 'system',
92
+ content: memoryContext,
93
+ };
94
+ if (insertionIndex === -1) {
95
+ messages.push(memoryMessage);
96
+ return messages;
97
+ }
98
+ messages.splice(insertionIndex, 0, memoryMessage);
99
+ return messages;
100
+ }
101
+ isDiagnosticPrompt(prompt) {
102
+ 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);
103
+ }
104
+ isBrowserTaskPrompt(prompt) {
105
+ return /(browser|chrome|devtools|console|dom|network tab|network request|frontend runtime|client-side|client side|rendering|page load|websocket|ui bug|inspect element)/i.test(prompt);
106
+ }
107
+ inferAgentTaskType(prompt) {
108
+ return this.isDiagnosticPrompt(prompt) ? 'debugging' : 'implementation';
109
+ }
110
+ buildTaskShapingInstructions(prompt) {
111
+ const instructions = [];
112
+ if (this.isDiagnosticPrompt(prompt)) {
113
+ instructions.push('Diagnostic mode is active.', 'Treat this as a debugging task, not a generic code review or feature request.', 'Start with concrete evidence: logs, runtime errors, config, launch files, and exact symbol references.', 'If log files exist, inspect them before proposing fixes.', 'Do not claim a file, definition, asset, or symbol is missing until you verify that with tools.', 'If a prior diagnosis mentioned a missing symbol or YAML entry, re-check the actual files before repeating it.', 'Prefer grep plus read_file around the exact references involved in the failure.', 'Separate your reasoning into: Evidence, Confirmed Cause, and Remaining Hypotheses.', 'Do not suggest speculative fixes when the current evidence contradicts them.');
114
+ }
115
+ if (this.isBrowserTaskPrompt(prompt)) {
116
+ instructions.push('Browser-debug mode is active.', 'Prefer concrete browser evidence such as console errors, network failures, DOM state, and websocket behavior.', 'If a DevTools Bridge is available, use it as the primary browser observability path.');
117
+ }
118
+ if (instructions.length === 0) {
119
+ return '';
120
+ }
121
+ return instructions.join('\n');
122
+ }
123
+ buildExecutionPrompt(prompt) {
124
+ const shaping = this.buildTaskShapingInstructions(prompt);
125
+ return shaping ? `${prompt}\n\n${shaping}` : prompt;
126
+ }
127
+ async getPromptRuntimeContext(prompt) {
128
+ if (!this.isBrowserTaskPrompt(prompt)) {
129
+ return {};
130
+ }
131
+ const bridgeStatus = await this.api.getDevtoolsBridgeStatus();
132
+ if (!this.jsonOutput && bridgeStatus.ok) {
133
+ console.log(chalk_1.default.gray(`Browser task detected. DevTools Bridge is reachable at ${bridgeStatus.endpoint}.`));
134
+ }
135
+ else if (!this.jsonOutput) {
136
+ console.log(chalk_1.default.yellow(`Browser task detected. DevTools Bridge is not running at ${bridgeStatus.endpoint}.`));
137
+ }
138
+ return {
139
+ browserTask: true,
140
+ devtoolsBridgeAvailable: bridgeStatus.ok,
141
+ devtoolsBridgeEndpoint: bridgeStatus.endpoint,
142
+ };
143
+ }
144
+ describeV3AgentTool(toolName) {
145
+ const normalized = String(toolName || '').toLowerCase();
146
+ if (/read|grep|search|list|find|glob/.test(normalized)) {
147
+ return 'Planning... gathering project context';
148
+ }
149
+ if (/write|edit|patch|create|delete|replace|rename/.test(normalized)) {
150
+ return 'Applying changes...';
151
+ }
152
+ if (/test|lint|build|run|exec|terminal/.test(normalized)) {
153
+ return 'Validating changes...';
154
+ }
155
+ return 'Working...';
156
+ }
157
+ updateV3AgentSpinner(spinner, event) {
158
+ if (!event || typeof event !== 'object') {
159
+ return;
160
+ }
161
+ if (event.type === 'tool_call') {
162
+ spinner.text = this.describeV3AgentTool(event.tool || event.name || event.tool_name);
163
+ return;
164
+ }
165
+ if (event.type === 'message') {
166
+ spinner.text = 'Writing response...';
167
+ return;
168
+ }
169
+ if (event.type === 'complete') {
170
+ spinner.text = 'Finishing...';
171
+ return;
172
+ }
173
+ if (event.type === 'plan' || event.type === 'analysis' || event.type === 'thinking') {
174
+ spinner.text = 'Planning...';
175
+ }
176
+ }
177
+ updateOperatorSpinner(spinner, event) {
178
+ if (!event || typeof event !== 'object') {
179
+ return;
180
+ }
181
+ if (event.type === 'started') {
182
+ spinner.text = 'Starting BMAD workflow...';
183
+ return;
184
+ }
185
+ if (event.type === 'connected') {
186
+ spinner.text = 'Connected to BMAD stream...';
187
+ return;
188
+ }
189
+ if (event.type === 'agent') {
190
+ spinner.text = `Running ${event.agent || 'BMAD agent'}...`;
191
+ return;
192
+ }
193
+ if (event.type === 'status') {
194
+ const progress = Number.isFinite(Number(event.progress)) ? ` (${event.progress}%)` : '';
195
+ spinner.text = `${event.status || 'Working'}${progress}`;
196
+ return;
197
+ }
198
+ if (event.type === 'result') {
199
+ spinner.text = 'Finishing operator workflow...';
200
+ return;
201
+ }
202
+ }
62
203
  constructor(config, logger) {
63
204
  this.config = config;
64
205
  this.logger = logger;
@@ -71,49 +212,246 @@ class ChatCommand {
71
212
  return;
72
213
  }
73
214
  this.agentMode = options.agent === true;
215
+ this.operatorMode = options.operator === true;
216
+ this.workflowTarget = typeof options.workflow === 'string' && options.workflow.trim()
217
+ ? options.workflow.trim()
218
+ : null;
219
+ this.savePlanToVigFlow = options.savePlan === true;
220
+ this.jsonOutput = options.json === true;
74
221
  this.autoApprove = options.autoApprove === true;
75
222
  this.currentModel = options.model || 'code';
76
223
  this.currentProjectPath = path.resolve(options.project || process.cwd());
224
+ if (this.jsonOutput && !options.prompt) {
225
+ throw new Error('--json is only supported together with --prompt.');
226
+ }
227
+ this.ensureProjectWorkspace();
77
228
  this.directPromptMode = Boolean(options.prompt);
78
229
  this.directToolContinuationCount = 0;
79
230
  this.tools = new tools_js_1.AgenticTools(this.logger, this.currentProjectPath, async (action) => this.requestPermission(action), this.autoApprove);
80
231
  this.initializeSession(options.resume === true);
232
+ if (this.operatorMode && !this.hasOperatorAccess()) {
233
+ if (this.currentSession) {
234
+ this.currentSession.operatorMode = false;
235
+ this.saveSession();
236
+ }
237
+ this.operatorMode = false;
238
+ this.logger.error(this.operatorAccessMessage());
239
+ return;
240
+ }
81
241
  if (options.prompt) {
82
242
  await this.handleDirectPrompt(options.prompt);
83
243
  return;
84
244
  }
85
245
  await this.startInteractiveChat();
86
246
  }
247
+ ensureProjectWorkspace() {
248
+ if (fs.existsSync(this.currentProjectPath)) {
249
+ if (!fs.statSync(this.currentProjectPath).isDirectory()) {
250
+ throw new Error(`Project path is not a directory: ${this.currentProjectPath}`);
251
+ }
252
+ return;
253
+ }
254
+ fs.mkdirSync(this.currentProjectPath, { recursive: true });
255
+ }
87
256
  initializeSession(resume) {
88
257
  if (resume) {
89
258
  this.currentSession = this.sessionManager.getLatest(this.currentProjectPath);
90
259
  if (this.currentSession) {
91
260
  this.messages = [...this.currentSession.messages];
92
261
  this.agentMode = this.currentSession.agentMode || this.agentMode;
262
+ this.operatorMode = this.currentSession.operatorMode || this.operatorMode;
93
263
  this.currentModel = this.currentSession.model || this.currentModel;
94
264
  return;
95
265
  }
96
266
  }
97
- this.currentSession = this.sessionManager.create(this.currentProjectPath, this.currentModel, this.agentMode);
267
+ this.currentSession = this.sessionManager.create(this.currentProjectPath, this.currentModel, this.agentMode, this.operatorMode);
98
268
  this.messages = [...this.currentSession.messages];
99
269
  }
100
270
  async handleDirectPrompt(prompt) {
101
- console.log(chalk_1.default.cyan('Running single prompt in direct mode.'));
102
- console.log(chalk_1.default.gray(`Model: ${this.currentModel}`));
103
- console.log(chalk_1.default.gray(`Project: ${this.currentProjectPath}`));
104
- console.log();
271
+ if (!this.jsonOutput) {
272
+ console.log(chalk_1.default.cyan('Running single prompt in direct mode.'));
273
+ console.log(chalk_1.default.gray(`Model: ${this.currentModel}`));
274
+ console.log(chalk_1.default.gray(`Project: ${this.currentProjectPath}`));
275
+ if (this.workflowTarget) {
276
+ console.log(chalk_1.default.gray(`Workflow target: ${this.workflowTarget}`));
277
+ }
278
+ console.log();
279
+ }
280
+ if (this.workflowTarget) {
281
+ await this.runWorkflowTargetPrompt(prompt);
282
+ return;
283
+ }
105
284
  if (this.agentMode) {
106
285
  await this.runAgentTurn(prompt);
107
286
  return;
108
287
  }
288
+ if (this.operatorMode) {
289
+ if (!this.hasOperatorAccess()) {
290
+ this.logger.error(this.operatorAccessMessage());
291
+ return;
292
+ }
293
+ await this.runOperatorTurn(prompt);
294
+ return;
295
+ }
109
296
  await this.runSimplePrompt(prompt);
110
297
  }
298
+ formatWorkflowTargetResult(result) {
299
+ if (typeof result === 'string') {
300
+ return result.trim();
301
+ }
302
+ if (result == null) {
303
+ return '';
304
+ }
305
+ if (typeof result !== 'object') {
306
+ return String(result);
307
+ }
308
+ const entries = Object.entries(result)
309
+ .filter(([, value]) => typeof value === 'string' && String(value).trim());
310
+ if (entries.length === 1) {
311
+ return String(entries[0][1]).trim();
312
+ }
313
+ if (entries.length > 1) {
314
+ return entries
315
+ .map(([key, value]) => `${key}:\n${String(value).trim()}`)
316
+ .join('\n\n');
317
+ }
318
+ const serialized = JSON.stringify(result, null, 2);
319
+ return serialized === '{}' ? '' : serialized;
320
+ }
321
+ async runWorkflowTargetPrompt(prompt) {
322
+ const selector = this.workflowTarget;
323
+ if (!selector) {
324
+ throw new Error('Workflow target is not configured.');
325
+ }
326
+ this.lastActionableUserInput = prompt;
327
+ const executionPrompt = this.buildExecutionPrompt(prompt);
328
+ this.messages.push({ role: 'user', content: executionPrompt });
329
+ const runtimeContext = await this.getPromptRuntimeContext(prompt);
330
+ const resolvedWorkflow = await this.api.resolveVigFlowWorkflow(selector);
331
+ const invocationMode = this.operatorMode ? 'operator' : this.agentMode ? 'agent' : 'chat';
332
+ const spinner = this.jsonOutput ? null : (0, ora_1.default)({ text: `Running workflow ${resolvedWorkflow.name}...`, spinner: 'clock' }).start();
333
+ try {
334
+ const execution = await this.api.runVigFlowWorkflow(resolvedWorkflow.id, {
335
+ data: {
336
+ request: executionPrompt,
337
+ prompt: executionPrompt,
338
+ rawPrompt: prompt,
339
+ workspacePath: this.currentProjectPath,
340
+ projectPath: this.currentProjectPath,
341
+ targetPath: this.currentProjectPath,
342
+ model: this.currentModel,
343
+ history: this.getMessagesForModel(),
344
+ executionSurface: invocationMode,
345
+ clientSurface: 'cli',
346
+ workflowTarget: {
347
+ id: resolvedWorkflow.id,
348
+ name: resolvedWorkflow.name,
349
+ selector: resolvedWorkflow.selector,
350
+ matchedBy: resolvedWorkflow.matchedBy,
351
+ },
352
+ ...runtimeContext,
353
+ },
354
+ executionOptions: {
355
+ targetType: 'vigflow-workflow',
356
+ targetSelector: resolvedWorkflow.selector,
357
+ targetMatchedBy: resolvedWorkflow.matchedBy,
358
+ executionSurface: invocationMode,
359
+ clientSurface: 'cli',
360
+ model: this.currentModel,
361
+ },
362
+ });
363
+ const content = this.formatWorkflowTargetResult(execution.result);
364
+ const assistantText = content || `Workflow ${resolvedWorkflow.name} completed with status ${execution.status}.`;
365
+ this.messages.push({ role: 'assistant', content: assistantText });
366
+ this.saveSession();
367
+ if (spinner) {
368
+ spinner.stop();
369
+ }
370
+ if (this.jsonOutput) {
371
+ console.log(JSON.stringify({
372
+ success: true,
373
+ workflow: resolvedWorkflow,
374
+ mode: invocationMode,
375
+ execution,
376
+ content,
377
+ }, null, 2));
378
+ return;
379
+ }
380
+ this.logger.success(`Workflow target ${resolvedWorkflow.name} ${execution.status}`);
381
+ console.log(chalk_1.default.gray(`Workflow ID: ${resolvedWorkflow.id}`));
382
+ console.log(chalk_1.default.gray(`Execution ID: ${execution.executionId}`));
383
+ console.log(chalk_1.default.gray(`Mode: ${invocationMode}`));
384
+ if (content) {
385
+ console.log(content);
386
+ }
387
+ }
388
+ catch (error) {
389
+ if (spinner) {
390
+ spinner.fail('Workflow target execution failed');
391
+ }
392
+ throw error;
393
+ }
394
+ }
395
+ async runOperatorTurn(prompt) {
396
+ if (!this.hasOperatorAccess()) {
397
+ this.logger.error(this.operatorAccessMessage());
398
+ return;
399
+ }
400
+ const runtimeContext = await this.getPromptRuntimeContext(prompt);
401
+ const spinner = this.jsonOutput ? null : (0, ora_1.default)({ text: 'Thinking like an operator...', spinner: 'clock' }).start();
402
+ const executionPrompt = this.buildExecutionPrompt(prompt);
403
+ const workflowType = this.isDiagnosticPrompt(prompt) ? 'analysis_only' : 'full_autonomy';
404
+ try {
405
+ const response = await this.api.runOperatorWorkflow(executionPrompt, {
406
+ workspacePath: this.currentProjectPath,
407
+ projectPath: this.currentProjectPath,
408
+ targetPath: this.currentProjectPath,
409
+ rawPrompt: prompt,
410
+ executionSurface: 'cli',
411
+ clientSurface: 'cli',
412
+ history: this.getMessagesForModel(),
413
+ workflowType,
414
+ model: this.currentModel,
415
+ savePlanToVigFlow: this.savePlanToVigFlow,
416
+ ...runtimeContext,
417
+ onStreamEvent: spinner ? (event) => this.updateOperatorSpinner(spinner, event) : undefined,
418
+ });
419
+ if (spinner) {
420
+ spinner.stop();
421
+ }
422
+ if (this.jsonOutput) {
423
+ console.log(JSON.stringify({
424
+ success: true,
425
+ mode: 'operator',
426
+ workflowId: response.workflowId,
427
+ savedWorkflow: response.savedWorkflow || null,
428
+ contextId: response.contextId || null,
429
+ content: response.content || 'Operator workflow completed.',
430
+ metadata: response.metadata || {},
431
+ }, null, 2));
432
+ }
433
+ else {
434
+ console.log(response.content || 'Operator workflow completed.');
435
+ if (response.savedWorkflow?.id) {
436
+ console.log(chalk_1.default.gray(`Saved VigFlow workflow: ${response.savedWorkflow.id}${response.savedWorkflow.name ? ` (${response.savedWorkflow.name})` : ''}`));
437
+ }
438
+ }
439
+ this.messages.push({ role: 'assistant', content: response.content || 'Operator workflow completed.' });
440
+ this.saveSession();
441
+ }
442
+ catch (error) {
443
+ if (spinner) {
444
+ spinner.fail('Operator workflow failed');
445
+ }
446
+ this.logger.error(error.message);
447
+ }
448
+ }
111
449
  async runSimplePrompt(prompt) {
112
450
  this.lastActionableUserInput = prompt;
113
- this.messages.push({ role: 'user', content: prompt });
451
+ this.messages.push({ role: 'user', content: this.buildExecutionPrompt(prompt) });
114
452
  const spinner = (0, ora_1.default)({ text: 'Thinking...', spinner: 'clock' }).start();
115
453
  try {
116
- const response = await this.api.chat(this.messages, this.currentModel);
454
+ const response = await this.api.chat(this.getMessagesForModel(), this.currentModel);
117
455
  spinner.stop();
118
456
  const finalText = response.message.trim();
119
457
  if (finalText) {
@@ -136,6 +474,11 @@ class ChatCommand {
136
474
  this.saveSession();
137
475
  return;
138
476
  }
477
+ const handledByV3Workflow = await this.tryV3AgentWorkflow(prompt);
478
+ if (handledByV3Workflow) {
479
+ this.saveSession();
480
+ return;
481
+ }
139
482
  this.lastActionableUserInput = prompt;
140
483
  this.directToolContinuationCount = 0;
141
484
  this.tools.clearSessionApprovals();
@@ -146,7 +489,7 @@ class ChatCommand {
146
489
  for (let turn = 0; turn < maxTurns; turn += 1) {
147
490
  const spinner = (0, ora_1.default)({ text: turn === 0 ? 'Planning...' : 'Continuing...', spinner: 'clock' }).start();
148
491
  try {
149
- const response = await this.api.chat(this.messages, this.currentModel);
492
+ const response = await this.api.chat(this.getMessagesForModel(), this.currentModel);
150
493
  spinner.stop();
151
494
  const assistantMessage = response.message || '';
152
495
  this.messages.push({ role: 'assistant', content: assistantMessage });
@@ -238,9 +581,87 @@ class ChatCommand {
238
581
  console.log(`Updated ${targetFile}.`);
239
582
  return true;
240
583
  }
584
+ async tryV3AgentWorkflow(prompt) {
585
+ const runtimeContext = await this.getPromptRuntimeContext(prompt);
586
+ const spinner = this.jsonOutput ? null : (0, ora_1.default)({ text: 'Thinking...', spinner: 'clock' }).start();
587
+ const executionPrompt = this.buildExecutionPrompt(prompt);
588
+ const agentTaskType = this.inferAgentTaskType(prompt);
589
+ try {
590
+ const response = await this.api.runV3AgentWorkflow(executionPrompt, {
591
+ workspace: { path: this.currentProjectPath },
592
+ workspacePath: this.currentProjectPath,
593
+ projectPath: this.currentProjectPath,
594
+ targetPath: this.currentProjectPath,
595
+ agentTaskType,
596
+ executionSurface: 'cli',
597
+ clientSurface: 'cli',
598
+ localMachineCapable: true,
599
+ agentTimeoutMs: DEFAULT_V3_AGENT_TIMEOUT_MS,
600
+ agentIdleTimeoutMs: 90000,
601
+ rawPrompt: prompt,
602
+ history: this.getMessagesForModel(),
603
+ ...runtimeContext,
604
+ onStreamEvent: spinner ? (event) => this.updateV3AgentSpinner(spinner, event) : undefined,
605
+ });
606
+ if (spinner) {
607
+ spinner.stop();
608
+ }
609
+ const previewGate = (response.metadata?.previewGate || null);
610
+ const success = previewGate?.required === true ? previewGate?.passed === true : true;
611
+ if (!success) {
612
+ if (spinner) {
613
+ spinner.warn('Falling back to legacy CLI agent loop');
614
+ }
615
+ this.logger.debug(`V3 agent workflow returned an incomplete result: ${previewGate?.error || 'workspace changes were not fully validated'}`);
616
+ return false;
617
+ }
618
+ if (this.jsonOutput) {
619
+ console.log(JSON.stringify({
620
+ success,
621
+ mode: 'agent',
622
+ taskId: response.taskId || null,
623
+ contextId: response.contextId || null,
624
+ partial: response.partial === true,
625
+ content: response.content || 'V3 agent workflow completed.',
626
+ metadata: response.metadata || {},
627
+ }, null, 2));
628
+ }
629
+ else if (response.content) {
630
+ console.log(response.content);
631
+ }
632
+ else {
633
+ console.log('V3 agent workflow completed.');
634
+ }
635
+ if (!this.jsonOutput && previewGate?.required) {
636
+ if (previewGate.passed) {
637
+ console.log(chalk_1.default.gray(`Template Service preview gate: passed via ${previewGate.backendUrl || 'unknown backend'}`));
638
+ }
639
+ else {
640
+ console.log(chalk_1.default.yellow(`Template Service preview gate: failed${previewGate.error ? ` - ${previewGate.error}` : ''}`));
641
+ }
642
+ }
643
+ this.messages.push({ role: 'assistant', content: response.content || 'V3 agent workflow completed.' });
644
+ return true;
645
+ }
646
+ catch (error) {
647
+ if (spinner) {
648
+ spinner.warn('Falling back to legacy CLI agent loop');
649
+ }
650
+ this.logger.debug(`V3 agent workflow unavailable: ${error.message}`);
651
+ return false;
652
+ }
653
+ }
241
654
  async startInteractiveChat() {
242
- this.logger.section(this.agentMode ? 'Interactive Agent Chat' : 'Interactive Chat');
655
+ const chatTitle = this.operatorMode
656
+ ? 'Interactive Operator Chat'
657
+ : this.agentMode
658
+ ? 'Interactive Agent Chat'
659
+ : 'Interactive Chat';
660
+ this.logger.section(this.workflowTarget ? `${chatTitle} Via Workflow Target` : chatTitle);
243
661
  console.log(chalk_1.default.gray('Type /help for commands. Type /exit to quit.'));
662
+ if (this.workflowTarget) {
663
+ console.log(chalk_1.default.gray(`Workflow target: ${this.workflowTarget}`));
664
+ }
244
665
  const rl = readline.createInterface({
245
666
  input: process.stdin,
246
667
  output: process.stdout,
@@ -261,11 +682,40 @@ class ChatCommand {
261
682
  this.showHelp();
262
683
  continue;
263
684
  }
685
+ if (trimmed === '/context') {
686
+ this.showContext();
687
+ continue;
688
+ }
689
+ if (trimmed === '/compact') {
690
+ this.compactCurrentSession();
691
+ continue;
692
+ }
264
693
  if (trimmed === '/agent') {
265
694
  this.agentMode = !this.agentMode;
695
+ if (this.agentMode) {
696
+ this.operatorMode = false;
697
+ }
266
698
  console.log(chalk_1.default.yellow(`Agent mode: ${this.agentMode ? 'ON' : 'OFF'}`));
267
699
  if (this.currentSession) {
268
700
  this.currentSession.agentMode = this.agentMode;
701
+ this.currentSession.operatorMode = this.operatorMode;
702
+ this.saveSession();
703
+ }
704
+ continue;
705
+ }
706
+ if (trimmed === '/operator') {
707
+ if (!this.operatorMode && !this.hasOperatorAccess()) {
708
+ this.logger.error(this.operatorAccessMessage());
709
+ continue;
710
+ }
711
+ this.operatorMode = !this.operatorMode;
712
+ if (this.operatorMode) {
713
+ this.agentMode = false;
714
+ }
715
+ console.log(chalk_1.default.yellow(`Operator mode: ${this.operatorMode ? 'ON' : 'OFF'}`));
716
+ if (this.currentSession) {
717
+ this.currentSession.agentMode = this.agentMode;
718
+ this.currentSession.operatorMode = this.operatorMode;
269
719
  this.saveSession();
270
720
  }
271
721
  continue;
@@ -289,7 +739,13 @@ class ChatCommand {
289
739
  }
290
740
  continue;
291
741
  }
292
- if (this.agentMode) {
742
+ if (this.workflowTarget) {
743
+ await this.runWorkflowTargetPrompt(trimmed);
744
+ }
745
+ else if (this.operatorMode) {
746
+ await this.runOperatorTurn(trimmed);
747
+ }
748
+ else if (this.agentMode) {
293
749
  await this.runAgentTurn(trimmed);
294
750
  }
295
751
  else {
@@ -303,11 +759,40 @@ class ChatCommand {
303
759
  console.log(' /help Show this help');
304
760
  console.log(' /exit Exit chat');
305
761
  console.log(' /agent Toggle agent mode');
762
+ console.log(' /operator Toggle BMAD operator mode');
763
+ console.log(' /context Show current session memory');
764
+ console.log(' /compact Compact current session into memory summary');
306
765
  console.log(' /clear Clear conversation');
307
766
  console.log(' /save Save session');
308
767
  console.log(' /model <name> Change model');
309
768
  console.log('');
310
769
  }
770
+ showContext() {
771
+ if (!this.currentSession) {
772
+ console.log(chalk_1.default.yellow('No active session.'));
773
+ return;
774
+ }
775
+ console.log(chalk_1.default.cyan(this.getCurrentSessionInfo()));
776
+ if (this.currentSession.memorySummary?.trim()) {
777
+ console.log();
778
+ console.log(chalk_1.default.white('Compact Memory:'));
779
+ console.log(chalk_1.default.gray(this.currentSession.memorySummary.trim()));
780
+ }
781
+ else {
782
+ console.log(chalk_1.default.gray('No compact memory summary yet.'));
783
+ }
784
+ }
785
+ compactCurrentSession() {
786
+ if (!this.currentSession) {
787
+ console.log(chalk_1.default.yellow('No active session.'));
788
+ return;
789
+ }
790
+ this.currentSession.messages = [...this.messages];
791
+ this.currentSession = this.sessionManager.compactInMemory(this.currentSession);
792
+ this.messages = [...this.currentSession.messages];
793
+ this.sessionManager.save(this.currentSession);
794
+ console.log(chalk_1.default.green('Session compacted into memory summary.'));
795
+ }
311
796
  ensureAgentSystemPrompt() {
312
797
  const hasSystemPrompt = this.messages.some((message) => message.role === 'system' && message.content.includes('Vigthoria CLI agent operating contract'));
313
798
  if (hasSystemPrompt) {
@@ -333,6 +818,10 @@ class ChatCommand {
333
818
  'Stay inside that project unless the user explicitly asks otherwise.',
334
819
  'Read files before editing or rewriting them.',
335
820
  'When the user asks to inspect a folder or find the right file, verify with tools before concluding.',
821
+ 'For debugging or startup issues, inspect logs and concrete runtime evidence before proposing fixes.',
822
+ 'Do not claim a file, asset, symbol, YAML entry, or definition is missing until you verify it with tools.',
823
+ 'If earlier output claimed something is missing, re-check the exact file and symbol before repeating that claim.',
824
+ 'When diagnosing failures, prefer evidence-backed conclusions over broad repo scans.',
336
825
  'If the user corrects you, treat that as evidence that your previous assumption was wrong and re-check with tools.',
337
826
  'Do not stop after a partial answer when more direct inspection is possible.',
338
827
  'When you need a tool, emit only one or more tool wrappers in this exact format:',
@@ -349,7 +838,7 @@ class ChatCommand {
349
838
  }
350
839
  buildScopedUserPrompt(prompt) {
351
840
  return [
352
- prompt,
841
+ this.buildExecutionPrompt(prompt),
353
842
  '',
354
843
  `Project root: ${this.currentProjectPath}`,
355
844
  'Stay within this project root unless the user explicitly expands scope.',
@@ -371,12 +860,14 @@ class ChatCommand {
371
860
  return null;
372
861
  }
373
862
  buildContinuationPrompt() {
863
+ const diagnosticMode = this.isDiagnosticPrompt(this.lastActionableUserInput);
374
864
  return [
375
865
  `Tool results received for direct mode step ${this.directToolContinuationCount + 1}.`,
376
866
  `Original user request: ${this.lastActionableUserInput}`,
377
867
  `Project root boundary: ${this.currentProjectPath}`,
378
868
  'Do not declare success until the exact user question has been answered with tool-backed evidence.',
379
869
  'If a user is asking which file is correct or most recent, keep inspecting until you can justify the answer from actual results.',
870
+ diagnosticMode ? 'Because this is a debugging task, prefer logs, runtime evidence, and exact symbol references over generic fixes.' : 'Keep working from concrete tool results.',
380
871
  'If the request is already satisfied, return a concise completion summary and no tool calls.',
381
872
  'If more work is required, continue with only the next minimal tool calls needed to finish it.',
382
873
  'Do not ask follow-up questions or drift into unrelated tasks.',
@@ -472,12 +963,15 @@ class ChatCommand {
472
963
  }
473
964
  saveSession() {
474
965
  if (!this.currentSession) {
475
- this.currentSession = this.sessionManager.create(this.currentProjectPath, this.currentModel, this.agentMode);
966
+ this.currentSession = this.sessionManager.create(this.currentProjectPath, this.currentModel, this.agentMode, this.operatorMode);
476
967
  }
477
968
  this.currentSession.project = this.currentProjectPath;
478
969
  this.currentSession.model = this.currentModel;
479
970
  this.currentSession.agentMode = this.agentMode;
971
+ this.currentSession.operatorMode = this.operatorMode;
480
972
  this.currentSession.messages = [...this.messages];
973
+ this.currentSession = this.sessionManager.compactInMemory(this.currentSession);
974
+ this.messages = [...this.currentSession.messages];
481
975
  this.sessionManager.save(this.currentSession);
482
976
  }
483
977
  async requestPermission(action) {
@@ -503,11 +997,11 @@ class ChatCommand {
503
997
  if (!this.currentSession) {
504
998
  return 'No active session';
505
999
  }
506
- return `Session: ${this.currentSession.name} (${this.currentSession.messages.length} messages)`;
1000
+ const compacted = this.currentSession.memorySummary ? ' with compact memory' : '';
1001
+ return `Session: ${this.currentSession.name} (${this.currentSession.messages.length} messages${compacted})`;
507
1002
  }
508
1003
  getChatHistory() {
509
1004
  return [...this.messages];
510
1005
  }
511
1006
  }
512
1007
  exports.ChatCommand = ChatCommand;
513
- //# sourceMappingURL=chat.js.map