vigthoria-cli 1.10.1 → 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 +52 -11
- 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/dist/commands/auth.d.ts
CHANGED
package/dist/commands/auth.js
CHANGED
|
@@ -7,7 +7,7 @@ import { Config } from '../utils/config.js';
|
|
|
7
7
|
const DEFAULT_API_URL = 'https://coder.vigthoria.io';
|
|
8
8
|
const CONFIG_DIR = path.join(homedir(), '.vigthoria');
|
|
9
9
|
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
10
|
-
const KNOWN_AUTH_BASE_URLS = ['https://coder.vigthoria.io'
|
|
10
|
+
const KNOWN_AUTH_BASE_URLS = ['https://coder.vigthoria.io'];
|
|
11
11
|
class HttpError extends Error {
|
|
12
12
|
status;
|
|
13
13
|
constructor(status, message) {
|
|
@@ -62,6 +62,9 @@ function syncSharedConfig(config) {
|
|
|
62
62
|
if (config.user?.email) {
|
|
63
63
|
shared.set('email', String(config.user.email));
|
|
64
64
|
}
|
|
65
|
+
if (config.v3ServiceKey) {
|
|
66
|
+
shared.set('v3ServiceKey', config.v3ServiceKey);
|
|
67
|
+
}
|
|
65
68
|
}
|
|
66
69
|
catch {
|
|
67
70
|
// Keep legacy auth flow working even if shared config write fails.
|
|
@@ -74,6 +77,7 @@ function clearSharedConfigAuth() {
|
|
|
74
77
|
shared.set('refreshToken', null);
|
|
75
78
|
shared.set('userId', null);
|
|
76
79
|
shared.set('email', null);
|
|
80
|
+
shared.set('v3ServiceKey', null);
|
|
77
81
|
}
|
|
78
82
|
catch {
|
|
79
83
|
// Ignore shared config clear failures during logout.
|
|
@@ -125,6 +129,7 @@ export function loadAuthConfig() {
|
|
|
125
129
|
return {
|
|
126
130
|
apiUrl: trimTrailingSlash(parsed.apiUrl || getApiUrl()),
|
|
127
131
|
token: parsed.token || parsed.authToken,
|
|
132
|
+
v3ServiceKey: typeof parsed.v3ServiceKey === 'string' ? parsed.v3ServiceKey : undefined,
|
|
128
133
|
user: parsed.user,
|
|
129
134
|
};
|
|
130
135
|
}
|
|
@@ -203,6 +208,23 @@ async function requestJson(url, init) {
|
|
|
203
208
|
}
|
|
204
209
|
return body;
|
|
205
210
|
}
|
|
211
|
+
async function fetchV3ServiceKey(apiBase, token) {
|
|
212
|
+
try {
|
|
213
|
+
const endpoint = `${trimTrailingSlash(apiBase)}/api/cli/v3-service-key`;
|
|
214
|
+
const result = await requestJson(endpoint, {
|
|
215
|
+
method: 'GET',
|
|
216
|
+
headers: { authorization: `Bearer ${token}` },
|
|
217
|
+
});
|
|
218
|
+
const key = result?.v3ServiceKey;
|
|
219
|
+
if (typeof key === 'string' && key.trim()) {
|
|
220
|
+
return key.trim();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// Non-fatal during login; V3 preflight can still fetch later via API utility.
|
|
225
|
+
}
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
206
228
|
async function ask(question, hidden = false) {
|
|
207
229
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
208
230
|
if (!hidden) {
|
|
@@ -214,18 +236,20 @@ async function ask(question, hidden = false) {
|
|
|
214
236
|
}
|
|
215
237
|
}
|
|
216
238
|
const output = process.stdout;
|
|
239
|
+
// Write the label directly so masking doesn't hide it
|
|
240
|
+
output.write(question);
|
|
217
241
|
const mutableRl = rl;
|
|
218
242
|
const originalWrite = mutableRl._writeToOutput;
|
|
219
243
|
mutableRl._writeToOutput = function writeMasked(value) {
|
|
220
244
|
if (value.includes('\n') || value.includes('\r')) {
|
|
221
245
|
output.write(value);
|
|
222
246
|
}
|
|
223
|
-
else {
|
|
247
|
+
else if (value.length > 0) {
|
|
224
248
|
output.write('*');
|
|
225
249
|
}
|
|
226
250
|
};
|
|
227
251
|
try {
|
|
228
|
-
return await new Promise((resolve) => rl.question(
|
|
252
|
+
return await new Promise((resolve) => rl.question('', resolve));
|
|
229
253
|
}
|
|
230
254
|
finally {
|
|
231
255
|
if (originalWrite) {
|
|
@@ -271,10 +295,13 @@ export async function login(email, password) {
|
|
|
271
295
|
failures.push(`${endpoint} -> success without token`);
|
|
272
296
|
continue;
|
|
273
297
|
}
|
|
298
|
+
const normalizedBase = trimTrailingSlash(base);
|
|
299
|
+
const v3ServiceKey = await fetchV3ServiceKey(normalizedBase, token);
|
|
274
300
|
const config = {
|
|
275
|
-
apiUrl:
|
|
301
|
+
apiUrl: normalizedBase,
|
|
276
302
|
token,
|
|
277
303
|
user: extractAuthUser(result, resolvedEmail),
|
|
304
|
+
...(v3ServiceKey ? { v3ServiceKey } : {}),
|
|
278
305
|
success: true,
|
|
279
306
|
};
|
|
280
307
|
saveAuthConfig(config);
|
|
@@ -287,11 +314,7 @@ export async function login(email, password) {
|
|
|
287
314
|
}
|
|
288
315
|
}
|
|
289
316
|
}
|
|
290
|
-
throw new Error(
|
|
291
|
-
'Login failed on all known auth endpoints.',
|
|
292
|
-
`Tried: ${attempted.join(', ')}`,
|
|
293
|
-
`Last errors: ${failures.slice(-4).join(' | ')}`,
|
|
294
|
-
].join(' '));
|
|
317
|
+
throw new Error('Invalid email or password. Please check your credentials and try again.');
|
|
295
318
|
}
|
|
296
319
|
catch (error) {
|
|
297
320
|
const message = humanMessage(error);
|
|
@@ -399,6 +422,10 @@ export async function handleLogin(options = {}) {
|
|
|
399
422
|
token: options.token,
|
|
400
423
|
success: true,
|
|
401
424
|
};
|
|
425
|
+
const v3ServiceKey = await fetchV3ServiceKey(config.apiUrl, options.token);
|
|
426
|
+
if (v3ServiceKey) {
|
|
427
|
+
config.v3ServiceKey = v3ServiceKey;
|
|
428
|
+
}
|
|
402
429
|
saveAuthConfig(config);
|
|
403
430
|
console.log(chalk.green('Logged in successfully with API token.'));
|
|
404
431
|
process.exitCode = 0;
|
|
@@ -413,7 +440,7 @@ export async function handleLogin(options = {}) {
|
|
|
413
440
|
email = (await ask('Email: ')).trim();
|
|
414
441
|
}
|
|
415
442
|
if (!password) {
|
|
416
|
-
password = await ask('Password: ', true);
|
|
443
|
+
password = (await ask('Password: ', true)).trim();
|
|
417
444
|
}
|
|
418
445
|
if (!email || !password) {
|
|
419
446
|
throw new Error('Email and password are required. Use --email and --password, or run vigthoria login interactively.');
|
|
@@ -423,6 +450,36 @@ export async function handleLogin(options = {}) {
|
|
|
423
450
|
if (config.user?.email) {
|
|
424
451
|
console.log(`Account: ${config.user.email}`);
|
|
425
452
|
}
|
|
453
|
+
// Fetch and display subscription tier + role
|
|
454
|
+
try {
|
|
455
|
+
const subResponse = await fetch(`${config.apiUrl}/api/user/subscription`, {
|
|
456
|
+
headers: { Authorization: `Bearer ${config.token}`, Cookie: `vigthoria-auth-token=${config.token}` },
|
|
457
|
+
signal: AbortSignal.timeout(5000),
|
|
458
|
+
});
|
|
459
|
+
if (subResponse.ok) {
|
|
460
|
+
const sub = await subResponse.json();
|
|
461
|
+
const subRecord = (sub.subscription && typeof sub.subscription === 'object') ? sub.subscription : {};
|
|
462
|
+
const userRecord = (sub.user && typeof sub.user === 'object') ? sub.user : {};
|
|
463
|
+
const plan = String(sub.plan || subRecord.plan || userRecord.plan || userRecord.subscription_plan || '').trim();
|
|
464
|
+
const role = String(sub.role || subRecord.role || userRecord.role || userRecord.user_role || '').trim();
|
|
465
|
+
if (plan) {
|
|
466
|
+
console.log(`Plan: ${plan.toUpperCase()}`);
|
|
467
|
+
}
|
|
468
|
+
if (role) {
|
|
469
|
+
console.log(`Role: ${role}`);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
catch { /* non-fatal — login already succeeded */ }
|
|
474
|
+
try {
|
|
475
|
+
const sharedConfig = new Config();
|
|
476
|
+
await sharedConfig.refreshHubModelPreferences();
|
|
477
|
+
const hubPrefs = sharedConfig.get('hubModelPrefs');
|
|
478
|
+
if (hubPrefs?.balance !== undefined) {
|
|
479
|
+
console.log(`Cloud credits: ${hubPrefs.balance}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
catch { /* non-fatal */ }
|
|
426
483
|
console.log(`API: ${config.apiUrl}`);
|
|
427
484
|
process.exitCode = 0;
|
|
428
485
|
return config;
|
|
@@ -446,27 +503,52 @@ export async function handleLogout(_options) {
|
|
|
446
503
|
}
|
|
447
504
|
export async function statusAction() {
|
|
448
505
|
try {
|
|
449
|
-
const
|
|
450
|
-
|
|
506
|
+
const legacyConfig = loadAuthConfig();
|
|
507
|
+
const sharedConfig = new Config();
|
|
508
|
+
const sharedApiUrl = String(sharedConfig.get('apiUrl') || '').trim();
|
|
509
|
+
const sharedToken = String(sharedConfig.get('authToken') || '').trim();
|
|
510
|
+
const effectiveApiUrl = trimTrailingSlash(sharedApiUrl || legacyConfig.apiUrl || getApiUrl());
|
|
511
|
+
const effectiveToken = sharedToken || legacyConfig.token || '';
|
|
512
|
+
if (!effectiveToken) {
|
|
451
513
|
console.log(chalk.yellow('Not logged in.'));
|
|
452
514
|
process.exitCode = 0;
|
|
453
515
|
return;
|
|
454
516
|
}
|
|
455
|
-
|
|
517
|
+
const authProbeHeaders = {
|
|
518
|
+
Authorization: `Bearer ${effectiveToken}`,
|
|
519
|
+
Cookie: `vigthoria-auth-token=${effectiveToken}`,
|
|
520
|
+
};
|
|
521
|
+
let authLooksValid = true;
|
|
522
|
+
try {
|
|
523
|
+
const authProbe = await fetch(`${effectiveApiUrl}/api/user/subscription`, { headers: authProbeHeaders, signal: AbortSignal.timeout(6000) });
|
|
524
|
+
if (authProbe.status === 401 || authProbe.status === 403) {
|
|
525
|
+
authLooksValid = false;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
catch {
|
|
529
|
+
// Network failures should not force logout status.
|
|
530
|
+
}
|
|
531
|
+
if (!authLooksValid) {
|
|
532
|
+
console.log(chalk.yellow('Not logged in. Session expired or invalid.'));
|
|
533
|
+
console.log(chalk.gray('Run: vigthoria login'));
|
|
534
|
+
process.exitCode = 1;
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
let user = legacyConfig.user;
|
|
456
538
|
try {
|
|
457
539
|
user = await whoami();
|
|
458
540
|
}
|
|
459
541
|
catch {
|
|
460
542
|
// Keep local status available even if remote whoami endpoint is down.
|
|
461
543
|
}
|
|
462
|
-
const sharedConfig = new Config();
|
|
463
544
|
let overallStatus = 'Unknown';
|
|
464
545
|
let coderStatus = 'Unknown';
|
|
465
546
|
let modelsStatus = 'Unknown';
|
|
547
|
+
const modelsApiBase = trimTrailingSlash(String(sharedConfig.get('modelsApiUrl') || 'https://api.vigthoria.io'));
|
|
466
548
|
try {
|
|
467
549
|
const [coderResponse, modelsResponse] = await Promise.all([
|
|
468
|
-
fetch(`${
|
|
469
|
-
fetch(
|
|
550
|
+
fetch(`${effectiveApiUrl}/api/health`, { signal: AbortSignal.timeout(8000) }),
|
|
551
|
+
fetch(`${modelsApiBase}/health`, { signal: AbortSignal.timeout(8000) }),
|
|
470
552
|
]);
|
|
471
553
|
const coderJson = await coderResponse.json().catch(() => ({}));
|
|
472
554
|
const modelsJson = await modelsResponse.json().catch(() => ({}));
|
|
@@ -491,7 +573,7 @@ export async function statusAction() {
|
|
|
491
573
|
console.log(`Overall: ${overallStatus}`);
|
|
492
574
|
console.log(`Coder API: ${coderStatus}`);
|
|
493
575
|
console.log(`Models API: ${modelsStatus}`);
|
|
494
|
-
console.log(`API: ${
|
|
576
|
+
console.log(`API: ${effectiveApiUrl}`);
|
|
495
577
|
process.exitCode = 0;
|
|
496
578
|
}
|
|
497
579
|
catch (error) {
|
package/dist/commands/chat.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ interface ChatOptions {
|
|
|
16
16
|
prompt?: string;
|
|
17
17
|
json?: boolean;
|
|
18
18
|
bridge?: string;
|
|
19
|
+
grant?: boolean;
|
|
19
20
|
}
|
|
20
21
|
export declare class ChatCommand {
|
|
21
22
|
private config;
|
|
@@ -34,6 +35,7 @@ export declare class ChatCommand {
|
|
|
34
35
|
private currentModel;
|
|
35
36
|
private modelExplicitlySelected;
|
|
36
37
|
private autoApprove;
|
|
38
|
+
private personaOverride;
|
|
37
39
|
private agentToolEvidence;
|
|
38
40
|
private operatorMode;
|
|
39
41
|
private workflowTarget;
|
|
@@ -59,12 +61,26 @@ export declare class ChatCommand {
|
|
|
59
61
|
private isLegacyAgentFallbackAllowed;
|
|
60
62
|
private resolveAgentExecutionPolicy;
|
|
61
63
|
private getMessagesForModel;
|
|
64
|
+
private normalizeClientV3ToolPath;
|
|
65
|
+
private resolveClientV3ToolPath;
|
|
66
|
+
private normalizeClientV3ToolArgs;
|
|
67
|
+
private executeClientV3Tool;
|
|
68
|
+
private getActivePersonaMode;
|
|
69
|
+
private buildActivePersonaOverlay;
|
|
62
70
|
private isDiagnosticPrompt;
|
|
63
71
|
/**
|
|
64
72
|
* Returns true when the prompt is a simple lookup / analysis / read-only
|
|
65
73
|
* question — these should use analysis_only workflow, not full_autonomy.
|
|
66
74
|
*/
|
|
67
75
|
private isAnalysisLookupPrompt;
|
|
76
|
+
private isImplementationPrompt;
|
|
77
|
+
private getWindowsPromptPathRoots;
|
|
78
|
+
private findPromptDirectoryByName;
|
|
79
|
+
private extractExplicitLocalPath;
|
|
80
|
+
private isUnscopedPromptPathOverrideAllowed;
|
|
81
|
+
private isPathWithinRoot;
|
|
82
|
+
private getPromptPathAllowedRoots;
|
|
83
|
+
private resolvePromptWorkspacePath;
|
|
68
84
|
private isBrowserTaskPrompt;
|
|
69
85
|
/**
|
|
70
86
|
* Returns true when a prompt can be answered directly without the full
|
|
@@ -81,6 +97,7 @@ export declare class ChatCommand {
|
|
|
81
97
|
*/
|
|
82
98
|
private isRepoGroundedPrompt;
|
|
83
99
|
private inferAgentTaskType;
|
|
100
|
+
private bindPromptWorkspace;
|
|
84
101
|
private buildTaskShapingInstructions;
|
|
85
102
|
private buildExecutionPrompt;
|
|
86
103
|
private isProjectBrainRuntimeDisabled;
|
|
@@ -91,15 +108,26 @@ export declare class ChatCommand {
|
|
|
91
108
|
private v3ToolCallCount;
|
|
92
109
|
private v3LastActivity;
|
|
93
110
|
private v3StreamingStarted;
|
|
111
|
+
private v3StreamedTextBuffer;
|
|
112
|
+
private v3LiveToolEvidence;
|
|
113
|
+
private v3PendingToolCalls;
|
|
94
114
|
/**
|
|
95
115
|
* Strip server-internal path prefixes from tool output strings.
|
|
96
116
|
* Prevents exposing paths like /var/www/V3-Code-Agent/... to end users.
|
|
97
117
|
*/
|
|
98
118
|
private sanitizeServerPath;
|
|
119
|
+
private stripHiddenThoughtBlocks;
|
|
99
120
|
private describeV3AgentTool;
|
|
100
121
|
private isRawV3StreamPayload;
|
|
101
122
|
private consumeV3StreamPayload;
|
|
102
123
|
private writeV3StreamText;
|
|
124
|
+
private isGenericV3AgentContent;
|
|
125
|
+
private hasAlreadyStreamedV3Content;
|
|
126
|
+
private isThinV3Summary;
|
|
127
|
+
private shouldPrintV3FinalContent;
|
|
128
|
+
private rememberV3ToolEvidence;
|
|
129
|
+
private buildUserFacingV3RunReport;
|
|
130
|
+
private printV3UserReport;
|
|
103
131
|
private updateV3AgentSpinner;
|
|
104
132
|
private updateOperatorSpinner;
|
|
105
133
|
constructor(config: Config, logger: Logger);
|
|
@@ -107,6 +135,7 @@ export declare class ChatCommand {
|
|
|
107
135
|
/** Handle an inbound admin command from the Commando Bridge. */
|
|
108
136
|
private handleAdminCommand;
|
|
109
137
|
private ensureProjectWorkspace;
|
|
138
|
+
private shouldStartWorkspaceWatcher;
|
|
110
139
|
private resolveProjectPath;
|
|
111
140
|
private shouldUseManagedWorkspace;
|
|
112
141
|
private getManagedWorkspaceRoot;
|
|
@@ -134,7 +163,11 @@ export declare class ChatCommand {
|
|
|
134
163
|
private runOperatorDirectAnswer;
|
|
135
164
|
private runSimplePrompt;
|
|
136
165
|
private runAgentTurn;
|
|
166
|
+
private localAgentIterationCount;
|
|
167
|
+
private buildLocalAgentChatOptions;
|
|
168
|
+
private printChatModelPreflight;
|
|
137
169
|
private runLocalAgentLoop;
|
|
170
|
+
private primeBypassedTargetFileContext;
|
|
138
171
|
private tryDirectSingleFileFlow;
|
|
139
172
|
private isConfirmationFollowUp;
|
|
140
173
|
private getPreviousActionablePrompt;
|
|
@@ -210,6 +243,7 @@ export declare class ChatCommand {
|
|
|
210
243
|
private buildLocalAnalysisFallback;
|
|
211
244
|
private tryDeterministicSingleFileRewrite;
|
|
212
245
|
private extractExactTextRequirement;
|
|
246
|
+
private tryLocalToolFallback;
|
|
213
247
|
private executeToolCalls;
|
|
214
248
|
private formatToolResult;
|
|
215
249
|
private truncateText;
|