vigthoria-cli 1.6.29 → 1.6.30
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.js +6 -2
- package/dist/commands/edit.js +31 -2
- package/dist/commands/explain.js +6 -0
- package/dist/commands/generate.js +6 -0
- package/dist/commands/review.js +6 -0
- package/dist/utils/api.d.ts +11 -0
- package/dist/utils/api.js +28 -0
- package/package.json +1 -1
package/dist/commands/auth.js
CHANGED
|
@@ -240,10 +240,14 @@ class AuthCommand {
|
|
|
240
240
|
if (capabilityStatus.devtoolsBridge.error) {
|
|
241
241
|
console.log(chalk_1.default.gray(' Error: ') + chalk_1.default.gray(capabilityStatus.devtoolsBridge.error));
|
|
242
242
|
}
|
|
243
|
-
// Auth scope summary
|
|
243
|
+
// Auth scope summary — use a real server-side probe for Model Auth
|
|
244
|
+
const tokenValidation = await this.api.validateToken();
|
|
244
245
|
console.log();
|
|
245
246
|
console.log(chalk_1.default.white('Auth Scopes:'));
|
|
246
|
-
console.log(chalk_1.default.gray(' Model Auth: ') + (
|
|
247
|
+
console.log(chalk_1.default.gray(' Model Auth: ') + (tokenValidation.valid ? chalk_1.default.green('Valid') : chalk_1.default.red('Invalid')) + chalk_1.default.gray(' (used by chat, agent, review, explain, generate, fix)'));
|
|
248
|
+
if (!tokenValidation.valid && tokenValidation.error) {
|
|
249
|
+
console.log(chalk_1.default.gray(' ') + chalk_1.default.red(tokenValidation.error));
|
|
250
|
+
}
|
|
247
251
|
console.log(chalk_1.default.gray(' Repo Auth: ') + (capabilityStatus.repoMemory.ok ? chalk_1.default.green('Active') : chalk_1.default.yellow('Inactive')) + chalk_1.default.gray(' (used by repo push/pull/list only)'));
|
|
248
252
|
console.log(chalk_1.default.gray(' Bridge Auth: ') + (capabilityStatus.devtoolsBridge.ok ? chalk_1.default.green('Connected') : chalk_1.default.gray('N/A')) + chalk_1.default.gray(' (used by --bridge flag only)'));
|
|
249
253
|
console.log();
|
package/dist/commands/edit.js
CHANGED
|
@@ -29,6 +29,12 @@ class EditCommand {
|
|
|
29
29
|
this.logger.error('Not authenticated. Run: vigthoria login');
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
+
// Server-side token validation — fail fast instead of waiting for 401
|
|
33
|
+
const tokenCheck = await this.api.validateToken();
|
|
34
|
+
if (!tokenCheck.valid) {
|
|
35
|
+
this.logger.error(tokenCheck.error || 'Auth token is invalid. Run: vigthoria login');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
32
38
|
// Read file
|
|
33
39
|
const file = this.fileUtils.readFile(filePath);
|
|
34
40
|
if (!file) {
|
|
@@ -46,6 +52,11 @@ class EditCommand {
|
|
|
46
52
|
this.logger.error('The --apply flag requires --instruction. Example: vigthoria edit file.ts --apply --instruction "fix the bug"');
|
|
47
53
|
return;
|
|
48
54
|
}
|
|
55
|
+
// Non-TTY stdin cannot prompt interactively
|
|
56
|
+
if (!process.stdin.isTTY) {
|
|
57
|
+
this.logger.error('No --instruction provided and stdin is not interactive. Use: vigthoria edit file.ts --instruction "..."');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
49
60
|
const answer = await inquirer_1.default.prompt([
|
|
50
61
|
{
|
|
51
62
|
type: 'input',
|
|
@@ -93,11 +104,14 @@ Return the complete modified file content:`,
|
|
|
93
104
|
], options.model);
|
|
94
105
|
spinner.stop();
|
|
95
106
|
// Extract code from response
|
|
96
|
-
|
|
107
|
+
let modifiedCode = this.extractCode(response.message, file.language);
|
|
97
108
|
if (!modifiedCode) {
|
|
98
109
|
this.logger.error('Failed to generate valid code changes');
|
|
99
110
|
return;
|
|
100
111
|
}
|
|
112
|
+
// Always deduplicate — extractCode only dedupes on the no-fence
|
|
113
|
+
// fallback path, so fenced responses (the common case) need this.
|
|
114
|
+
modifiedCode = this.deduplicateCode(modifiedCode);
|
|
101
115
|
// Show diff and apply
|
|
102
116
|
if (options.apply) {
|
|
103
117
|
await this.applyFix(file.path, file.content, modifiedCode);
|
|
@@ -118,6 +132,12 @@ Return the complete modified file content:`,
|
|
|
118
132
|
this.logger.error('Not authenticated. Run: vigthoria login');
|
|
119
133
|
return;
|
|
120
134
|
}
|
|
135
|
+
// Server-side token validation — fail fast instead of waiting for 401
|
|
136
|
+
const tokenCheck = await this.api.validateToken();
|
|
137
|
+
if (!tokenCheck.valid) {
|
|
138
|
+
this.logger.error(tokenCheck.error || 'Auth token is invalid. Run: vigthoria login');
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
121
141
|
// Read file
|
|
122
142
|
const file = this.fileUtils.readFile(filePath);
|
|
123
143
|
if (!file) {
|
|
@@ -238,11 +258,15 @@ Return the complete modified file content:`,
|
|
|
238
258
|
runEnd++;
|
|
239
259
|
}
|
|
240
260
|
const runLen = runEnd - i;
|
|
261
|
+
// Check if this run is "effectively at end" — only trailing empty
|
|
262
|
+
// lines follow the duplicate pair.
|
|
263
|
+
const isAtEffectiveEnd = runEnd === lines.length
|
|
264
|
+
|| lines.slice(runEnd).every(l => l.trim() === '');
|
|
241
265
|
if (runLen >= 3) {
|
|
242
266
|
// 3+ identical lines is almost certainly stutter — keep one
|
|
243
267
|
deduped.push(lines[i]);
|
|
244
268
|
}
|
|
245
|
-
else if (runLen === 2 &&
|
|
269
|
+
else if (runLen === 2 && isAtEffectiveEnd) {
|
|
246
270
|
// Exactly 2 identical lines at the very end — trailing stutter
|
|
247
271
|
deduped.push(lines[i]);
|
|
248
272
|
}
|
|
@@ -297,6 +321,11 @@ Return the complete modified file content:`,
|
|
|
297
321
|
await this.applyFix(filePath, original, modified);
|
|
298
322
|
return;
|
|
299
323
|
}
|
|
324
|
+
// Non-TTY: show the diff but don't try to prompt — re-run with --apply
|
|
325
|
+
if (!process.stdin.isTTY) {
|
|
326
|
+
this.logger.info('Non-interactive mode. Re-run with --apply to apply changes.');
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
300
329
|
const { action } = await inquirer_1.default.prompt([
|
|
301
330
|
{
|
|
302
331
|
type: 'list',
|
package/dist/commands/explain.js
CHANGED
|
@@ -33,6 +33,12 @@ class ExplainCommand {
|
|
|
33
33
|
this.logger.error('Not authenticated. Run: vigthoria login');
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
+
// Server-side token validation — fail fast instead of waiting for 401
|
|
37
|
+
const tokenCheck = await this.api.validateToken();
|
|
38
|
+
if (!tokenCheck.valid) {
|
|
39
|
+
this.logger.error(tokenCheck.error || 'Auth token is invalid. Run: vigthoria login');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
36
42
|
// Read file
|
|
37
43
|
const file = this.fileUtils.readFile(filePath);
|
|
38
44
|
if (!file) {
|
|
@@ -31,6 +31,12 @@ class GenerateCommand {
|
|
|
31
31
|
this.logger.error('Not authenticated. Run: vigthoria login');
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
+
// Server-side token validation — fail fast instead of waiting for 401
|
|
35
|
+
const tokenCheck = await this.api.validateToken();
|
|
36
|
+
if (!tokenCheck.valid) {
|
|
37
|
+
this.logger.error(tokenCheck.error || 'Auth token is invalid. Run: vigthoria login');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
34
40
|
// Determine mode
|
|
35
41
|
const proMode = options.pro === true;
|
|
36
42
|
// Auto-detect language from description if not explicitly specified
|
package/dist/commands/review.js
CHANGED
|
@@ -33,6 +33,12 @@ class ReviewCommand {
|
|
|
33
33
|
this.logger.error('Not authenticated. Run: vigthoria login');
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
+
// Server-side token validation — fail fast instead of waiting for 401
|
|
37
|
+
const tokenCheck = await this.api.validateToken();
|
|
38
|
+
if (!tokenCheck.valid) {
|
|
39
|
+
this.logger.error(tokenCheck.error || 'Auth token is invalid. Run: vigthoria login');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
36
42
|
// Read file
|
|
37
43
|
const file = this.fileUtils.readFile(filePath);
|
|
38
44
|
if (!file) {
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -201,6 +201,17 @@ export declare class APIClient {
|
|
|
201
201
|
private refreshToken;
|
|
202
202
|
getSubscriptionStatus(): Promise<void>;
|
|
203
203
|
private getAccessToken;
|
|
204
|
+
/**
|
|
205
|
+
* Validate the current auth token against the Coder API.
|
|
206
|
+
* Returns { valid: true } when the server accepts the token,
|
|
207
|
+
* { valid: false, error } when the token is rejected (401/403),
|
|
208
|
+
* and { valid: true } when the server is unreachable (network error)
|
|
209
|
+
* so that offline/degraded scenarios don't block the user.
|
|
210
|
+
*/
|
|
211
|
+
validateToken(): Promise<{
|
|
212
|
+
valid: boolean;
|
|
213
|
+
error?: string;
|
|
214
|
+
}>;
|
|
204
215
|
getV3AgentBaseUrls(preferLocal?: boolean): string[];
|
|
205
216
|
getV3AgentRunUrl(baseUrl: string): string;
|
|
206
217
|
getV3AgentContinueUrl(baseUrl: string): string;
|
package/dist/utils/api.js
CHANGED
|
@@ -340,6 +340,34 @@ class APIClient {
|
|
|
340
340
|
|| this.config.get('authToken')
|
|
341
341
|
|| null;
|
|
342
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* Validate the current auth token against the Coder API.
|
|
345
|
+
* Returns { valid: true } when the server accepts the token,
|
|
346
|
+
* { valid: false, error } when the token is rejected (401/403),
|
|
347
|
+
* and { valid: true } when the server is unreachable (network error)
|
|
348
|
+
* so that offline/degraded scenarios don't block the user.
|
|
349
|
+
*/
|
|
350
|
+
async validateToken() {
|
|
351
|
+
const token = this.getAccessToken();
|
|
352
|
+
if (!token) {
|
|
353
|
+
return { valid: false, error: 'No auth token configured. Run: vigthoria login' };
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
await this.client.get('/api/user/profile', { timeout: 10000 });
|
|
357
|
+
return { valid: true };
|
|
358
|
+
}
|
|
359
|
+
catch (error) {
|
|
360
|
+
if (error instanceof CLIError && error.category === 'auth') {
|
|
361
|
+
return { valid: false, error: 'Auth token expired or invalid. Run: vigthoria login' };
|
|
362
|
+
}
|
|
363
|
+
const axErr = error;
|
|
364
|
+
if (axErr.response?.status === 401 || axErr.response?.status === 403) {
|
|
365
|
+
return { valid: false, error: 'Auth token expired or invalid. Run: vigthoria login' };
|
|
366
|
+
}
|
|
367
|
+
// Network/timeout errors — don't assume token is bad
|
|
368
|
+
return { valid: true };
|
|
369
|
+
}
|
|
370
|
+
}
|
|
343
371
|
getV3AgentBaseUrls(preferLocal = false) {
|
|
344
372
|
const configuredApiUrl = String(this.config.get('apiUrl') || 'https://coder.vigthoria.io').replace(/\/$/, '');
|
|
345
373
|
const allowLocalV3Agent = process.env.VIGTHORIA_ALLOW_LOCAL_V3_AGENT === '1' || preferLocal;
|