vigthoria-cli 1.9.8 → 1.9.9
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/README.md +1 -1
- package/dist/utils/api.d.ts +6 -5
- package/dist/utils/api.js +34 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,7 +99,7 @@ If you see `ENOTFOUND registry.npmjs.org`, try these solutions:
|
|
|
99
99
|
4. **Direct tarball download:**
|
|
100
100
|
```bash
|
|
101
101
|
# Download directly
|
|
102
|
-
npm install -g https://coder.vigthoria.io/releases/vigthoria-cli-1.9.
|
|
102
|
+
npm install -g https://coder.vigthoria.io/releases/vigthoria-cli-1.9.9.tgz
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
5. **Use Git clone method (no npm registry needed):**
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -200,6 +200,7 @@ export declare class APIClient {
|
|
|
200
200
|
private ws;
|
|
201
201
|
private vigFlowTokens;
|
|
202
202
|
private _httpsAgent;
|
|
203
|
+
private lastChatTransportErrors;
|
|
203
204
|
constructor(config: Config, logger: Logger);
|
|
204
205
|
/**
|
|
205
206
|
* Destroy keep-alive sockets so the Node.js event loop can drain
|
|
@@ -217,12 +218,12 @@ export declare class APIClient {
|
|
|
217
218
|
private getAccessToken;
|
|
218
219
|
/**
|
|
219
220
|
* Validate the current auth token against the Coder API.
|
|
220
|
-
*
|
|
221
|
-
* { valid: false, error } when the token is rejected (401/403),
|
|
222
|
-
* and { valid: true } when the server is unreachable (network error)
|
|
223
|
-
* so that offline/degraded scenarios don't block the user.
|
|
221
|
+
* By default this fails open on network errors to keep offline commands usable.
|
|
224
222
|
*/
|
|
225
|
-
validateToken(
|
|
223
|
+
validateToken(options?: {
|
|
224
|
+
allowNetworkFailOpen?: boolean;
|
|
225
|
+
enforceTokenShape?: boolean;
|
|
226
|
+
}): Promise<{
|
|
226
227
|
valid: boolean;
|
|
227
228
|
error?: string;
|
|
228
229
|
}>;
|
package/dist/utils/api.js
CHANGED
|
@@ -207,6 +207,7 @@ class APIClient {
|
|
|
207
207
|
ws = null;
|
|
208
208
|
vigFlowTokens = new Map();
|
|
209
209
|
_httpsAgent = null;
|
|
210
|
+
lastChatTransportErrors = [];
|
|
210
211
|
constructor(config, logger) {
|
|
211
212
|
this.config = config;
|
|
212
213
|
this.logger = logger;
|
|
@@ -461,16 +462,23 @@ class APIClient {
|
|
|
461
462
|
}
|
|
462
463
|
/**
|
|
463
464
|
* Validate the current auth token against the Coder API.
|
|
464
|
-
*
|
|
465
|
-
* { valid: false, error } when the token is rejected (401/403),
|
|
466
|
-
* and { valid: true } when the server is unreachable (network error)
|
|
467
|
-
* so that offline/degraded scenarios don't block the user.
|
|
465
|
+
* By default this fails open on network errors to keep offline commands usable.
|
|
468
466
|
*/
|
|
469
|
-
async validateToken() {
|
|
467
|
+
async validateToken(options = {}) {
|
|
468
|
+
const allowNetworkFailOpen = options.allowNetworkFailOpen !== false;
|
|
469
|
+
const enforceTokenShape = options.enforceTokenShape !== false;
|
|
470
470
|
const token = this.getAccessToken();
|
|
471
471
|
if (!token) {
|
|
472
472
|
return { valid: false, error: 'No auth token configured. Run: vigthoria login' };
|
|
473
473
|
}
|
|
474
|
+
// Fast-fail obviously malformed tokens so invalid-token checks don't get
|
|
475
|
+
// masked by unrelated transport outages.
|
|
476
|
+
if (enforceTokenShape) {
|
|
477
|
+
const looksLikeJwt = token.split('.').length === 3;
|
|
478
|
+
if (!looksLikeJwt || token.length < 40) {
|
|
479
|
+
return { valid: false, error: 'Auth token expired or invalid. Run: vigthoria login' };
|
|
480
|
+
}
|
|
481
|
+
}
|
|
474
482
|
const explicitEnvToken = Boolean(process.env.VIGTHORIA_TOKEN || process.env.VIGTHORIA_AUTH_TOKEN);
|
|
475
483
|
const headers = {
|
|
476
484
|
Authorization: `Bearer ${token}`,
|
|
@@ -498,7 +506,7 @@ class APIClient {
|
|
|
498
506
|
}
|
|
499
507
|
}
|
|
500
508
|
}
|
|
501
|
-
if (explicitEnvToken) {
|
|
509
|
+
if (explicitEnvToken || !allowNetworkFailOpen) {
|
|
502
510
|
return { valid: false, error: 'Auth token expired or invalid. Run: vigthoria login' };
|
|
503
511
|
}
|
|
504
512
|
// Both unreachable — don't assume the stored token is bad when running offline.
|
|
@@ -958,6 +966,8 @@ class APIClient {
|
|
|
958
966
|
if (authToken) {
|
|
959
967
|
headers.Authorization = `Bearer ${authToken}`;
|
|
960
968
|
headers.Cookie = `vigthoria-auth-token=${authToken}`;
|
|
969
|
+
headers['X-Vigthoria-Token'] = authToken;
|
|
970
|
+
headers['X-Auth-Token'] = authToken;
|
|
961
971
|
}
|
|
962
972
|
return headers;
|
|
963
973
|
}
|
|
@@ -2987,8 +2997,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2987
2997
|
&& !process.env.VIGTHORIA_AUTH_TOKEN
|
|
2988
2998
|
&& Boolean(this.config.get('authToken'));
|
|
2989
2999
|
if (onlyUnauthorizedErrors && usingStoredConfigToken) {
|
|
2990
|
-
this.
|
|
2991
|
-
|
|
3000
|
+
const gatewayTokenCheck = await this.validateToken({ allowNetworkFailOpen: true, enforceTokenShape: true });
|
|
3001
|
+
if (!gatewayTokenCheck.valid) {
|
|
3002
|
+
this.config.clearAuth();
|
|
3003
|
+
throw new Error('V3 agent authentication failed. The stored CLI login token is invalid or expired. Run vigthoria login again.');
|
|
3004
|
+
}
|
|
3005
|
+
throw new Error('V3 agent authentication failed at the V3 service layer while your gateway login token is still valid. Please retry shortly.');
|
|
2992
3006
|
}
|
|
2993
3007
|
if (preferLocalV3
|
|
2994
3008
|
&& !this.hasAgentWorkspaceOutput(executionContext)
|
|
@@ -3212,6 +3226,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3212
3226
|
* NO localhost fallbacks - CLI is for external users, not server-side!
|
|
3213
3227
|
*/
|
|
3214
3228
|
async chat(messages, model, useLocal = false) {
|
|
3229
|
+
this.lastChatTransportErrors = [];
|
|
3215
3230
|
const resolvedModel = this.resolveModelId(model);
|
|
3216
3231
|
const candidateModels = this.isCloudModelId(resolvedModel) && !this.canUseCloudModel()
|
|
3217
3232
|
? [this.getSelfHostedFallbackModelId(resolvedModel, model)]
|
|
@@ -3230,12 +3245,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3230
3245
|
}
|
|
3231
3246
|
}
|
|
3232
3247
|
// No more localhost fallbacks - CLI is for external users!
|
|
3233
|
-
|
|
3248
|
+
const detail = this.lastChatTransportErrors.length > 0
|
|
3249
|
+
? ` Tried routes: ${this.lastChatTransportErrors.slice(0, 4).join(' | ')}`
|
|
3250
|
+
: '';
|
|
3251
|
+
throw new CLIError(`AI service unavailable. Please check your internet connection or try again later.${detail}`, 'model_backend');
|
|
3234
3252
|
}
|
|
3235
3253
|
shouldSkipCloudRoutes(resolvedModel) {
|
|
3236
3254
|
return this.shouldSimulateCloudFailure() && this.isCloudModelId(resolvedModel);
|
|
3237
3255
|
}
|
|
3238
3256
|
async tryChatWithModel(messages, resolvedModel, requestedModel) {
|
|
3257
|
+
const routeFailures = [];
|
|
3239
3258
|
const preferSelfHostedFirst = this.isSelfHostedPreferredModel(resolvedModel, requestedModel);
|
|
3240
3259
|
if (preferSelfHostedFirst) {
|
|
3241
3260
|
const selfHostedResponse = await this.trySelfHostedChatWithModel(messages, resolvedModel, requestedModel);
|
|
@@ -3276,6 +3295,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3276
3295
|
catch (error) {
|
|
3277
3296
|
const errMsg = error.response?.data?.error || error.message || 'Unknown error';
|
|
3278
3297
|
this.logger.debug(`Direct Vigthoria Models API failed for ${resolvedModel}: ${errMsg}`);
|
|
3298
|
+
routeFailures.push(`models:${String(errMsg).slice(0, 120)}`);
|
|
3279
3299
|
}
|
|
3280
3300
|
}
|
|
3281
3301
|
else {
|
|
@@ -3310,6 +3330,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3310
3330
|
catch (error) {
|
|
3311
3331
|
const errMsg = error.response?.data?.error || error.message || 'Unknown error';
|
|
3312
3332
|
this.logger.debug(`Vigthoria Cloud API failed for ${resolvedModel}: ${errMsg}`);
|
|
3333
|
+
routeFailures.push(`coder:${String(errMsg).slice(0, 120)}`);
|
|
3313
3334
|
}
|
|
3314
3335
|
try {
|
|
3315
3336
|
this.logger.debug(`Canonical Vigthoria Cloud fallback: ${resolvedModel}`);
|
|
@@ -3339,6 +3360,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3339
3360
|
catch (error) {
|
|
3340
3361
|
const errMsg = error.response?.data?.error || error.message || 'Unknown error';
|
|
3341
3362
|
this.logger.debug(`Canonical Vigthoria Cloud fallback failed for ${resolvedModel}: ${errMsg}`);
|
|
3363
|
+
routeFailures.push(`coder-canonical:${String(errMsg).slice(0, 120)}`);
|
|
3342
3364
|
}
|
|
3343
3365
|
}
|
|
3344
3366
|
if (!preferSelfHostedFirst) {
|
|
@@ -3347,6 +3369,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3347
3369
|
return selfHostedResponse;
|
|
3348
3370
|
}
|
|
3349
3371
|
}
|
|
3372
|
+
if (routeFailures.length > 0) {
|
|
3373
|
+
this.lastChatTransportErrors = routeFailures;
|
|
3374
|
+
}
|
|
3350
3375
|
return null;
|
|
3351
3376
|
}
|
|
3352
3377
|
async trySelfHostedChatWithModel(messages, resolvedModel, requestedModel) {
|