vigthoria-cli 1.9.2 → 1.9.8

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.
@@ -19,14 +19,9 @@ class BridgeCommand {
19
19
  console.log();
20
20
  console.log(chalk_1.default.white('DevTools Bridge:'));
21
21
  console.log(chalk_1.default.gray(' Status: ') + (bridge.ok ? chalk_1.default.green('Reachable') : chalk_1.default.yellow('Not running')));
22
- // Only show error details for unexpected failures — suppress
23
- // "Connection timed out" / "ECONNREFUSED" for the normal
24
- // not-running case to keep the UX clean.
25
- if (bridge.error && bridge.ok === false) {
26
- const isExpectedDown = /timed? out|ECONNREFUSED|connect ECONNREFUSED|Connection refused/i.test(bridge.error);
27
- if (!isExpectedDown) {
28
- console.log(chalk_1.default.gray(' Detail: ') + chalk_1.default.yellow(bridge.error));
29
- }
22
+ if (!bridge.ok) {
23
+ const detail = String(bridge.error || 'Connection refused').trim() || 'Connection refused';
24
+ console.log(chalk_1.default.gray(' Error: ') + chalk_1.default.yellow(detail));
30
25
  }
31
26
  console.log(chalk_1.default.gray(' Browser tasks: ') + (bridge.ok
32
27
  ? chalk_1.default.green('Local browser observability is available for debugging flows.')
@@ -90,6 +90,9 @@ export declare class ChatCommand {
90
90
  */
91
91
  private sanitizeServerPath;
92
92
  private describeV3AgentTool;
93
+ private isRawV3StreamPayload;
94
+ private consumeV3StreamPayload;
95
+ private writeV3StreamText;
93
96
  private updateV3AgentSpinner;
94
97
  private updateOperatorSpinner;
95
98
  constructor(config: Config, logger: Logger);
@@ -66,9 +66,12 @@ const DEFAULT_V3_AGENT_IDLE_TIMEOUT_MS = (() => {
66
66
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
67
67
  })();
68
68
  const DEFAULT_V3_AGENT_SOFT_TIMEOUT_MS = (() => {
69
- const rawValue = process.env.VIGTHORIA_AGENT_SOFT_TIMEOUT_MS || process.env.V3_AGENT_SOFT_TIMEOUT_MS || '300000';
69
+ const rawValue = process.env.VIGTHORIA_AGENT_SOFT_TIMEOUT_MS || process.env.V3_AGENT_SOFT_TIMEOUT_MS;
70
+ if (!rawValue) {
71
+ return 0;
72
+ }
70
73
  const parsed = Number.parseInt(rawValue, 10);
71
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 300000;
74
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
72
75
  })();
73
76
  class ChatCommand {
74
77
  config;
@@ -192,7 +195,9 @@ class ChatCommand {
192
195
  if (attempt >= retries || (!this.isNetworkError(error) && !this.isTimeoutError(error))) {
193
196
  this.handleApiError(error, context);
194
197
  }
195
- this.logger.warn(`${context} failed due to ${this.isTimeoutError(error) ? 'timeout' : 'network error'}; retrying (${attempt + 1}/${retries})...`);
198
+ if (!this.jsonOutput) {
199
+ this.logger.warn(`${context} failed due to ${this.isTimeoutError(error) ? 'timeout' : 'network error'}; retrying (${attempt + 1}/${retries})...`);
200
+ }
196
201
  await new Promise((resolve) => setTimeout(resolve, 500 * (attempt + 1)));
197
202
  }
198
203
  }
@@ -221,7 +226,9 @@ class ChatCommand {
221
226
  reason: 'governance-blocked-model',
222
227
  };
223
228
  this.currentModel = effectiveModel;
224
- this.logger.warn(`Model ${requestedModel} is not permitted for no-agent chat; using ${effectiveModel}`);
229
+ if (!this.jsonOutput) {
230
+ this.logger.warn(`Model ${requestedModel} is not permitted for no-agent chat; using ${effectiveModel}`);
231
+ }
225
232
  return;
226
233
  }
227
234
  this.modelGovernanceFallback = null;
@@ -248,7 +255,7 @@ class ChatCommand {
248
255
  }
249
256
  operatorAccessMessage() {
250
257
  const currentPlan = this.config.get('subscription').plan || 'free';
251
- return `Operator mode requires Enterprise or admin access. Current plan: ${currentPlan}.`;
258
+ return `Operator mode requires Pro, Ultra, Enterprise, or admin access. Current plan: ${currentPlan}.`;
252
259
  }
253
260
  getDefaultChatModel() {
254
261
  const preferredModel = String(this.config.get('preferences').defaultModel || '').trim().toLowerCase();
@@ -476,7 +483,67 @@ class ChatCommand {
476
483
  }
477
484
  return 'Working';
478
485
  }
486
+ isRawV3StreamPayload(event) {
487
+ if (!event) {
488
+ return false;
489
+ }
490
+ if (typeof event === 'string' || Buffer.isBuffer(event) || event instanceof Uint8Array) {
491
+ return true;
492
+ }
493
+ const body = event?.body ?? event?.stream ?? event?.response;
494
+ return Boolean(body && (typeof body[Symbol.asyncIterator] === 'function' || typeof body.getReader === 'function'));
495
+ }
496
+ async consumeV3StreamPayload(spinner, event) {
497
+ try {
498
+ const source = (event && typeof event === 'object' && !Buffer.isBuffer(event) && !(event instanceof Uint8Array))
499
+ ? (event.body ?? event.stream ?? event.response ?? event)
500
+ : event;
501
+ for await (const chunk of (0, tools_js_1.robustifyStreamResponse)(source)) {
502
+ this.v3LastActivity = Date.now();
503
+ if (chunk.type === 'error') {
504
+ if (spinner.isSpinning)
505
+ spinner.stop();
506
+ process.stderr.write(chalk_1.default.red(`\nStream error: ${chunk.content}\n`));
507
+ continue;
508
+ }
509
+ if (chunk.content) {
510
+ this.writeV3StreamText(spinner, chunk.content);
511
+ }
512
+ }
513
+ }
514
+ catch (error) {
515
+ const message = error instanceof Error ? error.message : String(error);
516
+ if (spinner.isSpinning)
517
+ spinner.stop();
518
+ process.stderr.write(chalk_1.default.red(`\nStream error: ${message}\n`));
519
+ }
520
+ }
521
+ writeV3StreamText(spinner, text) {
522
+ if (!text) {
523
+ return;
524
+ }
525
+ if (!this.v3StreamingStarted) {
526
+ this.v3StreamingStarted = true;
527
+ spinner.stop();
528
+ if (!this.directPromptMode) {
529
+ console.log();
530
+ }
531
+ }
532
+ else {
533
+ spinner.stop();
534
+ }
535
+ process.stdout.write(text);
536
+ }
479
537
  updateV3AgentSpinner(spinner, event) {
538
+ if (this.isRawV3StreamPayload(event)) {
539
+ this.consumeV3StreamPayload(spinner, event).catch((error) => {
540
+ const message = error instanceof Error ? error.message : String(error);
541
+ if (spinner.isSpinning)
542
+ spinner.stop();
543
+ process.stderr.write(chalk_1.default.red(`\nStream error: ${message}\n`));
544
+ });
545
+ return;
546
+ }
480
547
  if (!event || typeof event !== 'object') {
481
548
  return;
482
549
  }
@@ -543,17 +610,8 @@ class ChatCommand {
543
610
  ? (event.delta?.text || '')
544
611
  : (event.content || '');
545
612
  if (text) {
546
- if (!this.v3StreamingStarted) {
547
- this.v3StreamingStarted = true;
548
- spinner.stop();
549
- if (!this.directPromptMode) {
550
- console.log();
551
- }
552
- }
553
- else {
554
- spinner.stop();
555
- }
556
- process.stdout.write(text);
613
+ this.v3LastActivity = Date.now();
614
+ this.writeV3StreamText(spinner, text);
557
615
  }
558
616
  else {
559
617
  spinner.text = chalk_1.default.cyan('[Response] ') + 'Writing response...';
@@ -826,11 +884,16 @@ class ChatCommand {
826
884
  return;
827
885
  }
828
886
  if (options.prompt) {
829
- // Wrap in a timeout to guarantee bridge cleanup even if the agent
830
- // loop hangs (e.g. model takes forever on a turn).
831
- const BRIDGE_TIMEOUT_MS = 180_000; // 3 minutes max for a single prompt
887
+ const bridgePromptTimeoutMs = (() => {
888
+ const rawValue = process.env.VIGTHORIA_BRIDGE_PROMPT_TIMEOUT_MS || process.env.V3_BRIDGE_PROMPT_TIMEOUT_MS;
889
+ if (!rawValue) {
890
+ return 0;
891
+ }
892
+ const parsed = Number.parseInt(rawValue, 10);
893
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
894
+ })();
832
895
  let timedOut = false;
833
- const timeoutId = options.bridge
896
+ const timeoutId = options.bridge && bridgePromptTimeoutMs > 0
834
897
  ? setTimeout(() => {
835
898
  timedOut = true;
836
899
  const b = (0, bridge_client_js_1.getBridgeClient)();
@@ -839,10 +902,10 @@ class ChatCommand {
839
902
  b.destroy();
840
903
  }
841
904
  if (!this.jsonOutput) {
842
- this.logger.error('Bridge prompt timed out after 3 minutes.');
905
+ this.logger.error('Bridge prompt timed out after ' + Math.round(bridgePromptTimeoutMs / 1000) + ' seconds.');
843
906
  }
844
907
  process.exitCode = 1;
845
- }, BRIDGE_TIMEOUT_MS)
908
+ }, bridgePromptTimeoutMs)
846
909
  : null;
847
910
  await this.handleDirectPrompt(options.prompt);
848
911
  if (timeoutId)
@@ -1042,7 +1105,7 @@ class ChatCommand {
1042
1105
  async handleDirectPrompt(prompt) {
1043
1106
  // Suppress all setup banners in direct-prompt mode so only the final
1044
1107
  // answer reaches stdout. Interactive (REPL) mode still shows them.
1045
- if (!this.jsonOutput && !this.directPromptMode) {
1108
+ if (!this.jsonOutput) {
1046
1109
  console.log(chalk_1.default.cyan('Running single prompt in direct mode.'));
1047
1110
  console.log(chalk_1.default.gray(`Model: ${this.currentModel}`));
1048
1111
  console.log(chalk_1.default.gray(`Project: ${this.currentProjectPath}`));
@@ -1694,12 +1757,12 @@ class ChatCommand {
1694
1757
  tool: 'read_file',
1695
1758
  args: { path: targetFile },
1696
1759
  };
1697
- if (!this.jsonOutput && !this.directPromptMode) {
1760
+ if (!this.jsonOutput) {
1698
1761
  console.log(chalk_1.default.cyan(`⚙ Executing: ${readCall.tool}`));
1699
1762
  }
1700
1763
  const readResult = await this.tools.execute(readCall);
1701
1764
  const readSummary = this.formatToolResult(readCall, readResult);
1702
- if (!this.jsonOutput && !this.directPromptMode) {
1765
+ if (!this.jsonOutput) {
1703
1766
  console.log(readResult.success ? chalk_1.default.gray(readSummary) : chalk_1.default.red(readSummary));
1704
1767
  }
1705
1768
  this.messages.push({ role: 'system', content: readSummary });
@@ -1742,12 +1805,12 @@ class ChatCommand {
1742
1805
  content: rewrittenContent,
1743
1806
  },
1744
1807
  };
1745
- if (!this.jsonOutput && !this.directPromptMode) {
1808
+ if (!this.jsonOutput) {
1746
1809
  console.log(chalk_1.default.cyan(`⚙ Executing: ${writeCall.tool}`));
1747
1810
  }
1748
1811
  const writeResult = await this.tools.execute(writeCall);
1749
1812
  const writeSummary = this.formatToolResult(writeCall, writeResult);
1750
- if (!this.jsonOutput && !this.directPromptMode) {
1813
+ if (!this.jsonOutput) {
1751
1814
  console.log(writeResult.success ? chalk_1.default.gray(writeSummary) : chalk_1.default.red(writeSummary));
1752
1815
  }
1753
1816
  this.messages.push({ role: 'system', content: writeSummary });
@@ -1921,7 +1984,7 @@ class ChatCommand {
1921
1984
  }
1922
1985
  else if (this.v3StreamingStarted) {
1923
1986
  // Content was already streamed to stdout in real-time; skip duplicate print.
1924
- if (!this.directPromptMode) {
1987
+ if (!this.jsonOutput) {
1925
1988
  console.log(chalk_1.default.gray(`Agent routing: ${routingPolicy.cloudSelected ? 'Vigthoria Cloud' : 'V3 Agent'}`));
1926
1989
  }
1927
1990
  }
@@ -1937,7 +2000,7 @@ class ChatCommand {
1937
2000
  }
1938
2001
  console.log('V3 agent workflow completed.');
1939
2002
  }
1940
- if (!this.jsonOutput && !this.directPromptMode && previewGate?.required) {
2003
+ if (!this.jsonOutput && previewGate?.required) {
1941
2004
  if (previewGate.passed) {
1942
2005
  console.log(chalk_1.default.gray(`Template Service preview gate: passed via ${previewGate.backendUrl || 'unknown backend'}`));
1943
2006
  }
@@ -2481,10 +2544,10 @@ class ChatCommand {
2481
2544
  isProtectedFileReference(prompt, filePath) {
2482
2545
  const escapedPath = filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2483
2546
  const protectedPatterns = [
2484
- new RegExp(`do not modify\\s+[-\u001f\s\-\"][` + "'" + `]?${escapedPath}[` + "'" + `]?`, 'i'),
2485
- new RegExp(`don't modify\\s+[-\u001f\s\-\"][` + "'" + `]?${escapedPath}[` + "'" + `]?`, 'i'),
2486
- new RegExp(`leave\\s+[-\u001f\s\-\"][` + "'" + `]?${escapedPath}[` + "'" + `]?\\s+unchanged`, 'i'),
2487
- new RegExp(`without modifying\\s+[-\u001f\s\-\"][` + "'" + `]?${escapedPath}[` + "'" + `]?`, 'i'),
2547
+ new RegExp(`do not modify\\s+[-\u001f\s\-\"][` + "'" + `]?${escapedPath}[` + "'" + `]?`, 'i'),
2548
+ new RegExp(`don't modify\\s+[-\u001f\s\-\"][` + "'" + `]?${escapedPath}[` + "'" + `]?`, 'i'),
2549
+ new RegExp(`leave\\s+[-\u001f\s\-\"][` + "'" + `]?${escapedPath}[` + "'" + `]?\\s+unchanged`, 'i'),
2550
+ new RegExp(`without modifying\\s+[-\u001f\s\-\"][` + "'" + `]?${escapedPath}[` + "'" + `]?`, 'i'),
2488
2551
  ];
2489
2552
  return protectedPatterns.some((pattern) => pattern.test(prompt));
2490
2553
  }
@@ -2846,7 +2909,7 @@ class ChatCommand {
2846
2909
  }
2847
2910
  // In direct-prompt mode (--prompt), suppress verbose tool output so
2848
2911
  // only the final answer prints. In interactive mode, show full detail.
2849
- const verbose = !this.jsonOutput && !this.directPromptMode;
2912
+ const verbose = !this.jsonOutput;
2850
2913
  for (const call of toolCalls) {
2851
2914
  if (verbose) {
2852
2915
  console.log(chalk_1.default.cyan(`⚙ Executing: ${call.tool}`));
@@ -71,7 +71,7 @@ function registerVersionInfoCommand(program) {
71
71
  const commandRegistry = [
72
72
  {
73
73
  name: 'auth',
74
- handler: auth_js_1.registerAuthCommand,
74
+ handler: auth_js_1.registerAuthCommands,
75
75
  },
76
76
  {
77
77
  name: 'chat',
@@ -10,19 +10,15 @@
10
10
  */
11
11
  import { Config } from '../utils/config.js';
12
12
  import { Logger } from '../utils/logger.js';
13
- interface LegionOptions {
14
- workers?: boolean;
15
- status?: boolean;
16
- worker?: string;
17
- project?: string;
18
- godmode?: boolean;
19
- approve?: boolean;
20
- noApprove?: boolean;
21
- autoCharge?: boolean;
22
- planOnly?: boolean;
23
- models?: string;
24
- timeoutSec?: number;
25
- }
13
+ export type LegionOptions = {
14
+ /** Enables Vigthoria Cortex maximum-intelligence execution when --cortex is supplied. */
15
+ cortex?: boolean;
16
+ /** Model tier: 'heavy' (default — strongest LLMs) or 'lite' (cost-efficient, high quality). */
17
+ tier?: 'heavy' | 'lite';
18
+ email?: string;
19
+ password?: string;
20
+ [key: string]: any;
21
+ };
26
22
  export declare class LegionCommand {
27
23
  private config;
28
24
  private logger;
@@ -32,15 +28,20 @@ export declare class LegionCommand {
32
28
  private readJsonResponse;
33
29
  private propagateLegionApiError;
34
30
  run(request: string | undefined, options: LegionOptions): Promise<void>;
35
- private runGodmode;
31
+ private runCortex;
32
+ private isCriticalRoleFailure;
33
+ private isOptionalRepairRoleFailure;
34
+ private estimateAdditionalLoopQuote;
35
+ private confirmAdditionalLoopCharge;
36
+ private runMandatoryPreflight;
36
37
  private scanProject;
37
38
  private resolveModelProfiles;
38
39
  private buildRoleQuote;
39
- private buildGodmodeExplicitSteps;
40
+ private buildCortexExplicitSteps;
40
41
  private buildBillingQuote;
41
42
  private evaluateBillingGate;
42
43
  private parseBooleanCandidate;
43
- private fetchGodmodeEntitlement;
44
+ private fetchCortexEntitlement;
44
45
  private isMasterAdminFree;
45
46
  private getBillingBaseUrl;
46
47
  private parseNumericCandidate;
@@ -51,18 +52,20 @@ export declare class LegionCommand {
51
52
  private collectExecutionCharge;
52
53
  private resolveBillingInsufficientFunds;
53
54
  private printBillingGateSummary;
54
- private printGodmodeQuote;
55
+ private printCortexQuote;
55
56
  private confirmExecution;
56
57
  /**
57
58
  * SSE streaming URL for the Legion execution endpoint.
58
59
  * Always hits Hyper Loop directly (port 8020) with the service key to avoid
59
- * gateway JWT expiry killing long-running GodMode jobs.
60
+ * gateway JWT expiry killing long-running Cortex jobs.
60
61
  */
61
62
  private getLegionStreamUrl;
62
63
  private getLegionServiceKey;
63
64
  private planAndExecute;
65
+ private buildCortexRunReport;
66
+ private extractModifiedFiles;
67
+ private writeCortexSummaryReport;
64
68
  private formatLegionError;
65
69
  private showWorkers;
66
70
  private showStatus;
67
71
  }
68
- export {};