vigthoria-cli 1.10.0 → 1.10.36
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.
- package/dist/commands/auth.d.ts +1 -0
- package/dist/commands/auth.js +99 -17
- package/dist/commands/chat.d.ts +34 -0
- package/dist/commands/chat.js +1162 -61
- package/dist/commands/config.js +11 -2
- package/dist/commands/legion.js +8 -2
- package/dist/commands/wallet.d.ts +25 -0
- package/dist/commands/wallet.js +191 -0
- package/dist/index.js +158 -2
- package/dist/utils/api.d.ts +90 -2
- package/dist/utils/api.js +1730 -266
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.js +53 -12
- package/dist/utils/persona.d.ts +4 -0
- package/dist/utils/persona.js +34 -0
- package/dist/utils/tools.d.ts +5 -0
- package/dist/utils/tools.js +53 -1
- package/dist/utils/workspace-stream.js +56 -15
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +4 -2
- package/scripts/release/validate-no-go-gates.sh +3 -1
package/dist/commands/config.js
CHANGED
|
@@ -5,6 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
|
+
import { normalizePersonaMode } from '../utils/persona.js';
|
|
8
9
|
import { CH } from '../utils/logger.js';
|
|
9
10
|
export class ConfigCommand {
|
|
10
11
|
config;
|
|
@@ -164,6 +165,12 @@ export class ConfigCommand {
|
|
|
164
165
|
'modelsApiUrl': (v) => this.config.set('modelsApiUrl', v),
|
|
165
166
|
'wsUrl': (v) => this.config.set('wsUrl', v),
|
|
166
167
|
'selfHostedModelsApiUrl': (v) => this.config.set('selfHostedModelsApiUrl', v === 'null' || v === 'off' ? null : v),
|
|
168
|
+
'persona': (v) => {
|
|
169
|
+
const mode = normalizePersonaMode(v);
|
|
170
|
+
if (!mode)
|
|
171
|
+
throw new Error('Invalid persona. Use: default or wiener_grant');
|
|
172
|
+
this.config.set('persona', mode);
|
|
173
|
+
},
|
|
167
174
|
};
|
|
168
175
|
if (configMap[key]) {
|
|
169
176
|
configMap[key](value);
|
|
@@ -171,7 +178,7 @@ export class ConfigCommand {
|
|
|
171
178
|
}
|
|
172
179
|
else {
|
|
173
180
|
this.logger.error(`Unknown config key: ${key}`);
|
|
174
|
-
console.log(chalk.gray('Available keys: model, theme, autoApply, showDiffs, maxTokens, apiUrl, modelsApiUrl, wsUrl, selfHostedModelsApiUrl'));
|
|
181
|
+
console.log(chalk.gray('Available keys: model, theme, autoApply, showDiffs, maxTokens, persona, apiUrl, modelsApiUrl, wsUrl, selfHostedModelsApiUrl'));
|
|
175
182
|
}
|
|
176
183
|
}
|
|
177
184
|
formatConfigValueForDisplay(key, value) {
|
|
@@ -214,6 +221,7 @@ export class ConfigCommand {
|
|
|
214
221
|
maxTokens: all.preferences.maxTokens,
|
|
215
222
|
email: all.email,
|
|
216
223
|
plan: all.subscription.plan,
|
|
224
|
+
persona: all.persona,
|
|
217
225
|
};
|
|
218
226
|
if (key in flatConfig) {
|
|
219
227
|
console.log(flatConfig[key]);
|
|
@@ -231,7 +239,7 @@ export class ConfigCommand {
|
|
|
231
239
|
console.log(chalk.gray(' URL: ') + chalk.cyan(this.redactConfigUrl(all.apiUrl)));
|
|
232
240
|
console.log(chalk.gray(' Models API: ') + chalk.cyan(this.redactConfigUrl(all.modelsApiUrl)));
|
|
233
241
|
console.log(chalk.gray(' WebSocket: ') + chalk.cyan(this.redactConfigUrl(all.wsUrl)));
|
|
234
|
-
console.log(chalk.gray('
|
|
242
|
+
console.log(chalk.gray(' Vigthoria Model Endpoint: ') + chalk.cyan(all.selfHostedModelsApiUrl || 'default'));
|
|
235
243
|
console.log();
|
|
236
244
|
console.log(chalk.white('Preferences:'));
|
|
237
245
|
console.log(chalk.gray(' Default Model: ') + chalk.cyan(all.preferences.defaultModel));
|
|
@@ -239,6 +247,7 @@ export class ConfigCommand {
|
|
|
239
247
|
console.log(chalk.gray(' Auto Apply Fixes: ') + chalk.cyan(all.preferences.autoApplyFixes));
|
|
240
248
|
console.log(chalk.gray(' Show Diffs: ') + chalk.cyan(all.preferences.showDiffs));
|
|
241
249
|
console.log(chalk.gray(' Max Tokens: ') + chalk.cyan(all.preferences.maxTokens));
|
|
250
|
+
console.log(chalk.gray(' Persona: ') + chalk.cyan(all.persona));
|
|
242
251
|
console.log();
|
|
243
252
|
console.log(chalk.white('Project:'));
|
|
244
253
|
console.log(chalk.gray(' Ignore Patterns: ') + chalk.gray(all.project.ignorePatterns.join(', ')));
|
package/dist/commands/legion.js
CHANGED
|
@@ -68,7 +68,6 @@ export class LegionCommand {
|
|
|
68
68
|
const serviceKey = this.getLegionServiceKey();
|
|
69
69
|
if (serviceKey) {
|
|
70
70
|
headers['X-Service-Key'] = serviceKey;
|
|
71
|
-
return headers;
|
|
72
71
|
}
|
|
73
72
|
const token = this.config.get('authToken');
|
|
74
73
|
if (token) {
|
|
@@ -861,6 +860,7 @@ export class LegionCommand {
|
|
|
861
860
|
}
|
|
862
861
|
const endpoints = [
|
|
863
862
|
'/api/viagen6/vigcoin/balance',
|
|
863
|
+
'/api/user/vigcoin/balance',
|
|
864
864
|
'/api/user/subscription',
|
|
865
865
|
'/api/user/info',
|
|
866
866
|
'/api/user/profile',
|
|
@@ -868,6 +868,7 @@ export class LegionCommand {
|
|
|
868
868
|
'/api/billing/wallet',
|
|
869
869
|
'/api/billing/credits',
|
|
870
870
|
];
|
|
871
|
+
let sawUnauthorized = false;
|
|
871
872
|
for (const endpoint of endpoints) {
|
|
872
873
|
try {
|
|
873
874
|
const response = await fetch(`${baseUrl}${endpoint}`, {
|
|
@@ -876,6 +877,9 @@ export class LegionCommand {
|
|
|
876
877
|
headers,
|
|
877
878
|
});
|
|
878
879
|
if (!response.ok) {
|
|
880
|
+
if (response.status === 401 || response.status === 403) {
|
|
881
|
+
sawUnauthorized = true;
|
|
882
|
+
}
|
|
879
883
|
continue;
|
|
880
884
|
}
|
|
881
885
|
const payload = await this.readJsonResponse(response, `wallet balance request ${endpoint}`);
|
|
@@ -901,7 +905,9 @@ export class LegionCommand {
|
|
|
901
905
|
vigcoinBalance: null,
|
|
902
906
|
source: null,
|
|
903
907
|
purchaseUrl: `${baseUrl}/music/store#vigcoins`,
|
|
904
|
-
error:
|
|
908
|
+
error: sawUnauthorized
|
|
909
|
+
? 'Wallet session expired or unauthorized. Run: vigthoria login'
|
|
910
|
+
: 'Wallet endpoint unavailable from current gateway session',
|
|
905
911
|
};
|
|
906
912
|
}
|
|
907
913
|
async attemptDirectCharge(vigcoinNeeded) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wallet.ts — VigCoin wallet management for Vigthoria CLI.
|
|
3
|
+
*
|
|
4
|
+
* vigthoria wallet balance — show current balance
|
|
5
|
+
* vigthoria wallet history [--n 20] — recent transactions
|
|
6
|
+
* vigthoria wallet cloud-status — show cloud access and model pricing
|
|
7
|
+
*/
|
|
8
|
+
export interface WalletOptions {
|
|
9
|
+
n?: number;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class WalletCommand {
|
|
13
|
+
private config;
|
|
14
|
+
private logger;
|
|
15
|
+
constructor();
|
|
16
|
+
private getBaseUrl;
|
|
17
|
+
private getToken;
|
|
18
|
+
private getRefreshToken;
|
|
19
|
+
private refreshAccessToken;
|
|
20
|
+
private parseResponseBody;
|
|
21
|
+
private apiFetch;
|
|
22
|
+
showBalance(opts?: WalletOptions): Promise<void>;
|
|
23
|
+
showHistory(opts?: WalletOptions): Promise<void>;
|
|
24
|
+
showCloudStatus(opts?: WalletOptions): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wallet.ts — VigCoin wallet management for Vigthoria CLI.
|
|
3
|
+
*
|
|
4
|
+
* vigthoria wallet balance — show current balance
|
|
5
|
+
* vigthoria wallet history [--n 20] — recent transactions
|
|
6
|
+
* vigthoria wallet cloud-status — show cloud access and model pricing
|
|
7
|
+
*/
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import { Config } from '../utils/config.js';
|
|
10
|
+
import { Logger } from '../utils/logger.js';
|
|
11
|
+
export class WalletCommand {
|
|
12
|
+
config;
|
|
13
|
+
logger;
|
|
14
|
+
constructor() {
|
|
15
|
+
this.config = new Config();
|
|
16
|
+
this.logger = new Logger();
|
|
17
|
+
}
|
|
18
|
+
getBaseUrl() {
|
|
19
|
+
return String(this.config.get('apiUrl') || 'https://coder.vigthoria.io').replace(/\/$/, '');
|
|
20
|
+
}
|
|
21
|
+
getToken() {
|
|
22
|
+
return this.config.get('authToken') || null;
|
|
23
|
+
}
|
|
24
|
+
getRefreshToken() {
|
|
25
|
+
return this.config.get('refreshToken') || null;
|
|
26
|
+
}
|
|
27
|
+
async refreshAccessToken() {
|
|
28
|
+
const refreshToken = this.getRefreshToken();
|
|
29
|
+
if (!refreshToken)
|
|
30
|
+
return false;
|
|
31
|
+
try {
|
|
32
|
+
const response = await fetch(`${this.getBaseUrl()}/api/token/refresh`, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: { 'Content-Type': 'application/json' },
|
|
35
|
+
body: JSON.stringify({ refresh_token: refreshToken }),
|
|
36
|
+
});
|
|
37
|
+
if (!response.ok)
|
|
38
|
+
return false;
|
|
39
|
+
const payload = await response.json();
|
|
40
|
+
const nextToken = payload.token || payload.access_token;
|
|
41
|
+
if (!nextToken)
|
|
42
|
+
return false;
|
|
43
|
+
this.config.set('authToken', nextToken);
|
|
44
|
+
if (payload.refresh_token) {
|
|
45
|
+
this.config.set('refreshToken', payload.refresh_token);
|
|
46
|
+
}
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async parseResponseBody(resp) {
|
|
54
|
+
const raw = await resp.text();
|
|
55
|
+
if (!raw.trim())
|
|
56
|
+
return {};
|
|
57
|
+
try {
|
|
58
|
+
return JSON.parse(raw);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return { error: raw.slice(0, 240) };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async apiFetch(path) {
|
|
65
|
+
const url = `${this.getBaseUrl()}${path}`;
|
|
66
|
+
const runRequest = async (token) => fetch(url, {
|
|
67
|
+
headers: {
|
|
68
|
+
Authorization: `Bearer ${token}`,
|
|
69
|
+
Cookie: `vigthoria-auth-token=${token}`,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
let token = this.getToken();
|
|
73
|
+
if (!token)
|
|
74
|
+
throw new Error('Not authenticated. Run: vigthoria login');
|
|
75
|
+
let resp = await runRequest(token);
|
|
76
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
77
|
+
const refreshed = await this.refreshAccessToken();
|
|
78
|
+
if (refreshed) {
|
|
79
|
+
token = this.getToken();
|
|
80
|
+
if (token) {
|
|
81
|
+
resp = await runRequest(token);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const body = await this.parseResponseBody(resp);
|
|
86
|
+
if (!resp.ok) {
|
|
87
|
+
const err = body.error
|
|
88
|
+
|| body.message
|
|
89
|
+
|| `HTTP ${resp.status}`;
|
|
90
|
+
throw new Error(err);
|
|
91
|
+
}
|
|
92
|
+
return body;
|
|
93
|
+
}
|
|
94
|
+
async showBalance(opts = {}) {
|
|
95
|
+
try {
|
|
96
|
+
const data = await this.apiFetch('/api/user/vigcoin/balance');
|
|
97
|
+
if (opts.json) {
|
|
98
|
+
console.log(JSON.stringify(data, null, 2));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log(chalk.bold.cyan(' VigCoin Wallet'));
|
|
103
|
+
console.log(chalk.gray(' ─────────────────────────────'));
|
|
104
|
+
console.log(` Balance: ${chalk.bold.yellow(data.balance.toLocaleString())} ⓥ`);
|
|
105
|
+
console.log(` Lifetime earned: ${chalk.green(data.lifetimeEarned.toLocaleString())} ⓥ`);
|
|
106
|
+
console.log(` Lifetime spent: ${chalk.red(data.lifetimeSpent.toLocaleString())} ⓥ`);
|
|
107
|
+
if (data.lastUpdated) {
|
|
108
|
+
console.log(` Last updated: ${chalk.gray(new Date(data.lastUpdated).toLocaleString())}`);
|
|
109
|
+
}
|
|
110
|
+
console.log('');
|
|
111
|
+
console.log(chalk.gray(' Top up at: https://hub.vigthoria.io/credits'));
|
|
112
|
+
console.log('');
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
this.logger.error(err.message);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async showHistory(opts = {}) {
|
|
120
|
+
const limit = Math.max(1, Math.min(100, opts.n || 20));
|
|
121
|
+
try {
|
|
122
|
+
const data = await this.apiFetch(`/api/user/vigcoin/transactions?limit=${limit}`);
|
|
123
|
+
if (opts.json) {
|
|
124
|
+
console.log(JSON.stringify(data, null, 2));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const txs = data.transactions || [];
|
|
128
|
+
console.log('');
|
|
129
|
+
console.log(chalk.bold.cyan(` VigCoin Transaction History (last ${txs.length})`));
|
|
130
|
+
console.log(chalk.gray(' ──────────────────────────────────────────────────────────'));
|
|
131
|
+
if (txs.length === 0) {
|
|
132
|
+
console.log(chalk.gray(' No transactions found.'));
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
for (const tx of txs) {
|
|
136
|
+
const sign = tx.amount >= 0 ? chalk.green(`+${tx.amount}`) : chalk.red(String(tx.amount));
|
|
137
|
+
const date = new Date(tx.created_at).toLocaleString();
|
|
138
|
+
const desc = tx.description || tx.action || tx.type;
|
|
139
|
+
console.log(` ${chalk.gray(date)} ${sign.padStart(8)} ⓥ ${chalk.gray(`→`)} ${chalk.yellow(tx.balance_after)} ⓥ ${desc}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
console.log('');
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
this.logger.error(err.message);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async showCloudStatus(opts = {}) {
|
|
150
|
+
try {
|
|
151
|
+
const data = await this.apiFetch('/api/user/cloud-access/status');
|
|
152
|
+
if (opts.json) {
|
|
153
|
+
console.log(JSON.stringify(data, null, 2));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
console.log('');
|
|
157
|
+
console.log(chalk.bold.cyan(' Cloud Access Status'));
|
|
158
|
+
console.log(chalk.gray(' ─────────────────────────────'));
|
|
159
|
+
if (data.isMasterAdmin) {
|
|
160
|
+
console.log(` Access: ${chalk.bold.green('Master Admin — unlimited cloud access')}`);
|
|
161
|
+
}
|
|
162
|
+
else if (data.hasGrant) {
|
|
163
|
+
const models = data.grantDetails?.allowedModels === '*' ? 'All models' : data.grantDetails?.allowedModels;
|
|
164
|
+
const exp = data.grantDetails?.expiresAt ? ` (expires ${new Date(data.grantDetails.expiresAt).toLocaleDateString()})` : '';
|
|
165
|
+
console.log(` Access: ${chalk.green(`Granted — ${models}${exp}`)}`);
|
|
166
|
+
}
|
|
167
|
+
else if (data.cloudAccessAllowed) {
|
|
168
|
+
console.log(` Access: ${chalk.yellow('Enabled — pay per request with VigCoins')}`);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log(` Access: ${chalk.red('Not enabled — contact admin to request cloud access')}`);
|
|
172
|
+
}
|
|
173
|
+
console.log('');
|
|
174
|
+
if (data.cloudModels) {
|
|
175
|
+
console.log(chalk.bold(' Cloud Model Pricing'));
|
|
176
|
+
console.log(chalk.gray(' ─────────────────────────────'));
|
|
177
|
+
for (const [alias, cost] of Object.entries(data.cloudModels)) {
|
|
178
|
+
const displayName = alias.replace('vigthoria-cloud-', '').replace(/\b\w/g, c => c.toUpperCase());
|
|
179
|
+
console.log(` ${chalk.cyan(`vigthoria-cloud-${displayName.toLowerCase()}`).padEnd(36)} ${chalk.yellow(String(cost))} credits minimum reserve, then token-priced`);
|
|
180
|
+
}
|
|
181
|
+
console.log('');
|
|
182
|
+
console.log(chalk.gray(' Use --model vigthoria-cloud-fast|balanced|code|power|maximum in vigthoria chat'));
|
|
183
|
+
}
|
|
184
|
+
console.log('');
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
this.logger.error(err.message);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* vigthoria workflow - Manage repeatable VigFlow workflows
|
|
16
16
|
* vigthoria operator - Start BMAD operator mode
|
|
17
17
|
*/
|
|
18
|
-
import { Command } from 'commander';
|
|
18
|
+
import { Command, Option } from 'commander';
|
|
19
19
|
import { ChatCommand } from './commands/chat.js';
|
|
20
20
|
import { EditCommand } from './commands/edit.js';
|
|
21
21
|
import { GenerateCommand } from './commands/generate.js';
|
|
@@ -36,6 +36,7 @@ import { ReplayCommand } from './commands/replay.js';
|
|
|
36
36
|
import { ForkCommand } from './commands/fork.js';
|
|
37
37
|
import { CancelCommand } from './commands/cancel.js';
|
|
38
38
|
import { SecurityCommand } from './commands/security.js';
|
|
39
|
+
import { WalletCommand } from './commands/wallet.js';
|
|
39
40
|
import { Config } from './utils/config.js';
|
|
40
41
|
import { Logger, CH } from './utils/logger.js';
|
|
41
42
|
import chalk from 'chalk';
|
|
@@ -63,6 +64,56 @@ function getInvokedBinaryName() {
|
|
|
63
64
|
const executable = process.argv[1] || 'vigthoria';
|
|
64
65
|
return path.basename(executable, path.extname(executable)).toLowerCase();
|
|
65
66
|
}
|
|
67
|
+
function detectRuntimeEnvironment(cwd) {
|
|
68
|
+
const osPlatform = process.platform;
|
|
69
|
+
const normalizedPlatform = osPlatform === 'win32'
|
|
70
|
+
? 'windows'
|
|
71
|
+
: osPlatform === 'darwin'
|
|
72
|
+
? 'macos'
|
|
73
|
+
: osPlatform === 'linux'
|
|
74
|
+
? 'linux'
|
|
75
|
+
: 'unknown';
|
|
76
|
+
const release = os.release();
|
|
77
|
+
const isWSL = normalizedPlatform === 'linux' && (/microsoft/i.test(release)
|
|
78
|
+
|| Boolean(process.env.WSL_DISTRO_NAME)
|
|
79
|
+
|| Boolean(process.env.WSL_INTEROP));
|
|
80
|
+
let isContainer = false;
|
|
81
|
+
try {
|
|
82
|
+
if (fs.existsSync('/.dockerenv')) {
|
|
83
|
+
isContainer = true;
|
|
84
|
+
}
|
|
85
|
+
else if (fs.existsSync('/proc/1/cgroup')) {
|
|
86
|
+
const cgroup = fs.readFileSync('/proc/1/cgroup', 'utf8');
|
|
87
|
+
isContainer = /(docker|containerd|kubepods|podman)/i.test(cgroup);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
isContainer = false;
|
|
92
|
+
}
|
|
93
|
+
const isCodespaces = String(process.env.CODESPACES || '').toLowerCase() === 'true';
|
|
94
|
+
const isCI = String(process.env.CI || '').toLowerCase() === 'true';
|
|
95
|
+
const isMobileLikeRuntime = Boolean(process.env.TERMUX_VERSION
|
|
96
|
+
|| process.env.ANDROID_ROOT
|
|
97
|
+
|| process.env.IOS_SIMULATOR_DEVICE_NAME
|
|
98
|
+
|| /\/var\/mobile\//.test(cwd));
|
|
99
|
+
const workspaceKind = cwd.startsWith('/var/www/') || cwd.startsWith('/opt/vigthoria')
|
|
100
|
+
? 'server-workspace'
|
|
101
|
+
: 'local-machine';
|
|
102
|
+
return {
|
|
103
|
+
osPlatform,
|
|
104
|
+
normalizedPlatform,
|
|
105
|
+
arch: process.arch,
|
|
106
|
+
release,
|
|
107
|
+
isWSL,
|
|
108
|
+
isContainer,
|
|
109
|
+
isCodespaces,
|
|
110
|
+
isCI,
|
|
111
|
+
isMobileLikeRuntime,
|
|
112
|
+
workspaceKind,
|
|
113
|
+
cwd,
|
|
114
|
+
shell: process.env.SHELL || process.env.ComSpec || null,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
66
117
|
// Get version from package.json dynamically
|
|
67
118
|
function getPackageMetadataPaths() {
|
|
68
119
|
return [
|
|
@@ -149,7 +200,21 @@ function compareVersions(v1, v2) {
|
|
|
149
200
|
return 0;
|
|
150
201
|
}
|
|
151
202
|
const VERSION = getVersion();
|
|
203
|
+
function hiddenGrantOption() {
|
|
204
|
+
return new Option('--grant', 'Use optional Wiener Grantler persona for this invocation').hideHelp();
|
|
205
|
+
}
|
|
206
|
+
function allowInsecureCliVersionInstall() {
|
|
207
|
+
return /^(1|true|yes)$/i.test(String(process.env.VIGTHORIA_ALLOW_INSECURE_CLI_VERSION || ''));
|
|
208
|
+
}
|
|
209
|
+
function extractVersionFromUpdateTarget(target) {
|
|
210
|
+
const match = target.match(/(?:@|[-_])([0-9]+\.[0-9]+\.[0-9]+)(?:\.tgz)?(?:$|[^0-9])/);
|
|
211
|
+
return match ? match[1] : null;
|
|
212
|
+
}
|
|
213
|
+
function isBelowSecureCliBaseline(version) {
|
|
214
|
+
return compareVersions(version, VIGTHORIA_MIN_SECURE_CLI_VERSION) < 0;
|
|
215
|
+
}
|
|
152
216
|
const VIGTHORIA_DEFAULT_MANIFEST_URL = process.env.VIGTHORIA_UPDATE_MANIFEST_URL || "https://coder.vigthoria.io/releases/manifest.json";
|
|
217
|
+
const VIGTHORIA_MIN_SECURE_CLI_VERSION = '1.10.22';
|
|
153
218
|
function resolveManifestEntry(manifest, channel) {
|
|
154
219
|
const normalized = String(channel || 'stable').trim() || 'stable';
|
|
155
220
|
if (manifest.channels && manifest.channels[normalized]) {
|
|
@@ -524,7 +589,8 @@ export async function main(args) {
|
|
|
524
589
|
program
|
|
525
590
|
.name(invokedBinaryName === 'vigthoria-chat' ? 'vigthoria-chat' : 'vigthoria')
|
|
526
591
|
.description('AI-powered terminal coding assistant for Vigthoria Coder subscribers')
|
|
527
|
-
.version(VERSION)
|
|
592
|
+
.version(VERSION)
|
|
593
|
+
.addOption(hiddenGrantOption());
|
|
528
594
|
// Chat command - Interactive mode (Agent mode is default for best results)
|
|
529
595
|
program
|
|
530
596
|
.command('chat')
|
|
@@ -541,6 +607,7 @@ export async function main(args) {
|
|
|
541
607
|
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
542
608
|
.option('--auto-approve', 'Auto-approve agent actions (dangerous!)', false)
|
|
543
609
|
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
610
|
+
.addOption(hiddenGrantOption())
|
|
544
611
|
.action(async (options) => {
|
|
545
612
|
const chat = new ChatCommand(config, logger);
|
|
546
613
|
await chat.run({
|
|
@@ -555,6 +622,7 @@ export async function main(args) {
|
|
|
555
622
|
resume: options.resume,
|
|
556
623
|
prompt: options.prompt,
|
|
557
624
|
bridge: options.bridge,
|
|
625
|
+
grant: options.grant || program.opts().grant === true,
|
|
558
626
|
});
|
|
559
627
|
});
|
|
560
628
|
program
|
|
@@ -570,6 +638,7 @@ export async function main(args) {
|
|
|
570
638
|
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
571
639
|
.option('--auto-approve', 'Auto-approve agent actions (dangerous!)', false)
|
|
572
640
|
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
641
|
+
.addOption(hiddenGrantOption())
|
|
573
642
|
.action(async (options) => {
|
|
574
643
|
const chat = new ChatCommand(config, logger);
|
|
575
644
|
await chat.run({
|
|
@@ -584,6 +653,7 @@ export async function main(args) {
|
|
|
584
653
|
resume: true,
|
|
585
654
|
prompt: options.prompt,
|
|
586
655
|
bridge: options.bridge,
|
|
656
|
+
grant: options.grant || program.opts().grant === true,
|
|
587
657
|
});
|
|
588
658
|
});
|
|
589
659
|
// Agent command - Agentic mode (Vigthoria Autonomous)
|
|
@@ -600,6 +670,7 @@ export async function main(args) {
|
|
|
600
670
|
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
601
671
|
.option('--auto-approve', 'Auto-approve all actions (dangerous!)', false)
|
|
602
672
|
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
673
|
+
.addOption(hiddenGrantOption())
|
|
603
674
|
.action(async (options) => {
|
|
604
675
|
const chat = new ChatCommand(config, logger);
|
|
605
676
|
await chat.run({
|
|
@@ -614,6 +685,7 @@ export async function main(args) {
|
|
|
614
685
|
autoApprove: options.autoApprove,
|
|
615
686
|
prompt: options.prompt,
|
|
616
687
|
bridge: options.bridge,
|
|
688
|
+
grant: options.grant || program.opts().grant === true,
|
|
617
689
|
});
|
|
618
690
|
});
|
|
619
691
|
program
|
|
@@ -628,6 +700,7 @@ export async function main(args) {
|
|
|
628
700
|
.option('--save-plan', 'Save the completed BMAD plan into VigFlow for rerun and audit', false)
|
|
629
701
|
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
630
702
|
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
703
|
+
.addOption(hiddenGrantOption())
|
|
631
704
|
.action(async (options) => {
|
|
632
705
|
const chat = new ChatCommand(config, logger);
|
|
633
706
|
await chat.run({
|
|
@@ -642,6 +715,7 @@ export async function main(args) {
|
|
|
642
715
|
json: options.json,
|
|
643
716
|
prompt: options.prompt,
|
|
644
717
|
bridge: options.bridge,
|
|
718
|
+
grant: options.grant || program.opts().grant === true,
|
|
645
719
|
});
|
|
646
720
|
});
|
|
647
721
|
program
|
|
@@ -1295,10 +1369,25 @@ Examples:
|
|
|
1295
1369
|
const offline = isOfflineMode();
|
|
1296
1370
|
const updateSuppressed = isUpdateCheckSuppressed();
|
|
1297
1371
|
const subscription = config.get('subscription') || { plan: null, status: null, expiresAt: null };
|
|
1372
|
+
const runtime = detectRuntimeEnvironment(process.cwd());
|
|
1373
|
+
const warnings = [];
|
|
1374
|
+
if (runtime.normalizedPlatform === 'unknown') {
|
|
1375
|
+
warnings.push('Unknown OS platform detected. Run `vigthoria doctor --check-api` before agent tasks.');
|
|
1376
|
+
}
|
|
1377
|
+
if (runtime.isMobileLikeRuntime) {
|
|
1378
|
+
warnings.push('Mobile-like runtime detected (Termux/iOS-style path). Vigthoria CLI agent tooling is optimized for desktop/server shells.');
|
|
1379
|
+
}
|
|
1380
|
+
if (runtime.isWSL) {
|
|
1381
|
+
warnings.push('WSL detected. Prefer Linux-style paths and keep projects inside the WSL filesystem for stable tool execution.');
|
|
1382
|
+
}
|
|
1383
|
+
if (/127\.0\.0\.1:1/.test(modelsApiUrl)) {
|
|
1384
|
+
warnings.push('modelsApiUrl is set to 127.0.0.1:1 (unreachable). Set modelsApiUrl to https://api.vigthoria.io or your local model router.');
|
|
1385
|
+
}
|
|
1298
1386
|
const report = {
|
|
1299
1387
|
cliVersion: VERSION,
|
|
1300
1388
|
nodeVersion: process.version,
|
|
1301
1389
|
platform: `${process.platform} ${process.arch}`,
|
|
1390
|
+
runtimeEnvironment: runtime,
|
|
1302
1391
|
cwd: process.cwd(),
|
|
1303
1392
|
homeDir: os.homedir(),
|
|
1304
1393
|
configPath: config.getConfigPath(),
|
|
@@ -1310,6 +1399,7 @@ Examples:
|
|
|
1310
1399
|
subscriptionStatus: subscription.status || null,
|
|
1311
1400
|
offlineMode: offline,
|
|
1312
1401
|
updateCheckSuppressed: updateSuppressed,
|
|
1402
|
+
warnings,
|
|
1313
1403
|
envOverrides: {
|
|
1314
1404
|
VIGTHORIA_API_URL: process.env.VIGTHORIA_API_URL || null,
|
|
1315
1405
|
VIGTHORIA_V3_AGENT_URL: process.env.VIGTHORIA_V3_AGENT_URL || null,
|
|
@@ -1354,6 +1444,12 @@ Examples:
|
|
|
1354
1444
|
if (!options.checkApi) {
|
|
1355
1445
|
console.log(chalk.gray('\nTip: pass --check-api to verify API reachability.'));
|
|
1356
1446
|
}
|
|
1447
|
+
if (warnings.length > 0) {
|
|
1448
|
+
console.log(chalk.yellow('\nEnvironment warnings:'));
|
|
1449
|
+
for (const warning of warnings) {
|
|
1450
|
+
console.log(chalk.yellow(`- ${warning}`));
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1357
1453
|
}
|
|
1358
1454
|
process.exitCode = 0;
|
|
1359
1455
|
});
|
|
@@ -1428,6 +1524,21 @@ Examples:
|
|
|
1428
1524
|
return;
|
|
1429
1525
|
}
|
|
1430
1526
|
try {
|
|
1527
|
+
if (!allowInsecureCliVersionInstall()) {
|
|
1528
|
+
const detectedVersion = extractVersionFromUpdateTarget(updateTarget);
|
|
1529
|
+
if (!detectedVersion) {
|
|
1530
|
+
console.error(chalk.red('Refusing custom update source: unable to verify CLI version in update target.'));
|
|
1531
|
+
console.error(chalk.gray(`Allowed floor: ${VIGTHORIA_MIN_SECURE_CLI_VERSION}. Set VIGTHORIA_ALLOW_INSECURE_CLI_VERSION=1 only for trusted admin recovery.`));
|
|
1532
|
+
process.exitCode = 1;
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
if (isBelowSecureCliBaseline(detectedVersion)) {
|
|
1536
|
+
console.error(chalk.red(`Refusing insecure CLI version ${detectedVersion}.`));
|
|
1537
|
+
console.error(chalk.gray(`Minimum secure CLI version is ${VIGTHORIA_MIN_SECURE_CLI_VERSION}.`));
|
|
1538
|
+
process.exitCode = 1;
|
|
1539
|
+
return;
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1431
1542
|
if (options.check) {
|
|
1432
1543
|
console.log(chalk.cyan(`Update source configured: ${updateTarget}`));
|
|
1433
1544
|
console.log(chalk.gray('Run `vigthoria update --from <target>` to install from this source'));
|
|
@@ -1465,6 +1576,12 @@ Examples:
|
|
|
1465
1576
|
process.exitCode = 1;
|
|
1466
1577
|
return;
|
|
1467
1578
|
}
|
|
1579
|
+
if (!allowInsecureCliVersionInstall() && isBelowSecureCliBaseline(entry.version)) {
|
|
1580
|
+
console.error(chalk.red(`Refusing insecure manifest CLI version ${entry.version} for channel ${channel}.`));
|
|
1581
|
+
console.error(chalk.gray(`Minimum secure CLI version is ${VIGTHORIA_MIN_SECURE_CLI_VERSION}.`));
|
|
1582
|
+
process.exitCode = 1;
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1468
1585
|
const currentVersion = VERSION;
|
|
1469
1586
|
const comparison = compareVersions(entry.version, currentVersion);
|
|
1470
1587
|
if (!allowDowngrade && comparison <= 0) {
|
|
@@ -1533,6 +1650,12 @@ Examples:
|
|
|
1533
1650
|
windowsHide: true,
|
|
1534
1651
|
}).trim();
|
|
1535
1652
|
const currentVersion = VERSION;
|
|
1653
|
+
if (!allowInsecureCliVersionInstall() && isBelowSecureCliBaseline(latestVersion)) {
|
|
1654
|
+
console.error(chalk.red(`Refusing insecure npm latest CLI version ${latestVersion}.`));
|
|
1655
|
+
console.error(chalk.gray(`Minimum secure CLI version is ${VIGTHORIA_MIN_SECURE_CLI_VERSION}.`));
|
|
1656
|
+
process.exitCode = 1;
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1536
1659
|
// Use semantic version comparison (1.6.0 > 1.5.9)
|
|
1537
1660
|
const comparison = compareVersions(latestVersion, currentVersion);
|
|
1538
1661
|
if (comparison <= 0) {
|
|
@@ -1627,6 +1750,39 @@ Examples:
|
|
|
1627
1750
|
});
|
|
1628
1751
|
});
|
|
1629
1752
|
}
|
|
1753
|
+
// Wallet command — balance, transaction history, cloud access status
|
|
1754
|
+
const walletCommand = program
|
|
1755
|
+
.command('wallet')
|
|
1756
|
+
.alias('w')
|
|
1757
|
+
.description('Manage your VigCoin wallet and cloud access');
|
|
1758
|
+
walletCommand
|
|
1759
|
+
.command('balance')
|
|
1760
|
+
.alias('bal')
|
|
1761
|
+
.description('Show current VigCoin balance')
|
|
1762
|
+
.option('--json', 'Emit JSON output', false)
|
|
1763
|
+
.action(async (options) => {
|
|
1764
|
+
const wallet = new WalletCommand();
|
|
1765
|
+
await wallet.showBalance({ json: options.json });
|
|
1766
|
+
});
|
|
1767
|
+
walletCommand
|
|
1768
|
+
.command('history')
|
|
1769
|
+
.alias('hist')
|
|
1770
|
+
.description('Show recent VigCoin transactions')
|
|
1771
|
+
.option('-n, --n <number>', 'Number of transactions to show (default: 20)', parseInt)
|
|
1772
|
+
.option('--json', 'Emit JSON output', false)
|
|
1773
|
+
.action(async (options) => {
|
|
1774
|
+
const wallet = new WalletCommand();
|
|
1775
|
+
await wallet.showHistory({ n: options.n, json: options.json });
|
|
1776
|
+
});
|
|
1777
|
+
walletCommand
|
|
1778
|
+
.command('cloud-status')
|
|
1779
|
+
.alias('cs')
|
|
1780
|
+
.description('Show cloud model access status and pricing')
|
|
1781
|
+
.option('--json', 'Emit JSON output', false)
|
|
1782
|
+
.action(async (options) => {
|
|
1783
|
+
const wallet = new WalletCommand();
|
|
1784
|
+
await wallet.showCloudStatus({ json: options.json });
|
|
1785
|
+
});
|
|
1630
1786
|
try {
|
|
1631
1787
|
// Default to chat if no command
|
|
1632
1788
|
if (args.length === 2) {
|