vigthoria-cli 1.12.1 → 1.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -921,7 +921,13 @@ export class ChatCommand {
921
921
  }
922
922
  terminalColumns() {
923
923
  const raw = Number(process.stdout.columns || process.stderr.columns || 80);
924
- return Number.isFinite(raw) && raw > 0 ? raw : 80;
924
+ const safe = Number.isFinite(raw) && raw > 0 ? raw : 80;
925
+ // process.stdout.columns is not always a reliable indicator of how many
926
+ // columns actually render visually (seen mismatching badly in some
927
+ // embedded/split-pane terminal hosts on Windows) -- cap at a
928
+ // conservative width so wrapped/fitted text never overflows even when
929
+ // the reported column count is larger than the real usable width.
930
+ return Math.min(safe, 60);
925
931
  }
926
932
  fitTerminalText(text, reserve = 0) {
927
933
  const width = Math.max(24, this.terminalColumns() - reserve);
@@ -0,0 +1,9 @@
1
+ export interface V4MenuOptions {
2
+ defaultAgent?: string;
3
+ defaultProvider?: string;
4
+ byokApiKey?: string;
5
+ byokBaseUrl?: string;
6
+ byokModel?: string;
7
+ outFile: string;
8
+ }
9
+ export declare function runV4Menu(options: V4MenuOptions): Promise<void>;
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Interactive V3/V4 agent + V4 provider picker, styled to match the rest of
3
+ * the Vigthoria CLI's menus (see agent-session-menu.ts). This is invoked as a
4
+ * subprocess (with inherited stdio, so it keeps full TTY/inquirer rendering)
5
+ * by the V4 Operating Agent's Python launcher (cli_menu.py) instead of that
6
+ * project rendering its own boxed prompt_toolkit dialog, which looked
7
+ * inconsistent with the CLI's visual design.
8
+ *
9
+ * The result is written as JSON to --out-file rather than printed to stdout,
10
+ * so stdout can stay fully interactive (a piped stdout would make inquirer
11
+ * fall back to non-interactive/plain rendering).
12
+ */
13
+ import * as fs from 'fs';
14
+ import chalk from 'chalk';
15
+ import inquirer from 'inquirer';
16
+ function isCancelError(error) {
17
+ const name = error instanceof Error ? error.name : '';
18
+ return name === 'ExitPromptError' || name === 'ERR_CLOSED';
19
+ }
20
+ function writeResult(outFile, result) {
21
+ fs.writeFileSync(outFile, JSON.stringify(result), 'utf8');
22
+ }
23
+ export async function runV4Menu(options) {
24
+ const defaultAgent = options.defaultAgent === 'v4' ? 'v4' : 'v3';
25
+ const defaultProvider = options.defaultProvider === 'v3_local' || options.defaultProvider === 'byok'
26
+ ? options.defaultProvider
27
+ : 'cloud';
28
+ console.log();
29
+ console.log(chalk.cyan('═══ Vigthoria Agent Launcher ═══'));
30
+ console.log(chalk.gray('Choose which agent runtime to start.'));
31
+ console.log();
32
+ try {
33
+ const { agent } = await inquirer.prompt([
34
+ {
35
+ type: 'list',
36
+ name: 'agent',
37
+ message: 'Select runtime',
38
+ default: defaultAgent,
39
+ choices: [
40
+ { name: 'V3 Code Agent', value: 'v3' },
41
+ { name: 'V4 Operating Agent', value: 'v4' },
42
+ ],
43
+ },
44
+ ]);
45
+ if (agent === 'v3') {
46
+ console.log();
47
+ console.log(chalk.cyan('── Session ready ──'));
48
+ console.log(chalk.gray('Runtime: V3 Code Agent'));
49
+ console.log();
50
+ writeResult(options.outFile, { agent: 'v3' });
51
+ return;
52
+ }
53
+ const { provider } = await inquirer.prompt([
54
+ {
55
+ type: 'list',
56
+ name: 'provider',
57
+ message: 'Select V4 backend',
58
+ default: defaultProvider,
59
+ choices: [
60
+ { name: 'Vigthoria Cloud (Gateway + Session Wallet Token)', value: 'cloud' },
61
+ { name: 'Vigthoria V3 Local (Blackwell 35B Direct)', value: 'v3_local' },
62
+ { name: 'Bring Your Own Key (API Key + Base URL + Model)', value: 'byok' },
63
+ ],
64
+ },
65
+ ]);
66
+ if (provider !== 'byok') {
67
+ console.log();
68
+ console.log(chalk.cyan('── Session ready ──'));
69
+ console.log(chalk.gray(`Runtime: V4 Operating Agent (${provider === 'cloud' ? 'Vigthoria Cloud' : 'Vigthoria V3 Local'})`));
70
+ console.log();
71
+ writeResult(options.outFile, { agent: 'v4', provider });
72
+ return;
73
+ }
74
+ const existingApiKey = String(options.byokApiKey || '').trim();
75
+ const existingBaseUrl = String(options.byokBaseUrl || '').trim();
76
+ const existingModel = String(options.byokModel || '').trim();
77
+ const missing = !existingApiKey || !existingBaseUrl || !existingModel;
78
+ const questions = [];
79
+ if (!existingApiKey) {
80
+ questions.push({
81
+ type: 'password',
82
+ name: 'apiKey',
83
+ message: 'BYOK API key:',
84
+ mask: '*',
85
+ validate: (value) => (String(value || '').trim() ? true : 'API key is required.'),
86
+ });
87
+ }
88
+ if (!existingBaseUrl) {
89
+ questions.push({
90
+ type: 'input',
91
+ name: 'baseUrl',
92
+ message: 'BYOK base URL:',
93
+ validate: (value) => (String(value || '').trim() ? true : 'Base URL is required.'),
94
+ });
95
+ }
96
+ if (!existingModel) {
97
+ questions.push({
98
+ type: 'input',
99
+ name: 'model',
100
+ message: 'BYOK default model:',
101
+ validate: (value) => (String(value || '').trim() ? true : 'Model is required.'),
102
+ });
103
+ }
104
+ const answers = questions.length > 0 ? await inquirer.prompt(questions) : {};
105
+ const apiKey = String(answers.apiKey || existingApiKey).trim();
106
+ const baseUrl = String(answers.baseUrl || existingBaseUrl).trim();
107
+ const model = String(answers.model || existingModel).trim();
108
+ let save = false;
109
+ if (missing) {
110
+ const { saveLocally } = await inquirer.prompt([
111
+ {
112
+ type: 'confirm',
113
+ name: 'saveLocally',
114
+ message: 'Store BYOK values locally in ~/.config/vigthoria/config.yaml?',
115
+ default: true,
116
+ },
117
+ ]);
118
+ save = saveLocally;
119
+ }
120
+ console.log();
121
+ console.log(chalk.cyan('── Session ready ──'));
122
+ console.log(chalk.gray('Runtime: V4 Operating Agent (Bring Your Own Key)'));
123
+ console.log();
124
+ writeResult(options.outFile, { agent: 'v4', provider: 'byok', apiKey, baseUrl, model, save });
125
+ }
126
+ catch (error) {
127
+ if (isCancelError(error)) {
128
+ console.log();
129
+ console.log(chalk.yellow('Cancelled.'));
130
+ writeResult(options.outFile, { cancelled: true });
131
+ process.exitCode = 130;
132
+ return;
133
+ }
134
+ throw error;
135
+ }
136
+ }
@@ -1,6 +1,8 @@
1
1
  import { Command } from 'commander';
2
2
  import { Config } from '../utils/config.js';
3
3
  import { Logger } from '../utils/logger.js';
4
+ export declare function defaultV4PythonBin(): string;
5
+ export declare function defaultV4AgentDir(): string | undefined;
4
6
  type V4Options = {
5
7
  provider?: 'cloud' | 'v3_local' | 'byok';
6
8
  apiKey?: string;
@@ -3,10 +3,10 @@ import * as fs from 'fs';
3
3
  import * as path from 'path';
4
4
  import chalk from 'chalk';
5
5
  const DEFAULT_V4_AGENT_DIR_UNIX = '/var/www/V4-Operating-Agent';
6
- function defaultV4PythonBin() {
6
+ export function defaultV4PythonBin() {
7
7
  return process.env.VIGTHORIA_V4_PYTHON || (process.platform === 'win32' ? 'python' : 'python3');
8
8
  }
9
- function defaultV4AgentDir() {
9
+ export function defaultV4AgentDir() {
10
10
  if (process.env.VIGTHORIA_V4_AGENT_DIR) {
11
11
  return process.env.VIGTHORIA_V4_AGENT_DIR;
12
12
  }
package/dist/index.js CHANGED
@@ -38,7 +38,8 @@ import { ForkCommand } from './commands/fork.js';
38
38
  import { CancelCommand } from './commands/cancel.js';
39
39
  import { BackgroundCommand } from './commands/background.js';
40
40
  import { SecurityCommand } from './commands/security.js';
41
- import { V4Command } from './commands/v4.js';
41
+ import { V4Command, defaultV4PythonBin, defaultV4AgentDir } from './commands/v4.js';
42
+ import { runV4Menu } from './commands/v4-menu.js';
42
43
  import { Config } from './utils/config.js';
43
44
  import { Logger, CH } from './utils/logger.js';
44
45
  import chalk from 'chalk';
@@ -584,8 +585,13 @@ export async function main(args) {
584
585
  !jsonOutputRequested &&
585
586
  !directPromptRequested &&
586
587
  !helpOrVersionRequested) {
588
+ // process.stdout.columns is not always a reliable indicator of how
589
+ // many columns actually render visually (seen mismatching badly in some
590
+ // embedded/split-pane terminal hosts on Windows) -- cap the box at a
591
+ // conservative width so it never overflows even when the reported
592
+ // column count is larger than the real usable width.
587
593
  const terminalWidth = Math.max(36, Number(process.stdout.columns || 80));
588
- const boxWidth = Math.max(34, Math.min(61, terminalWidth - 2));
594
+ const boxWidth = Math.max(34, Math.min(44, terminalWidth - 8));
589
595
  const innerWidth = boxWidth;
590
596
  const fit = (text) => {
591
597
  const clean = String(text || '').replace(/\s+/g, ' ').trim();
@@ -759,8 +765,8 @@ export async function main(args) {
759
765
  .option('--harness-control-url <url>', 'Override harness control URL')
760
766
  .option('--session-id <id>', 'Explicit V4 session id')
761
767
  .option('--non-interactive', 'Disable interactive menu and use CLI options', false)
762
- .option('--python <bin>', 'Python binary to use', process.env.VIGTHORIA_V4_PYTHON || 'python3')
763
- .option('--v4-path <path>', 'V4 agent root path', process.env.VIGTHORIA_V4_AGENT_DIR || '/var/www/V4-Operating-Agent')
768
+ .option('--python <bin>', 'Python binary to use', defaultV4PythonBin())
769
+ .option('--v4-path <path>', 'V4 agent root path (or set VIGTHORIA_V4_AGENT_DIR)', defaultV4AgentDir())
764
770
  .action(async (options) => {
765
771
  const v4 = new V4Command(config, logger);
766
772
  await v4.run({
@@ -777,6 +783,25 @@ export async function main(args) {
777
783
  v4Path: options.v4Path,
778
784
  });
779
785
  });
786
+ program
787
+ .command('v4-menu')
788
+ .description('Internal: interactive V3/V4 agent + provider picker used by the V4 Operating Agent launcher')
789
+ .option('--default-agent <agent>', 'v3 | v4', 'v3')
790
+ .option('--default-provider <provider>', 'cloud | v3_local | byok', 'cloud')
791
+ .option('--byok-api-key <key>', 'Existing BYOK api key', '')
792
+ .option('--byok-base-url <url>', 'Existing BYOK base url', '')
793
+ .option('--byok-model <name>', 'Existing BYOK model', '')
794
+ .requiredOption('--out-file <path>', 'Write JSON selection result to this file')
795
+ .action(async (options) => {
796
+ await runV4Menu({
797
+ defaultAgent: options.defaultAgent,
798
+ defaultProvider: options.defaultProvider,
799
+ byokApiKey: options.byokApiKey,
800
+ byokBaseUrl: options.byokBaseUrl,
801
+ byokModel: options.byokModel,
802
+ outFile: options.outFile,
803
+ });
804
+ });
780
805
  program
781
806
  .command('bridge')
782
807
  .description('Inspect local DevTools Bridge availability for browser debugging tasks')
@@ -162,11 +162,16 @@ export class Logger {
162
162
  }
163
163
  // Section header
164
164
  section(title) {
165
+ // process.stdout.columns is not always a reliable indicator of how many
166
+ // columns actually render visually (seen mismatching badly in some
167
+ // embedded/split-pane terminal hosts on Windows) -- cap at a
168
+ // conservative width so the separator line never overflows even when
169
+ // the reported column count is larger than the real usable width.
165
170
  const width = Math.max(24, Number(process.stdout.columns || 80));
166
171
  const cleanTitle = String(title || '').replace(/\s+/g, ' ').trim();
167
172
  const maxTitle = Math.max(10, width - 10);
168
173
  const fittedTitle = cleanTitle.length > maxTitle ? `${cleanTitle.slice(0, maxTitle - 1)}…` : cleanTitle;
169
- const side = Math.max(3, Math.floor((Math.min(width, 72) - fittedTitle.length - 2) / 2));
174
+ const side = Math.max(3, Math.floor((Math.min(width, 44) - fittedTitle.length - 2) / 2));
170
175
  console.log();
171
176
  console.log(chalk.bold.cyan(`${CH.hDouble.repeat(side)} ${fittedTitle} ${CH.hDouble.repeat(side)}`));
172
177
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigthoria-cli",
3
- "version": "1.12.1",
3
+ "version": "1.12.3",
4
4
  "description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",